# Designing a plugin

A plugin that validates isn't finished. Most broken systems here save cleanly and then do
nothing, or do something nobody notices. This page is about getting past that.

## Start with the decision

A system is only interesting if it makes the player **choose** something. Before you declare a
field, finish this sentence:

> Because of this system, the player has to decide whether to ___.

- Hunger: *spend a day foraging, or push on hungry.*
- Infection: *treat the wound now with the only medicine, or save it.*
- Reputation: *help the smugglers, or stay welcome in town.*

If you can't fill the blank, you have a number, not a system.

## Every meter needs a way in and a way out

For each field, write down:

1. **What raises it.** Time, an action, a place, an enemy.
2. **What lowers it.** An item, a rest, a person, a ritual.
3. **What the fix costs.** A trip, money, a risk, a turn.

A meter nothing lowers is a countdown the player can't fight. A meter nothing raises never
moves. A fix that costs nothing isn't a decision.

The fixes usually live in the **world**, not the plugin: the herbalist who sells the cure, the
shrine that clears the curse. A plugin that ships without them is half a system. Say which
items, NPCs or places your plugin expects in its description.

## Make it visible

The player can't respond to what they can't see.

- **Tiers are how the narrator notices.** Write tier prose that shows up in the scene: "his
  hands have started to shake" beats "infection: moderate". See [Fields](/docs/fields).
- **Leave the calm tier silent.** If the lowest band says something, every turn carries a
  status report.
- **Put the important meter on the HUD.** If losing to it ends the run, it belongs on screen.
- **Warn before you punish.** Let a tier say "your stomach is hollow" before the damage
  starts. A penalty with no warning feels like a bug.

## Tune with dials, not literals

Every number a designer might want to change should be a [dial](/docs/formulas). Rates,
thresholds, costs. Then an author can make your plague deadly or mild without opening code.

- **Pick defaults by playing.** Play ten turns at the default. If the meter never reaches a
  tier, the rate is too low. If the player can't do anything else, it's too high.
- **Separate per-hour and per-turn rates** if your system uses time. See
  [Minutes are not time](/docs/minutes-are-not-time).
- **Let zero mean off.** An author who sets damage to 0 wants no damage. Check the dial before
  calling `$.damage`, since damage floors at 1.

## Play nicely with other plugins

- **Ask before you read.** `$.hasPlugin('hunger') && ...`, never a bare read of someone
  else's field.
- **Offer events instead of reaching in.** If other systems might want to stop your action,
  declare an event and let them `veto` it.
- **Don't take a seam unless you must.** Only one plugin can own each [seam](/docs/seams).
  Taking one locks every other plugin out of it.

The test for all of it: delete either plugin in any pair and the other still makes sense. See
[Cooperation](/docs/plugin-cooperation).

## Keep it small

One plugin, one idea. "Survival" as a single plugin with hunger, thirst, cold and sleep can only
be all on or all off. Four small plugins let an author take thirst and leave the cold.

Small plugins are also easier to debug. When a system does nothing, you want three hooks to
read, not thirty.

## When it does nothing

Most dead systems are one of these:

- **A field that's `null`.** Nobody has it, so every comparison fails. See
  [Missing values](/docs/missing-values).
- **Reading a different place than you wrote.** Values filled in a table, hook reads
  `$.location.fields`.
- **The wrong trigger.** An `onTimePasses` rule in a game with no clock, or an `onDamage` rule
  that should have been `onAttack`.
- **A frozen number.** A literal where a dial should be, now out of date.

The full list is on [Common mistakes](/docs/common-mistakes).

## Checklist

- [ ] I can say what decision this system forces.
- [ ] Every field has something that raises it and something that lowers it.
- [ ] The fix costs the player something.
- [ ] Tier prose reads like narration, and the calm tier is silent.
- [ ] Every tunable number is a dial.
- [ ] Reads of other plugins' fields are guarded with `$.hasPlugin`.
- [ ] Deleting the plugin leaves a working game.
- [ ] I played ten turns with it on.
