• 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.

Simple Modifications Directory

18,810
Posts
21
Years

Decomp Simple Modifications Directory

This thread is a collection of handy modifications for pokeemerald, pokeruby and pokefirered. Modifications tend to range in both size and scope and cover all different facets of the games. The goal of this collection is to share resources among all fan-game developers while also showcasing to newer developers the ease and benefits of switching to decompilation-based projects.

List of Tutorials / Modifications

For ease of maintenance, the list of tutorials is now listed on the pokeemerald wiki. If you notice a tutorial missing from that list, feel free to edit and add it yourself!

Before submitting


  1. PLEASE make sure your implementation works in an unchanged/vanilla version of the game.
  2. PLEASE try formatting your tutorial for ease of reading. A good format to follow can be seen in Show Type Effectiveness In-Battle by PokemonCrazy.
  3. Choose a place to submit your tutorial. GitHub is preferred, but if you can't use GitHub, you can create a new post in this thread.

After submitting


  1. Please add your tutorial to the list on github. (Or ask somebody who can, like psf on pokecommunity, or members of #pokeemerald in pret.) Adding to the index will help other developers find it quickly and easily.
  2. Publicize your work! Post about it on reddit, Twitter, or discord communities like #pokeemerald in pret or #decomps-disassemblies in PokéCommunity. Spread the good word, & thanks for the contribution! ☺️

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Editing Player PC Items
To change the items the player has in their PC at the start of the game, open "src\player_pc.c" in Notepad++ and find the following:

UMkZYpR.png


Ctrl+F "POTION" to locate it quickly. It's self-explanatory - on the left you have the item and on the right you have the amount. Just make sure you don't accidentally overwrite the "{ ITEM_NONE, 0 }" line. For example, if I wanted my player to have five Sitrus Berries and three Lum Berries in their PC at the beginning of the game, I'd have:

oHNasnM.png


A list of items can be found in "include\constants\items.h"

AwrxxXm.png
 
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Modifying Starter Pokémon
To change the three starters in less than 30 seconds, open "src\starter_choose.c" in Notepad++ and Ctrl+F "TREECKO" to find the following section quickly:

71j4O80.png


You've probably guessed what to do already - just change the species names. If you wanted the Johto starters, you could have:

MWa0Lfb.png


Compile and you're all set.

jI8TFRP.gif
 
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Changing the Beginning Amount of Money
For Pokéemerald, open "src\new_game.c" and look for this line:
Code:
SetMoney(&gSaveBlock1Ptr->money, 3000);
All there is to do is change that amount (3000) to whatever you like. For Pokéruby, it's the same file but this line:
Code:
gSaveBlock1.money = 3000;
 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Editing Default Options Settings
If you open "src\new_game.c" you'll come across this:

L7JcDgm.png


These are the attributes you can change from the "Options" window in the start menu - text speed, the menu frame, battle style (set/shift) etc. Having the text speed automatically set to fast is something I'd recommend to everyone, since going straight to the options menu and changing it is one of the first things a lot of people do in-game!
 
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Changing Birch's Intro Pokémon
Open "src\main_menu.c" and Ctrl+F for "SPECIES_LOTAD". Modify the following lines to change the sprite and cry:

fi8Ipt3.png


OrQG2Cq.png


The Pokémon species list is in "include\constants\species.h". For Pokéruby, substitute the instances of "SPECIES_LOTAD" for "SPECIES_AZURILL". I've changed it to Trapinch, for example:

zv0zRtG.png
 

paccy

Pokeholic
42
Posts
14
Years
Reusable TMs
To make TMs reusable open "src/party_menu.c" and search for the sub_81B6EB4 function.
In it delete the lines
Code:
if (item < ITEM_HM01_CUT)
    RemoveBagItem(item, 1);

If you also want to make TMs unholdable and remove the number from the bag saying how many of each TM you have open "src/data/items.h" and change the .importance number of each TM item from 0 to 1.

KwzzUSm.png
 
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Modifying the Start Location
Open "src\new_game.c"and look for the following section:
Code:
static void WarpToTruck(void)
{
[COLOR="Red"]    SetWarpDestination(MAP_GROUP(INSIDE_OF_TRUCK), MAP_NUM(INSIDE_OF_TRUCK), -1, -1, -1);[/COLOR]
    WarpIntoMap();
}
The line in red is the one we want to make changes to as you could probably already tell. It's self explanatory so it shouldn't need very much breaking down. For instance, let's say we wanted the start map to be Oldale Town. We would have:
Code:
SetWarpDestination(MAP_GROUP(OLDALE_TOWN), MAP_NUM(OLDALE_TOWN), -1, 6, 18);
The above will have the player start in Oldale Town, specifically outside the Pokémon Center. -1 is used for no warp ID, 6, 18 are co-ordinates. Something different, say you wanted the player to start off in the middle of May's room:
Code:
SetWarpDestination(MAP_GROUP(LITTLEROOT_TOWN_MAYS_HOUSE_2F), MAP_NUM(LITTLEROOT_TOWN_MAYS_HOUSE_2F), -1, -1, -1);
Using "-1, -1, -1" as the default does will place the player in the center of the map. That's it!
Oh and to remove the truck animation, again you only have to tweak a single line, this time in "src\overworld.c":
Code:
// gFieldCallback = ExecuteTruckSequence;
 
Last edited:
794
Posts
10
Years
BW Repel

Whenever the Repel's effect wears off, a prompt will appear asking player if they wish to use another one. Similarly to my old pre-decomp implementation, this one also lets you choose which Repel(Regular, Super, Max) to use. Obviously, if you have only one kind, this part is skipped.

Code:
src/script_menu.c DrawMultichoiceMenu
I modified the function, so it works with custom menu options, in ours case Repels ones. Change that part to:
Spoiler:

Now
Code:
data/scripts/repel.inc
Spoiler:

Screenshots:
Spoiler:

I also have the code in my github branch called repel, so you can pull directly from it.
 
Last edited:
794
Posts
10
Years
Money Limit
Spoiler:

Screenshots:
Spoiler:


I also have the code in my github branch called money, so you can pull directly from it.
 
Last edited:

Lunos

Random Uruguayan User
3,114
Posts
15
Years
I'm not entirely sure if I'm going OffTopic here, but while this implementation works perfectly on itself, it introduces one issue.
You can teach a TM to a pokémon, and the PPs for that move slot will refill as the pokémon learns a new move.
This kinda removes the necessity of healing when/if you run out of PPs in some of all of your moves.

ON: Since we're talking about quick modifications, I have to give some love to my favourite ability.

Modifying the table of items of the Pickup ability (Em)
(outside of the Battle Pyramid)


To do this, we're going to open the src\battle_script_commands.c file.
Next, we'll take a look at the sPickupItems variable in the Line 824.
What it contains is a list of the items the Player can obtain with a 4%, 10% or 30% chances every time they faint a pokémon, if a Pickup user is in their party.
fu6K2K3.png


Right after it, we have the variable sRarePickupItems, which similarly, also contains a list of items.
These are the items that the Player has a 1% chance of obtaining, every time they faint a pokémon, if a Pickup user is in their party.
UuEhWSx.png


To modify any of these lists, you simply have to swap the defined item/s that you want to replace with a different one of your liking, save and compile.

Here's a quick video, where I replaced all the common items (those in the 1st list) with Master Balls.


I haven't looked into the separate table used for the Battle Pyramid, so I won't go into details with that one, but it looks fairly simple.
Any curious people can find them (Lv50 and Open) starting from the Line 317 of the src/battle_pyramid.c file.​
 
Last edited:
794
Posts
10
Years
Scrolling Multichoices In Scripts

I was asked to implement this, so here it goes. Just so you know, scrolling lists are already coded in, they're called list menus in pokeemerald. Check out list_menu.h and list_menu.c.

Spoiler:


I also have the code in my github branch called script_multichoice, so you can pull directly from it.
 
Last edited:
49
Posts
5
Years
  • Age 29
  • Seen Dec 27, 2023
Running Indoors (EM)

Simply remove the following from /src/bike.c and you should be able to use your running shoes inside any building.

Inside the file search for:
Code:
bool32 IsRunningDisallowed(u8 metatile)

and delete the following:
Code:
!(gMapHeader.flags & MAP_ALLOW_RUNNING) ||

Thats it, now you should be good to go (or run in this case).


CREDIT:
None needed
 
Last edited:
49
Posts
5
Years
  • Age 29
  • Seen Dec 27, 2023
OUTDATED Surviving poison outside of battle with 1hp
This no longer works, but Lunos has found a fix further down - go check it out!



With just a few steps your pokemon should survive poison on the overworld now with 1hp, like in later gens.

Open the file /src/field_poison.c
Spoiler:


Next open /data/event_scripts.s and add the following to the end of the file:
Spoiler:


Thats it, everything should be done.
 
Last edited:
1
Posts
5
Years
  • Age 28
  • Seen Mar 20, 2019
Skipping the poochyena battle after choosing the starter (pokéemerald)

You can skip the poochyena battle started by the script command "special ChooseStarter" by modifying a few lines in src/battle_setup.c.

In the CB2_GiveStarter function

Spoiler:


In the CB2_StartFirstBattle function

Spoiler:


This modification also adds a graceful transition (a simple fade) to the overworld to avoid glitches. I didn't extensively test this, however since it only affects functions which are used once in the entire game, it should not have any unexpected side-effects.
 
50
Posts
6
Years
  • Age 25
  • Seen Oct 20, 2023
How to force the Battle style [Set|Shift] [EM]

This guide is for you when you want to force the player to play in set or shiftmode. For either the enteire game or just during important matches. ex: Always switch except during gyms matches were you force set.

Old tutorial:
Spoiler:

Edit: I made a small repository for merging here.

To change this style change the gSaveBlock2Ptr->optionsBattleStyle.
 
Last edited:

Delta231

A noob
681
Posts
7
Years
Have PokeBalls loading unique images [EM]

While, I was making my DS-Styled Balls for my Hack I noticed that some Balls loaded same 3rd animation image and only their palette was unique. This modification is for those who have their PokeBalls having different image.

Go to src/pokeball.c and go to function LoadBallGfx. You will find a switch case which would be similar to this
Spoiler:


Just add your own entries by adding
Code:
case BALL_OUR_OWN_BALL:

Save and compile and you are good to go.
 
Last edited:
137
Posts
10
Years
  • Age 35
  • Seen Apr 23, 2024

Remove badge boosts


Modern Pokemon games have done away with badge boosts and instead have the minimum level for obedience increase with every badge you acquire.

Ruby


First, open calculate_base_damage.c and edit the function CalculateBaseDamage by removing the BADGE_BOOST macro and the four lines where it's used.

Code:
#define BADGE_BOOST(badge, stat, bank) ({ \
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER))) \
{ \
    if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER) \
    && gTrainerBattleOpponent != SECRET_BASE_OPPONENT \
    && FlagGet(FLAG_BADGE0##badge##_GET) \
    && GetBattlerSide(bank) == B_SIDE_PLAYER) \
        (stat) = (110 * (stat)) / 100; \
} \
})
Code:
    BADGE_BOOST(1, attack, bankAtk);
    BADGE_BOOST(5, defense, bankDef);
    BADGE_BOOST(7, spAttack, bankAtk);
    BADGE_BOOST(7, spDefense, bankDef);

Next, open battle_2.c and edit the function GetWhoStrikesFirst by removing these two blocks of code.

Code:
    // Only give badge speed boost to the player's mon.
    if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) && FlagGet(FLAG_BADGE03_GET) && GetBattlerSide(bank1) == 0)
        bank1AdjustedSpeed = (bank1AdjustedSpeed * 110) / 100;
Code:
    // Only give badge speed boost to the player's mon.
    if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) && FlagGet(FLAG_BADGE03_GET) && GetBattlerSide(bank2) == 0)
    {
        bank2AdjustedSpeed = (bank2AdjustedSpeed * 110) / 100;
    }

Finally, open battle_util.c and edit the function IsMonDisobedient. You should be able to find this section of code.

Code:
	if (FlagGet(FLAG_BADGE02_GET))
	    obedienceLevel = 30;
	if (FlagGet(FLAG_BADGE04_GET))
	    obedienceLevel = 50;
	if (FlagGet(FLAG_BADGE06_GET))
            obedienceLevel = 70;

How badge boosts correspond to increases in the minimum obedience level is up to you. As an example, here's how obedience works in Omega Ruby/Alpha Sapphire, Gen 7 and the Let's Go games. (For X/Y-style obedience, increase all these values by 10.)

Code:
	if (FlagGet(FLAG_BADGE01_GET))
	    obedienceLevel = 20;
	if (FlagGet(FLAG_BADGE02_GET))
	    obedienceLevel = 30;
	if (FlagGet(FLAG_BADGE03_GET))
	    obedienceLevel = 40;
	if (FlagGet(FLAG_BADGE04_GET))
	    obedienceLevel = 50;
	if (FlagGet(FLAG_BADGE05_GET))
	    obedienceLevel = 60;
	if (FlagGet(FLAG_BADGE06_GET))
            obedienceLevel = 70;
	if (FlagGet(FLAG_BADGE07_GET))
	    obedienceLevel = 80;

Emerald


First, open pokemon.c and edit the function CalculateBaseDamage by removing the ShouldGetBadgeBoost function and the eight lines of code that use it.

Code:
static bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battlerId);
Code:
    if (ShouldGetStatBadgeBoost(FLAG_BADGE01_GET, battlerIdAtk))
        attack = (110 * attack) / 100;
    if (ShouldGetStatBadgeBoost(FLAG_BADGE05_GET, battlerIdDef))
        defense = (110 * defense) / 100;
    if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerIdAtk))
        spAttack = (110 * spAttack) / 100;
    if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerIdDef))
        spDefense = (110 * spDefense) / 100;
Code:
static bool8 ShouldGetStatBadgeBoost(u16 badgeFlag, u8 battlerId)
{
    if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER))
        return FALSE;
    else if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
        return FALSE;
    else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gTrainerBattleOpponent_A == TRAINER_SECRET_BASE)
        return FALSE;
    else if (FlagGet(badgeFlag))
        return TRUE;
    else
        return FALSE;
}

Next, open battle_main.c and edit the function GetWhoStrikesFirst. There are two blocks of seven lines of code with the comment "badge boost"; remove them.

Code:
    // badge boost
    if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER))
        && FlagGet(FLAG_BADGE03_GET)
        && GetBattlerSide(battler1) == B_SIDE_PLAYER)
    {
        speedBattler1 = (speedBattler1 * 110) / 100;
    }
Code:
    // badge boost
    if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER))
        && FlagGet(FLAG_BADGE03_GET)
        && GetBattlerSide(battler2) == B_SIDE_PLAYER)
    {
        speedBattler2 = (speedBattler2 * 110) / 100;
    }

Finally, open battle_util.c and edit the function IsMonDisobedient. You should be able to find this section of code.

Code:
        if (FlagGet(FLAG_BADGE02_GET))
            obedienceLevel = 30;
        if (FlagGet(FLAG_BADGE04_GET))
            obedienceLevel = 50;
        if (FlagGet(FLAG_BADGE06_GET))
            obedienceLevel = 70;

How badge boosts correspond to increases in the minimum obedience level is up to you. As an example, here's how obedience works in Omega Ruby/Alpha Sapphire, Gen 7 and the Let's Go games. (For X/Y-style obedience, increase all these values by 10.)

Code:
        if (FlagGet(FLAG_BADGE01_GET))
            obedienceLevel = 20;
        if (FlagGet(FLAG_BADGE02_GET))
            obedienceLevel = 30;
        if (FlagGet(FLAG_BADGE03_GET))
            obedienceLevel = 40;
        if (FlagGet(FLAG_BADGE04_GET))
            obedienceLevel = 50;
        if (FlagGet(FLAG_BADGE05_GET))
            obedienceLevel = 60;
        if (FlagGet(FLAG_BADGE06_GET))
            obedienceLevel = 70;
        if (FlagGet(FLAG_BADGE07_GET))
            obedienceLevel = 80;
 
Last edited:
137
Posts
10
Years
  • Age 35
  • Seen Apr 23, 2024

Change the limbo slots' hardcoded Unown cry


First, open the file pokemon_3.c (Ruby)/pokemon.c (Emerald) and find the function SpeciesToCryId. Remove the two if statements and alter the final line such that the function looks like this.

Code:
u16 SpeciesToCryId(u16 species)
{
    return gSpeciesIdToCryId[species];
}

Now extend the list gSpeciesIdToCryId in cry_ids.h to include BULBASAUR through OLD_UNOWN_Z. To replicate the vanilla experience the first 251 entries (Bulbasaur through Celebi) should be the National Pokédex number of that Pokémon minus one; after that are 26 copies of the value 200 for the limbo slots.
 
794
Posts
10
Years
Nature-affected stats colouring

I used the color red with light and dark shade to signify stat affected negatively and positively respectively. If you wish to use different colors, just modify the sTextNatureDown and sTextNatureUp strings, more specifically the byte value after {COLOR} special character.
Code:
src/pokemon_summary_screen.c
Changes include functions in range BufferLeftColumnStats - BufferRightColumnStats.
Spoiler:

Screenshot:
Spoiler:

I also have the code in my github branch called nature_color, so you can pull directly from it.
 
Last edited:
Back
Top