Misc style & minor tweaks

Remove move combobox flicker hack (no longer necessary)
Add more Array.Empty usages
cache mysterygift sizes
seal some classes

no functionality changes
This commit is contained in:
Kurt 2018-08-02 20:11:42 -07:00
parent 0745ba3294
commit 1486b7f14a
68 changed files with 987 additions and 239 deletions

View file

@ -34,6 +34,9 @@ namespace PKHeX.Core
public IReadOnlyList<string> Natures => natures;
private string[] Get(string ident) => GameInfo.GetStrings(ident, lang);
private const string NPC = "NPC";
private static readonly string[] abilIdentifier = { " (1)", " (2)", " (H)" };
private static readonly IReadOnlyList<ComboItem> LanguageList = Util.GetUnsortedCBList("languages");
public GameStrings(string l)
{
@ -63,12 +66,7 @@ namespace PKHeX.Core
metGSC_00000 = Get("gsc_00000");
metCXD_00000 = Get("cxd_00000");
// Sanitize a little
var metSanitize = (string[])metCXD_00000.Clone();
for (int i = 0; i < metSanitize.Length; i++)
if (metCXD_00000.Count(r => r == metSanitize[i]) > 1)
metSanitize[i] += $" [{i:000}]";
metCXD_00000 = metSanitize;
metCXD_00000 = SanitizeMetStringsCXD(metCXD_00000);
// Current Generation strings
natures = Util.GetNaturesList(l);
@ -127,7 +125,19 @@ namespace PKHeX.Core
InitializeDataSources();
}
private const string NPC = "NPC";
private static string[] SanitizeMetStringsCXD(string[] cxd)
{
// Mark duplicate locations with their index
var metSanitize = (string[])cxd.Clone();
for (int i = 0; i < metSanitize.Length; i++)
{
if (cxd.Count(r => r == metSanitize[i]) > 1)
metSanitize[i] += $" [{i:000}]";
}
return metSanitize;
}
private void Sanitize()
{
SanitizeItemNames();
@ -139,6 +149,7 @@ namespace PKHeX.Core
var none = $"({itemlist[0]})";
abilitylist[0] = itemlist[0] = movelist[0] = metXY_00000[0] = metBW2_00000[0] = metHGSS_00000[0] = metCXD_00000[0] = puffs[0] = none;
}
private void SanitizeItemNames()
{
// Fix Item Names (Duplicate entries)
@ -175,6 +186,7 @@ namespace PKHeX.Core
for (int i = 12; i <= 29; i++) // Differentiate DNA Samples
g3coloitems[500 + i] += $" ({i - 11:00})";
}
private void SanitizeMetLocations()
{
// Fix up some of the Location strings to make them more descriptive
@ -182,6 +194,7 @@ namespace PKHeX.Core
SanitizeMetG6XY();
SanitizeMetG7SM();
}
private void SanitizeMetG5BW()
{
metHGSS_02000[1] += $" ({NPC})"; // Anything from an NPC
@ -210,6 +223,7 @@ namespace PKHeX.Core
metBW2_60000[3 - 1] += $" ({eggname})"; // Egg Treasure Hunter/Breeder, whatever...
}
private void SanitizeMetG6XY()
{
metXY_00000[104] += " (X/Y)"; // Victory Road
@ -219,6 +233,7 @@ namespace PKHeX.Core
metXY_30000[0] += $" ({NPC})"; // Anything from an NPC
metXY_30000[1] += $" ({eggname})"; // Egg From Link Trade
}
private void SanitizeMetG7SM()
{
// Sun/Moon duplicates -- elaborate!
@ -252,6 +267,7 @@ namespace PKHeX.Core
default: return itemlist;
}
}
private string[] GetItemStrings3(GameVersion game)
{
switch (game)
@ -387,6 +403,7 @@ namespace PKHeX.Core
var items = GetItemStrings(generation, game);
ItemDataSource = Util.GetCBList(items, (allowed == null || HaX ? Enumerable.Range(0, MaxItemID) : allowed.Select(i => (int)i)).ToArray());
}
public IReadOnlyList<ComboItem> GetLocationList(GameVersion Version, int SaveFormat, bool egg)
{
if (SaveFormat == 2)
@ -471,19 +488,22 @@ namespace PKHeX.Core
// Currently on a future game, return corresponding list for generation
if (Version <= GameVersion.CXD && SaveFormat == 4)
{
return MetGen4.Where(loc => loc.Value == Legal.Transfer3) // Pal Park to front
.Concat(MetGen4.Take(4))
.Concat(MetGen4.Skip(4).Where(loc => loc.Value != Legal.Transfer3)).ToList();
.Concat(MetGen4.Take(4))
.Concat(MetGen4.Skip(4).Where(loc => loc.Value != Legal.Transfer3)).ToList();
}
if (Version < GameVersion.X && SaveFormat >= 5) // PokéTransfer to front
{
return MetGen5.Where(loc => loc.Value == Legal.Transfer4)
.Concat(MetGen5.Take(3))
.Concat(MetGen5.Skip(3).Where(loc => loc.Value != Legal.Transfer4)).ToList();
.Concat(MetGen5.Take(3))
.Concat(MetGen5.Skip(3).Where(loc => loc.Value != Legal.Transfer4)).ToList();
}
return MetGen6;
}
private static readonly IReadOnlyList<ComboItem> LanguageList = Util.GetUnsortedCBList("languages");
public static IReadOnlyList<ComboItem> LanguageDataSource(int gen)
{
var languages = LanguageList.ToList();
@ -494,14 +514,13 @@ namespace PKHeX.Core
return languages;
}
private static readonly string[] abilIdentifier = { " (1)", " (2)", " (H)" };
public IReadOnlyList<ComboItem> GetAbilityDataSource(IEnumerable<int> abils)
{
return abils.Select(GetItem).ToList();
ComboItem GetItem(int ability, int index) => new ComboItem
{
Value = ability,
Text = GameInfo.Strings.abilitylist[ability] + abilIdentifier[index]
Text = abilitylist[ability] + abilIdentifier[index]
};
}
}

View file

@ -7,6 +7,7 @@ namespace PKHeX.Core
public class MemoryStrings
{
private readonly GameStrings s;
public MemoryStrings(GameStrings strings)
{
s = strings;
@ -30,7 +31,6 @@ namespace PKHeX.Core
public List<ComboItem> SpecificLocations => specific.Value;
public List<ComboItem> Species => species.Value;
private List<ComboItem> GetMemories()
{
// Memory Chooser
@ -47,7 +47,6 @@ namespace PKHeX.Core
return Util.GetOffsetCBList(memory_list1, mems, 0, allowed);
}
public List<string> GetMemoryQualities()
{
List<string> list = new List<string>();
@ -55,6 +54,7 @@ namespace PKHeX.Core
list.Add(s.memories[2 + i]);
return list;
}
public List<string> GetMemoryFeelings()
{
List<string> list = new List<string>();

View file

@ -10,19 +10,19 @@ namespace PKHeX.Core
public static class EncounterEvent
{
/// <summary>Event Database for Generation 3</summary>
public static MysteryGift[] MGDB_G3 { get; private set; } = new MysteryGift[0];
public static MysteryGift[] MGDB_G3 { get; private set; } = Array.Empty<MysteryGift>();
/// <summary>Event Database for Generation 4</summary>
public static MysteryGift[] MGDB_G4 { get; private set; } = new MysteryGift[0];
public static MysteryGift[] MGDB_G4 { get; private set; } = Array.Empty<MysteryGift>();
/// <summary>Event Database for Generation 5</summary>
public static MysteryGift[] MGDB_G5 { get; private set; } = new MysteryGift[0];
public static MysteryGift[] MGDB_G5 { get; private set; } = Array.Empty<MysteryGift>();
/// <summary>Event Database for Generation 6</summary>
public static MysteryGift[] MGDB_G6 { get; private set; } = new MysteryGift[0];
public static MysteryGift[] MGDB_G6 { get; private set; } = Array.Empty<MysteryGift>();
/// <summary>Event Database for Generation 7</summary>
public static MysteryGift[] MGDB_G7 { get; private set; } = new MysteryGift[0];
public static MysteryGift[] MGDB_G7 { get; private set; } = Array.Empty<MysteryGift>();
/// <summary>Indicates if the databases are initialized.</summary>
public static bool Initialized => MGDB_G3.Length != 0;
@ -36,6 +36,7 @@ namespace PKHeX.Core
yield return data;
}
}
private static HashSet<MysteryGift> GetPCDDB(byte[] bin) => new HashSet<MysteryGift>(GetData(bin, PCD.Size).Select(d => new PCD(d)));
private static HashSet<MysteryGift> GetPGFDB(byte[] bin) => new HashSet<MysteryGift>(GetData(bin, PGF.Size).Select(d => new PGF(d)));
@ -56,19 +57,21 @@ namespace PKHeX.Core
var g7 = GetWC7DB(Util.GetBinaryResource("wc7.pkl"), Util.GetBinaryResource("wc7full.pkl"));
foreach (var path in paths.Where(Directory.Exists))
foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
{
var fi = new FileInfo(file);
if (!MysteryGift.IsMysteryGift(fi.Length))
continue;
var gift = MysteryGift.GetMysteryGift(File.ReadAllBytes(file), fi.Extension);
switch (gift?.Format)
foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
{
case 4: g4.Add(gift); continue;
case 5: g5.Add(gift); continue;
case 6: g6.Add(gift); continue;
case 7: g7.Add(gift); continue;
var fi = new FileInfo(file);
if (!MysteryGift.IsMysteryGift(fi.Length))
continue;
var gift = MysteryGift.GetMysteryGift(File.ReadAllBytes(file), fi.Extension);
switch (gift?.Format)
{
case 4: g4.Add(gift); continue;
case 5: g5.Add(gift); continue;
case 6: g6.Add(gift); continue;
case 7: g7.Add(gift); continue;
}
}
}

View file

@ -80,9 +80,12 @@ namespace PKHeX.Core
internal static void MarkEncountersStaticMagnetPull(IEnumerable<EncounterArea> Areas, PersonalTable t)
{
foreach (EncounterArea Area in Areas)
foreach (var grp in Area.Slots.GroupBy(z => z.Type))
MarkEncountersStaticMagnetPull(grp, t);
{
foreach (var grp in Area.Slots.GroupBy(z => z.Type))
MarkEncountersStaticMagnetPull(grp, t);
}
}
internal static void MarkEncountersStaticMagnetPull(IEnumerable<EncounterSlot> grp, PersonalTable t)
{
GetStaticMagnet(t, grp, out List<EncounterSlot> s, out List<EncounterSlot> m);
@ -99,6 +102,7 @@ namespace PKHeX.Core
slot.Permissions.MagnetPullCount = m.Count;
}
}
internal static void MarkEncountersStaticMagnetPullPermutation(IEnumerable<EncounterSlot> grp, PersonalTable t, List<EncounterSlot> permuted)
{
GetStaticMagnet(t, grp, out List<EncounterSlot> s, out List<EncounterSlot> m);
@ -137,6 +141,7 @@ namespace PKHeX.Core
slot.Permissions.MagnetPullCount = m.Count;
}
}
private static void GetStaticMagnet(PersonalTable t, IEnumerable<EncounterSlot> grp, out List<EncounterSlot> s, out List<EncounterSlot> m)
{
const int steel = (int)MoveType.Steel;
@ -162,8 +167,10 @@ namespace PKHeX.Core
internal static void MarkEncountersVersion(IEnumerable<EncounterArea> Areas, GameVersion Version)
{
foreach (EncounterArea Area in Areas)
foreach (var Slot in Area.Slots.OfType<EncounterSlot1>())
Slot.Version = Version;
{
foreach (var Slot in Area.Slots)
Slot.Version = Version;
}
}
/// <summary>
@ -185,9 +192,12 @@ namespace PKHeX.Core
internal static void MarkEncountersGeneration(int Generation, params IEnumerable<EncounterArea>[] Areas)
{
foreach (var table in Areas)
foreach (var area in table)
MarkEncountersGeneration(Generation, area.Slots);
{
foreach (var area in table)
MarkEncountersGeneration(Generation, area.Slots);
}
}
private static void MarkEncountersGeneration(int Generation, IEnumerable<IGeneration> Encounters)
{
foreach (IGeneration enc in Encounters)
@ -215,11 +225,14 @@ namespace PKHeX.Core
foreach (var area in areas)
MarkEncounterAreas(area);
}
private static void MarkEncounterAreas(params EncounterArea[] areas)
{
foreach (var area in areas)
foreach (var slot in area.Slots)
slot.Area = area;
{
foreach (var slot in area.Slots)
slot.Area = area;
}
}
internal static EncounterStatic Clone(this EncounterStatic s, int location)
@ -228,6 +241,7 @@ namespace PKHeX.Core
result.Location = location;
return result;
}
internal static EncounterStatic[] Clone(this EncounterStatic s, int[] locations)
{
EncounterStatic[] Encounters = new EncounterStatic[locations.Length];
@ -235,11 +249,13 @@ namespace PKHeX.Core
Encounters[i] = s.Clone(locations[i]);
return Encounters;
}
internal static IEnumerable<EncounterStatic> DreamRadarClone(this EncounterStatic s)
{
for (int i = 0; i < 8; i++)
yield return s.DreamRadarClone(5 * i + 5); // Level from 5->40 depends on the number of badges
yield return s.DreamRadarClone((5 * i) + 5); // Level from 5->40 depends on the number of badges
}
private static EncounterStatic DreamRadarClone(this EncounterStatic s, int level)
{
var result = s.Clone(level);

View file

@ -52,8 +52,11 @@ namespace PKHeX.Core
table[table.Length - 1] = FishOldGood_RBY;
foreach (var arr in table)
foreach (var slot in arr.Slots)
slot.Area = arr;
{
foreach (var slot in arr.Slots)
slot.Area = arr;
}
return table;
}
@ -197,6 +200,7 @@ namespace PKHeX.Core
new EncounterTrade { Species = 051, Level = 05, Version = GameVersion.RBY }, // Dugtrio - Trade Lickitung (GSC 5)
new EncounterTrade { Species = 047, Level = 05, Version = GameVersion.RBY }, // Parasect - Trade Tangela (GSC 5)
}).ToArray();
private static readonly EncounterArea FishOldGood_RBY = new EncounterArea
{
Location = -1,

View file

@ -44,7 +44,7 @@ namespace PKHeX.Core
// Fishing
var f = EncounterArea.GetArray2_F(Util.GetBinaryResource("encounter_gsc_f.pkl"));
EncounterArea[] Slots = new EncounterArea[0];
var Slots = Array.Empty<EncounterArea>();
if (Version.Contains(GameVersion.GS))
Slots = GetSlots_GS(f);
if (Version.Contains(GameVersion.C))
@ -265,6 +265,7 @@ namespace PKHeX.Core
new EncounterTrade { Species = 021, Level = 10, TID = 01001, Moves = new[] {64,45,43} }, // Spearow @ Goldenrod City for free
new EncounterTrade { Species = 213, Level = 15, TID = 00518 }, // Shuckle @ Cianwood City for free
};
internal static readonly string[][] TradeGift_GSC_OTs =
{
new string[0], // 0 - None

View file

@ -92,8 +92,10 @@ namespace PKHeX.Core
private static void MarkG3SlotsSafariZones(ref EncounterArea[] Areas, int location)
{
foreach (EncounterArea Area in Areas.Where(a => a.Location == location))
foreach (EncounterSlot Slot in Area.Slots)
Slot.Type |= SlotType.Safari;
{
foreach (EncounterSlot Slot in Area.Slots)
Slot.Type |= SlotType.Safari;
}
}
private static readonly int[] Roaming_MetLocation_FRLG =
@ -113,6 +115,7 @@ namespace PKHeX.Core
36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49,
};
private static readonly EncounterStatic[] Encounter_RSE_Roam =
{
new EncounterStatic { Species = 380, Level = 40, Version = GameVersion.S, Roaming = true }, // Latias
@ -120,6 +123,7 @@ namespace PKHeX.Core
new EncounterStatic { Species = 381, Level = 40, Version = GameVersion.R, Roaming = true }, // Latios
new EncounterStatic { Species = 381, Level = 40, Version = GameVersion.E, Roaming = true }, // Latios
};
private static readonly EncounterStatic[] Encounter_RSE_Regular =
{
// Starters
@ -173,6 +177,7 @@ namespace PKHeX.Core
new EncounterStatic { Species = 244, Level = 50, Roaming = true, }, // Entei
new EncounterStatic { Species = 245, Level = 50, Roaming = true, }, // Suicune
};
private static readonly EncounterStatic[] Encounter_FRLG_Stationary =
{
// Starters @ Pallet Town
@ -233,6 +238,7 @@ namespace PKHeX.Core
private static readonly int[] TradeContest_Cute = { 05, 05, 30, 05, 05, 10 };
private static readonly int[] TradeContest_Clever = { 05, 05, 05, 30, 05, 10 };
private static readonly int[] TradeContest_Tough = { 05, 05, 05, 05, 30, 10 };
internal static readonly EncounterTrade[] TradeGift_RSE =
{
new EncounterTradePID { Species = 296, Ability = 2, TID = 49562, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {5,5,4,4,4,4}, Level = 05, PID = 0x00009C40, Contest = TradeContest_Tough, Version = GameVersion.RS, }, // Slakoth (Level 5 Breeding) -> Makuhita
@ -244,6 +250,7 @@ namespace PKHeX.Core
new EncounterTradePID { Species = 052, Ability = 1, TID = 25945, SID = 00001, OTGender = 1, Gender = 0, IVs = new[] {4,5,4,5,4,4}, Level = 03, PID = 0x0000008B, Contest = TradeContest_Clever, Version = GameVersion.E, }, // Skitty (Level 3 Trade)-> Meowth*
// If Pokémon with * is evolved in a Generation IV or V game, its Ability will become its second Ability.
};
internal static readonly EncounterTrade[] TradeGift_FRLG =
{
new EncounterTradePID { Species = 122, Ability = 1, TID = 01985, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {20,15,17,24,23,22}, PID = 0x00009CAE, Contest = TradeContest_Clever, }, // Mr. Mime
@ -259,6 +266,7 @@ namespace PKHeX.Core
new EncounterTradePID { Species = 086, Ability = 1, TID = 09853, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {24,15,22,16,23,22}, PID = 0x482CAC89, Contest = TradeContest_Tough, }, // Seel *
// If Pokémon with * is evolved in a Generation IV or V game, its Ability will become its second Ability.
};
internal static readonly string[][] TradeRSE =
{
new string[0], // 0 - None
@ -270,6 +278,7 @@ namespace PKHeX.Core
new string[0], // 6 - None
Util.GetStringList("traderse", "es"), // 7
};
internal static readonly string[][] TradeFRLG =
{
new string[0], // 0 - None
@ -331,6 +340,7 @@ namespace PKHeX.Core
new EncounterSlot { Species = 349, LevelMin = 20, LevelMax = 25, Type = SlotType.Swarm } // Feebas with any Rod (50%)
},},
};
private static readonly EncounterArea[] SlotsFRLGUnown =
{
GetUnownArea(188, new[] { 00,00,00,00,00,00,00,00,00,00,00,26 }), // 188 = Monean Chamber
@ -341,6 +351,7 @@ namespace PKHeX.Core
GetUnownArea(193, new[] { 21,21,21,22,22,22,23,23,12,12,01,01 }), // 193 = Rixy Chamber
GetUnownArea(194, new[] { 25,25,25,25,25,25,25,25,25,25,25,27 }), // 194 = Viapois Chamber
};
private static EncounterArea GetUnownArea(int location, IReadOnlyList<int> SlotForms)
{
return new EncounterArea
@ -612,7 +623,9 @@ namespace PKHeX.Core
}
},
};
internal static readonly EncounterStatic[] Encounter_CXD = ConcatAll(Encounter_Colo, Encounter_XD);
private static IEnumerable<EncounterStatic> CloneMirorB(EncounterStatic arg)
{
yield return arg;

View file

@ -150,7 +150,7 @@ namespace PKHeX.Core
MarkHGSSEncounterTypeSlots_MultipleTypes(SS_Slots, Cianwood, EncounterType.RockSmash);
}
private static void MarkG4PokeWalker(EncounterStatic[] t)
private static void MarkG4PokeWalker(IEnumerable<EncounterStatic> t)
{
foreach (EncounterStatic s in t)
{
@ -159,13 +159,17 @@ namespace PKHeX.Core
s.Version = GameVersion.HGSS;
}
}
private static void MarkG4SlotsGreatMarsh(EncounterArea[] Areas, int location)
private static void MarkG4SlotsGreatMarsh(IEnumerable<EncounterArea> Areas, int location)
{
foreach (EncounterArea Area in Areas.Where(a => a.Location == location))
foreach (EncounterSlot Slot in Area.Slots)
Slot.Type |= SlotType.Safari;
{
foreach (EncounterSlot Slot in Area.Slots)
Slot.Type |= SlotType.Safari;
}
}
private static void MarkG4SwarmSlots(EncounterArea[] Areas, EncounterArea[] SwarmAreas)
private static void MarkG4SwarmSlots(IEnumerable<EncounterArea> Areas, EncounterArea[] SwarmAreas)
{
// Grass Swarm slots replace slots 0 and 1 from encounters data
// for surfing only replace slots 0 from encounters data
@ -192,14 +196,18 @@ namespace PKHeX.Core
Area.Slots = Area.Slots.Concat(OutputSlots).Where(a => a.Species > 0).ToArray();
}
}
// Gen 4 raw encounter data does not contains info for alt slots
// Shellos and Gastrodom East Sea form should be modified
private static void MarkG4AltFormSlots(EncounterArea[] Areas, int Species, int form, int[] Locations)
private static void MarkG4AltFormSlots(IEnumerable<EncounterArea> Areas, int Species, int form, int[] Locations)
{
foreach (EncounterArea Area in Areas.Where(a => Locations.Contains(a.Location)))
foreach (EncounterSlot Slot in Area.Slots.Where(s => s.Species == Species))
Slot.Form = form;
{
foreach (EncounterSlot Slot in Area.Slots.Where(s => s.Species == Species))
Slot.Form = form;
}
}
private static EncounterType GetEncounterTypeBySlotDPPt(SlotType Type, EncounterType GrassType)
{
switch (Type)
@ -221,6 +229,7 @@ namespace PKHeX.Core
}
return EncounterType.None;
}
private static EncounterType GetEncounterTypeBySlotHGSS(SlotType Type, EncounterType GrassType, EncounterType HeadbuttType)
{
switch (Type)
@ -254,6 +263,7 @@ namespace PKHeX.Core
}
return EncounterType.None;
}
private static void MarkDPPtEncounterTypeSlots_MultipleTypes(EncounterArea[] Areas, int Location, EncounterType NormalEncounterType, params int[] SpecialEncounterFiles)
{
var numfile = 0;
@ -267,6 +277,7 @@ namespace PKHeX.Core
}
}
}
private static void MarkHGSSEncounterTypeSlots_MultipleTypes(EncounterArea[] Areas, int Location, EncounterType NormalEncounterType, params int[] SpecialEncounterFile)
{
// Area with two different encounter type for grass encounters
@ -283,6 +294,7 @@ namespace PKHeX.Core
}
}
}
private static void MarkDPPtEncounterTypeSlots(EncounterArea[] Areas)
{
foreach (EncounterArea Area in Areas)
@ -299,6 +311,7 @@ namespace PKHeX.Core
}
}
}
private static EncounterType GetHeadbuttEncounterType(int Location)
{
if (Location == 195 || Location == 196) // Route 47/48
@ -306,24 +319,32 @@ namespace PKHeX.Core
// Routes with trees adjacent to water tiles
var allowsurf = HGSS_SurfingHeadbutt_Locations.Contains(Location);
// Cities
if (HGSS_CityLocations.Contains(Location))
{
return allowsurf
? EncounterType.Building_EnigmaStone | EncounterType.Surfing_Fishing
: EncounterType.Building_EnigmaStone;
}
// Caves with no exterior zones
if (!HGSS_MixInteriorExteriorLocations.Contains(Location) && HGSS_CaveLocations.Contains(Location))
{
return allowsurf
? EncounterType.Cave_HallOfOrigin | EncounterType.Surfing_Fishing
: EncounterType.Cave_HallOfOrigin;
}
// Routes and exterior areas
// Routes with trees adjacent to grass tiles
var allowgrass = HGSS_GrassHeadbutt_Locations.Contains(Location);
if (allowgrass)
{
return allowsurf
? EncounterType.TallGrass | EncounterType.Surfing_Fishing
: EncounterType.TallGrass;
}
return allowsurf
? EncounterType.Surfing_Fishing
@ -364,12 +385,14 @@ namespace PKHeX.Core
69, // Iron Island
84, // Stark Mountain
};
private static readonly HashSet<int> DPPt_MixInteriorExteriorLocations = new HashSet<int>
{
24, // Route 209 (Lost Tower)
50, // Mt Coronet
84, // Stark Mountain
};
private static readonly int[] DPPt_MtCoronetExteriorEncounters =
{
4, 5, 70
@ -461,6 +484,7 @@ namespace PKHeX.Core
192, // Route 44
214, // Ilex Forest
};
/// <summary>
/// Locations with headbutt trees accessible from tall grass tiles
/// </summary>
@ -502,15 +526,18 @@ namespace PKHeX.Core
219, // Mt. Silver Cave
224, // Viridian Forest
};
private static readonly int[] HGSS_MtSilverCaveExteriorEncounters =
{
2, 3
};
private static readonly int[] HGSS_MixInteriorExteriorLocations =
{
209, // Ruins of Alph
219, // Mt. Silver Cave
};
#endregion
#region Pokéwalker Encounter
// all pkm are in Poke Ball and have a met location of "PokeWalker"
@ -694,6 +721,7 @@ namespace PKHeX.Core
47, // Valley Windworks
49, // Fuego Ironworks
};
private static readonly int[] Roaming_MetLocation_DPPt_Surf =
{
// Routes 203-205, 208-210, 212-214, 218-222 can be encountered in water
@ -702,6 +730,7 @@ namespace PKHeX.Core
47, // Valley Windworks
49, // Fuego Ironworks
};
private static readonly EncounterStaticTyped[] Encounter_DPPt_Roam_Grass =
{
new EncounterStaticTyped { Species = 481, Level = 50, Roaming = true, TypeEncounter = EncounterType.TallGrass }, // Mesprit
@ -710,6 +739,7 @@ namespace PKHeX.Core
new EncounterStaticTyped { Species = 145, Level = 60, Roaming = true, TypeEncounter = EncounterType.TallGrass, Version = GameVersion.Pt }, // Zapdos
new EncounterStaticTyped { Species = 146, Level = 60, Roaming = true, TypeEncounter = EncounterType.TallGrass, Version = GameVersion.Pt }, // Moltres
};
private static readonly EncounterStaticTyped[] Encounter_DPPt_Roam_Surf =
{
new EncounterStaticTyped { Species = 481, Level = 50, Roaming = true, TypeEncounter = EncounterType.Surfing_Fishing }, // Mesprit
@ -718,6 +748,7 @@ namespace PKHeX.Core
new EncounterStaticTyped { Species = 145, Level = 60, Roaming = true, TypeEncounter = EncounterType.Surfing_Fishing, Version = GameVersion.Pt }, // Zapdos
new EncounterStaticTyped { Species = 146, Level = 60, Roaming = true, TypeEncounter = EncounterType.Surfing_Fishing, Version = GameVersion.Pt }, // Moltres
};
private static readonly EncounterStatic[] Encounter_DPPt_Regular =
{
//Starters
@ -778,6 +809,7 @@ namespace PKHeX.Core
new EncounterStatic { Species = 492, Form = 0, Level = 30, Location = 063, Fateful = true }, //Shaymin @ Flower Paradise (Unreleased in Diamond and Pearl)
new EncounterStaticTyped { Species = 493, Form = 0, Level = 80, Location = 086, TypeEncounter = EncounterType.Cave_HallOfOrigin }, //Arceus @ Hall of Origin (Unreleased)
};
private static readonly EncounterStatic[] Encounter_DPPt = Encounter_DPPt_Roam_Grass.SelectMany(e => e.Clone(Roaming_MetLocation_DPPt_Grass)).Concat(
Encounter_DPPt_Roam_Surf.SelectMany(e => e.Clone(Roaming_MetLocation_DPPt_Surf))).Concat(
Encounter_DPPt_Regular).ToArray();
@ -792,22 +824,26 @@ namespace PKHeX.Core
177,178,179,180,181,182,183,184,185,186,
187, 190,191,192,193,194,
};
private static readonly int[] Roaming_MetLocation_HGSS_Johto_Surf =
{
// Routes 30-32,34-35,40-45 and 47 can be encountered in water
// Won't go to routes 40,41,47,48
178,179,180,182,183,190,191,192,193
};
private static readonly EncounterStaticTyped[] Encounter_HGSS_JohtoRoam_Grass =
{
new EncounterStaticTyped { Species = 243, Level = 40, Roaming = true, TypeEncounter = EncounterType.TallGrass, }, // Raikou
new EncounterStaticTyped { Species = 244, Level = 40, Roaming = true, TypeEncounter = EncounterType.TallGrass, }, // Entei
};
private static readonly EncounterStaticTyped[] Encounter_HGSS_JohtoRoam_Surf =
{
new EncounterStaticTyped { Species = 243, Level = 40, Roaming = true, TypeEncounter = EncounterType.Surfing_Fishing, }, // Raikou
new EncounterStaticTyped { Species = 244, Level = 40, Roaming = true, TypeEncounter = EncounterType.Surfing_Fishing, }, // Entei
};
private static readonly int[] Roaming_MetLocation_HGSS_Kanto_Grass =
{
// Route 01-18,21,22,24,26 and 28 can be encountered in grass
@ -816,6 +852,7 @@ namespace PKHeX.Core
159,160,161,162,163,164,165,166,
169,170, 172, 174, 176,
};
private static readonly int[] Roaming_MetLocation_HGSS_Kanto_Surf =
{
// Route 4,6,9,10,12,13,19-22,24,26 and 28 can be encountered in water
@ -823,16 +860,19 @@ namespace PKHeX.Core
152,154,157,158,160,161,167,168,169,170,
172,174,176,
};
private static readonly EncounterStaticTyped[] Encounter_HGSS_KantoRoam_Grass =
{
new EncounterStaticTyped { Species = 380, Level = 35, Version = GameVersion.HG, Roaming = true, TypeEncounter = EncounterType.TallGrass, }, //Latias
new EncounterStaticTyped { Species = 381, Level = 35, Version = GameVersion.SS, Roaming = true, TypeEncounter = EncounterType.TallGrass, }, //Latios
};
private static readonly EncounterStaticTyped[] Encounter_HGSS_KantoRoam_Surf =
{
new EncounterStaticTyped { Species = 380, Level = 35, Version = GameVersion.HG, Roaming = true, TypeEncounter = EncounterType.Surfing_Fishing, }, //Latias
new EncounterStaticTyped { Species = 381, Level = 35, Version = GameVersion.SS, Roaming = true, TypeEncounter = EncounterType.Surfing_Fishing, }, //Latios
};
internal static readonly EncounterStatic SpikyEaredPichu = new EncounterStaticTyped // Spiky-Eared Pichu @ Ilex Forest
{
Species = 172,
@ -845,6 +885,7 @@ namespace PKHeX.Core
TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio,
Shiny = Shiny.Never
};
private static readonly EncounterStatic[] Encounter_HGSS_Regular =
{
//Starters
@ -915,6 +956,7 @@ namespace PKHeX.Core
new EncounterStaticTyped { Species = 484, Level = 01, Location = 231, Gift = true, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, //Palkia @ Sinjoh Ruins
new EncounterStaticTyped { Species = 487, Level = 01, Location = 231, Gift = true, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, Form = 1, HeldItem = 112 }, //Giratina @ Sinjoh Ruins
};
private static readonly EncounterStatic[] Encounter_HGSS = ConcatAll(
Encounter_HGSS_KantoRoam_Grass.SelectMany(e => e.Clone(Roaming_MetLocation_HGSS_Kanto_Grass)),
Encounter_HGSS_KantoRoam_Surf.SelectMany(e => e.Clone(Roaming_MetLocation_HGSS_Kanto_Surf)),
@ -924,6 +966,7 @@ namespace PKHeX.Core
#endregion
#region Trade Tables
internal static readonly string[] RanchOTNames = { null, "ユカリ", "Hayley", "EULALIE", "GIULIA", "EUKALIA", null, "Eulalia" };
private static readonly EncounterTrade[] RanchGifts =
{
new EncounterTradePID { Species = 025, Level = 18, Moves = new[] {447,085,148,104}, TID = 1000, SID = 19840, OTGender = 1, Version = GameVersion.D, Location = 0068, Gender = 0, Ability = 1, PID = 323975838, CurrentLevel = 20, }, // Pikachu
@ -949,6 +992,7 @@ namespace PKHeX.Core
new EncounterTradePID { Species = 459, Level = 32, Moves = new[] {452,420,275,059}, TID = 1000, SID = 23360, OTGender = 1, Version = GameVersion.D, Location = 0031, Gender = 0, Ability = 1, PID = 323975582, CurrentLevel = 41, }, // Snover
new EncounterTrade { Species = 489, Level = 01, Moves = new[] {447,240,156,057}, TID = 1000, SID = 09248, OTGender = 1, Version = GameVersion.D, Location = 3000, Gender = 2, Fateful = true, CurrentLevel = 50, Ball = 0x10, EggLocation = 3000, }, // Phione
};
internal static readonly EncounterTrade[] TradeGift_DPPt = new[]
{
new EncounterTradePID { Species = 063, Ability = 1, TID = 25643, SID = 00000, OTGender = 1, Gender = 0, IVs = new[] {15,15,15,20,25,25}, PID = 0x0000008E }, // Abra
@ -956,6 +1000,7 @@ namespace PKHeX.Core
new EncounterTradePID { Species = 093, Ability = 1, TID = 19248, SID = 00000, OTGender = 1, Gender = 0, IVs = new[] {20,25,15,25,15,15}, PID = 0x00000088 }, // Haunter
new EncounterTradePID { Species = 129, Ability = 1, TID = 53277, SID = 00000, OTGender = 0, Gender = 1, IVs = new[] {15,25,15,20,25,15}, PID = 0x0000045C }, // Magikarp
}.Concat(RanchGifts).ToArray();
internal static readonly EncounterTrade[] TradeGift_HGSS =
{
new EncounterTradePID { Species = 095, Ability = 2, TID = 48926, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {25,20,25,15,15,15}, PID = 0x000025EF }, // Onix
@ -972,6 +1017,7 @@ namespace PKHeX.Core
new EncounterTradePID { Species = 021, Ability = 1, TID = 01001, SID = 00000, OTGender = 0, Gender = 1, IVs = new[] {15,20,15,20,20,20}, PID = 0x00006B5E, Level = 20, Location = 183, Moves = new[]{043,031,228,332} },// Webster's Spearow
new EncounterTradePID { Species = 213, Ability = 2, TID = 04336, SID = 00001, OTGender = 0, Gender = 0, IVs = new[] {15,20,15,20,20,20}, PID = 0x000214D7, Level = 20, Location = 130, Moves = new[]{132,117,227,219} },// Kirk's Shuckle
};
internal static readonly string[][] TradeDPPt =
{
new string[0], // 0 - None
@ -984,6 +1030,7 @@ namespace PKHeX.Core
Util.GetStringList("tradedppt", "es"), // 7
Util.GetStringList("tradedppt", "ko"), // 8
};
internal static readonly string[][] TradeHGSS =
{
new string[0], // 0 - None
@ -1012,6 +1059,7 @@ namespace PKHeX.Core
Slots = new int[25].Select((_, i) => new EncounterSlot { Species = 201, LevelMin = 14, LevelMax = 30, Type = SlotType.Grass, Form = i+1 }).ToArray() // B->?, Unown A is loaded from encounters raw file
},
};
private static readonly EncounterArea SlotsHGSS_BCC =
new EncounterArea
@ -1100,6 +1148,7 @@ namespace PKHeX.Core
new EncounterSlot { Species = 449, LevelMin = 43, LevelMax = 43, Type = SlotType.Grass_Safari }, // Hippopotas
new EncounterSlot { Species = 455, LevelMin = 48, LevelMax = 48, Type = SlotType.Grass_Safari }, // Carnivine
};
private static readonly EncounterSlot[] SAFARIZONE_PLAINS =
{
new EncounterSlot { Species = 019, LevelMin = 15, LevelMax = 17, Type = SlotType.Grass_Safari }, // Rattata
@ -1160,6 +1209,7 @@ namespace PKHeX.Core
new EncounterSlot { Species = 299, LevelMin = 45, LevelMax = 45, Type = SlotType.Grass_Safari }, // Nosepass
new EncounterSlot { Species = 447, LevelMin = 45, LevelMax = 46, Type = SlotType.Grass_Safari }, // Riolu
};
private static readonly EncounterSlot[] SAFARIZONE_FOREST =
{
new EncounterSlot { Species = 016, LevelMin = 15, LevelMax = 17, Type = SlotType.Grass_Safari }, // Pidgey
@ -1179,6 +1229,7 @@ namespace PKHeX.Core
new EncounterSlot { Species = 406, LevelMin = 47, LevelMax = 47, Type = SlotType.Grass_Safari }, // Budew
new EncounterSlot { Species = 437, LevelMin = 44, LevelMax = 45, Type = SlotType.Grass_Safari }, // Bronzong
};
private static readonly EncounterSlot[] SAFARIZONE_SWAMP =
{
new EncounterSlot { Species = 039, LevelMin = 15, LevelMax = 17, Type = SlotType.Grass_Safari }, // Jigglypuff
@ -1257,6 +1308,7 @@ namespace PKHeX.Core
new EncounterSlot { Species = 453, LevelMin = 44, LevelMax = 44, Type = SlotType.Grass_Safari }, // Croagunk
new EncounterSlot { Species = 455, LevelMin = 41, LevelMax = 41, Type = SlotType.Grass_Safari }, // Carnivine
};
private static readonly EncounterSlot[] SAFARIZONE_MOUNTAIN =
{
new EncounterSlot { Species = 019, LevelMin = 15, LevelMax = 16, Type = SlotType.Grass_Safari }, // Rattata
@ -1277,6 +1329,7 @@ namespace PKHeX.Core
new EncounterSlot { Species = 375, LevelMin = 44, LevelMax = 44, Type = SlotType.Grass_Safari }, // Metang
new EncounterSlot { Species = 433, LevelMin = 38, LevelMax = 38, Type = SlotType.Grass_Safari }, // Chingling
};
private static readonly EncounterSlot[] SAFARIZONE_ROCKYBEACH =
{
new EncounterSlot { Species = 041, LevelMin = 15, LevelMax = 17, Type = SlotType.Grass_Safari }, // Zubat
@ -1316,6 +1369,7 @@ namespace PKHeX.Core
new EncounterSlot { Species = 406, LevelMin = 40, LevelMax = 40, Type = SlotType.Grass_Safari }, // Budew
new EncounterSlot { Species = 443, LevelMin = 44, LevelMax = 44, Type = SlotType.Grass_Safari }, // Gible
};
private static readonly EncounterSlot[] SAFARIZONE_WASTELAND =
{
new EncounterSlot { Species = 022, LevelMin = 15, LevelMax = 17, Type = SlotType.Grass_Safari }, // Fearow
@ -1335,6 +1389,7 @@ namespace PKHeX.Core
new EncounterSlot { Species = 338, LevelMin = 45, LevelMax = 46, Type = SlotType.Grass_Safari }, // Solrock
new EncounterSlot { Species = 451, LevelMin = 44, LevelMax = 45, Type = SlotType.Grass_Safari }, // Skorupi
};
private static readonly EncounterSlot[] SAFARIZONE_SAVANNAH =
{
new EncounterSlot { Species = 029, LevelMin = 15, LevelMax = 17, Type = SlotType.Grass_Safari }, // Nidoran♀
@ -1356,6 +1411,7 @@ namespace PKHeX.Core
new EncounterSlot { Species = 332, LevelMin = 42, LevelMax = 42, Type = SlotType.Grass_Safari }, // Cacturne
new EncounterSlot { Species = 404, LevelMin = 45, LevelMax = 46, Type = SlotType.Grass_Safari }, // Luxio
};
private static readonly EncounterSlot[] SAFARIZONE_WETLAND =
{
new EncounterSlot { Species = 021, LevelMin = 15, LevelMax = 17, Type = SlotType.Grass_Safari }, // Spearow
@ -1415,6 +1471,7 @@ namespace PKHeX.Core
SAFARIZONE_SAVANNAH,
SAFARIZONE_WETLAND)
};
private static readonly EncounterArea[] SlotsHGSSAlt =
{
SlotsHGSS_BCC,
@ -1471,6 +1528,7 @@ namespace PKHeX.Core
183,194,195,298,399,400, // Pre-National Pokédex
046,102,115,193,285,316,452,454 // Post-National Pokédex
};
private static readonly EncounterArea[] DP_GreatMarshAlt = EncounterArea.GetSimpleEncounterArea(DP_GreatMarshAlt_Species, new[] { 22, 22, 24, 24, 26, 26 }, 52, SlotType.Grass_Safari);
private static readonly int[] Pt_GreatMarshAlt_Species =
@ -1479,6 +1537,7 @@ namespace PKHeX.Core
194, // Pre-National Pokédex
046,102,115,285,316,352,452,454 // Post-National Pokédex
};
private static readonly EncounterArea[] Pt_GreatMarshAlt = EncounterArea.GetSimpleEncounterArea(Pt_GreatMarshAlt_Species, new[] { 27, 30 }, 52, SlotType.Grass_Safari);
private static readonly int[] Shellos_EastSeaLocation_DP =
@ -1556,10 +1615,12 @@ namespace PKHeX.Core
new EncounterArea {Location = 220, Slots = new[]{new EncounterSlot {Species = 206, Type = SlotType.Grass },},}, // Dunsparce @ Dark Cave
new EncounterArea {Location = 224, Slots = new[]{new EncounterSlot {Species = 401, Type = SlotType.Grass },},}, // Kricketot @ Viridian Forest
};
private static readonly EncounterArea[] SlotsHG_Swarm = SlotsHGSS_Swarm.Concat(new[] {
new EncounterArea {Location = 151, Slots = new[]{new EncounterSlot {Species = 343, Type = SlotType.Grass },},}, // Baltoy @ Route 3
new EncounterArea {Location = 157, Slots = new[]{new EncounterSlot {Species = 302, Type = SlotType.Grass },},}, // Sableye @ Route 9
}).ToArray();
private static readonly EncounterArea[] SlotsSS_Swarm = SlotsHGSS_Swarm.Concat(new[] {
new EncounterArea {Location = 151, Slots = new[]{new EncounterSlot {Species = 316, Type = SlotType.Grass },},}, // Gulpin @ Route 3
new EncounterArea {Location = 157, Slots = new[]{new EncounterSlot {Species = 303, Type = SlotType.Grass },},}, // Mawile @ Route 9

View file

@ -71,6 +71,7 @@ namespace PKHeX.Core
area.Slots = Legal.FriendSafari.Select(FriendSafariSlot).ToArray();
return area.Slots.ToLookup(s => s.Species);
}
private static void MarkG6XYSlots(ref EncounterArea[] Areas)
{
foreach (var area in Areas)
@ -81,6 +82,7 @@ namespace PKHeX.Core
}
ReduceAreasSize(ref Areas);
}
private static void MarkG6AOSlots(ref EncounterArea[] Areas)
{
foreach (var area in Areas)
@ -109,6 +111,7 @@ namespace PKHeX.Core
Util.GetStringList("tradexy", "es"), // 7
Util.GetStringList("tradexy", "ko"), // 8
};
internal static readonly string[][] TradeAO =
{
new string[0], // 0 - None
@ -247,6 +250,7 @@ namespace PKHeX.Core
new EncounterStatic { Species = 145, Level = 70, Location = 146, Ability = 1, Shiny = Shiny.Never, IV3 = true }, // Zapdos
new EncounterStatic { Species = 146, Level = 70, Location = 146, Ability = 1, Shiny = Shiny.Never, IV3 = true }, // Moltres
};
private static readonly EncounterStatic[] Encounter_AO_Regular =
{
new EncounterStatic { Gift = true, Species = 252, Level = 5, Location = 204, }, // Treeko
@ -352,7 +356,9 @@ namespace PKHeX.Core
new EncounterStatic { Species = 425, Level = 45, Location = 348 }, // Drifloon
new EncounterStatic { Species = 628, Level = 45, Location = 348 }, // Braviary
};
private static readonly EncounterStatic[] Encounter_AO = ConcatAll(Encounter_AO_Regular, PermuteCosplayPikachu().ToArray());
private static IEnumerable<EncounterStatic> PermuteCosplayPikachu()
{
var CosplayPikachu = new EncounterStatic
@ -361,8 +367,13 @@ namespace PKHeX.Core
Contest = new[] { 70, 70, 70, 70, 70, 0 }, Gift = true, Shiny = Shiny.Never
};
foreach (int loc in new[] { 178, 180, 186, 194 })
for (int f = 1; f <= 6; f++)
{ var pk = CosplayPikachu.Clone(loc); pk.Form = f; yield return pk; }
{
for (int f = 1; f <= 6; f++)
{
var pk = CosplayPikachu.Clone(loc); pk.Form = f;
yield return pk;
}
}
}
#endregion
#region Trade Tables
@ -381,6 +392,7 @@ namespace PKHeX.Core
new EncounterTrade { Species = 280, Level = 5, Ability = 1, Gender = 1, TID = 37110, Nature = Nature.Modest, IVs = new[] {20, 20, 20, 31, 31, 20}, IsNicknamed = false, }, // Ralts
};
internal static readonly EncounterTrade[] TradeGift_AO =
{
new EncounterTrade { Species = 296, Level = 9, Ability = 2, Gender = 0, TID = 30724, Nature = Nature.Brave, IVs = new[] {-1, 31, -1, -1, -1, -1}, }, // Makuhita

View file

@ -60,10 +60,12 @@ namespace PKHeX.Core
TradeGift_SM.SetVersion(GameVersion.SM);
TradeGift_USUM.SetVersion(GameVersion.USUM);
}
private static void MarkG7REGSlots(ref EncounterArea[] Areas)
{
ReduceAreasSize(ref Areas);
}
private static void MarkG7SMSlots(ref EncounterArea[] Areas)
{
foreach (EncounterSlot s in Areas.SelectMany(area => area.Slots))
@ -173,6 +175,7 @@ namespace PKHeX.Core
new EncounterStatic { Species = 787, Level = 60, Shiny = Shiny.Never, Ability = 1, Location = 140, IV3 = true, }, // Tapu Bulu
new EncounterStatic { Species = 788, Level = 60, Shiny = Shiny.Never, Ability = 1, Location = 180, IV3 = true, }, // Tapu Fini
};
internal static readonly EncounterTrade[] TradeGift_SM = // @ a\1\5\5
{
// Trades - 4.bin
@ -184,6 +187,7 @@ namespace PKHeX.Core
new EncounterTrade { Species = 762, Form = 0, Level = 43, Ability = 1, TID = 20679, SID = 00009, IVs = new[] {-1,-1,-1,-1,-1,31}, OTGender = 1, Gender = 1, Nature = Nature.Careful, }, // Steenee
new EncounterTrade { Species = 663, Form = 0, Level = 59, Ability = 4, TID = 56734, SID = 00008, IVs = new[] {-1,-1,-1,31,-1,-1}, OTGender = 0, Gender = 0, Nature = Nature.Jolly, }, // Talonflame
};
private static readonly EncounterStatic[] Encounter_USUM =
{
new EncounterStatic { Gift = true, Species = 722, Level = 05, Location = 8, }, // Rowlet
@ -379,6 +383,7 @@ namespace PKHeX.Core
new EncounterStatic { Species = 739, Level = 31, Location = 118, }, // Route 16
new EncounterStatic { Species = 739, Level = 32, Location = 120, }, // Route 17
};
internal static readonly EncounterTrade[] TradeGift_USUM =
{
// Trades - 4.bin
@ -390,6 +395,7 @@ namespace PKHeX.Core
new EncounterTrade { Species = 422, Form = 0, Level = 44, Ability = 2, TID = 20679, SID = 00009, IVs = new[] {-1,-1,31,-1,-1,-1}, OTGender = 1, Gender = 1, Nature = Nature.Quiet, }, // Shellos
new EncounterTrade { Species = 128, Form = 0, Level = 59, Ability = 1, TID = 56734, SID = 00008, IVs = new[] {-1,-1,-1,31,-1,-1}, OTGender = 0, Gender = 0, Nature = Nature.Jolly, }, // Tauros
};
internal static readonly string[][] TradeSM =
{
new string[0], // 0 - None
@ -404,6 +410,7 @@ namespace PKHeX.Core
Util.GetStringList("tradesm", "zh"), // 9
Util.GetStringList("tradesm", "zh"), // 10
};
internal static readonly string[][] TradeUSUM =
{
new string[0], // 0 - None
@ -420,6 +427,7 @@ namespace PKHeX.Core
};
private static EncounterArea[] Encounter_Pelago_SN, Encounter_Pelago_MN, Encounter_Pelago_US, Encounter_Pelago_UM;
private static void InitializePelagoAreas()
{
int[] minLevels = { 1, 11, 21, 37, 49 };
@ -447,6 +455,7 @@ namespace PKHeX.Core
speciesUU[3][3] = 309; // Houndour -> Electrike
Encounter_Pelago_UM = GetPelagoArea(speciesUU, minLevels);
}
private static EncounterArea[] GetPelagoArea(int[][] species, int[] min)
{
// Species that appear at a lower level than the current table show up too.

View file

@ -1,4 +1,6 @@
namespace PKHeX.Core
using System;
namespace PKHeX.Core
{
/// <summary>
/// Invalid Encounter Data
@ -20,6 +22,6 @@
EggEncounter = pkm.WasEgg;
}
public PKM ConvertToPKM(ITrainerInfo SAV) => throw new System.NotImplementedException();
public PKM ConvertToPKM(ITrainerInfo SAV) => throw new ArgumentException($"Cannot convert an {nameof(EncounterInvalid)} to PKM.");
}
}

View file

@ -1,3 +1,5 @@
using System;
namespace PKHeX.Core
{
/// <summary>
@ -21,6 +23,6 @@ namespace PKHeX.Core
Check = check;
}
public PKM ConvertToPKM(ITrainerInfo SAV) => throw new System.NotImplementedException();
public PKM ConvertToPKM(ITrainerInfo SAV) => throw new ArgumentException($"Cannot convert an {nameof(EncounterRejected)} to PKM.");
}
}

View file

@ -18,6 +18,7 @@ namespace PKHeX.Core
public bool IsDexNav => AllowDexNav && DexNav;
public EncounterSlotPermissions Clone() => (EncounterSlotPermissions)MemberwiseClone();
}
/// <summary>
/// Wild Encounter Slot data
/// </summary>

View file

@ -21,7 +21,7 @@ namespace PKHeX.Core
public int Ability { get; set; }
public int Form { get; set; }
public virtual Shiny Shiny { get; set; } = Shiny.Random;
public int[] Relearn { get; set; } = new int[4];
public int[] Relearn { get; set; } = Array.Empty<int>();
public int Gender { get; set; } = -1;
public int EggLocation { get; set; }
public Nature Nature { get; set; } = Nature.Random;
@ -56,6 +56,7 @@ namespace PKHeX.Core
Relearn = (int[])Relearn.Clone();
IVs = (int[])IVs?.Clone();
}
internal virtual EncounterStatic Clone()
{
var result = (EncounterStatic)MemberwiseClone();
@ -119,14 +120,16 @@ namespace PKHeX.Core
pk.Gender = PKX.GetGenderFromPID(Species, p.PID);
if (pk is PK5 pk5)
{
pk5.IVs = new[] { 30, 30, 30, 30, 30, 30 };
pk5.IVs = new[] {30, 30, 30, 30, 30, 30};
pk5.NPokémon = p.NSparkle;
pk5.OT_Name = Legal.GetG5OT_NSparkle(lang);
pk5.TID = 00002;
pk5.SID = 00000;
}
else
{
SetIVs(pk);
}
if (Generation >= 5)
pk.Nature = nature;
pk.RefreshAbility(Ability >> 1);
@ -160,7 +163,7 @@ namespace PKHeX.Core
pk.HeldItem = HeldItem;
pk.Moves = moves;
pk.SetMaximumPPCurrent(moves);
if (pk.Format >= 6 && Relearn != null)
if (pk.Format >= 6 && Relearn.Length > 0)
pk.RelearnMoves = Relearn;
pk.OT_Friendship = pk.PersonalInfo.BaseFriendship;
if (Fateful)
@ -179,7 +182,8 @@ namespace PKHeX.Core
private void SanityCheckVersion(ref GameVersion version)
{
if (Generation == 4 && (int)version != 12)
if (Generation != 4 || version == GameVersion.Pt)
return;
switch (Species)
{
case 491 when Location == 079: // DP Darkrai

View file

@ -1,10 +1,13 @@
namespace PKHeX.Core
using System;
namespace PKHeX.Core
{
internal class EncounterStaticShadow : EncounterStatic
{
public EncounterLock[][] Locks { get; internal set; } = new EncounterLock[0][];
public EncounterLock[][] Locks { get; internal set; } = Array.Empty<EncounterLock[]>();
public int Gauge { get; internal set; }
public bool EReader { get; set; }
internal override EncounterStatic Clone()
{
var result = (EncounterStaticShadow)base.Clone();

View file

@ -14,6 +14,7 @@ namespace PKHeX.Core
var evos = table.GetValidPreEvolutions(pkm, maxLevel: 100, maxSpeciesOrigin: maxSpeciesOrigin, skipChecks: true);
return GenerateEggs(pkm, evos, all);
}
public static IEnumerable<EncounterEgg> GenerateEggs(PKM pkm, IReadOnlyList<DexLevel> vs, bool all = false)
{
if (NoHatchFromEgg.Contains(pkm.Species))

View file

@ -17,7 +17,7 @@ namespace PKHeX.Core
/// <param name="pkm">Source data to find a match for</param>
/// <returns>
/// Information containing the matched encounter and any parsed checks.
/// If no clean match is found, the last checked match is returned.
/// If no clean match is found, the last checked match is returned.
/// If no match is found, an invalid encounter object is returned.
/// </returns>
public static LegalInfo FindVerifiedEncounter(PKM pkm)
@ -76,8 +76,10 @@ namespace PKHeX.Core
return false;
}
else
{
for (int i = 0; i < 4; i++)
info.Relearn[i] = new CheckResult(CheckIdentifier.RelearnMove);
}
info.Moves = VerifyCurrentMoves.VerifyMoves(pkm, info);
if (info.Moves.Any(z => !z.Valid) && iterator.PeekIsNext())

View file

@ -54,6 +54,7 @@ namespace PKHeX.Core
yield return z;
}
}
private static IEnumerable<IEncounterable> GetEncounters3(PKM pkm, LegalInfo info)
{
info.PIDIV = MethodFinder.Analyze(pkm);
@ -74,6 +75,7 @@ namespace PKHeX.Core
foreach (var z in deferred)
yield return z;
}
private static IEnumerable<IEncounterable> GetEncounters4(PKM pkm, LegalInfo info)
{
info.PIDIV = MethodFinder.Analyze(pkm);
@ -178,9 +180,10 @@ namespace PKHeX.Core
foreach (var d in deferred)
yield return d;
}
private static IEnumerable<IEncounterable> GenerateFilteredEncounters12(PKM pkm)
{
bool crystal = pkm.Format == 2 && pkm.Met_Location != 0 || pkm.Format >= 7 && pkm.OT_Gender == 1;
bool crystal = (pkm.Format == 2 && pkm.Met_Location != 0) || (pkm.Format >= 7 && pkm.OT_Gender == 1);
bool kadabra = pkm.Species == 64 && pkm is PK1 pk1
&& (pk1.Catch_Rate == PersonalTable.RB[64].CatchRate
|| pk1.Catch_Rate == PersonalTable.Y[64].CatchRate); // catch rate outsider, return gen1 first always
@ -210,18 +213,21 @@ namespace PKHeX.Core
foreach (var z in deferred)
yield return z;
}
private static IEnumerable<IEncounterable> GenerateRawEncounters1(PKM pkm, bool crystal)
{
return pkm.Gen2_NotTradeback || crystal
? Enumerable.Empty<IEncounterable>()
: GenerateRawEncounters12(pkm, GameVersion.RBY);
}
private static IEnumerable<IEncounterable> GenerateRawEncounters2(PKM pkm, bool crystal)
{
return pkm.Gen1_NotTradeback
? Enumerable.Empty<IEncounterable>()
: GenerateRawEncounters12(pkm, crystal ? GameVersion.C : GameVersion.GSC);
}
private static PeekEnumerator<IEncounterable> GetPreferredGBIterator(PKM pkm, PeekEnumerator<IEncounterable> g1i, PeekEnumerator<IEncounterable> g2i)
{
if (!g1i.PeekIsNext())
@ -232,6 +238,7 @@ namespace PKHeX.Core
var p2 = GetGBEncounterPriority(pkm, g2i.Current);
return p1 > p2 ? g1i : g2i;
}
private static GBEncounterPriority GetGBEncounterPriority(PKM pkm, IEncounterable Encounter)
{
switch (Encounter)
@ -300,6 +307,7 @@ namespace PKHeX.Core
{ yield return z; ++ctr; }
// if (ctr != 0) yield break;
}
private static IEnumerable<IEncounterable> GenerateRawEncounters4(PKM pkm, LegalInfo info)
{
bool wasEvent = pkm.WasEvent || pkm.WasEventEgg; // egg events?
@ -323,12 +331,14 @@ namespace PKHeX.Core
bool safari = pkm.Ball == 0x05; // never static encounters
bool safariSport = safari || sport;
if (!safariSport)
foreach (var z in GetValidStaticEncounter(pkm))
{
if (z.Gift && pkm.Ball != 4)
deferIncompat.Enqueue(z);
else
yield return z;
foreach (var z in GetValidStaticEncounter(pkm))
{
if (z.Gift && pkm.Ball != 4)
deferIncompat.Enqueue(z);
else
yield return z;
}
}
int species = pkm.Species;
@ -366,10 +376,12 @@ namespace PKHeX.Core
yield return z;
// do static encounters if they were deferred to end, spit out any possible encounters for invalid pkm
if (safariSport)
if (!safariSport)
yield break;
foreach (var z in GetValidStaticEncounter(pkm))
yield return z;
}
private static IEnumerable<IEncounterable> GenerateRawEncounters3(PKM pkm, LegalInfo info)
{
foreach (var z in GetValidGifts(pkm))
@ -380,12 +392,14 @@ namespace PKHeX.Core
var deferIncompat = new Queue<IEncounterable>();
bool safari = pkm.Ball == 0x05; // never static encounters
if (!safari)
foreach (var z in GetValidStaticEncounter(pkm))
{
if (z.Gift && pkm.Ball != 4)
deferIncompat.Enqueue(z);
else
yield return z;
foreach (var z in GetValidStaticEncounter(pkm))
{
if (z.Gift && pkm.Ball != 4)
deferIncompat.Enqueue(z);
else
yield return z;
}
}
int species = pkm.Species;
@ -421,13 +435,16 @@ namespace PKHeX.Core
info.FrameMatches = false;
if (pkm.Version != 15) // no eggs in C/XD
foreach (var z in GenerateEggs(pkm))
yield return z;
{
foreach (var z in GenerateEggs(pkm))
yield return z;
}
foreach (var z in deferIncompat)
yield return z;
// do static encounters if they were deferred to end, spit out any possible encounters for invalid pkm
if (safari)
if (!safari)
yield break;
foreach (var z in GetValidStaticEncounter(pkm))
yield return z;
}
@ -445,6 +462,7 @@ namespace PKHeX.Core
return type == 0;
}
}
internal static bool IsEncounterTrade1Valid(PKM pkm, EncounterTrade t)
{
string ot = pkm.OT_Name;

View file

@ -130,8 +130,10 @@ namespace PKHeX.Core
// generate possible eggs
var eggs = GetEggs(pk, needs, version);
if (!GameVersion.CXD.Contains(version))
foreach (var egg in eggs)
yield return egg;
{
foreach (var egg in eggs)
yield return egg;
}
// mystery gifts next
var gifts = GetGifts(pk, needs);
@ -304,7 +306,7 @@ namespace PKHeX.Core
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsUnobtainable(this EncounterSlot slot, PKM pk)
private static bool IsUnobtainable(this EncounterSlot slot, ITrainerID pk)
{
switch (slot.Generation)
{
@ -312,9 +314,8 @@ namespace PKHeX.Core
if ((slot.Type & SlotType.Safari) != 0) // Safari Zone is unavailable in Gen 2.
return true;
if ((slot.Type & SlotType.Headbutt) != 0)
if (Encounters2.GetGSCHeadbuttAvailability(slot, pk.TID) != TreeEncounterAvailable.ValidTree) // Unreachable Headbutt Trees.
return true;
if ((slot.Type & SlotType.Headbutt) != 0) // Unreachable Headbutt Trees.
return Encounters2.GetGSCHeadbuttAvailability(slot, pk.TID) != TreeEncounterAvailable.ValidTree;
break;
case 4:
if (slot.Location == 193 && slot.Type == SlotType.Surf) // Johto Route 45 surfing encounter. Unreachable Water tiles.

View file

@ -14,17 +14,20 @@ namespace PKHeX.Core
var vs = EvolutionChain.GetValidPreEvolutions(pkm, maxspeciesorigin: maxspeciesorigin);
return GetPossible(pkm, vs, gameSource);
}
public static IEnumerable<EncounterSlot> GetPossible(PKM pkm, IReadOnlyList<DexLevel> vs, GameVersion gameSource = GameVersion.Any)
{
var possibleAreas = GetEncounterSlots(pkm, gameSource);
return possibleAreas.SelectMany(area => area.Slots).Where(z => vs.Any(v => v.Species == z.Species));
}
private static IEnumerable<EncounterSlot> GetRawEncounterSlots(PKM pkm, int lvl, GameVersion gameSource)
{
int maxspeciesorigin = GetMaxSpecies(gameSource);
var vs = EvolutionChain.GetValidPreEvolutions(pkm, maxspeciesorigin: maxspeciesorigin);
return GetRawEncounterSlots(pkm, lvl, vs, gameSource);
}
private static IEnumerable<EncounterSlot> GetRawEncounterSlots(PKM pkm, int lvl, IReadOnlyList<EvoCriteria> vs, GameVersion gameSource)
{
var possibleAreas = GetEncounterAreas(pkm, gameSource);
@ -52,6 +55,7 @@ namespace PKHeX.Core
return s; // defer deferrals to the method consuming this collection
}
public static IEnumerable<EncounterSlot> GetValidWildEncounters12(PKM pkm, IReadOnlyList<EvoCriteria> vs, GameVersion gameSource = GameVersion.Any)
{
if (gameSource == GameVersion.Any)
@ -62,6 +66,7 @@ namespace PKHeX.Core
return Enumerable.Empty<EncounterSlot>();
return GetRawEncounterSlots(pkm, lvl, vs, gameSource);
}
public static IEnumerable<EncounterSlot> GetValidWildEncounters(PKM pkm, IReadOnlyList<EvoCriteria> vs, GameVersion gameSource = GameVersion.Any)
{
if (gameSource == GameVersion.Any)
@ -79,6 +84,7 @@ namespace PKHeX.Core
return s.DeferByBoolean(slot => slot.IsDeferred(species, pkm, IsSafariBall, IsSportBall, IsHidden)); // non-deferred first
}
public static IEnumerable<EncounterSlot> GetValidWildEncounters(PKM pkm, GameVersion gameSource = GameVersion.Any)
{
if (gameSource == GameVersion.Any)
@ -96,17 +102,20 @@ namespace PKHeX.Core
return s.DeferByBoolean(slot => slot.IsDeferred(species, pkm, IsSafariBall, IsSportBall, IsHidden)); // non-deferred first
}
public static bool IsDeferred3(this EncounterSlot slot, int currentSpecies, PKM pkm, bool IsSafariBall)
{
return slot.IsDeferredWurmple(currentSpecies, pkm)
|| slot.IsDeferredSafari(IsSafariBall);
}
public static bool IsDeferred4(this EncounterSlot slot, int currentSpecies, PKM pkm, bool IsSafariBall, bool IsSportBall)
{
return slot.IsDeferredWurmple(currentSpecies, pkm)
|| slot.IsDeferredSafari(IsSafariBall)
|| slot.IsDeferredSport(IsSportBall);
}
private static bool IsDeferred(this EncounterSlot slot, int currentSpecies, PKM pkm, bool IsSafariBall, bool IsSportBall, bool IsHidden)
{
return slot.IsDeferredWurmple(currentSpecies, pkm)
@ -114,6 +123,7 @@ namespace PKHeX.Core
|| slot.IsDeferredSafari(IsSafariBall)
|| slot.IsDeferredSport(IsSportBall);
}
private static bool IsDeferredWurmple(this IEncounterable slot, int currentSpecies, PKM pkm) => slot.Species == 265 && currentSpecies != 265 && !IsWurmpleEvoValid(pkm);
private static bool IsDeferredSafari(this EncounterSlot slot, bool IsSafariBall) => IsSafariBall != ((slot.Type & SlotType.Safari) != 0);
private static bool IsDeferredSport(this EncounterSlot slot, bool IsSportBall) => IsSportBall != ((slot.Type & SlotType.BugContest) != 0);
@ -155,6 +165,7 @@ namespace PKHeX.Core
return GetFilteredSlots6DexNav(pkm, lvl, encounterSlots, fluteBoost);
return GetFilteredSlots67(pkm, encounterSlots);
}
private static IEnumerable<EncounterSlot> GetValidEncounterSlots12(PKM pkm, EncounterArea loc, IEnumerable<DexLevel> vs, int lvl = -1, bool ignoreLevel = false)
{
if (lvl < 0)
@ -170,6 +181,7 @@ namespace PKHeX.Core
var encounterSlots = GetValidEncounterSlotsByEvoLevel(pkm, loc.Slots, lvl, ignoreLevel, vs);
return GetFilteredSlots12(pkm, pkm.GenNumber, Gen1Version, encounterSlots, RBDragonair).OrderBy(slot => slot.LevelMin); // prefer lowest levels
}
private static IEnumerable<EncounterSlot> GetValidEncounterSlotsByEvoLevel(PKM pkm, IEnumerable<EncounterSlot> slots, int lvl, bool ignoreLevel, IEnumerable<DexLevel> vs, int df = 0, int dn = 0)
{
// Get slots where pokemon can exist with respect to the evolution chain
@ -183,12 +195,14 @@ namespace PKHeX.Core
// check for any less than current level
return slots.Where(slot => slot.LevelMin <= lvl);
}
private static IEnumerable<EncounterSlot> GetFilteredSlotsByForm(PKM pkm, IEnumerable<EncounterSlot> encounterSlots)
{
return WildForms.Contains(pkm.Species)
? encounterSlots.Where(slot => slot.Form == pkm.AltForm)
: encounterSlots;
}
private static IEnumerable<EncounterSlot> GetFilteredSlots67(PKM pkm, IEnumerable<EncounterSlot> encounterSlots)
{
int species = pkm.Species;
@ -239,7 +253,7 @@ namespace PKHeX.Core
// Filter for Form Specific
// Pressure Slot
if (slotMax == null)
yield break; // yield break;
yield break;
if (AlolanVariantEvolutions12.Contains(species)) // match form if same species, else form 0.
{
@ -252,10 +266,13 @@ namespace PKHeX.Core
yield return GetPressureSlot(slotMax, pkm);
}
else
{
yield return GetPressureSlot(slotMax, pkm);
}
bool ShouldMatchSlotForm() => WildForms.Contains(species) || AlolanOriginForms.Contains(species) || FormConverter.IsTotemForm(species, form);
}
private static IEnumerable<EncounterSlot> GetFilteredSlots6DexNav(PKM pkm, int lvl, IEnumerable<EncounterSlot> encounterSlots, int fluteBoost)
{
EncounterSlot slotMax = null;
@ -290,6 +307,7 @@ namespace PKHeX.Core
if (slotMax != null)
yield return GetPressureSlot(slotMax, pkm);
}
private static EncounterSlot GetPressureSlot(EncounterSlot s, PKM pkm)
{
var max = s.Clone();
@ -346,6 +364,7 @@ namespace PKHeX.Core
return true;
}
}
private static IEnumerable<EncounterSlot> GetFilteredSlots12(PKM pkm, int gen, GameVersion Gen1Version, IEnumerable<EncounterSlot> slots, bool RBDragonair)
{
switch (gen)
@ -377,13 +396,14 @@ namespace PKHeX.Core
return GetEncounterTable(pkm, gameSource);
}
private static IEnumerable<EncounterArea> GetEncounterAreas(PKM pkm, GameVersion gameSource = GameVersion.Any)
{
if (gameSource == GameVersion.Any)
gameSource = (GameVersion)pkm.Version;
var slots = GetEncounterSlots(pkm, gameSource: gameSource);
bool noMet = !pkm.HasOriginalMetLocation || pkm.Format == 2 && gameSource != GameVersion.C;
bool noMet = !pkm.HasOriginalMetLocation || (pkm.Format == 2 && gameSource != GameVersion.C);
return noMet ? slots : slots.Where(area => area.Location == pkm.Met_Location);
}
@ -411,6 +431,7 @@ namespace PKHeX.Core
var d_areas = areas.Select(area => GetValidEncounterSlots(pkm, area, vs, DexNav: true));
return d_areas.Any(slots => slots.Any(slot => slot.Permissions.AllowDexNav && slot.Permissions.DexNav));
}
internal static EncounterArea GetCaptureLocation(PKM pkm)
{
var vs = EvolutionChain.GetValidPreEvolutions(pkm);

View file

@ -175,7 +175,7 @@ namespace PKHeX.Core
return false;
if (e.Form != pkm.AltForm && !e.SkipFormCheck && !IsFormChangeable(pkm, e.Species))
return false;
if (e.EggLocation == 60002 && e.Relearn[0] == 0 && pkm.RelearnMoves.Any(z => z != 0)) // gen7 eevee edge case
if (e.EggLocation == 60002 && e.Relearn.Length == 0 && pkm.RelearnMoves.Any(z => z != 0)) // gen7 eevee edge case
return false;
if (e.IVs != null && (e.Generation > 2 || pkm.Format <= 2)) // 1,2->7 regenerates IVs, only check if original IVs still exist

View file

@ -12,20 +12,23 @@ namespace PKHeX.Core
var p = EvolutionChain.GetValidPreEvolutions(pkm);
return GetPossible(pkm, p, gameSource);
}
public static IEnumerable<EncounterTrade> GetPossible(PKM pkm, IReadOnlyList<DexLevel> vs, GameVersion gameSource = GameVersion.Any)
{
if (gameSource == GameVersion.Any)
gameSource = (GameVersion)pkm.Version;
if (pkm.VC || pkm.Format <= 2)
return GetPossibleVC(pkm, vs, gameSource);
return GetPossibleVC(vs, gameSource);
return GetPossibleNonVC(pkm, vs, gameSource);
}
public static IEnumerable<EncounterTrade> GetValidEncounterTrades(PKM pkm, GameVersion gameSource = GameVersion.Any)
{
var p = EvolutionChain.GetValidPreEvolutions(pkm);
return GetValidEncounterTrades(pkm, p, gameSource);
}
public static IEnumerable<EncounterTrade> GetValidEncounterTrades(PKM pkm, IReadOnlyList<DexLevel> p, GameVersion gameSource = GameVersion.Any)
{
if (GetIsFromGB(pkm))
@ -38,6 +41,7 @@ namespace PKHeX.Core
var poss = GetPossibleNonVC(pkm, p, gameSource);
return poss.Where(z => IsEncounterTradeValid(pkm, z, lvl));
}
private static IEnumerable<EncounterTrade> GetPossibleNonVC(PKM pkm, IReadOnlyList<DexLevel> p, GameVersion gameSource = GameVersion.Any)
{
if (gameSource == GameVersion.Any)
@ -49,11 +53,13 @@ namespace PKHeX.Core
var table = GetEncounterTradeTable(pkm);
return table?.Where(f => p.Any(r => r.Species == f.Species)) ?? Enumerable.Empty<EncounterTrade>();
}
private static IEnumerable<EncounterTrade> GetPossibleVC(PKM pkm, IReadOnlyList<DexLevel> p, GameVersion gameSource = GameVersion.Any)
private static IEnumerable<EncounterTrade> GetPossibleVC(IReadOnlyList<DexLevel> p, GameVersion gameSource = GameVersion.Any)
{
var table = GetEncounterTradeTableVC(gameSource);
return table.Where(f => p.Any(r => r.Species == f.Species));
}
private static IEnumerable<EncounterTrade> GetEncounterTradeTableVC(GameVersion gameSource)
{
if (GameVersion.RBY.Contains(gameSource))
@ -62,6 +68,7 @@ namespace PKHeX.Core
return Encounters2.TradeGift_GSC;
return null;
}
private static IEnumerable<EncounterTrade> GetEncounterTradeTable(PKM pkm)
{
switch (pkm.GenNumber)
@ -74,13 +81,15 @@ namespace PKHeX.Core
}
return null;
}
private static IEnumerable<EncounterTrade> GetValidEncounterTradesVC(PKM pkm, IReadOnlyList<DexLevel> p, GameVersion gameSource)
{
var poss = GetPossibleVC(pkm, p, gameSource);
var poss = GetPossibleVC(p, gameSource);
if (gameSource == GameVersion.RBY)
return poss.Where(z => GetIsValidTradeVC1(pkm, z));
return poss.Where(z => GetIsValidTradeVC2(pkm, z));
}
private static bool GetIsValidTradeVC1(PKM pkm, EncounterTrade z)
{
if (z.Level > pkm.CurrentLevel) // minimum required level
@ -104,6 +113,7 @@ namespace PKHeX.Core
}
return true;
}
private static bool GetIsValidTradeVC2(PKM pkm, EncounterTrade z)
{
if (z.Level > pkm.CurrentLevel) // minimum required level
@ -127,12 +137,17 @@ namespace PKHeX.Core
}
private static bool GetIsFromGB(PKM pkm) => pkm.VC || pkm.Format <= 2;
private static bool IsEncounterTradeValid(PKM pkm, EncounterTrade z, int lvl)
{
if (z.IVs != null)
{
for (int i = 0; i < 6; i++)
{
if (z.IVs[i] != -1 && z.IVs[i] != pkm.IVs[i])
return false;
}
}
if (z is EncounterTradePID p)
{
@ -159,16 +174,21 @@ namespace PKHeX.Core
var loc = z.Location > 0 ? z.Location : EncounterTrade.DefaultMetLocation[z.Generation - 1];
if (loc != pkm.Met_Location)
return false;
if (pkm.Format < 5)
{
if (z.Level > lvl)
return false;
}
else if (z.Level != lvl)
{
return false;
}
}
else if (z.Level > lvl)
{
return false;
}
if (z.CurrentLevel != -1 && z.CurrentLevel > pkm.CurrentLevel)
return false;

View file

@ -13,11 +13,13 @@ namespace PKHeX.Core
var vs = EvolutionChain.GetValidPreEvolutions(pkm, maxSpecies);
return GetPossible(pkm, vs);
}
public static IEnumerable<MysteryGift> GetPossible(PKM pkm, IReadOnlyList<DexLevel> vs)
{
var table = GetTable(pkm.GenNumber);
return table.Where(wc => vs.Any(dl => dl.Species == wc.Species));
}
public static IEnumerable<MysteryGift> GetValidGifts(PKM pkm)
{
int gen = pkm.GenNumber;
@ -32,6 +34,7 @@ namespace PKHeX.Core
default: return Enumerable.Empty<MysteryGift>();
}
}
private static IEnumerable<MysteryGift> GetTable(int generation)
{
switch (generation)
@ -44,6 +47,7 @@ namespace PKHeX.Core
default: return Enumerable.Empty<MysteryGift>();
}
}
private static IEnumerable<MysteryGift> GetMatchingWC3(PKM pkm, IEnumerable<MysteryGift> DB)
{
if (DB == null)
@ -65,9 +69,10 @@ namespace PKHeX.Core
foreach (var z in validWC3)
yield return z;
}
private static IEnumerable<MysteryGift> GetMatchingPCD(PKM pkm, IEnumerable<MysteryGift> DB)
{
if (DB == null || pkm.IsEgg && pkm.Format != 4) // transferred
if (DB == null || (pkm.IsEgg && pkm.Format != 4)) // transferred
yield break;
if (IsRangerManaphy(pkm))
@ -95,6 +100,7 @@ namespace PKHeX.Core
foreach (var z in deferred)
yield return z;
}
private static IEnumerable<MysteryGift> GetMatchingPGF(PKM pkm, IEnumerable<MysteryGift> DB)
{
if (DB == null)
@ -116,6 +122,7 @@ namespace PKHeX.Core
foreach (var z in deferred)
yield return z;
}
private static IEnumerable<MysteryGift> GetMatchingWC6(PKM pkm, IEnumerable<MysteryGift> DB)
{
if (DB == null)
@ -135,6 +142,7 @@ namespace PKHeX.Core
foreach (var z in deferred)
yield return z;
}
private static IEnumerable<MysteryGift> GetMatchingWC7(PKM pkm, IEnumerable<MysteryGift> DB)
{
if (DB == null)
@ -164,6 +172,7 @@ namespace PKHeX.Core
foreach (var z in deferred)
yield return z;
}
private static bool GetIsMatchWC3(PKM pkm, WC3 wc)
{
// Gen3 Version MUST match.
@ -206,6 +215,7 @@ namespace PKHeX.Core
}
return true;
}
private static bool GetIsMatchPCD(PKM pkm, PK4 wc, IEnumerable<DexLevel> vs)
{
if (!wc.IsEgg)
@ -250,6 +260,7 @@ namespace PKHeX.Core
return true;
}
private static bool GetIsMatchPGF(PKM pkm, PGF wc, IEnumerable<DexLevel> vs)
{
if (!wc.IsEgg)
@ -275,7 +286,10 @@ namespace PKHeX.Core
return false;
}
else if (wc.PIDType == 0 && pkm.IsShiny)
{
return false; // can't be traded away for unshiny
}
if (pkm.IsEgg && !pkm.IsNative)
return false;
}
@ -292,6 +306,7 @@ namespace PKHeX.Core
return true;
}
private static bool GetIsMatchWC6(PKM pkm, WC6 wc, IEnumerable<DexLevel> vs)
{
if (pkm.Egg_Location == 0) // Not Egg
@ -316,7 +331,10 @@ namespace PKHeX.Core
return false;
}
else if (wc.PIDType == 0 && pkm.IsShiny)
{
return false; // can't be traded away for unshiny
}
if (pkm.IsEgg && !pkm.IsNative)
return false;
}
@ -337,6 +355,7 @@ namespace PKHeX.Core
return true;
}
private static bool GetIsMatchWC7(PKM pkm, WC7 wc, IEnumerable<DexLevel> vs)
{
if (pkm.Egg_Location == 0) // Not Egg
@ -359,7 +378,9 @@ namespace PKHeX.Core
// Rockruff gift edge case; has altform 1 then evolves to altform 2
}
else
{
return false;
}
}
if (wc.IsEgg)
@ -370,7 +391,10 @@ namespace PKHeX.Core
return false;
}
else if (wc.PIDType == 0 && pkm.IsShiny)
{
return false; // can't be traded away for unshiny
}
if (pkm.IsEgg && !pkm.IsNative)
return false;
}
@ -412,6 +436,7 @@ namespace PKHeX.Core
return true;
return wc.Species != pkm.Species;
}
private static bool GetIsDeferredWC7(PKM pkm, WC7 wc)
{
if (wc.RestrictLanguage != 0 && wc.RestrictLanguage != pkm.Language)
@ -423,6 +448,7 @@ namespace PKHeX.Core
// Utility
private static readonly PGT RangerManaphy = new PGT {Data = {[0] = 7, [8] = 1}};
private static bool IsRangerManaphy(PKM pkm)
{
var egg = pkm.Egg_Location;

View file

@ -27,6 +27,7 @@ namespace PKHeX.Core
didPeek = false;
return true;
}
/// <summary>
/// Sets the enumerator to its initial position, which is before the first element in the collection.
/// </summary>
@ -69,6 +70,7 @@ namespace PKHeX.Core
return peek;
}
public T PeekOrDefault() => !TryFetchPeek() ? default(T) : peek;
/// <summary>

View file

@ -27,6 +27,7 @@ namespace PKHeX.Core
return null;
}
private static EncounterStatic GetSuggestedEncounterEgg(PKM pkm, int loc = -1)
{
int lvl = GetSuggestedEncounterEggMetLevel(pkm);
@ -73,6 +74,7 @@ namespace PKHeX.Core
Level = first.LevelMin,
};
}
private static EncounterStatic GetSuggestedEncounterStatic(EncounterStatic s, int loc = -1)
{
if (loc == -1)
@ -143,6 +145,7 @@ namespace PKHeX.Core
}
return -1;
}
/// <summary>
/// Gets the correct Transfer Met location for the origin game.
/// </summary>

View file

@ -28,6 +28,7 @@ namespace PKHeX.Core
Parse.Clear();
}
}
private IEncounterable _match;
/// <summary>Indicates whether or not the <see cref="PKM"/> originated from <see cref="GameVersion.XD"/>.</summary>
@ -71,6 +72,7 @@ namespace PKHeX.Core
/// <summary>List of all near-matches that were rejected for a given reason.</summary>
public List<EncounterRejected> InvalidMatches;
internal void Reject(CheckResult c)
{
(InvalidMatches ?? (InvalidMatches = new List<EncounterRejected>())).Add(new EncounterRejected(EncounterMatch, c));

View file

@ -28,7 +28,7 @@ namespace PKHeX.Core
{
switch (info.EncounterMatch)
{
case EncounterEgg e: return VerifyEncounterEgg(pkm, e);
case EncounterEgg _: return VerifyEncounterEgg(pkm);
case EncounterLink l: return VerifyEncounterLink(pkm, l);
case EncounterTrade t: return VerifyEncounterTrade(pkm, t);
case EncounterSlot w: return VerifyEncounterWild(pkm, w);
@ -38,13 +38,14 @@ namespace PKHeX.Core
return new CheckResult(Severity.Invalid, V80, CheckIdentifier.Encounter);
}
}
private static CheckResult VerifyEncounterG12(PKM pkm, LegalInfo info)
{
var EncounterMatch = info.EncounterMatch;
if (EncounterMatch.EggEncounter)
{
pkm.WasEgg = true;
return VerifyEncounterEgg(pkm, EncounterMatch);
return VerifyEncounterEgg(pkm);
}
if (EncounterMatch is EncounterSlot1 l)
{
@ -77,6 +78,7 @@ namespace PKHeX.Core
return new CheckResult(Severity.Valid, V68, CheckIdentifier.Encounter);
}
private static CheckResult VerifyWildEncounterCrystal(PKM pkm, EncounterSlot encounter)
{
switch (encounter.Type)
@ -100,6 +102,7 @@ namespace PKHeX.Core
return new CheckResult(Severity.Valid, V68, CheckIdentifier.Encounter);
}
private static CheckResult VerifyWildEncounterCrystalHeadbutt(ITrainerID tr, EncounterSlot encounter)
{
var tree = Encounters2.GetGSCHeadbuttAvailability(encounter, tr.TID);
@ -115,7 +118,7 @@ namespace PKHeX.Core
}
// Eggs
private static CheckResult VerifyEncounterEgg(PKM pkm, IEncounterable egg)
private static CheckResult VerifyEncounterEgg(PKM pkm)
{
pkm.WasEgg = true;
// Check Species
@ -135,10 +138,12 @@ namespace PKHeX.Core
return new CheckResult(Severity.Invalid, V51, CheckIdentifier.Encounter);
}
}
private static CheckResult VerifyEncounterEgg3(PKM pkm)
{
return pkm.Format == 3 ? VerifyEncounterEgg3Native(pkm) : VerifyEncounterEgg3Transfer(pkm);
}
private static CheckResult VerifyEncounterEgg3Native(PKM pkm)
{
if (pkm.Met_Level != 0)
@ -160,6 +165,7 @@ namespace PKHeX.Core
}
return new CheckResult(Severity.Valid, V53, CheckIdentifier.Encounter);
}
private static CheckResult VerifyEncounterEgg3Transfer(PKM pkm)
{
if (pkm.IsEgg)
@ -175,6 +181,7 @@ namespace PKHeX.Core
return new CheckResult(Severity.Valid, V53, CheckIdentifier.Encounter);
}
private static CheckResult VerifyEncounterEgg4(PKM pkm)
{
if (pkm.Format == 4)
@ -189,10 +196,12 @@ namespace PKHeX.Core
return new CheckResult(Severity.Invalid, V61, CheckIdentifier.Encounter);
return new CheckResult(Severity.Valid, V53, CheckIdentifier.Encounter);
}
private static CheckResult VerifyEncounterEgg5(PKM pkm)
{
return VerifyEncounterEggLevelLoc(pkm, 1, pkm.B2W2 ? Legal.ValidMet_B2W2 : Legal.ValidMet_BW);
}
private static CheckResult VerifyEncounterEgg6(PKM pkm)
{
if (pkm.AO)
@ -203,6 +212,7 @@ namespace PKHeX.Core
return VerifyEncounterEggLevelLoc(pkm, 1, Legal.ValidMet_XY);
}
private static CheckResult VerifyEncounterEgg7(PKM pkm)
{
if (pkm.SM)
@ -213,6 +223,7 @@ namespace PKHeX.Core
// no other games
return new CheckResult(Severity.Invalid, V51, CheckIdentifier.Encounter);
}
private static CheckResult VerifyEncounterEggLevelLoc(PKM pkm, int eggLevel, ICollection<int> MetLocations)
{
if (pkm.Met_Level != eggLevel)
@ -221,6 +232,7 @@ namespace PKHeX.Core
? new CheckResult(Severity.Valid, V53, CheckIdentifier.Encounter)
: new CheckResult(Severity.Invalid, V54, CheckIdentifier.Encounter);
}
private static CheckResult VerifyUnhatchedEgg(PKM pkm, int tradeLoc)
{
var eggLevel = pkm.Format < 5 ? 0 : 1;
@ -249,27 +261,34 @@ namespace PKHeX.Core
}
if (slot.Permissions.IsNormalLead)
{
return slot.Permissions.Pressure
? new CheckResult(Severity.Valid, V67, CheckIdentifier.Encounter)
: new CheckResult(Severity.Valid, V68, CheckIdentifier.Encounter);
}
// Decreased Level Encounters
if (slot.Permissions.WhiteFlute)
{
return slot.Permissions.Pressure
? new CheckResult(Severity.Valid, V69, CheckIdentifier.Encounter)
: new CheckResult(Severity.Valid, V70, CheckIdentifier.Encounter);
}
// Increased Level Encounters
if (slot.Permissions.BlackFlute)
{
return slot.Permissions.Pressure
? new CheckResult(Severity.Valid, V71, CheckIdentifier.Encounter)
: new CheckResult(Severity.Valid, V72, CheckIdentifier.Encounter);
}
if (slot.Permissions.Pressure)
return new CheckResult(Severity.Valid, V67, CheckIdentifier.Encounter);
return new CheckResult(Severity.Valid, V73, CheckIdentifier.Encounter);
}
private static CheckResult VerifyEncounterStatic(PKM pkm, EncounterStatic s)
{
// Check for Unreleased Encounters / Collisions
@ -301,13 +320,14 @@ namespace PKHeX.Core
}
if (s.EggEncounter && !pkm.IsEgg) // hatched
{
var hatchCheck = VerifyEncounterEgg(pkm, null);
var hatchCheck = VerifyEncounterEgg(pkm);
if (!hatchCheck.Valid)
return hatchCheck;
}
return new CheckResult(Severity.Valid, V75, CheckIdentifier.Encounter);
}
private static CheckResult VerifyEncounterTrade(PKM pkm, EncounterTrade trade)
{
if (trade.Species == pkm.Species && trade.EvolveOnTrade)
@ -321,6 +341,7 @@ namespace PKHeX.Core
}
return new CheckResult(Severity.Valid, V76, CheckIdentifier.Encounter);
}
private static CheckResult VerifyEncounterLink(PKM pkm, EncounterLink enc)
{
// Should NOT be Fateful, and should be in Database
@ -339,6 +360,7 @@ namespace PKHeX.Core
? new CheckResult(Severity.Invalid, V48, CheckIdentifier.Encounter)
: new CheckResult(Severity.Valid, V49, CheckIdentifier.Encounter);
}
private static CheckResult VerifyEncounterEvent(PKM pkm, MysteryGift MatchedGift)
{
switch (MatchedGift)
@ -350,7 +372,7 @@ namespace PKHeX.Core
}
if (!pkm.IsEgg && MatchedGift.IsEgg) // hatched
{
var hatchCheck = VerifyEncounterEgg(pkm, null);
var hatchCheck = VerifyEncounterEgg(pkm);
if (!hatchCheck.Valid)
return hatchCheck;
}

View file

@ -39,15 +39,20 @@ namespace PKHeX.Core
public static int GetSuggestedLanguage(this MysteryGiftRestriction value)
{
for (int i = (int)LanguageID.Japanese; i <= (int)LanguageID.Korean; i++)
{
if (value.HasFlagFast((MysteryGiftRestriction)(1 << i)))
return i;
}
return -1;
}
public static int GetSuggestedRegion(this MysteryGiftRestriction value)
{
for (int i = (int)RegionID.Japan; i <= (int)RegionID.Taiwan; i++)
{
if (value.HasFlagFast((MysteryGiftRestriction)((int)MysteryGiftRestriction.RegionBase << i)))
return i;
}
return -1;
}
}

View file

@ -7,6 +7,7 @@ namespace PKHeX.Core
public static class MysteryGiftVerifier
{
private static readonly Dictionary<int, MysteryGiftRestriction>[] RestrictionSet = Get();
private static Dictionary<int, MysteryGiftRestriction>[] Get()
{
var s = new Dictionary<int, MysteryGiftRestriction>[PKX.Generation + 1];
@ -16,6 +17,7 @@ namespace PKHeX.Core
}
private static string RestrictionSetName(int i) => $"mgrestrict{i}.pkl";
private static Dictionary<int, MysteryGiftRestriction> GetRestriction(int generation)
{
var resource = RestrictionSetName(generation);

View file

@ -66,6 +66,7 @@ namespace PKHeX.Core
pkm.TradebackStatus = defaultTradeback;
return res;
}
private static CheckMoveResult[] ParseMovesForSmeargle(PKM pkm, int[] Moves, LegalInfo info)
{
if (!pkm.IsEgg)
@ -78,17 +79,19 @@ namespace PKHeX.Core
var source = new MoveParseSource { CurrentMoves = pkm.Moves, };
return ParseMoves(pkm, source, info);
}
private static CheckMoveResult[] ParseMovesIsEggPreRelearn(PKM pkm, int[] Moves, int[] SpecialMoves, EncounterEgg e)
{
EggInfoSource infoset = new EggInfoSource(pkm, SpecialMoves, e);
return VerifyPreRelearnEggBase(pkm, Moves, infoset);
}
private static CheckMoveResult[] ParseMovesWasEggPreRelearn(PKM pkm, int[] Moves, LegalInfo info, EncounterEgg e)
{
var EventEggMoves = GetSpecialMoves(info.EncounterMatch);
// Level up moves could not be inherited if Ditto is parent,
// that means genderless species and male only species except Nidoran and Volbeat (they breed with female nidoran and illumise) could not have level up moves as an egg
var AllowLevelUp = pkm.PersonalInfo.Gender > 0 && pkm.PersonalInfo.Gender < 255 || Legal.MixedGenderBreeding.Contains(e.Species);
var AllowLevelUp = (pkm.PersonalInfo.Gender > 0 && pkm.PersonalInfo.Gender < 255) || Legal.MixedGenderBreeding.Contains(e.Species);
int BaseLevel = AllowLevelUp ? 100 : e.LevelMin;
var LevelUp = Legal.GetBaseEggMoves(pkm, e.Species, e.Version, BaseLevel);
@ -116,15 +119,20 @@ namespace PKHeX.Core
};
return ParseMoves(pkm, source, info);
}
private static CheckMoveResult[] ParseMovesSketch(PKM pkm, int[] Moves)
{
CheckMoveResult[] res = new CheckMoveResult[4];
var res = new CheckMoveResult[4];
for (int i = 0; i < 4; i++)
{
res[i] = Legal.InvalidSketch.Contains(Moves[i])
? new CheckMoveResult(MoveSource.Unknown, pkm.Format, Severity.Invalid, V166, CheckIdentifier.Move)
: new CheckMoveResult(MoveSource.Sketch, pkm.Format, CheckIdentifier.Move);
}
return res;
}
private static CheckMoveResult[] ParseMoves3DS(PKM pkm, int[] Moves, LegalInfo info)
{
info.EncounterMoves.Relearn = info.Generation >= 6 ? pkm.RelearnMoves : Array.Empty<int>();
@ -134,6 +142,7 @@ namespace PKHeX.Core
// Everything else
return ParseMovesRelearn(pkm, Moves, info);
}
private static CheckMoveResult[] ParseMovesPre3DS(PKM pkm, int[] Moves, LegalInfo info)
{
if (pkm.IsEgg && info.EncounterMatch is EncounterEgg egg)
@ -143,12 +152,12 @@ namespace PKHeX.Core
}
if (info.EncounterMatch is EncounterEgg e)
return ParseMovesWasEggPreRelearn(pkm, Moves, info, e);
if (info.Generation <= 2 &&
info.EncounterMatch is IGeneration g && (g.Generation == 1 || g.Generation == 2 && !Legal.AllowGen2MoveReminder(pkm))) // fixed encounter moves without relearning
if (info.Generation <= 2 && info.EncounterMatch is IGeneration g && (g.Generation == 1 || (g.Generation == 2 && !Legal.AllowGen2MoveReminder(pkm)))) // fixed encounter moves without relearning
return ParseMovesGenGB(pkm, Moves, info);
return ParseMovesSpecialMoveset(pkm, Moves, info);
}
private static CheckMoveResult[] ParseMovesGenGB(PKM pkm, int[] Moves, LegalInfo info)
{
CheckMoveResult[] res = new CheckMoveResult[4];
@ -177,6 +186,7 @@ namespace PKHeX.Core
}
return res;
}
private static CheckMoveResult[] ParseMovesSpecialMoveset(PKM pkm, int[] Moves, LegalInfo info)
{
var source = new MoveParseSource
@ -186,12 +196,14 @@ namespace PKHeX.Core
};
return ParseMoves(pkm, source, info);
}
private static int[] GetSpecialMoves(IEncounterable EncounterMatch)
{
if (EncounterMatch is IMoveset mg)
return mg.Moves ?? Array.Empty<int>();
return Array.Empty<int>();
}
private static CheckMoveResult[] ParseMovesRelearn(PKM pkm, int[] Moves, LegalInfo info)
{
var source = new MoveParseSource
@ -207,11 +219,14 @@ namespace PKHeX.Core
int[] RelearnMoves = pkm.RelearnMoves;
for (int i = 0; i < 4; i++)
{
if ((pkm.IsEgg || res[i].Flag) && !RelearnMoves.Contains(Moves[i]))
res[i] = new CheckMoveResult(res[i], Severity.Invalid, string.Format(V170, res[i].Comment), res[i].Identifier);
}
return res;
}
private static CheckMoveResult[] ParseMoves(PKM pkm, MoveParseSource source, LegalInfo info)
{
CheckMoveResult[] res = new CheckMoveResult[4];
@ -255,6 +270,7 @@ namespace PKHeX.Core
}
return res;
}
private static void ParseMovesByGeneration(PKM pkm, CheckMoveResult[] res, int gen, LegalInfo info, LearnInfo learnInfo, int last)
{
GetHMCompatibility(pkm, res, gen, learnInfo.Source.CurrentMoves, out bool[] HMLearned, out bool KnowDefogWhirlpool);
@ -283,6 +299,7 @@ namespace PKHeX.Core
if (Legal.SpeciesEvolutionWithMove.Contains(pkm.Species))
ParseEvolutionLevelupMove(pkm, res, learnInfo.Source.CurrentMoves, learnInfo.IncenseMoves, info);
}
private static void ParseMovesByGeneration(PKM pkm, IList<CheckMoveResult> res, int gen, LegalInfo info, LearnInfo learnInfo)
{
var moves = learnInfo.Source.CurrentMoves;
@ -332,6 +349,7 @@ namespace PKHeX.Core
pkm.TradebackStatus = TradebackType.WasTradeback;
}
}
private static void ParseMovesByGeneration12(PKM pkm, CheckMoveResult[] res, int[] moves, int gen, LegalInfo info, LearnInfo learnInfo)
{
// Mark the gen 1 exclusive moves as illegal because the pokemon also have Non tradeback egg moves.
@ -350,12 +368,14 @@ namespace PKHeX.Core
ParseEvolutionsIncompatibleMoves(pkm, res, moves, info.EncounterMoves.TMHMMoves[1]);
}
}
private static void ParseMovesByGenerationLast(PKM pkm, CheckMoveResult[] res, int gen, LearnInfo learnInfo)
{
ParseEggMovesInherited(pkm, res, gen, learnInfo);
ParseEggMoves(pkm, res, gen, learnInfo);
ParseEggMovesRemaining(pkm, res, learnInfo);
}
private static void ParseEggMovesInherited(PKM pkm, CheckMoveResult[] res, int gen, LearnInfo learnInfo)
{
var moves = learnInfo.Source.CurrentMoves;
@ -376,12 +396,15 @@ namespace PKHeX.Core
learnInfo.MixedGen12NonTradeback = true;
}
else
{
res[m] = new CheckMoveResult(MoveSource.InheritLevelUp, gen, Severity.Valid, V345, CheckIdentifier.Move);
}
learnInfo.LevelUpEggMoves.Add(m);
if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1)
pkm.TradebackStatus = TradebackType.WasTradeback;
}
}
private static void ParseEggMoves(PKM pkm, CheckMoveResult[] res, int gen, LearnInfo learnInfo)
{
var moves = learnInfo.Source.CurrentMoves;
@ -405,7 +428,9 @@ namespace PKHeX.Core
learnInfo.MixedGen12NonTradeback = true;
}
else
{
res[m] = new CheckMoveResult(MoveSource.EggMove, gen, Severity.Valid, V171, CheckIdentifier.Move) { Flag = true };
}
learnInfo.EggMovesLearned.Add(m);
if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1)
@ -422,13 +447,16 @@ namespace PKHeX.Core
learnInfo.MixedGen12NonTradeback = true;
}
else
{
res[m] = new CheckMoveResult(MoveSource.SpecialEgg, gen, Severity.Valid, V333, CheckIdentifier.Move);
}
}
if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1)
pkm.TradebackStatus = TradebackType.WasTradeback;
learnInfo.EventEggMoves.Add(m);
}
}
private static void ParseEggMovesRemaining(PKM pkm, CheckMoveResult[] res, LearnInfo learnInfo)
{
// A pokemon could have normal egg moves and regular egg moves
@ -462,14 +490,17 @@ namespace PKHeX.Core
}
}
}
private static void ParseRedYellowIncompatibleMoves(PKM pkm, IList<CheckMoveResult> res, int[] moves)
{
var incompatible = GetIncompatibleRBYMoves(pkm, moves);
if (incompatible.Count == 0)
return;
for (int m = 0; m < 4; m++)
{
if (incompatible.Contains(moves[m]))
res[m] = new CheckMoveResult(res[m], Severity.Invalid, V363, CheckIdentifier.Move);
}
}
private static List<int> GetIncompatibleRBYMoves(PKM pkm, int[] moves)
@ -555,6 +586,7 @@ namespace PKHeX.Core
res[m] = new CheckMoveResult(res[m], Severity.Invalid, string.Format(V366, currentspecies, previousspecies), CheckIdentifier.Move);
}
}
private static void ParseShedinjaEvolveMoves(PKM pkm, IList<CheckMoveResult> res, int[] moves)
{
var ShedinjaEvoMovesLearned = new List<int>();
@ -605,17 +637,17 @@ namespace PKHeX.Core
res[m] = new CheckMoveResult(res[m], Severity.Invalid, string.Format(V366, SpeciesStrings[290], SpeciesStrings[291]), CheckIdentifier.Move);
}
}
private static void ParseEvolutionLevelupMove(PKM pkm, IList<CheckMoveResult> res, int[] moves, List<int> IncenseMovesLearned, LegalInfo info)
{
// Ignore if there is an invalid move or an empty move, this validation is only for 4 non-empty moves that are all valid, but invalid as a 4 combination
// Ignore Mr. Mime and Sudowodoo from generations 1 to 3, they cant be evolved from Bonsly or Munchlax
// Ignore if encounter species is the evolution species, the pokemon was not evolved by the player
if (!res.All(r => r?.Valid ?? false) || moves.Any(m => m == 0) ||
(Legal.BabyEvolutionWithMove.Contains(pkm.Species) && pkm.GenNumber <= 3) ||
info.EncounterMatch.Species == pkm.Species)
if (!res.All(r => r?.Valid ?? false) || moves.Any(m => m == 0) || (Legal.BabyEvolutionWithMove.Contains(pkm.Species) && pkm.GenNumber <= 3) || info.EncounterMatch.Species == pkm.Species)
return;
var ValidMoves = Legal.GetValidPostEvolutionMoves(pkm, pkm.Species, info.EvoChainsAllGens, GameVersion.Any);
// Add the evolution moves to valid moves in case some of these moves could not be learned after evolving
switch (pkm.Species)
{
@ -649,6 +681,7 @@ namespace PKHeX.Core
for (int m = 0; m < 4; m++)
res[m] = new CheckMoveResult(res[m], Severity.Invalid, string.Format(V385, SpeciesStrings[pkm.Species]), CheckIdentifier.Move);
}
private static void GetHMCompatibility(PKM pkm, IReadOnlyList<CheckResult> res, int gen, IReadOnlyList<int> moves, out bool[] HMLearned, out bool KnowDefogWhirlpool)
{
HMLearned = new bool[4];
@ -669,9 +702,11 @@ namespace PKHeX.Core
flags[i] = IsCheckInvalid(res[i]) && source.Contains(moves[i]);
}
}
private static bool IsDefogWhirl(int move) => move == 250 || move == 432;
private static bool IsCheckInvalid(CheckResult chk) => !(chk?.Valid ?? false);
private static bool IsCheckValid(CheckResult chk) => chk?.Valid ?? false;
private static void FlagIncompatibleTransferHMs(CheckMoveResult[] res, int[] moves, int gen, bool[] HMLearned, bool KnowDefogWhirlpool)
{
// After all the moves from the generations 3 and 4,
@ -682,15 +717,21 @@ namespace PKHeX.Core
{
int invalidCount = moves.Where((m, i) => IsDefogWhirl(m) && IsCheckValid(res[i])).Count();
if (invalidCount == 2) // can't know both at the same time
{
for (int i = 0; i < 4; i++) // flag both moves
{
if (IsDefogWhirl(moves[i]))
res[i] = new CheckMoveResult(res[i], Severity.Invalid, V338, CheckIdentifier.Move);
}
}
}
// Flag moves that are only legal when learned from a past-gen HM source
for (int i = 0; i < HMLearned.Length; i++)
{
if (HMLearned[i] && IsCheckValid(res[i]))
res[i] = new CheckMoveResult(res[i], Severity.Invalid, string.Format(V339, gen, gen + 1), CheckIdentifier.Move);
}
}
/* Similar to verifyRelearnEgg but in pre relearn generation is the moves what should match the expected order but only if the pokemon is inside an egg */
@ -766,6 +807,7 @@ namespace PKHeX.Core
return res;
}
private static int GetRequiredBaseMoveCount(int[] Moves, EggInfoSource infoset)
{
int baseCt = infoset.Base.Count;
@ -796,6 +838,7 @@ namespace PKHeX.Core
res[i] = new CheckMoveResult(res[i], Severity.Invalid, V168, res[i].Identifier);
}
}
private static void UpdateGen1LevelUpMoves(PKM pkm, ValidEncounterMoves EncounterMoves, int defaultLvlG1, int generation, LegalInfo info)
{
switch (generation)
@ -808,6 +851,7 @@ namespace PKHeX.Core
break;
}
}
private static void UpdateGen2LevelUpMoves(PKM pkm, ValidEncounterMoves EncounterMoves, int defaultLvlG2, int generation, LegalInfo info)
{
switch (generation)
@ -820,6 +864,7 @@ namespace PKHeX.Core
break;
}
}
public static int[] GetGenMovesCheckOrder(PKM pkm)
{
if (pkm.Format < 3)
@ -829,6 +874,7 @@ namespace PKHeX.Core
return GetGenMovesOrder(pkm.Format, pkm.GenNumber);
}
private static int[] GetGenMovesOrderVC(PKM pkm)
{
// VC case: check transfer games in reverse order (8, 7..) then past games.
@ -839,12 +885,14 @@ namespace PKHeX.Core
past.CopyTo(xfer, end);
return xfer;
}
private static int[] GetGenMovesCheckOrderGB(PKM pkm, int originalGeneration)
{
if (originalGeneration == 2)
return pkm.Korean ? new[] {2} : new[] {2, 1};
return new[] {1, 2}; // RBY
}
private static int[] GetGenMovesOrder(int start, int end)
{
if (end < 0)

View file

@ -22,7 +22,7 @@ namespace PKHeX.Core
return VerifyRelearnSpecifiedMoveset(pkm, info, l.RelearnMoves);
case MysteryGift g:
return VerifyRelearnSpecifiedMoveset(pkm, info, g.RelearnMoves);
case EncounterStatic s:
case EncounterStatic s when s.Relearn.Length > 0:
return VerifyRelearnSpecifiedMoveset(pkm, info, s.Relearn);
case EncounterEgg e:
return VerifyRelearnEggBase(pkm, info, e);
@ -36,16 +36,18 @@ namespace PKHeX.Core
{
CheckResult[] res = new CheckResult[4];
int[] RelearnMoves = pkm.RelearnMoves;
// Get gifts that match
for (int i = 0; i < 4; i++)
{
res[i] = moves[i] != RelearnMoves[i]
? new CheckResult(Severity.Invalid, string.Format(V178, MoveStrings[moves[i]]), CheckIdentifier.RelearnMove)
: new CheckResult(CheckIdentifier.RelearnMove);
}
info.RelearnBase = moves;
return res;
}
private static CheckResult[] VerifyRelearnDexNav(PKM pkm, LegalInfo info)
{
CheckResult[] res = new CheckResult[4];
@ -58,9 +60,11 @@ namespace PKHeX.Core
// All other relearn moves must be empty.
for (int i = 1; i < 4; i++)
{
res[i] = RelearnMoves[i] != 0
? new CheckResult(Severity.Invalid, V184, CheckIdentifier.RelearnMove)
: new CheckResult(CheckIdentifier.RelearnMove);
}
// Update the relearn base moves if the first relearn move is okay.
info.RelearnBase = res[0].Valid
@ -69,6 +73,7 @@ namespace PKHeX.Core
return res;
}
private static CheckResult[] VerifyRelearnNone(PKM pkm, LegalInfo info)
{
CheckResult[] res = new CheckResult[4];
@ -76,13 +81,16 @@ namespace PKHeX.Core
// No relearn moves should be present.
for (int i = 0; i < 4; i++)
{
res[i] = RelearnMoves[i] != 0
? new CheckResult(Severity.Invalid, V184, CheckIdentifier.RelearnMove)
: new CheckResult(CheckIdentifier.RelearnMove);
}
info.RelearnBase = new int[4];
return res;
}
private static CheckResult[] VerifyRelearnEggBase(PKM pkm, LegalInfo info, EncounterEgg e)
{
int[] RelearnMoves = pkm.RelearnMoves;
@ -118,6 +126,7 @@ namespace PKHeX.Core
info.RelearnBase = baseMoves;
return res;
}
private static void FlagBaseEggMoves(CheckResult[] res, int required, IReadOnlyList<int> baseMoves, IReadOnlyList<int> RelearnMoves)
{
for (int i = 0; i < required; i++)
@ -130,6 +139,7 @@ namespace PKHeX.Core
res[i] = new CheckResult(Severity.Valid, V179, CheckIdentifier.RelearnMove);
}
}
private static void FlagRelearnMovesMissing(CheckResult[] res, int required, IReadOnlyList<int> baseMoves, int start)
{
for (int z = start; z < required; z++)
@ -139,6 +149,7 @@ namespace PKHeX.Core
string em = string.Join(", ", GetMoveNames(baseMoves));
res[required - 1].Comment += string.Format(Environment.NewLine + V181, em);
}
private static bool FlagInvalidInheritedMoves(CheckResult[] res, int required, IReadOnlyList<int> RelearnMoves, IReadOnlyList<int> inheritMoves, IReadOnlyList<int> splitMoves)
{
bool splitInvalid = false;
@ -157,6 +168,7 @@ namespace PKHeX.Core
return splitInvalid;
}
private static void FlagSplitbreedMoves(CheckResult[] res, int required, EncounterEgg e, PKM pkm)
{
var other = e is EncounterEggSplit x ? x.OtherSpecies : Legal.GetBaseEggSpecies(pkm, 1);

View file

@ -7,107 +7,133 @@
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.Moves"/>.
/// </summary>
Move,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.RelearnMoves"/>.
/// </summary>
RelearnMove,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM"/>'s matched encounter information.
/// </summary>
Encounter,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.IsShiny"/> status.
/// </summary>
Shiny,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.EncryptionConstant"/>.
/// </summary>
EC,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.PID"/>.
/// </summary>
PID,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.Gender"/>.
/// </summary>
Gender,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.EVs"/>.
/// </summary>
EVs,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.Language"/>.
/// </summary>
Language,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.Nickname"/>.
/// </summary>
Nickname,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.OT_Name"/>, <see cref="PKM.TID"/>, or <see cref="PKM.SID"/>.
/// </summary>
Trainer,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.IVs"/>.
/// </summary>
IVs,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.Met_Level"/> or <see cref="PKM.CurrentLevel"/>.
/// </summary>
Level,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.Ball"/>.
/// </summary>
Ball,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM"/> memory data.
/// </summary>
Memory,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM"/> geography data.
/// </summary>
Geography,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.AltForm"/>.
/// </summary>
Form,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.IsEgg"/> status.
/// </summary>
Egg,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM"/> miscellaneous properties.
/// </summary>
Misc,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.FatefulEncounter"/>.
/// </summary>
Fateful,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM"/> ribbon data.
/// </summary>
Ribbon,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM"/> super training data.
/// </summary>
Training,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.Ability"/>.
/// </summary>
Ability,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM"/> evolution chain relative to the matched encounter.
/// </summary>
Evolution,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM.Nature"/>.
/// </summary>
Nature,
/// <summary>
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM"/>'s <see cref="PKM.Version"/> compatibility.
/// <remarks>This is used for parsing checks to ensure the <see cref="PKM"/> didn't debut on a future <see cref="PKM.GenNumber"/></remarks>
/// </summary>
GameOrigin,
/// <summary>
/// The CheckResult pertains to the <see cref="PKM.HeldItem"/>.
/// </summary>

View file

@ -17,6 +17,7 @@ namespace PKHeX.Core
internal static class EncounterTimeExtension
{
internal static bool Contains(this EncounterTime t1, int t2) => t1 == EncounterTime.Any || (t1 & (EncounterTime)(1 << t2)) != 0;
internal static int RandomValidTime(this EncounterTime t1)
{
int val = Util.Rand.Next(1, 4);

View file

@ -14,70 +14,87 @@ namespace PKHeX.Core
/// Default (un-assigned) encounter slot type.
/// </summary>
Any = 0,
/// <summary>
/// Slot is encountered via Grass.
/// </summary>
Grass = 1 << 00,
/// <summary>
/// Slot is encountered via Surfing.
/// </summary>
Surf = 1 << 01,
/// <summary>
/// Slot is encountered via Old Rod (Fishing).
/// </summary>
Old_Rod = 1 << 02,
/// <summary>
/// Slot is encountered via Good Rod (Fishing).
/// </summary>
Good_Rod = 1 << 03,
/// <summary>
/// Slot is encountered via Super Rod (Fishing).
/// </summary>
Super_Rod = 1 << 04,
/// <summary>
/// Slot is encountered via Rock Smash.
/// </summary>
Rock_Smash = 1 << 05,
/// <summary>
/// Slot is encountered via a Horde.
/// </summary>
Horde = 1 << 06,
/// <summary>
/// Slot is encountered via the Friend Safari.
/// </summary>
FriendSafari = 1 << 07,
/// <summary>
/// Slot is encountered through special means. Used to signify special slots for Gen2, sometimes for later follow-up).
/// </summary>
Special = 1 << 08,
/// <summary>
/// Slot is encountered via SOS signal.
/// </summary>
SOS = 1 << 09,
/// <summary>
/// Slot is encountered in a Swarm.
/// </summary>
Swarm = 1 << 10,
/// <summary>
/// Slot is encountered via Headbutt.
/// </summary>
Headbutt = 1 << 11,
/// <summary>
/// Slot is encountered via the Poké Radar.
/// </summary>
Pokeradar = 1 << 12,
/// <summary>
/// Slot is encountered via a Honey Tree.
/// </summary>
HoneyTree = 1 << 13,
/// <summary>
/// Slot is encountered via a Hidden Grotto.
/// </summary>
HiddenGrotto = 1 << 14,
/// <summary>
/// Slot is encountered via the Bug Catching Contest.
/// </summary>
BugContest = 1 << 15,
/// <summary>
/// Slot is encountered in the Safari Zone.
/// </summary>
@ -103,10 +120,12 @@ namespace PKHeX.Core
public static partial class Extensions
{
internal static bool IsSafariType(this SlotType t) => (t & SlotType.Safari) != 0;
internal static bool IsFishingRodType(this SlotType t)
{
return (t & SlotType.Old_Rod) != 0 || (t & SlotType.Good_Rod) != 0 || (t & SlotType.Super_Rod) != 0;
}
internal static bool IsSweetScentType(this SlotType t)
{
return !(t.IsFishingRodType() || (t & SlotType.Rock_Smash) != 0);

View file

@ -9,6 +9,7 @@ namespace PKHeX.Core
public static class EvolutionChain
{
private static readonly List<EvoCriteria> NONE = new List<EvoCriteria>(0);
internal static IReadOnlyList<EvoCriteria>[] GetEvolutionChainsAllGens(PKM pkm, IEncounterable Encounter)
{
var CompleteEvoChain = GetEvolutionChain(pkm, Encounter, pkm.Species, pkm.CurrentLevel);
@ -150,10 +151,13 @@ namespace PKHeX.Core
internal static int GetEvoChainSpeciesIndex(IReadOnlyList<EvoCriteria> chain, int species)
{
for (int i = 0; i < chain.Count; i++)
{
if (chain[i].Species == species)
return i;
}
return -1;
}
private static List<EvoCriteria> GetEvolutionChain(PKM pkm, IEncounterable Encounter, int maxspec, int maxlevel)
{
var vs = GetValidPreEvolutions(pkm);
@ -231,16 +235,22 @@ namespace PKHeX.Core
if (lvl < 0)
lvl = pkm.CurrentLevel;
if (pkm.IsEgg && !skipChecks)
{
return new List<EvoCriteria>
{
new EvoCriteria { Species = pkm.Species, Level = lvl, MinLevel = lvl },
};
}
if (pkm.Species == 292 && lvl >= 20 && (!pkm.HasOriginalMetLocation || pkm.Met_Level + 1 <= lvl))
{
return new List<EvoCriteria>
{
new EvoCriteria { Species = 292, Level = lvl, MinLevel = 20 },
new EvoCriteria { Species = 290, Level = lvl, MinLevel = 1 }
};
}
if (maxspeciesorigin == -1 && pkm.InhabitedGeneration(2) && pkm.Format <= 2 && pkm.GenNumber == 1)
maxspeciesorigin = MaxSpeciesID_2;
@ -248,6 +258,7 @@ namespace PKHeX.Core
var et = EvolutionTree.GetEvolutionTree(tree);
return et.GetValidPreEvolutions(pkm, maxLevel: lvl, maxSpeciesOrigin: maxspeciesorigin, skipChecks: skipChecks);
}
private static int GetMinLevelGeneration(PKM pkm, int generation)
{
if (!pkm.InhabitedGeneration(generation))

View file

@ -14,14 +14,17 @@ namespace PKHeX.Core
{
int matchChain = -1;
for (int i = 0; i < Chain.Count; i++)
{
if (Chain[i].StageEntryMethods.Any(e => e.Species == entry.Species))
matchChain = i;
}
if (matchChain != -1)
Chain[matchChain].StageEntryMethods.Add(entry);
else
Chain.Insert(0, new EvolutionStage { StageEntryMethods = new List<EvolutionMethod> {entry}});
}
public void Insert(EvolutionStage evo)
{
Chain.Insert(0, evo);
@ -71,6 +74,7 @@ namespace PKHeX.Core
last.RequiresLvlUp = false;
return dl;
}
private static void UpdateMinValues(IReadOnlyList<EvoCriteria> dl, EvolutionMethod evo)
{
var last = dl[dl.Count - 1];

View file

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
@ -17,7 +18,7 @@ namespace PKHeX.Core
public bool RequiresLevelUp;
internal static readonly HashSet<int> TradeMethods = new HashSet<int> {5, 6, 7};
private static readonly IReadOnlyCollection<GameVersion> NoBanlist = new GameVersion[0];
private static readonly IReadOnlyCollection<GameVersion> NoBanlist = Array.Empty<GameVersion>();
internal static readonly IReadOnlyCollection<GameVersion> BanSM = new[] {GameVersion.SN, GameVersion.MN};
internal IReadOnlyCollection<GameVersion> Banlist = NoBanlist;
@ -25,8 +26,10 @@ namespace PKHeX.Core
{
RequiresLevelUp = false;
if (Form > -1)
{
if (!skipChecks && pkm.AltForm != Form)
return false;
}
if (!skipChecks && Banlist.Contains((GameVersion)pkm.Version) && pkm.IsUntraded) // sm lacks usum kantonian evos
return false;
@ -68,7 +71,7 @@ namespace PKHeX.Core
case 37: // Daytime on Version
case 38: // Nighttime on Version
// Version checks come in pairs, check for any pair match
if ((pkm.Version & 1) != (Argument & 1) && pkm.IsUntraded || skipChecks)
if (((pkm.Version & 1) != (Argument & 1) && pkm.IsUntraded) || skipChecks)
return skipChecks;
goto default;

View file

@ -181,6 +181,7 @@ namespace PKHeX.Core
return pkm.Species;
return Personal.GetFormeIndex(pkm.Species, pkm.AltForm);
}
private int GetIndex(EvolutionMethod evo)
{
int evolvesToSpecies = evo.Species;

View file

@ -22,6 +22,7 @@ namespace PKHeX.Core
Levels = levels.ToArray();
Count = Moves.Length;
}
public static Learnset[] GetArray(byte[] input, int maxSpecies)
{
var data = new Learnset[maxSpecies + 1];

View file

@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
namespace PKHeX.Core
{
@ -15,6 +14,7 @@ namespace PKHeX.Core
public MoveParseSource Source { get; set; }
public readonly bool IsGen2Pkm;
public LearnInfo(PKM pkm)
{
IsGen2Pkm = pkm.Format == 2 || pkm.VC2;
@ -25,6 +25,7 @@ namespace PKHeX.Core
{
public readonly GameVersion Game;
public readonly int Level;
public LearnVersion(int lv, GameVersion game = GameVersion.Any)
{
Game = game;

View file

@ -13,6 +13,7 @@ namespace PKHeX.Core
private readonly GameVersion Version;
private readonly PersonalTable Table;
private readonly Learnset[] Learn;
public LearnLookup(PersonalTable table, Learnset[] learn, GameVersion version)
{
Version = version;
@ -26,22 +27,26 @@ namespace PKHeX.Core
return moves;
return Learn[index].AddMoves(moves, max, min);
}
public List<int> AddMoves(List<int> moves, int species, int form, int max, int min = 0)
{
int index = Table.GetFormeIndex(species, form);
return AddMovesIndex(moves, index, max, min);
}
public List<int> AddMoves1(List<int> moves, int species, int form, int max, int min)
{
int index = Table.GetFormeIndex(species, form);
return AddMovesIndex1(moves, index, max, min);
}
public List<int> AddMovesIndex1(List<int> moves, int index, int max, int min)
{
if (min == 1)
moves.AddRange(((PersonalInfoG1)Table[index]).Moves);
return AddMovesIndex(moves, index, max, min);
}
public List<int> GetMoves(int species, int form, int min, int max)
{
int index = Table.GetFormeIndex(species, form);

View file

@ -9,12 +9,13 @@ namespace PKHeX.Core
internal static int[] GetEggMoves(PKM pkm, int species, int formnum, GameVersion version)
{
int gen = pkm.Format <= 2 || pkm.VC ? 2 : pkm.GenNumber;
if (!pkm.InhabitedGeneration(gen, species) || pkm.PersonalInfo.Gender == 255 && !FixedGenderFromBiGender.Contains(species))
if (!pkm.InhabitedGeneration(gen, species) || (pkm.PersonalInfo.Gender == 255 && !FixedGenderFromBiGender.Contains(species)))
return Array.Empty<int>();
if (version == GameVersion.Any)
version = (GameVersion)pkm.Version;
return GetEggMoves(gen, species, formnum, version);
}
private static int[] GetEggMoves(int gen, int species, int formnum, GameVersion version)
{
switch (gen)

View file

@ -77,6 +77,7 @@ namespace PKHeX.Core
return LearnNONE;
}
private static LearnVersion GetIsLevelUp2(int species, int move, int max, int form, int min, bool korean, GameVersion ver = Any)
{
// No Korean Crystal
@ -95,6 +96,7 @@ namespace PKHeX.Core
}
return LearnNONE;
}
private static LearnVersion GetIsLevelUp3(int species, int move, int lvl, int form, GameVersion ver = Any)
{
if (species == 386)
@ -116,6 +118,7 @@ namespace PKHeX.Core
}
return LearnNONE;
}
private static LearnVersion GetIsLevelUp4(int species, int move, int lvl, int form, GameVersion ver = Any)
{
switch (ver)
@ -140,6 +143,7 @@ namespace PKHeX.Core
}
return LearnNONE;
}
private static LearnVersion GetIsLevelUp5(int species, int form, int move, int lvl, GameVersion ver = Any)
{
switch (ver)
@ -156,6 +160,7 @@ namespace PKHeX.Core
}
return LearnNONE;
}
private static LearnVersion GetIsLevelUp6(int species, int move, int lvl, int form, GameVersion ver = Any)
{
switch (ver)
@ -173,6 +178,7 @@ namespace PKHeX.Core
}
return LearnNONE;
}
private static LearnVersion GetIsLevelUp7(int species, int move, int form, GameVersion ver = Any)
{
switch (ver)
@ -223,17 +229,21 @@ namespace PKHeX.Core
return Invalid;
}
}
private static Learnset GetDeoxysLearn3(int form, GameVersion ver = Any)
{
if (ver == Any)
switch (form)
{
case 0: return LevelUpRS[386]; // Normal
case 1: return LevelUpFR[386]; // Attack
case 2: return LevelUpLG[386]; // Defense
case 3: return LevelUpE[386]; // Speed
default: return null;
switch (form)
{
case 0: return LevelUpRS[386]; // Normal
case 1: return LevelUpFR[386]; // Attack
case 2: return LevelUpLG[386]; // Defense
case 3: return LevelUpE[386]; // Speed
default: return null;
}
}
var gen = ver.GetGeneration();
if (gen != 3)
return GetDeoxysLearn3(form);
@ -263,6 +273,7 @@ namespace PKHeX.Core
{
return AddMovesLevelUp1(new List<int>(), ver, species, form, max, min);
}
private static List<int> GetMovesLevelUp2(int species, int form, int max, int min, bool korean, bool removeNewGSCMoves, GameVersion ver = Any)
{
var moves = AddMovesLevelUp2(new List<int>(), ver, species, form, max, min, korean);
@ -270,22 +281,27 @@ namespace PKHeX.Core
moves.RemoveAll(m => m > MaxMoveID_1);
return moves;
}
private static List<int> GetMovesLevelUp3(int species, int form, int max, GameVersion ver = Any)
{
return AddMovesLevelUp3(new List<int>(), ver, species, max, form);
}
private static List<int> GetMovesLevelUp4(int species, int form, int max, GameVersion ver = Any)
{
return AddMovesLevelUp4(new List<int>(), ver, species, max, form);
}
private static List<int> GetMovesLevelUp5(int species, int form, int max, GameVersion ver = Any)
{
return AddMovesLevelUp5(new List<int>(), ver, species, max, form);
}
private static List<int> GetMovesLevelUp6(int species, int form, int max, GameVersion ver = Any)
{
return AddMovesLevelUp6(new List<int>(), ver, species, max, form);
}
private static List<int> GetMovesLevelUp7(int species, int form, int max, bool MoveReminder, GameVersion ver = Any)
{
return AddMovesLevelUp7(new List<int>(), ver, species, max, form, MoveReminder);
@ -306,6 +322,7 @@ namespace PKHeX.Core
}
return moves;
}
private static List<int> AddMovesLevelUp2(List<int> moves, GameVersion ver, int species, int form, int max, int min, bool korean)
{
switch (ver)
@ -323,6 +340,7 @@ namespace PKHeX.Core
}
return moves;
}
private static List<int> AddMovesLevelUp3(List<int> moves, GameVersion ver, int species, int max, int form)
{
if (species == 386)
@ -347,6 +365,7 @@ namespace PKHeX.Core
}
return moves;
}
private static List<int> AddMovesLevelUp4(List<int> moves, GameVersion ver, int species, int max, int form)
{
switch (ver)
@ -367,6 +386,7 @@ namespace PKHeX.Core
}
return moves;
}
private static List<int> AddMovesLevelUp5(List<int> moves, GameVersion ver, int species, int max, int form)
{
switch (ver)
@ -382,6 +402,7 @@ namespace PKHeX.Core
}
return moves;
}
private static List<int> AddMovesLevelUp6(List<int> moves, GameVersion ver, int species, int max, int form)
{
switch (ver)
@ -397,6 +418,7 @@ namespace PKHeX.Core
}
return moves;
}
private static List<int> AddMovesLevelUp7(List<int> moves, GameVersion ver, int species, int max, int form, bool MoveReminder)
{
if (MoveReminder)
@ -442,6 +464,7 @@ namespace PKHeX.Core
return learn[index].GetEncounterMoves(level, lvl0, start);
}
private static int[] GetEncounterMoves2(int species, int level, GameVersion version)
{
var learn = GameData.GetLearnsets(version);

View file

@ -27,35 +27,43 @@ namespace PKHeX.Core
private static GameVersion GetIsMachine1(int species, int move)
{
for (int i = 0; i < Legal.TMHM_RBY.Length; i++)
if (Legal.TMHM_RBY[i] == move)
{
if (PersonalTable.RB[species].TMHM[i])
return GameVersion.RB;
if (PersonalTable.Y[species].TMHM[i])
return GameVersion.Y;
}
{
if (Legal.TMHM_RBY[i] != move)
continue;
if (PersonalTable.RB[species].TMHM[i])
return GameVersion.RB;
if (PersonalTable.Y[species].TMHM[i])
return GameVersion.Y;
}
return Legal.NONE;
}
private static GameVersion GetIsMachine2(int species, int move)
{
for (int i = 0; i < Legal.TMHM_GSC.Length; i++)
{
if (Legal.TMHM_GSC[i] == move && PersonalTable.C[species].TMHM[i])
return GameVersion.GS;
}
return Legal.NONE;
}
private static GameVersion GetIsMachine3(int species, int move, int format, bool RemoveTransfer)
{
for (int i = 0; i < Legal.TM_3.Length; i++)
{
if (Legal.TM_3[i] == move && PersonalTable.E[species].TMHM[i])
return GameVersion.Gen3;
}
if (!RemoveTransfer && format <= 3)
return GetIsMachine3HM(species, move);
return Legal.NONE;
}
private static GameVersion GetIsMachine3HM(int species, int move)
{
int x = 0;
@ -67,17 +75,21 @@ namespace PKHeX.Core
}
return Legal.NONE;
}
private static GameVersion GetIsMachine4(int species, int move, int format, bool RemoveTransfer, int form)
{
for (int i = 0; i < Legal.TM_3.Length; i++)
{
if (Legal.TM_4[i] == move && PersonalTable.HGSS.GetFormeEntry(species, form).TMHM[i])
return GameVersion.Gen4;
}
if (RemoveTransfer && format > 4)
return GetIsMachine4HMTransfer(species, move, form);
return GetIsMachine4HM(species, move, form);
}
private static GameVersion GetIsMachine4HMTransfer(int species, int move, int form)
{
// The combination of both these moves is illegal, it should be checked that the pokemon only learn one
@ -95,6 +107,7 @@ namespace PKHeX.Core
}
return Legal.NONE;
}
private static GameVersion GetIsMachine4HM(int species, int move, int form)
{
{
@ -122,6 +135,7 @@ namespace PKHeX.Core
}
return Legal.NONE;
}
private static GameVersion GetIsMachine5(int species, int move, int form)
{
for (int i = 0; i < Legal.TMHM_BW.Length; i++)
@ -129,6 +143,7 @@ namespace PKHeX.Core
return PersonalTable.B2W2.GetFormeEntry(species, form).TMHM[i] ? GameVersion.Gen5 : Legal.NONE;
return Legal.NONE;
}
private static GameVersion GetIsMachine6(int species, int move, int form, GameVersion ver)
{
if (GameVersion.XY.Contains(ver))
@ -149,6 +164,7 @@ namespace PKHeX.Core
}
return Legal.NONE;
}
private static GameVersion GetIsMachine7(int species, int move, int form, GameVersion ver)
{
if (GameVersion.SM.Contains(ver) && species <= Legal.MaxSpeciesID_7)
@ -201,6 +217,7 @@ namespace PKHeX.Core
r.AddRange(Legal.TMHM_RBY.Where((_, m) => pi_rb.TMHM[m]));
r.AddRange(Legal.TMHM_RBY.Where((_, m) => pi_y.TMHM[m]));
}
private static void AddMachine2(List<int> r, int species)
{
int index = PersonalTable.C.GetFormeIndex(species, 0);
@ -209,6 +226,7 @@ namespace PKHeX.Core
var pi_c = PersonalTable.C[index];
r.AddRange(Legal.TMHM_GSC.Where((_, m) => pi_c.TMHM[m]));
}
private static void AddMachine3(List<int> r, int species, int format, bool RemoveTransfer)
{
int index = PersonalTable.E.GetFormeIndex(species, 0);
@ -222,6 +240,7 @@ namespace PKHeX.Core
else if (format > 3) //Remove HM
r.AddRange(Legal.HM_3.Where((_, m) => pi_c.TMHM[m + 50]).Except(Legal.HM_3));
}
private static void AddMachine4(List<int> r, int species, int format, bool RemoveTransfer, int form)
{
var pi_hgss = PersonalTable.HGSS.GetFormeEntry(species, form);
@ -243,11 +262,13 @@ namespace PKHeX.Core
r.AddRange(Legal.HM_HGSS.Where((_, m) => pi_hgss.TMHM[m + 92]));
}
}
private static void AddMachine5(List<int> r, int species, int form)
{
var pi = PersonalTable.B2W2.GetFormeEntry(species, form);
r.AddRange(Legal.TMHM_BW.Where((_, m) => pi.TMHM[m]));
}
private static void AddMachine6(List<int> r, int species, int form, GameVersion ver = GameVersion.Any)
{
switch (ver)
@ -267,6 +288,7 @@ namespace PKHeX.Core
break;
}
}
private static void AddMachine7(List<int> r, int species, int form, GameVersion ver = GameVersion.Any)
{
switch (ver)
@ -287,16 +309,19 @@ namespace PKHeX.Core
return;
}
}
private static void AddMachine6XY(List<int> r, int species, int form)
{
var pi = PersonalTable.XY.GetFormeEntry(species, form);
r.AddRange(Legal.TMHM_XY.Where((_, m) => pi.TMHM[m]));
}
private static void AddMachine6AO(List<int> r, int species, int form)
{
var pi = PersonalTable.AO.GetFormeEntry(species, form);
r.AddRange(Legal.TMHM_AO.Where((_, m) => pi.TMHM[m]));
}
private static void AddMachineSM(List<int> r, int species, int form)
{
if (species > Legal.MaxSpeciesID_7)
@ -304,6 +329,7 @@ namespace PKHeX.Core
var pi = PersonalTable.SM.GetFormeEntry(species, form);
r.AddRange(Legal.TMHM_SM.Where((_, m) => pi.TMHM[m]));
}
private static void AddMachineUSUM(List<int> r, int species, int form)
{
var pi = PersonalTable.USUM.GetFormeEntry(species, form);

View file

@ -32,6 +32,7 @@ namespace PKHeX.Core
return GameVersion.Stadium;
return NONE;
}
private static GameVersion GetIsTutor2(PKM pkm, int species, int move)
{
if (!AllowGen2Crystal(pkm))
@ -44,14 +45,17 @@ namespace PKHeX.Core
}
return GetIsTutor1(pkm, species, move);
}
private static GameVersion GetIsTutor3(int species, int move)
{
// E Tutors (Free)
// E Tutors (BP)
var info = PersonalTable.E[species];
for (int i = 0; i < Tutor_E.Length; i++)
{
if (Tutor_E[i] == move && info.TypeTutors[i])
return GameVersion.E;
}
// FRLG Tutors
// Only special tutor moves, normal tutor moves are already included in Emerald data
@ -74,60 +78,90 @@ namespace PKHeX.Core
return NONE;
}
private static GameVersion GetIsTutor4(int species, int form, int move)
{
var pi = PersonalTable.HGSS.GetFormeEntry(species, form);
for (int i = 0; i < Tutors_4.Length; i++)
{
if (Tutors_4[i] == move && pi.TypeTutors[i])
return GameVersion.Gen4;
}
for (int i = 0; i < SpecialTutors_4.Length; i++)
{
if (SpecialTutors_4[i] == move && SpecialTutors_Compatibility_4[i].Any(e => e == species))
return GameVersion.HGSS;
}
return NONE;
}
private static GameVersion GetIsTutor5(PKM pkm, int species, int form, bool specialTutors, int move)
{
var pi = PersonalTable.B2W2.GetFormeEntry(species, form);
for (int i = 0; i < TypeTutor6.Length; i++)
{
if (TypeTutor6[i] == move && pi.TypeTutors[i])
return GameVersion.Gen5;
}
if (specialTutors && pkm.HasVisitedB2W2())
{
for (int i = 0; i < Tutors_B2W2.Length; i++)
for (int j = 0; j < Tutors_B2W2[i].Length; j++)
if (Tutors_B2W2[i][j] == move && pi.SpecialTutors[i][j])
return GameVersion.B2W2;
{
for (int j = 0; j < Tutors_B2W2[i].Length; j++)
{
if (Tutors_B2W2[i][j] == move && pi.SpecialTutors[i][j])
return GameVersion.B2W2;
}
}
}
return NONE;
}
private static GameVersion GetIsTutor6(PKM pkm, int species, int form, bool specialTutors, int move)
{
var pi = PersonalTable.AO.GetFormeEntry(species, form);
for (int i = 0; i < TypeTutor6.Length; i++)
{
if (TypeTutor6[i] == move && pi.TypeTutors[i])
return GameVersion.Gen6;
}
if (specialTutors && pkm.HasVisitedORAS())
{
for (int i = 0; i < Tutors_AO.Length; i++)
for (int j = 0; j < Tutors_AO[i].Length; j++)
if (Tutors_AO[i][j] == move && pi.SpecialTutors[i][j])
return GameVersion.ORAS;
{
for (int j = 0; j < Tutors_AO[i].Length; j++)
{
if (Tutors_AO[i][j] == move && pi.SpecialTutors[i][j])
return GameVersion.ORAS;
}
}
}
return NONE;
}
private static GameVersion GetIsTutor7(PKM pkm, int species, int form, bool specialTutors, int move)
{
var pi = PersonalTable.USUM.GetFormeEntry(species, form);
for (int i = 0; i < TypeTutor6.Length; i++)
{
if (TypeTutor6[i] == move && pi.TypeTutors[i])
return GameVersion.Gen7;
}
if (specialTutors && pkm.HasVisitedUSUM())
{
for (int i = 0; i < Tutors_USUM.Length; i++)
{
if (Tutors_USUM[i] == move && pi.SpecialTutors[0][i])
return GameVersion.USUM;
}
}
return NONE;
}
@ -153,6 +187,7 @@ namespace PKHeX.Core
if (AllowGBCartEra && format < 3 && (species == 25 || species == 26)) // Surf Pikachu via Stadium
moves.Add(57);
}
private static void AddMovesTutor2(List<int> moves, int species, int format, bool korean = false)
{
if (korean)
@ -161,6 +196,7 @@ namespace PKHeX.Core
moves.AddRange(Tutors_GSC.Where((_, i) => pi.TMHM[57 + i]));
AddMovesTutor1(moves, species, format);
}
private static void AddMovesTutor3(List<int> moves, int species)
{
// E Tutors (Free)
@ -176,12 +212,14 @@ namespace PKHeX.Core
if (species == 151)
moves.AddRange(Tutor_3Mew);
}
private static void AddMovesTutor4(List<int> moves, int species, int form)
{
var pi = PersonalTable.HGSS.GetFormeEntry(species, form);
moves.AddRange(Tutors_4.Where((_, i) => pi.TypeTutors[i]));
moves.AddRange(SpecialTutors_4.Where((_, i) => SpecialTutors_Compatibility_4[i].Any(e => e == species)));
}
private static void AddMovesTutor5(List<int> moves, int species, int form, PKM pkm, bool specialTutors)
{
var pi = PersonalTable.B2W2[species];
@ -189,6 +227,7 @@ namespace PKHeX.Core
if (pkm.InhabitedGeneration(5) && specialTutors)
moves.AddRange(GetTutors(PersonalTable.B2W2.GetFormeEntry(species, form), Tutors_B2W2));
}
private static void AddMovesTutor6(List<int> moves, int species, int form, PKM pkm, bool specialTutors)
{
var pi = PersonalTable.AO[species];
@ -196,6 +235,7 @@ namespace PKHeX.Core
if (specialTutors && pkm.HasVisitedORAS())
moves.AddRange(GetTutors(PersonalTable.AO.GetFormeEntry(species, form), Tutors_AO));
}
private static void AddMovesTutor7(List<int> moves, int species, int form, PKM pkm, bool specialTutors)
{
var pi = PersonalTable.USUM.GetFormeEntry(species, form);
@ -207,9 +247,13 @@ namespace PKHeX.Core
private static IEnumerable<int> GetTutors(PersonalInfo pi, params int[][] tutors)
{
for (int i = 0; i < tutors.Length; i++)
for (int b = 0; b < tutors[i].Length; b++)
if (pi.SpecialTutors[i][b])
yield return tutors[i][b];
{
for (int b = 0; b < tutors[i].Length; b++)
{
if (pi.SpecialTutors[i][b])
yield return tutors[i][b];
}
}
}
internal static void AddSpecialTutorMoves(List<int> r, PKM pkm, int Generation, int species)

View file

@ -53,6 +53,7 @@ namespace PKHeX.Core
return new PIDIV {Type=PIDType.None, NoSeed=true}; // no match
}
private static bool GetModifiedPIDMatch(PKM pk, uint pid, uint[] IVs, out PIDIV pidiv)
{
if (pk.IsShiny)
@ -70,11 +71,12 @@ namespace PKHeX.Core
return GetPokewalkerMatch(pk, pid, out pidiv);
}
private static bool GetModified8BitMatch(PKM pk, uint pid, out PIDIV pidiv)
{
return pk.Gen4
? pid <= 0xFF && GetCuteCharmMatch(pk, pid, out pidiv) || GetG5MGShinyMatch(pk, pid, out pidiv)
: GetG5MGShinyMatch(pk, pid, out pidiv) || pid <= 0xFF && GetCuteCharmMatch(pk, pid, out pidiv);
? (pid <= 0xFF && GetCuteCharmMatch(pk, pid, out pidiv)) || GetG5MGShinyMatch(pk, pid, out pidiv)
: GetG5MGShinyMatch(pk, pid, out pidiv) || (pid <= 0xFF && GetCuteCharmMatch(pk, pid, out pidiv));
}
private static bool GetLCRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv)
@ -126,6 +128,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetLCRNGUnownMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv)
{
// this is an exact copy of LCRNG 1,2,4 matching, except the PID has its halves switched (BACD, BADE, BACE)
@ -176,6 +179,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetLCRNGRoamerMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv)
{
if (IVs.Skip(2).Any(iv => iv != 0) || IVs[1] > 7)
@ -194,6 +198,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetXDRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv)
{
var xdc = GetSeedsFromPIDEuclid(RNG.XDRNG, top, bot);
@ -216,6 +221,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetChannelMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv, PKM pk)
{
var ver = pk.Version;
@ -250,6 +256,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetMG4Match(uint pid, uint[] IVs, out PIDIV pidiv)
{
uint mg4Rev = RNG.ARNG.Prev(pid);
@ -267,6 +274,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetG5MGShinyMatch(PKM pk, uint pid, out PIDIV pidiv)
{
var low = pid & 0xFFFF;
@ -283,6 +291,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetCuteCharmMatch(PKM pk, uint pid, out PIDIV pidiv)
{
if (pid > 0xFF)
@ -297,7 +306,7 @@ namespace PKHeX.Core
var gr = getRatio();
if (254 <= gr) // no modification for PID
break;
var rate = 25*(gr/25 + 1); // buffered
var rate = 25*((gr / 25) + 1); // buffered
var nature = pid % 25;
if (nature + rate != pid)
break;
@ -315,6 +324,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetChainShinyMatch(PKM pk, uint pid, uint[] IVs, out PIDIV pidiv)
{
// 13 shiny bits
@ -347,7 +357,7 @@ namespace PKHeX.Core
if ((lower >> 16 & 7) != (pid & 7))
continue;
var upid = ((pid & 0xFFFF) ^ pk.TID ^ pk.SID) & 0xFFF8 | (upper >> 16) & 0x7;
var upid = (((pid & 0xFFFF) ^ pk.TID ^ pk.SID) & 0xFFF8) | ((upper >> 16) & 0x7);
if (upid != pid >> 16)
continue;
@ -357,6 +367,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetBACDMatch(PKM pk, uint pid, uint[] IVs, out PIDIV pidiv)
{
var bot = GetIVChunk(IVs, 0);
@ -369,11 +380,11 @@ namespace PKHeX.Core
var A = RNG.LCRNG.Prev(B);
var low = B >> 16;
var PID = A & 0xFFFF0000 | low;
var PID = (A & 0xFFFF0000) | low;
if (PID != pid)
{
uint idxor = (uint)(pk.TID ^ pk.SID);
bool isShiny = (idxor ^ PID >> 16 ^ PID & 0xFFFF) < 8;
bool isShiny = (idxor ^ PID >> 16 ^ (PID & 0xFFFF)) < 8;
if (!isShiny)
{
if (!pk.IsShiny) // check for nyx antishiny
@ -412,6 +423,7 @@ namespace PKHeX.Core
}
return GetNonMatch(out pidiv);
}
private static bool GetPokewalkerMatch(PKM pk, uint oldpid, out PIDIV pidiv)
{
// check surface compatibility
@ -429,9 +441,10 @@ namespace PKHeX.Core
pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.Pokewalker};
return true;
}
private static bool GetColoStarterMatch(PKM pk, uint top, uint bot, uint[] IVs, out PIDIV pidiv)
{
if (pk.Version != 15 || pk.Species != 196 && pk.Species != 197)
if (pk.Version != 15 || (pk.Species != 196 && pk.Species != 197))
return GetNonMatch(out pidiv);
var iv1 = GetIVChunk(IVs, 0);
@ -460,6 +473,7 @@ namespace PKHeX.Core
pidiv = null;
return false;
}
/// <summary>
/// Checks if the PID is a <see cref="PIDType.BACD_U_S"></see> match.
/// </summary>
@ -480,7 +494,7 @@ namespace PKHeX.Core
// PID = PIDH << 16 | (SID ^ TID ^ PIDH)
var X = RNG.LCRNG.Prev(A); // unroll once as there's 3 calls instead of 2
uint PID = X & 0xFFFF0000 | idxor ^ X >> 16;
uint PID = (X & 0xFFFF0000) | (idxor ^ X >> 16);
PID &= 0xFFFFFFF8;
PID |= low & 0x7; // lowest 3 bits
@ -490,6 +504,7 @@ namespace PKHeX.Core
type = PIDType.BACD_U_S;
return true;
}
/// <summary>
/// Checks if the PID is a <see cref="PIDType.BACD_U_AX"></see> match.
/// </summary>
@ -519,7 +534,7 @@ namespace PKHeX.Core
return true;
}
private static PIDIV AnalyzeGB(PKM pk)
private static PIDIV AnalyzeGB(PKM _)
{
return null;
}
@ -532,6 +547,7 @@ namespace PKHeX.Core
uint first = b << 16;
return method.RecoverLower16Bits(first, second);
}
private static IEnumerable<uint> GetSeedsFromIVs(RNG method, uint a, uint b)
{
Debug.Assert(a >> 15 == 0);
@ -546,6 +562,7 @@ namespace PKHeX.Core
yield return z ^ 0x80000000; // sister bitflip
}
}
public static IEnumerable<uint> GetSeedsFromIVsSkip(RNG method, uint rand1, uint rand3)
{
Debug.Assert(rand1 >> 15 == 0);
@ -560,10 +577,12 @@ namespace PKHeX.Core
yield return z ^ 0x80000000; // sister bitflip
}
}
public static IEnumerable<uint> GetSeedsFromPIDEuclid(RNG method, uint rand1, uint rand2)
{
return method.RecoverLower16BitsEuclid16(rand1 << 16, rand2 << 16);
}
public static IEnumerable<uint> GetSeedsFromIVsEuclid(RNG method, uint rand1, uint rand2)
{
return method.RecoverLower16BitsEuclid15(rand1 << 16, rand2 << 16);
@ -587,6 +606,7 @@ namespace PKHeX.Core
r2 >> 10 & 31,
};
}
internal static int[] GetIVsInt32(uint r1, uint r2)
{
return new[]
@ -599,6 +619,7 @@ namespace PKHeX.Core
(int)r2 >> 10 & 31,
};
}
private static uint GetIVChunk(uint[] IVs, int start)
{
uint val = 0;
@ -624,6 +645,7 @@ namespace PKHeX.Core
yield return new PIDIV {OriginSeed = s, RNG = RNG.XDRNG, Type = PIDType.PokeSpot};
}
}
public static bool IsPokeSpotActivation(int slot, uint seed, out uint s)
{
s = seed;
@ -648,6 +670,7 @@ namespace PKHeX.Core
}
return true;
}
private static bool IsPokeSpotSlotValid(int slot, uint esv)
{
switch (slot)
@ -661,6 +684,7 @@ namespace PKHeX.Core
}
return false;
}
public static bool IsCompatible3(this PIDType val, IEncounterable encounter, PKM pkm)
{
switch (encounter)
@ -692,6 +716,7 @@ namespace PKHeX.Core
return val == PIDType.None;
}
}
private static bool IsRoamerPIDIV(this PIDType val, PKM pkm)
{
// Roamer PIDIV is always Method 1.
@ -703,12 +728,13 @@ namespace PKHeX.Core
var IVs = pkm.IVs;
return !(IVs.Skip(2).Any(iv => iv != 0) || IVs[1] > 7);
}
public static bool IsCompatible4(this PIDType val, IEncounterable encounter, PKM pkm)
{
switch (encounter)
{
case EncounterStatic s:
if (s == Encounters4.SpikyEaredPichu || s.Location == 233 && s.Gift) // Pokewalker
if (s == Encounters4.SpikyEaredPichu || (s.Location == 233 && s.Gift)) // Pokewalker
return val == PIDType.Pokewalker;
if (s.Shiny == Shiny.Always)
return val == PIDType.ChainShiny;
@ -732,6 +758,7 @@ namespace PKHeX.Core
return val == PIDType.None;
}
}
private static bool IsG4ManaphyPIDValid(PIDType val, PKM pkm)
{
if (pkm.IsEgg)
@ -753,15 +780,20 @@ namespace PKHeX.Core
return (pkm.TID ^ pkm.SID ^ (shinyPID & 0xFFFF) ^ (shinyPID >> 16)) < 8; // shiny proc
}
}
private static bool IsCuteCharm4Valid(IEncounterable encounter, PKM pkm)
{
if (pkm.Species == 183 || pkm.Species == 184)
{
return !IsCuteCharmAzurillMale(pkm.PID) // recognized as not Azurill
|| encounter.Species == 298; // encounter must be male Azurill
|| encounter.Species == 298; // encounter must be male Azurill
}
return true;
}
private static bool IsCuteCharmAzurillMale(uint pid) => pid >= 0xC8 && pid <= 0xE0;
private static void GetCuteCharmGenderSpecies(PKM pk, uint pid, out int genderValue, out int species)
{
// There are some edge cases when the gender ratio changes across evolutions.

View file

@ -9,7 +9,7 @@ namespace PKHeX.Core
var rng = RNG.LCRNG;
var A = rng.Next(seed);
var B = rng.Next(A);
var pid = B & 0xFFFF0000 | A >> 16;
var pid = (B & 0xFFFF0000) | A >> 16;
if (type == PIDType.Method_1_Unown || type == PIDType.Method_2_Unown || type == PIDType.Method_4_Unown)
pk.PID = (pid >> 16) | (pid << 16); // swap halves
else
@ -34,6 +34,7 @@ namespace PKHeX.Core
}
pk.IVs = IVs;
}
private static void SetValuesFromSeedBACD(PKM pk, PIDType type, uint seed)
{
var rng = RNG.LCRNG;
@ -46,7 +47,7 @@ namespace PKHeX.Core
if (shiny)
{
uint PID = X & 0xFFFF0000 | (uint)pk.SID ^ (uint)pk.TID ^ X >> 16;
uint PID = (X & 0xFFFF0000) | ((uint)pk.SID ^ (uint)pk.TID ^ X >> 16);
PID &= 0xFFFFFFF8;
PID |= B >> 16 & 0x7; // lowest 3 bits
@ -55,10 +56,12 @@ namespace PKHeX.Core
else if (type == PIDType.BACD_R_AX || type == PIDType.BACD_U_AX)
{
uint low = B >> 16;
pk.PID = A & 0xFFFF0000 ^ (((uint)pk.TID ^ (uint)pk.SID ^ low) << 16) | low;
pk.PID = ((A & 0xFFFF0000) ^ (((uint)pk.TID ^ (uint)pk.SID ^ low) << 16)) | low;
}
else
pk.PID = A & 0xFFFF0000 | B >> 16;
{
pk.PID = (A & 0xFFFF0000) | B >> 16;
}
pk.IVs = MethodFinder.GetIVsInt32(C >> 16, D >> 16);
@ -66,6 +69,7 @@ namespace PKHeX.Core
while (antishiny && pk.IsShiny)
pk.PID = unchecked(pk.PID + 1);
}
private static void SetValuesFromSeedXDRNG(PKM pk, uint seed)
{
var rng = RNG.XDRNG;
@ -89,9 +93,10 @@ namespace PKHeX.Core
var D = rng.Next(C); // PID
var E = rng.Next(D); // PID
pk.PID = D & 0xFFFF0000 | E >> 16;
pk.PID = (D & 0xFFFF0000) | E >> 16;
pk.IVs = MethodFinder.GetIVsInt32(A >> 16, B >> 16);
}
private static void SetValuesFromSeedChannel(PKM pk, uint seed)
{
var rng = RNG.XDRNG;
@ -123,6 +128,7 @@ namespace PKHeX.Core
var method = GetGeneratorMethod(type);
method(pk, seed);
}
private static Action<PKM, uint> GetGeneratorMethod(PIDType t)
{
switch (t)
@ -167,7 +173,7 @@ namespace PKHeX.Core
case PIDType.G4MGAntiShiny:
break;
}
return (pk, _) => { };
return (_, __) => { };
}
public static void SetRandomChainShinyPID(PKM pk, uint seed)
@ -182,7 +188,7 @@ namespace PKHeX.Core
for (int i = 0; i < 13; i++)
lower |= (Next() & 1) << (3 + i);
upper = (uint)(lower ^ pk.TID ^ pk.SID) & 0xFFF8 | upper & 0x7;
upper = ((uint)(lower ^ pk.TID ^ pk.SID) & 0xFFF8) | (upper & 0x7);
pk.PID = upper << 16 | lower;
pk.IVs = MethodFinder.GetIVsInt32(Next(), Next());
}
@ -199,7 +205,7 @@ namespace PKHeX.Core
var D = rng.Next(seed); // PID
var E = rng.Next(D); // PID
pk.PID = D & 0xFFFF0000 | E >> 16;
pk.PID = (D & 0xFFFF0000) | E >> 16;
if (!IsValidCriteria4(pk, nature, ability, gender))
continue;
@ -222,7 +228,7 @@ namespace PKHeX.Core
nature = 0;
uint pid = (uint)((TID ^ SID) >> 8 ^ 0xFF) << 24; // the most significant byte of the PID is chosen so the Pokémon can never be shiny.
// Ensure nature is set to required nature without affecting shininess
pid += nature - pid % 25;
pid += nature - (pid % 25);
// Ensure Gender is set to required gender without affecting other properties
// If Gender is modified, modify the ability if appropriate
@ -237,13 +243,13 @@ namespace PKHeX.Core
if (currentGender == 0) // Male
{
pid += (uint)(((gr - (pid & 0xFF)) / 25 + 1) * 25);
pid += (uint)((((gr - (pid & 0xFF)) / 25) + 1) * 25);
if ((nature & 1) != (pid & 1))
pid += 25;
}
else
{
pid -= (uint)((((pid & 0xFF) - gr) / 25 + 1) * 25);
pid -= (uint)(((((pid & 0xFF) - gr) / 25) + 1) * 25);
if ((nature & 1) != (pid & 1))
pid -= 25;
}
@ -338,6 +344,7 @@ namespace PKHeX.Core
return PIDType.Method_1;
}
private static void SetRandomWildPID5(PKM pk, int nature, int ability, int gender, PIDType specific = PIDType.None)
{
var tidbit = (pk.TID ^ pk.SID) & 1;

View file

@ -8,21 +8,27 @@
/// <summary> Method 1 Variants (H1/J/K) </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
Method_1,
/// <summary> Method H2 </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
Method_2,
/// <summary> Method H4 </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
Method_4,
/// <summary> Method H1_Unown (FRLG) </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
Method_1_Unown,
/// <summary> Method H2_Unown (FRLG) </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
Method_2_Unown,
/// <summary> Method H4_Unown (FRLG) </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
Method_4_Unown,
/// <summary> Method 1 Roamer (Gen3) </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
Method_1_Roamer,
@ -32,36 +38,43 @@
/// </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
BACD_R,
/// <summary>
/// Event Reversed Order PID without Origin Seed restrictions
/// </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
BACD_U,
/// <summary>
/// Event Reversed Order PID restricted to 16bit Origin Seed, antishiny.
/// </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
BACD_R_A,
/// <summary>
/// Event Reversed Order PID without Origin Seed restrictions, antishiny.
/// </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
BACD_U_A,
/// <summary>
/// Event Reversed Order PID restricted to 16bit Origin Seed, shiny
/// </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
BACD_R_S,
/// <summary>
/// Event Reversed Order PID without Origin Seed restrictions, shiny
/// </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
BACD_U_S,
/// <summary>
/// Event Reversed Order PID restricted to 16bit Origin Seed, antishiny (nyx)
/// </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
BACD_R_AX,
/// <summary>
/// Event Reversed Order PID without Origin Seed restrictions, antishiny (nyx)
/// </summary>
@ -73,6 +86,7 @@
/// </summary>
/// <remarks><see cref="RNG.LCRNG"/></remarks>
CuteCharm,
/// <summary>
/// Generation 4 Chained Shiny
/// </summary>
@ -85,6 +99,7 @@
/// </summary>
/// <remarks><see cref="RNG.XDRNG"/></remarks>
CXD,
/// <summary>
/// Standard <see cref="GameVersion.CXD"/> PIDIV which is immediately after the RNG calls that create the TID and SID.
/// </summary>

View file

@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
namespace PKHeX.Core
{
public class RNG
public sealed class RNG
{
public static readonly RNG LCRNG = new RNG(0x41C64E6D, 0x00006073, 0xEEB9EB65, 0x0A3561A1);
public static readonly RNG XDRNG = new RNG(0x000343FD, 0x00269EC3, 0xB9B33155, 0xA170F641);
@ -59,7 +59,7 @@ namespace PKHeX.Core
// with the current calc setup, the search loop's calculated value may be -1 (loop does subtraction)
// since LCGs are linear (hence the name), there's no values in adjacent cells. (no collisions)
// if we mark the prior adjacent cell, we eliminate the need to check flags twice on each loop.
uint right = mult * i + add;
uint right = (mult * i) + add;
ushort val = (ushort) (right >> 16);
f[val] = true; v[val] = (byte)i;
@ -69,9 +69,10 @@ namespace PKHeX.Core
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint Next(uint seed) => seed * Mult + Add;
public uint Next(uint seed) => (seed * Mult) + Add;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint Prev(uint seed) => seed * rMult + rAdd;
public uint Prev(uint seed) => (seed * rMult) + rAdd;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint Advance(uint seed, int frames)
@ -80,6 +81,7 @@ namespace PKHeX.Core
seed = Next(seed);
return seed;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint Reverse(uint seed, int frames)
{
@ -104,6 +106,7 @@ namespace PKHeX.Core
}
return ivs;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal int[] GetSequentialIVsInt32(uint seed)
{
@ -130,7 +133,7 @@ namespace PKHeX.Core
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal IEnumerable<uint> RecoverLower16Bits(uint first, uint second)
{
uint k1 = second - first * Mult;
uint k1 = second - (first * Mult);
for (uint i = 0, k3 = k1; i <= 255; ++i, k3 -= k2)
{
ushort val = (ushort)(k3 >> 16);
@ -138,6 +141,7 @@ namespace PKHeX.Core
yield return Prev(first | i << 8 | low8[val]);
}
}
/// <summary>
/// Gets the origin seeds for two 16 bit rand() calls (ignoring a rand() in between) using a meet-in-the-middle approach.
/// </summary>
@ -152,7 +156,7 @@ namespace PKHeX.Core
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal IEnumerable<uint> RecoverLower16BitsGap(uint first, uint third)
{
uint k1 = third - first * k0g;
uint k1 = third - (first * k0g);
for (uint i = 0, k3 = k1; i <= 255; ++i, k3 -= k2s)
{
ushort val = (ushort)(k3 >> 16);
@ -160,6 +164,7 @@ namespace PKHeX.Core
yield return Prev(first | i << 8 | g_low8[val]);
}
}
/// <summary>
/// Gets the origin seeds for two successive 16 bit rand() calls using a Euclidean division approach.
/// </summary>
@ -178,6 +183,7 @@ namespace PKHeX.Core
const long inc = 0x100000000; // 1 << 32;
return GetPossibleSeedsEuclid(first, second, bitshift, inc);
}
/// <summary>
/// Gets the origin seeds for two successive 15 bit rand() calls using a Euclidean division approach.
/// </summary>
@ -201,13 +207,13 @@ namespace PKHeX.Core
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private IEnumerable<uint> GetPossibleSeedsEuclid(uint first, uint second, int bitshift, long inc)
{
long t = second - Mult * first - t0;
long t = second - (Mult * first) - t0;
long kmax = (((t1 - t) >> bitshift) << bitshift) + t;
for (long k = t; k <= kmax; k += inc)
{
// compute modulo in steps for reuse in yielded value (x % Mult)
long fix = k / Mult;
long remainder = k - Mult * fix;
long remainder = k - (Mult * fix);
if (remainder >> 16 == 0)
yield return Prev(first | (uint) fix);
}

View file

@ -35,12 +35,14 @@
Source = m;
Generation = g;
}
internal CheckMoveResult(MoveSource m, int g, Severity s, string c, CheckIdentifier i)
: base(s, c, i)
{
Source = m;
Generation = g;
}
internal CheckMoveResult(CheckMoveResult Org, Severity s, string c, CheckIdentifier i)
: base(s, c, i)
{

View file

@ -11,7 +11,8 @@
public string Rating => Judgement.Description();
internal readonly CheckIdentifier Identifier;
internal CheckResult(CheckIdentifier i) { Identifier = i; }
internal CheckResult(CheckIdentifier i) => Identifier = i;
internal CheckResult(Severity s, string c, CheckIdentifier i)
{
Judgement = s;

View file

@ -13,29 +13,34 @@ namespace PKHeX.Core
public bool GetHasEggMove(int move) => Moves.Contains(move);
}
public class EggMoves2 : EggMoves
public sealed class EggMoves2 : EggMoves
{
private EggMoves2(byte[] data)
{
Count = data.Length;
Moves = data.Select(i => (int) i).ToArray();
}
public static EggMoves[] GetArray(byte[] data, int count)
{
int[] ptrs = new int[count+1];
int baseOffset = (data[1] << 8 | data[0]) - count * 2;
int baseOffset = (data[1] << 8 | data[0]) - (count * 2);
for (int i = 1; i < ptrs.Length; i++)
ptrs[i] = (data[(i - 1)*2 + 1] << 8 | data[(i - 1)*2]) - baseOffset;
{
var ofs = (i - 1) * 2;
ptrs[i] = (data[ofs + 1] << 8 | data[ofs]) - baseOffset;
}
EggMoves[] entries = new EggMoves[count + 1];
entries[0] = new EggMoves2(new byte[0]);
entries[0] = new EggMoves2(Array.Empty<byte>());
for (int i = 1; i < entries.Length; i++)
entries[i] = new EggMoves2(data.Skip(ptrs[i]).TakeWhile(b => b != 0xFF).ToArray());
return entries;
}
}
public class EggMoves6 : EggMoves
public sealed class EggMoves6 : EggMoves
{
private EggMoves6(byte[] data)
{
@ -48,6 +53,7 @@ namespace PKHeX.Core
Moves[i] = br.ReadUInt16();
}
}
public static EggMoves[] GetArray(byte[][] entries)
{
EggMoves[] data = new EggMoves[entries.Length];
@ -56,7 +62,8 @@ namespace PKHeX.Core
return data;
}
}
public class EggMoves7 : EggMoves
public sealed class EggMoves7 : EggMoves
{
private EggMoves7(byte[] data)
{
@ -71,6 +78,7 @@ namespace PKHeX.Core
Moves[i] = br.ReadUInt16();
}
}
public static EggMoves[] GetArray(byte[][] entries)
{
EggMoves[] data = new EggMoves[entries.Length];

View file

@ -20,6 +20,7 @@
{
return encounter.LevelMin <= lvl && lvl <= encounter.LevelMax;
}
public static bool IsWithinRange(this IEncounterable encounter, PKM pkm)
{
if (!pkm.HasOriginalMetLocation)
@ -30,6 +31,7 @@
return pkm.CurrentLevel == g.Level;
return pkm.CurrentLevel == pkm.Met_Level;
}
internal static string GetEncounterTypeName(this IEncounterable Encounter) => Encounter?.Name ?? "Unknown";
}
}

View file

@ -16,6 +16,7 @@
? encounter.Location
: encounter.EggLocation;
}
internal static string GetEncounterLocation(this ILocation Encounter, int gen, int version = -1)
{
int loc = Encounter.GetLocation();

View file

@ -10,6 +10,7 @@ namespace PKHeX.Core
public static partial class Extensions
{
public static bool CanBeReceivedBy(this IVersion ver, GameVersion game) => ver.Version.Contains(game);
public static GameVersion GetCompatibleVersion(this IVersion ver, GameVersion prefer)
{
if (ver.CanBeReceivedBy(prefer) || ver.Version <= GameVersion.Unknown)
@ -20,9 +21,12 @@ namespace PKHeX.Core
internal static void SetVersion(this IEnumerable<IVersion> arr, GameVersion game)
{
foreach (var z in arr)
{
if (z.Version <= 0)
z.Version = game;
}
}
internal static void SetVersion(this IEnumerable<EncounterArea> arr, GameVersion game)
{
foreach (var area in arr)

View file

@ -31,6 +31,7 @@
return GetMoveTypeFromG12(type);
return type;
}
private static MoveType GetMoveTypeFromG12(this MoveType type)
{
if (type <= MoveType.Rock)

View file

@ -5,10 +5,30 @@
/// </summary>
public enum Nature : byte
{
Hardy, Lonely, Brave, Adamant, Naughty, Bold,
Docile, Relaxed, Impish, Lax, Timid, Hasty,
Serious, Jolly, Naive, Modest, Mild, Quiet,
Bashful, Rash, Calm, Gentle, Sassy, Careful,
Hardy,
Lonely,
Brave,
Adamant,
Naughty,
Bold,
Docile,
Relaxed,
Impish,
Lax,
Timid,
Hasty,
Serious,
Jolly,
Naive,
Modest,
Mild,
Quiet,
Bashful,
Rash,
Calm,
Gentle,
Sassy,
Careful,
Quirky,
Random = 25,

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace PKHeX.Core
@ -13,10 +14,9 @@ namespace PKHeX.Core
/// </summary>
/// <param name="len">Length, in bytes, of the data of which to determine validity.</param>
/// <returns>A boolean indicating whether or not the given length is valid for a mystery gift.</returns>
public static bool IsMysteryGift(long len)
{
return new[] { WC6.SizeFull, WC6.Size, PGF.Size, PGT.Size, PCD.Size }.Contains((int)len);
}
public static bool IsMysteryGift(long len) => MGSizes.Contains((int)len);
private static readonly HashSet<int> MGSizes = new HashSet<int>(new[] { WC6.SizeFull, WC6.Size, PGF.Size, PGT.Size, PCD.Size });
/// <summary>
/// Converts the given data to a <see cref="MysteryGift"/>.
@ -133,8 +133,8 @@ namespace PKHeX.Core
}
// Search Properties
public virtual int[] Moves { get => new int[4]; set { } }
public virtual int[] RelearnMoves { get => new int[4]; set { } }
public virtual int[] Moves { get => Array.Empty<int>(); set { } }
public virtual int[] RelearnMoves { get => Array.Empty<int>(); set { } }
public virtual int[] IVs { get => null; set { } }
public virtual bool IsShiny => false;
public virtual bool IsEgg { get => false; set { } }

View file

@ -305,7 +305,7 @@ namespace PKHeX.Core
}
}
protected override bool[] MysteryGiftReceivedFlags { get => null; set { } }
protected override MysteryGift[] MysteryGiftCards { get => new MysteryGift[0]; set { } }
protected override MysteryGift[] MysteryGiftCards { get => Array.Empty<MysteryGift>(); set { } }
// Trainer Info
public override string OT

View file

@ -23,13 +23,14 @@ namespace PKHeX.Core
public bool Exportable { get; protected set; }
public abstract SaveFile Clone();
public abstract string Filter { get; }
public byte[] Footer { protected get; set; } = new byte[0]; // .dsv
public byte[] Header { protected get; set; } = new byte[0]; // .gci
public byte[] Footer { protected get; set; } = Array.Empty<byte>(); // .dsv
public byte[] Header { protected get; set; } = Array.Empty<byte>(); // .gci
public bool Japanese { get; protected set; }
public virtual string PlayTimeString => $"{PlayedHours}ː{PlayedMinutes:00}ː{PlayedSeconds:00}"; // not :
public bool IndeterminateGame => Version == GameVersion.Unknown;
public virtual bool IndeterminateSubVersion => false;
public abstract string Extension { get; }
public virtual string[] PKMExtensions => PKM.Extensions.Where(f =>
{
int gen = f.Last() - 0x30;
@ -52,6 +53,7 @@ namespace PKHeX.Core
{
return Write(DSV);
}
protected virtual byte[] Write(bool DSV)
{
SetChecksums();
@ -61,6 +63,7 @@ namespace PKHeX.Core
return Header.Concat(Data).ToArray();
return Data;
}
public virtual string MiscSaveChecks() => string.Empty;
public virtual string MiscSaveInfo() => string.Empty;
public virtual GameVersion Version { get; protected set; }
@ -117,7 +120,7 @@ namespace PKHeX.Core
public virtual bool HasGeolocation => false;
public bool HasPokeBlock => ORAS && !ORASDEMO;
public bool HasEvents => EventFlags != null;
public bool HasLink => ORAS && !ORASDEMO || XY;
public bool HasLink => (ORAS && !ORASDEMO) || XY;
// Counts
protected virtual int GiftCountMax { get; } = int.MinValue;
@ -175,6 +178,7 @@ namespace PKHeX.Core
SetBoxData(value, b, b * BoxSlotCount);
}
}
private void SetBoxData(IList<PKM> value, int box, int index = 0)
{
int ofs = GetBoxOffset(box);
@ -184,12 +188,14 @@ namespace PKHeX.Core
SetStoredSlot(value[index + slot], ofs);
}
}
public PKM[] GetBoxData(int box)
{
var data = new PKM[BoxSlotCount];
AddBoxData(data, box, 0);
return data;
}
private void AddBoxData(IList<PKM> data, int box, int index)
{
int ofs = GetBoxOffset(box);
@ -232,6 +238,7 @@ namespace PKHeX.Core
SetPartySlot(newParty[i], GetPartyOffset(i));
}
}
public IList<PKM> BattleBoxData
{
get
@ -242,7 +249,7 @@ namespace PKHeX.Core
PKM[] data = new PKM[6];
for (int i = 0; i < data.Length; i++)
{
data[i] = GetStoredSlot(BattleBox + SIZE_STORED * i);
data[i] = GetStoredSlot(BattleBox + (SIZE_STORED * i));
data[i].Locked = BattleBoxLocked;
if (data[i].Species != 0)
continue;
@ -276,6 +283,7 @@ namespace PKHeX.Core
SetEventFlag(i, value[i]);
}
}
/// <summary> All Event Constant values for the savegame </summary>
public ushort[] EventConsts
{
@ -286,7 +294,7 @@ namespace PKHeX.Core
ushort[] Constants = new ushort[EventConstMax];
for (int i = 0; i < Constants.Length; i++)
Constants[i] = BitConverter.ToUInt16(Data, EventConst + i * 2);
Constants[i] = BitConverter.ToUInt16(Data, EventConst + (i * 2));
return Constants;
}
set
@ -297,9 +305,10 @@ namespace PKHeX.Core
return;
for (int i = 0; i < value.Length; i++)
BitConverter.GetBytes(value[i]).CopyTo(Data, EventConst + i * 2);
BitConverter.GetBytes(value[i]).CopyTo(Data, EventConst + (i * 2));
}
}
/// <summary>
/// Gets the <see cref="bool"/> status of a desired Event Flag
/// </summary>
@ -324,6 +333,7 @@ namespace PKHeX.Core
throw new ArgumentException($"Event Flag to set ({flagNumber}) is greater than max ({EventFlagMax}).");
SetFlag(EventFlag + (flagNumber >> 3), flagNumber & 7, value);
}
/// <summary>
/// Gets the <see cref="bool"/> status of the Flag at the specified offset and index.
/// </summary>
@ -335,6 +345,7 @@ namespace PKHeX.Core
bitIndex &= 7; // ensure bit access is 0-7
return (Data[offset] >> bitIndex & 1) != 0;
}
/// <summary>
/// Sets the <see cref="bool"/> status of the Flag at the specified offset and index.
/// </summary>
@ -365,6 +376,7 @@ namespace PKHeX.Core
// Mystery Gift
protected virtual bool[] MysteryGiftReceivedFlags { get => null; set { } }
protected virtual MysteryGift[] MysteryGiftCards { get => null; set { } }
public virtual MysteryGiftAlbum GiftAlbum
{
get => new MysteryGiftAlbum
@ -405,6 +417,7 @@ namespace PKHeX.Core
public int SlotCount => BoxCount * BoxSlotCount;
public virtual int PartyCount { get; protected set; }
public virtual int MultiplayerSpriteID { get => 0; set { } }
public bool IsPartyAllEggs(params int[] except)
{
if (!HasParty)
@ -446,6 +459,7 @@ namespace PKHeX.Core
public virtual int CurrentBox { get => 0; set { } }
protected int[] LockedSlots = Array.Empty<int>();
protected int[] TeamSlots = Array.Empty<int>();
public bool MoveBox(int box, int insertBeforeBox)
{
if (box == insertBeforeBox) // no movement required
@ -484,6 +498,7 @@ namespace PKHeX.Core
}
return true;
}
public bool SwapBox(int box1, int box2)
{
if (box1 == box2) // no movement required
@ -514,10 +529,11 @@ namespace PKHeX.Core
SetBoxWallpaper(box2, b1w);
return true;
}
private bool IsBoxAbleToMove(int box)
{
int min = BoxSlotCount * box;
int max = BoxSlotCount * box + BoxSlotCount;
int max = min + BoxSlotCount;
if (LockedSlots.Any(slot => min <= slot && slot < max)) // locked slot within box
return false;
if (TeamSlots.Any(slot => min <= slot && slot < max)) // team slot within box
@ -526,6 +542,7 @@ namespace PKHeX.Core
}
protected virtual int GetBoxWallpaperOffset(int box) => -1;
public virtual int GetBoxWallpaper(int box)
{
int offset = GetBoxWallpaperOffset(box);
@ -533,6 +550,7 @@ namespace PKHeX.Core
return box;
return Data[offset];
}
public virtual void SetBoxWallpaper(int box, int value)
{
int offset = GetBoxWallpaperOffset(box);
@ -551,12 +569,15 @@ namespace PKHeX.Core
public PKM GetPartySlotAtIndex(int index) => GetPartySlot(GetPartyOffset(index));
public PKM GetBoxSlotAtIndex(int box, int slot) => GetStoredSlot(GetBoxSlotOffset(box, slot));
public PKM GetBoxSlotAtIndex(int index)
{
GetBoxSlotFromIndex(index, out int box, out int slot);
return GetBoxSlotAtIndex(box, slot);
}
public int GetBoxSlotOffset(int box, int slot) => GetBoxOffset(box) + slot * SIZE_STORED;
public int GetBoxSlotOffset(int box, int slot) => GetBoxOffset(box) + (slot * SIZE_STORED);
public int GetBoxSlotOffset(int index)
{
GetBoxSlotFromIndex(index, out int box, out int slot);
@ -568,10 +589,12 @@ namespace PKHeX.Core
public void SetPartySlotAtIndex(PKM pkm, int index, bool? trade = null, bool? dex = null) => SetPartySlot(pkm, GetPartyOffset(index), trade, dex);
public virtual PKM GetPartySlot(int offset) => GetPKM(DecryptPKM(GetData(offset, SIZE_PARTY)));
public virtual PKM GetStoredSlot(int offset)
{
return GetPKM(DecryptPKM(GetData(offset, SIZE_STORED)));
}
public void SetPartySlot(PKM pkm, int offset, bool? trade = null, bool? dex = null)
{
if (pkm == null) return;
@ -594,18 +617,24 @@ namespace PKHeX.Core
PartyCount = i + 1;
}
else if (PartyCount > i)
{
PartyCount = i;
}
SetData(pkm.EncryptedPartyData, offset);
Edited = true;
}
private int GetPartyIndex(int offset)
{
for (int i = 0; i < 6; i++)
{
if (GetPartyOffset(i) == offset)
return i;
}
return -1;
}
public virtual void SetStoredSlot(PKM pkm, int offset, bool? trade = null, bool? dex = null)
{
if (pkm == null) return;
@ -619,6 +648,7 @@ namespace PKHeX.Core
SetData(pkm.EncryptedBoxData, offset);
Edited = true;
}
public void DeletePartySlot(int slot)
{
if (PartyCount <= slot) // beyond party range (or empty data already present)
@ -633,11 +663,14 @@ namespace PKHeX.Core
SetStoredSlot(BlankPKM, GetPartyOffset(5), false, false);
PartyCount--;
}
public virtual bool IsSlotLocked(int box, int slot) => false;
public bool IsAnySlotLockedInBox(int BoxStart, int BoxEnd)
{
return LockedSlots.Any(slot => BoxStart*BoxSlotCount <= slot && slot < (BoxEnd + 1)*BoxSlotCount);
}
public virtual bool IsSlotInBattleTeam(int box, int slot) => false;
public void SortBoxes(int BoxStart = 0, int BoxEnd = -1, Func<IEnumerable<PKM>, IEnumerable<PKM>> sortMethod = null, bool reverse = false)
@ -655,6 +688,7 @@ namespace PKHeX.Core
Sorted.CopyTo(BD, start);
BoxData = BD;
}
public void ClearBoxes(int BoxStart = 0, int BoxEnd = -1, Func<PKM, bool> deleteCriteria = null)
{
if (BoxEnd < 0)
@ -671,7 +705,7 @@ namespace PKHeX.Core
{
if (IsSlotLocked(i, p))
continue;
var ofs = offset + SIZE_STORED * p;
var ofs = offset + (SIZE_STORED * p);
if (deleteCriteria != null)
{
var pk = GetStoredSlot(ofs);
@ -683,24 +717,29 @@ namespace PKHeX.Core
}
}
}
public void ModifyBoxes(Action<PKM> action, int BoxStart = 0, int BoxEnd = -1)
{
if (BoxEnd < 0)
BoxEnd = BoxCount - 1;
var BD = BoxData;
for (int b = BoxStart; b <= BoxEnd; b++)
for (int s = 0; s < BoxSlotCount; s++)
{
if (IsSlotLocked(b, s))
continue;
var index = b * BoxSlotCount + s;
action(BD[index]);
for (int s = 0; s < BoxSlotCount; s++)
{
if (IsSlotLocked(b, s))
continue;
var index = (b * BoxSlotCount) + s;
action(BD[index]);
}
}
BoxData = BD;
}
public byte[] PCBinary => BoxData.SelectMany(pk => pk.EncryptedBoxData).ToArray();
public byte[] GetBoxBinary(int box) => BoxData.Skip(box*BoxSlotCount).Take(BoxSlotCount).SelectMany(pk => pk.EncryptedBoxData).ToArray();
public bool SetPCBinary(byte[] data)
{
if (LockedSlots.Length != 0)
@ -714,6 +753,7 @@ namespace PKHeX.Core
BoxData = BD;
return true;
}
public bool SetBoxBinary(byte[] data, int box)
{
int start = box * BoxSlotCount;
@ -739,6 +779,7 @@ namespace PKHeX.Core
pkm.SetStats(pkm.GetStats(pkm.PersonalInfo));
pkm.Stat_Level = pkm.CurrentLevel;
}
protected virtual void SetPKM(PKM pkm) { }
protected virtual void SetDex(PKM pkm) { }
public virtual bool GetSeen(int species) => false;
@ -756,12 +797,15 @@ namespace PKHeX.Core
Buffer.BlockCopy(Data, Offset, data, 0, Length);
return data;
}
public void SetData(byte[] input, int Offset)
{
input.CopyTo(Data, Offset);
Edited = true;
}
public bool IsRangeEmpty(int Offset, int Length) => IsRangeAll(Offset, Length, 0);
public bool IsRangeAll(int Offset, int Length, int value)
{
for (int i = Offset; i < Offset + Length; i++)
@ -769,6 +813,7 @@ namespace PKHeX.Core
return false;
return true;
}
public virtual bool IsPKMPresent(int Offset) => PKX.IsPKMPresent(Data, Offset);
public abstract string GetString(int Offset, int Length);

View file

@ -456,43 +456,48 @@ namespace PKHeX.Core
public static SaveFile GetVariantSAV(byte[] data)
{
// Pre-check for header/footer signatures
SaveFile sav;
byte[] header = new byte[0], footer = new byte[0];
byte[] header = Array.Empty<byte>(), footer = Array.Empty<byte>();
CheckHeaderFooter(ref data, ref header, ref footer);
var sav = GetVariantSAVInternal(data);
if (sav == null)
return null;
sav.Header = header;
sav.Footer = footer;
return sav;
}
private static SaveFile GetVariantSAVInternal(byte[] data)
{
switch (GetSAVGeneration(data))
{
// Main Games
case GameVersion.Gen1: sav = new SAV1(data); break;
case GameVersion.Gen2: sav = new SAV2(data); break;
case GameVersion.Gen3: sav = new SAV3(data); break;
case GameVersion.Gen4: sav = new SAV4(data); break;
case GameVersion.Gen5: sav = new SAV5(data); break;
case GameVersion.Gen6: sav = new SAV6(data); break;
case GameVersion.Gen7: sav = new SAV7(data); break;
case GameVersion.Gen1: return new SAV1(data);
case GameVersion.Gen2: return new SAV2(data);
case GameVersion.Gen3: return new SAV3(data);
case GameVersion.Gen4: return new SAV4(data);
case GameVersion.Gen5: return new SAV5(data);
case GameVersion.Gen6: return new SAV6(data);
case GameVersion.Gen7: return new SAV7(data);
// Side Games
case GameVersion.COLO: sav = new SAV3Colosseum(data); break;
case GameVersion.XD: sav = new SAV3XD(data); break;
case GameVersion.RSBOX: sav = new SAV3RSBox(data); break;
case GameVersion.BATREV: sav = new SAV4BR(data); break;
case GameVersion.COLO: return new SAV3Colosseum(data);
case GameVersion.XD: return new SAV3XD(data);
case GameVersion.RSBOX: return new SAV3RSBox(data);
case GameVersion.BATREV: return new SAV4BR(data);
// Bulk Storage
case GameVersion.USUM: sav = Bank7.GetBank7(data); break;
case GameVersion.USUM: return Bank7.GetBank7(data);
// No pattern matched
default: return null;
}
sav.Header = header;
sav.Footer = footer;
return sav;
}
public static SaveFile GetVariantSAV(SAV3GCMemoryCard MC)
{
// Pre-check for header/footer signatures
SaveFile sav;
byte[] header = new byte[0], footer = new byte[0];
byte[] header = Array.Empty<byte>(), footer = Array.Empty<byte>();
byte[] data = MC.SelectedSaveData;
CheckHeaderFooter(ref data, ref header, ref footer);

View file

@ -142,7 +142,7 @@ namespace PKHeX.WinForms.Controls
public void SetPKMFormatMode(int Format)
{
byte[] extraBytes = new byte[0];
byte[] extraBytes = Array.Empty<byte>();
switch (Format)
{
case 1:
@ -288,8 +288,6 @@ namespace PKHeX.WinForms.Controls
var index = WinFormsUtil.GetIndex(c);
c.DataSource = new BindingSource(MoveDataAllowed, null);
c.SelectedValue = index;
if (c.Visible)
c.SelectionLength = 0; // flicker hack
}
public void UpdateUnicode(string[] symbols)

View file

@ -62,6 +62,7 @@ namespace PKHeX.WinForms.Controls
Parent = FindForm(),
};
}
private int GetSlot(PictureBox sender) => SlotPictureBoxes.IndexOf(WinFormsUtil.GetUnderlyingControl(sender) as PictureBox);
public int GetSlotOffset(int box, int slot) => GetOffset(slot, box);
public int GetSlotOffset(int slot) => GetSlotOffset(CurrentBox, slot);
@ -72,23 +73,28 @@ namespace PKHeX.WinForms.Controls
get => CB_BoxSelect.Enabled;
set => CB_BoxSelect.Enabled = CB_BoxSelect.Visible = B_BoxLeft.Visible = B_BoxRight.Visible = value;
}
public bool ControlsEnabled
{
get => CB_BoxSelect.Enabled;
set => CB_BoxSelect.Enabled = B_BoxLeft.Enabled = B_BoxRight.Enabled = value;
}
public int CurrentBox
{
get => CB_BoxSelect.SelectedIndex;
set => CB_BoxSelect.SelectedIndex = value;
}
public string CurrentBoxName => CB_BoxSelect.Text;
public int GetOffset(int slot, int box)
{
if (box < 0)
box = CurrentBox;
return SAV.GetBoxOffset(box) + slot * SAV.SIZE_STORED;
return SAV.GetBoxOffset(box) + (slot * SAV.SIZE_STORED);
}
public void Setup(SlotChangeManager m)
{
M = m;
@ -96,6 +102,7 @@ namespace PKHeX.WinForms.Controls
FlagIllegal = M.SE.FlagIllegal;
Reset();
}
public void SetSlotFiller(PKM p, int box = -1, int slot = -1, PictureBox pb = null)
{
if (pb == null)
@ -147,6 +154,7 @@ namespace PKHeX.WinForms.Controls
CB_BoxSelect.Items.Add($"Box {i+1}");
}
}
public void ResetSlots()
{
int box = CurrentBox;
@ -161,12 +169,13 @@ namespace PKHeX.WinForms.Controls
{
var pb = SlotPictureBoxes[i];
if (i < SAV.BoxSlotCount)
GetSlotFiller(boxoffset + SAV.SIZE_STORED * i, pb, box, i);
GetSlotFiller(boxoffset + (SAV.SIZE_STORED * i), pb, box, i);
else
pb.Visible = false;
pb.BackgroundImage = slot == i ? M?.ColorizedColor : null;
}
}
public bool SaveBoxBinary()
{
DialogResult dr = WinFormsUtil.Prompt(MessageBoxButtons.YesNoCancel,
@ -192,6 +201,7 @@ namespace PKHeX.WinForms.Controls
}
return false;
}
public void ClearEvents()
{
B_BoxRight.Click -= ClickBoxRight;
@ -204,6 +214,7 @@ namespace PKHeX.WinForms.Controls
ResetBoxNames();
ResetSlots();
}
private void GetBox(object sender, EventArgs e)
{
if (SAV.CurrentBox != CurrentBox)
@ -211,16 +222,21 @@ namespace PKHeX.WinForms.Controls
ResetSlots();
M?.RefreshHoverSlot(this);
}
private void ClickBoxLeft(object sender, EventArgs e) => MoveLeft(ModifierKeys == Keys.Control);
public void MoveLeft(bool max = false)
{
CurrentBox = max ? 0 : (CurrentBox + SAV.BoxCount - 1) % SAV.BoxCount;
}
private void ClickBoxRight(object sender, EventArgs e) => MoveRight(ModifierKeys == Keys.Control);
public void MoveRight(bool max = false)
{
CurrentBox = max ? SAV.BoxCount - 1 : (CurrentBox + 1) % SAV.BoxCount;
}
private void GetSlotFiller(int offset, PictureBox pb, int box = -1, int slot = -1)
{
if (!SAV.IsPKMPresent(offset))

View file

@ -44,6 +44,7 @@ namespace PKHeX.WinForms.Controls
IsPartyFormat = type.IsParty(SAV.Generation)
};
}
public IList<PictureBox> SlotPictureBoxes { get; }
public int GetSlot(PictureBox sender) => SlotPictureBoxes.IndexOf(WinFormsUtil.GetUnderlyingControl(sender) as PictureBox);
public int ViewIndex { get; set; } = -1;
@ -57,6 +58,7 @@ namespace PKHeX.WinForms.Controls
ReloadSlots();
}
}
public void ReloadSlots()
{
UpdateBoxViewers(all: true);
@ -110,6 +112,7 @@ namespace PKHeX.WinForms.Controls
SL_Extra.ViewIndex = -2;
M.OtherSlots.Add(SL_Extra);
}
private void InitializeDragDrop(Control pb)
{
pb.MouseEnter += M.MouseEnter;
@ -129,6 +132,7 @@ namespace PKHeX.WinForms.Controls
/// <summary>Occurs when the Control Collection requests a cloning operation to the current box.</summary>
public event EventHandler RequestCloneData;
/// <summary>Occurs when the Control Collection requests a save to be reloaded.</summary>
public event EventHandler RequestReloadSave;
@ -154,7 +158,7 @@ namespace PKHeX.WinForms.Controls
if (slot < (int)SlotIndex.BattleBox) // Party Slot
return SAV.GetPartyOffset(slot - (int)SlotIndex.Party);
if (slot < (int)SlotIndex.Daycare) // Battle Box Slot
return SAV.BattleBox + (slot - (int)SlotIndex.BattleBox) * SAV.SIZE_STORED;
return SAV.BattleBox + ((slot - (int)SlotIndex.BattleBox) * SAV.SIZE_STORED);
return SAV.GetDaycareSlotOffset(SAV.DaycareIndex, slot - (int)SlotIndex.Daycare);
}
@ -164,6 +168,7 @@ namespace PKHeX.WinForms.Controls
Box.CurrentBox = viewBox;
return mainBox;
}
public void UpdateBoxViewers(bool all = false)
{
foreach (var v in M.Boxes.Where(v => v.CurrentBox == Box.CurrentBox || all))
@ -172,6 +177,7 @@ namespace PKHeX.WinForms.Controls
v.ResetSlots();
}
}
public void SetPKMBoxes()
{
if (SAV.HasBox)
@ -183,6 +189,7 @@ namespace PKHeX.WinForms.Controls
if (M?.ColorizedSlot >= (int)SlotIndex.Party && M.ColorizedSlot < SlotPictureBoxes.Count)
SlotPictureBoxes[M.ColorizedSlot].BackgroundImage = M.ColorizedColor;
}
private void ResetNonBoxSlots()
{
ResetParty();
@ -190,12 +197,14 @@ namespace PKHeX.WinForms.Controls
ResetDaycare();
ResetMiscSlots();
}
private void ResetMiscSlots()
{
var slots = SL_Extra.SlotPictureBoxes;
for (int i = 0; i < SL_Extra.SlotCount; i++)
GetSlotFiller(SL_Extra.GetSlotOffset(i), slots[i]);
}
private void ResetParty()
{
if (!SAV.HasParty)
@ -204,18 +213,20 @@ namespace PKHeX.WinForms.Controls
for (int i = 0; i < 6; i++)
GetSlotFiller(SAV.GetPartyOffset(i), SlotPictureBoxes[i + (int)SlotIndex.Party]);
}
private void ResetBattleBox()
{
if (!SAV.HasBattleBox)
return;
for (int i = 0; i < 6; i++)
GetSlotFiller(SAV.BattleBox + SAV.SIZE_STORED * i, SlotPictureBoxes[i + (int)SlotIndex.BattleBox]);
GetSlotFiller(SAV.BattleBox + (SAV.SIZE_STORED * i), SlotPictureBoxes[i + (int)SlotIndex.BattleBox]);
}
private readonly Label[] L_SlotOccupied;
private readonly TextBox[] TB_SlotEXP;
private readonly Label[] L_SlotEXP;
private void ResetDaycare()
{
if (!SAV.HasDaycare)
@ -231,7 +242,9 @@ namespace PKHeX.WinForms.Controls
bool? occ = SAV.IsDaycareOccupied(SAV.DaycareIndex, i);
L_SlotOccupied[i].Visible = occ != null;
if (occ == true) // If Occupied
{
L_SlotOccupied[i].Text = $"{i + 1}: ✓";
}
else
{
L_SlotOccupied[i].Text = $"{i + 1}: ✘";
@ -251,6 +264,7 @@ namespace PKHeX.WinForms.Controls
}
L_DaycareSeed.Visible = TB_RNGSeed.Visible = seed != null;
}
public void SetParty()
{
// Refresh slots
@ -271,6 +285,7 @@ namespace PKHeX.WinForms.Controls
SlotPictureBoxes[i + (int)SlotIndex.BattleBox].Image = null;
}
}
public void ClickUndo()
{
if (UndoStack.Count == 0)
@ -290,6 +305,7 @@ namespace PKHeX.WinForms.Controls
UndoSlotChange(change);
M.SetColor(change.Box, change.Slot, Resources.slotSet);
}
public void ClickRedo()
{
if (RedoStack.Count == 0)
@ -309,6 +325,7 @@ namespace PKHeX.WinForms.Controls
UndoSlotChange(change);
M.SetColor(change.Box, change.Slot, Resources.slotSet);
}
public void SetClonesToBox(PKM pk)
{
if (WinFormsUtil.Prompt(MessageBoxButtons.YesNo, string.Format(MsgSaveBoxCloneFromTabs, Box.CurrentBoxName)) != DialogResult.Yes)
@ -320,6 +337,7 @@ namespace PKHeX.WinForms.Controls
UpdateBoxViewers();
}
private int SetClonesToCurrentBox(PKM pk, int box)
{
int slotSkipped = 0;
@ -333,6 +351,7 @@ namespace PKHeX.WinForms.Controls
return slotSkipped;
}
public void ClickSlot(object sender, EventArgs e)
{
switch (ModifierKeys)
@ -364,6 +383,7 @@ namespace PKHeX.WinForms.Controls
SystemSounds.Asterisk.Play();
}
private void GetSlotFiller(int offset, PictureBox pb)
{
if (!SAV.IsPKMPresent(offset))
@ -408,6 +428,7 @@ namespace PKHeX.WinForms.Controls
var pt = Tab_Box.PointToScreen(new Point(0, 0));
SortMenu.Show(pt);
}
public void ClearAll(Func<PKM, bool> criteria)
{
if (!CanManipulateRegion(0, SAV.BoxCount - 1, MsgSaveBoxClearAll, MsgSaveBoxClearAllFailBattle))
@ -415,6 +436,7 @@ namespace PKHeX.WinForms.Controls
SAV.ClearBoxes(deleteCriteria: criteria);
FinishBoxManipulation(MsgSaveBoxClearAllSuccess, true);
}
public void ClearCurrent(Func<PKM, bool> criteria)
{
if (!CanManipulateRegion(Box.CurrentBox, Box.CurrentBox, MsgSaveBoxClearCurrent, MsgSaveBoxClearCurrentFailBattle))
@ -422,6 +444,7 @@ namespace PKHeX.WinForms.Controls
SAV.ClearBoxes(Box.CurrentBox, Box.CurrentBox, criteria);
FinishBoxManipulation(MsgSaveBoxClearCurrentSuccess, false);
}
public void SortAll(Func<IEnumerable<PKM>, IEnumerable<PKM>> sorter, bool reverse)
{
if (!CanManipulateRegion(0, SAV.BoxCount - 1, MsgSaveBoxSortAll, MsgSaveBoxSortAllFailBattle))
@ -429,6 +452,7 @@ namespace PKHeX.WinForms.Controls
SAV.SortBoxes(sortMethod: sorter, reverse: reverse);
FinishBoxManipulation(MsgSaveBoxSortAllSuccess, true);
}
public void SortCurrent(Func<IEnumerable<PKM>, IEnumerable<PKM>> sorter, bool reverse)
{
if (!CanManipulateRegion(Box.CurrentBox, Box.CurrentBox, MsgSaveBoxSortCurrent, MsgSaveBoxSortCurrentFailBattle))
@ -436,18 +460,21 @@ namespace PKHeX.WinForms.Controls
SAV.SortBoxes(Box.CurrentBox, Box.CurrentBox, sorter, reverse: reverse);
FinishBoxManipulation(MsgSaveBoxSortCurrentSuccess, false);
}
public void ModifyAll(Action<PKM> action)
{
SAV.ModifyBoxes(action);
FinishBoxManipulation(null, true);
SystemSounds.Asterisk.Play();
}
public void ModifyCurrent(Action<PKM> action)
{
SAV.ModifyBoxes(action, Box.CurrentBox, Box.CurrentBox);
FinishBoxManipulation(null, true);
SystemSounds.Asterisk.Play();
}
private void FinishBoxManipulation(string message, bool all)
{
SetPKMBoxes();
@ -455,6 +482,7 @@ namespace PKHeX.WinForms.Controls
if (message != null)
WinFormsUtil.Alert(message);
}
private bool CanManipulateRegion(int start, int end, string prompt, string fail)
{
if (prompt != null && WinFormsUtil.Prompt(MessageBoxButtons.YesNo, prompt) != DialogResult.Yes)
@ -492,12 +520,14 @@ namespace PKHeX.WinForms.Controls
{ var z = M.Boxes[1].ParentForm; z.CenterToForm(ParentForm); z.BringToFront(); return; }
new SAV_BoxViewer(this, M).Show();
}
private void ClickClone(object sender, EventArgs e)
{
if (GetSlot((PictureBox)sender) >= 0)
return; // only perform action if cloning to boxes
RequestCloneData?.Invoke(sender, e);
}
private void UpdateSaveSlot(object sender, EventArgs e)
{
if (SAV.Version != GameVersion.BATREV)
@ -507,6 +537,7 @@ namespace PKHeX.WinForms.Controls
SetPKMBoxes();
UpdateBoxViewers(true);
}
private void UpdateStringSeed(object sender, EventArgs e)
{
if (!FieldsLoaded)
@ -552,6 +583,7 @@ namespace PKHeX.WinForms.Controls
SAV.Edited = true;
}
}
private void SwitchDaycare(object sender, EventArgs e)
{
if (!SAV.HasTwoDaycares)
@ -562,6 +594,7 @@ namespace PKHeX.WinForms.Controls
SAV.DaycareIndex ^= 1;
ResetDaycare();
}
private void B_SaveBoxBin_Click(object sender, EventArgs e)
{
if (!SAV.HasBox)
@ -583,11 +616,13 @@ namespace PKHeX.WinForms.Controls
private void B_Roamer_Click(object sender, EventArgs e) => new SAV_Roamer3(SAV).ShowDialog();
private void B_OpenApricorn_Click(object sender, EventArgs e) => new SAV_Apricorn(SAV).ShowDialog();
private void B_CGearSkin_Click(object sender, EventArgs e) => new SAV_CGearSkin(SAV).ShowDialog();
private void B_OpenEventFlags_Click(object sender, EventArgs e)
{
var form = SAV.Generation == 1 ? new SAV_EventReset1(SAV) as Form : new SAV_EventFlags(SAV);
form.ShowDialog();
}
private void B_OpenBoxLayout_Click(object sender, EventArgs e)
{
new SAV_BoxLayout(SAV, Box.CurrentBox).ShowDialog();
@ -595,6 +630,7 @@ namespace PKHeX.WinForms.Controls
Box.ResetSlots(); // refresh box background
UpdateBoxViewers(all: true); // update subviewers
}
private void B_OpenTrainerInfo_Click(object sender, EventArgs e)
{
if (SAV.Generation < 6)
@ -604,12 +640,14 @@ namespace PKHeX.WinForms.Controls
else if (SAV is SAV7)
new SAV_Trainer7(SAV).ShowDialog();
}
private void B_OpenOPowers_Click(object sender, EventArgs e)
{
if (SAV.Generation != 6)
return;
new SAV_OPower((SAV6)SAV).ShowDialog();
}
private void B_OpenFriendSafari_Click(object sender, EventArgs e)
{
if (!SAV.XY)
@ -636,11 +674,13 @@ namespace PKHeX.WinForms.Controls
default: return null;
}
}
private void B_OpenPokedex_Click(object sender, EventArgs e)
{
var editor = GetPokeDexEditor(SAV);
editor?.ShowDialog();
}
private void B_OpenMiscEditor_Click(object sender, EventArgs e)
{
switch (SAV.Generation)
@ -650,6 +690,7 @@ namespace PKHeX.WinForms.Controls
case 5: new SAV_Misc5(SAV).ShowDialog(); break;
}
}
private void B_OpenRTCEditor_Click(object sender, EventArgs e)
{
switch (SAV.Generation)
@ -660,6 +701,7 @@ namespace PKHeX.WinForms.Controls
new SAV_RTC3(SAV).ShowDialog(); break;
}
}
private void B_OpenHoneyTreeEditor_Click(object sender, EventArgs e)
{
switch (SAV.Version)
@ -669,6 +711,7 @@ namespace PKHeX.WinForms.Controls
new SAV_HoneyTree(SAV).ShowDialog(); break;
}
}
private void B_OUTPasserby_Click(object sender, EventArgs e)
{
if (SAV.Generation != 6)
@ -678,6 +721,7 @@ namespace PKHeX.WinForms.Controls
var result = PSS6.GetPSSParse((SAV6)SAV);
Clipboard.SetText(string.Join(Environment.NewLine, result));
}
private void B_OUTHallofFame_Click(object sender, EventArgs e)
{
if (SAV.Generation == 6)
@ -685,6 +729,7 @@ namespace PKHeX.WinForms.Controls
else if (SAV is SAV7)
new SAV_HallOfFame7(SAV).ShowDialog();
}
private void B_JPEG_Click(object sender, EventArgs e)
{
byte[] jpeg = SAV.JPEGData;
@ -695,6 +740,7 @@ namespace PKHeX.WinForms.Controls
if (sfd.ShowDialog() != DialogResult.OK) return;
File.WriteAllBytes(sfd.FileName, jpeg);
}
private void ClickVerifyCHK(object sender, EventArgs e)
{
if (SAV.Edited) { WinFormsUtil.Alert(MsgSaveChecksumFailEdited); return; }
@ -716,6 +762,7 @@ namespace PKHeX.WinForms.Controls
noSetb = GetPKMSetOverride();
return true;
}
private bool? GetPKMSetOverride()
{
var yn = ModifyPKM ? MsgYes : MsgNo;
@ -726,6 +773,7 @@ namespace PKHeX.WinForms.Controls
string.Format(MsgSaveBoxImportModifyCurrent, yn));
return noSet == DialogResult.Yes || noSet == DialogResult.No ? (bool?)false : null;
}
private static bool IsFolderPath(out string path)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
@ -739,6 +787,7 @@ namespace PKHeX.WinForms.Controls
ValidateChildren();
return WinFormsUtil.SaveSAVDialog(SAV, SAV.CurrentBox);
}
public bool ExportBackup()
{
if (!SAV.Exportable)
@ -753,7 +802,9 @@ namespace PKHeX.WinForms.Controls
return true;
}
public bool IsPCBoxBin(int length) => PKX.IsPKM(length / SAV.SlotCount) || PKX.IsPKM(length / SAV.BoxSlotCount);
public bool OpenPCBoxBin(byte[] input, out string c)
{
if (SAV.PCBinary.Length == input.Length)
@ -783,6 +834,7 @@ namespace PKHeX.WinForms.Controls
UpdateBoxViewers();
return true;
}
public bool OpenBattleVideo(BattleVideo b, out string c)
{
if (b == null || SAV.Generation != b.Generation)
@ -807,7 +859,7 @@ namespace PKHeX.WinForms.Controls
{
if (SAV.IsSlotLocked(Box.CurrentBox, i))
{ slotSkipped++; continue; }
SAV.SetStoredSlot(data[i], offset + i * SAV.SIZE_STORED, noSetb);
SAV.SetStoredSlot(data[i], offset + (i * SAV.SIZE_STORED), noSetb);
}
SetPKMBoxes();
@ -817,6 +869,7 @@ namespace PKHeX.WinForms.Controls
return true;
}
public bool DumpBoxes(out string result, string path = null, bool separate = false)
{
if (path == null && !IsFolderPath(out path))
@ -830,6 +883,7 @@ namespace PKHeX.WinForms.Controls
SAV.DumpBoxes(path, out result, separate);
return true;
}
public bool DumpBox(out string result, string path = null)
{
if (path == null && !IsFolderPath(out path))
@ -843,6 +897,7 @@ namespace PKHeX.WinForms.Controls
SAV.DumpBox(path, out result, Box.CurrentBox);
return true;
}
public bool LoadBoxes(out string result, string path = null)
{
result = string.Empty;
@ -887,6 +942,7 @@ namespace PKHeX.WinForms.Controls
FieldsLoaded = true;
return WindowTranslationRequired;
}
private void ToggleViewReset()
{
// Close subforms that are save dependent
@ -900,6 +956,7 @@ namespace PKHeX.WinForms.Controls
M.SetColor(-1, -1, null);
SortMenu.ToggleVisibility();
}
private bool ToggleViewBox(SaveFile sav)
{
if (!sav.HasBox)
@ -920,6 +977,7 @@ namespace PKHeX.WinForms.Controls
tabBoxMulti.TabPages.Insert(0, Tab_Box);
return true;
}
private bool ToggleViewParty(SaveFile sav, int BoxTab)
{
if (!sav.HasParty)
@ -939,6 +997,7 @@ namespace PKHeX.WinForms.Controls
tabBoxMulti.TabPages.Insert(index + 1, Tab_PartyBattle);
return true;
}
private bool ToggleViewDaycare(SaveFile sav, int BoxTab, int PartyTab)
{
if (!sav.HasDaycare)
@ -960,6 +1019,7 @@ namespace PKHeX.WinForms.Controls
tabBoxMulti.TabPages.Insert(index + 1, Tab_Other);
return true;
}
private void ToggleViewSubEditors(SaveFile sav)
{
if (!sav.Exportable || sav is BulkStorage)
@ -1007,6 +1067,7 @@ namespace PKHeX.WinForms.Controls
foreach (Control c in FLP_SAVtools.Controls.OfType<Control>())
c.Visible = c.Enabled;
}
private void ToggleViewMisc(SaveFile sav)
{
// Generational Interface
@ -1081,6 +1142,7 @@ namespace PKHeX.WinForms.Controls
catch { }
WinFormsUtil.Alert(MsgSimulatorExportBattleBox);
}
public void ClickShowdownExportCurrentBox(object sender, EventArgs e)
{
if (!SAV.HasBox)
@ -1105,11 +1167,13 @@ namespace PKHeX.WinForms.Controls
new SAV_Underground(SAV).ShowDialog(); break;
}
}
private void B_FestivalPlaza_Click(object sender, EventArgs e)
{
if (SAV is SAV7)
new SAV_FestivalPlaza(SAV).ShowDialog();
}
private void B_MailBox_Click(object sender, EventArgs e)
{
new SAV_MailBox(SAV).ShowDialog();

View file

@ -10,6 +10,7 @@ namespace PKHeX.WinForms
public partial class TrashEditor : Form
{
private readonly SaveFile SAV;
public TrashEditor(TextBoxBase TB_NN, byte[] raw, SaveFile sav)
{
InitializeComponent();
@ -52,6 +53,7 @@ namespace PKHeX.WinForms
private bool editing;
private readonly bool bigendian;
private void B_Cancel_Click(object sender, EventArgs e) => Close();
private void B_Save_Click(object sender, EventArgs e)
{
FinalString = TB_Text.Text;
@ -77,6 +79,7 @@ namespace PKHeX.WinForms
FLP_Characters.Controls.Add(l);
}
}
private void AddTrashEditing(int count)
{
FLP_Hex.Visible = true;
@ -87,7 +90,7 @@ namespace PKHeX.WinForms
{
var l = GetLabel($"${i:X2}");
l.Font = courier;
var n = GetNUD(hex: true, min: 0, max: 255);
var n = GetNUD(min: 0, max: 255, hex: true);
n.Click += (s, e) =>
{
switch (ModifierKeys)
@ -126,6 +129,7 @@ namespace PKHeX.WinForms
TB_Text.Text = str;
editing = false;
}
private void UpdateString(object sender, EventArgs e)
{
if (editing)
@ -138,6 +142,7 @@ namespace PKHeX.WinForms
Bytes[i].Value = Raw[i];
editing = false;
}
private void B_ApplyTrash_Click(object sender, EventArgs e)
{
string species = PKX.GetSpeciesNameGeneration(WinFormsUtil.GetIndex(CB_Species),
@ -162,18 +167,21 @@ namespace PKHeX.WinForms
for (int i = current.Length; i < data.Length; i++)
Bytes[i].Value = data[i];
}
private void B_ClearTrash_Click(object sender, EventArgs e)
{
byte[] current = SetString(TB_Text.Text);
for (int i = current.Length; i < Bytes.Count; i++)
Bytes[i].Value = 0;
}
private byte[] SetString(string text)
{
return SAV is SAV2 s && s.Korean
? StringConverter.SetString2KOR(text, Raw.Length)
: StringConverter.SetString(text, SAV.Generation, SAV.Japanese, bigendian, Raw.Length, SAV.Language);
}
private string GetString()
{
return SAV is SAV2 s && s.Korean
@ -183,6 +191,7 @@ namespace PKHeX.WinForms
// Helpers
private static Label GetLabel(string str) => new Label {Text = str, AutoSize = true};
private static NumericUpDown GetNUD(int min, int max, bool hex) => new NumericUpDown
{
Maximum = max,
@ -203,6 +212,7 @@ namespace PKHeX.WinForms
default: return Array.Empty<ushort>();
}
}
private static readonly ushort[] chars67 =
{
0xE081, 0xE082, 0xE083, 0xE084, 0xE085, 0xE086, 0xE087, 0xE08D,

View file

@ -184,7 +184,7 @@ namespace PKHeX.WinForms
// Data from Box: Delete from save file
int box = pk.Box-1;
int slot = pk.Slot-1;
int offset = SAV.GetBoxOffset(box) + slot*SAV.SIZE_STORED;
int offset = SAV.GetBoxOffset(box) + (slot *SAV.SIZE_STORED);
PKM pkSAV = SAV.GetStoredSlot(offset);
if (!pkSAV.DecryptedBoxData.SequenceEqual(pk.DecryptedBoxData)) // data still exists in SAV, unmodified
@ -239,7 +239,7 @@ namespace PKHeX.WinForms
slotColor = Properties.Resources.slotSet;
if ((SCR_Box.Maximum+1)*6 < Results.Count)
SCR_Box.Maximum++;
SCR_Box.Value = Math.Max(0, SCR_Box.Maximum - PKXBOXES.Length/6 + 1);
SCR_Box.Value = Math.Max(0, SCR_Box.Maximum - (PKXBOXES.Length/6) + 1);
FillPKXBoxes(SCR_Box.Value);
WinFormsUtil.Alert(MsgDBAddFromTabsSuccess);
}
@ -320,8 +320,7 @@ namespace PKHeX.WinForms
private void GenerateDBReport(object sender, EventArgs e)
{
if (WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgDBCreateReportPrompt, MsgDBCreateReportWarning)
!= DialogResult.Yes)
if (WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgDBCreateReportPrompt, MsgDBCreateReportWarning) != DialogResult.Yes)
return;
ReportGrid reportGrid = new ReportGrid();
@ -352,8 +351,10 @@ namespace PKHeX.WinForms
var sav = SaveUtil.GetVariantSAV(file);
var path = EXTERNAL_SAV + new FileInfo(file).Name;
if (sav.HasBox)
{
foreach (var pk in sav.BoxData)
addPKM(pk);
}
void addPKM(PKM pk)
{
@ -658,7 +659,7 @@ namespace PKHeX.WinForms
return;
}
int begin = start*RES_MIN;
int end = Math.Min(RES_MAX, Results.Count - start*RES_MIN);
int end = Math.Min(RES_MAX, Results.Count - begin);
for (int i = 0; i < end; i++)
PKXBOXES[i].Image = Results[i + begin].Sprite();
for (int i = end; i < RES_MAX; i++)
@ -666,8 +667,8 @@ namespace PKHeX.WinForms
for (int i = 0; i < RES_MAX; i++)
PKXBOXES[i].BackgroundImage = Properties.Resources.slotTrans;
if (slotSelected != -1 && slotSelected >= RES_MIN * start && slotSelected < RES_MIN * start + RES_MAX)
PKXBOXES[slotSelected - start * RES_MIN].BackgroundImage = slotColor ?? Properties.Resources.slotView;
if (slotSelected != -1 && slotSelected >= begin && slotSelected < begin + RES_MAX)
PKXBOXES[slotSelected - begin].BackgroundImage = slotColor ?? Properties.Resources.slotView;
}
// Misc Update Methods
@ -696,9 +697,15 @@ namespace PKHeX.WinForms
private void Menu_SearchAdvanced_Click(object sender, EventArgs e)
{
if (!Menu_SearchAdvanced.Checked)
{ Size = MinimumSize; RTB_Instructions.Clear(); }
else Size = MaximumSize;
if (Menu_SearchAdvanced.Checked)
{
Size = MaximumSize;
}
else
{
Size = MinimumSize;
RTB_Instructions.Clear();
}
}
private void Menu_Exit_Click(object sender, EventArgs e) => Close();

View file

@ -10,6 +10,7 @@ namespace PKHeX.WinForms
{
private readonly SaveFile Origin;
private readonly SAV3 SAV;
public SAV_Misc3(SaveFile sav)
{
InitializeComponent();
@ -34,7 +35,7 @@ namespace PKHeX.WinForms
if (SAV.FRLG)
{
TB_OTName.Text = StringConverter.GetString3(SAV.Data, SAV.GetBlockOffset(4) + 0xBCC, 8, SAV.Japanese);
TB_OTName.Text = SAV.GetString(SAV.GetBlockOffset(4) + 0xBCC, 8);
ComboBox[] cba = { CB_TCM1, CB_TCM2, CB_TCM3, CB_TCM4, CB_TCM5, CB_TCM6 };
int[] HoennListMixed = {
277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,
@ -64,6 +65,7 @@ namespace PKHeX.WinForms
NUD_BP.Value = Math.Min(NUD_BP.Maximum, SAV.BP);
NUD_Coins.Value = Math.Min(NUD_Coins.Maximum, SAV.Coin);
}
private void B_Save_Click(object sender, EventArgs e)
{
if (tabControl1.Controls.Contains(TAB_Joyful))
@ -75,7 +77,7 @@ namespace PKHeX.WinForms
if (SAV.FRLG)
{
SAV.SetData(SAV.SetString(TB_OTName.Text, TB_OTName.MaxLength), SAV.GetBlockOffset(4) + 0xBCC);
ComboBox[] cba = new[] { CB_TCM1, CB_TCM2, CB_TCM3, CB_TCM4, CB_TCM5, CB_TCM6 };
ComboBox[] cba = { CB_TCM1, CB_TCM2, CB_TCM3, CB_TCM4, CB_TCM5, CB_TCM6 };
int ofsTCM = SAV.GetBlockOffset(2) + 0x106;
for (int i = 0; i < cba.Length; i++)
BitConverter.GetBytes((ushort)(int)cba[i].SelectedValue).CopyTo(SAV.Data, ofsTCM + (i << 1));
@ -87,10 +89,8 @@ namespace PKHeX.WinForms
Origin.SetData(SAV.Data, 0);
Close();
}
private void B_Cancel_Click(object sender, EventArgs e)
{
Close();
}
private void B_Cancel_Click(object sender, EventArgs e) => Close();
#region Joyful
private int JUMPS_IN_ROW, JUMPS_SCORE, JUMPS_5_IN_ROW;
@ -249,6 +249,7 @@ namespace PKHeX.WinForms
private string[][] BFT;
private int[][] BFV;
private string[] BFN;
private void ChangeStat1(object sender, EventArgs e)
{
if (loading) return;

View file

@ -7,6 +7,7 @@ namespace PKHeX.WinForms
public sealed partial class SAV_BoxViewer : Form
{
private readonly SAVEditor parent;
public SAV_BoxViewer(SAVEditor p, SlotChangeManager m)
{
parent = p;
@ -35,6 +36,7 @@ namespace PKHeX.WinForms
foreach (PictureBox pb in Box.SlotPictureBoxes)
pb.ContextMenuStrip = parent.SlotPictureBoxes[0].ContextMenuStrip;
}
public int CurrentBox => Box.CurrentBox;
private void PB_BoxSwap_Click(object sender, EventArgs e) => Box.CurrentBox = parent.SwapBoxesViewer(Box.CurrentBox);
public void SetPKMBoxes() => Box.ResetSlots();