using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using PKHeX.Core; using PKHeX.WinForms.Properties; using System.ComponentModel; using static PKHeX.Core.MessageStrings; namespace PKHeX.WinForms.Controls { public sealed partial class PKMEditor : UserControl, IMainEditor { public PKMEditor() { InitializeComponent(); GB_OT.Click += ClickGT; GB_nOT.Click += ClickGT; GB_CurrentMoves.Click += ClickMoves; GB_RelearnMoves.Click += ClickMoves; TB_Nickname.Font = FontUtil.GetPKXFont(11); TB_OT.Font = (Font)TB_Nickname.Font.Clone(); TB_OTt2.Font = (Font)TB_Nickname.Font.Clone(); DrawForeColor = ForeColor; if (TextBrush == null) TextBrush = new SolidBrush(CB_Move1.ForeColor); if (BackBrush == null) BackBrush = new SolidBrush(CB_Move1.BackColor); // Commonly reused Control arrays Moves = new[] { CB_Move1, CB_Move2, CB_Move3, CB_Move4 }; Relearn = new[] { CB_RelearnMove1, CB_RelearnMove2, CB_RelearnMove3, CB_RelearnMove4 }; PPUps = new[] { CB_PPu1, CB_PPu2, CB_PPu3, CB_PPu4 }; MovePP = new[] { TB_PP1, TB_PP2, TB_PP3, TB_PP4 }; Markings = new[] { PB_Mark1, PB_Mark2, PB_Mark3, PB_Mark4, PB_Mark5, PB_Mark6 }; ValidationRequired = Moves.Concat(Relearn).Concat(new[] { CB_Species, CB_Nature, CB_HeldItem, CB_Ability, // Main Tab CB_MetLocation, CB_EggLocation, CB_Ball, // Met Tab }).ToArray(); relearnPB = new[] { PB_WarnRelearn1, PB_WarnRelearn2, PB_WarnRelearn3, PB_WarnRelearn4 }; movePB = new[] { PB_WarnMove1, PB_WarnMove2, PB_WarnMove3, PB_WarnMove4 }; foreach (var c in WinFormsUtil.GetAllControlsOfType<ComboBox>(this)) c.KeyDown += WinFormsUtil.RemoveDropCB; Stats.MainEditor = this; LoadShowdownSet = LoadShowdownSetDefault; TID_Trainer.UpdatedID += Update_ID; FieldsInitialized = true; } public void InitializeBinding() { ComboBox[] cbs = { CB_Nature, CB_Country, CB_SubRegion, CB_3DSReg, CB_Language, CB_Ball, CB_HeldItem, CB_Species, DEV_Ability, CB_EncounterType, CB_GameOrigin, CB_Ability, CB_MetLocation, CB_EggLocation, CB_Language, }; foreach (var cb in cbs.Concat(Moves.Concat(Relearn))) cb.InitializeBinding(); } private void UpdateStats() { Stats.UpdateStats(); if (pkm is PB7) SizeCP.TryResetStats(); } private void LoadPartyStats(PKM pk) => Stats.LoadPartyStats(pk); private void SavePartyStats(PKM pk) { Stats.SavePartyStats(pk); pk.Stat_Level = CurrentLevel; } public PKM CurrentPKM { get => FieldsInitialized ? PreparePKM() : pkm; set => pkm = value; } public bool ModifyPKM { private get; set; } = true; private bool _hideSecret; public bool HideSecretValues { private get => _hideSecret; set { _hideSecret = value; var sav = RequestSaveFile; if (sav != null) ToggleSecrets(_hideSecret, sav.Generation); } } public bool Unicode { get; set; } = true; private bool _hax; public bool HaX { get => _hax; set => _hax = Stats.HaX = value; } public byte[] LastData { private get; set; } public PKM Data { get => pkm; set => pkm = value; } public PKM pkm { get; private set; } public bool FieldsInitialized { get; private set; } public bool FieldsLoaded { get; private set; } public bool ChangingFields { get; set; } public int CurrentLevel => Util.ToInt32((HaX ? MT_Level : TB_Level).Text); private GameVersion origintrack; private Action GetFieldsfromPKM; private Func<PKM> GetPKMfromFields; private LegalityAnalysis Legality; private string[] gendersymbols = { "♂", "♀", "-" }; private readonly Image mixedHighlight = ImageUtil.ChangeOpacity(Resources.slotSet, 0.5); private HashSet<int> AllowedMoves = new HashSet<int>(); public event EventHandler LegalityChanged; public event EventHandler UpdatePreviewSprite; public event EventHandler RequestShowdownImport; public event EventHandler RequestShowdownExport; public event ReturnSAVEventHandler SaveFileRequested; public delegate SaveFile ReturnSAVEventHandler(object sender, EventArgs e); private readonly PictureBox[] movePB, relearnPB; private readonly ToolTip Tip3 = new ToolTip(), NatureTip = new ToolTip(), SpeciesIDTip = new ToolTip(); public SaveFile RequestSaveFile => SaveFileRequested?.Invoke(this, EventArgs.Empty); public bool PKMIsUnsaved => FieldsInitialized && FieldsLoaded && LastData?.Any(b => b != 0) == true && !LastData.SequenceEqual(CurrentPKM.Data); public bool IsEmptyOrEgg => CHK_IsEgg.Checked || CB_Species.SelectedIndex == 0; private readonly ComboBox[] Moves, Relearn, ValidationRequired, PPUps; private readonly MaskedTextBox[] MovePP; private readonly PictureBox[] Markings; private bool forceValidation; public PKM PreparePKM(bool click = true) { if (click) { forceValidation = true; ValidateChildren(); forceValidation = false; } PKM pk = GetPKMfromFields(); return pk?.Clone() ?? pkm; } public bool VerifiedPKM() { if (ModifierKeys == (Keys.Control | Keys.Shift | Keys.Alt)) return true; // Override var cb = Array.Find(ValidationRequired, c => c.BackColor == InvalidSelection && c.Items.Count != 0); if (cb != null) tabMain.SelectedTab = WinFormsUtil.FindFirstControlOfType<TabPage>(cb); else if (!Stats.Valid) tabMain.SelectedTab = Tab_Stats; else if (WinFormsUtil.GetIndex(CB_Species) == 0) tabMain.SelectedTab = Tab_Main; else return true; System.Media.SystemSounds.Exclamation.Play(); return false; } public void SetPKMFormatMode(int Format, PKM pk) { // Load Extra Byte List SetPKMFormatExtraBytes(pk); switch (Format) { case 1: GetFieldsfromPKM = PopulateFieldsPK1; GetPKMfromFields = PreparePK1; break; case 2: GetFieldsfromPKM = PopulateFieldsPK2; GetPKMfromFields = PreparePK2; break; case 3: GetFieldsfromPKM = PopulateFieldsPK3; GetPKMfromFields = PreparePK3; break; case 4: GetFieldsfromPKM = PopulateFieldsPK4; GetPKMfromFields = PreparePK4; break; case 5: GetFieldsfromPKM = PopulateFieldsPK5; GetPKMfromFields = PreparePK5; break; case 6: GetFieldsfromPKM = PopulateFieldsPK6; GetPKMfromFields = PreparePK6; break; case 7: switch (pk) { case PK7 _: GetFieldsfromPKM = PopulateFieldsPK7; GetPKMfromFields = PreparePK7; break; case PB7 _: GetFieldsfromPKM = PopulateFieldsPB7; GetPKMfromFields = PreparePB7; break; } break; } } private void SetPKMFormatExtraBytes(PKM pk) { byte[] extraBytes = pk.ExtraBytes; GB_ExtraBytes.Visible = GB_ExtraBytes.Enabled = extraBytes.Length != 0; CB_ExtraBytes.Items.Clear(); foreach (byte b in extraBytes) CB_ExtraBytes.Items.Add($"0x{b:X2}"); if (GB_ExtraBytes.Enabled) CB_ExtraBytes.SelectedIndex = 0; } public void PopulateFields(PKM pk, bool focus = true, bool skipConversionCheck = false) => LoadFieldsFromPKM(pk, focus, skipConversionCheck); private void LoadFieldsFromPKM(PKM pk, bool focus = true, bool skipConversionCheck = true) { if (pk == null) { WinFormsUtil.Error(MsgPKMLoadNull); return; } if (focus) Tab_Main.Focus(); if (!skipConversionCheck && !PKMConverter.TryMakePKMCompatible(pk, CurrentPKM, out string c, out pk)) { WinFormsUtil.Alert(c); return; } bool oldInit = FieldsInitialized; FieldsInitialized = FieldsLoaded = false; pkm = pk.Clone(); try { GetFieldsfromPKM(); } finally { FieldsInitialized = oldInit; } Stats.UpdateIVs(null, null); UpdatePKRSInfected(null, null); UpdatePKRSCured(null, null); UpdateNatureModification(null, null); if (HaX) // Load original values from pk not pkm { MT_Level.Text = (pk.Stat_HPMax != 0 ? pk.Stat_Level : Experience.GetLevel(pk.EXP, pk.Species, pk.AltForm)).ToString(); TB_EXP.Text = pk.EXP.ToString(); MT_Form.Text = pk.AltForm.ToString(); if (pk.PartyStatsPresent) // stats present Stats.LoadPartyStats(pk); } FieldsLoaded = true; SetMarkings(); UpdateLegality(); UpdateSprite(); LastData = PreparePKM()?.Data; } public void UpdateLegality(LegalityAnalysis la = null, bool skipMoveRepop = false) { if (!FieldsLoaded) return; Legality = la ?? new LegalityAnalysis(pkm, RequestSaveFile.Personal); if (!Legality.Parsed || HaX || pkm.Species == 0) { PB_WarnMove1.Visible = PB_WarnMove2.Visible = PB_WarnMove3.Visible = PB_WarnMove4.Visible = PB_WarnRelearn1.Visible = PB_WarnRelearn2.Visible = PB_WarnRelearn3.Visible = PB_WarnRelearn4.Visible = false; LegalityChanged?.Invoke(Legality.Valid, null); return; } // Refresh Move Legality for (int i = 0; i < 4; i++) movePB[i].Visible = !Legality.Info?.Moves[i].Valid ?? false; if (pkm.Format >= 6) { for (int i = 0; i < 4; i++) relearnPB[i].Visible = !Legality.Info?.Relearn[i].Valid ?? false; } if (skipMoveRepop) return; // Resort moves bool tmp = FieldsLoaded; FieldsLoaded = false; ReloadMoves(Legality.AllSuggestedMovesAndRelearn); FieldsLoaded |= tmp; LegalityChanged?.Invoke(Legality.Valid, null); } private IReadOnlyList<ComboItem> MoveDataAllowed = new List<ComboItem>(); private void ReloadMoves(IReadOnlyCollection<int> moves) { // check prior movepool to not needlessly refresh the dataset if (AllowedMoves.Count <= moves.Count && moves.All(AllowedMoves.Contains)) return; AllowedMoves = new HashSet<int>(moves); MoveDataAllowed = GameInfo.Strings.MoveDataSource.OrderByDescending(m => AllowedMoves.Contains(m.Value)).ToList(); // defer repop until dropdown is opened; handled by dropdown event for (int i = 0; i < IsMoveBoxOrdered.Count; i++) IsMoveBoxOrdered[i] = false; } private void SetMoveDataSource(ComboBox c) { var index = WinFormsUtil.GetIndex(c); c.DataSource = new BindingSource(MoveDataAllowed, null); c.SelectedValue = index; } public void UpdateUnicode(string[] symbols) { gendersymbols = symbols; if (!Unicode) { BTN_Shinytize.Text = ShinytizeDefault; TB_Nickname.Font = TB_OT.Font = TB_OTt2.Font = GB_OT.Font; } else { BTN_Shinytize.Text = ShinytizeUnicode; TB_Nickname.Font = TB_OT.Font = TB_OTt2.Font = FontUtil.GetPKXFont(11); } // Switch active gender labels to new if they are active. if (PKX.GetGenderFromString(Label_Gender.Text) < 2) Label_Gender.Text = gendersymbols[PKX.GetGenderFromString(Label_Gender.Text)]; if (PKX.GetGenderFromString(Label_OTGender.Text) < 2) Label_OTGender.Text = gendersymbols[PKX.GetGenderFromString(Label_OTGender.Text)]; if (PKX.GetGenderFromString(Label_CTGender.Text) < 2) Label_CTGender.Text = gendersymbols[PKX.GetGenderFromString(Label_CTGender.Text)]; } private void UpdateSprite() { if (FieldsLoaded && FieldsInitialized && !forceValidation) UpdatePreviewSprite?.Invoke(this, null); } // General Use Functions // private Color InvalidSelection { get; set; } = Color.DarkSalmon; private Color MarkBlue { get; set; } = Color.FromArgb(000, 191, 255); private Color MarkPink { get; set; } = Color.FromArgb(255, 117, 179); private Color MarkDefault { get; set; } = Color.Black; private Brush LegalMove { get; set; } = Brushes.PaleGreen; private Brush TextBrush { get; set; } private Brush BackBrush { get; set; } private string ShinytizeDefault { get; set; } = "*"; private string ShinytizeUnicode { get; set; } = "☆"; private Color DrawForeColor { get; set; } private Color GetGenderColor(int gender) { switch (gender) { case 0: return Color.Blue; case 1: return Color.Red; default: return DrawForeColor; } } private bool GetMarkingColor(int markval, out Color c) { switch (markval) { case 1: c = MarkBlue; return true; case 2: c = MarkPink; return true; default: c = MarkDefault; return false; // recolor not required } } private void SetDetailsOT(ITrainerInfo SAV) { if (!(SAV.OT?.Length > 0)) return; // Get Save Information TB_OT.Text = SAV.OT; Label_OTGender.Text = gendersymbols[SAV.Gender & 1]; Label_OTGender.ForeColor = GetGenderColor(SAV.Gender & 1); TID_Trainer.LoadInfo(SAV); if (SAV.Game >= 0) CB_GameOrigin.SelectedValue = SAV.Game; var lang = SAV.Language; if (lang <= 0) lang = (int)LanguageID.English; CB_Language.SelectedValue = lang; if (SAV.ConsoleRegion != 0) { CB_3DSReg.SelectedValue = SAV.ConsoleRegion; CB_Country.SelectedValue = SAV.Country; CB_SubRegion.SelectedValue = SAV.SubRegion; } // Copy OT trash bytes for sensitive games (Gen1/2) if (SAV is SAV1 s1 && pkm is PK1 p1) p1.OT_Trash = s1.OT_Trash; else if (SAV is SAV2 s2 && pkm is PK2 p2) p2.OT_Trash = s2.OT_Trash; UpdateNickname(null, null); } private void SetDetailsHT(ITrainerInfo SAV) { if (!(SAV.OT?.Length > 0)) return; if (TB_OTt2.Text.Length > 0) Label_CTGender.Text = gendersymbols[SAV.Gender & 1]; } private void SetForms() { 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; // show with value entry textbox if (!hasForms) return; var ds = PKX.GetFormList(species, GameInfo.Strings.types, GameInfo.Strings.forms, gendersymbols, pkm.Format); if (ds.Length == 1 && string.IsNullOrEmpty(ds[0])) // empty (Alolan Totems) CB_Form.Enabled = CB_Form.Visible = Label_Form.Visible = false; else CB_Form.DataSource = ds; } private void SetAbilityList() { if (pkm.Format < 3) // no abilities return; if (pkm.Format > 3 && FieldsLoaded) // has forms pkm.AltForm = CB_Form.SelectedIndex; // update pkm field for form specific abilities int abil = CB_Ability.SelectedIndex; bool tmp = FieldsLoaded; FieldsLoaded = false; CB_Ability.DataSource = GetAbilityList(pkm); CB_Ability.SelectedIndex = GetSafeIndex(CB_Ability, abil); // restore original index if available FieldsLoaded = tmp; } private static int GetSafeIndex(ComboBox cb, int index) => Math.Max(0, Math.Min(cb.Items.Count - 1, index)); private void UpdateIsShiny() { // Recalculate shininiess bool isShiny = pkm.IsShiny; // Set the Controls BTN_Shinytize.Visible = BTN_Shinytize.Enabled = !isShiny; Label_IsShiny.Visible = isShiny; // Refresh Markings (for Shiny Star if applicable) SetMarkings(); } private void SetMarkings() { double getOpacity(bool b) => b ? 1 : 0.175; Image changeOpacity(PictureBox p, double opacity) => opacity == 1 ? p.InitialImage : ImageUtil.ChangeOpacity(p.InitialImage, opacity); var pba = Markings; var markings = pkm.Markings; for (int i = 0; i < pba.Length; i++) pba[i].Image = changeOpacity(pba[i], getOpacity(markings[i] != 0)); PB_MarkShiny.Image = changeOpacity(PB_MarkShiny, getOpacity(!BTN_Shinytize.Enabled)); PB_MarkCured.Image = changeOpacity(PB_MarkCured, getOpacity(CHK_Cured.Checked)); PB_MarkPentagon.Image = changeOpacity(PB_MarkPentagon, getOpacity(pkm.Gen6)); PB_Favorite.Image = changeOpacity(PB_Favorite, getOpacity(pkm is PB7 pb7 && pb7.Favorite)); // Gen7 Markings if (pkm.Format != 7) return; PB_MarkAlola.Image = changeOpacity(PB_MarkAlola, getOpacity(pkm.Gen7)); PB_MarkVC.Image = changeOpacity(PB_MarkVC, getOpacity(pkm.VC)); PB_MarkGO.Image = changeOpacity(PB_MarkGO, getOpacity(pkm.GO)); for (int i = 0; i < pba.Length; i++) { if (GetMarkingColor(markings[i], out Color c)) pba[i].Image = ImageUtil.ChangeAllColorTo(pba[i].Image, c); } } private void UpdateGender() { int Gender = pkm.GetSaneGender(); Label_Gender.Text = gendersymbols[Gender]; Label_Gender.ForeColor = GetGenderColor(Gender); } private void SetCountrySubRegion(ComboBox CB, string type) { int index = CB.SelectedIndex; // fix for Korean / Chinese being swapped string cl = GameInfo.CurrentLanguage; cl = cl == "zh" ? "ko" : cl == "ko" ? "zh" : cl; CB.DataSource = Util.GetCBList(type, cl); if (index > 0 && index < CB.Items.Count && FieldsInitialized) CB.SelectedIndex = index; } // Prompted Updates of PKM // private void ClickFriendship(object sender, EventArgs e) { if (ModifierKeys == Keys.Control) // prompt to reset TB_Friendship.Text = pkm.CurrentFriendship.ToString(); else TB_Friendship.Text = TB_Friendship.Text == "255" ? pkm.PersonalInfo.BaseFriendship.ToString() : "255"; } private void ClickLevel(object sender, EventArgs e) { if (ModifierKeys == Keys.Control) ((MaskedTextBox)sender).Text = "100"; } private void ClickGender(object sender, EventArgs e) { // Get Gender Threshold int gt = pkm.PersonalInfo.Gender; if (gt == 255 || gt == 0 || gt == 254) // Single gender/genderless return; int newGender = (PKX.GetGenderFromString(Label_Gender.Text) & 1) ^ 1; if (pkm.Format <= 2) { Stats.SetATKIVGender(newGender); UpdateIsShiny(); } else if (pkm.Format <= 4) { pkm.Version = WinFormsUtil.GetIndex(CB_GameOrigin); pkm.Nature = WinFormsUtil.GetIndex(CB_Nature); pkm.AltForm = CB_Form.SelectedIndex; pkm.SetPIDGender(newGender); TB_PID.Text = pkm.PID.ToString("X8"); } pkm.Gender = newGender; Label_Gender.Text = gendersymbols[pkm.Gender]; Label_Gender.ForeColor = GetGenderColor(pkm.Gender); if (PKX.GetGenderFromString(CB_Form.Text) < 2) // Gendered Forms CB_Form.SelectedIndex = PKX.GetGenderFromString(Label_Gender.Text); UpdatePreviewSprite(Label_Gender, null); } private void ClickPPUps(object sender, EventArgs e) { bool min = ModifierKeys.HasFlag(Keys.Control); CB_PPu1.SelectedIndex = !min && WinFormsUtil.GetIndex(CB_Move1) > 0 ? 3 : 0; CB_PPu2.SelectedIndex = !min && WinFormsUtil.GetIndex(CB_Move2) > 0 ? 3 : 0; CB_PPu3.SelectedIndex = !min && WinFormsUtil.GetIndex(CB_Move3) > 0 ? 3 : 0; CB_PPu4.SelectedIndex = !min && WinFormsUtil.GetIndex(CB_Move4) > 0 ? 3 : 0; } private void ClickMarking(object sender, EventArgs e) { int index = Array.IndexOf(Markings, (PictureBox)sender); pkm.ToggleMarking(index); SetMarkings(); } private void ClickFavorite(object sender, EventArgs e) { if (pkm is PB7 pb7) pb7.Favorite ^= true; SetMarkings(); } private void ClickOT(object sender, EventArgs e) => SetDetailsOT(SaveFileRequested?.Invoke(this, e)); private void ClickCT(object sender, EventArgs e) => SetDetailsHT(SaveFileRequested?.Invoke(this, e)); private void ClickTRGender(object sender, EventArgs e) { Label lbl = sender as Label; if (!string.IsNullOrWhiteSpace(lbl?.Text)) // set gender label (toggle M/F) { int gender = PKX.GetGenderFromString(lbl.Text) ^ 1; lbl.Text = gendersymbols[gender]; lbl.ForeColor = GetGenderColor(gender); } } private void ClickBall(object sender, EventArgs e) { pkm.Ball = WinFormsUtil.GetIndex(CB_Ball); if (ModifierKeys.HasFlag(Keys.Alt)) { CB_Ball.SelectedValue = (int)Ball.Poke; return; } if (ModifierKeys.HasFlag(Keys.Shift)) { CB_Ball.SelectedValue = BallRandomizer.ApplyBallLegalByColor(pkm); return; } var legal = BallRandomizer.GetLegalBalls(pkm).ToArray(); var poss = ((Ball[]) Enum.GetValues(typeof(Ball))).Skip(1) .TakeWhile(z => (int) z <= pkm.MaxBallID).ToArray(); var names = GameInfo.BallDataSource; var frm = new Form { FormBorderStyle = FormBorderStyle.FixedToolWindow, StartPosition = FormStartPosition.CenterParent, AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, MaximizeBox = false, MinimizeBox = false, }; var flp = new FlowLayoutPanel {AutoSize = true, Dock = DockStyle.Fill}; for (int i = 0; i < poss.Length; i++) { var b = poss[i]; var img = SpriteUtil.GetBallSprite((int) b); bool valid = legal.Contains(b); var pb = new PictureBox { Size = img.Size, Image = img, BackgroundImage = valid ? Resources.slotSet : Resources.slotDel, BackgroundImageLayout = ImageLayout.Tile }; pb.MouseEnter += (_, __) => frm.Text = names.First(z => z.Value == (int)b).Text; pb.Click += (_, __) => { CB_Ball.SelectedValue = (int)b; frm.Close(); }; flp.Controls.Add(pb); const int width = 5; if (i % width == width - 1) flp.SetFlowBreak(pb, true); } frm.Controls.Add(flp); frm.ShowDialog(); } private void ClickShinyLeaf(object sender, EventArgs e) => ShinyLeaf.CheckAll(ModifierKeys != Keys.Control); private void ClickMetLocation(object sender, EventArgs e) { if (HaX) return; pkm = PreparePKM(); UpdateLegality(skipMoveRepop: true); if (Legality.Valid) return; if (!SetSuggestedMetLocation()) return; pkm = PreparePKM(); UpdateLegality(); } private void ClickGT(object sender, EventArgs e) { if (!GB_nOT.Visible) return; if (sender == GB_OT) { pkm.CurrentHandler = 0; GB_OT.BackgroundImage = mixedHighlight; GB_nOT.BackgroundImage = null; } else if (TB_OTt2.Text.Length > 0) { pkm.CurrentHandler = 1; GB_OT.BackgroundImage = null; GB_nOT.BackgroundImage = mixedHighlight; } TB_Friendship.Text = pkm.CurrentFriendship.ToString(); } private void ClickMoves(object sender, EventArgs e) { UpdateLegality(skipMoveRepop: true); if (sender == GB_CurrentMoves) { if (!SetSuggestedMoves(random: ModifierKeys == Keys.Control)) return; } else if (sender == GB_RelearnMoves) { if (!SetSuggestedRelearnMoves()) return; } else { return; } UpdateLegality(); } private bool SetSuggestedMoves(bool random = false, bool silent = false) { int[] m = pkm.GetMoveSet(random); if (m?.Any(z => z != 0) != true) { if (!silent) WinFormsUtil.Alert(MsgPKMSuggestionFormat); return false; } if (pkm.Moves.SequenceEqual(m)) return false; if (!silent) { var movestrings = m.Select(v => v >= GameInfo.Strings.Move.Count ? MsgProgramError : GameInfo.Strings.Move[v]); string r = string.Join(Environment.NewLine, movestrings); if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgPKMSuggestionMoves, r)) return false; } pkm.SetMoves(m); FieldsLoaded = false; LoadMoves(pkm); FieldsLoaded = true; return true; } private bool SetSuggestedRelearnMoves(bool silent = false) { if (pkm.Format < 6) return false; int[] m = pkm.GetSuggestedRelearnMoves(Legality); if (pkm.RelearnMoves.SequenceEqual(m)) return false; if (!silent) { var movestrings = m.Select(v => v >= GameInfo.Strings.Move.Count ? MsgProgramError : GameInfo.Strings.Move[v]); string r = string.Join(Environment.NewLine, movestrings); if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgPKMSuggestionRelearn, r)) return false; } CB_RelearnMove1.SelectedValue = m[0]; CB_RelearnMove2.SelectedValue = m[1]; CB_RelearnMove3.SelectedValue = m[2]; CB_RelearnMove4.SelectedValue = m[3]; return true; } private bool SetSuggestedMetLocation(bool silent = false) { var encounter = Legality.GetSuggestedMetInfo(); if (encounter == null || (pkm.Format >= 3 && encounter.Location < 0)) { if (!silent) WinFormsUtil.Alert(MsgPKMSuggestionNone); return false; } int level = encounter.Level; int location = encounter.Location; int minlvl = Legal.GetLowestLevel(pkm, encounter.LevelMin); if (minlvl == 0) minlvl = level; if (pkm.CurrentLevel >= minlvl && pkm.Met_Level == level && pkm.Met_Location == location) return false; if (minlvl < level) minlvl = level; if (!silent) { List<string> suggestion = GetSuggestionMessage(pkm, level, location, minlvl); if (suggestion.Count == 1) // no suggestion return false; string suggest = string.Join(Environment.NewLine, suggestion); if (WinFormsUtil.Prompt(MessageBoxButtons.YesNo, suggest) != DialogResult.Yes) return false; } if (pkm.Format >= 3) { TB_MetLevel.Text = level.ToString(); CB_MetLocation.SelectedValue = location; if (pkm.GenNumber == 6 && pkm.WasEgg && ModifyPKM) pkm.SetHatchMemory6(); } if (pkm.CurrentLevel < minlvl) TB_Level.Text = minlvl.ToString(); return true; } public void UpdateIVsGB(bool skipForm) { if (!FieldsLoaded) return; Label_Gender.Text = gendersymbols[pkm.Gender]; Label_Gender.ForeColor = GetGenderColor(pkm.Gender); if (pkm.Species == 201 && !skipForm) // Unown CB_Form.SelectedIndex = pkm.AltForm; UpdateIsShiny(); UpdateSprite(); } private void UpdateBall(object sender, EventArgs e) { PB_Ball.Image = SpriteUtil.GetBallSprite(WinFormsUtil.GetIndex(CB_Ball)); } private void UpdateEXPLevel(object sender, EventArgs e) { if (ChangingFields || !FieldsInitialized) return; ChangingFields = true; if (sender == TB_EXP) { // Change the Level uint EXP = Util.ToUInt32(TB_EXP.Text); int Species = pkm.Species; int Form = pkm.AltForm; int Level = Experience.GetLevel(EXP, Species, Form); if (Level == 100) EXP = Experience.GetEXP(100, Species, Form); TB_Level.Text = Level.ToString(); if (!HaX) TB_EXP.Text = EXP.ToString(); else if (Level <= 100 && Util.ToInt32(MT_Level.Text) <= 100) MT_Level.Text = Level.ToString(); } else { // Change the XP int Level = Util.ToInt32((HaX ? MT_Level : TB_Level).Text); if (Level <= 0) { TB_Level.Text = "1"; } else if (Level > 100) { TB_Level.Text = "100"; if (!HaX) Level = 100; } if (Level > byte.MaxValue) MT_Level.Text = "255"; else if (Level <= 100) TB_EXP.Text = Experience.GetEXP(Level, pkm.Species, pkm.AltForm).ToString(); } ChangingFields = false; if (FieldsLoaded) // store values back { pkm.EXP = Util.ToUInt32(TB_EXP.Text); pkm.Stat_Level = Util.ToInt32((HaX ? MT_Level : TB_Level).Text); } UpdateStats(); UpdateLegality(); } private void UpdateRandomPID(object sender, EventArgs e) { if (pkm.Format < 3) return; if (FieldsLoaded) pkm.PID = Util.GetHexValue(TB_PID.Text); if (sender == Label_Gender) pkm.SetPIDGender(pkm.Gender); else if (sender == CB_Nature && pkm.Nature != WinFormsUtil.GetIndex(CB_Nature)) pkm.SetPIDNature(WinFormsUtil.GetIndex(CB_Nature)); else if (sender == BTN_RerollPID) pkm.SetPIDGender(pkm.Gender); else if (sender == CB_Ability && CB_Ability.SelectedIndex != pkm.PIDAbility && pkm.PIDAbility > -1) pkm.SetAbilityIndex(CB_Ability.SelectedIndex); TB_PID.Text = pkm.PID.ToString("X8"); if (pkm.Format >= 6 && 3 <= pkm.GenNumber && pkm.GenNumber <= 5) TB_EC.Text = TB_PID.Text; Update_ID(TB_EC, e); } private void UpdateRandomEC(object sender, EventArgs e) { if (pkm.Format < 6) return; pkm.SetRandomEC(); TB_EC.Text = pkm.EncryptionConstant.ToString("X8"); Update_ID(TB_EC, e); UpdateLegality(); } private void Update255_MTB(object sender, EventArgs e) { if (!(sender is MaskedTextBox tb)) return; if (Util.ToInt32(tb.Text) > byte.MaxValue) tb.Text = "255"; if (sender == TB_Friendship && int.TryParse(TB_Friendship.Text, out var val)) { pkm.CurrentFriendship = val; UpdateStats(); } } private void UpdateForm(object sender, EventArgs e) { if (CB_Form == sender && FieldsLoaded) { pkm.AltForm = CB_Form.SelectedIndex; uint EXP = Experience.GetEXP(pkm.CurrentLevel, pkm.Species, pkm.AltForm); TB_EXP.Text = EXP.ToString(); } UpdateStats(); SetAbilityList(); // Gender Forms if (WinFormsUtil.GetIndex(CB_Species) == 201 && FieldsLoaded) { if (pkm.Format == 3) { pkm.SetPIDUnown3(CB_Form.SelectedIndex); TB_PID.Text = pkm.PID.ToString("X8"); } else if (pkm.Format == 2) { int desiredForm = CB_Form.SelectedIndex; while (pkm.AltForm != desiredForm) { FieldsLoaded = false; Stats.UpdateRandomIVs(null, null); FieldsLoaded = true; } } } else if (CB_Form.Enabled && PKX.GetGenderFromString(CB_Form.Text) < 2) { if (CB_Form.Items.Count == 2) // actually M/F; Pumpkaboo formes in German are S,M,L,XL { pkm.Gender = CB_Form.SelectedIndex; UpdateGender(); } } else { UpdateGender(); } if (ChangingFields) return; ChangingFields = true; MT_Form.Text = CB_Form.SelectedIndex.ToString(); ChangingFields = false; UpdateSprite(); } private void UpdateHaXForm(object sender, EventArgs e) { if (ChangingFields) return; ChangingFields = true; int form = pkm.AltForm = Util.ToInt32(MT_Form.Text); CB_Form.SelectedIndex = CB_Form.Items.Count > form ? form : -1; ChangingFields = false; UpdateSprite(); } private void UpdatePP(object sender, EventArgs e) { if (!(sender is ComboBox cb)) return; int index = Array.IndexOf(Moves, cb); if (index < 0) index = Array.IndexOf(PPUps, cb); if (index < 0) return; int move = WinFormsUtil.GetIndex(Moves[index]); var ppctrl = PPUps[index]; int ppups = ppctrl.SelectedIndex; if (move <= 0) { ppctrl.SelectedIndex = 0; MovePP[index].Text = 0.ToString(); } else { MovePP[index].Text = pkm.GetMovePP(move, ppups).ToString(); } } private void UpdatePKRSstrain(object sender, EventArgs e) { // Change the PKRS Days to the legal bounds. int currentDuration = CB_PKRSDays.SelectedIndex; CB_PKRSDays.Items.Clear(); int max = (CB_PKRSStrain.SelectedIndex % 4) + 2; foreach (int day in Enumerable.Range(0, max)) CB_PKRSDays.Items.Add(day); // Set the days back if they're legal, else set it to 1. (0 always passes). CB_PKRSDays.SelectedIndex = currentDuration < CB_PKRSDays.Items.Count ? currentDuration : 1; if (CB_PKRSStrain.SelectedIndex != 0) return; // Never Infected CB_PKRSDays.SelectedIndex = 0; CHK_Cured.Checked = false; CHK_Infected.Checked = false; } private void UpdatePKRSdays(object sender, EventArgs e) { if (CB_PKRSDays.SelectedIndex != 0) return; // If no days are selected if (CB_PKRSStrain.SelectedIndex == 0) CHK_Cured.Checked = CHK_Infected.Checked = false; // No Strain = Never Cured / Infected, triggers Strain update else CHK_Cured.Checked = true; // Any Strain = Cured } private void UpdatePKRSCured(object sender, EventArgs e) { if (!FieldsInitialized) return; // Cured PokeRus is toggled if (CHK_Cured.Checked) { // Has Had PokeRus Label_PKRSdays.Visible = CB_PKRSDays.Visible = false; CB_PKRSDays.SelectedIndex = 0; Label_PKRS.Visible = CB_PKRSStrain.Visible = true; CHK_Infected.Checked = true; // If we're cured we have to have a strain infection. if (CB_PKRSStrain.SelectedIndex == 0) CB_PKRSStrain.SelectedIndex = 1; } else if (!CHK_Infected.Checked) { // Not Infected, Disable the other Label_PKRS.Visible = CB_PKRSStrain.Visible = false; CB_PKRSStrain.SelectedIndex = 0; } else { // Still Infected for a duration Label_PKRSdays.Visible = CB_PKRSDays.Visible = true; CB_PKRSDays.SelectedValue = 1; } // if not cured yet, days > 0 if (!CHK_Cured.Checked && CHK_Infected.Checked && CB_PKRSDays.SelectedIndex == 0) CB_PKRSDays.SelectedIndex++; SetMarkings(); } private void UpdatePKRSInfected(object sender, EventArgs e) { if (!FieldsInitialized) return; if (CHK_Cured.Checked && !CHK_Infected.Checked) { CHK_Cured.Checked = false; return; } if (CHK_Cured.Checked) return; Label_PKRS.Visible = CB_PKRSStrain.Visible = CHK_Infected.Checked; if (!CHK_Infected.Checked) { CB_PKRSStrain.SelectedIndex = 0; CB_PKRSDays.SelectedIndex = 0; Label_PKRSdays.Visible = CB_PKRSDays.Visible = false; } else if (CB_PKRSStrain.SelectedIndex == 0) { CB_PKRSStrain.SelectedIndex = CB_PKRSDays.SelectedIndex = 1; Label_PKRSdays.Visible = CB_PKRSDays.Visible = true; UpdatePKRSCured(sender, e); } } private void UpdateCountry(object sender, EventArgs e) { int index; if (sender is ComboBox c && (index = WinFormsUtil.GetIndex(c)) > 0) SetCountrySubRegion(CB_SubRegion, $"sr_{index:000}"); } private void UpdateSpecies(object sender, EventArgs e) { // Get Species dependent information if (FieldsLoaded) pkm.Species = WinFormsUtil.GetIndex(CB_Species); SpeciesIDTip.SetToolTip(CB_Species, pkm.Species.ToString("000")); SetAbilityList(); SetForms(); UpdateForm(null, null); if (!FieldsLoaded) return; // Recalculate EXP for Given Level uint EXP = Experience.GetEXP(pkm.CurrentLevel, pkm.Species, pkm.AltForm); TB_EXP.Text = EXP.ToString(); // Check for Gender Changes UpdateGender(); // If species changes and no nickname, set the new name == speciesName. if (!CHK_Nicknamed.Checked) UpdateNickname(sender, e); UpdateLegality(); } private void UpdateOriginGame(object sender, EventArgs e) { GameVersion Version = (GameVersion)WinFormsUtil.GetIndex(CB_GameOrigin); if (FieldsLoaded) pkm.Version = (int)Version; // check if differs var group = GameUtil.GetMetLocationVersionGroup(Version); if (group == GameVersion.GSC && pkm.Format >= 7) group = GameVersion.USUM; else if (pkm.Format < 3) group = GameVersion.GSC; if (group != origintrack) ReloadMetLocations(Version); origintrack = group; // Visibility logic for Gen 4 encounter type; only show for Gen 4 Pokemon. if (pkm.Format >= 4) { bool g4 = pkm.Gen4; CB_EncounterType.Visible = Label_EncounterType.Visible = g4 && pkm.Format < 7; if (!g4) CB_EncounterType.SelectedValue = 0; } if (!FieldsLoaded) return; TID_Trainer.LoadIDValues(pkm); UpdateLegality(); } private void ReloadMetLocations(GameVersion Version) { var met_list = GameInfo.GetLocationList(Version, pkm.Format, egg: false); CB_MetLocation.DataSource = new BindingSource(met_list, null); var egg_list = GameInfo.GetLocationList(Version, pkm.Format, egg: true); CB_EggLocation.DataSource = new BindingSource(egg_list, null); // Stretch C/XD met location dropdowns int width = CB_EggLocation.DropDownWidth; if (Version == GameVersion.CXD && pkm.Format == 3) width *= 2; CB_MetLocation.DropDownWidth = width; if (FieldsLoaded) { SetMarkings(); // Set/Remove the Nativity marking when gamegroup changes too int metLoc = EncounterSuggestion.GetSuggestedTransferLocation(pkm); CB_MetLocation.SelectedValue = Math.Max(0, metLoc); CB_EggLocation.SelectedIndex = CHK_AsEgg.Checked ? 1 : 0; // daycare : none } else { CB_GameOrigin.Focus(); // hacky validation forcing } } private void UpdateExtraByteValue(object sender, EventArgs e) { if (CB_ExtraBytes.Items.Count == 0 || !(sender is MaskedTextBox mtb)) return; // Changed Extra Byte's Value if (Util.ToInt32(mtb.Text) > byte.MaxValue) mtb.Text = "255"; int value = Util.ToInt32(mtb.Text); int offset = Convert.ToInt32(CB_ExtraBytes.Text, 16); pkm.Data[offset] = (byte)value; } private void UpdateExtraByteIndex(object sender, EventArgs e) { if (CB_ExtraBytes.Items.Count == 0) return; // Byte changed, need to refresh the Text box for the byte's value. TB_ExtraByte.Text = pkm.Data[Convert.ToInt32(CB_ExtraBytes.Text, 16)].ToString(); } private void UpdateNatureModification(object sender, EventArgs e) { string text = Stats.UpdateNatureModification(pkm.Nature); NatureTip.SetToolTip(CB_Nature, text); } private void UpdateIsNicknamed(object sender, EventArgs e) { if (!FieldsLoaded) return; pkm.Nickname = TB_Nickname.Text; if (CHK_Nicknamed.Checked) return; int species = WinFormsUtil.GetIndex(CB_Species); if (species < 1 || species > pkm.MaxSpeciesID) return; if (CHK_IsEgg.Checked) species = 0; // get the egg name. if (PKX.IsNicknamedAnyLanguage(species, TB_Nickname.Text, pkm.Format)) CHK_Nicknamed.Checked = true; } private void UpdateNickname(object sender, EventArgs e) { if (sender == Label_Species) { switch (ModifierKeys) { case Keys.Control: RequestShowdownImport?.Invoke(sender, e); return; case Keys.Alt: RequestShowdownExport?.Invoke(sender, e); return; default: if (pkm is PK1 pk1) pk1.Catch_Rate = pk1.PersonalInfo.CatchRate; return; } } int lang = WinFormsUtil.GetIndex(CB_Language); if (!FieldsInitialized || CHK_Nicknamed.Checked) return; // Fetch Current Species and set it as Nickname Text int species = WinFormsUtil.GetIndex(CB_Species); if (species < 1 || species > pkm.MaxSpeciesID) { TB_Nickname.Text = string.Empty; return; } if (CHK_IsEgg.Checked) species = 0; // get the egg name. // If name is that of another language, don't replace the nickname if (sender != CB_Language && species != 0 && !PKX.IsNicknamedAnyLanguage(species, TB_Nickname.Text, pkm.Format)) return; TB_Nickname.Text = PKX.GetSpeciesNameGeneration(species, lang, pkm.Format); if (pkm is _K12 pk) pk.SetNotNicknamed(); } private void UpdateNicknameClick(object sender, MouseEventArgs e) { TextBox tb = sender as TextBox ?? TB_Nickname; // Special Character Form if (ModifierKeys != Keys.Control) return; var SAV = RequestSaveFile; if (SAV == null) // form did not provide the needed info return; if (tb == TB_Nickname) { pkm.Nickname = tb.Text; var d = new TrashEditor(tb, pkm.Nickname_Trash, SAV); d.ShowDialog(); tb.Text = d.FinalString; pkm.Nickname_Trash = d.FinalBytes; } else if (tb == TB_OT) { pkm.OT_Name = tb.Text; var d = new TrashEditor(tb, pkm.OT_Trash, SAV); d.ShowDialog(); tb.Text = d.FinalString; pkm.OT_Trash = d.FinalBytes; } else if (tb == TB_OTt2) { pkm.HT_Name = tb.Text; var d = new TrashEditor(tb, pkm.HT_Trash, SAV); d.ShowDialog(); tb.Text = d.FinalString; pkm.HT_Trash = d.FinalBytes; } } private void UpdateNotOT(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(TB_OTt2.Text)) { ClickGT(GB_OT, null); // Switch CT over to OT. Label_CTGender.Text = string.Empty; TB_Friendship.Text = pkm.CurrentFriendship.ToString(); } else if (string.IsNullOrWhiteSpace(Label_CTGender.Text)) { Label_CTGender.Text = gendersymbols[0]; } } private void UpdateIsEgg(object sender, EventArgs e) { // Display hatch counter if it is an egg, Display Friendship if it is not. Label_HatchCounter.Visible = CHK_IsEgg.Checked && pkm.Format > 1; Label_Friendship.Visible = !CHK_IsEgg.Checked && pkm.Format > 1; if (!FieldsLoaded) return; pkm.IsEgg = CHK_IsEgg.Checked; if (CHK_IsEgg.Checked) { TB_Friendship.Text = "1"; // If we are an egg, it won't have a met location. CHK_AsEgg.Checked = true; GB_EggConditions.Enabled = true; CAL_MetDate.Value = new DateTime(2000, 01, 01); // if egg wasn't originally obtained by OT => Link Trade, else => None bool isTraded = false; var SAV = SaveFileRequested?.Invoke(this, e); if (SAV != null) isTraded = SAV.OT != TB_OT.Text || SAV.TID != pkm.TID || SAV.SID != pkm.SID; CB_MetLocation.SelectedIndex = isTraded ? 2 : 0; if (!CHK_Nicknamed.Checked) { TB_Nickname.Text = PKX.GetSpeciesNameGeneration(0, WinFormsUtil.GetIndex(CB_Language), pkm.Format); if (pkm.Format != 4) // eggs in gen4 do not have nickname flag CHK_Nicknamed.Checked = true; } // Wipe egg memories if (pkm.Format >= 6 && ModifyPKM) pkm.ClearMemories(); } else // Not Egg { if (!CHK_Nicknamed.Checked) UpdateNickname(null, null); TB_Friendship.Text = pkm.PersonalInfo.BaseFriendship.ToString(); if (CB_EggLocation.SelectedIndex == 0) { CAL_EggDate.Value = new DateTime(2000, 01, 01); CHK_AsEgg.Checked = false; GB_EggConditions.Enabled = false; } if (TB_Nickname.Text == PKX.GetSpeciesNameGeneration(0, WinFormsUtil.GetIndex(CB_Language), pkm.Format)) CHK_Nicknamed.Checked = false; } UpdateNickname(null, null); UpdateSprite(); } private void UpdateMetAsEgg(object sender, EventArgs e) { GB_EggConditions.Enabled = CHK_AsEgg.Checked; if (CHK_AsEgg.Checked) { if (!FieldsLoaded) return; CAL_EggDate.Value = DateTime.Now; CB_EggLocation.SelectedIndex = 1; return; } // Remove egg met data CHK_IsEgg.Checked = false; CAL_EggDate.Value = new DateTime(2000, 01, 01); CB_EggLocation.SelectedValue = 0; UpdateLegality(); } private void UpdateShinyPID(object sender, EventArgs e) { var ShinyPID = pkm.Format <= 2 || ModifierKeys != Keys.Control; UpdateShiny(ShinyPID); } private void UpdateShiny(bool PID) { pkm.PID = Util.GetHexValue(TB_PID.Text); pkm.Nature = WinFormsUtil.GetIndex(CB_Nature); pkm.Gender = PKX.GetGenderFromString(Label_Gender.Text); pkm.AltForm = CB_Form.SelectedIndex; pkm.Version = WinFormsUtil.GetIndex(CB_GameOrigin); if (pkm.Format > 2) { if (PID) { pkm.SetShiny(); TB_PID.Text = pkm.PID.ToString("X8"); if (pkm.GenNumber < 6 && TB_EC.Visible) TB_EC.Text = TB_PID.Text; } else { pkm.SetShinySID(); TID_Trainer.UpdateSID(); } } else { pkm.SetShiny(); Stats.LoadIVs(pkm.IVs); Stats.UpdateIVs(null, null); } UpdateIsShiny(); UpdatePreviewSprite?.Invoke(this, null); UpdateLegality(); } private void UpdateTSV(object sender, EventArgs e) { if (pkm.Format < 6) return; TID_Trainer.UpdateTSV(); pkm.PID = Util.GetHexValue(TB_PID.Text); Tip3.SetToolTip(TB_PID, $"PSV: {pkm.PSV:d4}"); } private void Update_ID(object sender, EventArgs e) { if (!FieldsLoaded) return; // Trim out nonhex characters TB_PID.Text = (pkm.PID = Util.GetHexValue(TB_PID.Text)).ToString("X8"); TB_EC.Text = (pkm.EncryptionConstant = Util.GetHexValue(TB_EC.Text)).ToString("X8"); UpdateIsShiny(); UpdateSprite(); Stats.UpdateCharacteristic(); // If the EC is changed, EC%6 (Characteristic) might be changed. if (pkm.Format <= 4) { FieldsLoaded = false; pkm.PID = Util.GetHexValue(TB_PID.Text); CB_Nature.SelectedValue = pkm.Nature; Label_Gender.Text = gendersymbols[pkm.Gender]; Label_Gender.ForeColor = GetGenderColor(pkm.Gender); FieldsLoaded = true; } } private void UpdateShadowID(object sender, EventArgs e) { if (!FieldsLoaded) return; FLP_Purification.Visible = NUD_ShadowID.Value > 0; } private void UpdatePurification(object sender, EventArgs e) { if (!FieldsLoaded) return; FieldsLoaded = false; CHK_Shadow.Checked = NUD_Purification.Value > 0; FieldsLoaded = true; } private void UpdateShadowCHK(object sender, EventArgs e) { if (!FieldsLoaded) return; FieldsLoaded = false; NUD_Purification.Value = CHK_Shadow.Checked ? NUD_Purification.Maximum : 0; ((IShadowPKM)pkm).Purification = (int)NUD_Purification.Value; UpdatePreviewSprite?.Invoke(this, null); FieldsLoaded = true; } private void ValidateComboBox(object sender) { if (!FieldsInitialized) return; if (!(sender is ComboBox cb)) return; if (cb.Text.Length == 0 && cb.Items.Count > 0) cb.SelectedIndex = 0; else if (cb.SelectedValue == null) cb.BackColor = InvalidSelection; else cb.ResetBackColor(); } private void ValidateComboBox(object sender, CancelEventArgs e) { if (!(sender is ComboBox)) return; ValidateComboBox(sender); UpdateSprite(); } private void ValidateComboBox2(object sender, EventArgs e) { if (!FieldsInitialized || !FieldsLoaded) return; ValidateComboBox(sender, null); if (sender == CB_Ability) { if (pkm.Format >= 6) TB_AbilityNumber.Text = (1 << CB_Ability.SelectedIndex).ToString(); else if (pkm.Format <= 5 && CB_Ability.SelectedIndex < 2) // Format <= 5, not hidden UpdateRandomPID(sender, e); UpdateLegality(); } else if (sender == CB_Nature) { if (pkm.Format <= 4) UpdateRandomPID(sender, e); pkm.Nature = WinFormsUtil.GetIndex(CB_Nature); 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(); } } private void ValidateMove(object sender, EventArgs e) { if (!FieldsInitialized || !FieldsLoaded) return; ValidateComboBox(sender); if (Moves.Contains(sender)) // Move UpdatePP(sender, e); // Legality pkm.Moves = Moves.Select(WinFormsUtil.GetIndex).ToArray(); pkm.RelearnMoves = Relearn.Select(WinFormsUtil.GetIndex).ToArray(); UpdateLegality(skipMoveRepop: true); } private void ValidateMovePaint(object sender, DrawItemEventArgs e) { if (e.Index < 0) return; var i = (ComboItem)((ComboBox)sender).Items[e.Index]; bool valid = AllowedMoves.Contains(i.Value) && !HaX; bool current = (e.State & DrawItemState.Selected) == DrawItemState.Selected; Brush tBrush = current ? SystemBrushes.HighlightText : TextBrush; Brush brush = current ? SystemBrushes.Highlight : valid ? LegalMove : BackBrush; e.Graphics.FillRectangle(brush, e.Bounds); e.Graphics.DrawString(i.Text, e.Font, tBrush, e.Bounds, StringFormat.GenericDefault); } private readonly IList<bool> IsMoveBoxOrdered = new bool[4]; private void ValidateMoveDropDown(object sender, EventArgs e) { var s = (ComboBox) sender; var index = Array.IndexOf(Moves, s); if (IsMoveBoxOrdered[index]) return; SetMoveDataSource(s); IsMoveBoxOrdered[index] = true; } private void ValidateLocation(object sender, EventArgs e) { ValidateComboBox(sender); if (!FieldsLoaded) return; pkm.Met_Location = WinFormsUtil.GetIndex(CB_MetLocation); pkm.Egg_Location = WinFormsUtil.GetIndex(CB_EggLocation); UpdateLegality(); } // Secondary Windows for Ribbons/Amie/Memories private void OpenRibbons(object sender, EventArgs e) => new RibbonEditor(pkm).ShowDialog(); private void OpenMedals(object sender, EventArgs e) => new SuperTrainingEditor(pkm).ShowDialog(); private void OpenHistory(object sender, EventArgs e) { // Write back current values pkm.HT_Name = TB_OTt2.Text; pkm.OT_Name = TB_OT.Text; pkm.IsEgg = CHK_IsEgg.Checked; pkm.CurrentFriendship = Util.ToInt32(TB_Friendship.Text); new MemoryAmie(pkm).ShowDialog(); TB_Friendship.Text = pkm.CurrentFriendship.ToString(); } /// <summary> /// Refreshes the interface for the current PKM format. /// </summary> /// <param name="sav">Save File context the editor is editing for</param> /// <param name="pk">Pokémon data to edit</param> public bool ToggleInterface(SaveFile sav, PKM pk) { pkm = GetCompatiblePKM(sav, pk); ToggleInterface(pkm); return FinalizeInterface(sav); } private void ToggleInterface(PKM t) { FLP_Purification.Visible = FLP_ShadowID.Visible = t is IShadowPKM; FLP_SizeCP.Visible = PB_Favorite.Visible = t is PB7; BTN_Medals.Visible = BTN_History.Visible = t.Format >= 6 && !(t is PB7); BTN_Ribbons.Visible = t.Format >= 3 && !(t is PB7); ToggleInterface(pkm.Format); } private void ToggleSecrets(bool hidden, int gen) { Label_EncryptionConstant.Visible = BTN_RerollEC.Visible = TB_EC.Visible = gen >= 6 && !hidden; BTN_RerollPID.Visible = Label_PID.Visible = TB_PID.Visible = gen >= 3 && !hidden; } private void ToggleInterface(int gen) { ToggleSecrets(HideSecretValues, gen); FLP_Country.Visible = FLP_SubRegion.Visible = FLP_3DSRegion.Visible = gen >= 6; GB_nOT.Visible = GB_RelearnMoves.Visible = gen >= 6; PB_MarkPentagon.Visible = gen >= 6; PB_MarkAlola.Visible = PB_MarkVC.Visible = PB_MarkGO.Visible = gen >= 7; FLP_NSparkle.Visible = L_NSparkle.Visible = CHK_NSparkle.Visible = gen == 5; CB_Form.Visible = Label_Form.Visible = CHK_AsEgg.Visible = GB_EggConditions.Visible = PB_Mark5.Visible = PB_Mark6.Visible = gen >= 4; FLP_ShinyLeaf.Visible = L_ShinyLeaf.Visible = ShinyLeaf.Visible = gen == 4; DEV_Ability.Enabled = DEV_Ability.Visible = gen > 3 && HaX; CB_Ability.Visible = !DEV_Ability.Enabled && gen >= 3; FLP_Nature.Visible = gen >= 3; FLP_Ability.Visible = gen >= 3; GB_ExtraBytes.Visible = GB_ExtraBytes.Enabled = gen >= 3; GB_Markings.Visible = gen >= 3; CB_Form.Enabled = gen >= 3; FLP_FriendshipForm.Visible = gen >= 2; FLP_HeldItem.Visible = gen >= 2; CHK_IsEgg.Visible = gen >= 2; FLP_PKRS.Visible = FLP_EggPKRSRight.Visible = gen >= 2; Label_OTGender.Visible = gen >= 2; FLP_CatchRate.Visible = gen == 1; // HaX override, needs to be after DEV_Ability enabled assignment. TB_AbilityNumber.Visible = gen >= 6 && DEV_Ability.Enabled; // Met Tab FLP_MetDate.Visible = gen >= 4; FLP_Fateful.Visible = FLP_Ball.Visible = FLP_OriginGame.Visible = gen >= 3; FLP_MetLocation.Visible = FLP_MetLevel.Visible = gen >= 2; FLP_EncounterType.Visible = gen >= 4 && gen <= 6; FLP_TimeOfDay.Visible = gen == 2; Contest.ToggleInterface(pkm, gen); Stats.ToggleInterface(pkm, gen); CenterSubEditors(); } private bool FinalizeInterface(SaveFile sav) { bool init = FieldsInitialized; FieldsInitialized = FieldsLoaded = false; bool TranslationRequired = false; PopulateFilteredDataSources(sav); PopulateFields(pkm); FieldsInitialized |= init; // SAV Specific Limits TB_OT.MaxLength = pkm.OTLength; TB_OTt2.MaxLength = pkm.OTLength; TB_Nickname.MaxLength = pkm.NickLength; // Hide Unused Tabs if (pkm.Format == 1 && tabMain.TabPages.Contains(Tab_Met)) { tabMain.TabPages.Remove(Tab_Met); } else if (pkm.Format != 1 && !tabMain.TabPages.Contains(Tab_Met)) { tabMain.TabPages.Insert(1, Tab_Met); TranslationRequired = true; } if (!HaX && sav is SAV7b) { FLP_HeldItem.Visible = false; FLP_Country.Visible = false; FLP_SubRegion.Visible = false; FLP_3DSRegion.Visible = false; } // Common HaX Interface MT_Level.Enabled = MT_Level.Visible = MT_Form.Enabled = MT_Form.Visible = HaX; TB_Level.Visible = !HaX; // pk2 save files do not have an Origin Game stored. Prompt the met location list to update. if (pkm.Format == 2) UpdateOriginGame(null, null); return TranslationRequired; } private void CenterSubEditors() { // Recenter PKM SubEditors FLP_PKMEditors.Location = new Point((tabMain.TabPages[0].Width - FLP_PKMEditors.Width) / 2, FLP_PKMEditors.Location.Y); } // Loading Setup public void TemplateFields(ITrainerInfo info) { FieldsLoaded = false; if (CB_GameOrigin.Items.Count > 0) CB_GameOrigin.SelectedIndex = 0; CB_Move1.SelectedValue = 1; SetDetailsOT(info); CB_Ball.SelectedIndex = Math.Min(0, CB_Ball.Items.Count - 1); CAL_MetDate.Value = CAL_EggDate.Value = DateTime.Today; CB_Species.SelectedValue = RequestSaveFile?.MaxSpeciesID ?? pkm.MaxSpeciesID; CHK_Nicknamed.Checked = false; LastData = null; FieldsLoaded = true; UpdateSprite(); } public void EnableDragDrop(DragEventHandler enter, DragEventHandler drop) { AllowDrop = true; DragDrop += drop; foreach (TabPage tab in tabMain.TabPages) { tab.AllowDrop = true; tab.DragEnter += enter; tab.DragDrop += drop; } } // ReSharper disable once FieldCanBeMadeReadOnly.Global public Action<ShowdownSet> LoadShowdownSet; private void LoadShowdownSetDefault(ShowdownSet Set) { var pk = PreparePKM(); pk.ApplySetDetails(Set); PopulateFields(pk); } public void ChangeLanguage(SaveFile sav, PKM pk) { // Force an update to the met locations origintrack = GameVersion.Invalid; bool alreadyInit = FieldsInitialized; FieldsInitialized = false; InitializeLanguage(sav); CenterSubEditors(); PopulateFields(pk); // put data back in form FieldsInitialized |= alreadyInit; } public void FlickerInterface() { tabMain.SelectedTab = Tab_Met; // parent tab of CB_GameOrigin tabMain.SelectedTab = Tab_Main; // first tab } private void InitializeLanguage(SaveFile SAV) { // Set the various ComboBox DataSources up with their allowed entries SetCountrySubRegion(CB_Country, "countries"); CB_3DSReg.DataSource = Util.GetUnsortedCBList("regions3ds"); CB_EncounterType.DataSource = new BindingSource(GameInfo.EncounterTypeDataSource, null); CB_Nature.DataSource = new BindingSource(GameInfo.NatureDataSource, null); // Sub editors Stats.InitializeDataSources(); PopulateFilteredDataSources(SAV); } private void PopulateFilteredDataSources(SaveFile SAV) { GameInfo.Strings.SetItemDataSource(SAV.Version, SAV.Generation, SAV.MaxItemID, SAV.HeldItems, HaX); if (SAV.Generation > 1) CB_HeldItem.DataSource = new BindingSource(GameInfo.ItemDataSource.Where(i => i.Value <= SAV.MaxItemID).ToList(), null); 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); DEV_Ability.DataSource = new BindingSource(GameInfo.AbilityDataSource.Where(a => a.Value <= SAV.MaxAbilityID).ToList(), null); var gamelist = GameUtil.GetVersionsWithinRange(SAV, SAV.Generation).ToList(); CB_GameOrigin.DataSource = new BindingSource(GameInfo.VersionDataSource.Where(g => gamelist.Contains((GameVersion)g.Value)).ToList(), null); // Set the Move ComboBoxes too.. MoveDataAllowed = GameInfo.Strings.MoveDataSource = (HaX ? GameInfo.HaXMoveDataSource : GameInfo.LegalMoveDataSource).Where(m => m.Value <= SAV.MaxMoveID).ToList(); // Filter Z-Moves if appropriate foreach (var cb in Moves.Concat(Relearn)) { cb.DataSource = new BindingSource(GameInfo.MoveDataSource, null); } } private static List<string> GetSuggestionMessage(PKM pkm, int level, int location, int minlvl) { var suggestion = new List<string> { MsgPKMSuggestionStart }; if (pkm.Format >= 3) { var met_list = GameInfo.GetLocationList((GameVersion)pkm.Version, pkm.Format, egg: false); var locstr = met_list.First(loc => loc.Value == location).Text; suggestion.Add($"{MsgPKMSuggestionMetLocation} {locstr}"); suggestion.Add($"{MsgPKMSuggestionMetLevel} {level}"); } if (pkm.CurrentLevel < minlvl) suggestion.Add($"{MsgPKMSuggestionLevel} {minlvl}"); return suggestion; } private static IReadOnlyList<ComboItem> GetAbilityList(PKM pkm) { var abils = pkm.PersonalInfo.Abilities; return GameInfo.GetAbilityList(abils, pkm.Format); } private static PKM GetCompatiblePKM(SaveFile sav, PKM current) { if (current.Format < 3 || current.GetType() != sav.PKMType) return sav.BlankPKM; return current; } } }