Pointers

Required:

Files:

In this tutorial:

Introduction

If you've already gotten yourself through the required chapters, then you've probably attemted a hack/translation or two by yourself (if not, its no big deal, but from here on you might want to have some experience unless you're a quick learner). One thing that becomes fairly obvious not too soon after you start poking around with text, is that limited space makes for sad panda.

I have already stated in previous chapters that when editing text, you'll be limited to the amount of space already present in the rom (assigned to store said text). There's a number of solutions to this problem, but since you probably won't be able to make your own ASM-hacks or fiddle with decompression for a while, Pointers will be your only ally for now (and a powerfull ally it is...).

When it comes to pointers, there's a lot to tell, but little to show. The entire chapter will therefore be theoretical, all the way up until the section containing the FF3 example. Unlike previous chapters, everything from here on out is subject to vary between different titles and formats. The bottom line is, that some games store pointers in very different ways, while others follows the basic patterns (FF3 being one of them).

The Basics of Pointers

What is a pointer?

  • A4D2
  • 08C9F0AA

That's a pointer. Two of them, to be precise. A pointer is simply a string of hex. This string is in itself an adress, "pointing" to a specific offset (you know what that is, don't you?) in the rom. Hence the name Pointer.

Ok, so the pointer is actually an adress to a specific offset. Who needs that adress? To put it simple, it is the game in question that relies on theese to find the correct data to output. When Mario falls into the flaming pits of lava found in various castles, hence dying a painful death, the game itself determines that it's time to display the "GAME OVER"-text once you've run out of extra lives. Problem is, that it has no knowledge whatsoever as to the exact location of this particular line. To find it, it consults the pointer (this, it knows where to find), and checks the given adress to find the correct offset.

Note that the pointer in this case (and practically every other case) doesn't point to the entire string "GAME OVER". It only points to "G" (there can only be one hexdecimal per offset, you know), whereas the game then continues to read the hexdecimals following the given offset, until they reach the end of the paragraph. The end is usually marked by using a control code of some sort, although there can be exeptions.

Now we know what a pointer does, but what good is this to us?

---

No matter how much you edit text, the pointers still remain the same (unless they're located inside the text itself, but that's another story). Suppose we have the two following sentances written next to each other:

*Friends make me laugh*Hello

(* = Pointer, pointing to the letter that comes next)

  • Friends make me laugh
  • Hello

What if we wanted to edit "Hello?" into, say "Sayonara"? To do so, we would need to borrow some space from the previous line (let's pretend that these lines are the only two available in the entire rom). Perhaps something like this:

Friends make me laSayonara
(*Friends make me laSay*onara)

As you can see, the pointer to "Hello" still remains at the same place. The output would therefore look like this:

  • Friends make me laSay
  • onara

By locating the pointer, we would thus be able to repoint it to a different offset, in this case the adress where "S" is written at:

*Friends make me la*Sayonara

  • Friends make me la
  • Sayonara

---

Pointers won't give us any extra space to use. What they do, is to allow us to utilize the given space as effectively as possible. (Most people who attempts translations without pointers usually ends up with a little bit of blank space at the end of each piece of dialogue. Using pointers, that space can be relocated and used to better fit text that otherwise wouldn't fit, given the limited space of the original sentance.)

Let's take one more example before we move on. The japanese word for "yes" is "hai", and no is "iie". These are usually typed out using kana, like this ([]=one character, or one hexdecimal):

---

*[ha][i]*[i][i][e]

If you translate directly, it looks like this:

*[y][e]*[s][n][o]

Thus you get "ye" and "sno" in the game. But repoint the pointers like this, and the problem is solved:

*[y][e][s]*[n][o]

---

By now, you should have comprehended the following:

  • A Pointer is a string of hex
  • Said string points to a specific offset in a rom
  • You can use Pointers in order to better make use of the limited space often found in a rom
  • If you don't, limited space makes you sad panda (repeated for great truth)

Calculating Pointers

Note: Our FF3-example will refer to this chapter as much as possible, to make sure you understand everything. Thus, it isn't required that you grasp this entire section before moving on, but make sure you've read through it at least once.

Before we move on to editing FF3, we'll first go through some basics when it comes to calculating a Pointer.

Most pointers that you'll come across are 2 bytes in size. Meaning they consist of a pair of hexadecimal numbers (00 00 -> FF FF). Now, you may wonder how such a pair can be used to point to an offset like "0D0200". After all, those two numbers (XX XX) should only be able to refer to a part of the adress (0200 or 0D02), right? That's right.

Because most pointers are so small in size, they can only point to a very limited space of the rom. This, however, only holds true for older systems like Nes, Snes and Megadrive. GBA and Nintendo 64 (to take an example) often uses 4 byte pointers (00000000 -> FFFFFFFF), and because of that, you can basically point them anywhere you like.

But for now, let's stick to 2 byte pointers, since you will come across them more then often. For the sake of simplicity, we'll stick to our example offset above (0D0200). Now, a game that wishes to point at this offset, obviously can't do this by containing the entire offset in a pointer (0D 02 00 is 3 bytes, see?). This can be solved, by making 0D0000 a standard offset, so that the pointers can fill out the last 2 bytes.

  • 0D[XXXX] (XXXX = Our pointer, from 0000 to FFFF)

This way, we can use pointers to point somewhere between 0D[0000] and 0D[FFFF]. But what if we wanted to point to the offset 0A[XXXX]? Is it possible to do this with the same set of pointers that point to 0D[XXXX]? No, not unless you repoint the entire pointertable to 0A instead of 0D. But by doing so, all your pointers pointing to 0D will now point to 0A.

*** TERMINOLOGY ALERT! ***

What is a pointer table? In many roms, pointers are stored/clumped together at the same part of the rom, in what is usually referred to as a "pointer table". In other words, a pointer table simply refers to a number of pointers that all point to the same range of offsets (somewhere between 0000 and FFFF in this case), and because of that have been tucked together for simplicitys sake. Just like text usually is stored at the same place, so are pointers. Nothing complicated.

So, what happens if you have more data to point to than you can fit between 0D0000 and 0DFFFF? The answer is, you'll simply have to use more pointer tables.

By adding another table you could, for example, make it point to data between 0E0000 and 0EFFFF. You wouldn't be able to use these pointers in order to refer to data between 0D0000 and 0DFFFF, but that's your only limit.

For the record, you won't be able to actually add new pointers. But many (many) roms uses a different set of pointers for dialogue, menues, items, names etc. Because 2 byte pointers are so small in size (and have such a limited range), they're usually located somewhere near the data they point to. Very often, you'll find them right above (or under) the data you're hacking.

---

One last thing you need to know, is the formula used to actually calculate these offsets. It varies between every format (and sometimes between games), and this is how you do (this assumes that you have found the offset of the data that the pointer, the one you're trying to localize, points at):

Note: Back before emulators existed, every rom needed a header in order to run in backup machines (who were the only way to run them). A "header" is a fixed amount of code that exists at the beginning of the rom ( for example, snes rom headers are 200 bytes in size; Nes headers are 10 bytes). Some roms still have these headers, others do not. What's important, is that a rom with a header has all of its data pushed ahead in the rom. Data at offset 000000 in a snes rom without header is located at 000200 in a header-equiped rom. The actual code in the roms do not take this into consideration though (how could they, they weren't meant to be run as backups after all), so you'll have to subtract the header when calculating offsets.

Snes

  1. Take the offset of the data (Ex: 0D05B2)
  2. Take the 4 last digits of the offset (05B2)
  3. Subtract 200 bytes if the rom has a header (05B2 - 200 = 03B2)
  4. Break the number apart (03 B2)
  5. Switch places (B2 03)
  6. B203 is your pointer.

Nes

  1. Take the offset of the data (Ex: 0D05B2. Maybe it's a very large rom ^_^)
  2. Take the 4 last digits of the offset (05B2)
  3. Subtract 10 bytes if the rom has a header (05B2 - 10 = 05A2)
  4. Break the number apart (05 A2)
  5. Switch places (A2 05)
  6. A205 is your pointer

GBA (1)

  1. Take the offset of the data (Ex: 0D05B2)
  2. Add 08000000 (0D05B2 + 08000000 = 080D05B2)
  3. 080D05B2 is your pointer

GBA (2)

Sometimes a rom might store its pointers backwards (because of little endianess).

  1. Break your pointer apart (08 0D 05 B2)
  2. Type it backwards (B2 05 0D 08)
  3. B2050D08 is your pointer

Gameboy/GBC

  1. Take the offset of the data (Ex: 0D05B2)
  2. Take the 4 last digits of the offset (05B2)
  3. Here's something new. If the number (05B2) is between...
    • 0000 -> 3FFF, you add 4000
    • 4000 -> 7FFF, you do nothing
    • 8000 -> BFFF, subtract 4000
    • C000 -> FFFF, subtract 8000
  4. Now we have 45B2 (since 05B2 is between 0000 and 3FFF)
  5. Break it apart (45 B2)
  6. Switch places (B2 45)
  7. B245 is your pointer

Editing Pointers

Time to do some actual editing. Everything will be step by step, so don't worry if you haven't grasped everything mentioned above.

Because text (we'll be working with text-pointers in FF3) and pointers are stored in different places inside the rom, we'll open Windhex twice, loading the same rom into both programs. Windhex1 will be used to display pointers, and Windhex2 will keep an eye on the text that said pointers point to. Both can be done using only one copy of Windhex, but this way we won't have to scroll up and down between the pointers and text.

Note that since we're loading the same rom into both editors, we will only save using Windhex1. If we don't, Windhex2 will overwrite data, since the rom isn't reloaded into it every time an external program performs a save.

Every process involving the editing of data, first starts with locaing the data you want to edit. Step by step, it will look like this:

  1. Locate the text who's pointers you want to find.
  2. Take the offset of said text and calculate its pointer according the formulas mentioned in the last section
  3. Search for the pointer
  4. Edit it to see if you've found the correct one

Start by loading up your copy of FF3 in Windhex (twice). Load the tablefile into Windhex1 and 2. Open your rom in Snes9x (or whatever emulator you're using) and play until you reach this point in the game:


A few minutes into the game

As soon as Terra and C:O reaches Narshe, create a Savestate just as they enter the city (i.e, just after the credits have stopped rolling). Make sure that you create it BEFORE the text above is even loaded on screen.

This is the line of dialogue we'll be working with from here on. So far, we can't locate the pointer, but we can find the text. Unfortunately, FF3 uses a light text-compression called DTE, which makes text a hassle to search for. At this point, all you normally have to do is to perform a simple text-search like you did in the text chapter (and when you've found the text, all you have to do is to check the offset it is located at), but for now, I'll just give you the right offset.

In Windhex2, go to offset "0D04EB" (Ctrl+G). As you can see (if you scroll up from there), FF3's main text starts at 0D0200, the same offset used as an example in the previous section. This isn't because Snes games usually stores text at this offset or anything, I just wanted to make the rest of this tutorial easy to follow, in case you want to go back for some repetition.

Anyway, the dialogue we're using starts at 0D04EB. Since pointers only point to one offset (and not to the whole text), it would seem reasonable to assume that our pointer in this case points to "W" in "WEDGE". The game can't read data (in this case text) backwards from the pointer, so anything left behind it gets ignored. At this point, any assumptions regarding where the pointer is, how it works and where it points, is pure speculation. But we have to start somewhere, so we will make the following assumptions:

  1. The game uses regular snes pointers, calculated in the same manner as in the last section.
  2. The pointer we're searching for points at "W" in "WEDGE", i.e to 0D04EB.
  3. The game is using 2 byte pointers.
  4. The pointers are stored in a pointer table, as opposed to being spread throughout the rom.
  5. Said table is located somewhere near the textbank we're working in

---

For the record, our bank goes from 0D0200 to 0E01FF. In the original game, it went from 0D[0000] to 0D[FFFF], but since most dumped Snes rom has a header of 200 bytes added in the beginning of the rom, every offset get pushed forward 200 bytes/hex (and for this reason, we subtract the header whenever we calculate pointers, since they retain their original values no matter the size of the header is).

---

We know we're dealing with Snes pointers, FF3 being a Snes game and all. We have the offset of the text we want to check. Now it's time to do some math, in order to find the value of the pointer (and only the value. We still don't know where to find it, but it's a start):

  1. Take the last 4 digits if the offset (0D04EB -> 04EB)
  2. Subtract 200 (04EB - 200 = 02EB)
  3. Break apart (02 EB)
  4. Switch places (EB 02)
  5. EB02 is our pointer.

Now, given that a pointer pointing to 0D04EB actually exists in this rom, it should have the value EB02.

Before we move on, try doing a hex-search (Ctrl+H) for "EB02". If you did it right, you should end up with about 50 different search-results. If you think about it, given how many hexadecimals this rom consists of, it would be very likely that several combinations of "EB" and "02" would exist, even if they aren't all pointers. Now, you have a couple of options, given how much free time you have on your hands:

---

1)

This is the hard way, and should be considered a last resort. Do the search above, and for every result you get, edit the supposed pointer, and load the rom again to see if any changes accured in the text. If it didn't, go to the next result and try again. Rinse and repeat. Remember that you might be wrong in your assumptions. If you've calculated the pointer in the wrong way, you'll just waste your time since there's no chance of finding the right pointer.

2)

Go to the offset you've located the text on, and use a hexeditor that can perform searches upwards in the rom (Windhex can only search downwards, but Hex Workshop has this function). IF the pointer is located just above the text-bank, it should be the first result when you search for it. If not, continue like in option 1, only upwards this time.

3)

If you know how to spot a pointer-table by eye (later in this chapter, in case you're curious), simply check the premises around the text-bank for a set of pointers, then edit them to see if the text in question screws up.

4)

This is the method we'll stick with for now. Remember the basics of Relative Searching? The longer string of hex, the lesser are your chances of receiving multiple results. We can agree on the fact that "EB02" isn't very specific, but how can we possible make any more so? It's not like we can look for a better pointer, since all of them are the same in size (2 bytes).

This is where we make use of assumption 4 (see above): The pointers are stored in a pointer table, as opposed to being spread throughout the rom. Now, if they are tucked together, that would mean that they're stored in a specific order, yes? Indeed.

In fact, pointers are often (very often) stored in the same order as the text they're pointing to. This doesn't have to be the case, but it would make it easy on the programmers this way, and there really isn't any reason to input them completely random, is there?

Let's call our text (the one in the picture) T1. Our pointer pointing to T1 is called P1.

Open Windhex2 and ceck the text that comes after T1 in the rom (WEDGE: The Esper's gotta be in here.). Let's call it T2.

Now, if T2 comes after T1, that would mean that P2 might come after P1, right? So somewhere in the rom, we have P1P2. Take the offset of T2 and calculate its pointer using the snes-formula. The text begins at D051B, and the pointer in question is 1B03 (Highlight for the correct answer).

Now, do a hex-search (Ctrl+H) for "EB021B03" (i.e search for P1P2) from the beginning of your rom (Windhex1). You will only get 1 result, and it will be located at 0CE818 (unless you're using the wrong rom). And now? Well, now you're done locating what might be a pointer (actually, you searched for for both P1 and P2, so you might have found 2 pointers). If you recieve multiple results (in other games), you'll still get a lot less then when you search for a single 2-byte pointer, so you can do a check on all results if you like.

---

FINALLY. Time to edit a pointer. You have located what might be one at offset 0CE818, and now you have to edit it in order to check if you really did find a pointer. For now, you can ignore P2 (1B03). Instead, make sure hex/text-edit mode is not checked.

Then, edit EB02 to EC02. This way, the pointer is moved one step ahead, from "W" in "WEDGE" to "E". When you're done, save your rom and load it up in Snes9x. Use the savestate to skip the intro, and play until the dialogue comes up on screen. WEDGE is now named EDGE. Not because the name actually changed, but because the game now starts reading the text at 0D04EC instead of 0D04EB.


Like a dream come true. Right, Edgie?

Now we know that what we found was actually a pointer (if it hadn't been, our text wouldn't have been changed). It was also the pointer that pointed to the line of text we were searching for. Note that sometimes, several pointers point to the same text. In many RPG-towns, several inhabitants tell you the same cheesy line when you try to talk to them. In order to save space, many programmers insert only one line of text in the rom, and point several pointers to it. Neat.

You can also do the same. Say you have two characters saying two different messages (T1 and T2, pointers P1 and P2). By pointing P2 to T1, both of them will now say the message T1. This might seem irrelevant, but by doing so, you now have some free space since T2 no longer is needed, and can be used to make space for some other message.

To make all of this clear, we will do a complete pointer-swap with another message. Use Windhex2 to select some other message (your choice). In case you want to follow along with the examples below, there's a nice line at 0D08B6 (KEFKA: My sweet little magic user...).

  1. Take the last 4 digits from 0D08B6 (08B6)
  2. Subtract 200 (06B6)
  3. Break apart and switch places (B606, you should know it by now)

In Windhex 1, edit the pointer EC02 (or EB02 if you edited it back) to B606. Save, and check it out in Snes9x:


Sweet.

And that's it. Please note that not everything ahead of a text should be considered pointers. Some games store other data related to text-display there, and if you edit that data, the text will surely not display as normal any longer. Still, that doesn't mean you've found a pointer.

Coming up: How to spot Pointer tables by eye.

A Pointer Eye for the Hacking Guy

All search-methods aside, the fastest way to find a pointer table is to scroll up/down from the text and spot it by eye. Given that it is actually located next to the text, that is.

As i mentioned, in pointer tables the pointers are usually stored in the same order as the text. This means that the offsets they point at will usuallt be located very close to each other (unless the game contains extremely large chunks of dialogue). Let's look at the first pointertable in FF3 starting at 0CE804. These are the first pointers (next to each other), in the same order as in the rom:

00005900A000FF004E017401C4011C01027302B402EB021B033D037103
9C03B903F80314043004 ...

Try and see if you can spot any reoccuring pattern in the line above. If you can't I've colored it red below.

 

 

00 00 59 00 A0 00 FF 00 4E 01 74 01 C4 01 1C 02 73 02 B4 02 EB 02 1B 03 3D 03 71 03 9C 03 B9 03 F8 03 14 04 30 04 ...

The further down the rom your pointers point, the more will the second digit in the pointer increase. In other words, every other pair of hexadecimals in a pointer table will be the same, only to increment once in a while. When you see a big chunk of hexadecimals reading like:

$H = Some random hexadecimal value between 00 and FF.

$H XX $H XX $H XX $H XX $H YY $H YY $H YY $H YY $H ZZ $H ZZ ...

Where XX/YY/ZZ are identical (but sometimes incrementing) values, chances are that you have spotted a Pointer table. Windhex conveniently uses different color for every other row, so you can confirm that this is also the case in FF3. If you scroll down far enough down the table, the "countup" will restart att 00. This is because FF3 has two tables, given the large amount of text.

You can also use this information to search for a pointer-table. Suppose you know that a lot of pointers consists of the value "56$H", then you can do a hex-search for (this method isn't very reliable though):

56**56**56**56**56

** = Wildcard (any value) in Windhex. Must be enabled, or else you'll be searching for the actual "*".

Go to Top

Copyright © 2007 Romhacks.net
Code, Layout and tutorials are Copyright © by Aeris130. Other material, such as programs, are copyright to their respective authors. We do NOT claim copyright regarding the actual information described in the tutorials, as the author didn't play any part in discovering them in the first place.