• 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

239
Posts
8
Years
    • Seen Apr 15, 2024
    [Pokeemerald] Rock Climb

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

    3gvFEHy.gif
    I8JW7Ok.gif


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

    Please report any bugs.
     
    5
    Posts
    6
    Years
    • Seen Feb 28, 2023
    [PokeEmerald] Grindrunning For Easier Diagonal Movement​
    pPusQdp.gif

    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:
     
    239
    Posts
    8
    Years
    • Seen Apr 15, 2024
    [Pokeemerald] Give Custom Mon

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

    EWeAukI.gif


    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:
    1,403
    Posts
    10
    Years
    • Seen Apr 29, 2024
    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.
     
    8
    Posts
    3
    Years
    • Seen May 2, 2024
    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.
     
    146
    Posts
    16
    Years
    • Age 26
    • Seen Apr 29, 2024
    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!
     

    Jaizu

    Average rom hacker
    281
    Posts
    14
    Years
  • 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
     
    18,810
    Posts
    21
    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

    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.
     

    Lunos

    Random Uruguayan User
    3,114
    Posts
    15
    Years
  • 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:
    zLchlcW.gif
    Ol7WnQx.gif


    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:

    Jaizu

    Average rom hacker
    281
    Posts
    14
    Years
  • [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:
    X9dCrVa.png


    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:
    pV6UKWH.png


    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
    }
     

    Jaizu

    Average rom hacker
    281
    Posts
    14
    Years
  • [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!)

    ZDNLMDq.gif


    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
    }
     
    239
    Posts
    8
    Years
    • Seen Apr 15, 2024
    [Pokeemerald] Rival Nickname

    This adds FRLG's rival naming feature to pokeemerald.

    pB41oGy.gif


    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:
    18,810
    Posts
    21
    Years
  • 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).
     
    18,810
    Posts
    21
    Years
  • [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:
    23
    Posts
    6
    Years
    • Seen Nov 28, 2023
    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?
     
    8
    Posts
    3
    Years
    • Seen May 2, 2024
    [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:

    Lunos

    Random Uruguayan User
    3,114
    Posts
    15
    Years
  • 239
    Posts
    8
    Years
    • Seen Apr 15, 2024
    [Pokeemerald] Omnidirectional Jumping

    This is basically ledge jumping in all directions:
    excuse the unrealistic tiles
    fT9c6ZV.gif


    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