@motioneffector/stats

Documentation

Stat Block API

Functions and methods for creating and managing stat blocks.


createStatBlock()

Create a new stat block with the given definitions.

Signature:

function createStatBlock(
  definitions: StatDefinitions,
  options?: StatBlockOptions & { fromJSON?: SerializedStatBlock }
): StatBlock

Parameters:

Name Type Required Description
definitions StatDefinitions Yes Object mapping stat names to definitions
options StatBlockOptions No Configuration options
options.historyLimit number No Max roll history entries. Default: 100. Set to 0 to disable.
options.modifierFormula (value: number) => number No Custom formula for check modifiers
options.fromJSON SerializedStatBlock No Restore from serialized data

Returns: StatBlock — The created stat block

Example:

import { createStatBlock } from '@motioneffector/stats'

const hero = createStatBlock({
  strength: { base: 16, min: 1, max: 20 },
  health: { base: 100, min: 0 }
})

Throws:

  • ValidationError — When min > max in a stat definition

StatBlock Methods

get()

Get the effective value of a stat (base + modifiers).

Signature:

get(statName: string): number | undefined

Parameters:

Name Type Required Description
statName string Yes Name of the stat

Returns: number | undefined — The effective value, or undefined if stat doesn't exist

Example:

hero.get('strength') // 16
hero.get('unknown')  // undefined

getBase()

Get the base value of a stat (without modifiers).

Signature:

getBase(statName: string): number | undefined

Returns: number | undefined — The base value

Example:

hero.addModifier('strength', { value: 2, source: 'buff' })
hero.get('strength')     // 18
hero.getBase('strength') // 16

set()

Set the base value of a stat.

Signature:

set(statName: string, value: number): number

Parameters:

Name Type Required Description
statName string Yes Name of the stat
value number Yes New base value

Returns: number — The new base value (may be clamped to bounds)

Throws:

  • TypeError — If stat doesn't exist or is derived

Example:

hero.set('strength', 18) // Returns 18
hero.set('strength', 25) // Returns 20 (clamped to max)

modify()

Add to or subtract from the base value.

Signature:

modify(statName: string, delta: number): number

Parameters:

Name Type Required Description
statName string Yes Name of the stat
delta number Yes Amount to add (negative to subtract)

Returns: number — The new base value

Throws:

  • TypeError — If stat doesn't exist or is derived

Example:

hero.modify('health', -10) // Take 10 damage
hero.modify('health', 5)   // Heal 5

has()

Check if a stat exists.

Signature:

has(statName: string): boolean

Example:

hero.has('strength') // true
hero.has('luck')     // false

stats()

Get all stat names.

Signature:

stats(): string[]

Returns: string[] — Array of stat names

Example:

hero.stats() // ['strength', 'health']

addModifier()

Add a modifier to a stat.

Signature:

addModifier(statName: string, modifier: Modifier): Modifier

Parameters:

Name Type Required Description
statName string Yes Name of the stat
modifier Modifier Yes The modifier to add

Returns: Modifier — The added modifier

Throws:

  • TypeError — If stat doesn't exist or is derived

Example:

hero.addModifier('strength', {
  value: 2,
  source: 'belt-of-strength',
  type: 'flat',
  duration: 'permanent'
})

removeModifier()

Remove a modifier by source name.

Signature:

removeModifier(statName: string, source: string): boolean

Returns: booleantrue if removed, false if not found

Example:

hero.removeModifier('strength', 'belt-of-strength')

getModifiers()

Get all modifiers on a stat.

Signature:

getModifiers(statName: string): ModifierInfo[] | undefined

Returns: ModifierInfo[] | undefined — Array of modifiers, or undefined if stat doesn't exist

Example:

const mods = hero.getModifiers('strength')
// [{ value: 2, source: 'belt', type: 'flat', duration: 'permanent' }]

clearModifiers()

Remove all modifiers from a stat or all stats.

Signature:

clearModifiers(statName?: string): number

Parameters:

Name Type Required Description
statName string No Stat to clear. If omitted, clears all stats.

Returns: number — Count of modifiers removed

Example:

hero.clearModifiers('strength') // Clear one stat
hero.clearModifiers()           // Clear all stats

getRemainingDuration()

Get remaining duration of a modifier.

Signature:

getRemainingDuration(statName: string, source: string): number | undefined

Returns: number | undefined — Remaining ticks, Infinity for permanent, or undefined if not found

Example:

hero.getRemainingDuration('strength', 'rage') // 3

tick()

Advance time, decrementing modifier durations.

Signature:

tick(): string[]

Returns: string[] — Sources of expired modifiers

Example:

const expired = hero.tick()
console.log(expired) // ['rage', 'haste']

getRollHistory()

Get roll history entries.

Signature:

getRollHistory(limit?: number): HistoryEntry[]

Returns: HistoryEntry[] — Array of history entries


clearRollHistory()

Clear all roll history.

Signature:

clearRollHistory(): void

onChange()

Subscribe to all stat changes.

Signature:

onChange(callback: (event: StatChangeEvent) => void): () => void

Returns: () => void — Unsubscribe function

Example:

const unsubscribe = hero.onChange((event) => {
  console.log(`${event.stat}: ${event.oldValue} → ${event.newValue}`)
})

// Later...
unsubscribe()

onStat()

Subscribe to changes on a specific stat.

Signature:

onStat(statName: string, callback: (event: StatChangeEvent) => void): () => void

Throws:

  • TypeError — If stat doesn't exist

isDerived()

Check if a stat is derived.

Signature:

isDerived(name: string): boolean

toJSON()

Serialize the stat block.

Signature:

toJSON(): SerializedStatBlock

Returns: SerializedStatBlock — Serializable object


dispose()

Clean up resources and listeners.

Signature:

dispose(): void

Types

StatDefinition

interface StatDefinition {
  base: number
  min?: number
  max?: number
}

StatDefinitions

type StatDefinitions = Record<string, StatDefinition>

Modifier

interface Modifier {
  value: number
  source: string
  type?: 'flat' | 'multiply'
  duration?: 'permanent' | 'temporary' | number
}

ModifierInfo

interface ModifierInfo {
  value: number
  source: string
  type: 'flat' | 'multiply'
  duration: 'permanent' | number
}

StatChangeEvent

interface StatChangeEvent {
  stat: string
  newValue: number
  oldValue: number
  baseChanged: boolean
  modifiersChanged: boolean
}

StatBlockOptions

interface StatBlockOptions {
  historyLimit?: number
  modifierFormula?: (value: number) => number
}

SerializedStatBlock

interface SerializedStatBlock {
  version: 1
  stats: Record<string, number>
  modifiers: Record<string, ModifierInfo[]>
}

Related