Add status indication & switcher popup

Shows on all tabs to make it clear.
Obviously, status condition is only saved in formats that save status condition in their slot's resting format. Gen3 box mons won't store Burn, etc.
This commit is contained in:
Kurt 2024-04-17 00:35:42 -05:00
parent b60648627a
commit 35bf97eaf1
9 changed files with 432 additions and 6 deletions

View file

@ -0,0 +1,62 @@
using System;
namespace PKHeX.Core;
[Flags]
public enum StatusCondition
{
None = 0,
#pragma warning disable RCS1191 // Declare enum value as combination of names
// Sleep (if present) indicates the number of turns remaining
Sleep1 = 1,
Sleep2 = 2,
Sleep3 = 3,
Sleep4 = 4,
Sleep5 = 5,
Sleep6 = 6,
Sleep7 = 7,
#pragma warning restore RCS1191 // Declare enum value as combination of names
Poison = 1 << 3,
Burn = 1 << 4,
Freeze = 1 << 5,
Paralysis = 1 << 6,
PoisonBad = 1 << 7,
}
public static class StatusConditionUtil
{
public static StatusType GetStatusType(this PKM pk)
{
var value = (StatusCondition)pk.Status_Condition;
return GetStatusType(value);
}
public static StatusType GetStatusType(this StatusCondition value)
{
if (value == StatusCondition.None)
return StatusType.None;
if (value <= StatusCondition.Sleep7)
return (StatusType)value;
if ((value & StatusCondition.Paralysis) != 0)
return StatusType.Paralysis;
if ((value & StatusCondition.Burn) != 0)
return StatusType.Burn;
if ((value & (StatusCondition.Poison | StatusCondition.PoisonBad)) != 0)
return StatusType.Poison;
if ((value & StatusCondition.Freeze) != 0)
return StatusType.Freeze;
return StatusType.None;
}
}
public enum StatusType
{
None = 0,
Sleep = 1,
Poison = 2,
Burn = 3,
Freeze = 4,
Paralysis = 5,
}

View file

@ -310,4 +310,9 @@ public static class SpriteUtil
}
return img;
}
public static Image GetStatusSprite(StatusType value)
{
throw new NotImplementedException();
}
}

View file

@ -0,0 +1,60 @@
using System.Drawing;
using PKHeX.Core;
namespace PKHeX.Drawing.PokeSprite;
/// <summary>
/// Utility class for getting the color of a <see cref="StatusCondition"/>.
/// </summary>
public static class StatusColor
{
public static Color Sleep => Color.FromArgb(200, 200, 200);
public static Color Freeze => Color.FromArgb(0, 255, 255);
public static Color Paralysis => Color.FromArgb(255, 255, 0);
public static Color Burn => Color.FromArgb(255, 0, 0);
public static Color Poison => Color.FromArgb(128, 0, 255);
public static Color PoisonBad => Color.FromArgb(200, 0, 255);
public static Color None => Color.FromArgb(255, 255, 255, 255); // Transparent
/// <summary>
/// Gets the color of a <see cref="StatusCondition"/>.
/// </summary>
/// <param name="value">Status to get the color of.</param>
/// <returns>Color of the status.</returns>
public static Color GetStatusColor(int value) => ((StatusCondition)value).GetStatusColor();
/// <inheritdoc cref="GetStatusColor(int)"/>
public static Color GetStatusColor(this StatusType value) => value switch
{
StatusType.None => None,
StatusType.Sleep => Sleep,
StatusType.Freeze => Freeze,
StatusType.Paralysis => Paralysis,
StatusType.Burn => Burn,
StatusType.Poison => Poison,
_ => None,
};
/// <inheritdoc cref="GetStatusColor(int)"/>
public static Color GetStatusColor(this PKM pk) => ((StatusCondition)pk.Status_Condition).GetStatusColor();
/// <inheritdoc cref="GetStatusColor(int)"/>
public static Color GetStatusColor(this StatusCondition value)
{
if (value == StatusCondition.None)
return None;
if (value < StatusCondition.Poison)
return Sleep;
if (value.HasFlag(StatusCondition.Poison))
return Poison;
if (value.HasFlag(StatusCondition.Freeze))
return Freeze;
if (value.HasFlag(StatusCondition.Paralysis))
return Paralysis;
if (value.HasFlag(StatusCondition.Burn))
return Burn;
if (value.HasFlag(StatusCondition.PoisonBad))
return PoisonBad;
return default;
}
}

View file

@ -239,6 +239,7 @@ namespace PKHeX.WinForms.Controls
Label_EncryptionConstant = new System.Windows.Forms.Label();
BTN_RerollEC = new System.Windows.Forms.Button();
TB_EC = new System.Windows.Forms.TextBox();
StatusView = new StatusConditionView();
TC_Editor = new VerticalTabControlEntityEditor();
Tab_Main = new System.Windows.Forms.TabPage();
Tab_Met = new System.Windows.Forms.TabPage();
@ -510,8 +511,8 @@ namespace PKHeX.WinForms.Controls
//
// UC_Gender
//
UC_Gender.AccessibleDescription = "Entity Gender Pane (0) (0)";
UC_Gender.AccessibleName = "Entity Gender Pane (0) (0)";
UC_Gender.AccessibleDescription = "Entity Gender Pane";
UC_Gender.AccessibleName = "Entity Gender Pane";
UC_Gender.AccessibleRole = System.Windows.Forms.AccessibleRole.Graphic;
UC_Gender.AllowClick = false;
UC_Gender.BackgroundImage = (System.Drawing.Image)resources.GetObject("UC_Gender.BackgroundImage");
@ -2506,8 +2507,8 @@ namespace PKHeX.WinForms.Controls
//
// UC_OTGender
//
UC_OTGender.AccessibleDescription = "Trainer Gender Pane (0) (0)";
UC_OTGender.AccessibleName = "Trainer Gender Pane (0) (0)";
UC_OTGender.AccessibleDescription = "Trainer Gender Pane";
UC_OTGender.AccessibleName = "Trainer Gender Pane";
UC_OTGender.AccessibleRole = System.Windows.Forms.AccessibleRole.Graphic;
UC_OTGender.AllowClick = true;
UC_OTGender.BackgroundImage = (System.Drawing.Image)resources.GetObject("UC_OTGender.BackgroundImage");
@ -2714,8 +2715,8 @@ namespace PKHeX.WinForms.Controls
//
// UC_HTGender
//
UC_HTGender.AccessibleDescription = "Handling Trainer Gender Pane (0) (0)";
UC_HTGender.AccessibleName = "Handling Trainer Gender Pane (0) (0)";
UC_HTGender.AccessibleDescription = "Handling Trainer Gender Pane";
UC_HTGender.AccessibleName = "Handling Trainer Gender Pane";
UC_HTGender.AccessibleRole = System.Windows.Forms.AccessibleRole.Graphic;
UC_HTGender.AllowClick = true;
UC_HTGender.BackgroundImage = (System.Drawing.Image)resources.GetObject("UC_HTGender.BackgroundImage");
@ -2883,6 +2884,15 @@ namespace PKHeX.WinForms.Controls
TB_EC.TabIndex = 33;
TB_EC.Validated += Update_ID;
//
// StatusView
//
StatusView.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
StatusView.Location = new System.Drawing.Point(357, 1);
StatusView.Margin = new System.Windows.Forms.Padding(0);
StatusView.Name = "StatusView";
StatusView.Size = new System.Drawing.Size(40, 24);
StatusView.TabIndex = 2;
//
// TC_Editor
//
TC_Editor.Alignment = System.Windows.Forms.TabAlignment.Right;
@ -2967,6 +2977,7 @@ namespace PKHeX.WinForms.Controls
// PKMEditor
//
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
Controls.Add(StatusView);
Controls.Add(TC_Editor);
Controls.Add(Hidden_TC);
Name = "PKMEditor";
@ -3306,5 +3317,6 @@ namespace PKHeX.WinForms.Controls
private System.Windows.Forms.Button BTN_OTNameWarn;
private System.Windows.Forms.FlowLayoutPanel FLP_HomeTracker;
private System.Windows.Forms.FlowLayoutPanel FLP_EncryptionConstant;
private StatusConditionView StatusView;
}
}

View file

@ -114,6 +114,7 @@ public sealed partial class PKMEditor : UserControl, IMainEditor
Stats.UpdateStats();
if (Entity is IScaledSizeAbsolute)
SizeCP.TryResetStats();
StatusView.LoadPKM(Entity);
}
private void LoadPartyStats(PKM pk) => Stats.LoadPartyStats(pk);

View file

@ -0,0 +1,63 @@
namespace PKHeX.WinForms
{
partial class StatusBrowser
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
flp = new System.Windows.Forms.FlowLayoutPanel();
SuspendLayout();
//
// flp
//
flp.AutoSize = true;
flp.Dock = System.Windows.Forms.DockStyle.Fill;
flp.Location = new System.Drawing.Point(0, 0);
flp.Name = "flp";
flp.Size = new System.Drawing.Size(127, 88);
flp.TabIndex = 0;
//
// StatusBrowser
//
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
AutoSize = true;
AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
ClientSize = new System.Drawing.Size(127, 88);
Controls.Add(flp);
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
Name = "StatusBrowser";
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "Status Browser";
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.FlowLayoutPanel flp;
}
}

View file

@ -0,0 +1,100 @@
using System;
using System.Windows.Forms;
using PKHeX.Core;
using PKHeX.Drawing.PokeSprite;
using PKHeX.WinForms.Controls;
namespace PKHeX.WinForms;
public partial class StatusBrowser : Form
{
public bool WasChosen { get; private set; }
public StatusCondition Choice { get; private set; }
private const int StatusHeight = 24;
private const int StatusWidth = StatusHeight * 2;
private const int StatusCount = 7;
private const int StatusBrowserWidth = StatusWidth * 2;
public StatusBrowser()
{
InitializeComponent();
NUD_Sleep = new NumericUpDown
{
Minimum = 1,
Maximum = 7,
Value = 1,
Width = StatusWidth,
TextAlign = HorizontalAlignment.Center,
Margin = Padding.Empty,
Padding = Padding.Empty,
};
Add(GetImage(StatusCondition.None, "None"));
Add(GetImage(StatusCondition.Sleep1, "Sleep"), false);
Add(NUD_Sleep);
Add(GetImage(StatusCondition.Poison, "Poison"));
Add(GetImage(StatusCondition.Burn, "Burn"));
Add(GetImage(StatusCondition.Paralysis, "Paralysis"));
Add(GetImage(StatusCondition.Freeze, "Freeze"));
Add(GetImage(StatusCondition.PoisonBad, "Toxic"));
Height = StatusCount * StatusHeight;
Width = StatusBrowserWidth;
}
private readonly NumericUpDown NUD_Sleep;
private void Add(Control c, bool flowBreak = true)
{
flp.Controls.Add(c);
if (flowBreak)
flp.SetFlowBreak(c, true);
}
public void LoadList(PKM pk)
{
var condition = (StatusCondition)pk.Status_Condition;
NUD_Sleep.Value = Math.Max(1, (int)condition & 7);
Text = condition.ToString();
}
private SelectablePictureBox GetImage(StatusCondition value, string name)
{
var color = value.GetStatusColor();
var pb = new SelectablePictureBox
{
BackColor = color,
Name = name,
AccessibleDescription = name,
AccessibleName = name,
AccessibleRole = AccessibleRole.Graphic,
Margin = Padding.Empty,
Padding = Padding.Empty,
Width = StatusWidth,
Height = StatusHeight,
};
pb.MouseEnter += (_, _) => Text = name;
pb.Click += (_, _) =>
{
if (value is StatusCondition.Sleep1)
value = (StatusCondition)NUD_Sleep.Value;
SelectValue(value);
};
pb.KeyDown += (_, e) =>
{
if (e.KeyCode == Keys.Enter)
SelectValue(value);
};
return pb;
}
private void SelectValue(StatusCondition value)
{
Choice = value;
WasChosen = true;
Close();
}
}

View file

@ -0,0 +1,60 @@
namespace PKHeX.WinForms.Controls
{
partial class StatusConditionView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
PB_Status = new SelectablePictureBox();
((System.ComponentModel.ISupportInitialize)PB_Status).BeginInit();
SuspendLayout();
//
// PB_Status
//
PB_Status.Dock = System.Windows.Forms.DockStyle.Fill;
PB_Status.Location = new System.Drawing.Point(0, 0);
PB_Status.Margin = new System.Windows.Forms.Padding(0);
PB_Status.Name = "PB_Status";
PB_Status.Size = new System.Drawing.Size(224, 96);
PB_Status.TabIndex = 0;
PB_Status.Click += PB_Status_Click;
//
// StatusConditionView
//
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
Controls.Add(PB_Status);
Margin = new System.Windows.Forms.Padding(0);
Name = "StatusConditionView";
Size = new System.Drawing.Size(224, 96);
((System.ComponentModel.ISupportInitialize)PB_Status).EndInit();
ResumeLayout(false);
}
#endregion
private SelectablePictureBox PB_Status;
}
}

View file

@ -0,0 +1,63 @@
using System;
using System.Windows.Forms;
using PKHeX.Core;
using PKHeX.Drawing.PokeSprite;
namespace PKHeX.WinForms.Controls;
public partial class StatusConditionView : UserControl
{
private PKM? pk;
private bool Loading;
private readonly ToolTip Hover = new()
{
AutoPopDelay = 5000,
InitialDelay = 200,
ReshowDelay = 500,
ShowAlways = true,
};
public StatusConditionView()
{
InitializeComponent();
PB_Status.MouseHover += (s, e) => PB_Status.Cursor = Cursors.Hand;
}
public void LoadPKM(PKM entity)
{
pk = entity;
LoadStoredValues();
}
public void LoadStoredValues()
{
if (pk is null || Loading)
return;
Loading = true;
var status = pk.Status_Condition;
SetStatus((StatusCondition)status);
Loading = false;
}
private void SetStatus(StatusCondition status)
{
var color = status.GetStatusColor();
PB_Status.BackColor = color;
Hover.SetToolTip(PB_Status, $"Status Condition: {status}");
}
private void PB_Status_Click(object sender, EventArgs e)
{
ArgumentNullException.ThrowIfNull(pk);
using var form = new StatusBrowser();
form.LoadList(pk);
form.ShowDialog();
if (!form.WasChosen)
return;
var current = pk.Status_Condition;
current &= ~0xFF;
current |= (int)form.Choice;
pk.Status_Condition = current;
LoadStoredValues();
}
}