mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 14:44:24 +00:00
Reduce linq usage, minor perf
This commit is contained in:
parent
5140c47e84
commit
3dde8a7cfa
13 changed files with 215 additions and 80 deletions
|
@ -1,8 +1,7 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using static PKHeX.Core.EncountersWC3;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -74,7 +73,8 @@ public static class EncounterEvent
|
|||
ICollection<WB8> b8 = GetWB8DB(Util.GetBinaryResource("wb8.pkl"));
|
||||
ICollection<WA8> a8 = GetWA8DB(Util.GetBinaryResource("wa8.pkl"));
|
||||
|
||||
foreach (var gift in paths.Where(Directory.Exists).SelectMany(MysteryUtil.GetGiftsFromFolder))
|
||||
var gifts = GetGifts(paths);
|
||||
foreach (var gift in gifts)
|
||||
{
|
||||
static void AddOrExpand<T>(ref ICollection<T> arr, T obj)
|
||||
{
|
||||
|
@ -118,6 +118,18 @@ public static class EncounterEvent
|
|||
MGDB_G8B = SetArray(b8);
|
||||
}
|
||||
|
||||
private static IEnumerable<MysteryGift> GetGifts(IEnumerable<string> paths)
|
||||
{
|
||||
foreach (var path in paths)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
continue;
|
||||
var gifts = MysteryUtil.GetGiftsFromFolder(path);
|
||||
foreach (var gift in gifts)
|
||||
yield return gift;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<MysteryGift> GetAllEvents(bool sorted = true)
|
||||
{
|
||||
var regular = new IReadOnlyList<MysteryGift>[]
|
||||
|
|
|
@ -26,7 +26,11 @@ public static class EncounterSlotGenerator
|
|||
public static IEnumerable<EncounterSlot> GetPossible(PKM pk, EvoCriteria[] chain, GameVersion gameSource)
|
||||
{
|
||||
var possibleAreas = GetAreasByGame(pk, gameSource);
|
||||
return possibleAreas.SelectMany(z => z.GetSpecies(chain));
|
||||
foreach (var area in possibleAreas)
|
||||
{
|
||||
foreach (var result in area.GetSpecies(chain))
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<EncounterArea> GetAreasByGame(PKM pk, GameVersion gameSource) => gameSource switch
|
||||
|
@ -81,16 +85,23 @@ public static class EncounterSlotGenerator
|
|||
bool noMet = !pk.HasOriginalMetLocation || (pk.Format == 2 && gameSource != C);
|
||||
if (noMet)
|
||||
return slots;
|
||||
return GetIsMatchLocation(pk, slots);
|
||||
}
|
||||
|
||||
private static IEnumerable<EncounterArea> GetIsMatchLocation(PKM pk, IEnumerable<EncounterArea> areas)
|
||||
{
|
||||
var metLocation = pk.Met_Location;
|
||||
return slots.Where(z => z.IsMatchLocation(metLocation));
|
||||
foreach (var area in areas)
|
||||
{
|
||||
if (area.IsMatchLocation(metLocation))
|
||||
yield return area;
|
||||
}
|
||||
}
|
||||
|
||||
internal static EncounterSlot? GetCaptureLocation(PKM pk, EvoCriteria[] chain)
|
||||
{
|
||||
return GetPossible(pk, chain, (GameVersion)pk.Version)
|
||||
.OrderBy(z => !chain.Any(s => s.Species == z.Species && s.Form == z.Form))
|
||||
.ThenBy(z => z.LevelMin)
|
||||
.FirstOrDefault();
|
||||
var possible = GetPossible(pk, chain, (GameVersion)pk.Version);
|
||||
return EncounterUtil.GetMinByLevel(chain, possible);
|
||||
}
|
||||
|
||||
private static IEnumerable<EncounterArea> GetEncounterTable(PKM pk, GameVersion game) => game switch
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static PKHeX.Core.GameVersion;
|
||||
|
@ -17,13 +17,33 @@ public static class EncounterTradeGenerator
|
|||
private static IEnumerable<EncounterTradeGB> GetPossibleVC(EvoCriteria[] chain, GameVersion game)
|
||||
{
|
||||
var table = GetTableVC(game);
|
||||
return table.Where(e => chain.Any(c => c.Species == e.Species && c.Form == 0));
|
||||
foreach (var enc in table)
|
||||
{
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
if (evo.Species != enc.Species)
|
||||
continue;
|
||||
if (evo.Form != 0)
|
||||
break;
|
||||
yield return enc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<EncounterTrade> GetPossible(EvoCriteria[] chain, GameVersion game)
|
||||
{
|
||||
var table = GetTable(game);
|
||||
return table.Where(e => chain.Any(c => c.Species == e.Species));
|
||||
foreach (var enc in table)
|
||||
{
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
if (evo.Species != enc.Species)
|
||||
continue;
|
||||
yield return enc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<EncounterTradeGB> GetValidEncounterTradesVC(PKM pk, EvoCriteria[] chain, GameVersion game)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static PKHeX.Core.EncounterEvent;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -15,9 +14,16 @@ public static class MysteryGiftGenerator
|
|||
yield return RangerManaphy;
|
||||
|
||||
var table = GetTable(gen, game);
|
||||
var possible = table.Where(wc => chain.Any(evo => evo.Species == wc.Species));
|
||||
foreach (var enc in possible)
|
||||
yield return enc;
|
||||
foreach (var enc in table)
|
||||
{
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
if (evo.Species != enc.Species)
|
||||
continue;
|
||||
yield return enc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<MysteryGift> GetValidGifts(PKM pk, EvoCriteria[] chain, GameVersion game)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using static PKHeX.Core.GameVersion;
|
||||
|
||||
|
@ -28,8 +27,8 @@ public static class EncounterSuggestion
|
|||
if (s is null)
|
||||
return GetSuggestedEncounter(pk, w, loc);
|
||||
|
||||
bool isDefinitelySlot = chain.Any(z => z.Species == w.Species && z.Form == w.Form);
|
||||
bool isDefinitelyStatic = chain.Any(z => z.Species == s.Species && z.Form == s.Form);
|
||||
bool isDefinitelySlot = Array.Exists(chain, z => z.Species == w.Species && z.Form == w.Form);
|
||||
bool isDefinitelyStatic = Array.Exists(chain, z => z.Species == s.Species && z.Form == s.Form);
|
||||
IEncounterable obj = (isDefinitelySlot || !isDefinitelyStatic) ? w : s;
|
||||
return GetSuggestedEncounter(pk, obj, loc);
|
||||
}
|
||||
|
@ -108,12 +107,20 @@ public static class EncounterSuggestion
|
|||
{
|
||||
var evos = table.GetValidPreEvolutions(pk, levelMax: i, skipChecks: true, levelMin: startLevel);
|
||||
if (evos.Length < count) // lost an evolution, prior level was minimum current level
|
||||
return evos.Max(evo => evo.LevelMax) + 1;
|
||||
return GetMaxLevelMax(evos) + 1;
|
||||
count = evos.Length;
|
||||
}
|
||||
return startLevel;
|
||||
}
|
||||
|
||||
private static int GetMaxLevelMax(EvoCriteria[] evos)
|
||||
{
|
||||
int max = 0;
|
||||
foreach (var evo in evos)
|
||||
max = Math.Max(evo.LevelMax, max);
|
||||
return max;
|
||||
}
|
||||
|
||||
public static bool IterateMinimumCurrentLevel(PKM pk, bool isLegal, int max = 100)
|
||||
{
|
||||
var original = pk.CurrentLevel;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
|
@ -13,7 +12,7 @@ public static class MoveListSuggest
|
|||
return MoveList.GetBaseEggMoves(pk, pk.Species, 0, (GameVersion)pk.Version, pk.CurrentLevel);
|
||||
|
||||
if (types != MoveSourceType.None)
|
||||
return GetValidMoves(pk, enc, evoChains, types).ToArray();
|
||||
return GetValidMoves(pk, enc, evoChains, types);
|
||||
|
||||
// try to give current moves
|
||||
if (enc.Generation <= 2)
|
||||
|
@ -28,22 +27,28 @@ public static class MoveListSuggest
|
|||
return MoveLevelUp.GetEncounterMoves(pk.Species, pk.Form, pk.CurrentLevel, (GameVersion)pk.Version);
|
||||
}
|
||||
|
||||
return GetValidMoves(pk, enc, evoChains, types).ToArray();
|
||||
return GetValidMoves(pk, enc, evoChains, types);
|
||||
}
|
||||
|
||||
private static IEnumerable<int> GetValidMoves(PKM pk, IEncounterTemplate enc, EvolutionHistory evoChains, MoveSourceType types = MoveSourceType.ExternalSources)
|
||||
private static int[] GetValidMoves(PKM pk, IEncounterTemplate enc, EvolutionHistory evoChains, MoveSourceType types = MoveSourceType.ExternalSources)
|
||||
{
|
||||
var length = pk.MaxMoveID + 1;
|
||||
bool[] rent = ArrayPool<bool>.Shared.Rent(length);
|
||||
LearnPossible.Get(pk, enc, evoChains, rent, types);
|
||||
var span = rent.AsSpan(0, length);
|
||||
LearnPossible.Get(pk, enc, evoChains, span, types);
|
||||
|
||||
for (int i = 1; i < length; i++)
|
||||
var count = span[1..].Count(true);
|
||||
var result = new int[count];
|
||||
int ctr = 0;
|
||||
for (int i = 1; i < span.Length; i++)
|
||||
{
|
||||
if (rent[i])
|
||||
yield return i;
|
||||
result[ctr++] = i;
|
||||
}
|
||||
|
||||
ArrayPool<bool>.Shared.Return(rent, true);
|
||||
span.Clear();
|
||||
ArrayPool<bool>.Shared.Return(rent);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -135,11 +140,13 @@ public static class MoveListSuggest
|
|||
return result;
|
||||
|
||||
// Try again with the other split-breed species if possible.
|
||||
var incense = EncounterEggGenerator.GenerateEggs(tmp, generation).FirstOrDefault();
|
||||
if (incense is null || incense.Species == enc.Species)
|
||||
return result;
|
||||
|
||||
return incense.GetEggRelearnMoves(parse, pk);
|
||||
var other = EncounterEggGenerator.GenerateEggs(tmp, generation);
|
||||
foreach (var incense in other)
|
||||
{
|
||||
if (incense.Species != enc.Species)
|
||||
return incense.GetEggRelearnMoves(parse, pk);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int[] GetEggRelearnMoves(this IEncounterTemplate enc, ReadOnlySpan<MoveResult> parse, PKM pk)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static PKHeX.Core.PIDType;
|
||||
|
||||
|
@ -364,7 +363,7 @@ public static class MethodFinder
|
|||
(int species, int genderValue) = GetCuteCharmGenderSpecies(pk, pid, pk.Species);
|
||||
if ((uint)species > Legal.MaxSpeciesID_4)
|
||||
return GetNonMatch(out pidiv);
|
||||
|
||||
|
||||
static int getRatio(int species) => PersonalTable.HGSS[species].Gender;
|
||||
switch (genderValue)
|
||||
{
|
||||
|
@ -669,9 +668,15 @@ public static class MethodFinder
|
|||
Debug.Assert(b >> 15 == 0);
|
||||
uint second = a << 16;
|
||||
uint first = b << 16;
|
||||
var pairs = method.RecoverLower16Bits(first, second)
|
||||
.Concat(method.RecoverLower16Bits(first, second ^ 0x80000000));
|
||||
foreach (var z in pairs)
|
||||
|
||||
var attempt1 = method.RecoverLower16Bits(first, second);
|
||||
foreach (var z in attempt1)
|
||||
{
|
||||
yield return z;
|
||||
yield return z ^ 0x80000000; // sister bitflip
|
||||
}
|
||||
var attempt2 = method.RecoverLower16Bits(first, second ^ 0x80000000);
|
||||
foreach (var z in attempt2)
|
||||
{
|
||||
yield return z;
|
||||
yield return z ^ 0x80000000; // sister bitflip
|
||||
|
@ -684,9 +689,14 @@ public static class MethodFinder
|
|||
Debug.Assert(rand3 >> 15 == 0);
|
||||
rand1 <<= 16;
|
||||
rand3 <<= 16;
|
||||
var seeds = method.RecoverLower16BitsGap(rand1, rand3)
|
||||
.Concat(method.RecoverLower16BitsGap(rand1, rand3 ^ 0x80000000));
|
||||
foreach (var z in seeds)
|
||||
var attempt1 = method.RecoverLower16Bits(rand1, rand3);
|
||||
foreach (var z in attempt1)
|
||||
{
|
||||
yield return z;
|
||||
yield return z ^ 0x80000000; // sister bitflip
|
||||
}
|
||||
var attempt2 = method.RecoverLower16Bits(rand1, rand3 ^ 0x80000000);
|
||||
foreach (var z in attempt2)
|
||||
{
|
||||
yield return z;
|
||||
yield return z ^ 0x80000000; // sister bitflip
|
||||
|
@ -824,25 +834,27 @@ public static class MethodFinder
|
|||
{
|
||||
WC3 g => IsCompatible3Mystery(val, pk, g),
|
||||
EncounterStatic3 s => IsCompatible3Static(val, pk, s),
|
||||
EncounterSlot3 w => (w.Species == (int)Species.Unown ? MethodH_Unown : MethodH).Contains(val),
|
||||
EncounterStaticShadow => val is CXD or CXDAnti,
|
||||
EncounterSlot3PokeSpot => val == PokeSpot,
|
||||
_ => val == None,
|
||||
EncounterStaticShadow => val is (CXD or CXDAnti),
|
||||
EncounterSlot3PokeSpot => val is PokeSpot,
|
||||
EncounterSlot3 w => w.Species != (int)Species.Unown
|
||||
? val is (Method_1 or Method_2 or Method_3 or Method_4)
|
||||
: val is (Method_1_Unown or Method_2_Unown or Method_3_Unown or Method_4_Unown),
|
||||
_ => val is None,
|
||||
};
|
||||
|
||||
private static bool IsCompatible3Static(PIDType val, PKM pk, EncounterStatic3 s) => pk.Version switch
|
||||
{
|
||||
(int)GameVersion.CXD => val is CXD or CXD_ColoStarter or CXDAnti,
|
||||
(int)GameVersion.E => val == Method_1, // no roamer glitch
|
||||
(int)GameVersion.FR or (int) GameVersion.LG => s.Roaming ? val.IsRoamerPIDIV(pk) : val == Method_1, // roamer glitch
|
||||
_ => s.Roaming ? val.IsRoamerPIDIV(pk) : MethodH14.Contains(val), // RS, roamer glitch && RSBox s/w emulation => method 4 available
|
||||
(int)GameVersion.CXD => val is (CXD or CXD_ColoStarter or CXDAnti),
|
||||
(int)GameVersion.E => val is Method_1, // no roamer glitch
|
||||
(int)GameVersion.FR or (int) GameVersion.LG => s.Roaming ? val.IsRoamerPIDIV(pk) : val is Method_1, // roamer glitch
|
||||
_ => s.Roaming ? val.IsRoamerPIDIV(pk) : val is (Method_1 or Method_4), // RS, roamer glitch && RSBox s/w emulation => method 4 available
|
||||
};
|
||||
|
||||
private static bool IsCompatible3Mystery(PIDType val, PKM pk, WC3 g) => val == g.Method || val switch
|
||||
{
|
||||
// forced shiny eggs, when hatched, can lose their detectable correlation.
|
||||
None => (g.Method is BACD_R_S or BACD_U_S) && g.IsEgg && !pk.IsEgg,
|
||||
CXDAnti => g.Method == CXD && g.Shiny == Shiny.Never,
|
||||
None => (g.Method is (BACD_R_S or BACD_U_S)) && g.IsEgg && !pk.IsEgg,
|
||||
CXDAnti => g.Method is CXD && g.Shiny == Shiny.Never,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
@ -864,24 +876,24 @@ public static class MethodFinder
|
|||
{
|
||||
// Pokewalker can sometimes be confused with CuteCharm due to the PID creation routine. Double check if it is okay.
|
||||
EncounterStatic4Pokewalker when val is CuteCharm => GetCuteCharmMatch(pk, pk.EncryptionConstant, out _) && IsCuteCharm4Valid(encounter, pk),
|
||||
EncounterStatic4Pokewalker => val == Pokewalker,
|
||||
EncounterStatic4Pokewalker => val is Pokewalker,
|
||||
|
||||
EncounterStatic4 {Species: (int)Species.Pichu} => val == Pokewalker,
|
||||
EncounterStatic4 {Shiny: Shiny.Always} => val == ChainShiny,
|
||||
EncounterStatic4 {Species: (int)Species.Pichu} => val is Pokewalker,
|
||||
EncounterStatic4 {Shiny: Shiny.Always} => val is ChainShiny,
|
||||
EncounterStatic4 when val is CuteCharm => IsCuteCharm4Valid(encounter, pk),
|
||||
EncounterStatic4 => val == Method_1,
|
||||
EncounterStatic4 => val is Method_1,
|
||||
|
||||
EncounterSlot4 w => val switch
|
||||
{
|
||||
// Chain shiny with Poké Radar is only possible in DPPt, in grass. Safari Zone does not allow using the Poké Radar
|
||||
ChainShiny => pk.IsShiny && !pk.HGSS && (w.GroundTile & GroundTileAllowed.Grass) != 0 && !Locations.IsSafariZoneLocation4(w.Location),
|
||||
CuteCharm => IsCuteCharm4Valid(encounter, pk),
|
||||
_ => val == Method_1,
|
||||
_ => val is Method_1,
|
||||
},
|
||||
|
||||
PGT => IsG4ManaphyPIDValid(val, pk), // Manaphy is the only PGT in the database
|
||||
PCD d when d.Gift.PK.PID != 1 => true, // Already matches PCD's fixed PID requirement
|
||||
_ => val == None,
|
||||
_ => val is None,
|
||||
};
|
||||
|
||||
private static bool IsG4ManaphyPIDValid(PIDType val, PKM pk)
|
||||
|
@ -945,8 +957,4 @@ public static class MethodFinder
|
|||
|
||||
_ => (currentSpecies, pk.Gender),
|
||||
};
|
||||
|
||||
private static readonly PIDType[] MethodH = { Method_1, Method_2, Method_3, Method_4 };
|
||||
private static readonly PIDType[] MethodH14 = { Method_1, Method_4 };
|
||||
private static readonly PIDType[] MethodH_Unown = { Method_1_Unown, Method_2_Unown, Method_3_Unown, Method_4_Unown };
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using static PKHeX.Core.Legal;
|
||||
using static PKHeX.Core.GameVersion;
|
||||
|
@ -162,7 +161,7 @@ internal static class GBRestrictions
|
|||
if (!matchAny)
|
||||
return PotentialGBOrigin.Either;
|
||||
|
||||
if (HeldItems_GSC.Contains(catch_rate))
|
||||
if (IsTradebackCatchRate(catch_rate))
|
||||
return PotentialGBOrigin.Either;
|
||||
|
||||
return PotentialGBOrigin.Gen1Only;
|
||||
|
@ -221,7 +220,7 @@ internal static class GBRestrictions
|
|||
_ => RateMatchesEncounter(enc.Species, enc.Version, pk1.Catch_Rate),
|
||||
};
|
||||
|
||||
public static bool IsTradebackCatchRate(byte rate) => HeldItems_GSC.Contains(rate);
|
||||
public static bool IsTradebackCatchRate(byte rate) => Array.IndexOf(HeldItems_GSC, rate) != -1;
|
||||
}
|
||||
|
||||
public enum PotentialGBOrigin
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
using static PKHeX.Core.LanguageID;
|
||||
|
||||
|
@ -92,9 +91,11 @@ public sealed class NicknameVerifier : Verifier
|
|||
{
|
||||
// Gen3 gifts transferred to Generation 4 from another language can set the nickname flag.
|
||||
var evos = data.Info.EvoChainsAllGens.Gen3;
|
||||
bool matchAny = evos.Any(evo => !SpeciesName.IsNicknamedAnyLanguage(evo.Species, nickname, 3));
|
||||
if (matchAny)
|
||||
return;
|
||||
foreach (var evo in evos)
|
||||
{
|
||||
if (!SpeciesName.IsNicknamedAnyLanguage(evo.Species, nickname, 3))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pk.IsNicknamed)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.EReaderBerryMatch;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -15,7 +16,7 @@ public static class EReaderBerrySettings
|
|||
private static string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary> e-Reader Berry Name formatted in Title Case </summary>
|
||||
public static string DisplayName => string.Format(LegalityCheckStrings.L_XEnigmaBerry_0, Util.ToTitleCase(Name));
|
||||
public static string DisplayName => string.Format(LegalityCheckStrings.L_XEnigmaBerry_0, Util.ToTitleCase(Name.AsSpan()));
|
||||
|
||||
private static int Language { get; set; }
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
|
@ -49,7 +49,7 @@ public sealed class Record3
|
|||
for (int i = 0; i < result.Length; i++)
|
||||
{
|
||||
var replaced = names[i].Replace('_', ' ');
|
||||
var titled = Util.ToTitleCase(replaced);
|
||||
var titled = Util.ToTitleCase(replaced.AsSpan());
|
||||
result[i] = new ComboItem(titled, values[i]);
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
|
@ -162,19 +161,73 @@ public static partial class Util
|
|||
private static bool IsHexUpper(char c) => (uint)(c - 'A') <= 5;
|
||||
private static bool IsHexLower(char c) => (uint)(c - 'a') <= 5;
|
||||
private static bool IsHex(char c) => IsNum(c) || IsHexUpper(c) || IsHexLower(c);
|
||||
private static string TitleCase(string word) => char.ToUpper(word[0]) + word[1..].ToLower();
|
||||
|
||||
/// <summary>
|
||||
/// Filters the string down to only valid hex characters, returning a new string.
|
||||
/// </summary>
|
||||
/// <param name="str">Input string to filter</param>
|
||||
public static string GetOnlyHex(string str) => string.IsNullOrWhiteSpace(str) ? string.Empty : string.Concat(str.Where(IsHex));
|
||||
public static string GetOnlyHex(string str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return string.Empty;
|
||||
var sb = new StringBuilder(str.Length);
|
||||
foreach (var c in str)
|
||||
{
|
||||
if (IsHex(c))
|
||||
sb.Append(c);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new string with each word converted to its appropriate title case.
|
||||
/// </summary>
|
||||
/// <param name="str">Input string to modify</param>
|
||||
public static string ToTitleCase(string str) => string.IsNullOrWhiteSpace(str) ? string.Empty : string.Join(" ", str.Split(' ').Select(TitleCase));
|
||||
/// <param name="trim">Trim ends of whitespace</param>
|
||||
public static string ToTitleCase(ReadOnlySpan<char> str, bool trim = false)
|
||||
{
|
||||
int start = 0;
|
||||
if (trim)
|
||||
{
|
||||
// Get First index that isn't a space
|
||||
while (start < str.Length && char.IsWhiteSpace(str[start]))
|
||||
start++;
|
||||
}
|
||||
if (start == str.Length)
|
||||
return string.Empty;
|
||||
|
||||
int end = str.Length - 1;
|
||||
if (trim)
|
||||
{
|
||||
// Get Last index that isn't a space
|
||||
while (end > start && char.IsWhiteSpace(str[end]))
|
||||
end--;
|
||||
}
|
||||
|
||||
var span = str.Slice(start, end - start + 1);
|
||||
var sb = new StringBuilder(span.Length);
|
||||
// Add each word to the string builder. Continue from the first index that isn't a space.
|
||||
// Add the first character as uppercase, then add each successive character as lowercase.
|
||||
bool first = true;
|
||||
foreach (char c in span)
|
||||
{
|
||||
if (char.IsWhiteSpace(c))
|
||||
{
|
||||
first = true;
|
||||
sb.Append(c);
|
||||
}
|
||||
else if (first)
|
||||
{
|
||||
sb.Append(char.ToUpper(c));
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(char.ToLower(c));
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trims a string at the first instance of a 0x0000 terminator.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using PKHeX.Drawing;
|
||||
using PKHeX.WinForms.Properties;
|
||||
|
@ -17,7 +16,8 @@ public partial class ShinyLeaf : UserControl
|
|||
|
||||
private readonly CheckBox[] Flags;
|
||||
|
||||
public void CheckAll(bool all = true) => SetValue(all ? 0b00111111 : 0);
|
||||
private const byte CrownAndFiveLeafs = 0b00_1_11111;
|
||||
public void CheckAll(bool all = true) => SetValue(all ? CrownAndFiveLeafs : 0);
|
||||
|
||||
public int GetValue()
|
||||
{
|
||||
|
@ -51,11 +51,21 @@ public partial class ShinyLeaf : UserControl
|
|||
resource = Resources.leaf;
|
||||
if (!c.Checked)
|
||||
CHK_C.Checked = CHK_C.Enabled = false;
|
||||
else if (Flags.Take(5).All(z => z.Checked))
|
||||
else if (HasAllFiveLeafs())
|
||||
CHK_C.Enabled = true;
|
||||
}
|
||||
if (!c.Checked)
|
||||
resource = ImageUtil.ChangeOpacity(resource, 0.4);
|
||||
c.Image = resource;
|
||||
}
|
||||
|
||||
private bool HasAllFiveLeafs()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (!Flags[i].Checked)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue