private void SelectMoveForTurn(PBEMove move) { PBEBattlePokemon pkmn = _pkmn.Pkmn; PBEMoveTarget possibleTargets = pkmn.GetMoveTargets(move); // Single battle only PBETurnTarget targets; switch (possibleTargets) { case PBEMoveTarget.All: targets = PBETurnTarget.AllyCenter | PBETurnTarget.FoeCenter; break; case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: case PBEMoveTarget.AllSurrounding: case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.SingleFoeSurrounding: case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: targets = PBETurnTarget.FoeCenter; break; case PBEMoveTarget.AllTeam: case PBEMoveTarget.Self: case PBEMoveTarget.SelfOrAllySurrounding: case PBEMoveTarget.SingleAllySurrounding: targets = PBETurnTarget.AllyCenter; break; default: throw new ArgumentOutOfRangeException(nameof(possibleTargets)); } pkmn.TurnAction = new PBETurnAction(pkmn, move, targets); _parent.ActionsLoop(false); }
private PBEMoveData(PBEType type, PBEMoveCategory category, sbyte priority, byte ppTier, byte power, byte accuracy, PBEMoveEffect effect, int effectParam, PBEMoveTarget targets, PBEMoveFlag flags) { Type = type; Category = category; Priority = priority; PPTier = ppTier; Power = power; Accuracy = accuracy; Effect = effect; EffectParam = effectParam; Targets = targets; Flags = flags; }
public static bool IsSpreadMove(PBEMoveTarget targets) { switch (targets) { case PBEMoveTarget.All: case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: case PBEMoveTarget.AllSurrounding: case PBEMoveTarget.AllTeam: return(true); default: return(false); } }
private unsafe void SelectMoveForTurn(PBEMove move) { PBEMoveTarget possibleTargets = _pkmn.GetMoveTargets(move); if (_pkmn.Battle.BattleFormat == PBEBattleFormat.Single || _pkmn.Battle.BattleFormat == PBEBattleFormat.Rotation) { PBETurnTarget targets; switch (possibleTargets) { case PBEMoveTarget.All: targets = PBETurnTarget.AllyCenter | PBETurnTarget.FoeCenter; break; case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: case PBEMoveTarget.AllSurrounding: case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.SingleFoeSurrounding: case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: targets = PBETurnTarget.FoeCenter; break; case PBEMoveTarget.AllTeam: case PBEMoveTarget.Self: case PBEMoveTarget.SelfOrAllySurrounding: case PBEMoveTarget.SingleAllySurrounding: targets = PBETurnTarget.AllyCenter; break; default: throw new Exception(); } _pkmn.TurnAction = new PBETurnAction(_pkmn, move, targets); BattleGUI.Instance.ActionsLoop(false); } else // Double / Triple { void TargetSelected() { BattleGUI.Instance.ActionsLoop(false); _targetsGUI = null; // no need to change callbacks since this'll get disposed in actionsloop } void TargetCancelled() { _targetsGUI = null; SetCallbacksForMoves(); } _targetsGUI = new TargetsGUI(_pkmn, possibleTargets, move, BattleGUI.Instance.SpritedParties, TargetSelected, TargetCancelled); Game.Instance.SetCallback(CB_Targets); Game.Instance.SetRCallback(RCB_Targets); } }
/// <summary>Creates valid actions for a battle turn for a specific team.</summary> /// <param name="team">The team to create actions for.</param> /// <exception cref="InvalidOperationException">Thrown when <paramref name="team"/> has no active battlers or <paramref name="team"/>'s <see cref="PBETeam.Battle"/>'s <see cref="PBEBattle.BattleState"/> is not <see cref="PBEBattleState.WaitingForActions"/>.</exception> /// <exception cref="ArgumentOutOfRangeException">Thrown when a Pokémon has no moves, the AI tries to use a move with invalid targets, or <paramref name="team"/>'s <see cref="PBETeam.Battle"/>'s <see cref="PBEBattle.BattleFormat"/> is invalid.</exception> public static PBETurnAction[] CreateActions(PBETeam team) { if (team == null) { throw new ArgumentNullException(nameof(team)); } if (team.IsDisposed) { throw new ObjectDisposedException(nameof(team)); } if (team.Battle.BattleState != PBEBattleState.WaitingForActions) { throw new InvalidOperationException($"{nameof(team.Battle.BattleState)} must be {PBEBattleState.WaitingForActions} to create actions."); } var actions = new PBETurnAction[team.ActionsRequired.Count]; var standBy = new List <PBEPokemon>(); for (int i = 0; i < actions.Length; i++) { PBEPokemon user = team.ActionsRequired[i]; // If a Pokémon is forced to struggle, it is best that it just stays in until it faints if (user.IsForcedToStruggle()) { actions[i] = new PBETurnAction(user.Id, PBEMove.Struggle, GetPossibleTargets(user, user.GetMoveTargets(PBEMove.Struggle))[0]); } // If a Pokémon has a temp locked move (Dig, Dive, Shadow Force) it must be used else if (user.TempLockedMove != PBEMove.None) { actions[i] = new PBETurnAction(user.Id, user.TempLockedMove, user.TempLockedTargets); } // The Pokémon is free to switch or fight (unless it cannot switch due to Magnet Pull etc) else { // Gather all options of switching and moves PBEPokemon[] availableForSwitch = team.Party.Except(standBy).Where(p => p.FieldPosition == PBEFieldPosition.None && p.HP > 0).ToArray(); PBEMove[] usableMoves = user.GetUsableMoves(); var possibleActions = new List <(PBETurnAction Action, double Score)>(); for (int m = 0; m < usableMoves.Length; m++) // Score moves { PBEMove move = usableMoves[m]; PBEType moveType = user.GetMoveType(move); PBEMoveTarget moveTargets = user.GetMoveTargets(move); PBETurnTarget[] possibleTargets = PBEMoveData.IsSpreadMove(moveTargets) ? new PBETurnTarget[] { GetSpreadMoveTargets(user, moveTargets) } : GetPossibleTargets(user, moveTargets); foreach (PBETurnTarget possibleTarget in possibleTargets) { // TODO: RandomFoeSurrounding (probably just account for the specific effects that use this target type) // TODO: Don't queue up to do the same thing (two trying to afflict the same target when there are multiple targets) var targets = new List <PBEPokemon>(); if (possibleTarget.HasFlag(PBETurnTarget.AllyLeft)) { targets.Add(team.TryGetPokemon(PBEFieldPosition.Left)); } if (possibleTarget.HasFlag(PBETurnTarget.AllyCenter)) { targets.Add(team.TryGetPokemon(PBEFieldPosition.Center)); } if (possibleTarget.HasFlag(PBETurnTarget.AllyRight)) { targets.Add(team.TryGetPokemon(PBEFieldPosition.Right)); } if (possibleTarget.HasFlag(PBETurnTarget.FoeLeft)) { targets.Add(team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Left)); } if (possibleTarget.HasFlag(PBETurnTarget.FoeCenter)) { targets.Add(team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Center)); } if (possibleTarget.HasFlag(PBETurnTarget.FoeRight)) { targets.Add(team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Right)); } double score; if (targets.All(p => p == null)) { score = -100; } else { score = 0d; targets.RemoveAll(p => p == null); PBEMoveData mData = PBEMoveData.Data[move]; switch (mData.Effect) { case PBEMoveEffect.Attract: { foreach (PBEPokemon target in targets) { // TODO: Destiny knot if (target.IsAttractionPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == team ? -20 : +40; } else { score += target.Team == team ? 0 : -60; } } break; } case PBEMoveEffect.BrickBreak: case PBEMoveEffect.Dig: case PBEMoveEffect.Dive: case PBEMoveEffect.Fly: case PBEMoveEffect.Hit: case PBEMoveEffect.Hit__MaybeBurn: case PBEMoveEffect.Hit__MaybeBurn__10PercentFlinch: case PBEMoveEffect.Hit__MaybeConfuse: case PBEMoveEffect.Hit__MaybeFlinch: case PBEMoveEffect.Hit__MaybeFreeze: case PBEMoveEffect.Hit__MaybeFreeze__10PercentFlinch: case PBEMoveEffect.Hit__MaybeLowerTarget_ACC_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_ATK_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_DEF_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_SPATK_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_SPDEF_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_SPDEF_By2: case PBEMoveEffect.Hit__MaybeLowerTarget_SPE_By1: case PBEMoveEffect.Hit__MaybeLowerUser_ATK_DEF_By1: case PBEMoveEffect.Hit__MaybeLowerUser_DEF_SPDEF_By1: case PBEMoveEffect.Hit__MaybeLowerUser_SPATK_By2: case PBEMoveEffect.Hit__MaybeLowerUser_SPE_By1: case PBEMoveEffect.Hit__MaybeLowerUser_SPE_DEF_SPDEF_By1: case PBEMoveEffect.Hit__MaybeParalyze: case PBEMoveEffect.Hit__MaybeParalyze__10PercentFlinch: case PBEMoveEffect.Hit__MaybePoison: case PBEMoveEffect.Hit__MaybeRaiseUser_ATK_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_ATK_DEF_SPATK_SPDEF_SPE_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_DEF_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_SPATK_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_SPE_By1: case PBEMoveEffect.Hit__MaybeToxic: case PBEMoveEffect.HPDrain: case PBEMoveEffect.Recoil: case PBEMoveEffect.Recoil__10PercentBurn: case PBEMoveEffect.Recoil__10PercentParalyze: case PBEMoveEffect.SuckerPunch: { foreach (PBEPokemon target in targets) { // TODO: Favor hitting ally with move if waterabsorb/voltabsorb etc // TODO: Liquid ooze // TODO: Check items // TODO: Stat changes and accuracy (even thunder/guillotine accuracy) // TODO: Check base power specifically against hp remaining (include spread move damage reduction) target.IsAffectedByMove(user, moveType, out double damageMultiplier, useKnownInfo: true); if (damageMultiplier <= 0) // (-infinity, 0.0] Ineffective { score += target.Team == team ? 0 : -60; } else if (damageMultiplier <= 0.25) // (0.0, 0.25] NotVeryEffective { score += target.Team == team ? -5 : -30; } else if (damageMultiplier < 1) // (0.25, 1.0) NotVeryEffective { score += target.Team == team ? -10 : -10; } else if (damageMultiplier == 1) // [1.0, 1.0] Normal { score += target.Team == team ? -15 : +10; } else if (damageMultiplier < 4) // (1.0, 4.0) SuperEffective { score += target.Team == team ? -20 : +25; } else // [4.0, infinity) SuperEffective { score += target.Team == team ? -30 : +40; } if (user.HasType(moveType) && damageMultiplier > 0) // STAB { score += (user.Ability == PBEAbility.Adaptability ? 7 : 5) * (target.Team == team ? -1 : +1); } } break; } case PBEMoveEffect.Burn: { foreach (PBEPokemon target in targets) { // TODO: Heatproof, physical attacker if (target.IsBurnPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == team ? -20 : +40; } else { score += target.Team == team ? 0 : -60; } } break; } case PBEMoveEffect.ChangeTarget_ACC: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Accuracy, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_ATK: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_DEF: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Defense, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_EVA: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Evasion, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_SPATK: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.SpAttack, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_SPDEF: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.SpDefense, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_SPE: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Speed, mData.EffectParam, ref score); } break; } case PBEMoveEffect.Confuse: case PBEMoveEffect.Flatter: case PBEMoveEffect.Swagger: { foreach (PBEPokemon target in targets) { // TODO: Only swagger/flatter if the opponent most likely won't use it against you if (target.IsConfusionPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == team ? -20 : +40; } else { score += target.Team == team ? 0 : -60; } } break; } case PBEMoveEffect.Growth: { int change = team.Battle.WillLeafGuardActivate() ? +2 : +1; foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, change, ref score); ScoreStatChange(user, target, PBEStat.SpAttack, change, ref score); } break; } case PBEMoveEffect.LeechSeed: { foreach (PBEPokemon target in targets) { if (target.IsLeechSeedPossible(useKnownInfo: true) == PBEResult.Success) { score += target.Team == team ? -20 : +40; } else { score += target.Team == team ? 0 : -60; } } break; } case PBEMoveEffect.LightScreen: { score += team.TeamStatus.HasFlag(PBETeamStatus.LightScreen) || IsTeammateUsingEffect(actions, PBEMoveEffect.LightScreen) ? -100 : +40; break; } case PBEMoveEffect.LowerTarget_ATK_DEF_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, -1, ref score); ScoreStatChange(user, target, PBEStat.Defense, -1, ref score); } break; } case PBEMoveEffect.LowerTarget_DEF_SPDEF_By1_Raise_ATK_SPATK_SPE_By2: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Defense, -1, ref score); ScoreStatChange(user, target, PBEStat.SpDefense, -1, ref score); ScoreStatChange(user, target, PBEStat.Attack, +2, ref score); ScoreStatChange(user, target, PBEStat.SpAttack, +2, ref score); ScoreStatChange(user, target, PBEStat.Speed, +2, ref score); } break; } case PBEMoveEffect.LuckyChant: { score += team.TeamStatus.HasFlag(PBETeamStatus.LuckyChant) || IsTeammateUsingEffect(actions, PBEMoveEffect.LuckyChant) ? -100 : +40; break; } case PBEMoveEffect.Moonlight: case PBEMoveEffect.Rest: case PBEMoveEffect.RestoreTargetHP: { foreach (PBEPokemon target in targets) { if (target.Team == team) { score += HPAware(target.HPPercentage, +45, -15); } else { score -= 100; } } break; } case PBEMoveEffect.Nothing: case PBEMoveEffect.Teleport: { score -= 100; break; } case PBEMoveEffect.Paralyze: { foreach (PBEPokemon target in targets) { // TODO: Effectiveness with thunder wave/glare if (target.IsParalysisPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == team ? -20 : +40; } else { score += target.Team == team ? 0 : -60; } } break; } case PBEMoveEffect.Poison: case PBEMoveEffect.Toxic: { foreach (PBEPokemon target in targets) { // TODO: Poison Heal if (target.IsPoisonPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == team ? -20 : +40; } else { score += target.Team == team ? 0 : -60; } } break; } case PBEMoveEffect.RaiseTarget_ATK_ACC_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.Accuracy, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_ATK_DEF_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.Defense, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_ATK_DEF_ACC_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.Defense, +1, ref score); ScoreStatChange(user, target, PBEStat.Accuracy, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_ATK_SPATK_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.SpAttack, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_ATK_SPE_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.Speed, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_DEF_SPDEF_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Defense, +1, ref score); ScoreStatChange(user, target, PBEStat.SpDefense, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_SPATK_SPDEF_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.SpAttack, +1, ref score); ScoreStatChange(user, target, PBEStat.SpDefense, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_SPATK_SPDEF_SPE_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.SpAttack, +1, ref score); ScoreStatChange(user, target, PBEStat.SpDefense, +1, ref score); ScoreStatChange(user, target, PBEStat.Speed, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_SPE_By2_ATK_By1: { foreach (PBEPokemon target in targets) { ScoreStatChange(user, target, PBEStat.Speed, +2, ref score); ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); } break; } case PBEMoveEffect.Reflect: { score += team.TeamStatus.HasFlag(PBETeamStatus.Reflect) || IsTeammateUsingEffect(actions, PBEMoveEffect.Reflect) ? -100 : +40; break; } case PBEMoveEffect.Safeguard: { score += team.TeamStatus.HasFlag(PBETeamStatus.Safeguard) || IsTeammateUsingEffect(actions, PBEMoveEffect.Safeguard) ? -100 : +40; break; } case PBEMoveEffect.Sleep: { foreach (PBEPokemon target in targets) { // TODO: Bad Dreams if (target.IsSleepPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == team ? -20 : +40; } else { score += target.Team == team ? 0 : -60; } } break; } case PBEMoveEffect.Substitute: { foreach (PBEPokemon target in targets) { if (target.IsSubstitutePossible() == PBEResult.Success) { score += target.Team == team?HPAware(target.HPPercentage, -30, +50) : -60; } else { score += target.Team == team ? 0 : -20; } } break; } case PBEMoveEffect.ChangeTarget_SPATK__IfAttractionPossible: case PBEMoveEffect.Conversion: case PBEMoveEffect.Curse: case PBEMoveEffect.Endeavor: case PBEMoveEffect.FinalGambit: case PBEMoveEffect.FocusEnergy: case PBEMoveEffect.GastroAcid: case PBEMoveEffect.Hail: case PBEMoveEffect.Haze: case PBEMoveEffect.HelpingHand: case PBEMoveEffect.HPDrain__RequireSleep: case PBEMoveEffect.MagnetRise: case PBEMoveEffect.Metronome: case PBEMoveEffect.OneHitKnockout: case PBEMoveEffect.PainSplit: case PBEMoveEffect.PowerTrick: case PBEMoveEffect.Protect: case PBEMoveEffect.PsychUp: case PBEMoveEffect.Psywave: case PBEMoveEffect.RainDance: case PBEMoveEffect.Sandstorm: case PBEMoveEffect.SeismicToss: case PBEMoveEffect.Selfdestruct: case PBEMoveEffect.SetDamage: case PBEMoveEffect.SimpleBeam: case PBEMoveEffect.Snore: case PBEMoveEffect.Soak: case PBEMoveEffect.Spikes: case PBEMoveEffect.StealthRock: case PBEMoveEffect.SunnyDay: case PBEMoveEffect.SuperFang: case PBEMoveEffect.Tailwind: case PBEMoveEffect.ToxicSpikes: case PBEMoveEffect.Transform: case PBEMoveEffect.TrickRoom: case PBEMoveEffect.Whirlwind: case PBEMoveEffect.WideGuard: { // TODO Moves break; } default: throw new ArgumentOutOfRangeException(nameof(PBEMoveData.Effect)); } } possibleActions.Add((new PBETurnAction(user.Id, move, possibleTarget), score)); } } if (user.CanSwitchOut()) { for (int s = 0; s < availableForSwitch.Length; s++) // Score switches { PBEPokemon switchPkmn = availableForSwitch[s]; // TODO: Entry hazards // TODO: Known moves of active battlers // TODO: Type effectiveness double score = -10d; possibleActions.Add((new PBETurnAction(user.Id, switchPkmn.Id), score)); } } string ToDebugString((PBETurnAction Action, double Score) t) { string str = "{"; if (t.Action.Decision == PBETurnDecision.Fight) { str += string.Format("Fight {0} {1}", t.Action.FightMove, t.Action.FightTargets); } else { str += string.Format("Switch {0}", team.TryGetPokemon(t.Action.SwitchPokemonId).Nickname); } str += " [" + t.Score + "]}"; return(str); } IOrderedEnumerable <(PBETurnAction Action, double Score)> byScore = possibleActions.OrderByDescending(t => t.Score); Debug.WriteLine("{0}'s possible actions: {1}", user.Nickname, byScore.Select(t => ToDebugString(t)).Print()); double bestScore = byScore.First().Score; actions[i] = byScore.Where(t => t.Score == bestScore).ToArray().RandomElement().Action; // Pick random action of the ones that tied for best score } // Action was chosen, finish up for this Pokémon if (actions[i].Decision == PBETurnDecision.SwitchOut) { standBy.Add(team.TryGetPokemon(actions[i].SwitchPokemonId)); } } return(actions); }
/// <summary>Creates valid actions for a battle turn for a specific team.</summary> /// <param name="team">The team to create actions for.</param> /// <exception cref="InvalidOperationException">Thrown when <paramref name="team"/> has no active battlers or <paramref name="team"/>'s <see cref="PBETeam.Battle"/>'s <see cref="PBEBattle.BattleState"/> is not <see cref="PBEBattleState.WaitingForActions"/>.</exception> /// <exception cref="ArgumentOutOfRangeException">Thrown when a Pokémon has no moves, the AI tries to use a move with invalid targets, or <paramref name="team"/>'s <see cref="PBETeam.Battle"/>'s <see cref="PBEBattle.BattleFormat"/> is invalid.</exception> public static PBETurnAction[] CreateActions(PBETeam team) { if (team == null) { throw new ArgumentNullException(nameof(team)); } if (team.Battle.BattleState != PBEBattleState.WaitingForActions) { throw new InvalidOperationException($"{nameof(team.Battle.BattleState)} must be {PBEBattleState.WaitingForActions} to create actions."); } var actions = new PBETurnAction[team.ActionsRequired.Count]; var standBy = new List <PBEPokemon>(); for (int i = 0; i < actions.Length; i++) { PBEPokemon pkmn = team.ActionsRequired[i]; // If a Pokémon is forced to struggle, it is best that it just stays in until it faints if (pkmn.IsForcedToStruggle()) { actions[i] = new PBETurnAction(pkmn.Id, PBEMove.Struggle, GetPossibleTargets(pkmn, pkmn.GetMoveTargets(PBEMove.Struggle))[0]); } // If a Pokémon has a temp locked move (Dig, Dive, Shadow Force) it must be used else if (pkmn.TempLockedMove != PBEMove.None) { actions[i] = new PBETurnAction(pkmn.Id, pkmn.TempLockedMove, pkmn.TempLockedTargets); } // The Pokémon is free to switch or fight (unless it cannot switch due to Magnet Pull etc) else { // Gather all options of switching and moves PBEPokemon[] availableForSwitch = team.Party.Except(standBy).Where(p => p.FieldPosition == PBEFieldPosition.None && p.HP > 0).ToArray(); PBEMove[] usableMoves = pkmn.GetUsableMoves(); var possibleActions = new List <(PBETurnAction Action, double Score)>(); for (int m = 0; m < usableMoves.Length; m++) // Score moves { PBEMove move = usableMoves[m]; PBEType moveType = pkmn.GetMoveType(move); PBEMoveTarget moveTargets = pkmn.GetMoveTargets(move); PBETurnTarget[] possibleTargets = PBEMoveData.IsSpreadMove(moveTargets) ? new PBETurnTarget[] { GetSpreadMoveTargets(pkmn, moveTargets) } : GetPossibleTargets(pkmn, moveTargets); foreach (PBETurnTarget possibleTarget in possibleTargets) { // TODO: RandomFoeSurrounding (probably just account for the specific effects that use this target type) var targets = new List <PBEPokemon>(); if (possibleTarget.HasFlag(PBETurnTarget.AllyLeft)) { targets.Add(team.TryGetPokemon(PBEFieldPosition.Left)); } if (possibleTarget.HasFlag(PBETurnTarget.AllyCenter)) { targets.Add(team.TryGetPokemon(PBEFieldPosition.Center)); } if (possibleTarget.HasFlag(PBETurnTarget.AllyRight)) { targets.Add(team.TryGetPokemon(PBEFieldPosition.Right)); } if (possibleTarget.HasFlag(PBETurnTarget.FoeLeft)) { targets.Add(team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Left)); } if (possibleTarget.HasFlag(PBETurnTarget.FoeCenter)) { targets.Add(team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Center)); } if (possibleTarget.HasFlag(PBETurnTarget.FoeRight)) { targets.Add(team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Right)); } double score = 0.0; switch (PBEMoveData.Data[move].Effect) { case PBEMoveEffect.Burn: case PBEMoveEffect.Paralyze: case PBEMoveEffect.Poison: case PBEMoveEffect.Sleep: case PBEMoveEffect.Toxic: { foreach (PBEPokemon target in targets) { if (target == null) { // TODO: If all targets are null, this should give a bad score } else { // TODO: Effectiveness check // TODO: Favor sleep with Bad Dreams (unless ally) if (target.Status1 != PBEStatus1.None) { score += target.Team == team.OpposingTeam ? -60 : 0; } else { score += target.Team == team.OpposingTeam ? +40 : -20; } } } break; } case PBEMoveEffect.Hail: { if (team.Battle.Weather == PBEWeather.Hailstorm) { score -= 100; } break; } case PBEMoveEffect.BrickBreak: case PBEMoveEffect.Dig: case PBEMoveEffect.Dive: case PBEMoveEffect.Fly: case PBEMoveEffect.Hit: case PBEMoveEffect.Hit__MaybeBurn: case PBEMoveEffect.Hit__MaybeConfuse: case PBEMoveEffect.Hit__MaybeFlinch: case PBEMoveEffect.Hit__MaybeFreeze: case PBEMoveEffect.Hit__MaybeLowerTarget_ACC_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_ATK_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_DEF_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_SPATK_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_SPDEF_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_SPDEF_By2: case PBEMoveEffect.Hit__MaybeLowerTarget_SPE_By1: case PBEMoveEffect.Hit__MaybeLowerUser_ATK_DEF_By1: case PBEMoveEffect.Hit__MaybeLowerUser_DEF_SPDEF_By1: case PBEMoveEffect.Hit__MaybeLowerUser_SPATK_By2: case PBEMoveEffect.Hit__MaybeLowerUser_SPE_By1: case PBEMoveEffect.Hit__MaybeLowerUser_SPE_DEF_SPDEF_By1: case PBEMoveEffect.Hit__MaybeParalyze: case PBEMoveEffect.Hit__MaybePoison: case PBEMoveEffect.Hit__MaybeRaiseUser_ATK_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_ATK_DEF_SPATK_SPDEF_SPE_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_DEF_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_SPATK_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_SPE_By1: case PBEMoveEffect.Hit__MaybeToxic: case PBEMoveEffect.HPDrain: case PBEMoveEffect.Recoil: case PBEMoveEffect.FlareBlitz: case PBEMoveEffect.SuckerPunch: case PBEMoveEffect.VoltTackle: { foreach (PBEPokemon target in targets) { if (target == null) { // TODO: If all targets are null, this should give a bad score } else { // TODO: Put type checking somewhere in PBEPokemon (levitate, wonder guard, etc) // TODO: Favor hitting ally with move if it absorbs it // TODO: Check items // TODO: Stat changes and accuracy // TODO: Check base power specifically against hp remaining (include spread move damage reduction) double typeEffectiveness = PBEPokemonData.TypeEffectiveness[moveType][target.KnownType1]; typeEffectiveness *= PBEPokemonData.TypeEffectiveness[moveType][target.KnownType2]; if (typeEffectiveness <= 0.0) // (-infinity, 0.0] Ineffective { score += target.Team == team.OpposingTeam ? -60 : -1; } else if (typeEffectiveness <= 0.25) // (0.0, 0.25] NotVeryEffective { score += target.Team == team.OpposingTeam ? -30 : -5; } else if (typeEffectiveness < 1.0) // (0.25, 1.0) NotVeryEffective { score += target.Team == team.OpposingTeam ? -10 : -10; } else if (typeEffectiveness == 1.0) // [1.0, 1.0] Normal { score += target.Team == team.OpposingTeam ? +10 : -15; } else if (typeEffectiveness < 4.0) // (1.0, 4.0) SuperEffective { score += target.Team == team.OpposingTeam ? +25 : -20; } else // [4.0, infinity) SuperEffective { score += target.Team == team.OpposingTeam ? +40 : -30; } if (pkmn.HasType(moveType) && typeEffectiveness > 0.0) // STAB { score += (pkmn.Ability == PBEAbility.Adaptability ? 15 : 10) * (target.Team == team.OpposingTeam ? +1 : -1); } } } break; } case PBEMoveEffect.Moonlight: case PBEMoveEffect.Rest: case PBEMoveEffect.RestoreTargetHP: case PBEMoveEffect.RestoreUserHP: { PBEPokemon target = targets[0]; if (target == null || target.Team == team.OpposingTeam) { score -= 100; } else // Ally { // 0% = +45, 25% = +30, 50% = +15, 75% = 0, 100% = -15 score -= (60 * target.HPPercentage) - 45; } break; } case PBEMoveEffect.RainDance: { if (team.Battle.Weather == PBEWeather.Rain) { score -= 100; } break; } case PBEMoveEffect.Sandstorm: { if (team.Battle.Weather == PBEWeather.Sandstorm) { score -= 100; } break; } case PBEMoveEffect.SunnyDay: { if (team.Battle.Weather == PBEWeather.HarshSunlight) { score -= 100; } break; } case PBEMoveEffect.Attract: case PBEMoveEffect.ChangeTarget_ACC: case PBEMoveEffect.ChangeTarget_ATK: case PBEMoveEffect.ChangeTarget_DEF: case PBEMoveEffect.ChangeTarget_EVA: case PBEMoveEffect.ChangeTarget_SPDEF: case PBEMoveEffect.ChangeTarget_SPE: case PBEMoveEffect.ChangeUser_ATK: case PBEMoveEffect.ChangeUser_DEF: case PBEMoveEffect.ChangeUser_EVA: case PBEMoveEffect.ChangeUser_SPATK: case PBEMoveEffect.ChangeUser_SPDEF: case PBEMoveEffect.ChangeUser_SPE: case PBEMoveEffect.Confuse: case PBEMoveEffect.Curse: case PBEMoveEffect.Endeavor: case PBEMoveEffect.Fail: case PBEMoveEffect.FinalGambit: case PBEMoveEffect.Flatter: case PBEMoveEffect.FocusEnergy: case PBEMoveEffect.GastroAcid: case PBEMoveEffect.Growth: case PBEMoveEffect.HelpingHand: case PBEMoveEffect.LeechSeed: case PBEMoveEffect.LightScreen: case PBEMoveEffect.LowerTarget_ATK_DEF_By1: case PBEMoveEffect.LowerUser_DEF_SPDEF_By1_Raise_ATK_SPATK_SPE_By2: case PBEMoveEffect.LuckyChant: case PBEMoveEffect.Metronome: case PBEMoveEffect.OneHitKnockout: case PBEMoveEffect.PainSplit: case PBEMoveEffect.Protect: case PBEMoveEffect.PsychUp: case PBEMoveEffect.Psywave: case PBEMoveEffect.RaiseUser_ATK_ACC_By1: case PBEMoveEffect.RaiseUser_ATK_DEF_By1: case PBEMoveEffect.RaiseUser_ATK_DEF_ACC_By1: case PBEMoveEffect.RaiseUser_ATK_SPATK_By1: case PBEMoveEffect.RaiseUser_ATK_SPE_By1: case PBEMoveEffect.RaiseUser_DEF_SPDEF_By1: case PBEMoveEffect.RaiseUser_SPATK_SPDEF_By1: case PBEMoveEffect.RaiseUser_SPATK_SPDEF_SPE_By1: case PBEMoveEffect.RaiseUser_SPE_By2_ATK_By1: case PBEMoveEffect.Reflect: case PBEMoveEffect.SeismicToss: case PBEMoveEffect.Selfdestruct: case PBEMoveEffect.SetDamage: case PBEMoveEffect.Snore: case PBEMoveEffect.Spikes: case PBEMoveEffect.StealthRock: case PBEMoveEffect.Substitute: case PBEMoveEffect.SuperFang: case PBEMoveEffect.Swagger: case PBEMoveEffect.ToxicSpikes: case PBEMoveEffect.Transform: case PBEMoveEffect.TrickRoom: case PBEMoveEffect.Whirlwind: case PBEMoveEffect.WideGuard: { // TODO Moves break; } default: throw new ArgumentOutOfRangeException(nameof(PBEMoveData.Effect)); } possibleActions.Add((new PBETurnAction(pkmn.Id, move, possibleTarget), score)); } } if (pkmn.CanSwitchOut()) { for (int s = 0; s < availableForSwitch.Length; s++) // Score switches { PBEPokemon switchPkmn = availableForSwitch[s]; // TODO: Entry hazards // TODO: Known moves of active battlers // TODO: Type effectiveness double score = 0.0; possibleActions.Add((new PBETurnAction(pkmn.Id, switchPkmn.Id), score)); } } string ToDebugString((PBETurnAction Action, double Score) t) { string str = "{"; if (t.Action.Decision == PBETurnDecision.Fight) { str += string.Format("Fight {0} {1}", t.Action.FightMove, t.Action.FightTargets); } else { str += string.Format("Switch {0}", team.TryGetPokemon(t.Action.SwitchPokemonId).Nickname); } str += " [" + t.Score + "]}"; return(str); } IOrderedEnumerable <(PBETurnAction Action, double Score)> byScore = possibleActions.OrderByDescending(t => t.Score); Debug.WriteLine("{0}'s possible actions: {1}", pkmn.Nickname, byScore.Select(t => ToDebugString(t)).Print()); double bestScore = byScore.First().Score; actions[i] = byScore.Where(t => t.Score == bestScore).ToArray().RandomElement().Action; // Pick random action of the ones that tied for best score } // Action was chosen, finish up for this Pokémon if (actions[i].Decision == PBETurnDecision.SwitchOut) { standBy.Add(team.TryGetPokemon(actions[i].SwitchPokemonId)); } } return(actions); }
private PBETurnAction DecideAction(PBEBattlePokemon user, List <PBETurnAction> actions, List <PBEBattlePokemon> standBy) { // Gather all options of switching and moves PBEMove[] usableMoves = user.GetUsableMoves(); var possibleActions = new List <(PBETurnAction Action, float Score)>(); for (int m = 0; m < usableMoves.Length; m++) // Score moves { PBEMove move = usableMoves[m]; PBEType moveType = user.GetMoveType(move); PBEMoveTarget moveTargets = user.GetMoveTargets(move); PBETurnTarget[] possibleTargets = PBEDataUtils.IsSpreadMove(moveTargets) ? new PBETurnTarget[] { PBEBattleUtils.GetSpreadMoveTargets(user, moveTargets) } : PBEBattleUtils.GetPossibleTargets(user, moveTargets); foreach (PBETurnTarget possibleTarget in possibleTargets) { // TODO: RandomFoeSurrounding (probably just account for the specific effects that use this target type) // TODO: Don't queue up to do the same thing (two trying to afflict the same target when there are multiple targets) var targets = new List <PBEBattlePokemon>(); if (possibleTarget.HasFlag(PBETurnTarget.AllyLeft)) { Trainer.Team.TryAddPokemonToCollection(PBEFieldPosition.Left, targets); } if (possibleTarget.HasFlag(PBETurnTarget.AllyCenter)) { Trainer.Team.TryAddPokemonToCollection(PBEFieldPosition.Center, targets); } if (possibleTarget.HasFlag(PBETurnTarget.AllyRight)) { Trainer.Team.TryAddPokemonToCollection(PBEFieldPosition.Right, targets); } if (possibleTarget.HasFlag(PBETurnTarget.FoeLeft)) { Trainer.Team.OpposingTeam.TryAddPokemonToCollection(PBEFieldPosition.Left, targets); } if (possibleTarget.HasFlag(PBETurnTarget.FoeCenter)) { Trainer.Team.OpposingTeam.TryAddPokemonToCollection(PBEFieldPosition.Center, targets); } if (possibleTarget.HasFlag(PBETurnTarget.FoeRight)) { Trainer.Team.OpposingTeam.TryAddPokemonToCollection(PBEFieldPosition.Right, targets); } float score = ScoreMove(targets, user, move, moveType, actions); possibleActions.Add((new PBETurnAction(user, move, possibleTarget), score)); } } if (user.CanSwitchOut()) { PBEBattlePokemon[] availableForSwitch = Trainer.Party.Except(standBy).Where(p => p.FieldPosition == PBEFieldPosition.None && p.CanBattle).ToArray(); for (int s = 0; s < availableForSwitch.Length; s++) // Score switches { PBEBattlePokemon switchPkmn = availableForSwitch[s]; // TODO: Entry hazards // TODO: Known moves of active battlers // TODO: Type effectiveness float score = -10; possibleActions.Add((new PBETurnAction(user, switchPkmn), score)); } } IOrderedEnumerable <(PBETurnAction Action, float Score)> byScore = possibleActions.OrderByDescending(t => t.Score); Debug_LogGeneratedActions(user, byScore); float bestScore = byScore.First().Score; return(PBEDataProvider.GlobalRandom.RandomElement(byScore.Where(t => t.Score == bestScore).ToArray()).Action); // Pick random action of the ones that tied for best score }
private static PBETurnAction DecideAction(PBETrainer trainer, PBEBattlePokemon user, IEnumerable <PBETurnAction> actions, IEnumerable <PBEBattlePokemon> standBy) { // Gather all options of switching and moves PBEMove[] usableMoves = user.GetUsableMoves(); var possibleActions = new List <(PBETurnAction Action, double Score)>(); for (int m = 0; m < usableMoves.Length; m++) // Score moves { PBEMove move = usableMoves[m]; PBEType moveType = user.GetMoveType(move); PBEMoveTarget moveTargets = user.GetMoveTargets(move); PBETurnTarget[] possibleTargets = PBEDataUtils.IsSpreadMove(moveTargets) ? new PBETurnTarget[] { PBEBattleUtils.GetSpreadMoveTargets(user, moveTargets) } : PBEBattleUtils.GetPossibleTargets(user, moveTargets); foreach (PBETurnTarget possibleTarget in possibleTargets) { // TODO: RandomFoeSurrounding (probably just account for the specific effects that use this target type) // TODO: Don't queue up to do the same thing (two trying to afflict the same target when there are multiple targets) var targets = new List <PBEBattlePokemon>(); if (possibleTarget.HasFlag(PBETurnTarget.AllyLeft)) { targets.Add(trainer.TryGetPokemon(PBEFieldPosition.Left)); } if (possibleTarget.HasFlag(PBETurnTarget.AllyCenter)) { targets.Add(trainer.TryGetPokemon(PBEFieldPosition.Center)); } if (possibleTarget.HasFlag(PBETurnTarget.AllyRight)) { targets.Add(trainer.TryGetPokemon(PBEFieldPosition.Right)); } if (possibleTarget.HasFlag(PBETurnTarget.FoeLeft)) { targets.Add(trainer.Team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Left)); } if (possibleTarget.HasFlag(PBETurnTarget.FoeCenter)) { targets.Add(trainer.Team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Center)); } if (possibleTarget.HasFlag(PBETurnTarget.FoeRight)) { targets.Add(trainer.Team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Right)); } double score; if (targets.All(p => p == null)) { score = -100; } else { score = 0; targets.RemoveAll(p => p == null); IPBEMoveData mData = PBEDataProvider.Instance.GetMoveData(move); if (!mData.IsMoveUsable()) { throw new ArgumentOutOfRangeException(nameof(trainer), $"{move} is not yet implemented in Pokémon Battle Engine."); } switch (mData.Effect) { case PBEMoveEffect.Acrobatics: case PBEMoveEffect.Bounce: case PBEMoveEffect.BrickBreak: case PBEMoveEffect.Brine: case PBEMoveEffect.ChipAway: case PBEMoveEffect.CrushGrip: case PBEMoveEffect.Dig: case PBEMoveEffect.Dive: case PBEMoveEffect.Eruption: case PBEMoveEffect.Facade: case PBEMoveEffect.Feint: case PBEMoveEffect.Flail: case PBEMoveEffect.Fly: case PBEMoveEffect.FoulPlay: case PBEMoveEffect.Frustration: case PBEMoveEffect.GrassKnot: case PBEMoveEffect.HeatCrash: case PBEMoveEffect.Hex: case PBEMoveEffect.HiddenPower: case PBEMoveEffect.Hit: case PBEMoveEffect.Hit__2Times: case PBEMoveEffect.Hit__2Times__MaybePoison: case PBEMoveEffect.Hit__2To5Times: case PBEMoveEffect.Hit__MaybeBurn: case PBEMoveEffect.Hit__MaybeBurn__10PercentFlinch: case PBEMoveEffect.Hit__MaybeBurnFreezeParalyze: case PBEMoveEffect.Hit__MaybeConfuse: case PBEMoveEffect.Hit__MaybeFlinch: case PBEMoveEffect.Hit__MaybeFreeze: case PBEMoveEffect.Hit__MaybeFreeze__10PercentFlinch: case PBEMoveEffect.Hit__MaybeLowerTarget_ACC_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_ATK_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_DEF_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_SPATK_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_SPDEF_By1: case PBEMoveEffect.Hit__MaybeLowerTarget_SPDEF_By2: case PBEMoveEffect.Hit__MaybeLowerTarget_SPE_By1: case PBEMoveEffect.Hit__MaybeLowerUser_ATK_DEF_By1: case PBEMoveEffect.Hit__MaybeLowerUser_DEF_SPDEF_By1: case PBEMoveEffect.Hit__MaybeLowerUser_SPATK_By2: case PBEMoveEffect.Hit__MaybeLowerUser_SPE_By1: case PBEMoveEffect.Hit__MaybeLowerUser_SPE_DEF_SPDEF_By1: case PBEMoveEffect.Hit__MaybeParalyze: case PBEMoveEffect.Hit__MaybeParalyze__10PercentFlinch: case PBEMoveEffect.Hit__MaybePoison: case PBEMoveEffect.Hit__MaybeRaiseUser_ATK_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_ATK_DEF_SPATK_SPDEF_SPE_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_DEF_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_SPATK_By1: case PBEMoveEffect.Hit__MaybeRaiseUser_SPE_By1: case PBEMoveEffect.Hit__MaybeToxic: case PBEMoveEffect.HPDrain: case PBEMoveEffect.Judgment: case PBEMoveEffect.Magnitude: case PBEMoveEffect.Payback: case PBEMoveEffect.PayDay: case PBEMoveEffect.Psyshock: case PBEMoveEffect.Punishment: case PBEMoveEffect.Recoil: case PBEMoveEffect.Recoil__10PercentBurn: case PBEMoveEffect.Recoil__10PercentParalyze: case PBEMoveEffect.Retaliate: case PBEMoveEffect.Return: case PBEMoveEffect.SecretPower: case PBEMoveEffect.ShadowForce: case PBEMoveEffect.SmellingSalt: case PBEMoveEffect.StoredPower: case PBEMoveEffect.TechnoBlast: case PBEMoveEffect.Venoshock: case PBEMoveEffect.WakeUpSlap: case PBEMoveEffect.WeatherBall: { foreach (PBEBattlePokemon target in targets) { // TODO: Favor hitting ally with move if waterabsorb/voltabsorb etc // TODO: Liquid ooze // TODO: Check items // TODO: Stat changes and accuracy (even thunder/guillotine accuracy) // TODO: Check base power specifically against hp remaining (include spread move damage reduction) PBETypeEffectiveness.IsAffectedByAttack(user, target, moveType, out double damageMultiplier, useKnownInfo: true); if (damageMultiplier <= 0) // (-infinity, 0.0] Ineffective { score += target.Team == trainer.Team ? 0 : -60; } else if (damageMultiplier <= 0.25) // (0.0, 0.25] NotVeryEffective { score += target.Team == trainer.Team ? -5 : -30; } else if (damageMultiplier < 1) // (0.25, 1.0) NotVeryEffective { score += target.Team == trainer.Team ? -10 : -10; } else if (damageMultiplier == 1) // [1.0, 1.0] Normal { score += target.Team == trainer.Team ? -15 : +10; } else if (damageMultiplier < 4) // (1.0, 4.0) SuperEffective { score += target.Team == trainer.Team ? -20 : +25; } else // [4.0, infinity) SuperEffective { score += target.Team == trainer.Team ? -30 : +40; } if (user.ReceivesSTAB(moveType) && damageMultiplier > 0) { score += (user.Ability == PBEAbility.Adaptability ? 7 : 5) * (target.Team == trainer.Team ? -1 : +1); } } break; } case PBEMoveEffect.Attract: { foreach (PBEBattlePokemon target in targets) { // TODO: Destiny knot if (target.IsAttractionPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == trainer.Team ? -20 : +40; } else { score += target.Team == trainer.Team ? 0 : -60; } } break; } case PBEMoveEffect.Burn: { foreach (PBEBattlePokemon target in targets) { // TODO: Heatproof, physical attacker if (target.IsBurnPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == trainer.Team ? -20 : +40; } else { score += target.Team == trainer.Team ? 0 : -60; } } break; } case PBEMoveEffect.ChangeTarget_ACC: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Accuracy, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_ATK: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_DEF: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Defense, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_EVA: case PBEMoveEffect.Minimize: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Evasion, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_SPATK: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.SpAttack, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_SPDEF: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.SpDefense, mData.EffectParam, ref score); } break; } case PBEMoveEffect.ChangeTarget_SPE: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Speed, mData.EffectParam, ref score); } break; } case PBEMoveEffect.Confuse: case PBEMoveEffect.Flatter: case PBEMoveEffect.Swagger: { foreach (PBEBattlePokemon target in targets) { // TODO: Only swagger/flatter if the opponent most likely won't use it against you if (target.IsConfusionPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == trainer.Team ? -20 : +40; } else { score += target.Team == trainer.Team ? 0 : -60; } } break; } case PBEMoveEffect.Growth: { int change = trainer.Battle.WillLeafGuardActivate() ? +2 : +1; foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, change, ref score); ScoreStatChange(user, target, PBEStat.SpAttack, change, ref score); } break; } case PBEMoveEffect.LeechSeed: { foreach (PBEBattlePokemon target in targets) { if (target.IsLeechSeedPossible(useKnownInfo: true) == PBEResult.Success) { score += target.Team == trainer.Team ? -20 : +40; } else { score += target.Team == trainer.Team ? 0 : -60; } } break; } case PBEMoveEffect.LightScreen: { score += trainer.Team.TeamStatus.HasFlag(PBETeamStatus.LightScreen) || IsTeammateUsingEffect(actions, PBEMoveEffect.LightScreen) ? -100 : +40; break; } case PBEMoveEffect.LowerTarget_ATK_DEF_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, -1, ref score); ScoreStatChange(user, target, PBEStat.Defense, -1, ref score); } break; } case PBEMoveEffect.LowerTarget_DEF_SPDEF_By1_Raise_ATK_SPATK_SPE_By2: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Defense, -1, ref score); ScoreStatChange(user, target, PBEStat.SpDefense, -1, ref score); ScoreStatChange(user, target, PBEStat.Attack, +2, ref score); ScoreStatChange(user, target, PBEStat.SpAttack, +2, ref score); ScoreStatChange(user, target, PBEStat.Speed, +2, ref score); } break; } case PBEMoveEffect.LuckyChant: { score += trainer.Team.TeamStatus.HasFlag(PBETeamStatus.LuckyChant) || IsTeammateUsingEffect(actions, PBEMoveEffect.LuckyChant) ? -100 : +40; break; } case PBEMoveEffect.Moonlight: case PBEMoveEffect.Rest: case PBEMoveEffect.RestoreTargetHP: case PBEMoveEffect.Roost: { foreach (PBEBattlePokemon target in targets) { if (target.Team == trainer.Team) { score += HPAware(target.HPPercentage, +45, -15); } else { score -= 100; } } break; } case PBEMoveEffect.Nothing: case PBEMoveEffect.Teleport: { score -= 100; break; } case PBEMoveEffect.Paralyze: case PBEMoveEffect.ThunderWave: { foreach (PBEBattlePokemon target in targets) { bool tw = mData.Effect != PBEMoveEffect.ThunderWave || PBETypeEffectiveness.ThunderWaveTypeCheck(user, target, move, useKnownInfo: true) == PBEResult.Success; if (tw && target.IsParalysisPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == trainer.Team ? -20 : +40; } else { score += target.Team == trainer.Team ? 0 : -60; } } break; } case PBEMoveEffect.Poison: case PBEMoveEffect.Toxic: { foreach (PBEBattlePokemon target in targets) { // TODO: Poison Heal if (target.IsPoisonPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == trainer.Team ? -20 : +40; } else { score += target.Team == trainer.Team ? 0 : -60; } } break; } case PBEMoveEffect.RaiseTarget_ATK_ACC_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.Accuracy, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_ATK_DEF_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.Defense, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_ATK_DEF_ACC_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.Defense, +1, ref score); ScoreStatChange(user, target, PBEStat.Accuracy, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_ATK_SPATK_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.SpAttack, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_ATK_SPE_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); ScoreStatChange(user, target, PBEStat.Speed, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_DEF_SPDEF_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Defense, +1, ref score); ScoreStatChange(user, target, PBEStat.SpDefense, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_SPATK_SPDEF_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.SpAttack, +1, ref score); ScoreStatChange(user, target, PBEStat.SpDefense, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_SPATK_SPDEF_SPE_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.SpAttack, +1, ref score); ScoreStatChange(user, target, PBEStat.SpDefense, +1, ref score); ScoreStatChange(user, target, PBEStat.Speed, +1, ref score); } break; } case PBEMoveEffect.RaiseTarget_SPE_By2_ATK_By1: { foreach (PBEBattlePokemon target in targets) { ScoreStatChange(user, target, PBEStat.Speed, +2, ref score); ScoreStatChange(user, target, PBEStat.Attack, +1, ref score); } break; } case PBEMoveEffect.Reflect: { score += trainer.Team.TeamStatus.HasFlag(PBETeamStatus.Reflect) || IsTeammateUsingEffect(actions, PBEMoveEffect.Reflect) ? -100 : +40; break; } case PBEMoveEffect.Safeguard: { score += trainer.Team.TeamStatus.HasFlag(PBETeamStatus.Safeguard) || IsTeammateUsingEffect(actions, PBEMoveEffect.Safeguard) ? -100 : +40; break; } case PBEMoveEffect.Sleep: { foreach (PBEBattlePokemon target in targets) { // TODO: Bad Dreams if (target.IsSleepPossible(user, useKnownInfo: true) == PBEResult.Success) { score += target.Team == trainer.Team ? -20 : +40; } else { score += target.Team == trainer.Team ? 0 : -60; } } break; } case PBEMoveEffect.Substitute: { foreach (PBEBattlePokemon target in targets) { if (target.IsSubstitutePossible() == PBEResult.Success) { score += target.Team == trainer.Team ? HPAware(target.HPPercentage, -30, +50) : -60; } else { score += target.Team == trainer.Team ? 0 : -20; } } break; } case PBEMoveEffect.BellyDrum: case PBEMoveEffect.Camouflage: case PBEMoveEffect.ChangeTarget_SPATK__IfAttractionPossible: case PBEMoveEffect.Conversion: case PBEMoveEffect.Curse: case PBEMoveEffect.Endeavor: case PBEMoveEffect.Entrainment: case PBEMoveEffect.FinalGambit: case PBEMoveEffect.FocusEnergy: case PBEMoveEffect.Foresight: case PBEMoveEffect.GastroAcid: case PBEMoveEffect.Hail: case PBEMoveEffect.Haze: case PBEMoveEffect.HelpingHand: case PBEMoveEffect.HPDrain__RequireSleep: case PBEMoveEffect.LockOn: case PBEMoveEffect.MagnetRise: case PBEMoveEffect.Metronome: case PBEMoveEffect.MiracleEye: case PBEMoveEffect.Nightmare: case PBEMoveEffect.OneHitKnockout: case PBEMoveEffect.PainSplit: case PBEMoveEffect.PowerTrick: case PBEMoveEffect.Protect: case PBEMoveEffect.PsychUp: case PBEMoveEffect.Psywave: case PBEMoveEffect.QuickGuard: case PBEMoveEffect.RainDance: case PBEMoveEffect.ReflectType: case PBEMoveEffect.Refresh: case PBEMoveEffect.RolePlay: case PBEMoveEffect.Sandstorm: case PBEMoveEffect.SeismicToss: case PBEMoveEffect.Selfdestruct: case PBEMoveEffect.SetDamage: case PBEMoveEffect.SimpleBeam: case PBEMoveEffect.Sketch: case PBEMoveEffect.Snore: case PBEMoveEffect.Soak: case PBEMoveEffect.Spikes: case PBEMoveEffect.StealthRock: case PBEMoveEffect.SuckerPunch: case PBEMoveEffect.SunnyDay: case PBEMoveEffect.SuperFang: case PBEMoveEffect.Tailwind: case PBEMoveEffect.ToxicSpikes: case PBEMoveEffect.Transform: case PBEMoveEffect.TrickRoom: case PBEMoveEffect.Whirlwind: case PBEMoveEffect.WideGuard: case PBEMoveEffect.WorrySeed: { // TODO break; } default: throw new ArgumentOutOfRangeException(nameof(IPBEMoveData.Effect)); } } possibleActions.Add((new PBETurnAction(user, move, possibleTarget), score)); } } if (user.CanSwitchOut()) { PBEBattlePokemon[] availableForSwitch = trainer.Party.Except(standBy).Where(p => p.FieldPosition == PBEFieldPosition.None && p.HP > 0).ToArray(); for (int s = 0; s < availableForSwitch.Length; s++) // Score switches { PBEBattlePokemon switchPkmn = availableForSwitch[s]; // TODO: Entry hazards // TODO: Known moves of active battlers // TODO: Type effectiveness double score = -10d; possibleActions.Add((new PBETurnAction(user, switchPkmn), score)); } } string ToDebugString((PBETurnAction Action, double Score) t) { string str = "{"; if (t.Action.Decision == PBETurnDecision.Fight) { str += string.Format("Fight {0} {1}", t.Action.FightMove, t.Action.FightTargets); } else { str += string.Format("Switch {0}", trainer.TryGetPokemon(t.Action.SwitchPokemonId).Nickname); } str += " [" + t.Score + "]}"; return(str); } IOrderedEnumerable <(PBETurnAction Action, double Score)> byScore = possibleActions.OrderByDescending(t => t.Score); Debug.WriteLine("{0}'s possible actions: {1}", user.Nickname, byScore.Select(t => ToDebugString(t)).Print()); double bestScore = byScore.First().Score; return(PBEDataProvider.GlobalRandom.RandomElement(byScore.Where(t => t.Score == bestScore).ToArray()).Action); // Pick random action of the ones that tied for best score }
public static PBETurnTarget GetSpreadMoveTargets(PBEBattlePokemon pkmn, PBEMoveTarget targets) { switch (pkmn.Battle.BattleFormat) { case PBEBattleFormat.Single: { switch (targets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETurnTarget.AllyCenter | PBETurnTarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: case PBEMoveTarget.AllSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETurnTarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETurnTarget.AllyCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(targets)); } } case PBEBattleFormat.Double: { switch (targets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.AllyLeft | PBETurnTarget.AllyRight | PBETurnTarget.FoeLeft | PBETurnTarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.FoeLeft | PBETurnTarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.AllyLeft | PBETurnTarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETurnTarget.AllyRight | PBETurnTarget.FoeLeft | PBETurnTarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.AllyLeft | PBETurnTarget.FoeLeft | PBETurnTarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(targets)); } } case PBEBattleFormat.Triple: { switch (targets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.AllyLeft | PBETurnTarget.AllyCenter | PBETurnTarget.AllyRight | PBETurnTarget.FoeLeft | PBETurnTarget.FoeCenter | PBETurnTarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.FoeLeft | PBETurnTarget.FoeCenter | PBETurnTarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoesSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETurnTarget.FoeCenter | PBETurnTarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETurnTarget.FoeLeft | PBETurnTarget.FoeCenter | PBETurnTarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.FoeLeft | PBETurnTarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETurnTarget.AllyCenter | PBETurnTarget.FoeCenter | PBETurnTarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETurnTarget.AllyLeft | PBETurnTarget.AllyRight | PBETurnTarget.FoeLeft | PBETurnTarget.FoeCenter | PBETurnTarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.AllyCenter | PBETurnTarget.FoeLeft | PBETurnTarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.AllyLeft | PBETurnTarget.AllyCenter | PBETurnTarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(targets)); } } case PBEBattleFormat.Rotation: { switch (targets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.AllyCenter | PBETurnTarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: case PBEMoveTarget.AllSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETurnTarget.AllyCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(targets)); } } default: throw new ArgumentOutOfRangeException(nameof(pkmn.Battle.BattleFormat)); } }
public static PBETurnTarget[] GetPossibleTargets(PBEBattlePokemon pkmn, PBEMoveTarget targets) { switch (pkmn.Battle.BattleFormat) { case PBEBattleFormat.Single: { switch (targets) { case PBEMoveTarget.SingleFoeSurrounding: case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(new PBETurnTarget[] { PBETurnTarget.FoeCenter }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.Self: case PBEMoveTarget.SelfOrAllySurrounding: case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(new PBETurnTarget[] { PBETurnTarget.AllyCenter }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(targets)); } } case PBEBattleFormat.Double: { switch (targets) { case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.Self: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft }); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyRight }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SelfOrAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft, PBETurnTarget.AllyRight }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(new PBETurnTarget[] { PBETurnTarget.AllyRight }); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleFoeSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.FoeLeft, PBETurnTarget.FoeRight }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(new PBETurnTarget[] { PBETurnTarget.AllyRight, PBETurnTarget.FoeLeft, PBETurnTarget.FoeRight }); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft, PBETurnTarget.FoeLeft, PBETurnTarget.FoeRight }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(targets)); } } case PBEBattleFormat.Triple: { switch (targets) { case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.Self: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft }); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(new PBETurnTarget[] { PBETurnTarget.AllyCenter }); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyRight }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SelfOrAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft, PBETurnTarget.AllyCenter }); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft, PBETurnTarget.AllyCenter, PBETurnTarget.AllyRight }); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyCenter, PBETurnTarget.AllyRight }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyCenter }); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft, PBETurnTarget.AllyRight }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleFoeSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(new PBETurnTarget[] { PBETurnTarget.FoeCenter, PBETurnTarget.FoeRight }); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(new PBETurnTarget[] { PBETurnTarget.FoeLeft, PBETurnTarget.FoeCenter, PBETurnTarget.FoeRight }); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.FoeLeft, PBETurnTarget.FoeCenter }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleNotSelf: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(new PBETurnTarget[] { PBETurnTarget.AllyCenter, PBETurnTarget.AllyRight, PBETurnTarget.FoeLeft, PBETurnTarget.FoeCenter, PBETurnTarget.FoeRight }); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft, PBETurnTarget.AllyRight, PBETurnTarget.FoeLeft, PBETurnTarget.FoeCenter, PBETurnTarget.FoeRight }); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft, PBETurnTarget.AllyCenter, PBETurnTarget.FoeLeft, PBETurnTarget.FoeCenter, PBETurnTarget.FoeRight }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(new PBETurnTarget[] { PBETurnTarget.AllyCenter, PBETurnTarget.FoeCenter, PBETurnTarget.FoeRight }); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(new PBETurnTarget[] { PBETurnTarget.AllyLeft, PBETurnTarget.AllyRight, PBETurnTarget.FoeLeft, PBETurnTarget.FoeCenter, PBETurnTarget.FoeRight }); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyCenter, PBETurnTarget.FoeLeft, PBETurnTarget.FoeCenter }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(targets)); } } case PBEBattleFormat.Rotation: { switch (targets) { case PBEMoveTarget.SingleFoeSurrounding: case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.FoeCenter }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.Self: case PBEMoveTarget.SelfOrAllySurrounding: case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(new PBETurnTarget[] { PBETurnTarget.AllyCenter }); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(targets)); } } default: throw new ArgumentOutOfRangeException(nameof(pkmn.Battle.BattleFormat)); } }
static PBETarget DecideTargets(PBEPokemon pkmn, PBEMove move) { PBEMoveTarget possibleTargets = pkmn.GetMoveTargets(move); switch (pkmn.Team.Battle.BattleFormat) { case PBEBattleFormat.Single: { switch (possibleTargets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETarget.AllyCenter | PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: case PBEMoveTarget.AllSurrounding: case PBEMoveTarget.SingleFoeSurrounding: case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: case PBEMoveTarget.Self: case PBEMoveTarget.SelfOrAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETarget.AllyCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETarget.None); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(possibleTargets)); } } case PBEBattleFormat.Double: { switch (possibleTargets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyLeft | PBETarget.AllyRight | PBETarget.FoeLeft | PBETarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.FoeLeft | PBETarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyLeft | PBETarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETarget.AllyRight | PBETarget.FoeLeft | PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyLeft | PBETarget.FoeLeft | PBETarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.Self: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETarget.AllyLeft); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SelfOrAllySurrounding: // TODO { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { if (PBEUtils.RNG.NextBoolean()) { return(PBETarget.AllyLeft); } else { return(PBETarget.AllyRight); } } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETarget.AllyRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyLeft); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleFoeSurrounding: // TODO { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { if (PBEUtils.RNG.NextBoolean()) { return(PBETarget.FoeLeft); } else { return(PBETarget.FoeRight); } } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: // TODO { if (pkmn.FieldPosition == PBEFieldPosition.Left) { int val = PBEUtils.RNG.Next(0, 3); if (val == 0) { return(PBETarget.AllyRight); } else if (val == 1) { return(PBETarget.FoeLeft); } else { return(PBETarget.FoeRight); } } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { int val = PBEUtils.RNG.Next(0, 3); if (val == 0) { return(PBETarget.AllyLeft); } else if (val == 1) { return(PBETarget.FoeLeft); } else { return(PBETarget.FoeRight); } } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.None); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(possibleTargets)); } } case PBEBattleFormat.Triple: { switch (possibleTargets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyLeft | PBETarget.AllyCenter | PBETarget.AllyRight | PBETarget.FoeLeft | PBETarget.FoeCenter | PBETarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.FoeLeft | PBETarget.FoeCenter | PBETarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoesSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETarget.FoeCenter | PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETarget.FoeLeft | PBETarget.FoeCenter | PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.FoeLeft | PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETarget.AllyCenter | PBETarget.FoeCenter | PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETarget.AllyLeft | PBETarget.AllyRight | PBETarget.FoeLeft | PBETarget.FoeCenter | PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyCenter | PBETarget.FoeLeft | PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyLeft | PBETarget.AllyCenter | PBETarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.Self: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETarget.AllyLeft); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(PBETarget.AllyCenter); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SelfOrAllySurrounding: // TODO { if (pkmn.FieldPosition == PBEFieldPosition.Left) { if (PBEUtils.RNG.NextBoolean()) { return(PBETarget.AllyLeft); } else { return(PBETarget.AllyCenter); } } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { int val = PBEUtils.RNG.Next(0, 3); if (val == 0) { return(PBETarget.AllyLeft); } else if (val == 1) { return(PBETarget.AllyCenter); } else { return(PBETarget.AllyRight); } } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { if (PBEUtils.RNG.NextBoolean()) { return(PBETarget.AllyCenter); } else { return(PBETarget.AllyRight); } } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleAllySurrounding: // TODO { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(PBETarget.AllyCenter); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { if (PBEUtils.RNG.NextBoolean()) { return(PBETarget.AllyLeft); } else { return(PBETarget.AllyRight); } } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleFoeSurrounding: // TODO { if (pkmn.FieldPosition == PBEFieldPosition.Left) { if (PBEUtils.RNG.NextBoolean()) { return(PBETarget.FoeCenter); } else { return(PBETarget.FoeRight); } } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { int val = PBEUtils.RNG.Next(0, 3); if (val == 0) { return(PBETarget.FoeLeft); } else if (val == 1) { return(PBETarget.FoeCenter); } else { return(PBETarget.FoeRight); } } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { if (PBEUtils.RNG.NextBoolean()) { return(PBETarget.FoeLeft); } else { return(PBETarget.FoeCenter); } } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleNotSelf: // TODO { if (pkmn.FieldPosition == PBEFieldPosition.Left) { int val = PBEUtils.RNG.Next(0, 5); if (val == 0) { return(PBETarget.AllyCenter); } else if (val == 1) { return(PBETarget.AllyRight); } else if (val == 2) { return(PBETarget.FoeLeft); } else if (val == 3) { return(PBETarget.FoeCenter); } else { return(PBETarget.FoeRight); } } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { int val = PBEUtils.RNG.Next(0, 5); if (val == 0) { return(PBETarget.AllyLeft); } else if (val == 1) { return(PBETarget.AllyRight); } else if (val == 2) { return(PBETarget.FoeLeft); } else if (val == 3) { return(PBETarget.FoeCenter); } else { return(PBETarget.FoeRight); } } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { int val = PBEUtils.RNG.Next(0, 5); if (val == 0) { return(PBETarget.AllyLeft); } else if (val == 1) { return(PBETarget.AllyCenter); } else if (val == 2) { return(PBETarget.FoeLeft); } else if (val == 3) { return(PBETarget.FoeCenter); } else { return(PBETarget.FoeRight); } } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleSurrounding: // TODO { if (pkmn.FieldPosition == PBEFieldPosition.Left) { int val = PBEUtils.RNG.Next(0, 3); if (val == 0) { return(PBETarget.AllyCenter); } else if (val == 1) { return(PBETarget.FoeCenter); } else { return(PBETarget.FoeRight); } } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { int val = PBEUtils.RNG.Next(0, 5); if (val == 0) { return(PBETarget.AllyLeft); } else if (val == 1) { return(PBETarget.AllyRight); } else if (val == 2) { return(PBETarget.FoeLeft); } else if (val == 3) { return(PBETarget.FoeCenter); } else { return(PBETarget.FoeRight); } } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { int val = PBEUtils.RNG.Next(0, 3); if (val == 0) { return(PBETarget.AllyCenter); } else if (val == 1) { return(PBETarget.FoeLeft); } else { return(PBETarget.FoeCenter); } } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.None); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(possibleTargets)); } } case PBEBattleFormat.Rotation: { switch (possibleTargets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyCenter | PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: case PBEMoveTarget.AllSurrounding: case PBEMoveTarget.SingleFoeSurrounding: case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: case PBEMoveTarget.Self: case PBEMoveTarget.SelfOrAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.AllyCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(PBETarget.None); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(possibleTargets)); } } default: throw new ArgumentOutOfRangeException(nameof(pkmn.Team.Battle.BattleFormat)); } }
/// <summary> /// Determines whether chosen targets are valid for a given move. /// </summary> /// <param name="pkmn">The Pokémon that will act.</param> /// <param name="move">The move the Pokémon wishes to use.</param> /// <param name="targets">The targets bitfield to validate.</param> /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="targets"/>, <paramref name="move"/>, <paramref name="pkmn"/>'s <see cref="PBEPokemon.FieldPosition"/>, or <paramref name="pkmn"/>'s <see cref="PBEBattle"/>'s <see cref="BattleFormat"/> is invalid.</exception> public static bool AreTargetsValid(PBEPokemon pkmn, PBEMove move, PBETarget targets) { if (move == PBEMove.None || move >= PBEMove.MAX) { throw new ArgumentOutOfRangeException(nameof(move)); } PBEMoveTarget possibleTargets = pkmn.GetMoveTargets(move); switch (pkmn.Team.Battle.BattleFormat) { case PBEBattleFormat.Single: { switch (possibleTargets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == (PBETarget.AllyCenter | PBETarget.FoeCenter)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: case PBEMoveTarget.AllSurrounding: case PBEMoveTarget.SingleFoeSurrounding: case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: case PBEMoveTarget.Self: case PBEMoveTarget.SelfOrAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == PBETarget.AllyCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(true); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(possibleTargets)); } } case PBEBattleFormat.Double: { switch (possibleTargets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.AllyLeft | PBETarget.AllyRight | PBETarget.FoeLeft | PBETarget.FoeRight)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.FoeLeft | PBETarget.FoeRight)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.AllyLeft | PBETarget.AllyRight)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == (PBETarget.AllyRight | PBETarget.FoeLeft | PBETarget.FoeRight)); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.AllyLeft | PBETarget.FoeLeft | PBETarget.FoeRight)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.Self: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == PBETarget.AllyLeft); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SelfOrAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyLeft || targets == PBETarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == PBETarget.AllyRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyLeft); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleFoeSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.FoeLeft || targets == PBETarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == PBETarget.AllyRight || targets == PBETarget.FoeLeft || targets == PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyLeft || targets == PBETarget.FoeLeft || targets == PBETarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Right) { return(true); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(possibleTargets)); } } case PBEBattleFormat.Triple: { switch (possibleTargets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.AllyLeft | PBETarget.AllyCenter | PBETarget.AllyRight | PBETarget.FoeLeft | PBETarget.FoeCenter | PBETarget.FoeRight)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.FoeLeft | PBETarget.FoeCenter | PBETarget.FoeRight)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoesSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == (PBETarget.FoeCenter | PBETarget.FoeRight)); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == (PBETarget.FoeLeft | PBETarget.FoeCenter | PBETarget.FoeRight)); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.FoeLeft | PBETarget.FoeCenter)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == (PBETarget.AllyCenter | PBETarget.FoeCenter | PBETarget.FoeRight)); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == (PBETarget.AllyLeft | PBETarget.AllyRight | PBETarget.FoeLeft | PBETarget.FoeCenter | PBETarget.FoeRight)); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.AllyCenter | PBETarget.FoeLeft | PBETarget.FoeCenter)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.AllyLeft | PBETarget.AllyCenter | PBETarget.AllyRight)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.Self: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == PBETarget.AllyLeft); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == PBETarget.AllyCenter); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SelfOrAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == PBETarget.AllyLeft || targets == PBETarget.AllyCenter); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == PBETarget.AllyLeft || targets == PBETarget.AllyCenter || targets == PBETarget.AllyRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyCenter || targets == PBETarget.AllyRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == PBETarget.AllyCenter); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == PBETarget.AllyLeft || targets == PBETarget.AllyRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleFoeSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == PBETarget.FoeCenter || targets == PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == PBETarget.FoeLeft || targets == PBETarget.FoeCenter || targets == PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.FoeLeft || targets == PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleNotSelf: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == PBETarget.AllyCenter || targets == PBETarget.AllyRight || targets == PBETarget.FoeLeft || targets == PBETarget.FoeCenter || targets == PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == PBETarget.AllyLeft || targets == PBETarget.AllyRight || targets == PBETarget.FoeLeft || targets == PBETarget.FoeCenter || targets == PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyLeft || targets == PBETarget.AllyCenter || targets == PBETarget.FoeLeft || targets == PBETarget.FoeCenter || targets == PBETarget.FoeRight); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { return(targets == PBETarget.AllyCenter || targets == PBETarget.FoeCenter || targets == PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Center) { return(targets == PBETarget.AllyLeft || targets == PBETarget.AllyRight || targets == PBETarget.FoeLeft || targets == PBETarget.FoeCenter || targets == PBETarget.FoeRight); } else if (pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyCenter || targets == PBETarget.FoeLeft || targets == PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(true); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(possibleTargets)); } } case PBEBattleFormat.Rotation: { switch (possibleTargets) { case PBEMoveTarget.All: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == (PBETarget.AllyCenter | PBETarget.FoeCenter)); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllFoes: case PBEMoveTarget.AllFoesSurrounding: case PBEMoveTarget.AllSurrounding: case PBEMoveTarget.SingleFoeSurrounding: case PBEMoveTarget.SingleNotSelf: case PBEMoveTarget.SingleSurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.FoeCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.AllTeam: case PBEMoveTarget.Self: case PBEMoveTarget.SelfOrAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(targets == PBETarget.AllyCenter); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } case PBEMoveTarget.RandomFoeSurrounding: case PBEMoveTarget.SingleAllySurrounding: { if (pkmn.FieldPosition == PBEFieldPosition.Left || pkmn.FieldPosition == PBEFieldPosition.Center || pkmn.FieldPosition == PBEFieldPosition.Right) { return(true); } else { throw new ArgumentOutOfRangeException(nameof(pkmn.FieldPosition)); } } default: throw new ArgumentOutOfRangeException(nameof(possibleTargets)); } } default: throw new ArgumentOutOfRangeException(nameof(pkmn.Team.Battle.BattleFormat)); } }