From 99b2e41f42bc4e8ca0f1b8ecc68dbbbc9889ff26 Mon Sep 17 00:00:00 2001 From: Philippe Symons Date: Thu, 12 Dec 2024 13:22:31 +0100 Subject: [PATCH] Fix bug: Japanese saves were not detected correctly for gen I --- examples/findLocalizationOffsets/main.cpp | 4 +- src/gen1/Gen1GameReader.cpp | 58 ++++++++++++++++++----- src/gen1/Gen1Localization.cpp | 16 +++---- src/gen1/Gen1PlayerPokemonStorage.cpp | 22 +++++---- 4 files changed, 67 insertions(+), 33 deletions(-) diff --git a/examples/findLocalizationOffsets/main.cpp b/examples/findLocalizationOffsets/main.cpp index 883bace..ee2ddff 100644 --- a/examples/findLocalizationOffsets/main.cpp +++ b/examples/findLocalizationOffsets/main.cpp @@ -22,7 +22,7 @@ * Yes, I'm aware this is a bit unclean, but once the relevant rom offsets are found once, you don't typically need this tool anymore. * Still, I'm leaving this application in the codebase in case I need more rom offsets later (or in case Korean localization support would get implemented at some point) */ -static const Gen1LocalizationLanguage g1_localization = Gen1LocalizationLanguage::ENGLISH; +static const Gen1LocalizationLanguage g1_localization = Gen1LocalizationLanguage::JAPANESE; static const Gen2LocalizationLanguage g2_localization = Gen2LocalizationLanguage::ENGLISH; static uint32_t findBinaryPattern(uint8_t* buffer, size_t bufferSize, uint8_t* pattern, size_t patternSize) @@ -138,7 +138,7 @@ static void processGen1(Gen1GameType gameType, uint8_t* romBuffer, uint8_t* loca findBinaryPattern(localizedRomBuffer, localizedRomBufferSize, romBuffer + eng.numbers, 11); // WARNING: Modify this variable with the localized name of the pokémon we're trying to look up. (RHYDON, because it's index 1) - const char* pokeNames[] = {"RHYDON"}; + const char* pokeNames[] = {"サイドン"}; printf("Names: 0x%08x\n", findNames(localizedRomBuffer, localizedRomBufferSize, pokeNames, 1, 1)); printf("IconTypes:\n"); findBinaryPattern(localizedRomBuffer, localizedRomBufferSize, romBuffer + eng.iconTypes, 11); diff --git a/src/gen1/Gen1GameReader.cpp b/src/gen1/Gen1GameReader.cpp index 2b5d9fc..07d92f3 100644 --- a/src/gen1/Gen1GameReader.cpp +++ b/src/gen1/Gen1GameReader.cpp @@ -10,11 +10,11 @@ /** * @brief This function calculates the main data checksum */ -uint8_t calculateMainDataChecksum(ISaveManager& saveManager) +uint8_t calculateMainDataChecksum(ISaveManager& saveManager, uint8_t localization) { Gen1Checksum checksum; const uint16_t checksummedDataStart = 0x598; - const uint16_t checksummedDataEnd = 0x1523; + const uint16_t checksummedDataEnd = (localization != (uint8_t)Gen1LocalizationLanguage::JAPANESE) ? 0x1523: 0x1594; const uint16_t numBytes = checksummedDataEnd - checksummedDataStart; uint16_t i; uint8_t byte; @@ -322,7 +322,9 @@ const char *Gen1GameReader::getRivalName() const { static char result[20]; uint8_t encodedRivalName[0xB]; - saveManager_.seek(0x25F6); + const uint16_t savOffset = (localization_ != (uint8_t)Gen1LocalizationLanguage::JAPANESE) ? 0x25F6 : 0x25F1; + + saveManager_.seek(savOffset); saveManager_.readUntil(encodedRivalName, 0x50, sizeof(encodedRivalName)); gen1_decodePokeText(encodedRivalName, sizeof(encodedRivalName), result, sizeof(result), (Gen1LocalizationLanguage)localization_); @@ -332,8 +334,8 @@ const char *Gen1GameReader::getRivalName() const uint16_t Gen1GameReader::getTrainerID() const { uint16_t result; - - saveManager_.seek(0x2605); + const uint16_t savOffset = (localization_ != (uint8_t)Gen1LocalizationLanguage::JAPANESE) ? 0x2605 : 0x25FB; + saveManager_.seek(savOffset); saveManager_.readUint16(result); return result; @@ -352,8 +354,9 @@ Gen1Box Gen1GameReader::getBox(uint8_t boxIndex) uint8_t Gen1GameReader::getCurrentBoxIndex() { uint8_t byte; + const uint16_t savOffset = (localization_ != (uint8_t)Gen1LocalizationLanguage::JAPANESE) ? 0x284C : 0x2842; - saveManager_.seek(0x284C); + saveManager_.seek(savOffset); saveManager_.readByte(byte); return byte & 0x3F; @@ -361,8 +364,18 @@ uint8_t Gen1GameReader::getCurrentBoxIndex() bool Gen1GameReader::getPokedexFlag(PokedexFlag dexFlag, uint8_t pokedexNumber) const { - const uint16_t saveOffset = (dexFlag == POKEDEX_SEEN) ? 0x25B6 : 0x25A3; + uint16_t saveOffset; uint8_t byte; + + if(localization_ != (uint8_t)Gen1LocalizationLanguage::JAPANESE) + { + saveOffset = (dexFlag == POKEDEX_SEEN) ? 0x25B6 : 0x25A3; + } + else + { + saveOffset = (dexFlag == POKEDEX_SEEN) ? 0x25B1 : 0x259E; + } + if(pokedexNumber < 1 || pokedexNumber > 151) { return false; @@ -380,8 +393,18 @@ bool Gen1GameReader::getPokedexFlag(PokedexFlag dexFlag, uint8_t pokedexNumber) void Gen1GameReader::setPokedexFlag(PokedexFlag dexFlag, uint8_t pokedexNumber) const { - const uint16_t saveOffset = (dexFlag == POKEDEX_SEEN) ? 0x25B6 : 0x25A3; + uint16_t saveOffset; uint8_t byte; + + if(localization_ != (uint8_t)Gen1LocalizationLanguage::JAPANESE) + { + saveOffset = (dexFlag == POKEDEX_SEEN) ? 0x25B6 : 0x25A3; + } + else + { + saveOffset = (dexFlag == POKEDEX_SEEN) ? 0x25B1 : 0x259E; + } + if(pokedexNumber < 1 || pokedexNumber > 151) { return; @@ -400,10 +423,19 @@ void Gen1GameReader::setPokedexFlag(PokedexFlag dexFlag, uint8_t pokedexNumber) uint8_t Gen1GameReader::getPokedexCounter(PokedexFlag dexFlag) const { - const uint16_t saveOffset = (dexFlag == POKEDEX_SEEN) ? 0x25B6 : 0x25A3; + uint16_t saveOffset; uint8_t bytes[19]; uint8_t result = 0; + if(localization_ != (uint8_t)Gen1LocalizationLanguage::JAPANESE) + { + saveOffset = (dexFlag == POKEDEX_SEEN) ? 0x25B6 : 0x25A3; + } + else + { + saveOffset = (dexFlag == POKEDEX_SEEN) ? 0x25B1 : 0x259E; + } + saveManager_.seek(saveOffset); saveManager_.read(bytes, sizeof(bytes)); @@ -500,22 +532,22 @@ uint8_t Gen1GameReader::addDistributionPokemon(const Gen1DistributionPokemon& di bool Gen1GameReader::isMainChecksumValid() { - const uint16_t mainDataChecksumOffset = 0x3523; + const uint16_t mainDataChecksumOffset = (localization_ != (uint8_t)Gen1LocalizationLanguage::JAPANESE) ? 0x3523 : 0x3594; uint8_t storedChecksum; uint8_t calculatedChecksum; saveManager_.seek(mainDataChecksumOffset); saveManager_.readByte(storedChecksum); - calculatedChecksum = calculateMainDataChecksum(saveManager_); + calculatedChecksum = calculateMainDataChecksum(saveManager_, localization_); return (storedChecksum == calculatedChecksum); } void Gen1GameReader::updateMainChecksum() { - const uint16_t mainDataChecksumOffset = 0x3523; - const uint8_t calculatedChecksum = calculateMainDataChecksum(saveManager_); + const uint16_t mainDataChecksumOffset = (localization_ != (uint8_t)Gen1LocalizationLanguage::JAPANESE) ? 0x3523 : 0x3594; + const uint8_t calculatedChecksum = calculateMainDataChecksum(saveManager_, localization_); saveManager_.seek(mainDataChecksumOffset); saveManager_.writeByte(calculatedChecksum); diff --git a/src/gen1/Gen1Localization.cpp b/src/gen1/Gen1Localization.cpp index efe081e..414f33c 100644 --- a/src/gen1/Gen1Localization.cpp +++ b/src/gen1/Gen1Localization.cpp @@ -58,14 +58,14 @@ static const Gen1LocalizationRomOffsets g1_localizationOffsetsRB[] = { }, // Japanese { - .stats = 0x383DE, - .statsMew = 0x425B, - .numbers = 0x42784, - .names = 0x39446, - .iconTypes = 0x71DC1, - .icons = 0x71C74, - .paletteIndices = 0x72A0E, - .palettes = 0x72AA5 + .stats = 0x38000, + .statsMew = 0x4200, + .numbers = 0x4279A, + .names = 0x39068, + .iconTypes = 0x71DD1, + .icons = 0x71C84, + .paletteIndices = 0x72A1F, + .palettes = 0x72AB6 } }; diff --git a/src/gen1/Gen1PlayerPokemonStorage.cpp b/src/gen1/Gen1PlayerPokemonStorage.cpp index 22cfc41..71f0eea 100644 --- a/src/gen1/Gen1PlayerPokemonStorage.cpp +++ b/src/gen1/Gen1PlayerPokemonStorage.cpp @@ -25,18 +25,20 @@ static const uint8_t OT_NAME_SIZE = 0xB; * @brief This function will load the metadata of the trainer party into the specified outPartyMeta variable. * Note that it won't contain the detailed data about the pokemon in the party. */ -static bool getPartyMetadata(ISaveManager& saveManager, Gen1TrainerPartyMeta &outPartyMeta) +static bool getPartyMetadata(ISaveManager& saveManager, Gen1TrainerPartyMeta &outPartyMeta, Gen1LocalizationLanguage localization) { - saveManager.seek(0x2F2C); + const uint16_t savOffset = (localization != Gen1LocalizationLanguage::JAPANESE) ? 0x2F2C : 0x2ED5; + saveManager.seek(savOffset); saveManager.readByte(outPartyMeta.number_of_pokemon); saveManager.read(outPartyMeta.species_index_list, 6); outPartyMeta.species_index_list[6] = 0xFF; return true; } -static void writePartyMetadata(ISaveManager& saveManager, Gen1TrainerPartyMeta& partyMeta) +static void writePartyMetadata(ISaveManager& saveManager, Gen1TrainerPartyMeta& partyMeta, Gen1LocalizationLanguage localization) { - saveManager.seek(0x2F2C); + const uint16_t savOffset = (localization != Gen1LocalizationLanguage::JAPANESE) ? 0x2F2C : 0x2ED5; + saveManager.seek(savOffset); saveManager.writeByte(partyMeta.number_of_pokemon); saveManager.write(partyMeta.species_index_list, 6); saveManager.writeByte(0xFF); @@ -202,7 +204,7 @@ Gen1Party::~Gen1Party() uint8_t Gen1Party::getSpeciesAtIndex(uint8_t partyIndex) { Gen1TrainerPartyMeta partyMeta; - getPartyMetadata(saveManager_, partyMeta); + getPartyMetadata(saveManager_, partyMeta, localization_); if(partyIndex >= partyMeta.number_of_pokemon) { @@ -247,7 +249,7 @@ bool Gen1Party::setPokemon(uint8_t partyIndex, Gen1TrainerPokemon& poke) const uint8_t PARTY_POKEMON_NUM_BYTES = 44; const uint8_t FIRST_POKE_STRUCT_OFFSET = 8; Gen1TrainerPartyMeta partyMeta; - getPartyMetadata(saveManager_, partyMeta); + getPartyMetadata(saveManager_, partyMeta, localization_); if(partyIndex >= partyMeta.number_of_pokemon) { @@ -263,7 +265,7 @@ bool Gen1Party::setPokemon(uint8_t partyIndex, Gen1TrainerPokemon& poke) partyMeta.species_index_list[partyMeta.number_of_pokemon] = 0xFF; } - writePartyMetadata(saveManager_, partyMeta); + writePartyMetadata(saveManager_, partyMeta, localization_); // make sure the stat fields are filled in by recalculating them. // this is the same as what happens when withdrawing them from an ingame PC box @@ -289,7 +291,7 @@ bool Gen1Party::setPokemon(uint8_t partyIndex, Gen1TrainerPokemon& poke) uint8_t Gen1Party::getNumberOfPokemon() { Gen1TrainerPartyMeta partyMeta; - if(!getPartyMetadata(saveManager_, partyMeta)) + if(!getPartyMetadata(saveManager_, partyMeta, localization_)) { return 0; } @@ -360,7 +362,7 @@ void Gen1Party::setOriginalTrainerOfPokemon(uint8_t partyIndex, const char* orig bool Gen1Party::add(Gen1TrainerPokemon& poke, const char* originalTrainerID, const char* nickname) { Gen1TrainerPartyMeta partyMeta; - getPartyMetadata(saveManager_, partyMeta); + getPartyMetadata(saveManager_, partyMeta, localization_); const uint8_t partyIndex = partyMeta.number_of_pokemon; if(partyIndex >= getMaxNumberOfPokemon()) @@ -376,7 +378,7 @@ bool Gen1Party::add(Gen1TrainerPokemon& poke, const char* originalTrainerID, con partyMeta.species_index_list[partyMeta.number_of_pokemon] = 0xFF; } - writePartyMetadata(saveManager_, partyMeta); + writePartyMetadata(saveManager_, partyMeta, localization_); if(!setPokemon(partyIndex, poke)) { return false;