using System;
using System.Collections.Generic;
namespace PKHeX.Core
{
public abstract class DataMysteryGift : MysteryGift
{
public readonly byte[] Data;
protected DataMysteryGift(byte[] data) => Data = data;
///
/// Returns an array for exporting outside the program (to disk, etc).
///
public virtual byte[] Write() => Data;
public override int GetHashCode()
{
int hash = 17;
foreach (var b in Data)
hash = (hash * 31) + b;
return hash;
}
///
/// Creates a deep copy of the object data.
///
///
public override MysteryGift Clone()
{
byte[] data = (byte[])Data.Clone();
var result = GetMysteryGift(data);
if (result == null)
throw new ArgumentException(nameof(MysteryGift));
return result;
}
public override bool Empty => Data.IsRangeAll((byte)0, 0, Data.Length);
}
///
/// Mystery Gift Template File
///
public abstract class MysteryGift : IEncounterable, IMoveset, IRelearn, IGeneration, ILocation
{
///
/// Determines whether or not the given length of bytes is valid for a mystery gift.
///
/// Length, in bytes, of the data of which to determine validity.
/// A boolean indicating whether or not the given length is valid for a mystery gift.
public static bool IsMysteryGift(long len) => MGSizes.Contains((int)len);
private static readonly HashSet MGSizes = new HashSet{ WC8.Size, WC6Full.Size, WC6.Size, PGF.Size, PGT.Size, PCD.Size };
///
/// Converts the given data to a .
///
/// Raw data of the mystery gift.
/// Extension of the file from which the was retrieved.
/// An instance of representing the given data, or null if or is invalid.
/// This overload differs from by checking the / combo for validity. If either is invalid, a null reference is returned.
public static DataMysteryGift? GetMysteryGift(byte[] data, string ext)
{
if (ext == null)
return GetMysteryGift(data);
switch (data.Length)
{
case WC8.Size when ext == ".wc8":
return new WC8(data);
case WB7.SizeFull when ext == ".wb7full":
case WB7.Size when ext == ".wb7":
return new WB7(data);
case WC7Full.Size when ext == ".wc7full":
return new WC7Full(data).Gift;
case WC7.Size when ext == ".wc7":
return new WC7(data);
case WC6Full.Size when ext == ".wc6full":
return new WC6Full(data).Gift;
case WC6.Size when ext == ".wc6":
return new WC6(data);
case WR7.Size when ext == ".wr7":
return new WR7(data);
case WC8.Size when ext == ".wc8":
case WC8.Size when ext == ".wc8full":
return new WC8(data);
case PGF.Size when ext == ".pgf":
return new PGF(data);
case PGT.Size when ext == ".pgt":
return new PGT(data);
case PCD.Size when ext == ".pcd" || ext == ".wc4":
return new PCD(data);
}
return null;
}
///
/// Converts the given data to a .
///
/// Raw data of the mystery gift.
/// An instance of representing the given data, or null if is invalid.
public static DataMysteryGift? GetMysteryGift(byte[] data)
{
switch (data.Length)
{
case WC6Full.Size:
// Check WC7 size collision
if (data[0x205] == 0) // 3 * 0x46 for gen6, now only 2.
return new WC7Full(data).Gift;
return new WC6Full(data).Gift;
case WC6.Size:
// Check year for WC7 size collision
if (BitConverter.ToUInt32(data, 0x4C) / 10000 < 2000)
return new WC7(data);
return new WC6(data);
case WR7.Size: return new WR7(data);
case WC8.Size: return new WC8(data);
case PGF.Size: return new PGF(data);
case PGT.Size: return new PGT(data);
case PCD.Size: return new PCD(data);
default: return null;
}
}
public string Extension => GetType().Name.ToLower();
public string FileName => $"{CardHeader}.{Extension}";
public abstract int Format { get; }
public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted);
public abstract PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria);
protected abstract bool IsMatchExact(PKM pkm);
protected abstract bool IsMatchDeferred(PKM pkm);
public EncounterMatchRating IsMatch(PKM pkm)
{
if (!IsMatchExact(pkm))
return EncounterMatchRating.None;
if (IsMatchDeferred(pkm))
return EncounterMatchRating.Deferred;
return EncounterMatchRating.Match;
}
///
/// Creates a deep copy of the object data.
///
///
public abstract MysteryGift Clone();
///
/// Gets a friendly name for the underlying type.
///
public string Type => GetType().Name;
///
/// Gets a friendly name for the underlying type for the interface.
///
public string Name => $"Event Gift";
///
/// Gets a friendly name for the underlying type for the interface.
///
public string LongName => $"{Name} ({Type})";
// Properties
public virtual int Species { get => -1; set { } }
public abstract bool GiftUsed { get; set; }
public abstract string CardTitle { get; set; }
public abstract int CardID { get; set; }
public abstract bool IsItem { get; set; }
public abstract int ItemID { get; set; }
public abstract bool IsPokémon { get; set; }
public virtual int Quantity { get => 1; set { } }
public virtual bool Empty => false;
public virtual bool IsBP { get => false; set { } }
public virtual int BP { get => 0; set { } }
public virtual bool IsBean { get => false; set { } }
public virtual int Bean { get => 0; set { } }
public virtual int BeanCount { get => 0; set { } }
public virtual string CardHeader => (CardID > 0 ? $"Card #: {CardID:0000}" : "N/A") + $" - {CardTitle.Replace('\u3000',' ').Trim()}";
// Search Properties
public virtual IReadOnlyList Moves { get => Array.Empty(); set { } }
public virtual IReadOnlyList Relearn { get => Array.Empty(); set { } }
public virtual int[] IVs { get => Array.Empty(); set { } }
public virtual bool IsShiny => false;
public virtual bool IsEgg { get => false; set { } }
public virtual int HeldItem { get => -1; set { } }
public virtual int AbilityType { get => -1; set { } }
public virtual object Content => this;
public abstract int Gender { get; set; }
public abstract int Form { get; set; }
public abstract int TID { get; set; }
public abstract int SID { get; set; }
public abstract string OT_Name { get; set; }
public abstract int Location { get; set; }
public abstract int Level { get; set; }
public int LevelMin => Level;
public int LevelMax => Level;
public abstract int Ball { get; set; }
public virtual bool EggEncounter => IsEgg;
public int Generation { get => Format; set {} }
public abstract int EggLocation { get; set; }
public int TrainerID7 => (int)((uint)(TID | (SID << 16)) % 1000000);
public int TrainerSID7 => (int)((uint)(TID | (SID << 16)) / 1000000);
}
}