예제 #1
0
        /// <inheritdoc />
        public Pokemon GenerateRandomPokemon(int level)
        {
            if (level < 5 || level > 100)
            {
                throw new ArgumentOutOfRangeException($"level ({level}) must be between 5 and 100 inclusive.");
            }

            // Make sure both players end up with different pokemons, re-use the same list if possible
            if (_previousLevel != level || _randomBagOfPokemon.Count <= _config.Value.Configuration.RandomBagMinCount)
            {
                _previousLevel = level;
                ReloadRandomBag(level);
            }

            // add initial probabilities
            foreach (var choice in _randomBagOfPokemon)
            {
                if (_config.Value.Configuration.DisabledPokemon.Contains(choice.PokemonId) ||
                    _config.Value.Configuration.ForbiddenPokemon.Contains(choice.PokemonId))
                {
                    choice.Probability = _config.Value.Configuration.PokemonLiklihood.Ignored;
                }
                else if (_config.Value.Configuration.LegendaryPokemon.Contains(choice.PokemonId))
                {
                    choice.Probability = _config.Value.Configuration.PokemonLiklihood.Legendary;
                }
                else if (_config.Value.Configuration.SpecialPokemon.Contains(choice.PokemonId))
                {
                    choice.Probability = _config.Value.Configuration.PokemonLiklihood.Special;
                }
                else
                {
                    choice.Probability = _config.Value.Configuration.PokemonLiklihood.Standard;
                }
            }

            // choose
            var chosenId = _probabilityUtility.ChooseWithProbability(_randomBagOfPokemon.Cast <IChoice>().ToList());

            if (chosenId == null)
            {
                throw new ArgumentException("Not enough Pokemon to choose from.");
            }

            var iChooseYou = new Pokemon
            {
                SpeciesId = (byte)_randomBagOfPokemon[(int)chosenId].PokemonId,
                Unused    = 0x0,
                OTName    = "ROBOT",
                HeldItem  = 0x0
            };

            _randomBagOfPokemon.RemoveAt((int)chosenId);

            return(iChooseYou);
        }
        /// <summary>
        /// By far the most complex method here.
        /// Uses the parameters to choose one move for a pokemon by assigning a probability value to each possible move.
        /// The higher this value is compared to all of the other moves, the more likely this move is to be chosen.
        /// (See: <see cref="GeneratorConfig"/>, <see cref="PokemonAndMoveInfo"/>)
        /// </summary>
        private bool PickOneMove(PokemonAndMoveInfo info, out int chosenMoveId)
        {
            chosenMoveId = 0;
            var allPossibleMoves = new List <PokemonMoveSetResult>(info.AllPossibleMovesOrig);

            // Calculate probabilities
            var moveProbabilities = allPossibleMoves.Select(m =>
            {
                var moveChoice = new MoveChoice
                {
                    Probability = Likeliness.Full,
                    Move        = m
                };

                // filter out all non-damaging/damaging attacks depending on the flag
                if (info.DoSomeDamageFlag && (m.Power ?? 0) <= 0)
                {
                    moveChoice.Probability *= Likeliness.Extremely_Low;
                }

                if (!info.DoSomeDamageFlag && (m.Power ?? 0) > 0)
                {
                    moveChoice.Probability *= Likeliness.Extremely_Low;
                }

                // Apply weight on damage type
                // if damage type does not mesh with the pokemon, make the likelyhood VERY unlikely
                if ((info.PreferredDamageType == DamageType.Special && (m.DamageType ?? "special").Equals("physical")) ||
                    (info.PreferredDamageType == DamageType.Physical && (m.DamageType ?? "special").Equals("special")))
                {
                    moveChoice.Probability *= _config.Value.Configuration.DamageTypeModifier;
                }

                // Apply weight on effect
                foreach (var key in _config.Value.Configuration.MoveEffectFilters.Keys)
                {
                    if (m.Effect.Contains(key))
                    {
                        moveChoice.Probability *= _config.Value.Configuration.MoveEffectFilters[key];
                    }
                }

                // Apply weight on type
                if ((info.PokeTypes?.Contains(m.Type, StringComparer.CurrentCultureIgnoreCase) ?? false) ||
                    (info.AttackTypesToFavor.Contains(m.Type, StringComparer.CurrentCultureIgnoreCase)))
                {
                    moveChoice.Probability *= _config.Value.Configuration.SameTypeModifier;
                }

                // Apply weight on damage
                if (info.DoSomeDamageFlag)
                {
                    moveChoice.Probability *= Likeliness.Full + (m.Power ?? 0) / _config.Value.Configuration.DamageModifier;
                }

                // Apply special weight for paired moves
                if (info.AlreadyPicked.Any(id => _config.Value.Configuration.PairedMoves.ContainsKey(id) && _config.Value.Configuration.PairedMoves[id].Contains(m.MoveId)))
                {
                    moveChoice.Probability = Likeliness.Full * _config.Value.Configuration.PairedModifier;
                }

                // Filter out dependant moves which do not already have their dependency picked
                if (_config.Value.Configuration.DependantMoves.ContainsKey(m.MoveId) && !_config.Value.Configuration.DependantMoves[m.MoveId].Intersect(info.AlreadyPicked).Any())
                {
                    moveChoice.Probability = Likeliness.None;
                }

                // Apply weight on similar moves to already picked
                if (!string.IsNullOrWhiteSpace(m.Effect) && info.AlreadyPickedEffects.Contains(m.Effect, StringComparer.CurrentCultureIgnoreCase))
                {
                    moveChoice.Probability *= _config.Value.Configuration.AlreadyPickedMoveEffectsModifier;
                }

                // Finally, apply weight on moves already picked
                if (info.AlreadyPicked.Contains(m.MoveId))
                {
                    moveChoice.Probability *= _config.Value.Configuration.AlreadyPickedMoveModifier;
                }

                return(moveChoice);
            }).ToList();

            // Return false if we filtered out all of our choices
            if (!moveProbabilities.Any() || moveProbabilities.All(choice => choice.Probability == 0))
            {
                return(false);
            }

            // Choose with probabilities
            var chosen = _probabilityUtility.ChooseWithProbability(moveProbabilities.Cast <IChoice>().ToList());

            if (chosen != null)
            {
                chosenMoveId = moveProbabilities[(int)chosen].Move.MoveId;
                return(true);
            }
            return(false);
        }