mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-23 04:23:12 +00:00
Minor tweaks
I quite like the DeSmuME footer check simplification.
This commit is contained in:
parent
738c51d596
commit
da27814504
9 changed files with 66 additions and 62 deletions
|
@ -189,7 +189,7 @@ public sealed class LegalityAnalysis
|
|||
Nickname.Verify(this);
|
||||
Level.Verify(this);
|
||||
Level.VerifyG1(this);
|
||||
Trainer.VerifyOTG1(this);
|
||||
Trainer.VerifyOTGB(this);
|
||||
MiscValues.VerifyMiscG1(this);
|
||||
if (Entity.Format == 2)
|
||||
Item.Verify(this);
|
||||
|
|
|
@ -12,7 +12,7 @@ public static class ShinyUtil
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool GetIsShiny(in uint id32, in uint pid, [ConstantExpected] uint cmp = 16) => GetShinyXor(id32, pid) < cmp;
|
||||
public static bool GetIsShiny(in uint id32, in uint pid, [ConstantExpected(Max = 16, Min = 8)] uint cmp = 16) => GetShinyXor(id32, pid) < cmp;
|
||||
|
||||
public static uint GetShinyXor(in uint pid, in uint id32)
|
||||
{
|
||||
|
|
|
@ -93,25 +93,25 @@ internal static class GBRestrictions
|
|||
return rate == PersonalTable.RB[species].CatchRate;
|
||||
}
|
||||
|
||||
private static bool RateMatchesEither(byte catch_rate, ushort rate)
|
||||
{
|
||||
return catch_rate == PersonalTable.RB[rate].CatchRate || catch_rate == PersonalTable.Y[rate].CatchRate;
|
||||
}
|
||||
|
||||
private static bool GetCatchRateMatchesPreEvolution(PK1 pk, byte catch_rate)
|
||||
{
|
||||
// For species catch rate, discard any species that has no valid encounters and a different catch rate than their pre-evolutions
|
||||
var head = new EvoCriteria { Species = pk.Species, Form = pk.Form, LevelMax = (byte)pk.CurrentLevel }; // as struct to avoid boxing
|
||||
while (true)
|
||||
do
|
||||
{
|
||||
var s = head.Species;
|
||||
if (!IsSpeciesNotAvailableCatchRate((byte)s))
|
||||
{
|
||||
if (catch_rate == PersonalTable.RB[s].CatchRate || catch_rate == PersonalTable.Y[s].CatchRate)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!EvolutionGroup1.Instance.TryDevolve(head, pk, head.LevelMax, 2, false, out head))
|
||||
break;
|
||||
if (!IsSpeciesNotAvailableCatchRate((byte)s) && RateMatchesEither(catch_rate, s))
|
||||
return true;
|
||||
}
|
||||
while (EvolutionGroup1.Instance.TryDevolve(head, pk, head.LevelMax, 2, false, out head));
|
||||
|
||||
// Account for oddities via special catch rate encounters
|
||||
if (catch_rate is 167 or 168 && IsStadiumGiftSpecies((byte)pk.Species))
|
||||
if (catch_rate is 167 or 168 && IsStadiumGiftSpecies((byte)head.Species))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public sealed class TrainerNameVerifier : Verifier
|
|||
|
||||
if (pk.VC)
|
||||
{
|
||||
VerifyOTG1(data);
|
||||
VerifyOTGB(data);
|
||||
}
|
||||
else if (ot.Length > Legal.GetMaxLengthOT(data.Info.Generation, (LanguageID)pk.Language))
|
||||
{
|
||||
|
@ -65,11 +65,11 @@ public sealed class TrainerNameVerifier : Verifier
|
|||
_ => true,
|
||||
};
|
||||
|
||||
public static bool IsEdgeCaseLength(PKM pk, IEncounterTemplate e, string ot)
|
||||
public static bool IsEdgeCaseLength(PKM pk, IEncounterTemplate e, ReadOnlySpan<char> ot)
|
||||
{
|
||||
if (e.EggEncounter)
|
||||
{
|
||||
if (e is WC3 wc3 && pk.IsEgg && wc3.OT_Name == ot)
|
||||
if (e is WC3 wc3 && pk.IsEgg && ot.SequenceEqual(wc3.OT_Name))
|
||||
return true; // Fixed OT Mystery Gift Egg
|
||||
bool eggEdge = pk.IsEgg ? pk.IsTradedEgg || pk.Format == 3 : pk.WasTradedEgg;
|
||||
if (!eggEdge)
|
||||
|
@ -86,11 +86,22 @@ public sealed class TrainerNameVerifier : Verifier
|
|||
return false;
|
||||
}
|
||||
|
||||
public void VerifyOTG1(LegalityAnalysis data)
|
||||
public void VerifyOTGB(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
string tr = pk.OT_Name;
|
||||
var enc = data.EncounterOriginal;
|
||||
if (pk.OT_Gender == 1)
|
||||
{
|
||||
// Transferring from RBY->Gen7 won't have OT Gender in PK1, nor will PK1 originated encounters.
|
||||
// GSC Trades already checked for OT Gender matching.
|
||||
if (pk is { Format: > 2, VC1: true } || enc is { Generation: 1 } or EncounterGift2 { IsGift: true })
|
||||
data.AddLine(GetInvalid(LG1OTGender));
|
||||
}
|
||||
|
||||
if (enc is IFixedTrainer { IsFixedTrainer: true })
|
||||
return; // already verified
|
||||
|
||||
string tr = pk.OT_Name;
|
||||
if (tr.Length == 0)
|
||||
{
|
||||
if (pk is SK2 {TID16: 0, IsRental: true})
|
||||
|
@ -103,50 +114,46 @@ public sealed class TrainerNameVerifier : Verifier
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyG1OTWithinBounds(data, tr);
|
||||
|
||||
if (pk.OT_Gender == 1)
|
||||
{
|
||||
if (pk is ICaughtData2 {CaughtData:0} or { Format: > 2, VC1: true } || data is {EncounterOriginal: {Generation:1} or EncounterGift2 {IsGift:true}})
|
||||
data.AddLine(GetInvalid(LG1OTGender));
|
||||
}
|
||||
VerifyGBOTWithinBounds(data, tr);
|
||||
}
|
||||
|
||||
private void VerifyG1OTWithinBounds(LegalityAnalysis data, ReadOnlySpan<char> str)
|
||||
private void VerifyGBOTWithinBounds(LegalityAnalysis data, ReadOnlySpan<char> str)
|
||||
{
|
||||
if (StringConverter12.GetIsG1English(str))
|
||||
{
|
||||
if (str.Length > 7 && data.EncounterOriginal is not IFixedTrainer { IsFixedTrainer: true }) // OT already verified; GER shuckle has 8 chars
|
||||
data.AddLine(GetInvalid(LOTLong));
|
||||
}
|
||||
else if (StringConverter12.GetIsG1Japanese(str))
|
||||
var pk = data.Entity;
|
||||
if (pk.Japanese)
|
||||
{
|
||||
if (str.Length > 5)
|
||||
data.AddLine(GetInvalid(LOTLong));
|
||||
if (!StringConverter12.GetIsG1Japanese(str))
|
||||
data.AddLine(GetInvalid(LG1CharOT));
|
||||
}
|
||||
else if (data.Entity.Korean && StringConverter2KOR.GetIsG2Korean(str))
|
||||
else if (pk.Korean)
|
||||
{
|
||||
if (str.Length > 5)
|
||||
data.AddLine(GetInvalid(LOTLong));
|
||||
if (!StringConverter2KOR.GetIsG2Korean(str))
|
||||
data.AddLine(GetInvalid(LG1CharOT));
|
||||
}
|
||||
else if (data.EncounterOriginal is not EncounterTrade2) // OT already verified; SPA Shuckle/Voltorb transferred from French can yield 2 inaccessible chars
|
||||
else
|
||||
{
|
||||
data.AddLine(GetInvalid(LG1CharOT));
|
||||
if (str.Length > 7)
|
||||
data.AddLine(GetInvalid(LOTLong));
|
||||
if (!StringConverter12.GetIsG1English(str))
|
||||
data.AddLine(GetInvalid(LG1CharOT));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsOTNameSuspicious(string name)
|
||||
private static bool IsOTNameSuspicious(ReadOnlySpan<char> name)
|
||||
{
|
||||
foreach (var s in SuspiciousOTNames)
|
||||
{
|
||||
if (s.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (name.StartsWith(s, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ContainsTooManyNumbers(string str, int originalGeneration)
|
||||
public static bool ContainsTooManyNumbers(ReadOnlySpan<char> str, int originalGeneration)
|
||||
{
|
||||
if (originalGeneration <= 3)
|
||||
return false; // no limit from these generations
|
||||
|
@ -157,11 +164,11 @@ public sealed class TrainerNameVerifier : Verifier
|
|||
return count > max;
|
||||
}
|
||||
|
||||
private static int GetNumberCount(string str)
|
||||
private static int GetNumberCount(ReadOnlySpan<char> str)
|
||||
{
|
||||
static bool IsNumber(char c)
|
||||
{
|
||||
if ('0' <= c)
|
||||
if (c >= '0')
|
||||
return c <= '9';
|
||||
return (uint)(c - '0') <= 9;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,16 @@ namespace PKHeX.Core;
|
|||
|
||||
public static class EntityFileExtension
|
||||
{
|
||||
// All side-game formats that don't follow the usual pk* format
|
||||
private const string ExtensionSK2 = "sk2";
|
||||
private const string ExtensionCK3 = "ck3";
|
||||
private const string ExtensionXK3 = "xk3";
|
||||
private const string ExtensionBK4 = "bk4";
|
||||
private const string ExtensionRK4 = "rk4";
|
||||
private const string ExtensionPB7 = "pb7";
|
||||
private const string ExtensionPB8 = "pb8";
|
||||
private const string ExtensionPA8 = "pa8";
|
||||
private const int CountExtra = 8;
|
||||
|
||||
public static IReadOnlyList<string> Extensions7b => new[] { ExtensionPB7 };
|
||||
|
||||
|
@ -19,20 +26,22 @@ public static class EntityFileExtension
|
|||
public static string[] GetExtensions(int maxGeneration = PKX.Generation)
|
||||
{
|
||||
int min = maxGeneration is <= 2 or >= 7 ? 1 : 3;
|
||||
int size = maxGeneration - min + 1 + 6;
|
||||
int size = maxGeneration - min + 1 + CountExtra;
|
||||
var result = new List<string>(size);
|
||||
for (int i = min; i <= maxGeneration; i++)
|
||||
result.Add($"pk{i}");
|
||||
if (min < 3)
|
||||
result.Add(ExtensionSK2); // stadium
|
||||
|
||||
if (maxGeneration >= 3)
|
||||
{
|
||||
result.Add("ck3"); // colosseum
|
||||
result.Add("xk3"); // xd
|
||||
result.Add(ExtensionCK3); // colosseum
|
||||
result.Add(ExtensionXK3); // xd
|
||||
}
|
||||
if (maxGeneration >= 4)
|
||||
{
|
||||
result.Add("bk4"); // battle revolution
|
||||
result.Add("rk4"); // My Pokemon Ranch
|
||||
result.Add(ExtensionBK4); // battle revolution
|
||||
result.Add(ExtensionRK4); // My Pokemon Ranch
|
||||
}
|
||||
if (maxGeneration >= 7)
|
||||
result.Add(ExtensionPB7); // let's go
|
||||
|
@ -56,6 +65,7 @@ public static class EntityFileExtension
|
|||
return prefer;
|
||||
|
||||
static bool Is(ReadOnlySpan<char> ext, ReadOnlySpan<char> str) => ext.EndsWith(str, StringComparison.InvariantCultureIgnoreCase);
|
||||
if (Is(ext, "a8")) return EntityContext.Gen8a;
|
||||
if (Is(ext, "b8")) return EntityContext.Gen8b;
|
||||
if (Is(ext, "k8")) return EntityContext.Gen8;
|
||||
if (Is(ext, "b7")) return EntityContext.Gen7b;
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace PKHeX.Core;
|
|||
|
||||
public sealed class BV6 : BattleVideo
|
||||
{
|
||||
internal const int SIZE = 0x2E60;
|
||||
public const int SIZE = 0x2E60;
|
||||
private const string NPC = "NPC";
|
||||
private readonly byte[] Data;
|
||||
private const int PlayerCount = 4;
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace PKHeX.Core;
|
|||
|
||||
public sealed class BV7 : BattleVideo
|
||||
{
|
||||
internal const int SIZE = 0x2BC0;
|
||||
public const int SIZE = 0x2BC0;
|
||||
private const string NPC = "NPC";
|
||||
private const int PlayerCount = 4;
|
||||
|
||||
|
|
|
@ -11,20 +11,7 @@ public sealed class SaveHandlerDeSmuME : ISaveHandler
|
|||
private const int RealSize = SaveUtil.SIZE_G4RAW;
|
||||
private const int ExpectedSize = RealSize + sizeFooter;
|
||||
|
||||
private const string SignatureDSV = "|-DESMUME SAVE-|";
|
||||
|
||||
private static bool GetHasFooter(ReadOnlySpan<byte> input)
|
||||
{
|
||||
var start = input.Length - SignatureDSV.Length;
|
||||
var footer = input[start..];
|
||||
for (int i = SignatureDSV.Length - 1; i >= 0; i--)
|
||||
{
|
||||
byte c = (byte)SignatureDSV[i];
|
||||
if (footer[i] != c)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private static bool GetHasFooter(ReadOnlySpan<byte> input) => input.EndsWith("|-DESMUME SAVE-|"u8);
|
||||
|
||||
public bool IsRecognized(long size) => size is ExpectedSize;
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ public static class SaveExtensions
|
|||
/// <returns>Template if it exists, or a blank <see cref="PKM"/> from the <see cref="sav"/></returns>
|
||||
public static PKM LoadTemplate(this SaveFile sav, string? templatePath = null)
|
||||
{
|
||||
if (templatePath == null || !Directory.Exists(templatePath))
|
||||
if (!Directory.Exists(templatePath))
|
||||
return LoadTemplateInternal(sav);
|
||||
|
||||
var di = new DirectoryInfo(templatePath);
|
||||
|
|
Loading…
Reference in a new issue