Style cleanup
This commit is contained in:
parent
c0bc905c46
commit
284ab3079c
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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; }
|
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -45,6 +45,4 @@ public class RandomAI : PokemonAI
|
||||||
}
|
}
|
||||||
return new PassChoice(pokemon);
|
return new PassChoice(pokemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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; }
|
||||||
}
|
}
|
|
@ -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();
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 />
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 });
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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.
|
||||||
|
|
|
@ -66,5 +66,4 @@ public static class ScriptExecution
|
||||||
itemScript.OnUse();
|
itemScript.OnUse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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);
|
|
||||||
}
|
}
|
|
@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
namespace PkmnLib.Static.Utils.Errors;
|
namespace PkmnLib.Static.Utils.Errors;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
global using TUnit;
|
global using TUnit;
|
||||||
global using FluentAssertions;
|
global using FluentAssertions;
|
||||||
|
|
||||||
global using LevelInt = byte;
|
global using LevelInt = byte;
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
|
@ -59,5 +59,4 @@ public class AcrobaticsTests
|
||||||
// Assert
|
// Assert
|
||||||
await Assert.That(basePower).IsEqualTo(byte.MaxValue);
|
await Assert.That(basePower).IsEqualTo(byte.MaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)!;
|
||||||
|
|
|
@ -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 },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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 },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ public class Flail : Script
|
||||||
< 10 => 100,
|
< 10 => 100,
|
||||||
< 17 => 80,
|
< 17 => 80,
|
||||||
< 33 => 40,
|
< 33 => 40,
|
||||||
_ => 20
|
_ => 20,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue