Add more xmldoc

This commit is contained in:
Kurt 2023-03-31 13:00:34 -07:00
parent 3bfd302633
commit 4384cadefc
62 changed files with 682 additions and 85 deletions

View File

@ -7,6 +7,11 @@ namespace PKHeX.Core;
/// </summary>
public static class MoveSetApplicator
{
/// <summary>
/// Applies a new legal moveset to the <see cref="pk"/>, with option to apply random moves instead.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="random">True to apply a random moveset, false to apply a level-up moveset.</param>
public static void SetMoveset(this PKM pk, bool random = false)
{
Span<ushort> moves = stackalloc ushort[4];
@ -14,6 +19,11 @@ public static void SetMoveset(this PKM pk, bool random = false)
pk.SetMoves(moves);
}
/// <summary>
/// Applies the suggested Relearn Moves to the <see cref="pk"/>.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
/// <param name="la">Legality Analysis to use.</param>
public static void SetRelearnMoves(this PKM pk, LegalityAnalysis la)
{
Span<ushort> moves = stackalloc ushort[4];

View File

@ -8,6 +8,9 @@ namespace PKHeX.Core;
/// </summary>
public static class BatchFilters
{
/// <summary>
/// Filters to use for <see cref="BatchEditing"/> that are derived from the <see cref="PKM"/> data.
/// </summary>
public static readonly List<IComplexFilter> FilterMods = new()
{
new ComplexFilter(PROP_LEGAL,
@ -19,6 +22,9 @@ public static class BatchFilters
(info, cmd) => cmd.Comparer.IsCompareEquivalence(info.Entity.GetType().Name == cmd.PropertyValue)),
};
/// <summary>
/// Filters to use for <see cref="BatchEditing"/> that are derived from the <see cref="PKM"/> source.
/// </summary>
public static readonly List<IComplexFilterMeta> FilterMeta = new()
{
new MetaFilter(IdentifierContains,

View File

@ -38,6 +38,9 @@ public void SetScreenedValue(ReadOnlySpan<string> arr)
PropertyValue = index.ToString();
}
/// <summary>
/// Valid prefixes that are recognized for <see cref="InstructionComparer"/> value comparison types.
/// </summary>
public static ReadOnlySpan<char> Prefixes => new[] { Apply, FilterEqual, FilterNotEqual, FilterGreaterThan, FilterGreaterThanOrEqual, FilterLessThan, FilterLessThanOrEqual };
private const char Apply = '.';
private const char SplitRange = ',';
@ -61,7 +64,15 @@ public void SetScreenedValue(ReadOnlySpan<string> arr)
// Extra Functionality
private int RandomMinimum, RandomMaximum;
/// <summary>
/// Apply a <see cref="RandomValue"/> instead of fixed value, based on the <see cref="RandomMinimum"/> and <see cref="RandomMaximum"/> values.
/// </summary>
public bool Random { get; private set; }
/// <summary>
/// Gets a <see cref="Random"/> value, based on the <see cref="RandomMinimum"/> and <see cref="RandomMaximum"/> values.
/// </summary>
public int RandomValue => Util.Rand.Next(RandomMinimum, RandomMaximum + 1);
/// <summary>
@ -100,8 +111,14 @@ public void SetRandomRange(ReadOnlySpan<char> str)
}
}
/// <summary>
/// Gets a list of <see cref="StringInstruction"/>s from the input <see cref="text"/>.
/// </summary>
public static List<StringInstruction> GetFilters(ReadOnlySpan<char> text) => GetFilters(text.EnumerateLines());
/// <summary>
/// Gets a list of <see cref="StringInstruction"/> filters from the input <see cref="lines"/>.
/// </summary>
public static List<StringInstruction> GetFilters(ReadOnlySpan<string> lines)
{
var result = new List<StringInstruction>(lines.Length);
@ -113,6 +130,9 @@ public static List<StringInstruction> GetFilters(ReadOnlySpan<string> lines)
return result;
}
/// <summary>
/// Gets a list of <see cref="StringInstruction"/> filters from the input <see cref="lines"/>.
/// </summary>
public static List<StringInstruction> GetFilters(SpanLineEnumerator lines)
{
var result = new List<StringInstruction>();
@ -124,6 +144,9 @@ public static List<StringInstruction> GetFilters(SpanLineEnumerator lines)
return result;
}
/// <summary>
/// Gets a list of <see cref="StringInstruction"/> filters from the input <see cref="lines"/>.
/// </summary>
public static List<StringInstruction> GetFilters(IReadOnlyList<string> lines)
{
var result = new List<StringInstruction>(lines.Count);
@ -135,6 +158,9 @@ public static List<StringInstruction> GetFilters(IReadOnlyList<string> lines)
return result;
}
/// <summary>
/// Gets a list of <see cref="StringInstruction"/> filters from the input <see cref="lines"/>.
/// </summary>
public static List<StringInstruction> GetFilters(IEnumerable<string> lines)
{
var result = new List<StringInstruction>();
@ -146,8 +172,14 @@ public static List<StringInstruction> GetFilters(IEnumerable<string> lines)
return result;
}
/// <summary>
/// Gets a list of <see cref="StringInstruction"/> instructions from the input <see cref="text"/>.
/// </summary>
public static List<StringInstruction> GetInstructions(ReadOnlySpan<char> text) => GetInstructions(text.EnumerateLines());
/// <summary>
/// Gets a list of <see cref="StringInstruction"/> instructions from the input <see cref="lines"/>.
/// </summary>
public static List<StringInstruction> GetInstructions(ReadOnlySpan<string> lines)
{
var result = new List<StringInstruction>(lines.Length);
@ -159,6 +191,9 @@ public static List<StringInstruction> GetInstructions(ReadOnlySpan<string> lines
return result;
}
/// <summary>
/// Gets a list of <see cref="StringInstruction"/> instructions from the input <see cref="lines"/>.
/// </summary>
public static List<StringInstruction> GetInstructions(SpanLineEnumerator lines)
{
var result = new List<StringInstruction>();
@ -170,6 +205,9 @@ public static List<StringInstruction> GetInstructions(SpanLineEnumerator lines)
return result;
}
/// <summary>
/// Gets a list of <see cref="StringInstruction"/> instructions from the input <see cref="lines"/>.
/// </summary>
public static List<StringInstruction> GetInstructions(IReadOnlyList<string> lines)
{
var result = new List<StringInstruction>(lines.Count);
@ -181,6 +219,9 @@ public static List<StringInstruction> GetInstructions(IReadOnlyList<string> line
return result;
}
/// <summary>
/// Gets a list of <see cref="StringInstruction"/> instructions from the input <see cref="lines"/>.
/// </summary>
public static List<StringInstruction> GetInstructions(IEnumerable<string> lines)
{
var result = new List<StringInstruction>();
@ -192,6 +233,9 @@ public static List<StringInstruction> GetInstructions(IEnumerable<string> lines)
return result;
}
/// <summary>
/// Tries to parse a <see cref="StringInstruction"/> filter from the input <see cref="line"/>.
/// </summary>
public static bool TryParseFilter(ReadOnlySpan<char> line, [NotNullWhen(true)] out StringInstruction? entry)
{
entry = null;
@ -203,6 +247,9 @@ public static bool TryParseFilter(ReadOnlySpan<char> line, [NotNullWhen(true)] o
return TryParseSplitTuple(line[1..], ref entry, comparer);
}
/// <summary>
/// Tries to parse a <see cref="StringInstruction"/> instruction from the input <see cref="line"/>.
/// </summary>
public static bool TryParseInstruction(ReadOnlySpan<char> line, [NotNullWhen(true)] out StringInstruction? entry)
{
entry = null;
@ -211,6 +258,9 @@ public static bool TryParseInstruction(ReadOnlySpan<char> line, [NotNullWhen(tru
return TryParseSplitTuple(line[1..], ref entry);
}
/// <summary>
/// Tries to split a <see cref="StringInstruction"/> tuple from the input <see cref="tuple"/>.
/// </summary>
public static bool TryParseSplitTuple(ReadOnlySpan<char> tuple, [NotNullWhen(true)] ref StringInstruction? entry, InstructionComparer eval = default)
{
if (!TryParseSplitTuple(tuple, out var name, out var value))
@ -219,6 +269,9 @@ public static bool TryParseSplitTuple(ReadOnlySpan<char> tuple, [NotNullWhen(tru
return true;
}
/// <summary>
/// Tries to split a <see cref="StringInstruction"/> tuple from the input <see cref="tuple"/>.
/// </summary>
public static bool TryParseSplitTuple(ReadOnlySpan<char> tuple, out ReadOnlySpan<char> name, out ReadOnlySpan<char> value)
{
name = default;
@ -239,7 +292,12 @@ public static bool TryParseSplitTuple(ReadOnlySpan<char> tuple, out ReadOnlySpan
return true;
}
public static InstructionComparer GetComparer(char c) => c switch
/// <summary>
/// Gets the <see cref="InstructionComparer"/> from the input <see cref="opCode"/>.
/// </summary>
/// <param name="opCode"></param>
/// <returns></returns>
public static InstructionComparer GetComparer(char opCode) => opCode switch
{
FilterEqual => IsEqual,
FilterNotEqual => IsNotEqual,
@ -265,6 +323,9 @@ public enum InstructionComparer : byte
IsLessThanOrEqual,
}
/// <summary>
/// Extension methods for <see cref="InstructionComparer"/>
/// </summary>
public static class InstructionComparerExtensions
{
/// <summary>

View File

@ -9,10 +9,16 @@ namespace PKHeX.Core;
/// </summary>
public sealed class StringInstructionSet
{
/// <summary>
/// Filters to check if the object should be modified.
/// </summary>
public readonly IReadOnlyList<StringInstruction> Filters;
/// <summary>
/// Instructions to modify the object.
/// </summary>
public readonly IReadOnlyList<StringInstruction> Instructions;
private const string SetSeparator = ";";
private const char SetSeparatorChar = ';';
public StringInstructionSet(IReadOnlyList<StringInstruction> filters, IReadOnlyList<StringInstruction> instructions)
@ -58,6 +64,9 @@ public static bool HasEmptyLine(SpanLineEnumerator lines)
return false;
}
/// <summary>
/// Gets a list of <see cref="StringInstructionSet"/>s from the input <see cref="lines"/>.
/// </summary>
public static StringInstructionSet[] GetBatchSets(ReadOnlySpan<string> lines)
{
int ctr = 0;
@ -84,6 +93,9 @@ public static StringInstructionSet[] GetBatchSets(ReadOnlySpan<string> lines)
return result;
}
/// <summary>
/// Gets a list of <see cref="StringInstructionSet"/>s from the input <see cref="text"/>.
/// </summary>
public static StringInstructionSet[] GetBatchSets(ReadOnlySpan<char> text)
{
int ctr = 0;

View File

@ -10,6 +10,9 @@ internal static class BatchModifications
private static bool IsAll(ReadOnlySpan<char> p) => p.EndsWith("All", StringComparison.OrdinalIgnoreCase);
private static bool IsNone(ReadOnlySpan<char> p) => p.EndsWith("None", StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Sets a suggested legal moveset for the Entity.
/// </summary>
public static ModifyResult SetSuggestedMoveset(BatchInfo info, bool random = false)
{
Span<ushort> moves = stackalloc ushort[4];
@ -17,6 +20,9 @@ public static ModifyResult SetSuggestedMoveset(BatchInfo info, bool random = fal
return SetMoves(info.Entity, moves);
}
/// <summary>
/// Sets a suggested legal relearn moveset for the Entity.
/// </summary>
public static ModifyResult SetSuggestedRelearnData(BatchInfo info, ReadOnlySpan<char> propValue)
{
var pk = info.Entity;
@ -39,6 +45,10 @@ public static ModifyResult SetSuggestedRelearnData(BatchInfo info, ReadOnlySpan<
return ModifyResult.Modified;
}
/// <summary>
/// Sets all legal Move Mastery flag data for the Entity.
/// </summary>
/// <remarks>Only applicable for <see cref="IMoveShop8Mastery"/>.</remarks>
public static ModifyResult SetSuggestedMasteryData(BatchInfo info, ReadOnlySpan<char> propValue)
{
var pk = info.Entity;
@ -59,6 +69,10 @@ public static ModifyResult SetSuggestedMasteryData(BatchInfo info, ReadOnlySpan<
return ModifyResult.Modified;
}
/// <summary>
/// Sets suggested ribbon data for the Entity.
/// </summary>
/// <remarks>If None, removes all ribbons possible.</remarks>
public static ModifyResult SetSuggestedRibbons(BatchInfo info, ReadOnlySpan<char> value)
{
if (IsNone(value))
@ -68,6 +82,9 @@ public static ModifyResult SetSuggestedRibbons(BatchInfo info, ReadOnlySpan<char
return ModifyResult.Modified;
}
/// <summary>
/// Sets suggested met data for the Entity.
/// </summary>
public static ModifyResult SetSuggestedMetData(BatchInfo info)
{
var pk = info.Entity;
@ -86,6 +103,9 @@ public static ModifyResult SetSuggestedMetData(BatchInfo info)
return ModifyResult.Modified;
}
/// <summary>
/// Sets the lowest current level for the Entity.
/// </summary>
public static ModifyResult SetMinimumCurrentLevel(BatchInfo info)
{
var result = EncounterSuggestion.IterateMinimumCurrentLevel(info.Entity, info.Legal);

View File

@ -72,6 +72,12 @@ public static string GetMessage(DataMysteryGift mg)
return GetMessageBase64(data, server);
}
/// <summary>
/// Gets a QR Message from the input <see cref="byte"/> data.
/// </summary>
/// <param name="data">Data to include in the payload</param>
/// <param name="server">Website URL that sources the payload</param>
/// <returns>QR Message</returns>
public static string GetMessageBase64(ReadOnlySpan<byte> data, string server)
{
string payload = Convert.ToBase64String(data);

View File

@ -19,6 +19,12 @@ public static class BoxManipUtil
BoxManipDefaults.ModifyCommon,
};
/// <summary>
/// Manipulation Group Names to be used for uniquely naming groups of GUI controls.
/// </summary>
/// <remarks>
/// Order should match that of <see cref="ManipCategories"/>.
/// </remarks>
public static readonly string[] ManipCategoryNames =
{
"Delete",

View File

@ -23,6 +23,9 @@ public enum NamedEventType
Rebattle = 100,
}
/// <summary>
/// Utility logic methods for <see cref="NamedEventType"/>
/// </summary>
public static class NamedEventTypeUtil
{
public static NamedEventType GetEventType(ReadOnlySpan<char> s) => s.Length == 0 ? None : GetEventType(s[0]);

View File

@ -19,6 +19,9 @@ public enum EventWorkDiffCompatibility
FileMissing2,
}
/// <summary>
/// Extension methods and utility logic for <see cref="EventWorkDiffCompatibility"></see>.
/// </summary>
public static class EventWorkDiffCompatibilityExtensions
{
public static string GetMessage(this EventWorkDiffCompatibility value) => value switch

View File

@ -21,7 +21,7 @@ public static IReadOnlyList<PKM> GetAllPKM(this SaveFile sav)
public static PKM[] GetExtraPKM(this SaveFile sav) => sav.GetExtraPKM(sav.GetExtraSlots());
public static PKM[] GetExtraPKM(this SaveFile sav, IList<SlotInfoMisc> slots)
public static PKM[] GetExtraPKM(this SaveFile sav, IReadOnlyList<SlotInfoMisc> slots)
{
var arr = new PKM[slots.Count];
for (int i = 0; i < slots.Count; i++)

View File

@ -21,6 +21,9 @@ public enum SlotTouchType
External,
}
/// <summary>
/// Extension methods for <see cref="SlotTouchType"/>.
/// </summary>
public static class SlotTouchTypeUtil
{
/// <summary>

View File

@ -53,6 +53,9 @@ public enum Ball : byte
LAOrigin = 37,
}
/// <summary>
/// Extension methods for <see cref="Ball"/>.
/// </summary>
public static class BallExtensions
{
/// <summary>

View File

@ -25,6 +25,9 @@ public enum GCRegion : byte
PAL = 3,
}
/// <summary>
/// Extension methods for <see cref="GCVersion"/> and <see cref="GCRegion"/>.
/// </summary>
public static class GCVersionExtensions
{
/// <summary>

View File

@ -48,9 +48,14 @@ public enum LanguageGC : byte
UNUSED_6 = 7,
}
// Extension to remap LanguageGC to LanguageID
/// <summary>
/// Extension to convert between <see cref="LanguageGC"/> and <see cref="LanguageID"/>.
/// </summary>
public static class LanguageGCRemap
{
/// <summary>
/// Converts <see cref="LanguageGC"/> to <see cref="LanguageID"/>.
/// </summary>
public static LanguageID ToLanguageID(this LanguageGC lang) => lang switch
{
LanguageGC.Hacked => LanguageID.Hacked,
@ -63,6 +68,9 @@ public static class LanguageGCRemap
_ => LanguageID.English,
};
/// <summary>
/// Converts <see cref="LanguageID"/> to <see cref="LanguageGC"/>.
/// </summary>
public static LanguageGC ToLanguageGC(this LanguageID lang) => lang switch
{
LanguageID.Hacked => LanguageGC.Hacked,

View File

@ -26,6 +26,9 @@ public enum MoveType : sbyte
Fairy = 17,
}
/// <summary>
/// Extension methods for <see cref="MoveType"/>.
/// </summary>
public static class MoveTypeExtensions
{
public static MoveType GetMoveTypeGeneration(this MoveType type, int generation)

View File

@ -1,4 +1,4 @@
namespace PKHeX.Core;
namespace PKHeX.Core;
/// <summary>
/// Nature ID values for the corresponding English nature name.
@ -34,15 +34,29 @@ public enum Nature : byte
Random = 25,
}
/// <summary>
/// Extension methods for <see cref="Nature"/>.
/// </summary>
public static class NatureUtil
{
/// <summary>
/// Gets the <see cref="Nature"/> value that corresponds to the provided <see cref="value"/>.
/// </summary>
/// <remarks>Actual nature values will be unchanged; only out-of-bounds values re-map to <see cref="Nature.Random"/>.</remarks>
public static Nature GetNature(int value) => value switch
{
< 0 or >= (int)Nature.Random => Nature.Random,
_ => (Nature)value,
};
/// <summary>
/// Checks if the provided <see cref="value"/> is a valid stored <see cref="Nature"/> value.
/// </summary>
/// <returns>True if value is an actual nature.</returns>
public static bool IsFixed(this Nature value) => value is >= 0 and < Nature.Random;
/// <summary>
/// Checks if the provided <see cref="value"/> is a neutral nature which has no stat amps applied.
/// </summary>
public static bool IsNeutral(this Nature value) => value.IsFixed() && (byte)value % 6 == 0;
}

View File

@ -8,6 +8,9 @@ namespace PKHeX.Core;
/// </summary>
public sealed class GameDataSource
{
/// <summary>
/// List of <see cref="Region3DSIndex"/> values to display.
/// </summary>
public static readonly IReadOnlyList<ComboItem> Regions = new List<ComboItem>
{
new ("Japan (日本)", 0),
@ -18,6 +21,9 @@ public sealed class GameDataSource
new ("Taiwan (香港/台灣)", 6),
};
/// <summary>
/// List of <see cref="LanguageID"/> values to display.
/// </summary>
private static readonly List<ComboItem> LanguageList = new()
{
new ComboItem("JPN (日本語)", (int)LanguageID.Japanese),
@ -77,6 +83,10 @@ public GameDataSource(GameStrings s)
public readonly IReadOnlyList<ComboItem> HaXMoveDataSource;
public readonly IReadOnlyList<ComboItem> GroundTileDataSource;
/// <summary>
/// Preferentially ordered list of <see cref="GameVersion"/> values to display in a list.
/// </summary>
/// <remarks>Most recent games are at the top, loosely following Generation groups.</remarks>
private static ReadOnlySpan<byte> OrderedVersionArray => new byte[]
{
50, 51, // 9 sv
@ -103,7 +113,7 @@ public GameDataSource(GameStrings s)
00,
};
private static IReadOnlyList<ComboItem> GetBalls(string[] itemList) => Util.GetVariedCBListBall(itemList, BallStoredIndexes, BallItemIDs);
private static IReadOnlyList<ComboItem> GetBalls(ReadOnlySpan<string> itemList) => Util.GetVariedCBListBall(itemList, BallStoredIndexes, BallItemIDs);
// Since Poké Ball (and Great Ball / Ultra Ball) are most common, any list should have them at the top. The rest can be sorted alphabetically.
private static ReadOnlySpan<byte> BallStoredIndexes => new byte[] { 004, 003, 002, 001, 005, 006, 007, 008, 009, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 021, 022, 023, 024, 025, 026, 0027, 0028, 0029, 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037 };

View File

@ -1,4 +1,4 @@
using System;
using System;
namespace PKHeX.Core;
@ -35,15 +35,24 @@ public static int GetLanguageIndex(string lang)
/// </summary>
private static readonly string[] ptransp = { "ポケシフター", "Poké Transfer", "Poké Fret", "Pokétrasporto", "Poképorter", "Pokétransfer", "포케시프터", "宝可传送", "寶可傳送" };
public static string GetTransporterName(int index)
/// <summary>
/// Gets the Met Location display name for the Pokétransporter.
/// </summary>
/// <param name="language">Language Index from <see cref="LanguageCodes"/></param>
public static string GetTransporterName(int language)
{
if ((uint)index >= ptransp.Length)
index = 2;
return ptransp[index];
if ((uint)language >= ptransp.Length)
language = 2;
return ptransp[language];
}
/// <inheritdoc cref="GetTransporterName(int)"/>
/// <param name="lang">Language name from <see cref="LanguageCodes"/></param>
public static string GetTransporterName(string lang) => GetTransporterName(GetLanguageIndex(lang));
/// <summary>
/// Gets a list of strings for the specified language and file type.
/// </summary>
public static string[] GetStrings(string ident, string lang, string type = "text")
{
string[] data = Util.GetStringList(ident, lang, type);
@ -54,6 +63,9 @@ public static string[] GetStrings(string ident, string lang, string type = "text
}
}
/// <summary>
/// Program Languages supported; mirrors <see cref="GameLanguage.LanguageCodes"/>.
/// </summary>
public enum ProgramLanguage
{
/// <summary>

View File

@ -109,6 +109,9 @@ public static class Locations
public const ushort HOME_SWSHBDSPEgg = 65534; // -2 = 8bNone-1..
public const ushort Default8bNone = 65535;
/// <summary>
/// Gets the SW/SH-context <see cref="GameVersion"/> when an external entity from the input <see cref="ver"/> resides in SW/SH.
/// </summary>
public static int GetVersionSWSH(int ver) => (GameVersion)ver switch
{
GameVersion.PLA => (int)GameVersion.SW,
@ -117,6 +120,9 @@ public static class Locations
_ => ver,
};
/// <summary>
/// Gets the SW/SH-context Met Location when an external entity from the input <see cref="ver"/> resides in SW/SH.
/// </summary>
public static ushort GetMetSWSH(ushort loc, int ver) => (GameVersion)ver switch
{
GameVersion.PLA => HOME_SWLA,
@ -125,6 +131,10 @@ public static class Locations
_ => loc,
};
/// <summary>
/// Checks if the met location is a valid location for the input <see cref="ver"/>.
/// </summary>
/// <remarks>Relevant when a BD/SP entity is transferred to SW/SH.</remarks>
public static bool IsValidMetBDSP(ushort loc, int ver) => loc switch
{
HOME_SHSP when ver == (int)GameVersion.SH => true,
@ -132,16 +142,13 @@ public static class Locations
_ => false,
};
public static int TradedEggLocationNPC(int generation) => generation switch
{
1 => LinkTrade2NPC,
2 => LinkTrade2NPC,
3 => LinkTrade3NPC,
4 => LinkTrade4NPC,
5 => LinkTrade5NPC,
_ => LinkTrade6NPC,
};
/// <summary>
/// Gets the egg location value for a traded unhatched egg.
/// </summary>
/// <param name="generation">Generation of the egg</param>
/// <param name="ver">Game version of the egg</param>
/// <returns>Egg Location value</returns>
/// <remarks>Location will be set to the Met Location until it hatches, then moves to Egg Location.</remarks>
public static int TradedEggLocation(int generation, GameVersion ver) => generation switch
{
4 => LinkTrade4,

View File

@ -437,6 +437,9 @@ public enum AreaWeather8 : ushort
NotWeather = Shaking_Trees | Fishing,
}
/// <summary>
/// Extension methods for <see cref="AreaWeather8"/>.
/// </summary>
public static class AreaWeather8Extensions
{
public static bool IsMarkCompatible(this AreaWeather8 weather, IRibbonSetMark8 m)
@ -477,6 +480,9 @@ public enum AreaSlotType8 : byte
Inaccessible, // Shouldn't show up since these tables are not dumped.
}
/// <summary>
/// Extension methods for <see cref="AreaSlotType8"/>.
/// </summary>
public static class AreaSlotType8Extensions
{
public static bool CanCrossover(this AreaSlotType8 type) => type is not (HiddenMain or HiddenMain2 or OnlyFishing);

View File

@ -19,8 +19,14 @@ public sealed class BulkAnalysis
public readonly IBulkAnalysisSettings Settings;
private readonly bool[] CloneFlags;
/// <summary>
/// Checks if the <see cref="AllData"/> entity at <see cref="entryIndex"/> was previously marked as a clone of another index.
/// </summary>
public bool GetIsClone(int entryIndex) => CloneFlags[entryIndex];
/// <summary>
/// Marks the <see cref="AllData"/> entity at <see cref="entryIndex"/> as a clone of another index.
/// </summary>
public bool SetIsClone(int entryIndex, bool value = true) => CloneFlags[entryIndex] = value;
public BulkAnalysis(SaveFile sav, IBulkAnalysisSettings settings)
@ -49,6 +55,9 @@ private static bool IsEmptyData(SlotCache obj)
return false;
}
/// <summary>
/// Supported <see cref="IBulkAnalyzer"/> checkers that will be iterated through to check all entities.
/// </summary>
public static readonly List<IBulkAnalyzer> Analyzers = new()
{
new StandardCloneChecker(),
@ -67,6 +76,9 @@ private void ScanAll()
private static string GetSummary(SlotCache entry) => $"[{entry.Identify()}]";
/// <summary>
/// Adds a new entry to the <see cref="Parse"/> list.
/// </summary>
public void AddLine(SlotCache first, SlotCache second, string msg, CheckIdentifier i, Severity s = Severity.Invalid)
{
var c = $"{msg}{Environment.NewLine}{GetSummary(first)}{Environment.NewLine}{GetSummary(second)}{Environment.NewLine}";
@ -74,6 +86,9 @@ public void AddLine(SlotCache first, SlotCache second, string msg, CheckIdentifi
Parse.Add(chk);
}
/// <summary>
/// Adds a new entry to the <see cref="Parse"/> list.
/// </summary>
public void AddLine(SlotCache first, string msg, CheckIdentifier i, Severity s = Severity.Invalid)
{
var c = $"{msg}{Environment.NewLine}{GetSummary(first)}{Environment.NewLine}";

View File

@ -9,9 +9,13 @@ namespace PKHeX.Core;
/// </summary>
public static class BulkGenerator
{
/// <summary>
/// Gets a list of <see cref="PKM"/> data that are valid for the provided <see cref="sav"/>.
/// </summary>
public static List<PKM> GetLivingDex(this SaveFile sav)
{
var speciesToGenerate = GetAll(1, sav.MaxSpeciesID);
speciesToGenerate = speciesToGenerate.Where(sav.Personal.IsSpeciesInGame);
return GetLivingDex(sav, speciesToGenerate);
}

View File

@ -126,6 +126,11 @@ public static bool IsPPUpAvailable(PKM pk)
_ => true,
};
/// <summary>
/// Gets the maximum length of a Trainer Name for the input <see cref="generation"/> and <see cref="language"/>.
/// </summary>
/// <param name="generation">Generation of the Trainer</param>
/// <param name="language">Language of the Trainer</param>
public static int GetMaxLengthOT(int generation, LanguageID language) => language switch
{
LanguageID.ChineseS or LanguageID.ChineseT => 6,
@ -133,6 +138,11 @@ public static bool IsPPUpAvailable(PKM pk)
_ => generation >= 6 ? 12 : 7,
};
/// <summary>
/// Gets the maximum length of a Nickname for the input <see cref="generation"/> and <see cref="language"/>.
/// </summary>
/// <param name="generation">Generation of the Trainer</param>
/// <param name="language">Language of the Trainer</param>
public static int GetMaxLengthNickname(int generation, LanguageID language) => language switch
{
LanguageID.ChineseS or LanguageID.ChineseT => 6,
@ -140,6 +150,9 @@ public static bool IsPPUpAvailable(PKM pk)
_ => generation >= 6 ? 12 : 10,
};
/// <summary>
/// Checks if the input <see cref="pk"/> has IVs that match the template <see cref="IVs"/>.
/// </summary>
public static bool GetIsFixedIVSequenceValidSkipRand(ReadOnlySpan<int> IVs, PKM pk, uint max = 31)
{
for (int i = 0; i < 6; i++)
@ -152,6 +165,9 @@ public static bool GetIsFixedIVSequenceValidSkipRand(ReadOnlySpan<int> IVs, PKM
return true;
}
/// <summary>
/// Checks if the input <see cref="pk"/> has IVs that match the template <see cref="IVs"/>.
/// </summary>
public static bool GetIsFixedIVSequenceValidSkipRand(IndividualValueSet IVs, PKM pk, int max = 31)
{
// Template IVs not in the [0,max] range are random. Only check for IVs within the "specified" range.
@ -164,6 +180,9 @@ public static bool GetIsFixedIVSequenceValidSkipRand(IndividualValueSet IVs, PKM
return true;
}
/// <summary>
/// Checks if the input <see cref="pk"/> has IVs that match the template <see cref="IVs"/>.
/// </summary>
public static bool GetIsFixedIVSequenceValidNoRand(IndividualValueSet IVs, PKM pk)
{
if (IVs.HP != pk.IV_HP ) return false;

View File

@ -27,6 +27,9 @@ public enum AreaWeather9 : ushort
Inside = Normal | Overcast,
}
/// <summary>
/// Extension methods for <see cref="AreaWeather9"/>
/// </summary>
public static class AreaWeather9Extensions
{
public static bool IsMarkCompatible(this AreaWeather9 weather, RibbonIndex m) => m switch

View File

@ -43,6 +43,9 @@ public enum PogoType : byte
Shadow = 40,
}
/// <summary>
/// Extension methods for <see cref="PogoType"/>.
/// </summary>
public static class PogoTypeExtensions
{
/// <summary>

View File

@ -13,13 +13,10 @@ public interface IGroundTypeTile
/// Tile Type the <see cref="IEncounterTemplate"/> was obtained on.
/// </summary>
GroundTileAllowed GroundTile { get; }
}
public static class GroundTypeTileExtensions
{
/// <summary>
/// Gets if the resulting <see cref="PKM"/> will still have a value depending on the current <see cref="format"/>.
/// </summary>
/// <remarks>Generation 7 no longer stores this value.</remarks>
public static bool HasGroundTile(this IGroundTypeTile _, int format) => format is (4 or 5 or 6);
bool HasGroundTile(int format) => format is (4 or 5 or 6);
}

View File

@ -196,7 +196,7 @@ private static EncounterMight9 ReadEncounter(ReadOnlySpan<byte> data) => new()
RandRate3TotalViolet = ReadUInt16LittleEndian(data[(WeightStart + (sizeof(ushort) * 15))..]),
Nature = (Nature)data[0x34],
IVs = new IndividualValueSet((sbyte)data[0x35], (sbyte)data[0x36], (sbyte)data[0x37], (sbyte)data[0x38], (sbyte)data[0x39], (sbyte)data[0x3A], data[0x3B]),
IVs = new IndividualValueSet((sbyte)data[0x35], (sbyte)data[0x36], (sbyte)data[0x37], (sbyte)data[0x38], (sbyte)data[0x39], (sbyte)data[0x3A], (IndividualValueSetType)data[0x3B]),
ScaleType = (SizeType9)data[0x3C],
Scale = data[0x3D],
};

View File

@ -37,8 +37,15 @@ public enum GemType : sbyte
Fairy = 19,
}
/// <summary>
/// Extension methods for <see cref="GemType"/>.
/// </summary>
public static class GemTypeExtensions
{
/// <summary>
/// Gets the <see cref="expect"/> type that corresponds to the input <see cref="type"/>.
/// </summary>
/// <returns>False if no specific value is expected.</returns>
public static bool IsSpecified(this GemType type, out byte expect)
{
if (type is GemType.Default or GemType.Random)

View File

@ -3,19 +3,46 @@
namespace PKHeX.Core;
public enum SizeType9
/// <summary>
/// Generation 9 Size Type used by encounters to force a specific size range or value.
/// </summary>
public enum SizeType9 : byte
{
/// <summary> Size value is randomly distributed. </summary>
RANDOM = 0,
/// <summary> Size value is very small. </summary>
XS = 1,
/// <summary> Size value is small. </summary>
S = 2,
/// <summary> Size value is average. </summary>
M = 3,
/// <summary> Size value is large. </summary>
L = 4,
/// <summary> Size value is very large. </summary>
XL = 5,
/// <summary> Size value is a specific value. </summary>
VALUE = 6,
}
/// <summary>
/// Extension methods for <see cref="SizeType9"/>.
/// </summary>
public static class SizeType9Extensions
{
/// <summary>
/// Gets a random size value for the specified <see cref="SizeType9"/>.
/// </summary>
/// <param name="type">Size Type</param>
/// <param name="value">Value if <see cref="SizeType9.VALUE"/>, unused otherwise.</param>
/// <param name="rand">RNG to generate value with.</param>
/// <returns>Size Value</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static byte GetSizeValue(this SizeType9 type, byte value, ref Xoroshiro128Plus rand) => type switch
{
RANDOM => (byte)(rand.NextInt(0x81) + rand.NextInt(0x80)),

View File

@ -56,6 +56,9 @@ protected override bool IsMatchNatureGenderShiny(PKM pk)
public static bool IsValidMissingLanguage(PKM pk)
{
// Generation 5 trades from B/W forgot to set the Language ID, so it remains as 0.
// This value is fixed when it is transferred from PK5->PK6
// B2/W2 is unaffected by this game data bug.
return pk is { Context: EntityContext.Gen5, BW: true };
}
}

View File

@ -3,6 +3,9 @@
namespace PKHeX.Core;
/// <summary>
/// <see cref="PKM.Ability"/> legality permissions.
/// </summary>
public enum AbilityPermission : sbyte
{
Any12H = -1,
@ -12,6 +15,9 @@ public enum AbilityPermission : sbyte
OnlyHidden = 4,
}
/// <summary>
/// Extension methods for <see cref="AbilityPermission"/>.
/// </summary>
public static class AbilityPermissionExtensions
{
public static byte GetSingleValue(this AbilityPermission value) => value switch

View File

@ -1,7 +1,15 @@
namespace PKHeX.Core;
/// <summary>
/// Utility logic for checking encounter state.
/// </summary>
public static class EncounterStateUtil
{
/// <summary>
/// Checks if the input <see cref="pk"/> could have been a wild encounter.
/// </summary>
/// <param name="pk">Pokémon to check.</param>
/// <returns>True if the <see cref="pk"/> could have been a wild encounter, false otherwise.</returns>
public static bool CanBeWildEncounter(PKM pk)
{
if (pk.IsEgg)
@ -11,8 +19,17 @@ public static bool CanBeWildEncounter(PKM pk)
return true;
}
/// <summary>
/// Checks if the input <see cref="pk"/> was met as an egg.
/// </summary>
/// <param name="pk">Pokémon to check.</param>
/// <returns>True if the <see cref="pk"/> was met as an egg, false otherwise.</returns>
/// <remarks>Only applicable for Generation 4 origins and above.</remarks>
public static bool IsMetAsEgg(PKM pk) => pk switch
{
// This all could be simplified to just checking Egg_Day != 0 without type checks.
// Leaving like this to indicate how Egg_Location is not a true indicator due to quirks from BD/SP.
PA8 or PK8 => pk.Egg_Location is not 0 || pk is { BDSP: true, Egg_Day: not 0 },
PB8 pb8 => pb8.Egg_Location is not Locations.Default8bNone,
_ => pk.Egg_Location is not 0,

View File

@ -4,6 +4,9 @@
namespace PKHeX.Core;
/// <summary>
/// Verifies encounter data to check if the encounter really matches the <see cref="PKM"/>.
/// </summary>
public static class EncounterVerifier
{
/// <summary>

View File

@ -32,6 +32,9 @@ public enum MysteryGiftRestriction
OTReplacedOnTrade = RegTW << 1,
}
/// <summary>
/// Extension methods for <see cref="MysteryGiftRestriction"/>.
/// </summary>
public static class MysteryGiftRestrictionExtensions
{
/// <summary>
@ -49,6 +52,11 @@ public static int GetSuggestedLanguage(this MysteryGiftRestriction value)
return -1;
}
/// <summary>
/// Finds the lowest index of a region that can receive the gift.
/// </summary>
/// <param name="value">Flag value</param>
/// <returns>Region ID; -1 if none</returns>
public static int GetSuggestedRegion(this MysteryGiftRestriction value)
{
for (int i = (int)Region3DSIndex.Japan; i <= (int)Region3DSIndex.Taiwan; i++)

View File

@ -44,14 +44,23 @@ public enum GroundTileAllowed
Max_Pt = 1 << 24, // Unspecific, catch-all for Pt undefined tiles.
}
/// <summary>
/// Extension methods for <see cref="GroundTileAllowed"/>.
/// </summary>
public static class GroundTileAllowedExtensions
{
public static bool Contains(this GroundTileAllowed g1, GroundTileType g2) => (g1 & (GroundTileAllowed)(1 << (int)g2)) != 0;
/// <summary>
/// Checks if the <see cref="GroundTileAllowed"/> value is a valid tile type.
/// </summary>
/// <param name="permit">Tile bit-permission value</param>
/// <param name="value">Tile type to check.</param>
/// <returns></returns>
public static bool Contains(this GroundTileAllowed permit, GroundTileType value) => (permit & (GroundTileAllowed)(1 << (int)value)) != 0;
/// <summary>
/// Grabs the highest set bit from the tile value.
/// </summary>
/// <param name="g">Tile bit-permission value</param>
/// <param name="permit">Tile bit-permission value</param>
/// <returns>Bit index</returns>
public static GroundTileType GetIndex(this GroundTileAllowed g) => (GroundTileType)System.Numerics.BitOperations.Log2((uint)g);
public static GroundTileType GetIndex(this GroundTileAllowed permit) => (GroundTileType)System.Numerics.BitOperations.Log2((uint)permit);
}

View File

@ -3,10 +3,19 @@
namespace PKHeX.Core;
/// <summary>
/// Utility logic for getting an <see cref="IEvolutionGroup"/> based on the input.
/// </summary>
public static class EvolutionGroupUtil
{
/// <summary>
/// Gets the <see cref="IEvolutionGroup"/> for the <see cref="pk"/>.
/// </summary>
public static IEvolutionGroup GetCurrentGroup(PKM pk) => GetCurrentGroup(pk.Context);
/// <summary>
/// Gets the <see cref="IEvolutionGroup"/> for the <see cref="EntityContext"/>.
/// </summary>
public static IEvolutionGroup GetCurrentGroup(EntityContext context) => context switch
{
Gen1 => EvolutionGroup1.Instance,

View File

@ -6,6 +6,7 @@ namespace PKHeX.Core;
/// <summary>
/// Describes how an evolution can be triggered.
/// </summary>
/// <remarks>This ordering matches the mainline enumeration.</remarks>
public enum EvolutionType : byte
{
None = 0,
@ -79,10 +80,24 @@ public enum EvolutionType : byte
UseMoveStrongStyle = 92, // Overqwil
}
/// <summary>
/// Extension methods for <see cref="EvolutionType"/>.
/// </summary>
public static class EvolutionTypeExtensions
{
/// <summary>
/// Checks if the <see cref="EvolutionType"/> is a <see cref="Trade"/> evolution.
/// </summary>
/// <param name="t">Evolution Type</param>
/// <returns>True if the evolution is a trade evolution.</returns>
public static bool IsTrade(this EvolutionType t) => t is Trade or TradeHeldItem or TradeShelmetKarrablast;
/// <summary>
/// Checks if the <see cref="EvolutionType"/> is a <see cref="LevelUp"/> evolution.
/// </summary>
/// <param name="type">Evolution Type</param>
/// <returns>True if the evolution is a level up evolution.</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static bool IsLevelUpRequired(this EvolutionType type) => type switch
{
None => false,

View File

@ -21,6 +21,9 @@ public enum LearnEnvironment : byte
/* Gen9 */ SV,
}
/// <summary>
/// Extension methods for <see cref="LearnEnvironment"/>.
/// </summary>
public static class LearnEnvironmentExtensions
{
public static bool IsSpecified(this LearnEnvironment value) => value is not None;

View File

@ -34,10 +34,36 @@ public enum LearnMethod : byte
SpecialEgg,
}
/// <summary>
/// Extension methods for <see cref="LearnMethod"/>.
/// </summary>
public static class LearnMethodExtensions
{
/// <summary>
/// Checks if the <see cref="LearnMethod"/> is a valid method of learning a move.
/// </summary>
/// <param name="method">Method to check</param>
/// <returns>True if the method is valid, false otherwise.</returns>
public static bool IsValid(this LearnMethod method) => method >= Empty;
/// <summary>
/// CHecks if the <see cref="LearnMethod"/> is expecting another move instead.
/// </summary>
/// <param name="method">Method to check</param>
/// <returns>True if the method is valid, false otherwise.</returns>
public static bool HasExpectedMove(this LearnMethod method) => method is UnobtainableExpect;
/// <summary>
/// Checks if the <see cref="LearnMethod"/> is valid because of it being a Relearn move.
/// </summary>
/// <param name="method">Method to check</param>
/// <returns>True if the method is valid, false otherwise.</returns>
public static bool IsRelearn(this LearnMethod method) => method is Relearn;
/// <summary>
/// Checks if the <see cref="LearnMethod"/> is valid because of it being an egg move.
/// </summary>
/// <param name="method">Method to check</param>
/// <returns>True if the method is valid, false otherwise.</returns>
public static bool IsEggSource(this LearnMethod method) => method is EggMove or InheritLevelUp or SpecialEgg;
}

View File

@ -2,6 +2,9 @@
namespace PKHeX.Core;
/// <summary>
/// Indicates the source of a <see cref="Move"/> for a <see cref="PKM"/>.
/// </summary>
[Flags]
public enum MoveSourceType
{
@ -24,7 +27,15 @@ public enum MoveSourceType
All = ExternalSources | SharedEggMove | RelearnMoves,
}
/// <summary>
/// Extensions for <see cref="MoveSourceType"/>.
/// </summary>
public static class MoveSourceTypeExtensions
{
/// <summary>
/// Masks out the flags to only leave those that are possible for eggs.
/// </summary>
/// <param name="value">Flags to mask.</param>
/// <returns>Masked flags.</returns>
public static MoveSourceType ClearNonEggSources(this MoveSourceType value) => value & MoveSourceType.Encounter;
}

View File

@ -109,7 +109,7 @@ public static string GetSourceString(Array parse, int generation, int index)
};
}
public static string GetSourceString(this EggSource2 source) => source switch
private static string GetSourceString(this EggSource2 source) => source switch
{
EggSource2.Base => LMoveRelearnEgg,
EggSource2.FatherEgg => LMoveEggInherited,
@ -120,7 +120,7 @@ public static string GetSourceString(Array parse, int generation, int index)
_ => LMoveEggInvalid,
};
public static string GetSourceString(this EggSource34 source) => source switch
private static string GetSourceString(this EggSource34 source) => source switch
{
EggSource34.Base => LMoveRelearnEgg,
EggSource34.FatherEgg => LMoveEggInherited,
@ -131,7 +131,7 @@ public static string GetSourceString(Array parse, int generation, int index)
_ => LMoveEggInvalid,
};
public static string GetSourceString(this EggSource5 source) => source switch
private static string GetSourceString(this EggSource5 source) => source switch
{
EggSource5.Base => LMoveRelearnEgg,
EggSource5.FatherEgg => LMoveEggInherited,
@ -142,7 +142,7 @@ public static string GetSourceString(Array parse, int generation, int index)
_ => LMoveEggInvalid,
};
public static string GetSourceString(this EggSource6 source) => source switch
private static string GetSourceString(this EggSource6 source) => source switch
{
EggSource6.Base => LMoveRelearnEgg,
EggSource6.ParentLevelUp => LMoveEggLevelUp,
@ -164,7 +164,7 @@ public static string GetSourceString(Array parse, int generation, int index)
_ => None,
};
public static LearnMethod GetSource(this EggSource2 source) => source switch
private static LearnMethod GetSource(this EggSource2 source) => source switch
{
EggSource2.Base => Initial,
EggSource2.FatherEgg => EggMove,
@ -174,7 +174,7 @@ public static string GetSourceString(Array parse, int generation, int index)
_ => None,
};
public static LearnMethod GetSource(this EggSource34 source) => source switch
private static LearnMethod GetSource(this EggSource34 source) => source switch
{
EggSource34.Base => Initial,
EggSource34.FatherEgg => EggMove,
@ -184,7 +184,7 @@ public static string GetSourceString(Array parse, int generation, int index)
_ => None,
};
public static LearnMethod GetSource(this EggSource5 source) => source switch
private static LearnMethod GetSource(this EggSource5 source) => source switch
{
EggSource5.Base => Initial,
EggSource5.FatherEgg => EggMove,
@ -194,7 +194,7 @@ public static string GetSourceString(Array parse, int generation, int index)
_ => None,
};
public static LearnMethod GetSource(this EggSource6 source) => source switch
private static LearnMethod GetSource(this EggSource6 source) => source switch
{
EggSource6.Base => Initial,
EggSource6.ParentLevelUp => InheritLevelUp,

View File

@ -5,9 +5,15 @@
namespace PKHeX.Core;
/// <summary>
/// Shared logic for interacting with <see cref="EggMoves"/> data sources.
/// </summary>
public static class MoveEgg
{
public static ushort[] GetEggMoves(ushort species, byte form, GameVersion version, int generation)
/// <summary>
/// Gets the <see cref="EggMoves"/> data for the <see cref="version"/> and <see cref="species"/>.
/// </summary>
public static ReadOnlySpan<ushort> GetEggMoves(ushort species, byte form, GameVersion version, int generation)
{
if (!Breeding.CanGameGenerateEggs(version))
return Array.Empty<ushort>();
@ -15,7 +21,11 @@ public static ushort[] GetEggMoves(ushort species, byte form, GameVersion versio
return GetEggMoves(generation, species, form, version);
}
public static ushort[] GetEggMoves(int generation, ushort species, byte form, GameVersion version) => generation switch
/// <summary>
/// Gets the <see cref="EggMoves"/> data for the <see cref="version"/> and <see cref="species"/>.
/// </summary>
/// <remarks>Only use this if you're sure the game can generate eggs.</remarks>
public static ReadOnlySpan<ushort> GetEggMoves(int generation, ushort species, byte form, GameVersion version) => generation switch
{
1 or 2 => GetMovesSafe(version == C ? EggMovesC : EggMovesGS, species),
3 => GetMovesSafe(EggMovesRS, species),

View File

@ -3,8 +3,15 @@
namespace PKHeX.Core;
/// <summary>
/// Logic for Generation 9 Encounter RNG.
/// </summary>
public static class Encounter9RNG
{
/// <summary>
/// Sets the <see cref="pk"/> with random data based on the <see cref="enc"/> and <see cref="criteria"/>.
/// </summary>
/// <returns>True if the generated data matches the <see cref="criteria"/>.</returns>
public static bool TryApply32<TEnc>(this TEnc enc, PK9 pk, in ulong init, in GenerateParam9 param, EncounterCriteria criteria)
where TEnc : IEncounterTemplate, ITeraRaid9
{
@ -171,6 +178,9 @@ public static bool IsMatch(PKM pk, in GenerateParam9 enc, in ulong seed)
if (pk.IV_SPE != ivs[5])
return false;
// Ability can be changed by Capsule/Patch.
// Defer this check to later.
// ReSharper disable once UnusedVariable
int abil = enc.Ability switch
{
AbilityPermission.Any12H => (int)rand.NextInt(3) << 1,

View File

@ -2,6 +2,9 @@
namespace PKHeX.Core;
/// <summary>
/// RNG Correlation Logic for <see cref="ITeraRaid9"/> encounters.
/// </summary>
public static class Tera9RNG
{
private const uint TeraTypeCount = 18;
@ -154,7 +157,7 @@ public static bool IsMatchStarChoice(in uint seed, in byte stars, in byte raidRa
/// </summary>
/// <param name="pk">Entity to check for</param>
/// <returns>Seed</returns>
/// <see cref="Overworld8RNG.GetOriginalSeed"/>
/// <remarks>Refer to <see cref="Overworld8RNG.GetOriginalSeed"/> for similar implementation.</remarks>
public static uint GetOriginalSeed(PKM pk)
{
// Same RNG goof as SW/SH, the seed->PKM algorithm generates the EC first. Difference: has FakeTID roll between.

View File

@ -2,6 +2,9 @@
namespace PKHeX.Core;
/// <summary>
/// Logic for <see cref="Species.Toxtricity"></see> forms.
/// </summary>
public static class ToxtricityUtil
{
private static ReadOnlySpan<byte> Nature0 => new byte[] { 3, 4, 2, 8, 9, 19, 22, 11, 13, 14, 0, 6, 24 };

View File

@ -4,6 +4,8 @@
using static PKHeX.Core.Legal;
using static PKHeX.Core.GameVersion;
using static PKHeX.Core.Species;
using static PKHeX.Core.PotentialGBOrigin;
using static PKHeX.Core.TimeCapsuleEvaluation;
namespace PKHeX.Core;
@ -129,12 +131,12 @@ internal static PotentialGBOrigin GetTradebackStatusInitial(PKM pk)
return GetTradebackStatusRBY(pk1);
if (pk.Format == 2 || pk.VC2) // Check for impossible tradeback scenarios
return !pk.CanInhabitGen1() ? PotentialGBOrigin.Gen2Only : PotentialGBOrigin.Either;
return !pk.CanInhabitGen1() ? Gen2Only : Either;
// VC2 is released, we can assume it will be TradebackType.Any.
// Is impossible to differentiate a VC1 pokemon traded to Gen7 after VC2 is available.
// Met Date cannot be used definitively as the player can change their system clock.
return PotentialGBOrigin.Either;
return Either;
}
/// <summary>
@ -144,21 +146,21 @@ internal static PotentialGBOrigin GetTradebackStatusInitial(PKM pk)
private static PotentialGBOrigin GetTradebackStatusRBY(PK1 pk)
{
if (!ParseSettings.AllowGen1Tradeback)
return PotentialGBOrigin.Gen1Only;
return Gen1Only;
// Detect tradeback status by comparing the catch rate(Gen1)/held item(Gen2) to the species in the pk's evolution chain.
var catch_rate = pk.Catch_Rate;
if (catch_rate == 0)
return PotentialGBOrigin.Either;
return Either;
bool matchAny = GetCatchRateMatchesPreEvolution(pk, catch_rate);
if (!matchAny)
return PotentialGBOrigin.Either;
return Either;
if (IsTradebackCatchRate(catch_rate))
return PotentialGBOrigin.Either;
return Either;
return PotentialGBOrigin.Gen1Only;
return Gen1Only;
}
public static TimeCapsuleEvaluation IsTimeCapsuleTransferred(PKM pk, ReadOnlySpan<MoveResult> moves, IEncounterTemplate enc)
@ -168,43 +170,43 @@ public static TimeCapsuleEvaluation IsTimeCapsuleTransferred(PKM pk, ReadOnlySpa
if (z.Generation == enc.Generation || z.Generation > 2)
continue;
if (pk is PK1 {Catch_Rate: not 0} g1 && !IsTradebackCatchRate(g1.Catch_Rate))
return TimeCapsuleEvaluation.BadCatchRate;
return enc.Generation == 2 ? TimeCapsuleEvaluation.Transferred21 : TimeCapsuleEvaluation.Transferred12;
return BadCatchRate;
return enc.Generation == 2 ? Transferred21 : Transferred12;
}
if (pk is not GBPKM gb)
{
return enc.Generation switch
{
2 when pk.VC2 => TimeCapsuleEvaluation.Transferred21,
1 when pk.VC1 => TimeCapsuleEvaluation.Transferred12,
_ => TimeCapsuleEvaluation.NotTransferred,
2 when pk.VC2 => Transferred21,
1 when pk.VC1 => Transferred12,
_ => NotTransferred,
};
}
if (gb is ICaughtData2 pk2)
{
if (enc.Generation == 1)
return TimeCapsuleEvaluation.Transferred12;
return Transferred12;
if (pk2.CaughtData != 0)
return TimeCapsuleEvaluation.NotTransferred;
return NotTransferred;
if (enc.Version == C)
return TimeCapsuleEvaluation.Transferred21;
return TimeCapsuleEvaluation.Indeterminate;
return Transferred21;
return Indeterminate;
}
if (gb is PK1 pk1)
{
var rate = pk1.Catch_Rate;
if (rate == 0)
return TimeCapsuleEvaluation.Transferred12;
return Transferred12;
bool isTradebackItem = IsTradebackCatchRate(rate);
if (IsCatchRateMatchEncounter(enc, pk1))
return isTradebackItem ? TimeCapsuleEvaluation.Indeterminate : TimeCapsuleEvaluation.NotTransferred;
return isTradebackItem ? TimeCapsuleEvaluation.Transferred12 : TimeCapsuleEvaluation.BadCatchRate;
return isTradebackItem ? Indeterminate : NotTransferred;
return isTradebackItem ? Transferred12 : BadCatchRate;
}
return TimeCapsuleEvaluation.Indeterminate;
return Indeterminate;
}
private static bool IsCatchRateMatchEncounter(IEncounterTemplate enc, PK1 pk1) => enc switch
@ -217,10 +219,24 @@ public static TimeCapsuleEvaluation IsTimeCapsuleTransferred(PKM pk, ReadOnlySpa
public static bool IsTradebackCatchRate(byte rate) => Array.IndexOf(HeldItems_GSC, rate) != -1;
}
/// <summary>
/// Guess of the origin of a GB Pokémon.
/// </summary>
public enum PotentialGBOrigin
{
/// <summary>
/// Pokémon is possible from either generation.
/// </summary>
Either,
/// <summary>
/// Pokémon is only possible in Generation 1.
/// </summary>
Gen1Only,
/// <summary>
/// Pokémon is only possible in Generation 2.
/// </summary>
Gen2Only,
}
@ -255,10 +271,13 @@ public enum TimeCapsuleEvaluation
BadCatchRate,
}
/// <summary>
/// Extension methods for <see cref="TimeCapsuleEvaluation"/>.
/// </summary>
public static class TimeCapsuleEvlautationExtensions
{
/// <summary>
/// Indicates if the <see cref="eval"/> definitely transferred via Time Capsule.
/// </summary>
public static bool WasTimeCapsuleTransferred(this TimeCapsuleEvaluation eval) => eval is not (TimeCapsuleEvaluation.Indeterminate or TimeCapsuleEvaluation.NotTransferred or TimeCapsuleEvaluation.BadCatchRate);
public static bool WasTimeCapsuleTransferred(this TimeCapsuleEvaluation eval) => eval is not (Indeterminate or NotTransferred or BadCatchRate);
}

View File

@ -1,16 +1,44 @@
namespace PKHeX.Core;
/// <summary>
/// Lumped image type.
/// </summary>
public enum HeldItemLumpImage
{
NotLump,
/// <summary>
/// Held Item spriite is a specific held item.
/// </summary>
NotLump = 0,
/// <summary>
/// Held Item sprite should show the Technical Machine (TM) icon.
/// </summary>
TechnicalMachine,
/// <summary>
/// Held Item sprite should show the Technical Record (TR) icon.
/// </summary>
TechnicalRecord,
}
/// <summary>
/// Logic to check if a held item should how a lumped image sprite.
/// </summary>
public static class HeldItemLumpUtil
{
/// <summary>
/// Checks if the <see cref="image"/> is a lumped sprite.
/// </summary>
/// <param name="image">Evaluated type</param>
/// <returns>True if the <see cref="image"/> is a lumped sprite.</returns>
public static bool IsLump(this HeldItemLumpImage image) => image != HeldItemLumpImage.NotLump;
/// <summary>
/// Checks if the <see cref="item"/> should show a lumped sprite.
/// </summary>
/// <param name="item">Held Item index</param>
/// <param name="context">Generation context</param>
/// <returns>Evaluation result.</returns>
public static HeldItemLumpImage GetIsLump(int item, EntityContext context) => context.Generation() switch
{
<= 4 when item is (>= 0328 and <= 0419) => HeldItemLumpImage.TechnicalMachine, // gen2/3/4 TM

View File

@ -14,8 +14,16 @@ public interface ITrainerInfo : ITrainerID32
EntityContext Context { get; }
}
/// <summary>
/// Extension methods for <see cref="ITrainerInfo"/>.
/// </summary>
public static class TrainerInfoExtensions
{
/// <summary>
/// Copies the <see cref="ITrainerInfo"/> data to the <see cref="PKM"/> object.
/// </summary>
/// <param name="info">Trainer Information</param>
/// <param name="pk">Pokémon to copy to</param>
public static void ApplyTo(this ITrainerInfo info, PKM pk)
{
pk.OT_Name = info.OT;
@ -35,6 +43,12 @@ public static void ApplyTo(this ITrainerInfo info, PKM pk)
tr.ConsoleRegion = o.ConsoleRegion;
}
/// <summary>
/// Copies the <see cref="ITrainerInfo"/> data to the <see cref="PKM"/> object's Handling Trainer data.
/// </summary>
/// <param name="sav">Trainer Information</param>
/// <param name="pk">Pokémon to copy to</param>
/// <param name="force">If true, will overwrite the Handling Trainer Data even if it has not been traded.</param>
public static void ApplyHandlingTrainerInfo(this ITrainerInfo sav, PKM pk, bool force = false)
{
if (pk.Format == sav.Generation && !force)
@ -57,6 +71,12 @@ public static void ApplyHandlingTrainerInfo(this ITrainerInfo sav, PKM pk, bool
}
}
/// <summary>
/// Checks if the <see cref="ITrainerInfo"/> data matches the <see cref="PKM"/> object's Original Trainer data.
/// </summary>
/// <param name="tr">Trainer Information</param>
/// <param name="pk">Pokémon to compare to</param>
/// <returns>True if the data matches.</returns>
public static bool IsFromTrainer(this ITrainerInfo tr, PKM pk)
{
if (pk.IsEgg)
@ -71,6 +91,12 @@ public static bool IsFromTrainer(this ITrainerInfo tr, PKM pk)
return IsMatchVersion(tr, pk);
}
/// <summary>
/// Checks if the <see cref="ITrainerInfo"/> data matches the <see cref="PKM"/> object's Original Trainer data, ignoring the version.
/// </summary>
/// <param name="tr">Trainer Information</param>
/// <param name="pk">Pokémon to compare to</param>
/// <returns>True if the data matches.</returns>
public static bool IsFromTrainerNoVersion(ITrainerInfo tr, PKM pk)
{
if (tr.ID32 != pk.ID32)

View File

@ -5,20 +5,26 @@ namespace PKHeX.Core;
/// <summary>
/// Stores an IV template.
/// </summary>
/// <param name="HP "><see cref="PKM.IV_HP "/></param>
/// <param name="ATK"><see cref="PKM.IV_ATK"/></param>
/// <param name="DEF"><see cref="PKM.IV_DEF"/></param>
/// <param name="SPE"><see cref="PKM.IV_SPE"/></param>
/// <param name="SPA"><see cref="PKM.IV_SPA"/></param>
/// <param name="SPD"><see cref="PKM.IV_SPD"/></param>
/// <param name="HP "><see cref="PKM.IV_HP "/>; -1 indicates "random".</param>
/// <param name="ATK"><see cref="PKM.IV_ATK"/>; -1 indicates "random".</param>
/// <param name="DEF"><see cref="PKM.IV_DEF"/>; -1 indicates "random".</param>
/// <param name="SPE"><see cref="PKM.IV_SPE"/>; -1 indicates "random".</param>
/// <param name="SPA"><see cref="PKM.IV_SPA"/>; -1 indicates "random".</param>
/// <param name="SPD"><see cref="PKM.IV_SPD"/>; -1 indicates "random".</param>
/// <param name="Type">Differentiate between different IV templates, or lack thereof (0).</param>
public readonly record struct IndividualValueSet(sbyte HP, sbyte ATK, sbyte DEF, sbyte SPE, sbyte SPA, sbyte SPD, byte Type = 1)
public readonly record struct IndividualValueSet(sbyte HP, sbyte ATK, sbyte DEF, sbyte SPE, sbyte SPA, sbyte SPD, IndividualValueSetType Type = IndividualValueSetType.Specified)
{
// 8 BYTES MAX STRUCTURE
// Default struct will be zero type.
public bool IsSpecified => Type != 0;
public bool IsSpecified => Type != IndividualValueSetType.Unspecified;
/// <summary>
/// Gets the IV at the requested <see cref="index"/>.
/// </summary>
/// <param name="index"></param>
/// <remarks>Speed is at index 3, not 5.</remarks>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public sbyte this[int index] => index switch
{
0 => HP,
@ -40,3 +46,12 @@ public void CopyToSpeedLast(Span<int> span)
span[0] = HP;
}
}
/// <summary>
/// Used by <see cref="IndividualValueSet"/> to indicate if a value is present.
/// </summary>
public enum IndividualValueSetType : byte
{
Unspecified = 0,
Specified = 1,
}

View File

@ -1,4 +1,4 @@
namespace PKHeX.Core;
namespace PKHeX.Core;
/// <summary>
/// Specification for <see cref="PKM.IsShiny"/>, used for creating and validating.
@ -24,6 +24,9 @@ public enum Shiny : byte
FixedValue,
}
/// <summary>
/// Extension methods for <see cref="Shiny"/>.
/// </summary>
public static class ShinyExtensions
{
public static bool IsValid(this Shiny s, PKM pk) => s switch

View File

@ -8,12 +8,27 @@ namespace PKHeX.Core;
/// </summary>
public static class AbilityChangeRules
{
/// <summary>
/// Checks if the <see cref="abilityFlag"/> value is possible to obtain based on the original <see cref="enc"/> and game visiting.
/// </summary>
/// <param name="enc">Original Encounter</param>
/// <param name="evosAll">Evolution and game visitation</param>
/// <param name="abilityFlag">Current ability index value</param>
/// <returns>True if possible to obtain <see cref="abilityFlag"/></returns>
public static bool IsAbilityStateValid(this IEncounterTemplate enc, EvolutionHistory evosAll, int abilityFlag) => (enc switch
{
IFixedAbilityNumber f => f.Ability,
_ => Any12,
}).IsAbilityStateValid(evosAll, abilityFlag);
/// <summary>
/// Checks if the current <see cref="abilityFlag"/> value is possible to obtain based on the original <see cref="ability"/> and game visiting.
/// </summary>
/// <param name="ability">Original Ability Permitted</param>
/// <param name="evosAll">Evolution and game visitation</param>
/// <param name="abilityFlag">Current ability index value</param>
/// <returns>True if possible to obtain <see cref="abilityFlag"/></returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static bool IsAbilityStateValid(this AbilityPermission ability, EvolutionHistory evosAll, int abilityFlag) => ability switch
{
Any12H => true,
@ -24,12 +39,25 @@ public static class AbilityChangeRules
_ => throw new ArgumentOutOfRangeException(nameof(ability), ability, null),
};
/// <summary>
/// Checks if the original <see cref="enc"/> ability value can be changed based on the games visited.
/// </summary>
/// <param name="enc">Original Encounter</param>
/// <param name="evosAll">Evolution and game visitation</param>
/// <returns>True if the ability can be changed</returns>
public static bool IsAbilityChangeAvailable(this IEncounterTemplate enc, EvolutionHistory evosAll) => (enc switch
{
IFixedAbilityNumber f => f.Ability,
_ => Any12,
}).IsAbilityChangeAvailable(evosAll);
/// <summary>
/// Checks if the original <see cref="ability"/> value can be changed based on the games visited.
/// </summary>
/// <param name="ability">Original Ability Permitted</param>
/// <param name="evosAll">Evolution and game visitation</param>
/// <returns>True if the ability can be changed</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static bool IsAbilityChangeAvailable(this AbilityPermission ability, EvolutionHistory evosAll) => ability switch
{
Any12H => true,
@ -39,6 +67,11 @@ public static class AbilityChangeRules
_ => throw new ArgumentOutOfRangeException(nameof(ability), ability, null),
};
/// <summary>
/// Checks if the Ability Capsule (1 &lt;-&gt; 2) item is available in any game visited.
/// </summary>
/// <param name="evosAll">Evolution and game visitation</param>
/// <returns>True if possible</returns>
public static bool IsAbilityCapsuleAvailable(EvolutionHistory evosAll)
{
if (evosAll.HasVisitedGen9)
@ -54,6 +87,11 @@ public static bool IsAbilityCapsuleAvailable(EvolutionHistory evosAll)
return false;
}
/// <summary>
/// Checks if any of the games visited allow applying an Ability Capsule (1 &lt;-&gt; 2) item.
/// </summary>
/// <param name="evosAll">Evolution and game visitation</param>
/// <returns>True if possible</returns>
public static bool IsAbilityCapsulePossible(EvolutionHistory evosAll)
{
if (evosAll.HasVisitedGen9 && IsCapsulePossible<PersonalTable9SV, PersonalInfo9SV>(evosAll.Gen9, PersonalTable.SV))
@ -69,6 +107,11 @@ public static bool IsAbilityCapsulePossible(EvolutionHistory evosAll)
return false;
}
/// <summary>
/// Checks if the Ability Patch (1/2-&gt; H) item is available in any game visited.
/// </summary>
/// <param name="evosAll">Evolution and game visitation</param>
/// <returns>True if possible</returns>
public static bool IsAbilityPatchAvailable(EvolutionHistory evosAll)
{
if (evosAll.HasVisitedGen9)
@ -78,6 +121,11 @@ public static bool IsAbilityPatchAvailable(EvolutionHistory evosAll)
return false;
}
/// <summary>
/// Checks if any of the games visited allow applying an Ability Patch (1/2-&gt; H) item.
/// </summary>
/// <param name="evosAll">Evolution and game visitation</param>
/// <returns>True if possible</returns>
public static bool IsAbilityPatchPossible(EvolutionHistory evosAll)
{
if (evosAll.HasVisitedGen9 && IsPatchPossible<PersonalTable9SV, PersonalInfo9SV>(evosAll.Gen9, PersonalTable.SV))
@ -89,6 +137,11 @@ public static bool IsAbilityPatchPossible(EvolutionHistory evosAll)
return false;
}
/// <summary>
/// Checks if any of the games visited allow reverting an Ability Patch (1/2-&gt; H) item.
/// </summary>
/// <param name="evosAll">Evolution and game visitation</param>
/// <returns>True if possible</returns>
public static bool IsAbilityPatchRevertAvailable(EvolutionHistory evosAll)
{
if (evosAll.HasVisitedGen9)
@ -96,6 +149,12 @@ public static bool IsAbilityPatchRevertAvailable(EvolutionHistory evosAll)
return false;
}
/// <summary>
/// Checks if any of the games visited allow reverting an Ability Patch (1/2-&gt; H) item.
/// </summary>
/// <param name="evosAll">Evolution and game visitation</param>
/// <param name="abilityIndex">Current ability index value</param>
/// <returns>True if possible</returns>
public static bool IsAbilityPatchRevertPossible(EvolutionHistory evosAll, int abilityIndex)
{
if (evosAll.HasVisitedGen9 && IsRevertPossible<PersonalTable9SV, PersonalInfo9SV>(evosAll.Gen9, PersonalTable.SV, abilityIndex))

View File

@ -10,6 +10,9 @@ public interface IDynamaxLevelReadOnly
byte DynamaxLevel { get; }
}
/// <summary>
/// Extension methods for <see cref="IDynamaxLevelReadOnly"/>.
/// </summary>
public static class DynamaxLevelExtensions
{
/// <summary>
@ -25,7 +28,7 @@ public static bool CanHaveDynamaxLevel(this IDynamaxLevelReadOnly _, PKM pk)
public static byte GetSuggestedDynamaxLevel(this IDynamaxLevelReadOnly _, PKM pk, byte requested = 10) => _.CanHaveDynamaxLevel(pk) ? requested : (byte)0;
/// <summary>
/// Checks if the species is prevented from gaining any <see cref="IDynamaxLevel.DynamaxLevel"/> via candy in <see cref="GameVersion.SWSH"/>.
/// Checks if the species is prevented from gaining any <see cref="IDynamaxLevelReadOnly.DynamaxLevel"/> via candy in <see cref="GameVersion.SWSH"/>.
/// </summary>
private static bool CanHaveDynamaxLevel(ushort species)
{

View File

@ -2,6 +2,9 @@
namespace PKHeX.Core;
/// <summary>
/// Exposes properties about a Pokémon being capable of Gigantamax as opposed to regular Dynamax.
/// </summary>
public interface IGigantamaxReadOnly
{
/// <summary>
@ -10,6 +13,9 @@ public interface IGigantamaxReadOnly
bool CanGigantamax { get; }
}
/// <summary>
/// Extension methods for <see cref="IGigantamaxReadOnly"/>.
/// </summary>
public static class GigantamaxExtensions
{
/// <summary>

View File

@ -2,6 +2,9 @@
namespace PKHeX.Core;
/// <summary>
/// Generation 3 Mystery Event data structure.
/// </summary>
public class MysteryEvent3 : Gen3MysteryData
{
public const int SIZE = sizeof(uint) + 1000; // total 0x3EC

View File

@ -1,7 +1,10 @@
using System;
using System;
namespace PKHeX.Core
{
/// <summary>
/// Generation 3 Mystery Event data structure specific to <see cref="GameVersion.RS"/>
/// </summary>
public sealed class MysteryEvent3RS : MysteryEvent3
{
public MysteryEvent3RS(byte[] data) : base(data)
@ -10,7 +13,6 @@ public MysteryEvent3RS(byte[] data) : base(data)
throw new ArgumentException("Invalid size.", nameof(data));
}
public override bool IsChecksumValid() => Checksum == Checksums.CheckSum16(Data.AsSpan(4));
public override void FixChecksum() => Checksum = Checksums.CheckSum16(Data.AsSpan(4));
protected override ushort ComputeChecksum() => Checksums.CheckSum16(Data.AsSpan(4));
}
}
}

View File

@ -3,6 +3,9 @@
namespace PKHeX.Core;
/// <summary>
/// Mystery Data for Generation 3 <see cref="SAV3"/> games.
/// </summary>
public abstract class Gen3MysteryData
{
public readonly byte[] Data;
@ -15,8 +18,9 @@ public ushort Checksum
set => WriteUInt16LittleEndian(Data.AsSpan(0), value);
}
public virtual bool IsChecksumValid() => Checksum == GetChecksum(Data.AsSpan(4));
public virtual void FixChecksum() => Checksum = GetChecksum(Data.AsSpan(4));
public bool IsChecksumValid() => Checksum == ComputeChecksum();
public void FixChecksum() => Checksum = ComputeChecksum();
protected virtual ushort ComputeChecksum() => GetChecksum(Data.AsSpan(4));
private static ushort GetChecksum(ReadOnlySpan<byte> data)
{

View File

@ -3,6 +3,9 @@
namespace PKHeX.Core;
/// <summary>
/// Record Mixing Data for Generation 3 <see cref="SAV3"/> games.
/// </summary>
public class RecordMixing3Gift
{
/// <summary>
@ -20,8 +23,10 @@ public RecordMixing3Gift(byte[] data)
Data = data;
}
public bool IsChecksumValid() => Checksum == Checksums.CheckSum16(Data);
public void FixChecksum() => Checksum = Checksums.CheckSum16(Data);
public bool IsChecksumValid() => Checksum == ComputeChecksum();
public void FixChecksum() => Checksum = ComputeChecksum();
private ushort ComputeChecksum() => Checksums.CheckSum16(Data.AsSpan(4));
public ushort Checksum { get => ReadUInt16LittleEndian(Data.AsSpan(0)); set => WriteUInt16LittleEndian(Data.AsSpan(0), value); }
public byte Max { get => Data[4]; set => Data[4] = value; }

View File

@ -3,6 +3,9 @@
namespace PKHeX.Core;
/// <summary>
/// Generation 6 savedata object that stores the player's trainer data.
/// </summary>
public class MyStatus6 : SaveBlock<SAV6>, IRegionOrigin
{
public MyStatus6(SAV6 sav, int offset) : base(sav) => Offset = offset;
@ -57,7 +60,7 @@ public string GameSyncID
set
{
if (value.Length != GameSyncIDSize)
throw new ArgumentException(nameof(value));
throw new ArgumentOutOfRangeException(nameof(value));
var data = Util.GetBytesFromHexString(value);
SAV.SetData(data, Offset + 0x08);

View File

@ -4,6 +4,10 @@
namespace PKHeX.WinForms.Controls;
/// <summary>
/// PictureBox control that can be focused and selected.
/// </summary>
/// <remarks>Draws a focus rectangle, and can be tabbed between, raising events for screen readers.</remarks>
public class SelectablePictureBox : PictureBox
{
public SelectablePictureBox() => SetStyle(ControlStyles.Selectable, TabStop = true);

View File

@ -4,6 +4,9 @@
namespace PKHeX.WinForms.Controls;
/// <summary>
/// Aligns tabs to the left side of the control with text displayed horizontally.
/// </summary>
public class VerticalTabControl : TabControl
{
public VerticalTabControl()
@ -47,8 +50,14 @@ protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
}
}
/// <summary>
/// Specialized <see cref="VerticalTabControl"/> for displaying a <see cref="PKHeX.Core.PKM"/> editor tabs.
/// </summary>
public sealed class VerticalTabControlEntityEditor : VerticalTabControl
{
/// <summary>
/// Tab stripe colors based on Contest Stats.
/// </summary>
private static readonly Color[] SelectedTags =
{
Color.FromArgb(248, 152, 096),

View File

@ -308,7 +308,7 @@ private void CB_Key_KeyDown(object sender, KeyEventArgs e)
var filtered = Array.FindAll(SortedBlockKeys, x => x.Text.Contains(text, StringComparison.InvariantCultureIgnoreCase));
if (filtered.Length == 0)
return; // no results
CB_Key.DataSource = filtered;
CB_Key.SelectedIndex = 0;
}

View File

@ -1,4 +1,4 @@
using System.Linq;
using System;
using FluentAssertions;
using Xunit;
using static PKHeX.Core.Species;
@ -8,6 +8,7 @@ namespace PKHeX.Core.Tests.Legality;
public static class TempTests
{
// BD/SP has egg moves that cannot be obtained because no parents in the egg group can know the move.
[Theory]
[InlineData(Taillow, Boomburst)]
[InlineData(Plusle, TearfulLook)] [InlineData(Minun, TearfulLook)]
@ -22,6 +23,6 @@ public static void CanLearnEggMoveBDSP(Species species, Move move)
var pb8 = new PB8 { Species = (ushort)species };
var encs = EncounterMovesetGenerator.GenerateEncounters(pb8, new[] { (ushort)move }, GameVersion.BD);
encs.Any().Should().BeFalse("Unavailable until HOME update supports BD/SP.");
encs.Should().BeEmpty("HOME supports BD/SP, but does not make any disconnected moves available.");
}
}