• 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 Trading Card Game 2 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.

[Script] [Pokeruby/Pokeemerald] Script to let Pokémon use HM without knowing them

McPaul

On my way to become a controversial and hated memb
  • 289
    Posts
    7
    Years
    Hey yo!

    After months of crazy depression I'm kinda back in the ROM hack game.

    I'm still randomly trying some things to see if I can manage to get through. I want to get rid of HM slaves by letting mons use HM if they can learn them but without them having the move. How could I script that?

    I'm currently in pokeruby in the file pokeruby\data\field_move_scripts.inc and take for example the cut script:

    Spoiler:


    The interesting part there would be checkpartymove MOVE_CUT, it could be replaced by something like (I'm inventing there but let's be creative) checkifpartymoncanlearnmove MOVE_CUT but well I don't know how to do such a thing.

    The second part would me making HM moves appear in the Pokémon party menu even if they don't have the move and once the required badge is obtained (for HM moves like FLY for example)

    Could maybe someone help me?

    Thanks a lot!
     
    There's a function called CanMonLearnTMHM that you could use for TM/HM moves. If you don't care about preserving the old way, you could change checkpartymove by altering the ScrCmd_checkpartymove function in src/scrcmd.c to call that. I don't know if any of the field moves aren't TMs/HMs, if they are, you'd need to use a more sophisticated approach. If you want to add a command instead, that's the same src/scrcmd.c plus data/script_cmd_table.inc and asm/macros/event.inc. As for the party menu, that's in src/party_menu.c, try searching for sFieldMoves or SetPartyMonFieldSelectionActions. But that's as helpful as I can be.
     
    I've made this code:

    Spoiler:


    But now the problem is that EVERYONE can cut even Wurmple! Looks like it doesn't check the "canmonlearnTMHM" part.

    Tried with
    Spoiler:
    and changing checkpartymove MOVE_CUT to checkpartymove ITEM_HM_01_CUT but that still doesn't work.
     
    Last edited:
    CanMonLearnTMHM expects a TM/HM number as input, not an item ID or move ID. If you look at its other uses or the function definition you'll see the input should be something like CanMonLearnTMHM(mon, itemId - ITEM_TM01_FOCUS_PUNCH).

    itemId - ITEM_TM01_FOCUS_PUNCH will calculate the TM number from the TM's item ID.
     
    I've wrotten it like this:
    Spoiler:


    But can't manage to compile.
     
    This line is not syntactically correct:
    Code:
    u16 itemId - ITEM_TM01_FOCUS_PUNCH = ScriptReadHalfword(ctx);
    You can't have operations on the left side of a variable declaration. You can only have the data type (u16) and the variable name (I assume "itemId") on the left side.

    The other errors may all be affected by this one, so fixing that will help clear some stuff up and see which of the other errors are real errors and which aren't.
     
    Last edited:
    Ok thanks let's try my new code:

    Spoiler:


    Error:

    Spoiler:
     
    You'll need to put a semi-colon after
    Code:
    u16 itemId
    or give the variable a value at that line, still ending the line with a semi-colon. You never give this variable a value before using it as an operand in
    Code:
    if (!GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) && !CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01_FOCUS_PUNCH)
    Using a variable that has been declared but has no data as an operand will always produce an error.
     
    You'll need to put a semi-colon after
    Code:
    u16 itemId
    or give the variable a value at that line, still ending the line with a semi-colon. You never give this variable a value before using it as an operand in
    Code:
    if (!GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) && !CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01_FOCUS_PUNCH)
    Using a variable that has been declared but has no data as an operand will always produce an error.

    Thanks! I didn't understand the second part about the the no data as an operand as English is not my mother tongue, I should add something more? As I want the game to check If the Pokémon can learn the HM instead of checking if it has actually learned it I need the function to check for (for example) ITEM_HM01_CUT in "checkattack" function and bypass all mons that cannot learn Cut.
     
    Thanks! I didn't understand the second part about the the no data as an operand as English is not my mother tongue, I should add something more? As I want the game to check If the Pokémon can learn the HM instead of checking if it has actually learned it I need the function to check for (for example) ITEM_HM01_CUT in "checkattack" function and bypass all mons that cannot learn Cut.

    To explain that "no data as an operand" thing, you have a variable called "itemId", but you didn't give it a value, like
    Code:
    u16 itemId = 5;
    This would give itemId the value of 5. Since you didn't do that, itemId has no value. Then, when you try to use itemId to do this
    Code:
    itemId - ITEM_TM01_FOCUS_PUNCH
    You are trying to use a variable that has no value to do math. This results in an error.

    You'll probably want something like this:
    Code:
    bool8 ScrCmd_checkpartymove(struct ScriptContext *ctx)
    {
        u8 i;
        u16 itemId = ScriptReadHalfword(ctx);
    
        gSpecialVar_Result = 6;
        for (i = 0; i < PARTY_SIZE; i++)
        {
                u16 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL);
                if (!species)
                    break;
                // UB: GetMonData() arguments don't match function definition
                if (CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01)
                {
                    gSpecialVar_Result = i;
                    gSpecialVar_0x8004 = species;
                    break;
                }
        }
        return FALSE;
    }
    Here are the changes I've made:
    Code:
    u16 itemId = ScriptReadHalfword(ctx);
    This will give the variable itemId the number that is connected to the HM that you're checking for, like ITEM_HM01_CUT.
    Code:
    if (CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01)
    Now the if-statement simply checks to see if the Pokemon can learn the HM that you passed in. I took out the
    Code:
    !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)
    because the CanMonLearnTMHM method already checks to see if the Pokemon is an egg or not. I also took out the exclamation mark before CanMonLearnTMHM, because that would make the method return true when a Pokemon that COULDN'T learn Cut was checked. Finally, I changed ITEM_TM01_FOCUS_PUNCH to ITEM_TM01, because in the most recent version of pokeemerald, this is how that TM is named.
     
    To explain that "no data as an operand" thing, you have a variable called "itemId", but you didn't give it a value, like
    Code:
    u16 itemId = 5;
    This would give itemId the value of 5. Since you didn't do that, itemId has no value. Then, when you try to use itemId to do this
    Code:
    itemId - ITEM_TM01_FOCUS_PUNCH
    You are trying to use a variable that has no value to do math. This results in an error.

    You'll probably want something like this:
    Code:
    bool8 ScrCmd_checkpartymove(struct ScriptContext *ctx)
    {
        u8 i;
        u16 itemId = ScriptReadHalfword(ctx);
    
        gSpecialVar_Result = 6;
        for (i = 0; i < PARTY_SIZE; i++)
        {
                u16 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL);
                if (!species)
                    break;
                // UB: GetMonData() arguments don't match function definition
                if (CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01)
                {
                    gSpecialVar_Result = i;
                    gSpecialVar_0x8004 = species;
                    break;
                }
        }
        return FALSE;
    }
    Here are the changes I've made:
    Code:
    u16 itemId = ScriptReadHalfword(ctx);
    This will give the variable itemId the number that is connected to the HM that you're checking for, like ITEM_HM01_CUT.
    Code:
    if (CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01)
    Now the if-statement simply checks to see if the Pokemon can learn the HM that you passed in. I took out the
    Code:
    !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)
    because the CanMonLearnTMHM method already checks to see if the Pokemon is an egg or not. I also took out the exclamation mark before CanMonLearnTMHM, because that would make the method return true when a Pokemon that COULDN'T learn Cut was checked. Finally, I changed ITEM_TM01_FOCUS_PUNCH to ITEM_TM01, because in the most recent version of pokeemerald, this is how that TM is named.

    Thanks a lot for your time!

    I still get errors though.

    Here is the report:

    Spoiler:


    I still used ITEM_TM01_FOCUS_PUNCH as I'm not in pokeemerald but in pokeruby. I tried with just ITEM_TM01 too though but still got the same errors.
     
    I still used ITEM_TM01_FOCUS_PUNCH as I'm not in pokeemerald but in pokeruby. I tried with just ITEM_TM01 too though but still got the same errors.

    I see the error now. At the top of src/srcmd.c, add this to the end of the "#include" stuff:
    Code:
    #include "constants/items.h"
    It should look like this:
    Code:
    .......
    #include "shop.h"
    #include "slot_machine.h"
    #include "sound.h"
    #include "string_util.h"
    #include "tv.h"
    #include "constants/maps.h"
    #include "constants/items.h"
    This should fix the error. You are right, pokeruby still uses ITEM_TM01_FOCUS_PUNCH, so keep using that.
     
    I see the error now. At the top of src/srcmd.c, add this to the end of the "#include" stuff:
    Code:
    #include "constants/items.h"
    It should look like this:
    Code:
    .......
    #include "shop.h"
    #include "slot_machine.h"
    #include "sound.h"
    #include "string_util.h"
    #include "tv.h"
    #include "constants/maps.h"
    #include "constants/items.h"
    This should fix the error. You are right, pokeruby still uses ITEM_TM01_FOCUS_PUNCH, so keep using that.

    THANKS! Everything looks like it got fixed! There is just one last thing that looks like a "ghost" error, do you or someone perhaps know what it is?

    root@McPC:/mnt/c/Users/McPaul/decomps/pokeruby# make
    arm-none-eabi-cpp -iquote include -Werror -Wno-trigraphs -D RUBY -D REVISION=0 -D ENGLISH -D=DEBUG_FIX0 -D DEBUG=0 -D MODERN=0 -I tools/agbcc/include -nostdinc -undef src/scrcmd.c -o build/ruby/src/scrcmd.i
    tools/preproc/preproc build/ruby/src/scrcmd.i charmap.txt | tools/agbcc/bin/agbcc -mthumb-interwork -Wimplicit -Wparentheses -Wunused -Werror -O2 -fhex-asm -o build/ruby/src/scrcmd.s
    src/scrcmd.c: In function `ScrCmd_checkpartymove':
    src/scrcmd.c:1593: syntax error before `{'
    src/scrcmd.c: At top level:
    src/scrcmd.c:1599: syntax error before `return'
    Makefile:206: recipe for target 'build/ruby/src/scrcmd.o' failed
    make: *** [build/ruby/src/scrcmd.o] Error 1
    root@McPC:/mnt/c/Users/McPaul/decomps/pokeruby#

    I tried to delete and rewrite all the lines but it's still there!

    Thanks!
     
    THANKS! Everything looks like it got fixed! There is just one last thing that looks like a "ghost" error, do you or someone perhaps know what it is?

    root@McPC:/mnt/c/Users/McPaul/decomps/pokeruby# make
    arm-none-eabi-cpp -iquote include -Werror -Wno-trigraphs -D RUBY -D REVISION=0 -D ENGLISH -D=DEBUG_FIX0 -D DEBUG=0 -D MODERN=0 -I tools/agbcc/include -nostdinc -undef src/scrcmd.c -o build/ruby/src/scrcmd.i
    tools/preproc/preproc build/ruby/src/scrcmd.i charmap.txt | tools/agbcc/bin/agbcc -mthumb-interwork -Wimplicit -Wparentheses -Wunused -Werror -O2 -fhex-asm -o build/ruby/src/scrcmd.s
    src/scrcmd.c: In function `ScrCmd_checkpartymove':
    src/scrcmd.c:1593: syntax error before `{'
    src/scrcmd.c: At top level:
    src/scrcmd.c:1599: syntax error before `return'
    Makefile:206: recipe for target 'build/ruby/src/scrcmd.o' failed
    make: *** [build/ruby/src/scrcmd.o] Error 1
    root@McPC:/mnt/c/Users/McPaul/decomps/pokeruby#

    I tried to delete and rewrite all the lines but it's still there!

    Thanks!

    This line
    Code:
    if (CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01)
    You need to add another parenthesis at the end. Like this:
    Code:
    if (CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01))
     
    This line
    Code:
    if (CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01)
    You need to add another parenthesis at the end. Like this:
    Code:
    if (CanMonLearnTMHM(&gPlayerParty[i], itemId - ITEM_TM01))

    Well thank you it worked lik a charm!

    My next big step is the party menu!

    [PokeCommunity.com] [Pokeruby/Pokeemerald] Script to let Pokémon use HM without knowing them
    [PokeCommunity.com] [Pokeruby/Pokeemerald] Script to let Pokémon use HM without knowing them

    I didn't touch anything, just caught some mons hahahaha. Well I'm not that disappointed as It's already a step towards what I want to achieve without even doing anything (getting HM in the party menu without teaching them), what's left is getting control over it!
     
    ......what's left is getting control over it!

    I think you should focus your attention on src/pokemon_menu.c, more specifically this function:
    Spoiler:
    The code that seems to deal with adding "CUT" or "SURF" or whatever to that list seems to be this part:
    Code:
    u16 moveID, tableID;
            for (moveID = 0; moveID < 4; moveID++) // 4, max number of possible field moves
            {
                for (tableID = 0; sPokeMenuFieldMoves[tableID] != sFieldMovesTerminator; tableID++)
                {
                    if (GetMonData(&gPlayerParty[gLastFieldPokeMenuOpened], MON_DATA_MOVE1 + moveID) == sPokeMenuFieldMoves[tableID])
                    {
                        u8 fieldID = tableID + POKEMENU_FIRST_FIELD_MOVE_ID;
                        AppendToList(sPokeMenuOptionsOrder, &sPokeMenuOptionsNo, fieldID);
                        break;
                    }
                }
            }
     
    Back
    Top