mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-05-22 07:41:44 -05:00
All logic in PokeCrypto is separate from the rest of the PKHeX.Core library; makes it easy to just rip this portion out and reuse in other projects without needing the entirety of PKHeX.Core logic optimize out the CheckEncrypted to the actual path, separate methods. Only usages of this method were with hardcoded Format values, so no impact
126 lines
3.6 KiB
C#
126 lines
3.6 KiB
C#
using System;
|
|
|
|
namespace PKHeX.Core
|
|
{
|
|
/// <summary>
|
|
/// Generation 5 Entree Forest
|
|
/// </summary>
|
|
public sealed class EntreeForest
|
|
{
|
|
/// <summary>
|
|
/// Areas 1 thru 8 have 20 slots.
|
|
/// </summary>
|
|
private const byte Count18 = 20;
|
|
|
|
/// <summary>
|
|
/// 9th Area has only 10 slots.
|
|
/// </summary>
|
|
private const byte Count9 = 10;
|
|
|
|
private const int TotalSlots = Count18 + (3 * 8 * Count18) + (3 * Count9); // 530
|
|
|
|
/// <summary>
|
|
/// Areas 3 thru 8 can be unlocked (set a value 0 to 6).
|
|
/// </summary>
|
|
private const byte MaxUnlock38Areas = 6;
|
|
|
|
private const int EncryptionSeedOffset = 0x84C;
|
|
|
|
private readonly byte[] Data;
|
|
|
|
public EntreeForest(byte[] data)
|
|
{
|
|
Data = data;
|
|
PokeCrypto.CryptArray(data, EncryptionSeed, 0, EncryptionSeedOffset);
|
|
}
|
|
|
|
public byte[] Write()
|
|
{
|
|
byte[] data = (byte[])Data.Clone();
|
|
PokeCrypto.CryptArray(data, EncryptionSeed, 0, EncryptionSeedOffset);
|
|
return data;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all Entree Slot data.
|
|
/// </summary>
|
|
public EntreeSlot[] Slots
|
|
{
|
|
get
|
|
{
|
|
var slots = new EntreeSlot[TotalSlots];
|
|
for (int i = 0; i < slots.Length; i++)
|
|
slots[i] = new EntreeSlot(Data, i * 4) { Area = GetSlotArea(i) };
|
|
return slots;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if the 9th Area is available to enter.
|
|
/// </summary>
|
|
public bool Unlock9thArea
|
|
{
|
|
get => Data[0x848] == 1;
|
|
set => Data[0x848] = (byte)(value ? 1 : 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines how many extra areas are available to enter. Areas 1 & 2 are already available by default.
|
|
/// </summary>
|
|
public int Unlock38Areas
|
|
{
|
|
get => Data[0x849];
|
|
set => Data[0x849] = (byte)Math.Min(MaxUnlock38Areas, value);
|
|
}
|
|
|
|
public uint EncryptionSeed
|
|
{
|
|
get => BitConverter.ToUInt32(Data, EncryptionSeedOffset);
|
|
private set => BitConverter.GetBytes(value).CopyTo(Data, EncryptionSeedOffset);
|
|
}
|
|
|
|
public void UnlockAllAreas()
|
|
{
|
|
Unlock38Areas = MaxUnlock38Areas;
|
|
Unlock9thArea = true;
|
|
}
|
|
|
|
public void DeleteAll()
|
|
{
|
|
foreach (var e in Slots)
|
|
e.Delete();
|
|
}
|
|
|
|
private static EntreeForestArea GetSlotArea(int index)
|
|
{
|
|
if (index < Count18)
|
|
return EntreeForestArea.Deepest;
|
|
index -= Count18;
|
|
|
|
const int slots9 = 3 * Count9;
|
|
if (index < slots9)
|
|
return EntreeForestArea.Ninth | GetSlotPosition(index / Count9);
|
|
index -= slots9;
|
|
|
|
const int slots18 = 3 * Count18;
|
|
int area = index / slots18;
|
|
if (area >= 8)
|
|
throw new ArgumentOutOfRangeException(nameof(index));
|
|
index %= slots18;
|
|
|
|
return (EntreeForestArea)((int)EntreeForestArea.First << area) | GetSlotPosition(index / Count18);
|
|
}
|
|
|
|
private static EntreeForestArea GetSlotPosition(int index)
|
|
{
|
|
return index switch
|
|
{
|
|
0 => EntreeForestArea.Center,
|
|
1 => EntreeForestArea.Left,
|
|
2 => EntreeForestArea.Right,
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
};
|
|
}
|
|
}
|
|
}
|