mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-22 12:03:10 +00:00
Minor clean
indexof -> contains trailing space some variable reuse pcdata/boxdata less janky handling
This commit is contained in:
parent
40353c7922
commit
0f4024952e
34 changed files with 190 additions and 150 deletions
|
@ -158,61 +158,66 @@ public static class CommonEdits
|
|||
/// Copies <see cref="IBattleTemplate"/> details to the <see cref="PKM"/>.
|
||||
/// </summary>
|
||||
/// <param name="pk">Pokémon to modify.</param>
|
||||
/// <param name="Set"><see cref="IBattleTemplate"/> details to copy from.</param>
|
||||
public static void ApplySetDetails(this PKM pk, IBattleTemplate Set)
|
||||
/// <param name="set"><see cref="IBattleTemplate"/> details to copy from.</param>
|
||||
public static void ApplySetDetails(this PKM pk, IBattleTemplate set)
|
||||
{
|
||||
pk.Species = Math.Min(pk.MaxSpeciesID, Set.Species);
|
||||
pk.Form = Set.Form;
|
||||
if (Set.Moves[0] != 0)
|
||||
pk.SetMoves(Set.Moves, true);
|
||||
pk.ApplyHeldItem(Set.HeldItem, Set.Context);
|
||||
pk.CurrentLevel = Set.Level;
|
||||
pk.CurrentFriendship = Set.Friendship;
|
||||
pk.SetIVs(Set.IVs);
|
||||
pk.Species = Math.Min(pk.MaxSpeciesID, set.Species);
|
||||
pk.Form = set.Form;
|
||||
|
||||
ReadOnlySpan<ushort> moves = set.Moves;
|
||||
if (moves[0] != 0)
|
||||
pk.SetMoves(moves, true);
|
||||
if (Legal.IsPPUpAvailable(pk))
|
||||
pk.SetMaximumPPUps(moves);
|
||||
|
||||
pk.ApplyHeldItem(set.HeldItem, set.Context);
|
||||
pk.CurrentLevel = set.Level;
|
||||
pk.CurrentFriendship = set.Friendship;
|
||||
|
||||
ReadOnlySpan<int> ivs = set.IVs;
|
||||
ReadOnlySpan<int> evs = set.EVs;
|
||||
pk.SetIVs(ivs);
|
||||
|
||||
if (pk is GBPKM gb)
|
||||
{
|
||||
// In Generation 1/2 Format sets, when IVs are not specified with a Hidden Power set, we might not have the hidden power type.
|
||||
// Under this scenario, just force the Hidden Power type.
|
||||
if (Array.IndexOf(Set.Moves, (ushort)Move.HiddenPower) != -1 && gb.HPType != Set.HiddenPowerType)
|
||||
if (moves.Contains((ushort)Move.HiddenPower) && gb.HPType != set.HiddenPowerType)
|
||||
{
|
||||
if (Set.IVs.AsSpan().ContainsAny(30, 31))
|
||||
gb.SetHiddenPower(Set.HiddenPowerType);
|
||||
if (ivs.ContainsAny(30, 31))
|
||||
gb.SetHiddenPower(set.HiddenPowerType);
|
||||
}
|
||||
|
||||
// In Generation 1/2 Format sets, when EVs are not specified at all, it implies maximum EVs instead!
|
||||
// Under this scenario, just apply maximum EVs (65535).
|
||||
if (!Set.EVs.AsSpan().ContainsAnyExcept(0))
|
||||
if (!evs.ContainsAnyExcept(0))
|
||||
gb.MaxEVs();
|
||||
else
|
||||
gb.SetEVs(Set.EVs);
|
||||
gb.SetEVs(evs);
|
||||
}
|
||||
else
|
||||
{
|
||||
pk.SetEVs(Set.EVs);
|
||||
pk.SetEVs(evs);
|
||||
}
|
||||
|
||||
// IVs have no side effects such as hidden power type in gen 8
|
||||
// therefore all specified IVs are deliberate and should not be Hyper Trained for Pokémon met in gen 8
|
||||
if (pk.Generation < 8)
|
||||
pk.SetSuggestedHyperTrainingData(Set.IVs);
|
||||
pk.SetSuggestedHyperTrainingData(ivs);
|
||||
|
||||
if (ShowdownSetIVMarkings)
|
||||
pk.SetMarkings();
|
||||
|
||||
pk.SetNickname(Set.Nickname);
|
||||
pk.SetSaneGender(Set.Gender);
|
||||
|
||||
if (Legal.IsPPUpAvailable(pk))
|
||||
pk.SetMaximumPPUps(Set.Moves);
|
||||
pk.SetNickname(set.Nickname);
|
||||
pk.SetSaneGender(set.Gender);
|
||||
|
||||
if (pk.Format >= 3)
|
||||
{
|
||||
pk.SetAbility(Set.Ability);
|
||||
pk.SetNature(Set.Nature);
|
||||
pk.SetAbility(set.Ability);
|
||||
pk.SetNature(set.Nature);
|
||||
}
|
||||
|
||||
pk.SetIsShiny(Set.Shiny);
|
||||
pk.SetIsShiny(set.Shiny);
|
||||
pk.SetRandomEC();
|
||||
|
||||
if (pk is IAwakened a)
|
||||
|
@ -229,17 +234,17 @@ public static class CommonEdits
|
|||
g.SetSuggestedGanbaruValues(pk);
|
||||
|
||||
if (pk is IGigantamax c)
|
||||
c.CanGigantamax = Set.CanGigantamax;
|
||||
c.CanGigantamax = set.CanGigantamax;
|
||||
if (pk is IDynamaxLevel d)
|
||||
d.DynamaxLevel = d.GetSuggestedDynamaxLevel(pk, requested: Set.DynamaxLevel);
|
||||
d.DynamaxLevel = d.GetSuggestedDynamaxLevel(pk, requested: set.DynamaxLevel);
|
||||
if (pk is ITeraType tera)
|
||||
{
|
||||
var type = Set.TeraType == MoveType.Any ? (MoveType)pk.PersonalInfo.Type1 : Set.TeraType;
|
||||
var type = set.TeraType == MoveType.Any ? (MoveType)pk.PersonalInfo.Type1 : set.TeraType;
|
||||
tera.SetTeraType(type);
|
||||
}
|
||||
|
||||
if (pk is IMoveShop8Mastery s)
|
||||
s.SetMoveShopFlags(Set.Moves, pk);
|
||||
s.SetMoveShopFlags(set.Moves, pk);
|
||||
|
||||
if (ShowdownSetBehaviorNature && pk.Format >= 8)
|
||||
pk.Nature = pk.StatNature;
|
||||
|
@ -248,7 +253,7 @@ public static class CommonEdits
|
|||
if (pk is ITechRecord t)
|
||||
{
|
||||
t.ClearRecordFlags();
|
||||
t.SetRecordFlags(Set.Moves, legal.Info.EvoChainsAllGens.Get(pk.Context));
|
||||
t.SetRecordFlags(set.Moves, legal.Info.EvoChainsAllGens.Get(pk.Context));
|
||||
}
|
||||
if (legal.Parsed && !MoveResult.AllValid(legal.Info.Relearn))
|
||||
pk.SetRelearnMoves(legal);
|
||||
|
|
|
@ -212,16 +212,17 @@ public sealed class ShowdownSet : IBattleTemplate
|
|||
|
||||
private bool ParseLine(ReadOnlySpan<char> line, ref int movectr)
|
||||
{
|
||||
var moves = Moves.AsSpan();
|
||||
if (line[0] is '-' or '–')
|
||||
{
|
||||
var moveString = ParseLineMove(line);
|
||||
int move = StringUtil.FindIndexIgnoreCase(Strings.movelist, moveString);
|
||||
if (move < 0)
|
||||
InvalidLines.Add($"Unknown Move: {moveString}");
|
||||
else if (Array.IndexOf(Moves, (ushort)move) != -1)
|
||||
else if (moves.Contains((ushort)move))
|
||||
InvalidLines.Add($"Duplicate Move: {moveString}");
|
||||
else
|
||||
Moves[movectr++] = (ushort)move;
|
||||
moves[movectr++] = (ushort)move;
|
||||
|
||||
return movectr == MaxMoveCount;
|
||||
}
|
||||
|
@ -507,7 +508,12 @@ public sealed class ShowdownSet : IBattleTemplate
|
|||
Ability = pk.Ability;
|
||||
pk.GetEVs(EVs);
|
||||
pk.GetIVs(IVs);
|
||||
pk.GetMoves(Moves);
|
||||
|
||||
var moves = Moves.AsSpan();
|
||||
pk.GetMoves(moves);
|
||||
if (moves.Contains((ushort)Move.HiddenPower))
|
||||
HiddenPowerType = HiddenPower.GetType(IVs, Context);
|
||||
|
||||
Nature = pk.StatNature;
|
||||
Gender = pk.Gender < 2 ? pk.Gender : (byte)2;
|
||||
Friendship = pk.CurrentFriendship;
|
||||
|
@ -520,8 +526,6 @@ public sealed class ShowdownSet : IBattleTemplate
|
|||
DynamaxLevel = g.DynamaxLevel;
|
||||
}
|
||||
|
||||
if (Array.IndexOf(Moves, (ushort)Move.HiddenPower) != -1)
|
||||
HiddenPowerType = HiddenPower.GetType(IVs, Context);
|
||||
if (pk is ITeraType t)
|
||||
TeraType = t.TeraType;
|
||||
if (pk is IHyperTrain h)
|
||||
|
|
|
@ -25,10 +25,7 @@ public sealed record EncounterArea8a : IEncounterArea<EncounterSlot8a>, IAreaLoc
|
|||
|
||||
public ushort Location => Locations[0];
|
||||
|
||||
public bool IsMatchLocation(ushort location)
|
||||
{
|
||||
return Array.IndexOf(Locations, (byte)location) != -1;
|
||||
}
|
||||
public bool IsMatchLocation(ushort location) => Locations.AsSpan().Contains((byte)location);
|
||||
|
||||
public static EncounterArea8a[] GetAreas(BinLinkerAccessor input)
|
||||
{
|
||||
|
|
|
@ -86,7 +86,7 @@ public sealed class LearnSource8BDSP : ILearnSource<PersonalInfo8BDSP>, IEggSour
|
|||
{
|
||||
var baseSpecies = pi.HatchSpecies;
|
||||
var baseForm = pi.HatchFormIndex;
|
||||
return GetEggMoves(baseSpecies, baseForm).IndexOf(move) != -1;
|
||||
return GetEggMoves(baseSpecies, baseForm).Contains(move);
|
||||
}
|
||||
|
||||
public void GetAllMoves(Span<bool> result, PKM pk, EvoCriteria evo, MoveSourceType types = MoveSourceType.All)
|
||||
|
|
|
@ -98,7 +98,7 @@ public sealed class LearnSource8SWSH : ILearnSource<PersonalInfo8SWSH>, IEggSour
|
|||
{
|
||||
var baseSpecies = pi.HatchSpecies;
|
||||
var baseForm = pi.HatchFormIndexEverstone;
|
||||
return GetEggMoves(baseSpecies, baseForm).IndexOf(move) != -1;
|
||||
return GetEggMoves(baseSpecies, baseForm).Contains(move);
|
||||
}
|
||||
|
||||
private static bool GetIsTR(PersonalInfo8SWSH info, PKM pk, EvoCriteria evo, ushort move, LearnOption option)
|
||||
|
|
|
@ -35,7 +35,7 @@ public sealed class LearnSource9SV : ILearnSource<PersonalInfo9SV>, IEggSource,
|
|||
if (index >= EggMoves.Length)
|
||||
return false;
|
||||
var moves = EggMoves[index].AsSpan();
|
||||
return moves.IndexOf(move) != -1;
|
||||
return moves.Contains(move);
|
||||
}
|
||||
|
||||
public ReadOnlySpan<ushort> GetEggMoves(ushort species, byte form)
|
||||
|
@ -52,7 +52,7 @@ public sealed class LearnSource9SV : ILearnSource<PersonalInfo9SV>, IEggSource,
|
|||
if (index >= Reminder.Length)
|
||||
return false;
|
||||
var moves = Reminder[index].AsSpan();
|
||||
return moves.IndexOf(move) != -1;
|
||||
return moves.Contains(move);
|
||||
}
|
||||
|
||||
public ReadOnlySpan<ushort> GetReminderMoves(ushort species, byte form)
|
||||
|
@ -146,7 +146,7 @@ public sealed class LearnSource9SV : ILearnSource<PersonalInfo9SV>, IEggSource,
|
|||
{
|
||||
var baseSpecies = pi.HatchSpecies;
|
||||
var baseForm = pi.HatchFormIndexEverstone;
|
||||
return GetEggMoves(baseSpecies, baseForm).IndexOf(move) != -1;
|
||||
return GetEggMoves(baseSpecies, baseForm).Contains(move);
|
||||
}
|
||||
|
||||
public void GetAllMoves(Span<bool> result, PKM pk, EvoCriteria evo, MoveSourceType types = MoveSourceType.All)
|
||||
|
|
|
@ -187,7 +187,7 @@ public sealed class Learnset(ushort[] Moves, byte[] Levels)
|
|||
for (int i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
var move = Moves[i];
|
||||
if (ignore.IndexOf(move) >= 0)
|
||||
if (ignore.Contains(move))
|
||||
continue;
|
||||
|
||||
AddMoveShiftLater(moves, ref ctr, move);
|
||||
|
@ -207,7 +207,7 @@ public sealed class Learnset(ushort[] Moves, byte[] Levels)
|
|||
break;
|
||||
|
||||
var move = Moves[i];
|
||||
if (ignore.IndexOf(move) >= 0)
|
||||
if (ignore.Contains(move))
|
||||
continue;
|
||||
|
||||
AddMoveShiftLater(moves, ref ctr, move);
|
||||
|
|
|
@ -161,7 +161,7 @@ public static class MoveBreed2
|
|||
if (move > Legal.MaxMoveID_2) // byte
|
||||
continue;
|
||||
|
||||
if (baseEgg.IndexOf(move) != -1)
|
||||
if (baseEgg.Contains(move))
|
||||
possible[i] |= 1 << (int)Base;
|
||||
|
||||
if (inheritLevelUp && learn.GetIsLearn(move))
|
||||
|
|
|
@ -162,7 +162,7 @@ public static class MoveBreed3
|
|||
{
|
||||
var move = moves[i];
|
||||
|
||||
if (baseEgg.IndexOf(move) != -1)
|
||||
if (baseEgg.Contains(move))
|
||||
possible[i] |= 1 << (int)Base;
|
||||
|
||||
if (inheritLevelUp && learn.GetIsLearn(move))
|
||||
|
|
|
@ -165,7 +165,7 @@ public static class MoveBreed4
|
|||
{
|
||||
var move = moves[i];
|
||||
|
||||
if (baseEgg.IndexOf(move) != -1)
|
||||
if (baseEgg.Contains(move))
|
||||
possible[i] |= 1 << (int)Base;
|
||||
|
||||
if (inheritLevelUp && learn.GetIsLearn(move))
|
||||
|
|
|
@ -157,7 +157,7 @@ public static class MoveBreed5
|
|||
{
|
||||
var move = moves[i];
|
||||
|
||||
if (baseEgg.IndexOf(move) != -1)
|
||||
if (baseEgg.Contains(move))
|
||||
possible[i] |= 1 << (int)Base;
|
||||
|
||||
if (inheritLevelUp && learn.GetIsLearn(move))
|
||||
|
|
|
@ -149,7 +149,7 @@ public static class MoveBreed6
|
|||
{
|
||||
var move = moves[i];
|
||||
|
||||
if (baseEgg.IndexOf(move) != -1)
|
||||
if (baseEgg.Contains(move))
|
||||
possible[i] |= 1 << (int)Base;
|
||||
|
||||
if (inheritLevelUp && learn.GetIsLearn(move))
|
||||
|
|
|
@ -295,16 +295,16 @@ public static class XDRNG
|
|||
}
|
||||
return ctr;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Multiplication constants for jumping 2^(index) frames forward.
|
||||
/// </summary>
|
||||
private static ReadOnlySpan<uint> JumpMult =>
|
||||
[
|
||||
0x000343FD, 0xA9FC6809, 0xDDFF5051, 0xF490B9A1, 0x43BA1741, 0xD290BE81, 0x82E3BD01, 0xBF507A01,
|
||||
0xF8C4F401, 0x7A19E801, 0x1673D001, 0xB5E7A001, 0x8FCF4001, 0xAF9E8001, 0x9F3D0001, 0x3E7A0001,
|
||||
0x7CF40001, 0xF9E80001, 0xF3D00001, 0xE7A00001, 0xCF400001, 0x9E800001, 0x3D000001, 0x7A000001,
|
||||
0xF4000001, 0xE8000001, 0xD0000001, 0xA0000001, 0x40000001, 0x80000001, 0x00000001, 0x00000001,
|
||||
0x000343FD, 0xA9FC6809, 0xDDFF5051, 0xF490B9A1, 0x43BA1741, 0xD290BE81, 0x82E3BD01, 0xBF507A01,
|
||||
0xF8C4F401, 0x7A19E801, 0x1673D001, 0xB5E7A001, 0x8FCF4001, 0xAF9E8001, 0x9F3D0001, 0x3E7A0001,
|
||||
0x7CF40001, 0xF9E80001, 0xF3D00001, 0xE7A00001, 0xCF400001, 0x9E800001, 0x3D000001, 0x7A000001,
|
||||
0xF4000001, 0xE8000001, 0xD0000001, 0xA0000001, 0x40000001, 0x80000001, 0x00000001, 0x00000001,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace PKHeX.Core;
|
|||
public sealed class EffortValueVerifier : Verifier
|
||||
{
|
||||
protected override CheckIdentifier Identifier => CheckIdentifier.EVs;
|
||||
|
||||
|
||||
public override void Verify(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
|
@ -32,7 +32,8 @@ public sealed class EffortValueVerifier : Verifier
|
|||
var enc = data.EncounterMatch;
|
||||
Span<int> evs = stackalloc int[6];
|
||||
pk.GetEVs(evs);
|
||||
if (format >= 6 && evs.ContainsAny(253, 254, 255))
|
||||
|
||||
if (format >= 6 && IsAnyAboveHardLimit6(evs))
|
||||
data.AddLine(GetInvalid(LEffortAbove252));
|
||||
else if (format < 5) // 3/4
|
||||
VerifyGainedEVs34(data, enc, evs, pk);
|
||||
|
@ -46,9 +47,9 @@ public sealed class EffortValueVerifier : Verifier
|
|||
data.AddLine(Get(LEffortAllEqual, Severity.Fishy));
|
||||
}
|
||||
|
||||
private void VerifyGainedEVs34(LegalityAnalysis data, IEncounterTemplate enc, Span<int> evs, PKM pk)
|
||||
private void VerifyGainedEVs34(LegalityAnalysis data, IEncounterTemplate enc, ReadOnlySpan<int> evs, PKM pk)
|
||||
{
|
||||
bool anyAbove100 = evs.Find(static ev => ev > EffortValues.MaxVitamins34) != default;
|
||||
bool anyAbove100 = IsAnyAboveVitaminLimit(evs);
|
||||
if (!anyAbove100)
|
||||
return;
|
||||
|
||||
|
@ -66,4 +67,18 @@ public sealed class EffortValueVerifier : Verifier
|
|||
data.AddLine(GetInvalid(string.Format(LEffortUntrainedCap, EffortValues.MaxVitamins34)));
|
||||
}
|
||||
}
|
||||
|
||||
// Hard cap at 252 for Gen6+
|
||||
private static bool IsAnyAboveHardLimit6(ReadOnlySpan<int> evs) => evs.ContainsAny(253, 254, 255);
|
||||
|
||||
// Vitamins can only raise to 100 in Gen3/4
|
||||
private static bool IsAnyAboveVitaminLimit(ReadOnlySpan<int> evs)
|
||||
{
|
||||
foreach (var iv in evs)
|
||||
{
|
||||
if (iv > EffortValues.MaxVitamins34)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,8 @@ public sealed class IndividualValueVerifier : Verifier
|
|||
|
||||
Span<int> IVs = stackalloc int[6];
|
||||
g.GetIVs(IVs);
|
||||
var ivflag = IVs.Find(static iv => (byte)(iv - 0xFC) < 3);
|
||||
if (ivflag == default) // Random IVs
|
||||
var ivflag = IVs.IndexOfAny(0xFC, 0xFD, 0xFE);
|
||||
if (ivflag == -1) // Random IVs
|
||||
{
|
||||
bool valid = Legal.GetIsFixedIVSequenceValidSkipRand(IVs, data.Entity);
|
||||
if (!valid)
|
||||
|
@ -55,7 +55,7 @@ public sealed class IndividualValueVerifier : Verifier
|
|||
}
|
||||
else
|
||||
{
|
||||
int IVCount = ivflag - 0xFB; // IV2/IV3
|
||||
int IVCount = IVs[ivflag] - 0xFB; // IV2/IV3
|
||||
VerifyIVsFlawless(data, IVCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ public sealed class LegendsArceusVerifier : Verifier
|
|||
if (!mustKnow && currentLearn.GetLevelLearnMove(move) != level)
|
||||
continue;
|
||||
|
||||
if (current.IndexOf(move) == -1)
|
||||
if (!current.Contains(move))
|
||||
current[ctr++] = move;
|
||||
if (ctr == 4)
|
||||
return 4;
|
||||
|
|
|
@ -598,9 +598,9 @@ public sealed class WA8(byte[] Data) : DataMysteryGift(Data), ILangNick, INature
|
|||
{
|
||||
Span<int> finalIVs = stackalloc int[6];
|
||||
GetIVs(finalIVs);
|
||||
var ivflag = finalIVs.Find(static iv => (byte)(iv - 0xFC) < 3);
|
||||
var ivflag = finalIVs.IndexOfAny(0xFC, 0xFD, 0xFE);
|
||||
var rng = Util.Rand;
|
||||
if (ivflag == default) // Random IVs
|
||||
if (ivflag == -1) // Random IVs
|
||||
{
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
{
|
||||
|
@ -610,7 +610,7 @@ public sealed class WA8(byte[] Data) : DataMysteryGift(Data), ILangNick, INature
|
|||
}
|
||||
else // 1/2/3 perfect IVs
|
||||
{
|
||||
int IVCount = ivflag - 0xFB;
|
||||
int IVCount = finalIVs[ivflag] - 0xFB;
|
||||
do { finalIVs[rng.Next(6)] = 31; }
|
||||
while (finalIVs.Count(31) < IVCount);
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
|
|
|
@ -498,9 +498,9 @@ public sealed class WB7(byte[] Data)
|
|||
{
|
||||
Span<int> finalIVs = stackalloc int[6];
|
||||
GetIVs(finalIVs);
|
||||
var ivflag = finalIVs.Find(static iv => (byte)(iv - 0xFC) < 3);
|
||||
var ivflag = finalIVs.IndexOfAny(0xFC, 0xFD, 0xFE);
|
||||
var rng = Util.Rand;
|
||||
if (ivflag == default) // Random IVs
|
||||
if (ivflag == -1) // Random IVs
|
||||
{
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
{
|
||||
|
@ -510,7 +510,7 @@ public sealed class WB7(byte[] Data)
|
|||
}
|
||||
else // 1/2/3 perfect IVs
|
||||
{
|
||||
int IVCount = ivflag - 0xFB;
|
||||
int IVCount = finalIVs[ivflag] - 0xFB;
|
||||
do { finalIVs[rng.Next(6)] = 31; }
|
||||
while (finalIVs.Count(31) < IVCount);
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
|
|
|
@ -592,9 +592,9 @@ public sealed class WB8(byte[] Data) : DataMysteryGift(Data),
|
|||
{
|
||||
Span<int> finalIVs = stackalloc int[6];
|
||||
GetIVs(finalIVs);
|
||||
var ivflag = finalIVs.Find(static iv => (byte)(iv - 0xFC) < 3);
|
||||
var ivflag = finalIVs.IndexOfAny(0xFC, 0xFD, 0xFE);
|
||||
var rng = Util.Rand;
|
||||
if (ivflag == default) // Random IVs
|
||||
if (ivflag == -1) // Random IVs
|
||||
{
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
{
|
||||
|
@ -604,7 +604,7 @@ public sealed class WB8(byte[] Data) : DataMysteryGift(Data),
|
|||
}
|
||||
else // 1/2/3 perfect IVs
|
||||
{
|
||||
int IVCount = ivflag - 0xFB;
|
||||
int IVCount = finalIVs[ivflag] - 0xFB;
|
||||
do { finalIVs[rng.Next(6)] = 31; }
|
||||
while (finalIVs.Count(31) < IVCount);
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
|
|
|
@ -493,9 +493,9 @@ public sealed class WC6(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
{
|
||||
Span<int> finalIVs = stackalloc int[6];
|
||||
GetIVs(finalIVs);
|
||||
var ivflag = finalIVs.Find(static iv => (byte)(iv - 0xFC) < 3);
|
||||
var ivflag = finalIVs.IndexOfAny(0xFC, 0xFD, 0xFE);
|
||||
var rng = Util.Rand;
|
||||
if (ivflag == default) // Random IVs
|
||||
if (ivflag == -1) // Random IVs
|
||||
{
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
{
|
||||
|
@ -505,7 +505,7 @@ public sealed class WC6(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
}
|
||||
else // 1/2/3 perfect IVs
|
||||
{
|
||||
int IVCount = ivflag - 0xFB;
|
||||
int IVCount = finalIVs[ivflag] - 0xFB;
|
||||
do { finalIVs[rng.Next(6)] = 31; }
|
||||
while (finalIVs.Count(31) < IVCount);
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
|
|
|
@ -533,9 +533,9 @@ public sealed class WC7(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
{
|
||||
Span<int> finalIVs = stackalloc int[6];
|
||||
GetIVs(finalIVs);
|
||||
var ivflag = finalIVs.Find(static iv => (byte)(iv - 0xFC) < 3);
|
||||
var ivflag = finalIVs.IndexOfAny(0xFC, 0xFD, 0xFE);
|
||||
var rng = Util.Rand;
|
||||
if (ivflag == default) // Random IVs
|
||||
if (ivflag == -1) // Random IVs
|
||||
{
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
{
|
||||
|
@ -545,7 +545,7 @@ public sealed class WC7(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
}
|
||||
else // 1/2/3 perfect IVs
|
||||
{
|
||||
int IVCount = ivflag - 0xFB;
|
||||
int IVCount = finalIVs[ivflag] - 0xFB;
|
||||
do { finalIVs[rng.Next(6)] = 31; }
|
||||
while (finalIVs.Count(31) < IVCount);
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
|
|
|
@ -616,9 +616,9 @@ public sealed class WC8(byte[] Data) : DataMysteryGift(Data), ILangNick, INature
|
|||
{
|
||||
Span<int> finalIVs = stackalloc int[6];
|
||||
GetIVs(finalIVs);
|
||||
var ivflag = finalIVs.Find(static iv => (byte)(iv - 0xFC) < 3);
|
||||
var ivflag = finalIVs.IndexOfAny(0xFC, 0xFD, 0xFE);
|
||||
var rng = Util.Rand;
|
||||
if (ivflag == default) // Random IVs
|
||||
if (ivflag == -1) // Random IVs
|
||||
{
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
{
|
||||
|
@ -628,7 +628,7 @@ public sealed class WC8(byte[] Data) : DataMysteryGift(Data), ILangNick, INature
|
|||
}
|
||||
else // 1/2/3 perfect IVs
|
||||
{
|
||||
int IVCount = ivflag - 0xFB;
|
||||
int IVCount = finalIVs[ivflag] - 0xFB;
|
||||
do { finalIVs[rng.Next(6)] = 31; }
|
||||
while (finalIVs.Count(31) < IVCount);
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
|
|
|
@ -643,9 +643,9 @@ public sealed class WC9(byte[] Data) : DataMysteryGift(Data), ILangNick, INature
|
|||
{
|
||||
Span<int> finalIVs = stackalloc int[6];
|
||||
GetIVs(finalIVs);
|
||||
var ivflag = finalIVs.Find(static iv => (byte)(iv - 0xFC) < 3);
|
||||
var ivflag = finalIVs.IndexOfAny(0xFC, 0xFD, 0xFE);
|
||||
var rng = Util.Rand;
|
||||
if (ivflag == default) // Random IVs
|
||||
if (ivflag == -1) // Random IVs
|
||||
{
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
{
|
||||
|
@ -655,7 +655,7 @@ public sealed class WC9(byte[] Data) : DataMysteryGift(Data), ILangNick, INature
|
|||
}
|
||||
else // 1/2/3 perfect IVs
|
||||
{
|
||||
int IVCount = ivflag - 0xFB;
|
||||
int IVCount = finalIVs[ivflag] - 0xFB;
|
||||
do { finalIVs[rng.Next(6)] = 31; }
|
||||
while (finalIVs.Count(31) < IVCount);
|
||||
for (int i = 0; i < finalIVs.Length; i++)
|
||||
|
|
|
@ -12,7 +12,7 @@ public static class StringFont8b
|
|||
// BD/SP: StreamingAssets/AssetAssistant/Dpr/font
|
||||
// S/V: arc/appli/font/bin
|
||||
// For KOR/CHS/CHT, BD/SP uses a bundled copy of the Switch system font
|
||||
|
||||
|
||||
public static ReadOnlySpan<char> DefinedLiberationSans =>
|
||||
[
|
||||
'\u0020', '\u0021', '\u0022', '\u0023', '\u0024', '\u0025', '\u0026', '\u0027', '\u0028', '\u0029', '\u002A', '\u002B', '\u002C', '\u002D', '\u002E', '\u002F',
|
||||
|
|
|
@ -498,13 +498,17 @@ public abstract class SaveFile : ITrainerInfo, IGameValueLimit, IGeneration, IVe
|
|||
|
||||
private bool IsRegionOverwriteProtected(int min, int max)
|
||||
{
|
||||
foreach (var arrays in SlotPointers)
|
||||
var ptrs = SlotPointers;
|
||||
if (ptrs.Length == 0)
|
||||
return false;
|
||||
|
||||
foreach (var arrays in ptrs)
|
||||
{
|
||||
foreach (int slotIndex in arrays)
|
||||
{
|
||||
if (!GetSlotFlags(slotIndex).IsOverwriteProtected())
|
||||
continue;
|
||||
if (ArrayUtil.WithinRange(slotIndex, min, max))
|
||||
if (min <= slotIndex && slotIndex < max)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -514,13 +518,20 @@ public abstract class SaveFile : ITrainerInfo, IGameValueLimit, IGeneration, IVe
|
|||
|
||||
public bool IsAnySlotLockedInBox(int BoxStart, int BoxEnd)
|
||||
{
|
||||
foreach (var arrays in SlotPointers)
|
||||
var ptrs = SlotPointers;
|
||||
if (ptrs.Length == 0)
|
||||
return false;
|
||||
|
||||
var min = BoxStart * BoxSlotCount;
|
||||
var max = (BoxEnd + 1) * BoxSlotCount;
|
||||
|
||||
foreach (var arrays in ptrs)
|
||||
{
|
||||
foreach (int slotIndex in arrays)
|
||||
{
|
||||
if (!GetSlotFlags(slotIndex).HasFlag(StorageSlotSource.Locked))
|
||||
continue;
|
||||
if (ArrayUtil.WithinRange(slotIndex, BoxStart * BoxSlotCount, (BoxEnd + 1) * BoxSlotCount))
|
||||
if (min <= slotIndex && slotIndex < max)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public sealed class MyItem6XY(SAV6XY SAV, Memory<byte> raw) : MyItem(SAV, raw)
|
||||
public sealed class MyItem6XY(SAV6XY SAV, Memory<byte> raw) : MyItem(SAV, raw)
|
||||
{
|
||||
private const int HeldItem = 0; // 0
|
||||
private const int KeyItem = 0x640; // 1
|
||||
|
|
|
@ -56,7 +56,7 @@ public sealed class SevenStarRaidDetail(SevenStarRaidCapturedDetail captured, Se
|
|||
defeated.Defeated = value;
|
||||
else
|
||||
captured.Defeated = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ public sealed class Epoch0000DateTime(Memory<byte> Data): EpochDateTime(Data)
|
|||
|
||||
public override int Year { get => RawYear; set => RawYear = value; }
|
||||
public override int Month { get => RawMonth; set => RawMonth = value; }
|
||||
|
||||
|
||||
public override DateTime Timestamp
|
||||
{
|
||||
get => new(Year, Month, Day, Hour, Minute, 0);
|
||||
|
|
|
@ -40,14 +40,14 @@ public static class DexFormUtil
|
|||
|
||||
private static ReadOnlySpan<ushort> DexSpeciesWithForm_SM =>
|
||||
[
|
||||
003, 006, 009, 015, 018, 019, 020, 025, 026, 027, 028, 037, 038, 050, 051, 052,
|
||||
053, 065, 074, 075, 076, 080, 088, 089, 094, 103, 105, 115, 127, 130, 142, 150,
|
||||
181, 201, 208, 212, 214, 229, 248, 254, 257, 260, 282, 302, 303, 306, 308, 310,
|
||||
319, 323, 334, 351, 354, 359, 362, 373, 376, 380, 381, 382, 383, 384, 386, 412,
|
||||
413, 421, 422, 423, 428, 445, 448, 460, 475, 479, 487, 492, 493, 531, 550, 555,
|
||||
585, 586, 641, 642, 645, 646, 647, 648, 649, 658, 666, 669, 670, 671, 676, 678,
|
||||
681, 710, 711, 716, 718, 719, 720, 735, 738, 741, 745, 746, 754, 758, 773, 774,
|
||||
778, 784, 801,
|
||||
003, 006, 009, 015, 018, 019, 020, 025, 026, 027, 028, 037, 038, 050, 051, 052,
|
||||
053, 065, 074, 075, 076, 080, 088, 089, 094, 103, 105, 115, 127, 130, 142, 150,
|
||||
181, 201, 208, 212, 214, 229, 248, 254, 257, 260, 282, 302, 303, 306, 308, 310,
|
||||
319, 323, 334, 351, 354, 359, 362, 373, 376, 380, 381, 382, 383, 384, 386, 412,
|
||||
413, 421, 422, 423, 428, 445, 448, 460, 475, 479, 487, 492, 493, 531, 550, 555,
|
||||
585, 586, 641, 642, 645, 646, 647, 648, 649, 658, 666, 669, 670, 671, 676, 678,
|
||||
681, 710, 711, 716, 718, 719, 720, 735, 738, 741, 745, 746, 754, 758, 773, 774,
|
||||
778, 784, 801,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> DexSpeciesCount_SM =>
|
||||
|
@ -64,14 +64,14 @@ public static class DexFormUtil
|
|||
|
||||
private static ReadOnlySpan<ushort> DexSpeciesWithForm_USUM =>
|
||||
[
|
||||
003, 006, 009, 015, 018, 019, 020, 025, 026, 027, 028, 037, 038, 050, 051, 052,
|
||||
053, 065, 074, 075, 076, 080, 088, 089, 094, 103, 105, 115, 127, 130, 142, 150,
|
||||
181, 201, 208, 212, 214, 229, 248, 254, 257, 260, 282, 302, 303, 306, 308, 310,
|
||||
319, 323, 334, 351, 354, 359, 362, 373, 376, 380, 381, 382, 383, 384, 386, 412,
|
||||
413, 414, 421, 422, 423, 428, 445, 448, 460, 475, 479, 487, 492, 493, 531, 550,
|
||||
555, 585, 586, 641, 642, 645, 646, 647, 648, 649, 658, 664, 665, 666, 669, 670,
|
||||
671, 676, 678, 681, 710, 711, 716, 718, 719, 720, 735, 738, 741, 743, 744, 745,
|
||||
746, 752, 754, 758, 773, 774, 777, 778, 784, 800, 801,
|
||||
003, 006, 009, 015, 018, 019, 020, 025, 026, 027, 028, 037, 038, 050, 051, 052,
|
||||
053, 065, 074, 075, 076, 080, 088, 089, 094, 103, 105, 115, 127, 130, 142, 150,
|
||||
181, 201, 208, 212, 214, 229, 248, 254, 257, 260, 282, 302, 303, 306, 308, 310,
|
||||
319, 323, 334, 351, 354, 359, 362, 373, 376, 380, 381, 382, 383, 384, 386, 412,
|
||||
413, 414, 421, 422, 423, 428, 445, 448, 460, 475, 479, 487, 492, 493, 531, 550,
|
||||
555, 585, 586, 641, 642, 645, 646, 647, 648, 649, 658, 664, 665, 666, 669, 670,
|
||||
671, 676, 678, 681, 710, 711, 716, 718, 719, 720, 735, 738, 741, 743, 744, 745,
|
||||
746, 752, 754, 758, 773, 774, 777, 778, 784, 800, 801,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> DexSpeciesCount_USUM =>
|
||||
|
@ -88,8 +88,8 @@ public static class DexFormUtil
|
|||
|
||||
private static ReadOnlySpan<ushort> DexSpeciesWithForm_GG =>
|
||||
[
|
||||
003, 006, 009, 015, 018, 019, 020, 025, 026, 027, 028, 037, 038, 050, 051, 052,
|
||||
053, 065, 074, 075, 076, 080, 088, 089, 094, 103, 105, 115, 127, 130, 142, 150,
|
||||
003, 006, 009, 015, 018, 019, 020, 025, 026, 027, 028, 037, 038, 050, 051, 052,
|
||||
053, 065, 074, 075, 076, 080, 088, 089, 094, 103, 105, 115, 127, 130, 142, 150,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> DexSpeciesCount_GG =>
|
||||
|
|
|
@ -8,27 +8,6 @@ namespace PKHeX.Core;
|
|||
/// </summary>
|
||||
public static class ArrayUtil
|
||||
{
|
||||
public static T Find<T>(this Span<T> data, Func<T, bool> value) where T : unmanaged
|
||||
{
|
||||
foreach (var x in data)
|
||||
{
|
||||
if (value(x))
|
||||
return x;
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the range (exclusive max) if the <see cref="value"/> is inside.
|
||||
/// </summary>
|
||||
public static bool WithinRange(int value, int min, int max) => min <= value && value < max;
|
||||
|
||||
public static IEnumerable<T[]> EnumerateSplit<T>(T[] bin, int size, int start = 0)
|
||||
{
|
||||
for (int i = start; i < bin.Length; i += size)
|
||||
yield return bin.AsSpan(i, size).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies a <see cref="T"/> list to the destination list, with an option to copy to a starting point.
|
||||
/// </summary>
|
||||
|
|
|
@ -54,8 +54,8 @@ public static class FileUtil
|
|||
return mc;
|
||||
if (TryGetPKM(data, out var pk, ext))
|
||||
return pk;
|
||||
if (TryGetPCBoxBin(data, out IEnumerable<byte[]> pks, reference))
|
||||
return pks;
|
||||
if (TryGetPCBoxBin(data, out var concat, reference))
|
||||
return concat;
|
||||
if (TryGetBattleVideo(data, out var bv))
|
||||
return bv;
|
||||
if (TryGetMysteryGift(data, out var g, ext))
|
||||
|
@ -228,23 +228,34 @@ public static class FileUtil
|
|||
/// Tries to get a <see cref="IEnumerable{T}"/> object from the input parameters.
|
||||
/// </summary>
|
||||
/// <param name="data">Binary data</param>
|
||||
/// <param name="pkms">Output result</param>
|
||||
/// <param name="result">Output result</param>
|
||||
/// <param name="sav">Reference SaveFile used for PC Binary compatibility checks.</param>
|
||||
/// <returns>True if file object reference is valid, false if none found.</returns>
|
||||
public static bool TryGetPCBoxBin(byte[] data, out IEnumerable<byte[]> pkms, SaveFile? sav)
|
||||
public static bool TryGetPCBoxBin(byte[] data, [NotNullWhen(true)] out ConcatenatedEntitySet? result, SaveFile? sav)
|
||||
{
|
||||
if (sav == null || IsNoDataPresent(data))
|
||||
{
|
||||
pkms = [];
|
||||
result = null;
|
||||
if (sav is null || IsNoDataPresent(data))
|
||||
return false;
|
||||
}
|
||||
var length = data.Length;
|
||||
if (EntityDetection.IsSizePlausible(length / sav.SlotCount) || EntityDetection.IsSizePlausible(length / sav.BoxSlotCount))
|
||||
|
||||
// Only return if the size is one of the save file's data chunk formats.
|
||||
var expect = sav.SIZE_BOXSLOT;
|
||||
|
||||
// Check if it's the entire PC data.
|
||||
var countPC = sav.SlotCount;
|
||||
if (expect * countPC == data.Length)
|
||||
{
|
||||
pkms = ArrayUtil.EnumerateSplit(data, length);
|
||||
result = new(data, countPC);
|
||||
return true;
|
||||
}
|
||||
pkms = [];
|
||||
|
||||
// Check if it's a single box data.
|
||||
var countBox = sav.BoxSlotCount;
|
||||
if (expect * countBox == data.Length)
|
||||
{
|
||||
result = new(data, countBox);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -321,3 +332,22 @@ public static class FileUtil
|
|||
return pk;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a set of concatenated <see cref="PKM"/> data.
|
||||
/// </summary>
|
||||
/// <param name="Data">Object data</param>
|
||||
/// <param name="Count">Count of objects</param>
|
||||
public sealed record ConcatenatedEntitySet(Memory<byte> Data, int Count)
|
||||
{
|
||||
public int SlotSize => Data.Length / Count;
|
||||
|
||||
public Span<byte> GetSlot(int index)
|
||||
{
|
||||
var size = SlotSize;
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)index, (uint)size);
|
||||
|
||||
var offset = index * size;
|
||||
return Data.Span.Slice(offset, size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -618,7 +618,7 @@ public partial class Main : Form
|
|||
case SaveFile s: return OpenSAV(s, path);
|
||||
case IPokeGroup b: return OpenGroup(b);
|
||||
case MysteryGift g: return OpenMysteryGift(g, path);
|
||||
case IEnumerable<byte[]> pkms: return OpenPCBoxBin(pkms);
|
||||
case ConcatenatedEntitySet pkms: return OpenPCBoxBin(pkms);
|
||||
case IEncounterConvertible enc: return OpenPKM(enc.ConvertToPKM(C_SAV.SAV));
|
||||
|
||||
case SAV3GCMemoryCard gc:
|
||||
|
@ -678,10 +678,9 @@ public partial class Main : Form
|
|||
return true;
|
||||
}
|
||||
|
||||
private bool OpenPCBoxBin(IEnumerable<byte[]> pkms)
|
||||
private bool OpenPCBoxBin(ConcatenatedEntitySet pkms)
|
||||
{
|
||||
var data = pkms.SelectMany(z => z).ToArray();
|
||||
if (!C_SAV.OpenPCBoxBin(data, out string c))
|
||||
if (!C_SAV.OpenPCBoxBin(pkms.Data.Span, out string c))
|
||||
{
|
||||
WinFormsUtil.Alert(MsgFileLoadIncompatible, c);
|
||||
return true;
|
||||
|
|
|
@ -226,7 +226,7 @@ public partial class SAV_SecretBase : Form
|
|||
CB_Species.SelectedValue = (int)pk.Species;
|
||||
CB_HeldItem.SelectedValue = pk.HeldItem;
|
||||
CB_Form.SelectedIndex = pk.Form;
|
||||
|
||||
|
||||
CB_Nature.SelectedValue = (int)pk.Nature;
|
||||
CB_Ball.SelectedValue = (int)pk.Ball;
|
||||
|
||||
|
|
|
@ -29,6 +29,6 @@ public static class SMTests
|
|||
save.ChecksumInfo.Should().BeEquivalentTo(originalChecksumInfo, "because the checksum should have been modified");
|
||||
save.ChecksumsValid.Should().BeTrue("because the checksum should be valid after write");
|
||||
newSave.ChecksumsValid.Should().BeTrue("because the checksums should be valid after reopening the save");
|
||||
newSave.ChecksumInfo.Should().BeEquivalentTo(save.ChecksumInfo, "because the checksums should be the same since write and open");
|
||||
newSave.ChecksumInfo.Should().BeEquivalentTo(originalChecksumInfo, "because the checksums should be the same since write and open");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue