PKHeX/PKHeX.Core/Legality/Encounters/Information/EncounterSuggestion.cs
Kurt 09089da14e Use more expression return style
Reduces indentation & bracketing, a bit more concise
2021-01-01 17:08:49 -08:00

210 lines
7.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using static PKHeX.Core.GameVersion;
namespace PKHeX.Core
{
/// <summary>
/// Logic for providing suggested property values with respect to the input data.
/// </summary>
public static class EncounterSuggestion
{
/// <summary>
/// Gets an object containing met data properties that might be legal.
/// </summary>
public static EncounterSuggestionData? GetSuggestedMetInfo(PKM pkm)
{
int loc = GetSuggestedTransferLocation(pkm);
if (pkm.WasEgg)
return GetSuggestedEncounterEgg(pkm, loc);
var w = EncounterSlotGenerator.GetCaptureLocation(pkm);
if (w != null)
return GetSuggestedEncounterWild(pkm, w, loc);
var s = EncounterStaticGenerator.GetStaticLocation(pkm);
if (s != null)
return GetSuggestedEncounterStatic(pkm, s, loc);
return null;
}
private static EncounterSuggestionData GetSuggestedEncounterEgg(PKM pkm, int loc = -1)
{
int lvl = GetSuggestedEncounterEggMetLevel(pkm);
var met = loc != -1 ? loc : GetSuggestedEggMetLocation(pkm);
return new EncounterSuggestionData(pkm, met, lvl);
}
public static int GetSuggestedEncounterEggMetLevel(PKM pkm)
{
if (!pkm.IsNative && pkm.Generation < 5)
return pkm.CurrentLevel; // be generous with transfer conditions
if (pkm.Format < 5) // and native
return pkm.Format == 2 && pkm.Met_Location != 0 ? 1 : 0;
return 1; // gen5+
}
public static int GetSuggestedEncounterEggLocationEgg(PKM pkm, bool traded = false)
{
return GetSuggestedEncounterEggLocationEgg(pkm.Generation, traded);
}
public static int GetSuggestedEncounterEggLocationEgg(int generation, bool traded = false) => generation switch
{
1 or 2 or 3 => 0,
4 => traded ? Locations.LinkTrade4 : Locations.Daycare4,
5 => traded ? Locations.LinkTrade5 : Locations.Daycare5,
_ => traded ? Locations.LinkTrade6 : Locations.Daycare5,
};
private static EncounterSuggestionData GetSuggestedEncounterWild(PKM pkm, EncounterSlot first, int loc = -1)
{
var met = loc != -1 ? loc : first.Location;
return new EncounterSuggestionData(pkm, first, met);
}
private static EncounterSuggestionData GetSuggestedEncounterStatic(PKM pkm, EncounterStatic s, int loc = -1)
{
var met = loc != -1 ? loc : s.Location;
return new EncounterSuggestionData(pkm, s, met);
}
/// <summary>
/// Gets a valid Egg hatch location for the origin game.
/// </summary>
/// <param name="pkm">Pokémon data to suggest for</param>
public static int GetSuggestedEggMetLocation(PKM pkm) => (GameVersion)pkm.Version switch
{
R or S or E or FR or LG => pkm.Format switch
{
3 => (pkm.FRLG ? Locations.HatchLocationFRLG : Locations.HatchLocationRSE),
4 => Locations.Transfer3, // Pal Park
_ => Locations.Transfer4,
},
D or P or Pt => pkm.Format > 4 ? Locations.Transfer4 : Locations.HatchLocationDPPt,
HG or SS => pkm.Format > 4 ? Locations.Transfer4 : Locations.HatchLocationHGSS,
B or W or B2 or W2 => Locations.HatchLocation5,
X or Y => Locations.HatchLocation6XY,
AS or OR => Locations.HatchLocation6AO,
SN or MN or US or UM => Locations.HatchLocation7,
RD or BU or GN or Y => Locations.Transfer1,
GD or SV or C => Locations.Transfer2,
GSC or RBY => pkm.Met_Level == 0 ? 0 : Locations.HatchLocationC,
SW or SH => Locations.HatchLocation8,
_ => -1,
};
/// <summary>
/// Gets the correct Transfer Met location for the origin game.
/// </summary>
/// <param name="pkm">Pokémon data to suggest for</param>
/// <remarks>
/// Returns -1 if the met location is not overriden with a transfer location
/// </remarks>
public static int GetSuggestedTransferLocation(PKM pkm)
{
if (pkm.Version == (int)GO)
return Locations.GO8;
if (pkm.HasOriginalMetLocation)
return -1;
if (pkm.VC1)
return Locations.Transfer1;
if (pkm.VC2)
return Locations.Transfer2;
if (pkm.Format == 4) // Pal Park
return Locations.Transfer3;
if (pkm.Format >= 5) // Transporter
return Legal.GetTransfer45MetLocation(pkm);
return -1;
}
public static int GetLowestLevel(PKM pkm, int startLevel)
{
if (startLevel == -1)
startLevel = 100;
var table = EvolutionTree.GetEvolutionTree(pkm, pkm.Format);
int count = 1;
for (int i = 100; i >= startLevel; i--)
{
var evos = table.GetValidPreEvolutions(pkm, maxLevel: i, minLevel: startLevel, skipChecks: true);
if (evos.Count < count) // lost an evolution, prior level was minimum current level
return evos.Max(evo => evo.Level) + 1;
count = evos.Count;
}
return startLevel;
}
/// <summary>
/// Gets the suggested <see cref="PKM.Met_Level"/> based on a baseline <see cref="minLevel"/> and the <see cref="pkm"/>'s current moves.
/// </summary>
/// <param name="pkm">Entity to calculate for</param>
/// <param name="minLevel">Encounter minimum level to calculate for</param>
/// <returns>Minimum level the <see cref="pkm"/> can have for its <see cref="PKM.Met_Level"/></returns>
/// <remarks>Brute-forces the value by cloning the <see cref="pkm"/> and adjusting the <see cref="PKM.Met_Level"/> and returning the lowest valid value.</remarks>
public static int GetSuggestedMetLevel(PKM pkm, int minLevel)
{
var clone = pkm.Clone();
int minMove = -1;
for (int i = clone.CurrentLevel; i >= minLevel; i--)
{
clone.Met_Level = i;
var la = new LegalityAnalysis(clone);
if (la.Valid)
return i;
if (la.Info.Moves.All(z => z.Valid))
minMove = i;
}
return Math.Max(minMove, minLevel);
}
}
public sealed class EncounterSuggestionData : ISpeciesForm, IRelearn
{
private readonly IEncounterable? Encounter;
public IReadOnlyList<int> Relearn => Encounter is IRelearn r ? r.Relearn : Array.Empty<int>();
public EncounterSuggestionData(PKM pkm, IEncounterable enc, int met)
{
Encounter = enc;
Species = pkm.Species;
Form = pkm.Form;
Location = met;
LevelMin = enc.LevelMin;
LevelMax = enc.LevelMax;
}
public EncounterSuggestionData(PKM pkm, int met, int lvl)
{
Species = pkm.Species;
Form = pkm.Form;
Location = met;
LevelMin = lvl;
LevelMax = lvl;
}
public int Species { get; }
public int Form { get; }
public int Location { get; }
public int LevelMin { get; }
public int LevelMax { get; }
public int GetSuggestedMetLevel(PKM pkm) => EncounterSuggestion.GetSuggestedMetLevel(pkm, LevelMin);
public int GetSuggestedEncounterType() => Encounter is IEncounterTypeTile t ? t.TypeEncounter.GetIndex() : 0;
public bool HasEncounterType(int format) => Encounter is IEncounterTypeTile t && t.HasTypeEncounter(format);
}
}