using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Static; using PkmnLib.Static.Moves; using PkmnLib.Static.Utils; using PkmnLib.Static.Utils.Errors; namespace PkmnLib.Dynamic.Models; /// /// Data for a single hit on a target. /// public interface IHitData { /// /// Whether the hit is critical. /// bool IsCritical { get; } /// /// The base power of the hit. /// byte BasePower { get; } /// /// The effectiveness of the hit. /// float Effectiveness { get; } /// /// The damage done by the hit. /// uint Damage { get; } /// /// The type of the hit. /// TypeIdentifier Type { get; } /// /// Whether the hit has failed. /// bool HasFailed { get; } /// /// Fails the hit. /// void Fail(); } /// public record HitData : IHitData { /// public bool IsCritical { get; internal set; } /// public byte BasePower { get; internal set; } /// public float Effectiveness { get; internal set; } /// public uint Damage { get; internal set; } /// public TypeIdentifier Type { get; internal set; } /// public bool HasFailed { get; private set; } /// public void Fail() => HasFailed = true; } /// /// An executing move is the data of the move for while it is executing. /// public interface IExecutingMove : IScriptSource { /// /// The number of targets this move has. /// int TargetCount { get; } /// /// The number of hits this move has per target. /// byte NumberOfHits { get; } /// /// The user of the move. /// IPokemon User { get; } /// /// The move the user has actually chosen to do. /// ILearnedMove ChosenMove { get; } /// /// The move that the user is actually going to do. This can be different from the chosen move, for example /// when metronome is used, in which case the chosen move will be metronome, and the movedata will be the /// move that metronome has chosen. /// IMoveData UseMove { get; } /// /// The script of the move. /// ScriptContainer Script { get; } /// /// Gets a hit data for a target, with a specific index. /// IHitData GetHitData(IPokemon target, byte hit); /// /// Checks whether a Pokémon is a target for this move. /// bool IsPokemonTarget(IPokemon target); /// /// Gets the index of the hits in this move where the hits for a specific target start. /// int GetTargetIndex(IPokemon target); /// /// Gets a hit based on its raw index. /// IHitData GetDataFromRawIndex(int index); } /// public class ExecutingMoveImpl : ScriptSource, IExecutingMove { private readonly IReadOnlyList _targets; private readonly IHitData[] _hits; /// public ExecutingMoveImpl(IReadOnlyList targets, byte numberOfHits, IPokemon user, ILearnedMove chosenMove, IMoveData useMove, ScriptContainer script) { _targets = targets; NumberOfHits = numberOfHits; User = user; ChosenMove = chosenMove; UseMove = useMove; Script = script; var totalHits = targets.Count * numberOfHits; _hits = new IHitData[totalHits]; for (var i = 0; i < totalHits; i++) { _hits[i] = new HitData(); } } /// public int TargetCount => _targets.Count; /// public byte NumberOfHits { get; } /// public IPokemon User { get; } /// public ILearnedMove ChosenMove { get; } /// public IMoveData UseMove { get; } /// public ScriptContainer Script { get; } /// public IHitData GetHitData(IPokemon target, byte hit) { var targetIndex = _targets.IndexOf(target); if (targetIndex == -1) { throw new ArgumentException("The target is not a target of this move."); } var index = targetIndex * NumberOfHits + hit; return _hits[index]; } /// public bool IsPokemonTarget(IPokemon target) => _targets.Contains(target); /// public int GetTargetIndex(IPokemon target) { var targetIndex = _targets.IndexOf(target); if (targetIndex == -1) throw new ArgumentException("The target is not a target of this move."); return targetIndex * NumberOfHits; } /// public IHitData GetDataFromRawIndex(int index) { if (index < 0 || index >= _hits.Length) throw new OutOfRangeException("Hit", index, _hits.Length - 1); return _hits[index]; } /// public override int ScriptCount => 1 + User.ScriptCount; /// public override void GetOwnScripts(List> scripts) { scripts.Add(Script); } /// public override void CollectScripts(List> scripts) { scripts.Add(Script); User.CollectScripts(scripts); } }