Пример #1
0
        private ushort CalculateDamage(PBEPokemon user, PBEPokemon target, PBEMove move, PBEType moveType, PBEMoveCategory moveCategory, double basePower, bool criticalHit)
        {
            ushort damage;
            double a = 0, d = 0;

            bool unawareA = user != target && target.Ability == PBEAbility.Unaware && !user.HasCancellingAbility();
            bool unawareD = user != target && user.Ability == PBEAbility.Unaware && !target.HasCancellingAbility(); // Verified: A target with Mold Breaker will accept more damage from a user with Unaware

            switch (move)
            {
            case PBEMove.FoulPlay:
            {
                double aMod = unawareA ? 1 : GetStatChangeModifier(criticalHit ? Math.Max((sbyte)0, target.AttackChange) : target.AttackChange, false);
                a = CalculateAttack(user, target, moveType, target.Attack * aMod);
                double dMod = unawareD ? 1 : GetStatChangeModifier(criticalHit ? Math.Min((sbyte)0, target.DefenseChange) : target.DefenseChange, false);
                d = CalculateDefense(user, target, target.Defense * dMod);
                break;
            }

            case PBEMove.Psyshock:
            case PBEMove.Psystrike:
            case PBEMove.SecretSword:
            {
                double aMod = unawareA ? 1 : GetStatChangeModifier(criticalHit ? Math.Max((sbyte)0, user.SpAttackChange) : user.SpAttackChange, false);
                a = CalculateSpAttack(user, target, moveType, user.SpAttack * aMod);
                double dMod = unawareD ? 1 : GetStatChangeModifier(criticalHit ? Math.Min((sbyte)0, target.DefenseChange) : target.DefenseChange, false);
                d = CalculateDefense(user, target, target.Defense * dMod);
                break;
            }

            default:
            {
                if (moveCategory == PBEMoveCategory.Physical)
                {
                    double aMod = unawareA ? 1 : GetStatChangeModifier(criticalHit ? Math.Max((sbyte)0, user.AttackChange) : user.AttackChange, false);
                    a = CalculateAttack(user, target, moveType, user.Attack * aMod);
                    double dMod = unawareD ? 1 : GetStatChangeModifier(criticalHit ? Math.Min((sbyte)0, target.DefenseChange) : target.DefenseChange, false);
                    d = CalculateDefense(user, target, target.Defense * dMod);
                }
                else if (moveCategory == PBEMoveCategory.Special)
                {
                    double aMod = unawareA ? 1 : GetStatChangeModifier(criticalHit ? Math.Max((sbyte)0, user.SpAttackChange) : user.SpAttackChange, false);
                    a = CalculateSpAttack(user, target, moveType, user.SpAttack * aMod);
                    double dMod = unawareD ? 1 : GetStatChangeModifier(criticalHit ? Math.Min((sbyte)0, target.SpDefenseChange) : target.SpDefenseChange, false);
                    d = CalculateSpDefense(user, target, target.SpDefense * dMod);
                }
                break;
            }
            }

            damage  = (ushort)((2 * user.Level / 5) + 2);
            damage  = (ushort)(damage * a * basePower / d);
            damage /= 50;
            damage += 2;
            return((ushort)(damage * (100 - PBEUtils.RandomInt(0, 15)) / 100));
        }
Пример #2
0
        private double CalculateBasePower(PBEPokemon user, PBEPokemon[] targets, PBEMove move, PBEType moveType)
        {
            PBEMoveData mData = PBEMoveData.Data[move];
            // Get move's base power
            double basePower;

            switch (move)
            {
            case PBEMove.CrushGrip:
            case PBEMove.WringOut:
            {
                PBEPokemon target = targets[0];
                basePower = Math.Max(1, 120 * target.HP / target.MaxHP);
                break;
            }

            case PBEMove.Eruption:
            case PBEMove.WaterSpout:
            {
                basePower = Math.Max(1, mData.Power * user.HP / user.MaxHP);
                break;
            }

            case PBEMove.Flail:
            case PBEMove.Reversal:
            {
                int val = 48 * user.HP / user.MaxHP;
                if (val < 2)
                {
                    basePower = 200;
                }
                else if (val < 4)
                {
                    basePower = 150;
                }
                else if (val < 8)
                {
                    basePower = 100;
                }
                else if (val < 16)
                {
                    basePower = 80;
                }
                else if (val < 32)
                {
                    basePower = 40;
                }
                else
                {
                    basePower = 20;
                }
                break;
            }

            case PBEMove.Frustration:
            {
                basePower = Math.Max(1, (byte.MaxValue - user.Friendship) / 2.5);
                break;
            }

            case PBEMove.GrassKnot:
            case PBEMove.LowKick:
            {
                PBEPokemon target = targets[0];
                if (target.Weight >= 200.0)
                {
                    basePower = 120;
                }
                else if (target.Weight >= 100.0)
                {
                    basePower = 100;
                }
                else if (target.Weight >= 50.0)
                {
                    basePower = 80;
                }
                else if (target.Weight >= 25.0)
                {
                    basePower = 60;
                }
                else if (target.Weight >= 10.0)
                {
                    basePower = 40;
                }
                else
                {
                    basePower = 20;
                }
                break;
            }

            case PBEMove.HeatCrash:
            case PBEMove.HeavySlam:
            {
                PBEPokemon target   = targets[0];
                double     relative = user.Weight / target.Weight;
                if (relative < 2)
                {
                    basePower = 40;
                }
                else if (relative < 3)
                {
                    basePower = 60;
                }
                else if (relative < 4)
                {
                    basePower = 80;
                }
                else if (relative < 5)
                {
                    basePower = 100;
                }
                else
                {
                    basePower = 120;
                }
                break;
            }

            case PBEMove.HiddenPower:
            {
                basePower = user.IndividualValues.HiddenPowerBasePower;
                break;
            }

            case PBEMove.Magnitude:
            {
                int  val = PBEUtils.RandomInt(0, 99);
                byte magnitude;
                if (val < 5)     // Magnitude 4 - 5%
                {
                    magnitude = 4;
                    basePower = 10;
                }
                else if (val < 15)     // Magnitude 5 - 10%
                {
                    magnitude = 5;
                    basePower = 30;
                }
                else if (val < 35)     // Magnitude 6 - 20%
                {
                    magnitude = 6;
                    basePower = 50;
                }
                else if (val < 65)     // Magnitude 7 - 30%
                {
                    magnitude = 7;
                    basePower = 70;
                }
                else if (val < 85)     // Magnitude 8 - 20%
                {
                    magnitude = 8;
                    basePower = 90;
                }
                else if (val < 95)     // Magnitude 9 - 10%
                {
                    magnitude = 9;
                    basePower = 110;
                }
                else     // Magnitude 10 - 5%
                {
                    magnitude = 10;
                    basePower = 150;
                }
                BroadcastMagnitude(magnitude);
                break;
            }

            case PBEMove.Punishment:
            {
                PBEPokemon target = targets[0];
                basePower = Math.Max(1, Math.Min(200, 60 + (20 * target.GetPositiveStatTotal())));
                break;
            }

            case PBEMove.Return:
            {
                basePower = Math.Max(1, user.Friendship / 2.5);
                break;
            }

            case PBEMove.StoredPower:
            {
                basePower = mData.Power + (20 * user.GetPositiveStatTotal());
                break;
            }

            default:
            {
                basePower = mData.Power;
                break;
            }
            }

            // Ability/Item-specific power boosts
            bool canUseGems = !mData.Flags.HasFlag(PBEMoveFlag.UnaffectedByGems);

            switch (moveType)
            {
            case PBEType.Bug:
            {
                if (user.Ability == PBEAbility.Swarm && user.HP <= user.MaxHP / 3)
                {
                    basePower *= 1.5;
                }
                switch (user.Item)
                {
                case PBEItem.InsectPlate:
                case PBEItem.SilverPowder:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.BugGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.BugGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Dark:
            {
                switch (user.Item)
                {
                case PBEItem.BlackGlasses:
                case PBEItem.DreadPlate:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.DarkGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.DarkGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Dragon:
            {
                switch (user.Item)
                {
                case PBEItem.AdamantOrb:
                {
                    if (user.OriginalSpecies == PBESpecies.Dialga)
                    {
                        basePower *= 1.2;
                    }
                    break;
                }

                case PBEItem.DracoPlate:
                case PBEItem.DragonFang:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.GriseousOrb:
                {
                    if (user.OriginalSpecies == PBESpecies.Giratina_Origin)
                    {
                        basePower *= 1.2;
                    }
                    break;
                }

                case PBEItem.LustrousOrb:
                {
                    if (user.OriginalSpecies == PBESpecies.Palkia)
                    {
                        basePower *= 1.2;
                    }
                    break;
                }

                case PBEItem.DragonGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.DragonGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Electric:
            {
                switch (user.Item)
                {
                case PBEItem.Magnet:
                case PBEItem.ZapPlate:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.ElectricGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.ElectricGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Fighting:
            {
                switch (user.Item)
                {
                case PBEItem.BlackBelt:
                case PBEItem.FistPlate:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.FightingGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.FightingGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Fire:
            {
                switch (user.Item)
                {
                case PBEItem.Charcoal:
                case PBEItem.FlamePlate:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.FireGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.FireGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Flying:
            {
                switch (user.Item)
                {
                case PBEItem.SharpBeak:
                case PBEItem.SkyPlate:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.FlyingGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.FlyingGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Ghost:
            {
                switch (user.Item)
                {
                case PBEItem.GriseousOrb:
                {
                    if (user.OriginalSpecies == PBESpecies.Giratina_Origin)
                    {
                        basePower *= 1.2;
                    }
                    break;
                }

                case PBEItem.SpellTag:
                case PBEItem.SpookyPlate:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.GhostGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.GhostGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Grass:
            {
                switch (user.Item)
                {
                case PBEItem.MeadowPlate:
                case PBEItem.MiracleSeed:
                case PBEItem.RoseIncense:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.GrassGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.GrassGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Ground:
            {
                switch (user.Item)
                {
                case PBEItem.EarthPlate:
                case PBEItem.SoftSand:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.GroundGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.GroundGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Ice:
            {
                switch (user.Item)
                {
                case PBEItem.IciclePlate:
                case PBEItem.NeverMeltIce:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.IceGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.IceGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.None:
            {
                break;
            }

            case PBEType.Normal:
            {
                switch (user.Item)
                {
                case PBEItem.SilkScarf:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.NormalGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.NormalGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Poison:
            {
                switch (user.Item)
                {
                case PBEItem.PoisonBarb:
                case PBEItem.ToxicPlate:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.PoisonGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.PoisonGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Psychic:
            {
                switch (user.Item)
                {
                case PBEItem.MindPlate:
                case PBEItem.OddIncense:
                case PBEItem.TwistedSpoon:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.PsychicGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.PsychicGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Rock:
            {
                switch (user.Item)
                {
                case PBEItem.HardStone:
                case PBEItem.RockIncense:
                case PBEItem.StonePlate:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.RockGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.RockGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Steel:
            {
                switch (user.Item)
                {
                case PBEItem.AdamantOrb:
                {
                    if (user.OriginalSpecies == PBESpecies.Dialga)
                    {
                        basePower *= 1.2;
                    }
                    break;
                }

                case PBEItem.IronPlate:
                case PBEItem.MetalCoat:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.SteelGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.SteelGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            case PBEType.Water:
            {
                switch (user.Item)
                {
                case PBEItem.LustrousOrb:
                {
                    if (user.OriginalSpecies == PBESpecies.Palkia)
                    {
                        basePower *= 1.2;
                    }
                    break;
                }

                case PBEItem.MysticWater:
                case PBEItem.SeaIncense:
                case PBEItem.SplashPlate:
                case PBEItem.WaveIncense:
                {
                    basePower *= 1.2;
                    break;
                }

                case PBEItem.WaterGem:
                {
                    if (canUseGems)
                    {
                        BroadcastItem(user, user, PBEItem.WaterGem, PBEItemAction.Consumed);
                        basePower *= 1.5;
                    }
                    break;
                }
                }
                break;
            }

            default: throw new ArgumentOutOfRangeException(nameof(moveType));
            }

            // Move-specific power boosts
            switch (move)
            {
            case PBEMove.Acrobatics:
            {
                if (user.Item == PBEItem.None)
                {
                    basePower *= 2.0;
                }
                break;
            }

            case PBEMove.Brine:
            {
                PBEPokemon target = targets[0];
                if (target.HP <= target.HP / 2)
                {
                    basePower *= 2.0;
                }
                break;
            }

            case PBEMove.Facade:
            {
                if (user.Status1 == PBEStatus1.Burned || user.Status1 == PBEStatus1.Paralyzed || user.Status1 == PBEStatus1.Poisoned || user.Status1 == PBEStatus1.BadlyPoisoned)
                {
                    basePower *= 2.0;
                }
                break;
            }

            case PBEMove.Hex:
            {
                PBEPokemon target = targets[0];
                if (target.Status1 != PBEStatus1.None)
                {
                    basePower *= 2.0;
                }
                break;
            }

            case PBEMove.Retaliate:
            {
                if (user.Team.MonFaintedLastTurn)
                {
                    basePower *= 2.0;
                }
                break;
            }

            case PBEMove.Venoshock:
            {
                PBEPokemon target = targets[0];
                if (target.Status1 == PBEStatus1.Poisoned || target.Status1 == PBEStatus1.BadlyPoisoned)
                {
                    basePower *= 2.0;
                }
                break;
            }

            case PBEMove.WeatherBall:
            {
                if (ShouldDoWeatherEffects() && Weather != PBEWeather.None)
                {
                    basePower *= 2.0;
                }
                break;
            }
            }

            // Weather-specific power boosts
            if (ShouldDoWeatherEffects())
            {
                switch (Weather)
                {
                case PBEWeather.HarshSunlight:
                {
                    if (moveType == PBEType.Fire)
                    {
                        basePower *= 1.5;
                    }
                    else if (moveType == PBEType.Water)
                    {
                        basePower *= 0.5;
                    }
                    break;
                }

                case PBEWeather.Rain:
                {
                    if (moveType == PBEType.Water)
                    {
                        basePower *= 1.5;
                    }
                    else if (moveType == PBEType.Fire)
                    {
                        basePower *= 0.5;
                    }
                    break;
                }

                case PBEWeather.Sandstorm:
                {
                    if (user.Ability == PBEAbility.SandForce && (user.HasType(PBEType.Rock) || user.HasType(PBEType.Ground) || user.HasType(PBEType.Steel)))
                    {
                        basePower *= 1.3;
                    }
                    break;
                }
                }
            }

            // Other power boosts
            if (user.Status2.HasFlag(PBEStatus2.HelpingHand))
            {
                basePower *= 1.5;
            }
            if (user.Ability == PBEAbility.ToxicBoost && mData.Category == PBEMoveCategory.Physical && (user.Status1 == PBEStatus1.Poisoned || user.Status1 == PBEStatus1.BadlyPoisoned))
            {
                basePower *= 1.5;
            }
            if (user.Item == PBEItem.LifeOrb)
            {
                basePower *= 1.3;
            }
            if (user.Ability == PBEAbility.IronFist && mData.Flags.HasFlag(PBEMoveFlag.AffectedByIronFist))
            {
                basePower *= 1.2;
            }
            if (user.Ability == PBEAbility.Reckless && mData.Flags.HasFlag(PBEMoveFlag.AffectedByReckless))
            {
                basePower *= 1.2;
            }
            if (mData.Category == PBEMoveCategory.Physical && user.Item == PBEItem.MuscleBand)
            {
                basePower *= 1.1;
            }
            if (mData.Category == PBEMoveCategory.Special && user.Item == PBEItem.WiseGlasses)
            {
                basePower *= 1.1;
            }

            return(basePower);
        }
Пример #3
0
        /// <summary>Selects actions if they are valid. Changes the battle state if both teams have selected valid actions.</summary>
        /// <param name="team">The team the inputted actions belong to.</param>
        /// <param name="actions">The actions the team wishes to execute.</param>
        /// <returns>True if the actions are valid and were selected.</returns>
        /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForActions"/>.</exception>
        public static bool SelectActionsIfValid(PBETeam team, IList <PBETurnAction> actions)
        {
            if (team == null)
            {
                throw new ArgumentNullException(nameof(team));
            }
            if (actions == null)
            {
                throw new ArgumentNullException(nameof(actions));
            }
            if (team.IsDisposed)
            {
                throw new ObjectDisposedException(nameof(team));
            }
            if (team.Battle.BattleState != PBEBattleState.WaitingForActions)
            {
                throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} to select actions.");
            }
            if (AreActionsValid(team, actions))
            {
                lock (team.Battle._disposeLockObj)
                {
                    if (!team.Battle.IsDisposed)
                    {
                        team.ActionsRequired.Clear();
                        foreach (PBETurnAction action in actions)
                        {
                            PBEPokemon pkmn = team.TryGetPokemon(action.PokemonId);
                            if (action.Decision == PBETurnDecision.Fight && pkmn.GetMoveTargets(action.FightMove) == PBEMoveTarget.RandomFoeSurrounding)
                            {
                                switch (team.Battle.BattleFormat)
                                {
                                case PBEBattleFormat.Single:
                                case PBEBattleFormat.Rotation:
                                {
                                    action.FightTargets = PBETurnTarget.FoeCenter;
                                    break;
                                }

                                case PBEBattleFormat.Double:
                                {
                                    action.FightTargets = PBEUtils.RandomBool() ? PBETurnTarget.FoeLeft : PBETurnTarget.FoeRight;
                                    break;
                                }

                                case PBEBattleFormat.Triple:
                                {
                                    if (pkmn.FieldPosition == PBEFieldPosition.Left)
                                    {
                                        action.FightTargets = PBEUtils.RandomBool() ? PBETurnTarget.FoeCenter : PBETurnTarget.FoeRight;
                                    }
                                    else if (pkmn.FieldPosition == PBEFieldPosition.Center)
                                    {
                                        int r;     // Keep randomly picking until a non-fainted foe is selected
roll:
                                        r = PBEUtils.RandomInt(0, 2);
                                        if (r == 0)
                                        {
                                            if (team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Left) != null)
                                            {
                                                action.FightTargets = PBETurnTarget.FoeLeft;
                                            }
                                            else
                                            {
                                                goto roll;
                                            }
                                        }
                                        else if (r == 1)
                                        {
                                            if (team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Center) != null)
                                            {
                                                action.FightTargets = PBETurnTarget.FoeCenter;
                                            }
                                            else
                                            {
                                                goto roll;
                                            }
                                        }
                                        else
                                        {
                                            if (team.OpposingTeam.TryGetPokemon(PBEFieldPosition.Right) != null)
                                            {
                                                action.FightTargets = PBETurnTarget.FoeRight;
                                            }
                                            else
                                            {
                                                goto roll;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        action.FightTargets = PBEUtils.RandomBool() ? PBETurnTarget.FoeLeft : PBETurnTarget.FoeCenter;
                                    }
                                    break;
                                }

                                default: throw new ArgumentOutOfRangeException(nameof(team.Battle.BattleFormat));
                                }
                            }
                            pkmn.TurnAction = action;
                        }
                        if (team.Battle.Teams.All(t => t.ActionsRequired.Count == 0))
                        {
                            team.Battle.BattleState = PBEBattleState.ReadyToRunTurn;
                            team.Battle.OnStateChanged?.Invoke(team.Battle);
                        }
                        return(true);
                    }
                }
            }
            return(false);
        }
        /// <summary>
        /// Selects actions if they are valid. Changes the battle state if both teams have selected valid actions.
        /// </summary>
        /// <param name="team">The team the inputted actions belong to.</param>
        /// <param name="actions">The actions the team wishes to execute.</param>
        /// <returns>True if the actions are valid and were selected.</returns>
        /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForActions"/>.</exception>
        public static bool SelectActionsIfValid(PBETeam team, IEnumerable <PBEAction> actions)
        {
            if (team.Battle.BattleState != PBEBattleState.WaitingForActions)
            {
                throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} to select actions.");
            }
            if (AreActionsValid(team, actions))
            {
                team.ActionsRequired.Clear();
                foreach (PBEAction action in actions)
                {
                    PBEPokemon pkmn = team.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.RandomBool() ? PBETarget.FoeLeft : PBETarget.FoeRight;
                                break;
                            }

                            case PBEBattleFormat.Triple:
                            {
                                if (pkmn.FieldPosition == PBEFieldPosition.Left)
                                {
                                    pkmn.SelectedAction.FightTargets = PBEUtils.RandomBool() ? 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.RandomInt(0, 2);
                                    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.RandomBool() ? PBETarget.FoeLeft : PBETarget.FoeCenter;
                                }
                                break;
                            }
                            }
                            break;
                        }
                        }
                        break;
                    }
                    }
                }
                if (Array.TrueForAll(team.Battle.Teams, t => t.ActionsRequired.Count == 0))
                {
                    team.Battle.BattleState = PBEBattleState.ReadyToRunTurn;
                    team.Battle.OnStateChanged?.Invoke(team.Battle);
                }
                return(true);
            }
            return(false);
        }