Add entree forest abstractions

make cryptarray public
This commit is contained in:
Kurt
2018-05-27 14:19:19 -07:00
parent 4c1e014a53
commit 730709b33b
4 changed files with 200 additions and 1 deletions

View File

@@ -492,7 +492,7 @@ private static void CryptPKM45(byte[] data, uint pv, uint chk, int blockSize)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CryptArray(byte[] data, uint seed, int start, int end)
public static void CryptArray(byte[] data, uint seed, int start, int end)
{
for (int i = start; i < end; i += 2)
Crypt(data, ref seed, i);

View File

@@ -0,0 +1,119 @@
using System;
namespace PKHeX.Core
{
public 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);
/// <summary>
/// Areas 3 thru 8 can be unlocked (set a value 0 to 6).
/// </summary>
private const byte MaxUnlock38Areas = 6;
private readonly byte[] Data;
public EntreeForest(byte[] data)
{
Data = data;
PKX.CryptArray(data, EncryptionSeed, 0, data.Length);
}
public byte[] Write()
{
byte[] data = (byte[])Data.Clone();
PKX.CryptArray(data, EncryptionSeed, 0, data.Length);
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.Max(MaxUnlock38Areas, value);
}
public uint EncryptionSeed
{
get => BitConverter.ToUInt32(Data, 0x84C);
private set => BitConverter.GetBytes(value).CopyTo(Data, 0x84C);
}
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)
{
switch (index)
{
case 0: return EntreeForestArea.Center;
case 1: return EntreeForestArea.Left;
case 2: return EntreeForestArea.Right;
default: throw new ArgumentOutOfRangeException();
}
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
namespace PKHeX.Core
{
[Flags]
public enum EntreeForestArea
{
Deepest = 1 << 0,
First = 1 << 1,
Second = 1 << 2,
Third = 1 << 3,
Fourth = 1 << 4,
Fifth = 1 << 5,
Sixth = 1 << 6,
Seventh = 1 << 7,
Eighth = 1 << 8,
Ninth = 1 << 9,
Left = 1 << 10,
Right = 1 << 11,
Center = 1 << 12,
}
}

View File

@@ -0,0 +1,57 @@
using System;
namespace PKHeX.Core
{
public class EntreeSlot
{
public int Species // bits 0-10
{
get => (int)(RawValue & 0x7FF) >> 0;
set => RawValue = (RawValue & 0xFFFF_F800) | ((uint)value << 0);
}
public int Move // bits 11-20
{
get => (int)(RawValue & 0x1F_F800) >> 10;
set => RawValue = (RawValue & 0xFFF0_02FF) | ((uint)value << 10);
}
public int Gender // bits 21-22
{
get => (int)(RawValue & 60_0000) >> 21;
set => RawValue = (RawValue & 0xFF9F_FFFF) | ((uint)value << 21);
}
public int Form // bits 23-27
{
get => (int)(RawValue & 0x0F80_0000) >> 23;
set => RawValue = (RawValue & 0xF07F_FFFF) | ((uint)value << 23);
}
public bool Invisible // bit 28
{
get => ((RawValue >> 28) & 1) == 1;
set => RawValue = (RawValue & 0xEFFFFFFF) | (value ? 0 : 1u << 28);
}
public int Animation // bits 29-31
{
get => (int)(RawValue >> 29);
set => RawValue = (RawValue << 3) >> 3 | (uint)(value << 29);
}
private readonly byte[] Data;
private readonly int Offset;
public uint RawValue
{
get => BitConverter.ToUInt32(Data, Offset);
set => BitConverter.GetBytes(value).CopyTo(Data, Offset);
}
public void Delete() => RawValue = 0;
public EntreeForestArea Area { get; internal set; }
public EntreeSlot(byte[] data, int ofs)
{
Data = data;
Offset = ofs;
}
}
}