internal static PBEPokemonShell FromBytes(BinaryReader r)
        {
            var pkmn = new PBEPokemonShell
            {
                Species    = (PBESpecies)r.ReadUInt32(),
                Nickname   = PBEUtils.StringFromBytes(r),
                Level      = r.ReadByte(),
                Friendship = r.ReadByte(),
                Shiny      = r.ReadBoolean(),
                Ability    = (PBEAbility)r.ReadByte(),
                Nature     = (PBENature)r.ReadByte(),
                Gender     = (PBEGender)r.ReadByte(),
                Item       = (PBEItem)r.ReadUInt16(),
                EVs        = r.ReadBytes(6),
                IVs        = r.ReadBytes(6)
            };
            byte numMoves = r.ReadByte();

            pkmn.Moves = new PBEMove[numMoves];
            for (int i = 0; i < numMoves; i++)
            {
                pkmn.Moves[i] = (PBEMove)r.ReadUInt16();
            }
            pkmn.PPUps = r.ReadBytes(numMoves);
            return(pkmn);
        }
        // TODO: Include generation?
        // TODO: Sketch
        // TODO: Same goals as MoveLegalityCheck
        public static PBEMove[] GetLegalMoves(PBESpecies species, byte level, PBESettings settings)
        {
            PBEPokemonShell.ValidateSpecies(species);
            PBEPokemonShell.ValidateLevel(level, settings);
            var evolutionChain = new List <PBESpecies>();

            void AddPreEvolutions(PBESpecies sp)
            {
                foreach (PBESpecies pkmn in PBEPokemonData.GetData(sp).PreEvolutions)
                {
                    AddPreEvolutions(pkmn);
                }
                evolutionChain.Add(sp);
            }

            AddPreEvolutions(species);

            var moves = new List <PBEMove>();

            foreach (PBESpecies pkmn in evolutionChain)
            {
                var pData = PBEPokemonData.GetData(pkmn);
                moves.AddRange(pData.LevelUpMoves.Where(t => t.Level <= level).Select(t => t.Move));
                moves.AddRange(pData.OtherMoves.Select(t => t.Move));
                if (PBEEventPokemon.Events.TryGetValue(pkmn, out ReadOnlyCollection <PBEEventPokemon> events))
                {
                    moves.AddRange(events.SelectMany(e => e.Moves));
                }
            }

            return(moves.Distinct().Where(m => m != PBEMove.None).ToArray());
        }
Exemple #3
0
        public static void ValidateShell(this PBEPokemonShell shell, PBESettings settings)
        {
            // Validate Species
            PBEPokemonData pData;

            switch (shell.Species)
            {
            case PBESpecies.Darmanitan_Zen:
            case PBESpecies.Meloetta_Pirouette:
                throw new ArgumentOutOfRangeException(nameof(shell.Species), $"{shell.Species} must be in its base forme.");

            default:
                try
                {
                    pData = PBEPokemonData.Data[shell.Species];
                }
                catch (KeyNotFoundException)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Species), "Invalid species.");
                }
                break;
            }

            // Validate Nickname
            if (string.IsNullOrWhiteSpace(shell.Nickname))
            {
                throw new ArgumentOutOfRangeException(nameof(shell.Nickname), $"{nameof(shell.Nickname)} cannot be empty.");
            }
            if (shell.Nickname.Length > settings.MaxPokemonNameLength)
            {
                throw new ArgumentOutOfRangeException(nameof(shell.Nickname), $"{nameof(shell.Nickname)} cannot exceed {settings.MaxPokemonNameLength} characters.");
            }

            // Validate Level
            if (shell.Level < settings.MinLevel || shell.Level > settings.MaxLevel)
            {
                throw new ArgumentOutOfRangeException(nameof(shell.Level), $"A {shell.Species}'s level must be at least {settings.MinLevel} and cannot exceed {settings.MaxLevel}.");
            }

            // Validate Ability
            if (!pData.HasAbility(shell.Ability))
            {
                throw new ArgumentOutOfRangeException(nameof(shell.Ability), $"{shell.Species} cannot have {shell.Ability}.");
            }

            // Validate Nature
            if (shell.Nature >= PBENature.MAX)
            {
                throw new ArgumentOutOfRangeException(nameof(shell.Nature), "Invalid nature.");
            }

            // Validate Gender
            if (shell.Gender >= PBEGender.MAX ||
                (shell.Gender == PBEGender.Male && (pData.GenderRatio == PBEGenderRatio.M0_F1 || pData.GenderRatio == PBEGenderRatio.M0_F0)) ||
                (shell.Gender == PBEGender.Female && (pData.GenderRatio == PBEGenderRatio.M1_F0 || pData.GenderRatio == PBEGenderRatio.M0_F0)) ||
                (shell.Gender == PBEGender.Genderless && pData.GenderRatio != PBEGenderRatio.M0_F0)
                )
            {
                throw new ArgumentOutOfRangeException(nameof(shell.Gender), $"Invalid gender for {shell.Species}.");
            }

            // Validate Item
            if (shell.Item != PBEItem.None)
            {
                try
                {
                    PBEItemData iData = PBEItemData.Data[shell.Item];
                }
                catch
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), "Invalid item.");
                }
            }

            // Validate EVs
            if (shell.EVs == null || shell.EVs.Length != 6)
            {
                throw new ArgumentOutOfRangeException(nameof(shell.EVs), $"{nameof(shell.EVs)} array can only have a length of 6.");
            }
            if (shell.EVs.Select(e => (int)e).Sum() > settings.MaxTotalEVs)
            {
                throw new ArgumentOutOfRangeException(nameof(shell.EVs), $"Total EVs cannot exceed {settings.MaxTotalEVs}.");
            }
            // Validate IVs
            if (shell.IVs == null || shell.IVs.Length != 6)
            {
                throw new ArgumentOutOfRangeException(nameof(shell.IVs), $"{nameof(shell.IVs)} array can only have a length of 6.");
            }
            if (shell.IVs.Any(i => i > settings.MaxIVs))
            {
                throw new ArgumentOutOfRangeException(nameof(shell.IVs), $"Each IV cannot exceed {settings.MaxIVs}.");
            }

            // Validate Moves
            try
            {
                MoveLegalityCheck(shell.Species, shell.Level, shell.Moves, settings);
            }
            catch (Exception e)
            {
                throw new ArgumentOutOfRangeException(nameof(shell.Moves), e.Message);
            }

            // Validate PPUps
            if (shell.PPUps == null || shell.PPUps.Length != settings.NumMoves)
            {
                throw new ArgumentOutOfRangeException(nameof(shell.PPUps), $"{nameof(shell.PPUps)} array can only have a length of {settings.NumMoves}.");
            }
            if (shell.PPUps.Any(p => p > settings.MaxPPUps))
            {
                throw new ArgumentOutOfRangeException(nameof(shell.PPUps), $"Each PP-Up cannot exceed {settings.MaxPPUps}.");
            }

            // Validate Forme-Specific Requirements
            switch (shell.Species)
            {
            case PBESpecies.Shedinja:
                if (shell.EVs[0] > 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.EVs), $"{shell.Species} cannot have any HP EVs.");
                }
                break;

            case PBESpecies.Giratina:
                if (shell.Item == PBEItem.GriseousOrb)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} cannot hold a {shell.Item}.");
                }
                break;

            case PBESpecies.Giratina_Origin:
                if (shell.Item != PBEItem.GriseousOrb)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.GriseousOrb}.");
                }
                break;

            case PBESpecies.Arceus:
                if (shell.Item == PBEItem.DracoPlate ||
                    shell.Item == PBEItem.DreadPlate ||
                    shell.Item == PBEItem.EarthPlate ||
                    shell.Item == PBEItem.FistPlate ||
                    shell.Item == PBEItem.FlamePlate ||
                    shell.Item == PBEItem.IciclePlate ||
                    shell.Item == PBEItem.InsectPlate ||
                    shell.Item == PBEItem.IronPlate ||
                    shell.Item == PBEItem.MeadowPlate ||
                    shell.Item == PBEItem.MindPlate ||
                    shell.Item == PBEItem.SkyPlate ||
                    shell.Item == PBEItem.SplashPlate ||
                    shell.Item == PBEItem.SpookyPlate ||
                    shell.Item == PBEItem.StonePlate ||
                    shell.Item == PBEItem.ToxicPlate ||
                    shell.Item == PBEItem.ZapPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} cannot hold a {shell.Item}.");
                }
                break;

            case PBESpecies.Arceus_Bug:
                if (shell.Item != PBEItem.InsectPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.InsectPlate}.");
                }
                break;

            case PBESpecies.Arceus_Dark:
                if (shell.Item != PBEItem.DreadPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.DreadPlate}.");
                }
                break;

            case PBESpecies.Arceus_Dragon:
                if (shell.Item != PBEItem.DracoPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.DracoPlate}.");
                }
                break;

            case PBESpecies.Arceus_Electric:
                if (shell.Item != PBEItem.ZapPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.ZapPlate}.");
                }
                break;

            case PBESpecies.Arceus_Fighting:
                if (shell.Item != PBEItem.FistPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.FistPlate}.");
                }
                break;

            case PBESpecies.Arceus_Fire:
                if (shell.Item != PBEItem.FlamePlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.FlamePlate}.");
                }
                break;

            case PBESpecies.Arceus_Flying:
                if (shell.Item != PBEItem.SkyPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.SkyPlate}.");
                }
                break;

            case PBESpecies.Arceus_Ghost:
                if (shell.Item != PBEItem.SpookyPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.SpookyPlate}.");
                }
                break;

            case PBESpecies.Arceus_Grass:
                if (shell.Item != PBEItem.MeadowPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.MeadowPlate}.");
                }
                break;

            case PBESpecies.Arceus_Ground:
                if (shell.Item != PBEItem.EarthPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.EarthPlate}.");
                }
                break;

            case PBESpecies.Arceus_Ice:
                if (shell.Item != PBEItem.IciclePlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.IciclePlate}.");
                }
                break;

            case PBESpecies.Arceus_Poison:
                if (shell.Item != PBEItem.ToxicPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.ToxicPlate}.");
                }
                break;

            case PBESpecies.Arceus_Psychic:
                if (shell.Item != PBEItem.MindPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.MindPlate}.");
                }
                break;

            case PBESpecies.Arceus_Rock:
                if (shell.Item != PBEItem.StonePlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.StonePlate}.");
                }
                break;

            case PBESpecies.Arceus_Steel:
                if (shell.Item != PBEItem.IronPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.IronPlate}.");
                }
                break;

            case PBESpecies.Arceus_Water:
                if (shell.Item != PBEItem.SplashPlate)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.SplashPlate}.");
                }
                break;

            case PBESpecies.Genesect:
                if (shell.Item == PBEItem.BurnDrive ||
                    shell.Item == PBEItem.ChillDrive ||
                    shell.Item == PBEItem.DouseDrive ||
                    shell.Item == PBEItem.ShockDrive)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} cannot hold a {shell.Item}.");
                }
                break;

            case PBESpecies.Genesect_Burn:
                if (shell.Item != PBEItem.BurnDrive)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.BurnDrive}.");
                }
                break;

            case PBESpecies.Genesect_Chill:
                if (shell.Item != PBEItem.ChillDrive)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.ChillDrive}.");
                }
                break;

            case PBESpecies.Genesect_Douse:
                if (shell.Item != PBEItem.DouseDrive)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.DouseDrive}.");
                }
                break;

            case PBESpecies.Genesect_Shock:
                if (shell.Item != PBEItem.ShockDrive)
                {
                    throw new ArgumentOutOfRangeException(nameof(shell.Item), $"{shell.Species} must hold a {PBEItem.ShockDrive}.");
                }
                break;
            }
        }
        public static IEnumerable <PBEPokemonShell> TeamFromTextFile(string path)
        {
            using (StreamReader r = File.OpenText(path))
            {
                int amt  = int.Parse(r.ReadLine());
                var team = new PBEPokemonShell[amt];
                for (int i = 0; i < amt; i++)
                {
                    team[i] = new PBEPokemonShell
                    {
                        Species    = (PBESpecies)Enum.Parse(typeof(PBESpecies), r.ReadLine()),
                        Nickname   = r.ReadLine(),
                        Level      = byte.Parse(r.ReadLine()),
                        Friendship = byte.Parse(r.ReadLine()),
                        Shiny      = bool.Parse(r.ReadLine()),
                        Ability    = (PBEAbility)Enum.Parse(typeof(PBEAbility), r.ReadLine()),
                        Nature     = (PBENature)Enum.Parse(typeof(PBENature), r.ReadLine()),
                        Gender     = (PBEGender)Enum.Parse(typeof(PBEGender), r.ReadLine()),
                        Item       = (PBEItem)Enum.Parse(typeof(PBEItem), r.ReadLine()),
                    };
                    // Setup for arrays
                    string   line;
                    string[] args;
                    void SplitNext()
                    {
                        line = r.ReadLine();
                        args = line.Split(new[] { ", " }, StringSplitOptions.None);
                    }

                    // EVs
                    SplitNext();
                    team[i].EVs = new byte[args.Length];
                    for (int j = 0; j < args.Length; j++)
                    {
                        team[i].EVs[j] = byte.Parse(args[j]);
                    }
                    // IVs
                    SplitNext();
                    team[i].IVs = new byte[args.Length];
                    for (int j = 0; j < args.Length; j++)
                    {
                        team[i].IVs[j] = byte.Parse(args[j]);
                    }
                    // Moves
                    SplitNext();
                    team[i].Moves = new PBEMove[args.Length];
                    for (int j = 0; j < args.Length; j++)
                    {
                        team[i].Moves[j] = (PBEMove)Enum.Parse(typeof(PBEMove), args[j]);
                    }
                    // PPUps
                    SplitNext();
                    team[i].PPUps = new byte[args.Length];
                    for (int j = 0; j < args.Length; j++)
                    {
                        team[i].PPUps[j] = byte.Parse(args[j]);
                    }
                }
                return(team);
            }
        }