mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-22 03:53:08 +00:00
Reduce alloc for ot/nick by raw trash reads
Legality check now catches buffer overflow mons. Now that I have each type exposing a trash length & charcount, should be easy to have some reusable trash byte measuring methods (see the old branch)
This commit is contained in:
parent
08ed482555
commit
7b6abc0520
70 changed files with 286 additions and 138 deletions
|
@ -18,7 +18,7 @@ public sealed class FakeSaveFile : SaveFile
|
|||
public override int MaxEV => 0;
|
||||
public override ReadOnlySpan<ushort> HeldItems => Legal.HeldItems_RS;
|
||||
public override int GetBoxOffset(int box) => -1;
|
||||
public override int MaxStringLengthOT => 5;
|
||||
public override int MaxStringLengthTrainer => 5;
|
||||
public override int MaxStringLengthNickname => 5;
|
||||
public override ushort MaxMoveID => 5;
|
||||
public override ushort MaxSpeciesID => 1;
|
||||
|
|
|
@ -202,25 +202,39 @@ public sealed record EncounterGift1 : IEncounterable, IEncounterMatch, IEncounte
|
|||
return true;
|
||||
}
|
||||
|
||||
private bool IsTrainerNameValid(PKM pk) => Trainer switch
|
||||
private bool IsTrainerNameValid(PKM pk)
|
||||
{
|
||||
Recipient => true,
|
||||
VirtualConsoleMew => pk.OriginalTrainerName == (pk.Language == 1 ? VirtualConsoleMewJPN : VirtualConsoleMewINT),
|
||||
Stadium => pk.Language switch
|
||||
if (Trainer == Recipient)
|
||||
return true;
|
||||
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
if (Trainer == EuropeTour)
|
||||
return IsTourOT(trainer);
|
||||
|
||||
var language = pk.Language;
|
||||
if (Trainer == VirtualConsoleMew)
|
||||
return trainer.SequenceEqual(language == 1 ? VirtualConsoleMewJPN : VirtualConsoleMewINT);
|
||||
|
||||
if (Trainer == Stadium)
|
||||
{
|
||||
(int)Japanese => pk.OriginalTrainerName == StadiumJPN,
|
||||
_ => pk.OriginalTrainerName switch
|
||||
return language switch
|
||||
{
|
||||
StadiumENG => true,
|
||||
StadiumFRE => true,
|
||||
StadiumITA => true,
|
||||
StadiumSPA => true,
|
||||
_ => false,
|
||||
},
|
||||
},
|
||||
EuropeTour => IsTourOT(pk.OriginalTrainerName),
|
||||
_ => true,
|
||||
};
|
||||
(int)Japanese => trainer.SequenceEqual(StadiumJPN),
|
||||
_ => trainer switch
|
||||
{
|
||||
StadiumENG => true,
|
||||
StadiumFRE => true,
|
||||
StadiumITA => true,
|
||||
StadiumSPA => true,
|
||||
_ => false,
|
||||
},
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsTrainerIDValid(PKM pk) => Trainer switch
|
||||
{
|
||||
|
|
|
@ -75,7 +75,12 @@ public sealed record EncounterTrade1 : IEncounterable, IEncounterMatch, IFixedTr
|
|||
return pk.OriginalTrainerTrash is [StringConverter1.TradeOTCode, StringConverter1.TerminatorCode, ..];
|
||||
var lang = pk.Language;
|
||||
var expect = StringConverter12Transporter.GetTradeNameGen1(lang);
|
||||
return pk.OriginalTrainerName == expect;
|
||||
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
return trainer.SequenceEqual(expect);
|
||||
}
|
||||
|
||||
private int GetNicknameIndex(ReadOnlySpan<char> nickname) => GetIndex(nickname, Nicknames);
|
||||
|
|
|
@ -131,10 +131,19 @@ public sealed record EncounterTrade2 : IEncounterable, IEncounterMatch, IFixedTr
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsTrainerNicknameCorrect(PKM pk)
|
||||
{
|
||||
// Italian and English share the same OT name for Spearow, but different nicknames. Others are like this, so we need to check both.
|
||||
var lang = DetectLanguage(pk, pk.OriginalTrainerName, pk.Nickname);
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
Span<char> nickname = stackalloc char[pk.TrashCharCountNickname];
|
||||
len = pk.LoadString(pk.NicknameTrash, nickname);
|
||||
nickname = nickname[..len];
|
||||
|
||||
var lang = DetectLanguage(pk, trainer, nickname);
|
||||
return lang != -1;
|
||||
}
|
||||
|
||||
|
@ -244,7 +253,9 @@ public sealed record EncounterTrade2 : IEncounterable, IEncounterMatch, IFixedTr
|
|||
public bool IsNicknameMatch(PKM pk, ReadOnlySpan<char> nickname, int _)
|
||||
{
|
||||
// Match both.
|
||||
ReadOnlySpan<char> trainer = pk.OriginalTrainerName;
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
var lang = DetectLanguage(pk, trainer, nickname);
|
||||
if (lang != -1)
|
||||
return true;
|
||||
|
|
|
@ -243,15 +243,18 @@ public sealed record EncounterTrade4PID
|
|||
return lang;
|
||||
|
||||
// Since two locales (JPN/ENG) can have the same LanguageID, check which we should be validating with.
|
||||
ReadOnlySpan<char> ot = pk.OriginalTrainerName;
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
var len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
var expect = TrainerNames[1];
|
||||
var match = ot.SequenceEqual(expect);
|
||||
var match = trainer.SequenceEqual(expect);
|
||||
if (!match)
|
||||
return 2; // verify strings with English locale instead.
|
||||
return lang;
|
||||
}
|
||||
|
||||
private int DetectTradeLanguageG4MeisterMagikarp(PKM pk,int currentLanguageID)
|
||||
private int DetectTradeLanguageG4MeisterMagikarp(PKM pk, int currentLanguageID)
|
||||
{
|
||||
if (currentLanguageID == (int)LanguageID.English)
|
||||
return (int)LanguageID.German;
|
||||
|
@ -259,7 +262,13 @@ public sealed record EncounterTrade4PID
|
|||
// All have German, regardless of origin version.
|
||||
var lang = DetectTradeLanguage(pk.OriginalTrainerName, currentLanguageID);
|
||||
if (lang == (int)LanguageID.English) // possible collision with FR/ES/DE. Check nickname
|
||||
return pk.Nickname == Nicknames[(int)LanguageID.French] ? (int)LanguageID.French : (int)LanguageID.Spanish; // Spanish is same as English
|
||||
{
|
||||
Span<char> nickname = stackalloc char[pk.TrashCharCountNickname];
|
||||
var len = pk.LoadString(pk.NicknameTrash, nickname);
|
||||
nickname = nickname[..len];
|
||||
|
||||
return nickname.SequenceEqual(Nicknames[(int)LanguageID.French]) ? (int)LanguageID.French : (int)LanguageID.Spanish; // Spanish is same as English
|
||||
}
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
@ -271,8 +280,14 @@ public sealed record EncounterTrade4PID
|
|||
|
||||
// All have English, regardless of origin version.
|
||||
var lang = DetectTradeLanguage(pk.OriginalTrainerName, currentLanguageID);
|
||||
if (lang == 2) // possible collision with ES/IT. Check nickname
|
||||
return pk.Nickname == Nicknames[(int)LanguageID.Italian] ? (int)LanguageID.Italian : (int)LanguageID.Spanish;
|
||||
if (lang == (int)LanguageID.English) // possible collision with ES/IT. Check nickname
|
||||
{
|
||||
Span<char> nickname = stackalloc char[pk.TrashCharCountNickname];
|
||||
var len = pk.LoadString(pk.NicknameTrash, nickname);
|
||||
nickname = nickname[..len];
|
||||
|
||||
return nickname.SequenceEqual(Nicknames[(int)LanguageID.Italian]) ? (int)LanguageID.Italian : (int)LanguageID.Spanish;
|
||||
}
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,12 @@ public static class MysteryGiftVerifier
|
|||
return false; // no data
|
||||
if (!val.HasFlag(MysteryGiftRestriction.OTReplacedOnTrade))
|
||||
return false;
|
||||
return CurrentOTMatchesReplaced(g.Generation, pk.OriginalTrainerName);
|
||||
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
return CurrentOTMatchesReplaced(g.Generation, trainer);
|
||||
}
|
||||
|
||||
private static bool CanVersionReceiveGift(byte generation, int version4bit, GameVersion version)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#define SUPPRESS
|
||||
//#define SUPPRESS
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
|
@ -16,12 +16,15 @@ public sealed class NicknameVerifier : Verifier
|
|||
var pk = data.Entity;
|
||||
|
||||
// If the Pokémon is not nicknamed, it should match one of the language strings.
|
||||
var nickname = pk.Nickname;
|
||||
if (nickname.Length == 0)
|
||||
Span<char> nickname = stackalloc char[pk.TrashCharCountNickname];
|
||||
int len = pk.LoadString(pk.NicknameTrash, nickname);
|
||||
if (len == 0)
|
||||
{
|
||||
data.AddLine(GetInvalid(LNickLengthShort));
|
||||
return;
|
||||
}
|
||||
nickname = nickname[..len];
|
||||
|
||||
if (pk.Species > SpeciesName.MaxSpeciesID)
|
||||
{
|
||||
data.AddLine(Get(LNickLengthShort, Severity.Invalid));
|
||||
|
@ -65,7 +68,7 @@ public sealed class NicknameVerifier : Verifier
|
|||
// Non-nicknamed strings have already been checked.
|
||||
if (ParseSettings.Settings.WordFilter.IsEnabled(pk.Format) && pk.IsNicknamed)
|
||||
{
|
||||
if (WordFilter.IsFiltered(nickname, out var badPattern))
|
||||
if (WordFilter.IsFiltered(nickname.ToString(), out var badPattern))
|
||||
data.AddLine(GetInvalid($"Word Filter: {badPattern}"));
|
||||
if (TrainerNameVerifier.ContainsTooManyNumbers(nickname, data.Info.Generation))
|
||||
data.AddLine(GetInvalid("Word Filter: Too many numbers."));
|
||||
|
@ -261,16 +264,40 @@ public sealed class NicknameVerifier : Verifier
|
|||
}
|
||||
|
||||
if (format == 5 && enc.Generation != 5) // transfer
|
||||
{
|
||||
if (canHaveAnyLanguage)
|
||||
return !SpeciesName.IsNicknamedAnyLanguage(species, nickname, 4);
|
||||
expect = SpeciesName.GetSpeciesNameGeneration(species, language, 4);
|
||||
return nickname.SequenceEqual(expect);
|
||||
}
|
||||
return IsMatch45(nickname, species, expect, language, canHaveAnyLanguage);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsMatch45(ReadOnlySpan<char> nickname, ushort species, string expect, int language, bool canHaveAnyLanguage)
|
||||
{
|
||||
if (species is (int)Species.Farfetchd)
|
||||
{
|
||||
if (nickname.Length == expect.Length)
|
||||
{
|
||||
// Compare as upper -- different apostrophe than Gen4 encoding.
|
||||
if (IsMatchUpper45(nickname, expect))
|
||||
return true;
|
||||
}
|
||||
if (SpeciesName.IsApostropheFarfetchdLanguage(language))
|
||||
return false; // must have matched above
|
||||
}
|
||||
if (canHaveAnyLanguage)
|
||||
return !SpeciesName.IsNicknamedAnyLanguage(species, nickname, 4);
|
||||
expect = SpeciesName.GetSpeciesNameGeneration(species, language, 4);
|
||||
return nickname.SequenceEqual(expect);
|
||||
}
|
||||
|
||||
private static bool IsMatchUpper45(ReadOnlySpan<char> nickname, string expect)
|
||||
{
|
||||
for (int i = 0; i < expect.Length; i++)
|
||||
{
|
||||
if (nickname[i] != char.ToUpperInvariant(expect[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void VerifyNicknameEgg(LegalityAnalysis data)
|
||||
{
|
||||
var Info = data.Info;
|
||||
|
@ -280,7 +307,7 @@ public sealed class NicknameVerifier : Verifier
|
|||
if (pk.IsNicknamed != flagState)
|
||||
data.AddLine(GetInvalid(flagState ? LNickFlagEggYes : LNickFlagEggNo, CheckIdentifier.Egg));
|
||||
|
||||
Span<char> nickname = stackalloc char[pk.MaxStringLengthNickname];
|
||||
Span<char> nickname = stackalloc char[pk.TrashCharCountNickname];
|
||||
int len = pk.LoadString(pk.NicknameTrash, nickname);
|
||||
nickname = nickname[..len];
|
||||
|
||||
|
@ -351,7 +378,15 @@ public sealed class NicknameVerifier : Verifier
|
|||
return;
|
||||
}
|
||||
|
||||
lang = t.DetectMeisterMagikarpLanguage(pk.Nickname, pk.OriginalTrainerName, lang);
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
Span<char> nickname = stackalloc char[pk.TrashCharCountNickname];
|
||||
len = pk.LoadString(pk.NicknameTrash, nickname);
|
||||
nickname = nickname[..len];
|
||||
|
||||
lang = t.DetectMeisterMagikarpLanguage(nickname, trainer, lang);
|
||||
if (lang == -1) // err
|
||||
data.AddLine(GetInvalid(string.Format(LOTLanguage, $"{Japanese}/{German}", $"{(LanguageID)pk.Language}"), CheckIdentifier.Language));
|
||||
}
|
||||
|
@ -388,7 +423,12 @@ public sealed class NicknameVerifier : Verifier
|
|||
if (pk.IsNicknamed && (pk.Format < 8 || pk.FatefulEncounter))
|
||||
return GetInvalid(LEncTradeChangedNickname, CheckIdentifier.Nickname);
|
||||
int lang = pk.Language;
|
||||
if (!t.IsTrainerMatch(pk, pk.OriginalTrainerName, lang))
|
||||
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
if (!t.IsTrainerMatch(pk, trainer, lang))
|
||||
return GetInvalid(LEncTradeIndexBad, CheckIdentifier.Trainer);
|
||||
return GetValid(LEncTradeUnchanged, CheckIdentifier.Nickname);
|
||||
}
|
||||
|
@ -413,7 +453,11 @@ public sealed class NicknameVerifier : Verifier
|
|||
private static void VerifyTrainerName(LegalityAnalysis data, IFixedTrainer ft, int language)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
if (!ft.IsTrainerMatch(pk, pk.OriginalTrainerName, language))
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
if (!ft.IsTrainerMatch(pk, trainer, language))
|
||||
data.AddLine(GetInvalid(LEncTradeChangedOT, CheckIdentifier.Trainer));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ using static PKHeX.Core.LegalityCheckStrings;
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the <see cref="PKM.OriginalTrainerName"/>.
|
||||
/// Verifies the <see cref="PKM.ID32"/>.
|
||||
/// </summary>
|
||||
public sealed class TrainerIDVerifier : Verifier
|
||||
{
|
||||
|
|
|
@ -23,11 +23,16 @@ public sealed class TrainerNameVerifier : Verifier
|
|||
if (!IsPlayerOriginalTrainer(enc))
|
||||
return; // already verified
|
||||
|
||||
var ot = pk.OriginalTrainerName;
|
||||
if (ot.Length == 0)
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
if (len == 0)
|
||||
{
|
||||
data.AddLine(GetInvalid(LOTShort));
|
||||
return;
|
||||
}
|
||||
trainer = trainer[..len];
|
||||
|
||||
if (IsOTNameSuspicious(ot))
|
||||
if (IsOTNameSuspicious(trainer))
|
||||
{
|
||||
data.AddLine(Get(LOTSuspicious, Severity.Fishy));
|
||||
}
|
||||
|
@ -36,17 +41,17 @@ public sealed class TrainerNameVerifier : Verifier
|
|||
{
|
||||
VerifyOTGB(data);
|
||||
}
|
||||
else if (ot.Length > Legal.GetMaxLengthOT(data.Info.Generation, (LanguageID)pk.Language))
|
||||
else if (trainer.Length > Legal.GetMaxLengthOT(data.Info.Generation, (LanguageID)pk.Language))
|
||||
{
|
||||
if (!IsEdgeCaseLength(pk, data.EncounterOriginal, ot))
|
||||
if (!IsEdgeCaseLength(pk, data.EncounterOriginal, trainer))
|
||||
data.AddLine(Get(LOTLong, Severity.Invalid));
|
||||
}
|
||||
|
||||
if (ParseSettings.Settings.WordFilter.IsEnabled(pk.Format))
|
||||
{
|
||||
if (WordFilter.IsFiltered(ot, out var badPattern))
|
||||
if (WordFilter.IsFiltered(trainer.ToString(), out var badPattern))
|
||||
data.AddLine(GetInvalid($"Word Filter: {badPattern}"));
|
||||
if (ContainsTooManyNumbers(ot, data.Info.Generation))
|
||||
if (ContainsTooManyNumbers(trainer, data.Info.Generation))
|
||||
data.AddLine(GetInvalid("Word Filter: Too many numbers."));
|
||||
|
||||
if (WordFilter.IsFiltered(pk.HandlingTrainerName, out badPattern))
|
||||
|
@ -101,8 +106,11 @@ public sealed class TrainerNameVerifier : Verifier
|
|||
if (enc is IFixedTrainer { IsFixedTrainer: true })
|
||||
return; // already verified
|
||||
|
||||
string tr = pk.OriginalTrainerName;
|
||||
if (tr.Length == 0)
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
if (trainer.Length == 0)
|
||||
{
|
||||
if (pk is SK2 {TID16: 0, IsRental: true})
|
||||
{
|
||||
|
@ -114,7 +122,7 @@ public sealed class TrainerNameVerifier : Verifier
|
|||
return;
|
||||
}
|
||||
}
|
||||
VerifyGBOTWithinBounds(data, tr);
|
||||
VerifyGBOTWithinBounds(data, trainer);
|
||||
}
|
||||
|
||||
private void VerifyGBOTWithinBounds(LegalityAnalysis data, ReadOnlySpan<char> str)
|
||||
|
|
|
@ -28,6 +28,8 @@ public sealed class CK3(byte[] Data) : G3PKM(Data), IShadowCapture
|
|||
public override Span<byte> OriginalTrainerTrash => Data.AsSpan(0x18, 22);
|
||||
public override Span<byte> NicknameTrash => Data.AsSpan(0x2E, 22);
|
||||
public Span<byte> NicknameCopy_Trash => Data.AsSpan(0x44, 22);
|
||||
public override int TrashCharCountTrainer => 11;
|
||||
public override int TrashCharCountNickname => 11;
|
||||
|
||||
// Future Attributes
|
||||
public override ushort SpeciesInternal { get => ReadUInt16BigEndian(Data.AsSpan(0x00)); set => WriteUInt16BigEndian(Data.AsSpan(0x00), value); } // raw access
|
||||
|
|
|
@ -81,6 +81,8 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
public override Span<byte> NicknameTrash => Core.NicknameTrash;
|
||||
public override Span<byte> OriginalTrainerTrash => Core.OriginalTrainerTrash;
|
||||
public override Span<byte> HandlingTrainerTrash => Core.HandlingTrainerTrash;
|
||||
public override int TrashCharCountTrainer => 13;
|
||||
public override int TrashCharCountNickname => 13;
|
||||
public override bool IsUntraded => ReadUInt16LittleEndian(HandlingTrainerTrash) == 0; // immediately terminated HandlingTrainerName data (\0)
|
||||
|
||||
#region Core
|
||||
|
@ -233,7 +235,7 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
|
||||
public override int MaxIV => 31;
|
||||
public override int MaxEV => EffortValues.Max252;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_8a;
|
||||
public override ushort MaxSpeciesID => Legal.MaxSpeciesID_8a;
|
||||
|
|
|
@ -53,7 +53,7 @@ public interface IGameValueLimit
|
|||
/// <summary>
|
||||
/// Maximum length of a string field for a Trainer Name.
|
||||
/// </summary>
|
||||
int MaxStringLengthOT { get; }
|
||||
int MaxStringLengthTrainer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum length of a string field for a Pokémon Nickname.
|
||||
|
|
|
@ -65,11 +65,13 @@ public sealed class PA8 : PKM, ISanityChecksum,
|
|||
public override Span<byte> NicknameTrash => Data.AsSpan(0x60, 26);
|
||||
public override Span<byte> HandlingTrainerTrash => Data.AsSpan(0xB8, 26);
|
||||
public override Span<byte> OriginalTrainerTrash => Data.AsSpan(0x110, 26);
|
||||
public override int TrashCharCountTrainer => 13;
|
||||
public override int TrashCharCountNickname => 13;
|
||||
|
||||
// Maximums
|
||||
public override int MaxIV => 31;
|
||||
public override int MaxEV => EffortValues.Max252;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
|
||||
public override uint PSV => ((PID >> 16) ^ (PID & 0xFFFF)) >> 4;
|
||||
|
|
|
@ -252,7 +252,7 @@ public sealed class PK1 : GBPKML, IPersonalType
|
|||
=> StringConverter1.GetString(data, Japanese);
|
||||
public override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
||||
=> StringConverter1.LoadString(data, destBuffer, Japanese);
|
||||
public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option = StringConverterOption.None)
|
||||
public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter1.SetString(destBuffer, value, maxLength, Japanese, option);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -38,6 +38,8 @@ public sealed class PK3 : G3PKM, ISanityChecksum
|
|||
// Trash Bytes
|
||||
public override Span<byte> NicknameTrash => Data.AsSpan(0x08, 10); // no inaccessible terminator
|
||||
public override Span<byte> OriginalTrainerTrash => Data.AsSpan(0x14, 7); // no inaccessible terminator
|
||||
public override int TrashCharCountTrainer => 7;
|
||||
public override int TrashCharCountNickname => 10;
|
||||
|
||||
// At top for System.Reflection execution order hack
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ public sealed class PK5 : PKM, ISanityChecksum,
|
|||
// Trash Bytes
|
||||
public override Span<byte> NicknameTrash => Data.AsSpan(0x48, 22);
|
||||
public override Span<byte> OriginalTrainerTrash => Data.AsSpan(0x68, 16);
|
||||
public override int TrashCharCountNickname => 11;
|
||||
public override int TrashCharCountTrainer => 8;
|
||||
|
||||
// Future Attributes
|
||||
public override uint EncryptionConstant { get => PID; set { } }
|
||||
|
@ -297,7 +299,7 @@ public sealed class PK5 : PKM, ISanityChecksum,
|
|||
public override GameVersion MaxGameID => Legal.MaxGameID_5; // B2
|
||||
public override int MaxIV => 31;
|
||||
public override int MaxEV => EffortValues.Max255;
|
||||
public override int MaxStringLengthOT => 7;
|
||||
public override int MaxStringLengthTrainer => 7;
|
||||
public override int MaxStringLengthNickname => 10;
|
||||
|
||||
// Methods
|
||||
|
|
|
@ -65,11 +65,13 @@ public sealed class PK9 : PKM, ISanityChecksum, ITeraType, ITechRecord, IObedien
|
|||
public override Span<byte> NicknameTrash => Data.AsSpan(0x58, 26);
|
||||
public override Span<byte> HandlingTrainerTrash => Data.AsSpan(0xA8, 26);
|
||||
public override Span<byte> OriginalTrainerTrash => Data.AsSpan(0xF8, 26);
|
||||
public override int TrashCharCountTrainer => 13;
|
||||
public override int TrashCharCountNickname => 13;
|
||||
|
||||
// Maximums
|
||||
public override int MaxIV => 31;
|
||||
public override int MaxEV => EffortValues.Max252;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
|
||||
public override uint PSV => ((PID >> 16) ^ (PID & 0xFFFF)) >> 4;
|
||||
|
|
|
@ -252,8 +252,15 @@ public abstract class PKM : ISpeciesForm, ITrainerID32, IGeneration, IShiny, ILa
|
|||
public virtual GameVersion MinGameID => 0;
|
||||
public abstract int MaxIV { get; }
|
||||
public abstract int MaxEV { get; }
|
||||
public abstract int MaxStringLengthOT { get; }
|
||||
|
||||
/// <summary> Maximum length a Trainer Name can be represented as. </summary>
|
||||
public abstract int MaxStringLengthTrainer { get; }
|
||||
/// <summary> Maximum length a Nickname can be represented as. </summary>
|
||||
public abstract int MaxStringLengthNickname { get; }
|
||||
/// <summary> Total characters allocated for holding a Trainer Name. </summary>
|
||||
public abstract int TrashCharCountTrainer { get; }
|
||||
/// <summary> Total characters allocated for holding a Nickname. </summary>
|
||||
public abstract int TrashCharCountNickname { get; }
|
||||
|
||||
// Derived
|
||||
public virtual int SpriteItem => HeldItem;
|
||||
|
|
|
@ -18,7 +18,7 @@ public sealed class SK2 : GBPKM, ICaughtData2
|
|||
private const int StringLength = 12;
|
||||
|
||||
public override EntityContext Context => EntityContext.Gen2;
|
||||
public override int MaxStringLengthOT => StringLength;
|
||||
public override int MaxStringLengthTrainer => StringLength;
|
||||
public override int MaxStringLengthNickname => StringLength;
|
||||
|
||||
public SK2(bool jp = false) : base(PokeCrypto.SIZE_2STADIUM) => IsEncodingJapanese = jp;
|
||||
|
@ -114,6 +114,8 @@ public sealed class SK2 : GBPKM, ICaughtData2
|
|||
|
||||
public override Span<byte> NicknameTrash => Data.AsSpan(0x24, StringLength);
|
||||
public override Span<byte> OriginalTrainerTrash => Data.AsSpan(0x30, StringLength);
|
||||
public override int TrashCharCountTrainer => StringLength;
|
||||
public override int TrashCharCountNickname => StringLength;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ public abstract class G3PKM : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonS
|
|||
public sealed override GameVersion MaxGameID => Legal.MaxGameID_3;
|
||||
public sealed override int MaxIV => 31;
|
||||
public sealed override int MaxEV => EffortValues.Max255;
|
||||
public sealed override int MaxStringLengthOT => 7;
|
||||
public sealed override int MaxStringLengthTrainer => 7;
|
||||
public sealed override int MaxStringLengthNickname => 10;
|
||||
|
||||
// Generated Attributes
|
||||
|
|
|
@ -21,7 +21,7 @@ public abstract class G4PKM : PKM, IHandlerUpdate,
|
|||
public sealed override GameVersion MaxGameID => Legal.MaxGameID_4;
|
||||
public sealed override int MaxIV => 31;
|
||||
public sealed override int MaxEV => EffortValues.Max255;
|
||||
public sealed override int MaxStringLengthOT => 7;
|
||||
public sealed override int MaxStringLengthTrainer => 7;
|
||||
public sealed override int MaxStringLengthNickname => 10;
|
||||
|
||||
public sealed override uint PSV => ((PID >> 16) ^ (PID & 0xFFFF)) >> 3;
|
||||
|
@ -41,6 +41,8 @@ public abstract class G4PKM : PKM, IHandlerUpdate,
|
|||
// Trash Bytes
|
||||
public sealed override Span<byte> NicknameTrash => Data.AsSpan(0x48, 22);
|
||||
public sealed override Span<byte> OriginalTrainerTrash => Data.AsSpan(0x68, 16);
|
||||
public override int TrashCharCountNickname => 11;
|
||||
public override int TrashCharCountTrainer => 8;
|
||||
|
||||
// Future Attributes
|
||||
public sealed override uint EncryptionConstant { get => PID; set { } }
|
||||
|
|
|
@ -15,6 +15,8 @@ public abstract class G6PKM : PKM, ISanityChecksum, IHandlerUpdate
|
|||
public sealed override Span<byte> NicknameTrash => Data.AsSpan(0x40, 26);
|
||||
public sealed override Span<byte> HandlingTrainerTrash => Data.AsSpan(0x78, 26);
|
||||
public sealed override Span<byte> OriginalTrainerTrash => Data.AsSpan(0xB0, 26);
|
||||
public override int TrashCharCountTrainer => 13;
|
||||
public override int TrashCharCountNickname => 13;
|
||||
|
||||
public abstract ushort Sanity { get; set; }
|
||||
public abstract ushort Checksum { get; set; }
|
||||
|
@ -122,7 +124,7 @@ public abstract class G6PKM : PKM, ISanityChecksum, IHandlerUpdate
|
|||
// Maximums
|
||||
public sealed override int MaxIV => 31;
|
||||
public sealed override int MaxEV => EffortValues.Max252;
|
||||
public sealed override int MaxStringLengthOT => 12;
|
||||
public sealed override int MaxStringLengthTrainer => 12;
|
||||
public sealed override int MaxStringLengthNickname => 12;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,11 +41,13 @@ public abstract class G8PKM : PKM, ISanityChecksum,
|
|||
public override Span<byte> NicknameTrash => Data.AsSpan(0x58, 26);
|
||||
public override Span<byte> HandlingTrainerTrash => Data.AsSpan(0xA8, 26);
|
||||
public override Span<byte> OriginalTrainerTrash => Data.AsSpan(0xF8, 26);
|
||||
public override int TrashCharCountTrainer => 13;
|
||||
public override int TrashCharCountNickname => 13;
|
||||
|
||||
// Maximums
|
||||
public override int MaxIV => 31;
|
||||
public override int MaxEV => EffortValues.Max252;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
|
||||
public override uint PSV => ((PID >> 16) ^ (PID & 0xFFFF)) >> 4;
|
||||
|
|
|
@ -77,9 +77,9 @@ public abstract class GBPKM : PKM
|
|||
if (StringConverter1.IsG12German(OriginalTrainerTrash))
|
||||
return (int)LanguageID.German; // german
|
||||
|
||||
Span<char> nick = stackalloc char[11];
|
||||
int len = StringConverter1.LoadString(NicknameTrash, nick, false);
|
||||
int lang = SpeciesName.GetSpeciesNameLanguage(Species, nick[..len], Format);
|
||||
Span<char> nickname = stackalloc char[TrashCharCountNickname];
|
||||
int len = StringConverter1.LoadString(NicknameTrash, nickname, false);
|
||||
int lang = SpeciesName.GetSpeciesNameLanguage(Species, nickname[..len], Format);
|
||||
if (lang > 0)
|
||||
return lang;
|
||||
return 0;
|
||||
|
@ -255,8 +255,14 @@ public abstract class GBPKM : PKM
|
|||
|
||||
internal void ImportFromFuture(PKM pk)
|
||||
{
|
||||
Nickname = pk.Nickname;
|
||||
OriginalTrainerName = pk.OriginalTrainerName;
|
||||
Span<char> nickname = stackalloc char[pk.TrashCharCountNickname];
|
||||
pk.LoadString(pk.NicknameTrash, nickname);
|
||||
SetString(NicknameTrash, nickname, MaxStringLengthNickname, StringConverterOption.Clear50);
|
||||
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
SetString(OriginalTrainerTrash, nickname, MaxStringLengthTrainer, StringConverterOption.Clear50);
|
||||
|
||||
IV_ATK = pk.IV_ATK / 2;
|
||||
IV_DEF = pk.IV_DEF / 2;
|
||||
IV_SPC = pk.IV_SPA / 2;
|
||||
|
|
|
@ -11,7 +11,7 @@ public abstract class GBPKML : GBPKM
|
|||
{
|
||||
internal const int StringLengthJapanese = 6;
|
||||
internal const int StringLengthNotJapan = 11;
|
||||
public sealed override int MaxStringLengthOT => Japanese ? 5 : 7;
|
||||
public sealed override int MaxStringLengthTrainer => Japanese ? 5 : 7;
|
||||
public sealed override int MaxStringLengthNickname => Japanese ? 5 : 10;
|
||||
public sealed override bool Japanese => RawOT.Length == StringLengthJapanese;
|
||||
|
||||
|
@ -21,6 +21,8 @@ public abstract class GBPKML : GBPKM
|
|||
// Trash Bytes
|
||||
public sealed override Span<byte> NicknameTrash => RawNickname;
|
||||
public sealed override Span<byte> OriginalTrainerTrash => RawOT;
|
||||
public override int TrashCharCountTrainer => RawOT.Length;
|
||||
public override int TrashCharCountNickname => RawNickname.Length;
|
||||
|
||||
protected GBPKML([ConstantExpected] int size, bool jp = false) : base(size)
|
||||
{
|
||||
|
|
|
@ -98,9 +98,10 @@ public static class StringConverter345
|
|||
{
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
if (IsInvalid45(input[i]))
|
||||
var c = input[i];
|
||||
if (IsInvalid45(c))
|
||||
input[i] = '?';
|
||||
if (input[i] == '’') // Farfetch’d and CH’DING nicknames
|
||||
else if (c == '’') // Farfetch’d and CH’DING nicknames
|
||||
input[i] = '\''; // Wrong apostrophe, nice. Only is corrected when converted to Gen6.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -255,8 +255,11 @@ public static class EntityConverter
|
|||
if (pk.Nickname.Length > limit.MaxStringLengthNickname)
|
||||
pk.Nickname = pk.Nickname[..pk.MaxStringLengthNickname];
|
||||
|
||||
if (pk.OriginalTrainerName.Length > limit.MaxStringLengthOT)
|
||||
pk.OriginalTrainerName = pk.OriginalTrainerName[..pk.MaxStringLengthOT];
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
var max = limit.MaxStringLengthTrainer;
|
||||
if (len > max)
|
||||
pk.SetString(pk.OriginalTrainerTrash, trainer[..max], max, StringConverterOption.None);
|
||||
|
||||
if (pk.Move1 > limit.MaxMoveID || pk.Move2 > limit.MaxMoveID || pk.Move3 > limit.MaxMoveID || pk.Move4 > limit.MaxMoveID)
|
||||
pk.ClearInvalidMoves();
|
||||
|
|
|
@ -224,21 +224,26 @@ public static class EntitySorting
|
|||
/// <summary>
|
||||
/// Gets if the current handler is the original trainer.
|
||||
/// </summary>
|
||||
/// <param name="trainer">The <see cref="ITrainerInfo"/> requesting the check.</param>
|
||||
/// <param name="tr">The <see cref="ITrainerInfo"/> requesting the check.</param>
|
||||
/// <param name="pk">Pokémon data</param>
|
||||
/// <param name="checkGame">Toggle to check the game's version or not</param>
|
||||
/// <returns>True if OT, false if not OT.</returns>
|
||||
public static bool IsOriginalHandler(this ITrainerInfo trainer, PKM pk, bool checkGame)
|
||||
public static bool IsOriginalHandler(this ITrainerInfo tr, PKM pk, bool checkGame)
|
||||
{
|
||||
if (pk.Format >= 6)
|
||||
return pk.CurrentHandler != 1;
|
||||
if (checkGame && trainer.Version != pk.Version)
|
||||
if (checkGame && tr.Version != pk.Version)
|
||||
return false;
|
||||
if (trainer.TID16 != pk.TID16 || trainer.SID16 != pk.SID16)
|
||||
if (tr.TID16 != pk.TID16 || tr.SID16 != pk.SID16)
|
||||
return false;
|
||||
if (trainer.Gender != pk.OriginalTrainerGender)
|
||||
if (tr.Gender != pk.OriginalTrainerGender)
|
||||
return false;
|
||||
return trainer.OT == pk.OriginalTrainerName;
|
||||
|
||||
Span<char> trainer = stackalloc char[pk.TrashCharCountTrainer];
|
||||
int len = pk.LoadString(pk.OriginalTrainerTrash, trainer);
|
||||
trainer = trainer[..len];
|
||||
|
||||
return trainer.SequenceEqual(tr.OT);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -97,7 +97,7 @@ public static class SpeciesName
|
|||
return arr[species];
|
||||
}
|
||||
|
||||
private static bool IsApostropheFarfetchdLanguage(int language) => language is 2 or 4 or 7;
|
||||
public static bool IsApostropheFarfetchdLanguage(int language) => language is 2 or 4 or 7;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Pokémon's default name for the desired language ID and generation.
|
||||
|
|
|
@ -28,6 +28,8 @@ public sealed class XK3 : G3PKM, IShadowCapture
|
|||
public override Span<byte> OriginalTrainerTrash => Data.AsSpan(0x38, 22);
|
||||
public override Span<byte> NicknameTrash => Data.AsSpan(0x4E, 22);
|
||||
public Span<byte> NicknameCopy_Trash => Data.AsSpan(0x64, 22);
|
||||
public override int TrashCharCountTrainer => 11;
|
||||
public override int TrashCharCountNickname => 11;
|
||||
|
||||
public override ushort SpeciesInternal { get => ReadUInt16BigEndian(Data.AsSpan(0x00)); set => WriteUInt16BigEndian(Data.AsSpan(0x00), value); } // raw access
|
||||
public override ushort Species { get => SpeciesConverter.GetNational3(SpeciesInternal); set => SpeciesInternal = SpeciesConverter.GetInternal3(value); }
|
||||
|
|
|
@ -205,7 +205,7 @@ public sealed class SAV1 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWo
|
|||
public override int MaxIV => 15;
|
||||
public override byte Generation => 1;
|
||||
public override EntityContext Context => EntityContext.Gen1;
|
||||
public override int MaxStringLengthOT => Japanese ? 5 : 7;
|
||||
public override int MaxStringLengthTrainer => Japanese ? 5 : 7;
|
||||
public override int MaxStringLengthNickname => Japanese ? 5 : 10;
|
||||
public override int BoxSlotCount => Japanese ? 30 : 20;
|
||||
|
||||
|
@ -233,8 +233,8 @@ public sealed class SAV1 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWo
|
|||
|
||||
public override string OT
|
||||
{
|
||||
get => GetString(Data.AsSpan(Offsets.OT, MaxStringLengthOT));
|
||||
set => SetString(Data.AsSpan(Offsets.OT, MaxStringLengthOT + 1), value, MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
get => GetString(Data.AsSpan(Offsets.OT, MaxStringLengthTrainer));
|
||||
set => SetString(Data.AsSpan(Offsets.OT, MaxStringLengthTrainer + 1), value, MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public Span<byte> OriginalTrainerTrash { get => Data.AsSpan(Offsets.OT, StringLength); set { if (value.Length == StringLength) value.CopyTo(Data.AsSpan(Offsets.OT)); } }
|
||||
|
@ -261,8 +261,8 @@ public sealed class SAV1 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWo
|
|||
|
||||
public string Rival
|
||||
{
|
||||
get => GetString(Data.AsSpan(Offsets.Rival, MaxStringLengthOT));
|
||||
set => SetString(Data.AsSpan(Offsets.Rival, MaxStringLengthOT), value, MaxStringLengthOT, StringConverterOption.Clear50);
|
||||
get => GetString(Data.AsSpan(Offsets.Rival, MaxStringLengthTrainer));
|
||||
set => SetString(Data.AsSpan(Offsets.Rival, MaxStringLengthTrainer), value, MaxStringLengthTrainer, StringConverterOption.Clear50);
|
||||
}
|
||||
|
||||
public Span<byte> Rival_Trash { get => Data.AsSpan(Offsets.Rival, StringLength); set { if (value.Length == StringLength) value.CopyTo(Data.AsSpan(Offsets.Rival)); } }
|
||||
|
|
|
@ -24,7 +24,7 @@ public sealed class SAV1Stadium : SAV_STADIUM
|
|||
private int StringLength => Japanese ? StringLengthJ : StringLengthU;
|
||||
private const int StringLengthJ = 6;
|
||||
private const int StringLengthU = 11;
|
||||
public override int MaxStringLengthOT => StringLength;
|
||||
public override int MaxStringLengthTrainer => StringLength;
|
||||
public override int MaxStringLengthNickname => StringLength;
|
||||
public override int BoxCount => Japanese ? 8 : 12;
|
||||
public override int BoxSlotCount => Japanese ? 30 : 20;
|
||||
|
|
|
@ -22,7 +22,7 @@ public sealed class SAV1StadiumJ : SAV_STADIUM
|
|||
public override byte Generation => 1;
|
||||
public override EntityContext Context => EntityContext.Gen1;
|
||||
private const int StringLength = 6; // Japanese Only
|
||||
public override int MaxStringLengthOT => StringLength;
|
||||
public override int MaxStringLengthTrainer => StringLength;
|
||||
public override int MaxStringLengthNickname => StringLength;
|
||||
public override int BoxCount => 4; // 8 boxes stored sequentially; latter 4 are backups
|
||||
public override int BoxSlotCount => 30;
|
||||
|
|
|
@ -258,7 +258,7 @@ public sealed class SAV2 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWo
|
|||
public override int MaxIV => 15;
|
||||
public override byte Generation => 2;
|
||||
public override EntityContext Context => EntityContext.Gen2;
|
||||
public override int MaxStringLengthOT => Japanese || Korean ? 5 : 7;
|
||||
public override int MaxStringLengthTrainer => Japanese || Korean ? 5 : 7;
|
||||
public override int MaxStringLengthNickname => Japanese || Korean ? 5 : 10;
|
||||
public override int BoxSlotCount => Japanese ? 30 : 20;
|
||||
|
||||
|
@ -303,8 +303,8 @@ public sealed class SAV2 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWo
|
|||
|
||||
public override string OT
|
||||
{
|
||||
get => GetString(Data.AsSpan(Offsets.Trainer1 + 2, (Korean ? 2 : 1) * MaxStringLengthOT));
|
||||
set => SetString(Data.AsSpan(Offsets.Trainer1 + 2, (Korean ? 2 : 1) * MaxStringLengthOT), value, 8, StringConverterOption.Clear50);
|
||||
get => GetString(Data.AsSpan(Offsets.Trainer1 + 2, (Korean ? 2 : 1) * MaxStringLengthTrainer));
|
||||
set => SetString(Data.AsSpan(Offsets.Trainer1 + 2, (Korean ? 2 : 1) * MaxStringLengthTrainer), value, 8, StringConverterOption.Clear50);
|
||||
}
|
||||
|
||||
public Span<byte> OriginalTrainerTrash
|
||||
|
@ -315,8 +315,8 @@ public sealed class SAV2 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWo
|
|||
|
||||
public string Rival
|
||||
{
|
||||
get => GetString(Data.AsSpan(Offsets.Rival, (Korean ? 2 : 1) * MaxStringLengthOT));
|
||||
set => SetString(Data.AsSpan(Offsets.Rival, (Korean ? 2 : 1) * MaxStringLengthOT), value, 8, StringConverterOption.Clear50);
|
||||
get => GetString(Data.AsSpan(Offsets.Rival, (Korean ? 2 : 1) * MaxStringLengthTrainer));
|
||||
set => SetString(Data.AsSpan(Offsets.Rival, (Korean ? 2 : 1) * MaxStringLengthTrainer), value, 8, StringConverterOption.Clear50);
|
||||
}
|
||||
|
||||
public Span<byte> Rival_Trash
|
||||
|
|
|
@ -21,7 +21,7 @@ public sealed class SAV2Stadium : SAV_STADIUM, IBoxDetailName
|
|||
public override byte Generation => 2;
|
||||
public override EntityContext Context => EntityContext.Gen2;
|
||||
private const int StringLength = 12;
|
||||
public override int MaxStringLengthOT => StringLength;
|
||||
public override int MaxStringLengthTrainer => StringLength;
|
||||
public override int MaxStringLengthNickname => StringLength;
|
||||
public override int BoxCount => Japanese ? 9 : 14;
|
||||
public override int BoxSlotCount => Japanese ? 30 : 20;
|
||||
|
|
|
@ -191,7 +191,7 @@ public abstract class SAV3 : SaveFile, ILangDeviantSave, IEventFlag37, IBoxDetai
|
|||
public sealed override int MaxEV => EffortValues.Max255;
|
||||
public sealed override byte Generation => 3;
|
||||
public sealed override EntityContext Context => EntityContext.Gen3;
|
||||
public sealed override int MaxStringLengthOT => 7;
|
||||
public sealed override int MaxStringLengthTrainer => 7;
|
||||
public sealed override int MaxStringLengthNickname => 10;
|
||||
public sealed override int MaxMoney => 999999;
|
||||
|
||||
|
@ -324,7 +324,7 @@ public abstract class SAV3 : SaveFile, ILangDeviantSave, IEventFlag37, IBoxDetai
|
|||
get => GetString(OriginalTrainerTrash);
|
||||
set
|
||||
{
|
||||
int len = Japanese ? 5 : MaxStringLengthOT;
|
||||
int len = Japanese ? 5 : MaxStringLengthTrainer;
|
||||
SetString(OriginalTrainerTrash[..len], value, len, StringConverterOption.ClearFF); // match the game-init FF terminating pattern
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ public sealed class SAV3Colosseum : SaveFile, IGCSaveFile, IBoxDetailName, IDayc
|
|||
public override int MaxEV => EffortValues.Max255;
|
||||
public override byte Generation => 3;
|
||||
public override EntityContext Context => EntityContext.Gen3;
|
||||
public override int MaxStringLengthOT => 10; // as evident by Mattle Ho-Oh
|
||||
public override int MaxStringLengthTrainer => 10; // as evident by Mattle Ho-Oh
|
||||
public override int MaxStringLengthNickname => 10;
|
||||
public override int MaxMoney => 9999999;
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ public sealed class SAV3RSBox : SaveFile, IGCSaveFile, IBoxDetailName, IBoxDetai
|
|||
public override int MaxEV => EffortValues.Max255;
|
||||
public override byte Generation => 3;
|
||||
public override EntityContext Context => EntityContext.Gen3;
|
||||
public override int MaxStringLengthOT => 7;
|
||||
public override int MaxStringLengthTrainer => 7;
|
||||
public override int MaxStringLengthNickname => 10;
|
||||
public override int MaxMoney => 999999;
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ public sealed class SAV3XD : SaveFile, IGCSaveFile, IBoxDetailName, IDaycareStor
|
|||
public override int MaxEV => EffortValues.Max255;
|
||||
public override byte Generation => 3;
|
||||
public override EntityContext Context => EntityContext.Gen3;
|
||||
public override int MaxStringLengthOT => 7;
|
||||
public override int MaxStringLengthTrainer => 7;
|
||||
public override int MaxStringLengthNickname => 10;
|
||||
public override int MaxMoney => 9999999;
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ public abstract class SAV4 : SaveFile, IEventFlag37, IDaycareStorage, IDaycareRa
|
|||
public sealed override EntityContext Context => EntityContext.Gen4;
|
||||
public int EventFlagCount => 0xB60; // 2912
|
||||
public int EventWorkCount => (EventFlag - EventWork) >> 1;
|
||||
public sealed override int MaxStringLengthOT => 7;
|
||||
public sealed override int MaxStringLengthTrainer => 7;
|
||||
public sealed override int MaxStringLengthNickname => 10;
|
||||
public sealed override int MaxMoney => 999999;
|
||||
public sealed override int MaxCoins => 50_000;
|
||||
|
@ -243,7 +243,7 @@ public abstract class SAV4 : SaveFile, IEventFlag37, IDaycareStorage, IDaycareRa
|
|||
public override string OT
|
||||
{
|
||||
get => GetString(General.Slice(Trainer1, 16));
|
||||
set => SetString(General.Slice(Trainer1, 16), value, MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SetString(General.Slice(Trainer1, 16), value, MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public override uint ID32
|
||||
|
@ -325,7 +325,7 @@ public abstract class SAV4 : SaveFile, IEventFlag37, IDaycareStorage, IDaycareRa
|
|||
public string Rival
|
||||
{
|
||||
get => GetString(Rival_Trash);
|
||||
set => SetString(Rival_Trash, value, MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SetString(Rival_Trash, value, MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public abstract Span<byte> Rival_Trash { get; set; }
|
||||
|
|
|
@ -107,7 +107,7 @@ public sealed class SAV4BR : SaveFile, IBoxDetailName
|
|||
public override int MaxEV => EffortValues.Max255;
|
||||
public override byte Generation => 4;
|
||||
public override EntityContext Context => EntityContext.Gen4;
|
||||
public override int MaxStringLengthOT => 7;
|
||||
public override int MaxStringLengthTrainer => 7;
|
||||
public override int MaxStringLengthNickname => 10;
|
||||
public override int MaxMoney => 999999;
|
||||
public override int Language => (int)LanguageID.English; // prevent KOR from inhabiting
|
||||
|
|
|
@ -116,8 +116,8 @@ public sealed class SAV4DP : SAV4Sinnoh
|
|||
|
||||
public override Span<byte> Rival_Trash
|
||||
{
|
||||
get => General.Slice(0x25A8, MaxStringLengthOT * 2);
|
||||
set { if (value.Length == MaxStringLengthOT * 2) value.CopyTo(General[0x25A8..]); }
|
||||
get => General.Slice(0x25A8, MaxStringLengthTrainer * 2);
|
||||
set { if (value.Length == MaxStringLengthTrainer * 2) value.CopyTo(General[0x25A8..]); }
|
||||
}
|
||||
|
||||
public override int X2 { get => ReadUInt16LittleEndian(General[0x25FA..]); set => WriteUInt16LittleEndian(General[0x25FA..], (ushort)value); }
|
||||
|
|
|
@ -190,10 +190,10 @@ public sealed class SAV4HGSS : SAV4, IBoxDetailName, IBoxDetailWallpaper
|
|||
public override Span<byte> Rival_Trash
|
||||
{
|
||||
get => RivalSpan;
|
||||
set { if (value.Length == MaxStringLengthOT * 2) value.CopyTo(RivalSpan); }
|
||||
set { if (value.Length == MaxStringLengthTrainer * 2) value.CopyTo(RivalSpan); }
|
||||
}
|
||||
|
||||
private Span<byte> RivalSpan => General.Slice(0x22D4, MaxStringLengthOT * 2);
|
||||
private Span<byte> RivalSpan => General.Slice(0x22D4, MaxStringLengthTrainer * 2);
|
||||
|
||||
public override int X2 { get => ReadUInt16LittleEndian(General[0x236E..]); set => WriteUInt16LittleEndian(General[0x236E..], (ushort)value); }
|
||||
public override int Y2 { get => ReadUInt16LittleEndian(General[0x2372..]); set => WriteUInt16LittleEndian(General[0x2372..], (ushort)value); }
|
||||
|
|
|
@ -161,10 +161,10 @@ public sealed class SAV4Pt : SAV4Sinnoh
|
|||
public override Span<byte> Rival_Trash
|
||||
{
|
||||
get => RivalSpan;
|
||||
set { if (value.Length == MaxStringLengthOT * 2) value.CopyTo(RivalSpan); }
|
||||
set { if (value.Length == MaxStringLengthTrainer * 2) value.CopyTo(RivalSpan); }
|
||||
}
|
||||
|
||||
private Span<byte> RivalSpan => General.Slice(0x27E8, MaxStringLengthOT * 2);
|
||||
private Span<byte> RivalSpan => General.Slice(0x27E8, MaxStringLengthTrainer * 2);
|
||||
|
||||
public override int X2 { get => ReadUInt16LittleEndian(General[0x287E..]); set => WriteUInt16LittleEndian(General[0x287E..], (ushort)value); }
|
||||
public override int Y2 { get => ReadUInt16LittleEndian(General[0x2882..]); set => WriteUInt16LittleEndian(General[0x2882..], (ushort)value); }
|
||||
|
|
|
@ -26,7 +26,7 @@ public abstract class SAV5 : SaveFile, ISaveBlock5BW, IEventFlagProvider37, IBox
|
|||
public override int MaxEV => EffortValues.Max255;
|
||||
public override byte Generation => 5;
|
||||
public override EntityContext Context => EntityContext.Gen5;
|
||||
public override int MaxStringLengthOT => 7;
|
||||
public override int MaxStringLengthTrainer => 7;
|
||||
public override int MaxStringLengthNickname => 10;
|
||||
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_5;
|
||||
|
|
|
@ -65,13 +65,13 @@ public sealed class SAV5B2W2 : SAV5, ISaveBlock5B2W2
|
|||
public string Rival
|
||||
{
|
||||
get => GetString(Rival_Trash);
|
||||
set => SetString(Rival_Trash, value, MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SetString(Rival_Trash, value, MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public Span<byte> Rival_Trash
|
||||
{
|
||||
get => Data.AsSpan(0x23BA4, MaxStringLengthOT * 2);
|
||||
set { if (value.Length == MaxStringLengthOT * 2) value.CopyTo(Data.AsSpan(0x23BA4)); }
|
||||
get => Data.AsSpan(0x23BA4, MaxStringLengthTrainer * 2);
|
||||
set { if (value.Length == MaxStringLengthTrainer * 2) value.CopyTo(Data.AsSpan(0x23BA4)); }
|
||||
}
|
||||
|
||||
public override Memory<byte> BattleVideoNative => Data.AsMemory(0x4C000, BattleVideo5.SIZE_USED);
|
||||
|
|
|
@ -26,7 +26,7 @@ public abstract class SAV6 : SAV_BEEF, ITrainerStatRecord, ISaveBlock6Core, IReg
|
|||
public sealed override int MaxEV => EffortValues.Max252;
|
||||
public sealed override byte Generation => 6;
|
||||
public sealed override EntityContext Context => EntityContext.Gen6;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
|
||||
public override ushort MaxSpeciesID => Legal.MaxSpeciesID_6;
|
||||
|
|
|
@ -75,7 +75,7 @@ public abstract class SAV7 : SAV_BEEF, ITrainerStatRecord, ISaveBlock7Main, IReg
|
|||
public override int MaxEV => EffortValues.Max252;
|
||||
public override byte Generation => 7;
|
||||
public override EntityContext Context => EntityContext.Gen7;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
|
||||
public override int MaxBallID => Legal.MaxBallID_7; // 26
|
||||
|
|
|
@ -80,7 +80,7 @@ public sealed class SAV7b : SAV_BEEF, ISaveBlock7b, IGameSync, IMysteryGiftStora
|
|||
|
||||
public override int MaxIV => 31;
|
||||
public override int MaxEV => EffortValues.Max252;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
|
||||
public override bool HasParty => false; // handled via team slots
|
||||
|
|
|
@ -119,7 +119,7 @@ public sealed class SAV8BS : SaveFile, ISaveFileRevision, ITrainerStatRecord, IE
|
|||
public override byte Generation => 8;
|
||||
public override EntityContext Context => EntityContext.Gen8b;
|
||||
public override PersonalTable8BDSP Personal => PersonalTable.BDSP;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_8b;
|
||||
public override ushort MaxSpeciesID => Legal.MaxSpeciesID_8b;
|
||||
|
@ -283,7 +283,7 @@ public sealed class SAV8BS : SaveFile, ISaveFileRevision, ITrainerStatRecord, IE
|
|||
public string Rival
|
||||
{
|
||||
get => GetString(Data.AsSpan(0x55F4, 0x1A));
|
||||
set => SetString(Data.AsSpan(0x55F4, 0x1A), value, MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SetString(Data.AsSpan(0x55F4, 0x1A), value, MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public short ZoneID // map
|
||||
|
|
|
@ -67,7 +67,7 @@ public sealed class SAV8LA : SaveFile, ISaveBlock8LA, ISCBlockArray, ISaveFileRe
|
|||
public override int MaxEV => EffortValues.Max252;
|
||||
public override byte Generation => 8;
|
||||
public override EntityContext Context => EntityContext.Gen8a;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
|
||||
public override bool ChecksumsValid => true;
|
||||
|
|
|
@ -151,7 +151,7 @@ public sealed class SAV8SWSH : SaveFile, ISaveBlock8SWSH, ITrainerStatRecord, IS
|
|||
public override int MaxEV => EffortValues.Max252;
|
||||
public override byte Generation => 8;
|
||||
public override EntityContext Context => EntityContext.Gen8;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
protected override PK8 GetPKM(byte[] data) => new(data);
|
||||
protected override byte[] DecryptPKM(byte[] data) => PokeCrypto.DecryptArray8(data);
|
||||
|
|
|
@ -157,7 +157,7 @@ public sealed class SAV9SV : SaveFile, ISaveBlock9Main, ISCBlockArray, ISaveFile
|
|||
public override int MaxEV => EffortValues.Max252;
|
||||
public override byte Generation => 9;
|
||||
public override EntityContext Context => EntityContext.Gen9;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthTrainer => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
protected override PK9 GetPKM(byte[] data) => new(data);
|
||||
protected override byte[] DecryptPKM(byte[] data) => PokeCrypto.DecryptArray9(data);
|
||||
|
|
|
@ -88,7 +88,7 @@ public abstract class SaveFile : ITrainerInfo, IGameValueLimit, IGeneration, IVe
|
|||
|
||||
#region Stored PKM Limits
|
||||
public abstract IPersonalTable Personal { get; }
|
||||
public abstract int MaxStringLengthOT { get; }
|
||||
public abstract int MaxStringLengthTrainer { get; }
|
||||
public abstract int MaxStringLengthNickname { get; }
|
||||
public abstract ushort MaxMoveID { get; }
|
||||
public abstract ushort MaxSpeciesID { get; }
|
||||
|
|
|
@ -42,7 +42,7 @@ public abstract class BulkStorage : SaveFile
|
|||
public sealed override int MaxItemID => blank.MaxItemID;
|
||||
public sealed override int MaxBallID => blank.MaxBallID;
|
||||
public sealed override GameVersion MaxGameID => blank.MaxGameID;
|
||||
public sealed override int MaxStringLengthOT => blank.MaxStringLengthOT;
|
||||
public sealed override int MaxStringLengthTrainer => blank.MaxStringLengthTrainer;
|
||||
public sealed override int MaxStringLengthNickname => blank.MaxStringLengthNickname;
|
||||
public bool IsBigEndian => blank is BK4 or XK3 or CK3;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ public sealed class PlayerData5(SAV5 sav, Memory<byte> raw) : SaveBlock<SAV5>(sa
|
|||
public string OT
|
||||
{
|
||||
get => SAV.GetString(OriginalTrainerTrash);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public uint ID32
|
||||
|
|
|
@ -106,7 +106,7 @@ public class MyStatus6(SAV6 sav, Memory<byte> raw) : SaveBlock<SAV6>(sav, raw),
|
|||
public string OT
|
||||
{
|
||||
get => SAV.GetString(OriginalTrainerTrash);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
private Span<byte> GetSayingSpan(int say) => Data.Slice(GetSayingOffset(say), SAV6.LongStringLength);
|
||||
|
|
|
@ -18,7 +18,7 @@ public sealed class FieldMenu7(SAV7 sav, Memory<byte> raw) : SaveBlock<SAV7>(sav
|
|||
public string RotomOT
|
||||
{
|
||||
get => SAV.GetString(RotomNameSpan);
|
||||
set => SAV.SetString(RotomNameSpan, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(RotomNameSpan, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
private Span<byte> RotomNameSpan => Data.Slice(0x30, 0x1A);
|
||||
|
|
|
@ -16,6 +16,6 @@ public sealed class Misc7b(SAV7b sav, Memory<byte> raw) : SaveBlock<SAV7b>(sav,
|
|||
public string Rival
|
||||
{
|
||||
get => SAV.GetString(Rival_Trash);
|
||||
set => SAV.SetString(Rival_Trash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(Rival_Trash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public sealed class MyStatus7b(SAV7b sav, Memory<byte> raw) : SaveBlock<SAV7b>(s
|
|||
public string OT
|
||||
{
|
||||
get => SAV.GetString(OriginalTrainerTrash);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
// The value here corresponds to a Trainer Class string (ranging from 000 to 383, use pkNX to get a full list).
|
||||
|
|
|
@ -98,7 +98,7 @@ public sealed class MyStatus7(SAV7 sav, Memory<byte> raw) : SaveBlock<SAV7>(sav,
|
|||
public string OT
|
||||
{
|
||||
get => SAV.GetString(OriginalTrainerTrash);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public int DressUpSkinColor
|
||||
|
|
|
@ -19,7 +19,7 @@ public sealed class MyStatus8b(SAV8BS sav, Memory<byte> raw) : SaveBlock<SAV8BS>
|
|||
public string OT
|
||||
{
|
||||
get => SAV.GetString(OriginalTrainerTrash);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public uint ID32
|
||||
|
|
|
@ -62,7 +62,7 @@ public sealed class MyStatus8a(SAV8LA sav, SCBlock block) : SaveBlock<SAV8LA>(sa
|
|||
public string OT
|
||||
{
|
||||
get => SAV.GetString(OriginalTrainerTrash);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public byte Unk_0x50
|
||||
|
|
|
@ -170,7 +170,7 @@ public sealed class MyStatus8(SAV8SWSH sav, SCBlock block) : SaveBlock<SAV8SWSH>
|
|||
public string OT
|
||||
{
|
||||
get => SAV.GetString(OriginalTrainerTrash);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
// D0
|
||||
|
|
|
@ -12,7 +12,7 @@ public sealed class TrainerCard8(SAV8SWSH sav, SCBlock block) : SaveBlock<SAV8SW
|
|||
public string OT
|
||||
{
|
||||
get => SAV.GetString(OriginalTrainerTrash);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public byte Language
|
||||
|
|
|
@ -83,7 +83,7 @@ public sealed class MyStatus9(SAV9SV sav, SCBlock block) : SaveBlock<SAV9SV>(sav
|
|||
public string OT
|
||||
{
|
||||
get => SAV.GetString(OriginalTrainerTrash);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
set => SAV.SetString(OriginalTrainerTrash, value, SAV.MaxStringLengthTrainer, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
public byte BirthMonth { get => Data[0x5A]; set => Data[0x5A] = value; }
|
||||
|
|
|
@ -1997,8 +1997,8 @@ public sealed partial class PKMEditor : UserControl, IMainEditor
|
|||
PopulateFields(Entity);
|
||||
|
||||
// Save File Specific Limits
|
||||
TB_OT.MaxLength = Entity.MaxStringLengthOT;
|
||||
TB_HT.MaxLength = Entity.MaxStringLengthOT;
|
||||
TB_OT.MaxLength = Entity.MaxStringLengthTrainer;
|
||||
TB_HT.MaxLength = Entity.MaxStringLengthTrainer;
|
||||
TB_Nickname.MaxLength = Entity.MaxStringLengthNickname;
|
||||
|
||||
// Hide Unused Tabs
|
||||
|
|
|
@ -131,7 +131,7 @@ public partial class PokePreview : Form
|
|||
display.Visible = true;
|
||||
}
|
||||
|
||||
public static Size MeasureSize(string text, Font font)
|
||||
public static Size MeasureSize(ReadOnlySpan<char> text, Font font)
|
||||
{
|
||||
const TextFormatFlags flags = TextFormatFlags.LeftAndRightPadding | TextFormatFlags.VerticalCenter;
|
||||
return TextRenderer.MeasureText(text, font, new Size(), flags);
|
||||
|
|
|
@ -18,7 +18,7 @@ public partial class SAV_SimpleTrainer : Form
|
|||
Loading = true;
|
||||
|
||||
cba = [CHK_1, CHK_2, CHK_3, CHK_4, CHK_5, CHK_6, CHK_7, CHK_8];
|
||||
TB_OTName.MaxLength = SAV.MaxStringLengthOT;
|
||||
TB_OTName.MaxLength = SAV.MaxStringLengthTrainer;
|
||||
B_MaxCash.Click += (sender, e) => MT_Money.Text = SAV.MaxMoney.ToString();
|
||||
B_MaxCoins.Click += (sender, e) => MT_Coins.Text = SAV.MaxCoins.ToString();
|
||||
MT_Money.Mask = "".PadRight((int)Math.Floor(Math.Log10(SAV.MaxMoney) + 1), '0');
|
||||
|
|
Loading…
Reference in a new issue