PKHeX/PKHeX.Core/Legality/Verifiers/Misc/MiscVerifierG3.cs
Kurt 79a08822ea FR/LG VC: Handle unobtainable balls
https: //github.com/kwsch/PKHeX/pull/4735#issuecomment-3986152531
Co-Authored-By: Carbonara <108797333+Mimigris@users.noreply.github.com>
2026-03-03 00:35:18 -06:00

90 lines
3.0 KiB
C#

using System;
using static PKHeX.Core.LegalityCheckResultCode;
using static PKHeX.Core.CheckIdentifier;
namespace PKHeX.Core;
public sealed class MiscVerifierG3 : Verifier
{
protected override CheckIdentifier Identifier => Misc;
public override void Verify(LegalityAnalysis data)
{
if (data.Entity is G3PKM pk)
Verify(data, pk);
}
internal void Verify(LegalityAnalysis data, G3PKM pk)
{
if (ParseSettings.AllowGBACrossTransferRSE(pk))
return;
// Notes:
// Nicknamed by player: all FF'd trash.
// In-game trade: clean 00'd with a single FF on each.
// Only FR/LG are released. Only can originate from FR/LG.
if (pk.Version is not (GameVersion.FR or GameVersion.LG))
data.AddLine(GetInvalid(TradeNotAvailable));
else if (Legal.IsForeignFRLG(pk.Species))
data.AddLine(GetInvalid(TradeNotAvailable));
if (ItemStorage3FRLG_VC.IsUnreleasedHeld(pk.HeldItem))
data.AddLine(GetInvalid(ItemUnreleased));
if ((Ball)pk.Ball is Ball.Dive or Ball.Premier)
data.AddLine(GetInvalid(BallUnavailable));
if (pk is PK3 pk3)
VerifyTrash(data, pk3);
}
private void VerifyTrash(LegalityAnalysis data, PK3 pk)
{
var enc = data.EncounterOriginal;
if (enc is EncounterTrade3)
VerifyTrashTrade(data, pk);
else if (pk.Japanese && !(pk.IsEgg && pk.OriginalTrainerTrash[^1] == 0xFF))
VerifyTrashJPN(data, pk);
else
VerifyTrashINT(data, pk);
}
private void VerifyTrashTrade(LegalityAnalysis data, PK3 pk)
{
// For in-game trades, zeroes after the first terminator.
var trash = pk.OriginalTrainerTrash;
int len = TrashBytes8.GetStringLength(trash);
if (len == trash.Length)
return; // OK
if (trash[(len+1)..].ContainsAnyExcept<byte>(0))
data.AddLine(GetInvalid(TrashBytesMissingTerminator));
}
private void VerifyTrashJPN(LegalityAnalysis data, PK3 pk)
{
var trash = pk.OriginalTrainerTrash;
// OT name from save file is copied byte-for-byte. Byte 7 & 8 are always zero.
// PK3 do not store the 8th byte. Check the 7th explicitly.
if (trash[^1] != 0x00)
data.AddLine(GetInvalid(TrashBytesMissingTerminator));
int len = TrashBytes8.GetStringLength(trash);
if (len >= trash.Length - 2)
return; // OK -- invalid lengths will get warned elsewhere
if (trash[len..^2].ContainsAnyExcept<byte>(0xFF))
data.AddLine(GetInvalid(TrashBytesMissingTerminator));
}
private void VerifyTrashINT(LegalityAnalysis data, PK3 pk)
{
var trash = pk.OriginalTrainerTrash;
// OT name from save file is copied byte-for-byte. All 8 bytes are initialized to FF on new game.
int len = TrashBytes8.GetStringLength(trash);
if (trash[len..].ContainsAnyExcept<byte>(0xFF))
data.AddLine(GetInvalid(TrashBytesMissingTerminator));
}
}