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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,7 @@ public record struct CaptureResult
public int Shakes { get; init; } public int Shakes { get; init; }
public bool CriticalCapture { 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 public interface ICaptureLibrary

View File

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

View File

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

View File

@ -51,7 +51,6 @@ public class BattleChoiceQueue : IDeepCloneable
/// </summary> /// </summary>
public bool HasNext() => _currentIndex < _choices.Length; public bool HasNext() => _currentIndex < _choices.Length;
/// <summary> /// <summary>
/// This resorts the yet to be executed choices. This can be useful for dealing with situations /// 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 /// 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; 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); moveChoice.Script.Set(script);
} }
} }
} }
var targetType = moveData.Target; 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)); moveChoice.RunScriptHook(x => x.ChangeTargets(moveChoice, ref targets));
byte numberOfHits = 1; byte numberOfHits = 1;
@ -140,8 +140,8 @@ internal static class MoveTurnExecutor
// modifying it. // modifying it.
if (accuracy != 255) if (accuracy != 255)
{ {
accuracy = battle.Library.StatCalculator.CalculateModifiedAccuracy(executingMove, target, accuracy = battle.Library.StatCalculator.CalculateModifiedAccuracy(executingMove, target, hitIndex,
hitIndex, accuracy); accuracy);
} }
if (accuracy < 100 && battle.Random.GetInt(100) >= accuracy) if (accuracy < 100 && battle.Random.GetInt(100) >= accuracy)
@ -198,14 +198,16 @@ internal static class MoveTurnExecutor
if (secondaryEffect != null) if (secondaryEffect != null)
{ {
var preventSecondary = false; 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) if (!preventSecondary)
{ {
var chance = secondaryEffect.Chance; var chance = secondaryEffect.Chance;
if (chance < 0 || battle.Random.EffectChance(chance, executingMove, target, hitIndex)) 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)); executingMove.RunScriptHook(x => x.OnAfterHits(executingMove, target));
} }
} }
} }

View File

@ -15,8 +15,8 @@ public static class TargetResolver
return target switch return target switch
{ {
MoveTarget.Adjacent or MoveTarget.AdjacentAlly or MoveTarget.AdjacentAllySelf or MoveTarget.AdjacentOpponent MoveTarget.Adjacent or MoveTarget.AdjacentAlly or MoveTarget.AdjacentAllySelf or MoveTarget.AdjacentOpponent
or MoveTarget.Any or MoveTarget.RandomOpponent or MoveTarget.Any or MoveTarget.RandomOpponent or MoveTarget.SelfUse =>
or MoveTarget.SelfUse => [battle.GetPokemon(side, position)], [battle.GetPokemon(side, position)],
MoveTarget.All => GetAllTargets(battle), MoveTarget.All => GetAllTargets(battle),
MoveTarget.AllAdjacentOpponent => GetAllAdjacentAndOpponent(battle, side, position), MoveTarget.AllAdjacentOpponent => GetAllAdjacentAndOpponent(battle, side, position),
MoveTarget.AllAdjacent => GetAllAdjacent(battle, side, position), MoveTarget.AllAdjacent => GetAllAdjacent(battle, side, position),
@ -144,7 +144,8 @@ public static class TargetResolver
return 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; var queue = battle.ChoiceQueue;
if (queue == null) if (queue == null)
{
throw new ArgumentNullException(nameof(battle.ChoiceQueue), throw new ArgumentNullException(nameof(battle.ChoiceQueue),
"The battle's choice queue must be set before running a turn."); "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 // 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. // choices, and put them in the correct order.
@ -122,7 +124,6 @@ public static class TurnRunner
userSide.SwapPokemon(battleData.Position, fleeChoice.SwitchTo); userSide.SwapPokemon(battleData.Position, fleeChoice.SwitchTo);
} }
private static void ExecuteFleeChoice(IBattle battle, IFleeChoice fleeChoice) private static void ExecuteFleeChoice(IBattle battle, IFleeChoice fleeChoice)
{ {
var user = fleeChoice.User; var user = fleeChoice.User;
@ -171,5 +172,4 @@ public static class TurnRunner
} }
itemChoice.Item.RunItemScript(battle.Library.ScriptResolver, target ?? user); itemChoice.Item.RunItemScript(battle.Library.ScriptResolver, target ?? user);
} }
} }

View File

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

View File

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

View File

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

View File

@ -82,5 +82,5 @@ public class TurnChoiceComparer : IComparer<ITurnChoice>
} }
/// <inheritdoc /> /// <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; CurrentPp = MaxPp;
} }
public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod, byte pp) public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod, byte pp) : this(moveData, learnMethod)
: this(moveData, learnMethod)
{ {
CurrentPp = pp; CurrentPp = pp;
} }

View File

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

View File

@ -46,7 +46,6 @@ public class PokemonParty : IPokemonParty
_pokemon = new IPokemon[size]; _pokemon = new IPokemon[size];
} }
/// <inheritdoc /> /// <inheritdoc />
public event EventHandler<(IPokemon?, int index)>? OnSwapInto; public event EventHandler<(IPokemon?, int index)>? OnSwapInto;
@ -73,7 +72,6 @@ public class PokemonParty : IPokemonParty
OnSwap?.Invoke(this, (index1, index2)); OnSwap?.Invoke(this, (index1, index2));
} }
/// <inheritdoc /> /// <inheritdoc />
public bool HasUsablePokemon() => _pokemon.Any(p => p is { IsUsable: true }); 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; } protected IItem Item { get; private set; }
/// <summary> /// <summary>
/// Initializes the script with the given parameters for a specific item /// Initializes the script with the given parameters for a specific item
/// </summary> /// </summary>

View File

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

View File

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

View File

@ -83,32 +83,32 @@ public class ScriptRegistry
// This is more performant than using Activator.CreateInstance. // This is more performant than using Activator.CreateInstance.
var parameterExpression = Expression.Parameter(typeof(IItem), "item"); var parameterExpression = Expression.Parameter(typeof(IItem), "item");
var newExpression = Expression.New(constructor, parameterExpression); 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> /// <summary>
/// Register a battle stat calculator. /// Register a battle stat calculator.
/// </summary> /// </summary>
public void RegisterBattleStatCalculator<T>(T battleStatCalculator) public void RegisterBattleStatCalculator<T>(T battleStatCalculator) where T : IBattleStatCalculator =>
where T : IBattleStatCalculator => _battleStatCalculator = battleStatCalculator; _battleStatCalculator = battleStatCalculator;
/// <summary> /// <summary>
/// Register a damage calculator. /// Register a damage calculator.
/// </summary> /// </summary>
public void RegisterDamageCalculator<T>(T damageCalculator) public void RegisterDamageCalculator<T>(T damageCalculator) where T : IDamageCalculator =>
where T : IDamageCalculator => _damageCalculator = damageCalculator; _damageCalculator = damageCalculator;
/// <summary> /// <summary>
/// Register a misc library. /// Register a misc library.
/// </summary> /// </summary>
public void RegisterMiscLibrary<T>(T miscLibrary) where T : IMiscLibrary public void RegisterMiscLibrary<T>(T miscLibrary) where T : IMiscLibrary => _miscLibrary = miscLibrary;
=> _miscLibrary = miscLibrary;
/// <summary> /// <summary>
/// Register a capture library. /// Register a capture library.
/// </summary> /// </summary>
public void RegisterCaptureLibrary<T>(T captureLibrary) where T : ICaptureLibrary public void RegisterCaptureLibrary<T>(T captureLibrary) where T : ICaptureLibrary =>
=> _captureLibrary = captureLibrary; _captureLibrary = captureLibrary;
internal IReadOnlyDictionary<(ScriptCategory category, StringKey name), Func<Script>> ScriptTypes => _scriptTypes; internal IReadOnlyDictionary<(ScriptCategory category, StringKey name), Func<Script>> ScriptTypes => _scriptTypes;
internal IReadOnlyDictionary<StringKey, Func<IItem, ItemScript>> ItemScriptTypes => _itemScriptTypes; 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; yield return this;
} }
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary> /// <summary>
/// Assigns a new script to this container. If there was a script already, it is removed. /// 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(); itemScript.OnUse();
} }
} }
} }

View File

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

View File

@ -155,8 +155,5 @@ public class ScriptSet : IScriptSet
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<StringKey> GetScriptNames() => public IEnumerable<StringKey> GetScriptNames() =>
_scripts _scripts.Select(x => x.Script).WhereNotNull().Select(s => s.Name);
.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 /> /// <inheritdoc />
public uint CalculateExperience(LevelInt level) public uint CalculateExperience(LevelInt level)
{ {
if (level < 1) level = 1; if (level < 1)
level = 1;
return level >= _experienceTable.Length ? _experienceTable[^1] : _experienceTable[level - 1]; return level >= _experienceTable.Length ? _experienceTable[^1] : _experienceTable[level - 1];
} }
} }

View File

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

View File

@ -7,13 +7,13 @@ namespace PkmnLib.Static.Libraries;
/// <summary> /// <summary>
/// A basic library for data types. Stores data both by name and by index. /// A basic library for data types. Stores data both by name and by index.
/// </summary> /// </summary>
public abstract class DataLibrary<T> : IEnumerable<T> public abstract class DataLibrary<T> : IEnumerable<T> where T : INamedValue
where T : INamedValue
{ {
/// <summary> /// <summary>
/// The underlying data storage. /// The underlying data storage.
/// </summary> /// </summary>
protected readonly Dictionary<StringKey, T> Data = new(); protected readonly Dictionary<StringKey, T> Data = new();
private readonly List<T> _values = []; private readonly List<T> _values = [];
/// <summary> /// <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. /// Tries to get a growth rate from the library. Returns false if the growth rate is not found.
/// </summary> /// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out IGrowthRate value); bool TryGet(StringKey key, [MaybeNullWhen(false)] out IGrowthRate value);
/// <summary> /// <summary>
/// Gets a random growth rate from the library. /// Gets a random growth rate from the library.
/// </summary> /// </summary>
IGrowthRate GetRandom(IRandom random); IGrowthRate GetRandom(IRandom random);
/// <summary> /// <summary>
/// Gets the amount of growth rates in the library. /// Gets the amount of growth rates in the library.
/// </summary> /// </summary>
int Count { get; } int Count { get; }
/// <summary> /// <summary>
/// Whether the library is empty. /// Whether the library is empty.
/// </summary> /// </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. /// Tries to get a move from the library. Returns false if the move is not found.
/// </summary> /// </summary>
bool TryGet(StringKey key, [MaybeNullWhen(false)] out IMoveData value); bool TryGet(StringKey key, [MaybeNullWhen(false)] out IMoveData value);
/// <summary> /// <summary>
/// Gets a random move from the library. /// Gets a random move from the library.
/// </summary> /// </summary>
IMoveData GetRandom(IRandom random); IMoveData GetRandom(IRandom random);
/// <summary> /// <summary>
/// The amount of moves in the library. /// The amount of moves in the library.
/// </summary> /// </summary>
int Count { get; } int Count { get; }
/// <summary> /// <summary>
/// Whether the library is empty. /// Whether the library is empty.
/// </summary> /// </summary>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -131,7 +131,6 @@ public class SpeciesImpl : ISpecies
/// <inheritdoc /> /// <inheritdoc />
public ICollection<StringKey> EggGroups { get; } public ICollection<StringKey> EggGroups { get; }
/// <inheritdoc /> /// <inheritdoc />
public bool TryGetForm(StringKey id, [MaybeNullWhen(false)] out IForm form) => Forms.TryGetValue(id, out form); 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. /// Health Points determine how much damage a Pokémon can receive before fainting.
/// </summary> /// </summary>
Hp, Hp,
/// <summary> /// <summary>
/// Attack determines how much damage a Pokémon deals when using a physical attack. /// Attack determines how much damage a Pokémon deals when using a physical attack.
/// </summary> /// </summary>
Attack, Attack,
/// <summary> /// <summary>
/// Defense determines how much damage a Pokémon receives when it is hit by a physical attack. /// Defense determines how much damage a Pokémon receives when it is hit by a physical attack.
/// </summary> /// </summary>
Defense, Defense,
/// <summary> /// <summary>
/// Special Attack determines how much damage a Pokémon deals when using a special attack. /// Special Attack determines how much damage a Pokémon deals when using a special attack.
/// </summary> /// </summary>
SpecialAttack, SpecialAttack,
/// <summary> /// <summary>
/// Special Defense determines how much damage a Pokémon receives when it is hit by a special attack. /// Special Defense determines how much damage a Pokémon receives when it is hit by a special attack.
/// </summary> /// </summary>
SpecialDefense, SpecialDefense,
/// <summary> /// <summary>
/// Speed determines the order that a Pokémon can act in battle. /// Speed determines the order that a Pokémon can act in battle.
/// </summary> /// </summary>

View File

@ -8,8 +8,7 @@ namespace PkmnLib.Static;
/// A set of statistics that cannot be changed. /// A set of statistics that cannot be changed.
/// </summary> /// </summary>
/// <typeparam name="T">The size of the integer to be used</typeparam> /// <typeparam name="T">The size of the integer to be used</typeparam>
public record ImmutableStatisticSet<T> public record ImmutableStatisticSet<T> where T : struct
where T : struct
{ {
/// <summary> /// <summary>
/// The health points stat value. /// The health points stat value.
@ -84,8 +83,7 @@ public record ImmutableStatisticSet<T>
/// A set of statistics that can be changed. /// A set of statistics that can be changed.
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<T>, IDeepCloneable public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<T>, IDeepCloneable where T : struct
where T : struct
{ {
/// <inheritdoc cref="StatisticSet{T}"/> /// <inheritdoc cref="StatisticSet{T}"/>
public StatisticSet() : base(default, default, default, default, default, default) public StatisticSet() : base(default, default, default, default, default, default)
@ -175,17 +173,13 @@ public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<T>, IDeepC
return true; return true;
} }
protected virtual T GetUnknownStat(Statistic stat) protected virtual T GetUnknownStat(Statistic stat) => throw new ArgumentException($"Invalid statistic {stat}");
{
throw new ArgumentException($"Invalid statistic {stat}");
}
protected virtual void SetUnknownStat(Statistic stat, T value) protected virtual void SetUnknownStat(Statistic stat, T value)
{ {
throw new ArgumentException($"Invalid statistic {stat}"); throw new ArgumentException($"Invalid statistic {stat}");
} }
/// <summary> /// <summary>
/// Decreases a statistic in the set by a value. /// Decreases a statistic in the set by a value.
/// </summary> /// </summary>
@ -231,17 +225,13 @@ public record StatisticSet<T> : ImmutableStatisticSet<T>, IEnumerable<T>, IDeepC
} }
/// <inheritdoc /> /// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
{
return GetEnumerator();
}
} }
/// <summary> /// <summary>
/// A set of statistics that can be changed, but are clamped to a minimum and maximum value. /// A set of statistics that can be changed, but are clamped to a minimum and maximum value.
/// </summary> /// </summary>
public abstract record ClampedStatisticSet<T> : StatisticSet<T> public abstract record ClampedStatisticSet<T> : StatisticSet<T> where T : struct, IComparable<T>
where T : struct, IComparable<T>
{ {
/// <inheritdoc /> /// <inheritdoc />
[SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")] [SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")]
@ -322,6 +312,7 @@ public record StatBoostStatisticSet : ClampedStatisticSet<sbyte>
protected override sbyte Max => 6; protected override sbyte Max => 6;
private sbyte _evasion; private sbyte _evasion;
public sbyte Evasion public sbyte Evasion
{ {
get => _evasion; get => _evasion;
@ -329,6 +320,7 @@ public record StatBoostStatisticSet : ClampedStatisticSet<sbyte>
} }
private sbyte _accuracy; private sbyte _accuracy;
public sbyte Accuracy public sbyte Accuracy
{ {
get => _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 /// Recursive references will be handled correctly, and will only be cloned once, to prevent infinite loops and invalid
/// references. /// references.
/// </summary> /// </summary>
public static T DeepClone<T>(this T? obj, Dictionary<(Type, int), object>? objects = null) where T : IDeepCloneable public static T DeepClone<T>(this T? obj, Dictionary<(Type, int), object>? objects = null)
{ where T : IDeepCloneable => (T)DeepClone((object?)obj, objects)!;
return (T)DeepClone((object?)obj, objects)!;
}
private static object? DeepClone(this object? obj, Dictionary<(Type, int), object>? objects = null) 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 array = (Array)obj;
var newArray = Array.CreateInstance(type.GetElementType()!, array.Length); var newArray = Array.CreateInstance(type.GetElementType()!, array.Length);
for (var i = 0; i < array.Length; i++) 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; return newArray;
} }
@ -115,9 +114,10 @@ public static class DeepCloneHandler
var dictionary = (IDictionary)obj; var dictionary = (IDictionary)obj;
var newDictionary = (IDictionary)Activator.CreateInstance(type); var newDictionary = (IDictionary)Activator.CreateInstance(type);
foreach (DictionaryEntry entry in dictionary) 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)); DeepCloneInternal(entry.Value, type.GetGenericArguments()[1], objects));
}
return newDictionary; 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 /// 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. /// each field in the type, so that we can get high performance deep cloning.
/// </remarks> /// </remarks>
private static (Func<object, object?> getter, Action<object, object?> setter)[] private static (Func<object, object?> getter, Action<object, object?> setter)[] GetDeepCloneExpressions(Type type)
GetDeepCloneExpressions(Type type)
{ {
// We use a lock here to prevent multiple threads from trying to create the expressions at the same time. // We use a lock here to prevent multiple threads from trying to create the expressions at the same time.
lock (DeepCloneExpressions) lock (DeepCloneExpressions)

View File

@ -2,7 +2,8 @@ namespace PkmnLib.Static.Utils;
public static class DictionaryHelpers 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)) if (dictionary.TryGetValue(key, out var value))
return value; return value;

View File

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

View File

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

View File

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

View File

@ -10,10 +10,7 @@ public class MoveDataTests
public record TestCaseData(IDynamicLibrary Library, IMoveData Move) public record TestCaseData(IDynamicLibrary Library, IMoveData Move)
{ {
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString() => Move.Name + " has valid scripts";
{
return Move.Name + " has valid scripts";
}
} }
public static IEnumerable<TestCaseData> AllMovesHaveValidScriptsData() public static IEnumerable<TestCaseData> AllMovesHaveValidScriptsData()
@ -28,8 +25,7 @@ public class MoveDataTests
} }
} }
[Test] [Test, MethodDataSource(nameof(AllMovesHaveValidScriptsData))]
[MethodDataSource(nameof(AllMovesHaveValidScriptsData))]
public async Task AllMoveEffectsHaveValidScripts(TestCaseData test) public async Task AllMoveEffectsHaveValidScripts(TestCaseData test)
{ {
if (test.Move.SecondaryEffect == null) if (test.Move.SecondaryEffect == null)
@ -43,7 +39,8 @@ public class MoveDataTests
} }
catch (Exception e) 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 TUnit;
global using FluentAssertions; global using FluentAssertions;
global using LevelInt = byte; global using LevelInt = byte;

View File

@ -26,8 +26,7 @@ public class IntegrationTestRunner
} }
} }
[Test] [Test, MethodDataSource(nameof(TestCases))]
[MethodDataSource(nameof(TestCases))]
public async Task RunIntegrationTest(IntegrationTestModel test) public async Task RunIntegrationTest(IntegrationTestModel test)
{ {
var library = LibraryHelpers.LoadLibrary(); var library = LibraryHelpers.LoadLibrary();
@ -43,8 +42,7 @@ public class IntegrationTestRunner
{ {
IsHidden = false, IsHidden = false,
Index = 0, Index = 0,
}, }, pokemon.Level, 0, Gender.Genderless, 0, "hardy");
pokemon.Level, 0, Gender.Genderless, 0, "hardy");
foreach (var move in pokemon.Moves) foreach (var move in pokemon.Moves)
{ {
mon.LearnMove(move, MoveLearnMethod.Unknown, 255); 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()); return new BattlePartyImpl(party, x.Indices.Select(y => new ResponsibleIndex(y[0], y[1])).ToArray());
}).ProcessOneAtATime().GetResultsAsync(); }).ProcessOneAtATime().GetResultsAsync();
var battle = new BattleImpl(library, parties, test.BattleSetup.CanFlee, test.BattleSetup.NumberOfSides, 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) foreach (var action in test.Actions)
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -44,15 +44,18 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
var flatStat = CalculateFlatStat(pokemon, stat); var flatStat = CalculateFlatStat(pokemon, stat);
var boostModifier = GetStatBoostModifier(pokemon, stat); var boostModifier = GetStatBoostModifier(pokemon, stat);
var boostedStat = flatStat * boostModifier; var boostedStat = flatStat * boostModifier;
if (boostedStat > uint.MaxValue) boostedStat = uint.MaxValue; if (boostedStat > uint.MaxValue)
boostedStat = uint.MaxValue;
return (uint)boostedStat; return (uint)boostedStat;
} }
/// <inheritdoc /> /// <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; 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); var modifiedAccuracy = (int)(moveAccuracy * accuracyModifier);
executingMove.RunScriptHook(x => x.ChangeAccuracy(executingMove, target, hitIndex, ref modifiedAccuracy)); executingMove.RunScriptHook(x => x.ChangeAccuracy(executingMove, target, hitIndex, ref modifiedAccuracy));
var targetEvasion = target.StatBoost.Evasion; 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 / (3.0f + Math.Min(difference, 6)),
< 0 => 3.0f + -Math.Max(difference, -6) / 3.0f, < 0 => 3.0f + -Math.Max(difference, -6) / 3.0f,
_ => 1.0f _ => 1.0f,
}; };
modifiedAccuracy = (int)(modifiedAccuracy * statModifier); modifiedAccuracy = (int)(modifiedAccuracy * statModifier);
modifiedAccuracy = modifiedAccuracy switch modifiedAccuracy = modifiedAccuracy switch
{ {
> 255 => 255, > 255 => 255,
< 0 => 0, < 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" // 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. // 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 iv = (ulong)pokemon.IndividualValues.Hp;
var ev = (ulong)pokemon.EffortValues.Hp; var ev = (ulong)pokemon.EffortValues.Hp;
var level = (ulong)pokemon.Level; var level = (ulong)pokemon.Level;
var health = (((2 * baseValue + iv + (ev / 4)) * level) / 100) + level + 10; var health = (2 * baseValue + iv + ev / 4) * level / 100 + level + 10;
if (health > uint.MaxValue) health = uint.MaxValue; if (health > uint.MaxValue)
health = uint.MaxValue;
return (uint)health; return (uint)health;
} }
@ -97,10 +101,11 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
var iv = (ulong)pokemon.IndividualValues.GetStatistic(statistic); var iv = (ulong)pokemon.IndividualValues.GetStatistic(statistic);
var ev = (ulong)pokemon.EffortValues.GetStatistic(statistic); var ev = (ulong)pokemon.EffortValues.GetStatistic(statistic);
var level = (ulong)pokemon.Level; 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 natureModifier = pokemon.Nature.GetStatModifier(statistic);
var modified = (unmodified * natureModifier); var modified = unmodified * natureModifier;
if (modified > uint.MaxValue) modified = uint.MaxValue; if (modified > uint.MaxValue)
modified = uint.MaxValue;
return (uint)modified; return (uint)modified;
} }
@ -122,7 +127,7 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
4 => 6.0f / 2.0f, 4 => 6.0f / 2.0f,
5 => 7.0f / 2.0f, 5 => 7.0f / 2.0f,
6 => 8.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; byte bonusStatus = 1;
target.RunScriptHook(x => x.ChangeCatchRateBonus(target, captureItem, ref bonusStatus)); target.RunScriptHook(x => x.ChangeCatchRateBonus(target, captureItem, ref bonusStatus));
var modifiedCatchRate = var modifiedCatchRate = (3.0 * maxHealth - 2.0 * currentHealth) * catchRate * bonusBall / (3.0 * maxHealth);
(((3.0 * maxHealth) - (2.0 * currentHealth)) * catchRate * bonusBall) / (3.0 * maxHealth);
modifiedCatchRate *= bonusStatus; modifiedCatchRate *= bonusStatus;
var shakeProbability = 65536 / Math.Pow((255 / modifiedCatchRate), 0.1875); var shakeProbability = 65536 / Math.Pow(255 / modifiedCatchRate, 0.1875);
byte shakes = 0; byte shakes = 0;
if (modifiedCatchRate >= 255) if (modifiedCatchRate >= 255)
{ {

View File

@ -17,7 +17,7 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
if (hitData.Effectiveness == 0) if (hitData.Effectiveness == 0)
return 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 basePower = (float)hitData.BasePower;
var statModifier = GetStatModifier(executingMove, target, hitNumber, hitData); var statModifier = GetStatModifier(executingMove, target, hitNumber, hitData);
var damageModifier = GetDamageModifier(executingMove, target, hitNumber); var damageModifier = GetDamageModifier(executingMove, target, hitNumber);
@ -62,10 +62,8 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
< 1 => 1, < 1 => 1,
_ => (uint)floatDamage, _ => (uint)floatDamage,
}; };
executingMove.RunScriptHook(script => executingMove.RunScriptHook(script => script.ChangeMoveDamage(executingMove, target, hitNumber, ref damage));
script.ChangeMoveDamage(executingMove, target, hitNumber, ref damage)); target.RunScriptHook(script => script.ChangeIncomingMoveDamage(executingMove, target, hitNumber, ref damage));
target.RunScriptHook(script =>
script.ChangeIncomingMoveDamage(executingMove, target, hitNumber, ref damage));
return damage; return damage;
} }
@ -76,8 +74,7 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
if (executingMove.UseMove.Category == MoveCategory.Status) if (executingMove.UseMove.Category == MoveCategory.Status)
return 0; return 0;
var basePower = executingMove.UseMove.BasePower; var basePower = executingMove.UseMove.BasePower;
executingMove.RunScriptHook(script => executingMove.RunScriptHook(script => script.ChangeBasePower(executingMove, target, hitNumber, ref basePower));
script.ChangeBasePower(executingMove, target, hitNumber, ref basePower));
return 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; var category = executingMove.UseMove.Category;
if (category == MoveCategory.Status) if (category == MoveCategory.Status)

View File

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

View File

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

View File

@ -3,7 +3,8 @@ using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.MoveVolatile; namespace PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
[Script(ScriptCategory.MoveVolatile, "electrify")] [Script(ScriptCategory.MoveVolatile, "electrify")]
public class ElectrifyEffect : Script { public class ElectrifyEffect : Script
{
/// <inheritdoc /> /// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType) 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 numberOfTurns = 5;
var dict = new Dictionary<StringKey, object?>() var dict = new Dictionary<StringKey, object?>()
{ {
{ "duration", numberOfTurns } { "duration", numberOfTurns },
}; };
move.User.RunScriptHook(x => x.CustomTrigger(CustomTriggers.AuroraVeilDuration, dict)); move.User.RunScriptHook(x => x.CustomTrigger(CustomTriggers.AuroraVeilDuration, dict));
numberOfTurns = (int)dict.GetOrDefault("duration", numberOfTurns)!; 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) public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{ {
var user = move.User; var user = move.User;
if (user.ChangeStatBoost(Statistic.Speed, 2, true) && if (user.ChangeStatBoost(Statistic.Speed, 2, true) && user.ChangeWeightInKgBy(-100.0f))
user.ChangeWeightInKgBy(-100.0f))
{ {
var battle = user.BattleData?.Battle; var battle = user.BattleData?.Battle;
battle?.EventHook.Invoke(new DialogEvent("pokemon_became_nimble", new Dictionary<string, object>() 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 public class BanefulBunker : ProtectionScript
{ {
/// <inheritdoc /> /// <inheritdoc />
protected override Script GetEffectScript() protected override Script GetEffectScript() => new BanefulBunkerEffect();
{
return new BanefulBunkerEffect();
}
} }

View File

@ -15,7 +15,7 @@ public class BeakBlast : Script
choice.User.Volatile.Add(new BeakBlastEffect()); choice.User.Volatile.Add(new BeakBlastEffect());
battleData.Battle.EventHook.Invoke(new DialogEvent("beak_blast_charge", new Dictionary<string, object>() 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 public class BeatUp : Script
{ {
private IPokemon[]? _relevantPartyMembers; private IPokemon[]? _relevantPartyMembers;
private static IEnumerable<IPokemon> GetRelevantPartyMembers(IPokemon user) private static IEnumerable<IPokemon> GetRelevantPartyMembers(IPokemon user)
{ {
var battleData = user.BattleData; var battleData = user.BattleData;

View File

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

View File

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

View File

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

View File

@ -10,9 +10,7 @@ public class Copycat : Script
/// <inheritdoc /> /// <inheritdoc />
public override void ChangeMove(IMoveChoice choice, ref StringKey moveName) public override void ChangeMove(IMoveChoice choice, ref StringKey moveName)
{ {
var lastMove = choice.User.BattleData?.Battle.PreviousTurnChoices var lastMove = choice.User.BattleData?.Battle.PreviousTurnChoices.SelectMany(x => x).OfType<IMoveChoice>()
.SelectMany(x => x)
.OfType<IMoveChoice>()
.LastOrDefault(); .LastOrDefault();
if (lastMove == null || !lastMove.ChosenMove.MoveData.CanCopyMove()) 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.Volatile.Add(new DigEffect(move.User));
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dig_charge", new Dictionary<string, object>() move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dig_charge", new Dictionary<string, object>()
{ {
{ "user", move.User } { "user", move.User },
})); }));
prevent = true; prevent = true;
} }

View File

@ -13,10 +13,7 @@ public class Disable : Script
if (battleData == null) if (battleData == null)
return; return;
var choiceQueue = battleData.Battle.PreviousTurnChoices; var choiceQueue = battleData.Battle.PreviousTurnChoices;
var lastMove = choiceQueue var lastMove = choiceQueue.SelectMany(x => x).OfType<IMoveChoice>().LastOrDefault(x => x.User == target);
.SelectMany(x => x)
.OfType<IMoveChoice>()
.LastOrDefault(x => x.User == target);
if (lastMove == null) if (lastMove == null)
{ {
move.GetHitData(target, hit).Fail(); 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.Volatile.Add(new DigEffect(move.User));
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dive_charge", new Dictionary<string, object>() move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dive_charge", new Dictionary<string, object>()
{ {
{ "user", move.User } { "user", move.User },
})); }));
prevent = true; prevent = true;
} }

View File

@ -12,7 +12,8 @@ public class Electrify : Script
if (choiceQueue == null) if (choiceQueue == null)
return; 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(); move.GetHitData(target, hit).Fail();
return; return;

View File

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

View File

@ -14,11 +14,8 @@ public class Encore : Script
return; return;
var currentTurn = battle.ChoiceQueue!.LastRanChoice; var currentTurn = battle.ChoiceQueue!.LastRanChoice;
var lastMove = battle.PreviousTurnChoices var lastMove = battle.PreviousTurnChoices.SelectMany(x => x).OfType<IMoveChoice>()
.SelectMany(x => x) .TakeWhile(x => x != currentTurn).LastOrDefault(x => x.User == target);
.OfType<IMoveChoice>()
.TakeWhile(x => x != currentTurn)
.LastOrDefault(x => x.User == target);
if (lastMove == null) if (lastMove == null)
{ {
move.GetHitData(target, hit).Fail(); 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); 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, < 10 => 100,
< 17 => 80, < 17 => 80,
< 33 => 40, < 33 => 40,
_ => 20 _ => 20,
}; };
} }
} }

View File

@ -15,7 +15,6 @@ public class FlareBlitz : Script
target.SetStatus("burned"); target.SetStatus("burned");
} }
var hitData = move.GetHitData(target, hit); var hitData = move.GetHitData(target, hit);
var recoilDamage = (uint)(hitData.Damage * (1 / 3)); var recoilDamage = (uint)(hitData.Damage * (1 / 3));
move.User.Damage(recoilDamage, DamageSource.Misc); 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.Volatile.Add(new ChargeFlyEffect(move.User));
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("fly_charge", new Dictionary<string, object>() move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("fly_charge", new Dictionary<string, object>()
{ {
{ "user", move.User } { "user", move.User },
})); }));
prevent = true; prevent = true;
} }

View File

@ -13,7 +13,7 @@ public class FocusPunch : Script
choice.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("focus_punch_charge", choice.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("focus_punch_charge",
new Dictionary<string, object>() 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)) if (target.Types.Contains(waterType))
{ {
var effectivenessWithoutWater = target.Types var effectivenessWithoutWater = target.Types.Where(x => x != waterType)
.Where(x => x != waterType) .Select(x => typeLibrary.GetEffectiveness(x, target.Types)).Aggregate(1f, (a, b) => a * b);
.Select(x => typeLibrary.GetEffectiveness(x, target.Types))
.Aggregate(1f, (a, b) => a * b);
effectiveness = effectivenessWithoutWater * 2; effectiveness = effectivenessWithoutWater * 2;
} }
} }

View File

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

View File

@ -6,7 +6,8 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
public class OneHitKo : Script public class OneHitKo : Script
{ {
/// <inheritdoc /> /// <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; var levelDifference = executingMove.User.Level - target.Level;
if (levelDifference < 0) if (levelDifference < 0)

View File

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

View File

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

View File

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

View File

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

View File

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

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