using System.Collections;
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Utils;
namespace PkmnLib.Static;
///
/// A set of statistics that cannot be changed.
///
/// The size of the integer to be used
public record ImmutableStatisticSet where T : struct
{
///
/// The health points stat value.
///
public T Hp { get; protected set; }
///
/// The physical attack stat value.
///
public T Attack { get; protected set; }
///
/// The physical defense stat value.
///
public T Defense { get; protected set; }
///
/// The special attack stat value.
///
public T SpecialAttack { get; protected set; }
///
/// The special defense stat value.
///
public T SpecialDefense { get; protected set; }
///
/// The speed stat value.
///
public T Speed { get; protected set; }
///
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 set)
{
Hp = set.Hp;
Attack = set.Attack;
Defense = set.Defense;
SpecialAttack = set.SpecialAttack;
SpecialDefense = set.SpecialDefense;
Speed = set.Speed;
}
///
/// Gets a statistic from the set.
///
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."),
};
}
}
///
/// A set of statistics that can be changed.
///
///
public record StatisticSet : ImmutableStatisticSet, IEnumerable, IDeepCloneable where T : struct
{
///
public StatisticSet() : base(default, default, default, default, default, default)
{
}
///
public StatisticSet(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed) : base(hp, attack,
defense, specialAttack, specialDefense, speed)
{
}
public StatisticSet(StatisticSet set) : base(set)
{
}
///
/// Helper function to add two numerics together.
///
protected T Add(T a, T b) => (T)Convert.ChangeType(Convert.ToInt32(a) + Convert.ToInt32(b), typeof(T));
///
/// Helper function to subtract two numerics.
///
protected T Subtract(T a, T b) => (T)Convert.ChangeType(Convert.ToInt32(a) - Convert.ToInt32(b), typeof(T));
///
/// Modifies a statistic in the set.
///
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.");
}
}
///
/// Increases a statistic in the set by a value.
///
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:
SetUnknownStat(stat, Add(GetUnknownStat(stat), value));
break;
}
return true;
}
protected virtual T GetUnknownStat(Statistic stat) => throw new ArgumentException($"Invalid statistic {stat}");
protected virtual void SetUnknownStat(Statistic stat, T value)
{
throw new ArgumentException($"Invalid statistic {stat}");
}
///
/// Decreases a statistic in the set by a value.
///
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:
SetUnknownStat(stat, Subtract(GetUnknownStat(stat), value));
break;
}
return true;
}
///
public virtual IEnumerator GetEnumerator()
{
yield return Hp;
yield return Attack;
yield return Defense;
yield return SpecialAttack;
yield return SpecialDefense;
yield return Speed;
}
///
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
///
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value.
///
public abstract record ClampedStatisticSet : StatisticSet where T : struct, IComparable
{
///
[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 set) : base(set)
{
}
protected 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;
}
///
/// The minimum value for the statistics.
///
protected abstract T Min { get; }
///
/// The maximum value for the statistics.
///
protected abstract T Max { get; }
///
public override void SetStatistic(Statistic stat, T value) => base.SetStatistic(stat, Clamp(value, Min, Max));
///
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);
}
///
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);
}
}
///
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value of -6 and 6.
///
public record StatBoostStatisticSet : ClampedStatisticSet
{
///
protected override sbyte Min => -6;
///
protected override sbyte Max => 6;
private sbyte _evasion;
public sbyte Evasion
{
get => _evasion;
set => _evasion = Clamp(value, Min, Max);
}
private sbyte _accuracy;
public sbyte Accuracy
{
get => _accuracy;
set => _accuracy = Clamp(value, Min, Max);
}
///
public StatBoostStatisticSet() : base(0, 0, 0, 0, 0, 0)
{
}
///
public StatBoostStatisticSet(sbyte hp, sbyte attack, sbyte defense, sbyte specialAttack, sbyte specialDefense,
sbyte speed) : base(hp, attack, defense, specialAttack, specialDefense, speed)
{
}
///
protected override sbyte GetUnknownStat(Statistic stat)
{
return stat switch
{
Statistic.Evasion => Evasion,
Statistic.Accuracy => Accuracy,
_ => throw new ArgumentException($"Invalid statistic {stat}"),
};
}
///
///
protected override void SetUnknownStat(Statistic stat, sbyte value)
{
switch (stat)
{
case Statistic.Evasion:
Evasion = value;
break;
case Statistic.Accuracy:
Accuracy = value;
break;
default:
throw new ArgumentException($"Invalid statistic {stat}");
}
}
///
public override IEnumerator GetEnumerator()
{
yield return Hp;
yield return Attack;
yield return Defense;
yield return SpecialAttack;
yield return SpecialDefense;
yield return Speed;
yield return Evasion;
yield return Accuracy;
}
}
///
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value of 0 and 31.
///
public record IndividualValueStatisticSet : ClampedStatisticSet
{
///
protected override byte Min => 0;
///
protected override byte Max => 31;
///
public IndividualValueStatisticSet() : base(0, 0, 0, 0, 0, 0)
{
}
///
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)
{
}
}
///
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value of 0 and 252.
///
public record EffortValueStatisticSet : ClampedStatisticSet
{
///
protected override byte Min => 0;
///
protected override byte Max => 252;
///
public EffortValueStatisticSet() : base(0, 0, 0, 0, 0, 0)
{
}
///
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)
{
}
}