PKHeX/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_PokedexLA.cs
2023-11-05 14:20:35 -08:00

498 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using PKHeX.Core;
namespace PKHeX.WinForms;
public partial class SAV_PokedexLA : Form
{
private readonly SAV8LA Origin;
private readonly SAV8LA SAV;
private readonly PokedexSave8a Dex;
private readonly CheckBox[] CHK_SeenWild;
private readonly CheckBox[] CHK_Obtained;
private readonly CheckBox[] CHK_CaughtWild;
private readonly Controls.PokedexResearchTask8aPanel[] TaskControls;
private readonly ushort[] SpeciesToDex;
private readonly ushort[] DexToSpecies;
private int lastIndex = -1;
private int lastForm = -1;
private bool Editing;
private readonly bool CanSave;
private readonly IList<ComboItem> DisplayedForms;
private readonly string[] TaskDescriptions = Util.GetStringList("tasks8a", Main.CurrentLanguage);
private readonly string[] SpeciesQuests = Util.GetStringList("species_tasks8a", Main.CurrentLanguage);
private readonly string[] TimeTaskDescriptions = Util.GetStringList("time_tasks8a", Main.CurrentLanguage);
public SAV_PokedexLA(SAV8LA sav)
{
InitializeComponent();
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
SAV = (SAV8LA)(Origin = sav).Clone();
Dex = SAV.Blocks.PokedexSave;
var speciesNames = GameInfo.Strings.Species;
CHK_SeenWild = new[] { CHK_S0, CHK_S1, CHK_S2, CHK_S3, CHK_S4, CHK_S5, CHK_S6, CHK_S7 };
CHK_Obtained = new[] { CHK_O0, CHK_O1, CHK_O2, CHK_O3, CHK_O4, CHK_O5, CHK_O6, CHK_O7 };
CHK_CaughtWild = new[] { CHK_C0, CHK_C1, CHK_C2, CHK_C3, CHK_C4, CHK_C5, CHK_C6, CHK_C7 };
TaskControls = new[]
{
PRT_1,
PRT_2,
PRT_3,
PRT_4,
PRT_5,
PRT_6,
PRT_7,
PRT_8,
PRT_9,
PRT_10,
};
foreach (var tc in TaskControls)
{
tc.Visible = false;
tc.SetStrings(TaskDescriptions, SpeciesQuests, TimeTaskDescriptions);
}
SpeciesToDex = new ushort[SAV.Personal.MaxSpeciesID + 1];
var maxDex = 0;
for (ushort s = 1; s <= SAV.Personal.MaxSpeciesID; s++)
{
var hisuiDex = PokedexSave8a.GetDexIndex(PokedexType8a.Hisui, s);
if (hisuiDex == 0)
continue;
SpeciesToDex[s] = hisuiDex;
if (hisuiDex > maxDex)
maxDex = hisuiDex;
}
DexToSpecies = new ushort[maxDex + 1];
for (ushort s = 1; s <= SAV.Personal.MaxSpeciesID; s++)
{
if (SpeciesToDex[s] != 0)
DexToSpecies[SpeciesToDex[s]] = s;
}
Editing = true;
// Clear Listbox and ComboBox
LB_Species.Items.Clear();
CB_Species.Items.Clear();
// Fill List
CB_Species.InitializeBinding();
var species = GameInfo.FilteredSources.Species.Where(z => PokedexSave8a.GetDexIndex(PokedexType8a.Hisui, (ushort)z.Value) != 0).ToArray();
CB_Species.DataSource = new BindingSource(species, null);
CB_DisplayForm.InitializeBinding();
DisplayedForms = new List<ComboItem> { new(GameInfo.Strings.types[0], 0) };
CB_DisplayForm.DataSource = new BindingSource(DisplayedForms, null);
for (var d = 1; d < DexToSpecies.Length; d++)
LB_Species.Items.Add($"{d:000} - {speciesNames[DexToSpecies[d]]}");
Editing = false;
LB_Species.SelectedIndex = 0;
CB_Species.KeyDown += WinFormsUtil.RemoveDropCB;
CanSave = true;
}
private void ChangeCBSpecies(object sender, EventArgs e)
{
if (Editing)
return;
var species = WinFormsUtil.GetIndex(CB_Species);
var index = SpeciesToDex[species] - 1;
if (LB_Species.SelectedIndex != index)
LB_Species.SelectedIndex = index; // trigger event
}
private void ChangeLBSpecies(object sender, EventArgs e)
{
if (Editing || LB_Species.SelectedIndex < 0)
return;
SetEntry(lastIndex, lastForm);
Editing = true;
SuspendLayout();
lastIndex = LB_Species.SelectedIndex;
FillLBForms(lastIndex);
FillResearchTasks(lastIndex);
GetEntry(lastIndex, lastForm);
ResumeLayout();
Editing = false;
}
private void ChangeLBForms(object sender, EventArgs e)
{
if (Editing)
return;
SetEntry(lastIndex, lastForm);
lastForm = LB_Forms.SelectedIndex;
Editing = true;
SuspendLayout();
GetEntry(lastIndex, lastForm);
ResumeLayout();
Editing = false;
}
private bool FillLBForms(int index)
{
LB_Forms.DataSource = null;
LB_Forms.Items.Clear();
DisplayedForms.Clear();
DisplayedForms.Add(new ComboItem(GameInfo.Strings.types[0], 0));
CB_DisplayForm.DataSource = new BindingSource(DisplayedForms, null);
lastForm = 0;
ushort species = DexToSpecies[index + 1];
bool hasForms = FormInfo.HasFormSelection(SAV.Personal[species], species, 8);
LB_Forms.Enabled = CB_DisplayForm.Enabled = hasForms;
if (!hasForms)
return false;
var ds = FormConverter.GetFormList(species, GameInfo.Strings.types, GameInfo.Strings.forms, Main.GenderSymbols, SAV.Context);
if (ds.Length == 1 && string.IsNullOrEmpty(ds[0]))
{
// empty
LB_Forms.Enabled = CB_DisplayForm.Enabled = false;
return false;
}
// Sanitize forms to only show entries with form storage
var formCount = SAV.Personal[species].FormCount;
var sanitized = new List<string>();
DisplayedForms.Clear();
for (byte form = 0; form < formCount; form++)
{
if (!Dex.HasFormStorage(species, form) || Dex.IsBlacklisted(species, form))
continue;
sanitized.Add(ds[form]);
DisplayedForms.Add(new ComboItem(ds[form], form));
}
CB_DisplayForm.DataSource = new BindingSource(DisplayedForms, null);
LB_Forms.DataSource = sanitized;
LB_Forms.SelectedIndex = 0;
return true;
}
private void FillResearchTasks(int index)
{
var species = DexToSpecies[index + 1];
var tasks = PokedexConstants8a.ResearchTasks[index];
for (var i = 0; i < tasks.Length; i++)
{
var tc = TaskControls[i];
tc.Visible = false;
Dex.GetResearchTaskLevel(species, i, out var repLevel, out _, out _);
tc.SetTask(species, tasks[i], repLevel);
tc.Visible = true;
}
for (var i = tasks.Length; i < TaskControls.Length; i++)
TaskControls[i].Visible = false;
}
private void GetEntry(int index, int formIndex)
{
var species = DexToSpecies[index + 1];
var form = (byte)DisplayedForms[formIndex].Value;
// Flags
var seenWild = Dex.GetPokeSeenInWildFlags(species, form);
var obtain = Dex.GetPokeObtainFlags(species, form);
var caughtWild = Dex.GetPokeCaughtInWildFlags(species, form);
CHK_Solitude.Checked = Dex.GetSolitudeComplete(species);
for (var i = 0; i < CHK_SeenWild.Length; ++i)
{
CHK_SeenWild[i].Checked = (seenWild & (1 << i)) != 0;
CHK_Obtained[i].Checked = (obtain & (1 << i)) != 0;
CHK_CaughtWild[i].Checked = (caughtWild & (1 << i)) != 0;
}
// Display
if (CB_DisplayForm.Enabled)
{
var selectedForm = Dex.GetSelectedForm(species);
CB_DisplayForm.SelectedIndex = 0;
var items = CB_DisplayForm.Items;
for (var i = 0; i < items.Count; ++i)
{
var item = items[i];
if (item is not ComboItem cb)
throw new Exception("Invalid item type");
if (cb.Value != selectedForm)
continue;
CB_DisplayForm.SelectedIndex = i;
break;
}
}
CHK_A.Checked = Dex.GetSelectedAlpha(species);
CHK_S.Checked = Dex.GetSelectedShiny(species);
CHK_G.Enabled = PokedexSave8a.HasMultipleGenders(species);
CHK_G.Checked = Dex.GetSelectedGender1(species);
// Research
var reportedRate = Dex.GetPokeResearchRate(species);
var unreportedRate = reportedRate;
for (var i = 0; i < PokedexConstants8a.ResearchTasks[index].Length; i++)
{
var unreportedLevels = Dex.GetResearchTaskLevel(species, i, out _, out var taskValue, out _);
TaskControls[i].CurrentValue = taskValue;
unreportedRate += unreportedLevels * TaskControls[i].PointsPerLevel;
}
MTB_UpdateIndex.Text = Dex.GetUpdateIndex(species).ToString();
MTB_ResearchLevelReported.Text = reportedRate.ToString();
MTB_ResearchLevelUnreported.Text = unreportedRate.ToString();
CHK_Seen.Checked = Dex.HasPokeEverBeenUpdated(species);
CHK_Complete.Checked = Dex.IsComplete(species);
CHK_Perfect.Checked = Dex.IsPerfect(species);
// Statistics
Dex.GetSizeStatistics(species, form, out var hasMax, out var minHeight, out var maxHeight, out var minWeight, out var maxWeight);
CHK_MinAndMax.Checked = hasMax;
TB_MinHeight.Text = minHeight.ToString(CultureInfo.InvariantCulture);
TB_MaxHeight.Text = maxHeight.ToString(CultureInfo.InvariantCulture);
TB_MinWeight.Text = minWeight.ToString(CultureInfo.InvariantCulture);
TB_MaxWeight.Text = maxWeight.ToString(CultureInfo.InvariantCulture);
var pt = SAV.Personal;
var pi = pt.GetFormEntry(species, form);
var minTheoryHeight = PA8.GetHeightAbsolute(pi, 0x00).ToString(CultureInfo.InvariantCulture);
var maxTheoryHeight = PA8.GetHeightAbsolute(pi, 0xFF).ToString(CultureInfo.InvariantCulture);
var minTheoryWeight = PA8.GetWeightAbsolute(pi, 0x00, 0x00).ToString(CultureInfo.InvariantCulture);
var maxTheoryWeight = PA8.GetWeightAbsolute(pi, 0xFF, 0xFF).ToString(CultureInfo.InvariantCulture);
L_TheoryHeight.Text = $"Min: {minTheoryHeight}, Max: {maxTheoryHeight}";
L_TheoryWeight.Text = $"Min: {minTheoryWeight}, Max: {maxTheoryWeight}";
}
private bool IsEntryEmpty(int index, int formIndex)
{
var species = DexToSpecies[index + 1];
byte form = (byte)DisplayedForms[formIndex].Value;
// Any seen/obtain flags
for (var i = 0; i < CHK_SeenWild.Length; i++)
{
if (CHK_SeenWild[i].Checked)
return false;
if (CHK_Obtained[i].Checked)
return false;
if (CHK_CaughtWild[i].Checked)
return false;
}
// Any display flags
if ((CHK_G.Enabled && CHK_G.Checked) || CHK_S.Checked || CHK_A.Checked)
return false;
// Any research
for (var i = 0; i < PokedexConstants8a.ResearchTasks[index].Length; i++)
{
Dex.GetResearchTaskLevel(species, i, out var reportedLevels, out _, out _);
if (reportedLevels > 1)
return false;
if (TaskControls[i].CurrentValue != 0)
return false;
}
if (CHK_Complete.Checked || CHK_Perfect.Checked)
return false;
// Any statistics
Dex.GetSizeStatistics(species, form, out _, out var oldMinHeight, out var oldMaxHeight, out var oldMinWeight, out var oldMaxWeight);
if (!float.TryParse(TB_MinHeight.Text, out var minHeight))
minHeight = oldMinHeight;
if (!float.TryParse(TB_MaxHeight.Text, out var maxHeight))
maxHeight = oldMaxHeight;
if (!float.TryParse(TB_MinWeight.Text, out var minWeight))
minWeight = oldMinWeight;
if (!float.TryParse(TB_MaxWeight.Text, out var maxWeight))
maxWeight = oldMaxWeight;
if (CHK_MinAndMax.Checked)
return false;
return minHeight == 0 && maxHeight == 0 && minWeight == 0 && maxWeight == 0;
}
private void SetEntry(int index, int formIndex)
{
if (!CanSave || Editing || index < 0 || formIndex < 0)
return;
var empty = IsEntryEmpty(index, formIndex);
if (!CHK_Seen.Checked && empty)
return;
var species = DexToSpecies[index + 1];
var form = (byte)DisplayedForms[formIndex].Value;
if (!empty)
Dex.SetPokeHasBeenUpdated(species);
// Flags
var seenWild = 0;
var obtain = 0;
var caughtWild = 0;
for (var i = 0; i < CHK_SeenWild.Length; i++)
{
seenWild |= CHK_SeenWild[i].Checked ? (1 << i) : 0;
obtain |= CHK_Obtained[i].Checked ? (1 << i) : 0;
caughtWild |= CHK_CaughtWild[i].Checked ? (1 << i) : 0;
}
Dex.SetPokeSeenInWildFlags(species, form, (byte)seenWild);
Dex.SetPokeObtainFlags(species, form, (byte)obtain);
Dex.SetPokeCaughtInWildFlags(species, form, (byte)caughtWild);
Dex.SetSolitudeComplete(species, CHK_Solitude.Checked);
// Display
var dispForm = form;
if (CB_DisplayForm.Enabled)
dispForm = (byte)WinFormsUtil.GetIndex(CB_DisplayForm);
Dex.SetSelectedGenderForm(species, dispForm, CHK_G.Checked, CHK_S.Checked, CHK_A.Checked);
// Set research
for (var i = 0; i < PokedexConstants8a.ResearchTasks[index].Length; i++)
{
if (TaskControls[i].CanSetCurrentValue)
Dex.SetResearchTaskProgressByForce(species, TaskControls[i].Task, TaskControls[i].CurrentValue);
}
// Statistics
Dex.GetSizeStatistics(species, form, out _, out var oldMinHeight, out var oldMaxHeight, out var oldMinWeight, out var oldMaxWeight);
if (!float.TryParse(TB_MinHeight.Text, out var minHeight))
minHeight = oldMinHeight;
if (!float.TryParse(TB_MaxHeight.Text, out var maxHeight))
maxHeight = oldMaxHeight;
if (!float.TryParse(TB_MinWeight.Text, out var minWeight))
minWeight = oldMinWeight;
if (!float.TryParse(TB_MaxWeight.Text, out var maxWeight))
maxWeight = oldMaxWeight;
Dex.SetSizeStatistics(species, form, CHK_MinAndMax.Checked, minHeight, maxHeight, minWeight, maxWeight);
}
private void B_Cancel_Click(object sender, EventArgs e)
{
Close();
}
private void B_Save_Click(object sender, EventArgs e)
{
SetEntry(lastIndex, lastForm);
Origin.CopyChangesFrom(SAV);
Close();
}
private void CHK_ObtainFlag_Changed(object sender, EventArgs e)
{
if (Editing)
return;
var overrideObtainFlags = 0;
for (var i = 0; i < CHK_Obtained.Length; i++)
{
if (CHK_Obtained[i].Checked)
overrideObtainFlags |= (1 << i);
}
var tasks = PokedexConstants8a.ResearchTasks[lastIndex];
var species = DexToSpecies[lastIndex + 1];
var form = DisplayedForms[lastForm].Value;
SuspendLayout();
for (var i = 0; i < tasks.Length; i++)
{
if (tasks[i].Task != PokedexResearchTaskType8a.ObtainForms)
continue;
var formCount = Dex.GetObtainedFormCounts(species, form | (overrideObtainFlags << 16));
var tc = TaskControls[i];
if (tc.CurrentValue != formCount)
tc.CurrentValue = formCount;
}
ResumeLayout();
}
private void B_Report_Click(object sender, EventArgs e)
{
// Set the entry
SetEntry(lastIndex, lastForm);
Editing = true;
SuspendLayout();
// Perform a report on the specific species
var species = DexToSpecies[lastIndex + 1];
Dex.UpdateSpecificReportPoke(species, out _);
// Refresh all tasks
FillResearchTasks(lastIndex);
// Refresh all values
GetEntry(lastIndex, lastForm);
ResumeLayout();
Editing = false;
System.Media.SystemSounds.Asterisk.Play();
}
private void B_AdvancedResearch_Click(object sender, EventArgs e)
{
// Set the entry
SetEntry(lastIndex, lastForm);
// Show detailed editor form
using var form = new SAV_PokedexResearchEditorLA(SAV, DexToSpecies[lastIndex + 1], lastIndex, TaskDescriptions, TimeTaskDescriptions);
form.ShowDialog();
Editing = true;
SuspendLayout();
// Refresh all tasks
FillResearchTasks(lastIndex);
// Refresh all values
GetEntry(lastIndex, lastForm);
ResumeLayout();
Editing = false;
}
}