osrlib.crawl.views
The projection API: the player's safe whitelist and the referee's full state.
A view is the snapshot a front end renders: everything on the screen after a command, in one frozen object.
Where the views sit. A command changes the session state that
GameSession keeps, and
build_player_view and
build_referee_view read that state to build
these projections. The player view is built from session state alone and never from the
event log; the referee view has one typed field per group the save keeps, so it includes
the event log along with everything else, each group as the session's own model.
GameSession.view is the entry point most games
call, with a Visibility to pick which one. Events tell
you what just happened, and a view tells you what is true now. The ids a view includes,
MemberView.id and
EncounterGroupView.id, are the ids the
commands in osrlib.crawl.commands name.
The player view is an enumerated whitelist: party public sheets, location and facing, the mapped cells with their edges (walked cells, the remembered cells the party's light has shown it, and what its light reveals right now, with secret doors rendered as wall until discovered), known piles and emptied caches in explored space, active effects on party members with their remaining durations, the elapsed clock, the mode, the journal, the active quests with their revealed objectives, the current encounter or battle's public state, fatigue, exhaustion, and deprivation status, and the adventure's public prose.
It never includes unexplored geometry, undiscovered traps or secret doors, monster hit points or stat internals, referee-visibility roll outcomes, session flags, trigger fired-marks, referee notes, quest wiring such as activation clauses, patterns, conditions, rewards, and hidden objectives, the quests that are not active, meaning both the ones nobody has taken on yet and the ones already finished, RNG state, or the master seed, which lives only in the save and reaches neither view.
The referee view includes everything else the save does, minus RNG internals and the seed,
for LLM referees and tests. Its fields are the groups
session_state writes, so view.monsters[0].current_hp
and view.flags["key"] read with the types this reference documents, and
view.model_dump(mode="json") is that save payload without the two withheld keys. Never
trust the client with it: a networked game keeps the session and the referee view on the
server and sends only the player view, or player-visibility events, over the wire. The guide
Views and visibility
walks the whole projection in a running front end.
EdgeView
Bases: BaseModel
One visible edge: what occupies it, and a door's state.
You get these from the edges of an
ExploredLevelView, keyed by canonical edge
key. An undiscovered secret door renders as wall, so a front end that draws what it
is given never reveals one.
kind
instance-attribute
kind: str
What occupies the edge: "open", "wall", or "door", the wire values of
EdgeKind. An undiscovered secret door reports
"wall".
door_open
class-attribute
instance-attribute
door_open: bool | None = None
Whether the door stands open. None on an edge that is not a door.
door_wedged
class-attribute
instance-attribute
door_wedged: bool | None = None
Whether the door has been wedged with an iron spike. None on an edge that is not
a door.
EncounterGroupView
Bases: BaseModel
A monster group as the players see it: what it is, how many, how far, how it looks.
You get these from EncounterView.groups. Hit
points and stat internals never appear, because the players work from what they can
see across the room.
id
instance-attribute
id: str
The group's id, which is the command vocabulary: a battle declaration names its
target_group_id with it, so a wire client needs it to fight at all. It is an
allocator ordinal rather than a secret, the same way a
MemberView.id is.
label
instance-attribute
label: str
What the group is called, such as "goblins", for the line a front end prints.
count
instance-attribute
count: int
How many of the group are still standing. The dead are not counted.
distance_feet
instance-attribute
distance_feet: int
How far away the group is on the range track, in feet.
EncounterView
Bases: BaseModel
The current encounter or battle's public state.
You get one from PlayerView.encounter, and None
there means nothing is happening.
Four id tuples, declarers, front_rank, immobile, and reloading, describe the
round's shape as the players know it at the table: who is able to act, who stands
close enough to swing, who is held fast, and who is still cranking a windlass. Each
one corresponds to a rejection the engine would otherwise raise against the whole
round, so a front end that reads all four offers only the declarations the engine will
accept. Without them a front end has to assume a rank width, and a wrong assumption
costs the party its turn.
groups
instance-attribute
groups: tuple[EncounterGroupView, ...]
The monster groups in the encounter, in the order the encounter holds them.
stance
instance-attribute
stance: str | None
How the monsters are behaving, as a ReactionResult
wire value: "attacks", "hostile", "uncertain", "indifferent", or "friendly".
None before the reaction roll has settled it.
in_battle
instance-attribute
in_battle: bool
Whether the encounter has become a battle with rounds and declarations.
battle_round
class-attribute
instance-attribute
battle_round: int | None = None
The current battle round, counting from the first. None outside a battle.
pursuit_gap_feet
class-attribute
instance-attribute
pursuit_gap_feet: int | None = None
How far ahead of its pursuers the fleeing party is, in feet. None when nobody is
pursuing.
declarers
class-attribute
instance-attribute
Every member who has to declare this round, in marching order: the ones living and
able to act. A ResolveBattleRound
naming any other roster, a slept or paralysed member included, is rejected whole with
battle.declaration.roster_mismatch.
front_rank
class-attribute
instance-attribute
The living members close enough to attack in melee, in marching order. That is the
party's first rank at the current formation width, or every living member when the
ruleset's formation_width_limit flag is off. A melee attack declared for anyone
else is rejected with battle.declaration.not_in_front_rank, and inside melee reach a
weapon that is both melee and missile counts as a melee weapon.
immobile
class-attribute
instance-attribute
The declarers who cannot move this round, which in practice means the entangled,
since the states that stop a move otherwise stop a declaration as well. A move
declaration of any kind from one of them is rejected with
battle.declaration.cannot_move.
reloading
class-attribute
instance-attribute
The members who may not fire a reload weapon this round, because they fired one
last round (combat.attack.reload). Empty when the ruleset's weapon_reload flag is
off, so a front end can combine this list with the weapon's own qualities and never
read the flag itself.
ExplorationCounters
Bases: BaseModel
The crawl bookkeeping a session keeps between commands: distance, rest, wandering, noise, sleep, supplies.
You get one from RefereeView.exploration. These are the counters
GameSession keeps as attributes of its own and a save writes
under its exploration key, gathered here under the names the session gives them. They are the
referee's bookkeeping and none of them reaches PlayerView, which
reports the party's fatigue, exhaustion, and deprivation as status rather than as the counts behind
it.
odometer_thirds
instance-attribute
odometer_thirds: int
How much of the current turn the party's steps have used up, in thirds of its movement rate. A full turn's worth advances the clock and resets this to zero.
turns_since_rest
instance-attribute
turns_since_rest: int
Turns since the party last rested, which is what the fatigue cadence counts. A
Rest resets it.
wandering_counter
instance-attribute
wandering_counter: int
Turns since the last wandering-monster check. Reaching the level's interval fires the check and resets this to zero.
noise_since_check
instance-attribute
noise_since_check: bool
Whether the party has made noise since the last wandering check, which any attempt to force a door does, whether or not the door opens. Noise raises the next check's chance by one and then clears.
sleep_count
instance-attribute
sleep_count: int
How many nights or days the party has slept through. Preparing spells needs a sleep the caster has not already prepared from.
last_prepared_sleep
instance-attribute
The sleep_count at which each caster last prepared spells, keyed by character id. It is what
enforces one preparation per sleep.
alerted_areas
instance-attribute
The keyed areas whose occupants have been alerted, as area references. Monsters that heard the party coming are not surprised when it walks in.
heard_areas
instance-attribute
The keyed areas the party has heard something in, as area references. A party that knows what stands behind the door is not surprised by it.
provisions_day
instance-attribute
provisions_day: int
The last whole game day whose food and water upkeep has been settled, counting from the start of the session. Each day boundary charges the party once and then raises this.
ExploredLevelView
Bases: BaseModel
One level's explored map: the cells the party knows, and the edges around them.
You get these from PlayerView.explored, one per
level the party has any knowledge of. This is the map to draw: nothing outside it is
knowledge the party has.
cells
instance-attribute
The known cells as (x, y) pairs: the cells the party has walked, then the cells
it remembers having seen, then the cells its light shows from where it stands right
now. Lighting a torch redraws the room in the next view, with no footstep in
between.
MemberEffectView
Bases: BaseModel
An active effect on a party member: the players track their own torches and spells.
You get these from PlayerView.effects. Only
effects attached to a party member appear. An effect anchored to a dungeon cell is
the referee's business and stays out.
character_id
instance-attribute
character_id: str
The id of the member the effect is attached to, matching a
MemberView.id.
kind
instance-attribute
kind: str
The effect kind, such as "light" or "fatigue", which is the same string an
EffectActiveCondition names.
remaining_rounds
instance-attribute
remaining_rounds: int | None
Rounds left before the effect expires, never below zero. None means the players
are not told: an effect with no expiry, and any effect a potion granted, because the
referee rolls and tracks a potion's duration and never announces it.
MemberView
Bases: BaseModel
One member's public sheet: the players know their own characters.
You get these from PlayerView.party, in marching
order, and every party member has one, living or dead. A member's own numbers are
not secrets, so the sheet is full, and the one thing play hides from the players is
the identity of an unidentified magic item in the pack.
Examples:
from osrlib.crawl.views import MemberView
sheet = MemberView(
id="pc1",
name="Hild",
class_id="fighter",
level=1,
current_hp=7,
max_hp=7,
conditions=(),
inventory={},
memorized_spells=(),
)
assert sheet.id == "pc1" # the id a command's character_id names
id
instance-attribute
id: str
The member's character id. This is the id you put in the character_id of a
command such as GrantItem or a battle
declaration, so a wire client can act without holding the session.
class_id
instance-attribute
class_id: str
The character class id, such as "fighter", from the class catalog.
current_hp
instance-attribute
current_hp: int
Current hit points. Zero or less means the member is down, and conditions says
what took them out.
conditions
instance-attribute
The conditions on the member right now, as
Condition wire values such as "dead" or
"sleeping", in the order the ledger holds them.
inventory
instance-attribute
inventory: dict
The member's pack, in the shape the inventory serializes, with the keys items,
purse, valuables, worn_armour, shield, wielded, and rings. Magic items
are masked until identified: an unidentified one shows a category display name
instead of its true name. When that display name was built from a base weapon ("a
dagger with a faint aura"), the entry also includes the qualities of that mundane
weapon, exactly as an identified one does, so a front end can classify a declaration
without being told the arm's bonus, curse, or template id. The missile_ranges key
comes with it only for a weapon the rules give ranges to, so read the key as absent
on a sword rather than empty. An item whose display comes from its category instead,
such as a staff, includes neither field even when it resolves to a weapon, because
the display never named that weapon. Charges never appear at any identification
level.
memorized_spells
instance-attribute
The prepared spells, one dumped
MemorizedSpell per copy, in memorization
order. Empty for a class that casts nothing.
ObjectiveView
Bases: BaseModel
One revealed objective as the players know it: what it is called, and whether it is done.
You get these from QuestView.objectives. A hidden
objective has no view at all: one nobody has been told about is absent from the list
rather than listed as unknown, which is why state needs only the two values a
visible objective can be in. The authored source is
ObjectiveSpec and the live state is
ObjectiveState, neither of which a wire
client holds.
name
instance-attribute
name: str
The objective's display label: its authored name, or its id when the
document authors none. It is never empty, because the view's job is saying what the
objective is called.
PileView
Bases: BaseModel
A known dropped pile in explored space.
You get these from PlayerView.piles, keyed by cell
reference. A pile in a cell the party has not walked is left out, so the view never
tells the players about loot they have not found.
items
instance-attribute
One display string per thing in the pile, in the order mundane items, magic items,
then valuables. A mundane entry reads "{item_id}×{quantity}". A magic item shows its
name once identified and its masked display name before that. A valuable shows its
name, or its kind when it has no name.
coins_gp_value
instance-attribute
coins_gp_value: int
The pile's coins, converted to their value in gold pieces.
PlayerView
Bases: BaseModel
The safe projection: an enumerated whitelist of exactly the fields a player may see.
Build one with build_player_view, or with
GameSession.view and
Visibility.PLAYER. This is the object a networked game sends over the wire: every
field on it is safe to show at the table, and nothing the party has not learned is
on it. Rebuild it after every command, because it is a frozen snapshot and nothing
updates it in place.
adventure_description
instance-attribute
adventure_description: str
The adventure's public prose, the blurb a front end shows on the title screen.
town_services
instance-attribute
The services the town offers, as authored prose for a front end to list.
party
instance-attribute
party: tuple[MemberView, ...]
The party's public sheets, in marching order, the dead included.
location
instance-attribute
location: PartyLocation
Where the party is: the town, or a dungeon cell with its facing.
clock_rounds
instance-attribute
clock_rounds: int
The elapsed game clock in rounds, counting from the start of the session.
mode
instance-attribute
mode: str
The session mode as a SessionMode wire
value: "town", "exploring", "encounter", "battle", "game_over", or
"victory". It tells a front end which commands are legal right now.
explored
instance-attribute
explored: tuple[ExploredLevelView, ...]
The party's map, one entry per level it knows anything about.
piles
instance-attribute
The dropped piles the party knows about, keyed by the cell reference
cell_ref returns. A pile in a cell the party has
not walked is left out.
emptied_caches
instance-attribute
The treasure caches the party has already emptied, as "{dungeon}:{level}:{id}"
references, so a front end can draw a looted cache as looted.
effects
instance-attribute
effects: tuple[MemberEffectView, ...]
The active effects on party members, in ledger order.
deprivation
instance-attribute
Food and water deprivation, keyed by character id, each value holding
food_days and water_days. A member with no deprivation on either track is left
out, so an empty dict means the party has been eating and drinking.
journal
instance-attribute
journal: tuple[JournalEntry, ...]
The session journal, shipped as written: the players' own record of the adventure, in order of discovery, each beat with the clock position it landed at. The wiring behind the beats, meaning trigger fired-marks and referee notes, stays out.
quests
instance-attribute
The quests in play, in the order the adventure authored them: active ones only. A quest nobody has taken on yet is not the party's business, and a finished one leaves the list, and its record is the journal, which keeps every beat it wrote.
encounter
class-attribute
instance-attribute
encounter: EncounterView | None = None
The current encounter or battle's public state, or None when the party is not in
one.
QuestView
Bases: BaseModel
One active quest as the players know it: the charge, who gave it, and where it stands.
You get these from PlayerView.quests. The wiring
that starts a quest, checks it off, and pays it, meaning its clauses, patterns,
conditions, and rewards, never appears: that is the game's secret exactly as a
trigger's is. Read the authored quest itself from
QuestSpec and its live state from
QuestState when you hold the session.
narrative
instance-attribute
narrative: str
The quest's authored offer beat, or the empty string when unauthored. The words themselves travel, because a wire client holds no adventure document to resolve them from.
speaker
instance-attribute
speaker: str
Who is speaking the offer, such as "Sister Halda", or the empty string when the
block authors no attribution.
objectives
instance-attribute
objectives: tuple[ObjectiveView, ...]
The revealed objectives, in the order the quest authored them.
RefereeView
Bases: BaseModel
The full state projection minus RNG internals, one typed field per group the save keeps.
Build one with build_referee_view, or with
GameSession.view and Visibility.REFEREE. Use it behind
the screen: for the context an LLM referee reasons over, for a debugging panel, for a test that
asserts on state a player may not see. Never send it to a player's client, and draw nothing a player
sees from it, because that is what PlayerView is for.
Each field is the session's own model rather than a dict, so you read
view.monsters[0].current_hp and view.flags["key"] with the types this reference documents, and
each field's docstring names the model to read next. The fields are the groups
session_state writes, minus the master seed and the RNG stream
positions, so view.model_dump(mode="json") is that save payload without those two keys. The seed
and the stream positions live only in the save, because knowing them would let a player predict
every roll to come.
The view is a snapshot of the moment it was built: the session's mutable state is copied into it, so
play going on afterwards leaves the view as it was, and editing what you find on a view changes
nothing on the session. Being frozen fixes the view's fields rather than their contents, so
rebinding view.flags raises while view.flags["key"] = 1 and view.monsters[0].current_hp = 0
edit the view's own copies and are allowed. Build a fresh view after each command rather than
editing one. The command log, the event log, and the journal are shared with the session instead of
copied, because a command, an event, and a journal entry are frozen records of something that has
already happened.
ruleset
instance-attribute
ruleset: Ruleset
The options this session plays under, as a Ruleset: the flags
that decide which optional rules are on.
party
instance-attribute
party: Party
The party, as a Party of full
Character sheets in marching order, the dead included. Every
number is here, the spell book and the true names of magic items among them, so render a player's
own sheet from PlayerView.party instead, which masks what
the party has not identified.
adventure
instance-attribute
adventure: Adventure
The whole authored document, as an Adventure: the town, the
dungeons with their complete geometry and keyed areas, the triggers, and the quests. It is the map
with nothing hidden, so draw the party's map from
PlayerView.explored instead. The document is frozen and
the view copies it even so, because the tree under it contains dicts a caller can edit in place, the
town's travel turns and each level's edges among them.
mode
instance-attribute
mode: SessionMode
The SessionMode the session is in, which decides the
commands it will accept right now.
clock_rounds
instance-attribute
clock_rounds: int
The elapsed game clock in rounds, counting from the start of the session.
allocator
instance-attribute
allocator: IdAllocator
The id source, as an IdAllocator: the counter each
<kind>-NNNN id is handed out from, which is what makes two runs of the same commands name things
identically.
ledger
instance-attribute
ledger: EffectsLedger
The live effects, as an EffectsLedger: spells running,
conditions, a torch burning down, each with the round it expires at. It contains the effects anchored
to dungeon cells as well as the ones on members, and it contains a potion's true duration, which the
rules keep from the players.
dungeon_state
instance-attribute
dungeon_state: DungeonState
What play has written over the authored map, as a
DungeonState: where the party stands, the cells it has walked
and seen, door state, found and sprung traps, drop piles, and generated caches.
monsters
instance-attribute
monsters: tuple[MonsterInstance, ...]
Every creature spawned this session, as
MonsterInstance values in the order they were spawned, the
defeated ones included, so a later event can still name what it was. Hit points and stat internals
are here, which is the line the player view draws: the party sees only
EncounterGroupView.
npcs
instance-attribute
The NPC adventurers in play, as Character sheets in the order
they joined. They are characters rather than monsters, and they fight by the party's own rules.
flags
instance-attribute
The session flag store, keyed as the game chose: the memory
SetFlag writes and an adventure's gates and triggers read. Flags
are content wiring, so no flag ever reaches a player view.
fired_triggers
instance-attribute
The ids of the triggers that have fired, in the order they first fired. It answers "has this fired before", and it is referee-only wiring: the beat a trigger wrote reaches the players through the journal instead.
journal
instance-attribute
journal: tuple[JournalEntry, ...]
The adventure's beats, as JournalEntry values in the order
they were written. The players read the same list, and
PlayerView.journal is where a front end reads it.
quests
instance-attribute
quests: dict[str, QuestState]
Every authored quest's live state, as QuestState values keyed
by quest id, in the order the adventure authored them: the inactive and completed quests as well as
the active ones, and every objective whether revealed or hidden. The players' own reading is
PlayerView.quests.
listener_state
instance-attribute
Each registered listener's state, keyed by its key, in the shape that listener's handle
returned. The session stores it and never interprets it, so what the keys mean is the game's
business.
death_records
instance-attribute
death_records: dict[str, DeathRecord]
When and how each dead party member died, as DeathRecord
values keyed by character id. Raise dead reads the day count from here and neutralize poison
the round window.
defeated_monsters
instance-attribute
defeated_monsters: tuple[DefeatedMonsterRecord, ...]
The creatures defeated since the last experience award, as
DefeatedMonsterRecord values in the order they fell.
GameSession.award_adventure_xp adds up their
xp and clears the list.
deprivation
instance-attribute
deprivation: dict[str, DeprivationState]
Each member's food and water counts, as
DeprivationState values keyed by character id, one per
member a day boundary has charged and the members on zero among them.
PlayerView.deprivation reports the same counts for the
members going short alone.
treasure_snapshot_cp
instance-attribute
treasure_snapshot_cp: int | None
What the party's treasure was worth in copper pieces when it left town, or None when no delve
is under way. The adventure award pays for the difference between this and what comes back.
exploration
instance-attribute
exploration: ExplorationCounters
The crawl bookkeeping, as ExplorationCounters:
distance walked, turns since rest, the wandering cadence, noise, sleep, and provisions.
encounter
instance-attribute
encounter: EncounterState | None
The encounter under way, as an EncounterState, or
None when nothing is happening. It contains each group's monster ids, its distance, the stance the
reaction roll settled, and any chase in progress. The players' reading of the same encounter is
PlayerView.encounter.
battle
instance-attribute
battle: BattleState | None
The battle under way, as a BattleState, or None outside
one. It contains the round number and the per-battle trackers, including who fired a reloading weapon
last round.
command_log
instance-attribute
command_log: tuple[SerializeAsAny[Command], ...]
Every accepted command, in order, each one the Command
subclass it was issued as, so its own fields are there to read. Refused commands are absent, because
they changed nothing, and replay_game re-executes this list from
the master seed to rebuild the session.
event_log
instance-attribute
event_log: tuple[SerializeAsAny[Event] | dict, ...]
Everything that has happened, in order, each entry the Event
subclass that was emitted, including the referee-visibility events a player never sees. An entry
restored from a save whose event type this library has no class for stays the raw mapping it
arrived as, so check for a dict before reading an entry's attributes. The union is what keeps a
raw entry raw: an Event instance validates as the event, while a mapping, which a model refuses
under strict validation, falls to the dict arm and passes through unchanged.
build_player_view
build_player_view(session) -> PlayerView
Build the player view from session state, never from the event log.
Call it after every accepted command to get the snapshot your front end renders, and
send that object rather than the session to any client you do not control.
GameSession.view with Visibility.PLAYER
calls this for you, so use it when you already hold the session and reach for this
function when you want the builder itself.
The call reads session state and mutates nothing, so building a view twice gives two equal snapshots and costs the party no game time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
GameSession
|
The running session. |
required |
Returns:
| Type | Description |
|---|---|
PlayerView
|
The frozen whitelist projection, holding only what the party has learned. |
Examples:
from osrlib.core.alignment import Alignment
from osrlib.core.character import CHARACTER_CREATION_STREAM, create_character
from osrlib.core.rng import RngStreams
from osrlib.core.ruleset import Ruleset
from osrlib.crawl.adventure import Adventure, TownSpec
from osrlib.crawl.dungeon import DungeonSpec, LevelSpec
from osrlib.crawl.party import Party
from osrlib.crawl.session import GameSession
from osrlib.crawl.views import build_player_view
rules = Ruleset()
rng = RngStreams(master_seed=7).get(CHARACTER_CREATION_STREAM)
hero = create_character(
name="Hild",
class_id="fighter",
alignment=Alignment.LAWFUL,
ruleset=rules,
stream=rng,
)
level = LevelSpec(number=1, width=1, height=1, entrance=(0, 0))
crypt = DungeonSpec(id="crypt", name="The Old Crypt", levels=(level,))
adventure = Adventure(name="A First Delve", town=TownSpec(name="Threshold"), dungeons=(crypt,))
session = GameSession.new(Party(members=[hero.character]), adventure, seed=7)
player = build_player_view(session)
print(player.mode)
# town
print(player.party[0].id)
# character-0001
assert "flags" not in player.model_dump() # session flags are the game's secret
build_referee_view
build_referee_view(session) -> RefereeView
Build the referee view: every group the save keeps, typed, minus the seed and the RNG streams.
Use it for the context an LLM referee reasons over, for a debugging panel, or for a test that
asserts on state a player may not see.
GameSession.view with Visibility.REFEREE calls this
for you, so use that when you already hold the session and reach for this function when you want
the builder itself. Never hand the result to a player's client: that is what
build_player_view is for. To store a session rather
than read it, call save_game, which keeps the seed and the
stream positions a restored game needs.
The call reads session state and mutates nothing. What it returns is a snapshot rather than a window: the session's mutable models are copied into it, so the session playing on afterwards leaves the view as it was, and editing what you find on the view changes nothing on the session. A frozen model whose own containers cannot be edited goes in as it is, which covers the ruleset, the commands, the events, the journal entries, and the death and defeat records. The adventure is frozen as well and is copied anyway, because the authored tree contains dicts a caller can edit in place, the town's travel turns and each level's edges among them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
GameSession
|
The running session. |
required |
Returns:
| Type | Description |
|---|---|
RefereeView
|
The frozen full-state projection, minus the master seed and the RNG stream positions. |
Examples:
from osrlib.core.alignment import Alignment
from osrlib.core.character import CHARACTER_CREATION_STREAM, create_character
from osrlib.core.rng import RngStreams
from osrlib.core.ruleset import Ruleset
from osrlib.crawl.adventure import Adventure, TownSpec
from osrlib.crawl.commands import SetFlag
from osrlib.crawl.dungeon import DungeonSpec, LevelSpec
from osrlib.crawl.party import Party
from osrlib.crawl.session import GameSession
from osrlib.crawl.views import build_referee_view
rules = Ruleset()
rng = RngStreams(master_seed=7).get(CHARACTER_CREATION_STREAM)
hero = create_character(
name="Hild",
class_id="fighter",
alignment=Alignment.LAWFUL,
ruleset=rules,
stream=rng,
)
level = LevelSpec(number=1, width=1, height=1, entrance=(0, 0))
crypt = DungeonSpec(id="crypt", name="The Old Crypt", levels=(level,))
adventure = Adventure(name="A First Delve", town=TownSpec(name="Threshold"), dungeons=(crypt,))
session = GameSession.new(Party(members=[hero.character]), adventure, seed=7)
session.execute(SetFlag(key="gate_raised", value=True))
referee = build_referee_view(session)
print(referee.mode, referee.clock_rounds)
# town 0
print(referee.party.members[0].id, referee.party.members[0].current_hp)
# character-0001 3
print(referee.flags) # the wiring a player never sees
# {'gate_raised': True}