FF6 Hacking
Example Menu Layout Editing - Printable Version

+- FF6 Hacking (https://www.ff6hacking.com/forums)
+-- Forum: Discussion Forums (https://www.ff6hacking.com/forums/forum-5.html)
+--- Forum: Magitek Research Facility (https://www.ff6hacking.com/forums/forum-9.html)
+--- Thread: Example Menu Layout Editing (/thread-4457.html)



Example Menu Layout Editing - Fast Moon - 10-23-2024

I've been messing with some menu layout editing and wanted to share my experience for those who may be looking to do the same.

Goal of this example:
I wanted to rearrange the character info box in the Skills menu to make room to expand the Esper name from 8 characters to 10, as well as add room for a second 10-letter item underneath it (adding this item is out of scope for this example, we're just making space for it).

By default, the character info box is arranged like this:
[Image: 9gF6JX9.png]

The "LV" and "HP" rows are blocking anything longer than 8 characters from occupying the space to the left of it.  But it looks like there's a whole empty row at the bottom, so why not shift everything down one row, and swap the status icon display and the "LV" display?  The end goal is to make the menu look like this:
[Image: 07j9qhy.png]

Now there's lots of space for a longer Esper name, and space below it for another string of similar length.

Method

First, I went to find the coordinates of the LV/HP/MP labels.  The coordinates of the static row labels and the variable current/max values are in two separate places.  The blue label values and the "/" characters have their coordinates defined at C3/5CC2, followed by the tilemap indices of the text.  For example:

Code:
C3/5CC2:    2D42 8B9500                    ; LV

shows that the text for "LV" is at the tilemap position $422D, and the text is comprised of the tiles $8B and $95 ($00 to terminate string).  $422D is not an X/Y coordinate, but rather a position in the tile map.  Check the Menu RAM page to see the addresses of each layer.  Each layer contains four 32x32 quadrants to allow for scrolling if needed.  From the Menu RAM definition, we can see that $422D would be in the BG1, top right quadrant, whose map starts at $4049.  Each entry in the map is 2 bytes, so ($422D-$4049)/2 = $F2 (242), so this is tile position 242.  There's 32 tiles per row, so 242/32 = 7.5625, so this coordinate is row 7, column (0.5625*32) = 18.

If we open the tilemap viewer in Mesen and check the upper right quadrant of Layer 1, hey, there's our "LV" label at row 7, column 18 (0-based).
[Image: VpYqXL9.jpeg]

You see that the menus generally want a blank row in between rows of text in their tile maps (we'll see later why), so to move a line of text down two full tile rows, you'll need to add 32 tiles per row times 2 rows times 2 bytes per tilemap entry = 128 ($80).  I also want to move the "LV" label to the same column as the Esper name, but the same row as the "MP" entry to free up space at the top.  This makes my C3/5CC2 table now look like:

Code:
C3/5CC2:    9D43 8B9500                    ; LV
C3/5CC7:    2D43 878F00                    ; HP
C3/5CCC:    AD43 8C8F00                    ; MP
C3/5CD1:    3B43 C000                      ; /
C3/5CD5:    BB43 C000                      ; /

But that's just the static labels.  We also need to move the coordinates of their corresponding values, which are found at C3/4F12.  These work the same way, so their new values to align with the new positions of their labels are:

Code:
C3/4F12:    A343        ; Level
C3/4F14:    3343        ; HP
C3/4F16:    AD43        ; Max HP
C3/4F18:    B343        ; MP
C3/4F1A:    BD43        ; Max MP

Finally, I want to move the list of status ailments up to where the "LV" entry used to be, but shifted farther to the right.  This isn't a tilemap entry, but a sprite, so its coordinates aren't addressed the same way the tilemap is.  The coordinates for the status icons in the skills menu are set at C3/4EF0, and by default are $4F50.  This actually refers to literal pixel coordinates of $4F (79), $50 (80). Each tile in the tilemap is 8x8 pixels, so it would be approximately at tile position 10,10, which you can see is where it is in the assembled tilemap:
[Image: QLAXT3G.jpeg]

But I want to put it about where the "99" is under "Espers", which is at about row 7, column 22.  So 7*8 = 56 ($38), 22*8 = 176 ($B0).  I needed to shift it a little bit to not be exactly on the tile so that it didn't overlap the window border, so my final value was $36B0.  So, update C3/4EF0 to that:

Code:
C3/4EF0:    A2B036      LDX #$36B0     ; Icon position

All right! Everything's all repositioned!  Let's see how it looks!
[Image: lWYgpa8.png]

... Wait, that's not right.  Sure, the text and icons are mostly where I wanted them, but what's with that weird artifacting at the bottom of the window?

Turns out there's actually another component to drawing the window: V-shift.  You remember when we looked at the raw tilemap, there was a full line of empty space between each line of text, but you can see that's not the case in the final menu display.  And you can see if you look at the raw tilemap of the updated positions, they still seem to look okay:
[Image: kblYnv2.jpeg]

This is where we need to look at the V-shift table for the Skills menu, which starts at C3/4E7F.

Code:
C3/4E7F:    3F 0000     ; LV
C3/4E82:    0C 0400     ; HP
C3/4E85:    0C 0800     ; MP
C3/4E88:    0A 0C00     ; Nothing
C3/4E8B:    01 0C00     ; Nothing
C3/4E8E:    0D 0800     ; Nothing
C3/4E91:    04 94FF     ; Ability row A

What this table does is iterate through each row of pixels on the drawn screen, and tell it which offset pixel row in the tilemap to draw.  This allows for it to skip over some rows of pixels in the tilemap to condense some empty space.  The map above is telling the screen to do the following:

Starting at row 0, for the next $3F (63) rows of the display, draw the pixel row from the tilemap that is $0000 rows offset from that.  So, for display row 0, draw tilemap row 0, for display row 1, draw tilemap row 1 ... for display row 63, draw tilemap row 63.  Remember, the tiles on the tilemap are 8 pixels tall, so this corresponds to drawing tile rows 0-7 (up until the row where the Esper name text is) as-is.

But next it says, for the next $0C (12) rows of the display, draw the pixel row from the tilemap that is $0004 rows offset from that.  So for display row 64, draw tilemap row 68.  For display row 65, draw tilemap row 69 ... for display row 75, draw tilemap row 79.  This effectively means that the display drawing skips the first 4 rows of pixels in the blank row between the first two rows of text, and only draws the last 4 rows of that row, then all 8 pixels of the next row, eliminating 4 rows of blank space between them.

Then again, for the next $0C (12) rows of the display, draw the pixel row from the tilemap that is $0008 rows offset from that.  For display row 76, draw tilemap row 88 ... for display row 87, draw tilemap row 95.  This just condenses the next blank line to 4 pixels instead of 8 and moves the next line up accordingly.

Next, corresponding to our new 4th row of text, for the next $0A (10) rows of the display, draw the pixel row from the tilemap that is $000C rows offset from that.  For display row 88, draw tilemap row 100 ... for display row 97, draw tilemap row 109.

But, hang on.  The new 4th row of text starts at pixel row 104 in the tilemap, so if we're only drawing to 109, we're only drawing 6 of the 8 rows of pixels of that text.

Then it says for the next 1 row, also draw at an offset of $000C, so display row 98 draws tilemap row 110.

Then it says for the next $0D (13) rows, draw at an offset of $0008.  So display row 99 draws tilemap row 107, row 100 draws 108...

Wait, we already drew these (our 4th row of text covers tilemap pixel rows 104-111).

So, we need to fix the V-shift data to first cover our entire 4th row of text instead of only 6 pixels, and then adjust the blank rows below it to not redraw what we already have.  The other two text rows are 12 pixels high, so let's change that $0A to $0C at C3/4E88 to make our 4th row's height match the others.
[Image: x8pACg5.png]

Great!  That fixed it!
[Image: v0XD6oH.png]

... Wait.  OH NO I BROKE IT AAAAAHHH!!

So.  Need to keep in mind that by changing the row count from $0A to $0C, that also means that the row pointer of every entry below it has also been shifted ahead by 2.  So now the row pointers of every row below it don't line up anymore.

Thankfully, because the rows in between are blank, we can just adjust the row counts of the remaining two blank rows so that by the time we get to the entry at C3/4E91 which starts the scroll window, the total row counter at that point is the same as what it would have been before.  $3F + $0C + $0C + $0A + $01 + $0D = $6F (111), so we just need all of our adjusted row count values to add up to the same.

I ended up adjusting the values to the following, but there are multiple combinations that work:

Code:
C3/4E7F:    3F 0000     ; LV
C3/4E82:    0C 0400     ; HP
C3/4E85:    0C 0800     ; MP
C3/4E88:    0C 0C00     ; Nothing
C3/4E8B:    04 0C00     ; Nothing
C3/4E8E:    08 0800     ; Nothing
C3/4E91:    04 94FF     ; Ability row A

Now the screen looks like this, no artifacting, and the scroll window at the bottom remains as it should.
[Image: 07j9qhy.png]

Hope this was helpful for people who want to try messing with the menu window formatting!