2024-08-10 09:18:10 +00:00
|
|
|
using PkmnLib.Static.Moves;
|
|
|
|
|
|
|
|
namespace PkmnLib.Dynamic.Models.BattleFlow;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Helper class for resolving the targets of a move.
|
|
|
|
/// </summary>
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
return target switch
|
|
|
|
{
|
|
|
|
MoveTarget.Adjacent or MoveTarget.AdjacentAlly or MoveTarget.AdjacentAllySelf or MoveTarget.AdjacentOpponent
|
|
|
|
or MoveTarget.Any or MoveTarget.RandomOpponent
|
|
|
|
or MoveTarget.SelfUse => [battle.GetPokemon(side, position)],
|
|
|
|
MoveTarget.All => GetAllTargets(battle),
|
|
|
|
MoveTarget.AllAdjacentOpponent => GetAllAdjacentAndOpponent(battle, side, position),
|
|
|
|
MoveTarget.AllAdjacent => GetAllAdjacent(battle, side, position),
|
|
|
|
MoveTarget.AllAlly => battle.Sides[side].Pokemon.ToList(),
|
|
|
|
MoveTarget.AllOpponent => battle.Sides[GetOppositeSide(side)].Pokemon.ToList(),
|
2024-08-23 07:24:00 +00:00
|
|
|
_ => throw new ArgumentOutOfRangeException(nameof(target), target, null),
|
2024-08-10 09:18:10 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-12-27 14:53:11 +00:00
|
|
|
/// <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)
|
|
|
|
{
|
|
|
|
var userBattleData = user.BattleData;
|
|
|
|
if (userBattleData == null)
|
|
|
|
throw new ArgumentNullException(nameof(user.BattleData));
|
|
|
|
var userSide = userBattleData.SideIndex;
|
|
|
|
var userPosition = userBattleData.Position;
|
|
|
|
|
|
|
|
switch (target)
|
|
|
|
{
|
|
|
|
case MoveTarget.Adjacent:
|
|
|
|
case MoveTarget.AllAdjacent:
|
|
|
|
{
|
|
|
|
var diff = Math.Abs(position - userPosition);
|
|
|
|
if (diff == 0)
|
|
|
|
return userSide == side;
|
|
|
|
return diff <= 1;
|
|
|
|
}
|
|
|
|
case MoveTarget.AdjacentAlly:
|
|
|
|
{
|
|
|
|
if (userSide != side)
|
|
|
|
return false;
|
|
|
|
return Math.Abs(position - userPosition) == 1;
|
|
|
|
}
|
|
|
|
case MoveTarget.AdjacentAllySelf:
|
|
|
|
{
|
|
|
|
if (userSide != side)
|
|
|
|
return false;
|
|
|
|
return Math.Abs(position - userPosition) <= 1;
|
|
|
|
}
|
|
|
|
case MoveTarget.AdjacentOpponent:
|
|
|
|
case MoveTarget.AllAdjacentOpponent:
|
|
|
|
{
|
|
|
|
if (userSide == side)
|
|
|
|
return false;
|
|
|
|
return Math.Abs(position - userPosition) <= 1;
|
|
|
|
}
|
|
|
|
case MoveTarget.All:
|
|
|
|
case MoveTarget.Any:
|
|
|
|
case MoveTarget.RandomOpponent:
|
|
|
|
return true;
|
|
|
|
case MoveTarget.AllAlly:
|
|
|
|
return userSide == side;
|
|
|
|
case MoveTarget.AllOpponent:
|
|
|
|
return userSide != side;
|
|
|
|
case MoveTarget.SelfUse:
|
|
|
|
return userSide == side && userPosition == position;
|
|
|
|
}
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(target), target, null);
|
|
|
|
}
|
|
|
|
|
2024-08-10 09:18:10 +00:00
|
|
|
private static IReadOnlyList<IPokemon?> GetAllTargets(IBattle battle) =>
|
|
|
|
battle.Sides.SelectMany(x => x.Pokemon).ToList();
|
|
|
|
|
|
|
|
private static byte GetOppositeSide(byte side) => side == 0 ? (byte)1 : (byte)0;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 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)
|
|
|
|
{
|
|
|
|
var left = position - 1;
|
|
|
|
var right = position + 1;
|
|
|
|
if (left < 0 && right >= battle.PositionsPerSide)
|
|
|
|
{
|
|
|
|
return [battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position)];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (left < 0)
|
|
|
|
{
|
|
|
|
return
|
|
|
|
[
|
|
|
|
battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position),
|
2024-08-23 07:24:00 +00:00
|
|
|
battle.GetPokemon(side, (byte)right),
|
2024-08-10 09:18:10 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (right >= battle.PositionsPerSide)
|
|
|
|
{
|
|
|
|
return
|
|
|
|
[
|
|
|
|
battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position),
|
2024-08-23 07:24:00 +00:00
|
|
|
battle.GetPokemon(side, (byte)left),
|
2024-08-10 09:18:10 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
[
|
|
|
|
battle.GetPokemon(side, position), battle.GetPokemon(GetOppositeSide(side), position),
|
2024-08-23 07:24:00 +00:00
|
|
|
battle.GetPokemon(side, (byte)left), battle.GetPokemon(side, (byte)right),
|
2024-08-10 09:18:10 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
private static IReadOnlyList<IPokemon?> GetAllAdjacent(IBattle battle, byte side, byte position)
|
|
|
|
{
|
|
|
|
var left = position - 1;
|
|
|
|
var right = position + 1;
|
|
|
|
if (left < 0 && right >= battle.PositionsPerSide)
|
|
|
|
{
|
|
|
|
return [battle.GetPokemon(side, position)];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (left < 0)
|
|
|
|
{
|
|
|
|
return [battle.GetPokemon(side, position), battle.GetPokemon(side, (byte)right)];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (right >= battle.PositionsPerSide)
|
|
|
|
{
|
|
|
|
return [battle.GetPokemon(side, position), battle.GetPokemon(side, (byte)left)];
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
[
|
2024-08-23 07:24:00 +00:00
|
|
|
battle.GetPokemon(side, position), battle.GetPokemon(side, (byte)left), battle.GetPokemon(side, (byte)right),
|
2024-08-10 09:18:10 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|