// Trainer battle internal PBETeam(PBEBattle battle, byte id, IReadOnlyList <PBETrainerInfo> ti, List <PBETrainer> allTrainers) { int count = ti.Count; if (!VerifyTrainerCount(battle.BattleFormat, count)) { throw new ArgumentException($"Illegal trainer count (Format: {battle.BattleFormat}, Team: {id}, Count: {count}"); } foreach (PBETrainerInfo t in ti) { if (!t.IsOkayForSettings(battle.Settings)) { throw new ArgumentOutOfRangeException(nameof(ti), "Team settings do not comply with battle settings."); } } Battle = battle; Id = id; var trainers = new PBETrainer[ti.Count]; for (int i = 0; i < ti.Count; i++) { trainers[i] = new PBETrainer(this, ti[i], allTrainers); } Trainers = new ReadOnlyCollection <PBETrainer>(trainers); }
/// <summary>Determines whether chosen switches are valid.</summary> /// <param name="trainer">The trainer 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(PBETrainer trainer, IReadOnlyList <PBESwitchIn> switches) { if (trainer == null) { throw new ArgumentNullException(nameof(trainer)); } if (switches == null || switches.Any(s => s == null)) { throw new ArgumentNullException(nameof(switches)); } if (trainer.Battle.BattleState != PBEBattleState.WaitingForSwitchIns) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForSwitchIns} to validate switches."); } if (trainer.SwitchInsRequired == 0 || switches.Count != trainer.SwitchInsRequired) { return(false); } var verified = new List <PBEBattlePokemon>(trainer.SwitchInsRequired); foreach (PBESwitchIn s in switches) { if (s.Position == PBEFieldPosition.None || s.Position >= PBEFieldPosition.MAX || !trainer.OwnsSpot(s.Position)) { return(false); } PBEBattlePokemon pkmn = trainer.TryGetPokemon(s.PokemonId); if (pkmn == null || pkmn.HP == 0 || pkmn.FieldPosition != PBEFieldPosition.None || verified.Contains(pkmn)) { return(false); } verified.Add(pkmn); } return(true); }
internal static string SelectFleeIfValid(PBETrainer trainer) { string valid = IsFleeValid(trainer); if (valid is null) { trainer.RequestedFlee = true; if (trainer.Battle._battleState == PBEBattleState.WaitingForActions) { trainer.ActionsRequired.Clear(); if (trainer.Battle.Trainers.All(t => t.ActionsRequired.Count == 0)) { trainer.Battle.BattleState = PBEBattleState.ReadyToRunTurn; } } else { trainer.SwitchInsRequired = 0; if (trainer.Battle.Trainers.All(t => t.SwitchInsRequired == 0)) { trainer.Battle.BattleState = PBEBattleState.ReadyToRunSwitches; } } } return(valid); }
internal static string IsFleeValid(PBETrainer trainer) { if (trainer.Battle.BattleType != PBEBattleType.Wild) { throw new InvalidOperationException($"{nameof(BattleType)} must be {PBEBattleType.Wild} to flee."); } if (trainer.Battle._battleState == PBEBattleState.WaitingForActions) { if (trainer.ActionsRequired.Count == 0) { return("Actions were already submitted"); } PBEBattlePokemon pkmn = trainer.ActiveBattlersOrdered.First(); if (pkmn.TempLockedMove != PBEMove.None) { return($"Pokémon {pkmn.Id} must use {pkmn.TempLockedMove}"); } } else if (trainer.Battle._battleState == PBEBattleState.WaitingForSwitchIns) { if (trainer.SwitchInsRequired == 0) { return("Switches were already submitted"); } } else { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} or {PBEBattleState.WaitingForSwitchIns} to flee."); } return(null); }
internal static bool SelectFleeIfValid(PBETrainer trainer, [NotNullWhen(false)] out string?invalidReason) { if (!IsFleeValid(trainer, out invalidReason)) { return(false); } trainer.RequestedFlee = true; if (trainer.Battle._battleState == PBEBattleState.WaitingForActions) { trainer.ActionsRequired.Clear(); if (trainer.Battle.Trainers.All(t => t.ActionsRequired.Count == 0)) { trainer.Battle.BattleState = PBEBattleState.ReadyToRunTurn; } } else // WaitingForSwitches { trainer.SwitchInsRequired = 0; if (trainer.Battle.Trainers.All(t => t.SwitchInsRequired == 0)) { trainer.Battle.BattleState = PBEBattleState.ReadyToRunSwitches; } } return(true); }
public static PBEBattle LoadReplay(string path) { byte[] fileBytes = File.ReadAllBytes(path); using (var s = new MemoryStream(fileBytes)) using (var r = new EndianBinaryReader(s, encoding: EncodingType.UTF16)) { byte[] hash; using (var md5 = MD5.Create()) { hash = md5.ComputeHash(fileBytes, 0, fileBytes.Length - 16); } for (int i = 0; i < 16; i++) { if (hash[i] != fileBytes[fileBytes.Length - 16 + i]) { throw new InvalidDataException(); } } ushort version = r.ReadUInt16(); // Unused for now int seed = r.ReadInt32(); // Unused for now PBEBattle b = null; int numEvents = r.ReadInt32(); for (int i = 0; i < numEvents; i++) { IPBEPacket packet = PBEPacketProcessor.CreatePacket(b, r.ReadBytes(r.ReadUInt16())); if (packet is PBEBattlePacket bp) { b = new PBEBattle(bp); } else if (packet is PBEWildPkmnAppearedPacket wpap) { PBETrainer wildTrainer = b.Teams[1].Trainers[0]; foreach (PBEPkmnAppearedInfo info in wpap.Pokemon) { PBEBattlePokemon pkmn = wildTrainer.TryGetPokemon(info.Pokemon); // Process disguise and position now pkmn.FieldPosition = info.FieldPosition; if (info.IsDisguised) { pkmn.Status2 |= PBEStatus2.Disguised; pkmn.KnownCaughtBall = info.CaughtBall; pkmn.KnownGender = info.Gender; pkmn.KnownNickname = info.Nickname; pkmn.KnownShiny = info.Shiny; pkmn.KnownSpecies = info.Species; pkmn.KnownForm = info.Form; IPBEPokemonData pData = PBEDataProvider.Instance.GetPokemonData(info); pkmn.KnownType1 = pData.Type1; pkmn.KnownType2 = pData.Type2; } b.ActiveBattlers.Add(pkmn); } } b.Events.Add(packet); } b.BattleState = PBEBattleState.Ended; return(b); } }
public static int GetFieldPositionIndex(this PBETrainer trainer, PBEFieldPosition position) { if (!trainer.OwnsSpot(position)) { throw new ArgumentOutOfRangeException(nameof(position)); } PBEBattleFormat battleFormat = trainer.Battle.BattleFormat; int index = trainer.Team.Trainers.IndexOf(trainer); switch (battleFormat) { case PBEBattleFormat.Single: { switch (position) { case PBEFieldPosition.Center: return(0); } break; } case PBEBattleFormat.Double: { switch (position) { case PBEFieldPosition.Left: return(0); case PBEFieldPosition.Right: return(index == 1 ? 0 : 1); } break; } case PBEBattleFormat.Triple: { switch (position) { case PBEFieldPosition.Left: return(0); case PBEFieldPosition.Center: return(index == 1 ? 0 : 1); case PBEFieldPosition.Right: return(index == 2 ? 0 : 2); } break; } case PBEBattleFormat.Rotation: { switch (position) { case PBEFieldPosition.Center: return(0); case PBEFieldPosition.Left: return(1); case PBEFieldPosition.Right: return(2); } break; } } throw new Exception(); }
internal static bool AreSwitchesValid(PBETrainer trainer, IReadOnlyCollection <PBESwitchIn> switches, [NotNullWhen(false)] out string?invalidReason) { if (trainer.Battle._battleState != PBEBattleState.WaitingForSwitchIns) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForSwitchIns} to validate switches."); } if (trainer.SwitchInsRequired == 0) { invalidReason = "Switches were already submitted"; return(false); } if (switches.Count != trainer.SwitchInsRequired) { invalidReason = $"Invalid amount of switches submitted; required amount is {trainer.SwitchInsRequired}"; return(false); } var verified = new List <PBEBattlePokemon>(trainer.SwitchInsRequired); foreach (PBESwitchIn s in switches) { if (s.Position == PBEFieldPosition.None || s.Position >= PBEFieldPosition.MAX || !trainer.OwnsSpot(s.Position)) { invalidReason = $"Invalid position ({s.PokemonId})"; return(false); } if (!trainer.TryGetPokemon(s.PokemonId, out PBEBattlePokemon? pkmn)) { invalidReason = $"Invalid Pokémon ID ({s.PokemonId})"; return(false); } if (pkmn.HP == 0) { invalidReason = $"Pokémon {s.PokemonId} is fainted"; return(false); } if (pkmn.PBEIgnore) { invalidReason = $"Pokémon {s.PokemonId} cannot battle"; return(false); } if (pkmn.FieldPosition != PBEFieldPosition.None) { invalidReason = $"Pokémon {s.PokemonId} is already on the field"; return(false); } if (verified.Contains(pkmn)) { invalidReason = $"Pokémon {s.PokemonId} was asked to be switched in multiple times"; return(false); } verified.Add(pkmn); } invalidReason = null; return(true); }
internal static string AreSwitchesValid(PBETrainer trainer, IReadOnlyCollection <PBESwitchIn> switches) { if (switches == null || switches.Any(s => s == null)) { throw new ArgumentNullException(nameof(switches)); } if (trainer.Battle._battleState != PBEBattleState.WaitingForSwitchIns) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForSwitchIns} to validate switches."); } if (trainer.SwitchInsRequired == 0) { return("Switches were already submitted"); } if (switches.Count != trainer.SwitchInsRequired) { return($"Invalid amount of switches submitted; required amount is {trainer.SwitchInsRequired}"); } var verified = new List <PBEBattlePokemon>(trainer.SwitchInsRequired); foreach (PBESwitchIn s in switches) { if (s.Position == PBEFieldPosition.None || s.Position >= PBEFieldPosition.MAX || !trainer.OwnsSpot(s.Position)) { return($"Invalid position ({s.PokemonId})"); } PBEBattlePokemon pkmn = trainer.TryGetPokemon(s.PokemonId); if (pkmn is null) { return($"Invalid Pokémon ID ({s.PokemonId})"); } if (pkmn.HP == 0) { return($"Pokémon {s.PokemonId} is fainted"); } if (pkmn.FieldPosition != PBEFieldPosition.None) { return($"Pokémon {s.PokemonId} is already on the field"); } if (verified.Contains(pkmn)) { return($"Pokémon {s.PokemonId} was asked to be switched in multiple times"); } verified.Add(pkmn); } return(null); }
internal static bool SelectSwitchesIfValid(PBETrainer trainer, IReadOnlyCollection <PBESwitchIn> switches, [NotNullWhen(false)] out string?invalidReason) { if (!AreSwitchesValid(trainer, switches, out invalidReason)) { return(false); } trainer.SwitchInsRequired = 0; foreach (PBESwitchIn s in switches) { trainer.SwitchInQueue.Add((trainer.GetPokemon(s.PokemonId), s.Position)); } if (trainer.Battle.Trainers.All(t => t.SwitchInsRequired == 0)) { trainer.Battle.BattleState = PBEBattleState.ReadyToRunSwitches; } return(true); }
internal static string SelectSwitchesIfValid(PBETrainer trainer, IReadOnlyCollection <PBESwitchIn> switches) { string valid = AreSwitchesValid(trainer, switches); if (valid is null) { trainer.SwitchInsRequired = 0; foreach (PBESwitchIn s in switches) { PBEBattlePokemon pkmn = trainer.TryGetPokemon(s.PokemonId); trainer.SwitchInQueue.Add((pkmn, s.Position)); } if (trainer.Battle.Trainers.All(t => t.SwitchInsRequired == 0)) { trainer.Battle.BattleState = PBEBattleState.ReadyToRunSwitches; } } return(valid); }
// Remote battle internal PBETeam(PBEBattle battle, PBEBattlePacket.PBETeamInfo info, List <PBETrainer> allTrainers) { ReadOnlyCollection <PBEBattlePacket.PBETeamInfo.PBETrainerInfo> ti = info.Trainers; int count = ti.Count; if (!VerifyTrainerCount(battle.BattleFormat, count)) { throw new InvalidDataException(); } Battle = battle; Id = info.Id; var trainers = new PBETrainer[ti.Count]; for (int i = 0; i < trainers.Length; i++) { trainers[i] = new PBETrainer(this, ti[i], allTrainers); } Trainers = new ReadOnlyCollection <PBETrainer>(trainers); }
/// <summary>Selects switches if they are valid. Changes the battle state if both teams have selected valid switches.</summary> /// <param name="trainer">The trainer 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(PBETrainer trainer, IReadOnlyList <PBESwitchIn> switches) { if (AreSwitchesValid(trainer, switches)) { trainer.SwitchInsRequired = 0; foreach (PBESwitchIn s in switches) { PBEBattlePokemon pkmn = trainer.TryGetPokemon(s.PokemonId); trainer.SwitchInQueue.Add((pkmn, s.Position)); } if (trainer.Battle.Trainers.All(t => t.SwitchInsRequired == 0)) { trainer.Battle.BattleState = PBEBattleState.ReadyToRunSwitches; trainer.Battle.OnStateChanged?.Invoke(trainer.Battle); } return(true); } return(false); }
// Remote battle internal PBETeam(PBEBattle battle, PBEBattlePacket.PBETeamInfo info, List <PBETrainer> allTrainers) { ReadOnlyCollection <PBEBattlePacket.PBETeamInfo.PBETrainerInfo> ti = info.Trainers; int count = ti.Count; if (!VerifyTrainerCount(battle.BattleFormat, count)) { throw new InvalidDataException(); } Battle = battle; Id = info.Id; var trainers = new PBETrainer[ti.Count]; for (int i = 0; i < trainers.Length; i++) { trainers[i] = new PBETrainer(this, ti[i], allTrainers); } Trainers = new ReadOnlyCollection <PBETrainer>(trainers); CombinedName = GetCombinedName(); OpposingTeam = null !; // OpposingTeam is set in PBETeams after both are created }
internal static bool IsFleeValid(PBETrainer trainer, [NotNullWhen(false)] out string?invalidReason) { if (trainer.Battle.BattleType != PBEBattleType.Wild) { throw new InvalidOperationException($"{nameof(BattleType)} must be {PBEBattleType.Wild} to flee."); } switch (trainer.Battle._battleState) { case PBEBattleState.WaitingForActions: { if (trainer.ActionsRequired.Count == 0) { invalidReason = "Actions were already submitted"; return(false); } PBEBattlePokemon pkmn = trainer.ActiveBattlersOrdered.First(); if (pkmn.TempLockedMove != PBEMove.None) { invalidReason = $"Pokémon {pkmn.Id} must use {pkmn.TempLockedMove}"; return(false); } break; } case PBEBattleState.WaitingForSwitchIns: { if (trainer.SwitchInsRequired == 0) { invalidReason = "Switches were already submitted"; return(false); } break; } default: throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} or {PBEBattleState.WaitingForSwitchIns} to flee."); } invalidReason = null; return(true); }
internal static bool AreActionsValid(PBETrainer trainer, IReadOnlyCollection <PBETurnAction> actions, [NotNullWhen(false)] out string?invalidReason) { if (trainer.Battle._battleState != PBEBattleState.WaitingForActions) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} to validate actions."); } if (trainer.ActionsRequired.Count == 0) { invalidReason = "Actions were already submitted"; return(false); } if (actions.Count != trainer.ActionsRequired.Count) { invalidReason = $"Invalid amount of actions submitted; required amount is {trainer.ActionsRequired.Count}"; return(false); } var verified = new List <PBEBattlePokemon>(trainer.ActionsRequired.Count); var standBy = new List <PBEBattlePokemon>(trainer.ActionsRequired.Count); var items = new Dictionary <PBEItem, int>(trainer.ActionsRequired.Count); foreach (PBETurnAction action in actions) { if (!trainer.TryGetPokemon(action.PokemonId, out PBEBattlePokemon? pkmn)) { invalidReason = $"Invalid Pokémon ID ({action.PokemonId})"; return(false); } if (!trainer.ActionsRequired.Contains(pkmn)) { invalidReason = $"Pokémon {action.PokemonId} not looking for actions"; return(false); } if (verified.Contains(pkmn)) { invalidReason = $"Pokémon {action.PokemonId} was multiple actions"; return(false); } switch (action.Decision) { case PBETurnDecision.Fight: { if (Array.IndexOf(pkmn.GetUsableMoves(), action.FightMove) == -1) { invalidReason = $"{action.FightMove} is not usable by Pokémon {action.PokemonId}"; return(false); } if (action.FightMove == pkmn.TempLockedMove && action.FightTargets != pkmn.TempLockedTargets) { invalidReason = $"Pokémon {action.PokemonId} must target {pkmn.TempLockedTargets}"; return(false); } if (!AreTargetsValid(pkmn, action.FightMove, action.FightTargets)) { invalidReason = $"Invalid move targets for Pokémon {action.PokemonId}'s {action.FightMove}"; return(false); } break; } case PBETurnDecision.Item: { if (pkmn.TempLockedMove != PBEMove.None) { invalidReason = $"Pokémon {action.PokemonId} must use {pkmn.TempLockedMove}"; return(false); } if (!trainer.Inventory.TryGetValue(action.UseItem, out PBEBattleInventory.PBEBattleInventorySlot? slot)) { invalidReason = $"Trainer \"{trainer.Name}\" does not have any {action.UseItem}"; // Handles wild Pokémon return(false); } bool used = items.TryGetValue(action.UseItem, out int amtUsed); if (!used) { amtUsed = 0; } long newAmt = slot.Quantity - amtUsed; if (newAmt <= 0) { invalidReason = $"Tried to use too many {action.UseItem}"; return(false); } if (trainer.Battle.BattleType == PBEBattleType.Wild && trainer.Team.OpposingTeam.ActiveBattlers.Count > 1 && PBEDataUtils.AllBalls.Contains(action.UseItem)) { invalidReason = $"Cannot throw a ball at multiple wild Pokémon"; return(false); } amtUsed++; if (used) { items[action.UseItem] = amtUsed; } else { items.Add(action.UseItem, amtUsed); } break; } case PBETurnDecision.SwitchOut: { if (!pkmn.CanSwitchOut()) { invalidReason = $"Pokémon {action.PokemonId} cannot switch out"; return(false); } if (!trainer.TryGetPokemon(action.SwitchPokemonId, out PBEBattlePokemon? switchPkmn)) { invalidReason = $"Invalid switch Pokémon ID ({action.PokemonId})"; return(false); } if (switchPkmn.HP == 0) { invalidReason = $"Switch Pokémon {action.PokemonId} is fainted"; return(false); } if (switchPkmn.PBEIgnore) { invalidReason = $"Switch Pokémon {action.PokemonId} cannot battle"; return(false); } if (switchPkmn.FieldPosition != PBEFieldPosition.None) { invalidReason = $"Switch Pokémon {action.PokemonId} is already on the field"; return(false); } if (standBy.Contains(switchPkmn)) { invalidReason = $"Switch Pokémon {action.PokemonId} was asked to be switched in multiple times"; return(false); } standBy.Add(switchPkmn); break; } default: { invalidReason = $"Invalid turn decision ({action.Decision})"; return(false); } } verified.Add(pkmn); } invalidReason = null; return(true); }
public static bool SelectSwitchesIfValid(PBETrainer trainer, params PBESwitchIn[] switches) { return(SelectSwitchesIfValid(trainer, (IReadOnlyList <PBESwitchIn>)switches)); }
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); }
public static bool AreSwitchesValid(PBETrainer trainer, params PBESwitchIn[] switches) { return(AreSwitchesValid(trainer, (IReadOnlyList <PBESwitchIn>)switches)); }
/// <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); }
public static bool SelectActionsIfValid(PBETrainer trainer, params PBETurnAction[] actions) { return(SelectActionsIfValid(trainer, (IReadOnlyList <PBETurnAction>)actions)); }
/// <summary>Determines whether chosen actions are valid.</summary> /// <param name="trainer">The trainer 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(PBETrainer trainer, IReadOnlyList <PBETurnAction> actions) { if (trainer == null) { throw new ArgumentNullException(nameof(trainer)); } if (actions == null || actions.Any(a => a == null)) { throw new ArgumentNullException(nameof(actions)); } if (trainer.Battle.BattleState != PBEBattleState.WaitingForActions) { throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} to validate actions."); } if (trainer.ActionsRequired.Count == 0 || actions.Count != trainer.ActionsRequired.Count) { return(false); } var verified = new List <PBEBattlePokemon>(trainer.ActionsRequired.Count); var standBy = new List <PBEBattlePokemon>(trainer.ActionsRequired.Count); foreach (PBETurnAction action in actions) { PBEBattlePokemon pkmn = trainer.TryGetPokemon(action.PokemonId); if (pkmn == null || !trainer.ActionsRequired.Contains(pkmn) || verified.Contains(pkmn)) { return(false); } switch (action.Decision) { case PBETurnDecision.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 PBETurnDecision.SwitchOut: { if (!pkmn.CanSwitchOut()) { return(false); } PBEBattlePokemon switchPkmn = trainer.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); } standBy.Add(switchPkmn); break; } default: return(false); } verified.Add(pkmn); } return(true); }
public static bool AreActionsValid(PBETrainer trainer, params PBETurnAction[] actions) { return(AreActionsValid(trainer, (IReadOnlyList <PBETurnAction>)actions)); }
public static bool OwnsSpot(this PBETrainer trainer, PBEFieldPosition pos) { return(GetTrainer(trainer.Team, pos) == trainer); }
private void SwitchesOrActions() { BattleState = PBEBattleState.Processing; OnStateChanged?.Invoke(this); // Checking SwitchInQueue count since SwitchInsRequired is set to 0 after submitting switches PBETrainer[] trainersWithSwitchIns = Trainers.Where(t => t.SwitchInQueue.Count > 0).ToArray(); if (trainersWithSwitchIns.Length > 0) { var list = new List <PBEBattlePokemon>(6); foreach (PBETrainer trainer in trainersWithSwitchIns) { int count = trainer.SwitchInQueue.Count; var switches = new PBEPkmnSwitchInPacket.PBESwitchInInfo[count]; for (int i = 0; i < count; i++) { (PBEBattlePokemon pkmn, PBEFieldPosition pos) = trainer.SwitchInQueue[i]; pkmn.FieldPosition = pos; switches[i] = CreateSwitchInInfo(pkmn); PBETrainer.SwitchTwoPokemon(pkmn, pos); ActiveBattlers.Add(pkmn); // Add before broadcast list.Add(pkmn); } BroadcastPkmnSwitchIn(trainer, switches); } DoSwitchInEffects(list); } foreach (PBETrainer trainer in Trainers) { int available = trainer.NumConsciousPkmn - trainer.NumPkmnOnField; trainer.SwitchInsRequired = 0; trainer.SwitchInQueue.Clear(); if (available > 0) { switch (BattleFormat) { case PBEBattleFormat.Single: { if (trainer.TryGetPokemon(PBEFieldPosition.Center) == null) { trainer.SwitchInsRequired = 1; } break; } case PBEBattleFormat.Double: { if (trainer.OwnsSpot(PBEFieldPosition.Left) && trainer.TryGetPokemon(PBEFieldPosition.Left) == null) { available--; trainer.SwitchInsRequired++; } if (available > 0 && trainer.OwnsSpot(PBEFieldPosition.Right) && trainer.TryGetPokemon(PBEFieldPosition.Right) == null) { trainer.SwitchInsRequired++; } break; } case PBEBattleFormat.Rotation: case PBEBattleFormat.Triple: { if (trainer.OwnsSpot(PBEFieldPosition.Left) && trainer.TryGetPokemon(PBEFieldPosition.Left) == null) { available--; trainer.SwitchInsRequired++; } if (available > 0 && trainer.OwnsSpot(PBEFieldPosition.Center) && trainer.TryGetPokemon(PBEFieldPosition.Center) == null) { available--; trainer.SwitchInsRequired++; } if (available > 0 && trainer.OwnsSpot(PBEFieldPosition.Right) && trainer.TryGetPokemon(PBEFieldPosition.Right) == null) { trainer.SwitchInsRequired++; } break; } default: throw new ArgumentOutOfRangeException(nameof(BattleFormat)); } } } trainersWithSwitchIns = Trainers.Where(t => t.SwitchInsRequired > 0).ToArray(); if (trainersWithSwitchIns.Length > 0) { BattleState = PBEBattleState.WaitingForSwitchIns; OnStateChanged?.Invoke(this); foreach (PBETrainer trainer in trainersWithSwitchIns) { BroadcastSwitchInRequest(trainer); } } else { if (WinCheck()) { return; } foreach (PBEBattlePokemon pkmn in ActiveBattlers) { pkmn.HasUsedMoveThisTurn = false; pkmn.TurnAction = null; pkmn.SpeedBoost_AbleToSpeedBoostThisTurn = pkmn.Ability == PBEAbility.SpeedBoost; if (pkmn.Status2.HasFlag(PBEStatus2.Flinching)) { BroadcastStatus2(pkmn, pkmn, PBEStatus2.Flinching, PBEStatusAction.Ended); } if (pkmn.Status2.HasFlag(PBEStatus2.HelpingHand)) { BroadcastStatus2(pkmn, pkmn, PBEStatus2.HelpingHand, PBEStatusAction.Ended); } if (pkmn.Status2.HasFlag(PBEStatus2.LockOn)) { if (--pkmn.LockOnTurns == 0) { pkmn.LockOnPokemon = null; BroadcastStatus2(pkmn, pkmn, PBEStatus2.LockOn, PBEStatusAction.Ended); } } if (pkmn.Protection_Used) { pkmn.Protection_Counter++; pkmn.Protection_Used = false; if (pkmn.Status2.HasFlag(PBEStatus2.Protected)) { BroadcastStatus2(pkmn, pkmn, PBEStatus2.Protected, PBEStatusAction.Ended); } } else { pkmn.Protection_Counter = 0; } if (pkmn.Status2.HasFlag(PBEStatus2.Roost)) { pkmn.EndRoost(); BroadcastStatus2(pkmn, pkmn, PBEStatus2.Roost, PBEStatusAction.Ended); } } foreach (PBETeam team in Teams) { if (team.TeamStatus.HasFlag(PBETeamStatus.QuickGuard)) { BroadcastTeamStatus(team, PBETeamStatus.QuickGuard, PBETeamStatusAction.Ended); } if (team.TeamStatus.HasFlag(PBETeamStatus.WideGuard)) { BroadcastTeamStatus(team, PBETeamStatus.WideGuard, PBETeamStatusAction.Ended); } } foreach (PBETrainer trainer in Trainers) { trainer.ActionsRequired.Clear(); trainer.ActionsRequired.AddRange(trainer.ActiveBattlers); } if (BattleFormat == PBEBattleFormat.Triple && Teams.All(t => t.NumConsciousPkmn == 1)) { PBEBattlePokemon pkmn0 = ActiveBattlers[0], pkmn1 = ActiveBattlers[1]; if ((pkmn0.FieldPosition == PBEFieldPosition.Left && pkmn1.FieldPosition == PBEFieldPosition.Left) || (pkmn0.FieldPosition == PBEFieldPosition.Right && pkmn1.FieldPosition == PBEFieldPosition.Right)) { PBEFieldPosition pkmn0OldPos = pkmn0.FieldPosition, pkmn1OldPos = pkmn1.FieldPosition; pkmn0.FieldPosition = PBEFieldPosition.Center; pkmn1.FieldPosition = PBEFieldPosition.Center; BroadcastAutoCenter(pkmn0, pkmn0OldPos, pkmn1, pkmn1OldPos); } } TurnNumber++; BroadcastTurnBegan(); foreach (PBETeam team in Teams) { bool old = team.MonFaintedThisTurn; // Fire events in a specific order team.MonFaintedThisTurn = false; team.MonFaintedLastTurn = old; } BattleState = PBEBattleState.WaitingForActions; OnStateChanged?.Invoke(this); foreach (PBETrainer trainer in Trainers.Where(t => t.NumConsciousPkmn > 0)) { BroadcastActionsRequest(trainer); } } }