benfrosh

Jungo · @benfrosh

14th Dec 2015 from TwitLonger

Twelve Days Of Romhacking: How I Got Started


So, there was a period around December 2013. I had been fairly invested in the Crusader King 2 modding scene prior to this, and was thinking about modding games in general, and eventually came around to remember that rom hacks were, in fact, a thing. I started canvassing around to look for a specific kind of romhack: balance overhauls. I was interested in the idea of taking the spirit of the game but rejecting the specific numerical + mechanical framework, plus it was the easiest way to 'play a new game' with none of that risk of me hating the game's writing and characters. Plus I'm a huge numbers wonk and I love arguing, so. It was fate, really.

While it's not necessary for you to know anything about it for this blog series, the rom hack project I found was Final Fantasy VI: Brave New World, forums here: http://www.insanedifficulty.com/board/index.php?/forum/133-final-fantasy-vi-brave-new-world/ I'm Think0028 on those forums. You don't have to read about it or know anything about its design philosophies or even approve of it, but if I mention something that seems 'off' from the FFVI you remember, it's probably from the rest of the hack. For the sake of this series, all you need to know is that:

1) I loved it.
2) I felt like I could improve it, and that this was an audience that'd be receptive to change.

In regards to 2 in particular, there was a specific phenomenon I noticed that I wanted to fix. But that'll be spoilers for tomorrow's post. For now, know that I had a very specific thing I wanted to fix, and I wanted to fix it myself because it seemed like a cool project. But... how could I fix it? I had no idea what I was doing! So I took out to learn.

The first thing I found, after frantic googling, was this: http://datacrystal.romhacking.net/wiki/Final_Fantasy_VI:ROM_map
It's a wiki that has an annotated map of the entire FFVI ROM, with a focus on the executable code. This was a goddamn godsend. Hacking is so, so, so, so much easier if you don't have to map out the functions yourself. I did that once and only once, for an EXP All patch for Fire Red, and I hope to god I never have to do that again. But this made my job much easier, because instead of fishing around with breakpoints and experimentation I had a guide as to where to look for various bits of functionality. FFVI is a good game to start practicing ROM hacking and getting used to the tools, because it's so well documented and has a lot of good tools associated with it.

A lesson about SNES ROMs and addressing: C00000 refers to the first byte after the header of a ROM. This is the difference between headered and unheadered ROMs if you ever noticed someone mention those: headered roms have 512 bytes of data at the start describing the ROM, and unheadered ROMs do not. So

The second thing I found was the answer to, what the hell language is the ROM in? The answer is 65816 assembly: http://wiki.superfamicom.org/snes/show/65816+Reference

Yeah, yeah, assembly is scary, oooo. The only scary thing about it is going from the code to the opcodes, and that's honestly just a lookup table. 65816 assembly is both painful and merciful in how limited it is:

1) There are three registers, A, X, and Y. A is the only one you can do any real math instructions in. Registers are where we can have data we can actually work with. So a lot of time in the code I'll have X and Y being locations I can look up key data, and A being a scratchpad I can use to keep track of a single number.
2) Each register can switch between 8 bit and 16 bit mode, which can trip you up for a half second if you aren't careful about making sure which mode you're in. All this means is that sometimes A, X, and Y can hold numbers from 0-255, and sometimes 0-65535. I just have to be careful I'm using the right cap in the right situation. It can be correct to use the 0-255 mode because that uses less space in the code and in memory to store those numbers, and space is at a premium. A running theme of romhacking: you are not supposed to be in this codebase. You will have barely any freespace to work with (I often have to cut down my hacks to use 10-12 instructions, tops) and you will have to work very hard to make sure you don't break anything while you're in there. The other big thing? You only have 1 or 2 pointers to memory at a given time. If you don't have the pointer to some location you need (say I want to access a character's status conditions, but the game doesn't have it loaded), you'll need to find some way to either find it in RAM or reconstruct the location.
3) There's like barely any flags that can affect any given operation. The only three you really care about as a hacker are the zero, negative, and carry flags, which are plainly documented how they're changed and what they affect.
4) This is more assembly in general, but that list of instructions is all you can do. You're working with numbers, no weird data types to handle. Keep it simple. What this means, however, is that if you're doing anything complex, it's going to take a lot of code. Note that there's no multiplication or division functions in there: you have to do that by hand, or hope the game you're hacking already has those functions and you can call them without breaking something important.

Sidenote to other assembly programmers: my big complaint is that CMP sets the carry flag opposite from what I'd expect. I expect A less than the CMP argument to set the carry flag, but it clears the carry flag. That's weird, right? Wouldn't it be implemented as A subtract the argument? But that's me.

Thing 3 I found was HxD, a hex editor. You need a hex editor to edit ROMs; that's just how they're stored and manipulated. The SNES starts at C0/0000, reads a byte to read it as an instruction, figures out how many bytes to read as arguments, processes the instruction and changes its registers based on the instruction, and then continues after that. All one after the other. There's no difference in the ROM between code and data; it's all just numbers the SNES reads as it's instructed to. This lets you do very naughty things (the code for drawing the main menu animation is generated in RAM and then run) - but I digress.

If you don't quite understand assembly or programming in general, you don't have to bother understanding this. I'll explain any limitations as we come along. The big takeaway here should be that the biggest complication in romhacking is rarely if ever the actual logic of the program, if you're doing something sane. The top issues are space (how much code do I have to write to do this) and finding shit (where the hell is the data I want to manipulate?). This will be a recurring theme in the series, with one major exception on day 12.

So I had an idea, and I wanted to execute it. What did I do? I studied assembly and I started searching the wiki. If you want to simulate what I did and learn how to figure out what the game already does, I'll give you a homework assignment:

FFVI implements the ATB system: bars fill up based on a character's speed stat, and when the bar is full they get a turn. In addition, the bar goes up a static amount at a constant rate. What is the formula for how much that bar fills up every tick? More importantly, if I wanted to change this formula to make the bar rise at half the current speed, what block of code should I look at? I'll even give you a hint: there's a constant that needs to change.

Reply · Report Post