@adatechnology/game-player 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/index.d.ts +68 -1
- package/dist/index.global.js +108 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +108 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.global.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/data/defaults.json","../src/rng.ts","../src/player.ts","../src/furniture-push.ts","../src/locales/index.ts","../src/bench/locale.ts","../src/bench/module.ts"],"sourcesContent":["export { PLAYER_DEFAULTS, createPlayer, deriveVitals, drawWound } from './player'\nexport type { Player, PlayerOptions } from './player'\nexport { createRng } from './rng'\nexport { FURNITURE_PUSH_DEFAULTS, canPush, createFurniturePush, gripSecondsFor, pushSpeedFor } from './furniture-push'\nexport type { FurniturePush, FurniturePushBlock, FurniturePushInput, FurniturePushPhase, FurniturePushRules, FurniturePushStep, FurniturePushTarget } from './furniture-push'\nexport { PLAYER_TEXT, playerTextOf } from './locales'\nexport type { PlayerText } from './locales'\nexport { createPlayerTestModule } from './bench/module'\nexport type { PlayerTestModule, PlayerTestModuleOptions } from './bench/module'\nexport type * from './types'\n","{\n \"sources\": {\n \"game\": \"specs/001-migracao-entregas-dos-times/artefatos/2UG1Mhe9LqJkQKKVsJkTWR/jogo.js\",\n \"attributes\": \"G 62004 FICHA (Personagens 3.2: every attribute 5, no traits)\",\n \"derived\": \"G 62005-62012 DERIV\",\n \"wounds\": \"G 62016 FERIDA (Personagens 3.7): share of each wound kind, and its infection chance (used only when an infection rule is on)\",\n \"infection\": \"G 62015 INFEC (the slice's accelerated clock: fever 30 s, delirium 70 s, death 120 s, reanimation 8 s after); G 68509 fever noise\",\n \"numbers\": \"G 68427-68640 player, playerUpdate, frontZombies, shove, knife; G 68678-68681 the aim spread modifiers; G 65507 walkCad\"\n },\n \"attributes\": { \"strength\": 5, \"vigor\": 5, \"agility\": 5, \"perception\": 5, \"intellect\": 5, \"presence\": 5 },\n \"derived\": {\n \"maxHealth\": { \"base\": 70, \"terms\": [[\"vigor\", 6]] },\n \"maxStamina\": { \"base\": 40, \"terms\": [[\"vigor\", 6], [\"agility\", 4]] },\n \"runSpeed\": { \"base\": 5.2, \"terms\": [[\"agility\", 0.12]] },\n \"walkSpeed\": { \"base\": 1.6, \"terms\": [] },\n \"footstepNoise\": { \"base\": 100, \"terms\": [[\"agility\", -4]], \"divide\": 100 },\n \"composure\": { \"base\": 20, \"terms\": [[\"vigor\", 3], [\"presence\", 4]] }\n },\n \"wounds\": {\n \"scratch\": { \"share\": 0.6, \"infectionChance\": 0.06, \"bleeds\": false },\n \"laceration\": { \"share\": 0.3, \"infectionChance\": 0.22, \"bleeds\": true },\n \"bite\": { \"share\": 0.1, \"infectionChance\": 1, \"bleeds\": true }\n },\n \"infection\": {\n \"feverSeconds\": 30,\n \"deliriumSeconds\": 70,\n \"deathSeconds\": 120,\n \"reanimateSeconds\": 8,\n \"feverNoiseEvery\": 2,\n \"feverNoiseChance\": 0.5,\n \"feverNoiseRadius\": 10,\n \"feverNoiseVolume\": 2,\n \"feverSpeed\": 0.85,\n \"feverSpread\": 1.5\n },\n \"numbers\": {\n \"hurtFlash\": 0.4,\n \"hurtVolume\": 0.8,\n \"biteDamage\": 25,\n \"biteFlash\": 0.8,\n \"biteVolume\": 1.2,\n \"burnPerSecond\": 3,\n \"bleedPerSecond\": 0.15,\n \"grabSeconds\": 3,\n \"grabVolume\": 1,\n \"grabFollow\": 12,\n \"grabOffset\": 0.55,\n \"grabPushCost\": 6,\n \"grabPushMinStamina\": 5,\n \"grabPushVolume\": 1.5,\n \"grabPushes\": 6,\n \"grabPushStun\": 1.2,\n \"grabPushSpeed\": 3,\n \"grabKnifeChance\": 0.7,\n \"grabKnifeRegion\": 0,\n \"grabKnifeDamage\": 22,\n \"grabKnifeDistance\": 0.5,\n \"grabKnifeCut\": 0.7,\n \"drownDamage\": 30,\n \"drownFlash\": 0.8,\n \"noJawDamage\": 8,\n \"grabAttackCooldown\": 2,\n \"vaultSeconds\": 0.7,\n \"vaultCost\": 15,\n \"vaultHeight\": 1.9,\n \"vaultScanFrom\": 0.3,\n \"vaultScanTo\": 1.0,\n \"vaultScanStep\": 0.1,\n \"vaultLandFrom\": 0.4,\n \"vaultLandTo\": 1.4,\n \"vaultClearance\": 0.3,\n \"vaultCheckHeight\": 0.4,\n \"vaultNoise\": 6,\n \"vaultStartVolume\": 0.8,\n \"vaultLandVolume\": 1,\n \"crouchSpeed\": 1.0,\n \"walkFactor\": 1.35,\n \"aimSpeedCap\": 1.4,\n \"waterSpeed\": 0.55,\n \"runMinStamina\": 1,\n \"runDrain\": 12,\n \"regenMoving\": 4,\n \"regenStill\": 8,\n \"acceleration\": 10,\n \"radius\": 0.3,\n \"blockHeight\": 0.4,\n \"pushApartRadius\": 0.55,\n \"pushApartHeight\": 1.2,\n \"hipFollow\": 10,\n \"hipMinSpeed\": 0.3,\n \"hipLimit\": 0.9,\n \"backwardsBelow\": -0.1,\n \"cadenceBase\": 0.5,\n \"cadencePerSpeed\": 0.3,\n \"cadenceMinSpeed\": 0.05,\n \"turnFollow\": 12,\n \"stepEvery\": 0.75,\n \"stepMinSpeed\": 0.3,\n \"stepNoiseRun\": 8,\n \"stepNoiseWalk\": 3,\n \"stepNoiseCrouch\": 1,\n \"stepNoiseWater\": 2,\n \"stepVolumeRun\": 0.6,\n \"stepVolumeWalk\": 0.3,\n \"shoveCost\": 10,\n \"shoveVolume\": 1.2,\n \"shoveRange\": 1.6,\n \"shoveCone\": 0.3,\n \"shoveStun\": 0.9,\n \"shoveSpeed\": 2.5,\n \"meleeMinStamina\": 5,\n \"meleeCostLight\": 5,\n \"meleeCostHeavy\": 12,\n \"meleeHeavyKg\": 1.5,\n \"meleeVolume\": 0.6,\n \"meleeRangeBase\": 0.9,\n \"meleeCone\": 0.5,\n \"meleeHeadChance\": 0.35,\n \"meleeArmChance\": 0.5,\n \"meleeStrengthPerPoint\": 0.06,\n \"meleeStrengthBase\": 5,\n \"meleeCritToCut\": 60,\n \"panicGain\": 1.2,\n \"panicDecay\": 3,\n \"panicMax\": 100,\n \"panicSpreadAt\": 0.6,\n \"panicSpread\": 1.4,\n \"moveSpread\": 0.4\n },\n \"fist\": { \"damage\": 8, \"crit\": 0, \"reach\": 0.5, \"noise\": 1 }\n}\n","const FNV_OFFSET = 0x811c9dc5\nconst FNV_PRIME = 0x01000193\nconst MIX = 0x9e3779b1\n\n/** Deterministic mulberry32 generator; returns floats in [0, 1). */\nexport function createRng(seed: number): () => number {\n let state = seed >>> 0\n return () => {\n state = (state + 0x6d2b79f5) >>> 0\n let mixed = Math.imul(state ^ (state >>> 15), state | 1)\n mixed ^= mixed + Math.imul(mixed ^ (mixed >>> 7), mixed | 61)\n return ((mixed ^ (mixed >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** A seed for the stream called `name`: the same seed gives each name its own sequence, so lightning never shifts the schedule. */\nexport function streamSeed(seed: number, name: string): number {\n let hash = FNV_OFFSET\n for (let index = 0; index < name.length; index++) hash = Math.imul(hash ^ name.charCodeAt(index), FNV_PRIME) >>> 0\n return Math.imul((seed >>> 0) ^ hash, MIX) >>> 0\n}\n\nexport function createStream(seed: number, name: string): () => number {\n return createRng(streamSeed(seed, name))\n}\n\nexport function drawBetween(rng: () => number, range: readonly [min: number, max: number]): number {\n return range[0] + rng() * (range[1] - range[0])\n}\n","import defaults from './data/defaults.json'\nimport { createRng } from './rng'\nimport type {\n Attributes,\n DeathCause,\n Derived,\n DerivedFormulas,\n DerivedId,\n InfectionRule,\n LinearFormula,\n MeleeItem,\n PlayerAction,\n PlayerCrowd,\n PlayerEventMap,\n PlayerEventName,\n PlayerInput,\n PlayerMessageId,\n PlayerNumbers,\n PlayerSave,\n PlayerSoundId,\n PlayerState,\n PlayerWorld,\n WoundTable,\n} from './types'\n\nexport const PLAYER_DEFAULTS = defaults as unknown as {\n readonly sources: Readonly<Record<string, string>>\n readonly attributes: Attributes\n readonly derived: DerivedFormulas\n readonly wounds: WoundTable\n readonly infection: InfectionRule\n readonly numbers: PlayerNumbers\n readonly fist: MeleeItem\n}\n\nexport type PlayerOptions = {\n /** The random stream (the game passes its single stream). Default `createRng(seed)`. */\n readonly random?: () => number\n readonly seed?: number\n /** The sheet: every attribute 5 by default. */\n readonly attributes?: Partial<Attributes>\n readonly derived?: Partial<DerivedFormulas>\n readonly wounds?: WoundTable\n /** An individual infection (`true` uses the defaults; an object patches them). Off by default: the normal world comes first. */\n readonly infection?: boolean | Partial<InfectionRule>\n readonly numbers?: Partial<PlayerNumbers>\n readonly fist?: MeleeItem\n readonly position?: { readonly x?: number; readonly z?: number; readonly yaw?: number }\n readonly world?: PlayerWorld\n}\n\nexport type Player = {\n readonly state: PlayerState\n readonly attributes: Attributes\n readonly derived: Derived\n readonly numbers: PlayerNumbers\n readonly infection: InfectionRule | null\n update(dt: number, input?: PlayerInput, world?: PlayerWorld): void\n /** A hit that opens a wound (drawn from the wound table) and may infect. `by` is the agent that hit, if any. */\n hurt(amount: number, by?: number): void\n /** A bite: damage, bleeding, a bite wound and (with an infection rule) the infection. */\n bite(by?: number): void\n grab(by: number, noJaw?: boolean, drown?: boolean): void\n release(): void\n knock(seconds: number): void\n infect(source: string): void\n /** Kills the player with a cause (the host's deaths: a fall, a fire). */\n die(cause: DeathCause): void\n /** Infection stage: `none`, `malaise`, `fever`, `delirium`. */\n stage(): 'none' | 'malaise' | 'fever' | 'delirium'\n /** Seconds the infection has left, or null. */\n timeLeft(): number | null\n /** What the player's state does to aim spread (panic, fever, moving); the weapon multiplies its own spread by it. */\n spreadFactor(): number\n /** The agents in front (nearest first) within `range` m and a cone of `cosMin`, as `[distance, index]`. */\n front(range: number, cosMin: number, yaw: number, crowd?: PlayerCrowd): [number, number][]\n on<K extends PlayerEventName>(event: K, listener: (event: PlayerEventMap[K]) => void): () => void\n save(): PlayerSave\n load(save: PlayerSave): void\n /** The world `update` uses when it is given none. */\n setWorld(world: PlayerWorld): void\n}\n\nconst TAU_APPROX = 6.2832\n\nconst evaluate = (formula: LinearFormula, attributes: Attributes): number => {\n let value = formula.base\n for (const [attribute, coefficient] of formula.terms) value += coefficient * attributes[attribute]\n return formula.divide === undefined ? value : value / formula.divide\n}\n\n/** The derived values of a sheet (the game's `DERIV`). */\nexport const deriveVitals = (attributes: Attributes, formulas: DerivedFormulas = PLAYER_DEFAULTS.derived): Derived => {\n const out = {} as Record<DerivedId, number>\n for (const id of Object.keys(formulas) as DerivedId[]) out[id] = evaluate(formulas[id], attributes)\n return out\n}\n\n/** Which wound a hit opens: one draw, the kinds in the listed order, the last one takes the rest (the game's `FERIDA` draw). */\nexport const drawWound = (wounds: WoundTable, random: () => number): string => {\n const kinds = Object.keys(wounds)\n const draw = random()\n let acc = 0\n for (let k = 0; k < kinds.length - 1; k++) {\n acc += wounds[kinds[k]!]!.share\n if (draw < acc) return kinds[k]!\n }\n return kinds[kinds.length - 1]!\n}\n\nconst clamp = (v: number, a: number, b: number): number => (v < a ? a : v > b ? b : v)\nconst lerp = (a: number, b: number, t: number): number => a + (b - a) * t\n\nconst freshState = (derived: Derived, position: PlayerOptions['position']): PlayerState => ({\n x: position?.x ?? 0,\n z: position?.z ?? 0,\n y: 0,\n vx: 0,\n vz: 0,\n yaw: position?.yaw ?? 0,\n floor: 0,\n alive: true,\n turned: false,\n health: derived.maxHealth,\n stamina: derived.maxStamina,\n crouch: false,\n running: false,\n stepTimer: 0,\n phase: 0,\n hip: 0,\n grabbedBy: -1,\n grabTimer: 0,\n grabPushes: 0,\n grabNoJaw: false,\n grabDrown: false,\n infected: false,\n infectionTime: 0,\n infectionSource: '',\n wounds: [],\n bleeding: 0,\n blind: 0,\n screamBoost: 0,\n panic: 0,\n hurtFlash: 0,\n deathTime: 0,\n cause: '',\n downTimer: 0,\n burnTimer: 0,\n scentTimer: 0,\n vaultTimer: 0,\n vault: null,\n})\n\n/**\n * The player body: a literal port of the team game's `player` and `playerUpdate` (G 68427-68640) with the world, the crowd and the input as\n * arguments instead of globals. The draws on `random` happen in the game's order (wound kind, infection, the fever cough, the knife when grabbed,\n * the melee region), so a game that passes its own stream keeps its sequence.\n */\nexport function createPlayer(options: PlayerOptions = {}): Player {\n const random = options.random ?? createRng(options.seed ?? 1)\n const attributes: Attributes = { ...PLAYER_DEFAULTS.attributes, ...options.attributes }\n const formulas: DerivedFormulas = { ...PLAYER_DEFAULTS.derived, ...options.derived }\n const derived = deriveVitals(attributes, formulas)\n const numbers: PlayerNumbers = { ...PLAYER_DEFAULTS.numbers, ...options.numbers }\n const wounds = options.wounds ?? PLAYER_DEFAULTS.wounds\n const infection: InfectionRule | null =\n options.infection === undefined || options.infection === false ? null : options.infection === true ? PLAYER_DEFAULTS.infection : { ...PLAYER_DEFAULTS.infection, ...options.infection }\n const fist = options.fist ?? PLAYER_DEFAULTS.fist\n const listeners = new Map<PlayerEventName, Set<(event: never) => void>>()\n let P = freshState(derived, options.position)\n let defaultWorld: PlayerWorld = options.world ?? {}\n let world: PlayerWorld = defaultWorld\n\n const emit = <K extends PlayerEventName>(event: K, payload: PlayerEventMap[K]): void => {\n const set = listeners.get(event)\n if (set) for (const listener of set) (listener as (event: PlayerEventMap[K]) => void)(payload)\n }\n const sound = (id: PlayerSoundId, volume: number): void => emit('sound', { sound: id, volume, position: [P.x, P.y, P.z] })\n const noise = (x: number, z: number, radius: number): void => emit('noise', { x, z, radius })\n const message = (id: PlayerMessageId | DeathCause, seconds: number): void => emit('message', { id, seconds })\n const inWater = (x: number, z: number): boolean => world.inWater?.(x, z) ?? false\n const solidAt = (x: number, z: number, y: number): boolean => world.solidAt?.(x, z, y) ?? false\n const cellKind = (x: number, z: number): number => world.cellKind?.(x, z) ?? 0\n const blocked = (x: number, z: number): boolean => (world.blocked ? world.blocked(x, z) : solidAt(x, z, numbers.blockHeight))\n const chanceOf = (kind: string): number => infection?.chances?.[kind] ?? wounds[kind]?.infectionChance ?? 0\n\n const die = (cause: DeathCause): void => {\n if (!P.alive) return\n P.alive = false\n P.cause = cause\n P.deathTime = 0\n P.grabbedBy = -1\n message(cause, 6)\n emit('died', { cause })\n }\n const infect = (source: string): void => {\n if (P.infected || !infection) return\n P.infected = true\n P.infectionTime = 0\n P.infectionSource = source\n emit('infected', { source })\n }\n const release = (how: PlayerEventMap['released']['how'] = 'free'): void => {\n const by = P.grabbedBy\n P.grabbedBy = -1\n if (by >= 0) emit('released', { by, how })\n }\n const hurt = (amount: number): void => {\n if (!P.alive) return\n P.health -= amount\n P.hurtFlash = numbers.hurtFlash\n sound('flesh', numbers.hurtVolume)\n const kind = drawWound(wounds, random)\n P.wounds.push(kind)\n if (wounds[kind]?.bleeds) P.bleeding = 1\n emit('hurt', { amount, wound: kind })\n if (infection && !P.infected && random() < chanceOf(kind)) infect(kind)\n if (P.health <= 0) die(P.infected ? 'infected' : 'killed')\n }\n const bite = (): void => {\n P.health -= numbers.biteDamage\n P.hurtFlash = numbers.biteFlash\n P.bleeding = 1\n P.wounds.push('bite')\n sound('flesh', numbers.biteVolume)\n emit('hurt', { amount: numbers.biteDamage, wound: 'bite' })\n infect('bite')\n message('bitten', 5)\n if (P.health <= 0) die('bitten_to_death')\n }\n const grab = (by: number, noJaw = false, drown = false): void => {\n P.grabbedBy = by\n P.grabTimer = numbers.grabSeconds\n P.grabPushes = 0\n P.grabNoJaw = noJaw\n P.grabDrown = drown\n message(drown ? 'grabbed_drown' : 'grabbed', 3)\n sound('flesh', numbers.grabVolume)\n emit('grabbed', { by, noJaw, drown })\n }\n\n const front = (range: number, cosMin: number, yaw: number, crowd: PlayerCrowd | undefined = world.crowd): [number, number][] => {\n const out: [number, number][] = []\n if (!crowd) return out\n const fx = -Math.sin(yaw)\n const fz = -Math.cos(yaw)\n const n = crowd.count()\n for (let i = 0; i < n; i++) {\n if (!crowd.active(i) || crowd.floor(i) !== P.floor) continue\n const ex = crowd.x(i) - P.x\n const ez = crowd.z(i) - P.z\n const d = Math.hypot(ex, ez)\n if (d < range && (ex * fx + ez * fz) / (d || 1) > cosMin) out.push([d, i])\n }\n return out.sort((a, b) => a[0] - b[0])\n }\n\n const shove = (yaw: number): void => {\n sound('step', numbers.shoveVolume)\n const crowd = world.crowd\n const targets: number[] = []\n for (const [d, i] of front(numbers.shoveRange, numbers.shoveCone, yaw)) {\n crowd!.stun(i, numbers.shoveStun, ((crowd!.x(i) - P.x) / d) * numbers.shoveSpeed, ((crowd!.z(i) - P.z) / d) * numbers.shoveSpeed)\n targets.push(i)\n }\n emit('shove', { targets })\n }\n\n const melee = (item: MeleeItem, yaw: number): void => {\n const t = front(numbers.meleeRangeBase + (item.reach ?? 0), numbers.meleeCone, yaw)[0]\n sound('flesh', numbers.meleeVolume)\n noise(P.x, P.z, item.noise || 1)\n if (!t) return\n const crowd = world.crowd!\n const i = t[1]\n // a blow to the head is x3 in melee; on the ground or crawling it is an execution\n const region = crowd.down(i) ? 0 : random() < numbers.meleeHeadChance ? 0 : random() < numbers.meleeArmChance ? 1 : 2 + Math.floor(random() * 2)\n const damage = item.damage * (1 + (attributes.strength - numbers.meleeStrengthBase) * numbers.meleeStrengthPerPoint)\n const cut = Math.min(1, (item.crit || 0) / numbers.meleeCritToCut)\n crowd.damage(i, { region, amount: damage, distance: t[0], cut })\n emit('melee', { target: i, region, damage, distance: t[0], cut })\n }\n\n const update = (dt: number, input: PlayerInput = {}, frameWorld?: PlayerWorld): void => {\n world = frameWorld ?? defaultWorld\n if (!P.alive) {\n P.deathTime += dt\n if (P.infected && infection && !P.turned && P.deathTime >= infection.reanimateSeconds) {\n P.turned = true\n emit('turned', { x: P.x, z: P.z, floor: P.floor })\n }\n return\n }\n const pressed: Partial<Record<PlayerAction, boolean>> = { ...input.pressed }\n const wasPressed = (action: PlayerAction): boolean => {\n const v = pressed[action] === true\n pressed[action] = false\n return v\n }\n const viewYaw = input.yaw ?? 0\n const crowd = world.crowd\n P.screamBoost = Math.max(0, P.screamBoost - dt)\n P.blind = Math.max(0, P.blind - dt)\n P.hurtFlash = Math.max(0, P.hurtFlash - dt)\n // infection on its own clock\n if (P.infected && infection) {\n const before = P.infectionTime\n P.infectionTime += dt\n if (before <= infection.feverSeconds && P.infectionTime > infection.feverSeconds) emit('stage', { stage: 'fever' })\n if (before <= infection.deliriumSeconds && P.infectionTime > infection.deliriumSeconds) emit('stage', { stage: 'delirium' })\n const every = 1 / infection.feverNoiseEvery\n if (P.infectionTime > infection.feverSeconds && Math.floor(P.infectionTime * every) !== Math.floor((P.infectionTime - dt) * every) && random() < infection.feverNoiseChance) {\n noise(P.x, P.z, infection.feverNoiseRadius)\n sound('step', infection.feverNoiseVolume)\n }\n if (P.infectionTime > infection.deathSeconds) {\n P.health = 0\n die('infection')\n return\n }\n }\n if (P.burnTimer > 0) {\n P.burnTimer -= dt\n P.health -= numbers.burnPerSecond * dt\n if (inWater(P.x, P.z)) P.burnTimer = 0\n }\n P.scentTimer = Math.max(0, P.scentTimer - dt)\n if (P.bleeding) {\n P.health -= dt * numbers.bleedPerSecond\n if (input.bandage && P.bleeding) {\n P.bleeding = 0\n message('bandaged', 2)\n }\n }\n if (P.health <= 0) {\n die(P.infected ? 'infected' : P.bleeding ? 'bled_out' : 'hunger_thirst')\n return\n }\n // grabbed: seconds to react\n if (P.grabbedBy >= 0) {\n const i = P.grabbedBy\n P.grabTimer -= dt\n if (crowd) {\n const k = 1 - Math.exp(-dt * numbers.grabFollow) // glued to the body without a jump\n crowd.hold(i, P.x - Math.sin(P.yaw) * numbers.grabOffset, P.z - Math.cos(P.yaw) * numbers.grabOffset, k, P.x, P.z)\n }\n if (wasPressed('push') && P.stamina > numbers.grabPushMinStamina) {\n P.grabPushes++\n P.stamina -= numbers.grabPushCost\n sound('step', numbers.grabPushVolume)\n }\n if (wasPressed('knife')) {\n if (random() < numbers.grabKnifeChance) {\n crowd?.damage(i, { region: numbers.grabKnifeRegion, amount: numbers.grabKnifeDamage, distance: numbers.grabKnifeDistance, cut: numbers.grabKnifeCut })\n message('knife_head', 1.5)\n release('knife')\n return\n } else message('knife_miss', 1)\n }\n if (P.grabPushes >= numbers.grabPushes) {\n crowd?.stun(i, numbers.grabPushStun, -Math.sin(viewYaw) * numbers.grabPushSpeed, -Math.cos(viewYaw) * numbers.grabPushSpeed)\n release('push')\n message('pushed_off', 1.2)\n return\n }\n if (P.grabTimer <= 0) {\n if (P.grabDrown) {\n P.health -= numbers.drownDamage\n P.hurtFlash = numbers.drownFlash\n message('drowning', 2)\n if (P.health <= 0) {\n die('drowned')\n return\n }\n P.grabTimer = numbers.grabSeconds\n P.grabPushes = 0\n return\n }\n if (P.grabNoJaw) {\n hurt(numbers.noJawDamage)\n message('no_jaw', 2)\n } else bite()\n crowd?.chase(i, numbers.grabAttackCooldown)\n release(P.grabNoJaw ? 'scratch' : 'bite')\n }\n return\n }\n // knocked down\n if (P.downTimer > 0) {\n P.downTimer -= dt\n P.vx = P.vz = 0\n if (P.downTimer <= 0) message('stood_up', 0.8)\n return\n }\n if (world.busy?.(dt)) return\n // vaulting a low wall\n if (P.vaultTimer > 0 && P.vault) {\n P.vaultTimer -= dt\n const k = 1 - P.vaultTimer / numbers.vaultSeconds\n P.x = lerp(P.vault[0], P.vault[2], k)\n P.z = lerp(P.vault[1], P.vault[3], k)\n P.y = Math.sin(k * Math.PI) * numbers.vaultHeight\n if (P.vaultTimer <= 0) {\n P.y = 0\n noise(P.x, P.z, numbers.vaultNoise)\n sound('step', numbers.vaultLandVolume)\n }\n return\n }\n if (wasPressed('vault') && P.stamina > numbers.vaultCost && (world.canVault?.() ?? !P.floor)) {\n const fx0 = -Math.sin(viewYaw)\n const fz0 = -Math.cos(viewYaw)\n for (let a = numbers.vaultScanFrom; a <= numbers.vaultScanTo; a += numbers.vaultScanStep) {\n const c = cellKind(P.x + fx0 * a, P.z + fz0 * a)\n if (c === 2) {\n for (let e = a + numbers.vaultLandFrom; e <= a + numbers.vaultLandTo; e += numbers.vaultScanStep) {\n const ex = P.x + fx0 * e\n const ez = P.z + fz0 * e\n if (!solidAt(ex, ez, numbers.vaultCheckHeight) && !solidAt(ex + fx0 * numbers.vaultClearance, ez + fz0 * numbers.vaultClearance, numbers.vaultCheckHeight)) {\n P.vault = [P.x, P.z, ex, ez]\n P.vaultTimer = numbers.vaultSeconds\n P.stamina -= numbers.vaultCost\n sound('step', numbers.vaultStartVolume)\n emit('vault', { from: [P.x, P.z], to: [ex, ez] })\n return\n }\n }\n break\n }\n if (c > 0 && c !== 3) break\n }\n }\n // movement\n const f = input.forward ?? 0\n const s = input.right ?? 0\n if (wasPressed('crouch')) P.crouch = !P.crouch\n const want = f || s\n P.running = !!(input.run && want && P.stamina > numbers.runMinStamina && !input.aim && !P.crouch)\n const fever = P.infected && infection !== null && P.infectionTime > infection.feverSeconds\n let sp = P.running ? derived.runSpeed : P.crouch ? numbers.crouchSpeed : derived.walkSpeed * numbers.walkFactor\n if (fever) sp *= infection!.feverSpeed\n if (input.aim) sp = Math.min(sp, numbers.aimSpeedCap)\n const wet = inWater(P.x, P.z)\n if (wet) sp *= numbers.waterSpeed\n if (P.running) P.stamina = Math.max(0, P.stamina - numbers.runDrain * dt)\n else P.stamina = Math.min(derived.maxStamina, P.stamina + (want ? numbers.regenMoving : numbers.regenStill) * dt)\n const fx = -Math.sin(viewYaw)\n const fz = -Math.cos(viewYaw)\n const mx = fx * f - fz * s\n const mz = fz * f + fx * s\n const ml = Math.hypot(mx, mz) || 1\n const tvx = want ? (mx / ml) * sp : 0\n const tvz = want ? (mz / ml) * sp : 0\n P.vx = lerp(P.vx, tvx, Math.min(1, dt * numbers.acceleration))\n P.vz = lerp(P.vz, tvz, Math.min(1, dt * numbers.acceleration))\n const r = numbers.radius\n const nx = P.x + P.vx * dt\n const nz = P.z + P.vz * dt\n if (!blocked(nx + Math.sign(P.vx) * r, P.z)) P.x = nx\n if (!blocked(P.x, nz + Math.sign(P.vz) * r)) P.z = nz\n world.afterMove?.(P)\n // the player does not walk through the crowd: agents pressed against the body push it out\n if (crowd) {\n const n = crowd.count()\n const rr = numbers.pushApartRadius\n for (let i = 0; i < n; i++) {\n if (!crowd.active(i) || Math.abs(crowd.y(i) - P.y) > numbers.pushApartHeight) continue\n const ex = P.x - crowd.x(i)\n const ez = P.z - crowd.z(i)\n const e2 = ex * ex + ez * ez\n if (e2 < rr * rr && e2 > 1e-5) {\n const e = Math.sqrt(e2)\n const k = ((rr - e) / e) * 0.5\n if (!solidAt(P.x + ex * k, P.z + ez * k, numbers.blockHeight)) {\n P.x += ex * k\n P.z += ez * k\n }\n }\n }\n }\n const spd = Math.hypot(P.vx, P.vz)\n // the legs follow the move even with the torso on the aim; walking backwards flips the stride\n {\n const cy = Math.cos(P.yaw)\n const sy = Math.sin(P.yaw)\n const lx = P.vx * cy - P.vz * sy\n const lz = P.vx * sy + P.vz * cy\n const back = lz < numbers.backwardsBelow ? -1 : 1\n const hip = spd > numbers.hipMinSpeed ? clamp(Math.atan2(lx * back, lz * back), -numbers.hipLimit, numbers.hipLimit) : 0\n P.hip = P.hip + (hip - P.hip) * Math.min(1, dt * numbers.hipFollow)\n P.phase += dt * (spd < numbers.cadenceMinSpeed ? 0 : numbers.cadenceBase + numbers.cadencePerSpeed * spd) * back\n }\n // the body follows the view (fast, no snap); aiming or firing, at once\n {\n const target = viewYaw + Math.PI\n let dy = target - P.yaw\n dy -= Math.round(dy / TAU_APPROX) * TAU_APPROX\n P.yaw += input.aim || input.firing ? dy : dy * Math.min(1, dt * numbers.turnFollow)\n }\n // footsteps make noise: walk 3 m, run 8 m, crouched 1 m (x the sheet's footstep noise, x2 in water)\n P.stepTimer -= dt * spd\n if (P.stepTimer <= 0 && spd > numbers.stepMinSpeed) {\n P.stepTimer = numbers.stepEvery\n noise(P.x, P.z, (P.running ? numbers.stepNoiseRun : P.crouch ? numbers.stepNoiseCrouch : numbers.stepNoiseWalk) * derived.footstepNoise * (wet ? numbers.stepNoiseWater : 1))\n sound('step', P.running ? numbers.stepVolumeRun : numbers.stepVolumeWalk)\n emit('step', { x: P.x, z: P.z, yaw: P.yaw })\n }\n // shove and melee\n if (wasPressed('push') && P.stamina > numbers.shoveCost) {\n P.stamina -= numbers.shoveCost\n shove(viewYaw)\n }\n if (wasPressed('throw')) emit('throw', {})\n if (wasPressed('knife') && P.stamina > numbers.meleeMinStamina) {\n const item = input.melee ?? fist\n P.stamina -= (item.kg ?? 0) > numbers.meleeHeavyKg ? numbers.meleeCostHeavy : numbers.meleeCostLight\n melee(item, viewYaw)\n }\n // panic: chasing agents in sight nearby\n let near = 0\n if (crowd) {\n const n = crowd.count()\n for (let i = 0; i < n; i++) if (crowd.active(i) && crowd.chasing(i)) near += crowd.panicWeight?.(i) ?? 1\n }\n P.panic = clamp(P.panic + (near * numbers.panicGain - (near ? 0 : numbers.panicDecay)) * dt, 0, numbers.panicMax)\n }\n\n return {\n get state() {\n return P\n },\n attributes,\n derived,\n numbers,\n infection,\n update,\n hurt: (amount) => hurt(amount),\n bite: () => bite(),\n grab,\n release: () => release('free'),\n knock(seconds) {\n if (!P.alive) return\n P.downTimer = Math.max(P.downTimer, seconds)\n P.crouch = false\n },\n infect,\n die,\n stage() {\n if (!P.infected || !infection) return 'none'\n return P.infectionTime > infection.deliriumSeconds ? 'delirium' : P.infectionTime > infection.feverSeconds ? 'fever' : 'malaise'\n },\n timeLeft: () => (P.infected && infection ? Math.max(0, infection.deathSeconds - P.infectionTime) : null),\n spreadFactor() {\n const panic = P.panic > derived.composure * numbers.panicSpreadAt ? numbers.panicSpread : 1\n const fever = P.infected && infection && P.infectionTime > infection.feverSeconds ? infection.feverSpread : 1\n return panic * fever * (1 + Math.hypot(P.vx, P.vz) * numbers.moveSpread)\n },\n front,\n on(event, listener) {\n let set = listeners.get(event)\n if (!set) listeners.set(event, (set = new Set()))\n set.add(listener as (event: never) => void)\n return () => void set.delete(listener as (event: never) => void)\n },\n save: () => ({ state: structuredClone(P), attributes }),\n load(save) {\n P = structuredClone(save.state)\n },\n setWorld(next) {\n defaultWorld = next\n },\n }\n}\n","/**\n * Pushing furniture on foot: hold the interaction button against a piece, a timer that grows with its mass fills, and the player then walks with it.\n * Engine-agnostic: the host says where the player wants to go and answers whether the volume of the piece can go there; this says how fast, and when it locks.\n */\n\nexport type FurniturePushPhase = 'idle' | 'grip' | 'push' | 'strain'\nexport type FurniturePushBlock = 'too_heavy' | 'obstacle' | null\n\n/** Every number of the push; a game overrides what it wants (`createFurniturePush(rules)`). */\nexport interface FurniturePushRules {\n /** The most the player's legs put on the floor, newtons: with the friction it says the heaviest thing that moves. */\n readonly forceN: number\n readonly gravity: number\n /** Static friction of a base on a floor, by the material of the piece. */\n readonly frictionByMaterial: Readonly<Record<string, number>>\n readonly defaultFriction: number\n /** The hold before the push: `base + perKg * mass`, at most `max` seconds. */\n readonly gripSeconds: { readonly base: number; readonly perKg: number; readonly max: number }\n /** Metres per second: `max` with nothing on the hands, `min` at the limit of the force. */\n readonly speed: { readonly max: number; readonly min: number }\n /** A press shorter than this is not a push (the host keeps it for a tap, such as grabbing). */\n readonly tapSeconds: number\n /** How long the effort stays after the last step that was refused, so that it does not flicker. */\n readonly strainHoldSeconds: number\n}\n\nexport const FURNITURE_PUSH_DEFAULTS: FurniturePushRules = {\n forceN: 500,\n gravity: 9.81,\n frictionByMaterial: { wood_soft: 0.4, wood_hard: 0.4, mdf: 0.4, plywood: 0.4, steel: 0.35, aluminium: 0.35, cast_iron: 0.4, copper: 0.35, plastic: 0.35, rubber: 0.8, fabric: 0.45, foam: 0.5, ceramic: 0.5, glass: 0.3, tempered_glass: 0.3, brick: 0.6, concrete: 0.65 },\n defaultFriction: 0.45,\n gripSeconds: { base: 0.4, perKg: 0.015, max: 2.5 },\n speed: { max: 1.8, min: 0.35 },\n tapSeconds: 0.2,\n strainHoldSeconds: 0.25,\n}\n\nexport type FurniturePushTarget = { readonly massKg: number; readonly material?: string }\n\nconst frictionOf = (target: FurniturePushTarget, rules: FurniturePushRules): number => (target.material !== undefined ? rules.frictionByMaterial[target.material] : undefined) ?? rules.defaultFriction\n\nconst loadShare = (target: FurniturePushTarget, rules: FurniturePushRules): number => (frictionOf(target, rules) * target.massKg * rules.gravity) / rules.forceN\n\nexport const gripSecondsFor = (massKg: number, rules: FurniturePushRules = FURNITURE_PUSH_DEFAULTS): number => Math.min(rules.gripSeconds.max, rules.gripSeconds.base + rules.gripSeconds.perKg * Math.max(0, massKg))\n\n/** Whether the legs overcome the friction of the piece on the floor. */\nexport const canPush = (target: FurniturePushTarget, rules: FurniturePushRules = FURNITURE_PUSH_DEFAULTS): boolean => loadShare(target, rules) <= 1\n\n/** Metres per second with the piece on the hands: slower the closer it is to the limit of the force, 0 past it. */\nexport const pushSpeedFor = (target: FurniturePushTarget, rules: FurniturePushRules = FURNITURE_PUSH_DEFAULTS): number => {\n const share = loadShare(target, rules)\n return share > 1 ? 0 : rules.speed.max + (rules.speed.min - rules.speed.max) * share\n}\n\nexport type FurniturePushInput = {\n /** Where the player wants to go on the floor: a unit vector, or `[0, 0]` standing. */\n readonly walk: readonly [number, number]\n /** Whether the volume of the piece (and the player behind it) can move by this offset. */\n readonly isFree: (dx: number, dz: number) => boolean\n}\n\nexport type FurniturePushStep = {\n readonly dx: number\n readonly dz: number\n /** The grip closed on this update. */\n readonly engaged: boolean\n /** A step was refused now and the one before was not: the moment the piece hits something. */\n readonly hitObstacle: boolean\n}\n\nexport interface FurniturePush {\n readonly phase: FurniturePushPhase\n /** How far the hold timer is, 0 to 1. */\n readonly progress: number\n readonly block: FurniturePushBlock\n readonly heldSeconds: number\n /** Whether the hold is still short enough to be a tap. */\n readonly isTap: boolean\n begin(target: FurniturePushTarget): void\n release(): void\n update(dt: number, input: FurniturePushInput): FurniturePushStep\n}\n\nconst STILL: FurniturePushStep = { dx: 0, dz: 0, engaged: false, hitObstacle: false }\n\nexport function createFurniturePush(overrides: Partial<FurniturePushRules> = {}): FurniturePush {\n const rules: FurniturePushRules = { ...FURNITURE_PUSH_DEFAULTS, ...overrides }\n let phase: FurniturePushPhase = 'idle'\n let target: FurniturePushTarget = { massKg: 0 }\n let held = 0\n let gripSeconds = 1\n let speed = 0\n let block: FurniturePushBlock = null\n let refused = 0\n let wasRefused = false\n\n const walkWith = (dt: number, input: FurniturePushInput): FurniturePushStep => {\n refused = Math.max(0, refused - dt)\n if (block === 'too_heavy') return STILL\n const [x, z] = input.walk\n if ((x === 0 && z === 0) || dt <= 0) {\n if (refused === 0) {\n phase = 'push'\n block = null\n wasRefused = false\n }\n return STILL\n }\n const dx = x * speed * dt\n const dz = z * speed * dt\n if (input.isFree(dx, dz)) {\n if (refused === 0) {\n phase = 'push'\n block = null\n }\n wasRefused = false\n return { dx, dz, engaged: false, hitObstacle: false }\n }\n const hitObstacle = !wasRefused\n wasRefused = true\n refused = rules.strainHoldSeconds\n phase = 'strain'\n block = 'obstacle'\n return { dx: 0, dz: 0, engaged: false, hitObstacle }\n }\n\n return {\n get phase() {\n return phase\n },\n get progress() {\n return phase === 'idle' ? 0 : Math.min(1, held / gripSeconds)\n },\n get block() {\n return block\n },\n get heldSeconds() {\n return held\n },\n get isTap() {\n return phase === 'grip' && held < rules.tapSeconds\n },\n begin(next) {\n target = next\n phase = 'grip'\n held = 0\n block = null\n refused = 0\n wasRefused = false\n gripSeconds = gripSecondsFor(next.massKg, rules)\n speed = pushSpeedFor(next, rules)\n },\n release() {\n phase = 'idle'\n held = 0\n block = null\n },\n update(dt, input) {\n if (phase === 'idle') return STILL\n held += dt\n if (phase !== 'grip') return walkWith(dt, input)\n if (held < gripSeconds) return STILL\n if (canPush(target, rules)) phase = 'push'\n else {\n phase = 'strain'\n block = 'too_heavy'\n }\n return { ...STILL, engaged: true }\n },\n }\n}\n","import type { KnownDeathCause, PlayerMessageId } from '../types'\n\nexport type PlayerText = Readonly<Record<PlayerMessageId | KnownDeathCause, string>>\n\n/** The game's own words (G 68434, 68452, 68518, 68525-68541, 68547) and the death causes it shows (G 68448, 68454, 68510, 68519, 68539). */\nconst PT_BR: PlayerText = {\n grabbed: 'AGARRADO! Aperte E várias vezes para empurrar ou F para a faca',\n grabbed_drown: 'O AFOGADO TE PUXA PARA O FUNDO! E várias vezes ou F para a faca',\n bitten: 'Você foi mordido. Não há cura.',\n bandaged: 'Curativo feito',\n knife_head: 'Faca na cabeça!',\n knife_miss: 'Errou a facada',\n pushed_off: 'Empurrou!',\n drowning: 'Afogando! Solte-se!',\n no_jaw: 'Sem mandíbula: só arranhou',\n stood_up: 'De pé!',\n infected: 'Morreu infectado',\n killed: 'Morto pela horda',\n bitten_to_death: 'Mordido',\n infection: 'A infecção venceu',\n bled_out: 'Sangrou até a morte',\n hunger_thirst: 'Fome e sede',\n drowned: 'Afogado',\n burned: 'Queimado',\n}\n\nconst EN: PlayerText = {\n grabbed: 'GRABBED! Press E repeatedly to push or F for the knife',\n grabbed_drown: 'THE DROWNED PULLS YOU UNDER! E repeatedly or F for the knife',\n bitten: 'You were bitten. There is no cure.',\n bandaged: 'Wound dressed',\n knife_head: 'Knife to the head!',\n knife_miss: 'The stab missed',\n pushed_off: 'Pushed off!',\n drowning: 'Drowning! Break free!',\n no_jaw: 'No jaw: only a scratch',\n stood_up: 'Back on your feet!',\n infected: 'Died infected',\n killed: 'Killed by the horde',\n bitten_to_death: 'Bitten',\n infection: 'The infection won',\n bled_out: 'Bled to death',\n hunger_thirst: 'Hunger and thirst',\n drowned: 'Drowned',\n burned: 'Burned',\n}\n\nexport const PLAYER_TEXT: Readonly<Record<'en' | 'pt-BR', PlayerText>> = { en: EN, 'pt-BR': PT_BR }\n\n/** The text of a message or death cause id in a locale (`pt-BR` or `en`, the language part is enough); unknown ids come back as they are. */\nexport const playerTextOf = (id: string, locale = 'pt-BR'): string => {\n const table = locale.toLowerCase().startsWith('en') ? EN : PT_BR\n return (table as Readonly<Record<string, string>>)[id] ?? id\n}\n","export type PlayerBenchText = {\n readonly group: string\n readonly name: string\n readonly controls: Readonly<Record<'infection' | 'agility' | 'vigor' | 'seed' | 'hurt' | 'bite' | 'grab' | 'push' | 'knife' | 'bandage' | 'knock' | 'crouch' | 'reset', string>>\n readonly hints: Readonly<Record<'infection' | 'agility' | 'vigor' | 'seed' | 'grab' | 'push', string>>\n readonly metrics: Readonly<Record<'health' | 'stamina' | 'bleeding' | 'wounds' | 'stage' | 'time_left' | 'panic' | 'spread' | 'grab' | 'noise' | 'steps' | 'message', string>>\n readonly stages: Readonly<Record<'none' | 'malaise' | 'fever' | 'delirium' | 'dead', string>>\n readonly scenarios: Readonly<Record<'stamina' | 'bleed_bandage' | 'normal_world' | 'infection_kills' | 'grab_break_free' | 'determinism', string>>\n readonly yes: string\n readonly no: string\n}\n\nconst EN: PlayerBenchText = {\n group: 'Player',\n name: 'Player area',\n controls: {\n infection: 'Individual infection',\n agility: 'Agility',\n vigor: 'Vigor',\n seed: 'Seed',\n hurt: 'Take a hit (10)',\n bite: 'Bite',\n grab: 'Get grabbed',\n push: 'Push (E)',\n knife: 'Knife (F)',\n bandage: 'Bandage (B)',\n knock: 'Knocked down 1.5 s',\n crouch: 'Crouch (C)',\n reset: 'Start again',\n },\n hints: {\n infection: 'Off: a normal world, wounds never infect. On: the game rule (scratch 6%, laceration 22%, bite 100%; fever at 30 s, death at 120 s).',\n agility: 'The sheet: stamina, run speed and footstep noise come from it.',\n vigor: 'The sheet: health, stamina and composure come from it.',\n seed: 'The same seed gives the same wounds and the same knife rolls.',\n grab: 'Something grabs you from behind: 3 s to push it off (6 pushes) or to land the knife (70%).',\n push: 'Shoves what is in front, or pushes off what holds you.',\n },\n metrics: {\n health: 'Health',\n stamina: 'Stamina',\n bleeding: 'Bleeding',\n wounds: 'Wounds',\n stage: 'Infection',\n time_left: 'Time left',\n panic: 'Panic',\n spread: 'Aim spread x',\n grab: 'Grab timer',\n noise: 'Last noise',\n steps: 'Footsteps',\n message: 'Message',\n },\n stages: { none: 'None', malaise: 'Malaise', fever: 'Fever', delirium: 'Delirium', dead: 'Dead' },\n scenarios: {\n stamina: 'Running drains stamina and resting gives it back',\n bleed_bandage: 'A laceration bleeds until it is dressed',\n normal_world: 'In a normal world a bite hurts and bleeds but never infects',\n infection_kills: 'With the infection on, a bite brings fever and kills at its time',\n grab_break_free: 'Six pushes break a grab before the bite',\n determinism: 'The same seed gives the same wounds',\n },\n yes: 'yes',\n no: 'no',\n}\n\nconst PT_BR: PlayerBenchText = {\n group: 'Jogador',\n name: 'Área do jogador',\n controls: {\n infection: 'Infecção individual',\n agility: 'Agilidade',\n vigor: 'Vigor',\n seed: 'Semente',\n hurt: 'Levar um golpe (10)',\n bite: 'Mordida',\n grab: 'Ser agarrado',\n push: 'Empurrar (E)',\n knife: 'Faca (F)',\n bandage: 'Curativo (B)',\n knock: 'Derrubado 1,5 s',\n crouch: 'Agachar (C)',\n reset: 'Recomeçar',\n },\n hints: {\n infection: 'Desligada: mundo normal, ferida nunca infecta. Ligada: a regra do jogo (arranhão 6%, laceração 22%, mordida 100%; febre aos 30 s, morte aos 120 s).',\n agility: 'A ficha: fôlego, velocidade de corrida e ruído dos passos saem dela.',\n vigor: 'A ficha: vida, fôlego e compostura saem dela.',\n seed: 'A mesma semente dá as mesmas feridas e os mesmos golpes de faca.',\n grab: 'Algo te agarra por trás: 3 s para empurrar (6 empurrões) ou acertar a faca (70%).',\n push: 'Empurra o que está na frente, ou se solta do que te segura.',\n },\n metrics: {\n health: 'Vida',\n stamina: 'Fôlego',\n bleeding: 'Sangrando',\n wounds: 'Feridas',\n stage: 'Infecção',\n time_left: 'Tempo restante',\n panic: 'Pânico',\n spread: 'Dispersão x',\n grab: 'Agarrão',\n noise: 'Último ruído',\n steps: 'Passos',\n message: 'Mensagem',\n },\n stages: { none: 'Nenhuma', malaise: 'Mal-estar', fever: 'Febre', delirium: 'Delírio', dead: 'Morto' },\n scenarios: {\n stamina: 'Correr gasta fôlego e descansar devolve',\n bleed_bandage: 'Uma laceração sangra até o curativo',\n normal_world: 'No mundo normal a mordida machuca e sangra, mas não infecta',\n infection_kills: 'Com a infecção ligada, a mordida dá febre e mata no tempo dela',\n grab_break_free: 'Seis empurrões soltam o agarrão antes da mordida',\n determinism: 'A mesma semente dá as mesmas feridas',\n },\n yes: 'sim',\n no: 'não',\n}\n\nexport const playerBenchTextOf = (locale: string): PlayerBenchText => (locale.toLowerCase().startsWith('en') ? EN : PT_BR)\n","import type { BenchChange, ModuleControl, ModuleHost, ModuleMetric, ModuleScenario, TestableModule } from '@adatechnology/game-contracts'\n\nimport { playerTextOf } from '../locales'\nimport { createPlayer } from '../player'\nimport type { Player, PlayerOptions } from '../player'\nimport type { PlayerAction, PlayerCrowd, PlayerInput } from '../types'\nimport { playerBenchTextOf } from './locale'\n\nexport type PlayerTestModuleOptions = PlayerOptions & { readonly locale?: string }\n\n/** What the scenarios use of the context the test room passes. */\nexport interface PlayerScenarioLike {\n expect(condition: boolean, label: string, data?: Record<string, unknown>): void\n}\n\nexport type PlayerTestModule = TestableModule<PlayerScenarioLike> & {\n /** The player in use (replaced when the bench changes the sheet, the seed or the infection). */\n readonly player: Player\n}\n\ntype CameraLike = { position: { x: number; y: number; z: number }; rotation?: { y: number }; getWorldDirection?(target: unknown): { x: number; z: number } }\ntype ThreeLike = { Vector3?: new () => { x: number; y: number; z: number } }\n\nconst MOVING_SPEED = 0.2\nconst SPRINT_SPEED = 3.4\nconst FRAME = 1 / 30\n\n/**\n * One agent standing behind the player for the grab test: the bench has no crowd, so this is the hand that holds. It follows `hold`, takes\n * the shove and the knife, and leaves the count once it lets go.\n */\nconst createGrabber = () => {\n const agent = { x: 0, z: 0, on: false, stunned: 0, hits: 0 }\n const crowd: PlayerCrowd = {\n count: () => (agent.on ? 1 : 0),\n active: () => agent.on,\n x: () => agent.x,\n z: () => agent.z,\n y: () => 0,\n floor: () => 0,\n chasing: () => agent.on,\n down: () => agent.stunned > 0,\n hold(_i, x, z, k) {\n agent.x += (x - agent.x) * k\n agent.z += (z - agent.z) * k\n },\n stun(_i, seconds) {\n agent.stunned = seconds\n agent.on = false\n },\n chase() {\n agent.on = false\n },\n damage() {\n agent.hits += 1\n agent.on = false\n },\n }\n return { agent, crowd }\n}\n\n/**\n * The player area of a test room, against the generic contracts only. The room's camera is the player: where it walks, the player walks; its speed\n * decides walking or running, so stamina, footsteps and their noise follow the viewer. The bench hurts, bites, grabs and knocks the player down,\n * switches the individual infection (off by default: a normal world) and sets the sheet. Footsteps and flesh sounds go to `host.audio`.\n */\nexport function createPlayerTestModule(options: PlayerTestModuleOptions = {}): PlayerTestModule {\n const locale = options.locale ?? 'pt-BR'\n const text = playerBenchTextOf(locale)\n const { locale: _locale, ...playerOptions } = options\n void _locale\n const settings = { infection: options.infection === undefined ? false : options.infection !== false, agility: options.attributes?.agility ?? 5, vigor: options.attributes?.vigor ?? 5, seed: options.seed ?? 1 }\n let host: ModuleHost | null = null\n const grabber = createGrabber()\n let lastNoise = 0\n let steps = 0\n let lastMessage = ''\n let pending: Partial<Record<PlayerAction, boolean>> = {}\n let bandage = false\n let last: { x: number; z: number } | null = null\n const offs: (() => void)[] = []\n\n const build = (): Player => {\n for (const off of offs.splice(0)) off()\n const made = createPlayer({ ...playerOptions, seed: settings.seed, infection: settings.infection, attributes: { ...playerOptions.attributes, agility: settings.agility, vigor: settings.vigor } })\n offs.push(made.on('noise', (e) => void (lastNoise = e.radius)))\n offs.push(made.on('step', () => void (steps += 1)))\n offs.push(made.on('message', (e) => void (lastMessage = playerTextOf(e.id, locale))))\n offs.push(made.on('sound', (e) => void host?.audio?.play({ sound: e.sound, volume: e.volume, position: e.position })))\n offs.push(made.on('died', (e) => host?.log(`player died: ${e.cause}`, { cause: e.cause })))\n lastNoise = 0\n steps = 0\n lastMessage = ''\n return made\n }\n let player = build()\n\n const view = (): { x: number; z: number; yaw: number } | null => {\n const camera = host?.camera as CameraLike | undefined\n if (!camera?.position) return null\n const Vector3 = (host?.THREE as ThreeLike | undefined)?.Vector3\n if (camera.getWorldDirection && Vector3) {\n const look = camera.getWorldDirection(new Vector3())\n return { x: camera.position.x, z: camera.position.z, yaw: Math.atan2(-look.x, -look.z) }\n }\n return { x: camera.position.x, z: camera.position.z, yaw: camera.rotation?.y ?? 0 }\n }\n\n const frame = (dt: number): void => {\n const here = view()\n const speed = here && last && dt > 0 ? Math.hypot(here.x - last.x, here.z - last.z) / dt : 0\n if (here) {\n player.state.x = here.x\n player.state.z = here.z\n }\n const input: PlayerInput = { forward: speed > MOVING_SPEED ? 1 : 0, run: speed > SPRINT_SPEED, yaw: here?.yaw ?? 0, bandage, pressed: pending }\n pending = {}\n bandage = false\n player.update(dt, input, { crowd: grabber.crowd })\n if (here) {\n player.state.x = here.x\n player.state.z = here.z\n last = { x: here.x, z: here.z }\n }\n if (grabber.agent.stunned > 0) grabber.agent.stunned = Math.max(0, grabber.agent.stunned - dt)\n }\n\n const grab = (): void => {\n const P = player.state\n grabber.agent.on = true\n grabber.agent.x = P.x - Math.sin(P.yaw) * player.numbers.grabOffset\n grabber.agent.z = P.z - Math.cos(P.yaw) * player.numbers.grabOffset\n player.grab(0)\n }\n\n const onChange = (change: BenchChange): void => {\n if (change.kind === 'action') {\n const id = change.id\n if (id === 'hurt') player.hurt(10)\n else if (id === 'bite') player.bite()\n else if (id === 'grab') grab()\n else if (id === 'knock') player.knock(1.5)\n else if (id === 'bandage') bandage = true\n else if (id === 'push' || id === 'knife' || id === 'crouch') pending = { ...pending, [id]: true }\n else if (id === 'reset') player = build()\n return\n }\n if (change.kind !== 'control') return\n const { id, value } = change\n if (id === 'infection' && typeof value === 'boolean' && value !== settings.infection) settings.infection = value\n else if ((id === 'agility' || id === 'vigor' || id === 'seed') && typeof value === 'number' && value !== settings[id]) settings[id] = value\n else return\n player = build()\n }\n\n const controls = (): ModuleControl[] => [\n { kind: 'boolean', id: 'infection', name: text.controls.infection, hint: text.hints.infection, default: settings.infection },\n { kind: 'number', id: 'agility', name: text.controls.agility, hint: text.hints.agility, min: 1, max: 8, step: 1, default: settings.agility },\n { kind: 'number', id: 'vigor', name: text.controls.vigor, hint: text.hints.vigor, min: 1, max: 8, step: 1, default: settings.vigor },\n { kind: 'number', id: 'seed', name: text.controls.seed, hint: text.hints.seed, min: 1, max: 9999, step: 1, default: settings.seed },\n { kind: 'action', id: 'hurt', name: text.controls.hurt },\n { kind: 'action', id: 'bite', name: text.controls.bite },\n { kind: 'action', id: 'grab', name: text.controls.grab, hint: text.hints.grab },\n { kind: 'action', id: 'push', name: text.controls.push, hint: text.hints.push },\n { kind: 'action', id: 'knife', name: text.controls.knife },\n { kind: 'action', id: 'bandage', name: text.controls.bandage },\n { kind: 'action', id: 'knock', name: text.controls.knock },\n { kind: 'action', id: 'crouch', name: text.controls.crouch },\n { kind: 'action', id: 'reset', name: text.controls.reset },\n ]\n\n const stageName = (): string => (player.state.alive ? text.stages[player.stage()] : text.stages.dead)\n const metrics = (): ModuleMetric[] => [\n { id: 'health', name: text.metrics.health, digits: 1, max: player.derived.maxHealth, read: () => Math.max(0, player.state.health) },\n { id: 'stamina', name: text.metrics.stamina, digits: 1, max: player.derived.maxStamina, read: () => player.state.stamina },\n { id: 'bleeding', name: text.metrics.bleeding, read: () => (player.state.bleeding ? text.yes : text.no) },\n { id: 'wounds', name: text.metrics.wounds, digits: 0, read: () => player.state.wounds.length },\n { id: 'stage', name: text.metrics.stage, read: stageName },\n { id: 'time_left', name: text.metrics.time_left, unit: 's', digits: 0, read: () => player.timeLeft() ?? 0 },\n { id: 'panic', name: text.metrics.panic, digits: 1, read: () => player.state.panic },\n { id: 'spread', name: text.metrics.spread, digits: 2, read: () => player.spreadFactor() },\n { id: 'grab_timer', name: text.metrics.grab, unit: 's', digits: 1, read: () => (player.state.grabbedBy >= 0 ? player.state.grabTimer : 0) },\n { id: 'noise', name: text.metrics.noise, unit: 'm', digits: 1, read: () => lastNoise },\n { id: 'steps', name: text.metrics.steps, digits: 0, read: () => steps },\n { id: 'message', name: text.metrics.message, read: () => lastMessage },\n ]\n\n // each scenario runs its own player, so the bench's live one is not touched\n const fresh = (extra: PlayerOptions = {}): Player => createPlayer({ ...playerOptions, ...extra })\n const run = (made: Player, seconds: number, input: PlayerInput = {}, crowd?: PlayerCrowd): void => {\n for (let t = 0; t < seconds; t += FRAME) made.update(FRAME, input, crowd ? { crowd } : undefined)\n }\n const scenarios = (): Array<ModuleScenario<PlayerScenarioLike>> => [\n {\n id: 'player_stamina',\n name: text.scenarios.stamina,\n run: ({ expect }) => {\n const made = fresh({ seed: 1 })\n const full = made.state.stamina\n run(made, 4, { forward: 1, run: true })\n const tired = made.state.stamina\n expect(tired < full - 40, 'four seconds of running spend 48 of stamina', { full, tired })\n run(made, 3)\n expect(made.state.stamina > tired, 'standing still gives it back', { tired, rested: made.state.stamina })\n },\n },\n {\n id: 'player_bleed_bandage',\n name: text.scenarios.bleed_bandage,\n run: ({ expect }) => {\n const made = fresh({ seed: 1 })\n made.bite()\n const after = made.state.health\n run(made, 2)\n expect(made.state.bleeding === 1 && made.state.health < after, 'the wound bleeds', { health: made.state.health })\n run(made, FRAME, { bandage: true })\n const dressed = made.state.health\n run(made, 2)\n expect(made.state.bleeding === 0 && made.state.health === dressed, 'dressed, it stops', { health: made.state.health })\n },\n },\n {\n id: 'player_normal_world',\n name: text.scenarios.normal_world,\n run: ({ expect }) => {\n const made = fresh({ seed: 1, infection: false })\n made.bite()\n run(made, 10)\n expect(!made.state.infected && made.state.health < made.derived.maxHealth, 'bitten, hurt, not infected', { health: made.state.health })\n },\n },\n {\n id: 'player_infection_kills',\n name: text.scenarios.infection_kills,\n run: ({ expect }) => {\n const made = fresh({ seed: 1, infection: true })\n made.bite()\n run(made, FRAME, { bandage: true })\n run(made, 40)\n expect(made.stage() === 'fever', 'fever after 30 s', { stage: made.stage() })\n run(made, 90)\n expect(!made.state.alive && made.state.cause === 'infection', 'dead at 120 s', { cause: made.state.cause })\n },\n },\n {\n id: 'player_grab_break_free',\n name: text.scenarios.grab_break_free,\n run: ({ expect }) => {\n const made = fresh({ seed: 1 })\n const { agent, crowd } = createGrabber()\n agent.on = true\n made.grab(0)\n for (let push = 0; push < 6; push++) {\n made.update(FRAME, { pressed: { push: true } }, { crowd })\n made.update(FRAME, {}, { crowd })\n }\n expect(made.state.grabbedBy === -1 && made.state.wounds.length === 0, 'free, and no bite', { grabbedBy: made.state.grabbedBy })\n },\n },\n {\n id: 'player_determinism',\n name: text.scenarios.determinism,\n run: ({ expect }) => {\n const wounds = (seed: number): string => {\n const made = fresh({ seed })\n for (let k = 0; k < 12; k++) made.hurt(1)\n return made.state.wounds.join(',')\n }\n expect(wounds(4) === wounds(4), 'the same seed gives the same wounds')\n expect(wounds(4) !== wounds(5), 'another seed gives others')\n },\n },\n ]\n\n const module: PlayerTestModule = {\n id: 'player_area',\n name: text.name,\n ground: { surface: 'dirt' },\n group: text.group,\n get player() {\n return player\n },\n items: () => [],\n controls: () => controls(),\n metrics: () => metrics(),\n scenarios: () => scenarios(),\n attach(lent) {\n host = lent\n last = null\n const off = lent.bench?.onChange(onChange)\n const offFrame = lent.onFrame(frame)\n return () => {\n off?.()\n offFrame()\n host = null\n }\n },\n }\n return module\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA,IACE,SAAW;AAAA,MACT,MAAQ;AAAA,MACR,YAAc;AAAA,MACd,SAAW;AAAA,MACX,QAAU;AAAA,MACV,WAAa;AAAA,MACb,SAAW;AAAA,IACb;AAAA,IACA,YAAc,EAAE,UAAY,GAAG,OAAS,GAAG,SAAW,GAAG,YAAc,GAAG,WAAa,GAAG,UAAY,EAAE;AAAA,IACxG,SAAW;AAAA,MACT,WAAa,EAAE,MAAQ,IAAI,OAAS,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AAAA,MACnD,YAAc,EAAE,MAAQ,IAAI,OAAS,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE;AAAA,MACpE,UAAY,EAAE,MAAQ,KAAK,OAAS,CAAC,CAAC,WAAW,IAAI,CAAC,EAAE;AAAA,MACxD,WAAa,EAAE,MAAQ,KAAK,OAAS,CAAC,EAAE;AAAA,MACxC,eAAiB,EAAE,MAAQ,KAAK,OAAS,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,QAAU,IAAI;AAAA,MAC1E,WAAa,EAAE,MAAQ,IAAI,OAAS,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE;AAAA,IACtE;AAAA,IACA,QAAU;AAAA,MACR,SAAW,EAAE,OAAS,KAAK,iBAAmB,MAAM,QAAU,MAAM;AAAA,MACpE,YAAc,EAAE,OAAS,KAAK,iBAAmB,MAAM,QAAU,KAAK;AAAA,MACtE,MAAQ,EAAE,OAAS,KAAK,iBAAmB,GAAG,QAAU,KAAK;AAAA,IAC/D;AAAA,IACA,WAAa;AAAA,MACX,cAAgB;AAAA,MAChB,iBAAmB;AAAA,MACnB,cAAgB;AAAA,MAChB,kBAAoB;AAAA,MACpB,iBAAmB;AAAA,MACnB,kBAAoB;AAAA,MACpB,kBAAoB;AAAA,MACpB,kBAAoB;AAAA,MACpB,YAAc;AAAA,MACd,aAAe;AAAA,IACjB;AAAA,IACA,SAAW;AAAA,MACT,WAAa;AAAA,MACb,YAAc;AAAA,MACd,YAAc;AAAA,MACd,WAAa;AAAA,MACb,YAAc;AAAA,MACd,eAAiB;AAAA,MACjB,gBAAkB;AAAA,MAClB,aAAe;AAAA,MACf,YAAc;AAAA,MACd,YAAc;AAAA,MACd,YAAc;AAAA,MACd,cAAgB;AAAA,MAChB,oBAAsB;AAAA,MACtB,gBAAkB;AAAA,MAClB,YAAc;AAAA,MACd,cAAgB;AAAA,MAChB,eAAiB;AAAA,MACjB,iBAAmB;AAAA,MACnB,iBAAmB;AAAA,MACnB,iBAAmB;AAAA,MACnB,mBAAqB;AAAA,MACrB,cAAgB;AAAA,MAChB,aAAe;AAAA,MACf,YAAc;AAAA,MACd,aAAe;AAAA,MACf,oBAAsB;AAAA,MACtB,cAAgB;AAAA,MAChB,WAAa;AAAA,MACb,aAAe;AAAA,MACf,eAAiB;AAAA,MACjB,aAAe;AAAA,MACf,eAAiB;AAAA,MACjB,eAAiB;AAAA,MACjB,aAAe;AAAA,MACf,gBAAkB;AAAA,MAClB,kBAAoB;AAAA,MACpB,YAAc;AAAA,MACd,kBAAoB;AAAA,MACpB,iBAAmB;AAAA,MACnB,aAAe;AAAA,MACf,YAAc;AAAA,MACd,aAAe;AAAA,MACf,YAAc;AAAA,MACd,eAAiB;AAAA,MACjB,UAAY;AAAA,MACZ,aAAe;AAAA,MACf,YAAc;AAAA,MACd,cAAgB;AAAA,MAChB,QAAU;AAAA,MACV,aAAe;AAAA,MACf,iBAAmB;AAAA,MACnB,iBAAmB;AAAA,MACnB,WAAa;AAAA,MACb,aAAe;AAAA,MACf,UAAY;AAAA,MACZ,gBAAkB;AAAA,MAClB,aAAe;AAAA,MACf,iBAAmB;AAAA,MACnB,iBAAmB;AAAA,MACnB,YAAc;AAAA,MACd,WAAa;AAAA,MACb,cAAgB;AAAA,MAChB,cAAgB;AAAA,MAChB,eAAiB;AAAA,MACjB,iBAAmB;AAAA,MACnB,gBAAkB;AAAA,MAClB,eAAiB;AAAA,MACjB,gBAAkB;AAAA,MAClB,WAAa;AAAA,MACb,aAAe;AAAA,MACf,YAAc;AAAA,MACd,WAAa;AAAA,MACb,WAAa;AAAA,MACb,YAAc;AAAA,MACd,iBAAmB;AAAA,MACnB,gBAAkB;AAAA,MAClB,gBAAkB;AAAA,MAClB,cAAgB;AAAA,MAChB,aAAe;AAAA,MACf,gBAAkB;AAAA,MAClB,WAAa;AAAA,MACb,iBAAmB;AAAA,MACnB,gBAAkB;AAAA,MAClB,uBAAyB;AAAA,MACzB,mBAAqB;AAAA,MACrB,gBAAkB;AAAA,MAClB,WAAa;AAAA,MACb,YAAc;AAAA,MACd,UAAY;AAAA,MACZ,eAAiB;AAAA,MACjB,aAAe;AAAA,MACf,YAAc;AAAA,IAChB;AAAA,IACA,MAAQ,EAAE,QAAU,GAAG,MAAQ,GAAG,OAAS,KAAK,OAAS,EAAE;AAAA,EAC7D;;;AC7HO,WAAS,UAAU,MAA4B;AACpD,QAAI,QAAQ,SAAS;AACrB,WAAO,MAAM;AACX,cAAS,QAAQ,eAAgB;AACjC,UAAI,QAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,QAAQ,CAAC;AACvD,eAAS,QAAQ,KAAK,KAAK,QAAS,UAAU,GAAI,QAAQ,EAAE;AAC5D,eAAS,QAAS,UAAU,QAAS,KAAK;AAAA,IAC5C;AAAA,EACF;;;ACYO,MAAM,kBAAkB;AA0D/B,MAAM,aAAa;AAEnB,MAAM,WAAW,CAAC,SAAwB,eAAmC;AAC3E,QAAI,QAAQ,QAAQ;AACpB,eAAW,CAAC,WAAW,WAAW,KAAK,QAAQ,MAAO,UAAS,cAAc,WAAW,SAAS;AACjG,WAAO,QAAQ,WAAW,SAAY,QAAQ,QAAQ,QAAQ;AAAA,EAChE;AAGO,MAAM,eAAe,CAAC,YAAwB,WAA4B,gBAAgB,YAAqB;AACpH,UAAM,MAAM,CAAC;AACb,eAAW,MAAM,OAAO,KAAK,QAAQ,EAAkB,KAAI,EAAE,IAAI,SAAS,SAAS,EAAE,GAAG,UAAU;AAClG,WAAO;AAAA,EACT;AAGO,MAAM,YAAY,CAAC,QAAoB,WAAiC;AAC7E,UAAM,QAAQ,OAAO,KAAK,MAAM;AAChC,UAAM,OAAO,OAAO;AACpB,QAAI,MAAM;AACV,aAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;AACzC,aAAO,OAAO,MAAM,CAAC,CAAE,EAAG;AAC1B,UAAI,OAAO,IAAK,QAAO,MAAM,CAAC;AAAA,IAChC;AACA,WAAO,MAAM,MAAM,SAAS,CAAC;AAAA,EAC/B;AAEA,MAAM,QAAQ,CAAC,GAAW,GAAW,MAAuB,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AACpF,MAAM,OAAO,CAAC,GAAW,GAAW,MAAsB,KAAK,IAAI,KAAK;AAExE,MAAM,aAAa,CAAC,SAAkB,cAAsD;AAAA,IAC1F,GAAG,UAAU,KAAK;AAAA,IAClB,GAAG,UAAU,KAAK;AAAA,IAClB,GAAG;AAAA,IACH,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,KAAK,UAAU,OAAO;AAAA,IACtB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ,QAAQ;AAAA,IAChB,SAAS,QAAQ;AAAA,IACjB,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,WAAW;AAAA,IACX,OAAO;AAAA,IACP,KAAK;AAAA,IACL,WAAW;AAAA,IACX,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,IACV,OAAO;AAAA,IACP,aAAa;AAAA,IACb,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,OAAO;AAAA,EACT;AAOO,WAAS,aAAa,UAAyB,CAAC,GAAW;AAChE,UAAM,SAAS,QAAQ,UAAU,UAAU,QAAQ,QAAQ,CAAC;AAC5D,UAAM,aAAyB,EAAE,GAAG,gBAAgB,YAAY,GAAG,QAAQ,WAAW;AACtF,UAAM,WAA4B,EAAE,GAAG,gBAAgB,SAAS,GAAG,QAAQ,QAAQ;AACnF,UAAM,UAAU,aAAa,YAAY,QAAQ;AACjD,UAAM,UAAyB,EAAE,GAAG,gBAAgB,SAAS,GAAG,QAAQ,QAAQ;AAChF,UAAM,SAAS,QAAQ,UAAU,gBAAgB;AACjD,UAAM,YACJ,QAAQ,cAAc,UAAa,QAAQ,cAAc,QAAQ,OAAO,QAAQ,cAAc,OAAO,gBAAgB,YAAY,EAAE,GAAG,gBAAgB,WAAW,GAAG,QAAQ,UAAU;AACxL,UAAM,OAAO,QAAQ,QAAQ,gBAAgB;AAC7C,UAAM,YAAY,oBAAI,IAAkD;AACxE,QAAI,IAAI,WAAW,SAAS,QAAQ,QAAQ;AAC5C,QAAI,eAA4B,QAAQ,SAAS,CAAC;AAClD,QAAI,QAAqB;AAEzB,UAAM,OAAO,CAA4B,OAAU,YAAqC;AACtF,YAAM,MAAM,UAAU,IAAI,KAAK;AAC/B,UAAI,IAAK,YAAW,YAAY,IAAK,CAAC,SAAgD,OAAO;AAAA,IAC/F;AACA,UAAM,QAAQ,CAAC,IAAmB,WAAyB,KAAK,SAAS,EAAE,OAAO,IAAI,QAAQ,UAAU,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AACzH,UAAM,QAAQ,CAAC,GAAW,GAAW,WAAyB,KAAK,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC;AAC5F,UAAM,UAAU,CAAC,IAAkC,YAA0B,KAAK,WAAW,EAAE,IAAI,QAAQ,CAAC;AAC5G,UAAM,UAAU,CAAC,GAAW,MAAuB,MAAM,UAAU,GAAG,CAAC,KAAK;AAC5E,UAAM,UAAU,CAAC,GAAW,GAAW,MAAuB,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK;AAC1F,UAAM,WAAW,CAAC,GAAW,MAAsB,MAAM,WAAW,GAAG,CAAC,KAAK;AAC7E,UAAM,UAAU,CAAC,GAAW,MAAwB,MAAM,UAAU,MAAM,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,GAAG,QAAQ,WAAW;AAC3H,UAAM,WAAW,CAAC,SAAyB,WAAW,UAAU,IAAI,KAAK,OAAO,IAAI,GAAG,mBAAmB;AAE1G,UAAM,MAAM,CAAC,UAA4B;AACvC,UAAI,CAAC,EAAE,MAAO;AACd,QAAE,QAAQ;AACV,QAAE,QAAQ;AACV,QAAE,YAAY;AACd,QAAE,YAAY;AACd,cAAQ,OAAO,CAAC;AAChB,WAAK,QAAQ,EAAE,MAAM,CAAC;AAAA,IACxB;AACA,UAAM,SAAS,CAAC,WAAyB;AACvC,UAAI,EAAE,YAAY,CAAC,UAAW;AAC9B,QAAE,WAAW;AACb,QAAE,gBAAgB;AAClB,QAAE,kBAAkB;AACpB,WAAK,YAAY,EAAE,OAAO,CAAC;AAAA,IAC7B;AACA,UAAM,UAAU,CAAC,MAAyC,WAAiB;AACzE,YAAM,KAAK,EAAE;AACb,QAAE,YAAY;AACd,UAAI,MAAM,EAAG,MAAK,YAAY,EAAE,IAAI,IAAI,CAAC;AAAA,IAC3C;AACA,UAAM,OAAO,CAAC,WAAyB;AACrC,UAAI,CAAC,EAAE,MAAO;AACd,QAAE,UAAU;AACZ,QAAE,YAAY,QAAQ;AACtB,YAAM,SAAS,QAAQ,UAAU;AACjC,YAAM,OAAO,UAAU,QAAQ,MAAM;AACrC,QAAE,OAAO,KAAK,IAAI;AAClB,UAAI,OAAO,IAAI,GAAG,OAAQ,GAAE,WAAW;AACvC,WAAK,QAAQ,EAAE,QAAQ,OAAO,KAAK,CAAC;AACpC,UAAI,aAAa,CAAC,EAAE,YAAY,OAAO,IAAI,SAAS,IAAI,EAAG,QAAO,IAAI;AACtE,UAAI,EAAE,UAAU,EAAG,KAAI,EAAE,WAAW,aAAa,QAAQ;AAAA,IAC3D;AACA,UAAM,OAAO,MAAY;AACvB,QAAE,UAAU,QAAQ;AACpB,QAAE,YAAY,QAAQ;AACtB,QAAE,WAAW;AACb,QAAE,OAAO,KAAK,MAAM;AACpB,YAAM,SAAS,QAAQ,UAAU;AACjC,WAAK,QAAQ,EAAE,QAAQ,QAAQ,YAAY,OAAO,OAAO,CAAC;AAC1D,aAAO,MAAM;AACb,cAAQ,UAAU,CAAC;AACnB,UAAI,EAAE,UAAU,EAAG,KAAI,iBAAiB;AAAA,IAC1C;AACA,UAAM,OAAO,CAAC,IAAY,QAAQ,OAAO,QAAQ,UAAgB;AAC/D,QAAE,YAAY;AACd,QAAE,YAAY,QAAQ;AACtB,QAAE,aAAa;AACf,QAAE,YAAY;AACd,QAAE,YAAY;AACd,cAAQ,QAAQ,kBAAkB,WAAW,CAAC;AAC9C,YAAM,SAAS,QAAQ,UAAU;AACjC,WAAK,WAAW,EAAE,IAAI,OAAO,MAAM,CAAC;AAAA,IACtC;AAEA,UAAM,QAAQ,CAAC,OAAe,QAAgB,KAAa,QAAiC,MAAM,UAA8B;AAC9H,YAAM,MAA0B,CAAC;AACjC,UAAI,CAAC,MAAO,QAAO;AACnB,YAAM,KAAK,CAAC,KAAK,IAAI,GAAG;AACxB,YAAM,KAAK,CAAC,KAAK,IAAI,GAAG;AACxB,YAAM,IAAI,MAAM,MAAM;AACtB,eAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAI,CAAC,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,CAAC,MAAM,EAAE,MAAO;AACpD,cAAM,KAAK,MAAM,EAAE,CAAC,IAAI,EAAE;AAC1B,cAAM,KAAK,MAAM,EAAE,CAAC,IAAI,EAAE;AAC1B,cAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,YAAI,IAAI,UAAU,KAAK,KAAK,KAAK,OAAO,KAAK,KAAK,OAAQ,KAAI,KAAK,CAAC,GAAG,CAAC,CAAC;AAAA,MAC3E;AACA,aAAO,IAAI,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAAA,IACvC;AAEA,UAAM,QAAQ,CAAC,QAAsB;AACnC,YAAM,QAAQ,QAAQ,WAAW;AACjC,YAAM,QAAQ,MAAM;AACpB,YAAM,UAAoB,CAAC;AAC3B,iBAAW,CAAC,GAAG,CAAC,KAAK,MAAM,QAAQ,YAAY,QAAQ,WAAW,GAAG,GAAG;AACtE,cAAO,KAAK,GAAG,QAAQ,YAAa,MAAO,EAAE,CAAC,IAAI,EAAE,KAAK,IAAK,QAAQ,aAAc,MAAO,EAAE,CAAC,IAAI,EAAE,KAAK,IAAK,QAAQ,UAAU;AAChI,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,WAAK,SAAS,EAAE,QAAQ,CAAC;AAAA,IAC3B;AAEA,UAAM,QAAQ,CAAC,MAAiB,QAAsB;AACpD,YAAM,IAAI,MAAM,QAAQ,kBAAkB,KAAK,SAAS,IAAI,QAAQ,WAAW,GAAG,EAAE,CAAC;AACrF,YAAM,SAAS,QAAQ,WAAW;AAClC,YAAM,EAAE,GAAG,EAAE,GAAG,KAAK,SAAS,CAAC;AAC/B,UAAI,CAAC,EAAG;AACR,YAAM,QAAQ,MAAM;AACpB,YAAM,IAAI,EAAE,CAAC;AAEb,YAAM,SAAS,MAAM,KAAK,CAAC,IAAI,IAAI,OAAO,IAAI,QAAQ,kBAAkB,IAAI,OAAO,IAAI,QAAQ,iBAAiB,IAAI,IAAI,KAAK,MAAM,OAAO,IAAI,CAAC;AAC/I,YAAM,SAAS,KAAK,UAAU,KAAK,WAAW,WAAW,QAAQ,qBAAqB,QAAQ;AAC9F,YAAM,MAAM,KAAK,IAAI,IAAI,KAAK,QAAQ,KAAK,QAAQ,cAAc;AACjE,YAAM,OAAO,GAAG,EAAE,QAAQ,QAAQ,QAAQ,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC;AAC/D,WAAK,SAAS,EAAE,QAAQ,GAAG,QAAQ,QAAQ,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC;AAAA,IAClE;AAEA,UAAM,SAAS,CAAC,IAAY,QAAqB,CAAC,GAAG,eAAmC;AACtF,cAAQ,cAAc;AACtB,UAAI,CAAC,EAAE,OAAO;AACZ,UAAE,aAAa;AACf,YAAI,EAAE,YAAY,aAAa,CAAC,EAAE,UAAU,EAAE,aAAa,UAAU,kBAAkB;AACrF,YAAE,SAAS;AACX,eAAK,UAAU,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,CAAC;AAAA,QACnD;AACA;AAAA,MACF;AACA,YAAM,UAAkD,EAAE,GAAG,MAAM,QAAQ;AAC3E,YAAM,aAAa,CAAC,WAAkC;AACpD,cAAM,IAAI,QAAQ,MAAM,MAAM;AAC9B,gBAAQ,MAAM,IAAI;AAClB,eAAO;AAAA,MACT;AACA,YAAM,UAAU,MAAM,OAAO;AAC7B,YAAM,QAAQ,MAAM;AACpB,QAAE,cAAc,KAAK,IAAI,GAAG,EAAE,cAAc,EAAE;AAC9C,QAAE,QAAQ,KAAK,IAAI,GAAG,EAAE,QAAQ,EAAE;AAClC,QAAE,YAAY,KAAK,IAAI,GAAG,EAAE,YAAY,EAAE;AAE1C,UAAI,EAAE,YAAY,WAAW;AAC3B,cAAM,SAAS,EAAE;AACjB,UAAE,iBAAiB;AACnB,YAAI,UAAU,UAAU,gBAAgB,EAAE,gBAAgB,UAAU,aAAc,MAAK,SAAS,EAAE,OAAO,QAAQ,CAAC;AAClH,YAAI,UAAU,UAAU,mBAAmB,EAAE,gBAAgB,UAAU,gBAAiB,MAAK,SAAS,EAAE,OAAO,WAAW,CAAC;AAC3H,cAAM,QAAQ,IAAI,UAAU;AAC5B,YAAI,EAAE,gBAAgB,UAAU,gBAAgB,KAAK,MAAM,EAAE,gBAAgB,KAAK,MAAM,KAAK,OAAO,EAAE,gBAAgB,MAAM,KAAK,KAAK,OAAO,IAAI,UAAU,kBAAkB;AAC3K,gBAAM,EAAE,GAAG,EAAE,GAAG,UAAU,gBAAgB;AAC1C,gBAAM,QAAQ,UAAU,gBAAgB;AAAA,QAC1C;AACA,YAAI,EAAE,gBAAgB,UAAU,cAAc;AAC5C,YAAE,SAAS;AACX,cAAI,WAAW;AACf;AAAA,QACF;AAAA,MACF;AACA,UAAI,EAAE,YAAY,GAAG;AACnB,UAAE,aAAa;AACf,UAAE,UAAU,QAAQ,gBAAgB;AACpC,YAAI,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAG,GAAE,YAAY;AAAA,MACvC;AACA,QAAE,aAAa,KAAK,IAAI,GAAG,EAAE,aAAa,EAAE;AAC5C,UAAI,EAAE,UAAU;AACd,UAAE,UAAU,KAAK,QAAQ;AACzB,YAAI,MAAM,WAAW,EAAE,UAAU;AAC/B,YAAE,WAAW;AACb,kBAAQ,YAAY,CAAC;AAAA,QACvB;AAAA,MACF;AACA,UAAI,EAAE,UAAU,GAAG;AACjB,YAAI,EAAE,WAAW,aAAa,EAAE,WAAW,aAAa,eAAe;AACvE;AAAA,MACF;AAEA,UAAI,EAAE,aAAa,GAAG;AACpB,cAAM,IAAI,EAAE;AACZ,UAAE,aAAa;AACf,YAAI,OAAO;AACT,gBAAM,IAAI,IAAI,KAAK,IAAI,CAAC,KAAK,QAAQ,UAAU;AAC/C,gBAAM,KAAK,GAAG,EAAE,IAAI,KAAK,IAAI,EAAE,GAAG,IAAI,QAAQ,YAAY,EAAE,IAAI,KAAK,IAAI,EAAE,GAAG,IAAI,QAAQ,YAAY,GAAG,EAAE,GAAG,EAAE,CAAC;AAAA,QACnH;AACA,YAAI,WAAW,MAAM,KAAK,EAAE,UAAU,QAAQ,oBAAoB;AAChE,YAAE;AACF,YAAE,WAAW,QAAQ;AACrB,gBAAM,QAAQ,QAAQ,cAAc;AAAA,QACtC;AACA,YAAI,WAAW,OAAO,GAAG;AACvB,cAAI,OAAO,IAAI,QAAQ,iBAAiB;AACtC,mBAAO,OAAO,GAAG,EAAE,QAAQ,QAAQ,iBAAiB,QAAQ,QAAQ,iBAAiB,UAAU,QAAQ,mBAAmB,KAAK,QAAQ,aAAa,CAAC;AACrJ,oBAAQ,cAAc,GAAG;AACzB,oBAAQ,OAAO;AACf;AAAA,UACF,MAAO,SAAQ,cAAc,CAAC;AAAA,QAChC;AACA,YAAI,EAAE,cAAc,QAAQ,YAAY;AACtC,iBAAO,KAAK,GAAG,QAAQ,cAAc,CAAC,KAAK,IAAI,OAAO,IAAI,QAAQ,eAAe,CAAC,KAAK,IAAI,OAAO,IAAI,QAAQ,aAAa;AAC3H,kBAAQ,MAAM;AACd,kBAAQ,cAAc,GAAG;AACzB;AAAA,QACF;AACA,YAAI,EAAE,aAAa,GAAG;AACpB,cAAI,EAAE,WAAW;AACf,cAAE,UAAU,QAAQ;AACpB,cAAE,YAAY,QAAQ;AACtB,oBAAQ,YAAY,CAAC;AACrB,gBAAI,EAAE,UAAU,GAAG;AACjB,kBAAI,SAAS;AACb;AAAA,YACF;AACA,cAAE,YAAY,QAAQ;AACtB,cAAE,aAAa;AACf;AAAA,UACF;AACA,cAAI,EAAE,WAAW;AACf,iBAAK,QAAQ,WAAW;AACxB,oBAAQ,UAAU,CAAC;AAAA,UACrB,MAAO,MAAK;AACZ,iBAAO,MAAM,GAAG,QAAQ,kBAAkB;AAC1C,kBAAQ,EAAE,YAAY,YAAY,MAAM;AAAA,QAC1C;AACA;AAAA,MACF;AAEA,UAAI,EAAE,YAAY,GAAG;AACnB,UAAE,aAAa;AACf,UAAE,KAAK,EAAE,KAAK;AACd,YAAI,EAAE,aAAa,EAAG,SAAQ,YAAY,GAAG;AAC7C;AAAA,MACF;AACA,UAAI,MAAM,OAAO,EAAE,EAAG;AAEtB,UAAI,EAAE,aAAa,KAAK,EAAE,OAAO;AAC/B,UAAE,cAAc;AAChB,cAAM,IAAI,IAAI,EAAE,aAAa,QAAQ;AACrC,UAAE,IAAI,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC;AACpC,UAAE,IAAI,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC;AACpC,UAAE,IAAI,KAAK,IAAI,IAAI,KAAK,EAAE,IAAI,QAAQ;AACtC,YAAI,EAAE,cAAc,GAAG;AACrB,YAAE,IAAI;AACN,gBAAM,EAAE,GAAG,EAAE,GAAG,QAAQ,UAAU;AAClC,gBAAM,QAAQ,QAAQ,eAAe;AAAA,QACvC;AACA;AAAA,MACF;AACA,UAAI,WAAW,OAAO,KAAK,EAAE,UAAU,QAAQ,cAAc,MAAM,WAAW,KAAK,CAAC,EAAE,QAAQ;AAC5F,cAAM,MAAM,CAAC,KAAK,IAAI,OAAO;AAC7B,cAAM,MAAM,CAAC,KAAK,IAAI,OAAO;AAC7B,iBAAS,IAAI,QAAQ,eAAe,KAAK,QAAQ,aAAa,KAAK,QAAQ,eAAe;AACxF,gBAAM,IAAI,SAAS,EAAE,IAAI,MAAM,GAAG,EAAE,IAAI,MAAM,CAAC;AAC/C,cAAI,MAAM,GAAG;AACX,qBAAS,IAAI,IAAI,QAAQ,eAAe,KAAK,IAAI,QAAQ,aAAa,KAAK,QAAQ,eAAe;AAChG,oBAAM,KAAK,EAAE,IAAI,MAAM;AACvB,oBAAM,KAAK,EAAE,IAAI,MAAM;AACvB,kBAAI,CAAC,QAAQ,IAAI,IAAI,QAAQ,gBAAgB,KAAK,CAAC,QAAQ,KAAK,MAAM,QAAQ,gBAAgB,KAAK,MAAM,QAAQ,gBAAgB,QAAQ,gBAAgB,GAAG;AAC1J,kBAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE;AAC3B,kBAAE,aAAa,QAAQ;AACvB,kBAAE,WAAW,QAAQ;AACrB,sBAAM,QAAQ,QAAQ,gBAAgB;AACtC,qBAAK,SAAS,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;AAChD;AAAA,cACF;AAAA,YACF;AACA;AAAA,UACF;AACA,cAAI,IAAI,KAAK,MAAM,EAAG;AAAA,QACxB;AAAA,MACF;AAEA,YAAM,IAAI,MAAM,WAAW;AAC3B,YAAM,IAAI,MAAM,SAAS;AACzB,UAAI,WAAW,QAAQ,EAAG,GAAE,SAAS,CAAC,EAAE;AACxC,YAAM,OAAO,KAAK;AAClB,QAAE,UAAU,CAAC,EAAE,MAAM,OAAO,QAAQ,EAAE,UAAU,QAAQ,iBAAiB,CAAC,MAAM,OAAO,CAAC,EAAE;AAC1F,YAAM,QAAQ,EAAE,YAAY,cAAc,QAAQ,EAAE,gBAAgB,UAAU;AAC9E,UAAI,KAAK,EAAE,UAAU,QAAQ,WAAW,EAAE,SAAS,QAAQ,cAAc,QAAQ,YAAY,QAAQ;AACrG,UAAI,MAAO,OAAM,UAAW;AAC5B,UAAI,MAAM,IAAK,MAAK,KAAK,IAAI,IAAI,QAAQ,WAAW;AACpD,YAAM,MAAM,QAAQ,EAAE,GAAG,EAAE,CAAC;AAC5B,UAAI,IAAK,OAAM,QAAQ;AACvB,UAAI,EAAE,QAAS,GAAE,UAAU,KAAK,IAAI,GAAG,EAAE,UAAU,QAAQ,WAAW,EAAE;AAAA,UACnE,GAAE,UAAU,KAAK,IAAI,QAAQ,YAAY,EAAE,WAAW,OAAO,QAAQ,cAAc,QAAQ,cAAc,EAAE;AAChH,YAAM,KAAK,CAAC,KAAK,IAAI,OAAO;AAC5B,YAAM,KAAK,CAAC,KAAK,IAAI,OAAO;AAC5B,YAAM,KAAK,KAAK,IAAI,KAAK;AACzB,YAAM,KAAK,KAAK,IAAI,KAAK;AACzB,YAAM,KAAK,KAAK,MAAM,IAAI,EAAE,KAAK;AACjC,YAAM,MAAM,OAAQ,KAAK,KAAM,KAAK;AACpC,YAAM,MAAM,OAAQ,KAAK,KAAM,KAAK;AACpC,QAAE,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,QAAQ,YAAY,CAAC;AAC7D,QAAE,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,QAAQ,YAAY,CAAC;AAC7D,YAAM,IAAI,QAAQ;AAClB,YAAM,KAAK,EAAE,IAAI,EAAE,KAAK;AACxB,YAAM,KAAK,EAAE,IAAI,EAAE,KAAK;AACxB,UAAI,CAAC,QAAQ,KAAK,KAAK,KAAK,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,EAAG,GAAE,IAAI;AACnD,UAAI,CAAC,QAAQ,EAAE,GAAG,KAAK,KAAK,KAAK,EAAE,EAAE,IAAI,CAAC,EAAG,GAAE,IAAI;AACnD,YAAM,YAAY,CAAC;AAEnB,UAAI,OAAO;AACT,cAAM,IAAI,MAAM,MAAM;AACtB,cAAM,KAAK,QAAQ;AACnB,iBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,cAAI,CAAC,MAAM,OAAO,CAAC,KAAK,KAAK,IAAI,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,QAAQ,gBAAiB;AAC9E,gBAAM,KAAK,EAAE,IAAI,MAAM,EAAE,CAAC;AAC1B,gBAAM,KAAK,EAAE,IAAI,MAAM,EAAE,CAAC;AAC1B,gBAAM,KAAK,KAAK,KAAK,KAAK;AAC1B,cAAI,KAAK,KAAK,MAAM,KAAK,MAAM;AAC7B,kBAAM,IAAI,KAAK,KAAK,EAAE;AACtB,kBAAM,KAAM,KAAK,KAAK,IAAK;AAC3B,gBAAI,CAAC,QAAQ,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,GAAG,QAAQ,WAAW,GAAG;AAC7D,gBAAE,KAAK,KAAK;AACZ,gBAAE,KAAK,KAAK;AAAA,YACd;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,YAAM,MAAM,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE;AAEjC;AACE,cAAM,KAAK,KAAK,IAAI,EAAE,GAAG;AACzB,cAAM,KAAK,KAAK,IAAI,EAAE,GAAG;AACzB,cAAM,KAAK,EAAE,KAAK,KAAK,EAAE,KAAK;AAC9B,cAAM,KAAK,EAAE,KAAK,KAAK,EAAE,KAAK;AAC9B,cAAM,OAAO,KAAK,QAAQ,iBAAiB,KAAK;AAChD,cAAM,MAAM,MAAM,QAAQ,cAAc,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,QAAQ,UAAU,QAAQ,QAAQ,IAAI;AACvH,UAAE,MAAM,EAAE,OAAO,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,KAAK,QAAQ,SAAS;AAClE,UAAE,SAAS,MAAM,MAAM,QAAQ,kBAAkB,IAAI,QAAQ,cAAc,QAAQ,kBAAkB,OAAO;AAAA,MAC9G;AAEA;AACE,cAAM,SAAS,UAAU,KAAK;AAC9B,YAAI,KAAK,SAAS,EAAE;AACpB,cAAM,KAAK,MAAM,KAAK,UAAU,IAAI;AACpC,UAAE,OAAO,MAAM,OAAO,MAAM,SAAS,KAAK,KAAK,KAAK,IAAI,GAAG,KAAK,QAAQ,UAAU;AAAA,MACpF;AAEA,QAAE,aAAa,KAAK;AACpB,UAAI,EAAE,aAAa,KAAK,MAAM,QAAQ,cAAc;AAClD,UAAE,YAAY,QAAQ;AACtB,cAAM,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,QAAQ,eAAe,EAAE,SAAS,QAAQ,kBAAkB,QAAQ,iBAAiB,QAAQ,iBAAiB,MAAM,QAAQ,iBAAiB,EAAE;AAC5K,cAAM,QAAQ,EAAE,UAAU,QAAQ,gBAAgB,QAAQ,cAAc;AACxE,aAAK,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,KAAK,EAAE,IAAI,CAAC;AAAA,MAC7C;AAEA,UAAI,WAAW,MAAM,KAAK,EAAE,UAAU,QAAQ,WAAW;AACvD,UAAE,WAAW,QAAQ;AACrB,cAAM,OAAO;AAAA,MACf;AACA,UAAI,WAAW,OAAO,EAAG,MAAK,SAAS,CAAC,CAAC;AACzC,UAAI,WAAW,OAAO,KAAK,EAAE,UAAU,QAAQ,iBAAiB;AAC9D,cAAM,OAAO,MAAM,SAAS;AAC5B,UAAE,YAAY,KAAK,MAAM,KAAK,QAAQ,eAAe,QAAQ,iBAAiB,QAAQ;AACtF,cAAM,MAAM,OAAO;AAAA,MACrB;AAEA,UAAI,OAAO;AACX,UAAI,OAAO;AACT,cAAM,IAAI,MAAM,MAAM;AACtB,iBAAS,IAAI,GAAG,IAAI,GAAG,IAAK,KAAI,MAAM,OAAO,CAAC,KAAK,MAAM,QAAQ,CAAC,EAAG,SAAQ,MAAM,cAAc,CAAC,KAAK;AAAA,MACzG;AACA,QAAE,QAAQ,MAAM,EAAE,SAAS,OAAO,QAAQ,aAAa,OAAO,IAAI,QAAQ,eAAe,IAAI,GAAG,QAAQ,QAAQ;AAAA,IAClH;AAEA,WAAO;AAAA,MACL,IAAI,QAAQ;AACV,eAAO;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,CAAC,WAAW,KAAK,MAAM;AAAA,MAC7B,MAAM,MAAM,KAAK;AAAA,MACjB;AAAA,MACA,SAAS,MAAM,QAAQ,MAAM;AAAA,MAC7B,MAAM,SAAS;AACb,YAAI,CAAC,EAAE,MAAO;AACd,UAAE,YAAY,KAAK,IAAI,EAAE,WAAW,OAAO;AAC3C,UAAE,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AACN,YAAI,CAAC,EAAE,YAAY,CAAC,UAAW,QAAO;AACtC,eAAO,EAAE,gBAAgB,UAAU,kBAAkB,aAAa,EAAE,gBAAgB,UAAU,eAAe,UAAU;AAAA,MACzH;AAAA,MACA,UAAU,MAAO,EAAE,YAAY,YAAY,KAAK,IAAI,GAAG,UAAU,eAAe,EAAE,aAAa,IAAI;AAAA,MACnG,eAAe;AACb,cAAM,QAAQ,EAAE,QAAQ,QAAQ,YAAY,QAAQ,gBAAgB,QAAQ,cAAc;AAC1F,cAAM,QAAQ,EAAE,YAAY,aAAa,EAAE,gBAAgB,UAAU,eAAe,UAAU,cAAc;AAC5G,eAAO,QAAQ,SAAS,IAAI,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,QAAQ;AAAA,MAC/D;AAAA,MACA;AAAA,MACA,GAAG,OAAO,UAAU;AAClB,YAAI,MAAM,UAAU,IAAI,KAAK;AAC7B,YAAI,CAAC,IAAK,WAAU,IAAI,OAAQ,MAAM,oBAAI,IAAI,CAAE;AAChD,YAAI,IAAI,QAAkC;AAC1C,eAAO,MAAM,KAAK,IAAI,OAAO,QAAkC;AAAA,MACjE;AAAA,MACA,MAAM,OAAO,EAAE,OAAO,gBAAgB,CAAC,GAAG,WAAW;AAAA,MACrD,KAAK,MAAM;AACT,YAAI,gBAAgB,KAAK,KAAK;AAAA,MAChC;AAAA,MACA,SAAS,MAAM;AACb,uBAAe;AAAA,MACjB;AAAA,IACF;AAAA,EACF;;;ACliBO,MAAM,0BAA8C;AAAA,IACzD,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,oBAAoB,EAAE,WAAW,KAAK,WAAW,KAAK,KAAK,KAAK,SAAS,KAAK,OAAO,MAAM,WAAW,MAAM,WAAW,KAAK,QAAQ,MAAM,SAAS,MAAM,QAAQ,KAAK,QAAQ,MAAM,MAAM,KAAK,SAAS,KAAK,OAAO,KAAK,gBAAgB,KAAK,OAAO,KAAK,UAAU,KAAK;AAAA,IACzQ,iBAAiB;AAAA,IACjB,aAAa,EAAE,MAAM,KAAK,OAAO,OAAO,KAAK,IAAI;AAAA,IACjD,OAAO,EAAE,KAAK,KAAK,KAAK,KAAK;AAAA,IAC7B,YAAY;AAAA,IACZ,mBAAmB;AAAA,EACrB;AAIA,MAAM,aAAa,CAAC,QAA6B,WAAuC,OAAO,aAAa,SAAY,MAAM,mBAAmB,OAAO,QAAQ,IAAI,WAAc,MAAM;AAExL,MAAM,YAAY,CAAC,QAA6B,UAAuC,WAAW,QAAQ,KAAK,IAAI,OAAO,SAAS,MAAM,UAAW,MAAM;AAEnJ,MAAM,iBAAiB,CAAC,QAAgB,QAA4B,4BAAoC,KAAK,IAAI,MAAM,YAAY,KAAK,MAAM,YAAY,OAAO,MAAM,YAAY,QAAQ,KAAK,IAAI,GAAG,MAAM,CAAC;AAG9M,MAAM,UAAU,CAAC,QAA6B,QAA4B,4BAAqC,UAAU,QAAQ,KAAK,KAAK;AAG3I,MAAM,eAAe,CAAC,QAA6B,QAA4B,4BAAoC;AACxH,UAAM,QAAQ,UAAU,QAAQ,KAAK;AACrC,WAAO,QAAQ,IAAI,IAAI,MAAM,MAAM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,OAAO;AAAA,EACjF;AA+BA,MAAM,QAA2B,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,OAAO,aAAa,MAAM;AAE7E,WAAS,oBAAoB,YAAyC,CAAC,GAAkB;AAC9F,UAAM,QAA4B,EAAE,GAAG,yBAAyB,GAAG,UAAU;AAC7E,QAAI,QAA4B;AAChC,QAAI,SAA8B,EAAE,QAAQ,EAAE;AAC9C,QAAI,OAAO;AACX,QAAI,cAAc;AAClB,QAAI,QAAQ;AACZ,QAAI,QAA4B;AAChC,QAAI,UAAU;AACd,QAAI,aAAa;AAEjB,UAAM,WAAW,CAAC,IAAY,UAAiD;AAC7E,gBAAU,KAAK,IAAI,GAAG,UAAU,EAAE;AAClC,UAAI,UAAU,YAAa,QAAO;AAClC,YAAM,CAAC,GAAG,CAAC,IAAI,MAAM;AACrB,UAAK,MAAM,KAAK,MAAM,KAAM,MAAM,GAAG;AACnC,YAAI,YAAY,GAAG;AACjB,kBAAQ;AACR,kBAAQ;AACR,uBAAa;AAAA,QACf;AACA,eAAO;AAAA,MACT;AACA,YAAM,KAAK,IAAI,QAAQ;AACvB,YAAM,KAAK,IAAI,QAAQ;AACvB,UAAI,MAAM,OAAO,IAAI,EAAE,GAAG;AACxB,YAAI,YAAY,GAAG;AACjB,kBAAQ;AACR,kBAAQ;AAAA,QACV;AACA,qBAAa;AACb,eAAO,EAAE,IAAI,IAAI,SAAS,OAAO,aAAa,MAAM;AAAA,MACtD;AACA,YAAM,cAAc,CAAC;AACrB,mBAAa;AACb,gBAAU,MAAM;AAChB,cAAQ;AACR,cAAQ;AACR,aAAO,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,OAAO,YAAY;AAAA,IACrD;AAEA,WAAO;AAAA,MACL,IAAI,QAAQ;AACV,eAAO;AAAA,MACT;AAAA,MACA,IAAI,WAAW;AACb,eAAO,UAAU,SAAS,IAAI,KAAK,IAAI,GAAG,OAAO,WAAW;AAAA,MAC9D;AAAA,MACA,IAAI,QAAQ;AACV,eAAO;AAAA,MACT;AAAA,MACA,IAAI,cAAc;AAChB,eAAO;AAAA,MACT;AAAA,MACA,IAAI,QAAQ;AACV,eAAO,UAAU,UAAU,OAAO,MAAM;AAAA,MAC1C;AAAA,MACA,MAAM,MAAM;AACV,iBAAS;AACT,gBAAQ;AACR,eAAO;AACP,gBAAQ;AACR,kBAAU;AACV,qBAAa;AACb,sBAAc,eAAe,KAAK,QAAQ,KAAK;AAC/C,gBAAQ,aAAa,MAAM,KAAK;AAAA,MAClC;AAAA,MACA,UAAU;AACR,gBAAQ;AACR,eAAO;AACP,gBAAQ;AAAA,MACV;AAAA,MACA,OAAO,IAAI,OAAO;AAChB,YAAI,UAAU,OAAQ,QAAO;AAC7B,gBAAQ;AACR,YAAI,UAAU,OAAQ,QAAO,SAAS,IAAI,KAAK;AAC/C,YAAI,OAAO,YAAa,QAAO;AAC/B,YAAI,QAAQ,QAAQ,KAAK,EAAG,SAAQ;AAAA,aAC/B;AACH,kBAAQ;AACR,kBAAQ;AAAA,QACV;AACA,eAAO,EAAE,GAAG,OAAO,SAAS,KAAK;AAAA,MACnC;AAAA,IACF;AAAA,EACF;;;ACrKA,MAAM,QAAoB;AAAA,IACxB,SAAS;AAAA,IACT,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,IACf,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AAEA,MAAM,KAAiB;AAAA,IACrB,SAAS;AAAA,IACT,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,IACf,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AAEO,MAAM,cAA4D,EAAE,IAAI,IAAI,SAAS,MAAM;AAG3F,MAAM,eAAe,CAAC,IAAY,SAAS,YAAoB;AACpE,UAAM,QAAQ,OAAO,YAAY,EAAE,WAAW,IAAI,IAAI,KAAK;AAC3D,WAAQ,MAA2C,EAAE,KAAK;AAAA,EAC5D;;;ACzCA,MAAMA,MAAsB;AAAA,IAC1B,OAAO;AAAA,IACP,MAAM;AAAA,IACN,UAAU;AAAA,MACR,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,IACA,OAAO;AAAA,MACL,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAAA,IACA,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,WAAW;AAAA,MACX,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IACX;AAAA,IACA,QAAQ,EAAE,MAAM,QAAQ,SAAS,WAAW,OAAO,SAAS,UAAU,YAAY,MAAM,OAAO;AAAA,IAC/F,WAAW;AAAA,MACT,SAAS;AAAA,MACT,eAAe;AAAA,MACf,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,KAAK;AAAA,IACL,IAAI;AAAA,EACN;AAEA,MAAMC,SAAyB;AAAA,IAC7B,OAAO;AAAA,IACP,MAAM;AAAA,IACN,UAAU;AAAA,MACR,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,IACA,OAAO;AAAA,MACL,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAAA,IACA,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,WAAW;AAAA,MACX,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IACX;AAAA,IACA,QAAQ,EAAE,MAAM,WAAW,SAAS,aAAa,OAAO,SAAS,UAAU,cAAW,MAAM,QAAQ;AAAA,IACpG,WAAW;AAAA,MACT,SAAS;AAAA,MACT,eAAe;AAAA,MACf,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,KAAK;AAAA,IACL,IAAI;AAAA,EACN;AAEO,MAAM,oBAAoB,CAAC,WAAqC,OAAO,YAAY,EAAE,WAAW,IAAI,IAAID,MAAKC;;;AC/FpH,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,QAAQ,IAAI;AAMlB,MAAM,gBAAgB,MAAM;AAC1B,UAAM,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,OAAO,SAAS,GAAG,MAAM,EAAE;AAC3D,UAAM,QAAqB;AAAA,MACzB,OAAO,MAAO,MAAM,KAAK,IAAI;AAAA,MAC7B,QAAQ,MAAM,MAAM;AAAA,MACpB,GAAG,MAAM,MAAM;AAAA,MACf,GAAG,MAAM,MAAM;AAAA,MACf,GAAG,MAAM;AAAA,MACT,OAAO,MAAM;AAAA,MACb,SAAS,MAAM,MAAM;AAAA,MACrB,MAAM,MAAM,MAAM,UAAU;AAAA,MAC5B,KAAK,IAAI,GAAG,GAAG,GAAG;AAChB,cAAM,MAAM,IAAI,MAAM,KAAK;AAC3B,cAAM,MAAM,IAAI,MAAM,KAAK;AAAA,MAC7B;AAAA,MACA,KAAK,IAAI,SAAS;AAChB,cAAM,UAAU;AAChB,cAAM,KAAK;AAAA,MACb;AAAA,MACA,QAAQ;AACN,cAAM,KAAK;AAAA,MACb;AAAA,MACA,SAAS;AACP,cAAM,QAAQ;AACd,cAAM,KAAK;AAAA,MACb;AAAA,IACF;AACA,WAAO,EAAE,OAAO,MAAM;AAAA,EACxB;AAOO,WAAS,uBAAuB,UAAmC,CAAC,GAAqB;AAC9F,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,OAAO,kBAAkB,MAAM;AACrC,UAAM,EAAE,QAAQ,SAAS,GAAG,cAAc,IAAI;AAC9C,SAAK;AACL,UAAM,WAAW,EAAE,WAAW,QAAQ,cAAc,SAAY,QAAQ,QAAQ,cAAc,OAAO,SAAS,QAAQ,YAAY,WAAW,GAAG,OAAO,QAAQ,YAAY,SAAS,GAAG,MAAM,QAAQ,QAAQ,EAAE;AAC/M,QAAI,OAA0B;AAC9B,UAAM,UAAU,cAAc;AAC9B,QAAI,YAAY;AAChB,QAAI,QAAQ;AACZ,QAAI,cAAc;AAClB,QAAI,UAAkD,CAAC;AACvD,QAAI,UAAU;AACd,QAAI,OAAwC;AAC5C,UAAM,OAAuB,CAAC;AAE9B,UAAM,QAAQ,MAAc;AAC1B,iBAAW,OAAO,KAAK,OAAO,CAAC,EAAG,KAAI;AACtC,YAAM,OAAO,aAAa,EAAE,GAAG,eAAe,MAAM,SAAS,MAAM,WAAW,SAAS,WAAW,YAAY,EAAE,GAAG,cAAc,YAAY,SAAS,SAAS,SAAS,OAAO,SAAS,MAAM,EAAE,CAAC;AACjM,WAAK,KAAK,KAAK,GAAG,SAAS,CAAC,MAAM,MAAM,YAAY,EAAE,OAAO,CAAC;AAC9D,WAAK,KAAK,KAAK,GAAG,QAAQ,MAAM,MAAM,SAAS,EAAE,CAAC;AAClD,WAAK,KAAK,KAAK,GAAG,WAAW,CAAC,MAAM,MAAM,cAAc,aAAa,EAAE,IAAI,MAAM,EAAE,CAAC;AACpF,WAAK,KAAK,KAAK,GAAG,SAAS,CAAC,MAAM,KAAK,MAAM,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,QAAQ,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;AACrH,WAAK,KAAK,KAAK,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,gBAAgB,EAAE,KAAK,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAC1F,kBAAY;AACZ,cAAQ;AACR,oBAAc;AACd,aAAO;AAAA,IACT;AACA,QAAI,SAAS,MAAM;AAEnB,UAAM,OAAO,MAAoD;AAC/D,YAAM,SAAS,MAAM;AACrB,UAAI,CAAC,QAAQ,SAAU,QAAO;AAC9B,YAAM,UAAW,MAAM,OAAiC;AACxD,UAAI,OAAO,qBAAqB,SAAS;AACvC,cAAM,OAAO,OAAO,kBAAkB,IAAI,QAAQ,CAAC;AACnD,eAAO,EAAE,GAAG,OAAO,SAAS,GAAG,GAAG,OAAO,SAAS,GAAG,KAAK,KAAK,MAAM,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,EAAE;AAAA,MACzF;AACA,aAAO,EAAE,GAAG,OAAO,SAAS,GAAG,GAAG,OAAO,SAAS,GAAG,KAAK,OAAO,UAAU,KAAK,EAAE;AAAA,IACpF;AAEA,UAAM,QAAQ,CAAC,OAAqB;AAClC,YAAM,OAAO,KAAK;AAClB,YAAM,QAAQ,QAAQ,QAAQ,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,GAAG,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK;AAC3F,UAAI,MAAM;AACR,eAAO,MAAM,IAAI,KAAK;AACtB,eAAO,MAAM,IAAI,KAAK;AAAA,MACxB;AACA,YAAM,QAAqB,EAAE,SAAS,QAAQ,eAAe,IAAI,GAAG,KAAK,QAAQ,cAAc,KAAK,MAAM,OAAO,GAAG,SAAS,SAAS,QAAQ;AAC9I,gBAAU,CAAC;AACX,gBAAU;AACV,aAAO,OAAO,IAAI,OAAO,EAAE,OAAO,QAAQ,MAAM,CAAC;AACjD,UAAI,MAAM;AACR,eAAO,MAAM,IAAI,KAAK;AACtB,eAAO,MAAM,IAAI,KAAK;AACtB,eAAO,EAAE,GAAG,KAAK,GAAG,GAAG,KAAK,EAAE;AAAA,MAChC;AACA,UAAI,QAAQ,MAAM,UAAU,EAAG,SAAQ,MAAM,UAAU,KAAK,IAAI,GAAG,QAAQ,MAAM,UAAU,EAAE;AAAA,IAC/F;AAEA,UAAM,OAAO,MAAY;AACvB,YAAM,IAAI,OAAO;AACjB,cAAQ,MAAM,KAAK;AACnB,cAAQ,MAAM,IAAI,EAAE,IAAI,KAAK,IAAI,EAAE,GAAG,IAAI,OAAO,QAAQ;AACzD,cAAQ,MAAM,IAAI,EAAE,IAAI,KAAK,IAAI,EAAE,GAAG,IAAI,OAAO,QAAQ;AACzD,aAAO,KAAK,CAAC;AAAA,IACf;AAEA,UAAM,WAAW,CAAC,WAA8B;AAC9C,UAAI,OAAO,SAAS,UAAU;AAC5B,cAAMC,MAAK,OAAO;AAClB,YAAIA,QAAO,OAAQ,QAAO,KAAK,EAAE;AAAA,iBACxBA,QAAO,OAAQ,QAAO,KAAK;AAAA,iBAC3BA,QAAO,OAAQ,MAAK;AAAA,iBACpBA,QAAO,QAAS,QAAO,MAAM,GAAG;AAAA,iBAChCA,QAAO,UAAW,WAAU;AAAA,iBAC5BA,QAAO,UAAUA,QAAO,WAAWA,QAAO,SAAU,WAAU,EAAE,GAAG,SAAS,CAACA,GAAE,GAAG,KAAK;AAAA,iBACvFA,QAAO,QAAS,UAAS,MAAM;AACxC;AAAA,MACF;AACA,UAAI,OAAO,SAAS,UAAW;AAC/B,YAAM,EAAE,IAAI,MAAM,IAAI;AACtB,UAAI,OAAO,eAAe,OAAO,UAAU,aAAa,UAAU,SAAS,UAAW,UAAS,YAAY;AAAA,gBACjG,OAAO,aAAa,OAAO,WAAW,OAAO,WAAW,OAAO,UAAU,YAAY,UAAU,SAAS,EAAE,EAAG,UAAS,EAAE,IAAI;AAAA,UACjI;AACL,eAAS,MAAM;AAAA,IACjB;AAEA,UAAM,WAAW,MAAuB;AAAA,MACtC,EAAE,MAAM,WAAW,IAAI,aAAa,MAAM,KAAK,SAAS,WAAW,MAAM,KAAK,MAAM,WAAW,SAAS,SAAS,UAAU;AAAA,MAC3H,EAAE,MAAM,UAAU,IAAI,WAAW,MAAM,KAAK,SAAS,SAAS,MAAM,KAAK,MAAM,SAAS,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,SAAS,QAAQ;AAAA,MAC3I,EAAE,MAAM,UAAU,IAAI,SAAS,MAAM,KAAK,SAAS,OAAO,MAAM,KAAK,MAAM,OAAO,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,SAAS,MAAM;AAAA,MACnI,EAAE,MAAM,UAAU,IAAI,QAAQ,MAAM,KAAK,SAAS,MAAM,MAAM,KAAK,MAAM,MAAM,KAAK,GAAG,KAAK,MAAM,MAAM,GAAG,SAAS,SAAS,KAAK;AAAA,MAClI,EAAE,MAAM,UAAU,IAAI,QAAQ,MAAM,KAAK,SAAS,KAAK;AAAA,MACvD,EAAE,MAAM,UAAU,IAAI,QAAQ,MAAM,KAAK,SAAS,KAAK;AAAA,MACvD,EAAE,MAAM,UAAU,IAAI,QAAQ,MAAM,KAAK,SAAS,MAAM,MAAM,KAAK,MAAM,KAAK;AAAA,MAC9E,EAAE,MAAM,UAAU,IAAI,QAAQ,MAAM,KAAK,SAAS,MAAM,MAAM,KAAK,MAAM,KAAK;AAAA,MAC9E,EAAE,MAAM,UAAU,IAAI,SAAS,MAAM,KAAK,SAAS,MAAM;AAAA,MACzD,EAAE,MAAM,UAAU,IAAI,WAAW,MAAM,KAAK,SAAS,QAAQ;AAAA,MAC7D,EAAE,MAAM,UAAU,IAAI,SAAS,MAAM,KAAK,SAAS,MAAM;AAAA,MACzD,EAAE,MAAM,UAAU,IAAI,UAAU,MAAM,KAAK,SAAS,OAAO;AAAA,MAC3D,EAAE,MAAM,UAAU,IAAI,SAAS,MAAM,KAAK,SAAS,MAAM;AAAA,IAC3D;AAEA,UAAM,YAAY,MAAe,OAAO,MAAM,QAAQ,KAAK,OAAO,OAAO,MAAM,CAAC,IAAI,KAAK,OAAO;AAChG,UAAM,UAAU,MAAsB;AAAA,MACpC,EAAE,IAAI,UAAU,MAAM,KAAK,QAAQ,QAAQ,QAAQ,GAAG,KAAK,OAAO,QAAQ,WAAW,MAAM,MAAM,KAAK,IAAI,GAAG,OAAO,MAAM,MAAM,EAAE;AAAA,MAClI,EAAE,IAAI,WAAW,MAAM,KAAK,QAAQ,SAAS,QAAQ,GAAG,KAAK,OAAO,QAAQ,YAAY,MAAM,MAAM,OAAO,MAAM,QAAQ;AAAA,MACzH,EAAE,IAAI,YAAY,MAAM,KAAK,QAAQ,UAAU,MAAM,MAAO,OAAO,MAAM,WAAW,KAAK,MAAM,KAAK,GAAI;AAAA,MACxG,EAAE,IAAI,UAAU,MAAM,KAAK,QAAQ,QAAQ,QAAQ,GAAG,MAAM,MAAM,OAAO,MAAM,OAAO,OAAO;AAAA,MAC7F,EAAE,IAAI,SAAS,MAAM,KAAK,QAAQ,OAAO,MAAM,UAAU;AAAA,MACzD,EAAE,IAAI,aAAa,MAAM,KAAK,QAAQ,WAAW,MAAM,KAAK,QAAQ,GAAG,MAAM,MAAM,OAAO,SAAS,KAAK,EAAE;AAAA,MAC1G,EAAE,IAAI,SAAS,MAAM,KAAK,QAAQ,OAAO,QAAQ,GAAG,MAAM,MAAM,OAAO,MAAM,MAAM;AAAA,MACnF,EAAE,IAAI,UAAU,MAAM,KAAK,QAAQ,QAAQ,QAAQ,GAAG,MAAM,MAAM,OAAO,aAAa,EAAE;AAAA,MACxF,EAAE,IAAI,cAAc,MAAM,KAAK,QAAQ,MAAM,MAAM,KAAK,QAAQ,GAAG,MAAM,MAAO,OAAO,MAAM,aAAa,IAAI,OAAO,MAAM,YAAY,EAAG;AAAA,MAC1I,EAAE,IAAI,SAAS,MAAM,KAAK,QAAQ,OAAO,MAAM,KAAK,QAAQ,GAAG,MAAM,MAAM,UAAU;AAAA,MACrF,EAAE,IAAI,SAAS,MAAM,KAAK,QAAQ,OAAO,QAAQ,GAAG,MAAM,MAAM,MAAM;AAAA,MACtE,EAAE,IAAI,WAAW,MAAM,KAAK,QAAQ,SAAS,MAAM,MAAM,YAAY;AAAA,IACvE;AAGA,UAAM,QAAQ,CAAC,QAAuB,CAAC,MAAc,aAAa,EAAE,GAAG,eAAe,GAAG,MAAM,CAAC;AAChG,UAAM,MAAM,CAAC,MAAc,SAAiB,QAAqB,CAAC,GAAG,UAA8B;AACjG,eAAS,IAAI,GAAG,IAAI,SAAS,KAAK,MAAO,MAAK,OAAO,OAAO,OAAO,QAAQ,EAAE,MAAM,IAAI,MAAS;AAAA,IAClG;AACA,UAAM,YAAY,MAAiD;AAAA,MACjE;AAAA,QACE,IAAI;AAAA,QACJ,MAAM,KAAK,UAAU;AAAA,QACrB,KAAK,CAAC,EAAE,OAAO,MAAM;AACnB,gBAAM,OAAO,MAAM,EAAE,MAAM,EAAE,CAAC;AAC9B,gBAAM,OAAO,KAAK,MAAM;AACxB,cAAI,MAAM,GAAG,EAAE,SAAS,GAAG,KAAK,KAAK,CAAC;AACtC,gBAAM,QAAQ,KAAK,MAAM;AACzB,iBAAO,QAAQ,OAAO,IAAI,+CAA+C,EAAE,MAAM,MAAM,CAAC;AACxF,cAAI,MAAM,CAAC;AACX,iBAAO,KAAK,MAAM,UAAU,OAAO,gCAAgC,EAAE,OAAO,QAAQ,KAAK,MAAM,QAAQ,CAAC;AAAA,QAC1G;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,MAAM,KAAK,UAAU;AAAA,QACrB,KAAK,CAAC,EAAE,OAAO,MAAM;AACnB,gBAAM,OAAO,MAAM,EAAE,MAAM,EAAE,CAAC;AAC9B,eAAK,KAAK;AACV,gBAAM,QAAQ,KAAK,MAAM;AACzB,cAAI,MAAM,CAAC;AACX,iBAAO,KAAK,MAAM,aAAa,KAAK,KAAK,MAAM,SAAS,OAAO,oBAAoB,EAAE,QAAQ,KAAK,MAAM,OAAO,CAAC;AAChH,cAAI,MAAM,OAAO,EAAE,SAAS,KAAK,CAAC;AAClC,gBAAM,UAAU,KAAK,MAAM;AAC3B,cAAI,MAAM,CAAC;AACX,iBAAO,KAAK,MAAM,aAAa,KAAK,KAAK,MAAM,WAAW,SAAS,qBAAqB,EAAE,QAAQ,KAAK,MAAM,OAAO,CAAC;AAAA,QACvH;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,MAAM,KAAK,UAAU;AAAA,QACrB,KAAK,CAAC,EAAE,OAAO,MAAM;AACnB,gBAAM,OAAO,MAAM,EAAE,MAAM,GAAG,WAAW,MAAM,CAAC;AAChD,eAAK,KAAK;AACV,cAAI,MAAM,EAAE;AACZ,iBAAO,CAAC,KAAK,MAAM,YAAY,KAAK,MAAM,SAAS,KAAK,QAAQ,WAAW,8BAA8B,EAAE,QAAQ,KAAK,MAAM,OAAO,CAAC;AAAA,QACxI;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,MAAM,KAAK,UAAU;AAAA,QACrB,KAAK,CAAC,EAAE,OAAO,MAAM;AACnB,gBAAM,OAAO,MAAM,EAAE,MAAM,GAAG,WAAW,KAAK,CAAC;AAC/C,eAAK,KAAK;AACV,cAAI,MAAM,OAAO,EAAE,SAAS,KAAK,CAAC;AAClC,cAAI,MAAM,EAAE;AACZ,iBAAO,KAAK,MAAM,MAAM,SAAS,oBAAoB,EAAE,OAAO,KAAK,MAAM,EAAE,CAAC;AAC5E,cAAI,MAAM,EAAE;AACZ,iBAAO,CAAC,KAAK,MAAM,SAAS,KAAK,MAAM,UAAU,aAAa,iBAAiB,EAAE,OAAO,KAAK,MAAM,MAAM,CAAC;AAAA,QAC5G;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,MAAM,KAAK,UAAU;AAAA,QACrB,KAAK,CAAC,EAAE,OAAO,MAAM;AACnB,gBAAM,OAAO,MAAM,EAAE,MAAM,EAAE,CAAC;AAC9B,gBAAM,EAAE,OAAO,MAAM,IAAI,cAAc;AACvC,gBAAM,KAAK;AACX,eAAK,KAAK,CAAC;AACX,mBAAS,OAAO,GAAG,OAAO,GAAG,QAAQ;AACnC,iBAAK,OAAO,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC;AACzD,iBAAK,OAAO,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC;AAAA,UAClC;AACA,iBAAO,KAAK,MAAM,cAAc,MAAM,KAAK,MAAM,OAAO,WAAW,GAAG,qBAAqB,EAAE,WAAW,KAAK,MAAM,UAAU,CAAC;AAAA,QAChI;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,MAAM,KAAK,UAAU;AAAA,QACrB,KAAK,CAAC,EAAE,OAAO,MAAM;AACnB,gBAAM,SAAS,CAAC,SAAyB;AACvC,kBAAM,OAAO,MAAM,EAAE,KAAK,CAAC;AAC3B,qBAAS,IAAI,GAAG,IAAI,IAAI,IAAK,MAAK,KAAK,CAAC;AACxC,mBAAO,KAAK,MAAM,OAAO,KAAK,GAAG;AAAA,UACnC;AACA,iBAAO,OAAO,CAAC,MAAM,OAAO,CAAC,GAAG,qCAAqC;AACrE,iBAAO,OAAO,CAAC,MAAM,OAAO,CAAC,GAAG,2BAA2B;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAA2B;AAAA,MAC/B,IAAI;AAAA,MACJ,MAAM,KAAK;AAAA,MACX,QAAQ,EAAE,SAAS,OAAO;AAAA,MAC1B,OAAO,KAAK;AAAA,MACZ,IAAI,SAAS;AACX,eAAO;AAAA,MACT;AAAA,MACA,OAAO,MAAM,CAAC;AAAA,MACd,UAAU,MAAM,SAAS;AAAA,MACzB,SAAS,MAAM,QAAQ;AAAA,MACvB,WAAW,MAAM,UAAU;AAAA,MAC3B,OAAO,MAAM;AACX,eAAO;AACP,eAAO;AACP,cAAM,MAAM,KAAK,OAAO,SAAS,QAAQ;AACzC,cAAM,WAAW,KAAK,QAAQ,KAAK;AACnC,eAAO,MAAM;AACX,gBAAM;AACN,mBAAS;AACT,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;","names":["EN","PT_BR","id"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/data/defaults.json","../src/rng.ts","../src/player.ts","../src/furniture-push.ts","../src/locales/index.ts","../src/bench/locale.ts","../src/bench/module.ts","../src/door-use.ts"],"sourcesContent":["export { PLAYER_DEFAULTS, createPlayer, deriveVitals, drawWound } from './player'\nexport type { Player, PlayerOptions } from './player'\nexport { createRng } from './rng'\nexport { FURNITURE_PUSH_DEFAULTS, canPush, createFurniturePush, gripSecondsFor, pushSpeedFor } from './furniture-push'\nexport type { FurniturePush, FurniturePushBlock, FurniturePushInput, FurniturePushPhase, FurniturePushRules, FurniturePushStep, FurniturePushTarget } from './furniture-push'\nexport { PLAYER_TEXT, playerTextOf } from './locales'\nexport type { PlayerText } from './locales'\nexport { createPlayerTestModule } from './bench/module'\nexport type { PlayerTestModule, PlayerTestModuleOptions } from './bench/module'\nexport type * from './types'\nexport { DOOR_USE_DEFAULTS, createDoorUse, swingSecondsFor } from './door-use'\nexport type { DoorUse, DoorUseBlock, DoorUsePhase, DoorUseRules, DoorUseStep, DoorUseTarget } from './door-use'\n","{\n \"sources\": {\n \"game\": \"specs/001-migracao-entregas-dos-times/artefatos/2UG1Mhe9LqJkQKKVsJkTWR/jogo.js\",\n \"attributes\": \"G 62004 FICHA (Personagens 3.2: every attribute 5, no traits)\",\n \"derived\": \"G 62005-62012 DERIV\",\n \"wounds\": \"G 62016 FERIDA (Personagens 3.7): share of each wound kind, and its infection chance (used only when an infection rule is on)\",\n \"infection\": \"G 62015 INFEC (the slice's accelerated clock: fever 30 s, delirium 70 s, death 120 s, reanimation 8 s after); G 68509 fever noise\",\n \"numbers\": \"G 68427-68640 player, playerUpdate, frontZombies, shove, knife; G 68678-68681 the aim spread modifiers; G 65507 walkCad\"\n },\n \"attributes\": { \"strength\": 5, \"vigor\": 5, \"agility\": 5, \"perception\": 5, \"intellect\": 5, \"presence\": 5 },\n \"derived\": {\n \"maxHealth\": { \"base\": 70, \"terms\": [[\"vigor\", 6]] },\n \"maxStamina\": { \"base\": 40, \"terms\": [[\"vigor\", 6], [\"agility\", 4]] },\n \"runSpeed\": { \"base\": 5.2, \"terms\": [[\"agility\", 0.12]] },\n \"walkSpeed\": { \"base\": 1.6, \"terms\": [] },\n \"footstepNoise\": { \"base\": 100, \"terms\": [[\"agility\", -4]], \"divide\": 100 },\n \"composure\": { \"base\": 20, \"terms\": [[\"vigor\", 3], [\"presence\", 4]] }\n },\n \"wounds\": {\n \"scratch\": { \"share\": 0.6, \"infectionChance\": 0.06, \"bleeds\": false },\n \"laceration\": { \"share\": 0.3, \"infectionChance\": 0.22, \"bleeds\": true },\n \"bite\": { \"share\": 0.1, \"infectionChance\": 1, \"bleeds\": true }\n },\n \"infection\": {\n \"feverSeconds\": 30,\n \"deliriumSeconds\": 70,\n \"deathSeconds\": 120,\n \"reanimateSeconds\": 8,\n \"feverNoiseEvery\": 2,\n \"feverNoiseChance\": 0.5,\n \"feverNoiseRadius\": 10,\n \"feverNoiseVolume\": 2,\n \"feverSpeed\": 0.85,\n \"feverSpread\": 1.5\n },\n \"numbers\": {\n \"hurtFlash\": 0.4,\n \"hurtVolume\": 0.8,\n \"biteDamage\": 25,\n \"biteFlash\": 0.8,\n \"biteVolume\": 1.2,\n \"burnPerSecond\": 3,\n \"bleedPerSecond\": 0.15,\n \"grabSeconds\": 3,\n \"grabVolume\": 1,\n \"grabFollow\": 12,\n \"grabOffset\": 0.55,\n \"grabPushCost\": 6,\n \"grabPushMinStamina\": 5,\n \"grabPushVolume\": 1.5,\n \"grabPushes\": 6,\n \"grabPushStun\": 1.2,\n \"grabPushSpeed\": 3,\n \"grabKnifeChance\": 0.7,\n \"grabKnifeRegion\": 0,\n \"grabKnifeDamage\": 22,\n \"grabKnifeDistance\": 0.5,\n \"grabKnifeCut\": 0.7,\n \"drownDamage\": 30,\n \"drownFlash\": 0.8,\n \"noJawDamage\": 8,\n \"grabAttackCooldown\": 2,\n \"vaultSeconds\": 0.7,\n \"vaultCost\": 15,\n \"vaultHeight\": 1.9,\n \"vaultScanFrom\": 0.3,\n \"vaultScanTo\": 1.0,\n \"vaultScanStep\": 0.1,\n \"vaultLandFrom\": 0.4,\n \"vaultLandTo\": 1.4,\n \"vaultClearance\": 0.3,\n \"vaultCheckHeight\": 0.4,\n \"vaultNoise\": 6,\n \"vaultStartVolume\": 0.8,\n \"vaultLandVolume\": 1,\n \"crouchSpeed\": 1.0,\n \"walkFactor\": 1.35,\n \"aimSpeedCap\": 1.4,\n \"waterSpeed\": 0.55,\n \"runMinStamina\": 1,\n \"runDrain\": 12,\n \"regenMoving\": 4,\n \"regenStill\": 8,\n \"acceleration\": 10,\n \"radius\": 0.3,\n \"blockHeight\": 0.4,\n \"pushApartRadius\": 0.55,\n \"pushApartHeight\": 1.2,\n \"hipFollow\": 10,\n \"hipMinSpeed\": 0.3,\n \"hipLimit\": 0.9,\n \"backwardsBelow\": -0.1,\n \"cadenceBase\": 0.5,\n \"cadencePerSpeed\": 0.3,\n \"cadenceMinSpeed\": 0.05,\n \"turnFollow\": 12,\n \"stepEvery\": 0.75,\n \"stepMinSpeed\": 0.3,\n \"stepNoiseRun\": 8,\n \"stepNoiseWalk\": 3,\n \"stepNoiseCrouch\": 1,\n \"stepNoiseWater\": 2,\n \"stepVolumeRun\": 0.6,\n \"stepVolumeWalk\": 0.3,\n \"shoveCost\": 10,\n \"shoveVolume\": 1.2,\n \"shoveRange\": 1.6,\n \"shoveCone\": 0.3,\n \"shoveStun\": 0.9,\n \"shoveSpeed\": 2.5,\n \"meleeMinStamina\": 5,\n \"meleeCostLight\": 5,\n \"meleeCostHeavy\": 12,\n \"meleeHeavyKg\": 1.5,\n \"meleeVolume\": 0.6,\n \"meleeRangeBase\": 0.9,\n \"meleeCone\": 0.5,\n \"meleeHeadChance\": 0.35,\n \"meleeArmChance\": 0.5,\n \"meleeStrengthPerPoint\": 0.06,\n \"meleeStrengthBase\": 5,\n \"meleeCritToCut\": 60,\n \"panicGain\": 1.2,\n \"panicDecay\": 3,\n \"panicMax\": 100,\n \"panicSpreadAt\": 0.6,\n \"panicSpread\": 1.4,\n \"moveSpread\": 0.4\n },\n \"fist\": { \"damage\": 8, \"crit\": 0, \"reach\": 0.5, \"noise\": 1 }\n}\n","const FNV_OFFSET = 0x811c9dc5\nconst FNV_PRIME = 0x01000193\nconst MIX = 0x9e3779b1\n\n/** Deterministic mulberry32 generator; returns floats in [0, 1). */\nexport function createRng(seed: number): () => number {\n let state = seed >>> 0\n return () => {\n state = (state + 0x6d2b79f5) >>> 0\n let mixed = Math.imul(state ^ (state >>> 15), state | 1)\n mixed ^= mixed + Math.imul(mixed ^ (mixed >>> 7), mixed | 61)\n return ((mixed ^ (mixed >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** A seed for the stream called `name`: the same seed gives each name its own sequence, so lightning never shifts the schedule. */\nexport function streamSeed(seed: number, name: string): number {\n let hash = FNV_OFFSET\n for (let index = 0; index < name.length; index++) hash = Math.imul(hash ^ name.charCodeAt(index), FNV_PRIME) >>> 0\n return Math.imul((seed >>> 0) ^ hash, MIX) >>> 0\n}\n\nexport function createStream(seed: number, name: string): () => number {\n return createRng(streamSeed(seed, name))\n}\n\nexport function drawBetween(rng: () => number, range: readonly [min: number, max: number]): number {\n return range[0] + rng() * (range[1] - range[0])\n}\n","import defaults from './data/defaults.json'\nimport { createRng } from './rng'\nimport type {\n Attributes,\n DeathCause,\n Derived,\n DerivedFormulas,\n DerivedId,\n InfectionRule,\n LinearFormula,\n MeleeItem,\n PlayerAction,\n PlayerCrowd,\n PlayerEventMap,\n PlayerEventName,\n PlayerInput,\n PlayerMessageId,\n PlayerNumbers,\n PlayerSave,\n PlayerSoundId,\n PlayerState,\n PlayerWorld,\n WoundTable,\n} from './types'\n\nexport const PLAYER_DEFAULTS = defaults as unknown as {\n readonly sources: Readonly<Record<string, string>>\n readonly attributes: Attributes\n readonly derived: DerivedFormulas\n readonly wounds: WoundTable\n readonly infection: InfectionRule\n readonly numbers: PlayerNumbers\n readonly fist: MeleeItem\n}\n\nexport type PlayerOptions = {\n /** The random stream (the game passes its single stream). Default `createRng(seed)`. */\n readonly random?: () => number\n readonly seed?: number\n /** The sheet: every attribute 5 by default. */\n readonly attributes?: Partial<Attributes>\n readonly derived?: Partial<DerivedFormulas>\n readonly wounds?: WoundTable\n /** An individual infection (`true` uses the defaults; an object patches them). Off by default: the normal world comes first. */\n readonly infection?: boolean | Partial<InfectionRule>\n readonly numbers?: Partial<PlayerNumbers>\n readonly fist?: MeleeItem\n readonly position?: { readonly x?: number; readonly z?: number; readonly yaw?: number }\n readonly world?: PlayerWorld\n}\n\nexport type Player = {\n readonly state: PlayerState\n readonly attributes: Attributes\n readonly derived: Derived\n readonly numbers: PlayerNumbers\n readonly infection: InfectionRule | null\n update(dt: number, input?: PlayerInput, world?: PlayerWorld): void\n /** A hit that opens a wound (drawn from the wound table) and may infect. `by` is the agent that hit, if any. */\n hurt(amount: number, by?: number): void\n /** A bite: damage, bleeding, a bite wound and (with an infection rule) the infection. */\n bite(by?: number): void\n grab(by: number, noJaw?: boolean, drown?: boolean): void\n release(): void\n knock(seconds: number): void\n infect(source: string): void\n /** Kills the player with a cause (the host's deaths: a fall, a fire). */\n die(cause: DeathCause): void\n /** Infection stage: `none`, `malaise`, `fever`, `delirium`. */\n stage(): 'none' | 'malaise' | 'fever' | 'delirium'\n /** Seconds the infection has left, or null. */\n timeLeft(): number | null\n /** What the player's state does to aim spread (panic, fever, moving); the weapon multiplies its own spread by it. */\n spreadFactor(): number\n /** The agents in front (nearest first) within `range` m and a cone of `cosMin`, as `[distance, index]`. */\n front(range: number, cosMin: number, yaw: number, crowd?: PlayerCrowd): [number, number][]\n on<K extends PlayerEventName>(event: K, listener: (event: PlayerEventMap[K]) => void): () => void\n save(): PlayerSave\n load(save: PlayerSave): void\n /** The world `update` uses when it is given none. */\n setWorld(world: PlayerWorld): void\n}\n\nconst TAU_APPROX = 6.2832\n\nconst evaluate = (formula: LinearFormula, attributes: Attributes): number => {\n let value = formula.base\n for (const [attribute, coefficient] of formula.terms) value += coefficient * attributes[attribute]\n return formula.divide === undefined ? value : value / formula.divide\n}\n\n/** The derived values of a sheet (the game's `DERIV`). */\nexport const deriveVitals = (attributes: Attributes, formulas: DerivedFormulas = PLAYER_DEFAULTS.derived): Derived => {\n const out = {} as Record<DerivedId, number>\n for (const id of Object.keys(formulas) as DerivedId[]) out[id] = evaluate(formulas[id], attributes)\n return out\n}\n\n/** Which wound a hit opens: one draw, the kinds in the listed order, the last one takes the rest (the game's `FERIDA` draw). */\nexport const drawWound = (wounds: WoundTable, random: () => number): string => {\n const kinds = Object.keys(wounds)\n const draw = random()\n let acc = 0\n for (let k = 0; k < kinds.length - 1; k++) {\n acc += wounds[kinds[k]!]!.share\n if (draw < acc) return kinds[k]!\n }\n return kinds[kinds.length - 1]!\n}\n\nconst clamp = (v: number, a: number, b: number): number => (v < a ? a : v > b ? b : v)\nconst lerp = (a: number, b: number, t: number): number => a + (b - a) * t\n\nconst freshState = (derived: Derived, position: PlayerOptions['position']): PlayerState => ({\n x: position?.x ?? 0,\n z: position?.z ?? 0,\n y: 0,\n vx: 0,\n vz: 0,\n yaw: position?.yaw ?? 0,\n floor: 0,\n alive: true,\n turned: false,\n health: derived.maxHealth,\n stamina: derived.maxStamina,\n crouch: false,\n running: false,\n stepTimer: 0,\n phase: 0,\n hip: 0,\n grabbedBy: -1,\n grabTimer: 0,\n grabPushes: 0,\n grabNoJaw: false,\n grabDrown: false,\n infected: false,\n infectionTime: 0,\n infectionSource: '',\n wounds: [],\n bleeding: 0,\n blind: 0,\n screamBoost: 0,\n panic: 0,\n hurtFlash: 0,\n deathTime: 0,\n cause: '',\n downTimer: 0,\n burnTimer: 0,\n scentTimer: 0,\n vaultTimer: 0,\n vault: null,\n})\n\n/**\n * The player body: a literal port of the team game's `player` and `playerUpdate` (G 68427-68640) with the world, the crowd and the input as\n * arguments instead of globals. The draws on `random` happen in the game's order (wound kind, infection, the fever cough, the knife when grabbed,\n * the melee region), so a game that passes its own stream keeps its sequence.\n */\nexport function createPlayer(options: PlayerOptions = {}): Player {\n const random = options.random ?? createRng(options.seed ?? 1)\n const attributes: Attributes = { ...PLAYER_DEFAULTS.attributes, ...options.attributes }\n const formulas: DerivedFormulas = { ...PLAYER_DEFAULTS.derived, ...options.derived }\n const derived = deriveVitals(attributes, formulas)\n const numbers: PlayerNumbers = { ...PLAYER_DEFAULTS.numbers, ...options.numbers }\n const wounds = options.wounds ?? PLAYER_DEFAULTS.wounds\n const infection: InfectionRule | null =\n options.infection === undefined || options.infection === false ? null : options.infection === true ? PLAYER_DEFAULTS.infection : { ...PLAYER_DEFAULTS.infection, ...options.infection }\n const fist = options.fist ?? PLAYER_DEFAULTS.fist\n const listeners = new Map<PlayerEventName, Set<(event: never) => void>>()\n let P = freshState(derived, options.position)\n let defaultWorld: PlayerWorld = options.world ?? {}\n let world: PlayerWorld = defaultWorld\n\n const emit = <K extends PlayerEventName>(event: K, payload: PlayerEventMap[K]): void => {\n const set = listeners.get(event)\n if (set) for (const listener of set) (listener as (event: PlayerEventMap[K]) => void)(payload)\n }\n const sound = (id: PlayerSoundId, volume: number): void => emit('sound', { sound: id, volume, position: [P.x, P.y, P.z] })\n const noise = (x: number, z: number, radius: number): void => emit('noise', { x, z, radius })\n const message = (id: PlayerMessageId | DeathCause, seconds: number): void => emit('message', { id, seconds })\n const inWater = (x: number, z: number): boolean => world.inWater?.(x, z) ?? false\n const solidAt = (x: number, z: number, y: number): boolean => world.solidAt?.(x, z, y) ?? false\n const cellKind = (x: number, z: number): number => world.cellKind?.(x, z) ?? 0\n const blocked = (x: number, z: number): boolean => (world.blocked ? world.blocked(x, z) : solidAt(x, z, numbers.blockHeight))\n const chanceOf = (kind: string): number => infection?.chances?.[kind] ?? wounds[kind]?.infectionChance ?? 0\n\n const die = (cause: DeathCause): void => {\n if (!P.alive) return\n P.alive = false\n P.cause = cause\n P.deathTime = 0\n P.grabbedBy = -1\n message(cause, 6)\n emit('died', { cause })\n }\n const infect = (source: string): void => {\n if (P.infected || !infection) return\n P.infected = true\n P.infectionTime = 0\n P.infectionSource = source\n emit('infected', { source })\n }\n const release = (how: PlayerEventMap['released']['how'] = 'free'): void => {\n const by = P.grabbedBy\n P.grabbedBy = -1\n if (by >= 0) emit('released', { by, how })\n }\n const hurt = (amount: number): void => {\n if (!P.alive) return\n P.health -= amount\n P.hurtFlash = numbers.hurtFlash\n sound('flesh', numbers.hurtVolume)\n const kind = drawWound(wounds, random)\n P.wounds.push(kind)\n if (wounds[kind]?.bleeds) P.bleeding = 1\n emit('hurt', { amount, wound: kind })\n if (infection && !P.infected && random() < chanceOf(kind)) infect(kind)\n if (P.health <= 0) die(P.infected ? 'infected' : 'killed')\n }\n const bite = (): void => {\n P.health -= numbers.biteDamage\n P.hurtFlash = numbers.biteFlash\n P.bleeding = 1\n P.wounds.push('bite')\n sound('flesh', numbers.biteVolume)\n emit('hurt', { amount: numbers.biteDamage, wound: 'bite' })\n infect('bite')\n message('bitten', 5)\n if (P.health <= 0) die('bitten_to_death')\n }\n const grab = (by: number, noJaw = false, drown = false): void => {\n P.grabbedBy = by\n P.grabTimer = numbers.grabSeconds\n P.grabPushes = 0\n P.grabNoJaw = noJaw\n P.grabDrown = drown\n message(drown ? 'grabbed_drown' : 'grabbed', 3)\n sound('flesh', numbers.grabVolume)\n emit('grabbed', { by, noJaw, drown })\n }\n\n const front = (range: number, cosMin: number, yaw: number, crowd: PlayerCrowd | undefined = world.crowd): [number, number][] => {\n const out: [number, number][] = []\n if (!crowd) return out\n const fx = -Math.sin(yaw)\n const fz = -Math.cos(yaw)\n const n = crowd.count()\n for (let i = 0; i < n; i++) {\n if (!crowd.active(i) || crowd.floor(i) !== P.floor) continue\n const ex = crowd.x(i) - P.x\n const ez = crowd.z(i) - P.z\n const d = Math.hypot(ex, ez)\n if (d < range && (ex * fx + ez * fz) / (d || 1) > cosMin) out.push([d, i])\n }\n return out.sort((a, b) => a[0] - b[0])\n }\n\n const shove = (yaw: number): void => {\n sound('step', numbers.shoveVolume)\n const crowd = world.crowd\n const targets: number[] = []\n for (const [d, i] of front(numbers.shoveRange, numbers.shoveCone, yaw)) {\n crowd!.stun(i, numbers.shoveStun, ((crowd!.x(i) - P.x) / d) * numbers.shoveSpeed, ((crowd!.z(i) - P.z) / d) * numbers.shoveSpeed)\n targets.push(i)\n }\n emit('shove', { targets })\n }\n\n const melee = (item: MeleeItem, yaw: number): void => {\n const t = front(numbers.meleeRangeBase + (item.reach ?? 0), numbers.meleeCone, yaw)[0]\n sound('flesh', numbers.meleeVolume)\n noise(P.x, P.z, item.noise || 1)\n if (!t) return\n const crowd = world.crowd!\n const i = t[1]\n // a blow to the head is x3 in melee; on the ground or crawling it is an execution\n const region = crowd.down(i) ? 0 : random() < numbers.meleeHeadChance ? 0 : random() < numbers.meleeArmChance ? 1 : 2 + Math.floor(random() * 2)\n const damage = item.damage * (1 + (attributes.strength - numbers.meleeStrengthBase) * numbers.meleeStrengthPerPoint)\n const cut = Math.min(1, (item.crit || 0) / numbers.meleeCritToCut)\n crowd.damage(i, { region, amount: damage, distance: t[0], cut })\n emit('melee', { target: i, region, damage, distance: t[0], cut })\n }\n\n const update = (dt: number, input: PlayerInput = {}, frameWorld?: PlayerWorld): void => {\n world = frameWorld ?? defaultWorld\n if (!P.alive) {\n P.deathTime += dt\n if (P.infected && infection && !P.turned && P.deathTime >= infection.reanimateSeconds) {\n P.turned = true\n emit('turned', { x: P.x, z: P.z, floor: P.floor })\n }\n return\n }\n const pressed: Partial<Record<PlayerAction, boolean>> = { ...input.pressed }\n const wasPressed = (action: PlayerAction): boolean => {\n const v = pressed[action] === true\n pressed[action] = false\n return v\n }\n const viewYaw = input.yaw ?? 0\n const crowd = world.crowd\n P.screamBoost = Math.max(0, P.screamBoost - dt)\n P.blind = Math.max(0, P.blind - dt)\n P.hurtFlash = Math.max(0, P.hurtFlash - dt)\n // infection on its own clock\n if (P.infected && infection) {\n const before = P.infectionTime\n P.infectionTime += dt\n if (before <= infection.feverSeconds && P.infectionTime > infection.feverSeconds) emit('stage', { stage: 'fever' })\n if (before <= infection.deliriumSeconds && P.infectionTime > infection.deliriumSeconds) emit('stage', { stage: 'delirium' })\n const every = 1 / infection.feverNoiseEvery\n if (P.infectionTime > infection.feverSeconds && Math.floor(P.infectionTime * every) !== Math.floor((P.infectionTime - dt) * every) && random() < infection.feverNoiseChance) {\n noise(P.x, P.z, infection.feverNoiseRadius)\n sound('step', infection.feverNoiseVolume)\n }\n if (P.infectionTime > infection.deathSeconds) {\n P.health = 0\n die('infection')\n return\n }\n }\n if (P.burnTimer > 0) {\n P.burnTimer -= dt\n P.health -= numbers.burnPerSecond * dt\n if (inWater(P.x, P.z)) P.burnTimer = 0\n }\n P.scentTimer = Math.max(0, P.scentTimer - dt)\n if (P.bleeding) {\n P.health -= dt * numbers.bleedPerSecond\n if (input.bandage && P.bleeding) {\n P.bleeding = 0\n message('bandaged', 2)\n }\n }\n if (P.health <= 0) {\n die(P.infected ? 'infected' : P.bleeding ? 'bled_out' : 'hunger_thirst')\n return\n }\n // grabbed: seconds to react\n if (P.grabbedBy >= 0) {\n const i = P.grabbedBy\n P.grabTimer -= dt\n if (crowd) {\n const k = 1 - Math.exp(-dt * numbers.grabFollow) // glued to the body without a jump\n crowd.hold(i, P.x - Math.sin(P.yaw) * numbers.grabOffset, P.z - Math.cos(P.yaw) * numbers.grabOffset, k, P.x, P.z)\n }\n if (wasPressed('push') && P.stamina > numbers.grabPushMinStamina) {\n P.grabPushes++\n P.stamina -= numbers.grabPushCost\n sound('step', numbers.grabPushVolume)\n }\n if (wasPressed('knife')) {\n if (random() < numbers.grabKnifeChance) {\n crowd?.damage(i, { region: numbers.grabKnifeRegion, amount: numbers.grabKnifeDamage, distance: numbers.grabKnifeDistance, cut: numbers.grabKnifeCut })\n message('knife_head', 1.5)\n release('knife')\n return\n } else message('knife_miss', 1)\n }\n if (P.grabPushes >= numbers.grabPushes) {\n crowd?.stun(i, numbers.grabPushStun, -Math.sin(viewYaw) * numbers.grabPushSpeed, -Math.cos(viewYaw) * numbers.grabPushSpeed)\n release('push')\n message('pushed_off', 1.2)\n return\n }\n if (P.grabTimer <= 0) {\n if (P.grabDrown) {\n P.health -= numbers.drownDamage\n P.hurtFlash = numbers.drownFlash\n message('drowning', 2)\n if (P.health <= 0) {\n die('drowned')\n return\n }\n P.grabTimer = numbers.grabSeconds\n P.grabPushes = 0\n return\n }\n if (P.grabNoJaw) {\n hurt(numbers.noJawDamage)\n message('no_jaw', 2)\n } else bite()\n crowd?.chase(i, numbers.grabAttackCooldown)\n release(P.grabNoJaw ? 'scratch' : 'bite')\n }\n return\n }\n // knocked down\n if (P.downTimer > 0) {\n P.downTimer -= dt\n P.vx = P.vz = 0\n if (P.downTimer <= 0) message('stood_up', 0.8)\n return\n }\n if (world.busy?.(dt)) return\n // vaulting a low wall\n if (P.vaultTimer > 0 && P.vault) {\n P.vaultTimer -= dt\n const k = 1 - P.vaultTimer / numbers.vaultSeconds\n P.x = lerp(P.vault[0], P.vault[2], k)\n P.z = lerp(P.vault[1], P.vault[3], k)\n P.y = Math.sin(k * Math.PI) * numbers.vaultHeight\n if (P.vaultTimer <= 0) {\n P.y = 0\n noise(P.x, P.z, numbers.vaultNoise)\n sound('step', numbers.vaultLandVolume)\n }\n return\n }\n if (wasPressed('vault') && P.stamina > numbers.vaultCost && (world.canVault?.() ?? !P.floor)) {\n const fx0 = -Math.sin(viewYaw)\n const fz0 = -Math.cos(viewYaw)\n for (let a = numbers.vaultScanFrom; a <= numbers.vaultScanTo; a += numbers.vaultScanStep) {\n const c = cellKind(P.x + fx0 * a, P.z + fz0 * a)\n if (c === 2) {\n for (let e = a + numbers.vaultLandFrom; e <= a + numbers.vaultLandTo; e += numbers.vaultScanStep) {\n const ex = P.x + fx0 * e\n const ez = P.z + fz0 * e\n if (!solidAt(ex, ez, numbers.vaultCheckHeight) && !solidAt(ex + fx0 * numbers.vaultClearance, ez + fz0 * numbers.vaultClearance, numbers.vaultCheckHeight)) {\n P.vault = [P.x, P.z, ex, ez]\n P.vaultTimer = numbers.vaultSeconds\n P.stamina -= numbers.vaultCost\n sound('step', numbers.vaultStartVolume)\n emit('vault', { from: [P.x, P.z], to: [ex, ez] })\n return\n }\n }\n break\n }\n if (c > 0 && c !== 3) break\n }\n }\n // movement\n const f = input.forward ?? 0\n const s = input.right ?? 0\n if (wasPressed('crouch')) P.crouch = !P.crouch\n const want = f || s\n P.running = !!(input.run && want && P.stamina > numbers.runMinStamina && !input.aim && !P.crouch)\n const fever = P.infected && infection !== null && P.infectionTime > infection.feverSeconds\n let sp = P.running ? derived.runSpeed : P.crouch ? numbers.crouchSpeed : derived.walkSpeed * numbers.walkFactor\n if (fever) sp *= infection!.feverSpeed\n if (input.aim) sp = Math.min(sp, numbers.aimSpeedCap)\n const wet = inWater(P.x, P.z)\n if (wet) sp *= numbers.waterSpeed\n if (P.running) P.stamina = Math.max(0, P.stamina - numbers.runDrain * dt)\n else P.stamina = Math.min(derived.maxStamina, P.stamina + (want ? numbers.regenMoving : numbers.regenStill) * dt)\n const fx = -Math.sin(viewYaw)\n const fz = -Math.cos(viewYaw)\n const mx = fx * f - fz * s\n const mz = fz * f + fx * s\n const ml = Math.hypot(mx, mz) || 1\n const tvx = want ? (mx / ml) * sp : 0\n const tvz = want ? (mz / ml) * sp : 0\n P.vx = lerp(P.vx, tvx, Math.min(1, dt * numbers.acceleration))\n P.vz = lerp(P.vz, tvz, Math.min(1, dt * numbers.acceleration))\n const r = numbers.radius\n const nx = P.x + P.vx * dt\n const nz = P.z + P.vz * dt\n if (!blocked(nx + Math.sign(P.vx) * r, P.z)) P.x = nx\n if (!blocked(P.x, nz + Math.sign(P.vz) * r)) P.z = nz\n world.afterMove?.(P)\n // the player does not walk through the crowd: agents pressed against the body push it out\n if (crowd) {\n const n = crowd.count()\n const rr = numbers.pushApartRadius\n for (let i = 0; i < n; i++) {\n if (!crowd.active(i) || Math.abs(crowd.y(i) - P.y) > numbers.pushApartHeight) continue\n const ex = P.x - crowd.x(i)\n const ez = P.z - crowd.z(i)\n const e2 = ex * ex + ez * ez\n if (e2 < rr * rr && e2 > 1e-5) {\n const e = Math.sqrt(e2)\n const k = ((rr - e) / e) * 0.5\n if (!solidAt(P.x + ex * k, P.z + ez * k, numbers.blockHeight)) {\n P.x += ex * k\n P.z += ez * k\n }\n }\n }\n }\n const spd = Math.hypot(P.vx, P.vz)\n // the legs follow the move even with the torso on the aim; walking backwards flips the stride\n {\n const cy = Math.cos(P.yaw)\n const sy = Math.sin(P.yaw)\n const lx = P.vx * cy - P.vz * sy\n const lz = P.vx * sy + P.vz * cy\n const back = lz < numbers.backwardsBelow ? -1 : 1\n const hip = spd > numbers.hipMinSpeed ? clamp(Math.atan2(lx * back, lz * back), -numbers.hipLimit, numbers.hipLimit) : 0\n P.hip = P.hip + (hip - P.hip) * Math.min(1, dt * numbers.hipFollow)\n P.phase += dt * (spd < numbers.cadenceMinSpeed ? 0 : numbers.cadenceBase + numbers.cadencePerSpeed * spd) * back\n }\n // the body follows the view (fast, no snap); aiming or firing, at once\n {\n const target = viewYaw + Math.PI\n let dy = target - P.yaw\n dy -= Math.round(dy / TAU_APPROX) * TAU_APPROX\n P.yaw += input.aim || input.firing ? dy : dy * Math.min(1, dt * numbers.turnFollow)\n }\n // footsteps make noise: walk 3 m, run 8 m, crouched 1 m (x the sheet's footstep noise, x2 in water)\n P.stepTimer -= dt * spd\n if (P.stepTimer <= 0 && spd > numbers.stepMinSpeed) {\n P.stepTimer = numbers.stepEvery\n noise(P.x, P.z, (P.running ? numbers.stepNoiseRun : P.crouch ? numbers.stepNoiseCrouch : numbers.stepNoiseWalk) * derived.footstepNoise * (wet ? numbers.stepNoiseWater : 1))\n sound('step', P.running ? numbers.stepVolumeRun : numbers.stepVolumeWalk)\n emit('step', { x: P.x, z: P.z, yaw: P.yaw })\n }\n // shove and melee\n if (wasPressed('push') && P.stamina > numbers.shoveCost) {\n P.stamina -= numbers.shoveCost\n shove(viewYaw)\n }\n if (wasPressed('throw')) emit('throw', {})\n if (wasPressed('knife') && P.stamina > numbers.meleeMinStamina) {\n const item = input.melee ?? fist\n P.stamina -= (item.kg ?? 0) > numbers.meleeHeavyKg ? numbers.meleeCostHeavy : numbers.meleeCostLight\n melee(item, viewYaw)\n }\n // panic: chasing agents in sight nearby\n let near = 0\n if (crowd) {\n const n = crowd.count()\n for (let i = 0; i < n; i++) if (crowd.active(i) && crowd.chasing(i)) near += crowd.panicWeight?.(i) ?? 1\n }\n P.panic = clamp(P.panic + (near * numbers.panicGain - (near ? 0 : numbers.panicDecay)) * dt, 0, numbers.panicMax)\n }\n\n return {\n get state() {\n return P\n },\n attributes,\n derived,\n numbers,\n infection,\n update,\n hurt: (amount) => hurt(amount),\n bite: () => bite(),\n grab,\n release: () => release('free'),\n knock(seconds) {\n if (!P.alive) return\n P.downTimer = Math.max(P.downTimer, seconds)\n P.crouch = false\n },\n infect,\n die,\n stage() {\n if (!P.infected || !infection) return 'none'\n return P.infectionTime > infection.deliriumSeconds ? 'delirium' : P.infectionTime > infection.feverSeconds ? 'fever' : 'malaise'\n },\n timeLeft: () => (P.infected && infection ? Math.max(0, infection.deathSeconds - P.infectionTime) : null),\n spreadFactor() {\n const panic = P.panic > derived.composure * numbers.panicSpreadAt ? numbers.panicSpread : 1\n const fever = P.infected && infection && P.infectionTime > infection.feverSeconds ? infection.feverSpread : 1\n return panic * fever * (1 + Math.hypot(P.vx, P.vz) * numbers.moveSpread)\n },\n front,\n on(event, listener) {\n let set = listeners.get(event)\n if (!set) listeners.set(event, (set = new Set()))\n set.add(listener as (event: never) => void)\n return () => void set.delete(listener as (event: never) => void)\n },\n save: () => ({ state: structuredClone(P), attributes }),\n load(save) {\n P = structuredClone(save.state)\n },\n setWorld(next) {\n defaultWorld = next\n },\n }\n}\n","/**\n * Pushing furniture on foot: hold the interaction button against a piece, a timer that grows with its mass fills, and the player then walks with it.\n * Engine-agnostic: the host says where the player wants to go and answers whether the volume of the piece can go there; this says how fast, and when it locks.\n */\n\nexport type FurniturePushPhase = 'idle' | 'grip' | 'push' | 'strain'\nexport type FurniturePushBlock = 'too_heavy' | 'obstacle' | null\n\n/** Every number of the push; a game overrides what it wants (`createFurniturePush(rules)`). */\nexport interface FurniturePushRules {\n /** The most the player's legs put on the floor, newtons: with the friction it says the heaviest thing that moves. */\n readonly forceN: number\n readonly gravity: number\n /** Static friction of a base on a floor, by the material of the piece. */\n readonly frictionByMaterial: Readonly<Record<string, number>>\n readonly defaultFriction: number\n /** The hold before the push: `base + perKg * mass`, at most `max` seconds. */\n readonly gripSeconds: { readonly base: number; readonly perKg: number; readonly max: number }\n /** Metres per second: `max` with nothing on the hands, `min` at the limit of the force. */\n readonly speed: { readonly max: number; readonly min: number }\n /** A press shorter than this is not a push (the host keeps it for a tap, such as grabbing). */\n readonly tapSeconds: number\n /** How long the effort stays after the last step that was refused, so that it does not flicker. */\n readonly strainHoldSeconds: number\n}\n\nexport const FURNITURE_PUSH_DEFAULTS: FurniturePushRules = {\n forceN: 500,\n gravity: 9.81,\n frictionByMaterial: { wood_soft: 0.4, wood_hard: 0.4, mdf: 0.4, plywood: 0.4, steel: 0.35, aluminium: 0.35, cast_iron: 0.4, copper: 0.35, plastic: 0.35, rubber: 0.8, fabric: 0.45, foam: 0.5, ceramic: 0.5, glass: 0.3, tempered_glass: 0.3, brick: 0.6, concrete: 0.65 },\n defaultFriction: 0.45,\n gripSeconds: { base: 0.4, perKg: 0.015, max: 2.5 },\n speed: { max: 1.8, min: 0.35 },\n tapSeconds: 0.2,\n strainHoldSeconds: 0.25,\n}\n\nexport type FurniturePushTarget = { readonly massKg: number; readonly material?: string }\n\nconst frictionOf = (target: FurniturePushTarget, rules: FurniturePushRules): number => (target.material !== undefined ? rules.frictionByMaterial[target.material] : undefined) ?? rules.defaultFriction\n\nconst loadShare = (target: FurniturePushTarget, rules: FurniturePushRules): number => (frictionOf(target, rules) * target.massKg * rules.gravity) / rules.forceN\n\nexport const gripSecondsFor = (massKg: number, rules: FurniturePushRules = FURNITURE_PUSH_DEFAULTS): number => Math.min(rules.gripSeconds.max, rules.gripSeconds.base + rules.gripSeconds.perKg * Math.max(0, massKg))\n\n/** Whether the legs overcome the friction of the piece on the floor. */\nexport const canPush = (target: FurniturePushTarget, rules: FurniturePushRules = FURNITURE_PUSH_DEFAULTS): boolean => loadShare(target, rules) <= 1\n\n/** Metres per second with the piece on the hands: slower the closer it is to the limit of the force, 0 past it. */\nexport const pushSpeedFor = (target: FurniturePushTarget, rules: FurniturePushRules = FURNITURE_PUSH_DEFAULTS): number => {\n const share = loadShare(target, rules)\n return share > 1 ? 0 : rules.speed.max + (rules.speed.min - rules.speed.max) * share\n}\n\nexport type FurniturePushInput = {\n /** Where the player wants to go on the floor: a unit vector, or `[0, 0]` standing. */\n readonly walk: readonly [number, number]\n /** Whether the volume of the piece (and the player behind it) can move by this offset. */\n readonly isFree: (dx: number, dz: number) => boolean\n}\n\nexport type FurniturePushStep = {\n readonly dx: number\n readonly dz: number\n /** The grip closed on this update. */\n readonly engaged: boolean\n /** A step was refused now and the one before was not: the moment the piece hits something. */\n readonly hitObstacle: boolean\n}\n\nexport interface FurniturePush {\n readonly phase: FurniturePushPhase\n /** How far the hold timer is, 0 to 1. */\n readonly progress: number\n readonly block: FurniturePushBlock\n readonly heldSeconds: number\n /** Whether the hold is still short enough to be a tap. */\n readonly isTap: boolean\n begin(target: FurniturePushTarget): void\n release(): void\n update(dt: number, input: FurniturePushInput): FurniturePushStep\n}\n\nconst STILL: FurniturePushStep = { dx: 0, dz: 0, engaged: false, hitObstacle: false }\n\nexport function createFurniturePush(overrides: Partial<FurniturePushRules> = {}): FurniturePush {\n const rules: FurniturePushRules = { ...FURNITURE_PUSH_DEFAULTS, ...overrides }\n let phase: FurniturePushPhase = 'idle'\n let target: FurniturePushTarget = { massKg: 0 }\n let held = 0\n let gripSeconds = 1\n let speed = 0\n let block: FurniturePushBlock = null\n let refused = 0\n let wasRefused = false\n\n const walkWith = (dt: number, input: FurniturePushInput): FurniturePushStep => {\n refused = Math.max(0, refused - dt)\n if (block === 'too_heavy') return STILL\n const [x, z] = input.walk\n if ((x === 0 && z === 0) || dt <= 0) {\n if (refused === 0) {\n phase = 'push'\n block = null\n wasRefused = false\n }\n return STILL\n }\n const dx = x * speed * dt\n const dz = z * speed * dt\n if (input.isFree(dx, dz)) {\n if (refused === 0) {\n phase = 'push'\n block = null\n }\n wasRefused = false\n return { dx, dz, engaged: false, hitObstacle: false }\n }\n const hitObstacle = !wasRefused\n wasRefused = true\n refused = rules.strainHoldSeconds\n phase = 'strain'\n block = 'obstacle'\n return { dx: 0, dz: 0, engaged: false, hitObstacle }\n }\n\n return {\n get phase() {\n return phase\n },\n get progress() {\n return phase === 'idle' ? 0 : Math.min(1, held / gripSeconds)\n },\n get block() {\n return block\n },\n get heldSeconds() {\n return held\n },\n get isTap() {\n return phase === 'grip' && held < rules.tapSeconds\n },\n begin(next) {\n target = next\n phase = 'grip'\n held = 0\n block = null\n refused = 0\n wasRefused = false\n gripSeconds = gripSecondsFor(next.massKg, rules)\n speed = pushSpeedFor(next, rules)\n },\n release() {\n phase = 'idle'\n held = 0\n block = null\n },\n update(dt, input) {\n if (phase === 'idle') return STILL\n held += dt\n if (phase !== 'grip') return walkWith(dt, input)\n if (held < gripSeconds) return STILL\n if (canPush(target, rules)) phase = 'push'\n else {\n phase = 'strain'\n block = 'too_heavy'\n }\n return { ...STILL, engaged: true }\n },\n }\n}\n","import type { KnownDeathCause, PlayerMessageId } from '../types'\n\nexport type PlayerText = Readonly<Record<PlayerMessageId | KnownDeathCause, string>>\n\n/** The game's own words (G 68434, 68452, 68518, 68525-68541, 68547) and the death causes it shows (G 68448, 68454, 68510, 68519, 68539). */\nconst PT_BR: PlayerText = {\n grabbed: 'AGARRADO! Aperte E várias vezes para empurrar ou F para a faca',\n grabbed_drown: 'O AFOGADO TE PUXA PARA O FUNDO! E várias vezes ou F para a faca',\n bitten: 'Você foi mordido. Não há cura.',\n bandaged: 'Curativo feito',\n knife_head: 'Faca na cabeça!',\n knife_miss: 'Errou a facada',\n pushed_off: 'Empurrou!',\n drowning: 'Afogando! Solte-se!',\n no_jaw: 'Sem mandíbula: só arranhou',\n stood_up: 'De pé!',\n infected: 'Morreu infectado',\n killed: 'Morto pela horda',\n bitten_to_death: 'Mordido',\n infection: 'A infecção venceu',\n bled_out: 'Sangrou até a morte',\n hunger_thirst: 'Fome e sede',\n drowned: 'Afogado',\n burned: 'Queimado',\n}\n\nconst EN: PlayerText = {\n grabbed: 'GRABBED! Press E repeatedly to push or F for the knife',\n grabbed_drown: 'THE DROWNED PULLS YOU UNDER! E repeatedly or F for the knife',\n bitten: 'You were bitten. There is no cure.',\n bandaged: 'Wound dressed',\n knife_head: 'Knife to the head!',\n knife_miss: 'The stab missed',\n pushed_off: 'Pushed off!',\n drowning: 'Drowning! Break free!',\n no_jaw: 'No jaw: only a scratch',\n stood_up: 'Back on your feet!',\n infected: 'Died infected',\n killed: 'Killed by the horde',\n bitten_to_death: 'Bitten',\n infection: 'The infection won',\n bled_out: 'Bled to death',\n hunger_thirst: 'Hunger and thirst',\n drowned: 'Drowned',\n burned: 'Burned',\n}\n\nexport const PLAYER_TEXT: Readonly<Record<'en' | 'pt-BR', PlayerText>> = { en: EN, 'pt-BR': PT_BR }\n\n/** The text of a message or death cause id in a locale (`pt-BR` or `en`, the language part is enough); unknown ids come back as they are. */\nexport const playerTextOf = (id: string, locale = 'pt-BR'): string => {\n const table = locale.toLowerCase().startsWith('en') ? EN : PT_BR\n return (table as Readonly<Record<string, string>>)[id] ?? id\n}\n","export type PlayerBenchText = {\n readonly group: string\n readonly name: string\n readonly controls: Readonly<Record<'infection' | 'agility' | 'vigor' | 'seed' | 'hurt' | 'bite' | 'grab' | 'push' | 'knife' | 'bandage' | 'knock' | 'crouch' | 'reset', string>>\n readonly hints: Readonly<Record<'infection' | 'agility' | 'vigor' | 'seed' | 'grab' | 'push', string>>\n readonly metrics: Readonly<Record<'health' | 'stamina' | 'bleeding' | 'wounds' | 'stage' | 'time_left' | 'panic' | 'spread' | 'grab' | 'noise' | 'steps' | 'message', string>>\n readonly stages: Readonly<Record<'none' | 'malaise' | 'fever' | 'delirium' | 'dead', string>>\n readonly scenarios: Readonly<Record<'stamina' | 'bleed_bandage' | 'normal_world' | 'infection_kills' | 'grab_break_free' | 'determinism', string>>\n readonly yes: string\n readonly no: string\n}\n\nconst EN: PlayerBenchText = {\n group: 'Player',\n name: 'Player area',\n controls: {\n infection: 'Individual infection',\n agility: 'Agility',\n vigor: 'Vigor',\n seed: 'Seed',\n hurt: 'Take a hit (10)',\n bite: 'Bite',\n grab: 'Get grabbed',\n push: 'Push (E)',\n knife: 'Knife (F)',\n bandage: 'Bandage (B)',\n knock: 'Knocked down 1.5 s',\n crouch: 'Crouch (C)',\n reset: 'Start again',\n },\n hints: {\n infection: 'Off: a normal world, wounds never infect. On: the game rule (scratch 6%, laceration 22%, bite 100%; fever at 30 s, death at 120 s).',\n agility: 'The sheet: stamina, run speed and footstep noise come from it.',\n vigor: 'The sheet: health, stamina and composure come from it.',\n seed: 'The same seed gives the same wounds and the same knife rolls.',\n grab: 'Something grabs you from behind: 3 s to push it off (6 pushes) or to land the knife (70%).',\n push: 'Shoves what is in front, or pushes off what holds you.',\n },\n metrics: {\n health: 'Health',\n stamina: 'Stamina',\n bleeding: 'Bleeding',\n wounds: 'Wounds',\n stage: 'Infection',\n time_left: 'Time left',\n panic: 'Panic',\n spread: 'Aim spread x',\n grab: 'Grab timer',\n noise: 'Last noise',\n steps: 'Footsteps',\n message: 'Message',\n },\n stages: { none: 'None', malaise: 'Malaise', fever: 'Fever', delirium: 'Delirium', dead: 'Dead' },\n scenarios: {\n stamina: 'Running drains stamina and resting gives it back',\n bleed_bandage: 'A laceration bleeds until it is dressed',\n normal_world: 'In a normal world a bite hurts and bleeds but never infects',\n infection_kills: 'With the infection on, a bite brings fever and kills at its time',\n grab_break_free: 'Six pushes break a grab before the bite',\n determinism: 'The same seed gives the same wounds',\n },\n yes: 'yes',\n no: 'no',\n}\n\nconst PT_BR: PlayerBenchText = {\n group: 'Jogador',\n name: 'Área do jogador',\n controls: {\n infection: 'Infecção individual',\n agility: 'Agilidade',\n vigor: 'Vigor',\n seed: 'Semente',\n hurt: 'Levar um golpe (10)',\n bite: 'Mordida',\n grab: 'Ser agarrado',\n push: 'Empurrar (E)',\n knife: 'Faca (F)',\n bandage: 'Curativo (B)',\n knock: 'Derrubado 1,5 s',\n crouch: 'Agachar (C)',\n reset: 'Recomeçar',\n },\n hints: {\n infection: 'Desligada: mundo normal, ferida nunca infecta. Ligada: a regra do jogo (arranhão 6%, laceração 22%, mordida 100%; febre aos 30 s, morte aos 120 s).',\n agility: 'A ficha: fôlego, velocidade de corrida e ruído dos passos saem dela.',\n vigor: 'A ficha: vida, fôlego e compostura saem dela.',\n seed: 'A mesma semente dá as mesmas feridas e os mesmos golpes de faca.',\n grab: 'Algo te agarra por trás: 3 s para empurrar (6 empurrões) ou acertar a faca (70%).',\n push: 'Empurra o que está na frente, ou se solta do que te segura.',\n },\n metrics: {\n health: 'Vida',\n stamina: 'Fôlego',\n bleeding: 'Sangrando',\n wounds: 'Feridas',\n stage: 'Infecção',\n time_left: 'Tempo restante',\n panic: 'Pânico',\n spread: 'Dispersão x',\n grab: 'Agarrão',\n noise: 'Último ruído',\n steps: 'Passos',\n message: 'Mensagem',\n },\n stages: { none: 'Nenhuma', malaise: 'Mal-estar', fever: 'Febre', delirium: 'Delírio', dead: 'Morto' },\n scenarios: {\n stamina: 'Correr gasta fôlego e descansar devolve',\n bleed_bandage: 'Uma laceração sangra até o curativo',\n normal_world: 'No mundo normal a mordida machuca e sangra, mas não infecta',\n infection_kills: 'Com a infecção ligada, a mordida dá febre e mata no tempo dela',\n grab_break_free: 'Seis empurrões soltam o agarrão antes da mordida',\n determinism: 'A mesma semente dá as mesmas feridas',\n },\n yes: 'sim',\n no: 'não',\n}\n\nexport const playerBenchTextOf = (locale: string): PlayerBenchText => (locale.toLowerCase().startsWith('en') ? EN : PT_BR)\n","import type { BenchChange, ModuleControl, ModuleHost, ModuleMetric, ModuleScenario, TestableModule } from '@adatechnology/game-contracts'\n\nimport { playerTextOf } from '../locales'\nimport { createPlayer } from '../player'\nimport type { Player, PlayerOptions } from '../player'\nimport type { PlayerAction, PlayerCrowd, PlayerInput } from '../types'\nimport { playerBenchTextOf } from './locale'\n\nexport type PlayerTestModuleOptions = PlayerOptions & { readonly locale?: string }\n\n/** What the scenarios use of the context the test room passes. */\nexport interface PlayerScenarioLike {\n expect(condition: boolean, label: string, data?: Record<string, unknown>): void\n}\n\nexport type PlayerTestModule = TestableModule<PlayerScenarioLike> & {\n /** The player in use (replaced when the bench changes the sheet, the seed or the infection). */\n readonly player: Player\n}\n\ntype CameraLike = { position: { x: number; y: number; z: number }; rotation?: { y: number }; getWorldDirection?(target: unknown): { x: number; z: number } }\ntype ThreeLike = { Vector3?: new () => { x: number; y: number; z: number } }\n\nconst MOVING_SPEED = 0.2\nconst SPRINT_SPEED = 3.4\nconst FRAME = 1 / 30\n\n/**\n * One agent standing behind the player for the grab test: the bench has no crowd, so this is the hand that holds. It follows `hold`, takes\n * the shove and the knife, and leaves the count once it lets go.\n */\nconst createGrabber = () => {\n const agent = { x: 0, z: 0, on: false, stunned: 0, hits: 0 }\n const crowd: PlayerCrowd = {\n count: () => (agent.on ? 1 : 0),\n active: () => agent.on,\n x: () => agent.x,\n z: () => agent.z,\n y: () => 0,\n floor: () => 0,\n chasing: () => agent.on,\n down: () => agent.stunned > 0,\n hold(_i, x, z, k) {\n agent.x += (x - agent.x) * k\n agent.z += (z - agent.z) * k\n },\n stun(_i, seconds) {\n agent.stunned = seconds\n agent.on = false\n },\n chase() {\n agent.on = false\n },\n damage() {\n agent.hits += 1\n agent.on = false\n },\n }\n return { agent, crowd }\n}\n\n/**\n * The player area of a test room, against the generic contracts only. The room's camera is the player: where it walks, the player walks; its speed\n * decides walking or running, so stamina, footsteps and their noise follow the viewer. The bench hurts, bites, grabs and knocks the player down,\n * switches the individual infection (off by default: a normal world) and sets the sheet. Footsteps and flesh sounds go to `host.audio`.\n */\nexport function createPlayerTestModule(options: PlayerTestModuleOptions = {}): PlayerTestModule {\n const locale = options.locale ?? 'pt-BR'\n const text = playerBenchTextOf(locale)\n const { locale: _locale, ...playerOptions } = options\n void _locale\n const settings = { infection: options.infection === undefined ? false : options.infection !== false, agility: options.attributes?.agility ?? 5, vigor: options.attributes?.vigor ?? 5, seed: options.seed ?? 1 }\n let host: ModuleHost | null = null\n const grabber = createGrabber()\n let lastNoise = 0\n let steps = 0\n let lastMessage = ''\n let pending: Partial<Record<PlayerAction, boolean>> = {}\n let bandage = false\n let last: { x: number; z: number } | null = null\n const offs: (() => void)[] = []\n\n const build = (): Player => {\n for (const off of offs.splice(0)) off()\n const made = createPlayer({ ...playerOptions, seed: settings.seed, infection: settings.infection, attributes: { ...playerOptions.attributes, agility: settings.agility, vigor: settings.vigor } })\n offs.push(made.on('noise', (e) => void (lastNoise = e.radius)))\n offs.push(made.on('step', () => void (steps += 1)))\n offs.push(made.on('message', (e) => void (lastMessage = playerTextOf(e.id, locale))))\n offs.push(made.on('sound', (e) => void host?.audio?.play({ sound: e.sound, volume: e.volume, position: e.position })))\n offs.push(made.on('died', (e) => host?.log(`player died: ${e.cause}`, { cause: e.cause })))\n lastNoise = 0\n steps = 0\n lastMessage = ''\n return made\n }\n let player = build()\n\n const view = (): { x: number; z: number; yaw: number } | null => {\n const camera = host?.camera as CameraLike | undefined\n if (!camera?.position) return null\n const Vector3 = (host?.THREE as ThreeLike | undefined)?.Vector3\n if (camera.getWorldDirection && Vector3) {\n const look = camera.getWorldDirection(new Vector3())\n return { x: camera.position.x, z: camera.position.z, yaw: Math.atan2(-look.x, -look.z) }\n }\n return { x: camera.position.x, z: camera.position.z, yaw: camera.rotation?.y ?? 0 }\n }\n\n const frame = (dt: number): void => {\n const here = view()\n const speed = here && last && dt > 0 ? Math.hypot(here.x - last.x, here.z - last.z) / dt : 0\n if (here) {\n player.state.x = here.x\n player.state.z = here.z\n }\n const input: PlayerInput = { forward: speed > MOVING_SPEED ? 1 : 0, run: speed > SPRINT_SPEED, yaw: here?.yaw ?? 0, bandage, pressed: pending }\n pending = {}\n bandage = false\n player.update(dt, input, { crowd: grabber.crowd })\n if (here) {\n player.state.x = here.x\n player.state.z = here.z\n last = { x: here.x, z: here.z }\n }\n if (grabber.agent.stunned > 0) grabber.agent.stunned = Math.max(0, grabber.agent.stunned - dt)\n }\n\n const grab = (): void => {\n const P = player.state\n grabber.agent.on = true\n grabber.agent.x = P.x - Math.sin(P.yaw) * player.numbers.grabOffset\n grabber.agent.z = P.z - Math.cos(P.yaw) * player.numbers.grabOffset\n player.grab(0)\n }\n\n const onChange = (change: BenchChange): void => {\n if (change.kind === 'action') {\n const id = change.id\n if (id === 'hurt') player.hurt(10)\n else if (id === 'bite') player.bite()\n else if (id === 'grab') grab()\n else if (id === 'knock') player.knock(1.5)\n else if (id === 'bandage') bandage = true\n else if (id === 'push' || id === 'knife' || id === 'crouch') pending = { ...pending, [id]: true }\n else if (id === 'reset') player = build()\n return\n }\n if (change.kind !== 'control') return\n const { id, value } = change\n if (id === 'infection' && typeof value === 'boolean' && value !== settings.infection) settings.infection = value\n else if ((id === 'agility' || id === 'vigor' || id === 'seed') && typeof value === 'number' && value !== settings[id]) settings[id] = value\n else return\n player = build()\n }\n\n const controls = (): ModuleControl[] => [\n { kind: 'boolean', id: 'infection', name: text.controls.infection, hint: text.hints.infection, default: settings.infection },\n { kind: 'number', id: 'agility', name: text.controls.agility, hint: text.hints.agility, min: 1, max: 8, step: 1, default: settings.agility },\n { kind: 'number', id: 'vigor', name: text.controls.vigor, hint: text.hints.vigor, min: 1, max: 8, step: 1, default: settings.vigor },\n { kind: 'number', id: 'seed', name: text.controls.seed, hint: text.hints.seed, min: 1, max: 9999, step: 1, default: settings.seed },\n { kind: 'action', id: 'hurt', name: text.controls.hurt },\n { kind: 'action', id: 'bite', name: text.controls.bite },\n { kind: 'action', id: 'grab', name: text.controls.grab, hint: text.hints.grab },\n { kind: 'action', id: 'push', name: text.controls.push, hint: text.hints.push },\n { kind: 'action', id: 'knife', name: text.controls.knife },\n { kind: 'action', id: 'bandage', name: text.controls.bandage },\n { kind: 'action', id: 'knock', name: text.controls.knock },\n { kind: 'action', id: 'crouch', name: text.controls.crouch },\n { kind: 'action', id: 'reset', name: text.controls.reset },\n ]\n\n const stageName = (): string => (player.state.alive ? text.stages[player.stage()] : text.stages.dead)\n const metrics = (): ModuleMetric[] => [\n { id: 'health', name: text.metrics.health, digits: 1, max: player.derived.maxHealth, read: () => Math.max(0, player.state.health) },\n { id: 'stamina', name: text.metrics.stamina, digits: 1, max: player.derived.maxStamina, read: () => player.state.stamina },\n { id: 'bleeding', name: text.metrics.bleeding, read: () => (player.state.bleeding ? text.yes : text.no) },\n { id: 'wounds', name: text.metrics.wounds, digits: 0, read: () => player.state.wounds.length },\n { id: 'stage', name: text.metrics.stage, read: stageName },\n { id: 'time_left', name: text.metrics.time_left, unit: 's', digits: 0, read: () => player.timeLeft() ?? 0 },\n { id: 'panic', name: text.metrics.panic, digits: 1, read: () => player.state.panic },\n { id: 'spread', name: text.metrics.spread, digits: 2, read: () => player.spreadFactor() },\n { id: 'grab_timer', name: text.metrics.grab, unit: 's', digits: 1, read: () => (player.state.grabbedBy >= 0 ? player.state.grabTimer : 0) },\n { id: 'noise', name: text.metrics.noise, unit: 'm', digits: 1, read: () => lastNoise },\n { id: 'steps', name: text.metrics.steps, digits: 0, read: () => steps },\n { id: 'message', name: text.metrics.message, read: () => lastMessage },\n ]\n\n // each scenario runs its own player, so the bench's live one is not touched\n const fresh = (extra: PlayerOptions = {}): Player => createPlayer({ ...playerOptions, ...extra })\n const run = (made: Player, seconds: number, input: PlayerInput = {}, crowd?: PlayerCrowd): void => {\n for (let t = 0; t < seconds; t += FRAME) made.update(FRAME, input, crowd ? { crowd } : undefined)\n }\n const scenarios = (): Array<ModuleScenario<PlayerScenarioLike>> => [\n {\n id: 'player_stamina',\n name: text.scenarios.stamina,\n run: ({ expect }) => {\n const made = fresh({ seed: 1 })\n const full = made.state.stamina\n run(made, 4, { forward: 1, run: true })\n const tired = made.state.stamina\n expect(tired < full - 40, 'four seconds of running spend 48 of stamina', { full, tired })\n run(made, 3)\n expect(made.state.stamina > tired, 'standing still gives it back', { tired, rested: made.state.stamina })\n },\n },\n {\n id: 'player_bleed_bandage',\n name: text.scenarios.bleed_bandage,\n run: ({ expect }) => {\n const made = fresh({ seed: 1 })\n made.bite()\n const after = made.state.health\n run(made, 2)\n expect(made.state.bleeding === 1 && made.state.health < after, 'the wound bleeds', { health: made.state.health })\n run(made, FRAME, { bandage: true })\n const dressed = made.state.health\n run(made, 2)\n expect(made.state.bleeding === 0 && made.state.health === dressed, 'dressed, it stops', { health: made.state.health })\n },\n },\n {\n id: 'player_normal_world',\n name: text.scenarios.normal_world,\n run: ({ expect }) => {\n const made = fresh({ seed: 1, infection: false })\n made.bite()\n run(made, 10)\n expect(!made.state.infected && made.state.health < made.derived.maxHealth, 'bitten, hurt, not infected', { health: made.state.health })\n },\n },\n {\n id: 'player_infection_kills',\n name: text.scenarios.infection_kills,\n run: ({ expect }) => {\n const made = fresh({ seed: 1, infection: true })\n made.bite()\n run(made, FRAME, { bandage: true })\n run(made, 40)\n expect(made.stage() === 'fever', 'fever after 30 s', { stage: made.stage() })\n run(made, 90)\n expect(!made.state.alive && made.state.cause === 'infection', 'dead at 120 s', { cause: made.state.cause })\n },\n },\n {\n id: 'player_grab_break_free',\n name: text.scenarios.grab_break_free,\n run: ({ expect }) => {\n const made = fresh({ seed: 1 })\n const { agent, crowd } = createGrabber()\n agent.on = true\n made.grab(0)\n for (let push = 0; push < 6; push++) {\n made.update(FRAME, { pressed: { push: true } }, { crowd })\n made.update(FRAME, {}, { crowd })\n }\n expect(made.state.grabbedBy === -1 && made.state.wounds.length === 0, 'free, and no bite', { grabbedBy: made.state.grabbedBy })\n },\n },\n {\n id: 'player_determinism',\n name: text.scenarios.determinism,\n run: ({ expect }) => {\n const wounds = (seed: number): string => {\n const made = fresh({ seed })\n for (let k = 0; k < 12; k++) made.hurt(1)\n return made.state.wounds.join(',')\n }\n expect(wounds(4) === wounds(4), 'the same seed gives the same wounds')\n expect(wounds(4) !== wounds(5), 'another seed gives others')\n },\n },\n ]\n\n const module: PlayerTestModule = {\n id: 'player_area',\n name: text.name,\n ground: { surface: 'dirt' },\n group: text.group,\n get player() {\n return player\n },\n items: () => [],\n controls: () => controls(),\n metrics: () => metrics(),\n scenarios: () => scenarios(),\n attach(lent) {\n host = lent\n last = null\n const off = lent.bench?.onChange(onChange)\n const offFrame = lent.onFrame(frame)\n return () => {\n off?.()\n offFrame()\n host = null\n }\n },\n }\n return module\n}\n","/**\n * Opening and closing a hinged or sliding leaf by hand (a house door, a wardrobe or fridge door, a drawer, a car door, a hood): the hand reaches the handle, the leaf\n * follows the hand at a speed set by its mass, stops where something is in its way, and a locked leaf only rattles.\n * Engine-agnostic: the host says how open the leaf is (0 closed, 1 open) and answers whether it can go to a new opening; this says how far it goes each step.\n */\n\nexport type DoorUsePhase = 'idle' | 'reach' | 'swing' | 'release' | 'rattle'\nexport type DoorUseBlock = 'locked' | 'obstacle' | null\n\n/** Every number of the use; a game overrides what it wants (`createDoorUse(rules)`). */\nexport interface DoorUseRules {\n /** The hand going to the handle before the leaf moves, seconds. */\n readonly reachSeconds: number\n /** A full swing: `base + perKg * mass` of the leaf, between `min` and `max` seconds (a fridge door is quick, a car door slower, a steel door slower still). */\n readonly swingSeconds: { readonly base: number; readonly perKg: number; readonly min: number; readonly max: number }\n /** The hand letting go and coming back, seconds. */\n readonly releaseSeconds: number\n /** How long a locked leaf is shaken before the hand gives up, seconds. */\n readonly rattleSeconds: number\n /** The part of the swing tested at a time against what is around (smaller is finer and costs more). */\n readonly stepFraction: number\n /** Within this of closed or open a leaf counts as there: the last use's way no longer turns it round. */\n readonly endTolerance: number\n}\n\nexport const DOOR_USE_DEFAULTS: DoorUseRules = {\n reachSeconds: 0.3,\n swingSeconds: { base: 0.45, perKg: 0.02, min: 0.45, max: 1.6 },\n releaseSeconds: 0.22,\n rattleSeconds: 0.6,\n stepFraction: 0.04,\n endTolerance: 0.02,\n}\n\nexport type DoorUseTarget = {\n /** How open the leaf is now, 0 closed to 1 open. */\n readonly opening: number\n readonly massKg: number\n readonly locked?: boolean\n /** Where the last use sent this leaf: a leaf stopped between closed and open goes the other way (a door blocked half open closes). */\n readonly lastGoal?: 0 | 1\n}\n\nexport type DoorUseStep = {\n readonly phase: DoorUsePhase\n /** How open the leaf is after the step. */\n readonly opening: number\n /** The phase's own progress, 0 to 1 (how far the hand is to the handle, how far the swing went, how much of the rattle is left). */\n readonly progress: number\n /** Set on the step the leaf stopped short or would not move. */\n readonly block: DoorUseBlock\n /** The leaf got where it was going on this step (fully open or fully closed). */\n readonly arrived: boolean\n}\n\n/** Seconds of a full swing for a leaf of this mass. */\nexport const swingSecondsFor = (massKg: number, rules: DoorUseRules = DOOR_USE_DEFAULTS): number =>\n Math.min(rules.swingSeconds.max, Math.max(rules.swingSeconds.min, rules.swingSeconds.base + rules.swingSeconds.perKg * Math.max(0, massKg)))\n\nexport interface DoorUse {\n readonly phase: DoorUsePhase\n /** Where the leaf is going: 1 opening, 0 closing. */\n readonly goal: 0 | 1\n readonly opening: number\n /**\n * Starts using a leaf: the other way from where the last use sent it (`lastGoal`), else a closed or half-open leaf opens and an open\n * one closes. A use in the middle of a swing turns it round.\n * Answers the goal (1 open, 0 closed), or null when the leaf is locked (it rattles instead).\n */\n begin(target: DoorUseTarget): 0 | 1 | null\n /** Advances the use; `isFree(from, to)` answers whether the leaf can go from one opening to the other (nothing in the way of its sweep). */\n step(dt: number, isFree: (from: number, to: number) => boolean): DoorUseStep\n /** Lets go at once. */\n cancel(): void\n}\n\nexport function createDoorUse(rules: Partial<DoorUseRules> = {}): DoorUse {\n const r: DoorUseRules = { ...DOOR_USE_DEFAULTS, ...rules, swingSeconds: { ...DOOR_USE_DEFAULTS.swingSeconds, ...rules.swingSeconds } }\n let phase: DoorUsePhase = 'idle'\n let goal: 0 | 1 = 1\n let opening = 0\n let time = 0\n let swing = 1\n let start = 0\n\n const out = (progress: number, arrived = false, b: DoorUseBlock = null): DoorUseStep => ({ phase, opening, progress: Math.max(0, Math.min(1, progress)), block: b, arrived })\n\n return {\n get phase() {\n return phase\n },\n get goal() {\n return goal\n },\n get opening() {\n return opening\n },\n begin(target) {\n opening = Math.max(0, Math.min(1, target.opening))\n time = 0\n if (target.locked) {\n phase = 'rattle'\n return null\n }\n // in the middle of a swing the hand is already on the handle: the leaf turns round at once\n if (phase === 'swing' || phase === 'reach') goal = goal === 1 ? 0 : 1\n else if (target.lastGoal !== undefined && opening > r.endTolerance && opening < 1 - r.endTolerance) goal = target.lastGoal === 1 ? 0 : 1\n else goal = opening > 0.5 ? 0 : 1\n swing = swingSecondsFor(target.massKg, r)\n start = opening\n phase = phase === 'swing' ? 'swing' : 'reach'\n return goal\n },\n step(dt, isFree) {\n if (phase === 'idle') return out(0)\n time += dt\n if (phase === 'rattle') {\n const p = time / r.rattleSeconds\n if (p >= 1) {\n phase = 'idle'\n return out(1, false, 'locked')\n }\n return out(p, false, time === dt ? 'locked' : null)\n }\n if (phase === 'reach') {\n const p = time / r.reachSeconds\n if (p < 1) return out(p)\n phase = 'swing'\n time = 0\n start = opening\n }\n if (phase === 'swing') {\n const want = goal - opening\n const reach = Math.min(Math.abs(want), dt / swing)\n // the sweep is tested a little at a time, so a leaf stops at the first thing in its way and not past it\n let moved = 0\n let stopped = false\n while (moved < reach - 1e-9) {\n const inc = Math.min(r.stepFraction, reach - moved)\n const next = opening + Math.sign(want) * inc\n if (!isFree(opening, next)) {\n stopped = true\n break\n }\n opening = next\n moved += inc\n }\n const travel = Math.abs(goal - start) || 1\n if (stopped) {\n phase = 'release'\n time = 0\n return out(1 - Math.abs(goal - opening) / travel, false, 'obstacle')\n }\n if (Math.abs(goal - opening) < 1e-6) {\n opening = goal\n phase = 'release'\n time = 0\n return out(1, true)\n }\n return out(1 - Math.abs(goal - opening) / travel)\n }\n // release\n const p = time / r.releaseSeconds\n if (p >= 1) {\n phase = 'idle'\n }\n return out(p, false, null)\n },\n cancel() {\n phase = 'idle'\n time = 0\n },\n }\n}\n"],"mappings":"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","names":["EN","PT_BR","id","p"]}
|
package/dist/index.js
CHANGED
|
@@ -1118,11 +1118,117 @@ function createPlayerTestModule(options = {}) {
|
|
|
1118
1118
|
};
|
|
1119
1119
|
return module;
|
|
1120
1120
|
}
|
|
1121
|
+
|
|
1122
|
+
// src/door-use.ts
|
|
1123
|
+
var DOOR_USE_DEFAULTS = {
|
|
1124
|
+
reachSeconds: 0.3,
|
|
1125
|
+
swingSeconds: { base: 0.45, perKg: 0.02, min: 0.45, max: 1.6 },
|
|
1126
|
+
releaseSeconds: 0.22,
|
|
1127
|
+
rattleSeconds: 0.6,
|
|
1128
|
+
stepFraction: 0.04,
|
|
1129
|
+
endTolerance: 0.02
|
|
1130
|
+
};
|
|
1131
|
+
var swingSecondsFor = (massKg, rules = DOOR_USE_DEFAULTS) => Math.min(rules.swingSeconds.max, Math.max(rules.swingSeconds.min, rules.swingSeconds.base + rules.swingSeconds.perKg * Math.max(0, massKg)));
|
|
1132
|
+
function createDoorUse(rules = {}) {
|
|
1133
|
+
const r = { ...DOOR_USE_DEFAULTS, ...rules, swingSeconds: { ...DOOR_USE_DEFAULTS.swingSeconds, ...rules.swingSeconds } };
|
|
1134
|
+
let phase = "idle";
|
|
1135
|
+
let goal = 1;
|
|
1136
|
+
let opening = 0;
|
|
1137
|
+
let time = 0;
|
|
1138
|
+
let swing = 1;
|
|
1139
|
+
let start = 0;
|
|
1140
|
+
const out = (progress, arrived = false, b = null) => ({ phase, opening, progress: Math.max(0, Math.min(1, progress)), block: b, arrived });
|
|
1141
|
+
return {
|
|
1142
|
+
get phase() {
|
|
1143
|
+
return phase;
|
|
1144
|
+
},
|
|
1145
|
+
get goal() {
|
|
1146
|
+
return goal;
|
|
1147
|
+
},
|
|
1148
|
+
get opening() {
|
|
1149
|
+
return opening;
|
|
1150
|
+
},
|
|
1151
|
+
begin(target) {
|
|
1152
|
+
opening = Math.max(0, Math.min(1, target.opening));
|
|
1153
|
+
time = 0;
|
|
1154
|
+
if (target.locked) {
|
|
1155
|
+
phase = "rattle";
|
|
1156
|
+
return null;
|
|
1157
|
+
}
|
|
1158
|
+
if (phase === "swing" || phase === "reach") goal = goal === 1 ? 0 : 1;
|
|
1159
|
+
else if (target.lastGoal !== void 0 && opening > r.endTolerance && opening < 1 - r.endTolerance) goal = target.lastGoal === 1 ? 0 : 1;
|
|
1160
|
+
else goal = opening > 0.5 ? 0 : 1;
|
|
1161
|
+
swing = swingSecondsFor(target.massKg, r);
|
|
1162
|
+
start = opening;
|
|
1163
|
+
phase = phase === "swing" ? "swing" : "reach";
|
|
1164
|
+
return goal;
|
|
1165
|
+
},
|
|
1166
|
+
step(dt, isFree) {
|
|
1167
|
+
if (phase === "idle") return out(0);
|
|
1168
|
+
time += dt;
|
|
1169
|
+
if (phase === "rattle") {
|
|
1170
|
+
const p2 = time / r.rattleSeconds;
|
|
1171
|
+
if (p2 >= 1) {
|
|
1172
|
+
phase = "idle";
|
|
1173
|
+
return out(1, false, "locked");
|
|
1174
|
+
}
|
|
1175
|
+
return out(p2, false, time === dt ? "locked" : null);
|
|
1176
|
+
}
|
|
1177
|
+
if (phase === "reach") {
|
|
1178
|
+
const p2 = time / r.reachSeconds;
|
|
1179
|
+
if (p2 < 1) return out(p2);
|
|
1180
|
+
phase = "swing";
|
|
1181
|
+
time = 0;
|
|
1182
|
+
start = opening;
|
|
1183
|
+
}
|
|
1184
|
+
if (phase === "swing") {
|
|
1185
|
+
const want = goal - opening;
|
|
1186
|
+
const reach = Math.min(Math.abs(want), dt / swing);
|
|
1187
|
+
let moved = 0;
|
|
1188
|
+
let stopped = false;
|
|
1189
|
+
while (moved < reach - 1e-9) {
|
|
1190
|
+
const inc = Math.min(r.stepFraction, reach - moved);
|
|
1191
|
+
const next = opening + Math.sign(want) * inc;
|
|
1192
|
+
if (!isFree(opening, next)) {
|
|
1193
|
+
stopped = true;
|
|
1194
|
+
break;
|
|
1195
|
+
}
|
|
1196
|
+
opening = next;
|
|
1197
|
+
moved += inc;
|
|
1198
|
+
}
|
|
1199
|
+
const travel = Math.abs(goal - start) || 1;
|
|
1200
|
+
if (stopped) {
|
|
1201
|
+
phase = "release";
|
|
1202
|
+
time = 0;
|
|
1203
|
+
return out(1 - Math.abs(goal - opening) / travel, false, "obstacle");
|
|
1204
|
+
}
|
|
1205
|
+
if (Math.abs(goal - opening) < 1e-6) {
|
|
1206
|
+
opening = goal;
|
|
1207
|
+
phase = "release";
|
|
1208
|
+
time = 0;
|
|
1209
|
+
return out(1, true);
|
|
1210
|
+
}
|
|
1211
|
+
return out(1 - Math.abs(goal - opening) / travel);
|
|
1212
|
+
}
|
|
1213
|
+
const p = time / r.releaseSeconds;
|
|
1214
|
+
if (p >= 1) {
|
|
1215
|
+
phase = "idle";
|
|
1216
|
+
}
|
|
1217
|
+
return out(p, false, null);
|
|
1218
|
+
},
|
|
1219
|
+
cancel() {
|
|
1220
|
+
phase = "idle";
|
|
1221
|
+
time = 0;
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1121
1225
|
export {
|
|
1226
|
+
DOOR_USE_DEFAULTS,
|
|
1122
1227
|
FURNITURE_PUSH_DEFAULTS,
|
|
1123
1228
|
PLAYER_DEFAULTS,
|
|
1124
1229
|
PLAYER_TEXT,
|
|
1125
1230
|
canPush,
|
|
1231
|
+
createDoorUse,
|
|
1126
1232
|
createFurniturePush,
|
|
1127
1233
|
createPlayer,
|
|
1128
1234
|
createPlayerTestModule,
|
|
@@ -1131,6 +1237,7 @@ export {
|
|
|
1131
1237
|
drawWound,
|
|
1132
1238
|
gripSecondsFor,
|
|
1133
1239
|
playerTextOf,
|
|
1134
|
-
pushSpeedFor
|
|
1240
|
+
pushSpeedFor,
|
|
1241
|
+
swingSecondsFor
|
|
1135
1242
|
};
|
|
1136
1243
|
//# sourceMappingURL=index.js.map
|