using System.Collections.Generic;
using System.Linq;
namespace PKHeX.Core
{
///
/// Miscellaneous setup utility for legality checking data sources.
///
internal static class EncounterUtil
{
///
/// Gets the relevant objects that appear in the relevant game.
///
/// Table of valid encounters that appear for the game pairing
/// Game to filter for
/// Array of encounter objects that are encounterable on the input game
internal static EncounterStatic[] GetStaticEncounters(IEnumerable source, GameVersion game)
{
return source.Where(s => s.Version.Contains(game)).ToArray();
}
///
/// Gets the data for the input game via the program's resource streams.
///
/// Game to fetch for
/// data is not marked, as the RNG seed is 64 bits (permitting sufficient randomness).
/// Array of areas that are encounterable on the input game.
internal static EncounterArea[] GetEncounterTables(GameVersion game)
{
switch (game)
{
case GameVersion.B: return GetEncounterTables("51", "b");
case GameVersion.W: return GetEncounterTables("51", "w");
case GameVersion.B2: return GetEncounterTables("52", "b2");
case GameVersion.W2: return GetEncounterTables("52", "w2");
case GameVersion.X: return GetEncounterTables("xy", "x");
case GameVersion.Y: return GetEncounterTables("xy", "y");
case GameVersion.AS: return GetEncounterTables("ao", "a");
case GameVersion.OR: return GetEncounterTables("ao", "o");
case GameVersion.SN: return GetEncounterTables("sm", "sn");
case GameVersion.MN: return GetEncounterTables("sm", "mn");
case GameVersion.US: return GetEncounterTables("uu", "us");
case GameVersion.UM: return GetEncounterTables("uu", "um");
}
return null; // bad request
}
///
/// Direct fetch for data; can also be used to fetch supplementary encounter streams.
///
/// Unpacking identification ASCII characters (first two bytes of binary)
/// Resource name (will be prefixed with "encounter_"
/// Array of encounter areas
internal static EncounterArea[] GetEncounterTables(string ident, string resource)
{
byte[] mini = Util.GetBinaryResource($"encounter_{resource}.pkl");
return EncounterArea.GetArray(Data.UnpackMini(mini, ident));
}
///
/// Combines slot arrays with the same .
///
/// Input encounter areas to combine
/// Combined Array of encounter areas. No duplicate location IDs will be present.
internal static EncounterArea[] AddExtraTableSlots(params EncounterArea[][] tables)
{
return tables.SelectMany(s => s).GroupBy(l => l.Location)
.Select(t => t.Count() == 1
? t.First() // only one table, just return the area
: new EncounterArea { Location = t.First().Location, Slots = t.SelectMany(s => s.Slots).ToArray() })
.ToArray();
}
///
/// Marks Encounter Slots for party lead's ability slot influencing.
///
/// Magnet Pull attracts Steel type slots, and Static attracts Electric
/// Encounter Area array for game
/// Personal data for use with a given species' type
internal static void MarkEncountersStaticMagnetPull(ref EncounterArea[] Areas, PersonalTable t)
{
const int steel = 8;
const int electric = 12;
foreach (EncounterArea Area in Areas)
{
var s = new List(); // Static
var m = new List(); // Magnet Pull
foreach (EncounterSlot Slot in Area.Slots)
{
var types = t[Slot.Species].Types;
if (types[0] == steel || types[1] == steel)
m.Add(Slot);
if (types[0] == electric || types[1] == electric)
s.Add(Slot);
}
foreach (var slot in s)
{
slot.Permissions.Static = true;
slot.Permissions.StaticCount = s.Count;
}
foreach (var slot in m)
{
slot.Permissions.MagnetPull = true;
slot.Permissions.MagnetPullCount = s.Count;
}
}
}
///
/// Sets the value, for use in determining split-generation origins.
///
/// Only used for Gen 1 & 2, as data is not present.
/// Ingame encounter data
/// Generation number to set
internal static void MarkEncountersGeneration(IEnumerable Encounters, int Generation)
{
foreach (EncounterStatic Encounter in Encounters)
Encounter.Generation = Generation;
}
///
/// Sets the value, for use in determining split-generation origins.
///
/// Only used for Gen 1 & 2, as data is not present.
/// Ingame encounter data
/// Version ID to set
internal static void MarkEncountersVersion(IEnumerable Areas, GameVersion Version)
{
foreach (EncounterArea Area in Areas)
foreach (var Slot in Area.Slots.OfType())
Slot.Version = Version;
}
///
/// Sets the value, for use in determining split-generation origins.
///
/// Only used for Gen 1 & 2, as data is not present.
/// Ingame encounter data
/// Generation number to set
internal static void MarkEncountersGeneration(IEnumerable Areas, int Generation)
{
foreach (EncounterArea Area in Areas)
foreach (EncounterSlot Slot in Area.Slots)
Slot.Generation = Generation;
}
///
/// Groups areas by location id, raw data has areas with different slots but the same location id.
///
/// Similar to , this method combines a single array.
/// Ingame encounter data
internal static void ReduceAreasSize(ref EncounterArea[] Areas)
{
Areas = Areas.GroupBy(a => a.Location).Select(a => new EncounterArea
{
Location = a.First().Location,
Slots = a.SelectMany(m => m.Slots).ToArray()
}).ToArray();
}
///
/// Sets the to the for identifying where the slot is encountered.
///
/// Some games / transferred data do not contain original encounter location IDs; is mainly for info purposes.
/// Ingame encounter data
internal static void MarkSlotLocation(ref EncounterArea[] Areas)
{
foreach (EncounterArea Area in Areas)
foreach (EncounterSlot Slot in Area.Slots)
Slot.Location = Area.Location;
}
}
}