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);
}
}