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.
|
/// Calculate a single boosted stat of a Pokemon, including stat boosts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
uint CalculateBoostedStat(IPokemon pokemon, Statistic stat);
|
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.
|
// modifying it.
|
||||||
if (accuracy != 255)
|
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)
|
if (accuracy < 100 && battle.Random.GetInt(100) >= accuracy)
|
||||||
{
|
{
|
||||||
executingMove.RunScriptHook(x => x.OnMoveMiss(executingMove, target));
|
executingMove.RunScriptHook(x => x.OnMoveMiss(executingMove, target));
|
||||||
|
|
|
@ -43,9 +43,10 @@ public class ScriptRegistry
|
||||||
if (type == null)
|
if (type == null)
|
||||||
throw new ArgumentNullException(nameof(type));
|
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)
|
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.
|
// We create a lambda that creates a new instance of the script type.
|
||||||
// This is more performant than using Activator.CreateInstance.
|
// 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
|
/// 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.
|
/// the percentage accuracy, so anything above 100% will make it always hit.
|
||||||
/// </summary>
|
/// </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)
|
if (value.CompareTo(min) < 0)
|
||||||
return min;
|
return min;
|
||||||
|
@ -307,6 +307,20 @@ public record StatBoostStatisticSet : ClampedStatisticSet<sbyte>
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override sbyte Max => 6;
|
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"/>
|
/// <inheritdoc cref="StatBoostStatisticSet"/>
|
||||||
public StatBoostStatisticSet() : base(0, 0, 0, 0, 0, 0)
|
public StatBoostStatisticSet() : base(0, 0, 0, 0, 0, 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
using System;
|
||||||
using PkmnLib.Dynamic.Libraries;
|
using PkmnLib.Dynamic.Libraries;
|
||||||
using PkmnLib.Dynamic.Models;
|
using PkmnLib.Dynamic.Models;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
using PkmnLib.Static;
|
using PkmnLib.Static;
|
||||||
|
|
||||||
namespace PkmnLib.Plugin.Gen7.Libraries;
|
namespace PkmnLib.Plugin.Gen7.Libraries;
|
||||||
|
@ -48,6 +50,33 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
|
||||||
return (uint)boostedStat;
|
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)
|
private static uint CalculateHealthStat(IPokemon pokemon)
|
||||||
{
|
{
|
||||||
var baseValue = (ulong)pokemon.Form.BaseStats.Hp;
|
var baseValue = (ulong)pokemon.Form.BaseStats.Hp;
|
||||||
|
|
|
@ -28,6 +28,8 @@ public class AuroraVeilEffect : Script
|
||||||
{
|
{
|
||||||
public int NumberOfTurns { get; set; }
|
public int NumberOfTurns { get; set; }
|
||||||
|
|
||||||
|
private AuroraVeilEffect(){}
|
||||||
|
|
||||||
public AuroraVeilEffect(int numberOfTurns)
|
public AuroraVeilEffect(int numberOfTurns)
|
||||||
{
|
{
|
||||||
NumberOfTurns = numberOfTurns;
|
NumberOfTurns = numberOfTurns;
|
||||||
|
|
Loading…
Reference in New Issue