mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-10-02 02:19:12 -05:00
Misc simplifications
reduce nesting (evo.RequiresLevelUp is checked twice, only check once and handle path) compact some methods seal some classes add a little xmldoc to exposed members
This commit is contained in:
@@ -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; }
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace PKHeX.Core
|
||||
/// <summary>
|
||||
/// Informatics pertaining to a <see cref="PKM"/>'s evolution lineage.
|
||||
/// </summary>
|
||||
public class EvolutionLineage
|
||||
public sealed class EvolutionLineage
|
||||
{
|
||||
public readonly List<EvolutionStage> Chain = new List<EvolutionStage>();
|
||||
|
||||
@@ -30,7 +30,8 @@ public void Insert(EvolutionStage evo)
|
||||
public List<EvoCriteria> GetExplicitLineage(PKM pkm, int maxLevel, bool skipChecks, int maxSpeciesTree, int maxSpeciesOrigin, int minLevel)
|
||||
{
|
||||
int lvl = maxLevel;
|
||||
List<EvoCriteria> dl = new List<EvoCriteria> { 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<EvoCriteria> { first };
|
||||
for (int i = Chain.Count - 1; i >= 0; i--) // reverse evolution!
|
||||
{
|
||||
bool oneValid = false;
|
||||
@@ -73,19 +74,20 @@ public List<EvoCriteria> GetExplicitLineage(PKM pkm, int maxLevel, bool skipChec
|
||||
private static void UpdateMinValues(IReadOnlyList<EvoCriteria> 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
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace PKHeX.Core
|
||||
/// <summary>
|
||||
/// Criteria for evolving to this branch in the <see cref="EvolutionTree"/>
|
||||
/// </summary>
|
||||
public class EvolutionMethod
|
||||
public sealed class EvolutionMethod
|
||||
{
|
||||
public int Method;
|
||||
public int Species;
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace PKHeX.Core
|
||||
/// <summary>
|
||||
/// Generation 1 Evolution Branch Entries
|
||||
/// </summary>
|
||||
public class EvolutionSet1 : EvolutionSet
|
||||
public sealed class EvolutionSet1 : EvolutionSet
|
||||
{
|
||||
private static EvolutionMethod GetMethod(byte[] data, ref int offset)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace PKHeX.Core
|
||||
/// <summary>
|
||||
/// Generation 2 Evolution Branch Entries
|
||||
/// </summary>
|
||||
public class EvolutionSet2 : EvolutionSet
|
||||
public sealed class EvolutionSet2 : EvolutionSet
|
||||
{
|
||||
private static EvolutionMethod GetMethod(byte[] data, ref int offset)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace PKHeX.Core
|
||||
/// <summary>
|
||||
/// Generation 3 Evolution Branch Entries
|
||||
/// </summary>
|
||||
public class EvolutionSet3 : EvolutionSet
|
||||
public sealed class EvolutionSet3 : EvolutionSet
|
||||
{
|
||||
private static EvolutionMethod GetMethod(byte[] data, int offset)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace PKHeX.Core
|
||||
/// <summary>
|
||||
/// Generation 4 Evolution Branch Entries
|
||||
/// </summary>
|
||||
public class EvolutionSet4 : EvolutionSet
|
||||
public sealed class EvolutionSet4 : EvolutionSet
|
||||
{
|
||||
private static EvolutionMethod GetMethod(byte[] data, int offset)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace PKHeX.Core
|
||||
/// <summary>
|
||||
/// Generation 5 Evolution Branch Entries
|
||||
/// </summary>
|
||||
public class EvolutionSet5 : EvolutionSet
|
||||
public sealed class EvolutionSet5 : EvolutionSet
|
||||
{
|
||||
private static EvolutionMethod GetMethod(byte[] data, int offset)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace PKHeX.Core
|
||||
/// <summary>
|
||||
/// Generation 6 Evolution Branch Entries
|
||||
/// </summary>
|
||||
public class EvolutionSet6 : EvolutionSet
|
||||
public sealed class EvolutionSet6 : EvolutionSet
|
||||
{
|
||||
private static readonly HashSet<int> argEvos = new HashSet<int> {6, 8, 16, 17, 18, 19, 20, 21, 22, 29};
|
||||
private const int SIZE = 6;
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace PKHeX.Core
|
||||
/// <summary>
|
||||
/// Generation 7 Evolution Branch Entries
|
||||
/// </summary>
|
||||
public class EvolutionSet7 : EvolutionSet
|
||||
public sealed class EvolutionSet7 : EvolutionSet
|
||||
{
|
||||
private const int SIZE = 8;
|
||||
public EvolutionSet7(byte[] data)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace PKHeX.Core
|
||||
/// <remarks>
|
||||
/// Used to determine if a <see cref="PKM.Species"/> can evolve from prior steps in its evolution branch.
|
||||
/// </remarks>
|
||||
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<EvolutionSet> Entries { get; } = new List<EvolutionSet>();
|
||||
private readonly IReadOnlyList<EvolutionSet> 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<byte[]> 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<EvolutionSet> GetEntries(IReadOnlyList<byte[]> 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<EvolutionSet>(data.Select(d => new EvolutionSet6(d)));
|
||||
case GameVersion.Gen7: return new List<EvolutionSet>(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<EvolutionLineage> 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<EvolutionLineage> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of evolutions for the input <see cref="PKM"/> by checking each evolution in the chain.
|
||||
/// </summary>
|
||||
/// <param name="pkm">Pokémon data to check with.</param>
|
||||
/// <param name="maxLevel">Maximum level to permit before the chain breaks.</param>
|
||||
/// <param name="maxSpeciesOrigin">Maximum species ID to permit within the chain.</param>
|
||||
/// <param name="skipChecks">Ignores an evolution's criteria, causing the returned list to have all possible evolutions.</param>
|
||||
/// <param name="minLevel">Minimum level to permit before the chain breaks.</param>
|
||||
/// <returns></returns>
|
||||
public List<EvoCriteria> GetValidPreEvolutions(PKM pkm, int maxLevel, int maxSpeciesOrigin = -1, bool skipChecks = false, int minLevel = 1)
|
||||
{
|
||||
int index = GetIndex(pkm);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class Learnset1 : Learnset
|
||||
public sealed class Learnset1 : Learnset
|
||||
{
|
||||
private Learnset1(byte[] data, ref int offset)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user