Implement stat drop handling for AI, Fixes for Conversion2
All checks were successful
Build / Build (push) Successful in 39s
All checks were successful
Build / Build (push) Successful in 39s
This commit is contained in:
@@ -84,7 +84,10 @@ public class TypeLibrary : IReadOnlyTypeLibrary
|
|||||||
public IEnumerable<(TypeIdentifier, float)> GetAllEffectivenessFromAttacking(TypeIdentifier attacking)
|
public IEnumerable<(TypeIdentifier, float)> GetAllEffectivenessFromAttacking(TypeIdentifier attacking)
|
||||||
{
|
{
|
||||||
if (attacking.Value < 1 || attacking.Value > _effectiveness.Count)
|
if (attacking.Value < 1 || attacking.Value > _effectiveness.Count)
|
||||||
throw new ArgumentOutOfRangeException(nameof(attacking));
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(attacking), attacking,
|
||||||
|
"Attacking type index is out of range.");
|
||||||
|
}
|
||||||
for (var i = 0; i < _effectiveness.Count; i++)
|
for (var i = 0; i < _effectiveness.Count; i++)
|
||||||
{
|
{
|
||||||
var type = _types[i];
|
var type = _types[i];
|
||||||
|
|||||||
@@ -36,4 +36,7 @@ public readonly struct TypeIdentifier : IEquatable<TypeIdentifier>
|
|||||||
|
|
||||||
public static bool operator ==(TypeIdentifier left, TypeIdentifier right) => left.Equals(right);
|
public static bool operator ==(TypeIdentifier left, TypeIdentifier right) => left.Equals(right);
|
||||||
public static bool operator !=(TypeIdentifier left, TypeIdentifier right) => !left.Equals(right);
|
public static bool operator !=(TypeIdentifier left, TypeIdentifier right) => !left.Equals(right);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => Name.ToString();
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ public static class AIHelperFunctions
|
|||||||
{
|
{
|
||||||
return ExplicitAI.MoveUselessScore;
|
return ExplicitAI.MoveUselessScore;
|
||||||
}
|
}
|
||||||
return GetScoreForTargetStatDrop(move, target, statChanges, fixedChange, true);
|
return GetScoreForTargetStatDrop(score, move, target, statChanges, fixedChange, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var addEffect = move.GetScoreChangeForAdditionalEffect(target);
|
var addEffect = move.GetScoreChangeForAdditionalEffect(target);
|
||||||
@@ -80,9 +80,70 @@ public static class AIHelperFunctions
|
|||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetScoreForTargetStatDrop(AIMoveState move, IPokemon target, StatisticSet<sbyte> statChanges,
|
public static int GetScoreForTargetStatDrop(int score, AIMoveState move, IPokemon target,
|
||||||
bool fixedChange = false, bool ignoreContrary = false) =>
|
StatisticSet<sbyte> statChanges, bool fixedChange = false, bool ignoreContrary = false)
|
||||||
throw new NotImplementedException("This method is not implemented");
|
{
|
||||||
|
var wholeEffect = move.Move.Category != MoveCategory.Status;
|
||||||
|
|
||||||
|
var desireMult = -1;
|
||||||
|
if (move.User.BattleData?.SideIndex == target.BattleData?.SideIndex)
|
||||||
|
desireMult = 1;
|
||||||
|
if (!ignoreContrary && !fixedChange && target.ActiveAbility?.Name == "contrary")
|
||||||
|
{
|
||||||
|
if (desireMult > 0 && wholeEffect)
|
||||||
|
{
|
||||||
|
return ExplicitAI.MoveUselessScore;
|
||||||
|
}
|
||||||
|
return GetScoreForTargetStatRaise(score, move, target, statChanges, fixedChange, true);
|
||||||
|
}
|
||||||
|
var addEffect = move.GetScoreChangeForAdditionalEffect(target);
|
||||||
|
if (addEffect == -999)
|
||||||
|
{
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
var expectedEndOfTurnDamage = 0;
|
||||||
|
target.RunScriptHook<IAIInfoScriptExpectedEndOfTurnDamage>(x =>
|
||||||
|
x.ExpectedEndOfTurnDamage(target, ref expectedEndOfTurnDamage));
|
||||||
|
// If the target is expected to faint from the end of turn damage, the stat drop is useless
|
||||||
|
if (expectedEndOfTurnDamage >= target.CurrentHealth)
|
||||||
|
return wholeEffect ? ExplicitAI.MoveUselessScore : score;
|
||||||
|
|
||||||
|
var foeIsAware = false;
|
||||||
|
if (target.BattleData?.BattleSide.Pokemon.All(x => x?.ActiveAbility?.Name != "unaware") == true)
|
||||||
|
{
|
||||||
|
foeIsAware = true;
|
||||||
|
}
|
||||||
|
if (!foeIsAware)
|
||||||
|
{
|
||||||
|
return wholeEffect ? ExplicitAI.MoveUselessScore : score;
|
||||||
|
}
|
||||||
|
var realStatChanges = new StatBoostStatisticSet();
|
||||||
|
foreach (var (stat, i) in statChanges)
|
||||||
|
{
|
||||||
|
var decrement = i;
|
||||||
|
if (!IsStatDropWorthwhile(target, stat, decrement))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!fixedChange && target.ActiveAbility?.Name == "simple")
|
||||||
|
{
|
||||||
|
decrement *= 2;
|
||||||
|
}
|
||||||
|
decrement = (sbyte)Math.Min(decrement,
|
||||||
|
StatBoostStatisticSet.MinStatBoost - target.StatBoost.GetStatistic(stat));
|
||||||
|
realStatChanges.SetStatistic(stat, (sbyte)-decrement);
|
||||||
|
}
|
||||||
|
if (realStatChanges.IsEmpty)
|
||||||
|
return wholeEffect ? ExplicitAI.MoveUselessScore : score;
|
||||||
|
score += addEffect;
|
||||||
|
score = GetTargetStatDropScoreGeneric(score, target, realStatChanges, move, desireMult);
|
||||||
|
foreach (var realStatChange in realStatChanges.Where(x => x.value > 0))
|
||||||
|
{
|
||||||
|
GetTargetStatDropScoreOne(ref score, target, realStatChange.statistic, realStatChange.value, move,
|
||||||
|
desireMult);
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if a stat raise is worthwhile for the given Pokémon and stat.
|
/// Checks if a stat raise is worthwhile for the given Pokémon and stat.
|
||||||
@@ -158,6 +219,53 @@ public static class AIHelperFunctions
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsStatDropWorthwhile(IPokemon pokemon, Statistic stat, sbyte amount)
|
||||||
|
{
|
||||||
|
if (amount == 0)
|
||||||
|
return false;
|
||||||
|
switch (stat)
|
||||||
|
{
|
||||||
|
case Statistic.Attack:
|
||||||
|
{
|
||||||
|
return pokemon.Moves.WhereNotNull().Any(x => x.MoveData.Category == MoveCategory.Physical &&
|
||||||
|
x.MoveData.SecondaryEffect?.Name != FoulPlayAbilityName);
|
||||||
|
}
|
||||||
|
case Statistic.Defense:
|
||||||
|
{
|
||||||
|
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||||
|
return opponentSide.Pokemon.WhereNotNull().Any(x => x.Moves.WhereNotNull().Any(y =>
|
||||||
|
y.MoveData.Category == MoveCategory.Physical || y.MoveData.SecondaryEffect?.Name == "psyshock"));
|
||||||
|
}
|
||||||
|
case Statistic.SpecialAttack:
|
||||||
|
{
|
||||||
|
return pokemon.Moves.WhereNotNull().Any(x => x.MoveData.Category == MoveCategory.Special);
|
||||||
|
}
|
||||||
|
case Statistic.SpecialDefense:
|
||||||
|
{
|
||||||
|
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||||
|
return opponentSide.Pokemon.WhereNotNull().Any(x => x.Moves.WhereNotNull().Any(y =>
|
||||||
|
y.MoveData.Category == MoveCategory.Special && y.MoveData.SecondaryEffect?.Name != "psyshock"));
|
||||||
|
}
|
||||||
|
case Statistic.Speed:
|
||||||
|
{
|
||||||
|
if (!pokemon.HasMoveWithEffect("electro_ball"))
|
||||||
|
{
|
||||||
|
var targetSpeed = pokemon.BoostedStats.Speed;
|
||||||
|
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||||
|
return opponentSide.Pokemon.WhereNotNull().Select(opponent => opponent.BoostedStats.Speed)
|
||||||
|
.Any(foeSpeed => targetSpeed > foeSpeed && targetSpeed < foeSpeed * 2.5);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case Statistic.Accuracy:
|
||||||
|
{
|
||||||
|
var meaningful = pokemon.Moves.WhereNotNull().Any(x => x.MoveData.Accuracy != 255);
|
||||||
|
return meaningful;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly StringKey FoulPlayAbilityName = "foul_play";
|
private static readonly StringKey FoulPlayAbilityName = "foul_play";
|
||||||
|
|
||||||
private static void GetTargetStatRaiseScoreOne(ref int score, IPokemon target, Statistic stat, sbyte increment,
|
private static void GetTargetStatRaiseScoreOne(ref int score, IPokemon target, Statistic stat, sbyte increment,
|
||||||
@@ -295,6 +403,115 @@ public static class AIHelperFunctions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void GetTargetStatDropScoreOne(ref int score, IPokemon target, Statistic stat, sbyte decrement,
|
||||||
|
AIMoveState move, float desireMult = 1)
|
||||||
|
{
|
||||||
|
var oldStage = target.StatBoost.GetStatistic(stat);
|
||||||
|
var newStage = (sbyte)(oldStage - decrement);
|
||||||
|
var decMult = Gen7BattleStatCalculator.GetStatBoostModifier(oldStage) /
|
||||||
|
Gen7BattleStatCalculator.GetStatBoostModifier(Math.Max(newStage, (sbyte)-6));
|
||||||
|
decMult -= 1;
|
||||||
|
decMult *= desireMult;
|
||||||
|
var opponentSide = target.BattleData!.Battle.Sides.First(x => x != target.BattleData.BattleSide);
|
||||||
|
|
||||||
|
switch (stat)
|
||||||
|
{
|
||||||
|
case Statistic.Attack:
|
||||||
|
{
|
||||||
|
if (oldStage <= -2 && decrement == 1)
|
||||||
|
score -= (int)(10 * (target.Opposes(move.User) ? 1 : desireMult));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var hasSpecialMoves = target.Moves.WhereNotNull()
|
||||||
|
.Any(x => x.MoveData.Category == MoveCategory.Special);
|
||||||
|
var dec = hasSpecialMoves ? 8 : 12;
|
||||||
|
score += (int)(dec * decMult);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statistic.Defense:
|
||||||
|
{
|
||||||
|
if (oldStage <= -2 && decrement == 1)
|
||||||
|
score -= (int)(10 * (target.Opposes(move.User) ? 1 : desireMult));
|
||||||
|
else
|
||||||
|
score += (int)(10 * decMult);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statistic.SpecialAttack:
|
||||||
|
{
|
||||||
|
if (oldStage <= -2 && decrement == 1)
|
||||||
|
score -= (int)(10 * (target.Opposes(move.User) ? 1 : desireMult));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var hasPhysicalMoves = target.Moves.WhereNotNull().Any(x =>
|
||||||
|
x.MoveData.Category == MoveCategory.Physical &&
|
||||||
|
x.MoveData.SecondaryEffect?.Name != FoulPlayAbilityName);
|
||||||
|
var dec = hasPhysicalMoves ? 8 : 12;
|
||||||
|
score += (int)(dec * decMult);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statistic.SpecialDefense:
|
||||||
|
{
|
||||||
|
if (oldStage <= -2 && decrement == 1)
|
||||||
|
score -= (int)(10 * (target.Opposes(move.User) ? 1 : desireMult));
|
||||||
|
else
|
||||||
|
score += (int)(10 * decMult);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statistic.Speed:
|
||||||
|
{
|
||||||
|
var targetSpeed = target.BoostedStats.Speed;
|
||||||
|
foreach (var opponent in opponentSide.Pokemon.WhereNotNull())
|
||||||
|
{
|
||||||
|
var foeSpeed = opponent.BoostedStats.Speed;
|
||||||
|
if (targetSpeed < foeSpeed)
|
||||||
|
continue;
|
||||||
|
if (targetSpeed > foeSpeed * 2.5)
|
||||||
|
continue;
|
||||||
|
if (targetSpeed < foeSpeed * 2 / (decrement + 2))
|
||||||
|
score += (int)(15 * decMult);
|
||||||
|
else
|
||||||
|
score += (int)(8 * decMult);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (opponentSide.Pokemon.WhereNotNull().Any(x => x.HasMoveWithEffect("electro_ball")))
|
||||||
|
{
|
||||||
|
score += (int)(5 * decMult);
|
||||||
|
}
|
||||||
|
if (target.ActiveAbility?.Name == "speed_boost")
|
||||||
|
{
|
||||||
|
score -= (int)(15 * (target.Opposes(move.User) ? 1 : desireMult));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statistic.Accuracy:
|
||||||
|
{
|
||||||
|
if (oldStage <= -2 && decrement == 1)
|
||||||
|
score -= (int)(10 * (target.Opposes(move.User) ? 1 : desireMult));
|
||||||
|
else
|
||||||
|
score += (int)(10 * decMult);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statistic.Evasion:
|
||||||
|
{
|
||||||
|
if (oldStage <= -2 && decrement == 1)
|
||||||
|
score -= (int)(10 * (target.Opposes(move.User) ? 1 : desireMult));
|
||||||
|
else
|
||||||
|
score += (int)(10 * decMult);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target.HasMoveWithEffect("power_trip"))
|
||||||
|
{
|
||||||
|
score += (int)(5 * decrement * desireMult);
|
||||||
|
}
|
||||||
|
if (opponentSide.Pokemon.WhereNotNull().Any(x => x.HasMoveWithEffect("punishment")))
|
||||||
|
{
|
||||||
|
score -= (int)(5 * decrement * desireMult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates the score for the generic concept of raising a target's stats.
|
/// Calculates the score for the generic concept of raising a target's stats.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -311,6 +528,19 @@ public static class AIHelperFunctions
|
|||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int GetTargetStatDropScoreGeneric(int score, IPokemon target, StatisticSet<sbyte> statChanges,
|
||||||
|
AIMoveState move, float desireMult = 1)
|
||||||
|
{
|
||||||
|
var totalDecrement = statChanges.Sum(x => x.value);
|
||||||
|
var turns = target.BattleData!.Battle.CurrentTurnNumber - target.BattleData!.SwitchInTurn;
|
||||||
|
if (turns < 2 && move.Move.Category == MoveCategory.Status)
|
||||||
|
score += (int)(totalDecrement * desireMult * 5);
|
||||||
|
|
||||||
|
score +=
|
||||||
|
(int)(totalDecrement * desireMult * ((100 * (target.CurrentHealth / (float)target.MaxHealth) - 50) / 8));
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
private static int GetScoreChangeForAdditionalEffect(this AIMoveState move, IPokemon? target)
|
private static int GetScoreChangeForAdditionalEffect(this AIMoveState move, IPokemon? target)
|
||||||
{
|
{
|
||||||
if (move.Move.SecondaryEffect is null)
|
if (move.Move.SecondaryEffect is null)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
using PkmnLib.Dynamic.AI.Explicit;
|
||||||
|
using PkmnLib.Plugin.Gen7.AI;
|
||||||
|
|
||||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
public abstract class ChangeTargetStats : Script, IScriptOnInitialize, IScriptOnSecondaryEffect
|
public abstract class ChangeTargetStats : Script, IScriptOnInitialize, IScriptOnSecondaryEffect
|
||||||
@@ -31,6 +34,19 @@ public abstract class ChangeTargetStats : Script, IScriptOnInitialize, IScriptOn
|
|||||||
{
|
{
|
||||||
target.ChangeStatBoost(_stat, _amount, target == move.User, false);
|
target.ChangeStatBoost(_stat, _amount, target == move.User, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static void GetMoveEffectScore(MoveOption option, Statistic stat, ref int score)
|
||||||
|
{
|
||||||
|
if (option.Move.Move.SecondaryEffect == null ||
|
||||||
|
!option.Move.Move.SecondaryEffect.Parameters.TryGetValue("amount", out var amountObj) ||
|
||||||
|
amountObj is not int amount)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var statisticSet = new StatBoostStatisticSet();
|
||||||
|
statisticSet.SetStatistic(stat, (sbyte)amount);
|
||||||
|
score = AIHelperFunctions.GetScoreForTargetStatDrop(score, option.Move, option.Move.User, statisticSet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Script(ScriptCategory.Move, "change_target_attack")]
|
[Script(ScriptCategory.Move, "change_target_attack")]
|
||||||
@@ -39,6 +55,10 @@ public class ChangeTargetAttack : ChangeTargetStats
|
|||||||
public ChangeTargetAttack() : base(Statistic.Attack)
|
public ChangeTargetAttack() : base(Statistic.Attack)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AIMoveScoreFunction]
|
||||||
|
public static void AIMoveEffectScore(IExplicitAI ai, MoveOption option, ref int score) =>
|
||||||
|
GetMoveEffectScore(option, Statistic.Attack, ref score);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Script(ScriptCategory.Move, "change_target_defense")]
|
[Script(ScriptCategory.Move, "change_target_defense")]
|
||||||
@@ -47,6 +67,10 @@ public class ChangeTargetDefense : ChangeTargetStats
|
|||||||
public ChangeTargetDefense() : base(Statistic.Defense)
|
public ChangeTargetDefense() : base(Statistic.Defense)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AIMoveScoreFunction]
|
||||||
|
public static void AIMoveEffectScore(IExplicitAI ai, MoveOption option, ref int score) =>
|
||||||
|
GetMoveEffectScore(option, Statistic.Defense, ref score);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Script(ScriptCategory.Move, "change_target_special_attack")]
|
[Script(ScriptCategory.Move, "change_target_special_attack")]
|
||||||
@@ -55,6 +79,10 @@ public class ChangeTargetSpecialAttack : ChangeTargetStats
|
|||||||
public ChangeTargetSpecialAttack() : base(Statistic.SpecialAttack)
|
public ChangeTargetSpecialAttack() : base(Statistic.SpecialAttack)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AIMoveScoreFunction]
|
||||||
|
public static void AIMoveEffectScore(IExplicitAI ai, MoveOption option, ref int score) =>
|
||||||
|
GetMoveEffectScore(option, Statistic.SpecialAttack, ref score);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Script(ScriptCategory.Move, "change_target_special_defense")]
|
[Script(ScriptCategory.Move, "change_target_special_defense")]
|
||||||
@@ -63,6 +91,10 @@ public class ChangeTargetSpecialDefense : ChangeTargetStats
|
|||||||
public ChangeTargetSpecialDefense() : base(Statistic.SpecialDefense)
|
public ChangeTargetSpecialDefense() : base(Statistic.SpecialDefense)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AIMoveScoreFunction]
|
||||||
|
public static void AIMoveEffectScore(IExplicitAI ai, MoveOption option, ref int score) =>
|
||||||
|
GetMoveEffectScore(option, Statistic.SpecialDefense, ref score);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Script(ScriptCategory.Move, "change_target_speed")]
|
[Script(ScriptCategory.Move, "change_target_speed")]
|
||||||
@@ -71,6 +103,10 @@ public class ChangeTargetSpeed : ChangeTargetStats
|
|||||||
public ChangeTargetSpeed() : base(Statistic.Speed)
|
public ChangeTargetSpeed() : base(Statistic.Speed)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AIMoveScoreFunction]
|
||||||
|
public static void AIMoveEffectScore(IExplicitAI ai, MoveOption option, ref int score) =>
|
||||||
|
GetMoveEffectScore(option, Statistic.Speed, ref score);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Script(ScriptCategory.Move, "change_target_accuracy")]
|
[Script(ScriptCategory.Move, "change_target_accuracy")]
|
||||||
@@ -79,6 +115,10 @@ public class ChangeTargetAccuracy : ChangeTargetStats
|
|||||||
public ChangeTargetAccuracy() : base(Statistic.Accuracy)
|
public ChangeTargetAccuracy() : base(Statistic.Accuracy)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AIMoveScoreFunction]
|
||||||
|
public static void AIMoveEffectScore(IExplicitAI ai, MoveOption option, ref int score) =>
|
||||||
|
GetMoveEffectScore(option, Statistic.Accuracy, ref score);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Script(ScriptCategory.Move, "change_target_evasion")]
|
[Script(ScriptCategory.Move, "change_target_evasion")]
|
||||||
@@ -87,4 +127,8 @@ public class ChangeTargetEvasion : ChangeTargetStats
|
|||||||
public ChangeTargetEvasion() : base(Statistic.Evasion)
|
public ChangeTargetEvasion() : base(Statistic.Evasion)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AIMoveScoreFunction]
|
||||||
|
public static void AIMoveEffectScore(IExplicitAI ai, MoveOption option, ref int score) =>
|
||||||
|
GetMoveEffectScore(option, Statistic.Evasion, ref score);
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,8 @@ public class Conversion2 : Script, IScriptOnSecondaryEffect
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
{
|
{
|
||||||
var previousTurnChoices = target.BattleData?.Battle.PreviousTurnChoices;
|
|
||||||
var nextExecutingChoice = target.BattleData?.Battle.ChoiceQueue?.Peek();
|
|
||||||
var lastMoveByTarget = target.BattleData?.LastMoveChoice;
|
var lastMoveByTarget = target.BattleData?.LastMoveChoice;
|
||||||
if (lastMoveByTarget == null)
|
if (lastMoveByTarget == null || lastMoveByTarget.ChosenMove.MoveData.MoveType.Name == "none")
|
||||||
{
|
{
|
||||||
move.GetHitData(target, hit).Fail();
|
move.GetHitData(target, hit).Fail();
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user