diff --git a/PKHeX.Core/Legality/Evolutions/EvoCriteria.cs b/PKHeX.Core/Legality/Evolutions/EvoCriteria.cs
index 76962f5cc..151bde0cd 100644
--- a/PKHeX.Core/Legality/Evolutions/EvoCriteria.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvoCriteria.cs
@@ -1,6 +1,6 @@
namespace PKHeX.Core
{
- public class EvoCriteria : DexLevel
+ public sealed class EvoCriteria : DexLevel
{
public int MinLevel { get; set; }
public bool RequiresLvlUp { get; set; }
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionLineage.cs b/PKHeX.Core/Legality/Evolutions/EvolutionLineage.cs
index 8a173700f..a5bfe3520 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionLineage.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionLineage.cs
@@ -6,7 +6,7 @@ namespace PKHeX.Core
///
/// Informatics pertaining to a 's evolution lineage.
///
- public class EvolutionLineage
+ public sealed class EvolutionLineage
{
public readonly List Chain = new List();
@@ -30,7 +30,8 @@ public void Insert(EvolutionStage evo)
public List GetExplicitLineage(PKM pkm, int maxLevel, bool skipChecks, int maxSpeciesTree, int maxSpeciesOrigin, int minLevel)
{
int lvl = maxLevel;
- List dl = new List { new EvoCriteria { Species = pkm.Species, Level = lvl, Form = pkm.AltForm } };
+ var first = new EvoCriteria {Species = pkm.Species, Level = lvl, Form = pkm.AltForm};
+ var dl = new List { first };
for (int i = Chain.Count - 1; i >= 0; i--) // reverse evolution!
{
bool oneValid = false;
@@ -73,19 +74,20 @@ public List GetExplicitLineage(PKM pkm, int maxLevel, bool skipChec
private static void UpdateMinValues(IReadOnlyList dl, EvolutionMethod evo)
{
var last = dl[dl.Count - 1];
- if (evo.Level == 0 || !evo.RequiresLevelUp) // Evolutions like elemental stones, trade, etc
+ if (!evo.RequiresLevelUp)
{
- if (!evo.RequiresLevelUp)
- last.MinLevel = 1;
- else
- {
- // Evolutions like frienship, pichu -> pikachu, eevee -> umbreon, etc
- last.MinLevel = 2;
+ // Evolutions like elemental stones, trade, etc
+ last.MinLevel = 1;
+ return;
+ }
+ if (evo.Level == 0)
+ {
+ // Evolutions like frienship, pichu -> pikachu, eevee -> umbreon, etc
+ last.MinLevel = 2;
- var first = dl[0];
- if (dl.Count > 1 && !first.RequiresLvlUp)
- first.MinLevel = 2; // Raichu from Pikachu would have minimum level 1, but with Pichu included Raichu minimum level is 2
- }
+ var first = dl[0];
+ if (dl.Count > 1 && !first.RequiresLvlUp)
+ first.MinLevel = 2; // Raichu from Pikachu would have minimum level 1, but with Pichu included Raichu minimum level is 2
}
else // level up evolutions
{
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionMethod.cs b/PKHeX.Core/Legality/Evolutions/EvolutionMethod.cs
index 3d46a1588..aac2612b1 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionMethod.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionMethod.cs
@@ -6,7 +6,7 @@ namespace PKHeX.Core
///
/// Criteria for evolving to this branch in the
///
- public class EvolutionMethod
+ public sealed class EvolutionMethod
{
public int Method;
public int Species;
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet1.cs b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet1.cs
index 1daa32711..ffd3775a2 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet1.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet1.cs
@@ -5,7 +5,7 @@ namespace PKHeX.Core
///
/// Generation 1 Evolution Branch Entries
///
- public class EvolutionSet1 : EvolutionSet
+ public sealed class EvolutionSet1 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, ref int offset)
{
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet2.cs b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet2.cs
index 1bde693e1..d547c57cc 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet2.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet2.cs
@@ -5,7 +5,7 @@ namespace PKHeX.Core
///
/// Generation 2 Evolution Branch Entries
///
- public class EvolutionSet2 : EvolutionSet
+ public sealed class EvolutionSet2 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, ref int offset)
{
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet3.cs b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet3.cs
index 57df41a28..e17f728a8 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet3.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet3.cs
@@ -7,7 +7,7 @@ namespace PKHeX.Core
///
/// Generation 3 Evolution Branch Entries
///
- public class EvolutionSet3 : EvolutionSet
+ public sealed class EvolutionSet3 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, int offset)
{
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet4.cs b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet4.cs
index 2ed4270da..fc9283ab3 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet4.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet4.cs
@@ -7,7 +7,7 @@ namespace PKHeX.Core
///
/// Generation 4 Evolution Branch Entries
///
- public class EvolutionSet4 : EvolutionSet
+ public sealed class EvolutionSet4 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, int offset)
{
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet5.cs b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet5.cs
index 6143aedb2..749ebba63 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet5.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet5.cs
@@ -7,7 +7,7 @@ namespace PKHeX.Core
///
/// Generation 5 Evolution Branch Entries
///
- public class EvolutionSet5 : EvolutionSet
+ public sealed class EvolutionSet5 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, int offset)
{
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet6.cs b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet6.cs
index ae18fa4ac..45ca21bca 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet6.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet6.cs
@@ -6,7 +6,7 @@ namespace PKHeX.Core
///
/// Generation 6 Evolution Branch Entries
///
- public class EvolutionSet6 : EvolutionSet
+ public sealed class EvolutionSet6 : EvolutionSet
{
private static readonly HashSet argEvos = new HashSet {6, 8, 16, 17, 18, 19, 20, 21, 22, 29};
private const int SIZE = 6;
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet7.cs b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet7.cs
index b0d59e02b..c17696f95 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet7.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet7.cs
@@ -5,7 +5,7 @@ namespace PKHeX.Core
///
/// Generation 7 Evolution Branch Entries
///
- public class EvolutionSet7 : EvolutionSet
+ public sealed class EvolutionSet7 : EvolutionSet
{
private const int SIZE = 8;
public EvolutionSet7(byte[] data)
diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs b/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs
index e0ccac125..d11a58e0b 100644
--- a/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs
+++ b/PKHeX.Core/Legality/Evolutions/EvolutionTree.cs
@@ -10,7 +10,7 @@ namespace PKHeX.Core
///
/// Used to determine if a can evolve from prior steps in its evolution branch.
///
- public class EvolutionTree
+ public sealed class EvolutionTree
{
private static readonly EvolutionTree Evolves1;
private static readonly EvolutionTree Evolves2;
@@ -26,118 +26,113 @@ static EvolutionTree()
byte[] get(string resource) => Util.GetBinaryResource($"evos_{resource}.pkl");
byte[][] unpack(string resource) => Data.UnpackMini(get(resource), resource);
- Evolves1 = new EvolutionTree(new[] { get("rby") }, GameVersion.RBY, PersonalTable.Y, Legal.MaxSpeciesID_1);
- Evolves2 = new EvolutionTree(new[] { get("gsc") }, GameVersion.GSC, PersonalTable.C, Legal.MaxSpeciesID_2);
- Evolves3 = new EvolutionTree(new[] { get("g3") }, GameVersion.RS, PersonalTable.RS, Legal.MaxSpeciesID_3);
- Evolves4 = new EvolutionTree(new[] { get("g4") }, GameVersion.DP, PersonalTable.DP, Legal.MaxSpeciesID_4);
- Evolves5 = new EvolutionTree(new[] { get("g5") }, GameVersion.BW, PersonalTable.BW, Legal.MaxSpeciesID_5);
- Evolves6 = new EvolutionTree(unpack("ao"), GameVersion.ORAS, PersonalTable.AO, Legal.MaxSpeciesID_6);
- Evolves7 = new EvolutionTree(unpack("uu"), GameVersion.USUM, PersonalTable.USUM, Legal.MaxSpeciesID_7_USUM);
+ Evolves1 = new EvolutionTree(new[] { get("rby") }, GameVersion.Gen1, PersonalTable.Y, Legal.MaxSpeciesID_1);
+ Evolves2 = new EvolutionTree(new[] { get("gsc") }, GameVersion.Gen2, PersonalTable.C, Legal.MaxSpeciesID_2);
+ Evolves3 = new EvolutionTree(new[] { get("g3") }, GameVersion.Gen3, PersonalTable.RS, Legal.MaxSpeciesID_3);
+ Evolves4 = new EvolutionTree(new[] { get("g4") }, GameVersion.Gen4, PersonalTable.DP, Legal.MaxSpeciesID_4);
+ Evolves5 = new EvolutionTree(new[] { get("g5") }, GameVersion.Gen5, PersonalTable.BW, Legal.MaxSpeciesID_5);
+ Evolves6 = new EvolutionTree(unpack("ao"), GameVersion.Gen6, PersonalTable.AO, Legal.MaxSpeciesID_6);
+ Evolves7 = new EvolutionTree(unpack("uu"), GameVersion.Gen7, PersonalTable.USUM, Legal.MaxSpeciesID_7_USUM);
+
+ // There's always oddballs.
+ Evolves7.FixEvoTreeSM();
}
+
internal static EvolutionTree GetEvolutionTree(int generation)
{
switch (generation)
{
- case 1:
- return Evolves1;
- case 2:
- return Evolves2;
- case 3:
- return Evolves3;
- case 4:
- return Evolves4;
- case 5:
- return Evolves5;
- case 6:
- return Evolves6;
+ case 1: return Evolves1;
+ case 2: return Evolves2;
+ case 3: return Evolves3;
+ case 4: return Evolves4;
+ case 5: return Evolves5;
+ case 6: return Evolves6;
default:
return Evolves7;
}
}
- private List Entries { get; } = new List();
+ private readonly IReadOnlyList Entries;
private readonly EvolutionLineage[] Lineage;
private readonly GameVersion Game;
private readonly PersonalTable Personal;
private readonly int MaxSpeciesTree;
- public EvolutionTree(byte[][] data, GameVersion game, PersonalTable personal, int maxSpeciesTree)
+ private EvolutionTree(IReadOnlyList data, GameVersion game, PersonalTable personal, int maxSpeciesTree)
{
Game = game;
Personal = personal;
MaxSpeciesTree = maxSpeciesTree;
- switch (game)
- {
- case GameVersion.RBY:
- Entries = EvolutionSet1.GetArray(data[0], maxSpeciesTree);
- break;
- case GameVersion.GSC:
- Entries = EvolutionSet2.GetArray(data[0], maxSpeciesTree);
- break;
- case GameVersion.RS:
- Entries = EvolutionSet3.GetArray(data[0]);
- break;
- case GameVersion.DP:
- Entries = EvolutionSet4.GetArray(data[0]);
- break;
- case GameVersion.BW:
- Entries = EvolutionSet5.GetArray(data[0]);
- break;
- case GameVersion.ORAS:
- Entries.AddRange(data.Select(d => new EvolutionSet6(d)));
- break;
- case GameVersion.USUM:
- Entries.AddRange(data.Select(d => new EvolutionSet7(d)));
- break;
- }
+ Entries = GetEntries(data);
+ Lineage = CreateTree();
+ }
- // Create Lineages
- Lineage = new EvolutionLineage[Entries.Count];
+ private IReadOnlyList GetEntries(IReadOnlyList data)
+ {
+ switch (Game)
+ {
+ case GameVersion.Gen1: return EvolutionSet1.GetArray(data[0], MaxSpeciesTree);
+ case GameVersion.Gen2: return EvolutionSet2.GetArray(data[0], MaxSpeciesTree);
+ case GameVersion.Gen3: return EvolutionSet3.GetArray(data[0]);
+ case GameVersion.Gen4: return EvolutionSet4.GetArray(data[0]);
+ case GameVersion.Gen5: return EvolutionSet5.GetArray(data[0]);
+ case GameVersion.Gen6: return new List(data.Select(d => new EvolutionSet6(d)));
+ case GameVersion.Gen7: return new List(data.Select(d => new EvolutionSet7(d)));
+ default: throw new Exception();
+ }
+ }
+
+ private EvolutionLineage[] CreateTree()
+ {
+ var lineage = new EvolutionLineage[Entries.Count];
for (int i = 0; i < Entries.Count; i++)
- Lineage[i] = new EvolutionLineage();
+ lineage[i] = new EvolutionLineage();
if (Game == GameVersion.ORAS)
- Array.Resize(ref Lineage, MaxSpeciesTree + 1);
+ Array.Resize(ref lineage, MaxSpeciesTree + 1);
// Populate Lineages
- for (int i = 1; i < Lineage.Length; i++)
- {
- // Iterate over all possible evolutions
- var s = Entries[i];
- foreach (EvolutionMethod evo in s.PossibleEvolutions)
- {
- int index = GetIndex(evo);
- if (index < 0)
- continue;
-
- var sourceEvo = evo.Copy(i);
-
- Lineage[index].Insert(sourceEvo);
- // If current entries has a pre-evolution, propagate to evolution as well
- if (Lineage[i].Chain.Count > 0)
- Lineage[index].Insert(Lineage[i].Chain[0]);
-
- if (index >= i) continue;
- // If destination species evolves into something (ie a 'baby' Pokemon like Cleffa)
- // Add it to the corresponding parent chains
- foreach (EvolutionMethod mid in Entries[index].PossibleEvolutions)
- {
- int newIndex = GetIndex(mid);
- if (newIndex < 0)
- continue;
-
- Lineage[newIndex].Insert(sourceEvo);
- }
- }
- }
- FixEvoTreeManually();
+ for (int i = 1; i < lineage.Length; i++)
+ CreateBranch(lineage, i);
+ return lineage;
}
- // There's always oddballs.
- private void FixEvoTreeManually()
+ private void CreateBranch(IReadOnlyList lineage, int i)
{
- if (Game == GameVersion.USUM)
- FixEvoTreeSM();
+ // Iterate over all possible evolutions
+ foreach (var evo in Entries[i].PossibleEvolutions)
+ CreateLeaf(lineage, i, evo);
}
+
+ private void CreateLeaf(IReadOnlyList lineage, int i, EvolutionMethod evo)
+ {
+ int index = GetIndex(evo);
+ if (index < 0)
+ return;
+
+ var sourceEvo = evo.Copy(i);
+
+ lineage[index].Insert(sourceEvo);
+ // If current entries has a pre-evolution, propagate to evolution as well
+ var current = lineage[i].Chain;
+ if (current.Count > 0)
+ lineage[index].Insert(current[0]);
+
+ if (index >= i)
+ return;
+
+ // If destination species evolves into something (ie a 'baby' Pokemon like Cleffa)
+ // Add it to the corresponding parent chains
+ foreach (var method in Entries[index].PossibleEvolutions)
+ {
+ int newIndex = GetIndex(method);
+ if (newIndex < 0)
+ continue;
+
+ lineage[newIndex].Insert(sourceEvo);
+ }
+ }
+
private void FixEvoTreeSM()
{
// Wormadam -- Copy Burmy 0 to Wormadam-1/2
@@ -201,6 +196,16 @@ private int GetIndex(EvolutionMethod evo)
return Personal.GetFormeIndex(evolvesToSpecies, evolvesToForm);
}
+
+ ///
+ /// Gets a list of evolutions for the input by checking each evolution in the chain.
+ ///
+ /// Pokémon data to check with.
+ /// Maximum level to permit before the chain breaks.
+ /// Maximum species ID to permit within the chain.
+ /// Ignores an evolution's criteria, causing the returned list to have all possible evolutions.
+ /// Minimum level to permit before the chain breaks.
+ ///
public List GetValidPreEvolutions(PKM pkm, int maxLevel, int maxSpeciesOrigin = -1, bool skipChecks = false, int minLevel = 1)
{
int index = GetIndex(pkm);
diff --git a/PKHeX.Core/Legality/Learnset/Learnset1.cs b/PKHeX.Core/Legality/Learnset/Learnset1.cs
index baadf63d2..3fe7dbff5 100644
--- a/PKHeX.Core/Legality/Learnset/Learnset1.cs
+++ b/PKHeX.Core/Legality/Learnset/Learnset1.cs
@@ -2,7 +2,7 @@
namespace PKHeX.Core
{
- public class Learnset1 : Learnset
+ public sealed class Learnset1 : Learnset
{
private Learnset1(byte[] data, ref int offset)
{
diff --git a/PKHeX.Core/Legality/Learnset/Learnset6.cs b/PKHeX.Core/Legality/Learnset/Learnset6.cs
index 531a77fc1..9a71f2706 100644
--- a/PKHeX.Core/Legality/Learnset/Learnset6.cs
+++ b/PKHeX.Core/Legality/Learnset/Learnset6.cs
@@ -2,16 +2,17 @@
namespace PKHeX.Core
{
- public class Learnset6 : Learnset
+ public sealed class Learnset6 : Learnset
{
private Learnset6(byte[] data)
{
if (data.Length < 4 || data.Length % 4 != 0)
{ Count = 0; Levels = new int[0]; Moves = new int[0]; return; }
- Count = data.Length / 4 - 1;
+ Count = (data.Length / 4) - 1;
Moves = new int[Count];
Levels = new int[Count];
- using (BinaryReader br = new BinaryReader(new MemoryStream(data)))
+ using (var ms = new MemoryStream(data))
+ using (var br = new BinaryReader(ms))
for (int i = 0; i < Count; i++)
{
Moves[i] = br.ReadInt16();