’Cause all games were better on the GBC

You are not logged in.

#1 2011-05-13 10:14:17

Registered: 2010-10-16
Post 117/366

Repointing data


We'll need:
- a Gameboy(Color) game to hack (here we'll use Pokemon Blue);
- a debugger (BGB works fine);
- a hex editor with a decent search function(I use HexWorkshop);
- to know what a pointer is;
- very basic ASM understandings (registers, common commands like "call" and "ld");

One of the most frequent tasks in a ROM hack is data expansion; since most of the times we won't have a fully disassembled game to deal with, we have to repoint data somewhere else, or in the same bank or in a different bank.

If you don't know about this stuff, you can learn more HERE.

Let's say we are adding monsters to the game and want to expand the table of cries. If our data locations is documented in a ROM map, as it is, we already know its address (maybe I'll write a tutorial to find undocumented data, some other time); it's at $39446, so the pointer to look for is $4654 ($5446 in big-endian).
[Bank number is $0E ( = $39446/$4000), this information will help later.]
Using Hex Workshop's search function we'll get 8 results (none of them in the data's bank, i.e. $38000-$3BFFF range):

All of them are anonymous data (not being part of structured data) except the first one ($13DE), which isn't part of structured data, but is actually part of code. In fact the byte before the pointer is $21, an opcode (or operation command) for "ld hl,HHLL", which means "load a 2-byte value into register hl" (when you find that a value between 4000-7FFF is loaded into register hl you can fairly suspect that it's a pointer that points to some interesting data, like data-tables).
Now, since we have figured out where the code that deals with Cries is located, we can open our debugger to see what that code actually is, and to find the information for the bank switching, since code and data are in two different banks (by the way this condition is great because we are able to move Cries data anywhere in the ROM not limiting inside a certain bank, without big work, since the bankSwitching is already implemented in the original code).

Once we've loaded our ROM in BGB we open "Debug->breakpoint" and type 13dd in the "PC=" textbox (alternatively we could go to (ctrl+G) address 13dd ("ld hl,5446") and double click it). Now the line should be red.
Note: this routine actually starts at $13d9 and ends at $13fb

;a = pokemon index value
ROM0:13d9 3d               dec  a        ;a = a - 1 because first cry index is actually 0
ROM0:13da 4f               ld   c,a
ROM0:13db 06 00            ld   b,00        ;bc = pokemon index value - 1
ROM0:13dd 21 46 54         ld   hl,5446     ;get cries' table starting point
ROM0:13e0 09               add  hl,bc
ROM0:13e1 09               add  hl,bc        ;added 3 times because every
ROM0:13e2 09               add  hl,bc        ;cry info is 3 byte long
ROM0:13e3 3e 0e            ld   a,0e        ;bank where data is
ROM0:13e5 cd bc 35         call 35bc        ;this function switches bank to value in a
ROM0:13e8 2a               ldi  a,(hl)        ;load cry's data
ROM0:13e9 47               ld   b,a        ;b = byte1
ROM0:13ea 2a               ldi  a,(hl)
ROM0:13eb ea f1 c0         ld   (c0f1),a    ;[$c0f1] = byte 2
ROM0:13ee 7e               ld   a,(hl)
ROM0:13ef ea f2 c0         ld   (c0f2),a    ;[$c0f2] = byte 3
ROM0:13f2 cd cd 35         call 35cd        ;restores previous bank
ROM0:13f5 78               ld   a,b
ROM0:13f6 0e 14            ld   c,14
ROM0:13f8 07               rlca
ROM0:13f9 80               add  b
ROM0:13fa 81               add  c        ;a = byte1 * 3 + 14
ROM0:13fb c9               ret

Let's make the game run (press F9 if the game isn't running already). It will break at the titlescreen when you press A (since it's supposed to play the currently viewed pokemon's cry): so it conferms that the address we found locates the routine that plays cries.

Repointing is the act of moving data and update their pointers to the new location of the moved data. Now, once you have placed your data-table in a new location you have to edit the pointer, and the bank info too.
So get your address, calculate the 2-byte pointer + bank value:
pointer = address \ $4000
bank    = address (MOD $4000)

overwrite the pointer at $13de-$13df (remember to write it in little-endian format, i.e. the least significant byte first and the most significant byte secondly), and overwrite the bank value at $13e4.
Well done.

P.S.:remember that you will not always have pointer and data in two different banks so if you want to repoint data to a different bank, you'll have much more work than this to achieve your goal. Also, often data is pointed by more than one single pointer. (an example in Red/Blue is Evolution/Attacks learned that are pointed by four different pointers, therefore there are four different routines that use that data).


Board footer

Powered by FluxBB