/// <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); }