Add all missing docs
This commit is contained in:
parent
4d5dfd0342
commit
441f5dddaf
@ -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;
|
||||
/// <summary>
|
||||
/// The base class for implementing an AI for Pokémon.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public abstract class PokemonAI
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the AI.
|
||||
/// </summary>
|
||||
public StringKey Name { get; set; }
|
||||
public StringKey Name { get; }
|
||||
|
||||
/// <inheritdoc cref="PokemonAI" />
|
||||
protected PokemonAI(StringKey name)
|
||||
@ -26,9 +28,11 @@ public abstract class PokemonAI
|
||||
/// </summary>
|
||||
public abstract ITurnChoice GetChoice(IBattle battle, IPokemon pokemon);
|
||||
|
||||
/// <summary>
|
||||
/// For a given user and move, returns the valid targets for that move.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
@ -3,15 +3,26 @@ using PkmnLib.Dynamic.Models;
|
||||
|
||||
namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an event that occurs when a Pokémon capture attempt is made.
|
||||
/// </summary>
|
||||
public class CaptureAttemptEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="CaptureAttemptEvent"/>
|
||||
public CaptureAttemptEvent(IPokemon target, CaptureResult result)
|
||||
{
|
||||
Target = target;
|
||||
Result = result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Pokémon that is being captured.
|
||||
/// </summary>
|
||||
public IPokemon Target { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The result of the capture attempt.
|
||||
/// </summary>
|
||||
public CaptureResult Result { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -1,17 +1,27 @@
|
||||
namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an event that occurs when a dialog is displayed.
|
||||
/// </summary>
|
||||
public class DialogEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; } = new();
|
||||
|
||||
/// <inheritdoc cref="DialogEvent"/>
|
||||
public DialogEvent(string message, Dictionary<string, object>? parameters = null)
|
||||
{
|
||||
Message = message;
|
||||
Parameters = parameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The message to be displayed in the dialog. This is generally a key that needs to be localized.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional parameters that can be used to format the message in a localized string.
|
||||
/// </summary>
|
||||
public Dictionary<string, object>? Parameters { get; set; }
|
||||
}
|
@ -2,8 +2,12 @@ using PkmnLib.Dynamic.Models;
|
||||
|
||||
namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an event that occurs when a Pokémon gains experience.
|
||||
/// </summary>
|
||||
public class ExperienceGainEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="ExperienceGainEvent"/>
|
||||
public ExperienceGainEvent(IPokemon pokemon, uint previousExperience, uint newExperience)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
@ -11,8 +15,19 @@ public class ExperienceGainEvent : IEventData
|
||||
NewExperience = newExperience;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Pokémon that gained experience.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of experience the Pokémon had before the gain.
|
||||
/// </summary>
|
||||
public uint PreviousExperience { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of experience the Pokémon has after the gain.
|
||||
/// </summary>
|
||||
public uint NewExperience { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -3,11 +3,22 @@ using PkmnLib.Static.Species;
|
||||
|
||||
namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an event that occurs when a Pokémon changes its form.
|
||||
/// </summary>
|
||||
public class FormChangeEvent : IEventData
|
||||
{
|
||||
/// <summary>
|
||||
/// The Pokémon that changed its form.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The new form of the Pokémon.
|
||||
/// </summary>
|
||||
public IForm Form { get; }
|
||||
|
||||
/// <inheritdoc cref="FormChangeEvent"/>
|
||||
public FormChangeEvent(IPokemon pokemon, IForm form)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
|
@ -10,6 +10,7 @@ namespace PkmnLib.Dynamic.Events;
|
||||
/// </remarks>
|
||||
public readonly record struct EventBatchId
|
||||
{
|
||||
/// <inheritdoc cref="EventBatchId"/>
|
||||
public EventBatchId()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
|
@ -1,3 +1,5 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
/// <summary>
|
||||
@ -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.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public interface IEventData
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -2,8 +2,12 @@ using PkmnLib.Dynamic.Models;
|
||||
|
||||
namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an event that occurs when a Pokémon gains enough experience points to level up.
|
||||
/// </summary>
|
||||
public class LevelUpEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="LevelUpEvent"/>
|
||||
public LevelUpEvent(IPokemon pokemon, int previousLevel, int newLevel)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
@ -11,10 +15,19 @@ public class LevelUpEvent : IEventData
|
||||
NewLevel = newLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The new level of the Pokémon after leveling up.
|
||||
/// </summary>
|
||||
public int NewLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The previous level of the Pokémon before leveling up.
|
||||
/// </summary>
|
||||
public int PreviousLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Pokémon that leveled up.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -3,12 +3,27 @@ using PkmnLib.Static.Species;
|
||||
|
||||
namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an event that occurs when a Pokémon changes to a different species.
|
||||
/// </summary>
|
||||
public class SpeciesChangeEvent : IEventData
|
||||
{
|
||||
/// <summary>
|
||||
/// The Pokémon that changed species.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The new species of the Pokémon.
|
||||
/// </summary>
|
||||
public ISpecies Species { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The new form of the Pokémon, if applicable.
|
||||
/// </summary>
|
||||
public IForm Form { get; }
|
||||
|
||||
/// <inheritdoc cref="SpeciesChangeEvent"/>
|
||||
public SpeciesChangeEvent(IPokemon pokemon, ISpecies species, IForm form)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
|
@ -3,8 +3,12 @@ using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Dynamic.Libraries;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result of a capture attempt.
|
||||
/// </summary>
|
||||
public record struct CaptureResult
|
||||
{
|
||||
/// <inheritdoc cref="CaptureResult"/>
|
||||
public CaptureResult(bool IsCaught, int Shakes, bool CriticalCapture)
|
||||
{
|
||||
this.IsCaught = IsCaught;
|
||||
@ -12,14 +16,35 @@ public record struct CaptureResult
|
||||
this.CriticalCapture = CriticalCapture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the capture was successful.
|
||||
/// </summary>
|
||||
public bool IsCaught { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of shakes the Poké Ball made before the capture attempt was successful or failed.
|
||||
/// </summary>
|
||||
public int Shakes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public bool CriticalCapture { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CaptureResult"/> indicating a failed capture attempt.
|
||||
/// </summary>
|
||||
public static CaptureResult Failed => new(false, 0, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for a library that handles Pokémon capture mechanics.
|
||||
/// </summary>
|
||||
public interface ICaptureLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to capture a Pokémon using a specified item (e.g., Poké Ball).
|
||||
/// </summary>
|
||||
CaptureResult TryCapture(IPokemon target, IItem captureItem, IBattleRandom random);
|
||||
}
|
@ -20,5 +20,8 @@ public interface IMiscLibrary
|
||||
/// </summary>
|
||||
TimeOfDay GetTimeOfDay();
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the given Pokemon can flee from the battle.
|
||||
/// </summary>
|
||||
bool CanFlee(IBattle battle, IFleeChoice fleeChoice);
|
||||
}
|
@ -93,6 +93,10 @@ public interface IBattle : IScriptSource, IDeepCloneable
|
||||
/// </summary>
|
||||
void ValidateBattleState();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
bool HasForcedTurn(IPokemon pokemon, [NotNullWhen(true)] out ITurnChoice? choice);
|
||||
|
||||
/// <summary>
|
||||
@ -117,6 +121,9 @@ public interface IBattle : IScriptSource, IDeepCloneable
|
||||
/// </summary>
|
||||
bool SetWeather(StringKey? weatherName, int duration);
|
||||
|
||||
/// <summary>
|
||||
/// Volatile scripts are scripts that are not permanent and can be removed by other scripts.
|
||||
/// </summary>
|
||||
public IScriptSet Volatile { get; }
|
||||
|
||||
/// <summary>
|
||||
@ -124,8 +131,15 @@ public interface IBattle : IScriptSource, IDeepCloneable
|
||||
/// </summary>
|
||||
StringKey? WeatherName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current terrain for the battle. If null is passed, this clears the terrain.
|
||||
/// </summary>
|
||||
/// <param name="terrainName"></param>
|
||||
void SetTerrain(StringKey? terrainName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current terrain of the battle. If no terrain is present, this returns null.
|
||||
/// </summary>
|
||||
StringKey? TerrainName { get; }
|
||||
|
||||
/// <summary>
|
||||
@ -134,6 +148,9 @@ public interface IBattle : IScriptSource, IDeepCloneable
|
||||
/// </summary>
|
||||
IReadOnlyList<IReadOnlyList<ITurnChoice>> PreviousTurnChoices { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to capture a Pokemon. This will use the current RNG to determine whether the capture is successful.
|
||||
/// </summary>
|
||||
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();
|
||||
|
||||
/// <summary>
|
||||
/// The script that handles the current weather of the battle.
|
||||
/// </summary>
|
||||
public IReadOnlyScriptContainer WeatherScript => _weatherScript;
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -377,6 +398,7 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
// TODO: Trigger weather change script hooks
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IScriptSet Volatile { get; } = new ScriptSet();
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -16,6 +16,10 @@ public class BattleChoiceQueue : IDeepCloneable
|
||||
{
|
||||
private readonly ITurnChoice?[] _choices;
|
||||
private int _currentIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the last choice that was executed.
|
||||
/// </summary>
|
||||
public ITurnChoice? LastRanChoice { get; private set; }
|
||||
|
||||
/// <inheritdoc cref="BattleChoiceQueue"/>
|
||||
@ -122,9 +126,15 @@ public class BattleChoiceQueue : IDeepCloneable
|
||||
|
||||
internal IReadOnlyList<ITurnChoice?> GetChoices() => _choices;
|
||||
|
||||
/// <summary>
|
||||
/// This returns the first choice that matches the predicate, or null if none was found.
|
||||
/// </summary>
|
||||
public ITurnChoice? FirstOrDefault(Func<ITurnChoice, bool> predicate) =>
|
||||
_choices.Skip(_currentIndex).WhereNotNull().FirstOrDefault(predicate);
|
||||
|
||||
/// <summary>
|
||||
/// Removes a choice from the queue.
|
||||
/// </summary>
|
||||
public void Remove(ITurnChoice choice)
|
||||
{
|
||||
var index = Array.FindIndex(_choices, _currentIndex, x => x == choice);
|
||||
|
@ -19,10 +19,18 @@ public interface IBattleRandom : IRandom, IDeepCloneable
|
||||
/// <inheritdoc cref="IBattleRandom"/>
|
||||
public class BattleRandomImpl : RandomImpl, IBattleRandom
|
||||
{
|
||||
/// <inheritdoc cref="BattleRandomImpl"/>
|
||||
/// <remarks>
|
||||
/// This constructor is used to instantiate the class when no seed is provided. It uses a time-dependent default seed value.
|
||||
/// </remarks>
|
||||
public BattleRandomImpl()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BattleRandomImpl"/>
|
||||
/// <remarks>
|
||||
/// This constructor is used to instantiate the class with a specific seed value.
|
||||
/// </remarks>
|
||||
public BattleRandomImpl(int seed) : base(seed)
|
||||
{
|
||||
}
|
||||
|
@ -142,9 +142,19 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
|
||||
/// </summary>
|
||||
IItem? GetLastConsumedItem(byte battleDataPosition);
|
||||
|
||||
/// <summary>
|
||||
/// Marks a Pokémon as fainted. This is used to track the last turn a Pokémon in a position fainted.
|
||||
/// </summary>
|
||||
void MarkFaint(byte position);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last turn a Pokémon in a specific position fainted.
|
||||
/// </summary>
|
||||
uint? GetLastFaintTurn(byte position);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last turn a Pokémon in any position fainted.
|
||||
/// </summary>
|
||||
uint? GetLastFaintTurn();
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ public interface IItemChoice : ITurnChoice
|
||||
/// <inheritdoc cref="IItemChoice"/>
|
||||
public class ItemChoice : TurnChoice, IItemChoice
|
||||
{
|
||||
/// <inheritdoc cref="ItemChoice"/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The item that is used.
|
||||
/// </summary>
|
||||
public IItem Item { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -9,8 +9,10 @@ public interface IPassChoice : ITurnChoice
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IPassChoice"/>
|
||||
public class PassChoice : TurnChoice, IPassChoice
|
||||
{
|
||||
/// <inheritdoc cref="PassChoice"/>
|
||||
public PassChoice(IPokemon user) : base(user)
|
||||
{
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ public interface ISwitchChoice : ITurnChoice
|
||||
/// <inheritdoc cref="ISwitchChoice"/>
|
||||
public class SwitchChoice : TurnChoice, ISwitchChoice
|
||||
{
|
||||
/// <inheritdoc cref="SwitchChoice"/>
|
||||
public SwitchChoice(IPokemon user, IPokemon switchTo) : base(user)
|
||||
{
|
||||
SwitchTo = switchTo;
|
||||
|
@ -140,8 +140,14 @@ public interface IExecutingMove : IScriptSource
|
||||
/// </summary>
|
||||
IMoveChoice MoveChoice { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns all the hits of this move.
|
||||
/// </summary>
|
||||
IReadOnlyList<IHitData> Hits { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The battle this move is being executed in.
|
||||
/// </summary>
|
||||
IBattle Battle { get; }
|
||||
}
|
||||
|
||||
@ -189,6 +195,9 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
/// <inheritdoc />
|
||||
public ScriptContainer Script => MoveChoice.Script;
|
||||
|
||||
/// <summary>
|
||||
/// The volatile scripts that are applicable to this move.
|
||||
/// </summary>
|
||||
public IScriptSet Volatile => MoveChoice.Volatile;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -101,6 +101,7 @@ public class LearnedMoveImpl : ILearnedMove
|
||||
CurrentPp = MaxPp;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="LearnedMoveImpl" />
|
||||
public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod, byte pp) : this(moveData, learnMethod)
|
||||
{
|
||||
CurrentPp = pp;
|
||||
|
@ -202,6 +202,9 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// </summary>
|
||||
bool IsCaught { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Marks the Pokemon as caught. This makes it so that the Pokemon is not considered valid in battle anymore.
|
||||
/// </summary>
|
||||
public void MarkAsCaught();
|
||||
|
||||
/// <summary>
|
||||
@ -395,6 +398,9 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// </summary>
|
||||
void SetTypes(IReadOnlyList<TypeIdentifier> types);
|
||||
|
||||
/// <summary>
|
||||
/// Changes the ability of the Pokémon.
|
||||
/// </summary>
|
||||
void ChangeAbility(IAbility ability);
|
||||
|
||||
/// <summary>
|
||||
@ -449,8 +455,14 @@ public interface IPokemonBattleData : IDeepCloneable
|
||||
/// </summary>
|
||||
void MarkItemAsConsumed(IItem item);
|
||||
|
||||
/// <summary>
|
||||
/// The turn the Pokémon switched in.
|
||||
/// </summary>
|
||||
uint SwitchInTurn { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The side the Pokémon is on.
|
||||
/// </summary>
|
||||
IBattleSide BattleSide { get; }
|
||||
}
|
||||
|
||||
@ -483,6 +495,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
CurrentHealth = BoostedStats.Hp;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="PokemonImpl"/>
|
||||
public PokemonImpl(IDynamicLibrary library, SerializedPokemon serializedPokemon)
|
||||
{
|
||||
Library = library;
|
||||
|
@ -8,7 +8,14 @@ namespace PkmnLib.Dynamic.Models;
|
||||
/// </summary>
|
||||
public interface IPokemonParty : IReadOnlyList<IPokemon?>, IDeepCloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// Event that is triggered when a Pokemon is swapped into the party.
|
||||
/// </summary>
|
||||
event EventHandler<(IPokemon?, int index)>? OnSwapInto;
|
||||
|
||||
/// <summary>
|
||||
/// Event that is triggered when two Pokemon are swapped in the party.
|
||||
/// </summary>
|
||||
event EventHandler<(int index1, int index2)>? OnSwap;
|
||||
|
||||
/// <summary>
|
||||
|
@ -129,22 +129,23 @@ public record SerializedLearnedMove
|
||||
public required byte CurrentPp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A serialized stats is a representation of a Pokémon's stats that can be easily serialized and deserialized.
|
||||
/// </summary>
|
||||
public record SerializedStats
|
||||
{
|
||||
/// <inheritdoc cref="SerializedStats"/>
|
||||
public SerializedStats()
|
||||
{
|
||||
}
|
||||
|
||||
public SerializedStats(ImmutableStatisticSet<byte> stats)
|
||||
/// <inheritdoc cref="SerializedStats"/>
|
||||
public SerializedStats(ImmutableStatisticSet<byte> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="SerializedStats"/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The health points stat value.
|
||||
/// </summary>
|
||||
public long Hp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The physical attack stat value.
|
||||
/// </summary>
|
||||
public long Attack { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The physical defense stat value.
|
||||
/// </summary>
|
||||
public long Defense { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The special attack stat value.
|
||||
/// </summary>
|
||||
public long SpecialAttack { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The special defense stat value.
|
||||
/// </summary>
|
||||
public long SpecialDefense { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The speed stat value.
|
||||
/// </summary>
|
||||
public long Speed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts the serialized stats to an <see cref="IndividualValueStatisticSet"/>.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the serialized stats to an <see cref="EffortValueStatisticSet"/>.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public EffortValueStatisticSet ToEffortValueStatisticSet()
|
||||
{
|
||||
if (Hp < 0 || Attack < 0 || Defense < 0 || SpecialAttack < 0 || SpecialDefense < 0 || Speed < 0)
|
||||
|
@ -1,6 +1,12 @@
|
||||
namespace PkmnLib.Dynamic.ScriptHandling;
|
||||
|
||||
/// <summary>
|
||||
/// Helper interface for weather scripts.
|
||||
/// </summary>
|
||||
public interface IWeatherScript
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the number of turns the weather will last.
|
||||
/// </summary>
|
||||
public void SetTurns(int turns);
|
||||
}
|
@ -4,13 +4,20 @@ using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Dynamic.ScriptHandling;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for item scripts.
|
||||
/// </summary>
|
||||
public abstract class ItemScript : IDeepCloneable
|
||||
{
|
||||
/// <inheritdoc cref="ItemScript"/>
|
||||
protected ItemScript(IItem item)
|
||||
{
|
||||
Item = item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The item associated with this script.
|
||||
/// </summary>
|
||||
protected IItem Item { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -3,6 +3,9 @@ using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Dynamic.ScriptHandling;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for Pokéball scripts.
|
||||
/// </summary>
|
||||
public abstract class PokeballScript : ItemScript
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@ -10,6 +13,9 @@ public abstract class PokeballScript : ItemScript
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the catch rate of the Pokéball against the given target Pokémon.
|
||||
/// </summary>
|
||||
public abstract byte GetCatchRate(IPokemon target);
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -3,6 +3,9 @@ using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
|
||||
/// <summary>
|
||||
/// Attribute to mark a class as an item script.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class), MeansImplicitUse]
|
||||
public class ItemScriptAttribute : Attribute
|
||||
{
|
||||
|
@ -8,10 +8,12 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
|
||||
public abstract class Plugin
|
||||
{
|
||||
/// <inheritdoc cref="Plugin"/>
|
||||
protected Plugin()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Plugin"/>
|
||||
protected Plugin(PluginConfiguration configuration)
|
||||
{
|
||||
}
|
||||
@ -33,6 +35,9 @@ public abstract class Plugin
|
||||
public abstract void Register(ScriptRegistry registry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for plugin configuration.
|
||||
/// </summary>
|
||||
public abstract class PluginConfiguration
|
||||
{
|
||||
}
|
@ -18,6 +18,9 @@ public abstract class Script : IDeepCloneable
|
||||
|
||||
private int _suppressCount;
|
||||
|
||||
/// <summary>
|
||||
/// Remove the script from its owner.
|
||||
/// </summary>
|
||||
public void RemoveSelf()
|
||||
{
|
||||
OnRemoveEvent?.Invoke(this);
|
||||
@ -62,6 +65,10 @@ public abstract class Script : IDeepCloneable
|
||||
/// </summary>
|
||||
public void Unsuppress() => _suppressCount--;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public virtual void OnBeforeAnyHookInvoked(ref List<ScriptCategory>? suppressedCategories)
|
||||
{
|
||||
}
|
||||
@ -95,6 +102,10 @@ public abstract class Script : IDeepCloneable
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public virtual void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice)
|
||||
{
|
||||
}
|
||||
@ -140,6 +151,9 @@ public abstract class Script : IDeepCloneable
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function allows you to change the targets of a move choice before the move starts.
|
||||
/// </summary>
|
||||
public virtual void ChangeIncomingTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
|
||||
{
|
||||
}
|
||||
@ -230,6 +244,9 @@ public abstract class Script : IDeepCloneable
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function allows the script to override how effective a move is on a target.
|
||||
/// </summary>
|
||||
public virtual void ChangeIncomingEffectiveness(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||
ref float effectiveness)
|
||||
{
|
||||
@ -504,6 +521,10 @@ public abstract class Script : IDeepCloneable
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon switches out
|
||||
/// of the battlefield.
|
||||
/// </summary>
|
||||
public virtual void OnSwitchOut(IPokemon oldPokemon, byte position)
|
||||
{
|
||||
}
|
||||
@ -559,10 +580,16 @@ public abstract class Script : IDeepCloneable
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function allows a script to block an incoming hit.
|
||||
/// </summary>
|
||||
public virtual void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function allows a script to block an outgoing hit.
|
||||
/// </summary>
|
||||
public virtual void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
{
|
||||
}
|
||||
@ -582,23 +609,44 @@ public abstract class Script : IDeepCloneable
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function allows a script to prevent a held item from being consumed.
|
||||
/// </summary>
|
||||
public virtual void PreventHeldItemConsume(IPokemon pokemon, IItem heldItem, ref bool prevented)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function allows a script to change any kind of damage that is incoming.
|
||||
/// </summary>
|
||||
public virtual void ChangeIncomingDamage(IPokemon pokemon, DamageSource source, ref uint damage)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="executingMove"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="hitIndex"></param>
|
||||
/// <param name="modifiedAccuracy"></param>
|
||||
public virtual void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||
ref int modifiedAccuracy)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function allows a script to change the weather duration of a weather effect.
|
||||
/// </summary>
|
||||
public virtual void ChangeWeatherDuration(StringKey weatherName, ref int duration)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function allows a script to prevent a Pokemon from being healed.
|
||||
/// </summary>
|
||||
public virtual void PreventHeal(IPokemon pokemon, uint heal, bool allowRevive, ref bool prevented)
|
||||
{
|
||||
}
|
||||
|
@ -55,6 +55,9 @@ public enum ScriptCategory
|
||||
/// </summary>
|
||||
Weather = 7,
|
||||
|
||||
/// <summary>
|
||||
/// A special script for terrain, for use on battles.
|
||||
/// </summary>
|
||||
Terrain = 8,
|
||||
|
||||
/// <summary>
|
||||
|
@ -4,6 +4,10 @@ using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Dynamic.ScriptHandling;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public interface IReadOnlyScriptContainer : IEnumerable<ScriptContainer>, IDeepCloneable
|
||||
{
|
||||
/// <summary>
|
||||
@ -17,10 +21,7 @@ public interface IReadOnlyScriptContainer : IEnumerable<ScriptContainer>, IDeepC
|
||||
public Script? Script { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="IReadOnlyScriptContainer"/>
|
||||
public class ScriptContainer : IReadOnlyScriptContainer
|
||||
{
|
||||
/// <inheritdoc cref="ScriptContainer"/>
|
||||
@ -73,6 +74,11 @@ public class ScriptContainer : IReadOnlyScriptContainer
|
||||
return script;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the script from this container, but does not call <see cref="Script.OnRemove"/>.
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public void ClearWithoutRemoving()
|
||||
{
|
||||
Script = null;
|
||||
|
@ -64,6 +64,9 @@ public static class ScriptExecution
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a script on an item.
|
||||
/// </summary>
|
||||
public static void RunItemScript(this IItem item, ScriptResolver scriptResolver, IPokemon? target)
|
||||
{
|
||||
if (!scriptResolver.TryResolveBattleItemScript(item, out var itemScript))
|
||||
|
@ -106,11 +106,25 @@ public interface IItem : INamedValue
|
||||
/// </summary>
|
||||
ImmutableHashSet<StringKey> Flags { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The effect of the item when used outside of battle.
|
||||
/// </summary>
|
||||
ISecondaryEffect? Effect { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The effect of the item when used in battle.
|
||||
/// </summary>
|
||||
ISecondaryEffect? BattleEffect { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A set of arbitrary data that can be set on the item.
|
||||
/// </summary>
|
||||
IReadOnlyDictionary<StringKey, object?> AdditionalData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
bool TryGetAdditionalData<T>(StringKey key, out T? value);
|
||||
|
||||
/// <summary>
|
||||
|
@ -28,6 +28,9 @@ public interface IReadOnlyTypeLibrary
|
||||
/// </summary>
|
||||
float GetEffectiveness(TypeIdentifier attacking, IEnumerable<TypeIdentifier> defending);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the effectiveness for a single attacking type against all defending types.
|
||||
/// </summary>
|
||||
IEnumerable<(TypeIdentifier type, float effectiveness)> GetAllEffectivenessFromAttacking(TypeIdentifier attacking);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,9 @@ public interface IAbility : INamedValue
|
||||
/// </summary>
|
||||
IReadOnlyDictionary<StringKey, object?> Parameters { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the ability has a specific flag.
|
||||
/// </summary>
|
||||
bool HasFlag(StringKey key);
|
||||
}
|
||||
|
||||
@ -44,6 +47,9 @@ public class AbilityImpl : IAbility
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyDictionary<StringKey, object?> Parameters { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A collection of arbitrary flags that can be used to mark the ability with specific properties.
|
||||
/// </summary>
|
||||
public ImmutableHashSet<StringKey> Flags;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -51,6 +51,7 @@ public record ImmutableStatisticSet<T> where T : struct
|
||||
Speed = speed;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ImmutableStatisticSet{T}"/>
|
||||
public ImmutableStatisticSet(ImmutableStatisticSet<T> set)
|
||||
{
|
||||
Hp = set.Hp;
|
||||
@ -97,6 +98,7 @@ public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<(Statistic
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="StatisticSet{T}"/>
|
||||
public StatisticSet(StatisticSet<T> set) : base(set)
|
||||
{
|
||||
}
|
||||
@ -174,8 +176,16 @@ public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<(Statistic
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
protected virtual T GetUnknownStat(Statistic stat) => throw new ArgumentException($"Invalid statistic {stat}");
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
protected virtual void SetUnknownStat(Statistic stat, T value)
|
||||
{
|
||||
throw new ArgumentException($"Invalid statistic {stat}");
|
||||
@ -249,10 +259,14 @@ public abstract record ClampedStatisticSet<T> : StatisticSet<T> where T : struct
|
||||
Speed = Clamp(Speed, Min, Max);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ClampedStatisticSet{T}"/>
|
||||
protected ClampedStatisticSet(ClampedStatisticSet<T> set) : base(set)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps a value to be between the minimum and maximum values.
|
||||
/// </summary>
|
||||
protected static T Clamp(T value, T min, T max)
|
||||
{
|
||||
if (value.CompareTo(min) < 0)
|
||||
@ -314,6 +328,9 @@ public record StatBoostStatisticSet : ClampedStatisticSet<sbyte>
|
||||
|
||||
private sbyte _evasion;
|
||||
|
||||
/// <summary>
|
||||
/// The evasion stat value.
|
||||
/// </summary>
|
||||
public sbyte Evasion
|
||||
{
|
||||
get => _evasion;
|
||||
@ -322,6 +339,9 @@ public record StatBoostStatisticSet : ClampedStatisticSet<sbyte>
|
||||
|
||||
private sbyte _accuracy;
|
||||
|
||||
/// <summary>
|
||||
/// The accuracy stat value.
|
||||
/// </summary>
|
||||
public sbyte Accuracy
|
||||
{
|
||||
get => _accuracy;
|
||||
@ -403,6 +423,7 @@ public record IndividualValueStatisticSet : ClampedStatisticSet<byte>
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IndividualValueStatisticSet"/>
|
||||
public IndividualValueStatisticSet(IndividualValueStatisticSet ivs) : base(ivs)
|
||||
{
|
||||
}
|
||||
@ -430,6 +451,7 @@ public record EffortValueStatisticSet : ClampedStatisticSet<byte>
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="EffortValueStatisticSet"/>
|
||||
public EffortValueStatisticSet(EffortValueStatisticSet evs) : base(evs)
|
||||
{
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
namespace PkmnLib.Static.Utils;
|
||||
|
||||
/// <summary>
|
||||
/// Helpers for working with dictionaries.
|
||||
/// </summary>
|
||||
public static class DictionaryHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the value for a key in a dictionary, or returns a default value if the key is not found.
|
||||
/// </summary>
|
||||
public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> 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;
|
||||
}
|
@ -34,6 +34,9 @@ public static class EnumerableHelpers
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all elements from a list that match the given predicate.
|
||||
/// </summary>
|
||||
public static void RemoveAll<T>(this IList<T> list, Func<T, bool> predicate)
|
||||
{
|
||||
for (var i = list.Count - 1; i >= 0; i--)
|
||||
|
@ -50,12 +50,18 @@ public static class NumericHelpers
|
||||
return result > short.MaxValue ? short.MaxValue : (short)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies two values. If this overflows, returns <see cref="uint.MaxValue"/>.
|
||||
/// </summary>
|
||||
public static uint MultiplyOrMax(this uint value, uint multiplier)
|
||||
{
|
||||
var result = (ulong)value * multiplier;
|
||||
return result > uint.MaxValue ? uint.MaxValue : (uint)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies two values. If this overflows, returns <see cref="uint.MaxValue"/>.
|
||||
/// </summary>
|
||||
public static uint MultiplyOrMax(this uint value, float multiplier)
|
||||
{
|
||||
var result = value * multiplier;
|
||||
|
@ -4,9 +4,14 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
|
||||
|
||||
<NoWarn>
|
||||
<!-- Don't show warning to make method static for our tests. -->
|
||||
CA1822
|
||||
</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
Loading…
x
Reference in New Issue
Block a user