• Just a reminder that providing specifics on, sharing links to, or naming websites where ROMs can be accessed is against the rules. If your post has any of this information it will be removed.
  • Ever thought it'd be cool to have your art, writing, or challenge runs featured on PokéCommunity? Click here for info - we'd love to spotlight your work!
  • Our weekly protagonist poll is now up! Vote for your favorite Trading Card Game 2 protagonist in the poll by clicking here.
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Help Thread: ASM & Disassembly

Status
Not open for further replies.
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
 
Not entirely sure if I should post it here, but is there any replacement for IDA on linux or should I just use wine?
 
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
 
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.
 
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.
 
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?
 
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:
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?
 
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:
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.
 
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.
 
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.
 
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.
 
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?
 
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.
 
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.
 
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