feat: rule-pack contract v2 (params + summary) and registry listing
This commit is contained in:
@@ -11,6 +11,7 @@ export class DiceTray extends HTMLElement {
|
||||
this._systemId = 'year-zero';
|
||||
this.rng = Math.random;
|
||||
this.last = null;
|
||||
this.params = {};
|
||||
}
|
||||
get sides() { return this._sides; }
|
||||
set sides(v) { this._sides = Number(v); this.render(); }
|
||||
@@ -24,7 +25,7 @@ export class DiceTray extends HTMLElement {
|
||||
roll() {
|
||||
const { results, total } = rollPool([{ sides: this._sides, count: this._count }], this.rng);
|
||||
const pack = getRulePack(this._systemId);
|
||||
const verdict = pack ? pack.interpret(results) : null;
|
||||
const verdict = pack ? pack.interpret(results, this.params) : null;
|
||||
this.last = { results, total, verdict };
|
||||
this.render();
|
||||
this.dispatchEvent(new CustomEvent('rolled', { detail: this.last, bubbles: true }));
|
||||
@@ -36,9 +37,9 @@ export class DiceTray extends HTMLElement {
|
||||
const felt = this.last
|
||||
? this.last.results.map((r) => `<span class="rolled" data-value="${r.value}">${r.value}</span>`).join('')
|
||||
: '<span class="hint">Tap Roll</span>';
|
||||
const pack = getRulePack(this._systemId);
|
||||
const verdict = this.last?.verdict
|
||||
? `${this.last.verdict.successes} success${this.last.verdict.successes === 1 ? '' : 'es'}` +
|
||||
(this.last.verdict.ones ? ` · ${this.last.verdict.ones} stress` : '')
|
||||
? (pack && pack.summary ? pack.summary(this.last.verdict) : '')
|
||||
: '';
|
||||
|
||||
this.innerHTML = `
|
||||
|
||||
@@ -4,3 +4,6 @@ const packs = new Map([[yearZero.id, yearZero]]);
|
||||
|
||||
export function getRulePack(id) { return packs.get(id) || null; }
|
||||
export function registerRulePack(pack) { packs.set(pack.id, pack); }
|
||||
export function listRulePacks() {
|
||||
return [...packs.values()].map((p) => ({ id: p.id, label: p.label }));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
export const yearZero = {
|
||||
id: 'year-zero',
|
||||
label: 'Year-Zero',
|
||||
interpret(results) {
|
||||
params: [],
|
||||
interpret(results, params = {}) {
|
||||
let successes = 0, ones = 0;
|
||||
for (const r of results) {
|
||||
if (r.value >= 10) successes += 2;
|
||||
@@ -10,4 +11,8 @@ export const yearZero = {
|
||||
}
|
||||
return { successes, ones, canPush: true, isCritical: successes >= 2 };
|
||||
},
|
||||
summary(v) {
|
||||
const base = `${v.successes} success${v.successes === 1 ? '' : 'es'}`;
|
||||
return v.ones ? `${base} · ${v.ones} stress` : base;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { getRulePack, listRulePacks } from '../../src/dice/rulepacks/index.js';
|
||||
|
||||
describe('rule-pack registry', () => {
|
||||
it('lists registered packs as {id,label}', () => {
|
||||
const packs = listRulePacks();
|
||||
expect(packs.some((p) => p.id === 'year-zero' && typeof p.label === 'string')).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -24,3 +24,15 @@ describe('year-zero rule-pack', () => {
|
||||
expect(getRulePack('x')).toBe(custom);
|
||||
});
|
||||
});
|
||||
|
||||
describe('year-zero contract v2', () => {
|
||||
it('exposes an empty params list and a summary string', () => {
|
||||
expect(yearZero.params).toEqual([]);
|
||||
expect(yearZero.summary({ successes: 2, ones: 1 })).toBe('2 successes · 1 stress');
|
||||
expect(yearZero.summary({ successes: 1, ones: 0 })).toBe('1 success');
|
||||
});
|
||||
it('interpret ignores a params argument', () => {
|
||||
const v = yearZero.interpret([{ sides: 8, value: 8 }], { anything: true });
|
||||
expect(v.successes).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user