@adatechnology/game-player 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/locales/index.ts","../src/player.ts","../src/data/defaults.json","../src/rng.ts","../src/bench/locale.ts","../src/bench/module.ts"],"sourcesContent":["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","import { SWING_LEAD_SECONDS, footstepSoundId, hitSoundId, landSoundId, surfaceOfMaterial, swingSoundId } from '@adatechnology/game-contracts'\nimport type { BlowId, BodyFoleyId, SurfaceId } from '@adatechnology/game-contracts'\n\nimport 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, ids: readonly BodyFoleyId[], surface?: SurfaceId, at?: readonly number[]): void =>\n emit('sound', { sound: id, ids, volume, position: [P.x, P.y, P.z], ...(surface ? { surface } : {}), ...(at ? { at } : {}) })\n // what is under the feet: the host's word this frame, else the world's, else concrete; water wins over everything\n let surfaceHint: string | undefined\n const surfaceHere = (): SurfaceId => (inWater(P.x, P.z) ? 'water' : surfaceOfMaterial(surfaceHint ?? world.surfaceAt?.(P.x, P.z)))\n // set by the first `footfall` the host sends: from then on its feet, not the stride timer, decide the footsteps\n let hostFeet = false\n const blowOf = (item: MeleeItem): BlowId => item.blow ?? (item === fist ? 'punch' : (item.crit ?? 0) > 0 ? 'blade' : 'blunt')\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, ['player_hurt'])\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, ['bite', 'player_hurt'])\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, ['grab'])\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, ['shove_two_hands'])\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 const blow = blowOf(item)\n const swing = swingSoundId(blow)\n if (!t) {\n sound('flesh', numbers.meleeVolume, swing ? [swing] : [])\n noise(P.x, P.z, item.noise || 1)\n return\n }\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 hit = hitSoundId(blow, region === 0 ? 'head' : 'body')\n if (swing) sound('flesh', numbers.meleeVolume, [swing, hit], undefined, [0, SWING_LEAD_SECONDS[blow]])\n else sound('flesh', numbers.meleeVolume, [hit])\n noise(P.x, P.z, item.noise || 1)\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 surfaceHint = input.surface\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, ['cloth_rustle'])\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, ['shove_two_hands'])\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 const surface = surfaceHere()\n sound('step', numbers.vaultLandVolume, [landSoundId(surface, 0)], surface)\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, ['jump'])\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 // the host's feet (`input.footfall`) once it sends them, else the stride timer\n if (input.footfall) hostFeet = true\n P.stepTimer -= dt * spd\n const stepNow = hostFeet ? input.footfall === true : P.stepTimer <= 0 && spd > numbers.stepMinSpeed\n if (stepNow) {\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 const surface = surfaceHere()\n sound('step', P.running ? numbers.stepVolumeRun : numbers.stepVolumeWalk, [footstepSoundId(surface, P.running ? 'run' : 'walk')], surface)\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 \"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","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, GaitId, ModuleControl, ModuleHost, ModuleMetric, ModuleScenario, SurfaceId, 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\n/** Metres per second above which a move of the view is a jump of the camera, not the body walking. */\nconst TELEPORT_SPEED = 10\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 footfall = false\n let surface: SurfaceId | undefined\n let gait: GaitId | undefined\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 // the body sounds of each event (a footstep on its surface, the swing and then the hit of a blow); the team's class only when it names none\n offs.push(\n made.on('sound', (e) => {\n if (e.ids.length === 0) return\n e.ids.forEach((id, index) => {\n const delay = e.at?.[index] ?? 0\n host?.audio?.play({ sound: id, volume: e.volume, position: e.position, ...(delay > 0 ? { delay } : {}) })\n })\n }),\n )\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 raw = here && last && dt > 0 ? Math.hypot(here.x - last.x, here.z - last.z) / dt : 0\n // faster than anyone runs is the view put somewhere else (an area opening, a scripted look), not a walk: no footstep for it\n const speed = raw > TELEPORT_SPEED ? 0 : raw\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: gait ? gait === 'run' : speed > SPRINT_SPEED, yaw: here?.yaw ?? 0, bandage, pressed: pending, footfall, ...(surface ? { surface } : {}) }\n pending = {}\n footfall = false\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 // the host's body puts its feet down: the footsteps follow it (and what it says is under them)\n const offFeet = lent.on((event) => {\n if (event.type !== 'footfall') return\n footfall = true\n surface = event.surface\n gait = event.gait\n })\n return () => {\n off?.()\n offFrame()\n offFeet()\n host = null\n }\n },\n }\n return module\n}\n"],"mappings":"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","names":["EN","PT_BR","id"]}
package/dist/index.d.ts CHANGED
@@ -1,394 +1,6 @@
1
- import { TestableModule } from '@adatechnology/game-contracts';
2
-
3
- var numbers = {
4
- hurtFlash: 0.4,
5
- hurtVolume: 0.8,
6
- biteDamage: 25,
7
- biteFlash: 0.8,
8
- biteVolume: 1.2,
9
- burnPerSecond: 3,
10
- bleedPerSecond: 0.15,
11
- grabSeconds: 3,
12
- grabVolume: 1,
13
- grabFollow: 12,
14
- grabOffset: 0.55,
15
- grabPushCost: 6,
16
- grabPushMinStamina: 5,
17
- grabPushVolume: 1.5,
18
- grabPushes: 6,
19
- grabPushStun: 1.2,
20
- grabPushSpeed: 3,
21
- grabKnifeChance: 0.7,
22
- grabKnifeRegion: 0,
23
- grabKnifeDamage: 22,
24
- grabKnifeDistance: 0.5,
25
- grabKnifeCut: 0.7,
26
- drownDamage: 30,
27
- drownFlash: 0.8,
28
- noJawDamage: 8,
29
- grabAttackCooldown: 2,
30
- vaultSeconds: 0.7,
31
- vaultCost: 15,
32
- vaultHeight: 1.9,
33
- vaultScanFrom: 0.3,
34
- vaultScanTo: 1,
35
- vaultScanStep: 0.1,
36
- vaultLandFrom: 0.4,
37
- vaultLandTo: 1.4,
38
- vaultClearance: 0.3,
39
- vaultCheckHeight: 0.4,
40
- vaultNoise: 6,
41
- vaultStartVolume: 0.8,
42
- vaultLandVolume: 1,
43
- crouchSpeed: 1,
44
- walkFactor: 1.35,
45
- aimSpeedCap: 1.4,
46
- waterSpeed: 0.55,
47
- runMinStamina: 1,
48
- runDrain: 12,
49
- regenMoving: 4,
50
- regenStill: 8,
51
- acceleration: 10,
52
- radius: 0.3,
53
- blockHeight: 0.4,
54
- pushApartRadius: 0.55,
55
- pushApartHeight: 1.2,
56
- hipFollow: 10,
57
- hipMinSpeed: 0.3,
58
- hipLimit: 0.9,
59
- backwardsBelow: -0.1,
60
- cadenceBase: 0.5,
61
- cadencePerSpeed: 0.3,
62
- cadenceMinSpeed: 0.05,
63
- turnFollow: 12,
64
- stepEvery: 0.75,
65
- stepMinSpeed: 0.3,
66
- stepNoiseRun: 8,
67
- stepNoiseWalk: 3,
68
- stepNoiseCrouch: 1,
69
- stepNoiseWater: 2,
70
- stepVolumeRun: 0.6,
71
- stepVolumeWalk: 0.3,
72
- shoveCost: 10,
73
- shoveVolume: 1.2,
74
- shoveRange: 1.6,
75
- shoveCone: 0.3,
76
- shoveStun: 0.9,
77
- shoveSpeed: 2.5,
78
- meleeMinStamina: 5,
79
- meleeCostLight: 5,
80
- meleeCostHeavy: 12,
81
- meleeHeavyKg: 1.5,
82
- meleeVolume: 0.6,
83
- meleeRangeBase: 0.9,
84
- meleeCone: 0.5,
85
- meleeHeadChance: 0.35,
86
- meleeArmChance: 0.5,
87
- meleeStrengthPerPoint: 0.06,
88
- meleeStrengthBase: 5,
89
- meleeCritToCut: 60,
90
- panicGain: 1.2,
91
- panicDecay: 3,
92
- panicMax: 100,
93
- panicSpreadAt: 0.6,
94
- panicSpread: 1.4,
95
- moveSpread: 0.4
96
- };
97
- var defaults = {
98
- numbers: numbers};
99
-
100
- type AttributeId = 'strength' | 'vigor' | 'agility' | 'perception' | 'intellect' | 'presence';
101
- type Attributes = Readonly<Record<AttributeId, number>>;
102
- /** `(base + Σ coefficient × attribute) / divide`, summed left to right in the order given (the game's own order, so the floats match). */
103
- type LinearFormula = {
104
- readonly base: number;
105
- readonly terms: readonly (readonly [AttributeId, number])[];
106
- readonly divide?: number;
107
- };
108
- type DerivedId = 'maxHealth' | 'maxStamina' | 'runSpeed' | 'walkSpeed' | 'footstepNoise' | 'composure';
109
- type DerivedFormulas = Readonly<Record<DerivedId, LinearFormula>>;
110
- type Derived = Readonly<Record<DerivedId, number>>;
111
- /** A wound kind: its share of the hits (drawn in the listed order, the last one takes the rest), its infection chance and whether it bleeds. */
112
- type WoundRule = {
113
- readonly share: number;
114
- readonly infectionChance: number;
115
- readonly bleeds: boolean;
116
- };
117
- type WoundTable = Readonly<Record<string, WoundRule>>;
118
- /** An individual infection that runs on its own clock and kills at `deathSeconds`. Off by default: a normal world has none. */
119
- type InfectionRule = {
120
- readonly feverSeconds: number;
121
- readonly deliriumSeconds: number;
122
- readonly deathSeconds: number;
123
- /** Seconds after death the body turns (`turned` event). */
124
- readonly reanimateSeconds: number;
125
- /** With fever, every this many seconds there is a `feverNoiseChance` of a cough: noise of `feverNoiseRadius` m. */
126
- readonly feverNoiseEvery: number;
127
- readonly feverNoiseChance: number;
128
- readonly feverNoiseRadius: number;
129
- readonly feverNoiseVolume: number;
130
- readonly feverSpeed: number;
131
- readonly feverSpread: number;
132
- /** Infection chance per wound kind; a kind left out uses the wound table's `infectionChance`. */
133
- readonly chances?: Readonly<Record<string, number>>;
134
- };
135
- type PlayerNumbers = typeof defaults.numbers;
136
- /** What is in the hand for melee (the fist when absent): damage, critical (0..60 turns into a cut), reach in metres, noise radius, mass. */
137
- type MeleeItem = {
138
- readonly damage: number;
139
- readonly crit?: number;
140
- readonly reach?: number;
141
- readonly noise?: number;
142
- readonly kg?: number;
143
- };
144
- /** One frame of input. Held keys are booleans; the `pressed` ones are true only on the frame the key went down. */
145
- type PlayerInput = {
146
- /** -1 back, 0, 1 forward. */
147
- readonly forward?: number;
148
- /** -1 left, 0, 1 right. */
149
- readonly right?: number;
150
- readonly run?: boolean;
151
- /** Aiming down the sights: speed is capped and the body turns with the view at once. */
152
- readonly aim?: boolean;
153
- /** The trigger is held or the weapon is cooling: the body turns with the view at once. */
154
- readonly firing?: boolean;
155
- /** Where the view looks (radians, the camera's yaw: forward is `(-sin, -cos)`). */
156
- readonly yaw?: number;
157
- /** Held: dress the bleeding wound. */
158
- readonly bandage?: boolean;
159
- readonly pressed?: Readonly<Partial<Record<PlayerAction, boolean>>>;
160
- /** The melee item in hand. */
161
- readonly melee?: MeleeItem;
162
- };
163
- type PlayerAction = 'crouch' | 'push' | 'knife' | 'vault' | 'throw';
164
- /**
165
- * The crowd the player touches (a horde, any crowd): read by index, written through a few verbs. `game-crowd` implements it; a game with its own
166
- * agents writes a small adapter. Only agents that are `active` (close and simulated every frame) are pushed, counted for panic or hit.
167
- */
168
- interface PlayerCrowd {
169
- count(): number;
170
- active(i: number): boolean;
171
- x(i: number): number;
172
- z(i: number): number;
173
- y(i: number): number;
174
- floor(i: number): number;
175
- chasing(i: number): boolean;
176
- /** On the ground: crawling or stunned. A melee blow on it always goes to the head. */
177
- down(i: number): boolean;
178
- /** How much it adds to panic (default 1). */
179
- panicWeight?(i: number): number;
180
- /** The grabbing agent is glued to the player's body: move by `k` of the way to (x, z), stop, and face (lookX, lookZ). */
181
- hold(i: number, x: number, z: number, k: number, lookX: number, lookZ: number): void;
182
- stun(i: number, seconds: number, vx: number, vz: number): void;
183
- /** Back to chasing, with the attack cooling for `cooldown` seconds. */
184
- chase(i: number, cooldown: number): void;
185
- damage(i: number, hit: {
186
- region: number;
187
- amount: number;
188
- distance: number;
189
- cut: number;
190
- }): void;
191
- }
192
- /** What the player asks of the world. Everything is optional: the default is an open, dry field. */
193
- interface PlayerWorld {
194
- /** Occupancy code of the cell at (x, z): -1 outside, 0 free, 1 solid, 2 low wall that can be vaulted, 3 open door, others solid. */
195
- cellKind?(x: number, z: number): number;
196
- solidAt?(x: number, z: number, y: number): boolean;
197
- /** Blocks the player's body at (x, z). Default `solidAt(x, z, blockHeight)` (a roof or a floor plan passes its own). */
198
- blocked?(x: number, z: number): boolean;
199
- inWater?(x: number, z: number): boolean;
200
- /** Something else drives the player this frame (a car seat, a chair, a ladder): skip moving. */
201
- busy?(dt: number): boolean;
202
- /** Low walls can be vaulted here (the game says no on a roof or an upper floor). Default: only on the ground floor. */
203
- canVault?(): boolean;
204
- /** After the move (stairs change the floor and the height). */
205
- afterMove?(player: PlayerState): void;
206
- crowd?: PlayerCrowd;
207
- }
208
- type PlayerState = {
209
- x: number;
210
- z: number;
211
- y: number;
212
- vx: number;
213
- vz: number;
214
- /** The body's yaw (the view's yaw + π, smoothed). */
215
- yaw: number;
216
- floor: number;
217
- alive: boolean;
218
- turned: boolean;
219
- health: number;
220
- stamina: number;
221
- crouch: boolean;
222
- running: boolean;
223
- stepTimer: number;
224
- phase: number;
225
- hip: number;
226
- grabbedBy: number;
227
- grabTimer: number;
228
- grabPushes: number;
229
- grabNoJaw: boolean;
230
- grabDrown: boolean;
231
- infected: boolean;
232
- infectionTime: number;
233
- infectionSource: string;
234
- wounds: string[];
235
- bleeding: number;
236
- blind: number;
237
- screamBoost: number;
238
- panic: number;
239
- hurtFlash: number;
240
- deathTime: number;
241
- cause: string;
242
- downTimer: number;
243
- burnTimer: number;
244
- scentTimer: number;
245
- vaultTimer: number;
246
- vault: [number, number, number, number] | null;
247
- };
248
- type PlayerSoundId = 'step' | 'flesh';
249
- type PlayerMessageId = 'grabbed' | 'grabbed_drown' | 'bitten' | 'bandaged' | 'knife_head' | 'knife_miss' | 'pushed_off' | 'drowning' | 'no_jaw' | 'stood_up';
250
- type KnownDeathCause = 'infected' | 'killed' | 'bitten_to_death' | 'infection' | 'bled_out' | 'hunger_thirst' | 'drowned' | 'burned';
251
- /** Why the player died: the rule's own causes, or any id the host passes to `die`. */
252
- type DeathCause = KnownDeathCause | (string & {});
253
- type PlayerEventMap = {
254
- noise: {
255
- x: number;
256
- z: number;
257
- radius: number;
258
- };
259
- sound: {
260
- sound: PlayerSoundId;
261
- volume: number;
262
- position: [number, number, number];
263
- };
264
- step: {
265
- x: number;
266
- z: number;
267
- yaw: number;
268
- };
269
- message: {
270
- id: PlayerMessageId | DeathCause;
271
- seconds: number;
272
- };
273
- hurt: {
274
- amount: number;
275
- wound: string;
276
- };
277
- infected: {
278
- source: string;
279
- };
280
- stage: {
281
- stage: 'fever' | 'delirium';
282
- };
283
- died: {
284
- cause: DeathCause;
285
- };
286
- turned: {
287
- x: number;
288
- z: number;
289
- floor: number;
290
- };
291
- grabbed: {
292
- by: number;
293
- noJaw: boolean;
294
- drown: boolean;
295
- };
296
- released: {
297
- by: number;
298
- how: 'push' | 'knife' | 'bite' | 'scratch' | 'free';
299
- };
300
- vault: {
301
- from: [number, number];
302
- to: [number, number];
303
- };
304
- shove: {
305
- targets: number[];
306
- };
307
- melee: {
308
- target: number;
309
- region: number;
310
- damage: number;
311
- distance: number;
312
- cut: number;
313
- };
314
- throw: Record<string, never>;
315
- };
316
- type PlayerEventName = keyof PlayerEventMap;
317
- type PlayerEvent<K extends PlayerEventName = PlayerEventName> = PlayerEventMap[K];
318
- type PlayerSave = {
319
- readonly state: PlayerState;
320
- readonly attributes: Attributes;
321
- };
322
-
323
- declare const PLAYER_DEFAULTS: {
324
- readonly sources: Readonly<Record<string, string>>;
325
- readonly attributes: Attributes;
326
- readonly derived: DerivedFormulas;
327
- readonly wounds: WoundTable;
328
- readonly infection: InfectionRule;
329
- readonly numbers: PlayerNumbers;
330
- readonly fist: MeleeItem;
331
- };
332
- type PlayerOptions = {
333
- /** The random stream (the game passes its single stream). Default `createRng(seed)`. */
334
- readonly random?: () => number;
335
- readonly seed?: number;
336
- /** The sheet: every attribute 5 by default. */
337
- readonly attributes?: Partial<Attributes>;
338
- readonly derived?: Partial<DerivedFormulas>;
339
- readonly wounds?: WoundTable;
340
- /** An individual infection (`true` uses the defaults; an object patches them). Off by default: the normal world comes first. */
341
- readonly infection?: boolean | Partial<InfectionRule>;
342
- readonly numbers?: Partial<PlayerNumbers>;
343
- readonly fist?: MeleeItem;
344
- readonly position?: {
345
- readonly x?: number;
346
- readonly z?: number;
347
- readonly yaw?: number;
348
- };
349
- readonly world?: PlayerWorld;
350
- };
351
- type Player = {
352
- readonly state: PlayerState;
353
- readonly attributes: Attributes;
354
- readonly derived: Derived;
355
- readonly numbers: PlayerNumbers;
356
- readonly infection: InfectionRule | null;
357
- update(dt: number, input?: PlayerInput, world?: PlayerWorld): void;
358
- /** A hit that opens a wound (drawn from the wound table) and may infect. `by` is the agent that hit, if any. */
359
- hurt(amount: number, by?: number): void;
360
- /** A bite: damage, bleeding, a bite wound and (with an infection rule) the infection. */
361
- bite(by?: number): void;
362
- grab(by: number, noJaw?: boolean, drown?: boolean): void;
363
- release(): void;
364
- knock(seconds: number): void;
365
- infect(source: string): void;
366
- /** Kills the player with a cause (the host's deaths: a fall, a fire). */
367
- die(cause: DeathCause): void;
368
- /** Infection stage: `none`, `malaise`, `fever`, `delirium`. */
369
- stage(): 'none' | 'malaise' | 'fever' | 'delirium';
370
- /** Seconds the infection has left, or null. */
371
- timeLeft(): number | null;
372
- /** What the player's state does to aim spread (panic, fever, moving); the weapon multiplies its own spread by it. */
373
- spreadFactor(): number;
374
- /** The agents in front (nearest first) within `range` m and a cone of `cosMin`, as `[distance, index]`. */
375
- front(range: number, cosMin: number, yaw: number, crowd?: PlayerCrowd): [number, number][];
376
- on<K extends PlayerEventName>(event: K, listener: (event: PlayerEventMap[K]) => void): () => void;
377
- save(): PlayerSave;
378
- load(save: PlayerSave): void;
379
- /** The world `update` uses when it is given none. */
380
- setWorld(world: PlayerWorld): void;
381
- };
382
- /** The derived values of a sheet (the game's `DERIV`). */
383
- declare const deriveVitals: (attributes: Attributes, formulas?: DerivedFormulas) => Derived;
384
- /** Which wound a hit opens: one draw, the kinds in the listed order, the last one takes the rest (the game's `FERIDA` draw). */
385
- declare const drawWound: (wounds: WoundTable, random: () => number) => string;
386
- /**
387
- * 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
388
- * arguments instead of globals. The draws on `random` happen in the game's order (wound kind, infection, the fever cough, the knife when grabbed,
389
- * the melee region), so a game that passes its own stream keeps its sequence.
390
- */
391
- declare function createPlayer(options?: PlayerOptions): Player;
1
+ import { P as PlayerMessageId, K as KnownDeathCause } from './testing-CD4p4NR5.js';
2
+ export { A as AttributeId, a as Attributes, D as DeathCause, b as Derived, c as DerivedFormulas, d as DerivedId, I as InfectionRule, L as LinearFormula, M as MeleeItem, e as PLAYER_DEFAULTS, f as Player, g as PlayerAction, h as PlayerCrowd, i as PlayerEvent, j as PlayerEventMap, k as PlayerEventName, l as PlayerInput, m as PlayerNumbers, n as PlayerOptions, o as PlayerSave, p as PlayerSoundId, q as PlayerState, r as PlayerTestModule, s as PlayerTestModuleOptions, t as PlayerWorld, W as WoundRule, u as WoundTable, v as createPlayer, w as createPlayerTestModule, x as deriveVitals, y as drawWound } from './testing-CD4p4NR5.js';
3
+ import '@adatechnology/game-contracts';
392
4
 
393
5
  /** Deterministic mulberry32 generator; returns floats in [0, 1). */
394
6
  declare function createRng(seed: number): () => number;
@@ -466,24 +78,6 @@ declare const PLAYER_TEXT: Readonly<Record<'en' | 'pt-BR', PlayerText>>;
466
78
  /** 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. */
467
79
  declare const playerTextOf: (id: string, locale?: string) => string;
468
80
 
469
- type PlayerTestModuleOptions = PlayerOptions & {
470
- readonly locale?: string;
471
- };
472
- /** What the scenarios use of the context the test room passes. */
473
- interface PlayerScenarioLike {
474
- expect(condition: boolean, label: string, data?: Record<string, unknown>): void;
475
- }
476
- type PlayerTestModule = TestableModule<PlayerScenarioLike> & {
477
- /** The player in use (replaced when the bench changes the sheet, the seed or the infection). */
478
- readonly player: Player;
479
- };
480
- /**
481
- * 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
482
- * decides walking or running, so stamina, footsteps and their noise follow the viewer. The bench hurts, bites, grabs and knocks the player down,
483
- * switches the individual infection (off by default: a normal world) and sets the sheet. Footsteps and flesh sounds go to `host.audio`.
484
- */
485
- declare function createPlayerTestModule(options?: PlayerTestModuleOptions): PlayerTestModule;
486
-
487
81
  /**
488
82
  * 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
489
83
  * follows the hand at a speed set by its mass, stops where something is in its way, and a locked leaf only rattles.
@@ -551,4 +145,4 @@ interface DoorUse {
551
145
  }
552
146
  declare function createDoorUse(rules?: Partial<DoorUseRules>): DoorUse;
553
147
 
554
- export { type AttributeId, type Attributes, DOOR_USE_DEFAULTS, type DeathCause, type Derived, type DerivedFormulas, type DerivedId, type DoorUse, type DoorUseBlock, type DoorUsePhase, type DoorUseRules, type DoorUseStep, type DoorUseTarget, FURNITURE_PUSH_DEFAULTS, type FurniturePush, type FurniturePushBlock, type FurniturePushInput, type FurniturePushPhase, type FurniturePushRules, type FurniturePushStep, type FurniturePushTarget, type InfectionRule, type KnownDeathCause, type LinearFormula, type MeleeItem, PLAYER_DEFAULTS, PLAYER_TEXT, type Player, type PlayerAction, type PlayerCrowd, type PlayerEvent, type PlayerEventMap, type PlayerEventName, type PlayerInput, type PlayerMessageId, type PlayerNumbers, type PlayerOptions, type PlayerSave, type PlayerSoundId, type PlayerState, type PlayerTestModule, type PlayerTestModuleOptions, type PlayerText, type PlayerWorld, type WoundRule, type WoundTable, canPush, createDoorUse, createFurniturePush, createPlayer, createPlayerTestModule, createRng, deriveVitals, drawWound, gripSecondsFor, playerTextOf, pushSpeedFor, swingSecondsFor };
148
+ export { DOOR_USE_DEFAULTS, type DoorUse, type DoorUseBlock, type DoorUsePhase, type DoorUseRules, type DoorUseStep, type DoorUseTarget, FURNITURE_PUSH_DEFAULTS, type FurniturePush, type FurniturePushBlock, type FurniturePushInput, type FurniturePushPhase, type FurniturePushRules, type FurniturePushStep, type FurniturePushTarget, KnownDeathCause, PLAYER_TEXT, PlayerMessageId, type PlayerText, canPush, createDoorUse, createFurniturePush, createRng, gripSecondsFor, playerTextOf, pushSpeedFor, swingSecondsFor };