/// <summary> /// Determines whether chosen actions are valid. /// </summary> /// <param name="team">The team the inputted actions belong to.</param> /// <param name="actions">The actions the team wishes to execute.</param> /// <returns>False if the team already chose actions or the actions are illegal, True otherwise.</returns> /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForActions"/>.</exception> public static bool AreActionsValid(PBETeam team, IEnumerable <PBEAction> actions) { if (team.Battle.BattleState != PBEBattleState.WaitingForActions) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} to validate actions."); } if (team.ActionsRequired.Count == 0 || actions.Count() != team.ActionsRequired.Count) { return(false); } var standBy = new List <PBEPokemon>(); foreach (PBEAction action in actions) { PBEPokemon pkmn = team.TryGetPokemon(action.PokemonId); if (!team.ActionsRequired.Contains(pkmn)) { return(false); } switch (action.Decision) { case PBEDecision.Fight: { if (Array.IndexOf(pkmn.GetUsableMoves(), action.FightMove) == -1 || (action.FightMove == pkmn.TempLockedMove && action.FightTargets != pkmn.TempLockedTargets) || !AreTargetsValid(pkmn, action.FightMove, action.FightTargets) ) { return(false); } break; } case PBEDecision.SwitchOut: { if (!pkmn.CanSwitchOut()) { return(false); } PBEPokemon switchPkmn = team.TryGetPokemon(action.SwitchPokemonId); if (switchPkmn == null || switchPkmn.HP == 0 || switchPkmn.FieldPosition != PBEFieldPosition.None || // Also takes care of trying to switch into yourself standBy.Contains(switchPkmn) ) { return(false); } else { standBy.Add(switchPkmn); } break; } } } return(true); }
/// <summary>Selects switches if they are valid. Changes the battle state if both teams have selected valid switches.</summary> /// <param name="team">The team the inputted switches belong to.</param> /// <param name="switches">The switches the team wishes to execute.</param> /// <returns>True if the switches are valid and were selected.</returns> /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForSwitchIns"/>.</exception> public static bool SelectSwitchesIfValid(PBETeam team, IList <PBESwitchIn> switches) { if (AreSwitchesValid(team, switches)) { lock (team.Battle._disposeLockObj) { if (!team.Battle.IsDisposed) { team.SwitchInsRequired = 0; foreach (PBESwitchIn s in switches) { PBEPokemon pkmn = team.TryGetPokemon(s.PokemonId); pkmn.FieldPosition = s.Position; team.SwitchInQueue.Add(pkmn); } if (team.Battle.Teams.All(t => t.SwitchInsRequired == 0)) { team.Battle.SwitchesOrActions(); } return(true); } } } return(false); }
/// <summary>Determines whether chosen switches are valid.</summary> /// <param name="team">The team the inputted switches belong to.</param> /// <param name="switches">The switches the team wishes to execute.</param> /// <returns>False if the team already chose switches or the switches are illegal, True otherwise.</returns> /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForSwitchIns"/>.</exception> public static bool AreSwitchesValid(PBETeam team, IList <PBESwitchIn> switches) { if (team == null) { throw new ArgumentNullException(nameof(team)); } if (switches == null || switches.Any(s => s == null)) { throw new ArgumentNullException(nameof(switches)); } if (team.IsDisposed) { throw new ObjectDisposedException(nameof(team)); } if (team.Battle.BattleState != PBEBattleState.WaitingForSwitchIns) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForSwitchIns} to validate switches."); } if (team.SwitchInsRequired == 0 || switches.Count != team.SwitchInsRequired) { return(false); } var verified = new List <PBEPokemon>(team.SwitchInsRequired); foreach (PBESwitchIn s in switches) { PBEPokemon pkmn = team.TryGetPokemon(s.PokemonId); if (pkmn == null || pkmn.HP == 0 || pkmn.FieldPosition != PBEFieldPosition.None || verified.Contains(pkmn)) { return(false); } verified.Add(pkmn); } return(true); }
/// <summary>Selects switches if they are valid. Changes the battle state if both teams have selected valid switches.</summary> /// <param name="team">The team the inputted switches belong to.</param> /// <param name="switches">The switches the team wishes to execute.</param> /// <returns>True if the switches are valid and were selected.</returns> /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForSwitchIns"/>.</exception> public static bool SelectSwitchesIfValid(PBETeam team, IList <PBESwitchIn> switches) { if (team == null) { throw new ArgumentNullException(nameof(team)); } if (switches == null) { throw new ArgumentNullException(nameof(switches)); } if (team.IsDisposed) { throw new ObjectDisposedException(nameof(team)); } if (team.Battle.BattleState != PBEBattleState.WaitingForSwitchIns) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForSwitchIns} to select switches."); } if (AreSwitchesValid(team, switches)) { lock (team.Battle._disposeLockObj) { if (!team.Battle.IsDisposed) { team.SwitchInsRequired = 0; foreach (PBESwitchIn s in switches) { PBEPokemon pkmn = team.TryGetPokemon(s.PokemonId); pkmn.FieldPosition = s.Position; team.SwitchInQueue.Add(pkmn); } if (team.Battle.Teams.All(t => t.SwitchInsRequired == 0)) { team.Battle.SwitchesOrActions(); } return(true); } } } return(false); }
/// <summary>Selects actions if they are valid. Changes the battle state if both teams have selected valid actions.</summary> /// <param name="trainer">The trainer the inputted actions belong to.</param> /// <param name="actions">The actions the team wishes to execute.</param> /// <returns>True if the actions are valid and were selected.</returns> /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForActions"/>.</exception> public static bool SelectActionsIfValid(PBETrainer trainer, IReadOnlyList <PBETurnAction> actions) { if (AreActionsValid(trainer, actions)) { trainer.ActionsRequired.Clear(); foreach (PBETurnAction action in actions) { PBEBattlePokemon pkmn = trainer.TryGetPokemon(action.PokemonId); if (action.Decision == PBETurnDecision.Fight && pkmn.GetMoveTargets(action.FightMove) == PBEMoveTarget.RandomFoeSurrounding) { switch (trainer.Battle.BattleFormat) { case PBEBattleFormat.Single: case PBEBattleFormat.Rotation: { action.FightTargets = PBETurnTarget.FoeCenter; break; } case PBEBattleFormat.Double: { action.FightTargets = PBERandom.RandomBool() ? PBETurnTarget.FoeLeft : PBETurnTarget.FoeRight; break; } case PBEBattleFormat.Triple: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { action.FightTargets = PBERandom.RandomBool() ? PBETurnTarget.FoeCenter : PBETurnTarget.FoeRight; } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { PBETeam oppTeam = trainer.Team.OpposingTeam; int r; // Keep randomly picking until a non-fainted foe is selected roll: r = PBERandom.RandomInt(0, 2); if (r == 0) { if (oppTeam.TryGetPokemon(PBEFieldPosition.Left) != null) { action.FightTargets = PBETurnTarget.FoeLeft; } else { goto roll; } } else if (r == 1) { if (oppTeam.TryGetPokemon(PBEFieldPosition.Center) != null) { action.FightTargets = PBETurnTarget.FoeCenter; } else { goto roll; } } else { if (oppTeam.TryGetPokemon(PBEFieldPosition.Right) != null) { action.FightTargets = PBETurnTarget.FoeRight; } else { goto roll; } } } else { action.FightTargets = PBERandom.RandomBool() ? PBETurnTarget.FoeLeft : PBETurnTarget.FoeCenter; } break; } default: throw new ArgumentOutOfRangeException(nameof(trainer.Battle.BattleFormat)); } } pkmn.TurnAction = action; } if (trainer.Battle.Trainers.All(t => t.ActionsRequired.Count == 0)) { trainer.Battle.BattleState = PBEBattleState.ReadyToRunTurn; trainer.Battle.OnStateChanged?.Invoke(trainer.Battle); } return(true); } return(false); }
/// <summary>Selects actions if they are valid. Changes the battle state if both teams have selected valid actions.</summary> /// <param name="team">The team the inputted actions belong to.</param> /// <param name="actions">The actions the team wishes to execute.</param> /// <returns>True if the actions are valid and were selected.</returns> /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForActions"/>.</exception> public static bool SelectActionsIfValid(PBETeam team, IList <PBETurnAction> actions) { if (team == null) { throw new ArgumentNullException(nameof(team)); } if (actions == null) { throw new ArgumentNullException(nameof(actions)); } if (team.IsDisposed) { throw new ObjectDisposedException(nameof(team)); } if (team.Battle.BattleState != PBEBattleState.WaitingForActions) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} to select actions."); } if (AreActionsValid(team, actions)) { lock (team.Battle._disposeLockObj) { if (!team.Battle.IsDisposed) { team.ActionsRequired.Clear(); foreach (PBETurnAction action in actions) { PBEPokemon pkmn = team.TryGetPokemon(action.PokemonId); if (action.Decision == PBETurnDecision.Fight && pkmn.GetMoveTargets(action.FightMove) == PBEMoveTarget.RandomFoeSurrounding) { switch (team.Battle.BattleFormat) { case PBEBattleFormat.Single: case PBEBattleFormat.Rotation: { action.FightTargets = PBETurnTarget.FoeCenter; break; } case PBEBattleFormat.Double: { action.FightTargets = PBEUtils.RandomBool() ? PBETurnTarget.FoeLeft : PBETurnTarget.FoeRight; break; } case PBEBattleFormat.Triple: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { action.FightTargets = PBEUtils.RandomBool() ? PBETurnTarget.FoeCenter : PBETurnTarget.FoeRight; } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { int r; // Keep randomly picking until a non-fainted foe is selected roll: r = PBEUtils.RandomInt(0, 2); if (r == 0) { if (team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Left) != null) { action.FightTargets = PBETurnTarget.FoeLeft; } else { goto roll; } } else if (r == 1) { if (team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Center) != null) { action.FightTargets = PBETurnTarget.FoeCenter; } else { goto roll; } } else { if (team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Right) != null) { action.FightTargets = PBETurnTarget.FoeRight; } else { goto roll; } } } else { action.FightTargets = PBEUtils.RandomBool() ? PBETurnTarget.FoeLeft : PBETurnTarget.FoeCenter; } break; } default: throw new ArgumentOutOfRangeException(nameof(team.Battle.BattleFormat)); } } pkmn.TurnAction = action; } if (team.Battle.Teams.All(t => t.ActionsRequired.Count == 0)) { team.Battle.BattleState = PBEBattleState.ReadyToRunTurn; team.Battle.OnStateChanged?.Invoke(team.Battle); } return(true); } } } return(false); }
/// <summary> /// Selects actions if they are valid. Changes the battle state if both teams have selected valid actions. /// </summary> /// <param name="team">The team the inputted actions belong to.</param> /// <param name="actions">The actions the team wishes to execute.</param> /// <returns>True if the actions are valid and were selected.</returns> /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForActions"/>.</exception> public static bool SelectActionsIfValid(PBETeam team, IEnumerable <PBEAction> actions) { if (team.Battle.BattleState != PBEBattleState.WaitingForActions) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} to select actions."); } if (AreActionsValid(team, actions)) { team.ActionsRequired.Clear(); foreach (PBEAction action in actions) { PBEPokemon pkmn = team.Battle.TryGetPokemon(action.PokemonId); pkmn.SelectedAction = action; switch (pkmn.SelectedAction.Decision) { case PBEDecision.Fight: { switch (pkmn.GetMoveTargets(pkmn.SelectedAction.FightMove)) { case PBEMoveTarget.RandomFoeSurrounding: { switch (team.Battle.BattleFormat) { case PBEBattleFormat.Single: case PBEBattleFormat.Rotation: { pkmn.SelectedAction.FightTargets = PBETarget.FoeCenter; break; } case PBEBattleFormat.Double: { pkmn.SelectedAction.FightTargets = PBEUtils.RNG.NextBoolean() ? PBETarget.FoeLeft : PBETarget.FoeRight; break; } case PBEBattleFormat.Triple: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { pkmn.SelectedAction.FightTargets = PBEUtils.RNG.NextBoolean() ? PBETarget.FoeCenter : PBETarget.FoeRight; } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { PBETeam opposingTeam = team == team.Battle.Teams[0] ? team.Battle.Teams[1] : team.Battle.Teams[0]; int r; // Keep randomly picking until a non-fainted foe is selected roll: r = PBEUtils.RNG.Next(3); if (r == 0) { if (opposingTeam.TryGetPokemon(PBEFieldPosition.Left) != null) { pkmn.SelectedAction.FightTargets = PBETarget.FoeLeft; } else { goto roll; } } else if (r == 1) { if (opposingTeam.TryGetPokemon(PBEFieldPosition.Center) != null) { pkmn.SelectedAction.FightTargets = PBETarget.FoeCenter; } else { goto roll; } } else { if (opposingTeam.TryGetPokemon(PBEFieldPosition.Right) != null) { pkmn.SelectedAction.FightTargets = PBETarget.FoeRight; } else { goto roll; } } } else { pkmn.SelectedAction.FightTargets = PBEUtils.RNG.NextBoolean() ? PBETarget.FoeLeft : PBETarget.FoeCenter; } break; } } break; } case PBEMoveTarget.SingleAllySurrounding: { if (team.Battle.BattleFormat == PBEBattleFormat.Single || team.Battle.BattleFormat == PBEBattleFormat.Rotation) { pkmn.SelectedAction.FightTargets = PBETarget.AllyCenter; } break; } } break; } } } if (team.Battle.Teams.All(t => t.ActionsRequired.Count == 0)) { team.Battle.BattleState = PBEBattleState.ReadyToRunTurn; team.Battle.OnStateChanged?.Invoke(team.Battle); } return(true); } return(false); }
/// <summary> /// Gets all Pokémon that will be hit. /// </summary> /// <param name="user">The Pokémon that will act.</param> /// <param name="requestedTargets">The targets the Pokémon wishes to hit.</param> /// <param name="canHitFarCorners">Whether the move can hit far Pokémon in a triple battle.</param> static PBEPokemon[] GetRuntimeTargets(PBEPokemon user, PBETarget requestedTargets, bool canHitFarCorners) { PBETeam opposingTeam = user.Team == user.Team.Battle.Teams[0] ? user.Team.Battle.Teams[1] : user.Team.Battle.Teams[0]; var targets = new List <PBEPokemon>(); if (requestedTargets.HasFlag(PBETarget.AllyLeft)) { targets.Add(user.Team.TryGetPokemon(PBEFieldPosition.Left)); } if (requestedTargets.HasFlag(PBETarget.AllyCenter)) { targets.Add(user.Team.TryGetPokemon(PBEFieldPosition.Center)); } if (requestedTargets.HasFlag(PBETarget.AllyRight)) { targets.Add(user.Team.TryGetPokemon(PBEFieldPosition.Right)); } if (requestedTargets.HasFlag(PBETarget.FoeLeft)) { PBEPokemon pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Left); if (pkmn == null) { if (user.Team.Battle.BattleFormat == PBEBattleFormat.Double) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Right); } else if (user.Team.Battle.BattleFormat == PBEBattleFormat.Triple) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Center); // Center fainted as well and user can reach far right if (pkmn == null && (user.FieldPosition != PBEFieldPosition.Right || canHitFarCorners)) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Right); } } } targets.Add(pkmn); } if (requestedTargets.HasFlag(PBETarget.FoeCenter)) { PBEPokemon pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Center); // Target fainted, fallback to its teammate if (pkmn == null) { if (user.Team.Battle.BattleFormat == PBEBattleFormat.Triple) { if (user.FieldPosition == PBEFieldPosition.Left) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Right); // Right fainted as well and user can reach far left if (pkmn == null && (user.FieldPosition != PBEFieldPosition.Left || canHitFarCorners)) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Left); } } else if (user.FieldPosition == PBEFieldPosition.Right) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Left); // Left fainted as well and user can reach far right if (pkmn == null && (user.FieldPosition != PBEFieldPosition.Right || canHitFarCorners)) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Right); } } else // Center { PBEPokemon oppLeft = opposingTeam.TryGetPokemon(PBEFieldPosition.Left), oppRight = opposingTeam.TryGetPokemon(PBEFieldPosition.Right); // Left is dead but not right if (oppLeft == null && oppRight != null) { pkmn = oppRight; } // Right is dead but not left else if (oppLeft != null && oppRight == null) { pkmn = oppLeft; } // Randomly select left or right else { pkmn = PBEUtils.RNG.NextBoolean() ? oppLeft : oppRight; } } } } targets.Add(pkmn); } if (requestedTargets.HasFlag(PBETarget.FoeRight)) { PBEPokemon pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Right); // Target fainted, fallback to its teammate if (pkmn == null) { if (user.Team.Battle.BattleFormat == PBEBattleFormat.Double) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Left); } else if (user.Team.Battle.BattleFormat == PBEBattleFormat.Triple) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Center); // Center fainted as well and user can reach far left if (pkmn == null && (user.FieldPosition != PBEFieldPosition.Left || canHitFarCorners)) { pkmn = opposingTeam.TryGetPokemon(PBEFieldPosition.Left); } } } targets.Add(pkmn); } return(targets.Where(p => p != null).Distinct().ToArray()); // Remove duplicate targets }