PKHeX/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot7GO.cs
Kurt 85abb48da3 Misc tweaks for Hoopa-1 plus flags
Merge handling with Rotom's handling
Add logic for "Require" & "Set All" operations -- if the form isn't 0.

https://projectpokemon.org/home/forums/topic/57375-pkhex-new-update-legality-errors-contribution-page/page/35/#findComment-298854
2026-01-04 23:44:57 -06:00

163 lines
5.8 KiB
C#

using System;
namespace PKHeX.Core;
/// <summary>
/// Encounter Slot found in <see cref="EntityContext.Gen7b"/> (GO Park).
/// <inheritdoc cref="PogoSlotExtensions" />
/// </summary>
public sealed record EncounterSlot7GO(int StartDate, int EndDate, ushort Species, byte Form, byte LevelMin, byte LevelMax, Shiny Shiny, Gender Gender, PogoType Type)
: IEncounterable, IEncounterMatch, IPogoSlot, IEncounterConvertible<PB7>, IEncounterServerDate
{
public bool IsDateRestricted => true;
public byte Generation => 7;
public EntityContext Context => EntityContext.Gen7b;
public Ball FixedBall => Ball.None; // GO Park can override the ball; obey capture rules for LGP/E
public bool IsEgg => false;
public AbilityPermission Ability => AbilityPermission.Any12;
public bool IsShiny => Shiny.IsShiny();
public ushort EggLocation => 0;
public GameVersion Version => GameVersion.GO;
public ushort Location => Locations.GO7;
public string Name => $"GO Encounter ({Version})";
public string LongName
{
get
{
var init = $"{Name} ({Type})";
if (StartDate == 0 && EndDate == 0)
return init;
var start = PogoDateRangeExtensions.GetDateString(StartDate);
var end = PogoDateRangeExtensions.GetDateString(EndDate);
return $"{init}: {start}-{end}";
}
}
#region Generating
PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) => ConvertToPKM(tr, criteria);
PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr);
public PB7 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted);
public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
{
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
var rnd = Util.Rand;
var date = this.GetRandomValidDate();
var pk = new PB7
{
PID = EncounterUtil.GetRandomPID(tr, rnd, Shiny, criteria.Shiny),
EncryptionConstant = rnd.Rand32(),
Species = Species,
Form = Form,
CurrentLevel = LevelMin,
OriginalTrainerFriendship = PersonalTable.GG[Species].BaseFriendship,
MetLocation = Location,
MetLevel = LevelMin,
Version = Version,
Ball = (byte)Ball.Poke,
MetDate = date,
Language = language,
OriginalTrainerName = tr.OT,
OriginalTrainerGender = tr.Gender,
ID32 = tr.ID32,
ReceivedDate = date,
ReceivedTime = EncounterDate.GetTime(),
};
SetPINGA(pk, criteria);
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
pk.Nickname = SpeciesName.GetSpeciesNameGeneration(Species, language, Generation);
SetEncounterMoves(pk, LevelMin);
pk.AwakeningSetAllTo(2);
pk.HeightScalar = PokeSizeUtil.GetRandomScalar(rnd);
pk.WeightScalar = PokeSizeUtil.GetRandomScalar(rnd);
pk.ResetHeight();
pk.ResetWeight();
pk.ResetCP();
pk.ResetPartyStats();
return pk;
}
private void SetPINGA(PB7 pk, in EncounterCriteria criteria)
{
var pi = PersonalTable.GG[Species];
var gender = criteria.GetGender(Gender, pi);
var nature = criteria.GetNature();
var ability = criteria.GetAbilityFromNumber(Ability);
criteria.SetRandomIVsGO(pk, Type.MinimumIV);
pk.Nature = pk.StatNature = nature;
pk.Gender = gender;
pk.RefreshAbility(ability);
switch (Shiny)
{
case Shiny.Random when !pk.IsShiny && criteria.Shiny.IsShiny():
case Shiny.Always when !pk.IsShiny: // Force Square
var low = pk.PID & 0xFFFF;
pk.PID = ((low ^ pk.TID16 ^ pk.SID16 ^ 0) << 16) | low;
break;
case Shiny.Random when pk.IsShiny && !criteria.Shiny.IsShiny():
case Shiny.Never when pk.IsShiny: // Force Not Shiny
pk.PID ^= 0x1000_0000;
break;
}
}
private void SetEncounterMoves(PB7 pk, byte level)
{
Span<ushort> moves = stackalloc ushort[4];
var source = LearnSource7GG.Instance;
((ILearnSource)source).SetEncounterMoves(Species, Form, level, moves);
pk.SetMoves(moves);
}
#endregion
#region Matching
public bool IsMatchExact(PKM pk, EvoCriteria evo)
{
// Find the first chain that has slots defined.
// Since it is possible to evolve before transferring, we only need the highest evolution species possible.
// PoGoEncTool has already extrapolated the evolutions to separate encounters!
if (!this.IsLevelWithinRange(pk.MetLevel))
return false;
//if (!slot.IsBallValid(ball)) -- can have any of the in-game balls due to re-capture
// continue;
if (!Shiny.IsValid(pk))
return false;
// At least one encounter is a single gender (Pikachu 24-11-04 yay...) so check.
if (Gender != Gender.Random && (int)Gender != pk.Gender)
return false;
return true;
}
public bool IsWithinDistributionWindow(PKM pk)
{
var date = new DateOnly(pk.MetYear + 2000, pk.MetMonth, pk.MetDay);
return IsWithinDistributionWindow(date);
}
public bool IsWithinDistributionWindow(DateOnly date)
{
var stamp = PogoDateRangeExtensions.GetTimeStamp(date.Year, date.Month, date.Day);
return this.IsWithinStartEnd(stamp);
}
public EncounterMatchRating GetMatchRating(PKM pk)
{
if (!IsWithinDistributionWindow(pk))
return EncounterMatchRating.DeferredErrors;
if (!this.GetIVsValid(pk))
return EncounterMatchRating.Deferred;
return EncounterMatchRating.Match;
}
#endregion
}