Style cleanup

This commit is contained in:
Deukhoofd 2025-03-02 17:19:57 +01:00
parent c0bc905c46
commit 284ab3079c
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
175 changed files with 588 additions and 650 deletions

View File

@ -28,13 +28,13 @@ public static class ItemDataLoader
}
public delegate IItem ItemFactoryDelegate(SerializedItem serialized, StringKey name, ItemCategory type,
BattleItemCategory battleType, int price, ImmutableHashSet<StringKey> flags,
ISecondaryEffect? effect, ISecondaryEffect? battleTriggerEffect, byte flingPower);
BattleItemCategory battleType, int price, ImmutableHashSet<StringKey> flags, ISecondaryEffect? effect,
ISecondaryEffect? battleTriggerEffect, byte flingPower);
[PublicAPI]
public static ItemFactoryDelegate ItemConstructor { get; set; } = (_, name, type, battleType, price, flags, effect,
battleTriggerEffect, flingPower) =>
new ItemImpl(name, type, battleType, price, flags, effect, battleTriggerEffect, flingPower);
public static ItemFactoryDelegate ItemConstructor { get; set; } =
(_, name, type, battleType, price, flags, effect, battleTriggerEffect, flingPower) => new ItemImpl(name, type,
battleType, price, flags, effect, battleTriggerEffect, flingPower);
private static IItem DeserializeItem(SerializedItem serialized)
{

View File

@ -4,7 +4,7 @@ namespace PkmnLib.Dataloader;
internal static class JsonOptions
{
public static JsonSerializerOptions DefaultOptions => new JsonSerializerOptions()
public static JsonSerializerOptions DefaultOptions => new()
{
PropertyNameCaseInsensitive = true,
AllowTrailingCommas = true,

View File

@ -15,6 +15,5 @@ public class SerializedItem
public SerializedMoveEffect? Effect { get; set; }
public SerializedMoveEffect? BattleEffect { get; set; }
[JsonExtensionData]
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
[JsonExtensionData] public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}

View File

@ -23,8 +23,7 @@ public class SerializedMove
public string[] Flags { get; set; } = null!;
public SerializedMoveEffect? Effect { get; set; }
[JsonExtensionData]
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
[JsonExtensionData] public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}
public class SerializedMoveEffect

View File

@ -21,8 +21,7 @@ public class SerializedSpecies
public Dictionary<string, SerializedForm> Formes { get; set; } = null!;
public SerializedEvolution[] Evolutions { get; set; } = [];
[JsonExtensionData]
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
[JsonExtensionData] public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}
public class SerializedForm
@ -39,8 +38,7 @@ public class SerializedForm
public SerializedMoves Moves { get; set; } = null!;
public string[] Flags { get; set; } = [];
[JsonExtensionData]
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
[JsonExtensionData] public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}
public class SerializedEvolution

View File

@ -26,11 +26,12 @@ public static class MoveDataLoader
return library;
}
public static Func<SerializedMove, StringKey, TypeIdentifier, MoveCategory, byte, byte, byte, MoveTarget, sbyte,
ISecondaryEffect?, IEnumerable<StringKey>, MoveDataImpl> MoveConstructor =
(serialized, name, moveType, category, basePower, accuracy, baseUsages, target, priority, secondaryEffect,
flags) => new MoveDataImpl(name, moveType, category, basePower, accuracy, baseUsages, target, priority,
secondaryEffect, flags);
public static
Func<SerializedMove, StringKey, TypeIdentifier, MoveCategory, byte, byte, byte, MoveTarget, sbyte,
ISecondaryEffect?, IEnumerable<StringKey>, MoveDataImpl> MoveConstructor =
(serialized, name, moveType, category, basePower, accuracy, baseUsages, target, priority, secondaryEffect,
flags) => new MoveDataImpl(name, moveType, category, basePower, accuracy, baseUsages, target, priority,
secondaryEffect, flags);
private static MoveDataImpl DeserializeMove(SerializedMove serialized, TypeLibrary typeLibrary)
{
@ -55,9 +56,8 @@ public static class MoveDataLoader
throw new InvalidDataException($"Target {target} is not a valid target.");
var secondaryEffect = effect.ParseEffect();
var move = MoveConstructor(serialized, serialized.Name, typeIdentifier, categoryEnum, power, accuracy, pp, targetEnum,
priority, secondaryEffect, flags.Select(x => (StringKey)x).ToImmutableHashSet());
var move = MoveConstructor(serialized, serialized.Name, typeIdentifier, categoryEnum, power, accuracy, pp,
targetEnum, priority, secondaryEffect, flags.Select(x => (StringKey)x).ToImmutableHashSet());
return move;
}
}

View File

@ -20,8 +20,8 @@ public static class SpeciesDataLoader
var obj = JsonSerializer.Deserialize<JsonObject>(stream, JsonOptions.DefaultOptions);
if (obj == null)
throw new InvalidDataException("Species data is empty.");
return obj.Where(x => x.Key != "$schema")
.ToDictionary(x => x.Key, x => x.Value.Deserialize<SerializedSpecies>(JsonOptions.DefaultOptions));
return obj.Where(x => x.Key != "$schema").ToDictionary(x => x.Key,
x => x.Value.Deserialize<SerializedSpecies>(JsonOptions.DefaultOptions));
}
public static SpeciesLibrary LoadSpecies(Stream[] streams, IReadOnlyTypeLibrary typeLibrary)
@ -48,34 +48,37 @@ public static class SpeciesDataLoader
return library;
}
public static Func<SerializedSpecies, ushort, StringKey, float, StringKey, byte, byte, IReadOnlyDictionary<StringKey, IForm>,
IEnumerable<StringKey>, IReadOnlyList<IEvolution>, IEnumerable<StringKey>, SpeciesImpl> SpeciesConstructor =
(_, id, name, genderRate, growthRate, captureRate, baseHappiness, forms, flags, evolutionData,
eggGroups) =>
{
return new SpeciesImpl(id, name, genderRate, growthRate,
captureRate, baseHappiness, forms,
flags, evolutionData, eggGroups);
};
public static
Func<SerializedSpecies, ushort, StringKey, float, StringKey, byte, byte, IReadOnlyDictionary<StringKey, IForm>,
IEnumerable<StringKey>, IReadOnlyList<IEvolution>, IEnumerable<StringKey>, SpeciesImpl> SpeciesConstructor =
(_, id, name, genderRate, growthRate, captureRate, baseHappiness, forms, flags, evolutionData, eggGroups) =>
{
return new SpeciesImpl(id, name, genderRate, growthRate, captureRate, baseHappiness, forms, flags,
evolutionData, eggGroups);
};
private static SpeciesImpl DeserializeSpecies(SerializedSpecies serialized, IReadOnlyTypeLibrary typeLibrary)
{
var id = serialized.Id;
var genderRate = serialized.GenderRatio;
if (genderRate < -1.0 || genderRate > 100.0)
{
throw new InvalidDataException(
$"Gender rate for species {id} is invalid: {genderRate}. Must be between -1.0 and 100.0.");
}
if (serialized.EggCycles < 0)
{
throw new InvalidDataException(
$"Egg cycles for species {id} is invalid: {serialized.EggCycles}. Must be greater than or equal to 0.");
}
var forms = serialized.Formes.ToDictionary(x => (StringKey)x.Key,
x => DeserializeForm(x.Key, x.Value, typeLibrary));
var evolutions = serialized.Evolutions.Select(DeserializeEvolution).ToList();
var species = SpeciesConstructor(serialized, serialized.Id, serialized.Species, genderRate, serialized.GrowthRate,
serialized.CatchRate, serialized.BaseHappiness, forms,
var species = SpeciesConstructor(serialized, serialized.Id, serialized.Species, genderRate,
serialized.GrowthRate, serialized.CatchRate, serialized.BaseHappiness, forms,
serialized.Flags.Select(x => new StringKey(x)), evolutions, serialized.EggGroups.Select(x => (StringKey)x));
return species;
}
@ -85,11 +88,15 @@ public static class SpeciesDataLoader
if (form == null)
throw new ArgumentException("Form data is null.", nameof(form));
if (form.Height < 0.0)
{
throw new InvalidDataException(
$"Height for form {name} is invalid: {form.Height}. Must be greater than or equal to 0.0.");
}
if (form.Weight < 0.0)
{
throw new InvalidDataException(
$"Weight for form {name} is invalid: {form.Weight}. Must be greater than or equal to 0.0.");
}
var types = form.Types.Select(x =>
typeLibrary.TryGetTypeIdentifier(new StringKey(x), out var t)
? t
@ -105,25 +112,26 @@ public static class SpeciesDataLoader
{
var learnableMoves = new LearnableMovesImpl();
if (moves.LevelMoves != null)
{
foreach (var levelMove in moves.LevelMoves)
{
learnableMoves.AddLevelMove((byte)levelMove.Level, new StringKey(levelMove.Name));
}
}
if (moves.EggMoves != null)
{
foreach (var eggMove in moves.EggMoves)
{
learnableMoves.AddEggMove(new StringKey(eggMove));
}
}
return learnableMoves;
}
private static ImmutableStatisticSet<ushort> DeserializeStats(SerializedStats stats)
{
return new ImmutableStatisticSet<ushort>(stats.Hp, stats.Attack, stats.Defense, stats.SpecialAttack,
stats.SpecialDefense, stats.Speed);
}
private static ImmutableStatisticSet<ushort> DeserializeStats(SerializedStats stats) =>
new(stats.Hp, stats.Attack, stats.Defense, stats.SpecialAttack, stats.SpecialDefense, stats.Speed);
private static IEvolution DeserializeEvolution(SerializedEvolution evolution)
{
@ -223,8 +231,7 @@ public static class SpeciesDataLoader
{
Name = evolution.Data.AsObject()["type"]?.GetValue<string>() ??
throw new InvalidDataException("Type is null."),
Parameters = evolution.Data.AsObject()
.Where(x => x.Key != "type")
Parameters = evolution.Data.AsObject().Where(x => x.Key != "type")
.ToDictionary(x => new StringKey(x.Key), x => x.Value!.ToParameter()),
ToSpecies = evolution.Species,
},

View File

@ -42,8 +42,10 @@ public static class TypeDataLoader
{
var effectiveness = float.Parse(values[i]);
if (effectiveness < 0.0)
{
throw new InvalidDataException(
$"Effectiveness for {type} against {types[i]} is invalid: {effectiveness}. Must be greater than or equal to 0.0.");
}
library.SetEffectiveness(typeId, (TypeIdentifier)i, effectiveness);
}
}

View File

@ -15,8 +15,5 @@ public class PassTurnAI : PokemonAI
}
/// <inheritdoc />
public override ITurnChoice GetChoice(IBattle battle, IPokemon pokemon)
{
return new PassChoice(pokemon);
}
public override ITurnChoice GetChoice(IBattle battle, IPokemon pokemon) => new PassChoice(pokemon);
}

View File

@ -45,6 +45,4 @@ public class RandomAI : PokemonAI
}
return new PassChoice(pokemon);
}
}

View File

@ -15,7 +15,6 @@ public class ExperienceGainEvent : IEventData
public uint PreviousExperience { get; }
public uint NewExperience { get; }
/// <inheritdoc />
public EventBatchId BatchId { get; init; }
}

View File

@ -30,7 +30,6 @@ public class HealEvent : IEventData
/// </summary>
public uint NewHealth { get; }
/// <inheritdoc />
public EventBatchId BatchId { get; init; } = new();
}

View File

@ -16,7 +16,7 @@ public record struct CaptureResult
public int Shakes { get; init; }
public bool CriticalCapture { get; init; }
public static CaptureResult Failed => new CaptureResult(false, 0, false);
public static CaptureResult Failed => new(false, 0, false);
}
public interface ICaptureLibrary

View File

@ -66,12 +66,13 @@ public class DynamicLibraryImpl : IDynamicLibrary
if (registry.CaptureLibrary is null)
throw new InvalidOperationException("Capture library not found in plugins.");
var scriptResolver = new ScriptResolver(registry.ScriptTypes, registry.ItemScriptTypes);
return new DynamicLibraryImpl(staticLibrary, registry.BattleStatCalculator,
registry.DamageCalculator, registry.MiscLibrary, registry.CaptureLibrary, scriptResolver);
return new DynamicLibraryImpl(staticLibrary, registry.BattleStatCalculator, registry.DamageCalculator,
registry.MiscLibrary, registry.CaptureLibrary, scriptResolver);
}
private DynamicLibraryImpl(IStaticLibrary staticLibrary, IBattleStatCalculator statCalculator,
IDamageCalculator damageCalculator, IMiscLibrary miscLibrary, ICaptureLibrary captureLibrary, ScriptResolver scriptResolver)
IDamageCalculator damageCalculator, IMiscLibrary miscLibrary, ICaptureLibrary captureLibrary,
ScriptResolver scriptResolver)
{
StaticLibrary = staticLibrary;
StatCalculator = statCalculator;

View File

@ -249,8 +249,8 @@ public class BattleImpl : ScriptSource, IBattle
}
ITurnChoice? forcedChoice = null;
pokemon.RunScriptHook(
script => script.ForceTurnSelection(battleData.SideIndex, battleData.Position, ref forcedChoice));
pokemon.RunScriptHook(script =>
script.ForceTurnSelection(battleData.SideIndex, battleData.Position, ref forcedChoice));
choice = forcedChoice;
return choice != null;
}
@ -386,7 +386,6 @@ public class BattleImpl : ScriptSource, IBattle
/// <inheritdoc />
public StringKey? TerrainName => _terrainScript.Script?.Name;
private readonly List<IReadOnlyList<ITurnChoice>> _previousTurnChoices = new();
/// <inheritdoc />

View File

@ -51,7 +51,6 @@ public class BattleChoiceQueue : IDeepCloneable
/// </summary>
public bool HasNext() => _currentIndex < _choices.Length;
/// <summary>
/// This resorts the yet to be executed choices. This can be useful for dealing with situations
/// such as Pokémon changing forms just after the very start of a turn, when turn order has
@ -102,5 +101,6 @@ public class BattleChoiceQueue : IDeepCloneable
internal IReadOnlyList<ITurnChoice?> GetChoices() => _choices;
public ITurnChoice? FirstOrDefault(Func<ITurnChoice, bool> predicate) => _choices.WhereNotNull().FirstOrDefault(predicate);
public ITurnChoice? FirstOrDefault(Func<ITurnChoice, bool> predicate) =>
_choices.WhereNotNull().FirstOrDefault(predicate);
}

View File

@ -31,11 +31,11 @@ internal static class MoveTurnExecutor
moveChoice.Script.Set(script);
}
}
}
var targetType = moveData.Target;
var targets = TargetResolver.ResolveTargets(battle, moveChoice.TargetSide, moveChoice.TargetPosition, targetType);
var targets =
TargetResolver.ResolveTargets(battle, moveChoice.TargetSide, moveChoice.TargetPosition, targetType);
moveChoice.RunScriptHook(x => x.ChangeTargets(moveChoice, ref targets));
byte numberOfHits = 1;
@ -140,8 +140,8 @@ internal static class MoveTurnExecutor
// modifying it.
if (accuracy != 255)
{
accuracy = battle.Library.StatCalculator.CalculateModifiedAccuracy(executingMove, target,
hitIndex, accuracy);
accuracy = battle.Library.StatCalculator.CalculateModifiedAccuracy(executingMove, target, hitIndex,
accuracy);
}
if (accuracy < 100 && battle.Random.GetInt(100) >= accuracy)
@ -198,14 +198,16 @@ internal static class MoveTurnExecutor
if (secondaryEffect != null)
{
var preventSecondary = false;
target.RunScriptHook(x => x.PreventSecondaryEffect(executingMove, target, hitIndex, ref preventSecondary));
target.RunScriptHook(x =>
x.PreventSecondaryEffect(executingMove, target, hitIndex, ref preventSecondary));
if (!preventSecondary)
{
var chance = secondaryEffect.Chance;
if (chance < 0 || battle.Random.EffectChance(chance, executingMove, target, hitIndex))
{
executingMove.RunScriptHook(x => x.OnSecondaryEffect(executingMove, target, hitIndex));
executingMove.RunScriptHook(x =>
x.OnSecondaryEffect(executingMove, target, hitIndex));
}
}
}
@ -224,6 +226,5 @@ internal static class MoveTurnExecutor
{
executingMove.RunScriptHook(x => x.OnAfterHits(executingMove, target));
}
}
}

View File

@ -15,8 +15,8 @@ public static class TargetResolver
return target switch
{
MoveTarget.Adjacent or MoveTarget.AdjacentAlly or MoveTarget.AdjacentAllySelf or MoveTarget.AdjacentOpponent
or MoveTarget.Any or MoveTarget.RandomOpponent
or MoveTarget.SelfUse => [battle.GetPokemon(side, position)],
or MoveTarget.Any or MoveTarget.RandomOpponent or MoveTarget.SelfUse =>
[battle.GetPokemon(side, position)],
MoveTarget.All => GetAllTargets(battle),
MoveTarget.AllAdjacentOpponent => GetAllAdjacentAndOpponent(battle, side, position),
MoveTarget.AllAdjacent => GetAllAdjacent(battle, side, position),
@ -144,7 +144,8 @@ public static class TargetResolver
return
[
battle.GetPokemon(side, position), battle.GetPokemon(side, (byte)left), battle.GetPokemon(side, (byte)right),
battle.GetPokemon(side, position), battle.GetPokemon(side, (byte)left),
battle.GetPokemon(side, (byte)right),
];
}
}

View File

@ -16,8 +16,10 @@ public static class TurnRunner
{
var queue = battle.ChoiceQueue;
if (queue == null)
{
throw new ArgumentNullException(nameof(battle.ChoiceQueue),
"The battle's choice queue must be set before running a turn.");
}
// We are now at the very beginning of a turn. We have assigned speeds and priorities to all
// choices, and put them in the correct order.
@ -122,7 +124,6 @@ public static class TurnRunner
userSide.SwapPokemon(battleData.Position, fleeChoice.SwitchTo);
}
private static void ExecuteFleeChoice(IBattle battle, IFleeChoice fleeChoice)
{
var user = fleeChoice.User;
@ -171,5 +172,4 @@ public static class TurnRunner
}
itemChoice.Item.RunItemScript(battle.Library.ScriptResolver, target ?? user);
}
}

View File

@ -158,6 +158,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
public byte NumberOfPositions { get; }
private readonly IPokemon?[] _pokemon;
/// <inheritdoc />
public IReadOnlyList<IPokemon?> Pokemon => _pokemon;
@ -170,6 +171,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
public bool AllChoicesSet => _setChoices.All(choice => choice is not null);
private readonly bool[] _fillablePositions;
/// <inheritdoc />
public IReadOnlyList<bool> FillablePositions => _fillablePositions;

View File

@ -7,7 +7,6 @@ namespace PkmnLib.Dynamic.Models.Choices;
/// </summary>
public interface IFleeChoice : ITurnChoice
{
}
/// <inheritdoc cref="IFleeChoice"/>
@ -22,7 +21,9 @@ public class FleeTurnChoice : TurnChoice, IFleeChoice
public override int ScriptCount => User.ScriptCount;
/// <inheritdoc />
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts) { }
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts)
{
}
/// <inheritdoc />
public override void CollectScripts(List<IEnumerable<ScriptContainer>> scripts) => User.CollectScripts(scripts);

View File

@ -7,7 +7,6 @@ namespace PkmnLib.Dynamic.Models.Choices;
/// </summary>
public interface IPassChoice : ITurnChoice
{
}
public class PassChoice : TurnChoice, IPassChoice

View File

@ -82,5 +82,5 @@ public class TurnChoiceComparer : IComparer<ITurnChoice>
}
/// <inheritdoc />
public int Compare(ITurnChoice? x, ITurnChoice? y) => (int) CompareImpl(x, y);
public int Compare(ITurnChoice? x, ITurnChoice? y) => (int)CompareImpl(x, y);
}

View File

@ -95,8 +95,7 @@ public class LearnedMoveImpl : ILearnedMove
CurrentPp = MaxPp;
}
public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod, byte pp)
: this(moveData, learnMethod)
public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod, byte pp) : this(moveData, learnMethod)
{
CurrentPp = pp;
}

View File

@ -337,10 +337,12 @@ public interface IPokemon : IScriptSource, IDeepCloneable
/// Checks whether the Pokémon has a specific non-volatile status.
/// </summary>
bool HasStatus(StringKey status);
/// <summary>
/// Adds a non-volatile status to the Pokemon.
/// </summary>
void SetStatus(StringKey status);
/// <summary>
/// Removes the current non-volatile status from the Pokemon.
/// </summary>
@ -686,7 +688,11 @@ public class PokemonImpl : ScriptSource, IPokemon
private List<TypeIdentifier> _types = new();
/// <inheritdoc />
public IReadOnlyList<TypeIdentifier> Types { get => _types; private set => _types = value.ToList(); }
public IReadOnlyList<TypeIdentifier> Types
{
get => _types;
private set => _types = value.ToList();
}
/// <inheritdoc />
public bool IsEgg { get; private set; }
@ -989,7 +995,7 @@ public class PokemonImpl : ScriptSource, IPokemon
{
if (IsFainted && !allowRevive)
return false;
var maxAmount = this.BoostedStats.Hp - CurrentHealth;
var maxAmount = BoostedStats.Hp - CurrentHealth;
if (heal > maxAmount)
heal = maxAmount;
if (heal == 0)
@ -1019,7 +1025,8 @@ public class PokemonImpl : ScriptSource, IPokemon
{
for (byte i = 0; i < Moves.Count; i++)
{
if (Moves[i] is not null) continue;
if (Moves[i] is not null)
continue;
index = i;
break;
}

View File

@ -46,7 +46,6 @@ public class PokemonParty : IPokemonParty
_pokemon = new IPokemon[size];
}
/// <inheritdoc />
public event EventHandler<(IPokemon?, int index)>? OnSwapInto;
@ -73,7 +72,6 @@ public class PokemonParty : IPokemonParty
OnSwap?.Invoke(this, (index1, index2));
}
/// <inheritdoc />
public bool HasUsablePokemon() => _pokemon.Any(p => p is { IsUsable: true });

View File

@ -13,7 +13,6 @@ public abstract class ItemScript : IDeepCloneable
protected IItem Item { get; private set; }
/// <summary>
/// Initializes the script with the given parameters for a specific item
/// </summary>

View File

@ -3,8 +3,7 @@ using PkmnLib.Static.Utils;
namespace PkmnLib.Dynamic.ScriptHandling.Registry;
[AttributeUsage(AttributeTargets.Class)]
[MeansImplicitUse]
[AttributeUsage(AttributeTargets.Class), MeansImplicitUse]
public class ItemScriptAttribute : Attribute
{
/// <summary>

View File

@ -6,8 +6,7 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry;
/// <summary>
/// Helper attribute to register scripts through reflection.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
[MeansImplicitUse]
[AttributeUsage(AttributeTargets.Class, Inherited = false), MeansImplicitUse]
public class ScriptAttribute : Attribute
{
/// <summary>

View File

@ -83,32 +83,32 @@ public class ScriptRegistry
// This is more performant than using Activator.CreateInstance.
var parameterExpression = Expression.Parameter(typeof(IItem), "item");
var newExpression = Expression.New(constructor, parameterExpression);
_itemScriptTypes[name] = Expression.Lambda<Func<IItem, ItemScript>>(newExpression, parameterExpression).Compile();
_itemScriptTypes[name] =
Expression.Lambda<Func<IItem, ItemScript>>(newExpression, parameterExpression).Compile();
}
/// <summary>
/// Register a battle stat calculator.
/// </summary>
public void RegisterBattleStatCalculator<T>(T battleStatCalculator)
where T : IBattleStatCalculator => _battleStatCalculator = battleStatCalculator;
public void RegisterBattleStatCalculator<T>(T battleStatCalculator) where T : IBattleStatCalculator =>
_battleStatCalculator = battleStatCalculator;
/// <summary>
/// Register a damage calculator.
/// </summary>
public void RegisterDamageCalculator<T>(T damageCalculator)
where T : IDamageCalculator => _damageCalculator = damageCalculator;
public void RegisterDamageCalculator<T>(T damageCalculator) where T : IDamageCalculator =>
_damageCalculator = damageCalculator;
/// <summary>
/// Register a misc library.
/// </summary>
public void RegisterMiscLibrary<T>(T miscLibrary) where T : IMiscLibrary
=> _miscLibrary = miscLibrary;
public void RegisterMiscLibrary<T>(T miscLibrary) where T : IMiscLibrary => _miscLibrary = miscLibrary;
/// <summary>
/// Register a capture library.
/// </summary>
public void RegisterCaptureLibrary<T>(T captureLibrary) where T : ICaptureLibrary
=> _captureLibrary = captureLibrary;
public void RegisterCaptureLibrary<T>(T captureLibrary) where T : ICaptureLibrary =>
_captureLibrary = captureLibrary;
internal IReadOnlyDictionary<(ScriptCategory category, StringKey name), Func<Script>> ScriptTypes => _scriptTypes;
internal IReadOnlyDictionary<StringKey, Func<IItem, ItemScript>> ItemScriptTypes => _itemScriptTypes;

View File

@ -555,7 +555,8 @@ public abstract class Script : IDeepCloneable
{
}
public virtual void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy)
public virtual void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
ref int modifiedAccuracy)
{
}
}

View File

@ -38,11 +38,7 @@ public class ScriptContainer : IEnumerable<ScriptContainer>, IDeepCloneable
yield return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <summary>
/// Assigns a new script to this container. If there was a script already, it is removed.

View File

@ -66,5 +66,4 @@ public static class ScriptExecution
itemScript.OnUse();
}
}
}

View File

@ -46,14 +46,8 @@ public class ScriptIterator : IEnumerable<ScriptContainer>
}
/// <inheritdoc />
public IEnumerator<ScriptContainer> GetEnumerator()
{
return GetAsEnumerable().GetEnumerator();
}
public IEnumerator<ScriptContainer> GetEnumerator() => GetAsEnumerable().GetEnumerator();
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

View File

@ -155,8 +155,5 @@ public class ScriptSet : IScriptSet
/// <inheritdoc />
public IEnumerable<StringKey> GetScriptNames() =>
_scripts
.Select(x => x.Script)
.WhereNotNull()
.Select(s => s.Name);
_scripts.Select(x => x.Script).WhereNotNull().Select(s => s.Name);
}

View File

@ -64,13 +64,14 @@ public class LookupGrowthRate : IGrowthRate
}
}
return (LevelInt)(_experienceTable.Length);
return (LevelInt)_experienceTable.Length;
}
/// <inheritdoc />
public uint CalculateExperience(LevelInt level)
{
if (level < 1) level = 1;
if (level < 1)
level = 1;
return level >= _experienceTable.Length ? _experienceTable[^1] : _experienceTable[level - 1];
}
}

View File

@ -160,10 +160,6 @@ public class ItemImpl : IItem
/// <inheritdoc />
public byte FlingPower { get; }
/// <inheritdoc />
public bool HasFlag(string key)
{
return Flags.Contains(key);
}
public bool HasFlag(string key) => Flags.Contains(key);
}

View File

@ -7,13 +7,13 @@ namespace PkmnLib.Static.Libraries;
/// <summary>
/// A basic library for data types. Stores data both by name and by index.
/// </summary>
public abstract class DataLibrary<T> : IEnumerable<T>
where T : INamedValue
public abstract class DataLibrary<T> : IEnumerable<T> where T : INamedValue
{
/// <summary>
/// The underlying data storage.
/// </summary>
protected readonly Dictionary<StringKey, T> Data = new();
private readonly List<T> _values = [];
/// <summary>

View File

@ -12,14 +12,17 @@ public interface IReadOnlyGrowthRateLibrary : IEnumerable<IGrowthRate>
/// Tries to get a growth rate from the library. Returns false if the growth rate is not found.
/// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out IGrowthRate value);
/// <summary>
/// Gets a random growth rate from the library.
/// </summary>
IGrowthRate GetRandom(IRandom random);
/// <summary>
/// Gets the amount of growth rates in the library.
/// </summary>
int Count { get; }
/// <summary>
/// Whether the library is empty.
/// </summary>

View File

@ -13,14 +13,17 @@ public interface IReadOnlyMoveLibrary : IEnumerable<IMoveData>
/// Tries to get a move from the library. Returns false if the move is not found.
/// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out IMoveData value);
/// <summary>
/// Gets a random move from the library.
/// </summary>
IMoveData GetRandom(IRandom random);
/// <summary>
/// The amount of moves in the library.
/// </summary>
int Count { get; }
/// <summary>
/// Whether the library is empty.
/// </summary>

View File

@ -9,22 +9,27 @@ public interface IStaticLibrary
/// The miscellaneous settings for the library.
/// </summary>
LibrarySettings Settings { get; }
/// <summary>
/// All data for Pokémon species.
/// </summary>
IReadOnlySpeciesLibrary Species { get; }
/// <summary>
/// All data for Pokémon moves.
/// </summary>
IReadOnlyMoveLibrary Moves { get; }
/// <summary>
/// All data for Pokémon abilities.
/// </summary>
IReadOnlyAbilityLibrary Abilities { get; }
/// <summary>
/// All data for Pokémon types and their effectiveness.
/// </summary>
IReadOnlyTypeLibrary Types { get; }
/// <summary>
/// All data for Pokémon natures.
/// </summary>
@ -45,7 +50,9 @@ public interface IStaticLibrary
public class StaticLibraryImpl : IStaticLibrary
{
/// <inheritdoc cref="StaticLibraryImpl" />
public StaticLibraryImpl(LibrarySettings settings, IReadOnlySpeciesLibrary species, IReadOnlyMoveLibrary moves, IReadOnlyAbilityLibrary abilities, IReadOnlyTypeLibrary types, IReadOnlyNatureLibrary natures, IReadOnlyGrowthRateLibrary growthRates, IReadOnlyItemLibrary items)
public StaticLibraryImpl(LibrarySettings settings, IReadOnlySpeciesLibrary species, IReadOnlyMoveLibrary moves,
IReadOnlyAbilityLibrary abilities, IReadOnlyTypeLibrary types, IReadOnlyNatureLibrary natures,
IReadOnlyGrowthRateLibrary growthRates, IReadOnlyItemLibrary items)
{
Settings = settings;
Species = species;

View File

@ -88,7 +88,7 @@ public class TypeLibrary : IReadOnlyTypeLibrary
/// </summary>
public TypeIdentifier RegisterType(StringKey name)
{
var id = new TypeIdentifier((byte)( _types.Count + 1));
var id = new TypeIdentifier((byte)(_types.Count + 1));
_types.Add(name, id);
_effectiveness.Add(Enumerable.Repeat(1.0f, _effectiveness.Count).ToList());
foreach (var list in _effectiveness)

View File

@ -50,8 +50,7 @@ public class Nature(
Statistic increaseStat,
Statistic decreaseStat,
float increaseModifier,
float decreaseModifier)
: INature
float decreaseModifier) : INature
{
/// <inheritdoc />
public StringKey Name { get; } = name;
@ -79,8 +78,6 @@ public class Nature(
}
/// <inheritdoc />
public bool Equals(INature? other)
{
return other is not null && StringComparer.InvariantCultureIgnoreCase.Equals(Name, other.Name);
}
public bool Equals(INature? other) =>
other is not null && StringComparer.InvariantCultureIgnoreCase.Equals(Name, other.Name);
}

View File

@ -26,7 +26,8 @@ public interface IAbility : INamedValue
public class AbilityImpl : IAbility
{
/// <inheritdoc cref="AbilityImpl" />
public AbilityImpl(StringKey name, StringKey? effect, IReadOnlyDictionary<StringKey, object?> parameters, ImmutableHashSet<StringKey> flags)
public AbilityImpl(StringKey name, StringKey? effect, IReadOnlyDictionary<StringKey, object?> parameters,
ImmutableHashSet<StringKey> flags)
{
Name = name;
Effect = effect;
@ -46,10 +47,7 @@ public class AbilityImpl : IAbility
public ImmutableHashSet<StringKey> Flags;
/// <inheritdoc />
public bool HasFlag(StringKey key)
{
return Flags.Contains(key);
}
public bool HasFlag(StringKey key) => Flags.Contains(key);
}
/// <summary>

View File

@ -95,8 +95,8 @@ public interface IForm : INamedValue
public class FormImpl : IForm
{
/// <inheritdoc cref="FormImpl" />
public FormImpl(StringKey name, float height, float weight, uint baseExperience,
IEnumerable<TypeIdentifier> types, ImmutableStatisticSet<ushort> baseStats, IEnumerable<StringKey> abilities,
public FormImpl(StringKey name, float height, float weight, uint baseExperience, IEnumerable<TypeIdentifier> types,
ImmutableStatisticSet<ushort> baseStats, IEnumerable<StringKey> abilities,
IEnumerable<StringKey> hiddenAbilities, ILearnableMoves moves, ImmutableHashSet<StringKey> flags)
{
Name = name;
@ -163,20 +163,24 @@ public class FormImpl : IForm
for (var i = 0; i < Abilities.Count && i < 255; i++)
{
if (Abilities[i] == ability.Name)
{
return new AbilityIndex
{
IsHidden = false,
Index = (byte)i,
};
}
}
for (var i = 0; i < HiddenAbilities.Count && i < 255; i++)
{
if (HiddenAbilities[i] == ability.Name)
{
return new AbilityIndex
{
IsHidden = true,
Index = (byte)i,
};
}
}
return null;
}
@ -191,20 +195,11 @@ public class FormImpl : IForm
}
/// <inheritdoc />
public StringKey GetRandomAbility(IRandom rand)
{
return Abilities[rand.GetInt(Abilities.Count)];
}
public StringKey GetRandomAbility(IRandom rand) => Abilities[rand.GetInt(Abilities.Count)];
/// <inheritdoc />
public StringKey GetRandomHiddenAbility(IRandom rand)
{
return HiddenAbilities[rand.GetInt(HiddenAbilities.Count)];
}
public StringKey GetRandomHiddenAbility(IRandom rand) => HiddenAbilities[rand.GetInt(HiddenAbilities.Count)];
/// <inheritdoc />
public bool HasFlag(string key)
{
return Flags.Contains(key);
}
public bool HasFlag(string key) => Flags.Contains(key);
}

View File

@ -10,10 +10,12 @@ public enum Gender : byte
{
/// The Pokémon has no gender.
Genderless,
/// <summary>
/// The Pokémon is male.
/// </summary>
Male,
/// <summary>
/// The Pokémon is female.
/// </summary>

View File

@ -53,7 +53,6 @@ public class LearnableMovesImpl : ILearnableMoves
private readonly List<StringKey> _eggMoves = new();
/// <inheritdoc />
public void AddLevelMove(LevelInt level, StringKey move)
{
@ -81,10 +80,7 @@ public class LearnableMovesImpl : ILearnableMoves
}
/// <inheritdoc />
public IReadOnlyList<StringKey> GetDistinctLevelMoves()
{
return _distinctLevelMoves.ToList();
}
public IReadOnlyList<StringKey> GetDistinctLevelMoves() => _distinctLevelMoves.ToList();
/// <inheritdoc />
public IReadOnlyList<StringKey> GetLearnableMovesUpToLevel(LevelInt level)

View File

@ -131,7 +131,6 @@ public class SpeciesImpl : ISpecies
/// <inheritdoc />
public ICollection<StringKey> EggGroups { get; }
/// <inheritdoc />
public bool TryGetForm(StringKey id, [MaybeNullWhen(false)] out IForm form) => Forms.TryGetValue(id, out form);

View File

@ -9,22 +9,27 @@ public enum Statistic : byte
/// Health Points determine how much damage a Pokémon can receive before fainting.
/// </summary>
Hp,
/// <summary>
/// Attack determines how much damage a Pokémon deals when using a physical attack.
/// </summary>
Attack,
/// <summary>
/// Defense determines how much damage a Pokémon receives when it is hit by a physical attack.
/// </summary>
Defense,
/// <summary>
/// Special Attack determines how much damage a Pokémon deals when using a special attack.
/// </summary>
SpecialAttack,
/// <summary>
/// Special Defense determines how much damage a Pokémon receives when it is hit by a special attack.
/// </summary>
SpecialDefense,
/// <summary>
/// Speed determines the order that a Pokémon can act in battle.
/// </summary>

View File

@ -8,8 +8,7 @@ namespace PkmnLib.Static;
/// A set of statistics that cannot be changed.
/// </summary>
/// <typeparam name="T">The size of the integer to be used</typeparam>
public record ImmutableStatisticSet<T>
where T : struct
public record ImmutableStatisticSet<T> where T : struct
{
/// <summary>
/// The health points stat value.
@ -84,8 +83,7 @@ public record ImmutableStatisticSet<T>
/// A set of statistics that can be changed.
/// </summary>
/// <typeparam name="T"></typeparam>
public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<T>, IDeepCloneable
where T : struct
public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<T>, IDeepCloneable where T : struct
{
/// <inheritdoc cref="StatisticSet{T}"/>
public StatisticSet() : base(default, default, default, default, default, default)
@ -175,17 +173,13 @@ public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<T>, IDeepC
return true;
}
protected virtual T GetUnknownStat(Statistic stat)
{
throw new ArgumentException($"Invalid statistic {stat}");
}
protected virtual T GetUnknownStat(Statistic stat) => throw new ArgumentException($"Invalid statistic {stat}");
protected virtual void SetUnknownStat(Statistic stat, T value)
{
throw new ArgumentException($"Invalid statistic {stat}");
}
/// <summary>
/// Decreases a statistic in the set by a value.
/// </summary>
@ -231,17 +225,13 @@ public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<T>, IDeepC
}
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
/// <summary>
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value.
/// </summary>
public abstract record ClampedStatisticSet<T> : StatisticSet<T>
where T : struct, IComparable<T>
public abstract record ClampedStatisticSet<T> : StatisticSet<T> where T : struct, IComparable<T>
{
/// <inheritdoc />
[SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")]
@ -322,6 +312,7 @@ public record StatBoostStatisticSet : ClampedStatisticSet<sbyte>
protected override sbyte Max => 6;
private sbyte _evasion;
public sbyte Evasion
{
get => _evasion;
@ -329,6 +320,7 @@ public record StatBoostStatisticSet : ClampedStatisticSet<sbyte>
}
private sbyte _accuracy;
public sbyte Accuracy
{
get => _accuracy;

View File

@ -25,10 +25,8 @@ public static class DeepCloneHandler
/// Recursive references will be handled correctly, and will only be cloned once, to prevent infinite loops and invalid
/// references.
/// </summary>
public static T DeepClone<T>(this T? obj, Dictionary<(Type, int), object>? objects = null) where T : IDeepCloneable
{
return (T)DeepClone((object?)obj, objects)!;
}
public static T DeepClone<T>(this T? obj, Dictionary<(Type, int), object>? objects = null)
where T : IDeepCloneable => (T)DeepClone((object?)obj, objects)!;
private static object? DeepClone(this object? obj, Dictionary<(Type, int), object>? objects = null)
{
@ -91,8 +89,9 @@ public static class DeepCloneHandler
var array = (Array)obj;
var newArray = Array.CreateInstance(type.GetElementType()!, array.Length);
for (var i = 0; i < array.Length; i++)
newArray.SetValue(DeepCloneInternal(array.GetValue(i), type.GetElementType()!, objects),
i);
{
newArray.SetValue(DeepCloneInternal(array.GetValue(i), type.GetElementType()!, objects), i);
}
return newArray;
}
@ -115,9 +114,10 @@ public static class DeepCloneHandler
var dictionary = (IDictionary)obj;
var newDictionary = (IDictionary)Activator.CreateInstance(type);
foreach (DictionaryEntry entry in dictionary)
newDictionary.Add(
DeepCloneInternal(entry.Key, type.GetGenericArguments()[0], objects)!,
{
newDictionary.Add(DeepCloneInternal(entry.Key, type.GetGenericArguments()[0], objects)!,
DeepCloneInternal(entry.Value, type.GetGenericArguments()[1], objects));
}
return newDictionary;
}
}
@ -133,8 +133,7 @@ public static class DeepCloneHandler
/// This method is thread safe, and will only create the expressions once for each type. It returns compiled expressions for
/// each field in the type, so that we can get high performance deep cloning.
/// </remarks>
private static (Func<object, object?> getter, Action<object, object?> setter)[]
GetDeepCloneExpressions(Type type)
private static (Func<object, object?> getter, Action<object, object?> setter)[] GetDeepCloneExpressions(Type type)
{
// We use a lock here to prevent multiple threads from trying to create the expressions at the same time.
lock (DeepCloneExpressions)

View File

@ -2,7 +2,8 @@ namespace PkmnLib.Static.Utils;
public static class DictionaryHelpers
{
public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key,
TValue defaultValue)
{
if (dictionary.TryGetValue(key, out var value))
return value;

View File

@ -1,4 +1,3 @@
namespace PkmnLib.Static.Utils.Errors;
/// <summary>

View File

@ -55,5 +55,4 @@ public static class NumericHelpers
var result = (ulong)value * multiplier;
return result > uint.MaxValue ? uint.MaxValue : (uint)result;
}
}

View File

@ -26,10 +26,8 @@ public readonly record struct StringKey
/// <summary>
/// Converts a <see cref="string"/> to a <see cref="StringKey"/>.
/// </summary>
public static implicit operator StringKey(string key)
{
return string.IsNullOrWhiteSpace(key) ? default : new StringKey(key);
}
public static implicit operator StringKey(string key) =>
string.IsNullOrWhiteSpace(key) ? default : new StringKey(key);
/// <inheritdoc cref="string.ToString()"/>
public override string ToString() => _key.ToLowerInvariant();

View File

@ -10,10 +10,7 @@ public class MoveDataTests
public record TestCaseData(IDynamicLibrary Library, IMoveData Move)
{
/// <inheritdoc />
public override string ToString()
{
return Move.Name + " has valid scripts";
}
public override string ToString() => Move.Name + " has valid scripts";
}
public static IEnumerable<TestCaseData> AllMovesHaveValidScriptsData()
@ -28,8 +25,7 @@ public class MoveDataTests
}
}
[Test]
[MethodDataSource(nameof(AllMovesHaveValidScriptsData))]
[Test, MethodDataSource(nameof(AllMovesHaveValidScriptsData))]
public async Task AllMoveEffectsHaveValidScripts(TestCaseData test)
{
if (test.Move.SecondaryEffect == null)
@ -43,7 +39,8 @@ public class MoveDataTests
}
catch (Exception e)
{
throw new AggregateException($"Failed to resolve script for move {test.Move.Name} with effect {scriptName}", e);
throw new AggregateException($"Failed to resolve script for move {test.Move.Name} with effect {scriptName}",
e);
}
}
}

View File

@ -1,4 +1,3 @@
global using TUnit;
global using FluentAssertions;
global using LevelInt = byte;

View File

@ -26,8 +26,7 @@ public class IntegrationTestRunner
}
}
[Test]
[MethodDataSource(nameof(TestCases))]
[Test, MethodDataSource(nameof(TestCases))]
public async Task RunIntegrationTest(IntegrationTestModel test)
{
var library = LibraryHelpers.LoadLibrary();
@ -40,11 +39,10 @@ public class IntegrationTestRunner
var pokemon = x.Pokemon[index];
await Assert.That(library.StaticLibrary.Species.TryGet(pokemon.Species, out var species)).IsTrue();
var mon = new PokemonImpl(library, species!, species!.GetDefaultForm(), new AbilityIndex
{
IsHidden = false,
Index = 0,
},
pokemon.Level, 0, Gender.Genderless, 0, "hardy");
{
IsHidden = false,
Index = 0,
}, pokemon.Level, 0, Gender.Genderless, 0, "hardy");
foreach (var move in pokemon.Moves)
{
mon.LearnMove(move, MoveLearnMethod.Unknown, 255);
@ -56,7 +54,7 @@ public class IntegrationTestRunner
return new BattlePartyImpl(party, x.Indices.Select(y => new ResponsibleIndex(y[0], y[1])).ToArray());
}).ProcessOneAtATime().GetResultsAsync();
var battle = new BattleImpl(library, parties, test.BattleSetup.CanFlee, test.BattleSetup.NumberOfSides,
test.BattleSetup.PositionsPerSide, randomSeed: test.BattleSetup.Seed);
test.BattleSetup.PositionsPerSide, test.BattleSetup.Seed);
foreach (var action in test.Actions)
{

View File

@ -7,11 +7,8 @@ using JsonSerializer = System.Text.Json.JsonSerializer;
namespace PkmnLib.Tests.Integration.Models;
[JsonDerivedType(typeof(SetPokemonAction), "setPokemon")]
[JsonDerivedType(typeof(SetMoveChoiceAction), "setMoveChoice")]
[JsonDerivedType(typeof(SetPassChoiceAction), "setPassChoice")]
[JsonDerivedType(typeof(AssertAction), "assert")]
[JsonDerivedType(typeof(SetPokemonAction), "setPokemon"), JsonDerivedType(typeof(SetMoveChoiceAction), "setMoveChoice"),
JsonDerivedType(typeof(SetPassChoiceAction), "setPassChoice"), JsonDerivedType(typeof(AssertAction), "assert")]
public abstract class IntegrationTestAction
{
public abstract Task Execute(IBattle battle);
@ -36,7 +33,6 @@ public class SetMoveChoiceAction : IntegrationTestAction
public string Move { get; set; } = null!;
public List<byte> Target { get; set; } = null!;
/// <inheritdoc />
public override async Task Execute(IBattle battle)
{

View File

@ -8,10 +8,7 @@ public class IntegrationTestModel
public IntegrationTestAction[] Actions { get; set; } = null!;
/// <inheritdoc />
public override string ToString()
{
return Name;
}
public override string ToString() => Name;
}
public class IntegrationTestBattleSetup

View File

@ -11,8 +11,7 @@ namespace PkmnLib.Tests.Static;
public class DeepCloneTests
{
[SuppressMessage("ReSharper", "UnusedMember.Local")]
[SuppressMessage("ReSharper", "ValueParameterNotUsed")]
[SuppressMessage("ReSharper", "UnusedMember.Local"), SuppressMessage("ReSharper", "ValueParameterNotUsed")]
private class TestClass : IDeepCloneable
{
public int Value { get; set; }
@ -70,8 +69,7 @@ public class DeepCloneTests
var clone = obj.DeepClone();
await Assert.That(clone).IsNotEqualTo(obj);
var clonePrivateField =
clone.GetType().GetField("_privateField", BindingFlags.NonPublic | BindingFlags.Instance)!
.GetValue(clone);
clone.GetType().GetField("_privateField", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(clone);
await Assert.That(clonePrivateField).IsEqualTo(1);
}
@ -93,28 +91,24 @@ public class DeepCloneTests
await Assert.That(library.StaticLibrary.Species.TryGet("bulbasaur", out var bulbasaur)).IsTrue();
await Assert.That(library.StaticLibrary.Species.TryGet("charmander", out var charmander)).IsTrue();
var party1 = new PokemonParty(6);
party1.SwapInto(new PokemonImpl(library, bulbasaur!,
bulbasaur!.GetDefaultForm(), new AbilityIndex
{
IsHidden = false,
Index = 0,
}, 50, 0,
Gender.Male, 0, "hardy"), 0);
party1.SwapInto(new PokemonImpl(library, bulbasaur!, bulbasaur!.GetDefaultForm(), new AbilityIndex
{
IsHidden = false,
Index = 0,
}, 50, 0, Gender.Male, 0, "hardy"), 0);
var party2 = new PokemonParty(6);
party2.SwapInto(new PokemonImpl(library, charmander!,
charmander!.GetDefaultForm(), new AbilityIndex
{
IsHidden = false,
Index = 0,
}, 50, 0,
Gender.Male, 0, "hardy"), 0);
party2.SwapInto(new PokemonImpl(library, charmander!, charmander!.GetDefaultForm(), new AbilityIndex
{
IsHidden = false,
Index = 0,
}, 50, 0, Gender.Male, 0, "hardy"), 0);
var parties = new[]
{
new BattlePartyImpl(party1, [new ResponsibleIndex(0, 0)]),
new BattlePartyImpl(party2, [new ResponsibleIndex(1, 0)]),
};
var battle = new BattleImpl(library, parties, false, 2, 3, randomSeed: 0);
var battle = new BattleImpl(library, parties, false, 2, 3, 0);
battle.Sides[0].SwapPokemon(0, party1[0]);
battle.Sides[1].SwapPokemon(0, party2[0]);
party1[0]!.ChangeStatBoost(Statistic.Defense, 2, true);

View File

@ -21,8 +21,10 @@ public class GrowthRateTests
[Test]
public void TooLargeLookupGrowthRateTestShouldThrowArgumentException()
{
Action act = () => _ = new LookupGrowthRate("Test", Enumerable.Range(0, LevelInt.MaxValue + 1).Select(i => (uint)i));
act.Should().Throw<ArgumentException>().WithMessage($"Experience table may have at most {LevelInt.MaxValue} entries.");
Action act = () =>
_ = new LookupGrowthRate("Test", Enumerable.Range(0, LevelInt.MaxValue + 1).Select(i => (uint)i));
act.Should().Throw<ArgumentException>()
.WithMessage($"Experience table may have at most {LevelInt.MaxValue} entries.");
}
[Test]

View File

@ -15,8 +15,7 @@ public class StringKeyTests
yield return () => ("TeSt", "tesv", false);
}
[Test]
[MethodDataSource(nameof(StringKeyEqualityTestCases))]
[Test, MethodDataSource(nameof(StringKeyEqualityTestCases))]
public async Task StringKeyEqualityTest(string k1, string k2, bool expected)
{
var sk1 = new StringKey(k1);
@ -24,8 +23,7 @@ public class StringKeyTests
await Assert.That(sk1 == sk2).IsEqualTo(expected);
}
[Test]
[MethodDataSource(nameof(StringKeyEqualityTestCases))]
[Test, MethodDataSource(nameof(StringKeyEqualityTestCases))]
public async Task HashCodeEqualityTest(string k1, string k2, bool expected)
{
var sk1 = new StringKey(k1);
@ -33,8 +31,7 @@ public class StringKeyTests
await Assert.That(sk1.GetHashCode() == sk2.GetHashCode()).IsEqualTo(expected);
}
[Test]
[MethodDataSource(nameof(StringKeyEqualityTestCases))]
[Test, MethodDataSource(nameof(StringKeyEqualityTestCases))]
public async Task HashSetEqualityTest(string k1, string k2, bool expected)
{
var sk1 = new StringKey(k1);

View File

@ -27,15 +27,13 @@ public class DamageCalculatorTests
// Imagine a level 75 Glaceon
attacker.Setup(x => x.Level).Returns(75);
// with an effective Attack stat of 123
attacker.Setup(x => x.BoostedStats).Returns(new StatisticSet<uint>(
1, 123, 1, 1, 1, 1));
attacker.Setup(x => x.BoostedStats).Returns(new StatisticSet<uint>(1, 123, 1, 1, 1, 1));
// We use 10 as the Ice type
attacker.Setup(x => x.Types).Returns([new TypeIdentifier(10)]);
var defender = new Mock<IPokemon>();
// a Garchomp with an effective Defense stat of 163
defender.Setup(x => x.BoostedStats).Returns(new StatisticSet<uint>(
1, 1, 163, 1, 1, 1));
defender.Setup(x => x.BoostedStats).Returns(new StatisticSet<uint>(1, 1, 163, 1, 1, 1));
defender.Setup(x => x.GetScripts()).Returns(new ScriptIterator([]));
var useMove = new Mock<IMoveData>();

View File

@ -59,5 +59,4 @@ public class AcrobaticsTests
// Assert
await Assert.That(basePower).IsEqualTo(byte.MaxValue);
}
}

View File

@ -44,15 +44,18 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
var flatStat = CalculateFlatStat(pokemon, stat);
var boostModifier = GetStatBoostModifier(pokemon, stat);
var boostedStat = flatStat * boostModifier;
if (boostedStat > uint.MaxValue) boostedStat = uint.MaxValue;
if (boostedStat > uint.MaxValue)
boostedStat = uint.MaxValue;
return (uint)boostedStat;
}
/// <inheritdoc />
public byte CalculateModifiedAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, byte moveAccuracy)
public byte CalculateModifiedAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
byte moveAccuracy)
{
var accuracyModifier = 1.0f;
executingMove.RunScriptHook(x => x.ChangeAccuracyModifier(executingMove, target, hitIndex, ref accuracyModifier));
executingMove.RunScriptHook(
x => x.ChangeAccuracyModifier(executingMove, target, hitIndex, ref accuracyModifier));
var modifiedAccuracy = (int)(moveAccuracy * accuracyModifier);
executingMove.RunScriptHook(x => x.ChangeAccuracy(executingMove, target, hitIndex, ref modifiedAccuracy));
var targetEvasion = target.StatBoost.Evasion;
@ -66,14 +69,14 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
{
> 0 => 3.0f / (3.0f + Math.Min(difference, 6)),
< 0 => 3.0f + -Math.Max(difference, -6) / 3.0f,
_ => 1.0f
_ => 1.0f,
};
modifiedAccuracy = (int)(modifiedAccuracy * statModifier);
modifiedAccuracy = modifiedAccuracy switch
{
> 255 => 255,
< 0 => 0,
_ => modifiedAccuracy
_ => modifiedAccuracy,
};
// NOTE: the main games also consider friendship here, but we don't yet have the concept of a "player Pokémon"
// in the battle system, so for now we're just ignoring that.
@ -86,8 +89,9 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
var iv = (ulong)pokemon.IndividualValues.Hp;
var ev = (ulong)pokemon.EffortValues.Hp;
var level = (ulong)pokemon.Level;
var health = (((2 * baseValue + iv + (ev / 4)) * level) / 100) + level + 10;
if (health > uint.MaxValue) health = uint.MaxValue;
var health = (2 * baseValue + iv + ev / 4) * level / 100 + level + 10;
if (health > uint.MaxValue)
health = uint.MaxValue;
return (uint)health;
}
@ -97,10 +101,11 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
var iv = (ulong)pokemon.IndividualValues.GetStatistic(statistic);
var ev = (ulong)pokemon.EffortValues.GetStatistic(statistic);
var level = (ulong)pokemon.Level;
var unmodified = (((2 * baseValue + iv + (ev / 4)) * level) / 100) + 5;
var unmodified = (2 * baseValue + iv + ev / 4) * level / 100 + 5;
var natureModifier = pokemon.Nature.GetStatModifier(statistic);
var modified = (unmodified * natureModifier);
if (modified > uint.MaxValue) modified = uint.MaxValue;
var modified = unmodified * natureModifier;
if (modified > uint.MaxValue)
modified = uint.MaxValue;
return (uint)modified;
}
@ -122,7 +127,7 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
4 => 6.0f / 2.0f,
5 => 7.0f / 2.0f,
6 => 8.0f / 2.0f,
_ => throw new System.ArgumentException("Stat boost was out of expected range of -6 to 6"),
_ => throw new ArgumentException("Stat boost was out of expected range of -6 to 6"),
};
}
}

View File

@ -23,11 +23,10 @@ public class Gen7CaptureLibrary : ICaptureLibrary
byte bonusStatus = 1;
target.RunScriptHook(x => x.ChangeCatchRateBonus(target, captureItem, ref bonusStatus));
var modifiedCatchRate =
(((3.0 * maxHealth) - (2.0 * currentHealth)) * catchRate * bonusBall) / (3.0 * maxHealth);
var modifiedCatchRate = (3.0 * maxHealth - 2.0 * currentHealth) * catchRate * bonusBall / (3.0 * maxHealth);
modifiedCatchRate *= bonusStatus;
var shakeProbability = 65536 / Math.Pow((255 / modifiedCatchRate), 0.1875);
var shakeProbability = 65536 / Math.Pow(255 / modifiedCatchRate, 0.1875);
byte shakes = 0;
if (modifiedCatchRate >= 255)
{

View File

@ -17,7 +17,7 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
if (hitData.Effectiveness == 0)
return 0;
var levelModifier = (2.0f * executingMove.User.Level) / 5.0f + 2.0f;
var levelModifier = 2.0f * executingMove.User.Level / 5.0f + 2.0f;
var basePower = (float)hitData.BasePower;
var statModifier = GetStatModifier(executingMove, target, hitNumber, hitData);
var damageModifier = GetDamageModifier(executingMove, target, hitNumber);
@ -62,10 +62,8 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
< 1 => 1,
_ => (uint)floatDamage,
};
executingMove.RunScriptHook(script =>
script.ChangeMoveDamage(executingMove, target, hitNumber, ref damage));
target.RunScriptHook(script =>
script.ChangeIncomingMoveDamage(executingMove, target, hitNumber, ref damage));
executingMove.RunScriptHook(script => script.ChangeMoveDamage(executingMove, target, hitNumber, ref damage));
target.RunScriptHook(script => script.ChangeIncomingMoveDamage(executingMove, target, hitNumber, ref damage));
return damage;
}
@ -76,8 +74,7 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
if (executingMove.UseMove.Category == MoveCategory.Status)
return 0;
var basePower = executingMove.UseMove.BasePower;
executingMove.RunScriptHook(script =>
script.ChangeBasePower(executingMove, target, hitNumber, ref basePower));
executingMove.RunScriptHook(script => script.ChangeBasePower(executingMove, target, hitNumber, ref basePower));
return basePower;
}
@ -100,7 +97,8 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
};
}
private static float GetStatModifier(IExecutingMove executingMove, IPokemon target, byte hitNumber, IHitData hitData)
private static float GetStatModifier(IExecutingMove executingMove, IPokemon target, byte hitNumber,
IHitData hitData)
{
var category = executingMove.UseMove.Category;
if (category == MoveCategory.Status)

View File

@ -11,14 +11,12 @@ namespace PkmnLib.Plugin.Gen7.Libraries;
public class Gen7MiscLibrary : IMiscLibrary
{
private readonly IMoveData _struggleData = new MoveDataImpl("struggle", new TypeIdentifier(0),
MoveCategory.Physical, 50,
255, 255, MoveTarget.Any, 0,
MoveCategory.Physical, 50, 255, 255, MoveTarget.Any, 0,
new SecondaryEffectImpl(-1, "struggle", new Dictionary<StringKey, object?>()), []);
/// <inheritdoc />
public ITurnChoice ReplacementChoice(IPokemon user, byte targetSide, byte targetPosition) =>
new MoveChoice(user, new LearnedMoveImpl(_struggleData, MoveLearnMethod.Unknown), targetSide,
targetPosition);
new MoveChoice(user, new LearnedMoveImpl(_struggleData, MoveLearnMethod.Unknown), targetSide, targetPosition);
/// <inheritdoc />
public TimeOfDay GetTimeOfDay()
@ -57,7 +55,7 @@ public class Gen7MiscLibrary : IMiscLibrary
var userSide = battle.Sides[battleData.SideIndex];
userSide.RegisterFleeAttempt();
var fleeChance = ((userSpeed * 32) / (opponentSpeed / 4) + (30 * userSide.FleeAttempts)) / 256;
var fleeChance = (userSpeed * 32 / (opponentSpeed / 4) + 30 * userSide.FleeAttempts) / 256;
var random = battle.Random.GetInt(0, 100);
return random < fleeChance;
}

View File

@ -30,8 +30,5 @@ public class StaticPokeball : PokeballScript
}
/// <inheritdoc />
public override byte GetCatchRate(IPokemon target)
{
return _catchRate;
}
public override byte GetCatchRate(IPokemon target) => _catchRate;
}

View File

@ -3,7 +3,8 @@ using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
[Script(ScriptCategory.MoveVolatile, "electrify")]
public class ElectrifyEffect : Script {
public class ElectrifyEffect : Script
{
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
{

View File

@ -45,7 +45,7 @@ public class AuroraVeil : Script
var numberOfTurns = 5;
var dict = new Dictionary<StringKey, object?>()
{
{ "duration", numberOfTurns }
{ "duration", numberOfTurns },
};
move.User.RunScriptHook(x => x.CustomTrigger(CustomTriggers.AuroraVeilDuration, dict));
numberOfTurns = (int)dict.GetOrDefault("duration", numberOfTurns)!;

View File

@ -24,13 +24,12 @@ public class Autotomize : Script
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var user = move.User;
if (user.ChangeStatBoost(Statistic.Speed, 2, true) &&
user.ChangeWeightInKgBy(-100.0f))
if (user.ChangeStatBoost(Statistic.Speed, 2, true) && user.ChangeWeightInKgBy(-100.0f))
{
var battle = user.BattleData?.Battle;
battle?.EventHook.Invoke(new DialogEvent("pokemon_became_nimble", new Dictionary<string, object>()
{
{ "pokemon", user }
{ "pokemon", user },
}));
}
}

View File

@ -6,8 +6,5 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
public class BanefulBunker : ProtectionScript
{
/// <inheritdoc />
protected override Script GetEffectScript()
{
return new BanefulBunkerEffect();
}
protected override Script GetEffectScript() => new BanefulBunkerEffect();
}

View File

@ -15,7 +15,7 @@ public class BeakBlast : Script
choice.User.Volatile.Add(new BeakBlastEffect());
battleData.Battle.EventHook.Invoke(new DialogEvent("beak_blast_charge", new Dictionary<string, object>()
{
{ "user", choice.User }
{ "user", choice.User },
}));
}

View File

@ -8,6 +8,7 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
public class BeatUp : Script
{
private IPokemon[]? _relevantPartyMembers;
private static IEnumerable<IPokemon> GetRelevantPartyMembers(IPokemon user)
{
var battleData = user.BattleData;

View File

@ -15,7 +15,7 @@ public class Bounce : Script
move.User.Volatile.Add(new ChargeBounceEffect(move.User));
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("bounce_charge", new Dictionary<string, object>()
{
{ "user", move.User }
{ "user", move.User },
}));
prevent = true;
}

View File

@ -30,7 +30,6 @@ public class ChangeMultipleUserStatBoosts : Script
}
}
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{

View File

@ -8,6 +8,6 @@ public class ChipAway : Script
bypass = true;
/// <inheritdoc />
public override void BypassEvasionStatBoosts(IExecutingMove move, IPokemon target, byte hitIndex, ref bool bypass)
=> bypass = true;
public override void
BypassEvasionStatBoosts(IExecutingMove move, IPokemon target, byte hitIndex, ref bool bypass) => bypass = true;
}

View File

@ -27,8 +27,7 @@ public class Conversion2 : Script
if (indexOfNext == -1)
return x;
return x.Take(indexOfNext);
})
.SelectMany(x => x)
}).SelectMany(x => x)
// We only want the last move choice by the target
.OfType<IMoveChoice>().FirstOrDefault(x => x.User == target);
if (lastMoveByTarget == null)
@ -42,11 +41,9 @@ public class Conversion2 : Script
var type = typeLibrary.GetAllEffectivenessFromAttacking(lastMoveByTarget.ChosenMove.MoveData.MoveType)
.Where(x => x.effectiveness < 1)
// Shuffle them randomly, but deterministically
.OrderBy(_ => move.User.BattleData.Battle.Random.GetInt())
.ThenBy(x => x.type.Value)
.OrderBy(_ => move.User.BattleData.Battle.Random.GetInt()).ThenBy(x => x.type.Value)
// And grab the first one
.Select(x => x.type)
.FirstOrDefault();
.Select(x => x.type).FirstOrDefault();
if (type == null)
{
move.GetHitData(target, hit).Fail();

View File

@ -10,9 +10,7 @@ public class Copycat : Script
/// <inheritdoc />
public override void ChangeMove(IMoveChoice choice, ref StringKey moveName)
{
var lastMove = choice.User.BattleData?.Battle.PreviousTurnChoices
.SelectMany(x => x)
.OfType<IMoveChoice>()
var lastMove = choice.User.BattleData?.Battle.PreviousTurnChoices.SelectMany(x => x).OfType<IMoveChoice>()
.LastOrDefault();
if (lastMove == null || !lastMove.ChosenMove.MoveData.CanCopyMove())
{

View File

@ -15,7 +15,7 @@ public class Dig : Script
move.User.Volatile.Add(new DigEffect(move.User));
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dig_charge", new Dictionary<string, object>()
{
{ "user", move.User }
{ "user", move.User },
}));
prevent = true;
}

View File

@ -13,10 +13,7 @@ public class Disable : Script
if (battleData == null)
return;
var choiceQueue = battleData.Battle.PreviousTurnChoices;
var lastMove = choiceQueue
.SelectMany(x => x)
.OfType<IMoveChoice>()
.LastOrDefault(x => x.User == target);
var lastMove = choiceQueue.SelectMany(x => x).OfType<IMoveChoice>().LastOrDefault(x => x.User == target);
if (lastMove == null)
{
move.GetHitData(target, hit).Fail();

View File

@ -15,7 +15,7 @@ public class Dive : Script
move.User.Volatile.Add(new DigEffect(move.User));
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dive_charge", new Dictionary<string, object>()
{
{ "user", move.User }
{ "user", move.User },
}));
prevent = true;
}

View File

@ -12,7 +12,8 @@ public class Electrify : Script
if (choiceQueue == null)
return;
if (choiceQueue.FirstOrDefault(x => x is IMoveChoice moveChoice && moveChoice.User == target) is not IMoveChoice choice)
if (choiceQueue.FirstOrDefault(x => x is IMoveChoice moveChoice && moveChoice.User == target) is not IMoveChoice
choice)
{
move.GetHitData(target, hit).Fail();
return;

View File

@ -10,14 +10,14 @@ public class ElectroBall : Script
var targetSpeed = target.BoostedStats.Speed;
var userSpeed = user.BoostedStats.Speed;
var ratio = (float) userSpeed / targetSpeed;
var ratio = (float)userSpeed / targetSpeed;
basePower = ratio switch
{
> 4 => 150,
> 3 => 120,
> 2 => 80,
> 1 => 60,
_ => 40
_ => 40,
};
}
}

View File

@ -14,11 +14,8 @@ public class Encore : Script
return;
var currentTurn = battle.ChoiceQueue!.LastRanChoice;
var lastMove = battle.PreviousTurnChoices
.SelectMany(x => x)
.OfType<IMoveChoice>()
.TakeWhile(x => x != currentTurn)
.LastOrDefault(x => x.User == target);
var lastMove = battle.PreviousTurnChoices.SelectMany(x => x).OfType<IMoveChoice>()
.TakeWhile(x => x != currentTurn).LastOrDefault(x => x.User == target);
if (lastMove == null)
{
move.GetHitData(target, hit).Fail();

View File

@ -9,5 +9,4 @@ public class Eruption : Script
{
basePower = Math.Max((byte)(150 * move.User.CurrentHealth / move.User.BoostedStats.Hp), (byte)1);
}
}

View File

@ -15,7 +15,7 @@ public class Flail : Script
< 10 => 100,
< 17 => 80,
< 33 => 40,
_ => 20
_ => 20,
};
}
}

View File

@ -15,7 +15,6 @@ public class FlareBlitz : Script
target.SetStatus("burned");
}
var hitData = move.GetHitData(target, hit);
var recoilDamage = (uint)(hitData.Damage * (1 / 3));
move.User.Damage(recoilDamage, DamageSource.Misc);

View File

@ -15,7 +15,7 @@ public class Fly : Script
move.User.Volatile.Add(new ChargeFlyEffect(move.User));
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("fly_charge", new Dictionary<string, object>()
{
{ "user", move.User }
{ "user", move.User },
}));
prevent = true;
}

View File

@ -13,7 +13,7 @@ public class FocusPunch : Script
choice.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("focus_punch_charge",
new Dictionary<string, object>()
{
{ "pokemon", choice.User }
{ "pokemon", choice.User },
}));
}

View File

@ -18,10 +18,8 @@ public class FreezeDry : Script
if (target.Types.Contains(waterType))
{
var effectivenessWithoutWater = target.Types
.Where(x => x != waterType)
.Select(x => typeLibrary.GetEffectiveness(x, target.Types))
.Aggregate(1f, (a, b) => a * b);
var effectivenessWithoutWater = target.Types.Where(x => x != waterType)
.Select(x => typeLibrary.GetEffectiveness(x, target.Types)).Aggregate(1f, (a, b) => a * b);
effectiveness = effectivenessWithoutWater * 2;
}
}

View File

@ -17,7 +17,7 @@ public class MultiHitMove : Script
< 35 => 2,
< 70 => 3,
< 85 => 4,
_ => 5
_ => 5,
};
numberOfHits = (byte)newHits;
}

View File

@ -6,7 +6,8 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
public class OneHitKo : Script
{
/// <inheritdoc />
public override void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy)
public override void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
ref int modifiedAccuracy)
{
var levelDifference = executingMove.User.Level - target.Level;
if (levelDifference < 0)

View File

@ -25,7 +25,8 @@ public class Struggle : Script
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var damage = move.User.MaxHealth / 4;
if (damage == 0) damage = 1;
move.User.Damage(damage, DamageSource.Struggle, new());
if (damage == 0)
damage = 1;
move.User.Damage(damage, DamageSource.Struggle, new EventBatchId());
}
}

View File

@ -7,7 +7,6 @@ public class BindEffect : Script
private int _turns;
private readonly float _percentOfMaxHealth;
public BindEffect(IPokemon owner, int turns, float percentOfMaxHealth)
{
_owner = owner;

View File

@ -11,6 +11,7 @@ public class DigEffect : Script
{
_owner = owner;
}
/// <inheritdoc />
public override void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice)
{

View File

@ -11,6 +11,7 @@ public class DiveEffect : Script
{
_owner = owner;
}
/// <inheritdoc />
public override void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice)
{

View File

@ -24,9 +24,8 @@ public class EncoreEffect : Script
choice = TurnChoiceHelper.CreateMoveChoice(_owner, _move, opposingSideIndex, position);
if (choice is IMoveChoice { ChosenMove.CurrentPp: <= 0 } moveChoice)
{
choice =
moveChoice.User.BattleData?.Battle.Library.MiscLibrary.ReplacementChoice(_owner, opposingSideIndex,
position);
choice = moveChoice.User.BattleData?.Battle.Library.MiscLibrary.ReplacementChoice(_owner, opposingSideIndex,
position);
}
}

Some files were not shown because too many files have changed in this diff Show More