Ok, so this thing needs a title, doesn't it. How about: THE REALLY BIG, DEFINITIVE, OVERLY PRETENTIOUS EASY TO READ GUIDE TO NES POINTERS WRITTEN FOR MERE MORTALS Ooops. Better not use pretentious in there, Anus P might not like that. ;) Ok, how about: THE MADHACKER'S GUIDE TO NES POINTERS version 1.1 A reference for rom hackers of all levels (well, below assembly) I'm going to depart a little bit from the norm here just to irritate people. Since I know you all skip the thank you's anyway, I'm gonna put 'em first so you have to go through them to get to the rest of the document. THE REALLY BIG, MAJOR IMPORTANT THANK YOU GOES TO: animefx His simple, brief posting back on February, the first to break that veil of pointers, opened up a world of possibility for me. From that one slight glimpse, everything I learned and am now imparting in this document came. Other big thank you's: Necrosaro- For thingy, I suppose (hey, it's too good), but that's not why I'm thanking you here. Thank you for the help you selflessly try to provide others on demi's board. Likewise, thank you Wildbill for bringing a friendly, human touch to the message board (oh yeah, and that Earthbound Zero thing was pretty cool too). Anus P- Hey, I picked up a few tips and ideas that I never would have had otherwise if it hadn't been for your doc. Thanks for writing it. And thank you Ned, Noize, Reijin, SixMan, DraculaX, and CaTaclysmX (and animefx, but you're already listed above :D)- just for being cool guys to chat with online. Alright, enough of this mushy stuff. I'll start with what you need. FIRST AND FOREMOST YOU NEED TO KNOW HEXADECIMAL. I will not be going over that here, I'm going to automatically assume you know it. Just about every number you're going to find in here will be in hex, so be prepared. And, it's very helpful to be able to do simple hex arithmetic in your head. I'm also going to assume that you understand the basics of romhacking. I'm not going to go over text string replacement or even how to find them. That's been covered enough elsewhere. That's all you need to read this document (well, a computer and something to read it with- but you wouldn't be reading this if you didn't have those). You may find it useful to also have the following so you can try what I'm describing: A hex editor- My personal preference has become Hex Workshop. You're on your own to find the comparable features and terms on your own hex editor. An emulator- No offense fanwen, but NESticle tends to be better suited for what I'm about to describe, so I'm recommending NESticle. Thingy- I only recommend this here because I know many of you won't want to try and find the text strings by hex conversion (you know, the way some of us used to HAVE to do it). You're going to have to know how to anyway, though. :P Patience- Sometimes in spades. It's not easy at times. And even once you've got them figured out, that's no guarantee. A calculator- The hex math isn't difficult, but sometimes your mind just doesn't want to work that way any more. If you don't have a scientific calculator, Windows 95 provides one for you. Just open up calculator. What? Yours doesn't do hex? Sure it does, you just need to change modes to scientific. ROMS- I'm going to refer to several different roms through the course of this document. You probably want to get your hands on them. They are: Musashi (jap), Gryzor (Japanese Contra), Final Fantasy (US), RockBoard (jap). DO NOT E-MAIL ME OR OTHERWISE BOTHER ME ASKING FOR OR WHERE YOU CAN FIND THESE ROMS. WHEN AGGRAVATED I CAN HAVE A VERY SICK AND CRUEL SENSE OF HUMOR. I HAVE THE ISDA NARC PAGE BOOK MARKED (though I've never actually used it). HOW WOULD YOU LIKE TO BE RESPONSIBLE FOR SHUTTING DOWN A ROM SITE? THIS IS THE ONLY WARNING I GIVE. Ok, now, onto the doc. DISCLAIMER: I am in no way affiliated with Nintendo, or any other software company (hell, I don't even work with computers in my career, really). Almost everything I have learned has been through experimentation. I do not know assembly, or even understand anything about the inner workings of an NES (well, not much). Any terms used herein are my own (with only a few exceptions), and I apologize for any inaccuracies in title or otherwise. This guide is intended to make things easier to understand, so I've tried to use names which represent what they mean. Pointer Doc: What are pointers? Pointers actually have nothing to do with text. A pointer is, quite simply, a reference to somewhere else. Anyone who's ever used any kind of basic programming has used a simple pointer. Consider: 10 Print "Pointers are our friends." 20 Goto 10 Line 20 is a pointer. It POINTS to line 10 and says "GO THERE." Choose-Your-Own-Adventure books (anybody remember these). Go to page XX. That's a pointer. Now, these are admittedly very simple pointers, but the fundamental principal behind them are the same. And the beautiful thing is, NES pointers aren't THAT much more complicated than these themselves, only finding them. Uh-huh. So how do I find them? Whoa, slow down. First you need to understand what they are, or else knowing where they are won't do you any good. Go ahead and read further down if you want to, but I take no responsibility for the confusion you WILL cause yourself. Will pointers let me change how the text appears on the screen? No. Pointers have nothing to do with how text is DISPLAYED. That's somewhere and something else completely. I can see the blank space on the screen where I need to write just 1 or 2 more characters, why can't I just use that? Just because you can SEE blank space on the screen doesn't mean that you can USE that blank space. On a Nintendo, what we see as a blank space at the end of a line the NES sees as just somewhere that nothing has been written. Consider: (NOTE: This exercise only works on some programs- like Notepad or Netscape) A sentence. Select the sentence. Go ahead, highlight the entire line with your mouse. Notice how even though you can see blank space all the way to the edge of your screen, when it's highlighted, there's nothing there? That's how it is on the NES. Once it hits what it knows to be the end of the line, that's it. Fortunately, with pointers, we can change where the end of the text is, so we can overcome this barrier. Cool. So, pointers will give me access to unlimited space, right? No, Pointers (on the NES and sometimes on the SNES) do NOT give you unlimited space. Far from it. Most of the time you are still limited by amount of space set aside within the rom for text, which can be an extremely infuriating thing. What using pointers does allow you to do is use the space you've got more efficiently. With pointers, if you cut one string down by 4 characters, for instance, you can elongate another one by 4. There are some ways around this which I'll get into later. Well, what about rom expansion? I hear that's really easy. That's only on the SNES, and even then that's not always the case. NES rom expansion is so difficult and time consuming that you might as well think of it as impossible. But I'm willing to learn 6502. Good for you. Go learn it, then. When you come back you'll understand why it's practically impossible to do. But there's no way I can possibly fit all of this text in the limited space I've got. Why are you being such an asshole and refusing to tell me how to do it? (I originally had a big writeup here about why rom expansion was so close to impossible, but I've been unable to confirm it by the time of posting this file. If somebody who knows 6502 assembly would like to write their own section on why it's impossible, or would care to read over what I've got and make corrections, it'd be very much appreciated) But I really want to do it. Give it up. You're not going to be able to, and those who might be able to do it for you are smart enough that they don't need you. You're just going to have to make due with the rest of us. Anyway, how do I use pointers? Once you understand what pointers are, you may find it difficult to figure out how to use the pointers. The simplest way to use pointers is as follows: Let's use the most basic example possible, Yes/No. (Translators may note that this example actually becomes quite useful in some situations, since the Japanese word for yes is two characters, and the word for no is 3) The strings are stored in the rom as: * * Yes#No# (Note, the # is just a code which tells the NES that it's reached the end of the line. See other docs to learn how to use that) Let's say, for the sake of example, that you wanted to switch them (playing a malicious trick on your friends? Shame on you ;) ). Without any modification, they'd display as follows: Yes No Now, if you just went into the rom and made the following change: No#Yes# you'd get the following output: No es Hmmm, well, that's no good. Why does it do that? Because elsewhere in the rom, there's a pointer which tells the NES where each string begins. Looking back, you'd find that the pointers actually point to the following locations (noted as the star above the position): * * Yes#No# Now, when you change only the text, you aren't changing the pointers, so they keep pointing to the same place. Hence, your new version reads to the NES as: * * No#Yes# The No reads in fine, since it starts where the NES thinks it does. To the NES, the Yes, however, begins at the e, and so it only reads in the es# for that string. With pointer remapping we can change where the NES thinks the strings begin to reflect how they actually are: * * No#Yes# Voila. If we ran that through the NES, we'd get an output of: No Yes Hurray, it worked! Is that the only way to use pointers? No, there are two other ways to use text pointers. 1) If you have multiple people who used to say different things, but now you want them all to say the same thing, you can use pointers to change that. Yes, more than one pointer can point to a location in the rom. Example: In game X, you have two towns people. The first, when spoken to, says "Ohh..." while the second says "Ahhh...". With pointers, you can make it so that they both say "Ohhh..." Yes, you could just change the text of the second person in the rom, but here's the advantage to just changing the pointer: The area where "Ahhh..." had been stored can now be considered EMPTY, meaning that you can use that area to fit even more text in elsewhere! 2) Blank space in the rom can be your best friend, if you're lucky. If there's blank space in the right area, you may be able to put extra text there. I'll go over how to find it and take the best advantage of that later. Ok, so NOW can we learn how to find pointers? Not quite yet. First we have to go over how to Calculate them. In working with NES roms, I've found 5 major systems of pointer calculation. I'll explain them in more detail down below, but for right now we'll work with the STANDARD HEADER system (my name for them). The standard header system for pointers is your most basic system for pointers, and is the easiest to work with. For illustrative purposes, I'll use the Final Fantasy rom. This is where thingy comes in helpful. Let's say you wanted to change "Nothing here." to read "The Princess always worries about you." So, we follow these simple, handy dandy steps. 1) Locate the string we want to replace (remember, take the HEX value) 2) Locate the new string (remember, take the HEX value) 3) Since we know that this rom uses the STANDARD HEADER system (defined below), we can use that to calculate the header value. Don't worry, I'm going to walk you through it right here for your first time. 4) Take the location that you want to calculate your pointer for (The first text string: "Nothing here.", for instance). Because these are STANDARD HEADER pointers, we use the following steps: First we'll do: "Nothing here." It's position is at 28210 5) Subtract 10 from it. (hex) Why 10? NES cartridges do not have headers on them. The headers are added by the people who dump the rom to contain information that's needed for the emulators to run. The NES, therefore, doesn't recognize the existence of the header, and so we have to take it out. (The emulators do this automatically when they run the rom, but it doesn't change the values embedded in the code itself) Will I always need to do this? Yes. At least, I've never encountered or even heard of a rom where this wasn't true. RUNNING TOTAL: 28200 6) Now, drop the "Ten thousands" place digit (the first 2 here) RUNNING TOTAL: 8200 7) You should have a four digit number now. If you don't, add in a zero at the beginning (that is, C77 -> 0C77) 8) Break this number apart into two pairs, each with 2 digits. RUNNING TOTAL: 82 00 9) Switch these numbers RUNNING TOTAL: 00 82 10) Wait, there is no step 10. 00 82 is YOUR POINTER VALUE. Congratulations, you've just calculated your first NES pointer. Umm... now what? Well, now we go back and repeat the process, this time with our new pointer (the one that points to "The Princess always worries about you."). Go ahead and try it. (Did you find a location of: 282CD and a Pointer of: BD 82 ? If you did, then you're right.) Ok. I've got the pointers. Now what do I do with them? Well, you just scroll on down here to: LOCATING POINTER TABLES (the easy way): Yes, it's actually time to get down to what you've been waiting for. Now, aren't you glad you waited (if you did. If you skipped down to this point, get back up there to the top where you belong!)? Since we know what system the pointers use, finding the pointer tables for this rom are actually quite easy. The easiest way (but one which is by no means guaranteed to work- it will for Final Fantasy though, trust me) is to open up the rom in your hexeditor, and go down to the text block (you've already got the address written down for it: 28010- where you found "Nothing here."). In your hex editor, do a search, set it to search upwards, and type in the value of your old pointer. The first value you try should be your pointer (in Final Fantasy. In other roms this may not be the case, but if you've got the entire pointer, it probably is). So, once you've located that, replace it's value (the 00 82) with the pointer you calculated for your new pointer (BD 82). Save it (ALWAYS KEEP A BACKUP of the rom you're working off of, though, because you never know when you'll find the wrong location and mess up the game itself). Now, go into NESticle, and try it out. Talk to air while you're in town. If, instead, it says "The Princess always worries about you.", congratulations, you've just remapped your first pointer. Ok, that's fine if I know the pointer system. So, how do I figure out that? Ironically enough, you figure it out from the pointer table. Before I start to explain that, though, I should explain the major types of pointers. (NOTE: Although Standard header and SetOff X000 are technically all the same thing, I've got them broken up for simplicities sake) STANDARD HEADER By far the simplest and quickest pointers to work with. These pointers appear somewhat frequently. Calculating them is simple (Final Fantasy uses Standard Header pointers, and the procedure for calculating them is stepped through above). In brief, you: 1) Determine the position of the text. (SAMPLE: 12345) 2) Subtract 10 for the header. (SAMPLE: 12335) 3) Drop the Ten-thousands digit, if there is one. (SAMPLE: 2335) 4) Break the number into two pairs. (SAMPLE: 23 35) 5) Swap the number pairs. (SAMPLE: 35 23) Voila, you have your pointer value. SetOff X000 By far the most common type of pointers on the NES, SetOff X000 pointers are pointers whose position within the rom is modified for whatever reason. This amount of modification is indicated by the X000 value. Why they're modified isn't important, only how. To calculate them, you follow the same procedure as STANDARD HEADER pointers with one additional step. (IMPORTANT NOTE: You can only calculate X by locating the pointer table, which is described below) If you know X000, they are calculated by: 1) Determine the position of the text. (SAMPLE: 12345) 2) Subtract 10 for the header. (SAMPLE: 12335) 3) Add X000 to your value. (SAMPLE: if you found X000 to be 3000, then 12335 + 3000 => 15335) 4) Drop the Ten-thousands digit, if there is one. (SAMPLE: 5335) 5) Break the number into two pairs. (SAMPLE: 53 35) 6) Swap the number pairs. (SAMPLE: 53 35) Voila, you have your pointer value. If you do not know X000, you need to follow the steps outlined below in LOCATING THE POINTER TABLES. When you get there, read through that section below, and then come back up here and re-read this one to gain the best understanding of SetOff X000 pointers. Some notes about SetOff X000: 1) Standard Header pointers are just SetOff 0000 pointers, but usually it's just easier to think of them as their own type. 2) For whatever reason, X seems to be 8 more frequently than most other values. 3) Although it is theoretically possible to have SetOff 1500 pointers, or some other value which is not a multiple of 1000, I have never encountered them, and have reason to believe that they are not possible on the NES. SEQUENTIAL TEXT Technically, this is not even a pointer system, but I include it here because being able to recognize this when it's used can save you hours of headache and searching. Sequential text systems don't use pointers, making their widths adjustable without any problem. The Yes/No example above would actually reduce to being as simple as replacing: Yes#No# with: No#Yes# Although it is not used with a lot of frequency, it does get used in some games. The Adventures of Musashi (j) uses this system. One important note: With this system, it know's it's done when it reads in enough strings. Therefore, you cannot simply remove a string you don't want in the game. When using this system, make sure you have AT LEAST as many strings as you started with (if you have more, they won't get read in, however) FIXED LENGTH Rarely used for text, this system is frequently used for item and spell listings. The game knows that the text string is X characters long (usually 16, sometimes 8), and reads them accordingly. You don't really need to do anything with these. (The Adventures of Musashi uses these for it's item, spell, enemy, and town lists) SEQUENTIAL POINTERS If you see these, run for cover, because they're annoying in the extreme to work with. I've only encountered them once, in RockBoard, and I'm still trying to figure out how they know everything they're supposed to. Anyway, I'm including them here for completeness, but you're free to skip this section until you come across some pointers which you just can't find. Sequential pointers are stored in their simplest form, two digits (as opposed to the 4 used in SetOff X000 and Standard Header pointers). They're calculated as follows: 1) Determine the position of the text. (SAMPLE: 12345) 2) Subtract 10 for the header. (SAMPLE: 12335) 4) Drop all digits except for your ones and tens places. (SAMPLE: 35) Voila, you have your pointer value. Seems easy, doesn't it? Well, it's not, because as you try to remap these pointers, all kinds of weird things can happen without the hundreds and thousands place. Space constraints are worse here than anywhere else. Trust me, you really don't want to deal with these unless you absolutely have to. Well, there you have your standard pointer systems. Are there others? Probably. I've only encountered one other system on the NES, and I'm STILL trying to figure that one out... So, now, can we finally get to finding the pointer table? Yes. You've read this far. Now it's time to pull it all together. You're reward for having read through this far. FINDING POINTER TABLES and your pointer system (the easy way): (if you need an example, refer back up to the Final Fantasy one above) Does the rom use a SEQUENTIAL TEXT or FIXED WIDTH systems? 1) To determine if you've got a FIXED WIDTH system, just look at your text strings. If you've got a bunch of strings that are exactly the same length (especially if they use 00s at the end to guarantee that), odds are you've got a fixed width system at work. 2) To test and make sure, locate a string you can bring up easily in the game. Overwrite it with something longer which runs into the next string in your hex editor. Save, then load the rom and bring up that item. If it cuts off after a certain length, you've got a fixed width system. 3) To test if you've got SEQUENTIAL TEXT, locate dialog you can bring up easily in the game. Go into your hex editor, and locate that string. Now, go into the string BEFORE it and add an end of line code (you should have figured these out BEFORE looking for the pointers. If you don't know how, read someone else's doc, then try this one again.) right in the middle of it. Save, and load up your rom again. Bring up the dialog you used before. If it's different, then you've got a SEQUENTIAL TEXT system. If your rom does not use the SEQUENTIAL TEXT or FIXED WIDTH systems: 1) Open the rom in your hex editor. 2) Locate a string of dialog which you can bring up in the game easily or quickly. Don't use menu options, or other types of text, as these tend to be stored differently in the rom. 3) Write down your position. 4) Subtract 10 from your position for the header. 5) Note down the last two digits of your value. (If your adjusted position was 12345, the 45) 6) In your hex editor, Search UP for this value. (the 45) 7) Usually, you'll find one close to where you started your search. Regardless, write down the two digit number to the right of the one you just found (Let's say, searching for 45, your search returned the 45 in the following line: AB 45 FE write down the FE) 8) Check the second digit in the number you just wrote down (In FE it'd be the E). Compare that value with the hundreds place in your adjusted position (In 12345 it'd be the 3). If they match, you may have found the beginning of your pointer table. In they don't, continue searching UP. 9) Since the values didn't match, we continue searching upwards until they do. (Finally, we find it a line that includes 82 45 83) 10) Now that we've found a potential pointer, we need to test it. Change the pointer so that the text will display differently (my favorite is to just set the ones place ahead by 1, so that the first letter doesn't display. When that happens, you know it worked. Sometimes, when you've got control characters this isn't possible. Then you'll need to remap the pointer to another string of text, and see if it changed like you expected it to -> This is what we did in the Final Fantasy example above.) 11) If the text changed as you expected it to, CONGRATULATIONS, YOU'VE JUST LOCATED THE POINTER TABLE. 12) To figure out which pointer system you're dealing with, you only need to look at the pointer you've found and compare it to the position of the text you're using. Take the first digit of the right number in your pointer (45 83 -> Take the 8) and compare this to the thousands digit of your position (12345 -> The 2). If they're the same, you're dealing with STANDARD HEADER pointers, otherwise you've got SetOff X000 pointers (where X is the number you just examined from the pointer -8- less the number you just took from the position -2-, or 6 => Therefore, you're dealing with SetOff 6000 pointers) That's it. This system will work for most of the games that many of you will want to hack out there. Now that you know the pointer system, you can calculate the pointer for the first item in your text block. Find that, and you've found the beginning of your pointer table. FINDING THE POINTER TABLES (a harder way): If the above system didn't work for you, make sure you don't have any control codes (described below). If you're sure that there aren't any in there, try this system: 1) Test for SEQUENTIAL TEXT and FIXED WIDTH systems, as outlined above. 2) Locate a string you can bring up easily in the game. Find it in the rom. 3) Using it's position, calculate the pointer using the STANDARD HEADER system. 4) Search the hex for this value. Change every occurrence slightly (remember, change the second digit of the first number pair for minor changes). 5) Save, and load the rom. If the change you wanted occurred, then you know it's a STANDARD HEADER system. Change matches one by one until you find the right one. 6) If that doesn't work, then calculate the pointer using the SetOff 8000 system. Search for this value in the rom, changing every occurrence slightly. 7) Save, and load the rom. If the changes you wanted occurred, then you know it's a SetOff 8000 system. Change matches one by one until you find the right one. If these don't work, then I'm afraid you'll have to resort to: BRUTE FORCE POINTER LOCATION (the tedious way): The system of last resort. This will work 99.9% of the time if you know that you're not dealing with a FIXED WIDTH or SEQUENTIAL TEXT system, and that there are no control codes throwing you off (and in that 0.1% of the time, you don't want to deal with it anyway). 1) Locate a dialog string you can bring up easily in the rom. 2) Locate that string in the rom. 3) Calculate the pointer for it using the SEQUENTIAL POINTER system (no, don't worry. Using this method does not automatically mean you've got sequential pointers). 4) From the beginning of the rom, search through for that value. One by one, change that value slightly. Saving and testing to see each time if you've found the right one. 5) EVENTUALLY you'll come across it (hey, if you're lucky there will only be 500 occurrences in the rom). From there you can figure out the pointer system as described under the easy way above. So, is that it? Do I now know everything I need to about pointers? Almost. There are only two more minor things for me to address. Empty Space in the Rom: Fitting all of the text you need to into the rom can be quite troublesome. Fortunately, there is a solution... sometimes. On some occasions there will be blank space within the rom which you can use to fit some extra text in. You can recognize this space because it's usually just a large block of 00 or FFs (although I've also seen it take the form of alternating FF 00 from time to time). Look at the end of your rom and you'll probably see a good example of it. Now, because NES pointers are limited to 4 digits, so too are your pointers. Therefore, your range is limited to the 10000. Scan through the ROM for blank space. Finding blank space isn't a guarantee that you can use it, however. Often that blank space is out of the range of the pointer, or otherwise unusable. But, there's only one way to find out. Try it. Put some text there, remap a pointer to it, and see what happens. Sometimes you get lucky. Control Characters: Ballz calls these "Ballzy Tables," but I prefer to give them a name that has to do with their function (much less, a name that isn't horribly inaccurate. These aren't tabled information at all.). Control characters are codes that programmers put in with the text which tell the NES how to display it. Much like the font tables themselves, these vary from game to game. End of line and End of page are two examples of control characters. I bring these up because if the text string you're using has one (or more) of these at it's beginning, the pointer will point to THAT instead of the first displayed character in the string. How do I recognize them if they're there? Well, the easiest way is to work backwards. Figure out the End of Text character (End of Line, End of Page, whatever applies). Pick a string of text from the game, and find it in the rom (note: it can't be the first string in the rom). Look to the left of that first character. If that's your End of Whatever code, then you're fine. If it's something else, try changing it. If it effects the text when you load up the game again, then you've got a control code (I won't go over how to use control codes here because they vary with every game). Continue until you've found the TRUE beginning of the string. That's what you have to look for the pointer to. WOW. COULD IT BE? FINISH!!!!!!!! (This document is copyrighted 1998 to Timothy R. Dennie. Please do not redistribute it without his permission. Just ask, he'll probably let you. You can e-mail him at tdennie@hotmail.com)