Move all battle state from IPokemon to an ephemeral IBattlePokemon wrapper
This commit is contained in:
@@ -8,13 +8,13 @@ namespace PkmnLib.Plugin.Gen7.AI;
|
||||
|
||||
public static class AIHelperFunctions
|
||||
{
|
||||
public static int GetScoreForTargetStatRaise(int score, AIMoveState move, IPokemon target,
|
||||
public static int GetScoreForTargetStatRaise(int score, AIMoveState move, IBattlePokemon target,
|
||||
StatisticSet<sbyte> statChanges, bool fixedChange = false, bool ignoreContrary = false)
|
||||
{
|
||||
var wholeEffect = move.Move.Category != MoveCategory.Status;
|
||||
|
||||
var desireMult = 1;
|
||||
if (move.User.BattleData?.SideIndex != target.BattleData?.SideIndex)
|
||||
if (move.User.SideIndex != target.SideIndex)
|
||||
desireMult = -1;
|
||||
|
||||
if (!ignoreContrary && !fixedChange && target.ActiveAbility?.Name == AbilityNames.Contrary)
|
||||
@@ -41,8 +41,7 @@ public static class AIHelperFunctions
|
||||
|
||||
if (!move.User.HasMoveWithEffect(MoveEffectNames.PowerTrip))
|
||||
{
|
||||
var foeIsAware =
|
||||
target.BattleData?.BattleSide.Pokemon.Any(x => x?.ActiveAbility?.Name == AbilityNames.Unaware) != true;
|
||||
var foeIsAware = target.BattleSide.Pokemon.Any(x => x?.ActiveAbility?.Name == AbilityNames.Unaware) != true;
|
||||
if (!foeIsAware)
|
||||
{
|
||||
return wholeEffect ? ExplicitAI.MoveUselessScore : score;
|
||||
@@ -80,13 +79,13 @@ public static class AIHelperFunctions
|
||||
return score;
|
||||
}
|
||||
|
||||
public static int GetScoreForTargetStatDrop(int score, AIMoveState move, IPokemon target,
|
||||
public static int GetScoreForTargetStatDrop(int score, AIMoveState move, IBattlePokemon target,
|
||||
StatisticSet<sbyte> statChanges, bool fixedChange = false, bool ignoreContrary = false)
|
||||
{
|
||||
var wholeEffect = move.Move.Category != MoveCategory.Status;
|
||||
|
||||
var desireMult = -1;
|
||||
if (move.User.BattleData?.SideIndex == target.BattleData?.SideIndex)
|
||||
if (move.User.SideIndex == target.SideIndex)
|
||||
desireMult = 1;
|
||||
if (!ignoreContrary && !fixedChange && target.ActiveAbility?.Name == AbilityNames.Contrary)
|
||||
{
|
||||
@@ -109,7 +108,7 @@ public static class AIHelperFunctions
|
||||
return wholeEffect ? ExplicitAI.MoveUselessScore : score;
|
||||
|
||||
var foeIsAware = false;
|
||||
if (target.BattleData?.BattleSide.Pokemon.All(x => x?.ActiveAbility?.Name != AbilityNames.Unaware) == true)
|
||||
if (target.BattleSide.Pokemon.All(x => x?.ActiveAbility?.Name != AbilityNames.Unaware) == true)
|
||||
{
|
||||
foeIsAware = true;
|
||||
}
|
||||
@@ -148,7 +147,8 @@ public static class AIHelperFunctions
|
||||
/// <summary>
|
||||
/// Checks if a stat raise is worthwhile for the given Pokémon and stat.
|
||||
/// </summary>
|
||||
private static bool IsStatRaiseWorthwhile(IPokemon pokemon, Statistic stat, sbyte amount, bool fixedChange = false)
|
||||
private static bool IsStatRaiseWorthwhile(IBattlePokemon pokemon, Statistic stat, sbyte amount,
|
||||
bool fixedChange = false)
|
||||
{
|
||||
if (!fixedChange && pokemon.StatBoost.GetStatistic(stat) == StatBoostStatisticSet.MaxStatBoost)
|
||||
return false;
|
||||
@@ -169,7 +169,7 @@ public static class AIHelperFunctions
|
||||
}
|
||||
case Statistic.Defense:
|
||||
{
|
||||
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||
var opponentSide = pokemon.Battle.Sides.First(x => x != pokemon.BattleSide);
|
||||
return opponentSide.Pokemon.WhereNotNull().Any(x => x.Moves.WhereNotNull().Any(y =>
|
||||
y.MoveData.Category == MoveCategory.Physical ||
|
||||
y.MoveData.SecondaryEffect?.Name == MoveEffectNames.Psyshock));
|
||||
@@ -184,7 +184,7 @@ public static class AIHelperFunctions
|
||||
}
|
||||
case Statistic.SpecialDefense:
|
||||
{
|
||||
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||
var opponentSide = pokemon.Battle.Sides.First(x => x != pokemon.BattleSide);
|
||||
return opponentSide.Pokemon.WhereNotNull().Any(x => x.Moves.WhereNotNull().Any(y =>
|
||||
y.MoveData.Category == MoveCategory.Special &&
|
||||
y.MoveData.SecondaryEffect?.Name != MoveEffectNames.Psyshock));
|
||||
@@ -194,7 +194,7 @@ public static class AIHelperFunctions
|
||||
if (!pokemon.HasMoveWithEffect(MoveEffectNames.ElectroBall, MoveEffectNames.PowerTrip))
|
||||
{
|
||||
var targetSpeed = pokemon.BoostedStats.Speed;
|
||||
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||
var opponentSide = pokemon.Battle.Sides.First(x => x != pokemon.BattleSide);
|
||||
var meaningful = opponentSide.Pokemon.WhereNotNull().Select(opponent => opponent.BoostedStats.Speed)
|
||||
.Any(foeSpeed => targetSpeed < foeSpeed && targetSpeed * 2.5 > foeSpeed);
|
||||
if (!meaningful)
|
||||
@@ -208,7 +208,7 @@ public static class AIHelperFunctions
|
||||
if (minAccuracy >= 90 && pokemon.StatBoost.Accuracy >= 0)
|
||||
{
|
||||
var meaningful = false;
|
||||
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||
var opponentSide = pokemon.Battle.Sides.First(x => x != pokemon.BattleSide);
|
||||
if (opponentSide.Pokemon.WhereNotNull().Any(x => x.StatBoost.Evasion > 0))
|
||||
{
|
||||
meaningful = true;
|
||||
@@ -222,7 +222,7 @@ public static class AIHelperFunctions
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsStatDropWorthwhile(IPokemon pokemon, Statistic stat, sbyte amount)
|
||||
private static bool IsStatDropWorthwhile(IBattlePokemon pokemon, Statistic stat, sbyte amount)
|
||||
{
|
||||
if (amount == 0)
|
||||
return false;
|
||||
@@ -236,7 +236,7 @@ public static class AIHelperFunctions
|
||||
}
|
||||
case Statistic.Defense:
|
||||
{
|
||||
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||
var opponentSide = pokemon.Battle.Sides.First(x => x != pokemon.BattleSide);
|
||||
return opponentSide.Pokemon.WhereNotNull().Any(x => x.Moves.WhereNotNull().Any(y =>
|
||||
y.MoveData.Category == MoveCategory.Physical ||
|
||||
y.MoveData.SecondaryEffect?.Name == MoveEffectNames.Psyshock));
|
||||
@@ -247,7 +247,7 @@ public static class AIHelperFunctions
|
||||
}
|
||||
case Statistic.SpecialDefense:
|
||||
{
|
||||
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||
var opponentSide = pokemon.Battle.Sides.First(x => x != pokemon.BattleSide);
|
||||
return opponentSide.Pokemon.WhereNotNull().Any(x => x.Moves.WhereNotNull().Any(y =>
|
||||
y.MoveData.Category == MoveCategory.Special &&
|
||||
y.MoveData.SecondaryEffect?.Name != MoveEffectNames.Psyshock));
|
||||
@@ -257,7 +257,7 @@ public static class AIHelperFunctions
|
||||
if (!pokemon.HasMoveWithEffect(MoveEffectNames.ElectroBall))
|
||||
{
|
||||
var targetSpeed = pokemon.BoostedStats.Speed;
|
||||
var opponentSide = pokemon.BattleData!.Battle.Sides.First(x => x != pokemon.BattleData.BattleSide);
|
||||
var opponentSide = pokemon.Battle.Sides.First(x => x != pokemon.BattleSide);
|
||||
return opponentSide.Pokemon.WhereNotNull().Select(opponent => opponent.BoostedStats.Speed)
|
||||
.Any(foeSpeed => targetSpeed > foeSpeed && targetSpeed < foeSpeed * 2.5);
|
||||
}
|
||||
@@ -272,8 +272,8 @@ public static class AIHelperFunctions
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void GetTargetStatRaiseScoreOne(ref int score, IPokemon target, Statistic stat, sbyte increment,
|
||||
AIMoveState move, float desireMult = 1)
|
||||
private static void GetTargetStatRaiseScoreOne(ref int score, IBattlePokemon target, Statistic stat,
|
||||
sbyte increment, AIMoveState move, float desireMult = 1)
|
||||
{
|
||||
var oldStage = target.StatBoost.GetStatistic(stat);
|
||||
var newStage = (sbyte)(oldStage + increment);
|
||||
@@ -282,7 +282,7 @@ public static class AIHelperFunctions
|
||||
var actualIncrement = incMult;
|
||||
incMult -= 1;
|
||||
incMult *= desireMult;
|
||||
var opponentSide = target.BattleData!.Battle.Sides.First(x => x != target.BattleData.BattleSide);
|
||||
var opponentSide = target.Battle.Sides.First(x => x != target.BattleSide);
|
||||
|
||||
switch (stat)
|
||||
{
|
||||
@@ -407,7 +407,7 @@ public static class AIHelperFunctions
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetTargetStatDropScoreOne(ref int score, IPokemon target, Statistic stat, sbyte decrement,
|
||||
private static void GetTargetStatDropScoreOne(ref int score, IBattlePokemon target, Statistic stat, sbyte decrement,
|
||||
AIMoveState move, float desireMult = 1)
|
||||
{
|
||||
var oldStage = target.StatBoost.GetStatistic(stat);
|
||||
@@ -416,7 +416,7 @@ public static class AIHelperFunctions
|
||||
Gen7BattleStatCalculator.GetStatBoostModifier(Math.Max(newStage, (sbyte)-6));
|
||||
decMult -= 1;
|
||||
decMult *= desireMult;
|
||||
var opponentSide = target.BattleData!.Battle.Sides.First(x => x != target.BattleData.BattleSide);
|
||||
var opponentSide = target.Battle.Sides.First(x => x != target.BattleSide);
|
||||
|
||||
switch (stat)
|
||||
{
|
||||
@@ -519,11 +519,11 @@ public static class AIHelperFunctions
|
||||
/// <summary>
|
||||
/// Calculates the score for the generic concept of raising a target's stats.
|
||||
/// </summary>
|
||||
private static int GetTargetStatRaiseScoreGeneric(int score, IPokemon target, StatisticSet<sbyte> statChanges,
|
||||
private static int GetTargetStatRaiseScoreGeneric(int score, IBattlePokemon target, StatisticSet<sbyte> statChanges,
|
||||
AIMoveState move, float desireMult = 1)
|
||||
{
|
||||
var totalIncrement = statChanges.Sum(x => x.value);
|
||||
var turns = target.BattleData!.Battle.CurrentTurnNumber - target.BattleData!.SwitchInTurn;
|
||||
var turns = target.Battle.CurrentTurnNumber - target.SwitchInTurn;
|
||||
if (turns < 2 && move.Move.Category == MoveCategory.Status)
|
||||
score += (int)(totalIncrement * desireMult * 5);
|
||||
|
||||
@@ -532,11 +532,11 @@ public static class AIHelperFunctions
|
||||
return score;
|
||||
}
|
||||
|
||||
private static int GetTargetStatDropScoreGeneric(int score, IPokemon target, StatisticSet<sbyte> statChanges,
|
||||
private static int GetTargetStatDropScoreGeneric(int score, IBattlePokemon 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;
|
||||
var turns = target.Battle.CurrentTurnNumber - target.SwitchInTurn;
|
||||
if (turns < 2 && move.Move.Category == MoveCategory.Status)
|
||||
score += (int)(totalDecrement * desireMult * 5);
|
||||
|
||||
@@ -545,34 +545,34 @@ public static class AIHelperFunctions
|
||||
return score;
|
||||
}
|
||||
|
||||
private static int GetScoreChangeForAdditionalEffect(this AIMoveState move, IPokemon? target)
|
||||
private static int GetScoreChangeForAdditionalEffect(this AIMoveState move, IBattlePokemon? target)
|
||||
{
|
||||
if (move.Move.SecondaryEffect is null)
|
||||
return 0;
|
||||
if (move.User.ActiveAbility?.Name == AbilityNames.SheerForce)
|
||||
return -999;
|
||||
if (target is not null && target.BattleData?.Position != move.User.BattleData?.Position &&
|
||||
if (target is not null && target.Position != move.User.Position &&
|
||||
target.ActiveAbility?.Name == AbilityNames.ShieldDust)
|
||||
return -999;
|
||||
|
||||
if ((move.Move.SecondaryEffect.Chance < 100 && move.User.ActiveAbility?.Name == AbilityNames.SereneGrace) ||
|
||||
move.User.BattleData?.BattleSide.VolatileScripts.Contains<RainbowEffect>() == true)
|
||||
move.User.BattleSide.VolatileScripts.Contains<RainbowEffect>() == true)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static bool HasMoveWithEffect(this IPokemon pokemon, params StringKey[] effect)
|
||||
private static bool HasMoveWithEffect(this IBattlePokemon pokemon, params StringKey[] effect)
|
||||
{
|
||||
return pokemon.Moves.WhereNotNull().Any(move => move.MoveData.SecondaryEffect?.Name is not null &&
|
||||
effect.Contains(move.MoveData.SecondaryEffect.Name));
|
||||
}
|
||||
|
||||
private static bool Opposes(this IPokemon pokemon, IPokemon target) =>
|
||||
pokemon.BattleData?.BattleSide != target.BattleData?.BattleSide;
|
||||
private static bool Opposes(this IBattlePokemon pokemon, IBattlePokemon target) =>
|
||||
pokemon.BattleSide != target.BattleSide;
|
||||
|
||||
public static bool WantsStatusProblem(IPokemon pokemon, StringKey? status)
|
||||
public static bool WantsStatusProblem(IBattlePokemon pokemon, StringKey? status)
|
||||
{
|
||||
if (status is null)
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user