tinix
PearlShipper & C Programmer
- 86
- Posts
- 15
- Years
- Bratislava, Slovakia
- Seen Jun 19, 2021
Hello everybody,
Today I'm going to share my knowledge about how to use C for hacking pokemon roms instead of ASM.
Ive been polishing this method for last few days.
EDIT 16.8.2011: Added updated useful.h with header guard #define, remove .txt extension to use it
Required Tools & Knowledge
----------------------------
Compilation & Usage
------------------------------
EDIT 16.8.2011: Added Optimisation Switches
Action Time 1: Compiling, Using and Explanation of GetPokemonLevel.c
--------------------------------------------------------------------
Action Time 2: Calling Another Function (ASM or C)
-----------------------------------------------
That should be all regarding C & pokemon games :)
If you have any questions post here.
Do not copy without permission.
Thanks to: HackMew for creating ASM compiler package and bat file
Appendix: Pros and cons (if you think you have more say so in comments)
Today I'm going to share my knowledge about how to use C for hacking pokemon roms instead of ASM.
Ive been polishing this method for last few days.
EDIT 16.8.2011: Added updated useful.h with header guard #define, remove .txt extension to use it
Required Tools & Knowledge
----------------------------
Spoiler:
-Basic Knowledge of C (pointers,control statements,functions,structures) (If you don't know C I recommend this tutorial, you can skip ch9 for our purposes and all you need ends with ch10 https://einstein.drexel.edu/courses/Comp_Phys/General/C_basics/, only flaw is that tutorial is missing structures which I also use, see this one for them https://jan.newmarch.name/OS/l5_2.html)
-Basic Scripting Knowledge
-Know how to use command line (google helps here)
-devkitARM https://sourceforge.net/projects/devkitpro/files/devkitARM/ - install this
-CPKMN.zip file created by me, includes HackMews ASM Compiler package.
Zip file includes code samples used by this tutorial.
-Basic Scripting Knowledge
-Know how to use command line (google helps here)
-devkitARM https://sourceforge.net/projects/devkitpro/files/devkitARM/ - install this
-CPKMN.zip file created by me, includes HackMews ASM Compiler package.
Zip file includes code samples used by this tutorial.
Compilation & Usage
------------------------------
EDIT 16.8.2011: Added Optimisation Switches
Spoiler:
To compile your C code into .bin files we will be using arm-eabi-gcc compiler which in default assembles code into GBA/NDS roms.
This is good if you want to make your own GBA/NDS game but not good for what we are doing.
So we will tell compiler to NOT assemble & link files but only do C->ASM conversion.
So instead of using :
arm-eabi-gcc -mthumb -mthumb-interwork -Os -std=c99 %oursource% // std=c99 sets compiler to newest C standard so we can use some C++ style code
we will use:
arm-eabi-gcc -S -mthumb -mthumb-interwork Os -std=c99 -o whatever.asm %oursource% //NOTE: Im not sure if -mthumb -mthumb-interwork is needed here, so I rather left it int, the o switch is there because it defaults to .s extension instead of asm = we would have to rename.
The S switch tells compiler only to change the code into Assembly.
This is where ASM (folder) comes in.
Drag ASM file onto thumb.bat.
Voilà, you have your function compiled into .bin file.
To use it open it in hex editor & copy into free space into your rom.
When using add 1 to offset (so CPU knows it is not ARM code but THUMB) ie. you pasted in into 0x720000, so when you are going to use ie. in script you would write 0x720001.
To use your function in script use callasm 0xyouroffset (DON'T FORGET +1).
That should be all Concerning compilation.
If don't yet understand, don't worry i will show you how to do it with images :)
This is good if you want to make your own GBA/NDS game but not good for what we are doing.
So we will tell compiler to NOT assemble & link files but only do C->ASM conversion.
So instead of using :
arm-eabi-gcc -mthumb -mthumb-interwork -Os -std=c99 %oursource% // std=c99 sets compiler to newest C standard so we can use some C++ style code
we will use:
arm-eabi-gcc -S -mthumb -mthumb-interwork Os -std=c99 -o whatever.asm %oursource% //NOTE: Im not sure if -mthumb -mthumb-interwork is needed here, so I rather left it int, the o switch is there because it defaults to .s extension instead of asm = we would have to rename.
The S switch tells compiler only to change the code into Assembly.
This is where ASM (folder) comes in.
Drag ASM file onto thumb.bat.
Voilà, you have your function compiled into .bin file.
To use it open it in hex editor & copy into free space into your rom.
When using add 1 to offset (so CPU knows it is not ARM code but THUMB) ie. you pasted in into 0x720000, so when you are going to use ie. in script you would write 0x720001.
To use your function in script use callasm 0xyouroffset (DON'T FORGET +1).
That should be all Concerning compilation.
If don't yet understand, don't worry i will show you how to do it with images :)
Action Time 1: Compiling, Using and Explanation of GetPokemonLevel.c
--------------------------------------------------------------------
Spoiler:
NOTE 000: EXAMPLES ARE FOR FIRE RED US V1.0
NOTE 001: Im using LINUX on the images, they serve only for illustration
NOTE 002: Explanation at the end.
Step 1: Compile GetPokemonLevel.c using above command
NOTE 003: if it says unknown command use full path ie. C: \devkitARM\bin\arm-eabi-gcc.exe params
Step 2: Assemble GetPokemonLevel.asm //or whatever .s/asm file it generated
NOTE 004: If you DIDN'T put -o switch there you need to change file extension from .s to .asm
Step 3: Open GetPokemonLevel.bin & your FR rom with hex editor
Step 4: Copy Content of GetPokemonLevel.bin to free space on your FR rom (ie. at 0x720000)
Step 5: Insert this script into your rom & assign it to person
Step 6: Talk to that person and see results!
Code Explanation
-------------------------------------
Ok so what this junk does?
Lets go line by line:
----------------------------------------------------------------
PKMN_DATA* pPKMN_DATA = (PKMN_DATA*) pPKMN_FR;
-----------------------------------------------------------------
PKMN_DATA is structure defined in useful.h which holds data about pokemon.
It is defined as follows
Note, that this order CANNOT be changed because this is the order of data in WRAM (now you know why it is pointer).
So to get data about party I initialize pointer with address of first pokemon.
To get next pokemon add 0x64 (100dec) to the address.
----------------------------------------------------
int* LRESULT = (int*) pLRESULT_FR;
----------------------------------------------------
Pointer to LAST_RESULT variable.
TECHNICAL NOTE: Look into useful.h and on this #define, only if you like messing with offsets
----------------------------------------------------
*LRESULT = pPKMN_DATA->Level;
----------------------------------------------------
assign Level property to last result.
Compatibility note: To change addresses for your game change FR into your games name (LG/R/S/E/E_US in PKMN_DATA, RS/E in LRESULT).
NOTE 001: Im using LINUX on the images, they serve only for illustration
NOTE 002: Explanation at the end.
Step 1: Compile GetPokemonLevel.c using above command
NOTE 003: if it says unknown command use full path ie. C: \devkitARM\bin\arm-eabi-gcc.exe params
Spoiler:
![[PokeCommunity.com] Using C language to hack Pokemon (3rd Gen) [PokeCommunity.com] Using C language to hack Pokemon (3rd Gen)](https://img841.imageshack.us/img841/4687/stepthreed.png)
Step 2: Assemble GetPokemonLevel.asm //or whatever .s/asm file it generated
NOTE 004: If you DIDN'T put -o switch there you need to change file extension from .s to .asm
Step 3: Open GetPokemonLevel.bin & your FR rom with hex editor
Spoiler:
![[PokeCommunity.com] Using C language to hack Pokemon (3rd Gen) [PokeCommunity.com] Using C language to hack Pokemon (3rd Gen)](https://img847.imageshack.us/img847/3264/step8h.png)
Step 4: Copy Content of GetPokemonLevel.bin to free space on your FR rom (ie. at 0x720000)
Step 5: Insert this script into your rom & assign it to person
Code:
#dynamic 0x800000
#org @start
lock
faceplayer
callasm 0xyouroffset //ie. if you inserted at 0x720000 then this would be 0x720001
buffernumber 0x0 lastresult
msgbox @msg MSG_NORMAL
release
end
#org @msg
= Hey, that Pokemon's Level is [buffer1]!
Code Explanation
-------------------------------------
Spoiler:
Code:
#include "useful.h"
void GetMaxLvl()
{
PKMN_DATA* pPKMN_DATA = (PKMN_DATA*) pPKMN_FR;
int* LRESULT = (int*) pLRESULT_FR;
*LRESULT = pPKMN_DATA->Level;
}
Lets go line by line:
----------------------------------------------------------------
PKMN_DATA* pPKMN_DATA = (PKMN_DATA*) pPKMN_FR;
-----------------------------------------------------------------
PKMN_DATA is structure defined in useful.h which holds data about pokemon.
It is defined as follows
Code:
typedef char BYTE;
struct PKMN_DATA_S
{
int Personality;
int OT_ID;
char Nickname[10];
short Language;
char OT_NAME[7];
BYTE Mark;
short Checksum;
short unk1;
BYTE Data[48];
int status_aliment;
BYTE Level;
BYTE pokerus_rem;
short CurHP;
short TotalHP;
short Att;
short Def;
short Speed;
short SpAtt;
short SpDef;
};
typedef struct PKMN_DATA_S PKMN_DATA;
So to get data about party I initialize pointer with address of first pokemon.
To get next pokemon add 0x64 (100dec) to the address.
----------------------------------------------------
int* LRESULT = (int*) pLRESULT_FR;
----------------------------------------------------
Pointer to LAST_RESULT variable.
TECHNICAL NOTE: Look into useful.h and on this #define, only if you like messing with offsets
----------------------------------------------------
*LRESULT = pPKMN_DATA->Level;
----------------------------------------------------
assign Level property to last result.
Compatibility note: To change addresses for your game change FR into your games name (LG/R/S/E/E_US in PKMN_DATA, RS/E in LRESULT).
Action Time 2: Calling Another Function (ASM or C)
-----------------------------------------------
Spoiler:
I wont explain whole source here only this important bit.
Source itself is well documented ;)
This is function pointer. You can only assign functions with same return type and parameters to it.
Normal assignment: pFunc = Function; //this is ok if you are normally linking and compiling
our assignment: pFunc = 0x08ouroffset (+1 one ofc)
You need to change parameters and return type as needed(most ASM functions should have void return).
Compilation Notes: First Compile min_lvl.c then write down its offset and insert it into branch.c at specified place, modify script used in example one with offset of branch.c
Also please note this is only way to link functions together(except for having them in one file)
Source itself is well documented ;)
Code:
int (*pFunc) ();
Normal assignment: pFunc = Function; //this is ok if you are normally linking and compiling
our assignment: pFunc = 0x08ouroffset (+1 one ofc)
You need to change parameters and return type as needed(most ASM functions should have void return).
Compilation Notes: First Compile min_lvl.c then write down its offset and insert it into branch.c at specified place, modify script used in example one with offset of branch.c
Also please note this is only way to link functions together(except for having them in one file)
That should be all regarding C & pokemon games :)
If you have any questions post here.
Do not copy without permission.
Thanks to: HackMew for creating ASM compiler package and bat file
Appendix: Pros and cons (if you think you have more say so in comments)
Spoiler:
Pros:
- much easier than ASM
- no need to mess with registers
- more readable code
Cons:
- A bit larger than your usual ASM routine
- you need to guess types of original game data based on size
- much easier than ASM
- no need to mess with registers
- more readable code
Cons:
- A bit larger than your usual ASM routine
- you need to guess types of original game data based on size
Last edited: