/// <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); }
public PBEBattle(PBEBattleFormat battleFormat, PBESettings settings, IEnumerable <PBEPokemonShell> team0Party, IEnumerable <PBEPokemonShell> team1Party) { if (battleFormat >= PBEBattleFormat.MAX) { throw new ArgumentOutOfRangeException(nameof(battleFormat)); } if (team0Party == null) { throw new ArgumentNullException(nameof(team0Party)); } if (team1Party == null) { throw new ArgumentNullException(nameof(team1Party)); } if (team0Party.Count() == 0 || team0Party.Count() > settings.MaxPartySize) { throw new ArgumentOutOfRangeException(nameof(team0Party)); } if (team1Party.Count() == 0 || team1Party.Count() > settings.MaxPartySize) { throw new ArgumentOutOfRangeException(nameof(team1Party)); } BattleFormat = battleFormat; Settings = settings; Teams[0] = new PBETeam(this, 0, team0Party, ref pkmnIdCounter); Teams[1] = new PBETeam(this, 1, team1Party, ref pkmnIdCounter); CheckForReadiness(); }
// Outs are for hit targets that were not behind substitute private static void Hit_HitTargets(PBETeam user, Action <List <PBEAttackVictim> > doSub, Action <List <PBEAttackVictim> > doNormal, List <PBEAttackVictim> victims, out List <PBEAttackVictim> allies, out List <PBEAttackVictim> foes) { List <PBEAttackVictim> subAllies = victims.FindAll(v => { PBEBattlePokemon pkmn = v.Pkmn; return(pkmn.Team == user && pkmn.Status2.HasFlag(PBEStatus2.Substitute)); }); allies = victims.FindAll(v => { PBEBattlePokemon pkmn = v.Pkmn; return(pkmn.Team == user && !pkmn.Status2.HasFlag(PBEStatus2.Substitute)); }); List <PBEAttackVictim> subFoes = victims.FindAll(v => { PBEBattlePokemon pkmn = v.Pkmn; return(pkmn.Team != user && pkmn.Status2.HasFlag(PBEStatus2.Substitute)); }); foes = victims.FindAll(v => { PBEBattlePokemon pkmn = v.Pkmn; return(pkmn.Team != user && !pkmn.Status2.HasFlag(PBEStatus2.Substitute)); }); doSub(subAllies); doNormal(allies); doSub(subFoes); doNormal(foes); }
/// <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); }
internal PBEPokemon(BinaryReader r, PBETeam team) { Team = team; Id = r.ReadByte(); Species = OriginalSpecies = KnownSpecies = (PBESpecies)r.ReadUInt32(); var pData = PBEPokemonData.GetData(Species); KnownType1 = Type1 = pData.Type1; KnownType2 = Type2 = pData.Type2; KnownWeight = Weight = pData.Weight; Nickname = KnownNickname = PBEUtils.StringFromBytes(r); Level = r.ReadByte(); Friendship = r.ReadByte(); Shiny = KnownShiny = r.ReadBoolean(); Ability = OriginalAbility = (PBEAbility)r.ReadByte(); KnownAbility = PBEAbility.MAX; Nature = (PBENature)r.ReadByte(); Gender = KnownGender = (PBEGender)r.ReadByte(); Item = OriginalItem = (PBEItem)r.ReadUInt16(); KnownItem = (PBEItem)ushort.MaxValue; EffortValues = new PBEEffortValues(Team.Battle.Settings, r); IndividualValues = new PBEIndividualValues(Team.Battle.Settings, r); SetStats(); HP = MaxHP; HPPercentage = 1D; OriginalMoveset = new PBEMoveset(Species, Level, Team.Battle.Settings, r); Moves = new PBEBattleMoveset(OriginalMoveset); KnownMoves = new PBEBattleMoveset(Team.Battle.Settings); TransformBackupMoves = new PBEBattleMoveset(Team.Battle.Settings); Team.Party.Add(this); }
// Outs are for hit targets that were not behind substitute private void Hit_HitTargets(PBETeam user, Action <IEnumerable <PBEAttackVictim> > doSub, Action <IEnumerable <PBEAttackVictim> > doNormal, List <PBEAttackVictim> victims, out IEnumerable <PBEAttackVictim> allies, out IEnumerable <PBEAttackVictim> foes) { IEnumerable <PBEAttackVictim> subAllies = victims.Where(v => { PBEBattlePokemon pkmn = v.Pkmn; return(pkmn.Team == user && pkmn.Status2.HasFlag(PBEStatus2.Substitute)); }).ToArray(); allies = victims.Where(v => { PBEBattlePokemon pkmn = v.Pkmn; return(pkmn.Team == user && !pkmn.Status2.HasFlag(PBEStatus2.Substitute)); }).ToArray(); IEnumerable <PBEAttackVictim> subFoes = victims.Where(v => { PBEBattlePokemon pkmn = v.Pkmn; return(pkmn.Team != user && pkmn.Status2.HasFlag(PBEStatus2.Substitute)); }).ToArray(); foes = victims.Where(v => { PBEBattlePokemon pkmn = v.Pkmn; return(pkmn.Team != user && !pkmn.Status2.HasFlag(PBEStatus2.Substitute)); }).ToArray(); doSub(subAllies); doNormal(allies); doSub(subFoes); doNormal(foes); }
internal PBEPokemon(PBETeam team, byte id, PBEPokemonShell shell) { Team = team; Id = id; Species = OriginalSpecies = KnownSpecies = shell.Species; var pData = PBEPokemonData.GetData(Species); KnownType1 = Type1 = pData.Type1; KnownType2 = Type2 = pData.Type2; KnownWeight = Weight = pData.Weight; Nickname = KnownNickname = shell.Nickname; Level = shell.Level; Friendship = shell.Friendship; Shiny = KnownShiny = shell.Shiny; Ability = OriginalAbility = shell.Ability; KnownAbility = PBEAbility.MAX; Nature = shell.Nature; Gender = KnownGender = shell.Gender; Item = OriginalItem = shell.Item; KnownItem = (PBEItem)ushort.MaxValue; EffortValues = new PBEEffortValues(shell.EffortValues); IndividualValues = new PBEIndividualValues(shell.IndividualValues); SetStats(); HP = MaxHP; HPPercentage = 1D; OriginalMoveset = new PBEMoveset(shell.Moveset); Moves = new PBEBattleMoveset(OriginalMoveset); KnownMoves = new PBEBattleMoveset(Team.Battle.Settings); TransformBackupMoves = new PBEBattleMoveset(Team.Battle.Settings); team.Party.Add(this); }
// This constructor is to define a remote Pokémon public PBEPokemon(PBETeam team, PBEPkmnSwitchInPacket.PBESwitchInInfo info) { Team = team; Id = info.PokemonId; FieldPosition = info.FieldPosition; HP = info.HP; MaxHP = info.MaxHP; HPPercentage = info.HPPercentage; Status1 = info.Status1; Level = info.Level; KnownAbility = Ability = OriginalAbility = PBEAbility.MAX; KnownGender = Gender = info.Gender; KnownItem = Item = (PBEItem)ushort.MaxValue; Moves = new PBEMove[Team.Battle.Settings.NumMoves]; KnownMoves = new PBEMove[Team.Battle.Settings.NumMoves]; for (int i = 0; i < Team.Battle.Settings.NumMoves; i++) { KnownMoves[i] = Moves[i] = PBEMove.MAX; } PP = new byte[Team.Battle.Settings.NumMoves]; MaxPP = new byte[Team.Battle.Settings.NumMoves]; KnownNickname = Nickname = info.Nickname; KnownShiny = Shiny = info.Shiny; KnownSpecies = Species = OriginalSpecies = info.Species; var pData = PBEPokemonData.GetData(KnownSpecies); KnownType1 = Type1 = pData.Type1; KnownType2 = Type2 = pData.Type2; KnownWeight = Weight = pData.Weight; Team.Party.Add(this); }
// This constructor is to define a remote Pokémon public PBEPokemon(PBETeam team, PBEPkmnSwitchInPacket.PBESwitchInInfo info) { if (team == null) { throw new ArgumentNullException(nameof(team)); } if (info == null) { throw new ArgumentNullException(nameof(info)); } Team = team; Id = info.PokemonId; FieldPosition = info.FieldPosition; HP = info.HP; MaxHP = info.MaxHP; HPPercentage = info.HPPercentage; Status1 = info.Status1; Level = info.Level; KnownAbility = Ability = OriginalAbility = PBEAbility.MAX; KnownGender = Gender = info.Gender; KnownItem = Item = OriginalItem = (PBEItem)ushort.MaxValue; Moves = new PBEBattleMoveset(Team.Battle.Settings); KnownMoves = new PBEBattleMoveset(Team.Battle.Settings); TransformBackupMoves = new PBEBattleMoveset(Team.Battle.Settings); KnownNickname = Nickname = info.Nickname; KnownShiny = Shiny = info.Shiny; KnownSpecies = Species = OriginalSpecies = info.Species; var pData = PBEPokemonData.GetData(KnownSpecies); KnownType1 = Type1 = pData.Type1; KnownType2 = Type2 = pData.Type2; KnownWeight = Weight = pData.Weight; Team.Party.Add(this); }
// Stats & PP are set from the shell info public PBEPokemon(PBETeam team, byte id, PBEPokemonShell shell) { Team = team; SelectedAction.PokemonId = Id = id; Shell = shell; VisualGender = Shell.Gender; VisualNickname = Shell.Nickname; VisualShiny = Shell.Shiny; VisualSpecies = Shell.Species; Ability = Shell.Ability; Item = Shell.Item; CalculateStats(); HP = MaxHP; HPPercentage = 1.0; Moves = Shell.Moves; PP = new byte[Moves.Length]; MaxPP = new byte[Moves.Length]; for (int i = 0; i < Moves.Length; i++) { PBEMove move = Shell.Moves[i]; if (move != PBEMove.None) { byte tier = PBEMoveData.Data[move].PPTier; PP[i] = MaxPP[i] = (byte)Math.Max(1, (tier * Team.Battle.Settings.PPMultiplier) + (tier * Shell.PPUps[i])); } } PBEPokemonData pData = PBEPokemonData.Data[Shell.Species]; Type1 = pData.Type1; Type2 = pData.Type2; Weight = pData.Weight; Team.Party.Add(this); }
/// <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); }
public PBEBattle(PBEBattleFormat battleFormat, PBESettings settings) { if (battleFormat >= PBEBattleFormat.MAX) { throw new ArgumentOutOfRangeException(nameof(battleFormat)); } BattleFormat = battleFormat; Settings = settings; Teams[0] = new PBETeam(this, 0); Teams[1] = new PBETeam(this, 1); BattleState = PBEBattleState.WaitingForPlayers; OnStateChanged?.Invoke(this); }
/// <summary> /// Sets a specific team's party. <see cref="BattleState"/> will change to <see cref="PBEBattleState.ReadyToBegin"/> if all teams have parties. /// </summary> /// <param name="team">The team which will have its party set.</param> /// <param name="party">The Pokémon party <paramref name="team"/> will use.</param> /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForPlayers"/>.</exception> /// <exception cref="ArgumentNullException">Thrown when <paramref name="party"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="party"/>'s size is invalid.</exception> public static void CreateTeamParty(PBETeam team, IEnumerable <PBEPokemonShell> party) { if (team.Battle.BattleState != PBEBattleState.WaitingForPlayers) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForPlayers} to set a team's party."); } if (party == null) { throw new ArgumentNullException(nameof(party)); } if (party.Count() == 0 || party.Count() > team.Battle.Settings.MaxPartySize) { throw new ArgumentOutOfRangeException(nameof(party)); } team.CreateParty(party, ref team.Battle.pkmnIdCounter); team.Battle.CheckForReadiness(); }
// Stats & PP are set from the shell info internal PBEPokemon(PBETeam team, byte id, PBEPokemonShell shell) { Team = team; SelectedAction.PokemonId = Id = id; Shell = shell; Ability = OriginalAbility = Shell.Ability; KnownAbility = PBEAbility.MAX; Gender = KnownGender = Shell.Gender; Item = Shell.Item; KnownItem = (PBEItem)ushort.MaxValue; Moves = Shell.Moveset.MoveSlots.Select(m => m.Move).ToArray(); KnownMoves = new PBEMove[Team.Battle.Settings.NumMoves]; for (int i = 0; i < Team.Battle.Settings.NumMoves; i++) { KnownMoves[i] = PBEMove.MAX; } Nickname = KnownNickname = Shell.Nickname; Shiny = KnownShiny = Shell.Shiny; Species = OriginalSpecies = KnownSpecies = Shell.Species; var pData = PBEPokemonData.GetData(Species); KnownType1 = Type1 = pData.Type1; KnownType2 = Type2 = pData.Type2; KnownWeight = Weight = pData.Weight; EffortValues = new PBEEffortValueCollection(team.Battle.Settings, shell.EffortValues); IndividualValues = new PBEIndividualValueCollection(team.Battle.Settings, shell.IndividualValues); Friendship = Shell.Friendship; Level = Shell.Level; Nature = Shell.Nature; SetStats(); HP = MaxHP; HPPercentage = 1.0; PP = new byte[team.Battle.Settings.NumMoves]; MaxPP = new byte[team.Battle.Settings.NumMoves]; for (int i = 0; i < team.Battle.Settings.NumMoves; i++) { PBEMove move = Moves[i]; if (move != PBEMove.None) { byte tier = PBEMoveData.Data[move].PPTier; PP[i] = MaxPP[i] = (byte)Math.Max(1, (tier * team.Battle.Settings.PPMultiplier) + (tier * Shell.Moveset.MoveSlots[i].PPUps)); } } team.Party.Add(this); }
public static PBETrainer GetTrainer(this PBETeam team, PBEFieldPosition pos) { PBEBattleFormat format = team.Battle.BattleFormat; VerifyPosition(format, pos); int i = 0; if (team.Trainers.Count != 1) { switch (format) { case PBEBattleFormat.Double: i = pos == PBEFieldPosition.Left ? 0 : 1; break; case PBEBattleFormat.Triple: i = pos == PBEFieldPosition.Left ? 0 : pos == PBEFieldPosition.Center ? 1 : 2; break; } } return(team.Trainers[i]); }
/// <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, IEnumerable <Tuple <byte, PBEFieldPosition> > switches) { 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); } foreach (Tuple <byte, PBEFieldPosition> s in switches) { PBEPokemon pkmn = team.Battle.TryGetPokemon(s.Item1); if (pkmn == null || pkmn.Team != team || pkmn.HP == 0 || pkmn.FieldPosition != PBEFieldPosition.None) { return(false); } } 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); }
// This constructor is to define a remote Pokémon public PBEPokemon(PBETeam team, PBEPkmnSwitchInPacket.PBESwitchInInfo info) { Team = team; Id = info.PokemonId; Shell = new PBEPokemonShell { Species = VisualSpecies = info.Species, Shiny = VisualShiny = info.Shiny, Nickname = VisualNickname = info.Nickname, Level = info.Level, Gender = VisualGender = info.Gender, Ability = Ability = PBEAbility.MAX, Item = Item = (PBEItem)ushort.MaxValue, Nature = PBENature.MAX, Moves = new PBEMove[Team.Battle.Settings.NumMoves], PPUps = new byte[Team.Battle.Settings.NumMoves], EVs = new byte[6], IVs = new byte[6] }; Moves = new PBEMove[Shell.Moves.Length]; PP = new byte[Moves.Length]; MaxPP = new byte[Moves.Length]; for (int i = 0; i < Moves.Length; i++) { Shell.Moves[i] = Moves[i] = PBEMove.MAX; } FieldPosition = info.FieldPosition; HP = info.HP; MaxHP = info.MaxHP; HPPercentage = info.HPPercentage; Status1 = info.Status1; PBEPokemonData pData = PBEPokemonData.Data[Shell.Species]; Type1 = pData.Type1; Type2 = pData.Type2; Weight = pData.Weight; Team.Party.Add(this); }
/// <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, IEnumerable <Tuple <byte, PBEFieldPosition> > switches) { if (team.Battle.BattleState != PBEBattleState.WaitingForSwitchIns) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForSwitchIns} to select switches."); } if (AreSwitchesValid(team, switches)) { team.SwitchInsRequired = 0; foreach (Tuple <byte, PBEFieldPosition> s in switches) { PBEPokemon pkmn = team.Battle.TryGetPokemon(s.Item1); pkmn.FieldPosition = s.Item2; team.SwitchInQueue.Add(pkmn); } if (team.Battle.Teams.All(t => t.SwitchInsRequired == 0)) { team.Battle.SwitchesOrActions(); } return(true); } return(false); }
/// <summary>Sets a specific team's party. <see cref="BattleState"/> will change to <see cref="PBEBattleState.ReadyToBegin"/> if all teams have parties.</summary> /// <param name="team">The team which will have its party set.</param> /// <param name="teamShell">The information <paramref name="team"/> will use to create its party.</param> /// <param name="teamTrainerName">The name of the trainer(s) on <paramref name="team"/>.</param> /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForPlayers"/> or <paramref name="team"/> already has its party set.</exception> /// <exception cref="ArgumentNullException">Thrown when <paramref name="team"/> or <paramref name="teamShell"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="teamShell"/>'s settings are unequal to <paramref name="team"/>'s battle's settings or when <paramref name="teamTrainerName"/> is invalid.</exception> public static void CreateTeamParty(PBETeam team, PBETeamShell teamShell, string teamTrainerName) { if (team == null) { throw new ArgumentNullException(nameof(team)); } if (teamShell == null) { throw new ArgumentNullException(nameof(teamShell)); } if (string.IsNullOrEmpty(teamTrainerName)) { throw new ArgumentOutOfRangeException(nameof(teamTrainerName)); } if (team.IsDisposed) { throw new ObjectDisposedException(nameof(team)); } if (teamShell.IsDisposed) { throw new ObjectDisposedException(nameof(teamShell)); } if (!teamShell.Settings.Equals(team.Battle.Settings)) { throw new ArgumentOutOfRangeException(nameof(teamShell), $"\"{nameof(teamShell)}\"'s settings must be equal to the battle's settings."); } if (team.Battle.BattleState != PBEBattleState.WaitingForPlayers) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForPlayers} to set a team's party."); } if (team.Party.Count > 0) { throw new InvalidOperationException("This team already has its party set."); } team.CreateParty(teamShell, teamTrainerName); team.Battle.CheckForReadiness(); }
/// <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> /// 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, IEnumerable <(byte PokemonId, PBEFieldPosition Position)> switches)
internal static PBEPokemon FromBytes(BinaryReader r, PBETeam team) { return(new PBEPokemon(team, r.ReadByte(), PBEPokemonShell.FromBytes(r, team.Battle.Settings))); }
/// <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 }
/// <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); }
internal static bool SelectActionsIfValid(PBETrainer trainer, IReadOnlyCollection <PBETurnAction> actions, [NotNullWhen(false)] out string?invalidReason) { if (!AreActionsValid(trainer, actions, out invalidReason)) { return(false); } trainer.ActionsRequired.Clear(); foreach (PBETurnAction action in actions) { PBEBattlePokemon pkmn = trainer.GetPokemon(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 = trainer.Battle._rand.RandomBool() ? PBETurnTarget.FoeLeft : PBETurnTarget.FoeRight; break; } case PBEBattleFormat.Triple: { if (pkmn.FieldPosition == PBEFieldPosition.Left) { action.FightTargets = trainer.Battle._rand.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 = trainer.Battle._rand.RandomInt(0, 2); if (r == 0) { if (oppTeam.IsSpotOccupied(PBEFieldPosition.Left)) { action.FightTargets = PBETurnTarget.FoeLeft; } else { goto roll; } } else if (r == 1) { if (oppTeam.IsSpotOccupied(PBEFieldPosition.Center)) { action.FightTargets = PBETurnTarget.FoeCenter; } else { goto roll; } } else { if (oppTeam.IsSpotOccupied(PBEFieldPosition.Right)) { action.FightTargets = PBETurnTarget.FoeRight; } else { goto roll; } } } else { action.FightTargets = trainer.Battle._rand.RandomBool() ? PBETurnTarget.FoeLeft : PBETurnTarget.FoeCenter; } break; } default: throw new InvalidDataException(nameof(trainer.Battle.BattleFormat)); } } pkmn.TurnAction = action; } if (trainer.Battle.Trainers.All(t => t.ActionsRequired.Count == 0)) { trainer.Battle.BattleState = PBEBattleState.ReadyToRunTurn; } return(true); }
/// <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> /// 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.Battle.TryGetPokemon(action.PokemonId); if (!team.ActionsRequired.Contains(pkmn)) { return(false); } switch (action.Decision) { case PBEDecision.Fight: { if (action.FightMove == PBEMove.Struggle && pkmn.IsForcedToStruggle()) { continue; } else { if (action.FightMove == PBEMove.None || !pkmn.Moves.Contains(action.FightMove) || pkmn.PP[Array.IndexOf(pkmn.Moves, action.FightMove)] == 0) { return(false); } else if ((pkmn.TempLockedMove != PBEMove.None && pkmn.TempLockedMove != action.FightMove) || (pkmn.TempLockedTargets != PBETarget.None && pkmn.TempLockedTargets != action.FightTargets)) { return(false); } else if (pkmn.ChoiceLockedMove != PBEMove.None && pkmn.ChoiceLockedMove != action.FightMove) { return(false); } else if (!AreTargetsValid(pkmn, action.FightMove, action.FightTargets)) { return(false); } } break; } case PBEDecision.SwitchOut: { if (pkmn.Status2.HasFlag(PBEStatus2.Airborne) || pkmn.Status2.HasFlag(PBEStatus2.Underground) || pkmn.Status2.HasFlag(PBEStatus2.Underwater) ) { return(false); } PBEPokemon switchPkmn = team.Battle.TryGetPokemon(action.SwitchPokemonId); if (switchPkmn == null || switchPkmn.Team != team || switchPkmn.Id == pkmn.Id || switchPkmn.HP == 0 || switchPkmn.FieldPosition != PBEFieldPosition.None || standBy.Contains(switchPkmn) ) { return(false); } else { standBy.Add(switchPkmn); } break; } } } return(true); }