Improve handling of multi-nicknamed mystery gifts

This commit is contained in:
Kurt 2021-02-01 18:35:37 -08:00
parent 6d41d6a17c
commit 9124a3c62b
4 changed files with 147 additions and 20 deletions

View file

@ -30,6 +30,12 @@ namespace PKHeX.Core
}
var enc = data.EncounterOriginal;
if (enc is ILangNicknamedTemplate n)
{
VerifyFixedNicknameEncounter(data, n, enc, pkm, nickname);
return;
}
if (pkm.Format <= 7 && pkm.IsNicknamed) // can nickname afterwards
{
if (pkm.VC)
@ -65,6 +71,38 @@ namespace PKHeX.Core
}
}
private void VerifyFixedNicknameEncounter(LegalityAnalysis data, ILangNicknamedTemplate n, IEncounterTemplate enc, PKM pkm, string nickname)
{
var nick = n.GetNickname(pkm.Language);
if (string.IsNullOrWhiteSpace(nick))
{
if (pkm.IsNicknamed)
data.AddLine(Get(LEncGiftNicknamed, Severity.Invalid));
return;
}
if (!pkm.IsNicknamed)
{
// Check if it had a nickname at all
var orig = SpeciesName.GetSpeciesNameGeneration(enc.Species, pkm.Language, enc.Generation);
if (orig == nick)
{
// Didn't have a nickname. Ensure that the language matches the current nickname string.
if (!SpeciesName.IsNicknamed(pkm.Species, nickname, pkm.Language, pkm.Format))
return;
}
// Should have a nickname present.
data.AddLine(GetInvalid(LNickMatchLanguageFail));
return;
}
// Encounter has a nickname, and PKM should have it.
var severity = nick != nickname || !pkm.IsNicknamed ? Severity.Invalid : Severity.Valid;
data.AddLine(Get(LEncGiftNicknamed, severity));
}
private bool VerifyUnNicknamedEncounter(LegalityAnalysis data, PKM pkm, string nickname)
{
if (pkm.IsNicknamed)

View file

@ -7,7 +7,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 7 Mystery Gift Template File
/// </summary>
public sealed class WB7 : DataMysteryGift, ILangNick, IAwakened, INature
public sealed class WB7 : DataMysteryGift, ILangNick, IAwakened, INature, ILangNicknamedTemplate
{
public const int Size = 0x108;
public const int SizeFull = 0x310;
@ -22,7 +22,7 @@ namespace PKHeX.Core
public bool CanBeReceivedByVersion(int v)
{
if (v < (int)GameVersion.GP || v > (int)GameVersion.GE)
if (v is not ((int)GameVersion.GP or (int)GameVersion.GE))
return false;
if (RestrictVersion == 0)
return true; // no data
@ -274,6 +274,14 @@ namespace PKHeX.Core
public bool IsNicknamed => false;
public int Language => 2;
public bool IsForcedNickname() => false;
public int GetLanguage(int redeemLanguage)
{
var languageOffset = GetLanguageIndex(redeemLanguage);
return Data[0x1D8 + languageOffset];
}
public string GetNickname(int language) => StringConverter.GetString7(Data, GetNicknameOffset(language), 0x1A);
public void SetNickname(int language, string value) => StringConverter.SetString7b(value, 12, 2, 13).CopyTo(Data, GetNicknameOffset(language));
@ -302,7 +310,11 @@ namespace PKHeX.Core
int currentLevel = Level > 0 ? Level : rnd.Next(1, 101);
int metLevel = MetLevel > 0 ? MetLevel : currentLevel;
var pi = PersonalTable.GG.GetFormEntry(Species, Form);
var OT = GetOT(sav.Language);
var redeemLanguage = sav.Language;
var language = GetLanguage(redeemLanguage);
var OT = GetOT(redeemLanguage);
bool isRedeemHT = OT.Length != 0;
var pk = new PB7
{
@ -314,7 +326,7 @@ namespace PKHeX.Core
Form = Form,
EncryptionConstant = EncryptionConstant != 0 ? EncryptionConstant : Util.Rand32(),
Version = OriginGame != 0 ? OriginGame : sav.Game,
Language = sav.Language,
Language = language,
Ball = Ball,
Move1 = Move1,
Move2 = Move2,
@ -333,17 +345,22 @@ namespace PKHeX.Core
AV_SPA = AV_SPA,
AV_SPD = AV_SPD,
OT_Name = OT.Length > 0 ? OT : sav.OT,
OT_Name = isRedeemHT ? OT : sav.OT,
OT_Gender = OTGender != 3 ? OTGender % 2 : sav.Gender,
HT_Name = OT_Name.Length > 0 ? sav.OT : string.Empty,
HT_Gender = OT_Name.Length > 0 ? sav.Gender : 0,
CurrentHandler = OT_Name.Length > 0 ? 1 : 0,
CurrentHandler = isRedeemHT ? 1 : 0,
EXP = Experience.GetEXP(currentLevel, pi.EXPGrowth),
OT_Friendship = pi.BaseFriendship,
FatefulEncounter = true,
};
if (isRedeemHT)
{
pk.HT_Name = sav.OT;
pk.HT_Gender = sav.Gender;
}
pk.SetMaximumPPCurrent();
if ((sav.Generation > Generation && OriginGame == 0) || !CanBeReceivedByVersion(pk.Version))
@ -360,8 +377,8 @@ namespace PKHeX.Core
}
pk.MetDate = Date ?? DateTime.Now;
pk.IsNicknamed = GetIsNicknamed(pk.Language);
pk.Nickname = pk.IsNicknamed ? GetNickname(pk.Language) : SpeciesName.GetSpeciesNameGeneration(Species, pk.Language, Generation);
pk.IsNicknamed = GetIsNicknamed(redeemLanguage);
pk.Nickname = pk.IsNicknamed ? GetNickname(redeemLanguage) : SpeciesName.GetSpeciesNameGeneration(Species, pk.Language, Generation);
SetPINGA(pk, criteria);
@ -445,6 +462,27 @@ namespace PKHeX.Core
pk.IVs = finalIVs;
}
public bool CanHaveLanguage(int language)
{
if (language is < (int) LanguageID.Japanese or > (int) LanguageID.ChineseT)
return false;
if (CanBeAnyLanguage())
return true;
return Array.IndexOf(Data, language, 0x1D8, 9) >= 0;
}
public bool CanBeAnyLanguage()
{
for (int i = 0; i < 9; i++)
{
if (Data[0x1D8 + i] != 0)
return false;
}
return true;
}
public override bool IsMatchExact(PKM pkm, DexLevel evo)
{
if (pkm.Egg_Location == 0) // Not Egg
@ -459,6 +497,9 @@ namespace PKHeX.Core
if (!string.IsNullOrEmpty(OT) && OT != pkm.OT_Name) return false;
if (OriginGame != 0 && OriginGame != pkm.Version) return false;
if (EncryptionConstant != 0 && EncryptionConstant != pkm.EncryptionConstant) return false;
if (!CanBeAnyLanguage() && !CanHaveLanguage(pkm.Language))
return false;
}
if (Form != evo.Form && !FormInfo.IsFormChangeable(Species, Form, pkm.Form, pkm.Format))

View file

@ -8,7 +8,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 8 Mystery Gift Template File
/// </summary>
public sealed class WC8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDynamaxLevel, IRibbonIndex, IMemoryOT,
public sealed class WC8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDynamaxLevel, IRibbonIndex, IMemoryOT, ILangNicknamedTemplate,
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8
{
public const int Size = 0x2D0;
@ -259,7 +259,38 @@ namespace PKHeX.Core
public bool GetIsNicknamed(int language) => BitConverter.ToUInt16(Data, GetNicknameOffset(language)) != 0;
public int GetNicknameLanguage(int language) => Data[GetNicknameOffset(language) + 0x1A];
public bool CanBeAnyLanguage()
{
for (int i = 0; i < 9; i++)
{
var ofs = GetLanguageOffset(i);
var lang = BitConverter.ToInt16(Data, ofs);
if (lang != 0)
return false;
}
return true;
}
public bool CanHaveLanguage(int language)
{
if (language is < (int)LanguageID.Japanese or > (int)LanguageID.ChineseT)
return false;
if (CanBeAnyLanguage())
return true;
for (int i = 0; i < 9; i++)
{
var ofs = GetLanguageOffset(i);
var lang = BitConverter.ToInt16(Data, ofs);
if (lang == language)
return true;
}
return false;
}
public int GetLanguage(int redeemLanguage) => Data[GetLanguageOffset(GetLanguageIndex(redeemLanguage))];
private static int GetLanguageOffset(int index) => 0x12C + (index * 0x1C) + 0x1A;
public bool GetHasOT(int language) => BitConverter.ToUInt16(Data, GetOTOffset(language)) != 0;
@ -330,7 +361,9 @@ namespace PKHeX.Core
int currentLevel = Level > 0 ? Level : Util.Rand.Next(1, 101);
int metLevel = MetLevel > 0 ? MetLevel : currentLevel;
var pi = PersonalTable.SWSH.GetFormEntry(Species, Form);
var OT = GetOT(sav.Language);
var language = sav.Language;
var OT = GetOT(language);
bool hasOT = GetHasOT(language);
var pk = new PK8
{
@ -359,10 +392,10 @@ namespace PKHeX.Core
OT_Name = OT.Length > 0 ? OT : sav.OT,
OT_Gender = OTGender < 2 ? OTGender : sav.Gender,
HT_Name = GetHasOT(Language) ? sav.OT : string.Empty,
HT_Gender = GetHasOT(Language) ? sav.Gender : 0,
HT_Language = GetHasOT(Language) ? sav.Language : 0,
CurrentHandler = GetHasOT(Language) ? 1 : 0,
HT_Name = hasOT ? sav.OT : string.Empty,
HT_Gender = hasOT ? sav.Gender : 0,
HT_Language = hasOT ? language : 0,
CurrentHandler = hasOT ? 1 : 0,
OT_Friendship = pi.BaseFriendship,
OT_Intensity = OT_Intensity,
@ -410,10 +443,10 @@ namespace PKHeX.Core
pk.MetDate = DateTime.Now;
var nickname_language = GetNicknameLanguage(sav.Language);
var nickname_language = GetLanguage(language);
pk.Language = nickname_language != 0 ? nickname_language : sav.Language;
pk.IsNicknamed = GetIsNicknamed(pk.Language);
pk.Nickname = pk.IsNicknamed ? Nickname : SpeciesName.GetSpeciesNameGeneration(Species, pk.Language, Generation);
pk.IsNicknamed = GetIsNicknamed(language);
pk.Nickname = pk.IsNicknamed ? GetNickname(language) : SpeciesName.GetSpeciesNameGeneration(Species, pk.Language, Generation);
for (var i = 0; i < RibbonBytesCount; i++)
{
@ -524,6 +557,10 @@ namespace PKHeX.Core
if (TID != pkm.TID) return false;
if (OTGender != pkm.OT_Gender) return false;
}
if (!CanBeAnyLanguage() && !CanHaveLanguage(pkm.Language))
return false;
var OT = GetOT(pkm.Language); // May not be guaranteed to work.
if (!string.IsNullOrEmpty(OT) && OT != pkm.OT_Name) return false;
if (OriginGame != 0 && OriginGame != pkm.Version) return false;

View file

@ -0,0 +1,11 @@
namespace PKHeX.Core
{
internal interface ILangNicknamedTemplate
{
string GetNickname(int language);
bool GetIsNicknamed(int language);
bool CanBeAnyLanguage();
bool CanHaveLanguage(int language);
}
}