D2Multi/CharacterMissionsForm.cs
2026-03-22 19:54:19 -07:00

142 lines
5.3 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
namespace D2Multi
{
public partial class CharacterMissionsForm : Form
{
readonly D2Account _account;
readonly List<D2Character> _editingCharacters;
BindingList<CharacterMissionGridRow> _rows;
BindingSource _source;
public CharacterMissionsForm(D2Account account, string accountLabel)
{
if (account == null)
throw new ArgumentNullException(nameof(account));
_account = account;
_editingCharacters = CloneCharacterList(account.Characters);
InitializeComponent();
Text = "Characters — " + (accountLabel ?? account.Name ?? "Account");
BuildGrid();
}
static List<D2Character> CloneCharacterList(IEnumerable<D2Character> src)
{
var list = new List<D2Character>();
if (src == null)
return list;
foreach (var c in src)
{
if (c == null)
continue;
list.Add(CloneCharacter(c));
}
return list;
}
static D2Character CloneCharacter(D2Character c)
{
var missions = c.Missions == null
? new List<D2Mission>()
: c.Missions.Where(m => m != null).Select(m => new D2Mission
{
Level = m.Level,
A1_Enpowered = m.A1_Enpowered,
A5_Socket = m.A5_Socket,
}).ToList();
return new D2Character { Name = c.Name, Class = c.Class, Missions = missions };
}
void BuildGrid()
{
var wrapAccount = new D2Account { Characters = _editingCharacters };
_rows = new BindingList<CharacterMissionGridRow>(CharacterMissionGridRow.FromAccount(wrapAccount));
_source = new BindingSource { DataSource = _rows };
dgvCharacters.AutoGenerateColumns = false;
dgvCharacters.Columns.Clear();
void AddText(string prop, string header, int width)
{
dgvCharacters.Columns.Add(new DataGridViewTextBoxColumn
{
DataPropertyName = prop,
HeaderText = header,
Width = width,
});
}
void AddBool(string prop, string header, string tip, int width)
{
var col = new DataGridViewCheckBoxColumn
{
DataPropertyName = prop,
HeaderText = header,
Width = width,
ThreeState = false,
};
col.ToolTipText = tip;
dgvCharacters.Columns.Add(col);
}
AddText(nameof(CharacterMissionGridRow.Name), "Character", 140);
AddText(nameof(CharacterMissionGridRow.Class), "Class", 100);
const string tipDone = "Checked = reward taken (no longer available). Unchecked = still available.";
AddBool(nameof(CharacterMissionGridRow.NormalA1), "Normal A1", tipDone, 85);
AddBool(nameof(CharacterMissionGridRow.NormalA5), "Normal A5", tipDone, 85);
AddBool(nameof(CharacterMissionGridRow.NightmareA1), "NM A1", tipDone, 70);
AddBool(nameof(CharacterMissionGridRow.NightmareA5), "NM A5", tipDone, 70);
AddBool(nameof(CharacterMissionGridRow.HellA1), "Hell A1", tipDone, 75);
AddBool(nameof(CharacterMissionGridRow.HellA5), "Hell A5", tipDone, 75);
dgvCharacters.Columns.Add(new DataGridViewTextBoxColumn
{
DataPropertyName = nameof(CharacterMissionGridRow.MissionsAvailable),
HeaderText = "Available",
ReadOnly = true,
Width = 80,
ToolTipText = "Count of rewards not yet claimed (A1 + A5 across all difficulties).",
});
dgvCharacters.DataSource = _source;
}
void BtnAddCharacter_Click(object sender, EventArgs e)
{
var c = D2CharacterMissionHelper.CreateNewCharacter();
_editingCharacters.Add(c);
_rows.Add(new CharacterMissionGridRow(c));
if (_rows.Count > 0)
dgvCharacters.CurrentCell = dgvCharacters.Rows[_rows.Count - 1].Cells[0];
}
void BtnRemoveCharacter_Click(object sender, EventArgs e)
{
if (_source.Current is CharacterMissionGridRow row)
{
_editingCharacters.Remove(row.Character);
_rows.Remove(row);
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (DialogResult == DialogResult.OK)
{
dgvCharacters.EndEdit();
_source.EndEdit();
if (_editingCharacters.Any(c => string.IsNullOrWhiteSpace(c?.Name)))
{
e.Cancel = true;
MessageBox.Show(this, "Each character needs a name.", Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
_account.Characters = _editingCharacters;
}
base.OnFormClosing(e);
}
}
}