Move all battle state from IPokemon to an ephemeral IBattlePokemon wrapper
This commit is contained in:
@@ -14,7 +14,7 @@ public static class AIHelpers
|
||||
/// <summary>
|
||||
/// Estimates the amount of damage that will be done by a move against a target.
|
||||
/// </summary>
|
||||
public static uint CalculateDamageEstimation(IMoveData move, IPokemon user, IPokemon target,
|
||||
public static uint CalculateDamageEstimation(IMoveData move, IBattlePokemon user, IBattlePokemon target,
|
||||
IDynamicLibrary library)
|
||||
{
|
||||
var hitData = new CustomHitData
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace PkmnLib.Dynamic.AI.Explicit;
|
||||
public class AIMoveState
|
||||
{
|
||||
/// <inheritdoc cref="AIMoveState" />
|
||||
public AIMoveState(IPokemon user, IMoveData move)
|
||||
public AIMoveState(IBattlePokemon user, IMoveData move)
|
||||
{
|
||||
User = user;
|
||||
Move = move;
|
||||
@@ -18,7 +18,7 @@ public class AIMoveState
|
||||
/// <summary>
|
||||
/// The user that's being wrapper
|
||||
/// </summary>
|
||||
public IPokemon User { get; }
|
||||
public IBattlePokemon User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The move that's being wrapper
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace PkmnLib.Dynamic.AI.Explicit;
|
||||
|
||||
public partial class ExplicitAI
|
||||
{
|
||||
private bool TryChooseToSwitchOut(IBattle battle, IPokemon pokemon, bool terribleMoves,
|
||||
private bool TryChooseToSwitchOut(IBattle battle, IBattlePokemon pokemon, bool terribleMoves,
|
||||
[NotNullWhen(true)] out ITurnChoice? choice)
|
||||
{
|
||||
choice = null;
|
||||
@@ -17,13 +17,13 @@ public partial class ExplicitAI
|
||||
return false;
|
||||
if (TrainerHighSkill)
|
||||
{
|
||||
var opponentSide = battle.Sides.First(x => x != pokemon.BattleData?.BattleSide);
|
||||
var opponentSide = battle.Sides.First(x => x != pokemon.BattleSide);
|
||||
var foeCanAct = opponentSide.Pokemon.WhereNotNull().Any(CanAttack);
|
||||
if (!foeCanAct)
|
||||
return false;
|
||||
}
|
||||
var party = battle.Parties.FirstOrDefault(x => x.IsResponsibleForIndex(
|
||||
new ResponsibleIndex(pokemon.BattleData!.SideIndex, pokemon.BattleData.Position)));
|
||||
new ResponsibleIndex(pokemon.SideIndex, pokemon.Position)));
|
||||
if (party is null)
|
||||
return false;
|
||||
var usablePokemon = party.GetUsablePokemonNotInField().ToList();
|
||||
@@ -44,20 +44,20 @@ public partial class ExplicitAI
|
||||
if (!shouldSwitch)
|
||||
return false;
|
||||
}
|
||||
var battleSide = pokemon.BattleData!.BattleSide;
|
||||
var battleSide = pokemon.BattleSide;
|
||||
var bestReplacement = ChooseBestReplacementPokemon(terribleMoves, usablePokemon, battleSide);
|
||||
if (bestReplacement is null)
|
||||
{
|
||||
AILogging.LogInformation(
|
||||
$"ExplicitAI: No suitable replacement Pokemon found for {pokemon} at position {pokemon.BattleData.Position}.");
|
||||
$"ExplicitAI: No suitable replacement Pokemon found for {pokemon} at position {pokemon.Position}.");
|
||||
return false;
|
||||
}
|
||||
choice = new SwitchChoice(pokemon, bestReplacement);
|
||||
return true;
|
||||
}
|
||||
|
||||
private IPokemon? ChooseBestReplacementPokemon(bool terribleMoves, IReadOnlyList<IPokemon> usablePokemon,
|
||||
IBattleSide battleSide)
|
||||
private IBattlePokemon? ChooseBestReplacementPokemon(bool terribleMoves,
|
||||
IReadOnlyList<IBattlePokemon> usablePokemon, IBattleSide battleSide)
|
||||
{
|
||||
var options = usablePokemon.Where((_, index) =>
|
||||
{
|
||||
@@ -84,7 +84,7 @@ public partial class ExplicitAI
|
||||
private static readonly StringKey ToxicSpikesName = "toxic_spikes";
|
||||
private static readonly StringKey StickyWebName = "sticky_web";
|
||||
|
||||
private int RateReplacementPokemon(IPokemon pokemon, IBattleSide battleSide)
|
||||
private int RateReplacementPokemon(IBattlePokemon pokemon, IBattleSide battleSide)
|
||||
{
|
||||
var score = 0;
|
||||
var types = pokemon.Types;
|
||||
@@ -107,7 +107,7 @@ public partial class ExplicitAI
|
||||
var opponentSide = battleSide.Battle.Sides.First(x => x != battleSide);
|
||||
foreach (var foe in opponentSide.Pokemon.WhereNotNull())
|
||||
{
|
||||
var lastMoveUsed = foe.BattleData?.LastMoveChoice;
|
||||
var lastMoveUsed = foe.LastMoveChoice;
|
||||
if (lastMoveUsed is null || lastMoveUsed.ChosenMove.MoveData.Category == MoveCategory.Status)
|
||||
continue;
|
||||
var moveType = lastMoveUsed.ChosenMove.MoveData.MoveType;
|
||||
@@ -134,22 +134,19 @@ public partial class ExplicitAI
|
||||
/// <summary>
|
||||
/// Calculates the expected entry hazard damage for a given Pokémon on a given battle side.
|
||||
/// </summary>
|
||||
public static uint CalculateEntryHazardDamage(IPokemon pokemon, IBattleSide side)
|
||||
public static uint CalculateEntryHazardDamage(IBattlePokemon pokemon, IBattleSide side)
|
||||
{
|
||||
var damage = 0u;
|
||||
side.RunScriptHook<IAIInfoScriptExpectedEntryDamage>(x => x.ExpectedEntryDamage(pokemon, ref damage));
|
||||
return damage;
|
||||
}
|
||||
|
||||
private static bool CanSwitch(IPokemon pokemon)
|
||||
private static bool CanSwitch(IBattlePokemon pokemon)
|
||||
{
|
||||
var battleData = pokemon.BattleData;
|
||||
if (battleData == null)
|
||||
if (pokemon.Battle.IsWildBattle)
|
||||
return false;
|
||||
if (battleData.Battle.IsWildBattle)
|
||||
return false;
|
||||
var partyForIndex = battleData.Battle.Parties.FirstOrDefault(x =>
|
||||
x.IsResponsibleForIndex(new ResponsibleIndex(battleData.SideIndex, battleData.Position)));
|
||||
var partyForIndex = pokemon.Battle.Parties.FirstOrDefault(x =>
|
||||
x.IsResponsibleForIndex(new ResponsibleIndex(pokemon.SideIndex, pokemon.Position)));
|
||||
return partyForIndex != null && partyForIndex.HasUsablePokemonNotInField();
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public partial class ExplicitAI
|
||||
private static readonly StringKey KomalaName = "komala";
|
||||
private static readonly StringKey MiniorName = "minior";
|
||||
|
||||
private static bool CanBePoisoned(IPokemon pokemon, IBattle battle)
|
||||
private static bool CanBePoisoned(IBattlePokemon pokemon, IBattle battle)
|
||||
{
|
||||
if (battle.TerrainName == MistyTerrainName)
|
||||
return false;
|
||||
@@ -60,7 +60,7 @@ public partial class ExplicitAI
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CanAbsorbMove(IPokemon pokemon, IMoveData move, TypeIdentifier moveType, IBattle battle)
|
||||
private static bool CanAbsorbMove(IBattlePokemon pokemon, IMoveData move, TypeIdentifier moveType, IBattle battle)
|
||||
{
|
||||
if (pokemon.ActiveAbility == null)
|
||||
return false;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace PkmnLib.Dynamic.AI.Explicit;
|
||||
/// <summary>
|
||||
/// An option where a move is used against a target
|
||||
/// </summary>
|
||||
public record struct MoveOption(AIMoveState Move, IBattle Battle, IPokemon? Target, uint EstimatedDamage = 0);
|
||||
public record struct MoveOption(AIMoveState Move, IBattle Battle, IBattlePokemon? Target, uint EstimatedDamage = 0);
|
||||
|
||||
/// <summary>
|
||||
/// A function that takes an explicit AI and a move option and returns a boolean value.
|
||||
@@ -16,8 +16,8 @@ public delegate bool AIBoolHandler(IExplicitAI ai, MoveOption option);
|
||||
/// <summary>
|
||||
/// A function for returning whether a Pokemon should switch.
|
||||
/// </summary>
|
||||
public delegate bool AISwitchBoolHandler(IExplicitAI ai, IPokemon pokemon, IBattle battle,
|
||||
IReadOnlyList<IPokemon> reserves);
|
||||
public delegate bool AISwitchBoolHandler(IExplicitAI ai, IBattlePokemon pokemon, IBattle battle,
|
||||
IReadOnlyList<IBattlePokemon> reserves);
|
||||
|
||||
/// <summary>
|
||||
/// A function for returning the base power of a move.
|
||||
@@ -112,7 +112,7 @@ public interface IReadOnlyExplicitAIHandlers
|
||||
/// <summary>
|
||||
/// Indicates whether a Pokemon should switch into another Pokemon
|
||||
/// </summary>
|
||||
bool ShouldSwitch(IExplicitAI ai, IPokemon pokemon, IBattle battle, IReadOnlyList<IPokemon> reserves);
|
||||
bool ShouldSwitch(IExplicitAI ai, IBattlePokemon pokemon, IBattle battle, IReadOnlyList<IBattlePokemon> reserves);
|
||||
|
||||
/// <summary>
|
||||
/// Functions that indicate whether a Pokemon should NOT switch
|
||||
@@ -122,7 +122,8 @@ public interface IReadOnlyExplicitAIHandlers
|
||||
/// <summary>
|
||||
/// Indicates whether a Pokemon should NOT switch into another Pokemon
|
||||
/// </summary>
|
||||
bool ShouldNotSwitch(IExplicitAI ai, IPokemon pokemon, IBattle battle, IReadOnlyList<IPokemon> reserves);
|
||||
bool ShouldNotSwitch(IExplicitAI ai, IBattlePokemon pokemon, IBattle battle,
|
||||
IReadOnlyList<IBattlePokemon> reserves);
|
||||
|
||||
/// <summary>
|
||||
/// Scores abilities
|
||||
@@ -246,7 +247,8 @@ public class ExplicitAIHandlers : IReadOnlyExplicitAIHandlers
|
||||
ShouldSwitchFunctions;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ShouldSwitch(IExplicitAI ai, IPokemon pokemon, IBattle battle, IReadOnlyList<IPokemon> reserves)
|
||||
public bool ShouldSwitch(IExplicitAI ai, IBattlePokemon pokemon, IBattle battle,
|
||||
IReadOnlyList<IBattlePokemon> reserves)
|
||||
{
|
||||
var shouldSwitch = false;
|
||||
foreach (var (_, handler) in ShouldSwitchFunctions)
|
||||
@@ -272,7 +274,8 @@ public class ExplicitAIHandlers : IReadOnlyExplicitAIHandlers
|
||||
public FunctionHandlerDictionary<AIScoreMoveHandler> AbilityRanking = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ShouldNotSwitch(IExplicitAI ai, IPokemon pokemon, IBattle battle, IReadOnlyList<IPokemon> reserves)
|
||||
public bool ShouldNotSwitch(IExplicitAI ai, IBattlePokemon pokemon, IBattle battle,
|
||||
IReadOnlyList<IBattlePokemon> reserves)
|
||||
{
|
||||
var shouldNotSwitch = false;
|
||||
foreach (var (_, handler) in ShouldNotSwitchFunctions)
|
||||
|
||||
@@ -15,9 +15,9 @@ public class HighestDamageAI : PokemonAI
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ITurnChoice GetChoice(IBattle battle, IPokemon pokemon)
|
||||
public override ITurnChoice GetChoice(IBattle battle, IBattlePokemon pokemon)
|
||||
{
|
||||
var opponentSide = pokemon.BattleData!.SideIndex == 0 ? (byte)1 : (byte)0;
|
||||
var opponentSide = pokemon.SideIndex == 0 ? (byte)1 : (byte)0;
|
||||
var opponent = battle.Sides[opponentSide].Pokemon.WhereNotNull().FirstOrDefault(x => x.IsUsable);
|
||||
var moves = pokemon.Moves.WhereNotNull().Where(x => battle.CanUse(new MoveChoice(pokemon, x, opponentSide, 0)))
|
||||
.ToList();
|
||||
|
||||
@@ -14,5 +14,5 @@ public class PassTurnAI : PokemonAI
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ITurnChoice GetChoice(IBattle battle, IPokemon pokemon) => new PassChoice(pokemon);
|
||||
public override ITurnChoice GetChoice(IBattle battle, IBattlePokemon pokemon) => new PassChoice(pokemon);
|
||||
}
|
||||
@@ -26,70 +26,69 @@ public abstract class PokemonAI
|
||||
/// <summary>
|
||||
/// Gets the choice for the Pokémon.
|
||||
/// </summary>
|
||||
public abstract ITurnChoice GetChoice(IBattle battle, IPokemon pokemon);
|
||||
public abstract ITurnChoice GetChoice(IBattle battle, IBattlePokemon pokemon);
|
||||
|
||||
/// <summary>
|
||||
/// For a given user and move, returns the valid targets for that move.
|
||||
/// </summary>
|
||||
public IEnumerable<(byte side, byte position)> GetValidTargetsForMove(IPokemon user, ILearnedMove move)
|
||||
public IEnumerable<(byte side, byte position)> GetValidTargetsForMove(IBattlePokemon user, ILearnedMove move)
|
||||
{
|
||||
var userBattleData = user.BattleData!;
|
||||
switch (move.MoveData.Target)
|
||||
{
|
||||
case MoveTarget.Adjacent:
|
||||
yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position);
|
||||
yield return (GetOppositeSide(user.SideIndex), user.Position);
|
||||
break;
|
||||
case MoveTarget.AdjacentAlly:
|
||||
if (userBattleData.Position > 0)
|
||||
yield return (userBattleData.SideIndex, (byte)(userBattleData.Position - 1));
|
||||
if (userBattleData.Battle.PositionsPerSide > userBattleData.Position + 1)
|
||||
yield return (userBattleData.SideIndex, (byte)(userBattleData.Position + 1));
|
||||
if (user.Position > 0)
|
||||
yield return (user.SideIndex, (byte)(user.Position - 1));
|
||||
if (user.Battle.PositionsPerSide > user.Position + 1)
|
||||
yield return (user.SideIndex, (byte)(user.Position + 1));
|
||||
break;
|
||||
case MoveTarget.AdjacentAllySelf:
|
||||
if (userBattleData.Position > 0)
|
||||
yield return (userBattleData.SideIndex, (byte)(userBattleData.Position - 1));
|
||||
if (userBattleData.Battle.PositionsPerSide > userBattleData.Position + 1)
|
||||
yield return (userBattleData.SideIndex, (byte)(userBattleData.Position + 1));
|
||||
yield return (userBattleData.SideIndex, userBattleData.Position);
|
||||
if (user.Position > 0)
|
||||
yield return (user.SideIndex, (byte)(user.Position - 1));
|
||||
if (user.Battle.PositionsPerSide > user.Position + 1)
|
||||
yield return (user.SideIndex, (byte)(user.Position + 1));
|
||||
yield return (user.SideIndex, user.Position);
|
||||
break;
|
||||
case MoveTarget.AdjacentOpponent:
|
||||
yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position);
|
||||
if (userBattleData.Position > 0)
|
||||
yield return (GetOppositeSide(userBattleData.SideIndex), (byte)(userBattleData.Position - 1));
|
||||
if (userBattleData.Battle.PositionsPerSide > userBattleData.Position + 1)
|
||||
yield return (GetOppositeSide(userBattleData.SideIndex), (byte)(userBattleData.Position + 1));
|
||||
yield return (GetOppositeSide(user.SideIndex), user.Position);
|
||||
if (user.Position > 0)
|
||||
yield return (GetOppositeSide(user.SideIndex), (byte)(user.Position - 1));
|
||||
if (user.Battle.PositionsPerSide > user.Position + 1)
|
||||
yield return (GetOppositeSide(user.SideIndex), (byte)(user.Position + 1));
|
||||
break;
|
||||
case MoveTarget.All:
|
||||
yield return (userBattleData.SideIndex, userBattleData.Position);
|
||||
yield return (user.SideIndex, user.Position);
|
||||
break;
|
||||
case MoveTarget.AllAdjacent:
|
||||
yield return (userBattleData.SideIndex, userBattleData.Position);
|
||||
yield return (user.SideIndex, user.Position);
|
||||
break;
|
||||
case MoveTarget.AllAdjacentOpponent:
|
||||
yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position);
|
||||
yield return (GetOppositeSide(user.SideIndex), user.Position);
|
||||
break;
|
||||
case MoveTarget.AllAlly:
|
||||
yield return (userBattleData.SideIndex, userBattleData.Position);
|
||||
yield return (user.SideIndex, user.Position);
|
||||
break;
|
||||
case MoveTarget.AllOpponent:
|
||||
yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position);
|
||||
yield return (GetOppositeSide(user.SideIndex), user.Position);
|
||||
break;
|
||||
case MoveTarget.Any:
|
||||
foreach (var side in userBattleData.Battle.Sides)
|
||||
foreach (var side in user.Battle.Sides)
|
||||
{
|
||||
foreach (var pokemon in side.Pokemon)
|
||||
{
|
||||
if (pokemon?.BattleData == null)
|
||||
if (pokemon == null)
|
||||
continue;
|
||||
yield return (side.Index, pokemon.BattleData!.Position);
|
||||
yield return (side.Index, pokemon.Position);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MoveTarget.RandomOpponent:
|
||||
yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position);
|
||||
yield return (GetOppositeSide(user.SideIndex), user.Position);
|
||||
break;
|
||||
case MoveTarget.SelfUse:
|
||||
yield return (userBattleData.SideIndex, userBattleData.Position);
|
||||
yield return (user.SideIndex, user.Position);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
@@ -18,9 +18,9 @@ public class PrescientAI : PokemonAI
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ITurnChoice GetChoice(IBattle battle, IPokemon pokemon)
|
||||
public override ITurnChoice GetChoice(IBattle battle, IBattlePokemon pokemon)
|
||||
{
|
||||
var opponentSide = pokemon.BattleData!.SideIndex == 0 ? (byte)1 : (byte)0;
|
||||
var opponentSide = pokemon.SideIndex == 0 ? (byte)1 : (byte)0;
|
||||
var moves = pokemon.Moves.WhereNotNull().Where(x => battle.CanUse(new MoveChoice(pokemon, x, opponentSide, 0)))
|
||||
.ToList();
|
||||
|
||||
@@ -34,13 +34,13 @@ public class PrescientAI : PokemonAI
|
||||
}
|
||||
|
||||
private static IEnumerable<(ITurnChoice Choice, float Score)> ScoreChoices(IBattle battle,
|
||||
IReadOnlyList<ILearnedMove> moves, IPokemon pokemon)
|
||||
IReadOnlyList<ILearnedMove> moves, IBattlePokemon pokemon)
|
||||
{
|
||||
var opponentSide = pokemon.BattleData!.SideIndex == 0 ? (byte)1 : (byte)0;
|
||||
var opponentSide = pokemon.SideIndex == 0 ? (byte)1 : (byte)0;
|
||||
foreach (var learnedMoveOriginal in moves.WhereNotNull())
|
||||
{
|
||||
var battleClone = battle.DeepClone();
|
||||
var pokemonClone = battleClone.Sides[pokemon.BattleData!.SideIndex].Pokemon[pokemon.BattleData.Position]!;
|
||||
var pokemonClone = battleClone.Sides[pokemon.SideIndex].Pokemon[pokemon.Position]!;
|
||||
var learnedMove = pokemonClone.Moves.WhereNotNull()
|
||||
.First(m => m.MoveData.Name == learnedMoveOriginal.MoveData.Name);
|
||||
var choice = new MoveChoice(pokemonClone, learnedMove, opponentSide, 0);
|
||||
@@ -57,17 +57,16 @@ public class PrescientAI : PokemonAI
|
||||
}
|
||||
if (battleClone.TrySetChoice(choice))
|
||||
{
|
||||
var score = CalculateScore(battleClone.Parties[pokemon.BattleData.SideIndex],
|
||||
battleClone.Parties[opponentSide]);
|
||||
var score = CalculateScore(battleClone.Parties[pokemon.SideIndex], battleClone.Parties[opponentSide]);
|
||||
var realChoice = new MoveChoice(pokemon, learnedMoveOriginal, opponentSide, 0);
|
||||
yield return (realChoice, score);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ITurnChoice GetOpponentChoice(IBattle battle, IPokemon pokemon)
|
||||
private static ITurnChoice GetOpponentChoice(IBattle battle, IBattlePokemon pokemon)
|
||||
{
|
||||
var opponentSide = pokemon.BattleData!.SideIndex == 0 ? (byte)1 : (byte)0;
|
||||
var opponentSide = pokemon.SideIndex == 0 ? (byte)1 : (byte)0;
|
||||
var opponent = battle.Sides[opponentSide].Pokemon[0];
|
||||
if (opponent is null)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ public class RandomAI : PokemonAI
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ITurnChoice GetChoice(IBattle battle, IPokemon pokemon)
|
||||
public override ITurnChoice GetChoice(IBattle battle, IBattlePokemon pokemon)
|
||||
{
|
||||
var moves = pokemon.Moves.WhereNotNull().Where(x => x.CurrentPp > 0).ToList();
|
||||
while (moves.Count > 0)
|
||||
@@ -28,7 +28,7 @@ public class RandomAI : PokemonAI
|
||||
var targets = GetValidTargetsForMove(pokemon, move).ToArray();
|
||||
if (move.MoveData.Category is MoveCategory.Physical or MoveCategory.Special)
|
||||
{
|
||||
targets = targets.Where(x => x.side != pokemon.BattleData!.SideIndex).ToArray();
|
||||
targets = targets.Where(x => x.side != pokemon.SideIndex).ToArray();
|
||||
}
|
||||
if (targets.Length == 0)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ public class RandomAI : PokemonAI
|
||||
}
|
||||
moves.Remove(move);
|
||||
}
|
||||
return battle.Library.MiscLibrary.ReplacementChoice(pokemon,
|
||||
pokemon.BattleData!.SideIndex == 0 ? (byte)1 : (byte)0, pokemon.BattleData.Position);
|
||||
return battle.Library.MiscLibrary.ReplacementChoice(pokemon, pokemon.SideIndex == 0 ? (byte)1 : (byte)0,
|
||||
pokemon.Position);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public static class MoveTurnExecutor
|
||||
{
|
||||
internal static void ExecuteMoveChoice(IBattle battle, IMoveChoice moveChoice)
|
||||
{
|
||||
moveChoice.User.BattleData!.LastMoveChoice = moveChoice;
|
||||
moveChoice.User.LastMoveChoice = moveChoice;
|
||||
var chosenMove = moveChoice.ChosenMove;
|
||||
var useMove = chosenMove.MoveData;
|
||||
|
||||
@@ -126,7 +126,7 @@ public static class MoveTurnExecutor
|
||||
|
||||
private static readonly ThreadLocal<List<TypeIdentifier>> TypeListCache = new(() => []);
|
||||
|
||||
private static void ExecuteMoveChoiceForTarget(IBattle battle, IExecutingMove executingMove, IPokemon target)
|
||||
private static void ExecuteMoveChoiceForTarget(IBattle battle, IExecutingMove executingMove, IBattlePokemon target)
|
||||
{
|
||||
var failed = false;
|
||||
target.RunScriptHook<IScriptFailIncomingMove>(x => x.FailIncomingMove(executingMove, target, ref failed));
|
||||
|
||||
@@ -11,7 +11,8 @@ public static class TargetResolver
|
||||
/// <summary>
|
||||
/// Get the targets of a move based on the target type, and the selected side and position to target.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<IPokemon?> ResolveTargets(IBattle battle, byte side, byte position, MoveTarget target)
|
||||
public static IReadOnlyList<IBattlePokemon?> ResolveTargets(IBattle battle, byte side, byte position,
|
||||
MoveTarget target)
|
||||
{
|
||||
return target switch
|
||||
{
|
||||
@@ -29,13 +30,10 @@ public static class TargetResolver
|
||||
/// <summary>
|
||||
/// Validates whether a given target is valid for a move choice. Returns true if the target is valid.
|
||||
/// </summary>
|
||||
public static bool IsValidTarget(byte side, byte position, MoveTarget target, IPokemon user)
|
||||
public static bool IsValidTarget(byte side, byte position, MoveTarget target, IBattlePokemon user)
|
||||
{
|
||||
var userBattleData = user.BattleData;
|
||||
if (userBattleData == null)
|
||||
throw new ArgumentNullException(nameof(user.BattleData));
|
||||
var userSide = userBattleData.SideIndex;
|
||||
var userPosition = userBattleData.Position;
|
||||
var userSide = user.SideIndex;
|
||||
var userPosition = user.Position;
|
||||
|
||||
switch (target)
|
||||
{
|
||||
@@ -80,7 +78,7 @@ public static class TargetResolver
|
||||
throw new ArgumentOutOfRangeException(nameof(target), target, null);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<IPokemon?> GetAllTargets(IBattle battle) =>
|
||||
private static IReadOnlyList<IBattlePokemon?> GetAllTargets(IBattle battle) =>
|
||||
battle.Sides.SelectMany(x => x.Pokemon).ToList();
|
||||
|
||||
private static byte GetOppositeSide(byte side) => side == 0 ? (byte)1 : (byte)0;
|
||||
@@ -89,7 +87,7 @@ public static class TargetResolver
|
||||
/// Gets all Pokémon that are adjacent to of directly opposite of a Pokémon. This means the target,
|
||||
/// the Pokémon left of it, the Pokémon right of it, and the Pokémon opposite of it.
|
||||
/// </summary>
|
||||
private static IReadOnlyList<IPokemon?> GetAllAdjacentAndOpponent(IBattle battle, byte side, byte position)
|
||||
private static IReadOnlyList<IBattlePokemon?> GetAllAdjacentAndOpponent(IBattle battle, byte side, byte position)
|
||||
{
|
||||
var left = position - 1;
|
||||
var right = position + 1;
|
||||
@@ -123,7 +121,7 @@ public static class TargetResolver
|
||||
];
|
||||
}
|
||||
|
||||
private static IReadOnlyList<IPokemon?> GetAllAdjacent(IBattle battle, byte side, byte position)
|
||||
private static IReadOnlyList<IBattlePokemon?> GetAllAdjacent(IBattle battle, byte side, byte position)
|
||||
{
|
||||
var left = position - 1;
|
||||
var right = position + 1;
|
||||
|
||||
@@ -85,7 +85,7 @@ public static class TurnRunner
|
||||
return;
|
||||
if (!choice.User.IsUsable)
|
||||
return;
|
||||
if (choice.User.BattleData?.IsOnBattlefield != true)
|
||||
if (!choice.User.IsOnBattlefield)
|
||||
return;
|
||||
switch (choice)
|
||||
{
|
||||
@@ -108,9 +108,6 @@ public static class TurnRunner
|
||||
private static void ExecuteSwitchChoice(IBattle battle, ISwitchChoice fleeChoice)
|
||||
{
|
||||
var user = fleeChoice.User;
|
||||
var battleData = user.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
var preventSwitch = false;
|
||||
fleeChoice.RunScriptHook<IScriptPreventSelfSwitch>(script =>
|
||||
script.PreventSelfSwitch(fleeChoice, ref preventSwitch));
|
||||
@@ -118,7 +115,7 @@ public static class TurnRunner
|
||||
return;
|
||||
foreach (var side in battle.Sides)
|
||||
{
|
||||
if (side.Index == battleData.SideIndex)
|
||||
if (side.Index == user.SideIndex)
|
||||
continue;
|
||||
foreach (var pokemon in side.Pokemon.WhereNotNull())
|
||||
{
|
||||
@@ -129,16 +126,12 @@ public static class TurnRunner
|
||||
}
|
||||
}
|
||||
user.Volatile.Clear();
|
||||
var userSide = battle.Sides[battleData.SideIndex];
|
||||
userSide.SwapPokemon(battleData.Position, fleeChoice.SwitchTo);
|
||||
user.BattleSide.SwapPokemon(user.Position, fleeChoice.SwitchTo);
|
||||
}
|
||||
|
||||
private static void ExecuteFleeChoice(IBattle battle, IFleeChoice fleeChoice)
|
||||
{
|
||||
var user = fleeChoice.User;
|
||||
var battleData = user.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
if (!battle.CanFlee)
|
||||
return;
|
||||
|
||||
@@ -150,7 +143,7 @@ public static class TurnRunner
|
||||
|
||||
foreach (var side in battle.Sides)
|
||||
{
|
||||
if (side.Index == battleData.SideIndex)
|
||||
if (side.Index == user.SideIndex)
|
||||
continue;
|
||||
foreach (var pokemon in side.Pokemon.WhereNotNull())
|
||||
{
|
||||
@@ -167,8 +160,7 @@ public static class TurnRunner
|
||||
return;
|
||||
}
|
||||
|
||||
var userSide = battle.Sides[battleData.SideIndex];
|
||||
userSide.MarkAsFled();
|
||||
user.BattleSide.MarkAsFled();
|
||||
battle.EventHook.Invoke(new FleeEvent(user, true));
|
||||
battle.ValidateBattleState();
|
||||
}
|
||||
@@ -176,9 +168,6 @@ public static class TurnRunner
|
||||
private static void ExecuteItemChoice(IBattle battle, IItemChoice itemChoice)
|
||||
{
|
||||
var user = itemChoice.User;
|
||||
var battleData = user.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
var target = itemChoice.GetTargetPokemon(battle);
|
||||
battle.EventHook.Invoke(new ItemUseEvent(user, itemChoice.Item));
|
||||
itemChoice.Item.RunItemScript(battle.Library.ScriptResolver, target ?? user, user, battle, battle.EventHook);
|
||||
|
||||
@@ -12,7 +12,7 @@ public record AbilityTriggerEvent : IEventData
|
||||
/// <summary>
|
||||
/// The Pokémon whose ability is being triggered.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; }
|
||||
public IBattlePokemon Pokemon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The ability that is being triggered for the Pokémon.
|
||||
@@ -22,7 +22,7 @@ public record AbilityTriggerEvent : IEventData
|
||||
public Dictionary<StringKey, object?>? Metadata { get; init; } = null;
|
||||
|
||||
/// <inheritdoc cref="AbilityTriggerEvent"/>
|
||||
public AbilityTriggerEvent(IPokemon pokemon)
|
||||
public AbilityTriggerEvent(IBattlePokemon pokemon)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
Ability = pokemon.ActiveAbility;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace PkmnLib.Dynamic.Events;
|
||||
public class CaptureAttemptEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="CaptureAttemptEvent"/>
|
||||
public CaptureAttemptEvent(IPokemon target, CaptureResult result, IItem captureItem)
|
||||
public CaptureAttemptEvent(IBattlePokemon target, CaptureResult result, IItem captureItem)
|
||||
{
|
||||
Target = target;
|
||||
Result = result;
|
||||
@@ -20,7 +20,7 @@ public class CaptureAttemptEvent : IEventData
|
||||
/// <summary>
|
||||
/// The Pokémon that is being captured.
|
||||
/// </summary>
|
||||
public IPokemon Target { get; init; }
|
||||
public IBattlePokemon Target { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The result of the capture attempt.
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace PkmnLib.Dynamic.Events;
|
||||
public record DamageEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="DamageEvent"/>
|
||||
public DamageEvent(IPokemon pokemon, uint previousHealth, uint newHealth, DamageSource source)
|
||||
public DamageEvent(IBattlePokemon pokemon, uint previousHealth, uint newHealth, DamageSource source)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
PreviousHealth = previousHealth;
|
||||
@@ -19,7 +19,7 @@ public record DamageEvent : IEventData
|
||||
/// <summary>
|
||||
/// The Pokemon that took damage.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; init; }
|
||||
public IBattlePokemon Pokemon { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The previous health of the Pokemon.
|
||||
|
||||
@@ -5,11 +5,11 @@ namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
public class DisplaySpeciesChangeEvent : IEventData
|
||||
{
|
||||
public IPokemon Pokemon { get; }
|
||||
public IBattlePokemon Pokemon { get; }
|
||||
public ISpecies? Species { get; }
|
||||
public IForm? Form { get; }
|
||||
|
||||
public DisplaySpeciesChangeEvent(IPokemon pokemon, ISpecies? species, IForm? form)
|
||||
public DisplaySpeciesChangeEvent(IBattlePokemon pokemon, ISpecies? species, IForm? form)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
Species = species;
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace PkmnLib.Dynamic.Events;
|
||||
public class FaintEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="FaintEvent"/>
|
||||
public FaintEvent(IPokemon pokemon)
|
||||
public FaintEvent(IBattlePokemon pokemon)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ public class FaintEvent : IEventData
|
||||
/// <summary>
|
||||
/// The Pokemon that fainted.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; init; }
|
||||
public IBattlePokemon Pokemon { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; } = new();
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace PkmnLib.Dynamic.Events;
|
||||
public class FleeEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="FleeEvent"/>
|
||||
public FleeEvent(IPokemon pokemon, bool success)
|
||||
public FleeEvent(IBattlePokemon pokemon, bool success)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
Success = success;
|
||||
@@ -17,7 +17,7 @@ public class FleeEvent : IEventData
|
||||
/// <summary>
|
||||
/// The Pokémon that attempted to flee.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; }
|
||||
public IBattlePokemon Pokemon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the flee attempt was successful.
|
||||
|
||||
@@ -5,13 +5,13 @@ namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
public record ItemUseEvent : IEventData
|
||||
{
|
||||
public ItemUseEvent(IPokemon pokemon, IItem itemUsed)
|
||||
public ItemUseEvent(IBattlePokemon pokemon, IItem itemUsed)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
ItemUsed = itemUsed;
|
||||
}
|
||||
|
||||
public IPokemon Pokemon { get; set; }
|
||||
public IBattlePokemon Pokemon { get; set; }
|
||||
public IItem ItemUsed { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -20,10 +20,10 @@ public class MoveHitEvent : IEventData
|
||||
/// <summary>
|
||||
/// The target of the move.
|
||||
/// </summary>
|
||||
public IPokemon Target { get; }
|
||||
public IBattlePokemon Target { get; }
|
||||
|
||||
/// <inheritdoc cref="MoveHitEvent"/>
|
||||
public MoveHitEvent(IExecutingMove executingMove, IHitData hitData, IPokemon target)
|
||||
public MoveHitEvent(IExecutingMove executingMove, IHitData hitData, IBattlePokemon target)
|
||||
{
|
||||
ExecutingMove = executingMove;
|
||||
HitData = hitData;
|
||||
|
||||
@@ -5,9 +5,9 @@ namespace PkmnLib.Dynamic.Events;
|
||||
public class MoveInvulnerableEvent : IEventData
|
||||
{
|
||||
public IExecutingMove ExecutingMove { get; }
|
||||
public IPokemon Target { get; }
|
||||
public IBattlePokemon Target { get; }
|
||||
|
||||
public MoveInvulnerableEvent(IExecutingMove executingMove, IPokemon target)
|
||||
public MoveInvulnerableEvent(IExecutingMove executingMove, IBattlePokemon target)
|
||||
{
|
||||
ExecutingMove = executingMove;
|
||||
Target = target;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace PkmnLib.Dynamic.Events;
|
||||
public class StatBoostEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="StatBoostEvent" />
|
||||
public StatBoostEvent(IPokemon pokemon, Statistic statistic, sbyte oldBoost, sbyte newBoost)
|
||||
public StatBoostEvent(IBattlePokemon pokemon, Statistic statistic, sbyte oldBoost, sbyte newBoost)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
Statistic = statistic;
|
||||
@@ -20,7 +20,7 @@ public class StatBoostEvent : IEventData
|
||||
/// <summary>
|
||||
/// The Pokemon that had its stat boosted.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; }
|
||||
public IBattlePokemon Pokemon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The statistic that was boosted.
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace PkmnLib.Dynamic.Events;
|
||||
public record StatusChangeEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="StatusChangeEvent"/>
|
||||
public StatusChangeEvent(IPokemon pokemon, StringKey? previousStatus, StringKey? newStatus)
|
||||
public StatusChangeEvent(IBattlePokemon pokemon, StringKey? previousStatus, StringKey? newStatus)
|
||||
{
|
||||
Pokemon = pokemon;
|
||||
PreviousStatus = previousStatus;
|
||||
@@ -19,7 +19,7 @@ public record StatusChangeEvent : IEventData
|
||||
/// <summary>
|
||||
/// The Pokémon whose status has changed.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; }
|
||||
public IBattlePokemon Pokemon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The new status of the Pokémon after the change.
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace PkmnLib.Dynamic.Events;
|
||||
public class SwitchEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc cref="SwitchEvent"/>
|
||||
public SwitchEvent(byte sideIndex, byte position, IPokemon? pokemon)
|
||||
public SwitchEvent(byte sideIndex, byte position, IBattlePokemon? pokemon)
|
||||
{
|
||||
SideIndex = sideIndex;
|
||||
Position = position;
|
||||
@@ -28,7 +28,7 @@ public class SwitchEvent : IEventData
|
||||
/// <summary>
|
||||
/// The Pokémon that is switching in. If null, no Pokémon is switching in, and the slot is empty after the switch.
|
||||
/// </summary>
|
||||
public IPokemon? Pokemon { get; init; }
|
||||
public IBattlePokemon? Pokemon { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; }
|
||||
|
||||
@@ -21,15 +21,16 @@ public interface IBattleStatCalculator
|
||||
/// <summary>
|
||||
/// Calculate all the boosted stats of a Pokemon, including stat boosts.
|
||||
/// </summary>
|
||||
void CalculateBoostedStats(IPokemon pokemon, StatisticSet<uint> stats);
|
||||
void CalculateBoostedStats(IBattlePokemon pokemon, StatisticSet<uint> stats);
|
||||
|
||||
/// <summary>
|
||||
/// Calculate a single boosted stat of a Pokemon, including stat boosts.
|
||||
/// </summary>
|
||||
uint CalculateBoostedStat(IPokemon pokemon, Statistic stat);
|
||||
uint CalculateBoostedStat(IBattlePokemon 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);
|
||||
byte CalculateModifiedAccuracy(IExecutingMove executingMove, IBattlePokemon target, byte hitIndex,
|
||||
byte moveAccuracy);
|
||||
}
|
||||
@@ -46,5 +46,5 @@ public interface ICaptureLibrary
|
||||
/// <summary>
|
||||
/// Attempts to capture a Pokémon using a specified item (e.g., Poké Ball).
|
||||
/// </summary>
|
||||
CaptureResult TryCapture(IPokemon target, IItem captureItem, IBattleRandom random);
|
||||
CaptureResult TryCapture(IBattlePokemon target, IItem captureItem, IBattleRandom random);
|
||||
}
|
||||
@@ -11,16 +11,16 @@ public interface IDamageCalculator
|
||||
/// <summary>
|
||||
/// Calculate the damage for a given hit on a Pokemon.
|
||||
/// </summary>
|
||||
uint GetDamage(IExecutingMove? executingMove, MoveCategory category, IPokemon user, IPokemon target,
|
||||
uint GetDamage(IExecutingMove? executingMove, MoveCategory category, IBattlePokemon user, IBattlePokemon target,
|
||||
int targetCount, byte hitNumber, IHitData hitData);
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the base power for a given hit on a Pokemon.
|
||||
/// </summary>
|
||||
ushort GetBasePower(IExecutingMove executingMove, IPokemon target, byte hitNumber, IHitData hitData);
|
||||
ushort GetBasePower(IExecutingMove executingMove, IBattlePokemon target, byte hitNumber, IHitData hitData);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a specified hit should be critical or not.
|
||||
/// </summary>
|
||||
bool IsCritical(IBattle battle, IExecutingMove executingMove, IPokemon target, byte hitNumber);
|
||||
bool IsCritical(IBattle battle, IExecutingMove executingMove, IBattlePokemon target, byte hitNumber);
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public interface IMiscLibrary
|
||||
/// Returns the choice that's used when a Pokemon is unable to make the move choice it wants to, or when it has no
|
||||
/// moves left, yet wants to make a move.
|
||||
/// </summary>
|
||||
ITurnChoice ReplacementChoice(IPokemon user, byte targetSide, byte targetPosition);
|
||||
ITurnChoice ReplacementChoice(IBattlePokemon user, byte targetSide, byte targetPosition);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the given choice is the choice that is used when the user is unable to make a move choice.
|
||||
|
||||
@@ -92,7 +92,7 @@ public interface IBattle : IScriptSource, IDeepCloneable, IDisposable
|
||||
/// <summary>
|
||||
/// Get a Pokemon on the battlefield, on a specific side and an index on that side.
|
||||
/// </summary>
|
||||
IPokemon? GetPokemon(byte side, byte position);
|
||||
IBattlePokemon? GetPokemon(byte side, byte position);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a slot on the battlefield can still be filled. If no party is responsible
|
||||
@@ -116,7 +116,7 @@ public interface IBattle : IScriptSource, IDeepCloneable, IDisposable
|
||||
/// Checks whether a Pokemon has a forced turn choice. If it does, this returns true and the choice
|
||||
/// is set in the out parameter. If it does not, this returns false and the out parameter is null.
|
||||
/// </summary>
|
||||
bool HasForcedTurn(IPokemon pokemon, [NotNullWhen(true)] out ITurnChoice? choice);
|
||||
bool HasForcedTurn(IBattlePokemon pokemon, [NotNullWhen(true)] out ITurnChoice? choice);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a choice is actually possible.
|
||||
@@ -202,6 +202,8 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
Sides = sides;
|
||||
Random = randomSeed.HasValue ? new BattleRandomImpl(randomSeed.Value) : new BattleRandomImpl();
|
||||
EventHook = new EventHook();
|
||||
foreach (var party in parties)
|
||||
party.Initialize(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -248,12 +250,22 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
public BattleChoiceQueue? ChoiceQueue { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IPokemon? GetPokemon(byte side, byte position) => Sides[side].Pokemon[position];
|
||||
public IBattlePokemon? GetPokemon(byte side, byte position) => Sides[side].Pokemon[position];
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CanSlotBeFilled(byte side, byte position) => Parties.Any(x =>
|
||||
x.IsResponsibleForIndex(new ResponsibleIndex(side, position)) && x.HasUsablePokemonNotInField());
|
||||
|
||||
private readonly List<IPokemon> _capturedPokemon = [];
|
||||
|
||||
/// <summary>
|
||||
/// Attaches battle-wide result data, such as the captured Pokémon, to a result.
|
||||
/// </summary>
|
||||
private BattleResult FinalizeResult(BattleResult result) => result with
|
||||
{
|
||||
CapturedPokemon = _capturedPokemon.ToList(),
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ValidateBattleState()
|
||||
{
|
||||
@@ -265,7 +277,7 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
{
|
||||
if (side.HasFledBattle)
|
||||
{
|
||||
Result = BattleResult.Inconclusive;
|
||||
Result = FinalizeResult(BattleResult.Inconclusive);
|
||||
HasEnded = true;
|
||||
return;
|
||||
}
|
||||
@@ -283,13 +295,13 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
// If every side is defeated, the battle is a draw
|
||||
if (!survivingSideExists)
|
||||
{
|
||||
Result = BattleResult.Inconclusive;
|
||||
Result = FinalizeResult(BattleResult.Inconclusive);
|
||||
HasEnded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// If only one side is left, that side has won
|
||||
Result = BattleResult.Conclusive(survivingSide!.Index);
|
||||
Result = FinalizeResult(BattleResult.Conclusive(survivingSide!.Index));
|
||||
HasEnded = true;
|
||||
}
|
||||
|
||||
@@ -297,22 +309,15 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
public void ForceEndBattle()
|
||||
{
|
||||
HasEnded = true;
|
||||
Result = BattleResult.Inconclusive;
|
||||
Result = FinalizeResult(BattleResult.Inconclusive);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasForcedTurn(IPokemon pokemon, [NotNullWhen(true)] out ITurnChoice? choice)
|
||||
public bool HasForcedTurn(IBattlePokemon pokemon, [NotNullWhen(true)] out ITurnChoice? choice)
|
||||
{
|
||||
var battleData = pokemon.BattleData;
|
||||
if (battleData == null)
|
||||
{
|
||||
choice = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
ITurnChoice? forcedChoice = null;
|
||||
pokemon.RunScriptHook<IScriptForceTurnSelection>(script =>
|
||||
script.ForceTurnSelection(this, battleData.SideIndex, battleData.Position, ref forcedChoice));
|
||||
script.ForceTurnSelection(this, pokemon.SideIndex, pokemon.Position, ref forcedChoice));
|
||||
choice = forcedChoice;
|
||||
return choice != null;
|
||||
}
|
||||
@@ -346,7 +351,7 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
if (!switchChoice.SwitchTo.IsUsable)
|
||||
return false;
|
||||
// Can't switch to a Pokémon already on the field
|
||||
if (switchChoice.SwitchTo.BattleData is { IsOnBattlefield: true })
|
||||
if (switchChoice.SwitchTo.IsOnBattlefield)
|
||||
return false;
|
||||
if (switchChoice.SwitchTo == switchChoice.User)
|
||||
return false;
|
||||
@@ -389,10 +394,10 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
{
|
||||
if (!CanUse(choice))
|
||||
return false;
|
||||
if (choice.User.BattleData?.IsOnBattlefield != true)
|
||||
if (!choice.User.IsOnBattlefield)
|
||||
return false;
|
||||
var side = Sides[choice.User.BattleData!.SideIndex];
|
||||
side.SetChoice(choice.User.BattleData!.Position, choice);
|
||||
var side = Sides[choice.User.SideIndex];
|
||||
side.SetChoice(choice.User.Position, choice);
|
||||
CheckChoicesSetAndRun();
|
||||
return true;
|
||||
}
|
||||
@@ -555,8 +560,8 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
if (attemptCapture.IsCaught)
|
||||
{
|
||||
target.MarkAsCaught();
|
||||
var side = Sides[target.BattleData!.SideIndex];
|
||||
side.ForceClearPokemonFromField(target.BattleData.Position);
|
||||
_capturedPokemon.Add(target.UnderlyingPokemon);
|
||||
target.BattleSide.ForceClearPokemonFromField(target.Position);
|
||||
}
|
||||
EventHook.Invoke(new CaptureAttemptEvent(target, attemptCapture, item));
|
||||
|
||||
@@ -592,9 +597,9 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
{
|
||||
foreach (var party in Parties)
|
||||
{
|
||||
foreach (var pokemon in party.Party.WhereNotNull())
|
||||
foreach (var pokemon in party.BattlePokemon.WhereNotNull())
|
||||
{
|
||||
pokemon.ClearBattleData();
|
||||
pokemon.OnBattleEnd();
|
||||
}
|
||||
}
|
||||
_weatherScript.Clear();
|
||||
|
||||
@@ -87,7 +87,7 @@ public class BattleChoiceQueue : IDeepCloneable
|
||||
/// <returns>
|
||||
/// Returns true if the Pokémon was found and moved, false otherwise.
|
||||
/// </returns>
|
||||
public bool MovePokemonChoiceNext(IPokemon pokemon)
|
||||
public bool MovePokemonChoiceNext(IBattlePokemon pokemon)
|
||||
{
|
||||
var index = Array.FindIndex(_choices, _currentIndex, choice => choice?.User == pokemon);
|
||||
if (index == -1)
|
||||
@@ -110,7 +110,7 @@ public class BattleChoiceQueue : IDeepCloneable
|
||||
/// <returns>
|
||||
/// Returns true if the Pokémon was found and moved, false otherwise.
|
||||
/// </returns>
|
||||
public bool MovePokemonChoiceLast(IPokemon pokemon)
|
||||
public bool MovePokemonChoiceLast(IBattlePokemon pokemon)
|
||||
{
|
||||
var index = Array.FindIndex(_choices, _currentIndex, choice => choice?.User == pokemon);
|
||||
if (index == -1)
|
||||
|
||||
@@ -4,15 +4,35 @@ namespace PkmnLib.Dynamic.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A battle party is a wrapper around a Pokemon party that provides additional functionality for battles.
|
||||
/// It indicates for which side and position the party is responsible.
|
||||
/// It indicates for which side and position the party is responsible, and holds the battle-scoped
|
||||
/// <see cref="IBattlePokemon"/> wrappers for the party's Pokémon.
|
||||
/// </summary>
|
||||
public interface IBattleParty : IDeepCloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// The backing Pokemon party.
|
||||
/// The backing Pokemon party. Battle code should generally use <see cref="BattlePokemon"/> instead, as that
|
||||
/// view contains the battle-scoped wrappers.
|
||||
/// </summary>
|
||||
IPokemonParty Party { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The battle-scoped view of the party. Index-aligned with <see cref="Party"/>. Only available after
|
||||
/// <see cref="Initialize"/> has been called by the battle.
|
||||
/// </summary>
|
||||
IReadOnlyList<IBattlePokemon?> BattlePokemon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the battle-scoped wrapper for a Pokémon in this party. Returns null if the Pokémon is not in this
|
||||
/// party. Accepts either the underlying Pokémon or the wrapper itself.
|
||||
/// </summary>
|
||||
IBattlePokemon? GetBattlePokemon(IPokemon pokemon);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the battle-scoped wrappers for this party. This is called by the battle when it is created,
|
||||
/// and should not be called by user code.
|
||||
/// </summary>
|
||||
void Initialize(IBattle battle);
|
||||
|
||||
/// <summary>
|
||||
/// Whether the party is responsible for the specified side and position.
|
||||
/// </summary>
|
||||
@@ -26,7 +46,7 @@ public interface IBattleParty : IDeepCloneable
|
||||
/// <summary>
|
||||
/// Gets all usable Pokemon that are not currently in the field.
|
||||
/// </summary>
|
||||
IEnumerable<IPokemon> GetUsablePokemonNotInField();
|
||||
IEnumerable<IBattlePokemon> GetUsablePokemonNotInField();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -39,6 +59,8 @@ public record struct ResponsibleIndex(byte Side, byte Position);
|
||||
public class BattlePartyImpl : IBattleParty
|
||||
{
|
||||
private readonly ResponsibleIndex[] _responsibleIndices;
|
||||
private IBattlePokemon?[] _battlePokemon = [];
|
||||
private IBattle? _battle;
|
||||
|
||||
/// <inheritdoc cref="BattlePartyImpl"/>
|
||||
public BattlePartyImpl(IPokemonParty party, ResponsibleIndex[] responsibleIndices)
|
||||
@@ -50,14 +72,53 @@ public class BattlePartyImpl : IBattleParty
|
||||
/// <inheritdoc />
|
||||
public IPokemonParty Party { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<IBattlePokemon?> BattlePokemon => _battlePokemon;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IBattlePokemon? GetBattlePokemon(IPokemon pokemon) =>
|
||||
_battlePokemon.FirstOrDefault(x => x != null && (x == pokemon || x.UnderlyingPokemon == pokemon));
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Initialize(IBattle battle)
|
||||
{
|
||||
if (_battle != null)
|
||||
throw new InvalidOperationException("This battle party has already been initialized for a battle.");
|
||||
if (_responsibleIndices.Length == 0)
|
||||
throw new InvalidOperationException("A battle party must be responsible for at least one position.");
|
||||
var sideIndex = _responsibleIndices[0].Side;
|
||||
if (_responsibleIndices.Any(x => x.Side != sideIndex))
|
||||
throw new InvalidOperationException("A battle party can only be responsible for a single side.");
|
||||
|
||||
_battle = battle;
|
||||
_battlePokemon = new IBattlePokemon?[Party.Count];
|
||||
for (var i = 0; i < Party.Count; i++)
|
||||
{
|
||||
var pokemon = Party[i];
|
||||
if (pokemon != null)
|
||||
_battlePokemon[i] = new BattlePokemonImpl(pokemon, battle, sideIndex);
|
||||
}
|
||||
|
||||
Party.OnSwapInto += (_, args) =>
|
||||
{
|
||||
var (pokemon, index) = args;
|
||||
_battlePokemon[index] = pokemon == null ? null : new BattlePokemonImpl(pokemon, battle, sideIndex);
|
||||
};
|
||||
Party.OnSwap += (_, args) =>
|
||||
{
|
||||
var (index1, index2) = args;
|
||||
(_battlePokemon[index1], _battlePokemon[index2]) = (_battlePokemon[index2], _battlePokemon[index1]);
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsResponsibleForIndex(ResponsibleIndex index) => _responsibleIndices.Contains(index);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasUsablePokemonNotInField() =>
|
||||
Party.WhereNotNull().Any(x => x.IsUsable && x.BattleData?.IsOnBattlefield != true);
|
||||
_battlePokemon.WhereNotNull().Any(x => x.IsUsable && !x.IsOnBattlefield);
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IPokemon> GetUsablePokemonNotInField() =>
|
||||
Party.WhereNotNull().Where(x => x.IsUsable && x.BattleData?.IsOnBattlefield != true);
|
||||
public IEnumerable<IBattlePokemon> GetUsablePokemonNotInField() =>
|
||||
_battlePokemon.WhereNotNull().Where(x => x.IsUsable && !x.IsOnBattlefield);
|
||||
}
|
||||
1043
PkmnLib.Dynamic/Models/BattlePokemon.cs
Normal file
1043
PkmnLib.Dynamic/Models/BattlePokemon.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ public interface IBattleRandom : IRandom, IDeepCloneable
|
||||
/// rolls whether it triggers. As a side effect this run scripts to allow modifying this random
|
||||
/// chance.
|
||||
/// </summary>
|
||||
bool EffectChance(float chance, IExecutingMove executingMove, IPokemon target, byte hitNumber);
|
||||
bool EffectChance(float chance, IExecutingMove executingMove, IBattlePokemon target, byte hitNumber);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IBattleRandom"/>
|
||||
@@ -36,7 +36,7 @@ public class BattleRandomImpl : RandomImpl, IBattleRandom
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool EffectChance(float chance, IExecutingMove executingMove, IPokemon target, byte hitNumber)
|
||||
public bool EffectChance(float chance, IExecutingMove executingMove, IBattlePokemon target, byte hitNumber)
|
||||
{
|
||||
executingMove.RunScriptHook<IScriptChangeEffectChance>(script =>
|
||||
script.ChangeEffectChance(executingMove, target, hitNumber, ref chance));
|
||||
|
||||
@@ -30,4 +30,11 @@ public record struct BattleResult
|
||||
/// The side that won the battle. If null, no side has won.
|
||||
/// </summary>
|
||||
public byte? WinningSide { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Pokémon that were captured during the battle. These are the underlying Pokémon, so they remain
|
||||
/// valid after the battle has been disposed. This is set for both conclusive and inconclusive results, as
|
||||
/// captures complete the moment they happen.
|
||||
/// </summary>
|
||||
public IReadOnlyList<IPokemon> CapturedPokemon { get; init; } = [];
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
|
||||
/// <summary>
|
||||
/// A list of Pokémon currently on the battlefield.
|
||||
/// </summary>
|
||||
IReadOnlyList<IPokemon?> Pokemon { get; }
|
||||
IReadOnlyList<IBattlePokemon?> Pokemon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The currently set choices for all Pokémon on the battlefield. Cleared when the turn starts.
|
||||
@@ -84,7 +84,14 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
|
||||
/// Switches out a spot on the field for a different Pokémon. If null is passed, the spot is
|
||||
/// cleared. Returns the Pokémon that was previously in the spot.
|
||||
/// </summary>
|
||||
IPokemon? SwapPokemon(byte position, IPokemon? pokemon);
|
||||
IBattlePokemon? SwapPokemon(byte position, IBattlePokemon? pokemon);
|
||||
|
||||
/// <summary>
|
||||
/// Sends out a Pokémon by its persistent representation. This resolves the battle-scoped wrapper for
|
||||
/// the Pokémon from the parties in the battle, and swaps it into the given position. This is the
|
||||
/// convenient entry point for hosts, which generally hold the persistent party Pokémon.
|
||||
/// </summary>
|
||||
IBattlePokemon? SendOut(byte position, IPokemon pokemon);
|
||||
|
||||
/// <summary>
|
||||
/// Swaps two Pokémon on the side.
|
||||
@@ -94,7 +101,7 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
|
||||
/// <summary>
|
||||
/// Checks whether a Pokemon is on the field in this side.
|
||||
/// </summary>
|
||||
bool IsPokemonOnSide(IPokemon pokemon);
|
||||
bool IsPokemonOnSide(IBattlePokemon pokemon);
|
||||
|
||||
/// <summary>
|
||||
/// Marks a slot as unfillable. This happens when no parties are able to fill the slot anymore.
|
||||
@@ -166,7 +173,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
{
|
||||
Index = index;
|
||||
NumberOfPositions = numberOfPositions;
|
||||
_pokemon = new IPokemon?[numberOfPositions];
|
||||
_pokemon = new IBattlePokemon?[numberOfPositions];
|
||||
_setChoices = new ITurnChoice?[numberOfPositions];
|
||||
_fillablePositions = new bool[numberOfPositions];
|
||||
for (byte i = 0; i < numberOfPositions; i++)
|
||||
@@ -183,10 +190,10 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
/// <inheritdoc />
|
||||
public byte NumberOfPositions { get; }
|
||||
|
||||
private readonly IPokemon?[] _pokemon;
|
||||
private readonly IBattlePokemon?[] _pokemon;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<IPokemon?> Pokemon => _pokemon;
|
||||
public IReadOnlyList<IBattlePokemon?> Pokemon => _pokemon;
|
||||
|
||||
private readonly ITurnChoice?[] _setChoices;
|
||||
|
||||
@@ -249,28 +256,31 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
if (pokemon is not null)
|
||||
{
|
||||
pokemon.RunScriptHook<IScriptOnRemove>(script => script.OnRemove());
|
||||
pokemon.SetOnBattlefield(false);
|
||||
pokemon.OnSwitchedOut();
|
||||
}
|
||||
|
||||
_pokemon[index] = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IPokemon? SwapPokemon(byte position, IPokemon? pokemon)
|
||||
public IBattlePokemon? SwapPokemon(byte position, IBattlePokemon? pokemon)
|
||||
{
|
||||
var oldPokemon = _pokemon[position];
|
||||
if (oldPokemon is not null)
|
||||
{
|
||||
oldPokemon.RunScriptHook<IScriptOnSwitchOut>(script => script.OnSwitchOut(oldPokemon, position));
|
||||
oldPokemon.RunScriptHook<IScriptOnRemove>(script => script.OnRemove());
|
||||
oldPokemon.SetOnBattlefield(false);
|
||||
oldPokemon.OnSwitchedOut();
|
||||
}
|
||||
_pokemon[position] = pokemon;
|
||||
if (pokemon is not null)
|
||||
{
|
||||
pokemon.SetBattleData(Battle, Index);
|
||||
pokemon.SetOnBattlefield(true);
|
||||
pokemon.SetBattleSidePosition(position);
|
||||
if (pokemon.SideIndex != Index)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"A battle Pokémon can only be sent out on the side its party is responsible for.");
|
||||
}
|
||||
pokemon.OnSwitchedIn(position);
|
||||
Battle.EventHook.Invoke(new SwitchEvent(Index, position, pokemon));
|
||||
pokemon.RunScriptHook<IScriptOnSwitchIn>(script => script.OnSwitchIn(pokemon, position));
|
||||
|
||||
@@ -300,6 +310,14 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
return oldPokemon;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IBattlePokemon? SendOut(byte position, IPokemon pokemon)
|
||||
{
|
||||
var wrapper = Battle.Parties.Select(p => p.GetBattlePokemon(pokemon)).FirstOrDefault(x => x != null) ??
|
||||
throw new InvalidOperationException("The Pokémon does not belong to any party in this battle.");
|
||||
return SwapPokemon(position, wrapper);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SwapPokemon(byte position1, byte position2)
|
||||
{
|
||||
@@ -307,7 +325,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPokemonOnSide(IPokemon pokemon) => _pokemon.Contains(pokemon);
|
||||
public bool IsPokemonOnSide(IBattlePokemon pokemon) => _pokemon.Contains(pokemon);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void MarkPositionAsUnfillable(byte position) => _fillablePositions[position] = false;
|
||||
|
||||
@@ -13,7 +13,7 @@ public interface IFleeChoice : ITurnChoice
|
||||
public class FleeTurnChoice : TurnChoice, IFleeChoice
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public FleeTurnChoice(IPokemon user) : base(user)
|
||||
public FleeTurnChoice(IBattlePokemon user) : base(user)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -16,15 +16,15 @@ public interface IItemChoice : ITurnChoice
|
||||
/// <summary>
|
||||
/// The target Pokémon of the item, if any.
|
||||
/// </summary>
|
||||
IPokemon? GetTargetPokemon(IBattle battle);
|
||||
IBattlePokemon? GetTargetPokemon(IBattle battle);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IItemChoice"/>
|
||||
public class ItemChoice : TurnChoice, IItemChoice
|
||||
{
|
||||
/// <inheritdoc cref="ItemChoice"/>
|
||||
private ItemChoice(IPokemon user, IItem item, byte? targetSide, byte? targetPosition, IPokemon? targetPokemon) :
|
||||
base(user)
|
||||
private ItemChoice(IBattlePokemon user, IItem item, byte? targetSide, byte? targetPosition,
|
||||
IBattlePokemon? targetPokemon) : base(user)
|
||||
{
|
||||
Item = item;
|
||||
TargetSide = targetSide;
|
||||
@@ -32,13 +32,13 @@ public class ItemChoice : TurnChoice, IItemChoice
|
||||
TargetPokemon = targetPokemon;
|
||||
}
|
||||
|
||||
public static ItemChoice CreateWithoutTarget(IPokemon user, IItem item) =>
|
||||
public static ItemChoice CreateWithoutTarget(IBattlePokemon user, IItem item) =>
|
||||
new(user, item, null, null, null);
|
||||
|
||||
public static ItemChoice CreateForOpponent(IPokemon user, IItem item, byte targetSide, byte targetPosition) =>
|
||||
public static ItemChoice CreateForOpponent(IBattlePokemon user, IItem item, byte targetSide, byte targetPosition) =>
|
||||
new(user, item, targetSide, targetPosition, null);
|
||||
|
||||
public static ItemChoice CreateForPartyMember(IPokemon user, IItem item, IPokemon targetPokemon) =>
|
||||
public static ItemChoice CreateForPartyMember(IBattlePokemon user, IItem item, IBattlePokemon targetPokemon) =>
|
||||
new(user, item, null, null, targetPokemon);
|
||||
|
||||
/// <summary>
|
||||
@@ -47,7 +47,7 @@ public class ItemChoice : TurnChoice, IItemChoice
|
||||
public IItem Item { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IPokemon? GetTargetPokemon(IBattle battle)
|
||||
public IBattlePokemon? GetTargetPokemon(IBattle battle)
|
||||
{
|
||||
if (TargetPokemon != null)
|
||||
return TargetPokemon;
|
||||
@@ -71,7 +71,7 @@ public class ItemChoice : TurnChoice, IItemChoice
|
||||
/// <summary>
|
||||
/// The target Pokémon of the item, if any. This is used for party members.
|
||||
/// </summary>
|
||||
private IPokemon? TargetPokemon { get; }
|
||||
private IBattlePokemon? TargetPokemon { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int ScriptCount => User.ScriptCount;
|
||||
|
||||
@@ -51,7 +51,7 @@ public interface IMoveChoice : ITurnChoice
|
||||
public class MoveChoice : TurnChoice, IMoveChoice
|
||||
{
|
||||
/// <inheritdoc cref="MoveChoice"/>
|
||||
public MoveChoice(IPokemon user, ILearnedMove usedMove, byte targetSide, byte targetPosition) : base(user)
|
||||
public MoveChoice(IBattlePokemon user, ILearnedMove usedMove, byte targetSide, byte targetPosition) : base(user)
|
||||
{
|
||||
ChosenMove = usedMove;
|
||||
TargetSide = targetSide;
|
||||
|
||||
@@ -13,7 +13,7 @@ public interface IPassChoice : ITurnChoice
|
||||
public class PassChoice : TurnChoice, IPassChoice
|
||||
{
|
||||
/// <inheritdoc cref="PassChoice"/>
|
||||
public PassChoice(IPokemon user) : base(user)
|
||||
public PassChoice(IBattlePokemon user) : base(user)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -10,20 +10,20 @@ public interface ISwitchChoice : ITurnChoice
|
||||
/// <summary>
|
||||
/// The Pokémon to switch to.
|
||||
/// </summary>
|
||||
IPokemon SwitchTo { get; }
|
||||
IBattlePokemon SwitchTo { get; }
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ISwitchChoice"/>
|
||||
public class SwitchChoice : TurnChoice, ISwitchChoice
|
||||
{
|
||||
/// <inheritdoc cref="SwitchChoice"/>
|
||||
public SwitchChoice(IPokemon user, IPokemon switchTo) : base(user)
|
||||
public SwitchChoice(IBattlePokemon user, IBattlePokemon switchTo) : base(user)
|
||||
{
|
||||
SwitchTo = switchTo;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IPokemon SwitchTo { get; }
|
||||
public IBattlePokemon SwitchTo { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int ScriptCount => User.ScriptCount;
|
||||
|
||||
@@ -11,7 +11,7 @@ public interface ITurnChoice : IScriptSource, IDeepCloneable
|
||||
/// <summary>
|
||||
/// The user of the turn choice
|
||||
/// </summary>
|
||||
IPokemon User { get; }
|
||||
IBattlePokemon User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The speed of the user at the beginning of the turn.
|
||||
@@ -34,7 +34,7 @@ public interface ITurnChoice : IScriptSource, IDeepCloneable
|
||||
/// Fails the choice. This will prevent it from executing and run a specific fail handling during
|
||||
/// execution. Note that this can not be undone.
|
||||
/// </summary>
|
||||
public void Fail();
|
||||
void Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -43,7 +43,7 @@ public interface ITurnChoice : IScriptSource, IDeepCloneable
|
||||
public abstract class TurnChoice : ScriptSource, ITurnChoice
|
||||
{
|
||||
/// <inheritdoc cref="TurnChoice"/>
|
||||
protected TurnChoice(IPokemon user)
|
||||
protected TurnChoice(IBattlePokemon user)
|
||||
{
|
||||
User = user;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public abstract class TurnChoice : ScriptSource, ITurnChoice
|
||||
/// <summary>
|
||||
/// The Pokemon for which the choice is made.
|
||||
/// </summary>
|
||||
public IPokemon User { get; }
|
||||
public IBattlePokemon User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The speed of the user at the beginning of the turn.
|
||||
|
||||
@@ -129,7 +129,7 @@ public interface IExecutingMove : IScriptSource
|
||||
/// <summary>
|
||||
/// The user of the move.
|
||||
/// </summary>
|
||||
IPokemon User { get; }
|
||||
IBattlePokemon User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The move the user has actually chosen to do.
|
||||
@@ -151,17 +151,17 @@ public interface IExecutingMove : IScriptSource
|
||||
/// <summary>
|
||||
/// Gets a hit data for a target, with a specific index.
|
||||
/// </summary>
|
||||
IHitData GetHitData(IPokemon target, byte hit);
|
||||
IHitData GetHitData(IBattlePokemon target, byte hit);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a Pokémon is a target for this move.
|
||||
/// </summary>
|
||||
bool IsPokemonTarget(IPokemon target);
|
||||
bool IsPokemonTarget(IBattlePokemon target);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the hits in this move where the hits for a specific target start.
|
||||
/// </summary>
|
||||
int GetTargetIndex(IPokemon target);
|
||||
int GetTargetIndex(IBattlePokemon target);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a hit based on its raw index.
|
||||
@@ -171,7 +171,7 @@ public interface IExecutingMove : IScriptSource
|
||||
/// <summary>
|
||||
/// Gets the targets of this move.
|
||||
/// </summary>
|
||||
IReadOnlyList<IPokemon?> Targets { get; }
|
||||
IReadOnlyList<IBattlePokemon?> Targets { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The underlying move choice.
|
||||
@@ -192,12 +192,12 @@ public interface IExecutingMove : IScriptSource
|
||||
/// <inheritdoc cref="IExecutingMove"/>
|
||||
public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
{
|
||||
private readonly IReadOnlyList<IPokemon?> _targets;
|
||||
private readonly IReadOnlyList<IBattlePokemon?> _targets;
|
||||
private readonly IHitData[] _hits;
|
||||
private readonly IBattle _battle;
|
||||
|
||||
/// <inheritdoc cref="ExecutingMoveImpl"/>
|
||||
public ExecutingMoveImpl(IReadOnlyList<IPokemon?> targets, byte numberOfHits, ILearnedMove chosenMove,
|
||||
public ExecutingMoveImpl(IReadOnlyList<IBattlePokemon?> targets, byte numberOfHits, ILearnedMove chosenMove,
|
||||
IMoveData useMove, IMoveChoice moveChoice, IBattle battle)
|
||||
{
|
||||
_targets = targets;
|
||||
@@ -222,7 +222,7 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
public byte NumberOfHits { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IPokemon User => MoveChoice.User;
|
||||
public IBattlePokemon User => MoveChoice.User;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ILearnedMove ChosenMove { get; }
|
||||
@@ -239,7 +239,7 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
public IScriptSet Volatile => MoveChoice.Volatile;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IHitData GetHitData(IPokemon target, byte hit)
|
||||
public IHitData GetHitData(IBattlePokemon target, byte hit)
|
||||
{
|
||||
var targetIndex = _targets.IndexOf(target);
|
||||
if (targetIndex == -1)
|
||||
@@ -252,10 +252,10 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPokemonTarget(IPokemon target) => _targets.Contains(target);
|
||||
public bool IsPokemonTarget(IBattlePokemon target) => _targets.Contains(target);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int GetTargetIndex(IPokemon target)
|
||||
public int GetTargetIndex(IBattlePokemon target)
|
||||
{
|
||||
var targetIndex = _targets.IndexOf(target);
|
||||
if (targetIndex == -1)
|
||||
@@ -273,7 +273,7 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<IPokemon?> Targets => _targets.ToList();
|
||||
public IReadOnlyList<IBattlePokemon?> Targets => _targets.ToList();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMoveChoice MoveChoice { get; }
|
||||
|
||||
@@ -35,29 +35,30 @@ public static class ItemTargetTypeHelpers
|
||||
/// <summary>
|
||||
/// Determines if the given target is valid based on the ItemTargetType.
|
||||
/// </summary>
|
||||
public static bool IsValidTarget(this ItemTargetType targetType, IBattle battle, IPokemon user, IPokemon target)
|
||||
public static bool IsValidTarget(this ItemTargetType targetType, IBattle battle, IBattlePokemon user,
|
||||
IBattlePokemon target)
|
||||
{
|
||||
if (targetType == ItemTargetType.None)
|
||||
return true;
|
||||
|
||||
if (targetType.HasFlag(ItemTargetType.OwnPokemon))
|
||||
{
|
||||
var userParty = battle.Parties.FirstOrDefault(x => x.Party.Contains(user));
|
||||
var targetParty = battle.Parties.FirstOrDefault(x => x.Party.Contains(target));
|
||||
var userParty = battle.Parties.FirstOrDefault(x => x.BattlePokemon.Contains(user));
|
||||
var targetParty = battle.Parties.FirstOrDefault(x => x.BattlePokemon.Contains(target));
|
||||
if (userParty is not null && targetParty is not null && userParty == targetParty)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (targetType.HasFlag(ItemTargetType.AllyPokemon))
|
||||
{
|
||||
if (user.BattleData?.BattleSide == target.BattleData?.BattleSide)
|
||||
if (user.BattleSide == target.BattleSide)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (targetType.HasFlag(ItemTargetType.FoePokemon))
|
||||
{
|
||||
var userParty = battle.Parties.FirstOrDefault(x => x.Party.Contains(user));
|
||||
var targetParty = battle.Parties.FirstOrDefault(x => x.Party.Contains(target));
|
||||
var userParty = battle.Parties.FirstOrDefault(x => x.BattlePokemon.Contains(user));
|
||||
var targetParty = battle.Parties.FirstOrDefault(x => x.BattlePokemon.Contains(target));
|
||||
if (userParty is not null && targetParty is not null && userParty != targetParty)
|
||||
return true;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,7 @@ public record SerializedPokemon
|
||||
Nature = pokemon.Nature.Name;
|
||||
Nickname = pokemon.Nickname;
|
||||
Ability = pokemon.Form.GetAbility(pokemon.AbilityIndex);
|
||||
Moves = pokemon.BaseMoves.Select(move =>
|
||||
Moves = pokemon.Moves.Select(move =>
|
||||
{
|
||||
if (move == null)
|
||||
return null;
|
||||
|
||||
@@ -41,7 +41,7 @@ public abstract class ItemScript : IDeepCloneable
|
||||
/// <summary>
|
||||
/// Returns whether the item is usable on the given target.
|
||||
/// </summary>
|
||||
public virtual bool IsTargetValid(IPokemon target) => false;
|
||||
public virtual bool IsTargetValid(IBattlePokemon target) => false;
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the item can be held by a Pokémon.
|
||||
@@ -51,7 +51,7 @@ public abstract class ItemScript : IDeepCloneable
|
||||
/// <summary>
|
||||
/// Returns whether the item can be held by the given target.
|
||||
/// </summary>
|
||||
public virtual bool CanTargetHold(IPokemon pokemon) => true;
|
||||
public virtual bool CanTargetHold(IBattlePokemon pokemon) => true;
|
||||
|
||||
/// <summary>
|
||||
/// Handles the use of the item.
|
||||
@@ -63,7 +63,7 @@ public abstract class ItemScript : IDeepCloneable
|
||||
/// <summary>
|
||||
/// Handles the use of the item on the given target.
|
||||
/// </summary>
|
||||
public virtual void OnUseWithTarget(IPokemon target, EventHook eventHook)
|
||||
public virtual void OnUseWithTarget(IBattlePokemon target, EventHook eventHook)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,9 @@ public abstract class PokeballScript : ItemScript
|
||||
/// <summary>
|
||||
/// Returns the catch rate of the Pokéball against the given target Pokémon.
|
||||
/// </summary>
|
||||
public abstract void ChangeCatchRate(IPokemon target, ref byte catchRate);
|
||||
public abstract void ChangeCatchRate(IBattlePokemon target, ref byte catchRate);
|
||||
|
||||
public virtual void OnAfterSuccessfulCapture(IPokemon target)
|
||||
public virtual void OnAfterSuccessfulCapture(IBattlePokemon target)
|
||||
{
|
||||
// Default implementation does nothing.
|
||||
// Override this method in derived classes to add custom behavior after a successful capture.
|
||||
@@ -32,16 +32,13 @@ public abstract class PokeballScript : ItemScript
|
||||
public override ItemTargetType TargetType => ItemTargetType.FoePokemon;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsTargetValid(IPokemon target) =>
|
||||
target.BattleData is not null && target.BattleData.Battle.IsWildBattle;
|
||||
public override bool IsTargetValid(IBattlePokemon target) => target.Battle.IsWildBattle;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnUseWithTarget(IPokemon target, EventHook eventHook)
|
||||
public override void OnUseWithTarget(IBattlePokemon target, EventHook eventHook)
|
||||
{
|
||||
var battleData = target.BattleData;
|
||||
|
||||
var result = battleData?.Battle.AttempCapture(battleData.SideIndex, battleData.Position, Item);
|
||||
if (result is { IsCaught: true })
|
||||
var result = target.Battle.AttempCapture(target.SideIndex, target.Position, Item);
|
||||
if (result.IsCaught)
|
||||
{
|
||||
OnAfterSuccessfulCapture(target);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public interface IAIInfoScriptExpectedEndOfTurnDamage
|
||||
/// This function returns the expected end of turn damage for the script. This is used for scripts that
|
||||
/// have an end of turn effect, such as Poison or Burn.
|
||||
/// </summary>
|
||||
void ExpectedEndOfTurnDamage(IPokemon pokemon, ref int damage);
|
||||
void ExpectedEndOfTurnDamage(IBattlePokemon pokemon, ref int damage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -37,5 +37,5 @@ public interface IAIInfoScriptExpectedEntryDamage
|
||||
/// This function returns the expected entry damage for the script. This is used for scripts that have
|
||||
/// an entry hazard effect, such as Spikes or Stealth Rock.
|
||||
/// </summary>
|
||||
void ExpectedEntryDamage(IPokemon pokemon, ref uint damage);
|
||||
void ExpectedEntryDamage(IBattlePokemon pokemon, ref uint damage);
|
||||
}
|
||||
@@ -100,8 +100,8 @@ public static class ScriptExecution
|
||||
/// <summary>
|
||||
/// Executes a script on an item.
|
||||
/// </summary>
|
||||
public static void RunItemScript(this IItem item, ScriptResolver scriptResolver, IPokemon? target, IPokemon user,
|
||||
IBattle battle, EventHook eventHook)
|
||||
public static void RunItemScript(this IItem item, ScriptResolver scriptResolver, IBattlePokemon? target,
|
||||
IBattlePokemon user, IBattle battle, EventHook eventHook)
|
||||
{
|
||||
if (!scriptResolver.TryResolveBattleItemScript(item, out var itemScript))
|
||||
{
|
||||
|
||||
@@ -125,7 +125,7 @@ public interface IScriptChangeTargets
|
||||
/// <summary>
|
||||
/// Changes the targets of a move choice. This allows for changing the targets of a move before the move starts.
|
||||
/// </summary>
|
||||
void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets);
|
||||
void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IBattlePokemon?> targets);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -136,7 +136,7 @@ public interface IScriptChangeIncomingTargets
|
||||
/// <summary>
|
||||
/// This function allows you to change the targets of a move choice before the move starts.
|
||||
/// </summary>
|
||||
void ChangeIncomingTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets);
|
||||
void ChangeIncomingTargets(IMoveChoice moveChoice, ref IReadOnlyList<IBattlePokemon?> targets);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -219,7 +219,7 @@ public interface IScriptChangeMoveType
|
||||
/// This function allows the script to change the actual type that is used for the move on a target.
|
||||
/// If this is set to null, the move will be treated as a typeless move.
|
||||
/// </summary>
|
||||
void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? typeIdentifier);
|
||||
void ChangeMoveType(IExecutingMove move, IBattlePokemon target, byte hit, ref TypeIdentifier? typeIdentifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -230,7 +230,7 @@ public interface IScriptChangeEffectiveness
|
||||
/// <summary>
|
||||
/// This function allows the script to change how effective a move is on a target.
|
||||
/// </summary>
|
||||
void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness);
|
||||
void ChangeEffectiveness(IExecutingMove move, IBattlePokemon target, byte hit, ref float effectiveness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -241,7 +241,7 @@ public interface IScriptChangeIncomingEffectiveness
|
||||
/// <summary>
|
||||
/// This function allows the script to override how effective a move is on a target.
|
||||
/// </summary>
|
||||
void ChangeIncomingEffectiveness(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||
void ChangeIncomingEffectiveness(IExecutingMove executingMove, IBattlePokemon target, byte hitIndex,
|
||||
ref float effectiveness);
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ public interface IScriptBlockCriticalHit
|
||||
/// <summary>
|
||||
/// This function allows a script to block an outgoing move from being critical.
|
||||
/// </summary>
|
||||
void BlockCriticalHit(IExecutingMove move, IPokemon target, byte hit, ref bool block);
|
||||
void BlockCriticalHit(IExecutingMove move, IBattlePokemon target, byte hit, ref bool block);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -264,7 +264,7 @@ public interface IScriptBlockIncomingCriticalHit
|
||||
/// <summary>
|
||||
/// This function allows a script to block an incoming move from being critical.
|
||||
/// </summary>
|
||||
void BlockIncomingCriticalHit(IExecutingMove move, IPokemon target, byte hit, ref bool block);
|
||||
void BlockIncomingCriticalHit(IExecutingMove move, IBattlePokemon target, byte hit, ref bool block);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -276,7 +276,7 @@ public interface IScriptOnIncomingHit
|
||||
/// This function triggers when an incoming hit happens. This triggers after the damage is done,
|
||||
/// but before the secondary effect of the move happens.
|
||||
/// </summary>
|
||||
void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit);
|
||||
void OnIncomingHit(IExecutingMove move, IBattlePokemon target, byte hit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -287,7 +287,7 @@ public interface IScriptOnOpponentFaints
|
||||
/// <summary>
|
||||
/// This function triggers when an opponent on the f ield faints due to the move that is being executed.
|
||||
/// </summary>
|
||||
void OnOpponentFaints(IExecutingMove move, IPokemon target, byte hit);
|
||||
void OnOpponentFaints(IExecutingMove move, IBattlePokemon target, byte hit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -300,7 +300,7 @@ public interface IScriptOnSecondaryEffect
|
||||
/// secondary effects here. Status moves should implement their actual functionality in this
|
||||
/// function as well, as status moves effects are defined as secondary effects for simplicity.
|
||||
/// </summary>
|
||||
void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit);
|
||||
void OnSecondaryEffect(IExecutingMove move, IBattlePokemon target, byte hit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -312,7 +312,7 @@ public interface IScriptFailIncomingMove
|
||||
/// This function allows a script to prevent a move that is targeted at its owner. If set to true
|
||||
/// the move fails, and fail events get triggered.
|
||||
/// </summary>
|
||||
void FailIncomingMove(IExecutingMove move, IPokemon target, ref bool fail);
|
||||
void FailIncomingMove(IExecutingMove move, IBattlePokemon target, ref bool fail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -323,7 +323,7 @@ public interface IScriptIsInvulnerableToMove
|
||||
/// <summary>
|
||||
/// This function allows a script to make its owner invulnerable to an incoming move.
|
||||
/// </summary>
|
||||
void IsInvulnerableToMove(IExecutingMove move, IPokemon target, ref bool invulnerable);
|
||||
void IsInvulnerableToMove(IExecutingMove move, IBattlePokemon target, ref bool invulnerable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -335,7 +335,7 @@ public interface IScriptOnMoveMiss
|
||||
/// This function allows a script to run when a move misses its target. This is used for moves
|
||||
/// that have a secondary effect that should run even if the move misses, such as Spore.
|
||||
/// </summary>
|
||||
void OnMoveMiss(IExecutingMove move, IPokemon target);
|
||||
void OnMoveMiss(IExecutingMove move, IBattlePokemon target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -347,7 +347,7 @@ public interface IScriptChangeAccuracyModifier
|
||||
/// 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>
|
||||
void ChangeAccuracyModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier);
|
||||
void ChangeAccuracyModifier(IExecutingMove move, IBattlePokemon target, byte hit, ref float modifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -358,7 +358,7 @@ public interface IScriptChangeCriticalStage
|
||||
/// <summary>
|
||||
/// This function allows a script to change the critical stage of the move used.
|
||||
/// </summary>
|
||||
void ChangeCriticalStage(IExecutingMove move, IPokemon target, byte hit, ref byte stage);
|
||||
void ChangeCriticalStage(IExecutingMove move, IBattlePokemon target, byte hit, ref byte stage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -370,7 +370,7 @@ public interface IScriptChangeCriticalModifier
|
||||
/// This function allows a script to change the damage modifier of a critical hit. This will only
|
||||
/// run when a hit is critical.
|
||||
/// </summary>
|
||||
void ChangeCriticalModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier);
|
||||
void ChangeCriticalModifier(IExecutingMove move, IBattlePokemon target, byte hit, ref float modifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -382,7 +382,7 @@ public interface IScriptChangeStabModifier
|
||||
/// This function allows a script to change the damage modifier of a Same Type Attack Bonus, which
|
||||
/// occurs when the user has the move type as one of its own types.
|
||||
/// </summary>
|
||||
void ChangeStabModifier(IExecutingMove executingMove, IPokemon target, byte hitNumber, bool isStab,
|
||||
void ChangeStabModifier(IExecutingMove executingMove, IBattlePokemon target, byte hitNumber, bool isStab,
|
||||
ref float modifier);
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ public interface IScriptChangeBasePower
|
||||
/// <summary>
|
||||
/// This function allows a script to change the effective base power of a move hit.
|
||||
/// </summary>
|
||||
void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower);
|
||||
void ChangeBasePower(IExecutingMove move, IBattlePokemon target, byte hit, ref ushort basePower);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -407,7 +407,7 @@ public interface IScriptBypassDefensiveStatBoosts
|
||||
/// If this is true, the damage will be calculated as if the target has no positive stat boosts. Negative
|
||||
/// stat boosts will still be applied.
|
||||
/// </summary>
|
||||
void BypassDefensiveStatBoosts(IExecutingMove move, IPokemon target, byte hit, ref bool bypass);
|
||||
void BypassDefensiveStatBoosts(IExecutingMove move, IBattlePokemon target, byte hit, ref bool bypass);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -419,7 +419,7 @@ public interface IScriptBypassEvasionStatBoosts
|
||||
/// This function allows a script to bypass evasion stat boosts for a move hit.
|
||||
/// If this is true, the move will handle the evasion stat boosts as if the target has no positive stat boosts.
|
||||
/// </summary>
|
||||
void BypassEvasionStatBoosts(IExecutingMove move, IPokemon target, byte hitIndex, ref bool bypass);
|
||||
void BypassEvasionStatBoosts(IExecutingMove move, IBattlePokemon target, byte hitIndex, ref bool bypass);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -432,7 +432,7 @@ public interface IScriptBypassOffensiveStatBoosts
|
||||
/// If this is true, the damage will be calculated as if the user has no negative offensive stat boosts. Positive
|
||||
/// stat boosts will still be applied.
|
||||
/// </summary>
|
||||
void BypassOffensiveStatBoosts(IExecutingMove move, IPokemon target, byte hit, ref bool bypass);
|
||||
void BypassOffensiveStatBoosts(IExecutingMove move, IBattlePokemon target, byte hit, ref bool bypass);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -443,7 +443,7 @@ public interface IScriptChangeOffensiveStatValue
|
||||
/// <summary>
|
||||
/// This function allows a script to change the actual offensive stat values used when calculating damage
|
||||
/// </summary>
|
||||
void ChangeOffensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint defensiveStat,
|
||||
void ChangeOffensiveStatValue(IExecutingMove move, IBattlePokemon target, byte hit, uint defensiveStat,
|
||||
ImmutableStatisticSet<uint> targetStats, Statistic stat, ref uint value);
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ public interface IScriptChangeDefensiveStatValue
|
||||
/// <summary>
|
||||
/// This function allows a script to change the actual defensive stat values used when calculating damage.
|
||||
/// </summary>
|
||||
void ChangeDefensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint offensiveStat,
|
||||
void ChangeDefensiveStatValue(IExecutingMove move, IBattlePokemon target, byte hit, uint offensiveStat,
|
||||
ImmutableStatisticSet<uint> targetStats, Statistic stat, ref uint value);
|
||||
}
|
||||
|
||||
@@ -467,7 +467,7 @@ public interface IScriptChangeIncomingMoveOffensiveStatValue
|
||||
/// <summary>
|
||||
/// This function allows a script to change the offensive stat value of an incoming move.
|
||||
/// </summary>
|
||||
void ChangeIncomingMoveOffensiveStatValue(IExecutingMove executingMove, IPokemon target, byte hitNumber,
|
||||
void ChangeIncomingMoveOffensiveStatValue(IExecutingMove executingMove, IBattlePokemon target, byte hitNumber,
|
||||
uint defensiveStat, StatisticSet<uint> targetStats, Statistic offensive, ref uint offensiveStat);
|
||||
}
|
||||
|
||||
@@ -479,7 +479,7 @@ public interface IScriptChangeIncomingMoveDefensiveStatValue
|
||||
/// <summary>
|
||||
/// This function allows a script to change the defensive stat value of an incoming move.
|
||||
/// </summary>
|
||||
void ChangeIncomingMoveDefensiveStatValue(IExecutingMove executingMove, IPokemon target, byte hitNumber,
|
||||
void ChangeIncomingMoveDefensiveStatValue(IExecutingMove executingMove, IBattlePokemon target, byte hitNumber,
|
||||
uint origOffensiveStat, StatisticSet<uint> targetStats, Statistic defensive, ref uint defensiveStat);
|
||||
}
|
||||
|
||||
@@ -492,7 +492,7 @@ public interface IScriptChangeDamageStatModifier
|
||||
/// This function allows a script to change the raw modifier we retrieved from the stats of the
|
||||
/// defender and attacker. The default value is the offensive stat divided by the defensive stat.
|
||||
/// </summary>
|
||||
void ChangeDamageStatModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier);
|
||||
void ChangeDamageStatModifier(IExecutingMove move, IBattlePokemon target, byte hit, ref float modifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -503,7 +503,7 @@ public interface IScriptChangeDamageModifier
|
||||
/// <summary>
|
||||
/// This function allows a script to apply a raw multiplier to the damage done by a move.
|
||||
/// </summary>
|
||||
void ChangeDamageModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier);
|
||||
void ChangeDamageModifier(IExecutingMove move, IBattlePokemon target, byte hit, ref float modifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -514,7 +514,7 @@ public interface IScriptChangeIncomingMoveDamageModifier
|
||||
/// <summary>
|
||||
/// This function allows a script to change the damage modifier of an incoming move.
|
||||
/// </summary>
|
||||
void ChangeIncomingMoveDamageModifier(IExecutingMove executingMove, IPokemon target, byte hitNumber,
|
||||
void ChangeIncomingMoveDamageModifier(IExecutingMove executingMove, IBattlePokemon target, byte hitNumber,
|
||||
ref float modifier);
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ public interface IScriptChangeMoveDamage
|
||||
/// <summary>
|
||||
/// This function allows a script to modify the outgoing damage done by a move.
|
||||
/// </summary>
|
||||
void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage);
|
||||
void ChangeMoveDamage(IExecutingMove move, IBattlePokemon target, byte hit, ref uint damage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -537,7 +537,7 @@ public interface IScriptChangeIncomingMoveDamage
|
||||
/// <summary>
|
||||
/// This function allows a script to modify the incoming damage done by a move.
|
||||
/// </summary>
|
||||
void ChangeIncomingMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage);
|
||||
void ChangeIncomingMoveDamage(IExecutingMove move, IBattlePokemon target, byte hit, ref uint damage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -549,7 +549,8 @@ public interface IScriptPreventStatBoostChange
|
||||
/// This function allows a script attached to a Pokemon or its parents to prevent stat boost
|
||||
/// changes on that Pokemon.
|
||||
/// </summary>
|
||||
void PreventStatBoostChange(IPokemon target, Statistic stat, sbyte amount, bool selfInflicted, ref bool prevent);
|
||||
void PreventStatBoostChange(IBattlePokemon target, Statistic stat, sbyte amount, bool selfInflicted,
|
||||
ref bool prevent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -562,7 +563,7 @@ public interface IScriptChangeStatBoostChange
|
||||
/// which the stat boost will change. If the stat boost is done by the user itself, self
|
||||
/// inflicted will be true, otherwise it will be false.
|
||||
/// </summary>
|
||||
void ChangeStatBoostChange(IPokemon target, Statistic stat, bool selfInflicted, ref sbyte amount);
|
||||
void ChangeStatBoostChange(IBattlePokemon target, Statistic stat, bool selfInflicted, ref sbyte amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -573,7 +574,7 @@ public interface IScriptOnAfterStatBoostChange
|
||||
/// <summary>
|
||||
/// This function allows a script to run after a stat boost change has been applied.
|
||||
/// </summary>
|
||||
void OnAfterStatBoostChange(IPokemon pokemon, Statistic stat, bool selfInflicted, sbyte change);
|
||||
void OnAfterStatBoostChange(IBattlePokemon pokemon, Statistic stat, bool selfInflicted, sbyte change);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -586,7 +587,7 @@ public interface IScriptPreventSecondaryEffect
|
||||
/// This means the move will still hit and do damage, but not trigger its secondary effect. Note that this
|
||||
/// function is not called for status moves.
|
||||
/// </summary>
|
||||
void PreventSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent);
|
||||
void PreventSecondaryEffect(IExecutingMove move, IBattlePokemon target, byte hit, ref bool prevent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -599,7 +600,7 @@ public interface IScriptPreventIncomingSecondaryEffect
|
||||
/// secondary effect. This means the move will still hit and do damage, but not trigger its
|
||||
/// secondary effect. Note that this function is not called for status moves.
|
||||
/// </summary>
|
||||
void PreventIncomingSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent);
|
||||
void PreventIncomingSecondaryEffect(IExecutingMove move, IBattlePokemon target, byte hit, ref bool prevent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -613,7 +614,7 @@ public interface IScriptChangeEffectChance
|
||||
/// changing this to above or equal to 100 will make it always hit, while setting it to equal or
|
||||
/// below 0 will make it never hit.
|
||||
/// </summary>
|
||||
void ChangeEffectChance(IExecutingMove move, IPokemon target, byte hit, ref float chance);
|
||||
void ChangeEffectChance(IExecutingMove move, IBattlePokemon target, byte hit, ref float chance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -627,7 +628,7 @@ public interface IScriptChangeIncomingEffectChance
|
||||
/// so changing this to above or equal to 100 will make it always hit, while setting it to equal
|
||||
/// or below 0 will make it never hit.
|
||||
/// </summary>
|
||||
void ChangeIncomingEffectChance(IExecutingMove move, IPokemon target, byte hit, ref float chance);
|
||||
void ChangeIncomingEffectChance(IExecutingMove move, IBattlePokemon target, byte hit, ref float chance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -638,7 +639,7 @@ public interface IScriptOnAfterHits
|
||||
/// <summary>
|
||||
/// This function triggers on a move or its parents when all hits on a target are finished.
|
||||
/// </summary>
|
||||
void OnAfterHits(IExecutingMove move, IPokemon target);
|
||||
void OnAfterHits(IExecutingMove move, IBattlePokemon target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -706,7 +707,7 @@ public interface IScriptOnDamage
|
||||
/// <summary>
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage.
|
||||
/// </summary>
|
||||
void OnDamage(IPokemon pokemon, DamageSource source, uint oldHealth, uint newHealth);
|
||||
void OnDamage(IBattlePokemon pokemon, DamageSource source, uint oldHealth, uint newHealth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -717,7 +718,7 @@ public interface IScriptOnFaint
|
||||
/// <summary>
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon faints.
|
||||
/// </summary>
|
||||
void OnFaint(IPokemon pokemon, DamageSource source);
|
||||
void OnFaint(IBattlePokemon pokemon, DamageSource source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -728,7 +729,7 @@ public interface IScriptOnAllyFaint
|
||||
/// <summary>
|
||||
/// This function is triggered on a Pokemon when an ally Pokemon faints.
|
||||
/// </summary>
|
||||
void OnAllyFaint(IPokemon ally, IPokemon faintedPokemon);
|
||||
void OnAllyFaint(IBattlePokemon ally, IBattlePokemon faintedPokemon);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -740,7 +741,7 @@ public interface IScriptOnSwitchOut
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon switches out
|
||||
/// of the battlefield.
|
||||
/// </summary>
|
||||
void OnSwitchOut(IPokemon oldPokemon, byte position);
|
||||
void OnSwitchOut(IBattlePokemon oldPokemon, byte position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -752,7 +753,7 @@ public interface IScriptOnSwitchIn
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
|
||||
/// the battlefield.
|
||||
/// </summary>
|
||||
void OnSwitchIn(IPokemon pokemon, byte position);
|
||||
void OnSwitchIn(IBattlePokemon pokemon, byte position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -763,7 +764,7 @@ public interface IScriptOnOpponentSwitchIn
|
||||
/// <summary>
|
||||
/// This function is triggered on a Pokemon and its parents when an opponent switches in.
|
||||
/// </summary>
|
||||
void OnOpponentSwitchIn(IPokemon pokemon, byte position);
|
||||
void OnOpponentSwitchIn(IBattlePokemon pokemon, byte position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -787,7 +788,7 @@ public interface IScriptOnAfterItemConsume
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
|
||||
/// held item it had.
|
||||
/// </summary>
|
||||
void OnAfterItemConsume(IPokemon pokemon, IItem item);
|
||||
void OnAfterItemConsume(IBattlePokemon pokemon, IItem item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -798,7 +799,7 @@ public interface IScriptBlockIncomingHit
|
||||
/// <summary>
|
||||
/// This function allows a script to block an incoming hit.
|
||||
/// </summary>
|
||||
void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block);
|
||||
void BlockIncomingHit(IExecutingMove executingMove, IBattlePokemon target, byte hitIndex, ref bool block);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -809,7 +810,7 @@ public interface IScriptBlockOutgoingHit
|
||||
/// <summary>
|
||||
/// This function allows a script to block an outgoing hit.
|
||||
/// </summary>
|
||||
void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block);
|
||||
void BlockOutgoingHit(IExecutingMove executingMove, IBattlePokemon target, byte hitIndex, ref bool block);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -820,7 +821,7 @@ public interface IScriptPreventHeldItemConsume
|
||||
/// <summary>
|
||||
/// This function allows a script to prevent a held item from being consumed.
|
||||
/// </summary>
|
||||
void PreventHeldItemConsume(IPokemon pokemon, IItem heldItem, ref bool prevented);
|
||||
void PreventHeldItemConsume(IBattlePokemon pokemon, IItem heldItem, ref bool prevented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -831,7 +832,7 @@ public interface IScriptChangeIncomingDamage
|
||||
/// <summary>
|
||||
/// This function allows a script to change any kind of damage that is incoming.
|
||||
/// </summary>
|
||||
void ChangeIncomingDamage(IPokemon pokemon, DamageSource source, ref uint damage);
|
||||
void ChangeIncomingDamage(IBattlePokemon pokemon, DamageSource source, ref uint damage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -853,7 +854,7 @@ public interface IScriptPreventHeal
|
||||
/// <summary>
|
||||
/// This function allows a script to prevent a Pokemon from being healed.
|
||||
/// </summary>
|
||||
void PreventHeal(IPokemon pokemon, uint heal, bool allowRevive, ref bool prevented);
|
||||
void PreventHeal(IBattlePokemon pokemon, uint heal, bool allowRevive, ref bool prevented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -865,7 +866,8 @@ public interface IScriptChangeTypesForMove
|
||||
/// This function allows a script to change the types a target has. Multiple types can be set, and will be used
|
||||
/// for the effectiveness calculation.
|
||||
/// </summary>
|
||||
void ChangeTypesForMove(IExecutingMove executingMove, IPokemon target, byte hitIndex, IList<TypeIdentifier> types);
|
||||
void ChangeTypesForMove(IExecutingMove executingMove, IBattlePokemon target, byte hitIndex,
|
||||
IList<TypeIdentifier> types);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -877,7 +879,7 @@ public interface IScriptChangeTypesForIncomingMove
|
||||
/// This function allows a script to change the types a Pokemon has for a move that's incoming. Multiple types can
|
||||
/// be set, and will be used for the effectiveness calculation.
|
||||
/// </summary>
|
||||
void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||
void ChangeTypesForIncomingMove(IExecutingMove executingMove, IBattlePokemon target, byte hitIndex,
|
||||
IList<TypeIdentifier> types);
|
||||
}
|
||||
|
||||
@@ -890,7 +892,7 @@ public interface IScriptChangeCategory
|
||||
/// This function allows a script to change the handling of the move category. This is used for moves that
|
||||
/// are sometimes a status move, and sometimes a damaging move, such as pollen puff.
|
||||
/// </summary>
|
||||
void ChangeCategory(IExecutingMove move, IPokemon target, byte hitIndex, ref MoveCategory category);
|
||||
void ChangeCategory(IExecutingMove move, IBattlePokemon target, byte hitIndex, ref MoveCategory category);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -901,7 +903,7 @@ public interface IScriptOnBeforeHit
|
||||
/// <summary>
|
||||
/// Triggers first when we're about to hit a target.
|
||||
/// </summary>
|
||||
void OnBeforeHit(IExecutingMove move, IPokemon target, byte hitIndex);
|
||||
void OnBeforeHit(IExecutingMove move, IBattlePokemon target, byte hitIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -912,7 +914,7 @@ public interface IScriptPreventStatusChange
|
||||
/// <summary>
|
||||
/// This function allows a script to prevent a Pokemon from being affected by a status condition.
|
||||
/// </summary>
|
||||
void PreventStatusChange(IPokemon pokemon, StringKey status, bool selfInflicted, ref bool preventStatus);
|
||||
void PreventStatusChange(IBattlePokemon pokemon, StringKey status, bool selfInflicted, ref bool preventStatus);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -923,7 +925,7 @@ public interface IScriptOnAfterStatusChange
|
||||
/// <summary>
|
||||
/// This function triggers after a status condition has been applied to a Pokemon.
|
||||
/// </summary>
|
||||
void OnAfterStatusChange(IPokemon pokemon, StringKey status, IPokemon? originPokemon);
|
||||
void OnAfterStatusChange(IBattlePokemon pokemon, StringKey status, IPokemon? originPokemon);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -946,7 +948,7 @@ public interface IScriptIsFloating
|
||||
/// This function allows a script to make the Pokémon it is attached to float. This is used for moves
|
||||
/// such as levitate, and allows for moves such as earthquake to not hit the Pokémon.
|
||||
/// </summary>
|
||||
void IsFloating(IPokemon pokemon, ref bool isFloating);
|
||||
void IsFloating(IBattlePokemon pokemon, ref bool isFloating);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -991,7 +993,7 @@ public interface IScriptModifyIsContact
|
||||
/// <summary>
|
||||
/// Modifies whether a move is a contact move or not. This is used for abilities such as Long Reach.
|
||||
/// </summary>
|
||||
void ModifyIsContact(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool isContact);
|
||||
void ModifyIsContact(IExecutingMove executingMove, IBattlePokemon target, byte hitIndex, ref bool isContact);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1002,7 +1004,7 @@ public interface IScriptPreventHeldItemSteal
|
||||
/// <summary>
|
||||
/// This function allows a script to prevent a held item from being stolen by an effect such as Thief or Covet.
|
||||
/// </summary>
|
||||
void PreventHeldItemSteal(IPokemon pokemon, IItem heldItem, ref bool prevent);
|
||||
void PreventHeldItemSteal(IBattlePokemon pokemon, IItem heldItem, ref bool prevent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1013,7 +1015,7 @@ public interface IScriptOnAfterHeldItemChange
|
||||
/// <summary>
|
||||
/// This function allows a script to run after a held item has changed.
|
||||
/// </summary>
|
||||
void OnAfterHeldItemChange(IPokemon pokemon, IItem? previous, IItem? item);
|
||||
void OnAfterHeldItemChange(IBattlePokemon pokemon, IItem? previous, IItem? item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1080,7 +1082,7 @@ public interface IScriptChangeExperienceGained
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
|
||||
/// and allows for changing this amount of experience.
|
||||
/// </summary>
|
||||
void ChangeExperienceGained(IPokemon faintedPokemon, IPokemon winningPokemon, ref uint amount);
|
||||
void ChangeExperienceGained(IBattlePokemon faintedPokemon, IBattlePokemon winningPokemon, ref uint amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1093,7 +1095,8 @@ public interface IScriptShareExperience
|
||||
/// and allows for making the experience be shared across multiple Pokemon.
|
||||
/// Amount is the modifier for how much experience is shared, with 1 being the default amount.
|
||||
/// </summary>
|
||||
void ShareExperience(IPokemon faintedPokemon, IPokemon winningPokemon, ref bool share, ref float amount);
|
||||
void ShareExperience(IBattlePokemon faintedPokemon, IBattlePokemon winningPokemon, ref bool share,
|
||||
ref float amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1117,7 +1120,7 @@ public interface IScriptChangeCatchRateBonus
|
||||
/// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
|
||||
/// example status effects that change capture rates.
|
||||
/// </summary>
|
||||
void ChangeCatchRateBonus(IPokemon pokemon, IItem pokeball, ref byte modifier);
|
||||
void ChangeCatchRateBonus(IBattlePokemon pokemon, IItem pokeball, ref byte modifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1142,7 +1145,7 @@ public interface IScriptChangeAccuracy
|
||||
/// A custom case goes when 255 is returned, in which case the entire accuracy check is skipped, and the move
|
||||
/// will always hit.
|
||||
/// </summary>
|
||||
void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy);
|
||||
void ChangeAccuracy(IExecutingMove executingMove, IBattlePokemon target, byte hitIndex, ref int modifiedAccuracy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1155,5 +1158,6 @@ public interface IScriptChangeIncomingAccuracy
|
||||
/// A custom case goes when 255 is returned, in which case the entire accuracy check is skipped, and the move
|
||||
/// will always hit.
|
||||
/// </summary>
|
||||
void ChangeIncomingAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy);
|
||||
void ChangeIncomingAccuracy(IExecutingMove executingMove, IBattlePokemon target, byte hitIndex,
|
||||
ref int modifiedAccuracy);
|
||||
}
|
||||
Reference in New Issue
Block a user