Difference between revisions of "SEGA Master System format"
(Added reverse conversion for banked pointers) |
(→Addresses) |
||
Line 22: | Line 22: | ||
int bank = address & 0x000F; | int bank = address & 0x000F; | ||
int offset = address & 0xFFF0; | int offset = address & 0xFFF0; | ||
− | // assert(0x8000 | + | // assert(offset >= 0x8000 && offset <= 0xBFFF); |
return (bank << 14) + (offset - 0x8000); | return (bank << 14) + (offset - 0x8000); | ||
} | } |
Revision as of 11:34, 11 April 2020
This document describes the format of data in Prince of Persia 1 for the Sega Master System.
(A similar but slightly different version was released for the Sega Game Gear.)
Contents
General
Byte order
Little-endian (Intel) byte order is used, unless noted otherwise. This is the native endianness of the Z80 CPU in the Sega Master System.
Addresses
There are two kinds of addresses (pointers) in the ROM. Both are stored on 2 bytes.
1. Linear addresses. These are simply an address into the ROM. Linear pointers can address only the first 64 kiB (216 bytes) of the ROM, but they can point to any byte within that area.
2. Banked addresses. These can be converted to linear addresses with the following code:
int BankedToLinear(int address) { int bank = address & 0x000F; int offset = address & 0xFFF0; // assert(offset >= 0x8000 && offset <= 0xBFFF); return (bank << 14) + (offset - 0x8000); }
The reverse conversion is:
int LinearToBanked(int address) { // assert((address & 0x000F) == 0); // assert(address >= 0 && address < 0x40000); int bank = (address >> 14) & 0x000F; int offset = (address & 0x3FF0) + 0x8000; return offset | bank; }
Overview diagram for the two formats, between which the functions convert:
1 | 0 | OFFSET | BANK | banked (as it is stored) | ||||||||||||||
17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | bit numbers |
BANK | OFFSET | 0 | 0 | 0 | 0 | linear (as it is interpreted) |
Banked pointers can address the whole 256 kiB (218 bytes) of the ROM, but only in increments of 16 bytes.
Levels
The level table
The level table starts at offset 0x6A7C. (In the Game Gear version it starts at 0x719C.)
There are 14 levels. The table stores 20 bytes about each level:
Size | Contents |
---|---|
2 bytes | Always 0x60C9. |
2 bytes | Banked address of graphics tiles: 0x8003 (0x0C000) for dungeon levels, 0x94C3 (0x0D4C0) for palace levels. |
2 bytes | Linear address of level tiles (2x2 blocks of graphics tiles): 0xA5B2 for dungeon levels, 0xA8D2 for palace levels. |
2 bytes | Banked address of level's #Graphics map. |
1 byte | Level type: 0x05=dungeon, 0x85=palace. |
1 byte | Starting direction: 0x00=left, 0x20=right. |
1 byte | Starting X coordinate. |
1 byte | Starting Y coordinate. |
1 byte | Starting room. (0-23) |
1 byte | Starting animation.
|
4 bytes | Unknown. Their values are frequently similar to the previous 4 bytes. |
2 bytes | Linear address of the level's #Room links and objects table. |
Graphics map
The first 64 bytes contain the list of level tiles used in the map. Unused entries are filled with 0xFF.
After that comes the map itself. Each level is 128 tiles wide and 36 tiles tall. (Levels 13 and 14 are shorter, they are only 24 and 12 tiles tall, respectively.)
Each tile index is stored on 6 bits, so the level is 128*6/8 = 96 bytes wide.
The bits are read starting from the least significant bit of each byte.
The map consists of 24 rooms arranged in 3 rows and 8 columns. (Level 13 and 14 contain only 2 and 1 rows of rooms, respectively.) Each room is 36/3=12 tiles tall and 128/8=16 tiles wide.
(TODO: Which tiles are walls or floors?)
Room links and objects table
This table is preceded by a 2-byte number which tells the length of the following chunk of data. All offsets stored within this table are interpreted as offsets within this chunk.
The data within the chunk is arranged as follows:
Size | Contents |
---|---|
24*2 bytes | The offset of the #Objects' data for each room. Zero if the room doesn't exist. |
24*4 bytes | Room links for each room. Unlike in most other versions of PoP, their order is above,right,below,left. |
the rest | #Objects' data. |
Level 14 is special: Only the first 8 rooms exist. The rest of the rooms have zero offsets. The room links are included only for the first 5 rooms.
You can detect the number of rooms from the first offset: (offset-0x30)/4 gives how many rooms have room links.
Objects' data
Each object is stored as a byte telling what kind of object it is, followed by argument bytes whose number and meaning depends on the type of the object.
(TODO: figure out the unknown argument bytes)
value | object | argument bytes | notes |
---|---|---|---|
0x27 | level door | xx yy tt 07 00 uu 00 | x*=8,y*=8;
|
0x29 | mirror (level 4) | xx yy tt rx ry | tt: 0xDE, rx/ry are the reflection |
0x2B | spike | xx yy | |
0x2C | sword | xx yy | |
0x2D | red (hurt) potion | xx yy | |
0x2E | blue (heal) potion | xx yy | |
0x2F | green (life) potion | xx yy | |
0x30 | pink (slow fall) potion | xx yy | |
0x31 | chomper | xx yy | |
0x32 | gate | xx yy cl tt op uu 00 |
|
0x3E | skeleton wake up (level 3) | 07 01 40 xx yy | The argument bytes mean the same as for enemy (0x64). |
0x3F | skeleton continue (level 3) | 08 01 40 xx yy | The argument bytes mean the same as for enemy (0x64). |
0x41 | loose floor | xx yy | x*=8,y*=8; |
0x42 | falling loose floor (level 13) | xx yy | x*=8,y*=8; |
0x61 | close button | xx yy ww ln ln | x*=8,y*=8;
|
0x62 | open button | xx yy ww ln ln | x*=8,y*=8;
|
0x64 | enemy | cd tp an xx yy |
|
0x66 | shadow steps (level 6) | xx yy | |
0x69 | shadow steals (level 5) | xx yy | |
0x6F | princess (level 14) | xx yy | |
0x70 | mouse (level 8) | xx yy | |
0x74 | shadow fights (level 12) | xx yy | |
0xFF | end | - | Marks the end of object data for this room. |
Amazingly enough, if you set the starting animation in #The level table to a value from the table above, then that object will appear instead of the prince! (Note: not all objects seem to support this.) Conversely, if you add an object with a type byte corresponding to a valid starting animation, then a (controllable!) prince will appear at its place. In addition, you can set the enemy's animation byte to either a prince animation or an object type. This suggests that the game makes no hard distinction between level objects and the prince's and the guards' animations.
Guard table
The guard table starts at offset 0x6CAD. (In the Game Gear version it starts at 0x73CD.)
The table stores 3 bytes about each guard:
Size | Contents |
---|---|
1 byte | color (0-63)
|
1 byte | Number of level where this guard is used. (TODO: Is it used for anything?) |
1 byte | (bitfields)
|
TODO
- Tiles
- Sprites
- Texts
- (Music???)