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

Help Thread: ASM & Disassembly

Status
Not open for further replies.
534
Posts
11
Years
    • Age 26
    • Seen Jul 24, 2023
    Okay I see something. You say stuff like "A8+12=BA"
    But 0x12 is the number of items, right? You're adding 0x12 items, but each one is taking up 4 bytes. So you'd actually have to do 0x12 times four = 72 = 0x48.
    Oh crap. And all this time I thought that was 0x203988C + something = position of the next pocket. :( I thought so.
    Do you know how to write a routine? If not, I can help walk you through it. Because all that you should really care about is this:I think that looking at the hex and attempting to change the code byte by byte is a waste and only serves to create extra work.
    Uhm... Just a tiny bit. And all the routine that I ever did from scratch was a multiply variables and a change gender routine, both of which were based off of FBI's examples. I'd be really glad if you'd walk me through it! :D
     

    Kimonas

    %string not found
    91
    Posts
    13
    Years
  • Not entirely sure if I should post it here, but is there any replacement for IDA on linux or should I just use wine?
     
    417
    Posts
    9
    Years
    • Seen Nov 20, 2016
    Not entirely sure if I should post it here, but is there any replacement for IDA on linux or should I just use wine?
    I'm not sure. But one thing that I'd point out is that it isn't just about IDA itself. One of the biggest draws is being able to use knizz's idb. The power comes from the documentation in that specific file. So there may be some other good interactive disassembler (no clue), but it would be pointless if it couldn't also read the FireRed idb (or Emerald). Use wine :D
     

    C me

    Creator of Pokemon League Of Legends
    681
    Posts
    10
    Years
    • Seen Apr 9, 2021
    So the last thing I need for my hack now is to fix status effects. I've been looking at the setrest routine because it always sets the sleep turns to 3. In Emerald it's at 0x050528.

    I've found the length that you sleep for is determined by the byte at 0x0505C3 because of the mov r1, #0x3. But what I don't understand is where in RAM this number is stored because surely each turn it goes down and the game checks to see how many turns are left. The RAM locations in the routine are just the common ones like userbank and CurrentBS, nothing that relates to the sleep length.

    Eventually I'd like to change the main status effects to last for a set number of turns like in rest instead of lasting forever or having a random chance of wearing off.

    It would be really cool if someone could help me understand how to go about doing this and if there is an easier way to do it.
     
    4
    Posts
    7
    Years
    • Seen Jun 7, 2016
    I posted this over in the quick questions and answers, but I'm not sure if it's the right place since it's related to the Pokemon Crystal disassembly.

    I'm farily decent when it comes to programming, or at least editing and adding scripts to the already existing assembly code, but I just can't figure out how I'm supposed to edit or add maps in the Pokecrystal Disassembly.

    I can't find any guides, nothing at all anywhere on the internet. I'm sure if I should kick myself in the head for not being able to google or if they just don't exist at all.

    I supposed these were contained in the .blk files, but I have no way of editing them. I read some people saying that they used Crystalmap to do this, but even then they didn't explain how crystalmap is used at all, and since the program is used to edit an already existing ROM instead of the source code it's not very helpful in my case.

    If anyone can steer me in the right direction or can be kind enough to help me on this front they'd have my eternal gratitude.

    Once again sorry if I posted this in two threads, I wasn't sure which one was the right one as this seems to be more code-oriented.
     
    4
    Posts
    7
    Years
    • Seen Jun 7, 2016
    I found out the answer to my above question, I'm just going to write it here so that maybe someone in my same situation will have a solution ready.

    To edit maps in pokecrystal, look for crowdmap, it uncompresses the tilesets and has a WYSIWYG map and event editor.

    Moving to something else, any tips on replacing tilesets? As of now, even with the uncompressed tilesets, they're all messed up and it's really hard to make out what's on them. Is there any easier way to fix this or do I just need to edit them as they are?
     
    325
    Posts
    10
    Years
  • So recently I've been trying to port my project over to FBI's empty template, found here. I can get it to compile after changing the path in insert2, but how would I write hooks? The hooks file doesn't seem to do anything, because the only place that is changed is the offset specified in linker.ld.

    As an alternative, I've looked at armips, but I'm not quite sure how to handle it. I want to use 0.8 because it has more features, but right now I'm not sure how to get it in its .exe form. Any idea how to properly make it? The link is here.
     
    Last edited:

    C me

    Creator of Pokemon League Of Legends
    681
    Posts
    10
    Years
    • Seen Apr 9, 2021
    I'm having a problem with this routine in Emerald.

    Spoiler:
    It's supposed to check for the first gym badge (flag 0x867), then if it's set it checks for the other gym badges. It then branches to a script which adds 5 to the base power ram location 0x02024400 per badge. This is to increase the base power of a move as you progress through the game. The asm is called before the damagecalculation.

    Currently it just freezes the game. What's wrong with it?
     
    325
    Posts
    10
    Years
  • I'm having a problem with this routine in Emerald.

    [massive wall of text]

    It's supposed to check for the first gym badge (flag 0x867), then if it's set it checks for the other gym badges. It then branches to a script which adds 5 to the base power ram location 0x02024400 per badge. This is to increase the base power of a move as you progress through the game. The asm is called before the damagecalculation.

    Currently it just freezes the game. What's wrong with it?
    As far as I can see, there are a couple of small problems with this routine, as well as some things that we don't know. First of all, where are you hooking from? We need to know the offset of the hook.

    The first problem with this routine is that you don't actually get 0x867 into r0 in the very beginning.
    Code:
    .thumb
    
    start:
        mov r0, #0x86
        lsl r0, r0, #0x4
        add r0, r0, #0x7
    This is what you should be doing to get 0x867 into r0.

    In addition, some things are rather confusing. What is the function at 0x809D790? I know this is the get_flag address, but that's because I went and checked. You should use a label. Your first check is wrong as well. If you wanted to jump to the end if the first flag's not set, then just jump to the end rather than jumping to somewhere that jumps to the end.

    What I think you're trying to do; get the first flag in r0, then seeing if that flag is set. If it is, check to see if the next flag is set, otherwise jump to the first battlescript. If the second badge is set, check the third badge, etc.

    What you're actually doing; loading a flag into r0, then comparing that. If it is set, then it'll continue to add 1 to the result of the the function you called earlier. This will either cause only the first or second check to actually result in anything.

    My suggestion; drop the battlescript, it's rather complicated to call a battlescript in a function. Instead, read and write directly to that offset. Also, edit your checks and your flag checks.
    Code:
    start:
    push
    load byte from base_power(0x02024400) into r5
    get flag in both r0 and r4
    bl to flag_check
    check if the flag was set
    if it wasn't, b to the_end
    add five to r5
    add 1 to r4
    bl to flag_check
    check to see if second flag was set
    if it wasn't b to the_end
    add five to r5
    add 1 to r4, then bl to flag_check
    (you can do this until you checked all your flags)
    
    the_end:
    store r5 in 0x02024400
    pop
    
    flag_check:
    move r4 to r0
    make r1 0x0809D790 + 1
    bx r1
    This is kinda sloppy and can be done by a loop, but once you make a routine resembling this, I'll show you how to make this into a loop.

    ~EDIT~ Oh yeah and just as a reminder, you should add a check to make sure that this routine only does this to one move or else you'll be increasing the power of every move. In addition, the AI will calculate how to use that move based on its original base power, and will get the same bonus that you do when using this move.
     
    Last edited:

    C me

    Creator of Pokemon League Of Legends
    681
    Posts
    10
    Years
    • Seen Apr 9, 2021
    As far as I can see, there are a couple of small problems with this routine, as well as some things that we don't know. First of all, where are you hooking from? We need to know the offset of the hook.

    It's not being hooked from anywhere, it's being callasmd in a unique move effect.

    The first problem with this routine is that you don't actually get 0x867 into r0 in the very beginning.
    Code:
    .thumb
    
    start:
        mov r0, #0x86
        lsl r0, r0, #0x4
        add r0, r0, #0x7
    This is what you should be doing to get 0x867 into r0.
    (Why was I looking for 867 instead of 0x867? derp) I don't understand the maths here. What does the lsl line do that mul r0, #0x10 wouldn't do?

    My suggestion; drop the battlescript, it's rather complicated to call a battlescript in a function. Instead, read and write directly to that offset. Also, edit your checks and your flag checks.
    Code:
    start:
    push
    load byte from base_power(0x02024400) into r5
    get flag in both r0 and r4
    bl to flag_check
    check if the flag was set
    if it wasn't, b to the_end
    add five to r5
    add 1 to r4
    bl to flag_check
    check to see if second flag was set
    if it wasn't b to the_end
    add five to r5
    add 1 to r4, then bl to flag_check
    (you can do this until you checked all your flags)
    
    the_end:
    store r5 in 0x02024400
    pop
    
    flag_check:
    move r4 to r0
    make r1 0x0809D790 + 1
    bx r1
    This is kinda sloppy and can be done by a loop, but once you make a routine resembling this, I'll show you how to make this into a loop.
    I didn't know it was possible to write to a byte directly. What would be the point in loading the byte then doing the addition? Wouldn't it be simpler to just write the base power value? Then the summary screen value won't be confusing (Since the bp value will be --- and some npc will just tell the player that it changes per badge)

    ~EDIT~ Oh yeah and just as a reminder, you should add a check to make sure that this routine only does this to one move or else you'll be increasing the power of every move. In addition, the AI will calculate how to use that move based on its original base power, and will get the same bonus that you do when using this move.
    It would only affect the moves with the move effect that calls the routine so it should be fine. AI will be AI, can't do much with that. I don't mind the AI having the same bonus, the badge thing is just a good measurement of game progression so it makes sense that the AI's attacks would hurt more too.
     

    pokedude9

    Creator (with Diego) of AME and ASE
    31
    Posts
    8
    Years
    • Seen Jan 1, 2017
    (Why was I looking for 867 instead of 0x867? derp) I don't understand the maths here. What does the lsl line do that mul r0, #0x10 wouldn't do?

    MUL requires a second register that contains 0x10 as value already, whereas LSL accepts immediate values.
     
    325
    Posts
    10
    Years
  • It's not being hooked from anywhere, it's being callasmd in a unique move effect.
    Ah, ok. I didn't know that.

    (Why was I looking for 867 instead of 0x867? derp) I don't understand the maths here. What does the lsl line do that mul r0, #0x10 wouldn't do?
    I looked at it on a bitwise level. 0x86 is 10000110b, and 7 is 0111b. Because mov only accepts one byte, I loaded 0x86 into r0. Then I shifted it to the left by four spaces(note that 7 takes up four spaces). This makes 0x860. Adding 7 is obvious after that. It's shorter, and yeah, pokedude9 is right.

    I didn't know it was possible to write to a byte directly. What would be the point in loading the byte then doing the addition? Wouldn't it be simpler to just write the base power value? Then the summary screen value won't be confusing (Since the bp value will be --- and some npc will just tell the player that it changes per badge)
    You can store a byte, a half-word, or a word with strb, strh, and str respectively. Sometimes this is difficult becuase of malloc-ing, but the BP is stored in one location.
    I see, I thought you had a set base power like 50 for 0 badges and then added to it every time rather than it being null. In that case, load the base power of 0 badges into r5 in the beginning rather than loading from 0x02024400, and then you can add as you go along.

    It would only affect the moves with the move effect that calls the routine so it should be fine. AI will be AI, can't do much with that. I don't mind the AI having the same bonus, the badge thing is just a good measurement of game progression so it makes sense that the AI's attacks would hurt more too.
    K, just wanted to make sure I understood.
     

    C me

    Creator of Pokemon League Of Legends
    681
    Posts
    10
    Years
    • Seen Apr 9, 2021
    Code:
    start:
    push
    load byte from base_power(0x02024400) into r5
    get flag in both r0 and r4
    bl to flag_check
    check if the flag was set
    if it wasn't, b to the_end
    add five to r5
    add 1 to r4
    bl to flag_check
    check to see if second flag was set
    if it wasn't b to the_end
    add five to r5
    add 1 to r4, then bl to flag_check
    (you can do this until you checked all your flags)
    
    the_end:
    store r5 in 0x02024400
    pop
    
    flag_check:
    move r4 to r0
    make r1 0x0809D790 + 1
    bx r1

    So I've translated most of your example. I've highlighted the ones I can't get.

    Spoiler:

    I think everything else is fine.
     
    325
    Posts
    10
    Years
  • So I've translated most of your example. I've highlighted the ones I can't get.

    Spoiler:


    I think everything else is fine.
    You're really close now, just a few more edits and you've got it.

    The first thing you should pay attention to is the syntax that add needs. It goes
    add [register that the sum gets put into], [register to add], [second register to add or immediate]
    lsl has pretty much the same syntax, so that's worth noting. You should go over the whole thing and check all your adds and lsls to make sure you're actually doing what you want it to.

    Another thing to note is that flag_check, or 0x0809D790+1, returns true or false to r0 rather than r1, so you should change your cmp r1, #0 to r0, #0.

    As for your first highlighted section, you're close. By loading 0x02024400 into r5, you've discarded all of the the base power you had been storing in r5. You should load 0x02024400 into r0, then strb r5, [r0].

    You're more or less right? mov in the ROM is only used as mov r0, #[immediate], but we can still write mov r0, r1 and it'll come out correctly. Your assembler will read that and realize that you want to move one register into another(the register on the right into the register on the left). It'll assemble as add r0, r1, #0, so be aware of this when you look at your routine in a debugger/disassembler.
     

    C me

    Creator of Pokemon League Of Legends
    681
    Posts
    10
    Years
    • Seen Apr 9, 2021
    The first thing you should pay attention to is the syntax that add needs. It goes
    add [register that the sum gets put into], [register to add], [second register to add or immediate]
    lsl has pretty much the same syntax, so that's worth noting. You should go over the whole thing and check all your adds and lsls to make sure you're actually doing what you want it to.

    Another thing to note is that flag_check, or 0x0809D790+1, returns true or false to r0 rather than r1, so you should change your cmp r1, #0 to r0, #0.

    So it would be
    lsl r4, r0, #0x4
    add r4, r0, #0x7 and the other adds:
    add r5, r0, #0x5
    add r4, r0, #0x1

    How does the flag check return to r0 when it's ldr r1?
     
    325
    Posts
    10
    Years
  • How does the flag check return to r0 when it's ldr r1?
    Still slightly off I'm afraid. In order to shift left by four to r4, it'd be lsl r4, r4, #0x4. The first r4 is the destination, the second is the register you're shifting, and the third parameter is the amount of shifts you want to make. So if you want to just add to one register, you'd do add r5, r5, #0x5 and stuff like that.

    Alternatively, the assembler assumes certain things in cases where you don't use all the parameters. add r5, #0x5 is the same thing as add r5, r5, #0x5. This is different from add r5, r0, #0x5. In the last case that I showed you, you're adding 5 to r0, then storing r0 + 5 in r5.

    The flag check function is similar to many others. I told you to bx r1 because r0 needed to hold the flag. That function checks the flag number to make sure it's alright, then loads the saveblock and checks the flag. If it's set, it moves 1 into r0. If it's not, it moves 0 into r0.
     

    C me

    Creator of Pokemon League Of Legends
    681
    Posts
    10
    Years
    • Seen Apr 9, 2021
    Still slightly off I'm afraid.

    Code:
    start:
        push {r0-r5}
        mov r5, #0x3C 
        mov r4, #0x86        
        lsl r4, r4, #0x4    
        add r4, r4, #0x7    
        bl flag_check        
        cmp r0, #0x0        
        beq the_end        
        add r5, r5, #0x5    
        add r4, r4, #0x1
        bl flag_check        
        cmp r0, #0x0        
        beq the_end        
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        b the_end    
        
        
    the_end:
        ldrb r0, = 0x02024400 
        strb r5, [r0]        
        pop {r0-r5}
    
    flag_check:
        mov r0, r4
        ldr r1, = 0x809D790 +1
        bx r1
    I had to take out the LR or it wouldn't assemble but it still just freezes the game.
     
    325
    Posts
    10
    Years
  • Code:
    start:
        push {r0-r5}
        mov r5, #0x3C 
        mov r4, #0x86        
        lsl r4, r4, #0x4    
        add r4, r4, #0x7    
        bl flag_check        
        cmp r0, #0x0        
        beq the_end        
        add r5, r5, #0x5    
        add r4, r4, #0x1
        bl flag_check        
        cmp r0, #0x0        
        beq the_end        
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        bl flag_check
        cmp r0, #0x0
        beq the_end
        add r5, r5, #0x5
        add r4, r4, #0x1
        b the_end    
        
        
    the_end:
        ldrb r0, = 0x02024400 
        strb r5, [r0]        
        pop {r0-r5}
    
    flag_check:
        mov r0, r4
        ldr r1, = 0x809D790 +1
        bx r1
    I had to take out the LR or it wouldn't assemble but it still just freezes the game.
    Oh, I see what you did. The first time you made that routine, you made a small mistake at the very end, which is why it wouldn't assemble.

    lr is the last called location, and pc is the offset of the next opcode to be read. You were trying to pop lr rather than pc, which is why it wouldn't assemble. Add , lr to your push, and , pc to your pop and then it should work.

    ~EDIT~ I guess what I'm trying to say is that while you should always pop what you push, pc and lr are exceptions. When you push lr, pop pc and you will return to the function that it was at before.
     
    Status
    Not open for further replies.
    Back
    Top