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 | } | ||
