Пример #1
0
        static async Task GiveNonVolatileStatus(NonVolatileStatusDefinition Definition, Pokemon Target, Pokemon Attacker, BattleViewModel Battle, Func <Task> AbilityCallback = null)
        {
            if (Definition == null)
            {
                return;
            }

            if (Target.Stats.CurrentHP == 0)
            {
                return;
            }

            if (Target.NonVolatileStatus != NonVolatileStatus.None)
            {
                return;
            }

            // Leaf Guard
            if (Battle.SuppressWeather == 0 && Target.Ability == Ability.LeafGuard &&
                Battle.Weather.Is(Weather.HarshSunlight, Weather.ExtremelyHarshSunlight))
            {
                return;
            }

            if (Definition.Probability < 1 && BattleViewModel.Random.NextDouble() > Definition.Probability)
            {
                return;
            }

            switch (Definition.Status)
            {
            case NonVolatileStatus.Burn:
                if (Target.Is(Types.Fire))
                {
                    return;
                }

                // Water Veil, Water Bubble
                if (Target.Ability.Is(Ability.WaterVeil, Ability.WaterBubble))
                {
                    return;
                }

                if (AbilityCallback != null)
                {
                    await AbilityCallback.Invoke();
                }

                Target.NonVolatileStatus = NonVolatileStatus.Burn;

                await Battle.WriteStatus($"{Battle.GetStatusName(Target)} is burned");

                break;

            case NonVolatileStatus.Freeze:
                if (Battle.SuppressWeather == 0 && Battle.Weather.Is(Weather.HarshSunlight, Weather.ExtremelyHarshSunlight))
                {
                    return;
                }

                if (Target.Is(Types.Ice))
                {
                    return;
                }

                // Magma Armor
                if (Target.Ability == Ability.MagmaArmor)
                {
                    return;
                }

                if (AbilityCallback != null)
                {
                    await AbilityCallback.Invoke();
                }

                Target.NonVolatileStatus = NonVolatileStatus.Freeze;

                await Battle.WriteStatus($"{Battle.GetStatusName(Target)} is frozen");

                break;

            case NonVolatileStatus.Paralysis:
                if (Target.Is(Types.Electric))
                {
                    return;
                }

                // Limber
                if (Target.Ability == Ability.Limber)
                {
                    return;
                }

                if (AbilityCallback != null)
                {
                    await AbilityCallback.Invoke();
                }

                Target.NonVolatileStatus = NonVolatileStatus.Paralysis;

                await Battle.WriteStatus($"{Battle.GetStatusName(Target)} is paralysed. It may be unable to move.");

                break;

            case NonVolatileStatus.Poison:
            case NonVolatileStatus.BadPoison:
                if (Attacker?.Ability != Ability.Corrosion)
                {
                    if (Target.Is(Types.Poison, Types.Steel))
                    {
                        return;
                    }
                }

                // Immunity
                if (Target.Ability == Ability.Immunity)
                {
                    return;
                }

                if (AbilityCallback != null)
                {
                    await AbilityCallback.Invoke();
                }

                Target.NonVolatileStatus = Definition.Status;

                await Battle.WriteStatus($"{Battle.GetStatusName(Target)} is poisoned.");

                break;

            case NonVolatileStatus.Sleep:
                if (Target.Ability.Is(Ability.Insomnia, Ability.VitalSpirit))
                {
                    return;
                }

                if (AbilityCallback != null)
                {
                    await AbilityCallback.Invoke();
                }

                Target.SleepCounter      = BattleViewModel.Random.Next(1, 4);
                Target.NonVolatileStatus = NonVolatileStatus.Sleep;

                await Battle.WriteStatus($"{Battle.GetStatusName(Target)} fell asleep.");

                break;
            }

            // Synchronize
            if (Target.Ability == Ability.Synchronize && Attacker != null)
            {
                switch (Definition.Status)
                {
                case NonVolatileStatus.Burn:
                case NonVolatileStatus.Paralysis:
                case NonVolatileStatus.Poison:
                case NonVolatileStatus.BadPoison:
                    await Battle.ShowAbility(Target);

                    await GiveNonVolatileStatus(new NonVolatileStatusDefinition(Definition.Status), Attacker, Target, Battle);

                    break;
                }
            }
        }
Пример #2
0
        public static async Task StatChanges(Pokemon Attacker, Pokemon Opponent, IEnumerable <StatChange> StatChanges, BattleViewModel Battle)
        {
            foreach (var statChange in StatChanges)
            {
                if (statChange.Probability < 1)
                {
                    if (BattleViewModel.Random.NextDouble() > statChange.Probability)
                    {
                        continue;
                    }
                }

                var stageChange = statChange.StageChange;

                var victim = statChange.Self ? Attacker : Opponent;

                if (victim.Stats.CurrentHP == 0)
                {
                    continue;
                }

                // Clear Body, White Smoke, Full Metal Body
                if (stageChange < 0 && !statChange.Self && victim.Ability.Is(Ability.ClearBody, Ability.WhiteSmoke, Ability.FullMetalBody))
                {
                    await Battle.ShowAbility(victim);

                    await Battle.WriteStatus($"{Battle.GetStatusName(victim)}'s {statChange.Stat.SpaceAtCapitals()} was not lowered.");

                    continue;
                }

                // Contrary
                if (victim.Ability == Ability.Contrary)
                {
                    stageChange = -stageChange;
                }

                if (!statChange.Self &&
                    victim.Ability is StatFallPreventionAbility statFallPreventionAbility &&
                    statFallPreventionAbility.Stat == statChange.Stat &&
                    stageChange < 0)
                {
                    await Battle.ShowAbility(victim);

                    await Battle.WriteStatus($"{Battle.GetStatusName(victim)} {statChange.Stat.SpaceAtCapitals()} was not lowered");

                    continue;
                }

                stageChange = victim.Stats.ChangeStage(statChange.Stat, stageChange);

                if (stageChange == 0)
                {
                    await Battle.WriteStatus($"{Battle.GetStatusName(victim)}'s {statChange.Stat.SpaceAtCapitals()} won't go any {(statChange.StageChange > 0 ? "higher" : "lower")}");
                }
                else
                {
                    var sharply = stageChange > 1 || stageChange < -1;

                    await Battle.WriteStatus($"{Battle.GetStatusName(victim)}'s {statChange.Stat.SpaceAtCapitals()} {(stageChange > 0 ? "rose" : "fell")}{(sharply ? " sharply" : "")}");
                }
            }
        }
Пример #3
0
        static async Task <bool> Absorb(Move Move, Pokemon Opponent, BattleViewModel Battle)
        {
            // Flash Fire
            if (Opponent.Ability == Ability.FlashFire && Move.Type == Types.Fire)
            {
                await Battle.ShowAbility(Opponent);

                await Battle.WriteStatus($"{Battle.GetStatusName(Opponent)} absorbed the attack");

                // Hit by a fire type move
                Opponent.AbilityData = 1;

                return(true);
            }

            // Motor Drive
            if (Opponent.Ability == Ability.MotorDrive && Move.Type == Types.Electric &&
                Opponent.GetTypeEffectiveness(Types.Electric) > 0)
            {
                await Battle.ShowAbility(Opponent);

                await StatChange(Opponent, Stats.Speed, 1, Battle);

                return(true);
            }

            // Sap Sipper
            if (Opponent.Ability == Ability.SapSipper && Move.Type == Types.Grass)
            {
                await Battle.ShowAbility(Opponent);

                await StatChange(Opponent, Stats.Attack, 1, Battle);

                return(true);
            }

            // Volt Absorb
            if (Opponent.Ability == Ability.VoltAbsorb && Move.Type == Types.Electric &&
                Opponent.GetTypeEffectiveness(Types.Electric) > 0)
            {
                await Battle.ShowAbility(Opponent);

                if (Opponent.Stats.Heal(Opponent.Stats.MaxHP / 4))
                {
                    await Battle.WriteStatus($"{Battle.GetStatusName(Opponent)} absorbed the attack.");
                }

                return(true);
            }

            // Water Absorb, Dry Skin
            if (Opponent.Ability.Is(Ability.WaterAbsorb, Ability.DrySkin) && Move.Type == Types.Water &&
                Opponent.GetTypeEffectiveness(Types.Water) > 0)
            {
                await Battle.ShowAbility(Opponent);

                if (Opponent.Stats.Heal(Opponent.Stats.MaxHP / 4))
                {
                    await Battle.WriteStatus($"{Battle.GetStatusName(Opponent)} absorbed the attack.");
                }

                return(true);
            }

            return(false);
        }
Пример #4
0
        static async Task ContactEffects(Pokemon Attacker, Move Move, Pokemon Opponent, BattleViewModel Battle)
        {
            // Long Reach
            if (Attacker.Ability == Ability.LongReach)
            {
                return;
            }

            if (Move.Info.Flags.HasFlag(MoveFlags.Contact))
            {
                #region Opponent Abilities
                // Static
                if (Opponent.Ability == Ability.Static && Attacker.NonVolatileStatus == NonVolatileStatus.None)
                {
                    await GiveNonVolatileStatus(new NonVolatileStatusDefinition(NonVolatileStatus.Paralysis, 0.3), Attacker, Opponent, Battle, () => Battle.ShowAbility(Opponent));
                }

                // Flame Body
                else if (Opponent.Ability == Ability.FlameBody)
                {
                    await GiveNonVolatileStatus(new NonVolatileStatusDefinition(NonVolatileStatus.Burn, 0.3), Attacker, Opponent, Battle, () => Battle.ShowAbility(Opponent));
                }

                // Gooey, Tangling Hair
                else if (Opponent.Ability.Is(Ability.Gooey, Ability.TanglingHair))
                {
                    await StatChange(Attacker, Stats.Speed, -1, Battle);
                }

                // Iron Barbs, Rough Skin
                else if (Opponent.Ability.Is(Ability.IronBarbs, Ability.RoughSkin))
                {
                    await Battle.ShowAbility(Opponent);

                    await Battle.WriteStatus($"{Battle.GetStatusName(Attacker)} took damaged");

                    await Attacker.Stats.Damage(Attacker.Stats.MaxHP / 8, Battle);
                }

                // Poison Point
                else if (Opponent.Ability == Ability.PoisonPoint)
                {
                    await GiveNonVolatileStatus(new NonVolatileStatusDefinition(NonVolatileStatus.Poison, 0.3), Attacker, Opponent, Battle, () => Battle.ShowAbility(Opponent));
                }

                // Effect Spore
                else if (Opponent.Ability == Ability.EffectSpore)
                {
                    var status = NonVolatileStatus.None;

                    switch (BattleViewModel.Random.Next(3))
                    {
                    case 0:
                        status = NonVolatileStatus.Poison;
                        break;

                    case 1:
                        status = NonVolatileStatus.Paralysis;
                        break;

                    case 2:
                        status = NonVolatileStatus.Sleep;
                        break;
                    }

                    await GiveNonVolatileStatus(new NonVolatileStatusDefinition(status, 0.3), Attacker, Opponent, Battle, () => Battle.ShowAbility(Opponent));
                }
                #endregion

                #region Attacker abilities
                // Poison Touch
                if (Attacker.Ability == Ability.PoisonTouch)
                {
                    await GiveNonVolatileStatus(new NonVolatileStatusDefinition(NonVolatileStatus.Poison, 0.3), Opponent, Attacker, Battle, () => Battle.ShowAbility(Attacker));
                }
                #endregion
            }
        }
Пример #5
0
        public static async Task Default(Pokemon Attacker, Move Move, Pokemon Opponent, BattleViewModel Battle)
        {
            await StatChanges(Attacker, Opponent, Move.Info.PreStatChanges, Battle);

            if (!await IsHit(Attacker, Move, Opponent, Battle))
            {
                return;
            }

            if (await Absorb(Move, Opponent, Battle))
            {
                return;
            }

            var power = GetPower(Attacker, Move, Opponent, Battle);

            if (power != null)
            {
                var criticalHit = IsCriticalHit(Attacker, Move, Opponent);

                var attack  = GetAttack(Attacker, Move.Kind, Battle, criticalHit);
                var defense = GetDefense(Opponent, Move.Kind, Battle, criticalHit);

                var damage = GetBaseDamage(Attacker.Level, power.Value, attack, defense);

                damage *= SameTypeAttackBoost(Attacker, Move.Type);

                if (Battle.SuppressWeather == 0)
                {
                    switch (Battle.Weather)
                    {
                    case Weather.HeavyRain when Move.Type == Types.Fire:
                        damage = 0;
                        break;

                    case Weather.ExtremelyHarshSunlight when Move.Type == Types.Water:
                        damage = 0;
                        break;
                    }
                }

                // Weather can nullify damage
                if (damage == 0)
                {
                    await Battle.WriteStatus("But it failed");

                    return;
                }

                var typeEffectivenessDisplays = new List <string>();

                var typeEffect = TypeEffectiveness(Attacker, Move, Opponent, Battle, typeEffectivenessDisplays);

                if (typeEffect == 0)
                {
                    await Battle.WriteStatus(typeEffectivenessDisplays[0]);

                    return;
                }

                // Burn
                if (Move.Kind == MoveKind.Physical &&
                    Attacker.Ability != Ability.Guts &&
                    Attacker.NonVolatileStatus == NonVolatileStatus.Burn)
                {
                    damage /= 2;
                }

                // Heatproof
                if (Move.Type == Types.Fire && Opponent.Ability == Ability.Heatproof)
                {
                    damage /= 2;
                }

                // Fur Coat
                else if (Move.Kind == MoveKind.Physical && Opponent.Ability == Ability.FurCoat)
                {
                    damage /= 2;
                }

                // Water Bubble
                else if (Move.Type == Types.Fire && Opponent.Ability == Ability.WaterBubble)
                {
                    damage /= 2;
                }

                // Hustle
                if (Move.Kind == MoveKind.Physical && Attacker.Ability == Ability.Hustle)
                {
                    damage *= 1.5;
                }

                // Thick Fat
                else if (Move.Type.Is(Types.Fire, Types.Ice) && Attacker.Ability == Ability.ThickFat)
                {
                    damage /= 2;
                }

                // Tough Claws
                else if (Move.Info.Flags.HasFlag(MoveFlags.Contact) && Attacker.Ability == Ability.ToughClaws)
                {
                    damage *= 1.33;
                }

                damage *= typeEffect;

                if (criticalHit)
                {
                    damage *= Attacker.Ability == Ability.Sniper ? 2.25 : 1.5;
                }

                if (Attacker.Stats.CurrentHP <= Attacker.Stats.MaxHP / 3)
                {
                    if (Attacker.Ability is PinchAbility pinchAbility && pinchAbility.Type == Move.Type)
                    {
                        damage *= 1.5;
                    }
                }

                // Multiscale
                if (Opponent.Ability == Ability.Multiscale && Opponent.Stats.CurrentHP == Opponent.Stats.MaxHP)
                {
                    damage /= 2;
                }

                else if (Opponent.Ability == Ability.DrySkin)
                {
                    damage *= 1.25;
                }

                // Rivalry
                if (Attacker.Ability == Ability.Rivalry &&
                    Attacker.Gender != Gender.Genderless &&
                    Opponent.Gender != Gender.Genderless)
                {
                    damage *= Attacker.Gender == Opponent.Gender ? 1.25 : 0.75;
                }

                // Flash Fire
                if (Attacker.Ability == Ability.FlashFire &&
                    Move.Type == Types.Fire &&
                    Attacker.AbilityData == 1)
                {
                    damage *= 1.5;
                }

                // Random
                damage *= BattleViewModel.Random.Next(85, 101) / 100.0;

                // Damage is reduced by 25% when there are Multiple Targets
                if (Move.Multitargets)
                {
                    damage *= 0.75;
                }

                if (damage > Opponent.Stats.CurrentHP)
                {
                    damage = Opponent.Stats.CurrentHP;
                }

                if (damage < 1)
                {
                    damage = 1;
                }

                // Disguise
                if (Opponent.Ability == Ability.Disguise && Opponent.AbilityData == 0)
                {
                    await Battle.ShowAbility(Opponent);

                    await Battle.WriteStatus($"{Battle.GetStatusName(Opponent)}'s disguise was busted");

                    Opponent.AbilityData = 1;

                    return;
                }

                await Opponent.Stats.Damage((int)damage, Battle);

                foreach (var display in typeEffectivenessDisplays)
                {
                    await Battle.WriteStatus(display);
                }

                if (criticalHit)
                {
                    await Battle.WriteStatus("It's a critical hit");
                }

                if (damage > 0 && Move.Info.Drain > 0)
                {
                    await Battle.WriteStatus($"{Battle.GetStatusName(Opponent)} had its energy drained");

                    var drain = (int)(Move.Info.Drain * damage);

                    Attacker.Stats.Heal(drain);
                }

                if (damage > 0 && Move.Info.Recoil > 0 && Attacker.Ability != Ability.RockHead)
                {
                    await Battle.WriteStatus($"{Battle.GetStatusName(Attacker)} is hit by recoil");

                    var recoil = (int)(Move.Info.Recoil * damage);

                    await Attacker.Stats.Damage(recoil, Battle);
                }

                // Cell Battery
                if (Opponent.HeldItem == HeldItem.CellBattery && Move.Type == Types.Electric)
                {
                    await StatChange(Opponent, Stats.Attack, 1, Battle);

                    Opponent.HeldItem = null;
                }

                // Anger Point
                if (criticalHit && Opponent.Ability == Ability.AngerPoint)
                {
                    await Battle.ShowAbility(Opponent);

                    await StatChange(Opponent, Stats.Attack, 12, Battle);
                }

                // Cursed Body
                if (Opponent.Ability == Ability.CursedBody && BattleViewModel.Random.Next(100) < 30)
                {
                    await Battle.ShowAbility(Opponent);

                    Move.Disabled = true;

                    await Battle.WriteStatus($"{Battle.GetStatusName(Attacker)}'s {Move} was disabled");
                }
            }

            // Justified
            if (Move.Type == Types.Dark && Opponent.Ability == Ability.Justified)
            {
                await Battle.ShowAbility(Opponent);

                await StatChange(Opponent, Stats.Attack, 1, Battle);
            }

            // Stamina
            else if (Move.Kind != MoveKind.Status && Opponent.Ability == Ability.Stamina)
            {
                await Battle.ShowAbility(Opponent);

                await StatChange(Opponent, Stats.Defense, 1, Battle);
            }

            // Rattled
            else if (Opponent.Ability == Ability.Rattled)
            {
                if (Move.Type.Is(Types.Dark, Types.Ghost, Types.Bug))
                {
                    await Battle.ShowAbility(Opponent);

                    await StatChange(Opponent, Stats.Speed, 1, Battle);
                }
            }

            // Weak Armor
            else if (Move.Kind == MoveKind.Physical && Opponent.Ability == Ability.WeakArmor)
            {
                await Battle.ShowAbility(Opponent);

                await StatChange(Opponent, Stats.Speed, 1, Battle);
                await StatChange(Opponent, Stats.Defense, -1, Battle);
            }

            // Water Compaction
            else if (Move.Type == Types.Water && Opponent.Ability == Ability.WaterCompaction)
            {
                await Battle.ShowAbility(Opponent);

                await StatChange(Opponent, Stats.Defense, 2, Battle);
            }

            await ContactEffects(Attacker, Move, Opponent, Battle);

            await StatChanges(Attacker, Opponent, Move.Info.PostStatChanges, Battle);

            await GiveNonVolatileStatus(Move.Info.NonVolatileStatus, Opponent, Attacker, Battle);

            if (!Opponent.IsFainted)
            {
                if (Move.Info.Flinch != null)
                {
                    Flinch(Opponent, Move.Info.Flinch.Value);
                }
                else if (Attacker.Ability == Ability.Stench)
                {
                    Flinch(Opponent, 0.1);
                }

                if (Move.Info.ConfuseTarget != null)
                {
                    await Confuse(Opponent, Move.Info.ConfuseTarget.Value, Battle);
                }
            }

            if (Move.Info.Flags.HasFlag(MoveFlags.Recharge))
            {
                Attacker.Recharging = true;
            }
        }