diff options
Diffstat (limited to 'gba/source/gamedata.c')
| -rw-r--r-- | gba/source/gamedata.c | 512 |
1 files changed, 512 insertions, 0 deletions
| diff --git a/gba/source/gamedata.c b/gba/source/gamedata.c new file mode 100644 index 0000000..6868b2b --- /dev/null +++ b/gba/source/gamedata.c | |||
| @@ -0,0 +1,512 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2017 hatkirby | ||
| 3 | * Copyright (C) 2017 slipstream/RoL | ||
| 4 | * | ||
| 5 | * This software may be modified and distributed under the terms | ||
| 6 | * of the MIT license. See the LICENSE file for details. | ||
| 7 | */ | ||
| 8 | #include "gamedata.h" | ||
| 9 | |||
| 10 | void decryptSaveStructures( | ||
| 11 | pSaveBlock1 SaveBlock1, | ||
| 12 | pSaveBlock2 SaveBlock2, | ||
| 13 | pSaveBlock3 SaveBlock3) | ||
| 14 | { | ||
| 15 | if (GAME_RS) | ||
| 16 | { | ||
| 17 | // R/S doesn't have save crypto. | ||
| 18 | return; | ||
| 19 | } | ||
| 20 | |||
| 21 | u8* sb1raw = (u8*)SaveBlock1; | ||
| 22 | u8* sb2raw = (u8*)SaveBlock2; | ||
| 23 | //u8* sb3raw = (u8*)SaveBlock3; // unused | ||
| 24 | |||
| 25 | u32* xor_key_ptr = (u32*)(&sb2raw[( GAME_EM ? 0xA8 : 0xF20 )]); | ||
| 26 | |||
| 27 | u32 xor_key = *xor_key_ptr; | ||
| 28 | u16 xor_key16 = (u16)xor_key; | ||
| 29 | if (!xor_key) | ||
| 30 | { | ||
| 31 | // xor key is zero, nothing needs to be done. | ||
| 32 | return; | ||
| 33 | } | ||
| 34 | |||
| 35 | u32* ptr_to_xor; | ||
| 36 | u32 save_offset; | ||
| 37 | int i; | ||
| 38 | u32* bag_pocket_offsets; | ||
| 39 | u32* bag_pocket_counts; | ||
| 40 | if (GAME_FRLG) | ||
| 41 | { | ||
| 42 | // loop over and decrypt various things | ||
| 43 | save_offset = 0x3D38 + 4; | ||
| 44 | for (i = 3; i >= 0; i--) | ||
| 45 | { | ||
| 46 | ptr_to_xor = (u32*)(&sb1raw[save_offset]); | ||
| 47 | *ptr_to_xor ^= xor_key; | ||
| 48 | save_offset += 12; | ||
| 49 | } | ||
| 50 | |||
| 51 | for (i = 0; i <= 0x3f; i++) | ||
| 52 | { | ||
| 53 | save_offset = 0x1200 + (i*sizeof(u32)); | ||
| 54 | ptr_to_xor = (u32*)(&sb1raw[save_offset]); | ||
| 55 | *ptr_to_xor ^= xor_key; | ||
| 56 | } | ||
| 57 | |||
| 58 | // loop over each of the bag pockets and decrypt decrypt decrypt | ||
| 59 | bag_pocket_offsets = (u32[5]) { 0x310, 0x388, 0x430, 0x464, 0x54C }; | ||
| 60 | bag_pocket_counts = (u32[5]) { 42, 30, 13, 58, 43 }; | ||
| 61 | |||
| 62 | for (i = 0; i < 5; i++) | ||
| 63 | { | ||
| 64 | for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++) | ||
| 65 | { | ||
| 66 | save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2; | ||
| 67 | *(u16*)(&sb1raw[save_offset]) ^= xor_key16; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | // decrypt some more stuff | ||
| 72 | save_offset = 0xaf8; | ||
| 73 | ptr_to_xor = (u32*)(&sb1raw[save_offset]); | ||
| 74 | *ptr_to_xor ^= xor_key; | ||
| 75 | |||
| 76 | save_offset = 0x290; | ||
| 77 | ptr_to_xor = (u32*)(&sb1raw[save_offset]); | ||
| 78 | *ptr_to_xor ^= xor_key; | ||
| 79 | |||
| 80 | save_offset = 0x294; | ||
| 81 | *(u16*)(&sb1raw[save_offset]) ^= xor_key16; | ||
| 82 | } else { | ||
| 83 | // Emerald | ||
| 84 | |||
| 85 | // loop over and decrypt various things | ||
| 86 | for (i = 0; i <= 0x3f; i++) | ||
| 87 | { | ||
| 88 | save_offset = 0x159c + (i*sizeof(u32)); | ||
| 89 | ptr_to_xor = (u32*)(&sb1raw[save_offset]); | ||
| 90 | *ptr_to_xor ^= xor_key; | ||
| 91 | } | ||
| 92 | |||
| 93 | // loop over each of the bag pockets and decrypt decrypt decrypt | ||
| 94 | bag_pocket_offsets = (u32[5]) { 0x560, 0x5D8, 0x650, 0x690, 0x790 }; | ||
| 95 | bag_pocket_counts = (u32[5]) { 30, 30, 16, 64, 46 }; | ||
| 96 | |||
| 97 | for (i = 0; i < 5; i++) | ||
| 98 | { | ||
| 99 | for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++) | ||
| 100 | { | ||
| 101 | save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2; | ||
| 102 | *(u16*)(&sb1raw[save_offset]) ^= xor_key16; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | // decrypt some more stuff | ||
| 107 | save_offset = 0x1F4; | ||
| 108 | ptr_to_xor = (u32*)(&sb1raw[save_offset]); | ||
| 109 | *ptr_to_xor ^= xor_key; | ||
| 110 | |||
| 111 | save_offset = 0x490; | ||
| 112 | ptr_to_xor = (u32*)(&sb1raw[save_offset]); | ||
| 113 | *ptr_to_xor ^= xor_key; | ||
| 114 | |||
| 115 | save_offset = 0x494; | ||
| 116 | *(u16*)(&sb1raw[save_offset]) ^= xor_key16; | ||
| 117 | } | ||
| 118 | |||
| 119 | *xor_key_ptr = 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | bool initSaveData( | ||
| 123 | pSaveBlock1* SaveBlock1, | ||
| 124 | pSaveBlock2* SaveBlock2, | ||
| 125 | pSaveBlock3* SaveBlock3) | ||
| 126 | { | ||
| 127 | // check the ROM code, make sure this game is supported. | ||
| 128 | u8* ROM = (u8*) 0x8000000; | ||
| 129 | |||
| 130 | u32 gamecode = (*(u32*)(&ROM[0xAC])); | ||
| 131 | |||
| 132 | void(*loadsave)(char a1); | ||
| 133 | //void(*mainloop)(); | ||
| 134 | //void(*load_pokemon)(); | ||
| 135 | pSaveBlock1 gSaveBlock1; | ||
| 136 | pSaveBlock2 gSaveBlock2; | ||
| 137 | pSaveBlock3 gSaveBlock3; | ||
| 138 | //u32 titlemid = 0; | ||
| 139 | |||
| 140 | // get the address of the save loading function. | ||
| 141 | switch (gamecode) | ||
| 142 | { | ||
| 143 | // --- R/S --- | ||
| 144 | case 'DVXA': // Ruby German | ||
| 145 | case 'DPXA': // Sapphire German | ||
| 146 | { | ||
| 147 | // TODO: detect debug ROM? | ||
| 148 | gSaveBlock1 = (pSaveBlock1) 0x2025734; | ||
| 149 | gSaveBlock2 = (pSaveBlock2) 0x2024EA4; | ||
| 150 | gSaveBlock3 = (pSaveBlock3) 0x20300A0; | ||
| 151 | loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1 | ||
| 152 | //mainloop = (void(*)()) 0x80003D9; | ||
| 153 | //load_pokemon = (void(*)()) 0x8047da9; | ||
| 154 | |||
| 155 | break; | ||
| 156 | } | ||
| 157 | |||
| 158 | case 'FVXA': // Ruby French | ||
| 159 | case 'FPXA': // Sapphire French | ||
| 160 | { | ||
| 161 | gSaveBlock1 = (pSaveBlock1) 0x2025734; | ||
| 162 | gSaveBlock2 = (pSaveBlock2) 0x2024EA4; | ||
| 163 | gSaveBlock3 = (pSaveBlock3) 0x20300A0; | ||
| 164 | loadsave = (void(*)(char)) 0x8126351; // same for v1.0 + v1.1 | ||
| 165 | //mainloop = (void(*)()) 0x80003D9; | ||
| 166 | //load_pokemon = (void(*)()) 0x8047e95; | ||
| 167 | |||
| 168 | break; | ||
| 169 | } | ||
| 170 | |||
| 171 | case 'IVXA': // Ruby Italian | ||
| 172 | case 'IPXA': // Sapphire Italian | ||
| 173 | { | ||
| 174 | gSaveBlock1 = (pSaveBlock1) 0x2025734; | ||
| 175 | gSaveBlock2 = (pSaveBlock2) 0x2024EA4; | ||
| 176 | gSaveBlock3 = (pSaveBlock3) 0x20300A0; | ||
| 177 | loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1 | ||
| 178 | //mainloop = (void(*)()) 0x80003D9; | ||
| 179 | //load_pokemon = (void(*)()) 0x8047dbd; | ||
| 180 | |||
| 181 | break; | ||
| 182 | } | ||
| 183 | |||
| 184 | case 'SVXA': // Ruby Spanish | ||
| 185 | case 'SPXA': // Sapphire Spanish | ||
| 186 | { | ||
| 187 | gSaveBlock1 = (pSaveBlock1) 0x2025734; | ||
| 188 | gSaveBlock2 = (pSaveBlock2) 0x2024EA4; | ||
| 189 | gSaveBlock3 = (pSaveBlock3) 0x20300A0; | ||
| 190 | loadsave = (void(*)(char)) 0x8126349; // same for v1.0 + v1.1 | ||
| 191 | //mainloop = (void(*)()) 0x80003D9; | ||
| 192 | //load_pokemon = (void(*)()) 0x8047ea5; | ||
| 193 | |||
| 194 | break; | ||
| 195 | } | ||
| 196 | |||
| 197 | case 'EVXA': // Ruby English | ||
| 198 | case 'EPXA': // Sapphire English | ||
| 199 | { | ||
| 200 | gSaveBlock1 = (pSaveBlock1) 0x2025734; | ||
| 201 | gSaveBlock2 = (pSaveBlock2) 0x2024EA4; | ||
| 202 | gSaveBlock3 = (pSaveBlock3) 0x20300A0; | ||
| 203 | //mainloop = (void(*)()) 0x80002A5; | ||
| 204 | |||
| 205 | // version number | ||
| 206 | switch (ROM[0xBC]) | ||
| 207 | { | ||
| 208 | case 0: | ||
| 209 | { | ||
| 210 | loadsave = (void(*)(char)) 0x8125EC9; | ||
| 211 | //load_pokemon = (void(*)()) 0x8047a85; | ||
| 212 | |||
| 213 | break; | ||
| 214 | } | ||
| 215 | |||
| 216 | case 1: | ||
| 217 | case 2: | ||
| 218 | { | ||
| 219 | loadsave = (void(*)(char)) 0x8125EE9; | ||
| 220 | //load_pokemon = (void(*)()) 0x8047aa5; | ||
| 221 | |||
| 222 | break; | ||
| 223 | } | ||
| 224 | |||
| 225 | default: | ||
| 226 | { | ||
| 227 | return false; // unsupported version | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | break; | ||
| 232 | } | ||
| 233 | |||
| 234 | case 'JVXA': // Ruby Japanese | ||
| 235 | case 'JPXA': // Sapphire Japanese | ||
| 236 | { | ||
| 237 | gSaveBlock1 = (pSaveBlock1) 0x2025494; | ||
| 238 | gSaveBlock2 = (pSaveBlock2) 0x2024C04; | ||
| 239 | gSaveBlock3 = (pSaveBlock3) 0x202FDBC; | ||
| 240 | loadsave = (void(*)(char)) 0x8120d05; // same for v1.0 + v1.1 | ||
| 241 | //mainloop = (void(*)()) 0x80002A9; | ||
| 242 | //load_pokemon = (void(*)()) 0x8044d55; | ||
| 243 | |||
| 244 | break; | ||
| 245 | } | ||
| 246 | |||
| 247 | /// --- FR/LG --- | ||
| 248 | // In FR/LG, the function that initialises the save-block pointers to | ||
| 249 | // default does not set up saveblock3. Which will need to be set up before | ||
| 250 | // loading the save if we want boxed Pokémon to not disappear. Oh, and | ||
| 251 | // loadsave() offset is different between FR and LG... | ||
| 252 | |||
| 253 | case 'DRPB': // FireRed German | ||
| 254 | case 'DGPB': // LeafGreen German | ||
| 255 | { | ||
| 256 | gSaveBlock1 = (pSaveBlock1) 0x202552C; | ||
| 257 | gSaveBlock2 = (pSaveBlock2) 0x2024588; | ||
| 258 | gSaveBlock3 = (pSaveBlock3) 0x2029314; | ||
| 259 | *(pSaveBlock3*)(0x3004f60) = gSaveBlock3; | ||
| 260 | loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 ); | ||
| 261 | //mainloop = (void(*)()) 0x8000425; | ||
| 262 | //titlemid = 0x80791df; | ||
| 263 | //load_pokemon = (void(*)()) 0x804c251; | ||
| 264 | |||
| 265 | break; | ||
| 266 | } | ||
| 267 | |||
| 268 | case 'FRPB': // FireRed French | ||
| 269 | case 'FGPB': // LeafGreen French | ||
| 270 | { | ||
| 271 | gSaveBlock1 = (pSaveBlock1) 0x202552C; | ||
| 272 | gSaveBlock2 = (pSaveBlock2) 0x2024588; | ||
| 273 | gSaveBlock3 = (pSaveBlock3) 0x2029314; | ||
| 274 | *(pSaveBlock3*)(0x3004f60) = gSaveBlock3; | ||
| 275 | loadsave = (void(*)(char)) ( GAME_FR ? 0x80da7e1 : 0x80da7b5 ); | ||
| 276 | //mainloop = (void(*)()) 0x8000417; | ||
| 277 | //titlemid = 0x807929f; | ||
| 278 | //load_pokemon = (void(*)()) 0x804c311; | ||
| 279 | |||
| 280 | break; | ||
| 281 | } | ||
| 282 | |||
| 283 | case 'IRPB': // FireRed Italian | ||
| 284 | case 'IGPB': // LeafGreen Italian | ||
| 285 | { | ||
| 286 | gSaveBlock1 = (pSaveBlock1) 0x202552C; | ||
| 287 | gSaveBlock2 = (pSaveBlock2) 0x2024588; | ||
| 288 | gSaveBlock3 = (pSaveBlock3) 0x2029314; | ||
| 289 | *(pSaveBlock3*)(0x3004f60) = gSaveBlock3; | ||
| 290 | loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 ); | ||
| 291 | //mainloop = (void(*)()) 0x8000425; | ||
| 292 | //titlemid = 0x80791cb; | ||
| 293 | //load_pokemon = (void(*)()) 0x804c23d; | ||
| 294 | |||
| 295 | break; | ||
| 296 | } | ||
| 297 | |||
| 298 | case 'SRPB': // FireRed Spanish | ||
| 299 | case 'SGPB': // LeafGreen Spanish | ||
| 300 | { | ||
| 301 | gSaveBlock1 = (pSaveBlock1) 0x202552C; | ||
| 302 | gSaveBlock2 = (pSaveBlock2) 0x2024588; | ||
| 303 | gSaveBlock3 = (pSaveBlock3) 0x2029314; | ||
| 304 | *(pSaveBlock3*)(0x3004f60) = gSaveBlock3; | ||
| 305 | loadsave = (void(*)(char)) ( GAME_FR ? 0x80da809 : 0x80da7dd ); | ||
| 306 | //mainloop = (void(*)()) 0x8000417; | ||
| 307 | //titlemid = 0x80792b3; | ||
| 308 | //load_pokemon = (void(*)()) 0x804c325; | ||
| 309 | |||
| 310 | break; | ||
| 311 | } | ||
| 312 | |||
| 313 | case 'ERPB': // FireRed English | ||
| 314 | case 'EGPB': // LeafGreen English | ||
| 315 | { | ||
| 316 | gSaveBlock1 = (pSaveBlock1) 0x202552C; | ||
| 317 | gSaveBlock2 = (pSaveBlock2) 0x2024588; | ||
| 318 | gSaveBlock3 = (pSaveBlock3) 0x2029314; | ||
| 319 | *(pSaveBlock3*)(0x3005010) = gSaveBlock3; | ||
| 320 | |||
| 321 | // version number | ||
| 322 | switch (ROM[0xBC]) | ||
| 323 | { | ||
| 324 | case 0: | ||
| 325 | { | ||
| 326 | loadsave = (void(*)(char)) ( GAME_FR ? 0x80da4fd : 0x80da4d1 ); | ||
| 327 | //mainloop = (void(*)()) 0x800041b; | ||
| 328 | //titlemid = 0x807927b; | ||
| 329 | //load_pokemon = (void(*)()) 0x804c231; | ||
| 330 | |||
| 331 | break; | ||
| 332 | } | ||
| 333 | |||
| 334 | case 1: | ||
| 335 | { | ||
| 336 | loadsave = (void(*)(char)) ( GAME_FR ? 0x80da511 : 0x80da4e5 ); | ||
| 337 | //mainloop = (void(*)()) 0x8000429; | ||
| 338 | //titlemid = 0x807928f; | ||
| 339 | //load_pokemon = (void(*)()) 0x804c245; | ||
| 340 | |||
| 341 | break; | ||
| 342 | } | ||
| 343 | |||
| 344 | default: | ||
| 345 | { | ||
| 346 | return false; // unsupported version | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | break; | ||
| 351 | } | ||
| 352 | |||
| 353 | case 'JRPB': // FireRed Japanese | ||
| 354 | case 'JGPB': // LeafGreen Japanese | ||
| 355 | { | ||
| 356 | gSaveBlock1 = (pSaveBlock1) 0x202548C; | ||
| 357 | gSaveBlock2 = (pSaveBlock2) 0x20244E8; | ||
| 358 | gSaveBlock3 = (pSaveBlock3) 0x202924C; | ||
| 359 | *(pSaveBlock3*)(0x3005050) = gSaveBlock3; | ||
| 360 | |||
| 361 | // version number | ||
| 362 | switch (ROM[0xBC]) | ||
| 363 | { | ||
| 364 | case 0: | ||
| 365 | { | ||
| 366 | loadsave = (void(*)(char)) ( GAME_FR ? 0x80db4e5 : 0x80db4b9 ); | ||
| 367 | //mainloop = (void(*)()) 0x800041b; | ||
| 368 | //titlemid = 0x8078a0f; | ||
| 369 | //load_pokemon = (void(*)()) 0x804b9e9; | ||
| 370 | |||
| 371 | break; | ||
| 372 | } | ||
| 373 | |||
| 374 | case 1: | ||
| 375 | { | ||
| 376 | if ((gamecode << 8) == 'GPB\x00') | ||
| 377 | { | ||
| 378 | // LeafGreen v1.1 Japanese is undumped. | ||
| 379 | // Therefore, it is unsupported. | ||
| 380 | // I will make guesses at the offsets in the comments, but I will | ||
| 381 | // not actually implement them until LeafGreen v1.1 is dumped. | ||
| 382 | |||
| 383 | return false; | ||
| 384 | } | ||
| 385 | |||
| 386 | loadsave = (void(*)(char)) 0x80db529; | ||
| 387 | // potential LG1.1 address: 0x80db4fd | ||
| 388 | //mainloop = (void(*)()) 0x8000417; | ||
| 389 | //titlemid = 0x8078987; | ||
| 390 | //load_pokemon = (void(*)()) 0x804b9c5; | ||
| 391 | |||
| 392 | break; | ||
| 393 | } | ||
| 394 | |||
| 395 | default: | ||
| 396 | { | ||
| 397 | return false; // unsupported version | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | break; | ||
| 402 | } | ||
| 403 | |||
| 404 | /// --- Emerald --- | ||
| 405 | // In Emerald, the saveblock pointer that isn't set up is saveblock1 (in | ||
| 406 | // FR/LG it was saveblock3). The initial save loading code after the | ||
| 407 | // copyright screen is also updated, now it sets up ASLR/crypto here before | ||
| 408 | // loading the save. | ||
| 409 | |||
| 410 | case 'DEPB': // Emerald German | ||
| 411 | { | ||
| 412 | gSaveBlock1 = (pSaveBlock1) 0x2025A00; | ||
| 413 | gSaveBlock2 = (pSaveBlock2) 0x2024A54; | ||
| 414 | gSaveBlock3 = (pSaveBlock3) 0x2029808; | ||
| 415 | *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1; | ||
| 416 | loadsave = (void(*)(char)) 0x8153075; | ||
| 417 | //mainloop = (void(*)()) 0x800042b; | ||
| 418 | //titlemid = 0x816fdb5; | ||
| 419 | //load_pokemon = (void(*)()) 0x8076dd5; | ||
| 420 | |||
| 421 | break; | ||
| 422 | } | ||
| 423 | |||
| 424 | case 'FEPB': // Emerald French | ||
| 425 | { | ||
| 426 | gSaveBlock1 = (pSaveBlock1) 0x2025A00; | ||
| 427 | gSaveBlock2 = (pSaveBlock2) 0x2024A54; | ||
| 428 | gSaveBlock3 = (pSaveBlock3) 0x2029808; | ||
| 429 | *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1; | ||
| 430 | loadsave = (void(*)(char)) 0x815319d; | ||
| 431 | //mainloop = (void(*)()) 0x800042b; | ||
| 432 | //titlemid = 0x816fedd; | ||
| 433 | //load_pokemon = (void(*)()) 0x8076dd1; | ||
| 434 | |||
| 435 | break; | ||
| 436 | } | ||
| 437 | |||
| 438 | case 'IEPB': // Emerald Italian | ||
| 439 | { | ||
| 440 | gSaveBlock1 = (pSaveBlock1) 0x2025A00; | ||
| 441 | gSaveBlock2 = (pSaveBlock2) 0x2024A54; | ||
| 442 | gSaveBlock3 = (pSaveBlock3) 0x2029808; | ||
| 443 | *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1; | ||
| 444 | loadsave = (void(*)(char)) 0x8153065; | ||
| 445 | //mainloop = (void(*)()) 0x800042b; | ||
| 446 | //titlemid = 0x816fda5; | ||
| 447 | //load_pokemon = (void(*)()) 0x8076dd5; | ||
| 448 | |||
| 449 | break; | ||
| 450 | } | ||
| 451 | |||
| 452 | case 'SEPB': // Emerald Spanish | ||
| 453 | { | ||
| 454 | gSaveBlock1 = (pSaveBlock1) 0x2025A00; | ||
| 455 | gSaveBlock2 = (pSaveBlock2) 0x2024A54; | ||
| 456 | gSaveBlock3 = (pSaveBlock3) 0x2029808; | ||
| 457 | *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1; | ||
| 458 | loadsave = (void(*)(char)) 0x8153175; | ||
| 459 | //mainloop = (void(*)()) 0x800042b; | ||
| 460 | //titlemid = 0x816feb5; | ||
| 461 | //load_pokemon = (void(*)()) 0x8076dd1; | ||
| 462 | |||
| 463 | break; | ||
| 464 | } | ||
| 465 | |||
| 466 | case 'EEPB': // Emerald English | ||
| 467 | { | ||
| 468 | gSaveBlock1 = (pSaveBlock1) 0x2025A00; | ||
| 469 | gSaveBlock2 = (pSaveBlock2) 0x2024A54; | ||
| 470 | gSaveBlock3 = (pSaveBlock3) 0x2029808; | ||
| 471 | *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1; | ||
| 472 | loadsave = (void(*)(char)) 0x81534d1; | ||
| 473 | //mainloop = (void(*)()) 0x800042b; | ||
| 474 | //titlemid = 0x817014d; | ||
| 475 | //load_pokemon = (void(*)()) 0x8076dd5; | ||
| 476 | |||
| 477 | break; | ||
| 478 | } | ||
| 479 | |||
| 480 | case 'JEPB': // Emerald Japanese | ||
| 481 | { | ||
| 482 | gSaveBlock1 = (pSaveBlock1) 0x20256A4; | ||
| 483 | gSaveBlock2 = (pSaveBlock2) 0x20246F8; | ||
| 484 | gSaveBlock3 = (pSaveBlock3) 0x20294AC; | ||
| 485 | *(pSaveBlock1*)(0x3005aec) = gSaveBlock1; | ||
| 486 | loadsave = (void(*)(char)) 0x815340d; | ||
| 487 | //mainloop = (void(*)()) 0x800042b; | ||
| 488 | //titlemid = 0x816ff45; | ||
| 489 | //load_pokemon = (void(*)()) 0x80767dd; | ||
| 490 | |||
| 491 | break; | ||
| 492 | } | ||
| 493 | |||
| 494 | default: | ||
| 495 | { | ||
| 496 | return false; // this game isn't supported | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | loadsave(0); | ||
| 501 | |||
| 502 | // now the save is loaded, we can do what we want with the loaded blocks. | ||
| 503 | // first, we're going to want to decrypt the parts that are crypted, if | ||
| 504 | // applicable. | ||
| 505 | decryptSaveStructures(gSaveBlock1,gSaveBlock2,gSaveBlock3); | ||
| 506 | |||
| 507 | *SaveBlock1 = gSaveBlock1; | ||
| 508 | *SaveBlock2 = gSaveBlock2; | ||
| 509 | *SaveBlock3 = gSaveBlock3; | ||
| 510 | |||
| 511 | return true; | ||
| 512 | } | ||
