/// <summary>Determines whether chosen switches are valid.</summary>
        /// <param name="team">The team the inputted switches belong to.</param>
        /// <param name="switches">The switches the team wishes to execute.</param>
        /// <returns>False if the team already chose switches or the switches are illegal, True otherwise.</returns>
        /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForSwitchIns"/>.</exception>
        public static bool AreSwitchesValid(PBETeam team, IList <PBESwitchIn> switches)
        {
            if (team == null)
            {
                throw new ArgumentNullException(nameof(team));
            }
            if (switches == null || switches.Any(s => s == null))
            {
                throw new ArgumentNullException(nameof(switches));
            }
            if (team.IsDisposed)
            {
                throw new ObjectDisposedException(nameof(team));
            }
            if (team.Battle.BattleState != PBEBattleState.WaitingForSwitchIns)
            {
                throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForSwitchIns} to validate switches.");
            }
            if (team.SwitchInsRequired == 0 || switches.Count != team.SwitchInsRequired)
            {
                return(false);
            }
            var verified = new List <PBEPokemon>(team.SwitchInsRequired);

            foreach (PBESwitchIn s in switches)
            {
                PBEPokemon pkmn = team.TryGetPokemon(s.PokemonId);
                if (pkmn == null || pkmn.HP == 0 || pkmn.FieldPosition != PBEFieldPosition.None || verified.Contains(pkmn))
                {
                    return(false);
                }
                verified.Add(pkmn);
            }
            return(true);
        }
 /// <summary>Selects switches if they are valid. Changes the battle state if both teams have selected valid switches.</summary>
 /// <param name="team">The team the inputted switches belong to.</param>
 /// <param name="switches">The switches the team wishes to execute.</param>
 /// <returns>True if the switches are valid and were selected.</returns>
 /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForSwitchIns"/>.</exception>
 public static bool SelectSwitchesIfValid(PBETeam team, IList <PBESwitchIn> switches)
 {
     if (AreSwitchesValid(team, switches))
     {
         lock (team.Battle._disposeLockObj)
         {
             if (!team.Battle.IsDisposed)
             {
                 team.SwitchInsRequired = 0;
                 foreach (PBESwitchIn s in switches)
                 {
                     PBEPokemon pkmn = team.TryGetPokemon(s.PokemonId);
                     pkmn.FieldPosition = s.Position;
                     team.SwitchInQueue.Add(pkmn);
                 }
                 if (team.Battle.Teams.All(t => t.SwitchInsRequired == 0))
                 {
                     team.Battle.SwitchesOrActions();
                 }
                 return(true);
             }
         }
     }
     return(false);
 }
 /// <summary>
 /// Transforms into <paramref name="target"/> and sets <see cref="PBEStatus2.Transformed"/>.
 /// </summary>
 /// <param name="target">The Pokémon to transform into.</param>
 /// <remarks>Frees the Pokémon of its <see cref="ChoiceLockedMove"/>.</remarks>
 public void Transform(PBEPokemon target)
 {
     if (Team != target.Team)
     {
         KnownAbility = target.KnownAbility = Ability = target.Ability;
         KnownType1   = target.KnownType1 = Type1 = target.Type1;
         KnownType2   = target.KnownType2 = Type2 = target.Type2;
         KnownWeight  = target.KnownWeight = Weight = target.Weight;
     }
     else
     {
         Ability      = target.Ability;
         KnownAbility = target.KnownAbility;
         Type1        = target.Type1;
         KnownType1   = target.KnownType1;
         Type2        = target.Type2;
         KnownType2   = target.KnownType2;
         Weight       = target.Weight;
         KnownWeight  = target.KnownWeight;
     }
     KnownGender       = target.KnownGender = target.Gender;
     KnownShiny        = target.KnownShiny = target.Shiny;
     KnownSpecies      = target.KnownSpecies = Species = target.Species;
     Attack            = target.Attack;
     Defense           = target.Defense;
     SpAttack          = target.SpAttack;
     SpDefense         = target.SpDefense;
     Speed             = target.Speed;
     AttackChange      = target.AttackChange;
     DefenseChange     = target.DefenseChange;
     SpAttackChange    = target.SpAttackChange;
     SpDefenseChange   = target.SpDefenseChange;
     SpeedChange       = target.SpeedChange;
     AccuracyChange    = target.AccuracyChange;
     EvasionChange     = target.EvasionChange;
     PreTransformMoves = (PBEMove[])Moves.Clone();
     PreTransformPP    = (byte[])PP.Clone();
     PreTransformMaxPP = (byte[])MaxPP.Clone();
     for (int i = 0; i < Team.Battle.Settings.NumMoves; i++)
     {
         if (Team != target.Team)
         {
             KnownMoves[i] = target.KnownMoves[i] = Moves[i] = target.Moves[i];
         }
         else
         {
             Moves[i]      = target.Moves[i];
             KnownMoves[i] = target.KnownMoves[i];
         }
         if (Id != byte.MaxValue) // Don't set PP if this is a client's unknown remote Pokémon
         {
             PP[i] = MaxPP[i] = (byte)(Moves[i] == PBEMove.None ? 0 : PBEMoveData.Data[Moves[i]].PPTier == 0 ? 1 : Team.Battle.Settings.PPMultiplier);
         }
     }
     if (!Moves.Contains(ChoiceLockedMove))
     {
         ChoiceLockedMove = PBEMove.None;
     }
     Status2 |= PBEStatus2.Transformed;
 }
 public bool CanBecomePoisonedBy(PBEPokemon other)
 {
     return(Status1 == PBEStatus1.None &&
            !HasType(PBEType.Poison) &&
            !HasType(PBEType.Steel) &&
            !(Ability == PBEAbility.Immunity && !other.HasCancellingAbility()));
 }
Esempio n. 5
0
        private double CalculateSpDefense(PBEPokemon user, PBEPokemon target, double initialSpDefense)
        {
            double spDefense = initialSpDefense;

            if (target.Item == PBEItem.DeepSeaScale && target.OriginalSpecies == PBESpecies.Clamperl)
            {
                spDefense *= 2.0;
            }
            if (target.Item == PBEItem.SoulDew && (target.OriginalSpecies == PBESpecies.Latias || target.OriginalSpecies == PBESpecies.Latios))
            {
                spDefense *= 1.5;
            }
            if (target.Item == PBEItem.Eviolite && PBEPokemonData.GetData(target.OriginalSpecies).Evolutions.Count > 0)
            {
                spDefense *= 1.5;
            }
            if (ShouldDoWeatherEffects())
            {
                if (Weather == PBEWeather.Sandstorm && target.HasType(PBEType.Rock))
                {
                    spDefense *= 1.5;
                }
                if (!user.HasCancellingAbility() && Weather == PBEWeather.HarshSunlight && Array.Exists(target.Team.ActiveBattlers, p => p.Ability == PBEAbility.FlowerGift))
                {
                    spDefense *= 1.5;
                }
            }

            return(spDefense);
        }
        private void TypeCheck(PBEPokemon user, PBEPokemon target, PBEType moveType, out PBEEffectiveness moveEffectiveness, ref double moveEffectivenessMultiplier, bool ignoreWonderGuard)
        {
            double m = PBEPokemonData.TypeEffectiveness[moveType][target.Type1];

            m *= PBEPokemonData.TypeEffectiveness[moveType][target.Type2];

            if (m <= 0) // (-infinity, 0]
            {
                moveEffectiveness = PBEEffectiveness.Ineffective;
            }
            else if (m < 1) // (0, 1)
            {
                moveEffectiveness = PBEEffectiveness.NotVeryEffective;
            }
            else if (m == 1.0) // [1, 1]
            {
                moveEffectiveness = PBEEffectiveness.Normal;
            }
            else // (1, infinity)
            {
                moveEffectiveness = PBEEffectiveness.SuperEffective;
            }
            moveEffectivenessMultiplier *= m;

            if (moveEffectiveness != PBEEffectiveness.Ineffective)
            {
                if ((target.Ability == PBEAbility.Levitate && moveType == PBEType.Ground) ||
                    (!ignoreWonderGuard && target.Ability == PBEAbility.WonderGuard && moveEffectiveness != PBEEffectiveness.SuperEffective))
                {
                    moveEffectiveness           = PBEEffectiveness.Ineffective;
                    moveEffectivenessMultiplier = 0;
                    BroadcastAbility(target, target, target.Ability, PBEAbilityAction.Damage);
                }
            }
        }
Esempio n. 7
0
 /// <summary>
 /// Transforms into <paramref name="target"/> and sets <see cref="PBEStatus2.Transformed"/>.
 /// </summary>
 /// <param name="target">The Pokémon to transform into.</param>
 /// <remarks>Frees the Pokémon of its <see cref="ChoiceLockedMove"/>.</remarks>
 public void Transform(PBEPokemon target)
 {
     VisualSpecies   = target.Shell.Species;
     VisualShiny     = target.Shell.Shiny;
     VisualGender    = target.Shell.Gender;
     Ability         = target.Ability;
     Type1           = target.Type1;
     Type2           = target.Type2;
     Weight          = target.Weight;
     Attack          = target.Attack;
     Defense         = target.Defense;
     SpAttack        = target.SpAttack;
     SpDefense       = target.SpDefense;
     Speed           = target.Speed;
     AttackChange    = target.AttackChange;
     DefenseChange   = target.DefenseChange;
     SpAttackChange  = target.SpAttackChange;
     SpDefenseChange = target.SpDefenseChange;
     SpeedChange     = target.SpeedChange;
     AccuracyChange  = target.AccuracyChange;
     EvasionChange   = target.EvasionChange;
     Moves           = (PBEMove[])target.Moves.Clone();
     if (Id != byte.MaxValue)
     {
         for (int i = 0; i < Moves.Length; i++)
         {
             PP[i] = MaxPP[i] = (byte)(Moves[i] == PBEMove.None ? 0 : PBEMoveData.Data[Moves[i]].PPTier == 0 ? 1 : Team.Battle.Settings.PPMultiplier);
         }
     }
     if (!Moves.Contains(ChoiceLockedMove))
     {
         ChoiceLockedMove = PBEMove.None;
     }
     Status2 |= PBEStatus2.Transformed;
 }
Esempio n. 8
0
        private double CalculateAttack(PBEPokemon user, PBEPokemon target, PBEType moveType, double initialAttack)
        {
            double attack = initialAttack;

            if (user.Ability == PBEAbility.HugePower || user.Ability == PBEAbility.PurePower)
            {
                attack *= 2.0;
            }
            if (user.Item == PBEItem.ThickClub && (user.OriginalSpecies == PBESpecies.Cubone || user.OriginalSpecies == PBESpecies.Marowak))
            {
                attack *= 2.0;
            }
            if (user.Item == PBEItem.LightBall && user.OriginalSpecies == PBESpecies.Pikachu)
            {
                attack *= 2.0;
            }
            if (moveType == PBEType.Fire && user.Ability == PBEAbility.Blaze && user.HP <= user.MaxHP / 3)
            {
                attack *= 1.5;
            }
            if (moveType == PBEType.Grass && user.Ability == PBEAbility.Overgrow && user.HP <= user.MaxHP / 3)
            {
                attack *= 1.5;
            }
            if (moveType == PBEType.Water && user.Ability == PBEAbility.Torrent && user.HP <= user.MaxHP / 3)
            {
                attack *= 1.5;
            }
            if (user.Ability == PBEAbility.Hustle)
            {
                attack *= 1.5;
            }
            if (user.Ability == PBEAbility.Guts && user.Status1 != PBEStatus1.None)
            {
                attack *= 1.5;
            }
            if (user.Item == PBEItem.ChoiceBand)
            {
                attack *= 1.5;
            }
            if (!user.HasCancellingAbility() && ShouldDoWeatherEffects() && Weather == PBEWeather.HarshSunlight && Array.Exists(user.Team.ActiveBattlers, p => p.Ability == PBEAbility.FlowerGift))
            {
                attack *= 1.5;
            }
            if ((moveType == PBEType.Fire || moveType == PBEType.Ice) && target.Ability == PBEAbility.ThickFat && !user.HasCancellingAbility())
            {
                attack *= 0.5;
            }
            if (user.Ability == PBEAbility.Defeatist && user.HP <= user.MaxHP / 2)
            {
                attack *= 0.5;
            }
            if (user.Ability == PBEAbility.SlowStart && user.SlowStart_HinderTurnsLeft > 0)
            {
                attack *= 0.5;
            }

            return(attack);
        }
        /// <summary>
        /// Determines whether chosen actions are valid.
        /// </summary>
        /// <param name="team">The team the inputted actions belong to.</param>
        /// <param name="actions">The actions the team wishes to execute.</param>
        /// <returns>False if the team already chose actions or the actions are illegal, True otherwise.</returns>
        /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForActions"/>.</exception>
        public static bool AreActionsValid(PBETeam team, IEnumerable <PBEAction> actions)
        {
            if (team.Battle.BattleState != PBEBattleState.WaitingForActions)
            {
                throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForActions} to validate actions.");
            }
            if (team.ActionsRequired.Count == 0 || actions.Count() != team.ActionsRequired.Count)
            {
                return(false);
            }
            var standBy = new List <PBEPokemon>();

            foreach (PBEAction action in actions)
            {
                PBEPokemon pkmn = team.TryGetPokemon(action.PokemonId);
                if (!team.ActionsRequired.Contains(pkmn))
                {
                    return(false);
                }
                switch (action.Decision)
                {
                case PBEDecision.Fight:
                {
                    if (Array.IndexOf(pkmn.GetUsableMoves(), action.FightMove) == -1 ||
                        (action.FightMove == pkmn.TempLockedMove && action.FightTargets != pkmn.TempLockedTargets) ||
                        !AreTargetsValid(pkmn, action.FightMove, action.FightTargets)
                        )
                    {
                        return(false);
                    }
                    break;
                }

                case PBEDecision.SwitchOut:
                {
                    if (!pkmn.CanSwitchOut())
                    {
                        return(false);
                    }
                    PBEPokemon switchPkmn = team.TryGetPokemon(action.SwitchPokemonId);
                    if (switchPkmn == null ||
                        switchPkmn.HP == 0 ||
                        switchPkmn.FieldPosition != PBEFieldPosition.None ||     // Also takes care of trying to switch into yourself
                        standBy.Contains(switchPkmn)
                        )
                    {
                        return(false);
                    }
                    else
                    {
                        standBy.Add(switchPkmn);
                    }
                    break;
                }
                }
            }
            return(true);
        }
Esempio n. 10
0
 /// <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));
     }
 }
 public bool CanBecomeParalyzedBy(PBEPokemon other)
 {
     if (other == null)
     {
         throw new ArgumentNullException(nameof(other));
     }
     return(Status1 == PBEStatus1.None &&
            !(Ability == PBEAbility.Limber && !other.HasCancellingAbility()));
 }
 public bool CanBecomeConfusedBy(PBEPokemon other)
 {
     if (other == null)
     {
         throw new ArgumentNullException(nameof(other));
     }
     return(!Status2.HasFlag(PBEStatus2.Confused) &&
            !(Ability == PBEAbility.OwnTempo && !other.HasCancellingAbility()));
 }
 public bool CanFallAsleepFrom(PBEPokemon other)
 {
     if (other == null)
     {
         throw new ArgumentNullException(nameof(other));
     }
     return(Status1 == PBEStatus1.None &&
            !(Ability == PBEAbility.Insomnia && !other.HasCancellingAbility()));
 }
 public bool CanFlinchFrom(PBEPokemon other)
 {
     if (other == null)
     {
         throw new ArgumentNullException(nameof(other));
     }
     return(!Status2.HasFlag(PBEStatus2.Flinching) &&
            !(Ability == PBEAbility.InnerFocus && !other.HasCancellingAbility()));
 }
Esempio n. 15
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));
        }
 public bool CanBecomeFrozenBy(PBEPokemon other)
 {
     if (other == null)
     {
         throw new ArgumentNullException(nameof(other));
     }
     return(Status1 == PBEStatus1.None &&
            !HasType(PBEType.Ice) &&
            !(Ability == PBEAbility.MagmaArmor && !other.HasCancellingAbility()));
 }
 /// <summary>Returns True if the Pokémon can become <see cref="PBEStatus2.Infatuated"/> with <paramref name="other"/>.</summary>
 public bool CanBecomeInfatuatedWith(PBEPokemon other)
 {
     if (other == null)
     {
         throw new ArgumentNullException(nameof(other));
     }
     return(!Status2.HasFlag(PBEStatus2.Infatuated) &&
            ((Gender == PBEGender.Male && other.Gender == PBEGender.Female) || (Gender == PBEGender.Female && other.Gender == PBEGender.Male)) &&
            !(Ability == PBEAbility.Oblivious && !other.HasCancellingAbility()));
 }
 // TODO: Make different public versions that use Known*? AIs should not be able to cheat
 public bool CanBecomeBurnedBy(PBEPokemon other)
 {
     if (other == null)
     {
         throw new ArgumentNullException(nameof(other));
     }
     return(Status1 == PBEStatus1.None &&
            !HasType(PBEType.Fire) &&
            !(Ability == PBEAbility.WaterVeil && !other.HasCancellingAbility()));
 }
 public bool CanBecomePoisonedBy(PBEPokemon other)
 {
     if (other == null)
     {
         throw new ArgumentNullException(nameof(other));
     }
     return(Status1 == PBEStatus1.None &&
            !HasType(PBEType.Poison) &&
            !HasType(PBEType.Steel) &&
            !(Ability == PBEAbility.Immunity && !other.HasCancellingAbility()));
 }
Esempio n. 20
0
 /// <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>
 ushort DealDamage(PBEPokemon culprit, PBEPokemon victim, ushort hp, bool ignoreSubstitute, bool ignoreSturdy = false)
 {
     if (!ignoreSubstitute && victim.Status2.HasFlag(PBEStatus2.Substitute))
     {
         ushort oldHP = victim.SubstituteHP;
         victim.SubstituteHP = (ushort)Math.Max(0, victim.SubstituteHP - Math.Max((ushort)1, hp)); // Always lose at least 1 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 - Math.Max((ushort)1, hp)); // Always lose at least 1 HP
         bool sturdyHappened = false, focusBandHappened = false, focusSashHappened = false;
         if (!ignoreSturdy && victim.HP == 0)
         {
             // TODO: Endure
             if (oldHP == victim.MaxHP && victim.Ability == PBEAbility.Sturdy) // TODO: Mold Breaker
             {
                 sturdyHappened = true;
                 victim.HP      = 1;
             }
             else if (victim.Item == PBEItem.FocusBand && PBEUtils.RNG.ApplyChance(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)
         {
             victim.Item = PBEItem.None;
             BroadcastItem(victim, culprit, PBEItem.FocusSash, PBEItemAction.Consumed);
         }
         return((ushort)(oldHP - victim.HP));
     }
 }
Esempio n. 21
0
        private double CalculateSpAttack(PBEPokemon user, PBEPokemon target, PBEType moveType, double initialSpAttack)
        {
            double spAttack = initialSpAttack;

            if (user.Item == PBEItem.DeepSeaTooth && user.OriginalSpecies == PBESpecies.Clamperl)
            {
                spAttack *= 2.0;
            }
            if (user.Item == PBEItem.LightBall && user.OriginalSpecies == PBESpecies.Pikachu)
            {
                spAttack *= 2.0;
            }
            if (moveType == PBEType.Fire && user.Ability == PBEAbility.Blaze && user.HP <= user.MaxHP / 3)
            {
                spAttack *= 1.5;
            }
            if (moveType == PBEType.Grass && user.Ability == PBEAbility.Overgrow && user.HP <= user.MaxHP / 3)
            {
                spAttack *= 1.5;
            }
            if (moveType == PBEType.Water && user.Ability == PBEAbility.Torrent && user.HP <= user.MaxHP / 3)
            {
                spAttack *= 1.5;
            }
            if (ShouldDoWeatherEffects() && Weather == PBEWeather.HarshSunlight && user.Ability == PBEAbility.SolarPower)
            {
                spAttack *= 1.5;
            }
            if (user.Item == PBEItem.SoulDew && (user.OriginalSpecies == PBESpecies.Latias || user.OriginalSpecies == PBESpecies.Latios))
            {
                spAttack *= 1.5;
            }
            if (user.Item == PBEItem.ChoiceSpecs)
            {
                spAttack *= 1.5;
            }
            if ((user.Ability == PBEAbility.Minus || user.Ability == PBEAbility.Plus) && Array.Exists(user.Team.ActiveBattlers, p => p != user && (p.Ability == PBEAbility.Minus || p.Ability == PBEAbility.Plus)))
            {
                spAttack *= 1.5;
            }
            if ((moveType == PBEType.Fire || moveType == PBEType.Ice) && target.Ability == PBEAbility.ThickFat && !user.HasCancellingAbility())
            {
                spAttack *= 0.5;
            }
            if (user.Ability == PBEAbility.Defeatist && user.HP <= user.MaxHP / 2)
            {
                spAttack *= 0.5;
            }

            return(spAttack);
        }
Esempio n. 22
0
        double CalculateAttack(PBEPokemon user, PBEPokemon target, PBEType moveType, double initialAttack)
        {
            double attack = initialAttack;

            if (user.Ability == PBEAbility.HugePower || user.Ability == PBEAbility.PurePower)
            {
                attack *= 2.0;
            }
            if (user.Item == PBEItem.ThickClub && (user.Shell.Species == PBESpecies.Cubone || user.Shell.Species == PBESpecies.Marowak))
            {
                attack *= 2.0;
            }
            if (user.Item == PBEItem.LightBall && user.Shell.Species == PBESpecies.Pikachu)
            {
                attack *= 2.0;
            }
            if (moveType == PBEType.Fire && user.Ability == PBEAbility.Blaze && user.HP <= user.MaxHP / 3)
            {
                attack *= 1.5;
            }
            if (moveType == PBEType.Grass && user.Ability == PBEAbility.Overgrow && user.HP <= user.MaxHP / 3)
            {
                attack *= 1.5;
            }
            if (moveType == PBEType.Water && user.Ability == PBEAbility.Torrent && user.HP <= user.MaxHP / 3)
            {
                attack *= 1.5;
            }
            if (user.Ability == PBEAbility.Hustle)
            {
                attack *= 1.5;
            }
            if (user.Ability == PBEAbility.Guts && user.Status1 != PBEStatus1.None)
            {
                attack *= 1.5;
            }
            if (user.Item == PBEItem.ChoiceBand)
            {
                attack *= 1.5;
            }
            if ((moveType == PBEType.Fire || moveType == PBEType.Ice) && target.Ability == PBEAbility.ThickFat)
            {
                attack *= 0.5;
            }
            if (user.Ability == PBEAbility.Defeatist && user.HP <= user.MaxHP / 2)
            {
                attack *= 0.5;
            }

            return(attack);
        }
Esempio n. 23
0
 private bool TypeCheck(PBEPokemon user, PBEPokemon target, PBEType moveType, out PBEResult result, out double damageMultiplier, bool statusMove = false)
 {
     result = target.IsAffectedByMove(user, moveType, out damageMultiplier, statusMove: statusMove);
     if (result == PBEResult.Ineffective_Ability)
     {
         BroadcastAbility(target, target, target.Ability, PBEAbilityAction.Damage);
     }
     if (result != PBEResult.NotVeryEffective_Type && result != PBEResult.Success && result != PBEResult.SuperEffective_Type)
     {
         BroadcastMoveResult(user, target, result);
         return(false);
     }
     return(true);
 }
        /// <summary>
        /// Restores HP to <paramref name="pkmn"/> and broadcasts the HP changing if it changes.
        /// </summary>
        /// <param name="pkmn">The Pokémon receiving the HP.</param>
        /// <param name="hp">The amount of HP <paramref name="pkmn"/> will try to gain.</param>
        /// <returns>The amount of HP restored.</returns>
        private ushort HealDamage(PBEPokemon pkmn, ushort hp)
        {
            ushort oldHP         = pkmn.HP;
            double oldPercentage = pkmn.HPPercentage;

            pkmn.HP = (ushort)Math.Min(pkmn.MaxHP, pkmn.HP + Math.Max((ushort)1, hp)); // Always try to heal at least 1 HP
            ushort healAmt = (ushort)(pkmn.HP - oldHP);

            if (healAmt > 0)
            {
                pkmn.HPPercentage = (double)pkmn.HP / pkmn.MaxHP;
                BroadcastPkmnHPChanged(pkmn, oldHP, oldPercentage);
            }
            return(healAmt);
        }
 /// <summary>Transforms into <paramref name="target"/> and sets <see cref="PBEStatus2.Transformed"/>.</summary>
 /// <param name="target">The Pokémon to transform into.</param>
 /// <remarks>Frees the Pokémon of its <see cref="ChoiceLockedMove"/>.</remarks>
 public void Transform(PBEPokemon target)
 {
     if (target == null)
     {
         throw new ArgumentNullException(nameof(target));
     }
     if (Team != target.Team)
     {
         KnownAbility = target.KnownAbility = Ability = target.Ability;
         KnownType1   = target.KnownType1 = Type1 = target.Type1;
         KnownType2   = target.KnownType2 = Type2 = target.Type2;
         KnownWeight  = target.KnownWeight = Weight = target.Weight;
     }
     else
     {
         Ability      = target.Ability;
         KnownAbility = target.KnownAbility;
         Type1        = target.Type1;
         KnownType1   = target.KnownType1;
         Type2        = target.Type2;
         KnownType2   = target.KnownType2;
         Weight       = target.Weight;
         KnownWeight  = target.KnownWeight;
     }
     KnownGender     = target.KnownGender = target.Gender;
     KnownShiny      = target.KnownShiny = target.Shiny;
     KnownSpecies    = target.KnownSpecies = Species = target.Species;
     Attack          = target.Attack;
     Defense         = target.Defense;
     SpAttack        = target.SpAttack;
     SpDefense       = target.SpDefense;
     Speed           = target.Speed;
     AttackChange    = target.AttackChange;
     DefenseChange   = target.DefenseChange;
     SpAttackChange  = target.SpAttackChange;
     SpDefenseChange = target.SpDefenseChange;
     SpeedChange     = target.SpeedChange;
     AccuracyChange  = target.AccuracyChange;
     EvasionChange   = target.EvasionChange;
     TransformBackupMoves.Reset(Moves);
     PBEBattleMoveset.DoTransform(this, target);
     if (!Moves.Contains(ChoiceLockedMove))
     {
         ChoiceLockedMove = PBEMove.None;
     }
     Status2 |= PBEStatus2.Transformed;
 }
Esempio n. 26
0
        ushort CalculateDamage(PBEPokemon user, PBEPokemon target, PBEMove move, PBEType moveType, PBEMoveCategory moveCategory, double basePower, bool criticalHit)
        {
            ushort damage;
            double a = 0, d = 0;

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

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

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

            damage  = (ushort)(2 * user.Shell.Level / 5 + 2);
            damage  = (ushort)(damage * a * basePower / d);
            damage /= 50;
            damage += 2;
            return((ushort)(damage * PBEUtils.RNG.Next(85, 101) / 100));
        }
Esempio n. 27
0
        public bool Remove(PBEPokemon pokemon)
        {
            if (IsDisposed)
            {
                throw new ObjectDisposedException(null);
            }
            if (pokemon.IsDisposed)
            {
                throw new ObjectDisposedException(nameof(pokemon));
            }
            bool b = Party.Remove(pokemon);

            if (b)
            {
                pokemon.Dispose();
            }
            return(b);
        }
Esempio n. 28
0
        private double CalculateDefense(PBEPokemon user, PBEPokemon target, double initialDefense)
        {
            double defense = initialDefense;

            if (target.Item == PBEItem.MetalPowder && target.OriginalSpecies == PBESpecies.Ditto && !target.Status2.HasFlag(PBEStatus2.Transformed))
            {
                defense *= 2.0;
            }
            if (target.Ability == PBEAbility.MarvelScale && target.Status1 != PBEStatus1.None && !user.HasCancellingAbility())
            {
                defense *= 1.5;
            }
            if (target.Item == PBEItem.Eviolite && PBEPokemonData.GetData(target.OriginalSpecies).Evolutions.Count > 0)
            {
                defense *= 1.5;
            }

            return(defense);
        }
Esempio n. 29
0
 /// <summary>
 /// Determines whether chosen switches are valid.
 /// </summary>
 /// <param name="team">The team the inputted switches belong to.</param>
 /// <param name="switches">The switches the team wishes to execute.</param>
 /// <returns>False if the team already chose switches or the switches are illegal, True otherwise.</returns>
 /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForSwitchIns"/>.</exception>
 public static bool AreSwitchesValid(PBETeam team, IEnumerable <Tuple <byte, PBEFieldPosition> > switches)
 {
     if (team.Battle.BattleState != PBEBattleState.WaitingForSwitchIns)
     {
         throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForSwitchIns} to validate switches.");
     }
     if (team.SwitchInsRequired == 0 || switches.Count() != team.SwitchInsRequired)
     {
         return(false);
     }
     foreach (Tuple <byte, PBEFieldPosition> s in switches)
     {
         PBEPokemon pkmn = team.Battle.TryGetPokemon(s.Item1);
         if (pkmn == null || pkmn.Team != team || pkmn.HP == 0 || pkmn.FieldPosition != PBEFieldPosition.None)
         {
             return(false);
         }
     }
     return(true);
 }
Esempio n. 30
0
 /// <summary>Selects switches if they are valid. Changes the battle state if both teams have selected valid switches.</summary>
 /// <param name="team">The team the inputted switches belong to.</param>
 /// <param name="switches">The switches the team wishes to execute.</param>
 /// <returns>True if the switches are valid and were selected.</returns>
 /// <exception cref="InvalidOperationException">Thrown when <see cref="BattleState"/> is not <see cref="PBEBattleState.WaitingForSwitchIns"/>.</exception>
 public static bool SelectSwitchesIfValid(PBETeam team, IList <PBESwitchIn> switches)
 {
     if (team == null)
     {
         throw new ArgumentNullException(nameof(team));
     }
     if (switches == null)
     {
         throw new ArgumentNullException(nameof(switches));
     }
     if (team.IsDisposed)
     {
         throw new ObjectDisposedException(nameof(team));
     }
     if (team.Battle.BattleState != PBEBattleState.WaitingForSwitchIns)
     {
         throw new InvalidOperationException($"{nameof(BattleState)} must be {PBEBattleState.WaitingForSwitchIns} to select switches.");
     }
     if (AreSwitchesValid(team, switches))
     {
         lock (team.Battle._disposeLockObj)
         {
             if (!team.Battle.IsDisposed)
             {
                 team.SwitchInsRequired = 0;
                 foreach (PBESwitchIn s in switches)
                 {
                     PBEPokemon pkmn = team.TryGetPokemon(s.PokemonId);
                     pkmn.FieldPosition = s.Position;
                     team.SwitchInQueue.Add(pkmn);
                 }
                 if (team.Battle.Teams.All(t => t.SwitchInsRequired == 0))
                 {
                     team.Battle.SwitchesOrActions();
                 }
                 return(true);
             }
         }
     }
     return(false);
 }