using System.Collections.Immutable;
using PkmnLib.Static.Utils;
using PkmnLib.Static.Utils.Errors;
namespace PkmnLib.Static.Species;
///
/// A form is a variant of a specific species. A species always has at least one form, but can have
/// many more.
///
public interface IForm : INamedValue
{
///
/// The height of the form in meters.
///
float Height { get; }
///
/// The weight of the form in kilograms.
///
float Weight { get; }
///
/// The base amount of experience that is gained when beating a Pokémon with this form.
///
uint BaseExperience { get; }
///
/// The normal types a Pokémon with this form has.
///
IReadOnlyList Types { get; }
///
/// The inherent values of a form of species that are used for the stats of a Pokémon.
///
ImmutableStatisticSet BaseStats { get; }
///
/// The possible abilities a Pokémon with this form can have.
///
IReadOnlyList Abilities { get; }
///
/// The possible hidden abilities a Pokémon with this form can have.
///
IReadOnlyList HiddenAbilities { get; }
///
/// The moves a Pokémon with this form can learn.
///
ILearnableMoves Moves { get; }
///
/// Arbitrary flags can be set on a form for scripting use.
///
ImmutableHashSet Flags { get; }
///
/// Get a type of the form at a certain index.
///
TypeIdentifier GetType(int index);
///
/// Gets a single base stat value.
///
ushort GetBaseStat(Statistic stat);
///
/// Find the index of an ability that can be on this form.
///
AbilityIndex? FindAbilityIndex(IAbility ability);
///
/// Gets an ability from the form.
///
StringKey GetAbility(AbilityIndex index);
///
/// Gets a random ability from the form.
///
StringKey GetRandomAbility(IRandom rand);
///
/// Gets a random hidden ability from the form.
///
StringKey GetRandomHiddenAbility(IRandom rand);
///
/// Check if the form has a specific flag set.
///
bool HasFlag(string key);
}
///
public class FormImpl : IForm
{
///
public FormImpl(StringKey name, float height, float weight, uint baseExperience,
IEnumerable types, ImmutableStatisticSet baseStats, IEnumerable abilities,
IEnumerable hiddenAbilities, ILearnableMoves moves, ImmutableHashSet flags)
{
Name = name;
Height = height;
Weight = weight;
BaseExperience = baseExperience;
Types = [..types];
BaseStats = baseStats;
Abilities = [..abilities];
HiddenAbilities = [..hiddenAbilities];
Moves = moves;
Flags = flags;
if (Types.Count == 0)
throw new ArgumentException("A form must have at least one type.");
if (Abilities.Count == 0)
throw new ArgumentException("A form must have at least one ability.");
}
///
public StringKey Name { get; }
///
public float Height { get; }
///
public float Weight { get; }
///
public uint BaseExperience { get; }
///
public IReadOnlyList Types { get; }
///
public ImmutableStatisticSet BaseStats { get; }
///
public IReadOnlyList Abilities { get; }
///
public IReadOnlyList HiddenAbilities { get; }
///
public ILearnableMoves Moves { get; }
///
public ImmutableHashSet Flags { get; }
///
public TypeIdentifier GetType(int index)
{
if (index < 0 || index >= Types.Count)
throw new OutOfRangeException("Type", index, Types.Count);
return Types[index];
}
///
public ushort GetBaseStat(Statistic stat) => BaseStats.GetStatistic(stat);
///
public AbilityIndex? FindAbilityIndex(IAbility ability)
{
for (var i = 0; i < Abilities.Count && i < 255; i++)
{
if (Abilities[i] == ability.Name)
return new AbilityIndex
{
IsHidden = false,
Index = (byte)i
};
}
for (var i = 0; i < HiddenAbilities.Count && i < 255; i++)
{
if (HiddenAbilities[i] == ability.Name)
return new AbilityIndex
{
IsHidden = true,
Index = (byte)i
};
}
return null;
}
///
public StringKey GetAbility(AbilityIndex index)
{
var array = index.IsHidden ? HiddenAbilities : Abilities;
if (index.Index >= array.Count)
throw new OutOfRangeException("Ability", index.Index, array.Count);
return array[index.Index];
}
///
public StringKey GetRandomAbility(IRandom rand)
{
return Abilities[rand.GetInt(Abilities.Count)];
}
///
public StringKey GetRandomHiddenAbility(IRandom rand)
{
return HiddenAbilities[rand.GetInt(HiddenAbilities.Count)];
}
///
public bool HasFlag(string key)
{
return Flags.Contains(key);
}
}