PDA

View Full Version : Development: Take/Return Pokemon

thethethethe
February 3rd, 2009, 11:42 AM
ASM Take and Return Pokémon
NOTE:This is currently only for Fire Red. I’ll add support for other ROM’s when I find time.

To do this all you’ll need is a little knowledge about command #23 (callasm) and the ability to use a hex editor very basically. You don’t need to be an expert, because I’ll even give you an example script.

Okay here’s the code for those who know what to do with it. Its also is partly commented for those you have trouble understanding. Don’t ask what to do with this if you don’t already know. For those who don’t know what to do with this, I’ll give the other way to get the ASM code into the ROM. The code may not be the best but it works.
Take Pokemon
.text
.align 2
.thumb
.thumb_func
.global main

main:
push {r0-r4, lr}
ldr r0, .var1 @var for Pokemon to take
ldrh r0, [r0] @store Pokemon's number in party
ldr r1, .var2 @+2, var for total Pokemon(use command #43)
ldrh r1, [r1] @store max Pokemon in current party

cmp r0, r1 @If number to store is greater than number in party
bgt error

b taken

error:
mov r0, #1
ldr r1, .var3
strh r0, [r1] @+4, For error it will return 1 to var.
pop {r0-r4, pc}

taken:
ldr r3, .pokedata @loads Pokemon party data to reg
cmp r0, #0 @if Pokemon to take is first, jump further ahead
beq take

mov r2, #0 @loop counter

multiply:
add r3, #100 @For each Pokemon in party has 100 bytes
add r2, #1 @r2+=1
cmp r2, r0 @if counter equals Pokemon to copy
bne multiply
take:
mov r0, r3
ldr r1, =0x02010000 @Destination to place data until Pokemon is given back.
mov r2, #25 @or 50, I can't remember off the top of my head.
swi 0xC @Either 0xC or oxB I can't remember which one is 4 byte write and which is two byte write.

mov r0, #0 @loop counter
ldr r1, =0x00000000 @to overwrite old data with nothing.

remove:
str r1, [r3] @pverwrite Pokemon data with 0
add r3, #4 @add 4 to location for next spot
add r0, #1 @r0+=1 for loop
cmp r0, #25 @If all data is overwritten
blt remove

fix:
@to fix up party if needed
mov r1, #100
sub r2, r3, r1 @original calculated party spot
ldr r1, .pokedata
sub r1, r2, r1 @difference between data and Pokemon taken
ldr r4, =500
cmp r1, r4 @If last Pokemon
beq finish
cmp r1, #0
beq finish

mov r0, r1
mov r1, #4 @calculate length (Maybe two I need to check
swi 0x06 @divide interrupt result returned at r0

mov r1, r2 @r2 = Where to move party MOVE TO: r1
mov r2, r0 @r0 = Length MOVE TO: r2
mov r0, r3 @r3 = Rest of party MOVE TO: r0
swi 0xC

finish:
mov r0, #0 @If work correctly, returns 0 to var number 3.
ldr r1, .var3
strh r0, [r1]
pop {r0-r4, pc}

.align 2
.pokedata:
.word 0x02024284
.var1:
.word 0x020370b8
.var2:
.word 0x020370ba
.var3:
.word 0x020370b8

Return Pokemon
.text
.align 2
.thumb
.thumb_func
.global main

main:
push {r0-r2, lr}
ldr r0, .var1
ldrh r0, [r0] @Load amount of Pokemon in party
cmp r0, #5
beq error

b given

error:
mov r0, #1
ldr r1, .var3
str r0, [r1]
pop {r0-r2, pc}

given:
ldr r1, .pokedata
cmp r0, #0

mov r2, #0

loop1:
cmp r2, r0
bne loop1

ldr r0, .space
mov r2, #25
swi 0xC

mov r2, #0
mov r1, #0

remove:
str r1, [r0]
cmp r2, #25
blt remove

finish:
mov r0, #0
ldr r1, .var3
strh r0, [r1]
pop {r0-r2, pc}

.align 2
.pokedata:
.word 0x02024284
.var1:
.word 0x020370B8
.var3:
.word 0x020370BC
.space:
.word 0x02010000

Here’s the ASM code for those who don’t know how to compile it. This isn’t an ASM tutorial so I won’t cover anything other than what’s needed to get this working.
Input this data into your ROM through a hex editor at an address of your choice. Write the address down, because you’ll need them for the script.
Take Pokemon
1FB5 1A48 0088 1A49 0988 8842 00DC 03E0
0120 1849 0880 1FBD 134B 0028 04D0 0022
6433 0132 8242 FBD1 181C 1349 1922 0CDF
0020 0021 1960 0433 0130 1928 FADB 6421
5A1A 0949 511A 0D4C A142 08D0 0029 06D0
081C 0421 06DF 111C 021C 181C 0CDF 0020
0449 0880 1FBD 0000 8442 0202 B870 0302
BA70 0302 B870 0302 00F0 0202 F401 0000

Then you’ll also need to input this code into your Hex editor as well.
Return Pokemon
07B5 1048 0088 0528 00D0 03E0 0120 0E49
0860 07BD 0A49 0028 04D0 0022 6431 0132
8242 FBD1 0948 1922 0CDF 0022 0021 0160
0430 0132 1928 FADB 0020 0349 0880 07BD
8442 0202 B870 0302 BC70 0302 00F0 0202

Now that you have the ASM part done. This part should be easy. All we need to do now is script it. Most people are most comfortable with XSE nowadays so I’ll put my example script to use the code in XSE.
But now we’re still not ready to code. We need to know some things about your ASM code.
The first code uses 3 variables 0x8000, 0x8001, and 0x8002. The second code uses only two variables 0x8000 and 0x8002.
In the first code, 0x8000 is used to store the number of the Pokemon in your party. For example, if it’s the first Pokemon, you would store zero, if it were the sixth Pokemon, you would store 5 into the variable.
0x8001 is used to store the total amount of Pokemon in your party. This can be obtained by just using countpokemon and then a copyvar from 0x800D to 0x8001.
0x8002 is used as an error check. For example if the Pokemon’s number in your party that you wanted to take, was less than the total Pokemon in your party designated by the above two variables. This is just originating from a normal C/C++ and the fact that a returned 0 means no problems, and a return of anything else means an error occurred.

In the second script, 0x8000 is used for the total Pokemon you have.
0x8002 is used in the same way as in the first code and is an error check.

So here’s an example script using the ASM code. I’ll comment any important areas out so you should know what’s going on even if you don’t script very well.
#alias @ \$

#dynamic 0x800000

#org \$start 'Code to take a Pokemon
lock
faceplayer
checkflag 0x200
if 0x1 goto \$return
setvar 0x8000 0x0 'Pokemon to take is first in Party.
countpokemon 'Total Pokemon in party.
copyvar 0x8001 0x800D
callasm 0x800001 'callasm 0x(address + 1) Of course then I inserted this code at 0x800001
compare 0x800D 0x1 'If error occurred.
if 0x1 goto \$error
msgbox \$1 0x6
setflag 0x200
release
end

#org \$error
msgbox \$2 0x6
release
end

#org \$return
countpokemon
compare 0x800D 0x5
if 0x1 goto \$error 'If there’s no room for the return.
copyvar 0x8000 0x800D
callasm 0x800101 'Callasm 0x(address +1) Mine was 0x800100
compare 0x8002 0x1 'Error Check
if 0x1 goto \$error
msgbox \$3 0x6
clearflag 0x200
release
end

#org \$1
= Pokemon taken.

#org \$2
= Error occurred.

#org \$3
= Pokemon returned

Note this will only allow you to take one Pokemon at a time. If you try to take a second it will overwrite the first Pokemon and you’ll lose the first Pokemon.
Please let me know if there are any bugs. I haven’t extensively tested it out, I only checked whether it worked with the first Pokemon being taken and returned or not. The quicker people let me know, the quicker I can fix it.

Don't take without Permission.
Tutorial and code by thethethethe.

Gamer2020
February 3rd, 2009, 5:14 PM
This looks good. I will try it when i get a chance. I wish there was something like this for ruby. lol

Yay! first post!

Vrai
February 3rd, 2009, 6:03 PM
This is ftw, thethethethe. Nice job. ^^

You really should write an ASM tutorial.

ZodiacDaGreat
February 3rd, 2009, 9:32 PM
I see, so its posted :) Great job

Edit: I'll do another one where both routines are combined and works with special 0x9F.

Cy-Chan
February 3rd, 2009, 9:46 PM
Ahah, very nice. Very nice indeed.

Hm, DevKitPro?

thethethethe
February 4th, 2009, 2:08 AM
Sorry, I made a little mistake. I need to fix it up. At the moment this will only be good for taking the first Pokemon when only having one Pokemon. I know where the mistake is. I'll fix it up and test it properly by about tomorrow or possibly the day after.

Ahah, very nice. Very nice indeed.

Hm, DevKitPro?
If you'd like. devkitARM, HAM, goldroad, MIDI2GBA, it's all good.

Juan
February 4th, 2009, 4:18 AM
mov r2, #25 @or 50, I can't remember off the top of my head.
It is even 50, or 0x32(I used with 0x32 and worked)

I liked their routines had not seen before making mine.
You used three variables, but I think not need the number of Pokémon on the team, because a loop from 0 to 5 did not consume much space and not much memory.
I like to check the error occurred, and the "debugger" used with the variable 0x8002.
Never would have thought of something. :D
One more thing, I think you can simplify these routines, especially the label "fix" that though complex, can (I think) to be optimized.
Thank you for sharing your knowledge with us, are with examples such as I learn new things. ^^

PT_BR:
Gostei das suas rotinas, não tinha visto antes de fazer a minha.
Você usou três variáveis, mas acho que não precisaria o número de pokémon na equipe, pois um loop de 0 à 5 não consome tanto espaço, e nem tanta memória.
Gostei da parte de verificar se deu erro, e o "debugger" usado com a variável 0x8002.
Nunca teria pensado em algo parecido :D
Mais uma coisa, acho que dá para simplificar essas rotinas, principalmente o label "fix", que apesar de complexo, pode(eu acho) ser otimizado.
Obrigado por compartilhar seu conhecimento conosco, são com exemplos desse tipo que eu aprendo coisas novas. ^^

thethethethe
February 4th, 2009, 11:55 AM
It is even 50, or 0x32(I used with 0x32 and worked)

I liked their routines had not seen before making mine.
You used three variables, but I think not need the number of Pokémon on the team, because a loop from 0 to 5 did not consume much space and not much memory.
I like to check the error occurred, and the "debugger" used with the variable 0x8002.
Never would have thought of something. :D
One more thing, I think you can simplify these routines, especially the label "fix" that though complex, can (I think) to be optimized.
Thank you for sharing your knowledge with us, are with examples such as I learn new things. ^^

No. It's 25 for what I used. I checked that. That comment was there for me so I could check it later. You used swi 0xB, which the r2 amount is half of the full length because it uses two byte writes or half-word writes. 0xC uses double that and the r2 holds a quarter of the full amount because it uses word long writes.

You're right, the code still needs to be fixed up a bit.

Juan
February 4th, 2009, 1:23 PM
No. It's 25 for what I used. I checked that. That comment was there for me so I could check it later. You used swi 0xB, which the r2 amount is half of the full length because it uses two byte writes or half-word writes. 0xC uses double that and the r2 holds a quarter of the full amount because it uses word long writes.

You're right, the code still needs to be fixed up a bit.

now that I saw you used the 0xC and I 0xB ^^

EDIT:
.pokedata:
.word 0x02024284
.var1:
.word 0x020370b8
.var2:
.word 0x020370ba
.var3:
.word 0x020370b8

0x8002(var2) offset is \$020370BC, not \$020370b8 ^^

\$020370B8 0x8000
\$020370BA 0x8001
\$020370BC 0x8002
\$020370BE 0x8003
\$020370C0 0x8004
\$020370C2 0x8005
\$020370C4 0x8006
\$020370C6 0x8007
\$020370C8 0x8008
\$020370CA 0x8009
\$020370CC 0x800A
\$020370CE 0x800B
\$020370D0 0x800D (LASTRESULT)
\$020370D4 0x800C (PLAYERFACING)

0m3GA ARS3NAL
February 5th, 2009, 8:37 PM
This is great! But I gotta say, the ASM is a bit confusing, not many people will understand this at all...
Also, how do you compile all of this information? I certainly dont know how, and how do you know these functions and such, where can I learn all of this, because I really want to get into ASM!
A tutorial would be a great idea though, even if you were to release it in stages, like HackMew's XSE guide. (It does not have to be a .chm file though, lol. )
This is a breakthrough though, +Rep for you!

Juan
February 6th, 2009, 4:27 AM
If you'd like. devkitARM, HAM, goldroad, MIDI2GBA, it's all good.
I could not use with goldroad.
I modified his routine, and changed some things.
Take:

@define pokedata = 0x02024284
@define var1 = 0x020370B8
@define var2 = 0x020370BA
@define var3 = 0x020370BC
@define RAM_offset = 0x02123990
@thumb
thumb_code

main:
push {pc}
ldr r3, var1
ldrh r3, [r3]
ldr r4, var2
ldrh r4, [r4]

;the following two lines one can be removed
;as the script now checks which Pokémon was chosen
;
;cmp r3, r4
;bgt error
;

b taken

;error:
; mov r0, #1
; ldr r1, var3
; strh r0, [r1]
; pop {pc}

taken:
ldr r0, pokedata
mov r5, #0x64
mul r5, r3 ;multiplies '100' by the index of Pokémon chosen
;if r0 = 0, then r4 will be 0

add r0, r0, r5 ;calculates the offset of the selected Pokémon
ldr r1, RAM_offset
mov r2, 0x19 ;25
swi 0xC

sub r4, #0x1
ldr r6,= 0x00
mov r5, #0x0
cmp r3, r4
beq remove
ldr r1, pokedata
b fix

remove:
strb r6, [r0]
cmp r5, #0x64
blt remove

b finish

fix:
ldr r7, pokedata
mov r5, #0x64
mul r5, r3
add r1, r7, r5
add r3, r3, #0x01
mov r5, #0x64
mul r5, r3
add r0, r7, r5
swi 0xC
cmp r3, r4
blt fix
mov r5, #0x0
b remove

finish:
mov r0, #0x00
ldr r1, var3
strh r0, [r1]
pop {pc}

Return:

@define pokedata = 0x02024284
@define var1 = 0x020370B8
@define var3 = 0x020370BC
@define RAM_offset = 0x02123990;0x02010000
@thumb
thumb_code

main:
push {lr}
ldr r5, var1
ldrb r5, [r5]
cmp r5, #0x05
beq error
mov r4, #0x64
mul r4, r5
ldr, r0, RAM_offset
ldr, r1, pokedata
ldr r2, #0x19
swi 0xC
ldr r1,= 0x00000000
mov r4, #0x00

remove:
str r1, [r0]
cmp r2, #0x19
blt remove

finish:
mov r0, #0x00
ldr r1, var3
strh r0, [r1]
pop {pc}

error:
mov r0, #0x01
ldr r1, var3
strh r0, [r1]
pop {pc}

Take:
00B5 C046 154B 1B88 154C 2488 FFE7 C046
1448 6425 5D43 4019 1349 1922 0CDF 013C
124E 0025 A342 01D0 0E49 05E0 0670 0130
0135 642D FADB 0CE0 0A4F 6425 5D43 7919
5B1C 6425 5D43 7819 0CDF A342 F4DB 0025
ECE7 0020 0649 0880 00BD 0000 B870 0302
BA70 0302 8442 0202 9039 1202 0000 0000
BC70 0302
Where:
84420202 = pokedata
B8700302 = var1(0x8000)
BA700302 = var2(0x8001)
BC700302 = var3(0x8002)
9039 1202 = RAM_offset

Return:
00B5 C046 0D4D 2D78 052D 12D0 6424 6C43
FBFF FAFF 211C F9FF 0CDF C046 0849 0024
0160 0430 0134 192A FADB 0020 0549 0880
00BD 0120 0349 0880 00BD 0000 B870 0302
0000 0000 BC70 0302
Where:
84420202 = pokedata
B8700302 = var1(0x8000)
BC700302 = var3(0x8002)
9039 1202 = RAM_offset

Script:
#alias @ \$

#dynamic 0x800000

#org \$start 'Code to take a Pokemon
lock
faceplayer
checkflag 0x200
if 0x1 goto \$return
special2 LASTRESULT 0x84 'check how many Pokémon have on the team (no eggs)
copyvar 0x8001 LASTRESULT
compare 0x8001 0x2
if 0x0 goto \$1poke 'if less than two, the script does not run
special 0xBC 'choose a pokemon
waitstate
subvar LASTRESULT 0x1
comparevars 0x8004 LASTRESULT
if 0x4 goto \$none 'if choose none pokemon, the script stop
copyvar 0x8000 0x8004
callasm 0x800001 'callasm 0x(address + 1) Of course then I inserted this code at 0x800001
compare 0x8002 0x1 'If error occurred.
if 0x1 goto \$error
msgbox \$1 0x6
setflag 0x200
release
end

#org \$error
msgbox \$2 0x6
release
end

#org \$return
countpokemon
compare 0x800D 0x5
if 0x1 goto \$error 'If there’s no room for the return.
copyvar 0x8000 0x800D
callasm 0x800101 'Callasm 0x(address +1) Mine was 0x800100
compare 0x8002 0x1 'Error Check
if 0x1 goto \$error
msgbox \$3 0x6
clearflag 0x200
release
end

#org \$1poke
msgbox \$4 0x6
release
end

#org \$none
msgbox \$5 0x6
release
end

#org \$1
= Pokemon taken.

#org \$2
= Error occurred.

#org \$3
= Pokemon returned

#org \$4
= You must have at least two\nPokémon!

#org \$5
= No Pokémon has been chosen!

If want to use other variables, or in other versions:
BPRE:
\$020370B8 0x8000
\$020370BA 0x8001
\$020370BC 0x8002
\$020370BE 0x8003
\$020370C0 0x8004
\$020370C2 0x8005
\$020370C4 0x8006
\$020370C6 0x8007
\$020370C8 0x8008
\$020370CA 0x8009
\$020370CC 0x800A
\$020370CE 0x800B
\$020370D0 0x800D (LASTRESULT)
\$020370D4 0x800C (PLAYERFACING)

AXVE:

\$0202E8C4 0x8000
\$0202E8C6 0x8001
\$0202E8C8 0x8002
\$0202E8CA 0x8003
\$0202E8CC 0x8004
\$0202E8CE 0x8005
\$0202E8D0 0x8006
\$0202E8D2 0x8007
\$0202E8D4 0x8008
\$0202E8D6 0x8009
\$0202E8D8 0x800A
\$0202E8DA 0x800B
\$0202E8DC 0x800D (LASTRESULT)
\$0202E8E0 0x800C (PLAYERFACING)
\$0203855E 0x800E

AXPE:

\$0202E8C4 0x8000
\$0202E8C6 0x8001
\$0202E8C8 0x8002
\$0202E8CA 0x8003
\$0202E8CC 0x8004
\$0202E8CE 0x8005
\$0202E8D0 0x8006
\$0202E8D2 0x8007
\$0202E8D4 0x8008
\$0202E8D6 0x8009
\$0202E8D8 0x800A
\$0202E8DA 0x800B
\$0202E8DC 0x800D (LASTRESULT)
\$0202E8E0 0x800C (PLAYERFACING)
\$0203855E 0x800E

PBEE:
\$020375D8 0x8000
\$020375DA 0x8001
\$020375DC 0x8002
\$020375DE 0x8003
\$020375E0 0x8004
\$020375E2 0x8005
\$020375E4 0x8006
\$020375E6 0x8007
\$020375E8 0x8008
\$020375EA 0x8009
\$020375EC 0x800A
\$020375EE 0x800B
\$020375F0 0x800D (LASTRESULT)
\$020375F4 0x800C (PLAYERFACING)
\$0203CE7C 0x800E

Also, how do you compile all of this information?
Download the program "goldroad", save the routine in a text file.
Drag the file from the routine to the Goldroad, and a file .GBA will be generated, which is routinely compilled.

0m3GA ARS3NAL
February 6th, 2009, 11:32 AM
Download the program "goldroad", save the routine in a text file.
Drag the file from the routine to the Goldroad, and a file .GBA will be generated, which is routinely compilled.

Ok, and when it is compiled, the .gba will be just my routine in hex codes?

Juan
February 6th, 2009, 11:55 AM
Yes, the .GBA is the ASM routine in hexadecimal.

0m3GA ARS3NAL
February 6th, 2009, 12:08 PM
Yes, the .GBA is the ASM routine in hexadecimal.

Ok, now, where can I learn all of the definitions and stuff, knowledge basically, I would need in order to ASM hack?
To put it simple, are tehre any reference sheets and/or tutorials I can get ahold of?

ZodiacDaGreat
February 6th, 2009, 12:12 PM
Relax pal, You'll see a set soon ;) Anyway, I must insist that to asm hack you'll need to know the GBA's hardware as well :p

0m3GA ARS3NAL
February 6th, 2009, 12:20 PM
Relax pal, You'll see a set soon ;) Anyway, I must insist that to asm hack you'll need to know the GBA's hardware as well :p

>_> I get this answer / response to me trying to learn ASM from alot of people. Quite frankly, I am tired of it, I am ready to at least TRY, all I ask is a bit of knowlege, and I am actually ecstatic to hear an ASM tutorial might be on it's way, it is about time! ^-^
In any case, I have gold road, and looked at the stuff shown in the little intro .GBA file that came with it, I have been looking at the ASM for it, and don't understand much, since I dont know definitions, or the functions of many of the things in the code.

But all of that is off topic.

All I can say it, that I am glad some people finally cracked give/take pokemon, congrats you guys!

Juan
February 6th, 2009, 12:53 PM
>_> I get this answer / response to me trying to learn ASM from alot of people. Quite frankly, I am tired of it, I am ready to at least TRY, all I ask is a bit of knowlege, and I am actually ecstatic to hear an ASM tutorial might be on it's way, it is about time! ^-^
In any case, I have gold road, and looked at the stuff shown in the little intro .GBA file that came with it, I have been looking at the ASM for it, and don't understand much, since I dont know definitions, or the functions of many of the things in the code.

But all of that is off topic.

All I can say it, that I am glad some people finally cracked give/take pokemon, congrats you guys!

see GBA Tek: http://nocash.emubase.de/gbatek.htm

0m3GA ARS3NAL
February 6th, 2009, 1:35 PM
see GBA Tek: http://nocash.emubase.de/gbatek.htm

I will when I get home, I am at school now and they blocked the site from me.
But thank you for the link, I have been looking around for one for a while now, I guess I just did not know what to search for...

ZodiacDaGreat
February 6th, 2009, 5:19 PM
Here, I just posted this (http://www.pkhacks.webhosting4free.info/?page_id=92). I hope its not too technical.

Vrai
February 6th, 2009, 6:22 PM
AWESOME.

Thanks very much, you two. Maybe you'll help the community by teaching us to do ASM.. ^_^

Probably not, but meh. Thanks again.

liuyanghejerry
February 8th, 2009, 9:06 PM
Really good work...I always admire ASM hackers...
But what if you choose is an egg? will this code crash?
By the way, from the return code , it's possible to give player a specific Pokemon,isn't it?

Juan
February 9th, 2009, 4:20 AM
Really good work...I always admire ASM hackers...
But what if you choose is an egg? will this code crash?
By the way, from the return code , it's possible to give player a specific Pokemon,isn't it?

The command 'special 0xBC' does not choose eggs.
And yes, it's possible. But you have to write every 100bytes correctly, according to the article of bulbapedia (http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_structure_in_the_GBA). Otherwise one will BadEgg.
It would be similar to the tutorial "How to create predefined pokemon (http://www.pokecommunity.com/showthread.php?t=110453)" made by Mastermind_X, but instead of saving the Pokémon in the box, it saves the team.

roywillow
February 9th, 2009, 5:54 AM
In the battle field of Emerald there is a similar function I think...It take all your pokemon and return them when you finish battle...How it works?