Dragon Warrior II (NES)/ROM map: Difference between revisions

From Data Crystal
Jump to navigation Jump to search
No edit summary
m (simplified template declarations)
 
(5 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{rommap|game=Dragon Warrior II}}
{{rommap}}


== Dragon Quest ==
==Dragon Quest II==
<pre>
<pre>
* 0x02D9B to 0x????? = font, 1BPP.
* 0x02D9B to 0x????? = font, 1BPP.
Line 11: Line 11:
</pre>
</pre>


==Dragon Warrior==
==Dragon Warrior II==
===Overview===
  * 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 53: 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===
Line 67: Line 208:
{{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!}}
{{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===
[[Dragon_Warrior_II::ROM_map/ASM|Commented Disassembly]]


===Monster Name Pluralization Rules===
{{Internal Data}}
; pluralize monster name
;
; starts reading the monster name backwards from the end of the string and applies the first applicable transformation
; -ch    -> -ches
; -dead  -> -dead (i.e. no change)
; -f      -> -ves (but no monster has a name that ends in f, so this rule is never used)
; -i      -> -ies
; -Man    -> -Men
; -man    -> -men
; -Mouse  -> -Mice
; -mouse  -> -mice
; -ngo    -> -ngo (i.e. no change)
; -rus    -> -rii
; -s      -> -ses
; -sh    -> -shes
; -y      -> -ies
; -      -> -s (everything else)
;
; IN:
; A/X/Y/C: irrelevant, they all get potentially clobbered
; $6119-????: singular monster name terminated by [end-FA]
; OUT:
; A/X/Y: unreliable
; C: set
; indirect control flow target
; from $02:$BE2F via $8004
; call to code in a different bank
0x01C801|$07:$87F1:20 97 FE JSR $FE97 ; read next byte, parse it for bank and pointer index, execute ($8000,X) in selected bank, swap back in original bank
; code -> data
; indirect data load target
0x01C804|$07:$87F4:4B ; i.e. $02:$8016, a.k.a. copy $6119,X to $60F1,X until we read a #$FA
; at this point, X points to next byte in monster name stored starting at $60F1, i.e. the byte after the end token
; data -> code
0x01C805|$07:$87F5:A4 8F  LDY $8F ; number of monsters in the current group
0x01C807|$07:$87F7:88      DEY
0x01C808|$07:$87F8:F0 36  BEQ $8830 ; if only 1 monster, then no need to pluralize, so we're done
0x01C80A|$07:$87FA:CA      DEX ; back up to [end-FA]
0x01C80B|$07:$87FB:CA      DEX ; back up to final letter of monster name
0x01C80C|$07:$87FC:BD F1 60 LDA $60F1,X ; read final letter of monster name
0x01C80F|$07:$87FF:C9 18  CMP #$18 ; "o"
0x01C811|$07:$8801:F0 32  BEQ $8835 ; -ngo -> -ngo, -o -> -os
0x01C813|$07:$8803:C9 0F  CMP #$0F ; "f"
0x01C815|$07:$8805:F0 5E  BEQ $8865 ; -f -> -ves (not used)
0x01C817|$07:$8807:C9 22  CMP #$22 ; "y"
0x01C819|$07:$8809:F0 5F  BEQ $886A ; -y -> -ies
0x01C81B|$07:$880B:C9 12  CMP #$12 ; "i"
0x01C81D|$07:$880D:F0 5B  BEQ $886A ; -i -> -ies
0x01C81F|$07:$880F:C9 1C  CMP #$1C ; "s"
0x01C821|$07:$8811:F0 32  BEQ $8845 ; -rus -> -rii, -s -> -ses
0x01C823|$07:$8813:C9 11  CMP #$11 ; "h"
0x01C825|$07:$8815:F0 5B  BEQ $8872 ; -ch -> -ches, -sh -> -shes, -h -> -hs
0x01C827|$07:$8817:C9 17  CMP #$17 ; "n"
0x01C829|$07:$8819:F0 64  BEQ $887F ; -man -> -men, -Man -> -Men, -n -> -ns
0x01C82B|$07:$881B:C9 0E  CMP #$0E ; "e"
0x01C82D|$07:$881D:F0 79  BEQ $8898 ; -mouse -> -mice, -Mouse -> -Mice, -e -> es
0x01C82F|$07:$881F:C9 0D  CMP #$0D ; "d"
0x01C831|$07:$8821:F0 0F  BEQ $8832 ; -dead -> -dead, -d -> -ds
; control flow target (from $883A, $8841, $8863, $8884, $888F, $889D, $88E1)
; append "s" to monster name
; default pluralization if not handled above
0x01C833|$07:$8823:E8      INX
0x01C834|$07:$8824:A9 1C  LDA #$1C ; "s"
0x01C836|$07:$8826:9D F1 60 STA $60F1,X ; append "s" to monster name
0x01C839|$07:$8829:E8      INX
0x01C83A|$07:$882A:A9 FA  LDA #$FA ; [end-FA]
0x01C83C|$07:$882C:9D F1 60 STA $60F1,X ; append [end-FA] to monster name
0x01C83F|$07:$882F:E8      INX
; control flow target (from $87F8, $8843)
0x01C840|$07:$8830:38      SEC
0x01C841|$07:$8831:60      RTS
; control flow target (from $8821)
; jump to -d pluralization handler: -dead -> -dead, -d -> -ds
0x01C842|$07:$8832:4C CC 88 JMP $88CC
; control flow target (from $8801)
; -o pluralization handler: -ngo -> -ngo, -o -> -os
0x01C845|$07:$8835:BD F0 60 LDA $60F0,X ; read second-last letter of monster name
0x01C848|$07:$8838:C9 10  CMP #$10 ; "g"
0x01C84A|$07:$883A:D0 E7  BNE $8823 ; if not -go, append "s"
0x01C84C|$07:$883C:BD EF 60 LDA $60EF,X ; read third-last letter of monster name
0x01C84F|$07:$883F:C9 17  CMP #$17 ; "n"
0x01C851|$07:$8841:D0 E0  BNE $8823 ; if not -ngo, append "s"
0x01C853|$07:$8843:F0 EB  BEQ $8830 ; if -ngo, plural = singular
; control flow target (from $8811)
; -s pluralization handler: -rus -> -rii, -s -> -ses
0x01C855|$07:$8845:BD F0 60 LDA $60F0,X ; read second-last letter of monster name
0x01C858|$07:$8848:C9 1E  CMP #$1E ; "u"
0x01C85A|$07:$884A:D0 11  BNE $885D ; if not -us, append "es"
0x01C85C|$07:$884C:BD EF 60 LDA $60EF,X ; read third-last letter of monster name
0x01C85F|$07:$884F:C9 1B  CMP #$1B ; "r"
0x01C861|$07:$8851:D0 0A  BNE $885D ; if not -rus, append "es"
0x01C863|$07:$8853:A9 12  LDA #$12 ; "i"
0x01C865|$07:$8855:9D F0 60 STA $60F0,X ; replace -us with -ii
0x01C868|$07:$8858:9D F1 60 STA $60F1,X
0x01C86B|$07:$885B:38      SEC
0x01C86C|$07:$885C:60      RTS
; control flow target (from $884A, $8851, $886F)
; append "es" to monster name
0x01C86D|$07:$885D:E8      INX
0x01C86E|$07:$885E:A9 0E  LDA #$0E ; "e"
0x01C870|$07:$8860:9D F1 60 STA $60F1,X ; append "e" to monster name
0x01C873|$07:$8863:D0 BE  BNE $8823 ; append "s" to monster name; note that this branch is always taken
; control flow target (from $8805)
; unused code
; -f pluralization handler: -f -> -ves
0x01C875|$07:$8865:A9 1F  LDA #$1F ; "v"
0x01C877|$07:$8867:4C 6C 88 JMP $886C ; replace "f" with "v" then append "es"
; control flow target (from $8809, $880D)
; -i pluralization handler: -i -> -ies
0x01C87A|$07:$886A:A9 12  LDA #$12 ; "i"
; unused control flow target (from $8867)
0x01C87C|$07:$886C:9D F1 60 STA $60F1,X ; replace final letter with "i"
0x01C87F|$07:$886F:4C 5D 88 JMP $885D ; append "es"
; control flow target (from $8815)
; -h pluralization handler: -ch -> -ches, -sh -> -shes, -h -> -hs
0x01C882|$07:$8872:BD F0 60 ; LDA $60F0,X ; read second-last letter of monster name
0x01C885|$07:$8875:C9 0C  ; CMP #$0C ; "c"
0x01C887|$07:$8877:F0 E4  ; BEQ $885D ; if -ch, append "es"
0x01C889|$07:$8879:C9 1C  ; CMP #$1C ; "s"
0x01C88B|$07:$887B:F0 E0  ; BEQ $885D ; if -sh, append "es"
0x01C88D|$07:$887D:D0 A4  ; BNE $8823 ; else, append "s"
; control flow target (from $8819)
; -n pluralization handler: -man -> -men, -Man -> -Men, -n -> -ns
0x01C88F|$07:$887F:BD F0 60 LDA $60F0,X ; read second-last letter of monster name
0x01C892|$07:$8882:C9 0A  CMP #$0A ; "a"
0x01C894|$07:$8884:D0 9D  BNE $8823 ; if not -an, append "s"
0x01C896|$07:$8886:BD EF 60 LDA $60EF,X ; read third-last letter of monster name
0x01C899|$07:$8889:C9 16  CMP #$16 ; "m"
0x01C89B|$07:$888B:F0 04  BEQ $8891 ; -man -> -men
0x01C89D|$07:$888D:C9 30  CMP #$30 ; "M"
0x01C89F|$07:$888F:D0 92  BNE $8823 ; if not -Man, append "s"
; control flow target (from $888B)
0x01C8A1|$07:$8891:A9 0E  LDA #$0E ; "e"
0x01C8A3|$07:$8893:9D F0 60 STA $60F0,X ; replace second-last letter of monster name
; control flow target (from $88DF)
0x01C8A6|$07:$8896:38      SEC
0x01C8A7|$07:$8897:60      RTS
; control flow target (from $881D)
; -e pluralization handler: -mouse -> -mice, -Mouse -> -Mice, -e -> es
0x01C8A8|$07:$8898:BD F0 60 LDA $60F0,X ; read second-last letter of monster name
0x01C8AB|$07:$889B:C9 1C  CMP #$1C ; "s"
0x01C8AD|$07:$889D:D0 84  BNE $8823 ; if not -se, append "s"
0x01C8AF|$07:$889F:BD EF 60 LDA $60EF,X ; read third-last letter of monster name
0x01C8B2|$07:$88A2:C9 1E  CMP #$1E ; "u"
0x01C8B4|$07:$88A4:D0 3B  BNE $88E1 ; if not -use, append "s"
0x01C8B6|$07:$88A6:BD EE 60 LDA $60EE,X ; read fourth-last letter of monster name
0x01C8B9|$07:$88A9:C9 18  CMP #$18 ; "o"
0x01C8BB|$07:$88AB:D0 34  BNE $88E1 ; if not -ouse, append "s"
0x01C8BD|$07:$88AD:BD ED 60 LDA $60ED,X ; read fifth-last letter of monster name
0x01C8C0|$07:$88B0:C9 16  CMP #$16 ; "m"
0x01C8C2|$07:$88B2:F0 04  BEQ $88B8 ; -mouse -> -mice
0x01C8C4|$07:$88B4:C9 30  CMP #$30 ; "M"
0x01C8C6|$07:$88B6:D0 29  BNE $88E1 ; if not -Mouse, append "s"
; control flow target (from $88B2)
0x01C8C8|$07:$88B8:A0 00  LDY #$00 ; replace last 4 letters of monster name with "ice" + [end-FA]
; control flow target (from $88C4)
0x01C8CA|$07:$88BA:B9 C8 88 LDA $88C8,Y
0x01C8CD|$07:$88BD:9D EE 60 STA $60EE,X
0x01C8D0|$07:$88C0:E8      INX
0x01C8D1|$07:$88C1:C8      INY
0x01C8D2|$07:$88C2:C0 04  CPY #$04
0x01C8D4|$07:$88C4:90 F4  BCC $88BA
0x01C8D6|$07:$88C6:38      SEC
0x01C8D7|$07:$88C7:60      RTS
; code -> data
; data load target (from $88BA)
0x01C8D8|$07:$88C8:12 ; "i"
0x01C8D9|$07:$88C9:0C ; "c"
0x01C8DA|$07:$88CA:0E ; "e"
0x01C8DB|$07:$88CB:FA ; [end-FA]
; data -> code
; control flow target (from $8832)
; -d pluralization handler: -dead -> -dead, -d -> ds
0x01C8DC|$07:$88CC:BD F0 60 LDA $60F0,X ; read second-last letter of monster name
0x01C8DF|$07:$88CF:C9 0A  CMP #$0A ; "a"
0x01C8E1|$07:$88D1:D0 0E  BNE $88E1 ; if not -ad, append "s"
0x01C8E3|$07:$88D3:BD EF 60 LDA $60EF,X ; read third-last letter of monster name
0x01C8E6|$07:$88D6:C9 0E  CMP #$0E ; "e"
0x01C8E8|$07:$88D8:D0 07  BNE $88E1 ; if not -ead, append "s"
0x01C8EA|$07:$88DA:BD EE 60 LDA $60EE,X ; read fourth-last letter of monster name
0x01C8ED|$07:$88DD:C9 0D  CMP #$0D ; "d"
0x01C8EF|$07:$88DF:F0 B5  BEQ $8896 ; if -dead, plural = singular
; control flow target (from $88A4, $88AB, $88B6, $88D1, $88D8)
0x01C8F1|$07:$88E1:4C 23 88 JMP $8823 ; else, append "s"
 
{{Internal Data|game=Dragon Warrior II}}

Latest revision as of 05:01, 18 April 2024

Chip tiny.png 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:

  1. The first phase sequentially executes a list of building instructions that place the base tiles in their desired positions.
  2. 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.
  3. 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 for template.png
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

Commented Disassembly