PKHeX/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlot8GO.cs
Kurt 5bcccc6d92
HOME 2.0.0: Handle conversion behavior & restrictions (#3506)
* Revises legality checks to account for traveling between the three game islands (PLA/BDSP/SWSH)
* Adds conversion mechanisms between the three formats, as well as flexible conversion options to backfill missing data (thanks GameFreak/ILCA for opting for lossy conversion instead of updating the games).
* Adds API abstractions for HOME data storage format (EKH/PKH format 1, aka EH1/PH1).
* Revises some APIs for better usage:
  - `PKM` now exposes a `Context` to indicate the isolation context for legality purposes.
  - Some method signatures have changed to accept `Context` or `GameVersion` instead of a vague `int` for Generation.
  - Evolution History is now tracked in the Legality parse for specific contexts, rather than only per generation.
2022-05-30 21:43:52 -07:00

190 lines
7.4 KiB
C#

using System;
namespace PKHeX.Core
{
/// <summary>
/// Encounter Slot representing data transferred to <see cref="GameVersion.Gen8"/> (HOME).
/// <inheritdoc cref="EncounterSlotGO" />
/// </summary>
public sealed record EncounterSlot8GO : EncounterSlotGO, IFixedOTFriendship
{
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="OriginFormat"/> values.
/// </remarks>
public PogoImportFormat OriginFormat { get; }
public EncounterSlot8GO(EncounterArea8g area, int species, int form, int start, int end, Shiny shiny, Gender gender, PogoType type, PogoImportFormat originFormat)
: base(area, species, form, start, end, shiny, gender, type)
{
OriginFormat = originFormat;
}
/// <summary>
/// Checks if the <seealso cref="Ball"/> is compatible with the <seealso cref="PogoType"/>.
/// </summary>
public bool IsBallValid(Ball ball, int currentSpecies)
{
// GO does not natively produce Shedinja when evolving Nincada, and thus must be evolved in future games.
if (currentSpecies == (int)Core.Species.Shedinja && currentSpecies != Species)
return ball == Ball.Poke;
return Type.IsBallValid(ball);
}
protected override PKM GetBlank() => OriginFormat switch
{
PogoImportFormat.PK7 => new PK8(),
PogoImportFormat.PB7 => new PB7(),
PogoImportFormat.PK8 => new PK8(),
PogoImportFormat.PA8 => new PA8(),
_ => throw new ArgumentOutOfRangeException(nameof(OriginFormat)),
};
private PersonalInfo GetPersonal() => OriginFormat switch
{
PogoImportFormat.PK7 => PersonalTable.USUM.GetFormEntry(Species, Form),
PogoImportFormat.PB7 => PersonalTable.GG.GetFormEntry(Species, Form),
PogoImportFormat.PK8 => PersonalTable.SWSH.GetFormEntry(Species, Form),
PogoImportFormat.PA8 => PersonalTable.LA.GetFormEntry(Species, Form),
_ => throw new ArgumentOutOfRangeException(nameof(OriginFormat)),
};
internal GameVersion OriginGroup => OriginFormat switch
{
PogoImportFormat.PK7 => GameVersion.USUM,
PogoImportFormat.PB7 => GameVersion.GG,
PogoImportFormat.PK8 => GameVersion.SWSH,
PogoImportFormat.PA8 => GameVersion.PLA,
_ => throw new ArgumentOutOfRangeException(nameof(OriginFormat)),
};
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)
{
pk.HT_Name = "PKHeX";
pk.CurrentHandler = 1;
if (pk is IHandlerLanguage l)
l.HT_Language = 2;
base.ApplyDetails(sav, criteria, pk);
var ball = Type.GetValidBall();
if (ball != Ball.None)
pk.Ball = (int)ball;
if (pk is IScaledSize s)
{
s.HeightScalar = PokeSizeUtil.GetRandomScalar();
s.WeightScalar = PokeSizeUtil.GetRandomScalar();
}
if (OriginFormat is PogoImportFormat.PA8)
{
var pa8 = (PA8)pk;
pa8.ResetHeight();
pa8.ResetWeight();
pa8.HeightScalarCopy = pa8.HeightScalar;
}
pk.OT_Friendship = OT_Friendship;
pk.SetRandomEC();
}
protected override void SetPINGA(PKM pk, EncounterCriteria criteria)
{
var pi = GetPersonal();
if (OriginFormat is PogoImportFormat.PK7)
pk.EXP = Experience.GetEXP(LevelMin, pi.EXPGrowth);
int gender = criteria.GetGender(-1, pi);
int nature = (int)criteria.GetNature(Nature.Random);
var ability = criteria.GetAbilityFromNumber(Ability);
pk.PID = Util.Rand32();
pk.Nature = pk.StatNature = nature;
pk.Gender = gender;
pk.AbilityNumber = 1 << ability;
var abilities = pi.Abilities;
if ((uint)ability < abilities.Count)
pk.Ability = abilities[ability];
pk.SetRandomIVsGO();
base.SetPINGA(pk, criteria);
}
protected override void SetEncounterMoves(PKM pk, GameVersion version, int level)
{
var moves = MoveLevelUp.GetEncounterMoves(pk, level, OriginGroup);
pk.SetMoves(moves);
pk.SetMaximumPPCurrent(moves);
}
public override EncounterMatchRating GetMatchRating(PKM pkm)
{
if (IsMatchPartial(pkm))
return EncounterMatchRating.PartialMatch;
return base.GetMatchRating(pkm) == EncounterMatchRating.PartialMatch ? EncounterMatchRating.PartialMatch : EncounterMatchRating.Match;
}
public byte OT_Friendship => Species switch
{
(int)Core.Species.Timburr when Form == 0 => 70,
(int)Core.Species.Stunfisk when Form == 0 => 70,
(int)Core.Species.Hoopa when Form == 1 => 50,
_ => GetHOMEFriendship(),
};
private byte GetHOMEFriendship()
{
var fs = (byte)GetPersonal().BaseFriendship;
if (fs == 70)
return 50;
return fs;
}
private bool IsMatchPartial(PKM pk)
{
var stamp = GetTimeStamp(pk.Met_Year + 2000, pk.Met_Month, pk.Met_Day);
if (!IsWithinStartEnd(stamp))
return true;
if (!GetIVsAboveMinimum(pk))
return true;
if (!GetIVsBelowMaximum(pk))
return true;
// Eevee & Glaceon have different base friendships. Make sure if it is invalid that we yield the other encounter before.
if (pk.OT_Friendship != OT_Friendship)
return true;
return Species switch
{
(int)Core.Species.Yamask when pk.Species != Species && Form == 1 => pk is IFormArgument { FormArgument: 0 },
(int)Core.Species.Milcery when pk.Species != Species => pk is IFormArgument { FormArgument: 0 },
(int)Core.Species.Qwilfish when pk.Species != Species && Form == 1 => pk is IFormArgument { FormArgument: 0 },
(int)Core.Species.Basculin when pk.Species != Species && Form == 2 => pk is IFormArgument { FormArgument: 0 },
(int)Core.Species.Stantler when pk.Species != Species => pk is IFormArgument { FormArgument: 0 },
(int)Core.Species.Runerigus => pk is IFormArgument { FormArgument: not 0 },
(int)Core.Species.Alcremie => pk is IFormArgument { FormArgument: not 0 },
(int)Core.Species.Wyrdeer => pk is IFormArgument { FormArgument: not 0 },
(int)Core.Species.Basculegion => pk is IFormArgument { FormArgument: not 0 },
(int)Core.Species.Overqwil => pk is IFormArgument { FormArgument: not 0 },
_ => false,
};
}
}
public enum PogoImportFormat : byte
{
PK7 = 0,
PB7 = 1,
PK8 = 2,
PA8 = 3,
}
}