osrforge.tracing.truth
The geometry truth format: what a map shows, and the levels and areas made from it.
One document describes one adventure module's maps. It has two layers. The
reading layer is what the map shows: each printed Region with its
registration, and each Panel with its cells, edges, key marks, outlines, and
symbols. The resolution layer is what the rules in
docs/tracing-conventions.md make from that reading: each Level with its
grid, areas, placed keys, transitions, and passages, and each Dungeon with its
entrance. An answer key and a synthetic map's answer fill both layers. A trace
fills both too, and may add repairs and before_repair.
Cells are addressed as "x,y", with x the column from the west edge and y
the row from the north edge of the grid, both 0-based, the same addresses the
overrides contract uses. An edge is "x,y:side", the named side of that cell.
Cell and edge readings are letter grids: one string per row, one letter per
cell or edge, so a 50 by 50 level is readable in a text editor and small on
disk.
Examples:
from osrforge.tracing.truth import EdgeGrids, parse_cell
grids = EdgeGrids(vertical=("wow",), horizontal=("ww", "ww"))
assert grids.at((0, 0), "east") == "o"
assert parse_cell("3,4") == (3, 4)
EDGE_LETTERS
module-attribute
The edge letters, in the order EdgeLetter lists them.
SYMBOL_KINDS
module-attribute
SYMBOL_KINDS: tuple[str, ...] = get_args(SymbolKind)
The SymbolKind values, in vocabulary order.
EdgeLetter
module-attribute
EdgeLetter = Literal['o', 'p', 'w', 'n', 'd', 'l', 's', '-']
One edge reading: open, printed open line, wall, window, door, locked door, secret door, or no reading.
- stands where neither side of the edge is floor or water. Every other
position has a letter. Open and printed open line are the two passable
readings.
PageSide
module-attribute
PageSide = Literal['top', 'right', 'bottom', 'left']
A side of the printed page, for where a compass points and where an image edge cuts a region off.
Side
module-attribute
Side = Literal['north', 'east', 'south', 'west']
A side of a cell, named for the grid's own directions: north is the top row of the grid.
Style
module-attribute
Style = Literal[
"tsr_blue", "black_white", "dark_rock", "cave", "hex", "isometric", "side_view", "outdoor", "town", "no_grid"
]
A map's drawing style.
The first four are plan views the stage traces. The rest are styles it refuses
(hex, isometric, side_view, outdoor, town) or can't register
(no_grid).
SymbolKind
module-attribute
SymbolKind = Literal[
"stairs",
"ladder",
"trapdoor",
"hinged_floor",
"chute",
"slide",
"pit",
"cave_mouth",
"pillar",
"statue",
"pool",
"steps",
"bridge",
"footing",
"locked_door",
]
The symbol vocabulary: what a map symbol or a legend entry can be.
cave_mouth stands on an edge. footing marks steps, footings, or bars drawn
on one bank of water, and two footings facing each other across water make a
crossing. steps is steps inside a level and never makes a crossing.
locked_door is a legend entry only: a locked door on the map is the edge
letter l.
Area
Compass
Bases: BaseModel
Where north is on the page.
The level grid takes the map's north: panel placement turns each panel by
the quarter turn that puts north at the top. A printed compass that isn't
on a quarter turn records its angle, and north is the nearest quarter
turn, which the report flags. Exactly halfway, the quarter turn
counter-clockwise of the compass wins: 45 degrees is top, 135 right,
225 bottom, and 315 left.
north
instance-attribute
north: PageSide
The page side the map's north points to, to the nearest quarter turn. top when the map prints no compass.
printed
instance-attribute
printed: bool
True when the map prints a compass. When false, the report flags the default.
angle
class-attribute
instance-attribute
angle: float | None = None
The printed compass's direction in degrees clockwise from the top of the page, when it isn't on a quarter turn:
0 is the top, 90 the right edge. None when the compass points along a page side or the map prints none.
DamagedEdge
Dungeon
EdgeGrids
Bases: BaseModel
The edge readings of a grid, as two letter grids.
vertical has one row per grid row and one letter per grid line that runs
north to south, so each row is one letter longer than the grid is wide:
letter j of row y is the west side of cell (j, y), and the last letter
is the east frame. horizontal has one row per grid line that runs east to
west, so it has one more row than the grid: letter x of row i is the
north side of cell (x, i), and the last row is the south frame.
at
with_letter
positions
Entrance
GeometryTruth
Bases: BaseModel
One module's maps and the levels made from them.
An answer key or a synthetic answer has no repairs and no
before_repair. A trace has both when the checks repaired anything.
before_repair
class-attribute
instance-attribute
before_repair: GeometryTruth | None = None
The same document as the rules left it before any repair, its panels the reading as read. A trace fills it when it made repairs, and the trace's own panels then carry the reading with each repair mapped back onto its panel.
north_in_force
The page side a region's north points to, taking a half's partner's compass when the region prints none.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
region_id
|
str
|
The region's id. |
required |
Returns:
| Type | Description |
|---|---|
PageSide
|
The region's own |
PageSide
|
prints one, else the region's recorded default. |
region
panel
level
HalfPair
Bases: BaseModel
Two regions that are halves of one map, and how the stage handled them.
joined
instance-attribute
joined: bool
True when the halves became one panel, false when they stayed apart as two panels linked by passages.
rows
instance-attribute
rows: int
The row shift: the second half's row 0 lies this many rows south of the first half's row 0.
columns
class-attribute
instance-attribute
columns: int | None = None
The whole-cell column offset of the second half from the first, when joined.
Legend
Bases: BaseModel
The legend in force for a region.
from_page
class-attribute
instance-attribute
from_page: int | None = None
The page whose legend this region uses when it prints none.
symbols
class-attribute
instance-attribute
symbols: tuple[SymbolKind, ...] = ()
The vocabulary entries the legend in force explains.
Level
Bases: BaseModel
One level after resolution: its grid of 10-foot cells, its areas, and what stands on them.
A level's cells are floor only where the level owns them. Another level's floor and the outside are rock here. The grid has one cell of rock around the floor on every side, and the map's north is its top, so osrlib's north is the map's north.
verdict
instance-attribute
verdict: Literal['traced', 'fallback']
Whether the level was traced from its map or fell back to synthesis.
reason
class-attribute
instance-attribute
reason: str | None = None
Why the level fell back, or None when traced.
areas
class-attribute
instance-attribute
Areas by key, the survey's canonical key.
locked_doors
class-attribute
instance-attribute
The doors the prose locks, each as an edge address x,y:side of a cell of the level. The edge keeps the
letter the reading gives, so a secret door the prose locks stays s and is listed here. A door read as l
under a legend with the locked-door symbol is locked by its letter and isn't listed.
flags
class-attribute
instance-attribute
What the report flags on this level, one entry each.
LevelPanel
Bases: BaseModel
Where a panel sits on a level's grid, and how it was turned to put its north at the top.
origin
instance-attribute
The level cell where the turned panel's north-west cell sits. Panel cell c lands on
origin + rotate_cell(c, (panel.width, panel.height), rotation), with the panel's width and height those of the
converted panel when the panel is a 5-foot one.
rotation
class-attribute
instance-attribute
rotation: Rotation = 0
The clockwise quarter turn that put the panel's north at the top: rotation_for of its first region's
compass.
Mark
Bases: BaseModel
A label-sized mark printed on the map: a key, a letter, or a label.
text
instance-attribute
text: str
The mark's text as printed. Keys stacked one above the other are one mark whose text is their labels from
top to bottom joined by /.
cell
instance-attribute
cell: str
The cell under the mark's centre, or the edge's own cell when the mark sits on a door.
edge
class-attribute
instance-attribute
edge: str | None = None
The door edge the mark is printed on, when it sits on one. Its cell is cell.
leader_to
class-attribute
instance-attribute
leader_to: str | None = None
The cell a leader line from the mark ends on.
Outline
Bases: BaseModel
One level's outline on a panel, from the whole-map reading.
rects
class-attribute
instance-attribute
Rectangles [x, y, width, height] in panel cells. Their union is the outline.
seeds
class-attribute
instance-attribute
Cells well inside the level, where the partition starts.
Page
Bases: BaseModel
One page of the module, as the tracing stage's first step sees it.
images
class-attribute
instance-attribute
The embedded images, in drawing order.
blanked
class-attribute
instance-attribute
blanked: bool = False
True when the blank_page_renders setting blanks this page.
spread_with
class-attribute
instance-attribute
spread_with: int | None = None
The other page of a two-page spread that one image spans. The spread image is listed in images on both
pages, and each page names the other here.
PageImage
Bases: BaseModel
One image embedded on a page.
file
instance-attribute
file: str
The image file, relative to the document's directory. The same file on two pages is one image printed twice.
hidden
class-attribute
instance-attribute
hidden: bool = False
True when one later image on the page covers more than half of this image's placement rectangle, the rule
HIDDEN_COVERAGE in osrforge.tracing.images states, so the page doesn't show it.
Panel
Bases: BaseModel
The reading of one panel: a registered region, or two halves joined into one.
The grid is in the panel's own squares: 5-foot squares on a 5-foot map
until convert_five_foot
makes 10-foot cells of them.
regions
class-attribute
instance-attribute
regions: tuple[PanelRegion, ...] = Field(min_length=1)
The region, or the two joined halves, with their origins on this grid.
partial
class-attribute
instance-attribute
Cells that are partly floor: between a quarter and three quarters, or on a diagonal.
cave
class-attribute
instance-attribute
Cells whose walls are drawn off the grid. An edge touching one is a cave edge.
PanelRegion
Passage
Bases: BaseModel
A connection the party walks through: across one side of a cell to a cell elsewhere.
to_level
class-attribute
instance-attribute
The destination level of the same dungeon, or this level when the passage links two panels.
PlacedKey
Region
Bases: BaseModel
One framed drawing on a map image, with its registration and its verdicts.
columns
class-attribute
instance-attribute
The region's width in squares of its own scale, 0 when it has no grid.
rows
class-attribute
instance-attribute
The region's height in squares of its own scale, 0 when it has no grid.
cut_off
class-attribute
instance-attribute
The image edges that cut the drawing off.
verdict
instance-attribute
verdict: Literal['registered', 'unregistered', 'refused']
Whether the grid was fitted, the fit failed, or the style or scale is refused.
reason
class-attribute
instance-attribute
reason: str | None = None
Why the region is unregistered or refused, or None when registered.
registration
class-attribute
instance-attribute
registration: Registration | None = None
The fitted grid, present exactly when the verdict is registered.
Registration
Bases: BaseModel
Where each grid corner of a region lies on its image.
corners has rows + 1 rows of columns + 1 points, each the pixel
position [x, y] of a grid corner, so corner [j][i] is the north-west
corner of cell (i, j). Points record the fit exactly whatever the fit's
model is: pitch, shear, and drift are all in the corners.
corners
instance-attribute
The grid corners in pixels, row by row from the north-west.
pixel
The image position of a grid point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
point
|
tuple[float, float]
|
Grid coordinates |
required |
Returns:
| Type | Description |
|---|---|
tuple[float, float]
|
The pixel position, interpolated within the corner cell. |
Repair
Bases: BaseModel
One repair the checks made on a level.
cells
class-attribute
instance-attribute
Cells the repair changed, in the level's coordinates: floor made rock, or rock made floor.
Scale
Bases: BaseModel
A region's printed scale.
feet
class-attribute
instance-attribute
feet: int | None = None
Feet per square: 5 or 10 for a scale the stage accepts, None for any other.
printed
instance-attribute
printed: bool
True when the map prints its scale. When false, feet is the default, 10, and the report flags it.
text
class-attribute
instance-attribute
text: str | None = None
The printed scale statement, when there is one.
Symbol
Bases: BaseModel
One map symbol.
cells
class-attribute
instance-attribute
The cells the symbol covers. A cave mouth has none.
direction
class-attribute
instance-attribute
direction: Literal['up', 'down'] | None = None
The way the map shows stairs, a ladder, a trapdoor, or a chute going, or None when it shows none.
Transition
canonical_form
canonical_form(truth: GeometryTruth) -> GeometryTruth
The document with every list that has no meaningful order put in north-then-west order.
Two resolutions are the same when their canonical forms are equal, with
flags left out of the comparison. save_geometry_truth writes this
form.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
truth
|
GeometryTruth
|
Any document. |
required |
Returns:
| Type | Description |
|---|---|
GeometryTruth
|
A document equal to |
GeometryTruth
|
placed keys, transitions, passages, marks, symbols, partly-floor and |
GeometryTruth
|
cave cells, and flags. A level's lists are ordered on the level grid, |
GeometryTruth
|
and a panel's through the panel's compass in force. |
cell_key
edge_key
load_geometry_truth
load_geometry_truth(path: Path) -> GeometryTruth
Load and validate a geometry truth document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
The JSON file. |
required |
Returns:
| Type | Description |
|---|---|
GeometryTruth
|
The document. An unknown key or a reference to a missing region, panel, |
GeometryTruth
|
level, or cell fails loudly. |
order_key
The sort key that puts points in north-then-west order.
The item farther north comes first, and of two equally far north, the one
farther west. On a level's grid north is the top, so the key is (y, x).
For a point on a panel still in page orientation, north is where the
panel's compass points on the page, and the key gives the order the point
has once the panel is rotated onto the level: with north at the left edge
of the page, west is the bottom.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
point
|
tuple[float, float]
|
A grid point, such as a cell's centre |
required |
north
|
PageSide
|
The page side the panel's north points to, |
'top'
|
Returns:
| Type | Description |
|---|---|
tuple[float, float]
|
A pair that sorts ascending into north-then-west order. |
parse_cell
Parse a cell address.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The address, |
required |
Returns:
| Type | Description |
|---|---|
tuple[int, int]
|
The |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the text isn't two non-negative integers joined by a comma. |
parse_edge
rotate_cell
Where a panel cell lands after the panel turns clockwise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cell
|
tuple[int, int]
|
The cell |
required |
size
|
tuple[int, int]
|
The panel's |
required |
rotation
|
int
|
The quarter turn in degrees. |
required |
Returns:
| Type | Description |
|---|---|
tuple[int, int]
|
The cell on the turned panel, whose own cell |
rotate_side
rotated_size
rotation_for
save_geometry_truth
save_geometry_truth(path: Path, truth: GeometryTruth) -> None
Write a geometry truth document as sorted, indented JSON with a trailing newline.
The same document always writes the same bytes, so committed answers can be compared byte for byte.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
The JSON file to write. |
required |
truth
|
GeometryTruth
|
The document. |
required |