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

Code: ASM Resource Thread

19
Posts
7
Years
    • Seen Apr 14, 2017
    Good job :). I was pretty lazy back then and just duplicated the font functions :D.

    Seems you're quite proficient in ASM. Wonder if you use IDE?

    Thanks! Did you mean to ask if I use IDA? If so, yes. Been using it for years now, mainly with Android OS development (patching old closed-source libs to work on newer Android versions for example). This is my first time writing any substantial assembly though, just so happens that reading assembly the past few years translated well into writing it.

    In a way, ARM assembly is really not that different from programming in high-level languages like C. I just look at all the opcodes like functions, registers are variables, etc. Just takes more steps to do a particular task.

    I've also made use of the no$gba debugger, that's how I find tricks to save instructions, like r0 containing a return address and the usage of r9 to determine which code to run for the stat coloring merger.

    Sorry, I tend to ramble on and talk a lot. :p
     
    794
    Posts
    10
    Years
  • Thanks! Did you mean to ask if I use IDA? If so, yes. Been using it for years now, mainly with Android OS development (patching old closed-source libs to work on newer Android versions for example). This is my first time writing any substantial assembly though, just so happens that reading assembly the past few years translated well into writing it.

    In a way, ARM assembly is really not that different from programming in high-level languages like C. I just look at all the opcodes like functions, registers are variables, etc. Just takes more steps to do a particular task.

    I've also made use of the no$gba debugger, that's how I find tricks to save instructions, like r0 containing a return address and the usage of r9 to determine which code to run for the stat coloring merger.

    Sorry, I tend to ramble on and talk a lot. :p

    Yeah I meant IDA, lol. I asked, because I've got an up-to-date Emerald IDB. I know Touched has one in its signature, but it has less stuff labeled. Here's the link: https://www.dropbox.com/s/mksltpeelzj1tmi/BPEE_updated2.idb?dl=0

    And yeah I use no$gba debugger too, a pretty handy tool.
     
    352
    Posts
    7
    Years
    • Seen Mar 10, 2022
    Made another improvement to the reusable pokeballs: safari balls can now be reused as well!

    Code:
    .text
    .align 2
    .thumb
    
    @ FE3AA - 00 21
    @ 56818 - 00 48 00 47 XX+1 XX XX XX
    @ 3F008 - 02 E0 C0 46 C0 46 C0 46 [B][COLOR="Red"]! NEW[/COLOR][/B]
    @ Optional: change initial safari ball count?: FC0E6 - XX 20, XX = initial count
    
    main:
    	@ if safari ball counter is not 0, then that's what we need to delete
    	ldr r1, .safari_ball_count
    	ldrb r0, [r1]
    	cmp r0, #0x0
    	bne delete_safari_ball
    	
    	@ ...otherwise, delete the last used item (if it's a pokeball)
    	ldr r0, .last_used_item
    	ldrh r0, [r0]
    	@ checks that the item id is premier ball or lower
    	cmp r0, #0xC
    	bls delete_ball_in_bag
    	@ support for custom pokeballs can be added like so:
    	@ cmp r0, #CUSTOM_BALL_ID
    	@ beq delete_ball_in_bag
    	
    	b finish
    
    
    delete_safari_ball:
    	@ r0 already contains current safari ball count, and
    	@ r1 already contains safari ball count memory address
    	sub r0, #1
    	strb r0, [r1]
    	b finish
    
    
    delete_ball_in_bag:
    	@ r0 already contains last_used_item.
    	mov r1, #1
    	ldr r2, .bag_remove_item
    	bl x_r2
    	b finish
    
    
    finish:
    	mov r9, r4
    	mov r10, r5
    	pop {r4-r7}
    	pop {r2}
    x_r2:
    	bx r2
    
    
    .align 2
    .last_used_item:
    	.word 0x0203CE7C
    .bag_remove_item:
    	.word 0x080D6AA4|1
    .safari_ball_count:
    	.word 0x0203A04C

    Ported to Fire Red

    Code:
    .text
    .align 2
    .thumb
    
    [COLOR="red"]@ 0xA1E30 - 00 21
    @ 0x2D924 - 00 48 00 47 XX+1 XX XX 08
    @ 0x16AD8 - 02 E0 C0 46 C0 46 C0 46
    @ Optional: change initial safari ball count?: 0xA0ED2 - XX 20, XX = initial count[/COLOR]
    main:
    	@ if safari ball counter is not 0, then that's what we need to delete
    	ldr r1, .safari_ball_count
    	ldrb r0, [r1]
    	cmp r0, #0x0
    	bne delete_safari_ball
    	
    	@ ...otherwise, delete the last used item (if it's a pokeball)
    	ldr r0, .last_used_item
    	ldrh r0, [r0]
    	@ checks that the item id is premier ball or lower
    	cmp r0, #0xC
    	bls delete_ball_in_bag
    	@ support for custom pokeballs can be added like so:
    	@ cmp r0, #CUSTOM_BALL_ID
    	@ beq delete_ball_in_bag
    	
    	b finish
    
    
    delete_safari_ball:
    	@ r0 already contains current safari ball count, and
    	@ r1 already contains safari ball count memory address
    	sub r0, #1
    	strb r0, [r1]
    	b finish
    
    
    delete_ball_in_bag:
    	@ r0 already contains last_used_item.
    	mov r1, #1
    	ldr r2, .bag_remove_item
    	bl x_r2
    	b finish
    
    x_r2:
    	bx r2
    
    
    finish:
    	mov r9, r4
    	mov r10, r5
    	pop {r4-r7}
    	pop {r0}
    	bx r0
    
    .align 2
    [COLOR="red"].last_used_item:
    	.word 0x0203AD30
    .bag_remove_item:
    	.word 0x0809A1D8|1
    .safari_ball_count:
    	.word 0x02039994[/COLOR]
     

    ASDBUDDY

    The Derp
    347
    Posts
    7
    Years
  • I think he wants to set a default name while skipping the intro. If you skip the intro via ASM, the default name is left as 0s aka blank.

    Setting a static name to the player


    Well, this is beyond simple, lol. I'll keep my post the same format though, because first post :3

    How to insert:

    Before you begin to insert the routine, there are a few steps. Firstly player names are limited to 8 characters with the eighth character = 0xFF.
    Convert the static name you want from ascii to hex. For OP, he wanted Jesse and James which convert into:
    C4 D9 E7 E7 D9 FF FF FF - Jesse
    C4 D5 E1 D9 E7 FF FF FF -James
    Note that if all eight bytes don't get used, you should pad them with "FF" in your hex editor.
    Now insert the 8 byte names into some free space in your ROM via hex editor and write down the pointers.

    Now copy the following routine into a text editor:
    Spoiler:


    You'll notice that I have the lines:
    Code:
    .CustomNameBoy:
    	.word 0x@pointer to boy name
    
    .CustomNameGirl:
    	.word 0x@pointer to girl name

    Change the 0x@pointer text to 0x[offset you inserted]. No need to add one.
    After you've done that compile and insert into free space.

    Usage:
    You must callasm to the routine, and depending on the Player's gender it will set their name. To have their name inserted before the player starts playing the game, create a level script which calls this routine. If you don't know how, ask in a relevant thread (not here).

    Hi, well I did exactly what you said but now my gba file just shows a blank screen when loaded into the emulator. What should I do?
     
    100
    Posts
    7
    Years
  • Hey, IDK if it is possible, but could it be made so the battle text auto-advances when in battle (like Gen 4)?

    So, instead of being required to press A during certain parts (example: challenge, faint, disable, level up, etc), after 1 second, the next line will load. But you can interrupt it with A as well

    I can make it automatically skip by editing the hex, but it does it immediately.
     
    146
    Posts
    11
    Years
    • CO
    • Seen Mar 16, 2023

    Pokemon Storage (outside the PC)


    Basically, in it's current state, this is effectively a storage system. It stores Pokemon and can be interacted with by the player to withdraw or deposit Pokemon. It's standalone from the PC storage system and is also much smaller (I've limited it to 6, but it can go upto 47). Some things that you will be able to do with this routine (and conjunction with some smaller ones) include:
    - Extra Pokemon storage, you can possibly get a little over 1 box worth
    - Flash back battles (complete swap between stored Pokemon and party Pokemon with capabilities to swap back)
    - Carry a party of greater than 6 Pokemon (you can use the 2nd party for HM slaves, or whatever)
    - Trade evolver guy! He will take your Pokemon and then when you come back it can be evolved! (silent evolution ftw!)
    - Separate Daycare holding larger amount of Pokemon at once

    I've tested it thoroughly and there doesn't seem to be any problems. I will be adding more and more features into this because I believe that it has the potential to become a very useful feature.
    Currently planning to add:
    - Party swap completely all in one go (this will actually be in the very near future..maybe today even :P)
    - Partial swapping (believe it or not, this is hard because there's no graphical support)
    - Suggest me more :D

    How to insert:

    Compile into free space the following routine:
    Spoiler:

    Here's a compiled version:
    Code:
    11 B5 38 48 01 68 00 29 32 D0 37 48 01 38 01 78 06 29 65 D0 01 30 50 22 51 43 40 18 34 49 09 78 32 4A 64 23 59 43 89 18 50 22 32 4B 00 F0 59 F8 2F 49 09 78 05 29 0B D0 05 22 52 1A 64 23 5A 43 2A 48 59 43 40 18 1B 18 19 1C 2A 4B 00 F0 49 F8 29 48 00 21 64 22 29 4B 00 F0 43 F8 22 48 01 38 02 78 27 49 0B 78 01 32 02 70 01 3B 0B 70 37 E0 23 48 00 78 06 28 33 D0 1C 49 64 22 50 43 40 18 04 1C 19 4B 1A 49 09 78 50 22 51 43 C9 18 19 4B 00 F0 27 F8 20 1C 1B 4B 00 F0 23 F8 14 48 00 78 05 28 0B D0 05 22 12 1A 50 23 5A 43 0E 49 58 43 40 18 1B 18 19 1C 0F 4B 00 F0 13 F8 0A 48 C8 21 49 00 40 18 00 21 50 22 0C 4B 00 F0 0A F8 06 48 01 38 02 78 0A 49 0B 78 01 3A 02 70 01 33 0B 70 1F BD 18 47 B8 70 03 02 01 C0 03 02 84 42 02 02 C0 70 03 02 09 0B 04 08 78 44 02 02 D9 5E 1E 08 29 40 02 02 7D E4 03 08
    Usage:

    The routine itself manages party storage and storage extraction. What you need to do is determine which one it performs.
    If you want to remove a Pokemon from the party and into storage, setvar 0x8000 anything but zero
    if you want to remove a Pokemon from storage, setvar 0x8000 0x0
    Which variable you used can be changed, as always, by editing the pointer at the bottom of the routine.
    The next thing is variable 0x8004. I use this variable to determine the slot of extraction for both the Party and the Storage system.
    If I wanted to take the 3rd Pokemon in the party and put it in storage:
    setvar 0x8004 0x2
    setvar 0x8000 0x1
    callasm 0x[routine] +1

    The reason for this is to support easy use of special 0x9F. Though you can use copyvar, I suppose.

    Finally, the routine writes to RAM a counter, which keeps track of how many Pokemon are in the storage.
    This is written at 0x203C000, and can be retrieved by using the "copybyte" scripting command. For example:
    copybyte 0x20370D0 0x203C000 'puts the storage counter into variable 0x800D (lastresult).

    I tried to keep it simple, and do the work inside the routine, hopefully that paid off.
    Here's a very poor sample script. Poor because it handles all the cases, but it doesn't display the system's full potential :P

    Spoiler:

    That's it for now. Keep an eye out for "addons" for this routine in the future :)
    Sorry for the double post. I like seperate posts for my routines to keep the first post's links neat :x


    So for anyone who has used this they know that only the Pre-Compiled version works, and the routine given does not compile to match either and don't work at all for that matter.

    Also the Pre-Compiled version does work but has a bug from using Special 0x9F(Choose Pokemon from party).
    If the player says yes to storing a Pokemon then decides to either press "B" or "Cancel" then the game will jump to the overworld view, glitch out and freeze with a Black screen.

    Now I worked on this all day and was able to rebuild the Pre-Compiled routine so we could actually have the working source.
    FBI's - Pre-Compiled Storage System - Disassembled/Rebuilt Routine
    Code:
    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    
    main:
    push {r0, r4, lr}
        ldr r0, .FROM
        ldr r1,[r0]
        cmp r1, #0x0               @party
        beq addParty
    
    addStorage:    
        ldr r0, .STORAGE
        sub r0, #0x1
        ldrb r1, [r0]
        cmp r1, #0x6               @limit of storage. Change depending on your space situation
        beq end
        add r0, #0x1
        mov r2, #0x50
        mul r1, r2
        add r0, r0, r1             @destination
        ldr r1, =(0x20370C0)       @ 2b Var_8004
        ldrb r1, [r1]
        ldr r2, .PARTY
        mov r3, #0x64
        mul r1, r3
        add r1, r1, r2             @source
        mov r2, #0x50              @size
        ldr r3, =(0x8040B09)       @memcpy_pkm 'void __fastcall memcpy_pkm(void *dst, void *src, unsigned int size)'
        bl linker
        ldr r1, =(0x20370C0)       @need to fix up Player's party slots @ 2b Var_8004
        ldrb r1, [r1]
        cmp r1, #0x5
        beq writeLastZero
        mov r2, #0x5
        sub r2, r2, r1
        mov r3, #0x64
        mul r2, r3                 @size
        ldr r0, .PARTY
        mul r1, r3
        add r0, r0, r1             @dest
        add r3, r3, r0
        mov r1, r3                 @src
        ldr r3, =(0x8040B09)       @memcpy_pkm 'void __fastcall memcpy_pkm(void *dst, void *src, unsigned int size)'
        bl linker
        
    writeLastZero:
        ldr r0, =(0x2024478)       @ 100b    Party Pokemon 6
        mov r1, #0x0
        mov r2, #0x64
        ldr r3, =(0x81E5ED9)       @memset  'void __fastcall memset(char *dst, char pattern, int size)'
        bl linker
    
    correctCounters:
        ldr r0, .STORAGE
        sub r0, #0x1
        ldrb r2, [r0]              @pks in storage counter
        ldr r1, =(0x2024029)       @ 1b    Repeattrainerbattle: Unknown. Loaded if battle type is 9.
        ldrb r3, [r1]              @pks in party
        add r2, #0x1
        strb r2,[r0]
        sub r3, #0x1
        strb r3, [r1]
        b end
        
    addParty:
        ldr r0, =(0x2024029)       @ 1b    Repeattrainerbattle: Unknown. Loaded if battle type is 9.
        ldrb r0, [r0]
        cmp r0, #0x6
        beq end
        ldr r1, .PARTY
        mov r2, #0x64
        mul r0, r2
        add r0, r0, r1             @destination
        mov r4, r0
        ldr r3, .STORAGE
        ldr r1, =(0x20370C0)       @'var 0x8004 determines which slot of storage to take from'
        ldrb r1, [r1]
        mov r2, #0x50              @size
        mul r1, r2
        add r1, r1, r3             @source
        ldr r3, =(0x8040B09)       @memcpy_pkm 'void __fastcall memcpy_pkm(void *dst, void *src, unsigned int size)'
        bl linker
        mov r0, r4                 @update stats
        ldr r3, =(0x803E47D)       @pokemon_calc_effective_stats
        bl linker
        ldr r0, =(0x20370C0)       @adjust the storage   @ 2b Var_8004
        ldrb r0, [r0]
        cmp r0, #0x5               @storage limit minus 1
        beq writeZero
        mov r2, #0x5
        sub r2, r2, r0
        mov r3, #0x50
        mul r2, r3                 @size
        ldr r1, .STORAGE
        mul r0, r3
        add r0, r0, r1             @dest
        add r3, r3, r0
        mov r1, r3                 @src
        ldr r3, =(0x8040B09)       @memcpy_pkm 'void __fastcall memcpy_pkm(void *dst, void *src, unsigned int size)'
        bl linker
    
    writeZero:
        ldr r0, .STORAGE
        mov r1, #0xC8
        lsl r1, r1, #0x1
        add r0, r0, r1
        mov r1, #0x0
        mov r2, #0x50 
        ldr r3, =(0x81E5ED9)       @memset  'void __fastcall memset(char *dst, char pattern, int size)'
        bl linker
        
    updateCounters:
        ldr r0, .STORAGE
        sub r0, #0x1
        ldrb r2, [r0]
        ldr r1, =(0x2024029)       @ 1b    Repeattrainerbattle: Unknown. Loaded if battle type is 9.
        ldrb r3, [r1]
        sub r2, #0x1
        strb r2,[r0]
        add r3, #0x1
        strb r3, [r1]
    
    end:
        pop {r0-r4, pc}
        
    linker:
        bx r3
    
    .align 2
    
    .FROM:
        .word 0x20370B8            @var_8000
    
    .STORAGE:
        .word 0x203C001            @storage location
    
    .PARTY:
        .word 0x2024284            @player's party
    And to go along with that is the XSE script.
    Code:
    Code:
    #dynamic [COLOR=DarkOrange]0xFreeSpaceToStartFrom[/COLOR]
    
    //---------------
    #org @start
    lock
    faceplayer
    copybyte 0x20370D0 0x203C000
    compare 0x800D 0x0
    if 0x1 goto @snippet1
    msgbox @string1 0x5 //"Want your Pokemon back?"
    compare 0x800D 0x1
    if 0x1 goto @snippet2
    goto @snippet1
    
    //---------------
    #org @snippet1
    countpokemon
    copyvar 0x8000 0x800D
    compare 0x8000 0x1
    if 0x3 goto @snippet3
    msgbox @string2 0x5 //"Want to give me a pokemon?"
    compare 0x800D 0x1
    if 0x1 goto @snippet4
    msgbox @string3 0x6 //"Alright, next time then."
    release
    end
    
    //---------------
    #org @snippet2
    setvar 0x8000 0x0
    countpokemon
    compare 0x800D 0x6
    if 0x1 goto @snippet5
    msgbox @string4 0x6 //"Alright, I'll give it to you."
    setvar 0x8004 0x0
    [COLOR=DarkOrange]callasm 0xWhereYouPutYourTheRoutine+1[/COLOR]
    fanfare 0x101
    msgbox @string5 0x6 //"I gave it back."
    release
    end
    
    //---------------
    #org @snippet3
    msgbox @string6 0x6 //"Hi, I can't do anything\nyour slot..."
    release
    end
    
    //---------------
    #org @snippet4
    setvar 0x8000 0x1
    special 0x9F
    waitstate
    lockall
    compare 0x8004 0x7
    if 0x1 goto @snippet6
    countpokemon
    compare 0x800D 0x1
    if 0x3 goto @snippet6
    [COLOR=DarkOrange]callasm 0xWhereYouPutYourTheRoutine+1[/COLOR]
    msgbox @string7 0x6 //"Thanks for giving me this."
    release
    end
    
    //---------------
    #org @snippet5
    msgbox @string8 0x6 //"You're party is full!"
    release
    end
    
    //---------------
    #org @snippet6
    msgbox @string3 0x6 //"Alright, next time then."
    release
    end
    
    
    //---------
    // Strings
    //---------
    #org @string1
    = Want your Pokemon back?
    
    #org @string2
    = Want to give me a pokemon?
    
    #org @string3
    = Alright, next time then.
    
    #org @string4
    = Alright, I'll give it to you.
    
    #org @string5
    = I gave it back.
    
    #org @string6
    = Hi, I can't do anything\nyour slots are full or empty\lor mine are full while yours are\lfull[.]
    
    #org @string7
    = Thanks for giving me this.
    
    #org @string8
    = You're party is full!
    Edit the orange text before compiling.


    Hope this helps anyone.
    When I get the time I will see what I can do about fixing the bug as well.


    Edit_Two:
    Found the bug!
    Special 0x9F lets you choose any Pokemon as well as Eggs.
    And,
    Special 0xBC lets you choose any Pokemon beside Eggs(used for daycare)
    When pressing B var 0x8004 is set to 0x07 so I simply added a compare to fix the script.
     
    Last edited:
    352
    Posts
    7
    Years
    • Seen Mar 10, 2022
    I think he wants to set a default name while skipping the intro. If you skip the intro via ASM, the default name is left as 0s aka blank.

    Setting a static name to the player


    Well, this is beyond simple, lol. I'll keep my post the same format though, because first post :3

    How to insert:

    Before you begin to insert the routine, there are a few steps. Firstly player names are limited to 8 characters with the eighth character = 0xFF.
    Convert the static name you want from ascii to hex. For OP, he wanted Jesse and James which convert into:
    C4 D9 E7 E7 D9 FF FF FF - Jesse
    C4 D5 E1 D9 E7 FF FF FF -James
    Note that if all eight bytes don't get used, you should pad them with "FF" in your hex editor.
    Now insert the 8 byte names into some free space in your ROM via hex editor and write down the pointers.

    Now copy the following routine into a text editor:
    Spoiler:


    You'll notice that I have the lines:
    Code:
    .CustomNameBoy:
    	.word 0x@pointer to boy name
    
    .CustomNameGirl:
    	.word 0x@pointer to girl name

    Change the 0x@pointer text to 0x[offset you inserted]. No need to add one.
    After you've done that compile and insert into free space.

    Usage:
    You must callasm to the routine, and depending on the Player's gender it will set their name. To have their name inserted before the player starts playing the game, create a level script which calls this routine. If you don't know how, ask in a relevant thread (not here).

    It works, but the female player name becomes the same as the male.
     
    Last edited:

    Wesley FG

    Pokémon Kalos Advance !! Gba Hack
    338
    Posts
    15
    Years
  • I've noticed significant demand for working Dawn Stone evolutions, specifically ones that require the mon to be a specific gender. My bad if this is already posted somewhere but here y'all go:

    Code:
    .org 0x4318e
    lsl r0, r0, #0x0
    ldr r2, .MethodAddr
    bx r2
    
    .MethodAddr: .word 0x085B2521 #UPDATE THIS TO MAIN FUNCTION OFFSET+1
    
    
    .org 0x5B2520 #UPDATE THIS TO MOST CONVENIENT FREE SPACE IN YOUR HACK
    cmp r0, #0x7
    beq StandardStone
    cmp r0, #0x14 #UPDATE THIS
    beq MaleStone
    cmp r0, #0x15 #UPDATE THIS
    beq FemaleStone
    b NoEvo
    
    MaleStone:
    push {r1-r3}
    mov r0, r7
    mov r1, r8
    ldr r1, [r1, #0x0]
    bl DetermineGender
    pop {r1-r3}
    cmp r0, #0x0
    beq StandardStone
    b NoEvo
    
    
    FemaleStone:
    push {r1-r3}
    mov r0, r7
    mov r1, r8
    ldr r1, [r1, #0x0]
    bl DetermineGender
    pop {r1-r3}
    cmp r0, #0xFE
    beq StandardStone
    b NoEvo
    
    
    StandardStone:
    ldrh r0, [r1, #0x2]
    cmp r0, r9
    beq Finish
    
    NoEvo:
    ldr r2, .NoEvoReturn
    bx r2
    
    DetermineGender:
    ldr r2, .DetermineGenderFunc
    bx r2
    
    Finish:
    ldr r2, .EvoReturn
    bx r2
    
    .NoEvoReturn: .word 0x08043199
    .EvoReturn: .word 0x0804317d
    .DetermineGenderFunc: .word 0x0803f78d
    Change the values in the lines marked UPDATE THIS to the indexes of male stone evos and female stone evos. Leave their entries blank in the general evolution table; stone evolutions function differently from level-up evolutions.

    the value of "indexes of male stone" is the item value ?

    will have two dawn stone, one work in male and one work in female, it is correct ?

    i not understand it well
     
    352
    Posts
    7
    Years
    • Seen Mar 10, 2022
    the value of "indexes of male stone" is the item value ?

    will have two dawn stone, one work in male and one work in female, it is correct ?

    i not understand it well

    the indexes are your Evolution indexes, one for male stone evo and one for female stone evo, the item index will only be chosen on your editor (G3HS, G3T...)
     
    232
    Posts
    12
    Years
    • Seen Sep 10, 2019
    In response to this:

    Setting a random Secret and Trainer ID


    Requires the insertion of Random Number generator
    So apparently TID isn't set if you skip the intro, and I'm sure SID is probably also not set. The following routine will randomize them for you!


    To insert:

    There's some orange text here, set it to be the pointer to where you inserted the random number generator routine +1 (keep the 0x8 prefix, but don't reverse the pointer).

    After you've fixed the pointer, compile and insert into free space.

    Spoiler:
     
    5,256
    Posts
    16
    Years
  • [FR] Complimentary Premier Ball for purchases of over 9 Poké Balls


    Ever since RSE, the Poké Mart clerk has thrown in a bonus Premier Ball when the player purchases at least 10 Poké Balls. This feature was absent from FireRed, however, presumably for accuracy reasons for the remake factor of the game. To implement this feature, simply assemble the following routine and place a pointer (+1) at x9BF64.

    Code:
    .thumb @ pointer+1 at 0809BF64
    
    main:
        push {r4,r5,lr}
        lsl r0, r0, #0x18
        lsr r4, r0, #0x18    
        lsl r0, r4, #2
        add r0, r0, r4
        lsl r0, r0, #3
        ldr r1, =(0x03005098) @ tasks.args
        add r5, r0, r1
        ldr r0, =(0x030030F0) @ super
        ldrh r1, [r0, #0x2E]
        mov r0, #0x3
        and r0, r1
        cmp r0, #0
        beq end
        
    continue:
        mov r0, #5
        ldr r3, =(0x080722CC|1) @ audio_play
        bl call_via_r3
        mov r1, #0xA
        ldrh r0, [r5, r1]
        cmp r0, #0x4 @ Poké Ball item ID
        bne no_premier_ball
        mov r1, #2
        ldrh r0, [r5, r1]
        cmp r0, #0x9 @ Maximum quantity of Poké Balls to not qualify for a Premier Ball
        ble no_premier_ball
        mov r0, #0xC @ Premier Ball item ID
        mov r1, #1 @ Quantity to give
        ldr r3, =(0x0809A084|1) @ bag_add_item
        bl call_via_r3
        lsl r0, r0, #0x18
        lsr r0, r0, #0x18
        cmp r0, #1
        bne no_premier_ball
        ldr r1, =(0x08XXXXXX) @ Address of string: "I'll throw in a PREMIER BALL, too.[FC][09]"
        ldr r2, =(0x0809BF98|1)
        mov r0, r4
        ldr r3, =(0x0813F75C|1)
        bl call_via_r3
        b end
      
    no_premier_ball:
        mov r0, r4
        ldr r3, =(0x0809BF98|1)
        bl call_via_r3
        
    end:
        pop {r4,r5}
        pop {r0}
        bx r0
        
    call_via_r3:
        bx r3

    The routine specifies an address for the string "I'll throw in a PREMIER BALL, too." as 0x08XXXXXX. Replace this with the address at which you insert the following bytes:
    Code:
    C3 B4 E0 E0 00 E8 DC E6 E3 EB 00 DD E2 00 D5 00 CA CC BF C7 C3 BF CC 00 BC BB C6 C6 B8 00 E8 E3 E3 AD FC 09 FF

    The same string, but with "PREMIER BALL" in title case (i.e. "Premier Ball"), has the following bytes:
    Code:
    C3 B4 E0 E0 00 E8 DC E6 E3 EB 00 DD E2 00 D5 00 CA E6 D9 E1 DD D9 E6 00 BC D5 E0 E0 B8 00 E8 E3 E3 AD FC 09 FF

    As always with strings, it's recommended you place a byte after the FF delimiter at the end of the string to prevent tools which read FF bytes as free space from overwriting the string's delimiter and making the string bug.
     
    Last edited:

    Wesley FG

    Pokémon Kalos Advance !! Gba Hack
    338
    Posts
    15
    Years
  • Someone can convert this asm to EM
    is a screen that display IV and EV screens is very usefull
    https://www.pokecommunity.com/showpost.php?p=9229108&postcount=919
    q_zpshnquzant.gif
     
    232
    Posts
    12
    Years
    • Seen Sep 10, 2019
    REQUEST for FR:

    A 'givepokemon' routine that allows the user to set custom OT name and TID/SID. (useful for creating legal event pokemon)
     
    232
    Posts
    12
    Years
    • Seen Sep 10, 2019
    In response to this:

    Setting a random Secret and Trainer ID


    Requires the insertion of Random Number generator
    So apparently TID isn't set if you skip the intro, and I'm sure SID is probably also not set. The following routine will randomize them for you!


    To insert:

    There's some orange text here, set it to be the pointer to where you inserted the random number generator routine +1 (keep the 0x8 prefix, but don't reverse the pointer).

    After you've fixed the pointer, compile and insert into free space.

    Spoiler:



    Usage:

    setvar 0x8001 0x0
    callasm 0x[this routine +1]
    setvar 0x8001 0x2
    callasm 0x[this routine +1]

    Call it twice like I have, setting var 0x8001 to 0x0 and 0x2 respectively, it will generate a random PID and SID.

    Can anyone confirm that this routine works? My game freezes when using this routine. His random number routine has been inserted. I changed the highlighted orange text from
    Code:
    .word 0x8[random]
    to
    Code:
    .word 0x8800001
     
    Last edited by a moderator:

    Blah

    Free supporter
    1,924
    Posts
    11
    Years
  • Eh, this routine is around the time when I first started. I'm currently very rusty on ASM and haven't tested the fix. Please try this:

    Spoiler:


    Untested, and may not compile as is. Post updates here please.
     
    232
    Posts
    12
    Years
    • Seen Sep 10, 2019
    Eh, this routine is around the time when I first started. I'm currently very rusty on ASM and haven't tested the fix. Please try this:

    Spoiler:


    Untested, and may not compile as is. Post updates here please.
    Works well, thank you!
     
    352
    Posts
    7
    Years
    • Seen Mar 10, 2022

    Adjusting Shiny encounter chance


    Pre-requisites:
    - Shiny Pokemon Generator
    - Random Number Generator


    How to insert:

    Before compiling the routine look at the last line. There is a .word 0x8[RANDOM +1]. Change the content after the 0x8 to be a pointer to where you inserted RANDOM +1.

    Once you've done that, look for the line that says "mov r0, #0x1 @item ID". Change 0x1 to the Item ID for your Shiny charm item. If you don't have one implemented, delete these lines:
    Code:
    	mov r0, #0x1 @item ID
    	mov r1, #0x1
    	ldr r2, =(0x8099F40 +1)
    	bl linker
    	cmp r0, #0x0
    	beq normal
    	mov r0, #0xA
    	lsl r0, r0, #0x7
    	add r0, r0, #0x55 @1/1365 chance with shiny charm
    	b calcChance

    After you've done that, compile and insert the following routine into free space:

    Spoiler:


    Now navigate to 0x3DACE and insert the following byte changes:
    Code:
    00 00 00 4F 38 47 XX XX XX 08
    Where XX XX XX is the reverse hex pointer +1 to where you inserted this routine.


    Usage:

    It's Automagic, also happens to give the shiny chance to Pokemon in wild, trainer Pokemon, given Pokemon ect.

    Right now encounter chance is 1/4096 without shiny charm, and 1/1356 with it.

    There is a way to make it work only with wild and breeding and to make the shiny chance 1/2048?
     
    Back
    Top