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

[Battle] How to Add a New Move to Pokeemerald

  • 247
    Posts
    6
    Years
    • Seen May 28, 2024
    Is there a tutorial that explains how to add a new move to Pokeemerald? I looked around, and only found a guide for adding a move to a binary hack. I looked through the files in Pokeemerald, and it seems that there are many many files that need to be messed with for a new move to be added to the project. I've found several, but I'm not sure if I've found them all. I'd be real appreciative if someone would point me to a tutorial that would walk me through this. If it hasn't been made, then I'd be happy if someone made it.
     
  • 56
    Posts
    8
    Years
    There's not that many files for moves I think, there are the following:

    constants/include/moves.h
    src/data/battle_moves.h
    src/data/contest_moves.h
    src/data/text/move_descriptions.h
    src/data/text/move_names.h

    I added new moves recently and they work fine. You can look at the structures of each file and it shouldn't be hard. I recommend to add the move in constants/include/moves.h after Gen8 moves. You don't have to (I didn't), but it's less work. Also don't forget to change the MOVES_COUNT number

    If you need help I can help you later better
     
  • 247
    Posts
    6
    Years
    • Seen May 28, 2024
    If you need help I can help you later better
    I would appreciate that, since those files don't have anything to do with move animations or creating new move effects. What I'm trying to do is implement the move Sky Drop, which has not yet been added to any of the common Pokeemerald bases.
     
  • 460
    Posts
    6
    Years
    • Seen yesterday
    I would appreciate that, since those files don't have anything to do with move animations or creating new move effects. What I'm trying to do is implement the move Sky Drop, which has not yet been added to any of the common Pokeemerald bases.

    look at:
    data/battle_scripts_1.s
    data/battle_anim_scripts.s
     
  • 56
    Posts
    8
    Years
    I would appreciate that, since those files don't have anything to do with move animations or creating new move effects. What I'm trying to do is implement the move Sky Drop, which has not yet been added to any of the common Pokeemerald bases.

    Oh that's a completely different thing. I haven't looked into creating new effects or animations yet, but I plan to do it soon, when I'm done with my current work. If you haven't done it or haven't got help by then, I may be able to.

    But yeah, for that, look at the files Anon822 pointed at. You may catch some important info there
     
  • 56
    Posts
    8
    Years
    Okay, I've managed to both add a simple new effect and difficult new effect. At first is quite confusing, because a few effects are done in src\battle_script_commands.c, others are done in src\battle_util.c and a majority of them in data\battle_scripts_1.s

    You basically have to determine where to put your code, where it will fit better in. In any case, you can look into those files for similar effects and info for creating your new one. In my case, I used both data\battle_scripts_1.s and src\battle_script_commands.c

    Now, how do you add an effect? First, you have to create a constant in constants\include\battle_move_effects.h, following the structure. I created the effects of Shadow Rush and Shadow Half for my project so I'll explain with those examples.

    For Shadow Rush (simple)
    Spoiler:


    For Shadow Half (difficult)
    Spoiler:

    Here's a gif demostration on both moves
    How to Add a New Move to Pokeemerald


    The only things missing now are the animations of the moves. For your case (Sky Drop), I believe it will be easier than Shadow Half, but still quite difficult. What I guess you have to do, is look at some moves like Fly, but with the addendum of also making the selected target "Fly", making them wasting a turn. I'm honestly quite tired, if you need more help I can look into it but I'll rest a bit. Too much information in a few days xD
     
    Last edited:
  • 247
    Posts
    6
    Years
    • Seen May 28, 2024
    I'm honestly quite tired, if you need more help I can look into it but I'll rest a bit. Too much information in a few days xD
    No, this is great! I had started working on it, but I had gotten hung up on how to implement a few parts of my script. These examples help clear up some of those issues, so thanks!
     
  • 247
    Posts
    6
    Years
    • Seen May 28, 2024
    I've run into a new snag that I would appreciate some help with, if available. I have most of the effects of Sky Drop working, except for the part where the target cannot act while in the air. I'm currently trying to get the player to be unable to act while being the target and in the air, but it isn't working, to put it simply. The key to this seems to be hidden somewhere in src/battle_main.c. I've tried messing with the method SetActionsAndBattlersTurnOrder as so:
    Original
    Code:
    for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
                {
                    if (gChosenActionByBattler[gActiveBattler] != B_ACTION_USE_ITEM && gChosenActionByBattler[gActiveBattler] != B_ACTION_SWITCH)
                    {
    		    gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler];
                        gBattlerByTurnOrder[turnOrderId] = gActiveBattler;
                        turnOrderId++;
                    }
                }
    Changed
    Code:
    for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
                {
                    if (gChosenActionByBattler[gActiveBattler] != B_ACTION_USE_ITEM && gChosenActionByBattler[gActiveBattler] != B_ACTION_SWITCH)
                    {
    					if (gStatuses3[gActiveBattler] & STATUS3_SKY_DROPPED)
    						gActionsByTurnOrder[turnOrderId] = B_ACTION_NOTHING_FAINTED;
    					else
    						gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler];
                        gBattlerByTurnOrder[turnOrderId] = gActiveBattler;
                        turnOrderId++;
                    }
                }
    As you can see, I've tried to set it up so that, if the current Pokemon that is being looked at by the method is currently "sky dropped", which is what I've termed the state of being the target of Sky Drop and in the air, then their action should be nothing. However, when I've tested it out, I'll choose a random move for my "sky dropped" Pokemon to use, and instead of just not doing the move and the second move of Sky Drop occurring, the action menu will open up again. This code apparentally sticks the player in an infinite loop where, no matter what action they choose, the menu just opens again. I know "B_ACTION_NOTHING_FAINTED" isn't the issue, since it doesn't exclusively relate to when a Pokemon faints, and because I've tried other actions like "B_ACTION_FINISHED" and "B_ACTION_TRY_FINISH", which cause the same effect to occur.

    If anyone knows how to completely take away the action of a particular Pokemon based on a condition, I would love to hear it.
     
  • 853
    Posts
    3
    Years
    • Seen Nov 9, 2023
    I've run into a new snag that I would appreciate some help with, if available. I have most of the effects of Sky Drop working, except for the part where the target cannot act while in the air. I'm currently trying to get the player to be unable to act while being the target and in the air, but it isn't working, to put it simply. The key to this seems to be hidden somewhere in src/battle_main.c. I've tried messing with the method SetActionsAndBattlersTurnOrder as so:
    Original
    Code:
    for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
                {
                    if (gChosenActionByBattler[gActiveBattler] != B_ACTION_USE_ITEM && gChosenActionByBattler[gActiveBattler] != B_ACTION_SWITCH)
                    {
    		    gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler];
                        gBattlerByTurnOrder[turnOrderId] = gActiveBattler;
                        turnOrderId++;
                    }
                }
    Changed
    Code:
    for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
                {
                    if (gChosenActionByBattler[gActiveBattler] != B_ACTION_USE_ITEM && gChosenActionByBattler[gActiveBattler] != B_ACTION_SWITCH)
                    {
    					if (gStatuses3[gActiveBattler] & STATUS3_SKY_DROPPED)
    						gActionsByTurnOrder[turnOrderId] = B_ACTION_NOTHING_FAINTED;
    					else
    						gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler];
                        gBattlerByTurnOrder[turnOrderId] = gActiveBattler;
                        turnOrderId++;
                    }
                }
    As you can see, I've tried to set it up so that, if the current Pokemon that is being looked at by the method is currently "sky dropped", which is what I've termed the state of being the target of Sky Drop and in the air, then their action should be nothing. However, when I've tested it out, I'll choose a random move for my "sky dropped" Pokemon to use, and instead of just not doing the move and the second move of Sky Drop occurring, the action menu will open up again. This code apparentally sticks the player in an infinite loop where, no matter what action they choose, the menu just opens again. I know "B_ACTION_NOTHING_FAINTED" isn't the issue, since it doesn't exclusively relate to when a Pokemon faints, and because I've tried other actions like "B_ACTION_FINISHED" and "B_ACTION_TRY_FINISH", which cause the same effect to occur.

    If anyone knows how to completely take away the action of a particular Pokemon based on a condition, I would love to hear it.

    My assumption is this is using a "special state" byte, but if you want to do it cheap, you can make a function that if the atkr current move is sky drop, then the def mon moves would always miss.

    That should let it work for both turns of the move.

    There's not that many files for moves I think, there are the following:

    constants/include/moves.h
    src/data/battle_moves.h
    src/data/contest_moves.h
    src/data/text/move_descriptions.h
    src/data/text/move_names.h

    I added new moves recently and they work fine. You can look at the structures of each file and it shouldn't be hard. I recommend to add the move in constants/include/moves.h after Gen8 moves. You don't have to (I didn't), but it's less work. Also don't forget to change the MOVES_COUNT number

    If you need help I can help you later better

    Do you need to make some type of move string for a move? Like for example moves like ingrain, has a text that plays after the move is used something like. [pokemon] was rooted to the spot/took up roots.
     
    Last edited by a moderator:

    Lunos

    Random Uruguayan User
  • 3,116
    Posts
    15
    Years
    Do you need to make some type of move string for a move? Like for example moves like ingrain, has a text that plays after the move is used something like. [pokemon] was rooted to the spot/took up roots.
    It's not mandatory, but yes, you can add text strings to print in your move effects' battle scripts by using the printstring macro, yeah.
    To do it, you need to define your new strings in include/constants/battle_string_ids.h and change the value of BATTLESTRINGS_COUNT in the same file.
    Then you just add your string in src/battle_message.c following the example of the other strings already there.
    https://github.com/pret/pokeemerald/blob/master/src/battle_message.c#L59
    https://github.com/pret/pokeemerald/blob/master/src/battle_message.c#L523
     
  • 56
    Posts
    8
    Years
    Do you need to make some type of move string for a move? Like for example moves like ingrain, has a text that plays after the move is used something like. [pokemon] was rooted to the spot/took up roots.

    Yep. Well, it's not "needed", but to make it look good you must. As Lunos said. I also explained how to add a new string in the previous post, at the end of the Shadow Half example
     
  • 56
    Posts
    8
    Years

    If I understood correctly, the move currently gets the user and the target to the air, but when the target is in the air and needs to move, it doesn't let the user fall to the ground neither? I don't know what may be causing that, as I don't know all the code you did and I'd need to test it. But I suggest, for a turn to pass without doing nothing, to look on how the ability Truant or the status Flinched work. I think they can do the trick. I'll try to look into it soon though, just let me know if you achieve something before

    (Also sorry for the double post)
     
  • 853
    Posts
    3
    Years
    • Seen Nov 9, 2023
    Yep. Well, it's not "needed", but to make it look good you must. As Lunos said. I also explained how to add a new string in the previous post, at the end of the Shadow Half example

    I see, thanks, but what exactly is a "constant" is that like how you have to give something a name and index before it can "exist" in the game.

    Is the constant folder where everything we call in functions gets defined?

    It's not mandatory, but yes, you can add text strings to print in your move effects' battle scripts by using the printstring macro, yeah.
    To do it, you need to define your new strings in include/constants/battle_string_ids.h and change the value of BATTLESTRINGS_COUNT in the same file.
    Then you just add your string in src/battle_message.c following the example of the other strings already there.
    https://github.com/pret/pokeemerald/blob/master/src/battle_message.c#L59
    https://github.com/pret/pokeemerald/blob/master/src/battle_message.c#L523

    Thanks for the info & links, so what does it mean that each constant there is paired with a string?

    Like the practical purpose and use?
     
    Last edited by a moderator:
  • 56
    Posts
    8
    Years
    I see, thanks, but what exactly is a "constant" is that like how you have to give something a name and index before it can "exist" in the game.

    Is the constant folder where everything we call in functions gets defined?

    A constant is basically data with a fixed value. In this case, the data is the string itself, and the value would be "Pokémon did something". In my example, there's this line:
    Code:
    #define STRINGID_SHADOWHALFDAMAGE 563

    STRINGID_SHADOWHALFDAMAGE is the name of the constant, you have to give them a name, like with vars and flags. Its value is 563. So, that line is basically defining a constant with said name and a value always equal to 563.

    Then, in this part of code:
    Code:
    static const u8 sText_ShadowHalfDamage[] = _("{B_ATK_NAME_WITH_PREFIX}'s darkness damaged\nall Pokémon!");
    
    const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
    {
    ...
    [STRINGID_SCREENCLEANERENTERS - 12] = sText_ScreenCleanerActivates,
    [STRINGID_SHADOWHALFDAMAGE - 12] = sText_ShadowHalfDamage,

    Let's say, that's where all those constants with a number value are converted into text that appears in the game.

    Basically a constant is like a variable, though a variable can change its value. A constant cannot. I hope this makes it more or less clear
     
  • 247
    Posts
    6
    Years
    • Seen May 28, 2024
    If I understood correctly, the move currently gets the user and the target to the air, but when the target is in the air and needs to move, it doesn't let the user fall to the ground neither? I don't know what may be causing that, as I don't know all the code you did and I'd need to test it. But I suggest, for a turn to pass without doing nothing, to look on how the ability Truant or the status Flinched work. I think they can do the trick. I'll try to look into it soon though, just let me know if you achieve something before

    (Also sorry for the double post)

    I figured it out! I did some messing around with some other actions, specifically using the "Creep Closer" action that is used in the Safari Zone, as well as checking to see if the player's Pokemon is being "sky dropped" at the moment. If the Pokemon is being "sky dropped", then the player doesn't even get to choose an action. They immediately take the "Creep Closer" action, but that does nothing in a normal battle, effectively skipping their turn. I also modified the attackcanceler script so that, if the attacker is "sky dropped", they don't use their inputted attack. I just need to make sure the target of Sky Drop doesn't get to use their attack in the particular situation where the player's Pokemon goes first and uses the second part of Sky Drop, but that shouldn't be too hard to implement, since I already got it working for the player.
     
    Back
    Top