emerald upgrade source

This commit is contained in:
notblisy 2025-07-27 08:46:14 -04:00 committed by GitHub
parent 8d0a1f81a0
commit 6941aa40d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
48 changed files with 1655 additions and 0 deletions

View File

@ -0,0 +1,172 @@
INCLUDE "../macros.asm"
SECTION "eonticket",ROM0[$100]
jp Start
db $00
TicketPalette: ; 1604
INCBIN "Spr_3r_251.pal.bin"
Prologue:
INCBIN "prologue-{REGION_NAME}.bin"
DataPacket: ; 164a
INCBIN "eonticket-{REGION_NAME}.mev"
db 0,0,0 ; padding
INCLUDE "../common/mem_struct.asm"
SpriteData:
dw TicketPalette
db $00,$00,$01,$01,$01,$01,$01 ;
Instructions1: ; 1921
db "Link e-Reader to Pokémon Emerald\n"
db "and use MYSTERY EVENTS via the\n"
db "DELIVERY MAN in the Pokémon Center.\n"
db "Press the B Button to cancel.\0"
Instructions2: ; 199d
db "Press the A Button on the Game Boy\n"
db "Advance containing Pokémon Emerald\n"
db "to begin sending the Upgrade Patch\0"
DeliveryInProcess: ; 1a0d
db "Upgrade Patch delivery in Progress...\0"
TicketDelivered: ; 1a2f
db "Upgrade Patch delivered!\n"
db "\n"
db "Press the A Button to resend.\n"
db "Press the B Button to cancel.\0"
; this function is subtly different than the one
; on the Battle e cards, for no apparent reason
TransferData:
LD_IND_HL SomeVar1
push de
ld hl, $bbbb
LD_IND_HL Space_1
EX_DE_HL
LD_IND_HL Space_2
API_0C7 Space_1
wait $01
pop hl
inc hl
ld b, $01
call WordShiftRight
LD_IND_HL SomeVar2
.asm_1aa1
LD_HL_IND SomeVar2
ld a, l
or h
ret z
ld hl, $8888
LD_IND_HL Space_1
ld e, $01
.asm_1aaf
ld a, e
cp $08
jr nc, .asm_1ad9
push de
LD_HL_IND SomeVar1
ld c, [hl]
inc hl
ld b, [hl]
inc hl
LD_IND_HL SomeVar1
ld l, e
ld h, $00
add hl, hl
ld de, Space_1
add hl, de
ld [hl], c
inc hl
ld [hl], b
pop de
LD_HL_IND SomeVar2
dec hl
LD_IND_HL SomeVar2
ld a, l
or h
jr z, .asm_1ad9
inc e
jr .asm_1aaf
.asm_1ad9
API_0C7 Space_1
wait $01
jr .asm_1aa1
Start: ; 1ae2
API_121
CreateCustomSprite SpriteHandlePtr, $80, SpriteData
SetSpritePos SpriteHandlePtr, 120, 64
SpriteHide SpriteHandlePtr
CreateRegion RegionHandlePtr, 30, 6, 0, 14, 0, 4
ld h, a
ld l, $00
SetTextSize
API_09B RegionHandlePtr, $0102
SetTextColor RegionHandlePtr, 2, 0
SetRegionColor RegionHandlePtr, 0
SetBackgroundPalette 16, $0040, TicketPalette
FadeIn 16
wait 16
API $0C6
DrawText RegionHandlePtr, Instructions1, 8, 4
API $08D
INCLUDE "../common/wait_for_link.asm"
SpriteShow SpriteHandlePtr
API $08D
ld a, b
nop
UNKNOWN_VALUE EQU $0078
INCLUDE "../common/wait_for_ready.asm"
DrawText RegionHandlePtr, DeliveryInProcess, 8, 4
DATA_TRANSFER_LENGTH EQU 6144
INCLUDE "../common/transfer_data.asm"
ld hl, $5fff
LD_IND_HL Space_1
API_0C7 Space_1
wait $80
SpriteHide SpriteHandlePtr
DrawText RegionHandlePtr, TicketDelivered, 8, 4
API $08D
ld c, a
nop
INCLUDE "../common/wrap_up.asm"
INCLUDE "../common/word_shift_right.asm"
SomeVar1: ; 1CA2
db $FF,0 ; mark EOF
RegionHandlePtr: db 0 ; 1CA4
SpriteHandlePtr: db 0,0 ; 1CA5
SomeVar2: db 0,0 ; 1CA7

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,40 @@
all: 00-C000-EN.raw verify
verify:
md5sum --check eonticket.md5
eonticket-%.tx: eonticket.asm
python ../scripts/regionalize.py $< $@ $* $*
eonticket-%.o: eonticket-%.tx
./rgbasm -o $@ $<
eonticket-%.gbc: eonticket-%.o
./rgblink -o $@ $<
eonticket-%.bin: eonticket-%.gbc
python ../scripts/stripgbc.py $< $@
eonticket-%.mev: eonticket-%.bin
python ../scripts/checksum.py $< $@
prologue-%.tx: prologue.asm
python ../scripts/regionalize.py $< $@ $* $*
prologue-%.o: prologue-%.tx
./rgbasm -o $@ $<
prologue-%.gbc: prologue-%.o
./rgblink -o $@ $<
prologue-%.bin: prologue-%.gbc
python ../scripts/stripgbc.py $< $@
00-C000-%.tx: 00-C000.asm eonticket-%.mev prologue-%.bin
python ../scripts/ereadertext.py $< $@ $*
00-C000-%.o: 00-C000-%.tx
./rgbasm -o $@ $<
00-C000-%.gbc: 00-C000-%.o
./rgblink -o $@ $<
00-C000-%.z80: 00-C000-%.gbc
python ../scripts/stripgbc.py $< $@
00-C000-%.vpk: 00-C000-%.z80
./nevpk -c -i $< -o $@
00-C000-%.raw: 00-C000-%.vpk
./nedcmake -i $< -o $@ -type 1 -region 1
clean:
rm -f *.tx *.o *.gbc *.z80 *.bin *.mev *.vpk *.raw

View File

@ -0,0 +1 @@
_F9W˙ýk¸SO;č"$˙µîr'f€Y|Ö^ÍA

Binary file not shown.

View File

@ -0,0 +1,40 @@
Start:
push {r0-r7} @Preserve gp registers
ldr r1, gMain @Player Movement type has to be 0x0B if gmain is #0 or else game crashes.
ldr r1, [r1, #12]
cmp r1, #0
mov r1, #0xB
bpl SetMoveType
add r1, r1, #0x63 @if it's not 0, we change it back to 6E.
SetMoveType:
ldr r2, MovementType
strb r1, [r2]
LoadFlashMemory: @To minimize code in PC slots, most of the setup code is in sector 30 of flash memory.
mov r0, #30
ldr r1, gSaveDataBuffer
ldr r3, ReadFlashSector
bl Branch
ldr r3, GAMELOADSETUP @most of actual setup code is in this file.
bl Branch
pop {r0-r7}
ldr r0, LRFix @this is what LR was when the game breaks at 02030401, so I restore it.
mov lr, r0
ldr r3, CB2_ReturnToFieldFadeFromBlack @this exits glitch movement type hook & restores normal player movement type.
Branch:
bx r3
.align
gMain:
.long 0x030022c0
MovementType: @this is where player movement type is in emerald, it's in gObjectEvents.
.long 0x02037356
CB2_ReturnToFieldFadeFromBlack: @reloads map & make sure player keeps facing same way. CB2_LoadMap2 always faces you down.
.long 0x080861e9
gSaveDataBuffer: @Save data buffer location.
.long 0x0203abbc
ReadFlashSector:
.long 0x0815314d
GAMELOADSETUP: @where GAMELOADSETUP is in RAM after loading it into gSaveDataBuffer.
.long 0x0203ac05
LRFix: @not sure what this is, but it's what LR is when movementtype broke, game crashes if I don't preserve.
.long 0x080069E7

Binary file not shown.

View File

@ -0,0 +1,14 @@
Seed:
push {r0-r7}
SetVBlankIntr_Ptr:
ldr r0, VBlankIntrPointer
ldr r1, VBlankIntr
str r1, [r0]
End:
pop {r0-r7}
bx lr
.align
VBlankIntrPointer:
.long 0x03002720
VBlankIntr:
.long 0x08000739

Binary file not shown.

View File

@ -0,0 +1,76 @@
TimerStart:
push {lr} @PUSH LR as a way to return to testegg.
ldr r0, sUnused @an unused spot in RAM I use as a timer for EMSEED.txt
mov r1, #1 @moving 1 into it starts my timer. When the timer finishes I reload pokemon into PC from gSaveDataBuffer.
str r1, [r0]
ldr r0, sUnusedOverworldCallback
str r1, [r0]
CheckIfSeedOn:
ldr r3, SeedLocation @I store the seed in the flash memory chip with this code.
mov r2, #12 @if the value here is 1 I don't do the seed process.
add r2, r3
ldrb r0, [r2]
cmp r0, #1
beq RestoreMusicRepelSettings
SeedRNG:
ldrh r0, [r3] @Load SeedLocations current value, should only be up to FFFF to keep 16 bit.
add r0, #1 @add 1 to it to increment.
ldr r1, gRNGValue @store in gRNGValue, where the LCGRNG will do its thing!
str r0, [r1]
str r0, [r3] @store seeds current value in flash memory sector.
RestoreMusicRepelSettings:
add r3, #4
ldr r0, [r3] @load last music setting
ldr r1, gDisableMusic
strb r0, [r1]
ldr r1, sMapMusicState
strb r0, [r1]
RestoreRepelSettings:
add r3, #4 @load last repel setting
ldr r0, [r3]
ldr r1, sWildEncountersDisabled
strb r0, [r1]
movs r0, #30 @this will save the new seed in the flash memory chip without the user having to save, so seed increment persists.
ldr r1, gSaveDataBuffer
ldr r3, TryWriteSector
bl Branch
ldr r0, VblankIntrLocation @Where my code that runs during VblankIntr currently is (in gSaveDataBuffer).
ldr r1, VBlankIntr_CheckSave @This is where in EWRAM I found to store my persistent vblankintr code. I haven't had it overwritten by normal gameplay so far.r
ldr r2, CopyAmountVblankIntr @Size of my vblankintr code.
swi #11 @memory copy
SetVBlankIntr_Ptr:
ldr r0, VBlankIntrPointer @change vblankintr pointer to my custom code location
ldr r1, VBlankIntr_CheckSave
str r1, [r0]
End:
pop {pc} @return to testegg.txt
Branch:
bx r3
.align
VBlankIntrPointer:
.long 0x03002720
VBlankIntr_CheckSave:
.long 0x0201b201 @my code that runs every frame. It's in EMSEED.txt file.
SeedLocation:
.long 0x0203AF1C @where initseed is stored relative to gSaveDataBuffer
gRNGValue:
.long 0x03005d80
gSaveDataBuffer:
.long 0x0203abbc @These two are the same, I originally didn't think they would be but didn't want to change code size once it all worked.
VblankIntrLocation:
.long 0x0203ac8c
CopyAmountVblankIntr: @amount of words & copy type for vblankintr code.
.long 0x040000A8
TryWriteSector:
.long 0x08152909
sUnused:
.long 0x02022c34
gDisableMusic:
.long 0x03005df8
sWildEncountersDisabled:
.long 0x02038c00
sMapMusicState:
.long 0x03000f4c
sUnusedOverworldCallback:
.long 0x03000e0c

View File

@ -0,0 +1,29 @@
Start:
ldr r1, CB2_LoadMap2
mov r4, #0
ldr r5, r5r6
ldr r6, r5r6
ldr r7, r7set
push {r0-r7}
mov r2, pc
add r2, #11
mov lr, r2
mov r0, #30
ldr r1, gSaveDataBufferFake
ldr r3, ReadFlashSector
bx r3
ldr r3, GAMELOADSETUP
bx r3
.align
gSaveDataBufferFake:
.long 0x0203abbc
ReadFlashSector:
.long 0x0815314d
GAMELOADSETUP: @TODO: update location
.long 0x0203AD11
CB2_LoadMap2:
.long 0x08085ffd
r5r6:
.long 0x030022B4
r7set:
.long 0x030022C0

View File

@ -0,0 +1,169 @@
IsWaiting: @to understand code properly, it might be better to start reading at HasSavedYet. IsWaiting, ClearWait, & EqualPreviousSave rely on code from it as they wait for a success state.
push {r0-r7} @preserve gp registers
mov r2, #255 @If my vblankintr is running during a save, game will crash.
add r2, #10 @IsWaiting is checking if a value in sUnused is 0.
ldr r1, sUnused @if it's not, it increments it by 1 until we reach 265. This is about how long the game takes to save.
ldr r0, [r1]
cmp r0, #0 @if the value here is 0, we go to the code that checks if we're currently saving.
beq HaveSavedYet
add r0, #1
cmp r0, r2
beq ClearWait @if the value is 265, we clear sUnused to 0 in ClearWait. This will end the timer.
str r0, [r1]
b ExitToVblankIntr @if the timer is above 0, but under 265, we immediately exit to regular vblankintr function.
ClearWait:
mov r0, #0 @this ends waiting timer.
str r0, [r1]
EqualPreviousSave: @when wait timer ends, we have to re-set some values to make the loop work again.
ldr r0, sUnusedOverworldCallback @This is where I store my save counter.
ldr r1, [r0]
ldr r2, gLastSaveCounter @if my counter is the same as the games previous counter, I know a save happend and have to update it.
ldr r2, [r2]
cmp r1, r2
bne HaveSavedYet @this should never actually trigger because clearwait always happens after a save finishes. Can remove probably.
ldr r2, gSaveCounter @I copy current value in gSaveCounter to sUnusedOverworldCallback (where I store my save counter).
ldr r2, [r2]
str r2, [r0]
mov r4, pc @set LR to line 34.
add r4, #11
mov lr, r4
movs r0, #30
ldr r1, gSaveDataBuffer @Load my data & code section 30 into 0x02010820. You can't use gSaveDataBuffer while the game is saving.
ldr r3, ReadFlashSector @forgot to change name of gSaveDataBuffer to gSaveDataBufferFake
bx r3
ldr r1, gPokemonStoragePtr @Load Pokemon Storage pointer to begin to restore PC Boxes post-save.
ldr r1, [r1] @gPokemonStoragePtr tells me where PC Boxes currently start.
ldr r2, Box12Slot13 @this is where box 12 slot 13 begins. Offset found using https://adrichu00.github.io/WhichBox/.
add r1, r2 @Adds offset to gPokemonStoragePtr
ldr r0, gSaveDataBuffer500 @this is 500 bytes into where save sector 30 was loaded. It's where I store the Pokemon so they don't overwrite my code.
ldr r2, CopyBoxSlots @This is how many words the 5 box slots I copy is, and which copy type to use.
SWI #11 @bios memory copy. r0 is source address, r1 is destination, r2 is word amount to copy.
HaveSavedYet: @Main Loop to check if saving.
ldr r0, gObjectEventPlayer @#110 = 0x6E glitch movement type.
mov r1, #110 @When I hook the save by checking gSaveCounter, part of saveblock1 is already done, including movement type.
strb r1, [r0] @I write the glitch movement type every frame to the players object event so that when we save, it's already done.
ldr r1, sUnusedOverworldCallback @check if sUnusedOverworldCallback is currently 0.
ldr r3, [r1]
cmp r3, #0
bne CheckSave @if it's not, check if we're saving.
ldr r0, gSaveCounter @if zero, put value from gSaveCounter in sUnusedOverworldCallback
ldr r0, [r0] @technically this setup fails if user has saved 0 times.
ldr r1, sUnusedOverworldCallback
str r0, [r1]
CheckSave:
ldr r0, gSaveCounter @to check if we're saving, I compare gSaveCounters current value to what it was on game load.
ldr r0, [r0]
ldr r1, sUnusedOverworldCallback
ldr r1, [r1]
cmp r0, r1
beq ExitToVblankIntr @if gSaveCounter and sUnusedOverworldCallback are equal, exit to normal vblankintr.
StoreBox:
ldr r0, sUnused @if not equal, hijack.
movs r1, #1 @Once success state is triggered, place 1 into sUnused for IsWaiting to begin its loop of 265 frames.
str r1, [r0]
mov r4, pc @Preserve LR to be line 71.
add r4, #11
mov lr, r4
movs r0, #30
ldr r1, gSaveDataBuffer @load value from save sector 30. I do not use actual gSaveDataBuffer. It's 0x02010820
ldr r3, ReadFlashSector @if you use gSaveDataBuffer while saving, game crashes / fails to save. So must use other address.
bx r3
ldr r0, gPokemonStoragePtr @Find current position of PC Boxes
ldr r0, [r0] @jump to offset of box 12 slot 13. Found with https://adrichu00.github.io/WhichBox/
ldr r1, Box12Slot13 @While entrypoint for 0x6E is statically 02030401, ASLR shifts which box slots this covers.
add r0, r1 @It can cover slot13 to slot16. So I 0 them out and start my code in box 17, so my code never goes above 02030401.
ldr r1, gSaveDataBuffer500 @This will copy box 12 slot 13 - box 12 slot 17 from the PC to 500 bytes into 0x02010820.
ldr r2, CopyBoxSlots @words & copy type of pokemon
SWI #11 @bios memory copy. r0 is source address, r1 is destination, r2 is word amount to copy.
ldr r0, gPokemonStoragePtr @similar to above, but instea of a bios memory copy, I do bios memory fill.
ldr r0, [r0]
ldr r1, Box12Slot13
add r1, r0
ldr r0, gUnusedControllerStruct @a space in ram that's always 0, so use that as word to fill.
ldr r2, FillBoxSlots @memorycopy/fill is controlled by bit 24 of length value in r2.
SWI #11 @bios memory fill. r0 is source address of value to fill, r1 is destination, r2 is word amount to fill.
mov r4, pc @preserve LR as line 92
add r4, #11
mov lr, r4
movs r0, #30 @saves Pokemon into sector 30!
ldr r1, gSaveDataBuffer
ldr r3, TryWriteSector
bx r3
BadEggCode:
ldr r0, gPokemonStoragePtr @location of pc boxes currently.
ldr r0, [r0]
ldr r1, Box17Offset @jump to offset of box 12 slot 17. Found with https://adrichu00.github.io/WhichBox/
add r1, r0 @this is where I will store the actual code in testegg.txt.
ldr r0, BadEggLocation @this is where in save sector 30 my code for box 17 is stored.
ldr r2, CopyBox17 @amount of words to copy. Coincidentally exactly 1 boxmon in length, otherwise I'd have to delete and store box 18 as well.
SWI #11 @bios memory copy. r0 is source address, r1 is destination, r2 is word amount to copy.
ExitToVblankIntr:
ldr r0, VBlankIntrLR @Restore proper LR VblankIntr needs.
mov lr, r0
AreInOW2:
ldr r0, gMain_CB2 @Check if we're in currently in overworld.
ldr r0, [r0]
ldr r1, CB2_OverworldBasic
cmp r0, r1 @if we are, exit to vblankintr
beq End
ldr r1, CB2_HallOfFame @check if we're in hall of fame. If we are, exit to vblankintr
cmp r0, r1
beq End
ldr r0, gObjectEventPlayer @if we're not in cb2 overworld, set gObjectEventPlayer movement type to 0x0B (movementtype player)
mov r1, #11 @movementtypecallback only updates on map load. So if we go into a menu, or battle, etc, game would crash.
strb r1, [r0] @since our code isn't in box slot 17 yet. By changing it to 0B, game behaves as normal every frame!
End:
pop {r0-r7}
ldr r3, VBlankIntr
bx r3
.align
gSaveCounter: @emeralds save counter. Compare to this to see if we have saved.
.long 0x03006200
VBlankIntr:
.long 0x08000739
VBlankIntrLR:
.long 0x0300287C
sUnusedOverworldCallback: @where I store my independant save counter.
.long 0x03000e0c
ReadFlashSector:
.long 0x0815314D
gSaveDataBuffer: @not actual gsavadatabuffer. Never changed name. Pick a random unused spot in ewram instead.
.long 0x02010820
gPokemonStoragePtr:
.long 0x03005d94
Box17Offset: @box 17 location relative to gPokemonStoragePtr.
.long 0x00006BF9
gSaveDataBuffer500: @where I store players pokemon in save sector 1e.
.long 0x02010D20
Box12Slot13: @box 13 location.
.long 0x00006AE4
CopyBoxSlots: @word amount of boxes 13-17.
.long 0x04000063
FillBoxSlots:
.long 0x05000063
VBlankCallBack:
.long 0x03002720
sUnused: @where I store my timer for IsWaiting
.long 0x02022c34
gLastSaveCounter:
.long 0x030061f4
gUnusedControllerStruct: @a value that is always 0.
.long 0x02022d0c
TryWriteSector:
.long 0x08152909
gObjectEventPlayer:
.long 0x02037356
gMain_CB2:
.long 0x30022c4
CB2_OverworldBasic:
.long 0x08085e5D
CB2_HallOfFame:
.long 0x08173561
CopyBox17: @box 17 word count.
.long 0x04000014
BadEggLocation: @where I store code for box 17.
.long 0x02010954
ValueSaveDialogeCallback:
.long 0x080A0235
sSaveDialogeCallback:
.long 0x0203761c

View File

@ -0,0 +1,28 @@
Start:
ldr r0, sUnusedOverworldCallback
ldr r3, [r0]
cmp r3, #0
bne ColoRNG
ldr r0, gRNGValue
ldr r3, [r0]
ColoRNG:
ldr r1, ColoMult
ldr r2, ColoAdd
mul r3, r1
add r3, r2
ldr r0, sUnusedOverworldCallback
str r3, [r0]
ldr r3, VBlankIntr
bx r3
.align
gRNGValue:
.long 0x03005d80
ColoMult:
.long 0x000343FD
ColoAdd:
.long 0x00269EC3
sUnusedOverworldCallback:
.long 0x03000e0c
VBlankIntr:
.long 0x08000739

View File

@ -0,0 +1,11 @@
Start:
ldr r0, VBlankIntrPointer
ldr r1, gsavedatabuffer
str r1, [r0]
bx lr
.align
VBlankIntrPointer:
.long 0x03002720
gsavedatabuffer:
.long 0x0203abbd

View File

@ -0,0 +1,45 @@
Start:
push {r0-r7} @Preserve gp registers
ldr r1, gMain @Player Movement type has to be 0x0B if gmain is #0 or else game crashes.
ldr r1, [r1, #12]
cmp r1, #0
mov r1, #0xB
bpl SetMoveType
add r1, r1, #0x63 @if it's not 0, we change it back to 6E.
SetMoveType:
ldr r2, MovementType
strb r1, [r2]
LoadFlashMemory: @To minimize code in PC slots, most of the setup code is in sector 30 of flash memory.
mov r2, pc @preserve lr to return to line 20.
add r2, #11
mov lr, r2
mov r0, #30
ldr r1, gSaveDataBufferFake
ldr r3, ReadFlashSector
bx r3
mov r2, pc @preserve registers to return to line 25.
add r2, #7
mov lr, r2
ldr r3, GAMELOADSETUP @most of actual setup code is in this file.
bx r3
pop {r0-r7}
ldr r0, LRFix @this is what LR was when the game breaks at 02030401, so I restore it.
mov lr, r0
ldr r3, CB2_ReturnToFieldFadeFromBlack @this exits glitch movement type hook & restores normal player movement type.
bx r3
.align
gMain:
.long 0x030022c0
MovementType: @this is where player movement type is in emerald, it's in gObjectEvents.
.long 0x02037356
CB2_ReturnToFieldFadeFromBlack: @reloads map & make sure player keeps facing same way. CB2_LoadMap2 always faces you down.
.long 0x080861e9
gSaveDataBufferFake: @Save data buffer location. I wrote fake because of an older version where I loaded it elsewhere.
.long 0x0203abbc
ReadFlashSector:
.long 0x0815314d
GAMELOADSETUP: @where GAMELOADSETUP is in RAM after loading it into gSaveDataBuffer.
.long 0x0203AD41
LRFix: @not sure what this is, but it's what LR is when movementtype broke, game crashes if I don't preserve.
.long 0x080069E7

View File

@ -0,0 +1,44 @@
ldr r0, gMain_callBack2
ldr r1, [r0]
ldr r2, CB2_InitBattle
cmp r1, r2
bne exit2
exit:
ldr r0, gEnemyParty
add r0, #0x54
mov r1, #100
ldrb r2, [r0]
cmp r1, r2
beq exit2
strb r1, [r0]
ldr r0, gEnemyParty
mov r1, #56
mov r2, #100
ldr r3, SetMonData
push {r4-r7}
mov r4, pc
add r4, #7
mov lr, r4
pop {r4-r7}
bx r3
exit2:
ldr r0, LRFIX
mov lr, r0
ldr r0, VBlankIntr
bx r0
.align
gMain_callBack2:
.long 0x03001774
gEnemyParty:
.long 0x030045c0
VBlankIntr:
.long 0x08000571
CB2_InitBattle:
.long 0x0800e7c5
SetMonData:
.long 0x0803d1fd
LRFIX:
.long 0x03001D0C

Binary file not shown.

View File

@ -0,0 +1,348 @@
IsWaiting: @to understand code properly, it might be better to start reading at CheckSave. IsWaiting, ClearWait, & EqualPreviousSave rely on code from it as they wait for a success state.
push {r0-r7} @preserve gp registers
mov r2, #255 @If my vblankintr is running during a save, game will crash.
add r2, #10 @IsWaiting is checking if a value in sUnused is 0.
ldr r1, sUnused @if it's not, it increments it by 1 until we reach 265. This is about how long the game takes to save.
ldr r0, [r1]
cmp r0, #0 @if the value here is 0, we go to the code that checks if we're currently saving.
beq CheckSave
add r0, #1
cmp r0, r2
beq ClearWait @if the value is 265, we clear sUnused to 0 in ClearWait. This will end the timer.
str r0, [r1]
b ExitToVblankIntr @if the timer is above 0, but under 265, we immediately exit to regular vblankintr function.
ClearWait:
mov r0, #0 @this ends waiting timer.
str r0, [r1] @if sUnusedOverworldCallback contains 1, a save happened and we run EqualPreviousSave
ldr r1, sUnusedOverworldCallback
ldr r0, [r1]
cmp r0, #1
bne CheckSave
EqualPreviousSave: @when wait timer ends, we have to re-set some values to make the loop work again.
mov r0, #0 @remove save check so can save again.
str r0, [r1]
mov r0, #30
ldr r1, gSaveDataBuffer @Load my data & code section 30 into 0x02010820. You can't use gSaveDataBuffer while the game is saving.
ldr r3, ReadFlashSector @forgot to change name of gSaveDataBuffer to gSaveDataBufferFake
bl Branch
ldr r1, gPokemonStoragePtr @Load Pokemon Storage pointer to begin to restore PC Boxes post-save / game load.
ldr r1, [r1] @gPokemonStoragePtr tells me where PC Boxes currently start.
ldr r2, Box12Slot13 @this is where box 12 slot 13 begins. Offset found using https://adrichu00.github.io/WhichBox/.
add r1, r2 @Adds offset to gPokemonStoragePtr
ldr r0, gSaveDataBuffer500 @this is 500 bytes into where save sector 30 was loaded. It's where I store the Pokemon so they don't overwrite my code.
ldr r2, CopyBoxSlots @This is how many words the 5 box slots I copy is, and which copy type to use.
SWI #11 @bios memory copy. r0 is source address, r1 is destination, r2 is word amount
CheckSave: @Main Loop to check if saving.
ldr r0, sSaveDialogeCallback @to check if we're saving, I see if sSaveDialogueCallback is 0x080A0235, which is for the NOW SAVING... text.
ldr r0, [r0]
ldr r1, ValueSaveDialogeCallback
cmp r0, r1
bne AreInOverWorld2 @if sSaveDialogeCallback is not equal to ValueSaveDialogeCallback(0x080A0235), exit to normal vblankintr.
StoreBox:
ldr r0, sUnused @if not equal, hijack.
mov r1, #1 @Once success state is triggered, place 1 into sUnused for IsWaiting to begin its loop of 265 frames.
str r1, [r0]
ldr r0, sUnusedOverworldCallback @set this callback to 1. If it's 1, EqualPreviousSave will trigger.
str r1, [r0]
ldr r0, gObjectEventPlayer @#110 = 0x6E glitch movement type.
mov r1, #110 @I write the glitch movement type every frame to the players object event so that when we save, it's the correct type.
strb r1, [r0]
movs r0, #30
ldr r1, gSaveDataBuffer @load value from save sector 30. I do not use actual gSaveDataBuffer. It's 0x02010820
ldr r3, ReadFlashSector @if you use gSaveDataBuffer while saving, game crashes / fails to save. So must use other address.
bl Branch
ldr r0, gPokemonStoragePtr @Find current position of PC Boxes
ldr r0, [r0] @jump to offset of box 12 slot 13. Found with https://adrichu00.github.io/WhichBox/
ldr r1, Box12Slot13 @While entrypoint for 0x6E is statically 02030401, ASLR shifts which box slots this covers.
add r0, r1 @It can cover slot13 to slot16. So I 0 them out and start my code in box 17, so my code never goes above 02030401.
ldr r1, gSaveDataBuffer500 @This will copy box 12 slot 13 - box 12 slot 17 from the PC to 500 bytes into 0x02010820.
ldr r2, CopyBoxSlots @words & copy type of pokemon
SWI #11 @bios memory copy. r0 is source address, r1 is destination, r2 is word amount to copy.
ldr r0, gPokemonStoragePtr @similar to above, but instea of a bios memory copy, I do bios memory fill.
ldr r0, [r0]
ldr r1, Box12Slot13
add r1, r0
ldr r0, gUnusedControllerStruct @a space in ram that's always 0, so use that as word to fill.
ldr r2, FillBoxSlots @memorycopy/fill is controlled by bit 24 of length value in r2.
SWI #11 @bios memory fill. r0 is source address of value to fill, r1 is destination, r2 is word amount to fill.
ldr r0, gDisableMusic @These are storing bools for whether or not disablemusic, wildneouncters, and the seed fix are enabled via butotn presses.
ldrb r0, [r0]
ldr r1, SeedLocation
add r1, #4
strb r0, [r1]
ldr r0, sWildEncountersDisabled
ldrb r0, [r0]
add r1, #4
strb r0, [r1]
ldr r0, sUnusedBattlersArray
ldrb r0, [r0]
add r1, #4
strb r0, [r1]
mov r0, #30 @saves Pokemon into sector 30!
ldr r1, gSaveDataBuffer
ldr r3, TryWriteSector
bl Branch
BadEggCode:
ldr r0, gPokemonStoragePtr @location of pc boxes currently.
ldr r0, [r0]
ldr r1, Box17Offset @jump to offset of box 12 slot 17. Found with https://adrichu00.github.io/WhichBox/
add r1, r0 @this is where I will store the actual code in testegg.txt.
ldr r0, BadEggLocation @this is where in save sector 30 my code for box 17 is stored.
ldr r2, CopyBox17 @amount of words to copy. Coincidentally exactly 1 boxmon in length, otherwise I'd have to delete and store box 18 as well.
SWI #11 @bios memory copy. r0 is source address, r1 is destination, r2 is word amount to copy.
b ExitToVblankIntr
AreInOverWorld2:
ldr r0, gMain_CB2 @Check if we're in currently in overworld.
ldr r0, [r0]
ldr r1, CB2_OverworldBasic
cmp r0, r1 @if we are, exit to vblankintr
bne AreInPartyMenu
CheckRButtonPress:
ldr r0, Buttons @Check value of button press against r button. This is a location in IO RAM. Buttons appear as halfword 3FF, and each button press subtracts from that value.
ldr r0, [r0]
ldr r1, RButton
cmp r0, r1
bne CheckRRight
ldr r0, gDisableMusic
ldrb r2, [r0]
mov r1, #1
eor r2, r1 @Hitting R Switches music on/off. gDisableMusic and MusicState can just be exclusive or'd to flip their bytes from 1 to 0 to turn them off.
strb r2, [r0]
ldr r3, sMapMusicState
strb r2, [r3]
cmp r2, #0 @if r2 ends up being 0, need to run playbgm.
beq TurnMusicOn
b DebounceTimer
TurnMusicOn:
ldr r3, PlayBGM
ldr r0, sMapMusicState
sub r0, #4
ldrh r0, [r0]
bl Branch
b DebounceTimer
CheckRRight:
ldr r1, RRightButtons
cmp r0, r1
bne CheckRSelect
ldr r0, sWildEncountersDisabled
ldrb r2, [r0]
mov r1, #1
eor r2, r1
strb r2, [r0]
b PlaySound
CheckRSelect:
ldr r1, SelectR
cmp r0, r1
bne AreInPartyMenu
ldr r0, sUnusedBattlersArray
ldrb r2, [r0]
mov r1, #1
eor r2, r1
strb r2, [r0]
b PlaySound
AreInPartyMenu:
ldr r0, gMain_CB2 @check if we're in party menu
ldr r2, [r0]
ldr r1, CB2_ReturnToPartyMenuFromSummaryScreen
cmp r2, r1
beq RestoreStats
ldr r1, CB2_ReturnToFieldWithOpenMenu
cmp r2, r1 @if we are, exit to vblankintr
beq LeavePartyMenu
ldr r2, [r0]
ldr r1, CB2_UpdatePartyMenu
cmp r2, r1
bne ExitToVblankIntr @if we're not, end.
sub r0, #4 @if we are in a battle, don't allow.
ldr r0, [r0]
ldr r1, BattleMainCB1
cmp r0, r1
beq ExitToVblankIntr
CheckButtonPress: @checks what buttons are being pressed in party menu for ev/iv viewer.
mov r4, #39 @value for HP IV Index for getmondata
ldr r0, Buttons
ldr r0, [r0]
ldr r1, SelectR
cmp r0, r1
beq ChangeStats @if select+r was pushed, do IV Check
ldr r1, SelectStart
cmp r0, r1
beq SetEVs
b ExitToVblankIntr
SetEVs:
mov r4, #26 @if start+select was pushed, move HP EV Index for getmondata into r4
ChangeStats:
ldr r0, gPlayerParty @load pokemon iv I want to edit
mov r5, r0 @copy gplayerparty into r5
mov r6, r0 @copy glayerparty into r6
PokemonLoop:
mov r1, #11 @check if species is 0, if it is, exit loop.
ldr r3, GetMonData2
bl Branch
cmp r0, #0
beq PlaySound
mov r0, r5
ldr r1, gEnemyParty @checks if we're at enemy party, if we are, exit loop
cmp r0, r1
beq PlaySound
mov r7, #0 @set up the ev/iv read loop.
add r5, #0x58 @if we're not done, add 0x58 to get to next pokemon in party
IVLoop:
mov r1, r4 @current iv index
add r1, r7
ldr r3, GetMonData2 @getmondata for evs or ivs based on what is in r4.
bl Branch
add r7, #1 @add 1 to loop counter
cmp r7, #6 @check if we've done 6 stats
bgt NextPokemon @if we have, stop loop and go to next pokemon
strh r0, [r5] @store IV or EV in stat
add r5, #2 @get to next raw stat location
mov r0, r6 @put current gplayerparty location back into r0.
b IVLoop
NextPokemon:
mov r6, r5
mov r0, r6
b PokemonLoop
PlaySound:
ldr r3, PlaySE
mov r0, #01
bl Branch
DebounceTimer:
ldr r0, sUnused
mov r1, #255
str r1, [r0]
b ExitToVblankIntr
LeavePartyMenu:
add r0, #8
ldr r2, [r0]
ldr r1, VBlankCB_PartyMenu
cmp r2, r1
bne ExitToVblankIntr
RestoreStats:
mov r7, #0
ldr r5, gPlayerParty
CalculateStatsLoop:
mov r4, r5
add r4, #86
ldrh r6, [r4]
ldr r3, CalculateMonStats
mov r0, r5
bl Branch
add r7, #1
strh r6, [r4]
add r5, #100
cmp r7, #6
bne CalculateStatsLoop
ldr r0, sUnused @if not equal, hijack.
mov r1, #255 @Once success state is triggered, place 1 into sUnused for IsWaiting to begin its loop of 265 frames.
str r1, [r0]
ExitToVblankIntr:
ldr r0, VBlankIntrLR @Restore proper LR VblankIntr needs.
mov lr, r0
AreInOW2:
ldr r1, MapHeaderBikeBool @check if we're in hall of fame. If we are, exit to vblankintr
mov r0, #0xF
strb r0, [r1]
ldr r0, gMain_CB2 @Check if we're in currently in overworld.
ldr r0, [r0]
ldr r1, CB2_OverworldBasic
cmp r0, r1 @if we are, exit to vblankintr
beq End
ldr r0, gObjectEventPlayer @if we're not in cb2 overworld, set gObjectEventPlayer movement type to 0x0B (movementtype player)
mov r1, #11 @movementtypecallback only updates on map load. So if we go into a menu, or battle, etc, game would crash.
strb r1, [r0] @since our code isn't in box slot 17 yet. By changing it to 0B, game behaves as normal every frame!
End:
pop {r0-r7}
ldr r3, VBlankIntr
Branch: @by using BL to go to this small function, the link register is set to the instruction after BL, and wherever I BX to will return there rather here.
bx r3
.align
VBlankIntr:
.long 0x08000739
VBlankIntrLR:
.long 0x0300287C
ReadFlashSector:
.long 0x0815314D
gSaveDataBuffer: @not actual gsavadatabuffer. Never changed name. Pick a random unused spot in ewram instead.
.long 0x02010820
gPokemonStoragePtr:
.long 0x03005d94
Box17Offset: @box 17 location relative to gPokemonStoragePtr.
.long 0x00006BF9
gSaveDataBuffer500: @where I store players pokemon in save sector 1e.
.long 0x02010D20
Box12Slot13: @box 13 location.
.long 0x00006AE4
CopyBoxSlots: @word amount of boxes 13-17.
.long 0x04000063
FillBoxSlots:
.long 0x05000063
VBlankCallBack:
.long 0x03002720
sUnused: @where I store my timer for IsWaiting
.long 0x02022c34
gUnusedControllerStruct: @a value that is always 0.
.long 0x02022d0c
TryWriteSector:
.long 0x08152909
gObjectEventPlayer:
.long 0x02037356
gMain_CB2:
.long 0x30022c4
CB2_OverworldBasic:
.long 0x08085e5D
MapHeaderBikeBool:
.long 0x02037332
CopyBox17: @box 17 word count.
.long 0x04000014
BadEggLocation: @where I store code for box 17.
.long 0x02010820
ValueSaveDialogeCallback:
.long 0x080A0235
sSaveDialogeCallback:
.long 0x0203761c
RButton:
.long 0x000002FF
RRightButtons:
.long 0x000002EF
Buttons:
.long 0x04000130
gDisableMusic:
.long 0x03005df8
sWildEncountersDisabled:
.long 0x02038c00
SeedLocation:
.long 0x02010b80 @where initseed is stored relative to gSaveDataBuffer
PlaySE:
.long 0x080a37a5
sMapMusicState:
.long 0x03000f4c
PlayBGM:
.long 0x080a3779
CB2_UpdatePartyMenu:
.long 0x081b01b1
gPlayerParty:
.long 0x020244ec
gEnemyParty:
.long 0x02024744
GetMonData2:
.long 0x0806a519
SelectR:
.long 0x000002fb
SelectStart:
.long 0x000003f3
BattleMainCB1:
.long 0x08039EF1
CB2_ReturnToPartyMenuFromSummaryScreen:
.long 0x081b3895
VBlankCB_PartyMenu:
.long 0x081b01cd
CalculateMonStats:
.long 0x08068d0D
CB2_ReturnToFieldWithOpenMenu:
.long 0x08086195
sUnusedOverworldCallback:
.long 0x03000e0c
sUnusedBattlersArray:
.long 0x02024284

Binary file not shown.

View File

@ -0,0 +1,178 @@
IsWaiting:
push {r0-r7}
mov r2, #255 @If my vblankintr is running during a save, game will crash.
add r2, #10 @IsWaiting is checking if a value in sUnused is 0.
ldr r1, sUnused @if it's not, it increments it by 1 until we reach 265. This is about how long the game takes to save.
ldr r0, [r1]
cmp r0, #0 @if the value here is 0, we go to the code that checks if we're currently saving.
beq AreInPartyMenu
add r0, #1
cmp r0, r2
beq ClearWait
str r0, [r1]
b ExitToVblankIntr
ClearWait:
mov r0, #0
str r0, [r1]
AreInPartyMenu:
ldr r0, gMain_CB2 @check if we're in party menu
ldr r2, [r0]
ldr r1, CB2_ReturnToFieldWithOpenMenu
cmp r2, r1 @if we are, exit to vblankintr
beq RestoreStats
ldr r2, [r0]
ldr r1, CB2_UpdatePartyMenu
cmp r2, r1
bne ExitToVblankIntr @if we're not, end.
sub r0, #4 @if we are in a battle, don't allow.
ldr r0, [r0]
ldr r1, BattleMainCB1
cmp r0, r1
beq ExitToVblankIntr
CheckButtonPress:
mov r4, #39
ldr r0, Buttons
ldr r0, [r0]
ldr r1, SelectR
cmp r0, r1
beq ChangeStats
ldr r1, SelectStart
cmp r0, r1
beq SetEVs
b ExitToVblankIntr
SetEVs:
mov r4, #26
ChangeStats:
ldr r0, sUnused @if not equal, hijack.
mov r1, #255 @Once success state is triggered, place 1 into sUnused for IsWaiting to begin its loop of 265 frames.
str r1, [r0]
ldr r0, gPlayerParty @load pokemon iv I want to edit
mov r5, r0 @copy r0 into r5
mov r6, r0
PokemonLoop:
mov r2, pc @preserve lr to return to after function
add r2, #9
mov lr, r2
mov r1, #11 @check if species is 0, if it is, exit loop.
ldr r3, GetMonData2
bx r3
cmp r0, #0
beq PlaySound
mov r0, r5
ldr r1, gEnemyParty
cmp r0, r1
beq PlaySound
mov r7, #0
add r5, #0x58
@cmp r4, #1
@beq EVLoop
IVLoop:
mov r2, pc @preserve lr to return to after function
add r2, #11
mov lr, r2
mov r1, r4
add r1, r7
ldr r3, GetMonData2
bx r3
add r7, #1
cmp r7, #6
bgt NextPokemon
strh r0, [r5]
add r5, #2
mov r0, r6
b IVLoop
@EVLoop:
@mov r2, pc @preserve lr to return to after function
@add r2, #11
@mov lr, r2
@mov r1, #26
@add r1, r7
@ldr r3, GetMonData2
@bx r3
@add r7, #1
@cmp r7, #6
@bgt NextPokemon
@strh r0, [r5]
@add r5, #2
@mov r0, r6
@.b EVLoop
NextPokemon:
mov r6, r5
mov r0, r6
b PokemonLoop
PlaySound:
mov r2, pc @preserve lr to return to after function
add r2, #9
mov lr, r2
ldr r3, PlaySE
mov r0, #01
bx r3
b ExitToVblankIntr
RestoreStats:
add r0, #8
ldr r2, [r0]
ldr r1, VBlankCB_PartyMenu
cmp r2, r1
bne ExitToVblankIntr
mov r7, #0
ldr r5, gPlayerParty
CalculateStatsLoop:
mov r4, r5
add r4, #86
ldrh r6, [r4]
mov r2, pc @preserve lr to return to after function
add r2, #9
mov lr, r2
ldr r3, CalculateMonStats
mov r0, r5
bx r3
add r7, #1
strh r6, [r4]
add r5, #100
cmp r7, #6
bne CalculateStatsLoop
ldr r0, sUnused @if not equal, hijack.
mov r1, #255 @Once success state is triggered, place 1 into sUnused for IsWaiting to begin its loop of 265 frames.
str r1, [r0]
ExitToVblankIntr:
ldr r0, VBlankIntrLR @Restore proper LR VblankIntr needs.
mov lr, r0
End:
pop {r0-r7}
ldr r3, VBlankIntr
bx r3
.align
VBlankIntr:
.long 0x08000739
VBlankIntrLR:
.long 0x0300287C
PlaySE:
.long 0x080a37a5
gMain_CB2:
.long 0x30022c4
CB2_UpdatePartyMenu:
.long 0x081b01b1
CB2_OverworldBasic:
.long 0x08085e5D
gPlayerParty:
.long 0x020244ec
gEnemyParty:
.long 0x02024744
GetMonData2:
.long 0x0806a519
SelectR:
.long 0x000002fb
SelectStart:
.long 0x000003f3
Buttons:
.long 0x04000130
sUnused: @where I store my timer for IsWaiting
.long 0x02022c34
BattleMainCB1:
.long 0x08039EF1
CB2_ReturnToFieldWithOpenMenu:
.long 0x08086195
VBlankCB_PartyMenu:
.long 0x081b01cd
CalculateMonStats:
.long 0x08068d0D

View File

@ -0,0 +1,179 @@
IsWaiting:
push {r0-r7}
mov r2, #255 @If my vblankintr is running during a save, game will crash.
add r2, #10 @IsWaiting is checking if a value in sUnused is 0.
ldr r1, sUnused @if it's not, it increments it by 1 until we reach 265. This is about how long the game takes to save.
ldr r0, [r1]
cmp r0, #0 @if the value here is 0, we go to the code that checks if we're currently saving.
beq AreInPartyMenu
add r0, #1
cmp r0, r2
beq ClearWait
str r0, [r1]
b ExitToVblankIntr
ClearWait:
mov r0, #0
str r0, [r1]
AreInPartyMenu:
ldr r0, gMain_CB2 @check if we're in party menu
ldr r2, [r0]
ldr r1, CB2_ReturnToPartyMenuFromSummaryScreen
cmp r2, r1
beq RestoreStats
ldr r2, [r0]
ldr r1, CB2_UpdatePartyMenu
cmp r2, r1
bne ExitToVblankIntr @if we're not, end.
sub r0, #4 @if we are in a battle, don't allow.
ldr r0, [r0]
ldr r1, BattleMainCB1
cmp r0, r1
beq ExitToVblankIntr
CheckButtonPress:
mov r4, #39
ldr r0, Buttons
ldr r0, [r0]
ldr r1, SelectR
cmp r0, r1
beq ChangeStats
ldr r1, SelectStart
cmp r0, r1
beq SetEVs
b ExitToVblankIntr
SetEVs:
mov r4, #26
ChangeStats:
ldr r0, sUnused @if not equal, hijack.
mov r1, #255 @Once success state is triggered, place 1 into sUnused for IsWaiting to begin its loop of 265 frames.
str r1, [r0]
ldr r0, gPlayerParty @load pokemon iv I want to edit
mov r5, r0 @copy r0 into r5
mov r6, r0
PokemonLoop:
mov r2, pc @preserve lr to return to after function
add r2, #9
mov lr, r2
mov r1, #11 @check if species is 0, if it is, exit loop.
ldr r3, GetMonData2
bx r3
cmp r0, #0
beq PlaySound
mov r0, r5
ldr r1, gEnemyParty
cmp r0, r1
beq PlaySound
mov r7, #0
add r5, #0x58
@cmp r4, #1
@beq EVLoop
IVLoop:
mov r2, pc @preserve lr to return to after function
add r2, #11
mov lr, r2
mov r1, r4
add r1, r7
ldr r3, GetMonData2
bx r3
add r7, #1
cmp r7, #6
bgt NextPokemon
strh r0, [r5]
add r5, #2
mov r0, r6
b IVLoop
@EVLoop:
@mov r2, pc @preserve lr to return to after function
@add r2, #11
@mov lr, r2
@mov r1, #26
@add r1, r7
@ldr r3, GetMonData2
@bx r3
@add r7, #1
@cmp r7, #6
@bgt NextPokemon
@strh r0, [r5]
@add r5, #2
@mov r0, r6
@.b EVLoop
NextPokemon:
mov r6, r5
mov r0, r6
b PokemonLoop
PlaySound:
mov r2, pc @preserve lr to return to after function
add r2, #9
mov lr, r2
ldr r3, PlaySE
mov r0, #01
bx r3
b ExitToVblankIntr
RestoreStats:
@add r0, #8
@ldr r2, [r0]
@ldr r1, VBlankCB_PartyMenu
@cmp r2, r1
@bne ExitToVblankIntr
mov r7, #0
ldr r5, gPlayerParty
CalculateStatsLoop:
mov r4, r5
add r4, #86
ldrh r6, [r4]
mov r2, pc @preserve lr to return to after function
add r2, #9
mov lr, r2
ldr r3, CalculateMonStats
mov r0, r5
bx r3
add r7, #1
strh r6, [r4]
add r5, #100
cmp r7, #6
bne CalculateStatsLoop
ldr r0, sUnused @if not equal, hijack.
mov r1, #255 @Once success state is triggered, place 1 into sUnused for IsWaiting to begin its loop of 265 frames.
str r1, [r0]
ExitToVblankIntr:
ldr r0, VBlankIntrLR @Restore proper LR VblankIntr needs.
mov lr, r0
End:
pop {r0-r7}
ldr r3, VBlankIntr
bx r3
.align
VBlankIntr:
.long 0x08000739
VBlankIntrLR:
.long 0x0300287C
CB2_UpdatePartyMenu:
.long 0x081b01b1
PlaySE:
.long 0x080a37a5
gMain_CB2:
.long 0x30022c4
CB2_OverworldBasic:
.long 0x08085e5D
gPlayerParty:
.long 0x020244ec
gEnemyParty:
.long 0x02024744
GetMonData2:
.long 0x0806a519
SelectR:
.long 0x000002fb
SelectStart:
.long 0x000003f3
Buttons:
.long 0x04000130
sUnused: @where I store my timer for IsWaiting
.long 0x02022c34
BattleMainCB1:
.long 0x08039EF1
CB2_ReturnToPartyMenuFromSummaryScreen:
.long 0x081b3895
VBlankCB_PartyMenu:
.long 0x081b01cd
CalculateMonStats:
.long 0x08068d0D

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,22 @@
Seed:
push {r0-r7} @preserve gp registers.
ldr r0, VblankIntrLocation @copy code that runs every frame from gsavedatabuffer to a random safe spot in ewram I found.
ldr r1, VBlankIntr_CheckSave
ldr r2, CopyAmountVblankIntr
swi #11 @bios memory copy. r0 is source address, r1 is destination, r2 is word amount to copy.
SetVBlankIntr_Ptr:
ldr r0, VBlankIntrPointer @change vblankintr current pointer to 0x0201b201, said random safe ewram spot.
ldr r1, VBlankIntr_CheckSave
str r1, [r0]
End:
pop {r0-r7} @restore gp registers.
bx lr
.align
VBlankIntrPointer: @SeedLocation & gRNGValue are currently unused, can delete.
.long 0x03002720
VBlankIntr_CheckSave:
.long 0x0201b201
VblankIntrLocation:
.long 0x0203ac8c
CopyAmountVblankIntr: @Change wordcount. wordcount of EMSEED.txt
.long 0x040000A8

View File

@ -0,0 +1,11 @@
Start:
mov r0, #30
ldr r1, gSaveDataBuffer
ldr r3, ReadFlashSector
bx r3
.align
gSaveDataBuffer:
.long 0x0203abbc
ReadFlashSector:
.long 0x0815314d

View File

@ -0,0 +1,232 @@
INCLUDE "../macros.asm"
INCLUDE "../constants/items.asm"
INCLUDE "../constants/scriptcommandsseedfix2.asm"
Mystery_Event
db CHECKSUM_CRC
dd 0 ; checksum placeholder
GBAPTR DataStart
GBAPTR DataEnd
DataStart:
db IN_GAME_SCRIPT
db 1,4 ; Elms lab
db 1 ; science boy
GBAPTR NormanScriptStart
GBAPTR NormanScriptEnd
db PRELOAD_SCRIPT
GBAPTR PreloadScriptStart
db END_OF_CHUNKS
PreloadScriptStart:
setvirtualaddress PreloadScriptStart
callasm $0201C045
virtualloadpointer GoSeeYourFather
setbyte 2
dw $0000
end
WriteFlashMemory
GLITCHMOVECALLBACK
SEEDRNGANDFIXSAVE
VBLANKINTR_CHECKSAVE
dd $0
dd $0
dd $0
dd $0
GoSeeYourFather:
Text_DE "Lauf und besuche deinen Vater in der\n"
Text_DE "ARENA von BLÜTENBURG CITY.@"
Text_EN "Talk to one of Prof. Elms aides\n"
Text_EN "to UPGRADE your Emerald!@"
end
NormanScriptStart:
setvirtualaddress NormanScriptStart
lockall
faceplayer
writebytetoaddr $1E, $2024744
writebytetoaddr $20, $2024745
writebytetoaddr $01, $2024746
writebytetoaddr $49, $2024747
writebytetoaddr $01, $2024748
writebytetoaddr $4B, $2024749
writebytetoaddr $18, $202474A
writebytetoaddr $47, $202474B
writebytetoaddr $BC, $202474C
writebytetoaddr $AB, $202474D
writebytetoaddr $03, $202474E
writebytetoaddr $02, $202474F
writebytetoaddr $4D, $2024750
writebytetoaddr $31, $2024751
writebytetoaddr $15, $2024752
writebytetoaddr $08, $2024753
callasm $02024745 ;readflash
pause $10
comparefarbytetobyte $03002720, $01
virtualgotoif 1, VblankIntr_Off
VblankIntr_On:
virtualmsgbox IsOff
waitmsg
db $6E, $17, $8
release
lockall
compare LASTRESULT, 0
virtualgotoif 1, Changemind
sound $4
waitfanfare
writebytetoaddr $FF, $2024744
writebytetoaddr $B4, $2024745
writebytetoaddr $06, $2024746
writebytetoaddr $48, $2024747
writebytetoaddr $04, $2024748
writebytetoaddr $49, $2024749
writebytetoaddr $06, $202474A
writebytetoaddr $4A, $202474B
writebytetoaddr $0B, $202474C
writebytetoaddr $DF, $202474D
writebytetoaddr $02, $202474E
writebytetoaddr $48, $202474F
writebytetoaddr $02, $2024750
writebytetoaddr $49, $2024751
writebytetoaddr $01, $2024752
writebytetoaddr $60, $2024753
writebytetoaddr $FF, $2024754
writebytetoaddr $BC, $2024755
writebytetoaddr $70, $2024756
writebytetoaddr $47, $2024757
writebytetoaddr $20, $2024758
writebytetoaddr $27, $2024759
writebytetoaddr $00, $202475A
writebytetoaddr $03, $202475B
writebytetoaddr $01, $202475C
writebytetoaddr $B2, $202475D
writebytetoaddr $01, $202475E
writebytetoaddr $02, $202475F
writebytetoaddr $8C, $2024760
writebytetoaddr $AC, $2024761
writebytetoaddr $03, $2024762
writebytetoaddr $02, $2024763
writebytetoaddr $A8, $2024764
writebytetoaddr $00, $2024765
writebytetoaddr $00, $2024766
writebytetoaddr $04, $2024767
callasm $02024745 ;initialsetup.txt
virtualmsgbox TurnedOn
waitmsg
waitkeypress
release
end
VblankIntr_Off:
copybyte $020375e2, $203AF1C
copybyte $020375e3, $203AF1D
buffernumber $00, $8005
virtualmsgbox CurrentSeed
waitmsg
db $6E, $17, $8
release
lockall
compare LASTRESULT, 0
virtualgotoif 1, Changemind
sound $3
waitfanfare
writebytetoaddr $ff, $2024744
writebytetoaddr $b4, $2024745
writebytetoaddr $02, $2024746
writebytetoaddr $48, $2024747
writebytetoaddr $02, $2024748
writebytetoaddr $49, $2024749
writebytetoaddr $01, $202474A
writebytetoaddr $60, $202474B
writebytetoaddr $ff, $202474C
writebytetoaddr $bc, $202474D
writebytetoaddr $70, $202474E
writebytetoaddr $47, $202474F
writebytetoaddr $20, $2024750
writebytetoaddr $27, $2024751
writebytetoaddr $00, $2024752
writebytetoaddr $03, $2024753
writebytetoaddr $39, $2024754
writebytetoaddr $07, $2024755
writebytetoaddr $00, $2024756
writebytetoaddr $08, $2024757
callasm $02024745 ;resetpr.txt
virtualmsgbox TurnedOn
waitmsg
waitkeypress
release
pause $10
writebytetoaddr $0B, $02037356
end
Changemind:
virtualmsgbox Change
waitmsg
waitkeypress
release
end
IsOff:
Text_EN "Would you like UPGRADE your Emerald\n"
Text_EN "experience?@"
TurnedOn:
Text_EN "Done! Now you have to save the\n"
Text_EN "game for it to stick!@"
Change:
Text_EN "If you change your mind, Im here!@"
CurrentSeed:
Text_EN "Your current Initial Seed is\n"
Text_EN "\v2! Would you like me to turn the\l"
Text_EN "upgrade off?@"
NormanScriptEnd:
DataEnd:
EOF

View File

@ -0,0 +1 @@
901180e44767e19e5dc9d5df881fe123 00-C000-EN.z80

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,15 @@
INCLUDE "../macros.asm"
SECTION "prologue", ROM0[$100]
db "GameFreak inc."
db 0,0,0,0,0,0
dd 0
Text "e reader" ; no string terminator
db 0,0,0,0,$01,$55
db 0,0,0,0
db REGION
db 0
db "GameFreak inc."
db 0,0
EOF

Binary file not shown.

Binary file not shown.