Generators
A plugin tool that makes new places, creatures and things while people are playing.
Everything else a plugin does works on things that already exist. A generator (a plugin tool) makes new ones during play, in response to what the players did.
You describe the job in a sentence:
Add one new location further into the mine, connected to where they are standing.
Put something in it: something living, something worth taking, or nothing if the
place should be empty. Reuse creatures and items this mine already has where they
fit, rather than inventing near-duplicates.
That goes to an agent with the same tools as the game editor. It reads your world, then writes locations, items, creatures, characters, effects and abilities.
Tell it to reuse
A generator that only makes new things produces a list, not a world. The tenth room gets the tenth new monster and nothing feels like it belongs. Because it reads before it writes, it can put more of the crawlers from four rooms ago here instead. Say "reuse what fits", or it won't.
Where it writes
Everything a generator makes belongs to that play session, never to your game. Two groups playing your world get different mines. Your authored game stays exactly as you left it. A generator can also make a session-only version of something you wrote, like your innkeeper in a worse mood.
Declaring one
{
"key": "newRoom",
"describe": "The task, in your own words.",
"context": "'They are ' + ($.player.fields.depth || 0) + ' rooms in.'",
"body": "$.spawnItem({ itemExpr: $.minted.name })",
"fallback": "Copper Bit"
}
describe: the task. What to make. Don't explain what an item is; it knows.context: an expression giving what's happening right now, as prose. "They're nine rooms deep and just collapsed a tunnel."body: optional rule steps to run afterwards.fallback: an authored item to use if generation fails. Always set one.
Firing it
From a rule, for anything mechanical: a threshold, a timer, a place reached.
if ($.field('corruption') > 80) {
$.tool({ tool: 'spawnBloom' })
}
At the edge of the map, use the onMapEdge hook. It fires when the party
arrives somewhere with every exit already visited, which is exactly when a dungeon should grow:
// hook: onMapEdge
$.tool({ tool: 'newRoom' })
The room is made on arrival, so it's there to walk into next turn.
From the model's judgment, for questions about the fiction ("did that fight leave salvage?"): add a yes/no field to a section and fire the tool in the section's body when the answer is yes.
if ($.answer.leftSalvage) {
$.tool({ tool: 'salvage' })
}
Acting on what it made
A generator writes definitions. To put the new item on the floor or the new creature in the
room, use the body. It can't know the name in advance, so read it from $.minted.name:
$.spawnItem({ itemExpr: $.minted.name })
$.spawn({ mobExpr: $.minted.name })
$.grantAbility({ abilityExpr: $.minted.name })
The Expr versions take an expression; the plain ones take a fixed name. Use one or the other.
Cost
A generator is an extra model call while the player waits. It's capped (twelve tool calls, six writes), so a runaway costs a slow turn, not a slow evening. It still costs something every time, so gate it. A generator with no condition runs every turn.
Put it on background when the result can wait, so the player doesn't. Put it on
rollPreprocess when the narrator has to describe what appeared this turn.
What it can't do
- Edit plugins. A running game doesn't rewrite its own rules.
- Delete things. A player might be holding or standing in them.
- Change your game. Only the session.