Adds battle history, fixes code style

This commit is contained in:
Deukhoofd 2024-08-23 09:24:00 +02:00
parent d48889e21a
commit e7dc885afd
21 changed files with 80 additions and 70 deletions

View File

@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dataloader.Models; namespace PkmnLib.Dataloader.Models;

View File

@ -2,10 +2,10 @@ namespace PkmnLib.Dataloader.Models;
public class SerializedItem public class SerializedItem
{ {
public string Name { get; set; } public string Name { get; set; } = null!;
public string ItemType { get; set; } public string ItemType { get; set; } = null!;
public string BattleType { get; set; } public string BattleType { get; set; } = null!;
public string[] Flags { get; set; } public string[] Flags { get; set; } = null!;
public int Price { get; set; } public int Price { get; set; }
public byte FlingPower { get; set; } public byte FlingPower { get; set; }
} }

View File

@ -5,26 +5,26 @@ namespace PkmnLib.Dataloader.Models;
public class SerializedMoveDataWrapper public class SerializedMoveDataWrapper
{ {
public SerializedMove[] Data { get; set; } public SerializedMove[] Data { get; set; } = null!;
} }
public class SerializedMove public class SerializedMove
{ {
public string Name { get; set; } public string Name { get; set; } = null!;
public string Type { get; set; } public string Type { get; set; } = null!;
public byte Power { get; set; } public byte Power { get; set; }
public byte PP { get; set; } public byte PP { get; set; }
public byte Accuracy { get; set; } public byte Accuracy { get; set; }
public sbyte Priority { get; set; } public sbyte Priority { get; set; }
public string Target { get; set; } public string Target { get; set; } = null!;
public string Category { get; set; } public string Category { get; set; } = null!;
public string[] Flags { get; set; } public string[] Flags { get; set; } = null!;
public SerializedMoveEffect? Effect { get; set; } public SerializedMoveEffect? Effect { get; set; }
} }
public class SerializedMoveEffect public class SerializedMoveEffect
{ {
public string Name { get; set; } public string Name { get; set; } = null!;
public float Chance { get; set; } public float Chance { get; set; }
public Dictionary<string, JsonNode>? Parameters { get; set; } public Dictionary<string, JsonNode>? Parameters { get; set; } = null!;
} }

View File

@ -1,46 +1,45 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
namespace PkmnLib.Dataloader.Models; namespace PkmnLib.Dataloader.Models;
public class SerializedSpecies public class SerializedSpecies
{ {
public string Species { get; set; } public string Species { get; set; } = null!;
public ushort Id { get; set; } public ushort Id { get; set; }
public float GenderRatio { get; set; } public float GenderRatio { get; set; }
public string GrowthRate { get; set; } public string GrowthRate { get; set; } = null!;
public byte BaseHappiness { get; set; } public byte BaseHappiness { get; set; }
public byte CatchRate { get; set; } public byte CatchRate { get; set; }
public string Color { get; set; } public string Color { get; set; } = null!;
public bool GenderDifference { get; set; } public bool GenderDifference { get; set; }
public string[] EggGroups { get; set; } public string[] EggGroups { get; set; } = null!;
public int EggCycles { get; set; } public int EggCycles { get; set; }
public string[] Flags { get; set; } = []; public string[] Flags { get; set; } = [];
public Dictionary<string, SerializedForm> Formes { get; set; } public Dictionary<string, SerializedForm> Formes { get; set; } = null!;
public SerializedEvolution[] Evolutions { get; set; } = []; public SerializedEvolution[] Evolutions { get; set; } = [];
} }
public class SerializedForm public class SerializedForm
{ {
public string[] Abilities { get; set; } public string[] Abilities { get; set; } = null!;
public string[] HiddenAbilities { get; set; } = []; public string[] HiddenAbilities { get; set; } = [];
public SerializedStats BaseStats { get; set; } public SerializedStats BaseStats { get; set; } = null!;
public SerializedStats EVReward { get; set; } public SerializedStats EVReward { get; set; } = null!;
public string[] Types { get; set; } public string[] Types { get; set; } = null!;
public float Height { get; set; } public float Height { get; set; }
public float Weight { get; set; } public float Weight { get; set; }
public uint BaseExp { get; set; } public uint BaseExp { get; set; }
public bool IsMega { get; set; } public bool IsMega { get; set; }
public SerializedMoves Moves { get; set; } public SerializedMoves Moves { get; set; } = null!;
public string[] Flags { get; set; } = []; public string[] Flags { get; set; } = [];
} }
public class SerializedEvolution public class SerializedEvolution
{ {
public string Species { get; set; } public string Species { get; set; } = null!;
public string Method { get; set; } public string Method { get; set; } = null!;
public JsonNode Data { get; set; } public JsonNode Data { get; set; } = null!;
} }
public class SerializedStats public class SerializedStats
@ -55,14 +54,14 @@ public class SerializedStats
public class SerializedLevelMove public class SerializedLevelMove
{ {
public string Name { get; set; } public string Name { get; set; } = null!;
public uint Level { get; set; } public uint Level { get; set; }
} }
public class SerializedMoves public class SerializedMoves
{ {
public SerializedLevelMove[] LevelMoves { get; set; } public SerializedLevelMove[] LevelMoves { get; set; } = null!;
public string[] EggMoves { get; set; } public string[] EggMoves { get; set; } = null!;
public string[] TutorMoves { get; set; } public string[] TutorMoves { get; set; } = null!;
public string[] Machine { get; set; } public string[] Machine { get; set; } = null!;
} }

View File

@ -187,7 +187,7 @@ public static class SpeciesDataLoader
Name = "location", Name = "location",
Parameters = new Dictionary<StringKey, object?> Parameters = new Dictionary<StringKey, object?>
{ {
["location"] = evolution.Data.ToString() ?? throw new InvalidDataException("Location is null.") ["location"] = evolution.Data.ToString() ?? throw new InvalidDataException("Location is null."),
}, },
ToSpecies = evolution.Species, ToSpecies = evolution.Species,
}, },
@ -200,7 +200,7 @@ public static class SpeciesDataLoader
.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,
}, },
_ => throw new InvalidDataException($"Evolution type {evolution.Method} is invalid.") _ => throw new InvalidDataException($"Evolution type {evolution.Method} is invalid."),
}; };
} }
} }

View File

@ -110,6 +110,12 @@ public interface IBattle : IScriptSource
/// Gets the current weather of the battle. If no weather is present, this returns null. /// Gets the current weather of the battle. If no weather is present, this returns null.
/// </summary> /// </summary>
StringKey? WeatherName { get; } StringKey? WeatherName { get; }
/// <summary>
/// Gets the turn choices of the previous turn. This is a list of lists, where each list represents the choices
/// for a single turn. The outer list is ordered from oldest to newest turn.
/// </summary>
IReadOnlyList<IReadOnlyList<ITurnChoice>> PreviousTurnChoices { get; }
} }
/// <inheritdoc cref="IBattle"/> /// <inheritdoc cref="IBattle"/>
@ -172,7 +178,8 @@ public class BattleImpl : ScriptSource, IBattle
public IPokemon? GetPokemon(byte side, byte position) => Sides[side].Pokemon[position]; public IPokemon? GetPokemon(byte side, byte position) => Sides[side].Pokemon[position];
/// <inheritdoc /> /// <inheritdoc />
public bool CanSlotBeFilled(byte side, byte position) => Parties.Any(x => x.IsResponsibleForIndex(new ResponsibleIndex(side, position)) && x.HasPokemonNotInField()); public bool CanSlotBeFilled(byte side, byte position) => Parties.Any(x =>
x.IsResponsibleForIndex(new ResponsibleIndex(side, position)) && x.HasPokemonNotInField());
/// <inheritdoc /> /// <inheritdoc />
public void ValidateBattleState() public void ValidateBattleState()
@ -207,7 +214,7 @@ public class BattleImpl : ScriptSource, IBattle
HasEnded = true; HasEnded = true;
return; return;
} }
// If only one side is left, that side has won // If only one side is left, that side has won
Result = BattleResult.Conclusive(survivingSide!.Index); Result = BattleResult.Conclusive(survivingSide!.Index);
HasEnded = true; HasEnded = true;
@ -267,17 +274,22 @@ public class BattleImpl : ScriptSource, IBattle
choice.RunScriptHook(script => script.ChangePriority(moveChoice, ref priority)); choice.RunScriptHook(script => script.ChangePriority(moveChoice, ref priority));
moveChoice.Priority = priority; moveChoice.Priority = priority;
} }
var speed = choice.User.BoostedStats.Speed; var speed = choice.User.BoostedStats.Speed;
choice.RunScriptHook(script => script.ChangeSpeed(choice, ref speed)); choice.RunScriptHook(script => script.ChangeSpeed(choice, ref speed));
choice.Speed = speed; choice.Speed = speed;
choice.RandomValue = (uint)Random.GetInt(); choice.RandomValue = (uint)Random.GetInt();
choices[index * PositionsPerSide + i] = choice; choices[index * PositionsPerSide + i] = choice;
choices[index * PositionsPerSide + i] = choice; choices[index * PositionsPerSide + i] = choice;
} }
side.ResetChoices(); side.ResetChoices();
} }
_previousTurnChoices.Add(choices.ToList());
CurrentTurnNumber += 1; CurrentTurnNumber += 1;
ChoiceQueue = new BattleChoiceQueue(choices); ChoiceQueue = new BattleChoiceQueue(choices);
@ -288,6 +300,7 @@ public class BattleImpl : ScriptSource, IBattle
} }
private readonly ScriptContainer _weatherScript = new(); private readonly ScriptContainer _weatherScript = new();
/// <inheritdoc /> /// <inheritdoc />
public void SetWeather(StringKey? weatherName) public void SetWeather(StringKey? weatherName)
{ {
@ -303,19 +316,25 @@ public class BattleImpl : ScriptSource, IBattle
_weatherScript.Clear(); _weatherScript.Clear();
} }
} }
private IScriptSet Volatile { get; } = new ScriptSet(); private IScriptSet Volatile { get; } = new ScriptSet();
/// <inheritdoc /> /// <inheritdoc />
public StringKey? WeatherName => _weatherScript.Script?.Name; public StringKey? WeatherName => _weatherScript.Script?.Name;
private readonly List<IReadOnlyList<ITurnChoice>> _previousTurnChoices = new();
/// <inheritdoc />
public IReadOnlyList<IReadOnlyList<ITurnChoice>> PreviousTurnChoices => _previousTurnChoices;
/// <inheritdoc /> /// <inheritdoc />
public override int ScriptCount => 2; public override int ScriptCount => 2;
/// <inheritdoc /> /// <inheritdoc />
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts) public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts)
{ {
scripts.Add(_weatherScript ); scripts.Add(_weatherScript);
scripts.Add(Volatile); scripts.Add(Volatile);
} }

View File

@ -168,7 +168,7 @@ internal static class MoveTurnExecutor
var hitEventBatch = new EventBatchId(); var hitEventBatch = new EventBatchId();
battle.EventHook.Invoke(new MoveHitEvent(executingMove, hitData, target) battle.EventHook.Invoke(new MoveHitEvent(executingMove, hitData, target)
{ {
BatchId = hitEventBatch BatchId = hitEventBatch,
}); });
target.Damage(damage, DamageSource.MoveDamage, hitEventBatch); target.Damage(damage, DamageSource.MoveDamage, hitEventBatch);
if (!target.IsFainted) if (!target.IsFainted)

View File

@ -22,7 +22,7 @@ public static class TargetResolver
MoveTarget.AllAdjacent => GetAllAdjacent(battle, side, position), MoveTarget.AllAdjacent => GetAllAdjacent(battle, side, position),
MoveTarget.AllAlly => battle.Sides[side].Pokemon.ToList(), MoveTarget.AllAlly => battle.Sides[side].Pokemon.ToList(),
MoveTarget.AllOpponent => battle.Sides[GetOppositeSide(side)].Pokemon.ToList(), MoveTarget.AllOpponent => battle.Sides[GetOppositeSide(side)].Pokemon.ToList(),
_ => throw new ArgumentOutOfRangeException(nameof(target), target, null) _ => throw new ArgumentOutOfRangeException(nameof(target), target, null),
}; };
} }
@ -49,7 +49,7 @@ public static class TargetResolver
return return
[ [
battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position), battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position),
battle.GetPokemon(side, (byte)right) battle.GetPokemon(side, (byte)right),
]; ];
} }
@ -58,14 +58,14 @@ public static class TargetResolver
return return
[ [
battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position), battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position),
battle.GetPokemon(side, (byte)left) battle.GetPokemon(side, (byte)left),
]; ];
} }
return return
[ [
battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position), battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position),
battle.GetPokemon(side, (byte)left), battle.GetPokemon(side, (byte)right) battle.GetPokemon(side, (byte)left), battle.GetPokemon(side, (byte)right),
]; ];
} }
@ -90,7 +90,7 @@ public static class TargetResolver
return return
[ [
battle.GetPokemon(side, position), battle.GetPokemon(side, (byte)left), battle.GetPokemon(side, (byte)right) battle.GetPokemon(side, position), battle.GetPokemon(side, (byte)left), battle.GetPokemon(side, (byte)right),
]; ];
} }
} }

View File

@ -12,7 +12,7 @@ public class TurnChoiceComparer : IComparer<ITurnChoice>
{ {
XEqualsY = 0, XEqualsY = 0,
XLessThanY = -1, XLessThanY = -1,
XGreaterThanY = 1 XGreaterThanY = 1,
} }
private static CompareValues CompareForSameType(ITurnChoice x, ITurnChoice y) private static CompareValues CompareForSameType(ITurnChoice x, ITurnChoice y)
@ -58,7 +58,7 @@ public class TurnChoiceComparer : IComparer<ITurnChoice>
{ {
IMoveChoice => CompareValues.XLessThanY, IMoveChoice => CompareValues.XLessThanY,
IItemChoice itemY => CompareForSameType(itemX, itemY), IItemChoice itemY => CompareForSameType(itemX, itemY),
_ => CompareValues.XGreaterThanY _ => CompareValues.XGreaterThanY,
}; };
case ISwitchChoice switchX: case ISwitchChoice switchX:
// Switch choices go third // Switch choices go third
@ -66,7 +66,7 @@ public class TurnChoiceComparer : IComparer<ITurnChoice>
{ {
IMoveChoice or IItemChoice => CompareValues.XLessThanY, IMoveChoice or IItemChoice => CompareValues.XLessThanY,
ISwitchChoice switchY => CompareForSameType(switchX, switchY), ISwitchChoice switchY => CompareForSameType(switchX, switchY),
_ => CompareValues.XGreaterThanY _ => CompareValues.XGreaterThanY,
}; };
case IPassChoice passX: case IPassChoice passX:
// Pass choices go last // Pass choices go last
@ -74,7 +74,7 @@ public class TurnChoiceComparer : IComparer<ITurnChoice>
{ {
IMoveChoice or IItemChoice or ISwitchChoice => CompareValues.XLessThanY, IMoveChoice or IItemChoice or ISwitchChoice => CompareValues.XLessThanY,
IPassChoice passY => CompareForSameType(passX, passY), IPassChoice passY => CompareForSameType(passX, passY),
_ => CompareValues.XGreaterThanY _ => CompareValues.XGreaterThanY,
}; };
} }

View File

@ -35,7 +35,7 @@ public enum MoveLearnMethod
/// <summary> /// <summary>
/// The move is learned when the Pokémon changes form. /// The move is learned when the Pokémon changes form.
/// </summary> /// </summary>
FormChange FormChange,
} }
/// <summary> /// <summary>

View File

@ -523,7 +523,7 @@ public class PokemonImpl : ScriptSource, IPokemon
{ {
> 0 => StatBoost.IncreaseStatistic(stat, change), > 0 => StatBoost.IncreaseStatistic(stat, change),
< 0 => StatBoost.DecreaseStatistic(stat, change), < 0 => StatBoost.DecreaseStatistic(stat, change),
_ => changed _ => changed,
}; };
if (!changed) if (!changed)
return false; return false;
@ -599,7 +599,7 @@ public class PokemonImpl : ScriptSource, IPokemon
// If the Pokémon is in a battle, we trigger an event to the front-end. // If the Pokémon is in a battle, we trigger an event to the front-end.
BattleData.Battle.EventHook.Invoke(new DamageEvent(this, CurrentHealth, newHealth, source) BattleData.Battle.EventHook.Invoke(new DamageEvent(this, CurrentHealth, newHealth, source)
{ {
BatchId = batchId BatchId = batchId,
}); });
// And allow scripts to execute. // And allow scripts to execute.
this.RunScriptHook(script => script.OnDamage(this, source, CurrentHealth, newHealth)); this.RunScriptHook(script => script.OnDamage(this, source, CurrentHealth, newHealth));

View File

@ -14,7 +14,6 @@ namespace PkmnLib.Dynamic.ScriptHandling;
/// </summary> /// </summary>
public abstract class Script public abstract class Script
{ {
private bool _markedForDeletion;
private int _suppressCount; private int _suppressCount;
/// <summary> /// <summary>
@ -24,9 +23,6 @@ public abstract class Script
/// </summary> /// </summary>
public virtual StringKey Name => this.ResolveName(); public virtual StringKey Name => this.ResolveName();
public bool MarkForDeletion() => _markedForDeletion = true;
public bool IsMarkedForDeletion() => _markedForDeletion;
/// <summary> /// <summary>
/// A script can be suppressed by other scripts. If a script is suppressed by at least one script /// A script can be suppressed by other scripts. If a script is suppressed by at least one script
/// we will not execute its methods. This should return the number of suppressions on the script. /// we will not execute its methods. This should return the number of suppressions on the script.

View File

@ -52,7 +52,6 @@ public class ScriptContainer : IEnumerable<ScriptContainer>
if (Script is not null) if (Script is not null)
{ {
Script.OnRemove(); Script.OnRemove();
Script.MarkForDeletion();
} }
Script = script; Script = script;
} }
@ -65,7 +64,6 @@ public class ScriptContainer : IEnumerable<ScriptContainer>
if (Script is not null) if (Script is not null)
{ {
Script.OnRemove(); Script.OnRemove();
Script.MarkForDeletion();
} }
Script = null; Script = null;
} }

View File

@ -122,7 +122,6 @@ public class ScriptSet : IScriptSet
if (!script.IsEmpty) if (!script.IsEmpty)
{ {
script.Script.OnRemove(); script.Script.OnRemove();
script.Script.MarkForDeletion();
} }
} }
_scripts.Clear(); _scripts.Clear();

View File

@ -166,7 +166,7 @@ public class FormImpl : IForm
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++)
@ -175,7 +175,7 @@ public class FormImpl : IForm
return new AbilityIndex return new AbilityIndex
{ {
IsHidden = true, IsHidden = true,
Index = (byte)i Index = (byte)i,
}; };
} }
return null; return null;

View File

@ -17,5 +17,5 @@ public enum Gender : byte
/// <summary> /// <summary>
/// The Pokémon is female. /// The Pokémon is female.
/// </summary> /// </summary>
Female Female,
} }

View File

@ -28,5 +28,5 @@ public enum Statistic : byte
/// <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>
Speed Speed,
} }

View File

@ -63,7 +63,7 @@ public record ImmutableStatisticSet<T>
Statistic.SpecialAttack => SpecialAttack, Statistic.SpecialAttack => SpecialAttack,
Statistic.SpecialDefense => SpecialDefense, Statistic.SpecialDefense => SpecialDefense,
Statistic.Speed => Speed, Statistic.Speed => Speed,
_ => throw new ArgumentException("Invalid statistic.") _ => throw new ArgumentException("Invalid statistic."),
}; };
} }
} }

View File

@ -23,7 +23,7 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
return stat switch return stat switch
{ {
Statistic.Hp => CalculateHealthStat(pokemon), Statistic.Hp => CalculateHealthStat(pokemon),
_ => CalculateNormalStat(pokemon, stat) _ => CalculateNormalStat(pokemon, stat),
}; };
} }
@ -90,7 +90,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 System.ArgumentException("Stat boost was out of expected range of -6 to 6"),
}; };
} }
} }

View File

@ -62,7 +62,7 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
{ {
> uint.MaxValue => uint.MaxValue, > uint.MaxValue => uint.MaxValue,
< 1 => 1, < 1 => 1,
_ => (uint)floatDamage _ => (uint)floatDamage,
}; };
executingMove.RunScriptHook(script => executingMove.RunScriptHook(script =>
script.ChangeDamage(executingMove, target, hitNumber, ref damage)); script.ChangeDamage(executingMove, target, hitNumber, ref damage));
@ -98,7 +98,7 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
0 => random.GetInt(24) == 0, 0 => random.GetInt(24) == 0,
1 => random.GetInt(8) == 0, 1 => random.GetInt(8) == 0,
2 => random.GetInt(2) == 0, 2 => random.GetInt(2) == 0,
_ => true _ => true,
}; };
} }

View File

@ -32,7 +32,7 @@ public class Gen7MiscLibrary : IMiscLibrary
>= 6 and <= 9 => TimeOfDay.Morning, >= 6 and <= 9 => TimeOfDay.Morning,
>= 10 and <= 16 => TimeOfDay.Day, >= 10 and <= 16 => TimeOfDay.Day,
17 => TimeOfDay.Evening, 17 => TimeOfDay.Evening,
_ => TimeOfDay.Night _ => TimeOfDay.Night,
}; };
} }
} }