Exemple #1
0
        // 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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
 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);
 }
Exemple #6
0
 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);
        }
Exemple #9
0
        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);
 }
Exemple #11
0
        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);
        }
Exemple #12
0
        // 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);
 }
Exemple #14
0
        // 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);
 }
Exemple #25
0
        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);
                }
            }
        }