about summary refs log tree commit diff stats
path: root/gba
diff options
context:
space:
mode:
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 */