// Will cause double load for some cases (like status2 updating)
        // Because new animated image is created
        public void UpdateSprites(PkmnPosition pos, bool paused)
        {
            Mini = PokemonImageUtils.GetMini(Pkmn.KnownSpecies, Pkmn.KnownForm, Pkmn.KnownGender, Pkmn.KnownShiny, PartyPkmn.IsEgg);
            PBEStatus2 status2 = _useKnownInfo ? Pkmn.KnownStatus2 : Pkmn.Status2;

            AnimImage = PokemonImageUtils.GetPokemonImage(Pkmn.KnownSpecies, Pkmn.KnownForm, Pkmn.KnownGender, Pkmn.KnownShiny, _backImage,
                                                          status2.HasFlag(PBEStatus2.Substitute), status2.HasFlag(PBEStatus2.Disguised) ? DisguisedPID : PartyPkmn.PID, PartyPkmn.IsEgg);
            AnimImage.IsPaused = paused;
            if (pos is null)
            {
                return; // Only for updating visibility below
            }
            if (!status2.HasFlag(PBEStatus2.Substitute))
            {
                if (status2.HasFlag(PBEStatus2.Airborne) ||
                    status2.HasFlag(PBEStatus2.ShadowForce) ||
                    status2.HasFlag(PBEStatus2.Underground) ||
                    status2.HasFlag(PBEStatus2.Underwater))
                {
                    pos.PkmnVisible = false;
                }
                else
                {
                    pos.PkmnVisible = true;
                }
            }
        }
        //[InlineData(PBEMove.SkyDrop, PBEStatus2.Airborne)]
        public void HelpingHand_HitsSemiInvulnerable(PBEMove move, PBEStatus2 status2)
        {
            #region Setup
            PBEDataProvider.GlobalRandom.Seed = 0;
            PBESettings settings = PBESettings.DefaultSettings;

            var p0 = new TestPokemonCollection(2);
            p0[0] = new TestPokemon(settings, PBESpecies.Minun, 0, 100, PBEMove.HelpingHand, PBEMove.Splash);
            p0[1] = new TestPokemon(settings, PBESpecies.Giratina, 0, 1, move);

            var p1 = new TestPokemonCollection(1);
            p1[0] = new TestPokemon(settings, PBESpecies.Magikarp, 0, 100, PBEMove.Splash);

            var battle = PBEBattle.CreateTrainerBattle(PBEBattleFormat.Double, settings, new PBETrainerInfo(p0, "Trainer 0", false), new PBETrainerInfo(p1, "Trainer 1", false));
            battle.OnNewEvent += PBEBattle.ConsoleBattleEventHandler;

            PBETrainer       t0       = battle.Trainers[0];
            PBETrainer       t1       = battle.Trainers[1];
            PBEBattlePokemon minun    = t0.Party[0];
            PBEBattlePokemon giratina = t0.Party[1];
            PBEBattlePokemon magikarp = t1.Party[0];

            battle.Begin();
            #endregion

            #region Use Shadow Force
            Assert.True(t0.SelectActionsIfValid(out _,
                                                new PBETurnAction(minun, PBEMove.Splash, PBETurnTarget.AllyLeft),
                                                new PBETurnAction(giratina, move, PBETurnTarget.FoeLeft)));
            Assert.True(t1.SelectActionsIfValid(out _,
                                                new PBETurnAction(magikarp, PBEMove.Splash, PBETurnTarget.AllyLeft)));

            battle.RunTurn();

            Assert.True(giratina.Status2.HasFlag(status2));
            #endregion

            #region Use Helping Hand and check
            Assert.True(t0.SelectActionsIfValid(out _,
                                                new PBETurnAction(minun, PBEMove.HelpingHand, PBETurnTarget.AllyRight),
                                                new PBETurnAction(giratina, move, PBETurnTarget.FoeLeft)));
            Assert.True(t1.SelectActionsIfValid(out _,
                                                new PBETurnAction(magikarp, PBEMove.Splash, PBETurnTarget.AllyLeft)));

            battle.RunTurn();

            Assert.True(battle.VerifyStatus2Happened(giratina, minun, PBEStatus2.HelpingHand, PBEStatusAction.Added));
            #endregion

            #region Cleanup
            battle.OnNewEvent -= PBEBattle.ConsoleBattleEventHandler;
            #endregion
        }
        public PBEStatus2Packet(PBEPokemon status2Receiver, PBEPokemon pokemon2, PBEStatus2 status2, PBEStatusAction statusAction)
        {
            var bytes = new List <byte>();

            bytes.AddRange(BitConverter.GetBytes(Code));
            bytes.Add((byte)(Status2Receiver = status2Receiver.FieldPosition));
            bytes.Add((Status2ReceiverTeam = status2Receiver.Team).Id);
            bytes.Add((byte)(Pokemon2 = pokemon2.FieldPosition));
            bytes.Add((Pokemon2Team = pokemon2.Team).Id);
            bytes.AddRange(BitConverter.GetBytes((uint)(Status2 = status2)));
            bytes.Add((byte)(StatusAction = statusAction));
            Buffer = BitConverter.GetBytes((short)bytes.Count).Concat(bytes);
        }
예제 #4
0
        internal PBEStatus2Packet(PBEPokemon status2Receiver, PBEPokemon pokemon2, PBEStatus2 status2, PBEStatusAction statusAction)
        {
            var bytes = new List <byte>();

            bytes.AddRange(BitConverter.GetBytes(Code));
            bytes.Add((byte)(Status2Receiver = status2Receiver.FieldPosition));
            bytes.Add((Status2ReceiverTeam = status2Receiver.Team).Id);
            bytes.Add((byte)(Pokemon2 = pokemon2.FieldPosition));
            bytes.Add((Pokemon2Team = pokemon2.Team).Id);
            bytes.AddRange(BitConverter.GetBytes((uint)(Status2 = status2)));
            bytes.Add((byte)(StatusAction = statusAction));
            bytes.InsertRange(0, BitConverter.GetBytes((short)bytes.Count));
            Buffer = new ReadOnlyCollection <byte>(bytes);
        }
예제 #5
0
 internal PBEStatus2Packet(PBEPokemon status2Receiver, PBEPokemon pokemon2, PBEStatus2 status2, PBEStatusAction statusAction)
 {
     using (var ms = new MemoryStream())
         using (var w = new EndianBinaryWriter(ms, encoding: EncodingType.UTF16))
         {
             w.Write(Code);
             w.Write(Status2Receiver = status2Receiver.FieldPosition);
             w.Write((Status2ReceiverTeam = status2Receiver.Team).Id);
             w.Write(Pokemon2 = pokemon2.FieldPosition);
             w.Write((Pokemon2Team = pokemon2.Team).Id);
             w.Write(Status2      = status2);
             w.Write(StatusAction = statusAction);
             Data = new ReadOnlyCollection <byte>(ms.ToArray());
         }
 }
예제 #6
0
 public static bool VerifyStatus2Happened(this PBEBattle battle, PBEBattlePokemon status2Receiver, PBEBattlePokemon pokemon2, PBEStatus2 status2, PBEStatusAction statusAction)
 {
     foreach (IPBEPacket packet in battle.Events)
     {
         if (packet is PBEStatus2Packet s2p &&
             s2p.Status2 == status2 &&
             s2p.StatusAction == statusAction &&
             s2p.Status2ReceiverTrainer.TryGetPokemon(s2p.Status2Receiver) == status2Receiver &&
             s2p.Pokemon2Trainer.TryGetPokemon(s2p.Pokemon2) == pokemon2)
         {
             return(true);
         }
     }
     return(false);
 }
예제 #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.AppendLine($"Known types: {PBELocalizedString.GetTypeName(pkmn.KnownType1).FromUICultureInfo()}/{PBELocalizedString.GetTypeName(pkmn.KnownType2).FromUICultureInfo()}");
                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).FromUICultureInfo()))}");
                }
                else
                {
                    sb.AppendLine($"Known ability: {PBELocalizedString.GetAbilityName(pkmn.KnownAbility).FromUICultureInfo()}");
                }
                sb.AppendLine($"Known item: {(pkmn.KnownItem == (PBEItem)ushort.MaxValue ? "???" : PBELocalizedString.GetItemName(pkmn.KnownItem).FromUICultureInfo())}");
                sb.Append($"Known moves: {string.Join(", ", pkmn.KnownMoves.Select(m => m == PBEMove.MAX ? "???" : PBELocalizedString.GetMoveName(m).FromUICultureInfo()))}");
            }
            else
            {
                sb.AppendLine($"{pkmn.Nickname}/{pkmn.Species} {pkmn.GenderSymbol} Lv.{pkmn.Level}");
                sb.AppendLine($"HP: {pkmn.HP}/{pkmn.MaxHP} ({pkmn.HPPercentage:P2})");
                sb.AppendLine($"Types: {PBELocalizedString.GetTypeName(pkmn.Type1).FromUICultureInfo()}/{PBELocalizedString.GetTypeName(pkmn.Type2).FromUICultureInfo()}");
                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 && pkmn.Status2 != PBEStatus2.None)
                {
                    sb.AppendLine($"Volatile status: {pkmn.Status2}");
                    if (pkmn.Status2.HasFlag(PBEStatus2.Disguised))
                    {
                        sb.AppendLine($"Disguised as: {pkmn.DisguisedAsPokemon.Nickname}");
                    }
                    if (pkmn.Status2.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 (pkmn.Status2.HasFlag(PBEStatus2.LeechSeed))
                    {
                        sb.AppendLine($"Seeded position: {pkmn.SeededTeam.TrainerName}'s {pkmn.SeededPosition}");
                    }
                }
                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();
                }
                sb.AppendLine($"Ability: {PBELocalizedString.GetAbilityName(pkmn.Ability).FromUICultureInfo()}");
                sb.AppendLine($"Item: {PBELocalizedString.GetItemName(pkmn.Item).FromUICultureInfo()}");
                if (Array.IndexOf(pkmn.Moves, PBEMove.Frustration) != -1 || Array.IndexOf(pkmn.Moves, PBEMove.Return) != -1)
                {
                    sb.AppendLine($"Friendship: {pkmn.Friendship} ({pkmn.Friendship / (double)byte.MaxValue:P2})");
                }
                if (Array.IndexOf(pkmn.Moves, PBEMove.HiddenPower) != -1)
                {
                    sb.AppendLine($"{PBELocalizedString.GetMoveName(PBEMove.HiddenPower).FromUICultureInfo()}: {PBELocalizedString.GetTypeName(pkmn.IndividualValues.HiddenPowerType).FromUICultureInfo()}/{pkmn.IndividualValues.HiddenPowerBasePower}");
                }
                string[] moveStrs = new string[pkmn.Moves.Length];
                for (int i = 0; i < moveStrs.Length; i++)
                {
                    moveStrs[i] = $"{PBELocalizedString.GetMoveName(pkmn.Moves[i]).FromUICultureInfo()} {pkmn.PP[i]}/{pkmn.MaxPP[i]}";
                }
                sb.AppendLine($"Moves: {string.Join(", ", moveStrs)}");
                sb.Append($"Usable moves: {string.Join(", ", pkmn.GetUsableMoves().Select(m => PBELocalizedString.GetMoveName(m).FromUICultureInfo()))}");
            }
            return(sb.ToString());
        }
예제 #8
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})")}");
                    }
                }
            }