about summary refs log tree commit diff stats
path: root/gba
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2017-08-18 13:49:00 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2017-08-18 13:49:00 -0400
commit08dfb0aa80668b80c4a31bd064f5f2d729e5b7f6 (patch)
treeb46baa9353c0919efaed4349d2207958fa0bfaf5 /gba
parenta19507262602fa31f9f14a9e4f4e03e375bca111 (diff)
downloadgen3uploader-08dfb0aa80668b80c4a31bd064f5f2d729e5b7f6.tar.gz
gen3uploader-08dfb0aa80668b80c4a31bd064f5f2d729e5b7f6.tar.bz2
gen3uploader-08dfb0aa80668b80c4a31bd064f5f2d729e5b7f6.zip
Started working on serializing pokemon data
The GBA program now sends serialized data about the first pokemon in the
player's party over to the Wii. This data doesn't yet include all of the
information that we will eventually want. It does, however, not transfer
any private data, specifically IVs, EVs, and the personality value. It
does this by deriving the public information (stats, nature, gender,
shiny) before sending the pokemon over. Because of this, lookup tables
for things such as base stats were needed, and given that these are
large tables, it was easier to use the tables already existent in the
game's ROM. Thus, the addresses of the three lookup tables that are now
used are necessary for each ROM that this tool supports.

I derived the addresses for version 1 of English Pokemon LeafGreen by dumping
my own copy and searching through it with a text editor. Thus, at the current
time, that cartridge is the only one that is supported. I will supplement this
soon with addresses for the other four gen 3 carts that I have, but that will
still not provide a very large amount of coverage. I have not yet decided how
to address this issue.

There is one current bug with the serialized data: the Wii doesn't seem
to see the original trainer ID. Will fix.
Diffstat (limited to 'gba')
-rw-r--r--gba/Makefile2
-rw-r--r--gba/source/gamedata.c167
-rw-r--r--gba/source/gamedata.h191
-rw-r--r--gba/source/main.c86
-rw-r--r--gba/source/savestructs.h7
-rw-r--r--gba/source/serialize.c227
-rw-r--r--gba/source/serialize.h19
7 files changed, 656 insertions, 43 deletions
diff --git a/gba/Makefile b/gba/Makefile index 49d0777..7097b49 100644 --- a/gba/Makefile +++ b/gba/Makefile
@@ -25,7 +25,7 @@ BUILD := build
25SOURCES := source 25SOURCES := source
26DATA := 26DATA :=
27GRAPHICS := gfx 27GRAPHICS := gfx
28INCLUDES := 28INCLUDES := ../include
29 29
30#--------------------------------------------------------------------------------- 30#---------------------------------------------------------------------------------
31# options for code generation 31# options for code generation
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
10void decryptSaveStructures( 10static 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
122bool initSaveData( 122static 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
130bool 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
528void DecryptPokemon(struct Pokemon* pkm)
529{
530 struct BoxPokemon* boxMon = &(pkm->box);
531
532 CryptBoxPokemon(boxMon);
533}
534
535void DecryptBoxPokemon(struct BoxPokemon* pkm)
536{
537 CryptBoxPokemon(pkm);
538}
539
540void EncryptPokemon(struct Pokemon* pkm)
541{
542 struct BoxPokemon* boxMon = &(pkm->box);
543
544 EncryptBoxPokemon(boxMon);
545}
546
547void EncryptBoxPokemon(struct BoxPokemon* pkm)
548{
549 FixBoxPokemonChecksum(pkm);
550 CryptBoxPokemon(pkm);
551}
552
553union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId)
554{
555 struct BoxPokemon* boxMon = &(pkm->box);
556
557 return GetBoxPokemonSubstruct(boxMon,substructId);
558}
559
560union 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
590u16 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
612void FixBoxPokemonChecksum(struct BoxPokemon* pkm)
613{
614 pkm->checksum = CalculateBoxPokemonChecksum(pkm);
615}
616
617struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm)
618{
619 struct BoxPokemon* boxMon = &(pkm->box);
620
621 return GetBoxPokemonSubstruct0(boxMon);
622}
623
624struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm)
625{
626 return &(GetBoxPokemonSubstruct(pkm,0)->type0);
627}
628
629struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm)
630{
631 struct BoxPokemon* boxMon = &(pkm->box);
632
633 return GetBoxPokemonSubstruct1(boxMon);
634}
635
636struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm)
637{
638 return &(GetBoxPokemonSubstruct(pkm,1)->type1);
639}
640
641struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm)
642{
643 struct BoxPokemon* boxMon = &(pkm->box);
644
645 return GetBoxPokemonSubstruct2(boxMon);
646}
647
648struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm)
649{
650 return &(GetBoxPokemonSubstruct(pkm,2)->type2);
651}
652
653struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm)
654{
655 struct BoxPokemon* boxMon = &(pkm->box);
656
657 return GetBoxPokemonSubstruct3(boxMon);
658}
659
660struct 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
24bool initSaveData( 24typedef const u32 (*ExperienceTables)[101];
25 pSaveBlock1* SaveBlock1, 25
26 pSaveBlock2* SaveBlock2, 26struct 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
35bool 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 */
45void 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 */
57void 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 */
68void 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 */
80void 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 */
92union 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 */
104union 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 */
115u16 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 */
122void 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 */
133struct 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 */
144struct 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 */
155struct 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 */
166struct 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 */
177struct 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 */
188struct 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 */
199struct 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 */
210struct 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
11int main(void) 12int 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
16struct Coords16 14struct 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
500struct BattleMove 499struct 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
8enum Stat {
9 StatAttack,
10 StatDefense,
11 StatSpeed,
12 StatSpAttack,
13 StatSpDefense
14};
15
16u32 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
43void 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
219void 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
6struct BoxPokemon;
7struct PokemonIntermediate;
8struct GameData;
9
10void PokemonIntermediateInit(
11 struct PokemonIntermediate* pki,
12 struct BoxPokemon* bpkm,
13 u16 trainerId,
14 u16 secretId,
15 const struct GameData* gameData);
16
17void PokemonIntermediateStream(struct PokemonIntermediate* pki);
18
19#endif /* end of include guard: POKEMON_H_67C60AC1 */