/// <summary>Deals damage to <paramref name="victim"/> and broadcasts the HP changing and substitute damage.</summary>
 /// <param name="culprit">The Pokémon responsible for the damage.</param>
 /// <param name="victim">The Pokémon receiving the damage.</param>
 /// <param name="hp">The amount of HP <paramref name="victim"/> will try to lose.</param>
 /// <param name="ignoreSubstitute">Whether the damage should ignore <paramref name="victim"/>'s <see cref="PBEStatus2.Substitute"/>.</param>
 /// <param name="ignoreSturdy">Whether the damage should ignore <paramref name="victim"/>'s <see cref="PBEAbility.Sturdy"/>, <see cref="PBEItem.FocusBand"/>, or <see cref="PBEItem.FocusSash"/>.</param>
 /// <returns>The amount of damage dealt.</returns>
 private ushort DealDamage(PBEPokemon culprit, PBEPokemon victim, int hp, bool ignoreSubstitute, bool ignoreSturdy = false)
 {
     if (hp < 1)
     {
         hp = 1;
     }
     if (!ignoreSubstitute && victim.Status2.HasFlag(PBEStatus2.Substitute))
     {
         ushort oldHP = victim.SubstituteHP;
         victim.SubstituteHP = (ushort)Math.Max(0, victim.SubstituteHP - hp);
         ushort damageAmt = (ushort)(oldHP - victim.SubstituteHP);
         BroadcastStatus2(victim, culprit, PBEStatus2.Substitute, PBEStatusAction.Damage);
         return(damageAmt);
     }
     else
     {
         ushort oldHP         = victim.HP;
         double oldPercentage = victim.HPPercentage;
         victim.HP = (ushort)Math.Max(0, victim.HP - hp);
         bool sturdyHappened = false, focusBandHappened = false, focusSashHappened = false;
         if (!ignoreSturdy && victim.HP == 0)
         {
             // TODO: Endure
             if (oldHP == victim.MaxHP && victim.Ability == PBEAbility.Sturdy && !culprit.HasCancellingAbility())
             {
                 sturdyHappened = true;
                 victim.HP      = 1;
             }
             else if (victim.Item == PBEItem.FocusBand && PBEUtils.RandomBool(10, 100))
             {
                 focusBandHappened = true;
                 victim.HP         = 1;
             }
             else if (oldHP == victim.MaxHP && victim.Item == PBEItem.FocusSash)
             {
                 focusSashHappened = true;
                 victim.HP         = 1;
             }
         }
         victim.HPPercentage = (double)victim.HP / victim.MaxHP;
         BroadcastPkmnHPChanged(victim, oldHP, oldPercentage);
         if (sturdyHappened)
         {
             BroadcastAbility(victim, culprit, PBEAbility.Sturdy, PBEAbilityAction.Damage);
             BroadcastEndure(victim);
         }
         else if (focusBandHappened)
         {
             BroadcastItem(victim, culprit, PBEItem.FocusBand, PBEItemAction.Damage);
         }
         else if (focusSashHappened)
         {
             BroadcastItem(victim, culprit, PBEItem.FocusSash, PBEItemAction.Consumed);
         }
         return((ushort)(oldHP - victim.HP));
     }
 }
Example #2
0
        private PBEPokemon[] GetActingOrder(IEnumerable <PBEPokemon> pokemon, bool ignoreItemsThatActivate)
        {
            var evaluated = new List <(PBEPokemon Pokemon, double Speed)>(); // TODO: Full Incense, Lagging Tail, Stall, Quick Claw

            foreach (PBEPokemon pkmn in pokemon)
            {
                double speed = pkmn.Speed * GetStatChangeModifier(pkmn.SpeedChange, false);

                switch (pkmn.Item)
                {
                case PBEItem.ChoiceScarf:
                {
                    speed *= 1.5;
                    break;
                }

                case PBEItem.MachoBrace:
                case PBEItem.PowerAnklet:
                case PBEItem.PowerBand:
                case PBEItem.PowerBelt:
                case PBEItem.PowerBracer:
                case PBEItem.PowerLens:
                case PBEItem.PowerWeight:
                {
                    speed *= 0.5;
                    break;
                }

                case PBEItem.QuickPowder:
                {
                    if (pkmn.OriginalSpecies == PBESpecies.Ditto && !pkmn.Status2.HasFlag(PBEStatus2.Transformed))
                    {
                        speed *= 2.0;
                    }
                    break;
                }
                }
                if (ShouldDoWeatherEffects())
                {
                    if (Weather == PBEWeather.HarshSunlight && pkmn.Ability == PBEAbility.Chlorophyll)
                    {
                        speed *= 2.0;
                    }
                    if (Weather == PBEWeather.Rain && pkmn.Ability == PBEAbility.SwiftSwim)
                    {
                        speed *= 2.0;
                    }
                    if (Weather == PBEWeather.Sandstorm && pkmn.Ability == PBEAbility.SandRush)
                    {
                        speed *= 2.0;
                    }
                }

                if (pkmn.Ability == PBEAbility.QuickFeet)
                {
                    if (pkmn.Status1 != PBEStatus1.None)
                    {
                        speed *= 1.5;
                    }
                }
                else if (pkmn.Status1 == PBEStatus1.Paralyzed)
                {
                    speed *= 0.25;
                }

                Debug.WriteLine("Team {0}'s {1}'s evaluated speed: {2}", pkmn.Team.Id, pkmn.Nickname, speed);
                (PBEPokemon Pokemon, double Speed)tup = (pkmn, speed);
                if (evaluated.Count == 0)
                {
                    evaluated.Add(tup);
                }
                else
                {
                    int pkmnTiedWith = evaluated.FindIndex(t => t.Speed == speed);
                    if (pkmnTiedWith != -1) // Speed tie - randomly go before or after the Pokémon it tied with
                    {
                        if (PBEUtils.RandomBool())
                        {
                            if (pkmnTiedWith == evaluated.Count - 1)
                            {
                                evaluated.Add(tup);
                            }
                            else
                            {
                                evaluated.Insert(pkmnTiedWith + 1, tup);
                            }
                        }
                        else
                        {
                            evaluated.Insert(pkmnTiedWith, tup);
                        }
                    }
                    else
                    {
                        int pkmnToGoBefore = evaluated.FindIndex(t => BattleStatus.HasFlag(PBEBattleStatus.TrickRoom) ? t.Speed > speed : t.Speed < speed);
                        if (pkmnToGoBefore == -1)
                        {
                            evaluated.Add(tup);
                        }
                        else
                        {
                            evaluated.Insert(pkmnToGoBefore, tup);
                        }
                    }
                }
                Debug.WriteLine(evaluated.Select(t => $"{t.Pokemon.Team.Id} {t.Pokemon.Nickname} {t.Speed}").Print());
            }
            return(evaluated.Select(t => t.Pokemon).ToArray());
        }
Example #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);
        }