feat: CoC 7e d100 rule-pack
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
// Call of Cthulhu 7e success ladder vs a skill %.
|
||||
export const cocD100 = {
|
||||
id: 'coc-d100',
|
||||
label: 'd100 (Call of Cthulhu)',
|
||||
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 === 1) level = 'critical';
|
||||
else if (value <= Math.floor(target / 5)) level = 'extreme';
|
||||
else if (value <= Math.floor(target / 2)) level = 'hard';
|
||||
else if (value <= target) level = 'success';
|
||||
else if ((target < 50 && value >= 96) || value === 100) level = 'fumble';
|
||||
else level = 'failure';
|
||||
const success = ['critical', 'extreme', 'hard', 'success'].includes(level);
|
||||
return { value, target, level, success };
|
||||
},
|
||||
summary(v) {
|
||||
return `${v.value} vs ${v.target}% → ${v.level.toUpperCase()}`;
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import { yearZero } from './year-zero.js';
|
||||
import { cocD100 } from './coc-d100.js';
|
||||
|
||||
const packs = new Map([[yearZero.id, yearZero]]);
|
||||
const packs = new Map([[yearZero.id, yearZero], [cocD100.id, cocD100]]);
|
||||
|
||||
export function getRulePack(id) { return packs.get(id) || null; }
|
||||
export function registerRulePack(pack) { packs.set(pack.id, pack); }
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { cocD100 } from '../../src/dice/rulepacks/coc-d100.js';
|
||||
import { getRulePack } from '../../src/dice/rulepacks/index.js';
|
||||
|
||||
const roll = (v) => [{ sides: 100, value: v }];
|
||||
|
||||
describe('coc-d100 rule-pack', () => {
|
||||
it('grades a roll against a 50% skill', () => {
|
||||
expect(cocD100.interpret(roll(1), { target: 50 }).level).toBe('critical');
|
||||
expect(cocD100.interpret(roll(10), { target: 50 }).level).toBe('extreme'); // <= 10
|
||||
expect(cocD100.interpret(roll(25), { target: 50 }).level).toBe('hard'); // <= 25
|
||||
expect(cocD100.interpret(roll(50), { target: 50 }).level).toBe('success');
|
||||
expect(cocD100.interpret(roll(51), { target: 50 }).level).toBe('failure');
|
||||
expect(cocD100.interpret(roll(100), { target: 50 }).level).toBe('fumble');
|
||||
});
|
||||
it('fumbles on 96+ when the skill is under 50', () => {
|
||||
expect(cocD100.interpret(roll(96), { target: 40 }).level).toBe('fumble');
|
||||
expect(cocD100.interpret(roll(41), { target: 40 }).level).toBe('failure');
|
||||
});
|
||||
it('marks the four passing bands as success', () => {
|
||||
expect(cocD100.interpret(roll(10), { target: 50 }).success).toBe(true);
|
||||
expect(cocD100.interpret(roll(51), { target: 50 }).success).toBe(false);
|
||||
});
|
||||
it('defaults target to 50 and summarises', () => {
|
||||
const v = cocD100.interpret(roll(5));
|
||||
expect(v.target).toBe(50);
|
||||
expect(cocD100.summary(v)).toBe('5 vs 50% → EXTREME');
|
||||
});
|
||||
it('is registered', () => {
|
||||
expect(getRulePack('coc-d100')).toBe(cocD100);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user