From 25f6b5259bcbb71199518c0c8f4c943a88f3b132 Mon Sep 17 00:00:00 2001 From: Kurt Date: Sat, 4 Feb 2017 18:27:28 -0800 Subject: [PATCH] Refactoring Add documentation for PKM/PKX, move some code around --- PKHeX.WinForms/MainWindow/Main.cs | 14 +- .../Save Editors/Gen6/SAV_HallOfFame.cs | 2 +- PKHeX.WinForms/Subforms/frmReport.cs | 4 +- PKHeX/Game/GameInfo.cs | 82 +++ PKHeX/PKM/CK3.cs | 2 +- PKHeX/PKM/PK3.cs | 2 +- PKHeX/PKM/PKM.cs | 122 +++- PKHeX/PKM/PKX.cs | 539 +++++++++++++----- PKHeX/PKM/XK3.cs | 2 +- 9 files changed, 592 insertions(+), 177 deletions(-) diff --git a/PKHeX.WinForms/MainWindow/Main.cs b/PKHeX.WinForms/MainWindow/Main.cs index 8a1255a2f..cec9dc1f8 100644 --- a/PKHeX.WinForms/MainWindow/Main.cs +++ b/PKHeX.WinForms/MainWindow/Main.cs @@ -2543,7 +2543,7 @@ private void updateNickname(object sender, EventArgs e) species = 0; // get the egg name. // If name is that of another language, don't replace the nickname - if (species != 0 && !PKX.getIsNicknamedAnyLanguage(species, SAV.Generation, TB_Nickname.Text)) + if (species != 0 && !PKX.getIsNicknamedAnyLanguage(species, TB_Nickname.Text, SAV.Generation)) return; TB_Nickname.Text = PKX.getSpeciesNameGeneration(species, lang, SAV.Generation); @@ -2601,7 +2601,7 @@ private void updateIsEgg(object sender, EventArgs e) if (!CHK_Nicknamed.Checked) { - TB_Nickname.Text = PKX.getSpeciesName(0, WinFormsUtil.getIndex(CB_Language)); + TB_Nickname.Text = PKX.getSpeciesNameGeneration(0, WinFormsUtil.getIndex(CB_Language), pkm.Format); CHK_Nicknamed.Checked = true; } } @@ -2619,7 +2619,7 @@ private void updateIsEgg(object sender, EventArgs e) GB_EggConditions.Enabled = false; } - if (TB_Nickname.Text == PKX.getSpeciesName(0, WinFormsUtil.getIndex(CB_Language))) + if (TB_Nickname.Text == PKX.getSpeciesNameGeneration(0, WinFormsUtil.getIndex(CB_Language), pkm.Format)) CHK_Nicknamed.Checked = false; } @@ -3578,7 +3578,7 @@ private void updateIsNicknamed(object sender, EventArgs e) if (CHK_IsEgg.Checked) species = 0; // get the egg name. - if (PKX.getIsNicknamedAnyLanguage(species, SAV.Generation, TB_Nickname.Text)) + if (PKX.getIsNicknamedAnyLanguage(species, TB_Nickname.Text, SAV.Generation)) CHK_Nicknamed.Checked = true; } @@ -3984,13 +3984,13 @@ private void B_OUTPasserby_Click(object sender, EventArgs e) try { gamename = GameInfo.Strings.gamelist[game]; } catch { gamename = "UNKNOWN GAME"; } - string[] cr = PKX.getCountryRegionText(country, region, curlanguage); + var cr = GameInfo.getCountryRegionText(country, region, curlanguage); result += "OT: " + otname + Environment.NewLine + "Message: " + message + Environment.NewLine + "Game: " + gamename + Environment.NewLine + - "Country: " + cr[0] + Environment.NewLine + - "Region: " + cr[1] + Environment.NewLine + + "Country: " + cr.Item1 + Environment.NewLine + + "Region: " + cr.Item2 + Environment.NewLine + "Favorite: " + GameInfo.Strings.specieslist[favpkm]; r_offset += 0xC8; // Advance to next entry diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs index fce7c4748..d817907d1 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs @@ -311,7 +311,7 @@ private void updateNickname(object sender, EventArgs e) else try { // get language - TB_Nickname.Text = PKX.getSpeciesName(species, SAV.Language); + TB_Nickname.Text = PKX.getSpeciesNameGeneration(species, SAV.Language, 6); } catch { } } diff --git a/PKHeX.WinForms/Subforms/frmReport.cs b/PKHeX.WinForms/Subforms/frmReport.cs index 0f2ef7709..dcbbbe386 100644 --- a/PKHeX.WinForms/Subforms/frmReport.cs +++ b/PKHeX.WinForms/Subforms/frmReport.cs @@ -31,8 +31,8 @@ public class Preview public string Move3 => GameInfo.Strings.movelist[pkm.Move3]; public string Move4 => GameInfo.Strings.movelist[pkm.Move4]; public string HeldItem => GameInfo.Strings.itemlist[pkm.HeldItem]; - public string MetLoc => PKX.getLocation(pkm, eggmet: false); - public string EggLoc => PKX.getLocation(pkm, eggmet: true); + public string MetLoc => pkm.getLocation(eggmet: false); + public string EggLoc => pkm.getLocation(eggmet: true); public string Ball => GameInfo.Strings.balllist[pkm.Ball]; public string OT => pkm.OT_Name; public string Version => GameInfo.Strings.gamelist[pkm.Version]; diff --git a/PKHeX/Game/GameInfo.cs b/PKHeX/Game/GameInfo.cs index 6f2f8fa1d..4654a36b9 100644 --- a/PKHeX/Game/GameInfo.cs +++ b/PKHeX/Game/GameInfo.cs @@ -443,5 +443,87 @@ public static List getLocationList(GameVersion Version, int SaveForma return metGen6; } + + /// + /// Gets Country and Region strings for corresponding IDs and language. + /// + /// Country ID + /// Region ID + /// Language ID + /// + public static Tuple getCountryRegionText(int country, int region, string language) + { + // Get Language we're fetching for + int lang = Array.IndexOf(new[] { "ja", "en", "fr", "de", "it", "es", "zh", "ko" }, language); + string c = getCountryString(country, lang); + string r = getRegionString(country, region, lang); + return new Tuple(c, r); // country, region + } + + /// + /// Gets the Country string for a given Country ID + /// + /// Country ID + /// Language ID + /// Country ID string + private static string getCountryString(int country, int language) + { + string c; + // Get Country Text + try + { + string[] inputCSV = Util.getStringList("countries"); + // Set up our Temporary Storage + string[] unsortedList = new string[inputCSV.Length - 1]; + int[] indexes = new int[inputCSV.Length - 1]; + + // Gather our data from the input file + for (int i = 1; i < inputCSV.Length; i++) + { + string[] countryData = inputCSV[i].Split(','); + if (countryData.Length <= 1) continue; + indexes[i - 1] = Convert.ToInt32(countryData[0]); + unsortedList[i - 1] = countryData[language + 1]; + } + + int countrynum = Array.IndexOf(indexes, country); + c = unsortedList[countrynum]; + } + catch { c = "Illegal"; } + + return c; + } + + /// + /// Gets the Region string for a specified country ID. + /// + /// Country ID + /// Region ID + /// Language ID + /// Region ID string + private static string getRegionString(int country, int region, int language) + { + // Get Region Text + try + { + string[] inputCSV = Util.getStringList("sr_" + country.ToString("000")); + // Set up our Temporary Storage + string[] unsortedList = new string[inputCSV.Length - 1]; + int[] indexes = new int[inputCSV.Length - 1]; + + // Gather our data from the input file + for (int i = 1; i < inputCSV.Length; i++) + { + string[] countryData = inputCSV[i].Split(','); + if (countryData.Length <= 1) continue; + indexes[i - 1] = Convert.ToInt32(countryData[0]); + unsortedList[i - 1] = countryData[language + 1]; + } + + int regionnum = Array.IndexOf(indexes, region); + return unsortedList[regionnum]; + } + catch { return "Illegal"; } + } } } diff --git a/PKHeX/PKM/CK3.cs b/PKHeX/PKM/CK3.cs index e73e71ece..250bd2bcd 100644 --- a/PKHeX/PKM/CK3.cs +++ b/PKHeX/PKM/CK3.cs @@ -32,7 +32,7 @@ public CK3(byte[] decryptedData = null, string ident = null) public override int Nature { get { return (int)(PID % 25); } set { } } public override int AltForm { get { return Species == 201 ? PKX.getUnownForm(PID) : 0; } set { } } - public override bool IsNicknamed { get { return PKX.getIsNicknamed(Species, Nickname); } set { } } + public override bool IsNicknamed { get { return PKX.getIsNicknamedAnyLanguage(Species, Nickname, Format); } set { } } public override int Gender { get { return PKX.getGender(Species, PID); } set { } } public override int Characteristic => -1; public override int CurrentFriendship { get { return OT_Friendship; } set { OT_Friendship = value; } } diff --git a/PKHeX/PKM/PK3.cs b/PKHeX/PKM/PK3.cs index d5f4e4435..2bc039398 100644 --- a/PKHeX/PKM/PK3.cs +++ b/PKHeX/PKM/PK3.cs @@ -29,7 +29,7 @@ public PK3(byte[] decryptedData = null, string ident = null) public override int Nature { get { return (int)(PID % 25); } set { } } public override int AltForm { get { return Species == 201 ? PKX.getUnownForm(PID) : 0; } set { } } - public override bool IsNicknamed { get { return PKX.getIsNicknamed(Species, Nickname); } set { } } + public override bool IsNicknamed { get { return PKX.getIsNicknamedAnyLanguage(Species, Nickname, Format); } set { } } public override int Gender { get { return PKX.getGender(Species, PID); } set { } } public override int Characteristic => -1; public override int CurrentFriendship { get { return OT_Friendship; } set { OT_Friendship = value; } } diff --git a/PKHeX/PKM/PKM.cs b/PKHeX/PKM/PKM.cs index 3c385af7c..e9b44677b 100644 --- a/PKHeX/PKM/PKM.cs +++ b/PKHeX/PKM/PKM.cs @@ -300,7 +300,7 @@ public int GenNumber public int MarkStar { get { return Markings[4]; } set { var marks = Markings; marks[4] = value; Markings = marks; } } public int MarkDiamond { get { return Markings[5]; } set { var marks = Markings; marks[5] = value; Markings = marks; } } public string ShowdownText => ShowdownSet.getShowdownText(this); - public string[] QRText => PKX.getQRText(this); + public string[] QRText => this.getQRText(); public virtual string FileName { @@ -431,6 +431,11 @@ public virtual bool IsOriginValid() public virtual bool HT_SPA { get { return false; } set { } } public virtual bool HT_SPD { get { return false; } set { } } public virtual bool HT_SPE { get { return false; } set { } } + + /// + /// Toggles the Hyper Training flag for a given stat. + /// + /// Battle Stat (H/A/B/S/C/D) public void HyperTrainInvert(int stat) { switch (stat) @@ -444,8 +449,16 @@ public void HyperTrainInvert(int stat) } } + /// + /// Checks if the could inhabit a set of games. + /// + /// Set of games. + /// True if could inhabit, False if not. public bool InhabitedGeneration(int Generation) { + if (VC1 && Generation == 1) + return true; // Virtual Console Gen1 + if (Format < Generation) return false; // Future if (GenNumber > Generation) @@ -465,9 +478,20 @@ public bool InhabitedGeneration(int Generation) } } - // Methods + /// + /// Checks if the current is valid. + /// + /// True if valid, False if invalid. public abstract bool getGenderIsValid(); + + /// + /// Updates the checksum of the . + /// public void RefreshChecksum() { Checksum = CalculateChecksum(); } + + /// + /// Reorders moves and fixes PP if necessary. + /// public void FixMoves() { ReorderMoves(); @@ -478,6 +502,9 @@ public void FixMoves() if (Move4 == 0) { Move4_PP = 0; Move4_PPUps = 0; } } + /// + /// Reorders moves to put Empty entries last. + /// private void ReorderMoves() { if (Move4 != 0 && Move3 == 0) @@ -504,6 +531,11 @@ private void ReorderMoves() ReorderMoves(); } } + + /// + /// Applies the desired Ability option. + /// + /// Ability Number (0/1/2) public void RefreshAbility(int n) { AbilityNumber = 1 << n; @@ -512,7 +544,10 @@ public void RefreshAbility(int n) Ability = abilities[n]; } - + /// + /// Gets the IV Judge Rating value. + /// + /// IV Judge scales his response 0 (worst) to 3 (best). public int PotentialRating { get @@ -526,6 +561,11 @@ public int PotentialRating } } + /// + /// Gets the current Battle Stats. + /// + /// entry containing Base Stat Info + /// Battle Stats (H/A/B/S/C/D) public virtual ushort[] getStats(PersonalInfo p) { int level = CurrentLevel; @@ -545,6 +585,10 @@ public virtual ushort[] getStats(PersonalInfo p) Stats[decr] *= 9; Stats[decr] /= 10; return Stats; } + /// + /// Applies the specified stats to the . + /// + /// Battle Stats (H/A/B/S/C/D) public void setStats(ushort[] Stats) { Stat_HPMax = Stat_HPCurrent = Stats[0]; @@ -554,18 +598,39 @@ public void setStats(ushort[] Stats) Stat_SPA = Stats[4]; Stat_SPD = Stats[5]; } + + /// + /// Checks if the can hold its . + /// + /// Items that the can hold. + /// True/False if the can hold its . public virtual bool CanHoldItem(ushort[] ValidArray) { return ValidArray.Contains((ushort)HeldItem); } + /// + /// Deep clones the object. The clone will not have any shared resources with the source. + /// + /// Cloned object public abstract PKM Clone(); + /// + /// Gets the PP of a Move ID with consideration of the amount of PP Ups applied. + /// + /// Move ID + /// PP Ups count + /// Current PP for the move. public int getMovePP(int move, int ppup) { return getBasePP(move) * (5 + ppup) / 5; } + /// + /// Gets the base PP of a move ID depending on the 's format. + /// + /// Move ID + /// Amount of PP the move has by default (no PP Ups). private int getBasePP(int move) { int[] pptable; @@ -585,30 +650,58 @@ private int getBasePP(int move) return pptable[move]; } + /// + /// Applies a shiny PID to the . + /// + /// + /// If a originated in a generation prior to Generation 6, the is updated. + /// public void setShinyPID() { do PID = PKX.getRandomPID(Species, Gender, Version, Nature, AltForm, PID); while (!IsShiny); if (GenNumber < 6) EncryptionConstant = PID; } + /// + /// Applies a PID to the according to the specified . + /// + /// + /// If a originated in a generation prior to Generation 6, the is updated. + /// public void setPIDGender(int gender) { do PID = PKX.getRandomPID(Species, gender, Version, Nature, AltForm, PID); while (IsShiny); if (GenNumber < 6) EncryptionConstant = PID; } + /// + /// Applies a PID to the according to the specified . + /// + /// + /// If a originated in a generation prior to Generation 6, the is updated. + /// public void setPIDNature(int nature) { do PID = PKX.getRandomPID(Species, Gender, Version, nature, AltForm, PID); while (IsShiny); if (GenNumber < 6) EncryptionConstant = PID; } + /// + /// Applies a PID to the according to the specified . + /// + /// + /// This method should only be used for Unown originating in Generation 3 games. + /// If a originated in a generation prior to Generation 6, the is updated. + /// public void setPIDUnown3(int form) { do PID = Util.rnd32(); while (PKX.getUnownForm(PID) != form); } - - // Gen3 Conversion -- do not use if format > 4 + + /// + /// Converts a or to . + /// + /// format public PKM convertToCK3() { if (Format != 3) @@ -620,6 +713,10 @@ public PKM convertToCK3() pk.setStats(getStats(PersonalTable.RS[pk.Species])); return pk; } + /// + /// Converts a or to . + /// + /// format public PKM convertToXK3() { if (Format != 3) @@ -631,6 +728,10 @@ public PKM convertToXK3() pk.setStats(getStats(PersonalTable.RS[pk.Species])); return pk; } + /// + /// Converts a or to . + /// + /// format public PKM convertToPK3() { if (Format != 3) @@ -643,17 +744,22 @@ public PKM convertToPK3() return pk; } + /// + /// Applies all shared properties from to . + /// + /// that supplies property values. + /// that receives property values. protected void TransferPropertiesWithReflection(PKM Source, PKM Destination) { var SourceProperties = ReflectUtil.getPropertiesCanWritePublic(Source.GetType()); var DestinationProperties = ReflectUtil.getPropertiesCanWritePublic(Destination.GetType()); + // Skip Data property when applying all individual properties. Let the setters do the updates for Data. foreach (string property in SourceProperties.Intersect(DestinationProperties).Where(prop => prop != nameof(Data))) { var prop = ReflectUtil.GetValue(this, property); - if (prop == null) - continue; - ReflectUtil.SetValue(Destination, property, prop); + if (prop != null) + ReflectUtil.SetValue(Destination, property, prop); } } } diff --git a/PKHeX/PKM/PKX.cs b/PKHeX/PKM/PKX.cs index 766783525..132684f12 100644 --- a/PKHeX/PKM/PKX.cs +++ b/PKHeX/PKM/PKX.cs @@ -5,8 +5,14 @@ namespace PKHeX.Core { + /// + /// Common logic for data providing and manipulation. + /// public static class PKX { + private static readonly PersonalTable Personal = PersonalTable.SM; + private const int Generation = 7; + internal const int SIZE_1ULIST = 69; internal const int SIZE_1JLIST = 59; internal const int SIZE_1PARTY = 44; @@ -36,10 +42,10 @@ public static class PKX internal const int SIZE_6BLOCK = 56; /// - /// Determines if the given length is valid for a Pokemon file. + /// Determines if the given length is valid for a . /// - /// Length of the data to check. - /// A boolean indicating whether or not the length is valid for a Pokemon file. + /// Data length of the file/array. + /// A indicating whether or not the length is valid for a . public static bool getIsPKM(long len) { return new[] @@ -69,7 +75,7 @@ public static uint LCRNG(ref uint seed) return seed = seed * a + c; } #region ExpTable - public static readonly uint[,] ExpTable = + private static readonly uint[,] ExpTable = { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, @@ -190,6 +196,12 @@ public static uint LCRNG(ref uint seed) Util.getSpeciesList("zh2"), // 10 Traditional }; + /// + /// Gets a Pokémon's default name for the desired language ID. + /// + /// National Dex number of the Pokémon. Should be 0 if an egg. + /// Language ID of the Pokémon + /// The Species name if within expected range, else an empty string. public static string getSpeciesName(int species, int lang) { if (lang < 0 || SpeciesLang.Length <= lang) @@ -199,13 +211,14 @@ public static string getSpeciesName(int species, int lang) return SpeciesLang[lang][species]; } - public static bool getIsNicknamed(int species, string nick) - { - if (species < 0 || SpeciesLang[0].Length <= species) - return false; - - return SpeciesLang.All(list => list[species].ToUpper() != nick); - } + + /// + /// Gets a Pokémon's default name for the desired language ID and generation. + /// + /// National Dex number of the Pokémon. Should be 0 if an egg. + /// Language ID of the Pokémon + /// Generation specific formatting option + /// Generation specific default species name public static string getSpeciesNameGeneration(int species, int lang, int generation) { string nick = getSpeciesName(species, lang); @@ -216,20 +229,36 @@ public static string getSpeciesNameGeneration(int species, int lang, int generat nick = nick.Replace(" ", ""); return nick; } - public static bool getIsNicknamedAnyLanguage(int species, int generation, string nick) + + /// + /// Checks if a nickname matches the species name of any language. + /// + /// National Dex number of the Pokémon. Should be 0 if an egg. + /// Current name + /// Generation specific formatting option + /// True if it does not match any language name, False if not nicknamed + public static bool getIsNicknamedAnyLanguage(int species, string nick, int generation) { int len = SpeciesLang.Length; + if (generation < 3) + len = 3; + else if (generation < 7) + len = 8; + for (int i = 0; i < len; i++) if (getSpeciesNameGeneration(species, i, generation) == nick) return false; return true; } - public static readonly PersonalTable Personal = PersonalTable.SM; - // Stat Fetching - public static uint[] getRandomEVs(int Generation = 6) + /// + /// Gets randomized EVs for a given generation format + /// + /// Generation specific formatting option + /// Array containing randomized EVs (H/A/B/S/C/D) + public static uint[] getRandomEVs(int generation = Generation) { - if (Generation > 2) + if (generation > 2) { uint[] evs = new uint[6]; do @@ -248,10 +277,17 @@ public static uint[] getRandomEVs(int Generation = 6) { uint[] evs = new uint[6]; for (int i = 0; i < evs.Length; i++) - evs[i] = Util.rnd32()%0x10000; + evs[i] = Util.rnd32() & ushort.MaxValue; return evs; } } + + /// + /// Gets the current level of a species. + /// + /// National Dex number of the Pokémon. + /// Experience points + /// Current level of the species. public static int getLevel(int species, uint exp) { int growth = Personal[species].EXPGrowth; @@ -260,12 +296,25 @@ public static int getLevel(int species, uint exp) if (tl == 100) return 100; return --tl; } + + /// + /// Gets the minimum Experience points for the specified level. + /// + /// Current level + /// National Dex number of the Pokémon. + /// Experience points needed to have specified level. public static uint getEXP(int level, int species) { if (level <= 1) return 0; if (level > 100) level = 100; return ExpTable[level, Personal[species].EXPGrowth]; } + + /// + /// Translates a Gender string to Gender integer. + /// + /// Gender string + /// Gender integer public static int getGender(string s) { if (s == null) @@ -276,131 +325,10 @@ public static int getGender(string s) return 1; return 2; } - - public static string[] getCountryRegionText(int country, int region, string lang) - { - // Get Language we're fetching for - int index = Array.IndexOf(new[] { "ja", "en", "fr", "de", "it", "es", "zh", "ko"}, lang); - // Return value storage - string[] data = new string[2]; // country, region - - // Get Country Text - try - { - string[] inputCSV = Util.getStringList("countries"); - // Set up our Temporary Storage - string[] unsortedList = new string[inputCSV.Length - 1]; - int[] indexes = new int[inputCSV.Length - 1]; - - // Gather our data from the input file - for (int i = 1; i < inputCSV.Length; i++) - { - string[] countryData = inputCSV[i].Split(','); - if (countryData.Length <= 1) continue; - indexes[i - 1] = Convert.ToInt32(countryData[0]); - unsortedList[i - 1] = countryData[index + 1]; - } - - int countrynum = Array.IndexOf(indexes, country); - data[0] = unsortedList[countrynum]; - } - catch { data[0] = "Illegal"; } - - // Get Region Text - try - { - string[] inputCSV = Util.getStringList("sr_" + country.ToString("000")); - // Set up our Temporary Storage - string[] unsortedList = new string[inputCSV.Length - 1]; - int[] indexes = new int[inputCSV.Length - 1]; - - // Gather our data from the input file - for (int i = 1; i < inputCSV.Length; i++) - { - string[] countryData = inputCSV[i].Split(','); - if (countryData.Length <= 1) continue; - indexes[i - 1] = Convert.ToInt32(countryData[0]); - unsortedList[i - 1] = countryData[index + 1]; - } - - int regionnum = Array.IndexOf(indexes, region); - data[1] = unsortedList[regionnum]; - } - catch { data[1] = "Illegal"; } - return data; - } - - public static string getLocation(PKM pk, bool eggmet) - { - if (pk.Format <= 2) - return ""; - - int locval = eggmet ? pk.Egg_Location : pk.Met_Location; - - if (pk.Format == 2) - return GameInfo.Strings.metGSC_00000[locval]; - if (pk.Format == 3) - return GameInfo.Strings.metRSEFRLG_00000[locval%0x100]; - if (pk.Gen4 && (eggmet || pk.Format == 4)) - { - if (locval < 2000) return GameInfo.Strings.metHGSS_00000[locval]; - if (locval < 3000) return GameInfo.Strings.metHGSS_02000[locval % 2000]; - return GameInfo.Strings.metHGSS_03000[locval % 3000]; - } - if (pk.Gen5 || pk.Format <= 5) - { - if (locval < 30000) return GameInfo.Strings.metBW2_00000[locval]; - if (locval < 40000) return GameInfo.Strings.metBW2_30000[locval % 10000 - 1]; - if (locval < 60000) return GameInfo.Strings.metBW2_40000[locval % 10000 - 1]; - return GameInfo.Strings.metBW2_60000[locval % 10000 - 1]; - } - if (pk.Gen6 || pk.Format <= 6) - { - if (locval < 30000) return GameInfo.Strings.metXY_00000[locval]; - if (locval < 40000) return GameInfo.Strings.metXY_30000[locval % 10000 - 1]; - if (locval < 60000) return GameInfo.Strings.metXY_40000[locval % 10000 - 1]; - return GameInfo.Strings.metXY_60000[locval % 10000 - 1]; - } - if (pk.Gen7 || pk.Format <= 7) - { - if (locval < 30000) return GameInfo.Strings.metSM_00000[locval]; - if (locval < 40000) return GameInfo.Strings.metSM_30000[locval % 10000 - 1]; - if (locval < 60000) return GameInfo.Strings.metSM_40000[locval % 10000 - 1]; - return GameInfo.Strings.metSM_60000[locval % 10000 - 1]; - } - return null; // Shouldn't happen for gen 3+ - } - public static string[] getQRText(PKM pkm) - { - var s = GameInfo.Strings; - string[] response = new string[3]; - // Summarize - string filename = pkm.Nickname; - if (pkm.Nickname != s.specieslist[pkm.Species] && s.specieslist[pkm.Species] != null) - filename += $" ({s.specieslist[pkm.Species]})"; - response[0] = $"{filename} [{s.abilitylist[pkm.Ability]}] lv{pkm.Stat_Level} @ {s.itemlist[pkm.HeldItem]} -- {s.natures[pkm.Nature]}"; - response[1] = $"{s.movelist[pkm.Move1]} / {s.movelist[pkm.Move2]} / {s.movelist[pkm.Move3]} / {s.movelist[pkm.Move4]}"; - response[2] = string.Format( - "IVs:{0}{1}{2}{3}{4}{5}" - + Environment.NewLine + Environment.NewLine + - "EVs:{6}{7}{8}{9}{10}{11}", - Environment.NewLine + pkm.IV_HP.ToString("00"), - Environment.NewLine + pkm.IV_ATK.ToString("00"), - Environment.NewLine + pkm.IV_DEF.ToString("00"), - Environment.NewLine + pkm.IV_SPA.ToString("00"), - Environment.NewLine + pkm.IV_SPD.ToString("00"), - Environment.NewLine + pkm.IV_SPE.ToString("00"), - Environment.NewLine + pkm.EV_HP, - Environment.NewLine + pkm.EV_ATK, - Environment.NewLine + pkm.EV_DEF, - Environment.NewLine + pkm.EV_SPA, - Environment.NewLine + pkm.EV_SPD, - Environment.NewLine + pkm.EV_SPE); - - return response; - } - - // PKX Manipulation + + /// + /// Positions for shuffling. + /// public static readonly byte[][] blockPosition = { new byte[] {0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3}, @@ -409,10 +337,21 @@ public static string[] getQRText(PKM pkm) new byte[] {3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0}, }; + /// + /// Positions for unshuffling. + /// public static readonly byte[] blockPositionInvert = { 0, 1, 2, 4, 3, 5, 6, 7, 12, 18, 13, 19, 8, 10, 14, 20, 16, 22, 9, 11, 15, 21, 17, 23 }; + + + /// + /// Shuffles a 232 byte array containing data. + /// + /// Data to shuffle + /// Block Shuffle order + /// Shuffled byte array public static byte[] shuffleArray(byte[] data, uint sv) { byte[] sdata = new byte[data.Length]; @@ -428,6 +367,13 @@ public static byte[] shuffleArray(byte[] data, uint sv) return sdata; } + + /// + /// Decrypts a 232 byte + party stat byte array. + /// + /// Encrypted data. + /// Decrypted data. + /// Encrypted data. public static byte[] decryptArray(byte[] ekx) { byte[] pkx = (byte[])ekx.Clone(); @@ -452,6 +398,11 @@ public static byte[] decryptArray(byte[] ekx) return pkx; } + + /// + /// Encrypts a 232 byte + party stat byte array. + /// + /// Decrypted data. public static byte[] encryptArray(byte[] pkx) { // Shuffle @@ -479,6 +430,12 @@ public static byte[] encryptArray(byte[] pkx) // Done return ekx; } + + /// + /// Gets the checksum of a 232 byte array. + /// + /// Decrypted data. + /// public static ushort getCHK(byte[] data) { ushort chk = 0; @@ -488,6 +445,17 @@ public static ushort getCHK(byte[] data) return chk; } + /// + /// Gets a random PID according to specifications. + /// + /// National Dex ID + /// Current Gender + /// Origin Generation + /// Nature + /// AltForm + /// Current PID + /// Used to retain ability bits. + /// Rerolled PID. public static uint getRandomPID(int species, int cg, int origin, int nature, int form, uint OLDPID) { uint bits = OLDPID & 0x00010001; @@ -543,9 +511,17 @@ public static string getSpriteString(int species, int form, int gender, int gene return file; } - - // Personal.dat - public static string[] getFormList(int species, string[] t, string[] f, string[] g, int generation = 6) + + /// + /// Gets a list of formes that the species can have. + /// + /// National Dex number of the Pokémon. + /// List of type names + /// List of forme names + /// List of gender names + /// Generation number for exclusive formes + /// A list of strings corresponding to the formes that a Pokémon can have. + public static string[] getFormList(int species, string[] t, string[] f, string[] g, int generation = Generation) { // Mega List if (Array.IndexOf(new[] @@ -1036,7 +1012,7 @@ public static string[] getFormList(int species, string[] t, string[] f, string[] /// Calculate the Hidden Power Type of the entered IVs. /// Hidden Power Type - /// Order: HP,ATK,DEF,SPEED,SPA,SPD + /// Individual Values (H/A/B/S/C/D) /// Hidden Power Type public static int[] setHPIVs(int type, int[] ivs) { @@ -1077,6 +1053,7 @@ public static string SanitizeString(string str) s = s.Replace("\uE08E", "\u2642"); // ♂ return s; } + /// /// Converts full width to half width when appropriate /// @@ -1103,14 +1080,23 @@ public static string UnSanitizeString(string str, int species = -1, bool nicknam return s; } + /// + /// Trims a string at the first instance of a 0xFFFF terminator. + /// + /// String to trim. + /// Trimmed string. public static string TrimFromFFFF(string input) { int index = input.IndexOf((char)0xFFFF); return index < 0 ? input : input.Substring(0, index); } - // Past Gen Manipulation - + /// + /// Shuffles a 136 byte array containing data. + /// + /// Data to shuffle + /// Block Shuffle order + /// Shuffled byte array public static byte[] shuffleArray45(byte[] data, uint sv) { byte[] sdata = new byte[data.Length]; @@ -1127,6 +1113,11 @@ public static byte[] shuffleArray45(byte[] data, uint sv) return sdata; } + /// + /// Decrypts a 136 byte + party stat byte array. + /// + /// Encrypted data. + /// Decrypted data. public static byte[] decryptArray45(byte[] ekm) { byte[] pkm = (byte[])ekm.Clone(); @@ -1153,6 +1144,11 @@ public static byte[] decryptArray45(byte[] ekm) return pkm; } + /// + /// Encrypts a 136 byte + party stat byte array. + /// + /// Decrypted data. + /// Encrypted data. public static byte[] encryptArray45(byte[] pkm) { uint pv = BitConverter.ToUInt32(pkm, 0); @@ -1181,24 +1177,45 @@ public static byte[] encryptArray45(byte[] pkm) return ekm; } + /// + /// Gets the Unown Forme ID from PID. + /// + /// Personality ID + /// Should only be used for 3rd Generation origin specimens. + /// public static int getUnownForm(uint PID) { byte[] data = BitConverter.GetBytes(PID); return (((data[3] & 3) << 6) + ((data[2] & 3) << 4) + ((data[1] & 3) << 2) + ((data[0] & 3) << 0)) % 28; } + /// + /// Converts a Generation 4 value to Unicode character. + /// + /// Encoded value. + /// Decoded value (unicode). public static ushort val2charG4(ushort val) { int index = Array.IndexOf(G4Values, val); return index > -1 ? G4Chars[index] : (ushort)0xFFFF; } + /// + /// Converts a Unicode character to Generation 4 value. + /// + /// Decoded value (unicode). + /// Encoded value. public static ushort char2valG4(ushort chr) { int index = Array.IndexOf(G4Chars, chr); return index > -1 ? G4Values[index] : (ushort)0xFFFF; } + /// + /// Converts Generation 4 Little Endian encoded character data to string. + /// + /// Byte array containing encoded character data. + /// Converted string. public static string array2strG4(byte[] strdata) { string s = ""; @@ -1213,6 +1230,11 @@ public static string array2strG4(byte[] strdata) return s; } + /// + /// Converts a string to Generation 4 Little Endian encoded character data. + /// + /// String to be converted. + /// Byte array containing encoded character data public static byte[] str2arrayG4(string str) { byte[] strdata = new byte[str.Length * 2 + 2]; // +2 for 0xFFFF @@ -1228,6 +1250,11 @@ public static byte[] str2arrayG4(string str) return strdata; } + /// + /// Converts Generation 4 Big Endian encoded character data to string. + /// + /// Byte array containing encoded character data. + /// Converted string. public static string array2strG4BE(byte[] strdata) { string s = ""; @@ -1242,6 +1269,11 @@ public static string array2strG4BE(byte[] strdata) return s; } + /// + /// Converts a string to Generation 4 Big Endian encoded character data. + /// + /// String to be converted. + /// Byte array containing encoded character data public static byte[] str2arrayG4BE(string str) { byte[] strdata = new byte[str.Length * 2 + 2]; // +2 for 0xFFFF @@ -1257,16 +1289,40 @@ public static byte[] str2arrayG4BE(string str) return strdata; } - // Gen3 && 3->4 Conversion has two character tables, and translates to the same character map. - public static ushort getG4Val(byte val, bool jp) { return jp ? G34_4J[val] : G34_4E[val]; } - public static ushort getG3Char(byte val, bool jp) { return val2charG4(getG4Val(val, jp)); } + /// + /// Converts a Generation 3 encoded value to corresponding Generation 4 encoded value. + /// + /// Generation 3 encoded value. + /// Value source is Japanese font. + /// Generation 4 encoded value. + public static ushort getG4Val(byte val, bool jp) => jp ? G34_4J[val] : G34_4E[val]; + /// + /// Converts a Generation 3 encoded value to corresponding Generation 4 decoded character. + /// + /// Generation 3 encoded value. + /// Value source is Japanese font. + /// Decoded value. + public static ushort getG3Char(byte val, bool jp) => val2charG4(getG4Val(val, jp)); + + /// + /// Converts a Generation 4 decoded character to Generation 3 encoded value. + /// + /// Generation 4 decoded character. + /// Character destination is Japanese font. + /// Generation 3 encoded value. public static byte setG3Char(ushort chr, bool jp) { int index = Array.IndexOf(jp ? G34_4J : G34_4E, char2valG4(chr)); return (byte)(index > -1 ? index : 0xFF); } + /// + /// Converts a Generation 3 encoded value array to string. + /// + /// Byte array containing string data. + /// Value source is Japanese font. + /// Decoded string. public static string getG3Str(byte[] strdata, bool jp) { return strdata @@ -1276,6 +1332,12 @@ public static string getG3Str(byte[] strdata, bool jp) .Aggregate("", (current, chr) => current + (char)chr); } + /// + /// Converts a string to a Generation 3 encoded value array. + /// + /// Decoded string. + /// String destination is Japanese font. + /// public static byte[] setG3Str(string str, bool jp) { byte[] strdata = new byte[str.Length + 1]; // +1 for 0xFF @@ -1292,18 +1354,35 @@ public static byte[] setG3Str(string str, bool jp) return strdata; } + /// + /// Converts Generation 3 species ID to National Dex ID. + /// + /// Generation 3 species ID. + /// National Dex ID. public static int getG4Species(int g3index) { int index = Array.IndexOf(oldindex, g3index); return newindex[index > -1 ? index : 0]; } + /// + /// Converts a National Dex ID to Generation 3 species ID. + /// + /// National Dex ID + /// Generation 3 species ID. public static int getG3Species(int g4index) { int index = Array.IndexOf(newindex, g4index); return oldindex[index > -1 ? index : 0]; } + /// + /// Gets the gender ID of the species based on the Personality ID. + /// + /// National Dex ID. + /// Personality ID. + /// Gender ID (0/1/2) + /// This method should only be used for Generations 3-5 origin. public static int getGender(int species, uint PID) { int genderratio = Personal[species].Gender; @@ -1753,6 +1832,10 @@ public static int getGender(int species, uint PID) }; #endregion + /// + /// Trash Bytes for Generation 3->4 + /// + /// String buffers are reused, data is not cleared which yields the trash bytes. public static readonly byte[][] G4TransferTrashBytes = { new byte[] { }, // Unused new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, @@ -1764,6 +1847,11 @@ public static int getGender(int species, uint PID) new byte[] { 0x74, 0x20, 0x0D, 0x02, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xA1, 0x0C, 0x02, 0xE0, 0xFF }, }; + /// + /// Decrypts an 80 byte format byte array. + /// + /// Encrypted data. + /// Decrypted data. public static byte[] decryptArray3(byte[] ekm) { if (ekm.Length != SIZE_3PARTY && ekm.Length != SIZE_3STORED) @@ -1778,6 +1866,13 @@ public static byte[] decryptArray3(byte[] ekm) ekm[i] ^= xorkey[i % 4]; return shuffleArray3(ekm, PID%24); } + + /// + /// Shuffles an 80 byte format byte array. + /// + /// Unshuffled data. + /// Block order shuffle value + /// public static byte[] shuffleArray3(byte[] data, uint sv) { byte[] sdata = new byte[data.Length]; @@ -1793,6 +1888,12 @@ public static byte[] shuffleArray3(byte[] data, uint sv) return sdata; } + + /// + /// Encrypts an 80 byte format byte array. + /// + /// Decrypted data. + /// Encrypted data. public static byte[] encryptArray3(byte[] pkm) { if (pkm.Length != SIZE_3PARTY && pkm.Length != SIZE_3STORED) @@ -1809,7 +1910,14 @@ public static byte[] encryptArray3(byte[] pkm) return ekm; } - private const ushort ITEM_UNK = 128; // unused item, placeholder for sprite finding + /// Unused item, placeholder for sprite finding + private const ushort ITEM_UNK = 128; + + /// + /// Converts a Generation 2 Item ID to Generation 4+ Item ID. + /// + /// Generation 2 Item ID. + /// Generation 4+ Item ID. public static ushort getG4Item(byte g2val) { ushort[] arr = @@ -1845,6 +1953,12 @@ public static ushort getG4Item(byte g2val) ushort val = g2val > arr.Length ? ushort.MaxValue : arr[g2val]; return val == ushort.MaxValue ? ITEM_UNK : val; } + + /// + /// Converts a Generation 3 Item ID to Generation 4+ Item ID. + /// + /// Generation 3 Item ID. + /// Generation 4+ Item ID. public static ushort getG4Item(ushort g3val) { ushort[] arr = @@ -1889,6 +2003,12 @@ public static ushort getG4Item(ushort g3val) ushort val = g3val > arr.Length ? ushort.MaxValue : arr[g3val]; return val == ushort.MaxValue ? ITEM_UNK : val; } + + /// + /// Checks if the item can be kept during 3->4 conversion. + /// + /// Generation 3 Item ID. + /// True if transferrable, False if not transferrable. public static bool isTransferrable34(ushort item) { return item == ITEM_UNK && item > 0; @@ -2403,19 +2523,35 @@ public static bool isTransferrable34(ushort item) {0xFF, "9"} }; #endregion - + + /// + /// Converts Generation 1 species ID to National Dex ID. + /// + /// Generation 1 species ID. + /// National Dex ID. public static int getG1Species(int raw_id) { int[] table = { 0x00, 0x70, 0x73, 0x20, 0x23, 0x15, 0x64, 0x22, 0x50, 0x02, 0x67, 0x6C, 0x66, 0x58, 0x5E, 0x1D, 0x1F, 0x68, 0x6F, 0x83, 0x3B, 0x97, 0x82, 0x5A, 0x48, 0x5C, 0x7B, 0x78, 0x09, 0x7F, 0x72, 0x00, 0x00, 0x3A, 0x5F, 0x16, 0x10, 0x4F, 0x40, 0x4B, 0x71, 0x43, 0x7A, 0x6A, 0x6B, 0x18, 0x2F, 0x36, 0x60, 0x4C, 0x00, 0x7E, 0x00, 0x7D, 0x52, 0x6D, 0x00, 0x38, 0x56, 0x32, 0x80, 0x00, 0x00, 0x00, 0x53, 0x30, 0x95, 0x00, 0x00, 0x00, 0x54, 0x3C, 0x7C, 0x92, 0x90, 0x91, 0x84, 0x34, 0x62, 0x00, 0x00, 0x00, 0x25, 0x26, 0x19, 0x1A, 0x00, 0x00, 0x93, 0x94, 0x8C, 0x8D, 0x74, 0x75, 0x00, 0x00, 0x1B, 0x1C, 0x8A, 0x8B, 0x27, 0x28, 0x85, 0x88, 0x87, 0x86, 0x42, 0x29, 0x17, 0x2E, 0x3D, 0x3E, 0x0D, 0x0E, 0x0F, 0x00, 0x55, 0x39, 0x33, 0x31, 0x57, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x44, 0x00, 0x37, 0x61, 0x2A, 0x96, 0x8F, 0x81, 0x00, 0x00, 0x59, 0x00, 0x63, 0x5B, 0x00, 0x65, 0x24, 0x6E, 0x35, 0x69, 0x00, 0x5D, 0x3F, 0x41, 0x11, 0x12, 0x79, 0x01, 0x03, 0x49, 0x00, 0x76, 0x77, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x4E, 0x13, 0x14, 0x21, 0x1E, 0x4A, 0x89, 0x8E, 0x00, 0x51, 0x00, 0x00, 0x04, 0x07, 0x05, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x2C, 0x2D, 0x45, 0x46, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; return table[raw_id]; } + /// + /// Converts a National Dex ID to Generation 1 species ID. + /// + /// National Dex ID. + /// Generation 1 species ID. public static int setG1Species(int dex_id) { int[] table = { 0x00, 0x99, 0x09, 0x9A, 0xB0, 0xB2, 0xB4, 0xB1, 0xB3, 0x1C, 0x7B, 0x7C, 0x7D, 0x70, 0x71, 0x72, 0x24, 0x96, 0x97, 0xA5, 0xA6, 0x05, 0x23, 0x6C, 0x2D, 0x54, 0x55, 0x60, 0x61, 0x0F, 0xA8, 0x10, 0x03, 0xA7, 0x07, 0x04, 0x8E, 0x52, 0x53, 0x64, 0x65, 0x6B, 0x82, 0xB9, 0xBA, 0xBB, 0x6D, 0x2E, 0x41, 0x77, 0x3B, 0x76, 0x4D, 0x90, 0x2F, 0x80, 0x39, 0x75, 0x21, 0x14, 0x47, 0x6E, 0x6F, 0x94, 0x26, 0x95, 0x6A, 0x29, 0x7E, 0xBC, 0xBD, 0xBE, 0x18, 0x9B, 0xA9, 0x27, 0x31, 0xA3, 0xA4, 0x25, 0x08, 0xAD, 0x36, 0x40, 0x46, 0x74, 0x3A, 0x78, 0x0D, 0x88, 0x17, 0x8B, 0x19, 0x93, 0x0E, 0x22, 0x30, 0x81, 0x4E, 0x8A, 0x06, 0x8D, 0x0C, 0x0A, 0x11, 0x91, 0x2B, 0x2C, 0x0B, 0x37, 0x8F, 0x12, 0x01, 0x28, 0x1E, 0x02, 0x5C, 0x5D, 0x9D, 0x9E, 0x1B, 0x98, 0x2A, 0x1A, 0x48, 0x35, 0x33, 0x1D, 0x3C, 0x85, 0x16, 0x13, 0x4C, 0x66, 0x69, 0x68, 0x67, 0xAA, 0x62, 0x63, 0x5A, 0x5B, 0xAB, 0x84, 0x4A, 0x4B, 0x49, 0x58, 0x59, 0x42, 0x83, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; return table[dex_id]; } + /// + /// Converts Generation 1 encoded data into a string. + /// + /// Encoded data. + /// Data source is Japanese. + /// Decoded string. public static string getG1Str(byte[] strdata, bool jp) { Dictionary dict = jp ? RBY2U_J : RBY2U_U; @@ -2426,6 +2562,12 @@ public static string getG1Str(byte[] strdata, bool jp) .Aggregate("", (current, cur) => current + cur); } + /// + /// Converts Generation 1 encoded data the same way Bank converts. + /// + /// Generation 1 encoded data. + /// Data source is Japanese. + /// Decoded string. public static string getG1ConvertedString(byte[] strdata, bool jp) { var us_table = new ushort[] { 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x0028, 0x0029, 0x003A, 0x003B, 0x0028, 0x0029, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x00C4, 0x00D6, 0x00DC, 0x00E4, 0x00F6, 0x00FC, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0050, 0x004D, 0x002D, 0x0020, 0x0020, 0x003F, 0x0021, 0x002D, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0xE08E, 0x0020, 0x0078, 0x002E, 0x002F, 0x002C, 0xE08F, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }; @@ -2434,6 +2576,12 @@ public static string getG1ConvertedString(byte[] strdata, bool jp) return Util.TrimFromZero(new string(strdata.Select(b => (char)table[b]).ToArray())); } + /// + /// Converts a string to Generation 1 encoded data. + /// + /// Decoded string. + /// Data destination is Japanese. + /// Encoded data. public static byte[] setG1Str(string str, bool jp) { Dictionary dict = jp ? U2RBY_J : U2RBY_U; @@ -2446,10 +2594,24 @@ public static byte[] setG1Str(string str, bool jp) .ToArray(); } + /// + /// Converts Big Endian encoded data to decoded string. + /// + /// Encoded data + /// Offset to read from + /// Length of data to read. + /// Decoded string. public static string getColoStr(byte[] data, int offset, int length) { return Util.TrimFromZero(Encoding.BigEndianUnicode.GetString(data, offset, length * 2)); } + + /// + /// Gets the bytes for a BigEndian string. + /// + /// + /// + /// public static byte[] setColoStr(string value, int length) { if (value.Length > length) @@ -2462,14 +2624,79 @@ public static byte[] setColoStr(string value, int length) return Encoding.BigEndianUnicode.GetBytes(TempNick); } - public static string[] getPKMExtensions() + /// + /// Gets an array of valid file extensions. + /// + /// Valid file extensions. + public static string[] getPKMExtensions(int MaxGeneration = Generation) { - const int gens = 7; var result = new List(); result.AddRange(new [] {"ck3", "xk3", "bk4"}); // Special Cases - for (int i = 1; i <= gens; i++) + for (int i = 1; i <= MaxGeneration; i++) result.Add("pk"+i); return result.ToArray(); } + + // Extensions + public static string getLocation(this PKM pk, bool eggmet) + { + if (pk.Format <= 2) + return ""; + + int locval = eggmet ? pk.Egg_Location : pk.Met_Location; + + if (pk.Format == 2) + return GameInfo.Strings.metGSC_00000[locval]; + if (pk.Format == 3) + return GameInfo.Strings.metRSEFRLG_00000[locval % 0x100]; + if (pk.Gen4 && (eggmet || pk.Format == 4)) + { + if (locval < 2000) return GameInfo.Strings.metHGSS_00000[locval]; + if (locval < 3000) return GameInfo.Strings.metHGSS_02000[locval % 2000]; + return GameInfo.Strings.metHGSS_03000[locval % 3000]; + } + if (pk.Gen5 || pk.Format <= 5) + { + if (locval < 30000) return GameInfo.Strings.metBW2_00000[locval]; + if (locval < 40000) return GameInfo.Strings.metBW2_30000[locval % 10000 - 1]; + if (locval < 60000) return GameInfo.Strings.metBW2_40000[locval % 10000 - 1]; + return GameInfo.Strings.metBW2_60000[locval % 10000 - 1]; + } + if (pk.Gen6 || pk.Format <= 6) + { + if (locval < 30000) return GameInfo.Strings.metXY_00000[locval]; + if (locval < 40000) return GameInfo.Strings.metXY_30000[locval % 10000 - 1]; + if (locval < 60000) return GameInfo.Strings.metXY_40000[locval % 10000 - 1]; + return GameInfo.Strings.metXY_60000[locval % 10000 - 1]; + } + if (pk.Gen7 || pk.Format <= 7) + { + if (locval < 30000) return GameInfo.Strings.metSM_00000[locval]; + if (locval < 40000) return GameInfo.Strings.metSM_30000[locval % 10000 - 1]; + if (locval < 60000) return GameInfo.Strings.metSM_40000[locval % 10000 - 1]; + return GameInfo.Strings.metSM_60000[locval % 10000 - 1]; + } + return null; // Shouldn't happen for gen 3+ + } + public static string[] getQRText(this PKM pkm) + { + var s = GameInfo.Strings; + // Summarize + string filename = pkm.Nickname; + if (pkm.Nickname != s.specieslist[pkm.Species] && s.specieslist[pkm.Species] != null) + filename += $" ({s.specieslist[pkm.Species]})"; + + string header = $"{filename} [{s.abilitylist[pkm.Ability]}] lv{pkm.Stat_Level} @ {s.itemlist[pkm.HeldItem]} -- {s.natures[pkm.Nature]}"; + string moves = string.Join(" / ", pkm.Moves.Select(move => move < s.movelist.Length ? s.movelist[move] : "ERROR")); + string IVs = $"IVs: {pkm.IV_HP:00}/{pkm.IV_ATK:00}/{pkm.IV_DEF:00}/{pkm.IV_SPA:00}/{pkm.IV_SPD:00}/{pkm.IV_SPE:00}"; + string EVs = $"EVs: {pkm.EV_HP:00}/{pkm.EV_ATK:00}/{pkm.EV_DEF:00}/{pkm.EV_SPA:00}/{pkm.EV_SPD:00}/{pkm.EV_SPE:00}"; + + return new[] + { + header, + moves, + IVs + " " + EVs, + }; + } } } diff --git a/PKHeX/PKM/XK3.cs b/PKHeX/PKM/XK3.cs index 9b4a470ad..60783adf9 100644 --- a/PKHeX/PKM/XK3.cs +++ b/PKHeX/PKM/XK3.cs @@ -30,7 +30,7 @@ public XK3(byte[] decryptedData = null, string ident = null) public override int Nature { get { return (int)(PID % 25); } set { } } public override int AltForm { get { return Species == 201 ? PKX.getUnownForm(PID) : 0; } set { } } - public override bool IsNicknamed { get { return PKX.getIsNicknamed(Species, Nickname); } set { } } + public override bool IsNicknamed { get { return PKX.getIsNicknamedAnyLanguage(Species, Nickname, Format); } set { } } public override int Gender { get { return PKX.getGender(Species, PID); } set { } } public override int Characteristic => -1; public override int CurrentFriendship { get { return OT_Friendship; } set { OT_Friendship = value; } }