using System;
namespace PKHeX.Core;
///
/// Value result object of parsing a stat string.
///
public record struct StatParseResult()
{
private const uint MaxStatCount = 6; // Number of stats in the game
public const sbyte NoStatAmp = -1;
///
/// Count of parsed stats.
///
public byte CountParsed { get; private set; } = 0; // could potentially make this a computed value (popcnt), but it's not worth it
///
/// Bitflag indexes of parsed stats, indexed in visual order.
///
public byte IndexesParsed { get; private set; } = 0;
///
/// Stat index of increased stat, indexed in visual order.
///
public sbyte Plus { get; set; } = NoStatAmp;
///
/// Stat index of decreased stat, indexed in visual order.
///
public sbyte Minus { get; set; } = NoStatAmp;
///
/// Indicates if the parsing was clean (no un-parsed text).
///
public bool IsParseClean { get; private set; } = true;
///
/// Indicates if all stat indexes available were parsed.
///
public bool IsParsedAllStats { get; private set; }
///
/// Marks the stat index as parsed, and updates the count of parsed stats.
///
/// Visual index of the stat to mark as parsed.
/// True if the stat had not been parsed before, false if it was already parsed.
public bool MarkParsed(int statIndex)
{
// Check if the stat index is valid (0-5)
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)statIndex, MaxStatCount);
if (WasParsed(statIndex))
return false;
// Mark the stat index as parsed
IndexesParsed |= (byte)(1 << statIndex);
++CountParsed;
return true;
}
///
/// Checks if the stat index was parsed.
///
/// Visual index of the stat to check.
/// True if the stat was parsed, false otherwise.
public readonly bool WasParsed(int statIndex)
{
// Check if the stat index is valid (0-5)
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)statIndex, MaxStatCount);
return (IndexesParsed & (1 << statIndex)) != 0;
}
///
/// Marks the parsing as finished, and updates the internal state to indicate if all stats were parsed.
///
///
/// This is used when not all stats are required to be parsed.
///
///
public void FinishParse(int expect)
{
if (CountParsed == 0 && !HasAmps)
MarkDirty();
IsParsedAllStats = CountParsed == expect || IsParseClean;
}
///
/// Marks the parsing as finished, and updates the internal state to indicate if all stats were parsed.
///
///
/// This is used when a specific number of stats is expected.
///
///
public void FinishParseOnly(int expect) => IsParsedAllStats = CountParsed == expect;
///
/// Marks the parsing as dirty, indicating that the string was not a clean input string (user modified or the syntax doesn't match the spec).
///
public void MarkDirty() => IsParseClean = false;
///
/// Indicates if any stat has any amplified (+/-) requested, indicative of nature.
///
public readonly bool HasAmps => Plus != NoStatAmp || Minus != NoStatAmp;
///
/// Reorders the speed stat to be in the middle of the stats.
///
///
/// Speed is visually represented as the last stat in the list, but it is actually the 3rd stat stored.
///
public void TreatAmpsAsSpeedNotLast()
{
Plus = GetSpeedMiddleIndex(Plus);
Minus = GetSpeedMiddleIndex(Minus);
}
///
/// Adjusts stat indexes from visual to stored, and ignoring HP's index.
///
/// Visual index of the stat to get the adjusted value for.
/// Stored index of the stat.
private static sbyte GetSpeedMiddleIndex(sbyte amp) => amp switch
{
// 0 => NoStatAmp -- handle via default case
1 => 0, // Atk
2 => 1, // Def
3 => 3, // SpA
4 => 4, // SpD
5 => 2, // Spe
_ => NoStatAmp,
};
}