Revise EncounterArea and EncounterType for clarity (#3228)

EncounterArea now stores a more specific type'd array for encounter slots. Better iteration and less casting, as the nonspecific `Slots` fetch is rarely referenced.

EncounterType renamed to GroundTile to reflect how it actually works in Gen4. Was previously an ambiguous field that was clarified a little; we can describe it a little better now. Keep the GUI the same to not scare the end users.

Change Trash Byte properties to get/set a Span. Trash Byte legality checking easier on the garbage collector?
This commit is contained in:
Kurt 2021-06-29 20:58:06 -07:00 committed by GitHub
parent 9cd617708d
commit 103aa9aa4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 534 additions and 329 deletions

View file

@ -104,7 +104,6 @@ namespace PKHeX.Core
public int Met_Year => pkm.MetDate.GetValueOrDefault().Year;
public int Met_Month => pkm.MetDate.GetValueOrDefault().Month;
public int Met_Day => pkm.MetDate.GetValueOrDefault().Day;
public int Encounter => pkm.EncounterType;
#endregion

View file

@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
namespace PKHeX.Core
{
@ -11,7 +11,7 @@ namespace PKHeX.Core
public GameVersion Version { get; }
public int Location { get; protected init; }
public SlotType Type { get; protected init; } = SlotType.Any;
public EncounterSlot[] Slots { get; protected init; } = Array.Empty<EncounterSlot>();
protected abstract IReadOnlyList<EncounterSlot> Raw { get; }
protected EncounterArea(GameVersion game) => Version = game;
@ -29,5 +29,8 @@ namespace PKHeX.Core
/// <param name="location">Met Location ID</param>
/// <returns>True if possibly originated from this area, false otherwise.</returns>
public virtual bool IsMatchLocation(int location) => Location == location;
public bool HasSpecies(int species) => Raw.Any(z => z.Species == species);
public IEnumerable<EncounterSlot> GetSpecies(IReadOnlyList<DexLevel> chain) => Raw.Where(z => chain.Any(c => z.Species == c.Species));
}
}

View file

@ -9,6 +9,9 @@ namespace PKHeX.Core
public sealed record EncounterArea1 : EncounterArea
{
public readonly int Rate;
public readonly EncounterSlot1[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public static EncounterArea1[] GetAreas(byte[][] input, GameVersion game)
{

View file

@ -16,6 +16,9 @@ namespace PKHeX.Core
internal readonly EncounterTime Time;
public readonly int Rate;
public readonly IReadOnlyList<byte> Rates;
public readonly EncounterSlot2[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public static EncounterArea2[] GetAreas(byte[][] input, GameVersion game)
{
@ -86,7 +89,7 @@ namespace PKHeX.Core
return GetSlotsSpecificLevelTime(chain, pk2.Met_TimeOfDay, pk2.Met_Level);
}
private IEnumerable<EncounterSlot> GetSlotsSpecificLevelTime(IReadOnlyList<EvoCriteria> chain, int time, int lvl)
private IEnumerable<EncounterSlot2> GetSlotsSpecificLevelTime(IReadOnlyList<EvoCriteria> chain, int time, int lvl)
{
foreach (var slot in Slots)
{
@ -113,7 +116,7 @@ namespace PKHeX.Core
}
}
private IEnumerable<EncounterSlot> GetSlotsFuzzy(IReadOnlyList<EvoCriteria> chain)
private IEnumerable<EncounterSlot2> GetSlotsFuzzy(IReadOnlyList<EvoCriteria> chain)
{
foreach (var slot in Slots)
{

View file

@ -10,6 +10,9 @@ namespace PKHeX.Core
public sealed record EncounterArea3 : EncounterArea
{
public readonly int Rate;
public readonly EncounterSlot3[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public static EncounterArea3[] GetAreas(byte[][] input, GameVersion game)
{
@ -108,7 +111,7 @@ namespace PKHeX.Core
return GetSlotsMatching(chain, pkm.Met_Level);
}
private IEnumerable<EncounterSlot> GetSlotsMatching(IReadOnlyList<EvoCriteria> chain, int lvl)
private IEnumerable<EncounterSlot3> GetSlotsMatching(IReadOnlyList<EvoCriteria> chain, int lvl)
{
foreach (var slot in Slots)
{
@ -128,7 +131,7 @@ namespace PKHeX.Core
}
}
private IEnumerable<EncounterSlot> GetSlotsFuzzy(IReadOnlyList<EvoCriteria> chain)
private IEnumerable<EncounterSlot3> GetSlotsFuzzy(IReadOnlyList<EvoCriteria> chain)
{
foreach (var slot in Slots)
{

View file

@ -9,6 +9,10 @@ namespace PKHeX.Core
/// </summary>
public sealed record EncounterArea3XD : EncounterArea
{
public readonly EncounterSlot3PokeSpot[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public EncounterArea3XD(int loc, int s0, int l0, int s1, int l1, int s2, int l2) : base(GameVersion.XD)
{
Location = loc;
@ -26,11 +30,11 @@ namespace PKHeX.Core
if (pkm.Format != 3) // Met Location and Met Level are changed on PK3->PK4
return GetSlotsFuzzy(chain);
if (pkm.Met_Location != Location)
return Array.Empty<EncounterSlot>();
return Array.Empty<EncounterSlot3PokeSpot>();
return GetSlotsMatching(chain, pkm.Met_Level);
}
private IEnumerable<EncounterSlot> GetSlotsMatching(IReadOnlyList<EvoCriteria> chain, int lvl)
private IEnumerable<EncounterSlot3PokeSpot> GetSlotsMatching(IReadOnlyList<EvoCriteria> chain, int lvl)
{
foreach (var slot in Slots)
{
@ -50,7 +54,7 @@ namespace PKHeX.Core
}
}
private IEnumerable<EncounterSlot> GetSlotsFuzzy(IReadOnlyList<EvoCriteria> chain)
private IEnumerable<EncounterSlot3PokeSpot> GetSlotsFuzzy(IReadOnlyList<EvoCriteria> chain)
{
foreach (var slot in Slots)
{

View file

@ -9,8 +9,11 @@ namespace PKHeX.Core
/// </summary>
public sealed record EncounterArea4 : EncounterArea
{
public readonly EncounterType TypeEncounter;
public readonly int Rate;
public readonly GroundTilePermission GroundTile;
public readonly EncounterSlot4[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public static EncounterArea4[] GetAreas(byte[][] input, GameVersion game)
{
@ -25,7 +28,8 @@ namespace PKHeX.Core
Location = data[0] | (data[1] << 8);
Type = (SlotType)data[2];
Rate = data[3];
TypeEncounter = (EncounterType) BitConverter.ToUInt16(data, 4);
// although GroundTilePermission flags are 32bit, none have values > 16bit.
GroundTile = (GroundTilePermission) BitConverter.ToUInt16(data, 4);
Slots = ReadRegularSlots(data);
}
@ -60,11 +64,11 @@ namespace PKHeX.Core
if (pkm.Format != 4) // Met Location and Met Level are changed on PK4->PK5
return GetSlotsFuzzy(chain);
if (pkm.Met_Location != Location)
return Array.Empty<EncounterSlot>();
return Array.Empty<EncounterSlot4>();
return GetSlotsMatching(chain, pkm.Met_Level);
}
private IEnumerable<EncounterSlot> GetSlotsMatching(IReadOnlyList<EvoCriteria> chain, int lvl)
private IEnumerable<EncounterSlot4> GetSlotsMatching(IReadOnlyList<EvoCriteria> chain, int lvl)
{
foreach (var slot in Slots)
{
@ -84,7 +88,7 @@ namespace PKHeX.Core
}
}
private IEnumerable<EncounterSlot> GetSlotsFuzzy(IReadOnlyList<EvoCriteria> chain)
private IEnumerable<EncounterSlot4> GetSlotsFuzzy(IReadOnlyList<EvoCriteria> chain)
{
foreach (var slot in Slots)
{

View file

@ -9,6 +9,10 @@ namespace PKHeX.Core
/// </summary>
public sealed record EncounterArea5 : EncounterArea
{
public readonly EncounterSlot5[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public static EncounterArea5[] GetAreas(byte[][] input, GameVersion game)
{
var result = new EncounterArea5[input.Length];

View file

@ -9,6 +9,10 @@ namespace PKHeX.Core
/// </summary>
public sealed record EncounterArea6AO : EncounterArea
{
public readonly EncounterSlot6AO[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public static EncounterArea6AO[] GetAreas(byte[][] input, GameVersion game)
{
var result = new EncounterArea6AO[input.Length];
@ -68,12 +72,11 @@ namespace PKHeX.Core
break;
// Track some metadata about how this slot was matched.
var ao = (EncounterSlot6AO)slot;
var clone = ao with
var clone = slot with
{
WhiteFlute = evo.MinLevel < slot.LevelMin,
BlackFlute = evo.MinLevel > slot.LevelMax && evo.MinLevel <= slot.LevelMax + FluteBoostMax,
DexNav = ao.CanDexNav && (evo.MinLevel != slot.LevelMax || pkm.RelearnMove1 != 0 || pkm.AbilityNumber == 4),
DexNav = slot.CanDexNav && (evo.MinLevel != slot.LevelMax || pkm.RelearnMove1 != 0 || pkm.AbilityNumber == 4),
};
yield return clone;
break;

View file

@ -9,6 +9,10 @@ namespace PKHeX.Core
/// </summary>
public sealed record EncounterArea6XY : EncounterArea
{
public readonly EncounterSlot6XY[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public static EncounterArea6XY[] GetAreas(byte[][] input, GameVersion game, EncounterArea6XY safari)
{
var result = new EncounterArea6XY[input.Length + 1];
@ -124,7 +128,7 @@ namespace PKHeX.Core
if (maxLevel != pkm.Met_Level)
break;
yield return ((EncounterSlot6XY)slot).CreatePressureFormCopy(evo.Form);
yield return slot.CreatePressureFormCopy(evo.Form);
break;
}

View file

@ -9,6 +9,10 @@ namespace PKHeX.Core
/// </summary>
public sealed record EncounterArea7 : EncounterArea
{
public readonly EncounterSlot7[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public static EncounterArea7[] GetAreas(byte[][] input, GameVersion game)
{
var result = new EncounterArea7[input.Length];

View file

@ -8,6 +8,10 @@ namespace PKHeX.Core
/// </summary>
public sealed record EncounterArea7b : EncounterArea
{
public readonly EncounterSlot7b[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
public static EncounterArea7b[] GetAreas(byte[][] input, GameVersion game)
{
var result = new EncounterArea7b[input.Length];

View file

@ -15,12 +15,16 @@ namespace PKHeX.Core
public int Species { get; }
/// <summary> Form of the Species </summary>
public int Form { get; }
public readonly EncounterSlot7GO[] Slots;
private EncounterArea7g(int species, int form) : base(GameVersion.GO)
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
private EncounterArea7g(int species, int form, EncounterSlot7GO[] slots) : base(GameVersion.GO)
{
Species = species;
Form = form;
Location = Locations.GO7;
Slots = slots;
}
internal static EncounterArea7g[] GetArea(byte[][] data)
@ -40,7 +44,7 @@ namespace PKHeX.Core
int form = sf >> 11;
var result = new EncounterSlot7GO[(data.Length - 2) / entrySize];
var area = new EncounterArea7g(species, form) { Slots = result };
var area = new EncounterArea7g(species, form, result);
for (int i = 0; i < result.Length; i++)
{
var offset = (i * entrySize) + 2;
@ -72,11 +76,10 @@ namespace PKHeX.Core
var stamp = EncounterSlotGO.GetTimeStamp(pkm.Met_Year + 2000, pkm.Met_Month, pkm.Met_Day);
var met = Math.Max(sf.MinLevel, pkm.Met_Level);
EncounterSlot? deferredIV = null;
EncounterSlot7GO? deferredIV = null;
foreach (var s in Slots)
foreach (var slot in Slots)
{
var slot = (EncounterSlot7GO)s;
if (!slot.IsLevelWithinRange(met))
continue;
//if (!slot.IsBallValid(ball)) -- can have any of the in-game balls due to re-capture

View file

@ -10,6 +10,9 @@ namespace PKHeX.Core
/// </summary>
public sealed record EncounterArea8 : EncounterArea
{
public readonly EncounterSlot8[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
/// <summary>
/// Slots from this area can cross over to another area, resulting in a different met location.
/// </summary>
@ -234,9 +237,9 @@ namespace PKHeX.Core
Slots = ReadSlots(areaData, areaData[1]);
}
private EncounterSlot[] ReadSlots(byte[] areaData, byte slotCount)
private EncounterSlot8[] ReadSlots(byte[] areaData, byte slotCount)
{
var slots = new EncounterSlot[slotCount];
var slots = new EncounterSlot8[slotCount];
int ctr = 0;
int ofs = 2;

View file

@ -15,12 +15,16 @@ namespace PKHeX.Core
public int Species { get; }
/// <summary> Form of the Species </summary>
public int Form { get; }
public readonly EncounterSlot8GO[] Slots;
private EncounterArea8g(int species, int form) : base(GameVersion.GO)
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
private EncounterArea8g(int species, int form, EncounterSlot8GO[] slots) : base(GameVersion.GO)
{
Species = species;
Form = form;
Location = Locations.GO8;
Slots = slots;
}
internal static EncounterArea8g[] GetArea(byte[][] data)
@ -42,7 +46,7 @@ namespace PKHeX.Core
var group = GetGroup(species, form);
var result = new EncounterSlot8GO[(data.Length - 2) / entrySize];
var area = new EncounterArea8g(species, form) {Slots = result};
var area = new EncounterArea8g(species, form, result);
for (int i = 0; i < result.Length; i++)
{
var offset = (i * entrySize) + 2;
@ -102,11 +106,10 @@ namespace PKHeX.Core
var ball = (Ball)pkm.Ball;
var met = Math.Max(sf.MinLevel, pkm.Met_Level);
EncounterSlot? deferredIV = null;
EncounterSlot8GO? deferredIV = null;
foreach (var s in Slots)
foreach (var slot in Slots)
{
var slot = (EncounterSlot8GO)s;
if (!slot.IsLevelWithinRange(met))
continue;
if (!slot.IsBallValid(ball))

View file

@ -1,5 +1,6 @@
using static PKHeX.Core.EncounterUtil;
using static PKHeX.Core.GameVersion;
using static PKHeX.Core.GroundTilePermission;
namespace PKHeX.Core
{
@ -198,33 +199,33 @@ namespace PKHeX.Core
private static readonly EncounterStatic4[] Encounter_DPPt =
{
// Starters
new(DP) { Gift = true, Species = 387, Level = 5, Location = 076, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Turtwig @ Lake Verity
new(DP) { Gift = true, Species = 390, Level = 5, Location = 076, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Chimchar
new(DP) { Gift = true, Species = 393, Level = 5, Location = 076, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Piplup
new(Pt) { Gift = true, Species = 387, Level = 5, Location = 016, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Turtwig @ Route 201
new(Pt) { Gift = true, Species = 390, Level = 5, Location = 016, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Chimchar
new(Pt) { Gift = true, Species = 393, Level = 5, Location = 016, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Piplup
new(DP) { Gift = true, Species = 387, Level = 5, Location = 076, GroundTile = Max_DP }, // Turtwig @ Lake Verity
new(DP) { Gift = true, Species = 390, Level = 5, Location = 076, GroundTile = Max_DP }, // Chimchar
new(DP) { Gift = true, Species = 393, Level = 5, Location = 076, GroundTile = Max_DP }, // Piplup
new(Pt) { Gift = true, Species = 387, Level = 5, Location = 016, GroundTile = Max_Pt }, // Turtwig @ Route 201
new(Pt) { Gift = true, Species = 390, Level = 5, Location = 016, GroundTile = Max_Pt }, // Chimchar
new(Pt) { Gift = true, Species = 393, Level = 5, Location = 016, GroundTile = Max_Pt }, // Piplup
// Fossil @ Mining Museum
new(DP) { Gift = true, Species = 138, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Omanyte
new(DP) { Gift = true, Species = 140, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Kabuto
new(DP) { Gift = true, Species = 142, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Aerodactyl
new(DP) { Gift = true, Species = 345, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Lileep
new(DP) { Gift = true, Species = 347, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Anorith
new(DP) { Gift = true, Species = 408, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Cranidos
new(DP) { Gift = true, Species = 410, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Shieldon
new(Pt) { Gift = true, Species = 138, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Omanyte
new(Pt) { Gift = true, Species = 140, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Kabuto
new(Pt) { Gift = true, Species = 142, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Aerodactyl
new(Pt) { Gift = true, Species = 345, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Lileep
new(Pt) { Gift = true, Species = 347, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Anorith
new(Pt) { Gift = true, Species = 408, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Cranidos
new(Pt) { Gift = true, Species = 410, Level = 20, Location = 094, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Shieldon
new(DP) { Gift = true, Species = 138, Level = 20, Location = 094, GroundTile = Max_DP }, // Omanyte
new(DP) { Gift = true, Species = 140, Level = 20, Location = 094, GroundTile = Max_DP }, // Kabuto
new(DP) { Gift = true, Species = 142, Level = 20, Location = 094, GroundTile = Max_DP }, // Aerodactyl
new(DP) { Gift = true, Species = 345, Level = 20, Location = 094, GroundTile = Max_DP }, // Lileep
new(DP) { Gift = true, Species = 347, Level = 20, Location = 094, GroundTile = Max_DP }, // Anorith
new(DP) { Gift = true, Species = 408, Level = 20, Location = 094, GroundTile = Max_DP }, // Cranidos
new(DP) { Gift = true, Species = 410, Level = 20, Location = 094, GroundTile = Max_DP }, // Shieldon
new(Pt) { Gift = true, Species = 138, Level = 20, Location = 094, GroundTile = Max_Pt }, // Omanyte
new(Pt) { Gift = true, Species = 140, Level = 20, Location = 094, GroundTile = Max_Pt }, // Kabuto
new(Pt) { Gift = true, Species = 142, Level = 20, Location = 094, GroundTile = Max_Pt }, // Aerodactyl
new(Pt) { Gift = true, Species = 345, Level = 20, Location = 094, GroundTile = Max_Pt }, // Lileep
new(Pt) { Gift = true, Species = 347, Level = 20, Location = 094, GroundTile = Max_Pt }, // Anorith
new(Pt) { Gift = true, Species = 408, Level = 20, Location = 094, GroundTile = Max_Pt }, // Cranidos
new(Pt) { Gift = true, Species = 410, Level = 20, Location = 094, GroundTile = Max_Pt }, // Shieldon
// Gift
new(DP) { Gift = true, Species = 133, Level = 05, Location = 010, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP, }, // Eevee @ Hearthome City
new(Pt) { Gift = true, Species = 133, Level = 20, Location = 010, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Eevee @ Hearthome City
new(Pt) { Gift = true, Species = 137, Level = 25, Location = 012, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Porygon @ Veilstone City
new(DP) { Gift = true, Species = 133, Level = 05, Location = 010, GroundTile = Max_DP, }, // Eevee @ Hearthome City
new(Pt) { Gift = true, Species = 133, Level = 20, Location = 010, GroundTile = Max_Pt, }, // Eevee @ Hearthome City
new(Pt) { Gift = true, Species = 137, Level = 25, Location = 012, GroundTile = Max_Pt, }, // Porygon @ Veilstone City
new(Pt) { Gift = true, Species = 175, Level = 01, EggLocation = 2011 }, // Togepi Egg from Cynthia
new(DP) { Gift = true, Species = 440, Level = 01, EggLocation = 2009 }, // Happiny Egg from Traveling Man
new(DPPt) { Gift = true, Species = 447, Level = 01, EggLocation = 2010, }, // Riolu Egg from Riley
@ -232,95 +233,95 @@ namespace PKHeX.Core
// Stationary
new(DP) { Species = 425, Level = 22, Location = 47, }, // Drifloon @ Valley Windworks
new(Pt) { Species = 425, Level = 15, Location = 47, }, // Drifloon @ Valley Windworks
new(DP) { Species = 479, Level = 15, Location = 70, TypeEncounter = EncounterType.Building_EnigmaStone, }, // Rotom @ Old Chateau
new(Pt) { Species = 479, Level = 20, Location = 70, TypeEncounter = EncounterType.Building_EnigmaStone, }, // Rotom @ Old Chateau
new(DP) { Species = 479, Level = 15, Location = 70, GroundTile = Building, }, // Rotom @ Old Chateau
new(Pt) { Species = 479, Level = 20, Location = 70, GroundTile = Building, }, // Rotom @ Old Chateau
new(DPPt) { Species = 442, Level = 25, Location = 24 }, // Spiritomb @ Route 209
// Stationary Legendary
new(Pt) { Species = 377, Level = 30, Location = 125, TypeEncounter = EncounterType.Cave_HallOfOrigin, }, // Regirock @ Rock Peak Ruins
new(Pt) { Species = 378, Level = 30, Location = 124, TypeEncounter = EncounterType.Cave_HallOfOrigin, }, // Regice @ Iceberg Ruins
new(Pt) { Species = 379, Level = 30, Location = 123, TypeEncounter = EncounterType.Cave_HallOfOrigin, }, // Registeel @ Iron Ruins
new(DPPt) { Species = 480, Level = 50, Location = 089, TypeEncounter = EncounterType.Cave_HallOfOrigin, }, // Uxie @ Acuity Cavern
new(DPPt) { Species = 482, Level = 50, Location = 088, TypeEncounter = EncounterType.Cave_HallOfOrigin, }, // Azelf @ Valor Cavern
new(D ) { Species = 483, Level = 47, Location = 051, TypeEncounter = EncounterType.DialgaPalkia }, // Dialga @ Spear Pillar
new( P) { Species = 484, Level = 47, Location = 051, TypeEncounter = EncounterType.DialgaPalkia }, // Palkia @ Spear Pillar
new(Pt) { Species = 483, Level = 70, Location = 051, TypeEncounter = EncounterType.DialgaPalkia }, // Dialga @ Spear Pillar
new(Pt) { Species = 484, Level = 70, Location = 051, TypeEncounter = EncounterType.DialgaPalkia }, // Palkia @ Spear Pillar
new(DP) { Species = 485, Level = 70, Location = 084, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Heatran @ Stark Mountain
new(Pt) { Species = 485, Level = 50, Location = 084, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Heatran @ Stark Mountain
new(DP) { Species = 486, Level = 70, Location = 064, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Regigigas @ Snowpoint Temple
new(Pt) { Species = 486, Level = 01, Location = 064, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Regigigas @ Snowpoint Temple
new(DP) { Species = 487, Level = 70, Location = 062, TypeEncounter = EncounterType.Cave_HallOfOrigin, Form = 0, }, // Giratina @ Turnback Cave
new(Pt) { Species = 487, Level = 47, Location = 062, TypeEncounter = EncounterType.Cave_HallOfOrigin, Form = 0, }, // Giratina @ Turnback Cave
new(Pt) { Species = 487, Level = 47, Location = 117, TypeEncounter = EncounterType.DistortionWorld_Pt,Form = 1, HeldItem = 112 }, // Giratina @ Distortion World
new(Pt) { Species = 377, Level = 30, Location = 125, GroundTile = Cave, }, // Regirock @ Rock Peak Ruins
new(Pt) { Species = 378, Level = 30, Location = 124, GroundTile = Cave, }, // Regice @ Iceberg Ruins
new(Pt) { Species = 379, Level = 30, Location = 123, GroundTile = Cave, }, // Registeel @ Iron Ruins
new(DPPt) { Species = 480, Level = 50, Location = 089, GroundTile = Cave, }, // Uxie @ Acuity Cavern
new(DPPt) { Species = 482, Level = 50, Location = 088, GroundTile = Cave, }, // Azelf @ Valor Cavern
new(D ) { Species = 483, Level = 47, Location = 051, GroundTile = Rock }, // Dialga @ Spear Pillar
new( P) { Species = 484, Level = 47, Location = 051, GroundTile = Rock }, // Palkia @ Spear Pillar
new(Pt) { Species = 483, Level = 70, Location = 051, GroundTile = Rock }, // Dialga @ Spear Pillar
new(Pt) { Species = 484, Level = 70, Location = 051, GroundTile = Rock }, // Palkia @ Spear Pillar
new(DP) { Species = 485, Level = 70, Location = 084, GroundTile = Cave }, // Heatran @ Stark Mountain
new(Pt) { Species = 485, Level = 50, Location = 084, GroundTile = Cave }, // Heatran @ Stark Mountain
new(DP) { Species = 486, Level = 70, Location = 064, GroundTile = Cave }, // Regigigas @ Snowpoint Temple
new(Pt) { Species = 486, Level = 01, Location = 064, GroundTile = Cave }, // Regigigas @ Snowpoint Temple
new(DP) { Species = 487, Level = 70, Location = 062, GroundTile = Cave, Form = 0, }, // Giratina @ Turnback Cave
new(Pt) { Species = 487, Level = 47, Location = 062, GroundTile = Cave, Form = 0, }, // Giratina @ Turnback Cave
new(Pt) { Species = 487, Level = 47, Location = 117, GroundTile = Distortion,Form = 1, HeldItem = 112 }, // Giratina @ Distortion World
// Event
new(DP) { Species = 491, Level = 40, Location = 079, TypeEncounter = EncounterType.TallGrass }, // Darkrai @ Newmoon Island (Unreleased in Diamond and Pearl)
new(Pt) { Species = 491, Level = 50, Location = 079, TypeEncounter = EncounterType.TallGrass }, // Darkrai @ Newmoon Island
new(DP) { Species = 491, Level = 40, Location = 079, GroundTile = Grass }, // Darkrai @ Newmoon Island (Unreleased in Diamond and Pearl)
new(Pt) { Species = 491, Level = 50, Location = 079, GroundTile = Grass }, // Darkrai @ Newmoon Island
new(Pt) { Species = 492, Form = 0, Level = 30, Location = 063, Fateful = true }, // Shaymin @ Flower Paradise
new(DP) { Species = 492, Form = 0, Level = 30, Location = 063, Fateful = false }, // Shaymin @ Flower Paradise (Unreleased in Diamond and Pearl)
new(DPPt) { Species = 493, Form = 0, Level = 80, Location = 086, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Arceus @ Hall of Origin (Unreleased)
new(DPPt) { Species = 493, Form = 0, Level = 80, Location = 086, GroundTile = Cave }, // Arceus @ Hall of Origin (Unreleased)
// Roamers
new(DPPt) { Roaming = true, Species = 481, Level = 50, TypeEncounter = EncounterType.TallGrass | EncounterType.Surfing_Fishing }, // Mesprit
new(DPPt) { Roaming = true, Species = 488, Level = 50, TypeEncounter = EncounterType.TallGrass | EncounterType.Surfing_Fishing }, // Cresselia
new(Pt) { Roaming = true, Species = 144, Level = 60, TypeEncounter = EncounterType.TallGrass | EncounterType.Surfing_Fishing }, // Articuno
new(Pt) { Roaming = true, Species = 145, Level = 60, TypeEncounter = EncounterType.TallGrass | EncounterType.Surfing_Fishing }, // Zapdos
new(Pt) { Roaming = true, Species = 146, Level = 60, TypeEncounter = EncounterType.TallGrass | EncounterType.Surfing_Fishing }, // Moltres
new(DPPt) { Roaming = true, Species = 481, Level = 50, GroundTile = Grass | Water }, // Mesprit
new(DPPt) { Roaming = true, Species = 488, Level = 50, GroundTile = Grass | Water }, // Cresselia
new(Pt) { Roaming = true, Species = 144, Level = 60, GroundTile = Grass | Water }, // Articuno
new(Pt) { Roaming = true, Species = 145, Level = 60, GroundTile = Grass | Water }, // Zapdos
new(Pt) { Roaming = true, Species = 146, Level = 60, GroundTile = Grass | Water }, // Moltres
};
private static readonly EncounterStatic4[] Encounter_HGSS =
{
// Starters
new(HGSS) { Gift = true, Species = 001, Level = 05, Location = 138, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Bulbasaur @ Pallet Town
new(HGSS) { Gift = true, Species = 004, Level = 05, Location = 138, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Charmander
new(HGSS) { Gift = true, Species = 007, Level = 05, Location = 138, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Squirtle
new(HGSS) { Gift = true, Species = 152, Level = 05, Location = 126, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Chikorita @ New Bark Town
new(HGSS) { Gift = true, Species = 155, Level = 05, Location = 126, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Cyndaquil
new(HGSS) { Gift = true, Species = 158, Level = 05, Location = 126, TypeEncounter = EncounterType.Starter_Fossil_Gift_DP }, // Totodile
new(HGSS) { Gift = true, Species = 252, Level = 05, Location = 148, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Treecko @ Saffron City
new(HGSS) { Gift = true, Species = 255, Level = 05, Location = 148, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Torchic
new(HGSS) { Gift = true, Species = 258, Level = 05, Location = 148, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Mudkip
new(HGSS) { Gift = true, Species = 001, Level = 05, Location = 138, GroundTile = Max_Pt }, // Bulbasaur @ Pallet Town
new(HGSS) { Gift = true, Species = 004, Level = 05, Location = 138, GroundTile = Max_Pt }, // Charmander
new(HGSS) { Gift = true, Species = 007, Level = 05, Location = 138, GroundTile = Max_Pt }, // Squirtle
new(HGSS) { Gift = true, Species = 152, Level = 05, Location = 126, GroundTile = Max_DP }, // Chikorita @ New Bark Town
new(HGSS) { Gift = true, Species = 155, Level = 05, Location = 126, GroundTile = Max_DP }, // Cyndaquil
new(HGSS) { Gift = true, Species = 158, Level = 05, Location = 126, GroundTile = Max_DP }, // Totodile
new(HGSS) { Gift = true, Species = 252, Level = 05, Location = 148, GroundTile = Max_Pt }, // Treecko @ Saffron City
new(HGSS) { Gift = true, Species = 255, Level = 05, Location = 148, GroundTile = Max_Pt }, // Torchic
new(HGSS) { Gift = true, Species = 258, Level = 05, Location = 148, GroundTile = Max_Pt }, // Mudkip
// Fossils @ Pewter City
new(HGSS) { Gift = true, Species = 138, Level = 20, Location = 140, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Omanyte
new(HGSS) { Gift = true, Species = 140, Level = 20, Location = 140, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Kabuto
new(HGSS) { Gift = true, Species = 142, Level = 20, Location = 140, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Aerodactyl
new(HGSS) { Gift = true, Species = 345, Level = 20, Location = 140, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Lileep
new(HGSS) { Gift = true, Species = 347, Level = 20, Location = 140, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Anorith
new(HGSS) { Gift = true, Species = 408, Level = 20, Location = 140, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Cranidos
new(HGSS) { Gift = true, Species = 410, Level = 20, Location = 140, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Shieldon
new(HGSS) { Gift = true, Species = 138, Level = 20, Location = 140, GroundTile = Max_Pt, }, // Omanyte
new(HGSS) { Gift = true, Species = 140, Level = 20, Location = 140, GroundTile = Max_Pt, }, // Kabuto
new(HGSS) { Gift = true, Species = 142, Level = 20, Location = 140, GroundTile = Max_Pt, }, // Aerodactyl
new(HGSS) { Gift = true, Species = 345, Level = 20, Location = 140, GroundTile = Max_Pt, }, // Lileep
new(HGSS) { Gift = true, Species = 347, Level = 20, Location = 140, GroundTile = Max_Pt, }, // Anorith
new(HGSS) { Gift = true, Species = 408, Level = 20, Location = 140, GroundTile = Max_Pt, }, // Cranidos
new(HGSS) { Gift = true, Species = 410, Level = 20, Location = 140, GroundTile = Max_Pt, }, // Shieldon
// Gift
new(HGSS) { Gift = true, Species = 072, Level = 15, Location = 130, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Tentacool @ Cianwood City
new(HGSS) { Gift = true, Species = 133, Level = 05, Location = 131, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Eevee @ Goldenrod City
new(HGSS) { Gift = true, Species = 147, Level = 15, Location = 222, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, Moves = new[] {245} }, // Dratini @ Dragon's Den (ExtremeSpeed)
new(HGSS) { Gift = true, Species = 236, Level = 10, Location = 216, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, }, // Tyrogue @ Mt. Mortar
new(HGSS) { Gift = true, Species = 072, Level = 15, Location = 130, GroundTile = Max_Pt }, // Tentacool @ Cianwood City
new(HGSS) { Gift = true, Species = 133, Level = 05, Location = 131, GroundTile = Max_Pt }, // Eevee @ Goldenrod City
new(HGSS) { Gift = true, Species = 147, Level = 15, Location = 222, GroundTile = Max_Pt, Moves = new[] {245} }, // Dratini @ Dragon's Den (ExtremeSpeed)
new(HGSS) { Gift = true, Species = 236, Level = 10, Location = 216, GroundTile = Max_Pt, }, // Tyrogue @ Mt. Mortar
new(HGSS) { Gift = true, Species = 175, Level = 01, EggLocation = 2013, Moves = new[] {326} }, // Togepi Egg from Mr. Pokemon (Extrasensory as Egg move)
new(HGSS) { Gift = true, Species = 179, Level = 01, EggLocation = 2014, }, // Mareep Egg from Primo
new(HGSS) { Gift = true, Species = 194, Level = 01, EggLocation = 2014, }, // Wooper Egg from Primo
new(HGSS) { Gift = true, Species = 218, Level = 01, EggLocation = 2014, }, // Slugma Egg from Primo
// Celadon City Game Corner
new(HGSS) { Gift = true, Species = 122, Level = 15, Location = 144, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Mr. Mime
new(HGSS) { Gift = true, Species = 133, Level = 15, Location = 144, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Eevee
new(HGSS) { Gift = true, Species = 137, Level = 15, Location = 144, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Porygon
new(HGSS) { Gift = true, Species = 122, Level = 15, Location = 144, GroundTile = Max_Pt }, // Mr. Mime
new(HGSS) { Gift = true, Species = 133, Level = 15, Location = 144, GroundTile = Max_Pt }, // Eevee
new(HGSS) { Gift = true, Species = 137, Level = 15, Location = 144, GroundTile = Max_Pt }, // Porygon
// Goldenrod City Game Corner
new(HGSS) { Gift = true, Species = 063, Level = 15, Location = 131, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Abra
new(HG ) { Gift = true, Species = 023, Level = 15, Location = 131, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Ekans
new( SS) { Gift = true, Species = 027, Level = 15, Location = 131, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Sandshrew
new(HGSS) { Gift = true, Species = 147, Level = 15, Location = 131, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Dratini
new(HGSS) { Gift = true, Species = 063, Level = 15, Location = 131, GroundTile = Max_Pt }, // Abra
new(HG ) { Gift = true, Species = 023, Level = 15, Location = 131, GroundTile = Max_Pt }, // Ekans
new( SS) { Gift = true, Species = 027, Level = 15, Location = 131, GroundTile = Max_Pt }, // Sandshrew
new(HGSS) { Gift = true, Species = 147, Level = 15, Location = 131, GroundTile = Max_Pt }, // Dratini
// Team Rocket HQ Trap Floor
new(HGSS) { Species = 100, Level = 23, Location = 213, TypeEncounter = EncounterType.Building_EnigmaStone, }, // Voltorb
new(HGSS) { Species = 074, Level = 21, Location = 213, TypeEncounter = EncounterType.Building_EnigmaStone, }, // Geodude
new(HGSS) { Species = 109, Level = 21, Location = 213, TypeEncounter = EncounterType.Building_EnigmaStone, }, // Koffing
new(HGSS) { Species = 100, Level = 23, Location = 213, GroundTile = Building, }, // Voltorb
new(HGSS) { Species = 074, Level = 21, Location = 213, GroundTile = Building, }, // Geodude
new(HGSS) { Species = 109, Level = 21, Location = 213, GroundTile = Building, }, // Koffing
// Stationary
new(HGSS) { Species = 130, Level = 30, Location = 135, TypeEncounter = EncounterType.Surfing_Fishing, Shiny = Shiny.Always }, // Gyarados @ Lake of Rage
new(HGSS) { Species = 131, Level = 20, Location = 210, TypeEncounter = EncounterType.Surfing_Fishing, }, // Lapras @ Union Cave Friday Only
new(HGSS) { Species = 101, Level = 23, Location = 213, TypeEncounter = EncounterType.Building_EnigmaStone, }, // Electrode @ Team Rocket HQ
new(HGSS) { Species = 130, Level = 30, Location = 135, GroundTile = Water, Shiny = Shiny.Always }, // Gyarados @ Lake of Rage
new(HGSS) { Species = 131, Level = 20, Location = 210, GroundTile = Water, }, // Lapras @ Union Cave Friday Only
new(HGSS) { Species = 101, Level = 23, Location = 213, GroundTile = Building, }, // Electrode @ Team Rocket HQ
new(HGSS) { Species = 143, Level = 50, Location = 159, }, // Snorlax @ Route 11
new(HGSS) { Species = 143, Level = 50, Location = 160, }, // Snorlax @ Route 12
new(HGSS) { Species = 185, Level = 20, Location = 184, }, // Sudowoodo @ Route 36, Encounter does not have type
@ -334,37 +335,37 @@ namespace PKHeX.Core
Nature = Nature.Naughty,
Location = 214,
Moves = new[] { 344, 270, 207, 220 },
TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio,
GroundTile = Max_Pt,
Shiny = Shiny.Never
},
// Stationary Legendary
new(HGSS) { Species = 144, Level = 50, Location = 203, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Articuno @ Seafoam Islands
new(HGSS) { Species = 144, Level = 50, Location = 203, GroundTile = Cave }, // Articuno @ Seafoam Islands
new(HGSS) { Species = 145, Level = 50, Location = 158, }, // Zapdos @ Route 10
new(HGSS) { Species = 146, Level = 50, Location = 219, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Moltres @ Mt. Silver Cave
new(HGSS) { Species = 150, Level = 70, Location = 199, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Mewtwo @ Cerulean Cave
new(HGSS) { Species = 146, Level = 50, Location = 219, GroundTile = Cave }, // Moltres @ Mt. Silver Cave
new(HGSS) { Species = 150, Level = 70, Location = 199, GroundTile = Cave }, // Mewtwo @ Cerulean Cave
new(HGSS) { Species = 245, Level = 40, Location = 173, }, // Suicune @ Route 25
new(HGSS) { Species = 245, Level = 40, Location = 206, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Suicune @ Burned Tower
new( SS) { Species = 249, Level = 45, Location = 218, TypeEncounter = EncounterType.Surfing_Fishing }, // Lugia @ Whirl Islands
new(HG ) { Species = 249, Level = 70, Location = 218, TypeEncounter = EncounterType.Surfing_Fishing }, // Lugia @ Whirl Islands
new(HG ) { Species = 250, Level = 45, Location = 205, TypeEncounter = EncounterType.Building_EnigmaStone }, // Ho-Oh @ Bell Tower
new( SS) { Species = 250, Level = 70, Location = 205, TypeEncounter = EncounterType.Building_EnigmaStone }, // Ho-Oh @ Bell Tower
new( SS) { Species = 380, Level = 40, Location = 140, TypeEncounter = EncounterType.Building_EnigmaStone }, // Latias @ Pewter City
new(HG ) { Species = 381, Level = 40, Location = 140, TypeEncounter = EncounterType.Building_EnigmaStone }, // Latios @ Pewter City
new(HG ) { Species = 382, Level = 50, Location = 232, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Kyogre @ Embedded Tower
new( SS) { Species = 383, Level = 50, Location = 232, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Groudon @ Embedded Tower
new(HGSS) { Species = 384, Level = 50, Location = 232, TypeEncounter = EncounterType.Cave_HallOfOrigin }, // Rayquaza @ Embedded Tower
new(HGSS) { Species = 483, Level = 01, Location = 231, Gift = true, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Dialga @ Sinjoh Ruins
new(HGSS) { Species = 484, Level = 01, Location = 231, Gift = true, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, // Palkia @ Sinjoh Ruins
new(HGSS) { Species = 487, Level = 01, Location = 231, Gift = true, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, Form = 1, HeldItem = 112 }, // Giratina @ Sinjoh Ruins
new(HGSS) { Species = 245, Level = 40, Location = 206, GroundTile = Cave }, // Suicune @ Burned Tower
new( SS) { Species = 249, Level = 45, Location = 218, GroundTile = Water }, // Lugia @ Whirl Islands
new(HG ) { Species = 249, Level = 70, Location = 218, GroundTile = Water }, // Lugia @ Whirl Islands
new(HG ) { Species = 250, Level = 45, Location = 205, GroundTile = Building }, // Ho-Oh @ Bell Tower
new( SS) { Species = 250, Level = 70, Location = 205, GroundTile = Building }, // Ho-Oh @ Bell Tower
new( SS) { Species = 380, Level = 40, Location = 140, GroundTile = Building }, // Latias @ Pewter City
new(HG ) { Species = 381, Level = 40, Location = 140, GroundTile = Building }, // Latios @ Pewter City
new(HG ) { Species = 382, Level = 50, Location = 232, GroundTile = Cave }, // Kyogre @ Embedded Tower
new( SS) { Species = 383, Level = 50, Location = 232, GroundTile = Cave }, // Groudon @ Embedded Tower
new(HGSS) { Species = 384, Level = 50, Location = 232, GroundTile = Cave }, // Rayquaza @ Embedded Tower
new(HGSS) { Species = 483, Level = 01, Location = 231, Gift = true, GroundTile = Max_Pt }, // Dialga @ Sinjoh Ruins
new(HGSS) { Species = 484, Level = 01, Location = 231, Gift = true, GroundTile = Max_Pt }, // Palkia @ Sinjoh Ruins
new(HGSS) { Species = 487, Level = 01, Location = 231, Gift = true, GroundTile = Max_Pt, Form = 1, HeldItem = 112 }, // Giratina @ Sinjoh Ruins
// Johto Roamers
new(HGSS) { Roaming = true, Species = 243, Level = 40, TypeEncounter = EncounterType.TallGrass | EncounterType.Surfing_Fishing, }, // Raikou
new(HGSS) { Roaming = true, Species = 244, Level = 40, TypeEncounter = EncounterType.TallGrass | EncounterType.Surfing_Fishing, }, // Entei
new(HGSS) { Roaming = true, Species = 243, Level = 40, GroundTile = Grass | Water, }, // Raikou
new(HGSS) { Roaming = true, Species = 244, Level = 40, GroundTile = Grass | Water, }, // Entei
// Kanto Roamers
new(HG ) { Roaming = true, Species = 380, Level = 35, TypeEncounter = EncounterType.TallGrass | EncounterType.Surfing_Fishing, }, // Latias
new( SS) { Roaming = true, Species = 381, Level = 35, TypeEncounter = EncounterType.TallGrass | EncounterType.Surfing_Fishing, }, // Latios
new(HG ) { Roaming = true, Species = 380, Level = 35, GroundTile = Grass | Water, }, // Latias
new( SS) { Roaming = true, Species = 381, Level = 35, GroundTile = Grass | Water, }, // Latios
};
#endregion
#region Trade Tables

View file

@ -4,10 +4,10 @@ namespace PKHeX.Core
/// Encounter Slot found in <see cref="GameVersion.Gen4"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed record EncounterSlot4 : EncounterSlot, IMagnetStatic, INumberedSlot, IEncounterTypeTile
public sealed record EncounterSlot4 : EncounterSlot, IMagnetStatic, INumberedSlot, IGroundTypeTile
{
public override int Generation => 4;
public EncounterType TypeEncounter => ((EncounterArea4)Area).TypeEncounter;
public GroundTilePermission GroundTile => ((EncounterArea4)Area).GroundTile;
public int StaticIndex { get; }
public int MagnetPullIndex { get; }
@ -27,7 +27,7 @@ namespace PKHeX.Core
StaticCount = stc;
}
protected override void SetFormatSpecificData(PKM pk) => ((PK4)pk).EncounterType = TypeEncounter.GetIndex();
protected override void SetFormatSpecificData(PKM pk) => ((PK4)pk).GroundTile = GroundTile.GetIndex();
public override EncounterMatchRating GetMatchRating(PKM pkm)
{

View file

@ -7,20 +7,20 @@ namespace PKHeX.Core
/// <seealso cref="EncounterSlot4"/>
/// <seealso cref="EncounterStatic4"/>
/// </remarks>
public interface IEncounterTypeTile
public interface IGroundTypeTile
{
/// <summary>
/// Tile Type the <see cref="IEncounterable"/> was obtained on.
/// </summary>
EncounterType TypeEncounter { get; }
GroundTilePermission GroundTile { get; }
}
public static class EncounterTypeTileExtensions
public static class GroundTypeTileExtensions
{
/// <summary>
/// Gets if the resulting <see cref="PKM"/> will still have a value depending on the current <see cref="format"/>.
/// </summary>
/// <remarks>Generation 6 no longer stores this value.</remarks>
public static bool HasTypeEncounter(this IEncounterTypeTile _, int format) => format is 4 or 5;
/// <remarks>Generation 7 no longer stores this value.</remarks>
public static bool HasGroundTile(this IGroundTypeTile _, int format) => format is (4 or 5 or 6);
}
}

View file

@ -1,6 +1,6 @@
using System;
using System.Linq;
using static PKHeX.Core.EncounterType;
using static PKHeX.Core.GroundTilePermission;
namespace PKHeX.Core
{
@ -8,15 +8,15 @@ namespace PKHeX.Core
/// Generation 4 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public sealed record EncounterStatic4 : EncounterStatic, IEncounterTypeTile
public sealed record EncounterStatic4 : EncounterStatic, IGroundTypeTile
{
public override int Generation => 4;
/// <summary> Indicates if the encounter is a Roamer (variable met location) </summary>
public bool Roaming { get; init; }
/// <summary> <see cref="PK4.EncounterType"/> values permitted for the encounter. </summary>
public EncounterType TypeEncounter { get; init; } = None;
/// <summary> <see cref="PK4.GroundTile"/> values permitted for the encounter. </summary>
public GroundTilePermission GroundTile { get; init; } = None;
public EncounterStatic4(GameVersion game) : base(game) { }
@ -29,7 +29,7 @@ namespace PKHeX.Core
if (pkm is not G4PKM pk4)
return true;
var locs = GetRoamLocations(Species, pk4.EncounterType);
var locs = GetRoamLocations(Species, pk4.GroundTile);
return locs.Contains(pk4.Met_Location);
}
@ -95,17 +95,17 @@ namespace PKHeX.Core
protected override void SetMetData(PKM pk, int level, DateTime today)
{
var pk4 = (PK4)pk;
var type = pk4.EncounterType = TypeEncounter.GetIndex();
var type = pk4.GroundTile = GroundTile.GetIndex();
pk.Met_Location = Roaming ? GetRoamLocations(Species, type)[0] : Location;
pk.Met_Level = level;
pk.MetDate = today;
}
private static int[] GetRoamLocations(int species, int type) => species switch
private static int[] GetRoamLocations(int species, GroundTileType type) => species switch
{
481 or 488 or 144 or 145 or 146 => 1 << type == (int)TallGrass ? Roaming_MetLocation_DPPt_Grass : Roaming_MetLocation_DPPt_Surf,
243 or 244 => 1 << type == (int)TallGrass ? Roaming_MetLocation_HGSS_Johto_Grass : Roaming_MetLocation_HGSS_Johto_Surf,
380 or 381 => 1 << type == (int)TallGrass ? Roaming_MetLocation_HGSS_Kanto_Grass : Roaming_MetLocation_HGSS_Kanto_Surf,
481 or 488 or 144 or 145 or 146 => type == GroundTileType.Grass ? Roaming_MetLocation_DPPt_Grass : Roaming_MetLocation_DPPt_Surf,
243 or 244 => type == GroundTileType.Grass ? Roaming_MetLocation_HGSS_Johto_Grass : Roaming_MetLocation_HGSS_Johto_Surf,
380 or 381 => type == GroundTileType.Grass ? Roaming_MetLocation_HGSS_Kanto_Grass : Roaming_MetLocation_HGSS_Kanto_Surf,
_ => throw new IndexOutOfRangeException(nameof(species)),
};

View file

@ -22,7 +22,7 @@ namespace PKHeX.Core
{
if (!info.PIDIV.Type.IsCompatible4(z, pkm))
deferredPIDIV.Add(z);
else if (pkm.Format <= 6 && !(z is IEncounterTypeTile t ? t.TypeEncounter.Contains(pkm.EncounterType) : pkm.EncounterType == 0))
else if (pkm is IGroundTile e && !(z is IGroundTypeTile t ? t.GroundTile.Contains(e.GroundTile) : e.GroundTile == 0))
deferredEType.Add(z);
else
yield return z;

View file

@ -24,7 +24,7 @@ namespace PKHeX.Core
public static IEnumerable<EncounterSlot> GetPossible(PKM pkm, IReadOnlyList<DexLevel> chain, GameVersion gameSource = Any)
{
var possibleAreas = GetAreasByGame(pkm, gameSource);
return possibleAreas.SelectMany(area => area.Slots).Where(z => chain.Any(v => v.Species == z.Species));
return possibleAreas.SelectMany(z => z.GetSpecies(chain));
}
private static IEnumerable<EncounterArea> GetAreasByGame(PKM pkm, GameVersion gameSource) => gameSource switch

View file

@ -203,7 +203,7 @@ namespace PKHeX.Core
public int LevelMax { get; }
public int GetSuggestedMetLevel(PKM pkm) => EncounterSuggestion.GetSuggestedMetLevel(pkm, LevelMin);
public int GetSuggestedEncounterType() => Encounter is IEncounterTypeTile t ? t.TypeEncounter.GetIndex() : 0;
public bool HasEncounterType(int format) => Encounter is IEncounterTypeTile t && t.HasTypeEncounter(format);
public GroundTileType GetSuggestedGroundTile() => Encounter is IGroundTypeTile t ? t.GroundTile.GetIndex() : 0;
public bool HasGroundTile(int format) => Encounter is IGroundTypeTile t && t.HasGroundTile(format);
}
}

View file

@ -1,45 +0,0 @@
using System;
namespace PKHeX.Core
{
/// <summary>
/// Tile type the <see cref="PKM"/> was encountered from.
/// </summary>
/// <remarks>
/// Used in Generation 4 games, this value is set depending on what type of overworld tile the player is standing on when the <see cref="PKM"/> is obtained.
/// Some locations have multiple tile types, requiring multiple values possible.
/// </remarks>
[Flags]
public enum EncounterType
{
Undefined = 0,
None = 1 << 00,
RockSmash = 1 << 01,
TallGrass = 1 << 02,
DialgaPalkia = 1 << 04,
Cave_HallOfOrigin = 1 << 05,
Surfing_Fishing = 1 << 07,
Building_EnigmaStone = 1 << 09,
MarshSafari = 1 << 10,
Starter_Fossil_Gift_DP = 1 << 12,
DistortionWorld_Pt = 1 << 23,
Starter_Fossil_Gift_Pt_DPTrio = 1 << 24,
}
public static class EncounterTypeExtension
{
public static bool Contains(this EncounterType g1, int g2) => (g1 & (EncounterType)(1 << g2)) != 0;
public static int GetIndex(this EncounterType g)
{
int val = (int) g;
for (int i = 0; i < 8 * sizeof(EncounterType); i++)
{
val >>= 1;
if (val == 0)
return i;
}
return 0;
}
}
}

View file

@ -0,0 +1,68 @@
using System;
namespace PKHeX.Core
{
/// <summary>
/// Permitted <see cref="GroundTileType"/> values an encounter can be acquired with.
/// </summary>
/// <remarks>
/// Some locations have multiple tile types that can proc an encounter, requiring multiple values possible.
/// </remarks>
[Flags]
public enum GroundTilePermission
{
Undefined = 0,
None = 1 << 00, // No animation for the tile
Sand = 1 << 01, // Obtainable only via HG/SS
Grass = 1 << 02,
Puddle = 1 << 03, // No encounters from this tile type
Rock = 1 << 04,
Cave = 1 << 05,
Snow = 1 << 06, // No encounters from this tile type
Water = 1 << 07,
Ice = 1 << 08, // No encounters from this tile type
Building = 1 << 09,
Marsh = 1 << 10,
Bridge = 1 << 11, // No encounters from this tile type
Max_DP = 1 << 12, // Unspecific, catch-all for DP undefined tiles.
// added tile types in Pt
// no encounters from these tile types
Elite4_1 = 1 << 12, // Elite Four Room #1
Elite4_2 = 1 << 13, // Elite Four Room #2
Elite4_3 = 1 << 14, // Elite Four Room #3
Elite4_4 = 1 << 15, // Elite Four Room #4
Elite4_M = 1 << 16, // Elite Four Champion Room
DistortionSideways = 1 << 17, // Distortion World (Not Giratina)
BattleTower = 1 << 18,
BattleFactory = 1 << 19,
BattleArcade = 1 << 20,
BattleCastle = 1 << 21,
BattleHall = 1 << 22,
Distortion = 1 << 23,
Max_Pt = 1 << 24, // Unspecific, catch-all for Pt undefined tiles.
}
public static class GroundTilePermissionExtensions
{
public static bool Contains(this GroundTilePermission g1, GroundTileType g2) => (g1 & (GroundTilePermission)(1 << (int)g2)) != 0;
/// <summary>
/// Grabs the highest set bit from the tile value.
/// </summary>
/// <param name="g">Tile bit-permission value</param>
/// <returns>Bit index</returns>
public static GroundTileType GetIndex(this GroundTilePermission g)
{
int val = (int) g;
for (byte i = 0; i < 8 * sizeof(GroundTilePermission); i++)
{
val >>= 1;
if (val == 0)
return (GroundTileType)i;
}
return 0;
}
}
}

View file

@ -6,7 +6,7 @@ namespace PKHeX.Core
/// Wild Encounter data <see cref="EncounterSlot"/> Type
/// </summary>
/// <remarks>
/// Different from <see cref="EncounterType"/>, this corresponds to the method that the <see cref="IEncounterable"/> may be encountered.</remarks>
/// Different from <see cref="GroundTilePermission"/>, this corresponds to the method that the <see cref="IEncounterable"/> may be encountered.</remarks>
[Flags]
#pragma warning disable RCS1191 // Declare enum value as combination of names.
public enum SlotType : byte

View file

@ -297,7 +297,7 @@ namespace PKHeX.Core
var format = pkm.Format;
if (format is 4 or 5 or 6)
Gen4EncounterType.Verify(this); // Gen 6->7 transfer deletes encounter type data
Gen4GroundTile.Verify(this); // Gen 6->7 transfer deletes encounter type data
if (format < 6)
return;

View file

@ -16,7 +16,7 @@
public static readonly MedalVerifier Medal = new();
public static readonly RibbonVerifier Ribbon = new();
public static readonly ItemVerifier Item = new();
public static readonly EncounterTypeVerifier Gen4EncounterType = new();
public static readonly GroundTileVerifier Gen4GroundTile = new();
public static readonly HyperTrainingVerifier HyperTraining = new();
public static readonly GenderVerifier GenderValues = new();
public static readonly PIDVerifier PIDEC = new();

View file

@ -878,9 +878,9 @@ namespace PKHeX.Core
return true;
if (val != ChainShiny)
return false;
// Chain shiny with poke radar is only possible in DPPt in tall grass, safari zone do not allow pokeradar
// TypeEncounter TallGrass discard any cave or city
return pkm.IsShiny && !pkm.HGSS && sl.TypeEncounter == EncounterType.TallGrass && !Locations.IsSafariZoneLocation4(sl.Location);
// Chain shiny with poke radar is only possible in DPPt in grass, safari zone does not allow pokeradar
// TypeEncounter Grass discard any cave or city
return pkm.IsShiny && !pkm.HGSS && sl.GroundTile == GroundTilePermission.Grass && !Locations.IsSafariZoneLocation4(sl.Location);
case PGT: // manaphy
return IsG4ManaphyPIDValid(val, pkm);
case PCD d when d.Gift.PK.PID != 1:

View file

@ -1,19 +0,0 @@
using static PKHeX.Core.LegalityCheckStrings;
namespace PKHeX.Core
{
/// <summary>
/// Verifies the <see cref="PK4.EncounterType"/>.
/// </summary>
public sealed class EncounterTypeVerifier : Verifier
{
protected override CheckIdentifier Identifier => CheckIdentifier.Encounter;
public override void Verify(LegalityAnalysis data)
{
var type = data.EncounterMatch is IEncounterTypeTile t ? t.TypeEncounter : EncounterType.None;
var result = !type.Contains(data.pkm.EncounterType) ? GetInvalid(LEncTypeMismatch) : GetValid(LEncTypeMatch);
data.AddLine(result);
}
}
}

View file

@ -0,0 +1,21 @@
using static PKHeX.Core.LegalityCheckStrings;
namespace PKHeX.Core
{
/// <summary>
/// Verifies the <see cref="PK4.GroundTile"/>.
/// </summary>
public sealed class GroundTileVerifier : Verifier
{
protected override CheckIdentifier Identifier => CheckIdentifier.Encounter;
public override void Verify(LegalityAnalysis data)
{
if (data.pkm is not IGroundTile e)
return;
var type = data.EncounterMatch is IGroundTypeTile t ? t.GroundTile : GroundTilePermission.None;
var result = !type.Contains(e.GroundTile) ? GetInvalid(LEncTypeMismatch) : GetValid(LEncTypeMatch);
data.AddLine(result);
}
}
}

View file

@ -157,7 +157,7 @@ namespace PKHeX.Core
private static bool GetCanBeCaptured(int species, IEnumerable<EncounterArea> area, IEnumerable<EncounterStatic> statics)
{
if (area.Any(loc => loc.Slots.Any(slot => slot.Species == species)))
if (area.Any(loc => loc.HasSpecies(species)))
return true;
if (statics.Any(enc => enc.Species == species && !enc.Gift))
return true;

View file

@ -39,7 +39,7 @@ namespace PKHeX.Core
if (pkm.Format <= 7 && pkm.IsNicknamed) // can nickname afterwards
{
if (pkm.VC)
VerifyG1NicknameWithinBounds(data, nickname);
VerifyG1NicknameWithinBounds(data, nickname.AsSpan());
else if (enc is MysteryGift {IsEgg: false})
data.AddLine(Get(LEncGiftNicknamed, ParseSettings.NicknamedMysteryGift));
}
@ -264,7 +264,7 @@ namespace PKHeX.Core
}
}
private void VerifyG1NicknameWithinBounds(LegalityAnalysis data, string str)
private void VerifyG1NicknameWithinBounds(LegalityAnalysis data, ReadOnlySpan<char> str)
{
var pkm = data.pkm;
if (StringConverter12.GetIsG1English(str))

View file

@ -1,4 +1,4 @@
using System.Linq;
using System;
using static PKHeX.Core.LegalityCheckStrings;
namespace PKHeX.Core
@ -118,7 +118,7 @@ namespace PKHeX.Core
}
}
VerifyG1OTWithinBounds(data, tr);
VerifyG1OTWithinBounds(data, tr.AsSpan());
if (pkm.OT_Gender == 1)
{
@ -127,7 +127,7 @@ namespace PKHeX.Core
}
}
private void VerifyG1OTWithinBounds(LegalityAnalysis data, string str)
private void VerifyG1OTWithinBounds(LegalityAnalysis data, ReadOnlySpan<char> str)
{
if (StringConverter12.GetIsG1English(str))
{
@ -152,7 +152,12 @@ namespace PKHeX.Core
private static bool IsOTNameSuspicious(string name)
{
return SuspiciousOTNames.Any(name.StartsWith);
foreach (var s in SuspiciousOTNames)
{
if (s.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
return true;
}
return false;
}
public static bool IsOTIDSuspicious(int tid16, int sid16)
@ -187,7 +192,13 @@ namespace PKHeX.Core
return (uint)(c - '0') <= 9;
}
return str.Count(IsNumber);
int ctr = 0;
foreach (var c in str)
{
if (IsNumber(c))
++ctr;
}
return ctr;
}
}
}

View file

@ -331,7 +331,7 @@ namespace PKHeX.Core
public override int Met_Level { get => Data[0x84] >> 1; set => Data[0x84] = (byte)((Data[0x84] & 0x1) | value << 1); }
public override int OT_Gender { get => Data[0x84] & 1; set => Data[0x84] = (byte)((Data[0x84] & ~0x1) | (value & 1)); }
public override int EncounterType { get => Data[0x85]; set => Data[0x85] = (byte)value; }
public override GroundTileType GroundTile { get => (GroundTileType)Data[0x85]; set => Data[0x85] = (byte)value; }
// Unused 0x87
#endregion

View file

@ -29,8 +29,8 @@ namespace PKHeX.Core
private static byte[] SetString(string value, int maxLength) => StringConverter3.SetBEString3(value, maxLength);
// Trash Bytes
public override byte[] Nickname_Trash { get => GetData(0x2E, 20); set { if (value.Length == 20) value.CopyTo(Data, 0x2E); } }
public override byte[] OT_Trash { get => GetData(0x18, 20); set { if (value.Length == 20) value.CopyTo(Data, 0x18); } }
public override Span<byte> Nickname_Trash { get => Data.AsSpan(0x2E, 20); set { if (value.Length == 20) value.CopyTo(Data.AsSpan(0x2E)); } }
public override Span<byte> OT_Trash { get => Data.AsSpan(0x18, 20); set { if (value.Length == 20) value.CopyTo(Data.AsSpan(0x18)); } }
// Future Attributes

View file

@ -43,8 +43,8 @@ namespace PKHeX.Core
private const string EggNameJapanese = "タマゴ";
// Trash Bytes
public override byte[] Nickname_Trash { get => GetData(0x08, 10); set { if (value.Length == 10) value.CopyTo(Data, 0x08); } }
public override byte[] OT_Trash { get => GetData(0x14, 7); set { if (value.Length == 7) value.CopyTo(Data, 0x14); } }
public override Span<byte> Nickname_Trash { get => Data.AsSpan(0x08, 10); set { if (value.Length == 10) value.CopyTo(Data.AsSpan(0x08)); } }
public override Span<byte> OT_Trash { get => Data.AsSpan(0x14, 7); set { if (value.Length == 7) value.CopyTo(Data.AsSpan(0x14)); } }
// At top for System.Reflection execution order hack

View file

@ -310,8 +310,8 @@ namespace PKHeX.Core
public override int Met_Level { get => Data[0x84] & ~0x80; set => Data[0x84] = (byte)((Data[0x84] & 0x80) | value); }
public override int OT_Gender { get => Data[0x84] >> 7; set => Data[0x84] = (byte)((Data[0x84] & ~0x80) | value << 7); }
public override int EncounterType { get => Data[0x85]; set => Data[0x85] = (byte)value; }
public int PokéathlonStat { get => Data[0x87]; set => Data[0x87] = (byte)value; }
public override GroundTileType GroundTile { get => (GroundTileType)Data[0x85]; set => Data[0x85] = (byte)value; }
public byte PokéathlonStat { get => Data[0x87]; set => Data[0x87] = value; }
// Unused 0x87
#endregion

View file

@ -4,7 +4,9 @@ using System.Collections.Generic;
namespace PKHeX.Core
{
/// <summary> Generation 5 <see cref="PKM"/> format. </summary>
public sealed class PK5 : PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4, IContestStats, IContestStatsMutable
public sealed class PK5 : PKM,
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4,
IContestStats, IContestStatsMutable, IGroundTile
{
private static readonly ushort[] Unused =
{
@ -39,8 +41,8 @@ namespace PKHeX.Core
private static byte[] SetString(string value, int maxLength) => StringConverter.SetString5(value, maxLength);
// Trash Bytes
public override byte[] Nickname_Trash { get => GetData(0x48, 22); set { if (value.Length == 22) value.CopyTo(Data, 0x48); } }
public override byte[] OT_Trash { get => GetData(0x68, 16); set { if (value.Length == 16) value.CopyTo(Data, 0x68); } }
public override Span<byte> Nickname_Trash { get => Data.AsSpan(0x48, 22); set { if (value.Length == 22) value.CopyTo(Data.AsSpan(0x48)); } }
public override Span<byte> OT_Trash { get => Data.AsSpan(0x68, 16); set { if (value.Length == 16) value.CopyTo(Data.AsSpan(0x68)); } }
// Future Attributes
public override uint EncryptionConstant { get => PID; set { } }
@ -242,7 +244,7 @@ namespace PKHeX.Core
public override int Ball { get => Data[0x83]; set => Data[0x83] = (byte)value; }
public override int Met_Level { get => Data[0x84] & ~0x80; set => Data[0x84] = (byte)((Data[0x84] & 0x80) | value); }
public override int OT_Gender { get => Data[0x84] >> 7; set => Data[0x84] = (byte)((Data[0x84] & ~0x80) | value << 7); }
public override int EncounterType { get => Data[0x85]; set => Data[0x85] = (byte)value; }
public GroundTileType GroundTile { get => (GroundTileType)Data[0x85]; set => Data[0x85] = (byte)value; }
// 0x86 Unused
public byte PokeStarFame { get => Data[0x87]; set => Data[0x87] = value; }
public bool IsPokeStar { get => PokeStarFame > 250; set => PokeStarFame = value ? (byte)255 : (byte)0; }
@ -394,7 +396,7 @@ namespace PKHeX.Core
// OT Gender & Encounter Level
Met_Level = Met_Level,
OT_Gender = OT_Gender,
EncounterType = EncounterType,
GroundTile = GroundTile,
// Fill the Ribbon Counter Bytes
RibbonCountMemoryContest = CountContestRibbons(),

View file

@ -5,7 +5,7 @@ namespace PKHeX.Core
{
/// <summary> Generation 6 <see cref="PKM"/> format. </summary>
public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6,
IContestStats, IContestStatsMutable, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection
IContestStats, IContestStatsMutable, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection, IGroundTile
{
private static readonly ushort[] Unused =
{
@ -343,7 +343,7 @@ namespace PKHeX.Core
public override int Ball { get => Data[0xDC]; set => Data[0xDC] = (byte)value; }
public override int Met_Level { get => Data[0xDD] & ~0x80; set => Data[0xDD] = (byte)((Data[0xDD] & 0x80) | value); }
public override int OT_Gender { get => Data[0xDD] >> 7; set => Data[0xDD] = (byte)((Data[0xDD] & ~0x80) | (value << 7)); }
public override int EncounterType { get => Data[0xDE]; set => Data[0xDE] = (byte)value; }
public GroundTileType GroundTile { get => (GroundTileType)Data[0xDE]; set => Data[0xDE] = (byte)value; }
public override int Version { get => Data[0xDF]; set => Data[0xDF] = (byte)value; }
public int Country { get => Data[0xE0]; set => Data[0xE0] = (byte)value; }
public int Region { get => Data[0xE1]; set => Data[0xE1] = (byte)value; }

View file

@ -66,9 +66,9 @@ namespace PKHeX.Core
public override int SIZE_STORED => PokeCrypto.SIZE_8STORED;
// Trash Bytes
public override byte[] Nickname_Trash { get => GetData(0x58, 24); set { if (value.Length == 24) value.CopyTo(Data, 0x58); } }
public override byte[] HT_Trash { get => GetData(0xA8, 24); set { if (value.Length == 24) value.CopyTo(Data, 0xA8); } }
public override byte[] OT_Trash { get => GetData(0xF8, 24); set { if (value.Length == 24) value.CopyTo(Data, 0xF8); } }
public override Span<byte> Nickname_Trash { get => Data.AsSpan(0x58, 24); set { if (value.Length == 24) value.CopyTo(Data.AsSpan(0x58)); } }
public override Span<byte> HT_Trash { get => Data.AsSpan(0xA8, 24); set { if (value.Length == 24) value.CopyTo(Data.AsSpan(0xA8)); } }
public override Span<byte> OT_Trash { get => Data.AsSpan(0xF8, 24); set { if (value.Length == 24) value.CopyTo(Data.AsSpan(0xF8)); } }
// Maximums
public override int MaxIV => 31;

View file

@ -31,11 +31,9 @@ namespace PKHeX.Core
public virtual bool Valid { get => ChecksumValid && Sanity == 0; set { if (!value) return; Sanity = 0; RefreshChecksum(); } }
// Trash Bytes
public abstract byte[] Nickname_Trash { get; set; }
public abstract byte[] OT_Trash { get; set; }
public virtual byte[] HT_Trash { get => Array.Empty<byte>(); set { } }
protected byte[] GetData(int Offset, int Length) => Data.Slice(Offset, Length);
public abstract Span<byte> Nickname_Trash { get; set; }
public abstract Span<byte> OT_Trash { get; set; }
public virtual Span<byte> HT_Trash { get => Span<byte>.Empty; set { } }
protected virtual ushort CalculateChecksum() => PokeCrypto.GetCHK(Data, SIZE_STORED);
@ -223,7 +221,6 @@ namespace PKHeX.Core
public virtual int RelearnMove2 { get => 0; set { } }
public virtual int RelearnMove3 { get => 0; set { } }
public virtual int RelearnMove4 { get => 0; set { } }
public virtual int EncounterType { get => 0; set { } }
// Exposed but not Present in all
public abstract int CurrentHandler { get; set; }
@ -293,7 +290,6 @@ namespace PKHeX.Core
public bool LGPE => Version is (int)GP or (int)GE;
public bool SWSH => Version is (int)SW or (int)SH;
protected internal bool PtHGSS => Pt || HGSS;
public bool GO_LGPE => GO && Met_Location == Locations.GO7;
public bool GO_HOME => GO && Met_Location == Locations.GO8;
public bool VC => VC1 || VC2;

View file

@ -106,8 +106,8 @@ namespace PKHeX.Core
}
}
public override byte[] Nickname_Trash { get => GetData(0x24, 12); set { if (value.Length == 12) value.CopyTo(Data, 0x24); } }
public override byte[] OT_Trash { get => GetData(0x30, 12); set { if (value.Length == 12) value.CopyTo(Data, 0x30); } }
public override Span<byte> Nickname_Trash { get => Data.AsSpan(0x24, 12); set { if (value.Length == 12) value.CopyTo(Data.AsSpan(0x24)); } }
public override Span<byte> OT_Trash { get => Data.AsSpan(0x30, 12); set { if (value.Length == 12) value.CopyTo(Data.AsSpan(0x30)); } }
#endregion
#region Party Attributes
@ -186,24 +186,32 @@ namespace PKHeX.Core
};
}
private static bool IsJapanese(byte[] data)
private static bool IsJapanese(ReadOnlySpan<byte> data)
{
if (!StringConverter12.GetIsG1Japanese(data, 0x24, StringLength))
if (!StringConverter12.GetIsG1Japanese(data.Slice(0x30, StringLength)))
return false;
if (!StringConverter12.GetIsG1Japanese(data, 0x30, StringLength))
if (!StringConverter12.GetIsG1Japanese(data.Slice(0x24, StringLength)))
return false;
for (int i = 6; i < 0xC; i++)
{
if (data[0x24 + i] is not (0 or StringConverter12.G1TerminatorCode))
return false;
if (data[0x30 + i] is not (0 or StringConverter12.G1TerminatorCode))
return false;
if (data[0x24 + i] is not (0 or StringConverter12.G1TerminatorCode))
return false;
}
return true;
}
private static bool IsEnglish(byte[] data) => StringConverter12.GetIsG1English(data, 0x24, StringLength) && StringConverter12.GetIsG1English(data, 0x30, StringLength);
private static bool IsEnglish(ReadOnlySpan<byte> data)
{
if (!StringConverter12.GetIsG1English(data.Slice(0x30, StringLength)))
return false;
if (!StringConverter12.GetIsG1English(data.Slice(0x24, StringLength)))
return false;
return true;
}
public bool IsPossible(bool japanese) => japanese ? IsJapanese(Data) : IsEnglish(Data);
public void SwapLanguage() => IsEncodingJapanese ^= true;
}

View file

@ -1,6 +1,10 @@
namespace PKHeX.Core
using System;
namespace PKHeX.Core
{
public abstract class G4PKM : PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4, IContestStats, IContestStatsMutable
public abstract class G4PKM : PKM,
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4,
IContestStats, IContestStatsMutable, IGroundTile
{
protected G4PKM(byte[] data) : base(data) { }
protected G4PKM(int size) : base(size) { }
@ -20,6 +24,8 @@
public sealed override int PSV => (int)((PID >> 16 ^ (PID & 0xFFFF)) >> 3);
public sealed override int TSV => (TID ^ SID) >> 3;
protected bool PtHGSS => Pt || HGSS;
public sealed override int Characteristic
{
get
@ -38,8 +44,8 @@
}
// Trash Bytes
public sealed override byte[] Nickname_Trash { get => GetData(0x48, 22); set { if (value.Length == 22) value.CopyTo(Data, 0x48); } }
public sealed override byte[] OT_Trash { get => GetData(0x68, 16); set { if (value.Length == 16) value.CopyTo(Data, 0x68); } }
public sealed override Span<byte> Nickname_Trash { get => Data.AsSpan(0x48, 22); set { if (value.Length == 22) value.CopyTo(Data.AsSpan(0x48)); } }
public sealed override Span<byte> OT_Trash { get => Data.AsSpan(0x68, 16); set { if (value.Length == 16) value.CopyTo(Data.AsSpan(0x68)); } }
// Future Attributes
public sealed override uint EncryptionConstant { get => PID; set { } }
@ -158,6 +164,8 @@
public abstract byte CNT_Tough { get; set; }
public abstract byte CNT_Sheen { get; set; }
public abstract GroundTileType GroundTile { get; set; }
protected T ConvertTo<T>() where T : G4PKM, new()
{
var pk = new T
@ -215,7 +223,7 @@
PKRS_Days = PKRS_Days,
PKRS_Strain = PKRS_Strain,
Ball = Ball,
EncounterType = EncounterType,
GroundTile = GroundTile,
FatefulEncounter = FatefulEncounter,
Met_Level = Met_Level,

View file

@ -11,9 +11,9 @@ namespace PKHeX.Core
protected G6PKM(int size) : base(size) { }
// Trash Bytes
public sealed override byte[] Nickname_Trash { get => GetData(0x40, 24); set { if (value.Length == 24) value.CopyTo(Data, 0x40); } }
public sealed override byte[] HT_Trash { get => GetData(0x78, 24); set { if (value.Length == 24) value.CopyTo(Data, 0x78); } }
public sealed override byte[] OT_Trash { get => GetData(0xB0, 24); set { if (value.Length == 24) value.CopyTo(Data, 0xB0); } }
public sealed override Span<byte> Nickname_Trash { get => Data.AsSpan(0x40, 24); set { if (value.Length == 24) value.CopyTo(Data.AsSpan(0x40)); } }
public sealed override Span<byte> HT_Trash { get => Data.AsSpan(0x78, 24); set { if (value.Length == 24) value.CopyTo(Data.AsSpan(0x78)); } }
public sealed override Span<byte> OT_Trash { get => Data.AsSpan(0xB0, 24); set { if (value.Length == 24) value.CopyTo(Data.AsSpan(0xB0)); } }
protected sealed override ushort CalculateChecksum()
{

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace PKHeX.Core
{

View file

@ -18,8 +18,8 @@ namespace PKHeX.Core
internal readonly byte[] RawNickname;
// Trash Bytes
public sealed override byte[] Nickname_Trash { get => RawNickname; set { if (value.Length == RawNickname.Length) value.CopyTo(RawNickname, 0); } }
public sealed override byte[] OT_Trash { get => RawOT; set { if (value.Length == RawOT.Length) value.CopyTo(RawOT, 0); } }
public sealed override Span<byte> Nickname_Trash { get => RawNickname; set { if (value.Length == RawNickname.Length) value.CopyTo(RawNickname); } }
public sealed override Span<byte> OT_Trash { get => RawOT; set { if (value.Length == RawOT.Length) value.CopyTo(RawOT); } }
protected GBPKML(int size, bool jp = false) : base(size)
{

View file

@ -0,0 +1,47 @@
namespace PKHeX.Core
{
/// <summary>
/// Ground Tile Type the <see cref="PKM"/> was encountered from.
/// </summary>
/// <remarks>
/// Used in Generation 4 games, this value is set depending on what type of overworld tile the player is standing on when the <see cref="PKM"/> is obtained.
/// </remarks>
public enum GroundTileType : byte
{
None = 00, // No animation for the tile
Sand = 01, // Obtainable only via HG/SS
Grass = 02,
Puddle = 03, // No encounters from this tile type
Rock = 04,
Cave = 05,
Snow = 06, // No encounters from this tile type
Water = 07,
Ice = 08, // No encounters from this tile type
Building = 09,
Marsh = 10,
Bridge = 11, // No encounters from this tile type
Max_DP = 12, // Unspecific, catch-all for DP undefined tiles.
// added tile types in Pt
// no encounters from these tile types
Elite4_1 = 12, // Elite Four Room #1
Elite4_2 = 13, // Elite Four Room #2
Elite4_3 = 14, // Elite Four Room #3
Elite4_4 = 15, // Elite Four Room #4
Elite4_M = 16, // Elite Four Champion Room
DistortionSideways = 17, // Distortion World (Not Giratina)
BattleTower = 18,
BattleFactory = 19,
BattleArcade = 20,
BattleCastle = 21,
BattleHall = 22,
Distortion = 23,
Max_Pt = 24, // Unspecific, catch-all for Pt undefined tiles.
}
public static class GroundTileTypeExtensions
{
public static bool IsObtainable(this GroundTileType type) => ((0b_1_10000000_00010110_10110111 >> (int) type) & 1) == 1;
}
}

View file

@ -0,0 +1,13 @@
namespace PKHeX.Core
{
/// <summary>
/// Indicates the Type of Encounter Tile the Pokémon was encountered on.
/// </summary>
public interface IGroundTile
{
/// <summary>
/// Type of Encounter Tile the Pokémon was encountered on.
/// </summary>
GroundTileType GroundTile { get; set; }
}
}

View file

@ -149,9 +149,11 @@ namespace PKHeX.Core
int pkOfs = GetOffsetPKMData(base_ofs, i);
int otOfs = GetOffsetPKMOT(base_ofs, i);
int nkOfs = GetOffsetPKMNickname(base_ofs, i);
Array.Copy(Pokemon[i].Data, 0, Data, pkOfs, Entry_Size);
Array.Copy(Pokemon[i].OT_Trash, 0, Data, otOfs, StringLength);
Array.Copy(Pokemon[i].Nickname_Trash, 0, Data, nkOfs, StringLength);
var pk = Pokemon[i];
Array.Copy(pk.Data, 0, Data, pkOfs, Entry_Size);
pk.RawOT.CopyTo(Data, otOfs);
pk.RawNickname.CopyTo(Data, nkOfs);
}
}
}

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PKHeX.Core
@ -10,18 +9,25 @@ namespace PKHeX.Core
/// </summary>
public static class StringConverter12
{
public static bool GetIsG1Japanese(string str) => AllCharsInDictionary(str, U2RBY_J);
public static bool GetIsG1English(string str) => AllCharsInDictionary(str, U2RBY_U);
public static bool GetIsG1Japanese(byte[] data, int start, int length) => AllCharsInDictionary(data, start, length, RBY2U_J);
public static bool GetIsG1English(byte[] data, int start, int length) => AllCharsInDictionary(data, start, length, RBY2U_U);
public static bool GetIsG1Japanese(ReadOnlySpan<char> str) => AllCharsInDictionary(str, U2RBY_J);
public static bool GetIsG1English(ReadOnlySpan<char> str) => AllCharsInDictionary(str, U2RBY_U);
public static bool GetIsG1Japanese(ReadOnlySpan<byte> raw) => AllCharsInDictionary(raw, RBY2U_J);
public static bool GetIsG1English(ReadOnlySpan<byte> raw) => AllCharsInDictionary(raw, RBY2U_U);
private static bool AllCharsInDictionary(IEnumerable<char> c, IReadOnlyDictionary<char, byte> d) => c.All(d.ContainsKey);
private static bool AllCharsInDictionary(IReadOnlyList<byte> data, int start, int length, IReadOnlyDictionary<byte, char> d)
private static bool AllCharsInDictionary(ReadOnlySpan<char> c, IReadOnlyDictionary<char, byte> d)
{
for (int i = start; i < start + length; i++)
foreach (var x in c)
{
if (!d.ContainsKey(x))
return false;
}
return true;
}
private static bool AllCharsInDictionary(ReadOnlySpan<byte> data, IReadOnlyDictionary<byte, char> d)
{
foreach (var c in data)
{
var c = data[i];
if (c == 0)
break;
if (!d.ContainsKey(c))
@ -54,7 +60,15 @@ namespace PKHeX.Core
/// </summary>
/// <param name="data">Raw string bytes</param>
/// <returns>Indication if the data is from a definitely-german string</returns>
public static bool IsG12German(IEnumerable<byte> data) => data.Any(z => z is >= 0xC0 and <= 0xC6);
public static bool IsG12German(ReadOnlySpan<byte> data)
{
foreach (var b in data)
{
if (b is >= 0xC0 and <= 0xC6)
return true;
}
return false;
}
/// <summary>
/// Checks if the input byte array is definitely of German origin (any ÄÖÜäöü)
@ -71,14 +85,21 @@ namespace PKHeX.Core
/// <param name="count"></param>
/// <param name="jp">Data source is Japanese.</param>
/// <returns>Decoded string.</returns>
public static string GetString1(byte[] data, int offset, int count, bool jp)
public static string GetString1(byte[] data, int offset, int count, bool jp) => GetString1(data.AsSpan(offset, count), jp);
/// <summary>
/// Converts Generation 1 encoded data into a string.
/// </summary>
/// <param name="data">Encoded data.</param>
/// <param name="jp">Data source is Japanese.</param>
/// <returns>Decoded string.</returns>
public static string GetString1(ReadOnlySpan<byte> data, bool jp)
{
var dict = jp ? RBY2U_J : RBY2U_U;
var s = new StringBuilder(count);
for (int i = 0; i < count; i++)
var s = new StringBuilder(data.Length);
foreach (var val in data)
{
var val = data[offset + i];
if (!dict.TryGetValue(val, out var c)) // Take valid values
break;
if (c == G1Terminator) // Stop if Terminator
@ -127,12 +148,12 @@ namespace PKHeX.Core
/// <param name="key">Encoded character.</param>
/// <param name="jp">Data source is Japanese.</param>
/// <returns>Decoded string.</returns>
public static string GetG1Char(byte key, bool jp)
public static char GetG1Char(byte key, bool jp)
{
var dict = jp ? RBY2U_J : RBY2U_U;
if (dict.TryGetValue(key, out var val))
return val.ToString();
return string.Empty;
return val;
return G1Terminator;
}
#region Gen 1/2 Character Tables

View file

@ -15,7 +15,16 @@ namespace PKHeX.Core
/// <summary>
/// Checks if any of the characters inside <see cref="str"/> are from the special Korean codepoint pages.
/// </summary>
public static bool GetIsG2Korean(string str) => str.All(z => U2GSC_KOR.Any(x => x.ContainsKey(z)));
public static bool GetIsG2Korean(ReadOnlySpan<char> str)
{
var dict = U2GSC_KOR;
foreach (var c in str)
{
if (!dict.Any(d => d.ContainsKey(c)))
return false;
}
return true;
}
/// <summary>
/// Converts Generation 2 Korean encoded data into a string.

View file

@ -20,12 +20,19 @@ namespace PKHeX.Core
/// <param name="count">Length of data to read.</param>
/// <param name="jp">Value source is Japanese font.</param>
/// <returns>Decoded string.</returns>
public static string GetString3(byte[] data, int offset, int count, bool jp)
public static string GetString3(byte[] data, int offset, int count, bool jp) => GetString3(data.AsSpan(offset, count), jp);
/// <summary>
/// Converts a Generation 3 encoded value array to string.
/// </summary>
/// <param name="data">Byte array containing string data.</param>
/// <param name="jp">Value source is Japanese font.</param>
/// <returns>Decoded string.</returns>
public static string GetString3(ReadOnlySpan<byte> data, bool jp)
{
var s = new StringBuilder(count);
for (int i = 0; i < count; i++)
var s = new StringBuilder(data.Length);
foreach (var val in data)
{
var val = data[offset + i];
var c = GetG3Char(val, jp); // Convert to Unicode
if (c == Terminator) // Stop if Terminator/Invalid
break;

View file

@ -160,7 +160,8 @@ namespace PKHeX.Core
if (pk.HeldItem > Legal.MaxItemID_6_AO)
return true;
int et = pk.EncounterType;
// Ground Tile property is replaced with Hyper Training PK6->PK7
var et = pk.GroundTile;
if (et != 0)
{
if (pk.CurrentLevel < 100) // can't be hyper trained
@ -168,7 +169,7 @@ namespace PKHeX.Core
if (!pk.Gen4) // can't have encounter type
return true;
if (et > 24) // invalid gen4 EncounterType
if (et > GroundTileType.Max_Pt) // invalid gen4 EncounterType
return true;
}

View file

@ -28,8 +28,8 @@ namespace PKHeX.Core
private static byte[] SetString(string value, int maxLength) => StringConverter3.SetBEString3(value, maxLength);
// Trash Bytes
public override byte[] Nickname_Trash { get => GetData(0x4E, 20); set { if (value.Length == 20) value.CopyTo(Data, 0x4E); } }
public override byte[] OT_Trash { get => GetData(0x38, 20); set { if (value.Length == 20) value.CopyTo(Data, 0x38); } }
public override Span<byte> Nickname_Trash { get => Data.AsSpan(0x4E, 20); set { if (value.Length == 20) value.CopyTo(Data.AsSpan(0x4E)); } }
public override Span<byte> OT_Trash { get => Data.AsSpan(0x38, 20); set { if (value.Length == 20) value.CopyTo(Data.AsSpan(0x38)); } }
// Silly Attributes
public override ushort Sanity { get => 0; set { } } // valid flag set in pkm structure.

View file

@ -240,7 +240,7 @@ namespace PKHeX.Core
set => SetString(value, OTLength).CopyTo(Data, Offsets.OT);
}
public byte[] OT_Trash { get => GetData(Offsets.OT, StringLength); set { if (value.Length == StringLength) SetData(value, Offsets.OT); } }
public Span<byte> OT_Trash { get => Data.AsSpan(Offsets.OT, StringLength); set { if (value.Length == StringLength) value.CopyTo(Data.AsSpan(Offsets.OT)); } }
public override int Gender
{

View file

@ -321,10 +321,10 @@ namespace PKHeX.Core
set => SetString(value, (Korean ? 2 : 1) * OTLength).CopyTo(Data, Offsets.Trainer1 + 2);
}
public byte[] OT_Trash
{
get => GetData(Offsets.Trainer1 + 2, StringLength);
set { if (value.Length == StringLength) SetData(value, Offsets.Trainer1 + 2); }
public Span<byte> OT_Trash
{
get => Data.AsSpan(Offsets.Trainer1 + 2, StringLength);
set { if (value.Length == StringLength) value.CopyTo(Data.AsSpan(Offsets.Trainer1 + 2)); }
}
public override int Gender

View file

@ -15,7 +15,7 @@ namespace PKHeX.WinForms.Controls
LoadMisc3(pk4);
LoadMisc4(pk4);
CB_EncounterType.SelectedValue = pk4.Gen4 ? pk4.EncounterType : 0;
CB_EncounterType.SelectedValue = pk4.Gen4 ? (int)pk4.GroundTile : 0;
CB_EncounterType.Visible = Label_EncounterType.Visible = Entity.Gen4;
if (HaX)
@ -40,7 +40,7 @@ namespace PKHeX.WinForms.Controls
SaveMisc3(pk4);
SaveMisc4(pk4);
pk4.EncounterType = WinFormsUtil.GetIndex(CB_EncounterType);
pk4.GroundTile = (GroundTileType)WinFormsUtil.GetIndex(CB_EncounterType);
// Minor properties
pk4.ShinyLeaf = ShinyLeaf.GetValue();

View file

@ -14,7 +14,7 @@ namespace PKHeX.WinForms.Controls
LoadMisc2(pk5);
LoadMisc3(pk5);
LoadMisc4(pk5);
CB_EncounterType.SelectedValue = pk5.Gen4 ? pk5.EncounterType : 0;
CB_EncounterType.SelectedValue = pk5.Gen4 ? (int)pk5.GroundTile : 0;
CB_EncounterType.Visible = Label_EncounterType.Visible = pk5.Gen4;
CHK_NSparkle.Checked = pk5.NPokémon;
@ -39,7 +39,7 @@ namespace PKHeX.WinForms.Controls
SaveMisc3(pk5);
SaveMisc4(pk5);
pk5.EncounterType = WinFormsUtil.GetIndex(CB_EncounterType);
pk5.GroundTile = (GroundTileType)WinFormsUtil.GetIndex(CB_EncounterType);
pk5.NPokémon = CHK_NSparkle.Checked;
if (!HaX) // specify via extra 0x42 instead
pk5.HiddenAbility = CB_Ability.SelectedIndex > 1; // not 0 or 1

View file

@ -16,7 +16,7 @@ namespace PKHeX.WinForms.Controls
LoadMisc4(pk6);
LoadMisc6(pk6);
CB_EncounterType.SelectedValue = pk6.Gen4 ? pk6.EncounterType : 0;
CB_EncounterType.SelectedValue = pk6.Gen4 ? (int)pk6.GroundTile : 0;
CB_EncounterType.Visible = Label_EncounterType.Visible = pk6.Gen4;
LoadPartyStats(pk6);
@ -35,7 +35,7 @@ namespace PKHeX.WinForms.Controls
SaveMisc6(pk6);
CheckTransferPIDValid(pk6);
pk6.EncounterType = WinFormsUtil.GetIndex(CB_EncounterType);
pk6.GroundTile = (GroundTileType)WinFormsUtil.GetIndex(CB_EncounterType);
// Toss in Party Stats
SavePartyStats(pk6);

View file

@ -798,7 +798,7 @@ namespace PKHeX.WinForms.Controls
if (Entity.CurrentLevel >= minlvl && Entity.Met_Level == level && Entity.Met_Location == location)
{
if (!encounter.HasEncounterType(Entity.Format) || WinFormsUtil.GetIndex(CB_EncounterType) == encounter.GetSuggestedEncounterType())
if (!encounter.HasGroundTile(Entity.Format) || WinFormsUtil.GetIndex(CB_EncounterType) == (int)encounter.GetSuggestedGroundTile())
return false;
}
if (minlvl < level)
@ -821,8 +821,8 @@ namespace PKHeX.WinForms.Controls
TB_MetLevel.Text = encounter.GetSuggestedMetLevel(Entity).ToString();
CB_MetLocation.SelectedValue = location;
if (encounter.HasEncounterType(Entity.Format))
CB_EncounterType.SelectedValue = encounter.GetSuggestedEncounterType();
if (encounter.HasGroundTile(Entity.Format))
CB_EncounterType.SelectedValue = (int)encounter.GetSuggestedGroundTile();
if (Entity.Gen6 && Entity.WasEgg && ModifyPKM)
Entity.SetHatchMemory6();
@ -1200,7 +1200,7 @@ namespace PKHeX.WinForms.Controls
}
// Visibility logic for Gen 4 encounter type; only show for Gen 4 Pokemon.
if (Entity.Format >= 4)
if (Entity is IGroundTile)
{
bool g4 = Entity.Gen4;
CB_EncounterType.Visible = Label_EncounterType.Visible = g4 && Entity.Format < 7;

View file

@ -12,14 +12,14 @@ namespace PKHeX.WinForms
public TrashEditor(TextBoxBase TB_NN, SaveFile sav) : this(TB_NN, Array.Empty<byte>(), sav) { }
public TrashEditor(TextBoxBase TB_NN, byte[] raw, SaveFile sav)
public TrashEditor(TextBoxBase TB_NN, Span<byte> raw, SaveFile sav)
{
InitializeComponent();
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
SAV = sav;
FinalString = TB_NN.Text;
Raw = FinalBytes = raw;
Raw = FinalBytes = raw.ToArray();
editing = true;
if (raw.Length != 0)

View file

@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>

View file

@ -1,4 +1,4 @@
using System.Linq;
using System;
using FluentAssertions;
using PKHeX.Core;
using Xunit;
@ -49,14 +49,22 @@ namespace PKHeX.Tests.PKM
CheckStringGetSet(nameof(pkm.Nickname), name_nidoran, pkm.Nickname, byte_nidoran, pkm.Nickname_Trash);
}
private static void CheckStringGetSet(string check, string instr, string outstr, byte[] indata, byte[] outdata)
private static void CheckStringGetSet(string check, string instr, string outstr, ReadOnlySpan<byte> indata, ReadOnlySpan<byte> outdata)
{
instr.Should().BeEquivalentTo(outstr);
outdata = outdata[..indata.Length];
indata.SequenceEqual(outdata).Should()
.BeTrue($"expected {check} to set properly, instead got {string.Join(", ", outdata.Select(z => $"{z:X2}"))}");
.BeTrue($"expected {check} to set properly, instead got {Hex(outdata)}");
}
private static string Hex(ReadOnlySpan<byte> outdata)
{
var sb = new System.Text.StringBuilder(outdata.Length);
foreach (var b in outdata)
sb.AppendFormat("{0:X2}, ", b);
return sb.ToString();
}
[Theory]