Documents all public classes, adds PokemonParty
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2023-07-15 14:24:29 +02:00
parent a8a6b775b3
commit d03569aa3f
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
50 changed files with 1364 additions and 97 deletions

View File

@ -1,5 +1,8 @@
namespace PkmnLibSharp.DynamicData namespace PkmnLibSharp.DynamicData
{ {
/// <summary>
/// A source of damage.
/// </summary>
public enum DamageSource : byte public enum DamageSource : byte
{ {
/// <summary> /// <summary>

View File

@ -4,10 +4,17 @@ using Interface = PkmnLibSharp.FFI.DynamicData.LearnedMove;
namespace PkmnLibSharp.DynamicData namespace PkmnLibSharp.DynamicData
{ {
/// <summary>
/// A learned move is the data attached to a Pokemon for a move it has learned. It has information
/// such as the remaining amount of users, how it has been learned, etc.
/// </summary>
public class LearnedMove : HandleType public class LearnedMove : HandleType
{ {
private LearnedMove(FFIHandle handle) : base(handle){} private LearnedMove(FFIHandle handle) : base(handle){}
/// <summary>
/// Creates a new learned move.
/// </summary>
public static LearnedMove Create(MoveData moveData, MoveLearnMethod learnMethod) public static LearnedMove Create(MoveData moveData, MoveLearnMethod learnMethod)
{ {
var handle = Interface.learned_move_new(moveData.Handle, learnMethod); var handle = Interface.learned_move_new(moveData.Handle, learnMethod);
@ -53,6 +60,9 @@ namespace PkmnLibSharp.DynamicData
public void RestoreUses(byte amount) => Interface.learned_move_restore_uses(Handle, amount); public void RestoreUses(byte amount) => Interface.learned_move_restore_uses(Handle, amount);
} }
/// <summary>
/// The different ways a move can be learned.
/// </summary>
public enum MoveLearnMethod : byte public enum MoveLearnMethod : byte
{ {
/// We do not know the learn method. /// We do not know the learn method.

View File

@ -4,19 +4,30 @@ using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.BattleStatCalculator;
namespace PkmnLibSharp.DynamicData.Libraries namespace PkmnLibSharp.DynamicData.Libraries
{ {
/// <summary>
/// A battle stat calculator is used to calculate stats for a Pokemon.
/// </summary>
public abstract class BattleStatCalculator : HandleType public abstract class BattleStatCalculator : HandleType
{ {
/// <inheritdoc cref="BattleStatCalculator"/>
protected BattleStatCalculator(FFIHandle handle) : base(handle){} protected BattleStatCalculator(FFIHandle handle) : base(handle){}
} }
/// <summary>
/// A basic implementation of the Gen 7 stat calculator.
/// </summary>
public class Gen7BattleStatCalculator : BattleStatCalculator public class Gen7BattleStatCalculator : BattleStatCalculator
{ {
/// <inheritdoc cref="Gen7BattleStatCalculator"/>
protected Gen7BattleStatCalculator(FFIHandle handle) : base(handle){} protected Gen7BattleStatCalculator(FFIHandle handle) : base(handle){}
/// <summary>
/// Creates a new Gen 7 battle stat calculator
/// </summary>
public static Gen7BattleStatCalculator Create() public static Gen7BattleStatCalculator Create()
{ {
var handle = Interface.gen_7_battle_stat_calculator_new(); var handle = Interface.gen_7_battle_stat_calculator_new();
return Resolver.Instance.ResolveGen7BattleStatCalculator(handle.Resolve()); return (Gen7BattleStatCalculator)Resolver.Instance.ResolveBattleStatCalculator(handle.Resolve());
} }
} }
} }

View File

@ -4,23 +4,38 @@ using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.DamageLibrary;
namespace PkmnLibSharp.DynamicData.Libraries namespace PkmnLibSharp.DynamicData.Libraries
{ {
/// <summary>
/// A damage library holds the functions related to the calculation of damage.
/// </summary>
public abstract class DamageLibrary : HandleType public abstract class DamageLibrary : HandleType
{ {
/// <inheritdoc cref="DamageLibrary"/>
protected DamageLibrary(FFIHandle ptr) : base(ptr) protected DamageLibrary(FFIHandle ptr) : base(ptr)
{ {
} }
} }
/// <summary>
/// The implementation of a Damage Library for generation 7.
/// </summary>
public class Gen7DamageLibrary : DamageLibrary public class Gen7DamageLibrary : DamageLibrary
{ {
/// <inheritdoc cref="Gen7DamageLibrary"/>
public Gen7DamageLibrary(FFIHandle ptr) : base(ptr) public Gen7DamageLibrary(FFIHandle ptr) : base(ptr)
{ {
} }
/// <summary>
/// Creates a new generation 7 damage library
/// </summary>
/// <param name="hasRandomness">
/// Whether or not a random damage modifier (0.85x - 1.00x) is applied to the calculated damage
/// </param>
/// <returns></returns>
public static Gen7DamageLibrary Create(bool hasRandomness) public static Gen7DamageLibrary Create(bool hasRandomness)
{ {
var handle = Interface.gen_7_damage_library_new((byte)(hasRandomness ? 1 : 0)); var handle = Interface.gen_7_damage_library_new((byte)(hasRandomness ? 1 : 0));
return Resolver.Instance.ResolveGen7DamageLibrary(handle.Resolve()); return (Gen7DamageLibrary)Resolver.Instance.ResolveDamageLibrary(handle.Resolve());
} }
} }
} }

View File

@ -4,12 +4,20 @@ using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.DynamicLibrary;
namespace PkmnLibSharp.DynamicData.Libraries namespace PkmnLibSharp.DynamicData.Libraries
{ {
/// <summary>
/// The dynamic library stores a static data library, as well as holding different libraries and
/// calculators that might be customized between different generations and implementations.
/// </summary>
public class DynamicLibrary : HandleType public class DynamicLibrary : HandleType
{ {
/// <inheritdoc cref="DynamicLibrary"/>
protected DynamicLibrary(FFIHandle handle) : base(handle) protected DynamicLibrary(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new DynamicLibrary with given libraries.
/// </summary>
public static DynamicLibrary Create(StaticData.Libraries.StaticData staticData, public static DynamicLibrary Create(StaticData.Libraries.StaticData staticData,
BattleStatCalculator statCalculator, DamageLibrary damageLibrary, MiscLibrary miscLibrary, BattleStatCalculator statCalculator, DamageLibrary damageLibrary, MiscLibrary miscLibrary,
ScriptResolver scriptResolver) ScriptResolver scriptResolver)
@ -21,6 +29,9 @@ namespace PkmnLibSharp.DynamicData.Libraries
return lib; return lib;
} }
/// <summary>
/// The static data is the immutable storage data for this library.
/// </summary>
public StaticData.Libraries.StaticData StaticData { get; private set; } = null!; public StaticData.Libraries.StaticData StaticData { get; private set; } = null!;
} }
} }

View File

@ -4,23 +4,34 @@ using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.MiscLibrary;
namespace PkmnLibSharp.DynamicData.Libraries namespace PkmnLibSharp.DynamicData.Libraries
{ {
/// <summary>
/// The misc library holds several misc functions required for the battle to run.
/// </summary>
public abstract class MiscLibrary : HandleType public abstract class MiscLibrary : HandleType
{ {
/// <inheritdoc cref="MiscLibrary"/>
protected MiscLibrary(FFIHandle handle) : base(handle) protected MiscLibrary(FFIHandle handle) : base(handle)
{ {
} }
} }
/// <summary>
/// A gen 7 implementation for the MiscLibrary.
/// </summary>
public class Gen7MiscLibrary : MiscLibrary public class Gen7MiscLibrary : MiscLibrary
{ {
/// <inheritdoc cref="Gen7MiscLibrary"/>
protected Gen7MiscLibrary(FFIHandle handle) : base(handle) protected Gen7MiscLibrary(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new MiscLibrary.
/// </summary>
public static Gen7MiscLibrary Create() public static Gen7MiscLibrary Create()
{ {
var handle = Interface.gen_7_misc_library_new(); var handle = Interface.gen_7_misc_library_new();
return Resolver.Instance.ResolveGen7MiscLibrary(handle.Resolve()); return (Gen7MiscLibrary)Resolver.Instance.ResolveMiscLibrary(handle.Resolve());
} }
} }
} }

View File

@ -5,8 +5,14 @@ using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.ScriptResolver;
namespace PkmnLibSharp.DynamicData.Libraries namespace PkmnLibSharp.DynamicData.Libraries
{ {
/// <summary>
/// A script resolver deals with the resolving of scripts. These scripts are non-hardcoded
/// implementations of different effects in Pokemon. This allows for things such as generational
/// differences, and custom implementations.
/// </summary>
public abstract class ScriptResolver : HandleType public abstract class ScriptResolver : HandleType
{ {
/// <inheritdoc cref="ScriptResolver"/>
protected ScriptResolver(FFIHandle handle) : base(handle){} protected ScriptResolver(FFIHandle handle) : base(handle){}
} }
@ -15,8 +21,12 @@ namespace PkmnLibSharp.DynamicData.Libraries
/// </summary> /// </summary>
public class EmptyScriptResolver : ScriptResolver public class EmptyScriptResolver : ScriptResolver
{ {
/// <inheritdoc cref="EmptyScriptResolver"/>
protected EmptyScriptResolver(FFIHandle handle) : base(handle){} protected EmptyScriptResolver(FFIHandle handle) : base(handle){}
/// <summary>
/// Creates a new empty script resolver.
/// </summary>
public static EmptyScriptResolver Create() public static EmptyScriptResolver Create()
{ {
var handle = Interface.empty_script_resolver_new(); var handle = Interface.empty_script_resolver_new();

View File

@ -4,16 +4,23 @@ using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.ScriptResolver;
namespace PkmnLibSharp.DynamicData.Libraries namespace PkmnLibSharp.DynamicData.Libraries
{ {
/// <summary>
/// A WebAssembly script resolver implements the dynamic scripts functionality with WebAssembly.
/// </summary>
public class WasmScriptResolver : ScriptResolver public class WasmScriptResolver : ScriptResolver
{ {
/// <inheritdoc cref="WasmScriptResolver"/>
protected WasmScriptResolver(FFIHandle handle) : base(handle) protected WasmScriptResolver(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new WebAssemblyScriptResolver.
/// </summary>
public static WasmScriptResolver Create() public static WasmScriptResolver Create()
{ {
var handle = Interface.webassembly_script_resolver_new(); var handle = Interface.webassembly_script_resolver_new();
return Resolver.Instance.ResolveWasmScriptResolver(handle.Resolve()); return (WasmScriptResolver)Resolver.Instance.ResolveScriptResolver(handle.Resolve());
} }
/// <summary> /// <summary>

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using PkmnLibSharp.DynamicData.Libraries; using PkmnLibSharp.DynamicData.Libraries;
using PkmnLibSharp.StaticData; using PkmnLibSharp.StaticData;
using PkmnLibSharp.Utils; using PkmnLibSharp.Utils;
@ -8,20 +9,40 @@ using Species = PkmnLibSharp.StaticData.Species;
namespace PkmnLibSharp.DynamicData namespace PkmnLibSharp.DynamicData
{ {
/// <summary>
/// The data of a Pokemon.
/// </summary>
public class Pokemon : HandleType public class Pokemon : HandleType
{ {
protected Pokemon(FFIHandle handle) : base(handle){} /// <inheritdoc cref="Pokemon"/>
protected Pokemon(FFIHandle handle) : base(handle)
public static Pokemon Create(DynamicLibrary dynamicLibrary, Species species, Form form, bool hiddenAbility, byte abilityIndex,
LevelInt level, uint uid, Gender gender, byte coloring, string nature)
{ {
var handle = Interface.pokemon_new(dynamicLibrary.Handle, species.Handle, form.Handle, hiddenAbility.ForeignBool(), }
abilityIndex, level, uid, gender, coloring, nature.ToPtr())
/// <summary>
/// Instantiates a new Pokemon.
/// </summary>
/// <param name="dynamicLibrary">The library the Pokemon should fetch its data from</param>
/// <param name="species">The species of the Pokemon</param>
/// <param name="form">The form the Pokemon should be</param>
/// <param name="hiddenAbility">Whether or not the ability the Pokemon has is hidden</param>
/// <param name="abilityIndex">The index of the ability</param>
/// <param name="level">The level of the Pokemon</param>
/// <param name="uid">The unique identifier of the Pokemon</param>
/// <param name="gender">The gender of the Pokemon</param>
/// <param name="coloring">The coloring of the Pokemon. This should be 0 for regular, 1 for shiny, and any other value for custom implementations</param>
/// <param name="nature">The nature of the Pokemon</param>
public static Pokemon Create(DynamicLibrary dynamicLibrary, Species species, Form form, bool hiddenAbility,
byte abilityIndex, LevelInt level, uint uid, Gender gender, byte coloring, string nature)
{
var handle = Interface.pokemon_new(dynamicLibrary.Handle, species.Handle, form.Handle,
hiddenAbility.ForeignBool(), abilityIndex, level, uid, gender, coloring, nature.ToPtr())
.Result(); .Result();
return Resolver.Instance.ResolvePokemon(handle.Resolve()); return Resolver.Instance.ResolvePokemon(handle.Resolve());
} }
private DynamicLibrary? _library; private DynamicLibrary? _library;
/// <summary> /// <summary>
/// The library data the Pokemon uses. /// The library data the Pokemon uses.
/// </summary> /// </summary>
@ -49,13 +70,43 @@ namespace PkmnLibSharp.DynamicData
/// </summary> /// </summary>
public Form DisplayForm => Resolver.Instance.ResolveForm(Interface.pokemon_display_form(Handle).Resolve()); public Form DisplayForm => Resolver.Instance.ResolveForm(Interface.pokemon_display_form(Handle).Resolve());
/// <summary>
/// The level of the Pokemon.
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Level">See also</a>
/// </summary>
public LevelInt Level => Interface.pokemon_level(Handle); public LevelInt Level => Interface.pokemon_level(Handle);
/// <summary>
/// The experience of the Pokemon.
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Experience">See also</a>
/// </summary>
public uint Experience => Interface.pokemon_experience(Handle); public uint Experience => Interface.pokemon_experience(Handle);
public uint UniqueIdentifier => Interface.pokemon_unique_identifier(Handle);
/// <summary>
/// The personality value of the Pokemon.
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Personality_value">See also</a>
/// </summary>
public uint PersonalityValue => Interface.pokemon_personality_value(Handle);
/// <summary>
/// The gender of the Pokemon.
/// </summary>
public Gender Gender => Interface.pokemon_gender(Handle); public Gender Gender => Interface.pokemon_gender(Handle);
/// <summary>
/// The coloring of the Pokemon. If this is 1, the Pokemon is shiny, otherwise it is not. This can
/// also be used for other custom coloring schemes.
/// </summary>
public byte Coloring => Interface.pokemon_coloring(Handle); public byte Coloring => Interface.pokemon_coloring(Handle);
/// <summary>
/// Whether or not the Pokemon is shiny.
/// </summary>
public bool IsShiny => Coloring == 1; public bool IsShiny => Coloring == 1;
/// <summary>
/// Gets the held item of a Pokemon. If the Pokemon does not have a held item, this will return null.
/// </summary>
public Item? HeldItem public Item? HeldItem
{ {
get get
@ -65,91 +116,241 @@ namespace PkmnLibSharp.DynamicData
} }
} }
/// <summary>
/// Checks whether the Pokemon is holding an item with a specific name.
/// </summary>
/// <param name="name">The name of the item to check for</param>
public bool HasHeldItem(string name) => Interface.pokemon_has_held_item(Handle, name.ToPtr()) == 1; public bool HasHeldItem(string name) => Interface.pokemon_has_held_item(Handle, name.ToPtr()) == 1;
public void SetHeldItem(Item? item) /// <summary>
/// Changes the held item of the Pokemon. Returns the previously held item.
/// </summary>
/// <param name="item">The new item to use. If this is given null, it will call <see cref="RemoveHeldItem"/></param>
public Item? SetHeldItem(Item? item)
{ {
if (item == null) if (item == null)
RemoveHeldItem(); {
else return RemoveHeldItem();
Interface.pokemon_set_held_item(Handle, item.Handle); }
var handle = Interface.pokemon_set_held_item(Handle, item.Handle);
return handle.IsNull ? null : Resolver.Instance.ResolveItem(handle.Resolve());
} }
public void RemoveHeldItem() => Interface.pokemon_remove_held_item(Handle); /// <summary>
/// Removes the held item from the Pokemon. Returns the previously held item.
/// </summary>
/// <returns>The previous held item. If no item was previously held, this returns null</returns>
public Item? RemoveHeldItem()
{
var handle = Interface.pokemon_remove_held_item(Handle);
return handle.IsNull ? null : Resolver.Instance.ResolveItem(handle.Resolve());
}
/// <summary>
/// Makes the Pokemon uses its held item.
/// </summary>
/// <returns>Whether or not the held item was successfully consumed</returns>
public bool ConsumeHeldItem() => Interface.pokemon_consume_held_item(Handle).Result() == 1; public bool ConsumeHeldItem() => Interface.pokemon_consume_held_item(Handle).Result() == 1;
/// <summary>
/// The current health of the Pokemon.
/// </summary>
public uint CurrentHealth => Interface.pokemon_current_health(Handle); public uint CurrentHealth => Interface.pokemon_current_health(Handle);
/// <summary>
/// The max health of the Pokemon.
/// </summary>
public uint MaxHealth => Interface.pokemon_max_health(Handle); public uint MaxHealth => Interface.pokemon_max_health(Handle);
/// <summary>
/// The current weight of the Pokemon.
/// </summary>
public float Weight => Interface.pokemon_weight(Handle); public float Weight => Interface.pokemon_weight(Handle);
/// <summary>
/// The current height of the Pokemon.
/// </summary>
public float Height => Interface.pokemon_height(Handle); public float Height => Interface.pokemon_height(Handle);
/// <summary>
/// An optional nickname of the Pokemon. If the Pokemon does not have a nickname, this will return null.
/// </summary>
public string? Nickname => Interface.pokemon_nickname(Handle).Result().PtrString(); public string? Nickname => Interface.pokemon_nickname(Handle).Result().PtrString();
/// <summary>
/// Whether the actual ability the Pokemon has (so not its potentially overriden ability) is a hidden ability.
/// </summary>
public bool HasHiddenAbility => Interface.pokemon_real_ability_is_hidden(Handle) == 1; public bool HasHiddenAbility => Interface.pokemon_real_ability_is_hidden(Handle) == 1;
/// <summary>
/// The index of the actual ability the Pokemon has (so not its potentially overriden ability).
/// </summary>
public byte AbilityIndex => Interface.pokemon_real_ability_index(Handle); public byte AbilityIndex => Interface.pokemon_real_ability_index(Handle);
private ExternValueArray<TypeIdentifier>? _types; private ExternValueArray<TypeIdentifier>? _types;
public ExternValueArray<TypeIdentifier> Types =>
/// <summary>
/// An array of the types of the Pokemon.
/// </summary>
public IReadOnlyList<TypeIdentifier> Types =>
_types ??= new ExternValueArray<TypeIdentifier>(() => Interface.pokemon_types_length(Handle), _types ??= new ExternValueArray<TypeIdentifier>(() => Interface.pokemon_types_length(Handle),
arg => Interface.pokemon_types_get(Handle, arg).Result()); arg => Interface.pokemon_types_get(Handle, arg).Result());
public LearnedMove? LearnedMove(ulong index) private ExternValueArray<LearnedMove?>? _moves;
{
var ptr = Interface.pokemon_learned_move_get(Handle, index);
return ptr.IsNull ? null : Resolver.Instance.ResolveLearnedMove(ptr.Resolve());
}
/// <summary>
/// The moves the Pokemon has learned and can use.
/// </summary>
public IReadOnlyList<LearnedMove?> LearnedMoves =>
_moves ??= new ExternValueArray<LearnedMove?>(() => 4, arg =>
{
var ptr = Interface.pokemon_learned_move_get(Handle, arg);
return ptr.IsNull ? null : Resolver.Instance.ResolveLearnedMove(ptr.Resolve());
});
private StatisticSet<uint>? _flatStats; private StatisticSet<uint>? _flatStats;
/// <summary>
/// The stats of the Pokemon when disregarding any stat boosts.
/// </summary>
public StatisticSet<uint> FlatStats => public StatisticSet<uint> FlatStats =>
_flatStats ??= _flatStats ??= Resolver.Instance.ResolveStatisticSet<uint>(Interface.pokemon_flat_stats(Handle).Resolve());
Resolver.Instance.ResolveStatisticSet<uint>(Interface.pokemon_flat_stats(Handle).Resolve());
private StatisticSet<uint>? _boostedStats; private StatisticSet<uint>? _boostedStats;
/// <summary>
/// The stats of the Pokemon including the stat boosts.
/// </summary>
public StatisticSet<uint> BoostedStats => public StatisticSet<uint> BoostedStats =>
_boostedStats ??= _boostedStats ??=
Resolver.Instance.ResolveStatisticSet<uint>(Interface.pokemon_boosted_stats(Handle).Resolve()); Resolver.Instance.ResolveStatisticSet<uint>(Interface.pokemon_boosted_stats(Handle).Resolve());
/// <summary>
/// Get the stat boosts for a specific stat. Between -6 and 6.
/// </summary>
public sbyte GetStatBoost(Statistic statistic) => Interface.pokemon_get_stat_boost(Handle, statistic); public sbyte GetStatBoost(Statistic statistic) => Interface.pokemon_get_stat_boost(Handle, statistic);
public byte GetIndividualValue(Statistic statistic) => Interface.pokemon_get_individual_value(Handle, statistic);
/// <summary>
/// Gets an individual value of the Pokemon.
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Individual_values">See also</a>
/// </summary>
public byte GetIndividualValue(Statistic statistic) =>
Interface.pokemon_get_individual_value(Handle, statistic);
/// <summary>
/// Gets an effort value of the Pokemon.
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Effort_values">See also</a>
/// </summary>
public byte GetEffortValue(Statistic statistic) => Interface.pokemon_get_effort_value(Handle, statistic); public byte GetEffortValue(Statistic statistic) => Interface.pokemon_get_effort_value(Handle, statistic);
/// <summary>
/// Modifies an individual value of the Pokemon.
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Individual_values">See also</a>
/// </summary>
public void SetIndividualValue(Statistic statistic, byte value) => public void SetIndividualValue(Statistic statistic, byte value) =>
Interface.pokemon_set_individual_value(Handle, statistic, value).Result(); Interface.pokemon_set_individual_value(Handle, statistic, value).Result();
/// <summary>
/// Modifies a effort value of the Pokemon.
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Effort_values">See also</a>
/// </summary>
public void SetEffortValue(Statistic statistic, byte value) => public void SetEffortValue(Statistic statistic, byte value) =>
Interface.pokemon_set_effort_value(Handle, statistic, value).Result(); Interface.pokemon_set_effort_value(Handle, statistic, value).Result();
// TODO: Battle getter // TODO: Battle getter
/// <summary>
/// Get the index of the side of the battle the Pokemon is in. If the Pokemon
/// is not on the battlefield, this always returns 0.
/// </summary>
public byte BattleSideIndex => Interface.pokemon_get_battle_side_index(Handle); public byte BattleSideIndex => Interface.pokemon_get_battle_side_index(Handle);
/// <summary>
/// Get the index of the slot on the side of the battle the Pokemon is in. If the Pokemon
/// is not on the battlefield, this always returns 0.
/// </summary>
public byte BattleIndex => Interface.pokemon_get_battle_index(Handle); public byte BattleIndex => Interface.pokemon_get_battle_index(Handle);
/// <summary>
/// Returns whether something overrides the ability.
/// </summary>
public bool IsAbilityOverriden => Interface.pokemon_is_ability_overriden(Handle) == 1; public bool IsAbilityOverriden => Interface.pokemon_is_ability_overriden(Handle) == 1;
/// <summary>
/// Returns the currently active ability.
/// </summary>
public Ability ActiveAbility => public Ability ActiveAbility =>
Resolver.Instance.ResolveAbility(Interface.pokemon_active_ability(Handle).Result().Resolve()); Resolver.Instance.ResolveAbility(Interface.pokemon_active_ability(Handle).Result().Resolve());
/// <summary>
/// Whether or not the Pokemon is allowed to gain experience.
/// </summary>
public bool AllowedExperienceGain => Interface.pokemon_allowed_experience_gain(Handle) == 1; public bool AllowedExperienceGain => Interface.pokemon_allowed_experience_gain(Handle) == 1;
/// <summary>
/// The nature of the Pokemon.
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Nature">See also</a>
/// </summary>
public Nature Nature => Resolver.Instance.ResolveNature(Interface.pokemon_nature(Handle).Resolve()); public Nature Nature => Resolver.Instance.ResolveNature(Interface.pokemon_nature(Handle).Resolve());
/// <summary>
/// Calculates the flat stats on the Pokemon. This should be called when for example the base
/// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted
/// stats, as those depend on the flat stats.
/// </summary>
public void RecalculateFlatStats() => Interface.pokemon_recalculate_flat_stats(Handle).Result(); public void RecalculateFlatStats() => Interface.pokemon_recalculate_flat_stats(Handle).Result();
/// <summary>
/// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes.
/// </summary>
public void RecalculateBoostedStats() => Interface.pokemon_recalculate_boosted_stats(Handle).Result(); public void RecalculateBoostedStats() => Interface.pokemon_recalculate_boosted_stats(Handle).Result();
/// <summary>
/// Change the species of the Pokemon.
/// </summary>
public void ChangeSpecies(Species species, Form form) => public void ChangeSpecies(Species species, Form form) =>
Interface.pokemon_change_species(Handle, species.Handle, form.Handle).Result(); Interface.pokemon_change_species(Handle, species.Handle, form.Handle).Result();
/// <summary>
/// Change the form of the Pokemon.
/// </summary>
public void ChangeForm(Form form) => Interface.pokemon_change_form(Handle, form.Handle).Result(); public void ChangeForm(Form form) => Interface.pokemon_change_form(Handle, form.Handle).Result();
/// <summary>
/// Whether or not the Pokemon is useable in a battle.
/// </summary>
public bool IsUsable => Interface.pokemon_is_usable(Handle) == 1; public bool IsUsable => Interface.pokemon_is_usable(Handle) == 1;
/// <summary>
/// Returns whether the Pokemon is fainted.
/// </summary>
public bool IsFainted => Interface.pokemon_is_fainted(Handle) == 1; public bool IsFainted => Interface.pokemon_is_fainted(Handle) == 1;
/// <summary>
/// Whether or not the Pokemon is on the battlefield.
/// </summary>
public bool IsOnBattleField => Interface.pokemon_is_on_battlefield(Handle) == 1; public bool IsOnBattleField => Interface.pokemon_is_on_battlefield(Handle) == 1;
public void Damage(uint amount, DamageSource source) => Interface.pokemon_damage(Handle, amount, source).Result(); /// <summary>
/// Damages the Pokemon by a certain amount of damage, from a damage source.
/// </summary>
public void Damage(uint amount, DamageSource source) =>
Interface.pokemon_damage(Handle, amount, source).Result();
/// <summary>
/// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not
/// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false.
/// </summary>
public bool Heal(uint amount, bool allowRevive) => public bool Heal(uint amount, bool allowRevive) =>
Interface.pokemon_heal(Handle, amount, allowRevive.ForeignBool()) == 1; Interface.pokemon_heal(Handle, amount, allowRevive.ForeignBool()) == 1;
/// <summary>
/// Learn a move.
/// </summary>
public void LearnMove(string moveName, MoveLearnMethod learnMethod) => public void LearnMove(string moveName, MoveLearnMethod learnMethod) =>
Interface.pokemon_learn_move(Handle, moveName.ToPtr(), learnMethod).Result(); Interface.pokemon_learn_move(Handle, moveName.ToPtr(), learnMethod).Result();
/// <summary>
/// Removes the current non-volatile status from the Pokemon.
/// </summary>
public void ClearStatus() => Interface.pokemon_clear_status(Handle); public void ClearStatus() => Interface.pokemon_clear_status(Handle);
} }
} }

View File

@ -6,6 +6,9 @@ using PkmnLibSharp.Utils;
namespace PkmnLibSharp.DynamicData namespace PkmnLibSharp.DynamicData
{ {
/// <summary>
/// A builder class for creating <see cref="Pokemon"/> instances.
/// </summary>
public class PokemonBuilder public class PokemonBuilder
{ {
private static readonly Random DefaultRandom = new(); private static readonly Random DefaultRandom = new();
@ -29,6 +32,10 @@ namespace PkmnLibSharp.DynamicData
private byte _abilityIndex; private byte _abilityIndex;
private byte _coloring; private byte _coloring;
/// <inheritdoc cref="PokemonBuilder"/>
/// <param name="library">The library the Pokemon should use for data</param>
/// <param name="species">The name of the species of Pokemon</param>
/// <param name="level">The level the Pokemon should be</param>
public PokemonBuilder(DynamicLibrary library, string species, LevelInt level) public PokemonBuilder(DynamicLibrary library, string species, LevelInt level)
{ {
_library = library; _library = library;
@ -38,54 +45,82 @@ namespace PkmnLibSharp.DynamicData
_random = new Random(_randomSeed); _random = new Random(_randomSeed);
} }
/// <summary>
/// Sets the name of the form of the Pokemon.
/// </summary>
public PokemonBuilder WithForm(string form) public PokemonBuilder WithForm(string form)
{ {
_form = form; _form = form;
return this; return this;
} }
/// <summary>
/// Force the Pokemon to be shiny or not shiny, instead of letting this be determined randomly.
/// </summary>
public PokemonBuilder ForceShiny(bool value) public PokemonBuilder ForceShiny(bool value)
{ {
_forceShininess = value; _forceShininess = value;
return this; return this;
} }
/// <summary>
/// Sets the gender of the Pokemon to a specific value, instead of letting this be determined randomly.
/// </summary>
public PokemonBuilder WithGender(Gender gender) public PokemonBuilder WithGender(Gender gender)
{ {
_gender = gender; _gender = gender;
return this; return this;
} }
/// <summary>
/// Sets the identifier of the Pokemon to a specific value, instead of letting this be determined randomly.
/// </summary>
public PokemonBuilder WithIdentifier(uint identifier) public PokemonBuilder WithIdentifier(uint identifier)
{ {
_identifier = identifier; _identifier = identifier;
return this; return this;
} }
/// <summary>
/// Sets the nature of the Pokemon to a specific value, instead of letting this be determined randomly.
/// </summary>
public PokemonBuilder WithNature(string nature) public PokemonBuilder WithNature(string nature)
{ {
_natureName = nature; _natureName = nature;
return this; return this;
} }
/// <summary>
/// Sets the ability of the Pokemon to a specific value, instead of letting this be determined randomly.
/// </summary>
public PokemonBuilder WithAbility(string ability) public PokemonBuilder WithAbility(string ability)
{ {
_ability = ability; _ability = ability;
return this; return this;
} }
/// <summary>
/// Gives the Pokemon a specific amount of experience. If not set, the experience will be calculated based on
/// the Pokemon's level and growth rate.
/// </summary>
public PokemonBuilder WithExperience(uint experience) public PokemonBuilder WithExperience(uint experience)
{ {
_experience = experience; _experience = experience;
return this; return this;
} }
/// <summary>
/// Teaches the Pokemon a move.
/// </summary>
public PokemonBuilder LearnMove(string moveName, MoveLearnMethod learnMethod) public PokemonBuilder LearnMove(string moveName, MoveLearnMethod learnMethod)
{ {
_moves.Add((moveName, learnMethod)); _moves.Add((moveName, learnMethod));
return this; return this;
} }
/// <summary>
/// This method is called after all properties have been set, and will create the Pokemon.
/// </summary>
protected virtual Pokemon Finalize(Species species, Form form, Item? heldItem) protected virtual Pokemon Finalize(Species species, Form form, Item? heldItem)
{ {
var pokemon = Pokemon.Create(_library, species, form, _hiddenAbility, _abilityIndex, _level, var pokemon = Pokemon.Create(_library, species, form, _hiddenAbility, _abilityIndex, _level,
@ -100,6 +135,9 @@ namespace PkmnLibSharp.DynamicData
return pokemon; return pokemon;
} }
/// <summary>
/// Populates any properties that have not been set with random values.
/// </summary>
protected virtual void PopulateUninitialized(Species species, Form form, Random random) protected virtual void PopulateUninitialized(Species species, Form form, Random random)
{ {
_experience ??= _library.StaticData.GrowthRateLibrary.CalculateExperience(species.GrowthRate, _level); _experience ??= _library.StaticData.GrowthRateLibrary.CalculateExperience(species.GrowthRate, _level);
@ -146,6 +184,9 @@ namespace PkmnLibSharp.DynamicData
return (true, (byte)i); return (true, (byte)i);
} }
/// <summary>
/// Builds the Pokemon, based on the properties that have been set.
/// </summary>
public Pokemon Build() public Pokemon Build()
{ {
if (!_library.StaticData.SpeciesLibrary.TryGetValue(_species, out var species)) if (!_library.StaticData.SpeciesLibrary.TryGetValue(_species, out var species))

View File

@ -0,0 +1,102 @@
using System.Collections;
using System.Collections.Generic;
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.DynamicData.PokemonParty;
namespace PkmnLibSharp.DynamicData
{
/// <summary>
/// A list of Pokemon belonging to a trainer.
/// </summary>
public class PokemonParty : HandleType, IReadOnlyList<Pokemon?>
{
/// <summary>
/// A cache of the Pokemon in the party.
/// </summary>
private Pokemon?[] _cachedPokemon = null!;
internal PokemonParty(FFIHandle handle) : base(handle)
{
}
/// <summary>
/// Instantiates a party with a set size.
/// </summary>
/// <param name="capacity">The length of the party</param>
public static PokemonParty Create(ulong capacity)
{
var handle = Interface.pokemon_party_new(capacity).Resolve();
var party = Resolver.Instance.ResolvePokemonParty(handle);
party._cachedPokemon = new Pokemon?[capacity];
return party;
}
/// <inheritdoc />
public IEnumerator<Pokemon?> GetEnumerator()
{
return ((IEnumerable<Pokemon?>)_cachedPokemon).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <inheritdoc />
public int Count => _cachedPokemon.Length;
/// <inheritdoc />
public Pokemon? this[int index] => _cachedPokemon[index];
/// <summary>
/// Swaps two Pokemon in the party around.
/// </summary>
public void Switch(int a, int b)
{
Interface.pokemon_party_switch(Handle, (ulong)a, (ulong)b).Result();
(_cachedPokemon[a], _cachedPokemon[b]) = (_cachedPokemon[b], _cachedPokemon[a]);
}
/// <summary>
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
/// </summary>
/// <param name="index">The index to switch at</param>
/// <param name="pokemon">The pokemon to switch into the slot</param>
/// <returns>The previous Pokemon in the slot</returns>
public Pokemon? SwapInto(int index, Pokemon? pokemon)
{
var handle = Interface.pokemon_party_swap_into(Handle, (ulong)index, pokemon?.Handle ?? FFIHandle.Zero)
.Result();
var p = handle.IsNull ? null : Resolver.Instance.ResolvePokemon(handle.Resolve());
_cachedPokemon[index] = pokemon;
return p;
}
/// <summary>
/// Whether or not the party still has Pokemon that can be used in battle.
/// </summary>
public bool HasUsablePokemon() => Interface.pokemon_party_has_usable_pokemon(Handle) == 1;
/// <summary>
/// Checks if the party contains a given pokemon.
/// </summary>
/// <param name="pokemon">The pokemon to check for</param>
public bool HasPokemon(Pokemon pokemon) => Interface.pokemon_party_has_pokemon(Handle, pokemon.Handle) == 1;
/// <summary>
/// Makes sure there are no empty spots in the party anymore, leaving the length the same.
/// </summary>
public void PackParty()
{
Interface.pokemon_party_pack_party(Handle);
// Ensure the old cache is kept alive while we update the new one.
var oldCache = _cachedPokemon;
// Update the cache.
_cachedPokemon = new Pokemon?[oldCache.Length];
for (var i = 0; i < oldCache.Length; i++)
{
var handle = Interface.pokemon_party_at(Handle, (ulong)i).Resolve();
_cachedPokemon[i] = Resolver.Instance.ResolvePokemon(handle);
}
}
}
}

View File

@ -54,7 +54,7 @@ namespace PkmnLibSharp.FFI.DynamicData
internal static extern uint pokemon_experience(FFIHandleValue pokemon); internal static extern uint pokemon_experience(FFIHandleValue pokemon);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern uint pokemon_unique_identifier(FFIHandleValue pokemon); internal static extern uint pokemon_personality_value(FFIHandleValue pokemon);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern Gender pokemon_gender(FFIHandleValue pokemon); internal static extern Gender pokemon_gender(FFIHandleValue pokemon);
@ -78,13 +78,13 @@ namespace PkmnLibSharp.FFI.DynamicData
/// Changes the held item of the Pokemon. Returns the previously held item. /// Changes the held item of the Pokemon. Returns the previously held item.
/// </summary> /// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_set_held_item(FFIHandleValue pokemon, FFIHandle item); internal static extern FFIHandleValue pokemon_set_held_item(FFIHandleValue pokemon, FFIHandle item);
/// <summary> /// <summary>
/// Removes the held item from the Pokemon. Returns the previously held item. /// Removes the held item from the Pokemon. Returns the previously held item.
/// </summary> /// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_remove_held_item(FFIHandleValue pokemon); internal static extern FFIHandleValue pokemon_remove_held_item(FFIHandleValue pokemon);
/// <summary> /// <summary>
/// Makes the Pokemon uses its held item. /// Makes the Pokemon uses its held item.
@ -191,7 +191,7 @@ namespace PkmnLibSharp.FFI.DynamicData
/// returns null. /// returns null.
/// </summary> /// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_get_battle(FFIHandleValue pokemon); internal static extern FFIHandleValue pokemon_get_battle(FFIHandleValue pokemon);
/// <summary> /// <summary>
/// Get the index of the side of the battle the Pokemon is in. If the Pokemon /// Get the index of the side of the battle the Pokemon is in. If the Pokemon

View File

@ -0,0 +1,59 @@
using System;
using System.Runtime.InteropServices;
using PkmnLibSharp.StaticData;
using PkmnLibSharp.Utils;
namespace PkmnLibSharp.FFI.DynamicData
{
internal static class PokemonParty
{
/// <summary>
/// Instantiates a party with a set size.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern FFIHandleValue pokemon_party_new(ulong capacity);
/// <summary>
/// Gets a Pokemon at an index in the party.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern FFIHandleValue pokemon_party_at(FFIHandleValue party, ulong index);
/// <summary>
/// Swaps two Pokemon in the party around.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern NativeResult pokemon_party_switch(FFIHandle party, ulong a, ulong b);
/// <summary>
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern NativeResult<FFIHandleValue> pokemon_party_swap_into(FFIHandleValue party, ulong index,
FFIHandleValue pokemon);
/// <summary>
/// Whether or not the party still has Pokemon that can be used in battle.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_party_has_usable_pokemon(FFIHandleValue party);
/// <summary>
/// Get the length of the underlying list of Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern ulong pokemon_party_length(FFIHandleValue party);
/// <summary>
/// Makes sure there are no empty spots in the party anymore, leaving the length the same.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern NativeResult pokemon_party_pack_party(FFIHandleValue party);
/// <summary>
/// Checks if the party contains a given pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_party_has_pokemon(FFIHandleValue party, FFIHandleValue pokemon);
}
}

View File

@ -1,14 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace PkmnLibSharp.FFI
{
[StructLayout(LayoutKind.Sequential)]
public struct IdentifiablePointer
{
public readonly IntPtr Ptr;
public readonly nuint Identifier;
public bool IsNull => Ptr == IntPtr.Zero;
}
}

View File

@ -43,6 +43,9 @@ namespace PkmnLibSharp.FFI
} }
} }
/// <summary>
/// An error thrown by the library.
/// </summary>
public class PkmnLibException : Exception public class PkmnLibException : Exception
{ {
internal PkmnLibException(string message) : base(message){} internal PkmnLibException(string message) : base(message){}

View File

@ -10,7 +10,7 @@ namespace PkmnLibSharp.FFI.StaticData.Libraries
internal static extern FFIHandleValue move_library_new(ulong capacity); internal static extern FFIHandleValue move_library_new(ulong capacity);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer move_library_get(FFIHandleValue ptr, IntPtr key); internal static extern FFIHandleValue move_library_get(FFIHandleValue ptr, IntPtr key);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr move_library_get_key_by_index(FFIHandleValue ptr, ulong index); internal static extern IntPtr move_library_get_key_by_index(FFIHandleValue ptr, ulong index);

View File

@ -14,11 +14,13 @@
<NoWarn>IDISP012</NoWarn> <NoWarn>IDISP012</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>TRACE;WASM;</DefineConstants> <DefineConstants>TRACE;WASM;</DefineConstants>
<DocumentationFile>bin\Debug\PkmnLibRSharp.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>TRACE;WASM;</DefineConstants> <DefineConstants>TRACE;WASM;</DefineConstants>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -5,20 +5,38 @@ using Interface = PkmnLibSharp.FFI.StaticData.Ability;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// An ability is a passive effect in battle that is attached to a Pokemon.
/// </summary>
public class Ability : HandleType public class Ability : HandleType
{ {
private string? _name; private string? _name;
/// <summary>
/// The name of the ability.
/// </summary>
public string Name => _name ??= Interface.ability_name(Handle).Result().PtrString()!; public string Name => _name ??= Interface.ability_name(Handle).Result().PtrString()!;
private string? _effect; private string? _effect;
/// <summary>
/// The name of the script effect of the ability.
/// </summary>
public string Effect => _effect ??= Interface.ability_effect(Handle).Result().PtrString()!; public string Effect => _effect ??= Interface.ability_effect(Handle).Result().PtrString()!;
/// <summary>
/// The parameters for the script effect of the ability.
/// </summary>
public IReadOnlyList<EffectParameter> Parameters { get; private set; } = null!; public IReadOnlyList<EffectParameter> Parameters { get; private set; } = null!;
/// <inheritdoc cref="Ability"/>
protected Ability(FFIHandle handle) : base(handle) protected Ability(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new ability.
/// </summary>
public static Ability Create(string name, string effect, IReadOnlyList<EffectParameter> parameters) public static Ability Create(string name, string effect, IReadOnlyList<EffectParameter> parameters)
{ {
var parameterArray = parameters.Select(x => (FFIHandleValue)x.Handle).ToArray(); var parameterArray = parameters.Select(x => (FFIHandleValue)x.Handle).ToArray();

View File

@ -4,13 +4,27 @@ using Interface = PkmnLibSharp.FFI.StaticData.EffectParameter;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// A parameter for an effect. This is basically a simple way to dynamically store multiple different
/// primitives on data.
/// </summary>
public class EffectParameter : HandleType public class EffectParameter : HandleType
{ {
private ParameterType? _type; private ParameterType? _type;
/// <summary>
/// The underlying type of the parameter.
/// </summary>
public ParameterType? Type => _type ??= (ParameterType)Interface.effect_parameter_get_type(Handle); public ParameterType? Type => _type ??= (ParameterType)Interface.effect_parameter_get_type(Handle);
private object? _data; private object? _data;
/// <summary>
/// The data stored in the parameter.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when the parameter type is not recognized. This should never happen.
/// </exception>
public object Data public object Data
{ {
get get
@ -27,35 +41,75 @@ namespace PkmnLibSharp.StaticData
} }
} }
/// <inheritdoc cref="EffectParameter"/>
protected EffectParameter(FFIHandle handle) : base(handle) protected EffectParameter(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Creates a new parameter from a boolean.
/// </summary>
public static EffectParameter FromBool(bool b) => public static EffectParameter FromBool(bool b) =>
Resolver.Instance.ResolveEffectParameter(Interface.effect_parameter_new_bool(b.ForeignBool()).Resolve()); Resolver.Instance.ResolveEffectParameter(Interface.effect_parameter_new_bool(b.ForeignBool()).Resolve());
/// <summary>
/// Creates a new parameter from a 64 bit integer.
/// </summary>
public static EffectParameter FromLong(long l) => public static EffectParameter FromLong(long l) =>
Resolver.Instance.ResolveEffectParameter(Interface.effect_parameter_new_int(l).Resolve()); Resolver.Instance.ResolveEffectParameter(Interface.effect_parameter_new_int(l).Resolve());
/// <summary>
/// Creates a new parameter from a float.
/// </summary>
public static EffectParameter FromFloat(float f) => public static EffectParameter FromFloat(float f) =>
Resolver.Instance.ResolveEffectParameter(Interface.effect_parameter_new_float(f).Resolve()); Resolver.Instance.ResolveEffectParameter(Interface.effect_parameter_new_float(f).Resolve());
/// <summary>
/// Creates a new parameter from a string.
/// </summary>
public static EffectParameter FromString(string s) => public static EffectParameter FromString(string s) =>
Resolver.Instance.ResolveEffectParameter(Interface.effect_parameter_new_string(s.ToPtr()).Result().Resolve()); Resolver.Instance.ResolveEffectParameter(
Interface.effect_parameter_new_string(s.ToPtr()).Result().Resolve());
/// <inheritdoc cref="FromBool"/>
public static implicit operator EffectParameter(bool b) => FromBool(b); public static implicit operator EffectParameter(bool b) => FromBool(b);
/// <inheritdoc cref="FromLong"/>
public static implicit operator EffectParameter(long l) => FromLong(l); public static implicit operator EffectParameter(long l) => FromLong(l);
/// <inheritdoc cref="FromFloat"/>
public static implicit operator EffectParameter(float f) => FromFloat(f); public static implicit operator EffectParameter(float f) => FromFloat(f);
/// <inheritdoc cref="FromString"/>
public static implicit operator EffectParameter(string s) => FromString(s); public static implicit operator EffectParameter(string s) => FromString(s);
/// <summary>
/// The different types of parameters.
/// </summary>
public enum ParameterType : byte public enum ParameterType : byte
{ {
/// <summary>
/// A boolean parameter.
/// </summary>
Bool = 0, Bool = 0,
/// <summary>
/// A 64 bit integer parameter.
/// </summary>
Int = 1, Int = 1,
/// <summary>
/// A 32 bit floating point parameter.
/// </summary>
Float = 2, Float = 2,
/// <summary>
/// A string parameter.
/// </summary>
String = 3, String = 3,
} }
/// <inheritdoc />
public override string ToString() public override string ToString()
{ {
var data = Data; var data = Data;

View File

@ -5,12 +5,20 @@ using Interface = PkmnLibSharp.FFI.StaticData.Form;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// A form is a variant of a specific species. A species always has at least one form, but can have
/// many more.
/// </summary>
public class Form : HandleType public class Form : HandleType
{ {
/// <inheritdoc cref="Form"/>
protected Form(FFIHandle handle) : base(handle) protected Form(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new form.
/// </summary>
public static Form Create(string name, float height, float weight, uint baseExperience, TypeIdentifier[] types, public static Form Create(string name, float height, float weight, uint baseExperience, TypeIdentifier[] types,
StaticStatisticSet<ushort> baseStats, IReadOnlyCollection<string> abilities, StaticStatisticSet<ushort> baseStats, IReadOnlyCollection<string> abilities,
IReadOnlyCollection<string> hiddenAbilities, LearnableMoves learnableMoves, IReadOnlyCollection<string> hiddenAbilities, LearnableMoves learnableMoves,
@ -32,34 +40,69 @@ namespace PkmnLibSharp.StaticData
private string? _name; private string? _name;
/// <summary>
/// The name of the form.
/// </summary>
public string Name => _name ??= Interface.form_name(Handle).Result().PtrString()!; public string Name => _name ??= Interface.form_name(Handle).Result().PtrString()!;
private float? _height; private float? _height;
/// <summary>
/// The height of the form in meters.
/// </summary>
public float Height => _height ??= Interface.form_height(Handle); public float Height => _height ??= Interface.form_height(Handle);
private float? _weight; private float? _weight;
/// <summary>
/// The weight of the form in kilograms.
/// </summary>
public float Weight => _weight ??= Interface.form_weight(Handle); public float Weight => _weight ??= Interface.form_weight(Handle);
private uint? _baseExperience; private uint? _baseExperience;
/// <summary>
/// The base amount of experience that is gained when beating a Pokemon with this form.
/// </summary>
public uint BaseExperience => _baseExperience ??= Interface.form_base_experience(Handle); public uint BaseExperience => _baseExperience ??= Interface.form_base_experience(Handle);
private IReadOnlyList<TypeIdentifier>? _types; private IReadOnlyList<TypeIdentifier>? _types;
/// <summary>
/// The normal types a Pokemon with this form has.
/// </summary>
public IReadOnlyList<TypeIdentifier> Types => public IReadOnlyList<TypeIdentifier> Types =>
_types ??= new CachedExternValueArray<TypeIdentifier>(Interface.form_types_length(Handle), _types ??= new CachedExternValueArray<TypeIdentifier>(Interface.form_types_length(Handle),
arg => Interface.form_types_get(Handle, arg)); arg => Interface.form_types_get(Handle, arg));
private StaticStatisticSet<ushort>? _baseStats; private StaticStatisticSet<ushort>? _baseStats;
/// <summary>
/// The inherent values of a form of species that are used for the stats of a Pokemon.
/// </summary>
public StaticStatisticSet<ushort> BaseStats => public StaticStatisticSet<ushort> BaseStats =>
_baseStats ??= Resolver.Instance.ResolveStaticStatisticSet<ushort>(Interface.form_base_stats(Handle).Resolve()); _baseStats ??= Resolver.Instance.ResolveStaticStatisticSet<ushort>(Interface.form_base_stats(Handle).Resolve());
private IReadOnlyList<string>? _abilities; private IReadOnlyList<string>? _abilities;
/// <summary>
/// The possible abilities a Pokemon with this form can have.
/// </summary>
public IReadOnlyList<string> Abilities => public IReadOnlyList<string> Abilities =>
_abilities ??= new CachedExternArray<string>(Interface.form_abilities_length(Handle), _abilities ??= new CachedExternArray<string>(Interface.form_abilities_length(Handle),
arg => Interface.form_abilities_get(Handle, arg).PtrString()!); arg => Interface.form_abilities_get(Handle, arg).PtrString()!);
private IReadOnlyList<string>? _hiddenAbilities; private IReadOnlyList<string>? _hiddenAbilities;
/// <summary>
/// The possible hidden abilities a Pokemon with this form can have.
/// </summary>
public IReadOnlyList<string> HiddenAbilities => public IReadOnlyList<string> HiddenAbilities =>
_hiddenAbilities ??= new CachedExternArray<string>(Interface.form_hidden_abilities_length(Handle), _hiddenAbilities ??= new CachedExternArray<string>(Interface.form_hidden_abilities_length(Handle),
arg => Interface.form_hidden_abilities_get(Handle, arg).PtrString()!); arg => Interface.form_hidden_abilities_get(Handle, arg).PtrString()!);
private LearnableMoves? _learnableMoves; private LearnableMoves? _learnableMoves;
/// <summary>
/// The moves a Pokemon with this form can learn.
/// </summary>
public LearnableMoves LearnableMoves => public LearnableMoves LearnableMoves =>
_learnableMoves ??= Resolver.Instance.ResolveLearnableMoves(Interface.form_moves(Handle).Resolve()); _learnableMoves ??= Resolver.Instance.ResolveLearnableMoves(Interface.form_moves(Handle).Resolve());
} }

View File

@ -1,5 +1,11 @@
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// Gender is a Pokemon characteristic.
///
/// Required for standard pokemon functions, but somewhat controversial nowadays. Consider adding a feature
/// that allows for a more progressive gender system for those that want it?
/// </summary>
public enum Gender : byte public enum Gender : byte
{ {
/// <summary> /// <summary>

View File

@ -5,28 +5,45 @@ using Interface = PkmnLibSharp.FFI.StaticData.GrowthRate;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// A growth rate defines how much experience is required per level.
/// </summary>
public abstract class GrowthRate : HandleType public abstract class GrowthRate : HandleType
{ {
/// <inheritdoc cref="GrowthRate"/>
protected internal GrowthRate(FFIHandle ptr) : base(ptr) protected internal GrowthRate(FFIHandle ptr) : base(ptr)
{ {
} }
/// <summary>
/// Calculate the level something with this growth rate would have at a certain experience.
/// </summary>
public LevelInt CalculateLevel(uint experience) public LevelInt CalculateLevel(uint experience)
{ {
return Interface.growth_rate_calculate_level(Handle, experience); return Interface.growth_rate_calculate_level(Handle, experience);
} }
/// <summary>
/// Calculate the experience something with this growth rate would have at a certain level.
/// </summary>
public uint CalculateExperience(LevelInt level) public uint CalculateExperience(LevelInt level)
{ {
return Interface.growth_rate_calculate_experience(Handle, level).Result(); return Interface.growth_rate_calculate_experience(Handle, level).Result();
} }
} }
/// <summary>
/// An implementation of the growth rate that uses a lookup table for experience.
/// </summary>
public class LookupGrowthRate : GrowthRate public class LookupGrowthRate : GrowthRate
{ {
/// <inheritdoc cref="LookupGrowthRate"/>
protected LookupGrowthRate(FFIHandle handle) : base(handle){} protected LookupGrowthRate(FFIHandle handle) : base(handle){}
/// <summary>
/// Instantiates a new lookup growth rate. The experience vec should be the amount of experience
/// required per level, with the first element being the experience required for level 1 (generally 0).
/// </summary>
public static LookupGrowthRate Create(uint[] experienceArray) public static LookupGrowthRate Create(uint[] experienceArray)
{ {
var arrayPtr = experienceArray.ArrayPtr(); var arrayPtr = experienceArray.ArrayPtr();
@ -52,6 +69,10 @@ namespace PkmnLibSharp.StaticData
return i * i * i; return i * i * i;
} }
/// <summary>
/// The Fast experience group
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Experience#Fast">See also</a>
/// </summary>
public static LookupGrowthRate Fast(LevelInt maxLevel) public static LookupGrowthRate Fast(LevelInt maxLevel)
{ {
var arr = new uint[maxLevel]; var arr = new uint[maxLevel];
@ -64,6 +85,10 @@ namespace PkmnLibSharp.StaticData
return LookupGrowthRate.Create(arr); return LookupGrowthRate.Create(arr);
} }
/// <summary>
/// The Medium Fast experience group
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Experience#Medium_Fast">See also</a>
/// </summary>
public static LookupGrowthRate MediumFast(LevelInt maxLevel) public static LookupGrowthRate MediumFast(LevelInt maxLevel)
{ {
var arr = new uint[maxLevel]; var arr = new uint[maxLevel];
@ -76,6 +101,10 @@ namespace PkmnLibSharp.StaticData
return LookupGrowthRate.Create(arr); return LookupGrowthRate.Create(arr);
} }
/// <summary>
/// The Medium Slow experience group
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Experience#Medium_Slow">See also</a>
/// </summary>
public static LookupGrowthRate MediumSlow(LevelInt maxLevel) public static LookupGrowthRate MediumSlow(LevelInt maxLevel)
{ {
var arr = new uint[maxLevel]; var arr = new uint[maxLevel];
@ -88,6 +117,10 @@ namespace PkmnLibSharp.StaticData
return LookupGrowthRate.Create(arr); return LookupGrowthRate.Create(arr);
} }
/// <summary>
/// The Slow experience group
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Experience#Slow">See also</a>
/// </summary>
public static LookupGrowthRate Slow(LevelInt maxLevel) public static LookupGrowthRate Slow(LevelInt maxLevel)
{ {
var arr = new uint[maxLevel]; var arr = new uint[maxLevel];
@ -99,6 +132,10 @@ namespace PkmnLibSharp.StaticData
return LookupGrowthRate.Create(arr); return LookupGrowthRate.Create(arr);
} }
/// <summary>
/// The Erratic experience group
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Experience#Erratic">See also</a>
/// </summary>
public static LookupGrowthRate Erratic(LevelInt maxLevel) public static LookupGrowthRate Erratic(LevelInt maxLevel)
{ {
var arr = new uint[maxLevel]; var arr = new uint[maxLevel];
@ -127,6 +164,10 @@ namespace PkmnLibSharp.StaticData
return LookupGrowthRate.Create(arr); return LookupGrowthRate.Create(arr);
} }
/// <summary>
/// The fluctuating experience group
/// <a href="https://bulbapedia.bulbagarden.net/wiki/Experience#Fluctuating">See also</a>
/// </summary>
public static LookupGrowthRate Fluctuating(LevelInt maxLevel) public static LookupGrowthRate Fluctuating(LevelInt maxLevel)
{ {
var arr = new uint[maxLevel]; var arr = new uint[maxLevel];

View File

@ -82,10 +82,17 @@ namespace PkmnLibSharp.StaticData
MiscBattleItem, MiscBattleItem,
} }
/// <summary>
/// An item is an object which the player can pick up, keep in their Bag, and use in some manner
/// </summary>
public class Item : HandleType public class Item : HandleType
{ {
/// <inheritdoc cref="Item"/>
protected Item(FFIHandle handle) : base(handle){} protected Item(FFIHandle handle) : base(handle){}
/// <summary>
/// Instantiates an item.
/// </summary>
public static Item Create(string name, ItemCategory category, BattleItemCategory battleItemCategory, int price, public static Item Create(string name, ItemCategory category, BattleItemCategory battleItemCategory, int price,
IEnumerable<string> flags) IEnumerable<string> flags)
{ {
@ -97,14 +104,29 @@ namespace PkmnLibSharp.StaticData
} }
private string? _name; private string? _name;
/// <summary>
/// The name of the item.
/// </summary>
public string Name => _name ??= Interface.item_name(Handle).Result().PtrString()!; public string Name => _name ??= Interface.item_name(Handle).Result().PtrString()!;
private ItemCategory? _category; private ItemCategory? _category;
/// <summary>
/// Which bag slot items are stored in.
/// </summary>
public ItemCategory Category => _category ??= Interface.item_category(Handle); public ItemCategory Category => _category ??= Interface.item_category(Handle);
private BattleItemCategory? _battleCategory; private BattleItemCategory? _battleCategory;
/// <summary>
/// How the item is categorized when in battle.
/// </summary>
public BattleItemCategory BattleCategory => _battleCategory ??= Interface.item_battle_category(Handle); public BattleItemCategory BattleCategory => _battleCategory ??= Interface.item_battle_category(Handle);
private int? _price; private int? _price;
/// <summary>
/// The buying value of the item.
/// </summary>
public int Price => _price ??= Interface.item_price(Handle); public int Price => _price ??= Interface.item_price(Handle);
/// <summary>
/// Checks whether the item has a specific flag.
/// </summary>
public bool HasFlag(string flag) => Interface.item_has_flag(Handle, flag.ToPtr()) == 1; public bool HasFlag(string flag) => Interface.item_has_flag(Handle, flag.ToPtr()) == 1;
} }
} }

View File

@ -3,23 +3,36 @@ using Interface = PkmnLibSharp.FFI.StaticData.LearnableMoves;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// The storage of the moves a Pokemon can learn.
/// </summary>
public class LearnableMoves : HandleType public class LearnableMoves : HandleType
{ {
/// <inheritdoc cref="LearnableMoves"/>
protected LearnableMoves(FFIHandle handle) : base(handle) protected LearnableMoves(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new object to store the moves a Pokemon can learn.
/// </summary>
public static LearnableMoves Create() public static LearnableMoves Create()
{ {
var handle = Interface.learnable_moves_new(); var handle = Interface.learnable_moves_new();
return Resolver.Instance.ResolveLearnableMoves(handle.Resolve()); return Resolver.Instance.ResolveLearnableMoves(handle.Resolve());
} }
/// <summary>
/// Adds a new level move the Pokemon can learn.
/// </summary>
public void AddLevelMove(LevelInt level, string moveName) public void AddLevelMove(LevelInt level, string moveName)
{ {
Interface.learnable_moves_add_level_move(Handle, level, moveName.ToPtr()); Interface.learnable_moves_add_level_move(Handle, level, moveName.ToPtr());
} }
/// <summary>
/// Adds a new level move the Pokemon can learn.
/// </summary>
public void AddLevelMove(LevelInt level, MoveData move) public void AddLevelMove(LevelInt level, MoveData move)
{ {
Interface.learnable_moves_add_level_move(Handle, level, move.Name.ToPtr()); Interface.learnable_moves_add_level_move(Handle, level, move.Name.ToPtr());

View File

@ -1,29 +1,48 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using BackingLevelInt = System.Byte;
// ReSharper disable BuiltInTypeReferenceStyle // ReSharper disable BuiltInTypeReferenceStyle
// The type we store a level in. As our implementation is aimed at normal Pokemon behaviour, a u8
// is probably enough, as we'd go up to 100. If you for some reason want to go higher, you can just
// change this type to hold a higher number.
using BackingLevelInt = System.Byte;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// The data structure used to store a level. This is a struct to allow for easy modification of the data type.
/// </summary>
/// <remarks>
/// If you want to change the type of the level, you can just change the type of <see cref="BackingLevelInt"/>.
/// Most of the implementation below is to allow for easy conversion between the two types, and to allow for
/// using the type as a normal integer.
/// </remarks>
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct LevelInt : IComparable, IComparable<BackingLevelInt>, IComparable<LevelInt>, IConvertible, public struct LevelInt : IComparable, IComparable<BackingLevelInt>, IComparable<LevelInt>, IConvertible,
IEquatable<BackingLevelInt>, IEquatable<LevelInt>, IEquatable<int>, IFormattable IEquatable<BackingLevelInt>, IEquatable<LevelInt>, IEquatable<int>, IFormattable
{ {
[FieldOffset(0)] private BackingLevelInt _value; [FieldOffset(0)] private BackingLevelInt _value;
/// <summary>
/// Converts a <see cref="LevelInt"/> to a <see cref="BackingLevelInt"/>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator BackingLevelInt(LevelInt l) public static implicit operator BackingLevelInt(LevelInt l)
{ {
return l._value; return l._value;
} }
/// <summary>
/// Converts a <see cref="BackingLevelInt"/> to a <see cref="LevelInt"/>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator LevelInt(BackingLevelInt b) public static implicit operator LevelInt(BackingLevelInt b)
{ {
return new LevelInt { _value = b }; return new LevelInt { _value = b };
} }
/// <inheritdoc />
public int CompareTo(object obj) public int CompareTo(object obj)
{ {
if (obj is LevelInt l) if (obj is LevelInt l)
@ -31,89 +50,120 @@ namespace PkmnLibSharp.StaticData
return _value.CompareTo(obj); return _value.CompareTo(obj);
} }
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CompareTo(BackingLevelInt other) => _value.CompareTo(other); public int CompareTo(BackingLevelInt other) => _value.CompareTo(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CompareTo(LevelInt other) => _value.CompareTo(other._value); public int CompareTo(LevelInt other) => _value.CompareTo(other._value);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public TypeCode GetTypeCode() => Type.GetTypeCode(typeof(BackingLevelInt)); public TypeCode GetTypeCode() => Type.GetTypeCode(typeof(BackingLevelInt));
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool ToBoolean(IFormatProvider provider) => ((IConvertible)_value).ToBoolean(provider); public bool ToBoolean(IFormatProvider provider) => ((IConvertible)_value).ToBoolean(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte ToByte(IFormatProvider provider) => ((IConvertible)_value).ToByte(provider); public byte ToByte(IFormatProvider provider) => ((IConvertible)_value).ToByte(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public char ToChar(IFormatProvider provider) => ((IConvertible)_value).ToChar(provider); public char ToChar(IFormatProvider provider) => ((IConvertible)_value).ToChar(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public DateTime ToDateTime(IFormatProvider provider) => ((IConvertible)_value).ToDateTime(provider); public DateTime ToDateTime(IFormatProvider provider) => ((IConvertible)_value).ToDateTime(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public decimal ToDecimal(IFormatProvider provider) => ((IConvertible)_value).ToDecimal(provider); public decimal ToDecimal(IFormatProvider provider) => ((IConvertible)_value).ToDecimal(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public double ToDouble(IFormatProvider provider) => ((IConvertible)_value).ToDouble(provider); public double ToDouble(IFormatProvider provider) => ((IConvertible)_value).ToDouble(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public short ToInt16(IFormatProvider provider) => ((IConvertible)_value).ToInt16(provider); public short ToInt16(IFormatProvider provider) => ((IConvertible)_value).ToInt16(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ToInt32(IFormatProvider provider) => ((IConvertible)_value).ToInt32(provider); public int ToInt32(IFormatProvider provider) => ((IConvertible)_value).ToInt32(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public long ToInt64(IFormatProvider provider) => ((IConvertible)_value).ToInt64(provider); public long ToInt64(IFormatProvider provider) => ((IConvertible)_value).ToInt64(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public sbyte ToSByte(IFormatProvider provider) => ((IConvertible)_value).ToSByte(provider); public sbyte ToSByte(IFormatProvider provider) => ((IConvertible)_value).ToSByte(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public float ToSingle(IFormatProvider provider) => ((IConvertible)_value).ToSingle(provider); public float ToSingle(IFormatProvider provider) => ((IConvertible)_value).ToSingle(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ToString(IFormatProvider provider) => _value.ToString(provider); public string ToString(IFormatProvider provider) => _value.ToString(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public object ToType(Type conversionType, IFormatProvider provider) => public object ToType(Type conversionType, IFormatProvider provider) =>
((IConvertible)_value).ToType(conversionType, provider); ((IConvertible)_value).ToType(conversionType, provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ushort ToUInt16(IFormatProvider provider) => ((IConvertible)_value).ToUInt16(provider); public ushort ToUInt16(IFormatProvider provider) => ((IConvertible)_value).ToUInt16(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint ToUInt32(IFormatProvider provider) => ((IConvertible)_value).ToUInt32(provider); public uint ToUInt32(IFormatProvider provider) => ((IConvertible)_value).ToUInt32(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong ToUInt64(IFormatProvider provider) => ((IConvertible)_value).ToUInt64(provider); public ulong ToUInt64(IFormatProvider provider) => ((IConvertible)_value).ToUInt64(provider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(BackingLevelInt other) => _value == other; public bool Equals(BackingLevelInt other) => _value == other;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ToString(string format, IFormatProvider formatProvider) => public string ToString(string format, IFormatProvider formatProvider) =>
_value.ToString(format, formatProvider); _value.ToString(format, formatProvider);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(LevelInt other) => _value == other._value; public bool Equals(LevelInt other) => _value == other._value;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(int other) => _value == other; public bool Equals(int other) => _value == other;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object? obj) => obj is LevelInt other && Equals(other); public override bool Equals(object? obj) => obj is LevelInt other && Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode()
{ {
return _value.GetHashCode(); return _value.GetHashCode();
} }
/// <summary>
/// Equality operator for <see cref="LevelInt"/>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(LevelInt left, LevelInt right) => left.Equals(right); public static bool operator ==(LevelInt left, LevelInt right) => left.Equals(right);
/// <summary>
/// Inequality operator for <see cref="LevelInt"/>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(LevelInt left, LevelInt right) => !left.Equals(right); public static bool operator !=(LevelInt left, LevelInt right) => !left.Equals(right);
} }

View File

@ -6,12 +6,19 @@ using Interface = PkmnLibSharp.FFI.StaticData.Libraries.AbilityLibrary;
namespace PkmnLibSharp.StaticData.Libraries namespace PkmnLibSharp.StaticData.Libraries
{ {
/// <summary>
/// A storage for all abilities that can be used in this data library.
/// </summary>
public class AbilityLibrary : DataLibrary<Ability> public class AbilityLibrary : DataLibrary<Ability>
{ {
/// <inheritdoc cref="AbilityLibrary"/>
protected AbilityLibrary(FFIHandle handle) : base(handle) protected AbilityLibrary(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new ability library.
/// </summary>
public static AbilityLibrary Create(ulong capacity) public static AbilityLibrary Create(ulong capacity)
{ {
var handle = Interface.ability_library_new(capacity).Resolve(); var handle = Interface.ability_library_new(capacity).Resolve();
@ -20,6 +27,7 @@ namespace PkmnLibSharp.StaticData.Libraries
return self; return self;
} }
/// <inheritdoc />
protected override void AddNative(string key, Ability value) => protected override void AddNative(string key, Ability value) =>
Interface.ability_library_add(Handle, key.ToPtr(), value.Handle); Interface.ability_library_add(Handle, key.ToPtr(), value.Handle);
} }

View File

@ -5,19 +5,30 @@ using PkmnLibSharp.Utils;
namespace PkmnLibSharp.StaticData.Libraries namespace PkmnLibSharp.StaticData.Libraries
{ {
/// <summary>
/// The base backing class for all data libraries.
/// </summary>
/// <typeparam name="T">
/// The type that this data library stores.
/// </typeparam>
public abstract class DataLibrary<T> : HandleType, IReadOnlyDictionary<string, T> where T : HandleType public abstract class DataLibrary<T> : HandleType, IReadOnlyDictionary<string, T> where T : HandleType
{ {
private Dictionary<string, T> _backingDictionary = new(StringComparer.InvariantCultureIgnoreCase); private Dictionary<string, T> _backingDictionary = new(StringComparer.InvariantCultureIgnoreCase);
/// <inheritdoc cref="DataLibrary{T}"/>
protected DataLibrary(FFIHandle handle) : base(handle) protected DataLibrary(FFIHandle handle) : base(handle)
{ {
} }
protected void ReserveCapacity(ulong capacity) /// <summary>
/// Reserves the cache capacity for this data library.
/// </summary>
private protected void ReserveCapacity(ulong capacity)
{ {
_backingDictionary = new Dictionary<string, T>((int)capacity, StringComparer.InvariantCultureIgnoreCase); _backingDictionary = new Dictionary<string, T>((int)capacity, StringComparer.InvariantCultureIgnoreCase);
} }
/// <inheritdoc />
public IEnumerator<KeyValuePair<string, T>> GetEnumerator() public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
{ {
return _backingDictionary.GetEnumerator(); return _backingDictionary.GetEnumerator();
@ -28,22 +39,36 @@ namespace PkmnLibSharp.StaticData.Libraries
return GetEnumerator(); return GetEnumerator();
} }
/// <summary>
/// Calls the native add function for this data library.
/// </summary>
protected abstract void AddNative(string key, T value); protected abstract void AddNative(string key, T value);
/// <summary>
/// Adds a new value to the library.
/// </summary>
public void Add(string key, T value) public void Add(string key, T value)
{ {
AddNative(key, value); AddNative(key, value);
_backingDictionary.Add(key, value); _backingDictionary.Add(key, value);
} }
/// <inheritdoc />
public int Count => _backingDictionary.Count; public int Count => _backingDictionary.Count;
/// <inheritdoc />
public bool ContainsKey(string key) => _backingDictionary.ContainsKey(key); public bool ContainsKey(string key) => _backingDictionary.ContainsKey(key);
/// <inheritdoc />
public bool TryGetValue(string key, out T value) => _backingDictionary.TryGetValue(key, out value); public bool TryGetValue(string key, out T value) => _backingDictionary.TryGetValue(key, out value);
/// <inheritdoc />
public T this[string key] => _backingDictionary[key]; public T this[string key] => _backingDictionary[key];
/// <inheritdoc />
public IEnumerable<string> Keys => _backingDictionary.Keys; public IEnumerable<string> Keys => _backingDictionary.Keys;
/// <inheritdoc />
public IEnumerable<T> Values => _backingDictionary.Values; public IEnumerable<T> Values => _backingDictionary.Values;
} }
} }

View File

@ -6,15 +6,22 @@ using Interface = PkmnLibSharp.FFI.StaticData.Libraries.GrowthRateLibrary;
namespace PkmnLibSharp.StaticData.Libraries namespace PkmnLibSharp.StaticData.Libraries
{ {
/// <summary>
/// A library to store all growth rates.
/// </summary>
public class GrowthRateLibrary : HandleType public class GrowthRateLibrary : HandleType
{ {
// ReSharper disable once CollectionNeverQueried.Local // ReSharper disable once CollectionNeverQueried.Local
private Dictionary<string, GrowthRate> _growthRates = new(); private Dictionary<string, GrowthRate> _growthRates = new();
/// <inheritdoc cref="GrowthRateLibrary"/>
protected GrowthRateLibrary(FFIHandle handle) : base(handle) protected GrowthRateLibrary(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new growth rate library with a capacity.
/// </summary>
public static GrowthRateLibrary Create(ulong capacity) public static GrowthRateLibrary Create(ulong capacity)
{ {
var handle = Interface.growth_rate_library_new(capacity); var handle = Interface.growth_rate_library_new(capacity);
@ -24,16 +31,25 @@ namespace PkmnLibSharp.StaticData.Libraries
return lib; return lib;
} }
/// <summary>
/// Calculates the level for a given growth key name and a certain experience.
/// </summary>
[MustUseReturnValue] [MustUseReturnValue]
public LevelInt CalculateLevel(string name, uint experience) => public LevelInt CalculateLevel(string name, uint experience) =>
Interface.growth_rate_library_calculate_level(Handle, name.ToPtr(), experience).Result(); Interface.growth_rate_library_calculate_level(Handle, name.ToPtr(), experience).Result();
/// <summary>
/// Calculates the experience for a given growth key name and a certain level.
/// </summary>
[MustUseReturnValue] [MustUseReturnValue]
public uint CalculateExperience(string name, LevelInt level) public uint CalculateExperience(string name, LevelInt level)
{ {
return Interface.growth_rate_library_calculate_experience(Handle, name.ToPtr(), level).Result(); return Interface.growth_rate_library_calculate_experience(Handle, name.ToPtr(), level).Result();
} }
/// <summary>
/// Adds a new growth rate with a name and value.
/// </summary>
public void AddGrowthRate(string name, GrowthRate growthRate) public void AddGrowthRate(string name, GrowthRate growthRate)
{ {
Interface.growth_rate_library_add_growth_rate(Handle, name.ToPtr(), growthRate.Handle); Interface.growth_rate_library_add_growth_rate(Handle, name.ToPtr(), growthRate.Handle);

View File

@ -5,10 +5,17 @@ using Interface = PkmnLibSharp.FFI.StaticData.Libraries.ItemLibrary;
namespace PkmnLibSharp.StaticData.Libraries namespace PkmnLibSharp.StaticData.Libraries
{ {
/// <summary>
/// A library to store all items.
/// </summary>
public class ItemLibrary : DataLibrary<Item> public class ItemLibrary : DataLibrary<Item>
{ {
/// <inheritdoc />
protected ItemLibrary(FFIHandle handle) : base(handle){} protected ItemLibrary(FFIHandle handle) : base(handle){}
/// <summary>
/// Instantiates a new Item Library.
/// </summary>
public static ItemLibrary Create(ulong capacity) public static ItemLibrary Create(ulong capacity)
{ {
var handle = Interface.item_library_new(capacity).Resolve(); var handle = Interface.item_library_new(capacity).Resolve();
@ -17,6 +24,7 @@ namespace PkmnLibSharp.StaticData.Libraries
return self; return self;
} }
/// <inheritdoc />
protected override void AddNative(string key, Item value) protected override void AddNative(string key, Item value)
{ {
Interface.item_library_add(Handle, key.ToPtr(), value.Handle); Interface.item_library_add(Handle, key.ToPtr(), value.Handle);

View File

@ -10,6 +10,7 @@ namespace PkmnLibSharp.StaticData.Libraries
/// </summary> /// </summary>
public class LibrarySettings : HandleType public class LibrarySettings : HandleType
{ {
/// <inheritdoc cref="LibrarySettings"/>
protected LibrarySettings(FFIHandle handle) : base(handle) {} protected LibrarySettings(FFIHandle handle) : base(handle) {}
/// <inheritdoc cref="LibrarySettings"/> /// <inheritdoc cref="LibrarySettings"/>

View File

@ -6,18 +6,26 @@ using Interface = PkmnLibSharp.FFI.StaticData.Libraries.MoveLibrary;
namespace PkmnLibSharp.StaticData.Libraries namespace PkmnLibSharp.StaticData.Libraries
{ {
/// <summary>
/// A library to store all data for moves.
/// </summary>
public class MoveLibrary : DataLibrary<MoveData> public class MoveLibrary : DataLibrary<MoveData>
{ {
/// <inheritdoc cref="MoveLibrary"/>
protected MoveLibrary(FFIHandle handle) : base(handle) protected MoveLibrary(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new Move Library.
/// </summary>
public static MoveLibrary Create(ulong capacity) public static MoveLibrary Create(ulong capacity)
{ {
var handle = Interface.move_library_new(capacity); var handle = Interface.move_library_new(capacity);
return Resolver.Instance.ResolveMoveLibrary(handle.Resolve()); return Resolver.Instance.ResolveMoveLibrary(handle.Resolve());
} }
/// <inheritdoc />
protected override void AddNative(string key, MoveData value) protected override void AddNative(string key, MoveData value)
{ {
Interface.move_library_add(Handle, key.ToPtr(), value.Handle); Interface.move_library_add(Handle, key.ToPtr(), value.Handle);

View File

@ -8,14 +8,21 @@ using Interface = PkmnLibSharp.FFI.StaticData.Libraries.NatureLibrary;
namespace PkmnLibSharp.StaticData.Libraries namespace PkmnLibSharp.StaticData.Libraries
{ {
/// <summary>
/// A library of all natures that can be used, stored by their names.
/// </summary>
public class NatureLibrary : HandleType public class NatureLibrary : HandleType
{ {
private Dictionary<string, Nature> _natures = new(); private Dictionary<string, Nature> _natures = new();
/// <inheritdoc cref="NatureLibrary"/>
protected NatureLibrary(FFIHandle handle) : base(handle) protected NatureLibrary(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Creates a new nature library with a given capacity.
/// </summary>
public static NatureLibrary Create(ulong capacity) public static NatureLibrary Create(ulong capacity)
{ {
var handle = Interface.nature_library_new(capacity); var handle = Interface.nature_library_new(capacity);
@ -25,6 +32,9 @@ namespace PkmnLibSharp.StaticData.Libraries
return lib; return lib;
} }
/// <summary>
/// Try to get a nature from the library by its name.
/// </summary>
public bool TryGetNature(string name, [NotNullWhen(true)] out Nature? nature) public bool TryGetNature(string name, [NotNullWhen(true)] out Nature? nature)
{ {
if (_natures.TryGetValue(name, out nature)) if (_natures.TryGetValue(name, out nature))
@ -37,17 +47,29 @@ namespace PkmnLibSharp.StaticData.Libraries
return true; return true;
} }
/// <summary>
/// Gets a random nature.
/// </summary>
/// <param name="seed">
/// The seed to use for the random number generator.
/// </param>
public Nature GetRandomNature(ulong seed) public Nature GetRandomNature(ulong seed)
{ {
return Resolver.Instance.ResolveNature(Interface.nature_library_get_random_nature(Handle, seed).Result().Resolve()); return Resolver.Instance.ResolveNature(Interface.nature_library_get_random_nature(Handle, seed).Result().Resolve());
} }
/// <summary>
/// Gets the name of a nature from its object.
/// </summary>
public string GetNatureName(Nature nature) public string GetNatureName(Nature nature)
{ {
var fd = _natures.FirstOrDefault(x => x.Value == nature); var fd = _natures.FirstOrDefault(x => x.Value == nature);
return fd.Key ?? Interface.nature_library_get_nature_name(Handle, nature.Handle).PtrString()!; return fd.Key ?? Interface.nature_library_get_nature_name(Handle, nature.Handle).PtrString()!;
} }
/// <summary>
/// Adds a new nature with name to the library.
/// </summary>
public void LoadNature(string name, Nature nature) public void LoadNature(string name, Nature nature)
{ {
Interface.nature_library_load_nature(Handle, name.ToPtr(), nature.Handle); Interface.nature_library_load_nature(Handle, name.ToPtr(), nature.Handle);

View File

@ -3,12 +3,19 @@ using Interface = PkmnLibSharp.FFI.StaticData.Libraries.SpeciesLibrary;
namespace PkmnLibSharp.StaticData.Libraries namespace PkmnLibSharp.StaticData.Libraries
{ {
/// <summary>
/// A library to store all data for Pokemon species.
/// </summary>
public class SpeciesLibrary : DataLibrary<Species> public class SpeciesLibrary : DataLibrary<Species>
{ {
/// <inheritdoc cref="SpeciesLibrary"/>
protected SpeciesLibrary(FFIHandle handle) : base(handle) protected SpeciesLibrary(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new Species Library.
/// </summary>
public static SpeciesLibrary Create(ulong capacity) public static SpeciesLibrary Create(ulong capacity)
{ {
var handle = Interface.species_library_new(capacity); var handle = Interface.species_library_new(capacity);
@ -18,6 +25,7 @@ namespace PkmnLibSharp.StaticData.Libraries
return lib; return lib;
} }
/// <inheritdoc />
protected override void AddNative(string key, Species value) protected override void AddNative(string key, Species value)
{ {
Interface.species_library_add(Handle, key.ToPtr(), value.Handle); Interface.species_library_add(Handle, key.ToPtr(), value.Handle);

View File

@ -3,12 +3,19 @@ using Interface = PkmnLibSharp.FFI.StaticData.Libraries.StaticData;
namespace PkmnLibSharp.StaticData.Libraries namespace PkmnLibSharp.StaticData.Libraries
{ {
/// <summary>
/// The storage for all different libraries.
/// </summary>
public class StaticData : HandleType public class StaticData : HandleType
{ {
/// <inheritdoc cref="StaticData"/>
protected StaticData(FFIHandle handle) : base(handle) protected StaticData(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new data collection.
/// </summary>
public static StaticData Create(LibrarySettings settings, SpeciesLibrary speciesLibrary, public static StaticData Create(LibrarySettings settings, SpeciesLibrary speciesLibrary,
MoveLibrary moveLibrary, ItemLibrary itemLibrary, GrowthRateLibrary growthRateLibrary, MoveLibrary moveLibrary, ItemLibrary itemLibrary, GrowthRateLibrary growthRateLibrary,
TypeLibrary typeLibrary, NatureLibrary natureLibrary, AbilityLibrary abilityLibrary) TypeLibrary typeLibrary, NatureLibrary natureLibrary, AbilityLibrary abilityLibrary)
@ -28,13 +35,44 @@ namespace PkmnLibSharp.StaticData.Libraries
return data; return data;
} }
/// <summary>
/// Several misc settings for the library.
/// </summary>
public LibrarySettings LibrarySettings { get; private set; } = null!; public LibrarySettings LibrarySettings { get; private set; } = null!;
/// <summary>
/// All data for Pokemon species.
/// </summary>
public SpeciesLibrary SpeciesLibrary { get; private set; } = null!; public SpeciesLibrary SpeciesLibrary { get; private set; } = null!;
/// <summary>
/// All data for the moves.
/// </summary>
public MoveLibrary MoveLibrary { get; private set; } = null!; public MoveLibrary MoveLibrary { get; private set; } = null!;
/// <summary>
/// All data for the items.
/// </summary>
public ItemLibrary ItemLibrary { get; private set; } = null!; public ItemLibrary ItemLibrary { get; private set; } = null!;
/// <summary>
/// All data for growth rates.
/// </summary>
public GrowthRateLibrary GrowthRateLibrary { get; private set; } = null!; public GrowthRateLibrary GrowthRateLibrary { get; private set; } = null!;
/// <summary>
/// All data related to types and type effectiveness.
/// </summary>
public TypeLibrary TypeLibrary { get; private set; } = null!; public TypeLibrary TypeLibrary { get; private set; } = null!;
/// <summary>
/// All data related to natures.
/// </summary>
public NatureLibrary NatureLibrary { get; private set; } = null!; public NatureLibrary NatureLibrary { get; private set; } = null!;
/// <summary>
/// All data related to abilities.
/// </summary>
public AbilityLibrary AbilityLibrary { get; private set; } = null!; public AbilityLibrary AbilityLibrary { get; private set; } = null!;
} }
} }

View File

@ -7,53 +7,81 @@ using Interface = PkmnLibSharp.FFI.StaticData.Libraries.TypeLibrary;
namespace PkmnLibSharp.StaticData.Libraries namespace PkmnLibSharp.StaticData.Libraries
{ {
/// <summary>
/// All data related to types and effectiveness.
/// </summary>
public class TypeLibrary : HandleType public class TypeLibrary : HandleType
{ {
public Dictionary<string, TypeIdentifier> TypeCache { get; private set; } = private Dictionary<string, TypeIdentifier> _typeCache = new(StringComparer.InvariantCultureIgnoreCase);
new(StringComparer.InvariantCultureIgnoreCase);
/// <inheritdoc cref="TypeLibrary"/>
protected TypeLibrary(FFIHandle handle) : base(handle){} protected TypeLibrary(FFIHandle handle) : base(handle)
{
}
/// <summary>
/// Instantiates a new type library with a specific capacity.
/// </summary>
public static TypeLibrary Create(ulong capacity) public static TypeLibrary Create(ulong capacity)
{ {
var handle = Interface.type_library_new(capacity); var handle = Interface.type_library_new(capacity);
var lib = Resolver.Instance.ResolveTypeLibrary(handle.Resolve()); var lib = Resolver.Instance.ResolveTypeLibrary(handle.Resolve());
lib.TypeCache = new Dictionary<string, TypeIdentifier>((int)capacity, StringComparer.InvariantCultureIgnoreCase); lib._typeCache =
new Dictionary<string, TypeIdentifier>((int)capacity, StringComparer.InvariantCultureIgnoreCase);
return lib; return lib;
} }
/// <summary>
/// Gets the type identifier for a type with a name.
/// </summary>
public TypeIdentifier GetTypeId(string name) public TypeIdentifier GetTypeId(string name)
{ {
if (TypeCache.TryGetValue(name, out var typeIdentifier)) if (_typeCache.TryGetValue(name, out var typeIdentifier))
return typeIdentifier; return typeIdentifier;
throw new KeyNotFoundException($"No type found with name `{name}`"); throw new KeyNotFoundException($"No type found with name `{name}`");
} }
/// <summary>
/// Gets the type name from the type identifier.
/// </summary>
public string GetTypeName(TypeIdentifier typeIdentifier) public string GetTypeName(TypeIdentifier typeIdentifier)
{ {
var fd = TypeCache.FirstOrDefault(x => x.Value == typeIdentifier); var fd = _typeCache.FirstOrDefault(x => x.Value == typeIdentifier);
if (fd.Key != null) if (fd.Key != null)
return fd.Key; return fd.Key;
throw new KeyNotFoundException($"No type found for given identifier"); throw new KeyNotFoundException($"No type found for given identifier");
} }
/// <summary>
/// Gets the effectiveness for a single attacking type against a single defending type.
/// </summary>
public float GetSingleEffectiveness(TypeIdentifier attacking, TypeIdentifier defending) => public float GetSingleEffectiveness(TypeIdentifier attacking, TypeIdentifier defending) =>
Interface.type_library_get_single_effectiveness(Handle, attacking, defending); Interface.type_library_get_single_effectiveness(Handle, attacking, defending);
/// <summary>
/// Gets the effectiveness for a single attacking type against an amount of defending types.
/// This is equivalent to running <see cref="GetSingleEffectiveness"/> on each defending type, and
/// multiplying the results with each other.
/// </summary>
public float GetEffectiveness(TypeIdentifier attacking, TypeIdentifier[] defending) public float GetEffectiveness(TypeIdentifier attacking, TypeIdentifier[] defending)
{ {
var arrayPtr = defending.ArrayPtr(); var arrayPtr = defending.ArrayPtr();
return Interface.type_library_get_effectiveness(Handle, attacking, arrayPtr, (ulong)defending.Length); return Interface.type_library_get_effectiveness(Handle, attacking, arrayPtr, (ulong)defending.Length);
} }
/// <summary>
/// Registers a new type in the library.
/// </summary>
public TypeIdentifier RegisterType(string name) public TypeIdentifier RegisterType(string name)
{ {
var typeId = Interface.type_library_register_type(Handle, name.ToPtr()); var typeId = Interface.type_library_register_type(Handle, name.ToPtr());
TypeCache.Add(name, typeId); _typeCache.Add(name, typeId);
return typeId; return typeId;
} }
/// <summary>
/// Sets the effectiveness for an attacking type against a defending type.
/// </summary>
public void SetEffectiveness(TypeIdentifier attacking, TypeIdentifier defending, float effectiveness) => public void SetEffectiveness(TypeIdentifier attacking, TypeIdentifier defending, float effectiveness) =>
Interface.type_library_set_effectiveness(Handle, attacking, defending, effectiveness); Interface.type_library_set_effectiveness(Handle, attacking, defending, effectiveness);
} }

View File

@ -5,6 +5,9 @@ using Interface = PkmnLibSharp.FFI.StaticData.MoveData;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// The move category defines what global kind of move this move is.
/// </summary>
public enum MoveCategory : byte public enum MoveCategory : byte
{ {
/// A physical move uses the physical attack stats and physical defense stats to calculate damage. /// A physical move uses the physical attack stats and physical defense stats to calculate damage.
@ -17,6 +20,9 @@ namespace PkmnLibSharp.StaticData
Status = 2, Status = 2,
} }
/// <summary>
/// The move target defines what kind of targets the move can touch.
/// </summary>
public enum MoveTarget : byte public enum MoveTarget : byte
{ {
/// Adjacent allows a move to target any Pokemon that is either directly to the left or right of /// Adjacent allows a move to target any Pokemon that is either directly to the left or right of
@ -60,40 +66,87 @@ namespace PkmnLibSharp.StaticData
SelfUse, SelfUse,
} }
/// <summary>
/// A move is the skill Pokémon primarily use in battle. This is the data related to that.
/// </summary>
public class MoveData : HandleType public class MoveData : HandleType
{ {
protected MoveData(FFIHandle handle) : base(handle) {} /// <inheritdoc cref="MoveData"/>
protected MoveData(FFIHandle handle) : base(handle)
public static MoveData Create(string name, TypeIdentifier moveType, MoveCategory category, byte basePower, byte accuracy, {
byte baseUsages, MoveTarget target, sbyte priority, SecondaryEffect? secondaryEffect, }
/// <summary>
/// Instantiates a new move.
/// </summary>
public static MoveData Create(string name, TypeIdentifier moveType, MoveCategory category, byte basePower,
byte accuracy, byte baseUsages, MoveTarget target, sbyte priority, SecondaryEffect? secondaryEffect,
IEnumerable<string> flags) IEnumerable<string> flags)
{ {
var ptrArray = flags.Select(x => x.ToPtr()).ToArray(); var ptrArray = flags.Select(x => x.ToPtr()).ToArray();
var ptrToPtrArray = ptrArray.ArrayPtr(); var ptrToPtrArray = ptrArray.ArrayPtr();
var handle = Interface.move_data_new(name.ToPtr(), moveType, category, basePower, accuracy, baseUsages, target, var handle = Interface.move_data_new(name.ToPtr(), moveType, category, basePower, accuracy, baseUsages,
priority, secondaryEffect?.Handle ?? FFIHandle.Zero, ptrToPtrArray, target, priority, secondaryEffect?.Handle ?? FFIHandle.Zero, ptrToPtrArray, (ulong)ptrArray.Length);
(ulong)ptrArray.Length);
return Resolver.Instance.ResolveMoveData(handle.Result().Resolve()); return Resolver.Instance.ResolveMoveData(handle.Result().Resolve());
} }
private string? _name; private string? _name;
/// <summary>
/// The name of the move.
/// </summary>
public string Name => _name ??= Interface.move_data_name(Handle).Result().PtrString()!; public string Name => _name ??= Interface.move_data_name(Handle).Result().PtrString()!;
private TypeIdentifier? _type; private TypeIdentifier? _type;
/// <summary>
/// The attacking type of the move.
/// </summary>
public TypeIdentifier Type => _type ??= Interface.move_data_move_type(Handle); public TypeIdentifier Type => _type ??= Interface.move_data_move_type(Handle);
private byte? _basePower;
public byte BasePower => _basePower ??= Interface.move_data_base_power(Handle);
private MoveCategory? _category; private MoveCategory? _category;
/// <summary>
/// The category of the move.
/// </summary>
public MoveCategory Category => _category ??= Interface.move_data_category(Handle); public MoveCategory Category => _category ??= Interface.move_data_category(Handle);
private byte? _basePower;
/// <summary>
/// The base power, not considering any modifiers, the move has.
/// </summary>
public byte BasePower => _basePower ??= Interface.move_data_base_power(Handle);
private byte? _accuracy; private byte? _accuracy;
/// <summary>
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
/// </summary>
public byte Accuracy => _accuracy ??= Interface.move_data_accuracy(Handle); public byte Accuracy => _accuracy ??= Interface.move_data_accuracy(Handle);
private byte? _baseUsages; private byte? _baseUsages;
/// <summary>
/// The number of times the move can be used. This can be modified on actually learned moves using
/// PP-Ups
/// </summary>
public byte BaseUsages => _baseUsages ??= Interface.move_data_base_usages(Handle); public byte BaseUsages => _baseUsages ??= Interface.move_data_base_usages(Handle);
private MoveTarget? _target; private MoveTarget? _target;
/// <summary>
/// How the move handles targets.
/// </summary>
public MoveTarget Target => _target ??= Interface.move_data_target(Handle); public MoveTarget Target => _target ??= Interface.move_data_target(Handle);
private sbyte? _priority; private sbyte? _priority;
/// <summary>
/// The priority of the move. A higher priority means the move should go before other moves.
/// </summary>
public sbyte Priority => _priority ??= Interface.move_data_priority(Handle); public sbyte Priority => _priority ??= Interface.move_data_priority(Handle);
private SecondaryEffect? _secondaryEffect; private SecondaryEffect? _secondaryEffect;
/// <summary>
/// The optional secondary effect the move has.
/// </summary>
public SecondaryEffect? SecondaryEffect public SecondaryEffect? SecondaryEffect
{ {
get get
@ -108,6 +161,9 @@ namespace PkmnLibSharp.StaticData
} }
} }
/// <summary>
/// Checks if the move has a specific flag.
/// </summary>
public bool HasFlag(string flag) public bool HasFlag(string flag)
{ {
return Interface.move_data_has_flag(Handle, flag.ToPtr()) == 1; return Interface.move_data_has_flag(Handle, flag.ToPtr()) == 1;

View File

@ -3,36 +3,59 @@ using Interface = PkmnLibSharp.FFI.StaticData.Nature;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// A nature is an attribute on a Pokemon that modifies the effective base stats on a Pokemon. They
/// can have an increased statistic and a decreased statistic, or be neutral.
/// </summary>
public class Nature : HandleType public class Nature : HandleType
{ {
/// <inheritdoc cref="Nature"/>
protected Nature(FFIHandle handle) : base(handle) protected Nature(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new nature.
/// </summary>
public static Nature Create(Statistic increasedStat, Statistic decreasedStat, float increaseModifier = 1.1f, public static Nature Create(Statistic increasedStat, Statistic decreasedStat, float increaseModifier = 1.1f,
float decreaseModifier = 0.9f) float decreaseModifier = 0.9f)
{ {
var handle = Interface.nature_new(increasedStat, decreasedStat, increaseModifier, decreaseModifier); var handle = Interface.nature_new(increasedStat, decreasedStat, increaseModifier, decreaseModifier);
return Resolver.Instance.ResolveNature(handle.Resolve()); return Resolver.Instance.ResolveNature(handle.Resolve());
} }
/// <summary>
/// Instantiates a new nature that does not modify any stats.
/// </summary>
public static Nature NeutralNature() public static Nature NeutralNature()
{ {
return Create(Statistic.HP, Statistic.HP, 1f, 1f); return Create(Statistic.HP, Statistic.HP, 1f, 1f);
} }
private Statistic? _increasedStat; private Statistic? _increasedStat;
/// <summary>
/// The stat that should receive the increased modifier.
/// </summary>
public Statistic IncreasedStat public Statistic IncreasedStat
{ {
get { return _increasedStat ??= Interface.nature_increased_stat(Handle); } get { return _increasedStat ??= Interface.nature_increased_stat(Handle); }
} }
private Statistic? _decreasedStat; private Statistic? _decreasedStat;
/// <summary>
/// The stat that should receive the decreased modifier.
/// </summary>
public Statistic DecreasedStat public Statistic DecreasedStat
{ {
get { return _decreasedStat ??= Interface.nature_decreased_stat(Handle); } get { return _decreasedStat ??= Interface.nature_decreased_stat(Handle); }
} }
/// <summary>
/// Calculates the modifier for a given stat. If it's the increased stat, returns the increased
/// modifier, if it's the decreased stat, returns the decreased modifier. Otherwise returns 1.0
/// </summary>
public float GetStatModifier(Statistic statistic) public float GetStatModifier(Statistic statistic)
{ {
return Interface.nature_get_stat_modifier(Handle, statistic); return Interface.nature_get_stat_modifier(Handle, statistic);

View File

@ -5,12 +5,19 @@ using Interface = PkmnLibSharp.FFI.StaticData.MoveData;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// A secondary effect is an effect on a move that happens after it hits.
/// </summary>
public class SecondaryEffect : HandleType public class SecondaryEffect : HandleType
{ {
/// <inheritdoc cref="SecondaryEffect"/>
protected SecondaryEffect(FFIHandle handle) : base(handle) protected SecondaryEffect(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Instantiates a new Secondary Effect.
/// </summary>
public static SecondaryEffect Create(float chance, string effectName, IReadOnlyList<EffectParameter> parameters) public static SecondaryEffect Create(float chance, string effectName, IReadOnlyList<EffectParameter> parameters)
{ {
var parameterPtrs = parameters.Select(x => (FFIHandleValue)x.Handle).ToArray(); var parameterPtrs = parameters.Select(x => (FFIHandleValue)x.Handle).ToArray();
@ -23,11 +30,20 @@ namespace PkmnLibSharp.StaticData
} }
private float? _chance; private float? _chance;
/// <summary>
/// The chance in percentages that the effect triggers. -1 to make it always trigger.
/// </summary>
public float Chance => _chance ??= Interface.secondary_effect_chance(Handle); public float Chance => _chance ??= Interface.secondary_effect_chance(Handle);
private string? _name; private string? _name;
/// <summary>
/// The name of the effect.
/// </summary>
public string Name => _name ??= Interface.secondary_effect_effect_name(Handle).Result().PtrString()!; public string Name => _name ??= Interface.secondary_effect_effect_name(Handle).Result().PtrString()!;
/// <summary>
/// A list of parameters for the effect.
/// </summary>
public IReadOnlyList<EffectParameter> Parameters { get; private set; } = null!; public IReadOnlyList<EffectParameter> Parameters { get; private set; } = null!;
} }
} }

View File

@ -7,14 +7,21 @@ using Interface = PkmnLibSharp.FFI.StaticData.Species;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// The data belonging to a Pokemon with certain characteristics.
/// </summary>
public class Species : HandleType public class Species : HandleType
{ {
/// <inheritdoc cref="Species"/>
protected Species(FFIHandle handle) : base(handle) protected Species(FFIHandle handle) : base(handle)
{ {
} }
public static Species Create(ushort id, string name, float genderRate, string growthRate, byte captureRate, Form defaultForm, /// <summary>
IReadOnlyCollection<string> flags) /// Creates a new species.
/// </summary>
public static Species Create(ushort id, string name, float genderRate, string growthRate, byte captureRate,
Form defaultForm, IReadOnlyCollection<string> flags)
{ {
var flagsPtrArray = flags.Select(x => x.ToPtr()).ToArray(); var flagsPtrArray = flags.Select(x => x.ToPtr()).ToArray();
var handle = Interface.species_new(id, name.ToPtr(), genderRate, growthRate.ToPtr(), captureRate, var handle = Interface.species_new(id, name.ToPtr(), genderRate, growthRate.ToPtr(), captureRate,
@ -25,16 +32,44 @@ namespace PkmnLibSharp.StaticData
} }
private ushort? _id; private ushort? _id;
/// <summary>
/// The national dex identifier of the Pokemon.
/// </summary>
public ushort Id => _id ??= Interface.species_id(Handle); public ushort Id => _id ??= Interface.species_id(Handle);
private string? _name; private string? _name;
/// <summary>
/// The name of the Pokemon.
/// </summary>
public string Name => _name ??= Interface.species_name(Handle).PtrString()!; public string Name => _name ??= Interface.species_name(Handle).PtrString()!;
private float? _genderRate; private float? _genderRate;
/// <summary>
/// The chance between 0.0 and 1.0 that a Pokemon is female.
/// </summary>
public float GenderRate => _genderRate ??= Interface.species_gender_rate(Handle); public float GenderRate => _genderRate ??= Interface.species_gender_rate(Handle);
private string? _growthRate; private string? _growthRate;
/// <summary>
/// How much experience is required for a level.
/// </summary>
public string GrowthRate => _growthRate ??= Interface.species_growth_rate(Handle).PtrString()!; public string GrowthRate => _growthRate ??= Interface.species_growth_rate(Handle).PtrString()!;
private byte? _captureRate; private byte? _captureRate;
public byte CaptureRate => _captureRate ??= Interface.species_capture_rate(Handle);
/// <summary>
/// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is
/// uncatchable.
/// </summary>
public byte CaptureRate => _captureRate ??= Interface.species_capture_rate(Handle);
/// <summary>
/// Gets the form the Pokemon will have by default, if no other form is specified.
/// </summary>
public Form DefaultForm public Form DefaultForm
{ {
get get
@ -44,7 +79,11 @@ namespace PkmnLibSharp.StaticData
} }
} }
private Dictionary<string, Form> _forms = new(StringComparer.InvariantCultureIgnoreCase); private readonly Dictionary<string, Form> _forms = new(StringComparer.InvariantCultureIgnoreCase);
/// <summary>
/// Gets a form by name.
/// </summary>
public bool TryGetForm(string formName, [NotNullWhen(true)] out Form? form) public bool TryGetForm(string formName, [NotNullWhen(true)] out Form? form)
{ {
if (_forms.TryGetValue(formName, out form)) if (_forms.TryGetValue(formName, out form))
@ -61,12 +100,19 @@ namespace PkmnLibSharp.StaticData
return true; return true;
} }
/// <summary>
/// Adds a new form to the species.
/// </summary>
/// <param name="form"></param>
public void AddForm(Form form) public void AddForm(Form form)
{ {
Interface.species_add_form(Handle, form.Name.ToPtr(), form.Handle).Result(); Interface.species_add_form(Handle, form.Name.ToPtr(), form.Handle).Result();
_forms.Add(form.Name, form); _forms.Add(form.Name, form);
} }
/// <summary>
/// Gets a random gender, returning a value based on the species gender ratio.
/// </summary>
public Gender GetRandomGender(ulong seed) => Interface.species_get_random_gender(Handle, seed); public Gender GetRandomGender(ulong seed) => Interface.species_get_random_gender(Handle, seed);
} }
} }

View File

@ -5,13 +5,24 @@ using Interface = PkmnLibSharp.FFI.StaticData.StaticStatisticSet;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// A collection of statistics that can not be modified after creation.
/// </summary>
/// <typeparam name="T">
/// The integer type that this statistic set will use. This type must be one of the following: ushort
/// </typeparam>
public class StaticStatisticSet<T> : HandleType where T : struct, IConvertible public class StaticStatisticSet<T> : HandleType where T : struct, IConvertible
{ {
/// <inheritdoc cref="StaticStatisticSet{T}"/>
protected StaticStatisticSet(FFIHandle handle) : base(handle) protected StaticStatisticSet(FFIHandle handle) : base(handle)
{ {
} }
public static StaticStatisticSet<T> Create(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed) /// <summary>
/// Create a new static statistic set.
/// </summary>
public static StaticStatisticSet<T> Create(T hp, T attack, T defense, T specialAttack, T specialDefense,
T speed)
{ {
var handle = typeof(T) switch var handle = typeof(T) switch
{ {
@ -23,6 +34,9 @@ namespace PkmnLibSharp.StaticData
return Resolver.Instance.ResolveStaticStatisticSet<T>(handle.Resolve()); return Resolver.Instance.ResolveStaticStatisticSet<T>(handle.Resolve());
} }
/// <summary>
/// Get the value of a specific stat
/// </summary>
[PublicAPI] [PublicAPI]
public T GetStatistic(Statistic statistic) public T GetStatistic(Statistic statistic)
{ {
@ -73,22 +87,45 @@ namespace PkmnLibSharp.StaticData
} }
private T? _hp; private T? _hp;
/// <summary>
/// The health point stat value.
/// </summary>
public T HP => GetStatistic(Statistic.HP); public T HP => GetStatistic(Statistic.HP);
private T? _attack; private T? _attack;
/// <summary>
/// The physical attack stat value.
/// </summary>
public T Attack => GetStatistic(Statistic.Attack); public T Attack => GetStatistic(Statistic.Attack);
private T? _defense; private T? _defense;
/// <summary>
/// The physical defense stat value.
/// </summary>
public T Defense => GetStatistic(Statistic.Defense); public T Defense => GetStatistic(Statistic.Defense);
private T? _specialAttack; private T? _specialAttack;
/// <summary>
/// The special attack stat value.
/// </summary>
public T SpecialAttack => GetStatistic(Statistic.SpecialAttack); public T SpecialAttack => GetStatistic(Statistic.SpecialAttack);
private T? _specialDefense; private T? _specialDefense;
/// <summary>
/// The special defense stat value.
/// </summary>
public T SpecialDefense => GetStatistic(Statistic.SpecialDefense); public T SpecialDefense => GetStatistic(Statistic.SpecialDefense);
private T? _speed; private T? _speed;
/// <summary>
/// The speed stat value.
/// </summary>
public T Speed => GetStatistic(Statistic.Speed); public T Speed => GetStatistic(Statistic.Speed);
} }
} }

View File

@ -1,12 +1,38 @@
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// Stats are numerical values on Pokemon that are used in battle.
/// </summary>
public enum Statistic : byte public enum Statistic : byte
{ {
/// <summary>
/// Health Points determine how much damage a Pokemon can receive before fainting.
/// </summary>
HP = 0, HP = 0,
/// <summary>
/// Attack determines how much damage a Pokemon deals when using a physical attack.
/// </summary>
Attack = 1, Attack = 1,
/// <summary>
/// Defense determines how much damage a Pokemon receives when it is hit by a physical attack.
/// </summary>
Defense = 2, Defense = 2,
/// <summary>
/// Special Attack determines how much damage a Pokemon deals when using a special attack.
/// </summary>
SpecialAttack = 3, SpecialAttack = 3,
/// <summary>
/// Special Defense determines how much damage a Pokemon receives when it is hit by a special attack.
/// </summary>
SpecialDefense = 4, SpecialDefense = 4,
/// <summary>
/// Speed determines the order that a Pokemon can act in battle.
/// </summary>
Speed = 5, Speed = 5,
} }
} }

View File

@ -5,12 +5,23 @@ using Interface = PkmnLibSharp.FFI.StaticData.StatisticSet;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// A collection of every individual stat. This set can hold any value that is valid for its integer
/// type, and can be modified at will.
/// </summary>
/// <typeparam name="T">
/// The integer type that this statistic set will use. This type must be one of the following: byte, sbyte, uint.
/// </typeparam>
public class StatisticSet<T> : HandleType where T : struct, IConvertible public class StatisticSet<T> : HandleType where T : struct, IConvertible
{ {
/// <inheritdoc cref="StatisticSet{T}"/>
protected StatisticSet(FFIHandle handle) : base(handle) protected StatisticSet(FFIHandle handle) : base(handle)
{ {
} }
/// <summary>
/// Creates a new statistic set with given stats.
/// </summary>
public static StatisticSet<T> Create(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed) public static StatisticSet<T> Create(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed)
{ {
var handle = typeof(T) switch var handle = typeof(T) switch
@ -29,6 +40,9 @@ namespace PkmnLibSharp.StaticData
return Resolver.Instance.ResolveStatisticSet<T>(handle.Resolve()); return Resolver.Instance.ResolveStatisticSet<T>(handle.Resolve());
} }
/// <summary>
/// Get the value of a specific stat
/// </summary>
[PublicAPI] [PublicAPI]
public T GetStatistic(Statistic statistic) public T GetStatistic(Statistic statistic)
{ {
@ -42,6 +56,9 @@ namespace PkmnLibSharp.StaticData
return (T)p; return (T)p;
} }
/// <summary>
/// Modify the value of a specific stat.
/// </summary>
[PublicAPI] [PublicAPI]
public void SetStatistic(Statistic statistic, T value) public void SetStatistic(Statistic statistic, T value)
{ {
@ -53,36 +70,54 @@ namespace PkmnLibSharp.StaticData
else throw new ArgumentOutOfRangeException(); else throw new ArgumentOutOfRangeException();
} }
/// <summary>
/// The health point stat value.
/// </summary>
public T HP public T HP
{ {
get => GetStatistic(Statistic.HP); get => GetStatistic(Statistic.HP);
set => SetStatistic(Statistic.HP, value); set => SetStatistic(Statistic.HP, value);
} }
/// <summary>
/// The physical attack stat value.
/// </summary>
public T Attack public T Attack
{ {
get => GetStatistic(Statistic.Attack); get => GetStatistic(Statistic.Attack);
set => SetStatistic(Statistic.Attack, value); set => SetStatistic(Statistic.Attack, value);
} }
/// <summary>
/// The physical defense stat value.
/// </summary>
public T Defense public T Defense
{ {
get => GetStatistic(Statistic.Defense); get => GetStatistic(Statistic.Defense);
set => SetStatistic(Statistic.Defense, value); set => SetStatistic(Statistic.Defense, value);
} }
/// <summary>
/// The special attack stat value.
/// </summary>
public T SpecialAttack public T SpecialAttack
{ {
get => GetStatistic(Statistic.SpecialAttack); get => GetStatistic(Statistic.SpecialAttack);
set => SetStatistic(Statistic.SpecialAttack, value); set => SetStatistic(Statistic.SpecialAttack, value);
} }
/// <summary>
/// The special defense stat value.
/// </summary>
public T SpecialDefense public T SpecialDefense
{ {
get => GetStatistic(Statistic.SpecialDefense); get => GetStatistic(Statistic.SpecialDefense);
set => SetStatistic(Statistic.SpecialDefense, value); set => SetStatistic(Statistic.SpecialDefense, value);
} }
/// <summary>
/// The speed stat value.
/// </summary>
public T Speed public T Speed
{ {
get => GetStatistic(Statistic.Speed); get => GetStatistic(Statistic.Speed);

View File

@ -1,43 +1,61 @@
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace PkmnLibSharp.StaticData namespace PkmnLibSharp.StaticData
{ {
/// <summary>
/// An identifier for a type. This is stored as a single byte internally, but is represented as a struct so that
/// we can use the type system to ensure that we don't accidentally mix up type identifiers with other bytes.
/// </summary>
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public readonly struct TypeIdentifier public readonly struct TypeIdentifier : IEquatable<TypeIdentifier>
{ {
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
[FieldOffset(0)] private readonly byte _identifier; [FieldOffset(0)] private readonly byte _identifier;
/// <summary>
/// Creates a new type identifier.
/// </summary>
public TypeIdentifier(byte b) public TypeIdentifier(byte b)
{ {
_identifier = b; _identifier = b;
} }
/// <inheritdoc />
public bool Equals(TypeIdentifier other) public bool Equals(TypeIdentifier other)
{ {
return _identifier == other._identifier; return _identifier == other._identifier;
} }
/// <inheritdoc />
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
return obj is TypeIdentifier other && Equals(other); return obj is TypeIdentifier other && Equals(other);
} }
/// <inheritdoc />
public override int GetHashCode() public override int GetHashCode()
{ {
return _identifier.GetHashCode(); return _identifier.GetHashCode();
} }
/// <summary>
/// Equality operator for type identifiers.
/// </summary>
public static bool operator ==(TypeIdentifier left, TypeIdentifier right) public static bool operator ==(TypeIdentifier left, TypeIdentifier right)
{ {
return left.Equals(right); return left.Equals(right);
} }
/// <summary>
/// Inequality operator for type identifiers.
/// </summary>
public static bool operator !=(TypeIdentifier left, TypeIdentifier right) public static bool operator !=(TypeIdentifier left, TypeIdentifier right)
{ {
return !left.Equals(right); return !left.Equals(right);
} }
/// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return $"Type({_identifier})"; return $"Type({_identifier})";

View File

@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
namespace PkmnLibSharp.Utils namespace PkmnLibSharp.Utils
{ {
public sealed class CachedExternArray<T> : IReadOnlyList<T> internal sealed class CachedExternArray<T> : IReadOnlyList<T>
where T: class where T: class
{ {
private readonly T?[] _array; private readonly T?[] _array;
@ -50,7 +50,7 @@ namespace PkmnLibSharp.Utils
} }
public class CachedExternValueArray<T> : IReadOnlyList<T> internal class CachedExternValueArray<T> : IReadOnlyList<T>
where T: struct where T: struct
{ {
private readonly T?[] _array; private readonly T?[] _array;

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace PkmnLibSharp.Utils namespace PkmnLibSharp.Utils
{ {
public class ExternValueArray<T> : IReadOnlyList<T> where T : struct internal class ExternValueArray<T> : IReadOnlyList<T>
{ {
private readonly Func<ulong> _getLength; private readonly Func<ulong> _getLength;
private readonly Func<ulong, T> _getItem; private readonly Func<ulong, T> _getItem;

View File

@ -60,6 +60,9 @@ namespace PkmnLibSharp.Utils
} }
} }
/// <summary>
/// A handle to a native object.
/// </summary>
public struct FFIHandle public struct FFIHandle
{ {
internal FFIHandle(ulong handle, FFIHandleReference handleReference) internal FFIHandle(ulong handle, FFIHandleReference handleReference)
@ -68,7 +71,11 @@ namespace PkmnLibSharp.Utils
_handleReference = handleReference; _handleReference = handleReference;
} }
public ulong Handle { get; } internal ulong Handle { get; }
/// <summary>
/// A handle with a value of 0, which is the null handle.
/// </summary>
public static FFIHandle Zero => new(0, null!); public static FFIHandle Zero => new(0, null!);
/// <summary> /// <summary>

View File

@ -1,12 +1,22 @@
using JetBrains.Annotations;
namespace PkmnLibSharp.Utils namespace PkmnLibSharp.Utils
{ {
/// <summary>
/// A basic type that holds a handle to a native object.
/// </summary>
[UsedImplicitly(ImplicitUseTargetFlags.Default | ImplicitUseTargetFlags.WithInheritors)]
public abstract class HandleType public abstract class HandleType
{ {
/// <inheritdoc cref="HandleType"/>
protected internal HandleType(FFIHandle handle) protected internal HandleType(FFIHandle handle)
{ {
Handle = handle; Handle = handle;
} }
/// <summary>
/// The internal handle to the native object.
/// </summary>
protected internal FFIHandle Handle { get; } protected internal FFIHandle Handle { get; }
} }
} }

View File

@ -3,17 +3,31 @@ using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using PkmnLibSharp.DynamicData; using PkmnLibSharp.DynamicData;
using PkmnLibSharp.DynamicData.Libraries; using PkmnLibSharp.DynamicData.Libraries;
using PkmnLibSharp.FFI;
using PkmnLibSharp.StaticData; using PkmnLibSharp.StaticData;
using PkmnLibSharp.StaticData.Libraries; using PkmnLibSharp.StaticData.Libraries;
namespace PkmnLibSharp.Utils namespace PkmnLibSharp.Utils
{ {
/// <summary>
/// This class is used to resolve FFIHandles to their respective classes. We use this so we can handle inheritance
/// in our objects. By overriding a method in this class, we can return a different object than the default throughout
/// the library.
///
/// This class is a singleton, so you can replace the default resolver with your own by setting the Instance property.
/// </summary>
public class Resolver public class Resolver
{ {
/// <summary>
/// The global resolver instance. This is used throughout the library to resolve FFIHandles to their respective
/// classes.
/// </summary>
public static Resolver Instance { get; set; } = new(); public static Resolver Instance { get; set; } = new();
private static readonly Dictionary<FFIHandle, object> Instances = new(); private static readonly Dictionary<FFIHandle, object> Instances = new();
/// <summary>
/// Either returns an existing instance of the given type, or creates a new one and returns it.
/// </summary>
protected static T GetOrCreateInstance<T>(FFIHandle handle) protected static T GetOrCreateInstance<T>(FFIHandle handle)
{ {
if (!Instances.TryGetValue(handle, out var instance)) if (!Instances.TryGetValue(handle, out var instance))
@ -28,79 +42,177 @@ namespace PkmnLibSharp.Utils
return (T)instance!; return (T)instance!;
} }
/// <summary>
/// Resolve an effect parameter from the given handle.
/// </summary>
public virtual EffectParameter ResolveEffectParameter(FFIHandle handle) => public virtual EffectParameter ResolveEffectParameter(FFIHandle handle) =>
GetOrCreateInstance<EffectParameter>(handle); GetOrCreateInstance<EffectParameter>(handle);
/// <summary>
/// Resolve a move effect from the given handle.
/// </summary>
public virtual Ability ResolveAbility(FFIHandle handle) => GetOrCreateInstance<Ability>(handle); public virtual Ability ResolveAbility(FFIHandle handle) => GetOrCreateInstance<Ability>(handle);
/// <summary>
/// Resolve a form from the given handle.
/// </summary>
public virtual Form ResolveForm(FFIHandle handle) => GetOrCreateInstance<Form>(handle); public virtual Form ResolveForm(FFIHandle handle) => GetOrCreateInstance<Form>(handle);
/// <summary>
/// Resolve a static statistic set from the given handle.
/// </summary>
public virtual StaticStatisticSet<T> ResolveStaticStatisticSet<T>(FFIHandle handle) public virtual StaticStatisticSet<T> ResolveStaticStatisticSet<T>(FFIHandle handle)
where T : struct, IConvertible => where T : struct, IConvertible =>
GetOrCreateInstance<StaticStatisticSet<T>>(handle); GetOrCreateInstance<StaticStatisticSet<T>>(handle);
/// <summary>
/// Resolve a statistic set from the given handle.
/// </summary>
public virtual StatisticSet<T> ResolveStatisticSet<T>(FFIHandle handle) where T : struct, IConvertible => public virtual StatisticSet<T> ResolveStatisticSet<T>(FFIHandle handle) where T : struct, IConvertible =>
GetOrCreateInstance<StatisticSet<T>>(handle); GetOrCreateInstance<StatisticSet<T>>(handle);
/// <summary>
/// Resolve a learnable moves object from the given handle.
/// </summary>
public virtual LearnableMoves ResolveLearnableMoves(FFIHandle handle) => public virtual LearnableMoves ResolveLearnableMoves(FFIHandle handle) =>
GetOrCreateInstance<LearnableMoves>(handle); GetOrCreateInstance<LearnableMoves>(handle);
/// <summary>
/// Resolve an item object from the given handle.
/// </summary>
public virtual Item ResolveItem(FFIHandle handle) => GetOrCreateInstance<Item>(handle); public virtual Item ResolveItem(FFIHandle handle) => GetOrCreateInstance<Item>(handle);
/// <summary>
/// Resolve a secondary effect object from the given handle.
/// </summary>
public virtual SecondaryEffect ResolveSecondaryEffect(FFIHandle handle) => public virtual SecondaryEffect ResolveSecondaryEffect(FFIHandle handle) =>
GetOrCreateInstance<SecondaryEffect>(handle); GetOrCreateInstance<SecondaryEffect>(handle);
/// <summary>
/// Resolve a move data object from the given handle.
/// </summary>
public virtual MoveData ResolveMoveData(FFIHandle handle) => GetOrCreateInstance<MoveData>(handle); public virtual MoveData ResolveMoveData(FFIHandle handle) => GetOrCreateInstance<MoveData>(handle);
/// <summary>
/// Resolve an nature from the given handle.
/// </summary>
public virtual Nature ResolveNature(FFIHandle handle) => GetOrCreateInstance<Nature>(handle); public virtual Nature ResolveNature(FFIHandle handle) => GetOrCreateInstance<Nature>(handle);
/// <summary>
/// Resolve a species object from the given handle.
/// </summary>
public virtual Species ResolveSpecies(FFIHandle handle) => GetOrCreateInstance<Species>(handle); public virtual Species ResolveSpecies(FFIHandle handle) => GetOrCreateInstance<Species>(handle);
public virtual AbilityLibrary ResolveAbilityLibrary(FFIHandle handle) => /// <summary>
GetOrCreateInstance<AbilityLibrary>(handle); /// Resolve a growthrate object from the given handle.
/// </summary>
public virtual ItemLibrary ResolveItemLibrary(FFIHandle handle) => GetOrCreateInstance<ItemLibrary>(handle);
public virtual LookupGrowthRate ResolveLookupGrowthRate(FFIHandle ptr) => public virtual LookupGrowthRate ResolveLookupGrowthRate(FFIHandle ptr) =>
GetOrCreateInstance<LookupGrowthRate>(ptr); GetOrCreateInstance<LookupGrowthRate>(ptr);
/// <summary>
/// Resolve an ability library object from the given handle.
/// </summary>
public virtual AbilityLibrary ResolveAbilityLibrary(FFIHandle handle) =>
GetOrCreateInstance<AbilityLibrary>(handle);
/// <summary>
/// Resolve an item library object from the given handle.
/// </summary>
public virtual ItemLibrary ResolveItemLibrary(FFIHandle handle) => GetOrCreateInstance<ItemLibrary>(handle);
/// <summary>
/// Resolve a growthrate library object from the given handle.
/// </summary>
public virtual GrowthRateLibrary ResolveGrowthRateLibrary(FFIHandle handle) => public virtual GrowthRateLibrary ResolveGrowthRateLibrary(FFIHandle handle) =>
GetOrCreateInstance<GrowthRateLibrary>(handle); GetOrCreateInstance<GrowthRateLibrary>(handle);
/// <summary>
/// Resolve a move library object from the given handle.
/// </summary>
public virtual MoveLibrary ResolveMoveLibrary(FFIHandle handle) => GetOrCreateInstance<MoveLibrary>(handle); public virtual MoveLibrary ResolveMoveLibrary(FFIHandle handle) => GetOrCreateInstance<MoveLibrary>(handle);
/// <summary>
/// Resolve a nature library object from the given handle.
/// </summary>
public virtual NatureLibrary ResolveNatureLibrary(FFIHandle handle) => public virtual NatureLibrary ResolveNatureLibrary(FFIHandle handle) =>
GetOrCreateInstance<NatureLibrary>(handle); GetOrCreateInstance<NatureLibrary>(handle);
/// <summary>
/// Resolve a species library object from the given handle.
/// </summary>
public virtual SpeciesLibrary ResolveSpeciesLibrary(FFIHandle handle) => public virtual SpeciesLibrary ResolveSpeciesLibrary(FFIHandle handle) =>
GetOrCreateInstance<SpeciesLibrary>(handle); GetOrCreateInstance<SpeciesLibrary>(handle);
/// <summary>
/// Resolve a library settings object from the given handle.
/// </summary>
public virtual LibrarySettings ResolveLibrarySettings(FFIHandle handle) => public virtual LibrarySettings ResolveLibrarySettings(FFIHandle handle) =>
GetOrCreateInstance<LibrarySettings>(handle); GetOrCreateInstance<LibrarySettings>(handle);
/// <summary>
/// Resolve a type library object from the given handle.
/// </summary>
public virtual TypeLibrary ResolveTypeLibrary(FFIHandle handle) => GetOrCreateInstance<TypeLibrary>(handle); public virtual TypeLibrary ResolveTypeLibrary(FFIHandle handle) => GetOrCreateInstance<TypeLibrary>(handle);
/// <summary>
/// Resolve a static data object from the given handle.
/// </summary>
public virtual StaticData.Libraries.StaticData ResolveStaticData(FFIHandle handle) => public virtual StaticData.Libraries.StaticData ResolveStaticData(FFIHandle handle) =>
GetOrCreateInstance<StaticData.Libraries.StaticData>(handle); GetOrCreateInstance<StaticData.Libraries.StaticData>(handle);
/// <summary>
/// Resolve a learned move object from the given handle.
/// </summary>
public virtual LearnedMove ResolveLearnedMove(FFIHandle resolve) => GetOrCreateInstance<LearnedMove>(resolve); public virtual LearnedMove ResolveLearnedMove(FFIHandle resolve) => GetOrCreateInstance<LearnedMove>(resolve);
public virtual Gen7BattleStatCalculator ResolveGen7BattleStatCalculator(FFIHandle handle) => /// <summary>
/// Resolve a battle stat calculator object from the given handle.
/// </summary>
public virtual BattleStatCalculator ResolveBattleStatCalculator(FFIHandle handle) =>
GetOrCreateInstance<Gen7BattleStatCalculator>(handle); GetOrCreateInstance<Gen7BattleStatCalculator>(handle);
public virtual Gen7DamageLibrary ResolveGen7DamageLibrary(FFIHandle handle) => /// <summary>
/// Resolve a damage library object from the given handle.
/// </summary>
public virtual DamageLibrary ResolveDamageLibrary(FFIHandle handle) =>
GetOrCreateInstance<Gen7DamageLibrary>(handle); GetOrCreateInstance<Gen7DamageLibrary>(handle);
public virtual Gen7MiscLibrary ResolveGen7MiscLibrary(FFIHandle handle) => /// <summary>
GetOrCreateInstance<Gen7MiscLibrary>(handle); /// Resolve a misc library object from the given handle.
/// </summary>
public virtual MiscLibrary ResolveMiscLibrary(FFIHandle handle) => GetOrCreateInstance<Gen7MiscLibrary>(handle);
/// <summary>
/// Resolve an empty script resolver object from the given handle.
/// </summary>
public virtual EmptyScriptResolver ResolveEmptyScriptResolver(FFIHandle handle) => public virtual EmptyScriptResolver ResolveEmptyScriptResolver(FFIHandle handle) =>
GetOrCreateInstance<EmptyScriptResolver>(handle); GetOrCreateInstance<EmptyScriptResolver>(handle);
/// <summary>
/// Resolve a script resolver object from the given handle.
/// </summary>
#if WASM #if WASM
public virtual WasmScriptResolver ResolveWasmScriptResolver(FFIHandle handle) => public virtual ScriptResolver ResolveScriptResolver(FFIHandle handle) =>
GetOrCreateInstance<WasmScriptResolver>(handle); GetOrCreateInstance<WasmScriptResolver>(handle);
#else
public virtual ScriptResolver ResolveScriptResolver(FFIHandle handle) => ResolveEmptyScriptResolver(handle);
#endif #endif
public DynamicLibrary ResolveDynamicLibrary(FFIHandle resolve) => GetOrCreateInstance<DynamicLibrary>(resolve);
/// <summary>
/// Resolve a dynamic library object from the given handle.
/// </summary>
public virtual DynamicLibrary ResolveDynamicLibrary(FFIHandle resolve) =>
GetOrCreateInstance<DynamicLibrary>(resolve);
public Pokemon ResolvePokemon(FFIHandle resolve) => GetOrCreateInstance<Pokemon>(resolve); /// <summary>
/// Resolve a pokemon object from the given handle.
/// </summary>
public virtual Pokemon ResolvePokemon(FFIHandle resolve) => GetOrCreateInstance<Pokemon>(resolve);
/// <summary>
/// Resolve a pokemon party object from the given handle.
/// </summary>
public virtual PokemonParty ResolvePokemonParty(FFIHandle resolve) =>
GetOrCreateInstance<PokemonParty>(resolve);
} }
} }

BIN
PkmnLibRSharp/libpkmn_lib.so (Stored with Git LFS)

Binary file not shown.

View File

@ -72,7 +72,7 @@ namespace PkmnLibRSharpTests.DynamicData
{ {
var library = GetLibrary(); var library = GetLibrary();
var pokemon = new PokemonBuilder(library, "testSpecies", 100).WithIdentifier(1000).Build(); var pokemon = new PokemonBuilder(library, "testSpecies", 100).WithIdentifier(1000).Build();
Assert.AreEqual(1000, pokemon.UniqueIdentifier); Assert.AreEqual(1000, pokemon.PersonalityValue);
} }
[Test] [Test]