mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-08-24 10:48:45 -05:00
Merge pull request #3382 from kwsch/pla
Update 22.02.04 Individual commits from this PR are not cherry-pickable in a vacuum; these were manually re-committed from a staging repo in order to group together changes for general public viewing. There were over 250 commits on the private development repo for this update.
This commit is contained in:
6
.github/README-de.md
vendored
6
.github/README-de.md
vendored
@@ -24,13 +24,13 @@ PKHeX erwartet Spielstände, die mit konsolenspezifischen Schlüsseln entschlüs
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||
|
||||
## Erstellen
|
||||
|
||||
PKHeX ist eine Windows Forms Anwendung, die das [.NET Framework v4.6](https://www.microsoft.com/en-us/download/details.aspx?id=48137) benötigt, mit experimenteller Unterstützung für [.NET 5.0](https://dotnet.microsoft.com/download/dotnet/5.0).
|
||||
PKHeX ist eine Windows Forms Anwendung, die das [.NET Framework v4.6](https://www.microsoft.com/en-us/download/details.aspx?id=48137) benötigt, mit experimenteller Unterstützung für [.NET 6.0](https://dotnet.microsoft.com/download/dotnet/6.0).
|
||||
|
||||
Die Anwendung kann mit jedem Kompiler erstellt werde, der C# 8 unterstützt.
|
||||
Die Anwendung kann mit jedem Kompiler erstellt werde, der C# 10 unterstützt.
|
||||
|
||||
### Erstell Konfiguration
|
||||
|
||||
|
||||
6
.github/README-es.md
vendored
6
.github/README-es.md
vendored
@@ -24,13 +24,13 @@ PKHeX espera archivos de guardado que no estén cifrados con las claves específ
|
||||
|
||||
## Capturas de Pantalla
|
||||
|
||||

|
||||

|
||||
|
||||
## Building
|
||||
|
||||
PKHeX es una aplicación de Windows Forms que requiere [.NET Framework v4.6](https://www.microsoft.com/en-us/download/details.aspx?id=48137), con soporte experimental para [.NET 5.0](https://dotnet.microsoft.com/download/dotnet/5.0).
|
||||
PKHeX es una aplicación de Windows Forms que requiere [.NET Framework v4.6](https://www.microsoft.com/en-us/download/details.aspx?id=48137), con soporte experimental para [.NET 6.0](https://dotnet.microsoft.com/download/dotnet/6.0).
|
||||
|
||||
El archivo ejecutable puede ser construido con cualquier compilador que soporte C# 8.
|
||||
El archivo ejecutable puede ser construido con cualquier compilador que soporte C# 10.
|
||||
|
||||
### Configuraciones del Build
|
||||
|
||||
|
||||
6
.github/README-fr.md
vendored
6
.github/README-fr.md
vendored
@@ -23,13 +23,13 @@ PKHeX attend des fichiers de sauvegarde qui ne sont pas chiffrés avec des clés
|
||||
|
||||
## Captures d'écran
|
||||
|
||||

|
||||

|
||||
|
||||
## Construction
|
||||
|
||||
PKHeX est une application Windows Forms qui nécessite [.NET Framework v4.6](https://www.microsoft.com/en-us/download/details.aspx?id=48137), avec une prise en charge expérimentale de [.NET 5.0.](https://dotnet.microsoft.com/download/dotnet/5.0)
|
||||
PKHeX est une application Windows Forms qui nécessite [.NET Framework v4.6](https://www.microsoft.com/en-us/download/details.aspx?id=48137), avec une prise en charge expérimentale de [.NET 6.0.](https://dotnet.microsoft.com/download/dotnet/6.0)
|
||||
|
||||
L'exécutable peut être construit avec n'importe quel compilateur prenant en charge C# 8.
|
||||
L'exécutable peut être construit avec n'importe quel compilateur prenant en charge C# 10.
|
||||
|
||||
### Construire les configurations
|
||||
|
||||
|
||||
71
PKHeX.Core/Editing/Applicators/MoveShopRecordApplicator.cs
Normal file
71
PKHeX.Core/Editing/Applicators/MoveShopRecordApplicator.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Logic for modifying the Move Shop Record flags of a <see cref="PA8"/>.
|
||||
/// </summary>
|
||||
public static class MoveShopRecordApplicator
|
||||
{
|
||||
public static void ClearMoveShopFlags(this IMoveShop8 shop)
|
||||
{
|
||||
var bits = shop.MoveShopPermitFlags;
|
||||
for (int i = 0; i < bits.Length; i++)
|
||||
shop.SetPurchasedRecordFlag(i, false);
|
||||
|
||||
if (shop is IMoveShop8Mastery m)
|
||||
m.ClearMoveShopFlagsMastered();
|
||||
}
|
||||
|
||||
public static void ClearMoveShopFlagsMastered(this IMoveShop8Mastery shop)
|
||||
{
|
||||
var bits = shop.MoveShopPermitFlags;
|
||||
for (int i = 0; i < bits.Length; i++)
|
||||
shop.SetMasteredRecordFlag(i, false);
|
||||
}
|
||||
|
||||
public static void SetMoveShopFlags(this IMoveShop8 shop, bool value, int max = 100)
|
||||
{
|
||||
var bits = shop.MoveShopPermitFlags;
|
||||
max = Math.Min(bits.Length, max);
|
||||
for (int i = 0; i < max; i++)
|
||||
shop.SetPurchasedRecordFlag(i, value);
|
||||
}
|
||||
|
||||
public static void SetMoveShopFlagsMastered(this IMoveShop8Mastery shop)
|
||||
{
|
||||
var bits = shop.MoveShopPermitFlags;
|
||||
for (int i = 0; i < bits.Length; i++)
|
||||
shop.SetMasteredRecordFlag(i, shop.GetPurchasedRecordFlag(i));
|
||||
}
|
||||
|
||||
public static void SetMoveShopFlags(this IMoveShop8 shop)
|
||||
{
|
||||
var permit = shop.MoveShopPermitFlags;
|
||||
for (int index = 0; index < permit.Length; index++)
|
||||
{
|
||||
if (permit[index])
|
||||
shop.SetPurchasedRecordFlag(index, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Shop Record flags for the <see cref="shop"/> based on the current moves.
|
||||
/// </summary>
|
||||
/// <param name="shop">Pokémon to modify.</param>
|
||||
/// <param name="moves">Moves to set flags for. If a move is not a Technical Record, it is skipped.</param>
|
||||
public static void SetMoveShopFlags(this IMoveShop8 shop, IEnumerable<int> moves)
|
||||
{
|
||||
var permit = shop.MoveShopPermitFlags;
|
||||
var moveIDs = shop.MoveShopPermitIndexes;
|
||||
foreach (var m in moves)
|
||||
{
|
||||
var index = moveIDs.IndexOf(m);
|
||||
if (index == -1)
|
||||
continue;
|
||||
if (permit[index])
|
||||
shop.SetPurchasedRecordFlag(index, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,38 +14,37 @@ public static class TechnicalRecordApplicator
|
||||
/// <param name="pk">Pokémon to modify.</param>
|
||||
/// <param name="value">Value to set for the record.</param>
|
||||
/// <param name="max">Max record to set.</param>
|
||||
public static void SetRecordFlags(this PKM pk, bool value, int max = 100)
|
||||
public static void SetRecordFlags(this ITechRecord8 pk, bool value, int max = 100)
|
||||
{
|
||||
if (pk is not PK8 pk8)
|
||||
return;
|
||||
for (int i = 0; i < max; i++)
|
||||
pk8.SetMoveRecordFlag(i, value);
|
||||
pk.SetMoveRecordFlag(i, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the Technical Record flags for the <see cref="pk"/>.
|
||||
/// </summary>
|
||||
/// <param name="pk">Pokémon to modify.</param>
|
||||
public static void ClearRecordFlags(this PKM pk) => pk.SetRecordFlags(false, 112);
|
||||
public static void ClearRecordFlags(this ITechRecord8 pk) => pk.SetRecordFlags(false, 112);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Technical Record flags for the <see cref="pk"/> based on the current moves.
|
||||
/// </summary>
|
||||
/// <param name="pk">Pokémon to modify.</param>
|
||||
/// <param name="moves">Moves to set flags for. If a move is not a Technical Record, it is skipped.</param>
|
||||
public static void SetRecordFlags(this PKM pk, IEnumerable<int> moves)
|
||||
public static void SetRecordFlags(this ITechRecord8 pk, IEnumerable<int> moves)
|
||||
{
|
||||
if (pk is not PK8 pk8)
|
||||
if (pk is PA8)
|
||||
return;
|
||||
var permit = pk8.PersonalInfo.TMHM.AsSpan(PersonalInfoSWSH.CountTM);
|
||||
var moveIDs = Legal.TMHM_SWSH.AsSpan(PersonalInfoSWSH.CountTM);
|
||||
|
||||
var permit = pk.TechRecordPermitFlags;
|
||||
var moveIDs = pk.TechRecordPermitIndexes;
|
||||
foreach (var m in moves)
|
||||
{
|
||||
var index = moveIDs.IndexOf(m);
|
||||
if (index == -1)
|
||||
continue;
|
||||
if (permit[index])
|
||||
pk8.SetMoveRecordFlag(index, true);
|
||||
pk.SetMoveRecordFlag(index, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,15 +52,13 @@ public static void SetRecordFlags(this PKM pk, IEnumerable<int> moves)
|
||||
/// Sets all the Technical Record flags for the <see cref="pk"/> if they are permitted to be learned in-game.
|
||||
/// </summary>
|
||||
/// <param name="pk">Pokémon to modify.</param>
|
||||
public static void SetRecordFlags(this PKM pk)
|
||||
public static void SetRecordFlags(this ITechRecord8 pk)
|
||||
{
|
||||
if (pk is not PK8 pk8)
|
||||
return;
|
||||
var permit = pk8.PersonalInfo.TMHM.AsSpan(PersonalInfoSWSH.CountTM); // tm[100], tr[100]
|
||||
var permit = pk.TechRecordPermitFlags;
|
||||
for (int i = 0; i < permit.Length; i++)
|
||||
{
|
||||
if (permit[i])
|
||||
pk8.SetMoveRecordFlag(i, true);
|
||||
pk.SetMoveRecordFlag(i, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public static class BatchEditing
|
||||
{
|
||||
public static readonly Type[] Types =
|
||||
{
|
||||
typeof (PK8), typeof (PB8),
|
||||
typeof (PK8), typeof (PA8), typeof (PB8),
|
||||
typeof (PB7),
|
||||
typeof (PK7), typeof (PK6), typeof (PK5), typeof (PK4), typeof(BK4),
|
||||
typeof (PK3), typeof (XK3), typeof (CK3),
|
||||
|
||||
@@ -14,13 +14,13 @@ internal static class BatchModifications
|
||||
public static ModifyResult SetSuggestedRelearnData(BatchInfo info, string propValue)
|
||||
{
|
||||
var pk = info.Entity;
|
||||
if (pk.Format >= 8)
|
||||
if (pk is ITechRecord8 t)
|
||||
{
|
||||
pk.ClearRecordFlags();
|
||||
t.ClearRecordFlags();
|
||||
if (IsAll(propValue))
|
||||
pk.SetRecordFlags(); // all
|
||||
t.SetRecordFlags(); // all
|
||||
else if (!IsNone(propValue))
|
||||
pk.SetRecordFlags(pk.Moves); // whatever fit the current moves
|
||||
t.SetRecordFlags(pk.Moves); // whatever fit the current moves
|
||||
}
|
||||
|
||||
pk.SetRelearnMoves(info.SuggestedRelearn);
|
||||
|
||||
@@ -248,14 +248,19 @@ public static void ApplySetDetails(this PKM pk, IBattleTemplate Set)
|
||||
b.ResetCalculatedValues();
|
||||
}
|
||||
}
|
||||
if (pk is IGanbaru g)
|
||||
g.SetSuggestedGanbaruValues(pk);
|
||||
|
||||
if (pk is IGigantamax c)
|
||||
c.CanGigantamax = Set.CanGigantamax;
|
||||
if (pk is IDynamaxLevel d)
|
||||
d.DynamaxLevel = d.CanHaveDynamaxLevel(pk) ? (byte)10 : (byte)0;
|
||||
|
||||
pk.ClearRecordFlags();
|
||||
pk.SetRecordFlags(Set.Moves);
|
||||
if (pk is ITechRecord8 t)
|
||||
{
|
||||
t.ClearRecordFlags();
|
||||
t.SetRecordFlags(Set.Moves);
|
||||
}
|
||||
|
||||
if (ShowdownSetBehaviorNature && pk.Format >= 8)
|
||||
pk.Nature = pk.StatNature;
|
||||
|
||||
@@ -54,23 +54,25 @@ protected BoxManipBase(BoxManipType type, Func<SaveFile, bool> usable)
|
||||
public static readonly IReadOnlyList<BoxManipBase> ClearCommon = new List<BoxManipBase>
|
||||
{
|
||||
new BoxManipClear(BoxManipType.DeleteAll, _ => true),
|
||||
new BoxManipClear(BoxManipType.DeleteEggs, pk => pk.IsEgg, s => s.Generation >= 2),
|
||||
new BoxManipClear(BoxManipType.DeleteEggs, pk => pk.IsEgg, s => s.Generation >= 2 & s is not SAV8LA),
|
||||
new BoxManipClearComplex(BoxManipType.DeletePastGen, (pk, sav) => pk.Generation != sav.Generation, s => s.Generation >= 4),
|
||||
new BoxManipClearComplex(BoxManipType.DeleteForeign, (pk, sav) => !sav.IsOriginalHandler(pk, pk.Format > 2)),
|
||||
new BoxManipClear(BoxManipType.DeleteUntrained, pk => pk.EVTotal == 0),
|
||||
new BoxManipClear(BoxManipType.DeleteItemless, pk => pk.HeldItem == 0),
|
||||
new BoxManipClear(BoxManipType.DeleteUntrained, pk => pk.EVTotal == 0, s => s is not SAV8LA),
|
||||
new BoxManipClear(BoxManipType.DeleteUntrained, pk => !((PA8)pk).IsGanbaruValuesMax(pk), s => s is SAV8LA),
|
||||
new BoxManipClear(BoxManipType.DeleteItemless, pk => pk.HeldItem == 0, s => s is not SAV8LA),
|
||||
new BoxManipClear(BoxManipType.DeleteIllegal, pk => !new LegalityAnalysis(pk).Valid),
|
||||
new BoxManipClearDuplicate<string>(BoxManipType.DeleteClones, pk => SearchUtil.GetCloneDetectMethod(CloneDetectionMethod.HashDetails)(pk)),
|
||||
};
|
||||
|
||||
public static readonly IReadOnlyList<BoxManipModify> ModifyCommon = new List<BoxManipModify>
|
||||
{
|
||||
new(BoxManipType.ModifyHatchEggs, pk => pk.ForceHatchPKM(), s => s.Generation >= 2),
|
||||
new(BoxManipType.ModifyHatchEggs, pk => pk.ForceHatchPKM(), s => s.Generation >= 2 & s is not SAV8LA),
|
||||
new(BoxManipType.ModifyMaxFriendship, pk => pk.MaximizeFriendship()),
|
||||
new(BoxManipType.ModifyMaxLevel, pk => pk.MaximizeLevel()),
|
||||
new(BoxManipType.ModifyResetMoves, pk => pk.SetMoves(pk.GetMoveSet()), s => s.Generation >= 3),
|
||||
new(BoxManipType.ModifyRandomMoves, pk => pk.SetMoves(pk.GetMoveSet(true))),
|
||||
new(BoxManipType.ModifyHyperTrain,pk => pk.SetSuggestedHyperTrainingData(), s => s.Generation >= 7),
|
||||
new(BoxManipType.ModifyHyperTrain,pk => pk.SetSuggestedHyperTrainingData(), s => s.Generation >= 7 && s is not SAV8LA),
|
||||
new(BoxManipType.ModifyGanbaru,pk => ((IGanbaru)pk).SetSuggestedGanbaruValues(pk), s => s is SAV8LA),
|
||||
new(BoxManipType.ModifyRemoveNicknames, pk => pk.SetDefaultNickname()),
|
||||
new(BoxManipType.ModifyRemoveItem, pk => pk.HeldItem = 0, s => s.Generation >= 2),
|
||||
new(BoxManipType.ModifyHeal, pk => pk.Heal(), s => s.Generation >= 8 || s is SAV7b),
|
||||
|
||||
@@ -42,6 +42,7 @@ public enum BoxManipType
|
||||
ModifyResetMoves,
|
||||
ModifyRandomMoves,
|
||||
ModifyHyperTrain,
|
||||
ModifyGanbaru,
|
||||
ModifyRemoveNicknames,
|
||||
ModifyRemoveItem,
|
||||
ModifyHeal,
|
||||
|
||||
@@ -55,6 +55,7 @@ public static List<SlotInfoMisc> GetExtraSlots(this SaveFile sav, bool all = fal
|
||||
SAV7b lgpe => GetExtraSlots7b(lgpe),
|
||||
SAV8SWSH ss => GetExtraSlots8(ss),
|
||||
SAV8BS bs => GetExtraSlots8b(bs),
|
||||
SAV8LA la => GetExtraSlots8a(la),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@@ -218,5 +219,10 @@ private static List<SlotInfoMisc> GetExtraSlots8b(SAV8BS sav)
|
||||
new(sav.Data, 8, sav.UgSaveData.GetSlotOffset(8), true) { Type = StorageSlotType.Misc },
|
||||
};
|
||||
}
|
||||
|
||||
private static List<SlotInfoMisc> GetExtraSlots8a(SAV8LA sav)
|
||||
{
|
||||
return new List<SlotInfoMisc>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,19 @@ public enum Ball : byte
|
||||
Sport = 24,
|
||||
Dream = 25,
|
||||
Beast = 26,
|
||||
|
||||
// Legends: Arceus
|
||||
Strange = 27,
|
||||
LAPoke = 28,
|
||||
LAGreat = 29,
|
||||
LAUltra = 30,
|
||||
LAFeather = 31,
|
||||
LAWing = 32,
|
||||
LAJet = 33,
|
||||
LAHeavy = 34,
|
||||
LALeaden = 35,
|
||||
LAGigaton = 36,
|
||||
LAOrigin = 37,
|
||||
}
|
||||
|
||||
public static class BallExtensions
|
||||
|
||||
@@ -204,7 +204,7 @@ public enum GameVersion
|
||||
SH = 45,
|
||||
|
||||
// HOME = 46,
|
||||
// PLA = 47,
|
||||
PLA = 47,
|
||||
|
||||
/// <summary>
|
||||
/// Pokémon Brilliant Diamond (NX)
|
||||
@@ -459,6 +459,7 @@ public enum GameVersion
|
||||
/// </summary>
|
||||
/// <see cref="SWSH"/>
|
||||
/// <see cref="BDSP"/>
|
||||
/// <see cref="PLA"/>
|
||||
Gen8,
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -832,6 +832,30 @@ public enum Move
|
||||
GlacialLance,
|
||||
AstralBarrage,
|
||||
EerieSpell,
|
||||
DireClaw,
|
||||
PsyshieldBash,
|
||||
PowerShift,
|
||||
StoneAxe,
|
||||
SpringtideStorm,
|
||||
MysticalPower,
|
||||
RagingFury,
|
||||
WaveCrash,
|
||||
Chloroblast,
|
||||
MountainGale,
|
||||
VictoryDance,
|
||||
HeadlongRush,
|
||||
BarbBarrage,
|
||||
EsperWing,
|
||||
BitterMalice,
|
||||
Shelter,
|
||||
TripleArrows,
|
||||
InfernalParade,
|
||||
CeaselessEdge,
|
||||
BleakwindStorm,
|
||||
WildboltStorm,
|
||||
SandsearStorm,
|
||||
LunarBlessing,
|
||||
TakeHeart,
|
||||
MAX_COUNT,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,6 +904,13 @@ public enum Species : ushort
|
||||
Glastrier,
|
||||
Spectrier,
|
||||
Calyrex,
|
||||
Wyrdeer,
|
||||
Kleavor,
|
||||
Ursaluna,
|
||||
Basculegion,
|
||||
Sneasler,
|
||||
Overqwil,
|
||||
Enamorus,
|
||||
MAX_COUNT,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,8 +74,8 @@ public GameDataSource(GameStrings s)
|
||||
private static IReadOnlyList<ComboItem> GetBalls(string[] itemList)
|
||||
{
|
||||
// ignores Poke/Great/Ultra
|
||||
ReadOnlySpan<ushort> ball_nums = stackalloc ushort[] { 007, 576, 013, 492, 497, 014, 495, 493, 496, 494, 011, 498, 008, 006, 012, 015, 009, 005, 499, 010, 001, 016, 851 };
|
||||
ReadOnlySpan<byte> ball_vals = stackalloc byte[] { 007, 025, 013, 017, 022, 014, 020, 018, 021, 019, 011, 023, 008, 006, 012, 015, 009, 005, 024, 010, 001, 016, 026 };
|
||||
ReadOnlySpan<ushort> ball_nums = stackalloc ushort[] { 007, 576, 013, 492, 497, 014, 495, 493, 496, 494, 011, 498, 008, 006, 012, 015, 009, 005, 499, 010, 001, 016, 851, 1785, 1710, 1711, 1712, 1713, 1746, 1747, 1748, 1749, 1750, 1771 };
|
||||
ReadOnlySpan<byte> ball_vals = stackalloc byte[] { 007, 025, 013, 017, 022, 014, 020, 018, 021, 019, 011, 023, 008, 006, 012, 015, 009, 005, 024, 010, 001, 016, 026, 0027, 0028, 0029, 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037 };
|
||||
return Util.GetVariedCBListBall(itemList, ball_nums, ball_vals);
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ private static IReadOnlyList<ComboItem> GetVersionList(GameStrings s)
|
||||
var list = s.gamelist;
|
||||
ReadOnlySpan<byte> games = stackalloc byte[]
|
||||
{
|
||||
47, // 8 legends arceus
|
||||
48, 49, // 8 bdsp
|
||||
44, 45, // 8 swsh
|
||||
42, 43, // 7 gg
|
||||
|
||||
@@ -25,6 +25,7 @@ public sealed class GameStrings : IBasicStrings
|
||||
public readonly string[] metGG_00000, metGG_30000, metGG_40000, metGG_60000;
|
||||
public readonly string[] metSWSH_00000, metSWSH_30000, metSWSH_40000, metSWSH_60000;
|
||||
public readonly string[] metBDSP_00000, metBDSP_30000, metBDSP_40000, metBDSP_60000;
|
||||
public readonly string[] metLA_00000, metLA_30000, metLA_40000, metLA_60000;
|
||||
|
||||
// Misc
|
||||
public readonly string[] wallpapernames, puffs, walkercourses;
|
||||
@@ -48,9 +49,11 @@ public sealed class GameStrings : IBasicStrings
|
||||
/// </summary>
|
||||
private static readonly ushort[] Items_Ball =
|
||||
{
|
||||
000, 001, 002, 003, 004, 005, 006, 007, 008, 009, 010, 011, 012,
|
||||
013, 014, 015, 016, 492, 493, 494, 495, 496, 497, 498, 499, 576,
|
||||
851,
|
||||
0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, 0008, 0009,
|
||||
0010, 0011, 0012, 0013, 0014, 0015, 0016, 0492, 0493, 0494,
|
||||
0495, 0496, 0497, 0498, 0499, 0576, 0851,
|
||||
1785, 1710, 1711,
|
||||
1712, 1713, 1746, 1747, 1748, 1749, 1750, 1771,
|
||||
};
|
||||
|
||||
public GameStrings(string l)
|
||||
@@ -138,6 +141,11 @@ public GameStrings(string l)
|
||||
metSWSH_40000 = Get("swsh_40000");
|
||||
metSWSH_60000 = Get("swsh_60000");
|
||||
|
||||
metLA_00000 = Get("la_00000");
|
||||
metLA_30000 = Get("la_30000");
|
||||
metLA_40000 = Get("la_40000");
|
||||
metLA_60000 = Get("la_60000");
|
||||
|
||||
metBDSP_00000 = Get("bdsp_00000");
|
||||
metBDSP_30000 = Get("bdsp_30000");
|
||||
metBDSP_40000 = Get("bdsp_40000");
|
||||
@@ -250,6 +258,86 @@ private void SanitizeItemNames()
|
||||
g3coloitems[500 + i] += $" ({i - 11:00})";
|
||||
// differentiate G3 Card Key from Colo
|
||||
g3coloitems[500 + 10] += " (COLO)";
|
||||
|
||||
SanitizeItemsLA(itemlist);
|
||||
|
||||
if (lang is "fr")
|
||||
{
|
||||
itemlist[1681] += " (LA)"; // Galet Noir dup with 617 (Dark Stone | Black Tumblestone)
|
||||
}
|
||||
else if (lang is "ja")
|
||||
{
|
||||
itemlist[1693] += " (LA)"; // むしよけスプレー dup with 79 (Repel)
|
||||
itemlist[1716] += " (LA)"; // ビビリだま dup with 847 (Adrenaline Orb | Scatter Bang)
|
||||
itemlist[1717] += " (LA)"; // けむりだま dup with 228 (Smoke Ball | Smoke Bomb)
|
||||
}
|
||||
|
||||
itemlist[464] += " (G4)"; // Secret Medicine
|
||||
itemlist[1763] += " (LA)"; // Secret Medicine
|
||||
}
|
||||
|
||||
private static void SanitizeItemsLA(string[] items)
|
||||
{
|
||||
// Recipes
|
||||
items[1784] += " (~)"; // Gigaton Ball
|
||||
items[1783] += " (~)"; // Leaden Ball
|
||||
items[1753] += " (~)"; // Heavy Ball
|
||||
items[1752] += " (~)"; // Jet Ball
|
||||
items[1751] += " (~)"; // Wing Ball
|
||||
items[1731] += " (~)"; // Twice-Spiced Radish
|
||||
items[1730] += " (~)"; // Choice Dumpling
|
||||
items[1729] += " (~)"; // Swap Snack
|
||||
items[1677] += " (~)"; // Aux Powerguard
|
||||
items[1676] += " (~)"; // Aux Evasion
|
||||
items[1675] += " (~)"; // Dire Hit
|
||||
items[1674] += " (~)"; // Aux Guard
|
||||
items[1673] += " (~)"; // Aux Power
|
||||
items[1671] += " (~)"; // Stealth Spray
|
||||
items[1670] += " (~)"; // Max Elixir
|
||||
items[1669] += " (~)"; // Max Ether
|
||||
items[1668] += " (~)"; // Max Revive
|
||||
items[1667] += " (~)"; // Revive
|
||||
items[1666] += " (~)"; // Full Heal
|
||||
items[1665] += " (~)"; // Jubilife Muffin
|
||||
items[1664] += " (~)"; // Old Gateau
|
||||
items[1663] += " (~)"; // Superb Remedy
|
||||
items[1662] += " (~)"; // Fine Remedy
|
||||
items[1661] += " (~)"; // Remedy
|
||||
items[1660] += " (~)"; // Full Restore
|
||||
items[1659] += " (~)"; // Max Potion
|
||||
items[1658] += " (~)"; // Hyper Potion
|
||||
items[1657] += " (~)"; // Super Potion
|
||||
items[1656] += " (~)"; // Potion
|
||||
items[1655] += " (~)"; // Salt Cake
|
||||
items[1654] += " (~)"; // Bean Cake
|
||||
items[1653] += " (~)"; // Grain Cake
|
||||
items[1652] += " (~)"; // Honey Cake
|
||||
items[1650] += " (~)"; // Mushroom Cake
|
||||
items[1649] += " (~)"; // Star Piece
|
||||
items[1648] += " (~)"; // Sticky Glob
|
||||
items[1647] += " (~)"; // Scatter Bang
|
||||
items[1646] += " (~)"; // Smoke Bomb
|
||||
items[1644] += " (~)"; // Pokéshi Doll
|
||||
items[1643] += " (~)"; // Feather Ball
|
||||
items[1642] += " (~)"; // Ultra Ball
|
||||
items[1641] += " (~)"; // Great Ball
|
||||
items[1640] += " (~)"; // Poké Ball
|
||||
|
||||
// Items
|
||||
items[1616] += " (LA)"; // Dire Hit
|
||||
items[1689] += " (LA)"; // Snowball
|
||||
items[1710] += " (LA)"; // Poké Ball
|
||||
items[1711] += " (LA)"; // Great Ball
|
||||
items[1712] += " (LA)"; // Ultra Ball
|
||||
items[1748] += " (LA)"; // Heavy Ball
|
||||
|
||||
// Key Items
|
||||
items[1622] += " (-)"; // Poké Ball
|
||||
items[1765] += " (1)"; // Lost Satchel
|
||||
items[1766] += " (2)"; // Lost Satchel
|
||||
items[1767] += " (3)"; // Lost Satchel
|
||||
items[1768] += " (4)"; // Lost Satchel
|
||||
items[1769] += " (5)"; // Lost Satchel
|
||||
}
|
||||
|
||||
private void SanitizeMetLocations()
|
||||
@@ -260,7 +348,9 @@ private void SanitizeMetLocations()
|
||||
SanitizeMetG6XY();
|
||||
SanitizeMetG7SM();
|
||||
SanitizeMetG8SWSH();
|
||||
SanitizeMetG8LA();
|
||||
SanitizeMetG8BDSP();
|
||||
SanitizeMetG8PLA();
|
||||
|
||||
if (lang is "es" or "it")
|
||||
{
|
||||
@@ -394,6 +484,12 @@ private void SanitizeMetG8SWSH()
|
||||
// metSWSH_30000[18] += " (-)"; // Pokémon HOME -- duplicate with 40000's entry
|
||||
}
|
||||
|
||||
private void SanitizeMetG8LA()
|
||||
{
|
||||
metBDSP_30000[1] += $" ({NPC})"; // Anything from an NPC
|
||||
metBDSP_30000[2] += $" ({EggName})"; // Egg From Link Trade
|
||||
}
|
||||
|
||||
private void SanitizeMetG8BDSP()
|
||||
{
|
||||
metBDSP_30000[1] += $" ({NPC})"; // Anything from an NPC
|
||||
@@ -405,6 +501,48 @@ private void SanitizeMetG8BDSP()
|
||||
Deduplicate(metBDSP_60000, 60000);
|
||||
}
|
||||
|
||||
private void SanitizeMetG8PLA()
|
||||
{
|
||||
metLA_00000[31] += " (2)"; // in Floaro Gardens
|
||||
metLA_30000[1] += $" ({NPC})"; // Anything from an NPC
|
||||
metLA_30000[2] += $" ({EggName})"; // Egg From Link Trade
|
||||
for (int i = 3; i <= 6; i++) // distinguish first set of regions (unused) from second (used)
|
||||
metLA_30000[i] += " (-)";
|
||||
metLA_30000[19] += " (?)"; // Kanto for the third time
|
||||
|
||||
metLA_40000[30] += " (-)"; // a Video game Event (in spanish etc) -- duplicate with line 39
|
||||
metLA_40000[53] += " (-)"; // a Pokémon event -- duplicate with line 37
|
||||
|
||||
metLA_40000[81] += " (-)"; // Pokémon GO -- duplicate with 30000's entry
|
||||
metLA_40000[86] += " (-)"; // Pokémon HOME -- duplicate with 30000's entry
|
||||
// metLA_30000[12] += " (-)"; // Pokémon GO -- duplicate with 40000's entry
|
||||
// metLA_30000[18] += " (-)"; // Pokémon HOME -- duplicate with 40000's entry
|
||||
|
||||
for (int i = 55; i <= 60; i++) // distinguish second set of YYYY Event from the first
|
||||
metLA_40000[i] += " (-)";
|
||||
|
||||
if (lang is "es")
|
||||
{
|
||||
// en un lugar misterioso
|
||||
metLA_00000[2] += " (2)"; // in a mystery zone
|
||||
metLA_00000[4] += " (4)"; // in a faraway place
|
||||
}
|
||||
else if (lang is "ja")
|
||||
{
|
||||
// ひょうざんのいくさば
|
||||
metLA_00000[099] += " (099)"; // along the Arena’s Approach
|
||||
metLA_00000[142] += " (142)"; // at Icepeak Arena
|
||||
}
|
||||
else if (lang is "fr" or "it")
|
||||
{
|
||||
// Final four locations are not nouns, rather the same location reference (at the...) as prior entries.
|
||||
metLA_00000[152] += " (152)"; // Galaxy Hall
|
||||
metLA_00000[153] += " (153)"; // Front Gate
|
||||
metLA_00000[154] += " (154)"; // Farm
|
||||
metLA_00000[155] += " (155)"; // Training Grounds
|
||||
}
|
||||
}
|
||||
|
||||
private static void Deduplicate(string[] arr, int group)
|
||||
{
|
||||
var counts = new Dictionary<string, int>();
|
||||
@@ -557,7 +695,11 @@ public string GetLocationName(bool isEggLocation, int location, int format, int
|
||||
5 => GetLocationNames5(bankID),
|
||||
6 => GetLocationNames6(bankID),
|
||||
7 => GameVersion.Gen7b.Contains(version) ? GetLocationNames7GG(bankID) : GetLocationNames7(bankID),
|
||||
8 => GameVersion.BDSP.Contains(version) ? GetLocationNames8b(bankID) : GetLocationNames8(bankID),
|
||||
|
||||
8 when version is GameVersion.PLA => GetLocationNames8a(bankID),
|
||||
8 when GameVersion.BDSP.Contains(version) => GetLocationNames8b(bankID),
|
||||
8 => GetLocationNames8(bankID),
|
||||
|
||||
_ => Array.Empty<string>(),
|
||||
};
|
||||
|
||||
@@ -614,6 +756,15 @@ public string GetLocationName(bool isEggLocation, int location, int format, int
|
||||
_ => Array.Empty<string>(),
|
||||
};
|
||||
|
||||
public IReadOnlyList<string> GetLocationNames8a(int bankID) => bankID switch
|
||||
{
|
||||
0 => metLA_00000,
|
||||
3 => metLA_30000,
|
||||
4 => metLA_40000,
|
||||
6 => metLA_60000,
|
||||
_ => Array.Empty<string>(),
|
||||
};
|
||||
|
||||
public IReadOnlyList<string> GetLocationNames8b(int bankID) => bankID switch
|
||||
{
|
||||
0 => metBDSP_00000,
|
||||
|
||||
@@ -18,6 +18,7 @@ public sealed class MetDataSource
|
||||
private readonly List<ComboItem> MetGen7;
|
||||
private readonly List<ComboItem> MetGen7GG;
|
||||
private readonly List<ComboItem> MetGen8;
|
||||
private readonly List<ComboItem> MetGen8a;
|
||||
private readonly List<ComboItem> MetGen8b;
|
||||
|
||||
private IReadOnlyList<ComboItem>? MetGen4Transfer;
|
||||
@@ -34,6 +35,7 @@ public MetDataSource(GameStrings s)
|
||||
MetGen7 = CreateGen7(s);
|
||||
MetGen7GG = CreateGen7GG(s);
|
||||
MetGen8 = CreateGen8(s);
|
||||
MetGen8a = CreateGen8a(s);
|
||||
MetGen8b = CreateGen8b(s);
|
||||
}
|
||||
|
||||
@@ -152,6 +154,17 @@ private static List<ComboItem> CreateGen8(GameStrings s)
|
||||
return locations;
|
||||
}
|
||||
|
||||
private static List<ComboItem> CreateGen8a(GameStrings s)
|
||||
{
|
||||
var locations = Util.GetCBList(s.metLA_00000, 0);
|
||||
Util.AddCBWithOffset(locations, s.metLA_30000, 30000, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(locations, s.metLA_00000, 00000, Legal.Met_LA_0);
|
||||
Util.AddCBWithOffset(locations, s.metLA_30000, 30000, Legal.Met_LA_3);
|
||||
Util.AddCBWithOffset(locations, s.metLA_40000, 40000, Legal.Met_LA_4);
|
||||
Util.AddCBWithOffset(locations, s.metLA_60000, 60000, Legal.Met_LA_6);
|
||||
return locations;
|
||||
}
|
||||
|
||||
private static List<ComboItem> CreateGen8b(GameStrings s)
|
||||
{
|
||||
// Manually add invalid (-1) location from SWSH as ID 65535
|
||||
@@ -201,6 +214,7 @@ public IReadOnlyList<ComboItem> GetLocationList(GameVersion version, int current
|
||||
GP or GE or GO => Partition2(MetGen7GG, z => z <= 54), // Pokémon League
|
||||
SW or SH => Partition2(MetGen8, z => z < 400),
|
||||
BD or SP => Partition2(MetGen8b, z => z < 628),
|
||||
PLA => Partition2(MetGen8a, z => z < 512),
|
||||
_ => GetLocationListModified(version, currentGen),
|
||||
};
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ private static GameVersion[] GetValidGameVersions()
|
||||
// Gen8
|
||||
SW or SH => SWSH,
|
||||
BD or SP => BDSP,
|
||||
PLA => PLA,
|
||||
_ => Invalid,
|
||||
};
|
||||
|
||||
@@ -138,6 +139,7 @@ public static int GetMaxSpeciesID(this GameVersion game)
|
||||
return Legal.MaxSpeciesID_7_USUM;
|
||||
return Legal.MaxSpeciesID_7_USUM;
|
||||
}
|
||||
if (PLA == game) return Legal.MaxSpeciesID_8a;
|
||||
if (BDSP.Contains(game)) return Legal.MaxSpeciesID_8b;
|
||||
if (Gen8.Contains(game)) return Legal.MaxSpeciesID_8;
|
||||
return -1;
|
||||
@@ -200,7 +202,7 @@ public static bool Contains(this GameVersion g1, GameVersion g2)
|
||||
|
||||
SWSH => g2 is SW or SH,
|
||||
BDSP => g2 is BD or SP,
|
||||
Gen8 => SWSH.Contains(g2) || BDSP.Contains(g2),
|
||||
Gen8 => SWSH.Contains(g2) || BDSP.Contains(g2) || PLA == g2,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ public sealed record EncounterArea1 : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea1[] GetAreas(byte[][] input, GameVersion game)
|
||||
public static EncounterArea1[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea1[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea1(input[i], game);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ public sealed record EncounterArea2 : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea2[] GetAreas(byte[][] input, GameVersion game)
|
||||
public static EncounterArea2[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea2[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea2(input[i], game);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -15,18 +15,18 @@ public sealed record EncounterArea3 : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea3[] GetAreas(byte[][] input, GameVersion game)
|
||||
public static EncounterArea3[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea3[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea3(input[i], game);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static EncounterArea3[] GetAreasSwarm(byte[][] input, GameVersion game)
|
||||
public static EncounterArea3[] GetAreasSwarm(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea3[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea3(input[i], game, SlotType.Swarm | SlotType.Grass);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ public sealed record EncounterArea4 : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea4[] GetAreas(byte[][] input, GameVersion game)
|
||||
public static EncounterArea4[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea4[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea4(input[i], game);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ public sealed record EncounterArea5 : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea5[] GetAreas(byte[][] input, GameVersion game)
|
||||
public static EncounterArea5[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea5[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea5(input[i], game);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ public sealed record EncounterArea6AO : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea6AO[] GetAreas(byte[][] input, GameVersion game)
|
||||
public static EncounterArea6AO[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea6AO[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea6AO(input[i], game);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -14,10 +14,11 @@ public sealed record EncounterArea6XY : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea6XY[] GetAreas(byte[][] input, GameVersion game, EncounterArea6XY safari)
|
||||
public static EncounterArea6XY[] GetAreas(BinLinkerAccessor input, GameVersion game, EncounterArea6XY safari)
|
||||
{
|
||||
var result = new EncounterArea6XY[input.Length + 1];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
int count = input.Length;
|
||||
var result = new EncounterArea6XY[count + 1];
|
||||
for (int i = 0; i < count; i++)
|
||||
result[i] = new EncounterArea6XY(input[i], game);
|
||||
result[^1] = safari;
|
||||
return result;
|
||||
|
||||
@@ -14,10 +14,10 @@ public sealed record EncounterArea7 : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea7[] GetAreas(byte[][] input, GameVersion game)
|
||||
public static EncounterArea7[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea7[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea7(input[i], game);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@ public sealed record EncounterArea7b : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea7b[] GetAreas(byte[][] input, GameVersion game)
|
||||
public static EncounterArea7b[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea7b[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea7b(input[i], game);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ private EncounterArea7g(int species, int form, EncounterSlot7GO[] slots) : base(
|
||||
Slots = slots;
|
||||
}
|
||||
|
||||
internal static EncounterArea7g[] GetArea(byte[][] data)
|
||||
internal static EncounterArea7g[] GetArea(BinLinkerAccessor data)
|
||||
{
|
||||
var areas = new EncounterArea7g[data.Length];
|
||||
for (int i = 0; i < areas.Length; i++)
|
||||
|
||||
@@ -355,15 +355,15 @@ private static bool CanCrossoverTo(int fromLocation, int toLocation, AreaSlotTyp
|
||||
_ => false,
|
||||
};
|
||||
|
||||
public static EncounterArea8[] GetAreas(byte[][] input, GameVersion game, bool symbol = false)
|
||||
public static EncounterArea8[] GetAreas(BinLinkerAccessor input, GameVersion game, bool symbol = false)
|
||||
{
|
||||
var result = new EncounterArea8[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea8(input[i], symbol, game);
|
||||
return result;
|
||||
}
|
||||
|
||||
private EncounterArea8(byte[] areaData, bool symbol, GameVersion game) : base(game)
|
||||
private EncounterArea8(ReadOnlySpan<byte> areaData, bool symbol, GameVersion game) : base(game)
|
||||
{
|
||||
PermitCrossover = symbol;
|
||||
Location = areaData[0];
|
||||
|
||||
93
PKHeX.Core/Legality/Areas/EncounterArea8a.cs
Normal file
93
PKHeX.Core/Legality/Areas/EncounterArea8a.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <inheritdoc cref="EncounterArea" />
|
||||
/// <summary>
|
||||
/// <see cref="GameVersion.SWSH"/> encounter area
|
||||
/// </summary>
|
||||
public sealed record EncounterArea8a : EncounterArea
|
||||
{
|
||||
public readonly EncounterSlot8a[] Slots;
|
||||
public readonly int ParentLocation;
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public override bool IsMatchLocation(int location)
|
||||
{
|
||||
if (base.IsMatchLocation(location))
|
||||
return true;
|
||||
return CanCrossoverTo(location);
|
||||
}
|
||||
|
||||
private bool CanCrossoverTo(int location)
|
||||
{
|
||||
return location == ParentLocation;
|
||||
}
|
||||
|
||||
public override IEnumerable<EncounterSlot> GetMatchingSlots(PKM pkm, IReadOnlyList<EvoCriteria> chain) => GetMatches(chain, pkm.Met_Level);
|
||||
|
||||
private IEnumerable<EncounterSlot8a> GetMatches(IReadOnlyList<EvoCriteria> chain, int metLevel)
|
||||
{
|
||||
foreach (var slot in Slots)
|
||||
{
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
if (slot.Species != evo.Species)
|
||||
continue;
|
||||
|
||||
if (!slot.IsLevelWithinRange(metLevel))
|
||||
break;
|
||||
|
||||
if (slot.Form != evo.Form && slot.Species is not ((int)Species.Rotom or (int)Species.Burmy or (int)Species.Wormadam))
|
||||
break;
|
||||
|
||||
yield return slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static EncounterArea8a[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea8a[input.Length];
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea8a(input[i], game);
|
||||
return result;
|
||||
}
|
||||
|
||||
private EncounterArea8a(ReadOnlySpan<byte> areaData, GameVersion game) : base(game)
|
||||
{
|
||||
// Area Metadata
|
||||
Location = areaData[0];
|
||||
ParentLocation = areaData[1];
|
||||
Type = areaData[2] + SlotType.Overworld;
|
||||
var count = areaData[3];
|
||||
|
||||
var slots = areaData[4..];
|
||||
Slots = ReadSlots(slots, count);
|
||||
}
|
||||
|
||||
private EncounterSlot8a[] ReadSlots(ReadOnlySpan<byte> areaData, byte slotCount)
|
||||
{
|
||||
var slots = new EncounterSlot8a[slotCount];
|
||||
const int bpe = 8;
|
||||
for (int i = 0; i < slotCount; i++)
|
||||
{
|
||||
var ofs = i * bpe;
|
||||
var entry = areaData.Slice(ofs, bpe);
|
||||
byte flawless = entry[7];
|
||||
var gender = (Gender)entry[6];
|
||||
int max = entry[5];
|
||||
int min = entry[4];
|
||||
var alpha = entry[3];
|
||||
var form = entry[2];
|
||||
var species = ReadUInt16LittleEndian(entry);
|
||||
|
||||
slots[i] = new EncounterSlot8a(this, species, form, min, max, alpha, flawless, gender);
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,10 @@ public sealed record EncounterArea8b : EncounterArea
|
||||
|
||||
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
|
||||
|
||||
public static EncounterArea8b[] GetAreas(byte[][] input, GameVersion game)
|
||||
public static EncounterArea8b[] GetAreas(BinLinkerAccessor input, GameVersion game)
|
||||
{
|
||||
var result = new EncounterArea8b[input.Length];
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
result[i] = new EncounterArea8b(input[i], game);
|
||||
return result;
|
||||
}
|
||||
@@ -123,27 +123,27 @@ private static bool IsInaccessibleHoneySlotLocation(EncounterSlot8b slot, PKM pk
|
||||
|
||||
private static readonly ushort[] LocationID_HoneyTree =
|
||||
{
|
||||
359, // 00 Route 205 Floaroma
|
||||
361, // 01 Route 205 Eterna
|
||||
362, // 02 Route 206
|
||||
364, // 03 Route 207
|
||||
365, // 04 Route 208
|
||||
367, // 05 Route 209
|
||||
373, // 06 Route 210 Solaceon
|
||||
375, // 07 Route 210 Celestic
|
||||
378, // 08 Route 211
|
||||
379, // 09 Route 212 Hearthome
|
||||
383, // 10 Route 212 Pastoria
|
||||
385, // 11 Route 213
|
||||
392, // 12 Route 214
|
||||
394, // 13 Route 215
|
||||
400, // 14 Route 218
|
||||
404, // 15 Route 221
|
||||
407, // 16 Route 222
|
||||
197, // 17 Valley Windworks
|
||||
199, // 18 Eterna Forest
|
||||
201, // 19 Fuego Ironworks
|
||||
253, // 20 Floaroma Meadow
|
||||
359, // 00 Route 205 Floaroma
|
||||
361, // 01 Route 205 Eterna
|
||||
362, // 02 Route 206
|
||||
364, // 03 Route 207
|
||||
365, // 04 Route 208
|
||||
367, // 05 Route 209
|
||||
373, // 06 Route 210 Solaceon
|
||||
375, // 07 Route 210 Celestic
|
||||
378, // 08 Route 211
|
||||
379, // 09 Route 212 Hearthome
|
||||
383, // 10 Route 212 Pastoria
|
||||
385, // 11 Route 213
|
||||
392, // 12 Route 214
|
||||
394, // 13 Route 215
|
||||
400, // 14 Route 218
|
||||
404, // 15 Route 221
|
||||
407, // 16 Route 222
|
||||
197, // 17 Valley Windworks
|
||||
199, // 18 Eterna Forest
|
||||
201, // 19 Fuego Ironworks
|
||||
253, // 20 Floaroma Meadow
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ private EncounterArea8g(int species, int form, EncounterSlot8GO[] slots) : base(
|
||||
Slots = slots;
|
||||
}
|
||||
|
||||
internal static EncounterArea8g[] GetArea(byte[][] data)
|
||||
internal static EncounterArea8g[] GetArea(BinLinkerAccessor data)
|
||||
{
|
||||
var areas = new EncounterArea8g[data.Length];
|
||||
for (int i = 0; i < areas.Length; i++)
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public static class BinLinker
|
||||
{
|
||||
/// <summary>
|
||||
/// Unpacks a BinLinkerAccessor generated file container into individual arrays.
|
||||
/// </summary>
|
||||
/// <param name="fileData">Packed data</param>
|
||||
/// <param name="identifier">Signature expected in the first two bytes (ASCII)</param>
|
||||
/// <returns>Unpacked array containing all files that were packed.</returns>
|
||||
public static byte[][] Unpack(ReadOnlySpan<byte> fileData, string identifier)
|
||||
{
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Assert(fileData.Length > 4);
|
||||
System.Diagnostics.Debug.Assert(identifier[0] == fileData[0] && identifier[1] == fileData[1]);
|
||||
#endif
|
||||
MemoryMarshal.TryRead(fileData[4..], out int start);
|
||||
MemoryMarshal.TryRead(fileData[2..], out ushort count);
|
||||
var offsetBytes = fileData[8..(8 + (count * sizeof(int)))];
|
||||
var offsets = MemoryMarshal.Cast<byte, int>(offsetBytes);
|
||||
|
||||
byte[][] returnData = new byte[count][];
|
||||
for (int i = 0; i < offsets.Length; i++)
|
||||
{
|
||||
int end = offsets[i];
|
||||
returnData[i] = fileData[start..end].ToArray();
|
||||
start = end;
|
||||
}
|
||||
return returnData;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
PKHeX.Core/Legality/BinLinkerAccessor.cs
Normal file
50
PKHeX.Core/Legality/BinLinkerAccessor.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks a BinLinkerAccessor generated file container into individual arrays.
|
||||
/// </summary>
|
||||
public readonly ref struct BinLinkerAccessor
|
||||
{
|
||||
/// <summary> Backing data object </summary>
|
||||
private readonly ReadOnlySpan<byte> Data;
|
||||
|
||||
/// <summary> Total count of files available for accessing. </summary>
|
||||
public int Length => ReadUInt16LittleEndian(Data[2..]);
|
||||
|
||||
/// <summary> Magic identifier for the file. </summary>
|
||||
public string Identifier => new(new[] {(char)Data[0], (char)Data[1]});
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a view of the entry at the requested <see cref="index"/>.
|
||||
/// </summary>
|
||||
/// <param name="index">Entry to retrieve.</param>
|
||||
public ReadOnlySpan<byte> this[int index] => GetEntry(index);
|
||||
|
||||
private BinLinkerAccessor(ReadOnlySpan<byte> data) => Data = data;
|
||||
|
||||
private ReadOnlySpan<byte> GetEntry(int index)
|
||||
{
|
||||
int offset = 4 + (index * sizeof(int));
|
||||
int end = ReadInt32LittleEndian(Data[(offset + 4)..]);
|
||||
int start = ReadInt32LittleEndian(Data[offset..]);
|
||||
return Data[start..end];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanity checks the input <see cref="data"/> only in DEBUG builds, and returns a new wrapper.
|
||||
/// </summary>
|
||||
/// <param name="data">Data reference</param>
|
||||
/// <param name="identifier">Expected identifier (debug verification only)</param>
|
||||
public static BinLinkerAccessor Get(ReadOnlySpan<byte> data, string identifier)
|
||||
{
|
||||
var result = new BinLinkerAccessor(data);
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Assert(data.Length > 4);
|
||||
System.Diagnostics.Debug.Assert(identifier[0] == data[0] && identifier[1] == data[1]);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,9 @@ public static bool CanHatchAsEgg(int species, int form, int generation)
|
||||
if (FormInfo.IsTotemForm(species, form, generation))
|
||||
return false;
|
||||
|
||||
if (FormInfo.IsLordForm(species, form, generation))
|
||||
return false;
|
||||
|
||||
return IsBreedableForm(species, form);
|
||||
}
|
||||
|
||||
@@ -199,6 +202,7 @@ public static bool CanHatchAsEgg(int species, int form, GameVersion game)
|
||||
(int)Kubfu, (int)Urshifu, (int)Zarude,
|
||||
(int)Regieleki, (int)Regidrago,
|
||||
(int)Glastrier, (int)Spectrier, (int)Calyrex,
|
||||
(int)Enamorus,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.BinLinkerAccessor;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
@@ -16,50 +17,50 @@ public static partial class Legal
|
||||
internal static readonly Learnset[] LevelUpC = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_c.pkl"), MaxSpeciesID_2);
|
||||
|
||||
// Gen 3
|
||||
internal static readonly Learnset[] LevelUpE = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_e.pkl"), "em"));
|
||||
internal static readonly Learnset[] LevelUpRS = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_rs.pkl"), "rs"));
|
||||
internal static readonly Learnset[] LevelUpFR = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_fr.pkl"), "fr"));
|
||||
internal static readonly Learnset[] LevelUpLG = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_lg.pkl"), "lg"));
|
||||
internal static readonly EggMoves6[] EggMovesRS = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_rs.pkl"), "rs"));
|
||||
internal static readonly Learnset[] LevelUpE = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_e.pkl"), "em"));
|
||||
internal static readonly Learnset[] LevelUpRS = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_rs.pkl"), "rs"));
|
||||
internal static readonly Learnset[] LevelUpFR = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_fr.pkl"), "fr"));
|
||||
internal static readonly Learnset[] LevelUpLG = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_lg.pkl"), "lg"));
|
||||
internal static readonly EggMoves6[] EggMovesRS = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_rs.pkl"), "rs"));
|
||||
|
||||
// Gen 4
|
||||
internal static readonly Learnset[] LevelUpDP = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_dp.pkl"), "dp"));
|
||||
internal static readonly Learnset[] LevelUpPt = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_pt.pkl"), "pt"));
|
||||
internal static readonly Learnset[] LevelUpHGSS = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_hgss.pkl"), "hs"));
|
||||
internal static readonly EggMoves6[] EggMovesDPPt = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_dppt.pkl"), "dp"));
|
||||
internal static readonly EggMoves6[] EggMovesHGSS = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_hgss.pkl"), "hs"));
|
||||
internal static readonly Learnset[] LevelUpDP = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_dp.pkl"), "dp"));
|
||||
internal static readonly Learnset[] LevelUpPt = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_pt.pkl"), "pt"));
|
||||
internal static readonly Learnset[] LevelUpHGSS = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_hgss.pkl"), "hs"));
|
||||
internal static readonly EggMoves6[] EggMovesDPPt = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_dppt.pkl"), "dp"));
|
||||
internal static readonly EggMoves6[] EggMovesHGSS = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_hgss.pkl"), "hs"));
|
||||
|
||||
// Gen 5
|
||||
internal static readonly Learnset[] LevelUpBW = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_bw.pkl"), "51"));
|
||||
internal static readonly Learnset[] LevelUpB2W2 = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_b2w2.pkl"), "52"));
|
||||
internal static readonly EggMoves6[] EggMovesBW = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_bw.pkl"), "bw"));
|
||||
internal static readonly Learnset[] LevelUpBW = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_bw.pkl"), "51"));
|
||||
internal static readonly Learnset[] LevelUpB2W2 = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_b2w2.pkl"), "52"));
|
||||
internal static readonly EggMoves6[] EggMovesBW = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_bw.pkl"), "bw"));
|
||||
|
||||
// Gen 6
|
||||
internal static readonly EggMoves6[] EggMovesXY = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_xy.pkl"), "xy"));
|
||||
internal static readonly Learnset[] LevelUpXY = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_xy.pkl"), "xy"));
|
||||
internal static readonly EggMoves6[] EggMovesAO = EggMoves6.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_ao.pkl"), "ao"));
|
||||
internal static readonly Learnset[] LevelUpAO = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_ao.pkl"), "ao"));
|
||||
internal static readonly EggMoves6[] EggMovesXY = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_xy.pkl"), "xy"));
|
||||
internal static readonly Learnset[] LevelUpXY = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_xy.pkl"), "xy"));
|
||||
internal static readonly EggMoves6[] EggMovesAO = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_ao.pkl"), "ao"));
|
||||
internal static readonly Learnset[] LevelUpAO = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_ao.pkl"), "ao"));
|
||||
|
||||
// Gen 7
|
||||
internal static readonly EggMoves7[] EggMovesSM = EggMoves7.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_sm.pkl"), "sm"));
|
||||
internal static readonly Learnset[] LevelUpSM = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm"));
|
||||
internal static readonly EggMoves7[] EggMovesUSUM = EggMoves7.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_uu.pkl"), "uu"));
|
||||
internal static readonly Learnset[] LevelUpUSUM = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_uu.pkl"), "uu"));
|
||||
internal static readonly Learnset[] LevelUpGG = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_gg.pkl"), "gg"));
|
||||
internal static readonly EggMoves7[] EggMovesSM = EggMoves7.GetArray(Get(Util.GetBinaryResource("eggmove_sm.pkl"), "sm"));
|
||||
internal static readonly Learnset[] LevelUpSM = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm"));
|
||||
internal static readonly EggMoves7[] EggMovesUSUM = EggMoves7.GetArray(Get(Util.GetBinaryResource("eggmove_uu.pkl"), "uu"));
|
||||
internal static readonly Learnset[] LevelUpUSUM = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_uu.pkl"), "uu"));
|
||||
internal static readonly Learnset[] LevelUpGG = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_gg.pkl"), "gg"));
|
||||
|
||||
// Gen 8
|
||||
internal static readonly EggMoves7[] EggMovesSWSH = EggMoves7.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_swsh.pkl"), "ss"));
|
||||
internal static readonly Learnset[] LevelUpSWSH = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_swsh.pkl"), "ss"));
|
||||
internal static readonly EggMoves7[] EggMovesBDSP = EggMoves7.GetArray(BinLinker.Unpack(Util.GetBinaryResource("eggmove_bdsp.pkl"), "bs"));
|
||||
internal static readonly Learnset[] LevelUpBDSP = LearnsetReader.GetArray(BinLinker.Unpack(Util.GetBinaryResource("lvlmove_bdsp.pkl"), "bs"));
|
||||
internal static readonly EggMoves7[] EggMovesSWSH = EggMoves7.GetArray(Get(Util.GetBinaryResource("eggmove_swsh.pkl"), "ss"));
|
||||
internal static readonly Learnset[] LevelUpSWSH = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_swsh.pkl"), "ss"));
|
||||
internal static readonly EggMoves7[] EggMovesBDSP = EggMoves7.GetArray(Get(Util.GetBinaryResource("eggmove_bdsp.pkl"), "bs"));
|
||||
internal static readonly Learnset[] LevelUpBDSP = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_bdsp.pkl"), "bs"));
|
||||
internal static readonly Learnset[] LevelUpLA = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_la.pkl"), "la"));
|
||||
|
||||
public static IReadOnlyList<byte> GetPPTable(PKM pkm, int format)
|
||||
public static IReadOnlyList<byte> GetPPTable(PKM pkm, int format) => format switch
|
||||
{
|
||||
if (format != 7)
|
||||
return GetPPTable(format);
|
||||
var lgpe = pkm.Version is (int) GameVersion.GO or (int) GameVersion.GP or (int) GameVersion.GE;
|
||||
return lgpe ? MovePP_GG : MovePP_SM;
|
||||
}
|
||||
7 when pkm is PB7 => MovePP_GG,
|
||||
8 when pkm is PA8 => MovePP_LA,
|
||||
_ => GetPPTable(format),
|
||||
};
|
||||
|
||||
public static IReadOnlyList<byte> GetPPTable(int format) => format switch
|
||||
{
|
||||
@@ -78,6 +79,7 @@ public static IReadOnlyList<byte> GetPPTable(PKM pkm, int format)
|
||||
{
|
||||
PK8 => DummiedMoves_SWSH,
|
||||
PB8 => DummiedMoves_BDSP,
|
||||
PA8 => DummiedMoves_LA,
|
||||
_ => Array.Empty<int>(),
|
||||
};
|
||||
|
||||
@@ -99,7 +101,7 @@ internal static int GetMaxSpeciesOrigin(PKM pkm)
|
||||
5 => MaxSpeciesID_5,
|
||||
6 => MaxSpeciesID_6,
|
||||
7 => MaxSpeciesID_7b,
|
||||
8 => MaxSpeciesID_8,
|
||||
8 => MaxSpeciesID_8a,
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
@@ -112,7 +114,7 @@ internal static int GetMaxSpeciesOrigin(PKM pkm)
|
||||
<= MaxSpeciesID_5 => 5,
|
||||
<= MaxSpeciesID_6 => 6,
|
||||
<= MaxSpeciesID_7b => 7,
|
||||
<= MaxSpeciesID_8 => 8,
|
||||
<= MaxSpeciesID_8a => 8,
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
@@ -138,7 +140,7 @@ internal static int GetMaxSpeciesOrigin(PKM pkm)
|
||||
5 => MaxMoveID_5,
|
||||
6 => MaxMoveID_6_AO,
|
||||
7 => MaxMoveID_7b,
|
||||
8 => MaxMoveID_8,
|
||||
8 => MaxMoveID_8a,
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
@@ -161,6 +163,18 @@ internal static bool HasVisitedBDSP(this PKM pkm, int species)
|
||||
return pi.IsPresentInGame;
|
||||
}
|
||||
|
||||
internal static bool HasVisitedLA(this PKM pkm, int species)
|
||||
{
|
||||
if (!pkm.InhabitedGeneration(8, species))
|
||||
return false;
|
||||
if (pkm.LA)
|
||||
return true;
|
||||
if (pkm.IsUntraded)
|
||||
return false;
|
||||
var pi = (PersonalInfoLA)PersonalTable.LA[species];
|
||||
return pi.IsPresentInGame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the moveset is restricted to only the original version.
|
||||
/// </summary>
|
||||
@@ -172,6 +186,8 @@ internal static bool IsMovesetRestricted(this PKM pkm)
|
||||
return true;
|
||||
if (pkm.BDSP)
|
||||
return true;
|
||||
if (pkm.LA)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ public static class EncounterEvent
|
||||
/// <summary>Event Database for Generation 8</summary>
|
||||
public static IReadOnlyList<WC8> MGDB_G8 { get; private set; } = Array.Empty<WC8>();
|
||||
|
||||
/// <summary>Event Database for Generation 8 <see cref="GameVersion.BDSP"/></summary>
|
||||
public static IReadOnlyList<WA8> MGDB_G8A { get; private set; } = Array.Empty<WA8>();
|
||||
|
||||
/// <summary>Event Database for Generation 8 <see cref="GameVersion.BDSP"/></summary>
|
||||
public static IReadOnlyList<WB8> MGDB_G8B { get; private set; } = Array.Empty<WB8>();
|
||||
|
||||
@@ -45,6 +48,7 @@ public static class EncounterEvent
|
||||
private static WB7[] GetWB7DB(ReadOnlySpan<byte> bin) => Get(bin, WB7.SizeFull, d => new WB7(d));
|
||||
private static WC8[] GetWC8DB(ReadOnlySpan<byte> bin) => Get(bin, WC8.Size, d => new WC8(d));
|
||||
private static WB8[] GetWB8DB(ReadOnlySpan<byte> bin) => Get(bin, WB8.Size, d => new WB8(d));
|
||||
private static WA8[] GetWA8DB(ReadOnlySpan<byte> bin) => Get(bin, WA8.Size, d => new WA8(d));
|
||||
|
||||
private static T[] Get<T>(ReadOnlySpan<byte> bin, int size, Func<byte[], T> ctor)
|
||||
{
|
||||
@@ -68,6 +72,7 @@ public static void RefreshMGDB(params string[] paths)
|
||||
ICollection<WB7> b7 = GetWB7DB(Util.GetBinaryResource("wb7full.pkl"));
|
||||
ICollection<WC8> g8 = GetWC8DB(Util.GetBinaryResource("wc8.pkl"));
|
||||
ICollection<WB8> b8 = GetWB8DB(Util.GetBinaryResource("wb8.pkl"));
|
||||
ICollection<WA8> a8 = GetWA8DB(Util.GetBinaryResource("wa8.pkl"));
|
||||
|
||||
foreach (var gift in paths.Where(Directory.Exists).SelectMany(MysteryUtil.GetGiftsFromFolder))
|
||||
{
|
||||
@@ -87,6 +92,7 @@ static void AddOrExpand<T>(ref ICollection<T> arr, T obj)
|
||||
case WB7 wb7: AddOrExpand(ref b7, wb7); continue;
|
||||
case WC8 wc8: AddOrExpand(ref g8, wc8); continue;
|
||||
case WB8 wb8: AddOrExpand(ref b8, wb8); continue;
|
||||
case WA8 wa8: AddOrExpand(ref a8, wa8); continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +114,7 @@ static T[] SetArray<T>(ICollection<T> arr)
|
||||
MGDB_G7 = SetArray(g7);
|
||||
MGDB_G7GG = SetArray(b7);
|
||||
MGDB_G8 = SetArray(g8);
|
||||
MGDB_G8A = SetArray(a8);
|
||||
MGDB_G8B = SetArray(b8);
|
||||
}
|
||||
|
||||
@@ -121,6 +128,7 @@ public static IEnumerable<MysteryGift> GetAllEvents(bool sorted = true)
|
||||
MGDB_G7,
|
||||
MGDB_G7GG,
|
||||
MGDB_G8,
|
||||
MGDB_G8A,
|
||||
MGDB_G8B,
|
||||
}.SelectMany(z => z);
|
||||
regular = regular.Where(mg => !mg.IsItem && mg.IsPokémon && mg.Species > 0);
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace PKHeX.Core
|
||||
/// </summary>
|
||||
internal static class EncounterUtil
|
||||
{
|
||||
internal static BinLinkerAccessor Get(string resource, string ident) => BinLinkerAccessor.Get(Util.GetBinaryResource($"encounter_{resource}.pkl"), ident);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the relevant <see cref="EncounterStatic"/> objects that appear in the relevant game.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using static PKHeX.Core.GameVersion;
|
||||
using static PKHeX.Core.EncounterGBLanguage;
|
||||
using static PKHeX.Core.EncounterUtil;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
@@ -8,17 +9,14 @@ namespace PKHeX.Core
|
||||
/// </summary>
|
||||
internal static class Encounters1
|
||||
{
|
||||
internal static readonly EncounterArea1[] SlotsRD = Get("red", "g1", RD);
|
||||
internal static readonly EncounterArea1[] SlotsGN = Get("blue", "g1", GN);
|
||||
internal static readonly EncounterArea1[] SlotsYW = Get("yellow", "g1", YW);
|
||||
internal static readonly EncounterArea1[] SlotsBU = Get("blue_jp", "g1", BU);
|
||||
internal static readonly EncounterArea1[] SlotsRD = EncounterArea1.GetAreas(Get("red", "g1"), RD);
|
||||
internal static readonly EncounterArea1[] SlotsGN = EncounterArea1.GetAreas(Get("blue", "g1"), GN);
|
||||
internal static readonly EncounterArea1[] SlotsYW = EncounterArea1.GetAreas(Get("yellow", "g1"), YW);
|
||||
internal static readonly EncounterArea1[] SlotsBU = EncounterArea1.GetAreas(Get("blue_jp", "g1"), BU);
|
||||
internal static readonly EncounterArea1[] SlotsRBY = ArrayUtil.ConcatAll(SlotsRD, SlotsGN, SlotsYW);
|
||||
internal static readonly EncounterArea1[] SlotsRGBY = ArrayUtil.ConcatAll(SlotsRBY, SlotsBU);
|
||||
|
||||
private static EncounterArea1[] Get(string name, string ident, GameVersion game) =>
|
||||
EncounterArea1.GetAreas(BinLinker.Unpack(Util.GetBinaryResource($"encounter_{name}.pkl"), ident), game);
|
||||
|
||||
static Encounters1() => EncounterUtil.MarkEncounterTradeNicknames(TradeGift_RBY, TradeGift_RBY_OTs);
|
||||
static Encounters1() => MarkEncounterTradeNicknames(TradeGift_RBY, TradeGift_RBY_OTs);
|
||||
|
||||
internal static readonly EncounterStatic1[] StaticRBY =
|
||||
{
|
||||
|
||||
@@ -10,14 +10,12 @@ namespace PKHeX.Core
|
||||
/// </summary>
|
||||
internal static class Encounters2
|
||||
{
|
||||
internal static readonly EncounterArea2[] SlotsGD = Get("gold", "g2", GD);
|
||||
internal static readonly EncounterArea2[] SlotsSV = Get("silver", "g2", SV);
|
||||
internal static readonly EncounterArea2[] SlotsC = Get("crystal", "g2", C);
|
||||
internal static readonly EncounterArea2[] SlotsGD = EncounterArea2.GetAreas(Get("gold", "g2"), GD);
|
||||
internal static readonly EncounterArea2[] SlotsSV = EncounterArea2.GetAreas(Get("silver", "g2"), SV);
|
||||
internal static readonly EncounterArea2[] SlotsC = EncounterArea2.GetAreas(Get("crystal", "g2"), C);
|
||||
|
||||
internal static readonly EncounterArea2[] SlotsGS = ArrayUtil.ConcatAll(SlotsGD, SlotsSV);
|
||||
internal static readonly EncounterArea2[] SlotsGSC = ArrayUtil.ConcatAll(SlotsGS, SlotsC);
|
||||
private static EncounterArea2[] Get(string name, string ident, GameVersion game) =>
|
||||
EncounterArea2.GetAreas(BinLinker.Unpack(Util.GetBinaryResource($"encounter_{name}.pkl"), ident), game);
|
||||
|
||||
static Encounters2() => MarkEncounterTradeStrings(TradeGift_GSC, TradeGift_GSC_OTs);
|
||||
|
||||
|
||||
@@ -10,15 +10,14 @@ namespace PKHeX.Core
|
||||
internal static class Encounters3
|
||||
{
|
||||
private static readonly EncounterArea3[] SlotsSwarmRSE = GetSwarm("rse_swarm", "rs", RSE);
|
||||
internal static readonly EncounterArea3[] SlotsR = ArrayUtil.ConcatAll(Get("r", "ru", R), SlotsSwarmRSE);
|
||||
internal static readonly EncounterArea3[] SlotsS = ArrayUtil.ConcatAll(Get("s", "sa", S), SlotsSwarmRSE);
|
||||
internal static readonly EncounterArea3[] SlotsE = ArrayUtil.ConcatAll(Get("e", "em", E), SlotsSwarmRSE);
|
||||
internal static readonly EncounterArea3[] SlotsFR = Get("fr", "fr", FR);
|
||||
internal static readonly EncounterArea3[] SlotsLG = Get("lg", "lg", LG);
|
||||
internal static readonly EncounterArea3[] SlotsR = ArrayUtil.ConcatAll(GetRegular("r", "ru", R), SlotsSwarmRSE);
|
||||
internal static readonly EncounterArea3[] SlotsS = ArrayUtil.ConcatAll(GetRegular("s", "sa", S), SlotsSwarmRSE);
|
||||
internal static readonly EncounterArea3[] SlotsE = ArrayUtil.ConcatAll(GetRegular("e", "em", E), SlotsSwarmRSE);
|
||||
internal static readonly EncounterArea3[] SlotsFR = GetRegular("fr", "fr", FR);
|
||||
internal static readonly EncounterArea3[] SlotsLG = GetRegular("lg", "lg", LG);
|
||||
|
||||
private static byte[][] ReadUnpack(string resource, string ident) => BinLinker.Unpack(Util.GetBinaryResource($"encounter_{resource}.pkl"), ident);
|
||||
private static EncounterArea3[] Get(string resource, string ident, GameVersion game) => EncounterArea3.GetAreas(ReadUnpack(resource, ident), game);
|
||||
private static EncounterArea3[] GetSwarm(string resource, string ident, GameVersion game) => EncounterArea3.GetAreasSwarm(ReadUnpack(resource, ident), game);
|
||||
private static EncounterArea3[] GetRegular(string resource, string ident, GameVersion game) => EncounterArea3.GetAreas(Get(resource, ident), game);
|
||||
private static EncounterArea3[] GetSwarm(string resource, string ident, GameVersion game) => EncounterArea3.GetAreasSwarm(Get(resource, ident), game);
|
||||
|
||||
static Encounters3()
|
||||
{
|
||||
|
||||
@@ -15,7 +15,6 @@ internal static class Encounters4
|
||||
internal static readonly EncounterArea4[] SlotsPt = EncounterArea4.GetAreas(Get("pt", "pt"), Pt);
|
||||
internal static readonly EncounterArea4[] SlotsHG = EncounterArea4.GetAreas(Get("hg", "hg"), HG);
|
||||
internal static readonly EncounterArea4[] SlotsSS = EncounterArea4.GetAreas(Get("ss", "ss"), SS);
|
||||
private static byte[][] Get(string resource, string ident) => BinLinker.Unpack(Util.GetBinaryResource($"encounter_{resource}.pkl"), ident);
|
||||
|
||||
static Encounters4()
|
||||
{
|
||||
|
||||
@@ -13,7 +13,6 @@ public static class Encounters5
|
||||
internal static readonly EncounterArea5[] SlotsW = EncounterArea5.GetAreas(Get("w", "51"), W);
|
||||
internal static readonly EncounterArea5[] SlotsB2 = EncounterArea5.GetAreas(Get("b2", "52"), B2);
|
||||
internal static readonly EncounterArea5[] SlotsW2 = EncounterArea5.GetAreas(Get("w2", "52"), W2);
|
||||
private static byte[][] Get(string resource, string ident) => BinLinker.Unpack(Util.GetBinaryResource($"encounter_{resource}.pkl"), ident);
|
||||
|
||||
static Encounters5()
|
||||
{
|
||||
|
||||
@@ -14,7 +14,6 @@ internal static class Encounters6
|
||||
internal static readonly EncounterArea6XY[] SlotsY = EncounterArea6XY.GetAreas(Get("y", "xy"), Y, FriendSafari);
|
||||
internal static readonly EncounterArea6AO[] SlotsA = EncounterArea6AO.GetAreas(Get("as", "ao"), AS);
|
||||
internal static readonly EncounterArea6AO[] SlotsO = EncounterArea6AO.GetAreas(Get("or", "ao"), OR);
|
||||
private static byte[][] Get(string resource, string ident) => BinLinker.Unpack(Util.GetBinaryResource($"encounter_{resource}.pkl"), ident);
|
||||
|
||||
static Encounters6()
|
||||
{
|
||||
|
||||
@@ -13,7 +13,6 @@ internal static class Encounters7
|
||||
internal static readonly EncounterArea7[] SlotsMN = EncounterArea7.GetAreas(Get("mn", "sm"), MN);
|
||||
internal static readonly EncounterArea7[] SlotsUS = EncounterArea7.GetAreas(Get("us", "uu"), US);
|
||||
internal static readonly EncounterArea7[] SlotsUM = EncounterArea7.GetAreas(Get("um", "uu"), UM);
|
||||
private static byte[][] Get(string resource, string ident) => BinLinker.Unpack(Util.GetBinaryResource($"encounter_{resource}.pkl"), ident);
|
||||
|
||||
static Encounters7()
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@ internal static class Encounters7b
|
||||
{
|
||||
internal static readonly EncounterArea7b[] SlotsGP = EncounterArea7b.GetAreas(Get("gp", "gg"), GP);
|
||||
internal static readonly EncounterArea7b[] SlotsGE = EncounterArea7b.GetAreas(Get("ge", "gg"), GE);
|
||||
private static byte[][] Get(string resource, string ident) => BinLinker.Unpack(Util.GetBinaryResource($"encounter_{resource}.pkl"), ident);
|
||||
|
||||
private static readonly EncounterStatic7b[] Encounter_GG =
|
||||
{
|
||||
|
||||
@@ -17,7 +17,6 @@ internal static class Encounters8
|
||||
private static readonly EncounterArea8[] SlotsSH_Symbol = EncounterArea8.GetAreas(Get("sh_symbol", "sh"), SH, true);
|
||||
private static readonly EncounterArea8[] SlotsSW_Hidden = EncounterArea8.GetAreas(Get("sw_hidden", "sw"), SW);
|
||||
private static readonly EncounterArea8[] SlotsSH_Hidden = EncounterArea8.GetAreas(Get("sh_hidden", "sh"), SH);
|
||||
private static byte[][] Get(string resource, string ident) => BinLinker.Unpack(Util.GetBinaryResource($"encounter_{resource}.pkl"), ident);
|
||||
|
||||
internal static readonly EncounterArea8[] SlotsSW = ArrayUtil.ConcatAll(SlotsSW_Symbol, SlotsSW_Hidden);
|
||||
internal static readonly EncounterArea8[] SlotsSH = ArrayUtil.ConcatAll(SlotsSH_Symbol, SlotsSH_Hidden);
|
||||
|
||||
128
PKHeX.Core/Legality/Encounters/Data/Encounters8a.cs
Normal file
128
PKHeX.Core/Legality/Encounters/Data/Encounters8a.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using static PKHeX.Core.EncounterUtil;
|
||||
using static PKHeX.Core.Shiny;
|
||||
using static PKHeX.Core.GameVersion;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Encounters8a
|
||||
{
|
||||
internal static readonly EncounterArea8a[] SlotsLA = EncounterArea8a.GetAreas(Get("la", "la"), PLA);
|
||||
|
||||
private const byte M = 127; // Middle Height/Weight
|
||||
private const byte A = 255; // Max Height/Weight for Alphas
|
||||
private const byte U = 128; // Middle Height - Unown
|
||||
|
||||
internal static readonly EncounterStatic8a[] StaticLA =
|
||||
{
|
||||
// Gifts
|
||||
new(722,000,05,M,M) { Location = 006, Gift = true, Ball = (int)Ball.LAPoke }, // Rowlet
|
||||
new(155,000,05,M,M) { Location = 006, Gift = true, Ball = (int)Ball.LAPoke }, // Cyndaquil
|
||||
new(501,000,05,M,M) { Location = 006, Gift = true, Ball = (int)Ball.LAPoke }, // Oshawott
|
||||
new(037,001,40,M,M) { Location = 088, Gift = true, Ball = (int)Ball.LAPoke }, // Vulpix-1
|
||||
new(483,000,65,M,M) { Location = 109, FlawlessIVCount = 3, Gift = true, Ball = (int)Ball.LAOrigin }, // Dialga
|
||||
new(484,000,65,M,M) { Location = 109, FlawlessIVCount = 3, Gift = true, Ball = (int)Ball.LAOrigin }, // Palkia
|
||||
new(493,000,75,M,M) { Location = 109, FlawlessIVCount = 3, Gift = true, Ball = (int)Ball.LAPoke, Fateful = true }, // Arceus
|
||||
|
||||
// Static Encounters - Scripted Table Slots
|
||||
new(480,000,70,M,M) { Location = 111, FlawlessIVCount = 3 }, // Uxie
|
||||
new(481,000,70,M,M) { Location = 104, FlawlessIVCount = 3 }, // Mesprit
|
||||
new(482,000,70,M,M) { Location = 105, FlawlessIVCount = 3 }, // Azelf
|
||||
new(485,000,70,M,M) { Location = 068, FlawlessIVCount = 3 }, // Heatran
|
||||
new(488,000,70,M,M) { Location = 082, FlawlessIVCount = 3 }, // Cresselia
|
||||
|
||||
new(641,000,70,M,M) { Location = 090, FlawlessIVCount = 3 }, // Tornadus
|
||||
new(642,000,70,M,M) { Location = 009, FlawlessIVCount = 3 }, // Thundurus
|
||||
new(645,000,70,M,M) { Location = 027, FlawlessIVCount = 3 }, // Landorus
|
||||
new(905,000,70,M,M) { Location = 038, FlawlessIVCount = 3 }, // Enamorus
|
||||
|
||||
new(077,000,15 ) { Location = 014, Shiny = Always}, // Ponyta*
|
||||
new(442,000,60,M,M) { Location = 043, FlawlessIVCount = 3 }, // Spiritomb
|
||||
|
||||
new(489,000,33 ) { Location = 064, Fateful = true }, // Phione
|
||||
new(489,000,34 ) { Location = 064, Fateful = true }, // Phione
|
||||
new(489,000,35 ) { Location = 064, Fateful = true }, // Phione
|
||||
new(489,000,36 ) { Location = 064, Fateful = true }, // Phione
|
||||
new(490,000,50,M,M) { Location = 064, FlawlessIVCount = 3, Fateful = true }, // Manaphy
|
||||
new(491,000,70,M,M) { Location = 010, FlawlessIVCount = 3, Fateful = true }, // Darkrai
|
||||
new(492,000,70,M,M) { Location = 026, FlawlessIVCount = 3, Fateful = true }, // Shaymin
|
||||
|
||||
// Unown Notes
|
||||
new(201,000,25,U) { Location = 040 }, // Unown A
|
||||
new(201,001,25,U) { Location = 056 }, // Unown B
|
||||
new(201,002,25,U) { Location = 081 }, // Unown C
|
||||
new(201,003,25,U) { Location = 008 }, // Unown D
|
||||
new(201,004,25,U) { Location = 022 }, // Unown E
|
||||
new(201,005,25,U) { Location = 010 }, // Unown F
|
||||
new(201,006,25,U) { Location = 017 }, // Unown G
|
||||
new(201,007,25,U) { Location = 006 }, // Unown H
|
||||
new(201,008,25,U) { Location = 023 }, // Unown I
|
||||
new(201,009,25,U) { Location = 072 }, // Unown J
|
||||
new(201,010,25,U) { Location = 043 }, // Unown K
|
||||
new(201,011,25,U) { Location = 086 }, // Unown L
|
||||
new(201,012,25,U) { Location = 037 }, // Unown M
|
||||
new(201,013,25,U) { Location = 009 }, // Unown N
|
||||
new(201,014,25,U) { Location = 102 }, // Unown O
|
||||
new(201,015,25,U) { Location = 075 }, // Unown P
|
||||
new(201,016,25,U) { Location = 058 }, // Unown Q
|
||||
new(201,017,25,U) { Location = 059 }, // Unown R
|
||||
new(201,018,25,U) { Location = 025 }, // Unown S
|
||||
new(201,019,25,U) { Location = 092 }, // Unown T
|
||||
new(201,020,25,U) { Location = 011 }, // Unown U
|
||||
new(201,021,25,U) { Location = 038 }, // Unown V
|
||||
new(201,022,25,U) { Location = 006 }, // Unown W
|
||||
new(201,023,25,U) { Location = 021 }, // Unown X
|
||||
new(201,024,25,U) { Location = 097 }, // Unown Y
|
||||
new(201,025,25,U) { Location = 051 }, // Unown Z
|
||||
new(201,026,25,U) { Location = 142 }, // Unown ! at Snowfall Hot Spring
|
||||
new(201,026,25,U) { Location = 099 }, // Unown ! along the Arena’s Approach (crossover)
|
||||
new(201,027,25,U) { Location = 006 }, // Unown ?
|
||||
|
||||
// Static Encounters
|
||||
new(046,000,50,M,M) { Location = 019 }, // paras01: Paras
|
||||
new(390,000,12,M,M) { Location = 007 }, // hikozaru_01: Chimchar
|
||||
new(434,000,20,M,M) { Location = 008 }, // skunpuu01: Stunky
|
||||
new(441,000,34,M,M) { Location = 129 }, // perap01: Chatot
|
||||
new(450,000,34,M,M) { Location = 036, Gender = 0 }, // kabaldon01: Hippowdon
|
||||
new(459,000,50,M,M) { Location = 101, Gender = 1 }, // yukikaburi01: Snover
|
||||
|
||||
new(483,000,65,M,M) { Location = 109, FlawlessIVCount = 3 }, // dialga01: Dialga
|
||||
new(484,000,65,M,M) { Location = 109, FlawlessIVCount = 3 }, // palkia01: Palkia
|
||||
new(486,000,70,M,M) { Location = 095, FlawlessIVCount = 3 }, // regigigas01: Regigigas
|
||||
new(487,001,70,M,M) { Location = 067, FlawlessIVCount = 3 }, // giratina02: Giratina-1
|
||||
|
||||
new(362,000,64,A,A) { Location = 011, IsAlpha = true, Moves = new[] {442,059,556,242}, Mastery = new[] {true,true,true, true } }, // onigohri01: Glalie
|
||||
new(402,000,12,A,A) { Location = 007, IsAlpha = true, Gender = 0, Moves = new[] {206,071,033,332}, Mastery = new[] {true,true,false,false} }, // mev002: Kricketune
|
||||
new(416,000,60,A,A) { Location = 022, IsAlpha = true, Gender = 1, FlawlessIVCount = 3, Moves = new[] {188,403,408,405}, Mastery = new[] {true,true,true ,true } }, // beequen01: Vespiquen
|
||||
new(571,001,58,M,M) { Location = 111, IsAlpha = true, Moves = new[] {555,421,841,417}, Mastery = new[] {true,true,true ,true } }, // zoroark01: Zoroark-1
|
||||
new(706,001,58,M,M) { Location = 104, IsAlpha = true, Moves = new[] {231,406,842,056}, Mastery = new[] {true,true,true ,true } }, // numelgon01: Goodra-1
|
||||
new(904,000,58,M,M) { Location = 105, IsAlpha = true, Moves = new[] {301,398,401,038}, Mastery = new[] {true,true,true ,false} }, // harysen01: Overqwil
|
||||
|
||||
// Uncatchable
|
||||
// new(901,000,26,M,M) { Location = -01, Gender = 0, Nature = Adamant, FlawlessIVCount = 3, GVs = new[]{2,3,0,2,2,0} }, // ringuma01: Ursaluna
|
||||
// new(190,000,30,M,M) { Location = -01, Gender = 0 }, // aipom01: Aipom
|
||||
// new(190,000,30,M,M) { Location = -01, Gender = 1 }, // aipom01: Aipom
|
||||
// new(185,000,26,S,S) { Location = -01, Gender = 0 }, // usokkie01: Sudowoodo
|
||||
// new(460,000,55,M,M) { Location = -01, Gender = 0 }, // yukinooh01: Abomasnow
|
||||
// new(478,000,55,M,M) { Location = -01, Gender = 1 }, // yukimenoko01: Froslass
|
||||
// new(448,000,62,M,M) { Location = -01, Gender = 0, FlawlessIVCount = 3 }, // lucario01: Lucario
|
||||
// new(628,001,54,M,M) { Location = -01, Gender = 0, Nature = Adamant }, // warrgle01: Braviary-1
|
||||
// new(217,000,30,M,M) { Location = -01, Gender = 0, Nature = Modest }, // ringuma02: Ursaring
|
||||
// new(483,001,65,M,M) { Location = -01, FlawlessIVCount = 3 }, // nsi_ex_07: Dialga-1
|
||||
// new(484,001,65,M,M) { Location = -01, FlawlessIVCount = 3 }, // nsi_ex_08: Palkia-1
|
||||
// new(900,001,18,M,M) { Location = -01, Gender = 0, Nature = Adamant }, // ns001: Kleavor-1
|
||||
// new(900,001,18,M,M) { Location = -01, Gender = 0, Nature = Adamant, FlawlessIVCount = 3 }, // nsi_ex_01: Kleavor-1
|
||||
// new(549,002,30,M,M) { Location = -01, Gender = 1, Nature = Adamant, FlawlessIVCount = 3, Moves = new[] {078,077,412,249}, Mastery = new[] {true,true,true,true } }, // dredear01: Lilligant-2
|
||||
// new(059,002,36,M,M) { Location = -01, Gender = 0, Nature = Adamant, FlawlessIVCount = 3 }, // nsi_ex_06: Arcanine-2
|
||||
// new(101,002,46,M,M) { Location = -01, Gender = 0, Nature = Modest, FlawlessIVCount = 3, Moves = new[] {086,412,085,087}, Mastery = new[] {true,true,true,false} }, // nsi_ex_04: Electrode-2
|
||||
// new(713,002,56,M,M) { Location = -01, Gender = 0, Nature = Relaxed, FlawlessIVCount = 3 }, // nsi_ex_03: Avalugg-2
|
||||
// new(493,000,75,M,M) { Location = -01, FlawlessIVCount = 3, Moves = new[] {347,326,449,063}, Mastery = new[] {true,true,true,true } }, // nsi_ex_09: Arceus
|
||||
// new(483,001,85,M,M) { Location = -01, GVs = new[]{10,10,10,10,10,10} }, // nsi_ex_07_r: Dialga-1
|
||||
// new(484,001,85,M,M) { Location = -01, GVs = new[]{10,10,10,10,10,10} }, // nsi_ex_08_r: Palkia-1
|
||||
// new(900,001,70,M,M) { Location = -01, Gender = 0, Nature = Adamant, GVs = new[]{10,10,10,10,10,10}, Moves = new[] {830,403,404,370}, Mastery = new[] {true,true,true,true} }, // nsi_ex_01_r: Kleavor-1
|
||||
// new(549,002,70,M,M) { Location = -01, Gender = 1, Nature = Adamant, GVs = new[]{10,10,10,10,10,10}, Moves = new[] {837,080,409,416}, Mastery = new[] {true,true,true,true} }, // dredear01_r: Lilligant-2
|
||||
// new(059,002,70,M,M) { Location = -01, Gender = 0, Nature = Adamant, GVs = new[]{10,10,10,10,10,10}, Moves = new[] {833,444,242,528}, Mastery = new[] {true,true,true,true} }, // nsi_ex_06_r: Arcanine-2
|
||||
// new(101,002,70,M,M) { Location = -01, Gender = 0, Nature = Modest, GVs = new[]{10,10,10,10,10,10}, Moves = new[] {835,087,063,086}, Mastery = new[] {true,true,true,true} }, // nsi_ex_04_r: Electrode-2
|
||||
// new(713,002,70,M,M) { Location = -01, Gender = 0, Nature = Relaxed, GVs = new[]{10,10,10,10,10,10}, Moves = new[] {836,667,444,442}, Mastery = new[] {true,true,true,true} }, // nsi_ex_03_r: Avalugg-2
|
||||
// new(493,000,100,M,M){ Location = -01, GVs = new[]{10,10,10,10,10,10}, Moves = new[] {347,326,449,063}, Mastery = new[] {true,true,true,true} }, // nsi_ex_09_r: Arceus
|
||||
};
|
||||
}
|
||||
@@ -7,16 +7,14 @@ namespace PKHeX.Core
|
||||
{
|
||||
internal static class Encounters8b
|
||||
{
|
||||
private static readonly EncounterArea8b[] SlotsBD_OW = EncounterArea8b.GetAreas(Get("encounter_bd", "bs"), BD);
|
||||
private static readonly EncounterArea8b[] SlotsSP_OW = EncounterArea8b.GetAreas(Get("encounter_sp", "bs"), SP);
|
||||
private static readonly EncounterArea8b[] SlotsBD_UG = EncounterArea8b.GetAreas(Get("underground_bd", "bs"), BD);
|
||||
private static readonly EncounterArea8b[] SlotsSP_UG = EncounterArea8b.GetAreas(Get("underground_sp", "bs"), SP);
|
||||
private static readonly EncounterArea8b[] SlotsBD_OW = EncounterArea8b.GetAreas(Get("bd", "bs"), BD);
|
||||
private static readonly EncounterArea8b[] SlotsSP_OW = EncounterArea8b.GetAreas(Get("sp", "bs"), SP);
|
||||
private static readonly EncounterArea8b[] SlotsBD_UG = EncounterArea8b.GetAreas(Get("bd_underground", "bs"), BD);
|
||||
private static readonly EncounterArea8b[] SlotsSP_UG = EncounterArea8b.GetAreas(Get("sp_underground", "bs"), SP);
|
||||
|
||||
internal static readonly EncounterArea8b[] SlotsBD = ArrayUtil.ConcatAll(SlotsBD_OW, SlotsBD_UG);
|
||||
internal static readonly EncounterArea8b[] SlotsSP = ArrayUtil.ConcatAll(SlotsSP_OW, SlotsSP_UG);
|
||||
|
||||
private static byte[][] Get(string resource, string ident) => BinLinker.Unpack(Util.GetBinaryResource($"{resource}.pkl"), ident);
|
||||
|
||||
static Encounters8b() => MarkEncounterTradeStrings(TradeGift_BDSP, TradeBDSP);
|
||||
|
||||
private static readonly EncounterStatic8b[] Encounter_BDSP =
|
||||
|
||||
@@ -8,15 +8,8 @@ internal static class EncountersGO
|
||||
{
|
||||
internal const int MAX_LEVEL = 50;
|
||||
|
||||
internal static readonly EncounterArea7g[] SlotsGO_GG = EncounterArea7g.GetArea(Get("go_lgpe", "go"));
|
||||
internal static readonly EncounterArea8g[] SlotsGO = EncounterArea8g.GetArea(Get("go_home", "go"));
|
||||
|
||||
private static byte[][] Get(string resource, string ident)
|
||||
{
|
||||
var name = $"encounter_{resource}.pkl";
|
||||
var data = Util.GetBinaryResource(name);
|
||||
return BinLinker.Unpack(data, ident);
|
||||
}
|
||||
internal static readonly EncounterArea7g[] SlotsGO_GG = EncounterArea7g.GetArea(EncounterUtil.Get("go_lgpe", "go"));
|
||||
internal static readonly EncounterArea8g[] SlotsGO = EncounterArea8g.GetArea(EncounterUtil.Get("go_home", "go"));
|
||||
}
|
||||
#else
|
||||
public static class EncountersGO
|
||||
@@ -32,11 +25,11 @@ public static void Reload()
|
||||
SlotsGO = EncounterArea8g.GetArea(Get("go_home", "go"));
|
||||
}
|
||||
|
||||
private static byte[][] Get(string resource, string ident)
|
||||
private static BinLinkerAccessor Get(string resource, string ident)
|
||||
{
|
||||
var name = $"encounter_{resource}.pkl";
|
||||
var data = System.IO.File.Exists(name) ? System.IO.File.ReadAllBytes(name) : Util.GetBinaryResource(name);
|
||||
return BinLinker.Unpack(data, ident);
|
||||
return BinLinkerAccessor.Get(data, ident);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -91,8 +91,7 @@ protected virtual void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria
|
||||
pk.Version = (int)version;
|
||||
pk.Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation);
|
||||
|
||||
var ball = FixedBall;
|
||||
pk.Ball = (int)(ball == Ball.None ? Ball.Poke : ball);
|
||||
ApplyDetailsBall(pk);
|
||||
pk.Language = lang;
|
||||
pk.Form = GetWildForm(pk, Form, sav);
|
||||
pk.OT_Friendship = pk.PersonalInfo.BaseFriendship;
|
||||
@@ -114,6 +113,12 @@ protected virtual void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ApplyDetailsBall(PKM pk)
|
||||
{
|
||||
var ball = FixedBall;
|
||||
pk.Ball = (int)(ball == Ball.None ? Ball.Poke : ball);
|
||||
}
|
||||
|
||||
protected virtual void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var moves = MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
|
||||
@@ -17,5 +17,15 @@ protected override void SetPINGA(PKM pk, EncounterCriteria criteria)
|
||||
base.SetPINGA(pk, criteria);
|
||||
pk.SetRandomEC();
|
||||
}
|
||||
|
||||
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)
|
||||
{
|
||||
base.ApplyDetails(sav, criteria, pk);
|
||||
if (pk is IScaledSizeValue v)
|
||||
{
|
||||
v.ResetHeight();
|
||||
v.ResetWeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
101
PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8a.cs
Normal file
101
PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8a.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Encounter Slot found in <see cref="GameVersion.SWSH"/>.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="EncounterSlot"/>
|
||||
public sealed record EncounterSlot8a : EncounterSlot, IAlpha
|
||||
{
|
||||
public override int Generation => 8;
|
||||
|
||||
public bool IsAlpha { get => AlphaType is not 0; set => throw new InvalidOperationException("Do not mutate this field."); }
|
||||
public byte FlawlessIVCount { get; }
|
||||
public Gender Gender { get; }
|
||||
public byte AlphaType { get; } // 0=Never, 1=Random, 2=Guaranteed
|
||||
|
||||
public EncounterSlot8a(EncounterArea8a area, int species, int form, int min, int max, byte alphaType, byte flawlessIVs, Gender gender) : base(area, species, form, min, max)
|
||||
{
|
||||
AlphaType = alphaType;
|
||||
FlawlessIVCount = flawlessIVs;
|
||||
Gender = gender;
|
||||
}
|
||||
|
||||
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)
|
||||
{
|
||||
base.ApplyDetails(sav, criteria, pk);
|
||||
pk.SetRandomEC();
|
||||
if (Gender != Gender.Random)
|
||||
pk.Gender = (int)Gender;
|
||||
|
||||
if (IsAlpha)
|
||||
{
|
||||
if (pk is IAlpha a)
|
||||
a.IsAlpha = true;
|
||||
if (pk is IScaledSize s)
|
||||
s.HeightScalar = s.WeightScalar = byte.MaxValue;
|
||||
if (pk is PA8 pa)
|
||||
pa.SetMasteryFlagMove(pa.AlphaMove = pa.GetRandomAlphaMove());
|
||||
}
|
||||
if (pk is IScaledSizeValue v)
|
||||
{
|
||||
v.ResetHeight();
|
||||
v.ResetWeight();
|
||||
}
|
||||
if (pk is PA8 pa8)
|
||||
{
|
||||
pa8.HeightScalarCopy = pa8.HeightScalar;
|
||||
pa8.SetMasteryFlags();
|
||||
}
|
||||
if (FlawlessIVCount > 0)
|
||||
pk.SetRandomIVs(flawless: FlawlessIVCount);
|
||||
}
|
||||
|
||||
protected override void ApplyDetailsBall(PKM pk) => pk.Ball = (int)Ball.LAPoke;
|
||||
|
||||
public override EncounterMatchRating GetMatchRating(PKM pkm)
|
||||
{
|
||||
if (pkm is IAlpha a && a.IsAlpha != IsAlpha)
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
if (Gender is not Gender.Random && pkm.Gender != (int)Gender)
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
if (FlawlessIVCount is not 0 && pkm.FlawlessIVCount != FlawlessIVCount)
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
|
||||
var result = GetAlphaMoveCompatibility(pkm);
|
||||
var orig = base.GetMatchRating(pkm);
|
||||
return result > orig ? result : orig;
|
||||
}
|
||||
|
||||
private EncounterMatchRating GetAlphaMoveCompatibility(PKM pkm)
|
||||
{
|
||||
// Check for Alpha move compatibility.
|
||||
if (pkm is not PA8 pa)
|
||||
return EncounterMatchRating.Match;
|
||||
|
||||
var alphaMove = pa.AlphaMove;
|
||||
if (!pa.IsAlpha)
|
||||
return alphaMove == 0 ? EncounterMatchRating.Match : EncounterMatchRating.DeferredErrors;
|
||||
|
||||
var pi = PersonalTable.LA.GetFormEntry(Species, Form);
|
||||
var tutors = pi.SpecialTutors[0];
|
||||
|
||||
if (alphaMove is 0)
|
||||
{
|
||||
bool hasAnyTutor = Array.IndexOf(tutors, true) >= 0;
|
||||
if (hasAnyTutor)
|
||||
return EncounterMatchRating.Deferred;
|
||||
}
|
||||
else
|
||||
{
|
||||
var idx = pa.MoveShopPermitIndexes;
|
||||
var index = idx.IndexOf(idx);
|
||||
if (index == -1)
|
||||
return EncounterMatchRating.Deferred;
|
||||
if (!tutors[index])
|
||||
return EncounterMatchRating.Deferred;
|
||||
}
|
||||
return EncounterMatchRating.Match;
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ protected virtual void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria
|
||||
pk.Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation);
|
||||
|
||||
pk.CurrentLevel = level;
|
||||
pk.Ball = Ball;
|
||||
ApplyDetailsBall(pk);
|
||||
pk.HeldItem = HeldItem;
|
||||
pk.OT_Friendship = pk.PersonalInfo.BaseFriendship;
|
||||
|
||||
@@ -111,6 +111,8 @@ protected virtual void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria
|
||||
pd.DynamaxLevel = d.DynamaxLevel;
|
||||
}
|
||||
|
||||
protected virtual void ApplyDetailsBall(PKM pk) => pk.Ball = Ball;
|
||||
|
||||
protected virtual int GetMinimalLevel() => LevelMin;
|
||||
|
||||
protected virtual void SetPINGA(PKM pk, EncounterCriteria criteria)
|
||||
|
||||
@@ -11,6 +11,11 @@ public sealed record EncounterStatic7b(GameVersion Version) : EncounterStatic(Ve
|
||||
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)
|
||||
{
|
||||
base.ApplyDetails(sav, criteria, pk);
|
||||
if (pk is IScaledSizeValue v)
|
||||
{
|
||||
v.ResetHeight();
|
||||
v.ResetWeight();
|
||||
}
|
||||
pk.SetRandomEC();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Generation 8 Static Encounter
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="EncounterStatic"/>
|
||||
public sealed record EncounterStatic8a(GameVersion Version) : EncounterStatic(Version), IAlpha
|
||||
{
|
||||
public bool[]? Mastery;
|
||||
public override int Generation => 8;
|
||||
|
||||
public byte HeightScalar { get; }
|
||||
public byte WeightScalar { get; }
|
||||
public bool IsAlpha { get; set; }
|
||||
|
||||
public bool HasFixedHeight => HeightScalar != NoScalar;
|
||||
public bool HasFixedWeight => WeightScalar != NoScalar;
|
||||
private const byte NoScalar = 0;
|
||||
|
||||
public EncounterStatic8a(ushort species, ushort form, byte level, byte h = NoScalar, byte w = NoScalar) : this(GameVersion.PLA)
|
||||
{
|
||||
Species = species;
|
||||
Form = form;
|
||||
Level = level;
|
||||
HeightScalar = h;
|
||||
WeightScalar = w;
|
||||
Shiny = Shiny.Never;
|
||||
}
|
||||
|
||||
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)
|
||||
{
|
||||
base.ApplyDetails(sav, criteria, pk);
|
||||
if (pk is IScaledSize s)
|
||||
{
|
||||
if (HasFixedHeight)
|
||||
s.HeightScalar = HeightScalar;
|
||||
if (HasFixedWeight)
|
||||
s.WeightScalar = WeightScalar;
|
||||
}
|
||||
if (pk is IScaledSizeValue v)
|
||||
{
|
||||
v.ResetHeight();
|
||||
v.ResetWeight();
|
||||
}
|
||||
|
||||
if (IsAlpha && pk is IAlpha a)
|
||||
a.IsAlpha = true;
|
||||
|
||||
if (pk is PA8 pa)
|
||||
{
|
||||
pa.SetMasteryFlags();
|
||||
pa.HeightScalarCopy = pa.HeightScalar;
|
||||
if (IsAlpha)
|
||||
pa.SetMasteryFlagMove(pa.AlphaMove = pa.GetRandomAlphaMove());
|
||||
}
|
||||
|
||||
pk.SetRandomEC();
|
||||
}
|
||||
|
||||
protected override void ApplyDetailsBall(PKM pk) => pk.Ball = Gift ? Ball : (int)Core.Ball.LAPoke;
|
||||
|
||||
public override bool IsMatchExact(PKM pkm, DexLevel evo)
|
||||
{
|
||||
if (!base.IsMatchExact(pkm, evo))
|
||||
return false;
|
||||
|
||||
if (pkm is IScaledSize s)
|
||||
{
|
||||
if (HasFixedHeight && s.HeightScalar != HeightScalar)
|
||||
return false;
|
||||
if (HasFixedWeight && s.WeightScalar != WeightScalar)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pkm is IAlpha a && a.IsAlpha != IsAlpha)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override EncounterMatchRating GetMatchRating(PKM pkm)
|
||||
{
|
||||
if (Shiny != Shiny.Random && !Shiny.IsValid(pkm))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
if (Gift && pkm.Ball != Ball)
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
|
||||
if (!IsForcedMasteryCorrect(pkm))
|
||||
return EncounterMatchRating.PartialMatch;
|
||||
|
||||
var orig = base.GetMatchRating(pkm);
|
||||
if (orig is not EncounterMatchRating.Match)
|
||||
return orig;
|
||||
|
||||
if (IsAlpha && pkm is PA8 { AlphaMove: 0 })
|
||||
return EncounterMatchRating.Deferred;
|
||||
|
||||
return EncounterMatchRating.Match;
|
||||
}
|
||||
|
||||
private bool IsForcedMasteryCorrect(PKM pkm)
|
||||
{
|
||||
if (Mastery is not { } m)
|
||||
return true;
|
||||
|
||||
if (Species == (int)Core.Species.Kricketune && Level == 12)
|
||||
{
|
||||
if (pkm is PA8 { AlphaMove: not (int)Move.FalseSwipe })
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pkm is not IMoveShop8Mastery p)
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < m.Length; i++)
|
||||
{
|
||||
if (!m[i])
|
||||
continue;
|
||||
var move = Moves[i];
|
||||
var index = p.MoveShopPermitIndexes.IndexOf(move);
|
||||
if (index == -1)
|
||||
continue; // manually mastered for encounter, not a tutor
|
||||
if (!p.GetMasteredRecordFlag(index))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -14,5 +14,15 @@ public EncounterTrade7b(GameVersion game) : base(game)
|
||||
Shiny = Shiny.Random;
|
||||
IsNicknamed = false;
|
||||
}
|
||||
|
||||
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)
|
||||
{
|
||||
base.ApplyDetails(sav, criteria, pk);
|
||||
if (pk is IScaledSizeValue v)
|
||||
{
|
||||
v.ResetHeight();
|
||||
v.ResetWeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public static IEnumerable<IEncounterable> GetEncounters(PKM pkm)
|
||||
return pkm.Version switch
|
||||
{
|
||||
(int)GameVersion.GO => EncounterGenerator7.GetEncountersGO(pkm, chain),
|
||||
(int)GameVersion.PLA => EncounterGenerator8a.GetEncounters(pkm, chain),
|
||||
(int)GameVersion.BD or (int)GameVersion.SP => EncounterGenerator8b.GetEncounters(pkm, chain),
|
||||
_ => GetEncountersMainline(pkm, chain),
|
||||
};
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static PKHeX.Core.MysteryGiftGenerator;
|
||||
using static PKHeX.Core.EncounterSlotGenerator;
|
||||
using static PKHeX.Core.EncounterStaticGenerator;
|
||||
using static PKHeX.Core.EncounterMatchRating;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class EncounterGenerator8a
|
||||
{
|
||||
public static IEnumerable<IEncounterable> GetEncounters(PKM pkm, IReadOnlyList<EvoCriteria> chain)
|
||||
{
|
||||
if (pkm.IsEgg)
|
||||
yield break;
|
||||
|
||||
int ctr = 0;
|
||||
if (pkm.FatefulEncounter)
|
||||
{
|
||||
foreach (var z in GetValidGifts(pkm, chain))
|
||||
{ yield return z; ++ctr; }
|
||||
if (ctr != 0) yield break;
|
||||
}
|
||||
|
||||
IEncounterable? cache = null;
|
||||
EncounterMatchRating rating = None;
|
||||
|
||||
// Static Encounters can collide with wild encounters (close match); don't break if a Static Encounter is yielded.
|
||||
var encs = GetValidStaticEncounter(pkm, chain);
|
||||
foreach (var z in encs)
|
||||
{
|
||||
var match = z.GetMatchRating(pkm);
|
||||
if (match == Match)
|
||||
{
|
||||
yield return z;
|
||||
}
|
||||
else if (match < rating)
|
||||
{
|
||||
cache = z;
|
||||
rating = match;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var z in GetValidWildEncounters(pkm, chain))
|
||||
{
|
||||
var match = z.GetMatchRating(pkm);
|
||||
if (match == Match)
|
||||
{
|
||||
yield return z;
|
||||
}
|
||||
else if (match < rating)
|
||||
{
|
||||
cache = z;
|
||||
rating = match;
|
||||
}
|
||||
}
|
||||
|
||||
if (cache != null)
|
||||
yield return cache;
|
||||
}
|
||||
}
|
||||
@@ -202,7 +202,7 @@ private static IEnumerable<int> GetMovesForGeneration(PKM pk, IReadOnlyList<EvoC
|
||||
moves = moves.Concat(MoveEgg.GetSharedEggMoves(pk, generation));
|
||||
|
||||
// TR moves -- default logic checks the TR flags, so we need to add all possible ones here.
|
||||
if (!pk.BDSP)
|
||||
if (!(pk.BDSP || pk.LA))
|
||||
moves = moves.Concat(MoveTechnicalMachine.GetAllPossibleRecords(pk.Species, pk.Form));
|
||||
}
|
||||
if (pk.Species == (int)Species.Shedinja)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
using static PKHeX.Core.Encounters7;
|
||||
using static PKHeX.Core.Encounters7b;
|
||||
using static PKHeX.Core.Encounters8;
|
||||
using static PKHeX.Core.Encounters8a;
|
||||
using static PKHeX.Core.Encounters8b;
|
||||
using static PKHeX.Core.EncountersGO;
|
||||
|
||||
@@ -153,6 +154,7 @@ private static IEnumerable<EncounterArea> GetEncounterAreas(PKM pkm, GameVersion
|
||||
SH => SlotsSH,
|
||||
BD => SlotsBD,
|
||||
SP => SlotsSP,
|
||||
PLA => SlotsLA,
|
||||
_ => Array.Empty<EncounterArea>(),
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
using static PKHeX.Core.Encounters7;
|
||||
using static PKHeX.Core.Encounters7b;
|
||||
using static PKHeX.Core.Encounters8;
|
||||
using static PKHeX.Core.Encounters8a;
|
||||
using static PKHeX.Core.Encounters8b;
|
||||
|
||||
using static PKHeX.Core.GameVersion;
|
||||
@@ -175,6 +176,7 @@ internal static EncounterStatic7 GetVCStaticTransferEncounter(PKM pkm, IEncounte
|
||||
SH => StaticSH,
|
||||
BD => StaticBD,
|
||||
SP => StaticSP,
|
||||
PLA => StaticLA,
|
||||
_ => Array.Empty<EncounterStatic>(),
|
||||
};
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public static IEnumerable<MysteryGift> GetValidGifts(PKM pkm, IReadOnlyList<DexL
|
||||
5 => MGDB_G5,
|
||||
6 => MGDB_G6,
|
||||
7 => pkm.LGPE ? MGDB_G7GG : MGDB_G7,
|
||||
8 => pkm.BDSP ? MGDB_G8B : MGDB_G8,
|
||||
8 => pkm.BDSP ? MGDB_G8B : pkm.LA ? MGDB_G8A : MGDB_G8,
|
||||
_ => Array.Empty<MysteryGift>(),
|
||||
};
|
||||
|
||||
|
||||
@@ -140,7 +140,8 @@ private static CheckMoveResult[] ParseMovesGenGB(PKM pkm, IReadOnlyList<int> cur
|
||||
{
|
||||
var res = new CheckMoveResult[4];
|
||||
var enc = info.EncounterMatch;
|
||||
var level = info.EvoChainsAllGens[enc.Generation][^1].MinLevel;
|
||||
var evos = info.EvoChainsAllGens[enc.Generation];
|
||||
var level = evos.Count > 0 ? evos[^1].MinLevel : enc.LevelMin;
|
||||
var InitialMoves = Array.Empty<int>();
|
||||
var SpecialMoves = GetSpecialMoves(enc);
|
||||
var games = enc.Generation == 1 ? GBRestrictions.GetGen1Versions(enc) : GBRestrictions.GetGen2Versions(enc, pkm.Korean);
|
||||
|
||||
@@ -85,6 +85,10 @@ public enum SlotType : byte
|
||||
/// </summary>
|
||||
SOS = 15,
|
||||
|
||||
Overworld = 16,
|
||||
Distortion = 17,
|
||||
Landmark = 18,
|
||||
|
||||
// Modifiers
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -74,13 +74,14 @@ public bool Valid(PKM pkm, int lvl, bool skipChecks)
|
||||
RequiresLevelUp = false;
|
||||
switch ((EvolutionType)Method)
|
||||
{
|
||||
case UseItem or UseItemWormhole:
|
||||
case UseItem or UseItemWormhole or UseItemFullMoon:
|
||||
case CriticalHitsInBattle or HitPointsLostInBattle or Spin:
|
||||
case UseAgileStyleMoves or UseStrongStyleMoves:
|
||||
case TowerOfDarkness or TowerOfWaters:
|
||||
return true;
|
||||
case UseItemMale:
|
||||
case UseItemMale or RecoilDamageMale:
|
||||
return pkm.Gender == 0;
|
||||
case UseItemFemale:
|
||||
case UseItemFemale or RecoilDamageFemale:
|
||||
return pkm.Gender == 1;
|
||||
|
||||
case Trade or TradeHeldItem or TradeShelmetKarrablast:
|
||||
@@ -104,6 +105,9 @@ public bool Valid(PKM pkm, int lvl, bool skipChecks)
|
||||
|
||||
// Level Up (any); the above Level Up (with condition) cases will reach here if they were valid
|
||||
default:
|
||||
if (IsThresholdCheckMode(pkm))
|
||||
return lvl >= Level;
|
||||
|
||||
if (Level == 0 && lvl < 2)
|
||||
return false;
|
||||
if (lvl < Level)
|
||||
@@ -118,6 +122,13 @@ public bool Valid(PKM pkm, int lvl, bool skipChecks)
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsThresholdCheckMode(PKM pkm)
|
||||
{
|
||||
// Starting in Legends: Arceus, level-up evolutions can be triggered if the current level is >= criteria.
|
||||
// This allows for evolving over-leveled captures immediately without leveling up from capture level.
|
||||
return pkm is PA8;
|
||||
}
|
||||
|
||||
private bool HasMetLevelIncreased(PKM pkm, int lvl)
|
||||
{
|
||||
int origin = pkm.Generation;
|
||||
|
||||
@@ -35,9 +35,9 @@ private static EvolutionMethod GetMethod(ReadOnlySpan<byte> entry)
|
||||
return new EvolutionMethod(method, species, argument: arg, level: lvl);
|
||||
}
|
||||
|
||||
public static IReadOnlyList<EvolutionMethod[]> GetArray(IReadOnlyList<byte[]> data)
|
||||
public static IReadOnlyList<EvolutionMethod[]> GetArray(BinLinkerAccessor data)
|
||||
{
|
||||
var evos = new EvolutionMethod[data.Count][];
|
||||
var evos = new EvolutionMethod[data.Length][];
|
||||
for (int i = 0; i < evos.Length; i++)
|
||||
evos[i] = GetMethods(data[i]);
|
||||
return evos;
|
||||
|
||||
@@ -32,9 +32,9 @@ private static EvolutionMethod ReadEvolution(ReadOnlySpan<byte> entry)
|
||||
return new EvolutionMethod(method, species, argument: arg, level: level, form: form);
|
||||
}
|
||||
|
||||
public static IReadOnlyList<EvolutionMethod[]> GetArray(IReadOnlyList<byte[]> data)
|
||||
public static IReadOnlyList<EvolutionMethod[]> GetArray(BinLinkerAccessor data)
|
||||
{
|
||||
var evos = new EvolutionMethod[data.Count][];
|
||||
var evos = new EvolutionMethod[data.Length][];
|
||||
for (int i = 0; i < evos.Length; i++)
|
||||
evos[i] = GetMethods(data[i]);
|
||||
return evos;
|
||||
|
||||
@@ -14,25 +14,27 @@ namespace PKHeX.Core
|
||||
/// </remarks>
|
||||
public sealed class EvolutionTree
|
||||
{
|
||||
private static readonly EvolutionTree Evolves1 = new(new[] { Get("rby") }, Gen1, PersonalTable.Y, MaxSpeciesID_1);
|
||||
private static readonly EvolutionTree Evolves2 = new(new[] { Get("gsc") }, Gen2, PersonalTable.C, MaxSpeciesID_2);
|
||||
private static readonly EvolutionTree Evolves3 = new(new[] { Get("g3") }, Gen3, PersonalTable.RS, MaxSpeciesID_3);
|
||||
private static readonly EvolutionTree Evolves4 = new(new[] { Get("g4") }, Gen4, PersonalTable.DP, MaxSpeciesID_4);
|
||||
private static readonly EvolutionTree Evolves5 = new(new[] { Get("g5") }, Gen5, PersonalTable.BW, MaxSpeciesID_5);
|
||||
private static readonly EvolutionTree Evolves6 = new(Unpack("ao"), Gen6, PersonalTable.AO, MaxSpeciesID_6);
|
||||
private static readonly EvolutionTree Evolves7 = new(Unpack("uu"), Gen7, PersonalTable.USUM, MaxSpeciesID_7_USUM);
|
||||
private static readonly EvolutionTree Evolves7b = new(Unpack("gg"), Gen7, PersonalTable.GG, MaxSpeciesID_7b);
|
||||
private static readonly EvolutionTree Evolves8 = new(Unpack("ss"), Gen8, PersonalTable.SWSH, MaxSpeciesID_8);
|
||||
private static readonly EvolutionTree Evolves8b = new(Unpack("bs"), Gen8, PersonalTable.BDSP, MaxSpeciesID_8b);
|
||||
private static readonly EvolutionTree Evolves1 = new(GetResource("rby"), Gen1, PersonalTable.Y, MaxSpeciesID_1);
|
||||
private static readonly EvolutionTree Evolves2 = new(GetResource("gsc"), Gen2, PersonalTable.C, MaxSpeciesID_2);
|
||||
private static readonly EvolutionTree Evolves3 = new(GetResource("g3"), Gen3, PersonalTable.RS, MaxSpeciesID_3);
|
||||
private static readonly EvolutionTree Evolves4 = new(GetResource("g4"), Gen4, PersonalTable.DP, MaxSpeciesID_4);
|
||||
private static readonly EvolutionTree Evolves5 = new(GetResource("g5"), Gen5, PersonalTable.BW, MaxSpeciesID_5);
|
||||
private static readonly EvolutionTree Evolves6 = new(GetReader("ao"), Gen6, PersonalTable.AO, MaxSpeciesID_6);
|
||||
private static readonly EvolutionTree Evolves7 = new(GetReader("uu"), Gen7, PersonalTable.USUM, MaxSpeciesID_7_USUM);
|
||||
private static readonly EvolutionTree Evolves7b = new(GetReader("gg"), Gen7, PersonalTable.GG, MaxSpeciesID_7b);
|
||||
private static readonly EvolutionTree Evolves8 = new(GetReader("ss"), Gen8, PersonalTable.SWSH, MaxSpeciesID_8);
|
||||
private static readonly EvolutionTree Evolves8a = new(GetReader("la"), Gen8, PersonalTable.LA, MaxSpeciesID_8a);
|
||||
private static readonly EvolutionTree Evolves8b = new(GetReader("bs"), Gen8, PersonalTable.BDSP, MaxSpeciesID_8b);
|
||||
|
||||
private static byte[] Get(string resource) => Util.GetBinaryResource($"evos_{resource}.pkl");
|
||||
private static byte[][] Unpack(string resource) => BinLinker.Unpack(Get(resource), resource);
|
||||
private static ReadOnlySpan<byte> GetResource(string resource) => Util.GetBinaryResource($"evos_{resource}.pkl");
|
||||
private static BinLinkerAccessor GetReader(string resource) => BinLinkerAccessor.Get(GetResource(resource), resource);
|
||||
|
||||
static EvolutionTree()
|
||||
{
|
||||
// Add in banned evolution data!
|
||||
Evolves7.FixEvoTreeSM();
|
||||
Evolves8.FixEvoTreeSS();
|
||||
Evolves8a.FixEvoTreeLA();
|
||||
Evolves8b.FixEvoTreeBS();
|
||||
}
|
||||
|
||||
@@ -57,7 +59,12 @@ static EvolutionTree()
|
||||
5 => Evolves5,
|
||||
6 => Evolves6,
|
||||
7 => pkm.Version is (int)GO or (int)GP or (int)GE ? Evolves7b : Evolves7,
|
||||
_ => pkm.Version is (int)BD or (int)SP ? Evolves8b : Evolves8,
|
||||
_ => pkm.Version switch
|
||||
{
|
||||
(int)PLA => Evolves8a,
|
||||
(int)BD or (int)SP => Evolves8b,
|
||||
_ => Evolves8,
|
||||
},
|
||||
};
|
||||
|
||||
private readonly IReadOnlyList<EvolutionMethod[]> Entries;
|
||||
@@ -69,7 +76,22 @@ static EvolutionTree()
|
||||
|
||||
#region Constructor
|
||||
|
||||
private EvolutionTree(IReadOnlyList<byte[]> data, GameVersion game, PersonalTable personal, int maxSpeciesTree)
|
||||
private EvolutionTree(ReadOnlySpan<byte> data, GameVersion game, PersonalTable personal, int maxSpeciesTree)
|
||||
{
|
||||
Game = game;
|
||||
Personal = personal;
|
||||
MaxSpeciesTree = maxSpeciesTree;
|
||||
Entries = GetEntries(data, game);
|
||||
|
||||
// Starting in Generation 7, forms have separate evolution data.
|
||||
int format = Game - Gen1 + 1;
|
||||
var oldStyle = format < 7;
|
||||
var connections = oldStyle ? CreateTreeOld() : CreateTree();
|
||||
|
||||
Lineage = connections.ToLookup(obj => obj.Key, obj => obj.Value);
|
||||
}
|
||||
|
||||
private EvolutionTree(BinLinkerAccessor data, GameVersion game, PersonalTable personal, int maxSpeciesTree)
|
||||
{
|
||||
Game = game;
|
||||
Personal = personal;
|
||||
@@ -134,13 +156,18 @@ private EvolutionTree(IReadOnlyList<byte[]> data, GameVersion game, PersonalTabl
|
||||
}
|
||||
}
|
||||
|
||||
private IReadOnlyList<EvolutionMethod[]> GetEntries(IReadOnlyList<byte[]> data, GameVersion game) => game switch
|
||||
private IReadOnlyList<EvolutionMethod[]> GetEntries(ReadOnlySpan<byte> data, GameVersion game) => game switch
|
||||
{
|
||||
Gen1 => EvolutionSet1.GetArray(data, MaxSpeciesTree),
|
||||
Gen2 => EvolutionSet1.GetArray(data, MaxSpeciesTree),
|
||||
Gen3 => EvolutionSet3.GetArray(data),
|
||||
Gen4 => EvolutionSet4.GetArray(data),
|
||||
Gen5 => EvolutionSet5.GetArray(data),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
private IReadOnlyList<EvolutionMethod[]> GetEntries(BinLinkerAccessor data, GameVersion game) => game switch
|
||||
{
|
||||
Gen1 => EvolutionSet1.GetArray(data[0], MaxSpeciesTree),
|
||||
Gen2 => EvolutionSet1.GetArray(data[0], MaxSpeciesTree),
|
||||
Gen3 => EvolutionSet3.GetArray(data[0]),
|
||||
Gen4 => EvolutionSet4.GetArray(data[0]),
|
||||
Gen5 => EvolutionSet5.GetArray(data[0]),
|
||||
Gen6 => EvolutionSet6.GetArray(data),
|
||||
Gen7 => EvolutionSet7.GetArray(data),
|
||||
Gen8 => EvolutionSet7.GetArray(data),
|
||||
@@ -174,6 +201,10 @@ private void FixEvoTreeSS()
|
||||
BanEvo(s, 0, pkm => pkm is IGigantamax {CanGigantamax: true});
|
||||
}
|
||||
|
||||
private void FixEvoTreeLA()
|
||||
{
|
||||
}
|
||||
|
||||
private void FixEvoTreeBS()
|
||||
{
|
||||
BanEvo((int)Species.Glaceon, 0, pkm => pkm.CurrentLevel == pkm.Met_Level); // Ice Stone is unreleased, requires Route 217 Ice Rock Level Up instead
|
||||
|
||||
@@ -54,6 +54,11 @@ public enum EvolutionType : byte
|
||||
LevelUpNatureLowKey = 47, // Toxtricity
|
||||
TowerOfDarkness = 48, // Urshifu
|
||||
TowerOfWaters = 49, // Urshifu
|
||||
UseItemFullMoon = 50, // Ursaluna
|
||||
UseAgileStyleMoves = 51, // Wyrdeer
|
||||
UseStrongStyleMoves = 52, // Overqwil
|
||||
RecoilDamageMale = 53, // Basculegion-0
|
||||
RecoilDamageFemale = 54, // Basculegion-1
|
||||
}
|
||||
|
||||
public static class EvolutionTypeExtensions
|
||||
|
||||
@@ -269,6 +269,7 @@ public static class LegalityCheckStrings
|
||||
public static string LHyperBelow100 { get; set; } = "Can't Hyper Train a Pokémon that isn't level 100.";
|
||||
public static string LHyperPerfectAll { get; set; } = "Can't Hyper Train a Pokémon with perfect IVs.";
|
||||
public static string LHyperPerfectOne { get; set; } = "Can't Hyper Train a perfect IV.";
|
||||
public static string LHyperPerfectUnavailable { get; set; } = "Can't Hyper Train any IV(s).";
|
||||
|
||||
public static string LItemEgg { get; set; } = "Eggs cannot hold items.";
|
||||
public static string LItemUnreleased { get; set; } = "Held item is unreleased.";
|
||||
@@ -353,6 +354,7 @@ public static class LegalityCheckStrings
|
||||
public static string LMoveNincadaEvo { get; set; } = "Learned by evolving Nincada into Ninjask.";
|
||||
public static string LMoveNincadaEvoF_0 { get; set; } = "Learned by evolving Nincada into Ninjask in Generation {0}.";
|
||||
public static string LMovePPTooHigh_0 { get; set; } = "Move {0} PP is above the amount allowed.";
|
||||
public static string LMovePPUpsTooHigh_0 { get; set; } = "Move {0} PP Ups is above the amount allowed.";
|
||||
public static string LMoveSourceShared { get; set; } = "Shared Non-Relearn Move.";
|
||||
public static string LMoveSourceSharedF { get; set; } = "Shared Non-Relearn Move in Generation {0}.";
|
||||
|
||||
@@ -365,6 +367,13 @@ public static class LegalityCheckStrings
|
||||
public static string LMoveRelearnInvalid { get; set; } = "Not an expected Relearnable move.";
|
||||
public static string LMoveRelearnNone { get; set; } = "Expected no Relearn Move in slot.";
|
||||
|
||||
public static string LMoveShopAlphaMoveShouldBeMastered { get; set; } = "Alpha Move should be marked as mastered.";
|
||||
public static string LMoveShopAlphaMoveShouldBeOther { get; set; } = "Alpha encounter cannot be found with this Alpha Move.";
|
||||
public static string LMoveShopAlphaMoveShouldBeZero { get; set; } = "Only Alphas may have an Alpha Move set.";
|
||||
public static string LMoveShopMasterInvalid_0 { get; set; } = "Cannot manually master {0}: not permitted to master.";
|
||||
public static string LMoveShopMasterNotLearned_0 { get; set; } = "Cannot manually master {0}: not in possible learned level up moves.";
|
||||
public static string LMoveShopPurchaseInvalid_0 { get; set; } = "Cannot purchase {0} from the move shop.";
|
||||
|
||||
public static string LMoveSourceDefault { get; set; } = "Default move.";
|
||||
public static string LMoveSourceDuplicate { get; set; } = "Duplicate Move.";
|
||||
public static string LMoveSourceEgg { get; set; } = "Egg Move.";
|
||||
@@ -414,6 +423,9 @@ public static class LegalityCheckStrings
|
||||
public static string LPIDTypeMismatch { get; set; } = "Encounter Type PID mismatch.";
|
||||
public static string LPIDZero { get; set; } = "PID is not set.";
|
||||
|
||||
public static string LPokerusDaysTooHigh_0 { get; set; } = "Pokérus Days Remaining value is too high; expected <= {0}.";
|
||||
public static string LPokerusStrainUnobtainable_0 { get; set; } = "Pokérus Strain {0} cannot be obtained.";
|
||||
|
||||
public static string LRibbonAllValid { get; set; } = "All ribbons accounted for.";
|
||||
public static string LRibbonEgg { get; set; } = "Can't receive Ribbon(s) as an Egg.";
|
||||
public static string LRibbonFInvalid_0 { get; set; } = "Invalid Ribbons: {0}";
|
||||
@@ -423,13 +435,18 @@ public static class LegalityCheckStrings
|
||||
|
||||
public static string LStatDynamaxInvalid { get; set; } = "Dynamax Level is not within the expected range.";
|
||||
public static string LStatIncorrectHeight { get; set; } = "Calculated Height does not match stored value.";
|
||||
public static string LStatIncorrectHeightCopy { get; set; } = "Copy Height does not match the original value.";
|
||||
public static string LStatIncorrectHeightValue { get; set; } = "Height does not match the expected value.";
|
||||
public static string LStatIncorrectWeight { get; set; } = "Calculated Weight does not match stored value.";
|
||||
public static string LStatIncorrectWeightValue { get; set; } = "Weight does not match the expected value.";
|
||||
public static string LStatInvalidHeightWeight { get; set; } = "Height / Weight values are statistically improbable.";
|
||||
public static string LStatIncorrectCP { get; set; } = "Calculated CP does not match stored value.";
|
||||
public static string LStatGigantamaxInvalid { get; set; } = "Gigantamax Flag mismatch.";
|
||||
public static string LStatGigantamaxValid { get; set; } = "Gigantamax Flag was changed via Max Soup.";
|
||||
public static string LStatNatureInvalid { get; set; } = "Stat Nature is not within the expected range.";
|
||||
public static string LStatBattleVersionInvalid { get; set; } = "Battle Version is not within the expected range.";
|
||||
public static string LStatNobleInvalid { get; set; } = "Noble Flag mismatch.";
|
||||
public static string LStatAlphaInvalid { get; set; } = "Alpha Flag mismatch.";
|
||||
|
||||
public static string LSuperComplete { get; set; } = "Super Training complete flag mismatch.";
|
||||
public static string LSuperDistro { get; set; } = "Distribution Super Training missions are not released.";
|
||||
|
||||
@@ -94,7 +94,8 @@ public int[] GetEncounterMoves(int level)
|
||||
{
|
||||
const int count = 4;
|
||||
var moves = new int[count];
|
||||
return GetEncounterMoves(level, moves);
|
||||
SetEncounterMoves(level, moves);
|
||||
return moves;
|
||||
}
|
||||
|
||||
/// <summary>Returns the moves a Pokémon would have if it were encountered at the specified level.</summary>
|
||||
@@ -103,7 +104,7 @@ public int[] GetEncounterMoves(int level)
|
||||
/// <param name="moves">Move array to write to</param>
|
||||
/// <param name="ctr">Starting index to begin overwriting at</param>
|
||||
/// <returns>Array of Move IDs</returns>
|
||||
public int[] GetEncounterMoves(int level, int[] moves, int ctr = 0)
|
||||
public void SetEncounterMoves(int level, Span<int> moves, int ctr = 0)
|
||||
{
|
||||
for (int i = 0; i < Moves.Length; i++)
|
||||
{
|
||||
@@ -111,14 +112,50 @@ public int[] GetEncounterMoves(int level, int[] moves, int ctr = 0)
|
||||
break;
|
||||
|
||||
int move = Moves[i];
|
||||
bool alreadyHasMove = Array.IndexOf(moves, move) >= 0;
|
||||
bool alreadyHasMove = moves.IndexOf(move) >= 0;
|
||||
if (alreadyHasMove)
|
||||
continue;
|
||||
|
||||
moves[ctr++] = move;
|
||||
ctr &= 3;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Adds the learned moves by level up to the specified level.</summary>
|
||||
public void SetLevelUpMoves(int startLevel, int endLevel, Span<int> moves, int ctr = 0)
|
||||
{
|
||||
int startIndex = Array.FindIndex(Levels, z => z >= startLevel);
|
||||
int endIndex = Array.FindIndex(Levels, z => z > endLevel);
|
||||
for (int i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
int move = Moves[i];
|
||||
bool alreadyHasMove = moves.IndexOf(move) >= 0;
|
||||
if (alreadyHasMove)
|
||||
continue;
|
||||
|
||||
moves[ctr++] = move;
|
||||
ctr &= 3;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Adds the moves that are gained upon evolving.</summary>
|
||||
/// <param name="moves">Move array to write to</param>
|
||||
/// <param name="ctr">Starting index to begin overwriting at</param>
|
||||
public void SetEvolutionMoves(Span<int> moves, int ctr = 0)
|
||||
{
|
||||
for (int i = 0; i < Moves.Length; i++)
|
||||
{
|
||||
if (Levels[i] != 0)
|
||||
break;
|
||||
|
||||
int move = Moves[i];
|
||||
bool alreadyHasMove = moves.IndexOf(move) >= 0;
|
||||
if (alreadyHasMove)
|
||||
continue;
|
||||
|
||||
moves[ctr++] = move;
|
||||
ctr &= 3;
|
||||
}
|
||||
return moves;
|
||||
}
|
||||
|
||||
public IList<int> GetUniqueMovesLearned(IEnumerable<int> seed, int maxLevel, int minLevel = 0)
|
||||
|
||||
@@ -15,7 +15,7 @@ public static class LearnsetReader
|
||||
/// </summary>
|
||||
/// <param name="input">Raw ROM data containing the contiguous moves</param>
|
||||
/// <param name="maxSpecies">Highest species ID for the input game.</param>
|
||||
public static Learnset[] GetArray(byte[] input, int maxSpecies)
|
||||
public static Learnset[] GetArray(ReadOnlySpan<byte> input, int maxSpecies)
|
||||
{
|
||||
var data = new Learnset[maxSpecies + 1];
|
||||
|
||||
@@ -30,7 +30,7 @@ public static Learnset[] GetArray(byte[] input, int maxSpecies)
|
||||
/// Loads a learnset by reading 16-bit move,level pairs.
|
||||
/// </summary>
|
||||
/// <param name="entries">Entry data</param>
|
||||
public static Learnset[] GetArray(byte[][] entries)
|
||||
public static Learnset[] GetArray(BinLinkerAccessor entries)
|
||||
{
|
||||
Learnset[] data = new Learnset[entries.Length];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#define SUPPRESS
|
||||
//#define SUPPRESS
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -311,6 +311,7 @@ private void UpdateChecks()
|
||||
return;
|
||||
|
||||
Mark.Verify(this);
|
||||
Arceus.Verify(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,5 +32,6 @@ internal static class LegalityAnalyzers
|
||||
public static readonly MiscVerifier MiscValues = new();
|
||||
public static readonly TransferVerifier Transfer = new();
|
||||
public static readonly MarkVerifier Mark = new();
|
||||
public static readonly LegendsArceusVerifier Arceus = new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,10 +142,18 @@ internal static int[] GetBaseEggMoves(PKM pkm, int species, int form, GameVersio
|
||||
}
|
||||
break;
|
||||
|
||||
case PLA:
|
||||
if (pkm.InhabitedGeneration(8))
|
||||
{
|
||||
int index = PersonalTable.LA.GetFormIndex(species, form);
|
||||
return LevelUpLA[index].GetMoves(lvl);
|
||||
}
|
||||
break;
|
||||
|
||||
case BD or SP or BDSP:
|
||||
if (pkm.InhabitedGeneration(8))
|
||||
{
|
||||
int index = PersonalTable.SWSH.GetFormIndex(species, form);
|
||||
int index = PersonalTable.BDSP.GetFormIndex(species, form);
|
||||
return LevelUpBDSP[index].GetMoves(lvl);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -44,6 +44,7 @@ public static Learnset GetLearnset(GameVersion game, int species, int form)
|
||||
|
||||
SW or SH or SWSH => Legal.LevelUpSWSH,
|
||||
BD or SP or BDSP => Legal.LevelUpBDSP,
|
||||
PLA => Legal.LevelUpLA,
|
||||
|
||||
Gen1 => Legal.LevelUpY,
|
||||
Gen2 => Legal.LevelUpC,
|
||||
@@ -88,6 +89,7 @@ public static Learnset GetLearnset(GameVersion game, int species, int form)
|
||||
|
||||
SW or SH or SWSH => PersonalTable.SWSH,
|
||||
BD or SP or BDSP => PersonalTable.BDSP,
|
||||
PLA => PersonalTable.LA,
|
||||
|
||||
Gen1 => PersonalTable.Y,
|
||||
Gen2 => PersonalTable.C,
|
||||
|
||||
@@ -61,6 +61,7 @@ internal static int[] GetRelearnLVLMoves(PKM pkm, int species, int form, int lvl
|
||||
US or UM => getMoves(LevelUpUSUM, PersonalTable.USUM),
|
||||
SW or SH => getMoves(LevelUpSWSH, PersonalTable.SWSH),
|
||||
BD or SP => getMoves(LevelUpBDSP, PersonalTable.BDSP),
|
||||
PLA => getMoves(LevelUpLA, PersonalTable.LA),
|
||||
_ => Array.Empty<int>(),
|
||||
};
|
||||
|
||||
@@ -79,6 +80,7 @@ public static int[] GetSharedEggMoves(PKM pkm, int gen)
|
||||
{
|
||||
if (gen < 8 || pkm.IsEgg)
|
||||
return Array.Empty<int>();
|
||||
|
||||
if (pkm.BDSP)
|
||||
{
|
||||
var table = PersonalTable.BDSP;
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace PKHeX.Core
|
||||
public static class MoveLevelUp
|
||||
{
|
||||
private static readonly LearnLookup
|
||||
LearnLA = new(PersonalTable.LA, LevelUpLA, PLA),
|
||||
LearnBDSP = new(PersonalTable.BDSP, LevelUpBDSP, BDSP),
|
||||
LearnSWSH = new(PersonalTable.SWSH, LevelUpSWSH, SWSH),
|
||||
LearnSM = new(PersonalTable.SM, LevelUpSM, SM),
|
||||
@@ -215,6 +216,11 @@ private static LearnVersion GetIsLevelUp8(int species, int form, int move, int m
|
||||
return LearnNONE;
|
||||
return LearnSWSH.GetIsLevelUp(species, form, move, maxLevel);
|
||||
|
||||
case PLA:
|
||||
if (species > MaxSpeciesID_8a)
|
||||
return LearnNONE;
|
||||
return LearnLA.GetIsLevelUp(species, form, move, maxLevel);
|
||||
|
||||
case BD or SP or BDSP:
|
||||
if (species > MaxSpeciesID_8b)
|
||||
return LearnNONE;
|
||||
@@ -478,6 +484,11 @@ private static List<int> AddMovesLevelUp8(List<int> moves, GameVersion ver, int
|
||||
return moves;
|
||||
return LearnSWSH.AddMoves(moves, species, form, maxLevel);
|
||||
|
||||
case PLA:
|
||||
if (species > MaxSpeciesID_8a)
|
||||
return moves;
|
||||
return LearnLA.AddMoves(moves, species, form, maxLevel);
|
||||
|
||||
case BD or SP or BDSP:
|
||||
if (species > MaxSpeciesID_8b)
|
||||
return moves;
|
||||
@@ -501,7 +512,8 @@ private static int[] GetEncounterMoves1(int species, int level, GameVersion vers
|
||||
var lvl0 = (int[])((PersonalInfoG1) table[index]).Moves.Clone();
|
||||
int start = Math.Max(0, Array.IndexOf(lvl0, 0));
|
||||
|
||||
return learn[index].GetEncounterMoves(level, lvl0, start);
|
||||
learn[index].SetEncounterMoves(level, lvl0, start);
|
||||
return lvl0;
|
||||
}
|
||||
|
||||
private static int[] GetEncounterMoves2(int species, int level, GameVersion version)
|
||||
@@ -512,7 +524,8 @@ private static int[] GetEncounterMoves2(int species, int level, GameVersion vers
|
||||
var lvl0 = learn[species].GetEncounterMoves(1);
|
||||
int start = Math.Max(0, Array.IndexOf(lvl0, 0));
|
||||
|
||||
return learn[index].GetEncounterMoves(level, lvl0, start);
|
||||
learn[index].SetEncounterMoves(level, lvl0, start);
|
||||
return lvl0;
|
||||
}
|
||||
|
||||
public static int[] GetEncounterMoves(int species, int form, int level, GameVersion version)
|
||||
|
||||
@@ -245,7 +245,7 @@ private static GameVersion GetIsMachine8(int species, int move, int form, GameVe
|
||||
|
||||
if (GameVersion.BDSP.Contains(ver))
|
||||
{
|
||||
for (int i = 0; i < PersonalInfoSWSH.CountTM; i++)
|
||||
for (int i = 0; i < PersonalInfoBDSP.CountTM; i++)
|
||||
{
|
||||
if (Legal.TMHM_BDSP[i] != move)
|
||||
continue;
|
||||
@@ -272,7 +272,7 @@ private static GameVersion GetIsRecord8(PKM pkm, int species, int move, int form
|
||||
break;
|
||||
if (allowBit)
|
||||
return GameVersion.SWSH;
|
||||
if (((G8PKM)pkm).GetMoveRecordFlag(i))
|
||||
if (((ITechRecord8)pkm).GetMoveRecordFlag(i))
|
||||
return GameVersion.SWSH;
|
||||
if (i == 12 && species == (int)Species.Calyrex && form == 0) // TR12
|
||||
return GameVersion.SWSH; // Agility Calyrex without TR glitch.
|
||||
@@ -421,7 +421,7 @@ private static void AddMachine8(List<int> r, int species, int form, GameVersion
|
||||
case GameVersion.Any:
|
||||
case GameVersion.SW or GameVersion.SH or GameVersion.SWSH:
|
||||
AddMachineSWSH(r, species, form);
|
||||
break;
|
||||
return;
|
||||
case GameVersion.BD or GameVersion.SP or GameVersion.BDSP:
|
||||
AddMachineBDSP(r, species, form);
|
||||
return;
|
||||
|
||||
@@ -153,6 +153,17 @@ private static GameVersion GetIsTutor7(PKM pkm, int species, int form, bool spec
|
||||
|
||||
private static GameVersion GetIsTutor8(PKM pkm, int species, int form, bool specialTutors, int move)
|
||||
{
|
||||
if (pkm.LA)
|
||||
{
|
||||
var pi = (PersonalInfoLA)PersonalTable.LA.GetFormEntry(species, form);
|
||||
if (!pi.IsPresentInGame)
|
||||
return NONE;
|
||||
var index = Array.IndexOf(MoveShop8_LA, move);
|
||||
if (index != -1 && pi.SpecialTutors[0][index])
|
||||
return GameVersion.PLA;
|
||||
|
||||
return NONE;
|
||||
}
|
||||
if (pkm.BDSP)
|
||||
{
|
||||
var pi = (PersonalInfoBDSP)PersonalTable.BDSP.GetFormEntry(species, form);
|
||||
@@ -267,6 +278,13 @@ private static void AddMovesTutor7(List<int> moves, int species, int form, PKM p
|
||||
|
||||
private static void AddMovesTutor8(List<int> moves, int species, int form, PKM pkm, bool specialTutors)
|
||||
{
|
||||
if (pkm.LA)
|
||||
{
|
||||
var pi = (PersonalInfoLA)PersonalTable.LA.GetFormEntry(species, form);
|
||||
if (!pi.IsPresentInGame)
|
||||
return;
|
||||
moves.AddRange(MoveShop8_LA.Where((_, i) => pi.SpecialTutors[0][i]));
|
||||
}
|
||||
if (pkm.BDSP)
|
||||
{
|
||||
var pi = (PersonalInfoBDSP)PersonalTable.BDSP.GetFormEntry(species, form);
|
||||
|
||||
@@ -85,6 +85,20 @@ internal static class EvolutionRestrictions
|
||||
new byte[] { 00, 00, 00, 00, 00, 00, 00, 00, 35 }, // Grapploct (Clobbopus with Taunt)
|
||||
};
|
||||
|
||||
private static readonly byte[] MinLevelEvolutionWithMove_8LA =
|
||||
{
|
||||
00, // Sylveon (Eevee with Fairy Move)
|
||||
25, // Mr. Mime (Mime Jr with Mimic)
|
||||
29, // Sudowoodo (Bonsly with Mimic)
|
||||
25, // Ambipom (Aipom with Double Hit)
|
||||
34, // Lickilicky (Lickitung with Rollout)
|
||||
34, // Tangrowth (Tangela with Ancient Power)
|
||||
34, // Yanmega (Yanma with Ancient Power)
|
||||
34, // Mamoswine (Piloswine with Ancient Power)
|
||||
99, // Tsareena (Steenee with Stomp)
|
||||
99, // Grapploct (Clobbopus with Taunt)
|
||||
};
|
||||
|
||||
private static readonly bool[][] CanEggHatchWithEvolveMove =
|
||||
{
|
||||
new [] { false, false, true, true, true, true, true, true, true }, // Sylveon (Eevee with Fairy Move)
|
||||
@@ -153,6 +167,9 @@ public static bool IsValidEvolutionWithMove(PKM pkm, LegalInfo info)
|
||||
|
||||
private static int GetMinLevelKnowRequiredMove(PKM pkm, int gen, int index)
|
||||
{
|
||||
if (gen == 8 && pkm.LA) // No Level Up required, and different levels than mainline SW/SH.
|
||||
return MinLevelEvolutionWithMove_8LA[index];
|
||||
|
||||
var lvl = GetLevelLearnMove(pkm, gen, index);
|
||||
|
||||
// If has original met location the minimum evolution level is one level after met level
|
||||
|
||||
@@ -45,6 +45,7 @@ public static bool IsHeldItemAllowed(int item, int generation, PKM pk)
|
||||
5 => ReleasedHeldItems_5,
|
||||
6 => ReleasedHeldItems_6,
|
||||
7 => ReleasedHeldItems_7,
|
||||
8 when pk is PA8 => Array.Empty<bool>(),
|
||||
8 when pk is PB8 => ReleasedHeldItems_8b,
|
||||
8 => ReleasedHeldItems_8,
|
||||
_ => Array.Empty<bool>(),
|
||||
|
||||
@@ -61,7 +61,7 @@ private static EggMoves6 Get(ReadOnlySpan<byte> data)
|
||||
return new EggMoves6(moves);
|
||||
}
|
||||
|
||||
public static EggMoves6[] GetArray(byte[][] entries)
|
||||
public static EggMoves6[] GetArray(BinLinkerAccessor entries)
|
||||
{
|
||||
EggMoves6[] data = new EggMoves6[entries.Length];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
@@ -92,7 +92,7 @@ private static EggMoves7 Get(ReadOnlySpan<byte> data)
|
||||
return new EggMoves7(moves, formIndex);
|
||||
}
|
||||
|
||||
public static EggMoves7[] GetArray(byte[][] entries)
|
||||
public static EggMoves7[] GetArray(BinLinkerAccessor entries)
|
||||
{
|
||||
EggMoves7[] data = new EggMoves7[entries.Length];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
|
||||
@@ -100,25 +100,28 @@ public static bool IsFormChangeable(int species, int oldForm, int newForm, int f
|
||||
private static readonly HashSet<int> FormChange = new()
|
||||
{
|
||||
// Sometimes considered for wild encounters
|
||||
412, // Burmy
|
||||
479, // Rotom
|
||||
676, // Furfrou
|
||||
741, // Oricorio
|
||||
(int)Burmy,
|
||||
(int)Rotom,
|
||||
(int)Furfrou,
|
||||
(int)Oricorio,
|
||||
|
||||
386, // Deoxys
|
||||
487, // Giratina
|
||||
492, // Shaymin
|
||||
493, // Arceus
|
||||
641, // Tornadus
|
||||
642, // Thundurus
|
||||
645, // Landorus
|
||||
646, // Kyurem
|
||||
647, // Keldeo
|
||||
649, // Genesect
|
||||
720, // Hoopa
|
||||
773, // Silvally
|
||||
800, // Necrozma
|
||||
898, // Calyrex
|
||||
(int)Deoxys,
|
||||
(int)Dialga,
|
||||
(int)Palkia,
|
||||
(int)Giratina,
|
||||
(int)Shaymin,
|
||||
(int)Arceus,
|
||||
(int)Tornadus,
|
||||
(int)Thundurus,
|
||||
(int)Landorus,
|
||||
(int)Kyurem,
|
||||
(int)Keldeo,
|
||||
(int)Genesect,
|
||||
(int)Hoopa,
|
||||
(int)Silvally,
|
||||
(int)Necrozma,
|
||||
(int)Calyrex,
|
||||
(int)Enamorus,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -234,6 +237,24 @@ public static int GetTotemBaseForm(int species, int form)
|
||||
return form - 1;
|
||||
}
|
||||
|
||||
|
||||
public static bool IsLordForm(int species, int form, int generation)
|
||||
{
|
||||
if (generation != 8)
|
||||
return false;
|
||||
return IsLordForm(species, form);
|
||||
}
|
||||
|
||||
private static bool IsLordForm(int species, int form) => form != 0 && species switch
|
||||
{
|
||||
(int)Arcanine when form == 2 => true,
|
||||
(int)Electrode when form == 2 => true,
|
||||
(int)Lilligant when form == 2 => true,
|
||||
(int)Avalugg when form == 2 => true,
|
||||
(int)Kleavor when form == 1 => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="form"/> exists for the <see cref="species"/> without having an associated <see cref="PersonalInfo"/> index.
|
||||
/// </summary>
|
||||
|
||||
@@ -32,6 +32,7 @@ public static partial class Legal
|
||||
{(int)Thundurus,(g, _) => g >= 6},
|
||||
{(int)Landorus, (g, _) => g >= 6},
|
||||
{(int)Urshifu, (g, _) => g >= 8},
|
||||
{(int)Enamorus, (g, _) => g >= 8},
|
||||
|
||||
// Fused
|
||||
{(int)Kyurem, (g, _) => g >= 6},
|
||||
@@ -127,8 +128,14 @@ public static bool IsValidSketch(int move, int generation)
|
||||
return false;
|
||||
if (generation is 6 && move is ((int)ThousandArrows or (int)ThousandWaves))
|
||||
return false;
|
||||
if (generation is 8 && (SignatureSketch_BDSP.Contains(move) || DummiedMoves_BDSP.Contains(move))) // can't Sketch unusable moves in BDSP
|
||||
return false;
|
||||
if (generation is 8) // can't Sketch unusable moves in BDSP, no Sketch in PLA
|
||||
{
|
||||
if (SignatureSketch_BDSP.Contains(move) || DummiedMoves_BDSP.Contains(move))
|
||||
return false;
|
||||
if (move > MaxMoveID_8)
|
||||
return false;
|
||||
}
|
||||
|
||||
return move <= GetMaxMoveID(generation);
|
||||
}
|
||||
|
||||
@@ -177,7 +184,7 @@ public static bool IsValidSketch(int move, int generation)
|
||||
(int)TypeNull, (int)Silvally, (int)TapuKoko, (int)TapuLele, (int)TapuBulu, (int)TapuFini,
|
||||
(int)Nihilego, (int)Buzzwole, (int)Pheromosa, (int)Xurkitree, (int)Celesteela, (int)Kartana, (int)Guzzlord,
|
||||
(int)Poipole, (int)Naganadel, (int)Stakataka, (int)Blacephalon,
|
||||
(int)Kubfu, (int)Urshifu, (int)Regieleki, (int)Regidrago, (int)Glastrier, (int)Spectrier,
|
||||
(int)Kubfu, (int)Urshifu, (int)Regieleki, (int)Regidrago, (int)Glastrier, (int)Spectrier, (int)Enamorus,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
309
PKHeX.Core/Legality/Tables/Tables8a.cs
Normal file
309
PKHeX.Core/Legality/Tables/Tables8a.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public static partial class Legal
|
||||
{
|
||||
internal const int MaxSpeciesID_8a = (int)Species.Enamorus;
|
||||
internal const int MaxMoveID_8a = (int)Move.TakeHeart;
|
||||
internal const int MaxItemID_8a = 1828; // Legend Plate
|
||||
internal const int MaxBallID_8a = (int)Ball.LAOrigin;
|
||||
internal const int MaxGameID_8a = (int)GameVersion.SP;
|
||||
internal const int MaxAbilityID_8a = MaxAbilityID_8_R2;
|
||||
|
||||
#region Met Locations
|
||||
|
||||
internal static readonly int[] Met_LA_0 =
|
||||
{
|
||||
000, 002, 004, 006, 007, 008, 009,
|
||||
010, 011, 012, 013, 014, 015, 016, 017, 018, 019,
|
||||
020, 021, 022, 023, 024, 025, 026, 027, 028, 029,
|
||||
030, 031, 032, 033, 034, 035, 036, 037, 038, 039,
|
||||
040, 041, 042, 043, 045, 046, 047, 048, 049,
|
||||
050, 051, 052, 053, 054, 055, 056, 057, 058, 059,
|
||||
060, 061, 063, 064, 065, 066, 067, 068, 069,
|
||||
070, 071, 072, 073, 074, 075, 076, 077, 079,
|
||||
080, 081, 082, 083, 084, 085, 086, 087, 088, 089,
|
||||
090, 092, 093, 094, 095, 096, 097, 098, 099,
|
||||
100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
||||
110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
|
||||
130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
|
||||
140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
|
||||
150, 151, 152, 153, 154, 155,
|
||||
};
|
||||
|
||||
internal static readonly int[] Met_LA_3 =
|
||||
{
|
||||
30001, 30002, 30003, 30004, 30005, 30006, 30007, 30008, 30009, 30010, 30011, 30012, 30013, 30014, 30015, 30016, 30017, 30018, 30019, 30020, 30021, 30022,
|
||||
};
|
||||
|
||||
internal static readonly int[] Met_LA_4 =
|
||||
{
|
||||
40001, 40002, 40003, 40005, 40006, 40007, 40008, 40009,
|
||||
40010, 40011, 40012, 40013, 40014, 40016, 40017, 40018, 40019,
|
||||
40020, 40021, 40022, 40024, 40025, 40026, 40027, 40028, 40029,
|
||||
40030, 40032, 40033, 40034, 40035, 40036, 40037, 40038, 40039,
|
||||
40040, 40041, 40042, 40043, 40044, 40045, 40047, 40048, 40049,
|
||||
40050, 40051, 40052, 40053, 40055, 40056, 40057, 40058, 40059,
|
||||
40060, 40061, 40063, 40064, 40065, 40066, 40067, 40068, 40069,
|
||||
40070, 40071, 40072, 40074, 40075, 40076, 40077, 40078, 40079,
|
||||
40080, 40081, 40082, 40083, 40084, 40085, 40086,
|
||||
};
|
||||
|
||||
internal static readonly int[] Met_LA_6 = {/* XY */ 60001, 60003, /* ORAS */ 60004 };
|
||||
|
||||
#endregion
|
||||
|
||||
internal static readonly ushort[] Pouch_Items_LA =
|
||||
{
|
||||
017, 023, 024, 025, 026, 027, 028, 029, 039, 041,
|
||||
050, 054, 072, 073, 075, 080, 081, 082, 083, 084,
|
||||
085, 090, 091, 092, 107, 108, 109, 110, 149, 150,
|
||||
151, 152, 153, 154, 155, 157, 158, 159, 160, 161,
|
||||
162, 163, 164, 166, 168, 233, 252, 321, 322, 323,
|
||||
324, 325, 326, 327, 583, 849,
|
||||
|
||||
1125, 1126, 1127, 1128, 1231, 1232, 1233, 1234, 1235, 1236,
|
||||
1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246,
|
||||
1247, 1248, 1249, 1250, 1251,
|
||||
|
||||
1611, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621,
|
||||
1628, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638,
|
||||
1651, 1679, 1681, 1682, 1684, 1686, 1687, 1688, 1689, 1690,
|
||||
1691, 1692, 1693, 1694, 1695, 1696, 1699, 1700, 1701, 1702,
|
||||
1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1712,
|
||||
1713, 1716, 1717, 1720, 1724, 1725, 1726, 1727, 1728, 1732,
|
||||
1733, 1734, 1735, 1736, 1738, 1739, 1740, 1741, 1742, 1746,
|
||||
1747, 1748, 1749, 1750, 1754, 1755, 1756, 1757, 1758, 1759,
|
||||
1760, 1761, 1762, 1764, 1785,
|
||||
};
|
||||
|
||||
internal static readonly ushort[] Pouch_Recipe_LA =
|
||||
{
|
||||
1640, 1641, 1642, 1643, 1644, 1646, 1647, 1648, 1649,
|
||||
1650, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659,
|
||||
1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669,
|
||||
1670, 1671, 1673, 1674, 1675, 1676, 1677,
|
||||
|
||||
1729,
|
||||
1730, 1731,
|
||||
|
||||
1751, 1752, 1753,
|
||||
|
||||
1783, 1784,
|
||||
};
|
||||
|
||||
internal static readonly ushort[] Pouch_Key_LA =
|
||||
{
|
||||
111,
|
||||
298, 299,
|
||||
300, 301, 302, 303, 304, 305, 306, 307, 308, 309,
|
||||
310, 311, 312, 313,
|
||||
441, 455, 466,
|
||||
632, 638, 644,
|
||||
1608, 1609, 1610, 1612, 1622, 1624, 1625, 1626, 1627, 1629,
|
||||
1639, 1678, 1721, 1722, 1723, 1737, 1743, 1744, 1745, 1763,
|
||||
1765, 1766, 1767, 1768, 1769, 1771, 1776, 1777, 1778, 1779,
|
||||
1780, 1782, 1786, 1787, 1788, 1789, 1790, 1792, 1793, 1794,
|
||||
1795, 1796, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1804,
|
||||
1805, 1806, 1807,
|
||||
1828,
|
||||
};
|
||||
|
||||
internal static readonly ushort[] HeldItems_LA = { 0 };
|
||||
|
||||
internal static readonly HashSet<int> HisuiOriginForms = new()
|
||||
{
|
||||
(int)Species.Sneasel,
|
||||
(int)Species.Growlithe,
|
||||
(int)Species.Arcanine,
|
||||
(int)Species.Voltorb,
|
||||
(int)Species.Electrode,
|
||||
(int)Species.Qwilfish,
|
||||
(int)Species.Sliggoo,
|
||||
(int)Species.Goodra,
|
||||
};
|
||||
|
||||
internal static readonly IReadOnlyDictionary<int, int> HisuiForm0Evolutions = new Dictionary<int, int>
|
||||
{
|
||||
{(int)Species.Sneasler, 1},
|
||||
};
|
||||
|
||||
internal static readonly HashSet<int> HisuiVariantFormEvolutions = new()
|
||||
{
|
||||
(int)Species.Decidueye,
|
||||
(int)Species.Typhlosion,
|
||||
(int)Species.Samurott,
|
||||
(int)Species.Lilligant,
|
||||
(int)Species.Braviary,
|
||||
(int)Species.Avalugg,
|
||||
};
|
||||
|
||||
#region Moves
|
||||
|
||||
internal static readonly int[] MoveShop8_LA =
|
||||
{
|
||||
(int)Move.FalseSwipe,
|
||||
(int)Move.FireFang,
|
||||
(int)Move.ThunderFang,
|
||||
(int)Move.IceFang,
|
||||
(int)Move.IceBall,
|
||||
(int)Move.RockSmash,
|
||||
(int)Move.Spikes,
|
||||
(int)Move.Bulldoze,
|
||||
(int)Move.AerialAce,
|
||||
(int)Move.StealthRock,
|
||||
(int)Move.Swift,
|
||||
(int)Move.TriAttack,
|
||||
(int)Move.MagicalLeaf,
|
||||
(int)Move.OminousWind,
|
||||
(int)Move.PowerShift,
|
||||
(int)Move.FocusEnergy,
|
||||
(int)Move.BulkUp,
|
||||
(int)Move.CalmMind,
|
||||
(int)Move.Rest,
|
||||
(int)Move.BabyDollEyes,
|
||||
(int)Move.FirePunch,
|
||||
(int)Move.ThunderPunch,
|
||||
(int)Move.IcePunch,
|
||||
(int)Move.DrainPunch,
|
||||
(int)Move.PoisonJab,
|
||||
(int)Move.PsychoCut,
|
||||
(int)Move.ZenHeadbutt,
|
||||
(int)Move.LeechLife,
|
||||
(int)Move.XScissor,
|
||||
(int)Move.RockSlide,
|
||||
(int)Move.ShadowClaw,
|
||||
(int)Move.IronHead,
|
||||
(int)Move.IronTail,
|
||||
(int)Move.MysticalFire,
|
||||
(int)Move.WaterPulse,
|
||||
(int)Move.ChargeBeam,
|
||||
(int)Move.EnergyBall,
|
||||
(int)Move.IcyWind,
|
||||
(int)Move.SludgeBomb,
|
||||
(int)Move.EarthPower,
|
||||
(int)Move.ShadowBall,
|
||||
(int)Move.Snarl,
|
||||
(int)Move.FlashCannon,
|
||||
(int)Move.DazzlingGleam,
|
||||
(int)Move.GigaImpact,
|
||||
(int)Move.AquaTail,
|
||||
(int)Move.WildCharge,
|
||||
(int)Move.HighHorsepower,
|
||||
(int)Move.Megahorn,
|
||||
(int)Move.StoneEdge,
|
||||
(int)Move.Outrage,
|
||||
(int)Move.PlayRough,
|
||||
(int)Move.HyperBeam,
|
||||
(int)Move.Flamethrower,
|
||||
(int)Move.Thunderbolt,
|
||||
(int)Move.IceBeam,
|
||||
(int)Move.Psychic,
|
||||
(int)Move.DarkPulse,
|
||||
(int)Move.DracoMeteor,
|
||||
(int)Move.SteelBeam,
|
||||
(int)Move.VoltTackle,
|
||||
};
|
||||
|
||||
internal static readonly byte[] MovePP_LA =
|
||||
{
|
||||
00,
|
||||
35, 25, 10, 15, 20, 20, 10, 10, 10, 35, 30, 05, 10, 20, 30, 25, 35, 20, 15, 20, 20, 25, 20, 30, 05, 10, 15, 15, 15, 25, 20, 05, 30, 15, 20, 20, 10, 05, 30, 20, 20, 20, 30, 20, 40, 20, 15, 20, 20, 20,
|
||||
30, 25, 10, 30, 25, 05, 15, 10, 05, 20, 20, 20, 05, 35, 20, 20, 20, 20, 20, 15, 20, 15, 10, 20, 25, 10, 20, 20, 20, 10, 40, 10, 15, 25, 10, 20, 05, 15, 10, 05, 10, 10, 20, 10, 20, 40, 30, 20, 20, 20,
|
||||
15, 10, 40, 15, 10, 30, 10, 20, 10, 40, 40, 20, 30, 30, 20, 20, 10, 10, 20, 05, 10, 30, 20, 20, 20, 05, 15, 15, 20, 10, 15, 35, 20, 15, 10, 10, 30, 15, 20, 20, 10, 10, 05, 10, 25, 10, 10, 20, 15, 40,
|
||||
20, 10, 05, 15, 10, 10, 10, 15, 30, 30, 10, 10, 15, 10, 01, 01, 10, 25, 10, 05, 15, 20, 15, 10, 15, 30, 05, 40, 15, 10, 25, 10, 20, 10, 20, 10, 10, 10, 20, 15, 20, 05, 40, 05, 05, 20, 05, 10, 05, 10,
|
||||
10, 10, 10, 20, 20, 30, 15, 10, 20, 20, 25, 05, 15, 10, 05, 20, 15, 20, 25, 20, 05, 30, 05, 05, 20, 40, 05, 20, 40, 20, 05, 35, 10, 05, 05, 05, 15, 05, 25, 05, 05, 10, 20, 10, 05, 15, 10, 10, 20, 15,
|
||||
10, 10, 10, 20, 10, 10, 10, 10, 15, 15, 15, 10, 20, 20, 10, 20, 20, 20, 20, 20, 10, 10, 10, 20, 20, 05, 15, 10, 10, 15, 10, 20, 05, 05, 10, 10, 20, 05, 10, 20, 10, 20, 20, 20, 05, 05, 15, 20, 10, 15,
|
||||
20, 15, 10, 10, 15, 10, 05, 05, 10, 25, 10, 05, 20, 15, 05, 40, 15, 15, 40, 15, 20, 20, 05, 15, 20, 15, 15, 15, 05, 10, 30, 20, 30, 20, 05, 40, 10, 05, 10, 05, 15, 25, 25, 05, 20, 15, 10, 10, 20, 10,
|
||||
20, 20, 05, 05, 10, 05, 40, 10, 10, 05, 10, 10, 15, 10, 20, 15, 30, 10, 20, 05, 10, 10, 15, 10, 10, 05, 15, 05, 10, 10, 30, 20, 20, 10, 10, 05, 05, 10, 05, 20, 10, 20, 10, 05, 10, 10, 20, 10, 10, 15,
|
||||
10, 15, 10, 10, 10, 10, 10, 10, 10, 30, 05, 10, 05, 10, 10, 05, 20, 20, 10, 20, 15, 15, 15, 15, 20, 15, 15, 10, 10, 10, 20, 15, 05, 05, 15, 15, 05, 10, 05, 15, 05, 10, 20, 05, 20, 20, 20, 20, 05, 20,
|
||||
15, 05, 20, 15, 10, 10, 05, 10, 05, 05, 10, 05, 05, 10, 05, 15, 05, 15, 10, 10, 10, 10, 10, 15, 15, 20, 15, 10, 15, 10, 15, 10, 20, 10, 10, 10, 20, 20, 20, 20, 20, 15, 15, 15, 15, 15, 15, 20, 15, 10,
|
||||
15, 15, 15, 15, 10, 15, 10, 10, 10, 15, 15, 15, 15, 05, 05, 15, 05, 10, 10, 10, 20, 20, 20, 10, 10, 30, 15, 10, 10, 15, 25, 10, 15, 10, 10, 10, 20, 10, 10, 10, 10, 05, 15, 15, 05, 05, 10, 10, 10, 05,
|
||||
05, 10, 05, 05, 15, 10, 05, 05, 05, 10, 10, 10, 10, 20, 25, 10, 20, 30, 25, 20, 20, 15, 20, 15, 20, 20, 15, 10, 10, 10, 10, 20, 10, 25, 10, 10, 10, 10, 20, 20, 05, 05, 05, 20, 10, 10, 20, 15, 20, 20,
|
||||
10, 20, 30, 10, 10, 40, 40, 20, 20, 40, 20, 20, 10, 10, 10, 10, 05, 10, 10, 05, 05, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01,
|
||||
01, 01, 01, 01, 01, 01, 01, 01, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 25, 15, 20, 30, 20, 15, 15, 20, 10, 15, 15, 10, 05, 10, 10, 20, 15, 10, 15, 15, 15, 05, 15, 20, 20, 01, 01, 01, 01, 01, 01,
|
||||
01, 01, 01, 05, 05, 10, 10, 10, 20, 10, 10, 10, 05, 05, 20, 10, 10, 10, 01, 05, 15, 05, 01, 01, 01, 01, 01, 01, 10, 15, 15, 20, 20, 20, 20, 15, 15, 10, 10, 05, 20, 05, 10, 05, 15, 10, 10, 05, 15, 20,
|
||||
10, 10, 15, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 05, 10, 15, 10, 15, 05, 05, 05, 10, 15, 40, 10, 10, 10, 15, 10, 10, 10, 10, 05, 05, 05, 10, 05, 20, 10,
|
||||
10, 05, 20, 20, 10, 10, 05, 05, 05, 40, 10, 20, 10, 10, 10, 10, 05, 05, 15, 05, 10, 10, 10, 05, 05, 35, 15, 10, 10, 15, 05, 10, 10, 10, 05, 05, 10, 05, 15, 10, 15, 10, 15, 15, 15, 05, 05, 05, 10, 10,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Moves that are kill
|
||||
/// </summary>
|
||||
public static readonly HashSet<int> DummiedMoves_LA = new()
|
||||
{
|
||||
001, 002, 003, 004, 005, 006, 010, 011, 012, 013,
|
||||
015, 017, 018, 019, 020, 021, 022, 023, 024, 025,
|
||||
026, 027, 028, 029, 030, 031, 032, 034, 035, 036,
|
||||
037, 039, 041, 043, 045, 046, 047, 048, 049, 050,
|
||||
051, 054, 055, 057, 060, 061, 062, 064, 065, 066,
|
||||
067, 068, 069, 070, 072, 073, 074, 075, 076, 081,
|
||||
082, 083, 088, 089, 090, 091, 092, 096, 097, 099,
|
||||
101, 103, 104, 106, 107, 108, 109, 110, 111, 112,
|
||||
113, 114, 115, 117, 118, 119, 121, 122, 123, 124,
|
||||
125, 127, 128, 130, 131, 132, 133, 134, 136, 137,
|
||||
138, 140, 142, 143, 144, 146, 148, 149, 152, 153,
|
||||
154, 155, 158, 159, 160, 162, 164, 166, 167, 168,
|
||||
169, 170, 171, 173, 174, 175, 176, 177, 178, 179,
|
||||
180, 182, 184, 185, 186, 187, 192, 193, 194, 195,
|
||||
197, 198, 199, 201, 202, 203, 204, 207, 208, 210,
|
||||
211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
|
||||
221, 222, 223, 225, 226, 227, 228, 229, 230, 232,
|
||||
233, 234, 235, 236, 238, 240, 241, 243, 244, 245,
|
||||
248, 250, 251, 252, 253, 254, 255, 256, 257, 258,
|
||||
259, 260, 261, 262, 263, 264, 265, 266, 267, 268,
|
||||
269, 270, 271, 272, 273, 274, 275, 276, 277, 278,
|
||||
279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
|
||||
289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
|
||||
299, 300, 302, 303, 304, 305, 306, 307, 308, 309,
|
||||
311, 312, 313, 316, 317, 319, 320, 321, 322, 323,
|
||||
324, 325, 327, 328, 329, 330, 331, 333, 335, 336,
|
||||
338, 340, 341, 342, 343, 346, 349, 350, 351, 353,
|
||||
354, 356, 357, 358, 359, 360, 361, 362, 363, 364,
|
||||
365, 366, 367, 368, 369, 371, 372, 373, 374, 375,
|
||||
376, 377, 378, 379, 380, 381, 382, 383, 384, 385,
|
||||
386, 387, 388, 389, 390, 391, 392, 393, 395, 397,
|
||||
402, 407, 410, 411, 415, 419, 429, 431, 432, 433,
|
||||
435, 436, 438, 439, 441, 443, 445, 447, 448, 450,
|
||||
454, 455, 456, 461, 468, 469, 470, 471, 472, 473,
|
||||
475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
|
||||
485, 486, 487, 488, 489, 490, 492, 493, 494, 495,
|
||||
496, 497, 498, 499, 500, 501, 502, 503, 504, 505,
|
||||
507, 508, 509, 510, 511, 512, 513, 514, 515, 516,
|
||||
517, 518, 519, 520, 521, 524, 525, 526, 527, 529,
|
||||
530, 531, 532, 533, 534, 535, 536, 537, 538, 539,
|
||||
540, 541, 543, 544, 545, 546, 547, 548, 549, 550,
|
||||
551, 552, 553, 554, 557, 558, 559, 560, 561, 562,
|
||||
563, 564, 565, 566, 567, 568, 569, 570, 571, 572,
|
||||
573, 574, 575, 576, 578, 579, 580, 581, 582, 586,
|
||||
587, 588, 589, 590, 591, 592, 593, 594, 596, 597,
|
||||
598, 599, 600, 601, 602, 603, 604, 606, 607, 609,
|
||||
610, 611, 612, 613, 614, 615, 616, 617, 618, 619,
|
||||
620, 621, 622, 623, 624, 625, 626, 627, 628, 629,
|
||||
630, 631, 632, 633, 634, 635, 636, 637, 638, 639,
|
||||
640, 641, 642, 643, 644, 645, 646, 647, 648, 649,
|
||||
650, 651, 652, 653, 654, 655, 656, 657, 658, 659,
|
||||
660, 661, 662, 663, 664, 665, 666, 668, 669, 671,
|
||||
672, 673, 674, 675, 676, 677, 678, 679, 680, 681,
|
||||
682, 683, 684, 685, 686, 687, 688, 689, 690, 691,
|
||||
692, 693, 694, 695, 696, 697, 698, 699, 700, 701,
|
||||
702, 703, 704, 705, 706, 707, 708, 709, 711, 712,
|
||||
713, 714, 715, 716, 717, 718, 719, 720, 721, 722,
|
||||
723, 724, 725, 726, 727, 728, 729, 730, 731, 732,
|
||||
733, 734, 735, 736, 737, 738, 739, 740, 741, 742,
|
||||
743, 744, 745, 746, 747, 748, 749, 750, 751, 752,
|
||||
753, 754, 755, 756, 757, 758, 759, 760, 761, 762,
|
||||
763, 764, 765, 766, 767, 768, 769, 770, 771, 772,
|
||||
773, 774, 775, 776, 777, 778, 779, 780, 781, 782,
|
||||
783, 784, 785, 786, 787, 788, 789, 790, 791, 792,
|
||||
793, 794, 795, 797, 798, 799, 800, 801, 802, 803,
|
||||
804, 805, 806, 807, 808, 809, 810, 811, 812, 813,
|
||||
814, 815, 816, 817, 818, 819, 820, 821, 822, 823,
|
||||
824, 825, 826,
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ private CheckResult VerifyAbility(LegalityAnalysis data)
|
||||
|
||||
if (format >= 8) // Ability Patch
|
||||
{
|
||||
if (pkm.AbilityNumber == 4)
|
||||
if (pkm.AbilityNumber == 4 && !pkm.LA)
|
||||
{
|
||||
if (CanAbilityPatch(format, abilities, pkm.Species))
|
||||
return GetValid(LAbilityPatchUsed);
|
||||
@@ -452,6 +452,8 @@ private static bool IsAbilityCapsuleModified(PKM pkm, IReadOnlyList<int> abiliti
|
||||
return false;
|
||||
if (pkm.AbilityNumber == 4)
|
||||
return false; // Cannot alter to hidden ability.
|
||||
if (pkm.LA)
|
||||
return false; // Not available.
|
||||
if (encounterAbility == AbilityPermission.OnlyHidden)
|
||||
return false; // Cannot alter from hidden ability.
|
||||
return true;
|
||||
@@ -481,6 +483,7 @@ public static bool CanAbilityPatch(int format, IReadOnlyList<int> abilities, int
|
||||
(int)Species.Tornadus => true, // Form-0 is a/a/h
|
||||
(int)Species.Thundurus => true, // Form-0 is a/a/h
|
||||
(int)Species.Landorus => true, // Form-0 is a/a/h
|
||||
(int)Species.Enamorus => true, // Form-0 is a/a/h
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ internal static class BallUseLegality
|
||||
6 => WildPokeballs6,
|
||||
7 => GameVersion.Gen7b.Contains(game) ? WildPokeballs7b : WildPokeballs7,
|
||||
8 when GameVersion.BDSP.Contains(game) => WildPokeBalls4_HGSS,
|
||||
8 when GameVersion.PLA == game => WildPokeBalls8a,
|
||||
8 => GameVersion.GO == game ? WildPokeballs8g : WildPokeballs8,
|
||||
_ => Array.Empty<int>(),
|
||||
};
|
||||
@@ -66,5 +67,20 @@ internal static class BallUseLegality
|
||||
(int)Sport,
|
||||
// no cherish ball
|
||||
};
|
||||
|
||||
private static readonly HashSet<int> WildPokeBalls8a = new()
|
||||
{
|
||||
(int)LAPoke,
|
||||
(int)LAGreat,
|
||||
(int)LAUltra,
|
||||
|
||||
(int)LAFeather,
|
||||
(int)LAWing,
|
||||
(int)LAJet,
|
||||
|
||||
(int)LAHeavy,
|
||||
(int)LALeaden,
|
||||
(int)LAGigaton,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,6 @@ private CheckResult VerifyForm(LegalityAnalysis data)
|
||||
if (!PersonalInfo.IsFormWithinRange(form) && !FormInfo.IsValidOutOfBoundsForm(species, form, Info.Generation))
|
||||
return GetInvalid(string.Format(LFormInvalidRange, count - 1, form));
|
||||
|
||||
switch (enc)
|
||||
{
|
||||
case EncounterEgg e when FormInfo.IsTotemForm(species, form, e.Generation):
|
||||
return GetInvalid(LFormInvalidGame);
|
||||
}
|
||||
|
||||
switch ((Species)species)
|
||||
{
|
||||
case Pikachu when Info.Generation == 6: // Cosplay
|
||||
@@ -72,6 +66,8 @@ private CheckResult VerifyForm(LegalityAnalysis data)
|
||||
break;
|
||||
case Unown when Info.Generation == 2 && form >= 26:
|
||||
return GetInvalid(string.Format(LFormInvalidRange, "Z", form == 26 ? "!" : "?"));
|
||||
case Dialga or Palkia or Giratina or Arceus when form > 0 && pkm.LA: // can change forms with key items
|
||||
break;
|
||||
case Giratina when form == 1 ^ pkm.HeldItem == 112: // Giratina, Origin form only with Griseous Orb
|
||||
return GetInvalid(LFormItemInvalid);
|
||||
|
||||
@@ -279,6 +275,57 @@ private CheckResult VerifyFormArgument(LegalityAnalysis data, IFormArgument f)
|
||||
> (uint) AlcremieDecoration.Ribbon => GetInvalid(LFormArgumentHigh),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
Overqwil when enc.Species == (int)Overqwil => arg switch
|
||||
{
|
||||
not 0 => GetInvalid(LFormArgumentNotAllowed),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
Wyrdeer when enc.Species == (int)Wyrdeer => arg switch
|
||||
{
|
||||
not 0 => GetInvalid(LFormArgumentNotAllowed),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
Basculegion when enc.Species == (int)Basculegion => arg switch
|
||||
{
|
||||
not 0 => GetInvalid(LFormArgumentNotAllowed),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
Basculin when pkm.Form is 2 => arg switch
|
||||
{
|
||||
not 0 when pkm.IsEgg => GetInvalid(LFormArgumentNotAllowed),
|
||||
> 9_999 => GetInvalid(LFormArgumentHigh),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
Qwilfish when pkm.Form is 1 => arg switch
|
||||
{
|
||||
not 0 when pkm.IsEgg => GetInvalid(LFormArgumentNotAllowed),
|
||||
> 9_999 => GetInvalid(LFormArgumentHigh),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
Stantler when pkm is PA8 => arg switch
|
||||
{
|
||||
not 0 when pkm.IsEgg => GetInvalid(LFormArgumentNotAllowed),
|
||||
> 9_999 => GetInvalid(LFormArgumentHigh),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
Wyrdeer => arg switch // From Stantler
|
||||
{
|
||||
< 20 => GetInvalid(LFormArgumentLow),
|
||||
> 9_999 => GetInvalid(LFormArgumentHigh),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
Overqwil => arg switch // From Qwilfish-1
|
||||
{
|
||||
< 20 => GetInvalid(LFormArgumentLow),
|
||||
> 9_999 => GetInvalid(LFormArgumentHigh),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
Basculegion => arg switch // From Basculin-2
|
||||
{
|
||||
< 294 => GetInvalid(LFormArgumentLow),
|
||||
> 9_999 => GetInvalid(LFormArgumentHigh),
|
||||
_ => GetValid(LFormArgumentValid),
|
||||
},
|
||||
_ => VerifyFormArgumentNone(pkm, f),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -187,6 +187,7 @@ public static bool GetCanOTHandle(IEncounterTemplate enc, PKM pkm, int generatio
|
||||
WC7 wc7 when wc7.OT_Name.Length > 0 && wc7.TID != 18075 => false, // Ash Pikachu QR Gift doesn't set Current Handler
|
||||
WC8 wc8 when wc8.GetHasOT(pkm.Language) => false,
|
||||
WB8 wb8 when wb8.GetHasOT(pkm.Language) => false,
|
||||
WA8 wa8 when wa8.GetHasOT(pkm.Language) => false,
|
||||
WC8 {IsHOMEGift: true} => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
@@ -18,6 +18,12 @@ public override void Verify(LegalityAnalysis data)
|
||||
if (!t.IsHyperTrained())
|
||||
return;
|
||||
|
||||
if (!t.IsHyperTrainingAvailable())
|
||||
{
|
||||
data.AddLine(GetInvalid(LHyperPerfectUnavailable));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pkm.CurrentLevel != 100)
|
||||
{
|
||||
data.AddLine(GetInvalid(LHyperBelow100));
|
||||
|
||||
238
PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs
Normal file
238
PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the stat details of data that has not yet left <see cref="GameVersion.PLA"/>.
|
||||
/// </summary>
|
||||
public sealed class LegendsArceusVerifier : Verifier
|
||||
{
|
||||
protected override CheckIdentifier Identifier => CheckIdentifier.RelearnMove;
|
||||
|
||||
public override void Verify(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.pkm;
|
||||
if (!pk.LA || pk is not PA8 pa)
|
||||
return;
|
||||
|
||||
CheckLearnset(data, pa);
|
||||
CheckMastery(data, pa);
|
||||
|
||||
if (pa.IsNoble)
|
||||
data.AddLine(GetInvalid(LStatNobleInvalid));
|
||||
if (pa.IsAlpha != data.EncounterMatch is IAlpha { IsAlpha: true })
|
||||
data.AddLine(GetInvalid(LStatAlphaInvalid));
|
||||
|
||||
CheckScalars(data, pa);
|
||||
}
|
||||
|
||||
private void CheckScalars(LegalityAnalysis data, PA8 pa)
|
||||
{
|
||||
// Static encounters hard-match the Height & Weight; only slots are unchecked for Alpha Height/Weight.
|
||||
if (pa.IsAlpha && data.EncounterMatch is EncounterSlot8a)
|
||||
{
|
||||
if (pa.HeightScalar != 255)
|
||||
data.AddLine(GetInvalid(LStatIncorrectHeightValue));
|
||||
if (pa.WeightScalar != 255)
|
||||
data.AddLine(GetInvalid(LStatIncorrectWeightValue));
|
||||
}
|
||||
|
||||
// No way to mutate the display height scalar value. Must match!
|
||||
if (pa.HeightScalar != pa.HeightScalarCopy)
|
||||
data.AddLine(GetInvalid(LStatIncorrectHeightCopy, CheckIdentifier.Encounter));
|
||||
}
|
||||
|
||||
private static void CheckLearnset(LegalityAnalysis data, PA8 pa)
|
||||
{
|
||||
var moveCount = GetMoveCount(pa);
|
||||
if (moveCount == 4)
|
||||
return;
|
||||
|
||||
// Get the bare minimum moveset.
|
||||
Span<int> expect = stackalloc int[4];
|
||||
var minMoveCount = LoadBareMinimumMoveset(data.EncounterMatch, data.Info.EvoChainsAllGens[8], pa, expect);
|
||||
|
||||
// Flag move slots that are empty.
|
||||
for (int i = moveCount; i < minMoveCount; i++)
|
||||
{
|
||||
// Expected move should never be empty, but just future-proof against any revisions.
|
||||
var msg = expect[i] != 0 ? string.Format(LMoveFExpect_0, ParseSettings.MoveStrings[expect[i]]) : LMoveSourceEmpty;
|
||||
data.Info.Moves[i] = new CheckMoveResult(data.Info.Moves[i], Severity.Invalid, msg, CheckIdentifier.CurrentMove);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the expected minimum count of moves, and modifies the input <see cref="moves"/> with the bare minimum move IDs.
|
||||
/// </summary>
|
||||
private static int LoadBareMinimumMoveset(ISpeciesForm enc, IReadOnlyList<EvoCriteria> evos, PA8 pa, Span<int> moves)
|
||||
{
|
||||
// Get any encounter moves
|
||||
var pt = PersonalTable.LA;
|
||||
var index = pt.GetFormIndex(enc.Species, enc.Form);
|
||||
var moveset = Legal.LevelUpLA[index];
|
||||
moveset.SetEncounterMoves(pa.Met_Level, moves);
|
||||
var count = moves.IndexOf(0);
|
||||
if ((uint)count >= 4)
|
||||
return 4;
|
||||
|
||||
// Level up to current level
|
||||
moveset.SetLevelUpMoves(pa.Met_Level, pa.CurrentLevel, moves, count);
|
||||
count = moves.IndexOf(0);
|
||||
if ((uint)count >= 4)
|
||||
return 4;
|
||||
|
||||
// Evolve and try
|
||||
for (int i = 0; i < evos.Count - 1; i++)
|
||||
{
|
||||
var (species, form) = evos[i];
|
||||
index = pt.GetFormIndex(species, form);
|
||||
moveset = Legal.LevelUpLA[index];
|
||||
moveset.SetEvolutionMoves(moves, count);
|
||||
count = moves.IndexOf(0);
|
||||
if ((uint)count >= 4)
|
||||
return 4;
|
||||
}
|
||||
|
||||
// Any tutored moves we don't know about??
|
||||
return AddMasteredMissing(pa, moves, count);
|
||||
}
|
||||
|
||||
private static int AddMasteredMissing(PA8 pa, Span<int> current, int ctr)
|
||||
{
|
||||
for (int i = 0; i < pa.MoveShopPermitIndexes.Length; i++)
|
||||
{
|
||||
// Buying the move tutor grants access, but does not learn the move.
|
||||
// Mastering requires the move to be present in the movepool.
|
||||
if (!pa.GetMasteredRecordFlag(i))
|
||||
continue;
|
||||
|
||||
// Purchased moves can be swapped with existing moves; we're only interested in special granted moves.
|
||||
if (pa.GetPurchasedRecordFlag(i))
|
||||
continue;
|
||||
|
||||
var move = pa.MoveShopPermitIndexes[i];
|
||||
if (current.IndexOf(move) == -1)
|
||||
current[ctr++] = move;
|
||||
if (ctr == 4)
|
||||
return 4;
|
||||
}
|
||||
return ctr;
|
||||
}
|
||||
|
||||
private static int GetMoveCount(PKM pa)
|
||||
{
|
||||
var count = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (pa.GetMove(i) is not 0)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void CheckMastery(LegalityAnalysis data, PA8 pa)
|
||||
{
|
||||
var bits = pa.MoveShopPermitFlags;
|
||||
var moves = pa.MoveShopPermitIndexes;
|
||||
var alphaMove = pa.AlphaMove;
|
||||
if (alphaMove is not 0)
|
||||
VerifyAlphaMove(data, pa, alphaMove, moves, bits);
|
||||
else
|
||||
VerifyAlphaMoveZero(data);
|
||||
|
||||
for (int i = 0; i < bits.Length; i++)
|
||||
VerifyTutorMoveIndex(data, pa, i, bits, moves);
|
||||
}
|
||||
|
||||
private void VerifyTutorMoveIndex(LegalityAnalysis data, PA8 pa, int i, ReadOnlySpan<bool> bits, ReadOnlySpan<int> moves)
|
||||
{
|
||||
bool isPurchased = pa.GetPurchasedRecordFlag(i);
|
||||
if (isPurchased)
|
||||
{
|
||||
// Check if the move can be purchased.
|
||||
if (bits[i])
|
||||
return; // If it has been legally purchased, then any mastery state is legal.
|
||||
|
||||
data.AddLine(GetInvalid(string.Format(LMoveShopPurchaseInvalid_0, ParseSettings.MoveStrings[moves[i]])));
|
||||
return;
|
||||
}
|
||||
|
||||
bool isMastered = pa.GetMasteredRecordFlag(i);
|
||||
if (!isMastered)
|
||||
return; // All good.
|
||||
|
||||
// Check if the move can be purchased; using a Mastery Seed checks the permission.
|
||||
if (pa.AlphaMove == moves[i])
|
||||
return; // Previously checked.
|
||||
if (data.EncounterMatch is IAlpha { IsAlpha: true } && CanMasterMoveFromMoveShop(moves[i], moves, bits))
|
||||
return; // Alpha forced move.
|
||||
if (!bits[i])
|
||||
data.AddLine(GetInvalid(string.Format(LMoveShopMasterInvalid_0, ParseSettings.MoveStrings[moves[i]])));
|
||||
else if (!CanLearnMoveByLevelUp(data, pa, i, moves))
|
||||
data.AddLine(GetInvalid(string.Format(LMoveShopMasterNotLearned_0, ParseSettings.MoveStrings[moves[i]])));
|
||||
}
|
||||
|
||||
private static bool CanLearnMoveByLevelUp(LegalityAnalysis data, PA8 pa, int i, ReadOnlySpan<int> moves)
|
||||
{
|
||||
// Check if the move can be learned in the learnset...
|
||||
// Changing forms do not have separate tutor permissions, so we don't need to bother with form changes.
|
||||
// Level up movepools can grant moves for mastery at lower levels for earlier evolutions... find the minimum.
|
||||
int level = 101;
|
||||
foreach (var (species, form) in data.Info.EvoChainsAllGens[8])
|
||||
{
|
||||
var pt = PersonalTable.LA;
|
||||
var index = pt.GetFormIndex(species, form);
|
||||
var moveset = Legal.LevelUpLA[index];
|
||||
var lvl = moveset.GetLevelLearnMove(moves[i]);
|
||||
if (lvl == -1)
|
||||
continue; // cannot learn via level up
|
||||
level = Math.Min(lvl, level);
|
||||
}
|
||||
return pa.CurrentLevel >= level;
|
||||
}
|
||||
|
||||
private void VerifyAlphaMove(LegalityAnalysis data, PA8 pa, int alphaMove, ReadOnlySpan<int> moves, ReadOnlySpan<bool> bits)
|
||||
{
|
||||
if (!pa.IsAlpha)
|
||||
{
|
||||
data.AddLine(GetInvalid(LMoveShopAlphaMoveShouldBeZero));
|
||||
return;
|
||||
}
|
||||
if (!CanMasterMoveFromMoveShop(alphaMove, moves, bits))
|
||||
{
|
||||
data.AddLine(GetInvalid(LMoveShopAlphaMoveShouldBeOther));
|
||||
return;
|
||||
}
|
||||
|
||||
// An Alpha Move must be marked as mastered.
|
||||
var masteredIndex = moves.IndexOf(alphaMove);
|
||||
// Index is already >= 0, implicitly via the above call not returning false.
|
||||
if (!pa.GetMasteredRecordFlag(masteredIndex))
|
||||
data.AddLine(GetInvalid(LMoveShopAlphaMoveShouldBeMastered));
|
||||
}
|
||||
|
||||
private void VerifyAlphaMoveZero(LegalityAnalysis data)
|
||||
{
|
||||
var enc = data.Info.EncounterMatch;
|
||||
if (enc is IAlpha { IsAlpha: false })
|
||||
return; // okay
|
||||
|
||||
var pi = PersonalTable.LA.GetFormEntry(enc.Species, enc.Form);
|
||||
var tutors = pi.SpecialTutors[0];
|
||||
bool hasAnyTutor = Array.IndexOf(tutors, true) >= 0;
|
||||
if (hasAnyTutor) // must have had a tutor flag
|
||||
data.AddLine(GetInvalid(LMoveShopAlphaMoveShouldBeOther));
|
||||
}
|
||||
|
||||
private static bool CanMasterMoveFromMoveShop(int move, ReadOnlySpan<int> moves, ReadOnlySpan<bool> bits)
|
||||
{
|
||||
var index = moves.IndexOf(move);
|
||||
if (index == -1)
|
||||
return false; // not in the list
|
||||
if (!bits[index])
|
||||
return false; // not a possible move
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,11 @@ public sealed class MemoryVerifier : Verifier
|
||||
|
||||
public override void Verify(LegalityAnalysis data)
|
||||
{
|
||||
if (data.pkm.BDSP)
|
||||
var pkm = data.pkm;
|
||||
if (pkm.BDSP || pkm.LA)
|
||||
{
|
||||
VerifyOTMemoryIs(data, 0, 0, 0, 0);
|
||||
VerifyHTMemoryNone(data, (ITrainerMemories)data.pkm);
|
||||
VerifyHTMemoryNone(data, (ITrainerMemories)pkm);
|
||||
return;
|
||||
}
|
||||
VerifyOTMemory(data);
|
||||
@@ -259,6 +260,7 @@ private static bool CanHaveMemoryForOT(PKM pkm, int origin, int memory)
|
||||
case 8 when pkm.GO_HOME: // HOME does not set memories.
|
||||
case 8 when pkm.Met_Location == Locations.HOME8: // HOME does not set memories.
|
||||
case 8 when pkm.BDSP: // BDSP does not set memories.
|
||||
case 8 when pkm.LA: // LA does not set memories.
|
||||
return false;
|
||||
|
||||
// Eggs cannot have memories
|
||||
|
||||
@@ -62,6 +62,9 @@ public override void Verify(LegalityAnalysis data)
|
||||
case PB8 pb8:
|
||||
VerifyBDSPStats(data, pb8);
|
||||
break;
|
||||
case PA8 pa8:
|
||||
VerifyPLAStats(data, pa8);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pkm.Format >= 6)
|
||||
@@ -113,8 +116,34 @@ public override void Verify(LegalityAnalysis data)
|
||||
}
|
||||
|
||||
VerifyMiscFatefulEncounter(data);
|
||||
VerifyMiscPokerus(data);
|
||||
}
|
||||
|
||||
private void VerifyMiscPokerus(LegalityAnalysis data)
|
||||
{
|
||||
var pkm = data.pkm;
|
||||
if (pkm.Format == 1)
|
||||
return;
|
||||
|
||||
var strain = pkm.PKRS_Strain;
|
||||
var days = pkm.PKRS_Days;
|
||||
bool strainValid = IsPokerusStrainValid(pkm, strain, days);
|
||||
if (!strainValid)
|
||||
data.AddLine(GetInvalid(string.Format(LPokerusStrainUnobtainable_0, strain)));
|
||||
|
||||
var expect = (strain % 4) + 1;
|
||||
if (days > expect)
|
||||
data.AddLine(GetInvalid(string.Format(LPokerusDaysTooHigh_0, expect)));
|
||||
}
|
||||
|
||||
private static bool IsPokerusStrainValid(PKM pkm, int strain, int days) => strain switch
|
||||
{
|
||||
0 when days is not 0 => false,
|
||||
8 => false,
|
||||
not 0 when pkm is PA8 => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
public void VerifyMiscG1(LegalityAnalysis data)
|
||||
{
|
||||
var pkm = data.pkm;
|
||||
@@ -246,6 +275,19 @@ private static void VerifyMiscFatefulEncounter(LegalityAnalysis data)
|
||||
private static void VerifyMiscMovePP(LegalityAnalysis data)
|
||||
{
|
||||
var pkm = data.pkm;
|
||||
|
||||
if (pkm is PA8) // No PP Ups
|
||||
{
|
||||
if (pkm.Move1_PPUps is not 0)
|
||||
data.AddLine(GetInvalid(string.Format(LMovePPUpsTooHigh_0, 1), CurrentMove));
|
||||
if (pkm.Move2_PPUps is not 0)
|
||||
data.AddLine(GetInvalid(string.Format(LMovePPUpsTooHigh_0, 2), CurrentMove));
|
||||
if (pkm.Move3_PPUps is not 0)
|
||||
data.AddLine(GetInvalid(string.Format(LMovePPUpsTooHigh_0, 3), CurrentMove));
|
||||
if (pkm.Move4_PPUps is not 0)
|
||||
data.AddLine(GetInvalid(string.Format(LMovePPUpsTooHigh_0, 4), CurrentMove));
|
||||
}
|
||||
|
||||
if (pkm.Move1_PP > pkm.GetMovePP(pkm.Move1, pkm.Move1_PPUps))
|
||||
data.AddLine(GetInvalid(string.Format(LMovePPTooHigh_0, 1), CurrentMove));
|
||||
if (pkm.Move2_PP > pkm.GetMovePP(pkm.Move2, pkm.Move2_PPUps))
|
||||
@@ -275,11 +317,11 @@ private static void VerifyMiscEggCommon(LegalityAnalysis data)
|
||||
data.AddLine(GetInvalid(msg, Egg));
|
||||
}
|
||||
|
||||
if (pkm is G8PKM pk8)
|
||||
if (pkm is ITechRecord8 pk8)
|
||||
{
|
||||
if (pk8.HasAnyMoveRecordFlag())
|
||||
if (pk8.GetMoveRecordFlagAny())
|
||||
data.AddLine(GetInvalid(LEggRelearnFlags, Egg));
|
||||
if (pk8.StatNature != pk8.Nature)
|
||||
if (pkm.StatNature != pkm.Nature)
|
||||
data.AddLine(GetInvalid(LEggNature, Egg));
|
||||
}
|
||||
}
|
||||
@@ -331,6 +373,7 @@ private static void VerifyReceivability(LegalityAnalysis data, MysteryGift g)
|
||||
case WC7 wc7 when !wc7.CanBeReceivedByVersion(pkm.Version) && !pkm.WasTradedEgg:
|
||||
case WC8 wc8 when !wc8.CanBeReceivedByVersion(pkm.Version):
|
||||
case WB8 wb8 when !wb8.CanBeReceivedByVersion(pkm.Version):
|
||||
case WA8 wa8 when !wa8.CanBeReceivedByVersion(pkm.Version):
|
||||
data.AddLine(GetInvalid(LEncGiftVersionNotDistributed, GameOrigin));
|
||||
return;
|
||||
case WC6 wc6 when wc6.RestrictLanguage != 0 && pkm.Language != wc6.RestrictLanguage:
|
||||
@@ -424,16 +467,21 @@ private static void VerifyFullness(LegalityAnalysis data, PKM pkm)
|
||||
|
||||
private static void VerifyBelugaStats(LegalityAnalysis data, PB7 pb7)
|
||||
{
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator -- THESE MUST MATCH EXACTLY
|
||||
if (!IsCloseEnough(pb7.HeightAbsolute, pb7.CalcHeightAbsolute))
|
||||
data.AddLine(GetInvalid(LStatIncorrectHeight, Encounter));
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator -- THESE MUST MATCH EXACTLY
|
||||
if (!IsCloseEnough(pb7.WeightAbsolute, pb7.CalcWeightAbsolute))
|
||||
data.AddLine(GetInvalid(LStatIncorrectWeight, Encounter));
|
||||
VerifyAbsoluteSizes(data, pb7);
|
||||
if (pb7.Stat_CP != pb7.CalcCP && !IsStarterLGPE(pb7))
|
||||
data.AddLine(GetInvalid(LStatIncorrectCP, Encounter));
|
||||
}
|
||||
|
||||
private static void VerifyAbsoluteSizes(LegalityAnalysis data, IScaledSizeValue obj)
|
||||
{
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator -- THESE MUST MATCH EXACTLY
|
||||
if (!IsCloseEnough(obj.HeightAbsolute, obj.CalcHeightAbsolute))
|
||||
data.AddLine(GetInvalid(LStatIncorrectHeight, Encounter));
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator -- THESE MUST MATCH EXACTLY
|
||||
if (!IsCloseEnough(obj.WeightAbsolute, obj.CalcWeightAbsolute))
|
||||
data.AddLine(GetInvalid(LStatIncorrectWeight, Encounter));
|
||||
}
|
||||
|
||||
private static bool IsCloseEnough(float a, float b)
|
||||
{
|
||||
// since we don't have access to SingleToInt32Bits on net46, just do a temp write-read.
|
||||
@@ -518,6 +566,40 @@ private void VerifySWSHStats(LegalityAnalysis data, PK8 pk8)
|
||||
data.AddLine(Get(LStatInvalidHeightWeight, ParseSettings.ZeroHeightWeight, Encounter));
|
||||
}
|
||||
|
||||
private void VerifyPLAStats(LegalityAnalysis data, PA8 pa8)
|
||||
{
|
||||
VerifyAbsoluteSizes(data, pa8);
|
||||
|
||||
if (pa8.Favorite)
|
||||
data.AddLine(GetInvalid(LFavoriteMarkingUnavailable, Encounter));
|
||||
|
||||
var affix = pa8.AffixedRibbon;
|
||||
if (affix != -1) // None
|
||||
data.AddLine(GetInvalid(string.Format(LRibbonMarkingAffixedF_0, affix)));
|
||||
|
||||
var social = pa8.Sociability;
|
||||
if (social != 0)
|
||||
data.AddLine(GetInvalid(LMemorySocialZero, Encounter));
|
||||
|
||||
VerifyStatNature(data, pa8);
|
||||
|
||||
var bv = pa8.BattleVersion;
|
||||
if (bv != 0)
|
||||
data.AddLine(GetInvalid(LStatBattleVersionInvalid));
|
||||
|
||||
if (pa8.CanGigantamax)
|
||||
data.AddLine(GetInvalid(LStatGigantamaxInvalid));
|
||||
|
||||
if (pa8.DynamaxLevel != 0)
|
||||
data.AddLine(GetInvalid(LStatDynamaxInvalid));
|
||||
|
||||
if (pa8.GetMoveRecordFlagAny() && !pa8.IsEgg) // already checked for eggs
|
||||
data.AddLine(GetInvalid(LEggRelearnFlags));
|
||||
|
||||
if (CheckHeightWeightOdds(data.EncounterMatch) && pa8.HeightScalar == 0 && pa8.WeightScalar == 0 && ParseSettings.ZeroHeightWeight != Severity.Valid)
|
||||
data.AddLine(Get(LStatInvalidHeightWeight, ParseSettings.ZeroHeightWeight, Encounter));
|
||||
}
|
||||
|
||||
private void VerifyBDSPStats(LegalityAnalysis data, PB8 pb8)
|
||||
{
|
||||
if (pb8.Favorite)
|
||||
@@ -543,7 +625,7 @@ private void VerifyBDSPStats(LegalityAnalysis data, PB8 pb8)
|
||||
if (pb8.DynamaxLevel != 0)
|
||||
data.AddLine(GetInvalid(LStatDynamaxInvalid));
|
||||
|
||||
if (pb8.HasAnyMoveRecordFlag() && !pb8.IsEgg) // already checked for eggs
|
||||
if (pb8.GetMoveRecordFlagAny() && !pb8.IsEgg) // already checked for eggs
|
||||
data.AddLine(GetInvalid(LEggRelearnFlags));
|
||||
|
||||
if (CheckHeightWeightOdds(data.EncounterMatch) && pb8.HeightScalar == 0 && pb8.WeightScalar == 0 && ParseSettings.ZeroHeightWeight != Severity.Valid)
|
||||
@@ -555,7 +637,7 @@ private static bool CheckHeightWeightOdds(IEncounterTemplate enc)
|
||||
if (enc.Generation < 8)
|
||||
return false;
|
||||
|
||||
if (GameVersion.BDSP.Contains(enc.Version))
|
||||
if (GameVersion.BDSP.Contains(enc.Version) || GameVersion.PLA == enc.Version)
|
||||
return true;
|
||||
|
||||
if (enc is WC8 { IsHOMEGift: true })
|
||||
|
||||
@@ -467,8 +467,8 @@ private static IEnumerable<RibbonResult> GetInvalidRibbons8Any(PKM pkm, IRibbonS
|
||||
yield return new RibbonResult(nameof(s8.RibbonTwinklingStar));
|
||||
}
|
||||
|
||||
// new ribbon likely from Legends: Arceus; inaccessible until then
|
||||
if (s8.RibbonPioneer)
|
||||
// received when capturing photos with Pokémon in the Photography Studio
|
||||
if (s8.RibbonPioneer && !pkm.LA)
|
||||
{
|
||||
yield return new RibbonResult(nameof(s8.RibbonPioneer));
|
||||
}
|
||||
|
||||
@@ -125,16 +125,21 @@ public void VerifyTransferLegalityG4(LegalityAnalysis data)
|
||||
public void VerifyTransferLegalityG8(LegalityAnalysis data)
|
||||
{
|
||||
var pkm = data.pkm;
|
||||
if (pkm is PA8 pa8)
|
||||
{
|
||||
VerifyTransferLegalityG8a(data, pa8);
|
||||
return;
|
||||
}
|
||||
if (pkm is PB8 pb8)
|
||||
{
|
||||
VerifyTransferLegalityG8(data, pb8);
|
||||
VerifyTransferLegalityG8b(data, pb8);
|
||||
return;
|
||||
}
|
||||
|
||||
// PK8
|
||||
int species = pkm.Species;
|
||||
var pi = (PersonalInfoSWSH)PersonalTable.SWSH.GetFormEntry(species, pkm.Form);
|
||||
if (!pi.IsPresentInGame || pkm.BDSP) // Can't transfer
|
||||
if (!pi.IsPresentInGame || pkm.BDSP || pkm.LA) // Can't transfer
|
||||
{
|
||||
data.AddLine(GetInvalid(LTransferBad));
|
||||
return;
|
||||
@@ -159,9 +164,20 @@ public void VerifyTransferLegalityG8(LegalityAnalysis data)
|
||||
VerifyHOMETracker(data, pkm);
|
||||
}
|
||||
}
|
||||
private void VerifyTransferLegalityG8a(LegalityAnalysis data, PA8 pk)
|
||||
{
|
||||
// Tracker value is set via Transfer across HOME.
|
||||
// No HOME access yet.
|
||||
if (pk is IHomeTrack { Tracker: not 0 })
|
||||
data.AddLine(GetInvalid(LTransferTrackerShouldBeZero));
|
||||
|
||||
var pi = (PersonalInfoLA)PersonalTable.LA.GetFormEntry(pk.Species, pk.Form);
|
||||
if (!pi.IsPresentInGame || !pk.LA) // Can't transfer
|
||||
data.AddLine(GetInvalid(LTransferBad));
|
||||
}
|
||||
|
||||
// bdsp logic
|
||||
private void VerifyTransferLegalityG8(LegalityAnalysis data, PB8 pk)
|
||||
private void VerifyTransferLegalityG8b(LegalityAnalysis data, PB8 pk)
|
||||
{
|
||||
// Tracker value is set via Transfer across HOME.
|
||||
// No HOME access yet.
|
||||
|
||||
@@ -17,7 +17,7 @@ public abstract class MysteryGift : IEncounterable, IMoveset, IRelearn
|
||||
/// <returns>A boolean indicating whether or not the given length is valid for a mystery gift.</returns>
|
||||
public static bool IsMysteryGift(long len) => Sizes.Contains((int)len);
|
||||
|
||||
private static readonly HashSet<int> Sizes = new() { WB8.Size, WC8.Size, WC6Full.Size, WC6.Size, PGF.Size, PGT.Size, PCD.Size };
|
||||
private static readonly HashSet<int> Sizes = new() { WA8.Size, WB8.Size, WC8.Size, WC6Full.Size, WC6.Size, PGF.Size, PGT.Size, PCD.Size };
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given data to a <see cref="MysteryGift"/>.
|
||||
@@ -37,6 +37,7 @@ public abstract class MysteryGift : IEncounterable, IMoveset, IRelearn
|
||||
WR7.Size when ext == ".wr7" => new WR7(data),
|
||||
WC8.Size when ext is ".wc8" or ".wc8full" => new WC8(data),
|
||||
WB8.Size when ext is ".wb8" => new WB8(data),
|
||||
WA8.Size when ext is ".wa8" => new WA8(data),
|
||||
|
||||
WB7.SizeFull when ext == ".wb7full" => new WB7(data),
|
||||
WC6Full.Size when ext == ".wc6full" => new WC6Full(data).Gift,
|
||||
@@ -57,6 +58,7 @@ public abstract class MysteryGift : IEncounterable, IMoveset, IRelearn
|
||||
WR7.Size => new WR7(data),
|
||||
WC8.Size => new WC8(data),
|
||||
WB8.Size => new WB8(data),
|
||||
WA8.Size => new WA8(data),
|
||||
|
||||
// WC6/WC7: Check year
|
||||
WC6.Size => ReadUInt32LittleEndian(data.AsSpan(0x4C)) / 10000 < 2000 ? new WC7(data) : new WC6(data),
|
||||
|
||||
773
PKHeX.Core/MysteryGifts/WA8.cs
Normal file
773
PKHeX.Core/MysteryGifts/WA8.cs
Normal file
@@ -0,0 +1,773 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.RibbonIndex;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Generation 8 Mystery Gift Template File, same as <see cref="WC8"/> with <see cref="IGanbaru"/> fields at the end.
|
||||
/// </summary>
|
||||
public sealed class WA8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDynamaxLevel, IRibbonIndex, IMemoryOT, ILangNicknamedTemplate, IGanbaru,
|
||||
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8
|
||||
{
|
||||
public const int Size = 0x2C8;
|
||||
|
||||
public override int Generation => 8;
|
||||
|
||||
public enum GiftType : byte
|
||||
{
|
||||
None = 0,
|
||||
Pokemon = 1,
|
||||
Item = 2,
|
||||
}
|
||||
|
||||
public WA8() : this(new byte[Size]) { }
|
||||
public WA8(byte[] data) : base(data) { }
|
||||
|
||||
public bool CanBeReceivedByVersion(int v) => v is (int) GameVersion.PLA;
|
||||
|
||||
// General Card Properties
|
||||
public override int CardID
|
||||
{
|
||||
get => ReadUInt16LittleEndian(Data.AsSpan(0x8));
|
||||
set => WriteUInt16LittleEndian(Data.AsSpan(0x8), (ushort)value);
|
||||
}
|
||||
|
||||
public byte CardFlags { get => Data[0x10]; set => Data[0x10] = value; }
|
||||
public GiftType CardType { get => (GiftType)Data[0x11]; set => Data[0x11] = (byte)value; }
|
||||
public bool GiftRepeatable { get => (CardFlags & 1) == 0; set => CardFlags = (byte)((CardFlags & ~1) | (value ? 0 : 1)); }
|
||||
public override bool GiftUsed { get => false; set { } }
|
||||
|
||||
public int CardTitleIndex
|
||||
{
|
||||
get => Data[0x13];
|
||||
set => Data[0x13] = (byte) value;
|
||||
}
|
||||
|
||||
public override string CardTitle
|
||||
{
|
||||
get => "Mystery Gift"; // TODO: Use text string from CardTitleIndex
|
||||
set => throw new Exception();
|
||||
}
|
||||
|
||||
// Item Properties
|
||||
public override bool IsItem { get => CardType == GiftType.Item; set { if (value) CardType = GiftType.Item; } }
|
||||
|
||||
public override int ItemID
|
||||
{
|
||||
get => GetItem(0);
|
||||
set => SetItem(0, (ushort)value);
|
||||
}
|
||||
|
||||
public override int Quantity
|
||||
{
|
||||
get => GetQuantity(0);
|
||||
set => SetQuantity(0, (ushort)value);
|
||||
}
|
||||
|
||||
public int GetItem(int index) => ReadUInt16LittleEndian(Data.AsSpan(0x18 + (0x4 * index)));
|
||||
public void SetItem(int index, ushort item) => WriteUInt16LittleEndian(Data.AsSpan(0x18 + (4 * index)), item);
|
||||
public int GetQuantity(int index) => ReadUInt16LittleEndian(Data.AsSpan(0x1A + (0x4 * index)));
|
||||
public void SetQuantity(int index, ushort quantity) => WriteUInt16LittleEndian(Data.AsSpan(0x1A + (4 * index)), quantity);
|
||||
|
||||
// Pokémon Properties
|
||||
public override bool IsPokémon { get => CardType == GiftType.Pokemon; set { if (value) CardType = GiftType.Pokemon; } }
|
||||
|
||||
public override bool IsShiny => Shiny.IsShiny();
|
||||
|
||||
public override Shiny Shiny
|
||||
{
|
||||
get
|
||||
{
|
||||
var type = PIDType;
|
||||
if (type is not Shiny.FixedValue)
|
||||
return type;
|
||||
return GetShinyXor() switch
|
||||
{
|
||||
0 => Shiny.AlwaysSquare,
|
||||
<= 15 => Shiny.AlwaysStar,
|
||||
_ => Shiny.Never,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private int GetShinyXor()
|
||||
{
|
||||
// Player owned anti-shiny fixed PID
|
||||
if (TID == 0 && SID == 0)
|
||||
return int.MaxValue;
|
||||
|
||||
var pid = PID;
|
||||
var psv = (int)(pid >> 16 ^ (pid & 0xFFFF));
|
||||
var tsv = (TID ^ SID);
|
||||
return psv ^ tsv;
|
||||
}
|
||||
|
||||
public override int TID
|
||||
{
|
||||
get => ReadUInt16LittleEndian(Data.AsSpan(0x18));
|
||||
set => WriteUInt16LittleEndian(Data.AsSpan(0x18), (ushort)value);
|
||||
}
|
||||
|
||||
public override int SID {
|
||||
get => ReadUInt16LittleEndian(Data.AsSpan(0x1A));
|
||||
set => WriteUInt16LittleEndian(Data.AsSpan(0x1A), (ushort)value);
|
||||
}
|
||||
|
||||
public int OriginGame
|
||||
{
|
||||
get => ReadInt32LittleEndian(Data.AsSpan(0x1C));
|
||||
set => WriteInt32LittleEndian(Data.AsSpan(0x1C), value);
|
||||
}
|
||||
|
||||
public uint EncryptionConstant
|
||||
{
|
||||
get => ReadUInt32LittleEndian(Data.AsSpan(0x20));
|
||||
set => WriteUInt32LittleEndian(Data.AsSpan(0x20), value);
|
||||
}
|
||||
|
||||
public uint PID
|
||||
{
|
||||
get => ReadUInt32LittleEndian(Data.AsSpan(0x24));
|
||||
set => WriteUInt32LittleEndian(Data.AsSpan(0x24), value);
|
||||
}
|
||||
|
||||
// Nicknames, OT Names 0x30 - 0x228
|
||||
public override int EggLocation { get => ReadUInt16LittleEndian(Data.AsSpan(0x220)); set => WriteUInt16LittleEndian(Data.AsSpan(0x220), (ushort)value); }
|
||||
public int MetLocation { get => ReadUInt16LittleEndian(Data.AsSpan(0x222)); set => WriteUInt16LittleEndian(Data.AsSpan(0x222), (ushort)value); }
|
||||
|
||||
public override int Ball
|
||||
{
|
||||
get => ReadUInt16LittleEndian(Data.AsSpan(0x224));
|
||||
set => WriteUInt16LittleEndian(Data.AsSpan(0x224), (ushort)value);
|
||||
}
|
||||
|
||||
public override int HeldItem
|
||||
{
|
||||
get => ReadUInt16LittleEndian(Data.AsSpan(0x226));
|
||||
set => WriteUInt16LittleEndian(Data.AsSpan(0x226), (ushort)value);
|
||||
}
|
||||
|
||||
public int Move1 { get => ReadUInt16LittleEndian(Data.AsSpan(0x228)); set => WriteUInt16LittleEndian(Data.AsSpan(0x228), (ushort)value); }
|
||||
public int Move2 { get => ReadUInt16LittleEndian(Data.AsSpan(0x22A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x22A), (ushort)value); }
|
||||
public int Move3 { get => ReadUInt16LittleEndian(Data.AsSpan(0x22C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x22C), (ushort)value); }
|
||||
public int Move4 { get => ReadUInt16LittleEndian(Data.AsSpan(0x22E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x22E), (ushort)value); }
|
||||
public int RelearnMove1 { get => ReadUInt16LittleEndian(Data.AsSpan(0x230)); set => WriteUInt16LittleEndian(Data.AsSpan(0x230), (ushort)value); }
|
||||
public int RelearnMove2 { get => ReadUInt16LittleEndian(Data.AsSpan(0x232)); set => WriteUInt16LittleEndian(Data.AsSpan(0x232), (ushort)value); }
|
||||
public int RelearnMove3 { get => ReadUInt16LittleEndian(Data.AsSpan(0x234)); set => WriteUInt16LittleEndian(Data.AsSpan(0x234), (ushort)value); }
|
||||
public int RelearnMove4 { get => ReadUInt16LittleEndian(Data.AsSpan(0x236)); set => WriteUInt16LittleEndian(Data.AsSpan(0x236), (ushort)value); }
|
||||
|
||||
public override int Species { get => ReadUInt16LittleEndian(Data.AsSpan(0x238)); set => WriteUInt16LittleEndian(Data.AsSpan(0x238), (ushort)value); }
|
||||
public override int Form { get => Data[0x23A]; set => Data[0x23A] = (byte)value; }
|
||||
public override int Gender { get => Data[0x23B]; set => Data[0x23B] = (byte)value; }
|
||||
public override int Level { get => Data[0x23C]; set => Data[0x23C] = (byte)value; }
|
||||
public override bool IsEgg { get => Data[0x23D] == 1; set => Data[0x23D] = value ? (byte)1 : (byte)0; }
|
||||
public int Nature { get => (sbyte)Data[0x23E]; set => Data[0x23E] = (byte)value; }
|
||||
public override int AbilityType { get => Data[0x23F]; set => Data[0x23F] = (byte)value; }
|
||||
|
||||
private byte PIDTypeValue => Data[0x240];
|
||||
|
||||
public Shiny PIDType => PIDTypeValue switch
|
||||
{
|
||||
0 => Shiny.Never,
|
||||
1 => Shiny.Random,
|
||||
2 => Shiny.AlwaysStar,
|
||||
3 => Shiny.AlwaysSquare,
|
||||
4 => Shiny.FixedValue,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(PIDType)),
|
||||
};
|
||||
|
||||
public int MetLevel { get => Data[0x241]; set => Data[0x241] = (byte)value; }
|
||||
public byte DynamaxLevel { get => Data[0x242]; set => Data[0x242] = value; }
|
||||
public bool CanGigantamax { get => Data[0x243] != 0; set => Data[0x243] = value ? (byte)1 : (byte)0; }
|
||||
|
||||
// Ribbons 0x24C-0x26C
|
||||
private const int RibbonBytesOffset = 0x244;
|
||||
private const int RibbonBytesCount = 0x20;
|
||||
private const int RibbonByteNone = 0xFF; // signed -1
|
||||
|
||||
public bool HasMark()
|
||||
{
|
||||
for (int i = 0; i < RibbonBytesCount; i++)
|
||||
{
|
||||
var value = Data[RibbonBytesOffset + i];
|
||||
if (value == RibbonByteNone)
|
||||
return false;
|
||||
if ((RibbonIndex)value is >= MarkLunchtime and <= MarkSlump)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public byte GetRibbonAtIndex(int byteIndex)
|
||||
{
|
||||
if ((uint)byteIndex >= RibbonBytesCount)
|
||||
throw new IndexOutOfRangeException();
|
||||
return Data[RibbonBytesOffset + byteIndex];
|
||||
}
|
||||
|
||||
public void SetRibbonAtIndex(int byteIndex, byte ribbonIndex)
|
||||
{
|
||||
if ((uint)byteIndex >= RibbonBytesCount)
|
||||
throw new IndexOutOfRangeException();
|
||||
Data[RibbonBytesOffset + byteIndex] = ribbonIndex;
|
||||
}
|
||||
|
||||
public int IV_HP { get => Data[0x264]; set => Data[0x264] = (byte)value; }
|
||||
public int IV_ATK { get => Data[0x265]; set => Data[0x265] = (byte)value; }
|
||||
public int IV_DEF { get => Data[0x266]; set => Data[0x266] = (byte)value; }
|
||||
public int IV_SPE { get => Data[0x267]; set => Data[0x267] = (byte)value; }
|
||||
public int IV_SPA { get => Data[0x268]; set => Data[0x268] = (byte)value; }
|
||||
public int IV_SPD { get => Data[0x269]; set => Data[0x269] = (byte)value; }
|
||||
|
||||
public int OTGender { get => Data[0x26A]; set => Data[0x26A] = (byte)value; }
|
||||
|
||||
public int EV_HP { get => Data[0x26B]; set => Data[0x26B] = (byte)value; }
|
||||
public int EV_ATK { get => Data[0x26C]; set => Data[0x26C] = (byte)value; }
|
||||
public int EV_DEF { get => Data[0x26D]; set => Data[0x26D] = (byte)value; }
|
||||
public int EV_SPE { get => Data[0x26E]; set => Data[0x26E] = (byte)value; }
|
||||
public int EV_SPA { get => Data[0x26F]; set => Data[0x26F] = (byte)value; }
|
||||
public int EV_SPD { get => Data[0x270]; set => Data[0x270] = (byte)value; }
|
||||
|
||||
public int OT_Intensity { get => Data[0x271]; set => Data[0x271] = (byte)value; }
|
||||
public int OT_Memory { get => Data[0x272]; set => Data[0x272] = (byte)value; }
|
||||
public int OT_Feeling { get => Data[0x273]; set => Data[0x273] = (byte)value; }
|
||||
public int OT_TextVar { get => ReadUInt16LittleEndian(Data.AsSpan(0x274)); set => WriteUInt16LittleEndian(Data.AsSpan(0x274), (ushort)value); }
|
||||
|
||||
// Only derivations to WC8
|
||||
public int GV_HP { get => Data[0x27E]; set => Data[0x27E] = (byte)value; }
|
||||
public int GV_ATK { get => Data[0x27F]; set => Data[0x27F] = (byte)value; }
|
||||
public int GV_DEF { get => Data[0x280]; set => Data[0x280] = (byte)value; }
|
||||
public int GV_SPE { get => Data[0x281]; set => Data[0x281] = (byte)value; }
|
||||
public int GV_SPA { get => Data[0x282]; set => Data[0x282] = (byte)value; }
|
||||
public int GV_SPD { get => Data[0x283]; set => Data[0x283] = (byte)value; }
|
||||
|
||||
// Meta Accessible Properties
|
||||
public override int[] IVs
|
||||
{
|
||||
get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD };
|
||||
set
|
||||
{
|
||||
if (value.Length != 6) return;
|
||||
IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2];
|
||||
IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5];
|
||||
}
|
||||
}
|
||||
|
||||
public int[] EVs
|
||||
{
|
||||
get => new[] { EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD };
|
||||
set
|
||||
{
|
||||
if (value.Length != 6) return;
|
||||
EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2];
|
||||
EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5];
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetIsNicknamed(int language) => ReadUInt16LittleEndian(Data.AsSpan(GetNicknameOffset(language))) != 0;
|
||||
|
||||
public bool CanBeAnyLanguage()
|
||||
{
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
var ofs = GetLanguageOffset(i);
|
||||
var lang = ReadInt16LittleEndian(Data.AsSpan(ofs));
|
||||
if (lang != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanHaveLanguage(int language)
|
||||
{
|
||||
if (language is < (int)LanguageID.Japanese or > (int)LanguageID.ChineseT)
|
||||
return false;
|
||||
|
||||
if (CanBeAnyLanguage())
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
var ofs = GetLanguageOffset(i);
|
||||
var lang = ReadInt16LittleEndian(Data.AsSpan(ofs));
|
||||
if (lang == language)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetLanguage(int redeemLanguage) => Data[GetLanguageOffset(GetLanguageIndex(redeemLanguage))];
|
||||
private static int GetLanguageOffset(int index) => 0x28 + (index * 0x1C) + 0x1A;
|
||||
|
||||
public bool GetHasOT(int language) => ReadUInt16LittleEndian(Data.AsSpan(GetOTOffset(language))) != 0;
|
||||
|
||||
private static int GetLanguageIndex(int language)
|
||||
{
|
||||
var lang = (LanguageID) language;
|
||||
if (lang is < LanguageID.Japanese or LanguageID.UNUSED_6 or > LanguageID.ChineseT)
|
||||
return (int) LanguageID.English; // fallback
|
||||
return lang < LanguageID.UNUSED_6 ? language - 1 : language - 2;
|
||||
}
|
||||
|
||||
public override int Location { get => MetLocation; set => MetLocation = (ushort)value; }
|
||||
|
||||
public override IReadOnlyList<int> Moves
|
||||
{
|
||||
get => new[] { Move1, Move2, Move3, Move4 };
|
||||
set
|
||||
{
|
||||
if (value.Count > 0) Move1 = value[0];
|
||||
if (value.Count > 1) Move2 = value[1];
|
||||
if (value.Count > 2) Move3 = value[2];
|
||||
if (value.Count > 3) Move4 = value[3];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Relearn
|
||||
{
|
||||
get => new[] { RelearnMove1, RelearnMove2, RelearnMove3, RelearnMove4 };
|
||||
set
|
||||
{
|
||||
if (value.Count > 0) RelearnMove1 = value[0];
|
||||
if (value.Count > 1) RelearnMove2 = value[1];
|
||||
if (value.Count > 2) RelearnMove3 = value[2];
|
||||
if (value.Count > 3) RelearnMove4 = value[3];
|
||||
}
|
||||
}
|
||||
|
||||
public override string OT_Name { get; set; } = string.Empty;
|
||||
public string Nickname => string.Empty;
|
||||
public bool IsNicknamed => false;
|
||||
public int Language => 2;
|
||||
|
||||
public string GetNickname(int language) => StringConverter8.GetString(Data.AsSpan(GetNicknameOffset(language), 0x1A));
|
||||
public void SetNickname(int language, string value) => StringConverter8.SetString(Data.AsSpan(GetNicknameOffset(language), 0x1A), value.AsSpan(), 12, StringConverterOption.ClearZero);
|
||||
|
||||
public string GetOT(int language) => StringConverter8.GetString(Data.AsSpan(GetOTOffset(language), 0x1A));
|
||||
public void SetOT(int language, string value) => StringConverter8.SetString(Data.AsSpan(GetOTOffset(language), 0x1A), value.AsSpan(), 12, StringConverterOption.ClearZero);
|
||||
|
||||
private static int GetNicknameOffset(int language)
|
||||
{
|
||||
int index = GetLanguageIndex(language);
|
||||
return 0x28 + (index * 0x1C);
|
||||
}
|
||||
|
||||
private static int GetOTOffset(int language)
|
||||
{
|
||||
int index = GetLanguageIndex(language);
|
||||
return 0x124 + (index * 0x1C);
|
||||
}
|
||||
|
||||
public bool CanHandleOT(int language) => !GetHasOT(language);
|
||||
|
||||
public override GameVersion Version
|
||||
{
|
||||
get => OriginGame != 0 ? (GameVersion)OriginGame : GameVersion.PLA;
|
||||
set { }
|
||||
}
|
||||
|
||||
public override PKM ConvertToPKM(ITrainerInfo sav, EncounterCriteria criteria)
|
||||
{
|
||||
if (!IsPokémon)
|
||||
throw new ArgumentException(nameof(IsPokémon));
|
||||
|
||||
int currentLevel = Level > 0 ? Level : (1 + Util.Rand.Next(100));
|
||||
int metLevel = MetLevel > 0 ? MetLevel : currentLevel;
|
||||
var pi = PersonalTable.LA.GetFormEntry(Species, Form);
|
||||
var language = sav.Language;
|
||||
var OT = GetOT(language);
|
||||
bool hasOT = GetHasOT(language);
|
||||
|
||||
var pk = new PA8
|
||||
{
|
||||
EncryptionConstant = EncryptionConstant != 0 ? EncryptionConstant : Util.Rand32(),
|
||||
TID = TID,
|
||||
SID = SID,
|
||||
Species = Species,
|
||||
Form = Form,
|
||||
CurrentLevel = currentLevel,
|
||||
Ball = Ball != 0 ? Ball : 4, // Default is Pokeball
|
||||
Met_Level = metLevel,
|
||||
HeldItem = HeldItem,
|
||||
|
||||
EXP = Experience.GetEXP(currentLevel, pi.EXPGrowth),
|
||||
|
||||
Move1 = Move1,
|
||||
Move2 = Move2,
|
||||
Move3 = Move3,
|
||||
Move4 = Move4,
|
||||
RelearnMove1 = RelearnMove1,
|
||||
RelearnMove2 = RelearnMove2,
|
||||
RelearnMove3 = RelearnMove3,
|
||||
RelearnMove4 = RelearnMove4,
|
||||
|
||||
Version = OriginGame != 0 ? OriginGame : sav.Game,
|
||||
|
||||
OT_Name = OT.Length > 0 ? OT : sav.OT,
|
||||
OT_Gender = OTGender < 2 ? OTGender : sav.Gender,
|
||||
HT_Name = hasOT ? sav.OT : string.Empty,
|
||||
HT_Gender = hasOT ? sav.Gender : 0,
|
||||
HT_Language = hasOT ? language : 0,
|
||||
CurrentHandler = hasOT ? 1 : 0,
|
||||
OT_Friendship = pi.BaseFriendship,
|
||||
|
||||
OT_Intensity = OT_Intensity,
|
||||
OT_Memory = OT_Memory,
|
||||
OT_TextVar = OT_TextVar,
|
||||
OT_Feeling = OT_Feeling,
|
||||
FatefulEncounter = true,
|
||||
|
||||
EVs = EVs,
|
||||
|
||||
CanGigantamax = CanGigantamax,
|
||||
DynamaxLevel = DynamaxLevel,
|
||||
|
||||
Met_Location = MetLocation,
|
||||
Egg_Location = EggLocation,
|
||||
};
|
||||
pk.SetMaximumPPCurrent();
|
||||
|
||||
if ((sav.Generation > Generation && OriginGame == 0) || !CanBeReceivedByVersion(pk.Version))
|
||||
pk.Version = (int)GameVersion.PLA;
|
||||
|
||||
if (OTGender >= 2)
|
||||
{
|
||||
pk.TID = sav.TID;
|
||||
pk.SID = sav.SID;
|
||||
}
|
||||
|
||||
// Official code explicitly corrects for Meowstic
|
||||
if (pk.Species == (int)Core.Species.Meowstic)
|
||||
pk.Form = pk.Gender;
|
||||
|
||||
pk.MetDate = DateTime.Now;
|
||||
|
||||
var nickname_language = GetLanguage(language);
|
||||
pk.Language = nickname_language != 0 ? nickname_language : sav.Language;
|
||||
pk.IsNicknamed = GetIsNicknamed(language);
|
||||
pk.Nickname = pk.IsNicknamed ? GetNickname(language) : SpeciesName.GetSpeciesNameGeneration(Species, pk.Language, Generation);
|
||||
|
||||
for (var i = 0; i < RibbonBytesCount; i++)
|
||||
{
|
||||
var ribbon = GetRibbonAtIndex(i);
|
||||
if (ribbon != RibbonByteNone)
|
||||
pk.SetRibbon(ribbon);
|
||||
}
|
||||
|
||||
SetPINGA(pk, criteria);
|
||||
|
||||
if (IsEgg)
|
||||
SetEggMetData(pk);
|
||||
pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship;
|
||||
|
||||
{
|
||||
pk.HeightScalar = PokeSizeUtil.GetRandomScalar();
|
||||
pk.WeightScalar = PokeSizeUtil.GetRandomScalar();
|
||||
pk.HeightScalarCopy = pk.HeightScalar;
|
||||
pk.ResetHeight();
|
||||
pk.ResetWeight();
|
||||
}
|
||||
|
||||
pk.ResetPartyStats();
|
||||
pk.RefreshChecksum();
|
||||
return pk;
|
||||
}
|
||||
|
||||
private void SetEggMetData(PKM pk)
|
||||
{
|
||||
pk.IsEgg = true;
|
||||
pk.EggMetDate = DateTime.Now;
|
||||
pk.Nickname = SpeciesName.GetSpeciesNameGeneration(0, pk.Language, Generation);
|
||||
pk.IsNicknamed = true;
|
||||
}
|
||||
|
||||
private void SetPINGA(PKM pk, EncounterCriteria criteria)
|
||||
{
|
||||
var pi = PersonalTable.LA.GetFormEntry(Species, Form);
|
||||
pk.Nature = (int)criteria.GetNature(Nature == -1 ? Core.Nature.Random : (Nature)Nature);
|
||||
pk.StatNature = pk.Nature;
|
||||
pk.Gender = criteria.GetGender(Gender, pi);
|
||||
var av = GetAbilityIndex(criteria);
|
||||
pk.RefreshAbility(av);
|
||||
SetPID(pk);
|
||||
SetIVs(pk);
|
||||
}
|
||||
|
||||
private int GetAbilityIndex(EncounterCriteria criteria) => AbilityType switch
|
||||
{
|
||||
00 or 01 or 02 => AbilityType, // Fixed 0/1/2
|
||||
03 or 04 => criteria.GetAbilityFromNumber(Ability), // 0/1 or 0/1/H
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(AbilityType)),
|
||||
};
|
||||
|
||||
public override AbilityPermission Ability => AbilityType switch
|
||||
{
|
||||
0 => AbilityPermission.OnlyFirst,
|
||||
1 => AbilityPermission.OnlySecond,
|
||||
2 => AbilityPermission.OnlyHidden,
|
||||
3 => AbilityPermission.Any12,
|
||||
_ => AbilityPermission.Any12H,
|
||||
};
|
||||
|
||||
private uint GetPID(ITrainerID tr, byte type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
0 => GetAntishiny(tr), // Random, Never Shiny
|
||||
1 => Util.Rand32(), // Random, Any
|
||||
2 => (uint) (((tr.TID ^ tr.SID ^ (PID & 0xFFFF) ^ 1) << 16) | (PID & 0xFFFF)), // Fixed, Force Star
|
||||
3 => (uint) (((tr.TID ^ tr.SID ^ (PID & 0xFFFF) ^ 0) << 16) | (PID & 0xFFFF)), // Fixed, Force Square
|
||||
4 => PID, // Fixed, Force Value
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type)),
|
||||
};
|
||||
|
||||
static uint GetAntishiny(ITrainerID tr)
|
||||
{
|
||||
var pid = Util.Rand32();
|
||||
if (tr.IsShiny(pid, 8))
|
||||
return pid ^ 0x1000_0000;
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPID(PKM pk)
|
||||
{
|
||||
pk.PID = GetPID(pk, PIDTypeValue);
|
||||
}
|
||||
|
||||
private void SetIVs(PKM pk)
|
||||
{
|
||||
Span<int> finalIVs = stackalloc int[6];
|
||||
var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3);
|
||||
var rng = Util.Rand;
|
||||
if (ivflag == 0) // Random IVs
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
finalIVs[i] = IVs[i] > 31 ? rng.Next(32) : IVs[i];
|
||||
}
|
||||
else // 1/2/3 perfect IVs
|
||||
{
|
||||
int IVCount = ivflag - 0xFB;
|
||||
do { finalIVs[rng.Next(6)] = 31; }
|
||||
while (finalIVs.Count(31) < IVCount);
|
||||
for (int i = 0; i < 6; i++)
|
||||
finalIVs[i] = finalIVs[i] == 31 ? 31 : rng.Next(32);
|
||||
}
|
||||
pk.SetIVs(finalIVs);
|
||||
}
|
||||
|
||||
public override bool IsMatchExact(PKM pkm, DexLevel evo)
|
||||
{
|
||||
if (pkm.Egg_Location == 0) // Not Egg
|
||||
{
|
||||
if (OTGender < 2)
|
||||
{
|
||||
if (SID != pkm.SID) return false;
|
||||
if (TID != pkm.TID) return false;
|
||||
if (OTGender != pkm.OT_Gender) return false;
|
||||
}
|
||||
|
||||
if (!CanBeAnyLanguage() && !CanHaveLanguage(pkm.Language))
|
||||
return false;
|
||||
|
||||
var OT = GetOT(pkm.Language); // May not be guaranteed to work.
|
||||
if (!string.IsNullOrEmpty(OT) && OT != pkm.OT_Name) return false;
|
||||
if (OriginGame != 0 && OriginGame != pkm.Version) return false;
|
||||
if (EncryptionConstant != 0)
|
||||
{
|
||||
if (EncryptionConstant != pkm.EncryptionConstant)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Form != evo.Form && !FormInfo.IsFormChangeable(Species, Form, pkm.Form, pkm.Format))
|
||||
return false;
|
||||
|
||||
if (IsEgg)
|
||||
{
|
||||
if (EggLocation != pkm.Egg_Location) // traded
|
||||
{
|
||||
if (pkm.Egg_Location != Locations.LinkTrade6)
|
||||
return false;
|
||||
if (PIDType == Shiny.Random && pkm.IsShiny && pkm.ShinyXor > 1)
|
||||
return false; // shiny traded egg will always have xor0/1.
|
||||
}
|
||||
if (!PIDType.IsValid(pkm))
|
||||
{
|
||||
return false; // can't be traded away for unshiny
|
||||
}
|
||||
|
||||
if (pkm.IsEgg && !pkm.IsNative)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!PIDType.IsValid(pkm)) return false;
|
||||
if (EggLocation != pkm.Egg_Location) return false;
|
||||
if (MetLocation != pkm.Met_Location) return false;
|
||||
}
|
||||
|
||||
if (MetLevel != 0 && MetLevel != pkm.Met_Level) return false;
|
||||
if (OTGender < 2 && OTGender != pkm.OT_Gender) return false;
|
||||
if (Nature != -1 && pkm.Nature != Nature) return false;
|
||||
if (Gender != 3 && Gender != pkm.Gender) return false;
|
||||
|
||||
const int poke = (int)Core.Ball.LAPoke;
|
||||
var expectedBall = (Ball == 0 ? poke : Ball);
|
||||
if (expectedBall < poke) // Not even Cherish balls are safe! They get set to the proto-Poké ball.
|
||||
expectedBall = poke;
|
||||
if (expectedBall != pkm.Ball)
|
||||
return false;
|
||||
|
||||
if (pkm is IGigantamax g && g.CanGigantamax != CanGigantamax && !g.CanToggleGigantamax(pkm.Species, pkm.Form, Species, Form))
|
||||
return false;
|
||||
|
||||
if (pkm is not IDynamaxLevel dl || dl.DynamaxLevel < DynamaxLevel)
|
||||
return false;
|
||||
|
||||
// PID Types 0 and 1 do not use the fixed PID value.
|
||||
// Values 2,3 are specific shiny states, and 4 is fixed value.
|
||||
// 2,3,4 can change if it is a traded egg to ensure the same shiny state.
|
||||
var type = PIDTypeValue;
|
||||
if (type <= 1)
|
||||
return true;
|
||||
return pkm.PID == GetPID(pkm, type);
|
||||
}
|
||||
|
||||
protected override bool IsMatchDeferred(PKM pkm) => Species != pkm.Species;
|
||||
protected override bool IsMatchPartial(PKM pkm) => false; // no version compatibility checks yet.
|
||||
|
||||
#region Lazy Ribbon Implementation
|
||||
public bool RibbonEarth { get => this.GetRibbonIndex(Earth); set => this.SetRibbonIndex(Earth, value); }
|
||||
public bool RibbonNational { get => this.GetRibbonIndex(National); set => this.SetRibbonIndex(National, value); }
|
||||
public bool RibbonCountry { get => this.GetRibbonIndex(Country); set => this.SetRibbonIndex(Country, value); }
|
||||
public bool RibbonChampionBattle { get => this.GetRibbonIndex(ChampionBattle); set => this.SetRibbonIndex(ChampionBattle, value); }
|
||||
public bool RibbonChampionRegional { get => this.GetRibbonIndex(ChampionRegional); set => this.SetRibbonIndex(ChampionRegional, value); }
|
||||
public bool RibbonChampionNational { get => this.GetRibbonIndex(ChampionNational); set => this.SetRibbonIndex(ChampionNational, value); }
|
||||
public bool RibbonClassic { get => this.GetRibbonIndex(Classic); set => this.SetRibbonIndex(Classic, value); }
|
||||
public bool RibbonWishing { get => this.GetRibbonIndex(Wishing); set => this.SetRibbonIndex(Wishing, value); }
|
||||
public bool RibbonPremier { get => this.GetRibbonIndex(Premier); set => this.SetRibbonIndex(Premier, value); }
|
||||
public bool RibbonEvent { get => this.GetRibbonIndex(Event); set => this.SetRibbonIndex(Event, value); }
|
||||
public bool RibbonBirthday { get => this.GetRibbonIndex(Birthday); set => this.SetRibbonIndex(Birthday, value); }
|
||||
public bool RibbonSpecial { get => this.GetRibbonIndex(Special); set => this.SetRibbonIndex(Special, value); }
|
||||
public bool RibbonWorld { get => this.GetRibbonIndex(World); set => this.SetRibbonIndex(World, value); }
|
||||
public bool RibbonChampionWorld { get => this.GetRibbonIndex(ChampionWorld); set => this.SetRibbonIndex(ChampionWorld, value); }
|
||||
public bool RibbonSouvenir { get => this.GetRibbonIndex(Souvenir); set => this.SetRibbonIndex(Souvenir, value); }
|
||||
public bool RibbonChampionG3 { get => this.GetRibbonIndex(ChampionG3); set => this.SetRibbonIndex(ChampionG3, value); }
|
||||
public bool RibbonArtist { get => this.GetRibbonIndex(Artist); set => this.SetRibbonIndex(Artist, value); }
|
||||
public bool RibbonEffort { get => this.GetRibbonIndex(Effort); set => this.SetRibbonIndex(Effort, value); }
|
||||
public bool RibbonChampionSinnoh { get => this.GetRibbonIndex(ChampionSinnoh); set => this.SetRibbonIndex(ChampionSinnoh, value); }
|
||||
public bool RibbonAlert { get => this.GetRibbonIndex(Alert); set => this.SetRibbonIndex(Alert, value); }
|
||||
public bool RibbonShock { get => this.GetRibbonIndex(Shock); set => this.SetRibbonIndex(Shock, value); }
|
||||
public bool RibbonDowncast { get => this.GetRibbonIndex(Downcast); set => this.SetRibbonIndex(Downcast, value); }
|
||||
public bool RibbonCareless { get => this.GetRibbonIndex(Careless); set => this.SetRibbonIndex(Careless, value); }
|
||||
public bool RibbonRelax { get => this.GetRibbonIndex(Relax); set => this.SetRibbonIndex(Relax, value); }
|
||||
public bool RibbonSnooze { get => this.GetRibbonIndex(Snooze); set => this.SetRibbonIndex(Snooze, value); }
|
||||
public bool RibbonSmile { get => this.GetRibbonIndex(Smile); set => this.SetRibbonIndex(Smile, value); }
|
||||
public bool RibbonGorgeous { get => this.GetRibbonIndex(Gorgeous); set => this.SetRibbonIndex(Gorgeous, value); }
|
||||
public bool RibbonRoyal { get => this.GetRibbonIndex(Royal); set => this.SetRibbonIndex(Royal, value); }
|
||||
public bool RibbonGorgeousRoyal { get => this.GetRibbonIndex(GorgeousRoyal); set => this.SetRibbonIndex(GorgeousRoyal, value); }
|
||||
public bool RibbonFootprint { get => this.GetRibbonIndex(Footprint); set => this.SetRibbonIndex(Footprint, value); }
|
||||
public bool RibbonRecord { get => this.GetRibbonIndex(Record); set => this.SetRibbonIndex(Record, value); }
|
||||
public bool RibbonLegend { get => this.GetRibbonIndex(Legend); set => this.SetRibbonIndex(Legend, value); }
|
||||
public bool RibbonChampionKalos { get => this.GetRibbonIndex(ChampionKalos); set => this.SetRibbonIndex(ChampionKalos, value); }
|
||||
public bool RibbonChampionG6Hoenn { get => this.GetRibbonIndex(ChampionG6Hoenn); set => this.SetRibbonIndex(ChampionG6Hoenn, value); }
|
||||
public bool RibbonBestFriends { get => this.GetRibbonIndex(BestFriends); set => this.SetRibbonIndex(BestFriends, value); }
|
||||
public bool RibbonTraining { get => this.GetRibbonIndex(Training); set => this.SetRibbonIndex(Training, value); }
|
||||
public bool RibbonBattlerSkillful { get => this.GetRibbonIndex(BattlerSkillful); set => this.SetRibbonIndex(BattlerSkillful, value); }
|
||||
public bool RibbonBattlerExpert { get => this.GetRibbonIndex(BattlerExpert); set => this.SetRibbonIndex(BattlerExpert, value); }
|
||||
public bool RibbonContestStar { get => this.GetRibbonIndex(ContestStar); set => this.SetRibbonIndex(ContestStar, value); }
|
||||
public bool RibbonMasterCoolness { get => this.GetRibbonIndex(MasterCoolness); set => this.SetRibbonIndex(MasterCoolness, value); }
|
||||
public bool RibbonMasterBeauty { get => this.GetRibbonIndex(MasterBeauty); set => this.SetRibbonIndex(MasterBeauty, value); }
|
||||
public bool RibbonMasterCuteness { get => this.GetRibbonIndex(MasterCuteness); set => this.SetRibbonIndex(MasterCuteness, value); }
|
||||
public bool RibbonMasterCleverness { get => this.GetRibbonIndex(MasterCleverness); set => this.SetRibbonIndex(MasterCleverness, value); }
|
||||
public bool RibbonMasterToughness { get => this.GetRibbonIndex(MasterToughness); set => this.SetRibbonIndex(MasterToughness, value); }
|
||||
|
||||
public int RibbonCountMemoryContest { get => 0; set { } }
|
||||
public int RibbonCountMemoryBattle { get => 0; set { } }
|
||||
|
||||
public bool RibbonChampionAlola { get => this.GetRibbonIndex(ChampionAlola); set => this.SetRibbonIndex(ChampionAlola, value); }
|
||||
public bool RibbonBattleRoyale { get => this.GetRibbonIndex(BattleRoyale); set => this.SetRibbonIndex(BattleRoyale, value); }
|
||||
public bool RibbonBattleTreeGreat { get => this.GetRibbonIndex(BattleTreeGreat); set => this.SetRibbonIndex(BattleTreeGreat, value); }
|
||||
public bool RibbonBattleTreeMaster { get => this.GetRibbonIndex(BattleTreeMaster); set => this.SetRibbonIndex(BattleTreeMaster, value); }
|
||||
public bool RibbonChampionGalar { get => this.GetRibbonIndex(ChampionGalar); set => this.SetRibbonIndex(ChampionGalar, value); }
|
||||
public bool RibbonTowerMaster { get => this.GetRibbonIndex(TowerMaster); set => this.SetRibbonIndex(TowerMaster, value); }
|
||||
public bool RibbonMasterRank { get => this.GetRibbonIndex(MasterRank); set => this.SetRibbonIndex(MasterRank, value); }
|
||||
public bool RibbonMarkLunchtime { get => this.GetRibbonIndex(MarkLunchtime); set => this.SetRibbonIndex(MarkLunchtime, value); }
|
||||
public bool RibbonMarkSleepyTime { get => this.GetRibbonIndex(MarkSleepyTime); set => this.SetRibbonIndex(MarkSleepyTime, value); }
|
||||
public bool RibbonMarkDusk { get => this.GetRibbonIndex(MarkDusk); set => this.SetRibbonIndex(MarkDusk, value); }
|
||||
public bool RibbonMarkDawn { get => this.GetRibbonIndex(MarkDawn); set => this.SetRibbonIndex(MarkDawn, value); }
|
||||
public bool RibbonMarkCloudy { get => this.GetRibbonIndex(MarkCloudy); set => this.SetRibbonIndex(MarkCloudy, value); }
|
||||
public bool RibbonMarkRainy { get => this.GetRibbonIndex(MarkRainy); set => this.SetRibbonIndex(MarkRainy, value); }
|
||||
public bool RibbonMarkStormy { get => this.GetRibbonIndex(MarkStormy); set => this.SetRibbonIndex(MarkStormy, value); }
|
||||
public bool RibbonMarkSnowy { get => this.GetRibbonIndex(MarkSnowy); set => this.SetRibbonIndex(MarkSnowy, value); }
|
||||
public bool RibbonMarkBlizzard { get => this.GetRibbonIndex(MarkBlizzard); set => this.SetRibbonIndex(MarkBlizzard, value); }
|
||||
public bool RibbonMarkDry { get => this.GetRibbonIndex(MarkDry); set => this.SetRibbonIndex(MarkDry, value); }
|
||||
public bool RibbonMarkSandstorm { get => this.GetRibbonIndex(MarkSandstorm); set => this.SetRibbonIndex(MarkSandstorm, value); }
|
||||
public bool RibbonMarkMisty { get => this.GetRibbonIndex(MarkMisty); set => this.SetRibbonIndex(MarkMisty, value); }
|
||||
public bool RibbonMarkDestiny { get => this.GetRibbonIndex(MarkDestiny); set => this.SetRibbonIndex(MarkDestiny, value); }
|
||||
public bool RibbonMarkFishing { get => this.GetRibbonIndex(MarkFishing); set => this.SetRibbonIndex(MarkFishing, value); }
|
||||
public bool RibbonMarkCurry { get => this.GetRibbonIndex(MarkCurry); set => this.SetRibbonIndex(MarkCurry, value); }
|
||||
public bool RibbonMarkUncommon { get => this.GetRibbonIndex(MarkUncommon); set => this.SetRibbonIndex(MarkUncommon, value); }
|
||||
public bool RibbonMarkRare { get => this.GetRibbonIndex(MarkRare); set => this.SetRibbonIndex(MarkRare, value); }
|
||||
public bool RibbonMarkRowdy { get => this.GetRibbonIndex(MarkRowdy); set => this.SetRibbonIndex(MarkRowdy, value); }
|
||||
public bool RibbonMarkAbsentMinded { get => this.GetRibbonIndex(MarkAbsentMinded); set => this.SetRibbonIndex(MarkAbsentMinded, value); }
|
||||
public bool RibbonMarkJittery { get => this.GetRibbonIndex(MarkJittery); set => this.SetRibbonIndex(MarkJittery, value); }
|
||||
public bool RibbonMarkExcited { get => this.GetRibbonIndex(MarkExcited); set => this.SetRibbonIndex(MarkExcited, value); }
|
||||
public bool RibbonMarkCharismatic { get => this.GetRibbonIndex(MarkCharismatic); set => this.SetRibbonIndex(MarkCharismatic, value); }
|
||||
public bool RibbonMarkCalmness { get => this.GetRibbonIndex(MarkCalmness); set => this.SetRibbonIndex(MarkCalmness, value); }
|
||||
public bool RibbonMarkIntense { get => this.GetRibbonIndex(MarkIntense); set => this.SetRibbonIndex(MarkIntense, value); }
|
||||
public bool RibbonMarkZonedOut { get => this.GetRibbonIndex(MarkZonedOut); set => this.SetRibbonIndex(MarkZonedOut, value); }
|
||||
public bool RibbonMarkJoyful { get => this.GetRibbonIndex(MarkJoyful); set => this.SetRibbonIndex(MarkJoyful, value); }
|
||||
public bool RibbonMarkAngry { get => this.GetRibbonIndex(MarkAngry); set => this.SetRibbonIndex(MarkAngry, value); }
|
||||
public bool RibbonMarkSmiley { get => this.GetRibbonIndex(MarkSmiley); set => this.SetRibbonIndex(MarkSmiley, value); }
|
||||
public bool RibbonMarkTeary { get => this.GetRibbonIndex(MarkTeary); set => this.SetRibbonIndex(MarkTeary, value); }
|
||||
public bool RibbonMarkUpbeat { get => this.GetRibbonIndex(MarkUpbeat); set => this.SetRibbonIndex(MarkUpbeat, value); }
|
||||
public bool RibbonMarkPeeved { get => this.GetRibbonIndex(MarkPeeved); set => this.SetRibbonIndex(MarkPeeved, value); }
|
||||
public bool RibbonMarkIntellectual { get => this.GetRibbonIndex(MarkIntellectual); set => this.SetRibbonIndex(MarkIntellectual, value); }
|
||||
public bool RibbonMarkFerocious { get => this.GetRibbonIndex(MarkFerocious); set => this.SetRibbonIndex(MarkFerocious, value); }
|
||||
public bool RibbonMarkCrafty { get => this.GetRibbonIndex(MarkCrafty); set => this.SetRibbonIndex(MarkCrafty, value); }
|
||||
public bool RibbonMarkScowling { get => this.GetRibbonIndex(MarkScowling); set => this.SetRibbonIndex(MarkScowling, value); }
|
||||
public bool RibbonMarkKindly { get => this.GetRibbonIndex(MarkKindly); set => this.SetRibbonIndex(MarkKindly, value); }
|
||||
public bool RibbonMarkFlustered { get => this.GetRibbonIndex(MarkFlustered); set => this.SetRibbonIndex(MarkFlustered, value); }
|
||||
public bool RibbonMarkPumpedUp { get => this.GetRibbonIndex(MarkPumpedUp); set => this.SetRibbonIndex(MarkPumpedUp, value); }
|
||||
public bool RibbonMarkZeroEnergy { get => this.GetRibbonIndex(MarkZeroEnergy); set => this.SetRibbonIndex(MarkZeroEnergy, value); }
|
||||
public bool RibbonMarkPrideful { get => this.GetRibbonIndex(MarkPrideful); set => this.SetRibbonIndex(MarkPrideful, value); }
|
||||
public bool RibbonMarkUnsure { get => this.GetRibbonIndex(MarkUnsure); set => this.SetRibbonIndex(MarkUnsure, value); }
|
||||
public bool RibbonMarkHumble { get => this.GetRibbonIndex(MarkHumble); set => this.SetRibbonIndex(MarkHumble, value); }
|
||||
public bool RibbonMarkThorny { get => this.GetRibbonIndex(MarkThorny); set => this.SetRibbonIndex(MarkThorny, value); }
|
||||
public bool RibbonMarkVigor { get => this.GetRibbonIndex(MarkVigor); set => this.SetRibbonIndex(MarkVigor, value); }
|
||||
public bool RibbonMarkSlump { get => this.GetRibbonIndex(MarkSlump); set => this.SetRibbonIndex(MarkSlump, value); }
|
||||
public bool RibbonTwinklingStar { get => this.GetRibbonIndex(TwinklingStar); set => this.SetRibbonIndex(TwinklingStar, value); }
|
||||
public bool RibbonPioneer { get => this.GetRibbonIndex(Pioneer); set => this.SetRibbonIndex(Pioneer, value); }
|
||||
|
||||
public int GetRibbonByte(int index) => Array.FindIndex(Data, RibbonBytesOffset, RibbonBytesCount, z => z == index);
|
||||
public bool GetRibbon(int index) => GetRibbonByte(index) >= 0;
|
||||
|
||||
public void SetRibbon(int index, bool value = true)
|
||||
{
|
||||
if ((uint)index > (uint)MarkSlump)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
if (value)
|
||||
{
|
||||
if (GetRibbon(index))
|
||||
return;
|
||||
var openIndex = Array.FindIndex(Data, RibbonBytesOffset, RibbonBytesCount, z => z != RibbonByteNone);
|
||||
if (openIndex < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
SetRibbonAtIndex(openIndex, (byte)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ofs = GetRibbonByte(index);
|
||||
if (ofs < 0)
|
||||
return;
|
||||
SetRibbonAtIndex(ofs, RibbonByteNone);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user