2018-08-17 03:06:40 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
namespace PKHeX.Core.Searching;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <see cref="PKM"/> searching utility
|
|
|
|
/// </summary>
|
|
|
|
public static class SearchUtil
|
2018-08-17 03:06:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
// Future: Might need to clamp down further for generations that cannot exist in the current format.
|
|
|
|
public static bool SatisfiesFilterFormat(PKM pk, int format, SearchComparison formatOperand) => formatOperand switch
|
2018-08-17 03:06:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
SearchComparison.GreaterThanEquals when pk.Format < format => false,
|
|
|
|
SearchComparison.Equals when pk.Format != format => false,
|
|
|
|
SearchComparison.LessThanEquals when pk.Format > format => false,
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
_ when format <= 2 => pk.Format <= 2, // 1-2
|
|
|
|
_ when format <= 6 => pk.Format >= 3, // 3-6
|
|
|
|
_ => true,
|
|
|
|
};
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static bool SatisfiesFilterGeneration(PKM pk, int generation) => generation switch
|
|
|
|
{
|
|
|
|
1 => pk.VC || pk.Format < 3,
|
|
|
|
2 => pk.VC || pk.Format < 3,
|
|
|
|
_ => pk.Generation == generation,
|
|
|
|
};
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static bool SatisfiesFilterLevel(PKM pk, SearchComparison option, int level)
|
|
|
|
{
|
|
|
|
if (level > 100)
|
|
|
|
return true; // why???
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
return option switch
|
2018-08-17 03:06:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
SearchComparison.LessThanEquals => pk.Stat_Level <= level,
|
|
|
|
SearchComparison.Equals => pk.Stat_Level == level,
|
|
|
|
SearchComparison.GreaterThanEquals => pk.Stat_Level >= level,
|
2021-08-20 20:49:20 +00:00
|
|
|
_ => true,
|
2021-01-02 01:08:49 +00:00
|
|
|
};
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2021-01-02 01:08:49 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static bool SatisfiesFilterEVs(PKM pk, int option) => option switch
|
|
|
|
{
|
|
|
|
1 => pk.EVTotal == 0, // None (0)
|
|
|
|
2 => pk.EVTotal is (not 0) and < 128, // Some (127-1)
|
|
|
|
3 => pk.EVTotal is >= 128 and < 508, // Half (128-507)
|
|
|
|
4 => pk.EVTotal >= 508, // Full (508+)
|
|
|
|
_ => true,
|
|
|
|
};
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static bool SatisfiesFilterIVs(PKM pk, int option) => option switch
|
|
|
|
{
|
|
|
|
1 => pk.IVTotal <= 90, // <= 90
|
|
|
|
2 => pk.IVTotal is > 90 and <= 120, // 91-120
|
|
|
|
3 => pk.IVTotal is > 120 and <= 150, // 121-150
|
|
|
|
4 => pk.IVTotal is > 150 and < 180, // 151-179
|
|
|
|
5 => pk.IVTotal >= 180, // 180+
|
|
|
|
6 => pk.IVTotal == 186, // == 186
|
|
|
|
_ => true,
|
|
|
|
};
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-08-05 18:23:28 +00:00
|
|
|
public static bool SatisfiesFilterMoves(PKM pk, IReadOnlyList<int> requiredMoves)
|
2022-06-18 18:04:24 +00:00
|
|
|
{
|
|
|
|
foreach (var m in requiredMoves)
|
2018-08-17 03:06:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
if (!pk.HasMove(m))
|
|
|
|
return false;
|
2018-08-17 03:06:40 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static bool SatisfiesFilterBatchInstruction(PKM pk, IReadOnlyList<StringInstruction> filters)
|
|
|
|
{
|
|
|
|
return BatchEditing.IsFilterMatch(filters, pk); // Compare across all filters
|
|
|
|
}
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static Func<PKM, string> GetCloneDetectMethod(CloneDetectionMethod method) => method switch
|
|
|
|
{
|
|
|
|
CloneDetectionMethod.HashPID => HashByPID,
|
|
|
|
_ => HashByDetails,
|
|
|
|
};
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static string HashByDetails(PKM pk) => pk.Format switch
|
|
|
|
{
|
|
|
|
1 => $"{pk.Species:000}{((PK1) pk).DV16:X4}",
|
|
|
|
2 => $"{pk.Species:000}{((PK2) pk).DV16:X4}",
|
2022-08-05 18:23:28 +00:00
|
|
|
_ => $"{pk.Species:000}{pk.PID:X8}{GetIVString(pk)}{pk.Form:00}",
|
2022-06-18 18:04:24 +00:00
|
|
|
};
|
|
|
|
|
2022-08-05 18:23:28 +00:00
|
|
|
// use a space so we don't merge single digit IVs and potentially get incorrect collisions
|
|
|
|
private static string GetIVString(PKM pk) => $"{pk.IV_HP} {pk.IV_ATK} {pk.IV_DEF} {pk.IV_SPE} {pk.IV_SPA} {pk.IV_SPD}";
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static string HashByPID(PKM pk) => pk.Format switch
|
|
|
|
{
|
|
|
|
1 => $"{((PK1) pk).DV16:X4}",
|
|
|
|
2 => $"{((PK2) pk).DV16:X4}",
|
|
|
|
_ => $"{pk.PID:X8}",
|
|
|
|
};
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static IEnumerable<PKM> GetClones(IEnumerable<PKM> res, CloneDetectionMethod type = CloneDetectionMethod.HashDetails)
|
|
|
|
{
|
|
|
|
var method = GetCloneDetectMethod(type);
|
|
|
|
return GetExtraClones(res, method);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static IEnumerable<T> GetUniques<T>(IEnumerable<T> db, Func<T, string> method)
|
|
|
|
{
|
|
|
|
var hs = new HashSet<string>();
|
|
|
|
foreach (var t in db)
|
2018-08-17 03:06:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
var hash = method(t);
|
|
|
|
if (hs.Contains(hash))
|
|
|
|
continue;
|
|
|
|
yield return t;
|
|
|
|
hs.Add(hash);
|
2018-08-17 03:06:40 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2018-08-17 03:06:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static IEnumerable<T> GetExtraClones<T>(IEnumerable<T> db, Func<T, string> method)
|
|
|
|
{
|
|
|
|
var hs = new HashSet<string>();
|
|
|
|
foreach (var t in db)
|
2018-08-17 03:06:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
var hash = method(t);
|
|
|
|
if (hs.Contains(hash))
|
2022-04-17 21:58:52 +00:00
|
|
|
yield return t;
|
2022-06-18 18:04:24 +00:00
|
|
|
else
|
Track a PKM's Box,Slot,StorageFlags,Identifier metadata separately (#3222)
* Track a PKM's Box,Slot,StorageFlags,Identifier metadata separately
Don't store within the object, track the slot origin data separately.
Batch editing now pre-filters if using Box/Slot/Identifier logic; split up mods/filters as they're starting to get pretty hefty.
- Requesting a Box Data report now shows all slots in the save file (party, misc)
- Can now exclude backup saves from database search via toggle (separate from settings preventing load entirely)
- Replace some linq usages with direct code
* Remove WasLink virtual in PKM
Inline any logic, since we now have encounter objects to indicate matching, rather than the proto-legality logic checking properties of a PKM.
* Use Fateful to directly check gen5 mysterygift origins
No other encounter types in gen5 apply Fateful
* Simplify double ball comparison
Used to be separate for deferral cases, now no longer needed to be separate.
* Grab move/relearn reference and update locally
Fix relearn move identifier
* Inline defog HM transfer preference check
HasMove is faster than getting moves & checking contains. Skips allocation by setting values directly.
* Extract more met location metadata checks: WasBredEgg
* Replace Console.Write* with Debug.Write*
There's no console output UI, so don't include them in release builds.
* Inline WasGiftEgg, WasEvent, and WasEventEgg logic
Adios legality tags that aren't entirely correct for the specific format. Just put the computations in EncounterFinder.
2021-06-23 03:23:48 +00:00
|
|
|
hs.Add(hash);
|
2018-08-17 03:06:40 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-17 21:58:52 +00:00
|
|
|
}
|