PKHeX/PKHeX/PKM/PKM.cs

446 lines
18 KiB
C#
Raw Normal View History

using System;
using System.Drawing;
using System.Linq;
namespace PKHeX
{
public abstract class PKM
{
public abstract int SIZE_PARTY { get; }
public abstract int SIZE_STORED { get; }
public string Extension => "pk" + Format;
// Internal Attributes set on creation
public byte[] Data; // Raw Storage
public string Identifier; // User or Form Custom Attribute
public int Box { get; set; } = -1; // Batch Editor
public int Slot { get; set; } = -1; // Batch Editor
public byte[] EncryptedPartyData => Encrypt().Take(SIZE_PARTY).ToArray();
public byte[] EncryptedBoxData => Encrypt().Take(SIZE_STORED).ToArray();
public byte[] DecryptedPartyData => Write().Take(SIZE_PARTY).ToArray();
public byte[] DecryptedBoxData => Write().Take(SIZE_STORED).ToArray();
protected ushort CalculateChecksum()
{
ushort chk = 0;
switch (Format)
{
case 3:
for (int i = 32; i < SIZE_STORED; i += 2)
chk += BitConverter.ToUInt16(Data, i);
return chk;
default: // 4+
for (int i = 8; i < SIZE_STORED; i += 2)
chk += BitConverter.ToUInt16(Data, i);
return chk;
}
}
public abstract byte[] Encrypt();
public abstract int Format { get; }
public byte[] Write()
{
RefreshChecksum();
return Data;
}
// Surface Properties
public abstract int Species { get; set; }
public abstract string Nickname { get; set; }
public abstract int HeldItem { get; set; }
public abstract int Gender { get; set; }
public abstract int Nature { get; set; }
public abstract int Ability { get; set; }
public abstract int CurrentFriendship { get; set; }
public abstract int AltForm { get; set; }
public abstract bool IsEgg { get; set; }
public abstract bool IsNicknamed { get; set; }
public abstract uint EXP { get; set; }
public abstract int TID { get; set; }
public abstract string OT_Name { get; set; }
public abstract int OT_Gender { get; set; }
public abstract int Ball { get; set; }
public abstract int Met_Level { get; set; }
// Battle
public abstract int Move1 { get; set; }
public abstract int Move2 { get; set; }
public abstract int Move3 { get; set; }
public abstract int Move4 { get; set; }
public abstract int Move1_PP { get; set; }
public abstract int Move2_PP { get; set; }
public abstract int Move3_PP { get; set; }
public abstract int Move4_PP { get; set; }
public abstract int Move1_PPUps { get; set; }
public abstract int Move2_PPUps { get; set; }
public abstract int Move3_PPUps { get; set; }
public abstract int Move4_PPUps { get; set; }
public abstract int EV_HP { get; set; }
public abstract int EV_ATK { get; set; }
public abstract int EV_DEF { get; set; }
public abstract int EV_SPE { get; set; }
public abstract int EV_SPA { get; set; }
public abstract int EV_SPD { get; set; }
public abstract int IV_HP { get; set; }
public abstract int IV_ATK { get; set; }
public abstract int IV_DEF { get; set; }
public abstract int IV_SPE { get; set; }
public abstract int IV_SPA { get; set; }
public abstract int IV_SPD { get; set; }
public abstract int Stat_Level { get; set; }
public abstract int Stat_HPMax { get; set; }
public abstract int Stat_HPCurrent { get; set; }
public abstract int Stat_ATK { get; set; }
public abstract int Stat_DEF { get; set; }
public abstract int Stat_SPE { get; set; }
public abstract int Stat_SPA { get; set; }
public abstract int Stat_SPD { get; set; }
// Hidden Properties
public abstract int Version { get; set; }
public abstract int SID { get; set; }
public abstract int PKRS_Strain { get; set; }
public abstract int PKRS_Days { get; set; }
public abstract int CNT_Cool { get; set; }
public abstract int CNT_Beauty { get; set; }
public abstract int CNT_Cute { get; set; }
public abstract int CNT_Smart { get; set; }
public abstract int CNT_Tough { get; set; }
public abstract int CNT_Sheen { get; set; }
public abstract uint EncryptionConstant { get; set; }
public abstract uint PID { get; set; }
public abstract ushort Sanity { get; set; }
public abstract ushort Checksum { get; set; }
// Misc Properties
public abstract int Language { get; set; }
public abstract bool FatefulEncounter { get; set; }
public abstract int TSV { get; }
public abstract int PSV { get; }
public abstract int Characteristic { get; }
public abstract byte MarkByte { get; protected set; }
public abstract int Met_Location { get; set; }
public abstract int Egg_Location { get; set; }
public abstract int OT_Friendship { get; set; }
// Future Properties
protected virtual int Met_Year { get { return 0; } set { } }
protected virtual int Met_Month { get { return 0; } set { } }
protected virtual int Met_Day { get { return 0; } set { } }
/// <summary>
/// The date the Pokémon was met.
/// </summary>
/// <returns>A DateTime representing the date the Pokémon was met, or null if either the <see cref="PKM"/> format does not support dates or the stored date is invalid.</returns>
/// <remarks>Not all <see cref="PKM"/> types support the <see cref="MetDate"/> property. In these cases, this property will return null.
///
/// If null is assigned to this property, it will be cleared.</remarks>
public virtual DateTime? MetDate
{
get
{
// Check to see if date is valid
2016-08-11 00:54:12 +00:00
if (!Util.IsDateValid(2000 + Met_Year, Met_Month, Met_Day))
{
return null;
}
else
{
return new DateTime(2000 + Met_Year, Met_Month, Met_Day);
}
}
set
{
if (value.HasValue)
{
// Only update the properties if a value is provided.
2016-08-10 14:07:16 +00:00
Met_Year = value.Value.Year - 2000;
Met_Month = value.Value.Month;
Met_Day = value.Value.Day;
}
else
{
// Clear the Met Date.
// If code tries to access MetDate again, null will be returned.
Met_Year = 0;
Met_Month = 0;
Met_Day = 0;
}
}
}
protected virtual int Egg_Year { get { return 0; } set { } }
protected virtual int Egg_Month { get { return 0; } set { } }
protected virtual int Egg_Day { get { return 0; } set { } }
/// <summary>
/// The date a Pokémon was met as an egg.
/// </summary>
/// <returns>A DateTime representing the date the Pokémon was met as an egg, or null if the <see cref="PKM"/> format does not support dates.</returns>
/// <remarks>Not all <see cref="PKM"/> types support the <see cref="EggMetDate"/> property. In these cases, this property will return null.
///
/// If null is assigned to this property, it will be cleared.</remarks>
public virtual DateTime? EggMetDate
{
get
{
// Check to see if date is valid
2016-08-11 00:54:12 +00:00
if (!Util.IsDateValid(2000 + Egg_Year, Egg_Month, Egg_Day))
{
return null;
}
else
{
return new DateTime(2000 + Egg_Year, Egg_Month, Egg_Day);
}
}
set
{
if (value.HasValue)
{
// Only update the properties if a value is provided.
2016-08-10 14:07:16 +00:00
Egg_Year = value.Value.Year - 2000;
Egg_Month = value.Value.Month;
Egg_Day = value.Value.Day;
}
else
{
// Clear the Met Date.
// If code tries to access MetDate again, null will be returned.
Egg_Year = 0;
Egg_Month = 0;
Egg_Day = 0;
}
}
}
public virtual int OT_Affection { get { return 0; } set { } }
public virtual int RelearnMove1 { get { return 0; } set { } }
public virtual int RelearnMove2 { get { return 0; } set { } }
public virtual int RelearnMove3 { get { return 0; } set { } }
public virtual int RelearnMove4 { get { return 0; } set { } }
public virtual int EncounterType { get { return 0; } set { } }
// Exposed but not Present in all
public abstract int CurrentHandler { get; set; }
// Derived
public bool IsShiny => TSV == PSV;
public bool Gen6 => Version >= 24 && Version <= 29;
public bool XY => Version == (int)GameVersion.X || Version == (int)GameVersion.Y;
public bool AO => Version == (int)GameVersion.AS || Version == (int)GameVersion.OR;
public bool SM => Version == (int)GameVersion.SN || Version == (int)GameVersion.MN;
protected bool PtHGSS => GameVersion.Pt == (GameVersion)Version || HGSS;
public bool HGSS => new[] {GameVersion.HG, GameVersion.SS}.Contains((GameVersion)Version);
public bool Gen5 => Version >= 20 && Version <= 23;
public bool Gen4 => Version >= 10 && Version < 12 || Version >= 7 && Version <= 8;
public bool Gen3 => Version >= 1 && Version <= 5 || Version == 15;
public bool GenU => !(Gen6 || Gen5 || Gen4 || Gen3);
2016-08-09 01:42:42 +00:00
public int GenNumber
{
get
{
if (Gen6) return 6;
if (Gen5) return 5;
if (Gen4) return 4;
if (Gen3) return 3;
return -1;
}
}
public bool PKRS_Infected => PKRS_Strain > 0;
public bool PKRS_Cured => PKRS_Days == 0 && PKRS_Strain > 0;
public bool ChecksumValid => Checksum == CalculateChecksum();
public int CurrentLevel => PKX.getLevel(Species, EXP);
public bool MarkCircle { get { return (MarkByte & (1 << 0)) == 1 << 0; } set { MarkByte = (byte)(MarkByte & ~(1 << 0) | (value ? 1 << 0 : 0)); } }
public bool MarkTriangle { get { return (MarkByte & (1 << 1)) == 1 << 1; } set { MarkByte = (byte)(MarkByte & ~(1 << 0) | (value ? 1 << 0 : 0)); } }
public bool MarkSquare { get { return (MarkByte & (1 << 2)) == 1 << 2; } set { MarkByte = (byte)(MarkByte & ~(1 << 0) | (value ? 1 << 0 : 0)); } }
public bool MarkHeart { get { return (MarkByte & (1 << 3)) == 1 << 3; } set { MarkByte = (byte)(MarkByte & ~(1 << 0) | (value ? 1 << 0 : 0)); } }
public bool MarkStar { get { return (MarkByte & (1 << 4)) == 1 << 4; } set { MarkByte = (byte)(MarkByte & ~(1 << 0) | (value ? 1 << 0 : 0)); } }
public bool MarkDiamond { get { return (MarkByte & (1 << 5)) == 1 << 5; } set { MarkByte = (byte)(MarkByte & ~(1 << 0) | (value ? 1 << 0 : 0)); } }
public Image Sprite => PKX.getSprite(this);
public string ShowdownText => ShowdownSet.getShowdownText(this);
public string[] QRText => PKX.getQRText(this);
public string FileName => $"{Species.ToString("000")}{(IsShiny ? " " : "")} - {Nickname} - {Checksum.ToString("X4")}{EncryptionConstant.ToString("X8")}.{Extension}";
public int[] IVs
{
get { return new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; }
set
{
if (value?.Length != 6) return;
IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2];
IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5];
}
}
public int[] EVs
{
get { return new[] { EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD }; }
set
{
if (value?.Length != 6) return;
EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2];
EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5];
}
}
public int[] Moves
{
get { return new[] { Move1, Move2, Move3, Move4 }; }
set { if (value?.Length != 4) return; Move1 = value[0]; Move2 = value[1]; Move3 = value[2]; Move4 = value[3]; }
}
public bool[] Markings
{
get
{
bool[] mark = new bool[8];
for (int i = 0; i < 8; i++)
mark[i] = ((MarkByte >> i) & 1) == 1;
return mark;
}
set
{
if (value.Length > 8)
return;
byte b = 0;
for (int i = 0; i < value.Length; i++)
b |= (byte)(value[i] ? 1 << i : 0);
MarkByte = b;
}
}
public int[] CNTs
{
get { return new[] { CNT_Cool, CNT_Beauty, CNT_Cute, CNT_Smart, CNT_Tough, CNT_Sheen }; }
set { if (value?.Length != 6) return; CNT_Cool = value[0]; CNT_Beauty = value[1]; CNT_Cute = value[2]; CNT_Smart = value[3]; CNT_Tough = value[4]; CNT_Sheen = value[5]; }
}
public int HPType
{
get { return 15 * ((IV_HP & 1) + 2 * (IV_ATK & 1) + 4 * (IV_DEF & 1) + 8 * (IV_SPE & 1) + 16 * (IV_SPA & 1) + 32 * (IV_SPD & 1)) / 63; }
set
{
IV_HP = (IV_HP & ~1) + PKX.hpivs[value, 0];
IV_ATK = (IV_ATK & ~1) + PKX.hpivs[value, 1];
IV_DEF = (IV_DEF & ~1) + PKX.hpivs[value, 2];
IV_SPE = (IV_SPE & ~1) + PKX.hpivs[value, 3];
IV_SPA = (IV_SPA & ~1) + PKX.hpivs[value, 4];
IV_SPD = (IV_SPD & ~1) + PKX.hpivs[value, 5];
}
}
// Methods
public abstract bool getGenderIsValid();
public void RefreshChecksum() { Checksum = CalculateChecksum(); }
public void FixMoves()
{
if (Move4 != 0 && Move3 == 0)
{
Move3 = Move4;
Move3_PP = Move4_PP;
Move3_PPUps = Move4_PPUps;
Move4 = Move4_PP = Move4_PPUps = 0;
}
if (Move3 != 0 && Move2 == 0)
{
Move2 = Move3;
Move2_PP = Move3_PP;
Move2_PPUps = Move3_PPUps;
Move3 = Move3_PP = Move3_PPUps = 0;
}
if (Move2 != 0 && Move1 == 0)
{
Move1 = Move2;
Move1_PP = Move2_PP;
Move1_PPUps = Move2_PPUps;
Move2 = Move2_PP = Move2_PPUps = 0;
}
}
public int PotentialRating
{
get
{
int ivTotal = IVs.Sum();
if (ivTotal <= 90)
return 0;
if (ivTotal <= 120)
return 1;
return ivTotal <= 150 ? 2 : 3;
}
}
public ushort[] getStats(PersonalInfo p)
{
int level = CurrentLevel;
ushort[] Stats = new ushort[6];
Stats[0] = (ushort)(p.HP == 1 ? 1 : (IV_HP + 2 * p.HP + EV_HP / 4 + 100) * level / 100 + 10);
Stats[1] = (ushort)((IV_ATK + 2 * p.ATK + EV_ATK / 4) * level / 100 + 5);
Stats[2] = (ushort)((IV_DEF + 2 * p.DEF + EV_DEF / 4) * level / 100 + 5);
Stats[4] = (ushort)((IV_SPA + 2 * p.SPA + EV_SPA / 4) * level / 100 + 5);
Stats[5] = (ushort)((IV_SPD + 2 * p.SPD + EV_SPD / 4) * level / 100 + 5);
Stats[3] = (ushort)((IV_SPE + 2 * p.SPE + EV_SPE / 4) * level / 100 + 5);
// Account for nature
int incr = Nature / 5 + 1;
int decr = Nature % 5 + 1;
if (incr == decr) return Stats;
Stats[incr] *= 11; Stats[incr] /= 10;
Stats[decr] *= 9; Stats[decr] /= 10;
return Stats;
}
public void setStats(ushort[] Stats)
{
Stat_HPMax = Stat_HPCurrent = Stats[0];
Stat_ATK = Stats[1];
Stat_DEF = Stats[2];
Stat_SPE = Stats[3];
Stat_SPA = Stats[4];
Stat_SPD = Stats[5];
}
2016-07-09 01:38:40 +00:00
public virtual bool CanHoldItem(ushort[] ValidArray)
{
return ValidArray.Contains((ushort)HeldItem);
}
public abstract PKM Clone();
public int getMovePP(int move, int ppup)
{
return getBasePP(move) * (5 + ppup) / 5;
}
private int getBasePP(int move)
{
int[] pptable;
switch (Format)
{
case 3: pptable = Legal.MovePP_RS; break;
case 4: pptable = Legal.MovePP_DP; break;
case 5: pptable = Legal.MovePP_BW; break;
case 6: pptable = Legal.MovePP_XY; break;
default: pptable = new int[1]; break;
}
if (move >= pptable.Length)
move = 0;
return pptable[move];
}
2016-07-29 05:33:16 +00:00
public void setShinyPID()
{
do PID = PKX.getRandomPID(Species, Gender, Version, Nature, AltForm, PID); while (!IsShiny);
if (GenNumber < 6)
EncryptionConstant = PID;
2016-07-29 05:33:16 +00:00
}
2016-07-29 05:54:29 +00:00
public void setPIDGender(int gender)
{
do PID = PKX.getRandomPID(Species, gender, Version, Nature, AltForm, PID); while (IsShiny);
if (GenNumber < 6)
EncryptionConstant = PID;
}
public void setPIDNature(int nature)
{
do PID = PKX.getRandomPID(Species, Gender, Version, nature, AltForm, PID); while (IsShiny);
if (GenNumber < 6)
EncryptionConstant = PID;
2016-07-29 05:54:29 +00:00
}
}
}