The current URL is datacrystal.tcrf.net.
Dragon Warrior II (NES)/ROM map: Difference between revisions
(replacing pluralization extract with link to full disassembly) |
(Adding info about non-overworld map data) |
||
Line 15: | Line 15: | ||
* 0x07652 to 0x076E5 = Menu pointers. | * 0x07652 to 0x076E5 = Menu pointers. | ||
* 0x076E6 to 0x07F20 = Menu text. See [[#Menu_Format|Menu Format]] and [[Dragon_Warrior_II:TBL#Table_for_menu_data|Menu Table]]. | * 0x076E6 to 0x07F20 = Menu text. See [[#Menu_Format|Menu Format]] and [[Dragon_Warrior_II:TBL#Table_for_menu_data|Menu Table]]. | ||
* 0x08028 to 0x0838F = Non-overworld map setup info | |||
* 0x086E9 to 0x0A28D = Non-overworld map data See [[#Non-Overworld_Map_Data_Format|Non-Overworld Map Data Format]] | |||
* 0x0B44B to 0x0B686 = Dictionary for main script. | * 0x0B44B to 0x0B686 = Dictionary for main script. | ||
* 0x0B762 to 0x0B7C1 = Main script pointers. Each pointer points at a blob of 16 concatenated strings. | * 0x0B762 to 0x0B7C1 = Main script pointers. Each pointer points at a blob of 16 concatenated strings. | ||
Line 54: | Line 56: | ||
* 0x3F90D to 0x3F90E = Pointer to string used for partially redrawing the main COMMAND menu when switching between EQUIP sub-menus | * 0x3F90D to 0x3F90E = Pointer to string used for partially redrawing the main COMMAND menu when switching between EQUIP sub-menus | ||
* 0x3F90F to 0x3F94E = String used for partially redrawing the main COMMAND menu when switching between EQUIP sub-menus | * 0x3F90F to 0x3F94E = String used for partially redrawing the main COMMAND menu when switching between EQUIP sub-menus | ||
===Non-Overworld Map Data Format=== | |||
The primary data for each map starts with 24 bits of setup data: | |||
{| class="wikitable" | |||
|- | |||
|8 bits||map width | |||
|- | |||
|8 bits||map height | |||
|- | |||
|2 bits||tile ID size - 2 (i.e. the actual size is this value + 2) | |||
|- | |||
|6 bits||unused data | |||
|} | |||
Based on the map dimensions, the size of a map co-ordinate is effectively calculated as ceil(log2(width * height)), i.e. the minimum number of bits required to index into a width * height array (e.g. a map which is 8 tiles wide and 10 tiles high contains 80 tiles and requires 7 bits to uniquely identify each tile). The final setup step is to choose a tile ID to be used as the background; the map will be initialized as a single (map width) * (map height) rectangle of this tile ID: | |||
{| class="wikitable" | |||
|- | |||
|(tile ID size) bits||background tile ID | |||
|} | |||
After that, the map is constructed in 3 phases: | |||
# The first phase sequentially executes a list of building instructions that place the base tiles in their desired positions. | |||
# The second phase is much like the first phase in that it also sequentially executes a list of building instructions, but it is optional and instead of placing base tiles it divides the map up into different visibility regions. | |||
# The third phase happens automatically (i.e. it does not appear in the map data) and processes the current map state to convert wall tiles that are the bottom of a wall (i.e. wall tiles that do not have another wall tile below them) from vertical wall tiles to horizontal wall tiles. | |||
The primary map building instructions are: | |||
{| class="wikitable" | |||
|- | |||
|00||update current tile ID(s) | |||
|- | |||
|01||draw a rectangle between two points | |||
|- | |||
|10||draw tile ID(s) from a point in a direction | |||
|- | |||
|11||draw tile ID(s) at a point | |||
|} | |||
====Primary Map Building Instruction 00==== | |||
Updating the current tile ID(s) first selects a single tile ID: | |||
{| class="wikitable" | |||
|- | |||
|(tile ID size)||set tile ID 1 | |||
|} | |||
After selecting the first tile ID, if the next primary map building instruction is to update the current tile ID(s) again (i.e. 00), there is a 1 bit choice between ending the current map building phase (this is how the main building instruction loop exits) and reading 3 more tile IDs: | |||
{| class="wikitable" | |||
|- | |||
|000||read 3 more tile IDs | |||
|- | |||
|001||end current map building phase | |||
|} | |||
* When reading 3 more tile IDs, a further 3 tile IDs are selected which together with the first tile ID are arranged to form a 2x2 tile group with tile 1 in the top left, tile 2 in the top right, tile 3 in the bottom left, and tile 4 in the bottom right position: | |||
{| class="wikitable" | |||
|- | |||
|(tile ID size) bits||set tile ID 2 | |||
|- | |||
|(tile ID size) bits||set tile ID 3 | |||
|- | |||
|(tile ID size) bits||set tile ID 4 | |||
|} | |||
* When switching from phase 1 (base tiles) to phase 2 (visibility regions), the tile ID size is updated; if the new tile ID size is 0, then phase 2 is skipped, otherwise construction continues with the next primary map building instruction, but now affecting visibility regions instead of base tiles: | |||
{| class="wikitable" | |||
|- | |||
|2 bits||tile ID size | |||
|} | |||
====Primary Map Building Instruction 01==== | |||
Drawing a rectangle between two points requires specifying the two points: | |||
{| class="wikitable" | |||
|- | |||
|(map co-ordinate size) bits||point 1 | |||
|- | |||
|(map co-ordinate size) bits||point 2 | |||
|} | |||
The 2 points are converted from array indices to (X, Y) co-ordinates and then the rectangle formed by using the first point as the top-left corner and the second point as the bottom-right corner (i.e. (X1, Y1) to (X2, Y2)) is filled with the currently selected 1x1 or 2x2 tile group. When drawing with a 2x2 tile group, the tile groups are placed adjacent to each other so that they do not overlap and the rectangle dimensions should all be an even number of tiles. | |||
====Primary Map Building Instruction 10==== | |||
Drawing tile ID(s) from a point in a direction is the most complicated operation. It first requires specifying the starting point: | |||
{| class="wikitable" | |||
|- | |||
|(map co-ordinate size) bits||point | |||
|} | |||
and then 1 of 4 possible directions: | |||
{| class="wikitable" | |||
|- | |||
|00||up | |||
|- | |||
|01||right | |||
|- | |||
|10||down | |||
|- | |||
|11||left | |||
|} | |||
after which the currently selected 1x1 or 2x2 tile group is drawn at the specified point and map building continues by executing line drawing instructions: | |||
{| class="wikitable" | |||
|- | |||
|0||move and draw | |||
|- | |||
|100||rotate clockwise, move, and draw | |||
|- | |||
|101||rotate counter-clockwise, move, and draw | |||
|- | |||
|1100||push map data, rotate clockwise, move, and draw | |||
|- | |||
|1101||push map data, rotate counter-clockwise, move, and draw | |||
|- | |||
|1110||update map position and direction | |||
|- | |||
|1111||pop map data | |||
|} | |||
* Moving and drawing first updates the current drawing point by moving 1 or 2 tiles (depending on the number of tiles currently selected) in the current direction and then drawing a 1x1 or 2x2 tile group at the new point. | |||
* Rotating changes the current direction to the next clockwise (e.g. from up to right) or counter-clockwise (e.g. from right to up) direction; there is no single instruction for reversing (e.g. from up to down) the direction. | |||
* Pushing map data onto the map stack stores a copy of the current position and direction on the map stack for later retrieval. | |||
* Updating the map position and direction allows the drawing to jump from one point to another without affecting any intermediate points; it must be followed by a new starting point: | |||
{| class="wikitable" | |||
|- | |||
|(map co-ordinate size) bits||point | |||
|} | |||
and then 1 of 4 possible directions: | |||
{| class="wikitable" | |||
|- | |||
|00||up | |||
|- | |||
|01||right | |||
|- | |||
|10||down | |||
|- | |||
|11||left | |||
|} | |||
* Popping map data from the map stack retrieves previously pushed data in the opposite order from which it was pushed (a stack is a First In, Last Out [FIFO] data structure, so if data is pushed in the order A then B then C, it will be popped in the order C then B then A). Popping an empty stack ends the line drawing instructions and map building continues with the next primary map building instruction. | |||
====Primary Map Building Instruction 11==== | |||
Drawing tile ID(s) at a point requires specifying the point: | |||
{| class="wikitable" | |||
|- | |||
|(map co-ordinate size)||point | |||
|} | |||
The point is considered the top-left corner of a 1x1 or 2x2 rectangle depending on the number of tiles currently selected and is filled with the currently selected 1x1 or 2x2 tile group. | |||
===Menu Format=== | ===Menu Format=== |
Revision as of 00:20, 4 April 2021
The following article is a ROM map for Dragon Warrior II (NES).
Dragon Quest II
* 0x02D9B to 0x????? = font, 1BPP. * 0x1402B to 0x17D4C = dialogues. 0x14798 - beginning. * 0x180C4 to 0x18E12 = menus and referential bank. Equipments, items, monsters, magic and complements. * 0x1B730 to 0x1B8D7 = passwords. * 0x1BC5C to 0x1BC81 = character's naming. * 0x1BFB9 to 0x1BFF8 = standard names, better yet, some parts.
Dragon Warrior II
Overview
* 0x07652 to 0x076E5 = Menu pointers. * 0x076E6 to 0x07F20 = Menu text. See Menu Format and Menu Table. * 0x08028 to 0x0838F = Non-overworld map setup info * 0x086E9 to 0x0A28D = Non-overworld map data See Non-Overworld Map Data Format * 0x0B44B to 0x0B686 = Dictionary for main script. * 0x0B762 to 0x0B7C1 = Main script pointers. Each pointer points at a blob of 16 concatenated strings. * 0x0B7C2 to 0x0BE0F = Main script part 2 (continued from 0x17FE6). * 0x0BF1D to 0x0BF44 = Words for monster counts. * 0x14010 to 0x17FE6 = Main script part 1 (continued at 0xB7C2). * 0x18032 to 0x18033 = Item list part 1, line 1 pointer. * 0x18034 to 0x18035 = Item list part 1, line 2 pointer. * 0x18036 to 0x18037 = Spell list pointer. * 0x18038 to 0x18039 = Monster name list part 1, line 1 pointer. * 0x1803A to 0x1803B = Monster name list part 1, line 2 pointer. * 0x1803C to 0x1803D = Pointer to string used for partially redrawing the main COMMAND menu when switching between EQUIP sub-menus; only used in battle where there is no COMMAND menu * 0x18040 to 0x18041 = Item list part 2, line 1 pointer. * 0x18042 to 0x18043 = Item list part 2, line 2 pointer. * 0x18044 to 0x18045 = Monster name list part 2, line 1 pointer. * 0x18046 to 0x18047 = Monster name list part 2, line 2 pointer. * 0x1925E to 0x1925F = Pointer to direction names * 0x19260 to 0x19275 = Direction names (used by fortuneteller) * 0x19C36 to 0x19C37 = Pointer to Sun/Water/Life Crest names * 0x19F6F to 0x19F8F = Sun/Water/Life Crest names * 0x1AD49 to 0x1AD88 = Prince of Cannock names. * 0x1AD89 to 0x1ADC8 = Princess of Moonbrooke names. * 0x1B2DA to 0x1B3CD = Item list part 1, line 1 text. * 0x1B3CE to 0x1B4C1 = Item list part 2, line 1 text. * 0x1B4C2 to 0x1B58B = Item list part 1, line 2 text. * 0x1B58C to 0x1B633 = Item list part 2, line 2 text. * 0x1B634 to 0x1B727 = Spell list text. * 0x1B728 to 0x1B86D = Monster name list part 1, line 1 text. * 0x1B86E to 0x1B954 = Monster name list part 2, line 1 text. * 0x1B955 to 0x1B9E4 = Monster name list part 1, line 2 text. * 0x1B9E5 to 0x1BA53 = Monster name list part 2, line 2 text. * 0x1BA53 to 0x1BA92 = String used for partially redrawing the main COMMAND menu when switching between EQUIP sub-menus; only used in battle where there is no COMMAND menu * 0x1C805 to 0x1C8F1 = Code for pluralizing monster names. * 0x1CAC2 to 0x1CC21 = Prologue. * 0x243B6 to 0x247D4 = End credits. * 0x3EDBE to 0x3EDBE = Length of "ADVENTURE LOG" text * 0x3EDC4 to 0x3EDC5 = Pointer to "ADVENTURE LOG" text * 0x3EDCF to 0x3EDDC = "ADVENTURE LOG" text, stored backwards * 0x3F90D to 0x3F90E = Pointer to string used for partially redrawing the main COMMAND menu when switching between EQUIP sub-menus * 0x3F90F to 0x3F94E = String used for partially redrawing the main COMMAND menu when switching between EQUIP sub-menus
Non-Overworld Map Data Format
The primary data for each map starts with 24 bits of setup data:
8 bits | map width |
8 bits | map height |
2 bits | tile ID size - 2 (i.e. the actual size is this value + 2) |
6 bits | unused data |
Based on the map dimensions, the size of a map co-ordinate is effectively calculated as ceil(log2(width * height)), i.e. the minimum number of bits required to index into a width * height array (e.g. a map which is 8 tiles wide and 10 tiles high contains 80 tiles and requires 7 bits to uniquely identify each tile). The final setup step is to choose a tile ID to be used as the background; the map will be initialized as a single (map width) * (map height) rectangle of this tile ID:
(tile ID size) bits | background tile ID |
After that, the map is constructed in 3 phases:
- The first phase sequentially executes a list of building instructions that place the base tiles in their desired positions.
- The second phase is much like the first phase in that it also sequentially executes a list of building instructions, but it is optional and instead of placing base tiles it divides the map up into different visibility regions.
- The third phase happens automatically (i.e. it does not appear in the map data) and processes the current map state to convert wall tiles that are the bottom of a wall (i.e. wall tiles that do not have another wall tile below them) from vertical wall tiles to horizontal wall tiles.
The primary map building instructions are:
00 | update current tile ID(s) |
01 | draw a rectangle between two points |
10 | draw tile ID(s) from a point in a direction |
11 | draw tile ID(s) at a point |
Primary Map Building Instruction 00
Updating the current tile ID(s) first selects a single tile ID:
(tile ID size) | set tile ID 1 |
After selecting the first tile ID, if the next primary map building instruction is to update the current tile ID(s) again (i.e. 00), there is a 1 bit choice between ending the current map building phase (this is how the main building instruction loop exits) and reading 3 more tile IDs:
000 | read 3 more tile IDs |
001 | end current map building phase |
- When reading 3 more tile IDs, a further 3 tile IDs are selected which together with the first tile ID are arranged to form a 2x2 tile group with tile 1 in the top left, tile 2 in the top right, tile 3 in the bottom left, and tile 4 in the bottom right position:
(tile ID size) bits | set tile ID 2 |
(tile ID size) bits | set tile ID 3 |
(tile ID size) bits | set tile ID 4 |
- When switching from phase 1 (base tiles) to phase 2 (visibility regions), the tile ID size is updated; if the new tile ID size is 0, then phase 2 is skipped, otherwise construction continues with the next primary map building instruction, but now affecting visibility regions instead of base tiles:
2 bits | tile ID size |
Primary Map Building Instruction 01
Drawing a rectangle between two points requires specifying the two points:
(map co-ordinate size) bits | point 1 |
(map co-ordinate size) bits | point 2 |
The 2 points are converted from array indices to (X, Y) co-ordinates and then the rectangle formed by using the first point as the top-left corner and the second point as the bottom-right corner (i.e. (X1, Y1) to (X2, Y2)) is filled with the currently selected 1x1 or 2x2 tile group. When drawing with a 2x2 tile group, the tile groups are placed adjacent to each other so that they do not overlap and the rectangle dimensions should all be an even number of tiles.
Primary Map Building Instruction 10
Drawing tile ID(s) from a point in a direction is the most complicated operation. It first requires specifying the starting point:
(map co-ordinate size) bits | point |
and then 1 of 4 possible directions:
00 | up |
01 | right |
10 | down |
11 | left |
after which the currently selected 1x1 or 2x2 tile group is drawn at the specified point and map building continues by executing line drawing instructions:
0 | move and draw |
100 | rotate clockwise, move, and draw |
101 | rotate counter-clockwise, move, and draw |
1100 | push map data, rotate clockwise, move, and draw |
1101 | push map data, rotate counter-clockwise, move, and draw |
1110 | update map position and direction |
1111 | pop map data |
- Moving and drawing first updates the current drawing point by moving 1 or 2 tiles (depending on the number of tiles currently selected) in the current direction and then drawing a 1x1 or 2x2 tile group at the new point.
- Rotating changes the current direction to the next clockwise (e.g. from up to right) or counter-clockwise (e.g. from right to up) direction; there is no single instruction for reversing (e.g. from up to down) the direction.
- Pushing map data onto the map stack stores a copy of the current position and direction on the map stack for later retrieval.
- Updating the map position and direction allows the drawing to jump from one point to another without affecting any intermediate points; it must be followed by a new starting point:
(map co-ordinate size) bits | point |
and then 1 of 4 possible directions:
00 | up |
01 | right |
10 | down |
11 | left |
- Popping map data from the map stack retrieves previously pushed data in the opposite order from which it was pushed (a stack is a First In, Last Out [FIFO] data structure, so if data is pushed in the order A then B then C, it will be popped in the order C then B then A). Popping an empty stack ends the line drawing instructions and map building continues with the next primary map building instruction.
Primary Map Building Instruction 11
Drawing tile ID(s) at a point requires specifying the point:
(map co-ordinate size) | point |
The point is considered the top-left corner of a 1x1 or 2x2 rectangle depending on the number of tiles currently selected and is filled with the currently selected 1x1 or 2x2 tile group.
Menu Format
Menu string format is menu setup parameters + menu text, where the menu setup parameters are:
- 1 byte menu type: bit 7 controls whether the menu has a cursor (1) or not (0), bit 6 controls whether the menu is linked to another menu via a displayed arrow in the top border (1; only set by the in-battle item menu) or not (0), bit 5 controls line spacing (1 = single spacing, 0 = double spacing)
- 1 byte menu height: total height is this number of tiles x 2
- 1 byte menu width: number of tiles x 1
- 1 byte menu screen position: high nybble sets vertical position x 2, low nybble sets horizontal position x 2
If the menu has a cursor, then an additional two parameters are present:
- 1 byte horizontal offset of second column cursor position relative to left edge of menu
- 1 byte initial cursor position relative to top left menu corner; high nybble sets vertical position x 1, low nybble sets horizontal position x 1
If the menu is linked to another menu, then an additional parameter is present:
- 1 byte index into the menu pointer table identifying which menu to show when the arrow in the top border is selected
Note: There is no dedicated end token for menu text; the game keeps printing data until the menu space (width x height as modified by line spacing) has been completely filled! |
Disassembly
Internal Data for Dragon Warrior II
| |
---|---|