PHO - Pokémon Hackers Online
Go Back   PHO - Pokémon Hackers Online > Hacking Suite > Resources and Tutorials > Generation 3 (Disassembly)

Notices

Generation 3 (Disassembly) If you hack Generation 3 with pokeruby, pokeemerald or any other disassembly of RSE/FRLG then this is for you!

User Tag List

Reply
 
Thread Tools Display Modes
Old 2nd March 2018, 10:16 PM   #1
ProjectRevoTPP
Newbie
 
Join Date: Mar 2018
Posts: 1
ProjectRevoTPP
Default Setting up and using Pokeruby/Pokeemerald

Setting up and using Pokeruby/Pokeemerald


Part 0: An Introduction
Spoiler:

I'm sure you've all heard of the recent gen 3 disassemblies and want to use them. That's good: but I'm sure an equal portion of you are on Windows and don't know how to make salad from scratch. So, how do you use pokeruby to make changes to things such as the code itself and what advantages does it offer me over traditional binary hacking, I hear you ask?

I'm glad you asked, but first we need to go over traditional methods of hacking gen 3.

1. Pre-Existing Tools
Currently, changing things in ROM requires just that: directly editing a ROM. The thing is though that pointers and data itself cant be moved without moving it to free space in the ROM, and whatever pointed there needs to be repointed by hand, manually, in order to avoid issues. This is particularly annoying if you're making a lot of changes.

2. Compiled C Injection
So what if you want to add new code? Well, you could write some C and compile it into ARM and thumb, and then manually change the pointers in your code to direct at the correct ROM data and redirect anything to use your new function. Still sounds very annoying? Well, lets talk about how this ROM was assembled in the first place.

The Pokemon games, in Game Freak's original source, were written in a programming language called C - specifically C90, a version of C published in 1990. This means all the data and code that make up the ROM were written in separate human-readable C files. These files are then run through a compiler to generate machine code. This machine code output is all joined together using a tool called a linker, which figures out how to combine these fragments into the final output (the ROM). This linking process determines the final offsets and recalculates every pointer for all the data and code automatically, meaning you don't have to keep track of the locations of data, only the labels given to that data.

By reversing this process, we can translate all the pointers and binary data (that you'd edit in a hex editor or another tool) back into human-readable C. This means that we can repeat the compiling and linking processes to get a modified ROM, but maintain the flexibility of being able to work with labeled data and code.

What is compilation you ask?

Compilation is the process that takes a higher level language and compiles it into assembly so the computer can understand and execute the instructions. This can be used for a number of reasons: but the main one here is that it makes a programmer's job easier when all they have to deal with is the higher level language and not things like register balancing and reallocation by hand.

There are a number of compiler/developer environments, but the one we will be using for this tutorial is Cygwin and thus assumes you have Windows at the moment. (Sorry Linux and Mac)

Part 1: Setting up and using Cygwin (Skip this if you already have Cygwin and it has the git and make packages, or you have an environment like this already setup)
Spoiler:

What is Cygwin?
From Google: Cygwin is a Unix-like environment and command-line interface for Microsoft Windows. Cygwin provides native integration of Windows-based applications, data, and other system resources with applications, software tools, and data of the Unix-like environment.

Where do I get Cygwin?
Google it. I'm a new user, so I can't post links.

Which version do I pick? x86 or x86-64?
Depending on your operating system if it's 32-bit or 64-bit, pick the version appropriate.

Download the version you need and install it following its instructions. I recommend using a path such as
Code:
C:/cygwin
but it is up to you. For this tutorial we will be assuming it is at C:/cygwin, but use your own path. Once Cygwin is installed, run cygwin once and close out of it. This step is important. Run cygwin's setup again to install the "git" and "make" packages. You need these to compile pokeruby.

Follow the instructions here:
1] Select "Full" from the drop down menu on Cygwin Package Mansger.
2] Using the search bar, search for "git" and click the "Skip" on the row git is on to change it to a version number. This tells Cygwin to install the package. Bin will be checked to the right of it letting you know it will install this package. Note: git isn't (technically) required to compile pokeruby/pokeemerald, but the tutorial assumes you have it otherwise. You can use Download ZIP, although from experience it's a little less reliable. The tutorial recommends you fetch the source using git, hence this step.
3] Do the same thing for make. In this screenshot it doesn't show it checked; don't worry about that. Just install it like the one in the screenshot above. Click Next once you checked both packages to and follow the steps to install the packages.

Once that's done, Cygwin should be good to go, but we still need to setup devkitpro before we can compile pokeruby.

Part 2: Setting up Devkitpro and linking it with Cygwin (only applicable if you installed Cygwin)
Spoiler:

What is devkitpro?
From the devkitpro wiki: devkitPro is the vendor of a number of cross compilers intended for use by hobby programmers writing their own games and applications for popular games consoles where it's possible to run unsigned code. The goal is to provide amateur programmers with the means to program for resource limited devices and so gain valuable experience which would transfer well to a career in game development.

Where do I get devkitpro?
Google it. I can't post links as a new user.

One important note: If you already have devkitpro, make sure your version is r46 or later, or else pokeruby won't match when compiling!

It is strongly recommended you install devkitpro to C:/devkitpro to avoid confusion. The tutorial will assume this is the path of devkitpro, but it can be anything.

Do not forget to run cygwin once and close out of it to generate the home user files or else this bashrc adjustment will fail to recognize devkitpro!

Once you install devkitpro, we need to link it with cygwin. Open C:\cygwin32\home\(username)\.bashrc . If you do not have this file, remember to run cygwin once and let it generate these files. Be sure to use an editor to set it to Unix line endings (in notepad++, Edit > EOL Conversion > Unix) or else funny stuff will happen.

If you already have a bashrc, add:

Code:
export DEVKITPRO=/cygdrive/c/devkitPro
export DEVKITARM=$DEVKITPRO/devkitARM
...to the end of bashrc. let the "c/devkitPro" be your path to devkitPro if you do not have it at C:/devkitPro.

Close out of cygwin and reopen it. Devkitpro should now be configured correctly.

Part 3: Setting up Pokeruby/Pokeemerald
Spoiler:

We're now actually going to setup Pokeruby or Pokeemerald for compilation on Windows. We need to choose a folder to be our working folder; for this tutorial, we will be using C:/pokeruby as an example. Use C:/pokeemerald if you prefer that instead. Please note that you can use anywhere to do it.

Make the folder at the location, (alternatively you can switch to one folder above with cd and use mkdir (folder) to make it), and do the following commands:

Code:
cd C:/<your folder here>
git init
git remote add origin (your git link here)
git pull origin master
Note: you can use git clone to retrieve it alternatively, but this is the method I use since its more precise.

If you are on Windows and don't want to bother with compiling the tools and agbcc needed to compile pokeruby/pokeemerald (which I assume is most of you), visit the pokeruby-tools repo on pret's Github and download the ZIP. Overwrite tools/ with the one in the zip. agbcc.exe's path should be
Code:
pokeruby/tools/agbcc/agbcc.exe
, with similar paths for the other tools.

Finally, we are ready to build.

Type
Code:
make compare
to build, which will build the ROM and then compare its sha1 hash to the original to make sure it matches. If all goes well, you should see this at the end: Note: you can add -jN to the make command where N is the number of extra threads you want to use when compiling. If you have a good PC, you can take advantage of this for faster compile times. For example, I use -j16, but you might use -j4.

The disassembly make take many minutes to compile: be patient. I have heard of 15 minute compile times before, but the disassembly takes around 2-3 minutes for me for a clean build. It will take even longer if you are building pokeemerald.

Code:
pokeruby.gba: OK
or
Code:
pokeemerald.gba: OK
A .gba file has appeared in your folder where one didn't exist before. Congrats, you have built the disassembly into a ROM! Now lets practice making changes to it: in particular, a change to the pokedex code.

Part 4: Making changes and test them
Spoiler:

Here is the part of the guide where we're going to do a single change to how the game works. If you only wanted to know how to build the ROM and that's it - you can stop reading now. This section applies to pokeruby only, but the same principle of making code changes applies regardless of the dissassembly.

The change we have in mind is a simple one: change the pokedex so that when you use AREA mode, it plays a sound effect if the Pokemon you are looking at is in the same room you are. We need to insert a flag that says the game is currently in the Pokedex area screen, however, because pokeruby doesn't quite have all RAM Labeled yet, we need to use a hack to ensure we don't shift RAM. (Although all of pokeruby's ROM pointers are labeled and repoint correctly: there's still a few holdout RAM addresses that haven't been labeled yet [specifically in the battle scripts] as of the writing of this)

Make a new file called "pokedex_flag.c" and have it look like:

Code:
#include "global.h"

EWRAM_DATA bool8 gPokedexAreaScreenFlag = {0};
To note, make sure the file is saved in Unix line endings like you did earlier in notepad++, and the file has to have an extra new line.

Add
Code:
.include "src/pokedex_flag.o"
to the end of sym_ewram.txt so the game sees the new flag. Save the txt file.

Now that we have the hack out of the way, we can get to the real meat of the change itself. Lets think about it for a second: in order to play a sound if a Pokemon is in the same room you are, we first need to add a function which takes a species as input and returns TRUE or FALSE. Lets open wild_encounter.c to do that: the reason we need to put the function in wild_encounter.c is mainly that the structs used in the check are also declared in the same file - so it has to be here.

This tutorial wont teach you how to write C: There's other ones out there that can do better than I, so lets write the function:

Code:
#define NUM_GRASS_SLOTS 12
#define NUM_WATER_SLOTS 5
#define NUM_ROCK_SLOTS 5
#define NUM_FISHING_SLOTS 10

bool8 IsMonInLocalArea(u16 species)
{
    u8 i;
    u16 headerNum = GetCurrentMapWildMonHeader();
    struct WildPokemonInfo *landMonsInfo = gWildMonHeaders[headerNum].landMonsInfo;
    struct WildPokemonInfo *waterMonsInfo = gWildMonHeaders[headerNum].waterMonsInfo;
    struct WildPokemonInfo *rockSmashMonsInfo = gWildMonHeaders[headerNum].rockSmashMonsInfo;
    struct WildPokemonInfo *fishingMonsInfo = gWildMonHeaders[headerNum].fishingMonsInfo;

    if(headerNum == 0xFFFF)
        return FALSE;

    // do grass check.
    if(landMonsInfo != NULL)
    {
        for(i = 0; i < NUM_GRASS_SLOTS; i++)
            if(landMonsInfo->wildPokemon[i].species == species)
                return TRUE;
    }

    // do water check.
    if(waterMonsInfo != NULL)
    {
        for(i = 0; i < NUM_WATER_SLOTS; i++)
            if(waterMonsInfo->wildPokemon[i].species == species)
                return TRUE;
    }

    // do rock smash check.
    if(rockSmashMonsInfo != NULL)
    {
        for(i = 0; i < NUM_ROCK_SLOTS; i++)
            if(rockSmashMonsInfo->wildPokemon[i].species == species)
                return TRUE;
    }

    // do fishing check.
    if(fishingMonsInfo != NULL)
    {
        for(i = 0; i < NUM_FISHING_SLOTS; i++)
            if(fishingMonsInfo->wildPokemon[i].species == species)
                return TRUE;
    }

    return FALSE;
}
Add this to the end of wild_encounters.c. This code gets the map header of the player, fetches all 4 structs of the wild encounter data of the current map (regardless if NULL or not), then checks each struct one by one. If any of them have a matching species, the function will return TRUE. Makes sense, right?

Now that we're done, save the file (remember the newline at the end of every file is needed) and open up pokedex.c. The two functions we need to change are Task_InitAreaScreenMultistep and Task_AreaScreenProcessInput . Because pokedex_area_screen isn't decompiled yet (at the time of writing this), this is why we need the boolean flag.

First, add:

Code:
extern bool8 gPokedexAreaScreenFlag;
extern bool8 IsMonInLocalArea(u16 species);
before Task_InitAreaScreenMultistep. This tells the file where to find those two things so they can be called.

Add:

Code:
gPokedexAreaScreenFlag = TRUE;
...right after case 2 and before ShowPokedexAreaScreen is called in Task_InitAreaScreenMultistep. this will tell a later function to execute the check once, which sets the flag back to 0.

In Task_AreaScreenProcessInput, this function checks a flag to see if its no longer 0, and then puts a function on the task func to execute. This function is executed every frame while the Area screen is active, so we need the Area check to be here.

Insert:

Code:
    if(gPokedexAreaScreenFlag == TRUE)
    {
        if(IsMonInLocalArea(NationalPokedexNumToSpecies(gUnknown_0202FFBC->dexNum)) == TRUE)
            PlaySE(SE_C_PIKON);

        gPokedexAreaScreenFlag = FALSE;
    }
Note: gUnknown_0202FFBC may have been relabeled since this tutorial. You may need to update that label. Do a
Code:
git grep 202FFBC pokeruby.map
to find the new label after you have already compiled once.

...before the check. If "songs.h" is not already included at the top of pokedex.c, please add it via
Code:
#include "songs.h"
. Save the file and recompile the rom with "make" (dont use compare, as the ROM definitely wont match now, but that's not the point now). Use -jN if you want. Test your ROM and try to view the Pokedex area screen of a Pokemon that is in the route/cave you are in, for example, Poochyena in Route 101. You should hear the jingle, which means you succeeded!


Conclusion:

You'll be able to make code changes with the disassembly similar to this fashion. To note: pokeruby nor pokeemerald is not ready for production yet, obviously, but this tutorial will teach you how to use it on a most basic level. Although this does and will open up gen 3 tremendously: there is much work to be done; we need to work more on pokefirered sometime down the line. Hopefully, now that you know how to setup the dissassemblies, you know how to make changes and eventually contribute to our cause. Thanks for reading.

Last edited by Alice; 2nd March 2018 at 11:24 PM.
ProjectRevoTPP is offline   Reply With Quote
Likes Deokishisu, Adrevi liked this post
Sponsored Links
Old 2nd March 2018, 11:17 PM   #2
Pia Carrot
Orange Developer
Administrator
 
Pia Carrot's Avatar
 
Join Date: Aug 2010
Location: Valencia Island
Age: 23
Posts: 811
Pia Carrot Pia Carrot Pia Carrot Pia Carrot Pia Carrot
Default

Great start for the subforum, I've gone ahead and stickied the thread.
Pia Carrot is offline   Reply With Quote
Reply

Tags
pokeruby or pokeemerald, setting, [Tutorial]

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 07:08 PM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2018, vBulletin Solutions, Inc. User Alert System provided by Advanced User Tagging (Lite) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Feedback Buttons provided by Advanced Post Thanks / Like (Lite) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Pokémon characters and images belong to Pokémon USA, Inc. and Nintendo.
Pokémon Hackers Online (PHO) is in no way affiliated with or endorsed by Nintendo LLC, Creatures, GAMEFREAK inc,
The Pokémon Company, Pokémon USA, Inc., The Pokémon Company International, or Wizards of the Coast.
All forum/site content (unless noted otherwise) and site designs are © 2006-2013 Pokémon Hackers Online (PHO).
Green Charizard Christos TreeckoLv100

"Black 2" by ARTPOP. Kyurem artwork by XOUS.

no new posts