Fix daycare slot read

Closes #4279
adds writeback for daycare in gen2 as well
This commit is contained in:
Kurt
2024-05-23 13:31:23 -05:00
parent 93ae048246
commit cd6eadcd8d
4 changed files with 129 additions and 50 deletions

View File

@@ -271,4 +271,46 @@ public static byte[] WrapSingle(PK1 pk)
/// <param name="pk">Entity to wrap</param>
/// <param name="output">Destination to write the single-slot list</param>
public static void WrapSingle(PK1 pk, Span<byte> output) => WriteToList(output, pk);
public static void UnpackNOB(ReadOnlySpan<byte> input, Span<byte> output, int stringLength, bool isParty = false)
{
// Nickname, OT, Data
var lengthBody = GetBodyLength(isParty);
var lengthParty = GetBodyLength(true);
var nick = input[..stringLength];
var trainer = input.Slice(stringLength, stringLength);
var box = input.Slice(stringLength * 2, lengthBody);
var marker = box[0];
if (marker is 0) // Ensure deleted (zeroed) slots act as an Empty (FF) slot.
marker = SlotEmpty;
output[0] = 1;
output[1] = marker;
output = output[3..];
// Data, OT, Nickname
box.CopyTo(output);
output = output[lengthParty..];
trainer.CopyTo(output);
output = output[stringLength..];
nick.CopyTo(output);
}
public static void PackNOB(ReadOnlySpan<byte> input, Span<byte> output, int stringLength, bool isParty = false)
{
var lengthBody = GetBodyLength(isParty);
var lengthParty = GetBodyLength(true);
input = input[3..]; // Skip header.
var box = input[..lengthBody];
var trainer = input.Slice(lengthParty, stringLength);
var nick = input.Slice(lengthParty + stringLength, stringLength);
nick.CopyTo(output);
output = output[stringLength..];
trainer.CopyTo(output);
output = output[stringLength..];
box.CopyTo(output);
}
}

View File

@@ -274,4 +274,46 @@ public static byte[] WrapSingle(PK2 pk)
/// <param name="pk">Entity to wrap</param>
/// <param name="output">Destination to write the single-slot list</param>
public static void WrapSingle(PK2 pk, Span<byte> output) => WriteToList(output, pk);
public static void UnpackNOB(ReadOnlySpan<byte> input, Span<byte> output, int stringLength, bool isParty = false)
{
// Nickname, OT, Data
var lengthBody = GetBodyLength(isParty);
var lengthParty = GetBodyLength(true);
var nick = input[..stringLength];
var trainer = input.Slice(stringLength, stringLength);
var box = input.Slice(stringLength * 2, lengthBody);
var marker = box[0];
if (marker is 0) // Ensure deleted (zeroed) slots act as an Empty (FF) slot.
marker = SlotEmpty;
output[0] = 1;
output[1] = marker;
output = output[3..];
// Data, OT, Nickname
box.CopyTo(output);
output = output[lengthParty..];
trainer.CopyTo(output);
output = output[stringLength..];
nick.CopyTo(output);
}
public static void PackNOB(ReadOnlySpan<byte> input, Span<byte> output, int stringLength, bool isParty = false)
{
var lengthBody = GetBodyLength(isParty);
var lengthParty = GetBodyLength(true);
input = input[3..]; // Skip header.
var box = input[..lengthBody];
var trainer = input.Slice(lengthParty, stringLength);
var nick = input.Slice(lengthParty + stringLength, stringLength);
nick.CopyTo(output);
output = output[stringLength..];
trainer.CopyTo(output);
output = output[stringLength..];
box.CopyTo(output);
}
}

View File

@@ -105,20 +105,11 @@ private void Initialize(GameVersion versionOverride)
PokeList1.Unpack(src, dest, StringLength, 6, true);
}
ReadOnlySpan<byte> rawDC = Data.AsSpan(Offsets.Daycare, 0x38);
var daycareOffset = DaycareOffset = GetPartyOffset(6);
var TempDaycare = BoxBuffer[daycareOffset..];
TempDaycare[0] = rawDC[0];
var dcDest = TempDaycare[3..];
// OT, Nickname, and Core data (rather than the reverse...)
rawDC.Slice(1, StringLength).CopyTo(dcDest[(PokeCrypto.SIZE_1PARTY + StringLength)..]);
rawDC.Slice(1 + StringLength, StringLength).CopyTo(dcDest[PokeCrypto.SIZE_1PARTY..]);
rawDC.Slice(1 + (2 * StringLength), PokeCrypto.SIZE_1STORED).CopyTo(dcDest);
var dc = Data.AsSpan(Offsets.Daycare, 0x38);
PokeList1.UnpackNOB(dc[1..], PartyBuffer[DaycareOffset..], StringLength);
}
private int DaycareOffset = -1;
private int DaycareOffset => GetPartyOffset(6);
public override bool HasPokeDex => true;
// Event Flags
@@ -177,12 +168,7 @@ protected override byte[] GetFinalData()
}
// Daycare is read-only, but in case it ever becomes editable, copy it back in.
Span<byte> rawDC = Data.AsSpan(Offsets.Daycare, 0x38);
var TempDaycare = BoxBuffer[DaycareOffset..];
var dcDest = TempDaycare[3..];
dcDest.Slice(2 + 1 + PokeCrypto.SIZE_1PARTY + StringLength, StringLength).CopyTo(rawDC[1..]);
dcDest.Slice(2 + 1 + PokeCrypto.SIZE_1PARTY, StringLength).CopyTo(rawDC[(1 + StringLength)..]);
dcDest.Slice(2 + 1, PokeCrypto.SIZE_1STORED).CopyTo(rawDC[(1 + (2 * StringLength))..]);
PokeList1.PackNOB(PartyBuffer[DaycareOffset..], Data.AsSpan(Offsets.Daycare, 0x38)[1..], StringLength);
SetChecksums();
return Data;

View File

@@ -104,48 +104,43 @@ private void Initialize()
if (Offsets.Daycare >= 0)
{
int offset = Offsets.Daycare;
var dc0 = PartyBuffer[GetDaycareSlotOffset(0)..];
PokeList2.UnpackNOB(Data.AsSpan(GetRawDaycareSlotOffset(0)), dc0, StringLength);
offset++;
var pk1 = ReadPKMFromOffset(offset); // parent 1
offset += (StringLength * 2) + 0x20; // nick/ot/pk
offset++;
//byte steps = Data[offset];
offset++;
//byte BreedMotherOrNonDitto = Data[offset];
offset++;
var pk2 = ReadPKMFromOffset(offset); // parent 2
offset += (StringLength * 2) + PokeCrypto.SIZE_2STORED; // nick/ot/pk
var pk3 = ReadPKMFromOffset(offset); // egg!
pk3.IsEgg = true;
var dc1 = PartyBuffer[GetDaycareSlotOffset(1)..];
PokeList2.UnpackNOB(Data.AsSpan(GetRawDaycareSlotOffset(1)), dc1, StringLength);
PokeList2.WriteToList(PartyBuffer[GetPartyOffset(6 + (0 * 2))..], pk1, 1, true);
PokeList2.WriteToList(PartyBuffer[GetPartyOffset(6 + (1 * 2))..], pk2, 1, true);
PokeList2.WriteToList(PartyBuffer[GetPartyOffset(6 + (2 * 2))..], pk3, 1, true);
var egg = PartyBuffer[GetDaycareSlotOffset(2)..];
PokeList2.UnpackNOB(Data.AsSpan(GetRawDaycareSlotOffset(2)), egg, StringLength);
if (egg[2] != PokeList2.SlotEmpty)
egg[1] = PokeList2.SlotEgg;
}
}
private int GetRawDaycareSlotOffset(int index)
{
int offset = Offsets.Daycare;
offset++; // Breeding Status flags
if (index == 0)
return offset;
offset += (StringLength * 2) + PokeCrypto.SIZE_2STORED; // nick/ot/pk
offset++; // Lady Status flags
offset++; // Steps until Egg
offset++; // Ditto Parent state
if (index == 1)
return offset;
offset += (StringLength * 2) + PokeCrypto.SIZE_2STORED; // nick/ot/pk
return offset;
}
public override bool HasPokeDex => true;
private int EventFlag => Offsets.EventFlag;
private int EventWork => Offsets.EventWork;
private PK2 ReadPKMFromOffset(int offset)
{
var stringLength = StringLength;
var span = Data.AsSpan(offset);
var pkData = span.Slice(stringLength * 2, PokeCrypto.SIZE_2STORED).ToArray();
var pk = new PK2(pkData, jp: Japanese);
var nick = span[..stringLength];
var ot = span.Slice(stringLength, stringLength);
nick.CopyTo(pk.NicknameTrash);
ot.CopyTo(pk.OriginalTrainerTrash);
return pk;
}
private int GetBoxRawDataOffset(int i, int splitAtIndex)
{
if (i < splitAtIndex)
@@ -178,6 +173,20 @@ protected override byte[] GetFinalData()
PokeList2.MergeSingles(src, dest, StringLength, 6, true);
}
// Write Daycare
if (Offsets.Daycare >= 0)
{
var dc0 = PartyBuffer[GetDaycareSlotOffset(0)..];
PokeList2.PackNOB(dc0, Data.AsSpan(GetRawDaycareSlotOffset(0)), StringLength);
var dc1 = PartyBuffer[GetDaycareSlotOffset(1)..];
PokeList2.PackNOB(dc1, Data.AsSpan(GetRawDaycareSlotOffset(1)), StringLength);
var egg = PartyBuffer[GetDaycareSlotOffset(2)..];
PokeList2.PackNOB(egg, Data.AsSpan(GetRawDaycareSlotOffset(2)), StringLength);
}
SetChecksums();
if (Japanese)
{