• 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

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
For a while I was hoping to figure out a way to make a Pokemon disobedient, a sort of reverse of the setobedience command. I tried experimenting with Mew to see if there was anything in his code that would make him disobedient, but couldn't find anything, and I'm looking for more of the trade disobedience (occasionally sleeping, using other attacks, etc.).

Can anyone tell me if there was a way to create a custom ASM routine to set a specific Pokemon in your party as disobedient? Could you find the setobedience command and just change a few things, and create your own routine for setting a Pokemon to disobedient no matter what its level and what badges you've obtained? Any insight would be appreciated. I know I don't understand much about ASM, but I'm willing to do whatever possible to get this in, and I'm hoping it won't be too difficult, considering there's a command already in the game that does almost the same thing, but the opposite.

And now a solution to this problem. This code was made by colcolstyles, all credit goes to him:

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

^ Of course, you need to remove anything that says @ and whatever follows that - that's just explanation. With this you can make and Pokemon you want to be disobedient. It's really quite nifty.


Here's another code you can apply. This one was designed by JPAN, all credit to him. This is a code causes certain Pokemon to be disobedient, but instead of being completely disobedient, they are also occasionally obedient. It actually gives you some incentive to train a disobedient Pokemon, which can add to the depth of the game.

Code:
.align 2
.thumb
/*to use this code, place 00 49 08 47 at 0x0801d3f4, and the reversed pointer to  where
you put this code at 0x0801d3f8*/
    cmp r0, #0x5
    beq disobey_or_not
    cmp r0, #0x6 
    beq disobey_or_not    /*add more checks here for other pokemon*/
    ldr r1, mew_check
    bx r1
mew_check:   .word 0x0801D403
disobey_or_not: ldr r1, random_addr 
    ldrb r1, [r1]
    mov r0, #0xb4 /*change here the "perform attack" chance. percentage  is r0 divided by 256 times 100 */
    cmp r1, r0 /*aprox 70% chance of not performing an attack*/
    bgt is_obedient
    ldr r0, disobedient_ret_addr
    bx r0
is_obedient:   mov r0, #0x1
    pop {r4-r7,pc}
.hword 0x0000    
random_addr: .word 0x03005000
disobedient_ret_addr: .word 0x0801d415

And now here's a code that allows you to choose when a Pokemon is and isn't obedient. With this code, you can set a Pokemon's obedience to a variable, and have it only obey when that variable is set. Pretty cool, right? :cool:

All credit to this one goest to Jambo51:

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 @the variable you want to use
    push {lr}
    bl vardecrypt
    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

Lastly, a code to make a Pokemon only sometimes disobey unless a certain variable is set:

Special thanks to thank colcolstyles, Jambo51, and JPAN for working on this for me! Thanks! :)

So here's the routine:

First place 00 49 08 47 at 0x0801D3F4, and the reversed pointer to the code below at 0x0801D3F8 (per JPAN's routine).

Code:
.text
.align 2
.thumb
.thumb_func
.global obedience
 
main:
    cmp r0, #0x97    [b]@Mew's number, if you want it to disobey still[/b]
    beq disobey
    cmp r0, #0x05    [b]@Pokemon you want to disobey only sometimes [/b]
    beq disobey        [b](Charmeleon)[/b]
    cmp r0, #0x06    [b]@Pokemon you want to disobey only sometimes[/b]         
    beq disobey        [b](Charizard)[/b]
    ldr r1, mew_check
    bx r1

mew_check:
   .word 0x0801D403
 
disobey:
    ldr r0, =0x00006199    [b]@Variable you want to use[/b]
    push {lr}
    bl vardecrypt
    pop {r1}
    mov lr, r1
    ldrh r0, [r0]
    cmp r0, #0x00    [b]@the value of the variable you want to cause the[/b]
    beq disobey2       [b]Pokemon to sometimes disobey[/b]
     mov r0, #0x01
    ldr r1, .RESUME
    bx r1

disobey2:
    ldr r1, random_addr 
    ldrb r1, [r1]
    mov r0, #0xcd    [b]the number, divided by 256, that will be the[/b]
    cmp r1, r0          [b]percentage of how often the Pokemon disobeys[/b]
    bgt is_obedient    [b](in this case, cd (205)/256 = 80% disobey)[/b]
    ldr r0, disobedient_ret_addr
    bx r0
 
resume:
    ldr r1, .RESUME
    bx r1
 
vardecrypt:
    ldr r1, .VARDEC
    bx r1

is_obedient:   mov r0, #0x1
    pop {r4-r7,pc}
.hword 0x0000

.align 2
.RESUME:
    .word    0x0801D42B
.DISOBEY:
    .word    0x0801D415
.VARDEC:
    .word    0x0806E455
random_addr:
	.word 0x03005000

disobedient_ret_addr:
	.word 0x0801d415
 
Last edited:

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
I can be bothered writing a routine... but... 0x02024284 contains Party Pokemon data. I'm 90% sure the Sanity byte controls the obedience...

http://bulbapedia.bulbagarden.net/wiki/Pokémon_data_structure_in_Generation_III

I'm not on a computer with anything on it right now, so I can't do anything...

Okay, thank you, that should be helpful. It might be time for me to learn some basics about ASM. I know I can't expect anybody to do the work for me. Again, thanks.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
Well, I know this isn't right, because it didn't work, and I'm still an ASM-newb, but my thinking was that you would load the "sanity byte" of, say, the first Pokemon in your party, and either subtract 1 or add 1 to it. I kind of figured the sanity byte would start at 0x0 or 0x1 and need to have a byte removed or added to make the Pokemon disobey. So I tried a very basic routine, going off of HackMew's Secret ID example in his tutorial:

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

main:
	push {r0, lr}
	ldr r0, .POKE_DATA
	ldr r0, [r0]
	ldrb r0, [r0, #0x13]
	sub r0, #0x1
	pop {r0, pc}


.align 2
.POKE_DATA:
	.word 0x02024284

And then I tried this:

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

main:
	push {r0-r1, lr}
	ldr r0, .POKE_DATA
	ldr r0, [r0]
	ldrb r0, [r0, #0x13]
	mov r1, #0x1
	strb r1, [r0]
	pop {r0-r1, pc}


.align 2
.POKE_DATA:
	.word 0x02024284

In an attempt to simply change the byte itself to 0x0 or 0x1, but that didn't work either.

I know it's not correct, but any advice on where to go from this, or if I should be going in a completely different direction. I might have to do something a lot more complicated that I'm not capable of yet ...
 

colcolstyles

Yours truly
1,588
Posts
15
Years
The data at '0x02024284' is not a pointer. Because of this, the "ldr r0, [r0]" on the third line of each routine is unnecessary. It was needed in the Secret ID case because the trainer's data is moved around in-game and so in order to find it, you needed to load the pointer at an address and then subsequently load the data at that second pointer. It's kind of confusing and difficult to explain but if you remove the line that I told you to, you should hopefully have a little more success.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
The data at '0x02024284' is not a pointer. Because of this, the "ldr r0, [r0]" on the third line of each routine is unnecessary. It was needed in the Secret ID case because the trainer's data is moved around in-game and so in order to find it, you needed to load the pointer at an address and then subsequently load the data at that second pointer. It's kind of confusing and difficult to explain but if you remove the line that I told you to, you should hopefully have a little more success.

I removed it and tried it again for both routines, but the Pokemon still seems to obey. Thanks for the help, though.

Pro tip: Before you start making a routine, you need to observe the data.

Do you mean like the debugging part of HackMew's tutorial?


EDIT: According to this:

http://bulbapedia.bulbagarden.net/wiki/User:Kyoufu_Kawa#Font_and_Sanity

The sanity byte has to do with whether the Pokemon is an egg or not.

The sanity byte determines if the individual is an egg. Zero and 2 are a regular monster, 1, 3-5 are Bad EGGs but can be changed back, 6 makes the game write "EGG" instead of the monster's nickname but doesn't actually make it an egg and 7 is the actual Bad EGG. When you break the checksum, the sanity byte is set to 7. This persists! Several actions in the game (see below) make it check for Bad EGGs and keep resetting the byte to 7, for example stepping into tall grass and opening the party screen. Good luck turning the Bad EGG back into a real monster. Note that only the first few bits matter so the pattern repeats after 7.

I did a test with a new routine and was able to determine that in my game, with Pikachu as my only Pokemon, Pikachu's sanity byte was 2 - which according to this makes it a regular monster.

So does this mean that the sanity byte doesn't control obedience?



EDIT 2: I was trying out the debugger thing and I thought of something. Since you can view what's going on with custom routines, if I had the offset for the setobedience routine that's in the game, could I theoretically view that and see what it's dealing with? If I could see that, then I could use the same things for my custom routine, right? So if that's the case, how could I go about figuring out what the offset for the setobedience command is?
 
Last edited:

Iacobus

sǝɯɐɾ
64
Posts
20
Years
As you said yourself, the fact that your Pokémon obeys you is related to it's level and the number of badges you have. So, one could say that, before you attack, the game does a little calculation which takes the highest 'badge-flag' and the Pokémon level into account.
What one should do is find the routine that checks if the Pokémon obeys or not and eventually add another check. For example: One could use an unused bit in the Pokémon data and use this as a flag.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
What one should do is find the routine that checks if the Pokémon obeys or not and eventually add another check. For example: One could use an unused bit in the Pokémon data and use this as a flag.

It's something I'm willing to do, but how? How would I find that original routine? Is it in the party Pokemon data? And if it's not the "Sanity Byte," what is it?
 

Iacobus

sǝɯɐɾ
64
Posts
20
Years
It's something I'm willing to do, but how? How would I find that original routine? Is it in the party Pokemon data? And if it's not the "Sanity Byte," what is it?
Well, I surely trust Kawa's research. Which means that the "Sanity Byte" means exactly this:
The sanity byte determines if the individual is an egg. Zero and 2 are a regular monster, 1, 3-5 are Bad EGGs but can be changed back, 6 makes the game write "EGG" instead of the monster's nickname but doesn't actually make it an egg and 7 is the actual Bad EGG. When you break the checksum, the sanity byte is set to 7. This persists! Several actions in the game (see below) make it check for Bad EGGs and keep resetting the byte to 7, for example stepping into tall grass and opening the party screen. Good luck turning the Bad EGG back into a real monster. Note that only the first few bits matter so the pattern repeats after 7.
(Sure there is the possibility he made a mistake.)

Anyway, how I would try to find this routine you need to expand is, well..
The game displays a message when the Pokémon isn't willing to obey you, right?
I would try to find out when that message is loaded and like so work my way back and find the actual routine that does the 'check'.
Also, if indeed the "Sanity Byte's" pattern repeats after 7, you could easily use a bit from that byte for the new 'flag'. At least I think you could.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
Well, I surely trust Kawa's research. Which means that the "Sanity Byte" means exactly this:
(Sure there is the possibility he made a mistake.)

Anyway, how I would try to find this routine you need to expand is, well..
The game displays a message when the Pokémon isn't willing to obey you, right?
I would try to find out when that message is loaded and like so work my way back and find the actual routine that does the 'check'.
Also, if indeed the "Sanity Byte's" pattern repeats after 7, you could easily use a bit from that byte for the new 'flag'. At least I think you could.

Okay, that's a start. I'll see what I can do ...

EDIT: The following messages should be located at these offsets:

(Pokemon) ignored orders while asleep! - 0x3FD0F1
- The pointer to this message is at 0x3FE358

(Pokemon) ignored orders! - 0x3FD111
- The pointer to this message is at 0x3FE35C

(Pokemon) pretended not to notice! - 0x3FD16A
- The pointer to this message is at 0x3FE370

That's the end of the pointers. Not sure what I could do from here.
 
Last edited:

colcolstyles

Yours truly
1,588
Posts
15
Years
Oh wow. When I looked at your routines earlier, I just skimmed over them real briefly and then pointed out the first error that I saw. There are a bunch more too.

First of all, the first routine does absolutely nothing. It loads a byte from some address, subtracts one from it... and then restores the previous condition without changing anything. As for the second routine, if all you're trying to do is store '0x01' at '0x02024284', then all you need is the following (excluding push and pop):
Code:
ldr r0, .POKE_DATA
mov r1, #0x01
strb r1, [r0, #0x00]

Before, you weren't actually writing to the POKE_DATA. That's why you didn't notice any change.

Also, it was my understanding that a Pokémon was deemed an egg by setting one of the top two bits in the IV word. I could be mistaken, though.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
Oh wow. When I looked at your routines earlier, I just skimmed over them real briefly and then pointed out the first error that I saw. There are a bunch more too.

First of all, the first routine does absolutely nothing. It loads a byte from some address, subtracts one from it... and then restores the previous condition without changing anything. As for the second routine, if all you're trying to do is store '0x01' at '0x02024284', then all you need is the following (excluding push and pop):
Code:
ldr r0, .POKE_DATA
mov r1, #0x01
strb r1, [r0, #0x00]

Before, you weren't actually writing to the POKE_DATA. That's why you didn't notice any change.

Also, it was my understanding that a Pokémon was deemed an egg by setting one of the top two bits in the IV word. I could be mistaken, though.

Well, yeah, I did mention that I'm an ASM-newb, right? :embarrass

But no, I'm not storing 0x0 at that offset. That's only the beginning of the offset for the first Pokemon's data. I need to store it where the sanity byte is, which is (if I'm understanding correctly) 19 bytes (13 in hex) after that, which is why I had "ldrb r0, [r0, #0x13]" there.
 
1
Posts
13
Years
  • Seen Oct 27, 2010
I think you could find out more if you use the vba-sdl-h to set breakpoints, when the disobedience thing triggers.
 

colcolstyles

Yours truly
1,588
Posts
15
Years
One step ahead of you. :)

Well I've been slowly making my way through the assembly code for the 'setobedience' command and though I haven't figured it out yet, I've been following some values through the system and it looks like the game is trying to access the "Data" substructure of my Squirtle's data. I'll update this post once I figure out which block gets accessed and, from there, what piece of data exactly gets modified.
 

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
One step ahead of you. :)

Well I've been slowly making my way through the assembly code for the 'setobedience' command and though I haven't figured it out yet, I've been following some values through the system and it looks like the game is trying to access the "Data" substructure of my Squirtle's data. I'll update this post once I figure out which block gets accessed and, from there, what piece of data exactly gets modified.

Oh, wow! Thank you so much! I really do appreciate the help. :)
 
Back
Top