feat(games): add the generic d6 oracle game package
Serves as the reference implementation of the game package contract: rules, spark tables, character backgrounds, and an example command.
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
# Character backgrounds
|
||||||
|
|
||||||
|
The game's menu of character options: backgrounds, playbooks, and starting
|
||||||
|
packages. Campaigns do not copy these files — the *actual* PC sheet lives in
|
||||||
|
`campaigns/<name>/characters/`. This directory is where the options come from.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `backgrounds.csv` — rollable starting backgrounds (`min,max,text,tags`).
|
||||||
|
Roll one with `journal background --campaign <name>`.
|
||||||
|
|
||||||
|
Add more files here for playbooks, archetypes, or species. If a file should be
|
||||||
|
rollable through `journal roll`, put it in `tables/` instead; files here are
|
||||||
|
read by game commands or by the agent directly.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
min,max,text,tags
|
||||||
|
1,1,"The Seeker — you left a safe life chasing a rumour",seeker
|
||||||
|
2,2,"The Warden — you are sworn to protect something you no longer trust",warden
|
||||||
|
3,3,"The Exile — you were cast out and have not stopped running",exile
|
||||||
|
4,4,"The Artisan — your hands make things that outlive you",artisan
|
||||||
|
5,5,"The Witness — you saw something you were never meant to see",witness
|
||||||
|
6,6,"The Debtor — someone paid for your life, and the bill is due",debtor
|
||||||
|
@@ -0,0 +1,47 @@
|
|||||||
|
# Generic d6 Oracle
|
||||||
|
|
||||||
|
System-agnostic solo play. No stats are required: the fiction and the d6 carry
|
||||||
|
the game. Use this as a base for a setting, or as the reference for how a game
|
||||||
|
package is structured.
|
||||||
|
|
||||||
|
## Resolution
|
||||||
|
|
||||||
|
Ask the oracle one yes/no question at a time:
|
||||||
|
|
||||||
|
```
|
||||||
|
journal oracle "Is the bridge still standing?" --campaign <name>
|
||||||
|
```
|
||||||
|
|
||||||
|
| d6 | Result | Meaning |
|
||||||
|
|----|--------|---------|
|
||||||
|
| 6 | **Yes, and…** | It works, with a fortunate extra. |
|
||||||
|
| 5 | **Yes** | It works, plainly. |
|
||||||
|
| 4 | **Yes, but…** | It works, at a cost. |
|
||||||
|
| 3 | **No, but…** | It fails, with an opening. |
|
||||||
|
| 2 | **No** | It fails, plainly. |
|
||||||
|
| 1 | **No, and…** | It fails, and something gets worse. |
|
||||||
|
|
||||||
|
On `and`/`but` results, pass `--complicate` to fold in a twist.
|
||||||
|
|
||||||
|
## The PC
|
||||||
|
|
||||||
|
Keep a minimal sheet: name, background, inventory, and any lasting conditions.
|
||||||
|
`stats` and `tracks` may stay empty. If a stat grows out of play, record its
|
||||||
|
shape in the campaign's `house-rules.md` so it stays consistent.
|
||||||
|
|
||||||
|
## Character creation
|
||||||
|
|
||||||
|
1. Roll a background: `journal background --campaign <name>`
|
||||||
|
2. Give the PC a name and one relationship to the world.
|
||||||
|
3. Write a starting situation into `campaign.md`.
|
||||||
|
|
||||||
|
## Pacing
|
||||||
|
|
||||||
|
End a scene when the situation changes or the player's intent resolves. Append
|
||||||
|
scenes; never rewrite them.
|
||||||
|
|
||||||
|
## Content
|
||||||
|
|
||||||
|
- `tables/sparks.csv` — general content prompts.
|
||||||
|
- `tables/complication-themes.csv` — twists on `and`/`but` results.
|
||||||
|
- `characters/backgrounds.csv` — rollable starting backgrounds.
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { parseTable, rollTable } from '@solo/oracle';
|
||||||
|
|
||||||
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
/** Roll a starting background from characters/backgrounds.csv. */
|
||||||
|
function background() {
|
||||||
|
const file = path.join(HERE, 'characters', 'backgrounds.csv');
|
||||||
|
const entries = parseTable(fs.readFileSync(file, 'utf8'));
|
||||||
|
const { roll, entry } = rollTable(entries);
|
||||||
|
const tags = entry.tags.length ? ` [${entry.tags.join(', ')}]` : '';
|
||||||
|
console.log(`background roll ${roll} → "${entry.text}"${tags}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A game package's default export is its manifest. See docs/games.md.
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
id: 'generic',
|
||||||
|
title: 'Generic d6 Oracle',
|
||||||
|
description: 'System-agnostic solo play driven by the d6 oracle and spark tables.',
|
||||||
|
rules: 'game.md',
|
||||||
|
commands: {
|
||||||
|
background: {
|
||||||
|
description: 'Roll a starting character background.',
|
||||||
|
run: background,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "@solo/game-generic",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"description": "System-agnostic d6 oracle play for solo journaling.",
|
||||||
|
"main": "index.js",
|
||||||
|
"exports": {
|
||||||
|
".": "./index.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@solo/oracle": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Rulebook
|
||||||
|
|
||||||
|
Longer-form rules content for this game, one markdown file per topic
|
||||||
|
(`resolution.md`, `harm.md`, `advancement.md`, ...).
|
||||||
|
|
||||||
|
`game.md` is the authoritative summary the agent reads before every session.
|
||||||
|
The chapters here expand on it and are read on demand.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Tool scripts
|
||||||
|
|
||||||
|
Game-specific tooling lives here. There are two ways to ship it:
|
||||||
|
|
||||||
|
1. **CLI commands** — export a `commands` map from the game's `index.js`. The
|
||||||
|
`journal` CLI exposes each entry as `journal <name>`, with the shared dice
|
||||||
|
and table helpers passed in. This is the recommended path for anything the
|
||||||
|
agent calls during play (see `../index.js` for the `background` example).
|
||||||
|
2. **Standalone scripts** — drop one-off executables in this directory, for
|
||||||
|
jobs like importing content or converting data, and run them with `node`.
|
||||||
|
|
||||||
|
See `docs/games.md` for the full contract.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
min,max,text,tags
|
||||||
|
1,1,"A past debt comes due",obligation
|
||||||
|
2,2,"An ally's hidden motive surfaces",npc
|
||||||
|
3,3,"The environment turns hostile",environment
|
||||||
|
4,4,"A resource runs out at the worst time",resource
|
||||||
|
5,5,"Someone else wants the same thing",rival
|
||||||
|
6,6,"A truth is revealed that reframes the goal",revelation
|
||||||
|
@@ -0,0 +1,7 @@
|
|||||||
|
min,max,text,tags
|
||||||
|
1,1,"A sign of recent passage",exploration
|
||||||
|
2,2,"Something out of place",mystery
|
||||||
|
3,3,"A sound that does not belong",tension
|
||||||
|
4,4,"A memory surfaces unbidden",character
|
||||||
|
5,5,"A stranger with an offer",npc
|
||||||
|
6,6,"A chance to change the plan",opportunity
|
||||||
|
Reference in New Issue
Block a user