Misc tweaks

Rewrites super training editor to not need reflection and special handling for translation
Fixes trash check for traded egg
Fixes Scientist trash applying to Ultra Beasts -- much better comparison
This commit is contained in:
Kurt 2024-05-30 10:40:08 -05:00
parent b7298a7361
commit 650f23ab82
10 changed files with 303 additions and 92 deletions

View file

@ -57,8 +57,7 @@ public sealed record EncounterStatic8U : EncounterStatic8Nest<EncounterStatic8U>
public bool IsShinyXorValid(ushort pkShinyXor) => pkShinyXor is > 15 or 1;
public bool ShouldHaveScientistTrash => !SpeciesCategory.IsLegendary(Species)
&& !SpeciesCategory.IsSubLegendary(Species);
public bool ShouldHaveScientistTrash => Level != 70; // Level 65, not legendary/sub-legendary/ultra beast
public static ReadOnlySpan<char> GetScientistName(int language) => language switch
{

View file

@ -0,0 +1,208 @@
using System;
namespace PKHeX.Core;
public interface ISuperTrainRegimen : ISuperTrain
{
public bool SuperTrain1_HP { get; set; }
public bool SuperTrain1_ATK { get; set; }
public bool SuperTrain1_DEF { get; set; }
public bool SuperTrain1_SPA { get; set; }
public bool SuperTrain1_SPD { get; set; }
public bool SuperTrain1_SPE { get; set; }
public bool SuperTrain2_HP { get; set; }
public bool SuperTrain2_ATK { get; set; }
public bool SuperTrain2_DEF { get; set; }
public bool SuperTrain2_SPA { get; set; }
public bool SuperTrain2_SPD { get; set; }
public bool SuperTrain2_SPE { get; set; }
public bool SuperTrain3_HP { get; set; }
public bool SuperTrain3_ATK { get; set; }
public bool SuperTrain3_DEF { get; set; }
public bool SuperTrain3_SPA { get; set; }
public bool SuperTrain3_SPD { get; set; }
public bool SuperTrain3_SPE { get; set; }
public bool SuperTrain4_1 { get; set; }
public bool SuperTrain5_1 { get; set; }
public bool SuperTrain5_2 { get; set; }
public bool SuperTrain5_3 { get; set; }
public bool SuperTrain5_4 { get; set; }
public bool SuperTrain6_1 { get; set; }
public bool SuperTrain6_2 { get; set; }
public bool SuperTrain6_3 { get; set; }
public bool SuperTrain7_1 { get; set; }
public bool SuperTrain7_2 { get; set; }
public bool SuperTrain7_3 { get; set; }
public bool SuperTrain8_1 { get; set; }
public bool DistSuperTrain1 { get; set; }
public bool DistSuperTrain2 { get; set; }
public bool DistSuperTrain3 { get; set; }
public bool DistSuperTrain4 { get; set; }
public bool DistSuperTrain5 { get; set; }
public bool DistSuperTrain6 { get; set; }
}
public static class SuperTrainRegimenExtensions
{
public const int CountRegimen = 30;
public const int CountRegimenDistribution = 6;
public static bool GetRegimenState(this ISuperTrainRegimen sr, int index) => (uint)index switch
{
00 => sr.SuperTrain1_HP,
01 => sr.SuperTrain1_ATK,
02 => sr.SuperTrain1_DEF,
03 => sr.SuperTrain1_SPA,
04 => sr.SuperTrain1_SPD,
05 => sr.SuperTrain1_SPE,
06 => sr.SuperTrain2_HP,
07 => sr.SuperTrain2_ATK,
08 => sr.SuperTrain2_DEF,
09 => sr.SuperTrain2_SPA,
10 => sr.SuperTrain2_SPD,
11 => sr.SuperTrain2_SPE,
12 => sr.SuperTrain3_HP,
13 => sr.SuperTrain3_ATK,
14 => sr.SuperTrain3_DEF,
15 => sr.SuperTrain3_SPA,
16 => sr.SuperTrain3_SPD,
17 => sr.SuperTrain3_SPE,
18 => sr.SuperTrain4_1,
19 => sr.SuperTrain5_1,
20 => sr.SuperTrain5_2,
21 => sr.SuperTrain5_3,
22 => sr.SuperTrain5_4,
23 => sr.SuperTrain6_1,
24 => sr.SuperTrain6_2,
25 => sr.SuperTrain6_3,
26 => sr.SuperTrain7_1,
27 => sr.SuperTrain7_2,
28 => sr.SuperTrain7_3,
29 => sr.SuperTrain8_1,
_ => throw new ArgumentOutOfRangeException(nameof(index)),
};
public static bool SetRegimenState(this ISuperTrainRegimen sr, int index, bool value) => (uint)index switch
{
00 => sr.SuperTrain1_HP = value,
01 => sr.SuperTrain1_ATK = value,
02 => sr.SuperTrain1_DEF = value,
03 => sr.SuperTrain1_SPA = value,
04 => sr.SuperTrain1_SPD = value,
05 => sr.SuperTrain1_SPE = value,
06 => sr.SuperTrain2_HP = value,
07 => sr.SuperTrain2_ATK = value,
08 => sr.SuperTrain2_DEF = value,
09 => sr.SuperTrain2_SPA = value,
10 => sr.SuperTrain2_SPD = value,
11 => sr.SuperTrain2_SPE = value,
12 => sr.SuperTrain3_HP = value,
13 => sr.SuperTrain3_ATK = value,
14 => sr.SuperTrain3_DEF = value,
15 => sr.SuperTrain3_SPA = value,
16 => sr.SuperTrain3_SPD = value,
17 => sr.SuperTrain3_SPE = value,
18 => sr.SuperTrain4_1 = value,
19 => sr.SuperTrain5_1 = value,
20 => sr.SuperTrain5_2 = value,
21 => sr.SuperTrain5_3 = value,
22 => sr.SuperTrain5_4 = value,
23 => sr.SuperTrain6_1 = value,
24 => sr.SuperTrain6_2 = value,
25 => sr.SuperTrain6_3 = value,
26 => sr.SuperTrain7_1 = value,
27 => sr.SuperTrain7_2 = value,
28 => sr.SuperTrain7_3 = value,
29 => sr.SuperTrain8_1 = value,
_ => throw new ArgumentOutOfRangeException(nameof(index)),
};
public static string GetRegimenName(int index) => (uint)index switch
{
00 => nameof(ISuperTrainRegimen.SuperTrain1_HP),
01 => nameof(ISuperTrainRegimen.SuperTrain1_ATK),
02 => nameof(ISuperTrainRegimen.SuperTrain1_DEF),
03 => nameof(ISuperTrainRegimen.SuperTrain1_SPA),
04 => nameof(ISuperTrainRegimen.SuperTrain1_SPD),
05 => nameof(ISuperTrainRegimen.SuperTrain1_SPE),
06 => nameof(ISuperTrainRegimen.SuperTrain2_HP),
07 => nameof(ISuperTrainRegimen.SuperTrain2_ATK),
08 => nameof(ISuperTrainRegimen.SuperTrain2_DEF),
09 => nameof(ISuperTrainRegimen.SuperTrain2_SPA),
10 => nameof(ISuperTrainRegimen.SuperTrain2_SPD),
11 => nameof(ISuperTrainRegimen.SuperTrain2_SPE),
12 => nameof(ISuperTrainRegimen.SuperTrain3_HP),
13 => nameof(ISuperTrainRegimen.SuperTrain3_ATK),
14 => nameof(ISuperTrainRegimen.SuperTrain3_DEF),
15 => nameof(ISuperTrainRegimen.SuperTrain3_SPA),
16 => nameof(ISuperTrainRegimen.SuperTrain3_SPD),
17 => nameof(ISuperTrainRegimen.SuperTrain3_SPE),
18 => nameof(ISuperTrainRegimen.SuperTrain4_1),
19 => nameof(ISuperTrainRegimen.SuperTrain5_1),
20 => nameof(ISuperTrainRegimen.SuperTrain5_2),
21 => nameof(ISuperTrainRegimen.SuperTrain5_3),
22 => nameof(ISuperTrainRegimen.SuperTrain5_4),
23 => nameof(ISuperTrainRegimen.SuperTrain6_1),
24 => nameof(ISuperTrainRegimen.SuperTrain6_2),
25 => nameof(ISuperTrainRegimen.SuperTrain6_3),
26 => nameof(ISuperTrainRegimen.SuperTrain7_1),
27 => nameof(ISuperTrainRegimen.SuperTrain7_2),
28 => nameof(ISuperTrainRegimen.SuperTrain7_3),
29 => nameof(ISuperTrainRegimen.SuperTrain8_1),
_ => throw new ArgumentOutOfRangeException(nameof(index)),
};
public static bool GetRegimenStateDistribution(this ISuperTrainRegimen sr, int index) => (uint)index switch
{
0 => sr.DistSuperTrain1,
1 => sr.DistSuperTrain2,
2 => sr.DistSuperTrain3,
3 => sr.DistSuperTrain4,
4 => sr.DistSuperTrain5,
5 => sr.DistSuperTrain6,
_ => throw new ArgumentOutOfRangeException(nameof(index)),
};
public static bool SetRegimenStateDistribution(this ISuperTrainRegimen sr, int index, bool value) => (uint)index switch
{
0 => sr.DistSuperTrain1 = value,
1 => sr.DistSuperTrain2 = value,
2 => sr.DistSuperTrain3 = value,
3 => sr.DistSuperTrain4 = value,
4 => sr.DistSuperTrain5 = value,
5 => sr.DistSuperTrain6 = value,
_ => throw new ArgumentOutOfRangeException(nameof(index)),
};
public static string GetRegimenNameDistribution(int index) => (uint)index switch
{
0 => nameof(ISuperTrainRegimen.DistSuperTrain1),
1 => nameof(ISuperTrainRegimen.DistSuperTrain2),
2 => nameof(ISuperTrainRegimen.DistSuperTrain3),
3 => nameof(ISuperTrainRegimen.DistSuperTrain4),
4 => nameof(ISuperTrainRegimen.DistSuperTrain5),
5 => nameof(ISuperTrainRegimen.DistSuperTrain6),
_ => throw new ArgumentOutOfRangeException(nameof(index)),
};
}

View file

@ -6,7 +6,7 @@ namespace PKHeX.Core;
/// <summary> Generation 6 <see cref="PKM"/> format. </summary>
public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetRibbons,
IContestStats, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection, IGroundTile, IAppliedMarkings4
IContestStats, IGeoTrack, ISuperTrainRegimen, IFormArgument, ITrainerMemories, IAffection, IGroundTile, IAppliedMarkings4
{
public override ReadOnlySpan<ushort> ExtraBytes =>
[

View file

@ -6,7 +6,7 @@ namespace PKHeX.Core;
/// <summary> Generation 7 <see cref="PKM"/> format. </summary>
public sealed class PK7 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetRibbons,
IContestStats, IHyperTrain, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection, IPokerusStatus, IAppliedMarkings7
IContestStats, IHyperTrain, IGeoTrack, ISuperTrainRegimen, IFormArgument, ITrainerMemories, IAffection, IPokerusStatus, IAppliedMarkings7
{
public override ReadOnlySpan<ushort> ExtraBytes =>
[

View file

@ -86,7 +86,7 @@ public static class TrashBytesUTF16
return TrashMatch.TooLongToTell;
var remain = span[start..];
var end = GetTerminatorIndex(span) + 1;
var end = GetTerminatorIndex(remain) + 1;
start = end * BytesPerChar;
if ((uint)start < remain.Length && !IsTrashEmpty(remain[start..]))
return TrashMatch.NotEmpty;

View file

@ -2169,7 +2169,7 @@ namespace PKHeX.WinForms.Controls
BTN_Medals.TabIndex = 29;
BTN_Medals.Text = "Medals";
BTN_Medals.UseVisualStyleBackColor = true;
BTN_Medals.Click += OpenMedals;
BTN_Medals.Click += OpenSuperTrainRegimen;
//
// BTN_History
//

View file

@ -1848,9 +1848,11 @@ public sealed partial class PKMEditor : UserControl, IMainEditor
PB_Affixed.Visible = false;
}
private void OpenMedals(object sender, EventArgs e)
private void OpenSuperTrainRegimen(object sender, EventArgs e)
{
using var form = new SuperTrainingEditor(Entity);
if (Entity is not ISuperTrainRegimen st)
return;
using var form = new SuperTrainingEditor(st);
form.ShowDialog();
}

View file

@ -1,6 +1,7 @@
using System;
using System.Text;
using System.Windows.Forms;
using PKHeX.Core;
namespace PKHeX.WinForms;
@ -8,25 +9,25 @@ public sealed partial class ErrorWindow : Form
{
public static DialogResult ShowErrorDialog(string friendlyMessage, Exception ex, bool allowContinue)
{
var lang = System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName;
string lang = GetDisplayLanguage();
using var dialog = new ErrorWindow(lang);
dialog.ShowContinue = allowContinue;
dialog.Message = friendlyMessage;
dialog.Error = ex;
dialog.LoadException(ex, friendlyMessage, allowContinue);
var dialogResult = dialog.ShowDialog();
if (dialogResult == DialogResult.Abort)
Environment.Exit(1);
return dialogResult;
}
private ErrorWindow()
private static string GetDisplayLanguage()
{
InitializeComponent();
try { return Main.CurrentLanguage; }
catch { return System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; }
}
private ErrorWindow(string lang) : this()
private ErrorWindow(string? lang = GameLanguage.DefaultLanguage)
{
WinFormsUtil.TranslateInterface(this, lang);
InitializeComponent();
WinFormsUtil.TranslateInterface(this, lang ?? GetDisplayLanguage());
}
/// <summary>
@ -62,6 +63,13 @@ public sealed partial class ErrorWindow : Form
}
}
public void LoadException(Exception ex, string friendlyMessage, bool allowContinue) => Invoke(() =>
{
ShowContinue = allowContinue;
Message = friendlyMessage;
Error = ex;
});
private void UpdateExceptionDetailsMessage()
{
var details = new StringBuilder();

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Windows.Forms;
using PKHeX.Core;
@ -8,22 +7,29 @@ namespace PKHeX.WinForms;
public partial class SuperTrainingEditor : Form
{
public SuperTrainingEditor(PKM pk)
private readonly CheckBox[] Regular;
private readonly CheckBox[] Distribution;
public SuperTrainingEditor(ISuperTrainRegimen pk)
{
Entity = (ISuperTrain)pk;
InitializeComponent();
TLP_SuperTrain.SuspendLayout();
TLP_DistSuperTrain.SuspendLayout();
Regular = CreateRegular();
Distribution = CreateDistribution();
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
int vertScrollWidth = SystemInformation.VerticalScrollBarWidth;
TLP_SuperTrain.Padding = TLP_DistSuperTrain.Padding = new Padding(0, 0, vertScrollWidth, 0);
// Updating a Control display with auto-sized elements on every row addition is cpu intensive. Disable layout updates while populating.
TLP_SuperTrain.SuspendLayout();
TLP_DistSuperTrain.SuspendLayout();
TLP_SuperTrain.Scroll += WinFormsUtil.PanelScroll;
TLP_DistSuperTrain.Scroll += WinFormsUtil.PanelScroll;
PopulateRegimens("SuperTrain", TLP_SuperTrain, reglist);
PopulateRegimens("DistSuperTrain", TLP_DistSuperTrain, distlist);
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
Entity = pk;
LoadRegimens();
ResizePanel(TLP_SuperTrain);
ResizePanel(TLP_DistSuperTrain);
TLP_SuperTrain.ResumeLayout();
TLP_DistSuperTrain.ResumeLayout();
@ -50,9 +56,48 @@ public partial class SuperTrainingEditor : Form
}
}
private readonly List<RegimenInfo> reglist = [];
private readonly List<RegimenInfo> distlist = [];
private readonly ISuperTrain Entity;
private CheckBox[] CreateRegular()
{
var result = new CheckBox[SuperTrainRegimenExtensions.CountRegimen];
TLP_SuperTrain.RowCount = result.Length;
TLP_SuperTrain.ColumnCount = 1;
for (int i = 0; i < result.Length; i++)
{
var name = SuperTrainRegimenExtensions.GetRegimenName(i);
var chk = GetCheckbox(name);
TLP_SuperTrain.Controls.Add(chk, 0, i);
result[i] = chk;
}
return result;
}
private CheckBox[] CreateDistribution()
{
var result = new CheckBox[SuperTrainRegimenExtensions.CountRegimenDistribution];
TLP_DistSuperTrain.RowCount = result.Length;
TLP_DistSuperTrain.ColumnCount = 1;
for (int i = 0; i < result.Length; i++)
{
var name = SuperTrainRegimenExtensions.GetRegimenName(i);
var chk = GetCheckbox(name);
TLP_DistSuperTrain.Controls.Add(chk, 0, i);
result[i] = chk;
}
return result;
}
private static CheckBox GetCheckbox(string name) => new()
{
Name = PrefixCHK + name,
Text = name,
AutoSize = true,
Margin = new Padding(2),
Padding = Padding.Empty,
};
private readonly ISuperTrainRegimen Entity;
private const string PrefixCHK = "CHK_";
private void B_Cancel_Click(object sender, EventArgs e) => Close();
@ -63,61 +108,29 @@ public partial class SuperTrainingEditor : Form
Close();
}
private void PopulateRegimens(string propertyPrefix, TableLayoutPanel TLP, List<RegimenInfo> list)
private static void ResizePanel(TableLayoutPanel tlp)
{
// Get a list of all Regimen Attregutes in the PKM
list.AddRange(GetBooleanRegimenNames(Entity, propertyPrefix));
TLP.ColumnCount = 1;
TLP.RowCount = 0;
// Add Regimens
foreach (var reg in list)
AddRegimenChoice(reg, TLP);
// Force auto-size
foreach (var style in TLP.RowStyles.OfType<RowStyle>())
foreach (var style in tlp.RowStyles.OfType<RowStyle>())
style.SizeType = SizeType.AutoSize;
foreach (var style in TLP.ColumnStyles.OfType<ColumnStyle>())
foreach (var style in tlp.ColumnStyles.OfType<ColumnStyle>())
style.SizeType = SizeType.AutoSize;
}
private static IEnumerable<RegimenInfo> GetBooleanRegimenNames(ISuperTrain pk, string propertyPrefix)
private void LoadRegimens()
{
var names = ReflectUtil.GetPropertiesStartWithPrefix(pk.GetType(), propertyPrefix);
foreach (var name in names)
{
var value = ReflectUtil.GetValue(pk, name);
if (value is bool state)
yield return new RegimenInfo(name, state);
}
}
private static void AddRegimenChoice(RegimenInfo reg, TableLayoutPanel TLP)
{
// Get row we add to
int row = TLP.RowCount;
TLP.RowCount++;
var chk = new CheckBox
{
Anchor = AnchorStyles.Left,
Name = PrefixCHK + reg.Name,
Margin = new Padding(2),
Text = reg.Name,
AutoSize = true,
Padding = Padding.Empty,
};
chk.CheckedChanged += (sender, e) => reg.CompletedRegimen = chk.Checked;
chk.Checked = reg.CompletedRegimen;
TLP.Controls.Add(chk, 0, row);
for (int i = 0; i < Regular.Length; i++)
Regular[i].Checked = Entity.GetRegimenState(i);
for (int i = 0; i < Distribution.Length; i++)
Distribution[i].Checked = Entity.GetRegimenStateDistribution(i);
}
private void Save()
{
foreach (var reg in reglist)
ReflectUtil.SetValue(Entity, reg.Name, reg.CompletedRegimen);
foreach (var reg in distlist)
ReflectUtil.SetValue(Entity, reg.Name, reg.CompletedRegimen);
for (int i = 0; i < Regular.Length; i++)
Entity.SetRegimenState(i, Regular[i].Checked);
for (int i = 0; i < Distribution.Length; i++)
Entity.SetRegimenStateDistribution(i, Distribution[i].Checked);
if (Entity is PK6 pk6)
{
@ -133,18 +146,6 @@ public partial class SuperTrainingEditor : Form
}
}
private sealed class RegimenInfo
{
public readonly string Name;
public bool CompletedRegimen;
internal RegimenInfo(string name, bool completedRegimen)
{
Name = name;
CompletedRegimen = completedRegimen;
}
}
private void B_All_Click(object sender, EventArgs e)
{
if (CHK_SecretUnlocked.Checked) // only give dist if Secret is Unlocked (None -> All -> All*)

View file

@ -63,7 +63,7 @@ namespace PKHeX.WinForms
WinFormsTranslator.LoadSettings<PKHeXSettings>(DefaultLanguage, false);
WinFormsTranslator.LoadAllForms(types, LoadBanlist);
WinFormsTranslator.TranslateControls(GetExtraControls());
WinFormsTranslator.RemoveAll(DefaultLanguage, PurgeBanlist); // remove all lines from above generated files that still remain
WinFormsTranslator.RemoveAll(DefaultLanguage, []); // remove all lines from above generated files that still remain
// Move translated files from the debug exe loc to their project location
var files = Directory.GetFiles(Application.StartupPath);
@ -119,13 +119,6 @@ namespace PKHeX.WinForms
$"{nameof(SAV_OPower)}.L_", // Dynamic label
];
private static readonly string[] PurgeBanlist =
[
nameof(SuperTrainingEditor),
nameof(ErrorWindow),
nameof(SettingsEditor),
];
private static void DumpStringsMessage() => DumpStrings(typeof(MessageStrings), false, "PKHeX.Core", "Resources", "text", "program");
private static void DumpStringsLegality() => DumpStrings(typeof(LegalityCheckStrings), true, "PKHeX.Core", "Resources", "legality", "checks");