Male
Seen August 19th, 2018
Posted August 19th, 2018
1,312 posts
12.3 Years
Natural Gift for FireRed:

Step 1: First, add this command in commands.bsh for Battle Script Pro (credit to KDS for first discovering this when he posted his Incinerate script):
Spoiler:
#command removeitem 0x6A 0x1 "Bank" 0x1
(this command to remove items is already in the game so you don't need to add code or anything, it's just unidentified by BSP)

Step 2:
Compile the following table and put it into free space, make sure you take note of the offset you put it in. We'll refer to this table as NATURAL GIFT TABLE:
Spoiler:
.align 2
.text

main:
/*CHERI*/
.hword 0x0085
.byte 0x0A
.byte 0x50

/*CHESTO*/
.hword 0x0086
.byte 0x0B
.byte 0x50

/*PECHA*/
.hword 0x0087
.byte 0x0D
.byte 0x50

/*RAWST*/
.hword 0x0088
.byte 0x0C
.byte 0x50

/*ASPEAR*/
.hword 0x0089
.byte 0x0F
.byte 0x50

/*LEPPA*/
.hword 0x008A
.byte 0x01
.byte 0x50

/*ORAN*/
.hword 0x008B
.byte 0x03
.byte 0x50

/*PERSIM*/
.hword 0x008C
.byte 0x04
.byte 0x50

/*LUM*/
.hword 0x008D
.byte 0x02
.byte 0x50

/*SITRUS*/
.hword 0x008E
.byte 0x0E
.byte 0x50

/*FIGY*/
.hword 0x008F
.byte 0x06
.byte 0x50

/*WIKI*/
.hword 0x0090
.byte 0x05
.byte 0x50

/*MAGO*/
.hword 0x0091
.byte 0x07
.byte 0x50

/*AGUAV*/
.hword 0x0092
.byte 0x10
.byte 0x50

/*IAPAPA*/
.hword 0x0093
.byte 0x11
.byte 0x50

/*RAZZ*/
.hword 0x0094
.byte 0x08
.byte 0x50

/*BLUK*/
.hword 0x0095
.byte 0x0A
.byte 0x5A

/*NANAB*/
.hword 0x0096
.byte 0x0B
.byte 0x5A

/*WEPEAR*/
.hword 0x0097
.byte 0x0D
.byte 0x5A

/*PINAP*/
.hword 0x0098
.byte 0x0C
.byte 0x5A

/*POMEG*/
.hword 0x0099
.byte 0x0F
.byte 0x5A

/*KELPSY*/
.hword 0x009A
.byte 0x01
.byte 0x5A

/*QUALOT*/
.hword 0x009B
.byte 0x03
.byte 0x5A

/*HONDEW*/
.hword 0x009C
.byte 0x04
.byte 0x5A

/*GREPA*/
.hword 0x009D
.byte 0x02
.byte 0x5A

/*TAMATO*/
.hword 0x009E
.byte 0x0E
.byte 0x5A

/*CORNN*/
.hword 0x009F
.byte 0x06
.byte 0x5A

/*MAGOST*/
.hword 0x00A0
.byte 0x05
.byte 0x5A

/*RABUTA*/
.hword 0x00A1
.byte 0x07
.byte 0x5A

/*NOMEL*/
.hword 0x00A2
.byte 0x10
.byte 0x5A

/*SPELON*/
.hword 0x00A3
.byte 0x11
.byte 0x5A

/*PAMTRE*/
.hword 0x00A4
.byte 0x08
.byte 0x5A

/*WATMEL*/
.hword 0x00A5
.byte 0x0A
.byte 0x64

/*DURIN*/
.hword 0x00A6
.byte 0x0B
.byte 0x64

/*BELUE*/
.hword 0x00A7
.byte 0x0D
.byte 0x64

/*LIECHI*/
.hword 0x00A8
.byte 0x0C
.byte 0x64

/*GANLON*/
.hword 0x00A9
.byte 0x0F
.byte 0x64

/*SALAC*/
.hword 0x00AA
.byte 0x01
.byte 0x64

/*PETAYA*/
.hword 0x00AB
.byte 0x03
.byte 0x64

/*APICOT*/
.hword 0x00AC
.byte 0x04
.byte 0x64

/*LANSAT*/
.hword 0x00AD
.byte 0x02
.byte 0x64

/*STARF*/
.hword 0x00AE
.byte 0x0E
.byte 0x64

/*ENIGMA*/
.hword 0x00AF
.byte 0x06
.byte 0x64

/*end table*/
.hword 0xFFFF
.hword 0xFFFF

When compiled, the format of this table will be [XX XX] [YY] [ZZ], with XXXX being the index number of the item, YY being the type that Natural Gift will change into, and ZZ being the base power. This table only covers the berries that are in Gen 3, so if you've added new berries then you'll have to add them into the table. MAKE SURE YOU LEAVE THE FOUR FF BYTES AT THE END, DO NOT OVERWRITE IT. (or change them to FE bytes, and in Step 3 modify the line "mov r4, 0xFF" to "mov r4, 0xFE").

Step 3:
Insert this routine into free space, and take note of its offset. We'll refer to this as ASM ROUTINE 1:
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global test

main:
push {lr}
ldr r0, .UserBank
ldr r1, .BattleData
ldrb r0, [r0]
mov r2, #0x58
mul r2, r0
add r1, #0x2E
add r1, r2
ldrh r0, [r1] /*r0 should now have held item. r1 is the RAM offset of the held item*/
cmp r0, #0x0
beq Abort
ldr r2, .NaturalGiftTable
mov r4, #0xFF

loop:
ldrh r3, [r2] /*item ID*/
ldrb r5, [r2, #0x3]
cmp r5, r4
beq Abort /*fail if 4th byte is FF*/
cmp r0, r3
beq Confirmed
add r2, #0x4
b loop

Confirmed:
ldrb r4, [r2, #0x2] /*Type*/
ldrb r5, [r2, #0x3] /*Power*/
ldr r0, .MemAddress
ldr r0, [r0]
add r0, #0x13
strb r4, [r0] /*change Type*/
add r0, #0x7B
strb r4, [r0]
ldr r0, .BasePower
strb r5, [r0]
b Attack

Abort:
ldr r0, .CurrentScript
ldr r1, .FailScript
str r1, [r0]

Attack:
End:
pop {r0}
bx r0

.align 2
.BattleData: .word 0x02023BE4
.UserBank: .word 0x02023D6B
.BasePower: .word 0x02023F50
.MemAddress: .word 0x02023FE8
.CurrentScript: .word 0x02023D74
.FailScript: .word 0x081D7DF0
.NaturalGiftTable: .word 0x08(OFFSET OF NATURAL GIFT TABLE)

Make sure you put in the offset of the Natural Gift table at the last line.

Step 4:
Now, insert this routine into free space as well, and take note of its offset. We'll refer to this as ASM ROUTINE 2:
Spoiler:
.text
.align 2
.thumb
.thumb_func
.global test

GetOpponentType:
push {lr}
ldr r0, .TargetBank
ldr r1, .BattleData
ldrb r0, [r0]
mov r2, #0x58
mul r2, r0
add r1, #0x21
add r1, r2
ldrb r0, [r1] /*r0 should now have opponent Type 1*/
ldrb r2, [r1, #0x1] /*r2 should now have opponent Type 2*/

GetNaturalGiftType:
ldr r1, .MemAddress
ldr r1, [r1]
add r1, #0x13
ldrb r1, [r1] /*r1 should now have modified Natural Gift type*/
ldr r3, .TypeChart

/*check attacking type*/
Check1:
ldrb r4, [r3] /*r4 has Type Chart attacking type*/
ldrb r5, [r3, #0x1] /*r5 has Type Chart defending type*/
ldrb r6, [r3, #0x2] /*r6 has Type Chart effectiveness*/
cmp r4, #0xFE
beq Abort
cmp r1, r4 /*check NG type with Attacking type*/
bne Recheck
cmp r0, r5 /*check opponent Type 1 with Defending type*/
beq Type1Match
cmp r2, r5 /*check opponent Type 2 with Defending type*/
beq OkNowCheckType1
add r3, #0x3
b Check1

OkNowCheckType1:
ldr r3, .TypeChart
b StillCheckinglol

/*we should be here if Type 2 was a match but Type 1 wasn't*/
StillCheckinglol:
ldrb r4, [r3] /*r4 has Type Chart attacking type*/
ldrb r5, [r3, #0x1] /*r5 has Type Chart defending type*/
ldrb r7, [r3, #0x2] /*r7 has Type Chart effectiveness*/
cmp r4, #0xFE
beq SameOutcome
cmp r1, r4 /*check NG type with Attacking type*/
bne Recheck3
cmp r0, r5 /*check opponent Type 1 Defending type*/
beq Type2Match
add r3, #0x3
b Check2

Type1Match:
ldr r3, .TypeChart
b Check2

Check2:
ldrb r4, [r3] /*r4 has Type Chart attacking type*/
ldrb r5, [r3, #0x1] /*r5 has Type Chart defending type*/
ldrb r7, [r3, #0x2] /*r7 has Type Chart effectiveness*/
cmp r4, #0xFE
beq SameOutcome
cmp r1, r4 /*check NG type with Attacking type*/
bne Recheck2
cmp r2, r5 /*check opponent Type 2 Defending type*/
beq Type2Match
add r3, #0x3
b Check2

Type2Match:
cmp r6, r7
beq SameOutcome
cmp r6, #0x5
beq TOneIsWeak
cmp r6, #0x0
beq Sameoutcome
cmp r6, #0x14
beq TOneIsSuper

TOneIsWeak:
cmp r7, #0x5
beq SameOutcome
cmp r7, #0x0
beq NoDamage
cmp r7, #0x14
beq Abort

TOneIsSuper:
cmp r7, #0x5
beq Abort
cmp r7, #0x0
beq NoDamage
cmp r7, #0x14
beq SameOutcome

Recheck:
add r3, #0x3
b Check1

Recheck2:
add r3, #0x3
b Check2

Recheck3:
add r3, #0x3
b StillCheckinglol

SameOutcome:
cmp r6, #0x5
beq WeakDamage
cmp r6, #0x0
beq NoDamage
cmp r6, #0x14
beq SuperDamage
cmp r7, #0x5
beq WeakDamage
cmp r7, #0x0
beq NoDamage
cmp r7, #0x14
beq SuperDamage

WeakDamage:
ldr r0, .Outcome
mov r1, #0x04
strb r1, [r0]
b End

NoDamage:
ldr r0, .Outcome
mov r1, #0x08
strb r1, [r0]
b End

SuperDamage:
ldr r0, .Outcome
mov r1, #0x02
strb r1, [r0]
b End

Abort:
End:
pop {r0}
bx r0

.align 2
.Outcome: .word 0x02023DCC
.TypeChart: .word 0x0824F050 /*make sure you replace this with the offset of your own type chart*/
.BattleData: .word 0x02023BE4
.TargetBank: .word 0x02023D6C
.MemAddress: .word 0x02023FE8

Note: If you have repointed your type chart, then you will have to put its new offset where I've bolded above.

Step 5:
Now here's the battle script:
Spoiler:
#org @main
attackcanceler
accuracycheck 0x81D695E 0x0
attackstring
ppreduce
callasm 0x8(offset of ASM ROUTINE 1+1)
calculatedamage
callasm 0x8(offset of ASM ROUTINE 2+1)
attackanimation
waitanimation
missmessage
cmd5c 0x0
waitstate
graphicalhpupdate 0x0
datahpupdate 0x0
critmessage
waitmessage 0x40
resultmessage
waitmessage 0x40
jumpifbyte 0x4 0x02023DCC 0x8 0x81D694E
removeitem 0x1
goto 0x81D6947


And here's an animation:
02 24 7B 3E 08 02 05 01 00 01 00 00 00 0A 00 ED 33 05 03 19 34 0B 08 02 00 19 EC 00 C0 04 10 19 EC 00 C0 05 00 97 27 0A 01 0C 0C 08 19 7F 00 3F 02 08 7C 3E 08 02 04 00 00 00 00 01 00 02 00 03 F9 89 09 08 02 05 01 00 03 00 00 00 06 00 01 00 05 0B 01 0D 02 24 7B 3E 08 02 05 01 00 01 00 0A 00 00 00 ED 33 05 0B 03 0D 08
Here's an explanation as to how this works:
So as you can see, "ASM ROUTINE 1" looks up the custom table we inserted and matches your held item to it (the move will fail if you're not holding an item or if you're holding an item that's not in the table), and then updates the type and base power accordingly. Now, with this routine alone, the damage and type calculations are correct, but the outcome message will always act as a regular move (regular as in not super-effective or not not-very-effective) unless if you don't have an item in the table (then it will just fail), and turns out the reason why is for some reason the outcome RAM offset (02023DCC) wasn't getting updated even though the battle engine should theoretically already have done so (if you have the routine be the first thing in the script). So what "ASM ROUTINE 2" does is that it looks up the type chart and the opponent's types and determines the outcome that way (and yes, I checked and double checked and triple checked with various berry & type combinations, so it works). It wasn't ideal, but it was necessary in order to get the correct message to show up.

"But Chaos, couldn't you just look at how Weather Ball and Hidden Power does it"? Well, I did (for anyone curious, the Weather Ball command's routine is at 0802D090, while the Hidden Power command's routine is at 0802B678), and what both do is that they update the value held by the pointer at 02023FE8(a dynamic memory location) + 0x13, usually the pointer at 02023FE8 leads to 02000010, so the type value is (usually) at 02000023. No matter what I tried with updating that value, it always played the normal hit sound (but would still do more or less damage depending on type, such as Electric type Natural Gift doing more damage to Pidgey than Water type Natural Gift), unless if it was a type immunity in which case it worked as expected. For testing reasons I tried giving a new test move Hidden Power's battle script ID, and turns out the correct sound effect doesn't play either (but it does with Hidden Power itself, even though I gave them the same battle script ID), and turns out the outcome offset was only being updated when using the actual Hidden Power, which leads me to believe that Hidden Power and Weather Ball's move ID's are hard-coded to update the outcome offset. So the whole purpose of "ASM ROUTINE 2" is to circumvent that. "ASM ROUTINE 2" manually looks up the type chart and what outcome it should be, and updates the outcome value at 02023DCC accordingly.