Cooperation
How plugins work together without depending on each other.
Plugins never call each other. They meet through state the engine owns. That's what makes them removable: if hunger called into rest, deleting rest would break hunger.
They meet in three places.
1. Shared fields
Any plugin can read any field. So ask before you rely on one:
$.hasPlugin('hunger') && $.field('satiety') < 20
Without the check, a game with no hunger plugin reads null, and your rule behaves as if
everyone is always starving or never hungry. See Missing values.
2. Engine triggers
One plugin's $.damage() fires onDamage, and another plugin's hook catches it. Neither knows
the other exists.
3. Plugin events
A plugin can declare an event: a moment it lets other plugins veto. The rest plugin
declares rest:sleep. Hunger answers it:
// hook on rest:sleep
if ($.party.some(p => p.fields.satiety <= 0)) {
$.veto('they are too hollow with hunger to settle')
}
A hook on an event nobody declares does nothing. So hunger works fine in a game without rest.
Use veto here, not refuse. refuse stops the player's own action, and using it here tells
a player standing still that hunger woke them from a sleep they never started.
The test
Delete either side of any pair, and the other still works.
Hunger without rest still drains and still starves; it just never vetoes a sleep. Rest without hunger still restores; it just never gets vetoed. If deleting one breaks the other, you haven't built two plugins. You've built one in two pieces.