How the rooms are defined
In the previous installment, I introduced how the playfields were encoded in the Atari Adventure game. I had converted the assembly data into C code and made a command-line program that would print out the room graphics.
I then recreated the process in Microsoft Color BASIC on a Radio Shack Color Computer emulator.
My command-line C program was displaying on an 80-column Windows command prompt window (or Mac OS X terminal) so it had plenty of room to render the 40 pixel wide playfields. The CoCo’s 32-column screen could not, so I changed the BASIC version to use low-resolution (64×32) text-mode graphics. This also let me use colors, though the CoCo only had 8 foreground colors to work with in this mode, with some restrictions from the Motorola MC6847 video display chip.
The end result was a proof-of-concept showing I was decoding the cartridge data properly, even if I couldn’t render it exactly as the Atari VCS/2600 would have.
There is much more I need to explore. For instance, each room has a definition data structure that describes things like which graphics data to use, how it is displayed (right half of the screen reversed vs mirrored, thin line on the left or white wall), its color, as well as which rooms are connected to it (Up, Left, Down and Right). Here is an example of the yellow castle data structure bytes:
LFEB4: .byte <CastleDef,>CastleDef,$1A,$0A,$21,$06,$03,$02,$01
The first entry (CastleDef) is a two byte pointer to the graphics data elsewhere in the ROM:
;Castle Definition CastleDef: .byte $F0,$FE,$15 ;XXXXXXXXXXX X X X R R R RRRRRRRRRRR .byte $30,$03,$1F ;XX XXXXXXX RRRRRRR RR .byte $30,$03,$FF ;XX XXXXXXXXXXRRRRRRRRRR RR .byte $30,$00,$FF ;XX XXXXXXXXRRRRRRRR RR .byte $30,$00,$3F ;XX XXXXXX RRRRRR RR .byte $30,$00,$00 ;XX RR .byte $F0,$FF,$0F ;XXXXXXXXXXXXXX RRRRRRRRRRRRRR
Note that the comments above are misleading. The graphics data only describes the left side of the images (the “X” characters in the comment). The right is created as the room is displayed, based on a bit in the fourth byte of the data. Here are what all the bytes mean:
;Room Data ;Offset 0 : Low byte room graphics data. ;Offset 1 : High byte room graphics data ;Offset 2 : Color ;Offset 3 : B&W Color ;Offset 4 : Bits 5-0 : Playfield Control ; Bit 6 : True if right thin wall wanted. ; Bit 7 : True if left thin wall wanted. ;Offset 5 : Room Above ;Offset 6 : Room Left ;Offset 7 : Room Down ;Offset 8 : Room Right
Looking at that data again, we can describe is as:
- CastleDef – 2 byte pointer to graphics data.
- $1A – Color.
- $0A – B&W Color (the color to use with the Atari color switch is set to Black and White).
- $21 – Attributes for how to display the room.
- $06 – Room above (up).
- $03 – Room left.
- $02 – Room down.
- $01 – Room right.
This early disassembly did not specifically describe what offset 4’s bits 5-0 mean, but one of them makes the room mirror (both sides look the same) versus the default of reversed. (Odd description. To me, a mirror reverses an image. It’s more like Duplicate versus Mirror in my mind. But I digress…)
The castle is a standard Reversed room:
XXXXXXXXXXX X X X R R R RRRRRRRRRRR XX XXXXXXX RRRRRRR RR XX XXXXXXXXXXRRRRRRRRRR RR XX XXXXXXXXRRRRRRRR RR XX XXXXXX RRRRRR RR XX RR XXXXXXXXXXXXXX RRRRRRRRRRRRRR
It’s attributes of $21 are the bit pattern 00100001.
One of the black castle mazes is Mirrored. Here is the room that contains the secret “dot” which is used to access the hidden easter egg room:
;Black Maze #3 BlackMaze3: .byte $F0,$F0,$FF ;XXXXXXXX XXXXXXXXMMMMMMMM MMMMMMMM .byte $30,$00,$00 ;XX MM .byte $30,$3F,$FF ;XX XXXXXXXXXXXXXXMM MMMMMMMMMMMMMM .byte $00,$30,$00 ; XX MM .byte $F0,$F0,$FF ;XXXXXXXX XXXXXXXXMMMMMMMM MMMMMMMM .byte $30,$00,$03 ;XX XX MM MM .byte $F0,$F0,$FF ;XXXXXXXX XXXXXXXXMMMMMMMM MMMMMMMM
Note how that “box” is made up by the Mirroring of the left half. Neat! That room is defined as:
LFED8: .byte <BlackMaze3,>BlackMaze3,$08,$08,$24,$13,$16,$13,$14
Its attribute of $24 is the bit pattern of 00101000.
And in the game, the room below and to the right of the castle has a thin right wall:
If I understand which room this it, this is the data that draws it:
;Left of Name Room LeftOfName: .byte $F0,$FF,$FF ;XXXXXXXXXXXXXXXXXXXXRRRRRRRRRRRRRRRRRRRRRRRR .byte $00,$00,$00 .byte $00,$00,$00 .byte $00,$00,$00 .byte $00,$00,$00 .byte $00,$00,$00 ;Below Yellow Castle BelowYellowCastle: .byte $F0,$FF,$0F ;XXXXXXXXXXXXXXXX RRRRRRRRRRRRRRRRRRRR **Line Shared With Above Room ----^
Note a clever technique programmer Warren Robinett used to save three bytes of ROM space. The room definition points to the “LeftOfName” data and a room is 21 bytes. The bottom of that room (a wall with an opening in the middle) is the same as the top of another room, so the definition uses three bytes for the next room data for the last three bytes of the first room. Clever!
The definition of the “Left Of Name” room (because the hidden easter egg room with Mr. Robinett’s name is to the right of this room) is:
LFE36: .byte <LeftOfName,>LeftOfName,$E8,$0A,$61,$06,$01,$86,$02
Its attribute of $61 is the bit pattern 01100001.
And down and to the left of the castle is a room with a thin left wall:
Grrr. That Yorgel the yellow dragon ate me while I was trying to take this screen shot.
If I am reading things correctly, I believe this uses the same graphics data as the room below the yellow castle (opening at top, wall at bottom, no walls on left or right):
LFE24: .byte <BelowYellowCastle,>BelowYellowCastle,$D8,$0A,$A1,$08,$02,$80,$03
And its attributes of $A1 is the bit pattern 11000001.
So we have:
- 00100001 – Reversed (castle).
- 00101000 – Mirrored (maze).
- 01100001 – Reversed and thin right wall.
- 10100001 – Reversed and thin left wall.
Thus, looking back at the bit definitions:
;Offset 4 : Bits 5-0 : Playfield Control ; Bit 6 : True if right thin wall wanted. ; Bit 7 : True if left thin wall wanted.
It looks like we have:
- Bit 0 – Right half of screen is Reversed.
- Bit 1 – ?
- Bit 2 – ?
- Bit 3 – Right half of screen Mirrored.
- Bit 4 – ?
- Bit 5 – ?
- Bit 6 – Thin right wall.
- Bit 7 – Thin left wall.
It will take some more code exploring to see what bits 1, 2, 4 and 4 are used for, but understanding what controls Reverse and Mirrored was needed to properly draw the screens. One of those bits is probably used for rendering the “invisible” mazes, but I haven’t gotten to those yet.
Query: What happens if both bit 0 (Reverse) and bit 3 (Mirrored) are on? Why would those be separate bits? Perhaps there was an efficiency reason for checking for a set bit (less instructions than checking for a clear bit?) or perhaps bit 3 is something else. I guess I need to do more checking in to this, too.
The last bit of data (I’m assuming you can figure out “Color” and “B&W Color” entries) is the bytes that show which room is up, left, down or right. This is used by the game engine so it knows which room to display when the player moves off the current screen.
I’ll discuss that in a future installment. It’s not as straightforward as it seems. Here’s a quick teaser:
The “LeftOfName” room (solid walls with an opening at the bottom) is defined as:
LFE36: .byte <LeftOfName,>LeftOfName,$E8,$0A,$61,$06,$01,$86,$02
The room exists are defined as up ($06), left ($01), down ($86) and right ($02). But there are only 30 rooms ($00 to $1e) so there can be no room $86 (134). Maybe it actually means $06 with the high bit set (100000110). But room $06 is commented as “Bottom of Blue Maze” and looks like this:
BlueMazeBottom: XXXXXXXX XX XX RR RR RRRRRRRR XX XX XX RR RR RR XXXX XXXXXXXXXX RRRRRRRRRR RRRR XXXX RRRR XXXXXXXX RRRRRRRR XX RR XXXXXXXXXXXXXXXXXXXXRRRRRRRRRRRRRRRRRRRR
…and that most definitely isn’t the room below the “Left of Name” room.
And, this room is different between game 1 (“Small Kingdom”) and games 2 and 3. In game 1, it’s a room with an opening at the top, and in games 2 and 3 it is part of an invisible maze.
This will have to be figured out.