diff options
Diffstat (limited to 'gba/source/serialize.c')
-rw-r--r-- | gba/source/serialize.c | 227 |
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 | |||
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 | } | ||