Blah
Free supporter
- 1,924
- Posts
- 12
- Years
- Unknown Island
- Seen Feb 19, 2025
Programming in C for Gen III (In perspective of FireRed - Best ROM)
Hey, it's me FBI, I've decided to write a tutorial on programming in C for Gen III games. This tutorial will be mainly in the perspective of FireRed since I am a Fire Red ROM hacker (and if you aren't you should become one!). My main reason for writing this tutorial is because it had become apparent to me that we didn't have any tutorials detailing a more up to date process in ROM hacking using C. Before I begin, I'd like to point out some of the key difference between what I intend to write about in these tutorials and how/why they differ from other tutorials you may end up reading.
The first distinction I want to make, is that programming in C for the GBA is not the same as programming in C in general. When programming specifically for the GBA's hardware, we're working in an extremely low level environment, fiddling with IO registers and writing data into VRAM data buffers ect. What you may be used to writing are programs which call various functions from libraries such as <stdio.h>. These kinds of "higher level" concepts don't really make an appearance. The most comparable things to something like stdio.h would be the GBA's BIOS functions, which I'll talk about at a later time.
Finally the second and last distinction to make is that programming for the GBA in general is not the same as programming for a ROM hack. When working with a prebuilt ROM, we're forced to work within the confines of the existing code base, and we have to work around the systems in place by the default engine. If you're already familiar with how to code in C, then you might be able to read the code, but you might struggle understanding what it actually does. To remedy this situation, I suggest a solid understanding of ASM hacking in Gen III ROM hacks. Specifically Gen III ROM hacks, because you should have a good understanding of how FireRed and others work inorder to write good code to exploit what's already there.
This series of tutorials will be written under the following assumptions:
1) You have hacked Fire Red or some other lesser Gen III Pokemon game.
This tutorial is written specifically for FireRed. It does double up to be a good resource/tutorial for LG and R/S/E as well simply by the fact that all of these games are run on the same hardware and the game software engines are all extremely similar. I'm writing this for Fire Red hackers, so I will be using Fire Red.
2) You know ASM to a somewhat good degree (can write hooks, understands the stack, can read ASM code well)
At the stage of Gen III ROM hacking we're at right now, we absolutely don't know enough about any of our ROMs to write C source code without being able to read and understand ASM code. Writing hooks and the process of researching are all still done in ASM. Until the day comes by in which we get a full C source of FireRed, ASM will be needed. Not forgetting that, debugging is mainly done in ASM as well. Throughout this tutorial, I'll be expecting the reader to now what a function is, what parameters/arguements are and what a return is. These are all things you should have picked up working on ASM.
3) You satisfy the above two conditions and you're resilient
This tutorial is not for someone who doesn't know any ASM and hasn't hacked Gen III before. You will get intimidated and you will get thoroughly lost. I suggest learning ASM first. Before learning ASM, I suggest making your own mini-hack first. Finally, this isn't a tutorial for young children or people with low mental capacity. I don't write tutorials capable of teaching people who are unwilling or unable, this was never intended to be such a tutorial, and never will be. Please note the distinction between an idiot and a noobie. There may be parts of this tutorial which are too hard, or require more than one sitting to understand. Be motivated, and keep at it. Re-read points you don't understand, and finally post questions if you have any. I consider this first tutorial to be rather easy, but it may not be the case for you.
That should do for a brief introduction :)
Setting up your development environment!
A quick note, this is not a tutorial on how to use your operating system either. I'm heavily assuming that you know how to use the terminal/command prompt and know basic things.
Before we can start coding, we need to have some dependencies downloaded and installed properly. Please have the following installed:
Python v3.5 (minimum): https://www.python.org/downloads/
DevkitARM (neat installer for windows!): https://devkitpro.org/wiki/Getting_Started/devkitARM
The installer in DevKitARM, if you're on windows, should write itself to the PATH variable. However, if I recall correctly the slashes for the path may be incorrect. You can fix them by going into "Edit System Variables". This might not be the case however, so if it installs correctly for you, then great! If you've been able to compile Touched's Mega evolution code, then your DevkitARM has been installed correctly.
You need atleast Python ver.3.5 to run these Python scripts. At the time of writing this tutorial, none of the commands have depreciated. Make sure that your Python has been installed correctly, open the command prompt and try running Python like this:
Spoiler:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/rOK3bs4.gif)
You can, and probably should, set up your system variables to just use Python without an absolute path. Solely for convenience sake. The second part of the gif where I type in "python" to open the interactive interactive shell will only work if Python is added to your system path variable. It might be the case that the installer does this by default. You can check using "echo %PATH%".
If you had previous versions of Python on your computer, please confirm you're accessing the correct one by doing:
Code:
import sys
sys.version
In the interactive mode.
Finally, confirm that you have the objcopy.exe file in C:\devkitPro\devkitARM\arm-none-eabi\bin. This path may change depending on what operating system you are using. Once again, please confirm the appropriate executables have been added to your path variable.
After triple checking that you've got the setup done correctly, go ahead and download the repository here: https://github.com/EternalCode/Empty-Template. You'll need to either go through the normal github methods to grab it or you can easily download it as a zip file and extract the contents. Right now this repository is empty, and doesn't contain anything really worth compiling, but you should try to compile it to see if everything is working. Before you are able to do so, you'll need to include a FireRed ROM inside the "Sample Project" folder, and it MUST be named "BPRE0.gba".
Spoiler:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/MweXI5C.gif)
So the first thing you want to do is run Python on the build script inside the script folder. To do this, we give our Python.exe the file arguement which is a path to our build file. More simply explained, we do [Path to Python] [Path to build script]. So if you didn't have the Python Environment Variable set up, then you'd have to do, "C:\Python35\python scripts\build", while being in the Sample Project folder.
After building, we simply execute our insert scripts using python in the same way, however, we'll put in the "--debug" arguement. So this time, your input to the command line should look more like this, "C:\Python35\python scripts\insert --debug" (in the case that once again you didn't put in the env var).
With the Environment Variable set up, it's simply:
python scripts\build
python scripts\insert --debug
While being in the Sample Project directory.
In the case that it all compiled, like in the Gif, you too should recieve a message stating what has been compiled where. You should also have a new folder produced in the Sample Project directory labeled, "build", as well as a new GBA file called "test.GBA".
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/PzNRd8I.png)
If the original "insert" script did not work for you, you can try it using "insert2" instead of "insert". So your new command would be, "C:\Python35\python scripts\insert2 --debug". In the case which the build script isn't working for you, please make a post of the errors you are getting for further assistance.
If you've made it this far, then great job! We've completed, what is in my opinion, the hardest part of ROM hacking FireRed using C. The setup is indeed the part which takes the longest time. In cases where you need to install both Python and DevkitARM, depending on your OS, it could take almost an hour to do. Sometimes Windows cries about certain things in the setup process, sometimes it works without a hitch!
Understanding and modifying the files in Sample Project
There are five main files you really need to worry about here. They are:
- BPRE.ld
- insert (and insert2)
- hooks
- types.h
- user implanted files
About the BPRE.ld file:
The BPRE.ld file is a reference file of sorts. It indicates where certain things are in the ROM. For example, sets say I was writing some C code for a potion which healed your entire team (like the PC would). I may need to use special 0x0, which is the healing special in FireRed used by the PC. To do this, I first locate the routine for special 0x0, it'd be at 080A0058. Then I'd have to put it inside the BPRE.ld file.
So in BPRE.ld, I'd have place the line:
Code:
heal_special 0x080A0058|1;
Now when I need to use this heal special again, I'd be able to just reference it's name. Ex:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/V9ctuaA.png)
You can, and should also place any discovered data structures into your BPRE.ld file as well. For example, the sav data structure's location is also something that would go in BPRE.ld. I'll cover structures in a later section of this tutorial. That's all the BPRE.ld file is for. It provides a way for the compiler to know where to find certain functions/RAM structs you haven't written/defined in the ROM inorder to compile your code. But before we move on to the next file, I'd like to point out some things about the syntax of this file. In the file, each entry must follow this format:
Code:
name address|1;
Code:
main:
[stuff here]
ldr r0, address + 1
bl linker
[stuff here]
linker:
bx r0
The BX instruction tells the CPU to enter thumb mode if and only if the LSB (least significant bit) is 1. Since our ASM routines are always word aligned, this is the same as adding 1 to the routine. However, "binaricly" speaking, what really needs to happen is, the LSB needs to be set. This "|1" instruction does exactly that, it's a bit mask which is applied to the last bit turning it to 1 if it was 0, or leaving it at 1 if it was 1. I'd like to ask for anyone who devs in C in the future for ROM hacking to always use this format rather than doing +1. Lets keep our coding styles consistent please. Before I start ranting, I'll end off saying that ";" symbol is required after every line to signify the end of the line. [spoiler =Now for the mini-rant]Last time someone tried to be a special snowflake they did something silly like:
Code:
main:
bl some_func
some_func:
ldr rX, some_func
bx rX
And obviously, everytime you need to call this function with a different register you'd look like a total tool (requiring 4 extra bytes). Also jumping to other functions using the same register too required extra bytes. In the end that way inflated the size of your routines.[/spoiler]
About the insert files:
After you've gotten past the initial setup process, you may have noticed that the function "sample()" was compiled and inserted into the address 08800001. Well, actually it was inserted at 08800000, but the output message adds one to it. Anyways, you might find yourself wanting to have your C programs inserted at some other location, not 08800000, especially if you're not working with a clean ROM. To do this, open insert or insert2 (whichever one you're using, it opens in notepad) and simply ctrl + F "default=0x800000" and change that 0x800000 into whatever your desired starting point is. Once again, I'd like to point out that the original ROM you include in the folder, BPRE0.GBA will NOT be modified. It's simply copied, and renamed "test.GBA", and the changes are applied to "test.GBA".
About the hooks and other files
Ugh, this file is harder to explain until we actually start working on hooks. I'll omitt this section until we get to it :^)
Same with the other files like types.h.
A quick review of the GBA's Hardware
First of all, both GBATek and Cowbite are 100 times more clear at explaining the GBA's hardware than I am. I will simply give a generic memory map, and short explanation about things you need to note. Soley for the purpose that those reading this tutorial will not find themselves unable to follow because they don't know/understand the distinction between WRAM and VRAM, for example.
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/EK5RJ73.png)
This should be all you really need to know about the GBA's RAM to hack really. For more details check https://problemkaputt.de/gbatek.htm#gbamemorymap
I'll quickly go over some important technical details, and facts which may enlighten you!
First of all, you'll notice that there are two sections of WRAM, which have been labeled. One is 32KB and the other is 256 KB. The 256KB of EWRAM is what's available for your game to use for its RAM data. For example: the save structures, player name, rival name, NPC states, malloc calls ect are all placed in this 256 KB RAM slot we call EWRAM. This is called External Working RAM, this is not because it's not on the GBA or anything, this RAM is simply not on the CPU chip, hence it's naming of External Working RAM. The 32 KB RAM is called Internal Working RAM because well, it's on the GBA's CPU chip. In general, the IWRAM is considered very expensive memory. There isn't a large amount of it available and it's delegated to holding the Stack, Registers and other data placed on the stack. The IWRAM is indeed faster than the EWRAM because it uses a 32bit bus (allowing for faster execution of 4 byte intructions, and data transfers of 4 byte long data strings at a time) while EWRAM holds a 16 bit bus. This is also the main reason we write ASM in Thumb. Thumb instructions are 16 bits and when working with EWRAM, they'll execute much faster than the 32bit ARM counterpart. ARM should therefore be delegated work in the IWRAM and the EWRAM should be left to thumb.
Now for the IORAM or IO registers. The IO registers are best thought up as simply an area of Mapped RAM designated for the GBA to read inorder to know what settings certain features should be using. This is not to be confused with registers used in our ASM instructions, they more behaved as memory addresses which are read from by the GBA. See GBATEK for more detailed documentation https://problemkaputt.de/gbatek.htm#gbaiomap
Ahh...The VRAM, PAL RAM and OAM RAM in Generation III has a very close knit interaction with the FireRed game engine. I'll explain more about that shortly, but before that, lets look at a brief overview of all three.
There are a total of 16 slots of 16 colors pals available for all 4 backgrounds (BG0, BG1, BG2 and BG3). Starting at 0x5000000, each color in the palette takes 2 bytes, by extension you take 0x1E (or 32 in decimal) bytes per pal slot. With 16 pal slots, the BG PAL RAM would only extend from 0x5000000 to 0x5000200. So for example, Pal slot 1 of the BG pals, the starting address would be 0x5000020 (0x5000000 + 0x20), counting from Pal slot 0.
Following right after the BG pals, we have the PAL RAM allocated for Objects. Object Pal RAM is the same size as BG pal RAM, except, ofcourse it starts at 0x5000200 (where the BG Pals had ended). The math and the logic for how the pals are allocated are exactly the same, except, Objects have something called pal tags, which I'll talk about in a later section. In general terms, it's not the case that the first OAM will always be using the first pal slot (as you'd expect in BGs).
Finally we have VRAM. VRAM is split into basically two major sections. The first part is reserved for BGs, from 0x6000000 to 0x6010000. In the BGCNT registers in IO RAM, you are supposed to specify what areas of VRAM each of your BGs are using for their char and map bases (read as tileset and tilemap). In general, you're free to use this memory for BGs in general in whatever order you'd like. The second part of VRAM is from 0x06010000 to the end of VRAM, and this is strictly allocated for Object tiles. Here comes the interesting part. FireRed (and other Gen III games) have high level structures in EWRAM (some sometimes IWRAM) which they use to control various things like BG IOregs and display settings and more importantly to VRAM, sprites. The OAMs are backed up in a structure in FireRed, knizz called the superstate. The superstate, every vblank (which you don't need to know about yet, basically consider it a time where the GBA can safely write to the screen without causing glitches) syncs it's contents with the Object VRAM. This ultimately makes it so that when you write to the VRAM, your changes can be immediately reverted. You may have experienced something similar where you tried to write a byte to some area in RAM and it got ignored/written over. This is the FireRed/R/S/E engine's way of telling you that it's incharge and that you're just a peasant. Don't mind, there are work arounds which I'll explain later on.
"Hey, FBI, this section is supposed to be about the GBA's Hardware but all you've talked about so far is the RAM". Yeah, that's all I really plan to talk about. Fine, I'll talk about some hardware. The GBA also has a D-PAD and and A/B button and two Shoulder Buttons L/R. That should do it for the hardware section. This whole section may have seemed like a big rant, but actually, it's important to first know a little about the system you are working with before you can write code to be executed on it. Maybe not for this beginner's edition, but definitely later. Any amount of knowledge you can get on the GBA, is only going to be more useful to you in understanding how the GBA works. For this purpose I highly suggest you give documents like GBATEK and the introduction in Tonc a good read.
Understanding some basic content in your C files
We may be ready to start compiling C code, but we haven't quite explained enough to start developing our own. I'd like to direct your attention to this sniplet of C code I've written. All it does is return nothing. It's the same as having an ASM function who's only line is "bx lr" (Aka return). Without further delay, lets look at the code:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/JQrvrEa.png)
Take a minute to look at this code and try to guess what's happening. It's a good idea to first guess what's going on before learning the differences between your guesses and reality. Or so is how I like to learn about a new language :)
Code:
#include "types.h"
Code:
#include "stdpoke.rbh"
#dynamic 0x740000
#org @start
lock
faceplayer
end
Code:
#include "stdpoke.rbh"
I'll breifly explain what types.h is for. Basically, unlike ASM, C is a strongly typed language. Everything in C, from pointers, numbers to variables all have something called types. A character from a string is of type "char", a word or 4 bytes is of type long. In order to know what data is contained at what address, and how to access this data, C's compiler needs to know what type the data is. For example, lets say I have a pointer. This is a 4 byte piece of data, it cannot be loaded into a register using something like ldrh, only ldr can load it. Because issues like this arise, it's extremely important for the data in C to be strongly typed. Typing affects not only how your data is accessed by the compiled code, but also how it is read. The strong typing persists in such a way that you can't write large data into buffers which are marked as smaller. So in ASM, you COULD str a 4 byte value into something we know has a two byte data length (like a script variable), but in C, you can't do this (without casting - a topic for a later time, when you become a wizard). What types.h contains are a bunch of type definitions which are basically short hand notation for the standard typings. This allows us to write code faster and in a readable fashion.
The types we'll be working with include:
Code:
void - No defined type, could be anything. Or states empty return/arguement
u8 - unsigned char (use for 8 bit data that's not signed - byte)
u16 - unsigned short (use for 16 bit data that's not signed - half word)
u32 - unsigned long (use for 32 bit data that's not signed - word)
s8 - signed char (use for signed 8 bit data - byte)
s16 - signed short (use for signed 16 bit data - half word)
s32 - signed long )use for signed 32 bit data - word)
char - Characters are 8 bit, 1 byte pieces of data, mostly used for strings.
null - zero. 0. 0x0. Null is just zero!
true - one. 1, 0x1. True is denoted as 1. So if a function returns true, it returns 1
false - zero, 0, 0x0. Besides the value of 0, it's the same as true
Next, we have something called the function header.
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/C4cYA53.png)
A function header follows this format: [return type] [name] (paramateres)
So in this example, our function named "test" has void as it's return type (meaning it won't return anything. So r0, when returned, won't hold a meaningful value. Since there is nothing in the round brackets, this function also does not take any paramaters. The open round brace "{" indicates the start of the function body, while the "}" indicates the end. The code for our function must be contained within in. It's worth pointing out that the name of your function cannot have any special characters or spaces in it, otherwise it'll fail to compile (syntax error).
Finally, we have the return. After we're done, we return. This is the same concept (almost) as popping PC in ASM. However, in the case that your function's return type was void, you actually don't need the command "return" because it's assumed after the closing braces it would return. That being said, it's a good habit to write return anyways, simply because in the case a function does return a non-void value, you will have to write a return. So just ingeneral writing return for every function is a good idea, and it doesn't bloat your code at all.
FireRed hacking in C - Part 1: Function calling
Normally in this section of any tutorial, you'd have the simple task, like "Hey lets add 2 + 3 and put it in a variable!!", but that's insulting. We're not noobs anymore, as such, our starting task should be something which is somewhat interesting to do. Lets add 5 + 3 to a variable. Not just any variable, we'll add it to var 0x4000! Yes, a variable we cannot directly access! (Fun right?)
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/FkzLTxU.png)
You'll notice that I referenced a function in the ROM within my "set_var_eight" function. "var_set" is a function which is at 0806E584 in FireRed. As you can guess from it's ASM, it takes a var ID in r0 and in r1 it takes a value to set for the var; returning 0 if it failed to set the variable and 1 if it succeeds. We've simply called this function in C, but ofcourse it's not that simple, allow me to first remind you that when referencing functions like this from the ROM, you need to add it into BPRE.ld. After that, you can call it, almost. The truth is this code will not compile yet, we have to do one more thing. But before that, let me explain quickly the obvious syntax if calling a function.
Code:
function_name(parameter1, parameter2,...);
A) this is our first program, who cares
B) it'd only return 0 in the case the variable was invalid as opposed to a memory error. 0x4000 is valid.
Now going back to what I was saying earlier, even though we've included the line
Code:
var_set 0x0806E584|1;
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/HUwd1KA.png)
Take note of how the function was declared. The syntax is exactly the same as the function we wrote. The only difference is that we don't have to write it's function body, since it's already in the ROM. What I haven't explained is the way I've assigned the paramaters. The parameters are seperated by commas, and for each paramater you need to include a type then a name, in this format: [type] [name]. So in our example code, we have
Code:
(u16 var_id, u16 var_value);
We're all good to try and compile this now. Once again make sure your BPRE.ld has the line for telling the compiler where var_set is in the ROM. Upon compiling it, you can check the ASM code at where it compiled to confirm that it matches what you'd expect it to be like in ASM! Note that the compiler is generally pretty smart. It will optimize certain lines, but here everything should be the same (though 5 + 3 will just be solved to be 8 instead).
Operators C - Part 2: Operators
This will probably be the shortest section here. I'm just going to explain some quick operators in C, which you probably use in ASM very consistently anyways! I suggest just giving this section a quick read and using it as a reference for when you're actually writing your own C code. I've decided not to bloat the section, but it is important to read and understand.
Basic Arithmatic Operators:
Spoiler:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/la7mTiP.png)
Assignment instructions:
Note that if these values were signed, our C equivalent type would be s8, s16, and s32 respectively.
Spoiler:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/s8tUD5a.png)
Bit level operations:
Spoiler:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/ROEk1d9.png)
Now I'll explain equality. Things you would be checking via "beq", "ble" ect.
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/hSpEt9G.png)
Note these are adjusted to their signed equivalents depending on typings. Moving on, you don't exactly need to memorize them immediately. These are things you'll remember naturally as you use them. Most of them are very common sense too, for example "&" and the arithmetic operators.
Pointers and casting in C : Part 3
Oh baby, we're getting to the more fun parts of C. Pointers in ASM are generally a very simple concept. A pointer is always 4 bytes, and needs to be dereferenced inorder to store or access the value in the pointer. In ASM, we do this by:
Code:
ldr r0, pointer
ldr r1, [r0] @or ldrb, ldrh depending on what's in the pointer
Once again, I want to introduce the term dereferencing. When you're dereferencing a pointer, you're accessing the value directly at the pointer. Thankfully this concept extends to C, however, syntactically it's a little more different due to types in C. Lets look at an example.
Code:
u16 *var_8000;
Now lets say I wanted to assign this var_8000 an address. I want it so that my var_8000's pointer points to an address of my choosing. Going by what's in the ROM, we know that the address of this variable is at 0x20370B8, so the solution is simple right?
If I wanted to do this, the correct way to do so is to add this line into BPRE.ld:
Code:
var_8000 = 0x020370B8;
Code:
u16 *var_8000 = 0x20370B8;
Code:
u16 *var_8000 = (u16 *)0x20370B8;
Code:
u16 *A;
u32 B = 0x20370B8;
A = (u16 *)B;
We're ready to discuss deferencing pointers now. Lets say I wanted to retrieve the value at var_8000. So essentially I want a way to do something like this:
Code:
ldr r0, =(0x20370B8) @We did this with the casting portion of this section
mov r1, #0x5
strh r1, [r0] @ We want to learn how to do this
Hopping right to it,
Code:
u16 *var_8000 = (u16 *)0x20370B8; // Nothing new here
*var_8000 = 5; // Dereferencing
Well, this is kind of straight forward now, huh? Basically, var_8000 is a variable which is of a pointer type. We use the asterisk here to dereference this pointer, then we make the deferenced value 5. Note that the type of var_8000 is still of type u16 *, but the type of *var_8000 is type u16 (the type of the data at the pointer). What we've done with that last line is basically setvar 0x8000 0x5. Simple, and easy.
FireRed hacking in C - Part 4 structs
With that I think we're ready to dive into some action. Lets look at some data structures in FireRed. The most obvious one would be the Pokemon Data structure. It looks something like this (ripped from bulbapedia):
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/Z7GWpJe.png)
I'd like to note some term differences in this image which you might not be used to. First of all, everything in the type column refernces the size of the data. Everything on the offset column references the offset of the data from the start of the structure (not these numbers are in decimal, not hex). Finally, "dword" = 4 bytes, word = 2 bytes, and byte = 1 byte, obviously.
OK, so this is an example of a structure which you would encounter in FireRed. Each piece of data in the structure (struct for short) is called a member. So the second member in this struct is the OT ID. Something to note is that the data member is actually encrypted in the real games, but we'll ignore this fact for the sake of this tutorial. If I were to define this structure in C's syntax, it'd look something like this:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/J73E4K4.png)
A few things to note, the first thing is that I use arrays in this structure. A good way to think about arrays are as areas of memory with repeating data of the same type. For example,
Code:
char Nickname[10];
Going back to the struct itself, this is the format syntax:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/zz2rp6W.png)
I think structs are kind of self explanitory, so I'll leave it here. If it's too hard to understand, I'll write more of an explanation for this section. I'm hoping the general ASM knowledge means you pretty much already understand this example.
There IS something missing here though. The player doesn't just have one Pokemon, they would have 6. So how would we define the player's whole party? Well, we already know how, but to make it all click, I'll show you:
Code:
struct Pokemon player_party[6];
// type is "struct Pokemon", name of variable is player_party, which is an array of size 6
// so this is an array of six "struct Pokemon" in a row!
Doing something fun:
We'll do our first task since part 1 of this tutorial. We'll be write some code to set current_hp == total_hp, relatively simple.
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/lvNoQrT.png)
This won't actually compile. Can you guess why? It's because the game doesn't know where player_party[6] is located in the ROM. So you need to add it into BPRE.ld. Please add game structures and game functions intro BPRE.ld. Never define them in the function itself.
This function was really short, but there's a few things I introduced here which are new. The first thing is that this is the first function we made that actually had a parameter! "recover_hp" takes a paramater of type u8 called "slot". I intended this parameter to be the slot number of the Pokemon who's HP we set to it's current_hp to max_hp. The second thing to address is how to access members in a struct.
Code:
player_party[slot].current_hp;
Moving on, I'll talk about deferencing members in a struct. Say we have a struct like this:
Code:
struct test_struct {
u16 *var; // pointer to byte string, which is the graphic
};
How would I go about accessing or assigning the value at the member var? Well, it's pretty much as you would guess:
Code:
*test_struct.var;
Now how about if we have a pointer to test_struct and we wanted to access the member var's value? Now this is more interesting, let me show you some code which may result in a similar situation.
Code:
struct test_struct {
u16 *var; // pointer half word
};
struct test_struct *ptr_test;
Code:
ptr_test->var;
Code:
(*ptr_tast).var; //AKA dereferencing the struct first, then accessing the var member
The last thing to talk about in this section is retrieving a pointer to a struct (or variable for that matter). Lets say I have a function like this:
Code:
u32 get_attr(struct Pokemon *, u16 field);
Code:
u8 i = 5;
u8 *ptr_i = &i;
Part 5: Loops in C
This section is going to be relatively short (because I'm going to zoom through it :P).
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/cRb6tcq.png)
This is called a "for loop". The actual for loop follows this syntax:
Code:
for (variable = start_value; condition; what_happens_at_end_of_iteration) {
// contents to execute
}
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/k3b4q83.png)
is the same as:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/HDZvePg.png)
Now lets take at the next main type of loop, it's called a "while loop".
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/ah8WaOs.png)
This is effectively doing the same thing as the for loop in this case. The while loop executes the loop contents while "i < 5" evaluates as a true statement. Note that inside the while loop, we needed to update the pointer to be += 2, but for the for loop we just put it in the loop header.
Actually doing something to FireRed in C: Part 6
Well, it's going to be me doing something, then assigning you guys a task to try for yourselves at a later time :P
Here is our task:
1) Give the player a level 5 Charmander holding an Oran Berry, if it's not their first Pokemon. If it's their first pokemon, we give them Charizard at 36 holding master ball :^)
2) Recieved Pokemon needs to be at half HP
3) Make it's nickname all spaces (0x0), and the last character 0xFF
I think that's rather simple, and at the same time combines everything we've learned pretty much, with some added flair for learning purposes. We're going to keep it simple by assuming that the player's party is not full. This is how the base C file would look like:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/fE3V3P8.png)
This is actually rather bloating of our C file. Wouldn't it be great to put all of this into another file and just #include it? Yes, yes it would be and that's exactly what we'll do. We'll make another reference file to hold all of these function declarations and the structs. We'll call this file, "ugly_stuff.h". Just kidding, lets call it something meaningful like "Pokemon.h" since it'd contain functions and structs dealing with the Pokemon RAM data structure in FireRed. For an example header file, see types.h
Our "Pokemon.h" file contents:
Spoiler:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/EwHqmfq.png)
You might know about header guards, basically it makes it so your file will only be included once. That way you can have "#include filename" in multiple files without causing errors. There is more reasoning behind why we need to use headerguards, but the layman's explanation is that.
Once we've cleared out our main C file, we're left with this:
Spoiler:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/OmzldCZ.png)
Here it is without being filled with comments:
Spoiler:
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/yPYa106.png)
Compile it and try it yourself. You'll need these in your BPRE.ld File though:
Code:
player_party = 0x02024284;
give_pokemon = 0x080A011C|1;
count_pokemon = 0x08040C3C|1;
Cool, right? Let me take the time to explain the "if statement" that I used. If statements are similar to your
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/eS5VbRM.png)
Notice, that if the condition is true, then it'll execute the portion of code called "exec_true", otherwise it'll execute the "exec_false" portion. In no case will both "exec_true" and "exec_false" be executed. This is exactly how the if/else structure works. See
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/GGjZs1n.png)
It is entirely possible for the condition to be comprised of multiple conditions. For example:
Code:
if ((5 < 3) && (6 < 4))
It's also possible to have two or more seperate conditions and an else. We call this an "else if".
![[PokeCommunity.com] Hacking FireRed in C tutorial [PokeCommunity.com] Hacking FireRed in C tutorial](https://i.imgur.com/kPvdaAj.png)
Note, you can have more than one "else if", but only one "if" and one "else" per if statement.
Hacking FR using C: Part 7 (Video tut of something)
Beginner's FireRed C hacking Tutorial Task!
1) Loop through the player's Pokemon
2) If they have a Lapras, give him a rare candy
3) If they don't have a Lapras, give them one, take away some money. 50 should be fine.
4) Upon talking again to this NPC, he should not give you another Lapras, but should keep giving away rare candies
5) We're done with that!
6) You should use callasm to call the function
Post your not-working solutions, and maybe even working solutions in spoilers if you have any!
Last edited: