Beispiel #1
0
 private void CreateMoveChoices()
 {
     if (_moveChoices is null)
     {
         PBEBattleMoveset moves       = _pkmn.Moves;
         PBEMove[]        usableMoves = _pkmn.GetUsableMoves();
         _moveChoices = new TextGUIChoices(0.75f, 0.75f, bottomAlign: true, backCommand: SetCallbacksForAllChoices,
                                           font: Font.Default, fontColors: Font.DefaultWhite_I, selectedColors: Font.DefaultYellow_O, disabledColors: Font.DefaultDisabled);
         for (int i = 0; i < PkmnConstants.NumMoves; i++)
         {
             PBEBattleMoveset.PBEBattleMovesetSlot slot = moves[i];
             PBEMove m       = slot.Move;
             string  text    = PBEDataProvider.Instance.GetMoveName(m).English;
             bool    enabled = Array.IndexOf(usableMoves, m) != -1;
             Action  command = enabled ? () => SelectMoveForTurn(m) : null;
             _moveChoices.Add(new TextGUIChoice(text, command, isEnabled: enabled));
         }
     }
 }
Beispiel #2
0
        private void FightChoice()
        {
            PBEBattlePokemon pkmn = _pkmn.Pkmn;
            // Check if there's a move we must use
            bool auto = false;

            if (pkmn.IsForcedToStruggle())
            {
                pkmn.TurnAction = new PBETurnAction(pkmn, PBEMove.Struggle, PBEBattleUtils.GetPossibleTargets(pkmn, pkmn.GetMoveTargets(PBEMove.Struggle))[0]);
                auto            = true;
            }
            else if (pkmn.TempLockedMove != PBEMove.None)
            {
                pkmn.TurnAction = new PBETurnAction(pkmn, pkmn.TempLockedMove, pkmn.TempLockedTargets);
                auto            = true;
            }
            if (auto)
            {
                _parent.ActionsLoop(false);
                return;
            }

            // Create move choices if it's not already created
            if (_moveChoices is null)
            {
                PBEBattleMoveset moves       = pkmn.Moves;
                PBEMove[]        usableMoves = pkmn.GetUsableMoves();
                _moveChoices = new GUIChoices(0.8f, 0.7f, 0.06f, backCommand: () => _isShowingMoves = false,
                                              font: Font.Default, fontColors: Font.DefaultWhite, selectedColors: Font.DefaultSelected, disabledColors: Font.DefaultDisabled);
                for (int i = 0; i < PBESettings.DefaultNumMoves; i++)
                {
                    PBEBattleMoveset.PBEBattleMovesetSlot slot = moves[i];
                    PBEMove m       = slot.Move;
                    string  text    = PBELocalizedString.GetMoveName(m).English;
                    bool    enabled = Array.IndexOf(usableMoves, m) != -1;
                    Action  command = enabled ? () => SelectMoveForTurn(m) : (Action)null;
                    _moveChoices.Add(new GUIChoice(text, command, isEnabled: enabled));
                }
            }

            // Show moves
            _isShowingMoves = true;
        }
Beispiel #3
0
 public void UpdateFromBattle(PBEBattleMoveset.PBEBattleMovesetSlot slot)
 {
     Move = slot.Move;
     PP   = slot.PP;
 }
Beispiel #4
0
        private unsafe void DrawMovesPage(uint *bmpAddress, int bmpWidth, int bmpHeight)
        {
            const float winX         = 0.08f;
            const float winY         = 0.15f;
            const float winW         = 0.75f - winX;
            const float winH         = 0.9f - winY;
            const float moveColX     = winX + 0.03f;
            const float moveTextX    = moveColX + 0.02f;
            const float moveColW     = 0.69f - winX;
            const float itemSpacingY = winH / (PkmnConstants.NumMoves + 0.75f);
            const float moveX        = 0.21f;
            const float moveY        = 0.03f;
            const float ppX          = 0.12f;
            const float ppNumX       = 0.35f;
            const float ppY          = itemSpacingY / 2;
            const float cancelY      = winY + moveY + (PkmnConstants.NumMoves * itemSpacingY);

            RenderUtils.FillRoundedRectangle(bmpAddress, bmpWidth, bmpHeight, winX, winY, winX + winW, winY + winH, 15, RenderUtils.Color(250, 128, 120, 255));

            Font moveFont = Font.Default;

            uint[] moveColors = Font.DefaultWhite_DarkerOutline_I;
            uint[] ppColors   = Font.DefaultBlack_I;

            void Place(int i, PBEMove move, int pp, int maxPP)
            {
                PBEMoveData mData = PBEMoveData.Data[move];
                float       x     = moveTextX;
                float       y     = winY + moveY + (i * itemSpacingY);
                string      str   = PBELocalizedString.GetTypeName(mData.Type).English;

                moveFont.DrawString(bmpAddress, bmpWidth, bmpHeight, x, y, str, moveColors);
                x  += moveX;
                str = PBELocalizedString.GetMoveName(move).English;
                moveFont.DrawString(bmpAddress, bmpWidth, bmpHeight, x, y, str, moveColors);
                x   = moveTextX + ppX;
                y  += ppY;
                str = "PP";
                moveFont.DrawString(bmpAddress, bmpWidth, bmpHeight, x, y, str, ppColors);
                x   = moveTextX + ppNumX;
                str = string.Format("{0}/{1}", pp, maxPP);
                moveFont.MeasureString(str, out int strW, out _);
                moveFont.DrawString(bmpAddress, bmpWidth, bmpHeight, RenderUtils.GetCoordinatesForCentering(bmpWidth, strW, x), (int)(bmpHeight * y), str, ppColors);

                DrawSelection(i);
            }

            void DrawSelection(int i)
            {
                if (_selectingMove != i)
                {
                    return;
                }
                float x = moveColX;
                float y = winY + moveY + (i * itemSpacingY);
                float w = moveColW;
                float h = i == PkmnConstants.NumMoves ? itemSpacingY / 2 : itemSpacingY;

                RenderUtils.DrawRoundedRectangle(bmpAddress, bmpWidth, bmpHeight, x, y, x + w, y + h, 5, RenderUtils.Color(48, 180, 255, 200));
            }

            // Moves
            if (_pPkmn is not null)
            {
                Moveset moves = _pPkmn.Moveset;
                for (int m = 0; m < PkmnConstants.NumMoves; m++)
                {
                    Moveset.MovesetSlot slot = moves[m];
                    PBEMove             move = slot.Move;
                    if (move == PBEMove.None)
                    {
                        continue;
                    }
                    int pp    = slot.PP;
                    int maxPP = PBEDataUtils.CalcMaxPP(move, slot.PPUps, PkmnConstants.PBESettings);
                    Place(m, move, pp, maxPP);
                }
            }
            else if (_pcPkmn is not null)
            {
                BoxMoveset moves = _pcPkmn.Moveset;
                for (int m = 0; m < PkmnConstants.NumMoves; m++)
                {
                    BoxMoveset.BoxMovesetSlot slot = moves[m];
                    PBEMove move = slot.Move;
                    if (move == PBEMove.None)
                    {
                        continue;
                    }
                    int maxPP = PBEDataUtils.CalcMaxPP(move, slot.PPUps, PkmnConstants.PBESettings);
                    Place(m, move, maxPP, maxPP);
                }
            }
            else
            {
                PBEBattlePokemon bPkmn = _bPkmn.Pkmn;
                PBEBattleMoveset moves = bPkmn.Status2.HasFlag(PBEStatus2.Transformed) ? bPkmn.TransformBackupMoves : bPkmn.Moves;
                for (int m = 0; m < PkmnConstants.NumMoves; m++)
                {
                    PBEBattleMoveset.PBEBattleMovesetSlot slot = moves[m];
                    PBEMove move = slot.Move;
                    if (move == PBEMove.None)
                    {
                        continue;
                    }
                    int pp    = slot.PP;
                    int maxPP = slot.MaxPP;
                    Place(m, move, pp, maxPP);
                }
            }

            // Cancel or new move
            if (_learningMove != PBEMove.None)
            {
                uint[]      learnColors = Font.DefaultBlue_I;
                PBEMoveData mData       = PBEMoveData.Data[_learningMove];
                float       x           = moveTextX;
                string      str         = PBELocalizedString.GetTypeName(mData.Type).English;
                moveFont.DrawString(bmpAddress, bmpWidth, bmpHeight, x, cancelY, str, learnColors);
                x  += moveX;
                str = PBELocalizedString.GetMoveName(_learningMove).English;
                moveFont.DrawString(bmpAddress, bmpWidth, bmpHeight, x, cancelY, str, learnColors);
                DrawSelection(PkmnConstants.NumMoves);
            }
            else
            {
                if (_selectingMove != -1)
                {
                    string str = "Cancel";
                    moveFont.DrawString(bmpAddress, bmpWidth, bmpHeight, moveTextX, cancelY, str, moveColors);
                    DrawSelection(PkmnConstants.NumMoves);
                }
            }
        }
Beispiel #5
0
        public static string CustomPokemonToString(PBEBattlePokemon pkmn, bool useKnownInfo)
        {
            var sb = new StringBuilder();

            string GetTeamNickname(PBEBattlePokemon p)
            {
                return($"{p.Trainer.Name}'s {(useKnownInfo ? p.KnownNickname : p.Nickname)}");
            }

            void AddStatChanges()
            {
                PBEStat[] statChanges = pkmn.GetChangedStats();
                if (statChanges.Length > 0)
                {
                    var statStrs = new List <string>(7);
                    if (Array.IndexOf(statChanges, PBEStat.Attack) != -1)
                    {
                        statStrs.Add($"[A] x{PBEBattle.GetStatChangeModifier(pkmn.AttackChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.Defense) != -1)
                    {
                        statStrs.Add($"[D] x{PBEBattle.GetStatChangeModifier(pkmn.DefenseChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.SpAttack) != -1)
                    {
                        statStrs.Add($"[SA] x{PBEBattle.GetStatChangeModifier(pkmn.SpAttackChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.SpDefense) != -1)
                    {
                        statStrs.Add($"[SD] x{PBEBattle.GetStatChangeModifier(pkmn.SpDefenseChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.Speed) != -1)
                    {
                        statStrs.Add($"[S] x{PBEBattle.GetStatChangeModifier(pkmn.SpeedChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.Accuracy) != -1)
                    {
                        statStrs.Add($"[AC] x{PBEBattle.GetStatChangeModifier(pkmn.AccuracyChange, true):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.Evasion) != -1)
                    {
                        statStrs.Add($"[E] x{PBEBattle.GetStatChangeModifier(pkmn.EvasionChange, true):0.00}");
                    }
                    sb.AppendLine($"Stat changes: {string.Join(", ", statStrs)}");
                }
            }

            void AddStatus1()
            {
                if (pkmn.Status1 != PBEStatus1.None)
                {
                    sb.AppendLine($"Main status: {pkmn.Status1}");
                    if (pkmn.Status1 == PBEStatus1.Asleep)
                    {
                        sb.AppendLine($"Asleep turns: {pkmn.Status1Counter}");
                    }
                    else if (pkmn.Status1 == PBEStatus1.BadlyPoisoned)
                    {
                        sb.AppendLine($"Toxic counter: {pkmn.Status1Counter}");
                    }
                }
            }

            void AddStatus2(PBEStatus2 status2)
            {
                status2 &= ~PBEStatus2.Flinching; // Don't show flinching
                sb.AppendLine($"Volatile status: {status2}");
                if (status2.HasFlag(PBEStatus2.Disguised))
                {
                    sb.AppendLine($"Disguised as: {pkmn.DisguisedAsPokemon.Nickname}");
                }
                if (pkmn.Battle.BattleFormat != PBEBattleFormat.Single)
                {
                    if (status2.HasFlag(PBEStatus2.Infatuated))
                    {
                        sb.AppendLine($"Infatuated with: {GetTeamNickname(pkmn.InfatuatedWithPokemon)}");
                    }
                    if (status2.HasFlag(PBEStatus2.LeechSeed))
                    {
                        sb.AppendLine($"Seeded position: {pkmn.SeededTeam.CombinedName}'s {pkmn.SeededPosition}");
                    }
                    if (status2.HasFlag(PBEStatus2.LockOn))
                    {
                        sb.AppendLine($"Taking aim at: {GetTeamNickname(pkmn.LockOnPokemon)}");
                    }
                }
            }

            if (useKnownInfo)
            {
                var    pData   = PBEPokemonData.GetData(pkmn.KnownSpecies, pkmn.KnownForm);
                string formStr = PBEDataUtils.HasForms(pkmn.KnownSpecies, false) ? $" ({PBELocalizedString.GetFormName(pkmn.KnownSpecies, pkmn.KnownForm)})" : string.Empty;
                sb.AppendLine($"{pkmn.KnownNickname}/{pkmn.KnownSpecies}{formStr} {(pkmn.KnownStatus2.HasFlag(PBEStatus2.Transformed) ? pkmn.Gender.ToSymbol() : pkmn.KnownGender.ToSymbol())} Lv.{pkmn.Level}");
                sb.AppendLine($"HP: {pkmn.HPPercentage:P2}");
                sb.Append($"Known types: {PBELocalizedString.GetTypeName(pkmn.KnownType1)}");
                if (pkmn.KnownType2 != PBEType.None)
                {
                    sb.Append($"/{PBELocalizedString.GetTypeName(pkmn.KnownType2)}");
                }
                sb.AppendLine();
                if (pkmn.FieldPosition != PBEFieldPosition.None)
                {
                    sb.AppendLine($"Position: {pkmn.Team.CombinedName}'s {pkmn.FieldPosition}");
                }
                AddStatus1();
                if (pkmn.FieldPosition != PBEFieldPosition.None)
                {
                    if (pkmn.KnownStatus2 != PBEStatus2.None)
                    {
                        AddStatus2(pkmn.KnownStatus2);
                    }
                }
                PBEDataUtils.GetStatRange(pData, PBEStat.HP, pkmn.Level, pkmn.Battle.Settings, out ushort lowHP, out ushort highHP);
                PBEDataUtils.GetStatRange(pData, PBEStat.Attack, pkmn.Level, pkmn.Battle.Settings, out ushort lowAttack, out ushort highAttack);
                PBEDataUtils.GetStatRange(pData, PBEStat.Defense, pkmn.Level, pkmn.Battle.Settings, out ushort lowDefense, out ushort highDefense);
                PBEDataUtils.GetStatRange(pData, PBEStat.SpAttack, pkmn.Level, pkmn.Battle.Settings, out ushort lowSpAttack, out ushort highSpAttack);
                PBEDataUtils.GetStatRange(pData, PBEStat.SpDefense, pkmn.Level, pkmn.Battle.Settings, out ushort lowSpDefense, out ushort highSpDefense);
                PBEDataUtils.GetStatRange(pData, PBEStat.Speed, pkmn.Level, pkmn.Battle.Settings, out ushort lowSpeed, out ushort highSpeed);
                sb.AppendLine($"Stat range: [HP] {lowHP}-{highHP}, [A] {lowAttack}-{highAttack}, [D] {lowDefense}-{highDefense}, [SA] {lowSpAttack}-{highSpAttack}, [SD] {lowSpDefense}-{highSpDefense}, [S] {lowSpeed}-{highSpeed}, [W] {pkmn.KnownWeight:0.0}");
                if (pkmn.FieldPosition != PBEFieldPosition.None)
                {
                    AddStatChanges();
                }
                if (pkmn.KnownAbility == PBEAbility.MAX)
                {
                    sb.AppendLine($"Possible abilities: {string.Join(", ", pData.Abilities.Select(a => PBELocalizedString.GetAbilityName(a).ToString()))}");
                }
                else
                {
                    sb.AppendLine($"Known ability: {PBELocalizedString.GetAbilityName(pkmn.KnownAbility)}");
                }
                sb.AppendLine($"Known item: {(pkmn.KnownItem == (PBEItem)ushort.MaxValue ? "???" : PBELocalizedString.GetItemName(pkmn.KnownItem).ToString())}");
                sb.Append("Known moves: ");
                for (int i = 0; i < pkmn.Battle.Settings.NumMoves; i++)
                {
                    PBEBattleMoveset.PBEBattleMovesetSlot slot = pkmn.KnownMoves[i];
                    PBEMove move  = slot.Move;
                    int     pp    = slot.PP;
                    int     maxPP = slot.MaxPP;
                    if (i > 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(move == PBEMove.MAX ? "???" : PBELocalizedString.GetMoveName(move).ToString());
                    if (move != PBEMove.None && move != PBEMove.MAX)
                    {
                        sb.Append($" ({pp}{(maxPP == 0 ? ")" : $"/{maxPP})")}");
                    }
                }
            }
Beispiel #6
0
        protected override bool ProcessPacket(IPBEPacket packet)
        {
            switch (packet)
            {
            case PBEAbilityPacket ap:
            {
                PBEBattlePokemon abilityOwner = ap.AbilityOwnerTrainer.TryGetPokemon(ap.AbilityOwner);
                abilityOwner.Ability      = ap.Ability;
                abilityOwner.KnownAbility = ap.Ability;
                break;
            }

            case PBEAbilityReplacedPacket arp:
            {
                PBEBattlePokemon abilityOwner = arp.AbilityOwnerTrainer.TryGetPokemon(arp.AbilityOwner);
                abilityOwner.Ability      = arp.NewAbility;
                abilityOwner.KnownAbility = arp.NewAbility;
                break;
            }

            case PBEBattleStatusPacket bsp:
            {
                switch (bsp.BattleStatusAction)
                {
                case PBEBattleStatusAction.Added: Battle.BattleStatus |= bsp.BattleStatus; break;

                case PBEBattleStatusAction.Cleared:
                case PBEBattleStatusAction.Ended: Battle.BattleStatus &= ~bsp.BattleStatus; break;

                default: throw new ArgumentOutOfRangeException(nameof(bsp.BattleStatusAction));
                }
                break;
            }

            case PBECapturePacket cp:
            {
                if (cp.Success)
                {
                    PBEBattlePokemon pokemon = cp.PokemonTrainer.TryGetPokemon(cp.Pokemon);
                    pokemon.CaughtBall      = cp.Ball;
                    pokemon.KnownCaughtBall = cp.Ball;
                }
                break;
            }

            case PBEHazePacket _:
            {
                foreach (PBEBattlePokemon pkmn in Battle.ActiveBattlers)
                {
                    pkmn.ClearStatChanges();
                }
                break;
            }

            case PBEIllusionPacket ilp:
            {
                PBEBattlePokemon pokemon = ilp.PokemonTrainer.TryGetPokemon(ilp.Pokemon);
                pokemon.Ability    = pokemon.KnownAbility = PBEAbility.Illusion;
                pokemon.Gender     = pokemon.KnownGender = ilp.ActualGender;
                pokemon.CaughtBall = pokemon.KnownCaughtBall = ilp.ActualCaughtBall;
                pokemon.Nickname   = pokemon.KnownNickname = ilp.ActualNickname;
                pokemon.Shiny      = pokemon.KnownShiny = ilp.ActualShiny;
                pokemon.Species    = pokemon.KnownSpecies = ilp.ActualSpecies;
                pokemon.Form       = pokemon.KnownForm = ilp.ActualForm;
                pokemon.Type1      = pokemon.KnownType1 = ilp.ActualType1;
                pokemon.Type2      = pokemon.KnownType2 = ilp.ActualType2;
                pokemon.Weight     = pokemon.KnownWeight = ilp.ActualWeight;
                return(true);
            }

            case PBEItemPacket ip:
            {
                PBEBattlePokemon itemHolder = ip.ItemHolderTrainer.TryGetPokemon(ip.ItemHolder);
                switch (ip.ItemAction)
                {
                case PBEItemAction.Announced:
                case PBEItemAction.Damage:
                case PBEItemAction.RestoredHP: itemHolder.Item = itemHolder.KnownItem = ip.Item; break;

                case PBEItemAction.Consumed: itemHolder.Item = itemHolder.KnownItem = PBEItem.None; break;

                default: throw new ArgumentOutOfRangeException(nameof(ip.ItemAction));
                }
                break;
            }

            case PBEMoveLockPacket mlp:
            {
                PBEBattlePokemon moveUser = mlp.MoveUserTrainer.TryGetPokemon(mlp.MoveUser);
                switch (mlp.MoveLockType)
                {
                case PBEMoveLockType.ChoiceItem: moveUser.ChoiceLockedMove = mlp.LockedMove; break;

                case PBEMoveLockType.Temporary: moveUser.TempLockedMove = mlp.LockedMove; break;

                default: throw new ArgumentOutOfRangeException(nameof(mlp.MoveLockType));
                }
                if (mlp.LockedTargets.HasValue)
                {
                    moveUser.TempLockedTargets = mlp.LockedTargets.Value;
                }
                return(true);
            }

            case PBEMovePPChangedPacket mpcp:
            {
                PBEBattlePokemon moveUser = mpcp.MoveUserTrainer.TryGetPokemon(mpcp.MoveUser);
                moveUser.UpdateKnownPP(mpcp.Move, mpcp.AmountReduced);
                return(true);
            }

            case PBEMoveUsedPacket mup:
            {
                PBEBattlePokemon moveUser = mup.MoveUserTrainer.TryGetPokemon(mup.MoveUser);
                if (mup.Owned && !moveUser.KnownMoves.Contains(mup.Move))
                {
                    moveUser.KnownMoves[PBEMove.MAX].Move = mup.Move;
                    PBEBattleMoveset.PBEBattleMovesetSlot slot = moveUser.Moves[PBEMove.MAX];
                    if (slot != null)
                    {
                        slot.Move = mup.Move;     // Copy to Moves as well so Transform doesn't break for spectators/allies
                    }
                }
                break;
            }

            case PBEPkmnFaintedPacket pfp:
            {
                bool             ret     = base.ProcessPacket(packet); // Process before removal
                PBEBattlePokemon pokemon = pfp.PokemonTrainer.TryGetPokemon(pfp.Pokemon);
                Battle.ActiveBattlers.Remove(pokemon);
                pokemon.ClearForFaint();
                return(ret);
            }

            case PBEPkmnFormChangedPacket pfcp:
            {
                PBEBattlePokemon pokemon = pfcp.PokemonTrainer.TryGetPokemon(pfcp.Pokemon);
                pokemon.Attack       = pfcp.NewAttack;
                pokemon.Defense      = pfcp.NewDefense;
                pokemon.SpAttack     = pfcp.NewSpAttack;
                pokemon.SpDefense    = pfcp.NewSpDefense;
                pokemon.Speed        = pfcp.NewSpeed;
                pokemon.Ability      = pfcp.NewAbility;
                pokemon.KnownAbility = pfcp.NewKnownAbility;
                pokemon.Form         = pokemon.KnownForm = pfcp.NewForm;
                pokemon.Type1        = pokemon.KnownType1 = pfcp.NewType1;
                pokemon.Type2        = pokemon.KnownType2 = pfcp.NewType2;
                pokemon.Weight       = pokemon.KnownWeight = pfcp.NewWeight;
                if (pfcp.IsRevertForm)
                {
                    pokemon.RevertForm    = pfcp.NewForm;
                    pokemon.RevertAbility = pfcp.NewAbility;
                }
                break;
            }

            case PBEPkmnHPChangedPacket phcp:
            {
                PBEBattlePokemon pokemon = phcp.PokemonTrainer.TryGetPokemon(phcp.Pokemon);
                pokemon.HP           = phcp.NewHP;
                pokemon.HPPercentage = phcp.NewHPPercentage;
                break;
            }

            case PBEPkmnStatChangedPacket pscp:
            {
                PBEBattlePokemon pokemon = pscp.PokemonTrainer.TryGetPokemon(pscp.Pokemon);
                pokemon.SetStatChange(pscp.Stat, pscp.NewValue);
                break;
            }

            case PBEPkmnSwitchInPacket psip:
            {
                foreach (PBEPkmnAppearedInfo info in psip.SwitchIns)
                {
                    PBEBattlePokemon pokemon = psip.Trainer.TryGetPokemon(info.Pokemon);
                    pokemon.FieldPosition = info.FieldPosition;
                    PBETrainer.SwitchTwoPokemon(pokemon, info.FieldPosition);
                    DoDisguisedAppearance(pokemon, info);
                    Battle.ActiveBattlers.Add(pokemon);
                }
                break;
            }

            case PBEPkmnSwitchOutPacket psop:
            {
                bool             ret     = base.ProcessPacket(packet); // Process before removal
                PBEBattlePokemon pokemon = psop.PokemonTrainer.TryGetPokemon(psop.Pokemon);
                Battle.ActiveBattlers.Remove(pokemon);
                pokemon.ClearForSwitch();
                return(ret);
            }

            case PBEPsychUpPacket pup:
            {
                PBEBattlePokemon user   = pup.UserTrainer.TryGetPokemon(pup.User);
                PBEBattlePokemon target = pup.TargetTrainer.TryGetPokemon(pup.Target);
                user.AttackChange    = target.AttackChange = pup.AttackChange;
                user.DefenseChange   = target.DefenseChange = pup.DefenseChange;
                user.SpAttackChange  = target.SpAttackChange = pup.SpAttackChange;
                user.SpDefenseChange = target.SpDefenseChange = pup.SpDefenseChange;
                user.SpeedChange     = target.SpeedChange = pup.SpeedChange;
                user.AccuracyChange  = target.AccuracyChange = pup.AccuracyChange;
                user.EvasionChange   = target.EvasionChange = pup.EvasionChange;
                break;
            }

            case PBEReflectTypePacket rtp:
            {
                PBEBattlePokemon user   = rtp.UserTrainer.TryGetPokemon(rtp.User);
                PBEBattlePokemon target = rtp.TargetTrainer.TryGetPokemon(rtp.Target);
                user.Type1 = user.KnownType1 = target.KnownType1 = target.Type1 = rtp.Type1;
                user.Type2 = user.KnownType2 = target.KnownType2 = target.Type2 = rtp.Type2;
                break;
            }

            case PBEStatus1Packet s1p:
            {
                PBEBattlePokemon status1Receiver = s1p.Status1ReceiverTrainer.TryGetPokemon(s1p.Status1Receiver);
                switch (s1p.StatusAction)
                {
                case PBEStatusAction.Added:
                case PBEStatusAction.Announced:
                case PBEStatusAction.CausedImmobility:
                case PBEStatusAction.Damage: status1Receiver.Status1 = s1p.Status1; break;

                case PBEStatusAction.Cleared:
                case PBEStatusAction.Ended: status1Receiver.Status1 = PBEStatus1.None; break;

                default: throw new ArgumentOutOfRangeException(nameof(s1p.StatusAction));
                }
                break;
            }

            case PBEStatus2Packet s2p:
            {
                PBEBattlePokemon status2Receiver = s2p.Status2ReceiverTrainer.TryGetPokemon(s2p.Status2Receiver);
                PBEBattlePokemon pokemon2        = s2p.Pokemon2Trainer.TryGetPokemon(s2p.Pokemon2);
                switch (s2p.StatusAction)
                {
                case PBEStatusAction.Added:
                case PBEStatusAction.Announced:
                case PBEStatusAction.CausedImmobility:
                case PBEStatusAction.Damage: status2Receiver.Status2 |= s2p.Status2; status2Receiver.KnownStatus2 |= s2p.Status2; break;

                case PBEStatusAction.Cleared:
                case PBEStatusAction.Ended: status2Receiver.Status2 &= ~s2p.Status2; status2Receiver.KnownStatus2 &= ~s2p.Status2; break;

                default: throw new ArgumentOutOfRangeException(nameof(s2p.StatusAction));
                }
                switch (s2p.Status2)
                {
                case PBEStatus2.Infatuated:
                {
                    switch (s2p.StatusAction)
                    {
                    case PBEStatusAction.Added: status2Receiver.InfatuatedWithPokemon = pokemon2; break;

                    case PBEStatusAction.Cleared:
                    case PBEStatusAction.Ended: status2Receiver.InfatuatedWithPokemon = null; break;
                    }
                    break;
                }

                case PBEStatus2.LeechSeed:
                {
                    switch (s2p.StatusAction)
                    {
                    case PBEStatusAction.Added: status2Receiver.SeededPosition = pokemon2.FieldPosition; status2Receiver.SeededTeam = pokemon2.Team; break;
                    }
                    break;
                }

                case PBEStatus2.LockOn:
                {
                    switch (s2p.StatusAction)
                    {
                    case PBEStatusAction.Added: status2Receiver.LockOnPokemon = pokemon2; break;

                    case PBEStatusAction.Ended: status2Receiver.LockOnPokemon = null; break;
                    }
                    break;
                }

                case PBEStatus2.PowerTrick:
                {
                    switch (s2p.StatusAction)
                    {
                    case PBEStatusAction.Added: status2Receiver.ApplyPowerTrickChange(); break;
                    }
                    break;
                }

                case PBEStatus2.Roost:
                {
                    switch (s2p.StatusAction)
                    {
                    case PBEStatusAction.Added: status2Receiver.StartRoost(); break;

                    case PBEStatusAction.Ended: status2Receiver.EndRoost(); break;
                    }
                    break;
                }

                case PBEStatus2.Transformed:
                    switch (s2p.StatusAction)
                    {
                    case PBEStatusAction.Added: status2Receiver.Transform(pokemon2); break;
                    }
                    break;
                }
                break;
            }

            case PBETeamStatusPacket tsp:
            {
                PBETeam team = tsp.Team;
                switch (tsp.TeamStatusAction)
                {
                case PBETeamStatusAction.Added:
                case PBETeamStatusAction.Damage: team.TeamStatus |= tsp.TeamStatus; break;

                case PBETeamStatusAction.Cleared:
                case PBETeamStatusAction.Ended: team.TeamStatus &= ~tsp.TeamStatus; break;

                default: throw new ArgumentOutOfRangeException(nameof(tsp.TeamStatusAction));
                }
                switch (tsp.TeamStatus)
                {
                case PBETeamStatus.Spikes:
                {
                    switch (tsp.TeamStatusAction)
                    {
                    case PBETeamStatusAction.Added: team.SpikeCount++; break;
                        //case PBETeamStatusAction.Cleared: team.SpikeCount = 0; break;
                    }
                    break;
                }

                case PBETeamStatus.ToxicSpikes:
                {
                    switch (tsp.TeamStatusAction)
                    {
                    case PBETeamStatusAction.Added: team.ToxicSpikeCount++; break;

                    case PBETeamStatusAction.Cleared: team.ToxicSpikeCount = 0; break;
                    }
                    break;
                }
                }
                break;
            }

            case PBETransformPacket tp:
            {
                PBEBattlePokemon target = tp.TargetTrainer.TryGetPokemon(tp.Target);
                target.Attack          = tp.TargetAttack;
                target.Defense         = tp.TargetDefense;
                target.SpAttack        = tp.TargetSpAttack;
                target.SpDefense       = tp.TargetSpDefense;
                target.Speed           = tp.TargetSpeed;
                target.AttackChange    = tp.TargetAttackChange;
                target.DefenseChange   = tp.TargetDefenseChange;
                target.SpAttackChange  = tp.TargetSpAttackChange;
                target.SpDefenseChange = tp.TargetSpDefenseChange;
                target.SpeedChange     = tp.TargetSpeedChange;
                target.AccuracyChange  = tp.TargetAccuracyChange;
                target.EvasionChange   = tp.TargetEvasionChange;
                target.Ability         = target.KnownAbility = tp.TargetAbility;
                for (int i = 0; i < Battle.Settings.NumMoves; i++)
                {
                    target.Moves[i].Move = tp.TargetMoves[i];
                }
                target.Species = target.KnownSpecies = tp.TargetSpecies;
                target.Form    = target.KnownForm = tp.TargetForm;
                target.Type1   = target.KnownType1 = tp.TargetType1;
                target.Type2   = target.KnownType2 = tp.TargetType2;
                target.Weight  = target.KnownWeight = tp.TargetWeight;
                return(true);
            }

            case PBETypeChangedPacket tcp:
            {
                PBEBattlePokemon pokemon = tcp.PokemonTrainer.TryGetPokemon(tcp.Pokemon);
                pokemon.Type1 = pokemon.KnownType1 = tcp.Type1;
                pokemon.Type2 = pokemon.KnownType2 = tcp.Type2;
                break;
            }

            case PBEWeatherPacket wp:
            {
                switch (wp.WeatherAction)
                {
                case PBEWeatherAction.Added:
                case PBEWeatherAction.CausedDamage: Battle.Weather = wp.Weather; break;

                case PBEWeatherAction.Ended: Battle.Weather = PBEWeather.None; break;

                default: throw new ArgumentOutOfRangeException(nameof(wp.WeatherAction));
                }
                break;
            }

            case PBEWildPkmnAppearedPacket wpap:
            {
                PBETrainer wildTrainer = Battle.Teams[1].Trainers[0];
                foreach (PBEPkmnAppearedInfo info in wpap.Pokemon)
                {
                    PBEBattlePokemon pokemon = wildTrainer.TryGetPokemon(info.Pokemon);
                    DoDisguisedAppearance(pokemon, info);
                }
                break;
            }

            case IPBEAutoCenterPacket acp:
            {
                PBEBattlePokemon pokemon0 = acp.Pokemon0Trainer.TryGetPokemon(acp.Pokemon0OldPosition);
                PBEBattlePokemon pokemon1 = acp.Pokemon1Trainer.TryGetPokemon(acp.Pokemon1OldPosition);
                pokemon0.FieldPosition = PBEFieldPosition.Center;
                pokemon1.FieldPosition = PBEFieldPosition.Center;
                break;
            }

            case PBEBattleResultPacket brp:
            {
                Battle.BattleResult = brp.BattleResult;
                break;
            }

            case PBETurnBeganPacket tbp:
            {
                Battle.TurnNumber = tbp.TurnNumber;
                break;
            }
            }
            return(base.ProcessPacket(packet));
        }
Beispiel #7
0
        public static string CustomPokemonToString(PBEPokemon pkmn, bool showRawValues0, bool showRawValues1)
        {
            var sb = new StringBuilder();

            void AddStatChanges()
            {
                PBEStat[] statChanges = pkmn.GetChangedStats();
                if (statChanges.Length > 0)
                {
                    var statStrs = new List <string>(7);
                    if (Array.IndexOf(statChanges, PBEStat.Attack) != -1)
                    {
                        statStrs.Add($"[A] x{PBEBattle.GetStatChangeModifier(pkmn.AttackChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.Defense) != -1)
                    {
                        statStrs.Add($"[D] x{PBEBattle.GetStatChangeModifier(pkmn.DefenseChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.SpAttack) != -1)
                    {
                        statStrs.Add($"[SA] x{PBEBattle.GetStatChangeModifier(pkmn.SpAttackChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.SpDefense) != -1)
                    {
                        statStrs.Add($"[SD] x{PBEBattle.GetStatChangeModifier(pkmn.SpDefenseChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.Speed) != -1)
                    {
                        statStrs.Add($"[S] x{PBEBattle.GetStatChangeModifier(pkmn.SpeedChange, false):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.Accuracy) != -1)
                    {
                        statStrs.Add($"[AC] x{PBEBattle.GetStatChangeModifier(pkmn.AccuracyChange, true):0.00}");
                    }
                    if (Array.IndexOf(statChanges, PBEStat.Evasion) != -1)
                    {
                        statStrs.Add($"[E] x{PBEBattle.GetStatChangeModifier(pkmn.EvasionChange, true):0.00}");
                    }
                    sb.AppendLine($"Stat changes: {string.Join(", ", statStrs)}");
                }
            }

            if ((pkmn.Team.Id == 0 && !showRawValues0) || (pkmn.Team.Id == 1 && !showRawValues1))
            {
                sb.AppendLine($"{pkmn.KnownNickname}/{pkmn.KnownSpecies} {(pkmn.Status2.HasFlag(PBEStatus2.Transformed) ? pkmn.GenderSymbol : pkmn.KnownGenderSymbol)} Lv.{pkmn.Level}");
                sb.AppendLine($"HP: {pkmn.HPPercentage:P2}");
                sb.Append($"Known types: {PBELocalizedString.GetTypeName(pkmn.KnownType1).ToString()}");
                if (pkmn.KnownType2 != PBEType.None)
                {
                    sb.Append($"/{PBELocalizedString.GetTypeName(pkmn.KnownType2).ToString()}");
                }
                sb.AppendLine();
                if (pkmn.FieldPosition != PBEFieldPosition.None)
                {
                    sb.AppendLine($"Position: {pkmn.Team.TrainerName}'s {pkmn.FieldPosition}");
                }
                if (pkmn.Status1 != PBEStatus1.None)
                {
                    sb.AppendLine($"Main status: {pkmn.Status1}");
                }
                if (pkmn.FieldPosition != PBEFieldPosition.None)
                {
                    PBEStatus2 cleanStatus2 = pkmn.Status2;
                    cleanStatus2 &= ~PBEStatus2.Disguised;
                    if (cleanStatus2 != PBEStatus2.None)
                    {
                        sb.AppendLine($"Volatile status: {cleanStatus2}");
                        if (cleanStatus2.HasFlag(PBEStatus2.Infatuated))
                        {
                            sb.AppendLine($"Infatuated with: {((pkmn.InfatuatedWithPokemon.Team.Id == 0 && showRawValues0) || (pkmn.InfatuatedWithPokemon.Team.Id == 1 && showRawValues1) ? pkmn.InfatuatedWithPokemon.Nickname : pkmn.InfatuatedWithPokemon.KnownNickname)}");
                        }
                        if (cleanStatus2.HasFlag(PBEStatus2.LeechSeed))
                        {
                            sb.AppendLine($"Seeded position: {pkmn.SeededTeam.TrainerName}'s {pkmn.SeededPosition}");
                        }
                    }
                }
                PBEPokemonData.GetStatRange(PBEStat.HP, pkmn.KnownSpecies, pkmn.Level, pkmn.Team.Battle.Settings, out ushort lowHP, out ushort highHP);
                PBEPokemonData.GetStatRange(PBEStat.Attack, pkmn.KnownSpecies, pkmn.Level, pkmn.Team.Battle.Settings, out ushort lowAttack, out ushort highAttack);
                PBEPokemonData.GetStatRange(PBEStat.Defense, pkmn.KnownSpecies, pkmn.Level, pkmn.Team.Battle.Settings, out ushort lowDefense, out ushort highDefense);
                PBEPokemonData.GetStatRange(PBEStat.SpAttack, pkmn.KnownSpecies, pkmn.Level, pkmn.Team.Battle.Settings, out ushort lowSpAttack, out ushort highSpAttack);
                PBEPokemonData.GetStatRange(PBEStat.SpDefense, pkmn.KnownSpecies, pkmn.Level, pkmn.Team.Battle.Settings, out ushort lowSpDefense, out ushort highSpDefense);
                PBEPokemonData.GetStatRange(PBEStat.Speed, pkmn.KnownSpecies, pkmn.Level, pkmn.Team.Battle.Settings, out ushort lowSpeed, out ushort highSpeed);
                sb.AppendLine($"Stat range: [HP] {lowHP}-{highHP}, [A] {lowAttack}-{highAttack}, [D] {lowDefense}-{highDefense}, [SA] {lowSpAttack}-{highSpAttack}, [SD] {lowSpDefense}-{highSpDefense}, [S] {lowSpeed}-{highSpeed}, [W] {pkmn.KnownWeight:0.0}");
                if (pkmn.FieldPosition != PBEFieldPosition.None)
                {
                    AddStatChanges();
                }
                if (pkmn.KnownAbility == PBEAbility.MAX)
                {
                    sb.AppendLine($"Possible abilities: {string.Join(", ", PBEPokemonData.GetData(pkmn.KnownSpecies).Abilities.Select(a => PBELocalizedString.GetAbilityName(a).ToString()))}");
                }
                else
                {
                    sb.AppendLine($"Known ability: {PBELocalizedString.GetAbilityName(pkmn.KnownAbility).ToString()}");
                }
                sb.AppendLine($"Known item: {(pkmn.KnownItem == (PBEItem)ushort.MaxValue ? "???" : PBELocalizedString.GetItemName(pkmn.KnownItem).ToString())}");
                sb.Append("Known moves: ");
                for (int i = 0; i < pkmn.Team.Battle.Settings.NumMoves; i++)
                {
                    PBEBattleMoveset.PBEBattleMovesetSlot slot = pkmn.KnownMoves[i];
                    PBEMove move  = slot.Move;
                    int     pp    = slot.PP;
                    int     maxPP = slot.MaxPP;
                    if (i > 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(move == PBEMove.MAX ? "???" : PBELocalizedString.GetMoveName(move).ToString());
                    if (move != PBEMove.None && move != PBEMove.MAX)
                    {
                        sb.Append($" ({pp}{(maxPP == 0 ? ")" : $"/{maxPP})")}");
                    }
                }
            }
        private string CreateKnownPokemonEmbed(PBEBattlePokemon pkmn)
        {
            IPBEPokemonData pData   = PBEDataProvider.Instance.GetPokemonData(pkmn.KnownSpecies, pkmn.KnownForm);
            var             sb      = new StringBuilder();
            string          formStr = PBEDataUtils.HasForms(pkmn.KnownSpecies, false) ? $" ({PBEDataProvider.Instance.GetFormName(pkmn.KnownSpecies, pkmn.KnownForm).English})" : string.Empty;

            sb.AppendLine($"{GetTrainerName(pkmn.Trainer)}'s {pkmn.KnownNickname}/{pkmn.KnownSpecies}{formStr} {(pkmn.KnownStatus2.HasFlag(PBEStatus2.Transformed) ? pkmn.Gender.ToSymbol() : pkmn.KnownGender.ToSymbol())} Lv.{pkmn.Level}{(pkmn.KnownShiny ? $" {_shinyEmoji}" : string.Empty)}");
            sb.AppendLine($"**HP:** {pkmn.HPPercentage:P2}");
            sb.Append($"**Known types:** {Utils.TypeEmotes[pkmn.KnownType1]}");
            if (pkmn.KnownType2 != PBEType.None)
            {
                sb.Append($" {Utils.TypeEmotes[pkmn.KnownType2]}");
            }
            sb.AppendLine();
            if (pkmn.Status1 != PBEStatus1.None)
            {
                sb.AppendLine($"**Main status:** {Utils.Status1Emotes[pkmn.Status1]}");
                if (pkmn.Status1 == PBEStatus1.Asleep)
                {
                    sb.AppendLine($"**{Utils.Status1Emotes[PBEStatus1.Asleep]} turns:** {pkmn.Status1Counter}");
                }
                else if (pkmn.Status1 == PBEStatus1.BadlyPoisoned)
                {
                    sb.AppendLine($"**{Utils.Status1Emotes[PBEStatus1.BadlyPoisoned]} counter:** {pkmn.Status1Counter}");
                }
            }
            if (pkmn.KnownStatus2 != PBEStatus2.None)
            {
                sb.AppendLine($"**Volatile status:** {pkmn.KnownStatus2}");
                if (pkmn.KnownStatus2.HasFlag(PBEStatus2.Confused))
                {
                    sb.AppendLine($"**Confusion turns:** {pkmn.ConfusionCounter}");
                }
            }
            PBEDataUtils.GetStatRange(pData, PBEStat.HP, pkmn.Level, PBESettings.DefaultSettings, out ushort lowHP, out ushort highHP);
            PBEDataUtils.GetStatRange(pData, PBEStat.Attack, pkmn.Level, PBESettings.DefaultSettings, out ushort lowAttack, out ushort highAttack);
            PBEDataUtils.GetStatRange(pData, PBEStat.Defense, pkmn.Level, PBESettings.DefaultSettings, out ushort lowDefense, out ushort highDefense);
            PBEDataUtils.GetStatRange(pData, PBEStat.SpAttack, pkmn.Level, PBESettings.DefaultSettings, out ushort lowSpAttack, out ushort highSpAttack);
            PBEDataUtils.GetStatRange(pData, PBEStat.SpDefense, pkmn.Level, PBESettings.DefaultSettings, out ushort lowSpDefense, out ushort highSpDefense);
            PBEDataUtils.GetStatRange(pData, PBEStat.Speed, pkmn.Level, PBESettings.DefaultSettings, out ushort lowSpeed, out ushort highSpeed);
            sb.AppendLine($"**Stat range:** [HP] {lowHP}-{highHP}, [A] {lowAttack}-{highAttack}, [D] {lowDefense}-{highDefense}, [SA] {lowSpAttack}-{highSpAttack}, [SD] {lowSpDefense}-{highSpDefense}, [S] {lowSpeed}-{highSpeed}, [W] {pkmn.KnownWeight:0.0}");
            AddStatChanges(pkmn, sb);
            if (pkmn.KnownAbility == PBEAbility.MAX)
            {
                sb.AppendLine($"**Possible abilities:** {string.Join(", ", pData.Abilities.Select(a => PBEDataProvider.Instance.GetAbilityName(a).English))}");
            }
            else
            {
                sb.AppendLine($"**Known ability:** {PBEDataProvider.Instance.GetAbilityName(pkmn.KnownAbility).English}");
            }
            sb.AppendLine($"**Known item:** {(pkmn.KnownItem == (PBEItem)ushort.MaxValue ? "???" : PBEDataProvider.Instance.GetItemName(pkmn.KnownItem).English)}");
            sb.Append("**Known moves:** ");
            for (int i = 0; i < PBESettings.DefaultNumMoves; i++)
            {
                PBEBattleMoveset.PBEBattleMovesetSlot slot = pkmn.KnownMoves[i];
                PBEMove move = slot.Move;
                if (move != PBEMove.None)
                {
                    int pp    = slot.PP;
                    int maxPP = slot.MaxPP;
                    if (i > 0)
                    {
                        sb.Append(", ");
                    }
                    if (move == PBEMove.MAX)
                    {
                        sb.Append("???");
                    }
                    else
                    {
                        sb.Append($"{Utils.TypeEmotes[pkmn.GetMoveType(move, useKnownInfo: true)]} {PBEDataProvider.Instance.GetMoveName(move).English} ({pp}{(maxPP == 0 ? ")" : $"/{maxPP})")}");
                    }
                }
            }
        private static void CreatePokemonEmbed(PBEBattlePokemon pkmn, bool addReactionChars, out string outStr, out EmbedFieldBuilder[] outFields)
        {
            var    sb      = new StringBuilder();
            string formStr = PBEDataUtils.HasForms(pkmn.Species, false) ? $" ({PBEDataProvider.Instance.GetFormName(pkmn).English})" : string.Empty;

            sb.AppendLine($"{pkmn.Nickname}/{PBEDataProvider.Instance.GetSpeciesName(pkmn.Species).English}{formStr} {pkmn.Gender.ToSymbol()} Lv.{pkmn.Level}{(pkmn.Shiny ? $" {_shinyEmoji}" : string.Empty)}");
            sb.AppendLine($"**HP:** {pkmn.HP}/{pkmn.MaxHP} ({pkmn.HPPercentage:P2})");
            sb.Append($"**Types:** {Utils.TypeEmotes[pkmn.Type1]}");
            if (pkmn.Type2 != PBEType.None)
            {
                sb.Append($" {Utils.TypeEmotes[pkmn.Type2]}");
            }
            sb.AppendLine();
            if (pkmn.Status1 != PBEStatus1.None)
            {
                sb.AppendLine($"**Main status:** {Utils.Status1Emotes[pkmn.Status1]}");
            }
            if (pkmn.FieldPosition != PBEFieldPosition.None)
            {
                if (pkmn.Status1 == PBEStatus1.Asleep)
                {
                    sb.AppendLine($"**{Utils.Status1Emotes[PBEStatus1.Asleep]} turns:** {pkmn.Status1Counter}");
                }
                else if (pkmn.Status1 == PBEStatus1.BadlyPoisoned)
                {
                    sb.AppendLine($"**{Utils.Status1Emotes[PBEStatus1.BadlyPoisoned]} counter:** {pkmn.Status1Counter}");
                }
                if (pkmn.Status2 != PBEStatus2.None)
                {
                    sb.AppendLine($"**Volatile status:** {pkmn.Status2}");
                    if (pkmn.Status2.HasFlag(PBEStatus2.Confused))
                    {
                        sb.AppendLine($"**Confusion turns:** {pkmn.ConfusionCounter}");
                    }
                    if (pkmn.Status2.HasFlag(PBEStatus2.Disguised))
                    {
                        formStr = PBEDataUtils.HasForms(pkmn.KnownSpecies, false) ? $" ({PBEDataProvider.Instance.GetFormName(pkmn.KnownSpecies, pkmn.KnownForm).English})" : string.Empty;
                        sb.AppendLine($"**Disguised as:** {pkmn.KnownNickname}/{PBEDataProvider.Instance.GetSpeciesName(pkmn.KnownSpecies).English}{formStr} {pkmn.KnownGender.ToSymbol()}");
                    }
                    if (pkmn.Status2.HasFlag(PBEStatus2.Substitute))
                    {
                        sb.AppendLine($"**Substitute HP:** {pkmn.SubstituteHP}");
                    }
                }
            }
            sb.AppendLine($"**Stats:** [A] {pkmn.Attack}, [D] {pkmn.Defense}, [SA] {pkmn.SpAttack}, [SD] {pkmn.SpDefense}, [S] {pkmn.Speed}, [W] {pkmn.Weight:0.0}");
            if (pkmn.FieldPosition != PBEFieldPosition.None)
            {
                AddStatChanges(pkmn, sb);
            }
            sb.AppendLine($"**Ability:** {PBEDataProvider.Instance.GetAbilityName(pkmn.Ability).English}");
            sb.AppendLine($"**Item:** {PBEDataProvider.Instance.GetItemName(pkmn.Item).English}");
            if (pkmn.Moves.Contains(PBEMoveEffect.Frustration) || pkmn.Moves.Contains(PBEMoveEffect.Return))
            {
                sb.AppendLine($"**Friendship:** {pkmn.Friendship} ({pkmn.Friendship / (double)byte.MaxValue:P2})");
            }
            if (pkmn.Moves.Contains(PBEMoveEffect.HiddenPower))
            {
                sb.AppendLine($"**{PBEDataProvider.Instance.GetMoveName(PBEMove.HiddenPower).English}:** {Utils.TypeEmotes[pkmn.IndividualValues.GetHiddenPowerType()]}|{pkmn.IndividualValues.GetHiddenPowerBasePower(PBESettings.DefaultSettings)}");
            }
            outStr = sb.ToString();
            sb.Clear();
            outFields = new EmbedFieldBuilder[2];
            EmbedFieldBuilder field = new EmbedFieldBuilder()
                                      .WithName("**Moves:**")
                                      .WithIsInline(true);

            outFields[0] = field;
            for (int i = 0; i < PBESettings.DefaultNumMoves; i++)
            {
                PBEBattleMoveset.PBEBattleMovesetSlot slot = pkmn.Moves[i];
                PBEMove move = slot.Move;
                if (move != PBEMove.None)
                {
                    PBEType moveType = pkmn.GetMoveType(move);
                    sb.Append($"{Utils.TypeEmotes[moveType]} {PBEDataProvider.Instance.GetMoveName(move).English} ({slot.PP}/{slot.MaxPP})");
                    if (i < PBESettings.DefaultNumMoves - 1)
                    {
                        sb.AppendLine();
                    }
                }
            }
            field.WithValue(sb.ToString());
            sb.Clear();
            field = new EmbedFieldBuilder()
                    .WithName("**Usable moves:**")
                    .WithIsInline(true);
            outFields[1] = field;
            PBEMove[] usableMoves = pkmn.GetUsableMoves();
            for (int i = 0; i < usableMoves.Length; i++)
            {
                PBEMove move     = usableMoves[i];
                PBEType moveType = pkmn.GetMoveType(move);
                if (addReactionChars)
                {
                    sb.Append($"{_moveEmotes[i][moveType]} ");
                }
                else
                {
                    sb.Append($"{Utils.TypeEmotes[moveType]} ");
                }
                sb.Append(PBEDataProvider.Instance.GetMoveName(move).English);
                if (i < usableMoves.Length - 1)
                {
                    sb.AppendLine();
                }
            }
            field.WithValue(sb.ToString());
        }