Skip to content

osrlib.crawl.adventure

The adventure container: dungeons, the base town, and scenario metadata.

An adventure is frozen game content — the session runs it, never mutates it. The base town anchors the XP rule's "survive and return to safety" and safe day-level rest. It is a marker offering safe rest and equipment purchase through the kernel, not a simulated town. Content prose lives in these models — events carry ids and front ends resolve prose against the adventure.

Beyond the dungeons, the document carries the adventure's own content and behavior: monsters and items bundle templates that resolve beside the shipped catalogs for that session, triggers is the authored wiring (TriggerSpec), and quests the authored errands (QuestSpec) — with gates (GateSpec) riding the dungeon geometry's doors and transitions.

validate_adventure is the fail-fast content gate: dangling references (transition targets, monster template ids, item ids, area cells out of bounds, gate item ids, trigger and quest references — patterns, conditions, consequence targets, selectors) raise ContentValidationError before a session ever runs the content.

Adventure

Bases: BaseModel

An adventure: one or more dungeons plus the base town and metadata.

monsters are the adventure's bundled custom MonsterTemplates: they join the shipped catalog for this adventure's sessions everywhere the engine resolves template ids (keyed encounters, SpawnMonsters, inline wandering tables, listen checks). Bundled ids must not collide with the shipped catalog or each other — a collision is a validation error, never an override. The empty tuple is the universal default: an adventure that bundles nothing plays exactly as before.

items are the adventure's bundled custom ItemTemplates — weapons, armour, gear, and ammunition — under the same contract: they join the shipped equipment catalog for this adventure's sessions everywhere the engine resolves authored item ids (treasure caches, GrantItem, drop-pile recovery), and they ride every carry surface (gives, equips, drops) through the templates their instances embed. Bundled item ids must not collide with the equipment catalog, the magic-item catalog, or each other — one item id names one thing per session. The town shop is the one place they do not reach: it stocks the shipped equipment lists.

triggers are the adventure's authored TriggerSpecs, and the tuple's order is document order: triggers matching one event fire in it. A game plays them by registering an Interpreter on its session; an adventure that authors none plays exactly as one that never could.

quests are the adventure's authored QuestSpecs, in document order too: a session seeds one state block per quest at construction, in this order, and every walk over them follows it. Quest ids and trigger ids are separate namespaces — they live in separate state blocks — so a quest and a trigger may share an id.

name instance-attribute

name: str

description class-attribute instance-attribute

description: str = ''

hooks class-attribute instance-attribute

hooks: tuple[str, ...] = ()

town instance-attribute

town: TownSpec

dungeons class-attribute instance-attribute

dungeons: tuple[DungeonSpec, ...] = Field(min_length=1)

monsters class-attribute instance-attribute

monsters: tuple[MonsterTemplate, ...] = ()

items class-attribute instance-attribute

items: tuple[ItemTemplate, ...] = ()

triggers class-attribute instance-attribute

triggers: tuple[TriggerSpec, ...] = ()

quests class-attribute instance-attribute

quests: tuple[QuestSpec, ...] = ()

dungeon

dungeon(dungeon_id: str) -> DungeonSpec

Return the dungeon with dungeon_id.

Parameters:

Name Type Description Default
dungeon_id str

The dungeon id.

required

Returns:

Type Description
DungeonSpec

The dungeon spec.

Raises:

Type Description
ValueError

If no dungeon has that id.

quest

quest(quest_id: str) -> QuestSpec

Return the quest with quest_id.

The resolution behind the quest lifecycle commands' closed id domain: an id this cannot answer names no quest of this adventure.

Parameters:

Name Type Description Default
quest_id str

The quest id.

required

Returns:

Type Description
QuestSpec

The quest spec.

Raises:

Type Description
ValueError

If no quest has that id.

TownSpec

Bases: BaseModel

The base town: safe rest, equipment purchase, and travel costs.

services is prose for front ends. travel_turns maps dungeon ids to the town-to-entrance travel cost in exploration turns — content-authored, consumed by EnterDungeon and TravelToTown.

name instance-attribute

name: str

description class-attribute instance-attribute

description: str = ''

services class-attribute instance-attribute

services: tuple[str, ...] = ()

travel_turns class-attribute instance-attribute

travel_turns: dict[str, int] = {}

validate_adventure

validate_adventure(adventure: Adventure, monsters: MonsterCatalog, equipment: EquipmentCatalog) -> None

Validate an adventure's cross-references — the fail-fast content gate.

Checks: bundled monster ids colliding with the shipped catalog or each other, and bundled item ids colliding with the equipment catalog, the shipped magic-item catalog, or each other; then, per level: area cells and features in bounds, feature ids unique, cache item ids resolving against the effective equipment catalog, cache magic item ids resolving against the shipped magic-item catalog (load_magic_items — adventures bundle no magic items, so validation loads it itself), keyed-encounter template ids (and any fixed spawn alignment) and inline wandering-table monster ids resolving against the effective catalog, item ids named by has_item gates on doors and transitions resolving against the effective equipment catalog or the magic-item catalog, transition destinations resolving to real cells, town travel entries naming real dungeons, and an entrance existing somewhere in every dungeon.

Then, per trigger: ids unique across the adventure; the pattern's area, level, dungeon, item, and monster references resolving; the same item domain for has_item conditions; and per consequence, granted item ids, spawned template ids, a door edge at the cell a door write names, a placement landing on the grid, and the rule that a consequence addressing a character does so through a party selector — a session allocates character ids, so a document naming one is naming something that cannot exist when it is read.

Then, per quest: ids unique across the adventure (quest ids and trigger ids are separate namespaces, and nothing here cross-checks them); per clause — the activation, each objective's completion, each hidden objective's reveal — the same pattern and condition references a trigger's clause resolves; and per reward, the same references and the same party-selector rule a consequence gets. The two surfaces share one clause check and one consequence check, so neither can grow a reference the other fails to resolve.

Parameters:

Name Type Description Default
adventure Adventure

The adventure to validate.

required
monsters MonsterCatalog

The base monster catalog — validation unions it internally with the adventure's bundled templates, and every monster reference resolves against that union.

required
equipment EquipmentCatalog

The base equipment catalog — validation unions it internally with the adventure's bundled templates, and every cache item reference resolves against that union.

required

Raises:

Type Description
ContentValidationError

Listing every dangling reference found.