about summary refs log tree commit diff stats
path: root/gba/source/serialize.c
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/source/serialize.c
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/source/serialize.c')
-rw-r--r--gba/source/serialize.c227
1 files changed, 227 insertions, 0 deletions
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}