osrlib.core.effects
Named conditions and the effect lifecycle engine.
This module ships in two layers. The condition layer —
Condition and
ActiveCondition — is pure vocabulary:
creatures carry a tuple of active conditions so a serialized creature is honest on its
own. The engine layer — EffectsLedger — owns
durations, periodic ticks, expiry, and stacking, and is the single writer of
creature conditions: combat reads conditions locally, and only the engine's helpers
(plus the kernel's death routine, for dead) mutate them.
At each round boundary, expirations resolve before ticks, and simultaneous effects resolve in attachment order, tie-broken by effect id. While a target is petrified, its other attached effects suspend — no ticks, durations frozen — so a poisoned, petrified adventurer is a problem for after stone to flesh.
Effect-internal randomness (revival delays, onset dice, duration dice) draws from the
EFFECTS_STREAM stream, so battle-resolution
draws never shift effect draws and vice versa.
Part of the core kernel. Start with
EffectsLedger.attach to apply a spell or
ability's effect to a creature, item, or location, and with
grant_condition /
remove_condition for condition changes
outside the ledger's timed lifecycle, as the kernel's death routine does for dead.
The target/registry parameters below are duck-typed per the combatant convention
(see osrlib.core.combat).
EFFECTS_STREAM
module-attribute
Stream key convention for effect-internal draws: durations, onsets, revivals.
MODIFIER_KINDS
module-attribute
MODIFIER_KINDS = frozenset(
{
"attack_bonus",
"damage_bonus",
"morale_bonus",
"save_bonus",
"ac_bonus",
"ac_set",
"ac_set_vs_missile",
"attack_penalty_of_attackers",
"damage_reduction_per_die",
"damage_multiplier",
"melee_damage_multiplier",
"missile_immunity_nonmagical",
"strength_set",
"weapon_damage_dice_bonus",
"counts_as_magical",
"magical_healing_half",
}
)
The closed vocabulary of stat-modifier kinds combat consults.
ac_bonus, strength_set, and the damage multipliers serve the magic items:
ac_bonus improves AC by its value (descending down, ascending up), ac_set
sets it outright, strength_set replaces the STR score combat modifiers derive from
(Gauntlets of Ogre Power's 18, the Ring of Weakness's 3), and the multipliers double
weapon damage (giant strength) or melee damage only (growth) after the roll.
ActiveCondition
Bases: BaseModel
A condition a creature currently has, with the effect that owns it.
effect_id is None only for conditions no ledger effect owns: dead, written by
the kernel's death routine — death is a kernel outcome, not a timed effect.
ActiveEffect
Bases: BaseModel
A live effect on a creature, item, or location.
target_ref is an entity id or a location string (a burning oil pool attaches to
a location, a stationary silence to a cell). expires_round is the absolute round
the effect expires on (None for indefinite and permanent effects); petrification
suspension pushes it forward. state is the effect's own bookkeeping (revival
round, counted rest days). caster_level records the casting caster's level on
spell-attached effects — dispel magic's survival roll compares against it.
ActiveModifier
Bases: ModifierSpec
A live stat modifier on a creature, with the effect that owns it.
Creatures carry a stat_modifiers tuple so a serialized creature is honest on
its own, mirroring conditions. Only the effects engine writes it (attach
grants, expiry and release remove) — the single-writer rule extends; combat
reads it locally through the modifier_* helpers below.
Condition
Bases: StrEnum
The named conditions.
The wire values are lowercase — they serialize into creatures and saves; changing
them is a schema_version bump. Combat hooks exist for the subset the kernel
consumes (paralysed, asleep, blind, averted_eyes, petrified, poisoned, diseased,
dead; the silenced/feebleminded/weakened casting gates, the weakened attack
gate, and the entangled movement predicate); the rest are additive-safe
vocabulary — afraid, turned, confused, and invisible are marker states
consumed by the battle machine and by games.
LYCANTHROPY_INCUBATION
class-attribute
instance-attribute
EffectDefinition
Bases: BaseModel
A frozen effect blueprint: duration, ticks, stacking, expiry, and condition.
Durations are duration_amount (fixed) or duration_dice (rolled at attach from
the effects stream) counts of duration_unit; both None means indefinite (until
released) and permanent=True marks effects only magic removes (petrification —
stone is not dead). tick names a periodic behavior the ledger executes every
tick_interval_rounds; expiry names an outcome resolved when the duration runs
out (death for delayed poison, splash_damage for the douse's second
application). condition is granted at attach and removed at expiry or release;
modifiers are granted and removed the same way. dispellable=True marks
spell-attached effects dispel magic can end: every effect
cast_spell attaches is dispellable, including
permanent ones (permanent=True means "no duration expiry", not
"undispellable"), while monster-inflicted effects stay non-dispellable.
tick_interval_rounds
class-attribute
instance-attribute
stacking
class-attribute
instance-attribute
stacking: Literal['stack', 'refresh', 'ignore'] = 'stack'
EffectsLedger
Bases: BaseModel
The serializable effect engine: attach, release, and clock-driven advance.
active_on
active_on(target_ref: str, kind: str | None = None) -> list[ActiveEffect]
Return the live effects on a target, optionally filtered by kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target_ref
|
str
|
The entity id or location string. |
required |
kind
|
str | None
|
An effect kind to filter by. |
None
|
Returns:
| Type | Description |
|---|---|
list[ActiveEffect]
|
The matching effects, in attachment order. |
attach
attach(
definition: EffectDefinition,
target_ref: str,
*,
clock: GameClock,
allocator: Any,
registry: Mapping[str, Any] | None = None,
stream: RngStream | None = None,
caster_level: int | None = None
) -> tuple[ActiveEffect | None, list[Event]]
Attach an effect, resolving stacking, duration dice, conditions, and modifiers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
definition
|
EffectDefinition
|
The effect blueprint. |
required |
target_ref
|
str
|
The entity id or location string to attach to. |
required |
clock
|
GameClock
|
The game clock (the attach round anchors the duration). |
required |
allocator
|
Any
|
The |
required |
registry
|
Mapping[str, Any] | None
|
Live combatants by entity id — a
|
None
|
stream
|
RngStream | None
|
The effects stream; required when the definition rolls duration dice. |
None
|
caster_level
|
int | None
|
The casting caster's level, recorded on spell-attached effects for dispel magic's survival roll. |
None
|
Returns:
| Type | Description |
|---|---|
ActiveEffect | None
|
The attached effect and its events — or |
list[Event]
|
|
tuple[ActiveEffect | None, list[Event]]
|
effect's condition. |
release
Release an effect before expiry, removing its condition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
effect_id
|
str
|
The effect to release. |
required |
registry
|
Mapping[str, Any] | None
|
Live combatants by entity id — a
|
None
|
Returns:
| Type | Description |
|---|---|
list[Event]
|
The released and condition-removed events. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no live effect has that id. |
advance
advance(
clock: GameClock,
n: int,
unit: TimeUnit,
registry: Mapping[str, Any],
*,
stream: RngStream,
allocator: Any | None = None
) -> list[Event]
Advance the clock and resolve every round boundary in the span.
The canonical tick order, locked by test: at each boundary, expirations resolve before ticks; simultaneous effects resolve in attachment order, tie-broken by effect id. Suspended effects (target petrified by another effect) neither tick nor age — their expiry pushes forward one round per suspended round.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
clock
|
GameClock
|
The game clock; advanced in place. |
required |
n
|
int
|
How many units to advance. |
required |
unit
|
TimeUnit
|
The unit to advance in. |
required |
registry
|
Mapping[str, Any]
|
Live combatants by entity id — a
|
required |
stream
|
RngStream
|
The effects stream for effect-internal draws. |
required |
allocator
|
Any | None
|
The |
None
|
Returns:
| Type | Description |
|---|---|
list[Event]
|
Every event the advance produced, in resolution order. |
ModifierSpec
Bases: BaseModel
One stat modifier an effect grants while active.
value is the signed adjustment (bless's +1, protection from evil's −1 to
attackers, shield's AC-set values); dice carries dice-valued bonuses
(striking's +1d6 weapon damage). Scopes: element restricts save bonuses and
per-die reductions to one element (resist fire), versus_other_alignment
restricts save bonuses to attacks from creatures of another alignment
(protection from evil), save_categories restricts save bonuses to named
categories (the Displacer Cloak's petrification/rods/spells/staves/wands list),
and melee_only restricts an attacker penalty to melee attacks (the cloak's −2
leaves missiles unaffected, RAW). from_item marks item-sourced modifiers
(potion effects, ward scrolls): they are exempt from the cumulative
largest-bonus cap — RAW's carve-out covers magic items generally, not just
worn ones.
grant_condition
Grant a condition to a creature — the single-writer mutation point.
A condition the creature is immune to (its defenses' condition_immunities) is
not granted and nothing is emitted; duplicate grants from the same effect are
no-ops.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Any
|
The creature to grant the condition to: a
|
required |
condition
|
Condition
|
The condition to grant. |
required |
effect_id
|
str | None
|
The owning effect, or |
required |
Returns:
| Type | Description |
|---|---|
list[Event]
|
The condition-gained event, or nothing when immune or duplicate. |
has_condition
Return whether a creature currently has condition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Any
|
The creature to check: a |
required |
condition
|
Condition
|
The condition to look for. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True when any active condition matches. |
has_modifier
Return whether a creature carries any modifier of kind (the flag kinds).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Any
|
The creature to read modifiers from: a
|
required |
kind
|
str
|
The modifier kind to look for. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True when any active modifier matches. |
kill
Kill a creature: hit points to 0, the dead condition, and the death event.
"A character or monster reduced to 0 hit points or less is killed." Idempotent — a creature already dead emits nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Any
|
The creature to kill: a |
required |
permanent
|
bool
|
True for a regenerating creature's permanent death (the troll's non-regenerable ledger reaching max HP). |
False
|
Returns:
| Type | Description |
|---|---|
list[Event]
|
The death, condition, and referee hit-point events. |
modifier_dice
Return the dice of the first matching dice-valued modifier (striking's +1d6).
First-only is the cumulative rule for dice bonuses: two strikings don't combine.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Any
|
The creature to read modifiers from: a
|
required |
kind
|
str
|
The modifier kind to look for. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
The dice expression, or |
modifier_total
modifier_total(
target: Any,
kind: str,
*,
element: str | None = None,
versus_differs: bool = False,
save_category: str | None = None,
melee: bool = False
) -> int
Return a creature's cumulative modifier for one statistic.
The cumulative-effects rule, from the OSE SRD ("Multiple spells affecting the
same game statistic do not combine"): only the single largest bonus and the
single largest penalty apply — a bless and a blight offset; two blesses
don't stack. Spell modifiers combine freely with non-spell modifiers (the RAW
carve-out for magic items — item-sourced modifiers ride equipped-item queries
and item-kind effects, both outside this cap; see
osrlib.core.combat).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Any
|
The creature to total the modifier for: a
|
required |
kind
|
str
|
The modifier kind to total. |
required |
element
|
str | None
|
The damage or save element in play, if any. |
None
|
versus_differs
|
bool
|
True when the source creature's alignment differs. |
False
|
save_category
|
str | None
|
The saving throw category in play, if any. |
None
|
melee
|
bool
|
True when the attack in play is melee. |
False
|
Returns:
| Type | Description |
|---|---|
int
|
The signed cumulative modifier. |
modifier_values
modifier_values(
target: Any,
kind: str,
*,
element: str | None = None,
versus_differs: bool = False,
save_category: str | None = None,
melee: bool = False
) -> list[int]
Return the matching modifier values on a creature, scope-filtered.
Element-scoped modifiers match only their element; alignment-scoped modifiers
match only when the caller attests the source's alignment differs
(versus_differs); category-scoped save bonuses match only their categories;
melee-only modifiers match only when the caller attests a melee attack.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Any
|
The creature to read modifiers from: a
|
required |
kind
|
str
|
The modifier kind to look for. |
required |
element
|
str | None
|
The damage or save element in play, if any. |
None
|
versus_differs
|
bool
|
True when the source creature's alignment differs from the target's. |
False
|
save_category
|
str | None
|
The saving throw category in play, if any. |
None
|
melee
|
bool
|
True when the attack in play is melee. |
False
|
Returns:
| Type | Description |
|---|---|
list[int]
|
The matching values, in attachment order. |
regeneration_definition
regeneration_definition(params: Mapping[str, Any]) -> EffectDefinition
Build a regeneration effect from a monster's regeneration ability params.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
Mapping[str, Any]
|
The compiled tag params — |
required |
Returns:
| Type | Description |
|---|---|
EffectDefinition
|
An indefinite per-round regeneration effect definition. |
remove_condition
Remove the condition owned by effect_id from a creature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Any
|
The creature to remove the condition from: a
|
required |
condition
|
Condition
|
The condition to remove. |
required |
effect_id
|
str | None
|
The owning effect ( |
required |
Returns:
| Type | Description |
|---|---|
list[Event]
|
The condition-removed event, or nothing when the creature didn't have it. |