Skip to content

osrlib.crawl.exploration

The exploration turn: movement, doors, searching, traps, light, rest, wandering checks.

Each handler here is one function (session, command) -> (rejections, events). Callers never call a handler directly: they build one of the command classes in osrlib.crawl.commands (MoveParty, Search, Rest, and so on) and hand it to GameSession.execute, which dispatches to the matching handler here. Every handler validates before it draws, mutates, or advances the clock, so a rejected command costs nothing.

Movement accrues in thirds-of-feet: an unexplored cell costs 30 units, a previously explored cell 10 — the SRD's rule that familiar ground moves three times as fast. Once the accrued total reaches 3 × the party's exploration rate, the clock advances one full turn and the odometer resets; turn-costing actions advance a whole turn outright, absorbing whatever partial move was pending.

Trap resolution (the 2-in-6 spring check, saves, damage, volley counts) draws on the exploration stream, since the procedure owns its own dice; attach-time condition durations draw on the effects stream instead, matching every other effect attachment in the engine.

DEPRIVATION_KIND module-attribute

DEPRIVATION_KIND = 'deprivation'

EXHAUSTED_DEFINITION module-attribute

EXHAUSTED_DEFINITION = EffectDefinition(
    kind=EXHAUSTED_KIND,
    condition=Condition.EXHAUSTED,
    stacking="ignore",
    modifiers=(
        ModifierSpec(kind="attack_bonus", value=-2),
        ModifierSpec(kind="damage_bonus", value=-2),
        ModifierSpec(kind="attack_penalty_of_attackers", value=2),
    ),
)

EXHAUSTED_KIND module-attribute

EXHAUSTED_KIND = 'exhausted'

FATIGUE_KIND module-attribute

FATIGUE_KIND = 'fatigue'

HANDLERS module-attribute

HANDLERS = {
    MoveParty: _handle_move_party,
    TurnParty: _handle_turn_party,
    ReorderParty: _handle_reorder_party,
    OpenDoor: _handle_open_door,
    CloseDoor: _handle_close_door,
    ForceDoor: _handle_force_door,
    WedgeDoor: _handle_wedge_door,
    ListenAtDoor: _handle_listen_at_door,
    PickLock: _handle_pick_lock,
    Search: _handle_search,
    InspectTreasure: _handle_inspect_treasure,
    RemoveTreasureTrap: _handle_remove_treasure_trap,
    TakeTreasure: _handle_take_treasure,
    DropItems: _handle_drop_items,
    LightSource: _handle_light_source,
    ExtinguishSource: _handle_extinguish_source,
    EquipItem: _handle_equip_item,
    UnequipItem: _handle_unequip_item,
    Rest: _handle_rest,
    PrepareSpells: _handle_prepare_spells,
    CastSpell: _handle_cast_spell,
    UseItem: _handle_use_item,
    UseStairs: _handle_use_stairs,
    EnterDungeon: _handle_enter_dungeon,
    TravelToTown: _handle_travel_to_town,
    PurchaseEquipment: _handle_purchase_equipment,
    SellTreasure: _handle_sell_treasure,
    PurchaseHealing: _handle_purchase_healing,
}

HEALING_SERVICES module-attribute

HEALING_SERVICES: dict[str, tuple[str, int]] = {
    "cure_light_wounds": ("cure_light_wounds", 25),
    "cure_serious_wounds": ("cure_serious_wounds", 100),
    "cure_disease": ("cure_disease", 150),
    "neutralize_poison": ("neutralize_poison", 150),
    "remove_curse": ("remove_curse_c", 200),
    "raise_dead": ("raise_dead", 1500),
}

The temple's six services: spell id and price in gp, invented over the SRD's open list (see the adaptations register).

All services are always available — town size and cleric availability are game territory left to your front end.

check_fatigue

check_fatigue(session) -> list[Event]

Attach the unrested-fatigue penalty once the cadence threshold passes.

Parameters:

Name Type Description Default
session GameSession

The running session.

required

Returns:

Type Description
list[Event]

The events from attaching the fatigue effect, or an empty list before the

list[Event]

threshold or once fatigue is already active on every living member.

consume_provisions

consume_provisions(session) -> list[Event]

One day-boundary crossing: rations and water per living member.

Standard rations consume before iron, since fresh food spoils first; a carried waterskin satisfies the day without per-pint bookkeeping. In town, provisions consume but never run short. A successful day resets that member's deprivation track; under the deprivation_penalties flag, the schedule's effects sync afterwards (see the adaptations register).

Parameters:

Name Type Description Default
session GameSession

The running session.

required

Returns:

Type Description
list[Event]

One ProvisionsEvent per living

list[Event]

member per resource (food and water).

exploration_rate

exploration_rate(session) -> int

The party's exploration rate: slowest living member, deprivation-halved.

Under the deprivation_penalties flag, a member two or more days into the worse deprivation track moves at half rate.

Parameters:

Name Type Description Default
session GameSession

The running session.

required

Returns:

Type Description
int

The slowest living member's movement rate, in feet per turn.

wandering_check

wandering_check(session, *, resting: bool = False) -> tuple[list[Event], bool]

Fire one wandering-monster check; a hit spawns and opens an encounter.

The chance takes +1 for noise since the last check, +1 for daylight-bright light, −1 while resting, clamped to [0, 6]; a clamped 0 skips the roll. The check die draws from the wandering stream; the d20 table roll, count dice, and variant picks follow on the same stream (NPC-party rows spawn a real party, never a re-roll); spawned hit points draw from the monster-spawn stream, NPC composition from the npc-party stream, and the encounter's own dice from the encounter stream.

Parameters:

Name Type Description Default
session GameSession

The running session.

required
resting bool

Whether the party is resting: the −1 chance penalty applies.

False

Returns:

Type Description
list[Event]

The check's events and whether an encounter opened. The events always

bool

include one

tuple[list[Event], bool]
tuple[list[Event], bool]

adds the spawn and encounter-opening events too.

wandering_interval

wandering_interval(session) -> int

The current level's wandering-check interval in turns (RAW default 2).

Parameters:

Name Type Description Default
session GameSession

The running session.

required

Returns:

Type Description
int

The interval in turns, or an effectively unreachable value outside a

int

dungeon.