Implement PK1 loading/editing/saving.

This commit is contained in:
Michael Scire 2016-08-28 22:21:55 -07:00
parent 4738a2c716
commit 8cfe57d504
8 changed files with 93 additions and 23 deletions

View file

@ -237,7 +237,7 @@ namespace PKHeX
SaveFileDialog sfd = new SaveFileDialog
{
Filter = $"Decrypted PKM File|*.{pkx}" +
$"|Encrypted PKM File|*.{ekx}" +
(SAV.Generation > 2 ? "" : $"|Encrypted PKM File|*.{ekx}") +
"|Binary File|*.bin" +
"|All Files|*.*",
DefaultExt = pkx,
@ -592,6 +592,8 @@ namespace PKHeX
PKM pk = PKMConverter.convertToFormat(temp, SAV.Generation, out c);
if (pk == null)
Util.Alert("Conversion failed.", c);
else if (SAV.Generation == 1 && ((PK1) pk).Japanese != SAV.GetJapanese)
Util.Alert(string.Format("Cannot load {0} PK1 in {1} save file.", SAV.GetJapanese ? "an International" : "a Japanese", SAV.GetJapanese ? "a Japanese" : "an International"));
else
populateFields(pk);
Console.WriteLine(c);
@ -848,7 +850,23 @@ namespace PKHeX
Label_CharacteristicPrefix.Visible = L_Characteristic.Visible = SAV.Generation > 1;
Label_ContestStats.Visible = Label_Cool.Visible = Label_Tough.Visible = Label_Smart.Visible =
Label_Sheen.Visible = Label_Beauty.Visible = Label_Cute.Visible = TB_Cool.Visible = TB_Tough.Visible =
TB_Smart.Visible = TB_Sheen.Visible = TB_Beauty.Visible = TB_Cute.Visible = SAV.Generation >= 3;
TB_Smart.Visible = TB_Sheen.Visible = TB_Beauty.Visible = TB_Cute.Visible = Label_Nature.Visible =
CB_Nature.Visible = Label_Language.Visible = CB_Language.Visible = Label_Ability.Visible =
Label_Friendship.Visible = Label_HatchCounter.Visible = TB_Friendship.Visible = BTN_RerollPID.Visible =
Label_PID.Visible = TB_PID.Visible = Label_SID.Visible = TB_SID.Visible = SAV.Generation >= 3;
// Met Tab
CHK_Fateful.Visible = Label_OriginGame.Visible = Label_Ball.Visible = Label_MetLevel.Visible =
Label_MetLocation.Visible = CB_GameOrigin.Visible = CB_Ball.Visible = CB_MetLocation.Visible =
TB_MetLevel.Visible = SAV.Generation > 2;
CHK_Infected.Visible = CHK_Cured.Visible = SAV.Generation >= 3;
CHK_IsEgg.Visible = Label_Gender.Visible = SAV.Generation > 1;
Label_OTGender.Visible = SAV.Generation > 1;
CHK_Nicknamed.Enabled = SAV.Generation > 2;
if (1 <= sav.Generation && sav.Generation <= 2)
{
@ -922,7 +940,7 @@ namespace PKHeX
bool init = fieldsInitialized;
fieldsInitialized = false;
populateFilteredDataSources();
populateFields(pkm.Format != SAV.Generation ? SAV.BlankPKM : pk);
populateFields((pkm.Format != SAV.Generation || SAV.Generation == 1) ? SAV.BlankPKM : pk);
fieldsInitialized |= init;
// SAV Specific Limits
@ -1312,8 +1330,8 @@ namespace PKHeX
bool isShiny = pkm.IsShiny;
// Set the Controls
BTN_Shinytize.Visible = BTN_Shinytize.Enabled = !isShiny;
Label_IsShiny.Visible = isShiny;
BTN_Shinytize.Visible = BTN_Shinytize.Enabled = !isShiny && SAV.Generation > 2;
Label_IsShiny.Visible = isShiny && SAV.Generation > 1;
// Refresh Markings (for Shiny Star if applicable)
setMarkings();
@ -1686,6 +1704,7 @@ namespace PKHeX
}
private void updateRandomEVs(object sender, EventArgs e)
{
changingFields = true;
if (ModifierKeys == Keys.Control || ModifierKeys == Keys.Shift)
{
// Max EVs
@ -1706,6 +1725,8 @@ namespace PKHeX
TB_SPDEV.Text = evs[4].ToString();
TB_SPEEV.Text = evs[5].ToString();
}
changingFields = false;
updateEVs(null, null);
}
private void updateRandomPID(object sender, EventArgs e)
{
@ -2174,8 +2195,9 @@ namespace PKHeX
}
}
// Display hatch counter if it is an egg, Display Friendship if it is not.
Label_HatchCounter.Visible = CHK_IsEgg.Checked;
Label_Friendship.Visible = !CHK_IsEgg.Checked;
Label_HatchCounter.Visible = CHK_IsEgg.Checked && SAV.Generation > 1;
Label_Friendship.Visible = !CHK_IsEgg.Checked && SAV.Generation > 2;
// Update image to (not) show egg.
if (!fieldsInitialized) return;
@ -2981,11 +3003,13 @@ namespace PKHeX
for (int i = 0; i < 30; i++)
{
if (i < SAV.BoxSlotCount)
getSlotFiller(boxoffset + SAV.SIZE_STORED*i, SlotPictureBoxes[i]);
{
getSlotFiller(boxoffset + SAV.SIZE_STORED * i, SlotPictureBoxes[i]);
}
else
{
SlotPictureBoxes[i].Image = null;
SlotPictureBoxes[i].BackColor = Color.Gray;
SlotPictureBoxes[i].Visible = false;
}
}
}
@ -3100,6 +3124,7 @@ namespace PKHeX
// 00s present in slot.
pb.Image = null;
pb.BackColor = Color.Transparent;
pb.Visible = true;
return;
}
PKM p = SAV.getStoredSlot(offset);
@ -3108,11 +3133,13 @@ namespace PKHeX
// Bad Egg present in slot.
pb.Image = null;
pb.BackColor = Color.Red;
pb.Visible = true;
return;
}
// Something stored in slot. Only display if species is valid.
pb.Image = p.Species == 0 ? null : p.Sprite;
pb.BackColor = Color.Transparent;
pb.Visible = true;
}
private void getSlotColor(int slot, Image color)
{

View file

@ -1,4 +1,5 @@
using System;
using System.Linq;
namespace PKHeX
{
@ -94,7 +95,6 @@ namespace PKHeX
pk1.IV_SPE = Util.ToInt32(TB_SPEIV.Text);
pk1.IV_SPA = Util.ToInt32(TB_SPAIV.Text);
pk1.OT_Name = TB_OT.Text;
// Toss in Party Stats

View file

@ -8,8 +8,8 @@ namespace PKHeX
class PK1 : PKM
{
// Internal use only
protected byte[] otname;
protected byte[] nick;
protected internal byte[] otname;
protected internal byte[] nick;
public byte[] OT_Name_Raw => (byte[])otname.Clone();
public byte[] Nickname_Raw => (byte[])nick.Clone();
@ -24,6 +24,8 @@ namespace PKHeX
public bool Japanese => otname.Length == STRLEN_J;
public override string FileName => $"{Species.ToString("000")} - {Nickname} - {OT_Name}.{Extension}";
public PK1(byte[] decryptedData = null, string ident = null, bool jp = false)
{
Data = (byte[])(decryptedData ?? new byte[SIZE_PARTY]).Clone();
@ -41,7 +43,7 @@ namespace PKHeX
public override PKM Clone()
{
PK1 new_pk1 = new PK1(Data);
PK1 new_pk1 = new PK1(Data, Identifier, Japanese);
Array.Copy(otname, 0, new_pk1.otname, 0, otname.Length);
Array.Copy(nick, 0, new_pk1.nick, 0, nick.Length);
return new_pk1;
@ -53,7 +55,15 @@ namespace PKHeX
{
byte[] strdata = PKX.setG1Str(value, Japanese);
if (strdata.Length > StringLength)
throw new ArgumentOutOfRangeException("OT Name too long for given PK1");
throw new ArgumentOutOfRangeException($"Nickname {value} too long for given PK1");
if (nick.Any(b => b == 0) && nick[StringLength - 1] == 0x50 && Array.FindIndex(nick, b => b == 0) == strdata.Length - 1) // Handle JP Mew event with grace
{
int firstInd = Array.FindIndex(nick, b => b == 0);
for (int i = firstInd; i < StringLength - 1; i++)
if (nick[i] != 0)
break;
strdata = strdata.Take(strdata.Length - 1).ToArray();
}
strdata.CopyTo(nick, 0);
}
}
@ -65,7 +75,15 @@ namespace PKHeX
{
byte[] strdata = PKX.setG1Str(value, Japanese);
if (strdata.Length > StringLength)
throw new ArgumentOutOfRangeException("OT Name too long for given PK1");
throw new ArgumentOutOfRangeException($"OT Name {value} too long for given PK1");
if (otname.Any(b => b == 0) && otname[StringLength - 1] == 0x50 && Array.FindIndex(otname, b => b == 0) == strdata.Length - 1) // Handle JP Mew event with grace
{
int firstInd = Array.FindIndex(otname, b => b == 0);
for (int i = firstInd; i < StringLength - 1; i++)
if (otname[i] != 0)
break;
strdata = strdata.Take(strdata.Length - 1).ToArray();
}
strdata.CopyTo(otname, 0);
}
}
@ -80,6 +98,8 @@ namespace PKHeX
// Please forgive me.
public override byte[] EncryptedPartyData => Encrypt().ToArray();
public override byte[] EncryptedBoxData => Encrypt().ToArray();
public override byte[] DecryptedBoxData => Encrypt().ToArray();
public override byte[] DecryptedPartyData => Encrypt().ToArray();
public override bool IsNicknamed { get { throw new NotImplementedException(); } set { } }
@ -119,7 +139,7 @@ namespace PKHeX
public override int EV_SPE { get { return Util.SwapEndianness(BitConverter.ToUInt16(Data, 0x17)); } set { BitConverter.GetBytes(Util.SwapEndianness((ushort)value)).CopyTo(Data, 0x17); } }
public int EV_SPC { get { return Util.SwapEndianness(BitConverter.ToUInt16(Data, 0x19)); } set { BitConverter.GetBytes(Util.SwapEndianness((ushort)value)).CopyTo(Data, 0x19); } }
public override int EV_SPA { get { return EV_SPC; } set { EV_SPC = value; } }
public override int EV_SPD { get { return EV_SPC; } set { EV_SPC = value; } }
public override int EV_SPD { get { return EV_SPC; } set { } }
public ushort DV16 { get { return Util.SwapEndianness(BitConverter.ToUInt16(Data, 0x1B)); } set { BitConverter.GetBytes(Util.SwapEndianness(value)).CopyTo(Data, 0x1B); } }
public override int IV_HP { get { return ((IV_ATK & 1) << 3) | ((IV_DEF & 1) << 2) | ((IV_SPE & 1) << 1) | ((IV_SPC & 1) << 0); } set { } }
public override int IV_ATK { get { return (DV16 >> 12) & 0xF; } set { DV16 = (ushort)((DV16 & ~(0xF << 12)) | (ushort)((value > 0xF ? 0xF : value) << 12)); } }
@ -151,7 +171,7 @@ namespace PKHeX
public int Stat_SPC { get { return Util.SwapEndianness(BitConverter.ToUInt16(Data, 0x2A)); } set { BitConverter.GetBytes(Util.SwapEndianness((ushort)value)).CopyTo(Data, 0x2A); } }
// Leave SPA and SPD as alias for SPC
public override int Stat_SPA { get { return Stat_SPC; } set { Stat_SPC = value; } }
public override int Stat_SPD { get { return Stat_SPC; } set { Stat_SPC = value; } }
public override int Stat_SPD { get { return Stat_SPC; } set { } }
#endregion
public override ushort[] getStats(PersonalInfo p)
@ -278,8 +298,8 @@ namespace PKHeX
int base_ofs = 2 + Capacity;
byte[] dat = Data.Skip(base_ofs + Entry_Size * i).Take(Entry_Size).ToArray();
Pokemon[i] = new PK1(dat, null, jp);
Pokemon[i].OT_Name = PKX.getG1Str(Data.Skip(base_ofs + Capacity * Entry_Size + StringLength * i).Take(StringLength).ToArray(), Japanese);
Pokemon[i].Nickname = PKX.getG1Str(Data.Skip(base_ofs + Capacity * Entry_Size + StringLength * Capacity + StringLength * i).Take(StringLength).ToArray(), Japanese);
Pokemon[i].otname = Data.Skip(base_ofs + Capacity * Entry_Size + StringLength * i).Take(StringLength).ToArray();
Pokemon[i].nick = Data.Skip(base_ofs + Capacity * Entry_Size + StringLength * Capacity + StringLength * i).Take(StringLength).ToArray();
}
}
@ -331,7 +351,7 @@ namespace PKHeX
{
for (int i = 0; i < Count; i++)
{
Data[1 + i] = (byte)Pokemon[i].Species;
Data[1 + i] = (byte)PKX.setG1Species(Pokemon[i].Species);
Array.Copy(Pokemon[i].Data, 0, Data, 2 + Capacity + Entry_Size * i, Entry_Size);
Array.Copy(Pokemon[i].OT_Name_Raw, 0, Data, 2 + Capacity + Capacity * Entry_Size + StringLength * i, StringLength);
Array.Copy(Pokemon[i].Nickname_Raw, 0, Data, 2 + Capacity + Capacity * Entry_Size + StringLength * Capacity + StringLength * i, StringLength);

View file

@ -261,7 +261,7 @@ namespace PKHeX
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 virtual 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 }; }

View file

@ -31,6 +31,9 @@ namespace PKHeX
switch (data.Length)
{
case PKX.SIZE_1JLIST:
case PKX.SIZE_1ULIST:
return 1;
case PKX.SIZE_3PARTY:
case PKX.SIZE_3STORED:
return 3;
@ -70,6 +73,11 @@ namespace PKHeX
checkEncrypted(ref data);
switch (getPKMDataFormat(data))
{
case 1:
var PL = new PokemonList1(data, PokemonList1.CapacityType.Single, data.Length == PKX.SIZE_1JLIST);
if (ident != null)
PL[0].Identifier = ident;
return PL[0];
case 3:
return new PK3(data, ident);
case 4:
@ -101,6 +109,17 @@ namespace PKHeX
+ "Desired Format: " + Format;
return null;
}
if ((pk.Format == 1 || pk.Format == 2) && 2 < Format && Format < 7)
{
comment = $"Cannot convert a PK{pk.Format} to a PK{Format}.";
return null;
}
if (pk.Format == 1 && Format == 7)
{
comment = "PK1 to PK7 conversion is not yet supported." + Environment.NewLine
+ "Please wait for Sun/Moon to release and documentation to occur.";
return null;
}
string currentFormat = pk.Format.ToString();
PKM pkm = pk.Clone();
if (pkm.IsEgg) // force hatch
@ -130,6 +149,7 @@ namespace PKHeX
ushort chk = 0;
switch (format)
{
case 1:
case 3: // TOneverDO, nobody exports encrypted pk3s
return;
case 4:

View file

@ -38,7 +38,7 @@ namespace PKHeX
/// <returns>A boolean indicating whether or not the length is valid for a Pokemon file.</returns>
public static bool getIsPKM(long len)
{
return new[] {SIZE_3STORED, SIZE_3PARTY, SIZE_4STORED, SIZE_4PARTY, SIZE_5PARTY, SIZE_6STORED, SIZE_6PARTY}.Contains((int)len);
return new[] {SIZE_1JLIST, SIZE_1ULIST, SIZE_3STORED, SIZE_3PARTY, SIZE_4STORED, SIZE_4PARTY, SIZE_5PARTY, SIZE_6STORED, SIZE_6PARTY}.Contains((int)len);
}
// C# PKX Function Library
@ -1852,6 +1852,7 @@ namespace PKHeX
{"ぷ", 0x46},
{"ぺ", 0x47},
{"ぽ", 0x48},
{"\0", 0x50},
{"トレーナー", 0x5D},
{"ア", 0x80},
{"イ", 0x81},

View file

@ -105,7 +105,7 @@ namespace PKHeX
// Configuration
public override SaveFile Clone() { return new SAV1(Data); }
public override SaveFile Clone() { return new SAV1(Data.Take(Data.Length - SIZE_RESERVED).ToArray()); }
public override int SIZE_STORED => Japanese ? PKX.SIZE_1JLIST : PKX.SIZE_1ULIST;
public override int SIZE_PARTY => Japanese ? PKX.SIZE_1JLIST : PKX.SIZE_1ULIST;

View file

@ -21,6 +21,8 @@ namespace PKHeX
public byte[] Footer { protected get; set; } = new byte[0]; // .dsv
public bool Japanese { protected get; set; }
public bool GetJapanese => Japanese;
// General PKM Properties
protected abstract Type PKMType { get; }
public abstract PKM getPKM(byte[] data);