osrlib.crawl.events
The crawl event types, the combined registry, and the any-event parser.
Crawl events subclass the core Event base, inheriting
the emission contract (frozen, extra="ignore", dotted snake_case codes, declared
outcome-bearing code sets, visibility). CRAWL_EVENT_CLASSES joins the kernel tuple
in ALL_EVENT_CLASSES and the
AnyEvent union;
parse_any_event covers both and the session
log uses it.
Visibility follows B/X's hidden-roll doctrine: referee-rolled dice (detection, surprise, reaction, wandering checks) are referee events, and the player-facing events carry behavior and outcomes only — a silent listen is genuinely ambiguous.
ALL_EVENT_CLASSES
module-attribute
ALL_EVENT_CLASSES: tuple[type[Event], ...] = (*KERNEL_EVENT_CLASSES, *CRAWL_EVENT_CLASSES)
Every event class the library emits — kernel then crawl, in declaration order.
AnyEvent
module-attribute
AnyEvent = Annotated[Union[*ALL_EVENT_CLASSES,], Field(discriminator='event_type')]
Any library event, discriminated by event_type.
CRAWL_EVENT_CLASSES
module-attribute
CRAWL_EVENT_CLASSES: tuple[type[Event], ...] = (
PartyMovedEvent,
LocationEnteredEvent,
DoorEvent,
ListenedEvent,
DetectionRolledEvent,
SearchCompletedEvent,
TrapEvent,
ItemAcquiredEvent,
ItemConsumedEvent,
ItemsDroppedEvent,
ItemsLeftBehindEvent,
ItemsGivenEvent,
LightEvent,
RestedEvent,
FatigueEvent,
ProvisionsEvent,
WanderingCheckEvent,
EncounterStartedEvent,
SurpriseRolledEvent,
StanceChangedEvent,
EvasionEvent,
PursuitEvent,
ExhaustionEvent,
EncounterEndedEvent,
BattleStartedEvent,
BattleRoundEvent,
SpellDeclaredEvent,
GroupMovedEvent,
MonsterFledEvent,
MonstersLeftBehindEvent,
MonsterDefeatedEvent,
BattleEndedEvent,
HoardGeneratedEvent,
ItemUsedEvent,
ItemIdentifiedEvent,
CurseRevealedEvent,
NpcPartySpawnedEvent,
AdventureXpAwardEvent,
TreasureSoldEvent,
HealingPurchasedEvent,
FlagSetEvent,
MonstersSpawnedEvent,
XpAwardedEvent,
CharacterLeveledUpEvent,
TimeAdvancedEvent,
GameOverEvent,
DiceRolledEvent,
TriggerFiredEvent,
JournalEntryAddedEvent,
NoteRecordedEvent,
QuestActivatedEvent,
ObjectiveRevealedEvent,
ObjectiveCompletedEvent,
QuestCompletedEvent,
AdventureCompletedEvent,
)
Every crawl event class, in declaration order.
AdventureCompletedEvent
Bases: Event
The adventure is over in triumph: the session is in victory.
Follows the QuestCompletedEvent of
the quest that concludes the adventure, and carries the same completion beat.
name is that quest's authored display name, defaulting empty only because an
event logged before the field existed still parses; the engine always fills it.
The transition happens once and only from a session still in play — a party that
finishes the job after it has already fallen completes the quest and gets no
ending event.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['adventure_completed'] = 'adventure_completed'
AdventureXpAwardEvent
BattleEndedEvent
BattleRoundEvent
BattleStartedEvent
CharacterLeveledUpEvent
Bases: Event
One character gained a level — the award's threshold crossing made visible.
Fires immediately after the member's own
XpAwardedEvent whenever an XP award
crosses a level threshold, whichever surface awarded it (the end-of-adventure
award, the immediate timing, or the referee's
AwardXP). While the Hit Dice count still
grows, hp_roll is the raw die; past name level the gain is the flat-bonus
delta with no die, so hp_roll is None and con_applied is false. title
is the class's level title at level_after, None past the printed title
list (the SRD's lists run only through name level).
CurseRevealedEvent
DetectionRolledEvent
Bases: Event
A referee-rolled detection die: search, listen, and trap-spring checks.
Rolled whether or not anything is there (the no-leak convention); roll is
None when a zero chance consumed no die.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['detection_rolled'] = 'detection_rolled'
DiceRolledEvent
Bases: Event
An authorial dice roll resolved (referee — the referee's hidden adjudication rolls).
Emitted by RollDice when a referee resolves a
freeform chance outcome by rolling through the seeded session. Carries the
expression that was rolled, the total, and each individual die result in
rolls.
allowed_codes
class-attribute
DoorEvent
Bases: Event
A door changed state; the edge is named by its cell and direction.
allowed_codes
class-attribute
allowed_codes: frozenset[str] = frozenset(
{
"exploration.door.opened",
"exploration.door.closed",
"exploration.door.forced",
"exploration.door.stuck",
"exploration.door.wedged",
"exploration.door.swung_shut",
"exploration.door.unlocked",
}
)
narrative
class-attribute
instance-attribute
narrative: str | None = None
The authored success text of the door's gate, when the opening satisfied one. Authored text on an event is content data in a structured field, not engine-baked English: the event still carries its message code and its facts, and the default formatter appends this line verbatim after the templated one.
EncounterEndedEvent
EncounterStartedEvent
EvasionEvent
ExhaustionEvent
FatigueEvent
FlagSetEvent
Bases: Event
A session flag changed (referee — content wiring is the game's secret).
The flag store a FlagEqualsCondition
reads is the same one this event reports being written.
GameOverEvent
Bases: Event
The session ended: the party was wiped out, however it happened.
A lost battle, a save-or-die trap, a fall, starvation, or a poison that
finished the last member under the referee's clock all report the same
ending, and the session is in game_over when it lands.
GroupMovedEvent
HealingPurchasedEvent
HoardGeneratedEvent
Bases: Event
A lair hoard, carried bundle, or area treasure generated (referee).
Referee visibility — contents are itemized here and players learn by finding.
cache_ref is the engine-created cache's state reference (or the group id for
carried bundles); value and counts summarize the generation.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['hoard_generated'] = 'hoard_generated'
ItemAcquiredEvent
ItemConsumedEvent
Bases: Event
One carried item was used up — a gate's toll paid, a spike driven home.
item_id follows the acquisition masking rule: a mundane consumption carries
the catalog id, a magic one the instance's session-scoped instance_id, never
its template_id — an unidentified item's true identity never rides a
player-visible event.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['item_consumed'] = 'item_consumed'
ItemIdentifiedEvent
ItemUsedEvent
Bases: Event
A magic item used: a potion drunk (or mixed), a scroll read, a device activated.
items.device.inert is a rejection code, not an event — activating an
exhausted device costs nothing, the same as a blocked move. Charges
never appear here: they are referee-only forever (RAW, undiscoverable).
ItemsDroppedEvent
ItemsGivenEvent
Bases: Event
Items or coins handed from one party member to another.
character_id is the giver, recipient_id the companion who took the goods.
ItemsLeftBehindEvent
Bases: Event
Treasure the party could not carry, left where it lay.
Emitted by TakeTreasure when a haul
exceeds the carriers' remaining maximum load: the remainder lands in the drop
pile on the party's cell, so nothing is destroyed and a lightened party can come
back for it.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['items_left_behind'] = 'items_left_behind'
JournalEntryAddedEvent
Bases: Event
A beat was appended to the session journal — the whole entry, as written.
Player-visible: the journal is written for the table. The authored text is
content data in a structured field, not engine-baked English — the event still
carries its message code and its facts — and rounds is the clock position the
entry landed at, the same stamp the stored entry carries.
It is not the only event a growing journal emits. A quest beat appends its entry
and reports itself through its own lifecycle event — the whole set is this event
plus QuestActivatedEvent,
ObjectiveRevealedEvent,
ObjectiveCompletedEvent, and
QuestCompletedEvent — because
emitting both for one beat would report the same line to the table twice. A
client that wants the whole journal reads it from the view.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['journal_entry_added'] = 'journal_entry_added'
LightEvent
Bases: Event
A light source changed state.
source is the item or effect kind (torch, lantern, light); .failed
is a failed tinder-box attempt; .expired is the session's player-facing
translation of the ledger's referee-visibility expiry.
ListenedEvent
Bases: Event
What the listener heard — heard-something or silence, genuinely ambiguous.
Undead make no noise, so the referee-side roll (which rides
DetectionRolledEvent) happens
whether or not anything is there; silence never says which.
LocationEnteredEvent
Bases: Event
The party crossed a location boundary.
location_kind is area, level, dungeon, or town; location_id is the
area or dungeon id ("town" for town). level_number rides level and dungeon
entries, and dungeon_id rides area entries — an area id is scoped to its
level, so an area entry needs all three to name where the party is, while level
and dungeon entries carry the dungeon id in location_id and town has neither.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['location_entered'] = 'location_entered'
narrative
class-attribute
instance-attribute
narrative: str | None = None
The authored success text of the gate on the transition that was taken, when the author wrote one. Authored text on an event is content data in a structured field, not engine-baked English: the event still carries its message code and its facts, and the default formatter appends this line verbatim after the templated one.
MonsterDefeatedEvent
Bases: Event
One monster defeated — feeds the adventure's XP award.
Emitted per monster at battle end with outcome slain, routed, or
surrendered; xp is the template's printed award.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['monster_defeated'] = 'monster_defeated'
MonsterFledEvent
MonstersLeftBehindEvent
Bases: Event
A routing group left its helpless members where they lie.
Fleeing is movement, and a member who cannot move (asleep, paralysed, held by a
web) cannot run: the runners split off and keep fleeing under the original
group id while the helpless stay behind as the new group group_id, at the
distance the side broke from.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['monsters_left_behind'] = 'monsters_left_behind'
MonstersSpawnedEvent
NoteRecordedEvent
Bases: Event
A referee annotation was recorded (referee — and it changes no state).
The report of a machine-issued record — a dropped consequence, a cascade cut short — or of a referee's own margin note.
event_type
class-attribute
instance-attribute
event_type: Literal['note_recorded'] = 'note_recorded'
NpcPartySpawnedEvent
Bases: Event
An NPC adventuring party generated and fielded (referee — the full roster).
The player-facing EncounterStartedEvent names "adventurers" and the count;
the roster, classes, and levels are the referee's.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['npc_party_spawned'] = 'npc_party_spawned'
ObjectiveCompletedEvent
Bases: Event
One objective of a quest is done — including one nobody had announced yet.
name is the objective's display label — its authored name, or its id when the
document authors none — and quest_name the owning quest's name, both resolved
at emission so a renderer holds no document to look them up in. Both default
empty only because an event logged before the fields existed still parses; the
engine always fills them. narrative is the objective's authored progress beat,
None when unauthored, and the journal carries the same line.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['objective_completed'] = 'objective_completed'
ObjectiveRevealedEvent
Bases: Event
A hidden objective surfaced: the party can see what it is being asked for.
name is the objective's display label — its authored name, or its id when the
document authors none — and quest_name the owning quest's name, both resolved
at emission so a renderer holds no document to look them up in. Both default
empty only because an event logged before the fields existed still parses; the
engine always fills them. narrative is the objective's authored offer beat,
None when unauthored, and the journal carries the same line.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['objective_revealed'] = 'objective_revealed'
PartyMovedEvent
Bases: Event
The party moved or turned; x/y/facing are the resulting pose.
A blocked move is a rejection (exploration.move.blocked), never an event:
moving into a wall is an in-fiction invalid command, not a game state change.
allowed_codes
class-attribute
ProvisionsEvent
PursuitEvent
QuestActivatedEvent
Bases: Event
An authored quest came into play — the table's news, not the wiring behind it.
Player-visible: a quest the party has taken on is theirs to know, while the
clause that started it stays behind the screen with the trigger and flag events.
narrative is the quest's authored offer beat, None when unauthored — content
data in a structured field, not engine-baked English, appended verbatim by the
default formatter after the templated line. The same beat is appended to the
journal, so this event and its entry are one report of one moment.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['quest_activated'] = 'quest_activated'
QuestCompletedEvent
Bases: Event
A quest is finished, however the ruling was reached.
narrative is the quest's authored completion beat, None when unauthored, and
the journal carries the same line. Rewards, when the quest pays any, land as
their own commands and their own events after this one.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['quest_completed'] = 'quest_completed'
RestedEvent
SearchCompletedEvent
Bases: Event
A search finished: what it revealed, or nothing (which is ambiguous).
SpellDeclaredEvent
StanceChangedEvent
SurpriseRolledEvent
TimeAdvancedEvent
TrapEvent
Bases: Event
A trap outcome the party perceives.
.sprung when a trap goes off, .found when a search or inspection reveals
one, .removed on a successful removal, .safe when a known trap's trigger
resolved without springing — never emitted for unknown traps (the spring die
rides the referee-visibility
DetectionRolledEvent, no-leak).
TreasureSoldEvent
TriggerFiredEvent
Bases: Event
An authored trigger fired (referee — trigger wiring is the game's secret).
Emitted for every MarkTriggerFired,
a mark of an already-fired trigger included: session state records that a
trigger has fired, and these events record each firing.
narrative is the trigger's authored beat for the firing — content data in a
structured field, not engine-baked English: the event still carries its message
code and its facts, and the default formatter appends the line verbatim after
the templated one. It rides a referee-visibility event because trigger wiring is
the game's secret; a beat written for the table is a journal entry.
event_type
class-attribute
instance-attribute
event_type: Literal['trigger_fired'] = 'trigger_fired'
WanderingCheckEvent
XpAwardedEvent
parse_any_event
Parse one serialized event, kernel or crawl, skipping unknown event types.
The session log's parser: an event_type this library doesn't know returns
None instead of raising, so a newer producer's log loads under an older
consumer (the session preserves the raw record).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Mapping[str, object]
|
A mapping previously produced by an event's |
required |
Returns:
| Type | Description |
|---|---|
Event | None
|
The event, or |
Raises:
| Type | Description |
|---|---|
ContentValidationError
|
If the event type is known but the payload is malformed. |