Legality refactoring continued

Finish removing explicit gen6 objects so that multiple generations of
information can be checked.

Still only supports gen6, but will be much much easier to add in other
generations in the future.

Tested a few pk6's and the legality checks appear to be functioning the
same.
This commit is contained in:
Kaphotics 2016-10-23 22:03:19 -07:00
parent ed14ab7436
commit a462c09743
2 changed files with 459 additions and 217 deletions

View file

@ -971,7 +971,7 @@ namespace PKHeX
return;
case 14:
if (!Legal.getCanBeCaptured(pkm.OT_TextVar, pkm.Version))
if (!Legal.getCanBeCaptured(pkm.OT_TextVar, pkm.GenNumber, pkm.Version))
AddLine(Severity.Invalid, "OT Memory: Captured Species can not be captured in game.", CheckIdentifier.Memory);
else
AddLine(Severity.Valid, "OT Memory: Captured Species can be captured in game.", CheckIdentifier.Memory);
@ -1001,7 +1001,7 @@ namespace PKHeX
AddLine(Severity.Invalid, "HT Memory: Handling Trainer did not hatch this.", CheckIdentifier.Memory); return;
case 14:
if (!Legal.getCanBeCaptured(pkm.HT_TextVar))
if (!Legal.getCanBeCaptured(pkm.HT_TextVar, pkm.GenNumber))
AddLine(Severity.Invalid, "HT Memory: Captured Species can not be captured in game.", CheckIdentifier.Memory);
else
AddLine(Severity.Valid, "HT Memory: Captured Species can be captured in game.", CheckIdentifier.Memory);
@ -1217,6 +1217,7 @@ namespace PKHeX
int[] Moves = pkm.RelearnMoves;
if (pkm.GenNumber < 6)
goto noRelearn;
if (pkm.WasLink)
{
var Link = Legal.getValidLinkGifts(pkm);
@ -1239,7 +1240,7 @@ namespace PKHeX
if (pkm.WasEvent || pkm.WasEventEgg)
{
// Get WC6's that match
EventGiftMatch = new List<MysteryGift>(Legal.getValidWC6s(pkm));
EventGiftMatch = new List<MysteryGift>(Legal.getValidGifts(pkm));
foreach (MysteryGift mg in EventGiftMatch.ToArray())
{
int[] moves = mg.RelearnMoves;
@ -1261,7 +1262,20 @@ namespace PKHeX
if (pkm.WasEgg && !Legal.NoHatchFromEgg.Contains(pkm.Species))
{
const int games = 2;
int games = 1;
GameVersion[] Games = { GameVersion.XY };
switch (pkm.GenNumber)
{
case 6:
games = 2;
Games = new[] {GameVersion.XY, GameVersion.ORAS};
break;
case 7:
games = 1;
Games = new[] {GameVersion.SM};
break;
}
bool checkAllGames = pkm.WasTradedEgg;
bool splitBreed = Legal.SplitBreed.Contains(pkm.Species);
@ -1270,9 +1284,10 @@ namespace PKHeX
{
int gameSource = !checkAllGames ? -1 : i % iterate / (splitBreed ? 2 : 1);
int skipOption = splitBreed && iterate / 2 <= i ? 1 : 0;
GameVersion ver = gameSource == -1 ? GameVersion.Any : Games[gameSource];
// Obtain level1 moves
List<int> baseMoves = new List<int>(Legal.getBaseEggMoves(pkm, skipOption, gameSource));
List<int> baseMoves = new List<int>(Legal.getBaseEggMoves(pkm, skipOption, ver));
int baseCt = baseMoves.Count;
if (baseCt > 4) baseCt = 4;

View file

@ -5,26 +5,29 @@ namespace PKHeX
{
public static partial class Legal
{
// PKHeX master Wonder Card Database
// Event Database(s)
internal static WC6[] WC6DB;
// PKHeX master personal.dat
// Gen 6
private static readonly EggMoves[] EggMoveXY = EggMoves.getArray(Data.unpackMini(Properties.Resources.eggmove_xy, "xy"));
private static readonly Learnset[] LevelUpXY = Learnset.getArray(Data.unpackMini(Properties.Resources.lvlmove_xy, "xy"));
private static readonly EggMoves[] EggMoveAO = EggMoves.getArray(Data.unpackMini(Properties.Resources.eggmove_ao, "ao"));
private static readonly Learnset[] LevelUpAO = Learnset.getArray(Data.unpackMini(Properties.Resources.lvlmove_ao, "ao"));
private static readonly Evolutions[] Evolves = Evolutions.getArray(Data.unpackMini(Properties.Resources.evos_ao, "ao"));
private static readonly EncounterArea[] SlotsA;
private static readonly EncounterArea[] SlotsO;
private static readonly EncounterArea[] SlotsX;
private static readonly EncounterArea[] SlotsY;
private static readonly EncounterStatic[] StaticX;
private static readonly EncounterStatic[] StaticY;
private static readonly EncounterStatic[] StaticA;
private static readonly EncounterStatic[] StaticO;
private static EncounterStatic[] getSpecial(GameVersion Game)
private static readonly Evolutions[] Evolves6 = Evolutions.getArray(Data.unpackMini(Properties.Resources.evos_ao, "ao"));
private static readonly EncounterArea[] SlotsX, SlotsY, SlotsA, SlotsO;
private static readonly EncounterStatic[] StaticX, StaticY, StaticA, StaticO;
// Gen 7
private static readonly EggMoves[] EggMoveSM = new EggMoves[0];
private static readonly Learnset[] LevelUpSM = new Learnset[0];
private static readonly Evolutions[] Evolves7 = new Evolutions[0];
private static readonly EncounterArea[] SlotsSN, SlotsMN;
private static readonly EncounterStatic[] StaticSN, StaticMN;
// Setup Help
private static EncounterStatic[] getStaticEncounters(GameVersion Game)
{
EncounterStatic[] table = null;
EncounterStatic[] table;
switch (Game)
{
case GameVersion.X:
@ -39,9 +42,47 @@ namespace PKHeX
case GameVersion.MN:
table = Encounter_SM;
break;
default: return null;
}
return table?.Where(s => s.Version == GameVersion.Any || s.Version == Game).ToArray();
}
private static EncounterArea[] getEncounterTables(GameVersion Game)
{
string ident = null;
byte[] tables = null;
switch (Game)
{
case GameVersion.X:
ident = "xy";
tables = Properties.Resources.encounter_x;
break;
case GameVersion.Y:
ident = "xy";
tables = Properties.Resources.encounter_y;
break;
case GameVersion.AS:
ident = "ao";
tables = Properties.Resources.encounter_a;
break;
case GameVersion.OR:
ident = "ao";
tables = Properties.Resources.encounter_o;
break;
case GameVersion.SN:
ident = "sm";
// tables = Properties.Resources.encounter_sn;
break;
case GameVersion.MN:
ident = "sm";
// tables = Properties.Resources.encounter_mn;
break;
}
if (ident == null)
return null;
return EncounterArea.getArray(Data.unpackMini(tables, ident));
}
private static EncounterArea[] addXYAltTiles(EncounterArea[] GameSlots, EncounterArea[] SpecialSlots)
{
foreach (EncounterArea g in GameSlots)
@ -52,141 +93,123 @@ namespace PKHeX
}
return GameSlots;
}
private static void MarkG6XYSlots(ref EncounterArea[] Areas)
{
foreach (var area in Areas)
{
int slotct = area.Slots.Length;
for (int i = slotct - 15; i < slotct; i++)
area.Slots[i].Type = SlotType.Horde;
}
}
private static void MarkG6AOSlots(ref EncounterArea[] Areas)
{
foreach (var area in Areas)
{
for (int i = 32; i < 37; i++)
area.Slots[i].Type = SlotType.Rock_Smash;
int slotct = area.Slots.Length;
for (int i = slotct - 15; i < slotct; i++)
area.Slots[i].Type = SlotType.Horde;
for (int i = 0; i < slotct; i++)
area.Slots[i].AllowDexNav = area.Slots[i].Type != SlotType.Rock_Smash;
}
}
static Legal() // Setup
{
#region Gen6: XY & ORAS
StaticX = getSpecial(GameVersion.X);
StaticY = getSpecial(GameVersion.Y);
StaticA = getSpecial(GameVersion.AS);
StaticO = getSpecial(GameVersion.OR);
var XSlots = EncounterArea.getArray(Data.unpackMini(Properties.Resources.encounter_x, "xy"));
var YSlots = EncounterArea.getArray(Data.unpackMini(Properties.Resources.encounter_y, "xy"));
// Mark Horde Encounters
foreach (var area in XSlots)
// Gen 6
{
int slotct = area.Slots.Length;
for (int i = slotct - 15; i < slotct; i++)
area.Slots[i].Type = SlotType.Horde;
StaticX = getStaticEncounters(GameVersion.X);
StaticY = getStaticEncounters(GameVersion.Y);
StaticA = getStaticEncounters(GameVersion.AS);
StaticO = getStaticEncounters(GameVersion.OR);
var XSlots = getEncounterTables(GameVersion.X);
var YSlots = getEncounterTables(GameVersion.Y);
MarkG6XYSlots(ref XSlots);
MarkG6XYSlots(ref YSlots);
SlotsX = addXYAltTiles(XSlots, SlotsXYAlt);
SlotsY = addXYAltTiles(YSlots, SlotsXYAlt);
SlotsA = getEncounterTables(GameVersion.AS);
SlotsO = getEncounterTables(GameVersion.OR);
MarkG6AOSlots(ref SlotsA);
MarkG6AOSlots(ref SlotsO);
}
foreach (var area in YSlots)
// Gen 7
{
int slotct = area.Slots.Length;
for (int i = slotct - 15; i < slotct; i++)
area.Slots[i].Type = SlotType.Horde;
StaticSN = getStaticEncounters(GameVersion.SN);
StaticMN = getStaticEncounters(GameVersion.MN);
SlotsSN = getEncounterTables(GameVersion.SN);
SlotsMN = getEncounterTables(GameVersion.MN);
// TEMP
Evolves7 = Evolves6;
}
SlotsX = addXYAltTiles(XSlots, SlotsXYAlt);
SlotsY = addXYAltTiles(YSlots, SlotsXYAlt);
SlotsA = EncounterArea.getArray(Data.unpackMini(Properties.Resources.encounter_a, "ao"));
SlotsO = EncounterArea.getArray(Data.unpackMini(Properties.Resources.encounter_o, "ao"));
// Mark Encounters
foreach (var area in SlotsA)
{
for (int i = 32; i < 37; i++)
area.Slots[i].Type = SlotType.Rock_Smash;
int slotct = area.Slots.Length;
for (int i = slotct - 15; i < slotct; i++)
area.Slots[i].Type = SlotType.Horde;
for (int i = 0; i < slotct; i++)
area.Slots[i].AllowDexNav = area.Slots[i].Type != SlotType.Rock_Smash;
}
foreach (var area in SlotsO)
{
for (int i = 32; i < 37; i++)
area.Slots[i].Type = SlotType.Rock_Smash;
int slotct = area.Slots.Length;
for (int i = slotct - 15; i < slotct; i++)
area.Slots[i].Type = SlotType.Horde;
for (int i = 0; i < slotct; i++)
area.Slots[i].AllowDexNav = area.Slots[i].Type != SlotType.Rock_Smash;
}
#endregion
}
// Moves
internal static IEnumerable<int> getValidMoves(PKM pkm)
{ return getValidMoves(pkm, -1, LVL: true, Relearn: false, Tutor: true, Machine: true); }
{
int version = pkm.Version;
if (!pkm.IsUntraded)
version = -1;
return getValidMoves(pkm, version, LVL: true, Relearn: false, Tutor: true, Machine: true);
}
internal static IEnumerable<int> getValidRelearn(PKM pkm, int skipOption)
{
List<int> r = new List<int> { 0 };
int species = getBaseSpecies(pkm, skipOption);
r.AddRange(getLVLMoves(species, 1, pkm.AltForm));
r.AddRange(getEggMoves(species, pkm.Species == 678 ? pkm.AltForm : 0));
r.AddRange(getLVLMoves(species, 100, pkm.AltForm));
r.AddRange(getLVLMoves(pkm, species, 1, pkm.AltForm));
r.AddRange(getEggMoves(pkm, species, pkm.Species == 678 ? pkm.AltForm : 0));
r.AddRange(getLVLMoves(pkm, species, 100, pkm.AltForm));
return r.Distinct();
}
internal static IEnumerable<int> getBaseEggMoves(PKM pkm, int skipOption, int gameSource)
internal static IEnumerable<int> getBaseEggMoves(PKM pkm, int skipOption, GameVersion gameSource)
{
int species = getBaseSpecies(pkm, skipOption);
if (gameSource == -1)
if (gameSource == GameVersion.Any)
gameSource = (GameVersion) pkm.Version;
switch (gameSource)
{
if (pkm.XY)
return LevelUpXY[species].getMoves(1);
if (pkm.AO)
return LevelUpAO[species].getMoves(1);
return null;
case GameVersion.X:
case GameVersion.Y:
case GameVersion.XY:
if (pkm.InhabitedGeneration(6))
return LevelUpXY[species].getMoves(1);
break;
case GameVersion.AS:
case GameVersion.OR:
case GameVersion.ORAS:
if (pkm.InhabitedGeneration(6))
return LevelUpAO[species].getMoves(1);
break;
case GameVersion.SN:
case GameVersion.MN:
case GameVersion.SM:
if (pkm.InhabitedGeneration(7))
return LevelUpSM[species].getMoves(1);
break;
}
if (gameSource == 0) // XY
return LevelUpXY[species].getMoves(1);
// if (gameSource == 1) // ORAS
return LevelUpAO[species].getMoves(1);
return null;
}
internal static IEnumerable<MysteryGift> getValidWC6s(PKM pkm)
{
var vs = getValidPreEvolutions(pkm).ToArray();
List<MysteryGift> validWC6 = new List<MysteryGift>();
foreach (WC6 wc in WC6DB.Where(wc => vs.Any(dl => dl.Species == wc.Species)))
{
if (pkm.Egg_Location == 0) // Not Egg
{
if (wc.CardID != pkm.SID) continue;
if (wc.TID != pkm.TID) continue;
if (wc.OT != pkm.OT_Name) continue;
if (wc.OTGender != pkm.OT_Gender) continue;
if (wc.PIDType == 0 && pkm.PID != wc.PID) continue;
if (wc.PIDType == 2 && !pkm.IsShiny) continue;
if (wc.PIDType == 3 && pkm.IsShiny) continue;
if (wc.OriginGame != 0 && wc.OriginGame != pkm.Version) continue;
if (wc.EncryptionConstant != 0 && wc.EncryptionConstant != pkm.EncryptionConstant) continue;
if (wc.Language != 0 && wc.Language != pkm.Language) continue;
}
if (wc.Form != pkm.AltForm && vs.All(dl => !FormChange.Contains(dl.Species))) continue;
if (wc.MetLocation != pkm.Met_Location) continue;
if (wc.EggLocation != pkm.Egg_Location) continue;
if (wc.Level != pkm.Met_Level) continue;
if (wc.Ball != pkm.Ball) continue;
if (wc.OTGender < 3 && wc.OTGender != pkm.OT_Gender) continue;
if (wc.Nature != 0xFF && wc.Nature != pkm.Nature) continue;
if (wc.Gender != 3 && wc.Gender != pkm.Gender) continue;
if (wc.CNT_Cool > pkm.CNT_Cool) continue;
if (wc.CNT_Beauty > pkm.CNT_Beauty) continue;
if (wc.CNT_Cute > pkm.CNT_Cute) continue;
if (wc.CNT_Smart > pkm.CNT_Smart) continue;
if (wc.CNT_Tough > pkm.CNT_Tough) continue;
if (wc.CNT_Sheen > pkm.CNT_Sheen) continue;
// Some checks are best performed separately as they are caused by users screwing up valid data.
// if (!wc.RelearnMoves.SequenceEqual(pkm.RelearnMoves)) continue; // Defer to relearn legality
// if (wc.OT.Length > 0 && pkm.CurrentHandler != 1) continue; // Defer to ownership legality
// if (wc.OT.Length > 0 && pkm.OT_Friendship != PKX.getBaseFriendship(pkm.Species)) continue; // Friendship
// if (wc.Level > pkm.CurrentLevel) continue; // Defer to level legality
// RIBBONS: Defer to ribbon legality
validWC6.Add(wc);
}
return validWC6;
}
// Encounter
internal static EncounterLink getValidLinkGifts(PKM pkm)
{
return LinkGifts.FirstOrDefault(g => g.Species == pkm.Species && g.Level == pkm.Met_Level);
switch (pkm.GenNumber)
{
case 6:
return LinkGifts6.FirstOrDefault(g => g.Species == pkm.Species && g.Level == pkm.Met_Level);
default:
return null;
}
}
internal static EncounterSlot[] getValidWildEncounters(PKM pkm)
{
@ -295,8 +318,83 @@ namespace PKHeX
return slots.Any() ? slots.ToArray() : null;
}
// Generation Specific Fetching
private static Evolutions[] getEvolutionTable(PKM pkm)
{
switch (pkm.Format)
{
case 6:
return Evolves6;
case 7:
return Evolves7;
default:
return Evolves6;
}
}
internal static IEnumerable<MysteryGift> getValidGifts(PKM pkm)
{
switch (pkm.GenNumber)
{
case 6:
return getMatchingWC6(pkm);
default:
return null;
}
}
private static IEnumerable<MysteryGift> getMatchingWC6(PKM pkm)
{
List<MysteryGift> validWC6 = new List<MysteryGift>();
var vs = getValidPreEvolutions(pkm).ToArray();
foreach (WC6 wc in WC6DB.Where(wc => vs.Any(dl => dl.Species == wc.Species)))
{
if (pkm.Egg_Location == 0) // Not Egg
{
if (wc.CardID != pkm.SID) continue;
if (wc.TID != pkm.TID) continue;
if (wc.OT != pkm.OT_Name) continue;
if (wc.OTGender != pkm.OT_Gender) continue;
if (wc.PIDType == 0 && pkm.PID != wc.PID) continue;
if (wc.PIDType == 2 && !pkm.IsShiny) continue;
if (wc.PIDType == 3 && pkm.IsShiny) continue;
if (wc.OriginGame != 0 && wc.OriginGame != pkm.Version) continue;
if (wc.EncryptionConstant != 0 && wc.EncryptionConstant != pkm.EncryptionConstant) continue;
if (wc.Language != 0 && wc.Language != pkm.Language) continue;
}
if (wc.Form != pkm.AltForm && vs.All(dl => !FormChange.Contains(dl.Species))) continue;
if (wc.MetLocation != pkm.Met_Location) continue;
if (wc.EggLocation != pkm.Egg_Location) continue;
if (wc.Level != pkm.Met_Level) continue;
if (wc.Ball != pkm.Ball) continue;
if (wc.OTGender < 3 && wc.OTGender != pkm.OT_Gender) continue;
if (wc.Nature != 0xFF && wc.Nature != pkm.Nature) continue;
if (wc.Gender != 3 && wc.Gender != pkm.Gender) continue;
if (wc.CNT_Cool > pkm.CNT_Cool) continue;
if (wc.CNT_Beauty > pkm.CNT_Beauty) continue;
if (wc.CNT_Cute > pkm.CNT_Cute) continue;
if (wc.CNT_Smart > pkm.CNT_Smart) continue;
if (wc.CNT_Tough > pkm.CNT_Tough) continue;
if (wc.CNT_Sheen > pkm.CNT_Sheen) continue;
// Some checks are best performed separately as they are caused by users screwing up valid data.
// if (!wc.RelearnMoves.SequenceEqual(pkm.RelearnMoves)) continue; // Defer to relearn legality
// if (wc.OT.Length > 0 && pkm.CurrentHandler != 1) continue; // Defer to ownership legality
// if (wc.OT.Length > 0 && pkm.OT_Friendship != PKX.getBaseFriendship(pkm.Species)) continue; // Friendship
// if (wc.Level > pkm.CurrentLevel) continue; // Defer to level legality
// RIBBONS: Defer to ribbon legality
validWC6.Add(wc);
}
return validWC6;
}
internal static bool getDexNavValid(PKM pkm)
{
if (!pkm.AO || !pkm.InhabitedGeneration(6))
return false;
IEnumerable<EncounterArea> locs = getDexNavAreas(pkm);
return locs.Select(loc => getValidEncounterSlots(pkm, loc, DexNav: true)).Any(slots => slots.Any(slot => slot.AllowDexNav && slot.DexNav));
}
@ -306,7 +404,7 @@ namespace PKHeX
}
internal static bool getHasTradeEvolved(PKM pkm)
{
return Evolves[pkm.Species].Evos.Any(evo => evo.Level == 1); // 1: Trade, 0: Item, >=2: Levelup
return getEvolutionTable(pkm)[pkm.Species].Evos.Any(evo => evo.Level == 1); // 1: Trade, 0: Item, >=2: Levelup
}
internal static bool getIsFossil(PKM pkm)
{
@ -314,6 +412,7 @@ namespace PKHeX
return false;
if (pkm.Egg_Location != 0)
return false;
if (pkm.XY && pkm.Met_Location == 44)
return Fossils.Contains(getBaseSpecies(pkm));
if (pkm.AO && pkm.Met_Location == 190)
@ -334,50 +433,68 @@ namespace PKHeX
{
int species = pkm.Species;
List<int> res = new List<int>{species};
for (int i = 0; i < Evolves.Length; i++)
if (Evolves[i].Evos.Any(pk => pk.Species == species))
var table = getEvolutionTable(pkm);
for (int i = 0; i < table.Length; i++)
if (table[i].Evos.Any(pk => pk.Species == species))
res.Add(i);
for (int i = -1; i < 2; i++)
res.Add(getBaseSpecies(pkm, i));
return res.Distinct();
}
internal static bool getCanBeCaptured(int species, int version = -1)
internal static bool getCanBeCaptured(int species, int gen, int version = -1)
{
if (version < 0 || version == (int)GameVersion.X)
switch (gen)
{
if (SlotsX.Any(loc => loc.Slots.Any(slot => slot.Species == species)))
return true;
if (FriendSafari.Contains(species))
return true;
if (StaticX.Any(enc => enc.Species == species && !enc.Gift))
return true;
}
if (version < 0 || version == (int)GameVersion.Y)
{
if (SlotsY.Any(loc => loc.Slots.Any(slot => slot.Species == species)))
return true;
if (FriendSafari.Contains(species))
return true;
if (StaticY.Any(enc => enc.Species == species && !enc.Gift))
return true;
}
if (version < 0 || version == (int)GameVersion.AS)
{
if (SlotsA.Any(loc => loc.Slots.Any(slot => slot.Species == species)))
return true;
if (StaticA.Any(enc => enc.Species == species && !enc.Gift))
return true;
}
if (version < 0 || version == (int)GameVersion.OR)
{
if (SlotsO.Any(loc => loc.Slots.Any(slot => slot.Species == species)))
return true;
if (StaticO.Any(enc => enc.Species == species && !enc.Gift))
return true;
case 6:
switch (version)
{
case -1:
return getCanBeCaptured(species, SlotsX, StaticX, XY:true)
|| getCanBeCaptured(species, SlotsY, StaticY, XY:true)
|| getCanBeCaptured(species, SlotsA, StaticA)
|| getCanBeCaptured(species, SlotsO, StaticO);
case (int)GameVersion.X:
return getCanBeCaptured(species, SlotsX, StaticX, XY:true);
case (int)GameVersion.Y:
return getCanBeCaptured(species, SlotsY, StaticY, XY:true);
case (int)GameVersion.AS:
return getCanBeCaptured(species, SlotsA, StaticA);
case (int)GameVersion.OR:
return getCanBeCaptured(species, SlotsO, StaticO);
default:
return false;
}
case 7:
switch (version)
{
case -1:
return getCanBeCaptured(species, SlotsSN, StaticSN)
|| getCanBeCaptured(species, SlotsMN, StaticMN);
case (int)GameVersion.SN:
return getCanBeCaptured(species, SlotsSN, StaticSN);
case (int)GameVersion.MN:
return getCanBeCaptured(species, SlotsMN, StaticMN);
default:
return false;
}
}
return false;
}
private static bool getCanBeCaptured(int species, IEnumerable<EncounterArea> area, IEnumerable<EncounterStatic> statics, bool XY = false)
{
if (XY && FriendSafari.Contains(species))
return true;
if (area.Any(loc => loc.Slots.Any(slot => slot.Species == species)))
return true;
if (statics.Any(enc => enc.Species == species && !enc.Gift))
return true;
return false;
}
internal static bool getCanLearnMachineMove(PKM pkm, int move, int version = -1)
{
return getValidMoves(pkm, version, Machine: true).Contains(move);
@ -403,7 +520,10 @@ namespace PKHeX
return 290;
if (pkm.Species == 242 && pkm.CurrentLevel < 3) // Never Cleffa
return 113;
DexLevel[] evos = Evolves[pkm.Species].Evos;
Evolutions[] evotable = getEvolutionTable(pkm);
DexLevel[] evos = evotable[pkm.Species].Evos;
switch (skipOption)
{
case -1: return pkm.Species;
@ -413,29 +533,49 @@ namespace PKHeX
}
private static IEnumerable<EncounterArea> getDexNavAreas(PKM pkm)
{
bool alpha = pkm.Version == 26;
if (!alpha && pkm.Version != 27)
return new EncounterArea[0];
return (alpha ? SlotsA : SlotsO).Where(l => l.Location == pkm.Met_Location);
switch (pkm.Version)
{
case (int)GameVersion.AS:
return SlotsA.Where(l => l.Location == pkm.Met_Location);
case (int)GameVersion.OR:
return SlotsO.Where(l => l.Location == pkm.Met_Location);
default:
return new EncounterArea[0];
}
}
private static IEnumerable<int> getLVLMoves(int species, int lvl, int formnum)
private static IEnumerable<int> getLVLMoves(PKM pkm, int species, int lvl, int formnum)
{
int ind_XY = PersonalTable.XY.getFormeIndex(species, formnum);
int ind_AO = PersonalTable.AO.getFormeIndex(species, formnum);
return LevelUpXY[ind_XY].getMoves(lvl).Concat(LevelUpAO[ind_AO].getMoves(lvl));
List<int> moves = new List<int>();
if (pkm.InhabitedGeneration(6))
{
int ind_XY = PersonalTable.XY.getFormeIndex(species, formnum);
moves.AddRange(LevelUpXY[ind_XY].getMoves(lvl));
int ind_AO = PersonalTable.AO.getFormeIndex(species, formnum);
moves.AddRange(LevelUpAO[ind_AO].getMoves(lvl));
}
if (pkm.InhabitedGeneration(7))
{
int ind_SM = PersonalTable.SM.getFormeIndex(species, formnum);
moves.AddRange(LevelUpSM[ind_SM].getMoves(lvl));
}
return moves;
}
private static IEnumerable<EncounterArea> getEncounterSlots(PKM pkm)
{
switch (pkm.Version)
{
case 24: // X
case (int)GameVersion.X:
return getSlots(pkm, SlotsX);
case 25: // Y
case (int)GameVersion.Y:
return getSlots(pkm, SlotsY);
case 26: // AS
case (int)GameVersion.AS:
return getSlots(pkm, SlotsA);
case 27: // OR
case (int)GameVersion.OR:
return getSlots(pkm, SlotsO);
case (int)GameVersion.SN:
return getSlots(pkm, SlotsSN);
case (int)GameVersion.MN:
return getSlots(pkm, SlotsMN);
default: return new List<EncounterArea>();
}
}
@ -443,14 +583,18 @@ namespace PKHeX
{
switch (pkm.Version)
{
case 24: // X
case (int)GameVersion.X:
return getStatic(pkm, StaticX);
case 25: // Y
case (int)GameVersion.Y:
return getStatic(pkm, StaticY);
case 26: // AS
case (int)GameVersion.AS:
return getStatic(pkm, StaticA);
case 27: // OR
case (int)GameVersion.OR:
return getStatic(pkm, StaticO);
case (int)GameVersion.SN:
return getStatic(pkm, StaticSN);
case (int)GameVersion.MN:
return getStatic(pkm, StaticMN);
default: return new List<EncounterStatic>();
}
}
@ -462,6 +606,7 @@ namespace PKHeX
{
const int fluteBoost = 4;
const int dexnavBoost = 30;
int df = DexNav ? fluteBoost : 0;
int dn = DexNav ? fluteBoost + dexnavBoost : 0;
List<EncounterSlot> slotdata = new List<EncounterSlot>();
@ -533,7 +678,8 @@ namespace PKHeX
new DexLevel { Species = 292, Level = lvl },
new DexLevel { Species = 290, Level = lvl-1 }
};
var evos = Evolves[pkm.Species].Evos;
var table = getEvolutionTable(pkm);
var evos = table[pkm.Species].Evos;
List<DexLevel> dl = new List<DexLevel> { new DexLevel { Species = pkm.Species, Level = lvl } };
foreach (DexLevel evo in evos)
{
@ -555,76 +701,157 @@ namespace PKHeX
List<int> r = new List<int> { 0 };
int species = pkm.Species;
int lvl = pkm.CurrentLevel;
bool ORASTutors = Version == -1 || pkm.AO || !pkm.IsUntraded;
// Special (non Type) Tutor Availability
bool moveTutor = Version == -1 || pkm.Format != pkm.GenNumber;
// Add extra cases where tutors
moveTutor |= pkm.AO;
moveTutor |= pkm.XY && !pkm.IsUntraded;
moveTutor |= pkm.Format < 6;
if (FormChangeMoves.Contains(species)) // Deoxys & Shaymin & Giratina (others don't have extra but whatever)
{
int formcount = PersonalTable.AO[species].FormeCount;
int formcount = pkm.PersonalInfo.FormeCount;
for (int i = 0; i < formcount; i++)
r.AddRange(getMoves(species, lvl, i, ORASTutors, Version, LVL, Tutor, Machine));
r.AddRange(getMoves(pkm, species, lvl, i, moveTutor, Version, LVL, Tutor, Machine));
if (Relearn) r.AddRange(pkm.RelearnMoves);
return r.Distinct().ToArray();
}
r.AddRange(getMoves(species, lvl, pkm.AltForm, ORASTutors, Version, LVL, Tutor, Machine));
r.AddRange(getMoves(pkm, species, lvl, pkm.AltForm, moveTutor, Version, LVL, Tutor, Machine));
IEnumerable<DexLevel> vs = getValidPreEvolutions(pkm);
foreach (DexLevel evo in vs)
r.AddRange(getMoves(evo.Species, evo.Level, pkm.AltForm, ORASTutors, Version, LVL, Tutor, Machine));
r.AddRange(getMoves(pkm, evo.Species, evo.Level, pkm.AltForm, moveTutor, Version, LVL, Tutor, Machine));
if (species == 479) // Rotom
r.Add(RotomMoves[pkm.AltForm]);
if (species == 25) // Pikachu
if (species == 25 && pkm.Format == 6) // Pikachu
r.Add(PikachuMoves[pkm.AltForm]);
if (Relearn) r.AddRange(pkm.RelearnMoves);
return r.Distinct().ToArray();
}
private static IEnumerable<int> getMoves(int species, int lvl, int form, bool ORASTutors, int Version, bool LVL, bool Tutor, bool Machine)
private static IEnumerable<int> getMoves(PKM pkm, int species, int lvl, int form, bool moveTutor, int Version, bool LVL, bool Tutor, bool Machine)
{
List<int> r = new List<int> { 0 };
if (Version < 0 || Version == 0)
{
int index = PersonalTable.XY.getFormeIndex(species, form);
PersonalInfo pi = PersonalTable.XY.getFormeEntry(species, form);
for (int gen = pkm.GenNumber; gen <= pkm.Format; gen++)
r.AddRange(getMoves(pkm, species, lvl, form, moveTutor, Version, LVL, Tutor, Machine, gen));
return r.Distinct();
}
private static IEnumerable<int> getMoves(PKM pkm, int species, int lvl, int form, bool moveTutor, int Version, bool LVL, bool Tutor, bool Machine, int Generation)
{
List<int> r = new List<int>();
if (LVL) r.AddRange(LevelUpXY[index].getMoves(lvl));
if (Tutor) r.AddRange(getTutorMoves(species, form, ORASTutors));
if (Machine) r.AddRange(TMHM_XY.Where((t, m) => pi.TMHM[m]));
}
if (Version < 0 || Version == 1)
var ver = (GameVersion) Version;
switch (Generation)
{
int index = PersonalTable.AO.getFormeIndex(species, form);
PersonalInfo pi = PersonalTable.AO.getFormeEntry(species, form);
case 6:
switch (ver)
{
case GameVersion.Any: // Start at the top, hit every table
case GameVersion.X: case GameVersion.Y: case GameVersion.XY:
{
int index = PersonalTable.XY.getFormeIndex(species, form);
PersonalInfo pi = PersonalTable.XY.getFormeEntry(species, form);
if (LVL) r.AddRange(LevelUpAO[index].getMoves(lvl));
if (Tutor) r.AddRange(getTutorMoves(species, form, ORASTutors));
if (Machine) r.AddRange(TMHM_AO.Where((t, m) => pi.TMHM[m]));
if (LVL) r.AddRange(LevelUpXY[index].getMoves(lvl));
if (moveTutor) r.AddRange(getTutorMoves(pkm, species, form, Tutor));
if (Machine) r.AddRange(TMHM_XY.Where((t, m) => pi.TMHM[m]));
if (ver == GameVersion.Any) // Fall Through
goto case GameVersion.ORAS;
break;
}
case GameVersion.AS: case GameVersion.OR: case GameVersion.ORAS:
{
int index = PersonalTable.AO.getFormeIndex(species, form);
PersonalInfo pi = PersonalTable.AO.getFormeEntry(species, form);
if (LVL) r.AddRange(LevelUpAO[index].getMoves(lvl));
if (moveTutor) r.AddRange(getTutorMoves(pkm, species, form, Tutor));
if (Machine) r.AddRange(TMHM_AO.Where((t, m) => pi.TMHM[m]));
break;
}
}
break;
case 7:
switch (ver)
{
case GameVersion.Any:
case GameVersion.SN: case GameVersion.MN: case GameVersion.SM:
{
int index = PersonalTable.SM.getFormeIndex(species, form);
PersonalInfo pi = PersonalTable.SM.getFormeEntry(species, form);
if (LVL) r.AddRange(LevelUpSM[index].getMoves(lvl));
if (moveTutor) r.AddRange(getTutorMoves(pkm, species, form, Tutor));
if (Machine) r.AddRange(TMHM_SM.Where((t, m) => pi.TMHM[m]));
break;
}
}
break;
default:
return r;
}
return r;
}
private static IEnumerable<int> getEggMoves(int species, int formnum)
private static IEnumerable<int> getEggMoves(PKM pkm, int species, int formnum)
{
int ind_XY = PersonalTable.XY.getFormeIndex(species, formnum);
int ind_AO = PersonalTable.AO.getFormeIndex(species, formnum);
return EggMoveAO[ind_AO].Moves.Concat(EggMoveXY[ind_XY].Moves);
}
private static IEnumerable<int> getTutorMoves(int species, int formnum, bool ORASTutors)
{
PersonalInfo pkAO = PersonalTable.AO.getFormeEntry(species, formnum);
switch (pkm.GenNumber)
{
case 6:
int ind_XY = PersonalTable.XY.getFormeIndex(species, formnum);
int ind_AO = PersonalTable.AO.getFormeIndex(species, formnum);
return EggMoveAO[ind_AO].Moves.Concat(EggMoveXY[ind_XY].Moves);
case 7:
int ind_SM = PersonalTable.SM.getFormeIndex(species, formnum);
return EggMoveSM[ind_SM].Moves;
default:
return new List<int>();
}
}
private static IEnumerable<int> getTutorMoves(PKM pkm, int species, int form, bool Tutors)
{
PersonalInfo info = pkm.PersonalInfo;
// Type Tutor
List<int> moves = TypeTutor.Where((t, i) => pkAO.TypeTutors[i]).ToList();
List<int> moves = TypeTutor.Where((t, i) => info.TypeTutors[i]).ToList();
// Varied Tutors
if (ORASTutors)
for (int i = 0; i < Tutors_AO.Length; i++)
for (int b = 0; b < Tutors_AO[i].Length; b++)
if (pkAO.SpecialTutors[i][b])
moves.Add(Tutors_AO[i][b]);
//if (pkm.InhabitedGeneration(5) && Tutors)
//{
// //PersonalInfo pi = PersonalTable.B2W2.getFormeEntry(species, form);
// //for (int i = 0; i < Tutors_B2W2.Length; i++)
// // for (int b = 0; b < Tutors_B2W2[i].Length; b++)
// // if (pi.SpecialTutors[i][b])
// // moves.Add(Tutors_B2W2[i][b]);
//}
if (pkm.InhabitedGeneration(6) && Tutors)
{
PersonalInfo pi = PersonalTable.AO.getFormeEntry(species, form);
for (int i = 0; i < Tutors_AO.Length; i++)
for (int b = 0; b < Tutors_AO[i].Length; b++)
if (pi.SpecialTutors[i][b])
moves.Add(Tutors_AO[i][b]);
}
//if (pkm.InhabitedGeneration(7) && Tutors)
//{
// //PersonalInfo pi = PersonalTable.SM.getFormeEntry(species, form);
// //for (int i = 0; i < Tutors_SM.Length; i++)
// // for (int b = 0; b < Tutors_SM[i].Length; b++)
// // if (pi.SpecialTutors[i][b])
// // moves.Add(Tutors_SM[i][b]);
//}
// Keldeo - Secret Sword
if (species == 647)
moves.Add(548);
return moves;
return moves.Distinct();
}
}
}