Misc pogo pkl refinements

Add flags to pkl, +2 to each entry (oh well, maybe they'll add maxIV too)
Use flags to for random met date to a more reasonable day.
Use flags to remap displayed date range to the reasonable range.
This commit is contained in:
Kurt
2026-09-23 08:56:54 -05:00
parent fffec78498
commit 0e0bde1bf2
8 changed files with 74 additions and 38 deletions

View File

@@ -31,7 +31,7 @@ internal static EncounterArea7g[] GetArea(BinLinkerAccessor data)
}
private const int meta = 4;
private const int entrySize = (2 * sizeof(int)) + 2;
private const int entrySize = (2 * sizeof(ushort)) + 8;
private static EncounterArea7g GetArea(ReadOnlySpan<byte> data)
{
@@ -61,9 +61,10 @@ private static EncounterSlot7GO ReadSlot(ReadOnlySpan<byte> entry, ushort specie
var gender = (Gender)entry[5];
var type = (PogoType)entry[6];
//var ball = (PogoBallRestriction)entry[7];
var minLevel = entry[8];
var minIV = entry[9];
return new EncounterSlot7GO(start, end, species, form, minLevel, minIV, shiny, gender, type);
var flags = (PogoFlags)entry[8];
var minLevel = entry[9];
var minIV = entry[10];
return new EncounterSlot7GO(start, end, species, form, minLevel, minIV, shiny, gender, type, flags);
}
}

View File

@@ -31,7 +31,7 @@ internal static EncounterArea8g[] GetArea(BinLinkerAccessor data)
}
private const int meta = 4;
private const int entrySize = (2 * sizeof(ushort)) + 6;
private const int entrySize = (2 * sizeof(ushort)) + 8;
private static EncounterArea8g GetArea(ReadOnlySpan<byte> data)
{
@@ -61,8 +61,10 @@ private static EncounterSlot8GO ReadSlot(ReadOnlySpan<byte> entry, ushort specie
var gender = (Gender)entry[5];
var type = (PogoType)entry[6];
var ball = (PogoBallRestriction)entry[7];
var minLevel = entry[8];
var minIV = entry[9];
return new EncounterSlot8GO(start, end, species, form, minLevel, minIV, shiny, gender, type, ball, format);
var flags = (PogoFlags)entry[8];
var minLevel = entry[9];
var minIV = entry[10];
return new EncounterSlot8GO(start, end, species, form, minLevel, minIV, shiny, gender, type, ball, format, flags);
}
}

View File

@@ -6,7 +6,7 @@ namespace PKHeX.Core;
/// Encounter Slot found in <see cref="EntityContext.Gen7b"/> (GO Park).
/// <inheritdoc cref="PogoSlotExtensions" />
/// </summary>
public sealed record EncounterSlot7GO(ushort DayStart, ushort DayEnd, ushort Species, byte Form, byte LevelMin, byte MinimumIV, Shiny Shiny, Gender Gender, PogoType Type)
public sealed record EncounterSlot7GO(ushort DayStart, ushort DayEnd, ushort Species, byte Form, byte LevelMin, byte MinimumIV, Shiny Shiny, Gender Gender, PogoType Type, PogoFlags Flags)
: IEncounterable, IEncounterMatch, IPogoSlot, IEncounterConvertible<PB7>, IEncounterServerDate
{
public bool IsDateRestricted => true;
@@ -21,6 +21,8 @@ public sealed record EncounterSlot7GO(ushort DayStart, ushort DayEnd, ushort Spe
public GameVersion Version => GameVersion.GO;
public ushort Location => Locations.GO7;
public byte LevelMax => EncountersGO.MAX_LEVEL;
public bool IsLocalDayStart => Flags.HasFlag(PogoFlags.LocalDateStart);
public bool IsLocalDayEnd => Flags.HasFlag(PogoFlags.LocalDateEnd);
public string Name => $"GO Encounter ({Version})";
public string LongName
@@ -28,10 +30,8 @@ public string LongName
get
{
var init = $"{Name} ({Type})";
if (((IPogoDateRange)this).IsNoDateEither)
return init;
var start = PogoDateRangeExtensions.GetDateString(DayStart);
var end = PogoDateRangeExtensions.GetDateString(DayEnd);
var start = PogoDateRangeExtensions.GetDateString(DayStart, IsLocalDayStart ? 1 : 0, true);
var end = PogoDateRangeExtensions.GetDateString(DayEnd, IsLocalDayEnd ? -1 : 0);
return $"{init}: {start}-{end}";
}
}
@@ -158,3 +158,10 @@ public EncounterMatchRating GetMatchRating(PKM pk)
}
#endregion
}
public enum PogoFlags : byte
{
LocalDateStart = 1 << 0,
LocalDateEnd = 1 << 1,
FeaturedWildArea = 1 << 2,
}

View File

@@ -7,7 +7,7 @@ namespace PKHeX.Core;
/// Encounter Slot representing data transferred to HOME.
/// <inheritdoc cref="PogoSlotExtensions" />
/// </summary>
public sealed record EncounterSlot8GO(ushort DayStart, ushort DayEnd, ushort Species, byte Form, byte LevelMin, byte MinimumIV, Shiny Shiny, Gender Gender, PogoType Type, PogoBallRestriction BallRestrict, PogoImportFormat OriginFormat)
public sealed record EncounterSlot8GO(ushort DayStart, ushort DayEnd, ushort Species, byte Form, byte LevelMin, byte MinimumIV, Shiny Shiny, Gender Gender, PogoType Type, PogoBallRestriction BallRestrict, PogoImportFormat OriginFormat, PogoFlags Flags)
: IEncounterable, IEncounterMatch, IEncounterConvertible<PKM>, IPogoSlot, IFixedOTFriendship, IEncounterServerDate
{
public byte Generation => 8;
@@ -20,6 +20,8 @@ public sealed record EncounterSlot8GO(ushort DayStart, ushort DayEnd, ushort Spe
public GameVersion Version => GameVersion.GO;
public ushort Location => Locations.GO8;
public byte LevelMax => EncountersGO.MAX_LEVEL;
public bool IsLocalDayStart => Flags.HasFlag(PogoFlags.LocalDateStart);
public bool IsLocalDayEnd => Flags.HasFlag(PogoFlags.LocalDateEnd);
public string Name => $"GO Encounter ({Version})";
public string LongName
@@ -27,10 +29,8 @@ public string LongName
get
{
var init = $"{Name} ({Type})";
if (((IPogoDateRange)this).IsNoDateEither)
return init;
var start = PogoDateRangeExtensions.GetDateString(DayStart);
var end = PogoDateRangeExtensions.GetDateString(DayEnd);
var start = PogoDateRangeExtensions.GetDateString(DayStart, IsLocalDayStart ? 1 : 0, true);
var end = PogoDateRangeExtensions.GetDateString(DayEnd, IsLocalDayEnd ? -1 : 0);
return $"{init}: {start}-{end}";
}
}
@@ -58,9 +58,9 @@ public bool IsBallValid(Ball ball, ushort currentSpecies, PKM pk)
// GO does not natively produce Shedinja when evolving Nincada, and thus must be evolved in future games.
if (currentSpecies == (int)Shedinja && currentSpecies != Species)
return ball == Ball.Poke;
if (ball == Ball.Master)
return BallRestrict.IsMasterBallUsable && pk.MetDate >= new DateOnly(2023, 5, 21);
return BallRestrict.IsValidBall(ball);
if (ball == Ball.Master && pk.MetDate < new DateOnly(2023, 5, 21))
return false;
return BallRestrict.IsValidBall(ball, Type, Flags);
}
private PKM GetBlank() => OriginFormat switch

View File

@@ -14,6 +14,9 @@ public interface IPogoDateRange
/// <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>
ushort DayEnd { get; }
bool IsLocalDayStart { get; }
bool IsLocalDayEnd { get; }
internal const int FirstDay = 736150 - 1; // 2016-07-06 (Launch Day), -1 for time zones.
internal const ushort DateNone = 0;
internal bool IsNoDateEnd => DayEnd == DateNone;
@@ -23,7 +26,7 @@ public interface IPogoDateRange
public static class PogoDateRangeExtensions
{
public static string GetDateString(ushort day) => day == IPogoDateRange.DateNone ? "X" : $"{GetDate(day):yyyy.MM.dd}";
public static string GetDateString(ushort day, int shift, bool always = false) => day == IPogoDateRange.DateNone && !always ? "X" : $"{GetDate((ushort)(day + shift)):yyyy.MM.dd}";
private static DateOnly GetDate(ushort day) => DateOnly.FromDayNumber(GetDayNumber(day));
private static int GetDayNumber(ushort day) => IPogoDateRange.FirstDay + day;
private static ushort GetDayRelative(in DateOnly date) => (ushort)(date.DayNumber - IPogoDateRange.FirstDay);
@@ -47,13 +50,16 @@ public static bool IsWithinStartEnd(this IPogoDateRange time, DateOnly date)
public static DateOnly GetRandomValidDate(this IPogoDateRange time)
{
if (time.IsNoDateStart)
return time.IsNoDateEnd ? GetCurrentDateLocal() : GetDate(time.DayEnd);
return time.IsNoDateEnd ? GetCurrentDateLocal() : GetDate((ushort)(time.DayEnd - (time.IsLocalDayEnd ? 1 : 0)));
var start = time.DayStart + (time.IsLocalDayStart ? 1 : 0);
if (time.IsNoDateEnd)
return GetDate(time.DayStart);
return GetDate((ushort)start);
var delta = (time.DayEnd - time.DayStart) + 1;
var day = (ushort)Util.Rand.Next(delta);
// Both bounds present: apply local-day adjustments and pick a random day in the inclusive range.
var end = time.DayEnd - (time.IsLocalDayEnd ? 1 : 0);
var delta = end - start + 1;
var day = (ushort)(Util.Rand.Next(delta) + start);
return GetDate(day);
}
}

View File

@@ -66,6 +66,18 @@ public enum PogoType : byte
public static class PogoExtensions
{
private const Ball TransferSafariBall = Strange;
extension(PogoType type)
{
public bool IsRaid => type is PogoType.Raid
or PogoType.RaidMythical
or PogoType.RaidUltraBeast
or PogoType.RaidShadow
or PogoType.RaidShadowMythical
or PogoType.RaidShadowUltraBeast;
}
extension(PogoBallRestriction ball)
{
public Ball GetFixedBall() => ball switch
@@ -73,23 +85,31 @@ public static class PogoExtensions
PogoBallRestriction.OnlyPoke => Poke,
PogoBallRestriction.OnlyPremier => Premier,
PogoBallRestriction.OnlyBeast => Beast,
PogoBallRestriction.OnlySafari => Safari,
PogoBallRestriction.OnlySafari => TransferSafariBall,
_ => None,
};
public bool IsValidBall(Ball current) => ball switch
public bool IsValidBall(Ball current, PogoType type, PogoFlags flags)
{
PogoBallRestriction.None => true,
PogoBallRestriction.StandardMaster => current is Poke or Great or Ultra or Master,
PogoBallRestriction.Standard => current is Poke or Great or Ultra,
PogoBallRestriction.OnlyPoke => current is Poke,
PogoBallRestriction.OnlyPremier => current is Premier,
PogoBallRestriction.OnlyBeast => current is Beast,
PogoBallRestriction.OnlySafari => current is Safari,
_ => false,
};
if (current is Master)
return ball.IsMasterBallUsable(type);
if (current is TransferSafariBall)
return ball.IsSafariBallUsable(flags);
public bool IsMasterBallUsable => ball is PogoBallRestriction.StandardMaster;
return ball switch
{
PogoBallRestriction.None => true,
PogoBallRestriction.StandardMaster => current is Poke or Great or Ultra,
PogoBallRestriction.Standard => current is Poke or Great or Ultra,
PogoBallRestriction.OnlyPoke => current is Poke,
PogoBallRestriction.OnlyPremier => current is Premier,
PogoBallRestriction.OnlyBeast => current is Beast,
_ => false,
};
}
public bool IsMasterBallUsable(PogoType type) => ball is PogoBallRestriction.StandardMaster || type.IsRaid;
public bool IsSafariBallUsable(PogoFlags flags) => ball is PogoBallRestriction.OnlySafari || flags.HasFlag(PogoFlags.FeaturedWildArea);
}
}