Difference between revisions of "SEGA Genesis format"
(Added extra potion effects and self-closing gates) |
(Added starting place table) |
||
Line 1: | Line 1: | ||
− | This | + | This document describes the format of data in Prince of Persia 1 for the SEGA Genesis, also known as the SEGA Mega Drive. |
The game has two versions: One for the USA (Genesis), and one for Europe (Mega Drive). | The game has two versions: One for the USA (Genesis), and one for Europe (Mega Drive). | ||
Line 7: | Line 7: | ||
'''Byte order''': Big-endian (Motorola, network) byte order is used, unless noted otherwise. | '''Byte order''': Big-endian (Motorola, network) byte order is used, unless noted otherwise. | ||
− | This is the native | + | This is the native endianness of the Motorola 68k CPU in the SEGA Genesis. |
'''Numbering of bits''': The least significant bit of a byte is bit 0, the most significant bit of a byte is bit 7. | '''Numbering of bits''': The least significant bit of a byte is bit 0, the most significant bit of a byte is bit 7. | ||
Line 27: | Line 27: | ||
{| class="wikitable" | {| class="wikitable" | ||
− | ! Game version !! | + | ! Game version !! Address of level table !! Address of starting place table !! Number of levels |
|- | |- | ||
− | | USA || 0x6A5C || 13 levels | + | | USA || 0x6A5C || 0x20140 || 13 levels |
|- | |- | ||
− | | Europe || 0x358C2 || 17 levels | + | | Europe || 0x358C2 || 0x504B2 || 17 levels |
|} | |} | ||
− | '''Contents | + | '''Contents of the level table''' |
The table stores 20 bytes about each level: | The table stores 20 bytes about each level: | ||
Line 58: | Line 58: | ||
|} | |} | ||
− | + | '''Contents of the starting place table''' | |
+ | |||
+ | The table stores 6 bytes about each level: | ||
+ | |||
+ | * 2 bytes: starting Y coordinate, in pixels (bottom) | ||
+ | * 2 bytes: starting X coordinate, in pixels (left) | ||
+ | * 2 bytes: starting direction: 0=left, 0x800=right | ||
=== Maps === | === Maps === | ||
Line 78: | Line 84: | ||
The possible values are: | The possible values are: | ||
− | + | * 0x00: empty | |
− | 0x00: empty | + | * 0x01: wall |
− | 0x01: wall | + | * 0x02: floor (and all objects below include a floor) |
− | 0x02: floor (and all objects below include a floor) | + | * 0x03: opener button (*) |
− | 0x03: opener button (*) | + | * 0x04: closer button (*) |
− | 0x04: closer button (*) | + | * 0x05: gate (*) |
− | 0x05: gate (*) | + | * 0x06: loose floor (*) |
− | 0x06: loose floor (*) | + | * 0x07: spikes (*) |
− | 0x07: spikes (*) | + | * 0x08: chomper (*) |
− | 0x08: chomper (*) | + | * 0x09: potion (*) |
− | 0x09: potion (*) | + | * 0x0A: level door (*) |
− | 0x0A: level door (*) | + | * 0x0B: sword |
− | 0x0B: sword | ||
− | |||
Further info about objects marked with (*) (and also guards) can be found in the [[#Object tables]]. | Further info about objects marked with (*) (and also guards) can be found in the [[#Object tables]]. | ||
Line 147: | Line 151: | ||
'''potions''' | '''potions''' | ||
* 2 bytes: bubble colors: 1 (red) or 3 (green) | * 2 bytes: bubble colors: 1 (red) or 3 (green) | ||
+ | ** Even values (like 0 or 2) will make the potion gone. | ||
* 2 bytes: Y coordinate (bottom) | * 2 bytes: Y coordinate (bottom) | ||
* 2 bytes: X coordinate (left) | * 2 bytes: X coordinate (left) | ||
* 2 bytes: 0 | * 2 bytes: 0 | ||
* 2 bytes: effect: | * 2 bytes: effect: | ||
− | ** 0 = heal | + | ** 0 = heal (+1 HP) |
− | ** 1 = life | + | ** 1 = life (extra HP) |
− | ** 2 = hurt | + | ** 2 = hurt (-1 HP) |
** 3 = slow-fall | ** 3 = slow-fall | ||
− | ** 4 = | + | ** 4 = shake screen and drop all loose floors in the whole level |
** 5 = stop time | ** 5 = stop time | ||
− | ** 6 | + | ** 6..9 = extra time (5 minutes) |
− | + | Potion effects 4..9 are available only in the European version. | |
− | |||
− | |||
− | Potion effects 4 | ||
'''chompers''' | '''chompers''' | ||
Line 171: | Line 173: | ||
'''loose floors''' | '''loose floors''' | ||
− | * 2 bytes: 1 | + | * 2 bytes: 1 (other values hang the game) |
* 2 bytes: Y coordinate (bottom) | * 2 bytes: Y coordinate (bottom) | ||
* 2 bytes: X coordinate (left) | * 2 bytes: X coordinate (left) | ||
− | * 2 bytes: 0 | + | * 2 bytes: 0 (animation frame) |
* 2 bytes: 0 | * 2 bytes: 0 | ||
'''gates''' | '''gates''' | ||
− | * 2 bytes: state: 0=closed | + | * 2 bytes: state: (animation) |
+ | ** 0=closed | ||
+ | ** 1=open on start (not used) | ||
+ | ** 3=open | ||
+ | ** 7=close on start | ||
* 2 bytes: Y coordinate (top) | * 2 bytes: Y coordinate (top) | ||
* 2 bytes: X coordinate (left edge of the gate's tile, but the gate is on the ''right'' edge of this tile) | * 2 bytes: X coordinate (left edge of the gate's tile, but the gate is on the ''right'' edge of this tile) | ||
− | * 2 bytes: state: 0=closed | + | * 2 bytes: state: (amount of openness) |
− | * 2 bytes: state: 0=closed / close on start | + | ** 0=closed |
+ | ** 1..0x0B=partially open (not used) | ||
+ | ** 0x0C=open / close on start | ||
+ | * 2 bytes: state: (time before gate starts closing) | ||
+ | ** 0=closed / close on start | ||
+ | ** 0xFFFF=open | ||
* 2 bytes: unknown, 0 or 1 | * 2 bytes: unknown, 0 or 1 | ||
Line 198: | Line 209: | ||
* 2 bytes: direction: 0=left, 0x800=right | * 2 bytes: direction: 0=left, 0x800=right | ||
* 2 bytes: 0 | * 2 bytes: 0 | ||
− | * 4 bytes: guard sprite (values below are for USA / Europe) | + | * 4 bytes: guard sprite (values below are for USA / Europe) (unused?) |
** 0x23838 / 0x53C8C = regular guard | ** 0x23838 / 0x53C8C = regular guard | ||
** 0x23954 / 0x53DA2 = skeleton | ** 0x23954 / 0x53DA2 = skeleton | ||
Line 268: | Line 279: | ||
| 15 || 0x8000 || Priority. 0 = behind sprites, 1 = in front of sprites. | | 15 || 0x8000 || Priority. 0 = behind sprites, 1 = in front of sprites. | ||
|- | |- | ||
− | | 14..13 || 0x6000 || Palette index (0 | + | | 14..13 || 0x6000 || Palette index (0..3). For level graphics, only 0 and 1 are used, corresponding to the two palettes mentioned in [[#Palettes]]. |
|- | |- | ||
| 12 || 0x1000 || Vertical flip. | | 12 || 0x1000 || Vertical flip. |
Revision as of 16:38, 26 November 2016
This document describes the format of data in Prince of Persia 1 for the SEGA Genesis, also known as the SEGA Mega Drive.
The game has two versions: One for the USA (Genesis), and one for Europe (Mega Drive). They have data at different offsets, and I will always note which offsets are for which versions.
Contents
General
Byte order: Big-endian (Motorola, network) byte order is used, unless noted otherwise. This is the native endianness of the Motorola 68k CPU in the SEGA Genesis.
Numbering of bits: The least significant bit of a byte is bit 0, the most significant bit of a byte is bit 7.
Addresses: Since the CPU is 32-bit, there are no segments, banks, paging, or anything like that. You can just use each address as it is. (Only the bottom 24 bits are used by the hardware. The top 8 bits are usually 0, though.)
Compression: The European version of the game uses RNC compression for some graphics. This is a popular library by Rob Northen Computing.
Hardware: You can find some documentation about the SEGA Genesis at Zophar's Domain.
Levels
The level table
Starting address
Game version | Address of level table | Address of starting place table | Number of levels |
---|---|---|---|
USA | 0x6A5C | 0x20140 | 13 levels |
Europe | 0x358C2 | 0x504B2 | 17 levels |
Contents of the level table
The table stores 20 bytes about each level:
Size | Contents |
---|---|
2 bytes | Level's height, in pixels. Must be a multiple of 192, the height of a room. Divide by 64 to get the height in tiles. |
2 bytes | Level's width, in pixels. Must be a multiple of 320, the width of a room. Divide by 32 to get the width in tiles. |
2 bytes | Size of each level map, in tiles (bytes). (width * height) |
4 bytes | Start address of level's #Graphics map. |
4 bytes | Start address of level's #Objects map. |
2 bytes | Y coordinate of the top of the starting room, in pixels. Subject to the same restrictions as level height. |
2 bytes | X coordinate of the left of the starting room, in pixels. Subject to the same restrictions as level width. |
2 bytes | Level type: 0=dungeon, 1=palace. |
Contents of the starting place table
The table stores 6 bytes about each level:
- 2 bytes: starting Y coordinate, in pixels (bottom)
- 2 bytes: starting X coordinate, in pixels (left)
- 2 bytes: starting direction: 0=left, 0x800=right
Maps
Both maps store tiles in column-major order. That is, you start from the top-left corner of the level, and go down. After you finished a column, you continue at the top of the next column.
Note that maps are not split into rooms (only when displayed), and therefore there are no room links or room numbers.
Graphics map
Each byte tells which #Level graphics block is to be displayed here. The same index is used for both layers.
Objects map
Each byte tells what object is in the corresponding tile.
The possible values are:
- 0x00: empty
- 0x01: wall
- 0x02: floor (and all objects below include a floor)
- 0x03: opener button (*)
- 0x04: closer button (*)
- 0x05: gate (*)
- 0x06: loose floor (*)
- 0x07: spikes (*)
- 0x08: chomper (*)
- 0x09: potion (*)
- 0x0A: level door (*)
- 0x0B: sword
Further info about objects marked with (*) (and also guards) can be found in the #Object tables.
Object tables
type of object | USA address | Europe address | bytes per object |
---|---|---|---|
opener buttons | 0x1E592 | 0x4E8F6 | 14 |
closer buttons | 0x1EBFC | 0x4F138 | 14 |
spikes | 0x25F94 | 0x56612 | 8 |
potions | 0x27BAE | 0x581B0 | 10 |
chompers | 0x228DE | 0x52D86 | 10 |
loose floors | 0x1CD3E | 0x4CF3C | 10 |
gates | 0x5B96 | 0x61CE | 12 |
level doors | 0x41DE | 0x46C2 | 10 |
guards | 0x1FAC | 0x2B02 | 24 |
Each table has a header. The header contains 6 bytes per level:
- 2 bytes for the number of objects on that level,
- 4 bytes for the start address of the sub-table of the objects on this level. (It's 0 if the count is 0.)
(The two bytes before the header always contain 0x4E75. This is the RTS instruction that ends the preceding subroutine.)
The contents of each table depend on the type of the object.
All coordinates are in pixels.
opener and closer buttons
- 2 bytes: 1
- 2 bytes: Y coordinate (bottom)
- 2 bytes: X coordinate (left)
- 2 bytes: 0
- 2 bytes: first triggered gate: 0-based index into gates table, or 0xFFFF = exit door
- 2 bytes: second triggered gate, or 0xFFFD for none
- 2 bytes: third triggered gate, or 0xFFFD for none
spikes
- 2 bytes: 1
- 2 bytes: Y coordinate (bottom)
- 2 bytes: X coordinate (left)
- 2 bytes: 0xFFFF
potions
- 2 bytes: bubble colors: 1 (red) or 3 (green)
- Even values (like 0 or 2) will make the potion gone.
- 2 bytes: Y coordinate (bottom)
- 2 bytes: X coordinate (left)
- 2 bytes: 0
- 2 bytes: effect:
- 0 = heal (+1 HP)
- 1 = life (extra HP)
- 2 = hurt (-1 HP)
- 3 = slow-fall
- 4 = shake screen and drop all loose floors in the whole level
- 5 = stop time
- 6..9 = extra time (5 minutes)
Potion effects 4..9 are available only in the European version.
chompers
- 2 bytes: 1
- 2 bytes: Y coordinate (top)
- 2 bytes: X coordinate (left)
- 2 bytes: 0
- 2 bytes: 0
loose floors
- 2 bytes: 1 (other values hang the game)
- 2 bytes: Y coordinate (bottom)
- 2 bytes: X coordinate (left)
- 2 bytes: 0 (animation frame)
- 2 bytes: 0
gates
- 2 bytes: state: (animation)
- 0=closed
- 1=open on start (not used)
- 3=open
- 7=close on start
- 2 bytes: Y coordinate (top)
- 2 bytes: X coordinate (left edge of the gate's tile, but the gate is on the right edge of this tile)
- 2 bytes: state: (amount of openness)
- 0=closed
- 1..0x0B=partially open (not used)
- 0x0C=open / close on start
- 2 bytes: state: (time before gate starts closing)
- 0=closed / close on start
- 0xFFFF=open
- 2 bytes: unknown, 0 or 1
level doors
- 2 bytes: type: 0=start, 2=exit door
- 2 bytes: Y coordinate (top)
- 2 bytes: X coordinate (left)
- 2 bytes: 0
- 2 bytes: 0
guards
- 2 bytes: 0
- 2 bytes: Y coordinate (bottom)
- 2 bytes: X coordinate (left)
- 2 bytes: direction: 0=left, 0x800=right
- 2 bytes: 0
- 4 bytes: guard sprite (values below are for USA / Europe) (unused?)
- 0x23838 / 0x53C8C = regular guard
- 0x23954 / 0x53DA2 = skeleton
- 0x23DD8 / 0x54226 = fat
- 0x24000 / 0x54448 = shadow
- 0x241B2 / 0x545FA = Jaffar
- 2 bytes: guard type
- 0 = regular guard
- 1 = skeleton
- 2 = fat
- 3 = shadow
- 4 = Jaffar
- 2 bytes: skill
- 2 bytes: hit points
- 2 bytes: 0
- 2 bytes: 0
Level graphics
USA:
Level type | Palette addr | Tiles addr | Blocks addr | Number of tiles |
---|---|---|---|---|
0 (dungeon) | 0x47B20 | 0x40AC0 | 0xDCEE | 898 |
1 (palace) | 0x4E680 | 0x47B40 | 0x154EE | 858 |
Europe:
Level type | Palette addr | Tiles addr | Blocks addr | Number of tiles |
---|---|---|---|---|
0 (dungeon) | 0x7976C | 0x732D6 | 0x3DEEC | 898 |
1 (palace) | 0x7FA38 | 0x797AC | 0x456EC | 858 |
Palettes
A palette contains 16 colors. Each color is stored on 16 bits (2 bytes), in X:R:G:B = 4:4:4:4 bits format. (This means that a palette takes up 32 bytes.)
But each level graphics has two palettes, so there are 32 colors (64 bytes) at the pointed address!
Tiles
Each tile has 8*8 pixels. Each pixel is stored on 4 adjacent bits. (This means that each tile takes up 32 bytes.)
Within a byte, bits 7..4 store the left pixel, and bits 3..0 store the right pixel. (There is no interleaving or separated planes, as on some other hardware. (SNES, etc.))
Color 0 is transparent!
Blocks
There are 2*256 blocks. The first 256 are for the back layer, the next 256 for the front layer. Block with the same index from the two layers are always used together.
Each block is 4 tiles (32 pixels) wide and 8 tiles (64 pixels) high.
Each tile-position is stored on 2 bytes (16 bits):
bits | mask | meaning |
---|---|---|
15 | 0x8000 | Priority. 0 = behind sprites, 1 = in front of sprites. |
14..13 | 0x6000 | Palette index (0..3). For level graphics, only 0 and 1 are used, corresponding to the two palettes mentioned in #Palettes. |
12 | 0x1000 | Vertical flip. |
11 | 0x0800 | Horizontal flip. |
10..0 | 0x07FF | Tile number. |
TODO
- Texts
- Sprites
- Full-screen images
- Sound samples?
- (Music???)