miaoda-game-status-core
v0.3.0
Published
Engine-agnostic status-effect engine — the layer that sits ABOVE a stat sheet: periodic damage/heal-over-time ticks, stacking policies (refresh / stack / extend / independent, with a max-stack cap), control flags (stun / silence / root / disarm), and on-a
Downloads
525
Maintainers
Readme
miaoda-game-status-core
Use this package for behavior-bearing effects such as poison, regeneration, stun, silence, root, or disarm. It owns effect timers, periodic ticks, stacking policy, control flags, and lifecycle hooks. It does not calculate stat values or render icons.
Use miaoda-game-stats-core for a value modifier such as “attack -5 for 3 seconds”. Use this package when the effect must tick, stack, gate actions, or run onApply/onEnd behavior.
Install and apply an effect
pnpm add miaoda-game-status-coreimport { StatusSet } from 'miaoda-game-status-core';
const mob = { hp: 100 };
const statuses = new StatusSet(mob);
statuses.apply({
id: 'poison',
duration: 6,
tickInterval: 1,
stackPolicy: 'stack',
maxStacks: 5,
onTick: ({ target, stacks }) => { target.hp -= 3 * stacks; },
});
statuses.tick(1); // duration and tick units are your chosen units
statuses.hasFlag('stun');tick(dt) uses the same unit as duration and tickInterval: seconds for real-time games, one unit per turn for turn-based games. The core never assumes a clock.
Stacking and flags
| Policy | Re-applying an active effect |
| --- | --- |
| refresh | Reset duration, preserve stacks |
| stack | Add one stack and refresh, capped by maxStacks |
| extend | Add duration to remaining time |
| independent | Create a parallel instance with its own timer |
| ignore | Keep the current instance unchanged |
Flags remain active while any effect declares them, so overlapping stuns do not end early when one instance expires. Hooks receive the target and effect context; use them to apply damage, trigger animation events, or bracket a stats buff.
Pair with stats
const sheet = new StatSet({ attack: 20 });
const statuses = new StatusSet(sheet);
statuses.apply({
id: 'weaken', duration: 3,
onApply: ({ target }) => target.applyBuff({
id: 'weaken', modifiers: [{ stat: 'attack', op: 'flat', value: -5 }],
}),
onEnd: ({ target }) => target.removeBuff('weaken'),
});Stats owns the number; status owns the lifecycle. A status snapshot is JSON-safe and contains effect IDs, stacks, flags, remaining time, tick count, and next tick. Targets and hooks are omitted.
Save and restore
Persist snapshot with a stable catalog of status definitions. Restore by resolving IDs against the current catalog; onApply is not replayed, so use onRestore for derived state that must be rebuilt without repeating one-shot damage. Invalid definitions, IDs, stacks, or timing reject the load without partially replacing the live set.
