Further work on static side

This commit is contained in:
2024-07-20 16:12:39 +02:00
parent 3845f91601
commit 1b501dee7e
29 changed files with 670 additions and 155 deletions

View File

@@ -0,0 +1,34 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Species;
using PkmnLib.Static.Utils;
namespace PkmnLib.Static.Libraries;
/// <summary>
/// The library for all abilities in the game.
/// </summary>
public interface IReadOnlyAbilityLibrary
{
/// <summary>
/// Tries to get an ability from the library. Returns false if the ability is not found.
/// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out IAbility value);
/// <summary>
/// Gets a random ability from the library.
/// </summary>
IAbility GetRandom(IRandom random);
/// <summary>
/// The amount of abilities in the library.
/// </summary>
int Count { get; }
/// <summary>
/// Whether the library is empty.
/// </summary>
bool IsEmpty { get; }
}
/// <inheritdoc cref="IReadOnlyAbilityLibrary"/>
public class AbilityLibrary : DataLibrary<IAbility>, IReadOnlyAbilityLibrary;

View File

@@ -0,0 +1,52 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Utils;
namespace PkmnLib.Static.Libraries;
/// <summary>
/// A basic library for data types. Stores data both by name and by index.
/// </summary>
public abstract class DataLibrary<T>
where T : INamedValue
{
private readonly Dictionary<StringKey, T> _data = new();
private readonly List<T> _values = [];
/// <summary>
/// Adds a value to the library.
/// </summary>
public void Add(T value)
{
_data.Add(value.Name, value);
_values.Add(value);
}
/// <summary>
/// Removes a value from the library.
/// </summary>
public void Remove(T value)
{
_data.Remove(value.Name);
_values.Remove(value);
}
/// <summary>
/// Try to get a value from the library. Returns false if the value is not found.
/// </summary>
public bool TryGet(StringKey key, [MaybeNullWhen(false)] out T value) => _data.TryGetValue(key, out value);
/// <summary>
/// Get a random value from the library.
/// </summary>
public T GetRandom(IRandom random) => _values[random.GetInt(_values.Count)];
/// <summary>
/// The number of values in the library.
/// </summary>
public int Count => _values.Count;
/// <summary>
/// Whether the library is empty.
/// </summary>
public bool IsEmpty => _values.Count == 0;
}

View File

@@ -0,0 +1,30 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Utils;
namespace PkmnLib.Static.Libraries;
/// <summary>
/// The library for all growth rates in the game.
/// </summary>
public interface IReadOnlyGrowthRateLibrary
{
/// <summary>
/// Tries to get a growth rate from the library. Returns false if the growth rate is not found.
/// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out IGrowthRate value);
/// <summary>
/// Gets a random growth rate from the library.
/// </summary>
IGrowthRate GetRandom(IRandom random);
/// <summary>
/// Gets the amount of growth rates in the library.
/// </summary>
int Count { get; }
/// <summary>
/// Whether the library is empty.
/// </summary>
bool IsEmpty { get; }
}
/// <inheritdoc cref="IReadOnlyGrowthRateLibrary"/>
public class GrowthRateLibrary : DataLibrary<IGrowthRate>, IReadOnlyGrowthRateLibrary;

View File

@@ -0,0 +1,33 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Utils;
namespace PkmnLib.Static.Libraries;
/// <summary>
/// The library for all items in the game.
/// </summary>
public interface IReadOnlyItemLibrary
{
/// <summary>
/// Tries to get an item from the library. Returns false if the item is not found.
/// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out IItem value);
/// <summary>
/// Gets a random item from the library.
/// </summary>
IItem GetRandom(IRandom random);
/// <summary>
/// The amount of items in the library.
/// </summary>
int Count { get; }
/// <summary>
/// Whether the library is empty.
/// </summary>
bool IsEmpty { get; }
}
/// <inheritdoc cref="IReadOnlyItemLibrary"/>
public class ItemLibrary : DataLibrary<IItem>, IReadOnlyItemLibrary;

View File

@@ -0,0 +1,18 @@
namespace PkmnLib.Static.Libraries;
/// <summary>
/// General settings for the library.
/// </summary>
public record LibrarySettings
{
/// <summary>
/// The maximum level a Pokémon can reach.
/// </summary>
public required LevelInt MaxLevel { get; init; }
/// <summary>
/// The chance of a Pokémon being shiny, as the denominator of a fraction, where the nominator
/// is 1. For example, if this is 1000, then the chance of a Pokémon being shiny is 1/1000.
/// </summary>
public required uint ShinyRate { get; init; }
}

View File

@@ -0,0 +1,31 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;
namespace PkmnLib.Static.Libraries;
/// <summary>
/// The library for all moves in the game.
/// </summary>
public interface IReadOnlyMoveLibrary
{
/// <summary>
/// Tries to get a move from the library. Returns false if the move is not found.
/// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out IMoveData value);
/// <summary>
/// Gets a random move from the library.
/// </summary>
IMoveData GetRandom(IRandom random);
/// <summary>
/// The amount of moves in the library.
/// </summary>
int Count { get; }
/// <summary>
/// Whether the library is empty.
/// </summary>
bool IsEmpty { get; }
}
/// <inheritdoc cref="IReadOnlyMoveLibrary"/>
public class MoveLibrary : DataLibrary<IMoveData>, IReadOnlyMoveLibrary;

View File

@@ -0,0 +1,33 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Utils;
namespace PkmnLib.Static.Libraries;
/// <summary>
/// The library for all natures in the game.
/// </summary>
public interface IReadOnlyNatureLibrary
{
/// <summary>
/// Tries to get a nature from the library. Returns false if the nature is not found.
/// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out INature value);
/// <summary>
/// Gets a random nature from the library.
/// </summary>
INature GetRandom(IRandom random);
/// <summary>
/// The amount of natures in the library.
/// </summary>
int Count { get; }
/// <summary>
/// Whether the library is empty.
/// </summary>
bool IsEmpty { get; }
}
/// <inheritdoc cref="IReadOnlyNatureLibrary"/>
public class NatureLibrary : DataLibrary<INature>, IReadOnlyNatureLibrary;

View File

@@ -0,0 +1,34 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Species;
using PkmnLib.Static.Utils;
namespace PkmnLib.Static.Libraries;
/// <summary>
/// The library for all species in the game.
/// </summary>
public interface IReadOnlySpeciesLibrary
{
/// <summary>
/// Tries to get a species from the library. Returns false if the species is not found.
/// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out ISpecies value);
/// <summary>
/// Gets a random species from the library.
/// </summary>
ISpecies GetRandom(IRandom random);
/// <summary>
/// The amount of species in the library.
/// </summary>
int Count { get; }
/// <summary>
/// Whether the library is empty.
/// </summary>
bool IsEmpty { get; }
}
/// <inheritdoc cref="IReadOnlySpeciesLibrary"/>
public class SpeciesLibrary : DataLibrary<ISpecies>, IReadOnlySpeciesLibrary;

View File

@@ -0,0 +1,83 @@
namespace PkmnLib.Static.Libraries;
/// <summary>
/// The storage for all different static libraries.
/// </summary>
public interface IStaticLibrary
{
/// <summary>
/// The miscellaneous settings for the library.
/// </summary>
LibrarySettings Settings { get; }
/// <summary>
/// All data for Pokémon species.
/// </summary>
IReadOnlySpeciesLibrary Species { get; }
/// <summary>
/// All data for Pokémon moves.
/// </summary>
IReadOnlyMoveLibrary Moves { get; }
/// <summary>
/// All data for Pokémon abilities.
/// </summary>
IReadOnlyAbilityLibrary Abilities { get; }
/// <summary>
/// All data for Pokémon types and their effectiveness.
/// </summary>
IReadOnlyTypeLibrary Types { get; }
/// <summary>
/// All data for Pokémon natures.
/// </summary>
IReadOnlyNatureLibrary Natures { get; }
/// <summary>
/// All data for Pokémon growth rates.
/// </summary>
IReadOnlyGrowthRateLibrary GrowthRates { get; }
/// <summary>
/// All data for Pokémon items.
/// </summary>
IReadOnlyItemLibrary Items { get; }
}
/// <inheritdoc />
public class StaticLibraryImpl : IStaticLibrary
{
/// <inheritdoc cref="StaticLibraryImpl" />
public StaticLibraryImpl(LibrarySettings settings, IReadOnlySpeciesLibrary species, IReadOnlyMoveLibrary moves, IReadOnlyAbilityLibrary abilities, IReadOnlyTypeLibrary types, IReadOnlyNatureLibrary natures, IReadOnlyGrowthRateLibrary growthRates, IReadOnlyItemLibrary items)
{
Settings = settings;
Species = species;
Moves = moves;
Abilities = abilities;
Types = types;
Natures = natures;
GrowthRates = growthRates;
Items = items;
}
/// <inheritdoc />
public LibrarySettings Settings { get; }
/// <inheritdoc />
public IReadOnlySpeciesLibrary Species { get; }
/// <inheritdoc />
public IReadOnlyMoveLibrary Moves { get; }
/// <inheritdoc />
public IReadOnlyAbilityLibrary Abilities { get; }
/// <inheritdoc />
public IReadOnlyTypeLibrary Types { get; }
/// <inheritdoc />
public IReadOnlyNatureLibrary Natures { get; }
/// <inheritdoc />
public IReadOnlyGrowthRateLibrary GrowthRates { get; }
/// <inheritdoc />
public IReadOnlyItemLibrary Items { get; }
}

View File

@@ -0,0 +1,99 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Utils;
namespace PkmnLib.Static.Libraries;
/// <summary>
/// All data related to types and their effectiveness.
/// </summary>
public interface IReadOnlyTypeLibrary
{
/// <summary>
/// Gets the type identifier for a type with a name.
/// </summary>
bool TryGetTypeIdentifier(StringKey key, out TypeIdentifier typeIdentifier);
/// <summary>
/// Gets the type name from the type identifier.
/// </summary>
bool TryGetTypeName(TypeIdentifier t, [NotNullWhen(true)] out StringKey? stringKey);
/// <summary>
/// Gets the effectiveness for a single attacking type against a single defending type.
/// </summary>
float GetSingleEffectiveness(TypeIdentifier attacking, TypeIdentifier defending);
/// <summary>
/// Gets the effectiveness for a single attacking type against an amount of defending types.
/// This is equivalent to running get_single_effectiveness on each defending type, and multiplying the results with each other.
/// </summary>
float GetEffectiveness(TypeIdentifier attacking, TypeIdentifier[] defending);
}
/// <inheritdoc />
public class TypeLibrary : IReadOnlyTypeLibrary
{
private readonly Dictionary<StringKey, TypeIdentifier> _types = new();
private readonly List<List<float>> _effectiveness = new();
/// <inheritdoc />
public bool TryGetTypeIdentifier(StringKey key, out TypeIdentifier type) => _types.TryGetValue(key, out type);
/// <inheritdoc />
public bool TryGetTypeName(TypeIdentifier t, [NotNullWhen(true)] out StringKey? stringKey)
{
foreach (var (key, value) in _types)
{
if (value == t)
{
stringKey = key;
return true;
}
}
stringKey = default;
return false;
}
/// <inheritdoc />
public float GetSingleEffectiveness(TypeIdentifier attacking, TypeIdentifier defending)
{
if (attacking.Value < 1 || attacking.Value > _effectiveness.Count)
throw new ArgumentOutOfRangeException(nameof(attacking));
if (defending.Value < 1 || defending.Value > _effectiveness.Count)
throw new ArgumentOutOfRangeException(nameof(defending));
return _effectiveness[attacking.Value - 1][defending.Value - 1];
}
/// <inheritdoc />
public float GetEffectiveness(TypeIdentifier attacking, TypeIdentifier[] defending) =>
defending.Aggregate<TypeIdentifier, float>(1,
(current, type) => current * GetSingleEffectiveness(attacking, type));
/// <summary>
/// Registers a new type in the library.
/// </summary>
public TypeIdentifier RegisterType(StringKey name)
{
var id = new TypeIdentifier((byte)( _types.Count + 1));
_types.Add(name, id);
_effectiveness.Add(new List<float>(_types.Count));
foreach (var list in _effectiveness)
{
list.Add(1);
}
return id;
}
/// <summary>
/// Sets the effectiveness for an attacking type against a defending type.
/// </summary>
public void SetEffectiveness(TypeIdentifier attacking, TypeIdentifier defending, float effectiveness)
{
if (attacking.Value < 1 || attacking.Value > _effectiveness.Count)
throw new ArgumentOutOfRangeException(nameof(attacking));
if (defending.Value < 1 || defending.Value > _effectiveness.Count)
throw new ArgumentOutOfRangeException(nameof(defending));
_effectiveness[attacking.Value - 1][defending.Value - 1] = effectiveness;
}
}