Refactoring

reduce pk3/ck3/xk3 logic, share AbilityBit property within _K3, and when
loading, type check (favored over hardcoding individual load cases)
pull some non-gui code from PKMEditor to core/etc for general data
fetching
This commit is contained in:
Kurt 2018-07-06 17:37:07 -07:00
parent fe82fe8eab
commit e588565657
10 changed files with 119 additions and 151 deletions

View file

@ -54,6 +54,7 @@ namespace PKHeX.Core
public static IReadOnlyList<ComboItem> LegalMoveDataSource => Strings.LegalMoveDataSource;
public static IReadOnlyList<ComboItem> HaXMoveDataSource => Strings.HaXMoveDataSource;
public static IReadOnlyList<ComboItem> MoveDataSource => Strings.MoveDataSource;
public static IReadOnlyList<ComboItem> LanguageDataSource(int gen) => GameStrings.LanguageDataSource(gen);
/// <summary>

View file

@ -482,5 +482,28 @@ namespace PKHeX.Core
return MetGen6;
}
private static readonly IReadOnlyList<ComboItem> LanguageList = Util.GetUnsortedCBList("languages");
public static IReadOnlyList<ComboItem> LanguageDataSource(int gen)
{
var languages = LanguageList.ToList();
Util.GetUnsortedCBList("languages");
if (gen == 3)
languages.RemoveAll(l => l.Value >= (int)LanguageID.Korean);
else if (gen < 7)
languages.RemoveAll(l => l.Value > (int)LanguageID.Korean);
return languages;
}
private static readonly string[] abilIdentifier = { " (1)", " (2)", " (H)" };
public IReadOnlyList<ComboItem> GetAbilityDataSource(IEnumerable<int> abils)
{
return abils.Select(GetItem).ToList();
ComboItem GetItem(int ability, int index) => new ComboItem
{
Value = ability,
Text = GameInfo.Strings.abilitylist[ability] + abilIdentifier[index]
};
}
}
}

View file

@ -163,7 +163,7 @@ namespace PKHeX.Core
public override int PKRS_Strain { get => Data[0xCA] & 0xF; set => Data[0xCA] = (byte)(value & 0xF); }
public override bool IsEgg { get => Data[0xCB] == 1; set => Data[0xCB] = (byte)(value ? 1 : 0); }
public override int AbilityNumber { get => 1 << Data[0xCC]; set => Data[0xCC] = (byte)((value >> 1) & 1); }
public override bool AbilityBit { get => Data[0xCC] == 1; set => Data[0xCC] = (byte)(value ? 1 : 0); }
public override bool Valid { get => Data[0xCD] == 0; set { if (value) Data[0xCD] = 0; } }
// 0xCE unknown
public override int MarkValue { get => SwapBits(Data[0xCF], 1, 2); protected set => Data[0xCF] = (byte)SwapBits(value, 1, 2); }

View file

@ -109,7 +109,7 @@ namespace PKHeX.Core
public override int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); }
public override int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); }
private bool egg { get => ((IV32 >> 30) & 1) == 1; set => IV32 = (uint)((IV32 & ~0x40000000) | (uint)(value ? 0x40000000 : 0)); }
public bool AbilityBit { get => IV32 >> 31 == 1; set => IV32 = (IV32 & 0x7FFFFFFF) | (uint)(value ? 1 << 31 : 0); }
public override bool AbilityBit { get => IV32 >> 31 == 1; set => IV32 = (IV32 & 0x7FFFFFFF) | (uint)(value ? 1 << 31 : 0); }
private uint RIB0 { get => BitConverter.ToUInt32(Data, 0x4C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x4C); }
public override int RibbonCountG3Cool { get => (int)(RIB0 >> 00) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 00)) | (uint)(value & 7) << 00); }
@ -147,7 +147,6 @@ namespace PKHeX.Core
public override int Stat_SPD { get => BitConverter.ToUInt16(Data, 0x62); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x62); }
// Generated Attributes
public override int AbilityNumber { get => 1 << (AbilityBit ? 1 : 0); set => AbilityBit = value > 1; } // 1/2 -> 0/1
public override bool Japanese => IsEgg || Language == (int)LanguageID.Japanese;
protected override byte[] Encrypt()

View file

@ -26,7 +26,7 @@
public override bool WasGiftEgg => IsEgg && Met_Location == 253; // Gift Egg, indistinguible from normal eggs after hatch
public override bool WasEventEgg => IsEgg && Met_Location == 255; // Event Egg, indistinguible from normal eggs after hatch
public override int Ability { get { var pi = (PersonalInfoG3)PersonalInfo; return pi.Abilities[pi.HasSecondAbility ? AbilityNumber >> 1 : 0]; } set { } }
public override int Ability { get { var pi = (PersonalInfoG3)PersonalInfo; return pi.Abilities[pi.HasSecondAbility && AbilityBit ? 1 : 0]; } set { } }
public override uint EncryptionConstant { get => PID; set { } }
public override int Nature { get => (int)(PID % 25); set { } }
public override int AltForm { get => Species == 201 ? PKX.GetUnownForm(PID) : 0; set { } }
@ -37,6 +37,9 @@
public override int CurrentHandler { get => 0; set { } }
public override int Egg_Location { get => 0; set { } }
public override int AbilityNumber { get => 1 << (AbilityBit ? 1 : 0); set => AbilityBit = value > 1; } // [0,1]->[1,2] ; [1,x]->[0,1]
public abstract bool AbilityBit { get; set; }
public abstract bool RibbonEarth { get; set; }
public abstract bool RibbonNational { get; set; }
public abstract bool RibbonCountry { get; set; }

View file

@ -689,5 +689,31 @@ namespace PKHeX.Core
// AO
015, 018, 080, 208, 254, 260, 302, 319, 323, 334, 362, 373, 376, 384, 428, 475, 531, 719,
};
/// <summary>
/// Checks if the <see cref="PKM"/> data should have a drop-down selection visible for the <see cref="PKM.AltForm"/> value.
/// </summary>
/// <param name="pi">Game specific personal info</param>
/// <param name="species"><see cref="PKM.Species"/> ID</param>
/// <param name="format"><see cref="PKM.AltForm"/> ID</param>
/// <returns>True if has formes that can be provided by <see cref="GetFormList"/>, otherwise false for none.</returns>
public static bool HasFormSelection(PersonalInfo pi, int species, int format)
{
if (format <= 3 && species != 201)
return false;
if (HasFormeValuesNotIndicatedByPersonal.Contains(species))
return true;
int count = pi.FormeCount;
return count > 1;
}
private static readonly HashSet<int> HasFormeValuesNotIndicatedByPersonal = new HashSet<int>
{
201, // Unown
414, // Mothim (Burmy forme carried over, not cleared)
664, 665, // Vivillon pre-evos
};
}
}

View file

@ -60,7 +60,7 @@ namespace PKHeX.Core
public bool UnusedFlag3 { get => (XDPKMFLAGS & (1 << 3)) == 1 << 3; set => XDPKMFLAGS = XDPKMFLAGS & ~(1 << 3) | (value ? 1 << 3 : 0); }
public bool BlockTrades { get => (XDPKMFLAGS & (1 << 4)) == 1 << 4; set => XDPKMFLAGS = XDPKMFLAGS & ~(1 << 4) | (value ? 1 << 4 : 0); }
public override bool Valid { get => (XDPKMFLAGS & (1 << 5)) == 0; set => XDPKMFLAGS = XDPKMFLAGS & ~(1 << 5) | (value ? 0 : 1 << 5); } // invalid flag
public override int AbilityNumber { get => 1 << ((XDPKMFLAGS >> 6) & 1); set => XDPKMFLAGS = XDPKMFLAGS & ~(1 << 6) | (((value >> 1) & 1) << 6); }
public override bool AbilityBit { get => 1 << ((XDPKMFLAGS >> 6) & 1) == 1; set => XDPKMFLAGS = XDPKMFLAGS & ~(1 << 6) | ((value ? 1 : 0) << 6); }
public override bool IsEgg { get => (XDPKMFLAGS & (1 << 7)) == 1 << 7; set => XDPKMFLAGS = XDPKMFLAGS & ~(1 << 7) | (value ? 1 << 7 : 0); }
// 0x1E-0x1F Unknown
public override uint EXP { get => BigEndian.ToUInt32(Data, 0x20); set => BigEndian.GetBytes(value).CopyTo(Data, 0x20); }

View file

@ -6,7 +6,7 @@ namespace PKHeX.WinForms.Controls
{
private void PopulateFieldsPK3()
{
if (!(pkm is PK3 pk3))
if (!(pkm is _K3 pk3))
return;
LoadMisc1(pk3);
@ -14,92 +14,30 @@ namespace PKHeX.WinForms.Controls
LoadMisc3(pk3);
CB_Ability.SelectedIndex = pk3.AbilityBit && CB_Ability.Items.Count > 1 ? 1 : 0;
if (pk3 is IShadowPKM s)
LoadShadow3(s);
LoadPartyStats(pk3);
UpdateStats();
}
private void PopulateFieldsCK3()
{
if (!(pkm is CK3 ck3))
return;
LoadMisc1(ck3);
LoadMisc2(ck3);
LoadMisc3(ck3);
int abil = ck3.AbilityNumber >> 1;
CB_Ability.SelectedIndex = abil >= CB_Ability.Items.Count ? 0 : abil;
LoadShadow3(ck3);
LoadPartyStats(ck3);
UpdateStats();
}
private void PopulateFieldsXK3()
{
if (!(pkm is XK3 xk3))
return;
LoadMisc1(xk3);
LoadMisc2(xk3);
LoadMisc3(xk3);
int abil = xk3.AbilityNumber >> 1;
CB_Ability.SelectedIndex = abil >= CB_Ability.Items.Count ? 0 : abil;
LoadShadow3(xk3);
LoadPartyStats(xk3);
UpdateStats();
}
private PKM PreparePK3()
{
if (!(pkm is PK3 pk3))
if (!(pkm is _K3 pk3))
return null;
SaveMisc1(pk3);
SaveMisc2(pk3);
SaveMisc3(pk3);
pk3.AbilityNumber = 1 << CB_Ability.SelectedIndex;
pk3.AbilityBit = CB_Ability.SelectedIndex != 0;
if (pkm is IShadowPKM ck3)
SaveShadow3(ck3);
SavePartyStats(pk3);
pk3.FixMoves();
pk3.RefreshChecksum();
return pk3;
}
private PKM PrepareCK3()
{
if (!(pkm is CK3 ck3))
return null;
SaveMisc1(ck3);
SaveMisc2(ck3);
SaveMisc3(ck3);
ck3.AbilityNumber = 1 << CB_Ability.SelectedIndex; // to match gen6+
SaveShadow3(ck3);
SavePartyStats(ck3);
ck3.FixMoves();
ck3.RefreshChecksum();
return ck3;
}
private PKM PrepareXK3()
{
if (!(pkm is XK3 xk3))
return null;
SaveMisc1(xk3);
SaveMisc2(xk3);
SaveMisc3(xk3);
xk3.AbilityNumber = 1 << CB_Ability.SelectedIndex; // to match gen6+
SaveShadow3(xk3);
SavePartyStats(xk3);
xk3.FixMoves();
xk3.RefreshChecksum();
return xk3;
}
}
}

View file

@ -148,23 +148,14 @@ namespace PKHeX.WinForms.Controls
GetPKMfromFields = PreparePK2;
break;
case 3:
if (pkm is CK3)
{
GetFieldsfromPKM = PopulateFieldsCK3;
GetPKMfromFields = PrepareCK3;
extraBytes = CK3.ExtraBytes;
break;
}
if (pkm is XK3)
{
GetFieldsfromPKM = PopulateFieldsXK3;
GetPKMfromFields = PrepareXK3;
extraBytes = XK3.ExtraBytes;
break;
}
GetFieldsfromPKM = PopulateFieldsPK3;
GetPKMfromFields = PreparePK3;
extraBytes = PK3.ExtraBytes;
switch (pkm)
{
case CK3 _: extraBytes = CK3.ExtraBytes; break;
case XK3 _: extraBytes = XK3.ExtraBytes; break;
default: extraBytes = PK3.ExtraBytes; break;
}
break;
case 4:
GetFieldsfromPKM = PopulateFieldsPK4;
@ -345,21 +336,16 @@ namespace PKHeX.WinForms.Controls
if (TB_OTt2.Text.Length > 0)
Label_CTGender.Text = gendersymbols[SAV.Gender & 1];
}
private void SetForms()
{
int species = WinFormsUtil.GetIndex(CB_Species);
if (pkm.Format < 4 && species != 201)
{
Label_Form.Visible = CB_Form.Visible = CB_Form.Enabled = false;
return;
}
int count = (RequestSaveFile?.Personal[species] ?? pkm.PersonalInfo).FormeCount;
bool hasForms = count > 1 || new[] { 201, 664, 665, 414 }.Contains(species);
int species = pkm.Species;
var pi = RequestSaveFile?.Personal[species] ?? pkm.PersonalInfo;
bool hasForms = FormConverter.HasFormSelection(pi, species, pkm.Format);
CB_Form.Enabled = CB_Form.Visible = Label_Form.Visible = hasForms;
if (HaX && pkm.Format >= 4)
Label_Form.Visible = true;
Label_Form.Visible = true; // show with value entry textbox
if (!hasForms)
return;
@ -367,7 +353,8 @@ namespace PKHeX.WinForms.Controls
var ds = PKX.GetFormList(species, GameInfo.Strings.types, GameInfo.Strings.forms, gendersymbols, pkm.Format).ToList();
if (ds.Count == 1 && string.IsNullOrEmpty(ds[0])) // empty (Alolan Totems)
CB_Form.Enabled = CB_Form.Visible = Label_Form.Visible = false;
else CB_Form.DataSource = ds;
else
CB_Form.DataSource = ds;
}
private void SetAbilityList()
{
@ -388,22 +375,6 @@ namespace PKHeX.WinForms.Controls
}
private static int GetSafeIndex(ComboBox cb, int index) => Math.Max(0, Math.Min(cb.Items.Count - 1, index));
private static readonly string[] abilIdentifier = { " (1)", " (2)", " (H)" };
private static List<ComboItem> GetAbilityList(PKM pkm)
{
var abils = pkm.PersonalInfo.Abilities;
if (pkm.Format == 3 && abils[1] == abils[0])
abils = new[] {abils[0]};
return abils.Select(GetItem).ToList();
ComboItem GetItem(int ability, int index) => new ComboItem
{
Value = ability,
Text = GameInfo.Strings.abilitylist[ability] + abilIdentifier[index]
};
}
private void SetIsShiny(object sender)
{
if (sender == TB_PID)
@ -512,8 +483,6 @@ namespace PKHeX.WinForms.Controls
}
else if (pkm.Format <= 4)
{
if (FieldsLoaded)
pkm.Species = WinFormsUtil.GetIndex(CB_Species);
pkm.Version = WinFormsUtil.GetIndex(CB_GameOrigin);
pkm.Nature = WinFormsUtil.GetIndex(CB_Nature);
pkm.AltForm = CB_Form.SelectedIndex;
@ -1320,7 +1289,7 @@ namespace PKHeX.WinForms.Controls
SetIsShiny(sender);
UpdateSprite();
Stats.UpdateIVs(null, null); // If the EC is changed, EC%6 (Characteristic) might be changed.
Stats.UpdateCharacteristic(); // If the EC is changed, EC%6 (Characteristic) might be changed.
if (pkm.Format <= 4 && FieldsLoaded)
{
FieldsLoaded = false;
@ -1377,34 +1346,38 @@ namespace PKHeX.WinForms.Controls
}
private void ValidateComboBox2(object sender, EventArgs e)
{
if (!FieldsInitialized)
if (!FieldsInitialized || !FieldsLoaded)
return;
ValidateComboBox(sender, null);
if (FieldsLoaded)
if (sender == CB_Ability)
{
if (sender == CB_Ability && pkm.Format >= 6)
if (pkm.Format >= 6)
TB_AbilityNumber.Text = (1 << CB_Ability.SelectedIndex).ToString();
if (sender == CB_Ability && pkm.Format <= 5 && CB_Ability.SelectedIndex < 2) // not hidden
else if (pkm.Format <= 5 && CB_Ability.SelectedIndex < 2) // Format <= 5, not hidden
UpdateRandomPID(sender, e);
if (sender == CB_Nature && pkm.Format <= 4)
{
pkm.Nature = CB_Nature.SelectedIndex;
UpdateRandomPID(sender, e);
}
if (sender == CB_HeldItem || sender == CB_Ability)
UpdateLegality();
UpdateLegality();
}
else if (sender == CB_Nature)
{
pkm.Nature = CB_Nature.SelectedIndex;
if (pkm.Format <= 4)
UpdateRandomPID(sender, e);
UpdateNatureModification(sender, EventArgs.Empty);
Stats.UpdateIVs(null, EventArgs.Empty); // updating Nature will trigger stats to update as well
UpdateLegality();
}
else if (sender == CB_HeldItem)
{
UpdateLegality();
}
UpdateNatureModification(sender, null);
Stats.UpdateIVs(null, null); // updating Nature will trigger stats to update as well
}
private void ValidateMove(object sender, EventArgs e)
{
if (!FieldsInitialized)
return;
ValidateComboBox(sender);
if (!FieldsLoaded)
if (!FieldsInitialized || !FieldsLoaded)
return;
ValidateComboBox(sender);
if (Moves.Contains(sender)) // Move
UpdatePP(sender, e);
@ -1470,18 +1443,14 @@ namespace PKHeX.WinForms.Controls
/// <param name="pk">Pokémon data to edit</param>
public bool ToggleInterface(SaveFile sav, PKM pk)
{
if (pk.GetType() != sav.PKMType || pkm.Format < 3)
pk = sav.BlankPKM;
pkm = pk;
ToggleInterface(pkm.Format);
ToggleInterface(pkm.GetType());
pkm = GetCompatiblePKM(sav, pk);
ToggleInterface(pkm);
return FinalizeInterface(sav);
}
private void ToggleInterface(Type t)
private void ToggleInterface(PKM t)
{
FLP_Purification.Visible = FLP_ShadowID.Visible = t == typeof(XK3) || t == typeof(CK3);
FLP_Purification.Visible = FLP_ShadowID.Visible = t is IShadowPKM;
ToggleInterface(pkm.Format);
}
private void ToggleInterface(int gen)
{
@ -1661,12 +1630,7 @@ namespace PKHeX.WinForms.Controls
if (SAV.Generation > 1)
CB_HeldItem.DataSource = new BindingSource(GameInfo.ItemDataSource.Where(i => i.Value <= SAV.MaxItemID).ToList(), null);
var languages = Util.GetUnsortedCBList("languages");
if (SAV.Generation == 3)
languages.RemoveAll(l => l.Value >= (int)LanguageID.Korean);
else if (SAV.Generation < 7)
languages.RemoveAll(l => l.Value > (int)LanguageID.Korean);
CB_Language.DataSource = languages;
CB_Language.DataSource = GameInfo.LanguageDataSource(SAV.Generation);
CB_Ball.DataSource = new BindingSource(GameInfo.BallDataSource.Where(b => b.Value <= SAV.MaxBallID).ToList(), null);
CB_Species.DataSource = new BindingSource(GameInfo.SpeciesDataSource.Where(s => s.Value <= SAV.MaxSpeciesID).ToList(), null);
@ -1697,6 +1661,19 @@ namespace PKHeX.WinForms.Controls
suggestion.Add($"{MsgPKMSuggestionLevel} {minlvl}");
return suggestion;
}
private static IReadOnlyList<ComboItem> GetAbilityList(PKM pkm)
{
var abils = pkm.PersonalInfo.Abilities;
if (pkm.Format == 3 && abils[1] == abils[0])
abils = new[] { abils[0] };
return GameInfo.Strings.GetAbilityDataSource(abils);
}
private static PKM GetCompatiblePKM(SaveFile sav, PKM current)
{
if (current.Format < 3 || current.GetType() != sav.PKMType)
return sav.BlankPKM;
return current;
}
private static void InitializeBinding(ListControl cb)
{
cb.DisplayMember = nameof(ComboItem.Text);

View file

@ -285,6 +285,7 @@ namespace PKHeX.WinForms.Controls
LoadIVs(pkm.SetRandomIVs());
}
public void UpdateCharacteristic() => UpdateCharacteristic(pkm.Characteristic);
private void UpdateCharacteristic(int characteristic)
{
L_Characteristic.Visible = Label_CharacteristicPrefix.Visible = characteristic > -1;