diff options
| -rw-r--r-- | Makefile.wii | 2 | ||||
| -rw-r--r-- | gba/Makefile | 2 | ||||
| -rw-r--r-- | gba/source/gamedata.c | 167 | ||||
| -rw-r--r-- | gba/source/gamedata.h | 191 | ||||
| -rw-r--r-- | gba/source/main.c | 86 | ||||
| -rw-r--r-- | gba/source/savestructs.h | 7 | ||||
| -rw-r--r-- | gba/source/serialize.c | 227 | ||||
| -rw-r--r-- | gba/source/serialize.h | 19 | ||||
| -rw-r--r-- | include/pokemon.h | 62 | ||||
| -rw-r--r-- | source/link.c | 2 | ||||
| -rw-r--r-- | source/main.c | 54 |
11 files changed, 774 insertions, 45 deletions
| diff --git a/Makefile.wii b/Makefile.wii index 92ac7e7..8e2f2c8 100644 --- a/Makefile.wii +++ b/Makefile.wii | |||
| @@ -19,7 +19,7 @@ TARGET := gen3uploader_wii | |||
| 19 | BUILD := build | 19 | BUILD := build |
| 20 | SOURCES := source | 20 | SOURCES := source |
| 21 | DATA := data | 21 | DATA := data |
| 22 | INCLUDES := source | 22 | INCLUDES := source include |
| 23 | 23 | ||
| 24 | #--------------------------------------------------------------------------------- | 24 | #--------------------------------------------------------------------------------- |
| 25 | # options for code generation | 25 | # options for code generation |
| diff --git a/gba/Makefile b/gba/Makefile index 49d0777..7097b49 100644 --- a/gba/Makefile +++ b/gba/Makefile | |||
| @@ -25,7 +25,7 @@ BUILD := build | |||
| 25 | SOURCES := source | 25 | SOURCES := source |
| 26 | DATA := | 26 | DATA := |
| 27 | GRAPHICS := gfx | 27 | GRAPHICS := gfx |
| 28 | INCLUDES := | 28 | INCLUDES := ../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 | ||
| 10 | void decryptSaveStructures( | 10 | static 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 | ||
| 122 | bool initSaveData( | 122 | static 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 | |||
| 130 | bool 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 | |||
| 528 | void DecryptPokemon(struct Pokemon* pkm) | ||
| 529 | { | ||
| 530 | struct BoxPokemon* boxMon = &(pkm->box); | ||
| 531 | |||
| 532 | CryptBoxPokemon(boxMon); | ||
| 533 | } | ||
| 534 | |||
| 535 | void DecryptBoxPokemon(struct BoxPokemon* pkm) | ||
| 536 | { | ||
| 537 | CryptBoxPokemon(pkm); | ||
| 538 | } | ||
| 539 | |||
| 540 | void EncryptPokemon(struct Pokemon* pkm) | ||
| 541 | { | ||
| 542 | struct BoxPokemon* boxMon = &(pkm->box); | ||
| 543 | |||
| 544 | EncryptBoxPokemon(boxMon); | ||
| 545 | } | ||
| 546 | |||
| 547 | void EncryptBoxPokemon(struct BoxPokemon* pkm) | ||
| 548 | { | ||
| 549 | FixBoxPokemonChecksum(pkm); | ||
| 550 | CryptBoxPokemon(pkm); | ||
| 551 | } | ||
| 552 | |||
| 553 | union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId) | ||
| 554 | { | ||
| 555 | struct BoxPokemon* boxMon = &(pkm->box); | ||
| 556 | |||
| 557 | return GetBoxPokemonSubstruct(boxMon,substructId); | ||
| 558 | } | ||
| 559 | |||
| 560 | union 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 | |||
| 590 | u16 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 | |||
| 612 | void FixBoxPokemonChecksum(struct BoxPokemon* pkm) | ||
| 613 | { | ||
| 614 | pkm->checksum = CalculateBoxPokemonChecksum(pkm); | ||
| 615 | } | ||
| 616 | |||
| 617 | struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm) | ||
| 618 | { | ||
| 619 | struct BoxPokemon* boxMon = &(pkm->box); | ||
| 620 | |||
| 621 | return GetBoxPokemonSubstruct0(boxMon); | ||
| 622 | } | ||
| 623 | |||
| 624 | struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm) | ||
| 625 | { | ||
| 626 | return &(GetBoxPokemonSubstruct(pkm,0)->type0); | ||
| 627 | } | ||
| 628 | |||
| 629 | struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm) | ||
| 630 | { | ||
| 631 | struct BoxPokemon* boxMon = &(pkm->box); | ||
| 632 | |||
| 633 | return GetBoxPokemonSubstruct1(boxMon); | ||
| 634 | } | ||
| 635 | |||
| 636 | struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm) | ||
| 637 | { | ||
| 638 | return &(GetBoxPokemonSubstruct(pkm,1)->type1); | ||
| 639 | } | ||
| 640 | |||
| 641 | struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm) | ||
| 642 | { | ||
| 643 | struct BoxPokemon* boxMon = &(pkm->box); | ||
| 644 | |||
| 645 | return GetBoxPokemonSubstruct2(boxMon); | ||
| 646 | } | ||
| 647 | |||
| 648 | struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm) | ||
| 649 | { | ||
| 650 | return &(GetBoxPokemonSubstruct(pkm,2)->type2); | ||
| 651 | } | ||
| 652 | |||
| 653 | struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm) | ||
| 654 | { | ||
| 655 | struct BoxPokemon* boxMon = &(pkm->box); | ||
| 656 | |||
| 657 | return GetBoxPokemonSubstruct3(boxMon); | ||
| 658 | } | ||
| 659 | |||
| 660 | struct 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 | ||
| 24 | bool initSaveData( | 24 | typedef const u32 (*ExperienceTables)[101]; |
| 25 | pSaveBlock1* SaveBlock1, | 25 | |
| 26 | pSaveBlock2* SaveBlock2, | 26 | struct 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 | |||
| 35 | bool 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 | */ | ||
| 45 | void 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 | */ | ||
| 57 | void 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 | */ | ||
| 68 | void 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 | */ | ||
| 80 | void 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 | */ | ||
| 92 | union 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 | */ | ||
| 104 | union 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 | */ | ||
| 115 | u16 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 | */ | ||
| 122 | void 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 | */ | ||
| 133 | struct 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 | */ | ||
| 144 | struct 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 | */ | ||
| 155 | struct 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 | */ | ||
| 166 | struct 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 | */ | ||
| 177 | struct 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 | */ | ||
| 188 | struct 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 | */ | ||
| 199 | struct 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 | */ | ||
| 210 | struct 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 | ||
| 11 | int main(void) | 12 | int 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 | ||
| 16 | struct Coords16 | 14 | struct 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 | ||
| 500 | struct BattleMove | 499 | struct 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 | |||
| 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 | } | ||
| 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 | |||
| 6 | struct BoxPokemon; | ||
| 7 | struct PokemonIntermediate; | ||
| 8 | struct GameData; | ||
| 9 | |||
| 10 | void PokemonIntermediateInit( | ||
| 11 | struct PokemonIntermediate* pki, | ||
| 12 | struct BoxPokemon* bpkm, | ||
| 13 | u16 trainerId, | ||
| 14 | u16 secretId, | ||
| 15 | const struct GameData* gameData); | ||
| 16 | |||
| 17 | void PokemonIntermediateStream(struct PokemonIntermediate* pki); | ||
| 18 | |||
| 19 | #endif /* end of include guard: POKEMON_H_67C60AC1 */ | ||
| diff --git a/include/pokemon.h b/include/pokemon.h new file mode 100644 index 0000000..93766ba --- /dev/null +++ b/include/pokemon.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | #ifndef POKEMON_H_AD844D6F | ||
| 2 | #define POKEMON_H_AD844D6F | ||
| 3 | |||
| 4 | #define POKEMON_NAME_LENGTH 10 | ||
| 5 | #define OT_NAME_LENGTH 7 | ||
| 6 | #define TILE_SIZE_4BPP 32 | ||
| 7 | |||
| 8 | struct PokemonIntermediate { | ||
| 9 | u32 otId; | ||
| 10 | u32 experience; | ||
| 11 | |||
| 12 | // the stats are calculated from the base stats, IVs, EVs, and Nature, before | ||
| 13 | // transmitting the pokemon's data, in order to keep the IVs and EVs secret. | ||
| 14 | u32 hp; | ||
| 15 | u32 attack; | ||
| 16 | u32 defense; | ||
| 17 | u32 speed; | ||
| 18 | u32 spAttack; | ||
| 19 | u32 spDefense; | ||
| 20 | |||
| 21 | u16 species; | ||
| 22 | u16 heldItem; | ||
| 23 | u16 moves[4]; | ||
| 24 | |||
| 25 | u8 ppBonuses; | ||
| 26 | u8 otGender:1; | ||
| 27 | u8 metLevel:7; | ||
| 28 | u8 metLocation; | ||
| 29 | u8 nickname[POKEMON_NAME_LENGTH]; | ||
| 30 | u8 otName[OT_NAME_LENGTH]; | ||
| 31 | u8 pokeball; | ||
| 32 | u8 altAbility; // waste of space but nothing to pack it with | ||
| 33 | |||
| 34 | // the following values are generated from the personality value. | ||
| 35 | u8 nature:6; | ||
| 36 | u8 gender:1; | ||
| 37 | u8 shiny:1; | ||
| 38 | u8 unownLetter; | ||
| 39 | |||
| 40 | // the level is calculated from the species and experience. this is mostly | ||
| 41 | // included for convenience. | ||
| 42 | u8 level; | ||
| 43 | |||
| 44 | // instead of being represented as a number from 0 to 255, the conditions are | ||
| 45 | // transmitted as numbers from 0 to 10, so as to keep the exact condition | ||
| 46 | // values secret, since only an approximation of the condition value is ever | ||
| 47 | // visible in the game proper. the same goes for the sheen. | ||
| 48 | u8 cool; | ||
| 49 | u8 beauty; | ||
| 50 | u8 cute; | ||
| 51 | u8 smart; | ||
| 52 | u8 tough; | ||
| 53 | u8 sheen; | ||
| 54 | |||
| 55 | // this field can have the following values: | ||
| 56 | // 0 - pokemon does not have pokerus | ||
| 57 | // 1 - pokemon has pokerus | ||
| 58 | // 2 - pokemon had pokerus at one point | ||
| 59 | u8 pokerus; | ||
| 60 | }; | ||
| 61 | |||
| 62 | #endif /* end of include guard: POKEMON_H_AD844D6F */ | ||
| diff --git a/source/link.c b/source/link.c index f63f4a5..27837f8 100644 --- a/source/link.c +++ b/source/link.c | |||
| @@ -99,7 +99,7 @@ void getMsgArr(u32* arr, int len) | |||
| 99 | { | 99 | { |
| 100 | for (int i=0; i<len; i++) | 100 | for (int i=0; i<len; i++) |
| 101 | { | 101 | { |
| 102 | *(vu32*)(arr+i) = __builtin_bswap32(recv()); | 102 | *(vu32*)(arr+i) = recv(); |
| 103 | } | 103 | } |
| 104 | } | 104 | } |
| 105 | 105 | ||
| diff --git a/source/main.c b/source/main.c index 81f30a3..ceb24d5 100644 --- a/source/main.c +++ b/source/main.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include "link.h" | 13 | #include "link.h" |
| 14 | #include "encoding.h" | 14 | #include "encoding.h" |
| 15 | #include "multiboot.h" | 15 | #include "multiboot.h" |
| 16 | #include "pokemon.h" | ||
| 16 | 17 | ||
| 17 | void printmain() | 18 | void printmain() |
| 18 | { | 19 | { |
| @@ -204,6 +205,59 @@ void* extractor(void* userdata) | |||
| 204 | 205 | ||
| 205 | printf("\n"); | 206 | printf("\n"); |
| 206 | 207 | ||
| 208 | sendMsg(1); | ||
| 209 | |||
| 210 | // Start receiving party pokémon. | ||
| 211 | printf("Getting party...\n"); | ||
| 212 | |||
| 213 | u32 partyCount = getMsg(); | ||
| 214 | |||
| 215 | for (u32 i = 0; i < partyCount; i++) | ||
| 216 | { | ||
| 217 | u32 rawdata[sizeof(struct PokemonIntermediate) / 4]; | ||
| 218 | getMsgArr(rawdata, sizeof(struct PokemonIntermediate) / 4); | ||
| 219 | |||
| 220 | struct PokemonIntermediate* pki = (struct PokemonIntermediate*)(&rawdata); | ||
| 221 | |||
| 222 | printf("Species: %d\n", __builtin_bswap16(pki->species)); | ||
| 223 | |||
| 224 | u8* pokename = pki->nickname; | ||
| 225 | printf("Nickname: "); | ||
| 226 | |||
| 227 | for (int i = 0; i < 10; i++) | ||
| 228 | { | ||
| 229 | if (pokename[i] == 0xFF) | ||
| 230 | { | ||
| 231 | break; | ||
| 232 | } else { | ||
| 233 | printf("%c", debugGen3Decode(pokename[i])); | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | printf("\nOT: "); | ||
| 238 | |||
| 239 | for (int i=0; i<7; i++) | ||
| 240 | { | ||
| 241 | if (pki->otName[i] == 0xFF) | ||
| 242 | { | ||
| 243 | break; | ||
| 244 | } else { | ||
| 245 | printf("%c", debugGen3Decode(pki->otName[i])); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | printf("\n"); | ||
| 250 | printf("Level: %d\n", pki->level); | ||
| 251 | printf("HP: %ld\n", __builtin_bswap32(pki->hp)); | ||
| 252 | printf("Attack: %ld\n", __builtin_bswap32(pki->attack)); | ||
| 253 | printf("Defense: %ld\n", __builtin_bswap32(pki->defense)); | ||
| 254 | printf("Special Attack: %ld\n", __builtin_bswap32(pki->spAttack)); | ||
| 255 | printf("Special Defense: %ld\n", __builtin_bswap32(pki->spDefense)); | ||
| 256 | printf("Speed: %ld\n", __builtin_bswap32(pki->speed)); | ||
| 257 | |||
| 258 | printf("\n"); | ||
| 259 | } | ||
| 260 | |||
| 207 | waitForButtons(PAD_BUTTON_START); | 261 | waitForButtons(PAD_BUTTON_START); |
| 208 | } | 262 | } |
| 209 | 263 | ||
