mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-10-01 06:16:51 -05:00
Extract switch-entity HT update logic, fix
Closes #4227 SlotWrite no longer revises the data incorrectly if ot&gender mismatch, clear memories and set new values can retain wrong values by having ot&gender shared between games
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using static PKHeX.Core.CheckIdentifier;
|
||||
|
||||
namespace PKHeX.Core.Bulk;
|
||||
@@ -35,7 +36,11 @@ private static void Verify(BulkAnalysis input, SlotCache cs)
|
||||
if (flag != 1)
|
||||
return;
|
||||
|
||||
if (pk.HandlingTrainerName != tr.OT)
|
||||
Span<char> ht = stackalloc char[pk.TrashCharCountTrainer];
|
||||
var len = pk.LoadString(pk.HandlingTrainerTrash, ht);
|
||||
ht = ht[..len];
|
||||
|
||||
if (!ht.SequenceEqual(tr.OT))
|
||||
input.AddLine(cs, LegalityCheckStrings.LTransferHTMismatchName, Trainer);
|
||||
if (pk is IHandlerLanguage h && h.HandlingTrainerLanguage != tr.Language)
|
||||
input.AddLine(cs, LegalityCheckStrings.LTransferHTMismatchLanguage, Trainer);
|
||||
|
||||
@@ -70,7 +70,11 @@ private void VerifyHandlerState(LegalityAnalysis data, bool neverOT)
|
||||
|
||||
if (flag == 1)
|
||||
{
|
||||
if (pk.HandlingTrainerName != tr.OT)
|
||||
Span<char> ht = stackalloc char[pk.TrashCharCountTrainer];
|
||||
var len = pk.LoadString(pk.HandlingTrainerTrash, ht);
|
||||
ht = ht[..len];
|
||||
|
||||
if (!ht.SequenceEqual(tr.OT))
|
||||
data.AddLine(GetInvalid(LTransferHTMismatchName));
|
||||
if (pk is IHandlerLanguage h && h.HandlingTrainerLanguage != tr.Language)
|
||||
data.AddLine(Get(LTransferHTMismatchLanguage, Severity.Fishy));
|
||||
|
||||
@@ -432,4 +432,43 @@ public override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
||||
=> StringConverter8.LoadString(data, destBuffer);
|
||||
public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter8.SetString(destBuffer, value, maxLength, option);
|
||||
|
||||
/// <summary>
|
||||
/// Revises the Handler details of a <see cref="PKM"/> to match the current <see cref="ITrainerInfo"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Logic used starting in SW/SH games.</remarks>
|
||||
public static void UpdateHandler<T>(T pk, ITrainerInfo tr)
|
||||
where T : PKM, IHandlerLanguage, IMemoryHT
|
||||
{
|
||||
pk.CurrentHandler = 1;
|
||||
|
||||
var gender = tr.Gender;
|
||||
var other = tr.OT;
|
||||
if (IsHandlerSame(pk, other, gender))
|
||||
return;
|
||||
|
||||
// Clear the old Handler details and write our new ones.
|
||||
pk.ClearMemoriesHT();
|
||||
pk.HandlingTrainerName = other;
|
||||
pk.HandlingTrainerLanguage = (byte)tr.Language;
|
||||
pk.HandlingTrainerGender = gender;
|
||||
pk.HandlingTrainerFriendship = pk.PersonalInfo.BaseFriendship;
|
||||
// Memories are deferred to the game. SW/SH does not immediately set memories.
|
||||
}
|
||||
|
||||
private static bool IsHandlerSame<T>(T pk, ReadOnlySpan<char> newHT, byte newGender)
|
||||
where T : PKM, IHandlerLanguage
|
||||
{
|
||||
if (newGender != pk.HandlingTrainerGender)
|
||||
return false;
|
||||
|
||||
// Does not check Language or Version for equality! Can result in mismatches or empty (0) language value.
|
||||
// Check the trainer string for equality (most expensive of all last).
|
||||
|
||||
Span<char> exist = stackalloc char[pk.TrashCharCountTrainer];
|
||||
var len = pk.LoadString(pk.HandlingTrainerTrash, exist);
|
||||
exist = exist[..len];
|
||||
|
||||
return exist.SequenceEqual(newHT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,17 +628,7 @@ private bool TradeOT(ITrainerInfo tr)
|
||||
return true;
|
||||
}
|
||||
|
||||
private void TradeHT(ITrainerInfo tr)
|
||||
{
|
||||
if (HandlingTrainerName != tr.OT)
|
||||
{
|
||||
HandlingTrainerFriendship = PersonalInfo.BaseFriendship;
|
||||
HandlingTrainerName = tr.OT;
|
||||
}
|
||||
CurrentHandler = 1;
|
||||
HandlingTrainerGender = tr.Gender;
|
||||
HandlingTrainerLanguage = (byte)tr.Language;
|
||||
}
|
||||
private void TradeHT(ITrainerInfo tr) => PKH.UpdateHandler(this, tr);
|
||||
|
||||
// Maximums
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_8a;
|
||||
|
||||
@@ -346,10 +346,15 @@ protected override bool TradeOT(ITrainerInfo tr)
|
||||
|
||||
protected override void TradeHT(ITrainerInfo tr)
|
||||
{
|
||||
if (HandlingTrainerName != tr.OT)
|
||||
Span<char> ht = stackalloc char[TrashCharCountTrainer];
|
||||
var len = LoadString(HandlingTrainerTrash, ht);
|
||||
ht = ht[..len];
|
||||
|
||||
var other = tr.OT;
|
||||
if (!ht.SequenceEqual(other))
|
||||
{
|
||||
HandlingTrainerName = other;
|
||||
HandlingTrainerFriendship = CurrentFriendship; // copy friendship instead of resetting (don't alter CP)
|
||||
HandlingTrainerName = tr.OT;
|
||||
}
|
||||
CurrentHandler = 1;
|
||||
HandlingTrainerGender = tr.Gender;
|
||||
|
||||
@@ -121,18 +121,7 @@ private bool TradeOT(ITrainerInfo tr)
|
||||
return true;
|
||||
}
|
||||
|
||||
private void TradeHT(ITrainerInfo tr)
|
||||
{
|
||||
if (HandlingTrainerName != tr.OT)
|
||||
{
|
||||
HandlingTrainerFriendship = PersonalInfo.BaseFriendship;
|
||||
HandlingTrainerName = tr.OT;
|
||||
}
|
||||
CurrentHandler = 1;
|
||||
HandlingTrainerGender = tr.Gender;
|
||||
HandlingTrainerLanguage = (byte)tr.Language;
|
||||
//this.SetTradeMemoryHT8();
|
||||
}
|
||||
private void TradeHT(ITrainerInfo tr) => PKH.UpdateHandler(this, tr);
|
||||
|
||||
// Maximums
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_8b;
|
||||
|
||||
@@ -428,17 +428,18 @@ protected override bool TradeOT(ITrainerInfo tr)
|
||||
|
||||
protected override void TradeHT(ITrainerInfo tr)
|
||||
{
|
||||
if (tr.OT != HandlingTrainerName || tr.Gender != HandlingTrainerGender || (Geo1_Country == 0 && Geo1_Region == 0 && !IsUntradedEvent6))
|
||||
{
|
||||
if (tr is IRegionOrigin o)
|
||||
this.TradeGeoLocation(o.Country, o.Region);
|
||||
}
|
||||
Span<char> ht = stackalloc char[TrashCharCountTrainer];
|
||||
var len = LoadString(HandlingTrainerTrash, ht);
|
||||
ht = ht[..len];
|
||||
|
||||
if (tr.OT != HandlingTrainerName)
|
||||
var other = tr.OT;
|
||||
if (!ht.SequenceEqual(other) || tr.Gender != HandlingTrainerGender || (Geo1_Country == 0 && Geo1_Region == 0 && !IsUntradedEvent6))
|
||||
{
|
||||
HandlingTrainerName = other;
|
||||
HandlingTrainerFriendship = PersonalInfo.BaseFriendship;
|
||||
HandlingTrainerAffection = 0;
|
||||
HandlingTrainerName = tr.OT;
|
||||
if (tr is IRegionOrigin o)
|
||||
this.TradeGeoLocation(o.Country, o.Region);
|
||||
}
|
||||
CurrentHandler = 1;
|
||||
HandlingTrainerGender = tr.Gender;
|
||||
|
||||
@@ -486,17 +486,19 @@ protected override bool TradeOT(ITrainerInfo tr)
|
||||
|
||||
protected override void TradeHT(ITrainerInfo tr)
|
||||
{
|
||||
if (tr.OT != HandlingTrainerName || tr.Gender != HandlingTrainerGender || (Geo1_Country == 0 && Geo1_Region == 0 && !IsUntradedEvent6))
|
||||
{
|
||||
// No geolocations are set ingame -- except for bank transfers. Don't emulate bank transfers
|
||||
// this.TradeGeoLocation(tr.Country, tr.SubRegion);
|
||||
}
|
||||
// No geolocations are set in-game -- except for bank transfers. Don't emulate bank transfers
|
||||
// this.TradeGeoLocation(tr.Country, tr.SubRegion);
|
||||
|
||||
if (HandlingTrainerName != tr.OT)
|
||||
Span<char> ht = stackalloc char[TrashCharCountTrainer];
|
||||
var len = LoadString(HandlingTrainerTrash, ht);
|
||||
ht = ht[..len];
|
||||
|
||||
var other = tr.OT;
|
||||
if (!ht.SequenceEqual(other))
|
||||
{
|
||||
HandlingTrainerName = other;
|
||||
HandlingTrainerFriendship = PersonalInfo.BaseFriendship;
|
||||
HandlingTrainerAffection = 0;
|
||||
HandlingTrainerName = tr.OT;
|
||||
}
|
||||
CurrentHandler = 1;
|
||||
HandlingTrainerGender = tr.Gender;
|
||||
|
||||
@@ -103,18 +103,7 @@ private bool TradeOT(ITrainerInfo tr)
|
||||
return true;
|
||||
}
|
||||
|
||||
private void TradeHT(ITrainerInfo tr)
|
||||
{
|
||||
if (HandlingTrainerName != tr.OT)
|
||||
{
|
||||
HandlingTrainerFriendship = 50;
|
||||
HandlingTrainerName = tr.OT;
|
||||
}
|
||||
CurrentHandler = 1;
|
||||
HandlingTrainerGender = tr.Gender;
|
||||
HandlingTrainerLanguage = (byte)tr.Language;
|
||||
this.SetTradeMemoryHT8();
|
||||
}
|
||||
private void TradeHT(ITrainerInfo tr) => PKH.UpdateHandler(this, tr);
|
||||
|
||||
// Maximums
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_8;
|
||||
|
||||
@@ -661,19 +661,7 @@ private bool TradeOT(ITrainerInfo tr)
|
||||
return true;
|
||||
}
|
||||
|
||||
private void TradeHT(ITrainerInfo tr)
|
||||
{
|
||||
if (HandlingTrainerName != tr.OT)
|
||||
{
|
||||
HandlingTrainerFriendship = 50;
|
||||
HandlingTrainerName = tr.OT;
|
||||
}
|
||||
CurrentHandler = 1;
|
||||
HandlingTrainerGender = tr.Gender;
|
||||
if (HandlingTrainerLanguage == 0)
|
||||
this.ClearMemoriesHT();
|
||||
HandlingTrainerLanguage = (byte)tr.Language;
|
||||
}
|
||||
private void TradeHT(ITrainerInfo tr) => PKH.UpdateHandler(this, tr);
|
||||
|
||||
// Maximums
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_9;
|
||||
|
||||
@@ -10,6 +10,13 @@ namespace PKHeX.WinForms;
|
||||
public partial class TrashEditor : Form
|
||||
{
|
||||
private readonly IStringConverter Converter;
|
||||
private readonly ToolTip Tip = new() { InitialDelay = 200, IsBalloon = false, AutoPopDelay = 32_767 };
|
||||
private readonly List<NumericUpDown> Bytes = [];
|
||||
public string FinalString { get; private set; }
|
||||
public byte[] FinalBytes { get; private set; }
|
||||
|
||||
private readonly byte[] Raw;
|
||||
private bool editing;
|
||||
|
||||
public TrashEditor(TextBoxBase TB_NN, IStringConverter sav, byte generation) : this(TB_NN, [], sav, generation) { }
|
||||
|
||||
@@ -60,12 +67,6 @@ public TrashEditor(TextBoxBase TB_NN, Span<byte> raw, IStringConverter converter
|
||||
};
|
||||
}
|
||||
|
||||
private readonly ToolTip Tip = new() { InitialDelay = 200, IsBalloon = false, AutoPopDelay = 32_767 };
|
||||
private readonly List<NumericUpDown> Bytes = [];
|
||||
public string FinalString;
|
||||
public byte[] FinalBytes;
|
||||
private readonly byte[] Raw;
|
||||
private bool editing;
|
||||
private void B_Cancel_Click(object sender, EventArgs e) => Close();
|
||||
|
||||
private void B_Save_Click(object sender, EventArgs e)
|
||||
@@ -153,8 +154,10 @@ private void UpdateString(object sender, EventArgs e)
|
||||
return;
|
||||
editing = true;
|
||||
// build bytes
|
||||
byte[] data = SetString(TB_Text.Text);
|
||||
Array.Copy(data, Raw, Math.Min(data.Length, Raw.Length));
|
||||
ReadOnlySpan<byte> data = SetString(TB_Text.Text);
|
||||
if (data.Length > Raw.Length)
|
||||
data = data[..Raw.Length];
|
||||
data.CopyTo(Raw);
|
||||
for (int i = 0; i < Raw.Length; i++)
|
||||
Bytes[i].Value = Raw[i];
|
||||
editing = false;
|
||||
@@ -163,8 +166,8 @@ private void UpdateString(object sender, EventArgs e)
|
||||
private void B_ApplyTrash_Click(object sender, EventArgs e)
|
||||
{
|
||||
string text = GetTrashString();
|
||||
byte[] data = SetString(text);
|
||||
byte[] current = SetString(TB_Text.Text);
|
||||
ReadOnlySpan<byte> data = SetString(text);
|
||||
ReadOnlySpan<byte> current = SetString(TB_Text.Text);
|
||||
if (data.Length <= current.Length)
|
||||
{
|
||||
WinFormsUtil.Alert("Trash byte layer is hidden by current text.",
|
||||
|
||||
Reference in New Issue
Block a user