The PokéCommunity Forums

The PokéCommunity Forums (https://www.pokecommunity.com/index.php)
-   Binary Hack Research & Development (https://www.pokecommunity.com/forumdisplay.php?f=195)
-   -   Code ASM Resource Thread (https://www.pokecommunity.com/showthread.php?t=339153)

AkameTheBulbasaur June 6th, 2020 10:09 PM

Var Mathematics For FireRed
In NPC scripting, there exist commands to add/subtract an integer value to a variable (AddVar an SubtractVar). However, these commands may be a little bit limited. It may be that you want to multiply or divide a var, or add two vars together. In that case, you can use these:

What To Do First
First, you will want to find two half-words of free RAM. It does not need to be permanent RAM (RAM that is saved with the game). However, you will need to know what number var that RAM corresponds to. I recommend NOT using the 0x8000+ temp vars, since then you will be unable to manipulate values stored into them.

These routines use the vars 0x4074 and 0x4075 by default, but these can be changed in the following way.

1. Figure out the difference between the var you want to use and 0x4074. Keep in mind this is in hexadecimal.
2. Multiply that value by two.
3. Add (or subtract if your var is less than 0x4074) from 0x02026614. This is still in hexadecimal. You should then get the RAM address of the var you want to use.
4. Repeat for the second var if desired.
5. Change the addresses after .Var4074 and .Var4075.

The Actual Routines
The routines below perform the following operations:

1. Addition
2. Subtraction
3. Multiplication
4. Division
5. AND
6. OR

For the AND and OR operations, I'll explain them a little for those who are not familiar with them. If you AND two binary numbers, the resulting number has the bit equal to one if the corresponding bits of the input numbers are the same, and zero if they were different. For example, 1011 AND 1100 = 1000.

For the OR operation, if both bits of the input numbers are zero, it returns zero. Otherwise it returns one. In other words, if one OR the other number has a bit equal to one, the resulting number's bit is set equal to one. For example, 0010 OR 1000 = 1010.

Add Vars
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global AddVars

/* The purpose of this function is to add the vars */
/* stored in 0x4074 and 0x4075 */

/* This adds 0x4075 to 0x4074 */
/* Since addition is commutative, this doesn't matter */
/* But for the SubtractVar routine this will matter */

Main:
push {r0-r5, lr}
ldr r4, .Var4074 /* First Var */
ldrh r4, [r4]
ldr r5, .Var4075 /* Second Var */
ldrh r5, [r5]

GetTheRAM:
mov r0, r4
bl GetVarRAM
mov r4, r0 /* Address of the first var */
ldrh r4, [r4] /* Value in that var */
mov r0, r5
bl GetVarRAM
mov r5, r0 /* Address of the second var */
ldrh r5, [r5] /* Value in that var */

AddThem:
add r4, r4, r5 /* Adds r5 to r4 and stores in r4 */
ldr r0, .LastResult
strh r4, [r0] /* Puts result in LASTRESULT */
pop {r0-r5, pc}

GetVarRAM:
ldr r1, .GetVarRAM
bx r1

.align 2
.Var4074: .word 0x02026614
.Var4075: .word 0x02026616
.GetVarRAM: .word 0x0806E455
.LastResult: .word 0x020370D0


Subtract Vars
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global SubtractVars

/* The purpose of this function is to subtract the vars */
/* stored in 0x4074 and 0x4075 */

/* This subtracts 0x4075 from 0x4074 */
/* Subtraction is NOT commutative so the order matters! */
/* Also, negative numbers are represented as really big */
/* Positive numbers */

/* So 0x0 - 0x1 = 0xFFFF = 65,535 */

Main:
push {r0-r5, lr}
ldr r4, .Var4074 /* First Var */
ldrh r4, [r4]
ldr r5, .Var4075 /* Second Var */
ldrh r5, [r5]

GetTheRAM:
mov r0, r4
bl GetVarRAM
mov r4, r0 /* Address of the first var */
ldrh r4, [r4] /* Value in that var */
mov r0, r5
bl GetVarRAM
mov r5, r0 /* Address of the second var */
ldrh r5, [r5] /* Value in that var */

SubtractThem:
sub r4, r4, r5 /* Subtracts r5 from r4 and stores in r4 */
ldr r0, .LastResult
strh r4, [r0] /* Puts result in LASTRESULT */
pop {r0-r5, pc}

GetVarRAM:
ldr r1, .GetVarRAM
bx r1

.align 2
.Var4074: .word 0x02026614
.Var4075: .word 0x02026616
.GetVarRAM: .word 0x0806E455
.LastResult: .word 0x020370D0


Multiply Vars
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global MultiplyVars

/* The purpose of this function is to multiply the vars */
/* stored in 0x4074 and 0x4075 */

/* This multiplies 0x4075 and 0x4074 */
/* Multiplication is commutative yay */

Main:
push {r0-r5, lr}
ldr r4, .Var4074 /* First Var */
ldrh r4, [r4]
ldr r5, .Var4075 /* Second Var */
ldrh r5, [r5]

GetTheRAM:
mov r0, r4
bl GetVarRAM
mov r4, r0 /* Address of the first var */
ldrh r4, [r4] /* Value in that var */
mov r0, r5
bl GetVarRAM
mov r5, r0 /* Address of the second var */
ldrh r5, [r5] /* Value in that var */

MultiplyThem:
mul r4, r5 /* Multiplies r4 by r5 */
ldr r0, .LastResult
strh r4, [r0] /* Puts result in LASTRESULT */
pop {r0-r5, pc}

GetVarRAM:
ldr r1, .GetVarRAM
bx r1

.align 2
.Var4074: .word 0x02026614
.Var4075: .word 0x02026616
.GetVarRAM: .word 0x0806E455
.LastResult: .word 0x020370D0


Divide Vars
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global AddVars

/* The purpose of this function is to divide the vars */
/* stored in 0x4074 and 0x4075 */

/* This divides 0x4074 by 0x4075 */
/* Division is very much NOT commutative */
/* Also, this is INTEGER division */
/* Meaning that it rounds to the previous integer */
/* So if your result would be 1/2, it rounds to 0 */

Main:
push {r0-r5, lr}
ldr r4, .Var4074 /* First Var */
ldrh r4, [r4]
ldr r5, .Var4075 /* Second Var */
ldrh r5, [r5]

GetTheRAM:
mov r0, r4
bl GetVarRAM
mov r4, r0 /* Address of the first var */
ldrh r4, [r4] /* Value in that var */
mov r0, r5
bl GetVarRAM
mov r5, r0 /* Address of the second var */
ldrh r5, [r5] /* Value in that var */

DivideThem:
mov r0, r4
mov r1, r5
bl Division
mov r4, r0
ldr r0, .LastResult
strh r4, [r0] /* Puts result in LASTRESULT */
pop {r0-r5, pc}

GetVarRAM:
ldr r1, .GetVarRAM
bx r1

Division:
ldr r2, .Divide
bx r2

.align 2
.Var4074: .word 0x02026614
.Var4075: .word 0x02026616
.GetVarRAM: .word 0x0806E455
.Divide: .word 0x081E4019
.LastResult: .word 0x020370D0


AND Vars
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global ANDVars

/* The purpose of this function is to perform the AND operation on the vars */
/* stored in 0x4074 and 0x4075 */

/* This ANDs 0x4075 & 0x4074 */
/* This operation is commutative */

Main:
push {r0-r5, lr}
ldr r4, .Var4074 /* First Var */
ldrh r4, [r4]
ldr r5, .Var4075 /* Second Var */
ldrh r5, [r5]

GetTheRAM:
mov r0, r4
bl GetVarRAM
mov r4, r0 /* Address of the first var */
ldrh r4, [r4] /* Value in that var */
mov r0, r5
bl GetVarRAM
mov r5, r0 /* Address of the second var */
ldrh r5, [r5] /* Value in that var */

SubtractThem:
and r4, r5 /* AND r4, r5 */
ldr r0, .LastResult
strh r4, [r0] /* Puts result in LASTRESULT */
pop {r0-r5, pc}

GetVarRAM:
ldr r1, .GetVarRAM
bx r1

.align 2
.Var4074: .word 0x02026614
.Var4075: .word 0x02026616
.GetVarRAM: .word 0x0806E455
.LastResult: .word 0x020370D0


OR Vars
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global ANDVars

/* The purpose of this function is to perform the OR operation on the vars */
/* stored in 0x4074 and 0x4075 */

/* This ORs 0x4075 & 0x4074 */
/* This operation is commutative */


Main:
push {r0-r5, lr}
ldr r4, .Var4074 /* First Var */
ldrh r4, [r4]
ldr r5, .Var4075 /* Second Var */
ldrh r5, [r5]

GetTheRAM:
mov r0, r4
bl GetVarRAM
mov r4, r0 /* Address of the first var */
ldrh r4, [r4] /* Value in that var */
mov r0, r5
bl GetVarRAM
mov r5, r0 /* Address of the second var */
ldrh r5, [r5] /* Value in that var */

SubtractThem:
orr r4, r5 /* OR r4, r5 */
ldr r0, .LastResult
strh r4, [r0] /* Puts result in LASTRESULT */
pop {r0-r5, pc}

GetVarRAM:
ldr r1, .GetVarRAM
bx r1

.align 2
.Var4074: .word 0x02026614
.Var4075: .word 0x02026616
.GetVarRAM: .word 0x0806E455
.LastResult: .word 0x020370D0


How To Use Them
These are meant to be used in NPC scripts. You use them as follows:

#org @Script
setvar 0x8000 0xAAAA ' Whatever value you want
setvar 0x8001 0xBBBB ' Whatever value you want
setvar 0x4074 0x8000
setvar 0x4075 0x8001
callasm 0x8AABBCC+1 ' AABBCC is the offset where you inserted the routine. Add one for THUMB.
...


The result is stored into LASTRESULT. The original vars are not changed by the routine at all.

ssd1334 June 11th, 2020 7:53 PM

how did you edit the IV values for hidden power types?

RichterSnipes June 12th, 2020 4:23 PM

Quote:

Originally Posted by Skeli (Post 9936240)
Only Buy 1 TM From Shops [FR]

If you've decided to make your TMs reusable in Fire Red, this routine will remove the option to buy more than one of each from shops. Credits to azurile13 for the first part (Main) of the code.The only thing that needs changing is the line ".equ offset".
Spoiler:
Code:

.thumb
.global AlreadyOwnTM

.equ rom, 0x8000000
.equ offset, 0x893960 @CHANGE THIS LINE

.org 0x9BC3C, 0xFF
        ldr r1, .Pointer1
        bx r1
.Pointer1: .word Main + rom + 1

.org 0x9BC7C, 0xFF
        ldr r0, .Pointer2
        bx r0
.Pointer2: .word OnlyBuyOne + rom + 1

.org 0x9BEBC, 0xFF
        ldr r1, .Pointer3
        bx r1
.Pointer3: .word AddItem + rom + 1

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

.org offset, 0xFF
Main:
        lsr r4, r0, #0x10
        mov r0, r4
        ldr r2, .GetItemPocket
        bl Jump
        cmp r0, #0x4
        bne Return
        mov r0, r4
        mov r1, #0x1
        ldr r2, .CheckItem
        bl Jump
        cmp r0, #0x0
        bne AlreadyOwn

Return:
        mov r0, r4
        ldr r1, =0x809BC45
        bx r1

AlreadyOwn:
        ldr r1, .AlreadyHaveTMString
        ldr r2, =0x809BC67
        bx r2

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

OnlyBuyOne:
        ldr r1, .FCodeBuffer2
        mov r0, r4
        ldr r2, .ItemID_Copy_Name
        bl Jump
        mov r0, r4
        ldr r2, .GetItemPocket
        bl Jump
        cmp r0, #0x4
        bne Return2

GetPrice:
        mov r0, r4
        ldr r2, .GetMarketPrice
        bl Jump
        mov r1, r0
        ldr r0, .FCodeBuffer2
        add r0, #0x20
        mov r2, #0x3
        mov r3, #0x8
        bl Hex2Dec
        ldr r1, .NewYouWantString
        ldr r2, =0x809BE91
        ldr r3, =0x809BC89
        bx r3

Return2:
        ldr r1, =0x809BC85
        bx r1

Hex2Dec:
        ldr r4, =0x8008E79
        bx r4

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

AddItem:
        ldr r2, .GetItemPocket
        bl Jump
        cmp r0, #0x4
        bne Return3
        mov r0, #0x1
        strh r1, [r4, #0x2]

Return3:
        ldrh r0, [r4, #0xA]
        ldrh r1, [r4, #0x2]
        ldr r2, .Bag_Add_Item
        bl Jump
        lsl r0, #0x18
        ldr r2, =0x809BEC5
Jump:
        bx r2

.align 2
.FCodeBuffer2: .word 0x2021CD0
.GetItemPocket: .word 0x809A9D9
.CheckItem: .word 0x8099F41
.ItemID_Copy_Name: .word 0x8099E91
.GetMarketPrice: .word 0x809A901
.Bag_Add_Item: .word 0x809A085
.AlreadyHaveTMString: .word STRING1 + rom
.NewYouWantString: .word STRING2 + rom

STRING1: .byte 0xD3, 0xE3, 0xE9, 0x00, 0xD5, 0xE0, 0xE6, 0xD9, 0xD5, 0xD8, 0xED, 0x00, 0xE3, 0xEB, 0xE2, 0x00, 0xE8, 0xDC, 0xD5, 0xE8, 0x00, 0xCE, 0xC7, 0xAD, 0xFC, 0x09, 0xFF
STRING2: .byte 0xFD, 0x02, 0xB8, 0xFE, 0xCE, 0xDC, 0xD5, 0xE8, 0x00, 0xEB, 0xDD, 0xE0, 0xE0, 0x00, 0xD6, 0xD9, 0x00, 0xB7, 0xFD, 0x03, 0xAD, 0x00, 0xC9, 0xDF, 0xD5, 0xED, 0xAC, 0xFF



I've got a pretty big issue with this code. After inserting it, any time I try to purchase an item from a vendor they try to sell it for absurdly low prices at first. For example, if you try to buy a Great Ball from someone, they initially sell it at $3 instead of $600. And yes, that's how much it actually takes away from you, not the $600. If you change the quantity of item, the price goes back to what it normally should be per item.

These super low prices that are offered for each item appear to actually be the internal item ID number for each thing, converted to decimal format. One Potion, for instance, costs $13. It's item ID value is 0xD.

Anyone have any ideas what's going on here? Did I do something wrong?

elie2222 June 13th, 2020 2:25 AM

Can anyone please help me add the Everstone 100% chance nature inheriting mechanism to the IV inheriting posted by FBI ?

Spoiler:
Quote:

Originally Posted by FBI (Post 8514906)

Inheriting IVs from parents (via Destiny Knot, in the daycare)



How to insert:

Before doing anything, look at the code. There are two comments that say:
@masterball lol. Change to item you want :D
@Parent2 has masterball :D
At those lines, change the line to "cmp r0, #0xDestinyKnotItemID" and
"cmp r3, #0xDestinyKnotItemID" respectively.

Once you're done that, compile and insert into free space.
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r3, r6}
        mov r6, lr
        mov r0, r5
        mov r1, #0xC
        ldr r2, =(0x803FD44 +1)
        bl linker
        mov r3, r0
        mov r0, r5
        add r0, r0, #0x8C
        mov r1, #0xC
        ldr r2, =(0x803FD44 +1)
        bl linker
        cmp r0, #0x1 @masterball lol. Change to item you want :D
        beq inherit
        cmp r3, #0x1 @Parent2 has masterball :D
        beq inherit

end:
        mov lr, r6
        pop {r3, r6}
        mov r0, SP
        mov r1, r5
        ldr r3, = (0x8045AC0 +1)
        bl linkerTwo
        ldr r0, =(0x8046100+1)
        bx r0

inherit:
        mov r3, #0x5
        bl generateRand
        ldrh r3, [r3]
        push {r4, r7}
        mov r4, #0x27
        add r4, r4, r3 @uninherited stat
        mov r7, #0x0

loop:
        cmp r7, #0x6
        beq prepareEnd
        cmp r7, r4
        beq next
        mov r3, #0x1
        bl generateRand @get a random parent's specified IV
        mov r0, r3
        ldrh r0, [r0]
        mov r1, #0x8C
        mul r0, r0, r1
        add r0, r0, r5
        mov r1, #0x27
        add r1, r1, r7
        ldr r2, =(0x803FBE8 +1)
        bl linker
        ldr r2, = (0x20370D0) @set IV to child
        strh r0, [r2]
        mov r1, #0x27
        add r1, r1, r7
        mov r0, SP
        ldr r3, =(0x804037C +1)
        bl linkerTwo
next:
        add r7, r7, #0x1
        b loop

prepareEnd:
        mov r0, SP
        ldr r3, =(0x803E47C +1) @calc stats
        bl linker
        pop {r4, r7}
        b end

generateRand:
        ldr r2, =(0x8044EC8 +1) @get a random between 0 - r3 (r3 = HW)
        bl linker
        lsl r0, r0, #0x10
        lsr r0, r0, #0x10
        mov r1, r3
        ldr r3, =(0x81E4684 +1)
        bl linkerTwo
        ldr r3, = 0x20370D0 @could just move it to r3 I suppose
        strh r0, [r3]
        bx lr

linker:
        bx r2

linkerTwo:
        bx r3

.align 2




Here's a compiled version:
Code:

48 B4 76 46 28 1C 0C 21 26 4A 00 F0 49 F8 03 1C 28 1C 8C 30 0C 21 23 4A 00 F0 42 F8 01 28 0A D0 01 2B 08 D0 B6 46 48 BC 68 46 29 1C 1E 4B 00 F0 38 F8 1E 48 00 47 05 23 00 F0 26 F8 1B 88 90 B4 27 24 E4 18 00 27 06 2F 18 D0 A7 42 14 D0 01 23 00 F0 1A F8 18 1C 00 88 8C 21 48 43 40 19 27 21 C9 19 13 4A 00 F0 1C F8 12 4A 10 80 27 21 C9 19 68 46 11 4B 00 F0 15 F8 01 37 E4 E7 68 46 0F 4B 00 F0 0E F8 90 BC CD E7 0D 4A 00 F0 09 F8 00 04 00 0C 19 1C 0B 4B 00 F0 04 F8 06 4B 18 80 70 47 10 47 18 47 45 FD 03 08 C1 5A 04 08 01 61 04 08 E9 FB 03 08 D0 70 03 02 7D 03 04 08 7D E4 03 08 C9 4E 04 08 85 46 1E 08


Now go to 0x460F8 and insert the following:
Code:

00 48 00 47 XX XX XX 08


Where XX XX XX is the pointer in reverse hex +1 of the routine you just compiled.


How it works:
When the egg is generated, we check both parents to see if their holding an item matching the item we're looking for. If they are, the egg inherits 5/6 IVs from their parents. Each parent has a 50% chance to pass down one of their IVs.

There is no usage section, because the rest is done automagically when you have two compatible Pokemon in the daycare and they make an egg :)

Also, sorry for the double post, I wanted a fresh post for the first page :P


fireYtail June 16th, 2020 12:45 PM

Hi, there! I've been making Pokémon FireRed hack roms for some time now, but never got to understand ASM, so I have a few requests about problems I've been facing. First of all, I'm familiar with XSE scripts and hexadecial numbers and HxD (hex editor), but not with how ASM works. The furthest I've reached is executing my custom menus (normal XSE scripts) via a key item using the "use of select" option in complete item editor. However this only works in overworld mode... I've miserably failed to run anything custom in-battle. I know battle scripts are different than XSE scripts, and have also downloaded the battle script pro tool, but that's about it. I have the thumb ASM compiler too. Well, I should go to the point now.

I'll start with the biggest issue. If flag 0x301 is set then receive all Pokémon from trainers upon trainer defeat (thief mode) Now I have a few questions here. Is there a way to call an ASM routine every time a trainer has been defeated? (or a battle ends, for that matter?) Trainer party data is located at ram offset 0x0202402C, is this data automatically cleared upon battle finish? I would need this data to be taken and then given to the player in the same way givepokemon works. What I mean by this is, first use the player's party slots then send the remaining Pokémon to the PC. In other words I need the party at said address to be given to the player as is (save maybe bug fixes?) If this being done automatically is not possible then I can script every single NPC in the game a callasm. That'd be more work, but it'd still be doable without having to manually script every single Pokémon from every single trainer in the game via givepokemon, special(s) and JPAN's hacks. That's a lot of work to do, you got the idea. Plus, in such a way it'd be impossible to replicate the IVs (and EVs as well?) from the stolen Pokémon, since I can't know their values during battle. Again, I know nothing of ASM but I guess just copying data from one ram location to another must not be too hard to script.

But that's not my only concern. I also need a way to make battles against 1 Pokémon, fully customizable except for moves (default attacks), that you can't run away from, that you can't catch the Pokémon by any means and that you earn an also customizable amount of price money for. I'm unsure as to whether I can already do this with what's already on the internet. I used to "do this" by creating 386 new trainers with a single Pokémon each, but that's a lot of work to do and also "ugly" if you get my meaning. Unprofessional.

Last but not least, we hear a lot about XSE scripts calling ASM, but what about it in reverse? Is it possible? (Guessing it is, since "virtually anything" is possible with ASM) I ask this because I want to change the exit option of the start menu to one that runs my XSE script with custom multichoice menus and submenus, instead of having to use a key item to be able to run the script from anywhere. Or even better, cancel button select "register" feature and call my script whenever select is pressed (without a custom item) Is it possible? Or even better, if I'm allowed to request, whenever you press the L and R buttons both at the same time in overworld mode (I have already disabled the annoying help system that takes priority over everything else, but had no luck with JPAN's key scripts nor walking scripts, changed default game settings as well)

Thank you very much in advance for your help and please have a nice day ^^ If someone could lend me a hand with JPAN's key scripts and/or walking scripts, that would be a great plus.

Edit: Oh, I almost forgot, JPAN's species changer leaves the name intact so I'd need code to set a Pokémon name to the default for its species, too.
Edit2: Oh my God, I can't believe it but I managed to find the pointer to the script that runs when select is pressed and no item is registered, it's at offset 0x10ADA8!

fireYtail June 18th, 2020 11:57 PM

Quote:

Originally Posted by FBI (Post 8509928)
It should have no problems with any other hacks; this check is quite standalone. I should also mention the Pokemon you captured from another trainer will act like a Pokemon who has been traded. If you don't have the badges to train it, it will disobey you.



Thanks for that.



Thanks. To my knowledge, the gameshark code still turns your Pokemon to a bad egg. This fixes the bad egg too!

Anyways, I've finished all the requests which I'm willing to do. Keep shooting them at me guys :P

EDIT:


Toggling Capturability of Pokemon



So it's quite likely that maybe you want a Pokemon to be uncapturable, and at the same time you don't want to diminish it's catch rate to 0 in your Pokemon editor. Or perhaps you used the "capture trainer Pokemon" hack and you don't want it to work for all trainers. No problem, this is the hack for you :P

Basically it checks if variable 0x8000 is 0x1 or not. If it's 0x1, then any Pokemon you encounter (trainer or wild, via script or natural encounter) will become uncapturable even with the master ball. Simply set 0x8000 back to normal for the original game mechanics.
Note: If you use this hack, to say make it so the player can only capture a certain trainer's Pokemon, you will need to set 0x8000 right before the encounter, and unset it after (which is quite simple)
Note2: This hack won't let you capture trainer Pokemon, you need to have the capture trainer Pokemon hack from last time to create that effect.

How to insert:

First compile the following ASM code and insert into free space:
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        ldr r0, =(0x2022B4C)
        ldr r1, [r0]
        ldr r2, .VAR
        ldrb r2, [r2]
        cmp r2, #0x1
        beq uncatchable
        ldr r0, = (0x802D490 +1)
        bx r0

uncatchable:
        ldr r0, = (0x802D460 +1)
        bx r0

.align 2
.VAR:
        .word 0x020270B8 + (0x8000 * 2) @change to var of your choice if you want




Here is a compiled version:
Code:

05 48 01 68 03 4A 12 78 01 2A 01 D0 03 48 00 47 03 48 00 47 B8 70 03 02 4C 2B 02 02 91 D4 02 08 61 D4 02 08


Now navigate to 0x2D452 and insert the following:
Code:

01 48 00 47 00 00 XX XX XX 08


Where XX XX XX is the reverse hex pointer to where you inserted the above routine. That's it :)
EDIT: Add one to the pointer.

Here's a pesky Rattata:

(Yes, the Pokeball animation is still there, this was taken after it.)

Unfortunately, unlike the toggle run away code, this ASM isn't working with special 0x138...

Edit: After some more testing I found out neither of them worked because I was using a variable under 0x8000..

AkameTheBulbasaur June 24th, 2020 12:31 PM

Nature Changing
Before I begin, I should mention that this only works for FireRed at the moment. This is because it uses the Lustre stat, which in FireRed is unused but in Emerald is not. If you can find another stat to use, (or you don't have contests in your Emerald hack), then you can use this.

Offsets listed here are for FireRed, though, so keep that in mind if you decide to port it.

Anyway, without further ado, I present Nature Changing!

How Does It Work?
Skip this if you don't care about the behind the scenes stuff.

Basically, this hijacks the GetNature function. It first checks the Lustre stat of the Pokemon in question. If it's equal to zero, then it gets the Nature form the PID as usual. If it's not zero, then it uses the Lustre value as the Nature, effectively changing the Pokemon's Nature without messing with the PID (and potentially messing up other stuff like the Pokemon's gender, Shininess, etc.).

This does mean you can't set the Nature to Hardy, but this is not that big of a deal since there are other neutral Natures you can use.

The Main Event
I have written an instruction manual that explains how to use the hack in detail. It also contains links to download everything.

The link presented below is the link to download the folder with the Instruction Manual and all the routines. Not every routine in the folder is one you need to insert, as there are a couple of optional add-ons to make changed Natures compatible with other hacks.

Download: Here!

ssd1334 June 29th, 2020 7:10 AM

Quote:

Originally Posted by FBI (Post 8540240)

Getting IVs and EVs



The routines are very similar so I ended up just combining the two routines into one. Basically given a slot number of a Pokemon in 0x8004, the routines will return the EVs or IVs, respectively, into the vars 0x8005-0x800A with 0x8003 as the IV/EV switch.


How to insert:

Compile and insert the following routine into free space:

Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r0-r5, lr}
        mov r4, #0x0

loop:
        cmp r4, #0x6
        bhi end
        ldr r0, =(0x20370C0) @var 0x8004 = slot number
        ldrh r0, [r0]
        mov r1, #0x64
        mul r1, r1, r0
        ldr r0, =(0x2024284)
        add r0, r0, r1
        ldr r3, =(0x20370BE)
        ldrh r3, [r3]
        cmp r3, #0x0
        beq EVs
        add r1, r1, #0x27 @IV
        b continue

EVs:
        add r1, r1, #0x1A

continue:
        ldr r2, =(0x803FBE8 +1)
        bl linker
        mov r1, r0
        @get var
        ldr r2, =(0x20370C2) @using vars 0x8005-0x800A
        lsl r0, r4, #0x1
        add r2, r2, r0
        strh r1, [r2] @store IV in var
        add r4, r4, #0x1
        b loop

linker:
        bx r2

end:
        pop {r0-r5, pc}

.align 2





Usage:
setvar 0x8003 0x[anything except 0 = IV, 0 = EV]
setvar 0x8004 0x[slot number 0 to 5]
callasm 0x[this routine +1]

The variables will be:
0x8005: HP IV/EV
0x8006: Atk IV/EV
0x8007: Def IV/EV
0x8008: Spd IV/EV
0x8009: S.atk IV/EV
0x800A: S.def IV/EV

see idk if im stupid or something, but i cant seem to figure out how to compile stuff in assembly

AkameTheBulbasaur June 30th, 2020 1:19 AM

Quote:

Originally Posted by ssd1334 (Post 10176247)
see idk if im stupid or something, but i cant seem to figure out how to compile stuff in assembly

I recommend using this tool. It's easy to use and lets you assemble directly into the ROM. Just copy-paste the routine you want to assemble in there, click the button and go!

A Timer System
This is mainly for Fire Red, but it could also work for Emerald if you have enough Free RAM. More on that as we go.

Anyway, this is a way to allow yourself to have timed events in Fire Red. As you may already know, FireRed does not have a Real Time Clock like Ruby/Sapphire/Emerald does. It does, however, have an internal clock that keeps track of how long you have been playing the game.

You could, if you wanted, try to use it to have timed events. For example, if you wanted to have something occur every ten minutes, and you knew the RAM for where the time you've been playing is, then you could theoretically do something like this:
  1. Save the current time when the event starts.
  2. When the script is run again, check the time again.
  3. If it's StartingTime + LengthOfEvent, then the event is over.

This is obnoxious for a variety of reasons. One, it kind depends on having a script run to end the event. Two, what happens if you've somehow been playing for 999 hours and 59 minutes. Then all your timed events break. Sure, that is a ridiculously long time, but still.

Then, I came across a few hacks that other people had made, which when brought together, opened a whole new world for me.

What You Need
Before we get started, there are a few things that you will need to have in your game first.

Now, you may be wondering, what on Earth is this dubious, unnamed patch and what on Earth is it doing to my ROM? The answer to that is is disables the "Previously On Your Quest" feature (the little slideshow that happens when you boot up the game). Now why would this be required for a Timer System?

The answer is that it frees up a TON of RAM. Like seriously, a TON. Like sooooooooo many bytes of RAM it's ridiculous. The best part? This RAM is saved by the game. Basically, if you want to expand your bag size, you don't need to use JPAN's Save Block anymore.

If you have a hack in progress, this is objectively the better way to free up RAM because now you don't need to restart any save files. In fact, I would just do this anyway, unless you REEEEEEALLY need the "Previously On Your Quest" thing for some reason.

What To Do
First, you will need to create a table. This table will have all the RAM Addresses of all the timers that you will want to use. You are really only limited by the amount of free RAM you can use for Vars. You could have one timer, or 100! I personally have 96.

Each entry of the table is four bytes long and is simply a pointer to the RAM addresss. If you want some help with figuring out what RAM addresses to use, click on the spoiler. The table needs to be terminated with FF FF FF FF.

Spoiler:
Var 0x4000 is at 0x0202652C. Let's say I want to know where Var 0x4050 is located. First, get the difference between the Var and 0x4000. In this case, it is 0x50. Then, multiply it by two. We know have 0xA0. Then add it to 0x0202652C. So Var 0x4050 is located at 0x020265CC.


If you are lazy and you applied the patch above, then you can use this table. It has 100 timers (you can use only part of it if you need less). It starts at 0x0202752C and ends at 0x020275F4. In Var terms, this is 0x4800 to 0x4864.

Spoiler:
2C 75 02 02 2A 75 02 02 2E 75 02 02 30 75 02 02 32 75 02 02 34 75 02 02 36 75 02 02 38 75 02 02 3A 75 02 02 3E 75 02 02 40 75 02 02 42 75 02 02 44 75 02 02 46 75 02 02 48 75 02 02 4A 75 02 02 4E 75 02 02 50 75 02 02 52 75 02 02 54 75 02 02 56 75 02 02 58 75 02 02 5A 75 02 02 5E 75 02 02 60 75 02 02 62 75 02 02 64 75 02 02 66 75 02 02 68 75 02 02 6A 75 02 02 6E 75 02 02 70 75 02 02 72 75 02 02 74 75 02 02 76 75 02 02 78 75 02 02 7A 75 02 02 7E 75 02 02 80 75 02 02 82 75 02 02 84 75 02 02 86 75 02 02 88 75 02 02 8A 75 02 02 8E 75 02 02 90 75 02 02 92 75 02 02 94 75 02 02 96 75 02 02 98 75 02 02 9A 75 02 02 9E 75 02 02 A0 75 02 02 A2 75 02 02 A4 75 02 02 A6 75 02 02 A8 75 02 02 AA 75 02 02 AE 75 02 02 B0 75 02 02 B2 75 02 02 B4 75 02 02 B6 75 02 02 B8 75 02 02 BA 75 02 02 BE 75 02 02 C0 75 02 02 C2 75 02 02 C4 75 02 02 C6 75 02 02 C8 75 02 02 CA 75 02 02 CE 75 02 02 D0 75 02 02 D2 75 02 02 D4 75 02 02 D6 75 02 02 D8 75 02 02 DA 75 02 02 DE 75 02 02 E0 75 02 02 E2 75 02 02 E4 75 02 02 E6 75 02 02 E8 75 02 02 EA 75 02 02 EE 75 02 02 F0 75 02 02 F2 75 02 02 F4 75 02 02 FF FF FF FF


The second table you will need to insert is a table that has the time limits for all your timers. Each entry is a half-word (two bytes long) and you will need one for each timer that you have in the previous table.

There are two options you have for each entry. If you enter in a number other than 0xFFFE, then it will function as a typical timer. For example, if you set it to 0x5, then after five minutes, it will be reset.

If you use 0xFFFE, then it turns your timer into a stopwatch. This will make the timer keep going until it reaches 0xFFFF minutes. How long is that? 0xFFFF = 65,535 minutes = 1092.25 hours = 45.5 days = long enough that you probably won't get to that point.

Okay, now you're ready to insert this routine somewhere and then add a pointer to it in the Minute Routine table (see FBI's Minute Routine post). Add the addresses of the tables after where it says .VarRAMTable and .TimeLimits.

Advance Timer Routine
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global EventTimers

/*
The purpose of this routine is to increment by 1 the Vars
that contain the timers for events like the records for
Gaikoku's Place.

Every minute, it will check over each timer and see if it is
set to 0x1. If so, it means the timer is active.

It will then add one to the value of the timer. If the limit is
not 0xFFFE, it will then check to see if it's reached the limit
*/

Main:
push {r0-r7, lr}
ldr r0, .VarRAMTable
ldr r1, .TimeLimits
mov r2, #0x0
mov r7, #0x0

Loop:
add r0, r0, #0x4
add r1, r1, #0x2
ldr r3, [r0] /* RAM Address of first var */
ldr r5, .Done /* End of table */
cmp r3, r5
beq Return
ldrh r4, [r1] /* Time Limit */
ldrh r6, [r3] /* r6 = Value in timer */
cmp r6, #0x1 /* 0x1 = Timer is activated */
bge CheckMax


FinishLoop:
add r2, r2, #0x4
add r7, r7, #0x2
b Loop

CheckMax:
ldr r5, .Done2
cmp r4, r5 /* Infinite Time */
beq AddOne
add r4, r4, #0x1 /* Add one here because you needed Var = 0x1 to start timer at all */
cmp r6, r4 /* Compare current minutes to limit */
bge Reset
add r6, r6, #0x1
strh r6, [r3]
b FinishLoop

AddOne:
ldr r5, .Done
lsl r5, r5, #0x10
lsr r5, r5, #0x10
cmp r6, r5 /* Compare the current time to 0xFFFF (the maximum) */
beq FinishLoop /* Don't add one here or it will break other timers */
add r6, r6, #0x1
strh r6, [r3]
b FinishLoop

Reset:
mov r5, #0x0
strh r5, [r3] /* Set RAM to zero */
b FinishLoop

Return:
pop {r0-r7, pc}

.align 2
.VarRAMTable: .word 0x08
.TimeLimits: .word 0x08
.Done: .word 0xFFFFFFFF
.Done2: .word 0x0000FFFE


How To Use
Now that we have it all inserted, how do we use it? In order to start a timer, just set the corresponding Var equal to 0x1. If it's a timer, the Var will reset itself when it reaches the limit. If it's a stopwatch, you will have to set it back to zero yourself.

Here's an example script showing the basics. It uses the Subtract Var routine that I linked above. In the script, the player is asked if they want some Lemonade. If they accept, they are given a Lemonade item and the timer is set. They can come back after fifteen minutes and get another. If they talk to the NPC before 15 minutes have elapsed, the NPC will tell the player how long they have to wait.

Note that this is fifteen minutes of in-game time. Turning off/pausing the game and coming back fifteen minutes later will not count.

Spoiler:
#dyn 0x740000
#org @Start
lock
faceplayer
textcolor RED
compare 0x4075 0x0 ' Timer is not running
if true jump @TimeToGive
setvar 0x8000 0xF ' Reset every fifteen minutes
setvar 0x4819 0x8000
setvar 0x481A 0x4075
callasm 0x8DE2F81 ' Subtract 0x4075 from 0x8000
storevar 0 LASTRESULT
message @NotReady
callstd MSG_SIGN
release
end

#org @TimeToGive
message @Hello
callstd MSG_YESNO
compare LASTRESULT YES
if true jump @Yes
message @Okay
callstd MSG_SIGN
release
end

#org @Yes
checkitemspaceinbag LEMONADE 1 ' Room for lemonade?
compare LASTRESULT FALSE
if true jump @Item
message @Give
callstd MSG_SIGN
additem LEMONADE 1
setvar 0x4075 0x1 ' Set Timer
textcolor GRAY
message @Get
callstd MSG_SIGN
fanfare 0x102
waitfanfare
release
end

#org @Item
textcolor GRAY
message @NoRoom
callstd MSG_SIGN
release
end

#org @Hello
= Melissa Hydan: Hello \v\h01!\pI just made some lemonade!\pIt's the Hydan family specialty!\pWould you like some?

#org @Give
= Here you go!\pI'll have some more in 15 minutes.

#org @okay
= Oh, all right.\pYou can come back any time.

#org @Get
= I received a Lemonade!

#org @NoRoom
= I have no space for it!

#org @NotReady
= Melissa Hydan: Hello \v\h01!\pWere you wanting some lemonade?\pI'll have some more ready in \v\h02\nminutes.\pCome back then, okay?


Ideas
Here are some ideas of what you can use this for.
  • Berry Trees (Have berries grow after certain amount of time).
  • A lottery you can play once every X minutes.
  • A delivery system where you can get a package after X minutes.
  • Timing how long it takes you to beat a trainer.
  • A sale at a store that lasts for X minutes and occurs every Y minutes.
  • Anything you can think of!

Julez1003 July 12th, 2020 2:26 PM

Heyo, i really like the 80x80 Mugshot Routine jiangzhengwenjzw has made and try atm to make it work on emerald, but unfortunately, i couldn´t achieve this.
I already tried to research the offsets for emerald but i couldn´t find the correct offsets for this.
So i would like to ask for some help.
Can somebody of you help me with the routine, please?
It would be awesome, because my knowledge is not the greatest. I also searched a lot on google, but the results, i found, aren´t really useful.

Pyxal August 6th, 2020 11:00 AM

The following development is done by DoesntKnowHowToPlay, and I have no part in it. This has been re-posted as the original link had died.

[FR] Displaying IV's on the stat screen
A small piece of ASM that allows you to view IV's in the Pokémon stat screen.


• Step 1 - Image insert
First, insert the following image using NSE or TileMolester. Remember the address where you put it:
Spoiler:
https://i.ibb.co/68WSh0c/7UQxmA5.png

It uses the same palette as the type chart, which is located at 0xE95DBC in vanilla FR. If you changed that palette, you'll have to change the above image as well (You'll probably want to change the image anyway since it's frankly rather minimalist).


• Step 2 - Actual ASM
Next you will need to insert the following ASM. It doesn't matter where, but do remember where you put it.
Code:

cmp r0, #0x0
beq Abort
cmp r0, #0x3
bgt Abort
cmp r0, #0x1
bne StandardAbort
b Start

Abort:
ldr r1, .AbortAddr
bx r1

StandardAbort:
ldr r1, .StandardAbortAddr
bx r1

.align 2
.AbortAddr: .word 0x08137bfd
.StandardAbortAddr: .word 0x08137bf9

Start:
ldr r0, .ActiveMonPtr
ldr r1, .ActiveOffset
ldr r0, [r0, #0x0]
add r6, r0, r1

add sp, #-0x18

HPIV:
mov r0, r6
mov r1, #0x27
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x6
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

AtkIV:
mov r0, r6
mov r1, #0x28
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x17
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

DefIV:
mov r0, r6
mov r1, #0x29
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x24
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

SAtkIV:
mov r0, r6
mov r1, #0x2B
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x31
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

SDefIV:
mov r0, r6
mov r1, #0x2C
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x3E
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

SpeedIV:
mov r0, r6
mov r1, #0x2A
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x4B
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

add sp, #0x18
b Abort

GraphicHandler:
ldr r4, .HandlerAddr
bx r4

Decrypter:
ldr r2, .DecrypterAddr
bx r2

.align 2
.GraphicAddr: .word 0x08XXXXXX
.HandlerAddr: .word 0x080041f1
.ActiveMonPtr: .word 0x0203b140
.ActiveOffset: .word 0x00003290
.MonIndex: .word 0x0203b16c
.DecrypterAddr: .word 0x0803FBE9



Replace the
0x08XXXXXX
with the address of the image you just inserted (no +1 or reverse needed).

• Step 3 - Byte changes
  1. At 0x137BF0, place 00 49 08 47 followed by a pointer to the code you just inserted plus one (for example, if you inserted it at 0x800000, you will place 00 49 08 47 01 00 80 08 at 0x137BF0).
  2. At 0x137BE4, place 01 20 03 E0.

Ending notes
With that, you should be good to go. In typical Pokémon fashion, this code does not give you the specific values; it instead gives you a unique two-value range. If you want to change that it's rather easy; cut every line starting with lsr in the code and reassemble it, then adjust the image so it has 32 meaningful values instead of 16.

Credits
DoesntKnowHowToPlay - Actual code, image
Lunos - He did the actual Google cache magic too find it

Again, this is done by DoesntKnowHowToPlay, and it is not done by me. Any credit should go DoesntKnowHowToPlay, and not me.

Raduziel September 3rd, 2020 11:53 AM

Hey Upsurge,

First, thanks for the feedback at the other thread.

Second, I have some questions (I told I was green)...

1) The image you kindly provided was saved at 71C000 (used Free Space Finder to find this spot). Should I replace the XXXXXX in your routine as 0x0871C000 or as 0x71C000? I guess it is the first option but I think it is best to ask.

2) I've copied your routine using Notepad++ and saved as IVRanking.asm but I have no idea about what I do with this file. So, I used a Thumb to turn this .asm into a .bin, opened this .bin file and my rom using HxD and pasted the bin's code inside the ROM starting at 71B500, I think this covers this step - let me know if I'm wrong, please.

3)

Quote:

Originally Posted by Upsurge (Post 10192478)
• Step 3 - Byte changes
  1. At 0x137BF0, place 00 49 08 47 followed by a pointer to the code you just inserted plus one (for example, if you inserted it at 0x800000, you will place 00 49 08 47 01 00 80 08 at 0x137BF0).
  2. At x137BE4, place 01 20 03 E0.

Can you please explain exactly how this is done?

Thanks in advance.

Pyxal September 3rd, 2020 8:08 PM

Quote:

Originally Posted by Raduziel (Post 10204136)
<snip>

This is NOT my routine. As said above, it is done by DoesntKnowHowToPlay.

1) This image was by DonestKnowHowToPlay, and yes, like this: 71C000. As an example, the routine would become:
Spoiler:
Code:

cmp r0, #0x0
beq Abort
cmp r0, #0x3
bgt Abort
cmp r0, #0x1
bne StandardAbort
b Start

Abort:
ldr r1, .AbortAddr
bx r1

StandardAbort:
ldr r1, .StandardAbortAddr
bx r1

.align 2
.AbortAddr: .word 0x08137bfd
.StandardAbortAddr: .word 0x08137bf9

Start:
ldr r0, .ActiveMonPtr
ldr r1, .ActiveOffset
ldr r0, [r0, #0x0]
add r6, r0, r1

add sp, #-0x18

HPIV:
mov r0, r6
mov r1, #0x27
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x6
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

AtkIV:
mov r0, r6
mov r1, #0x28
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x17
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

DefIV:
mov r0, r6
mov r1, #0x29
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x24
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

SAtkIV:
mov r0, r6
mov r1, #0x2B
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x31
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

SDefIV:
mov r0, r6
mov r1, #0x2C
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x3E
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

SpeedIV:
mov r0, r6
mov r1, #0x2A
bl Decrypter

mov r5, r0
lsr r5, r5, #0x1
mov r0, #0x40
mul r5, r0, r5

mov r1, #0x80
str r1, [sp, #0x0]
str r1, [sp, #0x4]

#x, y position
mov r2, #0xC
str r2, [sp, #0x8]
mov r1, #0x4B
str r1, [sp, #0xc]

#x, y size
mov r2, #0x10
str r2, [sp, #0x10]
mov r1, #0x8
str r1, [sp, #0x14]

mov r0, #0x3
ldr r1, .GraphicAddr
add r1, r5
mov r2, #0x0
mov r3, #0x0
bl GraphicHandler

add sp, #0x18
b Abort

GraphicHandler:
ldr r4, .HandlerAddr
bx r4

Decrypter:
ldr r2, .DecrypterAddr
bx r2

.align 2
.GraphicAddr: .word 0x0871C000
.HandlerAddr: .word 0x080041f1
.ActiveMonPtr: .word 0x0203b140
.ActiveOffset: .word 0x00003290
.MonIndex: .word 0x0203b16c
.DecrypterAddr: .word 0x0803FBE9




2) Yes, it covers this step. To automagically insert routines into your ROM, use this tool.

3) Basically you go to address's 0x137BF0 and 0x137BE4 in any hex editor, and replace (Ctrl+B) them with the said bytes.

Raduziel September 3rd, 2020 8:23 PM

Thanks for linking the tool, this will make my life easier in the future, I suppose.

Quote:

Originally Posted by Upsurge (Post 10204287)
3) Basically you go to address's 0x137BF0 and 0x137BE4 in any hex editor, and replace (Ctrl+B) them with the said bytes.

Ok, I got step 3.2, but 3.1 keeps elluding me.

In your example 0x800000 became 00 80 08 and that is the part that I'm failing to understand. Can you please explain this further? My case is 71B500, would the final input be 00 49 08 47 01 00 71 B5 08?

Again, thanks for taking the time to guide me through this.

Pyxal September 3rd, 2020 8:24 PM

Quote:

Originally Posted by Raduziel (Post 10204290)
Thanks for linking the tool, this will make my life easier in the future, I suppose.



Ok, I got step 3.2, but 3.1 keeps elluding me.

In your example 0x800000 became 00 80 08 and that is the part that I'm failing to understand. Can you please explain this further? My case is 71B500, would the final input be 00 49 08 47 01 00 71 B5 08?

Again, thanks for taking the time to guide me through this.

It will become 00 49 08 47 01 01 B5 71 08.

Raduziel September 3rd, 2020 8:41 PM

1 Attachment(s)
Quote:

Originally Posted by Upsurge (Post 10204291)
It will become 00 49 08 47 01 01 B5 71 08.

Thanks!

Looks like it is almost done but apparently I messed up somehow. The attached image shows the ranking boxes are there but no value inside though.

Edit: This was how I've inserted the image

NSE -> Load ROM -> Open Sprite -> Selected the one from the image above -> File -> Insert -> Image Data -> FreeSpaceFinder (checking from the beginning of the ROM and telling the size is 2048 bytes) -> 71C000 - Save


It is working perfectly, I was dumb and using an old backup without the inserted image. Thanks for guiding me through this. Cheers!

Raduziel September 4th, 2020 1:27 PM

Does anyone know how to alter the ASM routine to use a 256x8 image instead of a 128x32 one?

Thanks!

Raduziel September 11th, 2020 5:02 AM

Quote:

Originally Posted by Pokemon_XY (Post 8933435)
I've found a way to make TMs unsellable:

Hi,

I made all the changes but I can still sell TMs (they are reusable already).

On top of your changes I've used HexManiacAdvance to alter the Mystery Byte of TMs to "1" (the same way that HMs are displayed).

I'm using CFRU, by the way, but didn't set the flag for reusable TMs while installing that - everything achieved was through this thread (so far: reusable and no number display).

Thanks!

BluRose September 18th, 2020 10:21 AM

modulate experience with two scripting vars

https://cdn.discordapp.com/attachments/642222929312088065/756675053831323708/help.gif

take your experience and multiply it by the "var numerator" and then divide it by the "var denominator"

strongly suggest using higher numbers, i.e. if you want a 60% experience thing then set the numerator to 60 and the denominator to 100 so that the processor generates slightly more accurate numbers
also make sure that you can't really get more than about 56,000 experience, as that causes interesting errors

credit me and akamethebulbasaur
for fire red:
Spoiler:
Code:

/* Put 00 48 00 47 XX XX XX 08 a 0x21C38 and edit the var numbers at the bottom as you please */
.text
.align 2
.thumb
.thumb_func

EditarExperiencia:
    push {r1}
    ldr r0, .VarDenominador        /* Puedes cambiarla */
    mov r3, pc
    add r3, #7
    mov lr, r3
    ldr r3, .VarGet
    bx r3
    cmp r0, #0
    beq _dontdividebyzero
_continue:
    push {r0}
    ldr r0, .VarNumerador
    mov r3, pc
    add r3, #7
    mov lr, r3
    ldr r3, .VarGet
    bx r3
_terminar:
    pop {r1-r2}
    mul r0, r2
    mov r3, pc
    add r3, #7
    mov lr, r3
    ldr r3, .Dividir
    bx r3
    ldr r2, .Volver
    bx r2

_dontdividebyzero:
    mov r0, #1
    b _continue 

.align 2

.Volver:
    .word 0x08021C40 | 1
.VarNumerador:
    .word 0x40XX
.VarDenominador:
    .word 0x40XX
.VarGet:
    .word 0x0806E568 | 1
.Dividir:
    .word 0x081E4018 | 1



BluRose September 20th, 2020 12:33 PM

not to double post but

give your opposing trainers evs and ivs based on a var each

https://cdn.discordapp.com/attachments/642222929312088065/757336539675230296/help.gif

this primarily to make difficulty hacks where there can be multiple difficulties

put a value in one var that you want the opponents ivs to be and another value in another var that you want your opponent's evs to be (and yes, all of them will be the same)
the pokemon has to have just a custom item (at least that check mark ticked in your favorite trainer editor) then all of their values will be set. custom moveset doesn't have to be defined :P

pastebin right here

credit me and doesntknowhowtoplay
for fire red:
Spoiler:
Code:

@ new and improved
@ note:  check the box that makes the mon hold an item
@ pokemon tiene que tener un objeto, no importa si tiene movimientos personalizados

.align 2
.thumb
.thumb_func

.equ address_to_insert, 0xXXXXXX @ cambia esto, no 08 o algo así

.org 0x11596
mov r0, #1 @ used to determine return address
push {r0}
ldr r0, .Address_2
bx r0

.align 2

.Address_2: .word (0x08000001 | address_to_insert)

.org 0x115f6
mov r0, r1
mov r6, r0
b 0x11604

.org 0x1162c
mov r0, #0
push {r0}
ldr r0, .Method_Addr
bx r0

.align 2

.Method_Addr: .word (0x08000001 | address_to_insert)

.org 0x3dc70
b 0x3dcd0

.org address_to_insert

LoadItem:
add r5, #0x6
add r0, r4, #0x0
mov r1, #0xc
add r2, r5, #0x0
bl Insert_Element

StartEVs:
ldr r0, .VarEVs
bl get_value_from_var
mov r5, #0x1A
push {r0}

LoadEVs:
mov r0, r4
mov r1, r5
mov r2, sp
bl Insert_Element
add r5, #1
cmp r5, #0x1F+1
bne LoadEVs

StartIVs:
pop {r0}
ldr r0, .VarIVs
bl get_value_from_var
mov r5, #0x27
push {r0}

IVLoop:
mov r0, r4
mov r1, r5
mov r2, sp
bl Insert_Element
add r5, r5, #0x1
cmp r5, #0x2C+1
bne IVLoop

End:
pop {r6}
mov r0, r4
bl Recalculate_Stats
pop {r1}
cmp r1, #0
bne return_2
ldr r1, .Return_Addr_1
bx r1

return_2:
ldr r1, .Return_Addr_2
bx r1

Insert_Element:
ldr r3, .Insert_Addr
bx r3

Recalculate_Stats:
ldr r1, .Recalc_Addr
bx r1

get_value_from_var:
ldr r2, .VarGet
bx r2

Mod:
ldr r3, .Mod_Addr
bx r3

.align 2
.Return_Addr_1: .word 0x08011639 @ item and custom moves
.Return_Addr_2: .word 0x0801166D @ just holding an item
.VarEVs: .word 0x000040XX @ change this
.VarIVs: .word 0x000040XX @ change this
.VarGet: .word 0x0806E569
.Insert_Addr: .word 0x0804037d
.Recalc_Addr: .word 0x0803e47d
.Mod_Addr: .word 0x081e4685




EDIT: new and improved! only needs you to check the custom item instead of going all in on the moveset too

Bela September 20th, 2020 8:40 PM

Quote:

Originally Posted by kleenexfeu (Post 8806372)
Well done on that KDS !

<snip>

Bonus:
-Life Orb boost
-Light ball updated
-Item that boost a certain type of attack for Emerald
-Timespace Orbs for Emerald

Note that for timespace orbs and new boost-type item, you can adjust the power added the same way than miracle seed and the like.

Spoiler:

Emerald:
Code:

CheckLifeOrb:
cmp r2, #0x43        /*Held item effect of life orb, I chose 0x43 (= 67 in decimal) because it's unused*/
beq Lifeorb

CheckNewItem:
cmp r2, #0x44        /*Held item effect of the boost item, I chose 0x44 (= 68 in decimal) because it's unused*/
beq NewItem

CheckAdamantOrb:
cmp r2, #0x45        /*Unused held item effect*/
bne CheckLustreous
ldrh r0, [r6]
mov r3, #0xFF        /*0xFF + 0xE4 = 0x1E3 = 483 = index number of Dialga*/
add r3, #0xE4
cmp r0, r3
beq AdamantOrb

CheckLustreous:
cmp r2, #0x46        /*Unused held item effect*/
bne CheckGriseous
ldrh r0, [r6]
mov r3, #0xFF        /*0xFF + 0xE5 = 0x1E4 = 484 = index number of Palkia*/
add r3, #0xE5
cmp r0, r3
beq LustreousOrb

CheckGriseous:
cmp r2, #0x47        /*Unused held item effect*/
bne CheckLightBall
ldrh r0, [r6]
mov r3, #0xFF        /*0xFF + 0xE8 = 0x1E7 = 487 = index number of Giratina*/
add r3, #0xE8
cmp r0, r3
beq GriseousOrb
b Back

AdamantOrb:
push {r0-r5}
mov r1, #8        /*Steel type*/
mov r2, #0x10        /*Dragon type*/
b CheckExceptionTypeAttack

LustreousOrb:
push {r0-r5}
mov r1, #0xB        /*Water type*/
mov r2, #0x10        /*Dragon type*/
b CheckExceptionTypeAttack

GriseousOrb:
push {r0-r5}
mov r1, #7        /*Ghost type*/
mov r2, #0x10        /*Dragon type*/
b CheckExceptionTypeAttack

NewItem:
push {r0-r5}
mov r1, #9        /*New type you want to boost*/
mov r2, #9        /*New type you want to boost, here I choose the same because I want it boost only one type*/

CheckExceptionTypeAttack:
ldr r4, CheckTypeLoc
ldr r4, [r4]
ldrb r4, [r4, #0x13]
cmp r4, #0
beq GetMoveType
mov r5, #0x3F
and r4, r5
cmp r4, r1
beq Boost
cmp r4, r2
beq Boost
b PopAndBack

Back:
ldr r0, Return
bx r0

PopAndBack:
pop {r0-r5}
b Back

CheckLightBall:
cmp r2, #0x2D
bne Back
ldrh r0, [r6]
cmp r0, #0x19
beq Lightball
b Back

GetMoveType:
ldr r3, CurMoveIndex
ldrh r3, [r3]
ldr r4, MoveData
mov r5, #0xC
mul r5, r3
add r4, r5
ldrb r4, [r4, #2]
cmp r4, r1
beq Boost
cmp r4, r2
bne PopAndBack

Boost:
pop {r0-r5}
ldrh r3, [r6, #0x2E]
lsl r0, r3, #4
push {r1}
mov r1, #6
mul r3, r1
pop {r1}
add r3, r0
lsl r3, #1
ldr r0, LocItems
add r3, r0
add r3, #0x13
ldrb r0, [r3]
mov r3, #0x52
mul r0, r3
lsr r0, #6
add r0, #0x7B
mul r7, r0
lsr r7, #7
mov r3, r8
mul r3, r0
lsr r3, #7
mov r8, r3
b Back

Lifeorb:
mov r0, r8
mov r3, #0xA7
mul r0, r3
lsr r0, #7
mov r8, r0
mul r7, r3
lsr r7, #7
b Back

Lightball:
mov r0, r8
lsl r0, r0, #0x1
mov r8, r0
lsl r7, r7, #0x1
b Back

.align 2
Return: .word 0x0806983E+1
LocItems: .word 0x085839A0          /*Location of your items Data*/
CurMoveIndex: .word 0x020241EA
MoveData: .word 0x0831C898          /*Location of your move data*/
CheckTypeLoc: .word 0x0202449C

/*00 48 00 47 XX XX XX 08 00 00 00 at 0x6982C*/


Fire Red:
Code:

cmp r2, #0x43  /*Held item effect, I chose 0x43 (=67 in dec) because it is unused in the game*/
beq Lifeorb
cmp r2, #0x2D
bne Back
ldrh r0, [r6]
cmp r0, #0x19
beq Lightball
b Back

Lifeorb:
mov r0, r8
mov r3, #0xA7
mul r0, r3
lsr r0, #7
mov r8, r0
mul r7, r3
lsr r7, #7
b Back

Lightball:
mov r0, r8
lsl r0, r0, #0x1
mov r8, r0
lsl r7, r7, #0x1

Back:
ldr r0, Return
bx r0

.align 2
Return: .word 0x0803F00A+1

/*00 48 00 47 XX XX XX 08 00 00 00 at 0803EFF8*/



Hey everybody, I know it's been 5 years since this was written and most people have moved on from this form of hacking, but I have a small request. I'm interested in adding the time-space orbs and the Pixie Plate to FireRed. From what I have been able to find on this forum, it looks like kleenexfeu did both for Emerald, but this has never been ported to FireRed.

While I know the CFRU engine exists and likely has these elements, I'm not looking to completely overhaul the game or re-do everything to use that base. I'm also unsure if these could be extracted from CFRU or not. My thinking is that the routines in the quoted post have not been written for FireRed, and a port of them are what I'd need. If someone out there is able to help me with this, please reach out to me on Discord or reply here. Thank you! :)

Super Versekr Dark September 21st, 2020 8:13 AM

Quote:

Originally Posted by BluRose (Post 10209680)
not to double post but

give your opposing trainers evs and ivs based on a var each

https://cdn.discordapp.com/attachments/642222929312088065/757336539675230296/help.gif

this primarily to make difficulty hacks where there can be multiple difficulties

put a value in one var that you want the opponents ivs to be and another value in another var that you want your opponent's evs to be (and yes, all of them will be the same)
the pokemon has to have both a custom moveset and a custom item (at least those check marks ticked in your favorite trainer editor) then all of their values will be set

pastebin right here

credit me and doesntknowhowtoplay
for fire red:
Spoiler:
Code:

# note:  mon has to hold both an item and have a custom moveset
# pokemon tiene que tener un objeto y tener movimientos definidos

.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 (0x08000001 | 0xXXXXXX)

.org 0x3dc70
b 0x3dcd0

.org 0xXXXXXX # change this and the other above

LoadItem:
add r5, #0x6
add r0, r4, #0x0
mov r1, #0xc
add r2, r5, #0x0
bl Insert_Element

StartEVs:
ldr r0, .VarEVs
bl get_value_from_var
mov r5, #0x1A
push {r0}

LoadEVs:
mov r0, r4
mov r1, r5
mov r2, sp
bl Insert_Element
add r5, #1
cmp r5, #0x1F+1
bne LoadEVs

StartIVs:
pop {r0}
ldr r0, .VarIVs
bl get_value_from_var
mov r5, #0x27
push {r0}

IVLoop:
mov r0, r4
mov r1, r5
mov r2, sp
bl Insert_Element
add r5, r5, #0x1
cmp r5, #0x2C+1
bne IVLoop

End:
pop {r6}
mov r0, r4
bl Recalculate_Stats
ldr r1, .Return_Addr
bx r1

Insert_Element:
ldr r3, .Insert_Addr
bx r3

Recalculate_Stats:
ldr r1, .Recalc_Addr
bx r1

get_value_from_var:
ldr r2, .VarGet
bx r2

Mod:
ldr r3, .Mod_Addr
bx r3

.align 2
.Return_Addr: .word 0x08011639
.VarEVs: .word 0x000040XX # change this
.VarIVs: .word 0x000040XX # change this
.VarGet: .word 0x0806E569
.Insert_Addr: .word 0x0804037d
.Recalc_Addr: .word 0x0803e47d
.Mod_Addr: .word 0x081e4685



Excuse me, how would the script be done?

BluRose September 21st, 2020 11:15 AM

Quote:

Originally Posted by Super Versekr Dark (Post 10209977)
Excuse me, how would the script be done?

if you want to have a trainer that has its evs and ivs change with difficulty, then you just need to
- make the trainer's pokémon have a custom held item (moveset optional)
- insert the routine
- in any script, set the variables that you chose to the evs and ivs you desire
i recommend using vars from 0x4012-0x40FF, or if you don't want to clean the rom of its scripts then 0x40C0-0x40FF

si quieres un entrenador que tiene evs y ivs que cambian con dificultad, pues necesitas
- hacer que el pokemon del entrenador tiene un objeto (moveset no es necesario)
- insertar la rutina
- en un script, carga las variables que escoges para tener los evs y los ivs a los valores que deseas
recomiendo que uses vars desde 0x4012-0x40FF, o si no quieres borrar la rom de sus scripts 0x40C0-0x40FF

Dr. Seuss September 21st, 2020 11:21 AM

It's been a long time since the main post was updated, so after a few hours I finished to update the index for you to easily find any ASM routine posted in this thread.

If a link is not properly working or I missed a routine feel free to PM me or any mod to add it to the index

BluRose September 25th, 2020 10:32 AM

Quote:

Originally Posted by Bela (Post 10209816)
- snip -

Quote:

Originally Posted by kleenexfeu (Post 8806372)
- snip -
Bonus:
-Life Orb boost
-Light ball updated
-Item that boost a certain type of attack for Emerald
-Timespace Orbs for Emerald

Note that for timespace orbs and new boost-type item, you can adjust the power added the same way than miracle seed and the like.

Spoiler:

Emerald:
Code:

CheckLifeOrb:
cmp r2, #0x43        /*Held item effect of life orb, I chose 0x43 (= 67 in decimal) because it's unused*/
beq Lifeorb

CheckNewItem:
cmp r2, #0x44        /*Held item effect of the boost item, I chose 0x44 (= 68 in decimal) because it's unused*/
beq NewItem

CheckAdamantOrb:
cmp r2, #0x45        /*Unused held item effect*/
bne CheckLustreous
ldrh r0, [r6]
mov r3, #0xFF        /*0xFF + 0xE4 = 0x1E3 = 483 = index number of Dialga*/
add r3, #0xE4
cmp r0, r3
beq AdamantOrb

CheckLustreous:
cmp r2, #0x46        /*Unused held item effect*/
bne CheckGriseous
ldrh r0, [r6]
mov r3, #0xFF        /*0xFF + 0xE5 = 0x1E4 = 484 = index number of Palkia*/
add r3, #0xE5
cmp r0, r3
beq LustreousOrb

CheckGriseous:
cmp r2, #0x47        /*Unused held item effect*/
bne CheckLightBall
ldrh r0, [r6]
mov r3, #0xFF        /*0xFF + 0xE8 = 0x1E7 = 487 = index number of Giratina*/
add r3, #0xE8
cmp r0, r3
beq GriseousOrb
b Back

AdamantOrb:
push {r0-r5}
mov r1, #8        /*Steel type*/
mov r2, #0x10        /*Dragon type*/
b CheckExceptionTypeAttack

LustreousOrb:
push {r0-r5}
mov r1, #0xB        /*Water type*/
mov r2, #0x10        /*Dragon type*/
b CheckExceptionTypeAttack

GriseousOrb:
push {r0-r5}
mov r1, #7        /*Ghost type*/
mov r2, #0x10        /*Dragon type*/
b CheckExceptionTypeAttack

NewItem:
push {r0-r5}
mov r1, #9        /*New type you want to boost*/
mov r2, #9        /*New type you want to boost, here I choose the same because I want it boost only one type*/

CheckExceptionTypeAttack:
ldr r4, CheckTypeLoc
ldr r4, [r4]
ldrb r4, [r4, #0x13]
cmp r4, #0
beq GetMoveType
mov r5, #0x3F
and r4, r5
cmp r4, r1
beq Boost
cmp r4, r2
beq Boost
b PopAndBack

Back:
ldr r0, Return
bx r0

PopAndBack:
pop {r0-r5}
b Back

CheckLightBall:
cmp r2, #0x2D
bne Back
ldrh r0, [r6]
cmp r0, #0x19
beq Lightball
b Back

GetMoveType:
ldr r3, CurMoveIndex
ldrh r3, [r3]
ldr r4, MoveData
mov r5, #0xC
mul r5, r3
add r4, r5
ldrb r4, [r4, #2]
cmp r4, r1
beq Boost
cmp r4, r2
bne PopAndBack

Boost:
pop {r0-r5}
ldrh r3, [r6, #0x2E]
lsl r0, r3, #4
push {r1}
mov r1, #6
mul r3, r1
pop {r1}
add r3, r0
lsl r3, #1
ldr r0, LocItems
add r3, r0
add r3, #0x13
ldrb r0, [r3]
mov r3, #0x52
mul r0, r3
lsr r0, #6
add r0, #0x7B
mul r7, r0
lsr r7, #7
mov r3, r8
mul r3, r0
lsr r3, #7
mov r8, r3
b Back

Lifeorb:
mov r0, r8
mov r3, #0xA7
mul r0, r3
lsr r0, #7
mov r8, r0
mul r7, r3
lsr r7, #7
b Back

Lightball:
mov r0, r8
lsl r0, r0, #0x1
mov r8, r0
lsl r7, r7, #0x1
b Back

.align 2
Return: .word 0x0806983E+1
LocItems: .word 0x085839A0          /*Location of your items Data*/
CurMoveIndex: .word 0x020241EA
MoveData: .word 0x0831C898          /*Location of your move data*/
CheckTypeLoc: .word 0x0202449C

/*00 48 00 47 XX XX XX 08 00 00 00 at 0x6982C*/


Fire Red:
Code:

cmp r2, #0x43  /*Held item effect, I chose 0x43 (=67 in dec) because it is unused in the game*/
beq Lifeorb
cmp r2, #0x2D
bne Back
ldrh r0, [r6]
cmp r0, #0x19
beq Lightball
b Back

Lifeorb:
mov r0, r8
mov r3, #0xA7
mul r0, r3
lsr r0, #7
mov r8, r0
mul r7, r3
lsr r7, #7
b Back

Lightball:
mov r0, r8
lsl r0, r0, #0x1
mov r8, r0
lsl r7, r7, #0x1

Back:
ldr r0, Return
bx r0

.align 2
Return: .word 0x0803F00A+1

/*00 48 00 47 XX XX XX 08 00 00 00 at 0803EFF8*/



life orb, new fairy plate, spacial orbs, and the new soul dew (as of gen 7) all in one routine! based on the quoted routine.

for fire red:
Spoiler:
Code:

.align 2

.thumb
.thumb_func

@ 00 48 00 47 XX XX XX 08 00 00 00 at 0803EFF8
@ also change gItems and gBattleMoves at the bottom of the post

.equ .giratina, 0x1000 @ giratina index
.equ .dialga, 0x1001 @ dialga index
.equ .palkia, 0x1002 @ palkia index
.equ .pikachu, 0x19 @ pikachu index
.equ .latios, 408
.equ .latias, 407

CheckAnyItem:
cmp r2, #0x43  @ boost life orb held effect
beq Lifeorb
cmp r2, #0x44  @ boost fairy type held effect
beq FairyPlate
cmp r2, #0x45  @ adamant orb held effect
beq AdamantOrb
cmp r2, #0x46  @ lustrous orb held effect
beq LustrousOrb
cmp r2, #0x47  @ griseous orb held effect
beq GriseousOrb
cmp r2, #0x48  @ soul dew gen 7 held effect.  can not be the same as the normal soul dew!  it's a new held effect here
beq NewSoulDew
cmp r2, #0x2D  @ light ball held effect
bne Back
ldrh r0, [r6]
cmp r0, #.pikachu
beq Lightball  @ if pikachu then go to lightball
b Back

FairyPlate:
push {r0-r5}
mov r0, #9 @ your fairy type
mov r1, #9 @ your fairy type
b CheckTypeOfAttack

AdamantOrb:
push {r0-r5}
ldrh r0, [r6]
ldr r1, =(.dialga)
cmp r0, r1
bne PopAndBack
mov r0, #8
mov r1, #16
b CheckTypeOfAttack

LustrousOrb:
push {r0-r5}
ldrh r0, [r6]
ldr r1, =(.palkia)
cmp r0, r1
bne PopAndBack
mov r0, #0xB
mov r1, #16
b CheckTypeOfAttack

GriseousOrb:
push {r0-r5}
ldrh r0, [r6]
ldr r1, =(.giratina)
cmp r0, r1
bne PopAndBack
mov r0, #7
mov r1, #16
b CheckTypeOfAttack

NewSoulDew:
push {r0-r5}
ldrh r0, [r6]
ldr r1, =(.latias)
cmp r0, r1
add r1, #1 @ latios = latias + 1
cmp r0, r1
bne PopAndBack
mov r0, #0xE
mov r1, #0x10
@b CheckTypeOfAttack  @ fall through

CheckTypeOfAttack:
ldr r4, gBattleStruct
ldr r4, [r4]
ldrb r4, [r4, #0x13] @ check for the dynamic move type
cmp r4, #0
beq GetMoveType
mov r5, #0x3F
and r4, r5
cmp r4, r1
beq Boost
cmp r4, r2
beq Boost
b PopAndBack

GetMoveType:
ldr r3, gCurrentMove
ldrh r3, [r3]
ldr r4, gBattleMoves
mov r5, #0xC
mul r5, r3
add r4, r5
ldrb r4, [r4, #2]
cmp r4, r1
beq Boost
cmp r4, r2
bne PopAndBack

@ fall through

Boost:
pop {r0-r5}
ldrh r3, [r6, #0x2E]
lsl r0, r3, #4
push {r1}
mov r1, #6
mul r3, r1
pop {r1}
add r3, r0
lsl r3, #1
ldr r0, gItems
add r3, r0
add r3, #0x13
ldrb r0, [r3]
mov r3, #0x52
mul r0, r3
lsr r0, #6
add r0, #0x7B
mul r7, r0
lsr r7, #7
mov r3, r8
mul r3, r0
lsr r3, #7
mov r8, r3
b Back

Lifeorb:
mov r0, r8
mov r3, #0xA7
mul r0, r3
lsr r0, #7
mov r8, r0
mul r7, r3
lsr r7, #7
b Back

Lightball:
mov r0, r8
lsl r0, r0, #0x1
mov r8, r0
lsl r7, r7, #0x1

Back:
ldr r0, Return
bx r0

PopAndBack:
pop {r0-r5}
b Back

.align 2
Return: .word 0x0803F00A | 1
gCurrentMove:  .word 0x02023D4A
gBattleMoves:  .word 0x08250C04 @ change this
gBattleStruct:  .word 0x02023FE8
gItems:  .word 0x083DB028 @ change this


works the same where it's based on the parameter in the item effect structure

EDIT: added species requirements and now it doesn't crash
wholly tested now basically

EDIT: updated it to include gen 7's soul dew updates. note that it can't use the same held effect as the normal soul dew

Super Versekr Dark September 29th, 2020 3:32 AM

Gen 7 Soul Dew Update

link down

Megax Rocker October 10th, 2020 11:29 PM

Is there a way to change the species of an egg generated from the daycare to be random between parents? like instead of the egg always hatching as the mother's species, it has a chance if being the father's as well.

for example, if you breed Nidoking with with Kanghaskhan, the resulting egg has a 50% chance of being a Nidoran, instead of always generating a Kangaskhan egg.

My idea is to have every pokemon be able to hatch from an egg from normal mothers, male only pokemon are stuck with ditto for mothers.

Splinxsh October 19th, 2020 8:49 AM

I don't suppose you could show me the HEX codes or the compiled script on here.

I've followed everything you put and made the Numerator 60 and Denominator on 100 and it only keeps saying that the Pokémon only receives 1 EXP.

Any help please would be great!

Fantaseed October 27th, 2020 11:43 AM

Since the start menu only runs asm offset,

I'd like to request an asm routine that targets and runs any chosen normal script offset for the start menu's selection.

Game: BPRE Fire red

GameBr8ker31 November 4th, 2020 1:00 PM

I would like to request for someone to make a fire red ASM routine that will always write the text string “Super Effective” if the move effectivness returns greater than 1 and “not very effective” if it returns less than 1.

I made changes to my type effectivness table to add better depth to it and now the game no longer prints the text!

Ive been trying to understand ASM for months now and just cant seem to teach myself fully. Someone with amazing skills...Please help!!!

Chesterking69 November 4th, 2020 3:48 PM

Hello.
I'm starting to make a ROM hack (or at least trying to make), and I recently discovered a specific program called TLP which I can edit the sprites.
Just to clarify, my plan is to make a Red or a Gold pokemon hack, with the main objective of maintaining the vintage aesthetic of the first game but with more pokemon beyond those that exist only in the first generation.
These programs were all founded through google, more specificaly in other threads in this forum.
In addition to this program, I am aware of what makes me able to edit the map as a puzzle, but I know that there are still many programs that I need to know and I need to see if I would be able to use it on my computer without problems (many programs that I found through internet had specific problems when I tried to run it, and it certainly has nothing related to problems in my computer, which has a good configuration).
I really want to know if I'm on the right path and if there is things that I need to know before move forward with the project. For now, I'm making the sprites of the story characters. The history that I have in mind is a universe full of life, something that I have several texts telling from different moments besides being something that I share with my friends who help me in the story.
This first ROM hack I plan on will tell only the beginning of the story. If it works, I intend to go to the end. If it goes as planned, I'm sure things will work out.

BluRose November 4th, 2020 6:54 PM

Quote:

Originally Posted by Chesterking69 (Post 10227170)
Hello.
I'm starting to make a ROM hack (or at least trying to make), and I recently discovered a specific program called TLP which I can edit the sprites.
Just to clarify, my plan is to make a Red or a Gold pokemon hack, with the main objective of maintaining the vintage aesthetic of the first game but with more pokemon beyond those that exist only in the first generation.
These programs were all founded through google, more specificaly in other threads in this forum.
In addition to this program, I am aware of what makes me able to edit the map as a puzzle, but I know that there are still many programs that I need to know and I need to see if I would be able to use it on my computer without problems (many programs that I found through internet had specific problems when I tried to run it, and it certainly has nothing related to problems in my computer, which has a good configuration).
I really want to know if I'm on the right path and if there is things that I need to know before move forward with the project. For now, I'm making the sprites of the story characters. The history that I have in mind is a universe full of life, something that I have several texts telling from different moments besides being something that I share with my friends who help me in the story.
This first ROM hack I plan on will tell only the beginning of the story. If it works, I intend to go to the end. If it goes as planned, I'm sure things will work out.

have you run into the pokered/pokecrystal disassemblies?

Lioniac November 5th, 2020 3:50 AM

Hello,

This is a request.

I'm learning XSE and trying to create a method to replace tileset dynamically for a map, but I cannot find the right script commands. I guess I'll have to go to ASM. Is it right? If so, it's a long learning curve LOL
Use case explained: I want to use RNG Weather + Battle weather that mimics OW weather + dynamic change OW tiles to snow ones when it's snowing.

- First I tried to create custom tileset, set it in the cities maps (A-Map) and using a script to change every tile using setmaptile... super impractical and waste of resource consumption... super ugly approach.
- Then, I realized the tile positions (X,Y) are static, so creating a "snow tileset" version with tiles in the same position of the original would be much more efficient. I just need a way to dynamic change the tileset when it's snowing.

That would be also useful if you want to generate events that dynamically change the map in general (e.g A HUGE Earthquake), so I believe this request could open many possibilities.

Example:


Thanks in advance.

PS: Yeah, I know about Seasons by DNS tool but I could not find the source code or anything to edit. The tool does not allow you to freely edit the months... e.g. I live in Brazil and December is Summer, not Winter... if anyone has a Github/source code on that, it should work as well.

Kertra November 10th, 2020 7:26 AM

Quote:

Originally Posted by FBI (Post 8877758)

Frontier Routines - Opponent Party generation



I've been meaning to implement a frontier of sorts into FireRed for some time but never really got a good opportunity to do so. Today I got a little bored and decided that I might as well start up. The first problem is obviously to generate a pseudo random party for the opposing trainer. That's what I've done today!

I had made a generation routine in the past as well, but it was incomplete and a little buggy. This one, as far as I can tell in my tests, should work fine :)


Setting up some prerequisites:
When making the routine for Pokemon generation, it was important that the hacker had some customization about which Pokemon were allowed into the opponents party (to prevent legendary Pokemon, or some specific Pokemon into the competition). The best way to do that is to either make a table of the Pokemon allowed to be in the opponent's party, or a table of the Pokemon not allowed to be in it. I decided to make the hacker do a table of all the Pokemon species allowed to be in the opponent's party.

It's important to remember that Pokemon Species ID takes 2 bytes per species, and that each entry in the table is in reverse hex. Bulbasaur for example would be: "01 00" in the table. The size of the table is up to you. The biggest reason I made the table be a table of all the Pokemon allowed is because this allows you to put more than 1 entry of the same Pokemon (thus increasing it's likelihood to be selected) ==> not all Pokemon species have the same chance of being selected!

Find some half-word aligned free space (offset divisible by 2) and fill up your table with as many entries as you'd like in this format:
Code:

[2 bytes (ID)] [2 bytes (ID)] ...


Write down how many entries you have, and where the start of the table is.


How to insert:

First take a look at the routine in the spoiler. Scroll to the very bottom, and you will see two fields which need filling. The first is called "Table". Table is supposed to be a location to the table of IDs we made earlier, replace 0x8750000 with your table location. Tsize is supposed to be the amount of Pokemon your table has in it, adjust that accordingly as well.

Finally, the routine is flag toggled. If flag 0x205 is set, the opponent is generated a random party. To adjust this change these lines accordingly:
Code:

        mov r0, #0xFF
        lsl r0, r0, #0x1 @0xFF * 2
        add r0, r0, #0x7 @ 0x1FE + 7


Once the adjustments are complete, compile and insert into free space.
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

@Hook 080112F8 via r0

main:
        push {r0-r7}
        @flag check 205
        mov r0, #0xFF
        lsl r0, r0, #0x1
        add r0, r0, #0x7
        ldr r4, =(0x806E6D0 +1)
        bl linker
        cmp r0, #0x0
        beq end

genAmount:
        ldr r4, =(0x8044EC8 +1)@gen random number
        bl linker
        lsl r0, r0, #0x10
        lsr r0, r0, #0x10
        mov r1, #0x6
        ldr r4, =(0x81E4684 +1)
        bl linker
        add r0, r0, #0x1
        mov r5, r0

mallocSpace:
        mov r0, #0x64
        mul r0, r0, r5
        ldr r4, =(0x8002BB0 +1) @malloc
        bl linker
        mov r6, r0
        mov r7, #0x0

@R5 = amount of mons
@R6 = free space to put them

genLoop:
        cmp r7, r5
        beq moveParty

genSpeciesFromTable:
        ldr r4, =(0x8044EC8 +1)@gen random number
        bl linker
        lsl r0, r0, #0x10
        lsr r0, r0, #0x10
        ldr r1, Tsize
        ldr r4, =(0x81E4684 +1)
        bl linker
        lsl r0, r0, #0x1
        ldr r1, Table
        add r1, r1, r0
        ldrh r1, [r1]

createMon:
        mov r0, #0x64
        mul r0, r0, r7
        add r0, r0, r6 @free memory
        ldr r2, =(0x20370BA)
        mov r2, #0x32 @level
        mov r3, #0x20 @cnst
        ldr r4, =(0x803DA54 +1)
        bl linker
        add r7, r7, #0x1
        b genLoop

moveParty:
        ldr r0, =(0x202402C)
        mov r1, r6
        mov r2, #0x64
        mul r2, r2, r5
        ldr r4, =(0x8040B08 +1) @func
        bl linker
        mov r0, r6
        ldr r4, =(0x8002BC4 +1) @free malloc'd memory
        bl linker
        pop {r0-r7}
        ldr r3, =(0x80116AC +1)
        bx r3

end:
        pop {r0-r7}
        ldr r0, =(0x400)
        cmp r1, r0
        bne place
        mov r0, #0x0
        ldr r3, =(0x80116AC +1)
        bx r3

place:
        ldr r3, =(0x8011304 +1)
        bx r3

linker:
        bx r4

.align 2

Table:
        .word 0x8750000 @your table of Mons

Tsize:
        .word 0x32 @Amount of entries in table




Finally, in a hex editor insert the following byte changes at 0x112F8:
Code:

00 48 00 47 XX XX XX 08


Where XX XX XX is the place you inserted the routine +1. Note that the trailing 08 may change depending on where you placed the routine.


Usage:

The routine is flag toggled. Set flag 0x205 before entering battle, and the rest is done automatically.

I wonder how to use this code for double battles ...

Angelkof14 November 15th, 2020 5:55 PM

Quote:

Originally Posted by DoesntKnowHowToPlay (Post 8538908)
Either turn set mode on in the options, or put 28 92 87 1D 08 at x1D8727. Be warned that the latter approach has a nasty side effect; scrubs will complain about your hack being "bugged" or that you removed a feature that should've stayed.

Do you know How to do that in emerald?

jirachiwishmaker November 15th, 2020 8:47 PM

Quote:

Originally Posted by Angelkof14 (Post 10231317)
Do you know How to do that in emerald?

Put 28 D0 A8 2D 08 at 0x2DA865.

Mxtrainer87 December 24th, 2020 6:32 AM

Quote:

Originally Posted by FBI (Post 8620314)

Changing the Player's Overworld ingame



Intro:

I recently made this routine, it's kind of limited in the sense that you can only be change to 30 different overworlds (excluding the special version of the default characters). While it is limited, I don't really think that that's a problem (you'd probably only be OWs swapping to 2-3 different OWs the entire game anyways, so unless you wanted to player to play as more than 30 characters, this routine will work just fine for you). It's also a little "smaller" in comparison to JPAN's 6 seperate routines which he used (though in his favor, I don't think his limits the amount like mine). I blame the table, it's weird. Actually the whole overworld loading thing is weird..it's done in like 9 places lol.

I should also note that if the OW you're changing to doesn't have a running frame, things are going to look weird when you try to run~

How to insert:

Compile into free space the following routine:
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

@hook from 0805CA4C via r0

main:
        @flag check
checkFlag:
        mov r0, #0xFF
        lsl r0, r0, #0x2
        add r0, r0, #0xA @0x3FC + 0xA = @406
        ldr r2, =(0x806E6D0 +1)
        push {r1, r3}
        bl linker
        pop {r1, r3}
        cmp r0, #0x1
        bne noCrash

setOW:
        ldr r0, =(0x20370B8)
        ldrb r0, [r0]
        cmp r0, #0xFF
        beq noCrash
        mov r3, r0

noCrash:
        mov r8, r3
        lsl r4, r4, #0x10
        lsr r4, r4, #0x10
        lsl r5, r5, #0x10
        ldr r0, =(0x805CA54 +1)
        bx r0

linker:
        bx r2

.align 2


Here's a compiled version:
Code:

FF 20 80 00 0A 30 09 4A 0A B4 00 F0 0E F8 0A BC 01 28 04 D1 06 48 00 78 FF 28 00 D0 03 1C 98 46 24 04 24 0C 2D 04 03 48 00 47 10 47 D1 E6 06 08 B8 70 03 02 55 CA 05 08




Now navigate to 0x5CA4C and insert the following byte changes:
Code:

00 48 00 47 XX XX XX 08


Where XX XX XX is where you inserted this routine +1.


Usage:

The routine requires two conditions to toggle.
1) Flag 0x406 is set
2) Var 0x8000 is not 0xFF

As you may have guessed you need to set variable 0x8000 to a value which matches the overworld you want the player to transform into. Please note that for the effect to happen, you need to warp first.
Here's a list of values and their corresponding sprite to the left:
Spoiler:

Code:

0 - male hero
1 - female hero
3 - female hero bike
4 - male hero run
5 - female hero run
6 - male hero vs-seeker
7 - female hero vs-seeker
8 - male hero fishing
9 - female hero fishing
12 - Brendon
13 - May
26 - Male + Female hero Vs seeker on bike
28 - Random guy (A-MAP ID 25)
29 - Little boy
44 - Gem sign thing (buggy)
48 - Spearow
52 - Old man 1 (A-MAP ID 33)
80 - Jogging girl
83 - Blonde dude (A-MAP ID 26)
84 - Fat guy
88 - Old man 2 (A-MAP ID 88)
92 - Scroll backpack thing (buggy)
93 - Team rocket male
104 - Meowth
112 - Chansey
116 - Slowbro
124 - Snorlax
125 - Fisherman
166 - Kid tuber (male)
170 - Old man 3 (A-MAP ID 30)
176 - Green girl (A-MAP ID 40)
213 - Red dress lady
214 - Old lady
228 - Deoxys (I think this one is normal)
245 - Misty
250 - Hey champ in the making guy
251 - Ghost Girl



While no particular value will cause a crash, I've excluded values which are "repeated" OWs. If you experience bugs, use it in conjunction with the backsprite hack I made. If you still have bugs, report them here!

Anyone out there that can help me with this? I want my temp sprite at the beginning of the game to disappear right after the first battle with Gary in Oaks lab

Mason Shu December 25th, 2020 9:49 PM

Quote:

Originally Posted by Mxtrainer87 (Post 10250409)
Anyone out there that can help me with this? I want my temp sprite at the beginning of the game to disappear right after the first battle with Gary in Oaks lab

Assemble the routine. The open your rom in your hex editor and paste the contents of the .bin into your rom, overwriting enough FF bytes, and make sure the offset ends in 0, 4, 8, or C. Then Copy the offset and add 1 to it. Then reverse it: Example:
Let's say the offset is 800000:
800000+1=800001: 01 00 80
Or if the number of digits is odd:
5673C+1=5673D=05673D: 3D 67 05
Then overwrite bytes at 5CA4C
00 48 00 47 [reverse hex pointer] 08
Then make the script

BluRose December 28th, 2020 7:13 PM

Quote:

Originally Posted by DoesntKnowHowToPlay (Post 9043968)
I've noticed significant demand for working Dawn Stone evolutions, specifically ones that require the mon to be a specific gender. My bad if this is already posted somewhere but here y'all go:

Code:

.org 0x4318e
lsl r0, r0, #0x0
ldr r2, .MethodAddr
bx r2

.MethodAddr: .word 0x085B2521 #UPDATE THIS TO MAIN FUNCTION OFFSET+1

.org 0x5B2520 #UPDATE THIS TO MOST CONVENIENT FREE SPACE IN YOUR HACK
cmp r0, #0x7
beq StandardStone
cmp r0, #0x14 #UPDATE THIS
beq MaleStone
cmp r0, #0x15 #UPDATE THIS
beq FemaleStone
b NoEvo

MaleStone:
push {r1-r3}
mov r0, r7
mov r1, r8
ldr r1, [r1, #0x0]
bl DetermineGender
pop {r1-r3}
cmp r0, #0x0
beq StandardStone
b NoEvo

FemaleStone:
push {r1-r3}
mov r0, r7
mov r1, r8
ldr r1, [r1, #0x0]
bl DetermineGender
pop {r1-r3}
cmp r0, #0xFE
beq StandardStone
b NoEvo

StandardStone:
ldrh r0, [r1, #0x2]
cmp r0, r9
beq Finish

NoEvo:
ldr r2, .NoEvoReturn
bx r2

DetermineGender:
ldr r2, .DetermineGenderFunc
bx r2

Finish:
ldr r2, .EvoReturn
bx r2

.NoEvoReturn: .word 0x08043199
.EvoReturn: .word 0x0804317d
.DetermineGenderFunc: .word 0x0803f78d


Change the values in the lines marked UPDATE THIS to the indexes of male stone evos and female stone evos. Leave their entries blank in the general evolution table; stone evolutions function differently from level-up evolutions.

this is 5 years old, but don't leave the entries blank in the general evolution table: it misbehaves when interacting with other evolutions.
if my kirlia has a level-up evolution method and a gendered stone evolution method, then when leveling up the game will crash. adding the pointers for the stone evolution in the gendered stone entries will fix the crash. in effect, write 26 30 04 08 in those entries.

FireFig January 7th, 2021 11:58 PM

Request for FIRERED:

An asm routine that gets into the Item storage in PC directly without opening any kind of menu first if (you get the gist ryt?) through calling the asm in a script.

It would be useful in many ways. Thanks :)

AkameTheBulbasaur January 11th, 2021 10:44 PM

Summary Screen Wrap-Around


First of all, I would like to thank Zeturic for creating the original routine for this. My routine is different from theirs, and I have extended it a bit, which is why I am posting this here.

Anyway, this patch modifies the summary screens in both the Party Menu and in the PC so that if you are on the first Pokemon and you go upwards, you will loop around to the last Pokemon (and vice versa). Ordinarily, in this circumstance, nothing would happen.

(Download)

This folder contains the patch itself, and the two routines that comprise it. There were two functions which were replaced, and both of the new functions were shorter than the originals (hence why this could be turned into a patch).

This patch will skip over Eggs when scrolling while in the Party or PC, but if you want to see the Egg's summary (to see how long it will take to hatch), you can select their summary individually.

/JASHIN/ January 29th, 2021 8:39 PM

Quote:

Originally Posted by MrDollSteak (Post 8530762)
Toggle Run Away

It can work with Toggle Capture very well, or completely independently.
If you use the same Variable as Toggle Capture, if the value is set to 0x1,
a Pokemon will be uncapturable, and you will be unable to Run Away from it.
If the value is 0x0, the game is as normal. If the value is anything else,
you cannot Run Away from the Pokemon BUT you can catch it.

However if you use a completely different variable you will be able to
run away, but not to catch the Pokemon, though to me this is pointless,
because if you have an uncatchable Pokemon, why would you be able to
Run Away from it?

Anyway here is the routine!

Fire Red


Spoiler:
Code:

.text
.align 2
.thumb
.thumb_func
.global ToggleRunAawayFR

Main:
        ldr r0, .Variable
        ldrb r0, [r0]
        cmp r0, #0x0
        bne CannotRun
Return:
        ldr r1, =(0x2023BE2)
        ldr r0, =(0x2023BCC)
        ldrb r0, [r0]
        strb r0, [r1]
        ldr r1, =(0x2023E8A)
        ldr r0, = (0x8016888 +1)
        bx r0
CannotRun:
        mov r6, #0x0
        ldr r0, = (0x801688C +1)
        bx r0

.align 2
.Variable:
        .word 0x020270B8 + (0x8000 * 2) @change to var of your choice if you want


Insert 01 48 00 47 00 00 xx xx xx 08 at 0801687E.


Once I finish porting other abilities I'll make a brand new post for the
Emerald version of this.

I'm probably very late to the party with this one, but I've run into an issue, where whenever the player obtains any items, be it a gift from a trainer, or a hidden item on the ground, the game locks running away. I have no code that sets it, but it instead auto sets and won't be dismissed until the var 0x8000 is set back to 0 via an event. Any one else face this problem and if so what was your solution? I know var 8000 is used quite a bit as a temporary var behind the scenes, so i was wondering if there was a safer one? I've tried using regular vars, but it seems as though it needs to be one of the temp ones specifically?

Edit: I fixed the issue by changing the var to 0x8003, for some reason 8001 and 8002 were insufficient, as obtaining an item from an NPC would still trigger the lock. Now what I'm wondering/ am worried about is whether or not the game is going to trigger this var behind the scenes like it did with the others, if so are there any temporary vars that go completely unused? Thanks :)

Paperfairy February 1st, 2021 9:09 PM

Quote:

Originally Posted by FBI (Post 8521318)
Here are the byte changes he wants you to do inorder to achieve an intro skip similar to Pokemon Rose (which you guys should all checkout, Bela's it's quite an awesome project).

So this works perfectly for removing the blue screen intro and the Oak intro. I am trying to retain the blue screen intro, but remove the Oak intro (I'll handle setting the player name with a custom routine later).

I tried editing this line by line to check and see what works, but didn't have any success or changes aside from noticing a binary change. Could somebody please point me in the right direction?

Dreamaker March 20th, 2021 10:03 AM

Quote:

Originally Posted by AkameTheBulbasaur (Post 9991240)
So because I have a life, I spent way too long yesterday writing a routine to change the measurements for the height and weight in the PokeDex to be in metric (for those who eschew the imperial system).

EDIT: I neglected to have this change the units for SEEN entries as well as CAUGHT entries. I fixed that now.


Height (Feet to Metres - (Uncaught Pokemon)):
Spoiler:
/* Assemble this at 0x1059D0 */
.text
.align 2
.thumb
.thumb_func

Main:
add r0, r13, #0xC
mov r1, #0xAC /* ? */
strb r1, [r0]
add r0, r0, #0x1
mov r1, #0xAC /* ? */
strb r1, [r0]
add r0, r0, #0x1
mov r1, #0x0 /* */
strb r1, [r0]
add r0, r0, #0x1
mov r1, #0xE1 /* m */
strb r1, [r0]
add r0, r0, #0x1
mov r1, #0xFF /* FF */
strb r1, [r0]
mov r0, r0
ldr r0, .Return
bx r0

.align 2
.Return: .word 0x081059FF


Height (Feet to Metres):
Spoiler:
/*00 48 00 47 XX XX XX 08 at 0x105924*/
.text
.align 2
.thumb
.thumb_func

/*r4 has the height number*/



Main:
mov r1, #0xB

Clear:
mov r2, r13
add r2, r2, r1
mov r0, #0x0
strb r0, [r2]
cmp r1, #0x10
beq Next
add r1, r1, #0x1
b Clear

Next:
mov r0, r4
cmp r4, #0xA
blt OneDigit
cmp r4, #0x64
blt TwoDigit

ThreeDigit:
mov r1, #0x64
bl Divide
mov r6, r0
mov r2, r13
add r2, r2, #0xC
mov r0, r6
add r0, r0, #0xA1
strb r0, [r2]
mul r1, r6
sub r0, r4, r1
mov r4, r0

TwoDigit:
mov r1, #0xA
bl Divide
mov r5, r0
mov r2, r13
add r2, r2, #0xD
mov r0, r5
add r0, r0, #0xA1
strb r0, [r2]
mul r1, r5
sub r0, r4, r1
mov r4, r0

OneDigit:
mov r2, r13
add r2, r2, #0xF
mov r0, r4
add r0, r0, #0xA1
strb r0, [r2]

PutTextIn:
mov r2, r13
add r2, r2, #0xE
mov r0, #0xAD
strb r0, [r2]
add r2, r2, #0x2
mov r0, #0x00
strb r0, [r2]
add r2, r2, #0x1
mov r0, #0xE1
strb r0, [r2]
add r2, r2, #0x1
mov r0, #0xFF
strb r0, [r2]
ldr r1, .Return
bx r1

Divide:
ldr r2, .Divide
bx r2

.align 2
.Return: .word 0x081059FF
.Divide: .word 0x081E4019


Weight (Pounds to Kilograms):
Spoiler:
/* 00 48 00 47 XX XX XX 08 at 0x105A94 */
/* Put AC 00 DF DB at 0x415FA0 */
.text
.align 2
.thumb
.thumb_func

/* r4 has the weight number */

Main:
mov r1, #0xB

Clear:
mov r2, r13
add r2, r2, r1
mov r0, #0x0
strb r0, [r2]
cmp r1, #0x10
beq Next
add r1, r1, #0x1
b Clear

Next:
mov r0, r4
cmp r4, #0xA
blt OneDigit
cmp r4, #0x64
blt TwoDigit
ldr r1, .Thousand
cmp r4, r1
blt ThreeDigit

FourDigit:
ldr r1, .Thousand
bl Divide
mov r6, r0
mov r2, r13
add r2, r2, #0xB
mov r0, r6
add r0, r0, #0xA1
strb r0, [r2]
ldr r1, .Thousand
mul r1, r6
sub r0, r4, r1
mov r4, r0

ThreeDigit:
mov r1, #0x64
bl Divide
mov r6, r0
mov r2, r13
add r2, r2, #0xC
mov r0, r6
add r0, r0, #0xA1
strb r0, [r2]
mov r1, #0x64
mul r1, r6
sub r0, r4, r1
mov r4, r0

TwoDigit:
mov r1, #0xA
bl Divide
mov r5, r0
mov r2, r13
add r2, r2, #0xD
mov r0, r5
add r0, r0, #0xA1
strb r0, [r2]
mov r1, #0xA
mul r1, r5
sub r0, r4, r1
mov r4, r0

OneDigit:
mov r2, r13
add r2, r2, #0xF
mov r0, r4
add r0, r0, #0xA1
strb r0, [r2]

PutTextIn:
mov r2, r13
add r2, r2, #0xE
mov r0, #0xAD
strb r0, [r2]
add r2, r2, #0x2
mov r0, #0x00
strb r0, [r2]
add r2, r2, #0x1
mov r0, #0xDF
strb r0, [r2]
add r2, r2, #0x1
mov r0, #0xDB
strb r0, [r2]
add r2, r2, #0x1
mov r0, #0x00
strb r0, [r2]
add r2, r2, #0x1
mov r0, #0xFF
strb r0, [r2]
ldr r1, .Return
bx r1

Divide:
ldr r2, .Divide
bx r2

.align 2
.Return: .word 0x08105BE7
.Divide: .word 0x081E4019
.Thousand: .word 0x000003E8


https://i.imgur.com/FKayVct.png
https://i.imgur.com/9QvzU7S.png

Manekimoney April 6th, 2021 1:57 PM

Quote:

Party Stat Checker



I promised someone that I'd post this once I found it. Well, I found it :P

How to insert:
Compile the following routine into free space:

Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r0-r6, lr}
        ldr r6, =(0x2024029)
        ldrb r6, [r6]
        mov r5, #0x0

PokeLoop:
        cmp r6, r5
        beq none
        mov r0, #0x64
        mul r0, r0, r5
        mov r1, r0
        ldr r0, =(0x2024284)
        add r0, r0, r1
        ldr r1, .INDEX
        ldrb r1, [r1]
        ldr r2, =(0x803FBE8 +1)
        bl linker
        ldr r3, .ARG
        ldrb r3, [r3]
        cmp r0, r3
        bge PokeMatch

next:
        add r5, r5, #0x1
        b PokeLoop

PokeMatch:
        ldr r3, .ARG
        strb r5, [r3]
        pop {r0-r6, pc}

none:
        ldr r3, .ARG
        mov r5, #0x6
        strb r5, [r3]
        pop {r0-r6, pc}

linker:
        bx r2

.align 2

.ARG:
        .word 0x020270B8 + (0x8000 *2)

.INDEX:
        .word 0x020270B8 + (0x8001 *2)


Here's a compiled version:
Code:

7F B5 10 4E 36 78 00 25 AE 42 12 D0 64 20 68 43 01 1C 0D 48 40 18 0A 49 09 78 0C 4A 00 F0 0D F8 06 4B 1B 78 98 42 01 DA 01 35 ED E7 03 4B 1D 70 7F BD 02 4B 06 25 1D 70 7F BD 10 47 B8 70 03 02 BA 70 03 02 29 40 02 02 84 42 02 02 E9 FB 03 08




Usage:
setvar 0x8001 0x[stat you want to retreive]
setvar 0x8000 0x[value you want stat to match]
callasm 0x[routine +1]

The return value will be stored in var 0x8000

Here's a brief list of useful stats you may be interested in checking:
Spoiler:

Code:

0x0B - Species
0x0C - Held Item
0x0D - Attack 1
0x0E - Attack 2
0x0F - Attack 3
0x10 - Attack 4
0x11 - PP 1
0x12 - PP 2
0x13 - PP 3
0x14 - PP 4
0x37 - Status Ailment
0x38 - Level
0x39 - Current HP
0x3A - Total HP
0x3B - Attack
0x3C - Defence
0x3D - Speed
0x3E - Sp. Attack
0x3F - Sp. Defence



This routine is odd. It's supposed to use 8001 to see which stat you want, then searches your entire team for a pokemon that has that stat equal to 8000 and then saves the first party slot number that matches that in 8000 (or outputs number 6 if none).

But the problem is that it thinks that the pokemon is valid, as long as it has the stat HIGHER or equal to what you use. For stuff like levels, atk, def etc. this has a use. But when searching stuff like species, items, attack or status ailments it completely falls apart (unless you want to check how deep down the pokedex a party member is? lol)

Anyway, my ASM knowledge is probably negative, but for searching these I think that "bge PokeMatch" would need to be changed to "beq PokeMatch", if you want to match the stats you search (correct me if I'm wrong) and in a cavemanish way, have two of these inserted and using one when you need higher than and the other one for matching the stat.

Honestly, it took me a while to figure out how the function is even supposed to work, since it's not very clearly explained.
This one caused me quite a headache, so hopefully this helps some poor lad out.

Manekimoney April 8th, 2021 4:48 AM

Quote:

Originally Posted by AkameTheBulbasaur (Post 10174606)
Nature Changing
Before I begin, I should mention that this only works for FireRed at the moment. This is because it uses the Lustre stat, which in FireRed is unused but in Emerald is not. If you can find another stat to use, (or you don't have contests in your Emerald hack), then you can use this.

Offsets listed here are for FireRed, though, so keep that in mind if you decide to port it.

Anyway, without further ado, I present Nature Changing!

How Does It Work?
Skip this if you don't care about the behind the scenes stuff.

Basically, this hijacks the GetNature function. It first checks the Lustre stat of the Pokemon in question. If it's equal to zero, then it gets the Nature form the PID as usual. If it's not zero, then it uses the Lustre value as the Nature, effectively changing the Pokemon's Nature without messing with the PID (and potentially messing up other stuff like the Pokemon's gender, Shininess, etc.).

This does mean you can't set the Nature to Hardy, but this is not that big of a deal since there are other neutral Natures you can use.

The Main Event
I have written an instruction manual that explains how to use the hack in detail. It also contains links to download everything.

The link presented below is the link to download the folder with the Instruction Manual and all the routines. Not every routine in the folder is one you need to insert, as there are a couple of optional add-ons to make changed Natures compatible with other hacks.

Download: Here!

Would it be possible to use a similar system to this one to change Pokemon IVs? I'm guessing it's not as simple as using 0x8005 to change IVs directly, but perhaps it would be possible to use other useless stats (like Lustre), to change IVs of pre-existing pokemon?

AkameTheBulbasaur April 14th, 2021 1:27 PM

Quote:

Originally Posted by Manekimoney (Post 10332814)
Would it be possible to use a similar system to this one to change Pokemon IVs? I'm guessing it's not as simple as using 0x8005 to change IVs directly, but perhaps it would be possible to use other useless stats (like Lustre), to change IVs of pre-existing pokemon?

You can use the Decrypt Function used in the Nature Changing Routine to change the IVs. Each IV is controlled individually, so if you use the right index number in the Decrypt Function, then you can edit the IVs.

The IVs are:
HP = 0x27
Attack = 0x28
Defence = 0x29
Speed = 0x2A
Sp. Attack = 0x2B
Sp. Defence = 0x2C

So, it actually is as simple as using 0x8005 to modify the IVs directly.

JK0JK April 24th, 2021 3:52 AM

Quote:

Originally Posted by FBI (Post 8620314)
Spoiler:

Code:

0 - male hero
1 - female hero
3 - female hero bike
4 - male hero run
5 - female hero run
6 - male hero vs-seeker
7 - female hero vs-seeker
8 - male hero fishing
9 - female hero fishing
12 - Brendon
13 - May
26 - Male + Female hero Vs seeker on bike
28 - Random guy (A-MAP ID 25)
29 - Little boy
44 - Gem sign thing (buggy)
48 - Spearow
52 - Old man 1 (A-MAP ID 33)
80 - Jogging girl
83 - Blonde dude (A-MAP ID 26)
84 - Fat guy
88 - Old man 2 (A-MAP ID 88)
92 - Scroll backpack thing (buggy)
93 - Team rocket male
104 - Meowth
112 - Chansey
116 - Slowbro
124 - Snorlax
125 - Fisherman
166 - Kid tuber (male)
170 - Old man 3 (A-MAP ID 30)
176 - Green girl (A-MAP ID 40)
213 - Red dress lady
214 - Old lady
228 - Deoxys (I think this one is normal)
245 - Misty
250 - Hey champ in the making guy
251 - Ghost Girl



While no particular value will cause a crash, I've excluded values which are "repeated" OWs. If you experience bugs, use it in conjunction with the backsprite hack I made. If you still have bugs, report them here!

How would I go about cloning to the Male Hero Bike sprite without using a bike or having it be the Female Hero Bike sprite?
Also, what do you mean by "repeated" OWs?

Any more clonable sprites are always helpful, especially in the rom hack I'm making.

JK0JK April 26th, 2021 4:33 AM

Trying to make it work. Got a few questions, though...
  1. 0x5CA4C already has things on it. Should I worry about overriting the already existing data? What does the data already in do and what did you change?
  2. What does flag 0x406 do? It's also not free space but what other scripts use it?
  3. Variable 0x8000 is also not free space by default. What does it do normally?
  4. Variable 0x8000 needs to be set to a number. Should we convert that number to bytes or does the game do that automatically?

Sorry for the noob questions, this is my first experience with Rom Hacking.

clinton6886 April 28th, 2021 10:50 PM

Quote:

Originally Posted by FBI (Post 8525633)
You would use the party checker routine to check if Mewtwo is holding the item. Then, depending on the return you would call silent evolution. It's just simply combining two routines I've already done.


Thanks.

Get Pokemon Type



Recently, someone commented on the limitations of my special 0x12b edit. Honestly speaking it is very limited, and only really has a use for checking if you have a certain type of Pokemon. If you had multiple pokemon of the same type it would only return the first one..ect.ect. Well I decided to customize it a little more. It's less powerful now, but more useful (hopefully). All it does is return the type of a Pokemon in a certain slot.

How to insert:

Compile and insert into free space the following routine:
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r0-r2, lr}
        ldr r1, =(0x20370B8) @var 0x8000 is slot (0x0 to 0x5)
        ldrb r1, [r1]
        mov r0, #0x64
        mul r1, r1, r0 @slot to check
        ldr r0, =(0x2024284)
        add r0, r0, r1
        mov r1, #0xB
        ldr r2, =(0x803FBE8 +1)
        bl linker
        lsl r0, r0, #0x10
        lsr r0, r0, #0x10
        lsl r1, r0, #0x3
        sub r1, r1, r0
        lsl r1, r1, #0x2
        ldr r2, =(0x8254784)
        add r1, r1, r2
        ldrb r0, [r1, #0x6]
        ldr r1, =(0x20370B8)
        strb r0, [r1]
        pop {r0-r2, pc}

linker:
        bx r2       

.align 2


Sorry, too lazy to fetch compiled version :D


Usage:
setvar 0x8000 0x[pokemon slot from 0 to 5]
callasm 0x[routine +1]

It will store the Pokemon's type in variable 0x8000 in the form of an integer. The values in decimal follow this table (it will be stored in hex of course):
Code:

0x0 - Normal
0x1 - Fighting
0x2 - Flying
0x3 - Poison
0x4 - Ground
0x5 - Rock
0x6 - Bug
0x7 - Ghost
0x8 - Steel
0x9 - ???
0xA - Fire
0xB - Water
0xC - Grass
0xD - Electric
0xE - Psychic
0xF - Ice
0x10 - Dragon
0x11 - Dark




clinton6886 April 28th, 2021 10:53 PM

I was wondering, how does the variable 0x8000 store a value for 2 type pokemon? thanks

Xero3C April 30th, 2021 6:37 AM

Hello,

I'd like to request an ASM to determine an NPC's location on a map. So if an NPC is moved (by the Copy-Player Movement f.ex.) and lands on a certain location, a script should trigger, like breaking a rock in order for the Player to pass.

Thank you :)

Best regards,
Xero3C

Neon Skylar June 6th, 2021 6:43 AM

Quote:

Originally Posted by Dreamaker (Post 10318978)

How to apply this at emerald?

Dreamaker June 12th, 2021 4:18 PM

Thick Club [ Fire Red ]

Spoiler:

Code:

@ Credits to blackuser and Dreamaker
@ at 03EFF8 insert 00 48 00 47 XX+1 XX XX 08 00 00 00

main:
cmp r2, #0x41        @ Thick Club Held Item Effect
beq thickclub
bne back

thickclub:
ldrh r0, [r6]
mov r3, #0xFF
add r3, #0x47
cmp r0, r3        @ 0xFF + 0x47 = 0x146 = 326 = Index Number of Regional Marowak
beq doubleattack
b back

doubleattack:
mov r0, r8
lsl r0, r0, #0x1
mov r8, r0
lsl r7, r7, #0x1

back:
ldr r0, return
bx r0

.align 2
return: .word 0x0803f00a | 1



Dreamaker June 12th, 2021 4:21 PM

Stick [ Fire Red ]

Spoiler:

Code:

@ Credits to blackuser and Dreamaker
@ at 01E498 insert 00 4B 1A 47 XX+1 XX XX 08

main:
cmp r6, #0x3f
beq check
cmp r6, #0x42        @ Stick Held Effect
bne end
add r0, r7, r4
ldrh r0, [r0]
mov r3, #0xFF
add r3, #0x42
cmp r0, r3        @ 0xFF + 0x42 = 0x141 = 321 = Index Number of Regional Farfetch'd
beq boost
mov r3, #0xFF
add r3, #0x43
cmp r0, r3        @ 0xFF + 0x43 = 0x142 = 322 = Index Number of Sirfetch'd
beq boost

end:
ldr r3, .return2
bx r3

check:
add r0, r7, r4
ldrh r0, [r0]
ldr r3, .return1
bx r3

boost:
ldr r3, .return3
bx r3

.align 2
.return1: .word 0x0801e4a1
.return2: .word 0x0801e4a7
.return3: .word 0x0801e4a5



Dreamaker June 13th, 2021 9:14 AM

Exp Block via Badge [ Fire Red ]

Spoiler:

Code:

@ Credits to blackuser
@ at 021CFA insert 00 00 00 49 08 47 XX+1 XX XX 08

main:
push {r0-r4}
mov r4, #0x82
lsl r4, #0x4
mov r3, #0x0

loop:
push {r3}
mov r0, r4
ldr r2, =(0x806e6d0 +1)
bl linker
cmp r0, #0x0
beq determinelevel
pop {r3}
add r4, #0x1
add r3, #0x1
cmp r3, #0x8
beq end
b loop

determinelevel:
pop {r3}
ldr r0, .table
ldrb r6, [r0, r3]
pop {r0-r4}
cmp r0, r6
bhs nocrash
b checkmaxlevel

end:
pop {r0-r4}

checkmaxlevel:
cmp r0, #0x64
beq nocrash

giveexp:
ldr r0, =(0x8021d24 +1)
bx r0

nocrash:
ldr r1, [r5]
add r1, #0x53
ldrb r0, [r1]
ldr r2, =(0x8021d04 +1)

linker:
bx r2

.align 2
.table: .word 0x08AAAAAA

/* AAAAAA
10 14 19 1E 23 28 2D 32
*/




Edit the level table to your liking. (AAAAAA)

JK0JK June 16th, 2021 8:05 AM

Quote:

Originally Posted by FBI (Post 8620314)
Actually the whole overworld loading thing is weird..it's done in like 9 places lol.

Quote:

If you experience bugs, use it in conjunction with the backsprite hack I made. If you still have bugs, report them here!
I've been experimenting with your routine and I noticed that, though it changes every time a warp is made, hiding the OW sprite with a menu (such as the backpack's or the trainer card's) will return the sprite to the "hero [gender]" sprite, with the colour palette of the most recently used sprite. Hiding the player a second time will return the colour palette to the one associated with the default sprite, only changing back to the one the routine wants once a warp is made.

How would I solve this?

JaBraden June 21st, 2021 10:50 PM

Quote:

Originally Posted by AkameTheBulbasaur (Post 10174606)
Nature Changing
Before I begin, I should mention that this only works for FireRed at the moment. This is because it uses the Lustre stat, which in FireRed is unused but in Emerald is not. If you can find another stat to use, (or you don't have contests in your Emerald hack), then you can use this.

Offsets listed here are for FireRed, though, so keep that in mind if you decide to port it.

Anyway, without further ado, I present Nature Changing!

How Does It Work?
Skip this if you don't care about the behind the scenes stuff.

Basically, this hijacks the GetNature function. It first checks the Lustre stat of the Pokemon in question. If it's equal to zero, then it gets the Nature form the PID as usual. If it's not zero, then it uses the Lustre value as the Nature, effectively changing the Pokemon's Nature without messing with the PID (and potentially messing up other stuff like the Pokemon's gender, Shininess, etc.).

This does mean you can't set the Nature to Hardy, but this is not that big of a deal since there are other neutral Natures you can use.

The Main Event
I have written an instruction manual that explains how to use the hack in detail. It also contains links to download everything.

The link presented below is the link to download the folder with the Instruction Manual and all the routines. Not every routine in the folder is one you need to insert, as there are a couple of optional add-ons to make changed Natures compatible with other hacks.

Download: Here!

Hey I just wanted to say great work with everything you have done!

But I’m sitting here going crazy at the moment because every time I’m testing my rom to see if I have implemented everything correctly, I run into an issue. When I select a starter Pokémon my game freezes after choosing the Pokémon. It only does this after I rewrite 0x42E9C.

I have chosen the offset 0x750040 for the routine. So it should be just replacing “00 B5 00 21 00 22 FC F7” with “00 49 08 47 40 00 75 08” right?

Not sure if you have had this issue in the past or may have an idea of what I might be doing wrong. Any help is much appreciated!

jirachiwishmaker June 23rd, 2021 11:49 PM

Quote:

Originally Posted by JaBraden (Post 10374091)
Hey I just wanted to say great work with everything you have done!

But I’m sitting here going crazy at the moment because every time I’m testing my rom to see if I have implemented everything correctly, I run into an issue. When I select a starter Pokémon my game freezes after choosing the Pokémon. It only does this after I rewrite 0x42E9C.

I have chosen the offset 0x750040 for the routine. So it should be just replacing “00 B5 00 21 00 22 FC F7” with “00 49 08 47 40 00 75 08” right?

Not sure if you have had this issue in the past or may have an idea of what I might be doing wrong. Any help is much appreciated!

Try replace it as 00 49 08 47 41 00 75 08.

Pyxal June 25th, 2021 4:55 AM

Change Titlescreen Cry For CFRU/DPE based hacks
Simple ASM which changes the TS cry for the ROM's that utilize the CFRU/DPE (since manually changing them doesn't work).

Code:
Code:

.thumb
.global TitlescreenCryFix

.org 0x791EE
ldr r0, .Pointer
bx r0

.align 2
.Pointer: .word Main + 0x8000001

.org 0x[Offset where you want to insert the code]
Main:
ldrh r0, .[Your PKMN Name; check names in DPE (include/species.h)]
mov r1, #0x0
bl CryRelated
ldrb r0, [r4, #0xC]
ldr r2, =0x80791F9
bx r2

CryRelated:
ldr r2, =0x8071DF1
bx r2

.align 2
.[Your PKMN Name; check names in DPE (include/species.h)]: .word 0x[Your PKMN Cry (same number); check names in DPE (include/species.h)]



Making it work:
Put
01 48 00 47 C0 46 XX XX XX XX 00
at
x791EE
where
XX XX XX XX
is your pointer + 1.


That's about it.

JaBraden June 25th, 2021 6:45 PM

Quote:

Originally Posted by jirachiwishmaker (Post 10374697)
Try replace it as 00 49 08 47 41 00 75 08.

Wow that worked! Thank you for your help

Dreamaker July 26th, 2021 9:26 AM

Hidden Power + Held Item = 2nd Type [ Fire Red ]

Spoiler:

Code:

@ Credits to blackuser
@ at 02B754 insert 00 48 00 47 XX+1 XX XX 08

main:
ldr r0, .userbank
ldrb r0, [r0]
mov r1, #0x58
mul r0, r1
ldr r1, .battledata
add r0, r1
add r0, #0x20
ldrb r1, [r0, #0x1]
ldrb r2, [r0, #0x2]
cmp r1, r2
bne end
ldr r2, .memadress
ldr r2, [r2]
ldrb r2, [r2, #0x13]
mov r1, #0x3f
and r1, r2
lsl r3, r1, #0x1
ldr r2, .itemstable
add r3, r2
ldrh r3, [r3]
ldrh r2, [r0, #0xe]
cmp r3, r2
bne end
strb r1, [r0, #0x2]

end:
pop {r3,r4}
mov r8, r3
mov r9, r4
pop {r4-r7}
pop {r0}
bx r0

.align 2
.userbank: .word 0x02023d6b
.battledata: .word 0x02023be4
.memadress: .word 0x02023fe8
.itemstable: .word 0x08AAAAAA

/*AA AA AA
00 00 CF 00 D2 00 D3 00 CB 00 CC 00 BC 00 D5 00 C7 00 00 00 D7 00 D1 00 CD 00 D0 00 D6 00 D4 00 D8 00 CE 00 00 00
*/




Same Hidden Power + Equivalent Held Item = 2nd Type (Only Works in Single Type Pokémon)

Example:
Alakazam + Hidden Power Dark + Black Glasses = Psychic / Dark
Tauros + Hidden Power Fighting + Black Belt = Normal / Fighting
Miltank + Hidden Power Rock + Hard Rock = Normal / Rock
Stantler + Hidden Power Psychic + Twisted Spoon = Normal / Psychic

DarkMadman_69 September 2nd, 2021 5:02 PM

I would like to request a routine that allows for more region maps in emerald.
I would also like to request a routine that allows for more map names in emerald
I'm not sure how hard this would be and I appreciate anybody who writes ASM Routines

BrandonFortie September 5th, 2021 6:56 AM

Quote:

Originally Posted by FBI (Post 8514906)

Inheriting IVs from parents (via Destiny Knot, in the daycare)



How to insert:

Before doing anything, look at the code. There are two comments that say:
@masterball lol. Change to item you want :D
@Parent2 has masterball :D
At those lines, change the line to "cmp r0, #0xDestinyKnotItemID" and
"cmp r3, #0xDestinyKnotItemID" respectively.

Once you're done that, compile and insert into free space.
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r3, r6}
        mov r6, lr
        mov r0, r5
        mov r1, #0xC
        ldr r2, =(0x803FD44 +1)
        bl linker
        mov r3, r0
        mov r0, r5
        add r0, r0, #0x8C
        mov r1, #0xC
        ldr r2, =(0x803FD44 +1)
        bl linker
        cmp r0, #0x1 @masterball lol. Change to item you want :D
        beq inherit
        cmp r3, #0x1 @Parent2 has masterball :D
        beq inherit

end:
        mov lr, r6
        pop {r3, r6}
        mov r0, SP
        mov r1, r5
        ldr r3, = (0x8045AC0 +1)
        bl linkerTwo
        ldr r0, =(0x8046100+1)
        bx r0

inherit:
        mov r3, #0x5
        bl generateRand
        ldrh r3, [r3]
        push {r4, r7}
        mov r4, #0x27
        add r4, r4, r3 @uninherited stat
        mov r7, #0x0

loop:
        cmp r7, #0x6
        beq prepareEnd
        cmp r7, r4
        beq next
        mov r3, #0x1
        bl generateRand @get a random parent's specified IV
        mov r0, r3
        ldrh r0, [r0]
        mov r1, #0x8C
        mul r0, r0, r1
        add r0, r0, r5
        mov r1, #0x27
        add r1, r1, r7
        ldr r2, =(0x803FBE8 +1)
        bl linker
        ldr r2, = (0x20370D0) @set IV to child
        strh r0, [r2]
        mov r1, #0x27
        add r1, r1, r7
        mov r0, SP
        ldr r3, =(0x804037C +1)
        bl linkerTwo
next:
        add r7, r7, #0x1
        b loop

prepareEnd:
        mov r0, SP
        ldr r3, =(0x803E47C +1) @calc stats
        bl linker
        pop {r4, r7}
        b end

generateRand:
        ldr r2, =(0x8044EC8 +1) @get a random between 0 - r3 (r3 = HW)
        bl linker
        lsl r0, r0, #0x10
        lsr r0, r0, #0x10
        mov r1, r3
        ldr r3, =(0x81E4684 +1)
        bl linkerTwo
        ldr r3, = 0x20370D0 @could just move it to r3 I suppose
        strh r0, [r3]
        bx lr

linker:
        bx r2

linkerTwo:
        bx r3

.align 2




Here's a compiled version:
Code:

48 B4 76 46 28 1C 0C 21 26 4A 00 F0 49 F8 03 1C 28 1C 8C 30 0C 21 23 4A 00 F0 42 F8 01 28 0A D0 01 2B 08 D0 B6 46 48 BC 68 46 29 1C 1E 4B 00 F0 38 F8 1E 48 00 47 05 23 00 F0 26 F8 1B 88 90 B4 27 24 E4 18 00 27 06 2F 18 D0 A7 42 14 D0 01 23 00 F0 1A F8 18 1C 00 88 8C 21 48 43 40 19 27 21 C9 19 13 4A 00 F0 1C F8 12 4A 10 80 27 21 C9 19 68 46 11 4B 00 F0 15 F8 01 37 E4 E7 68 46 0F 4B 00 F0 0E F8 90 BC CD E7 0D 4A 00 F0 09 F8 00 04 00 0C 19 1C 0B 4B 00 F0 04 F8 06 4B 18 80 70 47 10 47 18 47 45 FD 03 08 C1 5A 04 08 01 61 04 08 E9 FB 03 08 D0 70 03 02 7D 03 04 08 7D E4 03 08 C9 4E 04 08 85 46 1E 08


Now go to 0x460F8 and insert the following:
Code:

00 48 00 47 XX XX XX 08


Where XX XX XX is the pointer in reverse hex +1 of the routine you just compiled.


How it works:
When the egg is generated, we check both parents to see if their holding an item matching the item we're looking for. If they are, the egg inherits 5/6 IVs from their parents. Each parent has a 50% chance to pass down one of their IVs.

There is no usage section, because the rest is done automagically when you have two compatible Pokemon in the daycare and they make an egg :)

Also, sorry for the double post, I wanted a fresh post for the first page :P

so what program did you use to compile all of this? and can you provide a link?

DarkMadman_69 September 7th, 2021 4:23 AM

Quote:

Originally Posted by BrandonFortie (Post 10402967)
so what program did you use to compile all of this? and can you provide a link?

Here is a link to how to assemble and insert ASM routines into your rom
https://www.pokecommunity.com/showpost.php?p=8526603&postcount=196

There is also this tool that assembles and compiles routines
https://www.pokecommunity.com/showthread.php?t=314750

BrandonFortie September 7th, 2021 7:25 PM

seemed to work but i cant find the offset mentioned in the post, i hate to sound like a noob, but can you post a video or something. im fairly new to this and i dont get all the lingo.

Fantaseed September 13th, 2021 10:48 AM

I would like a request an ASM that stores the current map bank and map ID that the player is currently in, in variable let's say in vars 0x8003 and 0x8004

For future dynamic usage :3 (Think of how you drop down to the underground mines and pop out to the surface at the recent route you were in.)

DarkMadman_69 September 13th, 2021 2:23 PM

Quote:

Originally Posted by BrandonFortie (Post 10403922)
seemed to work but i cant find the offset mentioned in the post, i hate to sound like a noob, but can you post a video or something. im fairly new to this and i dont get all the lingo.

What offset are you referring to? If you are talking about the 5 digit offset in the post 460F8. Just add a zero in front so it now becomes 0460F8. Try searching that offset in your hex editor. If you are still having trouble I'll make a quick video for you. I'll try my best to help you anyway I can

Fantaseed September 15th, 2021 1:05 AM

Quote:

Originally Posted by FBI (Post 8876273)

OAM routines



The first hackathon was probably the worst thing that could have happened for this thread. It completely killed my motivation for hacking and made me quit for a few months. There are some good things that came out of it, I was able to do a lot of research on things I hadn't before including field moves, OAM, trainer generation and such. I was looking around my older routines for OAM manipulation, and I had trouble understanding and ripping my own code! I had lost the source code, so I decided to rip as much as I can and redo the jibberish including some clean up.

Similar routines to these ones I'm presenting were used for the custom intro in team 4's hackoff ROM :)


Generating OAMs



This routine is only to generate OAMs which are trainer or Pokemon sprites. I've modified it to be usable with a script, but honestly, setting the values yourself via ASM would've been faster (not that this is noticeably slow, just comparatively). I will have to do more research on making it portray an arbitrary image, but with the expansion work on the Pokedex and such, I don't see it as very necessary anymore.

How to insert:
Compile and insert the following routine into a free word aligned offset.

Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r0-r4, lr}
        sub SP, SP, #0x14

        @load PID
        ldr r2, =(0x20370B8) @PokeSlot
        ldrb r2, [r2]
        cmp r2, #0x6
        beq shiny
        ldr r0, =(0x2024284)
        mov r4, #0x64
        mul r2, r2, r4
        add r2, r2, r0
        ldrh r2, [r2] @PID

        @load TID
        ldr r1, =(0x300500C)
        ldr r1, [r1]
        ldrh r1, [r1, #0xA] @TID
        b cont

shiny:
        mov r0, #0x0
        mov r1, r0
        mov r2, r0

cont:
        @X-pos
        ldr r0, =(0x20370BA)
        ldrh r0, [r0]
        str r0, [SP] @X-Pos

        @Y-pos
        ldr r0, =(0x20370BC)
        ldrh r0, [r0]
        str r0, [SP, #0x4] @Y-Pos

        @pal #
        ldr r0, =(0x20370BE)
        ldrh r0, [r0]
        str r0, [SP, #0x8] @pal #

        ldr r3, =(0x20370C0)
        ldrb r3, [r3]
        cmp r3, #0x1
        bne nonsil
        mov r3, #0x0
        str r3, [SP, #0xC] @occupacity
        b unkn

nonsil:
        ldr r3, =(0x0000FFFF)
        str r3, [SP, #0xC] @occupacity

unkn:
        @??? - No idea, but leave as 0s
        @possibly priority?
        ldr r0, =(0x20370C6)
        ldrb r0, [r0]
        str r0, [SP, #0x10]
        mov r0, #0x0
        str r0, [SP, #0x14]

        @species/sprite ID
        ldr r0, =(0x20370C2)
        ldrh r0, [r0]

        @front VS back
        ldr r3, =(0x20370C4)
        ldrb r3, [r3]

        @display func
        ldr r4, =(0x810BDAC +1)
        bl linker
        add SP, SP, #0x14
        pop {r0-r4, pc}

linker:
        bx r4

.align 2


Compiled version:
Code:

1F B5 85 B0 18 4A 12 78 06 2A 08 D0 17 48 64 24 62 43 12 18 12 88 16 49 09 68 49 89 02 E0 00 20 01 1C 02 1C 13 48 00 88 00 90 13 48 00 88 01 90 12 48 00 88 02 90 12 4B 1B 78 01 2B 02 D1 00 23 03 93 01 E0 0F 4B 03 93 0F 48 00 78 04 90 00 20 05 90 0E 48 00 88 0E 4B 1B 78 0E 4C 00 F0 02 F8 05 B0 1F BD 20 47 C0 46 B8 70 03 02 84 42 02 02 0C 50 00 03 BA 70 03 02 BC 70 03 02 BE 70 03 02 C0 70 03 02 FF FF 00 00 C6 70 03 02 C2 70 03 02 C4 70 03 02 AD BD 10 08




Usage:
The usage is quite simple, but it takes up a lot of temporary variables :P

Code:

@var 0x8000 - Slot #. Set 0x6 for shiny.
@var 0x8001 - X-pos
@var 0x8002 - Y-pos
@var 0x8003 - Unoccupied Pal ID number. See OAM viewer.
@var 0x8004 - Occupacity silluette set 1
@var 0x8005 - species/trainer sprite ID
@var 0x8006 - Front (1) or Back (0)
@var 0x8007 - Toggle trainer or Pokemon


Some quick notes about these variables.

Variable 0x8000 is to determine the Pokemon's shinyness. If you're showing a Pokemon in your party just use that Pokemon's party slot. If you're showing a shiny Pokemon go ahead and use 0x6. Basically 0x6 = shiny, anything else (must be lower) depends on party slot.

Variable 0x8003 plays a key role. Make sure in the OAM viewer the sprite ID is free.
http://i.imgur.com/rwUxxWe.png
Here sprite number 0 is taken by Oak's OAM. Click the Arrow until you find something not occupied, and set this variable to that value!

Variable 0x8007 is a switch of sorts. It determines whether to show a trainer sprite or a Pokemon sprite.

I think the rest of the variables are self explanatory. Mess around with them a little :)


OAM tracking



So I'm sure you can imagine, that at some point in time you want your OAM to disappear. You can't have it on the screen forever, maybe even make it disappear temporarily and reshow it without having to do the painfully expensive creation call again. I made a routine which will take into account the last OAM ID which you created and stores it in var 0x8008. Note that this is an ID assigned by the game code, not the same ID as the one we assigned on creation. Therefore it's important to track this.

How to insert

Compile and insert the following routine into free space.
Spoiler:

.text
.align 2
.thumb
.thumb_func

@ID of last OAM created - 0x8008
@Hook at 0x80070B0 via r1

main:
ldr r1, =(0x20370C8)
strh r0, [r1]
lsl r6, r6, #0x10
lsr r6, r6, #0x10
lsl r4, r4, #0x18
lsr r4, r4, #0x18
lsl r0, r0, #0x4
ldr r1, =(0x80070BA +1)
bx r1

.align 2


Navigate to 080070B0 and insert the following byte changes:
Code:

00 49 08 47 XX XX XX 08


Where XX XX XX is the location your inserted your routine in reverse hex +1. The trailing "08" may change to 09 or something depending on where you inserted it. Remember to stay word aligned!

Usage:
This routine doesn't really do anything by itself. It's more of a routine which works in the background. It just writes to variable 0x8008 the last displayed OAM's ID. Basically, just insert it and do nothing :3


A quick explanation of how OAMs are shown/hidden in FireRed.



There's a neat RAM structure in FireRed which controls whether or not to show or unshow an OAM on the screen. This OAM's ID needs to be present in said structure. The structure, for some unknown reason, is 40 bytes in size. It looks like this:

[OAM ID (1 byte)] [OAM ID (1 byte)] [OAM ID (1 byte)] ... [Byte 0x3F] [Filler bytes] ...[40th filler byte]

In case you don't understand by now, it's basically a table of X entries where each entry is an OAM's ID to display. Every entry after the byte 0x3F is not read by game code, and is therefore nothing more than filler bytes!

The reason as to why I'm confused the structure is 40 bytes is because the routines which use this structure restrict themselves by using another structure. This second structure only holds 13 OAMs at a time, which is why we can only have 13 OAMs present in FR on screen at once WITHOUT fully customized code. For the most part you'll never go over 13 anyways. I used 9 in total for the custom intro and the screen was cluttered :X

My guess as to why it's 40 bytes is because it's used for animation frames as well. I'm not sure, I haven't researched that.
This structure is located at 0x2021800.

Hiding OAMs created



Now that you understood the data structure, you need to remove your OAM's byte ID from the table. But how do you know which byte is your OAM's byte? That was what the previous tracker routine was for. Right after you create your OAM the corresponding table ID will be in var 0x8008. Copy this value into somewhere you won't lose it (i,e a non-temporary variable), from there you can callasm this routine with the appropriate parameters :)

How to insert:

Compile and insert the following routine to free space:
Spoiler:

.text
.align 2
.thumb
.thumb_func

@OAM ID to hide - 0x8000

main:
push {r0-r2, lr}
ldr r0, =(0x2021800)
ldr r2, =(0x20370B8)
ldrb r2, [r2]

loop:
ldrb r1, [r0]
cmp r1, r2
beq set
add r0, r0, #0x1
b loop

set:
mov r1, #0x3F
strb r1, [r0]

done:
pop {r0-r2, pc}

.align 2



Usage:

In a script, set variable 0x8000 to the OAM ID you want to vanish, then simply callasm this routine. This data structure is updated every frame from what I was able to see, so the results should be immediate.


Show OAM



Sometimes you want to hide an OAM but only temporary. This routine will show an OAM which has already been loaded, but flagged as hidden or similar.

How to insert:

Compile and insert into free space the following routine:
Spoiler:

.text
.align 2
.thumb
.thumb_func

@OAM ID to set - 0x8000

main:
push {r0-r2, lr}
ldr r0, =(0x2021800)

loop:
ldrb r1, [r0]
cmp r1, #0x3F
beq set
add r0, r0, #0x1
b loop

set:
ldr r2, =(0x20370B8)
ldrb r2, [r2]
strb r2, [r0]
mov r1, #0x3F
add r0, r0, #0x1
strb r1, [r0]

done:
pop {r0-r2, pc}

.align 2


Usage:

In a script, set variable 0x8000 to the OAM ID you want to reappear, then simply callasm this routine. This data structure is updated every frame from what I was able to see, so the results should be immediate.

Closing notes:



I may or may not update these with animations as well. One I'm particularly interested in doing is a slow fade. The biggest thing I want to address is how to use these in a script. I think it's fairly intuitive, but a quick example may help :)

Spoiler:

Code:

#dyn 0x740000
#org @start
lock
faceplayer
fadescreen FADEOUT_BLACK

'setting up parameters for OAM creation routine
setvar 0x8007 0x0
setvar 0x8000 0x0
setvar 0x8001 0x74
setvar 0x8002 0x64
setvar 0x8003 0x1
setvar 0x8004 0x0
setvar 0x8005 0x85
setvar 0x8006 0x1
callasm 0x[location you inserted creation routine +1]

'recall our last created OAM is stored in 0x8008

copyvar 0x8009 0x8008

'simply vanishing the OAM
copyvar 0x8000 0x8008
callasm 0x[location you inserted hide routine +1]

'creating a second OAM!
setvar 0x8000 0x0
setvar 0x8001 0x74
setvar 0x8002 0x64
setvar 0x8003 0x2
setvar 0x8004 0x0
setvar 0x8005 0x86
setvar 0x8006 0x1
callasm 0x[location you inserted creation routine +1]

copyvar 0x800A 0x8008
copyvar 0x8000 0x8008
'remove visibility
callasm 0x[location you inserted hide routine +1]
jump @loop

#org @loop
'-----------------------------------
compare 0x8007 0x60
if == jump @done ' Equal To

'show OAM 1
copyvar 0x8000 0x8009
callasm 0x[location you inserted show routine +1]
pause 0x10

'hide OAM 1
copyvar 0x8000 0x8009
callasm 0x[location you inserted hide routine +1]

'show OAM 2
copyvar 0x8000 0x800A
callasm 0x[location you inserted hide routine +1]
pause 0x10

'hide OAM 2
copyvar 0x8000 0x800A
callasm 0x[location you inserted hide routine +1]

'increment loop
addvar 0x8007 0x1
jump @loop

#org @done
'-----------------------------------
fadescreen FADEIN_BLACK
msgbox @text ' Phew.
callstd MSG_LOCK ' Built-in lock command
release
end

#org @text
= Phew.




Play around with it. It can be fun, and hopefully this will open more doors for hackers. I've made it as friendly as possible even opening up the potential to use it in scripts, but if you have any questions you can direct them to me at the ASM help thread or something :D



Hi, the OAM sprite show works wonders. Although, is there a way to delete the OAM sprites rather than hide them? The hide OAM causes glitchy bugs. And after the battle or even talking to an NPC with a yes or no decision/buying at the show, it causes the OAM not to show up using Show OAM.

blackuser September 15th, 2021 2:07 PM

Display move power on press select [Fire Red]

when you select some move in battle to change the position will show the power of it.

here images for show what i mean.

or replacing the text completely(read the code for see how you can make this).


here the routine.
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global Move_Power_On_Press_Select

/*00 48 00 47 XX+1 XX XX 08 at 2eda4*/

@if you want to edit the string Switch which?, it is located at 3FE7A8 edit this to you liking.

main:
ldr r0, =0x083fe7a0
mov r1, #0xb
ldr r2, =0x080d87bd
bl BX_r2
ldr r0, =0x02023bc4
ldrb r0, [r0]
lsl r2, r0, #0x9
ldr r1, =0x02022bc8
add r2, r1
ldr r1, =0x02023ffc
ldrb r0, [r0, r1]
lsl r0, #0x1
ldrh r0, [r0, r2]
mov r1, #0xc
mul r0, r1
ldr r1, .movedata
add r0, r1
ldrb r1, [r0, #0x1] @move power
ldr r0, =0x0202298c
mov r2, #0xca @P
strb r2, [r0]
mov r2, #0xe3 @o
strb r2, [r0, #0x1]
mov r2, #0xeb @w
strb r2, [r0, #0x2]
mov r2, #0xd9 @e
strb r2, [r0, #0x3]
mov r2, #0xe6 @r
strb r2, [r0, #0x4]
mov r2, #0xf0 @:
strb r2, [r0, #0x5]
mov r2, #0x0 @space
strb r2, [r0, #0x6]
push {r0}
cmp r1, #0x2
bhs convertpower
mov r2, #0xae @-: if it's a move with no power, show as ---
strb r2, [r0, #0x7]
strb r2, [r0, #0x8]
strb r2, [r0, #0x9]
mov r2, #0xff @end string
strb r2, [r0, #0xa]
b end

convertpower:
add r0, #0x7
mov r2, #0x0
mov r3, #0x4
ldr r4, =0x08008e79 @convert the move power to decimal string No
bl BX_r4

end:
pop {r0} @draw the string in the box
mov r1, #0x8 @change this 0x8 to 0xb if you prefers that the string Switch which? will be totaly replaced.
ldr r2, =0x080d87bd
bl BX_r2
ldr r2, =0x0802edad

BX_r2:
bx r2

BX_r4:
bx r4

.align 2
.movedata: .word 0x08250c04 @you move data table location

ScyrousFX September 18th, 2021 2:31 PM

I couldn't find an Emerald equivalent of FBI's PID Generator (used for forced wild shiny encounters), so I decided to port it myself. This post also includes a port for the Random number generating routine that's necessary for the shiny encounter one. For the sake of clarity, the majority of the formatting is the same as FBI's original post.

Random Natural Number Generator

Simply compile into free space the following routine:
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r4, lr}
        ldr r4, =(0x806F5CC +1)@gen random number
        bl linker
        lsl r0, r0, #0x10
        lsr r0, r0, #0x10
        ldr r1, =(0x20375D8) @convert to int between 0x0 to [var 0x8000] exclusive
        ldrh r1, [r1]
        ldr r4, =(0x82E7BE0 +1)
        bl linker
        ldr r1, =(0x20375F0) @store in last result
        strh r0, [r1]
        pop {r4, pc}

linker:
        bx r4

.align 2




Shiny Pokémon

Before you can insert this routine you need to have inserted the Random number generating routine from before. Remember the offset which you inserted it because you're going to need to remember in a short while.

Look at the orange text in spoiled code below. Insert inside the brackets the location of where you compiled the random number generator code. Make sure to add an 0x8 prefix. So if I compiled the random number generator at 0x743210, I'd write:
Code:

ldr r4, =(0x8743210 +1)


After you've fixed that line, compile the code and insert into free space.
Spoiler:

PID Generator
Code:

.text
.align 2
.thumb
.thumb_func

main:
        ldr r0, =(0x20375DC) @0x8002 is shiny flag
        ldrb r0, [r0]
        cmp r0, #0xFF
        bne noCrash
        push {r4-r7}
        ldr r0, =(0x20375DC) @set back to 0x0 because users tend to be retarded
        mov r1, #0x0
        strb r1, [r0]
        bl generatePID
        mov r4, r0
        @c = A xor B; 0<= C <8; use random to determine C
        ldr r0, =(0x20375D8)
        mov r1, #0x8
        strb r1, [r0]
        ldr r4, =(OFFSET OF RANDOM)
        bl linker
        mov r3, r0
        @(TID xor SID)
        ldr r0, =(0x3005D90)
        ldr r0, [r0]
        mov r1, #0xA
        add r1, r1, [email protected]
        ldrh r1,[r1]
        mov r2, #0xC
        add r0, r0, r2 @SID
        ldrh r0, [r0]
        eor r0, r0, r1 @(TID XOR SID) = A
        eor r3, r3, r0 @(C XOR A) = B
        @B = (PID[half-word] xor PID2[half-word])
        lsl r4, r4, #0x10
        lsr r4, r4, #0x10
        eor r3, r3, r4 @(PID[half-word] XOR B) = PID2
        @concatinate r4 + r3
        lsl r3, #0x10
        orr r3,r3, r4 @PID for shiny
        pop {r4-r7}
        str r3, [SP, #0x14]
        b end

noCrash:
        bl generatePID
        mov r4, r0
        b old

generatePID:
        push {r4, lr}
        ldr r4, =(0x806F5CC +1)
        bl linker
        mov r4, r0
        ldr r3, =(0x806F5CC +1)
        bl linkerThree
        lsl r4, r4, #0x10
        lsr r4, r4, #0x10
        lsl r0, r0, #0x10
        orr r4, r0
        mov r0, r4
        pop {r4, pc}

old:
        str r4, [SP, #0x14]

end:
        ldr r0, =(0x8067C0C +1)
        bx r0

linker:
        bx r4

linkerThree:
        bx r3

.align 2




Now navigate to 0x067BF8 and insert the following byte changes:
Code:

00 48 00 47 XX XX XX 08


Where XX XX XX is the reverse hex pointer of where you compiled the PID generating routine +1.

Finally, go to 0x067BEE and insert the following byte changes:
Code:

00 00 02 E0


Usage:
Code:

setvar 0x8002 0xFF


This line makes it so the next Pokemon you encounter, or are given is a shiny Pokemon with a properly generated PID. The code sets 0xFF back to 0x0, so you don't have to disable it after.

Here are two Sharpedo generated with the same hack (no EVs).
https://i.imgur.com/fZ922T5.png

All credits go to FBI! I merely ported these routines to Emerald.

BrandonFortie October 3rd, 2021 10:07 PM

Quote:

Originally Posted by DarkMadman_69 (Post 10405949)
What offset are you referring to? If you are talking about the 5 digit offset in the post 460F8. Just add a zero in front so it now becomes 0460F8. Try searching that offset in your hex editor. If you are still having trouble I'll make a quick video for you. I'll try my best to help you anyway I can

still dont work

I like birds October 13th, 2021 3:32 PM

Ok so I have an .asm for a custom level/experience range system sent by a friend of mine but I am struggling to install it and he forgot to do so he can't help.

Spoiler:
Code:

/*Insert 00 48 00 47 XX XX XX 08 at 0x21CE8*/
.text
.align 2
.thumb
.thumb_func

Main:
push {r0-r7}

GetVictorLevel:

/*Gets party position and adds 100*X based on it*/
/*Then gets level and compares it to 0 and 100*/
/*If the Pokemon is level 100, it won’t gain exp.*/
/*If the Pokemon is level 0 (they don’t exist) they won’t gain exp. either*/
/*The level zero check is in case you use an exp. All patch*/
/*If you do, it won’t give exp. to blank party spaces*/

ldr r0, [r5]
ldrb r1, [r0, #0x10]
mov r0, #0x64
mul r0, r1
ldr r1, .FirstPoke
add r0, r0, r1
mov r1, #0x38
bl Decrypt
cmp r0, #0x64
beq Noexp.
cmp r0, #0x0
beq Noexp.
mov r6, r0 /*puts your level in r6*/

CheckIfFainted:

/*Gets current HP of each pokemon and compares it to 0*/
/*If it’s 0, the Pokemon won’t gain exp.*/

ldr r0, [r5]
ldrb r1, [r0, #0x10]
mov r0, #0x64
mul r0, r1
ldr r1, .FirstPoke
add r0, r0, r1
mov r1, #0x39
bl Decrypt
cmp r0, #0x0
beq Noexp.       

GetBaseexp.:

/*Gets base exp. from base stats table*/
/*It does this by getting the species of the Defending Pokemon*/
/*Then it multiplies the index number by 0x1c (or 28)*/
/*It adds this to the offset of the Base Stat table*/
/*Then it adds 9 to the offset of the Pokemon’s Base Stats to get base exp.*/

ldr r0, .Defender
ldrb r0, [r0]
mov r4, #0x58
ldr r1, .UserBank
mul r4, r0
add r0, r1, r4
ldrh r1, [r0] /*species index*/
ldr r0, .BaseStatTable
mov r2, #0x1C
mul r1, r2
add r0, r0, r1
mov r2, #0x9
add r0, r0, r2
ldrb r4, [r0] /*puts base exp. in r4*/

GetOpponentLevel:

/*Gets opponent's level and puts into r5*/

ldr r0, .Defender
ldrb r0, [r0]
cmp r0, #0x1
beq Level1
b Level2

Level1:

/*It goes here if the target’s user bank number was 1*/
/*This is always the opponent in a single battle*/
/*In doubles this is the Pokemon on the right*/

mov r1, #0x64
mul r0, r1
ldr r2, .FirstFoeMinus1 /*The RAM offset of the opponent’s first Pokemon - 100*/
b GetTheLevel

Level2:

/*This is the Pokemon on the left in Double Battles*/
/*They have a user bank number of 3*/

mov r1, #0x64
mul r0, r1
ldr r2, .FirstFoeMinus2 /*The RAM offset of the opponent’s first Pokemon - 300*/

GetTheLevel:

/*Gets the RAM for the opponent’s first or second Pokemon*/
/*Depending on the user bank number*/

add r0, r0, r2
mov r1, #0x38
bl Decrypt
mov r5, r0

Multiply:

/*r4 = base exp..*/
/*r5 = foe’s level*/
/*This multiplies the base exp. by the opponent’s level*/
/*Then it divides the whole thing by 20*/
/*r0 is the top number, r1 is the bottom number*/

mul r4, r5
mov r0, r4 /*r1 is B x L*/
mov r1, #0x14 /*r1 = 20*/
bl Divide /*divides by 20*/
mov r3, r0

LevelStuff:

/*r6 = your level*/
/*r5 = opponent's level*/
/*if r6 is 4+ higher than r5 no exp is earned*/

sub r1, r5, r6  /*(L-Lp)*/
mov r0, #0x21
mul r1, r0      /* 33*(L - Lp) */
mov r2, #0x64
add r1, r1, r2  /* (100 + 33*(L - Lp)) */
mul r1, r3    /* (B * L)/20 * (100 + 33*(L - Lp)) */
mov r0, r1
mov r1, #0x64
bl Divide /*divides by 100 to create a percentage multiplier*/
cmp r0, #0x0    /*if player is 4 levels higher */
blt ZeroExp      /*then no exp is earned*/
b LoadIntoExp

ZeroExp:
mov r0, #0x0

LoadIntoExp:
/*Stores the final amount into the address at r1*/
/*This address at r1 is used for the final results of things*/
/*I believe the damage calculation for moves uses the same RAM address*/

ldr r1, .Storage /*stores value into exp.*/
mov r2, r9
str r0, [r1]
mov r9, r1

ReturnToItemCheck:
/*This returns to right before the Exp. Share check*/
pop {r0-r7}
ldr r1, .Return2
bx r1

Divide:
ldr r2, .Divider
bx r2       

Decrypt:
ldr r2, .Decrypter
bx r2

Noexp.:
/*This returns to right before the skip exp. gain function*/
pop {r0-r7}
ldr r1, .Return1
bx r1

.align 2
.Return1:                        .word 0x08021CFF
.Return2:                        .word 0x0804A67B
.Decrypter:                .word 0x0803FBE9
.Divider:                        .word 0x081E4019
.FirstPoke:                .word 0x02024284
.BaseStatTable:                .word 0x08254784 /*Put offset of BST here*/
.Attacker:                        .word 0x02023D6B
.Defender:                        .word 0x02023D6C
.UserBank:                        .word 0x02023BE4
.Storage:                        .word 0x02023D50
.FirstFoeMinus2:        .word 0x02023F64
.FirstFoeMinus1:        .word 0x02023FC8




I turned it into a bin, put the code in an empty space and wrote on the place was supposed to be, replacing the XX XX XX with my address of choice for the code as usual. However, every time I try I have 2 results, either it
Doesn't work at all
Every battle soft-resets the game

Does anyone know what am I doing wrong, I'm doing it on Ruby and this code is for RSE btw

and if I recall correctly, is based on this one https://www.pokecommunity.com/showpost.php?p=9727834&postcount=1251

Super Versekr Dark October 14th, 2021 4:57 AM

Quote:

Originally Posted by I like birds (Post 10416693)
Ok so I have an .asm for a custom level/experience range system sent by a friend of mine but I am struggling to install it and he forgot to do so he can't help.

Spoiler:
Code:

/*Insert 00 48 00 47 XX XX XX 08 at 0x21CE8*/
.text
.align 2
.thumb
.thumb_func

Main:
push {r0-r7}

GetVictorLevel:

/*Gets party position and adds 100*X based on it*/
/*Then gets level and compares it to 0 and 100*/
/*If the Pokemon is level 100, it won’t gain exp.*/
/*If the Pokemon is level 0 (they don’t exist) they won’t gain exp. either*/
/*The level zero check is in case you use an exp. All patch*/
/*If you do, it won’t give exp. to blank party spaces*/

ldr r0, [r5]
ldrb r1, [r0, #0x10]
mov r0, #0x64
mul r0, r1
ldr r1, .FirstPoke
add r0, r0, r1
mov r1, #0x38
bl Decrypt
cmp r0, #0x64
beq Noexp.
cmp r0, #0x0
beq Noexp.
mov r6, r0 /*puts your level in r6*/

CheckIfFainted:

/*Gets current HP of each pokemon and compares it to 0*/
/*If it’s 0, the Pokemon won’t gain exp.*/

ldr r0, [r5]
ldrb r1, [r0, #0x10]
mov r0, #0x64
mul r0, r1
ldr r1, .FirstPoke
add r0, r0, r1
mov r1, #0x39
bl Decrypt
cmp r0, #0x0
beq Noexp.       

GetBaseexp.:

/*Gets base exp. from base stats table*/
/*It does this by getting the species of the Defending Pokemon*/
/*Then it multiplies the index number by 0x1c (or 28)*/
/*It adds this to the offset of the Base Stat table*/
/*Then it adds 9 to the offset of the Pokemon’s Base Stats to get base exp.*/

ldr r0, .Defender
ldrb r0, [r0]
mov r4, #0x58
ldr r1, .UserBank
mul r4, r0
add r0, r1, r4
ldrh r1, [r0] /*species index*/
ldr r0, .BaseStatTable
mov r2, #0x1C
mul r1, r2
add r0, r0, r1
mov r2, #0x9
add r0, r0, r2
ldrb r4, [r0] /*puts base exp. in r4*/

GetOpponentLevel:

/*Gets opponent's level and puts into r5*/

ldr r0, .Defender
ldrb r0, [r0]
cmp r0, #0x1
beq Level1
b Level2

Level1:

/*It goes here if the target’s user bank number was 1*/
/*This is always the opponent in a single battle*/
/*In doubles this is the Pokemon on the right*/

mov r1, #0x64
mul r0, r1
ldr r2, .FirstFoeMinus1 /*The RAM offset of the opponent’s first Pokemon - 100*/
b GetTheLevel

Level2:

/*This is the Pokemon on the left in Double Battles*/
/*They have a user bank number of 3*/

mov r1, #0x64
mul r0, r1
ldr r2, .FirstFoeMinus2 /*The RAM offset of the opponent’s first Pokemon - 300*/

GetTheLevel:

/*Gets the RAM for the opponent’s first or second Pokemon*/
/*Depending on the user bank number*/

add r0, r0, r2
mov r1, #0x38
bl Decrypt
mov r5, r0

Multiply:

/*r4 = base exp..*/
/*r5 = foe’s level*/
/*This multiplies the base exp. by the opponent’s level*/
/*Then it divides the whole thing by 20*/
/*r0 is the top number, r1 is the bottom number*/

mul r4, r5
mov r0, r4 /*r1 is B x L*/
mov r1, #0x14 /*r1 = 20*/
bl Divide /*divides by 20*/
mov r3, r0

LevelStuff:

/*r6 = your level*/
/*r5 = opponent's level*/
/*if r6 is 4+ higher than r5 no exp is earned*/

sub r1, r5, r6  /*(L-Lp)*/
mov r0, #0x21
mul r1, r0      /* 33*(L - Lp) */
mov r2, #0x64
add r1, r1, r2  /* (100 + 33*(L - Lp)) */
mul r1, r3    /* (B * L)/20 * (100 + 33*(L - Lp)) */
mov r0, r1
mov r1, #0x64
bl Divide /*divides by 100 to create a percentage multiplier*/
cmp r0, #0x0    /*if player is 4 levels higher */
blt ZeroExp      /*then no exp is earned*/
b LoadIntoExp

ZeroExp:
mov r0, #0x0

LoadIntoExp:
/*Stores the final amount into the address at r1*/
/*This address at r1 is used for the final results of things*/
/*I believe the damage calculation for moves uses the same RAM address*/

ldr r1, .Storage /*stores value into exp.*/
mov r2, r9
str r0, [r1]
mov r9, r1

ReturnToItemCheck:
/*This returns to right before the Exp. Share check*/
pop {r0-r7}
ldr r1, .Return2
bx r1

Divide:
ldr r2, .Divider
bx r2       

Decrypt:
ldr r2, .Decrypter
bx r2

Noexp.:
/*This returns to right before the skip exp. gain function*/
pop {r0-r7}
ldr r1, .Return1
bx r1

.align 2
.Return1:                        .word 0x08021CFF
.Return2:                        .word 0x0804A67B
.Decrypter:                .word 0x0803FBE9
.Divider:                        .word 0x081E4019
.FirstPoke:                .word 0x02024284
.BaseStatTable:                .word 0x08254784 /*Put offset of BST here*/
.Attacker:                        .word 0x02023D6B
.Defender:                        .word 0x02023D6C
.UserBank:                        .word 0x02023BE4
.Storage:                        .word 0x02023D50
.FirstFoeMinus2:        .word 0x02023F64
.FirstFoeMinus1:        .word 0x02023FC8




I turned it into a bin, put the code in an empty space and wrote on the place was supposed to be, replacing the XX XX XX with my address of choice for the code as usual. However, every time I try I have 2 results, either it
Doesn't work at all
Every battle soft-resets the game

Does anyone know what am I doing wrong, I'm doing it on Ruby and this code is for RSE btw

and if I recall correctly, is based on this one https://www.pokecommunity.com/showpost.php?p=9727834&postcount=1251


This code is not for ruby, it is for FR and Em, besides that I see that the one you are using is for FR due to the address of the table 0x254784, if you need it for ruby you should look for the corresponding compensations but the routines do not always work since at least in ruby there are many different things compared to FR and Em that are more similar.

I like birds October 14th, 2021 7:38 AM

Quote:

Originally Posted by Super Versekr Dark (Post 10416861)
This code is not for ruby, it is for FR and Em, besides that I see that the one you are using is for FR due to the address of the table 0x254784, if you need it for ruby you should look for the corresponding compensations but the routines do not always work since at least in ruby there are many different things compared to FR and Em that are more similar.

Is there any way I can find the corresponding compensation for ruby?

Furthermore when I applied to Emerald, the game would soft reset every time I received the experience

Super Versekr Dark October 14th, 2021 8:39 AM

Quote:

Originally Posted by I like birds (Post 10416882)
Is there any way I can find the corresponding compensation for ruby?

Furthermore when I applied to Emerald, the game would soft reset every time I received the experience

Well, the creator left a link with both routines, obviously you must apply depending on the rom you use, surely you are putting FR in Em and that's why that happens, and I don't know if there is a way to find all that data for ruby, as you do. I say it is more complicated to find those data for ruby, I would have to review them but I do not assure you that they are all found.

OPPAIDAISUKI October 18th, 2021 8:56 AM

Quote:

Originally Posted by Spherical Ice (Post 9878890)

Stats on the Pokédex screen replacing the weight comparison




Code:

.thumb

@ credits to DoesntKnowHowToPlay and Squeetz

.equ rom, 0x08000000
.equ offset, 0x

.org 0x10611E, 0xFF
        .byte 0x43, 0xE0

.org 0x106370, 0xFF
        .byte 0x0, 0x48, 0x0, 0x47
        .word main + rom + 1

.org 0x106530, 0xFF
        .byte 0xCE, 0xE0

.org 0x452200, 0xFF
        .byte 0xA

.org offset, 0xFF
main:
    mov r5, #4
    str r5, [sp]
    str r6, [sp, #4]
    mov r0, r10
    cmp r0, #0
    beq unknown_base_stats

hp:
    mov r0, #0
    bl print_stat
    mov r3, #4 @ y co-ord
    str r3, [sp]
    mov r3, #0 @ x co-ord
    ldr r5, write_method
    bl call_via_r5

atk:
    mov r0, #1
    bl print_stat
    mov r3, #4 @ y co-ord
    str r3, [sp]
    mov r3, #0x2C @ x co-ord
    ldr r5, write_method
    bl call_via_r5

def:
    mov r0, #2
    bl print_stat
    mov r3, #18 @ y co-ord
    str r3, [sp]
    mov r3, #0 @ x co-ord
    ldr r5, write_method
    bl call_via_r5

spa:
    mov r0, #4
    bl print_stat
    mov r3, #18 @ y co-ord
    str r3, [sp]
    mov r3, #0x2C @ x co-ord
    ldr r5, write_method
    bl call_via_r5

spd:
    mov r0, #5
    bl print_stat
    mov r3, #32 @ y co-ord
    str r3, [sp]
    mov r3, #0 @ x co-ord
    ldr r5, write_method
    bl call_via_r5

spe:
    mov r0, #3
    bl print_stat
    mov r3, #32 @ y co-ord
    str r3, [sp]
    mov r3, #0x2C @ x co-ord
    ldr r5, write_method
    bl call_via_r5

print_ability_one:
    ldr r0, [sp, #0x1C]
    mov r3, #0x1C
    mul r0, r3
    ldr r1, base_stats
        ldr r1, [r1]
    mov r3, #0x16
    add r1, r1, r3
    add r1, r0, r1
    ldr r3, abilities
        ldr r3, [r3]
    ldrb r2, [r1]
    mov r1, #0xD
    mul r1, r2
    add r2, r1, r3
    ldr r1, [r7]
    add r1, #0x53
    ldrb r1, [r1]
    mov r0, r1
    mov r1, #0
    mov r3, #46
    str r3, [sp]
    mov r3, #0
    ldr r5, write_method
    bl call_via_r5

print_ability_two:
    ldr r0, [sp, #0x1C]
    mov r3, #0x1C
    mul r0, r3
    ldr r1, base_stats
        ldr r1, [r1]
    mov r3, #0x16
    add r1, r1, r3
    add r1, r0, r1
    ldrb r2, [r1, #1]
    ldrb r5, [r1, #0]
    ldr r3, abilities
        ldr r3, [r3]
    cmp r2, r5
    beq return
    cmp r2, #0
    beq return
    mov r1, #0xD
    mul r1, r2
    add r2, r1, r3

    ldr r1, [r7]
    add r1, #0x53
    ldrb r1, [r1]
    mov r0, r1
    mov r1, #0
    mov r3, #60
    str r3, [sp]
    mov r3, #0
    ldr r5, write_method
    bl call_via_r5
    b return

unknown_base_stats:
    mov r0, r1
    mov r1, #0
    ldr r2, str_unknown
    mov r3, #4 @ y co-ord
    str r3, [sp]
    mov r3, #0 @ x co-ord
    ldr r5, write_method
    bl call_via_r5

return:
    mov r5, #0
    ldr r0, return_loc
    bx r0

print_stat:
    push {lr}
    ldr r3, [sp, #0x20]
    mov r1, #0x1C
    mul r3, r1
    ldr r2, base_stats
        ldr r2, [r2]
    add r2, r3
    add r2, r0
    ldrb r1, [r2]
    mov r4, r0
    ldr r0, fcode_buffer2
    mov r3, #0
    cmp r1, #99
    bhi no_leading_zeroes
    cmp r1, #9
    bhi one_leading_zero

two_leading_zeroes:
    str r3, [r0]
    add r0, #1

one_leading_zero:
    str r3, [r0]
    add r0, #1

no_leading_zeroes:
    mov r3, #3
    ldr r5, int_to_str
    bl call_via_r5

    mov r2, r4
    ldr r0, displayed_string
    ldr r1, str_table
    lsl r2, r2, #2
    add r1, r2
    ldr r1, [r1]
    ldr r5, fdecoder
    bl call_via_r5
    ldr r1, [r7]
    add r1, #0x53
    ldrb r1, [r1]
    mov r0, r1
    mov r1, #0
    ldr r2, displayed_string
    pop {r5}

call_via_r5:
    bx r5

.align 2
    base_stats:            .word 0x1BC + rom
    abilities:              .word 0x1C0 + rom
    str_table:              .word table + rom
    str_unknown:            .word capture + rom
    fcode_buffer2:          .word 0x02021CD0
    displayed_string:      .word 0x02021D18
    int_to_str:            .word 0x08008E78|1
    fdecoder:              .word 0x08008FCC|1
    write_method:          .word 0x081047C8|1
    return_loc:            .word 0x08106380|1
table:
        .word stat_hp + rom
        .word stat_atk + rom
        .word stat_def + rom
        .word stat_spe + rom
        .word stat_spa + rom
        .word stat_spd + rom

stat_hp:
        .byte 0xC2, 0xCA, 0x0, 0x0, 0xFD, 0x2, 0xFF

stat_atk:
        .byte 0xBB, 0xE8, 0xDF, 0x0, 0xFD, 0x2, 0xFF

stat_def:
        .byte 0xBE, 0xD9, 0xDA, 0x0, 0xFD, 0x2, 0xFF

stat_spe:
        .byte 0xCD, 0xE4, 0xD9, 0x0, 0xFD, 0x2, 0xFF

stat_spa:
        .byte 0xCD, 0xE4, 0xBB, 0x0, 0xFD, 0x2, 0xFF

stat_spd:
        .byte 0xCD, 0xE4, 0xBE, 0x0, 0xFD, 0x2, 0xFF

capture:
        .byte 0xBD, 0xD5, 0xE4, 0xE8, 0xE9, 0xE6, 0xD9, 0x0, 0xDA, 0xE3, 0xE6, 0xFE, 0xE1, 0xE3, 0xE6, 0xD9, 0x0, 0xDD, 0xE2, 0xDA, 0xE3, 0xE6, 0xE1, 0xD5, 0xE8, 0xDD, 0xE3, 0xE2, 0xAB, 0xFF


Thanks to DoesntKnowHowToPlay for the base routine which I slightly edited / optimised, and to Squeetz for making the routine into a form that can be applied as a patch.

HI SIR!!!!!!!!... Do you also have this kind of patch to Pokemon Emerald?....thanks in advance sir!!!

Yave Yu October 24th, 2021 4:22 AM

Quote:

Originally Posted by AkameTheBulbasaur (Post 9727834)
Scaled Experience Formula

In Generation V, a new way of determining the Experience Points gained after Battle was introduced. Previously, the Experience Formula was a flat one, which did not change based on Level Differences between your Pokemon and the other one.

In Black & White, they used a Scaled Experience Formula, which would cause your Pokemon to gain more experience if their opponent was a higher Level, and less if their opponent was a lower one.

Today, I am sharing a way to have this sort of Scaled Experience Points in Fire Red or Emerald. I have included the download link to a folder which contains four items.

Spoiler:
Folder: (Download)
  1. The Routine (For Fire Red)
  2. The Routine (For Emerald)
  3. Think0028's Experience All Patch
  4. An Instruction Manual

The Instruction Manual explains how the routine works and any extra information that is necessary to know (particularly if you would like to modify this routine for your specific hack).

Important:
Considering I first uploaded the first version of this routine a long time ago, you may have an older version of it. This version may be preferable to that one, and it is smaller than the previous version is. Therefore, one can simply insert it over the old version and not have to repoint anything.

Extra Information

This routine is compatible with Think0028's Experience All Patch. His original download link is unfortunately broken, hence why I put it in the download folder. If it was still active, I would have linked directly to it.

If you inserted the Disable Experience Gain With Flag routine, originally by FBI, then you may wish to remove it, as this routine implements it. I am not sure if there is a conflict due to this, but at the very least there is a redundant check if you have two routines which both check the same Flag. It is also possible that this routine bypasses that one entirely, in which case you would want to remove it to avoid wasting space.

Thanks and credits to FBI for that original routine, as without it I would likely not have been able to find the correct branching address for this routine.

As I have nowhere else to post this information, I will say here that to remove the 1.5x Experience Boost you get for defeating a Pokemon in a Trainer Battle (like they did in Generation VII), do the following:

Put 07 E0 at 0x21DD8 (FireRed) or 0x4A698 (Emerald)

Put 1C E0 at 0x21E00 (FireRed) or put 28 E0 at 0x4A6C0 (Emerald)

Amazing stuff, but I never get success :(
I try the script for EM, first I modified 0x0804A67B to 0x0804A66B at line 10 because I don't use that Exp. All patch, then I compiled it and insert them into 0x32A5F0 since there has a lot of 00, modified 0x4A5AC to 00 48 00 47 F0 A5 32 08 as your tutorial said, seems it all OK, but...
I tried to find a wild Pokemon to battle, after I win, the game crashed and mGBA gives an error message said somehow "Jumped to invalid address 0x09670880".
Could you help me how to implement it so it works well? Thanks.

AkameTheBulbasaur October 31st, 2021 6:28 PM

Quote:

Originally Posted by Yave Yu (Post 10420363)
Amazing stuff, but I never get success :(
I try the script for EM, first I modified 0x0804A67B to 0x0804A66B at line 10 because I don't use that Exp. All patch, then I compiled it and insert them into 0x32A5F0 since there has a lot of 00, modified 0x4A5AC to 00 48 00 47 F0 A5 32 08 as your tutorial said, seems it all OK, but...
I tried to find a wild Pokemon to battle, after I win, the game crashed and mGBA gives an error message said somehow "Jumped to invalid address 0x09670880".
Could you help me how to implement it so it works well? Thanks.

Well, I can see the first thing you did is that you forgot to add one to the address. You should have 00 48 00 47 F1 A5 32 08. The reason for this is because the "00 48 00 47 F1 A5 32 08" translates to:

ldr r0, #=0x0832A5F1
bx r0

The first thing loads the location of the routine, and the second tells the game to jump there.

However, when you use bx in particular, you need to add one to the location of the routine. The game has two modes, ARM and THUMB. When we do ASM, we use THUMB. The "bx r0" part jumps to the location you put in r0, but it also switches modes. If r0 has an even number, it goes to ARM mode (which we don't want). The solution is to add +1 to the routine so that r0 will be odd so it will stay in THUMB.

So, any time you call a routine this way (which will be 99.99999% of the time), you need to add one. I thought I would explain it since maybe some people don't know exactly why you have to do that.

Try doing that, and if it still doesn't work then we'll move from there!

Yave Yu November 1st, 2021 4:54 AM

Quote:

Originally Posted by AkameTheBulbasaur (Post 10423243)
Well, I can see the first thing you did is that you forgot to add one to the address. You should have 00 48 00 47 F1 A5 32 08. The reason for this is because the "00 48 00 47 F1 A5 32 08" translates to:
Spoiler:

ldr r0, #=0x0832A5F1
bx r0

The first thing loads the location of the routine, and the second tells the game to jump there.

However, when you use bx in particular, you need to add one to the location of the routine. The game has two modes, ARM and THUMB. When we do ASM, we use THUMB. The "bx r0" part jumps to the location you put in r0, but it also switches modes. If r0 has an even number, it goes to ARM mode (which we don't want). The solution is to add +1 to the routine so that r0 will be odd so it will stay in THUMB.

So, any time you call a routine this way (which will be 99.99999% of the time), you need to add one. I thought I would explain it since maybe some people don't know exactly why you have to do that.

Try doing that, and if it still doesn't work then we'll move from there!

Thanks for your advice, but still doesn't work :(
This time emulator won't pop up an error, but game stucks on "Wild <Name> fainted!" and producing garbage audio.
Oh wait, I need to try battle with trainer!
However no luck, when my Pokemon defeat an enemy, game encounters an error, mGBA said jumped to invalid address 0xFDFFB954.
I have no idea how to implement this correctly :(

AkameTheBulbasaur November 4th, 2021 6:56 PM

Quote:

Originally Posted by Yave Yu (Post 10423337)
Thanks for your advice, but still doesn't work :(
This time emulator won't pop up an error, but game stucks on "Wild <Name> fainted!" and producing garbage audio.
Oh wait, I need to try battle with trainer!
However no luck, when my Pokemon defeat an enemy, game encounters an error, mGBA said jumped to invalid address 0xFDFFB954.
I have no idea how to implement this correctly :(

I figured out the problem. Turns out, I am an idiot and I forgot to change the address of the Flag Check routine from FireRed to Emerald. :P I am updating the download to have the correct routine.

You can change the routine you have now by replacing "D1 E6 06 08" with "91 D7 09 08". This should allow it to work, as this made it work on a clean ROM.

leafeon_iscool November 21st, 2021 12:06 AM

Quote:

Originally Posted by FBI (Post 8517719)
Pokemon Storage (outside the PC)

Ah, heaven hath a place for HM slaves :)

blackuser December 30th, 2021 9:26 AM

Automatic swap page on naming screen [Fire Red]

when you write the first character in the naming screen of a pokemon(or the player/rival) the page automatic swap to lower case.

here the routine.
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global Swap_Page_On_Name_Screen

/*00 48 00 47 XX+1 XX XX 08 00 00 at 9f140*/

main:
cmp r4, #0x0
bne return
ldr r1, =0x0203998c
ldr r4, [r1]
ldr r0, =0x00001e22
ldrb r0, [r0, r4]
cmp r0, #0x1 @check if it's the first page
bne end
ldr r0, =0x0809f6bd
bl BX_r0
cmp r0, #0x0 @check if the character position is zero = no character written
bne end
ldr r0, =0x00001e10
mov r1, #0x4
strb r1, [r0, r4] @store page swap action

end:
ldr r0, =0x0809f157

BX_r0:
bx r0

return:
mov r0, #0x0
ldr r1, =0x0809f241
bl BX_r1
ldr r1, =0x0809f149

BX_r1:
bx r1


credits: Jaizu for the EM one made in C, i just port it to FR binary.

NormalGhost January 14th, 2022 1:27 AM

Hiya! I have a hack request for FireRed or RSE: Universal Pokemon Randomizer (UPR) + In-Battle Type Display
I'd like to use UPR combined with a, to my knowledge, non-existent hack that shows a pokemon's typing(s) in battle so I can react to its randomized typing.
I've attempted to mix UPR with Complete FireRed Upgrade (CFRU), as it has the type showing functionality, even following its documentation to remove functionalities I didn't want, but CFRU overall adds too many things past gen 3 that UPR doesn't handle.
I should also mention that I have Radical Red (which has the in-battle type showing functionality), but its randomizer is very limited and it doesn't even randomize types.
Something I could preferably patch before patching with UPR would be awesome. Patching after UPR would be fine too
In the meantime I'll hopefully be researching ASM to attempt this myself
Also please withhold fan game recommendations (rather than romhack recs), because I prefer playing roms on my 3ds

jacobhue January 29th, 2022 9:29 PM

Extremely decent instructional exercise!
The main thing I didn't comprehend is the motivation behind why we want midfix4agb.exe, as it appears to be not to be remembered for the instructional exercise. :(

GalarianZatcunoltres January 31st, 2022 3:47 PM

Quote:

Originally Posted by DarkPsychic (Post 9848167)
Here ya go ^_^
Faint/Low Hp Evolution:
Code:

.text
.align 2
.thumb
.thumb_func
.global faintEvolution

main:
push {r0-r7}
add r0, r6, r7  @line to change if expanded evos
lsl r0, r0, #0x3
add r0, r2, r0
add r3, r0, r3
ldrb r2, [r3, #0x2]
mov r0, r8
bl decrypt
mov r11, r0
pop {r0-r7}
mov r1, r11
cmp r1, #0x2    @Compare Amount of Current Hp
blo low_hp
b exit

low_hp:
mov r10, r3
pop {r0-r7}
mov r1, r10
ldr r0, evolution_loc
bx r0

exit:
pop {r0-r7}
ldr r0, no_evo
bx r0

decrypt:
push {r0-r7}
mov r1, #0x39
ldr r2, decryptpoke
bx r2

.align 2
no_evo: .word 0x08043111
evolution_loc: .word 0x0804310D
decryptpoke: .word 0x0803FBE9



Note for the first highlighted in green:
If you have expaned your evolutions for your pokemon you must change this line:
"add r0, r6, r7"
to:
8 evos or less = lsl r0, r6, #0x1
16 evos or less = lsl r0, r6, #0x2
32 evos or less = lsl r0, r6, #0x3

or
just change the bytes in the compiled file from F0 19 to:
8 evos or less = 70 00
16 evos or less = B0 00
32 evos or less = F0 00


Note for second highlighted in green:
As it is the Pokemon must be leveled up with a Rare Candy to get it to revive and have 1-Hp.
You can change the value of 0x2 to something higher but anything lower than 0x2 will not work with this routine.
After the compare it the vaule must be lower than the "0x2" or what ever value you decide to change it to.


Hope this helps!

o

Eu queria ver como era essa rotina em ação. ^_^ achei a temática legal.

O pequeno problema é que mesmo seguindo tutoriais que nos mesmos, funcionam a expansão de métedos evolutivos, eu não consigo fazer os métodos novos funcionarem enquanto eu jogo =_=

Queria saber ASM para fazer um metódo evolutivo igual ou semelhante ao de Basculegion, Ursaluna ou Wyrdeer e Overqwill T-T

Ansh¹⁹⁸⁸ February 16th, 2022 7:07 AM

I dont know if it already exists but is there any routine to show Pokemon icon at desired X Y position.

eMMe97 February 16th, 2022 12:05 PM

Quote:

Originally Posted by Ansh¹⁹⁸⁸ (Post 10470743)
I dont know if it already exists but is there any routine to show Pokemon icon at desired X Y position.

A simple "showpokepic" command...

#dynamic 0x800000
#org @start
showpokepic 0x[n° pokémon species to display] 0x[X coordinate] 0x[Y coordinate]
pause 0x80
hidepokepic
end

Ansh¹⁹⁸⁸ February 16th, 2022 4:26 PM

No i meant the mini icons
The smaller one which we can seen in Pokemon selection screen.

ShinyTillDawn March 19th, 2022 2:44 PM

I know this is an old thread, but I tried porting this to Emerald, and I'm stuck.
Spoiler:

.thumb

.equ location, 0xBAC000
.equ rom, (0x08000000 + 1)

.equ ability_name_length, 0x0D
.equ base_stats_length, 0x1C
.equ pokemon_length, 0x64
.equ req_species, 0x0B
.equ req_species2, 0x41
.equ req_ability, 0x2E
.equ ability1, 0x16
.equ ability2, 0x17
.equ egg_species, 0x19C

.org location, 0xFF
ability_capsule:
push {lr}
lsl r0, r0, #0x18
lsr r0, r0, #0x18
ldr r2, item_function_ptr
ldr r1, =(rom + dp05_abilitycapsule)
str r1, [r2]
ldr r3, item_consume_maybe
bl call_via_r3
pop {r3}
bx r3

dp05_abilitycapsule:
push {r4-r7,lr}
mov r6, r1
lsl r0, r0, #0x18
lsr r5, r0, #0x18

get_selected_pokemon:
ldr r0, brm
ldrb r0, [r0, #9]
mov r1, #pokemon_length
mul r0, r1
ldr r1, party_player
add r4, r0, r1

get_species:
mov r0, r4
mov r1, #req_species2
ldr r3, get_attr
bl call_via_r3

egg_check:
ldrh r1, =egg_species
cmp r0, r1
beq fail

compare_abilities:
ldr r1, base_stats_ptr
ldr r1, [r1]
mov r2, #base_stats_length
mul r0, r2
add r1, r0
ldrb r0, [r1, #ability1]
ldrb r1, [r1, #ability2]
cmp r0, r1
beq fail
cmp r0, #0
beq fail
cmp r1, #0
beq fail
mov r4, #0
b continue

fail:
mov r4, #1

continue:
mov r0, #5
ldr r3, audio_play
bl call_via_r3
cmp r4, #0
beq effect

no_effect:
ldr r0, no_effect_str
mov r1, #1
ldr r3, item_menu_string
bl call_via_r3
mov r0, #2
ldr r3, bgid_mark_for_sync
bl call_via_r3
ldr r1, tasks
lsl r0, r5, #2
add r0, r0, r5
lsl r0, r0, #3
add r0, r0, r1
mov r1, r6
str r1, [r0]
b end

effect:
mov r0, r5
ldr r3, item_use_animation
bl call_via_r3
ldr r1, item_function_ptr
ldr r0, =(rom + abilitycapsule_use)
str r0, [r1]
b end

abilitycapsule_use:
push {r4-r7,lr}
lsl r0, r0, #0x18
lsr r5, r0, #0x18

get_selected_pokemon_again:
ldr r0, brm
ldrb r0, [r0, #9]
mov r1, #pokemon_length
mul r0, r1
ldr r1, party_player
add r4, r0, r1

get_ability_id_again:
mov r0, r4
mov r1, #req_ability
ldr r3, get_attr
bl call_via_r3
lsl r0, r0, #0x18
lsr r0, r0, #0x18

invert_ability_id:
mov r1, #1
eor r0, r1
ldr r2, var_800D
strb r0, [r2]

set_new_ability_id:
mov r0, r4
mov r1, #req_ability
ldr r3, set_attr
bl call_via_r3

set_item_effectiveness:
mov r0, #1
ldr r1, item_effectiveness
strb r0, [r1]

remove_item:
ldr r0, var_800E
ldrh r0, [r0]
mov r1, #1
ldr r3, bag_remove_item
bl call_via_r3

buffer_nickname:
mov r0, r4
ldr r1, fcode_buffer2
ldr r3, buffer_pkmn_nick
bl call_via_r3

buffer_ability_name:
mov r0, r4
ldr r1, fcode_buffer3
ldr r3, =(rom + buffer_ability)
bl call_via_r3

construct_string:
ldr r4, displayed_string
mov r0, r4
ldr r1, =(rom + abilitycapsule_str)
ldr r3, fdecoder
bl call_via_r3

print_string:
mov r0, r4
mov r1, #1
ldr r3, item_menu_string
bl call_via_r3

display_box:
mov r0, #2
ldr r3, bgid_mark_for_sync
bl call_via_r3

add_callback_task:
ldr r1, tasks
mov r2, r5
lsl r0, r2, #2
add r0, r0, r5
lsl r0, r0, #3
add r0, r0, r1
ldr r1, item_menu_callback
str r1, [r0]
b end

buffer_ability:
push {r4-r7,lr}
mov r4, r0
mov r5, r1

get_species_again:
mov r1, #req_species2
ldr r3, get_attr
bl call_via_r3
lsl r0, r0, #0x10
lsr r6, r0, #0x10

get_ability_bit:
mov r0, r4
mov r1, #req_ability
ldr r3, get_attr
bl call_via_r3
lsl r0, r0, #0x18
lsr r1, r0, #0x18

get_ability_id:
mov r0, r6
mov r2, #base_stats_length
mul r0, r2
ldr r2, base_stats_ptr
ldr r2, [r2]
add r2, r0
add r2, #ability1
ldrb r0, [r2, r1]

get_ability_name_string:
mov r1, #ability_name_length
mul r0, r1
ldr r1, ability_names_ptr
ldr r1, [r1]
add r1, r0
mov r0, r5
ldr r3, strcpy_xFF_terminated
bl call_via_r3

end:
pop {r4-r7}
pop {r3}

call_via_r3:
bx r3

abilitycapsule_str:
.byte 0x00
.byte 0xFD, 0x02, 0xB4, 0xE7, 0x00, 0xBB, 0xD6, 0xDD, 0xE0, 0xDD, 0xE8, 0xED, 0xFE, 0xD7, 0xDC, 0xD5, 0xE2, 0xDB, 0xD9, 0xD8, 0x00, 0xE8, 0xE3, 0x00, 0xFD, 0x03, 0xAB, 0xFC, 0x09, 0xFF
@ "[PKMN]'s Ability[NEWLINE]changed to [ABILITY]![WAITKEYPRESS]"

.align 2
fcode_buffer2: .word 0x02021CC4
fcode_buffer3: .word 0x02021DC4
displayed_string: .word 0x02021FC4
party_player: .word 0x020244EC
var_800D: .word 0x020375F0
var_800E: .word 0x0203CE7C
brm: .word 0x0203CEC8
item_effectiveness: .word 0x0203CEE8

tasks: .word 0x03005E00
item_function_ptr: .word 0x03006328

base_stats_ptr: .word 0x080001BC
ability_names_ptr: .word 0x080001C0
strcpy_xFF_terminated: .word 0x08008BA0|1
fdecoder: .word 0x08008EE0|1
get_attr: .word 0x0806A518|1
set_attr: .word 0x0806ACAC|1
audio_play: .word 0x080A37A4|1
bag_remove_item: .word 0x080D6AA4|1
(I stopped here.)
item_consume_maybe: .word 0x080A16D0|1
bgid_mark_for_sync: .word 0x080F67A4|1
buffer_pkmn_nick: .word 0x081202E0|1
item_menu_string: .word 0x081202F8|1
item_use_animation: .word 0x08124DC0|1
item_menu_callback: .word 0x081255BC|1
no_effect_str: .word 0x084169DC @ "It won't have any effect."

I can't find the equivalent of "sub_80A16D0" in Emerald.

RuFF April 19th, 2022 6:28 AM

Quote:

Originally Posted by FBI (Post 8676351)

Button detection in scripts



How to insert:

First compile and insert into free space, the following routine
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        ldr r0, =(0x30030F0)
        ldrh r1, [r0, #0x2E] @byte in super state for keypress
        cmp r1, #0x0
        beq cont
        ldr r0, =(0x20370B8) @var 0x8000 location
        strh r1, [r0]
        ldr r4, =(0x806B922 +1)
        bx r4

cont:
        mov r0, #0x1
        and r0, r0, r1
        cmp r0, #0x0
        beq section
        ldr r1, =(0x806B922 +1)
        bx r1

section:
        ldr r0, =(0x806B8A6 +1)
        bx r0

.align 2




Now navigate to 0x6B89A and do the following byte changes:
Code:

00 00 00 48 00 47 XX XX XX 08


Where XX XX XX is the pointer to wherever you inserted this routine +1

Hello, I trying to convert this to Ruby. How will I find the corresponding offsets mentioned above?

(0x806B922 +1)
(0x806B8A6 +1)

0x6B89A

I already found the corresponding one for (0x30030F0).

Blah April 19th, 2022 8:06 AM

Quote:

Originally Posted by RuFF (Post 10494538)
Hello, I trying to convert this to Ruby. How will I find the corresponding offsets mentioned above?

(0x806B922 +1)
(0x806B8A6 +1)

0x6B89A

I already found the corresponding one for (0x30030F0).

Don't follow this method, it's a poor implementation. Instead, create a task which listens to a key press and use callasm to run it.

RuFF April 20th, 2022 1:41 AM

Quote:

Originally Posted by FBI (Post 10494564)
Don't follow this method, it's a poor implementation. Instead, create a task which listens to a key press and use callasm to run it.

How do you integrate wait key in asm? I tried looping until a button is pressed but I think I got stuck in an infinite loop.

Spoiler:

.text
.align 2
.thumb
.thumb_func

main:
push {r0-r2, lr}
ldr r0, =(0x3001770)
ldrh r1, [r0, #0x2E] @byte in super state for keypress
cmp r1, #0x0
beq cont
ldr r0, =(0x202E8C4) @var 0x8000 location
strh r1, [r0]
pop {r0-r1, PC}

cont:
in
ldr r0, =(0x3001770)
ldrh r1, [r0, #0x2E] @byte in super state for keypress
cmp r1, #0x0
beq cont
ldr r0, =(0x202E8C4) @var 0x8000 location
strh r1, [r0]
pop {r0-r2, PC}

.align 2


I also tried using waitbutton command from PKSV then callasm this routine but It just sets the var to 0. Also waitbutton only accepts "A" and "B"

Spoiler:

.text
.align 2
.thumb
.thumb_func

main:
push {r0-r2, lr}
ldr r0, =(0x3001770)
ldrh r1, [r0, #0x2E] @byte in super state for keypress
ldr r0, =(0x202E8C4) @var 0x8000 location
strh r1, [r0]
pop {r0-r1, PC}

.align 2

Blah April 24th, 2022 8:00 AM

Quote:

Originally Posted by RuFF (Post 10494752)
How do you integrate wait key in asm? I tried looping until a button is pressed but I think I got stuck in an infinite loop.

Spoiler:

.text
.align 2
.thumb
.thumb_func

main:
push {r0-r2, lr}
ldr r0, =(0x3001770)
ldrh r1, [r0, #0x2E] @byte in super state for keypress
cmp r1, #0x0
beq cont
ldr r0, =(0x202E8C4) @var 0x8000 location
strh r1, [r0]
pop {r0-r1, PC}

cont:
in
ldr r0, =(0x3001770)
ldrh r1, [r0, #0x2E] @byte in super state for keypress
cmp r1, #0x0
beq cont
ldr r0, =(0x202E8C4) @var 0x8000 location
strh r1, [r0]
pop {r0-r2, PC}

.align 2


I also tried using waitbutton command from PKSV then callasm this routine but It just sets the var to 0. Also waitbutton only accepts "A" and "B"

Spoiler:

.text
.align 2
.thumb
.thumb_func

main:
push {r0-r2, lr}
ldr r0, =(0x3001770)
ldrh r1, [r0, #0x2E] @byte in super state for keypress
ldr r0, =(0x202E8C4) @var 0x8000 location
strh r1, [r0]
pop {r0-r1, PC}

.align 2

You need two routines to pull this off. The first routine would pause script execution, and start a key listener task. Then the key listener task would check for a new key press, and destroy the task/resume the script

Pokémon Hack Lab April 27th, 2022 2:23 PM

Quote:

Originally Posted by FBI (Post 8527650)

Battle Modes!



In this post, we will be implementing a base skeleton structure to allow the hacker to add in their own battle modes, I'll also be including some example "add-ons" so you know how to do it yourself. The post currently contains possibilities for the hacker to implement routines which run once at the end of each turn (perfect for tournament clauses) and a routine which runs once every move is chosen and used (perfect for trainer sliding *hint hint danillS*).

I'm calling it a skeleton, but it's actually more like a hook into a routine which runs your routines!
It works like this:
1) Hook from original to routine which runs routines
2) If flag is set, routine runs the routines it's told to run
3) Returns back to hooking location

So all you really need to do to add new battle modes, is add to the list of routines we call (Which is simple, I'll explain in detail later). I should also mention that these routines are called in ALL types of battle including wild, trainer, and scripted. Happy hacking!

Battle Routine By Move:



This routine will run, on average four times per turn. Once you select your move, once you use your move, once the opponents uses their move and at the end of the aftermath. This makes the routine a perfect branching place for an Oak-tutorial like battle.

How to insert:
Look at the routine below. The last line .table has an incomplete pointer. It says 0x[pointer to routine table]. Find enough free space (takes 4 byte per routine) in your ROM and set the pointer for .table to that. You do not add +1 to the pointer, nor is it in reverse hex. Once you've fixed the pointer, compile the routine into free space. The last pointer in the routine NEEDS to be 00 00 00 00.


Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r0-r4}
        mov r0, #0xBF @flag to check divided by 4
        lsl r0, r0, #0x2
        ldr r1, =(0x806E6D0 +1)
        bl linker
        cmp r0, #0x0
        beq noCrash
        ldr r4, .table

loop:
        ldr r1, [r4]
        cmp r1, #0x0 @check table entry is null
        beq noCrash
        bl linker @call table routine
        add r4, r4, #0x4 @get next table routine
        b loop

noCrash:
        pop {r0-r4}
        lsl r0, r0, #0x18
        lsr r0, r0, #0x18
        mov r10, r0
        lsl r1, r1, #0x10
        lsr r1, r1, #0x10
        ldr r2, =(0x2022874)
        ldr r0, =(0x800E2EA +1)
        bx r0

linker:
        bx r1

.align 2

.table:
        .word 0x[pointer to routine table] @THIS IS FREE SPACE IF IT'S YOUR FIRST TIME USING THIS ROUTINE


Navigate to


Now navigate to 0xE2E0 and insert the byte changes:
Code:

00 4D 28 47 XX XX XX 08


Where XX XX XX is the reverse hex pointer to your routine +1.



Usage:
The routine is toggled by flag 0x2FC. Activate the flag to toggle routines called by this routine. To add routines into the list of called routines, navigate to the pointer of freespace you made .table point to. Insert into that table pointers in reverse hex +1 to wherever you compiled the addon routines make sure they have the 0x8 prefix. The structure of the table should be: [routine pointer in reverse hex +1 (4 bytes)] for each pointer in the table. I.e if I put the addon at 0x740000, the pointer would read 01 00 74 08.


Addons for Battle by move:



Prevent loss (white out):
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r0-r1, lr}
        ldr r0, =(0x2023E8A)
        ldrb r1, [r0]
        cmp r1, #0x1
        bhi setZero
        b end

setZero:
        cmp r1, #0x5
        beq end
        mov r1, #0x0
        strb r1, [r0]

end:
        pop {r0-r1, pc}





Battle by turn:



This routine will run all of it's referenced routines at the end of the turn (right before the turn counter in incremented.

How to insert:
Look at the routine below. The last line .table has an incomplete pointer. It says 0x[pointer to routine table]. Find enough free space (takes 4 byte per routine) in your ROM and set the pointer for .table to that. You do not add +1 to the pointer, nor is it in reverse hex. Once you've fixed the pointer, compile the routine into free space.
Last entry in the table needs to be 00 00 00 00.

Credits to daniilS for helping with optimization.
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        @check flag 0x2F8 to toggle routines (0xBE*4 = 0x2F8)
        mov r0, #0xBE
        lsl r0, r0, #0x2
        ldr r2, =(0x806E6D0 +1)
        bl linker
        cmp r0, #0x0
        beq skip
        ldr r4, .table

loop:
        ldr r2, [r4]
        cmp r2, #0x00
        beq skip
        bl linker @call table routine
        add r4, #0x4 @get next table routine
        b loop

skip:
        ldr r1, = 0x3004F90
        ldrb r0, [r1, #0x13]
        cmp r0, #0xFE
        bhi replacer
        add r0, #0x1
        strb r0, [r1, #0x13]

replacer:
        ldr r2, = (0x8013CBC + 1)

linker:
        bx r2

.align 2

.table:
        .word 0x[pointer to Routine table]




Now navigate to 0x13CB0 and insert the following byte changes:
Code:

00 48 00 47 XX XX XX 08



Usage:
The routine is toggled by flag 0x2F8. Activate the flag to toggle routines called by this routine. To add routines into the list of called routines, navigate to the pointer of freespace you made .table point to. Insert into that table pointers in reverse hex +1 to wherever you compiled the addon routines make sure they have the 0x8 prefix. The structure of the table should be: [routine pointer in reverse hex +1 (4 bytes)] for each pointer in the table. I.e if I put the addon at 0x740000, the pointer would read 01 00 74 08.

Battle by turn addons:



Sleeping clause:
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r0-r3,lr}
        mov r2, #0x0 @pokemon counter
        mov r3, #0x0 @sleeping counter

loop:
        cmp r2, #0x5
        beq validateBattle
        ldr r0, =(0x202402C + 0x50)
        mov r1, #0x64
        mul r1, r1, r2
        add r0, r0, r1
        ldrb r0, [r0]
        lsl r0, r0, #0x5
        lsr r0, r0, #0x5
        cmp r0, #0x0 @check sleeping
        beq next
        add r3, r3, #0x1
next:
        add r2, r2, #0x1
        b loop

validateBattle:
        cmp r3, #0x1 @check amount sleeping <=1
        ble end
        ldr r0, =(0x2023E8A)
        mov r1, #0x5
        strb r1, [r0]       

end:
        pop {r0-r3, pc}

.align 2




Battle end by turn:
Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        push {r0-r1,lr}
        ldr r0, =(0x20370CC)
        ldrb r0, [r0]
        ldr r1, =(0x3994FA3)
        ldrb r1, [r1]
        cmp r1, r0
        bne end
        ldr r0, =(0x2023E8A)
        mov r1, #0x5
        strb r1, [r0]
end:
        pop {r0-r1, pc}

.align 2



Sleep Clause it works?

I correctly installed Delete Fainted Pokémon and it worked, but Sleep Clause did not :[

Quote:

013CB0: 00 48 00 47 01 00 80 08
800000: BE 20 80 00 0B 4A 00 F0 11 F8 00 28 07 D0 08 4C 22 68 00 2A 03 D0 00 F0 09 F8 04 34 F8 E7 06 49 C8 7C FE 28 01 D8 01 30 C8 74 04 4A 10 47 C0 46 00 00 81 08 D1 E6 06 08 90 4F 00 03 BD 3C 01 08
810000: 01 00 82 08 00 00 00 00
820000: 0F B5 00 22 00 23 05 2A 0B D0 09 48 64 21 51 43 40 18 00 78 40 01 40 09 00 28 00 D0 01 33 01 32 F1 E7 01 2B 02 DD 03 48 05 21 01 70 0F BD C0 46 7C 40 02 02 8A 3E 02 02

Kaito11073 June 3rd, 2022 11:50 PM

How do you input these codes?

sylingga June 9th, 2022 7:54 AM

Quote:

Originally Posted by FBI (Post 8524910)
I don't really feel like doing a challenge cup. Also some of your features can be achieved using the already created party checker routine. Species Clause, Evasion Clause, OHKO clause can all be done by it. Maybe if I feel like it in future :P


Custom nicknames for enemy Pokemon



So this works for any wild or trainer Pokemon. It basically allows you to nickname a Pokemon on the enemy team prior to battling. For those special trainers or maybe special Pokemon :)

How to insert:

There's actually a little bit of work before you can compile and insert routines. First look at the routine below. You'll notice at the last line there is a Pointer to something that I call "TABLE". This table is going to be a table full of nickname with each entry 0xB bytes long. Find some space in your ROM which you will use for this table and correct the offset accordingly.

Spoiler:

Code:

.text
.align 2
.thumb
.thumb_func

main:
        mov r0, #0x9C
        lsl r0, #0x2
        push {r1-r7}
            ldr r2, =(0x806E6D0 +1)
        bl linker
        pop {r1-r7}
        cmp r0, #0x0
        beq old

nick:
        ldr r0, =(0x202402C)
        sub r0, r7, r0
        mov r1, #0x64
        ldr r2, =(0x81E4018 +1) @slot number
        bl linker
        mov r3, r0
        ldr r1, = (0x20370B8) @table entry position
        ldrb r1, [r1]
        mov r2, #0xB
        mul r1, r1, r2
        ldr r0, .TABLE
        add r0, r0, r1 @table start position
        mul r3, r3, r2
        add r0, r0, r3 @name to give
        mov r1, r7
        add r1, r1, #0x8 @nickname location
        mov r4, #0x0

nameLoop:
        cmp r4, #0xB
        beq end
        ldrb r3, [r0]
        strb r3, [r1]
        add r1, r1, #0x1
        add r0, r0, #0x1
        add r4, r4, #0x1
        b nameLoop

end:
        ldr r0, =(0x8040ADA +1)
        bx r0

old:
        mov r2, #0x0
        mov r3, r7
        add r3, #0x8

oldLoop:
        add r0, r3, r2
        add r1, r4, r2
        ldrb r1, [r1]
        strb r1, [r0]
        add r2, r2, #0x1
        cmp r2, #0x9
        ble oldLoop
        ldr r0, =(0x8040ADA +1)
        bx r0

linker:
        bx r2

.align 2

.TABLE:
        .word 0x8760000



Once you've made the modification to the pointer, compile and insert the routine into freespace.
Next navigate to offset 0x406DC and insert the following:
Code:

00 48 00 47 XX XX XX 08


Where XX is the pointer to the above routine in reverse hex +1.

Usage:
First navigate to your table which will contain the nicknames (it should be the offset in the routine you changed). You need to keep the table formatted like this [10 bytes (Name in hex)] [1 byte (0xFF)]. Insert as many names as you'd like.

Next, to activate the routine, you must setflag 0x270 AND you need to setvar 0x8000 0x[table starting index].
If you're battling a trainer with 6 Pokemon, the nicknames will be determined from the table. It will read six nicknames starting from the starting index given by variable 0x8000. There is no need to callasm. :)

http://i.imgur.com/wZeZnYU.png


I want to use this on my rom hack,
Can you help me?

i'm not really good at scripting

DjTarma June 19th, 2022 6:47 PM

Quote:

Originally Posted by Spherical Ice (Post 9681830)

[FR] EV-reducing Berries


Find 0x49C bytes of free space at a word-aligned address, and take note of it.
Set the EV-reducing berries' Type to Type 1 ("Out of battle").
Set the items' Field script pointers to the address you noted, plus 1.
Set the items' Battle script pointer to 0xA2239.
Assemble the following routine, changing 0xXXXXXX to the address you noted (not plus 1).
Open the generated .bin file, navigate to the location address, and select 0x49C bytes.
Copy the bytes and paste them in your ROM, at the same address.
...
This will introduce the Pomeg Glitch; see tkim's post here on how to fix it.

I implemented this routine in my project and it is working "as it should". 😔
There is a huge problem: If I use a Kelpsy Berry, it will reduce my Pokémon's Attack EVs without error, but if I use a Protein, the item is not consumed. 😡
If I accidentally use it on a level 100 Pokemon, I can no longer increase the EVs.

How can this be fixed?

Yave Yu June 20th, 2022 6:59 AM

I wonder is there has a code implements BW item use system...
If selected item (such as Potion) has many, on map use it to a Pokemon (or it won't affect) won't back to bag automaticly unless that item is last one.

sylingga June 22nd, 2022 11:39 PM

Quote:

Originally Posted by Yave Yu (Post 10518576)
I wonder is there has a code implements BW item use system...
If selected item (such as Potion) has many, on map use it to a Pokemon (or it won't affect) won't back to bag automaticly unless that item is last one.

yes there is.
i think its on HMA discord. try join that and you will see


All times are GMT -8. The time now is 8:46 AM.


Like our Facebook Page Follow us on Twitter © 2002 - 2018 The PokéCommunity™, pokecommunity.com.
Pokémon characters and images belong to The Pokémon Company International and Nintendo. This website is in no way affiliated with or endorsed by Nintendo, Creatures, GAMEFREAK, The Pokémon Company or The Pokémon Company International. We just love Pokémon.
All forum styles, their images (unless noted otherwise) and site designs are © 2002 - 2016 The PokéCommunity / PokéCommunity.com.
PokéCommunity™ is a trademark of The PokéCommunity. All rights reserved. Sponsor advertisements do not imply our endorsement of that product or service. User generated content remains the property of its creator.

Acknowledgements
Use of PokéCommunity Assets
vB Optimise by DragonByte Technologies Ltd © 2023.