mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 14:44:24 +00:00
Misc enc template tweaks
Skip string fetch for Trade1 Set gender for Trade8 Add record to wrap Gen8 raid generate params, return & use bool for filtering results, fallback to unrestricted if none succeed Fix gender comparison for Entree5 slot Simplify gen2 ResetKey fetch (byte sum of Money/ID/OT(used) Closes #3970 by filtering gender inside the method like Encounter9RNG with an early return Adds IV filtering inside the method with an early return like Encounter9RNG
This commit is contained in:
parent
5222fdc6ad
commit
978bcfa56f
10 changed files with 98 additions and 88 deletions
|
@ -75,7 +75,7 @@ public sealed record EncounterTrade1 : IEncounterable, IEncounterMatch, IFixedTr
|
|||
private static bool IsTrainerNameValid(PKM pk)
|
||||
{
|
||||
if (pk.Format <= 2)
|
||||
return pk.OT_Name == StringConverter12.G1TradeOTStr;
|
||||
return pk.OT_Trash is [StringConverter12.G1TradeOTCode, StringConverter12.G1TerminatorCode, _];
|
||||
return pk.Language switch
|
||||
{
|
||||
1 => GetIndex(pk.OT_Name, TrainerNames) == 1,
|
||||
|
@ -89,7 +89,7 @@ public sealed record EncounterTrade1 : IEncounterable, IEncounterMatch, IFixedTr
|
|||
{
|
||||
for (int i = 0; i < arr.Count; i++)
|
||||
{
|
||||
if (arr[i].AsSpan().SequenceEqual(name))
|
||||
if (name.SequenceEqual(arr[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -124,12 +124,12 @@ public sealed record EncounterTrade1 : IEncounterable, IEncounterMatch, IFixedTr
|
|||
Catch_Rate = EncounterUtil1.GetWildCatchRate(Version, Species),
|
||||
DV16 = EncounterUtil1.GetRandomDVs(Util.Rand),
|
||||
|
||||
OT_Name = StringConverter12.G1TradeOTStr,
|
||||
Nickname = Nicknames[lang],
|
||||
TID16 = tr.TID16,
|
||||
Type1 = pi.Type1,
|
||||
Type2 = pi.Type2,
|
||||
};
|
||||
pk.OT_Trash[0] = StringConverter12.G1TradeOTCode;
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, level);
|
||||
|
||||
|
|
|
@ -90,32 +90,37 @@ public abstract record EncounterStatic8Nest<T>(GameVersion Version)
|
|||
{
|
||||
bool requestShiny = criteria.Shiny.IsShiny();
|
||||
bool checkShiny = requestShiny && Shiny != Shiny.Never;
|
||||
var ratio = RemapGenderToParam(Gender, pi);
|
||||
var abil = RemapAbilityToParam(Ability);
|
||||
Span<int> iv = stackalloc int[6];
|
||||
|
||||
int ctr = 0;
|
||||
var rand = new Xoroshiro128Plus(Util.Rand.Rand64());
|
||||
var param = GetParam(pi);
|
||||
ulong seed;
|
||||
const int max = 100_000;
|
||||
do
|
||||
{
|
||||
seed = rand.Next();
|
||||
ApplyDetailsTo(pk, seed, iv, abil, ratio);
|
||||
|
||||
if (criteria.IV_ATK != 31 && pk.IV_ATK != criteria.IV_ATK)
|
||||
continue;
|
||||
if (criteria.IV_SPE != 31 && pk.IV_SPE != criteria.IV_SPE)
|
||||
if (!TryApply(pk, seed, iv, param, criteria))
|
||||
continue;
|
||||
if (checkShiny && pk.IsShiny != requestShiny)
|
||||
continue;
|
||||
break;
|
||||
} while (ctr++ < 100_000);
|
||||
} while (ctr++ < max);
|
||||
|
||||
if (ctr == max) // fail
|
||||
TryApply(pk, rand.Next(), iv, param, EncounterCriteria.Unrestricted);
|
||||
|
||||
FinishCorrelation(pk, seed);
|
||||
if ((byte)criteria.Nature != pk.Nature && criteria.Nature.IsMint())
|
||||
pk.StatNature = (byte)criteria.Nature;
|
||||
}
|
||||
|
||||
private GenerateParam8 GetParam(PersonalInfo8SWSH pi)
|
||||
{
|
||||
var ratio = RemapGenderToParam(Gender, pi);
|
||||
return new GenerateParam8(Species, ratio, FlawlessIVCount, Ability, Shiny, Nature.Random, IVs);
|
||||
}
|
||||
|
||||
protected virtual void FinishCorrelation(PK8 pk, ulong seed) { }
|
||||
|
||||
#endregion
|
||||
|
@ -239,28 +244,14 @@ public abstract record EncounterStatic8Nest<T>(GameVersion Version)
|
|||
/// <returns>True if the seed is valid for the criteria.</returns>
|
||||
public bool Verify(PKM pk, ulong seed, bool forceNoShiny = false)
|
||||
{
|
||||
var ratio = RemapGenderToParam(Gender, Info);
|
||||
var abil = RemapAbilityToParam(Ability);
|
||||
|
||||
var param = GetParam(PersonalTable.SWSH.GetFormEntry(Species, Form));
|
||||
Span<int> iv = stackalloc int[6];
|
||||
LoadIVs(iv);
|
||||
return RaidRNG.Verify(pk, seed, iv, Species, FlawlessIVCount, abil, ratio, forceNoShiny: forceNoShiny);
|
||||
return RaidRNG.Verify(pk, seed, iv, param, forceNoShiny: forceNoShiny);
|
||||
}
|
||||
|
||||
private void ApplyDetailsTo(PK8 pk, ulong seed, Span<int> iv, byte abil, byte ratio)
|
||||
private static bool TryApply(PK8 pk, ulong seed, Span<int> iv, GenerateParam8 param, EncounterCriteria criteria)
|
||||
{
|
||||
LoadIVs(iv);
|
||||
RaidRNG.ApplyDetailsTo(pk, seed, iv, Species, FlawlessIVCount, abil, ratio);
|
||||
}
|
||||
|
||||
private void LoadIVs(Span<int> span)
|
||||
{
|
||||
// Template stores with speed in middle (standard), convert for generator purpose.
|
||||
var ivs = IVs;
|
||||
if (ivs.IsSpecified)
|
||||
ivs.CopyToSpeedLast(span);
|
||||
else
|
||||
span.Fill(-1);
|
||||
return RaidRNG.TryApply(pk, seed, iv, param, criteria);
|
||||
}
|
||||
|
||||
private static byte RemapGenderToParam(byte gender, PersonalInfo8SWSH pi) => gender switch
|
||||
|
@ -271,13 +262,6 @@ public abstract record EncounterStatic8Nest<T>(GameVersion Version)
|
|||
_ => pi.Gender,
|
||||
};
|
||||
|
||||
private static byte RemapAbilityToParam(AbilityPermission a) => a switch
|
||||
{
|
||||
Any12H => 254,
|
||||
Any12 => 255,
|
||||
_ => a.GetSingleValue(),
|
||||
};
|
||||
|
||||
private bool IsMatchCorrelation(PKM pk)
|
||||
{
|
||||
if (pk.IsShiny)
|
||||
|
|
|
@ -109,6 +109,7 @@ public sealed record EncounterTrade8 : IEncounterable, IEncounterMatch, IFixedTr
|
|||
Met_Level = Level,
|
||||
MetDate = EncounterDate.GetDateSwitch(),
|
||||
Ball = (byte)FixedBall,
|
||||
Gender = Gender,
|
||||
|
||||
ID32 = ID32,
|
||||
Version = (byte)version,
|
||||
|
|
15
PKHeX.Core/Legality/RNG/Methods/GenerateParam8.cs
Normal file
15
PKHeX.Core/Legality/RNG/Methods/GenerateParam8.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parameters used to generate data for an encounter.
|
||||
/// </summary>
|
||||
/// <param name="Species">Species to generate.</param>
|
||||
/// <param name="GenderRatio">Gender ratio byte.</param>
|
||||
/// <param name="FlawlessIVs">Count of IVs that are perfect.</param>
|
||||
/// <param name="Ability">Ability type to generate.</param>
|
||||
/// <param name="Shiny">PID generation type.</param>
|
||||
/// <param name="Nature">Nature specification.</param>
|
||||
/// <param name="IVs">IV specification.</param>
|
||||
public readonly record struct GenerateParam8(ushort Species, byte GenderRatio, byte FlawlessIVs,
|
||||
AbilityPermission Ability = AbilityPermission.Any12, Shiny Shiny = Shiny.Random,
|
||||
Nature Nature = Nature.Random, IndividualValueSet IVs = default);
|
|
@ -14,14 +14,10 @@ public static class RaidRNG
|
|||
/// <param name="pk">Entity to verify against</param>
|
||||
/// <param name="seed">Seed that generated the entity</param>
|
||||
/// <param name="ivs">Buffer of IVs (potentially with already specified values)</param>
|
||||
/// <param name="species">Species of the entity</param>
|
||||
/// <param name="iv_count">Number of flawless IVs to generate</param>
|
||||
/// <param name="ability_param">Ability to generate</param>
|
||||
/// <param name="gender_ratio">Gender distribution to generate</param>
|
||||
/// <param name="nature_param">Nature to generate</param>
|
||||
/// <param name="param">Parameters to generate with</param>
|
||||
/// <param name="forceNoShiny">Force the entity to be non-shiny via special handling</param>
|
||||
/// <returns>True if the seed matches the entity</returns>
|
||||
public static bool Verify(PKM pk, ulong seed, Span<int> ivs, ushort species, byte iv_count, byte ability_param, byte gender_ratio, sbyte nature_param = -1, bool forceNoShiny = false)
|
||||
public static bool Verify(PKM pk, ulong seed, Span<int> ivs, in GenerateParam8 param, bool forceNoShiny = false)
|
||||
{
|
||||
var rng = new Xoroshiro128Plus(seed);
|
||||
var ec = (uint)rng.NextInt();
|
||||
|
@ -49,7 +45,12 @@ public static class RaidRNG
|
|||
|
||||
const int UNSET = -1;
|
||||
const int MAX = 31;
|
||||
for (int i = ivs.Count(MAX); i < iv_count; i++)
|
||||
if (param.IVs.IsSpecified)
|
||||
param.IVs.CopyToSpeedLast(ivs);
|
||||
else
|
||||
ivs.Fill(UNSET);
|
||||
|
||||
for (int i = ivs.Count(MAX); i < param.FlawlessIVs; i++)
|
||||
{
|
||||
int index = (int)rng.NextInt(6);
|
||||
while (ivs[index] != UNSET)
|
||||
|
@ -76,11 +77,11 @@ public static class RaidRNG
|
|||
if (pk.IV_SPE != ivs[5])
|
||||
return false;
|
||||
|
||||
int abil = ability_param switch
|
||||
int abil = param.Ability switch
|
||||
{
|
||||
254 => (int)rng.NextInt(3),
|
||||
255 => (int)rng.NextInt(2),
|
||||
_ => ability_param,
|
||||
AbilityPermission.Any12H => (int)rng.NextInt(3),
|
||||
AbilityPermission.Any12 => (int)rng.NextInt(2),
|
||||
_ => param.Ability.GetSingleValue(),
|
||||
};
|
||||
abil <<= 1; // 1/2/4
|
||||
|
||||
|
@ -92,7 +93,7 @@ public static class RaidRNG
|
|||
}
|
||||
// else, for things that were made Hidden Ability, defer to Ability Checks (Ability Patch)
|
||||
|
||||
switch (gender_ratio)
|
||||
switch (param.GenderRatio)
|
||||
{
|
||||
case PersonalInfo.RatioMagicGenderless:
|
||||
if (pk.Gender != 2)
|
||||
|
@ -107,14 +108,14 @@ public static class RaidRNG
|
|||
return false;
|
||||
break;
|
||||
default:
|
||||
var gender = (int)rng.NextInt(253) + 1 < gender_ratio ? 1 : 0;
|
||||
var gender = (int)rng.NextInt(253) + 1 < param.GenderRatio ? 1 : 0;
|
||||
if (pk.Gender != gender && pk.Gender != 2) // allow Nincada(0/1)->Shedinja(2)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
int nature = nature_param != -1 ? nature_param
|
||||
: species == (int)Species.Toxtricity
|
||||
int nature = param.Nature != Nature.Random ? (int)param.Nature
|
||||
: param.Species == (int)Species.Toxtricity
|
||||
? ToxtricityUtil.GetRandomNature(ref rng, pk.Form)
|
||||
: (byte)rng.NextInt(25);
|
||||
if (pk.Nature != nature)
|
||||
|
@ -164,14 +165,10 @@ public static class RaidRNG
|
|||
/// <param name="pk">Entity to verify against</param>
|
||||
/// <param name="seed">Seed that generated the entity</param>
|
||||
/// <param name="ivs">Buffer of IVs (potentially with already specified values)</param>
|
||||
/// <param name="species">Species of the entity</param>
|
||||
/// <param name="iv_count">Number of flawless IVs to generate</param>
|
||||
/// <param name="ability_param">Ability to generate</param>
|
||||
/// <param name="gender_ratio">Gender distribution to generate</param>
|
||||
/// <param name="nature_param">Nature to generate</param>
|
||||
/// <param name="shiny">Shiny state to generate</param>
|
||||
/// <param name="param">Parameters to generate with</param>
|
||||
/// <param name="criteria">Criteria to generate with</param>
|
||||
/// <returns>True if the seed matches the entity</returns>
|
||||
public static bool ApplyDetailsTo(PK8 pk, ulong seed, Span<int> ivs, ushort species, byte iv_count, byte ability_param, byte gender_ratio, sbyte nature_param = -1, Shiny shiny = Shiny.Random)
|
||||
public static bool TryApply(PK8 pk, ulong seed, Span<int> ivs, in GenerateParam8 param, EncounterCriteria criteria)
|
||||
{
|
||||
var rng = new Xoroshiro128Plus(seed);
|
||||
pk.EncryptionConstant = (uint)rng.NextInt();
|
||||
|
@ -183,7 +180,7 @@ public static class RaidRNG
|
|||
pid = (uint)rng.NextInt();
|
||||
var xor = GetShinyXor(pid, trID);
|
||||
isShiny = xor < 16;
|
||||
if (isShiny && shiny == Shiny.Never)
|
||||
if (isShiny && param.Shiny == Shiny.Never)
|
||||
{
|
||||
ForceShinyState(false, ref pid, trID);
|
||||
isShiny = false;
|
||||
|
@ -205,13 +202,21 @@ public static class RaidRNG
|
|||
|
||||
const int UNSET = -1;
|
||||
const int MAX = 31;
|
||||
for (int i = ivs.Count(MAX); i < iv_count; i++)
|
||||
if (param.IVs.IsSpecified)
|
||||
{
|
||||
int index = (int)rng.NextInt(6);
|
||||
while (ivs[index] != UNSET)
|
||||
index = (int)rng.NextInt(6);
|
||||
param.IVs.CopyToSpeedLast(ivs);
|
||||
}
|
||||
else
|
||||
{
|
||||
ivs.Fill(UNSET);
|
||||
for (int i = ivs.Count(MAX); i < param.FlawlessIVs; i++)
|
||||
{
|
||||
int index;
|
||||
do { index = (int)rng.NextInt(6); }
|
||||
while (ivs[index] != UNSET);
|
||||
ivs[index] = MAX;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
|
@ -219,6 +224,9 @@ public static class RaidRNG
|
|||
ivs[i] = (int)rng.NextInt(32);
|
||||
}
|
||||
|
||||
if (!param.IVs.IsSpecified && !criteria.IsIVsCompatible(ivs, 8))
|
||||
return false;
|
||||
|
||||
pk.IV_HP = ivs[0];
|
||||
pk.IV_ATK = ivs[1];
|
||||
pk.IV_DEF = ivs[2];
|
||||
|
@ -226,24 +234,27 @@ public static class RaidRNG
|
|||
pk.IV_SPD = ivs[4];
|
||||
pk.IV_SPE = ivs[5];
|
||||
|
||||
int abil = ability_param switch
|
||||
int abil = param.Ability switch
|
||||
{
|
||||
254 => (int)rng.NextInt(3),
|
||||
255 => (int)rng.NextInt(2),
|
||||
_ => ability_param,
|
||||
AbilityPermission.Any12H => (int)rng.NextInt(3),
|
||||
AbilityPermission.Any12 => (int)rng.NextInt(2),
|
||||
_ => param.Ability.GetSingleValue(),
|
||||
};
|
||||
pk.RefreshAbility(abil);
|
||||
|
||||
pk.Gender = gender_ratio switch
|
||||
var gender = param.GenderRatio switch
|
||||
{
|
||||
PersonalInfo.RatioMagicGenderless => 2,
|
||||
PersonalInfo.RatioMagicFemale => 1,
|
||||
PersonalInfo.RatioMagicMale => 0,
|
||||
_ => (int) rng.NextInt(253) + 1 < gender_ratio ? 1 : 0,
|
||||
_ => (int) rng.NextInt(253) + 1 < param.GenderRatio ? 1 : 0,
|
||||
};
|
||||
if (criteria.Gender != FixedGenderUtil.GenderRandom && gender != criteria.Gender)
|
||||
return false;
|
||||
pk.Gender = gender;
|
||||
|
||||
int nature = nature_param != -1 ? nature_param
|
||||
: species == (int)Species.Toxtricity
|
||||
int nature = param.Nature != Nature.Random ? (byte)param.Nature
|
||||
: param.Species == (int)Species.Toxtricity
|
||||
? ToxtricityUtil.GetRandomNature(ref rng, pk.Form)
|
||||
: (byte)rng.NextInt(25);
|
||||
|
||||
|
|
|
@ -229,8 +229,8 @@ public sealed class PK1 : GBPKML, IPersonalType
|
|||
|
||||
private string GetTransferTrainerName(int lang)
|
||||
{
|
||||
if (OT_Trash[0] == StringConverter12.G1TradeOTCode)
|
||||
return StringConverter12.G1TradeOTName[lang]; // In-game Trade
|
||||
if (OT_Trash[0] == StringConverter12.G1TradeOTCode) // In-game Trade
|
||||
return StringConverter12.G1TradeOTName[lang];
|
||||
return StringConverter12Transporter.GetString(OT_Trash, Japanese);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ public static class StringConverter12
|
|||
public const char G1Terminator = '\0';
|
||||
public const byte G1TradeOTCode = 0x5D;
|
||||
public const char G1TradeOT = '*';
|
||||
public const string G1TradeOTStr = "*";
|
||||
public const byte G1SpaceCode = 0x7F;
|
||||
|
||||
public static readonly IReadOnlyList<string> G1TradeOTName = new []
|
||||
|
@ -111,7 +110,7 @@ public static class StringConverter12
|
|||
/// <returns>Character count loaded.</returns>
|
||||
public static int LoadString(ReadOnlySpan<byte> data, Span<char> result, bool jp)
|
||||
{
|
||||
if (data[0] == G1TradeOTCode)
|
||||
if (data[0] == G1TradeOTCode) // In-game Trade
|
||||
{
|
||||
result[0] = G1TradeOT;
|
||||
return 1;
|
||||
|
|
|
@ -50,7 +50,7 @@ public static class StringConverter2KOR
|
|||
/// <returns>Character count loaded.</returns>
|
||||
public static int LoadString(ReadOnlySpan<byte> data, Span<char> result)
|
||||
{
|
||||
if (data[0] == G1TradeOTCode)
|
||||
if (data[0] == G1TradeOTCode) // In-game Trade
|
||||
{
|
||||
result[0] = G1TradeOT;
|
||||
return 1;
|
||||
|
|
|
@ -720,16 +720,16 @@ public sealed class SAV2 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWo
|
|||
|
||||
private ushort GetResetKey()
|
||||
{
|
||||
var value = (TID16 >> 8) + (TID16 & 0xFF) + ((Money >> 16) & 0xFF) + ((Money >> 8) & 0xFF) + (Money & 0xFF);
|
||||
var ot = Data.AsSpan(Offsets.Trainer1 + 2, 5);
|
||||
var sum = 0;
|
||||
foreach (var b in ot)
|
||||
{
|
||||
if (b == StringConverter12.G1TerminatorCode)
|
||||
break;
|
||||
sum += b;
|
||||
}
|
||||
return (ushort)(value + sum);
|
||||
ushort result = 0;
|
||||
foreach (var b in Data.AsSpan(Offsets.Money, 3))
|
||||
result += b;
|
||||
var tr = Data.AsSpan(Offsets.Trainer1, 7);
|
||||
var end = tr[2..].IndexOf(StringConverter12.G1TerminatorCode);
|
||||
if (end >= 0)
|
||||
tr = tr[..(end + 2)];
|
||||
foreach (var b in tr)
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -620,7 +620,7 @@ public partial class SAV_Misc5 : Form
|
|||
source.Remove(slot);
|
||||
s.Species = slot.Species;
|
||||
s.Form = slot.Form;
|
||||
s.Gender = slot.Gender == -1 ? PersonalTable.B2W2[slot.Species].RandomGender() : slot.Gender;
|
||||
s.Gender = slot.Gender == FixedGenderUtil.GenderRandom ? PersonalTable.B2W2[slot.Species].RandomGender() : slot.Gender;
|
||||
|
||||
slot.Moves.CopyTo(moves);
|
||||
var count = moves.Length - moves.Count((ushort)0);
|
||||
|
|
Loading…
Reference in a new issue