Finish Donut struct (0x00 is milliseconds!)

Interlink the GUI for ticks+calendar so that modifying one updates the other if applicable.

add randomize (very simplistic, just pick a random lv3 power)
add all-shiny (sparkling, alpha/big/little, catching)
This commit is contained in:
Kurt 2025-12-15 22:33:11 -06:00
parent d45cdcb9e0
commit ac25835d65
14 changed files with 270 additions and 52 deletions

View File

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using static System.Buffers.Binary.BinaryPrimitives;
namespace PKHeX.Core;
@ -14,6 +16,116 @@ public Donut9a GetDonut(int index)
var slice = Raw.Slice(index * Donut9a.Size, Donut9a.Size);
return new Donut9a(slice);
}
public void Compress()
{
// Remove slots where donut is empty, shift entry up.
int writePos = 0;
for (int readPos = 0; readPos < MaxCount; readPos++)
{
var read = GetDonut(readPos);
if (read.IsEmpty)
continue;
if (writePos != readPos)
{
var write = GetDonut(writePos);
read.CopyTo(write);
read.Clear(); // Clear old slot
}
writePos++;
}
}
private static ReadOnlySpan<byte> Template =>
[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x54, 0x96, 0x00, 0x10, 0x0E, 0x74, 0x0A,
0x74, 0x0A, 0x74, 0x0A, 0x74, 0x0A, 0x74, 0x0A, 0x74, 0x0A, 0x74, 0x0A, 0x74, 0x0A, 0x74, 0x0A,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xD4, 0xEC, 0xA6, 0x6A, 0x53, 0x37, 0x0D,
0x2E, 0xA0, 0x7F, 0xD6, 0xA0, 0x1E, 0xCF, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
public void SetAllAsShinyTemplate()
{
var rand = Util.Rand;
var flavorDict = DonutInfo.Flavors.ToDictionary(z => z.Name, z => z.Hash);
for (int i = 0; i < MaxCount; i++)
{
// Apply template data
var entry = GetDonut(i);
Template.CopyTo(entry.Data);
// Update donut with data to match what we want.
ApplyShinySizeCatch(entry, rand, flavorDict);
// Update creation time
ApplyTimestampNow(entry, i);
}
}
public void SetAllRandomLv3()
{
var rand = Util.Rand;
var flavorDict = DonutInfo.Flavors.Where(z => z.Name.EndsWith("lv3")).ToArray();
for (int i = 0; i < MaxCount; i++)
{
// Apply template data
var entry = GetDonut(i);
Template.CopyTo(entry.Data);
// Update donut with data to match what we want.
rand.Shuffle(flavorDict);
entry.Flavor0 = flavorDict[0].Hash;
entry.Flavor1 = flavorDict[1].Hash;
entry.Flavor2 = flavorDict[2].Hash;
// Update creation time
ApplyTimestampNow(entry, i);
}
}
private static void ApplyTimestampNow(Donut9a entry, int bias = 0)
{
var now = DateTime.Now;
if (bias != 0) // some fudge factor to differentiate donuts made on the same millisecond
now = now.AddMilliseconds(bias);
var ticks = (ulong)(now - new DateTime(1900, 1, 1)).TotalMilliseconds;
entry.MillisecondsSince1900 = ticks;
entry.DateTime1900.Timestamp = now;
}
private static void ApplyShinySizeCatch(Donut9a entry, Random rand, Dictionary<string, ulong> flavorDict)
{
// Shiny power is sweet 3-21. Allow "all" rather than just be single type.
var type = rand.Next(17 + 1 + 1);
var flavor0 = $"sweet_{(type + 3):00}_lv3"; // Sparkling (sweet_03-21)
var roll2 = rand.Next(3);
var flavor1 = roll2 switch
{
0 or 1 => $"fresh_{(1 + roll2):00}_lv3", // Humungo (fresh_01) or Teensy (fresh_02)
_ => "sweet_01_lv3", // Alpha
};
var flavor2 = $"fresh_{(type + 4):00}_lv3"; // Catching Power (fresh_04-22)
// Set flavors to donut
entry.Flavor0 = flavorDict[flavor0];
entry.Flavor1 = flavorDict[flavor1];
entry.Flavor2 = flavorDict[flavor2];
}
public void CloneAllFromIndex(int index)
{
ArgumentOutOfRangeException.ThrowIfGreaterThan<uint>((uint)index, MaxCount - 1);
var source = GetDonut(index);
for (int i = 0; i < MaxCount; i++)
{
if (i != index)
source.CopyTo(GetDonut(i));
}
}
}
public static class DonutInfo
@ -451,7 +563,7 @@ public static bool TryGetFlavorName(ulong hash, [NotNullWhen(true)] out string?
public Span<byte> Data => Raw.Span;
/*
0x00 u64 Unknown
0x00 u64 MillisecondsSince1900
0x08 u8 Stars
0x09 u8 LevelBoost
@ -475,7 +587,7 @@ public static bool TryGetFlavorName(ulong hash, [NotNullWhen(true)] out string?
0x40 u64 Reserved
*/
public ulong Unknown { get => ReadUInt64LittleEndian(Data); set => WriteUInt64LittleEndian(Data, value); }
public ulong MillisecondsSince1900 { get => ReadUInt64LittleEndian(Data); set => WriteUInt64LittleEndian(Data, value); }
public byte Stars { get => Data[0x08]; set => Data[0x08] = value; }
public byte LevelBoost { get => Data[0x09]; set => Data[0x09] = value; }
@ -505,7 +617,9 @@ public static bool TryGetFlavorName(ulong hash, [NotNullWhen(true)] out string?
public ulong Reserved { get => ReadUInt64LittleEndian(Data[0x40..]); set => WriteUInt64LittleEndian(Data[0x40..], value); }
public bool IsEmpty => Unknown != 0;
public void UpdateDateTime() => DateTime1900.Timestamp = new DateTime(1900, 1, 1).AddMilliseconds(MillisecondsSince1900);
public bool IsEmpty => MillisecondsSince1900 != 0;
public int FlavorCount => Flavor0 == 0 ? 0 : Flavor1 == 0 ? 1 : Flavor2 == 0 ? 2 : 3;
public ushort[] GetBerries() =>

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=Pokédex Skin
SAV_DLC5.Tab_Pokestar=Pokéwood
SAV_DLC5.Tab_PWT=PWT
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=Hinzuf.
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=PokéDex Skin
SAV_DLC5.Tab_Pokestar=Pokéstar Studios
SAV_DLC5.Tab_PWT=PWT
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=Add
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=PokéDex Skin
SAV_DLC5.Tab_Pokestar=Pokéstar Studios
SAV_DLC5.Tab_PWT=PWT
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=Add
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=PokéDex Skin
SAV_DLC5.Tab_Pokestar=Pokéstar Studios
SAV_DLC5.Tab_PWT=PWT
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=Add
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=PokéDex Skin
SAV_DLC5.Tab_Pokestar=Pokéstar Studios
SAV_DLC5.Tab_PWT=PWT
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=Ajouter
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=PokéDex Skin
SAV_DLC5.Tab_Pokestar=Pokéstar Studios
SAV_DLC5.Tab_PWT=PWT
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=Add
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=PokéDex Skin
SAV_DLC5.Tab_Pokestar=Pokéstar Studios
SAV_DLC5.Tab_PWT=PWT
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=追加
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=PokéDex Skin
SAV_DLC5.Tab_Pokestar=Pokéstar Studios
SAV_DLC5.Tab_PWT=PWT
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=Add
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=宝可梦图鉴皮肤
SAV_DLC5.Tab_Pokestar=宝可梦好莱坞
SAV_DLC5.Tab_PWT=宝可梦世界锦标赛
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=添加
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -1085,6 +1085,8 @@ SAV_DLC5.Tab_PokeDex=PokéDex Skin
SAV_DLC5.Tab_Pokestar=Pokéstar Studios
SAV_DLC5.Tab_PWT=PWT
SAV_Donut9a.B_Cancel=Cancel
SAV_Donut9a.B_Export=Export
SAV_Donut9a.B_Import=Import
SAV_Donut9a.B_ModifyAll=Modify All
SAV_Donut9a.B_Reset=Reset
SAV_Donut9a.B_Save=Save
@ -1103,6 +1105,7 @@ SAV_Donut9a.L_Flavor0=Flavor 1:
SAV_Donut9a.L_Flavor1=Flavor 2:
SAV_Donut9a.L_Flavor2=Flavor 3:
SAV_Donut9a.L_LevelBoost=Level Boost:
SAV_Donut9a.L_Milliseconds=Milliseconds:
SAV_Donut9a.L_Stars=Stars:
SAV_Encounters.B_Add=Add
SAV_Encounters.B_CriteriaFromTabs=From Editor

View File

@ -46,7 +46,7 @@ private void InitializeComponent()
PB_Donut = new System.Windows.Forms.PictureBox();
flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
TB_Unknown = new System.Windows.Forms.TextBox();
TB_Milliseconds = new System.Windows.Forms.TextBox();
NUD_Stars = new System.Windows.Forms.NumericUpDown();
L_Donut = new System.Windows.Forms.Label();
NUD_LevelBoost = new System.Windows.Forms.NumericUpDown();
@ -62,7 +62,7 @@ private void InitializeComponent()
NUD_Calories = new System.Windows.Forms.NumericUpDown();
CB_Donut = new System.Windows.Forms.ComboBox();
CAL_Date = new System.Windows.Forms.DateTimePicker();
L_Unknown = new System.Windows.Forms.Label();
L_Milliseconds = new System.Windows.Forms.Label();
tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)PB_Berry0).BeginInit();
((System.ComponentModel.ISupportInitialize)PB_Berry1).BeginInit();
@ -473,7 +473,7 @@ private void InitializeComponent()
tableLayoutPanel2.ColumnCount = 2;
tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
tableLayoutPanel2.Controls.Add(TB_Unknown, 1, 8);
tableLayoutPanel2.Controls.Add(TB_Milliseconds, 1, 8);
tableLayoutPanel2.Controls.Add(NUD_Stars, 1, 0);
tableLayoutPanel2.Controls.Add(L_Donut, 0, 3);
tableLayoutPanel2.Controls.Add(NUD_LevelBoost, 1, 2);
@ -489,7 +489,7 @@ private void InitializeComponent()
tableLayoutPanel2.Controls.Add(NUD_Calories, 1, 1);
tableLayoutPanel2.Controls.Add(CB_Donut, 1, 3);
tableLayoutPanel2.Controls.Add(CAL_Date, 1, 7);
tableLayoutPanel2.Controls.Add(L_Unknown, 0, 8);
tableLayoutPanel2.Controls.Add(L_Milliseconds, 0, 8);
tableLayoutPanel2.Location = new System.Drawing.Point(296, 0);
tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
tableLayoutPanel2.Name = "tableLayoutPanel2";
@ -507,13 +507,13 @@ private void InitializeComponent()
tableLayoutPanel2.Size = new System.Drawing.Size(348, 220);
tableLayoutPanel2.TabIndex = 2;
//
// TB_Unknown
// TB_Milliseconds
//
TB_Unknown.Location = new System.Drawing.Point(106, 194);
TB_Unknown.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
TB_Unknown.Name = "TB_Unknown";
TB_Unknown.Size = new System.Drawing.Size(163, 23);
TB_Unknown.TabIndex = 60;
TB_Milliseconds.Location = new System.Drawing.Point(106, 194);
TB_Milliseconds.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
TB_Milliseconds.Name = "TB_Milliseconds";
TB_Milliseconds.Size = new System.Drawing.Size(163, 23);
TB_Milliseconds.TabIndex = 60;
//
// NUD_Stars
//
@ -675,16 +675,16 @@ private void InitializeComponent()
CAL_Date.TabIndex = 58;
CAL_Date.Value = new System.DateTime(2000, 1, 1, 0, 0, 0, 0);
//
// L_Unknown
// L_Milliseconds
//
L_Unknown.Anchor = System.Windows.Forms.AnchorStyles.Right;
L_Unknown.Location = new System.Drawing.Point(2, 194);
L_Unknown.Margin = new System.Windows.Forms.Padding(0);
L_Unknown.Name = "L_Unknown";
L_Unknown.Size = new System.Drawing.Size(104, 24);
L_Unknown.TabIndex = 61;
L_Unknown.Text = "Unknown:";
L_Unknown.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
L_Milliseconds.Anchor = System.Windows.Forms.AnchorStyles.Right;
L_Milliseconds.Location = new System.Drawing.Point(2, 194);
L_Milliseconds.Margin = new System.Windows.Forms.Padding(0);
L_Milliseconds.Name = "L_Milliseconds";
L_Milliseconds.Size = new System.Drawing.Size(104, 24);
L_Milliseconds.TabIndex = 61;
L_Milliseconds.Text = "Milliseconds:";
L_Milliseconds.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// DonutEditor9a
//
@ -747,7 +747,7 @@ private void InitializeComponent()
private System.Windows.Forms.PictureBox PB_Donut;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.TextBox TB_Unknown;
private System.Windows.Forms.TextBox TB_Milliseconds;
private System.Windows.Forms.NumericUpDown NUD_Stars;
private System.Windows.Forms.Label L_Donut;
private System.Windows.Forms.NumericUpDown NUD_LevelBoost;
@ -763,6 +763,6 @@ private void InitializeComponent()
private System.Windows.Forms.NumericUpDown NUD_Calories;
private System.Windows.Forms.ComboBox CB_Donut;
private System.Windows.Forms.DateTimePicker CAL_Date;
private System.Windows.Forms.Label L_Unknown;
private System.Windows.Forms.Label L_Milliseconds;
}
}

View File

@ -12,6 +12,10 @@ public sealed partial class DonutEditor9a : UserControl
private Donut9a _donut;
public event EventHandler? ValueChanged;
private bool Loading;
private static readonly DateTime Epoch = new(1900, 1, 1);
public DonutEditor9a()
{
InitializeComponent();
@ -57,7 +61,9 @@ public void InitializeLists(ReadOnlySpan<string> flavors, ReadOnlySpan<string> i
// Not really necessary to indicate value changes (name wouldn't be different), but for consistency...
CAL_Date.ValueChanged += OnValueChanged;
TB_Unknown.TextChanged += OnValueChanged;
CAL_Date.ValueChanged += ChangeDateTime;
TB_Milliseconds.TextChanged += OnValueChanged;
TB_Milliseconds.TextChanged += ChangeMilliseconds;
}
private static void SetDataSource<T>(ComboBox cb, List<T> list)
@ -116,10 +122,9 @@ private static List<ComboText> GetFlavorText(ReadOnlySpan<string> localized, str
return result;
}
private static readonly DateTime Epoch = new(1900, 1, 1);
public void LoadDonut(Donut9a donut)
{
Loading = true;
_donut = donut;
LoadClamp(NUD_Stars, donut.Stars);
@ -156,8 +161,9 @@ public void LoadDonut(Donut9a donut)
CAL_Date.Value = Epoch;
}
TB_Unknown.Text = donut.Unknown.ToString();
TB_Milliseconds.Text = donut.MillisecondsSince1900.ToString();
Loading = false;
return;
static void LoadClamp(NumericUpDown nud, decimal value) => nud.Value = Math.Clamp(value, nud.Minimum, nud.Maximum);
@ -206,7 +212,7 @@ public void SaveDonut()
donut.ClearDateTime();
}
}
donut.Unknown = ulong.TryParse(TB_Unknown.Text, out var unk) ? unk : 0;
donut.MillisecondsSince1900 = ulong.TryParse(TB_Milliseconds.Text, out var unk) ? unk : 0;
}
private static void LoadDonutFlavorHash(ComboBox cb, ulong flavorHash)
@ -246,6 +252,80 @@ public void Reset()
LoadDonut(_donut);
}
private void ChangeMilliseconds(object? sender, EventArgs e)
{
if (Loading)
return;
if (!ulong.TryParse(TB_Milliseconds.Text, out var ms))
return;
try
{
var ticks = Epoch.AddMilliseconds(ms);
// If date is same, don't update the ticks.
var date = CAL_Date.Value;
if (IsDateEquivalent(date, ticks))
return;
Loading = true;
CAL_Date.Value = ticks;
Loading = false;
}
catch
{
// Why are you putting ugly values??
// Reset.
Loading = true;
CAL_Date.Value = DateTime.Now;
TB_Milliseconds.Text = ((ulong)(CAL_Date.Value - Epoch).TotalMilliseconds).ToString();
Loading = false;
}
}
private void ChangeDateTime(object? sender, EventArgs e)
{
if (Loading)
return;
if (!ulong.TryParse(TB_Milliseconds.Text, out var ms))
return;
try
{
var ticks = Epoch.AddMilliseconds(ms);
// If date is same, don't update the ticks.
var date = CAL_Date.Value;
if (IsDateEquivalent(date, ticks))
return;
var delta = ((ulong)(date - Epoch).TotalMilliseconds);
// retain existing ticks _xxx component, since datetime picker does not configure millis
var exist = ms % 1000;
delta -= delta % 1000;
delta += exist;
Loading = true;
TB_Milliseconds.Text = delta.ToString();
Loading = false;
}
catch
{
// Why are you putting ugly values??
// Reset.
Loading = true;
CAL_Date.Value = DateTime.Now;
TB_Milliseconds.Text = ((ulong)(CAL_Date.Value - Epoch).TotalMilliseconds).ToString();
Loading = false;
}
}
private static bool IsDateEquivalent(DateTime a, DateTime b) =>
a.Year == b.Year && a.Month == b.Month && a.Day == b.Day &&
a.Hour == b.Hour && a.Minute == b.Minute && a.Second == b.Second;
// bubble up to the parent control, if subscribed.
private void OnValueChanged(object? sender, EventArgs e) => ValueChanged?.Invoke(this, EventArgs.Empty);

View File

@ -34,10 +34,6 @@ public SAV_Donut9a(SAV9ZA sav)
lastIndex = 0;
GetEntry(0);
// Not implemented.
mnuRandomizeMax.Visible = false;
mnuShinyAssortment.Visible = false;
AddDrop(this, LB_Donut, donutEditor);
}
@ -60,6 +56,12 @@ private void LoadDonutNames()
LB_Donut.Items.AddRange(names);
}
private void ReloadDonutNames()
{
for (int i = 0; i < DonutPocket9a.MaxCount; i++)
LB_Donut.Items[i] = GetDonutName(i);
}
private string GetDonutName(int i)
{
var donut = Donuts.GetDonut(i);
@ -132,34 +134,26 @@ private void B_Modify_Click(object sender, EventArgs e)
private void RandomizeAll(object sender, EventArgs e)
{
for (int i = 0; i < DonutPocket9a.MaxCount; i++)
{
// todo
}
Donuts.SetAllRandomLv3();
ReloadDonutNames();
GetEntry(lastIndex);
System.Media.SystemSounds.Asterisk.Play();
}
private void CloneCurrent(object sender, EventArgs e)
{
SetEntry(lastIndex);
var current = Donuts.GetDonut(lastIndex);
for (int i = 0; i < DonutPocket9a.MaxCount; i++)
{
if (i == lastIndex)
continue;
var target = Donuts.GetDonut(i);
current.CopyTo(target);
LB_Donut.Items[i] = GetDonutName(target, i); // todo: test this to see if it is any bit slow
}
Donuts.CloneAllFromIndex(lastIndex);
ReloadDonutNames();
System.Media.SystemSounds.Asterisk.Play();
}
private void ShinyAssortment(object sender, EventArgs e)
{
for (int i = 0; i < DonutPocket9a.MaxCount; i++)
{
var donut = Donuts.GetDonut(i);
// todo: generate a shiny donut
LB_Donut.Items[i] = GetDonutName(donut, i); // todo: test this to see if it is any bit slow
}
Donuts.SetAllAsShinyTemplate();
ReloadDonutNames();
GetEntry(lastIndex);
System.Media.SystemSounds.Asterisk.Play();
}
private void B_Reset_Click(object sender, EventArgs e) => donutEditor.Reset();