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
Every event class the library emits — kernel then crawl, in declaration order.
AnyEvent
module-attribute
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,
ItemsDroppedEvent,
LightEvent,
RestedEvent,
FatigueEvent,
ProvisionsEvent,
WanderingCheckEvent,
EncounterStartedEvent,
SurpriseRolledEvent,
StanceChangedEvent,
EvasionEvent,
PursuitEvent,
ExhaustionEvent,
EncounterEndedEvent,
BattleStartedEvent,
BattleRoundEvent,
SpellDeclaredEvent,
GroupMovedEvent,
MonsterFledEvent,
MonsterDefeatedEvent,
BattleEndedEvent,
HoardGeneratedEvent,
ItemUsedEvent,
ItemIdentifiedEvent,
CurseRevealedEvent,
NpcPartySpawnedEvent,
AdventureXpAwardEvent,
TreasureSoldEvent,
HealingPurchasedEvent,
FlagSetEvent,
MonstersSpawnedEvent,
XpAwardedEvent,
TimeAdvancedEvent,
GameOverEvent,
DiceRolledEvent,
)
Every crawl event class, in declaration order.
AdventureXpAwardEvent
Bases: Event
The end-of-adventure XP award: the totals and the per-head share.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['adventure_xp_award'] = 'adventure_xp_award'
code
class-attribute
instance-attribute
code: str = 'session.xp.adventure_award'
visibility
class-attribute
instance-attribute
monster_xp
instance-attribute
treasure_xp
instance-attribute
survivors
instance-attribute
BattleEndedEvent
Bases: Event
The battle ended: victory, the party fled, or defeat.
allowed_codes
class-attribute
allowed_codes: frozenset[str] = frozenset({'battle.ended.victory', 'battle.ended.fled', 'battle.ended.defeat'})
event_type
class-attribute
instance-attribute
event_type: Literal['battle_ended'] = 'battle_ended'
visibility
class-attribute
instance-attribute
BattleRoundEvent
Bases: Event
A battle round began.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['battle_round'] = 'battle_round'
code
class-attribute
instance-attribute
code: str = 'battle.round.started'
visibility
class-attribute
instance-attribute
BattleStartedEvent
Bases: Event
Battle began: the range-track machine takes over.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['battle_started'] = 'battle_started'
code
class-attribute
instance-attribute
code: str = 'battle.started'
visibility
class-attribute
instance-attribute
CurseRevealedEvent
Bases: Event
A cursed item revealed its true nature — and pins itself to its bearer.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['curse_revealed'] = 'curse_revealed'
code
class-attribute
instance-attribute
code: str = 'items.curse.revealed'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
instance_id
instance-attribute
template_id
instance-attribute
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'
code
class-attribute
instance-attribute
code: str = 'exploration.detection.rolled'
visibility
class-attribute
instance-attribute
character_id
class-attribute
instance-attribute
character_id: str | None = None
chance
instance-attribute
roll
class-attribute
instance-attribute
passed
instance-attribute
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
event_type
class-attribute
instance-attribute
event_type: Literal['dice_rolled'] = 'dice_rolled'
code
class-attribute
instance-attribute
code: str = 'adjudication.dice_rolled'
visibility
class-attribute
instance-attribute
expression
instance-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",
}
)
event_type
class-attribute
instance-attribute
event_type: Literal['door'] = 'door'
visibility
class-attribute
instance-attribute
direction
instance-attribute
character_id
class-attribute
instance-attribute
character_id: str | None = None
EncounterEndedEvent
Bases: Event
The encounter concluded; the clock owes at least one full turn.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['encounter_ended'] = 'encounter_ended'
code
class-attribute
instance-attribute
code: str = 'encounter.ended'
visibility
class-attribute
instance-attribute
outcome
instance-attribute
EncounterStartedEvent
Bases: Event
An encounter opened: visible monster names and counts only.
The surprise rolls are referee events; the outcomes ride here — being
surprised is felt in the fiction.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['encounter_started'] = 'encounter_started'
code
class-attribute
instance-attribute
code: str = 'encounter.started'
visibility
class-attribute
instance-attribute
monster_name
instance-attribute
distance_feet
instance-attribute
party_surprised
class-attribute
instance-attribute
party_surprised: bool = False
monsters_surprised
class-attribute
instance-attribute
monsters_surprised: bool = False
EvasionEvent
Bases: Event
An evasion attempt resolved: immediate success, or a pursuit begins.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['evasion'] = 'evasion'
visibility
class-attribute
instance-attribute
ExhaustionEvent
Bases: Event
The party gained or recovered from running exhaustion (30 rounds, −2s).
allowed_codes
class-attribute
allowed_codes: frozenset[str] = frozenset({'encounter.exhaustion.gained', 'encounter.exhaustion.recovered'})
event_type
class-attribute
instance-attribute
event_type: Literal['exhaustion'] = 'exhaustion'
visibility
class-attribute
instance-attribute
FatigueEvent
Bases: Event
The party gained or recovered from the unrested-fatigue penalty.
allowed_codes
class-attribute
allowed_codes: frozenset[str] = frozenset({'exploration.fatigue.gained', 'exploration.fatigue.recovered'})
event_type
class-attribute
instance-attribute
event_type: Literal['fatigue'] = 'fatigue'
visibility
class-attribute
instance-attribute
FlagSetEvent
Bases: Event
A session flag changed (referee — content wiring is the game's secret).
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['flag_set'] = 'flag_set'
code
class-attribute
instance-attribute
code: str = 'session.flag.set'
visibility
class-attribute
instance-attribute
GameOverEvent
Bases: Event
The session reached its terminal state (TPK).
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['game_over'] = 'game_over'
code
class-attribute
instance-attribute
code: str = 'session.game_over'
visibility
class-attribute
instance-attribute
reason
instance-attribute
GroupMovedEvent
Bases: Event
A group's range-track distance changed.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['group_moved'] = 'group_moved'
code
class-attribute
instance-attribute
code: str = 'battle.group.moved'
visibility
class-attribute
instance-attribute
group_id
instance-attribute
distance_feet
instance-attribute
HealingPurchasedEvent
Bases: Event
A temple healing service purchased and cast.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['healing_purchased'] = 'healing_purchased'
code
class-attribute
instance-attribute
code: str = 'town.healing.purchased'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
service
instance-attribute
cost_gp
instance-attribute
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'
code
class-attribute
instance-attribute
code: str = 'treasure.hoard.generated'
visibility
class-attribute
instance-attribute
cache_ref
instance-attribute
treasure_types
class-attribute
instance-attribute
coins_gp_value
class-attribute
instance-attribute
valuable_ids
class-attribute
instance-attribute
magic_item_ids
class-attribute
instance-attribute
ItemAcquiredEvent
Bases: Event
Items or coins entered a character's inventory.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['item_acquired'] = 'item_acquired'
code
class-attribute
instance-attribute
code: str = 'exploration.item.acquired'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
item_ids
class-attribute
instance-attribute
coins_gp_value
class-attribute
instance-attribute
ItemIdentifiedEvent
Bases: Event
A magic item identified — a first meaningful use of it is the trigger.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['item_identified'] = 'item_identified'
code
class-attribute
instance-attribute
code: str = 'items.item.identified'
visibility
class-attribute
instance-attribute
instance_id
instance-attribute
template_id
instance-attribute
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).
allowed_codes
class-attribute
allowed_codes: frozenset[str] = frozenset(
{"items.potion.drunk", "items.potion.mixed", "items.scroll.read", "items.scroll.cursed", "items.device.activated"}
)
event_type
class-attribute
instance-attribute
event_type: Literal['item_used'] = 'item_used'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
instance_id
instance-attribute
manual
class-attribute
instance-attribute
ItemsDroppedEvent
Bases: Event
Items or coins dropped onto the party's cell (or the pursuit trail).
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['items_dropped'] = 'items_dropped'
code
class-attribute
instance-attribute
code: str = 'exploration.item.dropped'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
item_ids
class-attribute
instance-attribute
coins_gp_value
class-attribute
instance-attribute
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.
allowed_codes
class-attribute
allowed_codes: frozenset[str] = frozenset(
{"exploration.light.lit", "exploration.light.extinguished", "exploration.light.failed", "exploration.light.expired"}
)
event_type
class-attribute
instance-attribute
event_type: Literal['light'] = 'light'
visibility
class-attribute
instance-attribute
character_id
class-attribute
instance-attribute
character_id: str | None = None
source
instance-attribute
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.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['listened'] = 'listened'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
direction
instance-attribute
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.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['location_entered'] = 'location_entered'
code
class-attribute
instance-attribute
code: str = 'exploration.location.entered'
visibility
class-attribute
instance-attribute
location_kind
instance-attribute
location_id
instance-attribute
level_number
class-attribute
instance-attribute
level_number: int | None = None
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'
code
class-attribute
instance-attribute
code: str = 'battle.monster.defeated'
visibility
class-attribute
instance-attribute
monster_id
instance-attribute
template_id
instance-attribute
outcome
instance-attribute
MonsterFledEvent
Bases: Event
A monster group broke: fled the battle or surrendered.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['monster_fled'] = 'monster_fled'
visibility
class-attribute
instance-attribute
group_id
instance-attribute
Bases: Event
Monsters spawned into the session registry (referee bookkeeping).
event_type: Literal['monsters_spawned'] = 'monsters_spawned'
code: str = 'session.monsters.spawned'
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'
code
class-attribute
instance-attribute
code: str = 'encounter.npc_party.spawned'
visibility
class-attribute
instance-attribute
party_kind
instance-attribute
npc_ids
instance-attribute
class_ids
instance-attribute
levels
instance-attribute
alignment
instance-attribute
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
event_type
class-attribute
instance-attribute
event_type: Literal['party_moved'] = 'party_moved'
visibility
class-attribute
instance-attribute
facing
instance-attribute
ProvisionsEvent
Bases: Event
A day-boundary provision outcome: consumed, or short (food or water).
allowed_codes
class-attribute
allowed_codes: frozenset[str] = frozenset({'exploration.provisions.consumed', 'exploration.provisions.short'})
event_type
class-attribute
instance-attribute
event_type: Literal['provisions'] = 'provisions'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
PursuitEvent
Bases: Event
One pursuit beat: the round's gap, a distraction, escape, or capture.
allowed_codes
class-attribute
allowed_codes: frozenset[str] = frozenset(
{"encounter.pursuit.round", "encounter.pursuit.distracted", "encounter.pursuit.escaped", "encounter.pursuit.caught"}
)
event_type
class-attribute
instance-attribute
event_type: Literal['pursuit'] = 'pursuit'
visibility
class-attribute
instance-attribute
gap_feet
instance-attribute
RestedEvent
Bases: Event
A rest completed or was interrupted; kind is turn, night, or day.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['rested'] = 'rested'
visibility
class-attribute
instance-attribute
SearchCompletedEvent
Bases: Event
A search finished: what it revealed, or nothing (which is ambiguous).
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['search_completed'] = 'search_completed'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
found
class-attribute
instance-attribute
SpellDeclaredEvent
Bases: Event
A spell declaration posted — table-visible per RAW.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['spell_declared'] = 'spell_declared'
code
class-attribute
instance-attribute
code: str = 'battle.spell.declared'
visibility
class-attribute
instance-attribute
caster_id
instance-attribute
spell_id
instance-attribute
reversed
class-attribute
instance-attribute
StanceChangedEvent
Bases: Event
The monsters' stance, as behavior — the reaction roll itself is referee.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['stance_changed'] = 'stance_changed'
code
class-attribute
instance-attribute
code: str = 'encounter.stance.changed'
visibility
class-attribute
instance-attribute
stance
instance-attribute
SurpriseRolledEvent
Bases: Event
One side's surprise die (referee); roll is None when the side never rolls.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['surprise_rolled'] = 'surprise_rolled'
code
class-attribute
instance-attribute
code: str = 'encounter.surprise.rolled'
visibility
class-attribute
instance-attribute
threshold
instance-attribute
roll
class-attribute
instance-attribute
surprised
instance-attribute
TimeAdvancedEvent
Bases: Event
The clock advanced (referee bookkeeping); rounds_total is the new position.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['time_advanced'] = 'time_advanced'
code
class-attribute
instance-attribute
code: str = 'session.time.advanced'
visibility
class-attribute
instance-attribute
rounds_total
instance-attribute
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).
allowed_codes
class-attribute
allowed_codes: frozenset[str] = frozenset(
{"exploration.trap.sprung", "exploration.trap.safe", "exploration.trap.found", "exploration.trap.removed"}
)
event_type
class-attribute
instance-attribute
event_type: Literal['trap'] = 'trap'
visibility
class-attribute
instance-attribute
trap_ref
instance-attribute
character_id
class-attribute
instance-attribute
character_id: str | None = None
TreasureSoldEvent
Bases: Event
Valuables sold in town at full value (the 1-gp-1-XP identity kept clean).
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['treasure_sold'] = 'treasure_sold'
code
class-attribute
instance-attribute
code: str = 'town.treasure.sold'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
instance_ids
instance-attribute
gp_value
instance-attribute
WanderingCheckEvent
Bases: Event
A wandering-monster check fired (referee bookkeeping).
roll is None when the clamped chance was 0 and the roll was skipped.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['wandering_check'] = 'wandering_check'
code
class-attribute
instance-attribute
code: str = 'exploration.wandering.checked'
visibility
class-attribute
instance-attribute
chance
instance-attribute
roll
class-attribute
instance-attribute
encounter
instance-attribute
XpAwardedEvent
Bases: Event
An XP award applied to one character.
allowed_codes
class-attribute
event_type
class-attribute
instance-attribute
event_type: Literal['xp_awarded'] = 'xp_awarded'
code
class-attribute
instance-attribute
code: str = 'session.xp.awarded'
visibility
class-attribute
instance-attribute
character_id
instance-attribute
modified_award
instance-attribute
level_after
instance-attribute
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 model_dump.
|
required
|
Returns:
| Type |
Description |
Event | None
|
The event, or None when its event_type is unknown.
|
Raises:
| Type |
Description |
ContentValidationError
|
If the event type is known but the payload is
malformed.
|