automap.screen

Reading the C64’s text screen, from anything that can read memory.

Split out of vice.py because none of it is VICE-specific. The screen is 40x25 screen codes wherever the VIC is currently pointed, and finding it costs three reads of the I/O registers – so any backend with a read(addr, length) -> bytes can do it, and so can a dictionary of bytes in a test.

read is passed as a callable rather than an object with a method, so a backend that has to batch, resume or rate-limit around a burst of reads keeps that decision to itself: ViceTarget hands in its monitor’s raw read and resumes once at the end, where its public Target.read resumes every time.

Functions

band(codes, left, right)

A column band, out of a block read as whole screen rows.

codes_to_text(codes)

is_bitmap(read)

Title and credit screens are bitmaps and cannot be read as text.

read_screen(read)

screen_address(read)

Where the VIC is fetching characters from, right now.

screen_row(read, row)

One row as text.

Classes

Screen

One snapshot: 1000 screen codes and 1000 colour nybbles.

class automap.screen.Screen[source]

Bases: object

One snapshot: 1000 screen codes and 1000 colour nybbles.

__init__(codes, colours, address)[source]
Parameters:
contains(needle)[source]
Parameters:

needle (str)

Return type:

bool

find(needle)[source]
Parameters:

needle (str)

Return type:

tuple[int, int] | None

highlighted_rows(colour=1, column=None)[source]

Rows drawn in the menu highlight colour (white by default).

Parameters:
  • colour (int)

  • column (int | None)

Return type:

list[int]

row(r)[source]
Parameters:

r (int)

Return type:

str

row_colour(r)[source]

The dominant colour of the non-blank characters on a row.

Parameters:

r (int)

Return type:

int

rows()[source]
Return type:

list[str]

text()[source]
Return type:

str

automap.screen.band(codes, left, right)[source]

A column band, out of a block read as whole screen rows.

The game draws in windows – combat’s messages are columns 23 to 38 of rows 10 to 22 – and a window is not contiguous in memory, so it is read as whole rows and sliced here. right is one past the last column, which is how the game itself holds it at $03F3.

Parameters:
Return type:

list[str]

automap.screen.codes_to_text(codes)[source]
Parameters:

codes (bytes)

Return type:

str

automap.screen.is_bitmap(read)[source]

Title and credit screens are bitmaps and cannot be read as text.

Parameters:

read (Callable[[int, int], bytes])

Return type:

bool

automap.screen.read_screen(read)[source]
Parameters:

read (Callable[[int, int], bytes])

Return type:

automap.screen.Screen

automap.screen.screen_address(read)[source]

Where the VIC is fetching characters from, right now.

It moves: $0400 at boot, $CC00 once the game is running. Computing it each time is the difference between reading the screen and reading whatever used to be the screen.

Parameters:

read (Callable[[int, int], bytes])

Return type:

int

automap.screen.screen_row(read, row)[source]

One row as text. Two reads instead of three, which matters on a backend where a round trip is a network hop.

Parameters:
Return type:

str