DoesntKnowHowToPlay
Tiny Umbrella with Lots and Lots of Good
- 265
- Posts
- 13
- Years
- Seen Feb 24, 2024
I see a lot of talk about how to make hacks "difficult". The typical solutions are to:
-give trainers teams full of legendaries
-make the level curve absurdly steep
-inflate the base stats of everything
-give the AI illegal moves and custom attacks with absurd BP
-make every dungeon a flash maze where you can't use flash
Because Ihate everyone who plays romhacks for fun am a nice person, I've decided to release a bit of code that gives us another option- letting trainer pokemon have custom EVs. Normally, trainer pokemon have 0 EVs in every stat outside of the RSE Battle Tower/Frontier.
First you will need to insert this ASM:
Fire Red:
Emerald:
The bulk of this code is at xF90000- that part doesn't have to go there, it can be moved to wherever you have free space. Just make sure you change Method_Addr to whatever you change the offset to + 1.
You will also need to find x1000 bytes of space, and change the .EV_Table variable in the method to point to it (I used xF00000). This is where the spreads will go. The method gives you 256 spreads to use- this is not full control, but it is more than you are likely to need (the Emerald Battle Frontier only uses around 36 IIRC). The EV Spread table format is:
- Nature
- 3 unused bytes
- HP EV
- Attack EV
- Defense EV
- Speed EV
- Special Attack EV
- Special Defense EV
- What pokeball the mon comes out in
- 4 more unused bytes (I may update the method later to do something with these)
To assign an EV spread to a trainer's pokemon, set the value that was formerly their IVs to which slot in the table you want that pokemon to use. If you are using A-Trainer, this value is erroneously marked as AI Value. Note that the method only works for trainers with custom movesets and items- if they use default movesets or items, it will only affect IVs. It will still work if you manually give the trainer the moves it would have by default or explicitly define their mons as being empty-handed though.
This hack now allows custom natures. The natures are enumerated like so:
x0 - Arbitrary
x1 - Lonely (+Atk, -Def)
x2 - Brave (+Atk, -Speed)
x3 - Adamant (+Atk, -SpAtk)
x4 - Naughty (+Atk, -SpDef)
x5 - Bold (+Def, -Atk)
x6 - Docile (Neutral)
x7 - Relaxed (+Def, -Speed)
x8 - Impish (+Def, -SpAtk)
x9 - Lax (+Def, -SpDef)
xA - Timid (+Speed, -Atk)
xB - Hasty (+Speed, -Def)
xC - Serious (Neutral)
xD - Jolly (+Speed, -SpAtk)
xE - Naive (+Speed, -SpDef)
xF - Modest (+SpAtk, -Atk)
x10 - Mild (+SpAtk, -Def)
x11 - Quiet (+SpAtk, -Speed)
x12 - Bashful (Neutral)
x13 - Rash (+SpAtk, -SpDef)
x14 - Calm (+SpDef, -Atk)
x15 - Gentle (+SpDef, -Def)
x16 - Sassy (+SpDef, -Speed)
x17 - Careful (+SpDef, -SpAtk)
x18 - Quirky (Neutral)
Hardy is unavailable due to the way the method works, but that doesn't really matter since it's neutral. Higher values will crash the game. If 0 is used, the method does not touch nature, so it will be determined semi-randomly like normally.
It is worth nothing that this method allows you to give trainer pokemon more than 510 EVs if you are feeling exceptionally rude.
-give trainers teams full of legendaries
-make the level curve absurdly steep
-inflate the base stats of everything
-give the AI illegal moves and custom attacks with absurd BP
-make every dungeon a flash maze where you can't use flash
Because I
First you will need to insert this ASM:
Fire Red:
Spoiler:
Code:
#EV spread table format
#Each spread is 16 bytes
#0x0 = Nature
#0x4 = IVs (from 0-31, not 0-255, used for all IVs)
# (if you want hidden powers, recall the ai can't handle -- bp moves)
#0x5 = HP EVs
#0x6 = Atk EVs
#0x7 = Def EVs
#0x8 = Speed EVs
#0x9 = SAtk EVs
#0xA = SDef EVs
#0xB = Pokeball
#last four bytes are filler
.align 2
.thumb
.thumb_func
.org 0x115f6
mov r0, r1
mov r6, r0
b 0x11604
.org 0x1162c
ldr r0, .Method_Addr
bx r0
.Method_Addr: .word 0x08F90001
.org 0x3dc70
b 0x3dcd0
.org 0xF90000
LoadItem:
add r5, #0x6
add r0, r4, #0x0
mov r1, #0xc
add r2, r5, #0x0
bl Insert_Element
LoadHPEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x5
mov r1, #0x1A
mov r0, r4
bl Insert_Element
LoadAtkEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x6
mov r1, #0x1B
mov r0, r4
bl Insert_Element
LoadDefEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x7
mov r1, #0x1C
mov r0, r4
bl Insert_Element
LoadSpeedEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x8
mov r1, #0x1D
mov r0, r4
bl Insert_Element
LoadSAtkEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x9
mov r1, #0x1E
mov r0, r4
bl Insert_Element
LoadSDefEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0xA
mov r1, #0x1F
mov r0, r4
bl Insert_Element
LoadBall:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0xB
mov r1, #0x26
mov r0, r4
bl Insert_Element
StartNatureLoop:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
ldrb r5, [r2, #0x0]
cmp r5, #0x0
beq LoadIVs
ldr r0, [r4, #0x0]
ldr r1, [r4, #0x4]
eor r1, r0, r1
str r1, [r4, #0x4]
NatureLoop:
ldr r0, [r4, #0x0]
add r0, r0, #0x18
str r0, [r4, #0x0]
mov r1, #0x19
bl Mod
cmp r0, r5
bne NatureLoop
EndNatureLoop:
ldr r0, [r4, #0x0]
ldr r1, [r4, #0x4]
eor r1, r0, r1
str r1, [r4, #0x4]
LoadIVs:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
ldrb r6, [r2, #0x4]
push {r6}
StartIVLoop:
mov r5, #0x27
IVLoop:
mov r0, r4
mov r1, r5
mov r2, sp
bl Insert_Element
add r5, r5, #0x1
cmp r5, #0x2D
bne IVLoop
End:
pop {r6}
bl Recalculate_Stats
ldr r1, .Return_Addr
bx r1
Insert_Element:
ldr r3, .Insert_Addr
bx r3
Recalculate_Stats:
mov r0, r4
ldr r1, .Recalc_Addr
bx r1
Mod:
ldr r3, .Mod_Addr
bx r3
.align 2
.Return_Addr: .word 0x08011639
.EV_Table: .word 0x08F00000
.Insert_Addr: .word 0x0804037d
.Recalc_Addr: .word 0x0803e47d
.Mod_Addr: .word 0x081e4685
Emerald:
Spoiler:
Code:
#EV spread table format
#Each spread is 16 bytes
#0x0 = Nature
#0x4 = IVs (from 0-31, not 0-255, used for all IVs)
# (if you want hidden powers, recall the ai can't handle -- bp moves)
#0x5 = HP EVs
#0x6 = Atk EVs
#0x7 = Def EVs
#0x8 = Speed EVs
#0x9 = SAtk EVs
#0xA = SDef EVs
#0xB = Pokeball
#last four bytes are filler
.align 2
.thumb
.thumb_func
.org 0x38936
mov r0, r1
mov r6, r0
b 0x38944
.org 0x3896c
ldr r0, .Method_Addr
bx r0
.Method_Addr: .word 0x08F90001
.org 0x67d68
b 0x67dc8
.org 0xF90000
LoadItem:
add r5, #0x6
add r0, r4, #0x0
mov r1, #0xc
add r2, r5, #0x0
bl Insert_Element
LoadHPEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x5
mov r1, #0x1A
mov r0, r4
bl Insert_Element
LoadAtkEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x6
mov r1, #0x1B
mov r0, r4
bl Insert_Element
LoadDefEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x7
mov r1, #0x1C
mov r0, r4
bl Insert_Element
LoadSpeedEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x8
mov r1, #0x1D
mov r0, r4
bl Insert_Element
LoadSAtkEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0x9
mov r1, #0x1E
mov r0, r4
bl Insert_Element
LoadSDefEV:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0xA
mov r1, #0x1F
mov r0, r4
bl Insert_Element
LoadBall:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
add r2, #0xB
mov r1, #0x26
mov r0, r4
bl Insert_Element
StartNatureLoop:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
ldrb r5, [r2, #0x0]
cmp r5, #0x0
beq LoadIVs
ldr r0, [r4, #0x0]
ldr r1, [r4, #0x4]
eor r1, r0, r1
str r1, [r4, #0x4]
NatureLoop:
ldr r0, [r4, #0x0]
add r0, r0, #0x18
str r0, [r4, #0x0]
mov r1, #0x19
bl Mod
cmp r0, r5
bne NatureLoop
EndNatureLoop:
ldr r0, [r4, #0x0]
ldr r1, [r4, #0x4]
eor r1, r0, r1
str r1, [r4, #0x4]
LoadIVs:
lsl r0, r6, #0x4
ldr r2, .EV_Table
add r2, r0
ldrb r6, [r2, #0x4]
push {r6}
StartIVLoop:
mov r5, #0x27
IVLoop:
mov r0, r4
mov r1, r5
mov r2, sp
bl Insert_Element
add r5, r5, #0x1
cmp r5, #0x2D
bne IVLoop
End:
pop {r6}
bl Recalculate_Stats
ldr r1, .Return_Addr
bx r1
Insert_Element:
ldr r3, .Insert_Addr
bx r3
Recalculate_Stats:
mov r0, r4
ldr r1, .Recalc_Addr
bx r1
Mod:
ldr r3, .Mod_Addr
bx r3
.align 2
.Return_Addr: .word 0x08038979
.EV_Table: .word 0x08EF0000
.Insert_Addr: .word 0x0806acad
.Recalc_Addr: .word 0x08068d0d
.Mod_Addr: .word 0x082e7be1
The bulk of this code is at xF90000- that part doesn't have to go there, it can be moved to wherever you have free space. Just make sure you change Method_Addr to whatever you change the offset to + 1.
You will also need to find x1000 bytes of space, and change the .EV_Table variable in the method to point to it (I used xF00000). This is where the spreads will go. The method gives you 256 spreads to use- this is not full control, but it is more than you are likely to need (the Emerald Battle Frontier only uses around 36 IIRC). The EV Spread table format is:
- Nature
- 3 unused bytes
- HP EV
- Attack EV
- Defense EV
- Speed EV
- Special Attack EV
- Special Defense EV
- What pokeball the mon comes out in
- 4 more unused bytes (I may update the method later to do something with these)
To assign an EV spread to a trainer's pokemon, set the value that was formerly their IVs to which slot in the table you want that pokemon to use. If you are using A-Trainer, this value is erroneously marked as AI Value. Note that the method only works for trainers with custom movesets and items- if they use default movesets or items, it will only affect IVs. It will still work if you manually give the trainer the moves it would have by default or explicitly define their mons as being empty-handed though.
This hack now allows custom natures. The natures are enumerated like so:
x0 - Arbitrary
x1 - Lonely (+Atk, -Def)
x2 - Brave (+Atk, -Speed)
x3 - Adamant (+Atk, -SpAtk)
x4 - Naughty (+Atk, -SpDef)
x5 - Bold (+Def, -Atk)
x6 - Docile (Neutral)
x7 - Relaxed (+Def, -Speed)
x8 - Impish (+Def, -SpAtk)
x9 - Lax (+Def, -SpDef)
xA - Timid (+Speed, -Atk)
xB - Hasty (+Speed, -Def)
xC - Serious (Neutral)
xD - Jolly (+Speed, -SpAtk)
xE - Naive (+Speed, -SpDef)
xF - Modest (+SpAtk, -Atk)
x10 - Mild (+SpAtk, -Def)
x11 - Quiet (+SpAtk, -Speed)
x12 - Bashful (Neutral)
x13 - Rash (+SpAtk, -SpDef)
x14 - Calm (+SpDef, -Atk)
x15 - Gentle (+SpDef, -Def)
x16 - Sassy (+SpDef, -Speed)
x17 - Careful (+SpDef, -SpAtk)
x18 - Quirky (Neutral)
Hardy is unavailable due to the way the method works, but that doesn't really matter since it's neutral. Higher values will crash the game. If 0 is used, the method does not touch nature, so it will be determined semi-randomly like normally.
It is worth nothing that this method allows you to give trainer pokemon more than 510 EVs if you are feeling exceptionally rude.
Last edited: