diff --git a/PkmnLib.Dynamic/AI/PokemonAI.cs b/PkmnLib.Dynamic/AI/PokemonAI.cs index 40e5f09..fcf6805 100644 --- a/PkmnLib.Dynamic/AI/PokemonAI.cs +++ b/PkmnLib.Dynamic/AI/PokemonAI.cs @@ -1,3 +1,4 @@ +using JetBrains.Annotations; using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.Models.Choices; using PkmnLib.Static.Moves; @@ -8,12 +9,13 @@ namespace PkmnLib.Dynamic.AI; /// /// The base class for implementing an AI for Pokémon. /// +[PublicAPI] public abstract class PokemonAI { /// /// The name of the AI. /// - public StringKey Name { get; set; } + public StringKey Name { get; } /// protected PokemonAI(StringKey name) @@ -26,9 +28,11 @@ public abstract class PokemonAI /// public abstract ITurnChoice GetChoice(IBattle battle, IPokemon pokemon); + /// + /// For a given user and move, returns the valid targets for that move. + /// public IEnumerable<(byte side, byte position)> GetValidTargetsForMove(IPokemon user, ILearnedMove move) { - byte GetOppositeSide(byte side) => side == 0 ? (byte)1 : (byte)0; var userBattleData = user.BattleData!; switch (move.MoveData.Target) { @@ -90,5 +94,7 @@ public abstract class PokemonAI default: throw new ArgumentOutOfRangeException(); } + yield break; + byte GetOppositeSide(byte side) => side == 0 ? (byte)1 : (byte)0; } } \ No newline at end of file diff --git a/PkmnLib.Dynamic/Events/CaptureAttemptEvent.cs b/PkmnLib.Dynamic/Events/CaptureAttemptEvent.cs index 3ceae0a..6ef8d64 100644 --- a/PkmnLib.Dynamic/Events/CaptureAttemptEvent.cs +++ b/PkmnLib.Dynamic/Events/CaptureAttemptEvent.cs @@ -3,15 +3,26 @@ using PkmnLib.Dynamic.Models; namespace PkmnLib.Dynamic.Events; +/// +/// Represents an event that occurs when a Pokémon capture attempt is made. +/// public class CaptureAttemptEvent : IEventData { + /// public CaptureAttemptEvent(IPokemon target, CaptureResult result) { Target = target; Result = result; } + /// + /// The Pokémon that is being captured. + /// public IPokemon Target { get; init; } + + /// + /// The result of the capture attempt. + /// public CaptureResult Result { get; init; } /// diff --git a/PkmnLib.Dynamic/Events/DialogEvent.cs b/PkmnLib.Dynamic/Events/DialogEvent.cs index 7633f9a..fe3fcc8 100644 --- a/PkmnLib.Dynamic/Events/DialogEvent.cs +++ b/PkmnLib.Dynamic/Events/DialogEvent.cs @@ -1,17 +1,27 @@ namespace PkmnLib.Dynamic.Events; +/// +/// Represents an event that occurs when a dialog is displayed. +/// public class DialogEvent : IEventData { /// public EventBatchId BatchId { get; init; } = new(); + /// public DialogEvent(string message, Dictionary? parameters = null) { Message = message; Parameters = parameters; } + /// + /// The message to be displayed in the dialog. This is generally a key that needs to be localized. + /// public string Message { get; set; } + /// + /// Optional parameters that can be used to format the message in a localized string. + /// public Dictionary? Parameters { get; set; } } \ No newline at end of file diff --git a/PkmnLib.Dynamic/Events/ExperienceGainEvent.cs b/PkmnLib.Dynamic/Events/ExperienceGainEvent.cs index 7094430..09e2b77 100644 --- a/PkmnLib.Dynamic/Events/ExperienceGainEvent.cs +++ b/PkmnLib.Dynamic/Events/ExperienceGainEvent.cs @@ -2,8 +2,12 @@ using PkmnLib.Dynamic.Models; namespace PkmnLib.Dynamic.Events; +/// +/// Represents an event that occurs when a Pokémon gains experience. +/// public class ExperienceGainEvent : IEventData { + /// public ExperienceGainEvent(IPokemon pokemon, uint previousExperience, uint newExperience) { Pokemon = pokemon; @@ -11,8 +15,19 @@ public class ExperienceGainEvent : IEventData NewExperience = newExperience; } + /// + /// The Pokémon that gained experience. + /// public IPokemon Pokemon { get; set; } + + /// + /// The amount of experience the Pokémon had before the gain. + /// public uint PreviousExperience { get; } + + /// + /// The amount of experience the Pokémon has after the gain. + /// public uint NewExperience { get; } /// diff --git a/PkmnLib.Dynamic/Events/FormChangeEvent.cs b/PkmnLib.Dynamic/Events/FormChangeEvent.cs index bd90f0b..f11dddb 100644 --- a/PkmnLib.Dynamic/Events/FormChangeEvent.cs +++ b/PkmnLib.Dynamic/Events/FormChangeEvent.cs @@ -3,11 +3,22 @@ using PkmnLib.Static.Species; namespace PkmnLib.Dynamic.Events; +/// +/// Represents an event that occurs when a Pokémon changes its form. +/// public class FormChangeEvent : IEventData { + /// + /// The Pokémon that changed its form. + /// public IPokemon Pokemon { get; } + + /// + /// The new form of the Pokémon. + /// public IForm Form { get; } + /// public FormChangeEvent(IPokemon pokemon, IForm form) { Pokemon = pokemon; diff --git a/PkmnLib.Dynamic/Events/Handling/EventBatchId.cs b/PkmnLib.Dynamic/Events/Handling/EventBatchId.cs index ceb6b7c..22b9a41 100644 --- a/PkmnLib.Dynamic/Events/Handling/EventBatchId.cs +++ b/PkmnLib.Dynamic/Events/Handling/EventBatchId.cs @@ -10,6 +10,7 @@ namespace PkmnLib.Dynamic.Events; /// public readonly record struct EventBatchId { + /// public EventBatchId() { Id = Guid.NewGuid(); diff --git a/PkmnLib.Dynamic/Events/Handling/EventData.cs b/PkmnLib.Dynamic/Events/Handling/EventData.cs index 76ca0c0..4062393 100644 --- a/PkmnLib.Dynamic/Events/Handling/EventData.cs +++ b/PkmnLib.Dynamic/Events/Handling/EventData.cs @@ -1,3 +1,5 @@ +using JetBrains.Annotations; + namespace PkmnLib.Dynamic.Events; /// @@ -5,6 +7,7 @@ namespace PkmnLib.Dynamic.Events; /// display information about the battle to the user. This is the only way for the front-end to /// know what is happening in the battle. /// +[PublicAPI] public interface IEventData { /// diff --git a/PkmnLib.Dynamic/Events/LevelUpEvent.cs b/PkmnLib.Dynamic/Events/LevelUpEvent.cs index 62e6267..0106ff6 100644 --- a/PkmnLib.Dynamic/Events/LevelUpEvent.cs +++ b/PkmnLib.Dynamic/Events/LevelUpEvent.cs @@ -2,8 +2,12 @@ using PkmnLib.Dynamic.Models; namespace PkmnLib.Dynamic.Events; +/// +/// Represents an event that occurs when a Pokémon gains enough experience points to level up. +/// public class LevelUpEvent : IEventData { + /// public LevelUpEvent(IPokemon pokemon, int previousLevel, int newLevel) { Pokemon = pokemon; @@ -11,10 +15,19 @@ public class LevelUpEvent : IEventData NewLevel = newLevel; } + /// + /// The new level of the Pokémon after leveling up. + /// public int NewLevel { get; set; } + /// + /// The previous level of the Pokémon before leveling up. + /// public int PreviousLevel { get; set; } + /// + /// The Pokémon that leveled up. + /// public IPokemon Pokemon { get; set; } /// diff --git a/PkmnLib.Dynamic/Events/SpeciesChangeEvent.cs b/PkmnLib.Dynamic/Events/SpeciesChangeEvent.cs index 4307cbf..504a17e 100644 --- a/PkmnLib.Dynamic/Events/SpeciesChangeEvent.cs +++ b/PkmnLib.Dynamic/Events/SpeciesChangeEvent.cs @@ -3,12 +3,27 @@ using PkmnLib.Static.Species; namespace PkmnLib.Dynamic.Events; +/// +/// Represents an event that occurs when a Pokémon changes to a different species. +/// public class SpeciesChangeEvent : IEventData { + /// + /// The Pokémon that changed species. + /// public IPokemon Pokemon { get; } + + /// + /// The new species of the Pokémon. + /// public ISpecies Species { get; } + + /// + /// The new form of the Pokémon, if applicable. + /// public IForm Form { get; } + /// public SpeciesChangeEvent(IPokemon pokemon, ISpecies species, IForm form) { Pokemon = pokemon; diff --git a/PkmnLib.Dynamic/Libraries/CaptureLibrary.cs b/PkmnLib.Dynamic/Libraries/CaptureLibrary.cs index fcb045d..c575899 100644 --- a/PkmnLib.Dynamic/Libraries/CaptureLibrary.cs +++ b/PkmnLib.Dynamic/Libraries/CaptureLibrary.cs @@ -3,8 +3,12 @@ using PkmnLib.Static; namespace PkmnLib.Dynamic.Libraries; +/// +/// Represents the result of a capture attempt. +/// public record struct CaptureResult { + /// public CaptureResult(bool IsCaught, int Shakes, bool CriticalCapture) { this.IsCaught = IsCaught; @@ -12,14 +16,35 @@ public record struct CaptureResult this.CriticalCapture = CriticalCapture; } + /// + /// Indicates whether the capture was successful. + /// public bool IsCaught { get; init; } + + /// + /// The number of shakes the Poké Ball made before the capture attempt was successful or failed. + /// public int Shakes { get; init; } + + /// + /// Indicates whether a critical capture occurred. A critical capture is a special case where the Poké Ball + /// shakes only once and then captures the Pokémon. + /// public bool CriticalCapture { get; init; } + /// + /// Creates a indicating a failed capture attempt. + /// public static CaptureResult Failed => new(false, 0, false); } +/// +/// Interface for a library that handles Pokémon capture mechanics. +/// public interface ICaptureLibrary { + /// + /// Attempts to capture a Pokémon using a specified item (e.g., Poké Ball). + /// CaptureResult TryCapture(IPokemon target, IItem captureItem, IBattleRandom random); } \ No newline at end of file diff --git a/PkmnLib.Dynamic/Libraries/MiscLibrary.cs b/PkmnLib.Dynamic/Libraries/MiscLibrary.cs index 7549d4b..aa433f1 100644 --- a/PkmnLib.Dynamic/Libraries/MiscLibrary.cs +++ b/PkmnLib.Dynamic/Libraries/MiscLibrary.cs @@ -20,5 +20,8 @@ public interface IMiscLibrary /// TimeOfDay GetTimeOfDay(); + /// + /// Returns whether the given Pokemon can flee from the battle. + /// bool CanFlee(IBattle battle, IFleeChoice fleeChoice); } \ No newline at end of file diff --git a/PkmnLib.Dynamic/Models/Battle.cs b/PkmnLib.Dynamic/Models/Battle.cs index ba7db5a..bfc83a6 100644 --- a/PkmnLib.Dynamic/Models/Battle.cs +++ b/PkmnLib.Dynamic/Models/Battle.cs @@ -93,6 +93,10 @@ public interface IBattle : IScriptSource, IDeepCloneable /// void ValidateBattleState(); + /// + /// Checks whether a Pokemon has a forced turn choice. If it does, this returns true and the choice + /// is set in the out parameter. If it does not, this returns false and the out parameter is null. + /// bool HasForcedTurn(IPokemon pokemon, [NotNullWhen(true)] out ITurnChoice? choice); /// @@ -117,6 +121,9 @@ public interface IBattle : IScriptSource, IDeepCloneable /// bool SetWeather(StringKey? weatherName, int duration); + /// + /// Volatile scripts are scripts that are not permanent and can be removed by other scripts. + /// public IScriptSet Volatile { get; } /// @@ -124,8 +131,15 @@ public interface IBattle : IScriptSource, IDeepCloneable /// StringKey? WeatherName { get; } + /// + /// Sets the current terrain for the battle. If null is passed, this clears the terrain. + /// + /// void SetTerrain(StringKey? terrainName); + /// + /// Gets the current terrain of the battle. If no terrain is present, this returns null. + /// StringKey? TerrainName { get; } /// @@ -134,6 +148,9 @@ public interface IBattle : IScriptSource, IDeepCloneable /// IReadOnlyList> PreviousTurnChoices { get; } + /// + /// Attempts to capture a Pokemon. This will use the current RNG to determine whether the capture is successful. + /// CaptureResult AttempCapture(byte sideIndex, byte position, IItem item); } @@ -350,7 +367,11 @@ public class BattleImpl : ScriptSource, IBattle EventHook.Invoke(new EndTurnEvent()); } - private ScriptContainer _weatherScript = new(); + private readonly ScriptContainer _weatherScript = new(); + + /// + /// The script that handles the current weather of the battle. + /// public IReadOnlyScriptContainer WeatherScript => _weatherScript; /// @@ -377,6 +398,7 @@ public class BattleImpl : ScriptSource, IBattle // TODO: Trigger weather change script hooks } + /// public IScriptSet Volatile { get; } = new ScriptSet(); /// diff --git a/PkmnLib.Dynamic/Models/BattleChoiceQueue.cs b/PkmnLib.Dynamic/Models/BattleChoiceQueue.cs index 7ea9b9f..bdbf276 100644 --- a/PkmnLib.Dynamic/Models/BattleChoiceQueue.cs +++ b/PkmnLib.Dynamic/Models/BattleChoiceQueue.cs @@ -16,6 +16,10 @@ public class BattleChoiceQueue : IDeepCloneable { private readonly ITurnChoice?[] _choices; private int _currentIndex; + + /// + /// Returns the last choice that was executed. + /// public ITurnChoice? LastRanChoice { get; private set; } /// @@ -122,9 +126,15 @@ public class BattleChoiceQueue : IDeepCloneable internal IReadOnlyList GetChoices() => _choices; + /// + /// This returns the first choice that matches the predicate, or null if none was found. + /// public ITurnChoice? FirstOrDefault(Func predicate) => _choices.Skip(_currentIndex).WhereNotNull().FirstOrDefault(predicate); + /// + /// Removes a choice from the queue. + /// public void Remove(ITurnChoice choice) { var index = Array.FindIndex(_choices, _currentIndex, x => x == choice); diff --git a/PkmnLib.Dynamic/Models/BattleRandom.cs b/PkmnLib.Dynamic/Models/BattleRandom.cs index ff7cca7..c1c840c 100644 --- a/PkmnLib.Dynamic/Models/BattleRandom.cs +++ b/PkmnLib.Dynamic/Models/BattleRandom.cs @@ -19,10 +19,18 @@ public interface IBattleRandom : IRandom, IDeepCloneable /// public class BattleRandomImpl : RandomImpl, IBattleRandom { + /// + /// + /// This constructor is used to instantiate the class when no seed is provided. It uses a time-dependent default seed value. + /// public BattleRandomImpl() { } + /// + /// + /// This constructor is used to instantiate the class with a specific seed value. + /// public BattleRandomImpl(int seed) : base(seed) { } diff --git a/PkmnLib.Dynamic/Models/BattleSide.cs b/PkmnLib.Dynamic/Models/BattleSide.cs index a3365b1..d975487 100644 --- a/PkmnLib.Dynamic/Models/BattleSide.cs +++ b/PkmnLib.Dynamic/Models/BattleSide.cs @@ -142,9 +142,19 @@ public interface IBattleSide : IScriptSource, IDeepCloneable /// IItem? GetLastConsumedItem(byte battleDataPosition); + /// + /// Marks a Pokémon as fainted. This is used to track the last turn a Pokémon in a position fainted. + /// void MarkFaint(byte position); + /// + /// Gets the last turn a Pokémon in a specific position fainted. + /// uint? GetLastFaintTurn(byte position); + + /// + /// Gets the last turn a Pokémon in any position fainted. + /// uint? GetLastFaintTurn(); } diff --git a/PkmnLib.Dynamic/Models/Choices/ItemChoice.cs b/PkmnLib.Dynamic/Models/Choices/ItemChoice.cs index e7634e5..e4ff6da 100644 --- a/PkmnLib.Dynamic/Models/Choices/ItemChoice.cs +++ b/PkmnLib.Dynamic/Models/Choices/ItemChoice.cs @@ -27,6 +27,7 @@ public interface IItemChoice : ITurnChoice /// public class ItemChoice : TurnChoice, IItemChoice { + /// public ItemChoice(IPokemon user, IItem item, byte? targetSide, byte? targetPosition) : base(user) { Item = item; @@ -34,6 +35,9 @@ public class ItemChoice : TurnChoice, IItemChoice TargetPosition = targetPosition; } + /// + /// The item that is used. + /// public IItem Item { get; } /// diff --git a/PkmnLib.Dynamic/Models/Choices/PassChoice.cs b/PkmnLib.Dynamic/Models/Choices/PassChoice.cs index ec99f0c..5290fd3 100644 --- a/PkmnLib.Dynamic/Models/Choices/PassChoice.cs +++ b/PkmnLib.Dynamic/Models/Choices/PassChoice.cs @@ -9,8 +9,10 @@ public interface IPassChoice : ITurnChoice { } +/// public class PassChoice : TurnChoice, IPassChoice { + /// public PassChoice(IPokemon user) : base(user) { } diff --git a/PkmnLib.Dynamic/Models/Choices/SwitchChoice.cs b/PkmnLib.Dynamic/Models/Choices/SwitchChoice.cs index 02bfdad..538aaf0 100644 --- a/PkmnLib.Dynamic/Models/Choices/SwitchChoice.cs +++ b/PkmnLib.Dynamic/Models/Choices/SwitchChoice.cs @@ -16,6 +16,7 @@ public interface ISwitchChoice : ITurnChoice /// public class SwitchChoice : TurnChoice, ISwitchChoice { + /// public SwitchChoice(IPokemon user, IPokemon switchTo) : base(user) { SwitchTo = switchTo; diff --git a/PkmnLib.Dynamic/Models/ExecutingMove.cs b/PkmnLib.Dynamic/Models/ExecutingMove.cs index e440021..757bb03 100644 --- a/PkmnLib.Dynamic/Models/ExecutingMove.cs +++ b/PkmnLib.Dynamic/Models/ExecutingMove.cs @@ -140,8 +140,14 @@ public interface IExecutingMove : IScriptSource /// IMoveChoice MoveChoice { get; } + /// + /// Returns all the hits of this move. + /// IReadOnlyList Hits { get; } + /// + /// The battle this move is being executed in. + /// IBattle Battle { get; } } @@ -189,6 +195,9 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove /// public ScriptContainer Script => MoveChoice.Script; + /// + /// The volatile scripts that are applicable to this move. + /// public IScriptSet Volatile => MoveChoice.Volatile; /// diff --git a/PkmnLib.Dynamic/Models/LearnedMove.cs b/PkmnLib.Dynamic/Models/LearnedMove.cs index 74637cb..49423a9 100644 --- a/PkmnLib.Dynamic/Models/LearnedMove.cs +++ b/PkmnLib.Dynamic/Models/LearnedMove.cs @@ -101,6 +101,7 @@ public class LearnedMoveImpl : ILearnedMove CurrentPp = MaxPp; } + /// public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod, byte pp) : this(moveData, learnMethod) { CurrentPp = pp; diff --git a/PkmnLib.Dynamic/Models/Pokemon.cs b/PkmnLib.Dynamic/Models/Pokemon.cs index e96e8cf..d851011 100644 --- a/PkmnLib.Dynamic/Models/Pokemon.cs +++ b/PkmnLib.Dynamic/Models/Pokemon.cs @@ -202,6 +202,9 @@ public interface IPokemon : IScriptSource, IDeepCloneable /// bool IsCaught { get; } + /// + /// Marks the Pokemon as caught. This makes it so that the Pokemon is not considered valid in battle anymore. + /// public void MarkAsCaught(); /// @@ -395,6 +398,9 @@ public interface IPokemon : IScriptSource, IDeepCloneable /// void SetTypes(IReadOnlyList types); + /// + /// Changes the ability of the Pokémon. + /// void ChangeAbility(IAbility ability); /// @@ -449,8 +455,14 @@ public interface IPokemonBattleData : IDeepCloneable /// void MarkItemAsConsumed(IItem item); + /// + /// The turn the Pokémon switched in. + /// uint SwitchInTurn { get; internal set; } + /// + /// The side the Pokémon is on. + /// IBattleSide BattleSide { get; } } @@ -483,6 +495,7 @@ public class PokemonImpl : ScriptSource, IPokemon CurrentHealth = BoostedStats.Hp; } + /// public PokemonImpl(IDynamicLibrary library, SerializedPokemon serializedPokemon) { Library = library; diff --git a/PkmnLib.Dynamic/Models/PokemonParty.cs b/PkmnLib.Dynamic/Models/PokemonParty.cs index def8511..13b903b 100644 --- a/PkmnLib.Dynamic/Models/PokemonParty.cs +++ b/PkmnLib.Dynamic/Models/PokemonParty.cs @@ -8,7 +8,14 @@ namespace PkmnLib.Dynamic.Models; /// public interface IPokemonParty : IReadOnlyList, IDeepCloneable { + /// + /// Event that is triggered when a Pokemon is swapped into the party. + /// event EventHandler<(IPokemon?, int index)>? OnSwapInto; + + /// + /// Event that is triggered when two Pokemon are swapped in the party. + /// event EventHandler<(int index1, int index2)>? OnSwap; /// diff --git a/PkmnLib.Dynamic/Models/Serialized/SerializedPokemon.cs b/PkmnLib.Dynamic/Models/Serialized/SerializedPokemon.cs index c814ee2..5743e6d 100644 --- a/PkmnLib.Dynamic/Models/Serialized/SerializedPokemon.cs +++ b/PkmnLib.Dynamic/Models/Serialized/SerializedPokemon.cs @@ -129,22 +129,23 @@ public record SerializedLearnedMove public required byte CurrentPp { get; set; } } +/// +/// A serialized stats is a representation of a Pokémon's stats that can be easily serialized and deserialized. +/// public record SerializedStats { + /// public SerializedStats() { } - public SerializedStats(ImmutableStatisticSet stats) + /// + public SerializedStats(ImmutableStatisticSet stats) : this(stats.Hp, stats.Attack, stats.Defense, + stats.SpecialAttack, stats.SpecialDefense, stats.Speed) { - Hp = stats.Hp; - Attack = stats.Attack; - Defense = stats.Defense; - SpecialAttack = stats.SpecialAttack; - SpecialDefense = stats.SpecialDefense; - Speed = stats.Speed; } + /// public SerializedStats(long hp, long attack, long defense, long specialAttack, long specialDefense, long speed) { Hp = hp; @@ -155,13 +156,39 @@ public record SerializedStats Speed = speed; } + /// + /// The health points stat value. + /// public long Hp { get; set; } + + /// + /// The physical attack stat value. + /// public long Attack { get; set; } + + /// + /// The physical defense stat value. + /// public long Defense { get; set; } + + /// + /// The special attack stat value. + /// public long SpecialAttack { get; set; } + + /// + /// The special defense stat value. + /// public long SpecialDefense { get; set; } + + /// + /// The speed stat value. + /// public long Speed { get; set; } + /// + /// Converts the serialized stats to an . + /// public IndividualValueStatisticSet ToIndividualValueStatisticSet() { if (Hp < 0 || Attack < 0 || Defense < 0 || SpecialAttack < 0 || SpecialDefense < 0 || Speed < 0) @@ -174,6 +201,10 @@ public record SerializedStats (byte)SpecialDefense, (byte)Speed); } + /// + /// Converts the serialized stats to an . + /// + /// public EffortValueStatisticSet ToEffortValueStatisticSet() { if (Hp < 0 || Attack < 0 || Defense < 0 || SpecialAttack < 0 || SpecialDefense < 0 || Speed < 0) diff --git a/PkmnLib.Dynamic/ScriptHandling/IWeatherScript.cs b/PkmnLib.Dynamic/ScriptHandling/IWeatherScript.cs index a701b30..4d2e9da 100644 --- a/PkmnLib.Dynamic/ScriptHandling/IWeatherScript.cs +++ b/PkmnLib.Dynamic/ScriptHandling/IWeatherScript.cs @@ -1,6 +1,12 @@ namespace PkmnLib.Dynamic.ScriptHandling; +/// +/// Helper interface for weather scripts. +/// public interface IWeatherScript { + /// + /// Sets the number of turns the weather will last. + /// public void SetTurns(int turns); } \ No newline at end of file diff --git a/PkmnLib.Dynamic/ScriptHandling/ItemScript.cs b/PkmnLib.Dynamic/ScriptHandling/ItemScript.cs index 1ab921c..f5639e9 100644 --- a/PkmnLib.Dynamic/ScriptHandling/ItemScript.cs +++ b/PkmnLib.Dynamic/ScriptHandling/ItemScript.cs @@ -4,13 +4,20 @@ using PkmnLib.Static.Utils; namespace PkmnLib.Dynamic.ScriptHandling; +/// +/// Base class for item scripts. +/// public abstract class ItemScript : IDeepCloneable { + /// protected ItemScript(IItem item) { Item = item; } + /// + /// The item associated with this script. + /// protected IItem Item { get; private set; } /// diff --git a/PkmnLib.Dynamic/ScriptHandling/PokeballScript.cs b/PkmnLib.Dynamic/ScriptHandling/PokeballScript.cs index e697434..dae0942 100644 --- a/PkmnLib.Dynamic/ScriptHandling/PokeballScript.cs +++ b/PkmnLib.Dynamic/ScriptHandling/PokeballScript.cs @@ -3,6 +3,9 @@ using PkmnLib.Static; namespace PkmnLib.Dynamic.ScriptHandling; +/// +/// Base class for Pokéball scripts. +/// public abstract class PokeballScript : ItemScript { /// @@ -10,6 +13,9 @@ public abstract class PokeballScript : ItemScript { } + /// + /// Returns the catch rate of the Pokéball against the given target Pokémon. + /// public abstract byte GetCatchRate(IPokemon target); /// diff --git a/PkmnLib.Dynamic/ScriptHandling/Registry/ItemScriptAttribute.cs b/PkmnLib.Dynamic/ScriptHandling/Registry/ItemScriptAttribute.cs index 118c18b..a8f3519 100644 --- a/PkmnLib.Dynamic/ScriptHandling/Registry/ItemScriptAttribute.cs +++ b/PkmnLib.Dynamic/ScriptHandling/Registry/ItemScriptAttribute.cs @@ -3,6 +3,9 @@ using PkmnLib.Static.Utils; namespace PkmnLib.Dynamic.ScriptHandling.Registry; +/// +/// Attribute to mark a class as an item script. +/// [AttributeUsage(AttributeTargets.Class), MeansImplicitUse] public class ItemScriptAttribute : Attribute { diff --git a/PkmnLib.Dynamic/ScriptHandling/Registry/Plugin.cs b/PkmnLib.Dynamic/ScriptHandling/Registry/Plugin.cs index f1b60d5..2508269 100644 --- a/PkmnLib.Dynamic/ScriptHandling/Registry/Plugin.cs +++ b/PkmnLib.Dynamic/ScriptHandling/Registry/Plugin.cs @@ -8,10 +8,12 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry; [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] public abstract class Plugin { + /// protected Plugin() { } + /// protected Plugin(PluginConfiguration configuration) { } @@ -33,6 +35,9 @@ public abstract class Plugin public abstract void Register(ScriptRegistry registry); } +/// +/// Base class for plugin configuration. +/// public abstract class PluginConfiguration { } \ No newline at end of file diff --git a/PkmnLib.Dynamic/ScriptHandling/Script.cs b/PkmnLib.Dynamic/ScriptHandling/Script.cs index 4419f53..924a9ab 100644 --- a/PkmnLib.Dynamic/ScriptHandling/Script.cs +++ b/PkmnLib.Dynamic/ScriptHandling/Script.cs @@ -18,6 +18,9 @@ public abstract class Script : IDeepCloneable private int _suppressCount; + /// + /// Remove the script from its owner. + /// public void RemoveSelf() { OnRemoveEvent?.Invoke(this); @@ -62,6 +65,10 @@ public abstract class Script : IDeepCloneable /// public void Unsuppress() => _suppressCount--; + /// + /// This function is ran before any hook is invoked. This allows for suppressing certain categories + /// of scripts. This is useful for example to prevent certain effects from running. + /// public virtual void OnBeforeAnyHookInvoked(ref List? suppressedCategories) { } @@ -95,6 +102,10 @@ public abstract class Script : IDeepCloneable { } + /// + /// Force a certain move choice to be selected. If the choice is set, the Pokemon will be forced + /// to use it, and will not be able to select any other choice. + /// public virtual void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice) { } @@ -140,6 +151,9 @@ public abstract class Script : IDeepCloneable { } + /// + /// This function allows you to change the targets of a move choice before the move starts. + /// public virtual void ChangeIncomingTargets(IMoveChoice moveChoice, ref IReadOnlyList targets) { } @@ -230,6 +244,9 @@ public abstract class Script : IDeepCloneable { } + /// + /// This function allows the script to override how effective a move is on a target. + /// public virtual void ChangeIncomingEffectiveness(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref float effectiveness) { @@ -504,6 +521,10 @@ public abstract class Script : IDeepCloneable { } + /// + /// This function is triggered on a Pokemon and its parents when the given Pokemon switches out + /// of the battlefield. + /// public virtual void OnSwitchOut(IPokemon oldPokemon, byte position) { } @@ -559,10 +580,16 @@ public abstract class Script : IDeepCloneable { } + /// + /// This function allows a script to block an incoming hit. + /// public virtual void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block) { } + /// + /// This function allows a script to block an outgoing hit. + /// public virtual void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block) { } @@ -582,23 +609,44 @@ public abstract class Script : IDeepCloneable { } + /// + /// This function allows a script to prevent a held item from being consumed. + /// public virtual void PreventHeldItemConsume(IPokemon pokemon, IItem heldItem, ref bool prevented) { } + /// + /// This function allows a script to change any kind of damage that is incoming. + /// public virtual void ChangeIncomingDamage(IPokemon pokemon, DamageSource source, ref uint damage) { } + /// + /// This function allows a script to change the accuracy of a move used. The value for accuracy is in percentage. + /// A custom case goes when 255 is returned, in which case the entire accuracy check is skipped, and the move + /// will always hit. + /// + /// + /// + /// + /// public virtual void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy) { } + /// + /// This function allows a script to change the weather duration of a weather effect. + /// public virtual void ChangeWeatherDuration(StringKey weatherName, ref int duration) { } + /// + /// This function allows a script to prevent a Pokemon from being healed. + /// public virtual void PreventHeal(IPokemon pokemon, uint heal, bool allowRevive, ref bool prevented) { } diff --git a/PkmnLib.Dynamic/ScriptHandling/ScriptCategory.cs b/PkmnLib.Dynamic/ScriptHandling/ScriptCategory.cs index 7003919..22755ab 100644 --- a/PkmnLib.Dynamic/ScriptHandling/ScriptCategory.cs +++ b/PkmnLib.Dynamic/ScriptHandling/ScriptCategory.cs @@ -55,6 +55,9 @@ public enum ScriptCategory /// Weather = 7, + /// + /// A special script for terrain, for use on battles. + /// Terrain = 8, /// diff --git a/PkmnLib.Dynamic/ScriptHandling/ScriptContainer.cs b/PkmnLib.Dynamic/ScriptHandling/ScriptContainer.cs index f20e213..7500809 100644 --- a/PkmnLib.Dynamic/ScriptHandling/ScriptContainer.cs +++ b/PkmnLib.Dynamic/ScriptHandling/ScriptContainer.cs @@ -4,6 +4,10 @@ using PkmnLib.Static.Utils; namespace PkmnLib.Dynamic.ScriptHandling; +/// +/// A holder class for a script. This is used so we can cache a list of these, and iterate over them, even when +/// the underlying script changes. +/// public interface IReadOnlyScriptContainer : IEnumerable, IDeepCloneable { /// @@ -17,10 +21,7 @@ public interface IReadOnlyScriptContainer : IEnumerable, IDeepC public Script? Script { get; } } -/// -/// A holder class for a script. This is used so we can cache a list of these, and iterate over them, even when -/// the underlying script changes. -/// +/// public class ScriptContainer : IReadOnlyScriptContainer { /// @@ -73,6 +74,11 @@ public class ScriptContainer : IReadOnlyScriptContainer return script; } + /// + /// Removes the script from this container, but does not call . + /// Be very careful with this, as it can lead to unexpected behavior. An example of a valid use is Baton-Pass, + /// where scripts are being removed to be added to another Pokemon, so we want them to remain active. + /// public void ClearWithoutRemoving() { Script = null; diff --git a/PkmnLib.Dynamic/ScriptHandling/ScriptExecution.cs b/PkmnLib.Dynamic/ScriptHandling/ScriptExecution.cs index 0ef88a4..06154d8 100644 --- a/PkmnLib.Dynamic/ScriptHandling/ScriptExecution.cs +++ b/PkmnLib.Dynamic/ScriptHandling/ScriptExecution.cs @@ -64,6 +64,9 @@ public static class ScriptExecution } } + /// + /// Executes a script on an item. + /// public static void RunItemScript(this IItem item, ScriptResolver scriptResolver, IPokemon? target) { if (!scriptResolver.TryResolveBattleItemScript(item, out var itemScript)) diff --git a/PkmnLib.Static/Item.cs b/PkmnLib.Static/Item.cs index a8b1115..57b5f3e 100644 --- a/PkmnLib.Static/Item.cs +++ b/PkmnLib.Static/Item.cs @@ -106,11 +106,25 @@ public interface IItem : INamedValue /// ImmutableHashSet Flags { get; } + /// + /// The effect of the item when used outside of battle. + /// ISecondaryEffect? Effect { get; } + + /// + /// The effect of the item when used in battle. + /// ISecondaryEffect? BattleEffect { get; } + /// + /// A set of arbitrary data that can be set on the item. + /// IReadOnlyDictionary AdditionalData { get; } + /// + /// Tries to get additional data from the item. If the data is not present, the value will be null. + /// If the data is present, but cannot be converted to the requested type, the value will be null. + /// bool TryGetAdditionalData(StringKey key, out T? value); /// diff --git a/PkmnLib.Static/Libraries/TypeLibrary.cs b/PkmnLib.Static/Libraries/TypeLibrary.cs index a67e7b9..85c924d 100644 --- a/PkmnLib.Static/Libraries/TypeLibrary.cs +++ b/PkmnLib.Static/Libraries/TypeLibrary.cs @@ -28,6 +28,9 @@ public interface IReadOnlyTypeLibrary /// float GetEffectiveness(TypeIdentifier attacking, IEnumerable defending); + /// + /// Gets the effectiveness for a single attacking type against all defending types. + /// IEnumerable<(TypeIdentifier type, float effectiveness)> GetAllEffectivenessFromAttacking(TypeIdentifier attacking); } diff --git a/PkmnLib.Static/Species/Ability.cs b/PkmnLib.Static/Species/Ability.cs index 63aac23..eb40b39 100644 --- a/PkmnLib.Static/Species/Ability.cs +++ b/PkmnLib.Static/Species/Ability.cs @@ -19,6 +19,9 @@ public interface IAbility : INamedValue /// IReadOnlyDictionary Parameters { get; } + /// + /// Checks whether the ability has a specific flag. + /// bool HasFlag(StringKey key); } @@ -44,6 +47,9 @@ public class AbilityImpl : IAbility /// public IReadOnlyDictionary Parameters { get; } + /// + /// A collection of arbitrary flags that can be used to mark the ability with specific properties. + /// public ImmutableHashSet Flags; /// diff --git a/PkmnLib.Static/StatisticSet.cs b/PkmnLib.Static/StatisticSet.cs index fc81dc7..0cc188c 100644 --- a/PkmnLib.Static/StatisticSet.cs +++ b/PkmnLib.Static/StatisticSet.cs @@ -51,6 +51,7 @@ public record ImmutableStatisticSet where T : struct Speed = speed; } + /// public ImmutableStatisticSet(ImmutableStatisticSet set) { Hp = set.Hp; @@ -97,6 +98,7 @@ public record StatisticSet : ImmutableStatisticSet, IEnumerable<(Statistic { } + /// public StatisticSet(StatisticSet set) : base(set) { } @@ -174,8 +176,16 @@ public record StatisticSet : ImmutableStatisticSet, IEnumerable<(Statistic return true; } + /// + /// Gets a statistic that is not one of the standard statistics. This can be used for sets where there are + /// additional statistics, such as evasion or accuracy. + /// protected virtual T GetUnknownStat(Statistic stat) => throw new ArgumentException($"Invalid statistic {stat}"); + /// + /// Sets a statistic that is not one of the standard statistics. This can be used for sets where there are + /// additional statistics, such as evasion or accuracy. + /// protected virtual void SetUnknownStat(Statistic stat, T value) { throw new ArgumentException($"Invalid statistic {stat}"); @@ -249,10 +259,14 @@ public abstract record ClampedStatisticSet : StatisticSet where T : struct Speed = Clamp(Speed, Min, Max); } + /// protected ClampedStatisticSet(ClampedStatisticSet set) : base(set) { } + /// + /// Clamps a value to be between the minimum and maximum values. + /// protected static T Clamp(T value, T min, T max) { if (value.CompareTo(min) < 0) @@ -314,6 +328,9 @@ public record StatBoostStatisticSet : ClampedStatisticSet private sbyte _evasion; + /// + /// The evasion stat value. + /// public sbyte Evasion { get => _evasion; @@ -322,6 +339,9 @@ public record StatBoostStatisticSet : ClampedStatisticSet private sbyte _accuracy; + /// + /// The accuracy stat value. + /// public sbyte Accuracy { get => _accuracy; @@ -403,6 +423,7 @@ public record IndividualValueStatisticSet : ClampedStatisticSet { } + /// public IndividualValueStatisticSet(IndividualValueStatisticSet ivs) : base(ivs) { } @@ -430,6 +451,7 @@ public record EffortValueStatisticSet : ClampedStatisticSet { } + /// public EffortValueStatisticSet(EffortValueStatisticSet evs) : base(evs) { } diff --git a/PkmnLib.Static/Utils/DictionaryHelpers.cs b/PkmnLib.Static/Utils/DictionaryHelpers.cs index 06f78bf..11362fd 100644 --- a/PkmnLib.Static/Utils/DictionaryHelpers.cs +++ b/PkmnLib.Static/Utils/DictionaryHelpers.cs @@ -1,12 +1,14 @@ namespace PkmnLib.Static.Utils; +/// +/// Helpers for working with dictionaries. +/// public static class DictionaryHelpers { + /// + /// Gets the value for a key in a dictionary, or returns a default value if the key is not found. + /// public static TValue GetOrDefault(this IDictionary dictionary, TKey key, - TValue defaultValue) - { - if (dictionary.TryGetValue(key, out var value)) - return value; - return defaultValue; - } + TValue defaultValue) => + dictionary.TryGetValue(key, out var value) ? value : defaultValue; } \ No newline at end of file diff --git a/PkmnLib.Static/Utils/EnumerableHelpers.cs b/PkmnLib.Static/Utils/EnumerableHelpers.cs index e1fd84e..ef55297 100644 --- a/PkmnLib.Static/Utils/EnumerableHelpers.cs +++ b/PkmnLib.Static/Utils/EnumerableHelpers.cs @@ -34,6 +34,9 @@ public static class EnumerableHelpers return -1; } + /// + /// Removes all elements from a list that match the given predicate. + /// public static void RemoveAll(this IList list, Func predicate) { for (var i = list.Count - 1; i >= 0; i--) diff --git a/PkmnLib.Static/Utils/NumericHelpers.cs b/PkmnLib.Static/Utils/NumericHelpers.cs index 3fbb86e..d6424cc 100644 --- a/PkmnLib.Static/Utils/NumericHelpers.cs +++ b/PkmnLib.Static/Utils/NumericHelpers.cs @@ -50,12 +50,18 @@ public static class NumericHelpers return result > short.MaxValue ? short.MaxValue : (short)result; } + /// + /// Multiplies two values. If this overflows, returns . + /// public static uint MultiplyOrMax(this uint value, uint multiplier) { var result = (ulong)value * multiplier; return result > uint.MaxValue ? uint.MaxValue : (uint)result; } + /// + /// Multiplies two values. If this overflows, returns . + /// public static uint MultiplyOrMax(this uint value, float multiplier) { var result = value * multiplier; diff --git a/PkmnLib.Tests/PkmnLib.Tests.csproj b/PkmnLib.Tests/PkmnLib.Tests.csproj index a4fe053..a8ea84b 100644 --- a/PkmnLib.Tests/PkmnLib.Tests.csproj +++ b/PkmnLib.Tests/PkmnLib.Tests.csproj @@ -4,9 +4,14 @@ net9.0 enable enable - false true + + + + + CA1822 +