feat: dedicated BRP dice pack; Day One uses it instead of coc-d100

Add brp-d100 rule-pack (Basic Roleplaying roll-under): fumble on 100,
critical <= skill/20, special <= skill/5, success <= skill — bands
transcribed from the Continuum Day One console's verdict() logic.
Register it and switch day-one meta.system from coc-d100 to brp-d100.

tests/dice/brp-d100.test.js covers the ladder, low-skill rounding, and
the fumble-only-on-100 edge. 147 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
slaguru666
2026-07-20 22:48:28 +01:00
co-authored by Claude Opus 4.8
parent 9d0e6c7ec4
commit 49e9dcda46
6 changed files with 79 additions and 6 deletions
+23
View File
@@ -0,0 +1,23 @@
// Basic Roleplaying (BRP) roll-under d100 ladder vs a skill %.
// Bands match the Continuum "Day One" console: fumble on 100, critical ≤ skill/20,
// special ≤ skill/5, success ≤ skill (the fractions rounded up).
export const brpD100 = {
id: 'brp-d100',
label: 'd100 (Basic Roleplaying)',
params: [{ key: 'target', label: 'Skill %', default: 50 }],
interpret(results, params = {}) {
const value = results[0]?.value ?? 0;
const target = params.target ?? 50;
let level;
if (value === 100) level = 'fumble';
else if (value <= Math.ceil(target / 20)) level = 'critical';
else if (value <= Math.ceil(target / 5)) level = 'special';
else if (value <= target) level = 'success';
else level = 'failure';
const success = ['critical', 'special', 'success'].includes(level);
return { value, target, level, success };
},
summary(v) {
return `${v.value} vs ${v.target}% → ${v.level.toUpperCase()}`;
},
};
+2 -1
View File
@@ -1,10 +1,11 @@
import { yearZero } from './year-zero.js';
import { cocD100 } from './coc-d100.js';
import { brpD100 } from './brp-d100.js';
import { vanityD6 } from './vanity-d6.js';
import { panicGlory } from './panic-glory.js';
import { deeSanction } from './dee-sanction.js';
const packs = new Map([[yearZero.id, yearZero], [cocD100.id, cocD100], [vanityD6.id, vanityD6], [panicGlory.id, panicGlory], [deeSanction.id, deeSanction]]);
const packs = new Map([[yearZero.id, yearZero], [cocD100.id, cocD100], [brpD100.id, brpD100], [vanityD6.id, vanityD6], [panicGlory.id, panicGlory], [deeSanction.id, deeSanction]]);
export function getRulePack(id) { return packs.get(id) || null; }
export function registerRulePack(pack) { packs.set(pack.id, pack); }
+2 -2
View File
@@ -1,8 +1,8 @@
// DAY ONE — "London Falls" · Continuum 2026 · Fri Slot 1.
// Timeline transcribed from gm-utility/day-one-console.html (SCHED array).
// System is BRP; mapped to the d100 roller pack (no dedicated BRP pack yet).
// System is BRP (Basic Roleplaying) — uses the dedicated brp-d100 rule-pack.
export default {
meta: { id: 'day-one', title: 'DAY ONE — London Falls', system: 'coc-d100', players: 6, playMinutes: 210, slot: 'Fri · Slot 1' },
meta: { id: 'day-one', title: 'DAY ONE — London Falls', system: 'brp-d100', players: 6, playMinutes: 210, slot: 'Fri · Slot 1' },
timeline: [
{ id: 'intro', label: 'Intro done — six placed, alert fired, players converging', targetMin: 15 },
{ id: 'market', label: 'MARKET BREAKS — vendor bitten in full view, stampede (force it now if not yet)', targetMin: 60, hardTrigger: true },