mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-07-08 09:43:51 -05:00
Refactoring
Catch_Rate => CatchRate Make Location* classes public Extract a few methods, make public Merge EncounterUtil & EncounterUtil1 add xmldoc add missing deferral for Nest8 templates improve binlinker span fetch to a single read (-1)
This commit is contained in:
parent
cca9d55013
commit
8fa951bcd7
|
|
@ -75,13 +75,15 @@ public static int ApplyBallNext(PKM pk)
|
|||
|
||||
private static int ApplyFirstLegalBall(PKM pk, ReadOnlySpan<Ball> balls)
|
||||
{
|
||||
var initial = pk.Ball;
|
||||
foreach (var b in balls)
|
||||
{
|
||||
pk.Ball = (int)b;
|
||||
var test = (int)b;
|
||||
pk.Ball = test;
|
||||
if (new LegalityAnalysis(pk).Valid)
|
||||
break;
|
||||
return test;
|
||||
}
|
||||
return pk.Ball;
|
||||
return initial; // fail, revert
|
||||
}
|
||||
|
||||
private static int GetBallList(int ball, Span<Ball> result)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Logic for applying a <see cref="PK1.Catch_Rate"/> value.
|
||||
/// Logic for applying a <see cref="PK1.CatchRate"/> value.
|
||||
/// </summary>
|
||||
public static class CatchRateApplicator
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the suggested <see cref="PK1.Catch_Rate"/> for the entity.
|
||||
/// Gets the suggested <see cref="PK1.CatchRate"/> for the entity.
|
||||
/// </summary>
|
||||
public static int GetSuggestedCatchRate(PK1 pk, SaveFile sav)
|
||||
{
|
||||
|
|
@ -15,13 +15,13 @@ public static int GetSuggestedCatchRate(PK1 pk, SaveFile sav)
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the suggested <see cref="PK1.Catch_Rate"/> for the entity.
|
||||
/// Gets the suggested <see cref="PK1.CatchRate"/> for the entity.
|
||||
/// </summary>
|
||||
public static byte GetSuggestedCatchRate(PK1 pk, SaveFile sav, LegalityAnalysis la)
|
||||
{
|
||||
// If it is already valid, just use the current value.
|
||||
if (la.Valid)
|
||||
return pk.Catch_Rate;
|
||||
return pk.CatchRate;
|
||||
|
||||
// If it has ever visited generation 2, the Held Item can be removed prior to trade back.
|
||||
if (la.Info.Generation == 2)
|
||||
|
|
@ -36,7 +36,7 @@ public static byte GetSuggestedCatchRate(PK1 pk, SaveFile sav, LegalityAnalysis
|
|||
default:
|
||||
var pt = GetPersonalTable(sav, enc.Version);
|
||||
var pi = pt[enc.Species];
|
||||
return (byte)pi.CatchRate;
|
||||
return pi.CatchRate;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -232,69 +232,68 @@ public IReadOnlyList<ComboItem> GetLocationList(GameVersion version, EntityConte
|
|||
return result;
|
||||
}
|
||||
|
||||
private IReadOnlyList<ComboItem> GetLocationListInternal(GameVersion version, EntityContext context)
|
||||
private IReadOnlyList<ComboItem> GetLocationListInternal(GameVersion version, EntityContext context) => version switch
|
||||
{
|
||||
return version switch
|
||||
{
|
||||
CXD when context == EntityContext.Gen3 => MetGen3CXD,
|
||||
R or S when context == EntityContext.Gen3 => Partition1(MetGen3, IsMetLocation3RS),
|
||||
E when context == EntityContext.Gen3 => Partition1(MetGen3, IsMetLocation3E),
|
||||
FR or LG when context == EntityContext.Gen3 => Partition1(MetGen3, IsMetLocation3FRLG),
|
||||
D or P when context == EntityContext.Gen4 => Partition2(MetGen4, IsMetLocation4DP, 4),
|
||||
Pt when context == EntityContext.Gen4 => Partition2(MetGen4, IsMetLocation4Pt, 4),
|
||||
HG or SS when context == EntityContext.Gen4 => Partition2(MetGen4, IsMetLocation4HGSS, 4),
|
||||
CXD when context == EntityContext.Gen3 => MetGen3CXD,
|
||||
R or S when context == EntityContext.Gen3 => Partition1(MetGen3, IsMetLocation3RS),
|
||||
E when context == EntityContext.Gen3 => Partition1(MetGen3, IsMetLocation3E),
|
||||
FR or LG when context == EntityContext.Gen3 => Partition1(MetGen3, IsMetLocation3FRLG),
|
||||
D or P when context == EntityContext.Gen4 => Partition2(MetGen4, IsMetLocation4DP, 4),
|
||||
Pt when context == EntityContext.Gen4 => Partition2(MetGen4, IsMetLocation4Pt, 4),
|
||||
HG or SS when context == EntityContext.Gen4 => Partition2(MetGen4, IsMetLocation4HGSS, 4),
|
||||
|
||||
B or W => Partition2(MetGen5, IsMetLocation5BW), // Abyssal Ruins
|
||||
B2 or W2 => MetGen5,
|
||||
X or Y => Partition2(MetGen6, IsMetLocation6XY),
|
||||
OR or AS => Partition2(MetGen6, IsMetLocation6AO),
|
||||
SN or MN => Partition2(MetGen7, IsMetLocation7SM),
|
||||
US or UM
|
||||
or RD or BU or GN or YW
|
||||
or GD or SI or C => Partition2(MetGen7, IsMetLocation7USUM),
|
||||
GP or GE or GO => Partition2(MetGen7GG, IsMetLocation7GG),
|
||||
SW or SH => Partition2(MetGen8, IsMetLocation8SWSH),
|
||||
BD or SP => Partition2(MetGen8b, IsMetLocation8BDSP),
|
||||
PLA => Partition2(MetGen8a, IsMetLocation8LA),
|
||||
SL or VL => Partition2(MetGen9, IsMetLocation9SV),
|
||||
_ => GetLocationListModified(version, context),
|
||||
};
|
||||
B or W => Partition2(MetGen5, IsMetLocation5BW), // Abyssal Ruins
|
||||
B2 or W2 => MetGen5,
|
||||
|
||||
static ComboItem[] Partition1(List<ComboItem> list, Func<ushort, bool> criteria)
|
||||
X or Y => Partition2(MetGen6, IsMetLocation6XY),
|
||||
OR or AS => Partition2(MetGen6, IsMetLocation6AO),
|
||||
SN or MN => Partition2(MetGen7, IsMetLocation7SM),
|
||||
US or UM
|
||||
or RD or BU or GN or YW
|
||||
or GD or SI or C => Partition2(MetGen7, IsMetLocation7USUM),
|
||||
|
||||
GP or GE or GO => Partition2(MetGen7GG, IsMetLocation7GG),
|
||||
SW or SH => Partition2(MetGen8, IsMetLocation8SWSH),
|
||||
BD or SP => Partition2(MetGen8b, IsMetLocation8BDSP),
|
||||
PLA => Partition2(MetGen8a, IsMetLocation8LA),
|
||||
SL or VL => Partition2(MetGen9, IsMetLocation9SV),
|
||||
_ => GetLocationListModified(version, context),
|
||||
};
|
||||
|
||||
private static ComboItem[] Partition1(List<ComboItem> list, Func<ushort, bool> criteria)
|
||||
{
|
||||
var span = CollectionsMarshal.AsSpan(list);
|
||||
var result = new ComboItem[list.Count];
|
||||
ReorderList(span, result, criteria);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ComboItem[] Partition2(List<ComboItem> list, Func<ushort, bool> criteria, int keepFirst = 3)
|
||||
{
|
||||
var span = CollectionsMarshal.AsSpan(list);
|
||||
var result = new ComboItem[span.Length];
|
||||
for (int i = 0; i < keepFirst; i++)
|
||||
result[i] = list[i];
|
||||
ReorderList(span, result, criteria, keepFirst);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void ReorderList(Span<ComboItem> list, Span<ComboItem> result, Func<ushort, bool> criteria, int start = 0)
|
||||
{
|
||||
// store values that match criteria at the next available position of the array
|
||||
// store non-matches starting at the end. reverse before returning
|
||||
int end = list.Length - 1;
|
||||
for (var index = start; index < list.Length; index++)
|
||||
{
|
||||
var span = CollectionsMarshal.AsSpan(list);
|
||||
var result = new ComboItem[list.Count];
|
||||
ReorderList(span, result, criteria);
|
||||
return result;
|
||||
var item = list[index];
|
||||
if (criteria((ushort)item.Value))
|
||||
result[start++] = item;
|
||||
else
|
||||
result[end--] = item;
|
||||
}
|
||||
|
||||
static ComboItem[] Partition2(List<ComboItem> list, Func<ushort, bool> criteria, int keepFirst = 3)
|
||||
{
|
||||
var span = CollectionsMarshal.AsSpan(list);
|
||||
var result = new ComboItem[span.Length];
|
||||
for (int i = 0; i < keepFirst; i++)
|
||||
result[i] = list[i];
|
||||
ReorderList(span, result, criteria, keepFirst);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ReorderList(Span<ComboItem> list, Span<ComboItem> result, Func<ushort, bool> criteria, int start = 0)
|
||||
{
|
||||
// store values that match criteria at the next available position of the array
|
||||
// store non-matches starting at the end. reverse before returning
|
||||
int end = list.Length - 1;
|
||||
for (var index = start; index < list.Length; index++)
|
||||
{
|
||||
var item = list[index];
|
||||
if (criteria((ushort)item.Value))
|
||||
result[start++] = item;
|
||||
else
|
||||
result[end--] = item;
|
||||
}
|
||||
|
||||
// since the non-matches are reversed in order, we reverse that section.
|
||||
result[start..].Reverse();
|
||||
}
|
||||
// since the non-matches are reversed in order, we reverse that section.
|
||||
result[start..].Reverse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -129,11 +129,7 @@ public static class Locations
|
|||
|
||||
private const int SafariLocation_RSE = 57;
|
||||
private const int SafariLocation_FRLG = 136;
|
||||
private const int SafariLocation_HGSS = 202;
|
||||
private const int MarshLocation_DPPt = 52;
|
||||
public static bool IsSafariZoneLocation3(int loc) => loc is SafariLocation_RSE or SafariLocation_FRLG;
|
||||
public static bool IsSafariZoneLocation4(int loc) => loc is MarshLocation_DPPt or SafariLocation_HGSS;
|
||||
public static bool IsSafariZoneLocation8b(int loc) => loc is (>= 219 and <= 224);
|
||||
public static bool IsSafariZoneLocation3(byte loc) => loc is SafariLocation_RSE or SafariLocation_FRLG;
|
||||
|
||||
public static bool IsEggLocationBred4(int loc, GameVersion ver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,8 +2,18 @@
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Locations4
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.Gen4"/>.
|
||||
/// </summary>
|
||||
public static class Locations4
|
||||
{
|
||||
private const int SafariLocation_HGSS = 202;
|
||||
private const int MarshLocation_DPPt = 52;
|
||||
public static bool IsSafariZoneLocation(ushort loc) => loc is MarshLocation_DPPt or SafariLocation_HGSS;
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 00000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<byte> Met0 =>
|
||||
[
|
||||
000, 001, 002, 003, 004, 005, 006, 007, 008, 009,
|
||||
|
|
@ -32,13 +42,19 @@ internal static class Locations4
|
|||
230, 231, 232, 233, 234,
|
||||
];
|
||||
|
||||
// Ignore the --- met location at index 7.
|
||||
/// <summary>
|
||||
/// Available location list for the 02000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met2 =>
|
||||
[
|
||||
// Ignore the --- met location at index 7.
|
||||
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009,
|
||||
2010, 2011, 2012, 2013, 2014,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 03000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Locations5
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.Gen5"/>.
|
||||
/// </summary>
|
||||
public static class Locations5
|
||||
{
|
||||
/// <summary>
|
||||
/// Available location list for the 00000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<byte> Met0 =>
|
||||
[
|
||||
001, 002, 004, 005, 006, 007, 008, 009,
|
||||
|
|
@ -24,12 +30,18 @@ internal static class Locations5
|
|||
150, 151, 152, 153,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 30000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
30001, 30002, 30004, 30005, 30006, 30007, 30008,
|
||||
30010, 30011, 30012, 30013, 30014, 30015,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 40000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met4 =>
|
||||
[
|
||||
40001, 40002, 40003, 40004, 40005, 40006, 40007, 40008, 40009,
|
||||
|
|
@ -45,5 +57,8 @@ internal static class Locations5
|
|||
40100, 40101, 40102, 40103, 40104, 40105, 40106, 40107, 40108, 40109,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 60000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met6 => [60001, 60003];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Locations6
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.Gen6"/>.
|
||||
/// </summary>
|
||||
public static class Locations6
|
||||
{
|
||||
/// <summary>
|
||||
/// Available location list for the 00000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met0 =>
|
||||
[
|
||||
/* X/Y */
|
||||
|
|
@ -47,12 +53,18 @@ internal static class Locations6
|
|||
350, 352, 354,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 30000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
30001, 30003, 30004, 30005, 30006, 30007, 30008, 30009,
|
||||
30010, 30011,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 40000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met4 =>
|
||||
[
|
||||
40001, 40002, 40003, 40004, 40005, 40006, 40007, 40008, 40009,
|
||||
|
|
@ -65,5 +77,8 @@ internal static class Locations6
|
|||
40070, 40071, 40072, 40073, 40074, 40075, 40076, 40077, 40078, 40079,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 60000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met6 => [/* X/Y */ 60001, 60003, /* OR/AS */ 60004];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Locations7
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.Gen7"/>.
|
||||
/// </summary>
|
||||
public static class Locations7
|
||||
{
|
||||
/// <summary>
|
||||
/// Available location list for the 00000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<byte> Met0 =>
|
||||
[
|
||||
002, 004, 006, 008,
|
||||
|
|
@ -32,12 +38,18 @@ internal static class Locations7
|
|||
230, 232,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 30000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
30001, 30003, 30004, 30005, 30006, 30007, 30008, 30009,
|
||||
30010, 30011, 30012, 30013, 30014, 30015, 30016, 30017,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 40000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met4 =>
|
||||
[
|
||||
40001, 40002, 40003, 40004, 40005, 40006, 40007, 40008, 40009,
|
||||
|
|
@ -51,5 +63,8 @@ internal static class Locations7
|
|||
40080, 40081, 40082, 40083, 40084, 40085, 40086, 40087, 40088,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 60000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met6 => [/* X/Y */ 60001, 60003, /* OR/AS */ 60004];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Locations7b
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.GG"/>.
|
||||
/// </summary>
|
||||
public static class Locations7b
|
||||
{
|
||||
/// <summary>
|
||||
/// Available location list for the 00000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<byte> Met0 =>
|
||||
[
|
||||
002, 003, 004, 005, 006, 007, 008, 009,
|
||||
|
|
@ -14,12 +20,18 @@ internal static class Locations7b
|
|||
050, 051, 052, 053,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 30000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
30001, 30003, 30004, 30005, 30006, 30007, 30008, 30009,
|
||||
30010, 30011, 30012, 30013, 30014, 30015, 30016, 30017,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 40000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met4 =>
|
||||
[
|
||||
40001, 40002, 40003, 40004, 40005, 40006, 40007, 40008, 40009,
|
||||
|
|
@ -32,5 +44,8 @@ internal static class Locations7b
|
|||
40070, 40071, 40072, 40073, 40074, 40075, 40076, 40077,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 60000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met6 => [/* X/Y */ 60001, 60003, /* OR/AS */ 60004];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Locations8
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.SWSH"/>.
|
||||
/// </summary>
|
||||
public static class Locations8
|
||||
{
|
||||
/// <summary>
|
||||
/// Available location list for the 00000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<byte> Met0 =>
|
||||
[
|
||||
002, 004, 006, 008,
|
||||
|
|
@ -33,12 +39,18 @@ internal static class Locations8
|
|||
240, 242, 244, 246,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 30000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
30001, 30003, 30004, 30005, 30006, 30007, 30008, 30009,
|
||||
30010, 30011, 30012, 30013, 30014, 30015, 30016, 30017, 30018,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 40000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met4 =>
|
||||
[
|
||||
40001, 40002, 40003, 40005, 40006, 40007, 40008, 40009,
|
||||
|
|
@ -52,5 +64,8 @@ internal static class Locations8
|
|||
40080, 40081, 40082, 40083, 40084, 40085, 40086,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 60000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met6 => [/* X/Y */ 60001, 60003, /* OR/AS */ 60004];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Locations8a
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.PLA"/>.
|
||||
/// </summary>
|
||||
public static class Locations8a
|
||||
{
|
||||
/// <summary>
|
||||
/// Available location list for the 00000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<byte> Met0 =>
|
||||
[
|
||||
000, 002, 004, 006, 007, 008, 009,
|
||||
|
|
@ -24,6 +30,9 @@ internal static class Locations8a
|
|||
150, 151, 152, 153, 154, 155,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 30000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
30001, 30002, 30003, 30004, 30005, 30006, 30007, 30008, 30009,
|
||||
|
|
@ -31,6 +40,9 @@ internal static class Locations8a
|
|||
30020, 30021, 30022,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 40000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met4 =>
|
||||
[
|
||||
40001, 40002, 40003, 40005, 40006, 40007, 40008, 40009,
|
||||
|
|
@ -44,5 +56,8 @@ internal static class Locations8a
|
|||
40080, 40081, 40082, 40083, 40084, 40085, 40086,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 60000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met6 => [/* X/Y */ 60001, 60003, /* OR/AS */ 60004];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,28 @@
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Locations8b
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.BDSP"/>.
|
||||
/// </summary>
|
||||
public static class Locations8b
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if the location is a Grand Underground location.
|
||||
/// </summary>
|
||||
/// <param name="location">Location ID to check</param>
|
||||
/// <returns>True if the location is a Grand Underground location</returns>
|
||||
public static bool IsUnderground(ushort location) => location is (>= 508 and <= 617);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the location is a Great Marsh location.
|
||||
/// </summary>
|
||||
/// <param name="location">Location ID to check</param>
|
||||
/// <returns>True if the location is a Great Marsh location</returns>
|
||||
public static bool IsMarsh(ushort location) => location is (>= 219 and <= 224);
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 00000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met0 =>
|
||||
[
|
||||
000, 001, 002, 003, 004, 005, 006, 007, 008, 009,
|
||||
|
|
@ -79,6 +96,9 @@ internal static class Locations8b
|
|||
648, 649, 650, 651, 652, 653, 654, 655, 656, 657,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 30000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
30001, 30003, 30004, 30005, 30006, 30007, 30009,
|
||||
|
|
@ -86,6 +106,9 @@ internal static class Locations8b
|
|||
30020, 30022,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 40000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met4 =>
|
||||
[
|
||||
40001, 40002, 40003, 40005, 40006, 40007, 40008, 40009,
|
||||
|
|
@ -98,5 +121,8 @@ internal static class Locations8b
|
|||
40070, 40071, 40072, 40074, 40075, 40076, 40077,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 60000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met6 => [/* X/Y */ 60001, 60003, /* OR/AS */ 60004, /* BD/SP */ 60005, 60006, 60007, 60010];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.SV"/>.
|
||||
/// </summary>
|
||||
internal static class Locations9
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -24,6 +27,9 @@ internal static class Locations9
|
|||
/// </summary>
|
||||
public static bool IsPaldeaDLC(ushort location) => location is 196 or 198; // Area Zero Underdepths
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 00000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<byte> Met0 =>
|
||||
[
|
||||
002, 004, 006, 008,
|
||||
|
|
@ -52,6 +58,9 @@ internal static class Locations9
|
|||
200,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 30000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
30001, 30003, 30004, 30005, 30006, 30007, 30008, 30009,
|
||||
|
|
@ -59,6 +68,9 @@ internal static class Locations9
|
|||
30020, 30021, 30022, 30023, 30024,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 40000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met4 =>
|
||||
[
|
||||
40001, 40002, 40003, 40004, 40005, 40006, 40007, 40008, 40009,
|
||||
|
|
@ -71,5 +83,8 @@ internal static class Locations9
|
|||
40070, 40071, 40072, 40073, 40074, 40075, 40076, 40077, 40078,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 60000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met6 => [/* X/Y */ 60001, 60003, /* OR/AS */ 60004, /* S/V */ 60005];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace PKHeX.Core;
|
|||
private readonly ReadOnlySpan<byte> Data;
|
||||
|
||||
/// <summary> Total count of files available for accessing. </summary>
|
||||
public int Length => ReadUInt16LittleEndian(Data[2..]);
|
||||
public ushort Length => ReadUInt16LittleEndian(Data[2..]);
|
||||
|
||||
/// <summary> Magic identifier for the file. </summary>
|
||||
public string Identifier => new([(char)Data[0], (char)Data[1]]);
|
||||
|
|
@ -31,8 +31,11 @@ namespace PKHeX.Core;
|
|||
private ReadOnlySpan<byte> GetEntry(int index)
|
||||
{
|
||||
int offset = 4 + (index * sizeof(int));
|
||||
int end = ReadInt32LittleEndian(Data[(offset + 4)..]);
|
||||
int start = ReadInt32LittleEndian(Data[offset..]);
|
||||
// Start and End are both 32-bit integers, sequentially.
|
||||
// Read them in one shot a 64-bit integer and decompose.
|
||||
var startEnd = ReadUInt64LittleEndian(Data[offset..]);
|
||||
int start = (int)startEnd;
|
||||
int end = (int)(startEnd >> 32);
|
||||
return Data[start..end];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
|
@ -7,37 +6,24 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// Miscellaneous setup utility for legality checking <see cref="IEncounterTemplate"/> data sources.
|
||||
/// </summary>
|
||||
internal static class EncounterUtil
|
||||
public static class EncounterUtil
|
||||
{
|
||||
internal static ReadOnlySpan<byte> Get([Length(2, 2)] string resource) => Util.GetBinaryResource($"encounter_{resource}.pkl");
|
||||
internal static BinLinkerAccessor Get([Length(2, 2)] string resource, [Length(2, 2)] ReadOnlySpan<byte> ident) => BinLinkerAccessor.Get(Get(resource), ident);
|
||||
/// <summary> Magic value to indicate the form is dynamic and should not be used literally. </summary>
|
||||
public const byte FormDynamic = FormVivillon;
|
||||
/// <summary> Magic value to indicate the form is set by the save file and can be one of many within the permitted range. </summary>
|
||||
public const byte FormVivillon = 30;
|
||||
/// <summary> Magic value to indicate the form is random and can be one of many within the permitted range. </summary>
|
||||
public const byte FormRandom = 31;
|
||||
|
||||
internal static T? GetMinByLevel<T>(ReadOnlySpan<EvoCriteria> chain, IEnumerable<T> possible) where T : class, IEncounterTemplate
|
||||
{
|
||||
// MinBy grading: prefer species-form match, select lowest min level encounter.
|
||||
// Minimum allocation :)
|
||||
T? result = null;
|
||||
int min = int.MaxValue;
|
||||
/// <summary>
|
||||
/// Gets a raw chunk of data from the specified resource.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<byte> Get([Length(2, 2)] string resource) => Util.GetBinaryResource($"encounter_{resource}.pkl");
|
||||
|
||||
foreach (var enc in possible)
|
||||
{
|
||||
int m = int.MaxValue;
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
bool specDiff = enc.Species != evo.Species || enc.Form != evo.Form;
|
||||
var val = (Convert.ToInt32(specDiff) << 16) | enc.LevelMin;
|
||||
if (val < m)
|
||||
m = val;
|
||||
}
|
||||
|
||||
if (m >= min)
|
||||
continue;
|
||||
min = m;
|
||||
result = enc;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets an index-able accessor for the specified resource.
|
||||
/// </summary>
|
||||
public static BinLinkerAccessor Get([Length(2, 2)] string resource, [Length(2, 2)] ReadOnlySpan<byte> ident) => BinLinkerAccessor.Get(Get(resource), ident);
|
||||
|
||||
/// <summary>
|
||||
/// Grabs the localized names for individual templates for all languages from the specified <see cref="index"/> of the <see cref="names"/> list.
|
||||
|
|
@ -55,4 +41,62 @@ public static string[] GetNamesForLanguage(ReadOnlySpan<string[]> names, uint in
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the encounter moves for the given level and version to the provided PKM.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Entity type</typeparam>
|
||||
/// <param name="pk">Entity to apply the moves to</param>
|
||||
/// <param name="version">Version to apply the moves from</param>
|
||||
/// <param name="level">Level to apply the moves at</param>
|
||||
public static void SetEncounterMoves<T>(T pk, GameVersion version, byte level) where T : PKM
|
||||
{
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
var source = GameData.GetLearnSource(version);
|
||||
source.SetEncounterMoves(pk.Species, pk.Form, level, moves);
|
||||
pk.SetMoves(moves);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Generation 1-3 trainer name ensuring each character is present in the game's available character set.
|
||||
/// </summary>
|
||||
/// <remarks>Only falls back to a valid Name if the language is incompatible with the trainer's language. Doesn't sanity check otherwise.</remarks>
|
||||
/// <param name="tr">Trainer to apply the name from</param>
|
||||
/// <param name="lang">Language to apply the name in</param>
|
||||
public static string GetTrainerName(ITrainerInfo tr, int lang) => lang switch
|
||||
{
|
||||
(int)LanguageID.Japanese => tr.Language == 1 ? tr.OT : "ゲーフリ",
|
||||
_ => tr.Language == 1 ? "GF" : tr.OT,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets a random DV16 value.
|
||||
/// </summary>
|
||||
/// <param name="rand">Random number generator to use</param>
|
||||
/// <returns>Value between 0 and 65535 (inclusive)</returns>
|
||||
public static ushort GetRandomDVs(Random rand) => (ushort)rand.Next(ushort.MaxValue + 1);
|
||||
|
||||
/// <summary>
|
||||
/// Mashes the IVs into a DV16 value.
|
||||
/// </summary>
|
||||
public static ushort GetDV16(in IndividualValueSet actual)
|
||||
{
|
||||
ushort result = 0;
|
||||
result |= (ushort)(actual.SPA << 0);
|
||||
result |= (ushort)(actual.SPE << 4);
|
||||
result |= (ushort)(actual.DEF << 8);
|
||||
result |= (ushort)(actual.ATK << 12);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Generation 1 personal info for a Species.
|
||||
/// </summary>
|
||||
/// <param name="version">Pivot version</param>
|
||||
/// <param name="species">Species to get the personal info for</param>
|
||||
public static PersonalInfo1 GetPersonal1(GameVersion version, ushort species)
|
||||
{
|
||||
var pt = version == GameVersion.YW ? PersonalTable.Y : PersonalTable.RB;
|
||||
return pt[species];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ private static bool VerifySecondaryChecks(PKM pk, LegalInfo info, PeekEnumerator
|
|||
{
|
||||
if (!ParseSettings.AllowGen1Tradeback)
|
||||
return false;
|
||||
if (!PK1.IsCatchRateHeldItem(pk1.Catch_Rate))
|
||||
if (!PK1.IsCatchRateHeldItem(pk1.CatchRate))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,17 @@ public static class EncounterGenerator
|
|||
_ => EncounterGeneratorDummy.Instance.GetEncounters(pk, info),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IEncounterGenerator"/> for the given <see cref="GameVersion"/>.
|
||||
/// </summary>
|
||||
/// <param name="version">Original encounter version</param>
|
||||
public static IEncounterGenerator GetGenerator(GameVersion version) => GetGeneration(version, version.GetGeneration());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IEncounterGenerator"/> for the given <see cref="GameVersion"/>.
|
||||
/// </summary>
|
||||
/// <param name="version">Original encounter version</param>
|
||||
/// <param name="generation">Generation group</param>
|
||||
public static IEncounterGenerator GetGeneration(GameVersion version, int generation) => generation switch
|
||||
{
|
||||
1 => EncounterGenerator1.Instance,
|
||||
|
|
|
|||
|
|
@ -14,13 +14,14 @@ public static class EncounterMovesetGenerator
|
|||
/// <summary>
|
||||
/// Order in which <see cref="IEncounterable"/> objects are yielded from the <see cref="GenerateVersionEncounters(PKM,ReadOnlyMemory{ushort},GameVersion)"/> method.
|
||||
/// </summary>
|
||||
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
|
||||
public static IReadOnlyCollection<EncounterTypeGroup> PriorityList { get; set; } = PriorityList = (EncounterTypeGroup[])Enum.GetValues(typeof(EncounterTypeGroup));
|
||||
public static IReadOnlyCollection<EncounterTypeGroup> PriorityList { get; set; } = GetAllGroups();
|
||||
|
||||
/// <summary>
|
||||
/// Resets the <see cref="PriorityList"/> to the default values.
|
||||
/// </summary>
|
||||
public static void ResetFilters() => PriorityList = (EncounterTypeGroup[])Enum.GetValues(typeof(EncounterTypeGroup));
|
||||
public static void ResetFilters() => PriorityList = GetAllGroups();
|
||||
|
||||
private static EncounterTypeGroup[] GetAllGroups() => (EncounterTypeGroup[])Enum.GetValues(typeof(EncounterTypeGroup));
|
||||
|
||||
/// <summary>
|
||||
/// Gets possible <see cref="IEncounterable"/> objects that allow all moves requested to be learned.
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ public static class EncounterDate
|
|||
_ => throw new ArgumentOutOfRangeException(nameof(console), console, null),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the date is valid for the Nintendo DS.
|
||||
/// </summary>
|
||||
public static bool IsValidDateNDS(DateOnly date)
|
||||
{
|
||||
if (date.Year is < 2000 or > 2099)
|
||||
|
|
@ -47,6 +50,9 @@ public static bool IsValidDateNDS(DateOnly date)
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the date is valid for the Nintendo 3DS.
|
||||
/// </summary>
|
||||
public static bool IsValidDate3DS(DateOnly date)
|
||||
{
|
||||
if (date.Year is < 2000 or > 2050)
|
||||
|
|
@ -54,6 +60,9 @@ public static bool IsValidDate3DS(DateOnly date)
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the date is valid for the Nintendo Switch.
|
||||
/// </summary>
|
||||
public static bool IsValidDateSwitch(DateOnly date)
|
||||
{
|
||||
if (date.Year is < 2000 or > 2050)
|
||||
|
|
@ -72,6 +81,7 @@ public sealed class DefaultTimeProvider : ITimeProvider
|
|||
/// </summary>
|
||||
public static readonly DefaultTimeProvider Instance = new();
|
||||
|
||||
/// <inheritdoc cref="DateTime.Now"/>
|
||||
public DateTime Now => DateTime.Now;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.GameVersion;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
|
@ -25,8 +26,8 @@ public static class EncounterSuggestion
|
|||
var generator = EncounterGenerator.GetGenerator(ver);
|
||||
|
||||
var evos = chain[..count].ToArray();
|
||||
var w = EncounterUtil.GetMinByLevel(evos, generator.GetPossible(pk, evos, ver, EncounterTypeGroup.Slot));
|
||||
var s = EncounterUtil.GetMinByLevel(evos, generator.GetPossible(pk, evos, ver, EncounterTypeGroup.Static));
|
||||
var w = EncounterSelection.GetMinByLevel(evos, generator.GetPossible(pk, evos, ver, EncounterTypeGroup.Slot));
|
||||
var s = EncounterSelection.GetMinByLevel(evos, generator.GetPossible(pk, evos, ver, EncounterTypeGroup.Static));
|
||||
|
||||
if (w is null)
|
||||
return s is null ? null : GetSuggestedEncounter(pk, s, loc);
|
||||
|
|
@ -41,7 +42,7 @@ public static class EncounterSuggestion
|
|||
return GetSuggestedEncounter(pk, w, loc);
|
||||
}
|
||||
|
||||
private static bool IsSpeciesFormMatch(ReadOnlySpan<EvoCriteria> evos, ISpeciesForm encounter)
|
||||
private static bool IsSpeciesFormMatch<T>(ReadOnlySpan<EvoCriteria> evos, T encounter) where T : ISpeciesForm
|
||||
{
|
||||
foreach (var evo in evos)
|
||||
{
|
||||
|
|
@ -143,11 +144,21 @@ private static int GetMaxLevelMax(ReadOnlySpan<EvoCriteria> evos)
|
|||
return max;
|
||||
}
|
||||
|
||||
public static bool IterateMinimumCurrentLevel(PKM pk, bool isLegal, int max = 100)
|
||||
/// <summary>
|
||||
/// Iterates through all possible levels to drop to the lowest level possible.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to modify</param>
|
||||
/// <param name="isLegal">Current state is legal or invalid (false)</param>
|
||||
/// <param name="level">Maximum level to iterate down from</param>
|
||||
/// <returns>True if the level was changed, false if it was already at the lowest level possible or impossible.</returns>
|
||||
public static bool IterateMinimumCurrentLevel(PKM pk, bool isLegal, int level = 100)
|
||||
{
|
||||
// Find the lowest level possible while still remaining legal.
|
||||
var original = pk.CurrentLevel;
|
||||
var growth = pk.PersonalInfo.EXPGrowth;
|
||||
var table = Experience.GetTable(growth);
|
||||
|
||||
var originalEXP = pk.EXP;
|
||||
var original = Experience.GetLevel(originalEXP, table);
|
||||
if (isLegal)
|
||||
{
|
||||
// If we can't go any lower, we're already at the lowest level possible.
|
||||
|
|
@ -155,28 +166,31 @@ public static bool IterateMinimumCurrentLevel(PKM pk, bool isLegal, int max = 10
|
|||
return false;
|
||||
|
||||
// Skip to original - 1, since all levels [original,max] are already legal.
|
||||
max = original - 1;
|
||||
level = original - 1;
|
||||
}
|
||||
// If it's not legal, then we'll first try the max level and abort if it will never be legal.
|
||||
|
||||
// Find the first level that is illegal via searching downwards, and set it to the level above it.
|
||||
for (int i = max; i != 0; i--)
|
||||
while (level != 0)
|
||||
{
|
||||
pk.CurrentLevel = i;
|
||||
pk.EXP = table[level];
|
||||
var la = new LegalityAnalysis(pk);
|
||||
var valid = la.Valid;
|
||||
if (valid)
|
||||
{
|
||||
--level;
|
||||
continue;
|
||||
}
|
||||
|
||||
// First illegal level found, revert to the previous level.
|
||||
var revert = Math.Min(100, i + 1);
|
||||
if (revert == original) // same, revert actual EXP value.
|
||||
level = Math.Min(100, level + 1);
|
||||
if (level == original) // same, revert actual EXP value.
|
||||
{
|
||||
pk.EXP = originalEXP;
|
||||
return false;
|
||||
}
|
||||
|
||||
pk.CurrentLevel = revert;
|
||||
pk.EXP = table[level];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -208,3 +222,33 @@ public static int GetSuggestedMetLevel(PKM pk, int minLevel)
|
|||
return Math.Max(minMove, minLevel);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class EncounterSelection
|
||||
{
|
||||
internal static T? GetMinByLevel<T>(ReadOnlySpan<EvoCriteria> chain, IEnumerable<T> possible) where T : class, IEncounterTemplate
|
||||
{
|
||||
// MinBy grading: prefer species-form match, select lowest min level encounter.
|
||||
// Minimum allocation :)
|
||||
T? result = null;
|
||||
int min = int.MaxValue;
|
||||
|
||||
foreach (var enc in possible)
|
||||
{
|
||||
int m = int.MaxValue;
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
bool specDiff = enc.Species != evo.Species || enc.Form != evo.Form;
|
||||
var val = (Convert.ToInt32(specDiff) << 16) | enc.LevelMin;
|
||||
if (val < m)
|
||||
m = val;
|
||||
}
|
||||
|
||||
if (m >= min)
|
||||
continue;
|
||||
min = m;
|
||||
result = enc;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
ID32 = tr.ID32,
|
||||
};
|
||||
SetPINGA(pk, criteria);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
pk.Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation);
|
||||
SetEncounterMoves(pk, LevelMin);
|
||||
pk.AwakeningSetAllTo(2);
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ public PKM ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
l.HT_Language = 2;
|
||||
}
|
||||
SetPINGA(pk, criteria);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
pk.Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation);
|
||||
SetEncounterMoves(pk, LevelMin);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,15 +51,15 @@ public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
{
|
||||
var lang = GetTemplateLanguage(tr);
|
||||
var isJapanese = lang == (int)LanguageID.Japanese;
|
||||
var pi = EncounterUtil1.GetPersonal1(Version, Species);
|
||||
var pi = EncounterUtil.GetPersonal1(Version, Species);
|
||||
var pk = new PK1(isJapanese)
|
||||
{
|
||||
Species = Species,
|
||||
CurrentLevel = LevelMin,
|
||||
Catch_Rate = GetInitialCatchRate(),
|
||||
DV16 = IVs.IsSpecified ? EncounterUtil1.GetDV16(IVs) : EncounterUtil1.GetRandomDVs(Util.Rand),
|
||||
CatchRate = GetInitialCatchRate(pi),
|
||||
DV16 = IVs.IsSpecified ? EncounterUtil.GetDV16(IVs) : EncounterUtil.GetRandomDVs(Util.Rand),
|
||||
|
||||
OT_Name = EncounterUtil1.GetTrainerName(tr, lang),
|
||||
OT_Name = EncounterUtil.GetTrainerName(tr, lang),
|
||||
TID16 = tr.TID16,
|
||||
Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
|
||||
Type1 = pi.Type1,
|
||||
|
|
@ -77,15 +77,15 @@ public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
{
|
||||
// Amnesia Psyduck has different catch rates depending on language
|
||||
if (Species == (int)Core.Species.Psyduck)
|
||||
pk.Catch_Rate = pk.Japanese ? (byte)167 : (byte)168;
|
||||
pk.CatchRate = pk.Japanese ? (byte)167 : (byte)168;
|
||||
else
|
||||
pk.Catch_Rate = Util.Rand.Next(2) == 0 ? (byte)167 : (byte)168;
|
||||
pk.CatchRate = Util.Rand.Next(2) == 0 ? (byte)167 : (byte)168;
|
||||
}
|
||||
|
||||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
@ -106,7 +106,7 @@ private int GetTemplateLanguage(ITrainerInfo tr)
|
|||
|
||||
#endregion
|
||||
|
||||
private byte GetInitialCatchRate()
|
||||
private byte GetInitialCatchRate(PersonalInfo1 pi)
|
||||
{
|
||||
if (Version == GameVersion.Stadium)
|
||||
{
|
||||
|
|
@ -116,7 +116,7 @@ private byte GetInitialCatchRate()
|
|||
}
|
||||
|
||||
// Encounters can have different Catch Rates (RBG vs Y)
|
||||
return EncounterUtil1.GetWildCatchRate(Version, Species);
|
||||
return pi.CatchRate;
|
||||
}
|
||||
|
||||
#region Matching
|
||||
|
|
@ -205,24 +205,24 @@ private bool IsMatchPartial(PKM pk)
|
|||
{
|
||||
if (pk is not PK1 pk1)
|
||||
return false;
|
||||
return !IsCatchRateValid(pk1.Catch_Rate);
|
||||
return !IsCatchRateValid(pk1.CatchRate);
|
||||
}
|
||||
|
||||
private bool IsCatchRateValid(byte catch_rate)
|
||||
private bool IsCatchRateValid(byte rate)
|
||||
{
|
||||
if (ParseSettings.AllowGen1Tradeback && PK1.IsCatchRateHeldItem(catch_rate))
|
||||
if (ParseSettings.AllowGen1Tradeback && PK1.IsCatchRateHeldItem(rate))
|
||||
return true;
|
||||
|
||||
if (Version == GameVersion.Stadium)
|
||||
{
|
||||
// Amnesia Psyduck has different catch rates depending on language
|
||||
if (Species == (int)Core.Species.Psyduck)
|
||||
return catch_rate == (Language == EncounterGBLanguage.Japanese ? 167 : 168);
|
||||
return catch_rate is 167 or 168;
|
||||
return rate == (Language == EncounterGBLanguage.Japanese ? 167 : 168);
|
||||
return rate is 167 or 168;
|
||||
}
|
||||
|
||||
// Encounters can have different Catch Rates (RBG vs Y)
|
||||
return GBRestrictions.RateMatchesEncounter(Species, Version, catch_rate);
|
||||
return GBRestrictions.RateMatchesEncounter(Species, Version, rate);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -33,22 +33,22 @@ public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
{
|
||||
int lang = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
var isJapanese = lang == (int)LanguageID.Japanese;
|
||||
var pi = EncounterUtil1.GetPersonal1(Version, Species);
|
||||
var pi = EncounterUtil.GetPersonal1(Version, Species);
|
||||
var pk = new PK1(isJapanese)
|
||||
{
|
||||
Species = Species,
|
||||
CurrentLevel = LevelMin,
|
||||
Catch_Rate = EncounterUtil1.GetWildCatchRate(Version, Species),
|
||||
DV16 = EncounterUtil1.GetRandomDVs(Util.Rand),
|
||||
CatchRate = pi.CatchRate,
|
||||
DV16 = EncounterUtil.GetRandomDVs(Util.Rand),
|
||||
|
||||
OT_Name = EncounterUtil1.GetTrainerName(tr, lang),
|
||||
OT_Name = EncounterUtil.GetTrainerName(tr, lang),
|
||||
TID16 = tr.TID16,
|
||||
Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
|
||||
Type1 = pi.Type1,
|
||||
Type2 = pi.Type2,
|
||||
};
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
@ -65,8 +65,8 @@ public bool IsMatchExact(PKM pk, EvoCriteria evo)
|
|||
if (pk is not PK1 pk1)
|
||||
return true;
|
||||
|
||||
var rate = pk1.Catch_Rate;
|
||||
var expect = EncounterUtil1.GetWildCatchRate(Version, Species);
|
||||
var rate = pk1.CatchRate;
|
||||
var expect = EncounterUtil.GetPersonal1(Version, Species).CatchRate;
|
||||
if (expect != rate && !(ParseSettings.AllowGen1Tradeback && GBRestrictions.IsTradebackCatchRate(rate)))
|
||||
return false;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public sealed record EncounterStatic1(ushort Species, byte Level, GameVersion Ve
|
|||
public bool IsShiny => false;
|
||||
public int Location => 0;
|
||||
|
||||
private const int LightBallPikachuCatchRate = 0xA3; // 163
|
||||
private const byte LightBallPikachuCatchRate = 0xA3; // 163 - Light Ball
|
||||
public byte Form => 0;
|
||||
|
||||
public string Name => "Static Encounter";
|
||||
|
|
@ -26,15 +26,6 @@ public sealed record EncounterStatic1(ushort Species, byte Level, GameVersion Ve
|
|||
|
||||
public bool IsStarterPikachu => Version == GameVersion.YW && Species == (int)Core.Species.Pikachu && Level == 5;
|
||||
|
||||
private byte GetInitialCatchRate()
|
||||
{
|
||||
if (IsStarterPikachu)
|
||||
return LightBallPikachuCatchRate; // Light Ball
|
||||
|
||||
// Encounters can have different Catch Rates (RBG vs Y)
|
||||
return EncounterUtil1.GetWildCatchRate(Version, Species);
|
||||
}
|
||||
|
||||
#region Generating
|
||||
PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) => ConvertToPKM(tr, criteria);
|
||||
PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr);
|
||||
|
|
@ -45,22 +36,22 @@ public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
{
|
||||
int lang = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
var isJapanese = lang == (int)LanguageID.Japanese;
|
||||
var pi = EncounterUtil1.GetPersonal1(Version, Species);
|
||||
var pi = EncounterUtil.GetPersonal1(Version, Species);
|
||||
var pk = new PK1(isJapanese)
|
||||
{
|
||||
Species = Species,
|
||||
CurrentLevel = LevelMin,
|
||||
Catch_Rate = GetInitialCatchRate(),
|
||||
DV16 = EncounterUtil1.GetRandomDVs(Util.Rand),
|
||||
CatchRate = IsStarterPikachu ? LightBallPikachuCatchRate : pi.CatchRate,
|
||||
DV16 = EncounterUtil.GetRandomDVs(Util.Rand),
|
||||
|
||||
OT_Name = EncounterUtil1.GetTrainerName(tr, lang),
|
||||
OT_Name = EncounterUtil.GetTrainerName(tr, lang),
|
||||
TID16 = tr.TID16,
|
||||
Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
|
||||
Type1 = pi.Type1,
|
||||
Type2 = pi.Type2,
|
||||
};
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
@ -113,20 +104,20 @@ private bool IsMatchPartial(PKM pk)
|
|||
{
|
||||
if (pk is not PK1 pk1)
|
||||
return false;
|
||||
return !IsCatchRateValid(pk1.Catch_Rate);
|
||||
return !IsCatchRateValid(pk1.CatchRate);
|
||||
}
|
||||
|
||||
private bool IsCatchRateValid(byte catch_rate)
|
||||
private bool IsCatchRateValid(byte rate)
|
||||
{
|
||||
if (ParseSettings.AllowGen1Tradeback && PK1.IsCatchRateHeldItem(catch_rate))
|
||||
if (ParseSettings.AllowGen1Tradeback && PK1.IsCatchRateHeldItem(rate))
|
||||
return true;
|
||||
|
||||
// Light Ball (Yellow) starter
|
||||
if (IsStarterPikachu)
|
||||
return catch_rate == LightBallPikachuCatchRate;
|
||||
return rate == LightBallPikachuCatchRate;
|
||||
|
||||
// Encounters can have different Catch Rates (RBG vs Y)
|
||||
return GBRestrictions.RateMatchesEncounter(Species, Version, catch_rate);
|
||||
return GBRestrictions.RateMatchesEncounter(Species, Version, rate);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -113,13 +113,13 @@ public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
var level = gsc ? LevelMinGSC : LevelMinRBY;
|
||||
int lang = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
var isJapanese = lang == (int)LanguageID.Japanese;
|
||||
var pi = EncounterUtil1.GetPersonal1(Version, Species);
|
||||
var pi = EncounterUtil.GetPersonal1(Version, Species);
|
||||
var pk = new PK1(isJapanese)
|
||||
{
|
||||
Species = Species,
|
||||
CurrentLevel = level,
|
||||
Catch_Rate = EncounterUtil1.GetWildCatchRate(Version, Species),
|
||||
DV16 = EncounterUtil1.GetRandomDVs(Util.Rand),
|
||||
CatchRate = pi.CatchRate,
|
||||
DV16 = EncounterUtil.GetRandomDVs(Util.Rand),
|
||||
|
||||
Nickname = Nicknames[lang],
|
||||
TID16 = tr.TID16,
|
||||
|
|
@ -128,7 +128,7 @@ public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
};
|
||||
pk.OT_Trash[0] = StringConverter12.G1TradeOTCode;
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, level);
|
||||
if (EvolveOnTrade)
|
||||
pk.Species++;
|
||||
|
||||
|
|
@ -188,8 +188,8 @@ private bool IsMatchPartial(PKM pk)
|
|||
if (pk is not PK1 pk1)
|
||||
return false;
|
||||
|
||||
var req = EncounterUtil1.GetWildCatchRate(Version, Species);
|
||||
return req != pk1.Catch_Rate;
|
||||
var req = EncounterUtil.GetPersonal1(Version, Species).CatchRate;
|
||||
return req != pk1.CatchRate;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public static class EncounterUtil1
|
||||
{
|
||||
public const int FormDynamic = FormVivillon;
|
||||
public const byte FormVivillon = 30;
|
||||
public const byte FormRandom = 31;
|
||||
|
||||
public static ushort GetRandomDVs(Random rand) => (ushort)rand.Next(ushort.MaxValue + 1);
|
||||
|
||||
public static byte GetWildCatchRate(GameVersion version, ushort species) => (byte)(version == GameVersion.YW ? PersonalTable.Y : PersonalTable.RB)[species].CatchRate;
|
||||
public static (byte Type1, byte Type2) GetTypes(GameVersion version, ushort species)
|
||||
{
|
||||
var pi = GetPersonal1(version, species);
|
||||
return (pi.Type1, pi.Type2);
|
||||
}
|
||||
|
||||
public static PersonalInfo1 GetPersonal1(GameVersion version, ushort species)
|
||||
{
|
||||
var pt = version == GameVersion.YW ? PersonalTable.Y : PersonalTable.RB;
|
||||
return pt[species];
|
||||
}
|
||||
|
||||
public static void SetEncounterMoves<T>(T pk, GameVersion version, byte level) where T : PKM
|
||||
{
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
var source = GameData.GetLearnSource(version);
|
||||
source.SetEncounterMoves(pk.Species, pk.Form, level, moves);
|
||||
pk.SetMoves(moves);
|
||||
}
|
||||
|
||||
public static string GetTrainerName(ITrainerInfo tr, int lang) => lang switch
|
||||
{
|
||||
(int)LanguageID.Japanese => tr.Language == 1 ? tr.OT : "ゲーフリ",
|
||||
_ => tr.Language == 1 ? "GF" : tr.OT,
|
||||
};
|
||||
|
||||
public static ushort GetDV16(in IndividualValueSet actual)
|
||||
{
|
||||
ushort result = 0;
|
||||
result |= (ushort)(actual.SPA << 0);
|
||||
result |= (ushort)(actual.SPE << 4);
|
||||
result |= (ushort)(actual.DEF << 8);
|
||||
result |= (ushort)(actual.ATK << 12);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ private EncounterSlot2[] ReadSlots(ReadOnlySpan<byte> data, int count)
|
|||
byte min = entry[2];
|
||||
byte slotNum = entry[1];
|
||||
byte species = entry[0];
|
||||
var form = species == (int)Species.Unown ? EncounterUtil1.FormRandom : (byte)0;
|
||||
var form = species == (int)Species.Unown ? EncounterUtil.FormRandom : (byte)0;
|
||||
slots[i] = new EncounterSlot2(this, species, form, min, max, slotNum);
|
||||
}
|
||||
return slots;
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
|
||||
if (IVs.IsSpecified)
|
||||
criteria.SetRandomIVs(pk, IVs);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public sealed record EncounterSlot2(EncounterArea2 Parent, ushort Species, byte
|
|||
public Shiny Shiny => Shiny.Random;
|
||||
public bool IsShiny => false;
|
||||
public int EggLocation => 0;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil1.FormDynamic;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil.FormDynamic;
|
||||
|
||||
public string Name => $"Wild Encounter ({Version})";
|
||||
public string LongName => $"{Name} {Type.ToString().Replace('_', ' ')}";
|
||||
|
|
@ -91,7 +91,7 @@ public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
// Form is only Unown and is derived from IVs.
|
||||
CurrentLevel = LevelMin,
|
||||
OT_Friendship = pi.BaseFriendship,
|
||||
DV16 = EncounterUtil1.GetRandomDVs(Util.Rand),
|
||||
DV16 = EncounterUtil.GetRandomDVs(Util.Rand),
|
||||
|
||||
Language = lang,
|
||||
OT_Name = tr.OT,
|
||||
|
|
@ -107,7 +107,7 @@ public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
pk.Met_TimeOfDay = GetRandomTime();
|
||||
}
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
if (IsHeadbutt)
|
||||
{
|
||||
var id = pk.TID16;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
|
||||
if (IVs.IsSpecified)
|
||||
criteria.SetRandomIVs(pk, IVs);
|
||||
|
|
|
|||
|
|
@ -73,17 +73,17 @@ public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
|
||||
if (IVs.IsSpecified)
|
||||
{
|
||||
pk.DV16 = EncounterUtil1.GetDV16(IVs);
|
||||
pk.DV16 = EncounterUtil.GetDV16(IVs);
|
||||
pk.OT_Gender = OTGender;
|
||||
pk.TID16 = TID16;
|
||||
}
|
||||
else
|
||||
{
|
||||
pk.DV16 = EncounterUtil1.GetRandomDVs(Util.Rand);
|
||||
pk.DV16 = EncounterUtil.GetRandomDVs(Util.Rand);
|
||||
pk.TID16 = tr.TID16;
|
||||
}
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, Level);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ public CK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, Level);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public CK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
Ball = (byte)Ball.Poke,
|
||||
|
||||
Language = lang,
|
||||
OT_Name = tr.Language == lang ? tr.OT : lang == 1 ? "ゲーフリ" : "GF",
|
||||
OT_Name = EncounterUtil.GetTrainerName(tr, lang),
|
||||
OT_Gender = 0,
|
||||
ID32 = tr.ID32,
|
||||
Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public CK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, Level);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ public record EncounterSlot3(EncounterArea3 Parent, ushort Species, byte Form, b
|
|||
: IEncounterable, IEncounterMatch, IEncounterConvertible<PK3>, IMagnetStatic, INumberedSlot, ISlotRNGType, IRandomCorrelation
|
||||
{
|
||||
public int Generation => 3;
|
||||
int ILocation.Location => Location;
|
||||
public EntityContext Context => EntityContext.Gen3;
|
||||
public bool EggEncounter => false;
|
||||
public Ball FixedBall => GetRequiredBall();
|
||||
|
|
@ -19,7 +20,7 @@ public record EncounterSlot3(EncounterArea3 Parent, ushort Species, byte Form, b
|
|||
public string Name => $"Wild Encounter ({Version})";
|
||||
public string LongName => $"{Name} {Type.ToString().Replace('_', ' ')}";
|
||||
public GameVersion Version => Parent.Version;
|
||||
public int Location => Parent.Location;
|
||||
public byte Location => Parent.Location;
|
||||
public SlotType Type => Parent.Type;
|
||||
|
||||
private Ball GetRequiredBall(Ball fallback = Ball.None) => Locations.IsSafariZoneLocation3(Location) ? Ball.Safari : fallback;
|
||||
|
|
@ -78,7 +79,7 @@ private void SetPINGA(PK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
|||
}
|
||||
}
|
||||
|
||||
protected virtual void SetEncounterMoves(PKM pk) => EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
protected virtual void SetEncounterMoves(PKM pk) => EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
#endregion
|
||||
|
||||
#region Matching
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
FatefulEncounter = FatefulEncounter,
|
||||
|
||||
Language = lang,
|
||||
OT_Name = tr.Language == lang ? tr.OT : lang == 1 ? "ゲーフリ" : "GF",
|
||||
OT_Name = EncounterUtil.GetTrainerName(tr, lang),
|
||||
OT_Gender = tr.Gender,
|
||||
ID32 = tr.ID32,
|
||||
Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
|
||||
|
|
@ -72,7 +72,7 @@ public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
pk.Nickname = Nicknames[lang];
|
||||
pk.OT_Name = TrainerNames[lang];
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, Level);
|
||||
SetPINGA(pk, criteria);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, Level);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
};
|
||||
|
||||
SetPINGA(pk, criteria, pi);
|
||||
EncounterUtil1.SetEncounterMoves(pk, GameVersion.XD, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, GameVersion.XD, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, Level);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, Level);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ public sealed record EncounterSlot4(EncounterArea4 Parent, ushort Species, byte
|
|||
: IEncounterable, IEncounterMatch, IEncounterConvertible<PK4>, IMagnetStatic, INumberedSlot, IGroundTypeTile, ISlotRNGType, IEncounterFormRandom, IRandomCorrelation
|
||||
{
|
||||
public int Generation => 4;
|
||||
int ILocation.Location => Location;
|
||||
public EntityContext Context => EntityContext.Gen4;
|
||||
public bool EggEncounter => false;
|
||||
public AbilityPermission Ability => AbilityPermission.Any12;
|
||||
|
|
@ -14,22 +15,22 @@ public sealed record EncounterSlot4(EncounterArea4 Parent, ushort Species, byte
|
|||
public Shiny Shiny => Shiny.Random;
|
||||
public bool IsShiny => false;
|
||||
public int EggLocation => 0;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil1.FormDynamic;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil.FormDynamic;
|
||||
|
||||
public string Name => $"Wild Encounter ({Version})";
|
||||
public string LongName => $"{Name} {Type.ToString().Replace('_', ' ')}";
|
||||
public GameVersion Version => Parent.Version;
|
||||
public int Location => Parent.Location;
|
||||
public ushort Location => Parent.Location;
|
||||
public SlotType Type => Parent.Type;
|
||||
public GroundTileAllowed GroundTile => Parent.GroundTile;
|
||||
|
||||
public bool CanUseRadar => Version is not (GameVersion.HG or GameVersion.SS) && GroundTile.HasFlag(GroundTileAllowed.Grass) && !Locations.IsSafariZoneLocation4(Location);
|
||||
public bool CanUseRadar => Version is not (GameVersion.HG or GameVersion.SS) && GroundTile.HasFlag(GroundTileAllowed.Grass) && !Locations4.IsSafariZoneLocation(Location);
|
||||
|
||||
private Ball GetRequiredBallValue(Ball fallback = Ball.None)
|
||||
{
|
||||
if (Type is SlotType.BugContest)
|
||||
return Ball.Sport;
|
||||
return Locations.IsSafariZoneLocation4(Location) ? Ball.Safari : fallback;
|
||||
return Locations4.IsSafariZoneLocation(Location) ? Ball.Safari : fallback;
|
||||
}
|
||||
|
||||
#region Generating
|
||||
|
|
@ -63,7 +64,7 @@ public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
};
|
||||
|
||||
SetPINGA(pk, criteria, pi);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
@ -71,7 +72,7 @@ public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
|
||||
private byte GetWildForm(byte form)
|
||||
{
|
||||
if (form == EncounterUtil1.FormRandom) // flagged as totally random
|
||||
if (form == EncounterUtil.FormRandom) // flagged as totally random
|
||||
return (byte)Util.Rand.Next(PersonalTable.HGSS[Species].FormCount);
|
||||
return form;
|
||||
}
|
||||
|
|
@ -137,7 +138,7 @@ public bool IsInvalidMunchlaxTree(PKM pk)
|
|||
|
||||
public EncounterMatchRating GetMatchRating(PKM pk)
|
||||
{
|
||||
if ((pk.Ball == (int)Ball.Safari) != Locations.IsSafariZoneLocation4(Location))
|
||||
if ((pk.Ball == (int)Ball.Safari) != Locations4.IsSafariZoneLocation(Location))
|
||||
return EncounterMatchRating.PartialMatch;
|
||||
if ((pk.Ball == (int)Ball.Sport) != (Type == SlotType.BugContest))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
criteria.SetRandomIVs(pk, IVs);
|
||||
pk.PID = PID;
|
||||
pk.Gender = Gender;
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, actualLevel);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, actualLevel);
|
||||
SetPINGA(pk, criteria);
|
||||
pk.ResetPartyStats();
|
||||
|
||||
|
|
|
|||
|
|
@ -67,14 +67,14 @@ public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
};
|
||||
|
||||
SetPINGA(pk, criteria, pi);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
}
|
||||
|
||||
private byte GetWildForm(byte form)
|
||||
{
|
||||
if (form != EncounterUtil1.FormRandom)
|
||||
if (form != EncounterUtil.FormRandom)
|
||||
return form;
|
||||
// flagged as totally random
|
||||
return (byte)Util.Rand.Next(PersonalTable.B2W2[Species].FormCount);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
pk.EggMetDate = pk.MetDate;
|
||||
}
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
|
||||
SetPINGA(pk, criteria, pi);
|
||||
pk.ResetPartyStats();
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
|
||||
SetPINGA(pk, criteria, pi);
|
||||
pk.ResetPartyStats();
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
HiddenAbility = Ability == AbilityPermission.OnlyHidden,
|
||||
};
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
|
||||
};
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
|
||||
SetPINGA(pk, criteria, pi);
|
||||
pk.ResetPartyStats();
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
Nickname = IsFixedNickname ? Nicknames[lang] : SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
|
||||
};
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
SetPINGA(pk, criteria, pi);
|
||||
pk.ResetPartyStats();
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
Nickname = IsFixedNickname ? Nicknames[lang] : SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
|
||||
};
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
criteria.SetRandomIVs(pk, IVs);
|
||||
pk.RefreshAbility(criteria.GetAbilityFromNumber(Ability));
|
||||
pk.ResetPartyStats();
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ private EncounterSlot6XY[] LoadSafariSlots()
|
|||
slots[i++] = new EncounterSlot6XY(this, (int)Species.Floette, 3, Level, Level);
|
||||
|
||||
// Region Random Vivillon
|
||||
slots[i] = new EncounterSlot6XY(this, (int)Species.Vivillon, EncounterUtil1.FormVivillon, Level, Level);
|
||||
slots[i] = new EncounterSlot6XY(this, (int)Species.Vivillon, EncounterUtil.FormVivillon, Level, Level);
|
||||
return slots;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public sealed record EncounterSlot6AO(EncounterArea6AO Parent, ushort Species, b
|
|||
public Shiny Shiny => Shiny.Random;
|
||||
public bool IsShiny => false;
|
||||
public int EggLocation => 0;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil1.FormDynamic;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil.FormDynamic;
|
||||
|
||||
public string Name => $"Wild Encounter ({Version})";
|
||||
public string LongName => $"{Name} {Type.ToString().Replace('_', ' ')}";
|
||||
|
|
@ -82,7 +82,7 @@ public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
pk.SetDefaultRegionOrigins(lang);
|
||||
|
||||
SetPINGA(pk, criteria, pi);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
if (CanDexNav)
|
||||
{
|
||||
var eggMoves = GetDexNavMoves();
|
||||
|
|
@ -96,7 +96,7 @@ public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
|
||||
private byte GetWildForm(byte form)
|
||||
{
|
||||
if (form != EncounterUtil1.FormRandom)
|
||||
if (form != EncounterUtil.FormRandom)
|
||||
return form;
|
||||
// flagged as totally random
|
||||
return (byte)Util.Rand.Next(PersonalTable.AO[Species].FormCount);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public sealed record EncounterSlot6XY(EncounterArea6XY Parent, ushort Species, b
|
|||
public Shiny Shiny => Shiny.Random;
|
||||
public bool IsShiny => false;
|
||||
public int EggLocation => 0;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil1.FormDynamic;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil.FormDynamic;
|
||||
|
||||
private PersonalInfo6XY PersonalInfo => PersonalTable.XY[Species];
|
||||
public byte FlawlessIVCount => PersonalInfo.EggGroup1 == 15 ? (byte)3 : IsFriendSafari ? (byte)2 : (byte)0;
|
||||
|
|
@ -76,11 +76,11 @@ public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
else
|
||||
pk.SetDefaultRegionOrigins(lang);
|
||||
|
||||
if (IsRandomUnspecificForm && Form == EncounterUtil1.FormVivillon)
|
||||
if (IsRandomUnspecificForm && Form == EncounterUtil.FormVivillon)
|
||||
pk.Form = Vivillon3DS.GetPattern(pk.Country, pk.Region);
|
||||
|
||||
SetPINGA(pk, criteria);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
pk.SetRandomMemory6();
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
@ -88,9 +88,9 @@ public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
|
||||
private byte GetWildForm(byte form)
|
||||
{
|
||||
if (form < EncounterUtil1.FormDynamic)
|
||||
if (form < EncounterUtil.FormDynamic)
|
||||
return form;
|
||||
if (form == EncounterUtil1.FormVivillon)
|
||||
if (form == EncounterUtil.FormVivillon)
|
||||
return 0; // rectify later
|
||||
|
||||
// flagged as totally random
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
this.CopyContestStatsTo(pk);
|
||||
|
||||
pk.SetRandomMemory6();
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
else
|
||||
pk.SetDefaultRegionOrigins(lang);
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
if (pk.IsShiny)
|
||||
pk.PID ^= 0x1000_0000;
|
||||
criteria.SetRandomIVs(pk, IVs);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public sealed record EncounterSlot7(EncounterArea7 Parent, ushort Species, byte
|
|||
public Shiny Shiny => Shiny.Random;
|
||||
public bool IsShiny => false;
|
||||
public int EggLocation => 0;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil1.FormDynamic;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil.FormDynamic;
|
||||
|
||||
public string Name => $"Wild Encounter ({Version})";
|
||||
public string LongName => $"{Name} {Type.ToString().Replace('_', ' ')}";
|
||||
|
|
@ -72,14 +72,14 @@ public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
pk.SetDefaultRegionOrigins(lang);
|
||||
|
||||
SetPINGA(pk, criteria, pi);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
}
|
||||
|
||||
private byte GetWildForm(byte form)
|
||||
{
|
||||
if (form != EncounterUtil1.FormRandom)
|
||||
if (form != EncounterUtil.FormRandom)
|
||||
return form; // flagged as totally random
|
||||
if (Species == (int)Core.Species.Minior)
|
||||
return (byte)Util.Rand.Next(7, 14);
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
|
||||
if (Relearn.HasMoves)
|
||||
pk.SetRelearnMoves(Relearn);
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
SetPINGA(pk, criteria, pi);
|
||||
pk.ResetPartyStats();
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
else
|
||||
pk.SetDefaultRegionOrigins(lang);
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
if (pk.IsShiny)
|
||||
pk.PID ^= 0x1000_0000;
|
||||
criteria.SetRandomIVs(pk, IVs);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
pk.ResetHeight();
|
||||
pk.ResetWeight();
|
||||
pk.ResetCP();
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
pk.ResetHeight();
|
||||
pk.ResetWeight();
|
||||
pk.ResetCP();
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
HT_Friendship = pi.BaseFriendship,
|
||||
};
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
pk.ResetHeight();
|
||||
pk.ResetWeight();
|
||||
pk.ResetCP();
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
OT_Friendship = pi.BaseFriendship,
|
||||
};
|
||||
SetPINGA(pk, criteria, pi);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
|
||||
bool symbol = Parent.PermitCrossover;
|
||||
if (!symbol && Location is 30 or 54 && (Weather & AreaWeather8.Fishing) == 0)
|
||||
|
|
@ -83,7 +83,7 @@ public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
|
||||
private byte GetWildForm(byte form)
|
||||
{
|
||||
if (form == EncounterUtil1.FormRandom) // flagged as totally random
|
||||
if (form == EncounterUtil.FormRandom) // flagged as totally random
|
||||
return (byte)Util.Rand.Next(PersonalTable.SWSH[Species].FormCount);
|
||||
return form;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
pk.ResetPartyStats();
|
||||
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
pk.ResetPartyStats();
|
||||
|
||||
return pk;
|
||||
|
|
@ -199,6 +199,8 @@ private EncounterMatchRating IsMatchDeferred(PKM pk)
|
|||
{
|
||||
if (Ability is OnlyFirst or OnlySecond && !AbilityVerifier.CanAbilityCapsule(8, PersonalTable.SWSH.GetFormEntry(Species, Form)))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
if (Ability is OnlyHidden) // Can't revert to hidden ability even if transferred from HOME and another game with HA reversion.
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
pk.PID ^= 0x1000_0000u;
|
||||
pk.SetRelearnMoves(Relearn);
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
SetPINGA(pk, criteria, pi);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public PB8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
OT_Friendship = pi.BaseFriendship,
|
||||
};
|
||||
SetPINGA(pk, criteria, pi);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
if (IsUnderground && GetBaseEggMove(out var move1, pi))
|
||||
pk.RelearnMove1 = move1;
|
||||
pk.ResetPartyStats();
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public PB8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
|
||||
SetPINGA(pk, criteria);
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
pk.ResetPartyStats();
|
||||
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, Level);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
pk.Scale = !IsForcedScaleRange ? PokeSizeUtil.GetRandomScalar() : (byte)Util.Rand.Next(ScaleMin, ScaleMax + 1);
|
||||
|
||||
SetPINGA(pk, criteria, pi);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, Level);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public sealed record EncounterSlot9(EncounterArea9 Parent, ushort Species, byte
|
|||
public Shiny Shiny => Shiny.Random;
|
||||
public bool IsShiny => false;
|
||||
public int EggLocation => 0;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil1.FormDynamic;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil.FormDynamic;
|
||||
|
||||
public string Name => $"Wild Encounter ({Version})";
|
||||
public string LongName => $"{Name}";
|
||||
|
|
@ -151,16 +151,16 @@ public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
|
||||
};
|
||||
SetPINGA(pk, criteria, pi);
|
||||
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
}
|
||||
|
||||
private byte GetWildForm(byte form)
|
||||
{
|
||||
if (form < EncounterUtil1.FormDynamic)
|
||||
if (form < EncounterUtil.FormDynamic)
|
||||
return form;
|
||||
if (form == EncounterUtil1.FormVivillon)
|
||||
if (form == EncounterUtil.FormVivillon)
|
||||
return Vivillon3DS.FancyFormID; // Fancy Vivillon
|
||||
// flagged as totally random
|
||||
return (byte)Util.Rand.Next(PersonalTable.SV[Species].FormCount);
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
if (Moves.HasMoves)
|
||||
pk.SetMoves(Moves);
|
||||
else
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, LevelMin);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
return pk;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public sealed record EncounterTera9
|
|||
public bool IsAvailableHostViolet => RandRateMinViolet != -1;
|
||||
public required TeraRaidMapParent Map { get; init; }
|
||||
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil1.FormDynamic;
|
||||
public bool IsRandomUnspecificForm => Form >= EncounterUtil.FormDynamic;
|
||||
|
||||
public string Name => $"Tera Raid Encounter [{(Index == 0 ? "Base" : Index)}] {Stars}★";
|
||||
public string LongName => Name;
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ public PK9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
Obedience_Level = Level,
|
||||
};
|
||||
|
||||
EncounterUtil1.SetEncounterMoves(pk, version, Level);
|
||||
EncounterUtil.SetEncounterMoves(pk, version, Level);
|
||||
SetPINGA(pk, criteria, pi);
|
||||
if (EvolveOnTrade)
|
||||
pk.Species++;
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ private static bool HasDefinitelyVisitedGen2(PK1 pk1)
|
|||
{
|
||||
if (!ParseSettings.AllowGen1Tradeback)
|
||||
return false;
|
||||
var rate = pk1.Catch_Rate;
|
||||
var rate = pk1.CatchRate;
|
||||
return rate is 0 || GBRestrictions.IsTradebackCatchRate(rate);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public sealed record Frame(uint Seed, FrameType FrameType, LeadRequired Lead)
|
|||
}
|
||||
|
||||
// Check Level Now
|
||||
int lvl = SlotRange.GetLevel(slot, Lead, RandLevel);
|
||||
var lvl = SlotRange.GetLevel(slot, Lead, RandLevel);
|
||||
if (pk.HasOriginalMetLocation)
|
||||
{
|
||||
if (lvl != pk.Met_Level)
|
||||
|
|
|
|||
|
|
@ -72,6 +72,14 @@ private static int JSlot(SlotType type, uint rand)
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the level for the given slot.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Slot type</typeparam>
|
||||
/// <param name="slot">Slot reference</param>
|
||||
/// <param name="lead">Player's lead Pokémon</param>
|
||||
/// <param name="lvlrand">Random value to use for level calculation</param>
|
||||
/// <returns>Actual level of the encounter</returns>
|
||||
public static int GetLevel<T>(T slot, LeadRequired lead, uint lvlrand) where T : ILevelRange
|
||||
{
|
||||
if ((lead & LeadRequired.PressureHustleSpiritFail) == LeadRequired.PressureHustleSpirit)
|
||||
|
|
|
|||
|
|
@ -93,25 +93,25 @@ public static bool RateMatchesEncounter(ushort species, GameVersion version, byt
|
|||
return rate == PersonalTable.RB[species].CatchRate;
|
||||
}
|
||||
|
||||
private static bool RateMatchesEither(byte catch_rate, ushort rate)
|
||||
private static bool RateMatchesEither(byte rate, ushort species)
|
||||
{
|
||||
return catch_rate == PersonalTable.RB[rate].CatchRate || catch_rate == PersonalTable.Y[rate].CatchRate;
|
||||
return rate == PersonalTable.RB[species].CatchRate || rate == PersonalTable.Y[species].CatchRate;
|
||||
}
|
||||
|
||||
private static bool GetCatchRateMatchesPreEvolution(PK1 pk, byte catch_rate)
|
||||
private static bool GetCatchRateMatchesPreEvolution(PK1 pk, byte rate)
|
||||
{
|
||||
// For species catch rate, discard any species that has no valid encounters and a different catch rate than their pre-evolutions
|
||||
var head = new EvoCriteria { Species = pk.Species, Form = pk.Form, LevelMax = (byte)pk.CurrentLevel }; // as struct to avoid boxing
|
||||
do
|
||||
{
|
||||
var s = head.Species;
|
||||
if (!IsSpeciesNotAvailableCatchRate((byte)s) && RateMatchesEither(catch_rate, s))
|
||||
var species = head.Species;
|
||||
if (!IsSpeciesNotAvailableCatchRate((byte)species) && RateMatchesEither(rate, species))
|
||||
return true;
|
||||
}
|
||||
while (EvolutionGroup1.Instance.TryDevolve(head, pk, head.LevelMax, 2, false, out head));
|
||||
|
||||
// Account for oddities via special catch rate encounters
|
||||
if (catch_rate is 167 or 168 && IsStadiumGiftSpecies((byte)head.Species))
|
||||
if (rate is 167 or 168 && IsStadiumGiftSpecies((byte)head.Species))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@ internal static PotentialGBOrigin GetTradebackStatusInitial(PKM pk)
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Tradeback status depending on the <see cref="PK1.Catch_Rate"/>
|
||||
/// Gets the Tradeback status depending on the <see cref="PK1.CatchRate"/>
|
||||
/// </summary>
|
||||
/// <param name="pk">Pokémon to guess the Tradeback status from.</param>
|
||||
private static PotentialGBOrigin GetTradebackStatusRBY(PK1 pk)
|
||||
|
|
@ -169,7 +169,7 @@ private static PotentialGBOrigin GetTradebackStatusRBY(PK1 pk)
|
|||
return Gen1Only;
|
||||
|
||||
// Detect Tradeback status by comparing the catch rate(Gen1)/held item(Gen2) to the species in the Pokémon's evolution chain.
|
||||
var catch_rate = pk.Catch_Rate;
|
||||
var catch_rate = pk.CatchRate;
|
||||
if (catch_rate == 0)
|
||||
return Either;
|
||||
|
||||
|
|
@ -189,7 +189,7 @@ public static TimeCapsuleEvaluation IsTimeCapsuleTransferred(PKM pk, ReadOnlySpa
|
|||
{
|
||||
if (z.Generation == enc.Generation || z.Generation is not (1 or 2))
|
||||
continue;
|
||||
if (pk is PK1 {Catch_Rate: not 0} g1 && !IsTradebackCatchRate(g1.Catch_Rate))
|
||||
if (pk is PK1 {CatchRate: not 0} g1 && !IsTradebackCatchRate(g1.CatchRate))
|
||||
return BadCatchRate;
|
||||
return enc.Generation == 2 ? Transferred21 : Transferred12;
|
||||
}
|
||||
|
|
@ -217,7 +217,7 @@ public static TimeCapsuleEvaluation IsTimeCapsuleTransferred(PKM pk, ReadOnlySpa
|
|||
|
||||
if (gb is PK1 pk1)
|
||||
{
|
||||
var rate = pk1.Catch_Rate;
|
||||
var rate = pk1.CatchRate;
|
||||
if (rate == 0)
|
||||
return Transferred12;
|
||||
|
||||
|
|
@ -234,7 +234,7 @@ public static TimeCapsuleEvaluation IsTimeCapsuleTransferred(PKM pk, ReadOnlySpa
|
|||
EncounterGift1 g when g.GetMatchRating(pk1) < EncounterMatchRating.PartialMatch => true,
|
||||
EncounterStatic1 s when s.GetMatchRating(pk1) < EncounterMatchRating.PartialMatch => true,
|
||||
EncounterTrade1 => true,
|
||||
_ => RateMatchesEncounter(enc.Species, enc.Version, pk1.Catch_Rate),
|
||||
_ => RateMatchesEncounter(enc.Species, enc.Version, pk1.CatchRate),
|
||||
};
|
||||
|
||||
public static bool IsTradebackCatchRate(byte rate) => Array.IndexOf(HeldItems_GSC, rate) != -1;
|
||||
|
|
|
|||
|
|
@ -370,48 +370,45 @@ private void VerifyMiscG1Types(LegalityAnalysis data, PK1 pk1)
|
|||
|
||||
private void VerifyMiscG1CatchRate(LegalityAnalysis data, PK1 pk1)
|
||||
{
|
||||
var catch_rate = pk1.Catch_Rate;
|
||||
var tradeback = GBRestrictions.IsTimeCapsuleTransferred(pk1, data.Info.Moves, data.EncounterMatch);
|
||||
var result = tradeback is TimeCapsuleEvaluation.NotTransferred or TimeCapsuleEvaluation.BadCatchRate
|
||||
? GetWasNotTradeback(tradeback)
|
||||
: GetWasTradeback(tradeback);
|
||||
? GetWasNotTradeback(data, pk1, tradeback)
|
||||
: GetWasTradeback(data, pk1, tradeback);
|
||||
data.AddLine(result);
|
||||
}
|
||||
|
||||
CheckResult GetWasTradeback(TimeCapsuleEvaluation timeCapsuleEvalution)
|
||||
private CheckResult GetWasTradeback(LegalityAnalysis data, PK1 pk1, TimeCapsuleEvaluation eval)
|
||||
{
|
||||
var rate = pk1.CatchRate;
|
||||
if (PK1.IsCatchRateHeldItem(rate))
|
||||
return GetValid(LG1CatchRateMatchTradeback);
|
||||
return GetWasNotTradeback(data, pk1, eval);
|
||||
}
|
||||
|
||||
private CheckResult GetWasNotTradeback(LegalityAnalysis data, PK1 pk1, TimeCapsuleEvaluation eval)
|
||||
{
|
||||
var rate = pk1.CatchRate;
|
||||
if (MoveInfo.IsAnyFromGeneration(2, data.Info.Moves))
|
||||
return GetInvalid(LG1CatchRateItem);
|
||||
var e = data.EncounterMatch;
|
||||
if (e is EncounterGift1 { Version: GameVersion.Stadium } or EncounterTrade1)
|
||||
return GetValid(LG1CatchRateMatchPrevious); // Encounters detected by the catch rate, cant be invalid if match this encounters
|
||||
|
||||
ushort species = pk1.Species;
|
||||
if (GBRestrictions.IsSpeciesNotAvailableCatchRate((byte)species) && rate == PersonalTable.RB[species].CatchRate)
|
||||
{
|
||||
if (PK1.IsCatchRateHeldItem(catch_rate))
|
||||
return GetValid(LG1CatchRateMatchTradeback);
|
||||
if (timeCapsuleEvalution == TimeCapsuleEvaluation.BadCatchRate)
|
||||
return GetInvalid(LG1CatchRateItem);
|
||||
|
||||
return GetWasNotTradeback(timeCapsuleEvalution);
|
||||
}
|
||||
|
||||
CheckResult GetWasNotTradeback(TimeCapsuleEvaluation timeCapsuleEvalution)
|
||||
{
|
||||
if (MoveInfo.IsAnyFromGeneration(2, data.Info.Moves))
|
||||
return GetInvalid(LG1CatchRateItem);
|
||||
var e = data.EncounterMatch;
|
||||
if (e is EncounterGift1 {Version: GameVersion.Stadium} or EncounterTrade1)
|
||||
return GetValid(LG1CatchRateMatchPrevious); // Encounters detected by the catch rate, cant be invalid if match this encounters
|
||||
|
||||
ushort species = pk1.Species;
|
||||
if (GBRestrictions.IsSpeciesNotAvailableCatchRate((byte)species) && catch_rate == PersonalTable.RB[species].CatchRate)
|
||||
{
|
||||
if (species != (int) Species.Dragonite || catch_rate != 45 || !(e.Version == GameVersion.BU || e.Version.Contains(GameVersion.YW)))
|
||||
return GetInvalid(LG1CatchRateEvo);
|
||||
}
|
||||
if (!GBRestrictions.RateMatchesEncounter(e.Species, e.Version, catch_rate))
|
||||
return GetInvalid(timeCapsuleEvalution == TimeCapsuleEvaluation.Transferred12 ? LG1CatchRateChain : LG1CatchRateNone);
|
||||
return GetValid(LG1CatchRateMatchPrevious);
|
||||
if (species != (int)Species.Dragonite || rate != 45 || !(e.Version == GameVersion.BU || e.Version.Contains(GameVersion.YW)))
|
||||
return GetInvalid(LG1CatchRateEvo);
|
||||
}
|
||||
if (!GBRestrictions.RateMatchesEncounter(e.Species, e.Version, rate))
|
||||
return GetInvalid(eval == TimeCapsuleEvaluation.Transferred12 ? LG1CatchRateChain : LG1CatchRateNone);
|
||||
return GetValid(LG1CatchRateMatchPrevious);
|
||||
}
|
||||
|
||||
private static void VerifyMiscFatefulEncounter(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
var enc = data.EncounterMatch;
|
||||
switch (enc)
|
||||
switch (data.EncounterMatch)
|
||||
{
|
||||
case WC3 {FatefulEncounter: true} w:
|
||||
if (w.IsEgg)
|
||||
|
|
@ -420,7 +417,7 @@ private static void VerifyMiscFatefulEncounter(LegalityAnalysis data)
|
|||
// Hatching in Gen3 doesn't change the origin version.
|
||||
if (pk.Format != 3)
|
||||
return; // possible hatched in either game, don't bother checking
|
||||
if (pk.Met_Location <= 087) // hatched in RS or Emerald
|
||||
if (Locations.IsMetLocation3RS((ushort)pk.Met_Location)) // hatched in RS or Emerald
|
||||
return; // possible hatched in either game, don't bother checking
|
||||
// else, ensure fateful is active (via below)
|
||||
}
|
||||
|
|
@ -484,7 +481,7 @@ private static void VerifyMiscMovePP(LegalityAnalysis data)
|
|||
private static void VerifyMiscEggCommon(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
if (pk.Move1_PPUps > 0 || pk.Move2_PPUps > 0 || pk.Move3_PPUps > 0 || pk.Move4_PPUps > 0)
|
||||
if (pk.Move1_PPUps != 0 || pk.Move2_PPUps != 0 || pk.Move3_PPUps != 0 || pk.Move4_PPUps != 0)
|
||||
data.AddLine(GetInvalid(LEggPPUp, Egg));
|
||||
if (!IsZeroMovePP(pk))
|
||||
data.AddLine(GetInvalid(LEggPP, Egg));
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public override PK1 Clone()
|
|||
public override int Status_Condition { get => Data[4]; set => Data[4] = (byte)value; }
|
||||
public byte Type1 { get => Data[5]; set => Data[5] = value; }
|
||||
public byte Type2 { get => Data[6]; set => Data[6] = value; }
|
||||
public byte Catch_Rate { get => Data[7]; set => Data[7] = value; }
|
||||
public byte CatchRate { get => Data[7]; set => Data[7] = value; }
|
||||
public override ushort Move1 { get => Data[8]; set => Data[8] = (byte)value; }
|
||||
public override ushort Move2 { get => Data[9]; set => Data[9] = (byte)value; }
|
||||
public override ushort Move3 { get => Data[10]; set => Data[10] = (byte)value; }
|
||||
|
|
@ -104,11 +104,11 @@ private void SetSpeciesValues(ushort value)
|
|||
Type2 = pi.Type2;
|
||||
|
||||
// Before updating catch rate, check if non-standard
|
||||
if (IsValidCatchRateAnyPreEvo((byte)value, Catch_Rate))
|
||||
if (IsValidCatchRateAnyPreEvo((byte)value, CatchRate))
|
||||
return;
|
||||
|
||||
// Matches nothing possible; just reset to current Species' rate.
|
||||
Catch_Rate = (byte)pi.CatchRate;
|
||||
CatchRate = pi.CatchRate;
|
||||
}
|
||||
|
||||
private static bool IsValidCatchRateAnyPreEvo(byte species, byte rate)
|
||||
|
|
@ -145,7 +145,7 @@ private static bool IsValidCatchRateAnyPreEvo(byte species, byte rate)
|
|||
public override int MaxItemID => Legal.MaxItemID_1;
|
||||
|
||||
// Extra
|
||||
public int Gen2Item => ItemConverter.GetItemFuture1(Catch_Rate);
|
||||
public int Gen2Item => ItemConverter.GetItemFuture1(CatchRate);
|
||||
|
||||
public PK2 ConvertToPK2()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// Logic for converting Item IDs between the generation specific value sets.
|
||||
/// </summary>
|
||||
internal static class ItemConverter
|
||||
public static class ItemConverter
|
||||
{
|
||||
/// <summary>Unused item ID, placeholder for item/sprite finding in Generations 2-4.</summary>
|
||||
private const ushort NaN = 128;
|
||||
|
|
@ -15,32 +15,32 @@ internal static class ItemConverter
|
|||
/// </summary>
|
||||
/// <param name="item">Generation 3 Item ID.</param>
|
||||
/// <returns>True if transferable, False if not transferable.</returns>
|
||||
internal static bool IsItemTransferable34(ushort item) => item != NaN && item > 0;
|
||||
public static bool IsItemTransferable34(ushort item) => item != NaN && item > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Generation 3 Item ID to Generation 4+ Item ID.
|
||||
/// </summary>
|
||||
/// <param name="item">Generation 3 Item ID.</param>
|
||||
/// <returns>Generation 4+ Item ID.</returns>
|
||||
internal static ushort GetItemFuture3(ushort item) => item > arr3.Length ? NaN : arr3[item];
|
||||
public static ushort GetItemFuture3(ushort item) => item > Item3to4.Length ? NaN : Item3to4[item];
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Generation 2 Item ID to Generation 4+ Item ID.
|
||||
/// </summary>
|
||||
/// <param name="item">Generation 2 Item ID.</param>
|
||||
/// <returns>Generation 4+ Item ID.</returns>
|
||||
internal static ushort GetItemFuture2(byte item) => item > arr2.Length ? NaN : arr2[item];
|
||||
public static ushort GetItemFuture2(byte item) => item > Item2to4.Length ? NaN : Item2to4[item];
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Generation 4+ Item ID to Generation 3 Item ID.
|
||||
/// </summary>
|
||||
/// <param name="item">Generation 4+ Item ID.</param>
|
||||
/// <returns>Generation 3 Item ID.</returns>
|
||||
private static ushort GetItemOld3(ushort item)
|
||||
public static ushort GetItemOld3(ushort item)
|
||||
{
|
||||
if (item == NaN)
|
||||
return 0;
|
||||
int index = arr3.IndexOf(item);
|
||||
int index = Item3to4.IndexOf(item);
|
||||
return (ushort)Math.Max(0, index);
|
||||
}
|
||||
|
||||
|
|
@ -49,17 +49,17 @@ private static ushort GetItemOld3(ushort item)
|
|||
/// </summary>
|
||||
/// <param name="item">Generation 4+ Item ID.</param>
|
||||
/// <returns>Generation 2 Item ID.</returns>
|
||||
private static byte GetItemOld2(ushort item)
|
||||
public static byte GetItemOld2(ushort item)
|
||||
{
|
||||
if (item == NaN)
|
||||
return 0;
|
||||
int index = arr2.IndexOf(item);
|
||||
int index = Item2to4.IndexOf(item);
|
||||
return (byte)Math.Max(0, index);
|
||||
}
|
||||
|
||||
#region Item Mapping Tables
|
||||
/// <summary> Gen2 items (index) and their corresponding Gen4 item ID (value) </summary>
|
||||
private static ReadOnlySpan<ushort> arr2 =>
|
||||
private static ReadOnlySpan<ushort> Item2to4 =>
|
||||
[
|
||||
000, 001, 002, 213, 003, 004, NaN, 450, 081, 018, // 0
|
||||
019, 020, 021, 022, 023, 024, 025, 026, 017, 078, // 1
|
||||
|
|
@ -90,7 +90,7 @@ private static byte GetItemOld2(ushort item)
|
|||
];
|
||||
|
||||
/// <summary> Gen3 items (index) and their corresponding Gen4 item ID (value) </summary>
|
||||
private static ReadOnlySpan<ushort> arr3 =>
|
||||
private static ReadOnlySpan<ushort> Item3to4 =>
|
||||
[
|
||||
000, 001, 002, 003, 004, 005, 006, 007, 008, 009,
|
||||
010, 011, 012, 017, 018, 019, 020, 021, 022, 023,
|
||||
|
|
@ -149,11 +149,11 @@ private static byte GetItemOld2(ushort item)
|
|||
};
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Gen1 <see cref="PK1.Catch_Rate"/> value to Gen2 Item.
|
||||
/// Converts a Gen1 <see cref="PK1.CatchRate"/> value to Gen2 Item.
|
||||
/// </summary>
|
||||
/// <param name="value">Gen1 Item</param>
|
||||
/// <returns>Gen2 Item</returns>
|
||||
internal static int GetItemFuture1(byte value)
|
||||
public static int GetItemFuture1(byte value)
|
||||
{
|
||||
if (!IsItemTransferable12(value))
|
||||
return GetTeruSamaItem(value);
|
||||
|
|
@ -169,7 +169,7 @@ internal static int GetItemFuture1(byte value)
|
|||
/// <param name="srcFormat">Format from importing</param>
|
||||
/// <param name="destFormat">Format required for holder</param>
|
||||
/// <returns>destItem</returns>
|
||||
internal static int GetItemForFormat(int srcItem, EntityContext srcFormat, EntityContext destFormat)
|
||||
public static int GetItemForFormat(int srcItem, EntityContext srcFormat, EntityContext destFormat)
|
||||
{
|
||||
if (srcItem <= 0)
|
||||
return 0;
|
||||
|
|
@ -208,7 +208,7 @@ internal static int GetItemForFormat(int srcItem, EntityContext srcFormat, Entit
|
|||
/// <param name="item">Item ID</param>
|
||||
/// <param name="generation">Generation the <see cref="item"/> exists in</param>
|
||||
/// <returns>True if is an HM</returns>
|
||||
internal static bool IsItemHM(ushort item, int generation) => generation switch
|
||||
public static bool IsItemHM(ushort item, int generation) => generation switch
|
||||
{
|
||||
1 => item is (>= 196 and <= 200),
|
||||
2 => item is (>= 243 and <= 249),
|
||||
|
|
|
|||
|
|
@ -16,8 +16,24 @@ public static class Experience
|
|||
public static int GetLevel(uint exp, byte growth)
|
||||
{
|
||||
var table = GetTable(growth);
|
||||
return GetLevel(exp, table);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current level of a species.
|
||||
/// </summary>
|
||||
/// <param name="exp">Experience points</param>
|
||||
/// <param name="table">Experience growth table</param>
|
||||
/// <returns>Current level of the species.</returns>
|
||||
public static int GetLevel(uint exp, ReadOnlySpan<uint> table)
|
||||
{
|
||||
// Eagerly return 100 if the exp is at max
|
||||
// Also avoids overflow issues with the table in the event EXP is out of bounds
|
||||
if (exp >= table[^1])
|
||||
return 100;
|
||||
|
||||
// Most will be below level 50, so start from the bottom
|
||||
// Don't bother with binary search, as the table is small
|
||||
int tl = 1; // Initial Level. Iterate upwards to find the level
|
||||
while (exp >= table[tl])
|
||||
++tl;
|
||||
|
|
@ -41,7 +57,13 @@ public static uint GetEXP(int level, byte growth)
|
|||
return table[level - 1];
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<uint> GetTable(byte growth) => growth switch
|
||||
/// <summary>
|
||||
/// Gets the minimum Experience points for all levels possible.
|
||||
/// </summary>
|
||||
/// <param name="growth">Growth Rate type</param>
|
||||
/// <returns>Experience points needed to have an indexed level.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static ReadOnlySpan<uint> GetTable(byte growth) => growth switch
|
||||
{
|
||||
0 => Growth0,
|
||||
1 => Growth1,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public sealed class PersonalInfo1(byte[] Data) : PersonalInfo, IPersonalInfoTM
|
|||
public override int SPD { get => SPC; set => SPC = value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int BaseEXP { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
public byte Move1 { get => Data[0x0F]; set => Data[0x0F] = value; }
|
||||
public byte Move2 { get => Data[0x10]; set => Data[0x10] = value; }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo2(byte[] Data) : PersonalInfo, IPersonalInfoTM,
|
|||
public override int SPD { get => Data[0x06]; set => Data[0x06] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override byte Type2 { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int CatchRate { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x09]; set => Data[0x09] = value; }
|
||||
public override int BaseEXP { get => Data[0x0A]; set => Data[0x0A] = (byte)value; }
|
||||
public int Item1 { get => Data[0xB]; set => Data[0xB] = (byte)value; }
|
||||
public int Item2 { get => Data[0xC]; set => Data[0xC] = (byte)value; }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo3(byte[] Data) : PersonalInfo, IPersonalAbility1
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int BaseEXP { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo4(byte[] Data) : PersonalInfo, IPersonalAbility1
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int BaseEXP { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo5B2W2(byte[] Data) : PersonalInfo, IPersonalAbil
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo5BW(byte[] Data) : PersonalInfo, IPersonalAbilit
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo6AO(byte[] Data) : PersonalInfo, IPersonalAbilit
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo6XY(byte[] Data) : PersonalInfo, IPersonalAbilit
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public sealed class PersonalInfo7(byte[] Data)
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo7GG(byte[] Data) : PersonalInfo, IPersonalAbilit
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public sealed class PersonalInfo8BDSP(byte[] Data)
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo8LA(byte[] Data) : PersonalInfo, IPersonalAbilit
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public sealed class PersonalInfo8SWSH(byte[] Data) : PersonalInfo, IPersonalAbil
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class PersonalInfo9SV(byte[] Data) : PersonalInfo, IPersonalAbilit
|
|||
public override int SPD { get => Data[0x05]; set => Data[0x05] = (byte)value; }
|
||||
public override byte Type1 { get => Data[0x06]; set => Data[0x06] = value; }
|
||||
public override byte Type2 { get => Data[0x07]; set => Data[0x07] = value; }
|
||||
public override int CatchRate { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public override byte CatchRate { get => Data[0x08]; set => Data[0x08] = value; }
|
||||
public override int EvoStage { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
private int EVYield { get => ReadUInt16LittleEndian(Data.AsSpan(0x0A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value); }
|
||||
public override int EV_HP { get => (EVYield >> 0) & 0x3; set => EVYield = (EVYield & ~(0x3 << 0)) | ((value & 0x3) << 0); }
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public interface IPersonalEncounter
|
|||
/// <summary>
|
||||
/// Catch Rate
|
||||
/// </summary>
|
||||
int CatchRate { get; set; }
|
||||
byte CatchRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initial Friendship when captured or received.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user