• Just a reminder that providing specifics on, sharing links to, or naming websites where ROMs can be accessed is against the rules. If your post has any of this information it will be removed.
  • Ever thought it'd be cool to have your art, writing, or challenge runs featured on PokéCommunity? Click here for info - we'd love to spotlight your work!
  • Our weekly protagonist poll is now up! Vote for your favorite Conquest protagonist in the poll by clicking here.
  • 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

[Pokeemerald] Rock Climb

This adds the gen 4 rock climb field effect to scale cliffs.

[PokeCommunity.com] Simple Modifications Directory
[PokeCommunity.com] Simple Modifications Directory


How to add:
How to use:
  • Give your rock-climbable metatile the MB_ROCK_CLIMB behavior. That's it!

Please report any bugs.
 
[PokeEmerald] Grindrunning For Easier Diagonal Movement​
[PokeCommunity.com] Simple Modifications Directory

Causes the player to automatically turn left/right when running
into a wall. Thus "grinding" against any walls they press
against. This makes diagonal paths in level design much more
viable by removing the need for extra player inputs.

How to use:
  • Add the code to your pokeemerald decomp as described below.
  • Have the player run into walls that have diagonal free space
  • Never stop running!
  • Only sheer walls and small crevices will stop you!

How to add:
 
[Pokeemerald] Give Custom Mon

This adds a scripting command to give a completely custom pokemon, including evs, ivs, ability, nature, shininess, and moves.

[PokeCommunity.com] Simple Modifications Directory


Usage:
  • Use this very large scripting command.
    Code:
        .macro givecustommon species:req, level:req, item, ball, nature, abilityNum, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, isShiny
  • You can use arguments up to the last one you want customized. eg:
    Code:
    givecustommon SPECIES_TORHIC, 5, ITEM_NONE, ITEM_PREMIER_BALL, NATURE_ADAMANT, 1
  • Alternatively, create new macros for simpler scripting. eg: (this example is already in the repo)
    Code:
        .macro givemonmoves species:req, level:req, move1:req, move2:req, move3:req, move4:req
        customgivemon \species, \level, 0, 0, NUM_NATURES, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \move1, \move2, \move3, \move4, 0
        .endm

How to add:
Please report any bugs!
 
Last edited:
You can use arguments up to the last one you want customized.

The AS manual reckons you can pass arguments by name:
When you call a macro, you can specify the argument values either by position, or by keyword. For example, `sum 9,17' is equivalent to `sum to=17, from=9'.
Which is probably a better way to use the macro? From a quick check, things compile if you specify later parameters by name but not earlier ones, so I assume it works out fine.
 
Showing IVs/EVs in Summary Screen [EM]

In the
Code:
BufferIvOrEvStats
function, you need to change to a larger integer type for the stats (hp, hp2, atk, def, spA, spD, spe) or else you'll run into issues with stats above 255. The example uses u8, I changed mine to u32 as that's what the BufferStat function uses.
 
In the
Code:
BufferIvOrEvStats
function, you need to change to a larger integer type for the stats (hp, hp2, atk, def, spA, spD, spe) or else you'll run into issues with stats above 255. The example uses u8, I changed mine to u32 as that's what the BufferStat function uses.

You are completely right! My apologies. I changed u8 to u16 and changed the variable declaration at the top to use DYNAMIC instead of SPECIAL. Thank you!
 
Pokemerald: Change bag sound with the ones from FR

FR made the scroll in the bag less annoying by making it's own sound. In emerald we have all the FR sounds, so this is a pretty easy task.
In item_menu.c, in the function BagMenu_MoveCursorCallback, we replace SE_SELECT with SE_RG_BAG_CURSOR

We also have a new sound when switching pockets, let's change that as well.
In the function GetSwitchBagPocketDirection we replace SE_SELECT with SE_RG_BAG_POCKET
 
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.

[PokeCommunity.com] Simple Modifications Directory

By the way, if you're going to do this, you will want to make TMs unsellable, else a player could find themselves permanently selling their TM.

You COULD do this by setting .price to 0, but any TM shops would then sell that TM for free. And we don't want that.

So under void Task_ItemContext_Sell(u8 taskId):
Change if (ItemId_GetPrice(gSpecialVar_ItemId) == 0) to if ((ItemId_GetPrice(gSpecialVar_ItemId) == 0) || gBagPositionStruct.pocket == TMHM_POCKET):
Code:
void Task_ItemContext_Sell(u8 taskId)
{
    s16* data = gTasks[taskId].data;

    if ((ItemId_GetPrice(gSpecialVar_ItemId) == 0) || gBagPositionStruct.pocket == TMHM_POCKET)
    {
        CopyItemName(gSpecialVar_ItemId, gStringVar2);
        StringExpandPlaceholders(gStringVar4, gText_CantBuyKeyItem);
        DisplayItemMessage(taskId, 2, gStringVar4, BagMenu_InitListsMenu);
    }
    else
    {
[…]

This bars the player from selling anything inside the TM pocket.
 
Obtain exp. points per catch [EM/FR]

Starting from Pokémon X and Y for the 3DS, your Pokémon obtains experience if a battle ends by having you catch an opposing Pokémon.
This feature was implemented by DizzyEgg in his battle_engine_v2 for Pokeemerald.

I ported it some time ago to Pokefirered, and I remembered I never really posted it here, so I decided to reimplement it in a clean repository and from there I ported it to a clean copy of Pokeemerald, because why not.
The changes are exactly the same in both repositories.
https://github.com/pret/pokeemerald/compare/master...LOuroboros:pokeemerald:exp_per_catch
https://github.com/pret/pokefirered/compare/master...LOuroboros:pokefirered:exp_per_catch

Quick Showcase:
[PokeCommunity.com] Simple Modifications Directory
[PokeCommunity.com] Simple Modifications Directory


EDIT (22/05/2023): I updated both branches. I fixed a couple of issues in the Pokeemerald port reported to me by Restes#8110, and added a couple of missing things to the Pokefirered port.

And that's pretty much it.​
 
Last edited:
[Emerald] Managing trainer Rematches in Emerald

Remove the need of FLAG_HAS_MATCH_CALL flag
This one is pretty easy to understand. To get rematches we need that flag enabled. I will remove it.
In src/battle_setup.c, we remove the check in RegisterTrainerInMatchCall, leaving it like this:
Code:
static void RegisterTrainerInMatchCall(void)
{
    u32 matchCallFlagId = GetTrainerMatchCallFlag(gTrainerBattleOpponent_A);
    if (matchCallFlagId != 0xFFFF)
        FlagSet(matchCallFlagId);
}
Then, in src/match_call.c, we also remove it in the TryStartMatchCall function.
Code:
bool32 TryStartMatchCall(void)
{
    if (UpdateMatchCallStepCounter() && UpdateMatchCallMinutesCounter()
     && CheckMatchCallChance() && MapAllowsMatchCall() && SelectMatchCallTrainer())
    {
        StartMatchCall();
        return TRUE;
    }

    return FALSE;
}

Removing the 31% chance of getting a rematch
In src/battle_setup.c, in the function UpdateRandomTrainerRematches we just delete the random, leaving the function like this:
Code:
static bool32 UpdateRandomTrainerRematches(const struct RematchTrainer *table, u16 mapGroup, u16 mapNum)
{
    s32 i;
    bool32 ret = FALSE;

    for (i = 0; i <= REMATCH_SPECIAL_TRAINER_START; i++)
    {
        if (table[i].mapGroup == mapGroup && table[i].mapNum == mapNum && !sub_80B1D94(i))
        {
            if (gSaveBlock1Ptr->trainerRematches[i] != 0)
            {
                // Trainer already wants a rematch. Don't bother updating it.
                ret = TRUE;
            }
            else if (FlagGet(FLAG_MATCH_CALL_REGISTERED + i))
            {
                SetRematchIdForTrainer(table, i);
                ret = TRUE;
            }
        }
    }

    return ret;
}

Removing the fifht badge requirement
In src/battle_setup.c, we remove the HasAtLeastFiveBadges function.
Then we remove the check in the functions IncrementRematchStepCounter and IsRematchStepCounterMaxed, leaving them like this:
Code:
void IncrementRematchStepCounter(void)
{
        if (gSaveBlock1Ptr->trainerRematchStepCounter >= STEP_COUNTER_MAX)
            gSaveBlock1Ptr->trainerRematchStepCounter = STEP_COUNTER_MAX;
        else
            gSaveBlock1Ptr->trainerRematchStepCounter++;
}

static bool32 IsRematchStepCounterMaxed(void)
{
    if (gSaveBlock1Ptr->trainerRematchStepCounter >= STEP_COUNTER_MAX)
        return TRUE;
    else
        return FALSE;
}

Removing overworld pokenav calls
Example of what are we going to remove:
[PokeCommunity.com] Simple Modifications Directory


In src/match_call.c, we will make the function TryStartMatchCall always return FALSE, so we leave it like this:
Code:
bool32 TryStartMatchCall(void)
{
    return FALSE;
}

Removing the trainer registered script
Example of what are we going to remove:
[PokeCommunity.com] Simple Modifications Directory


In data/scripts/trainer_script.inc, we leave the Std_RegisteredInMatchCall script like this:
Code:
Std_RegisteredInMatchCall:: @ 82742C9
    return

Making your own rematchable scripts
You can use the vanilla ones from emerald, but there are some early trainers that have the FLAG_HAS_MATCH_CALL flag check, so you have to remove it from those.
And example would be turn this script
Code:
Route116_EventScript_TryRegisterJerryAfterBattle:: @ 81F2EF8
	goto_if_set FLAG_HAS_MATCH_CALL, Route116_EventScript_RegisterJerryAfterBattle
	release
	end
into this one
Code:
Route116_EventScript_TryRegisterJerryAfterBattle:: @ 81F2EF8
	goto FLAG_HAS_MATCH_CALL, Route116_EventScript_RegisterJerryAfterBattle

Otherwise, I have a poryscript example of a rematchable trainer, with some nice comments to help you understand it:
Code:
script Route104_EventScript_Haley_Pory {
	trainerbattle_single(TRAINER_HALEY_1, Route104_Text_HaleyIntro, Route104_Text_HaleyDefeat, Route104_EventScript_TryRegisterHaleyAfterBattle_Pory)
	specialvar(VAR_RESULT, ShouldTryRematchBattle) // Check if we should rematch her
    if (var(VAR_RESULT) == TRUE) { // If so we rematch her 
        	trainerbattle_rematch(TRAINER_HALEY_1, Route104_Text_HaleyRematchIntro, Route104_Text_HaleyRematchDefeat)
            msgbox(format( // This is the postbattle message
                "I made the decision to battle, so\n"
                "I can accept this loss with grace.\p"
                "I am still upset about losing!$"
            ), MSGBOX_AUTOCLOSE)
            end
    } else {
        setvar(VAR_0x8004, TRAINER_HALEY_1) // We save the trainer ID to a var
        specialvar(VAR_RESULT, IsTrainerRegistered) // We check if we have the trainer registered
        if (var(VAR_RESULT) == FALSE) { // If we don't have it registered...
                call(register_her) // We go and we register her!
        } else { // Otherwise he just show us postbattle message
            msgbox(format(
                "If you're faced with a decision and\n"
                "you let someone else choose for you,\l"
                "you will regret it, however things\l"
                "turn out.$"
            ), MSGBOX_DEFAULT)
        }
        release
        end
    }
}

text Route104_Text_HaleyIntro {
	"Should I…\n"
	"Or shouldn't I?\p"
	"Okay, sure, I will battle!$"
}

text Route104_Text_HaleyDefeat {
	"I shouldn't have battled…$"
}

text Route104_Text_HaleyRematchIntro {
	"Come on, battle with me!$"
}

text Route104_Text_HaleyRematchDefeat {
	"Ohh…\n"
	"I thought I could win…$"
}

script Route104_EventScript_TryRegisterHaleyAfterBattle_Pory {
	special(PlayerFaceTrainerAfterBattle)
	waitmovement(0)
    call(register_her)
    release
    end
}

script register_her {
    msgbox(format(
        "You're strong, but should I register\n"
        "you in my POKéNAV?\l"
        "Maybe I shouldn't…\p"
        "Okay, sure, I will register you!$"
    ), MSGBOX_DEFAULT)
    register_matchcall(TRAINER_HALEY_1)
    return
}
 
[Emerald] Move camera to a coordinates and return camera to the player specials.

Credit to Spherical Ice! I'm just sharing (I got his permission!)

[PokeCommunity.com] Simple Modifications Directory


In include/field_camera.h we declare our new functions, adding them under void FieldUpdateBgTilemapScroll(void);
Code:
void MoveCameraAndRedrawMap(int deltaX, int deltaY);
void UpdateSavedPos(void);

Now, in src/field_camera.c, in the function MoveCameraAndRedrawMap we can remove this comment, since we are going to use it now:
Code:
void MoveCameraAndRedrawMap(int deltaX, int deltaY) //unused
Leaving it like this
Code:
void MoveCameraAndRedrawMap(int deltaX, int deltaY)

And under that function, we add our new one
Code:
void UpdateSavedPos(void)
{
    gSaveBlock1Ptr->savedPos.x = gSaveBlock1Ptr->pos.x;
    gSaveBlock1Ptr->savedPos.y = gSaveBlock1Ptr->pos.y;
}

In src/field_specials.c, under the function OffsetCameraForBattle (or whatever your like really lol) we add this two new functions:
Code:
void TeleportCamera(void)
{
    UpdateSavedPos();
    MoveCameraAndRedrawMap(gSpecialVar_0x8004 - gSaveBlock1Ptr->pos.x,
                           gSpecialVar_0x8005 - gSaveBlock1Ptr->pos.y);
}

void ReturnCameraToPlayer(void)
{
    MoveCameraAndRedrawMap(gSaveBlock1Ptr->savedPos.x - gSaveBlock1Ptr->pos.x,
                           gSaveBlock1Ptr->savedPos.y - gSaveBlock1Ptr->pos.y);
}

Finally we have to add our player coordinates to our SaveBlock1.
If you didn't touch anything, in include/global.h you can replace this:
Code:
/*0x988*/ u8 filler1[0x34]; // Previously Dex Flags, feel free to remove.
With this
Code:
    /*0x988*/ struct Coords16 savedPos;
    /*0x98C*/ u8 filler1[0x30]; // Previously Dex Flags, feel free to remove.

Since I'm not sure if that's a thing from Egg branches, you can just add this to the end of your saveblock1
Code:
struct Coords16 savedPos;

Finally, we add them in data/specials.in, adding this at the end of it:
Code:
	def_special TeleportCamera
	def_special ReturnCameraToPlayer

Usage:
Code:
	setvar VAR_0x8004, 9  @ x
	setvar VAR_0x8005, 3  @ y
	special TeleportCamera
	-whatever u want-
	special ReturnCameraToPlayer

Poryscript example that I showed in the gif
Code:
script TestingMovement {
    setvar(VAR_0x8004, 33)
    setvar(VAR_0x8005, 15)
    special(TeleportCamera)
    msgbox(format("Testing camera!"))
    closemessage
    special(ReturnCameraToPlayer)
    end
}
 
[Pokeemerald] Rival Nickname

This adds FRLG's rival naming feature to pokeemerald.

[PokeCommunity.com] Simple Modifications Directory


Here is the repo. I may get around to posting in the wiki at some point as well.

How To Add:
How To Use:
  • In a script:
    Code:
    special NameRival
    waitstate
  • {RIVAL} will also buffer the rival's name appropriately
  • You can set default rival names in sDefaultRivalNames inside NameRival
  • Set Rival Trainer's name to "{B_RIVAL_NAME}." This has been done for all vanilla rival battles.
 
Last edited:
A previous post in this thread addresses Emerald's broken RNG by replacing the code in SeedRngAndSetTrainerId with something that uses the RTC to seed the RNG. The issue with it though is that on a newly-initialised game, the RTC is unset and hence unused, so any randomness won't actually occur until the clock has been started. It has the unfortunate consequence of having the Trainer ID no longer be randomly generated (or, it ends up being something predictable around the 10000 range).

For those who have pulled from the repo recently, the fixes simply require uncommenting of these code portions in main.c:

Declarations:
Code:
//static void SeedRngWithRtc(void);

Within the AgbMain() codeblock:
Code:
//SeedRngWithRtc(); see comment at SeedRngWithRtc declaration below

A function in the code commented out:
Code:
// oops! FRLG commented this out to remove RTC, however Emerald didnt undo this!
//static void SeedRngWithRtc(void)
//{
//    u32 seed = RtcGetMinuteCount();
//    seed = (seed >> 16) ^ (seed & 0xFFFF);
//    SeedRng(seed);
//}

For those with older clones that don't have these, simply put them in (without the comments).
 
[Pokeemerald] Removing the extra save confirmation

While I'm on a roll, if anyone wants to remove the "There is already a save file." confirmation when saving from the start menu, here's how. This makes saving consistent with how it is from Gen 5 forward, where the user is prompted only with the "Would you like to save the game?" message.

From start_menu.c, look for SaveFileExistsCallback:
Code:
// A different save file exists
static u8 SaveFileExistsCallback(void)
{
    if (gDifferentSaveFile == TRUE)
    {
        ShowSaveMessage(gText_DifferentSaveFile, SaveConfirmOverwriteDefaultNoCallback);
    }
    else
    {
        ShowSaveMessage(gText_AlreadySavedFile, SaveConfirmOverwriteCallback);
    }

    return SAVE_IN_PROGRESS;
}

Replace:
Code:
ShowSaveMessage(gText_AlreadySavedFile, SaveConfirmOverwriteCallback);
with:
Code:
sSaveDialogCallback = SaveSavingMessageCallback;

Keep gDifferentSaveFile and its conditional block there, as it will warn users who have started a new game and risking overriding existing save data.

The flow changes to:
START -> SAVE -> Would you like to save the game? -> SAVING… DON'T TURN OFF THE POWER -> [PLAYER] saved the game.
 
Last edited:
DPPt Bike (a 2-in-1 Bike) [Em]
This is pretty nice and simple. It allows you to swap between the Mach Bike and the Acro Bike by pressing the R Button in the overworld.
The code was originally written by Blurose, so the credits go to him. I simply checked if it worked in Pokeemerald, and since it does, I decided to come and share it here with his permission.

Do note that the Mach Bike breaks with this implementation. The correct bike to use is the Acro Bike specifically.
Needless to say, things like the Sound Effect casted when swapping from a bike mode to the other or even the button you have to press to change modes can be changed as y'all see fit.

Code:
https://github.com/LOuroboros/pokeemerald/commit/07e0517348374188663f45d719ed24cde2620624

Video:


And that's pretty much it.​

Thanks for this nice modification! I've got just one note: the bike resets to Acro Bike after checking the Bag menu even if Mach Bike was in use. Would there be any way to address this?
 
[Emerald] Item Descriptions On First Obtain

Recent games included a description of an item when you obtain it for the first time. This adds that feature to pokeemerald. it also adds the item icon to your message box on subsequent events.

I've found a couple of special cases that cause issues with displaying the item icons:

1. When buying Lava Cookies on Mt. Chimney. The yellow "MONEY" header image seems to be causing some sort of conflict.
2. Picking up any item while in a dark area that requires Flash doesn't show the item icon at all.

I can't post links yet, but here's the end of an imgur album url: a/H5FAIvM
 
Last edited:
[Pokeemerald] Omnidirectional Jumping

This is basically ledge jumping in all directions:
excuse the unrealistic tiles
[PokeCommunity.com] Simple Modifications Directory


It works for left/right as well but I was lazy with my examples. The repo

How to add:
How to use:
  • Add a new metatile and assign it MB_OMNIDIRECTIONAL_JUMP.
  • The behavior ID can be changed in include/constants/metatile_behaviors.h

Credit: CFRU
 
Last edited:
Back
Top