From fd1c538cc5e91cd7328f5048007f5f44bb78577c Mon Sep 17 00:00:00 2001 From: Kurt Date: Sun, 26 Oct 2025 19:01:44 -0500 Subject: [PATCH] Changes for Legends: Z-A support (#4596) Refer to pull request notes and the eventual changelog for a high-level summary. Co-authored-by: Matt <17801814+sora10pls@users.noreply.github.com> Co-authored-by: Lusamine <30205550+Lusamine@users.noreply.github.com> Co-authored-by: SciresM <8676005+SciresM@users.noreply.github.com> --- .github/README-de.md | 2 +- .github/README-es.md | 2 +- .github/README-fr.md | 2 +- .github/README-it.md | 2 +- .github/README-ko.md | 2 +- .github/README-zh-Hans.md | 2 +- .github/README-zh-Hant.md | 2 +- .../Applicators/PlusRecordApplicator.cs | 195 ++ .../Applicators/TechnicalRecordApplicator.cs | 5 + .../BattleTemplate/BattleTemplateConfig.cs | 2 +- .../BattleTemplateTypeSetting.cs | 2 +- .../Showdown/ShowdownParsing.cs | 3 + .../BattleTemplate/Showdown/ShowdownSet.cs | 2 +- PKHeX.Core/Editing/Bulk/BatchEditing.cs | 5 +- PKHeX.Core/Editing/Bulk/BatchMods.cs | 1 + .../Bulk/Suggestion/BatchModifications.cs | 22 + PKHeX.Core/Editing/CommonEdits.cs | 10 +- PKHeX.Core/Editing/Pokerus.cs | 2 + PKHeX.Core/Editing/Saves/Slots/Extensions.cs | 35 + .../Editing/Saves/Slots/StorageSlotType.cs | 2 + PKHeX.Core/Game/Enums/GameVersion.cs | 5 + PKHeX.Core/Game/Enums/LanguageID.cs | 5 + PKHeX.Core/Game/Enums/Move.cs | 1 + .../GameStrings/FilteredGameDataSource.cs | 3 +- PKHeX.Core/Game/GameStrings/GameDataSource.cs | 7 +- PKHeX.Core/Game/GameStrings/GameInfo.cs | 4 +- PKHeX.Core/Game/GameStrings/GameStrings.cs | 78 +- PKHeX.Core/Game/GameStrings/MetDataSource.cs | 15 + PKHeX.Core/Game/GameUtil.cs | 10 +- PKHeX.Core/Game/Locations/Locations.cs | 1 + PKHeX.Core/Game/Locations/Locations9.cs | 4 +- PKHeX.Core/Game/Locations/Locations9a.cs | 69 + PKHeX.Core/Items/ItemStorage9SV.cs | 30 +- PKHeX.Core/Items/ItemStorage9ZA.cs | 236 ++ PKHeX.Core/Legality/Assets/BinLinkerWriter.cs | 20 +- PKHeX.Core/Legality/Breeding.cs | 3 + PKHeX.Core/Legality/Bulk/BulkAnalysis.cs | 35 +- .../Bulk/SaveFile/DuplicateFusionChecker.cs | 108 + .../Bulk/SaveFile/DuplicateMegaChecker.cs | 80 + .../Encounters/Data/EncounterEvent.cs | 20 +- .../Legality/Encounters/Data/EncounterUtil.cs | 6 + .../Encounters/Data/Gen9/Encounters9a.cs | 91 + .../Data/Live/DistributionWindow.cs | 2 +- .../Data/Live/EncounterServerDate.cs | 16 +- .../ByGeneration/EncounterGenerator4.cs | 2 + .../ByGeneration/EncounterGenerator9.cs | 5 +- .../ByGeneration/EncounterGenerator9a.cs | 23 + .../ByGeneration/Lump/EncounterGenerator9X.cs | 33 + .../Encounters/Generator/EncounterCriteria.cs | 15 + .../Generator/EncounterGenerator.cs | 8 +- .../Generator/Possible/EncounterPossible9a.cs | 156 + .../Generator/Search/EncounterEnumerator9a.cs | 210 ++ .../Encounters/Information/EncounterLearn.cs | 7 + .../Templates/GO/EncounterSlot7GO.cs | 2 +- .../Templates/GO/EncounterSlot8GO.cs | 2 +- .../Templates/Gen1/EncounterSlot1.cs | 2 +- .../Templates/Gen1/EncounterStatic1.cs | 2 +- .../Templates/Gen1/EncounterTrade1.cs | 2 +- .../Templates/Gen2/EncounterEgg2.cs | 2 +- .../Templates/Gen2/EncounterSlot2.cs | 2 +- .../Templates/Gen2/EncounterStatic2.cs | 2 +- .../Templates/Gen2/EncounterTrade2.cs | 2 +- .../Templates/Gen3/Colo/EncounterGift3Colo.cs | 2 +- .../Gen3/Colo/EncounterShadow3Colo.cs | 2 +- .../Gen3/Colo/EncounterStarter3Colo.cs | 2 +- .../Templates/Gen3/EncounterEgg3.cs | 2 +- .../Templates/Gen3/EncounterSlot3.cs | 2 +- .../Templates/Gen3/EncounterStatic3.cs | 2 +- .../Templates/Gen3/EncounterTrade3.cs | 2 +- .../Templates/Gen3/XD/EncounterShadow3XD.cs | 2 +- .../Templates/Gen3/XD/EncounterSlot3XD.cs | 2 +- .../Templates/Gen3/XD/EncounterStatic3XD.cs | 2 +- .../Templates/Gen3/XD/EncounterTrade3XD.cs | 2 +- .../Templates/Gen4/EncounterEgg4.cs | 2 +- .../Templates/Gen4/EncounterSlot4.cs | 2 +- .../Templates/Gen4/EncounterStatic4.cs | 2 +- .../Gen4/EncounterStatic4Pokewalker.cs | 2 +- .../Templates/Gen4/EncounterTrade4PID.cs | 2 +- .../Gen4/EncounterTrade4RanchGift.cs | 2 +- .../Templates/Gen5/EncounterEgg5.cs | 2 +- .../Templates/Gen5/EncounterSlot5.cs | 2 +- .../Templates/Gen5/EncounterStatic5.cs | 2 +- .../Templates/Gen5/EncounterStatic5Entree.cs | 2 +- .../Templates/Gen5/EncounterStatic5N.cs | 2 +- .../Templates/Gen5/EncounterStatic5Radar.cs | 2 +- .../Templates/Gen5/EncounterTrade5B2W2.cs | 2 +- .../Templates/Gen5/EncounterTrade5BW.cs | 2 +- .../Templates/Gen6/EncounterEgg6.cs | 2 +- .../Templates/Gen6/EncounterSlot6AO.cs | 2 +- .../Templates/Gen6/EncounterSlot6XY.cs | 2 +- .../Templates/Gen6/EncounterStatic6.cs | 2 +- .../Templates/Gen6/EncounterTrade6.cs | 2 +- .../Templates/Gen7/EncounterEgg7.cs | 2 +- .../Templates/Gen7/EncounterSlot7.cs | 2 +- .../Templates/Gen7/EncounterStatic7.cs | 2 +- .../Templates/Gen7/EncounterTrade7.cs | 2 +- .../Templates/Gen7b/EncounterSlot7b.cs | 2 +- .../Templates/Gen7b/EncounterStatic7b.cs | 2 +- .../Templates/Gen7b/EncounterTrade7b.cs | 2 +- .../Templates/Gen8/EncounterEgg8.cs | 2 +- .../Templates/Gen8/EncounterSlot8.cs | 2 +- .../Templates/Gen8/EncounterStatic8.cs | 2 +- .../Templates/Gen8/EncounterStatic8Nest.cs | 2 +- .../Templates/Gen8/EncounterTrade8.cs | 2 +- .../Templates/Gen8a/EncounterSlot8a.cs | 2 +- .../Templates/Gen8a/EncounterStatic8a.cs | 2 +- .../Templates/Gen8b/EncounterEgg8b.cs | 2 +- .../Templates/Gen8b/EncounterSlot8b.cs | 2 +- .../Templates/Gen8b/EncounterStatic8b.cs | 2 +- .../Templates/Gen8b/EncounterTrade8b.cs | 2 +- .../Templates/Gen9/EncounterDist9.cs | 2 +- .../Templates/Gen9/EncounterEgg9.cs | 2 +- .../Templates/Gen9/EncounterFixed9.cs | 2 +- .../Templates/Gen9/EncounterMight9.cs | 2 +- .../Templates/Gen9/EncounterOutbreak9.cs | 2 +- .../Templates/Gen9/EncounterSlot9.cs | 2 +- .../Templates/Gen9/EncounterStatic9.cs | 2 +- .../Templates/Gen9/EncounterTera9.cs | 2 +- .../Templates/Gen9/EncounterTrade9.cs | 2 +- .../Templates/Gen9a/EncounterArea9a.cs | 52 + .../Templates/Gen9a/EncounterGift9a.cs | 302 ++ .../Templates/Gen9a/EncounterSlot9a.cs | 156 + .../Templates/Gen9a/EncounterStatic9a.cs | 211 ++ .../Templates/Gen9a/EncounterTrade9a.cs | 230 ++ .../Templates/Gen9a/GenerateParam9a.cs | 15 + .../Templates/Gen9a/IEncounter9a.cs | 17 + .../Templates/Gen9a/LumioseCorrelation.cs | 27 + .../Encounters/Templates/Gen9a/LumioseRNG.cs | 401 +++ .../Templates/Gen9a/LumioseSolver.cs | 260 ++ .../Encounters/Templates/Gen9a/SlotType9a.cs | 6 + .../EvolutionGroup/EvolutionGroupHOME.cs | 9 +- .../EvolutionGroup/EvolutionGroupHOME2.cs | 206 ++ .../EvolutionGroup/EvolutionGroupUtil.cs | 6 +- .../EvolutionGroup/EvolutionUtil.cs | 40 + .../Legality/Evolutions/EvolutionHistory.cs | 3 + .../Legality/Evolutions/EvolutionTree.cs | 2 + .../LearnSource/Group/LearnGroup9a.cs | 126 + .../LearnSource/Group/LearnGroupHOME.cs | 10 + .../LearnSource/Group/LearnGroupUtil.cs | 1 + .../Legality/LearnSource/LearnEnvironment.cs | 5 +- .../LearnSource/Sources/LearnSource9ZA.cs | 105 + .../LearnSource/Verify/LearnVerifier.cs | 10 + PKHeX.Core/Legality/Learnset/Learnset.cs | 12 +- PKHeX.Core/Legality/Legal.cs | 30 +- .../Localization/LegalityCheckLocalization.cs | 12 + .../LegalityCheckResultCodeExtensions.cs | 14 +- .../LegalityLocalizationContext.cs | 3 + PKHeX.Core/Legality/Moves/GameData.cs | 2 + .../Legality/RNG/ClassicEra/ClassicEraRNG.cs | 2 +- .../RNG/ClassicEra/Gen3/ChannelJirachi.cs | 2 +- .../Legality/Restrictions/ItemRestrictions.cs | 2 + .../Restrictions/Memories/MemoryRules.cs | 1 + .../Restrictions/WordFilter/WordFilter3DS.cs | 4 +- .../Restrictions/WordFilter/WordFilterNX.cs | 3 +- .../Specialized/HandlerRestrictions.cs | 3 + .../Specialized/NicknameRestriction.cs | 6 + .../Structures/LegalityCheckResultCode.cs | 16 + PKHeX.Core/Legality/Tables/FormInfo.cs | 46 +- .../Legality/Tables/TradeRestrictions.cs | 9 +- .../Verifiers/Ability/AbilityChangeRules.cs | 15 +- .../Verifiers/Ability/AbilityVerifier.cs | 15 + .../Verifiers/Ball/BallUseLegality.cs | 5 +- PKHeX.Core/Legality/Verifiers/FormVerifier.cs | 29 +- .../Legality/Verifiers/HistoryVerifier.cs | 15 +- .../Legality/Verifiers/LanguageVerifier.cs | 2 +- .../Verifiers/LegendsArceusVerifier.cs | 8 +- .../Legality/Verifiers/LegendsZAVerifier.cs | 232 ++ PKHeX.Core/Legality/Verifiers/MiscVerifier.cs | 28 +- .../Legality/Verifiers/MovePPVerifier.cs | 18 +- .../Legality/Verifiers/NicknameVerifier.cs | 17 +- .../Legality/Verifiers/TransferVerifier.cs | 4 + PKHeX.Core/Moves/MoveInfo.cs | 11 +- PKHeX.Core/Moves/MoveInfo9.cs | 100 +- PKHeX.Core/Moves/MoveInfo9a.cs | 129 + PKHeX.Core/MysteryGifts/WA8.cs | 14 +- PKHeX.Core/MysteryGifts/WA9.cs | 855 ++++++ PKHeX.Core/MysteryGifts/WB7.cs | 10 +- PKHeX.Core/MysteryGifts/WB8.cs | 9 +- PKHeX.Core/MysteryGifts/WC6.cs | 9 +- PKHeX.Core/MysteryGifts/WC7.cs | 9 +- PKHeX.Core/MysteryGifts/WC8.cs | 17 +- PKHeX.Core/MysteryGifts/WC9.cs | 18 +- PKHeX.Core/PKM/Enums/OriginMark.cs | 3 + PKHeX.Core/PKM/HOME/GameDataPA8.cs | 2 +- PKHeX.Core/PKM/HOME/GameDataPA9.cs | 281 ++ PKHeX.Core/PKM/HOME/HomeCrypto.cs | 3 + PKHeX.Core/PKM/HOME/HomeGameDataFormat.cs | 1 + PKHeX.Core/PKM/HOME/PKH.cs | 14 +- PKHeX.Core/PKM/Interfaces/IHyperTrain.cs | 9 +- PKHeX.Core/PKM/Interfaces/IPlusRecord.cs | 51 + PKHeX.Core/PKM/PA9.cs | 705 +++++ PKHeX.Core/PKM/PK5.cs | 2 +- PKHeX.Core/PKM/PK7.cs | 2 +- PKHeX.Core/PKM/PKM.cs | 5 +- .../PKM/Searching/EntityPresenceFilters.cs | 2 + PKHeX.Core/PKM/Shared/GBPKM.cs | 2 +- PKHeX.Core/PKM/Strings/Font/StringFontUtil.cs | 3 +- .../PKM/Util/Conversion/FormConverter.cs | 186 +- .../PKM/Util/Conversion/IEntityRejuvenator.cs | 5 + .../PKM/Util/Conversion/ItemConverter.cs | 33 +- PKHeX.Core/PKM/Util/EntityBlank.cs | 2 + PKHeX.Core/PKM/Util/EntityContext.cs | 12 +- PKHeX.Core/PKM/Util/EntityFileExtension.cs | 4 + PKHeX.Core/PKM/Util/EntityFormat.cs | 5 +- PKHeX.Core/PKM/Util/Language.cs | 46 +- PKHeX.Core/PKM/Util/Latest.cs | 4 +- PKHeX.Core/PKM/Util/SpeciesName.cs | 31 +- .../PersonalInfo/Info/PersonalInfo9ZA.cs | 174 ++ PKHeX.Core/PersonalInfo/PersonalTable.cs | 5 + .../PersonalInfo/Table/PersonalTable9ZA.cs | 75 + PKHeX.Core/Resources/byte/evolve/evos_za.pkl | Bin 0 -> 4290 bytes .../Resources/byte/levelup/lvlmove_za.pkl | Bin 0 -> 18708 bytes .../Resources/byte/personal/personal_za | Bin 0 -> 113760 bytes .../Resources/byte/personal/reminder_za.pkl | Bin 0 -> 3482 bytes .../legality/gen9a/text_tradeza_de.txt | 8 + .../legality/gen9a/text_tradeza_en.txt | 8 + .../legality/gen9a/text_tradeza_es-419.txt | 8 + .../legality/gen9a/text_tradeza_es.txt | 8 + .../legality/gen9a/text_tradeza_fr.txt | 8 + .../legality/gen9a/text_tradeza_it.txt | 8 + .../legality/gen9a/text_tradeza_ja.txt | 8 + .../legality/gen9a/text_tradeza_ko.txt | 8 + .../legality/gen9a/text_tradeza_zh-Hans.txt | 8 + .../legality/gen9a/text_tradeza_zh-Hant.txt | 8 + PKHeX.Core/Resources/legality/mgdb/wa9.pkl | Bin 0 -> 1424 bytes .../Resources/legality/misc/plus_za.pkl | Bin 0 -> 18708 bytes .../legality/wild/Gen9/encounter_za.pkl | Bin 0 -> 10600 bytes .../Resources/text/items/text_Items_de.txt | 79 +- .../Resources/text/items/text_Items_en.txt | 79 +- .../text/items/text_Items_es-419.txt | 2635 +++++++++++++++++ .../Resources/text/items/text_Items_es.txt | 203 +- .../Resources/text/items/text_Items_fr.txt | 79 +- .../Resources/text/items/text_Items_it.txt | 79 +- .../Resources/text/items/text_Items_ja.txt | 79 +- .../Resources/text/items/text_Items_ko.txt | 79 +- .../text/items/text_Items_zh-Hans.txt | 81 +- .../text/items/text_Items_zh-Hant.txt | 81 +- .../text/locations/gen9a/text_za_00000_de.txt | 236 ++ .../text/locations/gen9a/text_za_00000_en.txt | 236 ++ .../locations/gen9a/text_za_00000_es-419.txt | 236 ++ .../text/locations/gen9a/text_za_00000_es.txt | 236 ++ .../text/locations/gen9a/text_za_00000_fr.txt | 236 ++ .../text/locations/gen9a/text_za_00000_it.txt | 236 ++ .../text/locations/gen9a/text_za_00000_ja.txt | 236 ++ .../text/locations/gen9a/text_za_00000_ko.txt | 236 ++ .../locations/gen9a/text_za_00000_zh-Hans.txt | 236 ++ .../locations/gen9a/text_za_00000_zh-Hant.txt | 236 ++ .../text/locations/gen9a/text_za_30000_de.txt | 33 + .../text/locations/gen9a/text_za_30000_en.txt | 33 + .../locations/gen9a/text_za_30000_es-419.txt | 33 + .../text/locations/gen9a/text_za_30000_es.txt | 33 + .../text/locations/gen9a/text_za_30000_fr.txt | 33 + .../text/locations/gen9a/text_za_30000_it.txt | 33 + .../text/locations/gen9a/text_za_30000_ja.txt | 33 + .../text/locations/gen9a/text_za_30000_ko.txt | 33 + .../locations/gen9a/text_za_30000_zh-Hans.txt | 33 + .../locations/gen9a/text_za_30000_zh-Hant.txt | 33 + .../text/locations/gen9a/text_za_40000_de.txt | 71 + .../text/locations/gen9a/text_za_40000_en.txt | 71 + .../locations/gen9a/text_za_40000_es-419.txt | 146 + .../text/locations/gen9a/text_za_40000_es.txt | 71 + .../text/locations/gen9a/text_za_40000_fr.txt | 71 + .../text/locations/gen9a/text_za_40000_it.txt | 71 + .../text/locations/gen9a/text_za_40000_ja.txt | 71 + .../text/locations/gen9a/text_za_40000_ko.txt | 71 + .../locations/gen9a/text_za_40000_zh-Hans.txt | 71 + .../locations/gen9a/text_za_40000_zh-Hant.txt | 71 + .../text/locations/gen9a/text_za_60000_de.txt | 6 + .../text/locations/gen9a/text_za_60000_en.txt | 6 + .../locations/gen9a/text_za_60000_es-419.txt | 6 + .../text/locations/gen9a/text_za_60000_es.txt | 6 + .../text/locations/gen9a/text_za_60000_fr.txt | 6 + .../text/locations/gen9a/text_za_60000_it.txt | 6 + .../text/locations/gen9a/text_za_60000_ja.txt | 6 + .../text/locations/gen9a/text_za_60000_ko.txt | 6 + .../locations/gen9a/text_za_60000_zh-Hans.txt | 6 + .../locations/gen9a/text_za_60000_zh-Hant.txt | 6 + .../Resources/text/other/de/text_Forms_de.txt | 4 +- .../Resources/text/other/de/text_Games_de.txt | 5 +- .../Resources/text/other/de/text_Moves_de.txt | 3 +- .../Resources/text/other/en/text_Forms_en.txt | 4 +- .../Resources/text/other/en/text_Games_en.txt | 3 +- .../Resources/text/other/en/text_Moves_en.txt | 3 +- .../other/es-419/text_Abilities_es-419.txt | 311 ++ .../other/es-419/text_Character_es-419.txt | 30 + .../text/other/es-419/text_Forms_es-419.txt | 1139 +++++++ .../text/other/es-419/text_Games_es-419.txt | 53 + .../other/es-419/text_GroundTile_es-419.txt | 25 + .../text/other/es-419/text_Moves_es-419.txt | 921 ++++++ .../text/other/es-419/text_Natures_es-419.txt | 25 + .../other/es-419/text_Pokeblock_es-419.txt | 106 + .../text/other/es-419/text_Puff_es-419.txt | 27 + .../text/other/es-419/text_Ribbons_es-419.txt | 164 + .../text/other/es-419/text_Species_es-419.txt | 1026 +++++++ .../es-419/text_SuperTraining_es-419.txt | 38 + .../other/es-419/text_TrainingBag_es-419.txt | 27 + .../text/other/es-419/text_Types_es-419.txt | 19 + .../other/es-419/text_Wallpaper_es-419.txt | 32 + .../Resources/text/other/es/text_Forms_es.txt | 4 +- .../Resources/text/other/es/text_Games_es.txt | 3 +- .../Resources/text/other/es/text_Moves_es.txt | 11 +- .../Resources/text/other/fr/text_Forms_fr.txt | 4 +- .../Resources/text/other/fr/text_Games_fr.txt | 3 +- .../Resources/text/other/fr/text_Moves_fr.txt | 3 +- .../Resources/text/other/it/text_Forms_it.txt | 4 +- .../Resources/text/other/it/text_Games_it.txt | 3 +- .../Resources/text/other/it/text_Moves_it.txt | 3 +- .../Resources/text/other/ja/text_Forms_ja.txt | 4 +- .../Resources/text/other/ja/text_Games_ja.txt | 5 +- .../Resources/text/other/ja/text_Moves_ja.txt | 3 +- .../Resources/text/other/ko/text_Forms_ko.txt | 4 +- .../Resources/text/other/ko/text_Games_ko.txt | 5 +- .../Resources/text/other/ko/text_Moves_ko.txt | 3 +- .../Resources/text/other/text_language_de.txt | 3 +- .../text/other/text_language_e-419.txt | 12 + .../Resources/text/other/text_language_en.txt | 5 +- .../Resources/text/other/text_language_es.txt | 3 +- .../Resources/text/other/text_language_fr.txt | 3 +- .../Resources/text/other/text_language_it.txt | 3 +- .../Resources/text/other/text_language_ja.txt | 5 +- .../Resources/text/other/text_language_ko.txt | 5 +- .../text/other/text_language_zh-Hans.txt | 5 +- .../text/other/text_language_zh-Hant.txt | 3 +- .../text/other/zh/text_Forms_zh-Hans.txt | 4 +- .../text/other/zh/text_Forms_zh-Hant.txt | 4 +- .../text/other/zh/text_Games_zh-Hans.txt | 5 +- .../text/other/zh/text_Games_zh-Hant.txt | 5 +- .../text/other/zh/text_Moves_zh-Hans.txt | 3 +- .../text/other/zh/text_Moves_zh-Hant.txt | 3 +- .../Saves/Access/SaveBlockAccessor9SV.cs | 2 +- .../Saves/Access/SaveBlockAccessor9ZA.cs | 134 + .../Saves/Encryption/SwishCrypto/FnvHash.cs | 2 + .../Encryption/SwishCrypto/SCBlockMetadata.cs | 17 + PKHeX.Core/Saves/SAV1.cs | 6 +- PKHeX.Core/Saves/SAV3E.cs | 2 +- PKHeX.Core/Saves/SAV3RS.cs | 2 +- PKHeX.Core/Saves/SAV5B2W2.cs | 8 +- PKHeX.Core/Saves/SAV9ZA.cs | 254 ++ PKHeX.Core/Saves/SaveFileMetadata.cs | 12 + .../Substructures/Gen8/SWSH/TeamIndexes8.cs | 1 + .../Gen9/{ => SV}/BlankBlocks9.cs | 0 .../Gen9/{ => SV}/BlueberryClubRoom9.cs | 0 .../Gen9/{ => SV}/BlueberryQuestRecord9.cs | 0 .../Saves/Substructures/Gen9/{ => SV}/Box9.cs | 0 .../Substructures/Gen9/{ => SV}/BoxLayout9.cs | 3 +- .../Gen9/{ => SV}/ConfigCamera9.cs | 0 .../Gen9/{ => SV}/ConfigSave9.cs | 0 .../Saves/Substructures/Gen9/{ => SV}/DXT1.cs | 0 .../Gen9/{ => SV}/FixedSpawnList9.cs | 0 .../Substructures/Gen9/{ => SV}/MyItem9.cs | 0 .../Substructures/Gen9/{ => SV}/MyStatus9.cs | 0 .../Substructures/Gen9/{ => SV}/Party9.cs | 0 .../Substructures/Gen9/{ => SV}/PlayTime9.cs | 0 .../Gen9/{ => SV}/PlayerAppearance9.cs | 0 .../Gen9/{ => SV}/PlayerFashion9.cs | 0 .../Gen9/{ => SV}/PlayerFashionUnlock9.cs | 0 .../Substructures/Gen9/{ => SV}/PouchSize9.cs | 0 .../Gen9/{ => SV}/RaidSevenStar9.cs | 0 .../Gen9/{ => SV}/RaidSpawnList9.cs | 0 .../Gen9/{ => SV}/RuntimeLanguage.cs | 2 + .../Gen9/{ => SV}/ThrowStyle9.cs | 0 .../Substructures/Gen9/ZA/BlankBlocks9a.cs | 61 + .../Substructures/Gen9/ZA/BoxLayout9a.cs | 40 + .../Substructures/Gen9/ZA/Coordinates9a.cs | 70 + .../Gen9/ZA/EventWorkStorage64.cs | 207 ++ .../Substructures/Gen9/ZA/FashionItem9a.cs | 61 + .../Substructures/Gen9/ZA/HairMakeItem9a.cs | 57 + .../Gen9/ZA/IEventValueStorage.cs | 106 + .../Substructures/Gen9/ZA/InfiniteRoyale9a.cs | 13 + .../Saves/Substructures/Gen9/ZA/MyItem9a.cs | 125 + .../Saves/Substructures/Gen9/ZA/MyStatus9a.cs | 35 + .../Saves/Substructures/Gen9/ZA/Party9a.cs | 34 + .../Saves/Substructures/Gen9/ZA/PlayTime9a.cs | 107 + .../Substructures/Gen9/ZA/PlayerFashion9a.cs | 24 + .../Substructures/Gen9/ZA/PokeDexEntry9a.cs | 194 ++ .../Saves/Substructures/Gen9/ZA/Zukan9a.cs | 190 ++ .../Substructures/Inventory/IItemNewFlag.cs | 16 + .../Substructures/Inventory/InventoryType.cs | 1 + .../Inventory/Item/InventoryItem9a.cs | 98 + .../Inventory/Pouch/InventoryPouch9a.cs | 108 + PKHeX.Core/Saves/Util/BlankSaveFile.cs | 3 +- .../Util/{ => Detection}/SaveFileType.cs | 7 +- .../Saves/Util/Detection/SaveTypeInfo.cs | 21 + PKHeX.Core/Saves/Util/SaveUtil.cs | 57 +- PKHeX.Core/Util/ResourceUtil.cs | 21 + PKHeX.Drawing.Misc/Util/WallpaperUtil.cs | 4 + .../Builder/SpriteBuilderMode.cs | 2 +- .../Properties/Resources.Designer.cs | 1138 ++++++- .../Properties/Resources.resx | 377 ++- .../Resources/img/Artwork Items/aitem_103.png | Bin 0 -> 1718 bytes .../img/Artwork Items/aitem_2558.png | Bin 0 -> 1626 bytes .../img/Artwork Items/aitem_2559.png | Bin 0 -> 1478 bytes .../img/Artwork Items/aitem_2560.png | Bin 0 -> 1460 bytes .../img/Artwork Items/aitem_2561.png | Bin 0 -> 1598 bytes .../img/Artwork Items/aitem_2562.png | Bin 0 -> 1602 bytes .../img/Artwork Items/aitem_2563.png | Bin 0 -> 1515 bytes .../img/Artwork Items/aitem_2564.png | Bin 0 -> 1661 bytes .../img/Artwork Items/aitem_2565.png | Bin 0 -> 1586 bytes .../img/Artwork Items/aitem_2566.png | Bin 0 -> 1610 bytes .../img/Artwork Items/aitem_2569.png | Bin 0 -> 1590 bytes .../img/Artwork Items/aitem_2570.png | Bin 0 -> 1625 bytes .../img/Artwork Items/aitem_2571.png | Bin 0 -> 1584 bytes .../img/Artwork Items/aitem_2572.png | Bin 0 -> 1575 bytes .../img/Artwork Items/aitem_2573.png | Bin 0 -> 1519 bytes .../img/Artwork Items/aitem_2574.png | Bin 0 -> 1573 bytes .../img/Artwork Items/aitem_2575.png | Bin 0 -> 1541 bytes .../img/Artwork Items/aitem_2576.png | Bin 0 -> 1521 bytes .../img/Artwork Items/aitem_2577.png | Bin 0 -> 1626 bytes .../img/Artwork Items/aitem_2578.png | Bin 0 -> 1605 bytes .../img/Artwork Items/aitem_2579.png | Bin 0 -> 1611 bytes .../img/Artwork Items/aitem_2580.png | Bin 0 -> 1549 bytes .../img/Artwork Items/aitem_2581.png | Bin 0 -> 1574 bytes .../img/Artwork Items/aitem_2582.png | Bin 0 -> 1617 bytes .../img/Artwork Items/aitem_2583.png | Bin 0 -> 1514 bytes .../img/Artwork Items/aitem_2584.png | Bin 0 -> 1550 bytes .../img/Artwork Items/aitem_2585.png | Bin 0 -> 1579 bytes .../img/Artwork Items/aitem_2587.png | Bin 0 -> 1455 bytes .../img/Artwork Items/aitem_2618.png | Bin 0 -> 1470 bytes .../Resources/img/Artwork Items/aitem_646.png | Bin 0 -> 1506 bytes .../Resources/img/Artwork Items/aitem_647.png | Bin 0 -> 1586 bytes .../Resources/img/Artwork Items/aitem_656.png | Bin 0 -> 1597 bytes .../Resources/img/Artwork Items/aitem_657.png | Bin 0 -> 1540 bytes .../Resources/img/Artwork Items/aitem_658.png | Bin 0 -> 1554 bytes .../Resources/img/Artwork Items/aitem_659.png | Bin 0 -> 1546 bytes .../Resources/img/Artwork Items/aitem_660.png | Bin 0 -> 1616 bytes .../Resources/img/Artwork Items/aitem_661.png | Bin 0 -> 1633 bytes .../Resources/img/Artwork Items/aitem_662.png | Bin 0 -> 1635 bytes .../Resources/img/Artwork Items/aitem_663.png | Bin 0 -> 1630 bytes .../Resources/img/Artwork Items/aitem_665.png | Bin 0 -> 1623 bytes .../Resources/img/Artwork Items/aitem_666.png | Bin 0 -> 1555 bytes .../Resources/img/Artwork Items/aitem_667.png | Bin 0 -> 1443 bytes .../Resources/img/Artwork Items/aitem_668.png | Bin 0 -> 1594 bytes .../Resources/img/Artwork Items/aitem_669.png | Bin 0 -> 1562 bytes .../Resources/img/Artwork Items/aitem_670.png | Bin 0 -> 1500 bytes .../Resources/img/Artwork Items/aitem_671.png | Bin 0 -> 1612 bytes .../Resources/img/Artwork Items/aitem_672.png | Bin 0 -> 1611 bytes .../Resources/img/Artwork Items/aitem_673.png | Bin 0 -> 1568 bytes .../Resources/img/Artwork Items/aitem_674.png | Bin 0 -> 1578 bytes .../Resources/img/Artwork Items/aitem_675.png | Bin 0 -> 1563 bytes .../Resources/img/Artwork Items/aitem_676.png | Bin 0 -> 1596 bytes .../Resources/img/Artwork Items/aitem_677.png | Bin 0 -> 1573 bytes .../Resources/img/Artwork Items/aitem_678.png | Bin 0 -> 1535 bytes .../Resources/img/Artwork Items/aitem_679.png | Bin 0 -> 1563 bytes .../Resources/img/Artwork Items/aitem_680.png | Bin 0 -> 1489 bytes .../Resources/img/Artwork Items/aitem_681.png | Bin 0 -> 1591 bytes .../Resources/img/Artwork Items/aitem_682.png | Bin 0 -> 1504 bytes .../Resources/img/Artwork Items/aitem_683.png | Bin 0 -> 1567 bytes .../Resources/img/Artwork Items/aitem_710.png | Bin 0 -> 1983 bytes .../Resources/img/Artwork Items/aitem_711.png | Bin 0 -> 1899 bytes .../Resources/img/Artwork Items/aitem_754.png | Bin 0 -> 1526 bytes .../Resources/img/Artwork Items/aitem_755.png | Bin 0 -> 1480 bytes .../Resources/img/Artwork Items/aitem_756.png | Bin 0 -> 1531 bytes .../Resources/img/Artwork Items/aitem_757.png | Bin 0 -> 1400 bytes .../Resources/img/Artwork Items/aitem_758.png | Bin 0 -> 1560 bytes .../Resources/img/Artwork Items/aitem_759.png | Bin 0 -> 1571 bytes .../Resources/img/Artwork Items/aitem_760.png | Bin 0 -> 1626 bytes .../Resources/img/Artwork Items/aitem_761.png | Bin 0 -> 1568 bytes .../Resources/img/Artwork Items/aitem_762.png | Bin 0 -> 1511 bytes .../Resources/img/Artwork Items/aitem_763.png | Bin 0 -> 1529 bytes .../Resources/img/Artwork Items/aitem_764.png | Bin 0 -> 1470 bytes .../Resources/img/Artwork Items/aitem_767.png | Bin 0 -> 1641 bytes .../Resources/img/Artwork Items/aitem_768.png | Bin 0 -> 1522 bytes .../Resources/img/Artwork Items/aitem_769.png | Bin 0 -> 1637 bytes .../Resources/img/Artwork Items/aitem_770.png | Bin 0 -> 1586 bytes .../img/Artwork Pokemon Sprites/a_121-1.png | Bin 0 -> 5339 bytes .../img/Artwork Pokemon Sprites/a_149-1.png | Bin 0 -> 5913 bytes .../img/Artwork Pokemon Sprites/a_154-1.png | Bin 0 -> 4099 bytes .../img/Artwork Pokemon Sprites/a_160-1.png | Bin 0 -> 6068 bytes .../img/Artwork Pokemon Sprites/a_227-1.png | Bin 0 -> 5254 bytes .../img/Artwork Pokemon Sprites/a_25f.png | Bin 2958 -> 0 bytes .../img/Artwork Pokemon Sprites/a_36-1.png | Bin 0 -> 5049 bytes .../img/Artwork Pokemon Sprites/a_478-1.png | Bin 0 -> 4699 bytes .../img/Artwork Pokemon Sprites/a_500-1.png | Bin 0 -> 6393 bytes .../img/Artwork Pokemon Sprites/a_530-1.png | Bin 0 -> 3835 bytes .../img/Artwork Pokemon Sprites/a_545-1.png | Bin 0 -> 3742 bytes .../img/Artwork Pokemon Sprites/a_560-1.png | Bin 0 -> 3969 bytes .../img/Artwork Pokemon Sprites/a_604-1.png | Bin 0 -> 5701 bytes .../img/Artwork Pokemon Sprites/a_609-1.png | Bin 0 -> 5008 bytes .../img/Artwork Pokemon Sprites/a_652-1.png | Bin 0 -> 5746 bytes .../img/Artwork Pokemon Sprites/a_655-1.png | Bin 0 -> 4228 bytes .../img/Artwork Pokemon Sprites/a_658-3.png | Bin 0 -> 4144 bytes .../img/Artwork Pokemon Sprites/a_668-1.png | Bin 0 -> 5079 bytes .../img/Artwork Pokemon Sprites/a_668-1f.png | Bin 0 -> 4362 bytes .../img/Artwork Pokemon Sprites/a_670-6.png | Bin 0 -> 2798 bytes .../img/Artwork Pokemon Sprites/a_687-1.png | Bin 0 -> 4784 bytes .../img/Artwork Pokemon Sprites/a_689-1.png | Bin 0 -> 6258 bytes .../img/Artwork Pokemon Sprites/a_691-1.png | Bin 0 -> 3827 bytes .../img/Artwork Pokemon Sprites/a_701-1.png | Bin 0 -> 3657 bytes .../img/Artwork Pokemon Sprites/a_71-1.png | Bin 0 -> 4281 bytes .../img/Artwork Pokemon Sprites/a_718-5.png | Bin 0 -> 4585 bytes .../img/Artwork Pokemon Sprites/a_780-1.png | Bin 0 -> 4798 bytes .../img/Artwork Pokemon Sprites/a_870-1.png | Bin 0 -> 5159 bytes .../{b_25-1cf.png => b_25-1c.png} | Bin .../{b_25-2cf.png => b_25-2c.png} | Bin .../{b_25-3cf.png => b_25-3c.png} | Bin .../{b_25-4cf.png => b_25-4c.png} | Bin .../{b_25-5cf.png => b_25-5c.png} | Bin .../{b_25-6cf.png => b_25-6c.png} | Bin .../img/Big Pokemon Sprites/b_25-8pf.png | Bin 688 -> 0 bytes .../img/Big Pokemon Sprites/b_25f.png | Bin 539 -> 0 bytes .../{b_25-1cfs.png => b_25-1cs.png} | Bin .../{b_25-2cfs.png => b_25-2cs.png} | Bin .../{b_25-3cfs.png => b_25-3cs.png} | Bin .../{b_25-4cfs.png => b_25-4cs.png} | Bin .../{b_25-5cfs.png => b_25-5cs.png} | Bin .../{b_25-6cfs.png => b_25-6cs.png} | Bin .../img/Big Shiny Sprites/b_25-8pfs.png | Bin 715 -> 0 bytes .../img/Big Shiny Sprites/b_25fs.png | Bin 549 -> 0 bytes .../Legends Arceus Shiny Sprites/c_25fs.png | Bin 4787 -> 0 bytes .../img/Legends Arceus Sprites/c_25f.png | Bin 4847 -> 0 bytes PKHeX.Drawing.PokeSprite/Util/SpriteName.cs | 7 +- PKHeX.WinForms/Controls/PKM Editor/EditPK2.cs | 2 +- PKHeX.WinForms/Controls/PKM Editor/EditPK9.cs | 40 + .../Controls/PKM Editor/LoadSave.cs | 21 +- .../Controls/PKM Editor/MoveChoice.cs | 5 +- .../Controls/PKM Editor/PKMEditor.Designer.cs | 20 +- .../Controls/PKM Editor/PKMEditor.cs | 28 +- .../Controls/PKM Editor/StatEditor.cs | 3 +- .../Controls/SAV Editor/SAVEditor.Designer.cs | 50 +- .../Controls/SAV Editor/SAVEditor.cs | 14 +- .../Controls/SAV Editor/SlotChangeManager.cs | 2 +- PKHeX.WinForms/MainWindow/Main.cs | 6 + .../Properties/Resources.Designer.cs | 112 +- PKHeX.WinForms/Properties/Resources.resx | 8 +- PKHeX.WinForms/Resources/img/Bag/bag_mega.png | Bin 0 -> 1178 bytes .../Resources/img/Markings/gen_za.png | Bin 0 -> 1203 bytes PKHeX.WinForms/Subforms/KChart.cs | 22 +- .../PKM Editors/PlusRecordEditor.Designer.cs | 192 ++ .../Subforms/PKM Editors/PlusRecordEditor.cs | 170 ++ .../Subforms/PKM Editors/TechRecordEditor.cs | 3 +- PKHeX.WinForms/Subforms/PKM Editors/Text.cs | 6 +- .../Save Editors/Gen4/SAV_BattlePass.cs | 2 +- .../Save Editors/Gen4/SAV_Trainer4BR.cs | 2 +- .../Gen6/SAV_Pokepuff.Designer.cs | 4 +- .../Subforms/Save Editors/Gen6/SAV_Trainer.cs | 2 +- .../Gen7/SAV_Pokebean.Designer.cs | 4 +- .../Save Editors/Gen7/SAV_Trainer7.cs | 2 +- .../Save Editors/Gen7/SAV_Trainer7GG.cs | 2 +- .../Save Editors/Gen8/SAV_Trainer8.cs | 2 +- .../Save Editors/Gen8/SAV_Trainer8a.cs | 2 +- .../Save Editors/Gen8/SAV_Trainer8b.cs | 2 +- .../Save Editors/Gen9/EventWorkGrid64.cs | 303 ++ .../Gen9/SAV_Fashion9a.Designer.cs | 97 + .../Save Editors/Gen9/SAV_Fashion9a.cs | 461 +++ .../Gen9/SAV_FlagWork9a.Designer.cs | 226 ++ .../Save Editors/Gen9/SAV_FlagWork9a.cs | 186 ++ .../Gen9/SAV_Pokedex9a.Designer.cs | 651 ++++ .../Save Editors/Gen9/SAV_Pokedex9a.cs | 307 ++ .../Gen9/SAV_Trainer9.Designer.cs | 1 + .../Save Editors/Gen9/SAV_Trainer9.cs | 4 +- .../Gen9/SAV_Trainer9a.Designer.cs | 1139 +++++++ .../Save Editors/Gen9/SAV_Trainer9a.cs | 203 ++ .../Subforms/Save Editors/SAV_EventWork.cs | 1 + .../Subforms/Save Editors/SAV_Inventory.cs | 44 +- .../Subforms/Save Editors/SAV_MailBox.cs | 2 +- README.md | 2 +- 556 files changed, 25614 insertions(+), 900 deletions(-) create mode 100644 PKHeX.Core/Editing/Applicators/PlusRecordApplicator.cs create mode 100644 PKHeX.Core/Game/Locations/Locations9a.cs create mode 100644 PKHeX.Core/Items/ItemStorage9ZA.cs create mode 100644 PKHeX.Core/Legality/Bulk/SaveFile/DuplicateFusionChecker.cs create mode 100644 PKHeX.Core/Legality/Bulk/SaveFile/DuplicateMegaChecker.cs create mode 100644 PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Generator/ByGeneration/Lump/EncounterGenerator9X.cs create mode 100644 PKHeX.Core/Legality/Encounters/Generator/Possible/EncounterPossible9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterArea9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterGift9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterSlot9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterStatic9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterTrade9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/GenerateParam9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/IEncounter9a.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseCorrelation.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseRNG.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseSolver.cs create mode 100644 PKHeX.Core/Legality/Encounters/Templates/Gen9a/SlotType9a.cs create mode 100644 PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME2.cs create mode 100644 PKHeX.Core/Legality/LearnSource/Group/LearnGroup9a.cs create mode 100644 PKHeX.Core/Legality/LearnSource/Sources/LearnSource9ZA.cs create mode 100644 PKHeX.Core/Legality/Verifiers/LegendsZAVerifier.cs create mode 100644 PKHeX.Core/Moves/MoveInfo9a.cs create mode 100644 PKHeX.Core/MysteryGifts/WA9.cs create mode 100644 PKHeX.Core/PKM/HOME/GameDataPA9.cs create mode 100644 PKHeX.Core/PKM/Interfaces/IPlusRecord.cs create mode 100644 PKHeX.Core/PKM/PA9.cs create mode 100644 PKHeX.Core/PersonalInfo/Info/PersonalInfo9ZA.cs create mode 100644 PKHeX.Core/PersonalInfo/Table/PersonalTable9ZA.cs create mode 100644 PKHeX.Core/Resources/byte/evolve/evos_za.pkl create mode 100644 PKHeX.Core/Resources/byte/levelup/lvlmove_za.pkl create mode 100644 PKHeX.Core/Resources/byte/personal/personal_za create mode 100644 PKHeX.Core/Resources/byte/personal/reminder_za.pkl create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_de.txt create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_en.txt create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_es-419.txt create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_es.txt create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_fr.txt create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_it.txt create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_ja.txt create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_ko.txt create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_zh-Hans.txt create mode 100644 PKHeX.Core/Resources/legality/gen9a/text_tradeza_zh-Hant.txt create mode 100644 PKHeX.Core/Resources/legality/mgdb/wa9.pkl create mode 100644 PKHeX.Core/Resources/legality/misc/plus_za.pkl create mode 100644 PKHeX.Core/Resources/legality/wild/Gen9/encounter_za.pkl create mode 100644 PKHeX.Core/Resources/text/items/text_Items_es-419.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_de.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_en.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_es-419.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_es.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_fr.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_it.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_ja.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_ko.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_zh-Hans.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_zh-Hant.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_de.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_en.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_es-419.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_es.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_fr.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_it.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_ja.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_ko.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_zh-Hans.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_zh-Hant.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_de.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_en.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_es-419.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_es.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_fr.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_it.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_ja.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_ko.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_zh-Hans.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_zh-Hant.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_de.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_en.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_es-419.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_es.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_fr.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_it.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_ja.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_ko.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_zh-Hans.txt create mode 100644 PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_zh-Hant.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Abilities_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Character_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Forms_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Games_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_GroundTile_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Moves_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Natures_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Pokeblock_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Puff_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Ribbons_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Species_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_SuperTraining_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_TrainingBag_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Types_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/es-419/text_Wallpaper_es-419.txt create mode 100644 PKHeX.Core/Resources/text/other/text_language_e-419.txt create mode 100644 PKHeX.Core/Saves/Access/SaveBlockAccessor9ZA.cs create mode 100644 PKHeX.Core/Saves/SAV9ZA.cs rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/BlankBlocks9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/BlueberryClubRoom9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/BlueberryQuestRecord9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/Box9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/BoxLayout9.cs (91%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/ConfigCamera9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/ConfigSave9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/DXT1.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/FixedSpawnList9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/MyItem9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/MyStatus9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/Party9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/PlayTime9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/PlayerAppearance9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/PlayerFashion9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/PlayerFashionUnlock9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/PouchSize9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/RaidSevenStar9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/RaidSpawnList9.cs (100%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/RuntimeLanguage.cs (92%) rename PKHeX.Core/Saves/Substructures/Gen9/{ => SV}/ThrowStyle9.cs (100%) create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/BlankBlocks9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/BoxLayout9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/Coordinates9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/EventWorkStorage64.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/FashionItem9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/HairMakeItem9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/IEventValueStorage.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/InfiniteRoyale9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/MyItem9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/MyStatus9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/Party9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/PlayTime9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/PlayerFashion9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/PokeDexEntry9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen9/ZA/Zukan9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Inventory/Item/InventoryItem9a.cs create mode 100644 PKHeX.Core/Saves/Substructures/Inventory/Pouch/InventoryPouch9a.cs rename PKHeX.Core/Saves/Util/{ => Detection}/SaveFileType.cs (96%) create mode 100644 PKHeX.Core/Saves/Util/Detection/SaveTypeInfo.cs create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_103.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2558.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2559.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2560.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2561.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2562.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2563.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2564.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2565.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2566.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2569.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2570.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2571.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2572.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2573.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2574.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2575.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2576.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2577.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2578.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2579.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2580.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2581.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2582.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2583.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2584.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2585.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2587.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_2618.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_646.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_647.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_656.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_657.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_658.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_659.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_660.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_661.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_662.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_663.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_665.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_666.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_667.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_668.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_669.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_670.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_671.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_672.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_673.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_674.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_675.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_676.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_677.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_678.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_679.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_680.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_681.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_682.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_683.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_710.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_711.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_754.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_755.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_756.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_757.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_758.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_759.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_760.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_761.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_762.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_763.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_764.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_767.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_768.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_769.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Items/aitem_770.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_121-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_149-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_154-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_160-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_227-1.png delete mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_25f.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_36-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_478-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_500-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_530-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_545-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_560-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_604-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_609-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_652-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_655-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_658-3.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_668-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_668-1f.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_670-6.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_687-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_689-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_691-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_701-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_71-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_718-5.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_780-1.png create mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Artwork Pokemon Sprites/a_870-1.png rename PKHeX.Drawing.PokeSprite/Resources/img/Big Pokemon Sprites/{b_25-1cf.png => b_25-1c.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Pokemon Sprites/{b_25-2cf.png => b_25-2c.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Pokemon Sprites/{b_25-3cf.png => b_25-3c.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Pokemon Sprites/{b_25-4cf.png => b_25-4c.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Pokemon Sprites/{b_25-5cf.png => b_25-5c.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Pokemon Sprites/{b_25-6cf.png => b_25-6c.png} (100%) delete mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Big Pokemon Sprites/b_25-8pf.png delete mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Big Pokemon Sprites/b_25f.png rename PKHeX.Drawing.PokeSprite/Resources/img/Big Shiny Sprites/{b_25-1cfs.png => b_25-1cs.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Shiny Sprites/{b_25-2cfs.png => b_25-2cs.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Shiny Sprites/{b_25-3cfs.png => b_25-3cs.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Shiny Sprites/{b_25-4cfs.png => b_25-4cs.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Shiny Sprites/{b_25-5cfs.png => b_25-5cs.png} (100%) rename PKHeX.Drawing.PokeSprite/Resources/img/Big Shiny Sprites/{b_25-6cfs.png => b_25-6cs.png} (100%) delete mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Big Shiny Sprites/b_25-8pfs.png delete mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Big Shiny Sprites/b_25fs.png delete mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Legends Arceus Shiny Sprites/c_25fs.png delete mode 100644 PKHeX.Drawing.PokeSprite/Resources/img/Legends Arceus Sprites/c_25f.png create mode 100644 PKHeX.WinForms/Resources/img/Bag/bag_mega.png create mode 100644 PKHeX.WinForms/Resources/img/Markings/gen_za.png create mode 100644 PKHeX.WinForms/Subforms/PKM Editors/PlusRecordEditor.Designer.cs create mode 100644 PKHeX.WinForms/Subforms/PKM Editors/PlusRecordEditor.cs create mode 100644 PKHeX.WinForms/Subforms/Save Editors/Gen9/EventWorkGrid64.cs create mode 100644 PKHeX.WinForms/Subforms/Save Editors/Gen9/SAV_Fashion9a.Designer.cs create mode 100644 PKHeX.WinForms/Subforms/Save Editors/Gen9/SAV_Fashion9a.cs create mode 100644 PKHeX.WinForms/Subforms/Save Editors/Gen9/SAV_FlagWork9a.Designer.cs create mode 100644 PKHeX.WinForms/Subforms/Save Editors/Gen9/SAV_FlagWork9a.cs create mode 100644 PKHeX.WinForms/Subforms/Save Editors/Gen9/SAV_Pokedex9a.Designer.cs create mode 100644 PKHeX.WinForms/Subforms/Save Editors/Gen9/SAV_Pokedex9a.cs create mode 100644 PKHeX.WinForms/Subforms/Save Editors/Gen9/SAV_Trainer9a.Designer.cs create mode 100644 PKHeX.WinForms/Subforms/Save Editors/Gen9/SAV_Trainer9a.cs diff --git a/.github/README-de.md b/.github/README-de.md index 2dcca6124..bb9a6cc09 100644 --- a/.github/README-de.md +++ b/.github/README-de.md @@ -24,7 +24,7 @@ PKHeX erwartet entschlüsselte Spielstände. Da diese konsolenspezifisch verschl ## Screenshots -![Main Window](https://i.imgur.com/7ErmRJI.png) +![Main Window](https://i.imgur.com/0KYz0rO.png) ## Erstellen diff --git a/.github/README-es.md b/.github/README-es.md index 9c94a13df..86862964d 100644 --- a/.github/README-es.md +++ b/.github/README-es.md @@ -24,7 +24,7 @@ PKHeX espera archivos de guardado que no estén cifrados con las claves específ ## Capturas de Pantalla -![Pantalla principal](https://i.imgur.com/oM407mV.png) +![Pantalla principal](https://i.imgur.com/JFKIhnz.png) ## Building diff --git a/.github/README-fr.md b/.github/README-fr.md index 28d0a0cb0..b370d57a0 100644 --- a/.github/README-fr.md +++ b/.github/README-fr.md @@ -23,7 +23,7 @@ PKHeX attend des fichiers de sauvegarde qui ne sont pas chiffrés avec des clés ## Captures d'écran -![Main Window](https://i.imgur.com/YEdBzlt.png) +![Main Window](https://i.imgur.com/CpUzqmY.png) ## Construction diff --git a/.github/README-it.md b/.github/README-it.md index eb5e69bde..7d170465b 100644 --- a/.github/README-it.md +++ b/.github/README-it.md @@ -24,7 +24,7 @@ PKHeX si aspetta file di salvataggio non criptati con le chiavi specifiche della ## Screenshots -![Main Window](https://i.imgur.com/ICmQ41m.png) +![Main Window](https://i.imgur.com/vrWs9Xq.png) ## Building diff --git a/.github/README-ko.md b/.github/README-ko.md index 863367638..1059b664c 100644 --- a/.github/README-ko.md +++ b/.github/README-ko.md @@ -24,7 +24,7 @@ PKHeX는 콘솔 전용 키로 암호화되지 않은 세이브 파일을 요구 ## 스크린샷 -![Main Window](https://i.imgur.com/HZs37cM.png) +![Main Window](https://i.imgur.com/vDiaS7k.png) ## 빌드 diff --git a/.github/README-zh-Hans.md b/.github/README-zh-Hans.md index 2473c0f2d..84a7ca896 100644 --- a/.github/README-zh-Hans.md +++ b/.github/README-zh-Hans.md @@ -24,7 +24,7 @@ PKHeX 所读取存档文件必须是未经主机唯一密钥加密,因此请 ## 截图 -![主介面](https://i.imgur.com/SfskT2Q.png) +![主介面](https://i.imgur.com/MPN4Hk9.png) ## 构建 diff --git a/.github/README-zh-Hant.md b/.github/README-zh-Hant.md index e5ca632ea..099490ad2 100644 --- a/.github/README-zh-Hant.md +++ b/.github/README-zh-Hant.md @@ -24,7 +24,7 @@ PKHeX 所讀取檔案須未經主機唯一密鑰加密,因而請使用儲存 ## 螢幕擷取截圖 -![主介面](https://i.imgur.com/zEGGuJC.png) +![主介面](https://i.imgur.com/8IQx2jo.png) ## 構建 diff --git a/PKHeX.Core/Editing/Applicators/PlusRecordApplicator.cs b/PKHeX.Core/Editing/Applicators/PlusRecordApplicator.cs new file mode 100644 index 000000000..d7a6f262d --- /dev/null +++ b/PKHeX.Core/Editing/Applicators/PlusRecordApplicator.cs @@ -0,0 +1,195 @@ +using System; + +namespace PKHeX.Core; + +/// +/// Logic for modifying the Plus Record flags of a . +/// +public static class PlusRecordApplicator +{ + /// + /// Sets all the Plus Record flags for the to the given value. + /// + /// Pokémon to modify. + /// Total count of flags to modify [0,x). + /// Value to set for each record. + public static void SetPlusFlagsAll(this IPlusRecord record, int count, bool value) + { + for (int i = 0; i < count; i++) + record.SetMovePlusFlag(i, value); + } + + /// + /// Clears the Plus Record flags for the . + /// + /// Pokémon to modify. + /// Total count of flags to modify [0,x). + public static void ClearPlusFlags(this IPlusRecord record, int count) => record.SetPlusFlagsAll(count, false); + + /// + /// Sets the Plus Record flags for the based on the legality of learning moves. + /// + /// Pokémon to modify. + /// Sanity check to retrieve plus record indexes. + /// Legality analysis of the Pokémon. + /// Use a Seed of Mastery to bypass the level requirement of mastering the move. + /// Apply TM flags as Plus too. + public static void SetPlusFlags(this IPlusRecord record, IPermitPlus permit, LegalityAnalysis la, bool seedOfMastery, bool tm) + { + // Hopefully this is only called for Legends: Z-A format entities. + var entity = la.Entity; + var context = entity.Context; + var evos = la.Info.EvoChainsAllGens.Get(context); + switch (la.Entity.Context) + { + case EntityContext.Gen9a: + { + var learn = LearnSource9ZA.Instance; + SetPlusFlagsNatural(record, permit, evos, learn, seedOfMastery); + if (tm) + { + var table = PersonalTable.ZA; + SetPlusFlagsTM(record, permit, evos, learn, seedOfMastery, table); + } + break; + } + default: + throw new Exception("Format not supported."); + } + } + + public static void SetPlusFlagsNatural(IPlusRecord record, IPermitPlus permit, ReadOnlySpan evos, TSource source, bool seedOfMastery) where TSource : ILearnSourceBonus + { + var indexes = permit.PlusMoveIndexes; + foreach (var evo in evos) + { + var (levelUp, plus) = source.GetLearnsetAndOther(evo.Species, evo.Form); + var set = seedOfMastery ? levelUp : plus; + var levels = set.GetAllLevels(); + var moves = set.GetAllMoves(); + for (int i = 0; i < levels.Length; i++) + { + if (evo.LevelMax < levels[i]) + break; + + var move = moves[i]; + var index = indexes.IndexOf(move); + record.SetMovePlusFlag(index); + } + } + } + + public static void SetPlusFlagsTM(IPlusRecord record, IPermitPlus permit, + ReadOnlySpan evos, + TSource source, bool seedOfMastery, + TTable table) + where TTable : IPersonalTable + where TInfo : IPersonalInfo, IPersonalInfoTM + where TSource : ILearnSourceBonus + { + var indexes = permit.PlusMoveIndexes; + foreach (var evo in evos) + { + var pi = table[evo.Species, evo.Form]; + var (levelUp, plus) = source.GetLearnsetAndOther(evo.Species, evo.Form); + var set = seedOfMastery ? levelUp : plus; + for (int index = 0; index < indexes.Length; index++) + { + var move = indexes[index]; + var tmIndex = permit.RecordPermitIndexes.IndexOf(move); + if (tmIndex != -1 && pi.GetIsLearnTM(tmIndex)) + record.SetMovePlusFlag(index); + } + } + } + + /// + /// Sets all moves that would be learned and naturally available as Plus based on the given level + /// + /// Record to modify + /// Permit to use + /// Learnset to use + /// Current level + /// Extra moves to set as Plus + public static void SetPlusFlagsEncounter(IPlusRecord record, IPermitPlus permit, Learnset plus, byte level, params ReadOnlySpan extra) + { + var indexes = permit.PlusMoveIndexes; + var levels = plus.GetAllLevels(); + var moves = plus.GetAllMoves(); + + for (int i = 0; i < levels.Length; i++) + { + if (level < levels[i]) + break; + + var move = moves[i]; + var index = indexes.IndexOf(move); + record.SetMovePlusFlag(index); + } + + if (extra.Length != 0) + SetPlusFlagsSpecific(record, permit, extra); + } + + public static void SetPlusFlagsSpecific(IPlusRecord record, IPermitPlus permit, ReadOnlySpan extra) + { + var indexes = permit.PlusMoveIndexes; + foreach (var move in extra) + { + var index = indexes.IndexOf(move); + record.SetMovePlusFlag(index); + } + } + + public static void SetPlusFlags(this T pk, IPermitPlus permit, PlusRecordApplicatorOption option) + where T : PKM, IPlusRecord + => SetPlusFlags(pk, pk, permit, option); + + public static void SetPlusFlags(this IPlusRecord record, PKM pk, IPermitPlus permit, PlusRecordApplicatorOption option) + { + record.ClearPlusFlags(permit.PlusCountTotal); + if (option is PlusRecordApplicatorOption.None) + return; + if (option is PlusRecordApplicatorOption.ForceAll) + { + record.SetPlusFlagsAll(permit.PlusCountUsed, true); + return; + } + + var la = new LegalityAnalysis(pk); + SetPlusFlagsInternal(record, permit, option, la); + } + + public static void SetPlusFlags(this IPlusRecord record, IPermitPlus permit, PlusRecordApplicatorOption option, LegalityAnalysis la) + { + record.ClearPlusFlags(permit.PlusCountTotal); + if (option is PlusRecordApplicatorOption.None) + return; + if (option is PlusRecordApplicatorOption.ForceAll) + { + record.SetPlusFlagsAll(permit.PlusCountUsed, true); + return; + } + + SetPlusFlagsInternal(record, permit, option, la); + } + + private static void SetPlusFlagsInternal(IPlusRecord record, IPermitPlus permit, PlusRecordApplicatorOption option, LegalityAnalysis la) + { + if (option is PlusRecordApplicatorOption.LegalCurrent) + record.SetPlusFlags(permit, la, false, false); + else if (option is PlusRecordApplicatorOption.LegalCurrentTM) + record.SetPlusFlags(permit, la, false, true); + else if (option is PlusRecordApplicatorOption.LegalSeedTM) + record.SetPlusFlags(permit, la, true, true); + } +} + +public enum PlusRecordApplicatorOption +{ + None, + ForceAll, + LegalCurrent, + LegalCurrentTM, + LegalSeedTM, +} diff --git a/PKHeX.Core/Editing/Applicators/TechnicalRecordApplicator.cs b/PKHeX.Core/Editing/Applicators/TechnicalRecordApplicator.cs index a2532022c..f1ee00923 100644 --- a/PKHeX.Core/Editing/Applicators/TechnicalRecordApplicator.cs +++ b/PKHeX.Core/Editing/Applicators/TechnicalRecordApplicator.cs @@ -104,6 +104,8 @@ public static void SetRecordFlags(this ITechRecord pk, ReadOnlySpan move { if (pk is PK9 pk9) SetRecordFlags(pk9, moves, evos, PersonalTable.SV); + else if (pk is PA9 pa9) + SetRecordFlags(pa9, moves, evos, PersonalTable.ZA); else if (pk is PK8 pk8) SetRecordFlags(pk8, moves, evos, PersonalTable.SWSH); } @@ -113,6 +115,8 @@ public static void SetRecordFlagsAll(this ITechRecord pk, ReadOnlySpan(pk9, evos, PersonalTable.SV); + else if (pk is PA9 pa9) + SetRecordFlagsAll(pa9, evos, PersonalTable.ZA); else if (pk is PK8 pk8) SetRecordFlagsAll(pk8, evos, PersonalTable.SWSH); } @@ -121,6 +125,7 @@ public static void SetRecordFlagsAll(this ITechRecord pk, ReadOnlySpan evos, int index) => pk switch { PK9 => IsRecordPermitted(evos, PersonalTable.SV, index), + PA9 => IsRecordPermitted(evos, PersonalTable.ZA, index), PK8 => IsRecordPermitted(evos, PersonalTable.SWSH, index), _ => false, }; diff --git a/PKHeX.Core/Editing/BattleTemplate/BattleTemplateConfig.cs b/PKHeX.Core/Editing/BattleTemplate/BattleTemplateConfig.cs index 8cfb3dcc1..a6f223ed9 100644 --- a/PKHeX.Core/Editing/BattleTemplate/BattleTemplateConfig.cs +++ b/PKHeX.Core/Editing/BattleTemplate/BattleTemplateConfig.cs @@ -49,7 +49,7 @@ public sealed record BattleTemplateTuple(BattleTemplateToken Token, string Text) public static ReadOnlySpan GetMoveDisplay(MoveDisplayStyle style = MoveDisplayStyle.Fill) => style switch { MoveDisplayStyle.Fill => "----", - MoveDisplayStyle.Directional => "↑←↓→", + MoveDisplayStyle.Directional => "↑→←↓", _ => throw new ArgumentOutOfRangeException(nameof(style), style, null), }; diff --git a/PKHeX.Core/Editing/BattleTemplate/BattleTemplateTypeSetting.cs b/PKHeX.Core/Editing/BattleTemplate/BattleTemplateTypeSetting.cs index 6a2ca48fa..82b4f205e 100644 --- a/PKHeX.Core/Editing/BattleTemplate/BattleTemplateTypeSetting.cs +++ b/PKHeX.Core/Editing/BattleTemplate/BattleTemplateTypeSetting.cs @@ -70,7 +70,7 @@ private static LanguageID GetLanguage(LanguageID choice, LanguageID program) private static MoveDisplayStyle GetMoveDisplayStyle(MoveDisplayStyle style, EntityContext context) => style switch { - //MoveDisplayStyle.Directional when context is EntityContext.Gen9a => MoveDisplayStyle.Directional, TODO ZA + MoveDisplayStyle.Directional when context is EntityContext.Gen9a => MoveDisplayStyle.Directional, _ => MoveDisplayStyle.Fill, }; } diff --git a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownParsing.cs b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownParsing.cs index 8317c8d69..03ea5d0e1 100644 --- a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownParsing.cs +++ b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownParsing.cs @@ -154,6 +154,9 @@ public static string GetFormNameFromShowdownFormName(ushort species, string form (int)Maushold when form is "Four" => "Family of Four", (int)Urshifu or (int)Pikachu or (int)Alcremie => form.Replace('-', ' '), // Strike and Cosplay + (int)Pumpkaboo or (int)Gourgeist when form is "Average" => "Medium", + (int)Pumpkaboo or (int)Gourgeist when form is "Super" => "Jumbo", + _ => FormInfo.HasTotemForm(species) && form.EndsWith("Totem", StringComparison.OrdinalIgnoreCase) ? "Large" : form, }; } diff --git a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs index bfd378837..51c78dd66 100644 --- a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs +++ b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs @@ -523,7 +523,7 @@ private static string GetSpeciesNickname(string specForm, string nickname, ushor { if (nickname.Length == 0 || nickname == specForm) return specForm; - bool isNicknamed = SpeciesName.IsNicknamedAnyLanguage(species, nickname, context.Generation()); + bool isNicknamed = SpeciesName.IsNicknamedAnyLanguage(species, nickname, context); if (!isNicknamed) return specForm; return $"{nickname} ({specForm})"; diff --git a/PKHeX.Core/Editing/Bulk/BatchEditing.cs b/PKHeX.Core/Editing/Bulk/BatchEditing.cs index ff49d4751..a2ffdf67b 100644 --- a/PKHeX.Core/Editing/Bulk/BatchEditing.cs +++ b/PKHeX.Core/Editing/Bulk/BatchEditing.cs @@ -17,7 +17,7 @@ public static class BatchEditing { public static readonly Type[] Types = [ - typeof (PK9), + typeof (PK9), typeof (PA9), typeof (PK8), typeof (PA8), typeof (PB8), typeof (PB7), typeof (PK7), typeof (PK6), typeof (PK5), typeof (PK4), typeof(BK4), typeof(RK4), @@ -30,7 +30,7 @@ public static class BatchEditing /// private static readonly string[] CustomProperties = [ - PROP_LEGAL, PROP_TYPENAME, PROP_RIBBONS, PROP_CONTESTSTATS, PROP_MOVEMASTERY, + PROP_LEGAL, PROP_TYPENAME, PROP_RIBBONS, PROP_CONTESTSTATS, PROP_MOVEMASTERY, PROP_MOVEPLUS, PROP_TYPE1, PROP_TYPE2, PROP_TYPEEITHER, IdentifierContains, nameof(ISlotInfo.Slot), nameof(SlotInfoBox.Box), ]; @@ -77,6 +77,7 @@ public static class BatchEditing internal const string PROP_EVS = "EVs"; internal const string PROP_CONTESTSTATS = "ContestStats"; internal const string PROP_MOVEMASTERY = "MoveMastery"; + internal const string PROP_MOVEPLUS = "PlusMoves"; internal const string IdentifierContains = nameof(IdentifierContains); private static string[][] GetPropArray(Dictionary.AlternateLookup>[] types, ReadOnlySpan extra) diff --git a/PKHeX.Core/Editing/Bulk/BatchMods.cs b/PKHeX.Core/Editing/Bulk/BatchMods.cs index b040921cc..50cbb2786 100644 --- a/PKHeX.Core/Editing/Bulk/BatchMods.cs +++ b/PKHeX.Core/Editing/Bulk/BatchMods.cs @@ -52,6 +52,7 @@ public static class BatchMods new ComplexSuggestion(nameof(PKM.CurrentLevel), (_, _, info) => BatchModifications.SetMinimumCurrentLevel(info)), new ComplexSuggestion(PROP_CONTESTSTATS, p => p is IContestStats, (_, value, info) => BatchModifications.SetContestStats(info.Entity, info.Legality, value)), new ComplexSuggestion(PROP_MOVEMASTERY, (_, value, info) => BatchModifications.SetSuggestedMasteryData(info, value)), + new ComplexSuggestion(PROP_MOVEPLUS, (_, value, info) => BatchModifications.SetSuggestedMovePlusData(info, value)), ]; private static DateOnly ParseDate(ReadOnlySpan val) => DateOnly.ParseExact(val, "yyyyMMdd", CultureInfo.InvariantCulture); diff --git a/PKHeX.Core/Editing/Bulk/Suggestion/BatchModifications.cs b/PKHeX.Core/Editing/Bulk/Suggestion/BatchModifications.cs index 6185ae1ec..e87cf8c7c 100644 --- a/PKHeX.Core/Editing/Bulk/Suggestion/BatchModifications.cs +++ b/PKHeX.Core/Editing/Bulk/Suggestion/BatchModifications.cs @@ -69,6 +69,28 @@ public static ModifyResult SetSuggestedMasteryData(BatchInfo info, ReadOnlySpan< return ModifyResult.Modified; } + /// + /// Sets all legal Plus Move flag data for the Entity. + /// + /// Only applicable for . + public static ModifyResult SetSuggestedMovePlusData(BatchInfo info, ReadOnlySpan value) + { + var pk = info.Entity; + if (pk is not IPlusRecord t || pk.PersonalInfo is not IPermitPlus p) + return ModifyResult.Skipped; + + PlusRecordApplicatorOption option; + if (IsNone(value)) + option = PlusRecordApplicatorOption.None; + else if (IsAll(value)) + option = PlusRecordApplicatorOption.LegalSeedTM; + else + option = PlusRecordApplicatorOption.LegalCurrent; + + t.SetPlusFlags(p, option, info.Legality); + return ModifyResult.Modified; + } + /// /// Sets suggested ribbon data for the Entity. /// diff --git a/PKHeX.Core/Editing/CommonEdits.cs b/PKHeX.Core/Editing/CommonEdits.cs index bab771bd3..74cea4e06 100644 --- a/PKHeX.Core/Editing/CommonEdits.cs +++ b/PKHeX.Core/Editing/CommonEdits.cs @@ -58,7 +58,8 @@ public static void SetAbility(this PKM pk, int abilityID) if (abilityID < 0) return; var index = pk.PersonalInfo.GetIndexOfAbility(abilityID); - index = Math.Max(0, index); + if (index < 0) + return; // leave original value pk.SetAbilityIndex(index); } @@ -258,6 +259,13 @@ public static void ApplySetDetails(this PKM pk, IBattleTemplate set) t.ClearRecordFlags(); t.SetRecordFlags(set.Moves, legal.Info.EvoChainsAllGens.Get(pk.Context)); } + + if (pk is IPlusRecord plus && pk.PersonalInfo is IPermitPlus permit) + { + plus.ClearPlusFlags(permit.PlusCountTotal); + plus.SetPlusFlags(permit, legal, true, true); + } + if (legal.Parsed && !MoveResult.AllValid(legal.Info.Relearn)) pk.SetRelearnMoves(legal); pk.ResetPartyStats(); diff --git a/PKHeX.Core/Editing/Pokerus.cs b/PKHeX.Core/Editing/Pokerus.cs index c2cb91d98..b6b9a71bf 100644 --- a/PKHeX.Core/Editing/Pokerus.cs +++ b/PKHeX.Core/Editing/Pokerus.cs @@ -23,6 +23,7 @@ public static class Pokerus PA8 pa8 => HasVisitedAnother(pa8, enc), PB7 => false, // Does not exist in game. PK9 => false, // Does not exist in game, does not get copied over via HOME. + PA9 => false, // Does not exist in game, does not get copied over via HOME. _ => true, }; @@ -60,6 +61,7 @@ private static bool HasVisitedAnother(PA8 pk, ISpeciesForm enc) EntityContext.Gen7b => false, EntityContext.Gen8a => false, EntityContext.Gen9 => false, + EntityContext.Gen9a => false, _ => true, }; diff --git a/PKHeX.Core/Editing/Saves/Slots/Extensions.cs b/PKHeX.Core/Editing/Saves/Slots/Extensions.cs index e4ccfca86..1875b7f4a 100644 --- a/PKHeX.Core/Editing/Saves/Slots/Extensions.cs +++ b/PKHeX.Core/Editing/Saves/Slots/Extensions.cs @@ -44,6 +44,7 @@ public static PKM[] GetExtraPKM(this SaveFile sav, IReadOnlyList s SAV8BS bs => GetExtraSlots8b(bs), SAV8LA la => GetExtraSlots8a(la), SAV9SV sv => GetExtraSlots9(sv), + SAV9ZA za => GetExtraSlots9a(za), _ => None, }; @@ -240,4 +241,38 @@ private static List GetExtraSlots9(SAV9SV sav) } return list; } + + private static List GetExtraSlots9a(SAV9ZA sav) + { + var list = new List(); + + var shinyCache = sav.Blocks.GetBlock(SaveBlockAccessor9ZA.KStoredShinyEntity); + for (int i = 0; i < 10; i++) + { + const int size = 0x1F0; + var ofs = (i * size) + 8; + var entry = shinyCache.Raw.Slice(ofs, size); + if (EntityDetection.IsPresent(entry.Span)) + list.Add(new(entry, i, true) { Type = StorageSlotType.Shiny, HideLegality = true }); // no OT info + else + break; + } + + var giveAway = sav.Blocks.GetBlock(SaveBlockAccessor9ZA.KStoredEventEntity); + for (int i = 0; i < 128; i++) + { + const int size = 0x1A8; + var ofs = (i * size) + 8; + var entry = giveAway.Raw.Slice(ofs, PokeCrypto.SIZE_9PARTY); + if (EntityDetection.IsPresent(entry.Span)) + list.Add(new(entry, i, true) { Type = StorageSlotType.Misc }); + else + break; + } + + var block = sav.Blocks.GetBlock(SaveBlockAccessor9ZA.KFusedCalyrex); + list.Add(new(block.Raw, 0, true) { Type = StorageSlotType.FusedCalyrex }); + + return list; + } } diff --git a/PKHeX.Core/Editing/Saves/Slots/StorageSlotType.cs b/PKHeX.Core/Editing/Saves/Slots/StorageSlotType.cs index e2ae7e904..822faaa51 100644 --- a/PKHeX.Core/Editing/Saves/Slots/StorageSlotType.cs +++ b/PKHeX.Core/Editing/Saves/Slots/StorageSlotType.cs @@ -16,6 +16,8 @@ public enum StorageSlotType : byte Daycare, /// Global Trade Station (GTS) GTS, + /// Shiny Overworld Cache + Shiny, /// Fused Legendary Storage FusedKyurem, diff --git a/PKHeX.Core/Game/Enums/GameVersion.cs b/PKHeX.Core/Game/Enums/GameVersion.cs index 1ab699d7d..e4a088e9a 100644 --- a/PKHeX.Core/Game/Enums/GameVersion.cs +++ b/PKHeX.Core/Game/Enums/GameVersion.cs @@ -233,6 +233,11 @@ public enum GameVersion : byte /// Pokémon Violet (NX) /// VL = 51, + + /// + /// Pokémon Legends: (Z-A) (NX) + /// + ZA = 52, #endregion // The following values are not actually stored values in pk data, diff --git a/PKHeX.Core/Game/Enums/LanguageID.cs b/PKHeX.Core/Game/Enums/LanguageID.cs index d40a84e8d..e152e9d53 100644 --- a/PKHeX.Core/Game/Enums/LanguageID.cs +++ b/PKHeX.Core/Game/Enums/LanguageID.cs @@ -61,4 +61,9 @@ public enum LanguageID : byte /// Chinese Traditional (繁體中文) /// ChineseT = 10, + + /// + /// Spanish (LATAM) + /// + SpanishL = 11, } diff --git a/PKHeX.Core/Game/Enums/Move.cs b/PKHeX.Core/Game/Enums/Move.cs index b68ae2619..459925b57 100644 --- a/PKHeX.Core/Game/Enums/Move.cs +++ b/PKHeX.Core/Game/Enums/Move.cs @@ -925,5 +925,6 @@ public enum Move : ushort PsychicNoise, UpperHand, MalignantChain, + NihilLight, MAX_COUNT, } diff --git a/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs b/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs index f55caaefd..a05dc6b19 100644 --- a/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs +++ b/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs @@ -31,7 +31,7 @@ public FilteredGameDataSource(SaveFile sav, GameDataSource source, bool HaX = fa var gamelist = GameUtil.GetVersionsWithinRange(sav, sav.Generation).ToList(); Games = Source.VersionDataSource.Where(g => gamelist.Contains((GameVersion)g.Value) || g.Value == 0).ToList(); - Languages = Source.LanguageDataSource(sav.Generation); + Languages = Source.LanguageDataSource(sav.Generation, sav.Context); Balls = Source.BallDataSource.Where(b => b.Value <= sav.MaxBallID).ToList(); Abilities = Source.AbilityDataSource.Where(a => a.Value <= sav.MaxAbilityID).ToList(); @@ -57,6 +57,7 @@ public FilteredGameDataSource(SaveFile sav, GameDataSource source, bool HaX = fa // BD/SP can be handled by <= MaxSpeciesID as it as no gaps in species availability. SAV8SWSH g8 => FilterUnavailable(result, g8.Personal), SAV9SV g9 => FilterUnavailable(result, g9.Personal), + SAV9ZA za => FilterUnavailable(result, za.Personal), _ => FilterAbove(result, sav.MaxSpeciesID), }; return result; diff --git a/PKHeX.Core/Game/GameStrings/GameDataSource.cs b/PKHeX.Core/Game/GameStrings/GameDataSource.cs index a814b30f8..927f8526c 100644 --- a/PKHeX.Core/Game/GameStrings/GameDataSource.cs +++ b/PKHeX.Core/Game/GameStrings/GameDataSource.cs @@ -29,6 +29,7 @@ public sealed class GameDataSource (byte)LanguageID.Korean, (byte)LanguageID.ChineseS, (byte)LanguageID.ChineseT, + (byte)LanguageID.SpanishL, ]; /// @@ -36,11 +37,12 @@ public sealed class GameDataSource /// /// Generation to get the language list for. /// List of languages to display. - public IReadOnlyList LanguageDataSource(byte generation) => generation switch + public IReadOnlyList LanguageDataSource(byte generation, EntityContext context) => generation switch { 3 => LanguageList[..6], // No Korean+ < 7 => LanguageList[..7], // No Chinese+ - _ => [.. LanguageList], + _ when context is EntityContext.Gen9a => [.. LanguageList], + _ => [.. LanguageList.AsSpan(0, LanguageList.Length - 1)], }; public GameDataSource(GameStrings s) @@ -97,6 +99,7 @@ public GameDataSource(GameStrings s) /// Most recent games are at the top, loosely following Generation groups. private static ReadOnlySpan OrderedVersionArray => [ + 52, // 9 Z-A 50, 51, // 9 S/V 47, // 8 PLA 48, 49, // 8 BD/SP diff --git a/PKHeX.Core/Game/GameStrings/GameInfo.cs b/PKHeX.Core/Game/GameStrings/GameInfo.cs index 935abf0f2..97287eb9e 100644 --- a/PKHeX.Core/Game/GameStrings/GameInfo.cs +++ b/PKHeX.Core/Game/GameStrings/GameInfo.cs @@ -38,8 +38,8 @@ public static string GetVersionName(GameVersion version) return version.ToString(); } - public static IReadOnlyList LanguageDataSource(byte generation) - => Sources.LanguageDataSource(generation); + public static IReadOnlyList LanguageDataSource(byte generation, EntityContext context) + => Sources.LanguageDataSource(generation, context); /// /// Gets the location name for the specified parameters. diff --git a/PKHeX.Core/Game/GameStrings/GameStrings.cs b/PKHeX.Core/Game/GameStrings/GameStrings.cs index 65e717543..02320f82f 100644 --- a/PKHeX.Core/Game/GameStrings/GameStrings.cs +++ b/PKHeX.Core/Game/GameStrings/GameStrings.cs @@ -21,7 +21,7 @@ public sealed class GameStrings : IBasicStrings // Met Locations public readonly LocationSet0 Gen2, Gen3, CXD; public readonly LocationSet4 Gen4; - public readonly LocationSet6 Gen5, Gen6, Gen7, Gen7b, Gen8, Gen8a, Gen8b, Gen9; + public readonly LocationSet6 Gen5, Gen6, Gen7, Gen7b, Gen8, Gen8a, Gen8b, Gen9, Gen9a; // Misc public readonly string[] wallpapernames, puffs, walkercourses; @@ -143,6 +143,7 @@ internal GameStrings(string langFilePrefix) Gen8a = Get6("la"); Gen8b = Get6("bdsp"); Gen9 = Get6("sv"); + Gen9a = Get6("za"); Sanitize(); @@ -282,6 +283,7 @@ private void SanitizeItemNames() SanitizeItemsLA(itemlist); SanitizeItemsSV(itemlist); + SanitizeItemsZA(itemlist); if (Language is French) { @@ -300,6 +302,26 @@ private void SanitizeItemNames() itemlist[1763] += " (LA)"; // Secret Medicine } + private void SanitizeItemsZA(Span items) + { + // Seed of Mastery + items[1622] += " (LA)"; + items[2558] += " (ZA)"; + // Canari Plushes + Canari(items[2620..]); // Red + Canari(items[2623..]); // Gold + Canari(items[2626..]); // Pink + Canari(items[2629..]); // Green + Canari(items[2632..]); // Blue + return; + static void Canari(Span arr) + { + arr[0] += " (1)"; + arr[1] += " (2)"; + arr[2] += " (3)"; + } + } + private static void SanitizeItemsSV(Span items) { items[2313] += " (1)"; // Academy Bottle @@ -397,6 +419,7 @@ private void SanitizeMetLocations() SanitizeMetGen8a(Gen8a); SanitizeMetGen8b(Gen8b); SanitizeMetGen9(Gen9); + SanitizeMetGen9a(Gen9a); if (Language is Italian or Spanish) { @@ -692,6 +715,15 @@ private void SanitizeMetGen9(LocationSet6 set) // set.Met3[18] += " (-)"; // Pokémon HOME -- duplicate with 40000's entry } + private static void SanitizeMetGen9a(LocationSet6 set) + { + // ZA: Truncated list to remove all after 235 (no encounters there). + Deduplicate(set.Met0, 00000); + Deduplicate(set.Met3, 30000); + Deduplicate(set.Met4, 40000); + Deduplicate(set.Met6, 60000); + } + private static void Deduplicate(Span arr, int group) { var counts = new Dictionary(); @@ -737,6 +769,7 @@ private static void Deduplicate(Span arr, int group) EntityContext.Gen4 => g4items, // mail names changed 4->5 EntityContext.Gen8b => GetItemStrings8b(), EntityContext.Gen9 => GetItemStrings9(), + EntityContext.Gen9a => GetItemStrings9a(), _ => itemlist, }; @@ -778,6 +811,48 @@ static void InsertZero(Span arr, string insert) } } + private string[] GetItemStrings9a() + { + // in Generation 9, TM #'s are padded to 3 digits; format them appropriately here + var clone = (string[])itemlist.Clone(); + var span = clone.AsSpan(); + var zero = Language is Japanese or ChineseS or ChineseT ? '0' : '0'; + var prefix = span[328].AsSpan(0, 2); + + InsertZero(prefix, span[328..420], zero, 1); // 01-92 + InsertZero(prefix, span[618..621], zero, 93); // 93-95 + InsertZero(prefix, span[690..694], zero, 96); // 96-99 + InsertZero(prefix, span[2160..2290], zero, 100); // 100-229 + return clone; + + static void InsertZero(ReadOnlySpan prefix, Span arr, char zero, int start) + { + int i = 0; + foreach (ref var item in arr) + { + var index = start + i; + var remap = ItemConverter.RemapTechnicalMachineItemName9a; + if (index >= remap.Length) + break; + index += remap[index]; + item = GetActualName(prefix, index, zero); + i++; + } + arr[i..].Clear(); + } + static string GetActualName(ReadOnlySpan prefix, int value, char pad) + { + Span buffer = stackalloc char[5]; + prefix.CopyTo(buffer); + var arr = buffer[2..]; + arr.Fill(pad); + arr[2] += (char)(value % 10); value /= 10; + arr[1] += (char)(value % 10); value /= 10; + arr[0] += (char)(value % 10); + return new string(buffer); + } + } + private string[] GetItemStrings3(GameVersion version) { switch (version) @@ -869,6 +944,7 @@ private static byte GetGeneration(byte generation, bool isEggLocation, byte form 8 when version is GameVersion.PLA => Gen8a, 8 when GameVersion.BDSP.Contains(version) => Gen8b, 8 => Gen8, + 9 when version is GameVersion.ZA => Gen9a, 9 => Gen9, _ => null, diff --git a/PKHeX.Core/Game/GameStrings/MetDataSource.cs b/PKHeX.Core/Game/GameStrings/MetDataSource.cs index d780fc394..a440221ab 100644 --- a/PKHeX.Core/Game/GameStrings/MetDataSource.cs +++ b/PKHeX.Core/Game/GameStrings/MetDataSource.cs @@ -23,6 +23,7 @@ public sealed class MetDataSource(GameStrings s) private readonly List MetGen8a = CreateGen8a(s); private readonly List MetGen8b = CreateGen8b(s); private readonly List MetGen9 = CreateGen9(s); + private readonly List MetGen9a = CreateGen9a(s); private IReadOnlyList? MetGen4Transfer; private IReadOnlyList? MetGen5Transfer; @@ -150,6 +151,7 @@ private static List CreateGen8(GameStrings s) locations.Add(new ComboItem(s.gamelist[(int)BD], LocationsHOME.SWBD)); locations.Add(new ComboItem(s.gamelist[(int)SP], LocationsHOME.SHSP)); locations.Add(new ComboItem(s.gamelist[(int)PLA], LocationsHOME.SWLA)); + // No backwards from ZA+ return locations; } @@ -197,6 +199,18 @@ private static List CreateGen9(GameStrings s) return locations; } + private static List CreateGen9a(GameStrings s) + { + var locations = Util.GetCBList(s.Gen9a.Met0, 0); + Util.AddCBWithOffset(locations, s.Gen9a.Met6, 60000, Locations.Daycare5); + Util.AddCBWithOffset(locations, s.Gen9a.Met3, 30000, Locations.LinkTrade6); + Util.AddCBWithOffset(locations, s.Gen9a.Met0, 00000, Locations9a.Met0); + Util.AddCBWithOffset(locations, s.Gen9a.Met3, 30000, Locations9a.Met3); + Util.AddCBWithOffset(locations, s.Gen9a.Met4, 40000, Locations9a.Met4); + Util.AddCBWithOffset(locations, s.Gen9a.Met6, 60000, Locations9a.Met6); + return locations; + } + /// /// Fetches a Met Location list for a that has been transferred away from and overwritten. /// @@ -257,6 +271,7 @@ public IReadOnlyList GetLocationList(GameVersion version, EntityConte BD or SP => Partition2(MetGen8b, IsMetLocation8BDSP), PLA => Partition2(MetGen8a, IsMetLocation8LA), SL or VL => Partition2(MetGen9, IsMetLocation9SV), + ZA => Partition2(MetGen9a, IsMetLocation9ZA), _ => GetLocationListModified(version, context), }; diff --git a/PKHeX.Core/Game/GameUtil.cs b/PKHeX.Core/Game/GameUtil.cs index 0c1a3e1f0..281e37b42 100644 --- a/PKHeX.Core/Game/GameUtil.cs +++ b/PKHeX.Core/Game/GameUtil.cs @@ -80,6 +80,8 @@ private static GameVersion[] GetValidGameVersions() // Gen9 SL or VL => SV, + ZA => ZA, + _ => Invalid, }; @@ -130,7 +132,7 @@ public static byte GetGeneration(this GameVersion version) RD or GN or BU or YW => 1, GD or SI or C => 2, S or R or E or FR or LG or CXD => 3, - D or P or Pt or HG or SS => 4, + D or P or Pt or HG or SS or BATREV => 4, B or W or B2 or W2 => 5, X or Y or AS or OR => 6, GP or GE => 7, @@ -140,6 +142,7 @@ public static byte GetGeneration(this GameVersion version) BD or SP => 8, SW or SH => 8, SL or VL => 9, + ZA => 9, _ => 0 }; @@ -163,6 +166,7 @@ public static byte GetGeneration(this GameVersion version) BD or SP => Legal.MaxSpeciesID_8b, SW or SH => Legal.MaxSpeciesID_8, SL or VL => Legal.MaxSpeciesID_9, + ZA => Legal.MaxSpeciesID_9a, _ => 0 }; @@ -189,7 +193,7 @@ public static bool Contains(this GameVersion g1, GameVersion g2) public static bool IsGen7(this GameVersion version) => version is SN or MN or US or UM; public static bool IsGen7b(this GameVersion version) => version is GP or GE; public static bool IsGen8(this GameVersion version) => version is SW or SH or PLA or BD or SP; - public static bool IsGen9(this GameVersion version) => version is SL or VL; + public static bool IsGen9(this GameVersion version) => version is SL or VL or ZA; /// /// Checks if the version is the lump of the requested saved . @@ -241,7 +245,7 @@ public static bool Contains(this GameVersion g1, GameVersion g2) Gen8 => version is SW or SH or BD or SP or SWSH or BDSP or PLA, SV => version is SL or VL, - Gen9 => version is SL or VL or SV, + Gen9 => version is SL or VL or SV or ZA, _ => false, }; diff --git a/PKHeX.Core/Game/Locations/Locations.cs b/PKHeX.Core/Game/Locations/Locations.cs index 00c71f70b..b7a83b4d0 100644 --- a/PKHeX.Core/Game/Locations/Locations.cs +++ b/PKHeX.Core/Game/Locations/Locations.cs @@ -170,4 +170,5 @@ public static bool IsEggLocationBred4(ushort loc, GameVersion version) public static bool IsMetLocation8BDSP(ushort z) => z <= 657; // Ramanas Park (Genome Room) public static bool IsMetLocation8LA(ushort z) => z <= 155; // Training Grounds public static bool IsMetLocation9SV(ushort z) => z <= 200; // Terarium (Entry Tunnel) + public static bool IsMetLocation9ZA(ushort z) => z <= 235; // The Sewers } diff --git a/PKHeX.Core/Game/Locations/Locations9.cs b/PKHeX.Core/Game/Locations/Locations9.cs index 8e871e334..a2803127c 100644 --- a/PKHeX.Core/Game/Locations/Locations9.cs +++ b/PKHeX.Core/Game/Locations/Locations9.cs @@ -76,8 +76,8 @@ public static class Locations9 40001, 40002, 40003, 40004, 40005, 40006, 40007, 40008, 40009, 40010, 40011, 40012, 40013, 40014, 40015, 40016, 40017, 40018, 40019, 40020, 40021, 40022, 40024, 40024, 40025, 40026, 40027, 40028, 40029, - 40030, 40032, 40033, 40034, 40035, 40036, 40037, 40038, 40039, 40039, - 40040, 40041, 40042, 40043, 40044, 40045, 40047, 40047, 40048, 40049, + 40030, 40032, 40033, 40034, 40035, 40036, 40037, 40038, 40039, + 40040, 40041, 40042, 40043, 40044, 40045, 40046, 40047, 40048, 40049, 40050, 40051, 40052, 40053, 40054, 40055, 40056, 40057, 40058, 40059, 40060, 40061, 40062, 40063, 40064, 40065, 40066, 40067, 40068, 40069, 40070, 40071, 40072, 40073, 40074, 40075, 40076, 40077, 40078, diff --git a/PKHeX.Core/Game/Locations/Locations9a.cs b/PKHeX.Core/Game/Locations/Locations9a.cs new file mode 100644 index 000000000..ac92a5a50 --- /dev/null +++ b/PKHeX.Core/Game/Locations/Locations9a.cs @@ -0,0 +1,69 @@ +using System; + +namespace PKHeX.Core +{ + /// + /// Locations for . + /// + internal static class Locations9a + { + public static ReadOnlySpan Met0 => + [ + 002, 004, 006, 007, 008, 009, + 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, + 020, 021, 022, 023, 024, 025, 026, 027, 028, 029, + 030, 031, 032, 033, 034, 035, 036, 037, 038, 039, + 040, 041, 042, 043, 044, 045, 046, 047, 048, 049, + 050, 051, 052, 053, 054, 055, 056, 057, 058, 059, + 060, 061, 062, 063, 064, 065, 066, 067, 068, 069, + 070, 071, 072, 073, 074, 075, 076, 077, 078, 079, + 080, 081, 082, 083, 084, 085, 086, 087, 088, 089, + 090, 091, 092, 093, 094, 095, 096, 097, 098, 099, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, + ]; + + /// + /// Available location list for the 30000 set of location names. + /// + public static ReadOnlySpan Met3 => + [ + 30001, 30003, 30004, 30005, 30006, 30007, 30008, 30009, + 30010, 30011, 30012, 30013, 30014, 30015, 30016, 30017, 30018, 30019, + 30020, 30021, 30022, 30023, 30024, 30025, 30026, 30027, 30028, 30029, + 30030, 30031, 30032, + ]; + + /// + /// Available location list for the 40000 set of location names. + /// + public static ReadOnlySpan Met4 => + [ + 40001, 40002, 40003, 40005, 40006, 40007, 40008, 40009, + 40010, 40011, 40012, 40014, 40015, 40016, 40017, 40018, + 40020, 40021, 40022, 40024, 40024, 40026, 40027, 40029, + 40030, 40031, 40032, 40033, 40034, 40035, 40036, 40037, 40039, + 40040, 40041, 40042, 40043, 40045, 40046, 40047, 40048, 40049, + 40051, 40052, 40053, 40054, 40055, 40056, 40057, 40058, + 40060, 40061, 40062, 40063, 40064, 40065, 40066, 40067, 40068, 40069, + 40070, + ]; + + /// + /// Available location list for the 60000 set of location names. + /// + public static ReadOnlySpan Met6 => [ /* X/Y */ 60001, 60003, /* OR/AS */ 60004, /* Z-A */ 60005]; + } +} diff --git a/PKHeX.Core/Items/ItemStorage9SV.cs b/PKHeX.Core/Items/ItemStorage9SV.cs index 4e5fa1bac..de4a965b8 100644 --- a/PKHeX.Core/Items/ItemStorage9SV.cs +++ b/PKHeX.Core/Items/ItemStorage9SV.cs @@ -172,14 +172,6 @@ public sealed class ItemStorage9SV : IItemStorage InventoryType.Ingredients, InventoryType.Candy, ]; - private static ReadOnlySpan ValidHeldTypes => - [ - InventoryType.Items, - InventoryType.TMHMs, - InventoryType.Medicine, InventoryType.Berries, InventoryType.Balls, InventoryType.BattleItems, - InventoryType.Treasure, - ]; - public static ReadOnlySpan Unreleased => [ 0016, // Cherish Ball @@ -240,27 +232,7 @@ public bool IsLegal(InventoryType type, int itemIndex, int itemCount) _ => throw new ArgumentOutOfRangeException(nameof(type)), }; - public static ushort[] GetAllHeld() - { - var valid = ValidHeldTypes; - var sum = 0; - foreach (var type in valid) - sum += GetLegal(type).Length; - - var result = new ushort[sum]; - LoadAllHeld(valid, result); - return result; - } - - private static void LoadAllHeld(ReadOnlySpan valid, Span dest) - { - foreach (var type in valid) - { - var legal = GetLegal(type); - legal.CopyTo(dest); - dest = dest[legal.Length..]; - } - } + public static ushort[] GetAllHeld() => [..Other, ..Machine, ..Medicine, ..Berry, ..Balls, ..Battle, ..Treasure]; public static InventoryType GetInventoryPouch(ushort itemIndex) { diff --git a/PKHeX.Core/Items/ItemStorage9ZA.cs b/PKHeX.Core/Items/ItemStorage9ZA.cs new file mode 100644 index 000000000..dbb965db5 --- /dev/null +++ b/PKHeX.Core/Items/ItemStorage9ZA.cs @@ -0,0 +1,236 @@ +using System; +using static PKHeX.Core.Species; + +namespace PKHeX.Core; + +public sealed class ItemStorage9ZA : IItemStorage +{ + public static readonly ItemStorage9ZA Instance = new(); + + public static ReadOnlySpan Medicine => // 0 + [ + 0017, 0018, 0019, 0020, 0021, 0022, 0023, 0024, 0025, 0026, + 0027, 0028, 0029, 0030, 0031, 0032, 0033, 0708, + ]; + + public static ReadOnlySpan Balls => // 1 + [ + 0001, 0002, 0003, 0004, 0005, 0006, 0007, 0008, 0009, 0010, + 0011, 0012, 0013, 0014, 0015, 0016, 0492, 0493, 0494, 0495, + 0496, 0497, 0498, 0499, 0576, 0851, + ]; + + public static ReadOnlySpan Other => // 2 (Items) + [ + 0045, 0046, 0047, 0048, 0049, 0050, 0052, 0080, 0081, 0082, + 0083, 0084, 0085, 0103, 0107, 0108, 0109, 0214, 0217, 0218, + 0221, 0222, 0230, 0231, 0232, 0233, 0234, 0236, 0237, 0238, + 0239, 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 0248, + 0249, 0250, 0251, 0253, 0266, 0267, 0268, 0270, 0275, 0289, + 0290, 0291, 0292, 0293, 0294, 0296, 0538, 0540, 0564, 0565, + 0566, 0567, 0568, 0569, 0570, 0639, 0640, 0646, 0647, 0710, + 0711, 0795, 0796, 0849, 1124, 1125, 1126, 1127, 1128, 1231, + 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, + 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, + 1582, 1592, 2401, 2558, 2618, 2619, // Colorful Screw cannot be held. + ]; + + public static ReadOnlySpan Treasure => // 3 + [ + 0086, 0088, 0089, 0092, 0571, 0581, 0582, + ]; + + public static ReadOnlySpan Key => // 4 + [ + 0632, 0700, 0765, 0847, 2588, 2589, 2590, 2591, 2592, 2595, + 2596, 2597, 2598, 2599, 2600, 2620, 2621, 2622, 2623, 2624, + 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, + + ]; + + public static ReadOnlySpan Berry => // 5 + [ + 0149, 0150, 0151, 0152, 0153, 0155, 0156, 0157, 0158, 0169, + 0170, 0171, 0172, 0173, 0174, 0184, 0185, 0186, 0187, 0188, + 0189, 0190, 0191, 0192, 0193, 0194, 0195, 0196, 0197, 0198, + 0199, 0200, 0686, + ]; + + public static ReadOnlySpan TM => // 6 + [ + 0328, 0329, 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0338, 0339, 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0348, 0349, 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0358, 0359, 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0368, 0369, 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377, + 0378, 0379, 0380, 0381, 0382, 0383, 0384, 0385, 0386, 0387, + 0388, 0389, 0390, 0391, 0392, 0393, 0394, 0395, 0396, 0397, + 0398, 0399, 0400, 0401, 0402, 0403, 0404, 0405, 0406, 0407, + 0408, 0409, 0410, 0411, 0412, 0413, 0414, 0415, 0416, 0417, + 0418, 0419, 0618, 0619, 0620, 0690, 0691, 0692, 0693, 2160, + 2162, 2163, 2164, 2165, 2166, 2167, 2168, + ]; + + public static ReadOnlySpan MegaStones => // 7 + [ + 0656, 0657, 0658, 0659, 0660, 0661, 0662, 0663, 0665, 0666, + 0667, 0668, 0669, 0670, 0671, 0672, 0673, 0674, 0675, 0676, + 0677, 0678, 0679, 0680, 0681, 0682, 0683, 0754, 0755, 0756, + 0757, 0758, 0759, 0760, 0761, 0762, 0763, 0764, 0767, 0768, + 0769, 0770, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2566, + 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2577, 2578, + 2579, 2580, 2581, 2582, 2583, 2584, 2585, 2587, + ]; + + internal static ReadOnlySpan ValidTypes => + [ + // Display Order + InventoryType.Medicine, + InventoryType.Balls, + InventoryType.Berries, + InventoryType.Items, // Other + InventoryType.TMHMs, + InventoryType.MegaStones, + InventoryType.Treasure, + InventoryType.KeyItems, + ]; + + public static ReadOnlySpan Unreleased => + [ + 0005, // Safari Ball + 0499, // Sport Ball (first Season end reward) + + 0662, // Mewtwonite X + 0663, // Mewtwonite Y + 0764, // Diancite + + 0576, // Dream Ball + + 0851, // Beast Ball + + 2575, // Chesnaughtite + 2576, // Delphoxite + ]; + + public int GetMax(InventoryType type) => type switch + { + InventoryType.Medicine => 999, + InventoryType.Balls => 999, + InventoryType.Berries => 999, + InventoryType.Items => 999, // Other + InventoryType.TMHMs => 1, + InventoryType.MegaStones => 1, + InventoryType.Treasure => 999, + InventoryType.KeyItems => 1, + _ => throw new ArgumentOutOfRangeException(nameof(type)), + }; + + public bool IsLegal(InventoryType type, int itemIndex, int itemCount) => !Unreleased.Contains((ushort)itemIndex); + + public ReadOnlySpan GetItems(InventoryType type) => GetLegal(type); + + public static ReadOnlySpan GetLegal(InventoryType type) => type switch + { + InventoryType.Medicine => Medicine, + InventoryType.Balls => Balls, + InventoryType.Berries => Berry, + InventoryType.Items => Other, + InventoryType.TMHMs => TM, + InventoryType.MegaStones => MegaStones, + InventoryType.Treasure => Treasure, + InventoryType.KeyItems => Key, + _ => throw new ArgumentOutOfRangeException(nameof(type)), + }; + + public static ushort[] GetAllHeld() => [..Medicine, ..Balls, ..Berry, ..MegaStones, ..Treasure, ..Other[..^1]]; // Exclude Colorful Screw + + public static InventoryType GetInventoryPouch(ushort itemIndex) + { + foreach (var type in ValidTypes) + { + var legal = GetLegal(type); + if (legal.Contains(itemIndex)) + return type; + } + return InventoryType.None; + } + + public static bool IsMegaStone(ushort item) => MegaStones.Contains(item); + + /// + /// Retrieves the expected Mega Stone item ID for a given Pokémon species and form. + /// + /// 0 if no item is expected for this species and form combination (in other words, not a mega form). + public static ushort GetExpectedMegaStone(ushort species, byte form) => (Species)species switch + { + Gengar when form == 1 => 0656, + Gardevoir when form == 1 => 0657, + Ampharos when form == 1 => 0658, + Venusaur when form == 1 => 0659, + Charizard when form == 1 => 0660, // X + Blastoise when form == 1 => 0661, + Mewtwo when form == 1 => 0662, // X + Mewtwo when form == 2 => 0663, // Y + Medicham when form == 1 => 0665, + Houndoom when form == 1 => 0666, + Aggron when form == 1 => 0667, + Banette when form == 1 => 0668, + Tyranitar when form == 1 => 0669, + Scizor when form == 1 => 0670, + Pinsir when form == 1 => 0671, + Aerodactyl when form == 1 => 0672, + Lucario when form == 1 => 0673, + Abomasnow when form == 1 => 0674, + Kangaskhan when form == 1 => 0675, + Gyarados when form == 1 => 0676, + Absol when form == 1 => 0677, + Charizard when form == 2 => 0678, // Y + Alakazam when form == 1 => 0679, + Heracross when form == 1 => 0680, + Mawile when form == 1 => 0681, + Manectric when form == 1 => 0682, + Garchomp when form == 1 => 0683, + Sableye when form == 1 => 0754, + Altaria when form == 1 => 0755, + Gallade when form == 1 => 0756, + Audino when form == 1 => 0757, + Metagross when form == 1 => 0758, + Sharpedo when form == 1 => 0759, + Slowbro when form == 1 => 0760, + Steelix when form == 1 => 0761, + Pidgeot when form == 1 => 0762, + Glalie when form == 1 => 0763, + Diancie when form == 1 => 0764, + Camerupt when form == 1 => 0767, + Lopunny when form == 1 => 0768, + Salamence when form == 1 => 0769, + Beedrill when form == 1 => 0770, + Clefable when form == 1 => 2559, + Victreebel when form == 1 => 2560, + Starmie when form == 1 => 2561, + Dragonite when form == 1 => 2562, + Meganium when form == 1 => 2563, + Feraligatr when form == 1 => 2564, + Skarmory when form == 1 => 2565, + Froslass when form == 1 => 2566, + Emboar when form == 1 => 2569, + Excadrill when form == 1 => 2570, + Scolipede when form == 1 => 2571, + Scrafty when form == 1 => 2572, + Eelektross when form == 1 => 2573, + Chandelure when form == 1 => 2574, + Chesnaught when form == 1 => 2575, + Delphox when form == 1 => 2576, + Greninja when form == 3 => 2577, + Pyroar when form == 1 => 2578, + Floette when form == 6 => 2579, + Malamar when form == 1 => 2580, + Barbaracle when form == 1 => 2581, + Dragalge when form == 1 => 2582, + Hawlucha when form == 1 => 2583, + Zygarde when form == 5 => 2584, + Drampa when form == 1 => 2585, + Falinks when form == 1 => 2587, + _ => 0, + }; +} diff --git a/PKHeX.Core/Legality/Assets/BinLinkerWriter.cs b/PKHeX.Core/Legality/Assets/BinLinkerWriter.cs index 390d7fc2f..cae299f7a 100644 --- a/PKHeX.Core/Legality/Assets/BinLinkerWriter.cs +++ b/PKHeX.Core/Legality/Assets/BinLinkerWriter.cs @@ -80,7 +80,7 @@ public static byte[] Write32(byte[][] data, ReadOnlySpan identifier, int p for (int i = 0; i < count; i++) { // Write File Offset - var fileOffset = (ms.Position - start) + dataOffset; + var fileOffset = bw.BaseStream.Length - start; bw.Seek(start + 4 + (i * sizeof(uint)), SeekOrigin.Begin); bw.Write((uint)fileOffset); // Write File to Stream @@ -94,8 +94,12 @@ public static byte[] Write32(byte[][] data, ReadOnlySpan identifier, int p } // Cap the File - bw.Seek(start + 4 + (count * sizeof(uint)), SeekOrigin.Begin); - bw.Write((uint)((ms.Position - start) + dataOffset)); + { + var fileOffset = bw.BaseStream.Length - start; + bw.Seek(start + 4 + (count * sizeof(uint)), SeekOrigin.Begin); + bw.Write((uint)fileOffset); + } + // Return the byte array return ms.ToArray(); } @@ -121,7 +125,7 @@ public static byte[] Write16(byte[][] data, ReadOnlySpan identifier, int p for (int i = 0; i < count; i++) { // Write File Offset - var fileOffset = ((ms.Position - start) + dataOffset); + var fileOffset = bw.BaseStream.Length - start; bw.Seek(start + 4 + (i * sizeof(ushort)), SeekOrigin.Begin); bw.Write((ushort)fileOffset); // Write File to Stream @@ -135,8 +139,12 @@ public static byte[] Write16(byte[][] data, ReadOnlySpan identifier, int p } // Cap the File - bw.Seek(start + 4 + (count * sizeof(ushort)), SeekOrigin.Begin); - bw.Write((ushort)((ms.Position - start) + dataOffset)); + { + var fileOffset = bw.BaseStream.Length - start; + bw.Seek(start + 4 + (count * sizeof(ushort)), SeekOrigin.Begin); + bw.Write((ushort)fileOffset); + } + // Return the byte array return ms.ToArray(); } diff --git a/PKHeX.Core/Legality/Breeding.cs b/PKHeX.Core/Legality/Breeding.cs index 73075e354..a4889d770 100644 --- a/PKHeX.Core/Legality/Breeding.cs +++ b/PKHeX.Core/Legality/Breeding.cs @@ -40,6 +40,7 @@ public static class Breeding /// /// Checks if the species is valid for the if originated from Gen3/4 daycare eggs. /// + /// Only applies to species that satisfy . /// Encryption Constant /// Gender /// True if valid @@ -129,6 +130,8 @@ public static bool CanHatchAsEgg(ushort species, byte form, EntityContext contex /// /// Some species can have forms that cannot exist as egg (event/special forms). Same idea as /// + /// Current species + /// Current form, not 0. /// True if it can be bred. private static bool IsBreedableForm(ushort species, byte form) => species switch { diff --git a/PKHeX.Core/Legality/Bulk/BulkAnalysis.cs b/PKHeX.Core/Legality/Bulk/BulkAnalysis.cs index 1e4278f64..6c96f11d7 100644 --- a/PKHeX.Core/Legality/Bulk/BulkAnalysis.cs +++ b/PKHeX.Core/Legality/Bulk/BulkAnalysis.cs @@ -15,7 +15,7 @@ public sealed class BulkAnalysis public readonly ITrainerInfo Trainer; public readonly List Parse = []; public readonly Dictionary Trackers = []; - public readonly bool Valid; + public bool Valid => Parse.Count == 0 || Parse.TrueForAll(static z => z.Result.Valid); public readonly BulkAnalysisSettings Settings; private readonly bool[] CloneFlags; @@ -32,6 +32,7 @@ public sealed class BulkAnalysis public BulkAnalysis(SaveFile sav, BulkAnalysisSettings settings) : this(GetSlots(sav), settings, sav) { + RunSaveSpecificChecks(); } public BulkAnalysis(IEnumerable source, BulkAnalysisSettings settings, ITrainerInfo tr) : this(GetSlots(source), settings, tr) @@ -47,7 +48,6 @@ private BulkAnalysis(List list, BulkAnalysisSettings settings, ITrain CloneFlags = new bool[AllData.Count]; ScanAll(); - Valid = Parse.Count == 0 || Parse.TrueForAll(static z => z.Result.Valid); } private static List GetSlots(SaveFile sav) @@ -97,6 +97,12 @@ private static bool IsEmptyData(SlotCache obj) new DuplicateGiftChecker(), ]; + private static readonly List SaveAnalyzers = + [ + new DuplicateFusionChecker(), + new DuplicateMegaChecker(), + ]; + private void ScanAll() { foreach (var analyzer in Analyzers) @@ -105,6 +111,12 @@ private void ScanAll() analyzer.Analyze(this); } + private void RunSaveSpecificChecks() + { + foreach (var analyzer in SaveAnalyzers) + analyzer.Analyze(this); + } + private static string GetSummary(SlotCache entry) => $"[{entry.Identify()}]"; /// @@ -143,6 +155,8 @@ private void ScanAll() Parse.Add(new(chk, line, index1, index2)); } + public void AddMessage(string message, CheckResult chk, int index = BulkCheckResult.NoIndex) => Parse.Add(new(chk, message, index)); + public void AddExternal(SlotCache first, CheckIdentifier id, int index1, ushort identity, ushort argument = 0, Severity s = Severity.Invalid) => AddLine(first, id, index1, LegalityCheckResultCode.External, identity, argument, s); @@ -163,22 +177,27 @@ private static LegalityAnalysis[] GetIndividualAnalysis(ReadOnlySpan public string Report(LegalityLocalizationSet localization) { var sb = new StringBuilder(1024); + var context = LegalityLocalizationContext.Create(AllAnalysis[0], localization); foreach (var (chk, comment, index1, index2) in Parse) { if (sb.Length != 0) sb.AppendLine(); // gap for next result var code = chk.Result; - string template; if (code is LegalityCheckResultCode.External) - template = ExternalBulkCheck.Localize(chk, localization, AllAnalysis, index1, index2); + { + var judge = localization.Description(chk.Judgement); + var template = ExternalBulkCheck.Localize(chk, localization, AllAnalysis, index1, index2); + sb.AppendFormat(localization.Lines.F0_1, judge, template); + } else - template = code.GetTemplate(localization.Lines); - var judge = localization.Description(chk.Judgement); - sb.AppendFormat(localization.Lines.F0_1, judge, template); + { + sb.Append(context.Humanize(chk)); + } sb.AppendLine(); - sb.AppendLine(comment); + if (comment.Length != 0) + sb.AppendLine(comment); } if (sb.Length == 0) sb.AppendLine(localization.Lines.Valid); diff --git a/PKHeX.Core/Legality/Bulk/SaveFile/DuplicateFusionChecker.cs b/PKHeX.Core/Legality/Bulk/SaveFile/DuplicateFusionChecker.cs new file mode 100644 index 000000000..88d628c9c --- /dev/null +++ b/PKHeX.Core/Legality/Bulk/SaveFile/DuplicateFusionChecker.cs @@ -0,0 +1,108 @@ +using System; + +namespace PKHeX.Core.Bulk; + +public sealed class DuplicateFusionChecker : IBulkAnalyzer +{ + /// + /// + /// + /// + public void Analyze(BulkAnalysis input) + { + if (input.Trainer is not SaveFile sav) + return; + + // Rule: Only 1 Fusion of each of the stored fused species. + Span seen = stackalloc int[4]; // 0: Kyurem, 1: Necrozma-Dawn, 2: Necrozma-Dusk, 3: Calyrex-Ice/Ghost + const int seenNotSet = -1; + seen.Fill(seenNotSet); + + SearchForDuplicates(input, seen, seenNotSet); + + // Rule: The consumed species to obtain (species, form) must be present in the save file's fused storage. + if (seen.ContainsAnyExcept(seenNotSet)) + CheckConsumedSlots(input, sav, seen, seenNotSet); + } + + private static void SearchForDuplicates(BulkAnalysis input, Span seen, int seenNotSet) + { + for (var i = 0; i < input.AllData.Count; i++) + { + var slot = input.AllData[i]; + var pk = slot.Entity; + + var (species, form) = (pk.Species, pk.Form); + if (form == 0) // eager check -- fused forms always have form > 0 + continue; + + var index = GetIndexFusedStorage(species, form); + if (index == -1) + continue; + + if (seen[index] != seenNotSet) // Already given to another slot. + { + var other = seen[index]; + input.AddLine(slot, input.AllData[other], CheckIdentifier.Form, i, index2: other, LegalityCheckResultCode.BulkDuplicateFusionSlot, species); + continue; + } + + // First time seeing this Fusion, all good. + seen[index] = i; + } + } + + private static void CheckConsumedSlots(BulkAnalysis input, SaveFile sav, Span seen, int seenNotSet) + { + // Check that fused species is present in the fused source + var extraSlots = sav.GetExtraSlots(); + for (int i = 0; i < seen.Length; i++) + { + var index = seen[i]; + if (index == seenNotSet) + continue; + + var extra = extraSlots.Find(z => GetIndexFusedStorage(z.Type) == i); + if (extra is null) // uhh? shouldn't be in this save file, will be flagged by regular legality check. + continue; + + var exist = input.AllData[index]; + var pk = exist.Entity; + var form = pk.Form; + + var source = extra.Read(sav); + if (source.Form != 0 || !IsValidStoredBaseSpecies(i, source.Species, form)) + input.AddLine(exist, CheckIdentifier.Form, i, LegalityCheckResultCode.BulkFusionSourceInvalid, source.Species, source.Form); + } + } + + private static int GetIndexFusedStorage(StorageSlotType type) => type switch + { + StorageSlotType.FusedKyurem => 0, + StorageSlotType.FusedNecrozmaS => 1, + StorageSlotType.FusedNecrozmaM => 2, + StorageSlotType.FusedCalyrex => 3, + _ => -1, + }; + + // The games let you fuse two separate Necrozma with the box legends (N-Solarizer and N-Lunarizer). + private static int GetIndexFusedStorage(ushort species, byte form) => (species, form) switch + { + ((ushort)Species.Kyurem, _) => 0, // DNA Splicers + ((ushort)Species.Necrozma, 1) => 1, // N-Solarizer + ((ushort)Species.Necrozma, 2) => 2, // N-Lunarizer + ((ushort)Species.Calyrex, _) => 3, // Reins of Unity + _ => -1, + }; + + private static bool IsValidStoredBaseSpecies(int index, ushort consumedSpecies, byte resultForm) => index switch + { + 0 when resultForm == 1 => consumedSpecies is (ushort)Species.Reshiram, + 0 when resultForm == 2 => consumedSpecies is (ushort)Species.Zekrom, + 1 => consumedSpecies is (ushort)Species.Solgaleo, + 2 => consumedSpecies is (ushort)Species.Lunala, + 3 when resultForm == 1 => consumedSpecies == (ushort)Species.Glastrier, + 3 when resultForm == 2 => consumedSpecies == (ushort)Species.Spectrier, + _ => false, + }; +} diff --git a/PKHeX.Core/Legality/Bulk/SaveFile/DuplicateMegaChecker.cs b/PKHeX.Core/Legality/Bulk/SaveFile/DuplicateMegaChecker.cs new file mode 100644 index 000000000..7acfb4af6 --- /dev/null +++ b/PKHeX.Core/Legality/Bulk/SaveFile/DuplicateMegaChecker.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using static PKHeX.Core.LegalityCheckResultCode; + +namespace PKHeX.Core.Bulk; + +public sealed class DuplicateMegaChecker : IBulkAnalyzer +{ + private const CheckIdentifier Identifier = CheckIdentifier.HeldItem; + + public void Analyze(BulkAnalysis input) + { + if (input.Trainer is SAV9ZA za) + AnalyzeInventory(input, za); + else + AnalyzeNoInventory(input); + } + + private static void AnalyzeInventory(BulkAnalysis input, SAV9ZA za) + { + var items = za.Items; + + // Rule: Only 1 Mega Stone of a given Item ID may be held across all Pokémon, or present in the bag. + Dictionary seenStones = []; // ushort item, int index + for (var i = 0; i < input.AllData.Count; i++) + { + var slot = input.AllData[i]; + var pk = slot.Entity; + + var stone = (ushort)pk.HeldItem; + if (!ItemStorage9ZA.IsMegaStone(stone)) + continue; + + var item = items.GetItem(stone); + if (item.Count == 0) // Not acquired by the save file, thus not able to be held. + input.AddLine(slot, Identifier, BulkCheckResult.NoIndex, BulkNotAcquiredMegaStoneInventory, stone); + else if (!item.IsHeld) // Not marked as held, so it's still "in the bag" (not given). + input.AddLine(slot, Identifier, BulkCheckResult.NoIndex, BulkDuplicateMegaStoneInventory, stone); + else if (seenStones.TryGetValue(stone, out var otherIndex)) // Already given to another slot. + input.AddLine(slot, input.AllData[otherIndex], Identifier, i, index2: otherIndex, BulkDuplicateMegaStoneSlot, stone); + else // First time seeing this Mega Stone, all good. + seenStones[stone] = i; + } + + CheckOtherUnassigned(input, items, ItemStorage9ZA.MegaStones, seenStones); + } + + private static void CheckOtherUnassigned(BulkAnalysis input, MyItem9a items, ReadOnlySpan megaStones, IReadOnlyDictionary seenStones) + { + // Check that all other un-assigned stones are not marked as assigned. + foreach (var stone in megaStones) + { + if (seenStones.ContainsKey(stone)) + continue; + var item = items.GetItem(stone); + if (item.IsHeld) + input.AddMessage(string.Empty, CheckResult.Get(Severity.Invalid, CheckIdentifier.HeldItem, BulkAssignedMegaStoneNotFound_0, stone)); + } + } + + private static void AnalyzeNoInventory(BulkAnalysis input) + { + // Rule: Only 1 Mega Stone of a given Item ID may be held across all Pokémon, or present in the bag. + Dictionary seenStones = []; // ushort item, int index + for (var i = 0; i < input.AllData.Count; i++) + { + var slot = input.AllData[i]; + var pk = slot.Entity; + + var stone = (ushort)pk.HeldItem; + if (!ItemStorage9ZA.IsMegaStone(stone)) + continue; + + if (seenStones.TryGetValue(stone, out var otherIndex)) // Already given to another slot. + input.AddLine(slot, input.AllData[otherIndex], Identifier, i, index2: otherIndex, BulkDuplicateMegaStoneSlot, stone); + else // First time seeing this Mega Stone, all good. + seenStones[stone] = i; + } + } +} diff --git a/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs b/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs index b3d656b7e..203321382 100644 --- a/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs +++ b/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs @@ -40,6 +40,9 @@ public static class EncounterEvent /// Event Database for Generation 9 public static readonly WC9[] MGDB_G9 = GetWC9DB(Util.GetBinaryResource("wc9.pkl")); + + /// Event Database for Generation 9 + public static readonly WA9[] MGDB_G9A = GetWA9DB(Util.GetBinaryResource("wa9.pkl")); #endregion #region Locally Loaded Data @@ -55,20 +58,23 @@ public static class EncounterEvent /// Event Database for Generation 7 public static WC7[] EGDB_G7 { get; private set; } = []; - /// Event Database for Generation 7 + /// Event Database for Generation 7 public static WB7[] EGDB_G7GG { get; private set; } = []; - /// Event Database for Generation 8 + /// Event Database for Generation 8 public static WC8[] EGDB_G8 { get; private set; } = []; - /// Event Database for Generation 8 + /// Event Database for Generation 8 public static WA8[] EGDB_G8A { get; private set; } = []; - /// Event Database for Generation 8 + /// Event Database for Generation 8 public static WB8[] EGDB_G8B { get; private set; } = []; - /// Event Database for Generation 9 + /// Event Database for Generation 9 public static WC9[] EGDB_G9 { get; private set; } = []; + + /// Event Database for Generation 9 + public static WA9[] EGDB_G9A { get; private set; } = []; #endregion private static PCD[] GetPCDDB(Memory bin) => Get(bin, PCD.Size, static d => new PCD(d)); @@ -82,6 +88,7 @@ public static class EncounterEvent private static WB8[] GetWB8DB(Memory bin) => Get(bin, WB8.Size, static d => new WB8(d)); private static WA8[] GetWA8DB(Memory bin) => Get(bin, WA8.Size, static d => new WA8(d)); private static WC9[] GetWC9DB(Memory bin) => Get(bin, WC9.Size, static d => new WC9(d)); + private static WA9[] GetWA9DB(Memory bin) => Get(bin, WA9.Size, static d => new WA9(d)); private static T[] Get(Memory bin, int size, Func, T> ctor) { @@ -114,6 +121,7 @@ public static void RefreshMGDB(params ReadOnlySpan paths) HashSet? b8 = null; List? lb8 = null; HashSet? a8 = null; List? la8 = null; HashSet? g9 = null; List? lg9 = null; + HashSet? a9 = null; List? la9 = null; // Load external files // For each file, load the gift object into the appropriate list. @@ -135,6 +143,7 @@ public static void RefreshMGDB(params ReadOnlySpan paths) WB8 wb8 => AddOrExpand(ref b8, ref lb8, wb8), WA8 wa8 => AddOrExpand(ref a8, ref la8, wa8), WC9 wc9 => AddOrExpand(ref g9, ref lg9, wc9), + WA9 wa9 => AddOrExpand(ref a9, ref la9, wa9), _ => false, }; if (!added) @@ -165,6 +174,7 @@ static bool AddOrExpand([NotNullWhen(true)] ref HashSet? arr, ref List? EGDB_G8A = SetArray(la8); EGDB_G8B = SetArray(lb8); EGDB_G9 = SetArray(lg9); + EGDB_G9A = SetArray(la9); return; [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/PKHeX.Core/Legality/Encounters/Data/EncounterUtil.cs b/PKHeX.Core/Legality/Encounters/Data/EncounterUtil.cs index b5d1e7317..3f93a4456 100644 --- a/PKHeX.Core/Legality/Encounters/Data/EncounterUtil.cs +++ b/PKHeX.Core/Legality/Encounters/Data/EncounterUtil.cs @@ -28,6 +28,12 @@ public static ReadOnlySpan Get([ConstantExpected] string resource) public static BinLinkerAccessor Get([ConstantExpected] string resource, [Length(2, 2)] ReadOnlySpan ident) => BinLinkerAccessor.Get(Get(resource), ident); + /// + /// Gets an index-able accessor for the specified resource. + /// + public static BinLinkerAccessor16 Get16([ConstantExpected] string resource, [Length(2, 2)] ReadOnlySpan ident) + => BinLinkerAccessor16.Get(Get(resource), ident); + /// /// Grabs the localized names for individual templates for all languages from the specified of the list. /// diff --git a/PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs b/PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs new file mode 100644 index 000000000..810210e9c --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs @@ -0,0 +1,91 @@ +using static PKHeX.Core.EncounterUtil; +using static PKHeX.Core.Shiny; + +namespace PKHeX.Core; + +internal static class Encounters9a +{ + internal static readonly EncounterArea9a[] Slots = EncounterArea9a.GetAreas(Get16("za", "za"u8)); + + internal static readonly EncounterGift9a[] Gifts = + [ + // Z-A Starters + new(0152,0,05,128) { Location = 30026, FlawlessIVCount = 3, Moves = new(033,039,000,000) }, // Chikorita (test_encount_init_poke_0) + new(0498,0,05,128) { Location = 30026, FlawlessIVCount = 3, Moves = new(033,039,000,000) }, // Tepig (test_encount_init_poke_1) + new(0158,0,05,128) { Location = 30026, FlawlessIVCount = 3, Moves = new(033,043,000,000) }, // Totodile (test_encount_init_poke_2) + + // Kanto Starters + new(0001,0,05,000) { Location = 30027, FlawlessIVCount = 3 }, // Bulbasaur (sub_addpoke_fushigidane) + new(0004,0,05,000) { Location = 30027, FlawlessIVCount = 3 }, // Charmander (sub_addpoke_hitokage) + new(0007,0,05,000) { Location = 30027, FlawlessIVCount = 3 }, // Squirtle (sub_addpoke_zenigame) + + // Kalos Starters + new(0650,0,14,128) { Location = 30030, Gender = 1, Nature = Nature.Impish, IVs = new(31,31,31,15,15,15) }, // Chespin (sub_addpoke_harimaron) + new(0653,0,14,128) { Location = 30031, Gender = 1, Nature = Nature.Lonely, IVs = new(15,15,15,31,31,31) }, // Fennekin (sub_addpoke_fokko) + new(0656,0,14,128) { Location = 00069, Gender = 0, Nature = Nature.Sassy, IVs = new(15,31,15,31,31,15) }, // Froakie (sub_addpoke_keromatsu) + + // Side Missions + new(0618,1,38,128) { Location = 30028, Gender = 0, FlawlessIVCount = 3, Moves = new(319,334,089,340), Trainer = TrainerGift9a.Stunfisk }, // Stunfisk-1 (sub_addpoke_gmaggyo) + new(0665,8,09,128) { Location = 30029, Gender = 0, Nature = Nature.Naive, FlawlessIVCount = 3 }, // Spewpa-8 (sub_addpoke_kofuurai) + + // Eternal Flower Floette + new(0670,5,72,128) { Location = 30026, Gender = 1, Nature = Nature.Modest, FlawlessIVCount = 3, Moves = new(617,412,202,235), Trainer = TrainerGift9a.Floette }, // Floette-5 (addpoke_floette_eien) + + // Korrina's Lucario + new(0448,0,50,128) { Location = 30026, Gender = 0, Nature = Nature.Hardy, IVs = new(31,20,31,20,20,31), Moves = new(396,418,249,182), Trainer = TrainerGift9a.Lucario }, // Lucario (sub_addpoke_rukario) + + // Rogue Mega Absol + new(0359,0,30,128) { Location = 30026, FlawlessIVCount = 3, Moves = new(400,163,098,014) }, // Absol (vsmega_init_abusoru) + + // Fossils (Tutorial Revival) + new(0696,0,20,128) { Location = 30027, FlawlessIVCount = 3, Moves = new(046,088,204,044) }, // Tyrunt (sub_addpoke_chigoras) + new(0698,0,20,128) { Location = 30027, FlawlessIVCount = 3, Moves = new(088,196,036,054) }, // Amaura (sub_addpoke_amarus) + + // Fossils + new(0142,0,20,000) { Location = 30027, Shiny = Random }, // Aerodactyl (restoration_ptera) + new(0696,0,20,000) { Location = 30027, Shiny = Random }, // Tyrunt (restoration_chigoras) + new(0698,0,20,000) { Location = 30027, Shiny = Random }, // Amaura (restoration_amarus) + + // Alpha Fossils + new(0142,0,35,255) { Location = 30027, Shiny = Random, IsAlpha = true, FlawlessIVCount = 3 }, // Aerodactyl (restoration_ptera) + new(0696,0,35,255) { Location = 30027, Shiny = Random, IsAlpha = true, FlawlessIVCount = 3 }, // Tyrunt (restoration_chigoras) + new(0698,0,35,255) { Location = 30027, Shiny = Random, IsAlpha = true, FlawlessIVCount = 3 }, // Amaura (restoration_amarus) + ]; + + internal static readonly EncounterStatic9a[] Static = + [ + // Legendary and Mythical Pokémon + new(0716,0,75,128) { Location = 00210, FlawlessIVCount = 3, Moves = new(224,585,532,601) }, // Xerneas (m10_x) + new(0717,0,75,128) { Location = 00075, FlawlessIVCount = 3, Moves = new(542,399,094,613) }, // Yveltal (m10_y) + new(0718,2,84,128) { Location = 00212, Nature = Nature.Quiet, IVs = new(31,31,15,19,31,28), Moves = new(687,614,615,616) }, // Zygarde-2 (ect_boss_0718_01) + + // Main Missions / Side Missions + new(0013,0,45,255) { Location = 00055, Gender = 0, Nature = Nature.Naive, IsAlpha = true, FlawlessIVCount = 3 }, // Weedle (sub_023_oybn) + new(0092,0,40,128) { Location = 00231 }, // Gastly (ect_d03_01_z092_ev) + new(0094,0,42,128) { Location = 00231 }, // Gengar (ect_d03_01_z094_ev) + new(0302,0,10,128) { Location = 00205, Gender = 0, Nature = Nature.Naive, Moves = new(033,043,425,000) }, // Sableye (sub_003_ghost) + new(0303,0,52,255) { Location = 00057, Gender = 1, Nature = Nature.Hardy, FlawlessIVCount = 3 }, // Mawile (sub_107_kucheat) + new(0505,0,50,255) { Location = 00014, Gender = 0, Nature = Nature.Bold, IsAlpha = true, FlawlessIVCount = 3 }, // Watchog (sub_056_evoybn) + new(0569,0,50,128) { Location = 00030, Gender = 0, Nature = Nature.Naughty, Moves = new(398,693,205,232) }, // Garbodor (sub_027_predator) + new(0587,0,53,128) { Location = 00089, Gender = 1, Nature = Nature.Naive, Moves = new(113,521,403,209) }, // Emolga (sub_115_emonga) + new(0659,0,10,255) { Location = 00079, Gender = 0, Nature = Nature.Mild, IsAlpha = true, FlawlessIVCount = 3 }, // Bunnelby (sub_002_oybn) + new(0660,0,28,128) { Location = 00012, Gender = 0, Nature = Nature.Adamant }, // Diggersby (sub_055_evpoke) + new(0707,0,40,128) { Location = 00235, Gender = 0, Nature = Nature.Timid, Moves = new(583,430,577,319) }, // Klefki (m05_cleffy) + + // Side Missions EX + // new(0150,0,70,128) { Location = 00234, FlawlessIVCount = 3, Moves = new(094,396,427,133) }, // Mewtwo (sub_120_mewtwo) + // new(0703,0,66,128) { Location = 00063, FlawlessIVCount = 3, Moves = new(444,430,605,157) }, // Carbink (sub_119_melecie_01) + // new(0703,0,66,128) { Location = 00063, FlawlessIVCount = 3, Moves = new(444,446,408,605) }, // Carbink (sub_119_melecie_02) + // new(0719,0,70,128) { Location = 00063, FlawlessIVCount = 3, Moves = new(591,585,446,577) }, // Diancie (sub_119_diancie) + ]; + + private const string tradeZA = "tradeza"; + private static readonly string[][] TradeNames = Util.GetLanguageStrings11(tradeZA); + internal static readonly EncounterTrade9a[] Trades = + [ + new(TradeNames,0,0214,0,12) { ID32 = 797394, OTGender = 1, Gender = 0, Nature = Nature.Brave, IVs = new(31,31,15,31,15,15), Moves = new(033,043,203,042) }, // Heracross (sub_tradepoke_heracros) + new(TradeNames,1,0447,0,25) { ID32 = 348226, OTGender = 0, Gender = 0, Nature = Nature.Rash, IVs = new(15,31,15,31,31,15), Moves = new(418,098,249,197) }, // Riolu (sub_tradepoke_riolu) + new(TradeNames,2,0079,1,30) { ID32 = 934764, OTGender = 0, Gender = 0, FlawlessIVCount = 3, Moves = new(352,133,428,029) }, // Slowpoke-1 (sub_addpoke_gyadon) + new(TradeNames,3,0026,1,64) { ID32 = 693489, OTGender = 1, Gender = 0, Nature = Nature.Jolly, IVs = new(20,20,20,20,20,20), Moves = new(094,087,057,583) }, // Raichu-1 (sub_addpoke_araichu) + ]; +} diff --git a/PKHeX.Core/Legality/Encounters/Data/Live/DistributionWindow.cs b/PKHeX.Core/Legality/Encounters/Data/Live/DistributionWindow.cs index 4a39e9748..0b9c6a56b 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Live/DistributionWindow.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Live/DistributionWindow.cs @@ -21,7 +21,7 @@ public DistributionWindow(int startYear, int startMonth, int startDay, int endYe /// /// Date obtained. /// True if the date obtained is within the date of availability for the given range. - public bool Contains(DateOnly obtained) => (Start <= obtained && End is null) || obtained <= End; + public bool Contains(DateOnly obtained) => Start <= obtained && !(obtained > End); /// /// Get a valid date within the generation range. diff --git a/PKHeX.Core/Legality/Encounters/Data/Live/EncounterServerDate.cs b/PKHeX.Core/Legality/Encounters/Data/Live/EncounterServerDate.cs index 479b50240..7c50b9d92 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Live/EncounterServerDate.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Live/EncounterServerDate.cs @@ -24,6 +24,7 @@ public static class EncounterServerDate WA8 wa8 => Result(wa8.IsWithinDistributionWindow(obtained)), WB8 wb8 => Result(wb8.IsWithinDistributionWindow(obtained)), WC9 wc9 => Result(wc9.IsWithinDistributionWindow(obtained)), + WA9 wa9 => Result(wa9.IsWithinDistributionWindow(obtained)), EncounterSlot7GO g7 => Result(g7.IsWithinDistributionWindow(obtained)), EncounterSlot8GO g8 => Result(g8.IsWithinDistributionWindow(obtained)), _ => throw new ArgumentOutOfRangeException(nameof(enc)), @@ -44,11 +45,15 @@ public static class EncounterServerDate /// public static bool IsWithinDistributionWindow(this WC9 card, DateOnly obtained) => card.GetDistributionWindow(out var window) && window.Contains(obtained); + /// + public static bool IsWithinDistributionWindow(this WA9 card, DateOnly obtained) => card.GetDistributionWindow(out var window) && window.Contains(obtained); + public static bool GetDistributionWindow(this WB7 card, out DistributionWindow window) => WB7Gifts.TryGetValue(card.CardID, out window); public static bool GetDistributionWindow(this WC8 card, out DistributionWindow window) => WC8Gifts.TryGetValue(card.CardID, out window) || WC8GiftsChk.TryGetValue(card.Checksum, out window); public static bool GetDistributionWindow(this WA8 card, out DistributionWindow window) => WA8Gifts.TryGetValue(card.CardID, out window); public static bool GetDistributionWindow(this WB8 card, out DistributionWindow window) => WB8Gifts.TryGetValue(card.CardID, out window); public static bool GetDistributionWindow(this WC9 card, out DistributionWindow window) => WC9Gifts.TryGetValue(card.CardID, out window) || WC9GiftsChk.TryGetValue(card.Checksum, out window); + public static bool GetDistributionWindow(this WA9 card, out DistributionWindow window) => WA9Gifts.TryGetValue(card.CardID, out window); /// /// Initial introduction of HOME support for SW/SH; gift availability (generating) was revised in 3.0.0. @@ -228,7 +233,7 @@ public static class EncounterServerDate {1548, new(2025, 09, 18, 2025, 10, 01)}, // Shiny Chi-Yu {0524, new(2025, 08, 14, 2025, 08, 31)}, // WCS 2025 Toedscool {0525, new(2025, 08, 15, 2025, 08, 23)}, // WCS 2025 Luca Ceribelli's Farigiraf - {1540, new(2025, 09, 25, 2025, 10, 24)}, // Shiny Miraidon / Koraidon Gift + {1540, new(2025, 09, 25, 2025, 10, 25)}, // Shiny Miraidon / Koraidon Gift {9021, HOME3_ML}, // Hidden Ability Sprigatito {9022, HOME3_ML}, // Hidden Ability Fuecoco @@ -236,4 +241,13 @@ public static class EncounterServerDate {9024, new(2024, 10, 16)}, // Shiny Meloetta {9025, new(2024, 11, 01)}, // PokéCenter Birthday Tandemaus }; + + /// + /// Minimum date the gift can be received. + /// + private static readonly Dictionary WA9Gifts = new() + { + {1601, new(2025, 10, 14, 2026, 3, 1, +2)}, // Ralts holding Gardevoirite + {0102, new(2025, 10, 23, 2026, 2, 1, +2)}, // Slowpoke Poké Center Gift + }; } diff --git a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator4.cs b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator4.cs index e9673a8af..e646d867b 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator4.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator4.cs @@ -23,6 +23,8 @@ public IEnumerable GetEncounters(PKM pk, LegalInfo info) public IEnumerable GetPossible(PKM pk, EvoCriteria[] chain, GameVersion version, EncounterTypeGroup groups) { + if (version is GameVersion.BATREV) + yield break; var iterator = new EncounterPossible4(chain, groups, version, pk); foreach (var enc in iterator) yield return enc; diff --git a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator9.cs b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator9.cs index af1d1979f..b89277f11 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator9.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator9.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.GameVersion; @@ -50,14 +51,14 @@ public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, Le private const EntityContext Context = EntityContext.Gen9; private const byte EggLevel = 1; - public static bool TryGetEgg(PKM pk, EvoCriteria[] chain, GameVersion version, [NotNullWhen(true)] out EncounterEgg9? result) + public static bool TryGetEgg(PKM pk, ReadOnlySpan chain, GameVersion version, [NotNullWhen(true)] out EncounterEgg9? result) { if (version == 0 && pk.IsEgg) version = SL; return TryGetEgg(chain, version, out result); } - public static bool TryGetEgg(EvoCriteria[] chain, GameVersion version, [NotNullWhen(true)] out EncounterEgg9? result) + public static bool TryGetEgg(ReadOnlySpan chain, GameVersion version, [NotNullWhen(true)] out EncounterEgg9? result) { result = null; var devolved = chain[^1]; diff --git a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator9a.cs b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator9a.cs new file mode 100644 index 000000000..0491e02ff --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator9a.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace PKHeX.Core; + +public sealed class EncounterGenerator9a : IEncounterGenerator +{ + public static readonly EncounterGenerator9a Instance = new(); + public bool CanGenerateEggs => false; + + public IEnumerable GetPossible(PKM _, EvoCriteria[] chain, GameVersion __, EncounterTypeGroup groups) + { + var iterator = new EncounterPossible9a(chain, groups); + foreach (var enc in iterator) + yield return enc; + } + + public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, LegalInfo info) + { + var iterator = new EncounterEnumerator9a(pk, chain); + foreach (var enc in iterator) + yield return enc.Encounter; + } +} diff --git a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/Lump/EncounterGenerator9X.cs b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/Lump/EncounterGenerator9X.cs new file mode 100644 index 000000000..a3397cc69 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/Lump/EncounterGenerator9X.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using static PKHeX.Core.GameVersion; + +namespace PKHeX.Core; + +public sealed class EncounterGenerator9X : IEncounterGenerator +{ + public static readonly EncounterGenerator9X Instance = new(); + public bool CanGenerateEggs => false; + + public IEnumerable GetPossible(PKM pk, EvoCriteria[] chain, GameVersion game, EncounterTypeGroup groups) => game switch + { + ZA => EncounterGenerator9a.Instance.GetPossible(pk, chain, game, groups), + SL or VL => EncounterGenerator9.Instance.GetPossible(pk, chain, game, groups), + _ => [], + }; + + public IEnumerable GetEncounters(PKM pk, LegalInfo info) + { + var chain = EncounterOrigin.GetOriginChain(pk, 9, pk.Context); + if (chain.Length == 0) + return []; + + return GetEncounters(pk, chain, info); + } + + public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, LegalInfo info) => pk.Version switch + { + ZA => EncounterGenerator9a.Instance.GetEncounters(pk, chain, info), + SL or VL => EncounterGenerator9.Instance.GetEncounters(pk, chain, info), + _ => [], + }; +} diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs index fb5b4cd01..678835ed3 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs @@ -553,4 +553,19 @@ public bool IsSatisfiedIVs(uint iv32) if (!IsSatisfiedIV(IV_SPD, (int)((iv32 >> 25) & 0x1F))) return false; return true; } + + /// + /// Gets the IV based on the specified index (visual order). + /// + /// Stat index (visual order). + public sbyte GetIV(int index) => index switch + { + 0 => IV_HP, + 1 => IV_ATK, + 2 => IV_DEF, + 3 => IV_SPA, + 4 => IV_SPD, + 5 => IV_SPE, + _ => throw new ArgumentOutOfRangeException(nameof(index), index, null), + }; } diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterGenerator.cs index 30f875abf..ac3fcc915 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterGenerator.cs @@ -29,7 +29,7 @@ public static class EncounterGenerator 6 => EncounterGenerator6.Instance.GetEncounters(pk, info), 7 => EncounterGenerator7X.Instance.GetEncounters(pk, info), 8 => EncounterGenerator8X.Instance.GetEncounters(pk, info), - 9 => EncounterGenerator9.Instance.GetEncounters(pk, info), + 9 => EncounterGenerator9X.Instance.GetEncounters(pk, info), _ => EncounterGeneratorDummy.Instance.GetEncounters(pk, info), }; @@ -61,7 +61,11 @@ public static class EncounterGenerator GameVersion.BD or GameVersion.SP => EncounterGenerator8b.Instance, _ => EncounterGenerator8.Instance, }, - 9 => EncounterGenerator9.Instance, + 9 => version switch + { + GameVersion.ZA => EncounterGenerator9a.Instance, + _ => EncounterGenerator9.Instance, + }, _ => EncounterGeneratorDummy.Instance, }; } diff --git a/PKHeX.Core/Legality/Encounters/Generator/Possible/EncounterPossible9a.cs b/PKHeX.Core/Legality/Encounters/Generator/Possible/EncounterPossible9a.cs new file mode 100644 index 000000000..593f46b70 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Generator/Possible/EncounterPossible9a.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace PKHeX.Core; + +/// +/// Iterates to find possible encounters for encounters. +/// +public record struct EncounterPossible9a(EvoCriteria[] Chain, EncounterTypeGroup Flags) : IEnumerator +{ + public IEncounterable Current { get; private set; } = null!; + + private int Index; + private int SubIndex; + private YieldState State; + readonly object IEnumerator.Current => Current; + public readonly void Reset() => throw new NotSupportedException(); + public readonly void Dispose() { } + public readonly IEnumerator GetEnumerator() => this; + + private enum YieldState : byte + { + Start, + + EventStart, + Event, + EventLocal, + TradeStart, + Trade, + + StaticStart, + + SlotStart, + Slot, + SlotEnd, + + StaticCapture, + StaticGift, + StaticEnd, + + End, + } + + public bool MoveNext() + { + switch (State) + { + case YieldState.Start: + if (Chain.Length == 0) + break; + goto case YieldState.EventStart; + + case YieldState.EventStart: + if (!Flags.HasFlag(EncounterTypeGroup.Mystery)) + goto case YieldState.TradeStart; + State = YieldState.Event; goto case YieldState.Event; + case YieldState.Event: + if (TryGetNext(EncounterEvent.MGDB_G9A)) + return true; + Index = 0; State = YieldState.EventLocal; goto case YieldState.EventLocal; + case YieldState.EventLocal: + if (TryGetNext(EncounterEvent.EGDB_G9A)) + return true; + Index = 0; goto case YieldState.TradeStart; + + case YieldState.TradeStart: + if (!Flags.HasFlag(EncounterTypeGroup.Trade)) + goto case YieldState.StaticStart; + State = YieldState.Trade; goto case YieldState.Trade; + case YieldState.Trade: + if (TryGetNext(Encounters9a.Trades)) + return true; + Index = 0; goto case YieldState.StaticStart; + + case YieldState.StaticStart: + if (!Flags.HasFlag(EncounterTypeGroup.Static)) + goto case YieldState.SlotStart; + goto case YieldState.StaticCapture; + case YieldState.StaticCapture: + if (TryGetNext(Encounters9a.Static)) + return true; + Index = 0; State = YieldState.StaticGift; goto case YieldState.StaticGift; + case YieldState.StaticGift: + if (TryGetNext(Encounters9a.Gifts)) + return true; + Index = 0; goto case YieldState.StaticEnd; + case YieldState.StaticEnd: + goto case YieldState.SlotStart; + + case YieldState.SlotStart: + if (!Flags.HasFlag(EncounterTypeGroup.Slot)) + goto case YieldState.End; + goto case YieldState.Slot; + case YieldState.Slot: + if (TryGetNext(Encounters9a.Slots)) + return true; + goto case YieldState.SlotEnd; + case YieldState.SlotEnd: + goto case YieldState.End; + + case YieldState.End: + break; + } + return false; + } + + private bool TryGetNext(TArea[] areas) + where TArea : class, IEncounterArea + where TSlot : class, IEncounterable, IEncounterMatch + { + for (; Index < areas.Length; Index++, SubIndex = 0) + { + var area = areas[Index]; + if (TryGetNextSub(area.Slots)) + return true; + } + return false; + } + + private bool TryGetNextSub(T[] slots) where T : class, IEncounterable, IEncounterMatch + { + while (SubIndex < slots.Length) + { + var enc = slots[SubIndex++]; + foreach (var evo in Chain) + { + if (enc.Species != evo.Species) + continue; + return SetCurrent(enc); + } + } + return false; + } + + private bool TryGetNext(T[] db) where T : class, IEncounterable, IEncounterMatch + { + for (; Index < db.Length;) + { + var enc = db[Index++]; + foreach (var evo in Chain) + { + if (evo.Species != enc.Species) + continue; + return SetCurrent(enc); + } + } + return false; + } + + private bool SetCurrent(IEncounterable match) + { + Current = match; + return true; + } +} diff --git a/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator9a.cs b/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator9a.cs new file mode 100644 index 000000000..f75b116d0 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator9a.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace PKHeX.Core; + +/// +/// Iterates to find potentially matched encounters for . +/// +public record struct EncounterEnumerator9a(PKM Entity, EvoCriteria[] Chain) : IEnumerator> +{ + private IEncounterable? Deferred; + private int Index; + private int SubIndex; + private EncounterMatchRating Rating = EncounterMatchRating.MaxNotMatch; + private bool Yielded; + public MatchedEncounter Current { get; private set; } + private YieldState State; + private ushort met; + private bool mustBeSlot; + readonly object IEnumerator.Current => Current; + + public readonly void Reset() => throw new NotSupportedException(); + public readonly void Dispose() { } + public readonly IEnumerator> GetEnumerator() => this; + + private enum YieldState : byte + { + Start, + + Event, + EventLocal, + TradeStart, + Trade, + + StartCaptures, + StaticStart, + + SlotStart, + Slot, + SlotEnd, + + StaticCapture, + StaticGift, + StaticEnd, + + Fallback, + End, + } + + public bool MoveNext() + { + switch (State) + { + case YieldState.Start: + if (Chain.Length == 0) + break; + + if (!Entity.FatefulEncounter) + goto case YieldState.TradeStart; + State = YieldState.Event; goto case YieldState.Event; + + case YieldState.Event: + if (TryGetNext(EncounterEvent.MGDB_G9A)) + return true; + Index = 0; State = YieldState.EventLocal; goto case YieldState.EventLocal; + case YieldState.EventLocal: + if (TryGetNext(EncounterEvent.EGDB_G9A)) + return true; + if (Yielded) + break; + Index = 0; goto case YieldState.TradeStart; + + case YieldState.TradeStart: + if (Entity.MetLocation != Locations.LinkTrade6NPC) + goto case YieldState.StartCaptures; + State = YieldState.Trade; goto case YieldState.Trade; + case YieldState.Trade: + if (TryGetNext(Encounters9a.Trades)) + return true; + if (Yielded) + break; + Index = 0; goto case YieldState.StartCaptures; + + case YieldState.StartCaptures: + InitializeWildLocationInfo(); + if (mustBeSlot) + goto case YieldState.SlotStart; + goto case YieldState.StaticStart; + + case YieldState.SlotStart: + if (!EncounterStateUtil.CanBeWildEncounter(Entity)) + goto case YieldState.SlotEnd; + State = YieldState.Slot; goto case YieldState.Slot; + case YieldState.Slot: + if (TryGetNext(Encounters9a.Slots)) + return true; + Index = 0; goto case YieldState.SlotEnd; + case YieldState.SlotEnd: + if (!mustBeSlot) + goto case YieldState.Fallback; // already checked everything else + goto case YieldState.StaticStart; + + case YieldState.StaticStart: + State = YieldState.StaticCapture; goto case YieldState.StaticCapture; + + case YieldState.StaticCapture: + if (TryGetNext(Encounters9a.Static)) + return true; + Index = 0; State = YieldState.StaticGift; goto case YieldState.StaticGift; + case YieldState.StaticGift: + if (TryGetNext(Encounters9a.Gifts)) + return true; + Index = 0; State = YieldState.StaticEnd; goto case YieldState.StaticEnd; + + case YieldState.StaticEnd: + if (mustBeSlot) + goto case YieldState.Fallback; // already checked everything else + Index = 0; goto case YieldState.SlotStart; + + case YieldState.Fallback: + State = YieldState.End; + if (Deferred != null) + return SetCurrent(Deferred, Rating); + break; + } + return false; + } + + private void InitializeWildLocationInfo() + { + met = Entity.MetLocation; + mustBeSlot = Entity is IRibbonIndex r && r.HasEncounterMark(); + } + + private bool TryGetNext(TArea[] areas) + where TArea : class, IEncounterArea, IAreaLocation + where TSlot : class, IEncounterable, IEncounterMatch + { + for (; Index < areas.Length; Index++, SubIndex = 0) + { + var area = areas[Index]; + if (!area.IsMatchLocation(met)) + continue; + if (TryGetNextSub(area.Slots)) + return true; + } + return false; + } + + private bool TryGetNextSub(T[] slots) where T : class, IEncounterable, IEncounterMatch + { + while (SubIndex < slots.Length) + { + var enc = slots[SubIndex++]; + foreach (var evo in Chain) + { + if (enc.Species != evo.Species) + continue; + if (!enc.IsMatchExact(Entity, evo)) + break; + + var rating = enc.GetMatchRating(Entity); + if (rating == EncounterMatchRating.Match) + return SetCurrent(enc); + + if (rating < Rating) + { + Deferred = enc; + Rating = rating; + } + break; + } + } + return false; + } + + private bool TryGetNext(T[] db) where T : class, IEncounterable, IEncounterMatch + { + for (; Index < db.Length;) + { + var enc = db[Index++]; + foreach (var evo in Chain) + { + if (evo.Species != enc.Species) + continue; + if (!enc.IsMatchExact(Entity, evo)) + break; + var rating = enc.GetMatchRating(Entity); + if (rating == EncounterMatchRating.Match) + return SetCurrent(enc); + + if (rating < Rating) + { + Deferred = enc; + Rating = rating; + } + break; + } + } + return false; + } + + private bool SetCurrent(T enc, EncounterMatchRating rating = EncounterMatchRating.Match) where T : IEncounterable + { + Current = new MatchedEncounter(enc, rating); + Yielded = true; + return true; + } +} diff --git a/PKHeX.Core/Legality/Encounters/Information/EncounterLearn.cs b/PKHeX.Core/Legality/Encounters/Information/EncounterLearn.cs index bcaab90e2..ec67b2864 100644 --- a/PKHeX.Core/Legality/Encounters/Information/EncounterLearn.cs +++ b/PKHeX.Core/Legality/Encounters/Information/EncounterLearn.cs @@ -89,6 +89,13 @@ private static IEnumerable GetLearnInternal(ushort species, byte foreach (var enc in encs) yield return enc; } + if (PersonalTable.ZA.IsPresentInGame(species, form)) + { + var blank = new PA9 { Species = species, Form = form }; + var encs = EncounterMovesetGenerator.GenerateEncounters(blank, moves, GameVersion.ZA); + foreach (var enc in encs) + yield return enc; + } if (PersonalTable.LA.IsPresentInGame(species, form)) { var blank = new PA8 { Species = species, Form = form }; diff --git a/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot7GO.cs b/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot7GO.cs index 7c7976410..52eef77ed 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot7GO.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot7GO.cs @@ -41,7 +41,7 @@ public string LongName public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var rnd = Util.Rand; var date = this.GetRandomValidDate(); var pk = new PB7 diff --git a/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot8GO.cs b/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot8GO.cs index 58ddc65eb..01dfe97a2 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot8GO.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot8GO.cs @@ -113,7 +113,7 @@ public bool IsBallValid(Ball ball, ushort currentSpecies, PKM pk) public PKM ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { var pk = GetBlank(); - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var rnd = Util.Rand; { pk.Language = language; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterSlot1.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterSlot1.cs index a5861b841..f76c4437f 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterSlot1.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterSlot1.cs @@ -32,7 +32,7 @@ public sealed record EncounterSlot1(EncounterArea1 Parent, ushort Species, byte public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { var version = this.GetCompatibleVersion(tr.Version); - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version); + int language = (int)Language.GetSafeLanguage1((LanguageID)tr.Language, version); var isJapanese = language == (int)LanguageID.Japanese; var pi = EncounterUtil.GetPersonal1(version, Species); var pk = new PK1(isJapanese) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterStatic1.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterStatic1.cs index 653e10c2c..c0f7e4c43 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterStatic1.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterStatic1.cs @@ -35,7 +35,7 @@ public sealed record EncounterStatic1(ushort Species, byte Level, GameVersion Ve public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { var version = this.GetCompatibleVersion(tr.Version); - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version); + int language = (int)Language.GetSafeLanguage1((LanguageID)tr.Language, version); var isJapanese = language == (int)LanguageID.Japanese; var pi = EncounterUtil.GetPersonal1(version, Species); var pk = new PK1(isJapanese) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterTrade1.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterTrade1.cs index 2bf84b0ed..32884c25f 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterTrade1.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterTrade1.cs @@ -116,7 +116,7 @@ public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) bool gsc = CanObtainMinGSC(); var level = gsc ? LevelMinGSC : LevelMinRBY; var version = this.GetCompatibleVersion(tr.Version); - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version); + int language = (int)Language.GetSafeLanguage1((LanguageID)tr.Language, version); var isJapanese = language == (int)LanguageID.Japanese; var pi = EncounterUtil.GetPersonal1(version, Species); var pk = new PK1(isJapanese) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterEgg2.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterEgg2.cs index c34edfc0e..889283e85 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterEgg2.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterEgg2.cs @@ -31,7 +31,7 @@ public sealed record EncounterEgg2(ushort Species, GameVersion Version) : IEncou public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version); + int language = (int)Language.GetSafeLanguage2((LanguageID)tr.Language); var rnd = Util.Rand; var pk = new PK2(language == (int)LanguageID.Japanese) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterSlot2.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterSlot2.cs index 993d11ffb..a1b614fb3 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterSlot2.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterSlot2.cs @@ -80,7 +80,7 @@ public bool IsTreeAvailable(ushort trainerID) public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage2((LanguageID)tr.Language); var isJapanese = language == (int)LanguageID.Japanese; var pi = PersonalTable.C[Species]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterStatic2.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterStatic2.cs index 8ebb2d5d7..92b582a29 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterStatic2.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterStatic2.cs @@ -43,7 +43,7 @@ public sealed record EncounterStatic2(ushort Species, byte Level, GameVersion Ve public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { var version = this.GetCompatibleVersion(tr.Version); - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version); + int language = (int)Language.GetSafeLanguage2((LanguageID)tr.Language); var pi = PersonalTable.C[Species]; var pk = new PK2 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterTrade2.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterTrade2.cs index b88fefc59..c6d07fca3 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterTrade2.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen2/EncounterTrade2.cs @@ -57,7 +57,7 @@ public EncounterTrade2(ReadOnlySpan names, byte index, ushort species, public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { var version = this.GetCompatibleVersion(tr.Version); - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version); + int language = (int)Language.GetSafeLanguage2((LanguageID)tr.Language); var isJapanese = language == (int)LanguageID.Japanese; var pi = PersonalTable.C[Species]; var pk = new PK2(isJapanese) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterGift3Colo.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterGift3Colo.cs index d6e2822f4..5e181d6f6 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterGift3Colo.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterGift3Colo.cs @@ -85,7 +85,7 @@ private int GetTemplateLanguage(ITrainerInfo tr) { if (IsJapaneseBonusDisk) return 1; // Japanese - return (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + return (int)Language.GetSafeLanguage3((LanguageID)tr.Language); } private static void SetPINGA(CK3 pk, in EncounterCriteria criteria, PersonalInfo3 pi) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterShadow3Colo.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterShadow3Colo.cs index f2ecd9e95..8976b0072 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterShadow3Colo.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterShadow3Colo.cs @@ -78,7 +78,7 @@ public CK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) return pk; } - private int GetTemplateLanguage(ITrainerInfo tr) => IsEReader ? 1 : (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + private int GetTemplateLanguage(ITrainerInfo tr) => IsEReader ? 1 : (int)Language.GetSafeLanguage3((LanguageID)tr.Language); private void SetPINGA(CK3 pk, in EncounterCriteria criteria, PersonalInfo3 pi) { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterStarter3Colo.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterStarter3Colo.cs index 60882e152..c8e692593 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterStarter3Colo.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/Colo/EncounterStarter3Colo.cs @@ -67,7 +67,7 @@ public CK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) return pk; } - private int GetTemplateLanguage(ITrainerInfo tr) => (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + private int GetTemplateLanguage(ITrainerInfo tr) => (int)Language.GetSafeLanguage3((LanguageID)tr.Language); private void SetPINGA(CK3 pk, EncounterCriteria criteria) { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterEgg3.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterEgg3.cs index 5caaa11f0..59f25e374 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterEgg3.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterEgg3.cs @@ -45,7 +45,7 @@ public RandomCorrelationRating IsCompatible(PIDType type, PKM pk) public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version); + int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language); var pk = new PK3 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterSlot3.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterSlot3.cs index 7c1ae7cc0..e7b849770 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterSlot3.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterSlot3.cs @@ -39,7 +39,7 @@ public record EncounterSlot3(EncounterArea3 Parent, ushort Species, byte Form, b public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language); var version = Version switch { GameVersion.RSE => tr.Version switch diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterStatic3.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterStatic3.cs index bbd33830f..4b7ec7dcd 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterStatic3.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterStatic3.cs @@ -92,7 +92,7 @@ private int GetTemplateLanguage(ITrainerInfo tr) if (Species is (ushort)Core.Species.Deoxys && tr.Language == 1) return (int)LanguageID.English; - return (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + return (int)Language.GetSafeLanguage3((LanguageID)tr.Language); } private void SetPINGA(PK3 pk, in EncounterCriteria criteria, PersonalInfo3 pi) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterTrade3.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterTrade3.cs index 1a8bef640..639078a04 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterTrade3.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/EncounterTrade3.cs @@ -86,7 +86,7 @@ public EncounterTrade3(ReadOnlySpan names, byte index, GameVersion ver public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.E[Species]; var pk = new PK3 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterShadow3XD.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterShadow3XD.cs index 6d091490a..2f82500cb 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterShadow3XD.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterShadow3XD.cs @@ -44,7 +44,7 @@ public sealed record EncounterShadow3XD(byte Index, ushort Gauge, ReadOnlyMemory public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language); var pi = PersonalTable.E[Species]; var pk = new XK3 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterSlot3XD.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterSlot3XD.cs index 4b06e195f..96e3d6ee2 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterSlot3XD.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterSlot3XD.cs @@ -32,7 +32,7 @@ public sealed record EncounterSlot3XD(EncounterArea3XD Parent, ushort Species, b public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language); var pi = PersonalTable.E[Species]; var pk = new XK3 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterStatic3XD.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterStatic3XD.cs index 076ef41ea..f7829d3d1 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterStatic3XD.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterStatic3XD.cs @@ -36,7 +36,7 @@ public sealed record EncounterStatic3XD(ushort Species, byte Level) public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language); var pi = PersonalTable.E[Species]; var pk = new XK3 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterTrade3XD.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterTrade3XD.cs index 6652344f7..ea4173664 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterTrade3XD.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen3/XD/EncounterTrade3XD.cs @@ -91,7 +91,7 @@ public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) return pk; } - private int GetTemplateLanguage(ITrainerInfo tr) => (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + private int GetTemplateLanguage(ITrainerInfo tr) => (int)Language.GetSafeLanguage3((LanguageID)tr.Language); private static void SetPINGA(XK3 pk, in EncounterCriteria criteria, PersonalInfo3 pi) { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterEgg4.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterEgg4.cs index df845d53d..94ce77293 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterEgg4.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterEgg4.cs @@ -50,7 +50,7 @@ public RandomCorrelationRating IsCompatible(PIDType type, PKM pk) public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var date = EncounterDate.GetDateNDS(); var pk = new PK4 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterSlot4.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterSlot4.cs index 888a6663b..cd5bccb60 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterSlot4.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterSlot4.cs @@ -46,7 +46,7 @@ private Ball GetRequiredBallValue(Ball fallback = Ball.None) public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var pi = PersonalTable.HGSS[Species]; var pk = new PK4 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterStatic4.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterStatic4.cs index 84c6e4b07..8d7aa53d4 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterStatic4.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterStatic4.cs @@ -53,7 +53,7 @@ public sealed record EncounterStatic4(GameVersion Version) public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.HGSS[Species]; var pk = new PK4 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterStatic4Pokewalker.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterStatic4Pokewalker.cs index f9faf1777..9c8f9c9b9 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterStatic4Pokewalker.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterStatic4Pokewalker.cs @@ -69,7 +69,7 @@ public static EncounterStatic4Pokewalker[] GetAll(ReadOnlySpan data) public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.HGSS[Species]; var pk = new PK4 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterTrade4PID.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterTrade4PID.cs index cca842af0..67ddf6c42 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterTrade4PID.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterTrade4PID.cs @@ -77,7 +77,7 @@ public EncounterTrade4PID(ReadOnlySpan names, byte index, GameVersion public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.DP[Species]; var pk = new PK4 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterTrade4RanchGift.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterTrade4RanchGift.cs index f2433074a..1faeb62da 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterTrade4RanchGift.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterTrade4RanchGift.cs @@ -85,7 +85,7 @@ public EncounterTrade4RanchGift(ushort species, byte met, byte level) public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.DP[Species]; var pk = new PK4 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterEgg5.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterEgg5.cs index 5c4a42717..3ff338d65 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterEgg5.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterEgg5.cs @@ -34,7 +34,7 @@ public sealed record EncounterEgg5(ushort Species, byte Form, GameVersion Versio public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var date = EncounterDate.GetDateNDS(); var pk = new PK5 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterSlot5.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterSlot5.cs index da2d251e0..a286ca884 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterSlot5.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterSlot5.cs @@ -47,7 +47,7 @@ public sealed record EncounterSlot5(EncounterArea5 Parent, ushort Species, byte public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var pi = PersonalTable.B2W2[Species]; var pk = new PK5 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5.cs index 79609b336..ceadac519 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5.cs @@ -40,7 +40,7 @@ public sealed record EncounterStatic5(GameVersion Version) public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.B2W2[Species]; var pk = new PK5 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Entree.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Entree.cs index df6285a50..01d76bd40 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Entree.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Entree.cs @@ -32,7 +32,7 @@ public EncounterStatic5Entree(GameVersion version, ushort species, byte level, b public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.B2W2[Species]; var pk = new PK5 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5N.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5N.cs index dfa4bbeec..ff7d21341 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5N.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5N.cs @@ -47,7 +47,7 @@ public sealed record EncounterStatic5N(uint PID) public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.B2W2[Species]; var pk = new PK5 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Radar.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Radar.cs index 62a904250..675c3b342 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Radar.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Radar.cs @@ -28,7 +28,7 @@ public sealed record EncounterStatic5Radar(ushort Species, byte Form, AbilityPer public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.B2W2[Species]; var pk = new PK5 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterTrade5B2W2.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterTrade5B2W2.cs index def86bad1..9eafd4f62 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterTrade5B2W2.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterTrade5B2W2.cs @@ -71,7 +71,7 @@ public EncounterTrade5B2W2(string[] names, GameVersion version) public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.B2W2[Species]; var pk = new PK5 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterTrade5BW.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterTrade5BW.cs index db9f5df64..e23d633f0 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterTrade5BW.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterTrade5BW.cs @@ -69,7 +69,7 @@ public EncounterTrade5BW(ReadOnlySpan names, byte index, GameVersion v public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.BW[Species]; var pk = new PK5 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterEgg6.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterEgg6.cs index b7215e70f..017355030 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterEgg6.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterEgg6.cs @@ -32,7 +32,7 @@ public sealed record EncounterEgg6(ushort Species, byte Form, GameVersion Versio public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var date = EncounterDate.GetDate3DS(); var pi = PersonalTable.AO[Species, Form]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterSlot6AO.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterSlot6AO.cs index 46296a68a..dfb474d0c 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterSlot6AO.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterSlot6AO.cs @@ -57,7 +57,7 @@ private ReadOnlySpan GetDexNavMoves() public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var pi = PersonalTable.AO[Species]; var geo = tr.GetRegionOrigin(language); var pk = new PK6 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterSlot6XY.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterSlot6XY.cs index 2db828e23..f7cd504d1 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterSlot6XY.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterSlot6XY.cs @@ -49,7 +49,7 @@ public sealed record EncounterSlot6XY(EncounterArea6XY Parent, ushort Species, b public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = Version != GameVersion.XY ? Version : tr.Version is GameVersion.X or GameVersion.Y ? tr.Version : GameVersion.X; var form = GetWildForm(Form); var pi = PersonalTable.XY[Species, form]; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterStatic6.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterStatic6.cs index e266dc524..5068a0862 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterStatic6.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterStatic6.cs @@ -50,7 +50,7 @@ public sealed record EncounterStatic6(GameVersion Version) public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.AO[Species]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterTrade6.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterTrade6.cs index bd69c2ffd..f27420c64 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterTrade6.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen6/EncounterTrade6.cs @@ -66,7 +66,7 @@ public EncounterTrade6(ReadOnlySpan names, byte index, GameVersion ver public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.AO[Species]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterEgg7.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterEgg7.cs index 67e4c8628..b4cd7474e 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterEgg7.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterEgg7.cs @@ -30,7 +30,7 @@ public sealed record EncounterEgg7(ushort Species, byte Form, GameVersion Versio public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var date = EncounterDate.GetDate3DS(); var pi = PersonalTable.USUM[Species, Form]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterSlot7.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterSlot7.cs index bd349e2cf..45c586d02 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterSlot7.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterSlot7.cs @@ -45,7 +45,7 @@ public sealed record EncounterSlot7(EncounterArea7 Parent, ushort Species, byte public PK7 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var form = GetWildForm(Form); var pi = PersonalTable.USUM[Species, form]; var geo = tr.GetRegionOrigin(language); diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterStatic7.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterStatic7.cs index 5729ad9d3..f4a60cf8b 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterStatic7.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterStatic7.cs @@ -53,7 +53,7 @@ public sealed record EncounterStatic7(GameVersion Version) public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.USUM[Species, Form]; var geo = tr.GetRegionOrigin(language); diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterTrade7.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterTrade7.cs index 95787ded9..f40f83a01 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterTrade7.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen7/EncounterTrade7.cs @@ -64,7 +64,7 @@ public EncounterTrade7(ReadOnlySpan names, byte index, GameVersion ver public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.USUM[Species, Form]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterSlot7b.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterSlot7b.cs index 413c2b94b..826960f55 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterSlot7b.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterSlot7b.cs @@ -28,7 +28,7 @@ public sealed record EncounterSlot7b(EncounterArea7b Parent, ushort Species, byt public PB7 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var pi = PersonalTable.GG[Species]; var date = EncounterDate.GetDateSwitch(); var pk = new PB7 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterStatic7b.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterStatic7b.cs index f8bb435fb..8f6bb049f 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterStatic7b.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterStatic7b.cs @@ -34,7 +34,7 @@ public sealed record EncounterStatic7b(GameVersion Version) public PB7 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.GG[Species, Form]; var date = EncounterDate.GetDateSwitch(); diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterTrade7b.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterTrade7b.cs index c654b939a..f12a661af 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterTrade7b.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen7b/EncounterTrade7b.cs @@ -46,7 +46,7 @@ public sealed record EncounterTrade7b(GameVersion Version) : IEncounterable, IEn public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.GG[Species, Form]; var date = EncounterDate.GetDateSwitch(); diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterEgg8.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterEgg8.cs index f53e0d1d2..229dfb3fa 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterEgg8.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterEgg8.cs @@ -28,7 +28,7 @@ public sealed record EncounterEgg8(ushort Species, byte Form, GameVersion Versio public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var date = EncounterDate.GetDateSwitch(); var pi = PersonalTable.SWSH[Species, Form]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterSlot8.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterSlot8.cs index 919d40db8..d93bec282 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterSlot8.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterSlot8.cs @@ -47,7 +47,7 @@ public bool CanEncounterViaCurry public PK8 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var form = GetWildForm(Form); var pi = PersonalTable.SWSH[Species, form]; var pk = new PK8 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterStatic8.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterStatic8.cs index 12f4ad7e0..c3a65310d 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterStatic8.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterStatic8.cs @@ -72,7 +72,7 @@ public bool IsOverworldCorrelationCorrect(PKM pk) public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pk = new PK8 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterStatic8Nest.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterStatic8Nest.cs index 163790946..543ac6384 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterStatic8Nest.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterStatic8Nest.cs @@ -53,7 +53,7 @@ public abstract record EncounterStatic8Nest(GameVersion Version) public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = Info; var pk = new PK8 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterTrade8.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterTrade8.cs index 8f32ecbe7..98f83c806 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterTrade8.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8/EncounterTrade8.cs @@ -99,7 +99,7 @@ public EncounterTrade8(ReadOnlyMemory trainerNames, GameVersion version, public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.SWSH[Species, Form]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8a/EncounterSlot8a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8a/EncounterSlot8a.cs index 6b347c8b7..74e162762 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8a/EncounterSlot8a.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8a/EncounterSlot8a.cs @@ -36,7 +36,7 @@ public sealed record EncounterSlot8a(EncounterArea8a Parent, ushort Species, byt public PA8 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PA8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var pi = PersonalTable.LA[Species, Form]; var pk = new PA8 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8a/EncounterStatic8a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8a/EncounterStatic8a.cs index 95ee6bfb3..61abf9d32 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8a/EncounterStatic8a.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8a/EncounterStatic8a.cs @@ -60,7 +60,7 @@ public EncounterStatic8a(ushort species, byte form, byte level, byte heightScala public PA8 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PA8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var pi = PersonalTable.LA[Species, Form]; var pk = new PA8 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterEgg8b.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterEgg8b.cs index 9f37ac9f8..4538bbdf8 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterEgg8b.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterEgg8b.cs @@ -31,7 +31,7 @@ public sealed record EncounterEgg8b(ushort Species, byte Form, GameVersion Versi public PB8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var date = EncounterDate.GetDateSwitch(); var pi = PersonalTable.BDSP[Species, Form]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterSlot8b.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterSlot8b.cs index ad3fff3fe..b9fb9aef6 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterSlot8b.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterSlot8b.cs @@ -65,7 +65,7 @@ public sealed record EncounterSlot8b(EncounterArea8b Parent, ushort Species, byt public PB8 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PB8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var pi = PersonalTable.BDSP[Species, Form]; var pk = new PB8 { diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterStatic8b.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterStatic8b.cs index 28158dee1..243e6450f 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterStatic8b.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterStatic8b.cs @@ -61,7 +61,7 @@ public bool IsStaticCorrelationCorrect(PKM pk) public PB8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.BDSP[Species, Form]; var pk = new PB8 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterTrade8b.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterTrade8b.cs index f0826a909..d3de9ae94 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterTrade8b.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen8b/EncounterTrade8b.cs @@ -74,7 +74,7 @@ public EncounterTrade8b(ReadOnlySpan names, byte index, GameVersion ve public PB8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.BDSP[Species, Form]; var pk = new PB8 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterDist9.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterDist9.cs index cb4b75e38..cffa04323 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterDist9.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterDist9.cs @@ -237,7 +237,7 @@ private static EncounterDist9 ReadEncounter(ReadOnlySpan data) => new() public PK9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = GetPersonal(); var pk = new PK9 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterEgg9.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterEgg9.cs index 55aafe849..4500f86c4 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterEgg9.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterEgg9.cs @@ -28,7 +28,7 @@ public sealed record EncounterEgg9(ushort Species, byte Form, GameVersion Versio public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var date = EncounterDate.GetDateSwitch(); var pi = PersonalTable.SV[Species, Form]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterFixed9.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterFixed9.cs index ca64eaaec..269512213 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterFixed9.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterFixed9.cs @@ -77,7 +77,7 @@ private static EncounterFixed9 ReadEncounter(ReadOnlySpan data) => new() public PK9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.SV[Species, Form]; var pk = new PK9 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterMight9.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterMight9.cs index d570d98db..43baecf5e 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterMight9.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterMight9.cs @@ -251,7 +251,7 @@ private static EncounterMight9 ReadEncounter(ReadOnlySpan data) => new() public PK9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.SV[Species, Form]; var pk = new PK9 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterOutbreak9.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterOutbreak9.cs index cd629a6e0..2d836f915 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterOutbreak9.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterOutbreak9.cs @@ -77,7 +77,7 @@ private static EncounterOutbreak9 ReadEncounter(ReadOnlySpan data) => new( public PK9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.SV[Species, Form]; var pk = new PK9 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterSlot9.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterSlot9.cs index 1eb5f6890..7c67fb6ee 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterSlot9.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterSlot9.cs @@ -40,7 +40,7 @@ public sealed record EncounterSlot9(EncounterArea9 Parent, ushort Species, byte public PK9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var form = GetWildForm(Form); var version = Version != GameVersion.SV ? Version : tr.Version is GameVersion.SL or GameVersion.VL ? tr.Version : GameVersion.SL; var pi = PersonalTable.SV[Species, form]; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterStatic9.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterStatic9.cs index 274684177..0646b8e76 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterStatic9.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterStatic9.cs @@ -68,7 +68,7 @@ public bool IsMissingExtraMark(PKM pk, out RibbonIndex index) public PK9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.SV[Species, Form]; var pk = new PK9 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterTera9.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterTera9.cs index 287715136..9a8e39cd9 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterTera9.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterTera9.cs @@ -174,7 +174,7 @@ private static EncounterTera9 ReadEncounter(ReadOnlySpan data, TeraRaidMap public PK9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = GetPersonal(); var pk = new PK9 diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterTrade9.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterTrade9.cs index 996649e83..c61fc1b4e 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterTrade9.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9/EncounterTrade9.cs @@ -69,7 +69,7 @@ public EncounterTrade9(ReadOnlySpan names, byte index, GameVersion ver public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); var pi = PersonalTable.SV[Species, Form]; var rnd = Util.Rand; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterArea9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterArea9a.cs new file mode 100644 index 000000000..787711a91 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterArea9a.cs @@ -0,0 +1,52 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +/// +/// encounter area +/// +public sealed record EncounterArea9a : IEncounterArea, IAreaLocation +{ + public EncounterSlot9a[] Slots { get; } + + public readonly byte Location; + public readonly SlotType9a Type; + public bool IsMatchLocation(ushort location) => Location == location; // no crossovers! + + public static EncounterArea9a[] GetAreas(BinLinkerAccessor16 input) + { + var result = new EncounterArea9a[input.Length]; + for (int i = 0; i < result.Length; i++) + result[i] = new EncounterArea9a(input[i]); + return result; + } + + private EncounterArea9a(ReadOnlySpan areaData) + { + Location = areaData[0]; // 235 max, will overflow in DLC, probably. + Type = SlotType9a.Standard; + // 2..3 reserved + Slots = ReadSlots(areaData[4..]); + } + + private EncounterSlot9a[] ReadSlots(ReadOnlySpan areaData) + { + const int size = 8; + var result = new EncounterSlot9a[areaData.Length / size]; + for (int i = 0; i < result.Length; i++) + { + var entry = areaData[(i * size)..]; + var shiny = (Shiny)entry[7]; + var alpha = entry[6] == 1; + var max = entry[5]; + var min = entry[4]; + var gender = entry[3]; + var form = entry[2]; + var species = ReadUInt16LittleEndian(entry); + + result[i] = new EncounterSlot9a(this, species, form, min, max, alpha, gender, shiny); + } + return result; + } +} diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterGift9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterGift9a.cs new file mode 100644 index 000000000..e62e6eefc --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterGift9a.cs @@ -0,0 +1,302 @@ +using System; + +namespace PKHeX.Core; + +/// +/// Gift Encounter found in . +/// +public sealed record EncounterGift9a(ushort Species, byte Form, byte Level, byte Size = EncounterGift9a.NoScale) + : IEncounter9a, IEncounterConvertible, IFixedGender, IFixedNature, IFixedIVSet, IMoveset +{ + public byte Generation => 9; + private const GameVersion Version = GameVersion.ZA; + GameVersion IVersion.Version => GameVersion.ZA; + public EntityContext Context => EntityContext.Gen9a; + public bool IsEgg => false; + public AbilityPermission Ability => AbilityPermission.Any12; + public Ball FixedBall => Ball.Poke; + public Shiny Shiny { get; init; } = Shiny.Never; + public bool IsShiny => false; + public ushort EggLocation => 0; + public byte FlawlessIVCount { get; init; } + private const byte NoScale = 0; + private bool NoScalarsDefined => Size == NoScale; + public Moveset Moves { get; init; } + public IndividualValueSet IVs { get; init; } + public Nature Nature { get; init; } = Nature.Random; + public byte LevelMin => Level; + public byte LevelMax => Level; + + public required ushort Location { get; init; } + public byte Gender { get; init; } = FixedGenderUtil.GenderRandom; + public bool IsAlpha { get; init; } + public TrainerGift9a Trainer { get; init; } + + public string Name => "Gift Encounter"; + public string LongName => Name; + + #region Generating + + PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) => ConvertToPKM(tr, criteria); + PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr); + public PA9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); + public PA9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) + { + int lang = (int)Language.GetSafeLanguage9a((LanguageID)tr.Language); + var pi = PersonalTable.ZA[Species, Form]; + var pk = new PA9 + { + Language = lang, + Species = Species, + Form = Form, + CurrentLevel = LevelMin, + OriginalTrainerFriendship = pi.BaseFriendship, + MetLocation = Location, + MetLevel = LevelMin, + MetDate = EncounterDate.GetDateSwitch(), + Version = Version, + IsAlpha = IsAlpha, + Ball = (byte)Ball.Poke, + + Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation), + ObedienceLevel = LevelMin, + }; + + if (Trainer is TrainerGift9a.None) + { + pk.OriginalTrainerName = tr.OT; + pk.OriginalTrainerGender = tr.Gender; + pk.ID32 = tr.ID32; + } + else + { + pk.OriginalTrainerName = GetFixedTrainerName(Trainer, lang); + pk.OriginalTrainerGender = GetFixedTrainerGender(Trainer); + pk.ID32 = GetFixedTrainerID32(Trainer); + } + + SetPINGA(pk, criteria, pi); + SetMoves(pk, pi, LevelMin); + pk.HealPP(); + + pk.ResetPartyStats(); + return pk; + } + + private void SetPINGA(PA9 pk, EncounterCriteria criteria, PersonalInfo9ZA pi) + { + if (IVs.IsSpecified || Correlation is LumioseCorrelation.ReApplyIVs) + criteria = criteria.WithoutIVs(); + + var param = GetParams(pi); + ulong init = Util.Rand.Rand64(); + var success = this.TryApply64(pk, init, param, criteria); + if (!success && !this.TryApply64(pk, init, param, criteria.WithoutIVs())) + this.TryApply64(pk, init, param, EncounterCriteria.Unrestricted); + + if (IVs.IsSpecified) + criteria.SetRandomIVs(pk, IVs); + else if (Correlation is LumioseCorrelation.ReApplyIVs) + criteria.SetRandomIVs(pk, FlawlessIVCount); + } + + private void SetMoves(PA9 pk, PersonalInfo9ZA pi, byte level) + { + var (learn, plus) = LearnSource9ZA.GetLearnsetAndPlus(Species, Form); + Span moves = stackalloc ushort[4]; + if (Moves.HasMoves) + { + pk.SetMoves(Moves); + pk.GetMoves(moves); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level); + return; + } + + if (!IsAlpha) + { + learn.SetEncounterMoves(level, moves); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level); + } + else + { + learn.SetEncounterMovesBackwards(level, moves, sameDescend: false); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level, moves[0] = pi.AlphaMove); + } + pk.SetMoves(moves); + } + + #endregion + + #region Matching + + public bool IsMatchExact(PKM pk, EvoCriteria evo) + { + if (!this.IsLevelWithinRange(pk.MetLevel)) + return false; + if (Gender != FixedGenderUtil.GenderRandom && pk.Gender != Gender) + return false; + if (!IsMatchEggLocation(pk)) + return false; + if (!IsMatchLocation(pk)) + return false; + if (Form != evo.Form && !FormInfo.IsFormChangeable(Species, Form, pk.Form, Context, pk.Context)) + return false; + if (IVs.IsSpecified && !Legal.GetIsFixedIVSequenceValidSkipRand(IVs, pk)) + return false; + if (FlawlessIVCount != 0 && pk.FlawlessIVCount < FlawlessIVCount) + return false; + if (Nature != Nature.Random && pk.Nature != Nature) + return false; + if (pk is IAlphaReadOnly a && a.IsAlpha != IsAlpha) + return false; + if (Trainer != 0 && !IsMatchFixedTrainer(pk, Trainer)) + return false; + + return true; + } + + private bool IsMatchEggLocation(PKM pk) => pk.EggLocation == EggLocation; + private bool IsMatchLocation(PKM pk) => pk.MetLocation == Location; + + public EncounterMatchRating GetMatchRating(PKM pk) + { + if (IsMatchPartial(pk)) + return EncounterMatchRating.PartialMatch; + return IsMatchDeferred(pk); + } + + private EncounterMatchRating IsMatchDeferred(PKM pk) + { + if (Shiny != Shiny.Random && !Shiny.IsValid(pk)) + return EncounterMatchRating.DeferredErrors; + + if (!TryGetSeed(pk, out _)) + return EncounterMatchRating.DeferredErrors; + + return EncounterMatchRating.Match; + } + + private bool IsMatchPartial(PKM pk) + { + switch (Shiny) + { + case Shiny.Never when pk.IsShiny: + case Shiny.Always when !pk.IsShiny: + return true; + } + + if (!NoScalarsDefined && pk is IScaledSize3 size3 && size3.Scale != Size) + return true; + + return false; + } + + #endregion + + public bool TryGetSeed(PKM pk, out ulong seed) + { + if (GetParams(PersonalTable.ZA[Species, Form]).TryGetSeed(pk, out seed)) + return true; + if (pk.IsShiny && !LumioseSolver.SearchShiny1) + return true; + return false; + } + + public LumioseCorrelation Correlation => IsAlpha ? LumioseCorrelation.PreApplyIVs : LumioseCorrelation.ReApplyIVs; + + public GenerateParam9a GetParams(PersonalInfo9ZA pi) + { + const byte rollCount = 1; + var gender = Gender switch + { + 0 => PersonalInfo.RatioMagicMale, + 1 => PersonalInfo.RatioMagicFemale, + 2 => PersonalInfo.RatioMagicGenderless, + _ => pi.Gender, + }; + var scaleType = NoScalarsDefined ? SizeType9.RANDOM : SizeType9.VALUE; + return new GenerateParam9a(gender, FlawlessIVCount, rollCount, Correlation, scaleType, Size, Nature, Ability, Shiny, IVs); + } + + private bool IsMatchFixedTrainer(PKM pk, TrainerGift9a trainer) + { + if (pk.ID32 != GetFixedTrainerID32(trainer)) + return false; + if (pk.OriginalTrainerGender != GetFixedTrainerGender(trainer)) + return false; + if (pk.OriginalTrainerName != GetFixedTrainerName(trainer, pk.Language)) + return false; + return true; + } + + private static uint GetFixedTrainerID32(TrainerGift9a trainer) => trainer switch + { + TrainerGift9a.Lucario => 912562, + TrainerGift9a.Floette => 1, + TrainerGift9a.Stunfisk => 250932, + _ => throw new ArgumentOutOfRangeException(nameof(trainer), trainer, null), + }; + + private static byte GetFixedTrainerGender(TrainerGift9a trainer) => trainer switch + { + TrainerGift9a.Lucario => 1, + TrainerGift9a.Floette => 0, + TrainerGift9a.Stunfisk => 0, + _ => throw new ArgumentOutOfRangeException(nameof(trainer), trainer, null), + }; + + private static string GetFixedTrainerName(TrainerGift9a trainer, int language) => trainer switch + { + TrainerGift9a.Lucario => language switch + { + (int)LanguageID.Japanese => "コルニ", + (int)LanguageID.English => "Korrina", + (int)LanguageID.French => "Cornélia", + (int)LanguageID.Italian => "Ornella", + (int)LanguageID.German => "Connie", + (int)LanguageID.Spanish => "Corelia", + (int)LanguageID.Korean => "코르니", + (int)LanguageID.ChineseS => "可尔妮", + (int)LanguageID.ChineseT => "可爾妮", + (int)LanguageID.SpanishL => "Korrina", + _ => throw new ArgumentOutOfRangeException(nameof(language), language, null), + }, + TrainerGift9a.Floette => language switch + { + (int)LanguageID.Japanese => "AZ", + (int)LanguageID.English => "AZ", + (int)LanguageID.French => "A.Z.", + (int)LanguageID.Italian => "AZ", + (int)LanguageID.German => "Azett", + (int)LanguageID.Spanish => "A. Z.", + (int)LanguageID.Korean => "AZ", + (int)LanguageID.ChineseS => "AZ", + (int)LanguageID.ChineseT => "AZ", + (int)LanguageID.SpanishL => "A. Z.", + _ => throw new ArgumentOutOfRangeException(nameof(language), language, null), + }, + TrainerGift9a.Stunfisk => language switch + { + (int)LanguageID.Japanese => "グラウン", + (int)LanguageID.English => "Terri", + (int)LanguageID.French => "Gad", + (int)LanguageID.Italian => "Terrence", + (int)LanguageID.German => "Terry", + (int)LanguageID.Spanish => "Terry", + (int)LanguageID.Korean => "그라운", + (int)LanguageID.ChineseS => "帝尚", + (int)LanguageID.ChineseT => "帝尚", + (int)LanguageID.SpanishL => "René", + _ => throw new ArgumentOutOfRangeException(nameof(language), language, null), + }, + _ => throw new ArgumentOutOfRangeException(nameof(trainer), trainer, null), + }; +} + +public enum TrainerGift9a : byte +{ + None = 0, + Lucario, + Floette, + Stunfisk, +} diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterSlot9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterSlot9a.cs new file mode 100644 index 000000000..142cce76f --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterSlot9a.cs @@ -0,0 +1,156 @@ +using System; + +namespace PKHeX.Core; + +/// +/// Encounter Slot found in . +/// +public sealed record EncounterSlot9a(EncounterArea9a Parent, ushort Species, byte Form, byte LevelMin, byte LevelMax, bool IsAlpha, byte Gender, Shiny Shiny) + : IEncounter9a, IEncounterConvertible, IFixedGender +{ + public byte Generation => 9; + private const GameVersion Version = GameVersion.ZA; + GameVersion IVersion.Version => GameVersion.ZA; + public EntityContext Context => EntityContext.Gen9a; + public bool IsEgg => false; + public AbilityPermission Ability => AbilityPermission.Any12; + public Ball FixedBall => Ball.None; + public bool IsShiny => false; + public ushort EggLocation => 0; + public bool IsRandomUnspecificForm => Form >= EncounterUtil.FormDynamic; + + public string Name => "Wild Encounter"; + public string LongName => $"{Name} {Type.ToString().Replace('_', ' ')}"; + public ushort Location => Parent.Location; + public SlotType9a Type => Parent.Type; + + public byte FlawlessIVCount => IsAlpha ? (byte)3 : (byte)0; + + #region Generating + + PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) => ConvertToPKM(tr, criteria); + PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr); + public PA9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); + public PA9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) + { + int lang = (int)Language.GetSafeLanguage9a((LanguageID)tr.Language); + var pi = PersonalTable.ZA[Species, Form]; + var pk = new PA9 + { + Language = lang, + Species = Species, + Form = Form, + CurrentLevel = LevelMin, + MetLocation = Location, + MetLevel = LevelMin, + MetDate = EncounterDate.GetDateSwitch(), + Version = Version, + IsAlpha = IsAlpha, + Ball = (int)Ball.Poke, + + OriginalTrainerName = tr.OT, + OriginalTrainerGender = tr.Gender, + ID32 = tr.ID32, + OriginalTrainerFriendship = pi.BaseFriendship, + Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation), + }; + SetPINGA(pk, criteria, pi); + SetMoves(pk, pi, LevelMin); + pk.HealPP(); + + pk.ResetPartyStats(); + return pk; + } + + private void SetPINGA(PA9 pk, EncounterCriteria criteria, PersonalInfo9ZA pi) + { + if (Correlation is LumioseCorrelation.ReApplyIVs) + criteria = criteria.WithoutIVs(); + + var param = GetParams(pi); + ulong init = Util.Rand.Rand64(); + var success = this.TryApply64(pk, init, param, criteria); + if (!success && !this.TryApply64(pk, init, param, criteria.WithoutIVs())) + this.TryApply64(pk, init, param, EncounterCriteria.Unrestricted); + + if (Correlation is LumioseCorrelation.ReApplyIVs) + criteria.SetRandomIVs(pk, FlawlessIVCount); + } + + private void SetMoves(PA9 pk, PersonalInfo9ZA pi, byte level) + { + var (learn, plus) = LearnSource9ZA.GetLearnsetAndPlus(Species, Form); + Span moves = stackalloc ushort[4]; + if (!IsAlpha) + { + learn.SetEncounterMoves(level, moves); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level); + } + else + { + learn.SetEncounterMovesBackwards(level, moves, sameDescend: false); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level, moves[0] = pi.AlphaMove); + } + pk.SetMoves(moves); + } + + #endregion + + #region Matching + + public bool IsMatchExact(PKM pk, EvoCriteria evo) + { + if (Form != evo.Form && !IsRandomUnspecificForm && !IsValidOutOfBoundsForm(pk)) + return false; + if (!this.IsLevelWithinRange(pk.MetLevel)) + return false; + if (pk is IAlphaReadOnly a && a.IsAlpha != IsAlpha) + return false; + return true; + } + + private bool IsValidOutOfBoundsForm(PKM pk) => Species switch + { + (int)Core.Species.Furfrou => true, // Can change forms in-game. + _ => false, + }; + + public EncounterMatchRating GetMatchRating(PKM pk) + { + if (!IsMatchCorrelation(pk)) + return EncounterMatchRating.DeferredErrors; + + return EncounterMatchRating.Match; + } + + private bool IsMatchCorrelation(PKM pk) + { + if (TryGetSeed(pk, out _)) + return true; + if (!LumioseSolver.SearchShinyN) + return true; // can't check further without brute forcing + + return false; + } + + #endregion + + public bool TryGetSeed(PKM pk, out ulong seed) => GetParams(PersonalTable.ZA[Species, Form]).TryGetSeed(pk, out seed); + + public LumioseCorrelation Correlation => IsAlpha ? LumioseCorrelation.PreApplyIVs : LumioseCorrelation.Normal; + + public GenerateParam9a GetParams(PersonalInfo9ZA pi) + { + const byte rollCount = 1; + var scaleValue = IsAlpha ? (byte)255 : (byte)0; + var scaleType = IsAlpha ? SizeType9.VALUE : SizeType9.RANDOM; + var gender = Gender switch + { + 0 => PersonalInfo.RatioMagicMale, + 1 => PersonalInfo.RatioMagicFemale, + 2 => PersonalInfo.RatioMagicGenderless, + _ => pi.Gender, + }; + return new GenerateParam9a(gender, FlawlessIVCount, rollCount, Correlation, scaleType, Scale: scaleValue, Nature.Random, Ability, Shiny); + } +} diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterStatic9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterStatic9a.cs new file mode 100644 index 000000000..1560d354d --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterStatic9a.cs @@ -0,0 +1,211 @@ +using System; +using static PKHeX.Core.AbilityPermission; + +namespace PKHeX.Core; + +/// +/// Static Encounter found in . +/// +public sealed record EncounterStatic9a(ushort Species, byte Form, byte Level, byte Size = EncounterStatic9a.NoScale) + : IEncounter9a, IEncounterConvertible, IFixedGender, IFixedNature, IFixedIVSet, IMoveset +{ + public byte Generation => 9; + private const GameVersion Version = GameVersion.ZA; + GameVersion IVersion.Version => GameVersion.ZA; + public EntityContext Context => EntityContext.Gen9a; + public bool IsEgg => false; + public AbilityPermission Ability => Any12; + public Ball FixedBall => Ball.None; + public bool IsShiny => false; + public ushort EggLocation => 0; + public byte FlawlessIVCount { get; init; } + public byte LevelMin => Level; + public byte LevelMax => Level; + + private const byte NoScale = 0; + private bool NoScalarsDefined => Size == NoScale; + + public Moveset Moves { get; init; } + public IndividualValueSet IVs { get; init; } + public Nature Nature { get; init; } = Nature.Random; + public required byte Location { get; init; } + public byte Gender { get; init; } = FixedGenderUtil.GenderRandom; + public Shiny Shiny { get; init; } = Shiny.Never; + public bool IsAlpha { get; init; } + + ushort ILocation.Location => Location; + + public string Name => "Static Encounter"; + public string LongName => Name; + + #region Generating + + PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) => ConvertToPKM(tr, criteria); + PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr); + public PA9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); + public PA9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) + { + int lang = (int)Language.GetSafeLanguage9a((LanguageID)tr.Language); + var pi = PersonalTable.ZA[Species, Form]; + var pk = new PA9 + { + Language = lang, + Species = Species, + Form = Form, + CurrentLevel = LevelMin, + OriginalTrainerFriendship = pi.BaseFriendship, + MetLocation = Location, + MetLevel = LevelMin, + MetDate = EncounterDate.GetDateSwitch(), + Version = Version, + IsAlpha = IsAlpha, + Ball = (byte)Ball.Poke, + + Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation), + ObedienceLevel = LevelMin, + OriginalTrainerName = tr.OT, + OriginalTrainerGender = tr.Gender, + ID32 = tr.ID32, + }; + + SetPINGA(pk, criteria, pi); + SetMoves(pk, pi, LevelMin); + pk.HealPP(); + + pk.ResetPartyStats(); + return pk; + } + + private void SetPINGA(PA9 pk, EncounterCriteria criteria, PersonalInfo9ZA pi) + { + if (IVs.IsSpecified || Correlation is LumioseCorrelation.ReApplyIVs) + criteria = criteria.WithoutIVs(); + + var param = GetParams(pi); + ulong init = Util.Rand.Rand64(); + var success = this.TryApply64(pk, init, param, criteria); + if (!success && !this.TryApply64(pk, init, param, criteria.WithoutIVs())) + this.TryApply64(pk, init, param, EncounterCriteria.Unrestricted); + + if (IVs.IsSpecified) + criteria.SetRandomIVs(pk, IVs); + else if (Correlation is LumioseCorrelation.ReApplyIVs) + criteria.SetRandomIVs(pk, FlawlessIVCount); + } + + private void SetMoves(PA9 pk, PersonalInfo9ZA pi, byte level) + { + var (learn, plus) = LearnSource9ZA.GetLearnsetAndPlus(Species, Form); + Span moves = stackalloc ushort[4]; + if (Moves.HasMoves) + { + pk.SetMoves(Moves); + pk.GetMoves(moves); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level); + return; + } + + if (!IsAlpha) + { + learn.SetEncounterMoves(level, moves); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level); + } + else + { + learn.SetEncounterMovesBackwards(level, moves, sameDescend: false); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level, moves[0] = pi.AlphaMove); + } + pk.SetMoves(moves); + } + + #endregion + + #region Matching + + public bool IsMatchExact(PKM pk, EvoCriteria evo) + { + if (!this.IsLevelWithinRange(pk.MetLevel)) + return false; + if (Gender != FixedGenderUtil.GenderRandom && pk.Gender != Gender) + return false; + if (!IsMatchEggLocation(pk)) + return false; + if (!IsMatchLocation(pk)) + return false; + if (Form != evo.Form && !FormInfo.IsFormChangeable(Species, Form, pk.Form, Context, pk.Context)) + return false; + if (IVs.IsSpecified && !Legal.GetIsFixedIVSequenceValidSkipRand(IVs, pk)) + return false; + if (FlawlessIVCount != 0 && pk.FlawlessIVCount < FlawlessIVCount) + return false; + if (Nature != Nature.Random && pk.Nature != Nature) + return false; + if (pk is IAlphaReadOnly a && a.IsAlpha != IsAlpha) + return false; + + return true; + } + + private bool IsMatchEggLocation(PKM pk) => pk.EggLocation == EggLocation; + private bool IsMatchLocation(PKM pk) => pk.MetLocation == Location; + + public EncounterMatchRating GetMatchRating(PKM pk) + { + if (IsMatchPartial(pk)) + return EncounterMatchRating.PartialMatch; + return IsMatchDeferred(pk); + } + + private EncounterMatchRating IsMatchDeferred(PKM pk) + { + if (Shiny != Shiny.Random && !Shiny.IsValid(pk)) + return EncounterMatchRating.DeferredErrors; + + if (!TryGetSeed(pk, out _)) // maybe a Slot? + return EncounterMatchRating.DeferredErrors; + + return EncounterMatchRating.Match; + } + + private bool IsMatchPartial(PKM pk) + { + switch (Shiny) + { + case Shiny.Never when pk.IsShiny: + case Shiny.Always when !pk.IsShiny: + return true; + } + + if (!NoScalarsDefined && pk is IScaledSize3 size3 && size3.Scale != Size) + return true; + + return false; + } + + #endregion + + public bool TryGetSeed(PKM pk, out ulong seed) + { + if (GetParams(PersonalTable.ZA[Species, Form]).TryGetSeed(pk, out seed)) + return true; + if (pk.IsShiny && !LumioseSolver.SearchShiny1) + return true; + return false; + } + + public LumioseCorrelation Correlation => IsAlpha ? LumioseCorrelation.PreApplyIVs : LumioseCorrelation.Normal; + + public GenerateParam9a GetParams(PersonalInfo9ZA pi) + { + const byte rollCount = 1; + var gender = Gender switch + { + 0 => PersonalInfo.RatioMagicMale, + 1 => PersonalInfo.RatioMagicFemale, + 2 => PersonalInfo.RatioMagicGenderless, + _ => pi.Gender, + }; + var scaleType = NoScalarsDefined ? SizeType9.RANDOM : SizeType9.VALUE; + return new GenerateParam9a(gender, FlawlessIVCount, rollCount, Correlation, scaleType, Size, Nature, Ability, Shiny, IVs); + } +} diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterTrade9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterTrade9a.cs new file mode 100644 index 000000000..99e97ceae --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterTrade9a.cs @@ -0,0 +1,230 @@ +using System; + +namespace PKHeX.Core; + +/// +/// Trade Encounter found in . +/// +public sealed record EncounterTrade9a : IEncounter9a, + IFixedTrainer, IFixedNickname, IFixedGender, IFixedNature, IMoveset, IFixedIVSet, ITrainerID32ReadOnly +{ + public byte Generation => 9; + private const GameVersion Version = GameVersion.ZA; + GameVersion IVersion.Version => GameVersion.ZA; + public EntityContext Context => EntityContext.Gen9a; + public ushort Location => Locations.LinkTrade6NPC; + public bool IsEgg => false; + public AbilityPermission Ability => AbilityPermission.Any12; + public Ball FixedBall => Ball.Poke; + public Shiny Shiny => Shiny.Never; + public bool IsShiny => false; + public ushort EggLocation => 0; + public byte FlawlessIVCount { get; init; } + public byte LevelMin => Level; + public byte LevelMax => Level; + public bool IsFixedTrainer => true; + public bool IsFixedNickname => true; + public bool IsAlpha => false; + + private readonly ReadOnlyMemory TrainerNames; + private readonly ReadOnlyMemory Nicknames; + + public ushort Species { get; } + public byte Form { get; } + public byte Level { get; } + public Moveset Moves { get; init; } + public required uint ID32 { get; init; } + public ushort TID16 => (ushort)ID32; + public ushort SID16 => (ushort)(ID32 >> 16); + public required byte OTGender { get; init; } + public byte Gender { get; init; } + public IndividualValueSet IVs { get; init; } + public Nature Nature { get; init; } = Nature.Random; + private const byte Scale = 128; + + public string Name => "Trade Encounter"; + public string LongName => Name; + + public EncounterTrade9a(ReadOnlySpan names, byte index, ushort species, byte form, byte level) + { + Nicknames = EncounterUtil.GetNamesForLanguage(names, index); + TrainerNames = EncounterUtil.GetNamesForLanguage(names, (uint)(index + (names[1].Length >> 1))); + Species = species; + Form = form; + Level = level; + } + + #region Generating + + PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr); + PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) => ConvertToPKM(tr, criteria); + + public PA9 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); + + public PA9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) + { + int lang = (int)Language.GetSafeLanguage9a((LanguageID)tr.Language); + var pi = PersonalTable.ZA[Species, Form]; + var pk = new PA9 + { + Species = Species, + Form = Form, + CurrentLevel = Level, + MetLocation = Location, + MetLevel = Level, + MetDate = EncounterDate.GetDateSwitch(), + Gender = Gender, + Nature = Nature, + StatNature = Nature, + Ball = (byte)FixedBall, + + ID32 = ID32, + Version = Version, + Language = lang, + OriginalTrainerGender = OTGender, + OriginalTrainerName = TrainerNames.Span[lang], + + OriginalTrainerFriendship = pi.BaseFriendship, + + IsNicknamed = true, + Nickname = Nicknames.Span[lang], + + Scale = Scale, + + HandlingTrainerName = tr.OT, + HandlingTrainerLanguage = (byte)tr.Language, + CurrentHandler = 1, + HandlingTrainerFriendship = pi.BaseFriendship, + ObedienceLevel = Level, + }; + + SetPINGA(pk, criteria, pi); + SetMoves(pk, pi, Level); + pk.HealPP(); + + pk.ResetPartyStats(); + return pk; + } + + private void SetPINGA(PA9 pk, EncounterCriteria criteria, PersonalInfo9ZA pi) + { + if (IVs.IsSpecified || Correlation is LumioseCorrelation.ReApplyIVs) + criteria = criteria.WithoutIVs(); + + var param = GetParams(pi); + ulong init = Util.Rand.Rand64(); + var success = this.TryApply64(pk, init, param, criteria); + if (!success && !this.TryApply64(pk, init, param, criteria.WithoutIVs())) + this.TryApply64(pk, init, param, EncounterCriteria.Unrestricted); + + if (IVs.IsSpecified) + criteria.SetRandomIVs(pk, IVs); + else if (Correlation is LumioseCorrelation.ReApplyIVs) + criteria.SetRandomIVs(pk, FlawlessIVCount); + } + + private void SetMoves(PA9 pk, PersonalInfo9ZA pi, byte level) + { + var (learn, plus) = LearnSource9ZA.GetLearnsetAndPlus(Species, Form); + Span moves = stackalloc ushort[4]; + if (Moves.HasMoves) + { + pk.SetMoves(Moves); + pk.GetMoves(moves); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level); + return; + } + + if (!IsAlpha) + { + learn.SetEncounterMoves(level, moves); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level); + } + else + { + learn.SetEncounterMovesBackwards(level, moves, sameDescend: false); + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, level, moves[0] = pi.AlphaMove); + } + pk.SetMoves(moves); + } + + #endregion + + #region Matching + + public bool IsTrainerMatch(PKM pk, ReadOnlySpan trainer, int language) => (uint)language < TrainerNames.Length && trainer.SequenceEqual(TrainerNames.Span[language]); + public bool IsNicknameMatch(PKM pk, ReadOnlySpan nickname, int language) => (uint)language < Nicknames.Length && nickname.SequenceEqual(Nicknames.Span[language]); + public string GetNickname(int language) => Nicknames.Span[(uint)language < Nicknames.Length ? language : 0]; + + private bool IsMatchNatureGenderShiny(PKM pk) + { + if (!Shiny.IsValid(pk)) + return false; + if (pk.Gender != Gender) + return false; + if (Nature != Nature.Random && pk.Nature != Nature) + return false; + return true; + } + + public EncounterMatchRating GetMatchRating(PKM pk) + { + if (pk is IScaledSize3 size3 && size3.Scale != Scale) + return EncounterMatchRating.PartialMatch; + + if (!TryGetSeed(pk, out _)) // maybe a Slot? + return EncounterMatchRating.DeferredErrors; + + return EncounterMatchRating.Match; + } + + public bool IsMatchExact(PKM pk, EvoCriteria evo) + { + if (pk.MetLevel != Level) + return false; + if (!IsMatchLocation(pk)) + return false; + if (!IsMatchNatureGenderShiny(pk)) + return false; + if (pk.ID32 != ID32) + return false; + if (evo.Form != Form && !FormInfo.IsFormChangeable(Species, Form, pk.Form, Context, pk.Context)) + return false; + if (pk.OriginalTrainerGender != OTGender) + return false; + if (!IsMatchEggLocation(pk)) + return false; + if (IVs.IsSpecified && !Legal.GetIsFixedIVSequenceValidSkipRand(IVs, pk)) + return false; + if (FlawlessIVCount != 0 && pk.FlawlessIVCount < FlawlessIVCount) + return false; + if (Nature != Nature.Random && pk.Nature != Nature) + return false; + if (pk is IAlphaReadOnly a && a.IsAlpha != IsAlpha) + return false; + + return true; + } + + private bool IsMatchEggLocation(PKM pk) => pk.EggLocation == EggLocation; + private bool IsMatchLocation(PKM pk) => pk.MetLocation == Location; + + #endregion + + public bool TryGetSeed(PKM pk, out ulong seed) => GetParams(PersonalTable.ZA[Species, Form]).TryGetSeed(pk, out seed); + + public LumioseCorrelation Correlation => LumioseCorrelation.ReApplyIVs; + + public GenerateParam9a GetParams(PersonalInfo9ZA pi) + { + const byte rollCount = 1; + var gender = Gender switch + { + 0 => PersonalInfo.RatioMagicMale, + 1 => PersonalInfo.RatioMagicFemale, + 2 => PersonalInfo.RatioMagicGenderless, + _ => pi.Gender, + }; + return new GenerateParam9a(gender, FlawlessIVCount, rollCount, Correlation, SizeType9.VALUE, Scale, Nature, Ability, Shiny, IVs); + } +} diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/GenerateParam9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/GenerateParam9a.cs new file mode 100644 index 000000000..da58f62bd --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/GenerateParam9a.cs @@ -0,0 +1,15 @@ +namespace PKHeX.Core; + +/// +/// Parameters used to generate data for an encounter. +/// +/// Gender ratio byte. +/// Count of IVs that are perfect. +/// Count of shiny rolls allowed for the PID calculation. +/// PID generation type. +public readonly record struct GenerateParam9a(byte GenderRatio, byte FlawlessIVs, byte RollCount, + LumioseCorrelation Correlation = LumioseCorrelation.Normal, + SizeType9 SizeType = SizeType9.RANDOM, byte Scale = 0, // random + Nature Nature = Nature.Random, + AbilityPermission Ability = AbilityPermission.Any12, + Shiny Shiny = Shiny.Random, IndividualValueSet IVs = default); diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/IEncounter9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/IEncounter9a.cs new file mode 100644 index 000000000..ae83e77e8 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/IEncounter9a.cs @@ -0,0 +1,17 @@ +namespace PKHeX.Core; + +/// +/// Common interface for encounters originating from +/// +public interface IEncounter9a : IEncounterable, IEncounterMatch, IAlphaReadOnly, IFlawlessIVCount, ISeedCorrelation64 +{ + /// + /// RNG Correlation pattern that this encounter follows when generating its random values. + /// + LumioseCorrelation Correlation { get; } + + /// + /// Obtains the generation parameters for this encounter given the provided personal info (for Gender ratio). + /// + GenerateParam9a GetParams(PersonalInfo9ZA pi); +} diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseCorrelation.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseCorrelation.cs new file mode 100644 index 000000000..684b2c6ee --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseCorrelation.cs @@ -0,0 +1,27 @@ +namespace PKHeX.Core; + +/// +/// Defines the correlation types for Legends: Z-A encounter RNG patterns. +/// +public enum LumioseCorrelation : byte +{ + /// + /// RNG generation pattern is as expected, where all values enter FixInitSpec without any being already set or overwritten after generation. + /// + Normal = 0, + + /// + /// Discards the initially generated IVs and reapplies them after FixInitSpec with a separate (unrelated) RNG seed. + /// + ReApplyIVs = 1, + + /// + /// Prepares the IVs before entering FixInitSpec by deciding a quantity of flawless IV indexes first with a separate (unrelated) RNG seed. + /// + PreApplyIVs = 2, + + /// + /// No fake trainer ID is generated; uses the original trainer ID as-is due to it already being provided to FixInitSpec. + /// + SkipTrainer = 3, +} diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseRNG.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseRNG.cs new file mode 100644 index 000000000..91dd85e33 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseRNG.cs @@ -0,0 +1,401 @@ +using System; + +namespace PKHeX.Core; + +public static class LumioseRNG +{ + private const int UNSET = -1; + private const int MAX = 31; + + public static bool Verify(PKM pk, in GenerateParam9a enc, ulong seed) => IsMatch(pk, enc, seed); + + /// + /// Sets the with random data based on the and . + /// + /// True if the generated data matches the . + public static bool TryApply64(this TEnc enc, PA9 pk, in ulong init, in GenerateParam9a param, in EncounterCriteria criteria) + where TEnc : ISpeciesForm + { + var rand = new Xoroshiro128Plus(init); + const int maxCtr = 100_000; + for (int ctr = 0; ctr < maxCtr; ctr++) + { + ulong seed = rand.Next(); // fake cryptosecure + if (!GenerateData(pk, param, criteria, seed)) + continue; + return true; // done. + } + return false; + } + + /// + /// Fills out an entity with details from the provided encounter template. + /// + /// False if the seed cannot generate data matching the criteria. + public static bool GenerateData(PA9 pk, in GenerateParam9a enc, in EncounterCriteria criteria, in ulong seed) + { + var rand = new Xoroshiro128Plus(seed); + pk.EncryptionConstant = (uint)rand.NextInt(uint.MaxValue); + pk.PID = GetAdaptedPID(ref rand, pk, enc); + + if (enc.Shiny is Shiny.Random && criteria.Shiny.IsShiny() != pk.IsShiny) + return false; + + Span ivs = [UNSET, UNSET, UNSET, UNSET, UNSET, UNSET]; + if (enc.IVs.IsSpecified) + { + enc.IVs.CopyToSpeedLast(ivs); + } + else if (enc.Correlation is LumioseCorrelation.PreApplyIVs) + { + if (enc.FlawlessIVs != 0) + GenerouslyPreApplyIVs(criteria, ivs, enc.FlawlessIVs); + } + else + { + for (int i = 0; i < enc.FlawlessIVs; i++) + { + int index; + do { index = (int)rand.NextInt(6); } + while (ivs[index] != UNSET); + ivs[index] = MAX; + } + } + + for (int i = 0; i < 6; i++) + { + if (ivs[i] == UNSET) + ivs[i] = (int)rand.NextInt(MAX + 1); + } + + if (enc.Correlation == LumioseCorrelation.ReApplyIVs) + { + criteria.SetRandomIVs(pk, flawless: enc.FlawlessIVs); + } + else + { + if (!criteria.IsIVsCompatibleSpeedLast(ivs)) + return false; + pk.IV32 = (uint)ivs[0] | + (uint)(ivs[1] << 05) | + (uint)(ivs[2] << 10) | + (uint)(ivs[5] << 15) | // speed is last in the array, but in the middle of the 32bit value + (uint)(ivs[3] << 20) | + (uint)(ivs[4] << 25); + } + + int ability = enc.Ability switch + { + AbilityPermission.Any12H => (int)rand.NextInt(3) << 1, + AbilityPermission.Any12 => (int)rand.NextInt(2) << 1, + _ => (int)enc.Ability, + }; + pk.RefreshAbility(ability >> 1); + + var gender_ratio = enc.GenderRatio; + byte gender = gender_ratio switch + { + PersonalInfo.RatioMagicGenderless => 2, + PersonalInfo.RatioMagicFemale => 1, + PersonalInfo.RatioMagicMale => 0, + _ => GetGender(gender_ratio, rand.NextInt(100)), + }; + if (criteria.IsSpecifiedGender() && !criteria.IsSatisfiedGender(gender)) + return false; + pk.Gender = gender; + + var nature = enc.Nature != Nature.Random ? enc.Nature + : (Nature)rand.NextInt(25); + + // Compromise on Nature -- some are fixed, some are random. If the request wants a specific nature, just mint it. + if (criteria.IsSpecifiedNature() && !criteria.IsSatisfiedNature(nature)) + return false; + pk.Nature = pk.StatNature = nature; + + pk.Scale = enc.SizeType.GetSizeValue(enc.Scale, ref rand); + return true; + } + + /// + /// Gives a quantity of flawless IVs based on the criteria, unrelated to an RNG correlation. + /// + private static void GenerouslyPreApplyIVs(in EncounterCriteria criteria, Span ivs, byte encFlawlessIVs) + { + // Try to give a perfect IV where it's wanted first + for (int i = 0; i < ivs.Length; i++) + { + if (ivs[i] != UNSET) + continue; + var desire = criteria.GetIV(i); + if (desire is not MAX) + continue; + + ivs[i] = MAX; + encFlawlessIVs--; + if (encFlawlessIVs == 0) + return; + } + + // Then try to give a perfect IV where it's allowed + for (int i = 0; i < ivs.Length; i++) + { + if (ivs[i] != UNSET) + continue; + var desire = criteria.GetIV(i); + if (desire >= 0) + continue; + + ivs[i] = MAX; + encFlawlessIVs--; + if (encFlawlessIVs == 0) + return; + } + + // Apply remaining flawless IVs if not <= 1 + for (int i = 0; i < ivs.Length; i++) + { + if (ivs[i] != UNSET) + continue; + var desire = criteria.GetIV(i); + if (desire is 0 or 1) + continue; + + ivs[i] = MAX; + encFlawlessIVs--; + if (encFlawlessIVs == 0) + return; + } + + // If we reach here... we couldn't satisfy the flawless IV count requested. Probably the encounter isn't what the user expected/wanted. + for (int i = 0; i < ivs.Length; i++) + { + if (ivs[i] == UNSET) + ivs[i] = MAX; + } + } + + public static bool IsMatch(PKM pk, in GenerateParam9a enc, in ulong seed) + { + // same as above method + var rand = new Xoroshiro128Plus(seed); + if (pk.EncryptionConstant != (uint)rand.NextInt(uint.MaxValue)) + return false; + + var pid = GetAdaptedPID(ref rand, pk, enc); + if (pk.PID != pid) + return false; + + if (enc.Correlation is LumioseCorrelation.PreApplyIVs) + return IsMatchUnknownPreFillIVs(pk, in enc, rand); + return IsMatchIVsAndFollowing(pk, enc, rand); + } + + private static bool IsMatchIVsAndFollowing(PKM pk, in GenerateParam9a enc, Xoroshiro128Plus rand) + { + Span ivs = [UNSET, UNSET, UNSET, UNSET, UNSET, UNSET]; + if (enc.IVs.IsSpecified) + enc.IVs.CopyToSpeedLast(ivs); + for (int i = 0; i < enc.FlawlessIVs; i++) + { + int index; + do { index = (int)rand.NextInt(6); } + while (ivs[index] != UNSET); + ivs[index] = MAX; + } + return IsMatchIVsAndFollowing(pk, in enc, rand, ivs); + } + + private static bool IsMatchIVsAndFollowing(PKM pk, in GenerateParam9a enc, Xoroshiro128Plus rand, Span ivs) + { + for (int i = 0; i < 6; i++) + { + if (ivs[i] == UNSET) + ivs[i] = (int)rand.NextInt(32); + } + + if (enc.Correlation is not LumioseCorrelation.ReApplyIVs) + { + if (pk.IV_HP != ivs[0]) + return false; + if (pk.IV_ATK != ivs[1]) + return false; + if (pk.IV_DEF != ivs[2]) + return false; + if (pk.IV_SPA != ivs[3]) + return false; + if (pk.IV_SPD != ivs[4]) + return false; + if (pk.IV_SPE != ivs[5]) + return false; + } + + // No way to change abilities. Index must match. + int ability = enc.Ability switch + { + AbilityPermission.Any12H => (int)rand.NextInt(3) << 1, + AbilityPermission.Any12 => (int)rand.NextInt(2) << 1, + _ => (int)enc.Ability, + }; + if (pk.AbilityNumber != ability) + return false; + + var gender_ratio = enc.GenderRatio; + byte gender = gender_ratio switch + { + PersonalInfo.RatioMagicGenderless => 2, + PersonalInfo.RatioMagicFemale => 1, + PersonalInfo.RatioMagicMale => 0, + _ => GetGender(gender_ratio, rand.NextInt(100)), + }; + if (pk.Gender != gender) + return false; + + var nature = enc.Nature != Nature.Random ? enc.Nature + : (Nature)rand.NextInt(25); + if (pk.Nature != nature) + return false; + + // Scale + { + var value = enc.SizeType.GetSizeValue(enc.Scale, ref rand); + if (pk is IScaledSize3 s) + { + if (s.Scale != value) + return false; + } + } + return true; + } + + private static uint GetAdaptedPID(ref Xoroshiro128Plus rand, PKM pk, in GenerateParam9a enc) + { + var fakeTID = enc.Correlation is LumioseCorrelation.SkipTrainer ? pk.ID32 : (uint)rand.NextInt(); + uint pid = (uint)rand.NextInt(); + if (enc.Shiny == Shiny.Random) // let's decide if it's shiny or not! + { + int i = 1; + bool isShiny; + uint xor; + while (true) + { + xor = ShinyUtil.GetShinyXor(pid, fakeTID); + isShiny = xor < 16; + if (isShiny) + { + if (xor != 0) + xor = 1; + break; + } + if (i >= enc.RollCount) + break; + pid = (uint)rand.NextInt(); + i++; + } + ShinyUtil.ForceShinyState(isShiny, ref pid, pk.ID32, xor); + } + else if (enc.Shiny == Shiny.Always) + { + var tid = (ushort)fakeTID; + var sid = (ushort)(fakeTID >> 16); + if (!ShinyUtil.GetIsShiny6(fakeTID, pid)) // battled + pid = ShinyUtil.GetShinyPID(tid, sid, pid, 0); + if (!ShinyUtil.GetIsShiny6(pk.ID32, pid)) // captured + pid = ShinyUtil.GetShinyPID(pk.TID16, pk.SID16, pid, ShinyUtil.GetShinyXor(pid, fakeTID) == 0 ? 0u : 1u); + } + else // Never + { + if (ShinyUtil.GetIsShiny6(fakeTID, pid)) // battled + pid ^= 0x1000_0000; + if (ShinyUtil.GetIsShiny6(pk.ID32, pid)) // captured + pid ^= 0x1000_0000; + } + return pid; + } + + private static bool IsMatchUnknownPreFillIVs(PKM pk, in GenerateParam9a enc, Xoroshiro128Plus rand) + { + int k = enc.FlawlessIVs; + if (k == 0) + return IsMatchIVsAndFollowing(pk, in enc, rand, 0); // none + if (k == 6) + return IsMatchIVsAndFollowing(pk, in enc, rand, (1 << 6) - 1); // all + + // Treat flawless IVs as a combination problem: choose k flawless IVs from 6 stats. + // Since we don't know the IVs that were filled before entering FixInitSpec, we must guess every combination. + // We can do this efficiently using Gosper's hack to iterate combinations. + // https://rosettacode.org/wiki/Gosper%27s_hack + // Each bit set in our combination represents a flawless IV. + + // Usually, only k flawless IVs will be present in the result entity. + // Only a small subset of combinations will be valid based on the flawless IVs we can observe from the result entity. + // This will allow us to skip checking the majority of combinations. + var permit = GetBitmaskFlawlessIVs(pk); + if (System.Numerics.BitOperations.PopCount((uint)permit) == k) + return IsMatchIVsAndFollowing(pk, in enc, rand, permit); // only one possible combination + + const int limit = 1 << 6; + var comb = (1 << k) - 1; // initial combination: k low bits set + + while (true) + { + // If the combination sets a flawless IV that is not flawless in the entity, skip it. + // comb is a valid number with k bits set + if ((comb & permit) == comb) + { + if (IsMatchIVsAndFollowing(pk, in enc, rand, comb)) + return true; + } + + // Gosper's hack to get the next combination with same popcount + int c = comb; + int u = c & -c; + int v = c + u; + if (v is >= limit or 0) + break; // no further n-bit combinations + comb = v + (((v ^ c) / u) >> 2); + } + + return false; + } + + private static int GetBitmaskFlawlessIVs(PKM pk) + { + int result = 0; + if (pk.IV_HP == MAX) + result |= 1 << 0; + if (pk.IV_ATK == MAX) + result |= 1 << 1; + if (pk.IV_DEF == MAX) + result |= 1 << 2; + if (pk.IV_SPA == MAX) + result |= 1 << 3; + if (pk.IV_SPD == MAX) + result |= 1 << 4; + if (pk.IV_SPE == MAX) + result |= 1 << 5; + return result; + } + + private static bool IsMatchIVsAndFollowing(PKM pk, in GenerateParam9a enc, Xoroshiro128Plus rand, int flawlessBits) + { + Span ivs = [UNSET, UNSET, UNSET, UNSET, UNSET, UNSET]; + for (int i = 0; i < 6; i++) + { + if ((flawlessBits & (1 << i)) != 0) + ivs[i] = MAX; + } + + return IsMatchIVsAndFollowing(pk, in enc, rand, ivs); + } + + public static byte GetGender(in byte ratio, in ulong rand100) => ratio switch + { + EntityGender.VM => rand100 < 12 ? (byte)1 : (byte)0, // 12.5% + EntityGender.MM => rand100 < 25 ? (byte)1 : (byte)0, // 25% + EntityGender.HH => rand100 < 50 ? (byte)1 : (byte)0, // 50% + EntityGender.MF => rand100 < 75 ? (byte)1 : (byte)0, // 75% + EntityGender.VF => rand100 < 89 ? (byte)1 : (byte)0, // 87.5% + + _ => throw new ArgumentOutOfRangeException(nameof(ratio), ratio, null), + }; +} diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseSolver.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseSolver.cs new file mode 100644 index 000000000..6b45e4f40 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseSolver.cs @@ -0,0 +1,260 @@ +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Threading.Tasks; +using System.Threading; + +namespace PKHeX.Core; + +/// +/// Finding the crypto-secure encounter seed for encounters. +/// +public static class LumioseSolver +{ + /// + /// Allow searching for shiny seeds when is and is with only 1 roll. + /// + /// + /// Recovery of seeds is too slow for realtime checks. Default is . + /// + public static bool SearchShiny1 { get; set; } + + /// + /// Allow searching for seeds when is more than 1 roll. + /// + /// + /// Recovery of seeds is extremely slow. Default is . + /// + public static bool SearchShinyN { get; set; } + + /// + /// Tries to get the that originated the . + /// + /// Generating parameters for FixInitSpec + /// Entity that was generated + /// Seed that was used to generate the entity. + /// if the seed was found, otherwise . + public static bool TryGetSeed(this in GenerateParam9a param, PKM pk, out ulong seed) + { + // Technically a rand() result of 0xFFFFFFFF for either EC/PID will double-roll, but we'll just ignore that case due to it being so rare. + + if (param.Shiny is Shiny.Random && pk.IsShiny) + { + if (param.RollCount == 1 && SearchShiny1) // O(131072) + return TryGetSeedShiny(param, pk, out seed); + if (SearchShinyN) // O(4,294,967,296) -- this will take a while. + return TryGetSeedNoPID(param, pk, out seed); + seed = 0; + return false; + } + + // Assume the PID is the first result; otherwise we would need to brute force the other unknown bits. + if (TryGetSeedRegular(param, pk, out seed)) + return true; + if (SearchShinyN && param.RollCount != 1) + return TryGetSeedNoPID(param, pk, out seed); + seed = 0; + return false; + } + + private static bool TryGetSeedRegular(in GenerateParam9a param, PKM pk, out ulong seed) + { + var ec = pk.EncryptionConstant; + var pid = pk.PID; + if (param.Correlation is LumioseCorrelation.SkipTrainer) + return TryGetSeedConsecutive(param, pk, ec, pid, out seed); + return TryGetSeedSkip(param, pk, ec, pid, out seed); + } + + private static bool TryGetSeedShiny(in GenerateParam9a param, PKM pk, out ulong seed) + { + if (param.Correlation is LumioseCorrelation.SkipTrainer) + return TryGetSeedConsecutiveShiny(param, pk, out seed); + return TryGetSeedSkipShiny(param, pk, out seed); + } + + private static bool TryGetSeedConsecutive(in GenerateParam9a param, PKM pk, uint ec, uint pid, out ulong seed) + { + var solver = new XoroMachineConsecutive(ec, pid); + return TryGetSeed(param, pk, solver, out seed); + } + + private static bool TryGetSeedSkip(in GenerateParam9a param, PKM pk, uint ec, uint pid, out ulong seed) + { + var solver = new XoroMachineSkip(ec, pid); + return TryGetSeed(param, pk, solver, out seed); + } + + private static bool TryGetSeed(in GenerateParam9a param, PKM pk, T solver, out ulong seed) where T : struct, IEnumerator + { + while (solver.MoveNext()) + { + seed = solver.Current; + if (LumioseRNG.Verify(pk, param, seed)) + return true; + } + seed = 0; + return false; + } + + private static bool TryGetSeedConsecutiveShiny(in GenerateParam9a param, PKM pk, out ulong seed) + { + var ec = pk.EncryptionConstant; + var partial = pk.PID & 0x0000_FFF0; + var p = param; // copy to avoid capturing an in-parameter in lambdas + + // Parallelize over ranges of the high 16 bits. Each high value iterates the 16 low-nibble variants. + const int highMaxExclusive = 0x1_0000; // 0..65535 inclusive + // Batch a reasonable amount of highs per task to avoid tiny work-items. 2048 highs => 32768 PID attempts per task. + const int highBatchSize = 2048; + + var rangePartitioner = Partitioner.Create(0, highMaxExclusive, highBatchSize); + + ulong resultSeed = 0; + bool found = false; + Lock gate = new(); + + Parallel.ForEach(rangePartitioner, (range, state) => + { + if (Volatile.Read(ref found)) { state.Stop(); return; } + + for (int highStart = range.Item1; highStart < range.Item2; highStart++) + { + if (Volatile.Read(ref found)) { state.Stop(); return; } + + uint high = (uint)highStart << 16; + var pid = high | partial; + // Try all 16 low-nibble permutations + do + { + if (TryGetSeedConsecutive(p, pk, ec, pid, out var s)) + { + lock (gate) + { + if (!found) + { + resultSeed = s; + found = true; + } + } + state.Stop(); + return; + } + } while ((++pid & 0xF) != 0); // stop on low reset + } + }); + + seed = resultSeed; + return found; + } + + private static bool TryGetSeedSkipShiny(in GenerateParam9a param, PKM pk, out ulong seed) + { + var ec = pk.EncryptionConstant; + var partial = pk.PID & 0x0000_FFF0; + var p = param; + + const int highMaxExclusive = 0x1_0000; // 0..65535 inclusive + const int highBatchSize = 2048; // keep work units chunky + + var rangePartitioner = Partitioner.Create(0, highMaxExclusive, highBatchSize); + + ulong resultSeed = 0; + bool found = false; + Lock gate = new(); + + Parallel.ForEach(rangePartitioner, (range, state) => + { + if (Volatile.Read(ref found)) { state.Stop(); return; } + + for (int highStart = range.Item1; highStart < range.Item2; highStart++) + { + if (Volatile.Read(ref found)) { state.Stop(); return; } + + uint high = (uint)highStart << 16; + var pid = high | partial; + do + { + if (!TryGetSeedSkip(p, pk, ec, pid, out var s)) + continue; + + lock (gate) + { + if (!found) + { + resultSeed = s; + found = true; + } + } + state.Stop(); + return; + } while ((++pid & 0xF) != 0); // stop on low reset + } + }); + + seed = resultSeed; + return found; + } + + private static bool TryGetSeedNoPID(in GenerateParam9a param, PKM pk, out ulong seed) + { + // Abuse the fact that EC is the first result from the rand() output, and gives away 32-bits of the seed. + // We then only need to guess the high 32-bits of the seed, and can brute-force over that space. + var ec = pk.EncryptionConstant; + var p = param; + + // 32-bit PID space: 0..uint.MaxValue inclusive. Chunk into large ranges for better throughput. + const ulong total = uint.MaxValue + 1UL; + // Use a large batch size to reduce scheduling overhead; ~16M PIDs per work item. + const ulong batch = 1UL << 24; // 16,777,216 + + var partitions = CreateULongRangePartitions(total, batch); + + ulong resultSeed = 0; + bool found = false; + Lock gate = new(); + ulong partial = ec - unchecked((uint)Xoroshiro128Plus.XOROSHIRO_CONST); + + Parallel.ForEach(partitions, (range, state) => + { + if (Volatile.Read(ref found)) { state.Stop(); return; } + + uint start = (uint)range.start; + uint endExclusive = (uint)range.end; // safe due to batching within 0..2^32 + + for (ulong high = start; high < endExclusive; high++) + { + if (Volatile.Read(ref found)) { state.Stop(); return; } + + var s = (high << 32) | partial; + if (!LumioseRNG.Verify(pk, p, s)) + continue; + + lock (gate) + { + if (!found) + { + resultSeed = s; + found = true; + } + } + state.Stop(); + return; + } + }); + + seed = resultSeed; + return found; + } + + // Helper to build large range partitions for ulong-sized spaces, but kept within int-counted chunks for Parallel.ForEach. + private static IEnumerable<(ulong start, ulong end)> CreateULongRangePartitions(ulong totalCount, ulong batchSize) + { + for (ulong start = 0; start < totalCount; start += batchSize) + { + ulong end = start + batchSize; + if (end > totalCount) + end = totalCount; + yield return (start, end); + } + } +} diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/SlotType9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/SlotType9a.cs new file mode 100644 index 000000000..80bd90426 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/SlotType9a.cs @@ -0,0 +1,6 @@ +namespace PKHeX.Core; + +public enum SlotType9a : byte +{ + Standard = 0, +} diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs index d7ecf8969..2ed0ec482 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs @@ -13,7 +13,13 @@ public sealed class EvolutionGroupHOME : IEvolutionGroup private static readonly EvolutionEnvironment8b BDSP = new(); private static readonly EvolutionEnvironment9 SV = new(); - public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => null; + public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) + { + return null; // TODO HOME ZA2: Re-enable when we have more info. + // if (pk.Format <= 9 && pk.Context is not EntityContext.Gen9a) + // return null; + // return EvolutionGroupHOME.Instance; + } public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) { @@ -297,3 +303,4 @@ public sealed class EvolutionEnvironment9 : IEvolutionEnvironment public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm => Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } + diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME2.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME2.cs new file mode 100644 index 000000000..7a01d4d43 --- /dev/null +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME2.cs @@ -0,0 +1,206 @@ +using System; +using System.Runtime.CompilerServices; +using static PKHeX.Core.EvolutionUtil; +using static PKHeX.Core.Species; + +namespace PKHeX.Core; + +public sealed class EvolutionGroupHOME2 : IEvolutionGroup +{ + public static readonly EvolutionGroupHOME2 Instance = new(); + + private static readonly EvolutionEnvironment9a ZA = new(); + + public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => null; + + public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) + { + return null; // TODO HOME ZA2: Re-enable when we have more info. + // if (enc.Generation > 9 || enc.Context is EntityContext.Gen9a) + // return null; + // return EvolutionGroupHOME.Instance; + } + + public void DiscardForOrigin(Span result, PKM pk, EvolutionOrigin enc) + { + if (pk.ZA) + { + if (enc.Options.HasFlag(OriginOptions.SkipChecks)) + Discard(result, PersonalTable.ZA); + else + Discard(result, PersonalTable.ZA, pk.Ability, pk.AbilityNumber >> 1); + } + + if (GetPrevious(pk, enc) is { } prev) + prev.DiscardForOrigin(result, pk, enc); + } + + /// + /// Checks if we should check all adjacent evolution sources in addition to the current one. + /// + /// True if we should check all adjacent evolution sources. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool CheckAllAdjacent(PKM pk, EvolutionOrigin enc) => enc.SkipChecks || pk is IHomeTrack { HasTracker: true } || !ParseSettings.IgnoreTransferIfNoTracker; + + public int Devolve(Span result, PKM pk, EvolutionOrigin enc) + { + if (CheckAllAdjacent(pk, enc)) + return DevolveMulti(result, pk, enc); + return DevolveSingle(result, pk, enc); + } + + public int Evolve(Span result, PKM pk, EvolutionOrigin enc, EvolutionHistory history) + { + if (IsUnavailableEvoChain(pk.Species, pk.Form)) + result = result[..1]; // Only allow the highest (current). + if (CheckAllAdjacent(pk, enc)) + return EvolveMulti(result, pk, enc, history); + return EvolveSingle(result, pk, enc, history); + } + + private static bool IsUnavailableEvoChain(ushort species, byte form) => species switch + { + // TODO DLC ZA: ALT Evolutions + // Split-evolution Alolans can't be reached in any game Gen8+. Must have been via Gen7. + (int)Raichu when form == 1 => true, + (int)Exeggutor when form == 1 => true, + (int)Marowak when form == 1 => true, + _ => false, + }; + + private int DevolveMulti(Span result, PKM pk, in EvolutionOrigin enc) + { + int present = 1; + for (int i = 1; i < result.Length; i++) + { + ref var prev = ref result[i - 1]; + RevertMutatedForms(ref prev); + ref var reference = ref result[i]; + + bool devolvedAny = false; + if (ZA.TryDevolve(prev, pk, prev.LevelMax, enc.LevelMin, enc.SkipChecks, out var evo)) + devolvedAny = UpdateIfBetter(ref reference, evo); + + if (devolvedAny) + present++; + + static bool UpdateIfBetter(ref EvoCriteria reference, in EvoCriteria evo) + { + if (evo.IsBetterDevolution(reference)) + reference = evo; + return true; + } + } + + return present; + } + + private int EvolveMulti(Span result, PKM pk, in EvolutionOrigin enc, EvolutionHistory history) + { + int present = 1; + for (int i = result.Length - 1; i >= 1; i--) + { + ref var dest = ref result[i - 1]; + var devolved = result[i]; + + bool devolvedAny = false; + if (ZA.TryEvolve(devolved, dest, pk, enc.LevelMax, devolved.LevelMin, enc.SkipChecks, out var evo)) + devolvedAny = UpdateIfBetter(ref dest, evo); + + if (devolvedAny) + present++; + else if (dest.Method == EvoCriteria.SentinelNotReached) + break; // Don't continue for higher evolutions. + + static bool UpdateIfBetter(ref EvoCriteria reference, in EvoCriteria evo) + { + if (evo.IsBetterEvolution(reference)) + reference = evo; + return true; + } + } + + history.Gen9a = SetHistory(result, PersonalTable.ZA); + + return present; + } + + private static int DevolveSingle(Span result, PKM pk, in EvolutionOrigin enc) + { + int present = 1; + var env = GetSingleEnv(pk); + for (int i = 1; i < result.Length; i++) + { + ref var prev = ref result[i - 1]; + RevertMutatedForms(ref prev); + if (!env.TryDevolve(prev, pk, prev.LevelMax, enc.LevelMin, enc.SkipChecks, out var evo)) + continue; + + ref var reference = ref result[i]; + if (evo.IsBetterDevolution(reference)) + reference = evo; + present++; + } + + return present; + } + + private static void RevertMutatedForms(ref EvoCriteria evo) + { + var (species, form) = (evo.Species, evo.Form); + // Eager check: only reversions are if form is not 0. + if (form == 0) + return; + // TODO DLC ZA: Is this necessary? + //if (species is (ushort)Dialga or (ushort)Palkia or (ushort)Arceus or (ushort)Silvally) + // evo = evo with { Form = 0 }; // Normal + if (FormInfo.IsBattleOnlyForm(species, form, Latest.Generation)) + evo = evo with { Form = FormInfo.GetOutOfBattleForm(species, form, Latest.Generation) }; + } + + private int EvolveSingle(Span result, PKM pk, in EvolutionOrigin enc, EvolutionHistory history) + { + int present = 1; + var env = GetSingleEnv(pk); + for (int i = result.Length - 1; i >= 1; i--) + { + ref var dest = ref result[i - 1]; + var devolved = result[i]; + if (!env.TryEvolve(devolved, dest, pk, enc.LevelMax, devolved.LevelMin, enc.SkipChecks, out var evo)) + { + if (dest.Method == EvoCriteria.SentinelNotReached) + break; // Don't continue for higher evolutions. + continue; + } + + if (evo.IsBetterEvolution(dest)) + dest = evo; + present++; + } + + if (pk is PA9) history.Gen9a = SetHistory(result, PersonalTable.ZA); + + return present; + } + + private static IEvolutionEnvironment GetSingleEnv(PKM pk) => pk switch + { + PA9 => ZA, + _ => throw new ArgumentOutOfRangeException(nameof(pk), pk, null), + }; +} + +/// +/// Evolution environment for . +/// +public sealed class EvolutionEnvironment9a : IEvolutionEnvironment +{ + private static readonly EvolutionTree Tree = EvolutionTree.Evolves9a; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Level100; + + public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm + => Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); + + public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm + => Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); +} diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupUtil.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupUtil.cs index ba45779c1..6a5935aa9 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupUtil.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupUtil.cs @@ -1,3 +1,4 @@ +using System; using static PKHeX.Core.EntityContext; namespace PKHeX.Core; @@ -21,6 +22,9 @@ public static class EvolutionGroupUtil Gen7 => EvolutionGroup7.Instance, Gen7b => EvolutionGroup7b.Instance, - _ => EvolutionGroupHOME.Instance, + Gen8 or Gen8a or Gen8b or Gen9 => EvolutionGroupHOME.Instance, + Gen9a => EvolutionGroupHOME2.Instance, + + _ => throw new ArgumentOutOfRangeException(nameof(context), context, null), }; } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionUtil.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionUtil.cs index ebbd35d4b..092d3861e 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionUtil.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionUtil.cs @@ -63,6 +63,46 @@ private static EvoCriteria[] GetLocalEvolutionArray(Span result) continue; ShiftDown(result[i..]); + i--; // re-check this index + } + } + + public static void Discard(Span result, T pt, int ability, int abilityIndex) where T : IPersonalTable + { + Discard(result, pt); + + // Additionally, discard any that have abilities that don't match. + // Birth ability should match. + uint indexes = 0u; + for (int i = 0; i < result.Length; i++) + { + var evo = result[i]; + if (evo.Species == 0) + break; + if (pt.IsPresentInGame(evo.Species, evo.Form)) + continue; + + var pi = pt.GetFormEntry(evo.Species, evo.Form); + var evoAbility = pi.GetAbilityAtIndex(abilityIndex); + if (evoAbility == ability) + continue; // OK + + indexes |= 1u << i; // mark for removal + } + + if (indexes == 0 || indexes == (1u << result.Length) - 1) + return; // nothing to remove, or everything to remove + + for (int i = 0; i < result.Length; i++) + { + if ((indexes & 1u) == 0u) + { + indexes >>= 1; + continue; // keep + } + ShiftDown(result[i..]); + indexes >>= 1; + i--; // re-check this index } } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionHistory.cs b/PKHeX.Core/Legality/Evolutions/EvolutionHistory.cs index cb51e5ca7..b4c80ed04 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionHistory.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionHistory.cs @@ -22,6 +22,7 @@ public sealed class EvolutionHistory public EvoCriteria[] Gen7b = NONE; public EvoCriteria[] Gen8a = NONE; public EvoCriteria[] Gen8b = NONE; + public EvoCriteria[] Gen9a = NONE; public bool HasVisitedGen1 => Gen1.Length != 0; public bool HasVisitedGen2 => Gen2.Length != 0; @@ -36,6 +37,7 @@ public sealed class EvolutionHistory public bool HasVisitedLGPE => Gen7b.Length != 0; public bool HasVisitedPLA => Gen8a.Length != 0; public bool HasVisitedBDSP => Gen8b.Length != 0; + public bool HasVisitedZA => Gen9a.Length != 0; public ReadOnlySpan Get(EntityContext context) => context switch { @@ -52,6 +54,7 @@ public sealed class EvolutionHistory EntityContext.Gen7b => Gen7b, EntityContext.Gen8a => Gen8a, EntityContext.Gen8b => Gen8b, + EntityContext.Gen9a => Gen9a, _ => throw new ArgumentOutOfRangeException(nameof(context), context, null), }; diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs b/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs index 7c0f6f869..bf21dae7f 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs @@ -25,6 +25,7 @@ public sealed class EvolutionTree : EvolutionNetwork public static readonly EvolutionTree Evolves8a = GetViaPersonal(PersonalTable.LA, Get("la", "la"u8, 0)); public static readonly EvolutionTree Evolves8b = GetViaPersonal(PersonalTable.BDSP, Get("bs", "bs"u8)); public static readonly EvolutionTree Evolves9 = GetViaPersonal(PersonalTable.SV, Get("sv", "sv"u8)); + public static readonly EvolutionTree Evolves9a = GetViaPersonal(PersonalTable.ZA, Get("za", "za"u8, 0)); private static EvolutionMethod[][] Get([ConstantExpected] string resource, [Length(2, 2)] ReadOnlySpan identifier, [ConstantExpected] byte levelUp = 1) { @@ -68,6 +69,7 @@ private static EvolutionTree GetViaPersonal(IPersonalTable t, EvolutionMethod[][ EntityContext.Gen7b => Evolves7b, EntityContext.Gen8a => Evolves8a, EntityContext.Gen8b => Evolves8b, + EntityContext.Gen9a => Evolves9a, _ => throw new ArgumentOutOfRangeException(nameof(context), context, null), }; } diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9a.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9a.cs new file mode 100644 index 000000000..104b9d7bc --- /dev/null +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9a.cs @@ -0,0 +1,126 @@ +using System; + +namespace PKHeX.Core; + +/// +/// Group that checks the source of a move in . +/// +public sealed class LearnGroup9a : ILearnGroup +{ + public static readonly LearnGroup9a Instance = new(); + private const byte Generation = 9; + private const EntityContext Context = EntityContext.Gen9a; + public ushort MaxMoveID => Legal.MaxMoveID_9a; + + public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => null; + public bool HasVisited(PKM pk, EvolutionHistory history) => history.HasVisitedZA; + + public bool Check(Span result, ReadOnlySpan current, PKM pk, EvolutionHistory history, + IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) + { + var evos = history.Gen9a; + if (evos.Length == 0) + return false; + + for (var i = 0; i < evos.Length; i++) + Check(result, current, pk, evos[i], i); + + if (MoveResult.AllParsed(result)) + return true; + + var home = LearnGroupHOME.Instance; + if (option != LearnOption.HOME && home.HasVisited(pk, history)) + return home.Check(result, current, pk, history, enc, types); + return false; + } + + private static void Check(Span result, ReadOnlySpan current, PKM pk, EvoCriteria evo, int stage, MoveSourceType type = MoveSourceType.All, LearnOption option = LearnOption.Current) + { + if (!FormChangeUtil.ShouldIterateForms(evo.Species, evo.Form, Generation, option)) + { + CheckInternal(result, current, pk, evo, stage, type, option); + return; + } + + // Check all forms + var inst = LearnSource9ZA.Instance; + if (!inst.TryGetPersonal(evo.Species, evo.Form, out var pi)) + return; + + var fc = pi.FormCount; + for (int i = 0; i < fc; i++) + CheckInternal(result, current, pk, evo with { Form = (byte)i }, stage, i == 0 ? type : type & MoveSourceType.LevelUp, option); + } + + private static void CheckInternal(Span result, ReadOnlySpan current, PKM pk, EvoCriteria evo, int stage, MoveSourceType type, LearnOption option) + { + var game = LearnSource9ZA.Instance; + if (!game.TryGetPersonal(evo.Species, evo.Form, out var pi)) + return; + + for (int i = result.Length - 1; i >= 0; i--) + { + if (result[i].Valid) + continue; + + var move = current[i]; + var chk = game.GetCanLearn(pk, pi, evo, move, type, option); + if (chk != default) + result[i] = new(chk, (byte)stage, Generation); + } + } + + public void GetAllMoves(Span result, PKM pk, EvolutionHistory history, IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) + { + if (types.HasFlag(MoveSourceType.Encounter) && enc.Context == Context) + FlagEncounterMoves(enc, result); + + foreach (var evo in history.Gen9a) + GetAllMoves(result, pk, evo, types, option); + + var home = LearnGroupHOME.Instance; + if (option != LearnOption.HOME && home.HasVisited(pk, history)) + home.GetAllMoves(result, pk, history, enc, types); + } + + private static void GetAllMoves(Span result, PKM pk, EvoCriteria evo, MoveSourceType types, LearnOption option) + { + if (!FormChangeUtil.ShouldIterateForms(evo.Species, evo.Form, Generation, option)) + { + GetAllMovesInternal(result, pk, evo, types); + return; + } + + // Check all forms + var inst = LearnSource9ZA.Instance; + if (!inst.TryGetPersonal(evo.Species, evo.Form, out var pi)) + return; + + var fc = pi.FormCount; + for (int i = 0; i < fc; i++) + GetAllMovesInternal(result, pk, evo with { Form = (byte)i }, i == 0 ? types : types & MoveSourceType.LevelUp); + } + + private static void GetAllMovesInternal(Span result, PKM pk, EvoCriteria evo, MoveSourceType types) + { + LearnSource9ZA.Instance.GetAllMoves(result, pk, evo, types); + } + + private static void FlagEncounterMoves(IEncounterTemplate enc, Span result) + { + if (enc is IMoveset { Moves: { HasMoves: true } x }) + { + result[x.Move4] = true; + result[x.Move3] = true; + result[x.Move2] = true; + result[x.Move1] = true; + } + if (enc is IRelearn { Relearn: { HasMoves: true } r }) + { + result[r.Move4] = true; + result[r.Move3] = true; + result[r.Move2] = true; + result[r.Move1] = true; + } + } +} diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroupHOME.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroupHOME.cs index 8f15593cf..a8fb22fd4 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroupHOME.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroupHOME.cs @@ -33,6 +33,13 @@ public sealed class LearnGroupHOME : ILearnGroup if (CleanPurge(result, current, pk, types, local, evos)) return true; } + if (history.HasVisitedZA && pk is not PA9) + { + var instance = LearnGroup9a.Instance; + instance.Check(result, current, pk, history, enc, types, option); + if (CleanPurge(result, current, pk, types, local, evos)) + return true; + } if (history.HasVisitedSWSH && pk is not PK8) { var instance = LearnGroup8.Instance; @@ -153,6 +160,8 @@ private static bool CleanPurge(Span result, ReadOnlySpan cur // Check all adjacent games if (history.HasVisitedGen9 && pk is not PK9) RentLoopGetAll(LearnGroup9. Instance, result, pk, history, enc, types, option, evos, local); + if (history.HasVisitedZA && pk is not PA9) + RentLoopGetAll(LearnGroup9a.Instance, result, pk, history, enc, types, option, evos, local); if (history.HasVisitedSWSH && pk is not PK8) RentLoopGetAll(LearnGroup8. Instance, result, pk, history, enc, types, option, evos, local); if (history.HasVisitedPLA && pk is not PA8) @@ -253,6 +262,7 @@ private static void AddExclusiveMoves(Span result, PKM pk) EntityContext.Gen8a => LearnSource8LA.Instance, EntityContext.Gen8b => LearnSource8BDSP.Instance, EntityContext.Gen9 => LearnSource9SV.Instance, + EntityContext.Gen9a => LearnSource9ZA.Instance, _ => throw new ArgumentOutOfRangeException(nameof(context), context, null), }; diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroupUtil.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroupUtil.cs index c95a72a00..856443ac5 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroupUtil.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroupUtil.cs @@ -33,6 +33,7 @@ public static class LearnGroupUtil Gen7b => LearnGroup7b.Instance, Gen8a => LearnGroup8a.Instance, Gen8b => LearnGroup8b.Instance, + Gen9a => LearnGroup9a.Instance, _ => throw new ArgumentOutOfRangeException(nameof(context), context, null), }; diff --git a/PKHeX.Core/Legality/LearnSource/LearnEnvironment.cs b/PKHeX.Core/Legality/LearnSource/LearnEnvironment.cs index a49c4accf..c919bf4e0 100644 --- a/PKHeX.Core/Legality/LearnSource/LearnEnvironment.cs +++ b/PKHeX.Core/Legality/LearnSource/LearnEnvironment.cs @@ -24,7 +24,7 @@ public enum LearnEnvironment : byte /* Gen6 */ XY, ORAS, /* Gen7 */ SM, USUM, GG, /* Gen8 */ SWSH, BDSP, PLA, - /* Gen9 */ SV, + /* Gen9 */ SV, ZA, HOME, } @@ -51,7 +51,7 @@ public static class LearnEnvironmentExtensions XY or ORAS => 6, SM or USUM or GG => 7, SWSH or BDSP or PLA => 8, - SV => 9, + SV or ZA => 9, _ => 0, }; @@ -72,6 +72,7 @@ public static class LearnEnvironmentExtensions PLA => history.Gen8a, BDSP => history.Gen8b, SV => history.Gen9, + ZA => history.Gen9a, _ => [], }; } diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource9ZA.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource9ZA.cs new file mode 100644 index 000000000..4c3394731 --- /dev/null +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource9ZA.cs @@ -0,0 +1,105 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using static PKHeX.Core.LearnMethod; +using static PKHeX.Core.LearnEnvironment; + +namespace PKHeX.Core; + +/// +/// Exposes information about how moves are learned in . +/// +public sealed class LearnSource9ZA : ILearnSource, IHomeSource, ILearnSourceBonus +{ + public static readonly LearnSource9ZA Instance = new(); + private static readonly PersonalTable9ZA Personal = PersonalTable.ZA; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor16.Get(Util.GetBinaryResource("lvlmove_za.pkl"), "za"u8)); + private static readonly Learnset[] PlusLevels = LearnsetReader.GetArray(BinLinkerAccessor16.Get(Util.GetBinaryResource("plus_za.pkl"), "za"u8)); + private const int MaxSpecies = Legal.MaxSpeciesID_9a; + private const LearnEnvironment Game = ZA; + + public Learnset GetLearnset(ushort species, byte form) => Learnsets[Personal.GetFormIndex(species, form)]; + + public static (Learnset Learn, Learnset Plus) GetLearnsetAndPlus(ushort species, byte form) + { + var index = Personal.GetFormIndex(species, form); + return (Learnsets[index], PlusLevels[index]); + } + + public (Learnset Learn, Learnset Other) GetLearnsetAndOther(ushort species, byte form) + { + var index = Personal.GetFormIndex(species, form); + return (Learnsets[index], PlusLevels[index]); + } + + public bool TryGetPersonal(ushort species, byte form, [NotNullWhen(true)] out PersonalInfo9ZA? pi) + { + pi = null; + if (species > MaxSpecies) + return false; + pi = Personal[species, form]; + return true; + } + + public MoveLearnInfo GetCanLearn(PKM pk, PersonalInfo9ZA pi, EvoCriteria evo, ushort move, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) + { + if (types.HasFlag(MoveSourceType.LevelUp)) + { + var learn = GetLearnset(evo.Species, evo.Form); + if (learn.TryGetLevelLearnMove(move, out var level) && level <= evo.LevelMax) + return new(LevelUp, Game, (byte)level); + } + + if (types.HasFlag(MoveSourceType.Machine) && GetIsTM(pi, pk, move, option)) + return new(TMHM, Game); + + return default; + } + + private static bool GetIsTM(PersonalInfo9ZA info, PKM pk, ushort move, LearnOption option) + { + int index = PersonalInfo9ZA.MachineMoves.IndexOf(move); + if (index == -1) + return false; + if (!info.GetIsLearnTM(index)) + return false; + + // Can just use the TM at any time. Does not set record flag. + return true; + } + + public void GetAllMoves(Span result, PKM pk, EvoCriteria evo, MoveSourceType types = MoveSourceType.All) + { + if (!TryGetPersonal(evo.Species, evo.Form, out var pi)) + return; + + if (types.HasFlag(MoveSourceType.LevelUp)) + { + var learn = GetLearnset(evo.Species, evo.Form); + var span = learn.GetMoveRange(evo.LevelMax); + foreach (var move in span) + result[move] = true; + } + + if (types.HasFlag(MoveSourceType.Machine)) + pi.SetAllLearnTM(result); + } + + public LearnEnvironment Environment => Game; + + public MoveLearnInfo GetCanLearnHOME(PKM pk, EvoCriteria evo, ushort move, MoveSourceType types = MoveSourceType.All) + { + var pi = Personal[evo.Species, evo.Form]; + + if (types.HasFlag(MoveSourceType.LevelUp)) + { + var learn = GetLearnset(evo.Species, evo.Form); + if (learn.TryGetLevelLearnMove(move, out var level)) + return new(LevelUp, Game, level); + } + + if (types.HasFlag(MoveSourceType.Machine) && GetIsTM(pi, pk, move, LearnOption.HOME)) + return new(TMHM, Game); + + return default; + } +} diff --git a/PKHeX.Core/Legality/LearnSource/Verify/LearnVerifier.cs b/PKHeX.Core/Legality/LearnSource/Verify/LearnVerifier.cs index e9a778d81..42fac202e 100644 --- a/PKHeX.Core/Legality/LearnSource/Verify/LearnVerifier.cs +++ b/PKHeX.Core/Legality/LearnSource/Verify/LearnVerifier.cs @@ -21,6 +21,16 @@ public static void Verify(Span result, PKM pk, IEncounterTemplate en // Finalize the checks. Finalize(result, current); + + // If Empty slots are allowed, revert flagging. + if (pk.Context is EntityContext.Gen9a && current.ContainsAnyExcept(0)) + { + foreach (ref var x in result) + { + if (x.Info.Method is LearnMethod.EmptyInvalid) + x = MoveResult.Empty; + } + } } private static void VerifyMoves(Span result, ReadOnlySpan current, PKM pk, IEncounterTemplate enc, EvolutionHistory history) diff --git a/PKHeX.Core/Legality/Learnset/Learnset.cs b/PKHeX.Core/Legality/Learnset/Learnset.cs index 6d7e1321e..888a4d03d 100644 --- a/PKHeX.Core/Legality/Learnset/Learnset.cs +++ b/PKHeX.Core/Legality/Learnset/Learnset.cs @@ -20,6 +20,7 @@ public sealed class Learnset(ushort[] Moves, byte[] Levels) private const byte MagicEvolutionMoveLevel = 0; public ReadOnlySpan GetAllMoves() => Moves; + public ReadOnlySpan GetAllLevels() => Levels; public ReadOnlySpan GetMoveRange(byte maxLevel, byte minLevel = 0) { @@ -115,8 +116,9 @@ private static void RectifyOrderShift(Span moves, int ctr) } } - public void SetEncounterMovesBackwards(byte level, Span moves, int ctr = 0) + public void SetEncounterMovesBackwards(byte level, Span moves, int ctr = 0, bool sameDescend = true) { + // sameDescend makes it work like a push-queue in reverse int index = FindLastLeq(level); while (true) @@ -126,8 +128,12 @@ public void SetEncounterMovesBackwards(byte level, Span moves, int ctr = // In the event we have multiple moves at the same level, insert them in regular descending order. int start = index; - while (start != 0 && Levels[start] == Levels[start - 1]) - start--; + + if (sameDescend) + { + while(start != 0 && Levels[start] == Levels[start - 1]) + start--; + } for (int i = start; i <= index; i++) { diff --git a/PKHeX.Core/Legality/Legal.cs b/PKHeX.Core/Legality/Legal.cs index 8b9419583..9b682f3dd 100644 --- a/PKHeX.Core/Legality/Legal.cs +++ b/PKHeX.Core/Legality/Legal.cs @@ -104,14 +104,12 @@ public static class Legal internal const int MaxMoveID_8a = (int)Move.TakeHeart; internal const int MaxItemID_8a = 1828; // Legend Plate internal const int MaxBallID_8a = (int)Ball.LAOrigin; - //internal const GameVersion MaxGameID_8a = GameVersion.SP; internal const int MaxAbilityID_8a = MaxAbilityID_8_R2; internal const int MaxSpeciesID_8b = MaxSpeciesID_4; // Arceus-493 internal const int MaxMoveID_8b = MaxMoveID_8_R2; internal const int MaxItemID_8b = 1822; // DS Sounds internal const int MaxBallID_8b = (int)Ball.LAOrigin; - //internal const GameVersion MaxGameID_8b = GameVersion.SP; internal const int MaxAbilityID_8b = MaxAbilityID_8_R2; internal const ushort MaxSpeciesID_9 = MaxSpeciesID_9_T2; @@ -134,9 +132,15 @@ public static class Legal internal const ushort MaxItemID_9_T2 = 2557; // Briar’s Book internal const ushort MaxAbilityID_9_T2 = (int)Ability.PoisonPuppeteer; + internal const int MaxSpeciesID_9a = (int)Species.Falinks; + internal const int MaxMoveID_9a = (int)Move.NihilLight; + internal const int MaxItemID_9a = 2634; // Blue Canari Plush + internal const int MaxAbilityID_9a = (int)Ability.PoisonPuppeteer; + internal const int MaxBallID_9a = (int)Ball.LAOrigin; + internal const int MaxBallID_9 = (int)Ball.LAOrigin; - internal const GameVersion MaxGameID_9 = GameVersion.VL; - internal const GameVersion MaxGameID_HOME = MaxGameID_9; + internal const GameVersion MaxGameID_HOME = GameVersion.VL; // TODO HOME ZA - Replace with ZA when HOME; if backwards transfer is allowed. If prevented, rename epoch as HOME1. + internal const GameVersion MaxGameID_HOME2 = GameVersion.ZA; internal static readonly ushort[] HeldItems_GSC = ItemStorage2.GetAllHeld(); internal static readonly ushort[] HeldItems_RS = ItemStorage3RS.GetAllHeld(); @@ -153,8 +157,9 @@ public static class Legal internal static readonly ushort[] HeldItems_BS = ItemStorage8BDSP.GetAllHeld(); internal static readonly ushort[] HeldItems_LA = []; internal static readonly ushort[] HeldItems_SV = ItemStorage9SV.GetAllHeld(); + internal static readonly ushort[] HeldItems_ZA = ItemStorage9ZA.GetAllHeld(); - internal static int GetMaxLanguageID(byte generation) => generation switch + internal static int GetMaxLanguageID(byte generation, EntityContext context) => generation switch { 1 => (int) LanguageID.Spanish, // 1-7 except 6 3 => (int) LanguageID.Spanish, // 1-7 except 6 @@ -164,7 +169,7 @@ public static class Legal 6 => (int) LanguageID.Korean, 7 => (int) LanguageID.ChineseT, 8 => (int) LanguageID.ChineseT, - 9 => (int) LanguageID.ChineseT, + 9 => (int) (context == EntityContext.Gen9a ? LanguageID.SpanishL : LanguageID.ChineseT), _ => -1, }; @@ -179,6 +184,7 @@ public static class Legal PB8 pb8 => !pb8.BDSP, PK8 pk8 => pk8.IsSideTransfer || pk8.BattleVersion != 0, PK9 pk9 => !(pk9.SV || pk9 is { IsEgg: true, Version: 0 }), + PA9 pa9 => !pa9.ZA, _ => false, }; @@ -186,10 +192,14 @@ public static class Legal /// Indicates if PP Ups are available for use. /// /// Entity to check - public static bool IsPPUpAvailable(PKM pk) - { - return pk is not PA8; - } + public static bool IsPPUpAvailable(PKM pk) => pk is not (PA8 or PA9); + + /// + /// Indicates if PP is never used in-game and should always be default values. + /// + /// Entity to check + /// if PP is never used; otherwise, . + public static bool IsPPUnused(PKM pk) => pk is (PA9); /// /// Indicate if PP Ups are available for use. diff --git a/PKHeX.Core/Legality/Localization/LegalityCheckLocalization.cs b/PKHeX.Core/Legality/Localization/LegalityCheckLocalization.cs index 1855c267c..03d19ec44 100644 --- a/PKHeX.Core/Legality/Localization/LegalityCheckLocalization.cs +++ b/PKHeX.Core/Legality/Localization/LegalityCheckLocalization.cs @@ -338,6 +338,12 @@ public sealed class LegalityCheckLocalization public string PIDTypeMismatch { get; set; } = "PID+ correlation does not match what was expected for the Encounter's type."; public string PIDZero { get; set; } = "PID is not set."; + public string PlusMoveAlphaMissing_0 { get; set; } = "Expected to have mastered the move {0} when encountered as an alpha."; + public string PlusMoveMultipleInvalid { get; set; } = "Multiple Plus Move flags are invalid."; + public string PlusMoveInvalid_0 { get; set; } = "{0} cannot be learned and set as a Plus Move."; + public string PlusMoveSufficientLevelMissing_0 { get; set; } = "Plus Move flag for {0} must be set."; // as the Pokémon's current level is above the level it becomes available for use as a Plus Move. + public string PlusMoveCountInvalid { get; set; } = "Out of range Plus Move flag index is set."; + public string PokerusDaysTooHigh_0 { get; set; } = "Pokérus Days Remaining value is too high; expected <= {0}."; public string PokerusStrainUnobtainable_0 { get; set; } = "Pokérus Strain {0} cannot be obtained."; @@ -447,6 +453,12 @@ public sealed class LegalityCheckLocalization public string BulkDuplicateMysteryGiftEggReceived { get; set; } = "Detected multiple redemptions of the same non-repeatable Mystery Gift Egg."; public string BulkSharingTrainerID { get; set; } = "Detected sharing of Trainer ID across multiple trainer names."; public string BulkSharingTrainerVersion { get; set; } = "Detected sharing of Trainer ID across multiple versions."; + public string BulkDuplicateFusionSlot { get; set; } = "Detected multiple fusions of the same fusion stored slot species."; + public string BulkDuplicateMegaStoneSlot { get; set; } = "Detected multiple Pokémon holding the same Mega Stone."; + public string BulkDuplicateMegaStoneInventory { get; set; } = "Detected Pokémon holding a Mega Stone still stored in player inventory."; + public string BulkNotAcquiredMegaStoneInventory { get; set; } = "Mega Stone held by Pokémon has not been acquired in player inventory."; + public string BulkAssignedMegaStoneNotFound_0 { get; set; } = "{0} is marked as held by Pokémon but none found in slots checked."; + public string BulkFusionSourceInvalid { get; set; } = "The consumed Species-Form stored in the save file does not match the expected Species-Form of the fused slot."; } [JsonSerializable(typeof(LegalityCheckLocalization))] diff --git a/PKHeX.Core/Legality/Localization/LegalityCheckResultCodeExtensions.cs b/PKHeX.Core/Legality/Localization/LegalityCheckResultCodeExtensions.cs index 85619c4d2..126269eb6 100644 --- a/PKHeX.Core/Legality/Localization/LegalityCheckResultCodeExtensions.cs +++ b/PKHeX.Core/Legality/Localization/LegalityCheckResultCodeExtensions.cs @@ -9,7 +9,8 @@ namespace PKHeX.Core; public static class LegalityCheckResultCodeExtensions { public static bool IsArgument(this LegalityCheckResultCode code) => code is < FirstWithMove and >= FirstWithArgument; - public static bool IsMove(this LegalityCheckResultCode code) => code is < FirstWithLanguage and >= FirstWithMove; + public static bool IsMove(this LegalityCheckResultCode code) => code is < FirstWithItem and >= FirstWithMove; + public static bool IsItem(this LegalityCheckResultCode code) => code is < FirstWithLanguage and >= FirstWithItem; public static bool IsLanguage(this LegalityCheckResultCode code) => code is < FirstWithMemory and >= FirstWithLanguage; public static bool IsMemory(this LegalityCheckResultCode code) => code is < FirstComplex and >= FirstWithMemory; @@ -342,6 +343,11 @@ public static class LegalityCheckResultCodeExtensions PIDNatureMismatch => localization.PIDNatureMismatch, PIDTypeMismatch => localization.PIDTypeMismatch, PIDZero => localization.PIDZero, + PlusMoveCountInvalid => localization.PlusMoveCountInvalid, + PlusMoveInvalid_0 => localization.PlusMoveInvalid_0, + PlusMoveMultipleInvalid => localization.PlusMoveMultipleInvalid, + PlusMoveAlphaMissing_0 => localization.PlusMoveAlphaMissing_0, + PlusMoveSufficientLevelMissing_0 => localization.PlusMoveSufficientLevelMissing_0, RibbonAllValid => localization.RibbonAllValid, RibbonEgg => localization.RibbonEgg, StatDynamaxInvalid => localization.StatDynamaxInvalid, @@ -412,6 +418,12 @@ public static class LegalityCheckResultCodeExtensions BulkSharingPIDGenerationSame => localization.BulkSharingPIDGenerationSame, BulkSharingPIDEncounterType => localization.BulkSharingPIDRNGType, BulkDuplicateMysteryGiftEggReceived => localization.BulkDuplicateMysteryGiftEggReceived, + BulkDuplicateFusionSlot => localization.BulkDuplicateFusionSlot, + BulkDuplicateMegaStoneSlot => localization.BulkDuplicateMegaStoneSlot, + BulkDuplicateMegaStoneInventory => localization.BulkDuplicateMegaStoneInventory, + BulkNotAcquiredMegaStoneInventory => localization.BulkNotAcquiredMegaStoneInventory, + BulkAssignedMegaStoneNotFound_0 => localization.BulkAssignedMegaStoneNotFound_0, + BulkFusionSourceInvalid => localization.BulkFusionSourceInvalid, BulkSharingTrainerIDs => localization.BulkSharingTrainerID, BulkSharingTrainerVersion => localization.BulkSharingTrainerVersion, diff --git a/PKHeX.Core/Legality/Localization/LegalityLocalizationContext.cs b/PKHeX.Core/Legality/Localization/LegalityLocalizationContext.cs index 3bcaf6aad..bb2819740 100644 --- a/PKHeX.Core/Legality/Localization/LegalityLocalizationContext.cs +++ b/PKHeX.Core/Legality/Localization/LegalityLocalizationContext.cs @@ -37,6 +37,7 @@ public static LegalityLocalizationContext Create(LegalityAnalysis la, string lan public string GetRibbonMessage(LegalityCheckResultCode code) => RibbonVerifier.GetMessage(Analysis, Strings.Ribbons, code); public string GetStatName(int displayIndex) => GetSafe(Settings.General.StatNames, displayIndex); public string GetMoveName(ushort move) => GetSafe(Strings.movelist, move); + public string GetItemName(ushort item) => GetSafe(Strings.itemlist, item); public string GetSpeciesName(ushort species) => GetSafe(Strings.specieslist, species); public string GetConsoleRegion3DS(int index) => GetSafe(Strings.console3ds, index); public string GetRibbonName(RibbonIndex index) => Strings.Ribbons.GetNameSafe($"Ribbon{index}", out var result) ? result : index.ToString(); @@ -85,6 +86,8 @@ private string GetInternalString(CheckResult chk) return string.Format(template, chk.Argument); if (code.IsMove()) return string.Format(template, GetMoveName(chk.Argument)); + if (code.IsItem()) + return string.Format(template, GetItemName(chk.Argument)); if (code.IsLanguage()) return string.Format(template, GetLanguageName(chk.Argument), GetLanguageName(Analysis.Entity.Language)); if (code.IsMemory()) diff --git a/PKHeX.Core/Legality/Moves/GameData.cs b/PKHeX.Core/Legality/Moves/GameData.cs index bf0b1fa12..77988d73a 100644 --- a/PKHeX.Core/Legality/Moves/GameData.cs +++ b/PKHeX.Core/Legality/Moves/GameData.cs @@ -51,6 +51,7 @@ public static class GameData PLA => LearnSource8LA.Instance, SL or VL or SV => LearnSource9SV.Instance, + ZA => LearnSource9ZA.Instance, Gen1 => LearnSource1YW.Instance, Gen2 => LearnSource2C.Instance, @@ -105,6 +106,7 @@ public static class GameData PLA => PersonalTable.LA, SL or VL or SV => PersonalTable.SV, + ZA => PersonalTable.ZA, Gen1 => PersonalTable.Y, Gen2 => PersonalTable.C, diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/ClassicEraRNG.cs b/PKHeX.Core/Legality/RNG/ClassicEra/ClassicEraRNG.cs index 689a2dc68..da6cacacf 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/ClassicEraRNG.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/ClassicEraRNG.cs @@ -193,7 +193,7 @@ public static InitialSeedComponents4 DecomposeSeed(uint seed, uint year, uint mo { // Check component: hour var hour = (byte)(seed >> 16 & 0xFF); - ArgumentOutOfRangeException.ThrowIfGreaterThan(hour, 23, nameof(hour)); + ArgumentOutOfRangeException.ThrowIfGreaterThan(hour, 23); // Check component: everything else but delay/year using modular arithmetic to handle overflow const uint maxBonusMinSec = 59 + 59; // min + sec diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/ChannelJirachi.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/ChannelJirachi.cs index 41a3155c0..3b3ac52a8 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/ChannelJirachi.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/ChannelJirachi.cs @@ -60,7 +60,7 @@ public static bool IsValidAccept(ref uint seed, uint acceptPivot) { // The game checks for two random results (25% and 33%). // If either passes, we advance once, otherwise we advance twice. - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(acceptPivot, 3u, nameof(acceptPivot)); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(acceptPivot, 3u); // 71.9% chance of passing at least one of the following branches. // 28.1% chance of failing all branches. diff --git a/PKHeX.Core/Legality/Restrictions/ItemRestrictions.cs b/PKHeX.Core/Legality/Restrictions/ItemRestrictions.cs index 9a09861ad..8d3984dde 100644 --- a/PKHeX.Core/Legality/Restrictions/ItemRestrictions.cs +++ b/PKHeX.Core/Legality/Restrictions/ItemRestrictions.cs @@ -45,6 +45,7 @@ public static bool IsHeldItemAllowed(int item, EntityContext context) EntityContext.Gen9 => ReleasedHeldItems_9, EntityContext.Gen8b => ReleasedHeldItems_8b, + EntityContext.Gen9a => ReleasedHeldItems_9a, _ => [], // lgp/e, pla, etc }; @@ -58,6 +59,7 @@ public static bool IsHeldItemAllowed(int item, EntityContext context) private static readonly bool[] ReleasedHeldItems_8 = GetPermitList(MaxItemID_8, HeldItems_SWSH, ItemStorage8SWSH.Unreleased, ItemStorage8SWSH.DynamaxCrystalBCAT); private static readonly bool[] ReleasedHeldItems_8b = GetPermitList(MaxItemID_8b, HeldItems_BS, ItemStorage8BDSP.Unreleased, ItemStorage8BDSP.DisallowHeldTreasure); private static readonly bool[] ReleasedHeldItems_9 = GetPermitList(MaxItemID_9, HeldItems_SV, ItemStorage9SV.Unreleased); + private static readonly bool[] ReleasedHeldItems_9a = GetPermitList(MaxItemID_9a, HeldItems_ZA, ItemStorage9ZA.Unreleased); /// /// Gets a permit list with the permitted indexes, then un-flags the indexes that are not permitted. diff --git a/PKHeX.Core/Legality/Restrictions/Memories/MemoryRules.cs b/PKHeX.Core/Legality/Restrictions/Memories/MemoryRules.cs index 70c9b394d..d033a3526 100644 --- a/PKHeX.Core/Legality/Restrictions/Memories/MemoryRules.cs +++ b/PKHeX.Core/Legality/Restrictions/Memories/MemoryRules.cs @@ -22,6 +22,7 @@ public static MemorySource GetPossibleSources(EvolutionHistory history) sources |= MemorySource.Gen8; if (history.HasVisitedGen9) sources |= MemorySource.Deleted; + // TODO HOME ZA return sources; } diff --git a/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilter3DS.cs b/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilter3DS.cs index 29570be16..50a5da338 100644 --- a/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilter3DS.cs +++ b/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilter3DS.cs @@ -77,14 +77,14 @@ public static bool IsSpeciesName(ReadOnlySpan message, EntityContext origi private static bool IsSpeciesNameGen7(ReadOnlySpan message) { - if (!SpeciesName.TryGetSpeciesAnyLanguageCaseInsensitive(message, out var s7, 7)) + if (!SpeciesName.TryGetSpeciesAnyLanguageCaseInsensitive(message, out var s7, EntityContext.Gen7)) return false; return s7 <= Legal.MaxSpeciesID_7_USUM; } private static bool IsSpeciesNameGen6(ReadOnlySpan message) { - if (!SpeciesName.TryGetSpeciesAnyLanguage(message, out var s6, 6)) + if (!SpeciesName.TryGetSpeciesAnyLanguage(message, out var s6, EntityContext.Gen6)) return false; return s6 <= Legal.MaxSpeciesID_6; } diff --git a/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilterNX.cs b/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilterNX.cs index 61671684a..ee4d56704 100644 --- a/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilterNX.cs +++ b/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilterNX.cs @@ -59,8 +59,7 @@ public static bool IsFiltered(ReadOnlySpan message, out int regMatch, Enti private static bool IsSpeciesName(ReadOnlySpan message, EntityContext origin) { - var gen = origin.Generation(); - if (!SpeciesName.TryGetSpeciesAnyLanguageCaseInsensitive(message, out var species, gen)) + if (!SpeciesName.TryGetSpeciesAnyLanguageCaseInsensitive(message, out var species, origin)) return false; return species <= origin.GetSingleGameVersion().GetMaxSpeciesID(); } diff --git a/PKHeX.Core/Legality/Settings/Specialized/HandlerRestrictions.cs b/PKHeX.Core/Legality/Settings/Specialized/HandlerRestrictions.cs index 494fb23a3..efa74d677 100644 --- a/PKHeX.Core/Legality/Settings/Specialized/HandlerRestrictions.cs +++ b/PKHeX.Core/Legality/Settings/Specialized/HandlerRestrictions.cs @@ -24,6 +24,7 @@ public sealed class HandlerRestrictions public bool AllowHandleOTGen8a { get; set; } public bool AllowHandleOTGen8b { get; set; } public bool AllowHandleOTGen9 { get; set; } + public bool AllowHandleOTGen9a { get; set; } public void Disable() => SetAllTo(true); @@ -36,6 +37,7 @@ public void SetAllTo(bool value) AllowHandleOTGen8a = value; AllowHandleOTGen8b = value; AllowHandleOTGen9 = value; + AllowHandleOTGen9a = value; } public bool GetCanOTHandle(EntityContext encContext) => encContext switch @@ -47,6 +49,7 @@ public void SetAllTo(bool value) EntityContext.Gen8a => AllowHandleOTGen8a, EntityContext.Gen8b => AllowHandleOTGen8b, EntityContext.Gen9 => AllowHandleOTGen9, + EntityContext.Gen9a => AllowHandleOTGen9a, _ => false, }; } diff --git a/PKHeX.Core/Legality/Settings/Specialized/NicknameRestriction.cs b/PKHeX.Core/Legality/Settings/Specialized/NicknameRestriction.cs index 73de6c6ea..ef8b38be8 100644 --- a/PKHeX.Core/Legality/Settings/Specialized/NicknameRestriction.cs +++ b/PKHeX.Core/Legality/Settings/Specialized/NicknameRestriction.cs @@ -41,6 +41,9 @@ public sealed class NicknameSettings [LocalizedDescription("Nickname rules for Generation 9.")] public NicknameRestriction Nickname9 { get; set; } = new(); + [LocalizedDescription("Nickname rules for Generation 9a.")] + public NicknameRestriction Nickname9a { get; set; } = new(); + public void Disable() { var nick = new NicknameRestriction(); @@ -61,6 +64,7 @@ public void SetAllTo(NicknameRestriction all) Nickname8a.CopyFrom(all); Nickname8b.CopyFrom(all); Nickname9.CopyFrom(all); + Nickname9a.CopyFrom(all); } public Severity NicknamedMysteryGift(EntityContext encContext) => encContext switch @@ -77,6 +81,7 @@ public void SetAllTo(NicknameRestriction all) EntityContext.Gen8a => Nickname8a.NicknamedMysteryGift, EntityContext.Gen8b => Nickname8b.NicknamedMysteryGift, EntityContext.Gen9 => Nickname9.NicknamedMysteryGift, + EntityContext.Gen9a => Nickname9a.NicknamedMysteryGift, _ => Severity.Valid, }; @@ -94,6 +99,7 @@ public void SetAllTo(NicknameRestriction all) EntityContext.Gen8a => Nickname8a.NicknamedTrade, EntityContext.Gen8b => Nickname8b.NicknamedTrade, EntityContext.Gen9 => Nickname9.NicknamedTrade, + EntityContext.Gen9a => Nickname9a.NicknamedTrade, _ => Severity.Valid, }; } diff --git a/PKHeX.Core/Legality/Structures/LegalityCheckResultCode.cs b/PKHeX.Core/Legality/Structures/LegalityCheckResultCode.cs index 387bd6e3f..74d44ad02 100644 --- a/PKHeX.Core/Legality/Structures/LegalityCheckResultCode.cs +++ b/PKHeX.Core/Legality/Structures/LegalityCheckResultCode.cs @@ -294,6 +294,10 @@ public enum LegalityCheckResultCode : ushort PIDTypeMismatch, PIDZero, + // Plus Moves + PlusMoveCountInvalid, + PlusMoveMultipleInvalid, + // Ribbons RibbonAllValid, RibbonEgg, @@ -374,7 +378,12 @@ public enum LegalityCheckResultCode : ushort BulkSharingPIDGenerationDifferent, BulkSharingPIDGenerationSame, BulkSharingPIDEncounterType, + BulkDuplicateFusionSlot, BulkDuplicateMysteryGiftEggReceived, + BulkDuplicateMegaStoneSlot, + BulkDuplicateMegaStoneInventory, + BulkNotAcquiredMegaStoneInventory, + BulkFusionSourceInvalid, BulkSharingTrainerIDs, BulkSharingTrainerVersion, @@ -413,6 +422,13 @@ public enum LegalityCheckResultCode : ushort MoveShopMasterInvalid_0, // move ID MoveShopMasterNotLearned_0, // move ID MoveShopPurchaseInvalid_0, // move ID + PlusMoveInvalid_0, // move ID + PlusMoveAlphaMissing_0, // move ID + PlusMoveSufficientLevelMissing_0, // move ID + + // Single Argument: Item ID + FirstWithItem, + BulkAssignedMegaStoneNotFound_0 = FirstWithItem, // item ID // One Argument: Language FirstWithLanguage, diff --git a/PKHeX.Core/Legality/Tables/FormInfo.cs b/PKHeX.Core/Legality/Tables/FormInfo.cs index 49bfef359..5e4c6720b 100644 --- a/PKHeX.Core/Legality/Tables/FormInfo.cs +++ b/PKHeX.Core/Legality/Tables/FormInfo.cs @@ -55,12 +55,14 @@ public static bool IsMegaForm(ushort species, byte form) _ => form != 0, }; - private static bool IsBattleMegaForm(ushort species, byte form) + private static bool IsBattleMegaForm(ushort species, byte form) => species switch { - if (species is (ushort)Slowbro) - return form == 1; // Mega - return form != 0; - } + (ushort)Slowbro => form == 1, + (ushort)Zygarde => form == 5, + (ushort)Floette => form == 6, + (ushort)Greninja => form == 3, + _ => form != 0 + }; /// /// Reverts the Battle Form to the form it would have outside of Battle. @@ -77,6 +79,7 @@ private static bool IsBattleMegaForm(ushort species, byte form) (ushort)Minior => (byte)(form + 7), (ushort)Mimikyu => (byte)(form & 2), (ushort)Ogerpon => (byte)(form & 3), + (ushort)Floette => 5, _ => 0, }; @@ -110,12 +113,14 @@ public static bool IsFormChangeable(ushort species, byte oldForm, byte newForm, // Gen6: Introduced; no form changing. // Gen7: Form changing introduced; can only change to Form 2/3 (Power Construct), never to 0/1 (Aura Break). A form-1 can be boosted to form-0. // Gen8: Form changing improved; can pick any Form & Ability combination. + // Gen9a: Form 0/1 inaccessible, and can only toggle between 10%/50% Core Enforcer variants (form 2/3). if (species == (int)Zygarde) { return current switch { EntityContext.Gen6 => false, EntityContext.Gen7 => newForm >= 2 || (oldForm == 1 && newForm == 0), + EntityContext.Gen9a => newForm >= 2, _ => true, }; } @@ -239,6 +244,37 @@ public static bool IsFormChangeable(ushort species, byte oldForm, byte newForm, (int)Lopunny, (int)Gallade, (int)Audino, (int)Diancie, + + // ZA + (int)Clefable, + (int)Victreebel, + (int)Starmie, + (int)Dragonite, + (int)Meganium, + (int)Feraligatr, + (int)Skarmory, + (int)Froslass, + (int)Emboar, + (int)Excadrill, + (int)Scolipede, + (int)Scrafty, + (int)Eelektross, + (int)Chandelure, + (int)Chesnaught, + (int)Delphox, + (int)Pyroar, + (int)Malamar, + (int)Barbaracle, + (int)Dragalge, + (int)Hawlucha, + (int)Drampa, + (int)Falinks, + + (int)Floette, + + //(int)Heatran, + //(int)Darkrai, + //(int)Zeraora, ]; /// diff --git a/PKHeX.Core/Legality/Tables/TradeRestrictions.cs b/PKHeX.Core/Legality/Tables/TradeRestrictions.cs index 940b0d4e2..fdc7965f8 100644 --- a/PKHeX.Core/Legality/Tables/TradeRestrictions.cs +++ b/PKHeX.Core/Legality/Tables/TradeRestrictions.cs @@ -18,10 +18,15 @@ public static class TradeRestrictions (ushort)Species.Koraidon or (int)Species.Miraidon => formArg == 1, // Ride-able Box Legend (ushort)Species.Pikachu => format == 7 && form == 8, // Let's Go Pikachu Starter (ushort)Species.Eevee => format == 7 && form == 1, // Let's Go Eevee Starter - _ => FormInfo.IsFusedForm(species, form, format), + _ => FormInfo.IsFusedForm(species, form, format) || FormInfo.IsBattleOnlyForm(species, form, format), }; - public static bool IsUntradableHeld(int item) => ItemStorage7USUM.ZCrystalHeld.Contains((ushort)item); + public static bool IsUntradableHeld(EntityContext context, int item) => context switch + { + EntityContext.Gen7 => ItemStorage7USUM.ZCrystalHeld.Contains((ushort)item), + EntityContext.Gen9a => ItemStorage9ZA.IsMegaStone((ushort)item), + _ => false, + }; public static bool IsUntradableEncounter(IEncounterTemplate enc) => enc switch { diff --git a/PKHeX.Core/Legality/Verifiers/Ability/AbilityChangeRules.cs b/PKHeX.Core/Legality/Verifiers/Ability/AbilityChangeRules.cs index b0291e0c6..2eba7df5b 100644 --- a/PKHeX.Core/Legality/Verifiers/Ability/AbilityChangeRules.cs +++ b/PKHeX.Core/Legality/Verifiers/Ability/AbilityChangeRules.cs @@ -68,6 +68,7 @@ public static bool IsAbilityChangeAvailable(this IEncounterTemplate enc, Evoluti /// True if possible public static bool IsAbilityCapsuleAvailable(EvolutionHistory evosAll) { + // ZA: Not available if (evosAll.HasVisitedGen9) return true; if (evosAll.HasVisitedSWSH) @@ -88,6 +89,7 @@ public static bool IsAbilityCapsuleAvailable(EvolutionHistory evosAll) /// True if possible public static bool IsAbilityCapsulePossible(EvolutionHistory evosAll) { + // ZA: Not available if (evosAll.HasVisitedGen9 && IsCapsulePossible(evosAll.Gen9, PersonalTable.SV)) return true; if (evosAll.HasVisitedSWSH && IsCapsulePossible(evosAll.Gen8, PersonalTable.SWSH)) @@ -108,7 +110,7 @@ public static bool IsAbilityCapsulePossible(EvolutionHistory evosAll) /// True if possible public static bool IsAbilityPatchAvailable(EvolutionHistory evosAll) { - if (evosAll.HasVisitedGen9) + if (evosAll.HasVisitedGen9) // ZA: Not available return true; if (evosAll.HasVisitedSWSH || evosAll.HasVisitedBDSP) return true; @@ -122,6 +124,7 @@ public static bool IsAbilityPatchAvailable(EvolutionHistory evosAll) /// True if possible public static bool IsAbilityPatchPossible(EvolutionHistory evosAll) { + // ZA: Not available if (evosAll.HasVisitedSWSH && IsPatchPossible(evosAll.Gen8, PersonalTable.SWSH)) return true; if (evosAll.HasVisitedBDSP && IsPatchPossible(evosAll.Gen8b, PersonalTable.BDSP)) @@ -138,7 +141,7 @@ public static bool IsAbilityPatchPossible(EvolutionHistory evosAll) /// True if possible public static bool IsAbilityPatchRevertAvailable(EvolutionHistory evosAll) { - if (evosAll.HasVisitedGen9) + if (evosAll.HasVisitedGen9) // ZA: Not available return true; return false; } @@ -151,6 +154,7 @@ public static bool IsAbilityPatchRevertAvailable(EvolutionHistory evosAll) /// True if possible public static bool IsAbilityPatchRevertPossible(EvolutionHistory evosAll, int abilityIndex) { + // ZA: Not available if (evosAll.HasVisitedGen9 && IsRevertPossible(evosAll.Gen9, PersonalTable.SV, abilityIndex)) return true; return false; @@ -188,9 +192,16 @@ public static bool IsAbilityPatchRevertPossible(EvolutionHistory evosAll, int ab return IsFormChangeDifferentHidden(evos[0]); } + /// public static bool IsFormChangeDifferentHidden(TEvo first) where TEvo : ISpeciesForm => first.Form != 0 && IsFormChangeDifferentHidden(first.Species); + /// + /// Checks if the species has a different hidden ability on another form (usually Form-0). + /// + /// + /// Some forms are single ability, but if changed to another form, can be mutated to have an "inaccessible" index. + /// public static bool IsFormChangeDifferentHidden(ushort species) => species switch { (int)Species.Giratina => true, // Form-0 is a/a/h diff --git a/PKHeX.Core/Legality/Verifiers/Ability/AbilityVerifier.cs b/PKHeX.Core/Legality/Verifiers/Ability/AbilityVerifier.cs index 488219e6c..8b55cfdc9 100644 --- a/PKHeX.Core/Legality/Verifiers/Ability/AbilityVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/Ability/AbilityVerifier.cs @@ -27,6 +27,9 @@ private enum AbilityState : byte private CheckResult VerifyAbility(LegalityAnalysis data) { var pk = data.Entity; + if (pk is PA9 pa9) + return VerifyBirthAbility(data, pa9); + var abilities = (IPersonalAbility12)data.PersonalInfo; // Check ability is possible (within bounds) @@ -457,4 +460,16 @@ public static bool CanAbilityPatch(byte format, IPersonalAbility12H abilities, u // Some species have a distinct hidden ability only on another form, and can change between that form and its current form. return AbilityChangeRules.IsFormChangeDifferentHidden(species); } + + private CheckResult VerifyBirthAbility(LegalityAnalysis data, PA9 pa9) + { + var enc = data.EncounterMatch; + var pi = PersonalTable.ZA[enc.Species, enc.Form]; + var index = pa9.AbilityNumber >> 1; + var expect = pi.GetAbilityAtIndex(index); + if (pa9.Ability != expect) + return GetInvalid(AbilityMismatch); + + return VALID; + } } diff --git a/PKHeX.Core/Legality/Verifiers/Ball/BallUseLegality.cs b/PKHeX.Core/Legality/Verifiers/Ball/BallUseLegality.cs index 2ec60842c..55b7f957f 100644 --- a/PKHeX.Core/Legality/Verifiers/Ball/BallUseLegality.cs +++ b/PKHeX.Core/Legality/Verifiers/Ball/BallUseLegality.cs @@ -33,8 +33,9 @@ public static bool IsBallPermitted(ulong permit, byte ball) 6 => WildPokeballs6, 7 => GameVersion.Gen7b.Contains(version) ? WildPokeballs7b : WildPokeballs7, 8 when GameVersion.BDSP.Contains(version) => WildPokeBalls4_HGSS, - 8 when GameVersion.PLA == version => WildPokeBalls8a, + 8 when version is GameVersion.PLA => WildPokeBalls8a, 8 => GameVersion.GO == version ? WildPokeballs8g_WithRaid : WildPokeballs8, + 9 when version is GameVersion.ZA => WildPokeballs9a, // Dream Ball and Beast Ball not available 9 => WildPokeballs9, _ => 0, }; @@ -94,4 +95,6 @@ public static bool IsBallPermitted(ulong permit, byte ball) public const ulong WildPokeballs9 = WildPokeballs8; public const ulong WildPokeballs9PreDLC2 = WildPokeballs7 | WildPokeEnhance5; // Same as Gen7 + Dream + + public const ulong WildPokeballs9a = WildPokeBalls4_HGSS; // | (1 << (int)Sport); // no Safari, Dream, Beast } diff --git a/PKHeX.Core/Legality/Verifiers/FormVerifier.cs b/PKHeX.Core/Legality/Verifiers/FormVerifier.cs index 854980f49..24dcf2fd9 100644 --- a/PKHeX.Core/Legality/Verifiers/FormVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/FormVerifier.cs @@ -139,8 +139,8 @@ private CheckResult VerifyForm(LegalityAnalysis data) data.AddLine(Get(Severity.Fishy, FormVivillonNonNative)); break; - case Floette when form == 5: // Floette Eternal Flower -- Never Released - if (enc is not MysteryGift) + case Floette when form == 5: // Eternal Flower Floette - not released until Pokémon Legends: Z-A + if (enc is not EncounterGift9a) return GetInvalid(FormEternalInvalid); return GetValid(FormEternal); case Meowstic when form != pk.Gender: @@ -181,9 +181,28 @@ private CheckResult VerifyForm(LegalityAnalysis data) } var format = pk.Format; - if (FormInfo.IsBattleOnlyForm(species, form, format)) - return GetInvalid(FormBattle); + if (!FormInfo.IsBattleOnlyForm(species, form, format)) + return VALID; - return VALID; + if (pk.Context is EntityContext.Gen9a) + return VerifyBattleForms9a(data, species, form); + + return GetInvalid(FormBattle); + } + + private CheckResult VerifyBattleForms9a(LegalityAnalysis data, ushort species, byte form) + { + if (!data.IsStoredSlot(StorageSlotType.Party)) + return GetInvalid(FormBattle); // Should have reverted to base form when stored. + + // Battle forms can exist in Party. + if (!FormInfo.IsMegaForm(species, form)) + return VALID; + + var megaStone = ItemStorage9ZA.GetExpectedMegaStone(species, form); + if (megaStone == 0 || data.Entity.HeldItem == megaStone) + return VALID; + + return GetInvalid(FormBattle); } } diff --git a/PKHeX.Core/Legality/Verifiers/HistoryVerifier.cs b/PKHeX.Core/Legality/Verifiers/HistoryVerifier.cs index ed0a25803..6851478fd 100644 --- a/PKHeX.Core/Legality/Verifiers/HistoryVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/HistoryVerifier.cs @@ -318,13 +318,16 @@ public static bool GetCanOTHandle(IEncounterTemplate enc, PKM pk, byte generatio private static byte GetBaseFriendship(EntityContext context, ushort species, byte form) => context switch { - EntityContext.Gen6 => PersonalTable.AO[species].BaseFriendship, + EntityContext.Gen6 => PersonalTable.AO [species].BaseFriendship, EntityContext.Gen7 => PersonalTable.USUM[species].BaseFriendship, - EntityContext.Gen7b => PersonalTable.GG[species].BaseFriendship, - EntityContext.Gen8 => PersonalTable.SWSH.GetFormEntry(species, form).BaseFriendship, - EntityContext.Gen8a => PersonalTable.LA.GetFormEntry(species, form).BaseFriendship, - EntityContext.Gen8b => PersonalTable.BDSP.GetFormEntry(species, form).BaseFriendship, - EntityContext.Gen9 => PersonalTable.SV.GetFormEntry(species, form).BaseFriendship, + EntityContext.Gen7b => PersonalTable.GG [species].BaseFriendship, + + EntityContext.Gen8 => PersonalTable.SWSH[species, form].BaseFriendship, + EntityContext.Gen8a => PersonalTable.LA [species, form].BaseFriendship, + EntityContext.Gen8b => PersonalTable.BDSP[species, form].BaseFriendship, + EntityContext.Gen9 => PersonalTable.SV [species, form].BaseFriendship, + EntityContext.Gen9a => PersonalTable.ZA [species, form].BaseFriendship, + _ => throw new ArgumentOutOfRangeException(nameof(context)), }; } diff --git a/PKHeX.Core/Legality/Verifiers/LanguageVerifier.cs b/PKHeX.Core/Legality/Verifiers/LanguageVerifier.cs index f58ea0ecd..754ec7b37 100644 --- a/PKHeX.Core/Legality/Verifiers/LanguageVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/LanguageVerifier.cs @@ -16,7 +16,7 @@ public override void Verify(LegalityAnalysis data) var pk = data.Entity; var originalGeneration = data.Info.Generation; var currentLanguage = (LanguageID)pk.Language; - var maxLanguageID = (LanguageID)Legal.GetMaxLanguageID(originalGeneration); + var maxLanguageID = (LanguageID)Legal.GetMaxLanguageID(originalGeneration, data.EncounterOriginal.Context); var enc = data.EncounterMatch; if (!IsValidLanguageID(currentLanguage, maxLanguageID, pk, enc)) { diff --git a/PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs b/PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs index e6c5bc843..1ec026045 100644 --- a/PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs @@ -95,14 +95,14 @@ private static int LoadBareMinimumMoveset(ISpeciesForm enc, EvolutionHistory h, if ((uint)count >= 4) return 4; + // If it can be leveled up in other games, level it up in other games. + if (pa is IHomeTrack { HasTracker: true }) + return count; + var purchasedCount = pa.GetPurchasedCount(); Span purchased = stackalloc ushort[purchasedCount]; LoadPurchasedMoves(pa, purchased); - // If it can be leveled up in other games, level it up in other games. - if (h.HasVisitedSWSH || h.HasVisitedBDSP) - return count; - // Level up to current level var level = pa.CurrentLevel; moveset.SetLevelUpMoves(pa.MetLevel, level, moves, purchased, count); diff --git a/PKHeX.Core/Legality/Verifiers/LegendsZAVerifier.cs b/PKHeX.Core/Legality/Verifiers/LegendsZAVerifier.cs new file mode 100644 index 000000000..be093051a --- /dev/null +++ b/PKHeX.Core/Legality/Verifiers/LegendsZAVerifier.cs @@ -0,0 +1,232 @@ +using System; +using static PKHeX.Core.LegalityCheckResultCode; + +namespace PKHeX.Core; + +public sealed class LegendsZAVerifier : Verifier +{ + protected override CheckIdentifier Identifier => CheckIdentifier.RelearnMove; + + public override void Verify(LegalityAnalysis data) + { + if (data.Entity is not PA9 pa9) + return; + CheckLearnset(data, pa9); + CheckFlagsTM(data, pa9); + CheckFlagsPlus(data, pa9); + } + + private void CheckLearnset(LegalityAnalysis data, PA9 pa) + { + if (data.EncounterMatch is not IEncounter9a e9a) + return; // Don't bother. + + var moveCount = pa.MoveCount; + if (moveCount == 4) + return; + + // Flag move slots that are empty. + if (pa.Tracker != 0 || !ParseSettings.IgnoreTransferIfNoTracker) + return; // Can delete moves in PA8 moveset via HOME. + + // Get the bare minimum moveset. + Span expect = stackalloc ushort[4]; + _ = LoadBareMinimumMoveset(e9a, pa, expect); + + // Expected move can be empty due to user rearranging. + // Account for player rearrangement of moves. + var moves = data.Info.Moves; + for (int i = 0; i < moves.Length; i++) + { + var currentMove = pa.GetMove(i); + var index = expect.IndexOf(currentMove); + if (index != -1 && index != i) // Swapped move. Swap the expected slot. + (expect[i], expect[index]) = (expect[index], expect[i]); + } + + // Now that we've rearranged the expected moves to matching slots (if any), flag any mismatches. + // Basically only will flag "(None) => Expected {non-zero-move} instead." + for (int i = 0; i < expect.Length; i++) + { + var move = expect[i]; + if (pa.GetMove(i) != move) + moves[i] = MoveResult.Unobtainable(move); + } + } + + /// + /// Gets the expected minimum count of moves, and modifies the input with the bare minimum move IDs. + /// + private static int LoadBareMinimumMoveset(IEncounter9a enc, PA9 pa, Span moves) + { + // Get any encounter moves + var ls = LearnSource8LA.Instance; + var moveset = ls.GetLearnset(enc.Species, enc.Form); + GetInitialMoves(enc, pa, moves); + var count = moves.IndexOf((ushort)0); + if ((uint)count >= 4) + return 4; + + // If it can be leveled up in other games, level it up in other games. + if (pa is IHomeTrack { HasTracker: true }) + return count; + + // Level up moves never repeat, so just level up to current level. + var ms = moveset.GetMoveRange(pa.CurrentLevel, (byte)(pa.MetLevel + 1)); + foreach (var move in ms) + { + if (moves.Contains(move)) // just in case. + continue; + moves[count++] = move; + if ((uint)count >= 4) + return 4; + } + + // Check if any TM/Evo/Relearn moves were learned. They'll be anything we've not been able to learn yet. + // Don't check the validity of a foreign move. + for (int i = 0; i < 4; i++) + { + var move = pa.GetMove(i); + if (move == 0) + continue; + if (moves.Contains(move)) + continue; + moves[count++] = move; + if ((uint)count >= 4) + return 4; + } + + // No other tutor sources. + return count; + } + + private static void GetInitialMoves(IEncounter9a enc, PA9 pa9, Span moves) + { + if (enc is IMoveset { Moves: { HasMoves: true } m }) + { + m.CopyTo(moves); + return; + } + var level = Math.Max((byte)1, pa9.MetLevel); + var learn = LearnSource9ZA.Instance.GetLearnset(enc.Species, enc.Form); + if (!enc.IsAlpha) + { + learn.SetEncounterMoves(level, moves); + return; + } + learn.SetEncounterMovesBackwards(level, moves, sameDescend: false); + moves[0] = PersonalTable.ZA[enc.Species, enc.Form].AlphaMove; + } + + private void CheckFlagsTM(LegalityAnalysis data, PA9 pa9) + { + // Wild Alphas automatically come with a specific move. + var enc = data.EncounterMatch; + if (enc.Context is not EntityContext.Gen9a) + return; + if (enc is not IAlphaReadOnly { IsAlpha: true }) + return; + + var pi = PersonalTable.ZA[enc.Species, enc.Form]; + var move = pi.AlphaMove; + var indexPlus = PersonalInfo9ZA.PlusMoves.IndexOf(move); + + if (indexPlus != -1) + { + if (!pa9.GetMovePlusFlag(indexPlus)) + data.AddLine(GetInvalid(PlusMoveAlphaMissing_0, move)); + } + } + + + private void CheckFlagsPlus(LegalityAnalysis la, PA9 pk) + { + var permit = (IPermitPlus)la.PersonalInfo; + + // Check for any impossible-to-set flag indexes. + if (pk.GetMovePlusFlagAnyImpossible()) + la.AddLine(GetInvalid(PlusMoveCountInvalid)); + + // Check for all required indexes. + var (_, plus) = LearnSource9ZA.GetLearnsetAndPlus(pk.Species, pk.Form); + var currentLevel = pk.CurrentLevel; + CheckPlusMoveFlags(la, pk, plus, currentLevel, permit); + + + // Check for indexes set that cannot be set via TM or NPC. + int max = permit.PlusCountUsed; + var evos = la.Info.EvoChainsAllGens.Gen9a; + var invalidMove = GetInvalidPlusMove(pk, max, permit, evos); + if (invalidMove == 0) + return; + + // The above result stores the first invalid move, or a magic value for multiple invalid moves. + var msg = invalidMove is MultipleInvalidPlusMoves + ? GetInvalid(PlusMoveMultipleInvalid) + : GetInvalid(PlusMoveInvalid_0, invalidMove); + la.AddLine(msg); + } + + private void CheckPlusMoveFlags(LegalityAnalysis la, T pk, Learnset plus, byte currentLevel, IPermitPlus permit) where T : IPlusRecord + { + var levels = plus.GetAllLevels(); + var moves = plus.GetAllMoves(); + for (int i = 0; i < levels.Length; i++) + { + var level = levels[i]; + if (level > currentLevel) + break; // not able to be Plus'd, therefore no need to check. + + var move = moves[i]; + var index = permit.PlusMoveIndexes.IndexOf(move); + if (index == -1) + throw new IndexOutOfRangeException("Unexpected learn move index, not in Plus moves?"); + + if (!pk.GetMovePlusFlag(index)) + la.AddLine(GetInvalid(PlusMoveSufficientLevelMissing_0, move, level)); + } + } + + private const ushort MultipleInvalidPlusMoves = ushort.MaxValue; + + private static ushort GetInvalidPlusMove(T pk, int maxIndex, IPermitPlus permit, ReadOnlySpan evos) + where T : IPlusRecord + { + ushort invalid = 0; + for (int i = 0; i < maxIndex; i++) + { + if (!pk.GetMovePlusFlag(i)) + continue; + var move = permit.PlusMoveIndexes[i]; + var index = permit.RecordPermitIndexes.IndexOf(move); + if (CanAnyEvoLearnMovePlus(evos, index, move, PersonalTable.ZA, LearnSource9ZA.Instance)) + continue; // OK + + if (invalid != 0) // Multiple invalid moves + return MultipleInvalidPlusMoves; + invalid = move; + } + return invalid; + } + + private static bool CanAnyEvoLearnMovePlus(ReadOnlySpan evos, int tmIndex, ushort move, + TTable table, TSource source) + where TTable : IPersonalTable + where TInfo : IPersonalInfo, IPersonalInfoTM + where TSource : ILearnSourceBonus + { + foreach (var evo in evos) + { + // If the move can be learned as TM, can be marked as Plus Move regardless of level. + var pi = table[evo.Species, evo.Form]; + if (tmIndex != -1 && pi.GetIsLearnTM(tmIndex)) + return true; + + // If the move can be learned via learnset, check if the level is at or above the Plus required level. + var (_, plus) = source.GetLearnsetAndOther(evo.Species, evo.Form); + if (plus.TryGetLevelLearnMove(move, out var level) && level <= evo.LevelMax) + return true; + } + return false; + } +} diff --git a/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs b/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs index edc9269f7..8278016df 100644 --- a/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs @@ -10,6 +10,7 @@ namespace PKHeX.Core; public sealed class MiscVerifier : Verifier { private static readonly LegendsArceusVerifier Arceus = new(); + private static readonly LegendsZAVerifier LegendsZA = new(); protected override CheckIdentifier Identifier => Misc; @@ -57,6 +58,7 @@ public override void Verify(LegalityAnalysis data) case PB8 pb8: VerifyStats8b(data, pb8); break; case PA8 pa8: VerifyStats8a(data, pa8); break; case PK9 pk9: VerifyStats9(data, pk9); break; + case PA9 pa9: VerifyStats9a(data, pa9); break; } if (pk is IFullnessEnjoyment fe) // 6-8 @@ -64,10 +66,9 @@ public override void Verify(LegalityAnalysis data) var enc = data.EncounterMatch; if (enc is IEncounterServerDate { IsDateRestricted: true } encounterDate) - { VerifyServerDate2000(data, pk, enc, encounterDate); - } - else if (enc is IOverworldCorrelation8 z) + + if (enc is IOverworldCorrelation8 z) { VerifyCorrelation8(data, z, pk); } @@ -217,6 +218,13 @@ private void VerifyMiscScaleValues(LegalityAnalysis data, PKM pk, IEncounterTemp if (s2 is { HeightScalar: 0, WeightScalar: 0 } && !data.Info.EvoChainsAllGens.HasVisitedPLA && enc is not IPogoSlot) data.AddLine(Get(Encounter, Severity.Invalid, StatInvalidHeightWeight)); } + else if (data.EncounterMatch.Context is EntityContext.Gen9a) + { + if (s2.HeightScalar != 0) + data.AddLine(GetInvalid(Encounter, StatIncorrectHeightValue)); + if (s2.WeightScalar != 0) + data.AddLine(GetInvalid(Encounter, StatIncorrectWeightValue)); + } else if (CheckHeightWeightOdds(data.EncounterMatch)) { if (s2 is { HeightScalar: 0, WeightScalar: 0 }) @@ -368,6 +376,18 @@ private void VerifyStats9(LegalityAnalysis data, PK9 pk9) } } + private void VerifyStats9a(LegalityAnalysis data, PA9 pa9) + { + LegendsZA.Verify(data); + if (!pa9.IsBattleVersionValid(data.Info.EvoChainsAllGens)) + data.AddLine(GetInvalid(StatBattleVersionInvalid)); + VerifyStatNature(data, pa9); + if (!IsObedienceLevelValid(pa9, pa9.ObedienceLevel, pa9.MetLevel)) + data.AddLine(GetInvalid(TransferObedienceLevel)); + if (pa9.IsAlpha != data.EncounterMatch is IAlphaReadOnly { IsAlpha: true }) + data.AddLine(GetInvalid(StatAlphaInvalid)); + } + private static void DisallowLevelUpMove(byte level, ushort move, PK9 pk, LegalityAnalysis data) { if (pk.Tracker != 0) @@ -903,6 +923,8 @@ private static bool CheckHeightWeightOdds(IEncounterTemplate enc) { if (enc.Generation < 8) return false; + if (enc.Context is EntityContext.Gen9a) + return true; if (enc is WC8 { IsHOMEGift: true }) return false; if (enc is WC9) // fixed values (usually 0 or 128) diff --git a/PKHeX.Core/Legality/Verifiers/MovePPVerifier.cs b/PKHeX.Core/Legality/Verifiers/MovePPVerifier.cs index d20b8b57c..aa0fd9be9 100644 --- a/PKHeX.Core/Legality/Verifiers/MovePPVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/MovePPVerifier.cs @@ -47,11 +47,6 @@ private void VerifyEntity(LegalityAnalysis data) ReadOnlySpan moves = [pk.Move1, pk.Move2, pk.Move3, pk.Move4]; ReadOnlySpan pp = [pk.Move1_PP, pk.Move2_PP, pk.Move3_PP, pk.Move4_PP]; - bool expectHeal = !data.IsStoredSlot(StorageSlotType.Party) && data.SlotOrigin switch - { - StorageSlotType.Box or StorageSlotType.GTS or StorageSlotType.BattleBox => GetIsStoredHealed(pk, data.EncounterOriginal), - _ => false, // Deposited slots pass through party. - }; if (!Legal.IsPPUpAvailable(pk)) // No PP Ups for format { @@ -70,6 +65,7 @@ private void VerifyEntity(LegalityAnalysis data) } } + var expectHeal = Legal.IsPPUnused(pk) || IsPPHealed(data, pk); for (int i = 0; i < pp.Length; i++) { var expect = pk.GetMovePP(moves[i], ups[i]); @@ -80,6 +76,18 @@ private void VerifyEntity(LegalityAnalysis data) } } + private static bool IsPPHealed(LegalityAnalysis data, PKM pk) + { + if (data.IsStoredSlot(StorageSlotType.Party)) + return false; + + return data.SlotOrigin switch + { + StorageSlotType.Box or StorageSlotType.GTS or StorageSlotType.BattleBox => GetIsStoredHealed(pk, data.EncounterOriginal), + _ => false, // Deposited slots pass through party. + }; + } + /// /// Checks if the format is expected to have the Pokémon healed to full PP. /// diff --git a/PKHeX.Core/Legality/Verifiers/NicknameVerifier.cs b/PKHeX.Core/Legality/Verifiers/NicknameVerifier.cs index a0723aebd..b8a11424e 100644 --- a/PKHeX.Core/Legality/Verifiers/NicknameVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/NicknameVerifier.cs @@ -165,7 +165,7 @@ private bool VerifyUnNicknamedEncounter(LegalityAnalysis data, PKM pk, ReadOnlyS return true; } } - if (SpeciesName.TryGetSpeciesAnyLanguage(nickname, out var species, pk.Format)) + if (SpeciesName.TryGetSpeciesAnyLanguage(nickname, out var species, pk.Context)) { var msg = species == pk.Species ? NickMatchLanguageFlag : NickMatchNoOthersFail; data.AddLine(Get(ParseSettings.Settings.Nickname.NicknamedAnotherSpecies, msg)); @@ -211,9 +211,11 @@ private void VerifyUnNicknamed(LegalityAnalysis data, PKM pk, ReadOnlySpan private static bool CanNicknameForeign8Plus(LegalityAnalysis data, PKM pk) { - if (data.Info.EvoChainsAllGens.HasVisitedSWSH) + // I think this method needs to be rewritten and clarified. + var hist = data.Info.EvoChainsAllGens; + if (hist.HasVisitedSWSH || hist.HasVisitedZA) return true; - if (pk.Format >= 9) + if (pk.Format >= 9) // S/V disallows fateful encounter nicknaming return !pk.FatefulEncounter; return false; } @@ -242,6 +244,7 @@ private static bool IsNicknameValid(PKM pk, IEncounterTemplate enc, ReadOnlySpan { ushort species = pk.Species; byte format = pk.Format; + var context = pk.Context; int language = pk.Language; // Farfetch’d and Sirfetch’d have different apostrophes in HOME, only if transferred from 3DS or GO => HOME. @@ -268,10 +271,10 @@ private static bool IsNicknameValid(PKM pk, IEncounterTemplate enc, ReadOnlySpan // Also in Generation 8, evolving in a foreign language game will retain the original language as the source for the newly evolved species name. // Transferring from Gen7->Gen8 realigns the Nickname string to the Language, if not nicknamed. bool canHaveAnyLanguage = format <= 7 && (enc.Species != species || pk.WasTradedEgg || enc is WC7 {IsAshGreninja: true}) && !pk.GG; - if (canHaveAnyLanguage && !SpeciesName.IsNicknamedAnyLanguage(species, nickname, format)) + if (canHaveAnyLanguage && !SpeciesName.IsNicknamedAnyLanguage(species, nickname, context)) return true; - if (enc is ILangNick loc && loc.Language != 0 && !loc.IsNicknamed && !SpeciesName.IsNicknamedAnyLanguage(species, nickname, format)) + if (enc is ILangNick loc && loc.Language != 0 && !loc.IsNicknamed && !SpeciesName.IsNicknamedAnyLanguage(species, nickname, context)) return true; // fixed language without nickname, nice job event maker! if (format == 5 && enc.Generation != 5) // transfer @@ -294,7 +297,7 @@ private static bool IsMatch45(ReadOnlySpan nickname, ushort species, ReadO return false; // must have matched above } if (canHaveAnyLanguage) - return !SpeciesName.IsNicknamedAnyLanguage(species, nickname, 4); + return !SpeciesName.IsNicknamedAnyLanguage(species, nickname, EntityContext.Gen4); expect = SpeciesName.GetSpeciesNameGeneration(species, language, 4); return nickname.SequenceEqual(expect); } @@ -324,7 +327,7 @@ private static void VerifyNicknameEgg(LegalityAnalysis data) int len = pk.LoadString(pk.NicknameTrash, nickname); nickname = nickname[..len]; - if (pk.Format == 2 && !SpeciesName.IsNicknamedAnyLanguage(0, nickname, 2)) + if (pk.Format == 2 && !SpeciesName.IsNicknamedAnyLanguage(0, nickname, EntityContext.Gen2)) data.AddLine(GetValid(CheckIdentifier.Egg, NickMatchLanguageEgg)); else if (!nickname.SequenceEqual(SpeciesName.GetEggName(pk.Language, enc.Generation))) data.AddLine(GetInvalid(CheckIdentifier.Egg, NickMatchLanguageEggFail)); diff --git a/PKHeX.Core/Legality/Verifiers/TransferVerifier.cs b/PKHeX.Core/Legality/Verifiers/TransferVerifier.cs index 9202017f6..d325e22e0 100644 --- a/PKHeX.Core/Legality/Verifiers/TransferVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/TransferVerifier.cs @@ -149,6 +149,7 @@ public void VerifyTransferLegalityG8(LegalityAnalysis data) PA8 => PersonalTable.LA, PB8 => PersonalTable.BDSP, PK9 => PersonalTable.SV, + PA9 => PersonalTable.ZA, _ => PersonalTable.SWSH, }; if (!pt.IsPresentInGame(pk.Species, pk.Form)) @@ -183,6 +184,9 @@ private void VerifyHOMETracker(LegalityAnalysis data, PKM pk) // - Transfer a 0-Tracker pk to HOME to get assigned a valid Tracker via the game it originated from. // - Don't make one up. } + + if (pk.ZA != pk is PA9) // TODO: ZA HOME Compatibility - flag in/out transfers for now. + data.AddLine(GetInvalid(TransferBad)); } public void VerifyVCEncounter(PKM pk, IEncounterTemplate original, EncounterTransfer7 transfer, LegalityAnalysis data) diff --git a/PKHeX.Core/Moves/MoveInfo.cs b/PKHeX.Core/Moves/MoveInfo.cs index 79c14fec9..17bb46b0b 100644 --- a/PKHeX.Core/Moves/MoveInfo.cs +++ b/PKHeX.Core/Moves/MoveInfo.cs @@ -41,6 +41,7 @@ public static byte GetPP(EntityContext context, ushort move) Gen7b => MoveInfo7b.PP, Gen8a => MoveInfo8a.PP, Gen8b => MoveInfo8.PP, + Gen9a => MoveInfo9a.PP, _ => throw new ArgumentOutOfRangeException(nameof(context)), }; @@ -53,6 +54,7 @@ public static byte GetPP(EntityContext context, ushort move) Gen8a => MoveInfo8a.DummiedMoves, Gen8b => MoveInfo8b.DummiedMoves, Gen9 => MoveInfo9.DummiedMoves, + Gen9a => MoveInfo9a.DummiedMoves, _ => [], }; @@ -170,9 +172,6 @@ public static bool IsSketchValid(ushort move, EntityContext context) (int)Struggle => false, (int)Chatter => false, - // Unreleased - (int)LightofRuin => false, - _ => IsMoveKnowable(move), }; @@ -185,7 +184,7 @@ public static bool IsSketchValid(ushort move, EntityContext context) { Gen2 when move is (int)SelfDestruct or (int)Explosion or (ushort)Mimic or (ushort)Metronome or (ushort)MirrorMove or (ushort)Transform or (ushort)SleepTalk => false, Gen6 when move is (int)ThousandArrows or (int)ThousandWaves or (int)LightofRuin => false, - Gen7 when move is (int)LightofRuin => false, + Gen7 or Gen8 when move is (int)LightofRuin => false, Gen8b when IsDummiedMove(MoveInfo8b.DummiedMoves, move) => false, Gen9 when IsDummiedMove(MoveInfo9.DummiedMoves, move) || DisallowSketch9.Contains(move) => false, _ => true, @@ -197,6 +196,7 @@ public static bool IsSketchValid(ushort move, EntityContext context) private static ReadOnlySpan DisallowSketch9 => [ (ushort)DarkVoid, + (ushort)LightofRuin, // No backwards transfer from ZA (ushort)HyperspaceFury, //(ushort)BreakneckBlitzP, // 3.0.0 has this move set, but this move is disallowed with our other checks (ushort)RevivalBlessing, @@ -222,6 +222,7 @@ public static bool IsSketchValid(ushort move, EntityContext context) Gen8a => Legal.MaxMoveID_8a, Gen8b => Legal.MaxMoveID_8b, Gen9 => Legal.MaxMoveID_9, + Gen9a => Legal.MaxMoveID_9a, _ => -1, }; @@ -229,7 +230,7 @@ public static bool IsSketchValid(ushort move, EntityContext context) { Gen1 => GetType(move, MoveInfo1.Type), // Bite, Gust, Karate Chop, Sand Attack >= Gen2 and <= Gen5 => GetType(move, MoveInfo5.Type), // Charm, Moonlight, Sweet Kiss - _ => GetType(move, MoveInfo9.Type), + _ => GetType(move, MoveInfo9a.Type), }; private static byte GetType(ushort move, ReadOnlySpan types) diff --git a/PKHeX.Core/Moves/MoveInfo9.cs b/PKHeX.Core/Moves/MoveInfo9.cs index 4435d1c56..56d051d48 100644 --- a/PKHeX.Core/Moves/MoveInfo9.cs +++ b/PKHeX.Core/Moves/MoveInfo9.cs @@ -7,105 +7,9 @@ namespace PKHeX.Core; /// internal static class MoveInfo9 { - public static ReadOnlySpan PP => - [ - 00, 35, 25, 10, 15, 20, 20, 15, 15, 15, 35, 30, 05, 10, 20, 30, 35, 35, 20, 15, - 20, 20, 25, 20, 30, 05, 10, 15, 15, 15, 25, 20, 05, 35, 15, 20, 20, 10, 15, 30, - 35, 20, 20, 30, 25, 40, 20, 15, 20, 20, 20, 30, 25, 15, 30, 25, 05, 15, 10, 05, - 20, 20, 20, 05, 35, 20, 20, 20, 20, 20, 15, 25, 15, 10, 20, 25, 10, 35, 30, 15, - 10, 40, 10, 15, 30, 15, 20, 10, 15, 10, 05, 10, 10, 25, 10, 20, 40, 30, 30, 20, - 20, 15, 10, 40, 15, 05, 30, 10, 20, 10, 40, 40, 20, 30, 30, 20, 30, 10, 10, 20, - 05, 10, 30, 20, 20, 20, 05, 15, 15, 20, 10, 15, 35, 20, 15, 05, 10, 30, 15, 40, - 20, 10, 10, 05, 10, 30, 10, 15, 20, 15, 40, 20, 10, 05, 15, 10, 05, 10, 15, 30, - 30, 10, 10, 20, 10, 01, 01, 10, 25, 10, 05, 15, 25, 15, 10, 15, 30, 05, 40, 15, - 10, 25, 10, 30, 10, 20, 10, 10, 10, 10, 10, 20, 05, 40, 05, 05, 15, 05, 10, 05, - 10, 10, 10, 10, 20, 20, 40, 15, 05, 20, 20, 25, 05, 15, 10, 05, 20, 15, 20, 25, - 20, 05, 30, 05, 10, 20, 40, 05, 20, 40, 20, 15, 35, 10, 05, 05, 05, 15, 05, 20, - 05, 05, 15, 20, 10, 05, 05, 15, 10, 15, 15, 10, 10, 10, 20, 10, 10, 10, 10, 15, - 15, 15, 10, 20, 20, 10, 20, 20, 20, 20, 20, 10, 10, 10, 20, 20, 05, 15, 10, 10, - 15, 10, 20, 05, 05, 10, 10, 20, 05, 10, 20, 10, 20, 20, 20, 05, 05, 15, 20, 10, - 15, 20, 15, 05, 10, 15, 10, 05, 05, 10, 15, 10, 05, 20, 25, 05, 40, 15, 05, 40, - 15, 20, 20, 05, 15, 20, 20, 15, 15, 05, 10, 30, 20, 30, 15, 05, 40, 15, 05, 20, - 05, 15, 25, 25, 15, 20, 15, 20, 15, 20, 10, 20, 20, 05, 05, 05, 05, 40, 10, 10, - 05, 10, 10, 15, 10, 20, 15, 30, 10, 20, 05, 10, 10, 15, 10, 10, 05, 15, 05, 10, - 10, 30, 20, 20, 10, 10, 05, 05, 10, 05, 20, 10, 20, 10, 15, 10, 20, 20, 20, 15, - 15, 10, 15, 15, 15, 10, 10, 10, 20, 10, 30, 05, 10, 15, 10, 10, 05, 20, 30, 10, - 30, 15, 15, 15, 15, 30, 10, 20, 15, 10, 10, 20, 15, 05, 05, 15, 15, 05, 10, 05, - 20, 05, 15, 20, 05, 20, 20, 20, 20, 10, 20, 10, 15, 20, 15, 10, 10, 05, 10, 05, - 05, 10, 05, 05, 10, 05, 05, 05, 15, 10, 10, 10, 10, 10, 10, 15, 20, 15, 10, 15, - 10, 15, 10, 20, 10, 10, 10, 20, 20, 20, 20, 20, 15, 15, 15, 15, 15, 15, 20, 15, - 10, 15, 15, 15, 15, 10, 10, 10, 10, 10, 15, 15, 15, 15, 05, 05, 15, 05, 10, 10, - 10, 20, 20, 20, 10, 10, 30, 15, 15, 10, 15, 25, 10, 15, 10, 10, 10, 20, 10, 10, - 10, 10, 10, 15, 15, 05, 05, 10, 10, 10, 05, 05, 10, 05, 05, 15, 10, 05, 05, 05, - 10, 10, 10, 10, 20, 25, 10, 20, 30, 25, 20, 20, 15, 20, 15, 20, 20, 10, 10, 10, - 10, 10, 20, 10, 30, 15, 10, 10, 10, 20, 20, 05, 05, 05, 20, 10, 10, 20, 15, 20, - 20, 10, 20, 30, 10, 10, 40, 40, 30, 20, 40, 20, 20, 10, 10, 10, 10, 05, 10, 10, - 05, 05, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, - 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 05, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 40, 15, 20, 30, 20, 15, 15, 20, 10, 15, - 15, 10, 05, 10, 10, 20, 15, 10, 15, 15, 15, 05, 15, 20, 20, 01, 01, 01, 01, 01, - 01, 01, 01, 01, 05, 05, 10, 10, 10, 20, 10, 10, 10, 05, 05, 20, 10, 10, 10, 01, - 05, 15, 05, 01, 01, 01, 01, 01, 01, 10, 15, 15, 20, 20, 20, 20, 15, 15, 10, 10, - 05, 20, 05, 10, 05, 15, 10, 10, 05, 15, 20, 10, 10, 15, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 05, 10, 15, 10, 15, - 05, 05, 05, 10, 15, 40, 10, 10, 10, 15, 10, 10, 10, 10, 05, 05, 05, 10, 05, 20, - 10, 10, 05, 20, 20, 10, 10, 05, 05, 05, 40, 10, 20, 10, 10, 10, 10, 05, 05, 15, - 05, 10, 10, 10, 05, 05, 05, 15, 10, 10, 15, 05, 10, 10, 10, 05, 10, 10, 05, 10, - 10, 10, 10, 10, 15, 15, 10, 10, 10, 05, 15, 10, 10, 10, 10, 10, 10, 15, 15, 05, - 10, 15, 05, 01, 15, 10, 15, 10, 10, 10, 10, 10, 10, 10, 05, 15, 15, 10, 05, 05, - 10, 10, 10, 10, 20, 20, 20, 05, 10, 10, 05, 10, 05, 05, 10, 20, 10, 10, 10, 10, - 10, 05, 15, 10, 10, 10, 05, 05, 10, 05, 05, 10, 10, 15, 10, 10, 15, 10, 15, 05, - ]; + public static ReadOnlySpan PP => MoveInfo9a.PP; // subset, just return all - public static ReadOnlySpan Type => - [ - 00, 00, 01, 00, 00, 00, 00, 09, 14, 12, 00, 00, 00, 00, 00, 00, 02, 02, 00, 02, - 00, 00, 11, 00, 01, 00, 01, 01, 04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, - 03, 06, 06, 00, 16, 00, 00, 00, 00, 00, 00, 03, 09, 09, 14, 10, 10, 10, 14, 14, - 13, 10, 14, 00, 02, 02, 01, 01, 01, 01, 00, 11, 11, 11, 00, 11, 11, 03, 11, 11, - 11, 06, 15, 09, 12, 12, 12, 12, 05, 04, 04, 04, 03, 13, 13, 13, 13, 13, 00, 00, - 13, 07, 00, 00, 00, 00, 00, 00, 00, 07, 10, 00, 13, 13, 14, 13, 00, 00, 00, 02, - 00, 00, 07, 03, 03, 04, 09, 10, 10, 00, 00, 00, 00, 13, 13, 00, 01, 00, 13, 03, - 00, 06, 00, 02, 00, 10, 00, 11, 00, 13, 00, 03, 10, 00, 00, 04, 13, 05, 00, 00, - 00, 00, 00, 00, 00, 00, 00, 01, 16, 06, 00, 07, 09, 00, 07, 00, 00, 02, 11, 01, - 07, 14, 00, 01, 00, 16, 17, 00, 03, 04, 10, 04, 12, 00, 07, 00, 14, 01, 04, 00, - 15, 05, 11, 00, 17, 05, 00, 00, 00, 12, 06, 08, 00, 00, 00, 00, 00, 00, 00, 00, - 00, 09, 04, 01, 06, 15, 00, 00, 16, 00, 00, 08, 08, 01, 00, 11, 17, 00, 01, 15, - 10, 09, 16, 13, 00, 00, 05, 07, 13, 01, 10, 16, 00, 00, 00, 00, 00, 09, 14, 16, - 16, 09, 16, 00, 01, 00, 00, 00, 12, 16, 00, 13, 13, 00, 00, 11, 01, 13, 00, 01, - 01, 00, 16, 00, 09, 13, 13, 00, 07, 16, 00, 10, 01, 00, 06, 13, 13, 02, 00, 09, - 04, 14, 11, 00, 00, 03, 00, 09, 10, 08, 07, 00, 11, 16, 02, 09, 00, 05, 06, 08, - 11, 00, 13, 10, 06, 07, 13, 01, 04, 14, 10, 11, 02, 14, 08, 00, 00, 15, 11, 01, - 02, 04, 03, 00, 12, 11, 10, 13, 11, 15, 05, 12, 10, 08, 13, 02, 13, 13, 01, 01, - 08, 13, 10, 00, 00, 02, 02, 00, 08, 06, 01, 16, 16, 16, 16, 13, 00, 13, 00, 13, - 03, 00, 00, 00, 13, 13, 16, 00, 11, 16, 03, 13, 10, 12, 09, 01, 01, 05, 03, 16, - 16, 10, 11, 02, 06, 06, 15, 15, 05, 01, 01, 01, 11, 02, 04, 16, 00, 16, 08, 14, - 14, 07, 12, 14, 09, 07, 04, 13, 13, 08, 08, 00, 02, 13, 15, 12, 09, 11, 11, 05, - 03, 03, 08, 08, 05, 00, 05, 11, 02, 00, 06, 12, 11, 10, 06, 06, 06, 05, 00, 15, - 15, 13, 00, 09, 16, 11, 07, 07, 16, 05, 13, 13, 13, 13, 03, 08, 06, 13, 13, 05, - 01, 09, 03, 06, 08, 13, 12, 10, 09, 03, 01, 03, 16, 00, 00, 00, 00, 00, 00, 03, - 13, 01, 13, 10, 00, 13, 07, 02, 08, 01, 09, 16, 02, 00, 00, 01, 00, 09, 10, 09, - 11, 12, 06, 04, 14, 15, 00, 12, 12, 04, 15, 13, 11, 01, 10, 09, 11, 06, 11, 16, - 13, 00, 02, 00, 08, 09, 00, 00, 01, 14, 12, 09, 09, 14, 14, 16, 14, 09, 09, 12, - 01, 01, 03, 04, 06, 06, 07, 07, 00, 12, 12, 11, 11, 14, 17, 16, 16, 17, 17, 17, - 11, 17, 12, 17, 17, 17, 00, 17, 08, 00, 00, 05, 10, 13, 10, 09, 11, 17, 12, 03, - 06, 17, 12, 00, 12, 17, 00, 00, 17, 12, 00, 06, 01, 02, 04, 04, 04, 17, 10, 04, - 02, 16, 00, 00, 01, 01, 02, 02, 03, 03, 04, 04, 05, 05, 06, 06, 07, 07, 08, 08, - 09, 09, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 12, 04, - 06, 03, 07, 16, 10, 14, 17, 04, 11, 11, 11, 00, 03, 00, 08, 16, 06, 08, 13, 06, - 09, 16, 09, 13, 08, 03, 00, 15, 11, 13, 02, 15, 15, 16, 14, 07, 16, 10, 17, 07, - 12, 00, 00, 13, 09, 17, 13, 04, 07, 05, 10, 13, 07, 08, 07, 00, 12, 17, 00, 12, - 09, 12, 13, 13, 08, 07, 17, 05, 15, 12, 10, 02, 12, 10, 12, 09, 13, 16, 11, 14, - 17, 00, 08, 00, 15, 10, 16, 00, 01, 05, 13, 15, 00, 01, 12, 10, 00, 09, 06, 12, - 00, 01, 07, 14, 03, 10, 02, 17, 15, 13, 05, 04, 16, 11, 08, 15, 01, 17, 11, 11, - 09, 08, 08, 12, 15, 11, 12, 11, 11, 17, 17, 10, 16, 16, 01, 15, 08, 13, 08, 15, - 05, 03, 17, 11, 12, 00, 06, 09, 16, 07, 03, 01, 10, 14, 02, 04, 11, 16, 10, 12, - 15, 13, 16, 01, 14, 07, 13, 03, 13, 00, 05, 17, 13, 09, 10, 11, 14, 01, 04, 03, - 13, 07, 08, 01, 07, 16, 02, 12, 04, 13, 13, 00, 06, 01, 07, 13, 15, 10, 11, 08, - 00, 14, 15, 00, 05, 10, 03, 00, 00, 16, 11, 09, 10, 00, 08, 13, 10, 16, 01, 12, - 00, 14, 00, 14, 06, 11, 10, 00, 13, 07, 09, 09, 12, 08, 16, 10, 09, 16, 03, 01, - 17, 00, 11, 11, 11, 12, 00, 15, 09, 12, 05, 08, 08, 15, 17, 09, 12, 13, 01, 03, - ]; + public static ReadOnlySpan Type => MoveInfo9a.Type; // subset, just return all /// /// Bitflag indexes of moves that are not usable in game. diff --git a/PKHeX.Core/Moves/MoveInfo9a.cs b/PKHeX.Core/Moves/MoveInfo9a.cs new file mode 100644 index 000000000..12462e746 --- /dev/null +++ b/PKHeX.Core/Moves/MoveInfo9a.cs @@ -0,0 +1,129 @@ +using System; + +namespace PKHeX.Core; + +/// +/// Details about moves in +/// +internal static class MoveInfo9a +{ + public static ReadOnlySpan PP => + [ + 35, 35, 25, 10, 15, 20, 20, 15, 15, 15, 35, 30, 05, 10, 20, 30, 35, 35, 20, 15, + 20, 20, 25, 20, 30, 05, 10, 15, 15, 15, 25, 20, 05, 35, 15, 20, 20, 10, 15, 30, + 35, 20, 20, 30, 25, 40, 20, 15, 20, 20, 20, 30, 25, 15, 30, 25, 05, 15, 10, 05, + 20, 20, 20, 05, 35, 20, 20, 20, 20, 20, 15, 25, 15, 10, 20, 25, 10, 35, 30, 15, + 10, 40, 10, 15, 30, 15, 20, 10, 15, 10, 05, 10, 10, 25, 10, 20, 40, 30, 30, 20, + 20, 15, 10, 40, 15, 05, 30, 10, 20, 10, 40, 40, 20, 30, 30, 20, 30, 10, 10, 20, + 05, 10, 30, 20, 20, 20, 05, 15, 15, 20, 10, 15, 35, 20, 15, 05, 10, 30, 15, 40, + 20, 10, 10, 05, 10, 30, 10, 15, 20, 15, 40, 20, 10, 05, 15, 10, 05, 10, 15, 30, + 30, 10, 10, 20, 10, 01, 01, 10, 25, 10, 05, 15, 25, 15, 10, 15, 30, 05, 40, 15, + 10, 25, 10, 30, 10, 20, 10, 10, 10, 10, 10, 20, 05, 40, 05, 05, 15, 05, 10, 05, + 10, 10, 10, 10, 20, 20, 40, 15, 05, 20, 20, 25, 05, 15, 10, 05, 20, 15, 20, 25, + 20, 05, 30, 05, 10, 20, 40, 05, 20, 40, 20, 15, 35, 10, 05, 05, 05, 15, 05, 20, + 05, 05, 15, 20, 10, 05, 05, 15, 10, 15, 15, 10, 10, 10, 20, 10, 10, 10, 10, 15, + 15, 15, 10, 20, 20, 10, 20, 20, 20, 20, 20, 10, 10, 10, 20, 20, 05, 15, 10, 10, + 15, 10, 20, 05, 05, 10, 10, 20, 05, 10, 20, 10, 20, 20, 20, 05, 05, 15, 20, 10, + 15, 20, 15, 05, 10, 15, 10, 05, 05, 10, 15, 10, 05, 20, 25, 05, 40, 15, 05, 40, + 15, 20, 20, 05, 15, 20, 20, 15, 15, 05, 10, 30, 20, 30, 15, 05, 40, 15, 05, 20, + 05, 15, 25, 25, 15, 20, 15, 20, 15, 20, 10, 20, 20, 05, 05, 05, 05, 40, 10, 10, + 05, 10, 10, 15, 10, 20, 15, 30, 10, 20, 05, 10, 10, 15, 10, 10, 05, 15, 05, 10, + 10, 30, 20, 20, 10, 10, 05, 05, 10, 05, 20, 10, 20, 10, 15, 10, 20, 20, 20, 15, + 15, 10, 15, 15, 15, 10, 10, 10, 20, 10, 30, 05, 10, 15, 10, 10, 05, 20, 30, 10, + 30, 15, 15, 15, 15, 30, 10, 20, 15, 10, 10, 20, 15, 05, 05, 15, 15, 05, 10, 05, + 20, 05, 15, 20, 05, 20, 20, 20, 20, 10, 20, 10, 15, 20, 15, 10, 10, 05, 10, 05, + 05, 10, 05, 05, 10, 05, 05, 05, 15, 10, 10, 10, 10, 10, 10, 15, 20, 15, 10, 15, + 10, 15, 10, 20, 10, 10, 10, 20, 20, 20, 20, 20, 15, 15, 15, 15, 15, 15, 20, 15, + 10, 15, 15, 15, 15, 10, 10, 10, 10, 10, 15, 15, 15, 15, 05, 05, 15, 05, 10, 10, + 10, 20, 20, 20, 10, 10, 30, 15, 15, 10, 15, 25, 10, 15, 10, 10, 10, 20, 10, 10, + 10, 10, 10, 15, 15, 05, 05, 10, 10, 10, 05, 05, 10, 05, 05, 15, 10, 05, 05, 05, + 10, 10, 10, 10, 20, 25, 10, 20, 30, 25, 20, 20, 15, 20, 15, 20, 20, 10, 10, 10, + 10, 10, 20, 10, 30, 15, 10, 10, 10, 20, 20, 05, 05, 05, 20, 10, 10, 20, 15, 20, + 20, 10, 20, 30, 10, 10, 40, 40, 30, 20, 40, 20, 20, 10, 10, 10, 10, 05, 10, 10, + 05, 05, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, + 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 05, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 40, 15, 20, 30, 20, 15, 15, 20, 10, 15, + 15, 10, 05, 10, 10, 20, 15, 10, 15, 15, 15, 05, 15, 20, 20, 01, 01, 01, 01, 01, + 01, 01, 01, 01, 05, 05, 10, 10, 10, 20, 10, 10, 10, 05, 05, 20, 10, 10, 10, 01, + 05, 15, 05, 01, 01, 01, 01, 01, 01, 10, 15, 15, 20, 20, 20, 20, 15, 15, 10, 10, + 05, 20, 05, 10, 05, 15, 10, 10, 05, 15, 20, 10, 10, 15, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 05, 10, 15, 10, 15, + 05, 05, 05, 10, 15, 40, 10, 10, 10, 15, 10, 10, 10, 10, 05, 05, 05, 10, 05, 20, + 10, 10, 05, 20, 20, 10, 10, 05, 05, 05, 40, 10, 20, 10, 10, 10, 10, 05, 05, 15, + 05, 10, 10, 10, 05, 05, 05, 15, 10, 10, 15, 05, 10, 10, 10, 05, 10, 10, 05, 10, + 10, 10, 10, 10, 15, 15, 10, 10, 10, 05, 15, 10, 10, 10, 10, 10, 10, 15, 15, 05, + 10, 15, 05, 01, 15, 10, 15, 10, 10, 10, 10, 10, 10, 10, 05, 35, 35, 10, 05, 05, + 10, 10, 10, 10, 20, 20, 20, 05, 10, 10, 05, 10, 05, 05, 10, 20, 10, 10, 10, 10, + 10, 05, 15, 10, 10, 10, 05, 05, 10, 05, 05, 10, 10, 15, 10, 10, 15, 10, 15, 05, + 10, + ]; + + public static ReadOnlySpan Type => + [ + 00, 00, 01, 00, 00, 00, 00, 09, 14, 12, 00, 00, 00, 00, 00, 00, 02, 02, 00, 02, + 00, 00, 11, 00, 01, 00, 01, 01, 04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 03, 06, 06, 00, 16, 00, 00, 00, 00, 00, 00, 03, 09, 09, 14, 10, 10, 10, 14, 14, + 13, 10, 14, 00, 02, 02, 01, 01, 01, 01, 00, 11, 11, 11, 11, 11, 11, 03, 11, 11, + 11, 06, 15, 09, 12, 12, 12, 12, 05, 04, 04, 04, 03, 13, 13, 13, 13, 13, 00, 00, + 13, 07, 00, 00, 00, 00, 00, 00, 00, 07, 10, 00, 13, 13, 14, 13, 00, 00, 00, 02, + 00, 00, 07, 03, 03, 04, 09, 10, 10, 00, 00, 00, 00, 13, 13, 00, 01, 00, 13, 03, + 00, 06, 00, 02, 00, 10, 00, 11, 00, 13, 00, 03, 10, 00, 00, 04, 13, 05, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 01, 16, 06, 00, 07, 09, 00, 07, 00, 00, 02, 11, 01, + 07, 14, 00, 01, 00, 16, 17, 00, 03, 04, 10, 04, 12, 00, 07, 00, 14, 01, 04, 00, + 15, 05, 11, 00, 17, 05, 00, 00, 00, 12, 06, 08, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 09, 04, 01, 06, 15, 00, 00, 16, 00, 00, 08, 08, 01, 00, 11, 17, 00, 01, 15, + 10, 09, 16, 13, 00, 00, 05, 07, 13, 01, 10, 16, 00, 00, 00, 00, 00, 09, 14, 16, + 16, 09, 16, 00, 01, 00, 00, 00, 12, 16, 00, 13, 13, 00, 00, 11, 01, 13, 00, 01, + 01, 00, 16, 00, 09, 13, 13, 00, 07, 16, 00, 10, 01, 00, 06, 13, 13, 02, 00, 09, + 04, 14, 11, 00, 00, 03, 00, 09, 10, 08, 07, 00, 11, 16, 02, 09, 00, 05, 06, 08, + 11, 00, 13, 10, 06, 07, 13, 01, 04, 14, 10, 11, 02, 14, 08, 00, 00, 15, 11, 01, + 02, 04, 03, 00, 12, 11, 10, 13, 11, 15, 05, 12, 10, 08, 13, 02, 13, 13, 01, 01, + 08, 13, 10, 00, 00, 02, 02, 00, 08, 06, 01, 16, 16, 16, 16, 13, 00, 13, 00, 13, + 03, 00, 00, 00, 13, 13, 16, 00, 11, 16, 03, 13, 10, 12, 09, 01, 01, 05, 03, 16, + 16, 10, 11, 02, 06, 06, 15, 15, 05, 01, 01, 01, 11, 02, 04, 16, 00, 16, 08, 14, + 14, 07, 12, 14, 09, 07, 04, 13, 13, 08, 08, 00, 02, 13, 15, 12, 09, 11, 11, 05, + 03, 03, 08, 08, 05, 00, 05, 11, 02, 00, 06, 12, 11, 10, 06, 06, 06, 05, 00, 15, + 15, 13, 00, 09, 16, 11, 07, 07, 16, 05, 13, 13, 13, 13, 03, 08, 06, 13, 13, 05, + 01, 09, 03, 06, 08, 13, 12, 10, 09, 03, 01, 03, 16, 00, 00, 00, 00, 00, 00, 03, + 13, 01, 13, 10, 00, 13, 07, 02, 08, 01, 09, 16, 02, 00, 00, 01, 00, 09, 10, 09, + 11, 12, 06, 04, 14, 15, 00, 12, 12, 04, 15, 13, 11, 01, 10, 09, 11, 06, 11, 16, + 13, 00, 02, 00, 08, 09, 00, 00, 01, 14, 12, 09, 09, 14, 14, 16, 14, 09, 09, 12, + 01, 01, 03, 04, 06, 06, 07, 07, 00, 12, 12, 11, 11, 14, 17, 16, 16, 17, 17, 17, + 11, 17, 12, 17, 17, 17, 00, 17, 08, 00, 00, 05, 10, 13, 10, 09, 11, 17, 12, 03, + 06, 17, 12, 00, 12, 17, 00, 00, 17, 12, 00, 06, 01, 02, 04, 04, 04, 17, 10, 04, + 02, 16, 00, 00, 01, 01, 02, 02, 03, 03, 04, 04, 05, 05, 06, 06, 07, 07, 08, 08, + 09, 09, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 12, 04, + 06, 03, 07, 16, 10, 14, 17, 04, 11, 11, 11, 00, 03, 00, 08, 16, 06, 08, 13, 06, + 09, 16, 09, 13, 08, 03, 00, 15, 11, 13, 02, 15, 15, 16, 14, 07, 16, 10, 17, 07, + 12, 00, 00, 13, 09, 17, 13, 04, 07, 05, 10, 13, 07, 08, 07, 00, 12, 17, 00, 12, + 09, 12, 13, 13, 08, 07, 17, 05, 15, 12, 10, 02, 12, 10, 12, 09, 13, 16, 11, 14, + 17, 00, 08, 00, 15, 10, 16, 00, 01, 05, 13, 15, 00, 01, 12, 10, 00, 09, 06, 12, + 00, 01, 07, 14, 03, 10, 02, 17, 15, 13, 05, 04, 16, 11, 08, 15, 01, 17, 11, 11, + 09, 08, 08, 12, 15, 11, 12, 11, 11, 17, 17, 10, 16, 16, 01, 15, 08, 13, 08, 15, + 05, 03, 17, 11, 12, 00, 06, 09, 16, 07, 03, 01, 10, 14, 02, 04, 11, 16, 10, 12, + 15, 13, 16, 01, 14, 07, 13, 03, 13, 00, 05, 17, 13, 09, 10, 11, 14, 01, 04, 03, + 13, 07, 08, 01, 07, 16, 02, 12, 04, 13, 13, 00, 06, 01, 07, 13, 15, 10, 11, 08, + 00, 14, 15, 00, 05, 10, 03, 00, 00, 16, 11, 09, 10, 00, 08, 13, 10, 16, 01, 12, + 00, 14, 00, 14, 06, 11, 10, 00, 13, 07, 09, 09, 12, 08, 16, 10, 09, 16, 03, 01, + 17, 00, 11, 11, 11, 12, 00, 15, 09, 12, 05, 08, 08, 15, 17, 09, 12, 13, 01, 03, + 15 + ]; + + /// + /// Bitflag indexes of moves that are not usable in game. + /// + /// + /// This is a bitflag array, where each bit represents a move. If the bit is set, the move is not usable in game. + /// Instead of allocating a hashset, this is a more efficient method (no allocation) with O(1) lookup (faster than HashSet's O(1) lookup). + /// + public static ReadOnlySpan DummiedMoves => + [ + 0x7E, 0xBC, 0xB0, 0xDF, 0x29, 0x82, 0x0E, 0x40, 0x7E, 0x01, 0x05, 0x04, 0x69, 0xC8, 0xA1, 0x3A, 0xDD, 0xDD, + 0x3F, 0xDD, 0xE3, 0xAF, 0x3F, 0x6F, 0xC6, 0xC2, 0xF5, 0x77, 0x7C, 0x62, 0x5B, 0xF8, 0xDD, 0xCF, 0xFD, 0xFA, + 0xFF, 0xFD, 0xFE, 0x55, 0xFF, 0xA6, 0xC5, 0xA4, 0xFE, 0xFF, 0xF9, 0xFD, 0xBF, 0x2A, 0x06, 0x86, 0x08, 0xA4, + 0x83, 0xA9, 0xCF, 0xFD, 0xFF, 0xFD, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0x35, 0x6C, 0xAB, 0xFF, 0xE7, 0x2E, 0x13, + 0x7C, 0x68, 0xA0, 0xDD, 0x05, 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F, 0x7F, 0xDF, 0xFF, 0xBF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + ]; +} diff --git a/PKHeX.Core/MysteryGifts/WA8.cs b/PKHeX.Core/MysteryGifts/WA8.cs index aad3ffba3..889fbf6d7 100644 --- a/PKHeX.Core/MysteryGifts/WA8.cs +++ b/PKHeX.Core/MysteryGifts/WA8.cs @@ -7,14 +7,13 @@ namespace PKHeX.Core; /// /// Generation 8 Mystery Gift Template File, same as with fields at the end. /// -public sealed class WA8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDynamaxLevel, +public sealed class WA8(Memory raw) : DataMysteryGift(raw), ILangNick, INature, IGigantamax, IDynamaxLevel, IRibbonIndex, IMemoryOT, IRelearn, IEncounterServerDate, ILangNicknamedTemplate, IGanbaru, IAlpha, IMetLevel, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8 { public WA8() : this(new byte[Size]) { } - public WA8(Memory raw) : base(raw) { } public override WA8 Clone() => new(Data.ToArray()); public const int Size = 0x2C8; @@ -105,9 +104,7 @@ private uint GetShinyXor() // Player owned anti-shiny fixed PID if (ID32 == 0) return uint.MaxValue; - - var xor = PID ^ ID32; - return (xor >> 16) ^ (xor & 0xFFFF); + return ShinyUtil.GetShinyXor(PID, ID32); } public override uint ID32 @@ -483,10 +480,7 @@ public override PA8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) pk.Version = GameVersion.PLA; if (OTGender >= 2) - { - pk.TID16 = tr.TID16; - pk.SID16 = tr.SID16; - } + pk.ID32 = tr.ID32; var date = IsDateRestricted && this.GetDistributionWindow(out var dt) ? dt.GetGenerateDate() : EncounterDate.GetDateSwitch(); if (IsDateLockJapanese && language != (int)LanguageID.Japanese && date < new DateOnly(2022, 5, 20)) // 2022/05/18 @@ -847,7 +841,7 @@ public void SetRibbon(int index, bool value = true) if (GetRibbon(index)) return; var openIndex = RibbonSpan.IndexOf(RibbonByteNone); - ArgumentOutOfRangeException.ThrowIfNegative(openIndex, nameof(openIndex)); // Full? + ArgumentOutOfRangeException.ThrowIfNegative(openIndex); // Full? SetRibbonAtIndex(openIndex, (byte)index); } else diff --git a/PKHeX.Core/MysteryGifts/WA9.cs b/PKHeX.Core/MysteryGifts/WA9.cs new file mode 100644 index 000000000..85022b70e --- /dev/null +++ b/PKHeX.Core/MysteryGifts/WA9.cs @@ -0,0 +1,855 @@ +using System; +using static PKHeX.Core.RibbonIndex; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +/// +/// Generation 9 Mystery Gift Template File +/// +public sealed class WA9(Memory raw) : DataMysteryGift(raw), ILangNick, INature, IAlpha, IRibbonIndex, IMemoryOT, + ILangNicknamedTemplate, IEncounterServerDate, IRelearn, IMetLevel, ISeedCorrelation64, + IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, + IRibbonSetCommon8, IRibbonSetMark8, IRibbonSetCommon9, IRibbonSetMark9, IEncounterMarkExtra +{ + public WA9() : this(new byte[Size]) { } + public override WC9 Clone() => new(Data.ToArray()); + + public const int Size = 0x2C8; + + public override byte Generation => 9; + public override EntityContext Context => EntityContext.Gen9a; + public override bool FatefulEncounter => true; + + public enum GiftType : byte + { + None = 0, + Pokemon = 1, + Item = 2, + BP = 3, + Clothing = 4, + } + + public bool CanBeReceivedByVersion(PKM pk) => pk.Version is GameVersion.ZA; + + // General Card Properties + public override int CardID + { + get => ReadUInt16LittleEndian(Data[0x8..]); + set => WriteUInt16LittleEndian(Data[0x8..], (ushort)value); + } + + public byte RestrictVersion { get => Data[0xE]; set => Data[0xE] = value; } // 0x01 = ZA only (only one game in this Context, so always ZA). + public byte CardFlags { get => Data[0x10]; set => Data[0x10] = value; } + public GiftType CardType { get => (GiftType)Data[0x11]; set => Data[0x11] = (byte)value; } + public bool GiftRepeatable { get => (CardFlags & 1) == 0; set => CardFlags = (byte)((CardFlags & ~1) | (value ? 0 : 1)); } + public override bool GiftUsed { get => false; set { } } + + public int CardTitleIndex + { + get => Data[0x15]; + set => Data[0x15] = (byte) value; + } + + public override string CardTitle + { + get => "Mystery Gift"; // TODO: Use text string from CardTitleIndex + set => throw new Exception(); + } + + // Item Properties + public override bool IsItem { get => CardType == GiftType.Item; set { if (value) CardType = GiftType.Item; } } + + public override int ItemID + { + get => GetItem(0); + set => SetItem(0, (ushort)value); + } + + public override int Quantity + { + get => GetQuantity(0); + set => SetQuantity(0, (ushort)value); + } + + public int GetItem(int index) => ReadUInt16LittleEndian(Data[(0x18 + (0x4 * index))..]); + public void SetItem(int index, ushort item) => WriteUInt16LittleEndian(Data[(0x18 + (4 * index))..], item); + public int GetQuantity(int index) => ReadUInt16LittleEndian(Data[(0x1A + (0x4 * index))..]); + public void SetQuantity(int index, ushort quantity) => WriteUInt16LittleEndian(Data[(0x1A + (4 * index))..], quantity); + + // Pokémon Properties + public override bool IsEntity { get => CardType == GiftType.Pokemon; set { if (value) CardType = GiftType.Pokemon; } } + + public override bool IsShiny => Shiny.IsShiny(); + + public override Shiny Shiny => PIDType switch + { + ShinyType8.FixedValue => FixedShinyType(), + ShinyType8.Random => Shiny.Random, + ShinyType8.Never => Shiny.Never, + ShinyType8.AlwaysStar => Shiny.AlwaysStar, + ShinyType8.AlwaysSquare => Shiny.AlwaysSquare, + _ => throw new ArgumentOutOfRangeException(), + }; + + private Shiny FixedShinyType() => GetShinyXor() switch + { + 0 => Shiny.AlwaysSquare, + <= 15 => Shiny.AlwaysStar, + _ => Shiny.Never, + }; + + private uint GetShinyXor() + { + // Player owned anti-shiny fixed PID + if (ID32 == 0) + return uint.MaxValue; + return ShinyUtil.GetShinyXor(PID, ID32); + } + + // When applying the TID32, the game sets the DisplayTID7 directly, then sets PA9.DisplaySID7 as (wc9.DisplaySID7 - wc9.CardID) + // Since we expose the 16bit (PA9) component values here, just adjust them accordingly with an inlined calc. + public override uint ID32 { get => ReadUInt32LittleEndian(Data[0x18..]); set => WriteUInt32LittleEndian(Data[0x18..], value); } + + public int OriginGame { get => ReadInt32LittleEndian(Data[0x1C..]); set => WriteInt32LittleEndian(Data[0x1C..], value); } + public uint EncryptionConstant { get => ReadUInt32LittleEndian(Data[0x20..]); set => WriteUInt32LittleEndian(Data[0x20..], value); } + public uint PID { get => ReadUInt32LittleEndian(Data[0x24..]); set => WriteUInt32LittleEndian(Data[0x24..], value); } + + public override ushort TID16 + { + get => (ushort)(ID32 & 0xFFFF); + set => ID32 = (uint)SID16 << 16 | value; + } + + public override ushort SID16 + { + get => (ushort)(ID32 >> 16); + set => ID32 = (uint)value << 16 | TID16; + } + + // Nicknames, OT Names 0x28 - 0x220 + public override ushort EggLocation { get => ReadUInt16LittleEndian(Data[0x258..]); set => WriteUInt16LittleEndian(Data[0x258..], value); } + public override ushort Location { get => ReadUInt16LittleEndian(Data[0x25A..]); set => WriteUInt16LittleEndian(Data[0x25A..], value); } + public override byte Ball { get => (byte)ReadUInt16LittleEndian(Data[0x25C..]); set => WriteUInt16LittleEndian(Data[0x25C..], value); } + public override int HeldItem { get => ReadUInt16LittleEndian(Data[0x25E..]); set => WriteUInt16LittleEndian(Data[0x25E..], (ushort)value); } + public ushort Move1 { get => ReadUInt16LittleEndian(Data[0x260..]); set => WriteUInt16LittleEndian(Data[0x260..], value); } + public ushort Move2 { get => ReadUInt16LittleEndian(Data[0x262..]); set => WriteUInt16LittleEndian(Data[0x262..], value); } + public ushort Move3 { get => ReadUInt16LittleEndian(Data[0x264..]); set => WriteUInt16LittleEndian(Data[0x264..], value); } + public ushort Move4 { get => ReadUInt16LittleEndian(Data[0x266..]); set => WriteUInt16LittleEndian(Data[0x266..], value); } + public ushort RelearnMove1 { get => ReadUInt16LittleEndian(Data[0x268..]); set => WriteUInt16LittleEndian(Data[0x268..], value); } + public ushort RelearnMove2 { get => ReadUInt16LittleEndian(Data[0x26A..]); set => WriteUInt16LittleEndian(Data[0x26A..], value); } + public ushort RelearnMove3 { get => ReadUInt16LittleEndian(Data[0x26C..]); set => WriteUInt16LittleEndian(Data[0x26C..], value); } + public ushort RelearnMove4 { get => ReadUInt16LittleEndian(Data[0x26E..]); set => WriteUInt16LittleEndian(Data[0x26E..], value); } + + public override ushort Species { get => SpeciesConverter.GetNational9(ReadUInt16LittleEndian(Data[0x270..])); set => WriteUInt16LittleEndian(Data[0x270..], SpeciesConverter.GetInternal9(value)); } + public override byte Form { get => Data[0x272]; set => Data[0x272] = value; } + public override byte Gender { get => Data[0x273]; set => Data[0x273] = value; } + public override byte Level { get => Data[0x274]; set => Data[0x274] = value; } + public override bool IsEgg { get => Data[0x275] == 1; set => Data[0x275] = value ? (byte)1 : (byte)0; } // before level; might be a flag for random level? + public Nature Nature + { + get + { + var value = (Nature)Data[0x276]; + if (value >= Nature.Random) + return Nature.Random; + return value; + } + set + { + if (value == Nature.Random) + value = (Nature)255; + Data[0x276] = (byte)value; + } + } + + public int AbilityType { get => Data[0x277]; set => Data[0x277] = (byte)value; } + + public ShinyType8 PIDType { get => (ShinyType8)Data[0x278]; set => Data[0x278] = (byte)value; } + + public byte MetLevel { get => Data[0x279]; set => Data[0x279] = value; } + + // Ribbons 0x24C-0x26C + private const int RibbonBytesOffset = 0x27A; + private const int RibbonBytesCount = 0x20; + private const byte RibbonByteNone = 0xFF; // signed -1 + + private Span RibbonSpan => Data.Slice(RibbonBytesOffset, RibbonBytesCount); + + public bool HasMarkEncounter8 + { + get + { + foreach (var value in RibbonSpan) + { + if (((RibbonIndex)value).IsEncounterMark8()) + return true; + } + return false; + } + } + + public bool HasMarkEncounter9 + { + get + { + foreach (var value in RibbonSpan) + { + if (((RibbonIndex)value).IsEncounterMark9()) + return true; + } + return false; + } + } + + public byte GetRibbonAtIndex(int byteIndex) + { + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)byteIndex, RibbonBytesCount); + return RibbonSpan[byteIndex]; + } + + public void SetRibbonAtIndex(int byteIndex, byte ribbonIndex) + { + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)byteIndex, RibbonBytesCount); + RibbonSpan[byteIndex] = ribbonIndex; + } + + public int IV_HP { get => Data[0x29A]; set => Data[0x29A] = (byte)value; } + public int IV_ATK { get => Data[0x29B]; set => Data[0x29B] = (byte)value; } + public int IV_DEF { get => Data[0x29C]; set => Data[0x29C] = (byte)value; } + public int IV_SPE { get => Data[0x29D]; set => Data[0x29D] = (byte)value; } + public int IV_SPA { get => Data[0x29E]; set => Data[0x29E] = (byte)value; } + public int IV_SPD { get => Data[0x29F]; set => Data[0x29F] = (byte)value; } + + public byte OTGender { get => Data[0x2A0]; set => Data[0x2A0] = value; } + + public int EV_HP { get => Data[0x2A1]; set => Data[0x2A1] = (byte)value; } + public int EV_ATK { get => Data[0x2A2]; set => Data[0x2A2] = (byte)value; } + public int EV_DEF { get => Data[0x2A3]; set => Data[0x2A3] = (byte)value; } + public int EV_SPE { get => Data[0x2A4]; set => Data[0x2A4] = (byte)value; } + public int EV_SPA { get => Data[0x2A5]; set => Data[0x2A5] = (byte)value; } + public int EV_SPD { get => Data[0x2A6]; set => Data[0x2A6] = (byte)value; } + + // memories: unreferenced; retaining just in case + public byte OriginalTrainerMemoryIntensity { get => Data[0x2A7]; set => Data[0x2A7] = value; } + public byte OriginalTrainerMemory { get => Data[0x2A8]; set => Data[0x2A8] = value; } + public byte OriginalTrainerMemoryFeeling { get => Data[0x2A9]; set => Data[0x2A9] = value; } + public ushort OriginalTrainerMemoryVariable { get => ReadUInt16LittleEndian(Data[0x2AA..]); set => WriteUInt16LittleEndian(Data[0x2AA..], value); } + + public ushort Scale { get => ReadUInt16LittleEndian(Data[0x2AC..]); set => WriteUInt16LittleEndian(Data[0x2AC..], value); } + public bool IsAlpha { get => Data[0x2AE] != 0; set => Data[0x2AE] = value ? (byte)1 : (byte)0; } + + public ushort Checksum => ReadUInt16LittleEndian(Data[0x2C0..]); + + // Meta Accessible Properties + public int[] IVs + { + get => [IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD]; + set + { + if (value.Length != 6) + return; + IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; + IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; + } + } + + public override void GetIVs(Span value) + { + if (value.Length != 6) + return; + value[0] = IV_HP; + value[1] = IV_ATK; + value[2] = IV_DEF; + value[3] = IV_SPE; + value[4] = IV_SPA; + value[5] = IV_SPD; + } + + public int[] EVs + { + get => [EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD]; + set + { + if (value.Length != 6) + return; + EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2]; + EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5]; + } + } + + public bool GetIsNicknamed(int language) => ReadUInt16LittleEndian(Data[GetNicknameOffset(language)..]) != 0; + + public bool CanBeAnyLanguage() + { + for (int i = 0; i < 9; i++) + { + var ofs = GetLanguageOffset(i); + var lang = ReadInt16LittleEndian(Data[ofs..]); + if (lang != 0) + return false; + } + return true; + } + + public bool CanHaveLanguage(int language) + { + if (language is < (int)LanguageID.Japanese or > (int)LanguageID.ChineseT) + return false; + + if (CanBeAnyLanguage()) + return true; + + for (int i = 0; i < 9; i++) + { + var ofs = GetLanguageOffset(i); + var lang = ReadInt16LittleEndian(Data[ofs..]); + if (lang == language) + return true; + } + return GetLanguage(language) == 0; + } + + public int GetLanguage(int redeemLanguage) => Data[GetLanguageOffset(GetLanguageIndex(redeemLanguage))]; + private static int GetLanguageOffset(int index) => 0x28 + (index * 0x1C) + 0x1A; + + public bool GetHasOT(int language) => ReadUInt16LittleEndian(Data[GetOTOffset(language)..]) != 0; + + private static int GetLanguageIndex(int language) + { + var lang = (LanguageID) language; + if (lang is < LanguageID.Japanese or LanguageID.UNUSED_6 or > LanguageID.ChineseT) + return (int) LanguageID.English; // fallback + return lang < LanguageID.UNUSED_6 ? language - 1 : language - 2; + } + + public override Moveset Moves + { + get => new(Move1, Move2, Move3, Move4); + set + { + Move1 = value.Move1; + Move2 = value.Move2; + Move3 = value.Move3; + Move4 = value.Move4; + } + } + + public Moveset Relearn + { + get => new(RelearnMove1, RelearnMove2, RelearnMove3, RelearnMove4); + set + { + RelearnMove1 = value.Move1; + RelearnMove2 = value.Move2; + RelearnMove3 = value.Move3; + RelearnMove4 = value.Move4; + } + } + + public override string OriginalTrainerName + { + get => GetOT(Language); + set + { + for (int i = 1; i <= (int)LanguageID.ChineseT; i++) + SetOT(i, value); + } + } + + public string Nickname => GetIsNicknamed(Language) ? GetNickname(Language) : string.Empty; + public bool IsNicknamed => false; + public int Language => 2; + + private Span GetNicknameSpan(int language) => Data.Slice(GetNicknameOffset(language), 0x1A); + public string GetNickname(int language) => StringConverter8.GetString(GetNicknameSpan(language)); + public void SetNickname(int language, ReadOnlySpan value) => StringConverter8.SetString(GetNicknameSpan(language), value, 12, StringConverterOption.ClearZero); + + private Span GetOTSpan(int language) => Data.Slice(GetOTOffset(language), 0x1A); + public string GetOT(int language) => StringConverter8.GetString(GetOTSpan(language)); + public void SetOT(int language, ReadOnlySpan value) => StringConverter8.SetString(GetOTSpan(language), value, 12, StringConverterOption.ClearZero); + + private static int GetNicknameOffset(int language) + { + int index = GetLanguageIndex(language); + return 0x28 + (index * 0x1C); + } + + private static int GetOTOffset(int language) + { + int index = GetLanguageIndex(language); + return 0x124 + (index * 0x1C); + } + + public bool IsHOMEGift => CardID >= 9000; + + public bool CanHandleOT(int language) => !GetHasOT(language); + + public override GameVersion Version => OriginGame != 0 ? (GameVersion)OriginGame : GameVersion.SV; + + public override PA9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) + { + if (!IsEntity) + throw new ArgumentException(nameof(IsEntity)); + + var rnd = Util.Rand; + byte currentLevel = Level > 0 ? Level : (byte)(1 + rnd.Next(100)); + var metLevel = MetLevel > 0 ? MetLevel : currentLevel; + var pi = PersonalTable.ZA.GetFormEntry(Species, Form); + var language = tr.Language; + bool hasOT = GetHasOT(language); + var version = OriginGame != 0 ? (GameVersion)OriginGame : this.GetCompatibleVersion(tr.Version); + + var pk = new PA9 + { + EncryptionConstant = EncryptionConstant != 0 ? EncryptionConstant : rnd.Rand32(), + ID32 = OTGender >= 2 ? tr.ID32 : ID32, + Species = Species, + Form = Form, + CurrentLevel = currentLevel, + Ball = Ball != 0 ? Ball : (byte)4, // Default is Poké Ball + MetLevel = metLevel, + HeldItem = HeldItem, + + EXP = Experience.GetEXP(currentLevel, pi.EXPGrowth), + + Move1 = Move1, + Move2 = Move2, + Move3 = Move3, + Move4 = Move4, + RelearnMove1 = RelearnMove1, + RelearnMove2 = RelearnMove2, + RelearnMove3 = RelearnMove3, + RelearnMove4 = RelearnMove4, + + Version = version, + + OriginalTrainerName = hasOT ? GetOT(language) : tr.OT, + OriginalTrainerGender = OTGender < 2 ? OTGender : tr.Gender, + HandlingTrainerName = hasOT ? tr.OT : string.Empty, + HandlingTrainerGender = hasOT ? tr.Gender : default, + HandlingTrainerLanguage = (byte)(hasOT ? language : 0), + CurrentHandler = hasOT ? (byte)1 : (byte)0, + OriginalTrainerFriendship = pi.BaseFriendship, + + OriginalTrainerMemoryIntensity = OriginalTrainerMemoryIntensity, + OriginalTrainerMemory = OriginalTrainerMemory, + OriginalTrainerMemoryVariable = OriginalTrainerMemoryVariable, + OriginalTrainerMemoryFeeling = OriginalTrainerMemoryFeeling, + FatefulEncounter = true, + + EV_HP = EV_HP, + EV_ATK = EV_ATK, + EV_DEF = EV_DEF, + EV_SPE = EV_SPE, + EV_SPA = EV_SPA, + EV_SPD = EV_SPD, + + MetLocation = Location, + EggLocation = EggLocation, + IsAlpha = IsAlpha, + ObedienceLevel = currentLevel, + MetDate = GetSuggestedDate(), + }; + + var nickname_language = GetLanguage(language); + pk.Language = nickname_language != 0 ? nickname_language : tr.Language; + pk.IsNicknamed = GetIsNicknamed(language); + pk.Nickname = pk.IsNicknamed ? GetNickname(language) : SpeciesName.GetSpeciesNameGeneration(Species, pk.Language, Generation); + + // No ribbons set. + // for (var i = 0; i < RibbonBytesCount; i++) + // { + // var ribbon = GetRibbonAtIndex(i); + // if (ribbon == RibbonByteNone) + // continue; + // pk.SetRibbon(ribbon); + // pk.AffixedRibbon = (sbyte)ribbon; + // } + + SetPINGA(pk, criteria, pi); + SetMoves(currentLevel, pk, pi); + pk.HealPP(); + + if (IsEgg) + SetEggMetData(pk); + pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; + + pk.ResetPartyStats(); + pk.RefreshChecksum(); + return pk; + } + + private void SetMoves(byte currentLevel, PA9 pk, PersonalInfo9ZA pi) + { + var (learn, plus) = LearnSource9ZA.GetLearnsetAndPlus(Species, Form); + if (Move1 == 0) // Just in case they forget to set moves on an event. + { + Span moves = stackalloc ushort[4]; + learn.SetEncounterMoves(currentLevel, moves); + pk.SetMoves(moves); + } + PlusRecordApplicator.SetPlusFlagsEncounter(pk, pi, plus, currentLevel); + } + + private DateOnly GetSuggestedDate() + { + if (!IsDateRestricted) + return EncounterDate.GetDateSwitch(); + if (this.GetDistributionWindow(out var window)) + return window.GetGenerateDate(); + return EncounterDate.GetDateSwitch(); + } + + private void SetEggMetData(PA9 pk) + { + pk.IsEgg = true; + pk.EggMetDate = EncounterDate.GetDateSwitch(); + pk.Nickname = SpeciesName.GetEggName(pk.Language, Generation); + pk.IsNicknamed = true; + } + + private void SetPINGA(PA9 pk, EncounterCriteria criteria, PersonalInfo9ZA pi) + { + var param = GetParams(pi); + ulong init = Util.Rand.Rand64(); + var success = this.TryApply64(pk, init, param, criteria); + if (!success && !this.TryApply64(pk, init, param, criteria.WithoutIVs())) + this.TryApply64(pk, init, param, EncounterCriteria.Unrestricted); + + if (PIDType is not (ShinyType8.Never or ShinyType8.Random)) + pk.PID = GetPID(pk, PIDType); + } + + public override AbilityPermission Ability => AbilityType switch + { + 0 => AbilityPermission.OnlyFirst, + 1 => AbilityPermission.OnlySecond, + 2 => AbilityPermission.OnlyHidden, + 3 => AbilityPermission.Any12, + _ => AbilityPermission.Any12H, + }; + + private uint GetPID(ITrainerID32 tr, ShinyType8 type) => type switch + { + ShinyType8.Never => GetAntishiny(tr), // Random, Never Shiny + ShinyType8.Random => Util.Rand32(), // Random, Any + ShinyType8.AlwaysStar => (1u ^ (PID & 0xFFFF) ^ tr.TID16 ^ tr.SID16) << 16 | (PID & 0xFFFF), // Fixed, Force Star + ShinyType8.AlwaysSquare => (0u ^ (PID & 0xFFFF) ^ tr.TID16 ^ tr.SID16) << 16 | (PID & 0xFFFF), // Fixed, Force Square + ShinyType8.FixedValue => GetFixedPID(tr), + _ => throw new ArgumentOutOfRangeException(nameof(type)), + }; + + private uint GetFixedPID(ITrainerID32 tr) + { + var pid = PID; + if (pid != 0 && ID32 != 0) + return pid; + + if (!tr.IsShiny(pid, 9)) + return pid; + return pid; + } + + private static uint GetAntishiny(ITrainerID32 tr) + { + var pid = Util.Rand32(); + if (tr.IsShiny(pid, 9)) + return pid ^ 0x1000_0000; + return pid; + } + + public override bool IsMatchExact(PKM pk, EvoCriteria evo) + { + if (!IsEgg) + { + if (OTGender < 2) + { + var expect = ID32; + if (expect != pk.ID32) return false; + if (OTGender != pk.OriginalTrainerGender) return false; + } + + var language = pk.Language; + if (!CanBeAnyLanguage() && !CanHaveLanguage(language)) + return false; + + if (GetHasOT(language) && !IsMatchTrainerName(GetOTSpan(language), pk)) + return false; + + if (OriginGame != 0 && (GameVersion)OriginGame != pk.Version) return false; + if (EncryptionConstant != 0) + { + if (EncryptionConstant != pk.EncryptionConstant) + return false; + } + } + + if (Form != evo.Form && !FormInfo.IsFormChangeable(Species, Form, pk.Form, Context, pk.Context)) + return false; + + if (pk is IAlphaReadOnly t && t.IsAlpha != IsAlpha) + return false; + + var shinyType = Shiny; + if (PIDType == ShinyType8.FixedValue) + shinyType = FixedShinyType(); + if (IsEgg) + { + if (EggLocation != pk.EggLocation) // traded + { + if (pk.EggLocation != Locations.LinkTrade6) + return false; + if (PIDType == ShinyType8.Random && pk is { IsShiny: true, ShinyXor: > 1 }) + return false; // shiny traded egg will always have xor0/1. + } + if (!shinyType.IsValid(pk)) + { + return false; // can't be traded away for unshiny + } + + if (pk is { IsEgg: true, Context: not EntityContext.Gen9a }) + return false; + } + else + { + if (!shinyType.IsValid(pk)) return false; + if (!IsMatchEggLocation(pk)) return false; + if (!IsMatchLocation(pk)) return false; + } + + if (MetLevel != 0 && MetLevel != pk.MetLevel) return false; + if ((Ball == 0 ? 4 : Ball) != pk.Ball) return false; + if (OTGender < 2 && OTGender != pk.OriginalTrainerGender) return false; + if (Nature != Nature.Random && pk.Nature != Nature) return false; + if (Gender != 3 && Gender != pk.Gender) return false; + + if (pk is IScaledSize s) + { + if (Scale != 256) + { + var current = pk is IScaledSize3 s3 ? s3.Scale : s.HeightScalar; + if (Scale != current) + return false; + } + } + if (pk is IAlphaReadOnly a && a.IsAlpha != IsAlpha) + return true; + + // PID Types 0 and 1 do not use the fixed PID value. + // Values 2,3 are specific shiny states, and 4 is fixed value. + // 2,3,4 can change if it is a traded egg to ensure the same shiny state. + var type = PIDType; + if (type is ShinyType8.Never or ShinyType8.Random) + return true; + return pk.PID == GetPID(pk, type); + } + + private bool IsMatchTrainerName(ReadOnlySpan trainerTrash, PKM pk) + { + Span trainerName = stackalloc char[12]; + int length = StringConverter8.LoadString(trainerTrash, trainerName); + trainerName = trainerName[..length]; + + Span pkTrainerName = stackalloc char[pk.MaxStringLengthTrainer]; + int pkLength = pk.LoadString(pk.OriginalTrainerTrash, pkTrainerName); + pkTrainerName = pkTrainerName[..pkLength]; + + if (length == pkLength && trainerName.SequenceEqual(pkTrainerName)) + return true; + + var language = (LanguageID)pk.Language; + var version = pk.Version; + var other = ReplaceTrainerNameHOME.IsTriggerAndReplace(trainerName, pkTrainerName, language, version, Species, Form); + return other is not EntityContext.None; + } + + private bool IsMatchLocation(PKM pk) => IsMatchLocationExact(pk); + private bool IsMatchLocationExact(PKM pk) => pk.MetLocation == Location; + + public bool IsDateRestricted => true; + + protected override bool IsMatchDeferred(PKM pk) => false; + + protected override bool IsMatchPartial(PKM pk) => !TryGetSeed(pk, out _); + + #region Lazy Ribbon Implementation + + private static bool HasRibbon(RibbonIndex _) => false; // HasRibbon(index); // ZA is hard-coded to never set ribbons, so we need to return false for validation/setting. + public bool RibbonEarth { get => HasRibbon(Earth); set => this.SetRibbonIndex(Earth, value); } + public bool RibbonNational { get => HasRibbon(National); set => this.SetRibbonIndex(National, value); } + public bool RibbonCountry { get => HasRibbon(Country); set => this.SetRibbonIndex(Country, value); } + public bool RibbonChampionBattle { get => HasRibbon(ChampionBattle); set => this.SetRibbonIndex(ChampionBattle, value); } + public bool RibbonChampionRegional { get => HasRibbon(ChampionRegional); set => this.SetRibbonIndex(ChampionRegional, value); } + public bool RibbonChampionNational { get => HasRibbon(ChampionNational); set => this.SetRibbonIndex(ChampionNational, value); } + public bool RibbonClassic { get => HasRibbon(Classic); set => this.SetRibbonIndex(Classic, value); } + public bool RibbonWishing { get => HasRibbon(Wishing); set => this.SetRibbonIndex(Wishing, value); } + public bool RibbonPremier { get => HasRibbon(Premier); set => this.SetRibbonIndex(Premier, value); } + public bool RibbonEvent { get => HasRibbon(Event); set => this.SetRibbonIndex(Event, value); } + public bool RibbonBirthday { get => HasRibbon(Birthday); set => this.SetRibbonIndex(Birthday, value); } + public bool RibbonSpecial { get => HasRibbon(Special); set => this.SetRibbonIndex(Special, value); } + public bool RibbonWorld { get => HasRibbon(World); set => this.SetRibbonIndex(World, value); } + public bool RibbonChampionWorld { get => HasRibbon(ChampionWorld); set => this.SetRibbonIndex(ChampionWorld, value); } + public bool RibbonSouvenir { get => HasRibbon(Souvenir); set => this.SetRibbonIndex(Souvenir, value); } + public bool RibbonChampionG3 { get => HasRibbon(ChampionG3); set => this.SetRibbonIndex(ChampionG3, value); } + public bool RibbonArtist { get => HasRibbon(Artist); set => this.SetRibbonIndex(Artist, value); } + public bool RibbonEffort { get => HasRibbon(Effort); set => this.SetRibbonIndex(Effort, value); } + public bool RibbonChampionSinnoh { get => HasRibbon(ChampionSinnoh); set => this.SetRibbonIndex(ChampionSinnoh, value); } + public bool RibbonAlert { get => HasRibbon(Alert); set => this.SetRibbonIndex(Alert, value); } + public bool RibbonShock { get => HasRibbon(Shock); set => this.SetRibbonIndex(Shock, value); } + public bool RibbonDowncast { get => HasRibbon(Downcast); set => this.SetRibbonIndex(Downcast, value); } + public bool RibbonCareless { get => HasRibbon(Careless); set => this.SetRibbonIndex(Careless, value); } + public bool RibbonRelax { get => HasRibbon(Relax); set => this.SetRibbonIndex(Relax, value); } + public bool RibbonSnooze { get => HasRibbon(Snooze); set => this.SetRibbonIndex(Snooze, value); } + public bool RibbonSmile { get => HasRibbon(Smile); set => this.SetRibbonIndex(Smile, value); } + public bool RibbonGorgeous { get => HasRibbon(Gorgeous); set => this.SetRibbonIndex(Gorgeous, value); } + public bool RibbonRoyal { get => HasRibbon(Royal); set => this.SetRibbonIndex(Royal, value); } + public bool RibbonGorgeousRoyal { get => HasRibbon(GorgeousRoyal); set => this.SetRibbonIndex(GorgeousRoyal, value); } + public bool RibbonFootprint { get => HasRibbon(Footprint); set => this.SetRibbonIndex(Footprint, value); } + public bool RibbonRecord { get => HasRibbon(Record); set => this.SetRibbonIndex(Record, value); } + public bool RibbonLegend { get => HasRibbon(Legend); set => this.SetRibbonIndex(Legend, value); } + public bool RibbonChampionKalos { get => HasRibbon(ChampionKalos); set => this.SetRibbonIndex(ChampionKalos, value); } + public bool RibbonChampionG6Hoenn { get => HasRibbon(ChampionG6Hoenn); set => this.SetRibbonIndex(ChampionG6Hoenn, value); } + public bool RibbonBestFriends { get => HasRibbon(BestFriends); set => this.SetRibbonIndex(BestFriends, value); } + public bool RibbonTraining { get => HasRibbon(Training); set => this.SetRibbonIndex(Training, value); } + public bool RibbonBattlerSkillful { get => HasRibbon(BattlerSkillful); set => this.SetRibbonIndex(BattlerSkillful, value); } + public bool RibbonBattlerExpert { get => HasRibbon(BattlerExpert); set => this.SetRibbonIndex(BattlerExpert, value); } + public bool RibbonContestStar { get => HasRibbon(ContestStar); set => this.SetRibbonIndex(ContestStar, value); } + public bool RibbonMasterCoolness { get => HasRibbon(MasterCoolness); set => this.SetRibbonIndex(MasterCoolness, value); } + public bool RibbonMasterBeauty { get => HasRibbon(MasterBeauty); set => this.SetRibbonIndex(MasterBeauty, value); } + public bool RibbonMasterCuteness { get => HasRibbon(MasterCuteness); set => this.SetRibbonIndex(MasterCuteness, value); } + public bool RibbonMasterCleverness { get => HasRibbon(MasterCleverness); set => this.SetRibbonIndex(MasterCleverness, value); } + public bool RibbonMasterToughness { get => HasRibbon(MasterToughness); set => this.SetRibbonIndex(MasterToughness, value); } + + public bool RibbonChampionAlola { get => HasRibbon(ChampionAlola); set => this.SetRibbonIndex(ChampionAlola, value); } + public bool RibbonBattleRoyale { get => HasRibbon(BattleRoyale); set => this.SetRibbonIndex(BattleRoyale, value); } + public bool RibbonBattleTreeGreat { get => HasRibbon(BattleTreeGreat); set => this.SetRibbonIndex(BattleTreeGreat, value); } + public bool RibbonBattleTreeMaster { get => HasRibbon(BattleTreeMaster); set => this.SetRibbonIndex(BattleTreeMaster, value); } + public bool RibbonChampionGalar { get => HasRibbon(ChampionGalar); set => this.SetRibbonIndex(ChampionGalar, value); } + public bool RibbonTowerMaster { get => HasRibbon(TowerMaster); set => this.SetRibbonIndex(TowerMaster, value); } + public bool RibbonMasterRank { get => HasRibbon(MasterRank); set => this.SetRibbonIndex(MasterRank, value); } + public bool RibbonMarkLunchtime { get => HasRibbon(MarkLunchtime); set => this.SetRibbonIndex(MarkLunchtime, value); } + public bool RibbonMarkSleepyTime { get => HasRibbon(MarkSleepyTime); set => this.SetRibbonIndex(MarkSleepyTime, value); } + public bool RibbonMarkDusk { get => HasRibbon(MarkDusk); set => this.SetRibbonIndex(MarkDusk, value); } + public bool RibbonMarkDawn { get => HasRibbon(MarkDawn); set => this.SetRibbonIndex(MarkDawn, value); } + public bool RibbonMarkCloudy { get => HasRibbon(MarkCloudy); set => this.SetRibbonIndex(MarkCloudy, value); } + public bool RibbonMarkRainy { get => HasRibbon(MarkRainy); set => this.SetRibbonIndex(MarkRainy, value); } + public bool RibbonMarkStormy { get => HasRibbon(MarkStormy); set => this.SetRibbonIndex(MarkStormy, value); } + public bool RibbonMarkSnowy { get => HasRibbon(MarkSnowy); set => this.SetRibbonIndex(MarkSnowy, value); } + public bool RibbonMarkBlizzard { get => HasRibbon(MarkBlizzard); set => this.SetRibbonIndex(MarkBlizzard, value); } + public bool RibbonMarkDry { get => HasRibbon(MarkDry); set => this.SetRibbonIndex(MarkDry, value); } + public bool RibbonMarkSandstorm { get => HasRibbon(MarkSandstorm); set => this.SetRibbonIndex(MarkSandstorm, value); } + public bool RibbonMarkMisty { get => HasRibbon(MarkMisty); set => this.SetRibbonIndex(MarkMisty, value); } + public bool RibbonMarkDestiny { get => HasRibbon(MarkDestiny); set => this.SetRibbonIndex(MarkDestiny, value); } + public bool RibbonMarkFishing { get => HasRibbon(MarkFishing); set => this.SetRibbonIndex(MarkFishing, value); } + public bool RibbonMarkCurry { get => HasRibbon(MarkCurry); set => this.SetRibbonIndex(MarkCurry, value); } + public bool RibbonMarkUncommon { get => HasRibbon(MarkUncommon); set => this.SetRibbonIndex(MarkUncommon, value); } + public bool RibbonMarkRare { get => HasRibbon(MarkRare); set => this.SetRibbonIndex(MarkRare, value); } + public bool RibbonMarkRowdy { get => HasRibbon(MarkRowdy); set => this.SetRibbonIndex(MarkRowdy, value); } + public bool RibbonMarkAbsentMinded { get => HasRibbon(MarkAbsentMinded); set => this.SetRibbonIndex(MarkAbsentMinded, value); } + public bool RibbonMarkJittery { get => HasRibbon(MarkJittery); set => this.SetRibbonIndex(MarkJittery, value); } + public bool RibbonMarkExcited { get => HasRibbon(MarkExcited); set => this.SetRibbonIndex(MarkExcited, value); } + public bool RibbonMarkCharismatic { get => HasRibbon(MarkCharismatic); set => this.SetRibbonIndex(MarkCharismatic, value); } + public bool RibbonMarkCalmness { get => HasRibbon(MarkCalmness); set => this.SetRibbonIndex(MarkCalmness, value); } + public bool RibbonMarkIntense { get => HasRibbon(MarkIntense); set => this.SetRibbonIndex(MarkIntense, value); } + public bool RibbonMarkZonedOut { get => HasRibbon(MarkZonedOut); set => this.SetRibbonIndex(MarkZonedOut, value); } + public bool RibbonMarkJoyful { get => HasRibbon(MarkJoyful); set => this.SetRibbonIndex(MarkJoyful, value); } + public bool RibbonMarkAngry { get => HasRibbon(MarkAngry); set => this.SetRibbonIndex(MarkAngry, value); } + public bool RibbonMarkSmiley { get => HasRibbon(MarkSmiley); set => this.SetRibbonIndex(MarkSmiley, value); } + public bool RibbonMarkTeary { get => HasRibbon(MarkTeary); set => this.SetRibbonIndex(MarkTeary, value); } + public bool RibbonMarkUpbeat { get => HasRibbon(MarkUpbeat); set => this.SetRibbonIndex(MarkUpbeat, value); } + public bool RibbonMarkPeeved { get => HasRibbon(MarkPeeved); set => this.SetRibbonIndex(MarkPeeved, value); } + public bool RibbonMarkIntellectual { get => HasRibbon(MarkIntellectual); set => this.SetRibbonIndex(MarkIntellectual, value); } + public bool RibbonMarkFerocious { get => HasRibbon(MarkFerocious); set => this.SetRibbonIndex(MarkFerocious, value); } + public bool RibbonMarkCrafty { get => HasRibbon(MarkCrafty); set => this.SetRibbonIndex(MarkCrafty, value); } + public bool RibbonMarkScowling { get => HasRibbon(MarkScowling); set => this.SetRibbonIndex(MarkScowling, value); } + public bool RibbonMarkKindly { get => HasRibbon(MarkKindly); set => this.SetRibbonIndex(MarkKindly, value); } + public bool RibbonMarkFlustered { get => HasRibbon(MarkFlustered); set => this.SetRibbonIndex(MarkFlustered, value); } + public bool RibbonMarkPumpedUp { get => HasRibbon(MarkPumpedUp); set => this.SetRibbonIndex(MarkPumpedUp, value); } + public bool RibbonMarkZeroEnergy { get => HasRibbon(MarkZeroEnergy); set => this.SetRibbonIndex(MarkZeroEnergy, value); } + public bool RibbonMarkPrideful { get => HasRibbon(MarkPrideful); set => this.SetRibbonIndex(MarkPrideful, value); } + public bool RibbonMarkUnsure { get => HasRibbon(MarkUnsure); set => this.SetRibbonIndex(MarkUnsure, value); } + public bool RibbonMarkHumble { get => HasRibbon(MarkHumble); set => this.SetRibbonIndex(MarkHumble, value); } + public bool RibbonMarkThorny { get => HasRibbon(MarkThorny); set => this.SetRibbonIndex(MarkThorny, value); } + public bool RibbonMarkVigor { get => HasRibbon(MarkVigor); set => this.SetRibbonIndex(MarkVigor, value); } + public bool RibbonMarkSlump { get => HasRibbon(MarkSlump); set => this.SetRibbonIndex(MarkSlump, value); } + public bool RibbonTwinklingStar { get => HasRibbon(TwinklingStar); set => this.SetRibbonIndex(TwinklingStar, value); } + public bool RibbonHisui { get => HasRibbon(Hisui); set => this.SetRibbonIndex(Hisui, value); } + public bool RibbonChampionPaldea { get => HasRibbon(ChampionPaldea); set => this.SetRibbonIndex(ChampionPaldea, value); } + public bool RibbonMarkJumbo { get => HasRibbon(MarkJumbo); set => this.SetRibbonIndex(MarkJumbo, value); } + public bool RibbonMarkMini { get => HasRibbon(MarkMini); set => this.SetRibbonIndex(MarkMini, value); } + public bool RibbonMarkItemfinder { get => HasRibbon(MarkItemfinder); set => this.SetRibbonIndex(MarkItemfinder, value); } + public bool RibbonMarkPartner { get => HasRibbon(MarkPartner); set => this.SetRibbonIndex(MarkPartner, value); } + public bool RibbonMarkGourmand { get => HasRibbon(MarkGourmand); set => this.SetRibbonIndex(MarkGourmand, value); } + public bool RibbonOnceInALifetime { get => HasRibbon(OnceInALifetime); set => this.SetRibbonIndex(OnceInALifetime, value); } + public bool RibbonMarkAlpha { get => HasRibbon(MarkAlpha); set => this.SetRibbonIndex(MarkAlpha, value); } + public bool RibbonMarkMightiest { get => HasRibbon(MarkMightiest); set => this.SetRibbonIndex(MarkMightiest, value); } + public bool RibbonMarkTitan { get => HasRibbon(MarkTitan); set => this.SetRibbonIndex(MarkTitan, value); } + public bool RibbonPartner { get => HasRibbon(Partner); set => this.SetRibbonIndex(Partner, value); } + + public int GetRibbonByte(int index) => RibbonSpan.IndexOf((byte)index); + public bool GetRibbon(int index) => RibbonSpan.Contains((byte)index); + + public void SetRibbon(int index, bool value = true) + { + ArgumentOutOfRangeException.ThrowIfGreaterThan((uint)index, (uint)RibbonIndexExtensions.MAX_G9); + if (value) + { + if (GetRibbon(index)) + return; + var openIndex = RibbonSpan.IndexOf(RibbonByteNone); + ArgumentOutOfRangeException.ThrowIfNegative(openIndex); // Full? + SetRibbonAtIndex(openIndex, (byte)index); + } + else + { + var ofs = GetRibbonByte(index); + if (ofs < 0) + return; + SetRibbonAtIndex(ofs, RibbonByteNone); + } + } + #endregion + + public bool IsMissingExtraMark(PKM pk, out RibbonIndex missing) + { + foreach (var value in RibbonSpan) + { + missing = (RibbonIndex)value; + if (!missing.IsEncounterMark8()) + continue; + if (pk is IRibbonSetMark8 m8 && !m8.HasMark8(missing)) + return true; + } + missing = default; + return false; + } + + public bool TryGetSeed(PKM pk, out ulong seed) => GetParams(PersonalTable.ZA[Species, Form]).TryGetSeed(pk, out seed); + + private GenerateParam9a GetParams(PersonalInfo9ZA pi) + { + const LumioseCorrelation correlation = LumioseCorrelation.SkipTrainer; + const byte rollCount = 1; + var hp = IV_HP; + var flawless = GetFlawlessIVCount(hp); + var ivs = new IndividualValueSet((sbyte)hp, (sbyte)IV_ATK, (sbyte)IV_DEF, (sbyte)IV_SPE, (sbyte)IV_SPA, (sbyte)IV_SPD); + var sizeType = Scale == 256 ? SizeType9.RANDOM : SizeType9.VALUE; + var gender = Gender switch + { + 0 => PersonalInfo.RatioMagicMale, + 1 => PersonalInfo.RatioMagicFemale, + 2 => PersonalInfo.RatioMagicGenderless, + _ => pi.Gender, + }; + return new GenerateParam9a(gender, flawless, rollCount, correlation, sizeType, (byte)Scale, Nature, Ability, Shiny, ivs); + } + + private static byte GetFlawlessIVCount(int hp) + { + var tryFlawless = 0xFF - hp; + if ((uint)tryFlawless < 6) + return (byte)tryFlawless; + return 0; + } +} diff --git a/PKHeX.Core/MysteryGifts/WB7.cs b/PKHeX.Core/MysteryGifts/WB7.cs index 6315e9d8f..a79b63de8 100644 --- a/PKHeX.Core/MysteryGifts/WB7.cs +++ b/PKHeX.Core/MysteryGifts/WB7.cs @@ -6,11 +6,11 @@ namespace PKHeX.Core; /// /// Generation 7 Mystery Gift Template File (LGP/E) /// -public sealed class WB7 : DataMysteryGift, ILangNick, IAwakened, IRelearn, IEncounterServerDate, INature, ILangNicknamedTemplate, +public sealed class WB7(Memory raw) : DataMysteryGift(raw), ILangNick, IAwakened, IRelearn, IEncounterServerDate, + INature, ILangNicknamedTemplate, IMetLevel, IRestrictVersion, IRibbonSetEvent3, IRibbonSetEvent4 { public WB7() : this(new byte[Size]) { } - public WB7(Memory raw) : base(raw) { } public override WB7 Clone() => new(Data.ToArray()); public const int Size = 0x310; @@ -153,11 +153,7 @@ public override int Quantity _ => Shiny.Never, }; - private uint GetShinyXor() - { - var xor = PID ^ ID32; - return (xor >> 16) ^ (xor & 0xFFFF); - } + private uint GetShinyXor() => ShinyUtil.GetShinyXor(PID, ID32); public override uint ID32 { get => ReadUInt32LittleEndian(Card[0x68..]); set => WriteUInt32LittleEndian(Card[0x68..], value); } public override ushort TID16 { get => ReadUInt16LittleEndian(Card[0x68..]); set => WriteUInt16LittleEndian(Card[0x68..], value); } diff --git a/PKHeX.Core/MysteryGifts/WB8.cs b/PKHeX.Core/MysteryGifts/WB8.cs index d8b4eac24..615aea265 100644 --- a/PKHeX.Core/MysteryGifts/WB8.cs +++ b/PKHeX.Core/MysteryGifts/WB8.cs @@ -7,14 +7,13 @@ namespace PKHeX.Core; /// /// Generation 8b Mystery Gift Template File /// -public sealed class WB8 : DataMysteryGift, +public sealed class WB8(Memory raw) : DataMysteryGift(raw), ILangNick, INature, IRibbonIndex, IContestStatsReadOnly, IRelearn, ILangNicknamedTemplate, IEncounterServerDate, IMetLevel, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8 { public WB8() : this(new byte[Size]) { } - public WB8(Memory raw) : base(raw) { } public override WB8 Clone() => new(Data.ToArray()); public const int Size = 0x2DC; @@ -116,9 +115,7 @@ private uint GetShinyXor() // Player owned anti-shiny fixed PID if (ID32 == 0) return uint.MaxValue; - - var xor = PID ^ ID32; - return (xor >> 16) ^ (xor & 0xFFFF); + return ShinyUtil.GetShinyXor(PID, ID32); } public override uint ID32 @@ -866,7 +863,7 @@ public void SetRibbon(int index, bool value = true) if (GetRibbon(index)) return; var openIndex = RibbonSpan.IndexOf(RibbonByteNone); - ArgumentOutOfRangeException.ThrowIfNegative(openIndex, nameof(openIndex)); // Full? + ArgumentOutOfRangeException.ThrowIfNegative(openIndex); // Full? SetRibbonAtIndex(openIndex, (byte)index); } else diff --git a/PKHeX.Core/MysteryGifts/WC6.cs b/PKHeX.Core/MysteryGifts/WC6.cs index d02c4938e..40335eba7 100644 --- a/PKHeX.Core/MysteryGifts/WC6.cs +++ b/PKHeX.Core/MysteryGifts/WC6.cs @@ -6,11 +6,10 @@ namespace PKHeX.Core; /// /// Generation 6 Mystery Gift Template File /// -public sealed class WC6 : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, +public sealed class WC6(Memory raw) : DataMysteryGift(raw), IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IContestStats, INature, IMemoryOT, IRelearn, IRestrictVersion { public WC6() : this(new byte[Size]) { } - public WC6(Memory raw) : base(raw) { } public override WC6 Clone() => new(Data.ToArray()); public const int Size = 0x108; @@ -147,9 +146,7 @@ private uint GetShinyXor() // Player owned anti-shiny fixed PID if (ID32 == 0) return uint.MaxValue; - - var xor = PID ^ ID32; - return (xor >> 16) ^ (xor & 0xFFFF); + return ShinyUtil.GetShinyXor(PID, ID32); } public override uint ID32 { get => ReadUInt32LittleEndian(Data[0x68..]); set => WriteUInt32LittleEndian(Data[0x68..], value); } @@ -305,7 +302,7 @@ public override PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) throw new ArgumentException(nameof(IsEntity)); var version = OriginGame != 0 ? (GameVersion)OriginGame : this.GetCompatibleVersion(tr.Version); - int language = (int)Core.Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + int language = (int)Core.Language.GetSafeLanguage456((LanguageID)tr.Language); var geo = tr.GetRegionOrigin(language); var rnd = Util.Rand; byte currentLevel = Level > 0 ? Level : (byte)(1 + rnd.Next(100)); diff --git a/PKHeX.Core/MysteryGifts/WC7.cs b/PKHeX.Core/MysteryGifts/WC7.cs index 38619b6ad..d83b4b18e 100644 --- a/PKHeX.Core/MysteryGifts/WC7.cs +++ b/PKHeX.Core/MysteryGifts/WC7.cs @@ -6,11 +6,10 @@ namespace PKHeX.Core; /// /// Generation 7 Mystery Gift Template File /// -public sealed class WC7 : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, +public sealed class WC7(Memory raw) : DataMysteryGift(raw), IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IContestStats, INature, IMemoryOT, IRelearn, IMetLevel, IRestrictVersion { public WC7() : this(new byte[Size]) { } - public WC7(Memory raw) : base(raw) { } public override WC7 Clone() => new(Data.ToArray()); public const int Size = 0x108; @@ -163,9 +162,7 @@ private uint GetShinyXor() // Player owned anti-shiny fixed PID if (ID32 == 0) return uint.MaxValue; - - var xor = PID ^ ID32; - return (xor >> 16) ^ (xor & 0xFFFF); + return ShinyUtil.GetShinyXor(PID, ID32); } public override uint ID32 @@ -366,7 +363,7 @@ public override PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) throw new ArgumentException(nameof(IsEntity)); var version = OriginGame != 0 ? (GameVersion)OriginGame : this.GetCompatibleVersion(tr.Version); - var language = Language != 0 ? Language : (int)Core.Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + var language = Language != 0 ? Language : (int)Core.Language.GetSafeLanguage789((LanguageID)tr.Language); var geo = tr.GetRegionOrigin(language); var rnd = Util.Rand; byte currentLevel = Level > 0 ? Level : (byte)(1 + rnd.Next(100)); diff --git a/PKHeX.Core/MysteryGifts/WC8.cs b/PKHeX.Core/MysteryGifts/WC8.cs index 89884bb43..ac747127e 100644 --- a/PKHeX.Core/MysteryGifts/WC8.cs +++ b/PKHeX.Core/MysteryGifts/WC8.cs @@ -7,12 +7,11 @@ namespace PKHeX.Core; /// /// Generation 8 Mystery Gift Template File /// -public sealed class WC8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDynamaxLevel, IRibbonIndex, IMemoryOT, +public sealed class WC8(Memory raw) : DataMysteryGift(raw), ILangNick, INature, IGigantamax, IDynamaxLevel, IRibbonIndex, IMemoryOT, ILangNicknamedTemplate, IRelearn, IEncounterServerDate, IRestrictVersion, IMetLevel, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8, ITrashUnderlaySpecies { public WC8() : this(new byte[Size]) { } - public WC8(Memory raw) : base(raw) { } public override WC8 Clone() => new(Data.ToArray()); public const int Size = 0x2D0; @@ -113,9 +112,7 @@ private uint GetShinyXor() // Player owned anti-shiny fixed PID if (ID32 == 0) return uint.MaxValue; - - var xor = PID ^ ID32; - return (xor >> 16) ^ (xor & 0xFFFF); + return ShinyUtil.GetShinyXor(PID, ID32); } public override uint ID32 @@ -408,7 +405,7 @@ public override PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) var metLevel = MetLevel > 0 ? MetLevel : currentLevel; var pi = PersonalTable.SWSH.GetFormEntry(Species, Form); var version = OriginGame != 0 ? (GameVersion)OriginGame : this.GetCompatibleVersion(tr.Version); - var language = (int)Core.Language.GetSafeLanguage(Generation, (LanguageID)tr.Language); + var language = (int)Core.Language.GetSafeLanguage789((LanguageID)tr.Language); bool hasOT = GetHasOT(language); var pk = new PK8 @@ -474,15 +471,15 @@ public override PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) if (OTGender >= 2) { - pk.TID16 = tr.TID16; - pk.SID16 = tr.SID16; + var value = tr.ID32; // Initial updates of HOME did not assign a TSV of 0. // After enough server updates, HOME can now assign a TSV of 0. // They will XOR the PID to ensure the shiny state of gifts is matched. // Don't set a Secret ID. if (IsHOMEGift) - pk.ID32 %= 1_000_000; + value %= 1_000_000; + pk.ID32 = value; } // Official code explicitly corrects for Meowstic @@ -909,7 +906,7 @@ public void SetRibbon(int index, bool value = true) if (GetRibbon(index)) return; var openIndex = RibbonSpan.IndexOf(RibbonByteNone); - ArgumentOutOfRangeException.ThrowIfNegative(openIndex, nameof(openIndex)); // Full? + ArgumentOutOfRangeException.ThrowIfNegative(openIndex); // Full? SetRibbonAtIndex(openIndex, (byte)index); } else diff --git a/PKHeX.Core/MysteryGifts/WC9.cs b/PKHeX.Core/MysteryGifts/WC9.cs index 6fc7d22bf..3b59a51ed 100644 --- a/PKHeX.Core/MysteryGifts/WC9.cs +++ b/PKHeX.Core/MysteryGifts/WC9.cs @@ -7,13 +7,12 @@ namespace PKHeX.Core; /// /// Generation 9 Mystery Gift Template File /// -public sealed class WC9 : DataMysteryGift, ILangNick, INature, ITeraType, IRibbonIndex, IMemoryOT, +public sealed class WC9(Memory raw) : DataMysteryGift(raw), ILangNick, INature, ITeraType, IRibbonIndex, IMemoryOT, ILangNicknamedTemplate, IEncounterServerDate, IRelearn, IMetLevel, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8, IRibbonSetCommon9, IRibbonSetMark9, IEncounterMarkExtra { public WC9() : this(new byte[Size]) { } - public WC9(Memory raw) : base(raw) { } public override WC9 Clone() => new(Data.ToArray()); public const int Size = 0x2C8; @@ -120,9 +119,7 @@ private uint GetShinyXor() // Player owned anti-shiny fixed PID if (ID32 == 0) return uint.MaxValue; - - var xor = PID ^ ID32; - return (xor >> 16) ^ (xor & 0xFFFF); + return ShinyUtil.GetShinyXor(PID, ID32); } // When applying the TID32, the game sets the DisplayTID7 directly, then sets pk9.DisplaySID7 as (wc9.DisplaySID7 - wc9.CardID) @@ -507,14 +504,9 @@ public override PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) pk.MetDate = date; if (OTGender >= 2) - { - pk.TID16 = tr.TID16; - pk.SID16 = tr.SID16; - } + pk.ID32 = tr.ID32; else if (IsBeforePatch200(date)) - { pk.ID32 = ID32Old; - } var nickname_language = GetLanguage(language); pk.Language = nickname_language != 0 ? nickname_language : tr.Language; @@ -545,7 +537,7 @@ public override PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) else pk.Scale = (byte)Scale; - pk.ObedienceLevel = Level; + pk.ObedienceLevel = currentLevel; pk.ResetPartyStats(); pk.RefreshChecksum(); return pk; @@ -932,7 +924,7 @@ public void SetRibbon(int index, bool value = true) if (GetRibbon(index)) return; var openIndex = RibbonSpan.IndexOf(RibbonByteNone); - ArgumentOutOfRangeException.ThrowIfNegative(openIndex, nameof(openIndex)); // Full? + ArgumentOutOfRangeException.ThrowIfNegative(openIndex); // Full? SetRibbonAtIndex(openIndex, (byte)index); } else diff --git a/PKHeX.Core/PKM/Enums/OriginMark.cs b/PKHeX.Core/PKM/Enums/OriginMark.cs index 5fe7d827e..0091a0951 100644 --- a/PKHeX.Core/PKM/Enums/OriginMark.cs +++ b/PKHeX.Core/PKM/Enums/OriginMark.cs @@ -15,6 +15,7 @@ public enum OriginMark Gen8Trio, Gen8Arc, Gen9Paldea, + Gen9ZA, GameBoy, GO, @@ -46,6 +47,8 @@ public static OriginMark GetOriginMark(PKM pk) return Gen8Arc; if (pk.SV) return Gen9Paldea; + if (pk.ZA) + return Gen9ZA; return None; } diff --git a/PKHeX.Core/PKM/HOME/GameDataPA8.cs b/PKHeX.Core/PKM/HOME/GameDataPA8.cs index 581c017d8..3a59b87a4 100644 --- a/PKHeX.Core/PKM/HOME/GameDataPA8.cs +++ b/PKHeX.Core/PKM/HOME/GameDataPA8.cs @@ -6,7 +6,7 @@ namespace PKHeX.Core; /// /// Side game data for data transferred into HOME. /// -public sealed class GameDataPA8 : HomeOptional1, IGameDataSide, IScaledSizeAbsolute, IScaledSize3, IGameDataSplitAbility, IPokerusStatus +public sealed class GameDataPA8 : HomeOptional1, IGameDataSide, IScaledSizeAbsolute, IScaledSize3, IGameDataSplitAbility, IPokerusStatus, IAlpha { private const HomeGameDataFormat ExpectFormat = HomeGameDataFormat.PA8; private const int SIZE = HomeCrypto.SIZE_2GAME_PA8; diff --git a/PKHeX.Core/PKM/HOME/GameDataPA9.cs b/PKHeX.Core/PKM/HOME/GameDataPA9.cs new file mode 100644 index 000000000..541d758db --- /dev/null +++ b/PKHeX.Core/PKM/HOME/GameDataPA9.cs @@ -0,0 +1,281 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +// TODO HOME ZA -- Simply copied from SV, needs to be updated to ZA when official support is added. + +/// +/// Side game data for data transferred into HOME. +/// +public sealed class GameDataPA9 : HomeOptional1, IGameDataSide, IScaledSize3, IGameDataSplitAbility, IAlpha +{ + private const HomeGameDataFormat ExpectFormat = HomeGameDataFormat.PA9; + private const int SIZE = HomeCrypto.SIZE_4GAME_PA9; + protected override HomeGameDataFormat Format => ExpectFormat; + + public GameDataPA9() : base(SIZE) { } + public GameDataPA9(Memory data) : base(data) => EnsureSize(SIZE); + public GameDataPA9 Clone() => new(ToArray()); + public int WriteTo(Span result) => WriteWithHeader(result); + + #region Structure + + public byte Scale { get => Data[0x00]; set => Data[0x00] = value; } + public ushort Move1 { get => ReadUInt16LittleEndian(Data[0x01..]); set => WriteUInt16LittleEndian(Data[0x01..], value); } + public ushort Move2 { get => ReadUInt16LittleEndian(Data[0x03..]); set => WriteUInt16LittleEndian(Data[0x03..], value); } + public ushort Move3 { get => ReadUInt16LittleEndian(Data[0x05..]); set => WriteUInt16LittleEndian(Data[0x05..], value); } + public ushort Move4 { get => ReadUInt16LittleEndian(Data[0x07..]); set => WriteUInt16LittleEndian(Data[0x07..], value); } + + public int Move1_PP { get => Data[0x09]; set => Data[0x09] = (byte)value; } + public int Move2_PP { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } + public int Move3_PP { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } + public int Move4_PP { get => Data[0x0C]; set => Data[0x0C] = (byte)value; } + public int Move1_PPUps { get => Data[0x0D]; set => Data[0x0D] = (byte)value; } + public int Move2_PPUps { get => Data[0x0E]; set => Data[0x0E] = (byte)value; } + public int Move3_PPUps { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } + public int Move4_PPUps { get => Data[0x10]; set => Data[0x10] = (byte)value; } + + public ushort RelearnMove1 { get => ReadUInt16LittleEndian(Data[0x11..]); set => WriteUInt16LittleEndian(Data[0x11..], value); } + public ushort RelearnMove2 { get => ReadUInt16LittleEndian(Data[0x13..]); set => WriteUInt16LittleEndian(Data[0x13..], value); } + public ushort RelearnMove3 { get => ReadUInt16LittleEndian(Data[0x15..]); set => WriteUInt16LittleEndian(Data[0x15..], value); } + public ushort RelearnMove4 { get => ReadUInt16LittleEndian(Data[0x17..]); set => WriteUInt16LittleEndian(Data[0x17..], value); } + public bool IsAlpha { get => Data[0x19] != 0; set => Data[0x19] = value ? (byte)1 : (byte)0; } + // 0x1A Padding (???) TODO HOME ZA; this is adapted from SV's structure, replacing the 2 byte properties for Tera Type. + public byte Ball { get => Data[0x1B]; set => Data[0x1B] = value; } + public ushort EggLocation { get => ReadUInt16LittleEndian(Data[0x1C..]); set => WriteUInt16LittleEndian(Data[0x1C..], value); } + public ushort MetLocation { get => ReadUInt16LittleEndian(Data[0x1E..]); set => WriteUInt16LittleEndian(Data[0x1E..], value); } + + private const int RecordStartBase = 0x20; + internal const int COUNT_RECORD_BASE = PA9.COUNT_RECORD_BASE; // Up to 200 TM flags, but not all are used. + private const int RecordLengthBase = COUNT_RECORD_BASE / 8; // 0x19 bytes, 8 bits + public Span RecordFlagsBase => Data.Slice(RecordStartBase, RecordLengthBase); + + // Rev2 Additions + public byte Obedience_Level { get => Data[0x39]; set => Data[0x39] = value; } + public ushort Ability { get => ReadUInt16LittleEndian(Data[0x3A..]); set => WriteUInt16LittleEndian(Data[0x3A..], value); } + public byte AbilityNumber { get => Data[0x3C]; set => Data[0x3C] = value; } + + // Rev3 Additions + private const int RecordStartDLC = 0x3D; + internal const int COUNT_RECORD_DLC = PA9.COUNT_RECORD_DLC; // 13 additional bytes allocated for DLC1/2 TM Flags + private const int RecordLengthDLC = COUNT_RECORD_DLC / 8; + public Span RecordFlagsDLC => Data.Slice(RecordStartDLC, RecordLengthDLC); + + // Rev4 Additions (ZA) + private const int PlusStart0 = 0x4A; + internal const int PlusCount0 = PA9.PlusCount0; + private const int PlusLength0 = PlusCount0 / 8; + public Span PlusFlags0 => Data.Slice(PlusStart0, PlusLength0); + + private const int PlusStart1 = PlusStart0 + PlusLength0; // 0x6B + internal const int PlusCount1 = PA9.PlusCount1; + private const int PlusLength1 = PlusCount1 / 8; + public Span PlusFlags1 => Data.Slice(PlusStart1, PlusLength1); + + #endregion + + #region TM Flag Methods + public bool GetMoveRecordFlag(int index) + { + if ((uint)index >= COUNT_RECORD_BASE) + return GetMoveRecordFlagDLC(index - COUNT_RECORD_BASE); + int ofs = index >> 3; + return FlagUtil.GetFlag(Data, RecordStartBase + ofs, index & 7); + } + + private bool GetMoveRecordFlagDLC(int index) + { + if ((uint)index >= COUNT_RECORD_DLC) + throw new ArgumentOutOfRangeException(nameof(index)); + int ofs = index >> 3; + return FlagUtil.GetFlag(Data, RecordStartDLC + ofs, index & 7); + } + + public void SetMoveRecordFlag(int index, bool value = true) + { + if ((uint)index >= COUNT_RECORD_BASE) + { + SetMoveRecordFlagDLC(value, index - COUNT_RECORD_BASE); + return; + } + int ofs = index >> 3; + FlagUtil.SetFlag(Data, RecordStartBase + ofs, index & 7, value); + } + + private void SetMoveRecordFlagDLC(bool value, int index) + { + if ((uint)index >= COUNT_RECORD_DLC) + throw new ArgumentOutOfRangeException(nameof(index)); + int ofs = index >> 3; + FlagUtil.SetFlag(Data, RecordStartDLC + ofs, index & 7, value); + } + + public bool GetMoveRecordFlagAny() => GetMoveRecordFlagAnyBase() || GetMoveRecordFlagAnyDLC(); + private bool GetMoveRecordFlagAnyBase() => RecordFlagsBase.ContainsAnyExcept(0); + private bool GetMoveRecordFlagAnyDLC() => RecordFlagsDLC.ContainsAnyExcept(0); + + public void ClearMoveRecordFlags() + { + ClearMoveRecordFlagsBase(); + ClearMoveRecordFlagsDLC(); + } + + private void ClearMoveRecordFlagsBase() => RecordFlagsBase.Clear(); + private void ClearMoveRecordFlagsDLC() => RecordFlagsDLC.Clear(); + #endregion + + #region Plus Moves + + public bool GetMovePlusFlag(int index) + { + if ((uint)index >= PlusCount0) + return GetMovePlusFlag1(index - PlusCount0); + int ofs = index >> 3; + return FlagUtil.GetFlag(Data, PlusStart0 + ofs, index & 7); + } + + private bool GetMovePlusFlag1(int index) + { + if ((uint)index >= PlusCount1) + throw new ArgumentOutOfRangeException(nameof(index)); + int ofs = index >> 3; + return FlagUtil.GetFlag(Data, PlusStart1 + ofs, index & 7); + } + + public void SetMovePlusFlag(int index, bool value = true) + { + if ((uint)index >= PlusCount0) + { + SetMovePlusFlag1(value, index - PlusCount0); + return; + } + int ofs = index >> 3; + FlagUtil.SetFlag(Data, PlusStart0 + ofs, index & 7, value); + } + + private void SetMovePlusFlag1(bool value, int index) + { + if ((uint)index >= PlusCount1) + throw new ArgumentOutOfRangeException(nameof(index)); + int ofs = index >> 3; + FlagUtil.SetFlag(Data, PlusStart1 + ofs, index & 7, value); + } + + public bool GetMovePlusFlagAny() => GetMovePlusFlagAny0() || GetMovePlusFlagAny1(); + private bool GetMovePlusFlagAny0() => PlusFlags0.ContainsAnyExcept(0); + private bool GetMovePlusFlagAny1() => PlusFlags1.ContainsAnyExcept(0); + + public void ClearMovePlusFlags() + { + ClearMovePlusFlags0(); + ClearMovePlusFlags1(); + } + + private void ClearMovePlusFlags0() => PlusFlags0.Clear(); + private void ClearMovePlusFlags1() => PlusFlags1.Clear(); + #endregion + + #region Conversion + + public PersonalInfo GetPersonalInfo(ushort species, byte form) => PersonalTable.ZA.GetFormEntry(species, form); + + public void CopyTo(PA9 pk, PKH pkh) + { + this.CopyTo(pk); + pk.Scale = Scale; + PlusFlags0.CopyTo(pk.PlusFlags0); + PlusFlags1.CopyTo(pk.PlusFlags1); + RecordFlagsBase.CopyTo(pk.RecordFlagsBase); + RecordFlagsDLC.CopyTo(pk.RecordFlagsDLC); + pk.ObedienceLevel = Obedience_Level; + pk.Ability = Ability; + pk.AbilityNumber = AbilityNumber; + } + + public void CopyFrom(PA9 pk, PKH pkh) + { + this.CopyFrom(pk); + pkh.HeightScalar = Scale = pk.Scale; // Overwrite Height + pk.PlusFlags0.CopyTo(PlusFlags0); + pk.PlusFlags1.CopyTo(PlusFlags1); + pk.RecordFlagsBase.CopyTo(RecordFlagsBase); + pk.RecordFlagsDLC.CopyTo(RecordFlagsDLC); + Obedience_Level = pk.ObedienceLevel; + Ability = (ushort)pk.Ability; + AbilityNumber = (byte)pk.AbilityNumber; + } + + public PA9 ConvertToPKM(PKH pkh) + { + var pk = new PA9(); + pkh.CopyTo(pk); + CopyTo(pk, pkh); + + pk.ResetPartyStats(); + pk.RefreshChecksum(); + return pk; + } + + #endregion + + /// Reconstructive logic to best apply suggested values. + public static GameDataPA9? TryCreate(PKH pkh) + { + if (!PersonalTable.ZA.IsPresentInGame(pkh.Species, pkh.Form)) + return null; + + var result = CreateInternal(pkh); + if (result is null) + return null; + + result.PopulateFromCore(pkh); + return result; + } + + private static GameDataPA9? CreateInternal(PKH pkh) + { + var side = GetNearestNeighbor(pkh); + if (side is null) + return null; + + var result = new GameDataPA9(); + result.InitializeFrom(side, pkh); + return result; + } + + private static IGameDataSide? GetNearestNeighbor(PKH pkh) => pkh.DataPK9 as IGameDataSide + ?? pkh.DataPK8 as IGameDataSide + ?? pkh.DataPB8 as IGameDataSide + ?? pkh.DataPB7 as IGameDataSide + ?? pkh.DataPA8; + + public void InitializeFrom(IGameDataSide side, PKH pkh) + { + Ball = side.Ball; + MetLocation = side.MetLocation != Locations.Default8bNone ? side.MetLocation : (ushort)0; + EggLocation = side.EggLocation != Locations.Default8bNone ? side.EggLocation : (ushort)0; + + if (side is IScaledSize3 s3) + Scale = s3.Scale; + else + Scale = pkh.HeightScalar; + if (side is IGameDataSplitAbility a) + AbilityNumber = a.AbilityNumber; + else + AbilityNumber = 1; + + PopulateFromCore(pkh); + } + + private void PopulateFromCore(PKH pkh) + { + Obedience_Level = pkh.MetLevel; + + var pi = PersonalTable.ZA.GetFormEntry(pkh.Species, pkh.Form); + Ability = (ushort)pi.GetAbilityAtIndex(AbilityNumber >> 1); + + var level = Experience.GetLevel(pkh.EXP, pi.EXPGrowth); + this.ResetMoves(pkh.Species, pkh.Form, level, LearnSource9ZA.Instance, EntityContext.Gen9); + } +} diff --git a/PKHeX.Core/PKM/HOME/HomeCrypto.cs b/PKHeX.Core/PKM/HOME/HomeCrypto.cs index 3e4d97495..e9ade3239 100644 --- a/PKHeX.Core/PKM/HOME/HomeCrypto.cs +++ b/PKHeX.Core/PKM/HOME/HomeCrypto.cs @@ -41,6 +41,9 @@ public static class HomeCrypto /// Latest Version identifier stored in the header. public const int VersionLatest = Version3; + public const int SIZE_4GAME_PA9 = 0x77; // TODO HOME ZA + public const int SIZE_4STORED = 0x2BE; // 702 + public static bool IsKnownVersion(ushort version) => version is Version1 or Version2 or Version3; [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/PKHeX.Core/PKM/HOME/HomeGameDataFormat.cs b/PKHeX.Core/PKM/HOME/HomeGameDataFormat.cs index 2e1682852..6fc2a10b9 100644 --- a/PKHeX.Core/PKM/HOME/HomeGameDataFormat.cs +++ b/PKHeX.Core/PKM/HOME/HomeGameDataFormat.cs @@ -11,4 +11,5 @@ public enum HomeGameDataFormat : byte PA8 = 3, PB8 = 4, PK9 = 5, + PA9 = 6, } diff --git a/PKHeX.Core/PKM/HOME/PKH.cs b/PKHeX.Core/PKM/HOME/PKH.cs index 7055ac83f..0a0a977fa 100644 --- a/PKHeX.Core/PKM/HOME/PKH.cs +++ b/PKHeX.Core/PKM/HOME/PKH.cs @@ -14,6 +14,7 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat public GameDataPA8? DataPA8 { get; private set; } public GameDataPB8? DataPB8 { get; private set; } public GameDataPK9? DataPK9 { get; private set; } + public GameDataPA9? DataPA9 { get; private set; } public override EntityContext Context => EntityContext.None; @@ -59,6 +60,7 @@ private void ReadGameData1(Memory data) HomeGameDataFormat.PA8 => DataPA8 = new GameDataPA8(chunk), HomeGameDataFormat.PB8 => DataPB8 = new GameDataPB8(chunk), HomeGameDataFormat.PK9 => DataPK9 = new GameDataPK9(chunk), + HomeGameDataFormat.PA9 => DataPA9 = new GameDataPA9(chunk), _ => throw new ArgumentException($"Unknown {nameof(HomeGameDataFormat)} {format}"), }; @@ -282,6 +284,7 @@ public byte[] Rebuild() if (DataPA8 is { } pa8) ctr += pa8.WriteTo(span[ctr..]); if (DataPB8 is { } pb8) ctr += pb8.WriteTo(span[ctr..]); if (DataPK9 is { } pk9) ctr += pk9.WriteTo(span[ctr..]); + if (DataPA9 is { } pa9) ctr += pa9.WriteTo(span[ctr..]); WriteUInt16LittleEndian(gameDataLengthSpan, GameDataSize = (ushort)(ctr - gameDataStart)); // Update metadata to ensure we're a valid object. @@ -303,12 +306,14 @@ private int WriteLength if (DataPA8 is {} a8) length += a8.SerializedSize; if (DataPB8 is {} b8) length += b8.SerializedSize; if (DataPK9 is {} k9) length += k9.SerializedSize; + if (DataPA9 is {} a9) length += a9.SerializedSize; return length; } } public override PKH Clone() => new(Data.ToArray()) { + DataPA9 = DataPA9?.Clone(), DataPK9 = DataPK9?.Clone(), DataPK8 = DataPK8?.Clone(), DataPA8 = DataPA8?.Clone(), @@ -318,7 +323,8 @@ public override PKH Clone() => new(Data.ToArray()) public IGameDataSide LatestGameData => OriginalGameData() ?? GetFallbackGameData(); - private IGameDataSide GetFallbackGameData() => DataPB7 + private IGameDataSide GetFallbackGameData() => DataPA9 // Backwards transfer threshold. + ?? DataPB7 ?? DataPK9 ?? DataPB8 ?? DataPA8 @@ -330,6 +336,7 @@ public override PKH Clone() => new(Data.ToArray()) BD or SP => DataPB8 ??= new(), PLA => DataPA8 ??= new(), SL or VL => DataPK9 ??= new(), + GameVersion.ZA => DataPA9 ??= new(), _ => DataPK8 ??= new(), }; @@ -340,6 +347,7 @@ public override PKH Clone() => new(Data.ToArray()) BD or SP => DataPB8, PLA => DataPA8, SL or VL => DataPK9, + GameVersion.ZA => DataPA9, // SW/SH can be confused with others if we didn't seed with the original transfer data. SW or SH => DataPK8 switch @@ -358,6 +366,7 @@ public override PKH Clone() => new(Data.ToArray()) public PB8? ConvertToPB8() => DataPB8 is { } x ? x.ConvertToPKM(this) : (DataPB8 ??= GameDataPB8.TryCreate(this))?.ConvertToPKM(this); public PA8? ConvertToPA8() => DataPA8 is { } x ? x.ConvertToPKM(this) : (DataPA8 ??= GameDataPA8.TryCreate(this))?.ConvertToPKM(this); public PK9? ConvertToPK9() => DataPK9 is { } x ? x.ConvertToPKM(this) : (DataPK9 ??= GameDataPK9.TryCreate(this))?.ConvertToPKM(this); + public PA9? ConvertToPA9() => DataPA9 is { } x ? x.ConvertToPKM(this) : (DataPA9 ??= GameDataPA9.TryCreate(this))?.ConvertToPKM(this); public void CopyTo(PKM pk) => Core.CopyTo(pk); @@ -368,6 +377,7 @@ public static HomeGameDataFormat GetType(Type type) if (type == typeof(PB8)) return HomeGameDataFormat.PB8; if (type == typeof(PA8)) return HomeGameDataFormat.PA8; if (type == typeof(PK9)) return HomeGameDataFormat.PK9; + if (type == typeof(PA9)) return HomeGameDataFormat.PA9; return HomeGameDataFormat.None; } @@ -378,6 +388,7 @@ public static HomeGameDataFormat GetType(Type type) HomeGameDataFormat.PB8 => ConvertToPB8(), HomeGameDataFormat.PA8 => ConvertToPA8(), HomeGameDataFormat.PK9 => ConvertToPK9(), + HomeGameDataFormat.PA9 => ConvertToPA9(), _ => null, }; @@ -400,6 +411,7 @@ public void CopyFrom(PKM pk) else if (pk is PB8 pb8) (DataPB8 ??= new GameDataPB8()).CopyFrom(pb8, this); else if (pk is PA8 pa8) (DataPA8 ??= new GameDataPA8()).CopyFrom(pa8, this); else if (pk is PK9 pk9) (DataPK9 ??= new GameDataPK9()).CopyFrom(pk9, this); + else if (pk is PA9 pa9) (DataPA9 ??= new GameDataPA9()).CopyFrom(pa9, this); } private IGameDataSide? FirstScaleData => DataPK9 ?? DataPA8 as IGameDataSide; diff --git a/PKHeX.Core/PKM/Interfaces/IHyperTrain.cs b/PKHeX.Core/PKM/Interfaces/IHyperTrain.cs index 227415dfc..8a1cacd28 100644 --- a/PKHeX.Core/PKM/Interfaces/IHyperTrain.cs +++ b/PKHeX.Core/PKM/Interfaces/IHyperTrain.cs @@ -1,4 +1,5 @@ using System; +using static PKHeX.Core.EntityContext; namespace PKHeX.Core; @@ -156,8 +157,8 @@ public static bool IsHyperTrainingAvailable(this EntityContext c, byte currentLe /// public static int GetHyperTrainMinLevel(this EntityContext c) => c switch { - EntityContext.Gen7 or EntityContext.Gen8 or EntityContext.Gen8b => LevelHyperTrainMin8, - EntityContext.Gen9 => LevelHyperTrainMin9, + Gen7 or Gen8 or Gen8b => LevelHyperTrainMin8, + Gen9 or Gen9a => LevelHyperTrainMin9, _ => 101, }; @@ -172,10 +173,10 @@ public static int GetHyperTrainMinLevel(this IHyperTrain _, EvolutionHistory h, { // HOME 3.0.0+ disallows inbound transfers of Hyper Trained Pokémon below level 100. // PokeDupeChecker in BD/SP will DprIllegal if < 100, even if it was legitimately trained in S/V+. - if (current == EntityContext.Gen8b) + if (current == Gen8b) return LevelHyperTrainMin8; - if (h.HasVisitedGen9) + if (h.HasVisitedGen9 || h.HasVisitedZA) return LevelHyperTrainMin9; return LevelHyperTrainMin8; } diff --git a/PKHeX.Core/PKM/Interfaces/IPlusRecord.cs b/PKHeX.Core/PKM/Interfaces/IPlusRecord.cs new file mode 100644 index 000000000..f8d37e630 --- /dev/null +++ b/PKHeX.Core/PKM/Interfaces/IPlusRecord.cs @@ -0,0 +1,51 @@ +using System; + +namespace PKHeX.Core; + +/// +/// Exposes info about the Plus Move compatibility and history of use. +/// +public interface IPlusRecord +{ + /// + /// Indicates if the move at the requested index has been flagged. + /// + /// Move shop offering + /// True if flagged + bool GetMovePlusFlag(int index); + + /// + /// Sets the flag indicating that the move at the requested index has been flagged. + /// + /// Move index + /// True if flagged + void SetMovePlusFlag(int index, bool value = true); + + /// + /// Indicates if any move has been flagged. + /// + bool GetMovePlusFlagAny(); + + /// + /// Indicates if any move has been flagged that is outside the permitted range. + /// + bool GetMovePlusFlagAnyImpossible(); +} + +public interface IPermitPlus : IPermitRecord +{ + /// + /// Individual accessed move IDs that a given record remembers. + /// + ReadOnlySpan PlusMoveIndexes { get; } + + /// + /// Maximum count of record flags that are available. + /// + int PlusCountTotal { get; } + + /// + /// Maximum count of record flags that are used. + /// + int PlusCountUsed { get; } +} diff --git a/PKHeX.Core/PKM/PA9.cs b/PKHeX.Core/PKM/PA9.cs new file mode 100644 index 000000000..367a6669c --- /dev/null +++ b/PKHeX.Core/PKM/PA9.cs @@ -0,0 +1,705 @@ +using System; +using System.Numerics; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +/// Generation 9 format. +public sealed class PA9 : PKM, ISanityChecksum, ITechRecord, IObedienceLevel, IHandlerUpdate, IAlpha, IPlusRecord, + IContestStats, IHyperTrain, IScaledSize, IScaledSize3, IFavorite, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, IAppliedMarkings7, + IRibbonIndex, IRibbonSetAffixed, IRibbonSetRibbons, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetCommon9, IRibbonSetMarks, IRibbonSetMark8, IRibbonSetMark9 +{ + public override ReadOnlySpan ExtraBytes => + [ + 0x17, 0x1A, 0x1B, 0x33, 0x3E, 0x3F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xC5, + 0xF7, + 0x115, + ]; + + public override PersonalInfo9ZA PersonalInfo => PersonalTable.ZA.GetFormEntry(Species, Form); + public IPermitRecord Permit => PersonalInfo; + public override EntityContext Context => EntityContext.Gen9a; + + public PA9() : base(PokeCrypto.SIZE_9PARTY) => AffixedRibbon = PKHeX.Core.AffixedRibbon.None; + + public PA9(Memory data) : base(DecryptParty(data)) { } + public override PA9 Clone() => new(Data.ToArray()); + + private static Memory DecryptParty(Memory data) + { + PokeCrypto.DecryptIfEncrypted9(ref data); + if (data.Length >= PokeCrypto.SIZE_9PARTY) + return data; + + var result = new byte[PokeCrypto.SIZE_9PARTY]; + data.Span.CopyTo(result); + return result; + } + + private ushort CalculateChecksum() => Checksums.Add16(Data[8..PokeCrypto.SIZE_9STORED]); + + // Simple Generated Attributes + public override byte CurrentFriendship + { + get => CurrentHandler == 0 ? OriginalTrainerFriendship : HandlingTrainerFriendship; + set { if (CurrentHandler == 0) OriginalTrainerFriendship = value; else HandlingTrainerFriendship = value; } + } + + public override int SIZE_PARTY => PokeCrypto.SIZE_9PARTY; + public override int SIZE_STORED => PokeCrypto.SIZE_9STORED; + + public override bool ChecksumValid => CalculateChecksum() == Checksum; + public override void RefreshChecksum() => Checksum = CalculateChecksum(); + public override bool Valid { get => Sanity == 0 && ChecksumValid; set { if (!value) return; Sanity = 0; RefreshChecksum(); } } + + // Trash Bytes + public override Span NicknameTrash => Data.Slice(0x58, 26); + public override Span HandlingTrainerTrash => Data.Slice(0xA8, 26); + public override Span OriginalTrainerTrash => Data.Slice(0xF8, 26); + public override int TrashCharCountTrainer => 13; + public override int TrashCharCountNickname => 13; + + // Maximums + public override int MaxIV => 31; + public override int MaxEV => EffortValues.Max252; + public override int MaxStringLengthTrainer => 12; + public override int MaxStringLengthNickname => 12; + + public override uint PSV => ((PID >> 16) ^ (PID & 0xFFFF)) >> 4; + public override uint TSV => (uint)(TID16 ^ SID16) >> 4; + public override bool IsUntraded => Data[0xA8] == 0 && Data[0xA8 + 1] == 0 && (IsUnhatchedEgg || Format == Generation); // immediately terminated HandlingTrainerName data (\0) + public bool IsUnhatchedEgg => Version == 0 && IsEgg; + + // Complex Generated Attributes + public override int Characteristic => EntityCharacteristic.GetCharacteristicInit0(EncryptionConstant, IV32); + + // Methods + protected override byte[] Encrypt() + { + RefreshChecksum(); + return PokeCrypto.EncryptArray9(Data); + } + + public void FixRelearn() + { + while (true) + { + if (RelearnMove4 != 0 && RelearnMove3 == 0) + { + RelearnMove3 = RelearnMove4; + RelearnMove4 = 0; + } + if (RelearnMove3 != 0 && RelearnMove2 == 0) + { + RelearnMove2 = RelearnMove3; + RelearnMove3 = 0; + continue; + } + if (RelearnMove2 != 0 && RelearnMove1 == 0) + { + RelearnMove1 = RelearnMove2; + RelearnMove2 = 0; + continue; + } + break; + } + } + + public override uint EncryptionConstant { get => ReadUInt32LittleEndian(Data); set => WriteUInt32LittleEndian(Data, value); } + public ushort Sanity { get => ReadUInt16LittleEndian(Data[0x04..]); set => WriteUInt16LittleEndian(Data[0x04..], value); } + public ushort Checksum { get => ReadUInt16LittleEndian(Data[0x06..]); set => WriteUInt16LittleEndian(Data[0x06..], value); } + + // Structure + #region Block A + public ushort SpeciesInternal { get => ReadUInt16LittleEndian(Data[0x08..]); set => WriteUInt16LittleEndian(Data[0x08..], value); } + public override ushort Species { get => SpeciesConverter.GetNational9(SpeciesInternal); set => SpeciesInternal = SpeciesConverter.GetInternal9(value); } + public override int HeldItem { get => ReadUInt16LittleEndian(Data[0x0A..]); set => WriteUInt16LittleEndian(Data[0x0A..], (ushort)value); } + public override uint ID32 { get => ReadUInt32LittleEndian(Data[0x0C..]); set => WriteUInt32LittleEndian(Data[0x0C..], value); } + public override ushort TID16 { get => ReadUInt16LittleEndian(Data[0x0C..]); set => WriteUInt16LittleEndian(Data[0x0C..], value); } + public override ushort SID16 { get => ReadUInt16LittleEndian(Data[0x0E..]); set => WriteUInt16LittleEndian(Data[0x0E..], value); } + public override uint EXP { get => ReadUInt32LittleEndian(Data[0x10..]); set => WriteUInt32LittleEndian(Data[0x10..], value); } + public override int Ability { get => ReadUInt16LittleEndian(Data[0x14..]); set => WriteUInt16LittleEndian(Data[0x14..], (ushort)value); } + public override int AbilityNumber { get => Data[0x16] & 7; set => Data[0x16] = (byte)((Data[0x16] & ~7) | (value & 7)); } + public bool IsFavorite { get => (Data[0x16] & 8) != 0; set => Data[0x16] = (byte)((Data[0x16] & ~8) | ((value ? 1 : 0) << 3)); } // unused, was in LGPE but not in SWSH + // 0x17 alignment unused + public ushort MarkingValue { get => ReadUInt16LittleEndian(Data[0x18..]); set => WriteUInt16LittleEndian(Data[0x18..], value); } + // 0x1A alignment unused + // 0x1B alignment unused + public override uint PID { get => ReadUInt32LittleEndian(Data[0x1C..]); set => WriteUInt32LittleEndian(Data[0x1C..], value); } + public override Nature Nature { get => (Nature)Data[0x20]; set => Data[0x20] = (byte)value; } + public override Nature StatNature { get => (Nature)Data[0x21]; set => Data[0x21] = (byte)value; } + public override bool FatefulEncounter { get => (Data[0x22] & 1) == 1; set => Data[0x22] = (byte)((Data[0x22] & ~0x01) | (value ? 1 : 0)); } + public override byte Gender { get => (byte)((Data[0x22] >> 1) & 0x3); set => Data[0x22] = (byte)((Data[0x22] & 0xF9) | (value << 1)); } + public bool IsAlpha { get => Data[0x23] != 0; set => Data[0x23] = (byte)(value ? 1 : 0); } + public override byte Form { get => Data[0x24]; set => WriteUInt16LittleEndian(Data[0x24..], value); } + public override int EV_HP { get => Data[0x26]; set => Data[0x26] = (byte)value; } + public override int EV_ATK { get => Data[0x27]; set => Data[0x27] = (byte)value; } + public override int EV_DEF { get => Data[0x28]; set => Data[0x28] = (byte)value; } + public override int EV_SPE { get => Data[0x29]; set => Data[0x29] = (byte)value; } + public override int EV_SPA { get => Data[0x2A]; set => Data[0x2A] = (byte)value; } + public override int EV_SPD { get => Data[0x2B]; set => Data[0x2B] = (byte)value; } + public byte ContestCool { get => Data[0x2C]; set => Data[0x2C] = value; } + public byte ContestBeauty { get => Data[0x2D]; set => Data[0x2D] = value; } + public byte ContestCute { get => Data[0x2E]; set => Data[0x2E] = value; } + public byte ContestSmart { get => Data[0x2F]; set => Data[0x2F] = value; } + public byte ContestTough { get => Data[0x30]; set => Data[0x30] = value; } + public byte ContestSheen { get => Data[0x31]; set => Data[0x31] = value; } + public byte PokerusState { get => Data[0x32]; set => Data[0x32] = value; } + public override int PokerusDays { get => PokerusState & 0xF; set => PokerusState = (byte)((PokerusState & ~0xF) | value); } + public override int PokerusStrain { get => PokerusState >> 4; set => PokerusState = (byte)((PokerusState & 0xF) | (value << 4)); } + // 0x33 unused padding + + // ribbon u32 + public bool RibbonChampionKalos { get => FlagUtil.GetFlag(Data, 0x34, 0); set => FlagUtil.SetFlag(Data, 0x34, 0, value); } + public bool RibbonChampionG3 { get => FlagUtil.GetFlag(Data, 0x34, 1); set => FlagUtil.SetFlag(Data, 0x34, 1, value); } + public bool RibbonChampionSinnoh { get => FlagUtil.GetFlag(Data, 0x34, 2); set => FlagUtil.SetFlag(Data, 0x34, 2, value); } + public bool RibbonBestFriends { get => FlagUtil.GetFlag(Data, 0x34, 3); set => FlagUtil.SetFlag(Data, 0x34, 3, value); } + public bool RibbonTraining { get => FlagUtil.GetFlag(Data, 0x34, 4); set => FlagUtil.SetFlag(Data, 0x34, 4, value); } + public bool RibbonBattlerSkillful { get => FlagUtil.GetFlag(Data, 0x34, 5); set => FlagUtil.SetFlag(Data, 0x34, 5, value); } + public bool RibbonBattlerExpert { get => FlagUtil.GetFlag(Data, 0x34, 6); set => FlagUtil.SetFlag(Data, 0x34, 6, value); } + public bool RibbonEffort { get => FlagUtil.GetFlag(Data, 0x34, 7); set => FlagUtil.SetFlag(Data, 0x34, 7, value); } + + public bool RibbonAlert { get => FlagUtil.GetFlag(Data, 0x35, 0); set => FlagUtil.SetFlag(Data, 0x35, 0, value); } + public bool RibbonShock { get => FlagUtil.GetFlag(Data, 0x35, 1); set => FlagUtil.SetFlag(Data, 0x35, 1, value); } + public bool RibbonDowncast { get => FlagUtil.GetFlag(Data, 0x35, 2); set => FlagUtil.SetFlag(Data, 0x35, 2, value); } + public bool RibbonCareless { get => FlagUtil.GetFlag(Data, 0x35, 3); set => FlagUtil.SetFlag(Data, 0x35, 3, value); } + public bool RibbonRelax { get => FlagUtil.GetFlag(Data, 0x35, 4); set => FlagUtil.SetFlag(Data, 0x35, 4, value); } + public bool RibbonSnooze { get => FlagUtil.GetFlag(Data, 0x35, 5); set => FlagUtil.SetFlag(Data, 0x35, 5, value); } + public bool RibbonSmile { get => FlagUtil.GetFlag(Data, 0x35, 6); set => FlagUtil.SetFlag(Data, 0x35, 6, value); } + public bool RibbonGorgeous { get => FlagUtil.GetFlag(Data, 0x35, 7); set => FlagUtil.SetFlag(Data, 0x35, 7, value); } + + public bool RibbonRoyal { get => FlagUtil.GetFlag(Data, 0x36, 0); set => FlagUtil.SetFlag(Data, 0x36, 0, value); } + public bool RibbonGorgeousRoyal { get => FlagUtil.GetFlag(Data, 0x36, 1); set => FlagUtil.SetFlag(Data, 0x36, 1, value); } + public bool RibbonArtist { get => FlagUtil.GetFlag(Data, 0x36, 2); set => FlagUtil.SetFlag(Data, 0x36, 2, value); } + public bool RibbonFootprint { get => FlagUtil.GetFlag(Data, 0x36, 3); set => FlagUtil.SetFlag(Data, 0x36, 3, value); } + public bool RibbonRecord { get => FlagUtil.GetFlag(Data, 0x36, 4); set => FlagUtil.SetFlag(Data, 0x36, 4, value); } + public bool RibbonLegend { get => FlagUtil.GetFlag(Data, 0x36, 5); set => FlagUtil.SetFlag(Data, 0x36, 5, value); } + public bool RibbonCountry { get => FlagUtil.GetFlag(Data, 0x36, 6); set => FlagUtil.SetFlag(Data, 0x36, 6, value); } + public bool RibbonNational { get => FlagUtil.GetFlag(Data, 0x36, 7); set => FlagUtil.SetFlag(Data, 0x36, 7, value); } + + public bool RibbonEarth { get => FlagUtil.GetFlag(Data, 0x37, 0); set => FlagUtil.SetFlag(Data, 0x37, 0, value); } + public bool RibbonWorld { get => FlagUtil.GetFlag(Data, 0x37, 1); set => FlagUtil.SetFlag(Data, 0x37, 1, value); } + public bool RibbonClassic { get => FlagUtil.GetFlag(Data, 0x37, 2); set => FlagUtil.SetFlag(Data, 0x37, 2, value); } + public bool RibbonPremier { get => FlagUtil.GetFlag(Data, 0x37, 3); set => FlagUtil.SetFlag(Data, 0x37, 3, value); } + public bool RibbonEvent { get => FlagUtil.GetFlag(Data, 0x37, 4); set => FlagUtil.SetFlag(Data, 0x37, 4, value); } + public bool RibbonBirthday { get => FlagUtil.GetFlag(Data, 0x37, 5); set => FlagUtil.SetFlag(Data, 0x37, 5, value); } + public bool RibbonSpecial { get => FlagUtil.GetFlag(Data, 0x37, 6); set => FlagUtil.SetFlag(Data, 0x37, 6, value); } + public bool RibbonSouvenir { get => FlagUtil.GetFlag(Data, 0x37, 7); set => FlagUtil.SetFlag(Data, 0x37, 7, value); } + + // ribbon u32 + public bool RibbonWishing { get => FlagUtil.GetFlag(Data, 0x38, 0); set => FlagUtil.SetFlag(Data, 0x38, 0, value); } + public bool RibbonChampionBattle { get => FlagUtil.GetFlag(Data, 0x38, 1); set => FlagUtil.SetFlag(Data, 0x38, 1, value); } + public bool RibbonChampionRegional { get => FlagUtil.GetFlag(Data, 0x38, 2); set => FlagUtil.SetFlag(Data, 0x38, 2, value); } + public bool RibbonChampionNational { get => FlagUtil.GetFlag(Data, 0x38, 3); set => FlagUtil.SetFlag(Data, 0x38, 3, value); } + public bool RibbonChampionWorld { get => FlagUtil.GetFlag(Data, 0x38, 4); set => FlagUtil.SetFlag(Data, 0x38, 4, value); } + public bool HasContestMemoryRibbon { get => FlagUtil.GetFlag(Data, 0x38, 5); set => FlagUtil.SetFlag(Data, 0x38, 5, value); } + public bool HasBattleMemoryRibbon { get => FlagUtil.GetFlag(Data, 0x38, 6); set => FlagUtil.SetFlag(Data, 0x38, 6, value); } + public bool RibbonChampionG6Hoenn { get => FlagUtil.GetFlag(Data, 0x38, 7); set => FlagUtil.SetFlag(Data, 0x38, 7, value); } + + public bool RibbonContestStar { get => FlagUtil.GetFlag(Data, 0x39, 0); set => FlagUtil.SetFlag(Data, 0x39, 0, value); } + public bool RibbonMasterCoolness { get => FlagUtil.GetFlag(Data, 0x39, 1); set => FlagUtil.SetFlag(Data, 0x39, 1, value); } + public bool RibbonMasterBeauty { get => FlagUtil.GetFlag(Data, 0x39, 2); set => FlagUtil.SetFlag(Data, 0x39, 2, value); } + public bool RibbonMasterCuteness { get => FlagUtil.GetFlag(Data, 0x39, 3); set => FlagUtil.SetFlag(Data, 0x39, 3, value); } + public bool RibbonMasterCleverness { get => FlagUtil.GetFlag(Data, 0x39, 4); set => FlagUtil.SetFlag(Data, 0x39, 4, value); } + public bool RibbonMasterToughness { get => FlagUtil.GetFlag(Data, 0x39, 5); set => FlagUtil.SetFlag(Data, 0x39, 5, value); } + public bool RibbonChampionAlola { get => FlagUtil.GetFlag(Data, 0x39, 6); set => FlagUtil.SetFlag(Data, 0x39, 6, value); } + public bool RibbonBattleRoyale { get => FlagUtil.GetFlag(Data, 0x39, 7); set => FlagUtil.SetFlag(Data, 0x39, 7, value); } + + public bool RibbonBattleTreeGreat { get => FlagUtil.GetFlag(Data, 0x3A, 0); set => FlagUtil.SetFlag(Data, 0x3A, 0, value); } + public bool RibbonBattleTreeMaster { get => FlagUtil.GetFlag(Data, 0x3A, 1); set => FlagUtil.SetFlag(Data, 0x3A, 1, value); } + public bool RibbonChampionGalar { get => FlagUtil.GetFlag(Data, 0x3A, 2); set => FlagUtil.SetFlag(Data, 0x3A, 2, value); } + public bool RibbonTowerMaster { get => FlagUtil.GetFlag(Data, 0x3A, 3); set => FlagUtil.SetFlag(Data, 0x3A, 3, value); } + public bool RibbonMasterRank { get => FlagUtil.GetFlag(Data, 0x3A, 4); set => FlagUtil.SetFlag(Data, 0x3A, 4, value); } + public bool RibbonMarkLunchtime { get => FlagUtil.GetFlag(Data, 0x3A, 5); set => FlagUtil.SetFlag(Data, 0x3A, 5, value); } + public bool RibbonMarkSleepyTime { get => FlagUtil.GetFlag(Data, 0x3A, 6); set => FlagUtil.SetFlag(Data, 0x3A, 6, value); } + public bool RibbonMarkDusk { get => FlagUtil.GetFlag(Data, 0x3A, 7); set => FlagUtil.SetFlag(Data, 0x3A, 7, value); } + + public bool RibbonMarkDawn { get => FlagUtil.GetFlag(Data, 0x3B, 0); set => FlagUtil.SetFlag(Data, 0x3B, 0, value); } + public bool RibbonMarkCloudy { get => FlagUtil.GetFlag(Data, 0x3B, 1); set => FlagUtil.SetFlag(Data, 0x3B, 1, value); } + public bool RibbonMarkRainy { get => FlagUtil.GetFlag(Data, 0x3B, 2); set => FlagUtil.SetFlag(Data, 0x3B, 2, value); } + public bool RibbonMarkStormy { get => FlagUtil.GetFlag(Data, 0x3B, 3); set => FlagUtil.SetFlag(Data, 0x3B, 3, value); } + public bool RibbonMarkSnowy { get => FlagUtil.GetFlag(Data, 0x3B, 4); set => FlagUtil.SetFlag(Data, 0x3B, 4, value); } + public bool RibbonMarkBlizzard { get => FlagUtil.GetFlag(Data, 0x3B, 5); set => FlagUtil.SetFlag(Data, 0x3B, 5, value); } + public bool RibbonMarkDry { get => FlagUtil.GetFlag(Data, 0x3B, 6); set => FlagUtil.SetFlag(Data, 0x3B, 6, value); } + public bool RibbonMarkSandstorm { get => FlagUtil.GetFlag(Data, 0x3B, 7); set => FlagUtil.SetFlag(Data, 0x3B, 7, value); } + public byte RibbonCountMemoryContest { get => Data[0x3C]; set => HasContestMemoryRibbon = (Data[0x3C] = value) != 0; } + public byte RibbonCountMemoryBattle { get => Data[0x3D]; set => HasBattleMemoryRibbon = (Data[0x3D] = value) != 0; } + // 0x3E padding + // 0x3F padding + + // 0x40 Ribbon 1 + public bool RibbonMarkMisty { get => FlagUtil.GetFlag(Data, 0x40, 0); set => FlagUtil.SetFlag(Data, 0x40, 0, value); } + public bool RibbonMarkDestiny { get => FlagUtil.GetFlag(Data, 0x40, 1); set => FlagUtil.SetFlag(Data, 0x40, 1, value); } + public bool RibbonMarkFishing { get => FlagUtil.GetFlag(Data, 0x40, 2); set => FlagUtil.SetFlag(Data, 0x40, 2, value); } + public bool RibbonMarkCurry { get => FlagUtil.GetFlag(Data, 0x40, 3); set => FlagUtil.SetFlag(Data, 0x40, 3, value); } + public bool RibbonMarkUncommon { get => FlagUtil.GetFlag(Data, 0x40, 4); set => FlagUtil.SetFlag(Data, 0x40, 4, value); } + public bool RibbonMarkRare { get => FlagUtil.GetFlag(Data, 0x40, 5); set => FlagUtil.SetFlag(Data, 0x40, 5, value); } + public bool RibbonMarkRowdy { get => FlagUtil.GetFlag(Data, 0x40, 6); set => FlagUtil.SetFlag(Data, 0x40, 6, value); } + public bool RibbonMarkAbsentMinded { get => FlagUtil.GetFlag(Data, 0x40, 7); set => FlagUtil.SetFlag(Data, 0x40, 7, value); } + + public bool RibbonMarkJittery { get => FlagUtil.GetFlag(Data, 0x41, 0); set => FlagUtil.SetFlag(Data, 0x41, 0, value); } + public bool RibbonMarkExcited { get => FlagUtil.GetFlag(Data, 0x41, 1); set => FlagUtil.SetFlag(Data, 0x41, 1, value); } + public bool RibbonMarkCharismatic { get => FlagUtil.GetFlag(Data, 0x41, 2); set => FlagUtil.SetFlag(Data, 0x41, 2, value); } + public bool RibbonMarkCalmness { get => FlagUtil.GetFlag(Data, 0x41, 3); set => FlagUtil.SetFlag(Data, 0x41, 3, value); } + public bool RibbonMarkIntense { get => FlagUtil.GetFlag(Data, 0x41, 4); set => FlagUtil.SetFlag(Data, 0x41, 4, value); } + public bool RibbonMarkZonedOut { get => FlagUtil.GetFlag(Data, 0x41, 5); set => FlagUtil.SetFlag(Data, 0x41, 5, value); } + public bool RibbonMarkJoyful { get => FlagUtil.GetFlag(Data, 0x41, 6); set => FlagUtil.SetFlag(Data, 0x41, 6, value); } + public bool RibbonMarkAngry { get => FlagUtil.GetFlag(Data, 0x41, 7); set => FlagUtil.SetFlag(Data, 0x41, 7, value); } + + public bool RibbonMarkSmiley { get => FlagUtil.GetFlag(Data, 0x42, 0); set => FlagUtil.SetFlag(Data, 0x42, 0, value); } + public bool RibbonMarkTeary { get => FlagUtil.GetFlag(Data, 0x42, 1); set => FlagUtil.SetFlag(Data, 0x42, 1, value); } + public bool RibbonMarkUpbeat { get => FlagUtil.GetFlag(Data, 0x42, 2); set => FlagUtil.SetFlag(Data, 0x42, 2, value); } + public bool RibbonMarkPeeved { get => FlagUtil.GetFlag(Data, 0x42, 3); set => FlagUtil.SetFlag(Data, 0x42, 3, value); } + public bool RibbonMarkIntellectual { get => FlagUtil.GetFlag(Data, 0x42, 4); set => FlagUtil.SetFlag(Data, 0x42, 4, value); } + public bool RibbonMarkFerocious { get => FlagUtil.GetFlag(Data, 0x42, 5); set => FlagUtil.SetFlag(Data, 0x42, 5, value); } + public bool RibbonMarkCrafty { get => FlagUtil.GetFlag(Data, 0x42, 6); set => FlagUtil.SetFlag(Data, 0x42, 6, value); } + public bool RibbonMarkScowling { get => FlagUtil.GetFlag(Data, 0x42, 7); set => FlagUtil.SetFlag(Data, 0x42, 7, value); } + + public bool RibbonMarkKindly { get => FlagUtil.GetFlag(Data, 0x43, 0); set => FlagUtil.SetFlag(Data, 0x43, 0, value); } + public bool RibbonMarkFlustered { get => FlagUtil.GetFlag(Data, 0x43, 1); set => FlagUtil.SetFlag(Data, 0x43, 1, value); } + public bool RibbonMarkPumpedUp { get => FlagUtil.GetFlag(Data, 0x43, 2); set => FlagUtil.SetFlag(Data, 0x43, 2, value); } + public bool RibbonMarkZeroEnergy { get => FlagUtil.GetFlag(Data, 0x43, 3); set => FlagUtil.SetFlag(Data, 0x43, 3, value); } + public bool RibbonMarkPrideful { get => FlagUtil.GetFlag(Data, 0x43, 4); set => FlagUtil.SetFlag(Data, 0x43, 4, value); } + public bool RibbonMarkUnsure { get => FlagUtil.GetFlag(Data, 0x43, 5); set => FlagUtil.SetFlag(Data, 0x43, 5, value); } + public bool RibbonMarkHumble { get => FlagUtil.GetFlag(Data, 0x43, 6); set => FlagUtil.SetFlag(Data, 0x43, 6, value); } + public bool RibbonMarkThorny { get => FlagUtil.GetFlag(Data, 0x43, 7); set => FlagUtil.SetFlag(Data, 0x43, 7, value); } + // 0x44 Ribbon 2 + + public bool RibbonMarkVigor { get => FlagUtil.GetFlag(Data, 0x44, 0); set => FlagUtil.SetFlag(Data, 0x44, 0, value); } + public bool RibbonMarkSlump { get => FlagUtil.GetFlag(Data, 0x44, 1); set => FlagUtil.SetFlag(Data, 0x44, 1, value); } + public bool RibbonHisui { get => FlagUtil.GetFlag(Data, 0x44, 2); set => FlagUtil.SetFlag(Data, 0x44, 2, value); } + public bool RibbonTwinklingStar { get => FlagUtil.GetFlag(Data, 0x44, 3); set => FlagUtil.SetFlag(Data, 0x44, 3, value); } + public bool RibbonChampionPaldea { get => FlagUtil.GetFlag(Data, 0x44, 4); set => FlagUtil.SetFlag(Data, 0x44, 4, value); } + public bool RibbonMarkJumbo { get => FlagUtil.GetFlag(Data, 0x44, 5); set => FlagUtil.SetFlag(Data, 0x44, 5, value); } + public bool RibbonMarkMini { get => FlagUtil.GetFlag(Data, 0x44, 6); set => FlagUtil.SetFlag(Data, 0x44, 6, value); } + public bool RibbonMarkItemfinder { get => FlagUtil.GetFlag(Data, 0x44, 7); set => FlagUtil.SetFlag(Data, 0x44, 7, value); } + + public bool RibbonMarkPartner { get => FlagUtil.GetFlag(Data, 0x45, 0); set => FlagUtil.SetFlag(Data, 0x45, 0, value); } + public bool RibbonMarkGourmand { get => FlagUtil.GetFlag(Data, 0x45, 1); set => FlagUtil.SetFlag(Data, 0x45, 1, value); } + public bool RibbonOnceInALifetime { get => FlagUtil.GetFlag(Data, 0x45, 2); set => FlagUtil.SetFlag(Data, 0x45, 2, value); } + public bool RibbonMarkAlpha { get => FlagUtil.GetFlag(Data, 0x45, 3); set => FlagUtil.SetFlag(Data, 0x45, 3, value); } + public bool RibbonMarkMightiest { get => FlagUtil.GetFlag(Data, 0x45, 4); set => FlagUtil.SetFlag(Data, 0x45, 4, value); } + public bool RibbonMarkTitan { get => FlagUtil.GetFlag(Data, 0x45, 5); set => FlagUtil.SetFlag(Data, 0x45, 5, value); } + public bool RibbonPartner { get => FlagUtil.GetFlag(Data, 0x45, 6); set => FlagUtil.SetFlag(Data, 0x45, 6, value); } + public bool RIB45_7 { get => FlagUtil.GetFlag(Data, 0x45, 7); set => FlagUtil.SetFlag(Data, 0x45, 7, value); } + + public bool RIB46_0 { get => FlagUtil.GetFlag(Data, 0x46, 0); set => FlagUtil.SetFlag(Data, 0x46, 0, value); } + public bool RIB46_1 { get => FlagUtil.GetFlag(Data, 0x46, 1); set => FlagUtil.SetFlag(Data, 0x46, 1, value); } + public bool RIB46_2 { get => FlagUtil.GetFlag(Data, 0x46, 2); set => FlagUtil.SetFlag(Data, 0x46, 2, value); } + public bool RIB46_3 { get => FlagUtil.GetFlag(Data, 0x46, 3); set => FlagUtil.SetFlag(Data, 0x46, 3, value); } + public bool RIB46_4 { get => FlagUtil.GetFlag(Data, 0x46, 4); set => FlagUtil.SetFlag(Data, 0x46, 4, value); } + public bool RIB46_5 { get => FlagUtil.GetFlag(Data, 0x46, 5); set => FlagUtil.SetFlag(Data, 0x46, 5, value); } + public bool RIB46_6 { get => FlagUtil.GetFlag(Data, 0x46, 6); set => FlagUtil.SetFlag(Data, 0x46, 6, value); } + public bool RIB46_7 { get => FlagUtil.GetFlag(Data, 0x46, 7); set => FlagUtil.SetFlag(Data, 0x46, 7, value); } + + public bool RIB47_0 { get => FlagUtil.GetFlag(Data, 0x47, 0); set => FlagUtil.SetFlag(Data, 0x47, 0, value); } + public bool RIB47_1 { get => FlagUtil.GetFlag(Data, 0x47, 1); set => FlagUtil.SetFlag(Data, 0x47, 1, value); } + public bool RIB47_2 { get => FlagUtil.GetFlag(Data, 0x47, 2); set => FlagUtil.SetFlag(Data, 0x47, 2, value); } + public bool RIB47_3 { get => FlagUtil.GetFlag(Data, 0x47, 3); set => FlagUtil.SetFlag(Data, 0x47, 3, value); } + public bool RIB47_4 { get => FlagUtil.GetFlag(Data, 0x47, 4); set => FlagUtil.SetFlag(Data, 0x47, 4, value); } + public bool RIB47_5 { get => FlagUtil.GetFlag(Data, 0x47, 5); set => FlagUtil.SetFlag(Data, 0x47, 5, value); } + public bool RIB47_6 { get => FlagUtil.GetFlag(Data, 0x47, 6); set => FlagUtil.SetFlag(Data, 0x47, 6, value); } + public bool RIB47_7 { get => FlagUtil.GetFlag(Data, 0x47, 7); set => FlagUtil.SetFlag(Data, 0x47, 7, value); } + + public int RibbonCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x34..]) & 0b00000000_00011111__11111111_11111111__11111111_11111111__11111111_11111111) + + BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x40..]) & 0b00000000_00000000__00000100_00011100__00000000_00000000__00000000_00000000); + public int MarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x34..]) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000) + + BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x40..]) & 0b00000000_00000000__00111011_11100011__11111111_11111111__11111111_11111111); + public int RibbonMarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x34..]) & 0b11111111_11111111__11111111_11111111__11111111_11111111__11111111_11111111) + + BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x40..]) & 0b00000000_00000000__00111111_11111111__11111111_11111111__11111111_11111111); + + public bool HasMarkEncounter8 => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x34..]) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000) + + BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x40..]) & 0b00000000_00000000__00000000_00000011__11111111_11111111__11111111_11111111) != 0; + public bool HasMarkEncounter9 => (Data[0x45] & 0b00111000) != 0; + + public byte HeightScalar { get => Data[0x48]; set => Data[0x48] = value; } + public byte WeightScalar { get => Data[0x49]; set => Data[0x49] = value; } + public byte Scale { get => Data[0x4A]; set => Data[0x4A] = value; } + + // 0x4B-0x57 is unused. S/V used them for DLC TM Record Flags. + + #endregion + #region Block B + public override string Nickname + { + get => StringConverter8.GetString(NicknameTrash); + set => StringConverter8.SetString(NicknameTrash, value, 12, StringConverterOption.None); + } + + // 2 bytes for \0, automatically handled above + + public override ushort Move1 { get => ReadUInt16LittleEndian(Data[0x72..]); set => WriteUInt16LittleEndian(Data[0x72..], value); } + public override ushort Move2 { get => ReadUInt16LittleEndian(Data[0x74..]); set => WriteUInt16LittleEndian(Data[0x74..], value); } + public override ushort Move3 { get => ReadUInt16LittleEndian(Data[0x76..]); set => WriteUInt16LittleEndian(Data[0x76..], value); } + public override ushort Move4 { get => ReadUInt16LittleEndian(Data[0x78..]); set => WriteUInt16LittleEndian(Data[0x78..], value); } + + public override int Move1_PP { get => Data[0x7A]; set => Data[0x7A] = (byte)value; } + public override int Move2_PP { get => Data[0x7B]; set => Data[0x7B] = (byte)value; } + public override int Move3_PP { get => Data[0x7C]; set => Data[0x7C] = (byte)value; } + public override int Move4_PP { get => Data[0x7D]; set => Data[0x7D] = (byte)value; } + public override int Move1_PPUps { get => Data[0x7E]; set => Data[0x7E] = (byte)value; } + public override int Move2_PPUps { get => Data[0x7F]; set => Data[0x7F] = (byte)value; } + public override int Move3_PPUps { get => Data[0x80]; set => Data[0x80] = (byte)value; } + public override int Move4_PPUps { get => Data[0x81]; set => Data[0x81] = (byte)value; } + + public override ushort RelearnMove1 { get => ReadUInt16LittleEndian(Data[0x82..]); set => WriteUInt16LittleEndian(Data[0x82..], value); } + public override ushort RelearnMove2 { get => ReadUInt16LittleEndian(Data[0x84..]); set => WriteUInt16LittleEndian(Data[0x84..], value); } + public override ushort RelearnMove3 { get => ReadUInt16LittleEndian(Data[0x86..]); set => WriteUInt16LittleEndian(Data[0x86..], value); } + public override ushort RelearnMove4 { get => ReadUInt16LittleEndian(Data[0x88..]); set => WriteUInt16LittleEndian(Data[0x88..], value); } + + public override int Stat_HPCurrent { get => ReadUInt16LittleEndian(Data[0x8A..]); set => WriteUInt16LittleEndian(Data[0x8A..], (ushort)value); } + + public uint IV32 { get => ReadUInt32LittleEndian(Data[0x8C..]); set => WriteUInt32LittleEndian(Data[0x8C..], value); } + public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | ((value > 31 ? 31u : (uint)value) << 00); } + public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | ((value > 31 ? 31u : (uint)value) << 05); } + public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | ((value > 31 ? 31u : (uint)value) << 10); } + public override int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 15)) | ((value > 31 ? 31u : (uint)value) << 15); } + public override int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 20)) | ((value > 31 ? 31u : (uint)value) << 20); } + public override int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 25)) | ((value > 31 ? 31u : (uint)value) << 25); } + public override bool IsEgg { get => ((IV32 >> 30) & 1) == 1; set => IV32 = (IV32 & ~0x40000000u) | (value ? 0x40000000u : 0u); } + public override bool IsNicknamed { get => ((IV32 >> 31) & 1) == 1; set => IV32 = (IV32 & 0x7FFFFFFFu) | (value ? 0x80000000u : 0u); } + public override int Status_Condition { get => ReadInt32LittleEndian(Data[0x90..]); set => WriteInt32LittleEndian(Data[0x90..], value); } + + // 0x94: 0xC Plus move record flags + + // 0xA0-0xA7 unused + + #endregion + #region Block C + public override string HandlingTrainerName + { + get => StringConverter8.GetString(HandlingTrainerTrash); + set => StringConverter8.SetString(HandlingTrainerTrash, value, 12, StringConverterOption.None); + } + + public override byte HandlingTrainerGender { get => Data[0xC2]; set => Data[0xC2] = value; } + public byte HandlingTrainerLanguage { get => Data[0xC3]; set => Data[0xC3] = value; } + public override byte CurrentHandler { get => Data[0xC4]; set => Data[0xC4] = value; } + // 0xC5 unused (alignment) + public ushort HandlingTrainerID { get => ReadUInt16LittleEndian(Data[0xC6..]); set => WriteUInt16LittleEndian(Data[0xC6..], value); } // unused? + public override byte HandlingTrainerFriendship { get => Data[0xC8]; set => Data[0xC8] = value; } + public byte HandlingTrainerMemoryIntensity { get => Data[0xC9]; set => Data[0xC9] = value; } + public byte HandlingTrainerMemory { get => Data[0xCA]; set => Data[0xCA] = value; } + public byte HandlingTrainerMemoryFeeling { get => Data[0xCB]; set => Data[0xCB] = value; } + public ushort HandlingTrainerMemoryVariable { get => ReadUInt16LittleEndian(Data[0xCC..]); set => WriteUInt16LittleEndian(Data[0xCC..], value); } + public override GameVersion Version { get => (GameVersion)Data[0xCE]; set => Data[0xCE] = (byte)value; } + public GameVersion BattleVersion { get => (GameVersion)Data[0xCF]; set => Data[0xCF] = (byte)value; } + public uint FormArgument { get => ReadUInt32LittleEndian(Data[0xD0..]); set => WriteUInt32LittleEndian(Data[0xD0..], value); } + public byte FormArgumentRemain { get => (byte)FormArgument; set => FormArgument = (FormArgument & ~0xFFu) | value; } + public byte FormArgumentElapsed { get => (byte)(FormArgument >> 8); set => FormArgument = (FormArgument & ~0xFF00u) | (uint)(value << 8); } + public byte FormArgumentMaximum { get => (byte)(FormArgument >> 16); set => FormArgument = (FormArgument & ~0xFF0000u) | (uint)(value << 16); } + public sbyte AffixedRibbon { get => (sbyte)Data[0xD4]; set => Data[0xD4] = (byte)value; } // selected ribbon + public override int Language { get => Data[0xD5]; set => Data[0xD5] = (byte)value; } + + // 0xD6: 33 bytes for plus flags + // 0xF7 unused + + #endregion + #region Block D + public override string OriginalTrainerName + { + get => StringConverter8.GetString(OriginalTrainerTrash); + set => StringConverter8.SetString(OriginalTrainerTrash, value, 12, StringConverterOption.None); + } + + public override byte OriginalTrainerFriendship { get => Data[0x112]; set => Data[0x112] = value; } + public byte OriginalTrainerMemoryIntensity { get => Data[0x113]; set => Data[0x113] = value; } + public byte OriginalTrainerMemory { get => Data[0x114]; set => Data[0x114] = value; } + // 0x115 unused align + public ushort OriginalTrainerMemoryVariable { get => ReadUInt16LittleEndian(Data[0x116..]); set => WriteUInt16LittleEndian(Data[0x116..], value); } + public byte OriginalTrainerMemoryFeeling { get => Data[0x118]; set => Data[0x118] = value; } + public override byte EggYear { get => Data[0x119]; set => Data[0x119] = value; } + public override byte EggMonth { get => Data[0x11A]; set => Data[0x11A] = value; } + public override byte EggDay { get => Data[0x11B]; set => Data[0x11B] = value; } + public override byte MetYear { get => Data[0x11C]; set => Data[0x11C] = value; } + public override byte MetMonth { get => Data[0x11D]; set => Data[0x11D] = value; } + public override byte MetDay { get => Data[0x11E]; set => Data[0x11E] = value; } + public byte ObedienceLevel { get => Data[0x11F]; set => Data[0x11F] = value; } + public override ushort EggLocation { get => ReadUInt16LittleEndian(Data[0x120..]); set => WriteUInt16LittleEndian(Data[0x120..], value); } + public override ushort MetLocation { get => ReadUInt16LittleEndian(Data[0x122..]); set => WriteUInt16LittleEndian(Data[0x122..], value); } + public override byte Ball { get => Data[0x124]; set => Data[0x124] = value; } + public override byte MetLevel { get => (byte)(Data[0x125] & ~0x80); set => Data[0x125] = (byte)((Data[0x125] & 0x80) | value); } + public override byte OriginalTrainerGender { get => (byte)(Data[0x125] >> 7); set => Data[0x125] = (byte)((Data[0x125] & ~0x80) | (value << 7)); } + public byte HyperTrainFlags { get => Data[0x126]; set => Data[0x126] = value; } + public bool HT_HP { get => ((HyperTrainFlags >> 0) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 0)) | ((value ? 1 : 0) << 0)); } + public bool HT_ATK { get => ((HyperTrainFlags >> 1) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 1)) | ((value ? 1 : 0) << 1)); } + public bool HT_DEF { get => ((HyperTrainFlags >> 2) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 2)) | ((value ? 1 : 0) << 2)); } + public bool HT_SPA { get => ((HyperTrainFlags >> 3) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 3)) | ((value ? 1 : 0) << 3)); } + public bool HT_SPD { get => ((HyperTrainFlags >> 4) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 4)) | ((value ? 1 : 0) << 4)); } + public bool HT_SPE { get => ((HyperTrainFlags >> 5) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 5)) | ((value ? 1 : 0) << 5)); } + + public ulong Tracker + { + get => ReadUInt64LittleEndian(Data[0x127..]); + set => WriteUInt64LittleEndian(Data[0x127..], value); + } + + private const int RecordStartBase = 0x12F; + internal const int COUNT_RECORD_BASE = 200; // Up to 200 TM flags, but not all are used. + private const int RecordLengthBase = COUNT_RECORD_BASE / 8; // 0x19 bytes, 8 bits + public Span RecordFlagsBase => Data.Slice(RecordStartBase, RecordLengthBase); + + private const int RecordStartDLC = 0x4B; + internal const int COUNT_RECORD_DLC = 104; // 13 additional bytes allocated for DLC1/2 TM Flags + private const int RecordLengthDLC = COUNT_RECORD_DLC / 8; + public Span RecordFlagsDLC => Data.Slice(RecordStartDLC, RecordLengthDLC); + + public bool GetMoveRecordFlag(int index) + { + if ((uint)index >= COUNT_RECORD_BASE) + return GetMoveRecordFlagDLC(index - COUNT_RECORD_BASE); + int ofs = index >> 3; + return FlagUtil.GetFlag(Data, RecordStartBase + ofs, index & 7); + } + + private bool GetMoveRecordFlagDLC(int index) + { + if ((uint)index >= COUNT_RECORD_DLC) + throw new ArgumentOutOfRangeException(nameof(index)); + int ofs = index >> 3; + return FlagUtil.GetFlag(Data, RecordStartDLC + ofs, index & 7); + } + + public void SetMoveRecordFlag(int index, bool value = true) + { + if ((uint)index >= COUNT_RECORD_BASE) + { + SetMoveRecordFlagDLC(value, index - COUNT_RECORD_BASE); + return; + } + int ofs = index >> 3; + FlagUtil.SetFlag(Data, RecordStartBase + ofs, index & 7, value); + } + + private void SetMoveRecordFlagDLC(bool value, int index) + { + if ((uint)index >= COUNT_RECORD_DLC) + throw new ArgumentOutOfRangeException(nameof(index)); + int ofs = index >> 3; + FlagUtil.SetFlag(Data, RecordStartDLC + ofs, index & 7, value); + } + + public bool GetMoveRecordFlagAny() => GetMoveRecordFlagAnyBase() || GetMoveRecordFlagAnyDLC(); + private bool GetMoveRecordFlagAnyBase() => RecordFlagsBase.ContainsAnyExcept(0); + private bool GetMoveRecordFlagAnyDLC() => RecordFlagsDLC.ContainsAnyExcept(0); + + public void ClearMoveRecordFlags() + { + ClearMoveRecordFlagsBase(); + ClearMoveRecordFlagsDLC(); + } + + private void ClearMoveRecordFlagsBase() => RecordFlagsBase.Clear(); + private void ClearMoveRecordFlagsDLC() => RecordFlagsDLC.Clear(); + + #endregion + #region Battle Stats + public override byte Stat_Level { get => Data[0x148]; set => Data[0x148] = value; } + // 0x149 unused alignment + public override int Stat_HPMax { get => ReadUInt16LittleEndian(Data[0x14A..]); set => WriteUInt16LittleEndian(Data[0x14A..], (ushort)value); } + public override int Stat_ATK { get => ReadUInt16LittleEndian(Data[0x14C..]); set => WriteUInt16LittleEndian(Data[0x14C..], (ushort)value); } + public override int Stat_DEF { get => ReadUInt16LittleEndian(Data[0x14E..]); set => WriteUInt16LittleEndian(Data[0x14E..], (ushort)value); } + public override int Stat_SPE { get => ReadUInt16LittleEndian(Data[0x150..]); set => WriteUInt16LittleEndian(Data[0x150..], (ushort)value); } + public override int Stat_SPA { get => ReadUInt16LittleEndian(Data[0x152..]); set => WriteUInt16LittleEndian(Data[0x152..], (ushort)value); } + public override int Stat_SPD { get => ReadUInt16LittleEndian(Data[0x154..]); set => WriteUInt16LittleEndian(Data[0x154..], (ushort)value); } + #endregion + + public int MarkingCount => 6; + + public MarkingColor GetMarking(int index) + { + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)index, (uint)MarkingCount); + return (MarkingColor)((MarkingValue >> (index * 2)) & 3); + } + + public void SetMarking(int index, MarkingColor value) + { + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)index, (uint)MarkingCount); + var shift = index * 2; + MarkingValue = (ushort)((MarkingValue & ~(0b11 << shift)) | (((byte)value & 3) << shift)); + } + + public MarkingColor MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public MarkingColor MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public MarkingColor MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public MarkingColor MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public MarkingColor MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public MarkingColor MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } + + public bool GetRibbon(int index) => FlagUtil.GetFlag(Data, GetRibbonByte(index), index & 7); + public void SetRibbon(int index, bool value = true) => FlagUtil.SetFlag(Data, GetRibbonByte(index), index & 7, value); + + public int GetRibbonByte(int index) + { + if ((uint)index >= 128) + throw new ArgumentOutOfRangeException(nameof(index)); + if (index < 64) + return 0x34 + (index >> 3); + index -= 64; + return 0x40 + (index >> 3); + } + + // Synthetic Trading Logic + public bool BelongsTo(ITrainerInfo tr) + { + if (tr.Version != Version) + return false; + return BelongsToSkipVersion(tr); + } + + public bool BelongsToSkipVersion(ITrainerInfo tr) + { + if (tr.ID32 != ID32) + return false; + if (tr.Gender != OriginalTrainerGender) + return false; + if (tr.Language != Language) + return false; + + Span ot = stackalloc char[MaxStringLengthTrainer]; + int len = LoadString(OriginalTrainerTrash, ot); + return ot[..len].SequenceEqual(tr.OT); + } + + public void UpdateHandler(ITrainerInfo tr) + { + // Process to the HT if the OT of the Pokémon does not match the SAV's OT info. + if (!TradeOT(tr)) + TradeHT(tr); + } + + public void FixMemories() + { + if (IsEgg) // No memories if is egg. + { + // HT_Language is set for eggs + this.ClearMemoriesOT(); + if (IsUntraded) + { + this.ClearMemoriesHT(); + HandlingTrainerGender = 0; + HandlingTrainerFriendship = 0; + HandlingTrainerTrash.Clear(); + } + return; + } + + if (IsUntraded) + { + // HT_Language is set for gifts -- skip clearing that. + this.ClearMemoriesHT(); + HandlingTrainerGender = 0; + HandlingTrainerFriendship = 0; + HandlingTrainerTrash.Clear(); + } + else + { + var gen = Generation; + if (gen < 6) + this.ClearMemoriesOT(); + } + } + + private bool TradeOT(ITrainerInfo tr) + { + // Check to see if the OT matches the SAV's OT info. + if (!BelongsTo(tr)) + return false; + + CurrentHandler = 0; + return true; + } + + private void TradeHT(ITrainerInfo tr) => PKH.UpdateHandler(this, tr); + + // Maximums + public override ushort MaxMoveID => Legal.MaxMoveID_9a; + public override ushort MaxSpeciesID => Legal.MaxSpeciesID_9a; + public override int MaxAbilityID => Legal.MaxAbilityID_9a; + public override int MaxItemID => Legal.MaxItemID_9a; + public override int MaxBallID => Legal.MaxBallID_9a; + public override GameVersion MaxGameID => Legal.MaxGameID_HOME2; + + public override string GetString(ReadOnlySpan data) + => StringConverter8.GetString(data); + public override int LoadString(ReadOnlySpan data, Span destBuffer) + => StringConverter8.LoadString(data, destBuffer); + public override int SetString(Span destBuffer, ReadOnlySpan value, int maxLength, StringConverterOption option) + => StringConverter8.SetString(destBuffer, value, maxLength, option); + public override int GetStringTerminatorIndex(ReadOnlySpan data) + => TrashBytesUTF16.GetTerminatorIndex(data); + public override int GetStringLength(ReadOnlySpan data) + => TrashBytesUTF16.GetStringLength(data); + public override int GetBytesPerChar() => 2; + + private const int PlusStart0 = 0xD6; // Block C (33 bytes) + private const int PlusStart1 = 0x94; // Block B (12 bytes) + internal const int PlusCount0 = 264; // (33 bytes) + internal const int PlusCount1 = 96; // (12 bytes) + private const int PlusLength0 = PlusCount0 / 8; // 33 bytes, 8 bits + private const int PlusLength1 = PlusCount1 / 8; // 12 bytes, 8 bits + public Span PlusFlags0 => Data.Slice(PlusStart0, PlusLength0); + public Span PlusFlags1 => Data.Slice(PlusStart1, PlusLength1); + + public bool GetMovePlusFlag(int index) + { + if ((uint)index >= PlusCount0) + return GetMovePlusFlag1(index - PlusCount0); + int ofs = index >> 3; + return FlagUtil.GetFlag(Data, PlusStart0 + ofs, index & 7); + } + + private bool GetMovePlusFlag1(int index) + { + if ((uint)index >= PlusCount1) + throw new ArgumentOutOfRangeException(nameof(index)); + int ofs = index >> 3; + return FlagUtil.GetFlag(Data, PlusStart1 + ofs, index & 7); + } + + public void SetMovePlusFlag(int index, bool value = true) + { + if ((uint)index >= PlusCount0) + { + SetMovePlusFlag1(value, index - PlusCount0); + return; + } + int ofs = index >> 3; + FlagUtil.SetFlag(Data, PlusStart0 + ofs, index & 7, value); + } + + private void SetMovePlusFlag1(bool value, int index) + { + if ((uint)index >= PlusCount1) + throw new ArgumentOutOfRangeException(nameof(index)); + int ofs = index >> 3; + FlagUtil.SetFlag(Data, PlusStart1 + ofs, index & 7, value); + } + + public bool GetMovePlusFlagAny() => GetMovePlusFlagAny0() || GetMovePlusFlagAny1(); + public bool GetMovePlusFlagAnyImpossible() => PlusFlags0 is not [.., 0, 0] + || ((PlusFlags0[^3] & ~0x7F) != 0) // 17 bits unused + || GetMovePlusFlagAny1(); // All bits unused + + private bool GetMovePlusFlagAny0() => PlusFlags0.ContainsAnyExcept(0); + private bool GetMovePlusFlagAny1() => PlusFlags1.ContainsAnyExcept(0); + + public void ClearMovePlusFlags() + { + ClearMovePlusFlags0(); + ClearMovePlusFlags1(); + } + + private void ClearMovePlusFlags0() => PlusFlags0.Clear(); + private void ClearMovePlusFlags1() => PlusFlags1.Clear(); + + public override void FixMoves() + { + if (Move1 == 0) { Move1_PP = 35; Move1_PPUps = 0; } + if (Move2 == 0) { Move2_PP = 35; Move2_PPUps = 0; } + if (Move3 == 0) { Move3_PP = 35; Move3_PPUps = 0; } + if (Move4 == 0) { Move4_PP = 35; Move4_PPUps = 0; } + } +} diff --git a/PKHeX.Core/PKM/PK5.cs b/PKHeX.Core/PKM/PK5.cs index c39d9f0b3..093670444 100644 --- a/PKHeX.Core/PKM/PK5.cs +++ b/PKHeX.Core/PKM/PK5.cs @@ -491,7 +491,7 @@ public PK6 ConvertToPK6() // Apply trash bytes for species name of current app language -- default to PKM's language if no match Span nickname = stackalloc char[MaxStringLengthNickname]; int len = LoadString(NicknameTrash, nickname); - int curLang = SpeciesName.GetSpeciesNameLanguage(Species, nickname[..len], 5); + int curLang = SpeciesName.GetSpeciesNameLanguage(Species, nickname[..len], EntityContext.Gen5); if (curLang <= 0) curLang = Language; pk6.Nickname = SpeciesName.GetSpeciesNameGeneration(Species, curLang, 6); diff --git a/PKHeX.Core/PKM/PK7.cs b/PKHeX.Core/PKM/PK7.cs index 1d1930a79..a24cf7305 100644 --- a/PKHeX.Core/PKM/PK7.cs +++ b/PKHeX.Core/PKM/PK7.cs @@ -251,7 +251,7 @@ public override string Nickname { // Detect the language of the species name. // If the species name is the same for Traditional and Simplified Chinese, we prefer the saved language. - int lang = SpeciesName.GetSpeciesNameLanguage(Species, Language, value, 7); + int lang = SpeciesName.GetSpeciesNameLanguage(Species, Language, value, EntityContext.Gen7); if (lang is (int)LanguageID.ChineseS or (int)LanguageID.ChineseT) { StringConverter7.SetString(NicknameTrash, value, 12, lang, StringConverterOption.None, chinese: true); diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index 09c81b898..03c2a5ff7 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -294,12 +294,13 @@ public ushort ShinyXor public virtual bool BDSP => Version is BD or SP; public virtual bool LA => Version is PLA; public virtual bool SV => Version is SL or VL; + public bool ZA => Version is GameVersion.ZA; public bool GO_LGPE => GO && MetLocation == Locations.GO7; public bool GO_HOME => GO && MetLocation == Locations.GO8; public bool VC => VC1 || VC2; public bool GG => LGPE || GO_LGPE; - public bool Gen9 => SV; + public bool Gen9 => SV || ZA; public bool Gen8 => Version.IsGen8() || GO_HOME; public bool Gen7 => Version.IsGen7(); public bool Gen6 => Version.IsGen6(); @@ -632,7 +633,7 @@ public virtual bool IsGenderValid() /// /// Reorders moves and fixes PP if necessary. /// - public void FixMoves() + public virtual void FixMoves() { ReorderMoves(); diff --git a/PKHeX.Core/PKM/Searching/EntityPresenceFilters.cs b/PKHeX.Core/PKM/Searching/EntityPresenceFilters.cs index 173ce14f6..95b20bb53 100644 --- a/PKHeX.Core/PKM/Searching/EntityPresenceFilters.cs +++ b/PKHeX.Core/PKM/Searching/EntityPresenceFilters.cs @@ -19,6 +19,7 @@ public static class EntityPresenceFilters public static Func? GetFilterEntity(EntityContext context) => context switch { // Allow if it already is that format (eager check) + Gen9a => static pk => pk is PA9 || PersonalTable.ZA.IsPresentInGame(pk.Species, pk.Form), Gen9 => static pk => pk is PK9 || PersonalTable.SV.IsPresentInGame(pk.Species, pk.Form), Gen8a => static pk => pk is PA8 || PersonalTable.LA.IsPresentInGame(pk.Species, pk.Form), Gen8b => static pk => pk is PB8 || PersonalTable.BDSP.IsPresentInGame(pk.Species, pk.Form), @@ -33,6 +34,7 @@ public static class EntityPresenceFilters /// Null if no filter is applicable (allow all) public static Func? GetFilterGeneric(EntityContext context) where T : ISpeciesForm => context switch { + Gen9a => IsPresent(PersonalTable.ZA), Gen9 => IsPresent(PersonalTable.SV), Gen8a => IsPresent(PersonalTable.LA), Gen8b => IsPresent(PersonalTable.BDSP), diff --git a/PKHeX.Core/PKM/Shared/GBPKM.cs b/PKHeX.Core/PKM/Shared/GBPKM.cs index 69c26bf17..b9601e173 100644 --- a/PKHeX.Core/PKM/Shared/GBPKM.cs +++ b/PKHeX.Core/PKM/Shared/GBPKM.cs @@ -87,7 +87,7 @@ public sealed override int Language Span nickname = stackalloc char[TrashCharCountNickname]; int len = StringConverter1.LoadString(NicknameTrash, nickname, false); - int lang = SpeciesName.GetSpeciesNameLanguage(Species, nickname[..len], Format); + int lang = SpeciesName.GetSpeciesNameLanguage(Species, nickname[..len], Context); if (lang > 0) return lang; return 0; diff --git a/PKHeX.Core/PKM/Strings/Font/StringFontUtil.cs b/PKHeX.Core/PKM/Strings/Font/StringFontUtil.cs index d17b3c4b0..bd5dcb149 100644 --- a/PKHeX.Core/PKM/Strings/Font/StringFontUtil.cs +++ b/PKHeX.Core/PKM/Strings/Font/StringFontUtil.cs @@ -96,7 +96,8 @@ public static bool HasUndefinedCharacters(ReadOnlySpan str, EntityContext Gen5 or Gen4 => HasChar(c, G5.Defined), Gen6 => HasChar(c, G6.Defined), Gen7 or Gen1 or Gen2 => IsDefined7(c, saveLanguage), - Gen7b or Gen8 or Gen9 => IsDefined8(c, pkLanguage), + Gen7b or Gen8 + or Gen9 or Gen9a=> IsDefined8(c, pkLanguage), Gen8a => IsDefined8a(c, pkLanguage), Gen8b => IsDefined8b(c, pkLanguage, saveLanguage), _ => throw new ArgumentOutOfRangeException(nameof(context), context, null), diff --git a/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs b/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs index 30cbf2510..3bb5021d1 100644 --- a/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs +++ b/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs @@ -25,7 +25,7 @@ public static string[] GetFormList(ushort species, IReadOnlyList types, byte generation = context.Generation(); // Mega List - if (context.IsMegaContext() && IsFormListSingleMega(species)) + if (context.IsMegaContext() && IsFormListSingleMega(species, context)) return GetMegaSingle(types, forms); if (context is Gen7 && FormInfo.HasTotemForm(species)) @@ -38,18 +38,13 @@ public static string[] GetFormList(ushort species, IReadOnlyList types, <= Legal.MaxSpeciesID_3 => GetFormsGen3(species, types, forms, generation), <= Legal.MaxSpeciesID_4 => GetFormsGen4(species, types, forms, generation), <= Legal.MaxSpeciesID_5 => GetFormsGen5(species, types, forms, generation), - <= Legal.MaxSpeciesID_6 => GetFormsGen6(species, types, forms, genders, generation), + <= Legal.MaxSpeciesID_6 => GetFormsGen6(species, types, forms, genders, generation, context), <= Legal.MaxSpeciesID_7_USUM => GetFormsGen7(species, types, forms, generation), <= Legal.MaxSpeciesID_8a => GetFormsGen8(species, generation, types, forms, genders), _ => GetFormsGen9(species, generation, types, forms, genders), }; } - /// - /// Determines whether Mega Pokémon forms exist in the specified . - /// - private static bool IsMegaContext(this EntityContext context) => context is Gen6 or Gen7 or Gen7b; - /// /// Used to indicate that the form list is a single form, so no name is specified. /// @@ -225,19 +220,11 @@ private static string[] GetFormsGen5(ushort species, IReadOnlyList types }; } - private static string[] GetFormsGen6(ushort species, IReadOnlyList types, IReadOnlyList forms, IReadOnlyList genders, byte generation) + private static string[] GetFormsGen6(ushort species, IReadOnlyList types, IReadOnlyList forms, IReadOnlyList genders, byte generation, EntityContext context) { return (Species)species switch { - Greninja when generation < 9 => [ - types[0], // Normal - forms[962], // Ash - forms[1012], // "Bonded" - Active - ], - Greninja => [ - types[0], // Normal - forms[962], // Ash - ], + Greninja => GetFormsGreninja(types, forms, new string[!context.IsMegaContext() ? 2 : context.Generation() >= 9 ? 4 : 3]), Scatterbug or Spewpa or Vivillon => [ forms[(int)Vivillon], // Icy Snow forms[963], // Polar @@ -260,21 +247,14 @@ private static string[] GetFormsGen6(ushort species, IReadOnlyList types forms[980], // Fancy forms[981], // Poké Ball ], - Floette when generation < 9 => [ - forms[(int)Floette], // Red - forms[986], // Yellow - forms[987], // Orange - forms[988], // Blue - forms[989], // White - forms[990], // Eternal - ], - Flabébé or Floette or Florges => [ + Flabébé or Florges => [ forms[(int)Flabébé], // Red forms[986], // Yellow forms[987], // Orange forms[988], // Blue forms[989], // White ], + Floette => GetFormsFloette(forms, new string[!context.IsMegaContext() ? 5 : context.Generation() >= 9 ? 7 : 6]), Furfrou => [ forms[(int)Furfrou], // Natural forms[995], // Heart @@ -295,7 +275,13 @@ private static string[] GetFormsGen6(ushort species, IReadOnlyList types forms[(int)Aegislash], // Shield forms[1005], // Blade ], - Sliggoo or Goodra or Avalugg when generation >= 8 => GetFormsHisui(species, generation, types, forms), + Sliggoo or Goodra or Avalugg when context.Generation() >= 8 => GetFormsHisui(species, context.Generation(), types, forms), + Pumpkaboo or Gourgeist when generation >= 9 => [ + forms[MediumVariety], + forms[1006], // Small + forms[1007], // Large + forms[JumboVariety], + ], Pumpkaboo or Gourgeist => [ forms[(int)Pumpkaboo], // Average forms[1006], // Small @@ -306,17 +292,11 @@ private static string[] GetFormsGen6(ushort species, IReadOnlyList types forms[(int)Xerneas], // Neutral forms[1012], // Active ], + Zygarde => GetFormsZygarde(forms, new string[context.IsMegaContext() && context.Generation() >= 9 ? 6 : 5]), Hoopa => [ forms[(int)Hoopa], // Confined forms[1018], // Unbound ], - Zygarde => [ - forms[(int)Zygarde], // 50% (Aura Break) - forms[1013], // 10% (Aura Break) - forms[1014] + "-C", // 10% Cell (Power Construct) - forms[1015] + "-C", // 50% Cell (Power Construct) - forms[1016], // 100% Cell (Power Construct) - ], _ => EMPTY, }; } @@ -398,10 +378,6 @@ private static string[] GetFormsGen8(ushort species, byte generation, IReadOnlyL forms[(int)Toxtricity], // Amped forms[LowKey], ], - Indeedee or Basculegion => [ - genders[000], // Male - genders[001], // Female - ], Sinistea or Polteageist => [ forms[Phony], forms[Antique], @@ -417,14 +393,18 @@ private static string[] GetFormsGen8(ushort species, byte generation, IReadOnlyL forms[CaramelSwirl], forms[RainbowSwirl], ], - Morpeko => [ - forms[FullBellyMode], - forms[HangryMode], - ], Eiscue => [ forms[IceFace], forms[NoiceFace], ], + Indeedee or Basculegion => [ + genders[000], // Male + genders[001], // Female + ], + Morpeko => [ + forms[FullBellyMode], + forms[HangryMode], + ], Zacian or Zamazenta => [ forms[HeroOfManyBattles], forms[Crowned], @@ -443,8 +423,8 @@ private static string[] GetFormsGen8(ushort species, byte generation, IReadOnlyL ], Calyrex => [ types[0], // Normal - forms[CalyIce], - forms[CalyGhost], + forms[IceRider], + forms[ShadowRider], ], Kleavor when generation == 8 => [ types[0], @@ -470,29 +450,29 @@ private static string[] GetFormsGen9(ushort species, byte generation, IReadOnlyL genders[000], // Male genders[001], // Female ], - Dudunsparce => [ - forms[TwoSegment], - forms[ThreeSegment], - ], - Palafin => [ - forms[Zero], - forms[HeroPalafin], - ], Maushold => [ forms[FamilyOfThree], forms[FamilyOfFour], ], - Tatsugiri => [ - forms[Curly], - forms[Droopy], - forms[Stretchy], - ], Squawkabilly => [ forms[Green], forms[988], // Blue forms[986], // Yellow forms[989], // White ], + Palafin => [ + forms[Zero], + forms[HeroPalafin], + ], + Tatsugiri => [ + forms[Curly], + forms[Droopy], + forms[Stretchy], + ], + Dudunsparce => [ + forms[TwoSegment], + forms[ThreeSegment], + ], Gimmighoul => [ forms[Chest], forms[Roaming], @@ -511,6 +491,14 @@ private static string[] GetFormsGen9(ushort species, byte generation, IReadOnlyL forms[Aquatic], forms[Glide], ], + Poltchageist => [ + forms[Counterfeit], + forms[Artisan], + ], + Sinistcha => [ + forms[Unremarkable], + forms[Masterpiece], + ], Ogerpon => [ forms[MaskTeal], forms[MaskWellspring], @@ -521,14 +509,6 @@ private static string[] GetFormsGen9(ushort species, byte generation, IReadOnlyL $"*{forms[MaskHearthflame]}", $"*{forms[MaskCornerstone]}", ], - Poltchageist => [ - forms[Counterfeit], - forms[Artisan], - ], - Sinistcha => [ - forms[Unremarkable], - forms[Masterpiece], - ], Terapagos => [ types[0], // Normal forms[Terastal], @@ -763,16 +743,37 @@ private static string[] GetFormsArceus(ushort species, byte generation, IReadOnl "!", "?", ], }; + private static bool IsFormListSingleMega(ushort species, EntityContext context) + { + if (context.Generation() >= 9 && species is (int)Slowbro) // Kanto, Mega, Galar + return false; + if (IsFormListSingleMega6(species)) + return true; + if (context.Generation() >= 9 && IsFormListSingleMega9(species)) + return true; + return false; + } - private static bool IsFormListSingleMega(ushort species) => species is + private static bool IsFormListSingleMega6(ushort species) => (Species)species is // XY - 003 or 009 or 065 or 094 or 115 or 127 or 130 or 142 or 181 or 212 or - 214 or 229 or 248 or 257 or 282 or 303 or 306 or 308 or 310 or 354 or - 359 or 380 or 381 or 445 or 448 or 460 or + Venusaur or Blastoise or Alakazam or Gengar or Kangaskhan or Pinsir or Gyarados or Aerodactyl or Ampharos or Scizor or + Heracross or Houndoom or Tyranitar or Blaziken or Gardevoir or Mawile or Aggron or Medicham or Manectric or Banette or + Absol or Latias or Latios or Garchomp or Lucario or Abomasnow or // AO - 015 or 018 or 080 or 208 or 254 or 260 or 302 or 319 or 323 or 334 or - 362 or 373 or 376 or 384 or 428 or 475 or 531 or 719 + Beedrill or Pidgeot or Slowbro or Steelix or Sceptile or Swampert or Sableye or Sharpedo or Camerupt or Altaria or + Glalie or Salamence or Metagross or Rayquaza or Lopunny or Gallade or Audino or Diancie + ; + + private static bool IsFormListSingleMega9(ushort species) => (Species)species is + // ZA + Clefable or Victreebel or Starmie or Dragonite or + Meganium or Feraligatr or Skarmory or + Froslass or + Emboar or Excadrill or Scolipede or Scrafty or Eelektross or Chandelure or + Chesnaught or Delphox or Pyroar or Malamar or Barbaracle or Dragalge or Hawlucha or + Drampa or + Falinks ; private static string[] GetMegaSingle(IReadOnlyList types, IReadOnlyList forms) @@ -857,6 +858,43 @@ private static string[] GetFormsGalarSlowbro(IReadOnlyList types, IReadO ]; } + private static string[] GetFormsGreninja(IReadOnlyList types, IReadOnlyList forms, string[] result) + { + result[0] = types[0]; // Normal + result[1] = forms[962]; // Battle Bond + if (result.Length > 2) + result[2] = forms[1012]; // Ash-Greninja + if (result.Length > 3) + result[3] = forms[Mega]; // Mega Greninja + return result; + } + + private static string[] GetFormsFloette(IReadOnlyList forms, string[] result) + { + result[0] = forms[(int)Floette]; // Red + result[1] = forms[986]; // Yellow + result[2] = forms[987]; // Orange + result[3] = forms[988]; // Blue + result[4] = forms[989]; // White + if (result.Length > 5) + result[5] = forms[990]; // Eternal + if (result.Length > 6) + result[6] = forms[Mega]; + return result; + } + + private static string[] GetFormsZygarde(IReadOnlyList forms, string[] result) + { + result[0] = forms[(int)Zygarde]; // 50% Forme (Aura Break) + result[1] = forms[1013]; // 10% Forme (Aura Break) + result[2] = forms[1014] + "-C"; // 10% Forme (Power Construct) + result[3] = forms[1015] + "-C"; // 50% Forme (Power Construct) + result[4] = forms[1016]; // Complete Forme + if (result.Length > 5) + result[5] = forms[Mega]; + return result; + } + private const int Mega = 804; private const int MegaX = 805; private const int MegaY = 806; @@ -892,8 +930,8 @@ private static string[] GetFormsGalarSlowbro(IReadOnlyList types, IReadO private const int SingleStrike = 1086; private const int RapidStrike = 1087; private const int Dada = 1088; - private const int CalyIce = 1089; // Ice - private const int CalyGhost = 1090; // Shadow + private const int IceRider = 1089; + private const int ShadowRider = 1090; private const int Hisuian = 1094; private const int Lord = 1095; @@ -937,6 +975,8 @@ private static string[] GetFormsGalarSlowbro(IReadOnlyList types, IReadO private const int Masterpiece = 1134; private const int Terastal = 1135; private const int Stellar = 1136; + private const int MediumVariety = 1137; + private const int JumboVariety = 1138; public static string GetGigantamaxName(IReadOnlyList forms) => forms[Gigantamax]; diff --git a/PKHeX.Core/PKM/Util/Conversion/IEntityRejuvenator.cs b/PKHeX.Core/PKM/Util/Conversion/IEntityRejuvenator.cs index 81a48b048..ca7803f61 100644 --- a/PKHeX.Core/PKM/Util/Conversion/IEntityRejuvenator.cs +++ b/PKHeX.Core/PKM/Util/Conversion/IEntityRejuvenator.cs @@ -65,6 +65,11 @@ private static void ResetSideways(PKM pk) // Try to restore original Tera type / override instead of HOME's double override to current Type1. TeraTypeUtil.ResetTeraType(pk9, la.EncounterMatch); } + else if (pk is PA9 { ZA: true }) + { + var la = new LegalityAnalysis(pk); + ResetRelearn(pk, la); + } else if (pk is PK8 pk8 && !LocationsHOME.IsLocationSWSH(pk8.MetLocation)) { // Gen8 and below (Gen6/7) need their original relearn moves diff --git a/PKHeX.Core/PKM/Util/Conversion/ItemConverter.cs b/PKHeX.Core/PKM/Util/Conversion/ItemConverter.cs index a369b0ec6..fdbc03812 100644 --- a/PKHeX.Core/PKM/Util/Conversion/ItemConverter.cs +++ b/PKHeX.Core/PKM/Util/Conversion/ItemConverter.cs @@ -22,14 +22,14 @@ public static class ItemConverter /// /// Generation 3 Item ID. /// Generation 4+ Item ID. - public static ushort GetItemFuture3(ushort item) => item > Item3to4.Length ? NaN : Item3to4[item]; + public static ushort GetItemFuture3(ushort item) => item >= Item3to4.Length ? NaN : Item3to4[item]; /// /// Converts a Generation 2 Item ID to Generation 4+ Item ID. /// /// Generation 2 Item ID. /// Generation 4+ Item ID. - public static ushort GetItemFuture2(byte item) => item > Item2to4.Length ? NaN : Item2to4[item]; + public static ushort GetItemFuture2(byte item) => item >= Item2to4.Length ? NaN : Item2to4[item]; /// /// Converts a Generation 4+ Item ID to Generation 3 Item ID. @@ -230,4 +230,33 @@ public static int GetItemForFormat(int srcItem, EntityContext srcFormat, EntityC 0x18, 0x9C, 0xC5, 0xF1, 0xFB, 0x77, 0xF0, 0xBF, 0xF7, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x07, 0x00, ]; + + /// + /// Gets the TM index from the old sequential TM index. + /// + /// old TM index + /// New TM index + public static ushort GetTechnicalMachineIndex9a(ushort oldTM) + { + var arr = RemapTechnicalMachineItemName9a; + if ((uint)oldTM >= arr.Length) + return oldTM; + return (ushort)(oldTM + RemapTechnicalMachineItemName9a[oldTM]); + } + + // Old (sequential) index to Legends: Z-A "scrambled" order that is displayed to the user. + public static ReadOnlySpan RemapTechnicalMachineItemName9a => + [ + 0, 0, 0, 0, +02, 0, +01, +22, +03, 0, + +13, +35, +30, +11, +91, +29, 0, 0, +29, +40, + +31, -02, +42, +70, +43, +81, +43, -02, 0, +34, + +44, -21, 0, -02, -14, -02, +17, +11, 0, -03, + -18, +57, -03, -03, -31, +13, -03, +28, -03, +55, + 0, +22, +50, -27, -05, +52, -04, +22, -04, -25, + -04, -04, 0, -22, -04, -04, +12, +29, -13, +12, + -43, -06, -06, -65, -06, -45, -06, -06, -06, +22, + -68, +06, -68, -07, -07, -64, -71, -07, +15, -07, + -07, -07, -07, -07, -90, -07, -07, -07, -80, -07, + -63, 0, -08, -08, -13, -08, -71, -08, -08, + ]; } diff --git a/PKHeX.Core/PKM/Util/EntityBlank.cs b/PKHeX.Core/PKM/Util/EntityBlank.cs index d601cc504..3c11485c0 100644 --- a/PKHeX.Core/PKM/Util/EntityBlank.cs +++ b/PKHeX.Core/PKM/Util/EntityBlank.cs @@ -84,6 +84,8 @@ public static PKM GetIdealBlank(ushort species, byte form) return new PK7(); if (PersonalTable.SV.IsPresentInGame(species, form)) return new PK9(); + if (PersonalTable.ZA.IsPresentInGame(species, form)) + return new PA9(); return new PB7(); } } diff --git a/PKHeX.Core/PKM/Util/EntityContext.cs b/PKHeX.Core/PKM/Util/EntityContext.cs index 11b8a2c55..b492d1b7e 100644 --- a/PKHeX.Core/PKM/Util/EntityContext.cs +++ b/PKHeX.Core/PKM/Util/EntityContext.cs @@ -35,6 +35,8 @@ public enum EntityContext : byte Gen8a, /// Brilliant Diamond & Shining Pearl Gen8b, + /// Legends: Z-A + Gen9a, /// /// Internal separator to bounds check count. @@ -52,6 +54,7 @@ public static class EntityContextExtensions Gen7b => (byte)7, Gen8a => (byte)8, Gen8b => (byte)8, + Gen9a => (byte)9, _ => throw new ArgumentOutOfRangeException(nameof(value), value, null), }; @@ -80,6 +83,7 @@ public static class EntityContextExtensions Gen7b => GameVersion.GP, Gen8a => GameVersion.PLA, Gen8b => GameVersion.BD, + Gen9a => GameVersion.ZA, _ => throw new ArgumentOutOfRangeException(nameof(value), value, null), }; @@ -93,7 +97,7 @@ public static class EntityContextExtensions Gen3 => GameConsole.GBA, Gen4 or Gen5 => GameConsole.NDS, Gen6 or Gen7 => GameConsole._3DS, - Gen7b or Gen8 or Gen8a or Gen8b or Gen9 => GameConsole.NX, + Gen7b or Gen8 or Gen8a or Gen8b or Gen9 or Gen9a => GameConsole.NX, _ => throw new ArgumentOutOfRangeException(nameof(value), value, null), }; @@ -106,6 +110,12 @@ public static class EntityContextExtensions GameVersion.GP or GameVersion.GE or GameVersion.GO or GameVersion.GG or GameVersion.Gen7b => Gen7b, GameVersion.PLA => Gen8a, GameVersion.BD or GameVersion.SP => Gen8b, + GameVersion.ZA => Gen9a, _ => (EntityContext)version.GetGeneration(), }; + + /// + /// Determines whether Mega Pokémon forms exist in the specified . + /// + public static bool IsMegaContext(this EntityContext context) => context is Gen6 or Gen7 or Gen7b or Gen9a; } diff --git a/PKHeX.Core/PKM/Util/EntityFileExtension.cs b/PKHeX.Core/PKM/Util/EntityFileExtension.cs index 741f18eff..8efe39bfb 100644 --- a/PKHeX.Core/PKM/Util/EntityFileExtension.cs +++ b/PKHeX.Core/PKM/Util/EntityFileExtension.cs @@ -17,6 +17,7 @@ public static class EntityFileExtension private const string ExtensionPB7 = "pb7"; private const string ExtensionPB8 = "pb8"; private const string ExtensionPA8 = "pa8"; + private const string ExtensionPA9 = "pa9"; private const int CountExtra = 8; /// @@ -55,6 +56,8 @@ public static string[] GetExtensions(byte maxGeneration = Latest.Generation) result.Add(ExtensionPB8); // Brilliant Diamond & Shining Pearl if (maxGeneration >= 8) result.Add(ExtensionPA8); // Legends: Arceus + if (maxGeneration >= 9) + result.Add(ExtensionPA9); // Legends: Z-A return [.. result]; } @@ -71,6 +74,7 @@ public static EntityContext GetContextFromExtension(ReadOnlySpan ext, Enti return prefer; static bool Is(ReadOnlySpan ext, ReadOnlySpan str) => ext.EndsWith(str, StringComparison.InvariantCultureIgnoreCase); + if (Is(ext, "a9")) return EntityContext.Gen9a; if (Is(ext, "a8")) return EntityContext.Gen8a; if (Is(ext, "b8")) return EntityContext.Gen8b; if (Is(ext, "k8")) return EntityContext.Gen8; diff --git a/PKHeX.Core/PKM/Util/EntityFormat.cs b/PKHeX.Core/PKM/Util/EntityFormat.cs index 5a3a34d26..46cc10853 100644 --- a/PKHeX.Core/PKM/Util/EntityFormat.cs +++ b/PKHeX.Core/PKM/Util/EntityFormat.cs @@ -92,7 +92,7 @@ private static EntityFormatDetected GetFormat89(ReadOnlySpan data) { var pk = new PK8(data.ToArray()); if (IsFormatReally9(pk)) - return FormatPK9; + return pk.Data[0xCE] == (byte)GameVersion.ZA ? FormatPA9 : FormatPK9; return IsFormatReally8b(pk); } @@ -139,6 +139,7 @@ private static bool IsFormatReally9(PK8 pk) Format6or7 => prefer == EntityContext.Gen6 ? new PK6(data) : new PK7(data), Format8or8b => prefer == EntityContext.Gen8b ? new PB8(data) : new PK8(data), FormatPK9 => new PK9(data), + FormatPA9 => new PA9(data), _ => null, }; @@ -227,7 +228,7 @@ public enum EntityFormatDetected FormatPK4, FormatBK4, FormatRK4, FormatPK5, FormatPK6, FormatPK7, FormatPB7, FormatPK8, FormatPA8, FormatPB8, - FormatPK9, + FormatPK9, FormatPA9, Format6or7, Format8or8b, diff --git a/PKHeX.Core/PKM/Util/Language.cs b/PKHeX.Core/PKM/Util/Language.cs index 7feb54bd9..958f431b2 100644 --- a/PKHeX.Core/PKM/Util/Language.cs +++ b/PKHeX.Core/PKM/Util/Language.cs @@ -22,48 +22,46 @@ public static class Language (byte)ChineseS, (byte)ChineseT, + + (byte)SpanishL, // ZA: LATAM ]; // check Korean for the VC case, never possible to match string outside of this case private static ReadOnlySpan Languages_GB => Languages[..7]; // [..KOR] private static ReadOnlySpan Languages_3 => Languages[..6]; // [..KOR) + private static ReadOnlySpan Languages_9 => Languages[..9]; // [..CHT] private const LanguageID SafeLanguage = English; /// /// Returns the available languages for the given generation. /// - /// Generation to check. + /// Generation to check. /// Available languages for the given generation. - public static ReadOnlySpan GetAvailableGameLanguages(byte generation = Latest.Generation) => generation switch + public static ReadOnlySpan GetAvailableGameLanguages(EntityContext context = Latest.Context) => context.Generation() switch { 1 => Languages_3, // No KOR 2 => Languages_GB, 3 => Languages_3, // No KOR 4 or 5 or 6 => Languages_GB, + 7 or 8 => Languages_9, + 9 when context is EntityContext.Gen9 => Languages_9, _ => Languages, }; - private static bool HasLanguage(ReadOnlySpan permitted, byte language) => permitted.Contains(language); + private static bool HasLanguage(ReadOnlySpan permitted, LanguageID language) => permitted.Contains((byte)language); - /// - public static LanguageID GetSafeLanguage(byte generation, LanguageID prefer) => GetSafeLanguage(generation, prefer, GameVersion.Any); - - /// - /// Returns the language that is safe to use for the given generation. - /// - /// Generation to check. - /// Preferred language. - /// Game version to check. - /// Language that is safe to use for the given generation. - public static LanguageID GetSafeLanguage(byte generation, LanguageID prefer, GameVersion version) => generation switch + public static LanguageID GetSafeLanguage1(LanguageID prefer, GameVersion version) { - 1 when version == GameVersion.BU => Japanese, - 1 => HasLanguage(Languages_3, (byte)prefer) ? prefer : SafeLanguage, - 2 => HasLanguage(Languages_GB, (byte)prefer) ? prefer : SafeLanguage, - 3 => HasLanguage(Languages_3 , (byte)prefer) ? prefer : SafeLanguage, - 4 or 5 or 6 => HasLanguage(Languages_GB, (byte)prefer) ? prefer : SafeLanguage, - _ => HasLanguage(Languages, (byte)prefer) ? prefer : SafeLanguage, - }; + if (version is GameVersion.BU) + return Japanese; + return HasLanguage(Languages_3, prefer) ? prefer : SafeLanguage; + } + + public static LanguageID GetSafeLanguage2(LanguageID prefer) => HasLanguage(Languages_GB, prefer) ? prefer : SafeLanguage; + public static LanguageID GetSafeLanguage3(LanguageID prefer) => HasLanguage(Languages_3, prefer) ? prefer : SafeLanguage; + public static LanguageID GetSafeLanguage456(LanguageID prefer) => HasLanguage(Languages_GB, prefer) ? prefer : SafeLanguage; + public static LanguageID GetSafeLanguage789(LanguageID prefer) => HasLanguage(Languages_9, prefer) ? prefer : SafeLanguage; + public static LanguageID GetSafeLanguage9a(LanguageID prefer) => HasLanguage(Languages, prefer) ? prefer : SafeLanguage; /// /// Gets the language code for the given . @@ -73,6 +71,7 @@ public static class Language public static string GetLanguageCode(this LanguageID language) => language switch { Japanese => "ja", + English => "en", French => "fr", Italian => "it", German => "de", @@ -80,7 +79,7 @@ public static class Language Korean => "ko", ChineseS => "zh-Hans", ChineseT => "zh-Hant", - English => "en", + SpanishL => "es-419", _ => GameLanguage.DefaultLanguage, }; @@ -92,6 +91,7 @@ public static class Language public static LanguageID GetLanguageValue(string language) => language switch { "ja" => Japanese, + "en" => English, "fr" => French, "it" => Italian, "de" => German, @@ -99,7 +99,7 @@ public static class Language "ko" => Korean, "zh-Hans" => ChineseS, "zh-Hant" => ChineseT, - "en" => English, + "es-419" => SpanishL, _ => GetLanguageValue(GameLanguage.DefaultLanguage), }; diff --git a/PKHeX.Core/PKM/Util/Latest.cs b/PKHeX.Core/PKM/Util/Latest.cs index fe7d292fb..a344e54d3 100644 --- a/PKHeX.Core/PKM/Util/Latest.cs +++ b/PKHeX.Core/PKM/Util/Latest.cs @@ -5,7 +5,7 @@ namespace PKHeX.Core; /// public static class Latest { - public const EntityContext Context = EntityContext.Gen9; - public const GameVersion Version = GameVersion.SL; + public const EntityContext Context = EntityContext.Gen9a; + public const GameVersion Version = GameVersion.ZA; public const byte Generation = 9; } diff --git a/PKHeX.Core/PKM/Util/SpeciesName.cs b/PKHeX.Core/PKM/Util/SpeciesName.cs index d79c2b01c..154c62987 100644 --- a/PKHeX.Core/PKM/Util/SpeciesName.cs +++ b/PKHeX.Core/PKM/Util/SpeciesName.cs @@ -24,6 +24,7 @@ public static class SpeciesName Util.GetSpeciesList("ko"), // 8 Util.GetSpeciesList("zh-Hans"), // 9 Simplified Util.GetSpeciesList("zh-Hant"), // 10 Traditional + Util.GetSpeciesList("es-419"), // 11 Spanish ]; /// @@ -42,6 +43,7 @@ public static class SpeciesName (int)LanguageID.Korean => "알", (int)LanguageID.ChineseS => "蛋", (int)LanguageID.ChineseT => "蛋", + (int)LanguageID.SpanishL => "Huevo", _ => string.Empty, }; @@ -242,11 +244,12 @@ private static string GetEggName1234(ushort species, int language, byte generati /// /// National Dex number of the Pokémon. Should be 0 if an egg. /// Current name - /// Generation specific formatting option + /// Generation specific formatting option /// True if it does not match any language name, False if not nicknamed - public static bool IsNicknamedAnyLanguage(ushort species, ReadOnlySpan nickname, byte generation = Latest.Generation) + public static bool IsNicknamedAnyLanguage(ushort species, ReadOnlySpan nickname, EntityContext context = Latest.Context) { - var langs = Language.GetAvailableGameLanguages(generation); + var langs = Language.GetAvailableGameLanguages(context); + var generation = context.Generation(); foreach (var language in langs) { if (!IsNicknamed(species, nickname, language, generation)) @@ -275,11 +278,12 @@ public static bool IsNicknamed(ushort species, ReadOnlySpan nickname, int /// National Dex number of the Pokémon. Should be 0 if an egg. /// Language ID with a higher priority /// Current name - /// Generation specific formatting option + /// Generation specific formatting option /// Language ID if it does not match any language name, -1 if no matches - public static int GetSpeciesNameLanguage(ushort species, int priorityLanguage, ReadOnlySpan nickname, byte generation = Latest.Generation) + public static int GetSpeciesNameLanguage(ushort species, int priorityLanguage, ReadOnlySpan nickname, EntityContext context = Latest.Context) { - var langs = Language.GetAvailableGameLanguages(generation); + var langs = Language.GetAvailableGameLanguages(context); + var generation = context.Generation(); var priorityIndex = langs.IndexOf((byte)priorityLanguage); if (priorityIndex != -1) { @@ -296,11 +300,12 @@ public static int GetSpeciesNameLanguage(ushort species, int priorityLanguage, R /// /// National Dex number of the Pokémon. Should be 0 if an egg. /// Current name - /// Generation specific formatting option + /// Generation specific formatting option /// Language ID if it does not match any language name, -1 if no matches - public static int GetSpeciesNameLanguage(ushort species, ReadOnlySpan nickname, byte generation = Latest.Generation) + public static int GetSpeciesNameLanguage(ushort species, ReadOnlySpan nickname, EntityContext context = Latest.Context) { - var langs = Language.GetAvailableGameLanguages(generation); + var langs = Language.GetAvailableGameLanguages(context); + var generation = context.Generation(); return GetSpeciesNameLanguage(species, nickname, generation, langs); } @@ -327,9 +332,9 @@ public static bool TryGetSpecies(ReadOnlySpan speciesName, int language, o return SpeciesDict[language].TryGetValue(speciesName, out species); } - public static bool TryGetSpeciesAnyLanguage(ReadOnlySpan speciesName, out ushort species, byte generation = Latest.Generation) + public static bool TryGetSpeciesAnyLanguage(ReadOnlySpan speciesName, out ushort species, EntityContext context = Latest.Context) { - foreach (var language in Language.GetAvailableGameLanguages(generation)) + foreach (var language in Language.GetAvailableGameLanguages(context)) { if (SpeciesDict[language].TryGetValue(speciesName, out species)) return true; @@ -338,12 +343,12 @@ public static bool TryGetSpeciesAnyLanguage(ReadOnlySpan speciesName, out return false; } - public static bool TryGetSpeciesAnyLanguageCaseInsensitive(ReadOnlySpan speciesName, out ushort species, byte generation = Latest.Generation) + public static bool TryGetSpeciesAnyLanguageCaseInsensitive(ReadOnlySpan speciesName, out ushort species, EntityContext context = Latest.Context) { Span lowercase = stackalloc char[speciesName.Length]; speciesName.ToLowerInvariant(lowercase); - foreach (var language in Language.GetAvailableGameLanguages(generation)) + foreach (var language in Language.GetAvailableGameLanguages(context)) { if (SpeciesDictLower[language].TryGetValue(lowercase, out species)) return true; diff --git a/PKHeX.Core/PersonalInfo/Info/PersonalInfo9ZA.cs b/PKHeX.Core/PersonalInfo/Info/PersonalInfo9ZA.cs new file mode 100644 index 000000000..02536ce35 --- /dev/null +++ b/PKHeX.Core/PersonalInfo/Info/PersonalInfo9ZA.cs @@ -0,0 +1,174 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +/// +/// class with values from the games. +/// +public sealed class PersonalInfo9ZA(Memory Raw) : PersonalInfo, IPersonalAbility12H, IPersonalInfoTM, IPermitPlus +{ + public const int SIZE = 0x50; + + private Span Data => Raw.Span; + public override byte[] Write() => Raw.ToArray(); + + public override int HP { get => Data[0x00]; set => Data[0x00] = (byte)value; } + public override int ATK { get => Data[0x01]; set => Data[0x01] = (byte)value; } + public override int DEF { get => Data[0x02]; set => Data[0x02] = (byte)value; } + public override int SPE { get => Data[0x03]; set => Data[0x03] = (byte)value; } + public override int SPA { get => Data[0x04]; set => Data[0x04] = (byte)value; } + public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; } + public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; } + public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; } + public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; } + public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; } + private int EVYield { get => ReadUInt16LittleEndian(Data[0x0A..]); set => WriteUInt16LittleEndian(Data[0x0A..], (ushort)value); } + public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); } + public override int EV_ATK { get => (EVYield >> 2) & 0x3; set => EVYield = (EVYield & ~(0x3 << 2)) | ((value & 0x3) << 2); } + public override int EV_DEF { get => (EVYield >> 4) & 0x3; set => EVYield = (EVYield & ~(0x3 << 4)) | ((value & 0x3) << 4); } + public override int EV_SPE { get => (EVYield >> 6) & 0x3; set => EVYield = (EVYield & ~(0x3 << 6)) | ((value & 0x3) << 6); } + public override int EV_SPA { get => (EVYield >> 8) & 0x3; set => EVYield = (EVYield & ~(0x3 << 8)) | ((value & 0x3) << 8); } + public override int EV_SPD { get => (EVYield >> 10) & 0x3; set => EVYield = (EVYield & ~(0x3 << 10)) | ((value & 0x3) << 10); } + public override byte Gender { get => Data[0x0C]; set => Data[0x0C] = value; } + public override byte HatchCycles { get => Data[0x0D]; set => Data[0x0D] = value; } + public override byte BaseFriendship { get => Data[0x0E]; set => Data[0x0E] = value; } + public override byte EXPGrowth { get => Data[0x0F]; set => Data[0x0F] = value; } + public override int EggGroup1 { get => Data[0x10]; set => Data[0x10] = (byte)value; } + public override int EggGroup2 { get => Data[0x11]; set => Data[0x11] = (byte)value; } + public int Ability1 { get => ReadUInt16LittleEndian(Data[0x12..]); set => WriteUInt16LittleEndian(Data[0x12..], (ushort)value); } + public int Ability2 { get => ReadUInt16LittleEndian(Data[0x14..]); set => WriteUInt16LittleEndian(Data[0x14..], (ushort)value); } + public int AbilityH { get => ReadUInt16LittleEndian(Data[0x16..]); set => WriteUInt16LittleEndian(Data[0x16..], (ushort)value); } + public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data[0x18..]); set => WriteUInt16LittleEndian(Data[0x18..], (ushort)value); } + public override byte FormCount { get => Data[0x1A]; set => Data[0x1A] = value; } + public override int Color { get => Data[0x1B]; set => Data[0x1B] = (byte)value; } + public bool IsPresentInGame { get => Data[0x1C] != 0; set => Data[0x1C] = value ? (byte)1 : (byte)0; } + // 0x1D unused + public ushort DexIndex { get => ReadUInt16LittleEndian(Data[0x1E..]); set => WriteUInt16LittleEndian(Data[0x1E..], value); } + public override int Height { get => ReadUInt16LittleEndian(Data[0x20..]); set => WriteUInt16LittleEndian(Data[0x20..], (ushort)value); } + public override int Weight { get => ReadUInt16LittleEndian(Data[0x22..]); set => WriteUInt16LittleEndian(Data[0x22..], (ushort)value); } + public ushort HatchSpecies { get => ReadUInt16LittleEndian(Data[0x24..]); set => WriteUInt16LittleEndian(Data[0x24..], value); } // ZA: no eggs, but we'll retain it + public byte LocalFormIndex { get => (byte)ReadUInt16LittleEndian(Data[0x26..]); set => WriteUInt16LittleEndian(Data[0x26..], value); } // local region base form + public ushort RegionalFlags { get => ReadUInt16LittleEndian(Data[0x28..]); set => WriteUInt16LittleEndian(Data[0x28..], value); } + public bool IsRegionalForm { get => (RegionalFlags & 1) == 1; set => RegionalFlags = (ushort)((RegionalFlags & 0xFFFE) | (value ? 1 : 0)); } + public ushort RegionalFormIndex { get => (byte)ReadUInt16LittleEndian(Data[0x2A..]); set => WriteUInt16LittleEndian(Data[0x2A..], value); } + + public override int EscapeRate { get => 0; set { } } + + /// + /// Gets the Form that any offspring will hatch with, assuming it is holding an Everstone. + /// + public byte HatchFormIndexEverstone => IsRegionalForm ? (byte)RegionalFormIndex : LocalFormIndex; + + /// + /// Checks if the entry shows up in any of the built-in Pokédex. + /// + public bool IsInDex => DexIndex != 0; + + public override int AbilityCount => 3; + public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1; + public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch + { + 0 => Ability1, + 1 => Ability2, + 2 => AbilityH, + _ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null), + }; + + private const int TM = 0x2C; + private const int CountTM = 230; + private const int ByteCountTM = (CountTM + 7) / 8; + + public bool GetIsLearnTM(int index) + { + if ((uint)index >= CountTM) + return false; + return (Data[TM + (index >> 3)] & (1 << (index & 7))) != 0; + } + + public void SetIsLearnTM(int index, bool value) + { + if ((uint)index >= CountTM) + return; + if (value) + Data[TM + (index >> 3)] |= (byte)(1 << (index & 7)); + else + Data[TM + (index >> 3)] &= (byte)~(1 << (index & 7)); + } + + public void SetAllLearnTM(Span result) + { + var moves = MachineMoves; + var span = Data.Slice(TM, ByteCountTM); + for (int index = CountTM - 1; index >= 0; index--) + { + if ((span[index >> 3] & (1 << (index & 7))) != 0) + result[moves[index]] = true; + } + } + + public bool IsRecordPermitted(int index) => false; // Game never sets these flags, as TMs are infinite use. + + private const int COUNT_RECORD_BASE = 200; // Up to 200 TM flags, but not all are used. + private const int COUNT_RECORD_DLC = 104; // 13 additional bytes allocated for DLC1/2 TM Flags + public ReadOnlySpan RecordPermitIndexes => MachineMoves; + public int RecordCountTotal => COUNT_RECORD_BASE + COUNT_RECORD_DLC; + public int RecordCountUsed => CountTM; + + /// + /// Technical Machine moves corresponding to their index within TM bitflag permissions. + /// + public static ReadOnlySpan MachineMoves => + [ + 029, 337, 473, 249, 046, 347, 092, 086, 812, 280, + 339, 157, 058, 424, 423, 113, 182, 612, 408, 583, + 422, 332, 009, 008, 242, 412, 129, 091, 007, 014, + 115, 104, 034, 400, 203, 317, 446, 126, 435, 331, + 352, 202, 019, 063, 282, 341, 097, 120, 196, 315, + 219, 414, 188, 434, 416, 038, 261, 442, 428, 248, + 421, 053, 094, 076, 444, 521, 085, 257, 089, 250, + 304, 083, 057, 247, 406, 710, 398, 523, 542, 334, + 404, 369, 417, 430, 164, 528, 231, 191, 390, 399, + 174, 605, 200, 018, 269, 056, 377, 127, 118, 441, + 527, 411, 526, 394, 059, 087, 370, + ]; + + public override int BaseEXP { get => ReadUInt16LittleEndian(Data[0x4C..]); set => WriteUInt16LittleEndian(Data[0x4C..], (ushort)value); } + public ushort AlphaMove { get => ReadUInt16LittleEndian(Data[0x4E..]); set => WriteUInt16LittleEndian(Data[0x4E..], value); } + + public int PlusCountTotal => (33 + 12) * 8; // 360 + public int PlusCountUsed => 247; + + // Set by Seed of Mastery or Alpha Move granted + public static ReadOnlySpan PlusMoves => + [ + 007, 008, 009, 014, 016, 017, 018, 019, 022, 029, + 033, 034, 036, 038, 039, 040, 042, 043, 044, 045, + 046, 048, 052, 053, 054, 055, 056, 057, 058, 059, + 060, 061, 063, 064, 071, 073, 074, 075, 076, 077, + 078, 079, 081, 083, 084, 085, 086, 087, 088, 089, + 091, 092, 093, 094, 095, 098, 100, 103, 104, + 105, 106, 108, 109, 113, 114, 115, 116, 118, 120, + 122, 126, 127, 129, 133, 137, 141, 150, 151, 153, + 157, 162, 163, 164, 172, 174, 182, 183, 188, 191, + 192, 195, 196, 197, 200, 202, 203, 204, 205, 209, + 211, 219, 223, 224, 225, 231, 232, 234, 235, 236, + 239, 242, 245, 247, 248, 249, 250, 257, 261, 268, + 269, 273, 280, 282, 297, 304, 313, 315, 317, 319, + 328, 331, 332, 334, 337, 339, 340, 341, 344, 345, + 347, 348, 350, 352, 369, 370, 377, 390, 392, 394, + 396, 398, 399, 400, 403, 404, 405, 406, 407, 408, + 411, 412, 413, 414, 416, 417, 418, 420, 421, 422, + 423, 424, 425, 427, 428, 430, 434, 435, 436, 437, + 438, 441, 442, 444, 446, 452, 453, 457, 473, 482, + 484, 521, 523, 526, 527, 528, 529, 532, 535, 538, + 540, 542, 555, 556, 560, 564, 566, 567, 570, 571, + 573, 574, 575, 576, 577, 583, 584, 585, 586, 588, + 591, 592, 593, 594, 595, 596, 598, 601, 605, 609, + 611, 612, 613, 614, 615, 616, 617, 621, 670, 679, + 687, 693, 710, 748, 784, 812, 920, + 097, // lol + ]; + + public ReadOnlySpan PlusMoveIndexes => PlusMoves; +} diff --git a/PKHeX.Core/PersonalInfo/PersonalTable.cs b/PKHeX.Core/PersonalInfo/PersonalTable.cs index c188bbab2..05325d779 100644 --- a/PKHeX.Core/PersonalInfo/PersonalTable.cs +++ b/PKHeX.Core/PersonalInfo/PersonalTable.cs @@ -10,6 +10,11 @@ namespace PKHeX.Core; /// public static class PersonalTable { + /// + /// Personal Table used in . + /// + public static readonly PersonalTable9ZA ZA = new(GetTable("za")); + /// /// Personal Table used in . /// diff --git a/PKHeX.Core/PersonalInfo/Table/PersonalTable9ZA.cs b/PKHeX.Core/PersonalInfo/Table/PersonalTable9ZA.cs new file mode 100644 index 000000000..d93835783 --- /dev/null +++ b/PKHeX.Core/PersonalInfo/Table/PersonalTable9ZA.cs @@ -0,0 +1,75 @@ +using System; + +namespace PKHeX.Core; + +/// +/// Personal Table storing used in . +/// +public sealed class PersonalTable9ZA : IPersonalTable, IPersonalTable +{ + private readonly PersonalInfo9ZA[] Table; + private const int SIZE = PersonalInfo9ZA.SIZE; + private const ushort MaxSpecies = Legal.MaxSpeciesID_9a; + public ushort MaxSpeciesID => MaxSpecies; + public int Count => Table.Length; + + public PersonalTable9ZA(Memory data) + { + Table = new PersonalInfo9ZA[data.Length / SIZE]; + var count = data.Length / SIZE; + for (int i = 0, ofs = 0; i < count; i++, ofs += SIZE) + { + var slice = data.Slice(ofs, SIZE); + Table[i] = new PersonalInfo9ZA(slice); + } + } + + public PersonalInfo9ZA this[int index] => Table[(uint)index < Table.Length ? index : 0]; + public PersonalInfo9ZA this[ushort species, byte form] => Table[GetFormIndex(species, form)]; + public PersonalInfo9ZA GetFormEntry(ushort species, byte form) => Table[GetFormIndex(species, form)]; + + public int GetFormIndex(ushort species, byte form) + { + if (species <= MaxSpeciesID) + return Table[species].FormIndex(species, form); + return 0; + } + + public bool IsSpeciesInGame(ushort species) + { + if (species > MaxSpeciesID) + return false; + + var form0 = Table[species]; + if (form0.IsPresentInGame) + return true; + + var fc = form0.FormCount; + for (byte i = 1; i < fc; i++) + { + var entry = GetFormEntry(species, i); + if (entry.IsPresentInGame) + return true; + } + return false; + } + + public bool IsPresentInGame(ushort species, byte form) + { + if (species > MaxSpeciesID) + return false; + + var form0 = Table[species]; + if (form == 0) + return form0.IsPresentInGame; + if (!form0.HasForm(form)) + return false; + + var entry = GetFormEntry(species, form); + return entry.IsPresentInGame; + } + + PersonalInfo IPersonalTable.this[int index] => this[index]; + PersonalInfo IPersonalTable.this[ushort species, byte form] => this[species, form]; + PersonalInfo IPersonalTable.GetFormEntry(ushort species, byte form) => GetFormEntry(species, form); +} diff --git a/PKHeX.Core/Resources/byte/evolve/evos_za.pkl b/PKHeX.Core/Resources/byte/evolve/evos_za.pkl new file mode 100644 index 0000000000000000000000000000000000000000..4244054db451af56ef5fcbde5c6beb7b0405781b GIT binary patch literal 4290 zcmeH`U1*zC7{~wTBu&%2ALk^Ua}8V9W-D$5wFdDcUZ|Nk$%WKx-oy`FE~DNAMa^X{ zHiV*_hsOUw(3wv1wwO2mRo5zxF?QESBk@6$_@_)~B z&YSa`lgg3fJt-&Uj5=u|<7A1PlV73W6p4~k?xNyUoa!3XoWDoiX%J1PMNB!<7cuLs z$DA`yENq%Zhgs@k+3ApR*C*@dguGi=q3D(_pzQuh#jSQxbL&@_hWpnv-PUC@<+eA) ztUE`{6AN7|y3CTW?5>6OHb%@_P13uVls8JGz075i^)^b*yEJ*P5K#1rUTF==-akpj ztFBPfQH}jn|_O!BBqHpF-y!5^TYzNNGx@+>}$ishy;-&Qd?|w z;6K`dwAtd{>p;e2P0r*^!4yr&lugA{P0iFz!!%9HOqprZHnV2V%$o(XXqL>f(Kcoi zHfd9K)TV95W^K;qZNU~dOv#pQ#a3<2)@{Q!H$ls`?3A6h?f(g31!%ysL%89& z&yshkIL=W6G}U}YIYd5B=5k!ZTvi`Fc`<<_>Ro^2Gu#2w8ALo8x=;_Hz_2ecoZk;JLlV_ z{(!o6nW^thY==oT|#3wdq`tDdsuh&y-#Bo z=l!~~?wH0koNv{gbr0&!{_fGZo}WKJ<9zQPlyx7`*dN7XI3oEu-MQz_%lzY#Uy%Hw z&|{o%KIiX`uKef4VV3jJfGC)=kquv?|V&SXpqKVCtpo|Lt`KnSPk&J z(=?BN-{?`;_{% zn{rzt&HtD4RL7nn^Zd_gKKlz=FN*6T<8&}l+!C3A3dSe23idalwKyaWi+jWoaj!Tk z?i0tvj@T7@Vqa{;RvZ^6#QlLAS_S=XXe|zj!{Q!sMBFQmiu=Sdu_JcHp4b-~u@%R~ v32}emNv-<1pOadPL*lU92Sxqmd%=BXhs0s*raxF)tKghww32hu;t>7-L%jvW literal 0 HcmV?d00001 diff --git a/PKHeX.Core/Resources/byte/levelup/lvlmove_za.pkl b/PKHeX.Core/Resources/byte/levelup/lvlmove_za.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0cb1ee7b0acac9820957512573894ede17669cce GIT binary patch literal 18708 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≪wWg7OB&`uy zi1>rNm1cizO&UpFMxqp!=CxVuinV1n&)sIE&F;-cN}oT@@0|1e&U2pgwURGD^jc(M~pnlSo{t~W8 z@%AW2#&k-R-Zn#iEnPw}Oa8nJ=}M+-mOUXTl-^e)zvGnjy|dDj^YSk#k#9=nyGrRh z*W_=xE`QTa394#yPr~s?dh$emN3}eY8hIhF)ElW)b@HwY4bs@AS>VhMyw2;QT#SqD zFx-V^nw#e4hh?D)joqxT#ofD8U?G_hKlG0`SYYYNU9kZc;X-*@mp^Ce-b zeivx%mvrSmUTW4g%w`#LJU-o>f>iB%iS7n_ev&Ds)MUVqU>AMHXX^0n{BXywmzIt9 literal 0 HcmV?d00001 diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_de.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_de.txt new file mode 100644 index 000000000..245bd872c --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_de.txt @@ -0,0 +1,8 @@ +Corni +Rioluis +Picanto +Fluffy +Échan +Bondo +Tranquillo +Panca \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_en.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_en.txt new file mode 100644 index 000000000..3723355da --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_en.txt @@ -0,0 +1,8 @@ +Bois +Riolouie +Spicy +Floffy +Tracie +Bond +Quille +Griddella \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_es-419.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_es-419.txt new file mode 100644 index 000000000..ffb338ad8 --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_es-419.txt @@ -0,0 +1,8 @@ +Gastón +Riolito +Apetito +Pachoncito +Lidia +Sandro +Plácido +Mónica \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_es.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_es.txt new file mode 100644 index 000000000..50250fcbf --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_es.txt @@ -0,0 +1,8 @@ +Gastón +Riolito +Riquiño +Panqueque +Camille +Ludovic +Plácido +Loli \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_fr.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_fr.txt new file mode 100644 index 000000000..a9f18d4fc --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_fr.txt @@ -0,0 +1,8 @@ +Dyna +Ribébou +Piment +Raidoudou +Odile +Marsaut +Kylian +Rozell \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_it.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_it.txt new file mode 100644 index 000000000..17e824222 --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_it.txt @@ -0,0 +1,8 @@ +Cornì +Rioletto +Spezia +Sofficio +Echan +Balzac +Quilliam +Suzette \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_ja.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_ja.txt new file mode 100644 index 000000000..e86f7bdc1 --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_ja.txt @@ -0,0 +1,8 @@ +ボワ +リオぼう +スパイス +ふわふわ +エシャン +ボンド +トランキー +クレープ \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_ko.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_ko.txt new file mode 100644 index 000000000..b84c96aca --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_ko.txt @@ -0,0 +1,8 @@ +브와 +리오룽 +스파이스 +푹신이 +에스얀 +본드 +트랭키 +크레이프 \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_zh-Hans.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_zh-Hans.txt new file mode 100644 index 000000000..de486ba17 --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_zh-Hans.txt @@ -0,0 +1,8 @@ +大角 +利欧宝 +香料 +飘绵绵 +娇环 +斐岳 +佑哉 +可莉萍 \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/gen9a/text_tradeza_zh-Hant.txt b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_zh-Hant.txt new file mode 100644 index 000000000..68e7b4e66 --- /dev/null +++ b/PKHeX.Core/Resources/legality/gen9a/text_tradeza_zh-Hant.txt @@ -0,0 +1,8 @@ +大角 +利歐寶 +香料 +飄綿綿 +嬌環 +斐岳 +佑哉 +可莉萍 \ No newline at end of file diff --git a/PKHeX.Core/Resources/legality/mgdb/wa9.pkl b/PKHeX.Core/Resources/legality/mgdb/wa9.pkl new file mode 100644 index 0000000000000000000000000000000000000000..c5828faf5e89c9b2d8bba9d37f0b22db8a37697f GIT binary patch literal 1424 zcmZQzfB;7}5Y5QI$OxqPAz~&Fih)TZ`yG@yN{xm9ks;tXhlODxlO2;TLo7ohT#p1W ziLo*KXJBCaj|QaB_z*5LTqgrV0}>m?yrK(ZLFhCv1x?4mG%a8y!8V$XQNsuu@2x8Ah@k1B2Hb0brm+GwL!VFy4j-k3RzgGb<<^v!W+kIdlOqAFdI|Xh7yb J*zSLa$32*0?}e=^FoHRE&#+2yuztG^?zE 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 literal 0 HcmV?d00001 diff --git a/PKHeX.Core/Resources/text/items/text_Items_de.txt b/PKHeX.Core/Resources/text/items/text_Items_de.txt index 9e8aa8762..2156fa677 100644 --- a/PKHeX.Core/Resources/text/items/text_Items_de.txt +++ b/PKHeX.Core/Resources/text/items/text_Items_de.txt @@ -2555,4 +2555,81 @@ Synchromaschine Meteorit Karmesinbuch Purpurbuch -Briannas Buch \ No newline at end of file +Briannas Buch +Meistersamen +Pixinit +Sarzenianit +Starmienit +Dragoranit +Meganienit +Impergatornit +Panzaeronit +Frosdedjenit + + +Flambirexonit +Stalobornit +Cerapendranit +Irokexonit +Zapplarangonit +Skelabranit +Brigaronit +Fennexisnit +Quajutsunit +Pyroleonit +Floetteonit +Calamaneronit +Thanathoranit +Tandraknit +Resladeronit +Zygardenit +Sen-Longnit + +Legiosnit +Zimmerschlüssel 202 +Illumina-Gigalette +Laborpass A +Laborpass B +Laborpass C + + +Kieselstein +Besonderer Ring +Signierter Anhänger +Gourmetmüll +Vitalzweig +Duros Tasche + + + + + + + + + + + + + + + + + +Mega-Splitter +Bunte Schraube +Roter Canary-Anhänger +Roter Canary-Anhänger +Roter Canary-Anhänger +Goldener Canary-Anhänger +Goldener Canary-Anhänger +Goldener Canary-Anhänger +Pinker Canary-Anhänger +Pinker Canary-Anhänger +Pinker Canary-Anhänger +Grüner Canary-Anhänger +Grüner Canary-Anhänger +Grüner Canary-Anhänger +Blauer Canary-Anhänger +Blauer Canary-Anhänger +Blauer Canary-Anhänger diff --git a/PKHeX.Core/Resources/text/items/text_Items_en.txt b/PKHeX.Core/Resources/text/items/text_Items_en.txt index de7fa73ee..2784831ba 100644 --- a/PKHeX.Core/Resources/text/items/text_Items_en.txt +++ b/PKHeX.Core/Resources/text/items/text_Items_en.txt @@ -2555,4 +2555,81 @@ Synchro Machine Meteorite Scarlet Book Violet Book -Briar’s Book \ No newline at end of file +Briar’s Book +Seed of Mastery +Clefablite +Victreebelite +Starminite +Dragoninite +Meganiumite +Feraligite +Skarmorite +Froslassite + + +Emboarite +Excadrite +Scolipite +Scraftinite +Eelektrossite +Chandelurite +Chesnaughtite +Delphoxite +Greninjite +Pyroarite +Floettite +Malamarite +Barbaracite +Dragalgite +Hawluchanite +Zygardite +Drampanite + +Falinksite +Key to Room 202 +Super Lumiose Galette +Lab Key Card A +Lab Key Card B +Lab Key Card C + + +Pebble +Cherished Ring +Autographed Plush +Tasty Trash +Revitalizing Twig +Lida’s Things + + + + + + + + + + + + + + + + + +Mega Shard +Colorful Screw +Red Canari Plush +Red Canari Plush +Red Canari Plush +Gold Canari Plush +Gold Canari Plush +Gold Canari Plush +Pink Canari Plush +Pink Canari Plush +Pink Canari Plush +Green Canari Plush +Green Canari Plush +Green Canari Plush +Blue Canari Plush +Blue Canari Plush +Blue Canari Plush \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/items/text_Items_es-419.txt b/PKHeX.Core/Resources/text/items/text_Items_es-419.txt new file mode 100644 index 000000000..76a9a608c --- /dev/null +++ b/PKHeX.Core/Resources/text/items/text_Items_es-419.txt @@ -0,0 +1,2635 @@ +Ningún objeto +Masterbola +Ultrabola +Superbola +Pokébola +Safaribola +Mallabola +Buceobola +Nidobola +Acopiobola +Turnobola +Lujobola +Honorbola +Ocasobola +Sanabola +Velozbola +Gloriabola +Poción +Antídoto +Antiquemaduras +Antihielo +Despertar +Antiparalizador +Restauratodo +Poción Máxima +Hiperpoción +Superpoción +Curación Total +Revivir +Revivir Máximo +Agua Fresca +Refresco +Limonada +Leche Mu-mu +Polvo Energía +Raíz Energía +Polvo Curación +Hierba Revivir +Éter +Éter Máximo +Elíxir +Elíxir Máximo +Galleta Lava +Jugo de Baya +Ceniza Sagrada +Más PS +Proteína +Hierro +Carbohidratos +Calcio +Caramelo Raro +Más PP +Zinc +PP Máximos +Barrita Plus +Protección X +Crítico X +Ataque X +Defensa X +Velocidad X +Precisión X +Ataque Especial X +Defensa Especial X +Pokémuñeco +Cola de Skitty +Flauta Azul +Flauta Amarilla +Flauta Roja +Flauta Negra +Flauta Blanca +Sal Cardumen +Caracola Cardumen +Fragmento Rojo +Fragmento Azul +Fragmento Amarillo +Fragmento Verde +Superrepelente +Repelente Máximo +Cuerda de Huida +Repelente +Piedra Solar +Piedra Lunar +Piedra Fuego +Piedra Trueno +Piedra Agua +Piedra Hoja +Minihongo +Hongo Grande +Perla +Gran Perla +Polvo Estrella +Fragmento Estrella +Pepita de Oro +Escama Corazón +Miel +Abono Rápido +Abono Lento +Abono Fijador +Abono Germinador +Fósil Raíz +Fósil Garra +Fósil Hélix +Fósil Domo +Ámbar Viejo +Fósil Coraza +Fósil Cráneo +Hueso Raro +Piedra Día +Piedra Noche +Piedra Alba +Piedra Oval +Piedra Espíritu +Griseoesfera +Té +(?) +Autógrafo +HidroROM +FulgoROM +PiroROM +CrioROM +(?) +Caja de Pokémon +Botiquín +Estuche de MT +Tarro de Caramelos +Bolsillo de Mejoras +Maleta +Bolsillo de Captura +Bolsillo de Combate +(?) +(?) +(?) +(?) +(?) +Corazón Dulce +Diamansfera +Lustroesfera +Carta Inicial +Carta Favoritos +Carta Invitación +Carta Gracias +Carta Pregunta +Carta Gustos +Carta Respuesta +Carta Puente S +Carta Puente F +Carta Puente A +Carta Puente V +Carta Puente P +Baya Zreza +Baya Atania +Baya Duraz +Baya Safre +Baya Perasi +Baya Zanama +Baya Aranja +Baya Caquic +Baya Ziuela +Baya Citrón +Baya Higog +Baya Wiki +Baya Ango +Baya Guaya +Baya Pabaya +Baya Frambu +Baya Oram +Baya Látano +Baya Peragu +Baya Pinia +Baya Grana +Baya Algama +Baya Ispero +Baya Meluce +Baya Uvav +Baya Tamate +Baya Mais +Baya Aostan +Baya Rautan +Baya Monli +Baya Wikano +Baya Plama +Baya Sambia +Baya Rudion +Baya Andano +Baya Caoca +Baya Pasio +Baya Gualot +Baya Tamar +Baya Rimoya +Baya Pomaro +Baya Kebia +Baya Acardo +Baya Kouba +Baya Payapa +Baya Yecana +Baya Alcho +Baya Drasi +Baya Anjiro +Baya Dillo +Baya Baribá +Baya Chilan +Baya Lichi +Baya Gonlan +Baya Aslac +Baya Yapati +Baya Aricoc +Baya Lansat +Baya Arabol +Baya Enigma +Baya Lagro +Baya Chiri +Baya Jaboca +Baya Magua +Polvo Brillo +Hierba Blanca +Brazalete Firme +Repartir Experiencia +Garra Rápida +Cascabel Alivio +Hierba Mental +Cinta Elección +Roca del Rey +Polvo Plata +Moneda Amuleto +Amuleto +Rocío Bondad +Diente Marino +Escama Marina +Bola de Humo +Piedra Eterna +Cinta Aguante +Huevo Suerte +Periscopio +Revest. Metálico +Restos +Escama Dragón +Bola Luminosa +Arena Fina +Piedra Dura +Semilla Milagro +Lentes de Sol +Cinturón Negro +Imán +Agua Mística +Pico Afilado +Flecha Venenosa +Hielo Perpetuo +Hechizo +Cuchara Torcida +Carbón +Colmillo Dragón +Pañuelo de Seda +Mejora +Cascabel Nácar +Incienso Marino +Incienso Suave +Puño Suerte +Polvo Metálico +Hueso Grueso +Puerro +Pañuelo Rojo +Pañuelo Azul +Pañuelo Rosa +Pañuelo Esmeralda +Pañuelo Amarillo +Lupa +Cinta Fuerte +Lentes Especiales +Cinturón de Experto +Refleluz +Vidaesfera +Hierba Única +Toxiesfera +Llamaesfera +Polvo Velocidad +Banda Aguante +Telescopio +Metrónomo +Bola Férrea +Cola Plúmbea +Hilo Destino +Lodo Negro +Roca Helada +Roca Suave +Roca Calor +Roca Lluvia +Garra Garfio +Pañuelo Elección +Toxiestrella +Brazalete Recio +Cinturón Recio +Lente Recio +Banda Recia +Tobillera Recia +Pesa Recia +Muda de Piel +Raíz Grande +Lentes Elección +Placa Llama +Placa Linfa +Placa Trueno +Placa Pradal +Placa Helada +Placa Fuerte +Placa Tóxica +Placa Terral +Placa Cielo +Placa Mental +Placa Insecto +Placa Pétrea +Placa Terror +Placa Draco +Placa Oscura +Placa Acero +Incienso Raro +Incienso Roca +Incienso Lento +Incienso Acua +Incienso Floral +Incienso Duplo +Incienso Puro +Protector +Electrizador +Magmatizador +Disco Extraño +Tela Terrible +Garra Afilada +Colmillo Agudo +MT01 +MT02 +MT03 +MT04 +MT05 +MT06 +MT07 +MT08 +MT09 +MT10 +MT11 +MT12 +MT13 +MT14 +MT15 +MT16 +MT17 +MT18 +MT19 +MT20 +MT21 +MT22 +MT23 +MT24 +MT25 +MT26 +MT27 +MT28 +MT29 +MT30 +MT31 +MT32 +MT33 +MT34 +MT35 +MT36 +MT37 +MT38 +MT39 +MT40 +MT41 +MT42 +MT43 +MT44 +MT45 +MT46 +MT47 +MT48 +MT49 +MT50 +MT51 +MT52 +MT53 +MT54 +MT55 +MT56 +MT57 +MT58 +MT59 +MT60 +MT61 +MT62 +MT63 +MT64 +MT65 +MT66 +MT67 +MT68 +MT69 +MT70 +MT71 +MT72 +MT73 +MT74 +MT75 +MT76 +MT77 +MT78 +MT79 +MT80 +MT81 +MT82 +MT83 +MT84 +MT85 +MT86 +MT87 +MT88 +MT89 +MT90 +MT91 +MT92 +MO01 +MO02 +MO03 +MO04 +MO05 +MO06 +(?) +(?) +Kit de Explorador +Saco de Botín +Reglamento +Poké Radar +Tarjeta de Puntos +Guía de Viaje +Caja de Stickers +Caja Corazón +Bolsa de Stickers +Libreta de Amistades +Llave de la Central +Talismán +Llave Galaxia +Cadena Roja +Mapa +Buscapelea +Monedero +Caña Vieja +Caña Buena +Supercaña +Psyrregadera +Pokochera +Bici +Llave de la Suite +Carta del Prof. Oak +Pluma Lunar +Tarjeta de Socio +Flauta Azur +Boleto del Barco +Pase de Concurso +Piedra Magma +Paquete +Cupón 1 +Cupón 2 +Cupón 3 +Llave del Almacén +Medicamento Secreto +Cámara Lucha +Gracídea +Llave Secreta +Caja Bonguri +Tableta Unown +Plantabayas +Detector +Tarjeta Azul +Cola de Slowpoke +Cascabel Claro +Llave Magnética +Llave del Sótano +Squirregadera +Escama Roja +Objeto Perdido +Pase del Tren +Maquinaria +Pluma Plateada +Pluma Arcoíris +Huevo Misterioso +Bonguri Rojo +Bonguri Azul +Bonguri Amarillo +Bonguri Verde +Bonguri Rosa +Bonguri Blanco +Bonguri Negro +Rapibola +Nivelabola +Señuelobola +Pesabola +Amorbola +Amigobola +Lunabola +Competibola +Parquebola +Álbum +Reproductor GB +Cascabel Oleaje +Caramelo Furia +Tarjeta de Datos 01 +Tarjeta de Datos 02 +Tarjeta de Datos 03 +Tarjeta de Datos 04 +Tarjeta de Datos 05 +Tarjeta de Datos 06 +Tarjeta de Datos 07 +Tarjeta de Datos 08 +Tarjeta de Datos 09 +Tarjeta de Datos 10 +Tarjeta de Datos 11 +Tarjeta de Datos 12 +Tarjeta de Datos 13 +Tarjeta de Datos 14 +Tarjeta de Datos 15 +Tarjeta de Datos 16 +Tarjeta de Datos 17 +Tarjeta de Datos 18 +Tarjeta de Datos 19 +Tarjeta de Datos 20 +Tarjeta de Datos 21 +Tarjeta de Datos 22 +Tarjeta de Datos 23 +Tarjeta de Datos 24 +Tarjeta de Datos 25 +Tarjeta de Datos 26 +Tarjeta de Datos 27 +Esfera Verde +Cápsula Candado +Prisma Rojo +Prisma Azul +Misticristal +Escama Bella +Mineral Evolutivo +Piedra Pómez +Casco Dentado +Globo con Helio +Tarjeta Roja +Blanco +Banda Atadura +Tubérculo +Pila +Botón de Escape +Gema Fuego +Gema Agua +Gema Eléctrico +Gema Planta +Gema Hielo +Gema Pelea +Gema Veneno +Gema Tierra +Gema Volador +Gema Psíquico +Gema Insecto +Gema Roca +Gema Fantasma +Gema Dragón +Gema Siniestro +Gema Acero +Gema Normal +Pluma Vigor +Pluma Músculo +Pluma Aguante +Pluma Intelecto +Pluma Mente +Pluma Ímpetu +Pluma Bella +Fósil Cubierta +Fósil Pluma +Tarjeta Libertad +Regaloesfera +Ensueñobola +Pokéseñuelo +Neceser +Cráneo de Dragón +Hongo Aroma +Maxipepita de Oro +Cordón de Perlas +Fragmento Cometa +Reliquia de Cobre +Reliquia de Plata +Reliquia de Oro +Ánfora Antigua +Brazalete Antiguo +Estatua Antigua +Corona Antigua +Porcehelado +Crítico X 2 +Velocidad X 2 +Ataque Especial X 2 +Defensa Especial X 2 +Defensa X 2 +Ataque X 2 +Precisión X 2 +Velocidad X 3 +Ataque Especial X 3 +Defensa Especial X 3 +Defensa X 3 +Ataque X 3 +Precisión X 3 +Velocidad X 6 +Ataque Especial X 6 +Defensa Especial X 6 +Defensa X 6 +Ataque X 6 +Precisión X 6 +Habilitador +Tiraobjeto +Activaobjeto +Quitaestado +Crítico X 3 +Orbe Claro +Orbe Oscuro +MT93 +MT94 +MT95 +Videomisor +(?) +Envío 1 +Envío 2 +Envío 3 +Videomisor +Caja de Insignias +Punta ADN +Punta ADN +Pase +Amuleto Oval +Amuleto Iris +Tarjeta Plasma +Pañuelo Sucio +Máquina de Colress +Objeto Perdido +Objeto Perdido +Espejo Veraz +Seguro de Debilidad +Chaleco Asalto +Holomisor +Carta del Profesor +Patines +Placa Feérica +Cápsula Habilidad +Bocadito de Crema +Bolsita Fragante +Musgo Brillante +Bola de Nieve +Visor Protector +Pokéflauta +Abono Fértil +Abono Sorpresa +Abono Fructífero +Abono Insólito +Gengarita +Gardevoirita +Ampharosita +Venusaurita +Charizardita X +Blastoisita +Mewtwoita X +Mewtwoita Y +Blazikenita +Medichamita +Houndoomita +Aggronita +Banettita +Tyranitarita +Scizorita +Pinsirita +Aerodactylita +Lucarita +Abomasnowita +Kangaskhanita +Gyaradosita +Absolita +Charizardita Y +Alakazamita +Heracrossita +Mawilita +Manectricita +Garchompita +Latiasita +Latiosita +Baya Hibis +Baya Biglia +Baya Maranga +Lotarregadera +MT96 +MT97 +MT98 +MT99 +MT100 +Pase de la Central +Megaaro +Piedra Insólita +Piedra Común +Cupón de Descuento +Llave del Elevador +Pase del TMV +Emblema de Kalos +Guía de Aventuras +Estatuilla Rara +Portalentes +Kit de Maquillaje +Maleta +Galette Luminalia +Galleta Yantra +Fósil Mandíbula +Fósil Aleta +Boleto Looker +Bici +Holomisor +Gema Hada +Megacolgante +Megaguante +Bici de Carreras +Bici Acrobática +Wailrregadera +Piezas Devon +Saco de Hollín +Llave del Sótano +Kit de Pokécubos +Carta para Steven +Boleto Eón +Escáner +Lentes Aislantes +Meteorito +Llave Habitación 1 +Llave Habitación 2 +Llave Habitación 4 +Llave Habitación 6 +Llave del Almacén +Detector Devon +Boleto del Barco +MO07 +Tanque Devon +Traje de Concurso +Vestido de Concurso +Traje Magma +Traje Aqua +Boleto para dos +Megapulsera +Megacollar +Megalentes +Megaancla +Megabroche +Megatiara +Megatobillera +Meteorito +Swampertita +Sceptilita +Sableynita +Altarianita +Galladita +Audinita +Metagrossita +Sharpedonita +Slowbronita +Steelixita +Pidgeotita +Glalita +Diancita +Vasija de Castigo +Megabrazalete +Cameruptita +Lopunnita +Salamencita +Beedrillita +Meteorito +Meteorito +Piedra Llave +Fragmento Meteorito +Flauta Eón +Normastal Z +Pirostal Z +Hidrostal Z +Electrostal Z +Fitostal Z +Criostal Z +Lizastal Z +Toxistal Z +Geostal Z +Aerostal Z +Psicostal Z +Insectostal Z +Litostal Z +Espectrostal Z +Dracostal Z +Nictostal Z +Metalostal Z +Feeristal Z +Pikastal Z +Tapa Plateada +Tapa Dorada +Pulsera Z +Dueyestal Z +Incinostal Z +Primastal Z +Tapistal Z +Marshastal Z +Alo-Raistal Z +Snorlastal Z +Eeveestal Z +Mewstal Z +Normastal Z +Pirostal Z +Hidrostal Z +Electrostal Z +Fitostal Z +Criostal Z +Lizastal Z +Toxistal Z +Geostal Z +Aerostal Z +Psicostal Z +Insectostal Z +Litostal Z +Espectrostal Z +Dracostal Z +Nictostal Z +Metalostal Z +Feeristal Z +Pikastal Z +Dueyestal Z +Incinostal Z +Primastal Z +Tapistal Z +Marshastal Z +Alo-Raistal Z +Snorlastal Z +Eeveestal Z +Mewstal Z +Ash-Pikastal Z +Ash-Pikastal Z +(?) +(?) +(?) +(?) +Morral +Caña +Máscara del Profesor +Festicupón +Piedra Brillante +Nervioesfera +Arca de Zygarde +(?) +Piedra Hielo +Buscamontura +Entebola +Malasada Maxi +Néctar Rojo +Néctar Amarillo +Néctar Rosa +Néctar Violeta +Flauta Solar +Flauta Lunar +(?) +Nota Intrigante +Baya Frambu Plateada +Baya Frambu Dorada +Baya Látano Plateada +Baya Látano Dorada +Baya Pinia Plateada +Baya Pinia Dorada +(?) +(?) +(?) +(?) +(?) +Llave Secreta +Boleto del Barco +Visor Silph +Paquete +Llave Magnética +Dentadura de Oro +Llave del Elevador +Cubresuelos +Almohadillas +Semilla Electro +Semilla Psique +Semilla Bruma +Semilla Césped +Resorte Estirado +Tiza +Canica +Pendiente +Cristal Marino +Hoja de Oro +Hoja de Plata +Bola de Arcilla +Nácar Tropical +Hoja Escrita +Hoja Escrita +Ramo Pequeño +(?) +(?) +(?) +Perfume +Superperfume +Perfume Máximo +Rokikos +Disco Pelea +Disco Volador +Disco Veneno +Disco Tierra +Disco Roca +Disco Insecto +Disco Fantasma +Disco Acero +Disco Fuego +Disco Agua +Disco Planta +Disco Eléctrico +Disco Psíquico +Disco Hielo +Disco Dragón +Disco Siniestro +Disco Hada +Solgaleostal Z +Lunalastal Z +Ultranecrostal Z +Mimikyustal Z +Lycanrostal Z +Kommostal Z +Solgaleostal Z +Lunalastal Z +Ultranecrostal Z +Mimikyustal Z +Lycanrostal Z +Kommostal Z +Superpulsera Z +Pétalo Rosa +Pétalo Naranja +Pétalo Azul +Pétalo Rojo +Pétalo Verde +Pétalo Amarillo +Pétalo Violeta +Flor Irisada +Medalla Fulgor +Necrosol +Necroluna +Necrosol +Necroluna +Cristal Z (Ilima) +Pokébola Ajena +Cupón Eclosión +Cupón Rebaja +Cupón Botín +Cupón Experiencia +Cupón Amistad +Cupón Reclamo +Cupón Sigilo +Cupón PS +Cupón PP +Cupón Refuerzo +Cupón Captura +Caramelo Vigor +Caramelo Músculo +Caramelo Aguante +Caramelo Intelecto +Caramelo Mente +Caramelo Ímpetu +Caramelo Vigor L +Caramelo Músculo L +Caramelo Aguante L +Caramelo Intelecto L +Caramelo Mente L +Caramelo Ímpetu L +Caramelo Vigor XL +Caramelo Músculo XL +Caramelo Aguante XL +Caramelo Intelecto XL +Caramelo Mente XL +Caramelo Ímpetu XL +Caramelo Bulbasaur +Caramelo Charmander +Caramelo Squirtle +Caramelo Caterpie +Caramelo Weedle +Caramelo Pidgey +Caramelo Rattata +Caramelo Spearow +Caramelo Ekans +Caramelo Pikachu +Caramelo Sandshrew +Caramelo Nidoran♀ +Caramelo Nidoran♂ +Caramelo Clefairy +Caramelo Vulpix +Caramelo Jigglypuff +Caramelo Zubat +Caramelo Oddish +Caramelo Paras +Caramelo Venonat +Caramelo Diglett +Caramelo Meowth +Caramelo Psyduck +Caramelo Mankey +Caramelo Growlithe +Caramelo Poliwag +Caramelo Abra +Caramelo Machop +Caramelo Bellsprout +Caramelo Tentacool +Caramelo Geodude +Caramelo Ponyta +Caramelo Slowpoke +Caramelo Magnemite +Caramelo Farfetch’d +Caramelo Doduo +Caramelo Seel +Caramelo Grimer +Caramelo Shellder +Caramelo Gastly +Caramelo Onix +Caramelo Drowzee +Caramelo Krabby +Caramelo Voltorb +Caramelo Exeggcute +Caramelo Cubone +Caramelo Hitmonlee +Caramelo Hitmonchan +Caramelo Lickitung +Caramelo Koffing +Caramelo Rhyhorn +Caramelo Chansey +Caramelo Tangela +Caramelo Kangaskhan +Caramelo Horsea +Caramelo Goldeen +Caramelo Staryu +Caramelo Mr. Mime +Caramelo Scyther +Caramelo Jynx +Caramelo Electabuzz +Caramelo Pinsir +Caramelo Tauros +Caramelo Magikarp +Caramelo Lapras +Caramelo Ditto +Caramelo Eevee +Caramelo Porygon +Caramelo Omanyte +Caramelo Kabuto +Caramelo Aerodactyl +Caramelo Snorlax +Caramelo Articuno +Caramelo Zapdos +Caramelo Moltres +Caramelo Dratini +Caramelo Mewtwo +Caramelo Mew +Caramelo Meltan +Caramelo Magmar +(?) +(?) +(?) +(?) +(?) +(?) +(?) +(?) +(?) +(?) +(?) +(?) +(?) +(?) +(?) +(?) +Recomendación +Caja de Pokémon +Estrella Deseo +Banda Dinamax +(?) +(?) +Caña +Bici Rotom +(?) +(?) +Salchichas +Lata de Darren +Lata de Bach +Lata de Frijoles +Pan de Molde +Pasta +Hongos +Cola Ahumada +Puerro Grueso +Manzana Selecta +Huesos Finos +Papitas +Hierba Intensa +Verduras +Frituras +Huevo Duro +Kit de Campamento +(?) +(?) +Espada Oxidada +Escudo Oxidado +Ornitofósil +Ictiofósil +Dracofósil +Plesiofósil +Dulce de Fresa +Dulce de Corazón +Dulce de Fruto +Dulce de Trébol +Dulce de Flor +Dulce de Estrella +Dulce de Cinta +Manzana Dulce +Manzana Ácida +Aerosol Bucal +Mochila de Escape +Botas Gruesas +Seguro de Fallo +Servicio Raro +Paraguas Multiusos +Caramelo Exp. XS +Caramelo Exp. S +Caramelo Exp. M +Caramelo Exp. L +Caramelo Exp. XL +Caramelo Dinamax +DT00 +DT01 +DT02 +DT03 +DT04 +DT05 +DT06 +DT07 +DT08 +DT09 +DT10 +DT11 +DT12 +DT13 +DT14 +DT15 +DT16 +DT17 +DT18 +DT19 +DT20 +DT21 +DT22 +DT23 +DT24 +DT25 +DT26 +DT27 +DT28 +DT29 +DT30 +DT31 +DT32 +DT33 +DT34 +DT35 +DT36 +DT37 +DT38 +DT39 +DT40 +DT41 +DT42 +DT43 +DT44 +DT45 +DT46 +DT47 +DT48 +DT49 +DT50 +DT51 +DT52 +DT53 +DT54 +DT55 +DT56 +DT57 +DT58 +DT59 +DT60 +DT61 +DT62 +DT63 +DT64 +DT65 +DT66 +DT67 +DT68 +DT69 +DT70 +DT71 +DT72 +DT73 +DT74 +DT75 +DT76 +DT77 +DT78 +DT79 +DT80 +DT81 +DT82 +DT83 +DT84 +DT85 +DT86 +DT87 +DT88 +DT89 +DT90 +DT91 +DT92 +DT93 +DT94 +DT95 +DT96 +DT97 +DT98 +DT99 +MT00 +Menta Huraña +Menta Firme +Menta Pícara +Menta Audaz +Menta Osada +Menta Agitada +Menta Descuidada +Menta Relajada +Menta Modesta +Menta Cordial +Menta Alocada +Menta Apacible +Menta Serena +Menta Amable +Menta Cauta +Menta Grosera +Menta Miedosa +Menta Activa +Menta Alegre +Menta Ingenua +Menta Seria +Fragmento Deseo +Tetera Agrietada +Tetera Rota +Superauriculares +Fruta Tropical +Queso Mu-mu +Especias +Crema Fresca +Curry Instantáneo +Leche de Coco +Fideos Instantáneos +Hamburguesas +Especias Gigamax +Fragmentito Deseo +Bici Rotom +Amuleto Captura +(?) +Carta Vieja +Autógrafo del Grupo +Libro de Sonia +(?) +(?) +(?) +(?) +(?) +(?) +Catálogo Rotom +★And458 +★And15 +★And337 +★And603 +★And390 +★Sgr6879 +★Sgr6859 +★Sgr6913 +★Sgr7348 +★Sgr7121 +★Sgr6746 +★Sgr7194 +★Sgr7337 +★Sgr7343 +★Sgr6812 +★Sgr7116 +★Sgr7264 +★Sgr7597 +★Del7882 +★Del7906 +★Del7852 +★Psc596 +★Psc361 +★Psc510 +★Psc437 +★Psc8773 +★Lep1865 +★Lep1829 +★Boo5340 +★Boo5506 +★Boo5435 +★Boo5602 +★Boo5733 +★Boo5235 +★Boo5351 +★Hya3748 +★Hya3903 +★Hya3418 +★Hya3482 +★Hya3845 +★Eri1084 +★Eri472 +★Eri1666 +★Eri897 +★Eri1231 +★Eri874 +★Eri1298 +★Eri1325 +★Eri984 +★Eri1464 +★Eri1393 +★Eri850 +★Tau1409 +★Tau1457 +★Tau1165 +★Tau1791 +★Tau1910 +★Tau1346 +★Tau1373 +★Tau1412 +★CMa2491 +★CMa2693 +★CMa2294 +★CMa2827 +★CMa2282 +★CMa2618 +★CMa2657 +★CMa2646 +★UMa4905 +★UMa4301 +★UMa5191 +★UMa5054 +★UMa4295 +★UMa4660 +★UMa4554 +★UMa4069 +★UMa3569 +★UMa3323 +★UMa4033 +★UMa4377 +★UMa4375 +★UMa4518 +★UMa3594 +★Vir5056 +★Vir4825 +★Vir4932 +★Vir4540 +★Vir4689 +★Vir5338 +★Vir4910 +★Vir5315 +★Vir5359 +★Vir5409 +★Vir5107 +★Ari617 +★Ari553 +★Ari546 +★Ari951 +★Ori1713 +★Ori2061 +★Ori1790 +★Ori1903 +★Ori1948 +★Ori2004 +★Ori1852 +★Ori1879 +★Ori1899 +★Ori1543 +★Cas21 +★Cas168 +★Cas403 +★Cas153 +★Cas542 +★Cas219 +★Cas265 +★Cnc3572 +★Cnc3208 +★Cnc3461 +★Cnc3449 +★Cnc3429 +★Cnc3627 +★Cnc3268 +★Cnc3249 +★Com4968 +★Crv4757 +★Crv4623 +★Crv4662 +★Crv4786 +★Aur1708 +★Aur2088 +★Aur1605 +★Aur2095 +★Aur1577 +★Aur1641 +★Aur1612 +★Pav7790 +★Cet911 +★Cet681 +★Cet188 +★Cet539 +★Cet804 +★Cep8974 +★Cep8162 +★Cep8238 +★Cep8417 +★Cen5267 +★Cen5288 +★Cen551 +★Cen5459 +★Cen5460 +★CMi2943 +★CMi2845 +★Equ8131 +★Vul7405 +★UMi424 +★UMi5563 +★UMi5735 +★UMi6789 +★Crt4287 +★Lyr7001 +★Lyr7178 +★Lyr7106 +★Lyr7298 +★Ara6585 +★Sco6134 +★Sco6527 +★Sco6553 +★Sco5953 +★Sco5984 +★Sco6508 +★Sco6084 +★Sco5944 +★Sco6630 +★Sco6027 +★Sco6247 +★Sco6252 +★Sco5928 +★Sco6241 +★Sco6165 +★Tri544 +★Leo3982 +★Leo4534 +★Leo4357 +★Leo4057 +★Leo4359 +★Leo4031 +★Leo3852 +★Leo3905 +★Leo3773 +★Gru8425 +★Gru8636 +★Gru8353 +★Lib5685 +★Lib5531 +★Lib5787 +★Lib5603 +★Pup3165 +★Pup3185 +★Pup3045 +★Cyg7924 +★Cyg7417 +★Cyg7796 +★Cyg8301 +★Cyg7949 +★Cyg7528 +★Oct7228 +★Col1956 +★Col2040 +★Col2177 +★Gem2990 +★Gem2891 +★Gem2421 +★Gem2473 +★Gem2216 +★Gem2777 +★Gem2650 +★Gem2286 +★Gem2484 +★Gem2930 +★Peg8775 +★Peg8781 +★Peg39 +★Peg8308 +★Peg8650 +★Peg8634 +★Peg8684 +★Peg8450 +★Peg8880 +★Peg8905 +★Oph6556 +★Oph6378 +★Oph6603 +★Oph6149 +★Oph6056 +★Oph6075 +★Ser5854 +★Ser7141 +★Ser5879 +★Her6406 +★Her6148 +★Her6410 +★Her6526 +★Her6117 +★Her6008 +★Per936 +★Per1017 +★Per1131 +★Per1228 +★Per834 +★Per941 +★Phe99 +★Phe338 +★Vel3634 +★Vel3485 +★Vel3734 +★Aqr8232 +★Aqr8414 +★Aqr8709 +★Aqr8518 +★Aqr7950 +★Aqr8499 +★Aqr8610 +★Aqr8264 +★Cru4853 +★Cru4730 +★Cru4763 +★Cru4700 +★Cru4656 +★PsA8728 +★TrA6217 +★Cap7776 +★Cap7754 +★Cap8278 +★Cap8322 +★Cap7773 +★Sge7479 +★Car2326 +★Car3685 +★Car3307 +★Car3699 +★Dra5744 +★Dra5291 +★Dra6705 +★Dra6536 +★Dra7310 +★Dra6688 +★Dra4434 +★Dra6370 +★Dra7462 +★Dra6396 +★Dra6132 +★Dra6636 +★CVn4915 +★CVn4785 +★CVn4846 +★Aql7595 +★Aql7557 +★Aql7525 +★Aql7602 +★Aql7235 +Maxipanal +Maxihongo +Rama de Galanuez +Brazalete Galanuez +Tarjeta Chic +Pase Armadura +Bici Rotom +Bici Rotom +Amuleto Experiencia +Duralium +Amuleto Emblema +Riendas Unión +Riendas Unión +Corona Galanuez +Leyenda 1 +Leyenda 2 +Leyenda 3 +Leyenda (?) +Pase Corona +Corona Tallada +Pétalo Fulgor +Crin Blanca +Crin Negra +Zanahoria Nívea +Zanahoria Oscura +Maxinium +Semillas Zanahoria +Parche Habilidad +Riendas Unión +Calmaesfera Tiempo +Calmaesfera Espacio +Calmaesfera +Cordón Unión +Panqué Clásico +Bonguri +Panqué Júbilo +Vitamina Múltiple +Vitamina Crítica +Aperitivo Elección +Encurtidoble +Refrigerio Inversión +Helecho Rizado +Semilla Dominio +Pokébola +(?) +Hielo Eterno +Garra de Uxie +Colmillo de Azelf +Pluma de Mesprit +Piedra Roja +Flauta Celestial +Remedio +Superremedio +Miel Brillante +Espiga Vivaz +Haba Suculenta +Hongo Esponjoso +Mineral Crocante +Madera +Hierba Regia +Calmaesfera Pantano +Pokébola +Superbola +Ultrabola +Plumabola +Pokémuñeca +(?) +Bola Humareda +Bola Ruidosa +Bola Pegajosa +Fragmento Estrella +Cebo de Hongos +Hierba Repelente +Cebo Meloso +Cebo de Grano +Cebo de Habas +Cebo Mineral +Poción +Superpoción +Hiperpoción +Poción Máxima +Restauratodo +Remedio +Superremedio +Hiperremedio +Barrita Plus +Panqué Júbilo +Curación Total +Revivir +Revivir Máximo +Píldora Éter +Píldora Elíxir +Aerosol Sigilo +(?) +Vitamina Ofensiva +Vitamina Defensiva +Vitamina Crítica +Vitamina Evasiva +Vitamina Múltiple +Calmaesfera Bosque +Pepita de Hierro +(?) +Piedra Negra +Piedra Celeste +(?) +Bola de Lodo +(?) +Petaloalga Ruidosa +Fumibulbo +Bonguri Podrido +Bola de Nieve +Bola Pegajosa +Mineral Negro +Bloque de Turba +Aerosol Sigilo +Puerro Medicinal +Revivebrote +Hierba Éter +(?) +(?) +Amuleto Sustituto 2 +Amuleto Sustituto 3 +Hongo Espada +Hongo Férreo +Hongo Evasivo +Hongo Crítico +Rábano Arenero +Amuleto Sustituto 4 +Amuleto Sustituto 5 +Trufa Dulce +Masa para Cebo +Pokébola +Superbola +Ultrabola +Plumabola +(?) +(?) +Bola Ruidosa +Bola Humareda +(?) +(?) +Pokémuñeca +Calmaesfera Volcán +Calmaesfera Montaña +Calmaesfera Nieve +Cebo Meloso +Cebo de Grano +Cebo de Habas +Cebo de Hongos +Cebo Mineral +Refrigerio Inversión +Aperitivo Elección +Encurtidoble +Amuleto Protector 1 +Amuleto Protector 2 +Amuleto Protector 3 +Amuleto Protector 4 +Amuleto Protector 5 +Diario Rasgado +Amuleto Salud 1 +Amuleto Salud 2 +Amuleto Salud 3 +Amuleto Salud 4 +Amuleto Salud 5 +Fragmento Losa +Cebo Basculegion +Diario Antiguo +Alabola +Aerobola +Pesabola +Kilobola +Quintalbola +Alabola +Aerobola +Pesabola +Baya Lupu +Hiperremedio +Vitamina Ofensiva +Vitamina Defensiva +Vitamina Evasiva +Polvo Esfuerzo +Grava Esfuerzo +Piedra Esfuerzo +Roca Esfuerzo +Medicamento Secreto +Amuleto Sustituto 1 +Objeto Perdido +Objeto Perdido +Objeto Perdido +Objeto Perdido +Objeto Perdido +(?) +Origenbola +(?) +(?) +(?) +(?) +Mena Origen +Gran Diamansfera +Gran Lustroesfera +Gran Griseoesfera +Placa Neutral +(?) +Kit de Artesanía +Kilobola +Quintalbola +Extrañabola +Pokédex +Poema Antiguo 1 +Poema Antiguo 2 +Poema Antiguo 3 +Poema Antiguo 4 +(?) +Poema Antiguo 5 +Poema Antiguo 6 +Poema Antiguo 7 +Poema Antiguo 8 +Poema Antiguo 9 +Poema Antiguo 10 +Poema Antiguo 11 +Poema Antiguo 12 +Poema Antiguo 13 +Poema Antiguo 14 +Poema Antiguo 15 +Poema Antiguo 16 +Poema Antiguo 17 +Poema Antiguo 18 +Poema Antiguo 19 +Poema Antiguo 20 +Fragmento Extraño S +Fragmento Extraño L +Taladro +Tablilla Kanto +Tablilla Johto +Tablilla Empatía +Tablilla Arcoíris +Tablilla Tormenta +Tablilla Mar +Tablilla Tierra +Tablilla Cielo +Tablilla Genética +Tablilla Inicio +Tablilla Distorsión +Reproductor DS + + + + + +Placa Legendaria +SmartRotom +Sándwich +Pokébola de Koraidon +Pokébola de Miraidon +Orbe Teracristal +Libro Escarlata +Libro Púrpura +Billetera de Fuco + + + + + +Bambú Pequeño +Bambú Grande + + + + + + + + + + + + + +Manuscrito Sombras +Manuscrito Aguas + + +Armadura Maldita +Teralito Normal +Teralito Fuego +Teralito Agua +Teralito Eléctrico +Teralito Planta +Teralito Hielo +Teralito Pelea +Teralito Veneno +Teralito Tierra +Teralito Volador +Teralito Psíquico +Teralito Insecto +Teralito Roca +Teralito Fantasma +Teralito Dragón +Teralito Siniestro +Teralito Acero +Teralito Hada +Energía Potenciadora +Escudo Habilidad +Amuleto Puro +Hierba Copia +Guante de Boxeo +Capa Furtiva +Dado Cargado + +Baguette +Mayonesa +Kétchup +Mostaza +Mantequilla +Mantequilla de Maní +Salsa Picante +Sal +Pimienta +Yogur +Crema Chantillí +Queso Crema +Jalea de Bayas +Mermelada +Aceite de Oliva +Vinagre +Especia Oculta Dulce +Especia Oculta Salada +Especia Oculta Ácida +Especia Oculta Amarga +Especia Oculta Picante +Lechuga +Tomate +Tomate Cherry +Pepino +Pepinillo +Cebolla +Cebolla Roja +Pimiento Verde +Pimiento Rojo +Pimiento Amarillo +Aguacate +Tocino +Jamón +Jamón Serrano +Chorizo +Salchicha Sazonada +Hamburguesa +Surimi de Klawf +Filete Ahumado +Filete Frito +Huevo +Tortilla de Papas +Tofu +Arroz +Fideos +Ensalada de Papa +Queso +Plátano +Fresa +Manzana +Kiwi +Piña +Jalapeño +Rábano Picante +Curry en Polvo +Wasabi +Berros +Albahaca + + + + + + + + + +Colmillo de Venonat +Tierra de Diglett +Pelaje de Meowth +Plumaje de Psyduck +Pelaje de Mankey +Pelaje de Growlithe +Garra de Slowpoke +Tornillo de Magnemite +Toxinas de Grimer +Perla de Shellder +Gas de Gastly +Pelaje de Drowzee +Electricidad de Voltorb +Garra de Scyther +Pelo de Tauros +Escama de Magikarp +Baba de Ditto +Pelaje de Eevee +Escama de Dratini +Pelaje de Pichu +Pelusa de Igglybuff +Lana de Mareep +Hoja de Hoppip +Hoja de Sunkern +Tesoro de Murkrow +Lágrima de Misdreavus +Pelaje de Girafarig +Corteza de Pineco +Escama de Dunsparce +Púa de Qwilfish +Garra de Heracross +Garra de Sneasel +Garra de Teddiursa +Paquete de Delibird +Colmillo de Houndour +Uña de Phanpy +Pelo de Stantler +Garra de Larvitar +Pluma de Wingull +Pertenencia de Ralts +Néctar de Surskit +Esporas de Shroomish +Pelaje de Slakoth +Sudor de Makuhita +Pelaje de Azurill +Gema de Sableye +Sudor de Meditite +Baba de Gulpin +Lava de Numel +Carbón de Torkoal +Perla de Spoink +Espina de Cacnea +Pelusa de Swablu +Garra de Zangoose +Colmillo de Seviper +Baba de Barboach +Retazo de Shuppet +Hoja de Tropius +Pelaje de Snorunt +Escama de Luvdisc +Escama de Bagon +Pluma de Starly +Caparazón de Kricketot +Colmillo de Shinx +Miel de Combee +Pelaje de Pachirisu +Pelaje de Buizel +Baba de Shellos +Gas de Drifloon +Pelaje de Stunky +Fragmento de Bronzor +Lágrima de Bonsly +Pertenencia de Happiny +Fragmento de Spiritomb +Escama de Gible +Pelaje de Riolu +Arena de Hippopotas +Toxinas de Croagunk +Escama de Finneon +Baya de Snover +Electricidad de Rotom +Hoja de Petilil +Colmillo de Basculin +Garra de Sandile +Pelaje de Zorua +Pestaña de Gothita +Pelo de Deerling +Esporas de Foongus +Baba de Alomomola +Baba de Tynamo +Escama de Axew +Pelaje de Cubchoo +Hielo de Cryogonal +Cuchilla de Pawniard +Pluma de Rufflet +Escama de Deino +Pelusa de Larvesta +Pluma de Fletchling +Polvo de Scatterbug +Mechón de Litleo +Polen de Flabébé +Hoja de Skiddo +Alga de Skrelp +Pinza de Clauncher +Plumaje de Hawlucha +Pelaje de Dedenne +Baba de Goomy +Llave de Klefki +Hielo de Bergmite +Pelaje de Noibat +Pelaje de Yungoos +Caparazón de Crabrawler +Pluma de Oricorio +Roca de Rockruff +Aguijón de Mareanie +Lodo de Mudbray +Hoja de Fomantis +Gas de Salandit +Sudor de Bounsweet +Pelaje de Oranguru +Pelaje de Passimian +Arena de Sandygast +Garra de Komala +Retazo de Mimikyu +Diente de Bruxish +Garra de Chewtle +Pelaje de Skwovet +Escama de Arrokuda +Pluma de Rookidee +Electricidad de Toxel +Sudor de Falinks +Óxido de Cufant +Carbón de Rolycoly +Arena de Silicobra +Pelaje de Indeedee +Púa de Pincurchin +Hilo de Snom +Pelo de Impidimp +Jugo de Applin +Fragmento de Sinistea +Pertenencia de Hatenna +Roca de Stonjourner +Plumaje de Eiscue +Polvo de Dreepy + + + +Pelo de Lechonk +Hilo de Tarountula +Garra de Nymble +Lodo de Rellor +Cera de Greavard +Plumaje de Flittle +Arena de Wiglett +Bigote de Dondozo +Carne de Veluza +Baba de Finizen +Aceite de Smoliv +Semilla de Capsakid +Baba de Tadbulb +Gas de Varoom +Óxido de Orthworm +Pelaje de Tandemaus +Grasa de Cetoddle +Escama de Frigibax +Escama de Tatsugiri +Escama de Cyclizar +Pelaje de Pawmi + + +Pluma de Wattrel +Pluma de Bombirdier +Pluma de Squawkabilly +Plumaje de Flamigo +Pinza de Klawf +Sal de Nacli +Cristal de Glimmet +Tinta de Shroodle +Pelaje de Fidough +Colmillo de Maschiff +Rama de Bramblin +Moneda de Gimmighoul + + + + + + + + + + + + + + + + + + +Pelo de Tinkatink +Hollín de Charcadet +Membrana de Toedscool +Baba de Wooper +MT100 +MT101 +MT102 +MT103 +MT104 +MT105 +MT106 +MT107 +MT108 +MT109 +MT110 +MT111 +MT112 +MT113 +MT114 +MT115 +MT116 +MT117 +MT118 +MT119 +MT120 +MT121 +MT122 +MT123 +MT124 +MT125 +MT126 +MT127 +MT128 +MT129 +MT130 +MT131 +MT132 +MT133 +MT134 +MT135 +MT136 +MT137 +MT138 +MT139 +MT140 +MT141 +MT142 +MT143 +MT144 +MT145 +MT146 +MT147 +MT148 +MT149 +MT150 +MT151 +MT152 +MT153 +MT154 +MT155 +MT156 +MT157 +MT158 +MT159 +MT160 +MT161 +MT162 +MT163 +MT164 +MT165 +MT166 +MT167 +MT168 +MT169 +MT170 +MT171 +MT172 +MT173 +MT174 +MT175 +MT176 +MT177 +MT178 +MT179 +MT180 +MT181 +MT182 +MT183 +MT184 +MT185 +MT186 +MT187 +MT188 +MT189 +MT190 +MT191 +MT192 +MT193 +MT194 +MT195 +MT196 +MT197 +MT198 +MT199 +MT200 +MT201 +MT202 +MT203 +MT204 +MT205 +MT206 +MT207 +MT208 +MT209 +MT210 +MT211 +MT212 +MT213 +MT214 +MT215 +MT216 +MT217 +MT218 +MT219 +MT220 +MT221 +MT222 +MT223 +MT224 +MT225 +MT226 +MT227 +MT228 +MT229 + + + + + + + + + + + + + + + + + + + + + +Kit de Pícnic + +Termo Academia +Termo Academia +Termo Lunares +Termo Rayas +Termo Rombos +Taza Academia +Taza Academia +Taza Raya Vertical +Taza Lunares +Taza Flores +Mantel Academia +Mantel Academia +Mantel Pintoresco +Mantel Naturaleza +Mantel Espectral + +Pelota Academia +Pelota Academia +Pelota Marill +Pelota Ovillo +Pelota Cibernética +Palillo Oro +Palillo Plata +Palillo Bandera Roja +Palillo Bandera Azul +Palillo Pikachu +Palillo Pikaguiño +Palillo Eevee +Palillo Eevee Feliz +Palillo Bola Azul + +Armadura Auspiciosa +Distintivo de Líder + + +Termo Rosa +Termo Azul +Termo Amarillo +Termo Metal Rojo +Termo Metal Amarillo +Termo Metal Azul +Termo Plata +Taza Raya Horizontal +Taza Rombos +Taza Llamas +Taza Rosa +Taza Azul +Taza Amarilla +Taza Pikachu +Taza Eevee +Taza Slowpoke +Taza Plata +Pelota Pilates +Mantel Cuadros Ámbar +Mantel Cuadros Azul +Mantel Cuadros Rojo +Mantel Hierba Alta +Mantel Combate +Mantel Monstruoso +Mantel Rayas +Mantel Rombos +Mantel Lunares +Mantel Violeta +Mantel Menta +Mantel Beige +Mantel Amarillo +Mantel Azul +Mantel Rosa +Termo Oro +Termo Bronce +Taza Oro +Taza Bronce +Palillo Bola Verde +Palillo Bola Roja +Palillo Bengala +Palillo Heroico +Palillo Estrella +Palillo Corazón +Palillo Sombrilla +Palillo Flor Azul +Palillo Flor Naranja +Palillo Flor Rosa +Plato Azul +Plato Verde +Plato Naranja +Plato Rojo +Plato Blanco +Plato Amarillo +Pluma Feérica +Manzana Empalagosa +Cuenco Mediocre +Cuenco Exquisito +Máscara Turquesa +Máscara Cimiento +Máscara Fuente +Máscara Horno +Tarjeta Chic Verde +Fragmento de Cristal +Mochi Vigor +Mochi Músculo +Mochi Aguante +Mochi Intelecto +Mochi Mente +Mochi Ímpetu +Sillas Simples +Sillas Academia +Sillas Academia +Sillas Pintorescas +Sillas Naturaleza +Sillas Espectrales +Sillas Cuadros Ámbares +Sillas Cuadros Azules +Sillas Cuadros Rojas +Sillas Hierba Alta +Sillas Combate +Sillas Monstruosas +Sillas Rayas +Sillas Rombos +Sillas Lunares +Sillas Violetas +Sillas Menta +Sillas Beige +Sillas Amarillas +Sillas Azules +Sillas Rosas +Colmillo de Ekans +Garra de Sandshrew +Pelaje de Cleffa +Pelaje de Vulpix +Baba de Poliwag +Liana de Bellsprout +Fragmento de Geodude +Gas de Koffing +Colmillo de Munchlax +Pelaje de Sentret +Pluma de Hoothoot +Hilo de Spinarak +Pelo de Aipom +Aguijón de Yanma +Colmillo de Gligar +Lava de Slugma +Pelo de Swinub +Colmillo de Poochyena +Hoja de Lotad +Tallo de Seedot +Fragmento de Nosepass +Líquido de Volbeat +Líquido de Illumise +Caparazón de Corphish +Escama de Feebas +Fragmento de Duskull +Fragmento de Chingling +Sudor de Timburr +Hoja de Sewaddle +Pluma de Ducklett +Hollín de Litwick +Garra de Mienfoo +Pluma de Vullaby +Gema de Carbink +Rama de Phantump +Hilo de Grubbin +Polvo de Cutiefly +Escama de Jangmo-o +Plumaje de Cramorant +Semilla de Morpeko +Polvo de Poltchageist +Mochi Reinicio +Paloselfi Rotom +Amuleto Cristalino +Metal Compuesto +Tarjeta Chic Azul +Hoja de Oddish +Aguijón de Tentacool +Plumaje de Doduo +Pelaje de Seel +Cáscara de Exeggcute +Sudor de Tyrogue +Colmillo de Rhyhorn +Tinta de Horsea +Pelaje de Elekid +Pelo de Magby +Lágrima de Lapras +Fragmento de Porygon +Electricidad de Chinchou +Pelo de Snubbull +Pluma de Skarmory +Pintura de Smeargle +Pelaje de Plusle +Pelaje de Minun +Coraza de Trapinch +Garra de Beldum +Púa de Cranidos +Garra de Shieldon +Crin de Blitzle +Garra de Drilbur +Algodón de Cottonee +Sudor de Scraggy +Pelaje de Minccino +Gel de Solosis +Hilo de Joltik +Fragmento de Golett +Pelaje de Espurr +Tinta de Inkay +Pluma de Pikipek +Hilo de Dewpider +Flor de Comfey +Caparazón de Minior +Crema de Milcery +Óxido de Duraludon +Galleta Articuno +Galleta Zapdos +Galleta Moltres +Galleta Raikou +Galleta Entei +Galleta Suicune +Galleta Lugia +Galleta Ho-Oh +Galleta Latias +Galleta Latios +Galleta Kyogre +Galleta Groudon +Galleta Rayquaza +Galleta Cobalion +Galleta Terrakion +Galleta Virizion +Galleta Reshiram +Galleta Zekrom +Galleta Kyurem +Galleta Solgaleo +Galleta Lunala +Galleta Necrozma +Galleta Kubfu +Galleta Glastrier +Galleta Spectrier +Disco Índigo +Palillo Ígneo +Teralito Astral +Baya Duraz Mítica +Mantel Arándano +Sillas Arándano +Sincromisor +Meteorito +Libro Escarlata +Libro Púrpura +Libro de Brie +Semilla Dominio +Clefablita +Victreebelita +Starmita +Dragonitita +Meganiumita +Feraligatrita +Skarmorita +Froslassita + + +Emboarita +Excadrillita +Scolipedita +Scraftita +Eelektrossita +Chandelurita +Chesnaughtita +Delphoxita +Greninjanita +Pyroarita +Floettita +Malamarita +Barbaraclita +Dragalgita +Hawluchanita +Zygardita +Drampanita + +Falinksita +Llave Habitación 202 +Supergalette Luminalia +Llave Laboratorio A +Llave Laboratorio B +Llave Laboratorio C +Llave Laboratorio M +Llave Laboratorio X +Piedrita +Anillo Entrañable +Nariamuleto Autografiado +Basura Suculenta +Ramita Revitalizante +Cosas de Adira + + + + + + + + + + + + + + + + + +Megafragmento +Tornillo Colorido +Nariamuleto Rojo +Nariamuleto Rojo +Nariamuleto Rojo +Nariamuleto Dorado +Nariamuleto Dorado +Nariamuleto Dorado +Nariamuleto Rosa +Nariamuleto Rosa +Nariamuleto Rosa +Nariamuleto Verde +Nariamuleto Verde +Nariamuleto Verde +Nariamuleto Azul +Nariamuleto Azul +Nariamuleto Azul \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/items/text_Items_es.txt b/PKHeX.Core/Resources/text/items/text_Items_es.txt index 3a51abefc..abb647809 100644 --- a/PKHeX.Core/Resources/text/items/text_Items_es.txt +++ b/PKHeX.Core/Resources/text/items/text_Items_es.txt @@ -46,7 +46,7 @@ Ceniza Sagrada Más PS Proteína Hierro -Carburante +Carbohidratos Calcio Caramelo Raro Más PP @@ -62,7 +62,7 @@ Precisión X Ataque Especial X Defensa Especial X Pokémuñeco -Cola Skitty +Cola de Skitty Flauta Azul Flauta Amarilla Flauta Roja @@ -89,8 +89,8 @@ Seta Grande Perla Perla Grande Polvo Estelar -Trozo Estrella -Pepita +Trozo de Estrella +Pepita de Oro Escama Corazón Miel Abono Rápido @@ -123,10 +123,10 @@ Caja de Pokémon Botiquín Estuche de MT Tarro de Caramelos -Bolsillo Mejoras +Bolsillo de Mejoras Maleta -Bolsillo Captura -Bolsillo Combate +Bolsillo de Captura +Bolsillo de Combate (?) (?) (?) @@ -233,7 +233,7 @@ Huevo Suerte Periscopio Revest. Metálico Restos -Escama Dragón +Escama de Dragón Bola Luminosa Arena Fina Piedra Dura @@ -244,11 +244,11 @@ Imán Agua Mística Pico Afilado Flecha Venenosa -Antiderretir +Hielo Perpetuo Hechizo Cuchara Torcida Carbón -Colmillo Dragón +Colmillo de Dragón Pañuelo de Seda Mejora Cascabel Concha @@ -266,7 +266,7 @@ Pañuelo Amarillo Lupa Cinta Fuerte Gafas Especiales -Cinta Experto +Cinturón de Experto Refleluz Vidasfera Hierba Única @@ -291,7 +291,7 @@ Brazal Recio Cinto Recio Lente Recia Banda Recia -Franja Recia +Tobillera Recia Pesa Recia Muda Concha Raíz Grande @@ -450,7 +450,7 @@ Psydugadera Pokochera Bici Llave de la Suite -Carta Prof. Oak +Carta del Prof. Oak Pluma Lunar Carné de Socio Flauta Azur @@ -471,7 +471,7 @@ Bloc Unown Plantabayas Zahorí Tarjeta Azul -Cola Slowpoke +Cola de Slowpoke Cascabel Claro Llave Magnética Llave del Sótano @@ -503,33 +503,33 @@ Parque Ball Reproductor GB Cascabel Oleaje Caramelo Furia -Tarjeta Datos 01 -Tarjeta Datos 02 -Tarjeta Datos 03 -Tarjeta Datos 04 -Tarjeta Datos 05 -Tarjeta Datos 06 -Tarjeta Datos 07 -Tarjeta Datos 08 -Tarjeta Datos 09 -Tarjeta Datos 10 -Tarjeta Datos 11 -Tarjeta Datos 12 -Tarjeta Datos 13 -Tarjeta Datos 14 -Tarjeta Datos 15 -Tarjeta Datos 16 -Tarjeta Datos 17 -Tarjeta Datos 18 -Tarjeta Datos 19 -Tarjeta Datos 20 -Tarjeta Datos 21 -Tarjeta Datos 22 -Tarjeta Datos 23 -Tarjeta Datos 24 -Tarjeta Datos 25 -Tarjeta Datos 26 -Tarjeta Datos 27 +Tarjeta de Datos 01 +Tarjeta de Datos 02 +Tarjeta de Datos 03 +Tarjeta de Datos 04 +Tarjeta de Datos 05 +Tarjeta de Datos 06 +Tarjeta de Datos 07 +Tarjeta de Datos 08 +Tarjeta de Datos 09 +Tarjeta de Datos 10 +Tarjeta de Datos 11 +Tarjeta de Datos 12 +Tarjeta de Datos 13 +Tarjeta de Datos 14 +Tarjeta de Datos 15 +Tarjeta de Datos 16 +Tarjeta de Datos 17 +Tarjeta de Datos 18 +Tarjeta de Datos 19 +Tarjeta de Datos 20 +Tarjeta de Datos 21 +Tarjeta de Datos 22 +Tarjeta de Datos 23 +Tarjeta de Datos 24 +Tarjeta de Datos 25 +Tarjeta de Datos 26 +Tarjeta de Datos 27 Esfera Verde Cápsula Candado Prisma Rojo @@ -577,11 +577,11 @@ Regalosfera Ensueño Ball Pokéseñuelo Neceser -Cráneo Dragón +Cráneo de Dragón Seta Aroma -Maxipepita +Maxipepita de Oro Sarta de Perlas -Fragmento Cometa +Fragmento de Cometa Real de Cobre Real de Plata Real de Oro @@ -637,10 +637,10 @@ Acromáquina Objeto Perdido Objeto Perdido Espejo Veraz -Seguro Debilidad +Seguro de Debilidad Chaleco Asalto Holomisor -Carta Profesor +Carta del Profesor Patines Tabla Duende Cápsula Habilidad @@ -694,19 +694,19 @@ MT98 MT99 MT100 Pase de la Central -Mega-Aro +Megaaro Piedra Insólita Piedra Común -Vale Descuento +Vale de Descuento Llave del Ascensor Abono del TMV Emblema de Kalos Guía de Aventura Estatuilla Rara Portalentillas -Kit Maquillaje +Kit de Maquillaje Maleta -Crêpe Luminalia +Galette Luminalia Galleta Yantra Fósil Mandíbula Fósil Aleta @@ -720,7 +720,7 @@ Bici de Carreras Bici Acrobática Wailmegadera Piezas Devon -Saco Hollín +Saco de Hollín Llave del Sótano Kit de Pokécubos Carta a Máximo @@ -728,10 +728,10 @@ Ticket Eón Escáner Gafas Aislantes Meteorito -Ll. Habitación 1 -Ll. Habitación 2 -Ll. Habitación 4 -Ll. Habitación 6 +Llave Habitación 1 +Llave Habitación 2 +Llave Habitación 4 +Llave Habitación 6 Llave del Almacén Detector Devon Ticket del Barco @@ -763,7 +763,7 @@ Steelixita Pidgeotita Glalita Diancita -Vasija Castigo +Vasija de Castigo Megabrazalete Cameruptita Lopunnita @@ -841,7 +841,7 @@ Ash-Pikastal Z (?) Zurrón Caña -Máscara Profesor +Máscara del Profesor Festicupón Piedra Brillante Nerviosfera @@ -950,7 +950,7 @@ Poké Ball Ajena Cupón Eclosión Cupón Rebaja Cupón Botín -Cupón Exp +Cupón Experiencia Cupón Amistad Cupón Reclamo Cupón Sigilo @@ -1119,7 +1119,7 @@ Manzana Ácida Espray Bucal Mochila Escape Botas Gruesas -Seguro Fallo +Seguro de Fallo Servicio Raro Parasol Multiuso Caramelo Exp. XS @@ -1268,7 +1268,7 @@ Bici Rotom Amuleto Captura (?) Carta Ajada -Autógrafo Grupo +Autógrafo del Grupo Libro de Sonia (?) (?) @@ -1603,7 +1603,7 @@ Crin Negra Zanahoria Nívea Zanahoria Oscura Maxinium -Sem. Zanahoria +Semillas Zanahoria Parche Habilidad Riendas Unión Calmasfera Tiempo @@ -1647,7 +1647,7 @@ Pokémuñeca Bola Humareda Bola Ruidosa Bola Pegajosa -Trozo Estrella +Trozo de Estrella Cebo de Setas Hierba Repelente Cebo Meloso @@ -2555,4 +2555,81 @@ Sincromisor Meteorito Libro Escarlata Libro Púrpura -Libro de Brie \ No newline at end of file +Libro de Brie +Semilla Dominio +Clefablita +Victreebelita +Starmita +Dragonitita +Meganiumita +Feraligatrita +Skarmorita +Froslassita + + +Emboarita +Excadrillita +Scolipedita +Scraftita +Eelektrossita +Chandelurita +Chesnaughtita +Delphoxita +Greninjanita +Pyroarita +Floettita +Malamarita +Barbaraclita +Dragalgita +Hawluchanita +Zygardita +Drampanita + +Falinksita +Llave Habitación 202 +Supergalette Luminalia +Llave Laboratorio A +Llave Laboratorio B +Llave Laboratorio C +Llave Laboratorio M +Llave Laboratorio X +Piedrecita +Anillo Preciado +Amuleto de Naria Firmado +Basura Suculenta +Ramita Revitalizante +Enseres de Bárbara + + + + + + + + + + + + + + + + + +Megaesquirla +Tornillo Colorido +Amuleto de Naria Rojo +Amuleto de Naria Rojo +Amuleto de Naria Rojo +Amuleto de Naria Dorado +Amuleto de Naria Dorado +Amuleto de Naria Dorado +Amuleto de Naria Rosa +Amuleto de Naria Rosa +Amuleto de Naria Rosa +Amuleto de Naria Verde +Amuleto de Naria Verde +Amuleto de Naria Verde +Amuleto de Naria Azul +Amuleto de Naria Azul +Amuleto de Naria Azul diff --git a/PKHeX.Core/Resources/text/items/text_Items_fr.txt b/PKHeX.Core/Resources/text/items/text_Items_fr.txt index 3facd0884..53bf683db 100644 --- a/PKHeX.Core/Resources/text/items/text_Items_fr.txt +++ b/PKHeX.Core/Resources/text/items/text_Items_fr.txt @@ -2555,4 +2555,81 @@ Synchrotron Météorite Livre Écarlate Livre Violet -Livre de Bria \ No newline at end of file +Livre de Bria +Graine Maîtrise +Mélodelfite +Empiflorite +Starossite +Dracolossite +Méganiumite +Aligatueurite +Airmurite +Momartikite + + +Roitiflamite +Minotaupite +Brutapodite +Baggaïdite +Ohmassacrite +Lugulabrite +Blindépiquite +Goupelinite +Amphinolite +Néméliosite +Floettite +Sepiatrocite +Golgopathite +Kravarekite +Brutalibrite +Zygardite +Draïeulite + +Hexadronite +Clé de la Chambre 202 +Galette de Choc +Passe du Labo A +Passe du Labo B +Passe du Labo C + + +Caillou +Bague Souvenirs +Naricâline Dédicacée +Déchets Alléchants +Rameau de Vie +Sacoche de Rudi + + + + + + + + + + + + + + + + + +Méga-Fragment +Vis Colorée +Naricâline Rouge +Naricâline Rouge +Naricâline Rouge +Naricâline Dorée +Naricâline Dorée +Naricâline Dorée +Naricâline Rose +Naricâline Rose +Naricâline Rose +Naricâline Verte +Naricâline Verte +Naricâline Verte +Naricâline Bleue +Naricâline Bleue +Naricâline Bleue \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/items/text_Items_it.txt b/PKHeX.Core/Resources/text/items/text_Items_it.txt index 3daa3a775..07d5fd8a1 100644 --- a/PKHeX.Core/Resources/text/items/text_Items_it.txt +++ b/PKHeX.Core/Resources/text/items/text_Items_it.txt @@ -2555,4 +2555,81 @@ Sincronizzatore Meteorite Libro scarlatto Libro violetto -Libro di Rea \ No newline at end of file +Libro di Rea +Seme padronanza +Clefablite +Victreebelite +Starmite +Dragonitite +Meganiumite +Feraligatrite +Skarmorite +Froslassite + + +Emboarite +Excadrillite +Scolipedite +Scraftite +Eelektrossite +Chandelurite +Chesnaughtite +Delphoxite +Greninjite +Pyroarite +Floettite +Malamarite +Barbaraclite +Dragalgite +Hawluchite +Zygardite +Drampite + +Falinksite +Chiave stanza 202 +Pan di Lumi speciale +Chiave laboratorio A +Chiave laboratorio B +Chiave laboratorio C + + +Sasso +Anello prezioso +Peluche autografato +Rifiuti prelibati +Rametto energizzante +Sacca di Cerril + + + + + + + + + + + + + + + + + +Megaframmento +Vite colorata +Peluche di Canary rosso +Peluche di Canary rosso +Peluche di Canary rosso +Peluche di Canary oro +Peluche di Canary oro +Peluche di Canary oro +Peluche di Canary rosa +Peluche di Canary rosa +Peluche di Canary rosa +Peluche di Canary verde +Peluche di Canary verde +Peluche di Canary verde +Peluche di Canary blu +Peluche di Canary blu +Peluche di Canary blu \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/items/text_Items_ja.txt b/PKHeX.Core/Resources/text/items/text_Items_ja.txt index 88648a542..79762f1fd 100644 --- a/PKHeX.Core/Resources/text/items/text_Items_ja.txt +++ b/PKHeX.Core/Resources/text/items/text_Items_ja.txt @@ -2555,4 +2555,81 @@ Bステンレスボトル いんせき スカーレットブック バイオレットブック -ゼロの秘宝 \ No newline at end of file +ゼロの秘宝 +かいでんのタネ +ピクシナイト +ウツボットナイト +スターミナイト +カイリュナイト +メガニウムナイト +オーダイルナイト +エアームドナイト +ユキメノコナイト + + +エンブオナイト +ドリュウズナイト +ペンドラナイト +ズルズキナイト +シビルドナイト +シャンデラナイト +ブリガロナイト +マフォクシナイト +ゲッコウガナイト +カエンジシナイト +フラエッテナイト +カラマネナイト +ガメノデスナイト +ドラミドナイト +ルチャブルナイト +ジガルデナイト +ジジーロナイト + +タイレーツナイト +202ごうしつのカギ +すごいミアレガレット +ラボのカードキーA +ラボのカードキーB +ラボのカードキーC + + +いしころ +おもいでのゆびわ +サインいりのぬい +おいしいゴミ +げんきのこえだ +デウロのわすれもの + + + + + + + + + + + + + + + + + +メガカケラ +カラフルなネジ +あかのカナリィぬい +あかのカナリィぬい +あかのカナリィぬい +きんのカナリィぬい +きんのカナリィぬい +きんのカナリィぬい +ピンクのカナリィぬい +ピンクのカナリィぬい +ピンクのカナリィぬい +みどりのカナリィぬい +みどりのカナリィぬい +みどりのカナリィぬい +あおのカナリィぬい +あおのカナリィぬい +あおのカナリィぬい \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/items/text_Items_ko.txt b/PKHeX.Core/Resources/text/items/text_Items_ko.txt index 89c2dd748..b7fe55bb6 100644 --- a/PKHeX.Core/Resources/text/items/text_Items_ko.txt +++ b/PKHeX.Core/Resources/text/items/text_Items_ko.txt @@ -2555,4 +2555,81 @@ B 스테인리스 보틀 운석 스칼렛북 바이올렛북 -제로의 비보 \ No newline at end of file +제로의 비보 +숙달의씨 +픽시나이트 +우츠보트나이트 +아쿠스타나이트 +망나뇽나이트 +메가니움나이트 +장크로다일나이트 +무장조나이트 +눈여아나이트 + + +염무왕나이트 +몰드류나이트 +펜드라나이트 +곤율거니나이트 +저리더프나이트 +샹델라나이트 +브리가론나이트 +마폭시나이트 +개굴닌자나이트 +화염레오나이트 +플라엣테나이트 +칼라마네로나이트 +거북손데스나이트 +드래캄나이트 +루차불나이트 +지가르데나이트 +할비롱나이트 + +대여르나이트 +202호실열쇠 +대단한미르갈레트 +랩카드키A +랩카드키B +랩카드키C + + +돌멩이 +추억의반지 +친필사인인형 +맛있는쓰레기 +기력의잔가지 +루디의 잊은물건 + + + + + + + + + + + + + + + + + +메가조각 +컬러풀한나사 +빨강카나리인형 +빨강카나리인형 +빨강카나리인형 +금색카나리인형 +금색카나리인형 +금색카나리인형 +분홍카나리인형 +분홍카나리인형 +분홍카나리인형 +초록카나리인형 +초록카나리인형 +초록카나리인형 +파랑카나리인형 +파랑카나리인형 +파랑카나리인형 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/items/text_Items_zh-Hans.txt b/PKHeX.Core/Resources/text/items/text_Items_zh-Hans.txt index 71157f596..00f8c631b 100644 --- a/PKHeX.Core/Resources/text/items/text_Items_zh-Hans.txt +++ b/PKHeX.Core/Resources/text/items/text_Items_zh-Hans.txt @@ -2363,7 +2363,7 @@ 伊布水杯 呆呆兽水杯 银钛水杯 -瑜珈球 +瑜伽球 黄色格子桌巾 蓝色格子桌巾 红色格子桌巾 @@ -2555,4 +2555,81 @@ 陨石 朱之书 紫之书 -零之秘宝 \ No newline at end of file +零之秘宝 +精通种子 +皮可西进化石 +大食花进化石 +宝石海星进化石 +快龙进化石 +大竺葵进化石 +大力鳄进化石 +盔甲鸟进化石 +雪妖女进化石 + + +炎武王进化石 +龙头地鼠进化石 +蜈蚣王进化石 +头巾混混进化石 +麻麻鳗鱼王进化石 +水晶灯火灵进化石 +布里卡隆进化石 +妖火红狐进化石 +甲贺忍蛙进化石 +火炎狮进化石 +花叶蒂进化石 +乌贼王进化石 +龟足巨铠进化石 +毒藻龙进化石 +摔角鹰人进化石 +基格尔德进化石 +老翁龙进化石 + +列阵兵进化石 +202号客房的钥匙 +厉害密阿雷格雷派饼 +研究所的钥匙卡A +研究所的钥匙卡B +研究所的钥匙卡C + + +小石头 +纪念戒指 +签名玩偶 +美味垃圾 +活力小树枝 +玳萝的遗忘物 + + + + + + + + + + + + + + + + + +超级碎片 +彩色螺丝 +红色卡娜莉玩偶 +红色卡娜莉玩偶 +红色卡娜莉玩偶 +金色卡娜莉玩偶 +金色卡娜莉玩偶 +金色卡娜莉玩偶 +粉红色卡娜莉玩偶 +粉红色卡娜莉玩偶 +粉红色卡娜莉玩偶 +绿色卡娜莉玩偶 +绿色卡娜莉玩偶 +绿色卡娜莉玩偶 +蓝色卡娜莉玩偶 +蓝色卡娜莉玩偶 +蓝色卡娜莉玩偶 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/items/text_Items_zh-Hant.txt b/PKHeX.Core/Resources/text/items/text_Items_zh-Hant.txt index 2a67989e5..a90511153 100644 --- a/PKHeX.Core/Resources/text/items/text_Items_zh-Hant.txt +++ b/PKHeX.Core/Resources/text/items/text_Items_zh-Hant.txt @@ -2363,7 +2363,7 @@ 伊布水杯 呆呆獸水杯 銀鈦水杯 -瑜珈球 +瑜伽球 黃色格子桌巾 藍色格子桌巾 紅色格子桌巾 @@ -2555,4 +2555,81 @@ 隕石 朱之書 紫之書 -零之秘寶 \ No newline at end of file +零之秘寶 +精通種子 +皮可西進化石 +大食花進化石 +寶石海星進化石 +快龍進化石 +大竺葵進化石 +大力鱷進化石 +盔甲鳥進化石 +雪妖女進化石 + + +炎武王進化石 +龍頭地鼠進化石 +蜈蚣王進化石 +頭巾混混進化石 +麻麻鰻魚王進化石 +水晶燈火靈進化石 +布里卡隆進化石 +妖火紅狐進化石 +甲賀忍蛙進化石 +火炎獅進化石 +花葉蒂進化石 +烏賊王進化石 +龜足巨鎧進化石 +毒藻龍進化石 +摔角鷹人進化石 +基格爾德進化石 +老翁龍進化石 + +列陣兵進化石 +202號客房的鑰匙 +厲害密阿雷格雷派餅 +研究所的鑰匙卡A +研究所的鑰匙卡B +研究所的鑰匙卡C + + +小石頭 +紀念戒指 +簽名玩偶 +美味垃圾 +活力小樹枝 +玳蘿的遺忘物 + + + + + + + + + + + + + + + + + +超級碎片 +彩色螺絲 +紅色卡娜莉玩偶 +紅色卡娜莉玩偶 +紅色卡娜莉玩偶 +金色卡娜莉玩偶 +金色卡娜莉玩偶 +金色卡娜莉玩偶 +粉紅色卡娜莉玩偶 +粉紅色卡娜莉玩偶 +粉紅色卡娜莉玩偶 +綠色卡娜莉玩偶 +綠色卡娜莉玩偶 +綠色卡娜莉玩偶 +藍色卡娜莉玩偶 +藍色卡娜莉玩偶 +藍色卡娜莉玩偶 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_de.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_de.txt new file mode 100644 index 000000000..4a88c8c8b --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_de.txt @@ -0,0 +1,236 @@ +---------- + +Mysteriöser Ort + +Ferner Ort + +Zone Verte +Zone Cyan +Zone Rose +Zone Rouge +Zone Jaune +Zentral-Plaza +Frühlingsallee +Sommerallee +Herbstallee +Winterallee +Jahreszeitenkanal +Boulevard Vert +Boulevard Vert +Südring +Südring +Verte-Bezirk 1 +Verte-Bezirk 3 +Nasswasserweg +Verte-Bezirk 6 +Verte-Bezirk 7 +Bahnhofsplatz Illumina Süd +Verte-Bezirk 2 +Verte-Bezirk 4 +Verte-Bezirk 5 +Verte-Bezirk 8 +Verte-Bezirk 9 +Place Verte +Boulevard Cyan +Boulevard Cyan +Südring +Südring +Cyan-Bezirk 1 +Cyan-Bezirk 3 +Bummelpark +Cyan-Bezirk 5 +Cyan-Bezirk 7 +Cyan-Bezirk 2 +Cyan-Bezirk 4 +Espace Vide +Cyan-Bezirk 6 +Cyan-Bezirk 8 +Cyan-Bezirk 9 +Cyan-Bezirk 10 +Place Cyan +Boulevard Rose +Boulevard Rose +Südring +Nordring +Rose-Bezirk 1 +Rose-Bezirk 3 +Rose-Bezirk 5 +Rose-Bezirk 6 +Illumina-Umspannwerk +Rose-Bezirk 2 +Rose-Bezirk 4 +Rose-Bezirk 7 +Quazar Corporation +Rose-Bezirk 8 +Rose-Bezirk 9 +Place Rose +Boulevard Rouge +Boulevard Rouge +Nordring +Nordring +Rouge-Bezirk 1 +Rouge-Bezirk 3 +Rouge-Bezirk 4 +Rouge-Bezirk 5 +Rouge-Bezirk 7 +Rouge-Bezirk 2 +Académie Étoile +Rouge-Bezirk 6 +Friedhof Bonne Nuit +Rouge-Bezirk 8 +Place Rouge +Boulevard Jaune +Boulevard Jaune +Nordring +Nordring +Jaune-Bezirk 1 +Jaune-Bezirk 3 +Jaune-Bezirk 4 +Jaune-Bezirk 5 +Jaune-Bezirk 7 +Jaune-Bezirk 8 +Jaune-Bezirk 2 +Kanalpromenade +Jaune-Bezirk 6 +Jaune-Bezirk 9 +Jaune-Bezirk 10 +Jaune-Bezirk 11 +Jaune-Bezirk 12 +Place Jaune +Boulevard du Vent +Illumina-Kunstmuseum +Pokémon-Center (Verte) +Hotel Z +Pokémon-Labor +Prismaturm +LeBelle-Büro +Quazar Corporation +Baufirma Racine +Place Verte +Bahnhof Illumina Süd +Place Cyan +Corrosio-Clansitz +Pokémon-Center (Cyan) +Pokémon-Center (Frühlingsallee) +Place Rose +Bistro Flordelis +Pokémon-Center (Rose) +Pokémon-Center (Place Rose) +Place Rouge +Grand Hôtel Pique Faîne +Pokémon-Center (Rouge) +Pokémon-Center (Zentral-Plaza) +Place Jaune +Dojo der Gerechten +Pokémon-Center (Jaune) +Pokémon-Center (Winterallee) +Friseursalon +Stein-Boutique +Pokéball-Boutique +GEAR +Maison Très Chique +Restaurant Solala +Café Twister +Café à la Mode +Konnex-Café +Empty Room (Abandoned Building) +Sewer Entrance +Cutting Edge +Bravely +Le Dessert +Marché Cyan +Inner Space +Backspin +Sportsfreund Cyan +Defog Vision +Equip +Style-Salon +Café Wauwau +Café Soleil +Café Fokus +Illumina-Kanalisation +Café Spielstunde +Café Freestyle +Café Adonis +Café Coucou +ZéroHuit-15 +Énergétique +Paston +Wams im Glück +Pinceau +Heia Bubú +SneakPeak +Marquage +Chichiffon Chic +Chichiffon Pretty +Chichiffon Sporty +Eternuit +1G-PAKT +Minuit Rite +Le Bon Goût +Lichteloh +Pomp & Ös +CINEAST +DENSOKU Illumina +Schuhbidu +Prêt à Tête +Chichiffon Cute +ReFined +SUBATOMIC +SUBATOMIC 4 +Non + Ultra +Kleiderkiste +Sportsfreund Rouge +Schuhschrank +Tornado +Restaurant chez Norme +Sushi-Wok +Restaurant de Luxe +Illumina-Kanalisation +Café Ami +Café Ultimo +Café Nachdreh +Café Bataille +Wildsektor 17 +Wildsektor 1 +Wildsektor 2 +Wildsektor 12 +Wildsektor 10 +Wildsektor 5 +Wildsektor 16 +Wildsektor 14 +Wildsektor 9 +Wildsektor 18 +Wildsektor 7 +Wildsektor 13 +Wildsektor 4 +Wildsektor 3 +Wildsektor 15 +Wildsektor 19 +Wildsektor 6 +Wildsektor 11 +Wildsektor 8 +Wildsektor 20 +Kampfsektor +Passage Bonheur +Passage Ombre +Galerie Clair de Lune +Passage Palais +Dojo der Gerechten +Hotel Z +Baufirma Racine +Grand Hôtel Pique Faîne +Corrosio-Clansitz +Bahnhof Illumina Süd +Quazar Corporation +Restaurant Solala +Restaurant chez Norme +Restaurant de Luxe +Sushi-Wok +LeBelle-Büro +Pokémon-Labor +Geschäftsgebäude +Illumina-Kunstmuseum +Bistro Flordelis +Labor von Flordelis +Kanalisation \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_en.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_en.txt new file mode 100644 index 000000000..378768074 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_en.txt @@ -0,0 +1,236 @@ +—————— + +Mystery Zone + +Faraway place + +Vert District +Bleu District +Magenta District +Rouge District +Jaune District +Centrico Plaza +Vernal Avenue +Estival Avenue +Autumnal Avenue +Hibernal Avenue +Saison Canal +Vert Street +Vert Street +South Boulevard +South Boulevard +Vert Sector 1 +Vert Sector 3 +Coulant Waterway +Vert Sector 6 +Vert Sector 7 +Station Front +Vert Sector 2 +Vert Sector 4 +Vert Sector 5 +Vert Sector 8 +Vert Sector 9 +Vert Plaza +Bleu Street +Bleu Street +South Boulevard +South Boulevard +Bleu Sector 1 +Bleu Sector 3 +Aymlis Park +Bleu Sector 5 +Bleu Sector 7 +Bleu Sector 2 +Bleu Sector 4 +Espace Vide +Bleu Sector 6 +Bleu Sector 8 +Bleu Sector 9 +Bleu Sector 10 +Bleu Plaza +Magenta Street +Magenta Street +South Boulevard +North Boulevard +Magenta Sector 1 +Magenta Sector 3 +Magenta Sector 5 +Magenta Sector 6 +Electrical Substation +Magenta Sector 2 +Magenta Sector 4 +Magenta Sector 7 +Quasartico Inc. +Magenta Sector 8 +Magenta Sector 9 +Magenta Plaza +Rouge Street +Rouge Street +North Boulevard +North Boulevard +Rouge Sector 1 +Rouge Sector 3 +Rouge Sector 4 +Rouge Sector 5 +Rouge Sector 7 +Rouge Sector 2 +Académie Étoile +Rouge Sector 6 +Dormez Bien Cemetery +Rouge Sector 8 +Rouge Plaza +Jaune Street +Jaune Street +North Boulevard +North Boulevard +Jaune Sector 1 +Jaune Sector 3 +Jaune Sector 4 +Jaune Sector 5 +Jaune Sector 7 +Jaune Sector 8 +Jaune Sector 2 +Saison Canalside +Jaune Sector 6 +Jaune Sector 9 +Jaune Sector 10 +Jaune Sector 11 +Jaune Sector 12 +Jaune Plaza +Promenade du Vent +Lumiose Museum +Vert Pokémon Center +Hotel Z +Pokémon Research Lab +Prism Tower +Looker Bureau +Quasartico Inc. +Racine Construction +Vert Plaza +Gare de Lumiose +Bleu Plaza +Rust Syndicate Office +Bleu Pokémon Center +Vernal Pokémon Center +Magenta Plaza +Lysandre Café +Magenta Pokémon Center +Magenta Plaza Pokémon Center +Rouge Plaza +Hotel Richissime +Rouge Pokémon Center +Centrico Pokémon Center +Jaune Plaza +Justice Dojo +Jaune Pokémon Center +Hibernal Pokémon Center +Hair Salon +Stone Emporium +Poké Ball Boutique +Changing Gears +Boutique Couture +Restaurant Le Nah +Café Cyclone +Café Classe +Café Introversion +Empty Room (Abandoned Building) +Sewer Entrance +Fresh Fits +BRAVELY +Dessert du Moment +Marché Bleu +In the Zone +Kickspin +Triathlon Bleu +DEFOG Eyewear +Équipement +Coiffure Clips +Café Woof +Café Soleil +Shutterbug Café +Lumiose Sewers +Café Pokémon-Amie +Café Rouleau +Café Gallant +Café Triste +The Usual +Énergie +Le Passe-temps +Porte-Chance +Pinceau +Naptime +Soil and Sneaks +Marquage +Glammor Girli +Glammor Pretti +Glammor Sporti +NIGHTSIDE +Bundle Up +Midnight Rite +Mode Mature +Wisp +Mode Magnifique +FILMFAN +DENSOKU Lumiose +Les Chaussures +Atelier Heads +Glammor Cuti +Kikonashi +SUBATOMIC +SUBATOMIC 4 +Masterpiece +Le Pays des Vêtements +Triathlon Rouge +Le Pays des Pieds +La Tornade +Restaurant Le Yeah +Sushi High Roller +Restaurant Le Wow +Lumiose Sewers +Café Kizuna +Café Ultimo +Café Action! +Café Bataille +Wild Zone 17 +Wild Zone 1 +Wild Zone 2 +Wild Zone 12 +Wild Zone 10 +Wild Zone 5 +Wild Zone 16 +Wild Zone 14 +Wild Zone 9 +Wild Zone 18 +Wild Zone 7 +Wild Zone 13 +Wild Zone 4 +Wild Zone 3 +Wild Zone 15 +Wild Zone 19 +Wild Zone 6 +Wild Zone 11 +Wild Zone 8 +Wild Zone 20 +Battle Zone +Passage de la Félicité +Passage Ombragé +Galerie de la Lune +Passage du Palais +Justice Dojo +Hotel Z +Racine Construction +Hotel Richissime +Rust Syndicate Office +Gare de Lumiose +Quasartico Inc. +Restaurant Le Nah +Restaurant Le Yeah +Restaurant Le Wow +Sushi High Roller +Looker Bureau +Pokémon Research Lab +Old Building +Lumiose Museum +Lysandre Café +Lysandre Labs +The Sewers \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_es-419.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_es-419.txt new file mode 100644 index 000000000..ebd05a221 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_es-419.txt @@ -0,0 +1,236 @@ +- + +Lugar misterioso + +Lugar lejano + +Distrito Verde +Distrito Azul +Distrito Rosa +Distrito Rojo +Distrito Amarillo +Plaza Central +Avenida Primavera +Avenida Verano +Avenida Otoño +Avenida Invierno +Canal Saison +Gran Avenida Verde +Gran Avenida Verde +Bulevar Sur +Bulevar Sur +Distrito Verde: sector 1 +Distrito Verde: sector 3 +Canal Affluer +Distrito Verde: sector 6 +Distrito Verde: sector 7 +Estación Luminalia Sur +Distrito Verde: sector 2 +Distrito Verde: sector 4 +Distrito Verde: sector 5 +Distrito Verde: sector 8 +Distrito Verde: sector 9 +Plaza Verde +Gran Avenida Azul +Gran Avenida Azul +Bulevar Sur +Bulevar Sur +Distrito Azul: sector 1 +Distrito Azul: sector 3 +Parque Obnúbilo +Distrito Azul: sector 5 +Distrito Azul: sector 7 +Distrito Azul: sector 2 +Distrito Azul: sector 4 +Rincón Meh +Distrito Azul: sector 6 +Distrito Azul: sector 8 +Distrito Azul: sector 9 +Distrito Azul: sector 10 +Plaza Azul +Gran Avenida Rosa +Gran Avenida Rosa +Bulevar Sur +Bulevar Norte +Distrito Rosa: sector 1 +Distrito Rosa: sector 3 +Distrito Rosa: sector 5 +Distrito Rosa: sector 6 +Subestación Eléctrica +Distrito Rosa: sector 2 +Distrito Rosa: sector 4 +Distrito Rosa: sector 7 +Quastelar S. A. +Distrito Rosa: sector 8 +Distrito Rosa: sector 9 +Plaza Rosa +Gran Avenida Roja +Gran Avenida Roja +Bulevar Norte +Bulevar Norte +Distrito Rojo: sector 1 +Distrito Rojo: sector 3 +Distrito Rojo: sector 4 +Distrito Rojo: sector 5 +Distrito Rojo: sector 7 +Distrito Rojo: sector 2 +Escuela Andrómeda +Distrito Rojo: sector 6 +Cementerio Bonnuit +Distrito Rojo: sector 8 +Plaza Roja +Gran Avenida Amarilla +Gran Avenida Amarilla +Bulevar Norte +Bulevar Norte +Distrito Amarillo: sector 1 +Distrito Amarillo: sector 3 +Distrito Amarillo: sector 4 +Distrito Amarillo: sector 5 +Distrito Amarillo: sector 7 +Distrito Amarillo: sector 8 +Distrito Amarillo: sector 2 +Paseo Saison +Distrito Amarillo: sector 6 +Distrito Amarillo: sector 9 +Distrito Amarillo: sector 10 +Distrito Amarillo: sector 11 +Distrito Amarillo: sector 12 +Plaza Amarilla +Bulevar de la Brisa +Museo de Luminalia +Centro Pokémon del Distrito Verde +Hotel Z +Laboratorio Pokémon +Torre Prisma +Looker & Cía. +Quastelar S. A. +Construcciones Radix +Plaza Verde +Estación Luminalia Sur +Plaza Azul +Sede del Clan Corrosión +Centro Pokémon del Distrito Azul +Centro Pokémon de la Avenida Primavera +Plaza Rosa +Café Lysandre +Centro Pokémon del Distrito Rosa +Centro Pokémon de la Plaza Rosa +Plaza Roja +Gran Hotel Ricachilton +Centro Pokémon del Distrito Rojo +Centro Pokémon de la Plaza Central +Plaza Amarilla +Dojo del Círculo Justiciero +Centro Pokémon del Distrito Amarillo +Centro Pokémon de la Avenida Invierno +Peluquería +Boutique de la Piedra +Boutique Pokébola +Accessoire +Boutique Très Chic +Restaurante Fulanito Detal +Café Vorágine +Cafetería Prêt-à-Sorber +Café Rubor +Empty Room (Abandoned Building) +Sewer Entrance +Jar-cor +Héros +PosTrès Bon +Galerías Azul +Internaria +RitmiK +Triatlón Azul +Óptica Defog +Paramie +Salón Camerino +Café Guau +Café Soleil +Cafetería Enfoque +Alcantarillas de Luminalia +Café Recreo +Café Sobre Ruedas +Café Galanes +Café Coucou +Lo D 100pre +Énergie +Passe-temps +La Suertuda +ARTElier +Mimición +Correveidile +Eva Luar +Brillí Maniquí +Brillí Rubí +Brillí Sportif +Obscura +AbrigaDitto +Gothique +Enseñora +Ignis Fatuus +Las Divinas +Soy Fans +Densoku Luminalia +Zapateau +A-tête-lier +Brillí Kawaii +Kikonashi +Fotón +Fotón 4 +Kelegancia +Nación de la Distinción +Triatlón Rojo +Villa de la Zapatilla +Vortex +Restaurante Nifú Nifà +Sushi Tres Delicias +Restaurante Ulalá +Alcantarillas de Luminalia +Café Concordia +Café Quintaesencia +La Claqueta +Café Contienda +Zona salvaje 17 +Zona salvaje 1 +Zona salvaje 2 +Zona salvaje 12 +Zona salvaje 10 +Zona salvaje 5 +Zona salvaje 16 +Zona salvaje 14 +Zona salvaje 9 +Zona salvaje 18 +Zona salvaje 7 +Zona salvaje 13 +Zona salvaje 4 +Zona salvaje 3 +Zona salvaje 15 +Zona salvaje 19 +Zona salvaje 6 +Zona salvaje 11 +Zona salvaje 8 +Zona salvaje 20 +Zona de combate +Pasaje de la Prosperidad +Pasaje de la Penumbra +Pasaje del Plenilunio +Pasaje del Palacio +Dojo del Círculo Justiciero +Hotel Z +Construcciones Radix +Gran Hotel Ricachilton +Sede del Clan Corrosión +Estación Luminalia Sur +Quastelar S. A. +Restaurante Fulanito Detal +Restaurante Nifú Nifà +Restaurante Ulalá +Sushi Tres Delicias +Looker & Cía. +Laboratorio Pokémon +Local vacante +Museo de Luminalia +Café Lysandre +Laboratorios Lysandre +Alcantarillas \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_es.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_es.txt new file mode 100644 index 000000000..e6dcdfdd1 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_es.txt @@ -0,0 +1,236 @@ +- + +Lugar misterioso + +Lugar lejano + +Distrito Verde +Distrito Azul +Distrito Rosa +Distrito Rojo +Distrito Amarillo +Plaza Central +Avenida Primavera +Avenida Verano +Avenida Otoño +Avenida Invierno +Canal Saison +Vía Verde +Vía Verde +Bulevar Sur +Bulevar Sur +Distrito Verde: sector 1 +Distrito Verde: sector 3 +Canal Affluer +Distrito Verde: sector 6 +Distrito Verde: sector 7 +Estación Luminalia Sur +Distrito Verde: sector 2 +Distrito Verde: sector 4 +Distrito Verde: sector 5 +Distrito Verde: sector 8 +Distrito Verde: sector 9 +Plaza Verde +Vía Azul +Vía Azul +Bulevar Sur +Bulevar Sur +Distrito Azul: sector 1 +Distrito Azul: sector 3 +Parque Embelese +Distrito Azul: sector 5 +Distrito Azul: sector 7 +Distrito Azul: sector 2 +Distrito Azul: sector 4 +Rincón Nadená +Distrito Azul: sector 6 +Distrito Azul: sector 8 +Distrito Azul: sector 9 +Distrito Azul: sector 10 +Plaza Azul +Vía Rosa +Vía Rosa +Bulevar Sur +Bulevar Norte +Distrito Rosa: sector 1 +Distrito Rosa: sector 3 +Distrito Rosa: sector 5 +Distrito Rosa: sector 6 +Subestación Eléctrica +Distrito Rosa: sector 2 +Distrito Rosa: sector 4 +Distrito Rosa: sector 7 +Quastelar S. A. +Distrito Rosa: sector 8 +Distrito Rosa: sector 9 +Plaza Rosa +Vía Roja +Vía Roja +Bulevar Norte +Bulevar Norte +Distrito Rojo: sector 1 +Distrito Rojo: sector 3 +Distrito Rojo: sector 4 +Distrito Rojo: sector 5 +Distrito Rojo: sector 7 +Distrito Rojo: sector 2 +Escuela Perseida +Distrito Rojo: sector 6 +Cementerio Bonnuit +Distrito Rojo: sector 8 +Plaza Roja +Vía Amarilla +Vía Amarilla +Bulevar Norte +Bulevar Norte +Distrito Amarillo: sector 1 +Distrito Amarillo: sector 3 +Distrito Amarillo: sector 4 +Distrito Amarillo: sector 5 +Distrito Amarillo: sector 7 +Distrito Amarillo: sector 8 +Distrito Amarillo: sector 2 +Paseo Saison +Distrito Amarillo: sector 6 +Distrito Amarillo: sector 9 +Distrito Amarillo: sector 10 +Distrito Amarillo: sector 11 +Distrito Amarillo: sector 12 +Plaza Amarilla +Bulevar del Viento +Museo de Arte de Luminalia +Centro Pokémon del Distrito Verde +Hotel Z +Laboratorio Pokémon +Torre Prisma +Handsome & Cía. +Quastelar S. A. +Construcciones Radix +Plaza Verde +Estación Luminalia Sur +Plaza Azul +Sede del Clan Corrosión +Centro Pokémon del Distrito Azul +Centro Pokémon de la Avenida Primavera +Plaza Rosa +Café Lysson +Centro Pokémon del Distrito Rosa +Centro Pokémon de la Plaza Rosa +Plaza Roja +Gran Hotel Ricachilton +Centro Pokémon del Distrito Rojo +Centro Pokémon de la Plaza Central +Plaza Amarilla +Dojo del Círculo Justiciero +Centro Pokémon del Distrito Amarillo +Centro Pokémon de la Avenida Invierno +Peluquería +Boutique de la Piedra +Boutique Poké Ball +Gears +Boutique Très Chic +Restaurante Le Mindundi +Café Vorágine +Cafetería Prêt-à-Sorber +Café Rubor +Empty Room (Abandoned Building) +Sewer Entrance +Dispar +Héros +PosTrès Bon +Mercazul +Internaria +RitmiK +Triatlón Azul +Óptica Defog +Paramie +Salón Camerino +Café Can Can +Café Soleil +Cafetería Enfoque +Alcantarillas de Luminalia +Café Recreo +Café Sobre Ruedas +Café Galanes +Café Cuco +Decalle +Énergie +Passe-temps +La Suertuda +ARTElier +Somnus +Polvorosa +El Marcadillo +Brillí Fabulosa +Brillí Glamurosa +Brillí Sport +Obscura +De Buena Capa +Rite Gothique +Maduraleza +Lucerna +Corte Magnífico +Muy Fan +Densoku Luminalia +Zapateau +Taller Testa +Brillí Cuqui +Kikonashi +Luxon +Luxon 4 +Élégance +Ropatrópolis +Triatlón Rojo +País de Pisadas +Tornade +Restaurante Nifú Nifà +Sushi Tres Delicias +Restaurante Le Postín +Alcantarillas de Luminalia +Café Concordia +Café Quintaesencia +La Claqueta +Café Contienda +Zona salvaje 17 +Zona salvaje 1 +Zona salvaje 2 +Zona salvaje 12 +Zona salvaje 10 +Zona salvaje 5 +Zona salvaje 16 +Zona salvaje 14 +Zona salvaje 9 +Zona salvaje 18 +Zona salvaje 7 +Zona salvaje 13 +Zona salvaje 4 +Zona salvaje 3 +Zona salvaje 15 +Zona salvaje 19 +Zona salvaje 6 +Zona salvaje 11 +Zona salvaje 8 +Zona salvaje 20 +Zona de combate +Pasaje de la Alegría +Pasaje de la Sombra +Galería Claro de Luna +Pasaje del Palacio +Dojo del Círculo Justiciero +Hotel Z +Construcciones Radix +Gran Hotel Ricachilton +Sede del Clan Corrosión +Estación Luminalia Sur +Quastelar S. A. +Restaurante Le Mindundi +Restaurante Nifú Nifà +Restaurante Le Postín +Sushi Tres Delicias +Handsome & Cía. +Laboratorio Pokémon +Local vacante +Museo de Arte de Luminalia +Café Lysson +Laboratorios Lysson +Alcantarillas \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_fr.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_fr.txt new file mode 100644 index 000000000..15fc97411 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_fr.txt @@ -0,0 +1,236 @@ +---------- + +Endroit mystérieux + +Endroit lointain + +Beau-Vert +Valcyan +Rosavilliers +Maurouge +Jaunemont +Place Centrale +Avenue Floréal +Avenue Thermidor +Avenue Vendémiaire +Avenue Ventôse +Canal des Saisons +Avenue Verte +Avenue Verte +Rue Méridionale +Rue Méridionale +1ᵉʳ arrondissement de Beau-Vert +3ᵉ arrondissement de Beau-Vert +Canal Lacoulée +6ᵉ arrondissement de Beau-Vert +7ᵉ arrondissement de Beau-Vert +Parvis d’Illumis Sud +2ᵉ arrondissement de Beau-Vert +4ᵉ arrondissement de Beau-Vert +5ᵉ arrondissement de Beau-Vert +8ᵉ arrondissement de Beau-Vert +9ᵉ arrondissement de Beau-Vert +Place Verte +Avenue Cyan +Avenue Cyan +Rue Méridionale +Rue Méridionale +1ᵉʳ arrondissement de Valcyan +3ᵉ arrondissement de Valcyan +Parc Montprélasse +5ᵉ arrondissement de Valcyan +7ᵉ arrondissement de Valcyan +2ᵉ arrondissement de Valcyan +4ᵉ arrondissement de Valcyan +Allée Ranavoir +6ᵉ arrondissement de Valcyan +8ᵉ arrondissement de Valcyan +9ᵉ arrondissement de Valcyan +10ᵉ arrondissement de Valcyan +Place Cyan +Avenue Rose +Avenue Rose +Rue Méridionale +Rue Septentrionale +1ᵉʳ arrondissement de Rosavilliers +3ᵉ arrondissement de Rosavilliers +5ᵉ arrondissement de Rosavilliers +6ᵉ arrondissement de Rosavilliers +Poste Électrique d’Illumis +2ᵉ arrondissement de Rosavilliers +4ᵉ arrondissement de Rosavilliers +7ᵉ arrondissement de Rosavilliers +Société Quazar +8ᵉ arrondissement de Rosavilliers +9ᵉ arrondissement de Rosavilliers +Place Rose +Avenue Rouge +Avenue Rouge +Rue Septentrionale +Rue Septentrionale +1ᵉʳ arrondissement de Maurouge +3ᵉ arrondissement de Maurouge +4ᵉ arrondissement de Maurouge +5ᵉ arrondissement de Maurouge +7ᵉ arrondissement de Maurouge +2ᵉ arrondissement de Maurouge +Institut Nivers +6ᵉ arrondissement de Maurouge +Cimetière Dussommeil +8ᵉ arrondissement de Maurouge +Place Rouge +Avenue Jaune +Avenue Jaune +Rue Septentrionale +Rue Septentrionale +1ᵉʳ arrondissement de Jaunemont +3ᵉ arrondissement de Jaunemont +4ᵉ arrondissement de Jaunemont +5ᵉ arrondissement de Jaunemont +7ᵉ arrondissement de Jaunemont +8ᵉ arrondissement de Jaunemont +2ᵉ arrondissement de Jaunemont +Quai du Canal des Saisons +6ᵉ arrondissement de Jaunemont +9ᵉ arrondissement de Jaunemont +10ᵉ arrondissement de Jaunemont +11ᵉ arrondissement de Jaunemont +12ᵉ arrondissement de Jaunemont +Place Jaune +Boulevard du Vent +Musée d’Illumis +Centre Pokémon de Beau-Vert +Hôtel Z +Laboratoire Pokémon +Tour Prismatique +Agence Beladonis +Société Quazar +Bâti-Racines +Place Verte +Illumis Sud +Place Cyan +Agence Dérouillard +Centre Pokémon de Valcyan +Centre Pokémon de l’Avenue Floréal +Place Rose +Café Lysandre +Centre Pokémon de Rosavilliers +Centre Pokémon de la Place Rose +Place Rouge +Le Crésus +Centre Pokémon de Maurouge +Centre Pokémon de la Place Centrale +Place Jaune +Dojo de la Justice +Centre Pokémon de Jaunemont +Centre Pokémon de l’Avenue Ventôse +Salon de coiffure +Le Joyau de Kalos +Le Ball-Bazar +Gears +Au Chic-à-Porter +L’Étoilé +La Drôle d’Embringue +Le Lounge Café +Les Timides +Empty Room (Abandoned Building) +Sewer Entrance +La Pointe de la Mode +Braverry +Régal et Vous +Halle Cyan +Outlet’s Play +Folha +Triathlon Valcyan +Optique Defog +Prêt-à-Équiper +Détente et Beauté +Café Toutou +Café Soleil +Un Autre Regard +Égouts d’Illumis +Café Récré +Café Slalom +Le Café des Compères +Au Coucou +Comd’hab +Énergie +Passe-Temps +Porte-Chance +Pinceau +Beaudodo +Sol et Baskets +Marquage +Kawaï Joli +Kawaï Choupi +Kawaï Sporty +Alter & Goth +Mantotop +Rituel Nocturne +Mode Mature +De Mèche +Mode Magnifique +Cinéfil +Kaminari Illumis +La Chaussure +Atelier Chapelier +Kawaï Mimi +Kikonashi +Physix +Physix 4 +Lex & Lans +Le Paradis du Vêtement +Triathlon Maurouge +Le Paradis du Pied +Tornade +Les Algolides +Sushi Sans Chichis +Le Firmament +Égouts d’Illumis +Les Partenaires +L’Ultimate +Café Clap +La Bataille +Zone sauvage nº 17 +Zone sauvage nº 1 +Zone sauvage nº 2 +Zone sauvage nº 12 +Zone sauvage nº 10 +Zone sauvage nº 5 +Zone sauvage nº 16 +Zone sauvage nº 14 +Zone sauvage nº 9 +Zone sauvage nº 18 +Zone sauvage nº 7 +Zone sauvage nº 13 +Zone sauvage nº 4 +Zone sauvage nº 3 +Zone sauvage nº 15 +Zone sauvage nº 19 +Zone sauvage nº 6 +Zone sauvage nº 11 +Zone sauvage nº 8 +Zone sauvage nº 20 +Zone de combat +Passage du Bonheur +Passage de l’Ombre +Galerie Clair de Lune +Passage du Palais +Dojo de la Justice +Hôtel Z +Bâti-Racines +Grand Hôtel Le Crésus +Agence Dérouillard +Illumis Sud +Société Quazar +L’Étoilé +Les Algolides +Le Firmament +Sushi Sans Chichis +Agence Beladonis +Laboratoire Pokémon +Immeuble de bureaux +Musée d’Illumis +Café Lysandre +Labos Lysandre +Égouts \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_it.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_it.txt new file mode 100644 index 000000000..2c08b3cfc --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_it.txt @@ -0,0 +1,236 @@ +---------- + +Zona misteriosa + +Luogo remoto + +Quartiere Verde +Quartiere Blu +Quartiere Rosa +Quartiere Rosso +Quartiere Giallo +Piazza Centrale +Viale Primavera +Viale Estate +Viale Autunno +Viale Inverno +Canal des Saisons +Boulevard Verde +Boulevard Verde +Corso Basso +Corso Basso +1º isolato del Quartiere Verde +3º isolato del Quartiere Verde +Canal Couler +6º isolato del Quartiere Verde +7º isolato del Quartiere Verde +Piazzale del terminal +2º isolato del Quartiere Verde +4º isolato del Quartiere Verde +5º isolato del Quartiere Verde +8º isolato del Quartiere Verde +9º isolato del Quartiere Verde +Piazza Verde +Boulevard Blu +Boulevard Blu +Corso Basso +Corso Basso +1º isolato del Quartiere Blu +3º isolato del Quartiere Blu +Parco Distratto +5º isolato del Quartiere Blu +7º isolato del Quartiere Blu +2º isolato del Quartiere Blu +4º isolato del Quartiere Blu +Spazio Rienafaire +6º isolato del Quartiere Blu +8º isolato del Quartiere Blu +9º isolato del Quartiere Blu +10º isolato del Quartiere Blu +Piazza Blu +Boulevard Rosa +Boulevard Rosa +Corso Basso +Corso Alto +1º isolato del Quartiere Rosa +3º isolato del Quartiere Rosa +5º isolato del Quartiere Rosa +6º isolato del Quartiere Rosa +Sottostazione elettrica +2º isolato del Quartiere Rosa +4º isolato del Quartiere Rosa +7º isolato del Quartiere Rosa +Q-asar Inc. +8º isolato del Quartiere Rosa +9º isolato del Quartiere Rosa +Piazza Rosa +Boulevard Rosso +Boulevard Rosso +Corso Alto +Corso Alto +1º isolato del Quartiere Rosso +3º isolato del Quartiere Rosso +4º isolato del Quartiere Rosso +5º isolato del Quartiere Rosso +7º isolato del Quartiere Rosso +2º isolato del Quartiere Rosso +Istituto Étoile +6º isolato del Quartiere Rosso +Cimitero Dormibien +8º isolato del Quartiere Rosso +Piazza Rossa +Boulevard Giallo +Boulevard Giallo +Corso Alto +Corso Alto +1º isolato del Quartiere Giallo +3º isolato del Quartiere Giallo +4º isolato del Quartiere Giallo +5º isolato del Quartiere Giallo +7º isolato del Quartiere Giallo +8º isolato del Quartiere Giallo +2º isolato del Quartiere Giallo +Riva del Canal des Saisons +6º isolato del Quartiere Giallo +9º isolato del Quartiere Giallo +10º isolato del Quartiere Giallo +11º isolato del Quartiere Giallo +12º isolato del Quartiere Giallo +Piazza Gialla +Promenade du Vent +Museo di Luminopoli +Centro Pokémon del Quartiere Verde +Hotel Z +Laboratorio Pokémon +Torre Prisma +Agenzia Bellocchio +Q-asar Inc. +Costruzioni Racines +Piazza Verde +Terminal di Luminopoli +Piazza Blu +Sede del Clan Ruggine +Centro Pokémon del Quartiere Blu +Centro Pokémon di Viale Primavera +Piazza Rosa +Caffè Elisio +Centro Pokémon del Quartiere Rosa +Centro Pokémon di Piazza Rosa +Piazza Rossa +Grand Hotel Fior di Quattrini +Centro Pokémon del Quartiere Rosso +Centro Pokémon di Piazza Centrale +Piazza Gialla +Dojo del Gruppo Justice +Centro Pokémon del Quartiere Giallo +Centro Pokémon di Viale Inverno +Salone Acconciature +Gioielleria +Negozio di Poké Ball +Gears +Boutique Chic-à-Porter +Ristorante Bocca Buona +Caffè Burrasca +Caffè À la Mode +Bar I Timidi +Empty Room (Abandoned Building) +Sewer Entrance +Neat Edge +BRAVELY +Dessert du Chef +Mercato Blu +In The Zone +BACKFLIP +Triathlon Blu +Defog Ottica +Equip +Salone Camerino +Caffè Qua la Zampa +Café Soleil +Bar Lo Scatto +Acquedotto di Luminopoli +Caffè io&te +Caffè Slalom +Caffè I Ragazzi +Caffè La Tazza Vuota +Il Solito +Énergétique +Passe-temps +Porte-Chance +Pinceau +Penni Kelly +Sol et Baskets +Marquage +Girly Imp +Pretty Imp +Sporty Imp +Nyx Nox +Cappotti & Paltò +Rite de Minuit +Mode Mature +La Lanterna +Mode Magnifique +GRAN FAN +DENSOKU Luminopoli +La Chaussure +Atelier Capoccia +Cute Imp +Kikonashi +SUBATOMIC +SUBATOMIC 4 +Prima Scelta +Le Pays des Vêtements +Triathlon Rosso +Le Pays des Pieds +Tornado +Ristorante La Buona Forchetta +Ristorante Girasogno +Ristorante Gourmet +Acquedotto di Luminopoli +Caffè Concordia +Caffè I Patiti +Caffè Ciak +Caffè Le Lotte +Zona selvaggia 17 +Zona selvaggia 1 +Zona selvaggia 2 +Zona selvaggia 12 +Zona selvaggia 10 +Zona selvaggia 5 +Zona selvaggia 16 +Zona selvaggia 14 +Zona selvaggia 9 +Zona selvaggia 18 +Zona selvaggia 7 +Zona selvaggia 13 +Zona selvaggia 4 +Zona selvaggia 3 +Zona selvaggia 15 +Zona selvaggia 19 +Zona selvaggia 6 +Zona selvaggia 11 +Zona selvaggia 8 +Zona selvaggia 20 +Zona lotta +Passage du Bonheur +Passage de l’Ombre +Galleria Clair de Lune +Passage du Palais +Dojo del Gruppo Justice +Hotel Z +Costruzioni Racines +Grand Hotel Fior di Quattrini +Sede del Clan Ruggine +Terminal di Luminopoli +Q-asar Inc. +Ristorante Bocca Buona +Ristorante La Buona Forchetta +Ristorante Gourmet +Ristorante Girasogno +Agenzia Bellocchio +Laboratorio Pokémon +Edificio commerciale +Museo di Luminopoli +Caffè Elisio +Laboratori Elisio +Acquedotto \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_ja.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_ja.txt new file mode 100644 index 000000000..d635953d5 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_ja.txt @@ -0,0 +1,236 @@ +---------- + +なぞの場所 + +遠い場所 + +ベール地区 +ブルー地区 +ローズ地区 +ルージュ地区 +ジョーヌ地区 +メディオプラザ +プランタンアベニュー +エテアベニュー +オトンヌアベニュー +イベールアベニュー +セゾン運河 +ベール大通り +ベール大通り +サウスサイドストリート +サウスサイドストリート +ベール1番地 +ベール3番地 +クレ水路 +ベール6番地 +ベール7番地 +ミアレ駅前 +ベール2番地 +ベール4番地 +ベール5番地 +ベール8番地 +ベール9番地 +ベール広場 +ブルー大通り +ブルー大通り +サウスサイドストリート +サウスサイドストリート +ブルー1番地 +ブルー3番地 +ボンヤーリ公園 +ブルー5番地 +ブルー7番地 +ブルー2番地 +ブルー4番地 +リヤン・エスパス +ブルー6番地 +ブルー8番地 +ブルー9番地 +ブルー10番地 +ブルー広場 +ローズ大通り +ローズ大通り +サウスサイドストリート +ノースサイドストリート +ローズ1番地 +ローズ3番地 +ローズ5番地 +ローズ6番地 +ミアレ変電所 +ローズ2番地 +ローズ4番地 +ローズ7番地 +クエーサー社 +ローズ8番地 +ローズ9番地 +ローズ広場 +ルージュ大通り +ルージュ大通り +ノースサイドストリート +ノースサイドストリート +ルージュ1番地 +ルージュ3番地 +ルージュ4番地 +ルージュ5番地 +ルージュ7番地 +ルージュ2番地 +エトワール校 +ルージュ6番地 +ドールビアン墓地 +ルージュ8番地 +ルージュ広場 +ジョーヌ大通り +ジョーヌ大通り +ノースサイドストリート +ノースサイドストリート +ジョーヌ1番地 +ジョーヌ3番地 +ジョーヌ4番地 +ジョーヌ5番地 +ジョーヌ7番地 +ジョーヌ8番地 +ジョーヌ2番地 +セゾン運河沿い +ジョーヌ6番地 +ジョーヌ9番地 +ジョーヌ10番地 +ジョーヌ11番地 +ジョーヌ12番地 +ジョーヌ広場 +ブールバール・デュ・ヴォン +ミアレ美術館 +ポケモンセンター:ベール +ホテルZ +ポケモン研究所 +プリズムタワー +ハンサムハウス +クエーサー社 +ラシーヌ工務店 +ベール広場 +ミアレ駅 +ブルー広場 +サビ組事務所 +ポケモンセンター:ブルー +ポケモンセンター:プランタン +ローズ広場 +フラダリカフェ +ポケモンセンター:ローズ +ポケモンセンター:ローズ広場 +ルージュ広場 +ホテル シュールリッシュ +ポケモンセンター:ルージュ +ポケモンセンター:メディオ +ジョーヌ広場 +ジャスティスの会道場 +ポケモンセンター:ジョーヌ +ポケモンセンター:イベール +ヘアサロン +いしや +たまや +ギアーズ +メゾン・ド・ポルテ +レストラン・ド・フツー +カフェ・ツイスター +カフェ・アラモード +カフェ・ひとみしり +空き部屋(廃ビル) +地下水道入口 +エッジネート +BRAVELY +Dessert du jour +ブルーマーケット +インナースペース +FORIA +トリアトロンブルー店 +デフォッグ眼鏡 +ソーチャク +サロン・ド・ロージュ +カフェ・トウトウ +カフェ・ソレイユ +カフェ・フォーカス +ミアレ地下水道 +カフェ・かわいがり +カフェ・スラローム +カフェ・おとこまえ +カフェ・カンコドール +イツモノ +エネルジ +パストン +ポルト・シャンス +Pinceau +OHIRUNE +ソル・エ・バスケット +マルカージュ +キラキラガーリー +キラキラプリティー +キラキラスポーティ +アンドナイト +ツツミコム +MINUIT RITE +モード・マチュア +トモシビ +モード・マニフィック +BIG FAN +DENSOKUミアレ店 +ラ・ショスュール +アトリエヘッズ +キラキラキュート +キコナシ +AXION +AXION 4 +イッピン +ル・ペイ・デ・ヴェトモン +トリアトロンルージュ店 +ル・ペイ・デ・ピエ +トルナード +リストランテ ニ・リュー +レストラン ローリングドリーマー +レストラン・ド・キワミ +ミアレ地下水道 +カフェ・パルトネール +カフェ・アルティメット +カフェ・リテイク +カフェ・バタイユ +17番ワイルドゾーン +1番ワイルドゾーン +2番ワイルドゾーン +12番ワイルドゾーン +10番ワイルドゾーン +5番ワイルドゾーン +16番ワイルドゾーン +14番ワイルドゾーン +9番ワイルドゾーン +18番ワイルドゾーン +7番ワイルドゾーン +13番ワイルドゾーン +4番ワイルドゾーン +3番ワイルドゾーン +15番ワイルドゾーン +19番ワイルドゾーン +6番ワイルドゾーン +11番ワイルドゾーン +8番ワイルドゾーン +20番ワイルドゾーン +バトルゾーン +パサージュ・デュ・ボヌール +パサージュ・ド・ロンブル +ギャルリ・クレールドリュヌ +パサージュ・デュ・パレ +ジャスティスの会道場 +ホテルZ +ラシーヌ工務店 +グランドホテル シュールリッシュ +サビ組事務所 +ミアレ駅 +クエーサー社 +レストラン・ド・フツー +リストランテ ニ・リュー +レストラン・ド・キワミ +レストラン ローリングドリーマー +ハンサムハウス +ポケモン研究所 +雑居ビル +ミアレ美術館 +フラダリカフェ +フラダリラボ +地下水道 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_ko.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_ko.txt new file mode 100644 index 000000000..62d4aff09 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_ko.txt @@ -0,0 +1,236 @@ +---------- + +수수께끼의 장소 + +먼 곳 + +베르 지구 +블르 지구 +로즈 지구 +루주 지구 +존느 지구 +메디오 플라자 +프랭탕 애버뉴 +에테 애버뉴 +오톤 애버뉴 +이베르 애버뉴 +쉐종 운하 +베르대로 +베르대로 +사우스사이드 스트리트 +사우스사이드 스트리트 +베르 1번지 +베르 3번지 +쿨레 수로 +베르 6번지 +베르 7번지 +미르역 앞 +베르 2번지 +베르 4번지 +베르 5번지 +베르 8번지 +베르 9번지 +베르 광장 +블르대로 +블르대로 +사우스사이드 스트리트 +사우스사이드 스트리트 +블르 1번지 +블르 3번지 +몽테리공원 +블르 5번지 +블르 7번지 +블르 2번지 +블르 4번지 +리앙 에스파스 +블르 6번지 +블르 8번지 +블르 9번지 +블르 10번지 +블르 광장 +로즈대로 +로즈대로 +사우스사이드 스트리트 +노스사이드 스트리트 +로즈 1번지 +로즈 3번지 +로즈 5번지 +로즈 6번지 +미르변전소 +로즈 2번지 +로즈 4번지 +로즈 7번지 +퀘이사 주식회사 +로즈 8번지 +로즈 9번지 +로즈 광장 +루주대로 +루주대로 +노스사이드 스트리트 +노스사이드 스트리트 +루주 1번지 +루주 3번지 +루주 4번지 +루주 5번지 +루주 7번지 +루주 2번지 +에투알 스쿨 +루주 6번지 +도르비앙 묘지 +루주 8번지 +루주 광장 +존느대로 +존느대로 +노스사이드 스트리트 +노스사이드 스트리트 +존느 1번지 +존느 3번지 +존느 4번지 +존느 5번지 +존느 7번지 +존느 8번지 +존느 2번지 +쉐종 운하변 +존느 6번지 +존느 9번지 +존느 10번지 +존느 11번지 +존느 12번지 +존느 광장 +불바르 뒤 방 +미르 미술관 +베르 포켓몬센터 +호텔Z +포켓몬 연구소 +프리즘타워 +핸섬 하우스 +퀘이사 주식회사 +라시느건설 +베르 광장 +미르역 +블르 광장 +녹청파 사무소 +블르 포켓몬센터 +프랭탕 포켓몬센터 +로즈 광장 +플라드리 카페 +로즈 포켓몬센터 +로즈 광장 포켓몬센터 +루주 광장 +쉬르 리슈 호텔 +루주 포켓몬센터 +메디오 포켓몬센터 +존느 광장 +저스티스회 도장 +존느 포켓몬센터 +이베르 포켓몬센터 +헤어살롱 +스톤숍 +볼 가게 +기어스 +메종 드 포르테 +보통 레스토랑 +트위스터 카페 +아라모드 카페 +낯가림 카페 +空き部屋(廃ビル) +地下水道入口 +에지네이트 +BRAVELY +Dessert du jour +블르 마켓 +이너 스페이스 +GAINER +트라이애슬론 블르점 +드포그 안경 +Equip +살롱 드 로주 +뚜뚜 카페 +솔레유 카페 +포커스 카페 +미르 지하 수도 +가애 카페 +슬라롬 카페 +사나이 카페 +포곡쥬 카페 +유주얼 +에네르지 +파스통 +포르트 샹스 +Pinceau +SIESTE +솔 에 바스켓 +마르카주 +블링 걸리 +블링 프리티 +블링 스포티 +앤드 나이트 +COAT +MINUIT RITE +모드 머추어 +La Lampe +모드 마니피크 +BIG FAN +덴소쿠 미르점 +라 쇼쉬르 +아틀리에 헤즈 +블링 러블리 +MAPSY +SUBATOMIC +SUBATOMIC 4 +일품 +르 페이 데 베트멍 +트라이애슬론 루주점 +르 페이 데 피에 +토르나드 +리스토란테 이류 +롤링 드리머 레스토랑 +궁극 레스토랑 +미르 지하 수도 +파르트네르 카페 +얼티메이트 카페 +리테이크 카페 +바타유 카페 +17번 와일드 존 +1번 와일드 존 +2번 와일드 존 +12번 와일드 존 +10번 와일드 존 +5번 와일드 존 +16번 와일드 존 +14번 와일드 존 +9번 와일드 존 +18번 와일드 존 +7번 와일드 존 +13번 와일드 존 +4번 와일드 존 +3번 와일드 존 +15번 와일드 존 +19번 와일드 존 +6번 와일드 존 +11번 와일드 존 +8번 와일드 존 +20번 와일드 존 +배틀 존 +파사주 뒤 보뇌르 +파사주 드 롬브레 +갤러리 클레르 드 륀 +파사주 뒤 팔레 +저스티스회 도장 +호텔Z +라시느건설 +쉬르 리슈 그랜드 호텔 +녹청파 사무소 +미르역 +퀘이사 주식회사 +보통 레스토랑 +리스토란테 이류 +궁극 레스토랑 +롤링 드리머 레스토랑 +핸섬 하우스 +포켓몬 연구소 +상가 건물 +미르 미술관 +플라드리 카페 +플라드리 래버러토리 +지하 수도 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_zh-Hans.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_zh-Hans.txt new file mode 100644 index 000000000..caf970cbc --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_zh-Hans.txt @@ -0,0 +1,236 @@ +---------- + +神秘的地方 + +遥远的地方 + +翡绿区 +浦蓝区 +蓉粉区 +榴红区 +琼黄区 +中央广场 +春日大道 +夏日大道 +秋日大道 +冬日大道 +四季运河 +翡绿大道 +翡绿大道 +南侧大道 +南侧大道 +翡绿1号街区 +翡绿3号街区 +库流水路 +翡绿6号街区 +翡绿7号街区 +密阿雷南站前 +翡绿2号街区 +翡绿4号街区 +翡绿5号街区 +翡绿8号街区 +翡绿9号街区 +绿色广场 +浦蓝大道 +浦蓝大道 +南侧大道 +南侧大道 +浦蓝1号街区 +浦蓝3号街区 +发呆公园 +浦蓝5号街区 +浦蓝7号街区 +浦蓝2号街区 +浦蓝4号街区 +空空空地 +浦蓝6号街区 +浦蓝8号街区 +浦蓝9号街区 +浦蓝10号街区 +蓝色广场 +蓉粉大道 +蓉粉大道 +南侧大道 +北侧大道 +蓉粉1号街区 +蓉粉3号街区 +蓉粉5号街区 +蓉粉6号街区 +密阿雷变电站 +蓉粉2号街区 +蓉粉4号街区 +蓉粉7号街区 +阔星公司 +蓉粉8号街区 +蓉粉9号街区 +粉色广场 +榴红大道 +榴红大道 +北侧大道 +北侧大道 +榴红1号街区 +榴红3号街区 +榴红4号街区 +榴红5号街区 +榴红7号街区 +榴红2号街区 +艾特瓦鲁学校 +榴红6号街区 +安息墓地 +榴红8号街区 +红色广场 +琼黄大道 +琼黄大道 +北侧大道 +北侧大道 +琼黄1号街区 +琼黄3号街区 +琼黄4号街区 +琼黄5号街区 +琼黄7号街区 +琼黄8号街区 +琼黄2号街区 +四季运河沿岸 +琼黄6号街区 +琼黄9号街区 +琼黄10号街区 +琼黄11号街区 +琼黄12号街区 +黄色广场 +风之大道 +密阿雷美术馆 +宝可梦中心:翡绿 +旅馆Z +宝可梦研究所 +棱镜塔 +帅哥侦探事务所 +阔星公司 +木根工程 +绿色广场 +密阿雷南站 +蓝色广场 +锈蚀组事务所 +宝可梦中心:浦蓝 +宝可梦中心:春日大道 +粉色广场 +弗拉达利咖啡店 +宝可梦中心:蓉粉 +宝可梦中心:粉色广场 +红色广场 +秀丽世大酒店 +宝可梦中心:榴红 +宝可梦中心:中央 +黄色广场 +正义社道场 +宝可梦中心:琼黄 +宝可梦中心:冬日大道 +美发沙龙 +石头馆 +精灵球馆 +集而饰 +时尚服饰馆 +谱通餐馆 +龙卷风咖啡馆 +时髦咖啡馆 +帕生咖啡店 +空き部屋(廃ビル) +地下水道入口 +极特潮 +BRAVELY +Dessert du jour +浦蓝市集 +唯我空间 +FORIA +铁三浦蓝店 +名镜眼镜 +戴带屋 +包厢沙龙 +汪汪咖啡馆 +旭日咖啡馆 +定焦咖啡馆 +密阿雷下水道 +友友乐咖啡馆 +回旋咖啡馆 +英俊咖啡馆 +罗雀咖啡馆 +每日卓衣 +爱能极 +昔日时光 +小幸运 +Pinceau +NAPTIME +鞋踏实地 +玛尔卡珠 +GinGin☆女孩 +GinGin☆漂亮 +GinGin☆活泼 +AND NIGHT +COAT +MINUIT RITE +尚・雅致 +晶火 +尚・璀璨 +BIG FAN +电速密阿雷店 +好鞋家 +头头工坊 +GinGin☆可爱 +雅着 +SUBATOMIC +SUBATOMIC 4 +逸品 +裳之国 +铁三榴红店 +履之国 +炫风 +贰流餐馆 +回转梦想家高级餐厅 +鼎极餐馆 +密阿雷下水道 +牵绊咖啡馆 +极训咖啡馆 +开拍咖啡馆 +对战迷咖啡馆 +17号野生特区 +1号野生特区 +2号野生特区 +12号野生特区 +10号野生特区 +5号野生特区 +16号野生特区 +14号野生特区 +9号野生特区 +18号野生特区 +7号野生特区 +13号野生特区 +4号野生特区 +3号野生特区 +15号野生特区 +19号野生特区 +6号野生特区 +11号野生特区 +8号野生特区 +20号野生特区 +对战特区 +幸福廊街 +幽影廊街 +澄月廊街 +宫廷廊街 +正义社道场 +旅馆Z +木根工程 +秀丽世大酒店 +锈蚀组事务所 +密阿雷南站 +阔星公司 +谱通餐馆 +贰流餐馆 +鼎极餐馆 +回转梦想家高级餐厅 +帅哥侦探事务所 +宝可梦研究所 +商住楼 +密阿雷美术馆 +弗拉达利咖啡店 +弗拉达利研究所 +下水道 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_zh-Hant.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_zh-Hant.txt new file mode 100644 index 000000000..b73ab7f42 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_00000_zh-Hant.txt @@ -0,0 +1,236 @@ +---------- + +神秘的地方 + +遙遠的地方 + +翡綠區 +浦藍區 +蓉粉區 +榴紅區 +瓊黃區 +中央廣場 +春日大道 +夏日大道 +秋日大道 +冬日大道 +四季運河 +翡綠大道 +翡綠大道 +南側大道 +南側大道 +翡綠1號街區 +翡綠3號街區 +庫流水路 +翡綠6號街區 +翡綠7號街區 +密阿雷南站前 +翡綠2號街區 +翡綠4號街區 +翡綠5號街區 +翡綠8號街區 +翡綠9號街區 +綠色廣場 +浦藍大道 +浦藍大道 +南側大道 +南側大道 +浦藍1號街區 +浦藍3號街區 +發呆公園 +浦藍5號街區 +浦藍7號街區 +浦藍2號街區 +浦藍4號街區 +空空空地 +浦藍6號街區 +浦藍8號街區 +浦藍9號街區 +浦藍10號街區 +藍色廣場 +蓉粉大道 +蓉粉大道 +南側大道 +北側大道 +蓉粉1號街區 +蓉粉3號街區 +蓉粉5號街區 +蓉粉6號街區 +密阿雷變電所 +蓉粉2號街區 +蓉粉4號街區 +蓉粉7號街區 +闊星公司 +蓉粉8號街區 +蓉粉9號街區 +粉色廣場 +榴紅大道 +榴紅大道 +北側大道 +北側大道 +榴紅1號街區 +榴紅3號街區 +榴紅4號街區 +榴紅5號街區 +榴紅7號街區 +榴紅2號街區 +艾特瓦魯學校 +榴紅6號街區 +安息墓地 +榴紅8號街區 +紅色廣場 +瓊黃大道 +瓊黃大道 +北側大道 +北側大道 +瓊黃1號街區 +瓊黃3號街區 +瓊黃4號街區 +瓊黃5號街區 +瓊黃7號街區 +瓊黃8號街區 +瓊黃2號街區 +四季運河沿岸 +瓊黃6號街區 +瓊黃9號街區 +瓊黃10號街區 +瓊黃11號街區 +瓊黃12號街區 +黃色廣場 +風之大道 +密阿雷美術館 +寶可夢中心:翡綠 +旅館Z +寶可夢研究所 +稜鏡塔 +帥哥偵探事務所 +闊星公司 +木根工程 +綠色廣場 +密阿雷南站 +藍色廣場 +鏽蝕組事務所 +寶可夢中心:浦藍 +寶可夢中心:春日大道 +粉色廣場 +弗拉達利咖啡店 +寶可夢中心:蓉粉 +寶可夢中心:粉色廣場 +紅色廣場 +秀麗世大酒店 +寶可夢中心:榴紅 +寶可夢中心:中央 +黃色廣場 +正義社道場 +寶可夢中心:瓊黃 +寶可夢中心:冬日大道 +美髮沙龍 +石頭館 +精靈球館 +集而飾 +時尚服飾館 +譜通餐館 +龍捲風咖啡館 +時髦咖啡館 +帕生咖啡店 +空き部屋(廃ビル) +地下水道入口 +極特潮 +BRAVELY +Dessert du jour +浦藍市集 +唯我空間 +FORIA +三鐵浦藍店 +名鏡眼鏡 +戴帶屋 +包廂沙龍 +汪汪咖啡館 +旭日咖啡館 +定焦咖啡館 +密阿雷下水道 +友友樂咖啡館 +迴旋咖啡館 +英俊咖啡館 +羅雀咖啡館 +每日卓衣 +愛能極 +昔日時光 +小幸運 +Pinceau +NAPTIME +鞋踏實地 +瑪爾卡珠 +GinGin☆女孩 +GinGin☆漂亮 +GinGin☆活潑 +AND NIGHT +COAT +MINUIT RITE +尚・雅致 +晶火 +尚・璀璨 +BIG FAN +電速密阿雷店 +好鞋家 +頭頭工坊 +GinGin☆可愛 +雅著 +SUBATOMIC +SUBATOMIC 4 +逸品 +裳之國 +三鐵榴紅店 +履之國 +炫風 +貳流餐館 +回轉夢想家高級餐廳 +鼎極餐館 +密阿雷下水道 +牽絆咖啡館 +極訓咖啡館 +開拍咖啡館 +對戰迷咖啡館 +17號野生特區 +1號野生特區 +2號野生特區 +12號野生特區 +10號野生特區 +5號野生特區 +16號野生特區 +14號野生特區 +9號野生特區 +18號野生特區 +7號野生特區 +13號野生特區 +4號野生特區 +3號野生特區 +15號野生特區 +19號野生特區 +6號野生特區 +11號野生特區 +8號野生特區 +20號野生特區 +對戰特區 +幸福廊街 +幽影廊街 +澄月廊街 +宮廷廊街 +正義社道場 +旅館Z +木根工程 +秀麗世大酒店 +鏽蝕組事務所 +密阿雷南站 +闊星公司 +譜通餐館 +貳流餐館 +鼎極餐館 +回轉夢想家高級餐廳 +帥哥偵探事務所 +寶可夢研究所 +住商混合大樓 +密阿雷美術館 +弗拉達利咖啡店 +弗拉達利研究所 +下水道 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_de.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_de.txt new file mode 100644 index 000000000..cabdeb03e --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_de.txt @@ -0,0 +1,33 @@ + +Link-Tausch +Link-Tausch +Kanto-Region +Johto-Region +Hoenn-Region +Sinnoh-Region +Fernes Land +---------- +Einall-Region +Kalos-Region +Pokémon-Link +Pokémon GO +Kanto-Region +Hoenn-Region +Alola-Region +Pokémon-Resort +Johto-Region +Pokémon HOME +Kanto-Region +Galar-Region +Hisui-Region +Sinnoh-Region +Picknick +Kristallgrotte +Paldea-Region +Illumina City +Pokémon-Labor +Wildsektor 11 +Illumina-Kunstmuseum +Académie Étoile +Rose-Bezirk 2 +Nordring \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_en.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_en.txt new file mode 100644 index 000000000..39e419e13 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_en.txt @@ -0,0 +1,33 @@ + +a Link Trade +a Link Trade +the Kanto region +the Johto region +the Hoenn region +the Sinnoh region +a distant land +—————— +the Unova region +the Kalos region +Pokémon Link +Pokémon GO +the Kanto region +the Hoenn region +the Alola region +Poké Pelago +the Johto region +Pokémon HOME +the Kanto region +the Galar region +the Hisui region +the Sinnoh region +a picnic +a crystal cavern +the Paldea region +Lumiose City +the Pokémon Research Lab +Wild Zone 11 +the Lumiose Museum +Académie Étoile +Magenta Sector 2 +North Boulevard \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_es-419.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_es-419.txt new file mode 100644 index 000000000..0a53bedaf --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_es-419.txt @@ -0,0 +1,33 @@ + +Intercambio en línea +Intercambio en línea +Kanto +Johto +Hoenn +Sinnoh +Tierra lejana +---------- +Unova +Kalos +Nexo Pokémon +Pokémon GO +Kanto +Hoenn +Alola +Poké Resort +Johto +Pokémon HOME +Kanto +Galar +Hisui +Sinnoh +Pícnic +Cueva cristalina +Paldea +Ciudad Luminalia +Laboratorio Pokémon +Zona salvaje 11 +Museo de Luminalia +Escuela Andrómeda +Distrito Rosa: sector 2 +Bulevar Norte \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_es.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_es.txt new file mode 100644 index 000000000..15d83ac06 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_es.txt @@ -0,0 +1,33 @@ + +Intercambio en conexión +Intercambio en conexión +Kanto +Johto +Hoenn +Sinnoh +Tierra lejana +---------- +Teselia +Kalos +Nexo Pokémon +Pokémon GO +Kanto +Hoenn +Alola +Poké Resort +Johto +Pokémon HOME +Kanto +Galar +Hisui +Sinnoh +Pícnic +Cueva cristalina +Paldea +Ciudad Luminalia +Laboratorio Pokémon +Zona salvaje 11 +Museo de Arte de Luminalia +Escuela Perseida +Distrito Rosa: sector 2 +Bulevar Norte \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_fr.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_fr.txt new file mode 100644 index 000000000..4b95fa077 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_fr.txt @@ -0,0 +1,33 @@ + +Échange en réseau +Échange en réseau +Kanto +Johto +Hoenn +Sinnoh +Pays lointain +---------- +Unys +Kalos +Poké Lien +Pokémon GO +Kanto +Hoenn +Alola +Poké Loisir +Johto +Pokémon HOME +Kanto +Galar +Hisui +Sinnoh +Pique-nique +Grotte de cristal +Paldea +Illumis +Laboratoire Pokémon +Zone sauvage nº 11 +Musée d’Illumis +Institut Nivers +2ᵉ arrondissement de Rosavilliers +Rue Septentrionale \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_it.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_it.txt new file mode 100644 index 000000000..db510de5e --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_it.txt @@ -0,0 +1,33 @@ + +scambio in link +scambio in link +Kanto +Johto +Hoenn +Sinnoh +terra lontana +---------- +Unima +Kalos +Pokémon Link +Pokémon GO +Kanto +Hoenn +Alola +Poké Resort +Johto +Pokémon HOME +Kanto +Galar +Hisui +Sinnoh +picnic +grotta dei cristalli +Paldea +Luminopoli +Laboratorio Pokémon +zona selvaggia 11 +Museo di Luminopoli +Istituto Étoile +2º isolato del Quartiere Rosa +Corso Alto \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_ja.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_ja.txt new file mode 100644 index 000000000..7fea603bd --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_ja.txt @@ -0,0 +1,33 @@ + +通信交換 +通信交換 +カントー地方 +ジョウト地方 +ホウエン地方 +シンオウ地方 +遠く離れた土地 +---------- +イッシュ地方 +カロス地方 +ポケモンリンク +Pokémon GO +カントー地方 +ホウエン地方 +アローラ地方 +ポケリゾート +ジョウト地方 +Pokémon HOME +カントー地方 +ガラル地方 +ヒスイ地方 +シンオウ地方 +ピクニック +結晶洞くつ +パルデア地方 +ミアレシティ +ポケモン研究所 +11番ワイルドゾーン +ミアレ美術館 +エトワール校 +ローズ2番地 +ノースサイドストリート \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_ko.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_ko.txt new file mode 100644 index 000000000..091528edb --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_ko.txt @@ -0,0 +1,33 @@ + +통신교환 +통신교환 +관동지방 +성도지방 +호연지방 +신오지방 +아주 먼 땅 +---------- +하나지방 +칼로스지방 +포켓몬링크 +Pokémon GO +관동지방 +호연지방 +알로라지방 +포켓리조트 +성도지방 +Pokémon HOME +관동지방 +가라르지방 +히스이지방 +신오지방 +피크닉 +결정동굴 +팔데아지방 +미르시티 +포켓몬 연구소 +11번 와일드 존 +미르 미술관 +에투알 스쿨 +로즈 2번지 +노스사이드 스트리트 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_zh-Hans.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_zh-Hans.txt new file mode 100644 index 000000000..c6521c64a --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_zh-Hans.txt @@ -0,0 +1,33 @@ + +连接交换 +连接交换 +关都地区 +城都地区 +丰缘地区 +神奥地区 +遥远的土地 +---------- +合众地区 +卡洛斯地区 +宝可梦连接 +Pokémon GO +关都地区 +丰缘地区 +阿罗拉地区 +宝可度假地 +城都地区 +Pokémon HOME +关都地区 +伽勒尔地区 +洗翠地区 +神奥地区 +野餐 +结晶洞窟 +帕底亚地区 +密阿雷市 +宝可梦研究所 +11号野生特区 +密阿雷美术馆 +艾特瓦鲁学校 +蓉粉2号街区 +北侧大道 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_zh-Hant.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_zh-Hant.txt new file mode 100644 index 000000000..bd2996e6c --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_30000_zh-Hant.txt @@ -0,0 +1,33 @@ + +連線交換 +連線交換 +關都地區 +城都地區 +豐緣地區 +神奧地區 +遙遠的土地 +---------- +合眾地區 +卡洛斯地區 +寶可夢連結 +Pokémon GO +關都地區 +豐緣地區 +阿羅拉地區 +寶可度假地 +城都地區 +Pokémon HOME +關都地區 +伽勒爾地區 +洗翠地區 +神奧地區 +野餐 +結晶洞窟 +帕底亞地區 +密阿雷市 +寶可夢研究所 +11號野生特區 +密阿雷美術館 +艾特瓦魯學校 +蓉粉2號街區 +北側大道 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_de.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_de.txt new file mode 100644 index 000000000..3a5cd9921 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_de.txt @@ -0,0 +1,71 @@ + +Netter Ort +Ferner Ort +Pokémon-Film +Pokémon-Film 2024 +Pokémon-Film 2025 +Pokémon-Film 2026 +Pokémon-Film 2027 +Pokémon-Film 2028 +Pokémon-Zeichentrickserie +Pokémon Center +Pokémon Center Tohoku +WCS +WCS 2024 +WCS 2025 +WCS 2026 +WCS 2027 +WCS 2028 +Worlds +Worlds 2024 +Worlds 2025 +Worlds 2026 +Worlds 2027 +Worlds 2028 +VGE +VGE 2024 +VGE 2025 +VGE 2026 +VGE 2027 +VGE 2028 +Pokémon-Veranstaltung +Kampfturnier +Videospiel-Veranstaltung +Pokémon Daisuki Club +Pokémon-TV-Programm +Konzert +Online-Geschenk +PGL +Pokémon-Veranstaltung 2024 +Pokémon-Veranstaltung 2025 +Pokémon-Veranstaltung 2026 +Pokémon-Veranstaltung 2027 +Pokémon-Veranstaltung 2028 +Pokémon-Veranstaltung +Pokémon-Veranstaltung 2024 +Pokémon-Veranstaltung 2025 +Pokémon-Veranstaltung 2026 +Pokémon-Veranstaltung 2027 +Pokémon-Veranstaltung 2028 +PokéPark +PokéPark 2024 +PokéPark 2025 +PokéPark 2026 +PokéPark 2027 +PokéPark 2028 +Veranstaltung +GAME FREAK +Stadion +VGC +VGC 2024 +VGC 2025 +VGC 2026 +VGC 2027 +VGC 2028 +Virtual Console +Pokémon GO +Pokémon Bank +Pokémon-Geschäft +Demoversion +Pokéball Plus +Pokémon HOME \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_en.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_en.txt new file mode 100644 index 000000000..519738d0a --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_en.txt @@ -0,0 +1,71 @@ + +a lovely place +a faraway place +a Pokémon movie +a 2024 Pokémon movie +a 2025 Pokémon movie +a 2026 Pokémon movie +a 2027 Pokémon movie +a 2028 Pokémon movie +the Pokémon animated show +a Pokémon Center +Pokémon Center Tohoku +a WCS +WCS 2024 +WCS 2025 +WCS 2026 +WCS 2027 +WCS 2028 +Worlds +2024 Worlds +2025 Worlds +2026 Worlds +2027 Worlds +2028 Worlds +a VGE +VGE 2024 +VGE 2025 +VGE 2026 +VGE 2027 +VGE 2028 +a Pokémon event +a Battle Competition +a game event +the Pokémon Daisuki Club +a Pokémon TV program +a concert +an online present +the PGL +a 2024 Pokémon event +a 2025 Pokémon event +a 2026 Pokémon event +a 2027 Pokémon event +a 2028 Pokémon event +a Pokémon event +a 2024 Pokémon event +a 2025 Pokémon event +a 2026 Pokémon event +a 2027 Pokémon event +a 2028 Pokémon event +PokéPark +PokéPark 2024 +PokéPark 2025 +PokéPark 2026 +PokéPark 2027 +PokéPark 2028 +an event site +GAME FREAK +a stadium +a VGC event +the VGC 2024 +the VGC 2025 +the VGC 2026 +the VGC 2027 +the VGC 2028 +a Virtual Console game +Pokémon GO +Pokémon Bank +a Pokémon shop +a demo version +the Poké Ball Plus +Pokémon HOME \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_es-419.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_es-419.txt new file mode 100644 index 000000000..a2e1194ca --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_es-419.txt @@ -0,0 +1,146 @@ + +Lugar encantador +Lugar lejano +Película Pokémon +Película Pokémon 2024 +Película Pokémon 2025 +Película Pokémon 2026 +Película Pokémon 2027 +Película Pokémon 2028 +Dibujos animados Pokémon +Pokémon Center +Pokémon Center Tohoku +WCS +WCS 2024 +WCS 2025 +WCS 2026 +WCS 2027 +WCS 2028 +Worlds +Worlds 2024 +Worlds 2025 +Worlds 2026 +Worlds 2027 +Worlds 2028 +Evento de Videojuegos +Evento de Videojuegos 2024 +Evento de Videojuegos 2025 +Evento de Videojuegos 2026 +Evento de Videojuegos 2027 +Evento de Videojuegos 2028 +Evento Pokémon +Torneo +Evento de Videojuegos +Pokémon Daisuki Club +Programa sobre Pokémon +Concierto +Regalo en línea +Pokémon Global Link +Evento Pokémon 2024 +Evento Pokémon 2025 +Evento Pokémon 2026 +Evento Pokémon 2027 +Evento Pokémon 2028 +Evento Pokémon +Evento Pokémon 2024 +Evento Pokémon 2025 +Evento Pokémon 2026 +Evento Pokémon 2027 +Evento Pokémon 2028 +PokéPark +PokéPark 2024 +PokéPark 2025 +PokéPark 2026 +PokéPark 2027 +PokéPark 2028 +Evento +GAME FREAK +Estadio +VGC +VGC 2024 +VGC 2025 +VGC 2026 +VGC 2027 +VGC 2028 +Consola Virtual +Pokémon GO +Banco de Pokémon +Establecimiento Pokémon +Versión de prueba +Poké Ball Plus +Pokémon HOME +[~ 70] +[~ 71] +[~ 72] +[~ 73] +[~ 74] +[~ 75] +[~ 76] +[~ 77] +[~ 78] +[~ 79] +[~ 80] +[~ 81] +[~ 82] +[~ 83] +[~ 84] +[~ 85] +[~ 86] +[~ 87] +[~ 88] +[~ 89] +[~ 90] +[~ 91] +[~ 92] +[~ 93] +[~ 94] +[~ 95] +[~ 96] +[~ 97] +[~ 98] +[~ 99] +[~ 100] +[~ 101] +[~ 102] +[~ 103] +[~ 104] +[~ 105] +[~ 106] +[~ 107] +[~ 108] +[~ 109] +[~ 110] +[~ 111] +[~ 112] +[~ 113] +[~ 114] +[~ 115] +[~ 116] +[~ 117] +[~ 118] +[~ 119] +[~ 120] +[~ 121] +[~ 122] +[~ 123] +[~ 124] +[~ 125] +[~ 126] +[~ 127] +[~ 128] +[~ 129] +[~ 130] +[~ 131] +[~ 132] +[~ 133] +[~ 134] +[~ 135] +[~ 136] +[~ 137] +[~ 138] +[~ 139] +[~ 140] +[~ 141] +[~ 142] +[~ 143] +[~ 144] \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_es.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_es.txt new file mode 100644 index 000000000..281a23f48 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_es.txt @@ -0,0 +1,71 @@ + +Lugar encantador +Lugar lejano +Película Pokémon +Película Pokémon 2024 +Película Pokémon 2025 +Película Pokémon 2026 +Película Pokémon 2027 +Película Pokémon 2028 +Dibujos animados Pokémon +Pokémon Center +Pokémon Center Tohoku +WCS +WCS 2024 +WCS 2025 +WCS 2026 +WCS 2027 +WCS 2028 +Worlds +Worlds 2024 +Worlds 2025 +Worlds 2026 +Worlds 2027 +Worlds 2028 +Evento de Videojuegos +Evento de Videojuegos 2024 +Evento de Videojuegos 2025 +Evento de Videojuegos 2026 +Evento de Videojuegos 2027 +Evento de Videojuegos 2028 +Evento Pokémon +Torneo +Evento de Videojuegos +Pokémon Daisuki Club +Programa sobre Pokémon +Concierto +Regalo en línea +Pokémon Global Link +Evento Pokémon 2024 +Evento Pokémon 2025 +Evento Pokémon 2026 +Evento Pokémon 2027 +Evento Pokémon 2028 +Evento Pokémon +Evento Pokémon 2024 +Evento Pokémon 2025 +Evento Pokémon 2026 +Evento Pokémon 2027 +Evento Pokémon 2028 +PokéPark +PokéPark 2024 +PokéPark 2025 +PokéPark 2026 +PokéPark 2027 +PokéPark 2028 +Evento +GAME FREAK +Estadio +VGC +VGC 2024 +VGC 2025 +VGC 2026 +VGC 2027 +VGC 2028 +Consola Virtual +Pokémon GO +Banco de Pokémon +Establecimiento Pokémon +Versión de prueba +Poké Ball Plus +Pokémon HOME \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_fr.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_fr.txt new file mode 100644 index 000000000..1c357dec4 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_fr.txt @@ -0,0 +1,71 @@ + +Endroit superbe +Endroit lointain +Film Pokémon +Film Pokémon 2024 +Film Pokémon 2025 +Film Pokémon 2026 +Film Pokémon 2027 +Film Pokémon 2028 +Dessin animé Pokémon +Pokémon Center +Pokémon Center Tohoku +WCS +WCS 2024 +WCS 2025 +WCS 2026 +WCS 2027 +WCS 2028 +Worlds +Worlds 2024 +Worlds 2025 +Worlds 2026 +Worlds 2027 +Worlds 2028 +Évènement Jeu Vidéo +Évènement Jeu Vidéo 2024 +Évènement Jeu Vidéo 2025 +Évènement Jeu Vidéo 2026 +Évènement Jeu Vidéo 2027 +Évènement Jeu Vidéo 2028 +Évènement Pokémon +Compétition +Évènement +Pokémon Daisuki Club +Émission Pokémon +Concert +Cadeau téléchargeable +Pokémon Global Link +Évènement Pokémon 2024 +Évènement Pokémon 2025 +Évènement Pokémon 2026 +Évènement Pokémon 2027 +Évènement Pokémon 2028 +Évènement Pokémon +Évènement Pokémon 2024 +Évènement Pokémon 2025 +Évènement Pokémon 2026 +Évènement Pokémon 2027 +Évènement Pokémon 2028 +PokéPark +PokéPark 2024 +PokéPark 2025 +PokéPark 2026 +PokéPark 2027 +PokéPark 2028 +Lieu d’évènement +GAME FREAK +Stade +VGC +VGC 2024 +VGC 2025 +VGC 2026 +VGC 2027 +VGC 2028 +Console virtuelle +Pokémon GO +Banque Pokémon +Magasin Pokémon +Démo +Poké Ball Plus +Pokémon HOME \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_it.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_it.txt new file mode 100644 index 000000000..380663bf6 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_it.txt @@ -0,0 +1,71 @@ + +luogo grazioso +luogo remoto +film Pokémon +film Pokémon (2024) +film Pokémon (2025) +film Pokémon (2026) +film Pokémon (2027) +film Pokémon (2028) +cartone animato Pokémon +Pokémon Center +Pokémon Center Tohoku +WCS +WCS 2024 +WCS 2025 +WCS 2026 +WCS 2027 +WCS 2028 +Worlds +Worlds 2024 +Worlds 2025 +Worlds 2026 +Worlds 2027 +Worlds 2028 +VGE +VGE (2024) +VGE (2025) +VGE (2026) +VGE (2027) +VGE (2028) +evento Pokémon +gara +evento di gioco +Pokémon Daisuki Club +programma TV Pokémon +concerto +regalo online +PGL +evento Pokémon (2024) +evento Pokémon (2025) +evento Pokémon (2026) +evento Pokémon (2027) +evento Pokémon (2028) +evento Pokémon +evento Pokémon (2024) +evento Pokémon (2025) +evento Pokémon (2026) +evento Pokémon (2027) +evento Pokémon (2028) +PokéPark +PokéPark (2024) +PokéPark (2025) +PokéPark (2026) +PokéPark (2027) +PokéPark (2028) +evento +GAME FREAK +stadio +VGC +VGC 2024 +VGC 2025 +VGC 2026 +VGC 2027 +VGC 2028 +Virtual Console +Pokémon GO +Banca Pokémon +negozio Pokémon +demo +Poké Ball Plus +Pokémon HOME \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_ja.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_ja.txt new file mode 100644 index 000000000..6b1c1b2f2 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_ja.txt @@ -0,0 +1,71 @@ + +すてきな場所 +遠い場所 +ポケモン映画 +ポケモン映画24 +ポケモン映画25 +ポケモン映画26 +ポケモン映画27 +ポケモン映画28 +ポケモンアニメ +ポケモンセンター +PCトウホク +WCS +WCS2024 +WCS2025 +WCS2026 +WCS2027 +WCS2028 +Worlds +Worlds2024 +Worlds2025 +Worlds2026 +Worlds2027 +Worlds2028 +VGE +VGE2024 +VGE2025 +VGE2026 +VGE2027 +VGE2028 +ポケモンイベント +バトル大会 +ゲームイベント +だいすきクラブ +ポケモン番組 +コンサート +オンラインプレゼント +PGL +ポケモンイベント24 +ポケモンイベント25 +ポケモンイベント26 +ポケモンイベント27 +ポケモンイベント28 +ポケモンフェスタ +ポケモンフェスタ24 +ポケモンフェスタ25 +ポケモンフェスタ26 +ポケモンフェスタ27 +ポケモンフェスタ28 +ポケパーク +ポケパーク2024 +ポケパーク2025 +ポケパーク2026 +ポケパーク2027 +ポケパーク2028 +イベント会場 +ゲームフリーク +スタジアム +VGC +VGC2024 +VGC2025 +VGC2026 +VGC2027 +VGC2028 +バーチャルコンソール +Pokémon GO +ポケモンバンク +ポケモンのショップ +体験版 +モンスターボール Plus +Pokémon HOME \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_ko.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_ko.txt new file mode 100644 index 000000000..2ab673f03 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_ko.txt @@ -0,0 +1,71 @@ + +근사한 장소 +먼 곳 +포켓몬영화 +포켓몬영화24 +포켓몬영화25 +포켓몬영화26 +포켓몬영화27 +포켓몬영화28 +포켓몬 애니메이션 +포켓몬센터 +PC도호쿠 +WCS +WCS2024 +WCS2025 +WCS2026 +WCS2027 +WCS2028 +Worlds +Worlds2024 +Worlds2025 +Worlds2026 +Worlds2027 +Worlds2028 +VGE +VGE2024 +VGE2025 +VGE2026 +VGE2027 +VGE2028 +포켓몬이벤트 +배틀 대회 +게임 이벤트 +the Pokémon Daisuki Club +포켓몬 방송 +콘서트 +온라인 선물 +PGL +포켓몬이벤트24 +포켓몬이벤트25 +포켓몬이벤트26 +포켓몬이벤트27 +포켓몬이벤트28 +포켓몬페스타 +포켓몬페스타24 +포켓몬페스타25 +포켓몬페스타26 +포켓몬페스타27 +포켓몬페스타28 +포켓파크 +포켓파크2024 +포켓파크2025 +포켓파크2026 +포켓파크2027 +포켓파크2028 +이벤트회장 +게임프리크 +스타디움 +VGC +VGC2024 +VGC2025 +VGC2026 +VGC2027 +VGC2028 +버추얼 콘솔 +Pokémon GO +포켓몬 뱅크 +a Pokémon shop +체험판 +몬스터볼 Plus +Pokémon HOME \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_zh-Hans.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_zh-Hans.txt new file mode 100644 index 000000000..ac3cced47 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_zh-Hans.txt @@ -0,0 +1,71 @@ + +美丽的地方 +遥远的地方 +宝可梦电影 +宝可梦电影24 +宝可梦电影25 +宝可梦电影26 +宝可梦电影27 +宝可梦电影28 +宝可梦动画片 +宝可梦中心 +东北PC +WCS +WCS2024 +WCS2025 +WCS2026 +WCS2027 +WCS2028 +Worlds +Worlds2024 +Worlds2025 +Worlds2026 +Worlds2027 +Worlds2028 +VGE +VGE2024 +VGE2025 +VGE2026 +VGE2027 +VGE2028 +宝可梦活动 +对战大赛 +游戏活动 +发烧友俱乐部 +宝可梦节目 +音乐会 +在线礼物 +PGL +宝可梦活动24 +宝可梦活动25 +宝可梦活动26 +宝可梦活动27 +宝可梦活动28 +宝可梦庆典 +宝可梦庆典24 +宝可梦庆典25 +宝可梦庆典26 +宝可梦庆典27 +宝可梦庆典28 +宝可公园 +宝可公园2024 +宝可公园2025 +宝可公园2026 +宝可公园2027 +宝可公园2028 +活动会场 +GAME FREAK +竞技场 +VGC +VGC2024 +VGC2025 +VGC2026 +VGC2027 +VGC2028 +Virtual Console +Pokémon GO +宝可梦虚拟银行 +宝可梦的店 +体验版 +精灵球 Plus +Pokémon HOME \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_zh-Hant.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_zh-Hant.txt new file mode 100644 index 000000000..099d16bc1 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_40000_zh-Hant.txt @@ -0,0 +1,71 @@ + +美麗的地方 +遙遠的地方 +寶可夢電影 +寶可夢電影24 +寶可夢電影25 +寶可夢電影26 +寶可夢電影27 +寶可夢電影28 +寶可夢動畫片 +寶可夢中心 +東北PC +WCS +WCS2024 +WCS2025 +WCS2026 +WCS2027 +WCS2028 +Worlds +Worlds2024 +Worlds2025 +Worlds2026 +Worlds2027 +Worlds2028 +VGE +VGE2024 +VGE2025 +VGE2026 +VGE2027 +VGE2028 +寶可夢活動 +對戰大賽 +遊戲活動 +發燒友俱樂部 +寶可夢節目 +音樂會 +線上禮物 +PGL +寶可夢活動24 +寶可夢活動25 +寶可夢活動26 +寶可夢活動27 +寶可夢活動28 +寶可夢慶典 +寶可夢慶典24 +寶可夢慶典25 +寶可夢慶典26 +寶可夢慶典27 +寶可夢慶典28 +寶可公園 +寶可公園2024 +寶可公園2025 +寶可公園2026 +寶可公園2027 +寶可公園2028 +活動會場 +GAME FREAK +競技場 +VGC +VGC2024 +VGC2025 +VGC2026 +VGC2027 +VGC2028 +Virtual Console +Pokémon GO +寶可夢虛擬銀行 +寶可夢的店 +體驗版 +精靈球 Plus +Pokémon HOME \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_de.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_de.txt new file mode 100644 index 000000000..a66b2c9da --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_de.txt @@ -0,0 +1,6 @@ + +Ferne Person +Hortleiterinnen +Schatzsucher +Dame der Heißen Quellen +Illumina City \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_en.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_en.txt new file mode 100644 index 000000000..a15b5dd28 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_en.txt @@ -0,0 +1,6 @@ + +someone far away +a Nursery worker +a treasure hunter +an old hot-springs visitor +Lumiose City \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_es-419.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_es-419.txt new file mode 100644 index 000000000..bd5610b15 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_es-419.txt @@ -0,0 +1,6 @@ + +Persona lejana +Cuidados Pokémon +Buscatesoros +Anciana del Balneario +Ciudad Luminalia \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_es.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_es.txt new file mode 100644 index 000000000..bd5610b15 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_es.txt @@ -0,0 +1,6 @@ + +Persona lejana +Cuidados Pokémon +Buscatesoros +Anciana del Balneario +Ciudad Luminalia \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_fr.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_fr.txt new file mode 100644 index 000000000..9c44b9f64 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_fr.txt @@ -0,0 +1,6 @@ + +Personne lointaine +Responsable de la Garderie +Chercheur de Trésors +Dame des Eaux Thermales +Illumis \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_it.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_it.txt new file mode 100644 index 000000000..486456cb6 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_it.txt @@ -0,0 +1,6 @@ + +persona lontana +Ostello Pokémon +Cercatesori +vecchina delle terme +Luminopoli \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_ja.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_ja.txt new file mode 100644 index 000000000..73e48b6a6 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_ja.txt @@ -0,0 +1,6 @@ + +遠くにいる人 +あずかり屋さん +トレジャーハンター +おんせんばあさん +ミアレシティ \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_ko.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_ko.txt new file mode 100644 index 000000000..2aedee3e9 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_ko.txt @@ -0,0 +1,6 @@ + +멀리 있는 사람 +맡기미집 +트레져헌터 +온천 할머니 +미르시티 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_zh-Hans.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_zh-Hans.txt new file mode 100644 index 000000000..d155c41a4 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_zh-Hans.txt @@ -0,0 +1,6 @@ + +远处的人 +寄放屋 +寻宝猎人 +温泉婆婆 +密阿雷市 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_zh-Hant.txt b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_zh-Hant.txt new file mode 100644 index 000000000..c47f66a43 --- /dev/null +++ b/PKHeX.Core/Resources/text/locations/gen9a/text_za_60000_zh-Hant.txt @@ -0,0 +1,6 @@ + +遠方的人 +寄放屋 +尋寶獵人 +溫泉婆婆 +密阿雷市 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/de/text_Forms_de.txt b/PKHeX.Core/Resources/text/other/de/text_Forms_de.txt index ae7b2229d..5210035eb 100644 --- a/PKHeX.Core/Resources/text/other/de/text_Forms_de.txt +++ b/PKHeX.Core/Resources/text/other/de/text_Forms_de.txt @@ -1134,4 +1134,6 @@ Fundament Kostbarkeits Edle Terastal -Stellar \ No newline at end of file +Stellar +Mittelgroße +Extragroße \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/de/text_Games_de.txt b/PKHeX.Core/Resources/text/other/de/text_Games_de.txt index 3d5d9690b..189afee21 100644 --- a/PKHeX.Core/Resources/text/other/de/text_Games_de.txt +++ b/PKHeX.Core/Resources/text/other/de/text_Games_de.txt @@ -1,4 +1,4 @@ - + Saphir Rubin Smaragd @@ -49,4 +49,5 @@ Legenden: Arceus Strahlender Diamant Leuchtende Perle Karmesin -Purpur \ No newline at end of file +Purpur +Legenden: Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/de/text_Moves_de.txt b/PKHeX.Core/Resources/text/other/de/text_Moves_de.txt index 9ea5808fe..dcd3c8502 100644 --- a/PKHeX.Core/Resources/text/other/de/text_Moves_de.txt +++ b/PKHeX.Core/Resources/text/other/de/text_Moves_de.txt @@ -917,4 +917,5 @@ Frustflamme Donnerstoß Psycholärm Schnellkonter -Giftkettung \ No newline at end of file +Giftkettung +Tilgungslicht \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/en/text_Forms_en.txt b/PKHeX.Core/Resources/text/other/en/text_Forms_en.txt index 04ce4cbad..ba685244e 100644 --- a/PKHeX.Core/Resources/text/other/en/text_Forms_en.txt +++ b/PKHeX.Core/Resources/text/other/en/text_Forms_en.txt @@ -1134,4 +1134,6 @@ Cornerstone Artisan Masterpiece Terastal -Stellar \ No newline at end of file +Stellar +Medium +Jumbo \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/en/text_Games_en.txt b/PKHeX.Core/Resources/text/other/en/text_Games_en.txt index 2dabd0f4b..1dd701953 100644 --- a/PKHeX.Core/Resources/text/other/en/text_Games_en.txt +++ b/PKHeX.Core/Resources/text/other/en/text_Games_en.txt @@ -49,4 +49,5 @@ Legends: Arceus Brilliant Diamond Shining Pearl Scarlet -Violet \ No newline at end of file +Violet +Legends: Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/en/text_Moves_en.txt b/PKHeX.Core/Resources/text/other/en/text_Moves_en.txt index 7a514259a..17422ea5b 100644 --- a/PKHeX.Core/Resources/text/other/en/text_Moves_en.txt +++ b/PKHeX.Core/Resources/text/other/en/text_Moves_en.txt @@ -917,4 +917,5 @@ Temper Flare Supercell Slam Psychic Noise Upper Hand -Malignant Chain \ No newline at end of file +Malignant Chain +Nihil Light \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Abilities_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Abilities_es-419.txt new file mode 100644 index 000000000..44a63809a --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Abilities_es-419.txt @@ -0,0 +1,311 @@ +— +Hedor +Llovizna +Impulso +Armadura Batalla +Robustez +Humedad +Flexibilidad +Velo Arena +Elec. Estática +Absorbe Elec +Absorbe Agua +Despiste +Aclimatación +Ojo Compuesto +Insomnio +Cambio Color +Inmunidad +Absorbe Fuego +Polvo Escudo +Ritmo Propio +Ventosas +Intimidación +Sombra Trampa +Piel Tosca +Superguarda +Levitación +Efecto Espora +Sincronía +Cuerpo Puro +Cura Natural +Pararrayos +Dicha +Nado Rápido +Clorofila +Iluminación +Calco +Potencia +Punto Tóxico +Fuerza Mental +Escudo Magma +Velo Agua +Imán +Insonorizar +Cura Lluvia +Chorro Arena +Presión +Sebo +Madrugar +Cuerpo Llama +Fuga +Vista Lince +Corte Fuerte +Recogida +Pereza +Entusiasmo +Gran Encanto +Más +Menos +Predicción +Viscosidad +Mudar +Agallas +Escama Especial +Viscosecreción +Espesura +Mar Llamas +Torrente +Enjambre +Cabeza Roca +Sequía +Trampa Arena +Espíritu Vital +Humo Blanco +Energía Pura +Caparazón +Esclusa de Aire +Tumbos +Electromotor +Rivalidad +Impasible +Manto Níveo +Gula +Irascible +Liviano +Ignífugo +Simple +Piel Seca +Descarga +Puño Férreo +Antídoto +Adaptable +Encadenado +Hidratación +Poder Solar +Pies Rápidos +Normalidad +Francotirador +Muro Mágico +Indefenso +Rezagado +Experto +Defensa Hoja +Zoquete +Rompemoldes +Afortunado +Detonación +Anticipación +Alerta +Ignorante +Cromolente +Filtro +Inicio Lento +Intrépido +Colector +Gélido +Roca Sólida +Nevada +Recogemiel +Cacheo +Audaz +Multitipo +Don Floral +Mal Sueño +Hurto +Potencia Bruta +Respondón +Nerviosismo +Competitivo +Flaqueza +Cuerpo Maldito +Alma Cura +Compiescolta +Armadura Frágil +Metal Pesado +Metal Liviano +Multiescamas +Ímpetu Tóxico +Ímpetu Ardiente +Cosecha +Telepatía +Veleta +Funda +Toque Tóxico +Regeneración +Sacapecho +Ímpetu Arena +Piel Milagro +Cálculo Final +Ilusión +Impostor +Allanamiento +Momia +Autoestima +Justiciero +Cobardía +Espejo Mágico +Herbívoro +Bromista +Poder Arena +Punta Acero +Modo Daruma +Tinovictoria +Turbollama +Terravoltaje +Velo Aroma +Velo Flor +Carrillo +Mutatipo +Pelaje Recio +Prestidigitador +Antibalas +Tenacidad +Mandíbula Fuerte +Piel Helada +Velo Dulce +Cambio Táctico +Alas Vendaval +Megadisparador +Manto Frondoso +Simbiosis +Garra Dura +Piel Feérica +Baba +Piel Celeste +Amor Filial +Aura Oscura +Aura Feérica +Rompeaura +Mar del Albor +Tierra del Ocaso +Ráfaga Delta +Firmeza +Huida +Retirada +Hidrorrefuerzo +Ensañamiento +Escudo Limitado +Vigilante +Pompa +Acero Templado +Cólera +Quitanieves +Remoto +Voz Fluida +Primer Auxilio +Piel Eléctrica +Cola Surf +Banco +Disfraz +Fuerte Afecto +Agrupamiento +Corrosión +Letargo Perenne +Regia Presencia +Revés +Pareja de Baile +Batería +Peluche +Cuerpo Vívido +Coránima +Rizos Rebeldes +Receptor +Reacción Química +Ultraimpulso +Sistema Alfa +Electrogénesis +Psicogénesis +Nebulogénesis +Herbogénesis +Guardia Metálica +Guardia Espectro +Armadura Prisma +Fuerza Cerebral +Espada Indómita +Escudo Recio +Líbero +Recogebolas +Pelusa +Hélice Caudal +Coraza Reflejo +Tragamisil +Acérrimo +Combustible +Punk Rock +Expulsarena +Escama de Hielo +Maduración +Cara de Hielo +Fuente Energía +Mimetismo +Antibarrera +Alma Acerada +Cuerpo Mortal +Alma Errante +Monotema +Gas Reactivo +Velo Pastel +Mutapetito +Mano Rápida +Puño Invisible +Medicina Extraña +Transistor +Mandíbula Dragón +Relincho Blanco +Relincho Negro +Unidad Ecuestre +Unidad Ecuestre +Olor Persistente +Disemillar +Termoconversión +Coraza Ira +Sal Purificadora +Cuerpo Horneado +Surcavientos +Perro Guardián +Transportarrocas +Energía Eólica +Cambio Heroico +Comandar +Dinamo +Paleosíntesis +Carga Cuark +Cuerpo Áureo +Caldero Debacle +Espada Debacle +Tablilla Debacle +Abalorio Debacle +Latido Oricalco +Motor Hadrónico +Oportunista +Rumia +Cortante +General Supremo +Unísono +Capa Tóxica +Cola Armadura +Geofagia +Poder Fúngico +Hospitalidad +Ojo Mental +Evocarrecuerdos +Evocarrecuerdos +Evocarrecuerdos +Evocarrecuerdos +Cadena Tóxica +Néctar Dulce +Teracambio +Teracaparazón +Teraformación 0 +Títere Tóxico \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Character_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Character_es-419.txt new file mode 100644 index 000000000..a7a0b5d99 --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Character_es-419.txt @@ -0,0 +1,30 @@ +Le encanta comer. +A menudo se duerme. +Duerme mucho. +Suele desordenar cosas. +Le gusta relajarse. +Está orgulloso de su fuerza. +Le gusta revolverse. +A veces se enfada. +Le gusta luchar. +Tiene mal genio. +Se caracteriza por su cuerpo resistente. +Es un buen fajador. +Es muy persistente. +Se caracteriza por ser muy resistente. +Es muy perseverante. +Le gusta correr. +Siempre tiene el oído alerta. +Resulta algo impetuoso y bobo. +Es un poco payaso. +Huye rápido. +Es extremadamente curioso. +Le gusta hacer travesuras. +Es muy astuto. +A menudo está en Babia. +Es muy melindroso. +Se distingue por ser muy voluntarioso. +Es algo orgulloso. +Es muy insolente. +Odia perder. +Es un poco cabezota. \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Forms_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Forms_es-419.txt new file mode 100644 index 000000000..a2c707d91 --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Forms_es-419.txt @@ -0,0 +1,1139 @@ +Picoreja + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kyogre +Groudon + + +Normal + + + + + + + + + + + + + + + + + + + + + + + + + +Planta +Planta + + + + + + + +Encapotado +Oeste +Oeste + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Modificada + + + + +Tierra + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Raya Roja + + + + +Normal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Primavera +Primavera + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Avatar +Avatar + + +Avatar +Kyurem +Habitual +Lírica + + + + + + + + + + + + + + + + + +Polar + + +Roja +Roja +Roja + + + + +Salvaje + +Macho + + +Escudo + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Normal +Normal + + + + +Relajado + +50% + +Contenido + + + + + + + + +Roquera +Aristócrata +Superstar +Erudita +Enmascarada +Coqueta + + + + + + +Apasionado + + + +Diurna +Individual + + + + + + + + + + + + + + + + + + + + + + + + + + +Normal +M-Rojo + + + +Encubierta + + + + + + + + + + + + + + + + + + + + + + + + + +Mega +Mega X +Mega Y +Mega +Mega +Mega +Alola +Alola + +Original +Hoenn +Sinnoh +Teselia +Kalos +Alola +Alola +Alola +Alola +Alola +Alola +Alola +Alola +Alola +Alola +Mega +Alola +Alola +Alola +Mega +Alola +Alola +Mega +Alola +Alola +Mega +Mega +Mega +Mega +Mega +Mega +Mega + + + + +Aguda + + + + + + + + + + + + + + + + + + + +Crema de Vainilla + + +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Sol +Lluvia +Nieve +Mega +Mega +Mega +Mega +Mega +Mega +Mega +Primigenia +Primigenia +Mega +Ataque +Defensa +Velocidad +Arena +Basura +Arena +Basura +Soleado +Mar Este +Mar Este +Mega +Mega +Mega +Mega +Mega +Calor +Lavado +Frío +Ventilador +Corte +Origen +Cielo + + + + + + + + + + + + + + + + + +Mega +Raya Azul +Daruma +Verano +Otoño +Invierno +Verano +Otoño +Invierno +Tótem +Tótem +Tótem +Blanco +Negro +Brío +Danza + + + + + +Ash +Taiga +Tundra +Continental +Vergel +Oriental +Floral +Moderno +Marino +Isleño +Estepa +Desierto +Oasis +Monzón +Pantano +Solar +Océano +Jungla +Fantasía +Poké Ball +Amarilla +Naranja +Azul +Blanca +Amarilla +Naranja +Azul +Blanca +Eterna +Amarilla +Naranja +Azul +Blanca +Corazón +Estrella +Rombo +Señorita +Dama +Caballero +Aristocrático +Kabuki +Faraónico +Hembra +Filo +Pequeño +Grande +Extragrande +Pequeño +Grande +Extragrande +Activo +10% +10% +50% +Completa +Mega +Desatado + + +Animado +Plácido +Refinado +Nocturna +Banco + + +Lucha +Volador +Veneno +Tierra +Roca +Bicho +Fantasma +Acero +Fuego +Agua +Planta +Eléctrico +Psíquico +Hielo +Dragón +Siniestro +Hada +M-Naranja +M-Amarillo +M-Verde +M-Azul +M-Añil +M-Violeta +N-Rojo +N-Naranja +N-Amarillo +N-Verde +N-Azul +N-Añil +N-Violeta +Descubierta + + + +Vetusto +Gorra Compañero +Forma Crepuscular +Melena Crepuscular +Alas del Alba +Ultra +Galar +Gigamax +Tragatodo +Engulletodo +Grave +Rosa +de Té +de Menta +de Limón +Salada +Rosa +Caramelo +Tres Sabores +Cara Deshielo +Voraz +Suprema +Infinito +Trotamundos +Brusco +Fluido +Papá +Glacial +Espectral +Cara de Hielo +Saciada +Guerrero +Hisui +Señor +Señora +Legendaria +Falsificada +Genuina +Paldea +Binodular +Trinodular +Ingenua +Heroica +Familia de Tres +Familia de Cuatro +Curvada +Lánguida +Recta +Verde +Cofre +Andante +Plena +Limitada +Carrera +Nado +Planeo +Pleno +Limitado +Conducción +Flote +Planeo +Combatiente +Ardiente +Acuática +Turquesa +Fraudulenta +Mediocre +Luna Carmesí +Fuente +Horno +Cimiento +Opulenta +Exquisita +Teracristal +Astral +Mediana +Enorme \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Games_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Games_es-419.txt new file mode 100644 index 000000000..7f08fc2dd --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Games_es-419.txt @@ -0,0 +1,53 @@ + +Zafiro +Rubí +Esmeralda +RojoFuego +VerdeHoja + +Oro HeartGold +Plata SoulSilver + +Diamante +Perla +Platino + + +Colosseum/XD +Battle Revolution + + + +Blanca +Negra +Blanca 2 +Negra 2 +X +Y +Zafiro Alfa +Rubí Omega + + +Sol +Luna +Ultrasol +Ultraluna +GO +Roja +Azul [INT]/Verde [JP] +Azul [JP] +Amarilla +Oro +Plata +Cristal +Let's Go, Pikachu! +Let's Go, Eevee! +Espada +Escudo + +Leyendas: Arceus +Diamante Brillante +Perla Reluciente +Escarlata +Púrpura +Leyendas: Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_GroundTile_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_GroundTile_es-419.txt new file mode 100644 index 000000000..f328b747a --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_GroundTile_es-419.txt @@ -0,0 +1,25 @@ +Ninguno +Golpe roca (HGSS) +Hierba Alta + +Dialga/Palkia +Cueva/Sala del Origen + +Surfeando/Pescando + +Edificio/Misticristal +Pantano/Safari + +Inicial/Fósil/Regalo (DP) + + + + + + + + + + +Mundo Distorsión (Pt) +Inicial/Fósil/Regalo (Pt/DP Trio) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Moves_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Moves_es-419.txt new file mode 100644 index 000000000..c95968a43 --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Moves_es-419.txt @@ -0,0 +1,921 @@ +— +Destructor +Golpe Karate +Doble Bofetón +Puño Cometa +Megapuño +Día de Pago +Puño Fuego +Puño Hielo +Puño Trueno +Arañazo +Fuerza de Garra +Guillotina +Viento Cortante +Danza de Espadas +Corte +Ráfaga de Aire +Ataque de Ala +Torbellino +Vuelo +Atadura +Golpazo +Látigo Cepa +Pisotón +Doble Patada +Megapatada +Patada Salto +Patada Giro +Ataque Arena +Golpe Cabeza +Ataque Cuerno +Ataque Furia +Cuerno Taladro +Tacleada +Golpe de Cuerpo +Constricción +Derribo +Golpiza +Doble Filo +Látigo de Cola +Piquete Venenoso +Doble Aguijón +Misil Aguja +Malicioso +Mordida +Gruñido +Rugido +Canto +Supersónico +Explosión Sónica +Anulación +Ácido +Brasas +Lanzallamas +Neblina +Chorro de Agua +Hidrobomba +Surf +Rayo de Hielo +Ventisca +Psicorrayo +Rayo Burbuja +Rayo Aurora +Hiperrayo +Picotazo +Pico Taladro +Sumisión +Patada Baja +Contraataque +Sísmico +Fuerza +Absorción +Megadrenado +Drenadoras +Crecimiento +Hojas Navaja +Rayo Solar +Polvo Venenoso +Paralizador +Somnífero +Danza de Pétalos +Disparo de Seda +Furia Dragón +Giro Fuego +Impactrueno +Atactrueno +Onda Trueno +Trueno +Lanzarrocas +Terremoto +Fisura +Excavar +Tóxico +Confusión +Fuerza Psíquica +Hipnosis +Meditación +Agilidad +Ataque Rápido +Furia +Teletransporte +Tinieblas +Mímica +Chillido +Doble Equipo +Recuperación +Fortaleza +Reducción +Pantalla de Humo +Rayo de Confusión +Refugio +Hacerse Bolita +Barrera +Pantalla de Luz +Niebla +Reflejo +Centrar Energía +Venganza +Metrónomo +Espejo +Autodestrucción +Bomba Huevo +Lengüetazo +Humo +Residuos +Maza de Hueso +Llamarada +Cascada +Tenaza +Meteoros +Cabezazo +Cañón de Púas +Restricción +Amnesia +Kinético +Ovocuración +Pat. Salto Alto +Fulmirada +Comesueños +Gas Venenoso +Bombardeo +Chupavidas +Beso Amoroso +Ataque Celestial +Transformación +Burbuja +Puño Mareador +Esporas +Destello +Psicoonda +Salpicadura +Armadura Ácida +Martillazo +Explosión +Garras Furiosas +Huesomerang +Descanso +Avalancha +Hipercolmillo +Afilar +Conversión +Triataque +Supercolmillo +Cuchillada +Sustituto +Forcejeo +Boceto +Triple Patada +Ladrón +Telaraña +Telépata +Pesadilla +Rueda Ígnea +Ronquido +Maldición +Azote +Conversión 2 +Aerochorro +Esporagodón +Inversión +Rencor +Polvo de Nieve +Protección +Superpuño +Cara Aterradora +Ataque Finta +Beso Dulce +Tambor +Bomba Lodo +Bofetón Lodo +Octazuca +Púas +Electrocañón +Visión +Lazo del Destino +Canto Mortal +Viento Helado +Detección +Hueso Veloz +Fijar Blanco +Enfado +Tormenta Arena +Gigadrenado +Aguante +Encanto +Rodada +Falsa Bofetada +Fanfarronear +Licuado +Chispa +Corte Furia +Ala de Acero +Mal de Ojo +Atracción +Sonámbulo +Cascabel Sanador +Retribución +Obsequio +Frustración +Velo Sagrado +Dividedolor +Fuego Sagrado +Magnitud +Puño Dinámico +Megacuerno +Aliento Dragón +Relevo +Otra Vez +Persecución +Giro Rápido +Dulce Aroma +Cola de Hierro +Garra de Metal +Llave Vital +Sol Matutino +Fotosíntesis +Luz Lunar +Poder Oculto +Golpe Cruzado +Tornado +Danza de Lluvia +Día Soleado +Triturar +Escudo Espejo +Autosugestión +Veloc. Extrema +Poder Antiguo +Bola Sombra +Premonición +Golpe Roca +Remolino +Paliza +Sorpresa +Alboroto +Reserva +Escupida +Tragar +Onda Ígnea +Granizo +Tormento +Halago +Fuego Fatuo +Recuerdo +Fachada +Puño Centrado +Estímulo +Señuelo +Adaptación +Carga +Provocación +Refuerzos +Truco +Imitación +Deseo +Ayuda +Arraigo +Fuerza Bruta +Capa Mágica +Reciclaje +Desquite +Karatazo +Bostezo +Desarme +Esfuerzo +Estallido +Intercambio +Sellar +Alivio +Rabia +Robo +Poder Secreto +Buceo +Empujón +Camuflaje +Luminicola +Resplandor +Bola Neblina +Danza de Plumas +Danza del Caos +Patada Ígnea +Chapoteo de Lodo +Bola Hielo +Brazo Aguja +Relajar +Hipervoz +Colmillo Veneno +Garra Brutal +Anillo de Fuego +Hidrocañón +Puño Meteoro +Impresión +Meteorobola +Aromaterapia +Llanto Falso +Aire Cortante +Supercalor +Rastreo +Tumba de Rocas +Viento Plateado +Sonido Metálico +Silbato de Hoja +Cosquillas +Masa Cósmica +Columna de Agua +Rayo Señal +Puño Sombra +Extrasensorial +Corte Elevado +Tumba de Arena +Frío Extremo +Agua Lodosa +Bala Semilla +As Aéreo +Lanza de Hielo +Defensa Hierro +Bloqueo +Aullido +Garra Dragón +Planta Feroz +Corpulencia +Rebote +Disparo de Lodo +Cola Venenosa +Antojo +Tacleada de Voltios +Hojas Mágicas +Chapoteo de Agua +Paz Mental +Hoja Aguda +Danza de Dragón +Pedrada +Onda de Choque +Pulso de Agua +Deseo Final +Psicoimpulso +Respiro +Gravedad +Gran Ojo +Despabilador +Brazo Martillo +Giro Bola +Deseo Sanador +Agua Salada +Don Natural +Amago +Picoteo +Viento Afín +Acupresión +Expl. Metálica +Ida y Vuelta +Cuerpo a Cuerpo +Revancha +Garantía +Embargo +Lanzamiento +Psicocambio +As Oculto +Anticuración +Apretón +Truco Fuerza +Ácido Gástrico +Cántico Suerte +Yo Primero +Copión +Cambiafuerza +Cambiadefensa +Castigo +Último Recurso +Abatidoras +Golpe Bajo +Púas Tóxicas +Cambiaalmas +Acuaanillo +Superimán +Erupción +Fuerza de Palma +Aura Esfera +Pulimento +Golpe Venenoso +Pulso Oscuro +Corte Umbrío +Cola de Agua +Bomba Semilla +Corte Aéreo +Tijera X +Zumbido +Pulso Dragón +Carga Dragón +Joya de Luz +Puño Drenador +Onda de Vacío +Ataque Centrado +Bola de Energía +Ave Brava +Poder Terrestre +Trueque +Gigaimpacto +Maquinación +Puño Bala +Alud +Esquirla Helada +Garra de Sombra +Colmillo Trueno +Colmillo Hielo +Colmillo Fuego +Sombra Vil +Bomba Fango +Psicocorte +Cabezazo Zen +Disparo Espejo +Cañón Resplandor +Treparrocas +Desempañar +Espacio Raro +Meteoro Dragón +Chispazo +Bomba de Lava +Tormenta Hojas +Latigazo +Romperrocas +Veneno X +Lanzamugre +Cabeza de Hierro +Magnetobomba +Roca Afilada +Seducción +Trampa de Rocas +Nudo de Pasto +Parloteo +Juicio Final +Picadura +Rayo Carga +Mazazo +Acuajet +Al Ataque +A Defender +Auxilio +Topetazo +Doble Golpe +Rugido Temporal +Corte Espacial +Danza de la Luna +Garra Aplastante +Lluvia Ígnea +Abismo Negro +Fulgor Semilla +Viento Ominoso +Golpe Umbrío +Afilagarras +Guardia Amplia +Guardia Dividida +Fuerza Dividida +Zona Extraña +Choque Psíquico +Carga Tóxica +Aligerar +Polvo Ira +Telequinesis +Zona Mágica +Antiaéreo +Llave Tempestad +Golpe de Fuego +Ola de Lodo +Danza del Aleteo +Golpe Pesado +Sincrorruido +Electrobola +Empapar +Carga de Fuego +Enrosque +Barredora +Bomba Ácida +Juego Sucio +Onda Simple +Danza Amiga +Ceda el Paso +Canon +Eco Voz +Guardia Baja +Humo Claro +Poder Acumulado +Defensa Rápida +Cambio de Lado +Escaldar +Rompecoraza +Pulso Sanador +Infortunio +Caída Libre +Cambio de Marcha +Llave Giro +Incinerar +Último Lugar +Acrobacia +Clonatipo +Represalia +Sacrificio +Ofrenda +Infierno +Voto Agua +Voto Fuego +Voto Planta +Cambiavoltaje +Lucha Insecto +Terratemblor +Vaho Helado +Cola de Dragón +Avivar +Electrotela +Carga Salvaje +Taladradora +Golpe Dual +Sello de Corazón +Drenacuerno +Espada Sagrada +Coraza Afilada +Golpe de Calor +Ciclón de Hojas +Aplanadora +Guardialgodón +Pulso Nocturno +Onda Mental +Golpe de Cola +Huracán +Carga de Cabeza +Rueda Doble +Bomba Ígnea +Tecno Shock +Canto Arcaico +Espada Secreta +Mundo Gélido +Ataque Fulgor +Llama Azul +Danza de Llamas +Rayo Gélido +Llama Gélida +Alarido +Carámbano +V de Fuego +Llama Fusión +Rayo Fusión +Plancha Voladora +Escudo Tatami +Eructo +Fertilizante +Red Pegajosa +Aguijón Letal +Golpe Fantasma +Halloween +Rugido de Guerra +Cortina Plasma +Carga Parabólica +Condena Silvana +Tormenta Pétalos +Liofilización +Voz Encantadora +Última Palabra +Reversión +Beso Drenador +Truco Defensa +Defensa Floral +Campo de Césped +Campo de Niebla +Electrificación +Juego Rudo +Viento Feérico +Fuerza Lunar +Estruendo +Cerrojo Feérico +Escudo Real +Camaradería +Confidencia +Torm. Diamantes +Chorro de Vapor +Paso Dimensional +Shuriken de Agua +Fuego Místico +Barrera Espinosa +Niebla Aromática +Onda Anómala +Trampa Venenosa +Pólvora +Geocontrol +Aura Magnética +Paga Extra +Campo Eléctrico +Brillo Mágico +Celebración +Manos Juntas +Ojitos Tiernos +Frote +Clemencia +Infestación +Puño Incremento +Ala del Olvido +Mil Flechas +Mil Temblores +Fuerza Telúrica +Luz Aniquiladora +Pulso Primigenio +Filo del Abismo +Ascen. Dracónico +Cerco Dimensión +Carrera Arrolladora +Carrera Arrolladora +Ráfaga Demoledora +Ráfaga Demoledora +Picada Supersónica +Picada Supersónica +Diluvio Corrosivo +Diluvio Corrosivo +Barrena Telúrica +Barrena Telúrica +Aplastamiento Gigalítico +Aplastamiento Gigalítico +Guadaña Sedosa +Guadaña Sedosa +Presa Espectral +Presa Espectral +Hélice Trepanadora +Hélice Trepanadora +Hecatombe Pírica +Hecatombe Pírica +Hidrovórtice Abisal +Hidrovórtice Abisal +Megatón Floral +Megatón Floral +Gigavoltio Destructor +Gigavoltio Destructor +Disruptor Psíquico +Disruptor Psíquico +Crioaliento Despiadado +Crioaliento Despiadado +Dracoaliento Devastador +Dracoaliento Devastador +Agujero Negro Aniquilador +Agujero Negro Aniquilador +Tacleada Sideral +Tacleada Sideral +Pikavoltio Letal +Recogearena +Escaramuza +Búnker +Puntada Sombría +Lariat Oscuro +Aria Burbuja +Martillo Hielo +Flores Sanadoras +Fuerza Equina +Absorbefuerza +Cuchillada Solar +Follaje +Foco +Hilo Venenoso +Agudizar +Engranajes +Golpe al Cuello +Bola de Polen +Anclaje +Campo Psíquico +Plancha +Látigo Ígneo +Arrogancia +Llama Final +Cambiavelocidad +Cuerno Certero +Purificación +Danza Revelación +Núcleo Castigo +Patada Tropical +Mandato +Pico Cañón +Fragor Escamas +Martillo Dragón +Giro Vil +Velo Aurora +Aluvión de Flechas Sombrías +Hiperplancha Oscura +Sinfonía de la Diva Marina +Cólera del Guardián +Constelación Robaalmas +Surfeo Galvánico +Arrojo Intempestivo +Novena Potencia +Supernova Original +Trampa Coraza +Cañón Floral +Psicocolmillo +Pataleta +Hueso Sombrío +Roca Veloz +Hidroariete +Láser Prisma +Robasombra +Meteoimpacto +Rayo Umbrío +Ojos Llorosos +Electropunzada +Ira Natural +Multiataque +Gigarrayo Fulminante +Cabeza Sorpresa +Puños Plasma +Géiser Fotónico +Fotodestrucción Apocalíptica +Embestida Solar +Deflagración Lunar +Paliza Amistosa +Tempestad Rocosa +Estruendo Implacable +Pikaturbo +Salpikasurf +Pikaída +Pikatormenta +Vapodrenaje +Joltioparálisis +Flarembestida +Espeaura +Umbreozona +Leafitobombas +Glaceoprisma +Sylveotornado +Eevimpacto +Ferropuño Doble +Maxibarrera +Cañón Dinamax +Disparo Certero +Presa Maxilar +Atiborramiento +Bastión Final +Alquitranazo +Polvo Magia +Dracoflechas +Hora del Té +Octopresa +Electropico +Branquibocado +Cambio de Cancha +Maxignición +Maxinsecto +Maxitormenta +Maxiataque +Maxipuño +Maxiespectro +Maxihelada +Maxiácido +Maxichorro +Maxiciclón +Maxiestela +Maxidraco +Maxionda +Maxirroca +Maxitemblor +Maxisombra +Maxiflora +Maximetal +Estruendo Escama +Plancha Corporal +Decoración +Batería Asalto +Trampa Presión +Balón Ígneo +Corte Supremo +Golpe Supremo +Rueda Aural +Vasto Impacto +Ramazo Punzante +Amplificador +Ácido Málico +Fuerza G +Choque Anímico +Cautivapor +Gota Vital +Obstrucción +Irreverencia +Asalto Estelar +Rayo Infinito +Metaláser +Vasta Fuerza +Ferroaplanadora +Disparo Escamas +Rayo Meteórico +Moluscañón +Bruma Explosiva +Fitoimpulso +Alto Voltaje +Pulso de Campo +Golpe Rastrero +Envidia Ardiente +Desahogo +Poltergeist +Gas Corrosivo +Motivación +Viraje +Triple Axel +Aletazo Doble +Arenas Ardientes +Selva Sanadora +Golpe Oscuro +Golpe Torrencial +Electrojaula +Dracoenergía +Mirada Glacial +Furia Candente +Patada Relámpago +Lanza Glacial +Orbes Espectro +Conjuro Funesto +Garra Nociva +Asalto Barrera +Cambiapoder +Hachazo Pétreo +Ciclón Primavera +Poder Místico +Erupción de Ira +Acuatacleada +Clorofiláser +Viento Carámbano +Danza Triunfal +Asalto Frontal +Mil Púas Tóxicas +Ala Aural +Rencor Reprimido +Retracción +Triple Flecha +Marcha Espectral +Corte Metralla +Vendaval Gélido +Electormenta +Tifón de Arena +Plegaria Lunar +Bálsamo Osado +Teraexplosión +Telatrampa +Patada Hacha +Homenaje Póstumo +Fotocolisión +Emplatar +Puño Jet +Extracto Picante +Quemarrueda +Proliferación +Pirueta Helada +Asalto Espadón +Plegaria Vital +Salación +Triple Inmersión +Giro Mortífero +Plagio +Fileteo +Genufendiente +Truco Floral +Canto Ígneo +Danza Acuática +Furia Taurina +Fiebre Dorada +Psicohojas +Hidrovapor +Calamidad +Nitrochoque +Electroderrape +Autotomía +Respuesta Fría +Limpieza General +Paisaje Nevado +Brinco +Abrecaminos +Agua Fría +Hipertaladro +Láser Doble +Puño Furia +Cañón Armadura +Espada Lamento +Electropalmas +Martillo Colosal +Resarcimiento +Corte Acuático +Pirochoque +Ominochoque +Ponzochoque +Pugnachoque +Feerichoque +Luna Roja +Cañón Batidor +Bomba Caramelo +Garrote Liana +Electrorrayo +Teraclúster +Láser Caprichoso +Llama Protectora +Relámpago Súbito +Corte Potente +Corte Taquión +Prensa Metálica +Bramido Dragón +Canto Encantador +Furia Ardiente +Golpe Voltaico +Psicorruido +Palma Rauda +Cadena Virulenta +Luz Devastadora \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Natures_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Natures_es-419.txt new file mode 100644 index 000000000..94cf69252 --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Natures_es-419.txt @@ -0,0 +1,25 @@ +Fuerte +Huraña +Audaz +Firme +Pícara +Osada +Dócil +Plácida +Agitada +Floja +Miedosa +Activa +Seria +Alegre +Ingenua +Modesta +Afable +Mansa +Tímida +Alocada +Serena +Amable +Grosera +Cauta +Rara \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Pokeblock_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Pokeblock_es-419.txt new file mode 100644 index 000000000..f5b987507 --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Pokeblock_es-419.txt @@ -0,0 +1,106 @@ +Tubo Pokécubos +Licuabayas +Dar un Pokécubo +Dar +Hacer Pokécubos +Hacer +[~ 6] +Color +[VAR NUM3(0000)] +[VAR PKNICK(0000)] +[VAR MOVE(0000)] +¿A qué Pokémon quieres dárselo? +¡Le has dado el Pokécubo a [VAR PKNICK(0000)]! +Elige qué color de baya quieres filtrar. +Elige un Pokécubo. +¿Qué quieres hacer con el Pokécubo? +Elige las bayas que quieres licuar. +[~ 17] +¡Has conseguido [VAR NUM1(0001)] [VAR 01A3(0000)]![VAR BE05(0000)][VAR BE05(0001)] +¿Quieres darle el Pokécubo a [VAR PKNICK(0000)]? +¡Los Huevos no pueden comérselos! +¿A qué Pokémon quieres dárselo? +¡No puedes meter más de cuatro! +Bayas filtradas por color rojo. +Bayas filtradas por color azul. +Bayas filtradas por color rosa. +Bayas filtradas por color verde. +Bayas filtradas por color amarillo. +¡A licuar! +Recuperar baya +Dar a un Pokémon +Salir +Sí +No +Todas +Roja +Azul +Rosa +Verde +Amarilla +[~ 40] +[~ 41] +[~ 42] +[~ 43] +[~ 44] +[~ 45] +[~ 46] +[~ 47] +[~ 48] +[~ 49] +[~ 50] +[VAR 01A3(0000)] +[~ 52] +[~ 53] +[~ 54] +[~ 55] +[~ 56] +[~ 57] +[~ 58] +[~ 59] +[~ 60] +[~ 61] +[~ 62] +[~ 63] +[~ 64] +[~ 65] +[~ 66] +[~ 67] +[~ 68] +[~ 69] +[~ 70] +[~ 71] +[~ 72] +[~ 73] +[~ 74] +Exhibición +Interferencia +[~ 77] +[~ 78] +[~ 79] +[~ 80] +[~ 81] +Pokécubo Rojo +Pokécubo Azul +Pokécubo Rosa +Pokécubo Verde +Pokécubo Amarillo +Pokécubo Arcoíris +Pokécubo Rojo Plus +Pokécubo Azul Plus +Pokécubo Rosa Plus +Pokécubo Verde Plus +Pokécubo Amarillo Plus +Pokécubo Arcoíris Plus +Pokécubos Rojos +Pokécubos Azules +Pokécubos Rosas +Pokécubos Verdes +Pokécubos Amarillos +Pokécubos Arcoíris +Pokécubos Rojos Plus +Pokécubos Azules Plus +Pokécubos Rosas Plus +Pokécubos Verdes Plus +Pokécubos Amarillos Plus +Pokécubos Arcoíris Plus diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Puff_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Puff_es-419.txt new file mode 100644 index 000000000..49211ca56 --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Puff_es-419.txt @@ -0,0 +1,27 @@ + +Pokélito Dulce +Pokélito Menta +Pokélito Ácido +Pokélito Amargo +Pokélito Picante +Pokélito Crema Dulce +Pokélito Crema Menta +Pokélito Crema Ácida +Pokélito Crema Amarga +Pokélito Crema Picante +Pokélito Dulce Decorado +Pokélito Menta Decorado +Pokélito Ácido Decorado +Pokélito Amargo Decorado +Pokélito Picante Decorado +Pokélito Dulce Deluxe +Pokélito Menta Deluxe +Pokélito Ácido Deluxe +Pokélito Amargo Deluxe +Pokélito Picante Deluxe +Pokélito de Cumpleaños +Pokélito de Celebración +Pokélito Primaveral +Pokélito Estival +Pokélito Otoñal +Pokélito Invernal \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Ribbons_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Ribbons_es-419.txt new file mode 100644 index 000000000..b3f4289d6 --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Ribbons_es-419.txt @@ -0,0 +1,164 @@ +RibbonChampionKalos Campeón de Kalos +RibbonChampionG3 Campeón (Gen3) +RibbonChampionSinnoh Campeón de Sinnoh +RibbonBestFriends Afecto +RibbonTraining Ejercicio +RibbonBattlerSkillful Figura del Combate +RibbonBattlerExpert Experto del Combate +RibbonEffort Esfuerzo +RibbonAlert Alerta +RibbonShock Impacto +RibbonDowncast Abatimiento +RibbonCareless Descuido +RibbonRelax Relax +RibbonSnooze Cabezada +RibbonSmile Sonrisa +RibbonGorgeous Maravilla +RibbonRoyal Realeza +RibbonGorgeousRoyal Realeza Maravila +RibbonArtist Artista +RibbonFootprint Huella +RibbonRecord Récord +RibbonLegend Leyenda +RibbonCountry Campo +RibbonNational Nacional +RibbonEarth Planeta +RibbonWorld Mundo +RibbonClassic Clásica +RibbonPremier Principal +RibbonEvent Evento +RibbonBirthday Cumpleaños +RibbonSpecial Especial +RibbonSouvenir Recuerdo +RibbonWishing Deseo +RibbonChampionBattle Campeón de Torneo +RibbonChampionRegional Campeón de Área +RibbonChampionNational Campeón Nacional +RibbonChampionWorld Campeón Mundial +RibbonCountMemoryContest Cintas de concursos anteriores +RibbonCountMemoryBattle Cintas de batallas anteriores +RibbonChampionG6Hoenn Campeón de Hoenn (ORAS) +RibbonContestStar Cinta estelar de los concursos +RibbonMasterCoolness Cinta estrella del carisma +RibbonMasterBeauty Cinta estrella de la belleza +RibbonMasterCuteness Cinta estrella de la dulzura +RibbonMasterCleverness Cinta estrella del ingenio +RibbonMasterToughness Cinta estrella de la dureza +RibbonG3Cool Carisma (G3) +RibbonG3CoolSuper Carisma Alto +RibbonG3CoolHyper Carisma Avanzado +RibbonG3CoolMaster Carisma Experto +RibbonG3Beauty Belleza (G3) +RibbonG3BeautySuper Belleza Alto +RibbonG3BeautyHyper Belleza Avanzado +RibbonG3BeautyMaster Belleza Experto +RibbonG3Cute Dulzura (G3) +RibbonG3CuteSuper Dulzura Alto +RibbonG3CuteHyper Dulzura Avanzado +RibbonG3CuteMaster Dulzura Experto +RibbonG3Smart Ingenio (G3) +RibbonG3SmartSuper Ingenio Alto +RibbonG3SmartHyper Ingenio Avanzado +RibbonG3SmartMaster Ingenio Experto +RibbonG3Tough Dureza (G3) +RibbonG3ToughSuper Dureza Alto +RibbonG3ToughHyper Dureza Avanzado +RibbonG3ToughMaster Dureza Experto +RibbonG4Cool Carisma (G4) +RibbonG4CoolGreat Carisma Difícil +RibbonG4CoolUltra Carisma Superior +RibbonG4CoolMaster Carisma Experto +RibbonG4Beauty Belleza (G4) +RibbonG4BeautyGreat Belleza Difícil +RibbonG4BeautyUltra Belleza Superior +RibbonG4BeautyMaster Belleza Experto +RibbonG4Cute Dulzura (G4) +RibbonG4CuteGreat Dulzura Difícil +RibbonG4CuteUltra Dulzura Superior +RibbonG4CuteMaster Dulzura Experto +RibbonG4Smart Ingenio (G4) +RibbonG4SmartGreat Ingenio Difícil +RibbonG4SmartUltra Ingenio Superior +RibbonG4SmartMaster Ingenio Experto +RibbonG4Tough Dureza (G4) +RibbonG4ToughGreat Dureza Difícil +RibbonG4ToughUltra Dureza Superior +RibbonG4ToughMaster Dureza Experto +RibbonWinning Ganador +RibbonVictory Victoria +RibbonAbility Habilidad +RibbonAbilityGreat Gran Habilidad +RibbonAbilityDouble Doble Habilidad +RibbonAbilityMulti Habilidad Múltiple +RibbonAbilityPair Habilidad Par +RibbonAbilityWorld Hablildad Mundial +RibbonCountG3Cool Carisma +RibbonCountG3Beauty Belleza +RibbonCountG3Cute Dulzura +RibbonCountG3Smart Ingenio +RibbonCountG3Tough Dureza +RibbonChampionAlola Campeón de Alola +RibbonBattleRoyale Maestro Battle Royale +RibbonBattleTreeGreat As del Árbol +RibbonBattleTreeMaster Maestro del Árbol +RibbonChampionGalar Campeón de Galar +RibbonTowerMaster Maestro de la Torre +RibbonMasterRank Rango Maestro +RibbonMarkLunchtime Emblema Almuerzo +RibbonMarkSleepyTime Emblema Noche +RibbonMarkDusk Emblema Ocaso +RibbonMarkDawn Emblema Alba +RibbonMarkCloudy Emblema Nube +RibbonMarkRainy Emblema Lluvia +RibbonMarkStormy Emblema Tormenta +RibbonMarkSnowy Emblema Nieve +RibbonMarkBlizzard Emblema Nevasca +RibbonMarkDry Emblema Sequedad +RibbonMarkSandstorm Emblema Polvareda +RibbonMarkMisty Emblema Niebla +RibbonMarkDestiny Emblema Destino +RibbonMarkFishing Emblema Pesca +RibbonMarkCurry Emblema Curri +RibbonMarkUncommon Emblema Familiaridad +RibbonMarkRare Emblema Rareza +RibbonMarkRowdy Emblema Travesura +RibbonMarkAbsentMinded Emblema Despreocupación +RibbonMarkJittery Emblema Nerviosismo +RibbonMarkExcited Emblema Ilusión +RibbonMarkCharismatic Emblema Carisma +RibbonMarkCalmness Emblema Compostura +RibbonMarkIntense Emblema Pasión +RibbonMarkZonedOut Emblema Distracción +RibbonMarkJoyful Emblema Felicidad +RibbonMarkAngry Emblema Cólera +RibbonMarkSmiley Emblema Sonrisa +RibbonMarkTeary Emblema Llanto +RibbonMarkUpbeat Emblema Buen Humor +RibbonMarkPeeved Emblema Mal Humor +RibbonMarkIntellectual Emblema Intelecto +RibbonMarkFerocious Emblema Impulsividad +RibbonMarkCrafty Emblema Astucia +RibbonMarkScowling Emblema Intimidación +RibbonMarkKindly Emblema Amabilidad +RibbonMarkFlustered Emblema Desconcierto +RibbonMarkPumpedUp Emblema Motivación +RibbonMarkZeroEnergy Emblema Desgana +RibbonMarkPrideful Emblema Confianza +RibbonMarkUnsure Emblema Inseguridad +RibbonMarkHumble Emblema Sencillez +RibbonMarkThorny Emblema Altanería +RibbonMarkVigor Emblema Vigor +RibbonMarkSlump Emblema Extenuación +RibbonHisui Hisui +RibbonTwinklingStar Estrella Rutilante +RibbonChampionPaldea Campeón de Paldea +RibbonMarkJumbo Emblema Enormidad +RibbonMarkMini Emblema Miniatura +RibbonMarkItemfinder Emblema Recolección +RibbonMarkPartner Emblema Compañerismo +RibbonMarkGourmand Emblema Sibaritismo +RibbonOnceInALifetime Excepcionalidad +RibbonMarkAlpha Emblema Alfa +RibbonMarkMightiest Emblema Imbatibilidad +RibbonMarkTitan Emblema Dominancia +RibbonPartner Camarada \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Species_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Species_es-419.txt new file mode 100644 index 000000000..54d06f4ba --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Species_es-419.txt @@ -0,0 +1,1026 @@ +Huevo +Bulbasaur +Ivysaur +Venusaur +Charmander +Charmeleon +Charizard +Squirtle +Wartortle +Blastoise +Caterpie +Metapod +Butterfree +Weedle +Kakuna +Beedrill +Pidgey +Pidgeotto +Pidgeot +Rattata +Raticate +Spearow +Fearow +Ekans +Arbok +Pikachu +Raichu +Sandshrew +Sandslash +Nidoran♀ +Nidorina +Nidoqueen +Nidoran♂ +Nidorino +Nidoking +Clefairy +Clefable +Vulpix +Ninetales +Jigglypuff +Wigglytuff +Zubat +Golbat +Oddish +Gloom +Vileplume +Paras +Parasect +Venonat +Venomoth +Diglett +Dugtrio +Meowth +Persian +Psyduck +Golduck +Mankey +Primeape +Growlithe +Arcanine +Poliwag +Poliwhirl +Poliwrath +Abra +Kadabra +Alakazam +Machop +Machoke +Machamp +Bellsprout +Weepinbell +Victreebel +Tentacool +Tentacruel +Geodude +Graveler +Golem +Ponyta +Rapidash +Slowpoke +Slowbro +Magnemite +Magneton +Farfetch’d +Doduo +Dodrio +Seel +Dewgong +Grimer +Muk +Shellder +Cloyster +Gastly +Haunter +Gengar +Onix +Drowzee +Hypno +Krabby +Kingler +Voltorb +Electrode +Exeggcute +Exeggutor +Cubone +Marowak +Hitmonlee +Hitmonchan +Lickitung +Koffing +Weezing +Rhyhorn +Rhydon +Chansey +Tangela +Kangaskhan +Horsea +Seadra +Goldeen +Seaking +Staryu +Starmie +Mr. Mime +Scyther +Jynx +Electabuzz +Magmar +Pinsir +Tauros +Magikarp +Gyarados +Lapras +Ditto +Eevee +Vaporeon +Jolteon +Flareon +Porygon +Omanyte +Omastar +Kabuto +Kabutops +Aerodactyl +Snorlax +Articuno +Zapdos +Moltres +Dratini +Dragonair +Dragonite +Mewtwo +Mew +Chikorita +Bayleef +Meganium +Cyndaquil +Quilava +Typhlosion +Totodile +Croconaw +Feraligatr +Sentret +Furret +Hoothoot +Noctowl +Ledyba +Ledian +Spinarak +Ariados +Crobat +Chinchou +Lanturn +Pichu +Cleffa +Igglybuff +Togepi +Togetic +Natu +Xatu +Mareep +Flaaffy +Ampharos +Bellossom +Marill +Azumarill +Sudowoodo +Politoed +Hoppip +Skiploom +Jumpluff +Aipom +Sunkern +Sunflora +Yanma +Wooper +Quagsire +Espeon +Umbreon +Murkrow +Slowking +Misdreavus +Unown +Wobbuffet +Girafarig +Pineco +Forretress +Dunsparce +Gligar +Steelix +Snubbull +Granbull +Qwilfish +Scizor +Shuckle +Heracross +Sneasel +Teddiursa +Ursaring +Slugma +Magcargo +Swinub +Piloswine +Corsola +Remoraid +Octillery +Delibird +Mantine +Skarmory +Houndour +Houndoom +Kingdra +Phanpy +Donphan +Porygon2 +Stantler +Smeargle +Tyrogue +Hitmontop +Smoochum +Elekid +Magby +Miltank +Blissey +Raikou +Entei +Suicune +Larvitar +Pupitar +Tyranitar +Lugia +Ho-Oh +Celebi +Treecko +Grovyle +Sceptile +Torchic +Combusken +Blaziken +Mudkip +Marshtomp +Swampert +Poochyena +Mightyena +Zigzagoon +Linoone +Wurmple +Silcoon +Beautifly +Cascoon +Dustox +Lotad +Lombre +Ludicolo +Seedot +Nuzleaf +Shiftry +Taillow +Swellow +Wingull +Pelipper +Ralts +Kirlia +Gardevoir +Surskit +Masquerain +Shroomish +Breloom +Slakoth +Vigoroth +Slaking +Nincada +Ninjask +Shedinja +Whismur +Loudred +Exploud +Makuhita +Hariyama +Azurill +Nosepass +Skitty +Delcatty +Sableye +Mawile +Aron +Lairon +Aggron +Meditite +Medicham +Electrike +Manectric +Plusle +Minun +Volbeat +Illumise +Roselia +Gulpin +Swalot +Carvanha +Sharpedo +Wailmer +Wailord +Numel +Camerupt +Torkoal +Spoink +Grumpig +Spinda +Trapinch +Vibrava +Flygon +Cacnea +Cacturne +Swablu +Altaria +Zangoose +Seviper +Lunatone +Solrock +Barboach +Whiscash +Corphish +Crawdaunt +Baltoy +Claydol +Lileep +Cradily +Anorith +Armaldo +Feebas +Milotic +Castform +Kecleon +Shuppet +Banette +Duskull +Dusclops +Tropius +Chimecho +Absol +Wynaut +Snorunt +Glalie +Spheal +Sealeo +Walrein +Clamperl +Huntail +Gorebyss +Relicanth +Luvdisc +Bagon +Shelgon +Salamence +Beldum +Metang +Metagross +Regirock +Regice +Registeel +Latias +Latios +Kyogre +Groudon +Rayquaza +Jirachi +Deoxys +Turtwig +Grotle +Torterra +Chimchar +Monferno +Infernape +Piplup +Prinplup +Empoleon +Starly +Staravia +Staraptor +Bidoof +Bibarel +Kricketot +Kricketune +Shinx +Luxio +Luxray +Budew +Roserade +Cranidos +Rampardos +Shieldon +Bastiodon +Burmy +Wormadam +Mothim +Combee +Vespiquen +Pachirisu +Buizel +Floatzel +Cherubi +Cherrim +Shellos +Gastrodon +Ambipom +Drifloon +Drifblim +Buneary +Lopunny +Mismagius +Honchkrow +Glameow +Purugly +Chingling +Stunky +Skuntank +Bronzor +Bronzong +Bonsly +Mime Jr. +Happiny +Chatot +Spiritomb +Gible +Gabite +Garchomp +Munchlax +Riolu +Lucario +Hippopotas +Hippowdon +Skorupi +Drapion +Croagunk +Toxicroak +Carnivine +Finneon +Lumineon +Mantyke +Snover +Abomasnow +Weavile +Magnezone +Lickilicky +Rhyperior +Tangrowth +Electivire +Magmortar +Togekiss +Yanmega +Leafeon +Glaceon +Gliscor +Mamoswine +Porygon-Z +Gallade +Probopass +Dusknoir +Froslass +Rotom +Uxie +Mesprit +Azelf +Dialga +Palkia +Heatran +Regigigas +Giratina +Cresselia +Phione +Manaphy +Darkrai +Shaymin +Arceus +Victini +Snivy +Servine +Serperior +Tepig +Pignite +Emboar +Oshawott +Dewott +Samurott +Patrat +Watchog +Lillipup +Herdier +Stoutland +Purrloin +Liepard +Pansage +Simisage +Pansear +Simisear +Panpour +Simipour +Munna +Musharna +Pidove +Tranquill +Unfezant +Blitzle +Zebstrika +Roggenrola +Boldore +Gigalith +Woobat +Swoobat +Drilbur +Excadrill +Audino +Timburr +Gurdurr +Conkeldurr +Tympole +Palpitoad +Seismitoad +Throh +Sawk +Sewaddle +Swadloon +Leavanny +Venipede +Whirlipede +Scolipede +Cottonee +Whimsicott +Petilil +Lilligant +Basculin +Sandile +Krokorok +Krookodile +Darumaka +Darmanitan +Maractus +Dwebble +Crustle +Scraggy +Scrafty +Sigilyph +Yamask +Cofagrigus +Tirtouga +Carracosta +Archen +Archeops +Trubbish +Garbodor +Zorua +Zoroark +Minccino +Cinccino +Gothita +Gothorita +Gothitelle +Solosis +Duosion +Reuniclus +Ducklett +Swanna +Vanillite +Vanillish +Vanilluxe +Deerling +Sawsbuck +Emolga +Karrablast +Escavalier +Foongus +Amoonguss +Frillish +Jellicent +Alomomola +Joltik +Galvantula +Ferroseed +Ferrothorn +Klink +Klang +Klinklang +Tynamo +Eelektrik +Eelektross +Elgyem +Beheeyem +Litwick +Lampent +Chandelure +Axew +Fraxure +Haxorus +Cubchoo +Beartic +Cryogonal +Shelmet +Accelgor +Stunfisk +Mienfoo +Mienshao +Druddigon +Golett +Golurk +Pawniard +Bisharp +Bouffalant +Rufflet +Braviary +Vullaby +Mandibuzz +Heatmor +Durant +Deino +Zweilous +Hydreigon +Larvesta +Volcarona +Cobalion +Terrakion +Virizion +Tornadus +Thundurus +Reshiram +Zekrom +Landorus +Kyurem +Keldeo +Meloetta +Genesect +Chespin +Quilladin +Chesnaught +Fennekin +Braixen +Delphox +Froakie +Frogadier +Greninja +Bunnelby +Diggersby +Fletchling +Fletchinder +Talonflame +Scatterbug +Spewpa +Vivillon +Litleo +Pyroar +Flabébé +Floette +Florges +Skiddo +Gogoat +Pancham +Pangoro +Furfrou +Espurr +Meowstic +Honedge +Doublade +Aegislash +Spritzee +Aromatisse +Swirlix +Slurpuff +Inkay +Malamar +Binacle +Barbaracle +Skrelp +Dragalge +Clauncher +Clawitzer +Helioptile +Heliolisk +Tyrunt +Tyrantrum +Amaura +Aurorus +Sylveon +Hawlucha +Dedenne +Carbink +Goomy +Sliggoo +Goodra +Klefki +Phantump +Trevenant +Pumpkaboo +Gourgeist +Bergmite +Avalugg +Noibat +Noivern +Xerneas +Yveltal +Zygarde +Diancie +Hoopa +Volcanion +Rowlet +Dartrix +Decidueye +Litten +Torracat +Incineroar +Popplio +Brionne +Primarina +Pikipek +Trumbeak +Toucannon +Yungoos +Gumshoos +Grubbin +Charjabug +Vikavolt +Crabrawler +Crabominable +Oricorio +Cutiefly +Ribombee +Rockruff +Lycanroc +Wishiwashi +Mareanie +Toxapex +Mudbray +Mudsdale +Dewpider +Araquanid +Fomantis +Lurantis +Morelull +Shiinotic +Salandit +Salazzle +Stufful +Bewear +Bounsweet +Steenee +Tsareena +Comfey +Oranguru +Passimian +Wimpod +Golisopod +Sandygast +Palossand +Pyukumuku +Código Cero +Silvally +Minior +Komala +Turtonator +Togedemaru +Mimikyu +Bruxish +Drampa +Dhelmise +Jangmo-o +Hakamo-o +Kommo-o +Tapu Koko +Tapu Lele +Tapu Bulu +Tapu Fini +Cosmog +Cosmoem +Solgaleo +Lunala +Nihilego +Buzzwole +Pheromosa +Xurkitree +Celesteela +Kartana +Guzzlord +Necrozma +Magearna +Marshadow +Poipole +Naganadel +Stakataka +Blacephalon +Zeraora +Meltan +Melmetal +Grookey +Thwackey +Rillaboom +Scorbunny +Raboot +Cinderace +Sobble +Drizzile +Inteleon +Skwovet +Greedent +Rookidee +Corvisquire +Corviknight +Blipbug +Dottler +Orbeetle +Nickit +Thievul +Gossifleur +Eldegoss +Wooloo +Dubwool +Chewtle +Drednaw +Yamper +Boltund +Rolycoly +Carkol +Coalossal +Applin +Flapple +Appletun +Silicobra +Sandaconda +Cramorant +Arrokuda +Barraskewda +Toxel +Toxtricity +Sizzlipede +Centiskorch +Clobbopus +Grapploct +Sinistea +Polteageist +Hatenna +Hattrem +Hatterene +Impidimp +Morgrem +Grimmsnarl +Obstagoon +Perrserker +Cursola +Sirfetch’d +Mr. Rime +Runerigus +Milcery +Alcremie +Falinks +Pincurchin +Snom +Frosmoth +Stonjourner +Eiscue +Indeedee +Morpeko +Cufant +Copperajah +Dracozolt +Arctozolt +Dracovish +Arctovish +Duraludon +Dreepy +Drakloak +Dragapult +Zacian +Zamazenta +Eternatus +Kubfu +Urshifu +Zarude +Regieleki +Regidrago +Glastrier +Spectrier +Calyrex +Wyrdeer +Kleavor +Ursaluna +Basculegion +Sneasler +Overqwil +Enamorus +Sprigatito +Floragato +Meowscarada +Fuecoco +Crocalor +Skeledirge +Quaxly +Quaxwell +Quaquaval +Lechonk +Oinkologne +Tarountula +Spidops +Nymble +Lokix +Pawmi +Pawmo +Pawmot +Tandemaus +Maushold +Fidough +Dachsbun +Smoliv +Dolliv +Arboliva +Squawkabilly +Nacli +Naclstack +Garganacl +Charcadet +Armarouge +Ceruledge +Tadbulb +Bellibolt +Wattrel +Kilowattrel +Maschiff +Mabosstiff +Shroodle +Grafaiai +Bramblin +Brambleghast +Toedscool +Toedscruel +Klawf +Capsakid +Scovillain +Rellor +Rabsca +Flittle +Espathra +Tinkatink +Tinkatuff +Tinkaton +Wiglett +Wugtrio +Bombirdier +Finizen +Palafin +Varoom +Revavroom +Cyclizar +Orthworm +Glimmet +Glimmora +Greavard +Houndstone +Flamigo +Cetoddle +Cetitan +Veluza +Dondozo +Tatsugiri +Annihilape +Clodsire +Farigiraf +Dudunsparce +Kingambit +Colmilargo +Colagrito +Furioseta +Melenaleteo +Reptalada +Pelarena +Ferrodada +Ferrosaco +Ferropalmas +Ferrocuello +Ferropolilla +Ferropúas +Frigibax +Arctibax +Baxcalibur +Gimmighoul +Gholdengo +Wo-Chien +Chien-Pao +Ting-Lu +Chi-Yu +Bramaluna +Ferropaladín +Koraidon +Miraidon +Ondulagua +Ferroverdor +Dipplin +Poltchageist +Sinistcha +Okidogi +Munkidori +Fezandipiti +Ogerpon +Archaludon +Hydrapple +Flamariete +Electrofuria +Ferromole +Ferrotesta +Terapagos +Pecharunt \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_SuperTraining_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_SuperTraining_es-419.txt new file mode 100644 index 000000000..77d96d995 --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_SuperTraining_es-419.txt @@ -0,0 +1,38 @@ +¡Practica contra Scatterbug! +¡Tiro con ímpetu contra Spewpa! +¡Mejora tu Ataque Especial contra Magnemite! +¡Mejora tus PS contra Wailmer! +¡Mejora tu Ataque contra Axew! +¡Mejora tu Defensa Especial contra Tentacool! +¡Mejora tu Velocidad contra Noibat! +¡Mejora tu Defensa contra Geodude! +¡Los tiros rastreadores de Magneton! +¡La portería de oportunidad de Relicanth! +¡Ráfaga de tiros de Fraxure! +¡Tentacruel y sus globos de bits! +¡Dale a Aerodactyl con tiros rápidos! +¡Destruye la barrera de Graveler! +¡Líbrate de Magnezone! +¡Haz frente al gigantesco Wailord! +¡Esquiva los temibles ataques de Haxorus! +¡Derrota a Dragalge! +¡Más rápido que el viento contra Noivern! +¡Penetra la línea defensiva de Golem! +¡Una dificultad tras otra! +¡Compite por la Piedra Hoja! +¡Compite por la Piedra Fuego! +¡Compite por la Piedra Agua! +¡Acierta las evasivas porterías! +¡Contraataque en el segundo tiempo! +¡Agilidad en el primer tiempo! +¡Ristras de balones a diestro y siniestro! +¡La venganza de Scatterbug! +¡Bombardeo de globos de bits! +¡Todo o nada contra Hydreigon! +¿Quién es el más fuerte? (Pokémon X) +¡Las temibles mandíbulas gemelas! +¡Se abre la cremallera prohibida! +¡Pinzazos de acero sin tregua! +¡Confusión! ¡Danza de cucharas! +¡La remontada de Magikarp! +¡Megaevoluciones en serie! \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_TrainingBag_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_TrainingBag_es-419.txt new file mode 100644 index 000000000..6408b426b --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_TrainingBag_es-419.txt @@ -0,0 +1,27 @@ + +Saco PS S +Saco PS M +Saco PS L +Saco Ataque S +Saco Ataque M +Saco Ataque L +Saco Defensa S +Saco Defensa M +Saco Defensa L +Saco At. Esp. S +Saco At. Esp. M +Saco At. Esp. L +Saco Def. Esp. S +Saco Def. Esp. M +Saco Def. Esp. L +Saco Veloc. S +Saco Veloc. M +Saco Veloc. L +Saco Potencia ↑ +Saco Aguante ↑ +Saco Agilidad ↑ +Saco Tamaño ↑ +Saco Mejora x2 +Saco Team Flare +Saco Reinicio +Saco Relax \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Types_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Types_es-419.txt new file mode 100644 index 000000000..0b9cb021f --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Types_es-419.txt @@ -0,0 +1,19 @@ +Normal +Lucha +Volador +Veneno +Tierra +Roca +Bicho +Fantasma +Acero +Fuego +Agua +Planta +Eléctrico +Psíquico +Hielo +Dragón +Siniestro +Hada +Astral \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es-419/text_Wallpaper_es-419.txt b/PKHeX.Core/Resources/text/other/es-419/text_Wallpaper_es-419.txt new file mode 100644 index 000000000..a4a70686d --- /dev/null +++ b/PKHeX.Core/Resources/text/other/es-419/text_Wallpaper_es-419.txt @@ -0,0 +1,32 @@ +Bosque +Ciudad +Desierto +Sabana +Montaña +Volcán +Nieve +Cueva +Playa +Mar +Río +Cielo +Centro Pokémon +Máquina +Cuadros +Sencillo +Especial 1 +Especial 2 +Especial 3 +Especial 4 +Especial 5 +Especial 6 +Especial 7 +Especial 8 +Especial 9 +Especial 10 +Especial 11 +Especial 12 +Especial 13 +Especial 14 +Especial 15 +Especial 16 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es/text_Forms_es.txt b/PKHeX.Core/Resources/text/other/es/text_Forms_es.txt index 549ecdd7c..a2c707d91 100644 --- a/PKHeX.Core/Resources/text/other/es/text_Forms_es.txt +++ b/PKHeX.Core/Resources/text/other/es/text_Forms_es.txt @@ -1134,4 +1134,6 @@ Cimiento Opulenta Exquisita Teracristal -Astral \ No newline at end of file +Astral +Mediana +Enorme \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es/text_Games_es.txt b/PKHeX.Core/Resources/text/other/es/text_Games_es.txt index 049dc8ba6..7f08fc2dd 100644 --- a/PKHeX.Core/Resources/text/other/es/text_Games_es.txt +++ b/PKHeX.Core/Resources/text/other/es/text_Games_es.txt @@ -49,4 +49,5 @@ Leyendas: Arceus Diamante Brillante Perla Reluciente Escarlata -Púrpura \ No newline at end of file +Púrpura +Leyendas: Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/es/text_Moves_es.txt b/PKHeX.Core/Resources/text/other/es/text_Moves_es.txt index bebc04d4a..779238296 100644 --- a/PKHeX.Core/Resources/text/other/es/text_Moves_es.txt +++ b/PKHeX.Core/Resources/text/other/es/text_Moves_es.txt @@ -37,7 +37,7 @@ Constricción Derribo Saña Doble Filo -Látigo +Agitacola Picotazo Veneno Doble Ataque Pin Misil @@ -174,7 +174,7 @@ Rueda Fuego Ronquido Maldición Azote -Conversión2 +Conversión 2 Aerochorro Esporagodón Inversión @@ -233,7 +233,7 @@ Cola Férrea Garra Metal Llave Vital Sol Matinal -Síntesis +Fotosíntesis Luz Lunar Poder Oculto Tajo Cruzado @@ -428,7 +428,7 @@ Bomba Fango Psicocorte Cabezazo Zen Disparo Espejo -Foco Resplandor +Cañón Resplandor Treparrocas Despejar Espacio Raro @@ -917,4 +917,5 @@ Cólera Ardiente Plancha Voltaica Psicorruido Palma Rauda -Cadena Virulenta \ No newline at end of file +Cadena Virulenta +Luz Devastadora diff --git a/PKHeX.Core/Resources/text/other/fr/text_Forms_fr.txt b/PKHeX.Core/Resources/text/other/fr/text_Forms_fr.txt index a6fc9be2f..d7e237673 100644 --- a/PKHeX.Core/Resources/text/other/fr/text_Forms_fr.txt +++ b/PKHeX.Core/Resources/text/other/fr/text_Forms_fr.txt @@ -1134,4 +1134,6 @@ Pierre Onéreuse Exceptionnelle Téracristal -Stellaire \ No newline at end of file +Stellaire +Moyenne +Giga \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/fr/text_Games_fr.txt b/PKHeX.Core/Resources/text/other/fr/text_Games_fr.txt index 1aadcffc5..976f09a3d 100644 --- a/PKHeX.Core/Resources/text/other/fr/text_Games_fr.txt +++ b/PKHeX.Core/Resources/text/other/fr/text_Games_fr.txt @@ -49,4 +49,5 @@ Légendes: Arceus Diamant Étincelant Perle Scintillante Écarlate -Violet \ No newline at end of file +Violet +Légendes: Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/fr/text_Moves_fr.txt b/PKHeX.Core/Resources/text/other/fr/text_Moves_fr.txt index cb89f9115..6a54f2c27 100644 --- a/PKHeX.Core/Resources/text/other/fr/text_Moves_fr.txt +++ b/PKHeX.Core/Resources/text/other/fr/text_Moves_fr.txt @@ -917,4 +917,5 @@ Indignition Volt Assaut Dissonance Psy Prio-Parade -Chaîne Malsaine \ No newline at end of file +Chaîne Malsaine +Lux Nihilum \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/it/text_Forms_it.txt b/PKHeX.Core/Resources/text/other/it/text_Forms_it.txt index ab78da7cd..e4047a92b 100644 --- a/PKHeX.Core/Resources/text/other/it/text_Forms_it.txt +++ b/PKHeX.Core/Resources/text/other/it/text_Forms_it.txt @@ -1134,4 +1134,6 @@ Fondamenta Pregiata Eccezionale Teracristal -Astrale \ No newline at end of file +Astrale +Media +Gigante \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/it/text_Games_it.txt b/PKHeX.Core/Resources/text/other/it/text_Games_it.txt index 59f8cfdf6..8a8e914cf 100644 --- a/PKHeX.Core/Resources/text/other/it/text_Games_it.txt +++ b/PKHeX.Core/Resources/text/other/it/text_Games_it.txt @@ -49,4 +49,5 @@ Leggende: Arceus Diamante Lucente Perla Splendente Scarlatto -Violetto \ No newline at end of file +Violetto +Leggende: Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/it/text_Moves_it.txt b/PKHeX.Core/Resources/text/other/it/text_Moves_it.txt index 0f912d2e2..7a473cb21 100644 --- a/PKHeX.Core/Resources/text/other/it/text_Moves_it.txt +++ b/PKHeX.Core/Resources/text/other/it/text_Moves_it.txt @@ -917,4 +917,5 @@ Rabbia Bruciante Elettrotuffo Psicorumore Colpo di Mano -Intossicatena \ No newline at end of file +Intossicatena +Tabula Laser \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/ja/text_Forms_ja.txt b/PKHeX.Core/Resources/text/other/ja/text_Forms_ja.txt index b7b6231eb..bfdff3ffe 100644 --- a/PKHeX.Core/Resources/text/other/ja/text_Forms_ja.txt +++ b/PKHeX.Core/Resources/text/other/ja/text_Forms_ja.txt @@ -1134,4 +1134,6 @@ タカイモノ ケッサク テラスタル -ステラ \ No newline at end of file +ステラ +ちゅうだましゅ +ギガだましゅ \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/ja/text_Games_ja.txt b/PKHeX.Core/Resources/text/other/ja/text_Games_ja.txt index aa8ec1575..901ce9c4b 100644 --- a/PKHeX.Core/Resources/text/other/ja/text_Games_ja.txt +++ b/PKHeX.Core/Resources/text/other/ja/text_Games_ja.txt @@ -1,4 +1,4 @@ - + サファイア ルビー エメラルド @@ -49,4 +49,5 @@ LEGENDS アルセウス ブリリアントダイヤモンド シャイニングパール スカーレット -バイオレット \ No newline at end of file +バイオレット +LEGENDS Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/ja/text_Moves_ja.txt b/PKHeX.Core/Resources/text/other/ja/text_Moves_ja.txt index f1d051108..bbfa15bc7 100644 --- a/PKHeX.Core/Resources/text/other/ja/text_Moves_ja.txt +++ b/PKHeX.Core/Resources/text/other/ja/text_Moves_ja.txt @@ -917,4 +917,5 @@ サンダーダイブ サイコノイズ はやてがえし -じゃどくのくさり \ No newline at end of file +じゃどくのくさり +むにきすひかり \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/ko/text_Forms_ko.txt b/PKHeX.Core/Resources/text/other/ko/text_Forms_ko.txt index b3f00a2c6..92f7d6184 100644 --- a/PKHeX.Core/Resources/text/other/ko/text_Forms_ko.txt +++ b/PKHeX.Core/Resources/text/other/ko/text_Forms_ko.txt @@ -1134,4 +1134,6 @@ 알짜배기 걸작 테라스탈폼 -스텔라폼 \ No newline at end of file +스텔라폼 +중과종 +특대과종 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/ko/text_Games_ko.txt b/PKHeX.Core/Resources/text/other/ko/text_Games_ko.txt index d9ae730bf..5de09a17d 100644 --- a/PKHeX.Core/Resources/text/other/ko/text_Games_ko.txt +++ b/PKHeX.Core/Resources/text/other/ko/text_Games_ko.txt @@ -1,4 +1,4 @@ - + 사파이어 루비 에메랄드 @@ -49,4 +49,5 @@ LEGENDS 아르세우스 브릴리언트 다이아몬드 샤이닝 펄 스칼렛 -바이올렛 \ No newline at end of file +바이올렛 +LEGENDS Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/ko/text_Moves_ko.txt b/PKHeX.Core/Resources/text/other/ko/text_Moves_ko.txt index c84640293..64d393b78 100644 --- a/PKHeX.Core/Resources/text/other/ko/text_Moves_ko.txt +++ b/PKHeX.Core/Resources/text/other/ko/text_Moves_ko.txt @@ -917,4 +917,5 @@ G의힘 썬더다이브 사이코노이즈 기선제압 -악독사슬 \ No newline at end of file +악독사슬 +니힐레이저 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_de.txt b/PKHeX.Core/Resources/text/other/text_language_de.txt index 26dd42d74..b56ec4454 100644 --- a/PKHeX.Core/Resources/text/other/text_language_de.txt +++ b/PKHeX.Core/Resources/text/other/text_language_de.txt @@ -8,4 +8,5 @@ GER (Deutsch) SP-EU (Español) KOR (한국어) CHS (简体中文) -CHT (繁體中文) \ No newline at end of file +CHT (繁體中文) +ES-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_e-419.txt b/PKHeX.Core/Resources/text/other/text_language_e-419.txt new file mode 100644 index 000000000..90df549b1 --- /dev/null +++ b/PKHeX.Core/Resources/text/other/text_language_e-419.txt @@ -0,0 +1,12 @@ + +JAP (日本語) +ING (English) +FRA (Français) +ITA (Italiano) +ALE (Deutsch) + +ES-ES (Español) +COR (한국어) +CHS (简体中文) +CHT (繁體中文) +ES-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_en.txt b/PKHeX.Core/Resources/text/other/text_language_en.txt index 3462d9ae0..44172864e 100644 --- a/PKHeX.Core/Resources/text/other/text_language_en.txt +++ b/PKHeX.Core/Resources/text/other/text_language_en.txt @@ -1,4 +1,4 @@ - + JPN (日本語) ENG (English) FRE (Français) @@ -8,4 +8,5 @@ GER (Deutsch) ESP (Español) KOR (한국어) CHS (简体中文) -CHT (繁體中文) \ No newline at end of file +CHT (繁體中文) +ES-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_es.txt b/PKHeX.Core/Resources/text/other/text_language_es.txt index 16ec0ca10..05d16e65c 100644 --- a/PKHeX.Core/Resources/text/other/text_language_es.txt +++ b/PKHeX.Core/Resources/text/other/text_language_es.txt @@ -8,4 +8,5 @@ ALE (Deutsch) ES-ES (Español) COR (한국어) CHS (简体中文) -CHT (繁體中文) \ No newline at end of file +CHT (繁體中文) +ES-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_fr.txt b/PKHeX.Core/Resources/text/other/text_language_fr.txt index 71dc44e84..83ceae419 100644 --- a/PKHeX.Core/Resources/text/other/text_language_fr.txt +++ b/PKHeX.Core/Resources/text/other/text_language_fr.txt @@ -8,4 +8,5 @@ ALL (Deutsch) ES-EU (Español) COR (한국어) CHS (简体中文) -CHT (繁體中文) \ No newline at end of file +CHT (繁體中文) +ES-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_it.txt b/PKHeX.Core/Resources/text/other/text_language_it.txt index 3793a21de..d011ada75 100644 --- a/PKHeX.Core/Resources/text/other/text_language_it.txt +++ b/PKHeX.Core/Resources/text/other/text_language_it.txt @@ -8,4 +8,5 @@ TED (Deutsch) SPA-E (Español) COR (한국어) CIN-S (简体中文) -CIN-T (繁體中文) \ No newline at end of file +CIN-T (繁體中文) +SPA-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_ja.txt b/PKHeX.Core/Resources/text/other/text_language_ja.txt index 657c26bea..7729b31d2 100644 --- a/PKHeX.Core/Resources/text/other/text_language_ja.txt +++ b/PKHeX.Core/Resources/text/other/text_language_ja.txt @@ -5,7 +5,8 @@ FRE (Français) ITA (Italiano) GER (Deutsch) -SPA (Español) +SPA-ES (Español) KOR (한국어) CHS (简体中文) -CHT (繁體中文) \ No newline at end of file +CHT (繁體中文) +SPA-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_ko.txt b/PKHeX.Core/Resources/text/other/text_language_ko.txt index 657c26bea..7729b31d2 100644 --- a/PKHeX.Core/Resources/text/other/text_language_ko.txt +++ b/PKHeX.Core/Resources/text/other/text_language_ko.txt @@ -5,7 +5,8 @@ FRE (Français) ITA (Italiano) GER (Deutsch) -SPA (Español) +SPA-ES (Español) KOR (한국어) CHS (简体中文) -CHT (繁體中文) \ No newline at end of file +CHT (繁體中文) +SPA-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_zh-Hans.txt b/PKHeX.Core/Resources/text/other/text_language_zh-Hans.txt index 657c26bea..7729b31d2 100644 --- a/PKHeX.Core/Resources/text/other/text_language_zh-Hans.txt +++ b/PKHeX.Core/Resources/text/other/text_language_zh-Hans.txt @@ -5,7 +5,8 @@ FRE (Français) ITA (Italiano) GER (Deutsch) -SPA (Español) +SPA-ES (Español) KOR (한국어) CHS (简体中文) -CHT (繁體中文) \ No newline at end of file +CHT (繁體中文) +SPA-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/text_language_zh-Hant.txt b/PKHeX.Core/Resources/text/other/text_language_zh-Hant.txt index 657c26bea..d129c60b4 100644 --- a/PKHeX.Core/Resources/text/other/text_language_zh-Hant.txt +++ b/PKHeX.Core/Resources/text/other/text_language_zh-Hant.txt @@ -8,4 +8,5 @@ GER (Deutsch) SPA (Español) KOR (한국어) CHS (简体中文) -CHT (繁體中文) \ No newline at end of file +CHT (繁體中文) +ES-LA (Español) \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/zh/text_Forms_zh-Hans.txt b/PKHeX.Core/Resources/text/other/zh/text_Forms_zh-Hans.txt index 3e92a6661..637fab24a 100644 --- a/PKHeX.Core/Resources/text/other/zh/text_Forms_zh-Hans.txt +++ b/PKHeX.Core/Resources/text/other/zh/text_Forms_zh-Hans.txt @@ -1134,4 +1134,6 @@ 高档货的样子 杰作的样子 太晶形态 -星晶形态 \ No newline at end of file +星晶形态 +中颗种 +巨颗种 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/zh/text_Forms_zh-Hant.txt b/PKHeX.Core/Resources/text/other/zh/text_Forms_zh-Hant.txt index 71e8b9859..b7db7132c 100644 --- a/PKHeX.Core/Resources/text/other/zh/text_Forms_zh-Hant.txt +++ b/PKHeX.Core/Resources/text/other/zh/text_Forms_zh-Hant.txt @@ -1134,4 +1134,6 @@ Mega蒂安希 高檔貨的樣子 傑作的樣子 太晶形態 -星晶形態 \ No newline at end of file +星晶形態 +中顆種 +巨顆種 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/zh/text_Games_zh-Hans.txt b/PKHeX.Core/Resources/text/other/zh/text_Games_zh-Hans.txt index 12ec03270..3204516a0 100644 --- a/PKHeX.Core/Resources/text/other/zh/text_Games_zh-Hans.txt +++ b/PKHeX.Core/Resources/text/other/zh/text_Games_zh-Hans.txt @@ -1,4 +1,4 @@ - + 蓝宝石 红宝石 绿宝石 @@ -49,4 +49,5 @@ Let's Go!伊布 晶灿钻石 明亮珍珠 朱 -紫 \ No newline at end of file +紫 +傳說 寶可夢Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/zh/text_Games_zh-Hant.txt b/PKHeX.Core/Resources/text/other/zh/text_Games_zh-Hant.txt index 2699ed4a9..ccac0c476 100644 --- a/PKHeX.Core/Resources/text/other/zh/text_Games_zh-Hant.txt +++ b/PKHeX.Core/Resources/text/other/zh/text_Games_zh-Hant.txt @@ -1,4 +1,4 @@ - + 藍寶石 紅寶石 綠寶石 @@ -49,4 +49,5 @@ Let's Go!伊布 晶燦鑽石 明亮珍珠 朱 -紫 \ No newline at end of file +紫 +傳說:寶可夢Z-A \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/zh/text_Moves_zh-Hans.txt b/PKHeX.Core/Resources/text/other/zh/text_Moves_zh-Hans.txt index dda359e4c..dcde3c684 100644 --- a/PKHeX.Core/Resources/text/other/zh/text_Moves_zh-Hans.txt +++ b/PKHeX.Core/Resources/text/other/zh/text_Moves_zh-Hans.txt @@ -917,4 +917,5 @@ 闪电强袭 精神噪音 快手还击 -邪毒锁链 \ No newline at end of file +邪毒锁链 +归无之光 \ No newline at end of file diff --git a/PKHeX.Core/Resources/text/other/zh/text_Moves_zh-Hant.txt b/PKHeX.Core/Resources/text/other/zh/text_Moves_zh-Hant.txt index 6c86c0b52..8c247ae91 100644 --- a/PKHeX.Core/Resources/text/other/zh/text_Moves_zh-Hant.txt +++ b/PKHeX.Core/Resources/text/other/zh/text_Moves_zh-Hant.txt @@ -917,4 +917,5 @@ 閃電強襲 精神噪音 快手還擊 -邪毒鎖鏈 \ No newline at end of file +邪毒鎖鏈 +歸無之光 \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessor9SV.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessor9SV.cs index c9c5ceedf..0bee2aec8 100644 --- a/PKHeX.Core/Saves/Access/SaveBlockAccessor9SV.cs +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessor9SV.cs @@ -113,7 +113,7 @@ public Raid9(SAV9SV sav) private const uint KBlueberryQuestRecords = 0x7BF02DBE; private const uint KSandwiches = 0x29B4AED2; // [0xC][151] index, unlocked, times made private const uint KCurrentClothing = 0x64235B3D; - private const uint KCurrentAppearance = 0x812FC3E3; + private const uint KCurrentAppearance = 0x812FC3E3; // (conveniently named `PLAYER_SAVE_DATA`, same as PlayerData8b's official name! private const uint KCurrentRotomPhoneCase = 0x1433CED7; private const uint KRentalTeams = 0x19CB0339; private const uint KRentalTeamCodes = 0xB476F6D4; diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessor9ZA.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessor9ZA.cs new file mode 100644 index 000000000..9db9c9ad6 --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessor9ZA.cs @@ -0,0 +1,134 @@ +using System.Collections.Generic; +using System.Net.Mail; +// ReSharper disable UnusedMember.Local +#pragma warning disable IDE0051 // Remove unused private members +#pragma warning disable RCS1213 // Remove unused member declaration. + +namespace PKHeX.Core; + +/// +/// Information for Accessing individual blocks within a . +/// +public sealed class SaveBlockAccessor9ZA(SAV9ZA sav) : SCBlockAccessor +{ + public override IReadOnlyList BlockInfo { get; } = sav.AllBlocks; + public Box8 BoxInfo { get; } = new(sav, Block(sav, KBox)); + public Party9a PartyInfo { get; } = new(sav, Block(sav, KParty)); + public MyItem9a Items { get; } = new(sav, Block(sav, KItem)); + public MyStatus9a MyStatus { get; } = new(sav, Block(sav, KMyStatus)); + public BoxLayout9a BoxLayout { get; } = new(sav, Block(sav, KBoxLayout)); + public PlayTime9a Played { get; } = new(sav, Block(sav, KPlayTime)); // not actually used + public Zukan9a Zukan { get; } = new(sav, Block(sav, KPokedex)); + public Epoch1900DateTimeValue LastSaved { get; } = new(Block(sav, KLastSaved)); + public TeamIndexes8 TeamIndexes { get; } = new(sav, Block(sav, KTeamIndexes), Block(sav, KTeamLocks)); + public Epoch1900DateTimeValue EnrollmentDate { get; } = new(Block(sav, KEnrollmentDate)); // not actually used + public Coordinates9a Coordinates { get; } = new(sav, Block(sav, KCoordinates)); + public InfiniteRoyale9a InfiniteRoyale { get; } = new(sav, Block(sav, KInfiniteRoyale)); + public PlayerFashion9a PlayerFashion { get; } = new(sav, Block(sav, KCurrentClothing)); + + public EventWorkFlagStorage Event { get; } = new(sav, Block(sav, KEventFlag)); + public EventWorkValueStorage Quest { get; } = new(sav, Block(sav, KEventWorkQuest)); + public EventWorkValueStorage Mable { get; } = new(sav, Block(sav, KEventWorkMable)); + public EventWorkValueStorage Work { get; } = new(sav, Block(sav, KEventWork)); + public EventWorkValueStorage Work1 { get; } = new(sav, Block(sav, KEventWork1)); + public EventWorkValueStorage Work2 { get; } = new(sav, Block(sav, KEventWork2)); + public EventWorkValueStorage Work3 { get; } = new(sav, Block(sav, KEventWork3)); + public EventWorkFlagStorage Flags { get; } = new(sav, Block(sav, KEventFlagsOther)); + + private const uint KBox = 0x0d66012c; // Box Data + private const uint KParty = 0x3AA1A9AD; // Party Data + private const uint KItem = 0x21C9BD44; // Items + private const uint KMyStatus = 0xE3E89BD1; // Trainer Details + private const uint KBoxLayout = 0x19722c89; // Box Names + private const uint KPlayTime = 0xEDAFF794; // Time Played + private const uint KPokedex = 0x2D87BE5C; + private const uint KLastSaved = 0x1522C79C; // Epoch 1900 DateTime + private const uint KTeamIndexes = 0x33F39467; // Team Indexes for competition + private const uint KTeamLocks = 0x605EBC30; + private const uint KEnrollmentDate = 0xC7409C89; // Epoch 1900 Date + public const uint KBoxesUnlocked = 0x71825204; + public const uint KBoxWallpapers = 0x2EB1B190; // Box Wallpapers + public const uint KMoney = 0x4F35D0DD; // u32 + public const uint KCurrentBox = 0x017C3CBB; // U32 Box Index + private const uint KCoordinates = 0x910D381F; // Player Coordinates/Rotation + private const uint KInfiniteRoyale = 0x8929BFB6; // object + + private const uint KEventFlag = 0x58505C5E; // event_flag (u64,bool)[2048] + private const uint KEventFlagsOther = 0xED6F46E7; // system_flag (u64,bool)[2048] + private const uint KEventWorkQuest = 0xB9B223B9; // quest_work (u64,u64)[1024] + private const uint KEventWork = 0xFADA7742; // system_work (u64,u64)[256] + private const uint KEventWork1 = 0x2C2C6964; // object 0x400 records? (u64,u64)[64] + private const uint KEventWork2 = 0x8D80EC0F; // object 0x400 records? (u64,u64)[64] + private const uint KEventWorkMable = 0x03913534; // object 0x4000 work-like + private const uint KEventWork3 = 0x53FD0223; // object 0x46500 small values (u64,u64)[18000] + // 7C896A83 0x2000 unused + // B25E7EE5 0x400 unused + // AF2165F0 0x3000 (u64,u64,value) + private const uint KFieldObjectInteractable = 0x7147C953; // (u64,u64,u64,value)[5000] (mega crystal, prize medals) + + private const uint KObstruction = 0x4C26C29B; // (u64, u64-state, u64-unused)[2000] + + public const uint KTicketPointsZARoyale = 0x9A730DE1; // u32 + public const uint KTicketPointsZARoyaleInfinite = 0x1D7EE369; // u32 + + public const uint KPlayedSeconds = 0xCE3AF8F2; // d64 + private const uint KCurrentAppearance = 0x812FC3E3; // u32[18] (conveniently named `PLAYER_SAVE_DATA`, same as PlayerData8b's official name! + private const uint KCurrentClothing = 0x64235B3D; // u64[13], see PlayerFashion9 (size is bigger) + public const uint KFusedCalyrex = 0x916BCA9E; // unused + private const uint KFieldItems = 0x2482AD60; // Stores grabbed status for each existing field item + private const uint KOverworld = 0x5E8E1711; // object 0x28488 + private const uint KLostBalls = 0xDD90CEEC; // (uint ID, uint count)[50] items + public const uint KTimeSecondsPastMidnight = 0x7B70DA66; // f32 + + public const uint KStoredEventEntity = 0x654FCD1E; // 128 * (u64-hash + 0x158+48-entity) = 0x1A8 + public const uint KStoredShinyEntity = 0xF3A8569D; // 10 * (u64-hash + 0x158+48+40-entity + u64-hash) = 0x1F0 + + public const uint KFashionTops = 0xD4BCE690; // 01_230_101 - unlock[4800] + public const uint KFashionBottoms = 0x4DCB6EBC; // 02_011_010 - unlock[5300] + public const uint KFashionAllInOne = 0x324F26DD; // 03_021_212 - unlock[3000] + public const uint KFashionHeadwear = 0x293B1722; // 04_010_108 - unlock[600] + public const uint KFashionEyewear = 0xF4439BD4; // 05_060_101 - unlock[300] + public const uint KFashionGloves = 0x502EA6C8; // 06_010_101 - unlock[200] + public const uint KFashionLegwear = 0x6019F261; // 07_020_115 - unlock[700] + public const uint KFashionFootwear = 0x954C8BAB; // 08_010_105 - unlock[400] + public const uint KFashionSatchels = 0x08638763; // 09_010_101 - unlock[200] + public const uint KFashionEarrings = 0xFA089054; // 10_030_116 - unlock[300] + + public const uint KHairMake00StyleHair = 0x8E466865; // unlock[30] + public const uint KHairMake01StyleBangs = 0x7D78DBBB; // unlock[10] + public const uint KHairMake02ColorHair = 0xA9BF43AF; // unlock[64] - Base Color + public const uint KHairMake03ColorHair = 0x0AABCD8F; // unlock[64] - Blocking + public const uint KHairMake04ColorHair = 0x9D48303D; // unlock[64] - Balayage + public const uint KHairMake05StyleEyebrow = 0x1354939F; // unlock[30] + public const uint KHairMake06ColorEyebrow = 0xF428AFF2; // unlock[64] + public const uint KHairMake07StyleEyes = 0x267FB825; // unlock[8] + public const uint KHairMake08ColorEyes = 0x4856C1F4; // unlock[64] + public const uint KHairMake09StyleEyelash = 0xDE67CD9D; // unlock[16] + public const uint KHairMake10ColorEyelash = 0x53106AFC; // unlock[64] + public const uint KHairMake11Lips = 0xDACF515D; // unlock[20] + public const uint KHairMake12BeautyMark = 0x0B758BF5; // unlock[18] + public const uint KHairMake13Freckles = 0xFC08F055; // unlock[8] + public const uint KHairMake14DarkCircles = 0x550EC7E1; // unlock[8] + + // Taken during the story after the Society for Battle Connoisseurs complete + public const uint KPictureSBCWidth = 0x70CDE2DF; // 340 + public const uint KPictureSBCHeight = 0x08B59D02; // 340 + public const uint KPictureSBCData = 0x89816ADE; // byte[] + + // Taken at the start of the game inside Hotel Z + public const uint KPictureInitialWidth = 0x1C140AA0; // 564 + public const uint KPictureInitialHeight = 0x72A45DD7; // 292 + public const uint KPictureInitialData = 0x71392A77; // byte[] + + // Taken by the player at any time + public const uint KPictureCurrentWidth = 0x580634CD; // 564 + public const uint KPictureCurrentHeight = 0xF286ADA4; // 444 + public const uint KPictureCurrentData = 0x48064544; // byte[] + + private const uint KMysteryGiftRecords = 0xBEC26CD5; // object, stores the majority of received card? + private const uint KNPLNUserID = 0x6CF6C183; // NEX no longer being used, now using NPLN + + private const uint KNightRoyalePostBattleRewards = 0x356087AD; // object + private const uint KNightRoyaleTrainerStatus = 0x718B8CB1; // object + private const uint KNightRoyaleBonusCards = 0x2A07F494; // object +} diff --git a/PKHeX.Core/Saves/Encryption/SwishCrypto/FnvHash.cs b/PKHeX.Core/Saves/Encryption/SwishCrypto/FnvHash.cs index 34b9df4d9..30e0823a5 100644 --- a/PKHeX.Core/Saves/Encryption/SwishCrypto/FnvHash.cs +++ b/PKHeX.Core/Saves/Encryption/SwishCrypto/FnvHash.cs @@ -11,6 +11,8 @@ public static class FnvHash private const ulong kFnvPrime_64 = 0x00000100000001b3; private const ulong kOffsetBasis_64 = 0xCBF29CE484222645; + public const ulong HashEmpty = kOffsetBasis_64; + /// /// Gets the hash code of the input sequence via the alternative Fnv1 method. /// diff --git a/PKHeX.Core/Saves/Encryption/SwishCrypto/SCBlockMetadata.cs b/PKHeX.Core/Saves/Encryption/SwishCrypto/SCBlockMetadata.cs index ff6161838..30c81f0ee 100644 --- a/PKHeX.Core/Saves/Encryption/SwishCrypto/SCBlockMetadata.cs +++ b/PKHeX.Core/Saves/Encryption/SwishCrypto/SCBlockMetadata.cs @@ -60,6 +60,23 @@ public static void AddExtraKeyNames(Dictionary names, IEnumerable< } } + /// + public static void AddExtraKeyNames64(Dictionary names, IEnumerable lines) + { + foreach (ReadOnlySpan line in lines) + { + var split = line.IndexOf('\t'); + if (split < 0) + continue; + var hex = line[..split]; + if (!ulong.TryParse(hex, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out var value)) + continue; + + var name = line[(split + 1)..].ToString(); + names.TryAdd(value, name); + } + } + private static string GetSortKey(in ComboItem item) { var text = item.Text; diff --git a/PKHeX.Core/Saves/SAV1.cs b/PKHeX.Core/Saves/SAV1.cs index d529692f2..5d39b7c8d 100644 --- a/PKHeX.Core/Saves/SAV1.cs +++ b/PKHeX.Core/Saves/SAV1.cs @@ -439,19 +439,19 @@ public override IReadOnlyList Inventory public Memory GetDaycareSlot(int index) { - ArgumentOutOfRangeException.ThrowIfNotEqual(index, 0, nameof(index)); + ArgumentOutOfRangeException.ThrowIfNotEqual(index, 0); return Reserved.Slice(DaycareOffset, SIZE_STORED); } public bool IsDaycareOccupied(int index) { - ArgumentOutOfRangeException.ThrowIfNotEqual(index, 0, nameof(index)); + ArgumentOutOfRangeException.ThrowIfNotEqual(index, 0); return Data[Offsets.Daycare] == 0x01; } public void SetDaycareOccupied(int index, bool occupied) { - ArgumentOutOfRangeException.ThrowIfNotEqual(index, 0, nameof(index)); + ArgumentOutOfRangeException.ThrowIfNotEqual(index, 0); Data[Offsets.Daycare] = (byte)(occupied ? 0x01 : 0x00); } diff --git a/PKHeX.Core/Saves/SAV3E.cs b/PKHeX.Core/Saves/SAV3E.cs index db68d1c1e..32b1f2893 100644 --- a/PKHeX.Core/Saves/SAV3E.cs +++ b/PKHeX.Core/Saves/SAV3E.cs @@ -290,7 +290,7 @@ public override Gen3MysteryData MysteryData private const int CountPaintings = 5; private Span GetPaintingSpan(int index) { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, CountPaintings, nameof(index)); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, CountPaintings); return Large.Slice(Painting + (Paintings3.SIZE * index), Paintings3.SIZE * CountPaintings); } public Paintings3 GetPainting(int index) => new(GetPaintingSpan(index).ToArray(), Japanese); diff --git a/PKHeX.Core/Saves/SAV3RS.cs b/PKHeX.Core/Saves/SAV3RS.cs index 379043934..e9e07be7d 100644 --- a/PKHeX.Core/Saves/SAV3RS.cs +++ b/PKHeX.Core/Saves/SAV3RS.cs @@ -180,7 +180,7 @@ public int SwarmIndex private const int CountPaintings = 5; private Span GetPaintingSpan(int index) { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, CountPaintings, nameof(index)); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, CountPaintings); return Large.Slice(Painting + (Paintings3.SIZE * index), Paintings3.SIZE * CountPaintings); } public Paintings3 GetPainting(int index) => new(GetPaintingSpan(index).ToArray(), Japanese); diff --git a/PKHeX.Core/Saves/SAV5B2W2.cs b/PKHeX.Core/Saves/SAV5B2W2.cs index 05864eeb7..3c6dee817 100644 --- a/PKHeX.Core/Saves/SAV5B2W2.cs +++ b/PKHeX.Core/Saves/SAV5B2W2.cs @@ -92,13 +92,13 @@ public Span RivalTrash public Memory GetPokestarMovie([Range(0, PokestarCount)] int index) { - ArgumentOutOfRangeException.ThrowIfGreaterThan(index, PokestarCount, nameof(index)); + ArgumentOutOfRangeException.ThrowIfGreaterThan(index, PokestarCount); return Buffer.Slice(GetPokestarOffset(index), PokestarLength); } public void SetPokestarMovie([Range(0, PokestarCount)] int index, ReadOnlySpan data, ushort count = 1) { - ArgumentOutOfRangeException.ThrowIfGreaterThan(index, PokestarCount, nameof(index)); + ArgumentOutOfRangeException.ThrowIfGreaterThan(index, PokestarCount); var offset = GetPokestarOffset(index); WriteExtSection(data, offset, PokestarLength, count); PlayerData.UpdateExtData(ExtDataSectionNote5.Movie1 + index, count); @@ -111,13 +111,13 @@ public void SetPokestarMovie([Range(0, PokestarCount)] int index, ReadOnlySpan GetPWT([Range(0, PWTCount)] int index) { - ArgumentOutOfRangeException.ThrowIfGreaterThan(index, PWTCount, nameof(index)); + ArgumentOutOfRangeException.ThrowIfGreaterThan(index, PWTCount); return Buffer.Slice(PWTOffset + (index * PWTInterval), PWTLength); } public void SetPWT([Range(0, PWTCount)] int index, ReadOnlySpan data, ushort count = 1) { - ArgumentOutOfRangeException.ThrowIfGreaterThan(index, PWTCount, nameof(index)); + ArgumentOutOfRangeException.ThrowIfGreaterThan(index, PWTCount); var offset = GetPWTOffset(index); WriteExtSection(data, offset, PWTLength, count); PlayerData.UpdateExtData(ExtDataSectionNote5.PWT1 + index, count); diff --git a/PKHeX.Core/Saves/SAV9ZA.cs b/PKHeX.Core/Saves/SAV9ZA.cs new file mode 100644 index 000000000..f4ff14131 --- /dev/null +++ b/PKHeX.Core/Saves/SAV9ZA.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; + +namespace PKHeX.Core; + +public sealed class SAV9ZA : SaveFile, ISCBlockArray, ISaveFileRevision, IBoxDetailName, IBoxDetailWallpaper +{ + protected internal override string ShortSummary => $"{OT} ({Version}) - {LastSaved.DisplayValue}"; + public override string Extension => string.Empty; + + public SAV9ZA(Memory data) : this(SwishCrypto.Decrypt(data.Span)) { } + + private SAV9ZA(IReadOnlyList blocks) : base(Memory.Empty) + { + AllBlocks = blocks; + Blocks = new SaveBlockAccessor9ZA(this); + SaveRevision = 0; + Initialize(); + } + + public SAV9ZA() + { + AllBlocks = BlankBlocks9a.GetBlankBlocks(); + Blocks = new SaveBlockAccessor9ZA(this); + SaveRevision = 0; + Initialize(); + ClearBoxes(); + } + + public override void CopyChangesFrom(SaveFile sav) + { + // Absorb changes from all blocks + var z = (SAV9ZA)sav; + var mine = AllBlocks; + var newB = z.AllBlocks; + for (int i = 0; i < mine.Count; i++) + mine[i].CopyFrom(newB[i]); + State.Edited = true; + } + + public int SaveRevision { get; } + + public string SaveRevisionString => SaveRevision switch + { + 0 => "-Base", // Vanilla + _ => throw new ArgumentOutOfRangeException(nameof(SaveRevision)), + }; + + public override bool ChecksumsValid => true; + public override string ChecksumInfo => string.Empty; + protected override void SetChecksums() { } // None! + protected override Memory GetFinalData() => SwishCrypto.Encrypt(AllBlocks); + + public override PersonalTable9ZA Personal => PersonalTable.ZA; + public override ReadOnlySpan HeldItems => Legal.HeldItems_ZA; + + #region Blocks + public SCBlockAccessor Accessor => Blocks; + public SaveBlockAccessor9ZA Blocks { get; } + public IReadOnlyList AllBlocks { get; } + public T GetValue(uint key) where T : struct => Blocks.GetBlockValueSafe(key); + public void SetValue(uint key, T value) where T : struct => Blocks.SetBlockValueSafe(key, value); + public Box8 BoxInfo => Blocks.BoxInfo; + public Party9a PartyInfo => Blocks.PartyInfo; + public MyItem9a Items => Blocks.Items; + public MyStatus9a MyStatus => Blocks.MyStatus; + public Zukan9a Zukan => Blocks.Zukan; + public BoxLayout9a BoxLayout => Blocks.BoxLayout; + public PlayTime9a Played => Blocks.Played; + public TeamIndexes8 TeamIndexes => Blocks.TeamIndexes; + public Epoch1900DateTimeValue LastSaved => Blocks.LastSaved; + public Epoch1900DateTimeValue StartTime => Blocks.EnrollmentDate; + public Coordinates9a Coordinates => Blocks.Coordinates; + public InfiniteRoyale9a InfiniteRoyale => Blocks.InfiniteRoyale; + public PlayerFashion9a PlayerFashion => Blocks.PlayerFashion; + #endregion + + protected override SAV9ZA CloneInternal() + { + var blockCopy = new SCBlock[AllBlocks.Count]; + for (int i = 0; i < AllBlocks.Count; i++) + blockCopy[i] = AllBlocks[i].Clone(); + return new(blockCopy); + } + + private ushort m_spec, m_item, m_move, m_abil; + public override int MaxBallID => Legal.MaxBallID_9a; + public override GameVersion MaxGameID => Legal.MaxGameID_HOME2; + public override ushort MaxMoveID => m_move; + public override ushort MaxSpeciesID => m_spec; + public override int MaxItemID => m_item; + public override int MaxAbilityID => m_abil; + + public override bool HasPokeDex => true; + + private void Initialize() + { + Box = 0; + Party = 0; + TeamIndexes.LoadBattleTeams(); + + int rev = SaveRevision; + if (rev == 0) + { + m_move = Legal.MaxMoveID_9a; + m_spec = Legal.MaxSpeciesID_9a; + m_item = Legal.MaxItemID_9a; + m_abil = Legal.MaxAbilityID_9a; + } + else + { + throw new ArgumentOutOfRangeException(nameof(SaveRevision)); + } + } + + public override IReadOnlyList PKMExtensions => EntityFileExtension.GetExtensionsHOME(); + + // Configuration + protected override int SIZE_STORED => PokeCrypto.SIZE_9STORED; + protected override int SIZE_PARTY => PokeCrypto.SIZE_9PARTY; + public override int SIZE_BOXSLOT => PokeCrypto.SIZE_9PARTY + GapBoxSlot; + public override PA9 BlankPKM => new(); + public override Type PKMType => typeof(PA9); + + public override int BoxCount => BoxLayout9.BoxCount; + public override int MaxEV => EffortValues.Max252; + public override byte Generation => 9; + public override EntityContext Context => EntityContext.Gen9a; + public override int MaxStringLengthTrainer => 12; + public override int MaxStringLengthNickname => 12; + protected override PA9 GetPKM(byte[] data) => new(data); + protected override byte[] DecryptPKM(byte[] data) => PokeCrypto.DecryptArray9(data); + + public override bool IsVersionValid() => Version is GameVersion.ZA; + + public override string GetString(ReadOnlySpan data) + => StringConverter8.GetString(data); + public override int LoadString(ReadOnlySpan data, Span destBuffer) + => StringConverter8.LoadString(data, destBuffer); + public override int SetString(Span destBuffer, ReadOnlySpan value, int maxLength, StringConverterOption option) + => StringConverter8.SetString(destBuffer, value, maxLength, option); + + // Player Information + public override uint ID32 { get => MyStatus.ID32; set => MyStatus.ID32 = value; } + public override ushort TID16 { get => MyStatus.TID16; set => MyStatus.TID16 = value; } + public override ushort SID16 { get => MyStatus.SID16; set => MyStatus.SID16 = value; } + public override GameVersion Version { get => (GameVersion)MyStatus.Game; set => MyStatus.Game = (byte)value; } + public override byte Gender { get => MyStatus.Gender; set => MyStatus.Gender = value; } + public override int Language { get => MyStatus.Language; set => MyStatus.Language = value; } + public override string OT { get => MyStatus.OT; set => MyStatus.OT = value; } + public override uint Money { get => (uint)Blocks.GetBlockValue(SaveBlockAccessor9ZA.KMoney); set => Blocks.SetBlockValue(SaveBlockAccessor9ZA.KMoney, value); } + + public override int PlayedHours { get => Played.PlayedHours; set => Played.PlayedHours = value; } + public override int PlayedMinutes { get => Played.PlayedMinutes; set => Played.PlayedMinutes = value; } + public override int PlayedSeconds { get => Played.PlayedSeconds; set => Played.PlayedSeconds = value; } + + // Inventory + public override IReadOnlyList Inventory { get => Items.Inventory; set => Items.Inventory = value; } + + // Storage + private const int GapBoxSlot = 0x40; + private const int GapPartySlot = 0x88; // 0x40 + 0x48 + public override int GetPartyOffset(int slot) => Party + ((SIZE_PARTY + GapPartySlot) * slot); + public override int GetBoxOffset(int box) => Box + (SIZE_BOXSLOT * box * 30); + public string GetBoxName(int box) => BoxLayout[box]; + public void SetBoxName(int box, ReadOnlySpan value) => BoxLayout.SetBoxName(box, value); + public override byte[] GetDataForBox(PKM pk) => pk.EncryptedPartyData; + + protected override void SetPKM(PKM pk, bool isParty = false) + { + PA9 pa9 = (PA9)pk; + // Apply to this Save File + pa9.UpdateHandler(this); + + if (FormArgumentUtil.IsFormArgumentTypeDatePair(pa9.Species, pa9.Form)) + { + pa9.FormArgumentElapsed = pa9.FormArgumentMaximum = 0; + pa9.FormArgumentRemain = (byte)GetFormArgument(pa9); + } + + pa9.RefreshChecksum(); + } + + private static uint GetFormArgument(PKM pk) + { + if (pk.Form == 0) + return 0; + return pk.Species switch + { + (int)Species.Furfrou => 5u, // Furfrou + // Hoopa no longer sets Form Argument for Unbound form. Let it set 0. + _ => 0u, + }; + } + + protected override void SetDex(PKM pk) => Zukan.SetDex(pk); + public override bool GetCaught(ushort species) => Zukan.GetCaught(species); + public override bool GetSeen(ushort species) => Zukan.GetSeen(species); + + public override int PartyCount + { + get => PartyInfo.PartyCount; + protected set => PartyInfo.PartyCount = value; + } + + protected override Span BoxBuffer => BoxInfo.Data; + protected override Span PartyBuffer => PartyInfo.Data; + public override PA9 GetDecryptedPKM(byte[] data) => GetPKM(DecryptPKM(data)); + public override PA9 GetBoxSlot(int offset) => GetDecryptedPKM(BoxInfo.Data.Slice(offset, SIZE_PARTY).ToArray()); // party format in boxes! + + public override StorageSlotSource GetBoxSlotFlags(int index) + { + int team = Array.IndexOf(TeamIndexes.TeamSlots, index); + if (team < 0) + return StorageSlotSource.None; + + team /= 6; + var result = (StorageSlotSource)((int)StorageSlotSource.BattleTeam1 << team); + if (TeamIndexes.GetIsTeamLocked(team)) + result |= StorageSlotSource.Locked; + return result; + } + + public override int CurrentBox { get => BoxLayout.CurrentBox; set => BoxLayout.CurrentBox = value; } + public override int BoxesUnlocked { get => (byte)Blocks.GetBlockValue(SaveBlockAccessor9ZA.KBoxesUnlocked); set => Blocks.SetBlockValue(SaveBlockAccessor9ZA.KBoxesUnlocked, (byte)value); } + + public int GetBoxWallpaper(int box) + { + if ((uint)box >= BoxCount) + return box; + var b = Blocks.GetBlock(SaveBlockAccessor9ZA.KBoxWallpapers); + return b.Data[box]; + } + + public void SetBoxWallpaper(int box, int value) + { + if ((uint)box >= BoxCount) + return; + var b = Blocks.GetBlock(SaveBlockAccessor9ZA.KBoxWallpapers); + b.Data[box] = (byte)value; + } + + public uint TicketPointsRoyale + { + get => Blocks.GetBlockValue(SaveBlockAccessor9ZA.KTicketPointsZARoyale); + set => Blocks.SetBlockValue(SaveBlockAccessor9ZA.KTicketPointsZARoyale, value); + } + + public uint TicketPointsRoyaleInfinite + { + get => Blocks.GetBlockValue(SaveBlockAccessor9ZA.KTicketPointsZARoyaleInfinite); + set => Blocks.SetBlockValue(SaveBlockAccessor9ZA.KTicketPointsZARoyaleInfinite, value); + } +} diff --git a/PKHeX.Core/Saves/SaveFileMetadata.cs b/PKHeX.Core/Saves/SaveFileMetadata.cs index a4edaa670..d731515dc 100644 --- a/PKHeX.Core/Saves/SaveFileMetadata.cs +++ b/PKHeX.Core/Saves/SaveFileMetadata.cs @@ -85,6 +85,18 @@ public void SetExtraInfo(Memory header, Memory footer, ISaveHandler Handler = handler; } + /// + public void ShareExtraInfo(SaveFileMetadata other) + { + other.Header = Header; + other.Footer = Footer; + other.Handler = Handler; + if (FilePath is not null) + other.SetAsLoadedFile(FilePath); + else + other.SetAsBlank(); + } + /// /// Sets the details of a path to a object. /// diff --git a/PKHeX.Core/Saves/Substructures/Gen8/SWSH/TeamIndexes8.cs b/PKHeX.Core/Saves/Substructures/Gen8/SWSH/TeamIndexes8.cs index 5d3a64c3a..a0b568416 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/SWSH/TeamIndexes8.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/SWSH/TeamIndexes8.cs @@ -20,6 +20,7 @@ private TeamIndexes8(SaveFile sav, SCBlock indexes, SCBlock locks) public TeamIndexes8(SAV8SWSH sav, SCBlock indexes, SCBlock locks) : this((SaveFile)sav, indexes, locks) { } public TeamIndexes8(SAV9SV sav, SCBlock indexes, SCBlock locks) : this((SaveFile)sav, indexes, locks) { } + public TeamIndexes8(SAV9ZA sav, SCBlock indexes, SCBlock locks) : this((SaveFile)sav, indexes, locks) { } public void LoadBattleTeams() { diff --git a/PKHeX.Core/Saves/Substructures/Gen9/BlankBlocks9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/BlankBlocks9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/BlankBlocks9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/BlankBlocks9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/BlueberryClubRoom9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/BlueberryClubRoom9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/BlueberryClubRoom9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/BlueberryClubRoom9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/BlueberryQuestRecord9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/BlueberryQuestRecord9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/BlueberryQuestRecord9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/BlueberryQuestRecord9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/Box9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/Box9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/Box9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/Box9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/BoxLayout9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/BoxLayout9.cs similarity index 91% rename from PKHeX.Core/Saves/Substructures/Gen9/BoxLayout9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/BoxLayout9.cs index fbd7ba522..e9f66a99e 100644 --- a/PKHeX.Core/Saves/Substructures/Gen9/BoxLayout9.cs +++ b/PKHeX.Core/Saves/Substructures/Gen9/SV/BoxLayout9.cs @@ -1,4 +1,5 @@ using System; +using static System.Buffers.Binary.BinaryPrimitives; namespace PKHeX.Core; @@ -14,7 +15,7 @@ public sealed class BoxLayout9(SAV9SV sav, SCBlock block) : SaveBlock(sa public string GetBoxName(int box) { var span = GetBoxNameSpan(box); - if (System.Buffers.Binary.BinaryPrimitives.ReadUInt16LittleEndian(span) == 0) + if (ReadUInt16LittleEndian(span) == 0) return BoxDetailNameExtensions.GetDefaultBoxName(box); return SAV.GetString(span); } diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ConfigCamera9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/ConfigCamera9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/ConfigCamera9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/ConfigCamera9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ConfigSave9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/ConfigSave9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/ConfigSave9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/ConfigSave9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/DXT1.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/DXT1.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/DXT1.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/DXT1.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/FixedSpawnList9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/FixedSpawnList9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/FixedSpawnList9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/FixedSpawnList9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/MyItem9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/MyItem9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/MyItem9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/MyItem9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/MyStatus9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/MyStatus9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/MyStatus9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/MyStatus9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/Party9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/Party9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/Party9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/Party9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/PlayTime9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/PlayTime9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/PlayTime9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/PlayTime9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/PlayerAppearance9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/PlayerAppearance9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/PlayerAppearance9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/PlayerAppearance9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/PlayerFashion9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/PlayerFashion9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/PlayerFashion9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/PlayerFashion9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/PlayerFashionUnlock9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/PlayerFashionUnlock9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/PlayerFashionUnlock9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/PlayerFashionUnlock9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/PouchSize9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/PouchSize9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/PouchSize9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/PouchSize9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/RaidSevenStar9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/RaidSevenStar9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/RaidSevenStar9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/RaidSevenStar9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/RaidSpawnList9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/RaidSpawnList9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/RaidSpawnList9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/RaidSpawnList9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/RuntimeLanguage.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/RuntimeLanguage.cs similarity index 92% rename from PKHeX.Core/Saves/Substructures/Gen9/RuntimeLanguage.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/RuntimeLanguage.cs index 0ee5c4462..2316ce751 100644 --- a/PKHeX.Core/Saves/Substructures/Gen9/RuntimeLanguage.cs +++ b/PKHeX.Core/Saves/Substructures/Gen9/SV/RuntimeLanguage.cs @@ -11,6 +11,7 @@ public enum RuntimeLanguage Korean = 6, ChineseS = 7, ChineseT = 8, + LATAM = 9, } public static class RuntimeLanguageExtensions @@ -26,6 +27,7 @@ public static class RuntimeLanguageExtensions LanguageID.Korean => RuntimeLanguage.Korean, LanguageID.ChineseS => RuntimeLanguage.ChineseS, LanguageID.ChineseT => RuntimeLanguage.ChineseT, + LanguageID.SpanishL => RuntimeLanguage.LATAM, _ => RuntimeLanguage.English, // Default to English }; } diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ThrowStyle9.cs b/PKHeX.Core/Saves/Substructures/Gen9/SV/ThrowStyle9.cs similarity index 100% rename from PKHeX.Core/Saves/Substructures/Gen9/ThrowStyle9.cs rename to PKHeX.Core/Saves/Substructures/Gen9/SV/ThrowStyle9.cs diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/BlankBlocks9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/BlankBlocks9a.cs new file mode 100644 index 000000000..8efed4108 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/BlankBlocks9a.cs @@ -0,0 +1,61 @@ +using System; + +namespace PKHeX.Core; + +/// +/// metadata for +/// +public static class BlankBlocks9a +{ + public const byte BlankRevision = 0; // Latest + + /// + /// Creates a blank array for + /// + public static SCBlock[] GetBlankBlocks() => SCBlockUtil.GetBlankBlockArray(DefaultChunkSizes); + + private static ReadOnlySpan DefaultChunkSizes => + [ + 0x006ABFB7, 0x00004, 0x017C3CBB, 0x00001, 0x03913534, 0x04000, 0x041137D8, 0x00004, + 0x05773961, 0x00004, 0x08638763, 0x00640, 0x08B59D02, 0x00004, 0x08D4C4DC, 0x00008, + 0x0926555A, 0x00008, 0x0AABCD8F, 0x00200, 0x0B758BF5, 0x00090, 0x0D49F01C, 0x00008, + 0x0D66012C, 0x5FA00, 0x0F0A6814, 0x00004, 0x0FED62EB, 0x00020, 0x10789EC8, 0x00004, + 0x10B0677E, 0x00140, 0x11796819, 0x04000, 0x1354939F, 0x000F0, 0x150F04DB, 0x00900, + 0x1522C79C, 0x00008, 0x1720A5E0, 0x00400, 0x1866780C, 0x000E4, 0x18A80B0E, 0x08000, + 0x19722C89, 0x00440, 0x19FC5B7B, 0x00004, 0x1C140AA0, 0x00004, 0x1C91B58A, 0x00008, + 0x1CDCD72D, 0x00020, 0x1D7EE369, 0x00004, 0x20487806, 0x00044, 0x21BB87D5, 0x00018, + 0x21C9BD44, 0x0BC00, 0x23FF8209, 0x00002, 0x2482AD60, 0x3A980, 0x267FB825, 0x00040, + 0x293B1722, 0x01C20, 0x2A07F494, 0x00300, 0x2A192063, 0x00C00, 0x2C2C6964, 0x00400, + 0x2C5A822A, 0x00008, 0x2D87BE5C, 0x27068, 0x2EB1B190, 0x00020, 0x31379AF7, 0x00028, + 0x324F26DD, 0x05DC0, 0x33395EDE, 0x05A00, 0x33F30168, 0x00008, 0x33F39467, 0x00048, + 0x34597EF7, 0x00008, 0x356087AD, 0x02000, 0x385BD589, 0x00004, 0x3AA1A9AD, 0x00B40, + 0x40CC5A21, 0x00002, 0x41D869BD, 0x00004, 0x48064544, 0x2E2D8, 0x4856C1F4, 0x00200, + 0x4B5C1B96, 0x08000, 0x4BF1E19C, 0x00008, 0x4C26C29B, 0x05DC0, 0x4DCB6EBC, 0x0A5A0, + 0x4F35D0DD, 0x00004, 0x502EA6C8, 0x00640, 0x53106AFC, 0x00200, 0x53FD0223, 0x46500, + 0x550EC7E1, 0x00040, 0x580634CD, 0x00004, 0x58505C5E, 0x08000, 0x5CD6F27B, 0x00004, + 0x5D2A4162, 0x00004, 0x5E8E1711, 0x28488, 0x6019F261, 0x015E0, 0x605EBC30, 0x00001, + 0x618477B1, 0x00008, 0x6249C002, 0x00020, 0x64235B3D, 0x00068, 0x649123E2, 0x000CC, + 0x654FCD1E, 0x0D400, 0x698521C7, 0x00008, 0x6AC77BA1, 0x00068, 0x6BE9A4DA, 0x00008, + 0x6C585058, 0x00008, 0x6CF6C183, 0x0001D, 0x6F11121F, 0x00080, 0x703B681A, 0x00008, + 0x70CDE2DF, 0x00004, 0x711A8242, 0x00008, 0x71392A77, 0x2E2D8, 0x7147C953, 0x27100, + 0x71825204, 0x00001, 0x718B8CB1, 0x00800, 0x7211D868, 0x00100, 0x72A45DD7, 0x00004, + 0x7378188A, 0x00020, 0x79ABCB0B, 0x75300, 0x7B70DA66, 0x00004, 0x7C008151, 0x00004, + 0x7C858F12, 0x00008, 0x7C896A83, 0x02000, 0x7D78DBBB, 0x00050, 0x7DC11835, 0x05000, + 0x812FC3E3, 0x00048, 0x82EEA400, 0x00100, 0x835F3F37, 0x00004, 0x85DBDCE9, 0x0000C, + 0x8881D333, 0x00008, 0x8929BFB6, 0x00018, 0x89816ADE, 0x20000, 0x8C71870A, 0x00004, + 0x8D80EC0F, 0x00400, 0x8E466865, 0x000F0, 0x910D381F, 0x00070, 0x916BCA9E, 0x00158, + 0x92EA5F2C, 0x00030, 0x954C8BAB, 0x00C80, 0x9590D3F0, 0x00008, 0x9A730DE1, 0x00004, + 0x9AD85DFD, 0x00004, 0x9D48303D, 0x00200, 0x9EA30E65, 0x00008, 0x9FEC35B4, 0x00008, + 0xA1EDE127, 0x00008, 0xA9BF43AF, 0x00200, 0xAB54C91A, 0x00180, 0xAC6DD22F, 0x00008, + 0xAF2165F0, 0x03000, 0xB25E7EE5, 0x00400, 0xB654DB77, 0x0028C, 0xB7BA6680, 0x00001, + 0xB9B223B9, 0x04000, 0xB9DBD20C, 0x00008, 0xBAEF1BD4, 0x002B2, 0xBEC26CD5, 0x08D20, + 0xBF60CD09, 0x00004, 0xC074374C, 0x00008, 0xC7409C89, 0x00004, 0xC81B476B, 0x00008, + 0xC9541EB3, 0x00002, 0xCB883AEE, 0x00004, 0xCE3AF8F2, 0x00008, 0xD1A3FF7B, 0x15180, + 0xD1C4A383, 0x00008, 0xD4BCE690, 0x09600, 0xDACF515D, 0x000A0, 0xDD90CEEC, 0x00190, + 0xDE67CD9D, 0x00080, 0xE2CC4DC7, 0x00004, 0xE3AFBE89, 0x00020, 0xE3E89BD1, 0x00078, + 0xE9A56AA6, 0x00008, 0xE9DC8427, 0x00100, 0xEA8121EB, 0x00001, 0xED6F46E7, 0x08000, + 0xEDAFF794, 0x0000C, 0xF1397E13, 0x08000, 0xF286ADA4, 0x00004, 0xF3A8569D, 0x01360, + 0xF428AFF2, 0x00200, 0xF4439BD4, 0x00960, 0xFA089054, 0x00960, 0xFADA7742, 0x01000, + 0xFC08F055, 0x00040, + ]; +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/BoxLayout9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/BoxLayout9a.cs new file mode 100644 index 000000000..a513c375e --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/BoxLayout9a.cs @@ -0,0 +1,40 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +public sealed class BoxLayout9a(SAV9ZA sav, SCBlock block) : SaveBlock(sav, block.Raw), IBoxDetailName +{ + public const int BoxCount = 32; + + private const int StringMaxLength = SAV6.LongStringLength / 2; + + private static int GetBoxNameOffset(int box) => SAV6.LongStringLength * box; + private Span GetBoxNameSpan(int box) => Data.Slice(GetBoxNameOffset(box), SAV6.LongStringLength); + + public string GetBoxName(int box) + { + var span = GetBoxNameSpan(box); + if (ReadUInt16LittleEndian(span) == 0) + return BoxDetailNameExtensions.GetDefaultBoxName(box); + return SAV.GetString(span); + } + + public void SetBoxName(int box, ReadOnlySpan value) + { + var span = GetBoxNameSpan(box); + SAV.SetString(span, value, StringMaxLength, StringConverterOption.ClearZero); + } + + public string this[int i] + { + get => GetBoxName(i); + set => SetBoxName(i, value); + } + + public int CurrentBox + { + get => SAV.GetValue(SaveBlockAccessor9ZA.KCurrentBox); + set => SAV.SetValue(SaveBlockAccessor9ZA.KCurrentBox, (byte)value); + } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/Coordinates9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/Coordinates9a.cs new file mode 100644 index 000000000..d268f413f --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/Coordinates9a.cs @@ -0,0 +1,70 @@ +using System; +using System.Text; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +public sealed class Coordinates9a(SAV9ZA sav, SCBlock block) : SaveBlock(sav, block.Raw) +{ + private Span MapName() => Data[..0x20]; + + public string Map + { + get + { + var span = MapName(); + var trim = span.IndexOf(0); + if (trim >= 0) + span = span[..trim]; + return Encoding.ASCII.GetString(span); + } + set + { + var span = MapName(); + span.Clear(); + var toWrite = value.Length > span.Length ? span.Length : value.Length; + Encoding.ASCII.GetBytes(value.AsSpan(0, toWrite), span); + } + } + + // Position + public float X { get => ReadSingleLittleEndian(Data[0x20..]); set => WriteSingleLittleEndian(Data[0x20..], value); } + public float Z { get => ReadSingleLittleEndian(Data[0x24..]); set => WriteSingleLittleEndian(Data[0x24..], value); } + public float Y { get => ReadSingleLittleEndian(Data[0x28..]); set => WriteSingleLittleEndian(Data[0x28..], value); } + + // Rotation + public float RX { get => ReadSingleLittleEndian(Data[0x30..]); set => WriteSingleLittleEndian(Data[0x30..], value); } + public float RZ { get => ReadSingleLittleEndian(Data[0x34..]); set => WriteSingleLittleEndian(Data[0x34..], value); } + public float RY { get => ReadSingleLittleEndian(Data[0x38..]); set => WriteSingleLittleEndian(Data[0x38..], value); } + public float RW { get => ReadSingleLittleEndian(Data[0x3C..]); set => WriteSingleLittleEndian(Data[0x3C..], value); } + public double Rotation => Math.Atan2(RZ, RW) * 360.0 / Math.PI; + + public void SetCoordinates(float x, float y, float z) + { + // Only set coordinates if epsilon is different enough + const float epsilon = 0.0001f; + if (Math.Abs(X - x) < epsilon && Math.Abs(Y - y) < epsilon && Math.Abs(Z - z) < epsilon) + return; + X = x; + Y = y; + Z = z; + } + + public void SetPlayerRotation(double rotation) + { + var angle = rotation * Math.PI / 360.0d; + SAV.Coordinates.SetPlayerRotation(0, (float)Math.Sin(angle), 0, (float)Math.Cos(angle)); + } + + public void SetPlayerRotation(float rx, float ry, float rz, float rw) + { + // Only set coordinates if epsilon is different enough + const float epsilon = 0.0001f; + if (Math.Abs(RX - rx) < epsilon && Math.Abs(RY - ry) < epsilon && Math.Abs(RZ - rz) < epsilon && Math.Abs(RW - rw) < epsilon) + return; + RX = rx; + RY = ry; + RZ = rz; + RW = rw; + } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/EventWorkStorage64.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/EventWorkStorage64.cs new file mode 100644 index 000000000..25008127f --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/EventWorkStorage64.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +/// +/// Storage for event work values keyed by a 64-bit FNV-1a hash. +/// +/// Unmanaged value type stored alongside the hash. Backed by a 64-bit field. +/// Owning save file. +/// Underlying block providing the backing bytes. +public abstract class EventWorkStorage64(SaveFile sav, SCBlock block) : SaveBlock(sav, block.Raw), + IEventValueStorage where T : struct, IEquatable +{ + // Structure: + // entry[] of u64 hash, T value + // T is backed by a separate u64 + // Essentially, it is + // (u64, u64)[Count]; + // Empty entries use an empty hash value instead of 0. + // Default state is all entries initialized to "empty". + + /// + /// Size in bytes of a single entry: 8 bytes for the key hash + 8 bytes for the value. + /// + public const int ENTRY_SIZE = 16; + private const ulong HashEmpty = FnvHash.HashEmpty; + + public int Count => Data.Length / ENTRY_SIZE; + public int CountUsed => ScanCountUsed(Data); + + private int ScanCountUsed(ReadOnlySpan data) + { + int count = 0; + for (int i = 0; i < Count; i++) + { + var hash = ReadUInt64LittleEndian(data[GetOffset(i)..]); + if (hash == 0) + break; + count++; + } + return count; + } + + private static ulong Hash(ReadOnlySpan name) => FnvHash.HashFnv1a_64(name); + + public bool HasSpace(out int index) => (index = CountUsed) < Count; + public bool HasSpace() => HasSpace(out _); + public bool TryGetValue(ReadOnlySpan name, out T value) => TryGetValue(Hash(name), out value); + + public bool TryGetValue(ulong hash, out T value) + { + var index = GetIndex(hash); + if (index == -1) + { + value = default; + return false; + } + value = GetValue(index); + return true; + } + + protected int GetOffset(int index) + { + if ((uint)index > Count) + throw new ArgumentOutOfRangeException(nameof(index), index, null); + return index * ENTRY_SIZE; + } + + public int GetIndex(ulong hash) + { + for (int i = 0; i < Count; i++) + { + var ofs = i * ENTRY_SIZE; + var entryHash = ReadUInt64LittleEndian(Data.Slice(ofs, 8)); + if (entryHash == hash) + return i; + if (entryHash == HashEmpty) + break; + } + return -1; + } + + public void Clear(int index) => WriteEntry(Data[GetOffset(index)..], HashEmpty, 0); + + private void WriteEntry(int index, ulong hash, ulong value) => WriteEntry(Data[GetOffset(index)..], hash, value); + + private static void WriteEntry(Span data, ulong hash, ulong value) + { + WriteUInt64LittleEndian(data, hash); + WriteUInt64LittleEndian(data[8..], value); + } + + public void Compress() + { + int count = Count; + int writePtr = 0; + for (int readPtr = 0; readPtr < count; readPtr++) + { + var readOfs = GetOffset(readPtr); + var entryHash = ReadUInt64LittleEndian(Data.Slice(readOfs, 8)); + if (entryHash == HashEmpty) + continue; // skip empty + if (writePtr != readPtr) + { + var writeOfs = GetOffset(writePtr); + // Move entry + var dest = Data.Slice(writeOfs, ENTRY_SIZE); + var src = Data.Slice(readOfs, ENTRY_SIZE); + src.CopyTo(dest); + // Clear old entry + Clear(readPtr); + } + writePtr++; + } + } + + public void Sort() + { + Compress(); + var entries = new (ulong Hash, ulong Value)[CountUsed]; + + // Gather used entries. + for (int i = 0; i < entries.Length; i++) + { + var data = Data[GetOffset(i)..]; + var entryHash = ReadUInt64LittleEndian(data); + var entryValue = ReadUInt64LittleEndian(data[8..]); + entries[i] = (entryHash, entryValue); + } + + Array.Sort(entries, Comparer<(ulong Hash, ulong Value)>.Create((a, b) => a.Hash.CompareTo(b.Hash))); + + // Write back + for (int i = 0; i < entries.Length; i++) + WriteEntry(i, entries[i].Hash, entries[i].Value); + } + + public ulong GetKey(int index) => ReadUInt64LittleEndian(Data.Slice(GetOffset(index), 8)); + public void SetKey(int index, ulong key) => WriteUInt64LittleEndian(Data.Slice(GetOffset(index), 8), key); + public abstract T GetValue(int index); + public abstract void SetValue(int index, T value); + + public T this[ReadOnlySpan name] + { + get => TryGetValue(name, out var val) ? val : throw new KeyNotFoundException($"No entry found for name '{name.ToString()}'"); + set => SetValue(name, value); + } + + public T this[ulong hash] + { + get => TryGetValue(hash, out var val) ? val : throw new KeyNotFoundException($"No entry found for hash '{hash:X16}'"); + set => SetValue(hash, value); + } + + public void SetValue(ulong hash, T value) + { + var index = GetIndex(hash); + if (index == -1 && !HasSpace(out index)) + throw new InvalidOperationException("No space available to add new entry."); + WriteEntry(index, hash, 0); + } + + public void SetValue(ReadOnlySpan name, T value) => SetValue(Hash(name), value); +} + +/// +/// Event work storage specialized for boolean flags. Stores 0 or 1 in the value field. +/// +/// Owning save file. +/// Underlying block providing the backing bytes. +public sealed class EventWorkFlagStorage(SAV9ZA sav, SCBlock block) : EventWorkStorage64(sav, block) +{ + public override bool GetValue(int index) + { + var ofs = GetOffset(index); // key + return ReadUInt64LittleEndian(Data.Slice(ofs + 8, 8)) != 0; + } + + public override void SetValue(int index, bool value) + { + var ofs = GetOffset(index); // key + WriteUInt64LittleEndian(Data.Slice(ofs + 8, 8), value ? 1UL : 0UL); + } +} + +/// +/// Event work storage specialized for 64-bit integer values. +/// +/// Owning save file. +/// Underlying block providing the backing bytes. +public sealed class EventWorkValueStorage(SAV9ZA sav, SCBlock block) : EventWorkStorage64(sav, block) +{ + public override ulong GetValue(int index) + { + var ofs = GetOffset(index); // key + return ReadUInt64LittleEndian(Data.Slice(ofs + 8, 8)); + } + + public override void SetValue(int index, ulong value) + { + var ofs = GetOffset(index); // key + WriteUInt64LittleEndian(Data.Slice(ofs + 8, 8), value); + } +} + diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/FashionItem9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/FashionItem9a.cs new file mode 100644 index 000000000..6fc1b3048 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/FashionItem9a.cs @@ -0,0 +1,61 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +public sealed class FashionItem9a : IItemNewFlag, IItemNewShopFlag +{ + public const int SIZE = 8; + public const uint None = ushort.MaxValue; + + // Structure: + // 0x00: uint Fashion ItemID + // 0x04: uint Bitflags + // - 0 IsNew + // - 1 IsNewShop + // - 2 IsNewGroup + // - 3 IsEquipped + // - 4 IsOwned + // remainder: unused + public required uint Value { get; set; } + public uint Flags { get; set; } + + public bool IsNew { get => (Flags & 0x1) != 0; set => Flags = value ? (Flags | 0x1u) : (Flags & ~0x1u); } + public bool IsNewShop { get => (Flags & 0x2) != 0; set => Flags = value ? (Flags | 0x2u) : (Flags & ~0x2u); } + public bool IsNewGroup { get => (Flags & 0x4) != 0; set => Flags = value ? (Flags | 0x4u) : (Flags & ~0x4u); } + public bool IsEquipped { get => (Flags & 0x8) != 0; set => Flags = value ? (Flags | 0x8u) : (Flags & ~0x8u); } + public bool IsOwned { get => (Flags & 0x10) != 0; set => Flags = value ? (Flags | 0x10u) : (Flags & ~0x10u); } + + public static FashionItem9a Read(ReadOnlySpan data) => new() + { + Value = ReadUInt32LittleEndian(data), + Flags = ReadUInt32LittleEndian(data[4..]), + }; + + public void Write(Span data) + { + WriteUInt32LittleEndian(data, Value); + WriteUInt32LittleEndian(data[4..], Flags); + } + + public void Clear() + { + Value = None; + Flags = 0; + } + + public static FashionItem9a[] GetArray(ReadOnlySpan data) + { + int count = data.Length / SIZE; + var items = new FashionItem9a[count]; + for (int i = 0; i < count; i++) + items[i] = Read(data.Slice(i * SIZE, SIZE)); + return items; + } + + public static void SetArray(ReadOnlySpan items, Span data) + { + for (int i = 0; i < items.Length; i++) + items[i].Write(data.Slice(i * SIZE, SIZE)); + } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/HairMakeItem9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/HairMakeItem9a.cs new file mode 100644 index 000000000..d7f0f7230 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/HairMakeItem9a.cs @@ -0,0 +1,57 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +public sealed class HairMakeItem9a : IItemNewFlag +{ + public const int SIZE = 8; + public const uint None = ushort.MaxValue; + + // Structure: + // 0x00: uint Fashion ItemID + // 0x04: uint Bitflags + // - 0 IsNew + // - 1 IsNewShop + // - 2 IsNewGroup + // - 3 IsEquipped + // - 4 IsOwned + // remainder: unused + public required uint Value { get; set; } + public uint Flags { get; set; } + + public bool IsNew { get => (Flags & 0x1) != 0; set => Flags = value ? (Flags | 0x1u) : (Flags & ~0x1u); } + + public static HairMakeItem9a Read(ReadOnlySpan data) => new() + { + Value = ReadUInt32LittleEndian(data), + Flags = ReadUInt32LittleEndian(data[4..]), + }; + + public void Write(Span data) + { + WriteUInt32LittleEndian(data, Value); + WriteUInt32LittleEndian(data[4..], Flags); + } + + public void Clear() + { + Value = None; + Flags = 0; + } + + public static HairMakeItem9a[] GetArray(ReadOnlySpan data) + { + int count = data.Length / SIZE; + var items = new HairMakeItem9a[count]; + for (int i = 0; i < count; i++) + items[i] = Read(data.Slice(i * SIZE, SIZE)); + return items; + } + + public static void SetArray(ReadOnlySpan items, Span data) + { + for (int i = 0; i < items.Length; i++) + items[i].Write(data.Slice(i * SIZE, SIZE)); + } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/IEventValueStorage.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/IEventValueStorage.cs new file mode 100644 index 000000000..6566d4c7d --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/IEventValueStorage.cs @@ -0,0 +1,106 @@ +using System; + +namespace PKHeX.Core; + +/// +/// Provides indexed and key-based access to event work values. +/// +/// Unmanaged value type. +public interface IEventValueStorage where T : struct, IEquatable +{ + /// + /// Total number of entry slots available in the storage. + /// + int Count { get; } + + /// + /// Number of used entries from the start until the first empty slot. + /// + int CountUsed { get; } + + /// + /// Reads the value component of the entry at the specified index. + /// + /// Entry index. + /// The stored value. + T GetValue(int index); + + /// + /// Writes the value component of the entry at the specified index. + /// + /// Entry index. + /// Value to write. + void SetValue(int index, T value); + + /// + /// Writes the value for the entry identified by the 64-bit key. Adds a new entry if not present. + /// + /// 64-bit key. + /// Value to write. + void SetValue(ulong hash, T value); + + /// + /// Writes the value for the entry identified by the provided name. Adds a new entry if not present. + /// + /// Key name. Implementations may hash this to a 64-bit key. + /// Value to write. + void SetValue(ReadOnlySpan name, T value); + + /// + /// Reads the 64-bit key component of the entry at the specified index. + /// + /// Entry index. + ulong GetKey(int index); + + /// + /// Attempts to retrieve a value by the provided name. + /// + /// Key name. Implementations may hash this to a 64-bit key. + /// Resulting value if found; otherwise the default of . + /// true if the key exists; otherwise false. + bool TryGetValue(ReadOnlySpan name, out T value); + + /// + /// Attempts to retrieve a value by its 64-bit key. + /// + /// 64-bit key. + /// Resulting value if found; otherwise the default of . + /// true if the key exists; otherwise false. + bool TryGetValue(ulong hash, out T value); + + /// + /// Gets the index of the entry matching the provided 64-bit key, or -1 if not present. + /// + /// 64-bit key. + /// Index of the entry if found; otherwise -1. + int GetIndex(ulong hash); + + /// + /// Clears the entry at the specified index. + /// + /// Index of the entry to clear. + void Clear(int index); + + /// + /// Compacts the storage by shifting used entries toward the start, preserving order. + /// + void Compress(); + + /// + /// Sorts used entries by their key in ascending order. + /// + void Sort(); + + /// + /// Checks if there is a free slot available and returns the index of the first free slot. + /// + /// Index of the first free slot if available; otherwise undefined. + /// true if a free slot exists; otherwise false. + bool HasSpace(out int index); + + /// + /// Checks if there is a free slot available. + /// + /// true if a free slot exists; otherwise false. + bool HasSpace(); +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/InfiniteRoyale9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/InfiniteRoyale9a.cs new file mode 100644 index 000000000..c32357861 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/InfiniteRoyale9a.cs @@ -0,0 +1,13 @@ +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +public sealed class InfiniteRoyale9a(SAV9ZA sav, SCBlock block) : SaveBlock(sav, block.Raw) +{ + public uint Value0 { get => ReadUInt32LittleEndian(Data); set => WriteUInt32LittleEndian(Data, value); } + public uint Value1 { get => ReadUInt32LittleEndian(Data[0x04..]); set => WriteUInt32LittleEndian(Data[0x04..], value); } + public uint Wins { get => ReadUInt32LittleEndian(Data[0x08..]); set => WriteUInt32LittleEndian(Data[0x08..], value); } + public uint PrizeMedals { get => ReadUInt32LittleEndian(Data[0x0C..]); set => WriteUInt32LittleEndian(Data[0x0C..], value); } + public uint Value4 { get => ReadUInt32LittleEndian(Data[0x10..]); set => WriteUInt32LittleEndian(Data[0x10..], value); } + public uint Value5 { get => ReadUInt32LittleEndian(Data[0x14..]); set => WriteUInt32LittleEndian(Data[0x14..], value); } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/MyItem9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/MyItem9a.cs new file mode 100644 index 000000000..9a8106231 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/MyItem9a.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +/// +/// Player item pouches storage +/// +/// size=0xBB80 ( items) +public sealed class MyItem9a(SAV9ZA sav, SCBlock block) : MyItem(sav, block.Raw) +{ + public const int ItemSaveSize = 3000; + + private Span GetItemSpan(ushort itemIndex) => InventoryPouch9a.GetItemSpan(Data, itemIndex); + + public uint DefaultInitPouch => ReadUInt32LittleEndian(Data); // Item 0 + + /// + /// Deletes the item at the requested . + /// + /// + /// Copies item 0 to the requested item index, effectively deleting it. + /// Item 0 should always be un-tarnished, so this is a safe operation. + /// for remarks on Pouch type quirks. This aims to retain consistency within the block. + /// + public void DeleteItem(ushort itemIndex) => GetItemSpan(0).CopyTo(GetItemSpan(itemIndex)); + public InventoryItem9a GetItem(ushort itemIndex) => InventoryItem9a.Read(itemIndex, GetItemSpan(itemIndex)); + + public uint GetItemQuantity(ushort itemIndex) => InventoryItem9a.GetItemCount(GetItemSpan(itemIndex)); + + public void SetItemQuantity(ushort itemIndex, int quantity) + { + var pouch = GetPouchIndex(GetType(itemIndex)); + if (pouch == InventoryItem9a.PouchNone) + { + DeleteItem(itemIndex); // don't allow setting items that don't exist + return; + } + var span = GetItemSpan(itemIndex); + var item = InventoryItem9a.Read(itemIndex, span); + item.Count = quantity; + item.Pouch = GetPouchIndex(GetType(itemIndex)); + item.IsUpdated = true; + item.Write(span); + } + + public static InventoryType GetType(ushort itemIndex) => ItemStorage9ZA.GetInventoryPouch(itemIndex); + + public override IReadOnlyList Inventory { get => ConvertToPouches(); set => LoadFromPouches(value); } + + private IReadOnlyList ConvertToPouches() + { + InventoryPouch9a[] pouches = + [ + MakePouch(InventoryType.Medicine), + MakePouch(InventoryType.Balls), + MakePouch(InventoryType.Berries), + MakePouch(InventoryType.Items), // Other + MakePouch(InventoryType.TMHMs), + MakePouch(InventoryType.MegaStones), + MakePouch(InventoryType.Treasure), + MakePouch(InventoryType.KeyItems), + ]; + return pouches.LoadAll(Data); + } + + private void LoadFromPouches(IReadOnlyList value) + { + value.SaveAll(Data); + CleanIllegalSlots(); + } + + private void CleanIllegalSlots() + { + var types = ItemStorage9ZA.ValidTypes; + var hashSet = new HashSet(Legal.MaxItemID_9a); + foreach (var type in types) + { + var items = ItemStorage9ZA.GetLegal(type); + foreach (var item in items) + hashSet.Add(item); + } + // even though there are 3000, just overwrite the ones that people will mess up. + for (ushort itemIndex = 0; itemIndex < (ushort)SAV.MaxItemID; itemIndex++) + { + if (!hashSet.Contains(itemIndex)) + DeleteItem(itemIndex); + } + } + + public void ResetToDefault() + { + var block = Data; + var defaultPouch = DefaultInitPouch; + ResetToDefault(block, defaultPouch); + } + + public static void ResetToDefault(Span block, uint defaultPouch) + { + block.Clear(); + for (int i = 0; i < block.Length; i += InventoryItem9a.SIZE) + WriteUInt32LittleEndian(block[i..], defaultPouch); + } + + private static InventoryPouch9a MakePouch(InventoryType type) + { + var info = ItemStorage9ZA.Instance; + var max = info.GetMax(type); + return new InventoryPouch9a(type, info, max, GetPouchIndex(type)); + } + + private static uint GetPouchIndex(InventoryType type) => type switch + { + InventoryType.Items => InventoryItem9a.PouchOther, + InventoryType.KeyItems => InventoryItem9a.PouchKey, + InventoryType.TMHMs => InventoryItem9a.PouchTM, + InventoryType.Medicine => InventoryItem9a.PouchMedicine, + InventoryType.Berries => InventoryItem9a.PouchBerry, + InventoryType.Balls => InventoryItem9a.PouchBalls, + InventoryType.Treasure => InventoryItem9a.PouchTreasure, + InventoryType.MegaStones => InventoryItem9a.PouchMegaStones, + _ => InventoryItem9a.PouchNone, + }; +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/MyStatus9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/MyStatus9a.cs new file mode 100644 index 000000000..ff0e58378 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/MyStatus9a.cs @@ -0,0 +1,35 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +public sealed class MyStatus9a(SAV9ZA sav, SCBlock block) : SaveBlock(sav, block.Raw) +{ + public uint ID32 { get => ReadUInt32LittleEndian(Data); set => WriteUInt32LittleEndian(Data, value); } + + public ushort TID16 { get => ReadUInt16LittleEndian(Data); set => WriteUInt16LittleEndian(Data, value); } + public ushort SID16 { get => ReadUInt16LittleEndian(Data[0x02..]); set => WriteUInt16LittleEndian(Data[0x02..], value); } + + public byte Game { get => Data[0x04]; set => Data[0x04] = value; } + public byte Gender { get => Data[0x05]; set => Data[0x05] = value; } + + public int Language { get => Data[0x07]; set => Data[0x07] = (byte)value; } + + private Span OriginalTrainerTrash => Data.Slice(0x10, 0x1A); + + public string OT + { + get => SAV.GetString(OriginalTrainerTrash); + set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero); + } + + public byte BirthMonth { get => Data[0x5A]; set => Data[0x5A] = value; } + public byte BirthDay { get => Data[0x5B]; set => Data[0x5B] = value; } + + public float MegaGaugePercent { get => ReadSingleLittleEndian(Data[0x68..]); set => WriteSingleLittleEndian(Data[0x68..], value); } + + public uint HP { get => ReadUInt32LittleEndian(Data[0x70..]); set => WriteUInt32LittleEndian(Data[0x70..], value); } + public bool WasBirthdayGiven { get => Data[0x74] != 0; set => Data[0x74] = (byte)(value ? 1 : 0); } // un-setting allows to provide birthday day/month again + public bool ObservedBirthday { get => Data[0x75] != 0; set => Data[0x75] = (byte)(value ? 1 : 0); } + public ushort ObservedBirthdayYear { get => ReadUInt16LittleEndian(Data[0x76..]); set => WriteUInt16LittleEndian(Data[0x76..], value); } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/Party9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/Party9a.cs new file mode 100644 index 000000000..b06c07177 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/Party9a.cs @@ -0,0 +1,34 @@ +using System; + +namespace PKHeX.Core; + +public sealed class Party9a(SAV9ZA sav, SCBlock block) : SaveBlock(sav, block.Raw) +{ + private const int MaxCount = 6; + public const int SlotSize = PokeCrypto.SIZE_9PARTY + 0x40 + 0x48; + + public Memory GetSlot(int slot) => block.Raw.Slice(SlotSize * slot, SlotSize); + + public int PartyCount + { + get + { + for (int i = 0; i < MaxCount; i++) + { + var span = GetSlot(i).Span; + if (!EntityDetection.IsPresent(span)) + return i; + } + return MaxCount; + } + set + { + ArgumentOutOfRangeException.ThrowIfGreaterThan((uint)value, MaxCount); + var current = PartyCount; + if (value >= current) + return; + for (int i = value; i < current; i++) + GetSlot(i).Span.Clear(); // probably should fill with Empty pkm data... + } + } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/PlayTime9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/PlayTime9a.cs new file mode 100644 index 000000000..92af06d45 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/PlayTime9a.cs @@ -0,0 +1,107 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +public sealed class PlayTime9a(SAV9ZA sav, SCBlock block) : SaveBlock(sav, block.Raw) +{ + private readonly SAV9ZA _sav = sav; // for remapped value access + + // Actually unused! + + public int PlayedHoursUnused + { + get => ReadInt32LittleEndian(Data); + set => WriteInt32LittleEndian(Data, (ushort)value); + } + + public int PlayedMinutesUnused + { + get => ReadInt32LittleEndian(Data[4..]); + set => WriteInt32LittleEndian(Data[4..], (ushort)value); + } + + public int PlayedSecondsUnused + { + get => ReadInt32LittleEndian(Data[8..]); + set => WriteInt32LittleEndian(Data[8..], (ushort)value); + } + + /// + /// Elapsed play time in seconds (floating point, double precision). + /// + public double RawSeconds + { + get => _sav.Blocks.GetBlockValue(SaveBlockAccessor9ZA.KPlayedSeconds); + set => _sav.Blocks.SetBlockValue(SaveBlockAccessor9ZA.KPlayedSeconds, value); + } + + public int PlayedHours + { + get => (int)(RawSeconds / 3600); + set => RawSeconds = GetPlayedSeconds(value, PlayedMinutes, PlayedSeconds, PlayedFractionalSeconds); + } + + public int PlayedMinutes + { + get => (int)((RawSeconds % 3600) / 60); + set => RawSeconds = GetPlayedSeconds(PlayedHours, value, PlayedSeconds, PlayedFractionalSeconds); + } + + public int PlayedSeconds + { + get => (int)(RawSeconds % 60); + set => RawSeconds = GetPlayedSeconds(PlayedHours, PlayedMinutes, value, PlayedFractionalSeconds); + } + + public double PlayedFractionalSeconds + { + get => RawSeconds - Math.Floor(RawSeconds); + set + { + var whole = Math.Floor(RawSeconds); + RawSeconds = whole + value; + } + } + + public static double GetPlayedSeconds(double hours, double minutes, double seconds, double fraction) => (hours * 3600) + (minutes * 60) + seconds + fraction; + + /// + /// In-game time in seconds since midnight (floating point). + /// + public double RawDaySeconds + { + get => _sav.Blocks.GetBlockValue(SaveBlockAccessor9ZA.KTimeSecondsPastMidnight); + set => _sav.Blocks.SetBlockValue(SaveBlockAccessor9ZA.KTimeSecondsPastMidnight, value); + } + + public int CurrentDayHours + { + get => (int)(RawDaySeconds / 3600); + set => RawDaySeconds = GetCurrentDaySeconds(value, CurrentDayMinutes, CurrentDaySeconds, CurrentDayFractionalSeconds); + } + + public int CurrentDayMinutes + { + get => (int)((RawDaySeconds % 3600) / 60); + set => RawDaySeconds = GetCurrentDaySeconds(CurrentDayHours, value, CurrentDaySeconds, CurrentDayFractionalSeconds); + } + + public int CurrentDaySeconds + { + get => (int)(RawDaySeconds % 60); + set => RawDaySeconds = GetCurrentDaySeconds(CurrentDayHours, CurrentDayMinutes, value, CurrentDayFractionalSeconds); + } + + public float CurrentDayFractionalSeconds + { + get => (float)(RawDaySeconds - Math.Floor(RawDaySeconds)); + set + { + var whole = Math.Floor(RawDaySeconds); + RawDaySeconds = whole + value; + } + } + + public static float GetCurrentDaySeconds(float hours, float minutes, float seconds, float fraction) => (hours * 3600) + (minutes * 60) + seconds + fraction; +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/PlayerFashion9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/PlayerFashion9a.cs new file mode 100644 index 000000000..98b0cc936 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/PlayerFashion9a.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +/// +/// Stores the selected clothing choices of the player. +/// +public sealed class PlayerFashion9a(SAV9ZA sav, SCBlock block) : SaveBlock(sav, block.Raw) +{ + [TypeConverter(typeof(TypeConverterU64))] public ulong Base { get => ReadUInt64LittleEndian(Data); set => WriteUInt64LittleEndian(Data, value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Accessory { get => ReadUInt64LittleEndian(Data[0x08..]); set => WriteUInt64LittleEndian(Data[0x08..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Bag { get => ReadUInt64LittleEndian(Data[0x10..]); set => WriteUInt64LittleEndian(Data[0x10..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Eyewear { get => ReadUInt64LittleEndian(Data[0x18..]); set => WriteUInt64LittleEndian(Data[0x18..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Footwear { get => ReadUInt64LittleEndian(Data[0x20..]); set => WriteUInt64LittleEndian(Data[0x20..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Gloves { get => ReadUInt64LittleEndian(Data[0x28..]); set => WriteUInt64LittleEndian(Data[0x28..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Headwear { get => ReadUInt64LittleEndian(Data[0x30..]); set => WriteUInt64LittleEndian(Data[0x30..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Hairstyle { get => ReadUInt64LittleEndian(Data[0x38..]); set => WriteUInt64LittleEndian(Data[0x38..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Legwear { get => ReadUInt64LittleEndian(Data[0x40..]); set => WriteUInt64LittleEndian(Data[0x40..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Clothing { get => ReadUInt64LittleEndian(Data[0x48..]); set => WriteUInt64LittleEndian(Data[0x48..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong Face { get => ReadUInt64LittleEndian(Data[0x50..]); set => WriteUInt64LittleEndian(Data[0x50..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong LowerBody { get => ReadUInt64LittleEndian(Data[0x58..]); set => WriteUInt64LittleEndian(Data[0x58..], value); } + [TypeConverter(typeof(TypeConverterU64))] public ulong UpperBody { get => ReadUInt64LittleEndian(Data[0x60..]); set => WriteUInt64LittleEndian(Data[0x60..], value); } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/PokeDexEntry9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/PokeDexEntry9a.cs new file mode 100644 index 000000000..5e2f4bd9c --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/PokeDexEntry9a.cs @@ -0,0 +1,194 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +public readonly ref struct PokeDexEntry9a +{ + public const int SIZE = 0x84; + + private readonly Span Data; + // ReSharper disable once ConvertToPrimaryConstructor + public PokeDexEntry9a(Span data) => Data = data; + public void Clear() => Data.Clear(); + + /* + Structure: 0x84 bytes + 0x00 u32 [form-flags] Captured + 0x04 u32 [form-flags] Seen + 0x08 u16 language obtained + 0x0A b8 IsNew + 0x0B u8 flags for genders seen, can be on mons you don't have + 01: male seen + 02: female seen + 04: genderless seen + 0x0C u32 [form-flags] Shiny Seen + 0x10 b8 Seen Mega + 0x11 b8 Seen Alpha + + 0x12-0x59: ??? all zeroes + + 0x5A u8 DisplayForm + 0x5B u8 DisplayGender + 0x5C b8 DisplayShiny + + 0x5D-0x83: ??? all zeroes, last 2 bytes junk (alloc?) + */ + + private uint FlagsFormCaught { get => ReadUInt32LittleEndian(Data); set => WriteUInt32LittleEndian(Data, value); } + private uint FlagsFormSeen { get => ReadUInt32LittleEndian(Data[0x04..]); set => WriteUInt32LittleEndian(Data[0x04..], value); } + private ushort FlagsLanguage { get => ReadUInt16LittleEndian(Data[0x08..]); set => WriteUInt16LittleEndian(Data[0x08..], value); } + private ref byte FlagsIsNew => ref Data[0x0A]; + private ref byte FlagsGenderSeen => ref Data[0x0B]; + private uint FlagsShinySeen { get => ReadUInt32LittleEndian(Data[0x0C..]); set => WriteUInt32LittleEndian(Data[0x0C..], value); } + private ref byte FlagIsMega => ref Data[0x10]; + private ref byte FlagIsAlpha => ref Data[0x11]; + + // + + public byte DisplayForm { get => Data[0x5A]; set => Data[0x5A] = value; } + public DisplayGender9a DisplayGender { get => (DisplayGender9a)Data[0x5B]; set => Data[0x5B] = (byte)value; } + private byte DisplayShiny { get => Data[0x5C]; set => Data[0x5C] = value; } + + // + + #region Interaction + public bool IsSeen => FlagsFormSeen != 0; + public bool IsCaught => FlagsFormCaught != 0; + public bool GetIsFormCaught(byte form) => (FlagsFormCaught & (1u << form)) != 0; + public void SetIsFormCaught(byte form, bool value) + { + if (value) + FlagsFormCaught |= 1u << form; + else + FlagsFormCaught &= ~(1u << form); + } + + public bool GetIsFormSeen(byte form) => (FlagsFormSeen & (1u << form)) != 0; + public void SetIsFormSeen(byte form, bool value) + { + if (value) + FlagsFormSeen |= 1u << form; + else + FlagsFormSeen &= ~(1u << form); + } + + public static int GetDexLangFlag(int lang) => (uint)lang switch + { + > (int)MaxLanguageID or 6 or <= 0 => 0, // invalid language + // skip over langID 0 (unused) => [0-8] + // skip over langID 6 (unused) + >= 7 => lang - 2, + _ => lang - 1, + }; + + private static int GetLanguageBitMask(int langIndex) => 1 << GetDexLangFlag(langIndex); + + public bool GetLanguageFlag(int langIndex) => (FlagsLanguage & GetLanguageBitMask(langIndex)) != 0; + + public void SetLanguageFlag(int langIndex, bool value) + { + var mask = GetLanguageBitMask(langIndex); + if (value) + FlagsLanguage |= (ushort)mask; + else + FlagsLanguage &= (ushort)~mask; + } + + public bool GetDisplayIsNew() => FlagsIsNew != 0; + public void SetDisplayIsNew(bool value) => FlagsIsNew = value ? (byte)1 : (byte)0; + + public bool GetIsGenderSeen(byte gender) => (FlagsGenderSeen & (1u << gender)) != 0; + public void SetIsGenderSeen(byte gender, bool value) + { + gender &= 1; + var flag = 1u << gender; + if (value) + FlagsGenderSeen |= (byte)flag; + else + FlagsGenderSeen &= (byte)~flag; + } + + public bool GetIsShinySeen(byte form) => (FlagsShinySeen & (1u << form)) != 0; + public void SetIsShinySeen(byte form, bool value) + { + if (value) + FlagsShinySeen |= 1u << form; + else + FlagsShinySeen &= ~(1u << form); + } + + public bool GetIsSeenMega() => FlagIsMega != 0; + public bool GetIsSeenAlpha() => FlagIsAlpha != 0; + public void SetIsSeenMega(bool value) => FlagIsMega = value ? (byte)1 : (byte)0; + public void SetIsSeenAlpha(bool value) => FlagIsAlpha = value ? (byte)1 : (byte)0; + + public DisplayGender9a GetDisplayGender(Gender gender, ushort species, byte form) + { + if (gender == Gender.Genderless) + return DisplayGender9a.Genderless; // Genderless + + var pi = PersonalTable.ZA[species, form]; + if (!pi.IsDualGender) + { + if (pi.OnlyMale) + return DisplayGender9a.Male; + if (pi.OnlyFemale) + return DisplayGender9a.Female; + return DisplayGender9a.Genderless; + } + + // Gender differences? + if (BiGender.Contains(species)) + return gender == Gender.Male ? DisplayGender9a.Male : DisplayGender9a.Female; + return DisplayGender9a.GenderedNoDifference; + } + /// + /// Species with gender differences in the dex. + /// + private static ReadOnlySpan BiGender => + [ + 003, 025, 026, 064, 065, 123, 129, 130, 133, + 154, 208, 212, 214, 229, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 307, 308, 315, 322, 323, + 407, 443, 444, 445, 449, 450, 459, 460, + 485, // Heatran + 668, // Pyroar + ]; + + public void SetDisplayGender(Gender gender, ushort species, byte form) + { + DisplayGender = GetDisplayGender(gender, species, form); + } + + #endregion + + public void ClearDisplay() + { + DisplayGender = 0; + DisplayForm = 0; + DisplayShiny = 0; + } + + public void ClearCaught() + { + FlagsFormCaught = 0; + FlagsLanguage = 0; + ClearDisplay(); + } + + public bool GetDisplayIsShiny() => DisplayShiny != 0; + public void SetDisplayIsShiny(bool state) => DisplayShiny = state ? (byte)1 : (byte)0; + + private const LanguageID MaxLanguageID = LanguageID.SpanishL; + private const ushort LanguageMask = 0x3FF; // 10 bits set, ^ with unused (6) skipped. + public void SetLanguageFlagAll(bool value) => FlagsLanguage = value ? LanguageMask : (ushort)0; +} + +public enum DisplayGender9a : byte +{ + Genderless = 0, + Male = 1, + Female = 2, + GenderedNoDifference = 3, +} diff --git a/PKHeX.Core/Saves/Substructures/Gen9/ZA/Zukan9a.cs b/PKHeX.Core/Saves/Substructures/Gen9/ZA/Zukan9a.cs new file mode 100644 index 000000000..57ebdfeb9 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen9/ZA/Zukan9a.cs @@ -0,0 +1,190 @@ +namespace PKHeX.Core; + +public sealed class Zukan9a(SAV9ZA sav, SCBlock block) : ZukanBase(sav, block.Raw) +{ + public override bool GetSeen(ushort species) => GetEntry(species).IsSeen; + + public override bool GetCaught(ushort species) => GetEntry(species).IsCaught; + + public PokeDexEntry9a GetEntry(ushort species) + { + ushort index = species > SAV.MaxSpeciesID ? (ushort)0 : species; + index = SpeciesConverter.GetInternal9(index); + + var offset = index * PokeDexEntry9a.SIZE; + var slice = Data.Slice(offset, PokeDexEntry9a.SIZE); + return new PokeDexEntry9a(slice); + } + + #region Inherited + public override void SetDex(PKM pk) + { + if (pk.IsEgg) // do not add + return; + var species = pk.Species; + var form = pk.Form; + var pt = SAV.Personal; + if (!pt.IsPresentInGame(species, form)) + return; + Register(pk, species, form); + } + + private void Register(PKM pk, ushort species, byte form) + { + var entry = GetEntry(species); + var isRegistered = entry.IsCaught; + + entry.SetIsFormSeen(form, true); + entry.SetIsFormCaught(form, true); + if (FormInfo.IsMegaForm(species, form)) + entry.SetIsSeenMega(true); + entry.SetLanguageFlag(pk.Language, true); + + var isShiny = pk.IsShiny; + if (isShiny) + { + entry.SetIsShinySeen(form, true); + } + if (!isRegistered) + { + entry.DisplayForm = form; + entry.SetDisplayGender((Gender)pk.Gender, species, form); + entry.SetDisplayIsShiny(isShiny); + + entry.SetDisplayIsNew(true); + } + if (pk is IAlphaReadOnly { IsAlpha: true }) + entry.SetIsSeenAlpha(true); + } + + public override void SeenNone() + { + Data.Clear(); + } + + public override void CaughtNone() + { + for (ushort species = 1; species <= SAV.MaxSpeciesID; species++) + SetAllCaught(species, false); + } + + public override void SeenAll(bool shinyToo = false) + { + SetAllSeen(true, shinyToo); + } + + private void SeenAll(ushort species, PersonalInfo9ZA pi, bool value = true, bool shinyToo = false) + { + var formCount = pi.FormCount; + var entry = GetEntry(species); + for (byte form = 0; form < formCount; form++) + { + var other = SAV.Personal[species, form]; + if (!other.IsPresentInGame) + continue; + entry.SetIsFormSeen(form, value); + if (shinyToo) + entry.SetIsShinySeen(form, value); + } + + // Set other seen flags + if (pi.Genderless) + { + entry.SetIsGenderSeen(2, value); + } + else + { + if (!pi.OnlyFemale) + entry.SetIsGenderSeen(0, value); + if (!pi.OnlyMale) + entry.SetIsGenderSeen(1, value); + } + } + + public override void CompleteDex(bool shinyToo = false) + { + for (ushort species = 0; species <= SAV.MaxSpeciesID; species++) + { + if (!SAV.Personal.IsSpeciesInGame(species)) + continue; + SetDexEntryAll(species, shinyToo); + } + } + + public override void CaughtAll(bool shinyToo = false) + { + SeenAll(shinyToo); + for (ushort species = 0; species <= SAV.MaxSpeciesID; species++) + { + if (!SAV.Personal.IsSpeciesInGame(species)) + continue; + SetAllCaught(species, true, shinyToo); + } + } + + private void SetAllCaught(ushort species, bool value = true, bool shinyToo = false) + { + var entry = GetEntry(species); + var formCount = SAV.Personal[species].FormCount; + byte firstForm = 0xFF; + for (byte form = 0; form < formCount; form++) + { + var other = SAV.Personal[species, form]; + if (!other.IsPresentInGame) + continue; + if (firstForm == 0xFF) + firstForm = form; + + entry.SetIsFormCaught(form, value); + entry.SetIsFormSeen(form, value); + if (shinyToo) + entry.SetIsShinySeen(form, value); + } + + // Set language + entry.SetLanguageFlagAll(value); + + if (!value) + { + entry.ClearDisplay(); + } + else + { + // Set display data + if (firstForm == 0xFF) + firstForm = 0; // Failsafe, should not happen + var pi = SAV.Personal[species, firstForm]; + entry.SetDisplayGender((Gender)pi.RandomGender(), species, firstForm); + } + } + + public override void SetAllSeen(bool value = true, bool shinyToo = false) + { + var pt = SAV.Personal; + for (ushort species = 0; species <= SAV.MaxSpeciesID; species++) + { + var pi = pt[species]; + SeenAll(species, pi, value, shinyToo); + } + } + + private void SetAllSeen(ushort species, bool value = true, bool shinyToo = false) + { + var pi = SAV.Personal[species]; + SeenAll(species, pi, value, shinyToo); + } + + public override void SetDexEntryAll(ushort species, bool shinyToo = false) + { + SetAllSeen(species, true, shinyToo); + SetAllCaught(species, true, shinyToo); + } + + public override void ClearDexEntryAll(ushort species) + { + var entry = GetEntry(species); + entry.Clear(); + } + + #endregion +} diff --git a/PKHeX.Core/Saves/Substructures/Inventory/IItemNewFlag.cs b/PKHeX.Core/Saves/Substructures/Inventory/IItemNewFlag.cs index 740cb0dd4..409a88fe0 100644 --- a/PKHeX.Core/Saves/Substructures/Inventory/IItemNewFlag.cs +++ b/PKHeX.Core/Saves/Substructures/Inventory/IItemNewFlag.cs @@ -5,3 +5,19 @@ public interface IItemNewFlag /// Indicates if the item is NEW-ly obtained and not yet viewed. bool IsNew { get; set; } } + +public interface IItemNewShopFlag +{ + /// Indicates if the item is NEW-ly available in the shop. + bool IsNewShop { get; set; } +} + +public interface IItemHeldFlag +{ + /// Indicates if the item is given to a Pokémon and cannot be given to another. + /// + /// This is how the game leases out Mega Stones to one Pokémon at a time. + /// In Legends: Z-A, the game will show a green checkmark above the item sprite in the bag. + /// + bool IsHeld { get; set; } +} diff --git a/PKHeX.Core/Saves/Substructures/Inventory/InventoryType.cs b/PKHeX.Core/Saves/Substructures/Inventory/InventoryType.cs index df25f6034..96d99472e 100644 --- a/PKHeX.Core/Saves/Substructures/Inventory/InventoryType.cs +++ b/PKHeX.Core/Saves/Substructures/Inventory/InventoryType.cs @@ -21,4 +21,5 @@ public enum InventoryType Candy, Treasure, Ingredients, + MegaStones, } diff --git a/PKHeX.Core/Saves/Substructures/Inventory/Item/InventoryItem9a.cs b/PKHeX.Core/Saves/Substructures/Inventory/Item/InventoryItem9a.cs new file mode 100644 index 000000000..2207d9872 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Inventory/Item/InventoryItem9a.cs @@ -0,0 +1,98 @@ +using System; +using static System.Buffers.Binary.BinaryPrimitives; + +namespace PKHeX.Core; + +public sealed record InventoryItem9a : InventoryItem, IItemFavorite, IItemNewFlag, IItemNewShopFlag, IItemHeldFlag +{ + public const int SIZE = 0x10; + + public const uint PouchNone = 0xFFFFFFFF; + public const uint PouchMedicine = 0; + public const uint PouchBalls = 1; + public const uint PouchOther = 2; + public const uint PouchTreasure = 3; + public const uint PouchKey = 4; + public const uint PouchBerry = 5; + public const uint PouchTM = 6; + public const uint PouchMegaStones = 7; + + public uint Pouch { get; set; } + public uint Flags { get; set; } + public uint Padding { get; set; } + + public bool IsNew { get => (Flags & 0x1) != 0; set => Flags = (Flags & ~0x1u) | (value ? 0x1u : 0x0u); } // red dot + public bool IsFavorite { get => (Flags & 0x2) != 0; set => Flags = (Flags & ~0x2u) | (value ? 0x2u : 0x0u); } + public bool IsUpdated { get => (Flags & 0x4) != 0; set => Flags = (Flags & ~0x4u) | (value ? 0x4u : 0x0u); } // always true if pouch is set + public bool IsNewShop { get => (Flags & 0x8) != 0; set => Flags = (Flags & ~0x8u) | (value ? 0x8u : 0x0u); } + public bool IsHeld { get => (Flags & 0x10) != 0; set => Flags = (Flags & ~0x10u) | (value ? 0x10u : 0x0u); } // only for Mega Stones currently held by a Pokémon + + private const byte DefaultFlagValue = 0b0_1101; + + public override string ToString() => $"{Index:000} x{Count}{(IsNew ? "*" : "")}{(IsFavorite ? "F" : "")} - {Flags:X8}"; + + public override void Clear() + { + Index = Count = 0; + Flags = DefaultFlagValue; + Pouch = PouchNone; + } + + /// + /// Indicates if the item has been acquired by the player. + /// + public bool IsValidPouch => Pouch != PouchNone; + + public static InventoryItem9a Read(ushort index, ReadOnlySpan data) => new() + { + Index = index, + Pouch = ReadUInt32LittleEndian(data), + Count = ReadInt32LittleEndian(data[4..]), + Flags = ReadUInt32LittleEndian(data[8..]), + Padding = ReadUInt32LittleEndian(data[12..]), + }; + + public void Write(Span data) + { + IsUpdated = Pouch != PouchNone; + + // Index is not saved. + WriteUInt32LittleEndian(data, Pouch); + WriteUInt32LittleEndian(data[4..], (uint)Count); + WriteUInt32LittleEndian(data[8..], Flags); + WriteUInt32LittleEndian(data[12..], Padding); + } + + public static void Clear(Span data, int offset) + { + data.Slice(offset, SIZE).Clear(); + WriteUInt32LittleEndian(data[offset..], PouchNone); + WriteUInt32LittleEndian(data[(offset + 8)..], DefaultFlagValue); + } + + public static uint GetItemCount(Span data) => ReadUInt32LittleEndian(data[4..]); + + public override void SetNewDetails(int count) + { + base.SetNewDetails(count); + if (IsValidPouch) + return; + + // If a Mega Stone, shouldn't be given yet. + // Flag value is equivalent to that of a fresh item. + Flags = DefaultFlagValue; + } + + /// + /// Item has been matched to a previously existing item. Copy over the misc details. + /// + public override void MergeOverwrite(T other) + { + base.MergeOverwrite(other); + if (other is not InventoryItem9a item) + return; + Pouch = item.Pouch; + Flags = item.Flags; + Padding = item.Padding; + } +} diff --git a/PKHeX.Core/Saves/Substructures/Inventory/Pouch/InventoryPouch9a.cs b/PKHeX.Core/Saves/Substructures/Inventory/Pouch/InventoryPouch9a.cs new file mode 100644 index 000000000..fe2ff77b3 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Inventory/Pouch/InventoryPouch9a.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace PKHeX.Core; + +public sealed class InventoryPouch9a(InventoryType type, IItemStorage info, int maxCount, uint pouch) + : InventoryPouch(type, info, maxCount, 0) +{ + public bool SetNew { get; set; } + public uint PouchIndex { get; set; } = pouch; + + public override InventoryItem9a GetEmpty(int itemID = 0, int count = 0) => new() { Index = itemID, Count = count, IsNew = count != 0 }; + public static int GetItemOffset(ushort index) => InventoryItem9a.SIZE * index; + public static Span GetItemSpan(Span block, ushort index) => block.Slice(GetItemOffset(index), InventoryItem9a.SIZE); + + public override void GetPouch(ReadOnlySpan data) + { + var LegalItems = Info.GetItems(Type); + var items = new InventoryItem9a[LegalItems.Length]; + + int ctr = 0; + foreach (var index in LegalItems) + items[ctr++] = GetItem(data, index); + + Items = items; + } + + public static InventoryItem9a GetItem(ReadOnlySpan block, ushort itemID) + { + var ofs = GetItemOffset(itemID); + return InventoryItem9a.Read(itemID, block[ofs..]); + } + + public override void SetPouch(Span block) + { + // Write all the item slots still present in the pouch. Keep track of the item IDs processed. + var items = (InventoryItem9a[])Items; + var processed = new HashSet(items.Length); + + var legal = Info.GetItems(Type); + foreach (var item in items) + { + var index = (ushort)item.Index; + if (index == 0) + continue; + if (!legal.Contains(index)) + { + Debug.WriteLine($"Invalid Item ID returned within this pouch: {index}"); + continue; + } + + var span = GetItemSpan(block, index); + var original = InventoryItem9a.Read(index, span); + EnsureFlagsConsistent(item, original); + + // In the event of duplicates, we just overwrite what was previously written by a prior duplicate. + // Don't care if we've already processed this item, just write it again. + item.Write(span); + processed.Add(index); + } + + // For all the items that were not present in the pouch, clear the data for them. + foreach (var index in legal) + { + if (processed.Contains(index)) + continue; + SetQuantityZero(block, index); + } + + if (Type is InventoryType.KeyItems) // Key items that can never be saved with + SetQuantityZero(block, 2598); // Tasty Trash + } + + private void EnsureFlagsConsistent(InventoryItem9a item, InventoryItem9a original) + { + if (item.Count != 0) + { + // Ensure the flag is set; 0->X and Y->Z + item.IsUpdated = true; + if (!original.IsUpdated && SetNew) + item.IsNew = true; + } + else + { + if (!item.IsUpdated) + { + item.IsNew = item.IsFavorite = false; + if (item.Pouch is not (0 or uint.MaxValue)) + item.Pouch = 0; + } + } + + if (item.IsUpdated) + item.Pouch = PouchIndex; // ensure the pouch is set + } + + public static void SetQuantityZero(Span block, ushort index) + { + var span = GetItemSpan(block, index); + var exist = InventoryItem9a.Read(index, span); + if (exist.Count == 0) + return; + exist.Count = 0; + exist.IsUpdated = true; + exist.Write(span); + } +} diff --git a/PKHeX.Core/Saves/Util/BlankSaveFile.cs b/PKHeX.Core/Saves/Util/BlankSaveFile.cs index f3669ed39..a3ff3e75f 100644 --- a/PKHeX.Core/Saves/Util/BlankSaveFile.cs +++ b/PKHeX.Core/Saves/Util/BlankSaveFile.cs @@ -33,7 +33,7 @@ public static SaveFile Get(GameVersion version, SaveFile? current) { null => English, ILangDeviantSave s => s.Japanese ? Japanese : s.Korean ? Korean : English, - _ => (uint)sav.Language <= Legal.GetMaxLanguageID(sav.Generation) ? (LanguageID)sav.Language : English, + _ => (uint)sav.Language <= Legal.GetMaxLanguageID(sav.Generation, sav.Context) ? (LanguageID)sav.Language : English, }; /// @@ -139,6 +139,7 @@ public static SaveFile Get(SaveFileType type, GameVersion version, string traine LA => new SAV8LA(), SV => new SAV9SV(), + ZA => new SAV9ZA(), _ => throw new ArgumentOutOfRangeException(nameof(type), type, null), }; diff --git a/PKHeX.Core/Saves/Util/SaveFileType.cs b/PKHeX.Core/Saves/Util/Detection/SaveFileType.cs similarity index 96% rename from PKHeX.Core/Saves/Util/SaveFileType.cs rename to PKHeX.Core/Saves/Util/Detection/SaveFileType.cs index d64dd1d38..66b5911c4 100644 --- a/PKHeX.Core/Saves/Util/SaveFileType.cs +++ b/PKHeX.Core/Saves/Util/Detection/SaveFileType.cs @@ -34,6 +34,7 @@ public enum SaveFileType : byte BDSP, LA, SV, + ZA, // Side Games Colosseum, @@ -60,7 +61,7 @@ public static class SaveFileTypeExtensions /// Corresponding for the given . public static SaveFileType GetSaveFileType(this GameVersion version) => version switch { - > GameVersion.VL => 0, + > GameUtil.HighestGameID => 0, GameVersion.RD or GameVersion.GN or GameVersion.YW or GameVersion.BU => RBY, GameVersion.GD or GameVersion.SI or GameVersion.C => GSC, GameVersion.R or GameVersion.S => RS, @@ -82,12 +83,12 @@ public static class SaveFileTypeExtensions GameVersion.BD or GameVersion.SP => BDSP, GameVersion.PLA => LA, GameVersion.SL or GameVersion.VL => SV, + GameVersion.ZA => ZA, _ => None, }; public static byte GetGeneration(this SaveFileType type) => type switch { - 0 => 0, RBY or Stadium1J or Stadium1 => 1, GSC or Stadium2 => 2, RS or Emerald or FRLG => 3, @@ -96,7 +97,7 @@ public static class SaveFileTypeExtensions XY or AO or AODemo => 6, SM or USUM or LGPE => 7, SWSH or BDSP or LA => 8, - SV => 9, + SV or ZA => 9, Colosseum or XD or RSBox => 3, Ranch or BattleRevolution => 4, Bulk3 => 3, diff --git a/PKHeX.Core/Saves/Util/Detection/SaveTypeInfo.cs b/PKHeX.Core/Saves/Util/Detection/SaveTypeInfo.cs new file mode 100644 index 000000000..2762d0a64 --- /dev/null +++ b/PKHeX.Core/Saves/Util/Detection/SaveTypeInfo.cs @@ -0,0 +1,21 @@ +namespace PKHeX.Core; + +/// +/// Stores the result from a save detection. +/// +/// The save file type detected +/// Specific game version within the type, or Any if not distinguished +public readonly record struct SaveTypeInfo(SaveFileType Type, GameVersion SubVersion = default, LanguageID Language = default) +{ + /// + /// Implicit conversion from SaveTypeInfo to SaveFileType for convenience. + /// + public static implicit operator SaveFileType(SaveTypeInfo info) => info.Type; + + public static implicit operator SaveTypeInfo(SaveFileType type) => new(type); + + /// + /// Returns Invalid save type info. + /// + public static SaveTypeInfo Invalid => default; +} diff --git a/PKHeX.Core/Saves/Util/SaveUtil.cs b/PKHeX.Core/Saves/Util/SaveUtil.cs index 91c3840f4..e5c121be9 100644 --- a/PKHeX.Core/Saves/Util/SaveUtil.cs +++ b/PKHeX.Core/Saves/Util/SaveUtil.cs @@ -14,6 +14,9 @@ namespace PKHeX.Core; /// public static class SaveUtil { + private const int SIZE_G9ZA_Min = 0x2F3284; + private const int SIZE_G9ZA_Max = 0x2F3284; + private const int SIZE_G9_0 = 0x31626F; // 1.0.0 fresh private const int SIZE_G9_0a = 0x31627C; // 1.0.0 after multiplayer private const int SIZE_G9_1 = 0x319DB3; // 1.0.1 fresh @@ -117,6 +120,8 @@ public static class SaveUtil new SaveHandlerNSO(), ]; + private static bool IsSizeGen9ZA(int length) => length is (>= SIZE_G9ZA_Min) and (<= SIZE_G9ZA_Max); + private static bool IsSizeGen9SV(int length) => length is SIZE_G9_0 or SIZE_G9_0a or SIZE_G9_1 or SIZE_G9_1a or SIZE_G9_1A or SIZE_G9_1Aa or SIZE_G9_1Ba or SIZE_G9_1Ab or @@ -175,6 +180,7 @@ private static SaveTypeInfo GetTypeInfo(ReadOnlySpan data) if (IsG8BDSP(data)) return BDSP; if (IsG8LA(data)) return LA; if (IsG9SV(data)) return SV; + if (IsG9ZA(data)) return ZA; // Side-game if (IsG3Colosseum(data)) return Colosseum; @@ -433,6 +439,7 @@ private static bool IsG7LGPE(ReadOnlySpan data) private static bool IsG8LA(ReadOnlySpan data) => data.Length is SIZE_G8LA or SIZE_G8LA_1 && SwishCrypto.GetIsHashValid(data); private static bool IsG8SWSH(ReadOnlySpan data) => IsSizeGen8SWSH(data.Length) && SwishCrypto.GetIsHashValid(data); private static bool IsG9SV(ReadOnlySpan data) => IsSizeGen9SV(data.Length) && SwishCrypto.GetIsHashValid(data); + private static bool IsG9ZA(ReadOnlySpan data) => IsSizeGen9ZA(data.Length) && SwishCrypto.GetIsHashValid(data); private static bool IsBank7(ReadOnlySpan data) => data.Length == SIZE_G7BANK && data[0] != 0; private static bool IsBank4(ReadOnlySpan data) => data.Length == SIZE_G4BANK && ReadUInt32LittleEndian(data[0x3FC00..]) != 0; // box name present @@ -498,6 +505,33 @@ public static bool TryGetSaveFile(Memory data, [NotNullWhen(true)] out Sav return false; } + /// + /// Overrides the detected save type with the manually specified . + /// + /// Save file to override + /// Manually specified save type information + /// Overridden save file, or null if the override failed. + /// if the override was successful; otherwise, . + public static bool TryOverride(SaveFile sav, SaveTypeInfo toType, [NotNullWhen(true)] out SaveFile? result) + { + try + { + var data = sav.Buffer; + result = GetSaveFileInternal(data, toType); + if (result is null) + return false; + + result.Metadata.ShareExtraInfo(sav.Metadata); + return true; + } + catch + { + // General failure, probably bad type selected / bad data. + result = null; + return false; + } + } + private static bool TryGetSaveFileCustom(Memory data, [NotNullWhen(true)] out SaveFile? result, string? path) { foreach (var h in CustomSaveReaders) @@ -573,6 +607,7 @@ private static bool TryGetSaveFileHandler(Memory data, [NotNullWhen(true)] LA => new SAV8LA(data), SV => new SAV9SV(data), + ZA => new SAV9ZA(data), // Side Games Colosseum => new SAV3Colosseum(data), @@ -714,6 +749,8 @@ public static bool IsSizeValidNoHandler(long size) if ((uint)size > int.MaxValue) return false; int length = (int)size; + if (IsSizeGen9ZA(length)) + return true; if (IsSizeGen9SV(length)) return true; if (IsSizeGen8SWSH(length)) @@ -722,24 +759,4 @@ public static bool IsSizeValidNoHandler(long size) return true; return false; } - - /// - /// Stores the result from a save detection. - /// - /// The save file type detected - /// Specific game version within the type, or Any if not distinguished - private readonly record struct SaveTypeInfo(SaveFileType Type, GameVersion SubVersion = default, LanguageID Language = default) - { - /// - /// Implicit conversion from SaveTypeInfo to SaveFileType for convenience. - /// - public static implicit operator SaveFileType(SaveTypeInfo info) => info.Type; - - public static implicit operator SaveTypeInfo(SaveFileType type) => new(type); - - /// - /// Returns Invalid save type info. - /// - public static SaveTypeInfo Invalid => default; - } } diff --git a/PKHeX.Core/Util/ResourceUtil.cs b/PKHeX.Core/Util/ResourceUtil.cs index cb84f1082..a0a3d17ee 100644 --- a/PKHeX.Core/Util/ResourceUtil.cs +++ b/PKHeX.Core/Util/ResourceUtil.cs @@ -130,6 +130,27 @@ public static partial class Util GetStringList(fileName, zh ?? "zh-Hant"), // 10 ]; + /// + /// Retrieves the localization index list for all requested strings for the through Latin American Spanish. + /// + /// Base file name + /// Language code to use for both Chinese localizations. + public static string[][] GetLanguageStrings11([ConstantExpected] string fileName, string? zh = null) => + [ + [], // 0 - None + GetStringList(fileName, "ja"), // 1 + GetStringList(fileName, "en"), // 2 + GetStringList(fileName, "fr"), // 3 + GetStringList(fileName, "it"), // 4 + GetStringList(fileName, "de"), // 5 + [], // 6 - None + GetStringList(fileName, "es"), // 7 + GetStringList(fileName, "ko"), // 8 + GetStringList(fileName, zh ?? "zh-Hans"), // 9 + GetStringList(fileName, zh ?? "zh-Hant"), // 10 + GetStringList(fileName, "es-419"), // 11 + ]; + #endregion /// diff --git a/PKHeX.Drawing.Misc/Util/WallpaperUtil.cs b/PKHeX.Drawing.Misc/Util/WallpaperUtil.cs index 6c41ef0d1..10f885750 100644 --- a/PKHeX.Drawing.Misc/Util/WallpaperUtil.cs +++ b/PKHeX.Drawing.Misc/Util/WallpaperUtil.cs @@ -25,6 +25,10 @@ private static Bitmap GetWallpaper(SaveFile sav, int box) if (sav is not IBoxDetailWallpaper wp) return DefaultWallpaper; + // City box wallpaper for Lumiose City + if (sav is SAV9ZA) + return Resources.box_wp02bdsp; + int wallpaper = wp.GetBoxWallpaper(box); string s = GetWallpaperResourceName(sav.Version, wallpaper); return (Bitmap?)Resources.ResourceManager.GetObject(s) ?? DefaultWallpaper; diff --git a/PKHeX.Drawing.PokeSprite/Builder/SpriteBuilderMode.cs b/PKHeX.Drawing.PokeSprite/Builder/SpriteBuilderMode.cs index 97dcb17fe..778f15b55 100644 --- a/PKHeX.Drawing.PokeSprite/Builder/SpriteBuilderMode.cs +++ b/PKHeX.Drawing.PokeSprite/Builder/SpriteBuilderMode.cs @@ -78,7 +78,7 @@ public static class SpriteBuilderUtil _ => sav switch // Default, suggest. { SAV8LA => CircleMugshot5668, - SAV9SV => SpritesArtwork5668, + SAV9SV or SAV9ZA => SpritesArtwork5668, _ => SpritesClassic5668, }, }; diff --git a/PKHeX.Drawing.PokeSprite/Properties/Resources.Designer.cs b/PKHeX.Drawing.PokeSprite/Properties/Resources.Designer.cs index e09b13382..903b9a4b6 100644 --- a/PKHeX.Drawing.PokeSprite/Properties/Resources.Designer.cs +++ b/PKHeX.Drawing.PokeSprite/Properties/Resources.Designer.cs @@ -1180,6 +1180,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_121_1 { + get { + object obj = ResourceManager.GetObject("a_121_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -1590,6 +1600,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_149_1 { + get { + object obj = ResourceManager.GetObject("a_149_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -1680,6 +1700,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_154_1 { + get { + object obj = ResourceManager.GetObject("a_154_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -1760,6 +1790,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_160_1 { + get { + object obj = ResourceManager.GetObject("a_160_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -2890,6 +2930,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_227_1 { + get { + object obj = ResourceManager.GetObject("a_227_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -3370,16 +3420,6 @@ public class Resources { } } - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap a_25f { - get { - object obj = ResourceManager.GetObject("a_25f", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -4710,6 +4750,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_36_1 { + get { + object obj = ResourceManager.GetObject("a_36_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -6290,6 +6340,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_478_1 { + get { + object obj = ResourceManager.GetObject("a_478_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -6840,6 +6900,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_500_1 { + get { + object obj = ResourceManager.GetObject("a_500_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -7230,6 +7300,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_530_1 { + get { + object obj = ResourceManager.GetObject("a_530_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -7400,6 +7480,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_545_1 { + get { + object obj = ResourceManager.GetObject("a_545_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -7640,6 +7730,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_560_1 { + get { + object obj = ResourceManager.GetObject("a_560_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -8280,6 +8380,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_604_1 { + get { + object obj = ResourceManager.GetObject("a_604_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -8330,6 +8440,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_609_1 { + get { + object obj = ResourceManager.GetObject("a_609_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -8950,6 +9070,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_652_1 { + get { + object obj = ResourceManager.GetObject("a_652_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -8980,6 +9110,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_655_1 { + get { + object obj = ResourceManager.GetObject("a_655_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -9030,6 +9170,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_658_3 { + get { + object obj = ResourceManager.GetObject("a_658_3", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -9330,6 +9480,26 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_668_1 { + get { + object obj = ResourceManager.GetObject("a_668_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_668_1f { + get { + object obj = ResourceManager.GetObject("a_668_1f", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -9460,6 +9630,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_670_6 { + get { + object obj = ResourceManager.GetObject("a_670_6", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -9790,6 +9970,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_687_1 { + get { + object obj = ResourceManager.GetObject("a_687_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -9810,6 +10000,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_689_1 { + get { + object obj = ResourceManager.GetObject("a_689_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -9840,6 +10040,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_691_1 { + get { + object obj = ResourceManager.GetObject("a_691_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -9960,6 +10170,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_701_1 { + get { + object obj = ResourceManager.GetObject("a_701_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -10070,6 +10290,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_71_1 { + get { + object obj = ResourceManager.GetObject("a_71_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -10280,6 +10510,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_718_5 { + get { + object obj = ResourceManager.GetObject("a_718_5", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -11410,6 +11650,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_780_1 { + get { + object obj = ResourceManager.GetObject("a_780_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -13140,6 +13390,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap a_870_1 { + get { + object obj = ResourceManager.GetObject("a_870_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -14830,6 +15090,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_103 { + get { + object obj = ResourceManager.GetObject("aitem_103", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -16940,6 +17210,276 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2558 { + get { + object obj = ResourceManager.GetObject("aitem_2558", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2559 { + get { + object obj = ResourceManager.GetObject("aitem_2559", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2560 { + get { + object obj = ResourceManager.GetObject("aitem_2560", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2561 { + get { + object obj = ResourceManager.GetObject("aitem_2561", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2562 { + get { + object obj = ResourceManager.GetObject("aitem_2562", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2563 { + get { + object obj = ResourceManager.GetObject("aitem_2563", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2564 { + get { + object obj = ResourceManager.GetObject("aitem_2564", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2565 { + get { + object obj = ResourceManager.GetObject("aitem_2565", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2566 { + get { + object obj = ResourceManager.GetObject("aitem_2566", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2569 { + get { + object obj = ResourceManager.GetObject("aitem_2569", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2570 { + get { + object obj = ResourceManager.GetObject("aitem_2570", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2571 { + get { + object obj = ResourceManager.GetObject("aitem_2571", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2572 { + get { + object obj = ResourceManager.GetObject("aitem_2572", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2573 { + get { + object obj = ResourceManager.GetObject("aitem_2573", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2574 { + get { + object obj = ResourceManager.GetObject("aitem_2574", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2575 { + get { + object obj = ResourceManager.GetObject("aitem_2575", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2576 { + get { + object obj = ResourceManager.GetObject("aitem_2576", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2577 { + get { + object obj = ResourceManager.GetObject("aitem_2577", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2578 { + get { + object obj = ResourceManager.GetObject("aitem_2578", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2579 { + get { + object obj = ResourceManager.GetObject("aitem_2579", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2580 { + get { + object obj = ResourceManager.GetObject("aitem_2580", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2581 { + get { + object obj = ResourceManager.GetObject("aitem_2581", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2582 { + get { + object obj = ResourceManager.GetObject("aitem_2582", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2583 { + get { + object obj = ResourceManager.GetObject("aitem_2583", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2584 { + get { + object obj = ResourceManager.GetObject("aitem_2584", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2585 { + get { + object obj = ResourceManager.GetObject("aitem_2585", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2587 { + get { + object obj = ResourceManager.GetObject("aitem_2587", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -16950,6 +17490,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_2618 { + get { + object obj = ResourceManager.GetObject("aitem_2618", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -18310,6 +18860,26 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_646 { + get { + object obj = ResourceManager.GetObject("aitem_646", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_647 { + get { + object obj = ResourceManager.GetObject("aitem_647", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -18340,6 +18910,276 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_656 { + get { + object obj = ResourceManager.GetObject("aitem_656", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_657 { + get { + object obj = ResourceManager.GetObject("aitem_657", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_658 { + get { + object obj = ResourceManager.GetObject("aitem_658", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_659 { + get { + object obj = ResourceManager.GetObject("aitem_659", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_660 { + get { + object obj = ResourceManager.GetObject("aitem_660", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_661 { + get { + object obj = ResourceManager.GetObject("aitem_661", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_662 { + get { + object obj = ResourceManager.GetObject("aitem_662", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_663 { + get { + object obj = ResourceManager.GetObject("aitem_663", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_665 { + get { + object obj = ResourceManager.GetObject("aitem_665", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_666 { + get { + object obj = ResourceManager.GetObject("aitem_666", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_667 { + get { + object obj = ResourceManager.GetObject("aitem_667", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_668 { + get { + object obj = ResourceManager.GetObject("aitem_668", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_669 { + get { + object obj = ResourceManager.GetObject("aitem_669", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_670 { + get { + object obj = ResourceManager.GetObject("aitem_670", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_671 { + get { + object obj = ResourceManager.GetObject("aitem_671", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_672 { + get { + object obj = ResourceManager.GetObject("aitem_672", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_673 { + get { + object obj = ResourceManager.GetObject("aitem_673", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_674 { + get { + object obj = ResourceManager.GetObject("aitem_674", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_675 { + get { + object obj = ResourceManager.GetObject("aitem_675", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_676 { + get { + object obj = ResourceManager.GetObject("aitem_676", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_677 { + get { + object obj = ResourceManager.GetObject("aitem_677", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_678 { + get { + object obj = ResourceManager.GetObject("aitem_678", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_679 { + get { + object obj = ResourceManager.GetObject("aitem_679", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_680 { + get { + object obj = ResourceManager.GetObject("aitem_680", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_681 { + get { + object obj = ResourceManager.GetObject("aitem_681", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_682 { + get { + object obj = ResourceManager.GetObject("aitem_682", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_683 { + get { + object obj = ResourceManager.GetObject("aitem_683", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -18400,6 +19240,176 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_710 { + get { + object obj = ResourceManager.GetObject("aitem_710", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_711 { + get { + object obj = ResourceManager.GetObject("aitem_711", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_754 { + get { + object obj = ResourceManager.GetObject("aitem_754", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_755 { + get { + object obj = ResourceManager.GetObject("aitem_755", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_756 { + get { + object obj = ResourceManager.GetObject("aitem_756", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_757 { + get { + object obj = ResourceManager.GetObject("aitem_757", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_758 { + get { + object obj = ResourceManager.GetObject("aitem_758", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_759 { + get { + object obj = ResourceManager.GetObject("aitem_759", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_760 { + get { + object obj = ResourceManager.GetObject("aitem_760", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_761 { + get { + object obj = ResourceManager.GetObject("aitem_761", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_762 { + get { + object obj = ResourceManager.GetObject("aitem_762", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_763 { + get { + object obj = ResourceManager.GetObject("aitem_763", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_764 { + get { + object obj = ResourceManager.GetObject("aitem_764", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_767 { + get { + object obj = ResourceManager.GetObject("aitem_767", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_768 { + get { + object obj = ResourceManager.GetObject("aitem_768", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_769 { + get { + object obj = ResourceManager.GetObject("aitem_769", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap aitem_770 { + get { + object obj = ResourceManager.GetObject("aitem_770", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -23393,9 +24403,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_1cf { + public static System.Drawing.Bitmap b_25_1c { get { - object obj = ResourceManager.GetObject("b_25_1cf", resourceCulture); + object obj = ResourceManager.GetObject("b_25_1c", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23403,9 +24413,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_1cfs { + public static System.Drawing.Bitmap b_25_1cs { get { - object obj = ResourceManager.GetObject("b_25_1cfs", resourceCulture); + object obj = ResourceManager.GetObject("b_25_1cs", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23433,9 +24443,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_2cf { + public static System.Drawing.Bitmap b_25_2c { get { - object obj = ResourceManager.GetObject("b_25_2cf", resourceCulture); + object obj = ResourceManager.GetObject("b_25_2c", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23443,9 +24453,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_2cfs { + public static System.Drawing.Bitmap b_25_2cs { get { - object obj = ResourceManager.GetObject("b_25_2cfs", resourceCulture); + object obj = ResourceManager.GetObject("b_25_2cs", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23473,9 +24483,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_3cf { + public static System.Drawing.Bitmap b_25_3c { get { - object obj = ResourceManager.GetObject("b_25_3cf", resourceCulture); + object obj = ResourceManager.GetObject("b_25_3c", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23483,9 +24493,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_3cfs { + public static System.Drawing.Bitmap b_25_3cs { get { - object obj = ResourceManager.GetObject("b_25_3cfs", resourceCulture); + object obj = ResourceManager.GetObject("b_25_3cs", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23513,9 +24523,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_4cf { + public static System.Drawing.Bitmap b_25_4c { get { - object obj = ResourceManager.GetObject("b_25_4cf", resourceCulture); + object obj = ResourceManager.GetObject("b_25_4c", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23523,9 +24533,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_4cfs { + public static System.Drawing.Bitmap b_25_4cs { get { - object obj = ResourceManager.GetObject("b_25_4cfs", resourceCulture); + object obj = ResourceManager.GetObject("b_25_4cs", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23553,9 +24563,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_5cf { + public static System.Drawing.Bitmap b_25_5c { get { - object obj = ResourceManager.GetObject("b_25_5cf", resourceCulture); + object obj = ResourceManager.GetObject("b_25_5c", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23563,9 +24573,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_5cfs { + public static System.Drawing.Bitmap b_25_5cs { get { - object obj = ResourceManager.GetObject("b_25_5cfs", resourceCulture); + object obj = ResourceManager.GetObject("b_25_5cs", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23593,9 +24603,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_6cf { + public static System.Drawing.Bitmap b_25_6c { get { - object obj = ResourceManager.GetObject("b_25_6cf", resourceCulture); + object obj = ResourceManager.GetObject("b_25_6c", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23603,9 +24613,9 @@ public class Resources { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap b_25_6cfs { + public static System.Drawing.Bitmap b_25_6cs { get { - object obj = ResourceManager.GetObject("b_25_6cfs", resourceCulture); + object obj = ResourceManager.GetObject("b_25_6cs", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -23650,26 +24660,6 @@ public class Resources { } } - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap b_25_8pf { - get { - object obj = ResourceManager.GetObject("b_25_8pf", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap b_25_8pfs { - get { - object obj = ResourceManager.GetObject("b_25_8pfs", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -23960,26 +24950,6 @@ public class Resources { } } - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap b_25f { - get { - object obj = ResourceManager.GetObject("b_25f", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap b_25fs { - get { - object obj = ResourceManager.GetObject("b_25fs", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -53070,26 +54040,6 @@ public class Resources { } } - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap c_25f { - get { - object obj = ResourceManager.GetObject("c_25f", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap c_25fs { - get { - object obj = ResourceManager.GetObject("c_25fs", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/PKHeX.Drawing.PokeSprite/Properties/Resources.resx b/PKHeX.Drawing.PokeSprite/Properties/Resources.resx index e69a450d8..f6dedf7de 100644 --- a/PKHeX.Drawing.PokeSprite/Properties/Resources.resx +++ b/PKHeX.Drawing.PokeSprite/Properties/Resources.resx @@ -1,4 +1,4 @@ - +