PKHeX/PKHeX.Core/MysteryGifts/WC7.cs
Kurt f674d45854 Misc changes
Properly handle egg hatch counters for generated mystery gifts, as well
as HT friendship for gen6+
fetch form specific (friendship doesn't change but abilities fetch
species specific data later, so just fetch once up front). Do not depend
on save file as SAV7 importing PGF may have different abilities
allocated
Pad buttons for folder popup
fix double Japanese/International error message for importing jpk1<->pk1
2017-05-16 20:34:24 -07:00

459 lines
21 KiB
C#

using System;
using System.Linq;
using System.Text;
namespace PKHeX.Core
{
public sealed class WC7 : MysteryGift, IRibbonSet1, IRibbonSet2
{
public const int Size = 0x108;
public const int SizeFull = 0x310;
public override int Format => 7;
public WC7(byte[] data = null)
{
Data = (byte[])(data?.Clone() ?? new byte[Size]);
if (Data.Length == SizeFull)
{
Data = Data.Skip(SizeFull - Size).ToArray();
DateTime now = DateTime.Now;
Year = (uint)now.Year;
Month = (uint)now.Month;
Day = (uint)now.Day;
}
}
// General Card Properties
public override int CardID {
get => BitConverter.ToUInt16(Data, 0);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0); }
public override string CardTitle { // Max len 36 char, followed by null terminator
get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 2, 72));
set => Encoding.Unicode.GetBytes(value.PadRight(36, '\0')).CopyTo(Data, 2); }
private uint RawDate {
get => BitConverter.ToUInt32(Data, 0x4C);
set => BitConverter.GetBytes(value).CopyTo(Data, 0x4C); }
private uint Year {
get => RawDate / 10000 + 2000;
set => RawDate = (value - 2000) * 10000 + RawDate % 10000; }
private uint Month {
get => RawDate % 10000 / 100;
set => RawDate = (Year - 2000) * 10000 + value * 100 + RawDate % 100; }
private uint Day {
get => RawDate % 100;
set => RawDate = (Year - 2000) * 10000 + Month * 100 + value; }
/// <summary>
/// Gets or sets the date of the card.
/// </summary>
public DateTime? Date
{
get
{
// Check to see if date is valid
if (!Util.IsDateValid(Year, Month, Day))
return null;
return new DateTime((int)Year, (int)Month, (int)Day);
}
set
{
if (value.HasValue)
{
// Only update the properties if a value is provided.
Year = (ushort)value.Value.Year;
Month = (byte)value.Value.Month;
Day = (byte)value.Value.Day;
}
else
{
// Clear the Met Date.
// If code tries to access MetDate again, null will be returned.
Year = 0;
Month = 0;
Day = 0;
}
}
}
public int CardLocation { get => Data[0x50]; set => Data[0x50] = (byte)value; }
public int CardType { get => Data[0x51]; set => Data[0x51] = (byte)value; }
public byte CardFlags { get => Data[0x52]; set => Data[0x52] = value; }
public bool GiftRepeatable { get => (CardFlags & 1) == 0; set => CardFlags = (byte)(CardFlags & ~1 | (value ? 0 : 1)); }
public override bool GiftUsed { get => (CardFlags & 2) == 2; set => CardFlags = (byte)(CardFlags & ~2 | (value ? 2 : 0)); }
public bool GiftOncePerDay { get => (CardFlags & 4) == 4; set => CardFlags = (byte)(CardFlags & ~4 | (value ? 4 : 0)); }
public bool MultiObtain { get => Data[0x53] == 1; set => Data[0x53] = (byte)(value ? 1 : 0); }
// BP Properties
public override bool IsBP { get => CardType == 3; set { if (value) CardType = 3; } }
public override int BP
{
get => Item;
set => Item = value;
}
// Bean (Mame) Properties
public override bool IsBean { get => CardType == 2; set { if (value) CardType = 2; } }
public override int Bean
{
get => Item;
set => Item = value;
}
// Item Properties
public override bool IsItem { get => CardType == 1; set { if (value) CardType = 1; } }
public override int Item {
get => BitConverter.ToUInt16(Data, 0x68);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x68); }
public int GetItem(int index) => BitConverter.ToUInt16(Data, 0x68 + 0x4*index);
public void SetItem(int index, ushort item) => BitConverter.GetBytes(item).CopyTo(Data, 0x68 + 4*index);
public int GetQuantity(int index) => BitConverter.ToUInt16(Data, 0x6A + 0x4 * index);
public void SetQuantity(int index, ushort quantity) => BitConverter.GetBytes(quantity).CopyTo(Data, 0x6A + 4 * index);
public override int Quantity {
get => BitConverter.ToUInt16(Data, 0x6A);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x6A); }
// Pokémon Properties
public override bool IsPokémon { get => CardType == 0; set { if (value) CardType = 0; } }
public override bool IsShiny => PIDType == 2;
public int TID {
get => BitConverter.ToUInt16(Data, 0x68);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x68); }
public int SID {
get => BitConverter.ToUInt16(Data, 0x6A);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x6A); }
public int OriginGame {
get => Data[0x6C];
set => Data[0x6C] = (byte)value; }
public uint EncryptionConstant {
get => BitConverter.ToUInt32(Data, 0x70);
set => BitConverter.GetBytes(value).CopyTo(Data, 0x70); }
public override int Ball {
get => Data[0x76];
set => Data[0x76] = (byte)value; }
public override int HeldItem {
get => BitConverter.ToUInt16(Data, 0x78);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x78); }
public int Move1 {
get => BitConverter.ToUInt16(Data, 0x7A);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x7A); }
public int Move2 {
get => BitConverter.ToUInt16(Data, 0x7C);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x7C); }
public int Move3 {
get => BitConverter.ToUInt16(Data, 0x7E);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x7E); }
public int Move4 {
get => BitConverter.ToUInt16(Data, 0x80);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x80); }
public override int Species {
get => BitConverter.ToUInt16(Data, 0x82);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x82); }
public int Form {
get => Data[0x84];
set => Data[0x84] = (byte)value; }
public int Language {
get => Data[0x85];
set => Data[0x85] = (byte)value; }
public string Nickname {
get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x86, 0x1A));
set => Encoding.Unicode.GetBytes(value.PadRight(12 + 1, '\0')).CopyTo(Data, 0x86); }
public int Nature {
get => Data[0xA0];
set => Data[0xA0] = (byte)value; }
public int Gender {
get => Data[0xA1];
set => Data[0xA1] = (byte)value; }
public int AbilityType {
get => Data[0xA2];
set => Data[0xA2] = (byte)value; }
public int PIDType {
get => Data[0xA3];
set => Data[0xA3] = (byte)value; }
public int EggLocation {
get => BitConverter.ToUInt16(Data, 0xA4);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xA4); }
public int MetLocation {
get => BitConverter.ToUInt16(Data, 0xA6);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xA6); }
public int MetLevel { get => Data[0xA8]; set => Data[0xA8] = (byte)value; }
public int CNT_Cool { get => Data[0xA9]; set => Data[0xA9] = (byte)value; }
public int CNT_Beauty { get => Data[0xAA]; set => Data[0xAA] = (byte)value; }
public int CNT_Cute { get => Data[0xAB]; set => Data[0xAB] = (byte)value; }
public int CNT_Smart { get => Data[0xAC]; set => Data[0xAC] = (byte)value; }
public int CNT_Tough { get => Data[0xAD]; set => Data[0xAD] = (byte)value; }
public int CNT_Sheen { get => Data[0xAE]; set => Data[0xAE] = (byte)value; }
public int IV_HP { get => Data[0xAF]; set => Data[0xAF] = (byte)value; }
public int IV_ATK { get => Data[0xB0]; set => Data[0xB0] = (byte)value; }
public int IV_DEF { get => Data[0xB1]; set => Data[0xB1] = (byte)value; }
public int IV_SPE { get => Data[0xB2]; set => Data[0xB2] = (byte)value; }
public int IV_SPA { get => Data[0xB3]; set => Data[0xB3] = (byte)value; }
public int IV_SPD { get => Data[0xB4]; set => Data[0xB4] = (byte)value; }
public int OTGender { get => Data[0xB5]; set => Data[0xB5] = (byte)value; }
public string OT {
get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0xB6, 0x1A));
set => Encoding.Unicode.GetBytes(value.PadRight(value.Length + 1, '\0')).CopyTo(Data, 0xB6); }
public override int Level { get => Data[0xD0]; set => Data[0xD0] = (byte)value; }
public override bool IsEgg { get => Data[0xD1] == 1; set => Data[0xD1] = (byte)(value ? 1 : 0); }
public ushort AdditionalItem { get => BitConverter.ToUInt16(Data, 0xD2); set => BitConverter.GetBytes(value).CopyTo(Data, 0xD2); }
public uint PID {
get => BitConverter.ToUInt32(Data, 0xD4);
set => BitConverter.GetBytes(value).CopyTo(Data, 0xD4); }
public int RelearnMove1 {
get => BitConverter.ToUInt16(Data, 0xD8);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xD8); }
public int RelearnMove2 {
get => BitConverter.ToUInt16(Data, 0xDA);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xDA); }
public int RelearnMove3 {
get => BitConverter.ToUInt16(Data, 0xDC);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xDC); }
public int RelearnMove4 {
get => BitConverter.ToUInt16(Data, 0xDE);
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xDE); }
public int OT_Intensity { get => Data[0xE0]; set => Data[0xE0] = (byte)value; }
public int OT_Memory { get => Data[0xE1]; set => Data[0xE1] = (byte)value; }
public int OT_TextVar { get => BitConverter.ToUInt16(Data, 0xE2); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xE2); }
public int OT_Feeling { get => Data[0xE4]; set => Data[0xE4] = (byte)value; }
public int EV_HP { get => Data[0xE5]; set => Data[0xE5] = (byte)value; }
public int EV_ATK { get => Data[0xE6]; set => Data[0xE6] = (byte)value; }
public int EV_DEF { get => Data[0xE7]; set => Data[0xE7] = (byte)value; }
public int EV_SPE { get => Data[0xE8]; set => Data[0xE8] = (byte)value; }
public int EV_SPA { get => Data[0xE9]; set => Data[0xE9] = (byte)value; }
public int EV_SPD { get => Data[0xEA]; set => Data[0xEA] = (byte)value; }
private byte RIB0 { get => Data[0x74]; set => Data[0x74] = value; }
public bool RibbonChampionBattle { get => (RIB0 & (1 << 0)) == 1 << 0; set => RIB0 = (byte)(RIB0 & ~(1 << 0) | (value ? 1 << 0 : 0)); } // Battle Champ Ribbon
public bool RibbonChampionRegional { get => (RIB0 & (1 << 1)) == 1 << 1; set => RIB0 = (byte)(RIB0 & ~(1 << 1) | (value ? 1 << 1 : 0)); } // Regional Champ Ribbon
public bool RibbonChampionNational { get => (RIB0 & (1 << 2)) == 1 << 2; set => RIB0 = (byte)(RIB0 & ~(1 << 2) | (value ? 1 << 2 : 0)); } // National Champ Ribbon
public bool RibbonCountry { get => (RIB0 & (1 << 3)) == 1 << 3; set => RIB0 = (byte)(RIB0 & ~(1 << 3) | (value ? 1 << 3 : 0)); } // Country Ribbon
public bool RibbonNational { get => (RIB0 & (1 << 4)) == 1 << 4; set => RIB0 = (byte)(RIB0 & ~(1 << 4) | (value ? 1 << 4 : 0)); } // National Ribbon
public bool RibbonEarth { get => (RIB0 & (1 << 5)) == 1 << 5; set => RIB0 = (byte)(RIB0 & ~(1 << 5) | (value ? 1 << 5 : 0)); } // Earth Ribbon
public bool RibbonWorld { get => (RIB0 & (1 << 6)) == 1 << 6; set => RIB0 = (byte)(RIB0 & ~(1 << 6) | (value ? 1 << 6 : 0)); } // World Ribbon
public bool RibbonEvent { get => (RIB0 & (1 << 7)) == 1 << 7; set => RIB0 = (byte)(RIB0 & ~(1 << 7) | (value ? 1 << 7 : 0)); } // Event Ribbon
private byte RIB1 { get => Data[0x75]; set => Data[0x75] = value; }
public bool RibbonChampionWorld { get => (RIB1 & (1 << 0)) == 1 << 0; set => RIB1 = (byte)(RIB1 & ~(1 << 0) | (value ? 1 << 0 : 0)); } // World Champ Ribbon
public bool RibbonBirthday { get => (RIB1 & (1 << 1)) == 1 << 1; set => RIB1 = (byte)(RIB1 & ~(1 << 1) | (value ? 1 << 1 : 0)); } // Birthday Ribbon
public bool RibbonSpecial { get => (RIB1 & (1 << 2)) == 1 << 2; set => RIB1 = (byte)(RIB1 & ~(1 << 2) | (value ? 1 << 2 : 0)); } // Special Ribbon
public bool RibbonSouvenir { get => (RIB1 & (1 << 3)) == 1 << 3; set => RIB1 = (byte)(RIB1 & ~(1 << 3) | (value ? 1 << 3 : 0)); } // Souvenir Ribbon
public bool RibbonWishing { get => (RIB1 & (1 << 4)) == 1 << 4; set => RIB1 = (byte)(RIB1 & ~(1 << 4) | (value ? 1 << 4 : 0)); } // Wishing Ribbon
public bool RibbonClassic { get => (RIB1 & (1 << 5)) == 1 << 5; set => RIB1 = (byte)(RIB1 & ~(1 << 5) | (value ? 1 << 5 : 0)); } // Classic Ribbon
public bool RibbonPremier { get => (RIB1 & (1 << 6)) == 1 << 6; set => RIB1 = (byte)(RIB1 & ~(1 << 6) | (value ? 1 << 6 : 0)); } // Premier Ribbon
public bool RIB1_7 { get => (RIB1 & (1 << 7)) == 1 << 7; set => RIB1 = (byte)(RIB1 & ~(1 << 7) | (value ? 1 << 7 : 0)); } // Empty
// Meta Accessible Properties
public int[] IVs
{
get => 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 => 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 bool IsNicknamed => Nickname.Length > 0 || IsEgg;
public override int[] Moves
{
get => new[] { Move1, Move2, Move3, Move4 };
set
{
if (value.Length > 0) Move1 = value[0];
if (value.Length > 1) Move2 = value[1];
if (value.Length > 2) Move3 = value[2];
if (value.Length > 3) Move4 = value[3];
}
}
public override int[] RelearnMoves
{
get => new[] { RelearnMove1, RelearnMove2, RelearnMove3, RelearnMove4 };
set
{
if (value.Length > 0) RelearnMove1 = value[0];
if (value.Length > 1) RelearnMove2 = value[1];
if (value.Length > 2) RelearnMove3 = value[2];
if (value.Length > 3) RelearnMove4 = value[3];
}
}
public override PKM convertToPKM(SaveFile SAV)
{
if (!IsPokémon)
return null;
int currentLevel = Level > 0 ? Level : (int)(Util.rnd32()%100 + 1);
int metLevel = MetLevel > 0 ? MetLevel : currentLevel;
var pi = PersonalTable.SM.getFormeEntry(Species, Form);
PK7 pk = new PK7
{
Species = Species,
HeldItem = HeldItem,
TID = TID,
SID = SID,
Met_Level = metLevel,
Nature = Nature != 0xFF ? Nature : (int)(Util.rnd32() % 25),
Gender = Gender != 3 ? Gender : pi.RandomGender,
AltForm = Form,
EncryptionConstant = EncryptionConstant != 0 ? EncryptionConstant : Util.rnd32(),
Version = OriginGame != 0 ? OriginGame : SAV.Game,
Language = Language != 0 ? Language : SAV.Language,
Ball = Ball,
Country = SAV.Country,
Region = SAV.SubRegion,
ConsoleRegion = SAV.ConsoleRegion,
Move1 = Move1, Move2 = Move2, Move3 = Move3, Move4 = Move4,
RelearnMove1 = RelearnMove1, RelearnMove2 = RelearnMove2,
RelearnMove3 = RelearnMove3, RelearnMove4 = RelearnMove4,
Met_Location = MetLocation,
Egg_Location = EggLocation,
CNT_Cool = CNT_Cool,
CNT_Beauty = CNT_Beauty,
CNT_Cute = CNT_Cute,
CNT_Smart = CNT_Smart,
CNT_Tough = CNT_Tough,
CNT_Sheen = CNT_Sheen,
OT_Name = OT.Length > 0 ? OT : SAV.OT,
OT_Gender = OTGender != 3 ? OTGender % 2 : SAV.Gender,
HT_Name = OT.Length > 0 ? SAV.OT : "",
HT_Gender = OT.Length > 0 ? SAV.Gender : 0,
CurrentHandler = OT.Length > 0 ? 1 : 0,
EXP = PKX.getEXP(currentLevel, Species),
// Ribbons
RibbonCountry = RibbonCountry,
RibbonNational = RibbonNational,
RibbonEarth = RibbonEarth,
RibbonWorld = RibbonWorld,
RibbonClassic = RibbonClassic,
RibbonPremier = RibbonPremier,
RibbonEvent = RibbonEvent,
RibbonBirthday = RibbonBirthday,
RibbonSpecial = RibbonSpecial,
RibbonSouvenir = RibbonSouvenir,
RibbonWishing = RibbonWishing,
RibbonChampionBattle = RibbonChampionBattle,
RibbonChampionRegional = RibbonChampionRegional,
RibbonChampionNational = RibbonChampionNational,
RibbonChampionWorld = RibbonChampionWorld,
OT_Friendship = pi.BaseFriendship,
OT_Intensity = OT_Intensity,
OT_Memory = OT_Memory,
OT_TextVar = OT_TextVar,
OT_Feeling = OT_Feeling,
FatefulEncounter = true,
EVs = EVs,
};
pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship;
pk.Move1_PP = pk.getMovePP(Move1, 0);
pk.Move2_PP = pk.getMovePP(Move2, 0);
pk.Move3_PP = pk.getMovePP(Move3, 0);
pk.Move4_PP = pk.getMovePP(Move4, 0);
if (OTGender == 3)
{
pk.TID = SAV.TID;
pk.SID = SAV.SID;
}
pk.MetDate = Date ?? DateTime.Now;
pk.IsNicknamed = IsNicknamed;
pk.Nickname = IsNicknamed ? Nickname : PKX.getSpeciesName(Species, pk.Language);
// More 'complex' logic to determine final values
// Dumb way to generate random IVs.
int[] finalIVs = new int[6];
switch (IVs[0])
{
case 0xFE:
do { // 3 Perfect IVs
for (int i = 0; i < 6; i++)
finalIVs[i] = IVs[i] > 31 ? (int)(Util.rnd32() & 0x1F) : IVs[i];
} while (finalIVs.Count(r => r == 31) < 3); // 3*31
break;
case 0xFD:
do { // 2 other 31s
for (int i = 0; i < 6; i++)
finalIVs[i] = IVs[i] > 31 ? (int)(Util.rnd32() & 0x1F) : IVs[i];
} while (finalIVs.Count(r => r == 31) < 2); // 2*31
break;
default: // Random IVs
for (int i = 0; i < 6; i++)
finalIVs[i] = IVs[i] > 31 ? (int)(Util.rnd32() & 0x1F) : IVs[i];
break;
}
pk.IVs = finalIVs;
int av = 0;
switch (AbilityType)
{
case 00: // 0 - 0
case 01: // 1 - 1
case 02: // 2 - H
av = AbilityType;
break;
case 03: // 0/1
case 04: // 0/1/H
av = (int)(Util.rnd32()%(AbilityType - 1));
break;
}
pk.Ability = pi.Abilities[av];
pk.AbilityNumber = 1 << av;
switch (PIDType)
{
case 00: // Specified
pk.PID = PID;
break;
case 01: // Random
pk.PID = Util.rnd32();
break;
case 02: // Random Shiny
pk.PID = Util.rnd32();
pk.PID = (uint)(((TID ^ SID ^ (pk.PID & 0xFFFF)) << 16) + (pk.PID & 0xFFFF));
break;
case 03: // Random Nonshiny
pk.PID = Util.rnd32();
if ((uint)(((TID ^ SID ^ (pk.PID & 0xFFFF)) << 16) + (pk.PID & 0xFFFF)) < 16) pk.PID ^= 0x10000000;
break;
}
if (IsEgg)
{
pk.IsEgg = true;
pk.EggMetDate = Date;
pk.Nickname = PKX.getSpeciesName(0, pk.Language);
}
pk.RefreshChecksum();
return pk;
}
}
}