mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-22 03:53:08 +00:00
Revise gender symbol remapping
Handles Nidoran's shenanigans as well as more clear method names - Add normalization for PK7->PK8 (no more 0xE... usage for the gender symbols... maybe more chars?) - Not sure if Gen3 gamecube encoding needs sanitizing. Who is transferring Nidoran to CXD? :) Requires some silly usage of Language passing as arguments. Future improvements can be made to revise the half/full encoding determination when setting a string. Probably has issues since we're just doing a naive check without considering nicknames w/ special chars. Closes #4174
This commit is contained in:
parent
a33884895f
commit
08ed482555
38 changed files with 338 additions and 162 deletions
|
@ -424,7 +424,7 @@ public sealed class ShowdownSet : IBattleTemplate
|
|||
|
||||
private string GetSpeciesNickname(string specForm)
|
||||
{
|
||||
if (Nickname.Length == 0)
|
||||
if (Nickname.Length == 0 || Nickname == specForm)
|
||||
return specForm;
|
||||
bool isNicknamed = SpeciesName.IsNicknamedAnyLanguage(Species, Nickname, Context.Generation());
|
||||
if (!isNicknamed)
|
||||
|
|
|
@ -280,7 +280,10 @@ public sealed class NicknameVerifier : Verifier
|
|||
if (pk.IsNicknamed != flagState)
|
||||
data.AddLine(GetInvalid(flagState ? LNickFlagEggYes : LNickFlagEggNo, CheckIdentifier.Egg));
|
||||
|
||||
ReadOnlySpan<char> nickname = pk.Nickname;
|
||||
Span<char> nickname = stackalloc char[pk.MaxStringLengthNickname];
|
||||
int len = pk.LoadString(pk.NicknameTrash, nickname);
|
||||
nickname = nickname[..len];
|
||||
|
||||
if (pk.Format == 2 && !SpeciesName.IsNicknamedAnyLanguage(0, nickname, 2))
|
||||
data.AddLine(GetValid(LNickMatchLanguageEgg, CheckIdentifier.Egg));
|
||||
else if (!nickname.SequenceEqual(SpeciesName.GetEggName(pk.Language, Info.Generation)))
|
||||
|
|
|
@ -76,7 +76,7 @@ public sealed class PCD(byte[] Data)
|
|||
public override string CardTitle
|
||||
{
|
||||
get => StringConverter4.GetString(CardTitleSpan);
|
||||
set => StringConverter4.SetString(CardTitleSpan, value, TitleLength / 2, StringConverterOption.ClearFF);
|
||||
set => StringConverter4.SetString(CardTitleSpan, value, TitleLength / 2, 0, StringConverterOption.ClearFF);
|
||||
}
|
||||
|
||||
public ushort CardCompatibility => ReadUInt16LittleEndian(Data.AsSpan(0x14C)); // rest of bytes we don't really care about
|
||||
|
|
|
@ -57,7 +57,7 @@ public sealed class PGF(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
public string Nickname
|
||||
{
|
||||
get => StringConverter5.GetString(Data.AsSpan(0x1E, 11 * 2));
|
||||
set => StringConverter5.SetString(Data.AsSpan(0x1E, 11 * 2), value, 11, StringConverterOption.ClearFF);
|
||||
set => StringConverter5.SetString(Data.AsSpan(0x1E, 11 * 2), value, 11, Language, StringConverterOption.ClearFF);
|
||||
}
|
||||
|
||||
public Nature Nature { get => (Nature)Data[0x34]; set => Data[0x34] = (byte)value; }
|
||||
|
@ -83,7 +83,7 @@ public sealed class PGF(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
public override string OriginalTrainerName
|
||||
{
|
||||
get => StringConverter5.GetString(Data.AsSpan(0x4A, 8 * 2));
|
||||
set => StringConverter5.SetString(Data.AsSpan(0x4A, 8 * 2), value, 8, StringConverterOption.ClearFF);
|
||||
set => StringConverter5.SetString(Data.AsSpan(0x4A, 8 * 2), value, 8, Language, StringConverterOption.ClearFF);
|
||||
}
|
||||
|
||||
public byte OTGender { get => Data[0x5A]; set => Data[0x5A] = value; }
|
||||
|
@ -93,7 +93,7 @@ public sealed class PGF(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
public override string CardTitle
|
||||
{
|
||||
get => StringConverter5.GetString(Data.AsSpan(0x60, 37 * 2));
|
||||
set => StringConverter5.SetString(Data.AsSpan(0x60, 37 * 2), value, 36, StringConverterOption.ClearZero);
|
||||
set => StringConverter5.SetString(Data.AsSpan(0x60, 37 * 2), value, 36, Language, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
// Card Attributes
|
||||
|
|
|
@ -35,7 +35,7 @@ public sealed class PL6(Memory<byte> Raw)
|
|||
/// <summary>
|
||||
/// Name of data source
|
||||
/// </summary>
|
||||
public string Origin { get => StringConverter6.GetString(Source); set => StringConverter6.SetString(Source, value, 54, StringConverterOption.ClearZero); }
|
||||
public string Origin { get => StringConverter6.GetString(Source); set => StringConverter6.SetString(Source, value, 54, 0, StringConverterOption.ClearZero); }
|
||||
|
||||
// Pokemon transfer flags?
|
||||
public uint Flags1 { get => ReadUInt32LittleEndian(Data[0x099..]); set => WriteUInt32LittleEndian(Data[0x099..], value); }
|
||||
|
@ -109,7 +109,7 @@ public sealed class LinkEntity6(Memory<byte> Raw) : IRibbonSetEvent3, IRibbonSet
|
|||
public string Nickname
|
||||
{
|
||||
get => StringConverter6.GetString(NicknameTrash);
|
||||
set => StringConverter6.SetString(NicknameTrash, value, 12, StringConverterOption.ClearZero);
|
||||
set => StringConverter6.SetString(NicknameTrash, value, 12, Language, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public Nature Nature { get => (Nature)Data[0x38]; set => Data[0x38] = (byte)value; }
|
||||
|
@ -141,7 +141,7 @@ public sealed class LinkEntity6(Memory<byte> Raw) : IRibbonSetEvent3, IRibbonSet
|
|||
public string OT
|
||||
{
|
||||
get => StringConverter6.GetString(OriginalTrainerTrash);
|
||||
set => StringConverter6.SetString(OriginalTrainerTrash, value, 12, StringConverterOption.ClearZero);
|
||||
set => StringConverter6.SetString(OriginalTrainerTrash, value, 12, Language, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public int Level { get => Data[0x68]; set => Data[0x68] = (byte)value; }
|
||||
|
|
|
@ -43,7 +43,7 @@ public sealed class WC6(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
{
|
||||
// Max len 36 char, followed by null terminator
|
||||
get => StringConverter6.GetString(Data.AsSpan(2, 0x4A));
|
||||
set => StringConverter6.SetString(Data.AsSpan(2, 0x4A), value, 36, StringConverterOption.ClearZero);
|
||||
set => StringConverter6.SetString(Data.AsSpan(2, 0x4A), value, 36, Language, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
internal uint RawDate
|
||||
|
@ -170,7 +170,7 @@ public sealed class WC6(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
public string Nickname
|
||||
{
|
||||
get => StringConverter6.GetString(Data.AsSpan(0x86, 0x1A));
|
||||
set => StringConverter6.SetString(Data.AsSpan(0x86, 0x1A), value, 12, StringConverterOption.ClearZero);
|
||||
set => StringConverter6.SetString(Data.AsSpan(0x86, 0x1A), value, 12, Language, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public Nature Nature { get => (Nature)Data[0xA0]; set => Data[0xA0] = (byte)value; }
|
||||
|
@ -199,7 +199,7 @@ public sealed class WC6(byte[] Data) : DataMysteryGift(Data), IRibbonSetEvent3,
|
|||
public override string OriginalTrainerName
|
||||
{
|
||||
get => StringConverter6.GetString(Data.AsSpan(0xB6, 0x1A));
|
||||
set => StringConverter6.SetString(Data.AsSpan(0xB6, 0x1A), value, 12, StringConverterOption.ClearZero);
|
||||
set => StringConverter6.SetString(Data.AsSpan(0xB6, 0x1A), value, 12, Language, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public override byte Level { get => Data[0xD0]; set => Data[0xD0] = value; }
|
||||
|
|
|
@ -200,7 +200,18 @@ public sealed class BK4 : G4PKM
|
|||
#endregion
|
||||
|
||||
#region Block C
|
||||
public override string Nickname { get => StringConverter4GC.GetString(NicknameTrash); set => StringConverter4GC.SetString(NicknameTrash, value, 10, StringConverterOption.None); }
|
||||
|
||||
public override string Nickname
|
||||
{
|
||||
get => StringConverter4GC.GetString(NicknameTrash);
|
||||
set
|
||||
{
|
||||
var language = Language;
|
||||
CheckKoreanNidoranDPPt(value, ref language);
|
||||
StringConverter4GC.SetString(NicknameTrash, value, 10, language, StringConverterOption.None);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x5E unused
|
||||
public override GameVersion Version { get => (GameVersion)Data[0x5F]; set => Data[0x5F] = (byte)value; }
|
||||
private byte RIB8 { get => Data[0x60]; set => Data[0x60] = value; } // Sinnoh 3
|
||||
|
@ -243,7 +254,7 @@ public sealed class BK4 : G4PKM
|
|||
#endregion
|
||||
|
||||
#region Block D
|
||||
public override string OriginalTrainerName { get => StringConverter4GC.GetString(OriginalTrainerTrash); set => StringConverter4GC.SetString(OriginalTrainerTrash, value, 7, StringConverterOption.None); }
|
||||
public override string OriginalTrainerName { get => StringConverter4GC.GetString(OriginalTrainerTrash); set => StringConverter4GC.SetString(OriginalTrainerTrash, value, 7, Language, StringConverterOption.None); }
|
||||
public override byte EggYear { get => Data[0x78]; set => Data[0x78] = value; }
|
||||
public override byte EggMonth { get => Data[0x79]; set => Data[0x79] = value; }
|
||||
public override byte EggDay { get => Data[0x7A]; set => Data[0x7A] = value; }
|
||||
|
@ -307,5 +318,5 @@ public sealed class BK4 : G4PKM
|
|||
public override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
||||
=> StringConverter4.LoadString(data, destBuffer);
|
||||
public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter4.SetString(destBuffer, value, maxLength, option);
|
||||
=> StringConverter4.SetString(destBuffer, value, maxLength, Language, option);
|
||||
}
|
||||
|
|
|
@ -113,10 +113,17 @@ public sealed class GameDataPK8 : HomeOptional1, IGameDataSide<PK8>, IGigantamax
|
|||
Ability = (ushort)pk.Ability;
|
||||
|
||||
pkh.MarkingValue &= 0b1111_1111_1111;
|
||||
if (!pk.IsNicknamed)
|
||||
pkh.Nickname = SpeciesName.GetSpeciesNameImportHOME(pk.Species, pk.Language, 8);
|
||||
if (FormInfo.IsTotemForm(pk.Species, pk.Form))
|
||||
pkh.Form = FormInfo.GetTotemBaseForm(pk.Species, pk.Form);
|
||||
StringConverter8.NormalizeHalfWidth(pkh.OriginalTrainerTrash);
|
||||
if (pk.IsNicknamed)
|
||||
{
|
||||
StringConverter8.NormalizeHalfWidth(pkh.NicknameTrash);
|
||||
}
|
||||
else
|
||||
{
|
||||
pkh.NicknameTrash.Clear();
|
||||
var reset = SpeciesName.GetSpeciesNameImportHOME(pk.Species, pk.Language, 8);
|
||||
pkh.SetString(pkh.NicknameTrash, reset, reset.Length, StringConverterOption.None);
|
||||
}
|
||||
}
|
||||
|
||||
public PK8 ConvertToPKM(PKH pkh)
|
||||
|
|
|
@ -183,7 +183,12 @@ public sealed class PK4 : G4PKM
|
|||
public override string Nickname
|
||||
{
|
||||
get => StringConverter4.GetString(NicknameTrash);
|
||||
set => StringConverter4.SetString(NicknameTrash, value, 10, StringConverterOption.None);
|
||||
set
|
||||
{
|
||||
var language = Language;
|
||||
CheckKoreanNidoranDPPt(value, ref language);
|
||||
StringConverter4.SetString(NicknameTrash, value, 10, language, StringConverterOption.None);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x5E unused
|
||||
|
@ -231,7 +236,7 @@ public sealed class PK4 : G4PKM
|
|||
public override string OriginalTrainerName
|
||||
{
|
||||
get => StringConverter4.GetString(OriginalTrainerTrash);
|
||||
set => StringConverter4.SetString(OriginalTrainerTrash, value, 7, StringConverterOption.None);
|
||||
set => StringConverter4.SetString(OriginalTrainerTrash, value, 7, Language, StringConverterOption.None);
|
||||
}
|
||||
|
||||
public override byte EggYear { get => Data[0x78]; set => Data[0x78] = value; }
|
||||
|
@ -352,8 +357,8 @@ public sealed class PK4 : G4PKM
|
|||
pk5.Ball = Ball;
|
||||
|
||||
// Transfer Nickname and OT Name, update encoding
|
||||
TransferTrash(NicknameTrash, pk5.NicknameTrash);
|
||||
TransferTrash(OriginalTrainerTrash, pk5.OriginalTrainerTrash);
|
||||
TransferTrash(NicknameTrash, pk5.NicknameTrash, Language);
|
||||
TransferTrash(OriginalTrainerTrash, pk5.OriginalTrainerTrash, Language);
|
||||
|
||||
// Fix Level
|
||||
pk5.MetLevel = pk5.CurrentLevel;
|
||||
|
@ -376,12 +381,12 @@ public sealed class PK4 : G4PKM
|
|||
return pk5;
|
||||
}
|
||||
|
||||
public static void TransferTrash(ReadOnlySpan<byte> src, Span<byte> dest)
|
||||
public static void TransferTrash(ReadOnlySpan<byte> src, Span<byte> dest, int language)
|
||||
{
|
||||
Span<char> temp = stackalloc char[13];
|
||||
var len = StringConverter4.LoadString(src, temp);
|
||||
StringConverter345.TransferGlyphs45(temp[..len]);
|
||||
StringConverter5.SetString(dest, temp[..len], len);
|
||||
StringConverter5.SetString(dest, temp[..len], len, language);
|
||||
}
|
||||
|
||||
public override string GetString(ReadOnlySpan<byte> data)
|
||||
|
@ -389,5 +394,5 @@ public sealed class PK4 : G4PKM
|
|||
public override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
||||
=> StringConverter4.LoadString(data, destBuffer);
|
||||
public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter4.SetString(destBuffer, value, maxLength, option);
|
||||
=> StringConverter4.SetString(destBuffer, value, maxLength, Language, option);
|
||||
}
|
||||
|
|
|
@ -191,7 +191,18 @@ public sealed class PK5 : PKM, ISanityChecksum,
|
|||
#endregion
|
||||
|
||||
#region Block C
|
||||
public override string Nickname { get => StringConverter5.GetString(NicknameTrash); set => StringConverter5.SetString(NicknameTrash, value, 10, StringConverterOption.None); }
|
||||
|
||||
public override string Nickname
|
||||
{
|
||||
get => StringConverter5.GetString(NicknameTrash);
|
||||
set
|
||||
{
|
||||
var language = Language;
|
||||
CheckKoreanNidoranDPPt(value, ref language);
|
||||
StringConverter5.SetString(NicknameTrash, value, 10, language, StringConverterOption.None);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x5E unused
|
||||
public override GameVersion Version { get => (GameVersion)Data[0x5F]; set => Data[0x5F] = (byte)value; }
|
||||
private byte RIB8 { get => Data[0x60]; set => Data[0x60] = value; } // Sinnoh 3
|
||||
|
@ -234,7 +245,7 @@ public sealed class PK5 : PKM, ISanityChecksum,
|
|||
#endregion
|
||||
|
||||
#region Block D
|
||||
public override string OriginalTrainerName { get => StringConverter5.GetString(OriginalTrainerTrash); set => StringConverter5.SetString(OriginalTrainerTrash, value, 7, StringConverterOption.None); }
|
||||
public override string OriginalTrainerName { get => StringConverter5.GetString(OriginalTrainerTrash); set => StringConverter5.SetString(OriginalTrainerTrash, value, 7, Language, StringConverterOption.None); }
|
||||
public override byte EggYear { get => Data[0x78]; set => Data[0x78] = value; }
|
||||
public override byte EggMonth { get => Data[0x79]; set => Data[0x79] = value; }
|
||||
public override byte EggDay { get => Data[0x7A]; set => Data[0x7A] = value; }
|
||||
|
@ -558,5 +569,24 @@ public sealed class PK5 : PKM, ISanityChecksum,
|
|||
public override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
||||
=> StringConverter5.LoadString(data, destBuffer);
|
||||
public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter5.SetString(destBuffer, value, maxLength, option);
|
||||
=> StringConverter5.SetString(destBuffer, value, maxLength, Language, option);
|
||||
|
||||
/// <inheritdoc cref="G4PKM.CheckKoreanNidoranDPPt"/>
|
||||
/// <remarks> Gen4->Gen5 chars transfer without resetting the name. Still relevant even as PK5. </remarks>
|
||||
private void CheckKoreanNidoranDPPt(ReadOnlySpan<char> value, ref int language)
|
||||
{
|
||||
if (language != (int)LanguageID.Korean)
|
||||
return;
|
||||
if (IsNicknamed)
|
||||
return;
|
||||
if (Version is not (GameVersion.D or GameVersion.P or GameVersion.Pt))
|
||||
return;
|
||||
// Full-width gender symbols for not-nicknamed Nidoran in D/P/Pt
|
||||
// Full/Half is technically legal either way as trainers can reset the nickname in HG/SS, or vice versa for origins.
|
||||
// Still try to set whichever it originated with. Default would be half, but if it's a Nidoran species name, set full-width.
|
||||
if (Species == (int)Core.Species.NidoranM && value is "니드런♂")
|
||||
language = 1; // Use Japanese to force full-width encoding of the gender symbol.
|
||||
else if (Species == (int)Core.Species.NidoranF && value is "니드런♀")
|
||||
language = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC
|
|||
public override string Nickname
|
||||
{
|
||||
get => StringConverter6.GetString(NicknameTrash);
|
||||
set => StringConverter6.SetString(NicknameTrash, value, 12, StringConverterOption.None);
|
||||
set => StringConverter6.SetString(NicknameTrash, value, 12, Language, StringConverterOption.None);
|
||||
}
|
||||
|
||||
public override ushort Move1
|
||||
|
@ -304,7 +304,7 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC
|
|||
public override string HandlingTrainerName
|
||||
{
|
||||
get => StringConverter6.GetString(HandlingTrainerTrash);
|
||||
set => StringConverter6.SetString(HandlingTrainerTrash, value, 12, StringConverterOption.None);
|
||||
set => StringConverter6.SetString(HandlingTrainerTrash, value, 12, Language, StringConverterOption.None);
|
||||
}
|
||||
public override byte HandlingTrainerGender { get => Data[0x92]; set => Data[0x92] = value; }
|
||||
public override byte CurrentHandler { get => Data[0x93]; set => Data[0x93] = value; }
|
||||
|
@ -340,7 +340,7 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC
|
|||
public override string OriginalTrainerName
|
||||
{
|
||||
get => StringConverter6.GetString(OriginalTrainerTrash);
|
||||
set => StringConverter6.SetString(OriginalTrainerTrash, value, 12, StringConverterOption.None);
|
||||
set => StringConverter6.SetString(OriginalTrainerTrash, value, 12, Language, StringConverterOption.None);
|
||||
}
|
||||
public override byte OriginalTrainerFriendship { get => Data[0xCA]; set => Data[0xCA] = value; }
|
||||
public byte OriginalTrainerAffection { get => Data[0xCB]; set => Data[0xCB] = value; }
|
||||
|
@ -529,5 +529,5 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC
|
|||
public override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
||||
=> StringConverter6.LoadString(data, destBuffer);
|
||||
public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter6.SetString(destBuffer, value, maxLength, option);
|
||||
=> StringConverter6.SetString(destBuffer, value, maxLength, Language, option);
|
||||
}
|
||||
|
|
|
@ -186,7 +186,12 @@ public sealed class RK4 : G4PKM
|
|||
public override string Nickname
|
||||
{
|
||||
get => StringConverter4.GetString(NicknameTrash);
|
||||
set => StringConverter4.SetString(NicknameTrash, value, 10, StringConverterOption.None);
|
||||
set
|
||||
{
|
||||
var language = Language;
|
||||
CheckKoreanNidoranDPPt(value, ref language);
|
||||
StringConverter4.SetString(NicknameTrash, value, 10, language, StringConverterOption.None);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x5E unused
|
||||
|
@ -234,7 +239,7 @@ public sealed class RK4 : G4PKM
|
|||
public override string OriginalTrainerName
|
||||
{
|
||||
get => StringConverter4.GetString(OriginalTrainerTrash);
|
||||
set => StringConverter4.SetString(OriginalTrainerTrash, value, 7, StringConverterOption.None);
|
||||
set => StringConverter4.SetString(OriginalTrainerTrash, value, 7, Language, StringConverterOption.None);
|
||||
}
|
||||
|
||||
public override byte EggYear { get => Data[0x78]; set => Data[0x78] = value; }
|
||||
|
@ -314,7 +319,7 @@ public sealed class RK4 : G4PKM
|
|||
public override string HandlingTrainerName
|
||||
{
|
||||
get => StringConverter4.GetString(HandlingTrainerTrash);
|
||||
set => StringConverter4.SetString(HandlingTrainerTrash, value, 7, StringConverterOption.None);
|
||||
set => StringConverter4.SetString(HandlingTrainerTrash, value, 7, Language, StringConverterOption.None);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -351,5 +356,5 @@ public sealed class RK4 : G4PKM
|
|||
public override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
||||
=> StringConverter4.LoadString(data, destBuffer);
|
||||
public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter4.SetString(destBuffer, value, maxLength, option);
|
||||
=> StringConverter4.SetString(destBuffer, value, maxLength, Language, option);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
|
@ -497,6 +498,27 @@ public abstract class G4PKM : PKM, IHandlerUpdate,
|
|||
// Strings need to change between Little Endian and Big Endian
|
||||
var s = MemoryMarshal.Cast<byte, ushort>(src);
|
||||
var d = MemoryMarshal.Cast<byte, ushort>(dest);
|
||||
System.Buffers.Binary.BinaryPrimitives.ReverseEndianness(s, d);
|
||||
ReverseEndianness(s, d);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Nidoran originating from Korean D/P/Pt games use the Full-width gender symbols instead of the other Gen4-Gen7 games which use Half-width.
|
||||
/// </summary>
|
||||
/// <seealso cref="PK5.CheckKoreanNidoranDPPt"/>
|
||||
protected void CheckKoreanNidoranDPPt(ReadOnlySpan<char> value, ref int language)
|
||||
{
|
||||
if (language != (int)LanguageID.Korean)
|
||||
return;
|
||||
if (IsNicknamed)
|
||||
return;
|
||||
if (Version is not (GameVersion.D or GameVersion.P or GameVersion.Pt))
|
||||
return;
|
||||
// Full-width gender symbols for not-nicknamed Nidoran in D/P/Pt
|
||||
// Full/Half is technically legal either way as trainers can reset the nickname in HG/SS, or vice versa for origins.
|
||||
// Still try to set whichever it originated with. Default would be half, but if it's a Nidoran species name, set full-width.
|
||||
if (Species == (int)Core.Species.NidoranM && value is "니드런♂")
|
||||
language = 1; // Use Japanese to force full-width encoding of the gender symbol.
|
||||
else if (Species == (int)Core.Species.NidoranF && value is "니드런♀")
|
||||
language = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,30 +76,46 @@ public static class StringConverter
|
|||
byte generation, bool jp, bool isBigEndian, int language = 0) => generation switch
|
||||
{
|
||||
3 when isBigEndian => StringConverter3GC.SetString(destBuffer, value, maxLength, option),
|
||||
4 when isBigEndian => StringConverter4GC.SetString(destBuffer, value, maxLength, option),
|
||||
4 when isBigEndian => StringConverter4GC.SetString(destBuffer, value, maxLength, language, option),
|
||||
|
||||
1 => StringConverter1.SetString(destBuffer, value, maxLength, jp, option),
|
||||
2 => StringConverter2.SetString(destBuffer, value, maxLength, language, option),
|
||||
3 => StringConverter3.SetString(destBuffer, value, maxLength, language, option),
|
||||
4 => StringConverter4.SetString(destBuffer, value, maxLength, option),
|
||||
5 => StringConverter5.SetString(destBuffer, value, maxLength, option),
|
||||
6 => StringConverter6.SetString(destBuffer, value, maxLength, option),
|
||||
4 => StringConverter4.SetString(destBuffer, value, maxLength, language, option),
|
||||
5 => StringConverter5.SetString(destBuffer, value, maxLength, language, option),
|
||||
6 => StringConverter6.SetString(destBuffer, value, maxLength, language, option),
|
||||
7 => StringConverter7.SetString(destBuffer, value, maxLength, language, option),
|
||||
8 => StringConverter8.SetString(destBuffer, value, maxLength, option),
|
||||
9 => StringConverter8.SetString(destBuffer, value, maxLength, option),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(generation)),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Full-width gender 16-bit char representation.
|
||||
/// </summary>
|
||||
public const char FGF = '\u2640'; // '♀'
|
||||
/// <inheritdoc cref="FGM"/>
|
||||
public const char FGM = '\u2642'; // '♂'
|
||||
|
||||
/// <summary>
|
||||
/// Half-width gender 16-bit char representation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Exact value is the value when converted to Generation 6 & 7 encoding.
|
||||
/// Once transferred to the Nintendo Switch era, the value is converted to full-width.
|
||||
/// </remarks>
|
||||
public const char HGM = '\uE08E'; // '♂'
|
||||
/// <inheritdoc cref="HGM"/>
|
||||
public const char HGF = '\uE08F'; // '♀'
|
||||
|
||||
/// <summary>
|
||||
/// Converts full width to single width
|
||||
/// </summary>
|
||||
/// <param name="chr">Input character to sanitize.</param>
|
||||
internal static char SanitizeChar(char chr) => chr switch
|
||||
public static char NormalizeGenderSymbol(char chr) => chr switch
|
||||
{
|
||||
'\uE08F' => '♀',
|
||||
'\uE08E' => '♂',
|
||||
'\u246E' => '♀',
|
||||
'\u246D' => '♂',
|
||||
HGM => FGM, // '♂'
|
||||
HGF => FGF, // '♀'
|
||||
_ => chr,
|
||||
};
|
||||
|
||||
|
@ -108,27 +124,10 @@ public static class StringConverter
|
|||
/// </summary>
|
||||
/// <param name="chr">Input character to set back to data</param>
|
||||
/// <param name="fullWidth">Checks if the overall string is full-width</param>
|
||||
internal static char UnSanitizeChar(char chr, bool fullWidth = false)
|
||||
public static char UnNormalizeGenderSymbol(char chr, bool fullWidth = false) => fullWidth ? chr : chr switch
|
||||
{
|
||||
if (fullWidth) // jp/ko/zh strings
|
||||
return chr; // keep as full width
|
||||
|
||||
return chr switch
|
||||
{
|
||||
'\u2640' => '\uE08F',
|
||||
'\u2642' => '\uE08E',
|
||||
_ => chr,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts full width to half width when appropriate, for Gen5 and prior.
|
||||
/// </summary>
|
||||
/// <param name="chr">Input character to set back to data</param>
|
||||
internal static char UnSanitizeChar5(char chr) => chr switch
|
||||
{
|
||||
'\u2640' => '\u246E',
|
||||
'\u2642' => '\u246D',
|
||||
FGM => HGM, // '♂'
|
||||
FGF => HGF, // '♀'
|
||||
_ => chr,
|
||||
};
|
||||
|
||||
|
@ -143,7 +142,7 @@ public static class StringConverter
|
|||
{
|
||||
if (c >> 12 is (0 or 0xE))
|
||||
continue;
|
||||
if (c is '\u2640' or '\u2642') // ♀♂
|
||||
if (c is FGF or FGM) // ♀♂
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,11 @@ public static class StringConverter3
|
|||
private const byte QuoteLeftByte = 0xB1;
|
||||
private const byte QuoteRightByte = 0xB2;
|
||||
|
||||
private const char FGM = '♂';
|
||||
private const char FGF = '♀';
|
||||
private const char HGM = StringConverter4Util.HGM; // '♂'
|
||||
private const char HGF = StringConverter4Util.HGF; // '♀'
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Generation 3 encoded value array to string.
|
||||
/// </summary>
|
||||
|
@ -53,7 +58,7 @@ public static class StringConverter3
|
|||
}; // Convert to Unicode
|
||||
if (c == Terminator) // Stop if Terminator/Invalid
|
||||
break;
|
||||
c = StringConverter.SanitizeChar(c);
|
||||
c = StringConverter4Util.NormalizeGenderSymbol(c);
|
||||
result[i] = c;
|
||||
}
|
||||
return i;
|
||||
|
@ -84,12 +89,15 @@ public static class StringConverter3
|
|||
else if (option is StringConverterOption.ClearZero)
|
||||
buffer.Clear();
|
||||
|
||||
var table = (language == (int)LanguageID.Japanese) ? G3_JP : G3_EN;
|
||||
bool jp = language == (int)LanguageID.Japanese;
|
||||
var table = jp ? G3_JP : G3_EN;
|
||||
int i = 0;
|
||||
for (; i < value.Length; i++)
|
||||
{
|
||||
var c = StringConverter.UnSanitizeChar5(value[i]);
|
||||
if (!TryGetIndex(table, c, language, out var b))
|
||||
var chr = value[i];
|
||||
if (!jp)
|
||||
chr = StringConverter4Util.UnNormalizeGenderSymbol(chr);
|
||||
if (!TryGetIndex(table, chr, language, out var b))
|
||||
break;
|
||||
buffer[i] = b;
|
||||
}
|
||||
|
@ -193,7 +201,7 @@ public static class StringConverter3
|
|||
'ィ', 'ゥ', 'ェ', 'ォ', 'ャ', 'ュ', 'ョ', 'ガ', 'ギ', 'グ', 'ゲ', 'ゴ', 'ザ', 'ジ', 'ズ', 'ゼ', // 8
|
||||
'ゾ', 'ダ', 'ヂ', 'ヅ', 'デ', 'ド', 'バ', 'ビ', 'ブ', 'ベ', 'ボ', 'パ', 'ピ', 'プ', 'ペ', 'ポ', // 9
|
||||
'ッ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '?', '.', '-', '・',// A
|
||||
'⑬', '“', '”', '‘', '’', '⑭', '⑮', '$', ',', '⑧', '/', 'A', 'B', 'C', 'D', 'E', // B
|
||||
'⑬', '“', '”', '‘', '’', HGM, HGF, '$', ',', '⑧', '/', 'A', 'B', 'C', 'D', 'E', // B
|
||||
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', // C
|
||||
'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', // D
|
||||
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '►', // E
|
||||
|
@ -216,7 +224,7 @@ public static class StringConverter3
|
|||
'ィ', 'ゥ', 'ェ', 'ォ', 'ャ', 'ュ', 'ョ', 'ガ', 'ギ', 'グ', 'ゲ', 'ゴ', 'ザ', 'ジ', 'ズ', 'ゼ', // 8
|
||||
'ゾ', 'ダ', 'ヂ', 'ヅ', 'デ', 'ド', 'バ', 'ビ', 'ブ', 'ベ', 'ボ', 'パ', 'ピ', 'プ', 'ペ', 'ポ', // 9
|
||||
'ッ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '?', '。', 'ー', '・', // A
|
||||
'…', '『', '』', '「', '」', '♂', '♀', '円', '.', '×', '/', 'A', 'B', 'C', 'D', 'E', // B
|
||||
'…', '『', '』', '「', '」', FGM, FGF, '円', '.', '×', '/', 'A', 'B', 'C', 'D', 'E', // B
|
||||
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', // C
|
||||
'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', // D
|
||||
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '►', // E
|
||||
|
|
|
@ -31,7 +31,7 @@ public static class StringConverter345
|
|||
{
|
||||
Span<char> result = stackalloc char[data.Length];
|
||||
int count = TransferGlyphs34(data, result, language, maxLength);
|
||||
StringConverter4.SetString(dest, result[..count], maxLength, StringConverterOption.None);
|
||||
StringConverter4.SetString(dest, result[..count], maxLength, language, StringConverterOption.None);
|
||||
}
|
||||
|
||||
private static int TransferGlyphs34(ReadOnlySpan<byte> data, Span<char> result, int language, int maxLength)
|
||||
|
|
|
@ -28,25 +28,27 @@ public static class StringConverter4
|
|||
public static int LoadString(ReadOnlySpan<byte> data, Span<char> result)
|
||||
{
|
||||
int i = 0;
|
||||
int ctr = 0;
|
||||
for (; i < data.Length; i += 2)
|
||||
{
|
||||
var value = ReadUInt16LittleEndian(data[i..]);
|
||||
if (value == Terminator)
|
||||
break;
|
||||
char chr = (char)ConvertValue2CharG4(value);
|
||||
chr = StringConverter.SanitizeChar(chr);
|
||||
result[i/2] = chr;
|
||||
chr = NormalizeGenderSymbol(chr);
|
||||
result[ctr++] = chr;
|
||||
}
|
||||
return i/2;
|
||||
return ctr;
|
||||
}
|
||||
|
||||
/// <summary>Gets the bytes for a 4th Generation String</summary>
|
||||
/// <param name="destBuffer">Span of bytes to write encoded string data</param>
|
||||
/// <param name="value">Decoded string.</param>
|
||||
/// <param name="maxLength">Maximum length of the input <see cref="value"/></param>
|
||||
/// <param name="language">Language specific conversion</param>
|
||||
/// <param name="option">Buffer pre-formatting option</param>
|
||||
/// <returns>Encoded data.</returns>
|
||||
public static int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength,
|
||||
public static int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, int language,
|
||||
StringConverterOption option = StringConverterOption.ClearZero)
|
||||
{
|
||||
if (value.Length > maxLength)
|
||||
|
@ -55,10 +57,12 @@ public static class StringConverter4
|
|||
if (option is StringConverterOption.ClearZero)
|
||||
destBuffer.Clear();
|
||||
|
||||
bool isHalfWidth = language == (int)LanguageID.Korean || !StringConverter.GetIsFullWidthString(value);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
var chr = value[i];
|
||||
chr = StringConverter.UnSanitizeChar5(chr);
|
||||
if (isHalfWidth)
|
||||
chr = UnNormalizeGenderSymbol(chr);
|
||||
ushort val = ConvertChar2ValueG4(chr);
|
||||
WriteUInt16LittleEndian(destBuffer[(i * 2)..], val);
|
||||
}
|
||||
|
|
|
@ -31,16 +31,17 @@ public static class StringConverter4GC
|
|||
public static int LoadString(ReadOnlySpan<byte> data, Span<char> result)
|
||||
{
|
||||
int i = 0;
|
||||
int ctr = 0;
|
||||
for (; i < data.Length; i += 2)
|
||||
{
|
||||
var value = ReadUInt16BigEndian(data[i..]);
|
||||
if (value == Terminator)
|
||||
break;
|
||||
char chr = (char)ConvertValue2CharG4(value);
|
||||
chr = StringConverter.SanitizeChar(chr);
|
||||
result[i/2] = chr;
|
||||
chr = NormalizeGenderSymbol(chr);
|
||||
result[ctr++] = chr;
|
||||
}
|
||||
return i/2;
|
||||
return ctr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -49,9 +50,10 @@ public static class StringConverter4GC
|
|||
/// <param name="destBuffer">Span of bytes to write encoded string data</param>
|
||||
/// <param name="value">String to be converted.</param>
|
||||
/// <param name="maxLength">Maximum length of string</param>
|
||||
/// <param name="language">Language specific conversion</param>
|
||||
/// <param name="option">Buffer pre-formatting option</param>
|
||||
/// <returns>Byte array containing encoded character data</returns>
|
||||
public static int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength,
|
||||
public static int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, int language,
|
||||
StringConverterOption option = StringConverterOption.ClearZero)
|
||||
{
|
||||
if (value.Length > maxLength)
|
||||
|
@ -60,10 +62,12 @@ public static class StringConverter4GC
|
|||
if (option is StringConverterOption.ClearZero)
|
||||
destBuffer.Clear();
|
||||
|
||||
bool isHalfWidth = language == (int)LanguageID.Korean || !StringConverter.GetIsFullWidthString(value);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
var chr = value[i];
|
||||
chr = StringConverter.UnSanitizeChar5(chr);
|
||||
if (isHalfWidth)
|
||||
chr = UnNormalizeGenderSymbol(chr);
|
||||
ushort val = ConvertChar2ValueG4(chr);
|
||||
WriteUInt16BigEndian(destBuffer[(i * 2)..], val);
|
||||
}
|
||||
|
@ -95,15 +99,15 @@ public static class StringConverter4GC
|
|||
public static int LoadStringUnicode(ReadOnlySpan<byte> data, Span<char> result)
|
||||
{
|
||||
int i = 0;
|
||||
int ctr = 0;
|
||||
for (; i < data.Length; i += 2)
|
||||
{
|
||||
char chr = (char)ReadUInt16BigEndian(data[i..]);
|
||||
if (chr == TerminatorChar)
|
||||
break;
|
||||
chr = StringConverter.SanitizeChar(chr);
|
||||
result[i/2] = chr;
|
||||
result[ctr++] = chr;
|
||||
}
|
||||
return i/2;
|
||||
return ctr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -126,7 +130,6 @@ public static class StringConverter4GC
|
|||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
var c = value[i];
|
||||
c = StringConverter.UnSanitizeChar5(c);
|
||||
WriteUInt16BigEndian(destBuffer[(i * 2)..], c);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,37 @@ public static class StringConverter4Util
|
|||
private const char NUL = (char)StringConverter4.Terminator;
|
||||
private const char EMP = NUL; // Empty, not available on keyboard.
|
||||
|
||||
/// <summary>
|
||||
/// Half-width gender 16-bit char representation.
|
||||
/// </summary>
|
||||
/// <remarks>Exact value is the value when converted to Generation 5's encoding.</remarks>
|
||||
public const char HGM = '\u246D'; // '♂'
|
||||
/// <inheritdoc cref="HGM"/>
|
||||
public const char HGF = '\u246E'; // '♀'
|
||||
|
||||
/// <summary>
|
||||
/// Converts full width to single width from the 0x246D/0x246E characters.
|
||||
/// </summary>
|
||||
/// <param name="chr">Input character to sanitize.</param>
|
||||
public static char NormalizeGenderSymbol(char chr) => chr switch
|
||||
{
|
||||
HGM => '♂',
|
||||
HGF => '♀',
|
||||
_ => chr,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Converts full width to half width when appropriate
|
||||
/// </summary>
|
||||
/// <param name="chr">Input character to set back to data</param>
|
||||
/// <param name="fullWidth">Checks if the overall string is full-width</param>
|
||||
public static char UnNormalizeGenderSymbol(char chr, bool fullWidth = false) => fullWidth ? chr : chr switch
|
||||
{
|
||||
'♂' => HGM,
|
||||
'♀' => HGF,
|
||||
_ => chr,
|
||||
};
|
||||
|
||||
public static ReadOnlySpan<char> TableINT =>
|
||||
[
|
||||
NUL, ' ', 'ぁ', 'あ', 'ぃ', 'い', 'ぅ', 'う', 'ぇ', 'え', 'ぉ', 'お', 'か', 'が', 'き', 'ぎ', // 000-00F
|
||||
|
@ -101,7 +132,7 @@ public static class StringConverter4Util
|
|||
'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ð', // 180-18F
|
||||
'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '⑨', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ', 'Œ', // 190-19F
|
||||
'œ', 'Ş', 'ş', 'ª', 'º', '⑩', '⑪', '⑫', '$', '¡', '¿', '!', '?', ',', '.', '⑬', // 1A0-1AF
|
||||
'・', '/', '‘', '’', '“', '”', '„', '«', '»', '(', ')', '⑭', '⑮', '+', '-', '*', // 1B0-1BF
|
||||
'・', '/', '‘', '’', '“', '”', '„', '«', '»', '(', ')', HGM, HGF, '+', '-', '*', // 1B0-1BF
|
||||
'#', '=', '&', '~', ':', ';', '⑯', '⑰', '⑱', '⑲', '⑳', '⑴', '⑵', '⑶', '⑷', '⑸', // 1C0-1CF
|
||||
'@', '⑹', '%', '⑺', '⑻', '⑼', '⑽', '⑾', '⑿', '⒀', '⒁', '⒂', '⒃', '⒄', ' ', '⒅', // 1D0-1DF
|
||||
'⒆', '⒇', '⒈', '⒉', '⒊', '⒋', '⒌', '⒍', '°', '_', '_', '⒎', '⒏', // 1E0-1EC*
|
||||
|
|
|
@ -27,23 +27,25 @@ public static class StringConverter5
|
|||
public static int LoadString(ReadOnlySpan<byte> data, Span<char> result)
|
||||
{
|
||||
int i = 0;
|
||||
int ctr = 0;
|
||||
for (; i < data.Length; i += 2)
|
||||
{
|
||||
var value = ReadUInt16LittleEndian(data[i..]);
|
||||
if (value == TerminatorFFFF)
|
||||
break;
|
||||
result[i/2] = StringConverter.SanitizeChar((char)value);
|
||||
result[ctr++] = (char)value;
|
||||
}
|
||||
return i/2;
|
||||
return ctr;
|
||||
}
|
||||
|
||||
/// <summary>Gets the bytes for a Generation 5 string.</summary>
|
||||
/// <param name="destBuffer">Span of bytes to write encoded string data</param>
|
||||
/// <param name="value">Decoded string.</param>
|
||||
/// <param name="maxLength">Maximum length of the input <see cref="value"/></param>
|
||||
/// <param name="language">Language specific conversion</param>
|
||||
/// <param name="option">Buffer pre-formatting option</param>
|
||||
/// <returns>Encoded data.</returns>
|
||||
public static int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength,
|
||||
public static int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, int language,
|
||||
StringConverterOption option = StringConverterOption.ClearZero)
|
||||
{
|
||||
if (value.Length > maxLength)
|
||||
|
@ -54,11 +56,13 @@ public static class StringConverter5
|
|||
else if (option is StringConverterOption.ClearFF)
|
||||
destBuffer.Fill(0xFF);
|
||||
|
||||
bool isHalfWidth = language == (int)LanguageID.Korean || !StringConverter.GetIsFullWidthString(value);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
char c = value[i];
|
||||
ushort val = StringConverter.UnSanitizeChar5(c);
|
||||
WriteUInt16LittleEndian(destBuffer[(i * 2)..], val);
|
||||
var chr = value[i];
|
||||
if (isHalfWidth)
|
||||
chr = StringConverter4Util.UnNormalizeGenderSymbol(chr);
|
||||
WriteUInt16LittleEndian(destBuffer[(i * 2)..], chr);
|
||||
}
|
||||
|
||||
int count = value.Length * 2;
|
||||
|
|
|
@ -28,23 +28,26 @@ public static class StringConverter6
|
|||
public static int LoadString(ReadOnlySpan<byte> data, Span<char> result)
|
||||
{
|
||||
int i = 0;
|
||||
int ctr = 0;
|
||||
for (; i < data.Length; i += 2)
|
||||
{
|
||||
var value = ReadUInt16LittleEndian(data[i..]);
|
||||
if (value == TerminatorNull)
|
||||
break;
|
||||
result[i/2] = StringConverter.SanitizeChar((char)value);
|
||||
result[ctr++] = StringConverter.NormalizeGenderSymbol((char)value);
|
||||
}
|
||||
return i/2;
|
||||
return ctr;
|
||||
}
|
||||
|
||||
/// <summary>Gets the bytes for a Generation 6 string.</summary>
|
||||
/// <param name="destBuffer">Span of bytes to write encoded string data</param>
|
||||
/// <param name="value">Decoded string.</param>
|
||||
/// <param name="maxLength">Maximum length of the input <see cref="value"/></param>
|
||||
/// <param name="language">Language specific conversion</param>
|
||||
/// <param name="option">Buffer pre-formatting option</param>
|
||||
/// <returns>Encoded data.</returns>
|
||||
public static int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength,
|
||||
int language,
|
||||
StringConverterOption option = StringConverterOption.ClearZero)
|
||||
{
|
||||
if (value.Length > maxLength)
|
||||
|
@ -53,13 +56,13 @@ public static class StringConverter6
|
|||
if (option is StringConverterOption.ClearZero)
|
||||
destBuffer.Clear();
|
||||
|
||||
bool isFullWidth = StringConverter.GetIsFullWidthString(value);
|
||||
bool isHalfWidth = language == (int)LanguageID.Korean || !StringConverter.GetIsFullWidthString(value);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
char c = value[i];
|
||||
if (!isFullWidth)
|
||||
c = StringConverter.UnSanitizeChar(c);
|
||||
WriteUInt16LittleEndian(destBuffer[(i * 2)..], c);
|
||||
var chr = value[i];
|
||||
if (isHalfWidth)
|
||||
chr = StringConverter.UnNormalizeGenderSymbol(chr);
|
||||
WriteUInt16LittleEndian(destBuffer[(i * 2)..], chr);
|
||||
}
|
||||
|
||||
int count = value.Length * 2;
|
||||
|
|
|
@ -28,24 +28,25 @@ public static class StringConverter7
|
|||
public static int LoadString(ReadOnlySpan<byte> data, Span<char> result)
|
||||
{
|
||||
int i = 0;
|
||||
int ctr = 0;
|
||||
for (; i < data.Length; i += 2)
|
||||
{
|
||||
var value = ReadUInt16LittleEndian(data[i..]);
|
||||
var value = (char)ReadUInt16LittleEndian(data[i..]);
|
||||
if (value == TerminatorNull)
|
||||
break;
|
||||
result[i/2] = StringConverter.SanitizeChar((char)value);
|
||||
}
|
||||
|
||||
var span = result[..(i/2)];
|
||||
StringConverter7ZH.RemapChineseGlyphsBin2String(span);
|
||||
return i/2;
|
||||
result[ctr++] = StringConverter7ZH.IsPrivateChar(value)
|
||||
? StringConverter7ZH.GetUnicodeChar(value)
|
||||
: StringConverter.NormalizeGenderSymbol(value);
|
||||
}
|
||||
return ctr;
|
||||
}
|
||||
|
||||
/// <summary>Gets the bytes for a Generation 7 string.</summary>
|
||||
/// <param name="destBuffer">Span of bytes to write encoded string data</param>
|
||||
/// <param name="value">Decoded string.</param>
|
||||
/// <param name="maxLength">Maximum length of the input <see cref="value"/></param>
|
||||
/// <param name="language">Language specific conversion (Chinese)</param>
|
||||
/// <param name="language">Language specific conversion</param>
|
||||
/// <param name="option">Buffer pre-formatting option</param>
|
||||
/// <param name="chinese">Chinese string remapping should be attempted (only Pokémon names, without Nickname flag set)</param>
|
||||
/// <returns>Encoded data.</returns>
|
||||
|
@ -58,15 +59,15 @@ public static class StringConverter7
|
|||
if (option is StringConverterOption.ClearZero)
|
||||
destBuffer.Clear();
|
||||
|
||||
bool isFullWidth = StringConverter.GetIsFullWidthString(value);
|
||||
bool isHalfWidth = language == (int)LanguageID.Korean || !StringConverter.GetIsFullWidthString(value);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
char c = value[i];
|
||||
if (!isFullWidth)
|
||||
c = StringConverter.UnSanitizeChar(c);
|
||||
var chr = value[i];
|
||||
if (isHalfWidth)
|
||||
chr = StringConverter.UnNormalizeGenderSymbol(chr);
|
||||
if (chinese)
|
||||
c = StringConverter7ZH.GetPrivateChar(c, language == (int)LanguageID.ChineseT);
|
||||
WriteUInt16LittleEndian(destBuffer[(i * 2)..], c);
|
||||
chr = StringConverter7ZH.GetPrivateChar(chr, language == (int)LanguageID.ChineseT);
|
||||
WriteUInt16LittleEndian(destBuffer[(i * 2)..], chr);
|
||||
}
|
||||
|
||||
int count = value.Length * 2;
|
||||
|
|
|
@ -12,8 +12,8 @@ namespace PKHeX.Core;
|
|||
/// </remarks>
|
||||
public static class StringConverter7ZH
|
||||
{
|
||||
private static bool IsPrivateChar(ushort glyph) => glyph is >= Start and <= End;
|
||||
private static char GetUnicodeChar(char glyph) => Table[glyph - Start];
|
||||
internal static bool IsPrivateChar(ushort glyph) => glyph is >= Start and <= End;
|
||||
internal static char GetUnicodeChar(char glyph) => Table[glyph - Start];
|
||||
|
||||
public static bool IsTraditional(ushort glyph) => glyph is (>= StartTraditional and <= EndTraditional) or (>= StartTraditionalUSUM and <= EndTraditionalUSUM);
|
||||
public static bool IsSimplified(ushort glyph) => glyph is (>= StartSimplified and <= EndSimplified) or (>= StartSimplifiedUSUM and <= EndSimplifiedUSUM);
|
||||
|
@ -50,21 +50,6 @@ public static class StringConverter7ZH
|
|||
return chr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Generation 7 in-game Chinese string to Unicode string.
|
||||
/// </summary>
|
||||
/// <param name="input">In-game Chinese string.</param>
|
||||
/// <returns>Unicode string.</returns>
|
||||
internal static void RemapChineseGlyphsBin2String(Span<char> input)
|
||||
{
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
var val = input[i];
|
||||
if (IsPrivateChar(val))
|
||||
input[i] = GetUnicodeChar(val);
|
||||
}
|
||||
}
|
||||
|
||||
#region Gen 7 Chinese Character Table
|
||||
private const ushort Start = 0xE800;
|
||||
|
||||
|
|
|
@ -137,4 +137,33 @@ public static class StringConverter8
|
|||
WriteCharacters(expect, under);
|
||||
return relevantSection.SequenceEqual(expect);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used when importing a 3DS string into HOME.
|
||||
/// </summary>
|
||||
public static void NormalizeHalfWidth(Span<byte> str)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
var u16 = MemoryMarshal.Cast<byte, char>(str);
|
||||
foreach (ref var c in u16)
|
||||
{
|
||||
if (c == TerminatorNull)
|
||||
return;
|
||||
c = NormalizeHalfWidth(c);
|
||||
}
|
||||
}
|
||||
|
||||
// Slower path for Big-Endian runtimes.
|
||||
for (int i = 0; i < str.Length; i += 2)
|
||||
{
|
||||
var data = str[i..];
|
||||
var c = ReadUInt16LittleEndian(data);
|
||||
if (c == TerminatorNull)
|
||||
return;
|
||||
WriteUInt16LittleEndian(data, NormalizeHalfWidth((char)c));
|
||||
}
|
||||
}
|
||||
|
||||
private static char NormalizeHalfWidth(char str) => StringConverter.NormalizeGenderSymbol(str);
|
||||
}
|
||||
|
|
|
@ -483,7 +483,7 @@ public abstract class SAV4 : SaveFile, IEventFlag37, IDaycareStorage, IDaycareRa
|
|||
public sealed override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
||||
=> StringConverter4.LoadString(data, destBuffer);
|
||||
public sealed override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter4.SetString(destBuffer, value, maxLength, option);
|
||||
=> StringConverter4.SetString(destBuffer, value, maxLength, Language, option);
|
||||
|
||||
#region Event Flag/Event Work
|
||||
public bool GetEventFlag(int flagNumber)
|
||||
|
|
|
@ -122,7 +122,7 @@ public abstract class SAV5 : SaveFile, ISaveBlock5BW, IEventFlagProvider37, IBox
|
|||
public sealed override int LoadString(ReadOnlySpan<byte> data, Span<char> result)
|
||||
=> StringConverter5.LoadString(data, result);
|
||||
public sealed override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter5.SetString(destBuffer, value, maxLength, option);
|
||||
=> StringConverter5.SetString(destBuffer, value, maxLength, Language, option);
|
||||
|
||||
// DLC
|
||||
private int CGearSkinInfoOffset => CGearInfoOffset + (this is SAV5B2W2 ? 0x10 : 0) + 0x24;
|
||||
|
|
|
@ -143,7 +143,7 @@ public abstract class SAV6 : SAV_BEEF, ITrainerStatRecord, ISaveBlock6Core, IReg
|
|||
public sealed override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
||||
=> StringConverter6.LoadString(data, destBuffer);
|
||||
public sealed override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter6.SetString(destBuffer, value, maxLength, option);
|
||||
=> StringConverter6.SetString(destBuffer, value, maxLength, Language, option);
|
||||
|
||||
public int GetRecord(int recordID) => Records.GetRecord(recordID);
|
||||
public int GetRecordOffset(int recordID) => Records.GetRecordOffset(recordID);
|
||||
|
|
|
@ -30,13 +30,13 @@ public sealed class BattleVideo6(byte[] Data) : IBattleVideo
|
|||
public string Debug1
|
||||
{
|
||||
get => StringConverter6.GetString(Data.AsSpan(0x6, 0x1A));
|
||||
set => StringConverter6.SetString(Data.AsSpan(0x6, 0x1A), value, 12, StringConverterOption.ClearZero);
|
||||
set => StringConverter6.SetString(Data.AsSpan(0x6, 0x1A), value, 12, 0, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public string Debug2
|
||||
{
|
||||
get => StringConverter6.GetString(Data.AsSpan(0x50, 0x1A));
|
||||
set => StringConverter6.SetString(Data.AsSpan(0x50, 0x1A), value, 12, StringConverterOption.ClearZero);
|
||||
set => StringConverter6.SetString(Data.AsSpan(0x50, 0x1A), value, 12, 0, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public ulong RNGConst1 { get => ReadUInt64LittleEndian(Data.AsSpan(0x1A0)); set => WriteUInt64LittleEndian(Data.AsSpan(0x1A0), value); }
|
||||
|
@ -70,7 +70,7 @@ public sealed class BattleVideo6(byte[] Data) : IBattleVideo
|
|||
{
|
||||
var span = Data.AsSpan(0xEC + (0x1A * i), 0x1A);
|
||||
string tr = value[i] == NPC ? string.Empty : value[i];
|
||||
StringConverter6.SetString(span, tr, 12, StringConverterOption.ClearZero);
|
||||
StringConverter6.SetString(span, tr, 12, 0, StringConverterOption.ClearZero);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ using static System.Buffers.Binary.BinaryPrimitives;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public sealed class Dendou4(Memory<byte> raw)
|
||||
public sealed class Dendou4(Memory<byte> raw, int language)
|
||||
{
|
||||
private const int SIZE = 0x2AB0;
|
||||
private const int SIZE_FOOTER = 0x10;
|
||||
|
@ -25,7 +25,7 @@ public sealed class Dendou4(Memory<byte> raw)
|
|||
{
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<uint>((uint)index, MaxRecords);
|
||||
var slice = Data.Slice(index * Dendou4Record.SIZE, Dendou4Record.SIZE);
|
||||
return new Dendou4Record(slice);
|
||||
return new Dendou4Record(slice, language);
|
||||
}
|
||||
|
||||
private const int EndDataOffset = MaxRecords * Dendou4Record.SIZE; // 0x2AA8
|
||||
|
@ -63,9 +63,14 @@ public readonly ref struct Dendou4Record
|
|||
// u8 Day
|
||||
|
||||
private readonly Span<byte> Data;
|
||||
private readonly int Language;
|
||||
|
||||
// ReSharper disable once ConvertToPrimaryConstructor
|
||||
public Dendou4Record(Span<byte> data) => Data = data;
|
||||
public Dendou4Record(Span<byte> data, int language)
|
||||
{
|
||||
Data = data;
|
||||
Language = language;
|
||||
}
|
||||
|
||||
public Dendou4Entity this[int index] => GetEntity(index);
|
||||
|
||||
|
@ -78,7 +83,7 @@ public readonly ref struct Dendou4Record
|
|||
{
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<uint>((uint)index, Count);
|
||||
var slice = Data.Slice(index * Dendou4Entity.SIZE, Dendou4Entity.SIZE);
|
||||
return new Dendou4Entity(slice);
|
||||
return new Dendou4Entity(slice, Language);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,9 +91,15 @@ public readonly ref struct Dendou4Entity
|
|||
{
|
||||
public const int SIZE = 0x3C;
|
||||
private readonly Span<byte> Data;
|
||||
private readonly int Language;
|
||||
|
||||
// ReSharper disable once ConvertToPrimaryConstructor
|
||||
public Dendou4Entity(Span<byte> data) => Data = data;
|
||||
public Dendou4Entity(Span<byte> data, int language)
|
||||
{
|
||||
Data = data;
|
||||
Language = language;
|
||||
}
|
||||
|
||||
public ushort Species { get => ReadUInt16LittleEndian(Data); set => WriteUInt16LittleEndian(Data, value); }
|
||||
public byte Level { get => Data[2]; set => Data[2] = value; }
|
||||
public byte Form { get => Data[3]; set => Data[3] = value; }
|
||||
|
@ -100,12 +111,12 @@ public readonly ref struct Dendou4Entity
|
|||
public string Nickname
|
||||
{
|
||||
get => StringConverter4.GetString(NicknameTrash);
|
||||
set => StringConverter4.SetString(NicknameTrash, value, 10, StringConverterOption.None);
|
||||
set => StringConverter4.SetString(NicknameTrash, value, 10, Language, StringConverterOption.None);
|
||||
}
|
||||
public string OriginalTrainerName
|
||||
{
|
||||
get => StringConverter4.GetString(OriginalTrainerTrash);
|
||||
set => StringConverter4.SetString(OriginalTrainerTrash, value, 7, StringConverterOption.None);
|
||||
set => StringConverter4.SetString(OriginalTrainerTrash, value, 7, 0, StringConverterOption.None);
|
||||
}
|
||||
|
||||
public ushort Move1 { get => ReadUInt16LittleEndian(Data[0x32..]); set => WriteUInt16LittleEndian(Data[0x32..], value); }
|
||||
|
|
|
@ -23,9 +23,11 @@ public sealed class RanchTrainerMii(byte[] Data)
|
|||
// 0x28-29: ??
|
||||
// 0x2A-2B: ??
|
||||
|
||||
private static byte Language => 0;
|
||||
|
||||
public string TrainerName
|
||||
{
|
||||
get => StringConverter4.GetString(Trainer_Trash);
|
||||
set => StringConverter4.SetString(Trainer_Trash, value, 7);
|
||||
set => StringConverter4.SetString(Trainer_Trash, value, 7, Language);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,14 @@ public readonly ref struct HallFame6Entity
|
|||
{
|
||||
public const int SIZE = 0x48;
|
||||
private readonly Span<byte> Data;
|
||||
private readonly int Language;
|
||||
|
||||
// ReSharper disable once ConvertToPrimaryConstructor
|
||||
public HallFame6Entity(Span<byte> data) => Data = data;
|
||||
public HallFame6Entity(Span<byte> data, int language)
|
||||
{
|
||||
Data = data;
|
||||
Language = language;
|
||||
}
|
||||
|
||||
public ushort Species { get => ReadUInt16LittleEndian(Data); set => WriteUInt16LittleEndian(Data, value); }
|
||||
public ushort HeldItem { get => ReadUInt16LittleEndian(Data[0x02..]); set => WriteUInt16LittleEndian(Data[0x02..], value); }
|
||||
|
@ -48,13 +54,13 @@ public readonly ref struct HallFame6Entity
|
|||
public string Nickname
|
||||
{
|
||||
get => StringConverter6.GetString(Nick_Trash);
|
||||
set => StringConverter6.SetString(Nick_Trash, value, 12, Option);
|
||||
set => StringConverter6.SetString(Nick_Trash, value, 12, Language, Option);
|
||||
}
|
||||
|
||||
public string OriginalTrainerName
|
||||
{
|
||||
get => StringConverter6.GetString(OriginalTrainerTrash);
|
||||
set => StringConverter6.SetString(OriginalTrainerTrash, value, 12, Option);
|
||||
set => StringConverter6.SetString(OriginalTrainerTrash, value, 12, Language, Option);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,15 +80,17 @@ public class SecretBase6(Memory<byte> raw)
|
|||
private const int NameLength = (0x1A / 2) - 1; // + terminator
|
||||
private const int MessageLength = (0x22 / 2) - 1; // + terminator
|
||||
|
||||
private static int Language => 0;
|
||||
|
||||
public string TrainerName
|
||||
{
|
||||
get => StringConverter6.GetString(Data.Slice(0x21A, NameLengthBytes));
|
||||
set => StringConverter6.SetString(Data.Slice(0x21A, NameLengthBytes), value, NameLength, StringConverterOption.ClearZero);
|
||||
set => StringConverter6.SetString(Data.Slice(0x21A, NameLengthBytes), value, NameLength, Language, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
private Span<byte> GetMessageSpan(int index) => Data.Slice(0x234 + (MessageLengthBytes * index), MessageLengthBytes);
|
||||
private string GetMessage(int index) => StringConverter6.GetString(GetMessageSpan(index));
|
||||
private void SetMessage(int index, ReadOnlySpan<char> value) => StringConverter6.SetString(GetMessageSpan(index), value, MessageLength, StringConverterOption.ClearZero);
|
||||
private void SetMessage(int index, ReadOnlySpan<char> value) => StringConverter6.SetString(GetMessageSpan(index), value, MessageLength, Language, StringConverterOption.ClearZero);
|
||||
|
||||
public string TeamName { get => GetMessage(0); set => SetMessage(0, value); }
|
||||
public string TeamSlogan { get => GetMessage(1); set => SetMessage(1, value); }
|
||||
|
|
|
@ -35,8 +35,8 @@ public static class UgItemUtil
|
|||
}
|
||||
|
||||
#region Table
|
||||
private static readonly IReadOnlyList<UgItemDef> Items = new UgItemDef[]
|
||||
{
|
||||
private static readonly IReadOnlyList<UgItemDef> Items =
|
||||
[
|
||||
new(000,000,000,000,000), // None
|
||||
new(001, -1,001, -1, -1), // Red Sphere S
|
||||
new(002, -1,002, -1, -1), // Blue Sphere S
|
||||
|
@ -994,6 +994,6 @@ public static class UgItemUtil
|
|||
new(954, -1, -1, -1, -1), //
|
||||
new(955, -1, -1, -1, -1), //
|
||||
new(956, -1, -1, -1, -1), //
|
||||
};
|
||||
];
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public sealed class Mail4 : MailDetail
|
|||
public override byte AuthorLanguage { get => Data[5]; set => Data[5] = value; }
|
||||
public override byte AuthorVersion { get => Data[6]; set => Data[6] = value; }
|
||||
public override int MailType { get => Data[7]; set => Data[7] = (byte)value; }
|
||||
public override string AuthorName { get => StringConverter4.GetString(Data.AsSpan(8, 0x10)); set => StringConverter4.SetString(Data.AsSpan(8, 0x10), value, 7, StringConverterOption.ClearFF); }
|
||||
public override string AuthorName { get => StringConverter4.GetString(Data.AsSpan(8, 0x10)); set => StringConverter4.SetString(Data.AsSpan(8, 0x10), value, 7, AuthorLanguage, StringConverterOption.ClearFF); }
|
||||
public ushort GetAppearSpecies(int index) => ReadUInt16LittleEndian(Data.AsSpan(0x1C - (index * 2)));
|
||||
public void SetAppearSpecies(int index, ushort value) => WriteUInt16LittleEndian(Data.AsSpan(0x1C - (index * 2)), (ushort)(value == 0 ? 0xFFFF : value));
|
||||
public override ushort GetMessage(int index1, int index2) => ReadUInt16LittleEndian(Data.AsSpan(0x20 + (((index1 * 4) + index2) * 2)));
|
||||
|
|
|
@ -40,7 +40,7 @@ public sealed class Mail5 : MailDetail
|
|||
public override byte AuthorLanguage { get => Data[5]; set => Data[5] = value; }
|
||||
public override byte AuthorVersion { get => Data[6]; set => Data[6] = value; }
|
||||
public override int MailType { get => Data[7]; set => Data[7] = (byte)value; }
|
||||
public override string AuthorName { get => StringConverter5.GetString(Data.AsSpan(8, 0x10)); set => StringConverter5.SetString(Data.AsSpan(8, 0x10), value, 7, StringConverterOption.ClearZero); }
|
||||
public override string AuthorName { get => StringConverter5.GetString(Data.AsSpan(8, 0x10)); set => StringConverter5.SetString(Data.AsSpan(8, 0x10), value, 7, AuthorLanguage, StringConverterOption.ClearZero); }
|
||||
public int GetMisc(int index) => ReadUInt16LittleEndian(Data.AsSpan(0x1C - (index * 2)));
|
||||
public void SetMisc(int index, int value) => WriteUInt16LittleEndian(Data.AsSpan(0x1C - (index * 2)), (ushort)value);
|
||||
public ushort MessageEnding { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), value); }
|
||||
|
|
|
@ -120,7 +120,7 @@ public partial class SAV_HallOfFame : Form
|
|||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
var slice = data[(i * HallFame6Entity.SIZE)..];
|
||||
var entry = new HallFame6Entity(slice);
|
||||
var entry = new HallFame6Entity(slice, SAV.Language);
|
||||
if (entry.Species == 0)
|
||||
continue;
|
||||
moncount++;
|
||||
|
@ -156,7 +156,7 @@ public partial class SAV_HallOfFame : Form
|
|||
int index = LB_DataEntry.SelectedIndex;
|
||||
var member = (Convert.ToInt32(NUP_PartyIndex.Value) - 1);
|
||||
var slice = Fame.GetEntity(index, member);
|
||||
var entry = new HallFame6Entity(slice);
|
||||
var entry = new HallFame6Entity(slice, SAV.Language);
|
||||
CB_Species.SelectedValue = (int)entry.Species;
|
||||
CB_HeldItem.SelectedValue = (int)entry.HeldItem;
|
||||
CB_Move1.SelectedValue = (int)entry.Move1;
|
||||
|
@ -196,7 +196,7 @@ public partial class SAV_HallOfFame : Form
|
|||
int member = Convert.ToInt32(NUP_PartyIndex.Value) - 1;
|
||||
|
||||
var slice = Fame.GetEntity(index, member);
|
||||
var entry = new HallFame6Entity(slice)
|
||||
var entry = new HallFame6Entity(slice, SAV.Language)
|
||||
{
|
||||
Species = Convert.ToUInt16(CB_Species.SelectedValue),
|
||||
HeldItem = Convert.ToUInt16(CB_HeldItem.SelectedValue),
|
||||
|
|
|
@ -11,7 +11,7 @@ public class StringTests
|
|||
{
|
||||
const string name_fabian = "Fabian♂";
|
||||
var pk = new PK7 { OriginalTrainerName = name_fabian };
|
||||
Span<byte> byte_fabian =
|
||||
ReadOnlySpan<byte> byte_fabian =
|
||||
[
|
||||
0x46, 0x00, // F
|
||||
0x61, 0x00, // a
|
||||
|
@ -30,7 +30,7 @@ public class StringTests
|
|||
{
|
||||
const string name_nidoran = "ニドラン♀";
|
||||
var pk = new PK7 { Nickname = name_nidoran };
|
||||
Span<byte> byte_nidoran =
|
||||
ReadOnlySpan<byte> byte_nidoran =
|
||||
[
|
||||
0xCB, 0x30, // ニ
|
||||
0xC9, 0x30, // ド
|
||||
|
|
|
@ -7,6 +7,11 @@ namespace PKHeX.Core.Tests.Simulator;
|
|||
|
||||
public class ShowdownSetTests
|
||||
{
|
||||
static ShowdownSetTests()
|
||||
{
|
||||
ParseSettings.Settings.Handler.CheckActiveHandler = false;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SimulatorGetParse()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue