goldbox.world¶
The overland travel map — SQRDATA0n, read and stitched into one world.
Not `goldbox/world_state.py`, which is where a party is standing and when. This module is the map itself.
The overland map is not a `GEO`. It is the combat square engine –
SQRPACI descriptor, one byte a square – pointed at SQRDATA0n instead of
a combat arena. automap/combat.py reads exactly this shape for a fight;
this module reads the same shape for the three files that make up Pool of
Radiance’s wilderness.
A SQRDATA file is 648 bytes of grid, then 120 tile entries of 18 bytes
each: an 18 x 36 grid, one byte a square, indexed y * 18 + x, followed by
120 glyphs of nine screen codes then nine colour attributes – a 3 x 3 block
of characters out of SECSET0n. SQRDATA05 is 648 + 120 x 18 = 2808 bytes
exactly; SQRDATA04 and SQRDATA06 carry eight spare bytes after that. All
of this is CONFIRMED (docs/113-world-map.md, docs/137-wilderness-automap.md)
and pinned against the player’s own disks by tests/test_p3.py.
The three files are overlapping windows on one world, thirteen columns
apart, west to east: SQRDATA04 (west), SQRDATA05 (middle), SQRDATA06
(east) – goldbox/areas.py’s own order for areas 25, 26 and 27. The game’s
own world coordinate is the window-local x plus 13 * window_index –
docs/137-wilderness-automap.md §1: “the party marked at ($49C3 + 13 x k,
$49C4)” – so this module keeps that coordinate system rather than
renormalising it to start at zero. The two windows stitch at world x = 15
and x = 28, and the walkable part of the world is x 2-41, y 2-33: 40 x 32
squares. CONFIRMED: the raw grid overlaps in a five-column band at each
seam (18-13 = 5 columns, all 36 rows), and 179 of those 180 squares agree
between the west and middle windows, 180 of 180 between the middle and east
(docs/113-world-map.md); tests/test_world.py recomputes both counts
against the disks.
A terrain code means only what its own window’s tables say. 2E is
walkable mountain on map 19 and solid on map 1B
(docs/113-world-map.md, docs/137-wilderness-automap.md, both “Do not
read a terrain code against another window’s table”). So Window.square
never crosses into another window’s data, and there is deliberately no
global tile-name table here – only the raw index, which the window it came
from is the sole authority on.
## What this module does not do, and why
passable(window, x, y) and site_at(world_x, y) are named by
#11 (Draw the wilderness on the automapper) and are not implemented.
Both need a table that is not in SQRDATA0n at all: “each script carries
its site list as four tables (y, count, x, event) and its impassable-terrain
list as one more” (docs/113-world-map.md) – inside ECL19/ECL1A/ECL1B’s
own bytecode, not in the file this module reads. The byte offsets of those
tables were recorded once, in work/reports/world-map.md, which is lost
with work/ (#136 (Thirty-two cited write-ups are gone, because the
knowledge base pointed into gitignored scratch)) – confirmed by
tools/windowsquare.py’s own docstring: “Passability cannot be read off the
disk: the impassable-terrain table’s address was in
work/reports/world-map.md, which is lost (#136), so the running game is
the only authority left.” Recovering the offsets means rebuilding an ECL
decoder, and docs/115-review-the-scripts.md records that reading the ECL
scripts at all was closed at Donald’s own direction on 2026-08-31 –
“I don’t need to see the ECL scripts. If I decide I want to see them, we can
approach the issue again at that time.” Reopening that is his call, not a
default this module can reach for. Both functions raise NotImplementedError
naming this rather than guessing at an address or shipping a table that was
never read off anything.
Module Attributes
The grid is 18 columns wide and 36 rows tall, one byte a square, indexed |
|
120 glyph entries, nine screen codes then nine colour attributes -- a 3 x 3 block of characters. |
|
|
|
The walkable part of a window, window-local -- the two-square border is never shown to the player and the game never walks a party into it ( |
|
Windows are |
|
west, middle, east -- |
|
Where the walkable world starts and how wide/tall it is, in the game's own coordinate system (window-local x plus |
|
The two seams, in world x -- where window k hands off to window k + 1. |
Functions
|
Whether the party may walk onto window-local |
|
The site at world |
Classes
One of a window's 120 glyphs. |
|
One |
|
The three |
Exceptions
A |
- goldbox.world.MIN_FILE_SIZE = 2808¶
SQRDATA05is exactly this size;SQRDATA04andSQRDATA06carry eight spare bytes after it (tests/test_p3.py).
- goldbox.world.PLAYABLE_X = range(2, 16)¶
The walkable part of a window, window-local – the two-square border is never shown to the player and the game never walks a party into it (
docs/113-world-map.md: “Walkable is x 2..15, y 2..33 of each window”).
- goldbox.world.SEAM_WEST_MIDDLE = 15¶
The two seams, in world x – where window k hands off to window k + 1. A world x at or past a seam belongs to the eastern window of the pair; the two windows’ raw data agree there (179/180 and 180/180, see the module docstring), so which side answers a seam square is a bookkeeping choice, not a correctness one.
- goldbox.world.STRIDE = 18¶
The grid is 18 columns wide and 36 rows tall, one byte a square, indexed
y * STRIDE + x. This is$0612 + 1, read offGDRIVE00 $C3AF– not$0607= 20, which isautomap/combat.py’s own corrected note (docs/113-world-map.md, “Correction todocs/101-combat-view.md”).
- goldbox.world.TILE_COUNT = 120¶
120 glyph entries, nine screen codes then nine colour attributes – a 3 x 3 block of characters. PROBABLE (
docs/113-world-map.md): the split between the two halves is measured from the file’s own arithmetic, but which set the codes are drawn from is not independently confirmed.
- class goldbox.world.Tile[source]¶
Bases:
objectOne of a window’s 120 glyphs.
screen_codesandattributesare nine bytes each, PROBABLE as “a 3 x 3 block of characters out ofSECSET0n” (docs/113-world-map.md) – this module hands the two halves back as measured and decodes no further, since drawing the game’s own art is not what any of this is for (docs/137-wilderness-automap.md§5: “what aSECSET0nglyph looks like – not needed”).- __init__(screen_codes, attributes)¶
- goldbox.world.WINDOW_NAMES = ('SQRDATA04', 'SQRDATA05', 'SQRDATA06')¶
west, middle, east –
goldbox/areas.py’s own order for areas 25, 26 and 27.- Type:
The three files, in world order
- goldbox.world.WINDOW_STEP = 13¶
Windows are
WINDOW_STEPworld columns apart, west to east – the game’s own arithmetic,$49C3 + 13 * k(docs/137-wilderness-automap.md).
- goldbox.world.WORLD_X_MIN = 2¶
Where the walkable world starts and how wide/tall it is, in the game’s own coordinate system (window-local x plus
13 * window_index, never renormalised to 0).docs/113-world-map.md: “the world’s playable area is 40 x 32”;docs/137-wilderness-automap.md: “stitched at world x 15 and 28”.
- class goldbox.world.Window[source]¶
Bases:
objectOne
SQRDATAfile: an 18 x 36 grid of tile indices, plus its 120 tiles.A terrain code means only what this window’s own tables say – see the module docstring. There is no method here that accepts a foreign code or reaches into another
Window.- classmethod from_disk(disk, name)[source]¶
- Parameters:
disk (goldbox.d64.D64 | str)
- Return type:
- is_playable(x, y)[source]¶
Whether
(x, y)is in the two-square-deep border the game never shows or walks a party into.
- tile(index)[source]¶
One of the 120 glyph entries this window’s grid indexes into.
- Parameters:
index (int)
- Return type:
- class goldbox.world.World[source]¶
Bases:
objectThe three
SQRDATAwindows, addressed by the game’s own world coordinate: window-local x plus13 * window_index, never renormalised.windowsis(west, middle, east)–SQRDATA04,05,06– matchingWINDOW_NAMESandgoldbox/areas.py’s order for areas 25, 26 and 27.- __init__(windows)¶
- Parameters:
windows (tuple[goldbox.world.Window, goldbox.world.Window, goldbox.world.Window])
- Return type:
None
- classmethod from_disks(disks)[source]¶
The three windows, found across a set of disks.
SQRDATA04,05and06are never on the same disk – they ridePOOL6,7and8respectively (areas 25-27,goldbox/areas.py) – so, unlikeGeo.from_disk, this cannot open one image and read three files out of it.disksis any iterable ofD64objects or paths; for each window the first disk that carries its file wins, the waytests/gamedata.py’sgame_filedoes.Raises
WorldErrornaming whichever window no disk indiskscarried.- Return type:
- locate(world_x)[source]¶
Which window owns
world_x, and that window’s own local x there.Raises
IndexErroroutside the walkable world (WORLD_X_MIN..WORLD_X_MAX). At a seam, the eastern window answers – seeSEAM_WEST_MIDDLE/SEAM_MIDDLE_EAST.- Parameters:
world_x (int)
- Return type:
- square(world_x, y)[source]¶
The raw tile index at world
(world_x, y).yis not stitched – every window shares the same y range, and only x moves between them.The int this returns does not carry the window it came from, and a terrain code only means anything against its own window’s table:
2Eis walkable mountain on map19and solid on1B. Nothing here can be asked what a bare code means – there is no global code-to-name table to misuse – but a caller that stores this number and decodes it later, oncepassableexists, is the way that protection is lost. Uselocateand keep theWindow, or callWindow.squaredirectly.
- exception goldbox.world.WorldError[source]¶
Bases:
ValueErrorA
SQRDATApayload too short to hold a grid and its glyph table.
- goldbox.world.passable(window, x, y)[source]¶
Whether the party may walk onto window-local
(x, y). Not implemented – see the module docstring.- Parameters:
window (goldbox.world.Window)
x (int)
y (int)
- Return type: