Xmldoc, minor tweaks

Move form-info logic from FormConverter to AltFormInfo; now FormConverter is entirely form=>string[]
Add a bunch of xmldoc
Make pogo no-end-date cmp agaisnt UTCnow rather than local now.
This commit is contained in:
Kurt 2020-11-27 11:51:02 -08:00
parent a437cbb9ca
commit 9b178fefe2
56 changed files with 329 additions and 159 deletions

View file

@ -281,24 +281,4 @@ namespace PKHeX.Core
NotWeather = Shaking_Trees | Fishing,
}
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.SWSH"/>
/// </summary>
public sealed class EncounterSlot8 : EncounterSlot
{
public readonly AreaWeather8 Weather;
public override string LongName => Weather == AreaWeather8.All ? wild : $"{wild} - {Weather.ToString().Replace("_", string.Empty)}";
public override int Generation => 8;
public EncounterSlot8(EncounterArea8 area, int specForm, int min, int max, AreaWeather8 weather) : base(area)
{
Species = specForm & 0x7FF;
Form = specForm >> 11;
LevelMin = min;
LevelMax = max;
Weather = weather;
}
}
}

View file

@ -5,6 +5,7 @@ namespace PKHeX.Core
/// <summary>
/// Wild Encounter Slot data
/// </summary>
/// <remarks>Wild encounter slots are found as random encounters in-game.</remarks>
public abstract class EncounterSlot : IEncounterable, ILocation
{
public int Species { get; protected set; }
@ -160,15 +161,19 @@ namespace PKHeX.Core
pk.MetDate = DateTime.Today;
}
private const int FormDynamic = FormVivillon;
private const int FormVivillon = 30;
private const int FormRandom = 31;
private static int GetWildAltForm(PKM pk, int form, ITrainerInfo sav)
{
if (form < 30) // specified form
if (form < FormDynamic) // specified form
{
if (pk.Species == (int) Core.Species.Minior)
return Util.Rand.Next(7, 14);
return form;
}
if (form == 31) // flagged as totally random
if (form == FormRandom) // flagged as totally random
return Util.Rand.Next(pk.PersonalInfo.FormeCount);
int spec = pk.Species;

View file

@ -1,12 +1,13 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 1 Wild Encounter Slot data
/// Encounter Slot found in <see cref="GameVersion.Gen1"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot1 : EncounterSlot, INumberedSlot
{
public override int Generation => 1;
public int SlotNumber { get; set; }
public int SlotNumber { get; }
public EncounterSlot1(EncounterArea1 area, int species, int min, int max, int slot) : base(area)
{
@ -23,6 +24,7 @@
var pk1 = (PK1)pk;
if (Version == GameVersion.YW)
{
// Since we don't keep track of Yellow's Personal Data, just handle any differences here.
pk1.Catch_Rate = Species switch
{
(int) Core.Species.Kadabra => 96,

View file

@ -1,15 +1,16 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 2 Wild Encounter Slot data
/// Encounter Slot found in <see cref="GameVersion.Gen2"/>.
/// </summary>
/// <remarks>
/// Contains Time data which is present in <see cref="GameVersion.C"/> origin data.
/// Referenced Area object contains Time data which is used for <see cref="GameVersion.C"/> origin data.
/// </remarks>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot2 : EncounterSlot, INumberedSlot
{
public override int Generation => 2;
public int SlotNumber { get; set; }
public int SlotNumber { get; }
public EncounterSlot2(EncounterArea2 area, int species, int min, int max, int slot) : base(area)
{
@ -25,7 +26,7 @@
var pk2 = (PK2)pk;
if (Version == GameVersion.C)
pk2.Met_TimeOfDay = ((EncounterArea2)Area!).Time.RandomValidTime();
pk2.Met_TimeOfDay = ((EncounterArea2)Area).Time.RandomValidTime();
}
}
}

View file

@ -1,15 +1,19 @@
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.Gen3"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public class EncounterSlot3 : EncounterSlot, IMagnetStatic, INumberedSlot
{
public sealed override int Generation => 3;
public int StaticIndex { get; set; }
public int MagnetPullIndex { get; set; }
public int StaticCount { get; set; }
public int MagnetPullCount { get; set; }
public int StaticIndex { get; }
public int MagnetPullIndex { get; }
public int StaticCount { get; }
public int MagnetPullCount { get; }
public int SlotNumber { get; set; }
public int SlotNumber { get; }
public EncounterSlot3(EncounterArea3 area, int species, int form, int min, int max, int slot, int mpi, int mpc, int sti, int stc) : base(area)
{

View file

@ -1,10 +1,14 @@
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.XD"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot3PokeSpot : EncounterSlot, INumberedSlot
{
public override int Generation => 3;
public int SlotNumber { get; set; }
public int SlotNumber { get; }
public EncounterSlot3PokeSpot(EncounterArea3XD area, int species, int min, int max, int slot) : base(area)
{

View file

@ -2,6 +2,13 @@ using System.Collections.Generic;
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.RSE"/>.
/// </summary>
/// <remarks>
/// Handled differently as these slots have fixed moves that are different from their normal level-up moves.
/// </remarks>
/// <inheritdoc cref="EncounterSlot"/>
internal sealed class EncounterSlot3Swarm : EncounterSlot3, IMoveset
{
public IReadOnlyList<int> Moves { get; }

View file

@ -1,16 +1,20 @@
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.Gen4"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot4 : EncounterSlot, IMagnetStatic, INumberedSlot, IEncounterTypeTile
{
public override int Generation => 4;
public EncounterType TypeEncounter => ((EncounterArea4)Area).TypeEncounter;
public int StaticIndex { get; set; }
public int MagnetPullIndex { get; set; }
public int StaticCount { get; set; }
public int MagnetPullCount { get; set; }
public int StaticIndex { get; }
public int MagnetPullIndex { get; }
public int StaticCount { get; }
public int MagnetPullCount { get; }
public int SlotNumber { get; set; }
public int SlotNumber { get; }
public EncounterSlot4(EncounterArea4 area, int species, int form, int min, int max, int slot, int mpi, int mpc, int sti, int stc) : base(area)
{

View file

@ -1,5 +1,9 @@
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.Gen5"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot5 : EncounterSlot
{
public override int Generation => 5;

View file

@ -1,8 +1,18 @@
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.ORAS"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot6AO : EncounterSlot
{
public override int Generation => 6;
public bool CanDexNav => Area.Type != SlotType.Rock_Smash;
public bool Pressure { get; set; }
public bool DexNav { get; set; }
public bool WhiteFlute { get; set; }
public bool BlackFlute { get; set; }
public EncounterSlot6AO(EncounterArea6AO area, int species, int form, int min, int max) : base(area)
{
@ -12,13 +22,6 @@ namespace PKHeX.Core
LevelMax = max;
}
public bool Pressure { get; set; }
public bool DexNav { get; set; }
public bool WhiteFlute { get; set; }
public bool BlackFlute { get; set; }
public bool CanDexNav => Area.Type != SlotType.Rock_Smash;
protected override void SetFormatSpecificData(PKM pk)
{
var pk6 = (PK6)pk;

View file

@ -1,5 +1,9 @@
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.XY"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot6XY : EncounterSlot
{
public override int Generation => 6;

View file

@ -1,7 +1,13 @@
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.Gen7"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot7 : EncounterSlot
{
public override int Generation => 7;
public EncounterSlot7(EncounterArea7 area, int species, int form, int min, int max) : base(area)
{
Species = species;
@ -9,8 +15,5 @@ namespace PKHeX.Core
LevelMin = min;
LevelMax = max;
}
public override int Generation => 7;
public bool Pressure { get; set; }
}
}
}

View file

@ -1,5 +1,9 @@
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.GG"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot7b : EncounterSlot
{
public override int Generation => 7;

View file

@ -0,0 +1,23 @@
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot found in <see cref="GameVersion.SWSH"/>.
/// </summary>
/// <inheritdoc cref="EncounterSlot"/>
public sealed class EncounterSlot8 : EncounterSlot
{
public readonly AreaWeather8 Weather;
public override string LongName => Weather == AreaWeather8.All ? wild : $"{wild} - {Weather.ToString().Replace("_", string.Empty)}";
public override int Generation => 8;
public EncounterSlot8(EncounterArea8 area, int specForm, int min, int max, AreaWeather8 weather) : base(area)
{
Species = specForm & 0x7FF;
Form = specForm >> 11;
LevelMin = min;
LevelMax = max;
Weather = weather;
}
}
}

View file

@ -1,7 +1,8 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 7 Wild Encounter Slot data (GO Park)
/// Encounter Slot found in <see cref="GameVersion.Gen7"/> (GO Park, <seealso cref="GameVersion.GG"/>).
/// <inheritdoc/>
/// </summary>
public sealed class EncounterSlot7GO : EncounterSlotGO
{

View file

@ -1,11 +1,20 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 8 Wild Encounter Slot data (GO -> HOME)
/// Encounter Slot representing data transferred to <see cref="GameVersion.Gen8"/> (HOME).
/// <inheritdoc/>
/// </summary>
public sealed class EncounterSlot8GO : EncounterSlotGO
{
public override int Generation => 8;
/// <summary>
/// Encounters need a Parent Game to determine the original moves when transferred to HOME.
/// </summary>
/// <remarks>
/// Future game releases might change this value.
/// With respect to date legality, new dates might be incompatible with initial <seealso cref="OriginGroup"/> values.
/// </remarks>
public GameVersion OriginGroup { get; }
public EncounterSlot8GO(EncounterArea8g area, int species, int form, int start, int end, Shiny shiny, PogoType type, GameVersion originGroup)
@ -17,7 +26,14 @@ namespace PKHeX.Core
OriginGroup = originGroup;
}
/// <summary>
/// Gets the minimum IV (in GO) the encounter must have.
/// </summary>
public int GetMinIV() => Type.GetMinIV();
/// <summary>
/// Checks if the <seealso cref="Ball"/> is compatible with the <seealso cref="PogoType"/>.
/// </summary>
public bool IsBallValid(Ball ball) => Type.IsBallValid(ball);
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)

View file

@ -3,21 +3,20 @@ using System;
namespace PKHeX.Core
{
/// <summary>
/// Contains details about an encounter that can be found in <see cref="GameVersion.GO"/>
/// Contains details about an encounter that can be found in <see cref="GameVersion.GO"/>.
/// </summary>
public abstract class EncounterSlotGO : EncounterSlot, IPogoSlot
{
/// <summary> Start Date timestamp of when the encounter became available. </summary>
/// <inheritdoc/>
public int Start { get; }
/// <summary> End Date timestamp of when the encounter became unavailable. </summary>
/// <remarks> If there is no end date (yet), we'll try to clamp to a date in the near-future to prevent it from being open-ended. </remarks>
/// <inheritdoc/>
public int End { get; }
/// <summary> Possibility of being shiny. </summary>
/// <inheritdoc/>
public Shiny Shiny { get; }
/// <summary> How the encounter was captured. </summary>
/// <inheritdoc/>
public PogoType Type { get; }
protected EncounterSlotGO(EncounterArea area, int start, int end, Shiny shiny, PogoType type) : base(area)
@ -56,7 +55,7 @@ namespace PKHeX.Core
public bool IsWithinStartEnd(int stamp)
{
if (End == 0)
return Start <= stamp && GetDate(stamp) <= DateTime.Now;
return Start <= stamp && GetDate(stamp) <= DateTime.UtcNow;
if (Start == 0)
return stamp <= End;
return Start <= stamp && stamp <= End;
@ -73,7 +72,7 @@ namespace PKHeX.Core
public DateTime GetRandomValidDate()
{
if (Start == 0)
return End == 0 ? DateTime.Now : GetDate(End);
return End == 0 ? DateTime.UtcNow : GetDate(End);
var start = GetDate(Start);
if (End == 0)

View file

@ -9,6 +9,7 @@ namespace PKHeX.Core
int Start { get; }
/// <summary> Last day the encounter was available. If zero, no date specified (unbounded finish). </summary>
/// <remarks> If there is no end date (yet), we'll try to clamp to a date in the near-future to prevent it from being open-ended. </remarks>
int End { get; }
/// <summary> Possibility of shiny for the encounter. </summary>

View file

@ -1,7 +1,17 @@
namespace PKHeX.Core
{
/// <summary>
/// Contains information pertaining the floor tile the <see cref="IEncounterable"/> was obtained on in <see cref="GameVersion.Gen4"/>.
/// </summary>
/// <remarks>
/// <seealso cref="EncounterSlot4"/>
/// <seealso cref="EncounterStaticTyped"/>
/// </remarks>
public interface IEncounterTypeTile
{
/// <summary>
/// Tile Type the <see cref="IEncounterable"/> was obtained on.
/// </summary>
EncounterType TypeEncounter { get; }
}

View file

@ -1,12 +1,24 @@
namespace PKHeX.Core
{
/// <summary>
/// Contains information about the RNG restrictions for the slot, and any mutated RNG values.
/// </summary>
/// <remarks>
/// When encountering a Wild Pokémon with a lead that has an ability of <see cref="Ability.Static"/> or <see cref="Ability.MagnetPull"/>,
/// the game picks encounters from the <seealso cref="EncounterArea"/> that match the type.
/// The values in this interface change the <seealso cref="INumberedSlot"/> to allow different values for slot yielding.
/// </remarks>
public interface IMagnetStatic
{
int StaticIndex { get; set; }
int MagnetPullIndex { get; set; }
/// <summary> <see cref="INumberedSlot.SlotNumber"/> if the lead is <see cref="Ability.Static"/> </summary>
int StaticIndex { get; }
/// <summary> <see cref="INumberedSlot.SlotNumber"/> if the lead is <see cref="Ability.MagnetPull"/> </summary>
int MagnetPullIndex { get; }
int StaticCount { get; set; }
int MagnetPullCount { get; set; }
/// <summary> Count of slots in the parent area that can be yielded by <see cref="Ability.Static"/> </summary>
int StaticCount { get; }
/// <summary> Count of slots in the parent area that can be yielded by <see cref="Ability.MagnetPull"/> </summary>
int MagnetPullCount { get; }
}
public static class MagnetStaticExtensions

View file

@ -1,7 +1,16 @@
namespace PKHeX.Core
{
/// <summary>
/// <seealso cref="EncounterSlot"/> that contains information about what Index it is within the <seealso cref="EncounterArea"/>'s type-group of slots.
/// </summary>
/// <remarks>
/// Useful for checking legality (if the RNG can yield this slot).
/// </remarks>
public interface INumberedSlot
{
int SlotNumber { get; set; }
/// <summary>
/// Number Index of the <seealso cref="EncounterSlot"/>.
/// </summary>
int SlotNumber { get; }
}
}

View file

@ -1,5 +1,9 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 1 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public class EncounterStatic1 : EncounterStatic
{
public override int Generation => 1;

View file

@ -7,6 +7,7 @@ namespace PKHeX.Core
/// <summary>
/// Event data for Generation 1
/// </summary>
/// <inheritdoc cref="EncounterStatic1"/>
public sealed class EncounterStatic1E : EncounterStatic1
{
public EncounterGBLanguage Language { get; set; } = EncounterGBLanguage.Japanese;

View file

@ -3,6 +3,10 @@ using System.Linq;
namespace PKHeX.Core
{
/// <summary>
/// Generation 2 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public class EncounterStatic2 : EncounterStatic
{
public sealed override int Generation => 2;

View file

@ -7,6 +7,7 @@ namespace PKHeX.Core
/// <summary>
/// Event data for Generation 2
/// </summary>
/// <inheritdoc cref="EncounterStatic2"/>
public sealed class EncounterStatic2E : EncounterStatic2
{
public EncounterGBLanguage Language { get; set; } = EncounterGBLanguage.Japanese;

View file

@ -3,6 +3,10 @@ using System.Linq;
namespace PKHeX.Core
{
/// <summary>
/// Generation 3 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public sealed class EncounterStatic3 : EncounterStatic
{
public override int Generation => 3;

View file

@ -1,5 +1,9 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 4 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public class EncounterStatic4 : EncounterStatic
{
public sealed override int Generation => 4;

View file

@ -2,6 +2,10 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 5 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public class EncounterStatic5 : EncounterStatic
{
public sealed override int Generation => 5;

View file

@ -3,6 +3,7 @@
/// <summary>
/// Generation 5 Dream Radar gift encounters
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public sealed class EncounterStatic5DR : EncounterStatic5
{
public EncounterStatic5DR(int species, int form, int abilityIndex = 4)

View file

@ -1,5 +1,9 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 5 Static Encounter from N
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
internal sealed class EncounterStatic5N : EncounterStatic5
{
public readonly uint PID;

View file

@ -2,6 +2,10 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 6 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public sealed class EncounterStatic6 : EncounterStatic, IContestStats
{
public override int Generation => 6;

View file

@ -3,6 +3,10 @@ using System.Collections.Generic;
namespace PKHeX.Core
{
/// <summary>
/// Generation 7 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public sealed class EncounterStatic7 : EncounterStatic, IRelearn
{
public override int Generation => 7;
@ -20,9 +24,9 @@ namespace PKHeX.Core
if (SkipFormCheck)
return true;
if (FormConverter.IsTotemForm(Species, Form, Generation))
if (AltFormInfo.IsTotemForm(Species, Form, Generation))
{
var expectForm = pkm.Format == 7 ? Form : FormConverter.GetTotemBaseForm(Species, Form);
var expectForm = pkm.Format == 7 ? Form : AltFormInfo.GetTotemBaseForm(Species, Form);
return expectForm == evo.Form;
}

View file

@ -1,5 +1,9 @@
namespace PKHeX.Core
{
/// <summary>
/// Generation 7 Static Encounter (<see cref="GameVersion.GG"/>
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public sealed class EncounterStatic7b : EncounterStatic
{
public override int Generation => 7;

View file

@ -3,6 +3,10 @@ using System.Collections.Generic;
namespace PKHeX.Core
{
/// <summary>
/// Generation 8 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public class EncounterStatic8 : EncounterStatic, IDynamaxLevel, IGigantamax, IRelearn
{
public sealed override int Generation => 8;

View file

@ -5,8 +5,9 @@ using static PKHeX.Core.Encounters8Nest;
namespace PKHeX.Core
{
/// <summary>
/// Generation 8 Nest Encounter (Raid)
/// Generation 8 Nest Encounter (Regular Raid Dens)
/// </summary>
/// <inheritdoc cref="EncounterStatic8Nest{T}"/>
public sealed class EncounterStatic8N : EncounterStatic8Nest<EncounterStatic8N>
{
private readonly uint MinRank;

View file

@ -5,6 +5,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 8 Nest Encounter (Distributed Crystal Data)
/// </summary>
/// <inheritdoc cref="EncounterStatic8Nest{T}"/>
public sealed class EncounterStatic8NC : EncounterStatic8Nest<EncounterStatic8NC>
{
public override int Location { get => SharedNest; set { } }

View file

@ -5,6 +5,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 8 Nest Encounter (Distributed Data)
/// </summary>
/// <inheritdoc cref="EncounterStatic8Nest{T}"/>
public sealed class EncounterStatic8ND : EncounterStatic8Nest<EncounterStatic8ND>
{
public EncounterStatic8ND(byte lvl, byte dyna, byte flawless)

View file

@ -3,9 +3,13 @@ using static PKHeX.Core.Encounters8Nest;
namespace PKHeX.Core
{
/// <summary>
/// Generation 8 Nest Encounter (Raid)
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public abstract class EncounterStatic8Nest<T> : EncounterStatic, IGigantamax, IDynamaxLevel where T : EncounterStatic8Nest<T>
{
public override int Generation => 8;
public sealed override int Generation => 8;
public static Func<PKM, T, bool>? VerifyCorrelation { private get; set; }
public static Action<PKM, T, EncounterCriteria>? GenerateData { private get; set; }
@ -41,7 +45,7 @@ namespace PKHeX.Core
return base.IsMatch(pkm, evo);
}
public override bool IsMatchDeferred(PKM pkm)
public sealed override bool IsMatchDeferred(PKM pkm)
{
if (base.IsMatchDeferred(pkm))
return true;
@ -75,7 +79,7 @@ namespace PKHeX.Core
return false;
}
protected override void SetPINGA(PKM pk, EncounterCriteria criteria)
protected sealed override void SetPINGA(PKM pk, EncounterCriteria criteria)
{
if (GenerateData != null)
GenerateData(pk, (T)this, criteria);

View file

@ -7,6 +7,7 @@ namespace PKHeX.Core
/// <summary>
/// <see cref="EncounterStatic8"/> with multiple references (used for multiple met locations)
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public sealed class EncounterStatic8S : EncounterStatic8
{
public override int Location { get => Locations[0]; set { } }

View file

@ -5,6 +5,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 8 Nest Encounter (Max Raid) Underground
/// </summary>
/// <inheritdoc cref="EncounterStatic8Nest{T}"/>
public sealed class EncounterStatic8U : EncounterStatic8Nest<EncounterStatic8U>
{
public override int Location { get => MaxLair; set { } }

View file

@ -7,6 +7,7 @@ namespace PKHeX.Core
/// <summary>
/// Shadow Pokémon Encounter found in <see cref="GameVersion.CXD"/>
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public sealed class EncounterStaticShadow : EncounterStatic
{
public override int Generation => 3;

View file

@ -3,6 +3,10 @@ using System.Linq;
namespace PKHeX.Core
{
/// <summary>
/// Generation 4 Static Encounter
/// </summary>
/// <inheritdoc cref="EncounterStatic"/>
public sealed class EncounterStaticTyped : EncounterStatic4, IEncounterTypeTile
{
public bool Roaming { get; set; }
@ -17,6 +21,7 @@ namespace PKHeX.Core
if (!Roaming)
return base.IsMatchLocation(pkm);
// Met location is lost on transfer
if (!(pkm is G4PKM pk4))
return true;

View file

@ -259,16 +259,16 @@ namespace PKHeX.Core
private bool IsMatchLevel(PKM pkm, DexLevel evo)
{
if (!pkm.HasOriginalMetLocation)
return Level <= evo.Level;
return evo.Level >= Level;
var loc = Location != 0 ? Location : GetDefaultMetLocation(Generation);
if (loc != pkm.Met_Location)
return false;
if (pkm.Format < 5)
return Level <= evo.Level;
return evo.Level >= Level;
return Level == pkm.Met_Level;
return pkm.Met_Level == Level;
}
protected virtual bool IsMatchNatureGenderShiny(PKM pkm)

View file

@ -60,7 +60,7 @@ namespace PKHeX.Core
{
if (form == 0)
return false;
if (FormConverter.IsTotemForm(species, form, gen))
if (AltFormInfo.IsTotemForm(species, form, gen))
return true;
if (species == (int) Species.Pichu)
return true; // can't get Spiky Ear Pichu eggs

View file

@ -204,5 +204,88 @@ namespace PKHeX.Core
hs.UnionWith(BattlePrimals);
return hs;
}
/// <summary>
/// Chhecks if the <see cref="form"/> for the <see cref="species"/> is a Totem form.
/// </summary>
/// <param name="species">Entity species</param>
/// <param name="form">Entity form</param>
/// <param name="format">Current generation format</param>
public static bool IsTotemForm(int species, int form, int format)
{
if (format != 7)
return false;
if (form == 0)
return false;
if (!Legal.Totem_USUM.Contains(species))
return false;
if (species == (int)Mimikyu)
return form == 2 || form == 3;
if (Legal.Totem_Alolan.Contains(species))
return form == 2;
return form == 1;
}
/// <summary>
/// Gets the base <see cref="form"/> for the <see cref="species"/> when the Totem form is reverted (on transfer).
/// </summary>
/// <param name="species">Entity species</param>
/// <param name="form">Entity form</param>
public static int GetTotemBaseForm(int species, int form)
{
if (species == (int)Mimikyu)
return form - 2;
return form - 1;
}
/// <summary>
/// Checks if the <see cref="form"/> exists for the <see cref="species"/> without having an associated <see cref="PersonalInfo"/> index.
/// </summary>
/// <param name="species">Entity species</param>
/// <param name="form">Entity form</param>
/// <param name="format">Current generation format</param>
/// <seealso cref="HasFormeValuesNotIndicatedByPersonal"/>
public static bool IsValidOutOfBoundsForme(int species, int form, int format)
{
return (Species) species switch
{
Unown => form < (format == 2 ? 26 : 28), // A-Z : A-Z?!
Mothim => form < 3, // Burmy base form is kept
Scatterbug => form < 18, // Vivillon Pre-evolutions
Spewpa => form < 18, // Vivillon Pre-evolutions
_ => false
};
}
/// <summary>
/// Checks if the <see cref="PKM"/> data should have a drop-down selection visible for the <see cref="PKM.AltForm"/> value.
/// </summary>
/// <param name="pi">Game specific personal info</param>
/// <param name="species"><see cref="Species"/> ID</param>
/// <param name="format"><see cref="PKM.AltForm"/> ID</param>
/// <returns>True if has formes that can be provided by <see cref="FormConverter.GetFormList"/>, otherwise false for none.</returns>
public static bool HasFormSelection(PersonalInfo pi, int species, int format)
{
if (format <= 3 && species != (int)Unown)
return false;
if (HasFormeValuesNotIndicatedByPersonal.Contains(species))
return true;
int count = pi.FormeCount;
return count > 1;
}
/// <summary>
/// <seealso cref="IsValidOutOfBoundsForme"/>
/// </summary>
private static readonly HashSet<int> HasFormeValuesNotIndicatedByPersonal = new HashSet<int>
{
(int)Unown,
(int)Mothim, // (Burmy forme carried over, not cleared)
(int)Scatterbug, (int)Spewpa, // Vivillon pre-evos
};
}
}

View file

@ -39,7 +39,7 @@ namespace PKHeX.Core
var EncounterMatch = data.EncounterMatch;
var Info = data.Info;
if (!PersonalInfo.IsFormeWithinRange(form) && !FormConverter.IsValidOutOfBoundsForme(species, form, Info.Generation))
if (!PersonalInfo.IsFormeWithinRange(form) && !AltFormInfo.IsValidOutOfBoundsForme(species, form, Info.Generation))
return GetInvalid(string.Format(LFormInvalidRange, count - 1, form));
if (EncounterMatch is EncounterSlot w && w.Area.Type == SlotType.FriendSafari)
@ -48,7 +48,7 @@ namespace PKHeX.Core
}
else if (EncounterMatch is EncounterEgg)
{
if (FormConverter.IsTotemForm(species, form, data.Info.Generation))
if (AltFormInfo.IsTotemForm(species, form, data.Info.Generation))
return GetInvalid(LFormInvalidGame);
}

View file

@ -128,11 +128,11 @@ namespace PKHeX.Core
}
else if (enc.Generation < 8 && pkm.Format >= 8)
{
if (enc is EncounterStatic7 s && FormConverter.IsTotemForm(s.Species, s.Form, 7))
if (enc is EncounterStatic7 s && AltFormInfo.IsTotemForm(s.Species, s.Form, 7))
{
if (Legal.Totem_NoTransfer.Contains(s.Species))
data.AddLine(GetInvalid(LTransferBad));
if (pkm.AltForm != FormConverter.GetTotemBaseForm(s.Species, s.Form))
if (pkm.AltForm != AltFormInfo.GetTotemBaseForm(s.Species, s.Form))
data.AddLine(GetInvalid(LTransferBad));
}

View file

@ -1713,9 +1713,4 @@
<EmbeddedResource Include="Resources\text\zh\text_xy_60000_zh.txt" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
<Folder Include="Saves\Substructures\Mail\" />
</ItemGroup>
</Project>

View file

@ -633,8 +633,8 @@ namespace PKHeX.Core
};
// Wipe Totem Forms
if (FormConverter.IsTotemForm(Species, AltForm, 7))
pk8.AltForm = FormConverter.GetTotemBaseForm(Species, AltForm);
if (AltFormInfo.IsTotemForm(Species, AltForm, 7))
pk8.AltForm = AltFormInfo.GetTotemBaseForm(Species, AltForm);
// Fix PP and Stats
pk8.Heal();

View file

@ -5,7 +5,7 @@ using static PKHeX.Core.Species;
namespace PKHeX.Core
{
/// <summary>
/// Logic for various <see cref="PKM.AltForm"/> related requests.
/// Retrieves localized form names for indicating <see cref="PKM.AltForm"/> values.
/// </summary>
public static class FormConverter
{
@ -47,44 +47,6 @@ namespace PKHeX.Core
// this is a hack; depends on currently loaded SaveFile's Game ID
private static bool IsGG() => PKMConverter.Game == (int)GameVersion.GP || PKMConverter.Game == (int)GameVersion.GE;
public static bool IsTotemForm(int species, int form, int generation)
{
if (generation != 7)
return false;
if (form == 0)
return false;
if (!Legal.Totem_USUM.Contains(species))
return false;
if (species == (int)Mimikyu)
return form == 2 || form == 3;
if (Legal.Totem_Alolan.Contains(species))
return form == 2;
return form == 1;
}
public static int GetTotemBaseForm(int species, int form)
{
if (species == (int)Mimikyu)
return form - 2;
return form - 1;
}
public static bool IsValidOutOfBoundsForme(int species, int form, int generation)
{
switch ((Species)species)
{
case Unown:
return form < (generation == 2 ? 26 : 28); // A-Z : A-Z?!
case Mothim: // Burmy base form is kept
return form < 3;
case Scatterbug:
case Spewpa: // Vivillon Pre-evolutions
return form < 18;
default:
return false;
}
}
private static readonly string[] EMPTY = { string.Empty };
private const string Starter = nameof(Starter);
@ -904,32 +866,6 @@ namespace PKHeX.Core
015, 018, 080, 208, 254, 260, 302, 319, 323, 334, 362, 373, 376, 384, 428, 475, 531, 719,
};
/// <summary>
/// Checks if the <see cref="PKM"/> data should have a drop-down selection visible for the <see cref="PKM.AltForm"/> value.
/// </summary>
/// <param name="pi">Game specific personal info</param>
/// <param name="species"><see cref="Species"/> ID</param>
/// <param name="format"><see cref="PKM.AltForm"/> ID</param>
/// <returns>True if has formes that can be provided by <see cref="GetFormList"/>, otherwise false for none.</returns>
public static bool HasFormSelection(PersonalInfo pi, int species, int format)
{
if (format <= 3 && species != (int)Unown)
return false;
if (HasFormeValuesNotIndicatedByPersonal.Contains(species))
return true;
int count = pi.FormeCount;
return count > 1;
}
private static readonly HashSet<int> HasFormeValuesNotIndicatedByPersonal = new HashSet<int>
{
(int)Unown,
(int)Mothim, // (Burmy forme carried over, not cleared)
(int)Scatterbug, (int)Spewpa, // Vivillon pre-evos
};
private static string[] GetMegaSingle(IReadOnlyList<string> types, IReadOnlyList<string> forms)
{
return new[]
@ -969,7 +905,7 @@ namespace PKHeX.Core
}
private const int Galarian = 1068;
// private const int Gigantamax = 1069;
private const int Gigantamax = 1069;
private const int Gulping = 1070;
private const int Gorging = 1071;
private const int LowKey = 1072;
@ -995,6 +931,8 @@ namespace PKHeX.Core
private const int CalyIce = 1089; // Ice
private const int CalyGhost = 1090; // Shadow
public static string GetGigantamaxName(IReadOnlyList<string> forms) => forms[Gigantamax];
public static string[] GetAlcremieFormList(IReadOnlyList<string> forms)
{
var result = new string[63];

View file

@ -95,7 +95,7 @@ namespace PKHeX.Core
else if (sav.MaxSpeciesID < pkm.Species)
errata.Add($"{MsgIndexSpeciesGame} {strings.Species[pkm.Species]}");
if (!sav.Personal[pkm.Species].IsFormeWithinRange(pkm.AltForm) && !FormConverter.IsValidOutOfBoundsForme(pkm.Species, pkm.AltForm, pkm.GenNumber))
if (!sav.Personal[pkm.Species].IsFormeWithinRange(pkm.AltForm) && !AltFormInfo.IsValidOutOfBoundsForme(pkm.Species, pkm.AltForm, pkm.GenNumber))
errata.Add(string.Format(LegalityCheckStrings.LFormInvalidRange, Math.Max(0, sav.Personal[pkm.Species].FormeCount - 1), pkm.AltForm));
if (pkm.Moves.Any(m => m > strings.Move.Count))

View file

@ -84,7 +84,7 @@ namespace PKHeX.Drawing
private Image GetBaseImage(int species, int form, int gender, uint formarg, bool shiny, int generation)
{
var img = FormConverter.IsTotemForm(species, form, generation)
var img = AltFormInfo.IsTotemForm(species, form, generation)
? GetBaseImageTotem(species, form, gender, formarg, shiny, generation)
: GetBaseImageDefault(species, form, gender, formarg, shiny, generation);
return img ?? GetBaseImageFallback(species, form, gender, formarg, shiny, generation);
@ -92,7 +92,7 @@ namespace PKHeX.Drawing
private Image? GetBaseImageTotem(int species, int form, int gender, uint formarg, bool shiny, int generation)
{
var baseform = FormConverter.GetTotemBaseForm(species, form);
var baseform = AltFormInfo.GetTotemBaseForm(species, form);
var baseImage = GetBaseImageDefault(species, baseform, gender, formarg, shiny, generation);
if (baseImage == null)
return null;

View file

@ -427,7 +427,7 @@ namespace PKHeX.WinForms.Controls
{
int species = Entity.Species;
var pi = RequestSaveFile.Personal[species];
bool hasForms = FormConverter.HasFormSelection(pi, species, Entity.Format);
bool hasForms = AltFormInfo.HasFormSelection(pi, species, Entity.Format);
CB_Form.Enabled = CB_Form.Visible = Label_Form.Visible = hasForms;
if (HaX && Entity.Format >= 4)

View file

@ -458,7 +458,7 @@ namespace PKHeX.WinForms
private void SetForms()
{
int species = WinFormsUtil.GetIndex(CB_Species);
bool hasForms = FormConverter.HasFormSelection(PersonalTable.AO[species], species, 6);
bool hasForms = AltFormInfo.HasFormSelection(PersonalTable.AO[species], species, 6);
CB_Form.Enabled = CB_Form.Visible = hasForms;
CB_Form.InitializeBinding();

View file

@ -133,7 +133,7 @@ namespace PKHeX.WinForms
int fspecies = LB_Species.SelectedIndex + 1;
var bspecies = Dex.GetBaseSpecies(fspecies);
bool hasForms = FormConverter.HasFormSelection(SAV.Personal[bspecies], bspecies, 7);
bool hasForms = AltFormInfo.HasFormSelection(SAV.Personal[bspecies], bspecies, 7);
LB_Forms.Enabled = hasForms;
if (!hasForms) return false;
var ds = FormConverter.GetFormList(bspecies, GameInfo.Strings.types, GameInfo.Strings.forms, Main.GenderSymbols, SAV.Generation).ToList();

View file

@ -120,7 +120,7 @@ namespace PKHeX.WinForms
int fspecies = LB_Species.SelectedIndex + 1;
var bspecies = Dex.GetBaseSpecies(fspecies);
bool hasForms = FormConverter.HasFormSelection(SAV.Personal[bspecies], bspecies, 7);
bool hasForms = AltFormInfo.HasFormSelection(SAV.Personal[bspecies], bspecies, 7);
LB_Forms.Enabled = hasForms;
if (!hasForms)
return false;