Implements accuracy/evasion
This commit is contained in:
parent
06ce7fd38d
commit
5b518df24a
|
@ -27,4 +27,9 @@ public interface IBattleStatCalculator
|
|||
/// Calculate a single boosted stat of a Pokemon, including stat boosts.
|
||||
/// </summary>
|
||||
uint CalculateBoostedStat(IPokemon pokemon, Statistic stat);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the accuracy for a move, taking into account any accuracy modifiers.
|
||||
/// </summary>
|
||||
byte CalculateModifiedAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, byte moveAccuracy);
|
||||
}
|
|
@ -140,10 +140,10 @@ internal static class MoveTurnExecutor
|
|||
// modifying it.
|
||||
if (accuracy != 255)
|
||||
{
|
||||
executingMove.RunScriptHook(x => x.ChangeAccuracy(executingMove, target, hitIndex, ref accuracy));
|
||||
accuracy = battle.Library.StatCalculator.CalculateModifiedAccuracy(executingMove, target,
|
||||
hitIndex, accuracy);
|
||||
}
|
||||
|
||||
// TODO: Deal with accuracy/evasion stats.
|
||||
if (accuracy < 100 && battle.Random.GetInt(100) >= accuracy)
|
||||
{
|
||||
executingMove.RunScriptHook(x => x.OnMoveMiss(executingMove, target));
|
||||
|
|
|
@ -43,9 +43,10 @@ public class ScriptRegistry
|
|||
if (type == null)
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
|
||||
var constructor = type.GetConstructor(Type.EmptyTypes);
|
||||
var constructor = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
|
||||
null, Type.EmptyTypes, null);
|
||||
if (constructor == null)
|
||||
throw new ArgumentException("The type must have a parameterless constructor.");
|
||||
throw new ArgumentException($"Type {type} does not have a parameterless constructor.");
|
||||
|
||||
// We create a lambda that creates a new instance of the script type.
|
||||
// This is more performant than using Activator.CreateInstance.
|
||||
|
|
|
@ -207,7 +207,7 @@ public abstract class Script
|
|||
/// This function allows a script to modify the accuracy of a move used. This value represents
|
||||
/// the percentage accuracy, so anything above 100% will make it always hit.
|
||||
/// </summary>
|
||||
public virtual void ChangeAccuracy(IExecutingMove move, IPokemon target, byte hit, ref byte accuracy)
|
||||
public virtual void ChangeAccuracyModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -248,7 +248,7 @@ public abstract record ClampedStatisticSet<T> : StatisticSet<T>
|
|||
{
|
||||
}
|
||||
|
||||
private static T Clamp(T value, T min, T max)
|
||||
protected static T Clamp(T value, T min, T max)
|
||||
{
|
||||
if (value.CompareTo(min) < 0)
|
||||
return min;
|
||||
|
@ -307,6 +307,20 @@ public record StatBoostStatisticSet : ClampedStatisticSet<sbyte>
|
|||
/// <inheritdoc />
|
||||
protected override sbyte Max => 6;
|
||||
|
||||
private sbyte _evasion;
|
||||
public sbyte Evasion
|
||||
{
|
||||
get => _evasion;
|
||||
set => _evasion = Clamp(value, Min, Max);
|
||||
}
|
||||
|
||||
private sbyte _accuracy;
|
||||
public sbyte Accuracy
|
||||
{
|
||||
get => _accuracy;
|
||||
set => _accuracy = Clamp(value, Min, Max);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="StatBoostStatisticSet"/>
|
||||
public StatBoostStatisticSet() : base(0, 0, 0, 0, 0, 0)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using PkmnLib.Dynamic.Libraries;
|
||||
using PkmnLib.Dynamic.Models;
|
||||
using PkmnLib.Dynamic.ScriptHandling;
|
||||
using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Libraries;
|
||||
|
@ -48,6 +50,33 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
|
|||
return (uint)boostedStat;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte CalculateModifiedAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, byte moveAccuracy)
|
||||
{
|
||||
var accuracyModifier = 1.0f;
|
||||
executingMove.RunScriptHook(x => x.ChangeAccuracyModifier(executingMove, target, hitIndex, ref accuracyModifier));
|
||||
var modifiedAccuracy = (int)(moveAccuracy * accuracyModifier);
|
||||
var targetEvasion = target.StatBoost.Evasion;
|
||||
var userAccuracy = executingMove.User.StatBoost.Accuracy;
|
||||
var difference = targetEvasion - userAccuracy;
|
||||
var statModifier = difference switch
|
||||
{
|
||||
> 0 => 3.0f / (3.0f + difference),
|
||||
< 0 => 3.0f + Math.Abs(difference) / 3.0f,
|
||||
_ => 1.0f
|
||||
};
|
||||
modifiedAccuracy = (int)(modifiedAccuracy * statModifier);
|
||||
modifiedAccuracy = modifiedAccuracy switch
|
||||
{
|
||||
> 255 => 255,
|
||||
< 0 => 0,
|
||||
_ => modifiedAccuracy
|
||||
};
|
||||
// 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.
|
||||
return (byte)modifiedAccuracy;
|
||||
}
|
||||
|
||||
private static uint CalculateHealthStat(IPokemon pokemon)
|
||||
{
|
||||
var baseValue = (ulong)pokemon.Form.BaseStats.Hp;
|
||||
|
|
|
@ -28,6 +28,8 @@ public class AuroraVeilEffect : Script
|
|||
{
|
||||
public int NumberOfTurns { get; set; }
|
||||
|
||||
private AuroraVeilEffect(){}
|
||||
|
||||
public AuroraVeilEffect(int numberOfTurns)
|
||||
{
|
||||
NumberOfTurns = numberOfTurns;
|
||||
|
|
Loading…
Reference in New Issue