123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- .align 2
- .thumb
- /*A very pertinent problem arose from the study of Variables. The fact is, we
- never knew much about them, and just used them. But in the end, those variables
- were, in fact, pieces of other program's memory. Solution is to find a location
- where we can lay our own variables, and use those to our advantage.
- Every pokemon game accesses variables through the same mechanism every time.
- Variable is accessed by using a call to a specialized function, that because of
- its lack of boundaries, let us use every piece of code there as our own.
- The proposed solution is to find a large RAM address (0x1000 long) and use it to
- make a place for 0x800 variables (something like 0x5000 to 0x57ff.) This should
- be enough for most games, and they're perfectly safe. Then, during the Save and
- Load Routines, add a new module to load from 0xe01f000 (bank1, slot f), that is
- unused by the game, and can carry that much information.
- Also proposed, to solve the problem, is to use any variable from 0x5800 to 0x5fff
- as a mirror to the first pair, any variable from 0x6000 to 0x6fff as a byte-load
- for the 0x5000 variables, and any from the 0x7000 as a word-load for the 0x5000
- variable family, and 0x7400-0x7fff as flag-load for some select few.*/
- /*first, and most important, we need the 0x5000 flags stored somewhere, even if
- the game didn't save them. That is where the Var-Decrypt come in.*/
- /*var decrypt is located at 0x0806E454. Because most of the code is harmless in
- its own, we will only change the part that loads variables above 0x4000 and below
- 0x8000. That is located at 0x6e4f2. We change 0x6e4f4 to 0x10 47, and place the
- pointer to this function at 0x6e508
- Even though Emerald code is different, it's in fact much simpler. As such all
- old rules apply. at 0809D682 place 10 47 and at 0809D690 the pointer*/
- /*begin*/
- Var_decrypt_change: mov r1, #0x50
- lsl r1, r1, #0x8
- sub r1, r6, r1 /*if it is lower than 0x5000, it will be less than 0*/
- cmp r1, #0x0
- blt is_4xxx
- mov r2, #0x80
- lsl r2, r2, #0x4
- cmp r1, r2 /*r2 = 0x800*/
- blt load_5xxx
- sub r1, r1, r2
- cmp r1, r2 /*r2 = 0x800, this is the mirrored line*/
- blt load_5xxx
- sub r1, r1, r2
- lsl r2, #0x1
- cmp r1, r2
- blt load_6xxx
- sub r1, r1, r2
- lsr r2, r2, #0x2
- cmp r1, r2
- blt load_7xxx
- mov r0, #0x0
- pop {r4-r6,pc}
-
- is_4xxx: ldr r2, mask_9x
- lsl r1, r6, #0x1
- add r1, r2, r1
- ldr r0, [r0]
- add r0, r0, r1
- pop {r4-r6,pc}
-
- load_7xxx: lsl r1, r1, #0x1 /*r1<<2 = word address */
- load_5xxx: lsl r1, r1, #0x1 /*r1 << 1 = halfword address*/
- load_6xxx: ldr r0, new_var_location /*no shift means byte address*/
- add r0, r0, r1
- pop {r4-r6,pc}
- .hword 0x0000
- mask_9x: .word 0xffff9000 /*for Emerald, it's 0xffff939c*/
- new_var_location: .word 0x0203e000
- /*end*/
- /*the other way to load variables is through the Variable Loader. But that raises
- a problem: It only loads halfwords. To solve that problem, at 0806e574, place
- 0049 0847 pointer to this
- In Emerald, place at 0809d6a0 the 0049 0847 pointer to this
- */
- /*begin*/
- VarLoader_change: cmp r0, #0x0
- beq no_variable_loaded
- mov r1, #0x60
- lsl r1, r1, #0x8
- sub r1, r4, r1
- cmp r1, #0x0
- blt var_load_hword
- mov r2, #0x80
- lsl r2, r2, #0x8
- cmp r4, r2
- bge var_load_hword
- lsr r2, r2, #0x3
- sub r1, r1, r2
- cmp r1, #0x0
- blt var_load_byte
- ldr r0, [r0]
- pop {r4,pc}
-
- no_variable_loaded: add r0, r4, #0x0
- pop {r4, pc}
-
- var_load_byte: ldrb r0, [r0]
- pop {r4,pc}
-
- var_load_hword: ldrh r0, [r0]
- pop {r4,pc}
- .hword 0x0000
- /*end*/
- /*var store will be fixed for Storing only 0x4000-0x6fff.
- That way, you can have byte storage for variables
- In Fire Red, place at 0x0806E584 30 b5 05 04 28 0c
- at 0x0806E592 01 49 08 47 00 00 pointer
- In Emerald, place at 0x0809d6b0 30 b5 05 04 28 0c
- at 0x0809d6be 01 49 08 47 00 00 pointer
- */
- /*begin*/
- Var_store_cont: cmp r0, #0x0
- beq no_store
-
- mov r1, #0x60
- lsl r1, r1, #0x8
- sub r1, r5, r1
- cmp r1, #0x0
- blt var_store_hword
- mov r2, #0x80
- lsl r2, r2, #0x8
- cmp r5, r2
- bge var_store_hword
- lsr r2, r2, #0x3
- sub r1, r1, r2
- cmp r1, #0x0
- blt var_store_byte
- no_store: pop {r4-r5,pc}
-
- var_store_byte: strb r4, [r0]
- pop {r4-r5,pc}
-
- var_store_hword: strh r4, [r0]
- pop {r4-r5,pc}
- /*end*/
- /*finally, we need to save those variables from being purged at the end of the
- game. So, we will modify the Save file to allow us to keep the variables
- somewhere where nobody gets hurt (bank 0x1f)*/
- /*this first code is the save one, and allows us to save the new variable
- location at bank 0x1f. for that, we need to edit the code at 080D9838, right
- after the standart save is finished. Lucky, that is a load that has a pointer!
- Then, change 0x080d983a with 00 47 and 0x080D986C with the pointer to this.
- In Emerald, change 0x0815276a with 00 47 and 0x0815279C with the pointer */
- /*begin*/
- Save_vars: mov r0, #0x1f
- ldr r1, variable_new_addr
- bl SetFlash4k
- ldr r1, Save_ret
- sub r6, #0x4
- ldr r0, [r6]
- add r6, #0x4
- bx r1
- .hword 0x0000
- Save_ret: .word 0x080D983d /*in Emerald, change this to 0815276d*/
-
- /*end*/
- /*then we also need the Load code. This one is more wordy, as we need to
- load byte by byte the entire content we need from the Flash.
- In Emerald, the location to change is 0x08152ea0
- In fire red, the location to change is 0x080D9EE4
- place a 0048 0047 pointer. We'll take care of exiting the
- function*/
- /*begin*/
- Load_Vars: bl SetSecondBank
- ldr r0, variable_new_addr
- mov r1, #0xf0
- lsl r1, r1, #0x8
- orr r3, r1
- mov r2, #0x10
- lsl r2, r2, #0x8
- byte_load_loop: ldrb r1, [r3]
- strb r1, [r0]
- add r0, #0x1
- add r3, #0x1
- sub r2, #0x1
- cmp r2, #0x0
- bgt byte_load_loop
- add r0, r5, #0x0
- pop {r1}
- mov r8, r1
- pop {r4-r7, pc}
- .hword 0x0000
- /*end*/
- variable_new_addr: .word 0x0203e000
- SetFlash4k: ldr r3, set_flash_addr
- bx r3
- set_flash_addr: .word 0x081DF071 /*for emerald, 0x082E20Ad*/
- SetSecondBank: mov r3, #0x0e
- mov r2, #0x55
- lsl r3, r3, #0x18
- lsl r1, r2, #0x8 /*r1 = 5500*/
- orr r1, r3 /*r1 = 0e005500*/
- orr r1, r2 /*r1 = 0e005555*/
- mov r0, #0xAA
- strb r0, [r1]
- mov r2, #0x2a
- lsl r2, r2, #0x8 /*r2 = 2a00*/
- orr r2, r0 /*r2 = 2aaa*/
- orr r2, r3 /*r2 = 0e002aaa*/
- mov r0, #0x55
- strb r0, [r2]
- mov r0, #0xb0
- strb r0, [r1]
- mov r0, #0x1
- strb r0, [r3]
- bx lr
-
|