/** * What a creature's POWER actually does in a fight. * * Every statblock in content.mjs carries its tactics as prose, and 41 of them contain a * POWER. R-274 found that none of them reach `simulate.mjs`: the harness reads * characteristics and weapons and has no idea a redcap ignores the thing that makes every * other defender worse. So the redcap has been measured — in check-lethality, in * check-focus, in every figure this project has published about it — as a creature that * tires, which its own entry says it does not. * * This is the classification, not a second copy of the prose. content.mjs remains the * text; this says which of those powers are fight rules, which of the fight rules the * harness can express, and — for the ones it cannot — why, in one line, so the gap is a * recorded decision rather than an absence. * * wired the simulator applies it; `effect` says how * outOfCombat not a fight rule at all — a scene, a social problem, a clock * notSimulable a fight rule the harness cannot express, with the reason * * check-powers refuses any POWER in content.mjs that is not in one of the three, so a * creature added tomorrow cannot quietly arrive unclassified. That is the whole point: * the defect was not that the powers were unimplemented, it was that nothing said so. * * EFFECTS THE SIMULATOR UNDERSTANDS * defenceStacking: "ignores" the cumulative penalty never applies to its defences * damageFactor: n damage it takes is multiplied by n, floored * attackFactor: n its attack rating is multiplied by n, floored */ export const POWERS = { /* ---- wired: the harness applies these ---- */ redcap: { name: "NOT TIRED", kind: "wired", effect: { defenceStacking: "ignores" }, note: "every parry it makes is at full skill" }, the_courier: { name: "THE CONSIGNMENT", kind: "wired", effect: { attackFactor: 0.5 }, note: "it will not fight with the carrying limb, so it attacks at half until the consignment is taken" }, /* ---- notSimulable: fight rules the harness cannot express ---- */ /* Wired first, and reverted on the measurement. Halving everything the supporter takes tripled its wipe rate — 25.1% to 75.2% against the frozen party — because the harness has no ground and so applied "while it stands on ground the borough holds" unconditionally. That is a 50-point swing resting on an assumption the harness cannot state, which is the same reason THE PULL is not wired: a power conditional on a place cannot be simulated by something with no places in it. R-275. */ supporter: { name: "ARGENT AND GULES", kind: "notSimulable", why: "half damage only on ground the borough holds, and the harness has no ground — wiring it " + "unconditionally moved its wipe rate 25.1% to 75.2%, which is the assumption speaking" }, the_choir: { name: "ONE VOICE", kind: "notSimulable", why: "costs Coherence, which the harness does not model" }, hollow_man: { name: "THE FILE IS YOURS NOW", kind: "notSimulable", why: "an opposed POWx5 whose stake is Coherence, which the harness does not model" }, carrion_file: { name: "AMENDMENT", kind: "notSimulable", why: "removes a trained skill permanently; the harness has no character to amend" }, the_understudy: { name: "REHEARSED", kind: "notSimulable", why: "acts before the agent it is copying, and the harness has no notion of which agent that is" }, the_predecessor: { name: "HANDOVER", kind: "notSimulable", why: "takes an agent's action for a task the harness does not model" }, grindylow: { name: "THE PULL", kind: "notSimulable", why: "only in water, and resolves as a grapple into the ASPHYXIA rules" }, nuckelavee: { name: "THE BLIGHT", kind: "notSimulable", why: "a CONx5 each round for 1 point; the harness rolls no characteristics" }, surveyor: { name: "ALREADY SURVEYED", kind: "notSimulable", why: "cover and ambush, neither of which the harness has" }, spriggan: { name: "WHAT IT REALLY IS", kind: "notSimulable", why: "runs at a smaller statblock until the barrow is disturbed, which is a scene state" }, long_walker: { name: "DISTANCE MEANS NOTHING", kind: "notSimulable", why: "damage buys movement rather than injury; the harness has no ground" }, the_stanchion: { name: "DRIVEN", kind: "notSimulable", why: "its armour is already on the statblock; the rest is about a crossing" }, the_margin: { name: "NOT MENTIONED", kind: "notSimulable", why: "a Spot penalty for looking, and the harness never looks" }, the_relay: { name: "WHILE QUORATE", kind: "notSimulable", why: "body count holds a crossing open; nothing about the fight itself" }, /* ---- outOfCombat: not fight rules ---- */ barghest: { name: "THE SUMMONS", kind: "outOfCombat" }, kelpie: { name: "ADHESION", kind: "outOfCombat", why: "its own entry says run ASPHYXIA and not a combat" }, boggart: { name: "THE WRONG NAME", kind: "outOfCombat" }, churchgrim: { name: "THE GROUND IS MINE", kind: "outOfCombat" }, the_tenant: { name: "TENANCY", kind: "outOfCombat" }, precedent: { name: "COUNTERSIGNED", kind: "outOfCombat" }, quarantine_unit: { name: "STERILISATION ORDER", kind: "outOfCombat" }, cuckoo_array: { name: "HOUSE RULES", kind: "outOfCombat" }, auditor: { name: "THE DISCREPANCY", kind: "outOfCombat" }, washer_ford: { name: "THE COLLAR", kind: "outOfCombat" }, lantern_man: { name: "THE SHORTER WAY", kind: "outOfCombat" }, knockers: { name: "THE KNOCK", kind: "outOfCombat" }, hedley_kow: { name: "THE SWAP", kind: "outOfCombat" }, apple_man: { name: "THE RECKONING", kind: "outOfCombat" }, the_committee: { name: "RESOLVED", kind: "outOfCombat" }, night_registry: { name: "CORRECTLY FILED", kind: "outOfCombat" }, the_locum: { name: "OF COURSE", kind: "outOfCombat" }, lost_property: { name: "UNCLAIMED", kind: "outOfCombat" }, the_minutes: { name: "AS AGREED", kind: "outOfCombat" }, waiting_room: { name: "SHORTLY", kind: "outOfCombat" }, switchboard: { name: "PUTTING YOU THROUGH", kind: "outOfCombat" }, the_census: { name: "ENUMERATED", kind: "outOfCombat", why: "its own entry says the threat is not a combat one" }, the_yield: { name: "THE COUNT", kind: "outOfCombat" }, the_overwriter: { name: "THE CORRECTION", kind: "outOfCombat" }, the_arrears: { name: "THE PRINCIPAL", kind: "outOfCombat" } }; export const EFFECT_KINDS = ["defenceStacking", "damageFactor", "attackFactor"]; /** The fight effect for a creature, or null. Only `wired` powers have one. */ export function combatPowerFor(key) { const p = POWERS[key]; return p && p.kind === "wired" ? p.effect : null; }