PKHeX/PKHeX.Avalonia/ViewModels/Subforms/SAVSuperTrain6ViewModel.cs
montanon 875f7904ea Fix WinForms parity: BoxViewer DnD, auto-load, recent files, plugins
BoxViewer drag-drop (4 files):
- SlotControl: FindSlotChangeManager now resolves from BoxViewerVM
- SlotChangeManager: register/unregister box viewers, ResolveSlot
  checks main editor + all registered box viewers for slot lookups
- BoxViewerVM: accepts shared SlotChangeManager reference
- MainWindowVM: pass SlotChangeManager to BoxViewer on open

Auto-load save on startup:
- App: call StartupUtil.GetStartup() with CLI args on window open
- App: call StartupUtil.FormLoadInitialActions() for HaX/version
- MainWindowVM: add LoadInitialSave() for startup entity loading

Recent files in FolderList:
- FolderListVM: populate Recent tab from RecentlyLoaded settings
- FolderListVM: add FileOpenRequested callback + OpenSaveFile command
- FolderListView: double-tap DataGrid row opens the save file

Plugin initialization:
- MainWindowVM: check PluginLoadEnable before loading plugins
- MainWindowVM: pass AvaloniaPluginHost (ISaveFileProvider) to plugins
- MainWindowVM: update plugin host save reference on file load

Clone pattern fixes:
- SimpleTrainerVM: actually clone SAV (was storing live reference)
- Misc4VM: clone SAV4, CopyChangesFrom on save
- Misc5VM: clone SAV5, CopyChangesFrom on save
- SAVSuperTrain6VM: flush stage record before switching stages

Other:
- MemoryAmieView: Sociability max changed from 255 to 4294967295
2026-03-18 15:32:37 -03:00

168 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PKHeX.Core;
namespace PKHeX.Avalonia.ViewModels.Subforms;
/// <summary>
/// Model for a training bag slot.
/// </summary>
public partial class TrainingBagSlotModel : ObservableObject
{
public int Index { get; }
[ObservableProperty]
private int _selectedBagIndex;
public string DisplayName => $"Slot {Index + 1}";
public TrainingBagSlotModel(int index, int bagIndex)
{
Index = index;
_selectedBagIndex = bagIndex;
}
}
/// <summary>
/// ViewModel for the Gen 6 Super Training editor.
/// Edits training bags and regimen records.
/// </summary>
public partial class SAVSuperTrain6ViewModel : SaveEditorViewModelBase
{
private readonly SaveFile _origin;
private readonly SAV6 _sav;
private readonly SuperTrainBlock _stb;
private bool _loading;
public List<string> StageNames { get; } = [];
public List<string> BagNames { get; }
public List<ComboItem> SpeciesList { get; }
public ObservableCollection<TrainingBagSlotModel> BagSlots { get; } = [];
[ObservableProperty]
private int _selectedStageIndex = -1;
// Record holder 1
[ObservableProperty]
private int _species1;
[ObservableProperty]
private string _gender1 = "0";
[ObservableProperty]
private string _form1 = "0";
[ObservableProperty]
private string _time1 = "0";
// Record holder 2
[ObservableProperty]
private int _species2;
[ObservableProperty]
private string _gender2 = "0";
[ObservableProperty]
private string _form2 = "0";
[ObservableProperty]
private string _time2 = "0";
public SAVSuperTrain6ViewModel(SAV6 sav) : base(sav)
{
_sav = (SAV6)(_origin = sav).Clone();
_stb = ((ISaveBlock6Main)_sav).SuperTrain;
var bagNames = GameInfo.Strings.trainingbags.ToList();
if (bagNames.Count > 0)
bagNames[0] = "---";
BagNames = bagNames;
SpeciesList = GameInfo.FilteredSources.Species.ToList();
var stages = GameInfo.Strings.trainingstage;
for (int i = 0; i < 32; i++)
StageNames.Add($"{i + 1:00} - {stages[i]}");
// Load bags
for (int i = 0; i < 12; i++)
{
int bagId = _stb.GetBag(i);
BagSlots.Add(new TrainingBagSlotModel(i, bagId));
}
SelectedStageIndex = 0;
}
partial void OnSelectedStageIndexChanged(int oldValue, int newValue)
{
if (oldValue >= 0)
SaveStageRecord(oldValue);
if (newValue >= 0)
LoadStageRecord(newValue);
}
private void LoadStageRecord(int index)
{
_loading = true;
var h1 = _stb.GetHolder1(index);
var h2 = _stb.GetHolder2(index);
Species1 = h1.Species;
Gender1 = h1.Gender.ToString();
Form1 = h1.Form.ToString();
Species2 = h2.Species;
Gender2 = h2.Gender.ToString();
Form2 = h2.Form.ToString();
Time1 = _stb.GetTime1(index).ToString(CultureInfo.InvariantCulture);
Time2 = _stb.GetTime2(index).ToString(CultureInfo.InvariantCulture);
_loading = false;
}
private void SaveStageRecord(int index)
{
if (index < 0)
return;
var h1 = _stb.GetHolder1(index);
h1.Species = (ushort)Species1;
if (byte.TryParse(Gender1, out var g1)) h1.Gender = g1;
if (byte.TryParse(Form1, out var f1)) h1.Form = f1;
var h2 = _stb.GetHolder2(index);
h2.Species = (ushort)Species2;
if (byte.TryParse(Gender2, out var g2)) h2.Gender = g2;
if (byte.TryParse(Form2, out var f2)) h2.Form = f2;
if (float.TryParse(Time1, out var t1)) _stb.SetTime1(index, t1);
if (float.TryParse(Time2, out var t2)) _stb.SetTime2(index, t2);
}
[RelayCommand]
private void Save()
{
SaveStageRecord(SelectedStageIndex);
// Save bags (compact non-empty slots to the front)
int emptySlots = 0;
for (int i = 0; i < 12; i++)
{
int bagIndex = BagSlots[i].SelectedBagIndex;
if (bagIndex <= 0)
{
emptySlots++;
continue;
}
_stb.SetBag(i - emptySlots, (byte)bagIndex);
}
// Clear trailing stale slots left after compaction
for (int i = 12 - emptySlots; i < 12; i++)
_stb.SetBag(i, 0);
_origin.CopyChangesFrom(_sav);
Modified = true;
}
}