• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Adding a New Type to the Pokeruby decompilation

6
Posts
5
Years
  • Age 34
  • Seen Apr 24, 2023
Pokeruby is a decompilation of Pokemon Ruby & Sapphire.
ProjectRevoTPP is absolutely certain that this will be the next wave of hacking Pokemon games, so I decided to give it a shot and slap a new type in.

Was it easier than hacking the binary ROM? Well, that depends on your preference. If you can't or refuse to read source code, you might enjoy repointing tables. Personally, I've been doing both for a while, but I think editing the source code is a lot easier.

In this tutorial, I will be adding a Fairy type, include the type image & effectiveness chart.
Here is the result:
2018-10-07-115946_1920x1080_scrot.png


Step 0: Setup Pokeruby
You can follow Revo's tutorial here.
I am using commit 09b8f4c09e69a2359cdf5e4497b97aca3746b8b1 (future commits will most likely be the same unless some things are renamed).

Step 1: Add the new Type Constant
All types have an ID associated with them. We need to put the ID of our new type in two places.

In constants/type_constants.inc:
Code:
	// ...
	.set TYPE_ICE,      0x0f
	.set TYPE_DRAGON,   0x10
	.set TYPE_DARK,     0x11
	.set TYPE_FAIRY,    0x12

In include/pokemon.h:
Code:
// ...
#define TYPE_ICE      0x0f
#define TYPE_DRAGON   0x10
#define TYPE_DARK     0x11
#define TYPE_FAIRY    0x12

Step 2: Adding the Type Name
Next we need to add the name of the type so it shows up properly in the battle screen.

In data/text/type_names.inc:
Code:
	// ...
	.string "ICE$", 7
	.string "DRAGON$", 7
	.string "DARK$", 7
	.string "FAIRY$", 7

Step 3: Adding the Type Effectiveness
Next, we're going to add the effectiveness for our type. This isn't needed, but I doubt you want your type to not do anything special.

The type effectiveness table is in the format
Code:
.byte TYPE_ATTACKING, TYPE_DEFENDING, EFFECTIVENESS
where EFFECTIVENESS is one of
* 0: no effect
* 5: not very effective
* 20: super effective

From what I know, you can use any number here, but these numbers are the standard ones that will display the proper messages.

In data/type_effectiveness.inc:
(this is formatted as a git diff)
Code:
 	.byte TYPE_FIGHTING,     TYPE_ROCK, 20
 	.byte TYPE_FIGHTING,     TYPE_DARK, 20
 	.byte TYPE_FIGHTING,    TYPE_STEEL, 20
+	.byte TYPE_FIGHTING,    TYPE_FAIRY,  5
 	.byte   TYPE_POISON,    TYPE_GRASS, 20
 	.byte   TYPE_POISON,   TYPE_POISON,  5
 	.byte   TYPE_POISON,   TYPE_GROUND,  5
 	.byte   TYPE_POISON,     TYPE_ROCK,  5
 	.byte   TYPE_POISON,    TYPE_GHOST,  5
 	.byte   TYPE_POISON,    TYPE_STEEL,  0
+	.byte   TYPE_POISON,    TYPE_FAIRY, 20
 	.byte   TYPE_GROUND,     TYPE_FIRE, 20
 	.byte   TYPE_GROUND, TYPE_ELECTRIC, 20
 	.byte   TYPE_GROUND,    TYPE_GRASS,  5
@@ -88,6 +90,7 @@ gTypeEffectiveness:: @ 81F9720
 	.byte      TYPE_BUG,    TYPE_GHOST,  5
 	.byte      TYPE_BUG,     TYPE_DARK, 20
 	.byte      TYPE_BUG,    TYPE_STEEL,  5
+	.byte      TYPE_BUG,    TYPE_FAIRY,  5
 	.byte     TYPE_ROCK,     TYPE_FIRE, 20
 	.byte     TYPE_ROCK,      TYPE_ICE, 20
 	.byte     TYPE_ROCK, TYPE_FIGHTING,  5
@@ -102,17 +105,26 @@ gTypeEffectiveness:: @ 81F9720
 	.byte    TYPE_GHOST,    TYPE_GHOST, 20
 	.byte   TYPE_DRAGON,   TYPE_DRAGON, 20
 	.byte   TYPE_DRAGON,    TYPE_STEEL,  5
+	.byte   TYPE_DRAGON,    TYPE_FAIRY,  0
 	.byte     TYPE_DARK, TYPE_FIGHTING,  5
 	.byte     TYPE_DARK,  TYPE_PSYCHIC, 20
 	.byte     TYPE_DARK,    TYPE_GHOST, 20
 	.byte     TYPE_DARK,     TYPE_DARK,  5
 	.byte     TYPE_DARK,    TYPE_STEEL,  5
+	.byte     TYPE_DARK,    TYPE_FAIRY,  5
 	.byte    TYPE_STEEL,     TYPE_FIRE,  5
 	.byte    TYPE_STEEL,    TYPE_WATER,  5
 	.byte    TYPE_STEEL, TYPE_ELECTRIC,  5
 	.byte    TYPE_STEEL,      TYPE_ICE, 20
 	.byte    TYPE_STEEL,     TYPE_ROCK, 20
 	.byte    TYPE_STEEL,    TYPE_STEEL,  5
+	.byte    TYPE_STEEL,    TYPE_FAIRY, 20
+	.byte    TYPE_FAIRY,     TYPE_DARK, 20
+	.byte    TYPE_FAIRY,   TYPE_DRAGON, 20
+	.byte    TYPE_FAIRY, TYPE_FIGHTING, 20
+	.byte    TYPE_FAIRY,     TYPE_FIRE,  5
+	.byte    TYPE_FAIRY,   TYPE_POISON,  5
+	.byte    TYPE_FAIRY,    TYPE_STEEL,  5
 	.byte          0xFE,          0xFE,  0
 	.byte   TYPE_NORMAL,    TYPE_GHOST,  0
 	.byte TYPE_FIGHTING,    TYPE_GHOST,  0

Step 4: The Type Image
Images are super simple to add to the decompilation.

Here's my fairy.png:
fairy.png


I'm using the same palette as the Flying type image. I haven't tried to add a new palette yet.

To build this new image, we need to add it to the Makefile responsible for building the graphics.

In misc.mk:
Code:
types := normal fight flying poison ground rock bug ghost steel mystery fire water grass electric psychic ice dragon dark fairy

This will build, but if you check in game you'll see the wrong palette!
To fix this, we need to change what palette is loaded for our type image.
The code that maps types to image palettes is in src/pokemon_summary_screen.c:
Code:
static const u8 sUnknown_PaletteNums[] = { 0xD, 0xD, 0xE, 0xE, 0xD, 0xD, 0xF, 0xE, 0xD, 0xF, 0xD, 0xE, 0xF, 0xD, 0xE, 0xE, 0xF, 0xD, 0xD, 0xE, 0xE, 0xF, 0xD };

Currently this variable doesn't have a nice name, but essentially it contains a list of palette indexes. The list is indexed by Type IDs.

Code:
TYPE_NORMAL = 0x00 => 0xD
TYPE_FIGHTING = 0x01 => 0xD
TYPE_FLYING = 0x02 => 0xE

We want the palette for the Flying type image, so we want to grab the third number (index of 0x2) from the list, which is 0xE.

Next, we want to add a new number into the list. Our Fairy type has the ID of 0x12, so we want to add a number at index 18 (the 19th number).

This is what the change should look like:
Code:
Original:
static const u8 sUnknown_PaletteNums[] = { 0xD, 0xD, 0xE, 0xE, 0xD, 0xD, 0xF, 0xE, 0xD, 0xF, 0xD, 0xE, 0xF, 0xD, 0xE, 0xE, 0xF, 0xD, 0xD, 0xE, 0xE, 0xF, 0xD };

Changed:
static const u8 sUnknown_PaletteNums[] = { 0xD, 0xD, 0xE, 0xE, 0xD, 0xD, 0xF, 0xE, 0xD, 0xF, 0xD, 0xE, 0xF, 0xD, 0xE, 0xE, 0xF, 0xD, /*FAIRY:*/0xE, 0xD, 0xE, 0xE, 0xF, 0xD };

And that's it! You can try out your new type by changing an existing Pokemon or move.
I changed Tackle to the TYPE_FAIRY and got the result I put above!
If you want a summary of the changes as a git commit, you can view them here.
 
Last edited by a moderator:

Lunos

Random Uruguayan User
3,114
Posts
15
Years
First of all, I have to say you did an amazing work here dude. The tutorial is easy to understand and the changes are well explained.

With that being said, are you sure these are all the changes to get a fully working Fairy type?
In some sort of united effort between Wahackforo, me and some other people in some other place, we also tried to add the Fairy type to Pokeruby almost 2 months ago, and along all the changes you're showing here, we also had to do some other changes that are not being shown in this thread, changes in pokemon_summary_screen.c and changes in the pokedex.c file too.
Click here to read the full post that I wrote in Wahack with all the changes.

With that being said, although the Fairy type itself does work correctly, our implementation showed some issues In-Game:
-The poké ball sprites in the lower left corner of the Pokémon Summary Screen get buggy after the 10th one.
-The Normal and Fighting types sprites can get buggy too.
-Searching for a Fairy type pokémon with the pokédex gives you a lot of irrelevant results. (In this short video, only Jigglypuff should be showing up when searching a Normal-Fairy pokémon, for example.)

Could you confirm if they happen on your end, just in case? I'm curious.
I suppose they could have been fixed automagically with recent commits done to the main Pokeruby repo though, so there's that.
 
Last edited:

Lunos

Random Uruguayan User
3,114
Posts
15
Years
Back
Top