• 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.
  • Dawn, Gloria, Juliana, or Summer - which Pokémon protagonist is your favorite? Let us know by voting in our poll!
  • Our friends from the Johto Times are hosting a favorite Pokémon poll - and we'd love for you to participate! Click here for information on how to vote for your favorites!
  • 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] I'd like to make a request for a step by step tutorial for adding in new Abilities

  • 111
    Posts
    7
    Years
    • Seen Nov 11, 2023
    I've noticed from my searching that there is next to 0 documentation on how to actually implement new abilities into gen 3 games. I see many threads such as this one https://www.pokecommunity.com/posts/8989368/ showing a thumb script that can be compiled into a rom and the offsets that must be changed to make it work but... that's it. To someone who isn't sure about the details this is all just very confusing. How do I assign the ability to a Pokemon? How do I create a text box for this ability and how do I even make sure the thumb script is assigned to a new ability slot? This type of information is extremely useful IMO but criminally undocumented. I think just a tiny, tiny handful of the people seeing these scripts and wanting to use them actually understand how to get them functioning in the game. If anyone could help explain the process I'm sure a ton of us here would appreciate it!
     
    I definitely second these requests. I posted a thread a month ago or so asking how I'd implement an ability idea I had and the only reply was four bytes long: "asm."

    Like, yeah, no s*it, it's gonna take ASM, but where do you put the code? How to you tell the game it's an Ability? How do you *make the damn thing work,* let alone write the ability's code? No one seems to want to provide that kind of info and it's really frustrating lmao (I know I'm basically repeating what you said but this is an issue which needs as much attention as it can get)
     
    You need to use Battle Script Pro for making the ability work. There's a tutorial but it looks like a foreign language to me. I wish someone would make a video tutorial or another tutorial that I can understand.
     
    I've noticed from my searching that there is next to 0 documentation on how to actually implement new abilities into gen 3 games. I see many threads such as this one https://www.pokecommunity.com/posts/8989368/ showing a thumb script that can be compiled into a rom and the offsets that must be changed to make it work but... that's it. To someone who isn't sure about the details this is all just very confusing. How do I assign the ability to a Pokemon? How do I create a text box for this ability and how do I even make sure the thumb script is assigned to a new ability slot? This type of information is extremely useful IMO but criminally undocumented. I think just a tiny, tiny handful of the people seeing these scripts and wanting to use them actually understand how to get them functioning in the game. If anyone could help explain the process I'm sure a ton of us here would appreciate it!

    In a crude sense, most abilities are essentially just if/then statements to change the outcome of certain battle commands or effects. For example, wonder guard is: If target has wonder guard/outcome is not super effective, return 0 damage. else, proceed with damage calcs.

    Because of this, you will need to understand how to read/write ASM in order to make new effects, because they require editing the game code itself. There is no cookie-cutter method to writing the abilities, each one requires unique logic and a unique location in the game code.

    Adding the ability/name to the game is pretty simple, and a tutorial already exists for that. The effects are what require assembly. When you expand the ability names, you can update your INIs for tools like G3T, etc, and select your ability from the drop down menu. It's assigned as a byte in the Pokemon data structure, which corresponds to its position in the ability tables.

    I hope this helps!
     
    Last edited:
    In a crude sense, most abilities are essentially just if/then statements to change the outcome of certain battle commands or effects. For example, wonder guard is: If target has wonder guard/outcome is not super effective, return 0 damage. else, proceed with damage calcs.

    Because of this, you will need to understand how to read/write ASM in order to make new effects, because they require editing the game code itself. There is no cookie-cutter method to writing the abilities, each one requires unique logic and a unique location in the game code.

    Adding the ability/name to the game is pretty simple, and a tutorial already exists for that. The effects are what require assembly. When you expand the ability names, you can update your INIs for tools like G3T, etc, and select your ability from the drop down menu. It's assigned as a byte in the Pokemon data structure, which corresponds to its position in the ability tables.

    I hope this helps!

    The thing is there are already pre-written thumb scripts for new items and abilities it's just no one know how to add them in. Or, I guess, the people who do know how don't really seem to want to tell anyone how. I haven't been able to find a single post or thread explaining how to actually get the thumb script ability codes into an ability slot
     
    The thing is there are already pre-written thumb scripts for new items and abilities it's just no one know how to add them in. Or, I guess, the people who do know how don't really seem to want to tell anyone how. I haven't been able to find a single post or thread explaining how to actually get the thumb script ability codes into an ability slot

    The scripts aren't related to assigning abilities to Pokemon, just editing the code to implement their effects by checking for the Pokemon's ability byte. They will come with some instructions like "insert 00 48 00 47 xx+1 xx xx 08 at 0x[address], for example. This just means the code branches from the original game code to perform the appropriate ability checks before returning.

    When you expand the name/description table, you can assign your new ability byte to your Pokemon and the inserted code will do the rest. This is easy if you edit your INIs to increase the number of abilities. If this doesn't make sense, I would take a look at the Pokemon data structure some more.
     
    So if I compile the script and "insert 00 48 00 47 xx+1 xx xx 08 at 0x[address]" how can I assign this code to a new ability slot? I have created new slots using PGE and I have free space to assign new abilities. How can I take this script and assign it to the ability slot?
     
    So if I compile the script and "insert 00 48 00 47 xx+1 xx xx 08 at 0x[address]" how can I assign this code to a new ability slot? I have created new slots using PGE and I have free space to assign new abilities. How can I take this script and assign it to the ability slot?

    I'm pretty sure that's where the battle scripting comes in. You'll need to use Battle Script Pro
     
    I'm pretty sure that's where the battle scripting comes in. You'll need to use Battle Script Pro

    Does anyone know anything else about this? What exactly am I trying to put into Battle Script Pro? The offset of the compiled code for the new ability? Battle Script Pro makes absolutely no sense to me and doesn't even seem to have options to change abilities, just moves.
     
    Last edited:
    So if I compile the script and "insert 00 48 00 47 xx+1 xx xx 08 at 0x[address]" how can I assign this code to a new ability slot? I have created new slots using PGE and I have free space to assign new abilities. How can I take this script and assign it to the ability slot?

    Maybe I didn't explain it well enough, but my last post describes the difference here. Again, the code has nothing to do with assigning the ability to the pokemon. The game has a list of abilities (eg. Wonder Guard is ability 25 (or 0x19) ) that are ordered by their positions in the ability description/name tables. These bytes are assigned to the 22nd/23rd bytes in the base stats data structure. This byte is loaded during battle and used to check for unique ability effects. The code you are inserting is checking for this byte as a way of implementing the ability, so you just need to insert the code, insert your new ability description/pointer in an unused table entry, and assign that index to your pokemon. For example, if you add your ability name right after Air Lock, your ability ID would be 77 (0x4D).
     
    Maybe I didn't explain it well enough, but my last post describes the difference here. Again, the code has nothing to do with assigning the ability to the pokemon. The game has a list of abilities (eg. Wonder Guard is ability 25 (or 0x19) ) that are ordered by their positions in the ability description/name tables. These bytes are assigned to the 22nd/23rd bytes in the base stats data structure. This byte is loaded during battle and used to check for unique ability effects. The code you are inserting is checking for this byte as a way of implementing the ability, so you just need to insert the code, insert your new ability description/pointer in an unused table entry, and assign that index to your pokemon. For example, if you add your ability name right after Air Lock, your ability ID would be 77 (0x4D).

    So what part of the code he's inserting is the ability name?
     
    Maybe I didn't explain it well enough, but my last post describes the difference here. Again, the code has nothing to do with assigning the ability to the pokemon. The game has a list of abilities (eg. Wonder Guard is ability 25 (or 0x19) ) that are ordered by their positions in the ability description/name tables. These bytes are assigned to the 22nd/23rd bytes in the base stats data structure. This byte is loaded during battle and used to check for unique ability effects. The code you are inserting is checking for this byte as a way of implementing the ability, so you just need to insert the code, insert your new ability description/pointer in an unused table entry, and assign that index to your pokemon. For example, if you add your ability name right after Air Lock, your ability ID would be 77 (0x4D).

    Thank you for the help! I've decided to post screenshots of a step by step process I will do beginning from the insertion of the Thumb Script up to testing it in game so that it might be easier to identify where I am having an issue.

    First, I begin by inserting this code

    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    .global typechangeabilities
    
    BufferAbility:
    	mov r0, r6
    	add r0, #0x20
    	ldrb r1, [r0]
    NormalCheck:
    	mov r0, r10
    	cmp r0, #0x0
    	bne NormalizeCheck
    RefrigerateCheck:
    	cmp r1, #0xAF
    	bne PixilateCheck
    Refrigerate:
    	mov r0, #0xF
    	b StoreType
    PixilateCheck:
    	cmp r1, #0xB7
    	bne AerilateCheck
    Pixilate:
    	mov r0, #0x17
    	b StoreType
    AerilateCheck:
    	cmp r1, #0xB9
    	bne Return
    Aerilate:
    	mov r0, #0x2
    StoreType:
    	mov r10, r0
    	ldr r0, .ChangeTypeLoc
    	ldr r1, [r0]
    	add r1, #0x13
    	ldrb r1, [r1]
    	mov r2, #0x3F
    	and r2, r1
    	cmp r2, #0x0
    	bne Return
    	mov r2, r10
    	strb r2, [r1]
    Boost:
    	mov r0, r8
    	mov r1, #0xA7
    	mul r0, r1
    	lsr r0, #0x7
    	mov r8, r0
    	mul r7, r1
    	lsr r7, #0x7
    	b Return
    NormalizeCheck:
    	cmp r1, #0x61
    	bne Return
    Normalize:
    	mov r0, #0x0
    	mov r10, r0
    Return:
    	ldr r0, [sp, #0x4]
    	ldrh r0, [r0, #0xA]
    	str r0, [sp, #0x1C]
    	ldrh r0, [r6, #0x2E]
    	cmp r0, #0xAF
    	bne NoEnigmaBerry
    	ldr r1, .Return
    	bx r1
    NoEnigmaBerry:
    	ldr r0, .Return2
    	bx r0
    
    .align 2
    .ChangeTypeLoc: .word 0x0202449C
    .Return: .word 0x0806961B
    .Return2: .word 0x08069635

    (NOTE: my game does not have the Fairy type however I am assuming if I ignore the Pixiliate ability this will be harmless as the routine to check for the Fairy type should only be run if a Pixilate Pokemon is on the field)

    https://i.imgur.com/YJwHeNZ.png

    Here I can see that the test compile is successful and there are no issues in the script

    https://i.imgur.com/ifpwEcW.png

    Then, using the THUMB Editor and Assembler, I insert the code into my rom at free space offset 0xFE3E00

    Now, here's part of where I'm stumped. This code is inserted but how do I assign it to an ability number? Do I need to edit a value in the actual Thumb script itself that is deciding what number each ability is? If so, where even is that? What am I supposed to change to get, say, empty ability slots 78-82 to be these abilities?

    https://i.imgur.com/cAgRPxF.png

    Here is the location of the bytes I have changed according to the footnote at the bottom of the Thumb script

    Also, in this script at the bottom he says "01 48 00 47 00 0 xx+1 xx xx 08 at 0806960E" Is the single 0 a typo? bytes are always supposed to be two digits. Am I supposed to infer this is 00 or am I supposed to simply put one 0 and then the beginning of the offset as the second digit?
     
    Last edited:

    I see why you are confused - the abilities posted publicly assume you have set up your abilities ordered the same way they are in the game. Here is an updated script that you can use (I removed pixilate since you do not have fairy type). The 0xAF, etc, are the ability ID the game will check for on the user pokemon. This is assigned in the base stats data structure and is based on the ability name/description order in the relevant tables. The original gen 3 abilities go from index 0x0 (Stench) to 0x76 (Cacophany or Air Lock I forget). So If you expand these tables and add pointers to Refrigerate strings, it would be ability ID 0x77 and you would replace 0xAF with 0x77.

    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    .global typechangeabilities
    
    BufferAbility:
    	mov r0, r6
    	add r0, #0x20
    	ldrb r1, [r0]
    NormalCheck:
    	mov r0, r10
    	cmp r0, #0x0
    	bne NormalizeCheck
    RefrigerateCheck:
    	cmp r1, #0xAF         @ regrigerate ability ID
    	bne AerilateCheck
    Refrigerate:
    	mov r0, #0xF
    	b StoreType
    AerilateCheck:
    	cmp r1, #0xB9      @ aerilate ability ID
    	bne Return
    Aerilate:
    	mov r0, #0x2
    StoreType:
    	mov r10, r0
    	ldr r0, .ChangeTypeLoc
    	ldr r1, [r0]
    	add r1, #0x13
    	ldrb r1, [r1]
    	mov r2, #0x3F
    	and r2, r1
    	cmp r2, #0x0
    	bne Return
    	mov r2, r10
    	strb r2, [r1]
    Boost:
    	mov r0, r8
    	mov r1, #0xA7
    	mul r0, r1
    	lsr r0, #0x7
    	mov r8, r0
    	mul r7, r1
    	lsr r7, #0x7
    	b Return
    NormalizeCheck:
    	cmp r1, #0x61      @ normalize ability ID
    	bne Return
    Normalize:
    	mov r0, #0x0
    	mov r10, r0
    Return:
    	ldr r0, [sp, #0x4]
    	ldrh r0, [r0, #0xA]
    	str r0, [sp, #0x1C]
    	ldrh r0, [r6, #0x2E]
    	cmp r0, #0xAF
    	bne NoEnigmaBerry
    	ldr r1, .Return
    	bx r1
    NoEnigmaBerry:
    	ldr r0, .Return2
    	bx r0
    
    .align 2
    .ChangeTypeLoc: .word 0x0202449C
    .Return: .word 0x0806961B
    .Return2: .word 0x08069635
     
    I see why you are confused - the abilities posted publicly assume you have set up your abilities ordered the same way they are in the game. Here is an updated script that you can use (I removed pixilate since you do not have fairy type). The 0xAF, etc, are the ability ID the game will check for on the user pokemon. This is assigned in the base stats data structure and is based on the ability name/description order in the relevant tables. The original gen 3 abilities go from index 0x0 (Stench) to 0x76 (Cacophany or Air Lock I forget). So If you expand these tables and add pointers to Refrigerate strings, it would be ability ID 0x77 and you would replace 0xAF with 0x77.

    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    .global typechangeabilities
    
    BufferAbility:
    	mov r0, r6
    	add r0, #0x20
    	ldrb r1, [r0]
    NormalCheck:
    	mov r0, r10
    	cmp r0, #0x0
    	bne NormalizeCheck
    RefrigerateCheck:
    	cmp r1, #0xAF         @ regrigerate ability ID
    	bne AerilateCheck
    Refrigerate:
    	mov r0, #0xF
    	b StoreType
    AerilateCheck:
    	cmp r1, #0xB9      @ aerilate ability ID
    	bne Return
    Aerilate:
    	mov r0, #0x2
    StoreType:
    	mov r10, r0
    	ldr r0, .ChangeTypeLoc
    	ldr r1, [r0]
    	add r1, #0x13
    	ldrb r1, [r1]
    	mov r2, #0x3F
    	and r2, r1
    	cmp r2, #0x0
    	bne Return
    	mov r2, r10
    	strb r2, [r1]
    Boost:
    	mov r0, r8
    	mov r1, #0xA7
    	mul r0, r1
    	lsr r0, #0x7
    	mov r8, r0
    	mul r7, r1
    	lsr r7, #0x7
    	b Return
    NormalizeCheck:
    	cmp r1, #0x61      @ normalize ability ID
    	bne Return
    Normalize:
    	mov r0, #0x0
    	mov r10, r0
    Return:
    	ldr r0, [sp, #0x4]
    	ldrh r0, [r0, #0xA]
    	str r0, [sp, #0x1C]
    	ldrh r0, [r6, #0x2E]
    	cmp r0, #0xAF
    	bne NoEnigmaBerry
    	ldr r1, .Return
    	bx r1
    NoEnigmaBerry:
    	ldr r0, .Return2
    	bx r0
    
    .align 2
    .ChangeTypeLoc: .word 0x0202449C
    .Return: .word 0x0806961B
    .Return2: .word 0x08069635

    Thank you! However, I do have an issue with this unfortunately. I have inserted the code and changed the bytes where it's mentioned that I should but now when I get into a battle the game freezes. I am almost positive there is some kind of typo in the bytes he says we are supposed to change or I'm doing something else wrong. Would you mind testing this in your emerald rom to see if it works?
     
    He has other abilities than Refrigerate in the code (Pixelate and Aerilate). Does he make those 78 and 79?

    If that's how its ordered in your ability tables, then yes.

    Thank you! However, I do have an issue with this unfortunately. I have inserted the code and changed the bytes where it's mentioned that I should but now when I get into a battle the game freezes. I am almost positive there is some kind of typo in the bytes he says we are supposed to change or I'm doing something else wrong. Would you mind testing this in your emerald rom to see if it works?

    I don't hack emerald so I can't test it for you, but my guess is something went wrong with the insertion. Check the VBA dissasembler at 0806960E to make sure it says
    Code:
    ldr r0, =(0x08FE3E01)   @ assuming you kept the same address in your rom
    bx r0

    You might have also changed the wrong byte in the compiled code. I would change the text in the script and re-compile it into compiled code.
     
    If that's how its ordered in your ability tables, then yes.



    I don't hack emerald so I can't test it for you, but my guess is something went wrong with the insertion. Check the VBA dissasembler at 0806960E to make sure it says
    Code:
    ldr r0, =(0x08FE3E01)   @ assuming you kept the same address in your rom
    bx r0

    You might have also changed the wrong byte in the compiled code. I would change the text in the script and re-compile it into compiled code.


    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    .global typechangeabilities
    
    BufferAbility:
    	mov r0, r6
    	add r0, #0x20
    	ldrb r1, [r0]
    NormalCheck:
    	mov r0, r10
    	cmp r0, #0x0
    	bne NormalizeCheck
    RefrigerateCheck:
    	cmp r1, #0x78         @ regrigerate ability ID
    	bne AerilateCheck
    Refrigerate:
    	mov r0, #0xF
    	b StoreType
    AerilateCheck:
    	cmp r1, #0x79      @ aerilate ability ID
    	bne Return
    Aerilate:
    	mov r0, #0x2
    StoreType:
    	mov r10, r0
    	ldr r0, .ChangeTypeLoc
    	ldr r1, [r0]
    	add r1, #0x13
    	ldrb r1, [r1]
    	mov r2, #0x3F
    	and r2, r1
    	cmp r2, #0x0
    	bne Return
    	mov r2, r10
    	strb r2, [r1]
    Boost:
    	mov r0, r8
    	mov r1, #0xA7
    	mul r0, r1
    	lsr r0, #0x7
    	mov r8, r0
    	mul r7, r1
    	lsr r7, #0x7
    	b Return
    NormalizeCheck:
    	cmp r1, #0x80      @ normalize ability ID
    	bne Return
    Normalize:
    	mov r0, #0x0
    	mov r10, r0
    Return:
    	ldr r0, [sp, #0x4]
    	ldrh r0, [r0, #0xA]
    	str r0, [sp, #0x1C]
    	ldrh r0, [r6, #0x2E]
    	cmp r0, #0xAF
    	bne NoEnigmaBerry
    	ldr r1, .Return
    	bx r1
    NoEnigmaBerry:
    	ldr r0, .Return2
    	bx r0
    
    .align 2
    .ChangeTypeLoc: .word 0x0202449C
    .Return: .word 0x0806961B
    .Return2: .word 0x08069635

    So here is the script I'm using.

    After inserting into the rom everything is fine.

    The issue arises when I attempt to repoint this code using the offset listed at the bottom.

    "01 48 00 47 00 0 xx+1 xx xx 08 at 0806960E"

    https://i.gyazo.com/551caab17832253b534bbdb80be5a2b2.png

    This is the code I have placed at the offset (you can't search the first 08 in a hex editor so it has to be 00 and then the offset. Is this a mistake?)

    https://i.gyazo.com/7dafdebbe441c21fe60763cafa7a22ff.png

    This is what I see when I check VBA disassembler (so i definitely did something wrong somehow?)
    I am following the instructions verbatim but there is something going wrong. Am I missing something in how the offset is supposed to be written? It says XX+1 XX XX so I am converting FE 33 00 to FF 33 00 in the area where I need to place the XX XX XX.

    Attempting to use any attacks causes a crash

    EDIT: So I decided to try changing my offset to be formatted as ZZ YY XX+1 the way a thumb script normally is (I didn't do this before because is just says do xx+1 xx xx) and now the abilities seem to just do nothing instead. No crash, but the abilities are totally useless
     
    Last edited:
    If that's how its ordered in your ability tables, then yes.



    I don't hack emerald so I can't test it for you, but my guess is something went wrong with the insertion. Check the VBA dissasembler at 0806960E to make sure it says
    Code:
    ldr r0, =(0x08FE3E01)   @ assuming you kept the same address in your rom
    bx r0

    You might have also changed the wrong byte in the compiled code. I would change the text in the script and re-compile it into compiled code.


    Just to clarify for when you see this I have managed to get this accomplished:

    https://i.gyazo.com/c0f82224f6e4ca729edad185724b537c.png

    I have the proper code assembled in the bytes I was told to change in the THUMB script

    Here it is in hex:

    https://i.gyazo.com/77af6ec5face4d4b06d6fdcc9873e26e.png


    I tried making the abilities index in the thumb script 78, 79, and 80 and had no results.

    I tried converting 78, 79, and 80 from dec to hex and re-compiling and inserting the script and also had no results.

    The game isn't crashing or anything, it's just the abilities do literally nothing. I even tried overwriting an existing ability instead of one of the empty, expanded ones just to test and it still did nothing.

    I just can't figure out what I'm doing wrong here...
     
    Just to clarify for when you see this I have managed to get this accomplished:

    https://i.gyazo.com/c0f82224f6e4ca729edad185724b537c.png

    I have the proper code assembled in the bytes I was told to change in the THUMB script

    Here it is in hex:

    https://i.gyazo.com/77af6ec5face4d4b06d6fdcc9873e26e.png


    I tried making the abilities index in the thumb script 78, 79, and 80 and had no results.

    I tried converting 78, 79, and 80 from dec to hex and re-compiling and inserting the script and also had no results.

    The game isn't crashing or anything, it's just the abilities do literally nothing. I even tried overwriting an existing ability instead of one of the empty, expanded ones just to test and it still did nothing.

    I just can't figure out what I'm doing wrong here...

    I think you should read some ASM insertion tutorials, you seem to be confused about how the hook works. if you insert the compiled code at 0xfe3e00 you should insert
    Code:
    01 48 00 47 00 00 01 3e fe 08 at 0x6960E

    where 01 3e fe 08 is the pointer+1 to your compiled code. That is what is meant by insert xx+1 xx xx 08 at 0x[offset].
     
    Back
    Top