Difference between revisions of "SEGA Master System format"

From Princed Wiki
Jump to: navigation, search
(Objects' data: typo)
(Graphics map)
 
(6 intermediate revisions by 2 users not shown)
Line 15: Line 15:
  
 
1. Linear addresses. These are simply an address into the ROM.
 
1. Linear addresses. These are simply an address into the ROM.
Linear pointers can address only the first 64 kiB of the ROM, but they can point to any byte within that area.
+
Linear pointers can address only the first 64 kiB (2<sup>16</sup> 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:
 
2. Banked addresses. These can be converted to linear addresses with the following code:
Line 22: Line 22:
 
int bank = address & 0x000F;
 
int bank = address & 0x000F;
 
int offset = address & 0xFFF0;
 
int offset = address & 0xFFF0;
// assert(0x8000 <= offset && offset <= 0xBFFF);
+
// assert(offset >= 0x8000 && offset <= 0xBFFF);
 
return (bank << 14) + (offset - 0x8000);
 
return (bank << 14) + (offset - 0x8000);
 
}
 
}
 
</pre>
 
</pre>
Banked pointers can address the whole 256 kiB of the ROM, but only in increments of 16 bytes.
+
The reverse conversion is:
 +
<pre>
 +
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;
 +
}
 +
</pre>
 +
Overview diagram for the two formats, between which the functions convert:
 +
{| class="wikitable"
 +
| colspan=2 align=center | || 1 || 0 || colspan=10 align=center | OFFSET || colspan=4 align=center | 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
 +
|-
 +
| colspan=4 align=center | BANK || colspan=10 align=center | OFFSET || 0 || 0 || 0 || 0 || linear (as it is interpreted)
 +
|}
 +
 
 +
Banked pointers can address the whole 256 kiB (2<sup>18</sup> bytes) of the ROM, but only in increments of 16 bytes.
  
 
== Levels ==
 
== Levels ==
Line 33: Line 52:
  
 
The level table starts at offset 0x6A7C.
 
The level table starts at offset 0x6A7C.
(TODO: In the Game Gear version it starts at 0x719C.)
+
(In the Game Gear version it starts at 0x719C.)
  
 
There are 14 levels.
 
There are 14 levels.
Line 57: Line 76:
 
| 1 byte || Starting Y coordinate.
 
| 1 byte || Starting Y coordinate.
 
|-
 
|-
| 1 byte || Starting room. (0..23)
+
| 1 byte || Starting room. (0-23)
 
|-
 
|-
 
| 1 byte || Starting animation.
 
| 1 byte || Starting animation.
 +
* 0x00: standing (most levels)
 +
* 0x17: falling (level 1)
 +
* 0x18: falling (level 7)
 
|-
 
|-
 
| 4 bytes || Unknown. Their values are frequently similar to the previous 4 bytes.
 
| 4 bytes || Unknown. Their values are frequently similar to the previous 4 bytes.
Line 80: Line 102:
 
Each room is 36/3=12 tiles tall and 128/8=16 tiles wide.
 
Each room is 36/3=12 tiles tall and 128/8=16 tiles wide.
  
(TODO: Which tiles are walls or floors?)
+
Tiles that are floors (dec values):
 +
* palace: 5-9, 12, 17-19, 26-30, 40-41, 60-61
 +
* dungeon: 5-9, 12, 15, 17, 22-23, 27-28, 31-34
 +
 
 +
Tiles that are walls only exist in the dungeon, when the prince is going from left to right (dec values: 1-4, 13, 20-21, 40, 58). The game uses tile-combos as walls, e.g. in dungeon from right to left certain values followed by 12, such as 20+12.
 +
 
 +
(TODO: find out the exact wall combos)
  
 
=== Room links and objects table ===
 
=== Room links and objects table ===
Line 115: Line 143:
 
! value !! object !! argument bytes !! notes
 
! value !! object !! argument bytes !! notes
 
|-
 
|-
| 0x27 || level door || xx yy tt 07 00 uu 00 || x*=8,y*=8; If fourth byte is not 07 then the door opens by itself.<br>
+
| 0x27 || level door || xx yy tt 07 00 uu 00 || x*=8,y*=8;
tt is 01 or 02, uu is 00 or FA
+
* If the fourth byte is not 07 then the door opens by itself.
 +
* tt: unknown (0x02 usually, 0x01 for the level door in the first room of level 5).
 +
* uu: unknown (0x00 usually, 0xFA for the level door in the first room of level 5).
 
|-
 
|-
| 0x29 || mirror (level 4) || xx yy tt rx ry || tt: DE, rx/ry are the reflection
+
| 0x29 || mirror (level 4) || xx yy tt rx ry || tt: 0xDE, rx/ry are the reflection
 
|-
 
|-
 
| 0x2B || spike || xx yy
 
| 0x2B || spike || xx yy
Line 134: Line 164:
 
| 0x31 || chomper || xx yy
 
| 0x31 || chomper || xx yy
 
|-
 
|-
| 0x32 || gate || xx yy cl tt op uu 00 || cl: 02 or FF, tt: 01 or 07, op: 0-5 (05 or 1F), uu: 8C,FA,FE
+
| 0x32 || gate || xx yy cl tt op uu 00 ||
|-
+
* cl: animation: 1=temporary open, 2=close immediately, 0xFF=permanent open, others=close later.
| 0x3E || skeleton wake up (level 3) || 07 01 40 xx yy || x*=32,y*=64;
+
* tt: animation speed, bigger is slower (0x01 usually, 0x07 for the top-left gate in the first room of level 5).
 +
* op: openness: 0-6 (0x05 usually, 0x1F for the first gate on level 3).
 +
* uu: unknown (0xFA usually, 0x8C for the left-side gate in level 9 room 18, 0xFE for the first gate on level 3 and the top-left gate in the first room of level 5).
 
|-
 
|-
| 0x3F || skeleton continue (level 3) || 08 01 40 xx yy || x*=32,y*=64;
+
| 0x3E || skeleton wake up (level 3) || 07 01 40 xx yy || The argument bytes mean the same as for enemy (0x64).
 
|-
 
|-
| 0x40 || skeleton (level 3) || xx yy || Used after the other two skeleton objects, but why?
+
| 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;
 
| 0x41 || loose floor || xx yy || x*=8,y*=8;
Line 146: Line 178:
 
| 0x42 || falling loose floor (level 13) || 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; ln: address of triggered object within the level data chunk.<br>
+
| 0x61 || close button || xx yy ww ln ln || x*=8,y*=8;
For some reason, exit doors are always triggered by close buttons.<br>
+
* ln: address of triggered object within the level data chunk.
ww: 00 (without wall), 02 (with wall)
+
* ww: 0x00 (without wall), 0x02 (with wall).
 +
* For some reason, exit doors can only be opened by close buttons.
 
|-
 
|-
| 0x62 || open button || xx yy ww ln ln || x*=8,y*=8; ln: address of triggered object within the level data chunk.<br>
+
| 0x62 || open button || xx yy ww ln ln || x*=8,y*=8;
ww: 00 (without wall), 02 (with wall)
+
* ln: address of triggered object within the level data chunk.
 +
* ww: 0x00 (without wall), 0x02 (with wall).
 
|-
 
|-
| 0x64 || enemy || cd tp an xx yy || cd: color and direction (00-25), tp: type (00=guard,01=skel,02=Jaffar), an:animation (B5)
+
| 0x64 || enemy || cd tp an xx yy ||
 +
* cd: Index into the [[#Guard table]] (0x00-0x25),
 +
* tp: type (0x00=guard, 0x01=skeleton, 0x02=Jaffar),
 +
* an: animation (0xB5)
 
|-
 
|-
 
| 0x66 || shadow steps (level 6) || xx yy
 
| 0x66 || shadow steps (level 6) || xx yy
Line 159: Line 196:
 
| 0x69 || shadow steals (level 5) || xx yy
 
| 0x69 || shadow steals (level 5) || xx yy
 
|-
 
|-
| 0x6F || princess (level 14) || xx yy || object is added later?
+
| 0x6F || princess (level 14) || xx yy
 
|-
 
|-
 
| 0x70 || mouse (level 8) || xx yy
 
| 0x70 || mouse (level 8) || xx yy
Line 168: Line 205:
 
|}
 
|}
  
=== TODO ===
+
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:
 +
 
 +
{| class="wikitable"
 +
! Size !! Contents
 +
|-
 +
| 1 byte || color (0-63)
 +
* bits 0-1: red (0-3, respectively +0, +1, +2, +3)
 +
* bits 2-3: green (0-3, respectively +0, +4, +8, +12)
 +
* bits 4-5: blue (0-3, respectively +0, +16, +32, +48)
 +
* bits 6-7: unused (always 0)
 +
|-
 +
| 1 byte || Number of level where this guard is used. (TODO: Is it used for anything?)
 +
|-
 +
| 1 byte || (bitfields)
 +
* bits 0-3: Number of hitpoints (0-15). They are not shown if above 7.
 +
** 15 will make the guard invincible. This is used for skeletons.
 +
** If it's 0 the prince will sheathe his sword immediately. But the guard can kill the prince!
 +
* bit 4-5: unused (always 0)
 +
* bit 6: direction: 0=left, 1=right
 +
* bit 7: moves toward the prince initially?: 0=yes, 1=no
 +
|}
 +
 
 +
== TODO ==
  
 
* Tiles
 
* Tiles

Latest revision as of 14:40, 25 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.)

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.
  • 0x00: standing (most levels)
  • 0x17: falling (level 1)
  • 0x18: falling (level 7)
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.

Tiles that are floors (dec values):

  • palace: 5-9, 12, 17-19, 26-30, 40-41, 60-61
  • dungeon: 5-9, 12, 15, 17, 22-23, 27-28, 31-34

Tiles that are walls only exist in the dungeon, when the prince is going from left to right (dec values: 1-4, 13, 20-21, 40, 58). The game uses tile-combos as walls, e.g. in dungeon from right to left certain values followed by 12, such as 20+12.

(TODO: find out the exact wall combos)

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 rooms are numbered from 0 to 23 (0x00 to 0x17). 0xFF means no room. 0x80 means a special exit (used on level 6 and 12).

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;
  • If the fourth byte is not 07 then the door opens by itself.
  • tt: unknown (0x02 usually, 0x01 for the level door in the first room of level 5).
  • uu: unknown (0x00 usually, 0xFA for the level door in the first room of level 5).
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
  • cl: animation: 1=temporary open, 2=close immediately, 0xFF=permanent open, others=close later.
  • tt: animation speed, bigger is slower (0x01 usually, 0x07 for the top-left gate in the first room of level 5).
  • op: openness: 0-6 (0x05 usually, 0x1F for the first gate on level 3).
  • uu: unknown (0xFA usually, 0x8C for the left-side gate in level 9 room 18, 0xFE for the first gate on level 3 and the top-left gate in the first room of level 5).
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;
  • ln: address of triggered object within the level data chunk.
  • ww: 0x00 (without wall), 0x02 (with wall).
  • For some reason, exit doors can only be opened by close buttons.
0x62 open button xx yy ww ln ln x*=8,y*=8;
  • ln: address of triggered object within the level data chunk.
  • ww: 0x00 (without wall), 0x02 (with wall).
0x64 enemy cd tp an xx yy
  • cd: Index into the #Guard table (0x00-0x25),
  • tp: type (0x00=guard, 0x01=skeleton, 0x02=Jaffar),
  • an: animation (0xB5)
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)
  • bits 0-1: red (0-3, respectively +0, +1, +2, +3)
  • bits 2-3: green (0-3, respectively +0, +4, +8, +12)
  • bits 4-5: blue (0-3, respectively +0, +16, +32, +48)
  • bits 6-7: unused (always 0)
1 byte Number of level where this guard is used. (TODO: Is it used for anything?)
1 byte (bitfields)
  • bits 0-3: Number of hitpoints (0-15). They are not shown if above 7.
    • 15 will make the guard invincible. This is used for skeletons.
    • If it's 0 the prince will sheathe his sword immediately. But the guard can kill the prince!
  • bit 4-5: unused (always 0)
  • bit 6: direction: 0=left, 1=right
  • bit 7: moves toward the prince initially?: 0=yes, 1=no

TODO

  • Tiles
  • Sprites
  • Texts
  • (Music???)