diff options
Diffstat (limited to 'gba/source')
-rw-r--r-- | gba/source/gamedata.c | 167 | ||||
-rw-r--r-- | gba/source/gamedata.h | 191 | ||||
-rw-r--r-- | gba/source/main.c | 86 | ||||
-rw-r--r-- | gba/source/savestructs.h | 7 | ||||
-rw-r--r-- | gba/source/serialize.c | 227 | ||||
-rw-r--r-- | gba/source/serialize.h | 19 |
6 files changed, 655 insertions, 42 deletions
diff --git a/gba/source/gamedata.c b/gba/source/gamedata.c index bbcf4dd..ae593b1 100644 --- a/gba/source/gamedata.c +++ b/gba/source/gamedata.c | |||
@@ -7,7 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | #include "gamedata.h" | 8 | #include "gamedata.h" |
9 | 9 | ||
10 | void decryptSaveStructures( | 10 | static void decryptSaveStructures( |
11 | pSaveBlock1 SaveBlock1, | 11 | pSaveBlock1 SaveBlock1, |
12 | pSaveBlock2 SaveBlock2, | 12 | pSaveBlock2 SaveBlock2, |
13 | pSaveBlock3 SaveBlock3) | 13 | pSaveBlock3 SaveBlock3) |
@@ -119,10 +119,15 @@ void decryptSaveStructures( | |||
119 | *xor_key_ptr = 0; | 119 | *xor_key_ptr = 0; |
120 | } | 120 | } |
121 | 121 | ||
122 | bool initSaveData( | 122 | static void CryptBoxPokemon(struct BoxPokemon* pkm) |
123 | pSaveBlock1* SaveBlock1, | 123 | { |
124 | pSaveBlock2* SaveBlock2, | 124 | for (u32 i = 0; i < 12; i++) |
125 | pSaveBlock3* SaveBlock3) | 125 | { |
126 | pkm->secure.raw[i] ^= (pkm->otId ^ pkm->personality); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | bool initSaveData(struct GameData* gameData) | ||
126 | { | 131 | { |
127 | // check the ROM code, make sure this game is supported. | 132 | // check the ROM code, make sure this game is supported. |
128 | u8* ROM = (u8*) 0x8000000; | 133 | u8* ROM = (u8*) 0x8000000; |
@@ -135,6 +140,9 @@ bool initSaveData( | |||
135 | pSaveBlock1 gSaveBlock1; | 140 | pSaveBlock1 gSaveBlock1; |
136 | pSaveBlock2 gSaveBlock2; | 141 | pSaveBlock2 gSaveBlock2; |
137 | pSaveBlock3 gSaveBlock3; | 142 | pSaveBlock3 gSaveBlock3; |
143 | struct BaseStats* gBaseStats; | ||
144 | const u32 (*gExpTables)[101]; | ||
145 | const u16* gNatOrder; | ||
138 | //u32 titlemid = 0; | 146 | //u32 titlemid = 0; |
139 | 147 | ||
140 | // get the address of the save loading function. | 148 | // get the address of the save loading function. |
@@ -337,6 +345,9 @@ bool initSaveData( | |||
337 | //mainloop = (void(*)()) 0x8000429; | 345 | //mainloop = (void(*)()) 0x8000429; |
338 | //titlemid = 0x807928f; | 346 | //titlemid = 0x807928f; |
339 | //load_pokemon = (void(*)()) 0x804c245; | 347 | //load_pokemon = (void(*)()) 0x804c245; |
348 | gBaseStats = (struct BaseStats*) ( GAME_FR ? 0 : 0x82547d0 ); | ||
349 | gExpTables = (ExperienceTables) ( GAME_FR ? 0 : 0x8253b30 ); | ||
350 | gNatOrder = (const u16*) ( GAME_FR ? 0 : 0x825203a ); | ||
340 | 351 | ||
341 | break; | 352 | break; |
342 | } | 353 | } |
@@ -504,9 +515,149 @@ bool initSaveData( | |||
504 | // applicable. | 515 | // applicable. |
505 | decryptSaveStructures(gSaveBlock1,gSaveBlock2,gSaveBlock3); | 516 | decryptSaveStructures(gSaveBlock1,gSaveBlock2,gSaveBlock3); |
506 | 517 | ||
507 | *SaveBlock1 = gSaveBlock1; | 518 | gameData->SaveBlock1 = gSaveBlock1; |
508 | *SaveBlock2 = gSaveBlock2; | 519 | gameData->SaveBlock2 = gSaveBlock2; |
509 | *SaveBlock3 = gSaveBlock3; | 520 | gameData->SaveBlock3 = gSaveBlock3; |
521 | gameData->baseStats = gBaseStats; | ||
522 | gameData->expTables = gExpTables; | ||
523 | gameData->natOrder = gNatOrder; | ||
510 | 524 | ||
511 | return true; | 525 | return true; |
512 | } | 526 | } |
527 | |||
528 | void DecryptPokemon(struct Pokemon* pkm) | ||
529 | { | ||
530 | struct BoxPokemon* boxMon = &(pkm->box); | ||
531 | |||
532 | CryptBoxPokemon(boxMon); | ||
533 | } | ||
534 | |||
535 | void DecryptBoxPokemon(struct BoxPokemon* pkm) | ||
536 | { | ||
537 | CryptBoxPokemon(pkm); | ||
538 | } | ||
539 | |||
540 | void EncryptPokemon(struct Pokemon* pkm) | ||
541 | { | ||
542 | struct BoxPokemon* boxMon = &(pkm->box); | ||
543 | |||
544 | EncryptBoxPokemon(boxMon); | ||
545 | } | ||
546 | |||
547 | void EncryptBoxPokemon(struct BoxPokemon* pkm) | ||
548 | { | ||
549 | FixBoxPokemonChecksum(pkm); | ||
550 | CryptBoxPokemon(pkm); | ||
551 | } | ||
552 | |||
553 | union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId) | ||
554 | { | ||
555 | struct BoxPokemon* boxMon = &(pkm->box); | ||
556 | |||
557 | return GetBoxPokemonSubstruct(boxMon,substructId); | ||
558 | } | ||
559 | |||
560 | union PokemonSubstruct* GetBoxPokemonSubstruct( | ||
561 | struct BoxPokemon* pkm, | ||
562 | u8 substructId) | ||
563 | { | ||
564 | if (substructId > 3) | ||
565 | { | ||
566 | return NULL; | ||
567 | } | ||
568 | |||
569 | u32 personality = pkm->personality; | ||
570 | u32 modulo = (personality % 24); | ||
571 | |||
572 | // Staring at the substruct indexes, I noticed the last two columns are the | ||
573 | // reverse of the first two! that is, substructId==2 column is the reverse of | ||
574 | // substructId==1, substructId==3 is the reverse of substructId==0. | ||
575 | // At least that means there's no need to hardcode all four. | ||
576 | u8 substruct_idxes[2][24] = { | ||
577 | { 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3 }, | ||
578 | { 1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2 } | ||
579 | }; | ||
580 | |||
581 | if (substructId < 2) | ||
582 | { | ||
583 | return &(pkm->secure.substructs[substruct_idxes[substructId][modulo]]); | ||
584 | } | ||
585 | |||
586 | return &(pkm->secure.substructs[ | ||
587 | substruct_idxes[3 - substructId][23 - modulo]]); | ||
588 | } | ||
589 | |||
590 | u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm) | ||
591 | { | ||
592 | u16 checksum = 0; | ||
593 | |||
594 | union PokemonSubstruct* substructs[4] = { | ||
595 | GetBoxPokemonSubstruct(pkm,0), | ||
596 | GetBoxPokemonSubstruct(pkm,1), | ||
597 | GetBoxPokemonSubstruct(pkm,2), | ||
598 | GetBoxPokemonSubstruct(pkm,3) | ||
599 | }; | ||
600 | |||
601 | for (int substruct = 0; substruct < 4; substruct++) | ||
602 | { | ||
603 | for (int i = 0; i < 6; i++) | ||
604 | { | ||
605 | checksum += substructs[substruct]->raw[i]; | ||
606 | } | ||
607 | } | ||
608 | |||
609 | return checksum; | ||
610 | } | ||
611 | |||
612 | void FixBoxPokemonChecksum(struct BoxPokemon* pkm) | ||
613 | { | ||
614 | pkm->checksum = CalculateBoxPokemonChecksum(pkm); | ||
615 | } | ||
616 | |||
617 | struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm) | ||
618 | { | ||
619 | struct BoxPokemon* boxMon = &(pkm->box); | ||
620 | |||
621 | return GetBoxPokemonSubstruct0(boxMon); | ||
622 | } | ||
623 | |||
624 | struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm) | ||
625 | { | ||
626 | return &(GetBoxPokemonSubstruct(pkm,0)->type0); | ||
627 | } | ||
628 | |||
629 | struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm) | ||
630 | { | ||
631 | struct BoxPokemon* boxMon = &(pkm->box); | ||
632 | |||
633 | return GetBoxPokemonSubstruct1(boxMon); | ||
634 | } | ||
635 | |||
636 | struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm) | ||
637 | { | ||
638 | return &(GetBoxPokemonSubstruct(pkm,1)->type1); | ||
639 | } | ||
640 | |||
641 | struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm) | ||
642 | { | ||
643 | struct BoxPokemon* boxMon = &(pkm->box); | ||
644 | |||
645 | return GetBoxPokemonSubstruct2(boxMon); | ||
646 | } | ||
647 | |||
648 | struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm) | ||
649 | { | ||
650 | return &(GetBoxPokemonSubstruct(pkm,2)->type2); | ||
651 | } | ||
652 | |||
653 | struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm) | ||
654 | { | ||
655 | struct BoxPokemon* boxMon = &(pkm->box); | ||
656 | |||
657 | return GetBoxPokemonSubstruct3(boxMon); | ||
658 | } | ||
659 | |||
660 | struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm) | ||
661 | { | ||
662 | return &(GetBoxPokemonSubstruct(pkm,3)->type3); | ||
663 | } | ||
diff --git a/gba/source/gamedata.h b/gba/source/gamedata.h index 4d0a2a9..247626a 100644 --- a/gba/source/gamedata.h +++ b/gba/source/gamedata.h | |||
@@ -21,9 +21,192 @@ | |||
21 | 21 | ||
22 | #define LANG_JAPAN ((*(u8*)(0x80000AF)) == 'J') | 22 | #define LANG_JAPAN ((*(u8*)(0x80000AF)) == 'J') |
23 | 23 | ||
24 | bool initSaveData( | 24 | typedef const u32 (*ExperienceTables)[101]; |
25 | pSaveBlock1* SaveBlock1, | 25 | |
26 | pSaveBlock2* SaveBlock2, | 26 | struct GameData { |
27 | pSaveBlock3* SaveBlock3); | 27 | pSaveBlock1 SaveBlock1; |
28 | pSaveBlock2 SaveBlock2; | ||
29 | pSaveBlock3 SaveBlock3; | ||
30 | struct BaseStats* baseStats; | ||
31 | ExperienceTables expTables; | ||
32 | const u16* natOrder; | ||
33 | }; | ||
34 | |||
35 | bool initSaveData(struct GameData* gameData); | ||
36 | |||
37 | /** | ||
38 | * Decrypts the substructures of a Pokémon structure, so they can be viewed or | ||
39 | * modified easily. | ||
40 | * | ||
41 | * Remember to call EncryptPokemon() afterwards. | ||
42 | * | ||
43 | * @param pkm The Pokémon to decrypt the substructures of. | ||
44 | */ | ||
45 | void DecryptPokemon(struct Pokemon* pkm); | ||
46 | |||
47 | /** | ||
48 | * Decrypts the substructures of a core Pokémon structure, so they can be viewed | ||
49 | * or modified easily. | ||
50 | * | ||
51 | * Used by DecryptPokemon(). | ||
52 | * | ||
53 | * Remember to call EncryptPokemon() afterwards. | ||
54 | * | ||
55 | * @param pkm The BoxPokemon to decrypt the substructures of. | ||
56 | */ | ||
57 | void DecryptBoxPokemon(struct BoxPokemon* pkm); | ||
58 | |||
59 | /** | ||
60 | * Encrypts the substructures of a Pokémon structure, and fixes the checksum. | ||
61 | * | ||
62 | * Must be used after DecryptPokemon() has been called, otherwise the Pokémon | ||
63 | * you decrypted and forgot to re-encrypt will become a Bad Egg. | ||
64 | * | ||
65 | * @param pkm The Pokémon to encrypt the substructures and fix | ||
66 | * the checksum of. | ||
67 | */ | ||
68 | void EncryptPokemon(struct Pokemon* pkm); | ||
69 | |||
70 | /** | ||
71 | * Encrypts the substructures of a core Pokémon structure, and fixes the | ||
72 | * checksum. | ||
73 | * | ||
74 | * Must be used after DecryptBoxPokemon() has been called, otherwise the Pokémon | ||
75 | * you decrypted and forgot to re-encrypt will become a Bad Egg. | ||
76 | * | ||
77 | * @param pkm The BoxPokemon to encrypt the substructures and fix the checksum | ||
78 | * of. | ||
79 | */ | ||
80 | void EncryptBoxPokemon(struct BoxPokemon* pkm); | ||
81 | |||
82 | /** | ||
83 | * Gets a substructure of a Pokémon structure. | ||
84 | * | ||
85 | * Call DecryptPokemon() first or the substructure data will be encrypted. | ||
86 | * | ||
87 | * @param pkm The Pokemon to get a substructure of. | ||
88 | * @param substructId The substructure to get. | ||
89 | * | ||
90 | * @return The substructure. | ||
91 | */ | ||
92 | union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId); | ||
93 | |||
94 | /** | ||
95 | * Gets a substructure of a core Pokémon structure. | ||
96 | * | ||
97 | * Call DecryptBoxPokemon() first or the substructure data will be encrypted. | ||
98 | * | ||
99 | * @param pkm The Pokemon to get a substructure of. | ||
100 | * @param substructId The substructure to get. | ||
101 | * | ||
102 | * @return The substructure. | ||
103 | */ | ||
104 | union PokemonSubstruct* GetBoxPokemonSubstruct( | ||
105 | struct BoxPokemon* pkm, | ||
106 | u8 substructId); | ||
107 | |||
108 | /** | ||
109 | * Gets the checksum of a core Pokémon structure. | ||
110 | * | ||
111 | * @param pkm The BoxPokemon to calculate the checksum of. | ||
112 | * | ||
113 | * @return The checksum. | ||
114 | */ | ||
115 | u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm); | ||
116 | |||
117 | /** | ||
118 | * Fixes the checksum of a core Pokémon structure. | ||
119 | * | ||
120 | * @param pkm The BoxPokemon to fix the checksum of. | ||
121 | */ | ||
122 | void FixBoxPokemonChecksum(struct BoxPokemon* pkm); | ||
123 | |||
124 | /** | ||
125 | * Gets the zeroth substructure ("Growth") of a Pokémon structure. | ||
126 | * | ||
127 | * Call DecryptPokemon() first or the substructure data will be encrypted. | ||
128 | * | ||
129 | * @param pkm The Pokémon to get a substructure of. | ||
130 | * | ||
131 | * @return The substructure. | ||
132 | */ | ||
133 | struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm); | ||
134 | |||
135 | /** | ||
136 | * Gets the zeroth substructure ("Growth") of a core Pokémon structure. | ||
137 | * | ||
138 | * Call DecryptBoxPokemon() first or the substructure data will be encrypted. | ||
139 | * | ||
140 | * @param pkm The BoxPokemon to get the substructure of. | ||
141 | * | ||
142 | * @return The substructure. | ||
143 | */ | ||
144 | struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm); | ||
145 | |||
146 | /** | ||
147 | * Gets the first substructure ("Attacks") of a Pokémon structure. | ||
148 | * | ||
149 | * Call DecryptPokemon() first or the substructure data will be encrypted. | ||
150 | * | ||
151 | * @param pkm The Pokémon to get a substructure of. | ||
152 | * | ||
153 | * @return The substructure. | ||
154 | */ | ||
155 | struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm); | ||
156 | |||
157 | /** | ||
158 | * Gets the first substructure ("Attacks") of a core Pokémon structure. | ||
159 | * | ||
160 | * Call DecryptBoxPokemon() first or the substructure data will be encrypted. | ||
161 | * | ||
162 | * @param pkm The BoxPokemon to get the substructure of. | ||
163 | * | ||
164 | * @return The substructure. | ||
165 | */ | ||
166 | struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm); | ||
167 | |||
168 | /** | ||
169 | * Gets the second substructure ("EVs & Condition") of a Pokémon structure. | ||
170 | * | ||
171 | * Call DecryptPokemon() first or the substructure data will be encrypted. | ||
172 | * | ||
173 | * @param pkm The Pokémon to get a substructure of. | ||
174 | * | ||
175 | * @return The substructure. | ||
176 | */ | ||
177 | struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm); | ||
178 | |||
179 | /** | ||
180 | * Gets the second substructure ("EVs & Condition") of a core Pokémon structure. | ||
181 | * | ||
182 | * Call DecryptBoxPokemon() first or the substructure data will be encrypted. | ||
183 | * | ||
184 | * @param pkm The BoxPokemon to get the substructure of. | ||
185 | * | ||
186 | * @return The substructure. | ||
187 | */ | ||
188 | struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm); | ||
189 | |||
190 | /** | ||
191 | * Gets the third substructure ("Miscellaneous") of a Pokémon structure. | ||
192 | * | ||
193 | * Call DecryptPokemon() first or the substructure data will be encrypted. | ||
194 | * | ||
195 | * @param pkm The Pokémon to get a substructure of. | ||
196 | * | ||
197 | * @return The substructure. | ||
198 | */ | ||
199 | struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm); | ||
200 | |||
201 | /** | ||
202 | * Gets the third substructure ("Miscellaneous") of a core Pokémon structure. | ||
203 | * | ||
204 | * Call DecryptBoxPokemon() first or the substructure data will be encrypted. | ||
205 | * | ||
206 | * @param pkm The BoxPokemon to get the substructure of. | ||
207 | * | ||
208 | * @return The substructure. | ||
209 | */ | ||
210 | struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm); | ||
28 | 211 | ||
29 | #endif | 212 | #endif |
diff --git a/gba/source/main.c b/gba/source/main.c index 14d2f1d..aeb05af 100644 --- a/gba/source/main.c +++ b/gba/source/main.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <gba.h> | 7 | #include <gba.h> |
8 | #include "gamedata.h" | 8 | #include "gamedata.h" |
9 | #include "link.h" | 9 | #include "link.h" |
10 | #include "serialize.h" | ||
10 | 11 | ||
11 | int main(void) | 12 | int main(void) |
12 | { | 13 | { |
@@ -42,11 +43,9 @@ int main(void) | |||
42 | waitForAck(); | 43 | waitForAck(); |
43 | 44 | ||
44 | // Get access to save data. | 45 | // Get access to save data. |
45 | pSaveBlock1 SaveBlock1; | 46 | struct GameData gameData; |
46 | pSaveBlock2 SaveBlock2; | ||
47 | pSaveBlock3 SaveBlock3; | ||
48 | 47 | ||
49 | if (!initSaveData(&SaveBlock1, &SaveBlock2, &SaveBlock3)) | 48 | if (!initSaveData(&gameData)) |
50 | { | 49 | { |
51 | // Unsupported game version. | 50 | // Unsupported game version. |
52 | sendS32(-1); | 51 | sendS32(-1); |
@@ -63,13 +62,13 @@ int main(void) | |||
63 | 62 | ||
64 | if (GAME_RS) | 63 | if (GAME_RS) |
65 | { | 64 | { |
66 | trainerName = SaveBlock2->rs.playerName; | 65 | trainerName = gameData.SaveBlock2->rs.playerName; |
67 | } else if (GAME_FRLG) | 66 | } else if (GAME_FRLG) |
68 | { | 67 | { |
69 | trainerName = SaveBlock2->frlg.playerName; | 68 | trainerName = gameData.SaveBlock2->frlg.playerName; |
70 | } else if (GAME_EM) | 69 | } else if (GAME_EM) |
71 | { | 70 | { |
72 | trainerName = SaveBlock2->e.playerName; | 71 | trainerName = gameData.SaveBlock2->e.playerName; |
73 | } | 72 | } |
74 | 73 | ||
75 | u32 tn1 = | 74 | u32 tn1 = |
@@ -94,20 +93,24 @@ int main(void) | |||
94 | u8* trainerId = 0; | 93 | u8* trainerId = 0; |
95 | if (GAME_RS) | 94 | if (GAME_RS) |
96 | { | 95 | { |
97 | trainerId = SaveBlock2->rs.playerTrainerId; | 96 | trainerId = gameData.SaveBlock2->rs.playerTrainerId; |
98 | } else if (GAME_FRLG) | 97 | } else if (GAME_FRLG) |
99 | { | 98 | { |
100 | trainerId = SaveBlock2->frlg.playerTrainerId; | 99 | trainerId = gameData.SaveBlock2->frlg.playerTrainerId; |
101 | } else if (GAME_EM) | 100 | } else if (GAME_EM) |
102 | { | 101 | { |
103 | trainerId = SaveBlock2->e.playerTrainerId; | 102 | trainerId = gameData.SaveBlock2->e.playerTrainerId; |
104 | } | 103 | } |
105 | 104 | ||
106 | u32 tti = | 105 | u16 trainerIdNum = |
107 | (trainerId[1] << 8) | 106 | (trainerId[1] << 8) |
108 | | (trainerId[0]); | 107 | | (trainerId[0]); |
109 | 108 | ||
110 | sendU32(tti); | 109 | u16 secretIdNum = |
110 | (trainerId[3] << 8) | ||
111 | | (trainerId[2]); | ||
112 | |||
113 | sendU32(trainerIdNum); | ||
111 | waitForAck(); | 114 | waitForAck(); |
112 | 115 | ||
113 | // Does the player want to import this game? | 116 | // Does the player want to import this game? |
@@ -120,22 +123,22 @@ int main(void) | |||
120 | u8* pokedexSeen = 0; | 123 | u8* pokedexSeen = 0; |
121 | if (GAME_RS) | 124 | if (GAME_RS) |
122 | { | 125 | { |
123 | pokedexSeen = SaveBlock2->rs.pokedex.seen; | 126 | pokedexSeen = gameData.SaveBlock2->rs.pokedex.seen; |
124 | } else if (GAME_FRLG) | 127 | } else if (GAME_FRLG) |
125 | { | 128 | { |
126 | pokedexSeen = SaveBlock2->frlg.pokedex.seen; | 129 | pokedexSeen = gameData.SaveBlock2->frlg.pokedex.seen; |
127 | } else if (GAME_EM) | 130 | } else if (GAME_EM) |
128 | { | 131 | { |
129 | pokedexSeen = SaveBlock2->e.pokedex.seen; | 132 | pokedexSeen = gameData.SaveBlock2->e.pokedex.seen; |
130 | } | 133 | } |
131 | 134 | ||
132 | for (int i=0; i<13; i++) | 135 | for (int i=0; i<13; i++) |
133 | { | 136 | { |
134 | u32 psi = | 137 | u32 psi = |
135 | (pokedexSeen[i*4]) | 138 | (pokedexSeen[i*4] << 24) |
136 | | (pokedexSeen[i*4+1] << 8) | 139 | | (pokedexSeen[i*4+1] << 16) |
137 | | (pokedexSeen[i*4+2] << 16) | 140 | | (pokedexSeen[i*4+2] << 8) |
138 | | (pokedexSeen[i*4+3] << 24); | 141 | | (pokedexSeen[i*4+3]); |
139 | 142 | ||
140 | directSendU32(psi); | 143 | directSendU32(psi); |
141 | } | 144 | } |
@@ -143,23 +146,54 @@ int main(void) | |||
143 | u8* pokedexCaught = 0; | 146 | u8* pokedexCaught = 0; |
144 | if (GAME_RS) | 147 | if (GAME_RS) |
145 | { | 148 | { |
146 | pokedexCaught = SaveBlock2->rs.pokedex.owned; | 149 | pokedexCaught = gameData.SaveBlock2->rs.pokedex.owned; |
147 | } else if (GAME_FRLG) | 150 | } else if (GAME_FRLG) |
148 | { | 151 | { |
149 | pokedexCaught = SaveBlock2->frlg.pokedex.owned; | 152 | pokedexCaught = gameData.SaveBlock2->frlg.pokedex.owned; |
150 | } else if (GAME_EM) | 153 | } else if (GAME_EM) |
151 | { | 154 | { |
152 | pokedexCaught = SaveBlock2->e.pokedex.owned; | 155 | pokedexCaught = gameData.SaveBlock2->e.pokedex.owned; |
153 | } | 156 | } |
154 | 157 | ||
155 | for (int i=0; i<13; i++) | 158 | for (int i=0; i<13; i++) |
156 | { | 159 | { |
157 | u32 psi = | 160 | u32 psi = |
158 | (pokedexCaught[i*4]) | 161 | (pokedexCaught[i*4] << 24) |
159 | | (pokedexCaught[i*4+1] << 8) | 162 | | (pokedexCaught[i*4+1] << 16) |
160 | | (pokedexCaught[i*4+2] << 16) | 163 | | (pokedexCaught[i*4+2] << 8) |
161 | | (pokedexCaught[i*4+3] << 24); | 164 | | (pokedexCaught[i*4+3]); |
162 | 165 | ||
163 | directSendU32(psi); | 166 | directSendU32(psi); |
164 | } | 167 | } |
168 | |||
169 | // Start sending over party pokémon. | ||
170 | struct Pokemon* playerParty = 0; | ||
171 | if (GAME_RS) | ||
172 | { | ||
173 | playerParty = gameData.SaveBlock1->rs.playerParty; | ||
174 | } else if (GAME_FRLG) | ||
175 | { | ||
176 | playerParty = gameData.SaveBlock1->frlg.playerParty; | ||
177 | } else if (GAME_EM) | ||
178 | { | ||
179 | playerParty = gameData.SaveBlock1->e.playerParty; | ||
180 | } | ||
181 | |||
182 | waitForResponse(); | ||
183 | |||
184 | u32 partyCount = 1; | ||
185 | |||
186 | sendU32(partyCount); | ||
187 | waitForAck(); | ||
188 | |||
189 | for (int pki=0; pki<partyCount; pki++) | ||
190 | { | ||
191 | struct Pokemon* pkm = (playerParty + pki); | ||
192 | struct BoxPokemon* bpkm = &(pkm->box); | ||
193 | |||
194 | struct PokemonIntermediate pki; | ||
195 | |||
196 | PokemonIntermediateInit(&pki, bpkm, trainerIdNum, secretIdNum, &gameData); | ||
197 | PokemonIntermediateStream(&pki); | ||
198 | } | ||
165 | } | 199 | } |
diff --git a/gba/source/savestructs.h b/gba/source/savestructs.h index 2bf4d4d..fb8ef36 100644 --- a/gba/source/savestructs.h +++ b/gba/source/savestructs.h | |||
@@ -9,9 +9,7 @@ | |||
9 | 9 | ||
10 | // Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity | 10 | // Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity |
11 | 11 | ||
12 | #define POKEMON_NAME_LENGTH 10 | 12 | #include "pokemon.h" |
13 | #define OT_NAME_LENGTH 7 | ||
14 | #define TILE_SIZE_4BPP 32 | ||
15 | 13 | ||
16 | struct Coords16 | 14 | struct Coords16 |
17 | { | 15 | { |
@@ -495,6 +493,7 @@ struct BaseStats | |||
495 | /* 0x17 */ u8 ability2; | 493 | /* 0x17 */ u8 ability2; |
496 | /* 0x18 */ u8 safariZoneFleeRate; | 494 | /* 0x18 */ u8 safariZoneFleeRate; |
497 | /* 0x19 */ u8 bodyColor; | 495 | /* 0x19 */ u8 bodyColor; |
496 | u16 filler; | ||
498 | }; | 497 | }; |
499 | 498 | ||
500 | struct BattleMove | 499 | struct BattleMove |
@@ -790,4 +789,4 @@ struct Pokedex | |||
790 | /*0x0C*/ u32 unknown3; | 789 | /*0x0C*/ u32 unknown3; |
791 | /*0x10*/ u8 owned[52]; | 790 | /*0x10*/ u8 owned[52]; |
792 | /*0x44*/ u8 seen[52]; | 791 | /*0x44*/ u8 seen[52]; |
793 | }; \ No newline at end of file | 792 | }; |
diff --git a/gba/source/serialize.c b/gba/source/serialize.c new file mode 100644 index 0000000..6303772 --- /dev/null +++ b/gba/source/serialize.c | |||
@@ -0,0 +1,227 @@ | |||
1 | #include "serialize.h" | ||
2 | #include "gamedata.h" | ||
3 | #include "link.h" | ||
4 | |||
5 | #define UNOWN_SPECIES_INDEX 201 | ||
6 | #define SHEDINJA_SPECIES_INDEX 303 | ||
7 | |||
8 | enum Stat { | ||
9 | StatAttack, | ||
10 | StatDefense, | ||
11 | StatSpeed, | ||
12 | StatSpAttack, | ||
13 | StatSpDefense | ||
14 | }; | ||
15 | |||
16 | u32 CalculateStat( | ||
17 | u8 base, | ||
18 | u32 iv, | ||
19 | u8 ev, | ||
20 | u8 level, | ||
21 | u8 statIndex, | ||
22 | u8 nature) | ||
23 | { | ||
24 | u32 n = (((2 * base + iv + ev / 4) * level) / 100) + 5; | ||
25 | |||
26 | u8 naturePlus = (nature / 5); | ||
27 | u8 natureMinus = (nature % 5); | ||
28 | |||
29 | if (naturePlus != natureMinus) | ||
30 | { | ||
31 | if (statIndex == naturePlus) | ||
32 | { | ||
33 | return (u32)(n * 110) / 100; | ||
34 | } else if (statIndex == natureMinus) | ||
35 | { | ||
36 | return (u32)(n * 90) / 100; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | return n; | ||
41 | } | ||
42 | |||
43 | void PokemonIntermediateInit( | ||
44 | struct PokemonIntermediate* pki, | ||
45 | struct BoxPokemon* bpkm, | ||
46 | u16 trainerId, | ||
47 | u16 secretId, | ||
48 | const struct GameData* gameData) | ||
49 | { | ||
50 | DecryptBoxPokemon(bpkm); | ||
51 | |||
52 | struct PokemonSubstruct0* sub0 = GetBoxPokemonSubstruct0(bpkm); | ||
53 | struct PokemonSubstruct1* sub1 = GetBoxPokemonSubstruct1(bpkm); | ||
54 | struct PokemonSubstruct2* sub2 = GetBoxPokemonSubstruct2(bpkm); | ||
55 | struct PokemonSubstruct3* sub3 = GetBoxPokemonSubstruct3(bpkm); | ||
56 | |||
57 | struct BaseStats* baseStats = &gameData->baseStats[sub0->species]; | ||
58 | |||
59 | for (int i=0; i<POKEMON_NAME_LENGTH; i++) | ||
60 | { | ||
61 | pki->nickname[i] = bpkm->nickname[i]; | ||
62 | } | ||
63 | |||
64 | for (int i=0; i<OT_NAME_LENGTH; i++) | ||
65 | { | ||
66 | pki->otName[i] = bpkm->otName[i]; | ||
67 | } | ||
68 | |||
69 | pki->otId = bpkm->otId; | ||
70 | pki->otGender = sub3->otGender; | ||
71 | pki->species = gameData->natOrder[sub0->species - 1]; | ||
72 | pki->heldItem = sub0->heldItem; | ||
73 | pki->experience = sub0->experience; | ||
74 | |||
75 | pki->moves[0] = sub1->moves[0]; | ||
76 | pki->moves[1] = sub1->moves[1]; | ||
77 | pki->moves[2] = sub1->moves[2]; | ||
78 | pki->moves[3] = sub1->moves[3]; | ||
79 | |||
80 | pki->ppBonuses = sub0->ppBonuses; | ||
81 | pki->metLevel = sub3->metLevel; | ||
82 | pki->metLocation = sub3->metLocation; | ||
83 | pki->pokeball = sub3->pokeball; | ||
84 | pki->altAbility = sub3->altAbility; | ||
85 | |||
86 | // Derive nature from the personality value. | ||
87 | pki->nature = (bpkm->personality % 25); | ||
88 | |||
89 | // Derive gender from the personality value. | ||
90 | int genderThreshold = baseStats->genderRatio; | ||
91 | |||
92 | if ((genderThreshold == 0) || (genderThreshold == 255)) | ||
93 | { | ||
94 | pki->gender = 0; | ||
95 | } else if (genderThreshold == 254) | ||
96 | { | ||
97 | pki->gender = 1; | ||
98 | } else { | ||
99 | u8 genderDeterminer = bpkm->personality & 0x000000FF; | ||
100 | |||
101 | if (genderDeterminer >= genderThreshold) | ||
102 | { | ||
103 | pki->gender = 0; | ||
104 | } else { | ||
105 | pki->gender = 1; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // Determine shininess from the personality value. | ||
110 | u16 shinyDeterminer = | ||
111 | (trainerId) | ||
112 | ^ (secretId) | ||
113 | ^ ((bpkm->personality >> 16) & 0x0000FFFF) | ||
114 | ^ (bpkm->personality & 0x0000FFFF); | ||
115 | |||
116 | if (shinyDeterminer < 8) | ||
117 | { | ||
118 | pki->shiny = 1; | ||
119 | } else { | ||
120 | pki->shiny = 0; | ||
121 | } | ||
122 | |||
123 | // Determine Unown letter from the personality value. | ||
124 | if (sub0->species == UNOWN_SPECIES_INDEX) | ||
125 | { | ||
126 | u8 unownDeterminer = | ||
127 | ((bpkm->personality & 0x07000000) >> 18) | ||
128 | | ((bpkm->personality & 0x00070000) >> 12) | ||
129 | | ((bpkm->personality & 0x00000700) >> 6) | ||
130 | | (bpkm->personality & 0x00000007); | ||
131 | |||
132 | pki->unownLetter = (unownDeterminer % 28); | ||
133 | } | ||
134 | |||
135 | // Calculate level from experience. | ||
136 | pki->level = 1; | ||
137 | |||
138 | const u32* expTable = gameData->expTables[baseStats->growthRate]; | ||
139 | while ((pki->level <= 100) && (expTable[pki->level] <= sub0->experience)) | ||
140 | { | ||
141 | pki->level++; | ||
142 | } | ||
143 | |||
144 | pki->level--; | ||
145 | |||
146 | // Calculate stats. | ||
147 | if (sub0->species == SHEDINJA_SPECIES_INDEX) | ||
148 | { | ||
149 | pki->hp = 1; | ||
150 | } else { | ||
151 | u32 n = 2 * baseStats->baseHP + sub3->hpIV; | ||
152 | pki->hp = (((n + sub2->hpEV / 4) * pki->level) / 100) + pki->level + 10; | ||
153 | } | ||
154 | |||
155 | pki->attack = CalculateStat( | ||
156 | baseStats->baseAttack, | ||
157 | sub3->attackIV, | ||
158 | sub2->attackEV, | ||
159 | pki->level, | ||
160 | 0, | ||
161 | pki->nature); | ||
162 | |||
163 | pki->defense = CalculateStat( | ||
164 | baseStats->baseDefense, | ||
165 | sub3->defenseIV, | ||
166 | sub2->defenseEV, | ||
167 | pki->level, | ||
168 | 1, | ||
169 | pki->nature); | ||
170 | |||
171 | pki->speed = CalculateStat( | ||
172 | baseStats->baseSpeed, | ||
173 | sub3->speedIV, | ||
174 | sub2->speedEV, | ||
175 | pki->level, | ||
176 | 2, | ||
177 | pki->nature); | ||
178 | |||
179 | pki->spAttack = CalculateStat( | ||
180 | baseStats->baseSpAttack, | ||
181 | sub3->spAttackIV, | ||
182 | sub2->spAttackEV, | ||
183 | pki->level, | ||
184 | 3, | ||
185 | pki->nature); | ||
186 | |||
187 | pki->spDefense = CalculateStat( | ||
188 | baseStats->baseSpDefense, | ||
189 | sub3->spDefenseIV, | ||
190 | sub2->spDefenseEV, | ||
191 | pki->level, | ||
192 | 4, | ||
193 | pki->nature); | ||
194 | |||
195 | // Approximate the values of the contest conditions. | ||
196 | pki->cool = ((u16)(sub2->cool) * 10) / 255; | ||
197 | pki->beauty = ((u16)(sub2->beauty) * 10) / 255; | ||
198 | pki->cute = ((u16)(sub2->cute) * 10) / 255; | ||
199 | pki->smart = ((u16)(sub2->smart) * 10) / 255; | ||
200 | pki->tough = ((u16)(sub2->tough) * 10) / 255; | ||
201 | pki->sheen = ((u16)(sub2->sheen) * 10) / 255; | ||
202 | |||
203 | // Determine Pokerus status. | ||
204 | if (sub3->pokerus & 0xF0) | ||
205 | { | ||
206 | if (sub3->pokerus & 0x0F) | ||
207 | { | ||
208 | pki->pokerus = 1; | ||
209 | } else { | ||
210 | pki->pokerus = 2; | ||
211 | } | ||
212 | } else { | ||
213 | pki->pokerus = 0; | ||
214 | } | ||
215 | |||
216 | EncryptBoxPokemon(bpkm); | ||
217 | } | ||
218 | |||
219 | void PokemonIntermediateStream(struct PokemonIntermediate* pki) | ||
220 | { | ||
221 | u32* raw = (u32*)pki; | ||
222 | |||
223 | for (int i=0; i<(sizeof(struct PokemonIntermediate)/4); i++) | ||
224 | { | ||
225 | directSendU32(raw[i]); | ||
226 | } | ||
227 | } | ||
diff --git a/gba/source/serialize.h b/gba/source/serialize.h new file mode 100644 index 0000000..21049c5 --- /dev/null +++ b/gba/source/serialize.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef POKEMON_H_67C60AC1 | ||
2 | #define POKEMON_H_67C60AC1 | ||
3 | |||
4 | #include <gba.h> | ||
5 | |||
6 | struct BoxPokemon; | ||
7 | struct PokemonIntermediate; | ||
8 | struct GameData; | ||
9 | |||
10 | void PokemonIntermediateInit( | ||
11 | struct PokemonIntermediate* pki, | ||
12 | struct BoxPokemon* bpkm, | ||
13 | u16 trainerId, | ||
14 | u16 secretId, | ||
15 | const struct GameData* gameData); | ||
16 | |||
17 | void PokemonIntermediateStream(struct PokemonIntermediate* pki); | ||
18 | |||
19 | #endif /* end of include guard: POKEMON_H_67C60AC1 */ | ||