• 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?".
  • Forum moderator applications are now open! Click here for details.
  • 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.

Development: Set Disobedience

colcolstyles

Yours truly
1,588
Posts
15
Years
Sorry for the delay. The game uses a very long and inefficient way to perform the modulo operation and it does it about 6 times before it actually starts to edit anything. D:

Well from what I can tell, the game is editing the last byte of the Growth substructure. There is no documentation on that piece of data which means that is possible that it controls obedience. The guy who wrote that article seems to think that it's a halfword (16-bit) but the game reads from it using ldrb so I'm guessing that it is actually two bytes. The 'setobedience' command takes whatever value is stored there, 'and's it with '0x7F' (i.e., clears the most significant bit), 'orr's that with some other value (it was '0x80' for me) and then stores the final result back in the Growth substructure. I'll look more into it later but right now I have to go run a few errands. If anyone's interested, the routine that does what I mentioned above is located at '0x08040A82'.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
Sorry for the delay. The game uses a very long and inefficient way to perform the modulo operation and it does it about 6 times before it actually starts to edit anything. D:

Well from what I can tell, the game is editing the last byte of the Growth substructure. There is no documentation on that piece of data which means that is possible that it controls obedience. The guy who wrote that article seems to think that it's a halfword (16-bit) but the game reads from it using ldrb so I'm guessing that it is actually two bytes. The 'setobedience' command takes whatever value is stored there, 'and's it with '0x7F' (i.e., clears the most significant bit), 'orr's that with some other value (it was '0x80' for me) and then stores the final result back in the Growth substructure. I'll look more into it later but right now I have to go run a few errands. If anyone's interested, the routine that does what I mentioned above is located at '0x08040A82'.

That's interesting, thanks. Don't worry about delays, take your time. I appreciate the effort. :)

Oh, and I thought that ldrb was for reading one byte, and that two bytes = 16 bits. So if the game uses ldrb, it's only loading one byte?
 
Last edited:

colcolstyles

Yours truly
1,588
Posts
15
Years
Oh, and I thought that ldrb was for reading one byte, and that two bytes = 16 bits. So if the game uses ldrb, it's only loading one byte?

I'm sorry, I should have been more clear. The Bulbapedia article says that the last two bytes of the Growth substructure are unknown. It groups them together as one halfword. However, because the game reads from that data in bytes, I'm guessing that instead the "unknown halfword" is actually two unknown bytes (though it might be safe to say that the second byte is no longer unknown).

I'm going to go do a little more research on that byte. Perhaps by looking at Mew's data (who I've heard is disobedient unless obtained legally or something like that) I can figure out if there's a certain value which makes a pokémon disobedient.


edit: At '0x0801D402' the game checks if the player's pokémon is Mew. I expanded the routine to add a check for Squirtle (which was the only other pokémon I had in my party at the time). And look what I got:
Spoiler:


In an unedited ROM, all pokémon except Mew will always obey the player unless they don't have enough badges (but I didn't look up those routines). If the player is using a Mew, it checks the top bit of the last byte in the Growth Structure. If it is set, then Mew will obey. If not, then Mew won't obey. By default, all pokémon don't have that bit set but because it isn't checked, it doesn't matter. However, in order to get Mew to obey, you need to use the 'setobedience' command to set that bit, unless you want to do the work of decrypting the Pokémon data and then recalculating the checksum. Once you use 'setobedience', Mew/Squirtle will start to obey again:
Spoiler:


Because I'm a nice guy, here's the code:

Code:
.text
.align 2
.thumb
.thumb_func
.global hijack

	@ put at 0x0801D404
	@ also put 0x0000 at 0x081D402

main:
	ldr r1, .ADDRESS
	bx r1

.align 2
.ADDRESS:
	.word	0x08720001

That branches off to the new routine at '0x720000' (that address can be changed) which is:

Code:
.text
.align 2
.thumb
.thumb_func
.global obedience

main:
	cmp r0, #0x97		@ if current attacker == Mew
	beq disobey
	cmp r0, #0x07		@ if current attacker == Squirtle
	beq disobey
	
	mov r0, #0x01
	ldr r1, .RESUME
	bx r1
	
disobey:
	ldr r1, .DISOBEY
	bx r1
	
branchlink:
	bx r3

.align 2
.RESUME:
	.word	0x0801D42B
.DISOBEY:
	.word	0x0801D415	@ goes on to check obedient byte

Obviously, you should change #0x07 to #0x06 for Charizard. That should do the trick.
 
Last edited:

PiaCRT

[i]Orange Dev[/i]
934
Posts
13
Years
Perhaps researching what makes herbs/roots make your pokemon happiness go down may help? or maybe gym badges (pokemon up to lvl 30 can obey you)

hope it helps.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
I'm sorry, I should have been more clear. The Bulbapedia article says that the last two bytes of the Growth substructure are unknown. It groups them together as one halfword. However, because the game reads from that data in bytes, I'm guessing that instead the "unknown halfword" is actually two unknown bytes (though it might be safe to say that the second byte is no longer unknown).

I'm going to go do a little more research on that byte. Perhaps by looking at Mew's data (who I've heard is disobedient unless obtained legally or something like that) I can figure out if there's a certain value which makes a pokémon disobedient.


edit: At '0x0801D402' the game checks if the player's pokémon is Mew. I expanded the routine to add a check for Squirtle (which was the only other pokémon I had in my party at the time). And look what I got:
Spoiler:


In an unedited ROM, all pokémon except Mew will always obey the player unless they don't have enough badges (but I didn't look up those routines). If the player is using a Mew, it checks the top bit of the last byte in the Growth Structure. If it is set, then Mew will obey. If not, then Mew won't obey. By default, all pokémon don't have that bit set but because it isn't checked, it doesn't matter. However, in order to get Mew to obey, you need to use the 'setobedience' command to set that bit, unless you want to do the work of decrypting the Pokémon data and then recalculating the checksum. Once you use 'setobedience', Mew/Squirtle will start to obey again:
Spoiler:


Because I'm a nice guy, here's the code:

Code:
.text
.align 2
.thumb
.thumb_func
.global hijack

	@ put at 0x0801D404
	@ also put 0x0000 at 0x081D402

main:
	ldr r1, .ADDRESS
	bx r1

.align 2
.ADDRESS:
	.word	0x08720001

That branches off to the new routine at '0x720000' (that address can be changed) which is:

Code:
.text
.align 2
.thumb
.thumb_func
.global obedience

main:
	cmp r0, #0x97		@ if current attacker == Mew
	beq disobey
	cmp r0, #0x07		@ if current attacker == Squirtle
	beq disobey
	
	mov r0, #0x01
	ldr r1, .RESUME
	bx r1
	
disobey:
	ldr r1, .DISOBEY
	bx r1
	
branchlink:
	bx r3

.align 2
.RESUME:
	.word	0x0801D42B
.DISOBEY:
	.word	0x0801D415	@ goes on to check obedient byte

Obviously, you should change #0x07 to #0x06 for Charizard. That should do the trick.

You're a saint! lol!

Thank you very much. I really do appreciate it. I'm gonna test it out and then post the code with credit in the first post of the thread. :)

EDIT: Might I ask something?

In your post you said that 0x0801D415 goes on to check the obedience byte? What I'd really like to do is have a code to change an individual Pokemon obedience byte. So presumably an obedient byte does exist then? While having the Mew type of disobedience would work, I'd prefer it to be more like the traded-overtrained disobedience, where the Pokemon falls asleep, and refused to attack. With the Mew disobedience, Mew simply doesn't do anything, I believe. Maybe if I do checkobedience and use 0x0801D415 as a breakpoint I could figure it out?

Oh, and I'm dumb, so I don't know how to insert the first code into the game properly. Do I copy the code to a specific offset once it's assembled? Or maybe there's a way to assemble it I don't know, since there's a command to tell it where to put it in the code itself. Right now, all I really know is the "thumb" command to create the hex script to be inserted ...

EDIT2: Never mind - got it to work. Had to copy the code 0x1d415. And as HackMew said in the post after this one, only Mew and Deoxys do the complete disobedience thing. I just tried it with Charizard and it worked perfectly.

The last thing I'd like to know is I can undo the setobedience command? See, I kind of want to make Charizard obedient for a bit, then make it disobedient again, then make it obedient once more later. Possible?
 
Last edited:

JPAN

pokemon rom researcher
104
Posts
15
Years
  • Seen Jul 2, 2016
The disobedience check is part of the BattleScript commands, namely command 0, that checks what the pokemon will do. The actual obedience check is at 0801D438, covering all types of disobedience. The code checks for the obedience flag first, then proceeds to check for badges and levels. I'll post here the relevant piece of code for this matter:
Spoiler:
0801D4D4 checks one last time if, by chance, the attack will go trough. If not it will proceed to 0x0801d518, where what will the pokemon actually do\say is calculated.
So, several modifications can be made here to change the level a pokemon will become disobedient and in what conditions will it become disobedient.
The location of the obedience flag is actually in the last part of the Ribbon data in the Misc block, the topmost flag (bit 31 of the Ribbon word), but it's only useful for the species listed on the disobedience byte. And as for why Mew\Deoxys only disobey, it's because the chance of attack is determined by a random number (from 0-ff) to be smaller than the max level (that in the byte case is 0).

Edit: If I understood correctly, the code needed here is one that, if a pokemon doesn't have the flag, the pokemon has some chances of attacking, instead of just laying around all the time. With that in mind, I made a code for the occasion
Spoiler:
The trick in that code is that the pokemon will act as if it was obedient every once in a while thanks to the random number stored at 0x03005000.
 
Last edited:

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
^ That's an interesting code, JPAN. I might have to try it out. I think it might be useful to have the disobedient Pokemon attack every once in a while. I'll add it to the main page, too.

Oh, and colcolstyles, I'm so pleased with routine you made that I added you to the credits of my hack. I just want you to know that it's appreciated. Thanks again! :)

The disobedience check is part of the BattleScript commands, namely command 0, that checks what the pokemon will do. The actual obedience check is at 0801D438, covering all types of disobedience. The code checks for the obedience flag first, then proceeds to check for badges and levels. I'll post here the relevant piece of code for this matter:
Spoiler:
0801D4D4 checks one last time if, by chance, the attack will go trough. If not it will proceed to 0x0801d518, where what will the pokemon actually do\say is calculated.
So, several modifications can be made here to change the level a pokemon will become disobedient and in what conditions will it become disobedient.
The location of the obedience flag is actually in the last part of the Ribbon data in the Misc block, the topmost flag (bit 31 of the Ribbon word), but it's only useful for the species listed on the disobedience byte. And as for why Mew\Deoxys only disobey, it's because the chance of attack is determined by a random number (from 0-ff) to be smaller than the max level (that in the byte case is 0).

Edit: If I understood correctly, the code needed here is one that, if a pokemon doesn't have the flag, the pokemon has some chances of attacking, instead of just laying around all the time. With that in mind, I made a code for the occasion
Spoiler:
The trick in that code is that the pokemon will act as if it was obedient every once in a while thanks to the random number stored at 0x03005000.

JPAN, I tried to assemble this code I got some error messages: invalid offset, target not word aligned; invalid offset, value too big.

I couldn't get it to assemble.
 
Last edited:

NarutoActor

The rocks cry out to me
1,974
Posts
15
Years
Yup. Also, You can edit the asm routine to compare with a var. For an example if var 0x8000 is 0x1 then it will be a bulbasaur. That would make the asm routine more universal for other hackers. All you need to do is set the var before the asm routine, copy the var value into a registry, and compare.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
Yup. Also, You can edit the asm routine to compare with a var. For an example if var 0x8000 is 0x1 then it will be a bulbasaur. That would make the asm routine more universal for other hackers. All you need to do is set the var before the asm routine, copy the var value into a registry, and compare.

So could I create a routine that only has Charmeleon or Charizard obey or disobey if a certain variable (or flag) was set? That would be the best thing, imho. Then I could just set the variable (say, to 0x1) when I want them to obey, and unset it when I want them to disobey.

If that's possible, any chance you can enlighten me on to how that routine might be written?

(And I still can't get JPAN's routine to assemble. :()
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
Yup. Also, You can edit the asm routine to compare with a var. For an example if var 0x8000 is 0x1 then it will be a bulbasaur. That would make the asm routine more universal for other hackers. All you need to do is set the var before the asm routine, copy the var value into a registry, and compare.

So I spent a good part of my day trying to get this to work with this code. I've tried various things, but here's what I tried recently:

Code:
.text
.align 2
.thumb
.thumb_func
.global obedience

main:
	cmp r0, #0x97
	beq disobey
	cmp r0, #0x05
	beq disobey
	cmp r0, #0x06
	beq disobey

	mov r0, #0x01
	ldr r1, .RESUME
	bx r1
	
disobey:
	[b]ldr r1, .VAR
	cmp r1, #0x00
	beq disobey2[/b]

	mov r0, #0x01
	ldr r1, .RESUME
	bx r1

disobey2:
	ldr r1, .DISOBEY
	bx r1

resume:
	ldr r1, .RESUME
	bx r1
	
branchlink:
	bx r3

.align 2
.RESUME:
	.word	0x0801D42B
.DISOBEY:
	.word	0x0801D415
[b].VAR:
	.word 0x020370d2
[/b]

I bolded what I was attempting to do, which is to set a variable to a register, compare it to a number (in this case, 0) and if it's set to 0, have the Poké disobey; if not, have it obey.

I want to use variable 6187, just because I haven't used that one yet, but I'm just trying to experiment with 0x800d to see if I can get it to work. So far with my attempts, Charizard has either obeyed the entire time, whether 0x800d was set to 0x0 or 0x1, or has disobeyed in either event.

Any input would be appreciated. :)
 

colcolstyles

Yours truly
1,588
Posts
15
Years
You need a 'ldrh r1, [r1]' instruction after 'ldr r1, .VAR'.

Also, you can get rid of the "branchlink" section. That must have been left in from a previous project. It's unnecessary here.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
You need a 'ldrh r1, [r1]' instruction after 'ldr r1, .VAR'.

Also, you can get rid of the "branchlink" section. That must have been left in from a previous project. It's unnecessary here.

It worked! Thanks! :)

Now I'm just trying to find the right register for variable 0x6200. I tried debugging with VBA-SLD-H, but when I try to use the breakpoint command for the script I'm testing, it kind of freezes, and I haven't had any luck comparing registers when I hit F11 right after I activate the script and after/before I activate a different script. At least none of the ones I have tried have worked.

Anybody have any advice?
 

colcolstyles

Yours truly
1,588
Posts
15
Years
I'm not really sure what you're asking but if you want to retrieve the value of a non-0x8000 variable, you should call the THUMB routine at '0x0806E454' and pass the variable number as a parameter through r0.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
I'm not really sure what you're asking but if you want to retrieve the value of a non-0x8000 variable, you should call the THUMB routine at '0x0806E454' and pass the variable number as a parameter through r0.

Unfortunately, I have no idea how to do that. :\

I'll keep searching the forums/google to see if I can scrounge up something. None of the tutorials or topics I've found have made it very clear to me.
 

TheDarkShark

Metal Headed Hacker
56
Posts
13
Years
My ASM isn't very good, but I think the code would be something like this:

ldrh r0, <whatever variable you want to use>
bal 0x0806E454

EDIT: Here's the full code. I'm not shure if this will work, but here it is (changes in bold) :
.text
.align 2
.thumb
.thumb_func
.global obedience

main:
cmp r0, #0x97
beq disobey
cmp r0, #0x05
beq disobey
cmp r0, #0x06
beq disobey

mov r0, #0x01
ldr r1, .RESUME
bx r1

disobey:
ldrh r0, 0x6187 @The number of the variable is stored
bal 0x0806E454 @The Routine is called
cmp r0, #0x00 @Maybe, you have to compare another Register, as I don't know, where the value of the variable is stored
beq disobey2[/B]

mov r0, #0x01
ldr r1, .RESUME
bx r1

disobey2:
ldr r1, .DISOBEY
bx r1

resume:
ldr r1, .RESUME
bx r1

branchlink:
bx r3

.align 2
.RESUME:
.word 0x0801D42B
.DISOBEY:
.word 0x0801D415
 
Last edited:

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
My ASM isn't very good, but I think the code would be something like this:

ldrh r0, <whatever variable you want to use>
bal 0x0806E454

.........

Thanks for responding. It didn't work, but it got me trying some different things. Taking word for word what colcol instructed, I tried this:

Code:
.text
.align 2
.thumb
.thumb_func
.global obedience

main:
	cmp r0, #0x97
	beq disobey
	cmp r0, #0x05
	beq disobey
	cmp r0, #0x06
	beq disobey

	mov r0, #0x01
	ldr r1, .RESUME
	bx r1
	
disobey:
[b]	bl =0x0806E454
	ldr r0, =0x00006200
	ldrh r0, [r0][/b]
	cmp r0, #0x00
	beq disobey2

	mov r0, #0x01
	ldr r1, .RESUME
	bx r1

disobey2:
	ldr r1, .DISOBEY
	bx r1

resume:
	ldr r1, .RESUME
	bx r1

.align 2
.RESUME:
	.word	0x0801D42B
.DISOBEY:
	.word	0x0801D415

It doesn't work, though, so obviously I'm doing something wrong. I was trying to use this tut - http://pkmnhackersonline.com/zodiacdagreat/ASM/Lesson3.htm - as reference.

It doesn't crash/freeze the game like some of my attempts (like using labels for the variable/routine), but the Pokemon obeys no matter what the variable is set to.

Maybe someone could help me figure out my mistakes?
 

Jambo51

Glory To Arstotzka
736
Posts
14
Years
  • Seen Jan 28, 2018
...Maybe someone could help me figure out my mistakes?

The Line of code I left in bold is the problem here. The bl thumb command has a VERY short range (0xFFFF bytes I think), so instead of trying to directly link to it, try this instead. Unless you are inserting this code within that range. First of all, what you're doing here, because the code is written the wrong way around, is running the variable decrypting routine, then overwriting the result with "garbage".

Try this instead. Essentially the same, but should work better:

Code:
.text
.align 2
.thumb
.thumb_func
.global obedience
 
main:
    cmp r0, #0x97
    beq disobey
    cmp r0, #0x05
    beq disobey
    cmp r0, #0x06
    beq disobey
 
    mov r0, #0x01
    ldr r1, .RESUME
    bx r1
 
disobey:
    ldr r0, =0x00006200
    push {lr}
[B]  bl vardecrypt[/B]
    pop {r1}
    mov lr, r1
    ldrh r0, [r0]
    cmp r0, #0x00
    beq disobey2
 
    mov r0, #0x01
    ldr r1, .RESUME
    bx r1
 
disobey2:
    ldr r1, .DISOBEY
    bx r1
 
resume:
    ldr r1, .RESUME
    bx r1
 
vardecrypt:
    ldr r1, .VARDEC
    bx r1
 
.align 2
.RESUME:
    .word    0x0801D42B
.DISOBEY:
    .word    0x0801D415
.VARDEC:
    .word    0x0806E455

For the record, you should ALWAYS precede a bl command with a push {lr} command and follow it with a combo of pop {whatever}, mov lr, whatever; as you don't know if the calling routine needs the value held in lr for the rest of the routine. Better safe than sorry!

Incidentally, I'd assume that this is the same routine which runs the checks on Mew and Deoxys for disobedience? If so, could we rewrite it to exclude those rather frustrating checks?
 
Last edited:

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
The Line of code I left in bold is the problem here. The bl thumb command has a VERY short range (0xFFFF bytes I think), so instead of trying to directly link to it, try this instead. Unless you are inserting this code within that range. First of all, what you're doing here, because the code is written the wrong way around, is running the variable decrypting routine, then overwriting the result with "garbage".

Try this instead. Essentially the same, but should work better:

Code:
.text
.align 2
.thumb
.thumb_func
.global obedience
 
main:
    cmp r0, #0x97
    beq disobey
    cmp r0, #0x05
    beq disobey
    cmp r0, #0x06
    beq disobey
 
    mov r0, #0x01
    ldr r1, .RESUME
    bx r1
 
disobey:
    ldr r0, =0x00006200
    push {lr}
[B]  bl vardecrypt[/B]
    pop {r1}
    mov lr, r1
    ldrh r0, [r0]
    cmp r0, #0x00
    beq disobey2
 
    mov r0, #0x01
    ldr r1, .RESUME
    bx r1
 
disobey2:
    ldr r1, .DISOBEY
    bx r1
 
resume:
    ldr r1, .RESUME
    bx r1
 
vardecrypt:
    ldr r1, .VARDEC
    bx r1
 
.align 2
.RESUME:
    .word    0x0801D42B
.DISOBEY:
    .word    0x0801D415
.VARDEC:
    .word    0x0806E455

For the record, you should ALWAYS precede a bl command with a push {lr} command and follow it with a combo of pop {whatever}, mov lr, whatever; as you don't know if the calling routine needs the value held in lr for the rest of the routine. Better safe than sorry!

Thanks for the response, but it's still not working for me. :(
Charizard obeys whether the variable is set to 0x0 or 0x1 ...

Incidentally, I'd assume that this is the same routine which runs the checks on Mew and Deoxys for disobedience? If so, could we rewrite it to exclude those rather frustrating checks?

That's correct, it's the same routine. I would guess that you could just alter the routine at 0x0801D404, which I think was the original location of the routine to check for disobedience? I would guess you could just write a new routine that doesn't really do anything and insert it there?

I'm sure there's a routine before this that goes to the routine at 0x0801D404 if an attack is selected, though, and it would be best to edit that routine to not have it go to the routine at 0x0801D404 at all, but I don't know what the offset of that one would be ...
 

Jambo51

Glory To Arstotzka
736
Posts
14
Years
  • Seen Jan 28, 2018
Thanks for the response, but it's still not working for me. :(
Charizard obeys whether the variable is set to 0x0 or 0x1 ...



That's correct, it's the same routine. I would guess that you could just alter the routine at 0x0801D404, which I think was the original location of the routine to check for disobedience? I would guess you could just write a new routine that doesn't really do anything and insert it there?

I'm sure there's a routine before this that goes to the routine at 0x0801D404 if an attack is selected, though, and it would be best to edit that routine to not have it go to the routine at 0x0801D404 at all, but I don't know what the offset of that one would be ...

This might sound a bit iffy, but let me insert this routine and i'll see if I can find why it isn't working for you. If you say yes, you'll need to tell me the insertion location so I can do it. Also, 2 seconds after posting this, I found and removed the Mew and Deoxys checks. Hooray! Now we can all catch and actually use Mew. Simply replace the cmp r1, #0x97 line with lsl r0, r0, #0x0 (97 29 with 00 00) and the check won't run.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
This might sound a bit iffy, but let me insert this routine and i'll see if I can find why it isn't working for you. If you say yes, you'll need to tell me the insertion location so I can do it. Also, 2 seconds after posting this, I found and removed the Mew and Deoxys checks. Hooray! Now we can all catch and actually use Mew. Simply replace the cmp r1, #0x97 line with lsl r0, r0, #0x0 (97 29 with 00 00) and the check won't run.

Sure, go ahead. I've been placing the routine at 0x859000.

EDIT

Actually, now I realize that it does work. Thanks!! :D

For some reason variable 0x6200 wasn't already set to 0, even though I hadn't used it in my game yet - I was assuming that it was. :embarrass

I switched it to 0x6199 and it works perfectly. Thanks again, Jambo51! I really appreciate it. :)

Also, I put the code in the first post, and I'll add you and others that helped on this code to the credits for my hack. :)
 
Last edited:
Back
Top