Misc fixes

Allow dragon ascent bitfetch for gen6/7
Fix hidden power type parse/trim
Remove */ from hidden power type calc
allow longer set lines (full EVs specified for Gen2 is 74 chars
allow set lines of length 1-2 to fully support trash sets for all languages
Tweak pb8->pk8 to be more straightforward
This commit is contained in:
Kurt 2023-01-26 19:03:06 -08:00
parent 387ab6d546
commit 9ddfe3f629
9 changed files with 60 additions and 28 deletions

View file

@ -31,11 +31,22 @@ public static class HiddenPower
int hp = 0;
for (int i = 0; i < 6; i++)
hp |= (IVs[i] & 1) << i;
hp *= 0xF;
hp /= 0x3F;
return hp;
return SixBitType[hp];
}
private static ReadOnlySpan<byte> SixBitType => new byte[]
{
// (low-bit mash) * 15 / 63
00, 00, 00, 00, 00, 01, 01, 01,
01, 02, 02, 02, 02, 03, 03, 03,
03, 04, 04, 04, 04, 05, 05, 05,
05, 05, 06, 06, 06, 06, 07, 07,
07, 07, 08, 08, 08, 08, 09, 09,
09, 09, 10, 10, 10, 10, 10, 11,
11, 11, 11, 12, 12, 12, 12, 13,
13, 13, 13, 14, 14, 14, 14, 15,
};
/// <summary>
/// Gets the current Hidden Power Type of the input <see cref="IVs"/> for Generations 1 &amp; 2
/// </summary>
@ -83,6 +94,10 @@ public static class HiddenPower
/// <returns>True if the Hidden Power of the <see cref="IVs"/> is obtained, with or without modifications</returns>
public static bool SetIVsForType(int hpVal, Span<int> IVs)
{
int current = GetType(IVs);
if (current == hpVal)
return true; // no mods necessary
int flawlessCount = IVs.Count(31);
if (flawlessCount == 0)
return false;
@ -93,10 +108,6 @@ public static class HiddenPower
return true;
}
int current = GetType(IVs);
if (current == hpVal)
return true; // no mods necessary
// Required HP type doesn't match IVs. Make currently-flawless IVs flawed.
Span<int> scratch = stackalloc int[IVs.Length];
Span<int> result = stackalloc int[IVs.Length];

View file

@ -139,6 +139,15 @@ public sealed class ShowdownSet : IBattleTemplate
private const int MaxMoveCount = 4;
// Skip lines that are too short or too long.
// Longest line is ~74 (Gen2 EVs)
// Length permitted: 3-80
// The shortest Pokémon name in Japanese is "ニ" (Ni) which is the name for the Pokémon, Nidoran♂ (male Nidoran). It has only one letter.
// We will handle this 1-2 letter edge case only if the line is the first line of the set, in the rare chance we are importing for a non-English language?
private const int MinLength = 3;
private const int MaxLength = 80;
private static bool IsLengthOutOfRange(ReadOnlySpan<char> trim) => (uint)(trim.Length - MinLength) > MaxLength + MinLength;
private void ParseLines(SpanLineEnumerator lines)
{
int movectr = 0;
@ -146,8 +155,15 @@ public sealed class ShowdownSet : IBattleTemplate
foreach (var line in lines)
{
ReadOnlySpan<char> trim = line.Trim();
if (trim.Length is <= 2 or >= 40)
if (IsLengthOutOfRange(trim))
{
// Try for other languages just in case.
if (first && trim.Length != 0)
{
ParseFirstLine(trim);
first = false;
continue;
}
InvalidLines.Add(line.ToString());
continue;
}
@ -170,8 +186,15 @@ public sealed class ShowdownSet : IBattleTemplate
foreach (var line in lines)
{
ReadOnlySpan<char> trim = line.Trim();
if (trim.Length is <= 2 or >= 40)
if (IsLengthOutOfRange(trim))
{
// Try for other languages just in case.
if (first && trim.Length != 0)
{
ParseFirstLine(trim);
first = false;
continue;
}
InvalidLines.Add(line);
continue;
}
@ -680,7 +703,8 @@ public sealed class ShowdownSet : IBattleTemplate
Span<char> type = stackalloc char[moveString.Length - hiddenPowerName.Length];
moveString[hiddenPowerName.Length..].CopyTo(type);
RemoveAll(ref type, ParenJunk); // Trim out excess data
int hpVal = StringUtil.FindIndexIgnoreCase(Strings.types, type) - 1; // Get HP Type
type = type.Trim();
int hpVal = StringUtil.FindIndexIgnoreCase(Strings.types.AsSpan(1), type); // Get HP Type
HiddenPowerType = hpVal;
if (!Array.TrueForAll(IVs, z => z == 31))

View file

@ -127,6 +127,7 @@ public static class Breeding
(int)Pikachu or (int)Eevee => false, // can't get these forms as egg
(int)Pichu => false, // can't get Spiky Ear Pichu eggs
(int)Floette when form == 5 => false, // can't get Eternal Flower from egg
(int)Greninja when form == 1 => false, // can't get Battle Bond Greninja from egg
(int)Sinistea or (int)Polteageist => false, // can't get Antique eggs
_ => true,
};

View file

@ -208,7 +208,7 @@ public sealed class MiscVerifier : Verifier
(int)Species.Sliggoo | (1 << 11), // Sliggoo-1
(int)Species.Avalugg | (1 << 11), // Avalugg-1
(int)Species.Decidueye | (1 << 11), // Decidueye-1
(int)Species.Wyrdeer,
(int)Species.Kleavor,
(int)Species.Ursaluna,

View file

@ -163,31 +163,27 @@ public sealed class PK8 : G8PKM
public void SanitizeImport()
{
// BDSP->SWSH: Set the Met Location to the magic Location, set the Egg Location to 0 if -1, otherwise BDSPEgg (0 is a valid location, but no eggs can be EggMet there -- only hatched.)
// PLA->SWSH: Set the Met Location to the magic Location, set the Egg Location to 0 (no eggs in game).
var ver = Version;
if (ver is (int)GameVersion.SP)
{
Met_Location = Locations.HOME_SHSP;
Version = (int)GameVersion.SH;
if (Egg_Location != 0)
Egg_Location = Locations.HOME_SHSP;
Met_Location = Locations.HOME_SHSP;
Egg_Location = Egg_Location == Locations.Default8bNone ? 0 : Locations.HOME_SWSHBDSPEgg;
}
else if (ver is (int)GameVersion.BD)
{
Met_Location = Locations.HOME_SWBD;
Version = (int)GameVersion.SW;
if (Egg_Location != 0)
Egg_Location = Locations.HOME_SWBD;
Met_Location = Locations.HOME_SWBD;
Egg_Location = Egg_Location == Locations.Default8bNone ? 0 : Locations.HOME_SWSHBDSPEgg;
}
else if (ver is (int)GameVersion.PLA)
{
Met_Location = Locations.HOME_SWLA;
const ushort met = Locations.HOME_SWLA;
Version = (int)GameVersion.SW;
if (Egg_Location != 0)
Egg_Location = Locations.HOME_SWLA;
}
else if (ver > (int)GameVersion.PLA)
{
Met_Location = Met_Location <= Locations.HOME_SWLA ? Locations.HOME_SWLA : Locations.HOME_SWSHBDSPEgg;
Met_Location = met;
Egg_Location = 0; // Everything originating from this game has an Egg Location of 0.
}
if (Ball > (int)Core.Ball.Beast)

View file

@ -42,7 +42,7 @@ public class LegalityRejuvenator : IEntityRejuvenator
// No egg encounters. Always not-egg.
{
result.Met_Location = enc.Location;
result.Egg_Location = Locations.Default8bNone;
result.Egg_Location = 0;
}
// Try again with rectified locations.

View file

@ -73,7 +73,7 @@ public sealed class PersonalInfo6AO : PersonalInfo, IPersonalAbility12H, IPerson
private const int CountTMHM = CountTM + CountHM;
private const int ByteCountTM = (CountTMHM + 7) / 8;
private const int TypeTutor = 0x38;
private const int TypeTutorCount = 7;
private const int TypeTutorCount = 8;
public bool GetIsLearnTM(int index)
{

View file

@ -78,7 +78,7 @@ public sealed class PersonalInfo7 : PersonalInfo, IPersonalAbility12H, IPersonal
private const int CountTMHM = CountTM + CountHM;
private const int ByteCountTM = (CountTMHM + 7) / 8;
private const int TypeTutor = 0x38;
private const int TypeTutorCount = 7;
private const int TypeTutorCount = 8;
public bool GetIsLearnTM(int index)
{

View file

@ -16,7 +16,7 @@ public static class StringUtil
/// <param name="arr">Array of strings to search in</param>
/// <param name="value">Value to search for</param>
/// <returns>Index within <see cref="arr"/></returns>
public static int FindIndexIgnoreCase(string[] arr, ReadOnlySpan<char> value)
public static int FindIndexIgnoreCase(ReadOnlySpan<string> arr, ReadOnlySpan<char> value)
{
for (int i = 0; i < arr.Length; i++)
{