mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-15 16:48:01 +00:00
858aa50689
exercise in deferred execution/state machine, only calculate possible
matches until a sufficiently valid match is obtained. Previous setup
would try to calculate the 'best match' and had band-aid workarounds in
cases where a subsequent check may determine it to be a false match.
There's still more ways to improve speed:
- precalculate relationships for Encounter Slots rather than iterating
over every area
- yielding individual slots instead of an entire area
- group non-egg wondercards by ID in a dict/hashtable for faster
retrieval
reworked some internals:
- EncounterMatch is always an IEncounterable instead of an object, for
easy pattern matching.
- Splitbreed checking is done per encounter and is stored in the
EncounterEgg result
- Encounter validation uses Encounter/Move/RelearnMove/Evolution to
whittle to the final encounter.
As a part of the encounter matching, a lazy peek is used to check if an
invalid encounter should be retained instead of discarded; if another
encounter has not been checked, it'll stop the invalid checks and move
on. If it is the last encounter, no other valid encounters exist so it
will keep the parse for the invalid encounter.
If no encounters are yielded, then there is no encountermatch. An
EncounterInvalid is created to store basic details, and the parse is
carried out.
Breaks some legality checking features for flagging invalid moves in
more detail, but those can be re-added in a separate check (if
splitbreed & any move invalid -> check for other split moves).
Should now be easier to follow the flow & maintain 😄
189 lines
8.3 KiB
C#
189 lines
8.3 KiB
C#
using System;
|
|
using System.Linq;
|
|
|
|
namespace PKHeX.Core
|
|
{
|
|
public class PersonalTable
|
|
{
|
|
public static readonly PersonalTable SM = new PersonalTable(Util.getBinaryResource("personal_sm"), GameVersion.SM);
|
|
public static readonly PersonalTable AO = new PersonalTable(Util.getBinaryResource("personal_ao"), GameVersion.ORAS);
|
|
public static readonly PersonalTable XY = new PersonalTable(Util.getBinaryResource("personal_xy"), GameVersion.XY);
|
|
public static readonly PersonalTable B2W2 = new PersonalTable(Util.getBinaryResource("personal_b2w2"), GameVersion.B2W2);
|
|
public static readonly PersonalTable BW = new PersonalTable(Util.getBinaryResource("personal_bw"), GameVersion.BW);
|
|
public static readonly PersonalTable HGSS = new PersonalTable(Util.getBinaryResource("personal_hgss"), GameVersion.HGSS);
|
|
public static readonly PersonalTable Pt = new PersonalTable(Util.getBinaryResource("personal_pt"), GameVersion.Pt);
|
|
public static readonly PersonalTable DP = new PersonalTable(Util.getBinaryResource("personal_dp"), GameVersion.DP);
|
|
public static readonly PersonalTable LG = new PersonalTable(Util.getBinaryResource("personal_lg"), GameVersion.LG);
|
|
public static readonly PersonalTable FR = new PersonalTable(Util.getBinaryResource("personal_fr"), GameVersion.FR);
|
|
public static readonly PersonalTable E = new PersonalTable(Util.getBinaryResource("personal_e"), GameVersion.E);
|
|
public static readonly PersonalTable RS = new PersonalTable(Util.getBinaryResource("personal_rs"), GameVersion.RS);
|
|
public static readonly PersonalTable C = new PersonalTable(Util.getBinaryResource("personal_c"), GameVersion.C);
|
|
public static readonly PersonalTable GS = new PersonalTable(Util.getBinaryResource("personal_c"), GameVersion.GS);
|
|
public static readonly PersonalTable RB = new PersonalTable(Util.getBinaryResource("personal_rb"), GameVersion.RBY);
|
|
public static readonly PersonalTable Y = new PersonalTable(Util.getBinaryResource("personal_y"), GameVersion.RBY);
|
|
|
|
private static byte[][] splitBytes(byte[] data, int size)
|
|
{
|
|
byte[][] r = new byte[data.Length / size][];
|
|
for (int i = 0; i < data.Length; i += size)
|
|
{
|
|
r[i / size] = new byte[size];
|
|
Array.Copy(data, i, r[i / size], 0, size);
|
|
}
|
|
return r;
|
|
}
|
|
private PersonalTable(byte[] data, GameVersion format)
|
|
{
|
|
int size = 0;
|
|
switch (format)
|
|
{
|
|
case GameVersion.RBY: size = PersonalInfoG1.SIZE; break;
|
|
case GameVersion.GS:
|
|
case GameVersion.C: size = PersonalInfoG2.SIZE; break;
|
|
case GameVersion.RS:
|
|
case GameVersion.E:
|
|
case GameVersion.FR:
|
|
case GameVersion.LG: size = PersonalInfoG3.SIZE; break;
|
|
case GameVersion.DP:
|
|
case GameVersion.Pt:
|
|
case GameVersion.HGSS: size = PersonalInfoG4.SIZE; break;
|
|
case GameVersion.BW: size = PersonalInfoBW.SIZE; break;
|
|
case GameVersion.B2W2: size = PersonalInfoB2W2.SIZE; break;
|
|
case GameVersion.XY: size = PersonalInfoXY.SIZE; break;
|
|
case GameVersion.ORAS: size = PersonalInfoORAS.SIZE; break;
|
|
case GameVersion.SM: size = PersonalInfoSM.SIZE; break;
|
|
}
|
|
|
|
if (size == 0)
|
|
{ Table = null; return; }
|
|
|
|
byte[][] entries = splitBytes(data, size);
|
|
PersonalInfo[] d = new PersonalInfo[data.Length / size];
|
|
|
|
switch (format)
|
|
{
|
|
case GameVersion.RBY:
|
|
for (int i = 0; i < d.Length; i++)
|
|
d[i] = new PersonalInfoG1(entries[i]);
|
|
break;
|
|
case GameVersion.GS:
|
|
case GameVersion.C:
|
|
for (int i = 0; i < d.Length; i++)
|
|
d[i] = new PersonalInfoG2(entries[i]);
|
|
break;
|
|
case GameVersion.RS:
|
|
case GameVersion.E:
|
|
case GameVersion.FR:
|
|
case GameVersion.LG:
|
|
for (int i = 0; i < d.Length; i++)
|
|
d[i] = new PersonalInfoG3(entries[i]);
|
|
break;
|
|
case GameVersion.DP:
|
|
case GameVersion.Pt:
|
|
case GameVersion.HGSS:
|
|
for (int i = 0; i < d.Length; i++)
|
|
d[i] = new PersonalInfoG4(entries[i]);
|
|
break;
|
|
case GameVersion.BW:
|
|
for (int i = 0; i < d.Length; i++)
|
|
d[i] = new PersonalInfoBW(entries[i]);
|
|
break;
|
|
case GameVersion.B2W2:
|
|
for (int i = 0; i < d.Length; i++)
|
|
d[i] = new PersonalInfoB2W2(entries[i]);
|
|
break;
|
|
case GameVersion.XY:
|
|
for (int i = 0; i < d.Length; i++)
|
|
d[i] = new PersonalInfoXY(entries[i]);
|
|
break;
|
|
case GameVersion.ORAS:
|
|
for (int i = 0; i < d.Length; i++)
|
|
d[i] = new PersonalInfoORAS(entries[i]);
|
|
break;
|
|
case GameVersion.SM:
|
|
for (int i = 0; i < d.Length; i++)
|
|
d[i] = new PersonalInfoSM(entries[i]);
|
|
break;
|
|
}
|
|
Table = d;
|
|
}
|
|
|
|
private readonly PersonalInfo[] Table;
|
|
public PersonalInfo this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (0 <= index && index < Table.Length)
|
|
return Table[index];
|
|
return Table[0];
|
|
}
|
|
set
|
|
{
|
|
if (index < 0 || index >= Table.Length)
|
|
return;
|
|
Table[index] = value;
|
|
}
|
|
}
|
|
|
|
public int[] getAbilities(int species, int forme)
|
|
{
|
|
if (species >= Table.Length)
|
|
{ species = 0; Console.WriteLine("Requested out of bounds SpeciesID"); }
|
|
return this[getFormeIndex(species, forme)].Abilities;
|
|
}
|
|
public int getFormeIndex(int species, int forme)
|
|
{
|
|
if (species >= Table.Length)
|
|
{ species = 0; Console.WriteLine("Requested out of bounds SpeciesID"); }
|
|
return this[species].FormeIndex(species, forme);
|
|
}
|
|
public PersonalInfo getFormeEntry(int species, int forme)
|
|
{
|
|
return this[getFormeIndex(species, forme)];
|
|
}
|
|
|
|
public int TableLength => Table.Length;
|
|
public string[][] getFormList(string[] species, int MaxSpecies)
|
|
{
|
|
string[][] FormList = new string[MaxSpecies+1][];
|
|
for (int i = 0; i <= MaxSpecies; i++) //Hardcode 721 species + null
|
|
{
|
|
int FormCount = this[i].FormeCount;
|
|
FormList[i] = new string[FormCount];
|
|
if (FormCount <= 0) continue;
|
|
FormList[i][0] = species[i];
|
|
for (int j = 1; j < FormCount; j++)
|
|
{
|
|
FormList[i][j] = $"{species[i]} " + j;
|
|
}
|
|
}
|
|
|
|
return FormList;
|
|
}
|
|
public string[] getPersonalEntryList(string[][] AltForms, string[] species, int MaxSpecies, out int[] baseForm, out int[] formVal)
|
|
{
|
|
string[] result = new string[Table.Length];
|
|
baseForm = new int[result.Length];
|
|
formVal = new int[result.Length];
|
|
for (int i = 0; i <= MaxSpecies; i++)
|
|
{
|
|
result[i] = species[i];
|
|
if (AltForms[i].Length == 0) continue;
|
|
int altformpointer = this[i].FormStatsIndex;
|
|
if (altformpointer <= 0) continue;
|
|
for (int j = 1; j < AltForms[i].Length; j++)
|
|
{
|
|
int ptr = altformpointer + j - 1;
|
|
baseForm[ptr] = i;
|
|
formVal[ptr] = j;
|
|
result[ptr] = AltForms[i][j];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
public bool IsValidTypeCombination(int Type1, int Type2)
|
|
{
|
|
return Table.Any(p => p.Types[0] == Type1 && p.Types[1] == Type2);
|
|
}
|
|
}
|
|
}
|