Add Gen1/2=>7 VC pp table & check bypass

ty anubis, santacrab, and Bowarcky for testing & data aggregation

Co-Authored-By: Lusamine <30205550+Lusamine@users.noreply.github.com>
Co-Authored-By: santacrab2 <79347566+santacrab2@users.noreply.github.com>
Co-Authored-By: Bowarcky <54773567+bowarcky@users.noreply.github.com>
This commit is contained in:
Kurt
2026-06-27 17:40:32 -05:00
parent 69ab4e3391
commit 25e3c4d352
34 changed files with 319 additions and 13 deletions

View File

@@ -295,6 +295,7 @@ public sealed class LegalityCheckLocalization
public string MoveEvoFCombination_0 { get; init; } = "Moves combinations is not compatible with {0} evolution.";
public string MoveFExpectSingle_0 { get; init; } = "Expected: {0}";
public string MoveKeldeoMismatch { get; init; } = "Keldeo Move/Form mismatch.";
public string MovePPMatchesVirtualConsole { get; init; } = "Move PP exactly matches values from the 3DS Virtual Console transfer bug.";
public string MovePPExpectHealed_01 { get; init; } = "Move {0} PP is below the amount expected ({1}).";
public string MovePPTooHigh_01 { get; init; } = "Move {0} PP is above the amount allowed ({1}).";
public string MovePPUpsTooHigh_01 { get; init; } = "Move {0} PP Ups is above the amount allowed ({1}).";

View File

@@ -173,6 +173,7 @@ public static class LegalityCheckResultCodeExtensions
MarkValueUnusedBitsPresent => localization.MarkValueUnusedBitsPresent,
// Moves
MovePPMatchesVirtualConsole => localization.MovePPMatchesVirtualConsole,
MoveEvoFCombination_0 => localization.MoveEvoFCombination_0,
MovePPExpectHealed_01 => localization.MovePPExpectHealed_01,
MovePPTooHigh_01 => localization.MovePPTooHigh_01,

View File

@@ -254,6 +254,7 @@ public enum LegalityCheckResultCode : ushort
// Moves - General
MoveKeldeoMismatch,
MovesShouldMatchRelearnMoves,
MovePPMatchesVirtualConsole,
// Moves - Shop & Alpha
MoveShopAlphaMoveShouldBeOther,

View File

@@ -67,12 +67,18 @@ private void VerifyEntity(LegalityAnalysis data)
}
}
// Sometimes the PP count will exceed (such as VC=>Bank); rather than flag it as invalid, add a tag indicating it is an untouched VC transfer.
// Gen7 3DS VC: Bad values are valid only if they never move it from the box. Could be more restrictive with disallowing other attributes, alas.
if (pk is PK7 { VC: true } pk7 && data.IsStoredSlot(StorageSlotType.Box) && IsVirtualConsoleUntouched(pk7, moves, pp))
{
data.AddLine(GetValid(MovePPMatchesVirtualConsole));
return; // Don't check further; we've verified all values match.
}
var allowedStates = GetPermittedStatePP(data, pk);
for (int i = 0; i < pp.Length; i++)
{
// Sometimes the PP count will exceed (such as VC=>Bank); just flag it as invalid so the user knows they need to heal them.
// Technically that case is legal (game bug) only if they never move it from the box, but we want to inform the user.
var healed = pk.GetMovePP(moves[i], ups[i]);
var value = pp[i];
if (value > healed)
@@ -157,6 +163,30 @@ private static MoveHealState HasLeftBoxAfterAcquisition(PKM pk, IEncounterTempla
return pk.MetLevel != current ? OnlyHealed : Any;
return !enc.IsLevelWithinRange(current) ? OnlyHealed : Any;
}
private static bool IsVirtualConsoleUntouched(PK7 pk, ReadOnlySpan<ushort> moves, ReadOnlySpan<int> pp)
{
// Sanity check the language is a possible VC-transfer language.
var language = (LanguageID)pk.Language;
if (!VirtualConsolePP.IsSupportedLanguage(language))
return false;
// Pre-check to ensure the moves are only available from the game they were transferred from.
// Can't leave the box immediately after transfer (else PP would heal), but we don't prevent the Move Verifier from passing Gen3+ moves.
// Maybe in a future update we can add more strict interlocks.
if (pk.VC1)
{
if (!VirtualConsolePP.IsPossibleVC1(moves))
return false; // GSC+ moves
}
else // VC2
{
if (!VirtualConsolePP.IsPossibleVC2(moves))
return false; // RSE+ moves
}
return VirtualConsolePP.IsMatch(language, moves, pp);
}
}
[Flags]

View File

@@ -0,0 +1,98 @@
using System;
using static PKHeX.Core.LanguageID;
namespace PKHeX.Core;
/// <summary>
/// Transfers from Gen1/2=>Gen7 don't set PP correctly (ignoring PP Ups and bad range fetch).
/// This class contains the expected PP values for each move in each language, as well as methods to check if a given set of moves and PP values match the expected values.
/// </summary>
public static class VirtualConsolePP
{
// Skip move IDs 0-109, no need to duplicate them since we have the valid table elsewhere.
private const byte MoveFirst = 110; // Withdraw
private static ReadOnlySpan<byte> TableENG => [000, 000, 109, 000, 000, 165, 255, 000, 000, 017, 023, 047, 213, 201, 207, 232, 236, 037, 070, 205, 100, 118, 211, 238, 006, 016, 089, 086, 172, 032, 151, 000, 089, 000, 022, 000, 023, 000, 024, 000, 025, 000, 025, 000, 026, 000, 027, 000, 027, 000, 028, 000, 029, 000, 030, 000, 030, 000, 031, 000, 032, 000, 032, 000, 033, 000, 034, 000, 034, 000, 035, 000, 036, 000, 036, 000, 037, 000, 038, 000, 039, 000, 039, 000, 040, 000, 041, 000, 042, 000, 042, 000, 043, 000, 044, 000, 044, 000, 045, 000, 046, 000, 047, 000, 048, 000, 048, 000, 049, 000, 050, 000, 051, 000, 052, 000, 052, 000, 053, 000, 054, 000, 055, 000, 055, 000, 056, 000, 057, 000, 058, 000, 059, 000, 060, 000, 060, 000, 061, 000, 062, 000];
private static ReadOnlySpan<byte> TableJPN => [000, 000, 123, 000, 000, 164, 255, 000, 000, 022, 030, 059, 224, 028, 037, 065, 069, 142, 180, 065, 015, 039, 147, 178, 206, 219, 032, 087, 082, 003, 045, 000, 105, 000, 023, 000, 024, 000, 024, 000, 025, 000, 026, 000, 027, 000, 028, 000, 029, 000, 030, 000, 031, 000, 031, 000, 032, 000, 033, 000, 034, 000, 035, 000, 036, 000, 037, 000, 038, 000, 039, 000, 039, 000, 040, 000, 041, 000, 042, 000, 043, 000, 044, 000, 045, 000, 046, 000, 046, 000, 047, 000, 048, 000, 049, 000, 050, 000, 051, 000, 052, 000, 053, 000, 054, 000, 055, 000, 055, 000, 056, 000, 057, 000, 058, 000, 059, 000, 060, 000, 061, 000, 062, 000, 063, 000, 064, 000, 065, 000, 066, 000, 067, 000, 068, 000, 069, 000, 070, 000, 062, 000];
private static ReadOnlySpan<byte> TableSPA => [000, 000, 109, 000, 000, 161, 255, 000, 000, 017, 023, 048, 147, 147, 153, 179, 182, 242, 022, 161, 054, 072, 170, 197, 221, 232, 226, 231, 064, 219, 105, 000, 093, 000, 023, 000, 023, 000, 024, 000, 025, 000, 026, 000, 026, 000, 027, 000, 028, 000, 029, 000, 030, 000, 030, 000, 031, 000, 032, 000, 033, 000, 033, 000, 034, 000, 035, 000, 036, 000, 037, 000, 037, 000, 038, 000, 039, 000, 040, 000, 040, 000, 041, 000, 042, 000, 043, 000, 044, 000, 045, 000, 045, 000, 046, 000, 046, 000, 047, 000, 048, 000, 049, 000, 050, 000, 050, 000, 051, 000, 052, 000, 053, 000, 054, 000, 054, 000, 055, 000, 056, 000, 057, 000, 058, 000, 058, 000, 059, 000, 060, 000, 061, 000, 062, 000, 063, 000, 064, 000, 064, 000];
private static ReadOnlySpan<byte> TableFRE => [000, 000, 113, 000, 000, 165, 255, 000, 000, 017, 023, 049, 173, 169, 176, 201, 204, 007, 042, 199, 093, 111, 206, 236, 003, 014, 054, 059, 154, 091, 016, 000, 092, 000, 023, 000, 023, 000, 024, 000, 025, 000, 026, 000, 026, 000, 027, 000, 028, 000, 029, 000, 029, 000, 030, 000, 031, 000, 031, 000, 032, 000, 033, 000, 034, 000, 034, 000, 035, 000, 036, 000, 036, 000, 037, 000, 038, 000, 039, 000, 039, 000, 040, 000, 041, 000, 042, 000, 043, 000, 043, 000, 044, 000, 045, 000, 046, 000, 046, 000, 047, 000, 048, 000, 049, 000, 050, 000, 050, 000, 051, 000, 052, 000, 053, 000, 054, 000, 054, 000, 055, 000, 056, 000, 057, 000, 058, 000, 058, 000, 059, 000, 060, 000, 061, 000, 062, 000, 063, 000, 063, 000];
private static ReadOnlySpan<byte> TableDEU => [000, 000, 110, 000, 000, 166, 255, 000, 000, 017, 023, 049, 191, 177, 184, 208, 212, 022, 057, 207, 099, 118, 222, 251, 017, 028, 065, 065, 114, 036, 251, 000, 093, 000, 023, 000, 023, 000, 024, 000, 025, 000, 026, 000, 026, 000, 027, 000, 028, 000, 028, 000, 029, 000, 030, 000, 031, 000, 032, 000, 032, 000, 033, 000, 034, 000, 035, 000, 035, 000, 036, 000, 037, 000, 038, 000, 038, 000, 039, 000, 040, 000, 041, 000, 041, 000, 042, 000, 043, 000, 044, 000, 045, 000, 045, 000, 046, 000, 047, 000, 048, 000, 049, 000, 049, 000, 050, 000, 051, 000, 052, 000, 053, 000, 053, 000, 054, 000, 055, 000, 056, 000, 057, 000, 057, 000, 058, 000, 059, 000, 060, 000, 061, 000, 062, 000, 063, 000, 063, 000, 064, 000];
private static ReadOnlySpan<byte> TableKOR => [000, 000, 082, 000, 000, 162, 255, 000, 000, 017, 022, 039, 237, 154, 160, 178, 180, 219, 239, 050, 186, 203, 253, 014, 029, 036, 039, 247, 228, 151, 138, 000, 056, 000, 022, 000, 023, 000, 023, 000, 024, 000, 024, 000, 024, 000, 025, 000, 025, 000, 025, 000, 026, 000, 026, 000, 027, 000, 027, 000, 027, 000, 028, 000, 028, 000, 028, 000, 029, 000, 029, 000, 030, 000, 030, 000, 030, 000, 031, 000, 031, 000, 031, 000, 032, 000, 032, 000, 033, 000, 033, 000, 033, 000, 034, 000, 034, 000, 034, 000, 035, 000, 035, 000, 036, 000, 036, 000, 036, 000, 037, 000, 037, 000, 038, 000, 038, 000, 038, 000, 039, 000, 039, 000, 040, 000, 040, 000, 040, 000, 041, 000, 041, 000, 041, 000, 042, 000, 042, 000, 043, 000];
private static ReadOnlySpan<byte> TableITA => [000, 000, 109, 000, 000, 166, 255, 000, 000, 017, 023, 048, 185, 173, 180, 206, 209, 012, 046, 195, 090, 108, 197, 225, 248, 003, 074, 078, 163, 046, 202, 000, 093, 000, 022, 000, 023, 000, 024, 000, 025, 000, 025, 000, 026, 000, 027, 000, 028, 000, 029, 000, 029, 000, 030, 000, 031, 000, 032, 000, 032, 000, 033, 000, 034, 000, 035, 000, 035, 000, 036, 000, 037, 000, 037, 000, 038, 000, 039, 000, 040, 000, 041, 000, 041, 000, 042, 000, 043, 000, 044, 000, 045, 000, 045, 000, 046, 000, 047, 000, 048, 000, 048, 000, 049, 000, 050, 000, 051, 000, 052, 000, 052, 000, 053, 000, 054, 000, 055, 000, 056, 000, 057, 000, 057, 000, 058, 000, 059, 000, 060, 000, 061, 000, 062, 000, 062, 000, 063, 000, 064, 000];
private static ReadOnlySpan<byte> TableZHS => [000, 000, 082, 000, 000, 162, 255, 000, 000, 017, 022, 038, 154, 068, 074, 092, 094, 126, 146, 198, 075, 092, 132, 147, 160, 167, 106, 051, 200, 227, 050, 000, 051, 000, 022, 000, 023, 000, 023, 000, 023, 000, 024, 000, 024, 000, 024, 000, 025, 000, 025, 000, 025, 000, 026, 000, 026, 000, 026, 000, 027, 000, 027, 000, 027, 000, 028, 000, 028, 000, 028, 000, 028, 000, 029, 000, 029, 000, 029, 000, 030, 000, 030, 000, 030, 000, 031, 000, 031, 000, 031, 000, 032, 000, 032, 000, 032, 000, 033, 000, 033, 000, 033, 000, 034, 000, 034, 000, 034, 000, 035, 000, 035, 000, 035, 000, 036, 000, 036, 000, 036, 000, 037, 000, 037, 000, 037, 000, 038, 000, 038, 000, 038, 000, 039, 000, 039, 000, 040, 000, 040, 000];
private static ReadOnlySpan<byte> TableZHT => [000, 000, 082, 000, 000, 163, 255, 000, 000, 017, 022, 039, 151, 065, 072, 089, 091, 124, 143, 195, 073, 089, 130, 145, 158, 165, 107, 052, 199, 227, 060, 000, 051, 000, 022, 000, 023, 000, 023, 000, 023, 000, 024, 000, 024, 000, 024, 000, 025, 000, 025, 000, 025, 000, 026, 000, 026, 000, 026, 000, 027, 000, 027, 000, 027, 000, 028, 000, 028, 000, 028, 000, 028, 000, 029, 000, 029, 000, 029, 000, 030, 000, 030, 000, 030, 000, 031, 000, 031, 000, 031, 000, 032, 000, 032, 000, 032, 000, 033, 000, 033, 000, 033, 000, 034, 000, 034, 000, 034, 000, 035, 000, 035, 000, 035, 000, 036, 000, 036, 000, 036, 000, 037, 000, 037, 000, 037, 000, 038, 000, 038, 000, 038, 000, 039, 000, 039, 000, 040, 000, 040, 000];
/// <summary>
/// Sanity check the languages possible.
/// </summary>
/// <param name="language">Language ID to check.</param>
/// <returns>True if the language is supported for VC PP table; false otherwise.</returns>
public static bool IsSupportedLanguage(LanguageID language) => language is (>= Japanese and <= ChineseT) and not UNUSED_6;
public static ReadOnlySpan<byte> GetTable(LanguageID language) => language switch
{
English => TableENG,
Japanese => TableJPN,
Spanish => TableSPA,
French => TableFRE,
German => TableDEU,
Korean => TableKOR,
Italian => TableITA,
ChineseS => TableZHS,
ChineseT => TableZHT,
_ => throw new NotSupportedException($"Language {language} is not supported for VC PP table."),
};
/// <summary>
/// Fetches the expected PP for the given move from the VC PP table. Returns false if the move is not in the VC range.
/// </summary>
/// <param name="move">Move ID.</param>
/// <param name="arr">Glitched PP table for the Pokémon's language.</param>
/// <param name="pp">Output expected PP for the move.</param>
/// <returns><see langword="true"/> if the move is in the VC range and the expected PP was fetched; <see langword="false"/> otherwise.</returns>
public static bool IsGlitched(ushort move, ReadOnlySpan<byte> arr, out byte pp)
{
var index = move - MoveFirst;
if (index < 0)
{
pp = MoveInfo7.PP[move]; // fetch from the normal table for moves below the glitched range
return true;
}
if ((uint)index < arr.Length)
{
pp = arr[index]; // fetch from the glitched table for moves in the glitched range
return true;
}
pp = 0; // unexpected move, ignore.
return false;
}
/// <summary>
/// Checks if all moves are possible from R/B/Y only.
/// </summary>
public static bool IsPossibleVC1(ReadOnlySpan<ushort> moves)
=> !moves.ContainsAnyExceptInRange<ushort>(0, Legal.MaxMoveID_1);
/// <summary>
/// Checks if all moves are possible from R/B/Y/G/S/C only.
/// </summary>
public static bool IsPossibleVC2(ReadOnlySpan<ushort> moves)
=> !moves.ContainsAnyExceptInRange<ushort>(0, Legal.MaxMoveID_2);
/// <summary>
/// Checks the moves against the table to see if all match their stored PP value.
/// </summary>
public static bool IsMatch(LanguageID language, ReadOnlySpan<ushort> moves, ReadOnlySpan<int> pp)
{
var arr = GetTable(language);
for (int i = 0; i < moves.Length; i++)
{
var move = moves[i];
if (!IsGlitched(move, arr, out var expected))
return false;
if (pp[i] != expected)
return false;
}
return true;
}
}

View File

@@ -247,6 +247,7 @@ public PK7 ConvertToPK7()
pk7.Nickname = StringConverter12Transporter.GetString(NicknameTrash, Japanese);
}
// Don't replicate the bugged PP application method; heal the PP to correct values.
pk7.HealPP();
pk7.RefreshChecksum();
return pk7;

View File

@@ -219,6 +219,7 @@ public PK7 ConvertToPK7()
pk7.FixMoves();
}
// Don't replicate the bugged PP application method; heal the PP to correct values.
pk7.HealPP();
pk7.RefreshChecksum();
return pk7;

View File

@@ -549,6 +549,26 @@ internal void SetTransferPID(bool isShiny)
}
}
/// <summary>
/// Resets the PP of moves to match Bank's initial values.
/// </summary>
public void SetVirtualConsoleTransferPP()
{
var language = (LanguageID)Language;
if (!VirtualConsolePP.IsSupportedLanguage(language))
return;
var arr = VirtualConsolePP.GetTable(language);
if (VirtualConsolePP.IsGlitched(Move1, arr, out var pp))
Move1_PP = pp;
if (VirtualConsolePP.IsGlitched(Move2, arr, out pp))
Move2_PP = pp;
if (VirtualConsolePP.IsGlitched(Move3, arr, out pp))
Move3_PP = pp;
if (VirtualConsolePP.IsGlitched(Move4, arr, out pp))
Move4_PP = pp;
}
public override string GetString(ReadOnlySpan<byte> data)
=> StringConverter7.GetString(data);
public override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "Attacken-Kombination ist nicht mit der Entwicklung zu {0} kompatibel.",
"MoveFExpectSingle_0": "Erwartet: {0}",
"MoveKeldeoMismatch": "Keldeo: Attacke und Form stimmen nicht überein.",
"MovePPMatchesVirtualConsole": "Die AP der Attacken stimmen exakt mit den Werten des 3DSVirtualConsoleTransferfehlers überein.",
"MovePPExpectHealed_01": "Die AP der Attacke {0} liegen unter dem erwarteten Wert ({1}).",
"MovePPTooHigh_01": "Die AP der Attacke {0} liegen über dem erlaubten Wert ({1}).",
"MovePPUpsTooHigh_01": "Die Anzahl der AP-Plus bei der Attacke {0} liegt über dem erlaubten Limit ({1}).",

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "Moves combinations is not compatible with {0} evolution.",
"MoveFExpectSingle_0": "Expected: {0}",
"MoveKeldeoMismatch": "Keldeo Move/Form mismatch.",
"MovePPMatchesVirtualConsole": "Move PP exactly matches values from the 3DS Virtual Console transfer bug.",
"MovePPExpectHealed_01": "Move {0} PP is below the amount expected ({1}).",
"MovePPTooHigh_01": "Move {0} PP is above the amount allowed ({1}).",
"MovePPUpsTooHigh_01": "Move {0} PP Ups is above the amount allowed ({1}).",

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "Combinaciones de Movimientos no son compatibles con Movimientos de la evolución de {0}.",
"MoveFExpectSingle_0": "Esperado: {0}",
"MoveKeldeoMismatch": "Movimiento/Forma de Keldeo incorrecta.",
"MovePPMatchesVirtualConsole": "Los PP de los movimientos coinciden exactamente con los valores del error de transferencia de la Consola Virtual de 3DS.",
"MovePPExpectHealed_01": "Los PP del movimiento {0} son inferiores a la cantidad esperada ({1}).",
"MovePPTooHigh_01": "Los PP del movimiento {0} están por encima de los permitidos ({1}).",
"MovePPUpsTooHigh_01": "Los Más PP del movimiento {0} superan la cantidad permitida ({1}).",

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "Combinaciones de Movimientos no son compatibles con Movimientos de la evolución de {0}.",
"MoveFExpectSingle_0": "Esperado: {0}",
"MoveKeldeoMismatch": "Movimiento/Forma de Keldeo incorrecta.",
"MovePPMatchesVirtualConsole": "Los PP de los movimientos coinciden exactamente con los valores del error de transferencia de la Consola Virtual de 3DS.",
"MovePPExpectHealed_01": "Los PP del movimiento {0} son inferiores a la cantidad esperada ({1}).",
"MovePPTooHigh_01": "Los PP del movimiento {0} están por encima de los permitidos ({1}).",
"MovePPUpsTooHigh_01": "Los Más PP del movimiento {0} superan la cantidad permitida ({1}).",

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "Le moveset est incompatible avec l'évolution de {0}.",
"MoveFExpectSingle_0": "Attendu : {0}",
"MoveKeldeoMismatch": "Combinaison forme/capacité invalide chez Keldeo.",
"MovePPMatchesVirtualConsole": "Les PP des capacités correspondent exactement aux valeurs du bug de transfert sur la console virtuelle 3DS.",
"MovePPExpectHealed_01": "Les PP de la capacité {0} sont inférieures à la quantité attendue ({1}).",
"MovePPTooHigh_01": "Les PP de la capacité {0} sont supérieures à la quantité attendue ({1}).",
"MovePPUpsTooHigh_01": "La quantité de PP Plus pour la capacité {0} est supérieure à la quantité attendue ({1}).",

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "la combinazione di mosse non è compatibile con l'evoluzione di {0}.",
"MoveFExpectSingle_0": "Previsto: {0}",
"MoveKeldeoMismatch": "Mossa/Forma di Keldeo non corrispondente.",
"MovePPMatchesVirtualConsole": "I PP delle mosse corrispondono esattamente ai valori del bug di trasferimento della Virtual Console 3DS.",
"MovePPExpectHealed_01": "I PP della mossa {0} sono inferiori alla quantità prevista ({1}).",
"MovePPTooHigh_01": "I PP della mossa {0} sono oltre il massimo consentito ({1}).",
"MovePPUpsTooHigh_01": "I PP Up della mossa {0} sono oltre il massimo consentito ({1}).",

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "技の組み合わせは {0} 進化と両立できません。",
"MoveFExpectSingle_0": "予想: {0}",
"MoveKeldeoMismatch": "ケルディオの技/フォルムが一致しません。",
"MovePPMatchesVirtualConsole": "技のPPが3DSバーチャルコンソール転送バグの値と完全に一致しています。",
"MovePPExpectHealed_01": "Move {0} PP is below the amount expected ({1}).",
"MovePPTooHigh_01": "技 {0} のPPが上限を超えています ({1})。",
"MovePPUpsTooHigh_01": "技 {0} のポイントアップ上限を超えています ({1})。",

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "기술 조합이 {0} 진화와 호환되지 않습니다.",
"MoveFExpectSingle_0": "예상되는: {0}",
"MoveKeldeoMismatch": "케르디오의 기술과 폼이 일치하지 않습니다.",
"MovePPMatchesVirtualConsole": "기술의 PP가 3DS 가상 콘솔 전송 버그의 값과 정확히 일치합니다.",
"MovePPExpectHealed_01": "기술 {0}의 PP가 예상 수치({1})보다 낮습니다.",
"MovePPTooHigh_01": "기술 {0}의 PP가 허용된 값보다 많습니다 ({1}).",
"MovePPUpsTooHigh_01": "기술 {0}의 포인트업 횟수가 허용 수치({1})를 초과했습니다.",

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "招式组合与{0}进化型不兼容。",
"MoveFExpectSingle_0": "预期: {0}",
"MoveKeldeoMismatch": "凯路迪欧的招式与形态不匹配。",
"MovePPMatchesVirtualConsole": "招式的PP与3DS虚拟主机传输漏洞的数值完全一致。",
"MovePPExpectHealed_01": "招式 {0} 的PP恢复量未达预期值 ({1})。",
"MovePPTooHigh_01": "招式 {0} PP高于允许值 ({1})。",
"MovePPUpsTooHigh_01": "招式 {0} PP上升高于允许值 ({1})。",

View File

@@ -228,6 +228,7 @@
"MoveEvoFCombination_0": "招式組合與{0}進化型不相容。",
"MoveFExpectSingle_0": "應該是該招式: {0}。",
"MoveKeldeoMismatch": "凱路迪歐之現時招式與當前形態不匹配。",
"MovePPMatchesVirtualConsole": "招式的PP與3DS虛擬主機傳輸漏洞的數值完全一致。",
"MovePPExpectHealed_01": "招式 {0} 的PP恢復量未達預期值 ({1})。",
"MovePPTooHigh_01": "招式 {0} PP 高於允許值。 ({1})",
"MovePPUpsTooHigh_01": "招式 {0} PP 高於允許值。 ({1})",

View File

@@ -1424,6 +1424,9 @@ private static bool IsPossibleNotNicknamed(PKM pk, ReadOnlySpan<char> current)
private void UpdateNickname(object sender, EventArgs e)
{
if (!FieldsLoaded)
return;
if (sender == Label_Species)
{
switch (ModifierKeys)

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=Hinterlege verschiedene Begegnungs Vo
LocalizedDescription.ShowEncounterOpacityBackground=Deckkraft des Hintergrunds des Begegnungs Typen.
LocalizedDescription.ShowEncounterOpacityStripe=Deckkraft der Begegnungs Typen Streifen Schicht.
LocalizedDescription.ShowEncounterThicknessStripe=Anzahl der Pixel des farbigen Streifens der Begegnungs Typen.
LocalizedDescription.ShowExperienceBar=Beim Anzeigen einer Entität die Erfahrungsleiste anzeigen, um EXP und Level bearbeiten zu können.
LocalizedDescription.ShowExperiencePercent=Zeige einen dünnen Streifen, der den Level-Up Fortschritt darstellt.
LocalizedDescription.ShowGenderGen1=Zeigt bei Entitäten im Generation-1-Format das Geschlecht an, das sie beim Transfer in spätere Generationen erhalten würden.
LocalizedDescription.ShowLegalBallsFirst=Zeige in der Ball Auswahl legale Bälle zuerst und illegale Bälle darunter an.

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=Show a background to differentiate th
LocalizedDescription.ShowEncounterOpacityBackground=Opacity for the Encounter Type background layer.
LocalizedDescription.ShowEncounterOpacityStripe=Opacity for the Encounter Type stripe layer.
LocalizedDescription.ShowEncounterThicknessStripe=Amount of pixels thick to show when displaying the encounter type color stripe.
LocalizedDescription.ShowExperienceBar=When showing an entity, show the Experience Bar to allow editing of EXP and Level.
LocalizedDescription.ShowExperiencePercent=Show a thin stripe to indicate the percent of level-up progress
LocalizedDescription.ShowGenderGen1=When showing a Generation 1 format entity, show the gender it would have if transferred to other generations.
LocalizedDescription.ShowLegalBallsFirst=When showing the list of balls to select, show the legal balls before the illegal balls rather than sorting by Ball ID.

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=Mostrar un fondo para diferenciar el
LocalizedDescription.ShowEncounterOpacityBackground=Nivel de opacidad de la capa de fondo correspondiente al tipo de encuentro.
LocalizedDescription.ShowEncounterOpacityStripe=Nivel de opacidad de la raya correspondiente al tipo de encuentro.
LocalizedDescription.ShowEncounterThicknessStripe=Nivel de grosor (en píxeles) al mostrar la raya coloreada del tipo de encuentro.
LocalizedDescription.ShowExperienceBar=Al mostrar una entidad, mostrar la barra de experiencia para permitir editar el EXP y el nivel.
LocalizedDescription.ShowExperiencePercent=Mostrar una raya fina para indicar el porcentaje de subida de nivel.
LocalizedDescription.ShowGenderGen1=Al mostrar una entidad en el formato de la 1a generación, mostrar el sexo que tendría al ser transferido a otra generación.
LocalizedDescription.ShowLegalBallsFirst=Al mostrar la lista de Pokébolas a seleccionar, ordenarlas por Pokébolas legales primero, en vez de ordenarlas por ID.

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=Mostrar un fondo para diferenciar el
LocalizedDescription.ShowEncounterOpacityBackground=Nivel de opacidad de la capa de fondo correspondiente al tipo de encuentro.
LocalizedDescription.ShowEncounterOpacityStripe=Nivel de opacidad de la raya correspondiente al tipo de encuentro.
LocalizedDescription.ShowEncounterThicknessStripe=Nivel de grosor (en píxeles) al mostrar la raya coloreada del tipo de encuentro.
LocalizedDescription.ShowExperienceBar=Al mostrar una entidad, mostrar la barra de experiencia para permitir editar el EXP y el nivel.
LocalizedDescription.ShowExperiencePercent=Mostrar una raya fina para indicar el porcentaje de subida de nivel.
LocalizedDescription.ShowGenderGen1=Al mostrar una entidad en el formato de la 1a generación, mostrar el sexo que tendría al ser transferido a otra generación.
LocalizedDescription.ShowLegalBallsFirst=Al mostrar la lista de Poké Balls a seleccionar, ordenarlas por Poké Balls legales primero, en vez de ordenarlas por ID.

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=Afficher un arrière-plan pour diffé
LocalizedDescription.ShowEncounterOpacityBackground=Opacité pour la couche d'arrière-plan du modèle de rencontre.
LocalizedDescription.ShowEncounterOpacityStripe=Opacité pour la couche de rayure du modèle de rencontre.
LocalizedDescription.ShowEncounterThicknessStripe=Épaisseur de pixels à montrer lors de l'affichage de la couleur de la rayure du modèle de rencontre.
LocalizedDescription.ShowExperienceBar=Lors de laffichage dune entité, afficher la barre dexpérience pour permettre lédition de lEXP et du niveau.
LocalizedDescription.ShowExperiencePercent=Afficher une fine rayure pour indiquer le pourcentage de progression de niveau
LocalizedDescription.ShowGenderGen1=Lorsqu'une entité au format génération 1 est montrée, afficher le sexe que l'entité aurait si elle devait être transférée vers d'autres générations.
LocalizedDescription.ShowLegalBallsFirst=Lors de l'affichage de la liste des balls à choisir, montrer les balls légales avant celles illégales au lieu de simplement les trier par ID.

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=Mostra uno sfondo per differenziare i
LocalizedDescription.ShowEncounterOpacityBackground=Opacità per lo sfondo del Tipo di Incontro.
LocalizedDescription.ShowEncounterOpacityStripe=Opacità per la barra del Tipo di Incontro.
LocalizedDescription.ShowEncounterThicknessStripe=Spessore dei Pixel da mostrare per la barra del Tipo di Incontro.
LocalizedDescription.ShowExperienceBar=Quando si mostra unentità, mostra la barra dellesperienza per consentire la modifica di EXP e livello.
LocalizedDescription.ShowExperiencePercent=Mostra una piccola barra per indicare la percentuale di progresso di Aumento Livello
LocalizedDescription.ShowGenderGen1=Quando viene mostrata un'entità in formato Gen 1, mostra il sesso che avrebbe se venisse trasferita nelle altre generazioni.
LocalizedDescription.ShowLegalBallsFirst= Quando viene mostrata la lista di Ball, mostra le Ball legali prima di quelle illegali, anziché andare per ordine di ID.

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=PKMスロットで認識された出
LocalizedDescription.ShowEncounterOpacityBackground=出会いタイプ背景レイヤーの不透明度。
LocalizedDescription.ShowEncounterOpacityStripe=出会いタイプのストライプレイヤーの不透明度。
LocalizedDescription.ShowEncounterThicknessStripe=エンカウントタイプのカラーストライプを表示する時のピクセルの太さ。
LocalizedDescription.ShowExperienceBar=個体を表示する際、EXPとレベルを編集できるように経験値バーを表示します。
LocalizedDescription.ShowExperiencePercent=次のレベルに必要な経験値のストライプを表示します。
LocalizedDescription.ShowGenderGen1=1世代のゲームを編集時、2世代の条件でポケモンの性別を表示するかどうか。
LocalizedDescription.ShowLegalBallsFirst=ボールを選択する時のリストはID順ではなく、正規が先で後から不正の順番にする。

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=포켓몬 슬롯에 인식된 인카
LocalizedDescription.ShowEncounterOpacityBackground=인카운터 유형 배경 레이어의 불투명도입니다.
LocalizedDescription.ShowEncounterOpacityStripe=인카운터 유형 스트라이프 레이어의 불투명도입니다.
LocalizedDescription.ShowEncounterThicknessStripe=인카운터 유형 색상 스트라이프를 표시할 때의 두께입니다.
LocalizedDescription.ShowExperienceBar=개체를 표시할 때 EXP와 레벨을 편집할 수 있도록 경험치 바를 표시합니다.
LocalizedDescription.ShowExperiencePercent=레벨업 진행률을 나타내는 얇은 스트라이프를 표시합니다.
LocalizedDescription.ShowGenderGen1=1세대 형식의 개체를 표시할 때, 다른 세대로 옮겼을 경우 갖게 될 성별을 표시합니다.
LocalizedDescription.ShowLegalBallsFirst=선택 가능한 볼 목록을 표시할 때, 볼 ID 순서로 정렬하는 대신 합법적인 볼을 불법적인 볼보다 먼저 표시합니다.

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=显示背景以区分PKM槽位的已
LocalizedDescription.ShowEncounterOpacityBackground=相遇方式指示背景层的透明度。
LocalizedDescription.ShowEncounterOpacityStripe=相遇方式指示条的透明度。
LocalizedDescription.ShowEncounterThicknessStripe=相遇方式指示条的画素高度。
LocalizedDescription.ShowExperienceBar=显示个体时显示经验条以便编辑EXP和等级。
LocalizedDescription.ShowExperiencePercent=显示一条细条纹来表示升级进度的百分比。
LocalizedDescription.ShowGenderGen1=当显示第1代格式的数据时显示其在转移到其他代时会有的性别。
LocalizedDescription.ShowLegalBallsFirst=当显示要选择的球列表时在非法球之前显示合法球而不是按球ID排序。

View File

@@ -380,6 +380,7 @@ LocalizedDescription.ShowEncounterColorPKM=顯示背景以區分 PKM 槽位的
LocalizedDescription.ShowEncounterOpacityBackground=遇見方式指示背景層之透明度。
LocalizedDescription.ShowEncounterOpacityStripe=遇見方式指示條之透明度。
LocalizedDescription.ShowEncounterThicknessStripe=遇見方式指示條之畫素高度。
LocalizedDescription.ShowExperienceBar=顯示個體時顯示經驗值條以便編輯EXP和等級。
LocalizedDescription.ShowExperiencePercent=顯示一條細條紋來表示升級進度的百分比。
LocalizedDescription.ShowGenderGen1=當顯示第1代格式的資料時顯示其在轉移到其他世代時會有的性別。
LocalizedDescription.ShowLegalBallsFirst=當顯示要選擇的球列表時在非法球之前顯示合法球而不是按球ID排序。

View File

@@ -91,9 +91,9 @@ private void InitializeComponent()
TC_Editor = new System.Windows.Forms.TabControl();
Tab_Overview = new System.Windows.Forms.TabPage();
tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
trainerID1 = new PKHeX.WinForms.Controls.TrainerID();
CAL_LastSavedTime = new System.Windows.Forms.DateTimePicker();
CAL_LastSavedDate = new System.Windows.Forms.DateTimePicker();
trainerID1 = new PKHeX.WinForms.Controls.TrainerID();
L_LastSaved = new System.Windows.Forms.Label();
flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
CB_Gender = new PKHeX.WinForms.Controls.GenderToggle();
@@ -700,16 +700,6 @@ private void InitializeComponent()
tableLayoutPanel1.Size = new System.Drawing.Size(593, 297);
tableLayoutPanel1.TabIndex = 75;
//
// trainerID1
//
tableLayoutPanel1.SetColumnSpan(trainerID1, 2);
trainerID1.Dock = System.Windows.Forms.DockStyle.Fill;
trainerID1.Location = new System.Drawing.Point(88, 30);
trainerID1.Margin = new System.Windows.Forms.Padding(88, 0, 0, 0);
trainerID1.Name = "trainerID1";
trainerID1.Size = new System.Drawing.Size(593, 25);
trainerID1.TabIndex = 74;
//
// CAL_LastSavedTime
//
CAL_LastSavedTime.Anchor = System.Windows.Forms.AnchorStyles.Left;
@@ -735,6 +725,16 @@ private void InitializeComponent()
CAL_LastSavedDate.TabIndex = 55;
CAL_LastSavedDate.Value = new System.DateTime(2000, 1, 1, 0, 0, 0, 0);
//
// trainerID1
//
tableLayoutPanel1.SetColumnSpan(trainerID1, 2);
trainerID1.Dock = System.Windows.Forms.DockStyle.Fill;
trainerID1.Location = new System.Drawing.Point(88, 30);
trainerID1.Margin = new System.Windows.Forms.Padding(88, 0, 0, 0);
trainerID1.Name = "trainerID1";
trainerID1.Size = new System.Drawing.Size(593, 25);
trainerID1.TabIndex = 74;
//
// L_LastSaved
//
L_LastSaved.Anchor = System.Windows.Forms.AnchorStyles.Right;

View File

@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="CB_Gender.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAACHSURBVDhPzZQhDsAgDEV3bBAcB8Up0ByD4ECB74KAtSxZ
ISD2k6fof6kp14UihIAVcLdnHJrliERK+cjGxxWaqPIPEWZLdGyjT5ExBkIIkFKCUgohxgjee9Ba86KZ
5Jx5kXNu7L1ireVFjTqklCLg4rRolS3RsY2IaPfeumT3ByCSlnGIA3dvHLf7kzM4Ke4AAAAASUVORK5C
YII=
</value>
</data>
</root>