PkmnLib.NET/PkmnLib.Static/StatisticSet.cs

374 lines
11 KiB
C#

using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace PkmnLib.Static;
/// <summary>
/// A set of statistics that cannot be changed.
/// </summary>
/// <typeparam name="T">The size of the integer to be used</typeparam>
public record ImmutableStatisticSet<T>
where T : struct
{
/// <summary>
/// The health points stat value.
/// </summary>
public T Hp { get; protected set; }
/// <summary>
/// The physical attack stat value.
/// </summary>
public T Attack { get; protected set; }
/// <summary>
/// The physical defense stat value.
/// </summary>
public T Defense { get; protected set; }
/// <summary>
/// The special attack stat value.
/// </summary>
public T SpecialAttack { get; protected set; }
/// <summary>
/// The special defense stat value.
/// </summary>
public T SpecialDefense { get; protected set; }
/// <summary>
/// The speed stat value.
/// </summary>
public T Speed { get; protected set; }
/// <inheritdoc cref="ImmutableStatisticSet{T}"/>
public ImmutableStatisticSet(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed)
{
Hp = hp;
Attack = attack;
Defense = defense;
SpecialAttack = specialAttack;
SpecialDefense = specialDefense;
Speed = speed;
}
public ImmutableStatisticSet(ImmutableStatisticSet<T> set)
{
Hp = set.Hp;
Attack = set.Attack;
Defense = set.Defense;
SpecialAttack = set.SpecialAttack;
SpecialDefense = set.SpecialDefense;
Speed = set.Speed;
}
/// <summary>
/// Gets a statistic from the set.
/// </summary>
public T GetStatistic(Statistic stat)
{
return stat switch
{
Statistic.Hp => Hp,
Statistic.Attack => Attack,
Statistic.Defense => Defense,
Statistic.SpecialAttack => SpecialAttack,
Statistic.SpecialDefense => SpecialDefense,
Statistic.Speed => Speed,
_ => throw new ArgumentException("Invalid statistic."),
};
}
}
/// <summary>
/// A set of statistics that can be changed.
/// </summary>
/// <typeparam name="T"></typeparam>
public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<T>
where T : struct
{
/// <inheritdoc cref="StatisticSet{T}"/>
public StatisticSet() : base(default, default, default, default, default, default)
{
}
/// <inheritdoc cref="StatisticSet{T}"/>
public StatisticSet(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed) : base(hp, attack,
defense, specialAttack, specialDefense, speed)
{
}
public StatisticSet(StatisticSet<T> set) : base(set)
{
}
/// <summary>
/// Helper function to add two numerics together.
/// </summary>
protected T Add(T a, T b) => (T)Convert.ChangeType(Convert.ToInt32(a) + Convert.ToInt32(b), typeof(T));
/// <summary>
/// Helper function to subtract two numerics.
/// </summary>
protected T Subtract(T a, T b) => (T)Convert.ChangeType(Convert.ToInt32(a) - Convert.ToInt32(b), typeof(T));
/// <summary>
/// Modifies a statistic in the set.
/// </summary>
public virtual void SetStatistic(Statistic stat, T value)
{
switch (stat)
{
case Statistic.Hp:
Hp = value;
break;
case Statistic.Attack:
Attack = value;
break;
case Statistic.Defense:
Defense = value;
break;
case Statistic.SpecialAttack:
SpecialAttack = value;
break;
case Statistic.SpecialDefense:
SpecialDefense = value;
break;
case Statistic.Speed:
Speed = value;
break;
default:
throw new ArgumentException("Invalid statistic.");
}
}
/// <summary>
/// Increases a statistic in the set by a value.
/// </summary>
public virtual bool IncreaseStatistic(Statistic stat, T value)
{
switch (stat)
{
case Statistic.Hp:
Hp = Add(Hp, value);
break;
case Statistic.Attack:
Attack = Add(Attack, value);
break;
case Statistic.Defense:
Defense = Add(Defense, value);
break;
case Statistic.SpecialAttack:
SpecialAttack = Add(SpecialAttack, value);
break;
case Statistic.SpecialDefense:
SpecialDefense = Add(SpecialDefense, value);
break;
case Statistic.Speed:
Speed = Add(Speed, value);
break;
default:
throw new ArgumentException("Invalid statistic.");
}
return true;
}
/// <summary>
/// Decreases a statistic in the set by a value.
/// </summary>
public virtual bool DecreaseStatistic(Statistic stat, T value)
{
switch (stat)
{
case Statistic.Hp:
Hp = Subtract(Hp, value);
break;
case Statistic.Attack:
Attack = Subtract(Attack, value);
break;
case Statistic.Defense:
Defense = Subtract(Defense, value);
break;
case Statistic.SpecialAttack:
SpecialAttack = Subtract(SpecialAttack, value);
break;
case Statistic.SpecialDefense:
SpecialDefense = Subtract(SpecialDefense, value);
break;
case Statistic.Speed:
Speed = Subtract(Speed, value);
break;
default:
throw new ArgumentException("Invalid statistic.");
}
return true;
}
/// <inheritdoc />
public IEnumerator<T> GetEnumerator()
{
yield return Hp;
yield return Attack;
yield return Defense;
yield return SpecialAttack;
yield return SpecialDefense;
yield return Speed;
}
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
/// <summary>
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value.
/// </summary>
public abstract record ClampedStatisticSet<T> : StatisticSet<T>
where T : struct, IComparable<T>
{
/// <inheritdoc />
[SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")]
protected ClampedStatisticSet(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed) : base(hp,
attack, defense, specialAttack, specialDefense, speed)
{
if (Min.CompareTo(Max) > 0)
throw new ArgumentException("Minimum value must be less than or equal to maximum value.");
Hp = Clamp(Hp, Min, Max);
Attack = Clamp(Attack, Min, Max);
Defense = Clamp(Defense, Min, Max);
SpecialAttack = Clamp(SpecialAttack, Min, Max);
SpecialDefense = Clamp(SpecialDefense, Min, Max);
Speed = Clamp(Speed, Min, Max);
}
protected ClampedStatisticSet(ClampedStatisticSet<T> set) : base(set)
{
}
private static T Clamp(T value, T min, T max)
{
if (value.CompareTo(min) < 0)
return min;
if (value.CompareTo(max) > 0)
return max;
return value;
}
/// <summary>
/// The minimum value for the statistics.
/// </summary>
protected abstract T Min { get; }
/// <summary>
/// The maximum value for the statistics.
/// </summary>
protected abstract T Max { get; }
/// <inheritdoc />
public override void SetStatistic(Statistic stat, T value) => base.SetStatistic(stat, Clamp(value, Min, Max));
/// <inheritdoc />
public override bool IncreaseStatistic(Statistic stat, T value)
{
var current = GetStatistic(stat);
var newValue = Add(current, value);
if (newValue.CompareTo(Max) > 0)
value = Subtract(Max, current);
if (value.CompareTo(default) == 0)
return false;
return base.IncreaseStatistic(stat, value);
}
/// <inheritdoc />
public override bool DecreaseStatistic(Statistic stat, T value)
{
var current = GetStatistic(stat);
var newValue = Subtract(current, value);
if (newValue.CompareTo(Min) < 0)
value = Subtract(current, Min);
if (value.CompareTo(default) == 0)
return false;
return base.DecreaseStatistic(stat, value);
}
}
/// <summary>
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value of -6 and 6.
/// </summary>
public record StatBoostStatisticSet : ClampedStatisticSet<sbyte>
{
/// <inheritdoc />
protected override sbyte Min => -6;
/// <inheritdoc />
protected override sbyte Max => 6;
/// <inheritdoc cref="StatBoostStatisticSet"/>
public StatBoostStatisticSet() : base(0, 0, 0, 0, 0, 0)
{
}
/// <inheritdoc cref="StatBoostStatisticSet"/>
public StatBoostStatisticSet(sbyte hp, sbyte attack, sbyte defense, sbyte specialAttack, sbyte specialDefense,
sbyte speed) : base(hp, attack, defense, specialAttack, specialDefense, speed)
{
}
}
/// <summary>
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value of 0 and 31.
/// </summary>
public record IndividualValueStatisticSet : ClampedStatisticSet<byte>
{
/// <inheritdoc />
protected override byte Min => 0;
/// <inheritdoc />
protected override byte Max => 31;
/// <inheritdoc cref="IndividualValueStatisticSet"/>
public IndividualValueStatisticSet() : base(0, 0, 0, 0, 0, 0)
{
}
/// <inheritdoc cref="IndividualValueStatisticSet"/>
public IndividualValueStatisticSet(byte hp, byte attack, byte defense, byte specialAttack, byte specialDefense,
byte speed) : base(hp, attack, defense, specialAttack, specialDefense, speed)
{
}
public IndividualValueStatisticSet(IndividualValueStatisticSet ivs) : base(ivs)
{
}
}
/// <summary>
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value of 0 and 252.
/// </summary>
public record EffortValueStatisticSet : ClampedStatisticSet<byte>
{
/// <inheritdoc />
protected override byte Min => 0;
/// <inheritdoc />
protected override byte Max => 252;
/// <inheritdoc cref="EffortValueStatisticSet"/>
public EffortValueStatisticSet() : base(0, 0, 0, 0, 0, 0)
{
}
/// <inheritdoc cref="EffortValueStatisticSet"/>
public EffortValueStatisticSet(byte hp, byte attack, byte defense, byte specialAttack, byte specialDefense,
byte speed) : base(hp, attack, defense, specialAttack, specialDefense, speed)
{
}
public EffortValueStatisticSet(EffortValueStatisticSet evs) : base(evs)
{
}
}