private float CalculateSpDefense(PBEBattlePokemon user, PBEBattlePokemon target, float initialSpDefense)
        {
            float spDefense = initialSpDefense;

            if (target.Item == PBEItem.DeepSeaScale && target.OriginalSpecies == PBESpecies.Clamperl)
            {
                spDefense *= 2.0f;
            }
            if (target.Item == PBEItem.SoulDew && (target.OriginalSpecies == PBESpecies.Latias || target.OriginalSpecies == PBESpecies.Latios))
            {
                spDefense *= 1.5f;
            }
            if (target.Item == PBEItem.Eviolite && PBEDataProvider.Instance.HasEvolutions(target.OriginalSpecies, target.RevertForm))
            {
                spDefense *= 1.5f;
            }
            if (ShouldDoWeatherEffects())
            {
                if (Weather == PBEWeather.Sandstorm && target.HasType(PBEType.Rock))
                {
                    spDefense *= 1.5f;
                }
                if (!user.HasCancellingAbility() && Weather == PBEWeather.HarshSunlight && target.Team.ActiveBattlers.FindIndex(p => p.Ability == PBEAbility.FlowerGift) != -1)
                {
                    spDefense *= 1.5f;
                }
            }

            return(spDefense);
        }
        private double CalculateSpDefense(PBEBattlePokemon user, PBEBattlePokemon 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, target.RevertForm).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 && target.Team.ActiveBattlers.Any(p => p.Ability == PBEAbility.FlowerGift))
                {
                    spDefense *= 1.5;
                }
            }

            return(spDefense);
        }
        // Verified: Sturdy and Substitute only activate on damaging attacks (so draining HP or liquid ooze etc can bypass sturdy)
        private ushort DealDamage(PBEBattlePokemon culprit, PBEBattlePokemon victim, int hp, bool ignoreSubstitute = true, bool ignoreSturdy = true)
        {
            if (hp < 1)
            {
                hp = 1;
            }
            if (!ignoreSubstitute && victim.Status2.HasFlag(PBEStatus2.Substitute))
            {
                ushort oldSubHP = victim.SubstituteHP;
                victim.SubstituteHP = (ushort)Math.Max(0, victim.SubstituteHP - hp);
                ushort damageAmt = (ushort)(oldSubHP - victim.SubstituteHP);
                BroadcastStatus2(victim, culprit, PBEStatus2.Substitute, PBEStatusAction.Damage);
                return(damageAmt);
            }
            ushort oldHP         = victim.HP;
            float  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 && _rand.RandomBool(10, 100))
                {
                    focusBandHappened = true;
                    victim.HP         = 1;
                }
                else if (oldHP == victim.MaxHP && victim.Item == PBEItem.FocusSash)
                {
                    focusSashHappened = true;
                    victim.HP         = 1;
                }
            }
            victim.UpdateHPPercentage();
            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));
        }
Esempio n. 4
0
        public static PBEResult IsAffectedByAttack(PBEBattlePokemon user, PBEBattlePokemon target, PBEType moveType, out double damageMultiplier, bool useKnownInfo = false)
        {
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }
            if (moveType >= PBEType.MAX)
            {
                throw new ArgumentOutOfRangeException(nameof(moveType));
            }

            PBEResult result;

            if (moveType == PBEType.Ground)
            {
                result = target.IsGrounded(user, useKnownInfo: useKnownInfo);
                if (result != PBEResult.Success)
                {
                    damageMultiplier = 0;
                    return(result);
                }
            }
            bool ignoreGhost = user.Ability == PBEAbility.Scrappy || target.Status2.HasFlag(PBEStatus2.Identified),
                 ignoreDark  = target.Status2.HasFlag(PBEStatus2.MiracleEye);

            damageMultiplier = GetEffectiveness(moveType, target, useKnownInfo, ignoreGhost: ignoreGhost, ignoreDark: ignoreDark);
            if (damageMultiplier <= 0) // (-infinity, 0]
            {
                damageMultiplier = 0;
                return(PBEResult.Ineffective_Type);
            }
            else if (damageMultiplier < 1) // (0, 1)
            {
                result = PBEResult.NotVeryEffective_Type;
            }
            else if (damageMultiplier == 1) // [1, 1]
            {
                result = PBEResult.Success;
            }
            else // (1, infinity)
            {
                return(PBEResult.SuperEffective_Type);
            }
            PBEAbility kAbility = useKnownInfo ? target.KnownAbility : target.Ability;

            if (kAbility == PBEAbility.WonderGuard && !user.HasCancellingAbility())
            {
                damageMultiplier = 0;
                result           = PBEResult.Ineffective_Ability;
            }
            return(result);
        }
        private float CalculateAttack(PBEBattlePokemon user, PBEBattlePokemon target, PBEType moveType, float initialAttack)
        {
            float attack = initialAttack;

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

            return(attack);
        }
        private float CalculateDamageMultiplier(PBEBattlePokemon user, PBEBattlePokemon target, IPBEMoveData mData, PBEType moveType, PBEResult moveResult, bool criticalHit)
        {
            float damageMultiplier = 1;

            if (target.Status2.HasFlag(PBEStatus2.Airborne) && mData.Flags.HasFlag(PBEMoveFlag.DoubleDamageAirborne))
            {
                damageMultiplier *= 2.0f;
            }
            if (target.Minimize_Used && mData.Flags.HasFlag(PBEMoveFlag.DoubleDamageMinimized))
            {
                damageMultiplier *= 2.0f;
            }
            if (target.Status2.HasFlag(PBEStatus2.Underground) && mData.Flags.HasFlag(PBEMoveFlag.DoubleDamageUnderground))
            {
                damageMultiplier *= 2.0f;
            }
            if (target.Status2.HasFlag(PBEStatus2.Underwater) && mData.Flags.HasFlag(PBEMoveFlag.DoubleDamageUnderwater))
            {
                damageMultiplier *= 2.0f;
            }

            if (criticalHit)
            {
                damageMultiplier *= Settings.CritMultiplier;
                if (user.Ability == PBEAbility.Sniper)
                {
                    damageMultiplier *= 1.5f;
                }
            }
            else if (user.Ability != PBEAbility.Infiltrator)
            {
                if ((target.Team.TeamStatus.HasFlag(PBETeamStatus.Reflect) && mData.Category == PBEMoveCategory.Physical) ||
                    (target.Team.TeamStatus.HasFlag(PBETeamStatus.LightScreen) && mData.Category == PBEMoveCategory.Special))
                {
                    if (target.Team.NumPkmnOnField == 1)
                    {
                        damageMultiplier *= 0.5f;
                    }
                    else
                    {
                        damageMultiplier *= 0.66f;
                    }
                }
            }

            switch (moveResult)
            {
            case PBEResult.NotVeryEffective_Type:
            {
                if (user.Ability == PBEAbility.TintedLens)
                {
                    damageMultiplier *= 2.0f;
                }
                break;
            }

            case PBEResult.SuperEffective_Type:
            {
                if ((target.Ability == PBEAbility.Filter || target.Ability == PBEAbility.SolidRock) && !user.HasCancellingAbility())
                {
                    damageMultiplier *= 0.75f;
                }
                if (user.Item == PBEItem.ExpertBelt)
                {
                    damageMultiplier *= 1.2f;
                }
                break;
            }
            }
            if (user.ReceivesSTAB(moveType))
            {
                if (user.Ability == PBEAbility.Adaptability)
                {
                    damageMultiplier *= 2.0f;
                }
                else
                {
                    damageMultiplier *= 1.5f;
                }
            }
            if (mData.Category == PBEMoveCategory.Physical && user.Status1 == PBEStatus1.Burned && user.Ability != PBEAbility.Guts)
            {
                damageMultiplier *= 0.5f;
            }
            if (moveType == PBEType.Fire && target.Ability == PBEAbility.Heatproof && !user.HasCancellingAbility())
            {
                damageMultiplier *= 0.5f;
            }

            return(damageMultiplier);
        }
        private int CalculateDamage(PBEBattlePokemon user, PBEBattlePokemon target, IPBEMoveData mData, PBEType moveType, float basePower, bool criticalHit)
        {
            PBEBattlePokemon aPkmn;
            PBEMoveCategory  aCat = mData.Category, dCat;

            switch (mData.Effect)
            {
            case PBEMoveEffect.FoulPlay:
            {
                aPkmn = target;
                dCat  = aCat;
                break;
            }

            case PBEMoveEffect.Psyshock:
            {
                aPkmn = user;
                dCat  = PBEMoveCategory.Physical;
                break;
            }

            default:
            {
                aPkmn = user;
                dCat  = aCat;
                break;
            }
            }

            bool  ignoreA = user != target && target.Ability == PBEAbility.Unaware && !user.HasCancellingAbility();
            bool  ignoreD = user != target && (mData.Effect == PBEMoveEffect.ChipAway || user.Ability == PBEAbility.Unaware);
            float a, d;

            if (aCat == PBEMoveCategory.Physical)
            {
                float m = ignoreA ? 1 : GetStatChangeModifier(criticalHit ? Math.Max((sbyte)0, aPkmn.AttackChange) : aPkmn.AttackChange, false);
                a = CalculateAttack(user, target, moveType, aPkmn.Attack * m);
            }
            else
            {
                float m = ignoreA ? 1 : GetStatChangeModifier(criticalHit ? Math.Max((sbyte)0, aPkmn.SpAttackChange) : aPkmn.SpAttackChange, false);
                a = CalculateSpAttack(user, target, moveType, aPkmn.SpAttack * m);
            }
            if (dCat == PBEMoveCategory.Physical)
            {
                float m = ignoreD ? 1 : GetStatChangeModifier(criticalHit ? Math.Min((sbyte)0, target.DefenseChange) : target.DefenseChange, false);
                d = CalculateDefense(user, target, target.Defense * m);
            }
            else
            {
                float m = ignoreD ? 1 : GetStatChangeModifier(criticalHit ? Math.Min((sbyte)0, target.SpDefenseChange) : target.SpDefenseChange, false);
                d = CalculateSpDefense(user, target, target.SpDefense * m);
            }

            return(CalculateDamage(user, a, d, basePower));
        }
        private float CalculateSpAttack(PBEBattlePokemon user, PBEBattlePokemon target, PBEType moveType, float initialSpAttack)
        {
            float spAttack = initialSpAttack;

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

            return(spAttack);
        }
        private static float CalculateDefense(PBEBattlePokemon user, PBEBattlePokemon target, float initialDefense)
        {
            float defense = initialDefense;

            if (target.Item == PBEItem.MetalPowder && target.OriginalSpecies == PBESpecies.Ditto && !target.Status2.HasFlag(PBEStatus2.Transformed))
            {
                defense *= 2.0f;
            }
            if (target.Ability == PBEAbility.MarvelScale && target.Status1 != PBEStatus1.None && !user.HasCancellingAbility())
            {
                defense *= 1.5f;
            }
            if (target.Item == PBEItem.Eviolite && PBEDataProvider.Instance.HasEvolutions(target.OriginalSpecies, target.RevertForm))
            {
                defense *= 1.5f;
            }

            return(defense);
        }
        private double CalculateDefense(PBEBattlePokemon user, PBEBattlePokemon 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, target.RevertForm).Evolutions.Count > 0)
            {
                defense *= 1.5;
            }

            return(defense);
        }