Move all battle state from IPokemon to an ephemeral IBattlePokemon wrapper
This commit is contained in:
@@ -118,7 +118,7 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
public IRandom Random => _random;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ITurnChoice GetChoice(IBattle battle, IPokemon pokemon)
|
||||
public override ITurnChoice GetChoice(IBattle battle, IBattlePokemon pokemon)
|
||||
{
|
||||
if (battle.HasForcedTurn(pokemon, out var choice))
|
||||
return choice;
|
||||
@@ -131,8 +131,8 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
var moveChoices = GetMoveScores(pokemon, battle);
|
||||
if (moveChoices.Count == 0)
|
||||
{
|
||||
var opponentSide = (byte)(pokemon.BattleData!.SideIndex == 0 ? 1 : 0);
|
||||
return battle.Library.MiscLibrary.ReplacementChoice(pokemon, opponentSide, pokemon.BattleData.Position);
|
||||
var opponentSide = (byte)(pokemon.SideIndex == 0 ? 1 : 0);
|
||||
return battle.Library.MiscLibrary.ReplacementChoice(pokemon, opponentSide, pokemon.Position);
|
||||
}
|
||||
var maxScore = moveChoices.Max(x => x.score);
|
||||
if (TrainerHighSkill && CanSwitch(pokemon))
|
||||
@@ -144,7 +144,7 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
if (!badMoves && _random.GetInt(100) < 25)
|
||||
badMoves = true;
|
||||
}
|
||||
else if (maxScore < MoveBaseScore * MoveScoreThreshold && pokemon.BattleData?.TurnsOnField > 2 &&
|
||||
else if (maxScore < MoveBaseScore * MoveScoreThreshold && pokemon.TurnsOnField > 2 &&
|
||||
_random.GetInt(100) < 80)
|
||||
{
|
||||
badMoves = true;
|
||||
@@ -164,8 +164,8 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
var totalScore = considerChoices.Sum(x => x.Item2);
|
||||
if (totalScore == 0)
|
||||
{
|
||||
var opponentSide = (byte)(pokemon.BattleData!.SideIndex == 0 ? 1 : 0);
|
||||
return battle.Library.MiscLibrary.ReplacementChoice(pokemon, opponentSide, pokemon.BattleData.Position);
|
||||
var opponentSide = (byte)(pokemon.SideIndex == 0 ? 1 : 0);
|
||||
return battle.Library.MiscLibrary.ReplacementChoice(pokemon, opponentSide, pokemon.Position);
|
||||
}
|
||||
var initialRandomValue = _random.GetFloat(0, totalScore);
|
||||
var randomValue = initialRandomValue;
|
||||
@@ -177,15 +177,15 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
|
||||
var (index, _, targetIndex) = considerChoices[i].x;
|
||||
var learnedMove = pokemon.Moves[index];
|
||||
var opponentSide = (byte)(pokemon.BattleData!.SideIndex == 0 ? 1 : 0);
|
||||
var opponentSide = (byte)(pokemon.SideIndex == 0 ? 1 : 0);
|
||||
if (targetIndex == -1)
|
||||
targetIndex = pokemon.BattleData.Position;
|
||||
targetIndex = pokemon.Position;
|
||||
return new MoveChoice(pokemon, learnedMove!, opponentSide, (byte)targetIndex);
|
||||
}
|
||||
throw new InvalidOperationException("No valid move choice found. This should not happen.");
|
||||
}
|
||||
|
||||
private List<(int index, int score, int targetIndex)> GetMoveScores(IPokemon user, IBattle battle)
|
||||
private List<(int index, int score, int targetIndex)> GetMoveScores(IBattlePokemon user, IBattle battle)
|
||||
{
|
||||
var choices = new List<(int index, int score, int targetIndex)>();
|
||||
foreach (var (learnedMove, index) in user.Moves.Select((x, i) => (x, i)).Where(x => x.x != null))
|
||||
@@ -249,30 +249,24 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
// TODO: get redirected target
|
||||
foreach (var pokemon in battle.Sides.SelectMany(x => x.Pokemon).WhereNotNull())
|
||||
{
|
||||
var battleData = pokemon.BattleData;
|
||||
if (battleData == null)
|
||||
if (!TargetResolver.IsValidTarget(pokemon.SideIndex, pokemon.Position, target, user))
|
||||
continue;
|
||||
if (!TargetResolver.IsValidTarget(battleData.SideIndex, battleData.Position, target, user))
|
||||
continue;
|
||||
if (target.TargetsFoe() && battleData.SideIndex == user.BattleData?.SideIndex)
|
||||
if (target.TargetsFoe() && pokemon.SideIndex == user.SideIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var score = GetMoveScoreAgainstTarget(user, aiMove, pokemon, battle);
|
||||
AddMoveToChoices(index, score, battleData.Position);
|
||||
AddMoveToChoices(index, score, pokemon.Position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var targets = new List<IPokemon>();
|
||||
var targets = new List<IBattlePokemon>();
|
||||
foreach (var pokemon in battle.Sides.SelectMany(x => x.Pokemon).WhereNotNull())
|
||||
{
|
||||
var battleData = pokemon.BattleData;
|
||||
if (battleData == null)
|
||||
if (!TargetResolver.IsValidTarget(pokemon.SideIndex, pokemon.Position, target, user))
|
||||
continue;
|
||||
if (!TargetResolver.IsValidTarget(battleData.SideIndex, battleData.Position, target, user))
|
||||
continue;
|
||||
if (target.TargetsFoe() && battleData.SideIndex == user.BattleData?.SideIndex)
|
||||
if (target.TargetsFoe() && pokemon.SideIndex == user.SideIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -295,7 +289,7 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
}
|
||||
}
|
||||
|
||||
private bool PredictMoveFailure(IPokemon user, IBattle battle, AIMoveState aiMove)
|
||||
private bool PredictMoveFailure(IBattlePokemon user, IBattle battle, AIMoveState aiMove)
|
||||
{
|
||||
if (user.HasStatus("sleep"))
|
||||
{
|
||||
@@ -333,14 +327,15 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
private static readonly StringKey SubstituteName = new("substitute");
|
||||
private static readonly StringKey InfiltratorName = new("infiltrator");
|
||||
|
||||
private bool PredictMoveFailureAgainstTarget(IPokemon user, AIMoveState aiMove, IPokemon target, IBattle battle)
|
||||
private bool PredictMoveFailureAgainstTarget(IBattlePokemon user, AIMoveState aiMove, IBattlePokemon target,
|
||||
IBattle battle)
|
||||
{
|
||||
if (aiMove.Move.SecondaryEffect != null && _handlers.MoveWillFailAgainstTarget(this,
|
||||
aiMove.Move.SecondaryEffect.Name, new MoveOption(aiMove, battle, target)))
|
||||
return true;
|
||||
if (aiMove.Move.Priority > 0)
|
||||
{
|
||||
if (target.BattleData?.SideIndex != user.BattleData?.SideIndex)
|
||||
if (target.SideIndex != user.SideIndex)
|
||||
{
|
||||
// Psychic Terrain makes all priority moves fail if the target is affected
|
||||
if (battle.TerrainName == PsychicTerrainName && !target.IsFloating)
|
||||
@@ -348,7 +343,7 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
return true;
|
||||
}
|
||||
// Dazzling and Queenly Majesty prevent priority moves from being used against the Pokémon with those abilities
|
||||
if (target.BattleData?.BattleSide.Pokemon.WhereNotNull().Any(x =>
|
||||
if (target.BattleSide.Pokemon.WhereNotNull().Any(x =>
|
||||
x.ActiveAbility?.Name == DazzlingName || x.ActiveAbility?.Name == QueenlyMajestyName) == true)
|
||||
{
|
||||
return true;
|
||||
@@ -362,7 +357,7 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
if (aiMove.Move.Category != MoveCategory.Status && typeEffectiveness == 0)
|
||||
return true;
|
||||
if (user.ActiveAbility?.Name == PranksterName && aiMove.Move.Category == MoveCategory.Status &&
|
||||
target.Types.Any(x => x.Name == DarkName) && target.BattleData?.SideIndex != user.BattleData?.SideIndex)
|
||||
target.Types.Any(x => x.Name == DarkName) && target.SideIndex != user.SideIndex)
|
||||
return true;
|
||||
if (aiMove.Move.Category != MoveCategory.Status && moveType.Name == GroundName && target.IsFloating)
|
||||
return true;
|
||||
@@ -375,7 +370,8 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
return false;
|
||||
}
|
||||
|
||||
private int GetMoveScore(IPokemon user, AIMoveState aiMove, IBattle battle, IReadOnlyList<IPokemon>? targets = null)
|
||||
private int GetMoveScore(IBattlePokemon user, AIMoveState aiMove, IBattle battle,
|
||||
IReadOnlyList<IBattlePokemon>? targets = null)
|
||||
{
|
||||
var score = MoveBaseScore;
|
||||
if (targets != null)
|
||||
@@ -411,7 +407,8 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
return score;
|
||||
}
|
||||
|
||||
private int GetMoveScoreAgainstTarget(IPokemon user, AIMoveState aiMove, IPokemon target, IBattle battle)
|
||||
private int GetMoveScoreAgainstTarget(IBattlePokemon user, AIMoveState aiMove, IBattlePokemon target,
|
||||
IBattle battle)
|
||||
{
|
||||
if (_skillFlags.CanPredictMoveFailure && PredictMoveFailureAgainstTarget(user, aiMove, target, battle))
|
||||
{
|
||||
@@ -427,8 +424,7 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
_handlers.ApplyGenerateMoveAgainstTargetScoreModifiers(this, moveOption, ref score);
|
||||
}
|
||||
|
||||
if (aiMove.Move.Target.TargetsFoe() && target.BattleData?.SideIndex == user.BattleData?.SideIndex &&
|
||||
target.BattleData?.Position != user.BattleData?.Position)
|
||||
if (aiMove.Move.Target.TargetsFoe() && target.SideIndex == user.SideIndex && target.Position != user.Position)
|
||||
{
|
||||
if (score == MoveUselessScore)
|
||||
return -1;
|
||||
@@ -442,7 +438,7 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
private static readonly StringKey OvercoatName = new("overcoat");
|
||||
private static readonly StringKey SafetyGogglesName = new("safety_goggles");
|
||||
|
||||
private static bool AffectedByPowder(IPokemon pokemon)
|
||||
private static bool AffectedByPowder(IBattlePokemon pokemon)
|
||||
{
|
||||
if (pokemon.Types.Any(x => x.Name == GrassName))
|
||||
return false;
|
||||
@@ -456,7 +452,7 @@ public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
private static readonly StringKey TruantName = "truant";
|
||||
private static readonly StringKey TruantEffectName = "truant_effect";
|
||||
|
||||
private static bool CanAttack(IPokemon pokemon)
|
||||
private static bool CanAttack(IBattlePokemon pokemon)
|
||||
{
|
||||
if (pokemon.Volatile.Contains("requires_recharge"))
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user