Initial Commit

First commit of the overhauled ACSE. Supports all Animal Crossing games
from the GameCube version all the way through Welcome Amiibo!
This commit is contained in:
Cuyler36 2017-06-14 05:36:44 -04:00
commit b8d714beaa
945 changed files with 62460 additions and 0 deletions

17
.gitattributes vendored Normal file
View file

@ -0,0 +1,17 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

10
.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
*.suo
*.exe
*.resources
*.cache
*.pdb
*.db
*.config
bin/
.vs/
obj/

2816
ACSE.csproj Normal file

File diff suppressed because it is too large Load diff

3
ACSE.csproj.user Normal file
View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

28
ACSE.sln Normal file
View file

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACSE", "ACSE.csproj", "{078BA400-42DD-432A-9844-32213157A29D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{078BA400-42DD-432A-9844-32213157A29D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{078BA400-42DD-432A-9844-32213157A29D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{078BA400-42DD-432A-9844-32213157A29D}.Debug|x86.ActiveCfg = Debug|x86
{078BA400-42DD-432A-9844-32213157A29D}.Debug|x86.Build.0 = Debug|x86
{078BA400-42DD-432A-9844-32213157A29D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{078BA400-42DD-432A-9844-32213157A29D}.Release|Any CPU.Build.0 = Release|Any CPU
{078BA400-42DD-432A-9844-32213157A29D}.Release|x86.ActiveCfg = Release|x86
{078BA400-42DD-432A-9844-32213157A29D}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

BIN
ACSE_Logo_2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

2007
Classes/AcreData.cs Normal file

File diff suppressed because it is too large Load diff

206
Classes/Checksum.cs Normal file
View file

@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ACSE
{
//Used in Doubutsu no Mori, Doubutsu no Mori+, Animal Crossing, Doubutsu no Mori e+, and Wild World
public static class Checksum
{
//Checksum Calculation Method:
//The checksum is located at 0x26052, and is an Unsigned Short
//The checksum is an offset value, so that the final additive of the save + the checksum is equal to 0
//The checksum offset is calculated by iterating through 0x26040 - 0x26051 and 0x26053 - 0x4C03F inclusively and adding every two bytes as a 16 bit ushort
//The checksum offset can then be verfied by adding 0x26040 - 0x4C03F in two byte intervals. If your sum is 0, then the checksum offset value is correct!
//Important to note that the gamecube used Big Endian notation, so you will likely have to convert between Little & Big Endian values to get a correct chksum
public static ushort Calculate(byte[] buffer, int checksumOffset, bool little_endian = false)
{
ushort checksum = 0;
if (little_endian)
{
for (int i = 0; i < checksumOffset; i += 2)
checksum += (ushort)((buffer[i + 1] << 8) + buffer[i]);
for (int i = checksumOffset + 2; i < buffer.Length - 1; i += 2)
checksum += (ushort)((buffer[i + 1] << 8) + buffer[i]);
}
else
{
for (int i = 0; i < checksumOffset; i += 2)
checksum += (ushort)((buffer[i] << 8) + buffer[i + 1]);
for (int i = checksumOffset + 2; i < buffer.Length - 1; i += 2)
checksum += (ushort)((buffer[i] << 8) + buffer[i + 1]);
}
return (ushort)-checksum;
}
public static bool Verify(byte[] buffer, int checksumOffset)
{
return BitConverter.ToUInt16(new byte[2] { buffer[checksumOffset + 1], buffer[checksumOffset] }, 0) == Calculate(buffer, checksumOffset);
}
public static void Update(byte[] buffer, int checksumOffset)
{
byte[] chksumBytes = BitConverter.GetBytes(Calculate(buffer, checksumOffset));
Array.Reverse(chksumBytes);
chksumBytes.CopyTo(buffer, checksumOffset);
}
}
//Used in City Folk
public static class CRC32
{
// Table of CRC-32's of all single byte values
public static uint[] crctab = new uint[]
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
0x2D02EF8D
};
public static uint GetCRC32(byte[] pBuf, uint initial = 0xFFFFFFFF)
{
uint c = initial;
int i, n = pBuf.Length;
for (i = 0; i < n; i++)
{
byte index = (byte)((c & 0xFF) ^ pBuf[i]);
c = crctab[index] ^ ((c >> 8) & 0xFFFFFF);
}
return ~c;
}
}
//Used in New Leaf
public static class NL_CRC32
{
public static uint[] NL_CRC_Table = {
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F,
0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC,
0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27,
0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x30E349B,
0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0,
0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC,
0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29,
0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E,
0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2,
0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59,
0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC,
0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0,
0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584,
0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC,
0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F,
0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4,
0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD,
0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1,
0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA,
0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD,
0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B,
0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90,
0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17,
0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B,
0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F,
0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9,
0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A,
0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81,
0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06,
0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A,
0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633,
0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914,
0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8,
0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643,
0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A,
0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06,
0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022,
0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A,
0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9,
0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052,
0xAD7D5351
};
public static uint Calculate_CRC32(byte[] data)
{
int size = data.Length;
uint crc = 0xFFFFFFFF;
int p = 0;
while (size-- != 0)
crc = NL_CRC_Table[(crc ^ data[p++]) & 0xFF] ^ (crc >> 8);
return ~crc;
}
public static uint Get_CRC32(byte[] data, int offset, int length)
{
return Calculate_CRC32(data.Skip(offset).Take(length).ToArray());
}
public static bool Verify_CRC32(byte[] data, int offset, int length)
{
return Get_CRC32(data, offset + 4, length - 4) == BitConverter.ToUInt32(data, offset);
}
}
}

173
Classes/DataConverter.cs Normal file
View file

@ -0,0 +1,173 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Collections;
using System.Runtime.InteropServices;
namespace ACSE
{
public static class DataConverter
{
private static byte ConvertByte(BitArray b)
{
byte value = 0;
for (byte i = 0; i < b.Count; i++)
if (b[i])
value |= (byte)(1 << i);
return value;
}
public static Dictionary<Type, Delegate> typeMap = new Dictionary<Type, Delegate>
{
{typeof(byte[]), new Func<byte[], byte>
(b => {
return ConvertByte(new BitArray(b));
})
},
{typeof(BitArray), new Func<BitArray, byte>
(b => {
return ConvertByte(b);
})
}
};
public static void WriteByte(int offset, byte data)
{
//MainForm.SaveBuffer[offset] = data;
}
public static void WriteByteArray(int offset, byte[] data, bool reverse = true)
{
if (reverse)
Array.Reverse(data);
//data.CopyTo(MainForm.SaveBuffer, offset);
}
public static void Write(int offset, object data, bool reverse = true)
{
Type type = data.GetType();
if (type.IsArray && typeof(byte[]) != type)
{
object[] arr = ((Array)data).Cast<object>().ToArray();
int objSize = Marshal.SizeOf(arr[0]);
Type t = type.GetElementType();
for (int i = 0; i < arr.Length; i++)
WriteByteArray(offset + i * objSize,
(byte[])typeof(BitConverter).GetMethod("GetBytes", new Type[] { type.GetElementType() }).Invoke(null, new object[] { arr[i] }),
reverse);
}
else if (type.IsArray && typeof(byte[]) == type)
WriteByteArray(offset, (byte[])data, reverse);
else if (typeof(byte) == type)
WriteByte(offset, (byte)data);
else
{
var convertedData = Convert.ChangeType(data, type);
WriteByteArray(offset, (byte[])typeof(BitConverter)
.GetMethod("GetBytes", new Type[] { convertedData.GetType() })
.Invoke(null, new object[] { convertedData }), reverse);
}
}
public static byte ReadByte(int offset)
{
return 0; //MainForm.SaveBuffer[offset];
}
public static byte[] ReadData(int offset, int size)
{
byte[] data = new byte[size];
//Buffer.BlockCopy(MainForm.SaveBuffer, offset, data, 0, size);
Array.Reverse(data);
return data;
}
public static byte[] ReadDataRaw(int offset, int size)
{
byte[] data = new byte[size];
//Buffer.BlockCopy(MainForm.SaveBuffer, offset, data, 0, size);
return data;
}
public static ushort ReadUShort(int offset)
{
return BitConverter.ToUInt16(ReadData(offset, 2), 0);
}
public static ushort[] ReadUShortArray(int offset, int numUshorts)
{
ushort[] ushortArray = new ushort[numUshorts];
for (int i = 0; i < numUshorts; i++)
ushortArray[i] = ReadUShort(offset + i * 2);
return ushortArray;
}
public static uint ReadUInt(int offset)
{
return BitConverter.ToUInt32(ReadData(offset, 4), 0);
}
public static uint[] ReadUIntArray(int offset, int numInts)
{
uint[] uintArray = new uint[numInts];
for (int i = 0; i < numInts; i++)
uintArray[i] = ReadUInt(offset + i * 4);
return uintArray;
}
public static ACString ReadString(int offset, int maxSize)
{
byte[] data = new byte[maxSize];
//Buffer.BlockCopy(MainForm.SaveBuffer, offset, data, 0, maxSize);
return new ACString(data);
}
public static void WriteString(int offset, string str, int maxSize)
{
byte[] strBytes = new byte[maxSize];
byte[] ACStringBytes = ACString.GetBytes(str, maxSize);
if (ACStringBytes.Length <= maxSize)
{
ACStringBytes.CopyTo(strBytes, 0);
if (str.Length < maxSize)
for (int i = (str.Length); i <= maxSize - 1; i++)
strBytes[i] = 0x20;
//strBytes.CopyTo(MainForm.SaveBuffer, offset);
}
}
public static byte[] ToBits(byte[] Byte_Buffer, bool Reverse = false)
{
byte[] Bits = new byte[8 * Byte_Buffer.Length];
for (int i = 0; i < Byte_Buffer.Length; i++)
{
BitArray Bit_Array = new BitArray(new byte[] { Byte_Buffer[i] });
for (int x = 0; x < Bit_Array.Length; x++)
Bits[i * 8 + (Reverse ? 7 - x : x)] = Convert.ToByte(Bit_Array[x]);
}
return Bits;
}
public static byte ToBit(byte Bit_Byte, int Bit_Index, bool Reverse = false)
{
return (byte)((Reverse ? Bit_Byte >> (7 - Bit_Index) : Bit_Byte >> Bit_Index) & 1);
}
public static void SetBit(ref byte Bit_Byte, int Bit_Index, bool Set, bool Reverse = false)
{
int Mask = 1 << (Reverse ? 7 - Bit_Index : Bit_Index);
if (Set)
Bit_Byte = Bit_Byte |= (byte)Mask;
else
Bit_Byte = Bit_Byte &= (byte)~Mask;
}
public static byte ToByte(object Variant)
{
return (byte)typeMap[Variant.GetType()].DynamicInvoke(Variant);
}
}
}

90
Classes/DateUtil.cs Normal file
View file

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ACSE
{
public static class DateUtil
{
//Might use for something
public static uint Day_String_to_Number(string day)
{
if (Enum.IsDefined(typeof(DayOfWeek), day))
return Convert.ToUInt32((DayOfWeek)Enum.Parse(typeof(DayOfWeek), day, true));
return 0; //Guess we're going Sunday
}
}
public class ACDate
{
public uint Second = 0;
public uint Minute = 0;
public uint Hour = 0;
public uint Day = 0;
public uint Day_of_Week = 0;
public uint Month = 0;
public uint Year = 0;
public string Date_Time_String = "";
public bool Is_PM = false;
public ACDate(byte[] dateData, bool reversed = false)
{
if (dateData.Length == 0x8)
{
Second = dateData[0];
Minute = dateData[1];
Hour = dateData[2];
Day = dateData[3];
Day_of_Week = dateData[4];
Month = dateData[5];
Year = BitConverter.ToUInt16(new byte[] { dateData[7], dateData[6] }, 0);
}
else if (dateData.Length == 0x4)
{
Year = BitConverter.ToUInt16(new byte[] { dateData[reversed ? 3 : 1], dateData[reversed ? 2 : 0] }, 0);
Month = dateData[reversed ? 1 : 2];
Day = dateData[reversed ? 0 : 3];
}
Is_PM = Hour >= 12;
Date_Time_String = string.Format("{0}:{1}:{2} {3}, {4}/{5}/{6}", (Hour % 12) == 0 ? 12 : Hour % 12,
Minute.ToString("D2"), Second.ToString("D2"), Is_PM ? "PM" : "AM", Month, Day, Year); //Default date/time string
}
public string Format(string formatString) //Need to redo this if there is a more efficient/cleaner way
{
formatString = formatString.Replace("(s)", Second.ToString("D2"));
formatString = formatString.Replace("(m)", Minute.ToString("D2"));
formatString = formatString.Replace("(h)", (Hour % 12) == 0 ? "12" : (Hour % 12).ToString());
formatString = formatString.Replace("(H)", Hour.ToString());
formatString = formatString.Replace("(d)", Day.ToString());
formatString = formatString.Replace("(D)", Day.ToString("D2"));
formatString = formatString.Replace("(w)", Day_of_Week.ToString());
formatString = formatString.Replace("(W)", Enum.GetName(typeof(DayOfWeek), Day_of_Week));
formatString = formatString.Replace("(m)", Month.ToString());
formatString = formatString.Replace("(M)", Month.ToString("D2"));
formatString = formatString.Replace("(y)", Year.ToString());
formatString = formatString.Replace("(Y)", Year.ToString().Substring(2, 2));
formatString = formatString.Replace("(a)", Is_PM ? "PM" : "AM");
formatString = formatString.Replace("(A)", Is_PM ? "P.M." : "A.M.");
return formatString;
}
public byte[] ToBytes()
{
return new byte[8]
{
(byte)Second,
(byte)Minute,
(byte)Hour,
(byte)Day,
(byte)Day_of_Week,
(byte)Month,
(byte)((Year & 0xFF00) >> 8),
(byte)(Year & 0x00FF)
};
}
}
}

60
Classes/DebugManager.cs Normal file
View file

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ACSE
{
public enum DebugLevel
{
None,
Error,
Info,
Debug
}
public class DebugManager
{
private static string Log_File_Name = "ACSE_Log";
private FileStream Log_File;
private StreamWriter Log_Writer;
public bool Enabled = false;
public DebugManager()
{
if (Properties.Settings.Default.DebugLevel > 0)
{
Log_File = new FileStream(Get_Log_File_Path(), FileMode.OpenOrCreate);
Log_Writer = new StreamWriter(Log_File);
Log_Writer.BaseStream.Seek(0, SeekOrigin.End);
Enabled = true;
WriteLine("========== Debug Log Initiated ==========");
}
else
{
Enabled = false;
}
}
public bool Log_File_Exists()
{
return File.Exists(Get_Log_File_Path());
}
public string Get_Log_File_Path()
{
return NewMainForm.Assembly_Location + string.Format("\\{0}.txt", Log_File_Name);
}
public void WriteLine(string Contents, DebugLevel Level = DebugLevel.Info)
{
if (Log_Writer != null && Level <= Properties.Settings.Default.DebugLevel)
{
Log_Writer.WriteLine(string.Format("[{0}] - ({1}) - {2} => {3}", Level, NewMainForm.Save_File != null
? NewMainForm.Save_File.Save_Type.ToString().Replace("_", " ") : "No Save", DateTime.Now, Contents));
Log_Writer.Flush();
}
}
}
}

315
Classes/HouseData.cs Normal file
View file

@ -0,0 +1,315 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ACSE
{
public struct House_Offsets
{
public int Room_Start;
public int Room_Size;
public int Layer_Size;
public int Layer_Count;
public int House_Upgrade_Size;
public int Owning_Player_ID;
public int Owning_Player_Name;
public int Town_ID;
public int Town_Name;
public int Design;
public int Design_Size;
public int Bed; //CF Exclusive
public int Roof_Color;
public int Customization_Start; //NL Exclusive
public int Mailbox;
public int Mail_Size;
public int Mail_Count;
public int Gyroid_Items; //AC Exclusive
public int Gryoid_Message; //AC Exclusive
}
public struct House_Data
{
public Room[] Rooms;
public byte House_Upgrade_Size;
public ushort Owning_Player_ID;
public string Owning_Player_Name;
public ushort Town_ID;
public string Town_Name;
public Pattern Design;
public Item Bed;
public byte Roof_Color;
public Item[] Customizations;
public Mail[] Mailbox;
public Gyroid_Item[] Gyroid_Items;
public string Gyroid_Message;
}
public class NewHouse
{
public int Index;
public int Offset;
public House_Data Data;
}
class HouseData
{
public static House_Offsets City_Folk_Offsets = new House_Offsets
{
Room_Start = 0x8AC,
Room_Size = 0x458,
Layer_Size = 0x200, //16 * 16 DWORDs
Layer_Count = 2,
House_Upgrade_Size = 0x15B4, //Also at 0x15B5
};
public static House_Offsets New_Leaf_Offsets = new House_Offsets //HouseData is duplicated starting at 0x9 (0x0 - 0x8)
{
House_Upgrade_Size = 0,
Customization_Start = 1,
//Style = 1,
//DoorShape = 2,
//Walls = 3,
//Roof = 4,
//Door = 5,
//Fence = 6,
//Pavement = 7,
//Mailbox = 8,
Room_Start = 0x76,
Room_Size = 0x302,
};
/*
* New Discovery (AC):
* Houses have four levels in them. These are layers you can store items on top of each other.
* This is how dressers work in the game. Each layer is 0x228 bytes away from the beginning of the previous one.
* So, a dresser with three items looks like this:
* Fourth Layer: Item 3
* Third Layer: Item 2
* Second Layer: Item 1
* Main Floor: Dresser
*
* This means that it's unnecessary to add "storage" to the inventory editor.
*/
public static ushort[] House_Identifiers = new ushort[10]
{
0x0480, 0x2480, 0x4880, 0x24A0, 0x4890, 0x48A0, 0x6C90, 0x6C80, 0x7000, 0x0000
//StarterHouse, First Upgrade, Expanded Main Room (No Basement), First Upgrade + Basement, Expanded Room + Basement (From Basement),
//Expanded Room + Basement (From Expanded Room), 2nd Floor (From Expanded Room), 2nd Floor (From Basement), Statue (From Basement)
};
//Rewrote all methods here to be significantly shorter. I originally wrote them when I had just started in C#.
public static int ReadHouseSize(ushort[] houseBuffer, bool includesPadding = true)
{
int x;
for (x = (includesPadding ? 0x11 : 0x0); x < houseBuffer.Length; x++)
if (houseBuffer[x] == 0xFFFE)
break;
return (x - (includesPadding ? 0x11 : 0x0));
}
public static Furniture[] ReadHouseData(ushort[] houseBuffer, int size = 0, bool includesPadding = true)
{
if (size == 0)
size = ReadHouseSize(houseBuffer, includesPadding);
Furniture[] Furniture_Array = new Furniture[size * size];
for (int y = 0; y < size; y++)
for (int x = 0; x < size; x++)
Furniture_Array[y * size + x] = new Furniture(houseBuffer[(includesPadding ? 0x11 : 0x0) + 0x10 * y + x]);
return Furniture_Array;
}
public static void UpdateHouseData(Furniture[] houseItems, ushort[] houseBuffer, int size, bool includesPadding = true)
{
for (int y = 0; y < size; y++)
for (int x = 0; x < size; x++)
houseBuffer[(includesPadding ? 0x11 : 0x0) + 0x10 * y + x] = houseItems[y * size + x].ItemID;
}
}
//Struct Size: 0x26B0
public class House
{
public int Offset;
//
public string Owning_Player_Name;
public string Town_Name;
public uint Player_ID;
public ACDate Last_Entry_Date; //Last day the house was entered
public ACDate Last_Upgrade_Date; //Not sure if this is accurate (Also is reversed)
public ushort Garbage; //Not really sure what this is (it could also be two bytes)
public byte House_Number; //Appears again two bytes away, with 0xFF following (not always FF following..)
public Room[] Rooms = new Room[3];
public Mail[] Mailbox = new Mail[10];
public Gyroid_Item[] Gyroid_Storage = new Gyroid_Item[4];
public ACString Gyroid_Message;
public byte Cockroach_Count;
public House(int offset)
{
Offset = offset;
Owning_Player_Name = DataConverter.ReadString(offset, 8).Trim();
Town_Name = DataConverter.ReadString(offset + 8, 8).Trim();
Player_ID = DataConverter.ReadUInt(offset + 0x10);
Last_Entry_Date = new ACDate(DataConverter.ReadDataRaw(offset + 0x1C, 4));
Last_Upgrade_Date = new ACDate(DataConverter.ReadDataRaw(offset + 0x26, 4), true);
//Garbage here
House_Number = (byte)((offset - 0x9CE8) / 0x26B0);
for (int i = 0; i < 3; i++)
Rooms[i] = new Room(DataConverter.ReadUShortArray(offset + 0x38 + i * 0x8A8, 0x454), i);
for (int i = 0; i < 10; i++)
Mailbox[i] = new Mail(offset + 0x1A30 + i * 0x12A);
for (int i = 0; i < 4; i++)
{
int local_Offset = offset + 0x25D4 + i * 0x8;
Gyroid_Storage[i] = new Gyroid_Item(DataConverter.ReadUShort(local_Offset), DataConverter.ReadUInt(local_Offset + 4), DataConverter.ReadByte(local_Offset + 3));
}
Gyroid_Message = DataConverter.ReadString(offset + 0x25F4, 0x80);
Cockroach_Count = DataConverter.ReadByte(offset + 0x2648);
//MessageBox.Show(Gyroid_Message.Clean());
}
}
//Struct Size: 0x8A8
public class Room
{
public Layer[] Layers = new Layer[4];
public Item Carpet;
public Item Wallpaper;
public byte Unknown_1;
public byte Unknown_2;
public int Room_Size;
public Room(ushort[] Room_Buffer, int Floor)
{
bool Includes_Wall = Room_Buffer[1] == 0xFFFE;
int Data_Start_Offset = Includes_Wall ? 16 : 1; //Data with wall looks like this: 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE, ..., 0xFFFE, 0xITEM_ID
Room_Size = HouseData.ReadHouseSize(Room_Buffer, Includes_Wall);
for (int i = 0; i < 4; i++) //4 layers per room
{
ushort[] Layer_Buffer = new ushort[0x114];
Buffer.BlockCopy(Room_Buffer, i * 0x228, Layer_Buffer, 0, 0x228);
Layers[i] = new Layer(Layer_Buffer, Room_Size, Floor, i, true);
}
Carpet = new Item((ushort)((0x26 << 8) + (Room_Buffer[0x450] & 0xFF00) >> 8));
Wallpaper = new Item((ushort)((0x27 << 8) + Room_Buffer[0x450] & 0x00FF));
Unknown_1 = (byte)((Room_Buffer[0x451] & 0xFF00) >> 4);
Unknown_2 = (byte)(Room_Buffer[0x451] & 0x00FF);
}
}
//Struct Size: 0x228
public class Layer
{
public Furniture[] Furniture;
public ushort[] Raw_Data;
public bool Has_Wall;
public int Size;
public string Name;
public Layer(ushort[] Layer_Buffer, int Layer_Size, int Floor, int Layer, bool Includes_Wall = false)
{
Name = (Floor == 0 ? "First Floor" : (Floor == 1 ? "Second Floor" : "Basement")) + " Layer #" + Layer;
Size = Layer_Size;
Has_Wall = Includes_Wall;
Raw_Data = Layer_Buffer; //Remove this to use Furniture in the future
Furniture = new Furniture[Size * Size];
for (int y = 0; y < Size; y++)
for (int x = 0; x < Size; x++)
Furniture[y * Size + x] = new Furniture(Layer_Buffer[(Includes_Wall ? 0x11 : 0) + y * 0x10 + x]);
}
public ushort[] Get_Data(Furniture[] Updated_Furniture)
{
if (Updated_Furniture.Length == Furniture.Length)
for (int y = 0; y < Size; y++)
for (int x = 0; x < Size; x++)
Raw_Data[(Has_Wall ? 0x11 : 0) + y * 0x10 + x] = Updated_Furniture[y * Size + x].ItemID;
else
MessageBox.Show(string.Format("{0}: New Furniture Array length ({1}) does not match original length ({2})!", Name, Updated_Furniture.Length, Furniture.Length));
Furniture = Updated_Furniture;
return Raw_Data;
}
}
//Struct Size: 0x12A (Villager Stored Mail Size: 0x100)
public class Mail
{
public int Offset;
public bool Player_Mail;
public string Reciepiant_Name;
public string Reciepiant_Town_Name;
public uint Reciepiant_ID;
public string Sender_Name;
public string Sender_Town_Name;
public uint Sender_ID;
public byte Event_Flag; //Not sure about this
public byte Unknown_1; //Never seen it be anything other than 0
public Item Present;
public byte Read;
public byte Unknown_2; //Letter_Type/Event_ID? (Could have something to do with name positioning, since it's not in the message)
public byte Sender_Type; //Not 100% sure (0 = Player, 2 = Tom Nook, 6 = HRA, A = Post Office)
public Item Stationary_Type;
public ACString Message_Data;
public string Message;
public Mail(int offset, bool Player_Mail = false)
{
this.Player_Mail = Player_Mail;
Offset = Player_Mail ? offset : offset - 0x2A;
if (Player_Mail)
{
Reciepiant_Name = DataConverter.ReadString(Offset, 8).Trim();
Reciepiant_Town_Name = DataConverter.ReadString(Offset + 8, 8).Trim();
Reciepiant_ID = DataConverter.ReadUInt(Offset + 0x10);
Sender_Name = DataConverter.ReadString(Offset + 0x16, 8).Trim();
Sender_Town_Name = DataConverter.ReadString(Offset + 0x1E, 8).Trim();
Sender_ID = DataConverter.ReadUInt(Offset + 0x26);
}
Event_Flag = DataConverter.ReadByte(Offset + 0x2A);
Unknown_1 = DataConverter.ReadByte(Offset + 0x2B);
Present = new Item(DataConverter.ReadUShort(Offset + 0x2C));
Read = DataConverter.ReadByte(Offset + 0x2E);
Unknown_2 = DataConverter.ReadByte(Offset + 0x2F);
Sender_Type = DataConverter.ReadByte(Offset + 0x30);
Stationary_Type = new Item((ushort)((0x20 << 8) + DataConverter.ReadByte(Offset + 0x31)));
Message_Data = DataConverter.ReadString(Offset + 0x32, 0xF8);
Message = Message_Data.Clean();
}
public string GetMessage()
{
int idx = Message.IndexOf(",");
if (idx > -1)
return string.Format("{0}{1},\n\n{2}", idx > 0 ? Message.Substring(0, idx - 1) : "", Reciepiant_Name, Message.Substring(idx + 1));
else
return string.Format("{0}{1}{2}", Message.IndexOf(" ") > 0 ? Message.Substring(0, Message.IndexOf(" ") + 1) : "", Reciepiant_Name + "\n",
Message.IndexOf(" ") > 0 ? Message.Substring(Message.IndexOf(" ")) : Message);
}
}
//Struct Size: 0xC8
public class Messageboard_Post
{
public ACString Post;
public string Post_String;
public ACDate Post_Date;
public Messageboard_Post(int offset)
{
Post = DataConverter.ReadString(offset, 0xC0);
Post_String = Post.Clean();
Post_Date = new ACDate(DataConverter.ReadDataRaw(offset + 0xC0, 8));
//MessageBox.Show(string.Format("{0}\n\nPosted at:\n{1}", Post_String, Post_Date.Date_Time_String));
}
}
}

283
Classes/ImageGeneration.cs Normal file
View file

@ -0,0 +1,283 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Resources;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ACSE
{
public static class ImageGeneration
{
//From: http://stackoverflow.com/questions/7350679/convert-a-bitmap-into-a-byte-array
public static byte[] BitmapToByteArray(Bitmap bitmap)
{
BitmapData bmpdata = null;
try
{
bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
int numbytes = bmpdata.Stride * bitmap.Height;
byte[] bytedata = new byte[numbytes];
IntPtr ptr = bmpdata.Scan0;
Marshal.Copy(ptr, bytedata, 0, numbytes);
return bytedata;
}
finally
{
if (bmpdata != null)
bitmap.UnlockBits(bmpdata);
}
}
public static Bitmap Draw_Grid(Bitmap Map, int Item_Size, uint Grid_Color = 0x41444444, int Grid_Pixel_Size = 1)
{
Graphics Bitmap_Graphics = Graphics.FromImage(Map);
Bitmap_Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Bitmap_Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
Bitmap_Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int Num_Lines_X = Map.Width / Item_Size, Num_Lines_Y = Map.Height / Item_Size;
Pen Grid_Pen = new Pen(new SolidBrush(Color.FromArgb((int)Grid_Color)));
Grid_Pen.Width = Grid_Pixel_Size;
for (int Y = 1; Y < Num_Lines_Y; Y++)
Bitmap_Graphics.DrawLine(Grid_Pen, 0, Y * Item_Size - 1, Map.Width, Y * Item_Size - 1);
for (int X = 1; X < Num_Lines_X; X++)
Bitmap_Graphics.DrawLine(Grid_Pen, X * Item_Size - 1, 0, X * Item_Size - 1, Map.Height);
Bitmap_Graphics.Flush();
Bitmap_Graphics.Dispose();
return Map;
}
public static Bitmap Draw_Acre_Highlight()
{
Bitmap Acre_Highlight = new Bitmap(64, 64);
Graphics Bitmap_Graphics = Graphics.FromImage(Acre_Highlight);
Pen Border_Color = new Pen(Color.FromArgb(0x80, Color.Gold));
Border_Color.Width = 8;
Bitmap_Graphics.DrawRectangle(Border_Color, new Rectangle(0, 0, 64, 64));
Bitmap_Graphics.FillRectangle(new SolidBrush(Color.FromArgb(0x80, Color.Yellow)), new Rectangle(4, 4, 56, 56));
Bitmap_Graphics.Flush();
Bitmap_Graphics.Dispose();
return Acre_Highlight;
}
public static Bitmap Draw_Building(Bitmap Acre_Map, Building Building_to_Draw, bool Use_Text = false)
{
RectangleF RectF = new RectangleF(Building_to_Draw.X_Pos * 8, Building_to_Draw.Y_Pos * 8, 8, 8);
Graphics Bitmap_Graphics = Graphics.FromImage(Acre_Map);
Bitmap_Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Bitmap_Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
Bitmap_Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
if (Use_Text)
{
Bitmap_Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
Bitmap_Graphics.DrawString("B", new Font("Tahoma", 8), Brushes.White, RectF);
}
else
Bitmap_Graphics.DrawImage(Properties.Resources.Building, Building_to_Draw.X_Pos * 8, Building_to_Draw.Y_Pos * 8, 8, 8);
Bitmap_Graphics.Flush();
return Acre_Map;
}
public static Bitmap Draw_Buildings(Bitmap Acre_Map, Building[] Building_List, int Acre)
{
if (Building_List == null)
return Acre_Map;
foreach (Building B in Building_List)
{
if (B.Exists && B.Acre_Index == Acre)
{
Draw_Building(Acre_Map, B);
}
}
return Acre_Map;
}
public static Bitmap Draw_Inner_House_Extents(Bitmap Furniture_Map, int Floor_Size = 8)
{
using (Graphics Bitmap_Graphics = Graphics.FromImage(Furniture_Map))
{
int Corner = (16 - Floor_Size) / 2;
using (Pen Border_Pen = new Pen(Color.Gray, 2))
{
Border_Pen.Alignment = PenAlignment.Inset;
Bitmap_Graphics.DrawRectangle(Border_Pen, new Rectangle(Corner, Corner, Floor_Size * 16, Floor_Size * 16));
}
}
return Furniture_Map;
}
public static Bitmap Draw_Furniture_Arrows(Bitmap Furniture_Map, Furniture[] Furniture, int Columns = 16)
{
Graphics Bitmap_Graphics = Graphics.FromImage(Furniture_Map);
Bitmap_Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Bitmap_Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
Bitmap_Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
for (int i = 0; i < Furniture.Length; i++)
{
if (Furniture[i].Name != "Empty")
{
Image Arrow = Properties.Resources.Arrow;
if (Furniture[i].Rotation > 0)
{
switch(Furniture[i].Rotation)
{
case 90:
Arrow.RotateFlip(RotateFlipType.Rotate90FlipNone);
break;
case 180:
Arrow.RotateFlip(RotateFlipType.Rotate180FlipNone);
break;
case 270:
Arrow.RotateFlip(RotateFlipType.Rotate270FlipNone);
break;
}
}
Bitmap_Graphics.DrawImage(Arrow, (i % Columns) * (Furniture_Map.Width / Columns), (i / Columns) * (Furniture_Map.Width / Columns));
}
}
Bitmap_Graphics.Flush();
Bitmap_Graphics.Dispose();
return Furniture_Map;
}
public static int[] Grass_Wear_Offset_Map = new int[64] //Lazy Hack
{
0, 1, 4, 5, 16, 17, 20, 21,
2, 3, 6, 7, 18, 19, 22, 23,
8, 9, 12, 13, 24, 25, 28, 29,
10, 11, 14, 15, 26, 27, 30, 31,
32, 33, 36, 37, 48, 49, 52, 53,
34, 35, 38, 39, 50, 51, 54, 55,
40, 41, 44, 45, 56, 57, 60, 61,
42, 43, 46, 47, 58, 59, 62, 63
};
public static Bitmap Draw_Grass_Wear(byte[] Grass_Buffer)
{
if (NewMainForm.Save_File.Save_Type == SaveType.City_Folk)
{
Bitmap Grass_Bitmap = new Bitmap(64, 64, PixelFormat.Format32bppArgb);
Graphics Bitmap_Graphics = Graphics.FromImage(Grass_Bitmap);
int i = 0;
for (int Y2 = 0; Y2 < 4; Y2++)
for (int X2 = 0; X2 < 2; X2++)
for (int Y = 0; Y < 4; Y++)
for (int X = 0; X < 8; X++)
{
Bitmap_Graphics.FillRectangle(new SolidBrush(Color.FromArgb(Grass_Buffer[i] == 0 ? 0 : 0x60, 0, Grass_Buffer[i], 0)), (X + X2 * 8) * 4, (Y + Y2 * 4) * 4, 4, 4);
i++;
}
Bitmap_Graphics.Flush();
Bitmap_Graphics.Dispose();
return Grass_Bitmap;
}
else // NL/WA
{
Bitmap Grass_Bitmap = new Bitmap(7 * 64, 6 * 64, PixelFormat.Format32bppArgb);
Graphics Bitmap_Graphics = Graphics.FromImage(Grass_Bitmap);
for (int Y = 0; Y < 6 * 16; Y++)
{
for (int X = 0; X < 7 * 16; X++)
{
int Offset = 64 * ((Y / 8) * 16 + (X / 8)) + Grass_Wear_Offset_Map[(Y % 8) * 8 + (X % 8)];
SolidBrush Brush = new SolidBrush(Color.FromArgb(Grass_Buffer[Offset] == 0 ? 0 : 0x60, 0, Grass_Buffer[Offset], 0));
Bitmap_Graphics.FillRectangle(Brush, X * 4, Y * 4, 4, 4);
}
}
Bitmap_Graphics.Flush();
Bitmap_Graphics.Dispose();
return Grass_Bitmap;
}
}
public static Bitmap Draw_NL_Grass_BG(PictureBox[] Acre_Map)
{
Bitmap BG_Bitmap = new Bitmap(64 * 7, 64 * 6);
Graphics BG_Graphics = Graphics.FromImage(BG_Bitmap);
for (int i = 0; i < Acre_Map.Length; i++)
if (Acre_Map[i].BackgroundImage != null)
BG_Graphics.DrawImage(MakeGrayscale((Bitmap)Acre_Map[i].BackgroundImage), 64 * (i % 7), 64 * (i / 7));
BG_Graphics.Flush();
BG_Graphics.Dispose();
return BG_Bitmap;
}
//From: http://stackoverflow.com/questions/2265910/convert-an-image-to-grayscale
public static Bitmap MakeGrayscale(Bitmap original)
{
if (original == null)
return null;
Bitmap newBitmap = new Bitmap(original.Width, original.Height);
Graphics g = Graphics.FromImage(newBitmap);
//create the grayscale ColorMatrix
ColorMatrix colorMatrix = new ColorMatrix(
new float[][]
{
new float[] {.3f, .3f, .3f, 0, 0},
new float[] {.59f, .59f, .59f, 0, 0},
new float[] {.11f, .11f, .11f, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
});
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(colorMatrix);
g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);
g.Dispose();
return newBitmap;
}
public static byte[] GetTPCTrimmedBytes(byte[] TPC_Bytes)
{
byte[] Finalized_TPC_Bytes = new byte[0x1400];
if (TPC_Bytes.Length > 0x1400)
{
MessageBox.Show("Received TPC Card file size: " + TPC_Bytes.Length.ToString("X"));
Array.Resize(ref TPC_Bytes, 0x1400);
}
for (int i = TPC_Bytes.Length - 1; i > 0; i--)
{
if (i > 0 && TPC_Bytes[i - 1] == 0xFF && TPC_Bytes[i] == 0xD9)
{
Buffer.BlockCopy(TPC_Bytes, 0, Finalized_TPC_Bytes, 0, i == 0x13FF ? i : i + 1);
break;
}
}
return Finalized_TPC_Bytes;
}
public static Image GetTPCImage(byte[] TPC_Bytes)
{
if (TPC_Bytes.Length != 0x1400)
{
MessageBox.Show("The TPC Picture was an incorrect data size.");
return null;
}
if (TPC_Bytes[TPC_Bytes.Length - 1] == 0xD9 && TPC_Bytes[TPC_Bytes.Length - 2] == 0xFF)
return Image.FromStream(new MemoryStream(TPC_Bytes));
for (int i = TPC_Bytes.Length - 1; i > 0; i --)
{
if (i > 0 && TPC_Bytes[i - 1] == 0xFF && TPC_Bytes[i] == 0xD9)
{
return Image.FromStream(new MemoryStream(TPC_Bytes.Take(i).ToArray()));
}
}
NewMainForm.Debug_Manager.WriteLine("Unable to find JPEG End-of-File marker. No TPC?", DebugLevel.Error);
return Properties.Resources.no_tpc;
}
}
}

114
Classes/Inventory.cs Normal file
View file

@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
namespace ACSE
{
public class Inventory
{
public Item[] Items;
public Inventory(ushort[] inventoryData)
{
Items = new Item[inventoryData.Length];
for(int i = 0; i < inventoryData.Length; i++)
{
Item item = new Item(inventoryData[i]);
Items[i] = item;
}
}
public Inventory(uint[] inventoryData)
{
Items = new Item[inventoryData.Length];
for (int i = 0; i < inventoryData.Length; i++)
{
Item item = new Item(inventoryData[i]);
Items[i] = item;
}
}
public static Image GetItemPic(int itemsize, int itemsPerRow, Item[] items, SaveType Save_Type = SaveType.Animal_Crossing)
{
int width = itemsize * itemsPerRow, height = itemsize * items.Length / itemsPerRow;
height = height < 1 ? width : height;
byte[] bmpData = new byte[4 * ((width) * (height))];
for (int i = 0; i < items.Length; i++)
{
int X = i % itemsPerRow;
int Y = i / itemsPerRow;
Item item = items[i] ?? new Item(0);
uint itemColor = ItemData.GetItemColor(ItemData.GetItemType(item.ItemID, Save_Type));
for (int x = 0; x < itemsize * itemsize; x++)
{
int dataPosition = (Y * itemsize + x % itemsize) * width * 4 + (X * itemsize + x / itemsize) * 4;
if (dataPosition >= bmpData.Length)
{
System.Windows.Forms.MessageBox.Show("Item Bitmap generation received more items than allocated space. Skipping " + (items.Length - i).ToString() + " Item(s).");
break;
}
Buffer.BlockCopy(BitConverter.GetBytes(itemColor), 0, bmpData, dataPosition, 4);
}
}
for (int i = 0; i < (width * height); i++)
if ((i / itemsize > 0 && i % (itemsize * itemsPerRow) > 0 && i % (itemsize) == 0) || (i / (itemsize * itemsPerRow) > 0 && (i / (itemsize * itemsPerRow)) % (itemsize) == 0))
Buffer.BlockCopy(BitConverter.GetBytes(0x41000000), 0, bmpData,
((i / (itemsize * itemsPerRow)) * width * 4) + ((i % (itemsize * itemsPerRow)) * 4), 4);
Bitmap b = new Bitmap(width, height, PixelFormat.Format32bppArgb);
BitmapData bData = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(bmpData, 0, bData.Scan0, bmpData.Length);
b.UnlockBits(bData);
return b;
}
public static Image GetItemPic(int itemsize, Item item, SaveType Save_Type = SaveType.Animal_Crossing)
{
int width = 16;
int height = 16;
byte[] bmpData = new byte[1024];
byte[] itemColor = item == null ? new byte[4] { 0xFF, 0xFF, 0x00, 0x00 } : BitConverter.GetBytes(ItemData.GetItemColor(ItemData.GetItemType(item.ItemID, Save_Type)));
for (int i = 0; i < 1024; i+=4)
itemColor.CopyTo(bmpData, i);
for (int i = 0; i < (width * height); i++)
if ((i / itemsize > 0 && i % 16 > 0 && i % 16 == 0) || (i / 16 > 0 && (i / 16) % 16 == 0))
Buffer.BlockCopy(BitConverter.GetBytes(0x41000000), 0, bmpData,
((i / 16) * width * 4) + ((i % 16) * 4), 4);
Bitmap b = new Bitmap(width, height, PixelFormat.Format32bppArgb);
BitmapData bData = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(bmpData, 0, bData.Scan0, bmpData.Length);
b.UnlockBits(bData);
return b;
}
public ushort[] GetItemIDs()
{
ushort[] ids = new ushort[15];
for (int i = 0; i < 15; i++)
ids[i] = Items[i].ItemID;
return ids;
}
}
public class InventorySlot
{
public Item Item;
public int SlotID;
public InventorySlot(Item item, int slotId)
{
Item = item;
SlotID = slotId;
}
}
}

1419
Classes/ItemData.cs Normal file

File diff suppressed because one or more lines are too long

102
Classes/NL_Int32.cs Normal file
View file

@ -0,0 +1,102 @@
using System;
namespace ACSE
{
/*
* Animal Crossing: New Leaf (and Welcome Amiibo) Interger Encryption Documentation
*
* Animal Crossing: New Leaf uses a combination of methods to obfuscate their integer values in the save file.
* The encryption consists of two integer values. The first integer is the encrypted integer. The second integer contains the checksum of the encryption and
* the data needed to decrypt it.
*
* The lower two bytes are a short which has a randomized "adjustment value"
* This is likely to throw off anyone looking for a static value that is added/removed from it.
*
* The second byte in the int contains the "Shift Value" which is a random number between 0x00 and 0x1A. This number is then subtracted from a static value of 0x1C
* to determine the left bitshift count.
*
* The left bitshift count is then subtracted from a static value of 0x20 to determine the right bitshift count.
*
* The uppermost byte in the second integer is the Checksum of all the bytes in the Encrypted Integer + a statc value of 0xBA.
*
* Once we have the left & right bitshift counts, we can decode the Encrypted Integer.
*
* The formula is this:
* uint Unencrypted_Int = ((Encrypted_Integer << Left_Shift_Count) + (Encrypted_Integer >> Right_Shift_Count)) - (Random_Adjustment_Value + Static_Int 0x8F187432);
*/
public class NL_Int32
{
public uint Int_1;
public uint Int_2;
public uint Value;
public bool Valid = false;
public NL_Int32()
{
Int_1 = 0;
Int_2 = 0;
Value = 0;
}
public NL_Int32(uint Int_A, uint Int_B)
{
Int_1 = Int_A;
Int_2 = Int_B;
ushort Adjust_Value = (ushort)(Int_B);
byte Shift_Value = (byte)(Int_B >> 16);
byte Int_Checksum = (byte)(Int_B >> 24);
byte Computed_Checksum = GetChecksum(Int_A);
if (Int_Checksum != Computed_Checksum)
{
NewMainForm.Debug_Manager.WriteLine("Encrypted Int had an invalid Checksum at offset!", DebugLevel.Error);
Int_1 = 0;
Int_2 = 0;
Value = 0;
Valid = false;
}
else
{
byte Left_Shift_Count = (byte)(0x1C - Shift_Value);
byte Right_Shift_Count = (byte)(0x20 - Left_Shift_Count);
if (Left_Shift_Count < 0x20)
{
Value = ((Int_A << Left_Shift_Count) + (Int_A >> Right_Shift_Count)) - (Adjust_Value + 0x8F187432);
Valid = true;
}
else
{
NewMainForm.Debug_Manager.WriteLine("Invalid Shift Count was detected!", DebugLevel.Error);
Value = (Int_A << Right_Shift_Count) - (Adjust_Value + 0x8F187432);
Valid = true; // Is this right?
}
}
//System.Windows.Forms.MessageBox.Show("Value = " + Value.ToString());
}
public NL_Int32(uint Unencrypted_Int)
{
Random Generator = new Random();
ushort Adjust_Value = (ushort)(Generator.Next(0x10000));
byte Shift_Value = (byte)(Generator.Next(0x1A));
uint Encrypted_Int = Unencrypted_Int + Adjust_Value + 0x8F187432;
Encrypted_Int = (Encrypted_Int >> (0x1C - Shift_Value)) + (Encrypted_Int << (Shift_Value + 4));
uint Encryption_Data = (uint)(Adjust_Value + (Shift_Value << 16) + (GetChecksum(Encrypted_Int) << 24));
//System.Windows.Forms.MessageBox.Show("Encryped Int is decrypted properly: " + (new NL_Int32(Encrypted_Int, Encryption_Data).Value == Unencrypted_Int).ToString());
Int_1 = Encrypted_Int;
Int_2 = Encryption_Data;
Value = Unencrypted_Int;
}
public static byte GetChecksum(uint Encrypted_Int)
{
return (byte)((byte)(Encrypted_Int) + (byte)(Encrypted_Int >> 8) + (byte)(Encrypted_Int >> 16) + (byte)(Encrypted_Int >> 24) + 0xBA);
}
}
}

574
Classes/Pattern.cs Normal file
View file

@ -0,0 +1,574 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ACSE
{
/// <summary>
/// GameCube Pattern Data Write-up
/// Patterns consist of a 15-color palette.
/// There are 16 palettes to select from, but you can only use one palette at a time.
/// To save space, the AC Devs used each nibble for a pixel on the pattern. FF = White, White | 1F = Red, White
/// Each Pattern is 32x32 pixels. So the total space in memory was halved by doing this (only 0x220 bytes)
/// Data is stored like this:
/// Name: 0x10 bytes
/// Palette: 0x1 bytes
/// Alignment Bytes?: 0xF bytes
/// Pattern Data: 0x200 bytes
/// </summary>
class PatternData
{
public static uint[][] AC_Palette_Data = new uint[16][]
{
new uint[15]
{
0xFFCD4A4A, 0xFFDE8341, 0xFFE6AC18, 0xFFE6C520, 0xFFD5DE18, 0xFFB4E618, 0xFF83D552, 0xFF39C56A, 0xFF29ACC5, 0xFF417BEE, 0xFF6A4AE6, 0xFF945ACD, 0xFFBD41B4, 0xFF000000, 0xFFFFFFFF
},
new uint[15]
{
0xFFFF8B8B, 0xFFFFCD83, 0xFFFFE65A, 0xFFFFF662, 0xFFFFFF83, 0xFFDEFF52, 0xFFB4FF83, 0xFF7BF6AC, 0xFF62E6F6, 0xFF83C5FF, 0xFFA49CFF, 0xFFD59CFF, 0xFFFF9CF6, 0xFF8B8B8B, 0xFFFFFFFF
},
new uint[15]
{
0xFF9C1818, 0xFFAC5208, 0xFFB47B00, 0xFFB49400, 0xFFA4AC00, 0xFF83B400, 0xFF52A431, 0xFF089439, 0xFF007B94, 0xFF104ABD, 0xFF3918AC, 0xFF5A2994, 0xFF8B087B, 0xFF080808, 0xFFFFFFFF
},
new uint[15]
{
0xFF41945A, 0xFF73C58B, 0xFF94E6AC, 0xFF008B7B, 0xFF5AB4AC, 0xFF83C5C5, 0xFF2073A4, 0xFF4A9CCD, 0xFF6AACDE, 0xFF7383BD, 0xFF6A73AC, 0xFF525294, 0xFF39397B, 0xFF181862, 0xFFFFFFFF
},
new uint[15]
{
0xFF9C8352, 0xFFBD945A, 0xFFD5BD83, 0xFF9C5252, 0xFFCD7362, 0xFFEE9C8B, 0xFF8B6283, 0xFFA483B4, 0xFFDEB4DE, 0xFFBD8383, 0xFFAC736A, 0xFF945252, 0xFF7B3939, 0xFF621810, 0xFFFFFFFF
},
new uint[15]
{
0xFFEE5A00, 0xFFFF9C41, 0xFFFFCD83, 0xFFFFEEA4, 0xFF8B4A29, 0xFFB47B5A, 0xFFE6AC8B, 0xFFFFDEBD, 0xFF318BFF, 0xFF62B4FF, 0xFF9CDEFF, 0xFFC5E6FF, 0xFF6A6A6A, 0xFF000000, 0xFFFFFFFF
},
new uint[15]
{
0xFF39B441, 0xFF62DE5A, 0xFF8BEE83, 0xFFB4FFAC, 0xFF2020C5, 0xFF5252F6, 0xFF8383FF, 0xFFB4B4FF, 0xFFCD3939, 0xFFDE6A6A, 0xFFE68B9C, 0xFFEEBDBD, 0xFF6A6A6A, 0xFF000000, 0xFFFFFFFF
},
new uint[15]
{
0xFF082000, 0xFF415A39, 0xFF6A8362, 0xFF9CB494, 0xFF5A2900, 0xFF7B4A20, 0xFFA4734A, 0xFFD5A47B, 0xFF947B00, 0xFFB49439, 0xFFCDB46A, 0xFFDED59C, 0xFF6A6A6A, 0xFF000000, 0xFFFFFFFF
},
new uint[15]
{
0xFF2020FF, 0xFFFF2020, 0xFFD5D500, 0xFF6262FF, 0xFFFF6262, 0xFFD5D562, 0xFF9494FF, 0xFFFF9494, 0xFFD5D594, 0xFFACACFF, 0xFFFFACAC, 0xFFE6E6AC, 0xFF6A6A6A, 0xFF000000, 0xFFFFFFFF
},
new uint[15]
{
0xFF20A420, 0xFF39ACFF, 0xFF9C52EE, 0xFF52BD52, 0xFF5AC5FF, 0xFFB49CFF, 0xFF6AD573, 0xFF8BE6FF, 0xFFCDB4FF, 0xFF94DEAC, 0xFFBDF6FF, 0xFFD5CDFF, 0xFF6A6A6A, 0xFF000000, 0xFFFFFFFF
},
new uint[15]
{
0xFFD50000, 0xFFFFBD00, 0xFFEEF631, 0xFF4ACD41, 0xFF299C29, 0xFF528BBD, 0xFF414AAC, 0xFF9452D5, 0xFFF67BDE, 0xFFA49439, 0xFF9C4141, 0xFF5A3139, 0xFF6A6A6A, 0xFF000000, 0xFFFFFFFF
},
new uint[15]
{
0xFFE6CD18, 0xFF20C518, 0xFFFF6A00, 0xFF0000FF, 0xFF9400BD, 0xFFE6CD18, 0xFF00A400, 0xFFCD4100, 0xFF0000D5, 0xFF5A008B, 0xFF9C8B18, 0xFF008300, 0xFFA42000, 0xFF0000A4, 0xFF4A005A
},
new uint[15]
{
0xFFFF2020, 0xFFE6D500, 0xFFF639BD, 0xFF00D59C, 0xFF107310, 0xFFC52020, 0xFFBDA400, 0xFFCD3994, 0xFF009C6A, 0xFF204A20, 0xFF8B2020, 0xFF836A00, 0xFF941862, 0xFF00734A, 0xFF183918
},
new uint[15]
{
0xFFEED5D5, 0xFFDEC5C5, 0xFFCDB4B4, 0xFFBDA4A4, 0xFFAC9494, 0xFF9C8383, 0xFF8B7373, 0xFF7B6262, 0xFF6A5252, 0xFF5A4141, 0xFF4A3131, 0xFF392020, 0xFF291010, 0xFF180000, 0xFF100000
},
new uint[15]
{
0xFFEEEEEE, 0xFFDEDEDE, 0xFFCDCDCD, 0xFFBDBDBD, 0xFFACACAC, 0xFF9C9C9C, 0xFF8B8B8B, 0xFF7B7B7B, 0xFF6A6A6A, 0xFF5A5A5A, 0xFF4A4A4A, 0xFF393939, 0xFF292929, 0xFF181818, 0xFF101010
},
new uint[15]
{
0xFFEE7B7B, 0xFFD51818, 0xFFF69418, 0xFFE6E652, 0xFF006A00, 0xFF39B439, 0xFF0039B4, 0xFF399CFF, 0xFF940094, 0xFFFF6AFF, 0xFF944108, 0xFFEE9C5A, 0xFFFFC594, 0xFF000000, 0xFFFFFFFF
},
};
public static byte[] WW_Pattern_Offsets = new byte[16]
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xC, 0xB, 0xD, 0xE, 0xF //Not in order??
};
public static uint[][] WW_Palette_Data = new uint[16][]
{
new uint [15]
{
0xFF0000FF, 0xFF3173FF, 0xFF00ADFF, 0xFF00FFFF, 0xFF00FFAD, 0xFF00FF52, 0xFF00FF00, 0xFF52AD00, 0xFFAD5200, 0xFFFF0000, 0xFFFF0052, 0xFFFF00AD, 0xFFFF00FF, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFF7B7BFF, 0xFF7BB5FF, 0xFF7BE7FF, 0xFF7BFFFF, 0xFF7BFFDE, 0xFF7BFFAD, 0xFF7BFF7B, 0xFF84AD52, 0xFFAD8452, 0xFFFF7B7B, 0xFFFF7BB5, 0xFFFF7BE7, 0xFFFF7BFF, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFF0000A5, 0xFF0031A5, 0xFF0073A5, 0xFF00A5A5, 0xFF00A573, 0xFF00A531, 0xFF00A500, 0xFF215200, 0xFF522100, 0xFFA50000, 0xFFA50031, 0xFFA50073, 0xFFA500A5, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFF009C00, 0xFF6BCE5A, 0xFFDEFFB5, 0xFF6B9C00, 0xFFA5CE52, 0xFFD6FFAD, 0xFFAD5200, 0xFFD68429, 0xFFFFAD5A, 0xFFFF0000, 0xFFFF6B4A, 0xFFDE4A31, 0xFFB52118, 0xFF8C0000, 0xFFFFFFFF
},
new uint [15]
{
0xFF0073AD, 0xFF42ADD6, 0xFF8CDEFF, 0xFF3908FF, 0xFF6B4AFF, 0xFF9C94FF, 0xFFFF00AD, 0xFFFF63D6, 0xFFFFCEFF, 0xFF9CBDFF, 0xFF7394DE, 0xFF4A63BD, 0xFF21399C, 0xFF00107B, 0xFFFFFFFF
},
new uint [15]
{
0xFF0000FF, 0xFF0052FF, 0xFF5AB5FF, 0xFFADEFFF, 0xFF00107B, 0xFF314AA5, 0xFF6B84D6, 0xFF9CBDFF, 0xFFFFAD5A, 0xFFFFC684, 0xFFFFE7AD, 0xFFFFFFD6, 0xFF6B6B6B, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFF00FF00, 0xFF42FF42, 0xFF8CFF8C, 0xFFD6FFD6, 0xFFFF0000, 0xFFFF4242, 0xFFFF8C8C, 0xFFFFD6D6, 0xFF0000FF, 0xFF4242FF, 0xFF8C8CFF, 0xFFD6D6FF, 0xFF6B6B6B, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFF003100, 0xFF426342, 0xFF849C84, 0xFFC6D6C6, 0xFF00107B, 0xFF294AA5, 0xFF5A8CD6, 0xFF8CC6FF, 0xFF00B5D6, 0xFF39CEE7, 0xFF7BDEF7, 0xFFBDF7FF, 0xFF6B6B6B, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFFFF0000, 0xFF0000FF, 0xFF00FFFF, 0xFFFF4242, 0xFF4242FF, 0xFF42FFFF, 0xFFFF8C8C, 0xFF8C8CFF, 0xFF8CFFFF, 0xFFFFD6D6, 0xFFD6D6FF, 0xFFD6FFFF, 0xFF6B6B6B, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFF00FF00, 0xFFFF0000, 0xFFFF00FF, 0xFF42FF42, 0xFFFF4242, 0xFFFF42FF, 0xFF8CFF8C, 0xFFFF8C8C, 0xFFFF8CFF, 0xFFD6FFD6, 0xFFFFD6D6, 0xFFFFD6FF, 0xFF6B6B6B, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFF0000FF, 0xFF007BFF, 0xFF00FFFF, 0xFF00FF84, 0xFF00FF00, 0xFF7B8400, 0xFFFF0000, 0xFFFF007B, 0xFFFF94FF, 0xFF00B5D6, 0xFF0010BD, 0xFF00105A, 0xFF6B6B6B, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFF639410, 0xFF527B08, 0xFF398C10, 0xFF319C31, 0xFF4AA5CE, 0xFF3994CE, 0xFF4A8CBD, 0xFF318CD6, 0xFF4A73AD, 0xFF315A8C, 0xFF29426B, 0xFFFFEF84, 0xFFEFCE31, 0xFFC6A500, 0xFFFFFFFF
},
new uint [15]
{
0xFFE7DED6, 0xFFDECEB5, 0xFFEFEFE7, 0xFFF7F7F7, 0xFF7B7384, 0xFF6B8C94, 0xFF637B84, 0xFF5A849C, 0xFFB59C73, 0xFF2929FF, 0xFF00FFFF, 0xFFFF2194, 0xFFBD9C00, 0xFF000000, 0xFFFFFFFF
},
new uint [15]
{
0xFFFFFFFF, 0xFFEFEFF7, 0xFFDEDEE7, 0xFFCECED6, 0xFFB5B5C6, 0xFFA5A5B5, 0xFF9494A5, 0xFF84849C, 0xFF6B6B8C, 0xFF5A5A7B, 0xFF4A4A6B, 0xFF31315A, 0xFF21214A, 0xFF101042, 0xFF000031
},
new uint [15]
{
0xFFFFFFFF, 0xFFEFEFEF, 0xFFDEDEDE, 0xFFCECECE, 0xFFB5B5B5, 0xFFA5A5A5, 0xFF949494, 0xFF848484, 0xFF6B6B6B, 0xFF5A5A5A, 0xFF4A4A4A, 0xFF313131, 0xFF212121, 0xFF101010, 0xFF000000
},
new uint [15]
{
0xFF7B8CFF, 0xFF0000FF, 0xFF007BFF, 0xFF00FFFF, 0xFF008400, 0xFF00FF00, 0xFFFF0000, 0xFFFF9C00, 0xFFFF00D6, 0xFFFF6BFF, 0xFF00009C, 0xFF0094FF, 0xFF94BDFF, 0xFF000000, 0xFFFFFFFF
},
};
public static uint[][] CF_Palette_Data = new uint[16][]
{
new uint [15]
{
0xFFFF0000, 0xFF008000, 0xFF0000FF, 0xFF804000, 0xFF000000, 0xFFFF8000, 0xFF80FF00, 0xFF00EAEA, 0xFF800080, 0xFF808080, 0xFFFFCAE4, 0xFFFFFF00, 0xFFACCCFD, 0xFFFF66B3, 0xFFFFFFFF
},
new uint [15]
{
0xFFFD561E, 0xFF00C400, 0xFF3982FB, 0xFFAC6802, 0xFF000000, 0xFFFFA54A, 0xFF9FFF40, 0xFF51A8FF, 0xFFEE70FC, 0xFF808080, 0xFFFFC993, 0xFFFFFF80, 0xFFC1E0FF, 0xFFFFC4E1, 0xFFFFFFFF
},
new uint [15]
{
0xFF804040, 0xFF006633, 0xFF4B4BA9, 0xFF4B2F21, 0xFF000000, 0xFFAC6802, 0xFF00A854, 0xFF317BF7, 0xFF5F3E86, 0xFF969696, 0xFFDFB9AC, 0xFFA4A400, 0xFF9CBACF, 0xFFB06FB0, 0xFFFFFFFF
},
new uint [15]
{
0xFFB02902, 0xFFA29F4F, 0xFF008282, 0xFF022B68, 0xFF000000, 0xFFFA7403, 0xFFE6C947, 0xFF04C67D, 0xFF5A5ACD, 0xFF808080, 0xFFFED7AF, 0xFFFFFFA8, 0xFFC4EBC2, 0xFF94B4FE, 0xFFFFFFFF
},
new uint [15]
{
0xFFD05B9C, 0xFFEAB602, 0xFF2291FF, 0xFF8000FF, 0xFF000000, 0xFFFF9FCF, 0xFFF4F400, 0xFF7EC8FE, 0xFFB376C7, 0xFF808080, 0xFFEECCCC, 0xFFFFFFB0, 0xFFC1F4F3, 0xFFE7CFEF, 0xFFFFFFFF
},
new uint [15]
{
0xFF400040, 0xFF424505, 0xFF006262, 0xFF2D0059, 0xFF000000, 0xFF981F5F, 0xFF9D6B4D, 0xFF377D95, 0xFF7143BC, 0xFF808080, 0xFFEC95C5, 0xFFCEC68A, 0xFF80AECA, 0xFFB56AFF, 0xFFFFFFFF
},
new uint [15]
{
0xFF710071, 0xFF950000, 0xFF438507, 0xFF005984, 0xFF000000, 0xFFD9006C, 0xFFFF8000, 0xFF66CC00, 0xFF049788, 0xFF808080, 0xFFFF93FF, 0xFFF7BA02, 0xFFDCD838, 0xFF00FFFF, 0xFFFFFFFF
},
new uint [15]
{
0xFF6D6D36, 0xFFA4A4A4, 0xFF371C00, 0xFF002D00, 0xFF000000, 0xFFAD8301, 0xFFB4B4B4, 0xFF5C3F23, 0xFF23673A, 0xFF808080, 0xFFD2CC5B, 0xFFE1E1E1, 0xFFB08364, 0xFF66938A, 0xFFFFFFFF
},
new uint [15]
{
0xFF804040, 0xFF666666, 0xFF003737, 0xFF83745C, 0xFF000000, 0xFFB3757E, 0xFFC3C3C3, 0xFF233641, 0xFFA39E65, 0xFF808080, 0xFFD7A8A8, 0xFFD0CDB9, 0xFF5F5F6D, 0xFFC9BE98, 0xFFFFFFFF
},
new uint [15]
{
0xFFAB5436, 0xFF3D140A, 0xFF6B3F8F, 0xFF793431, 0xFF000000, 0xFFD69769, 0xFF6A390D, 0xFF5050AF, 0xFFD1423F, 0xFF808080, 0xFFFABEBE, 0xFFCBAB69, 0xFF286249, 0xFFFF8B17, 0xFFFFFFFF
},
new uint [15]
{
0xFF800080, 0xFF800040, 0xFFB35900, 0xFF8C8C00, 0xFF000000, 0xFFDF00DF, 0xFFE4013A, 0xFFFF8000, 0xFFFFFF00, 0xFF808080, 0xFFFF8CFF, 0xFFD68585, 0xFFFECF78, 0xFFFFFF80, 0xFFFFFFFF
},
new uint [15]
{
0xFF4E009B, 0xFF0000A0, 0xFF538BB5, 0xFF008040, 0xFF000000, 0xFF8000FF, 0xFF5F22FD, 0xFF58CFFC, 0xFF029D5B, 0xFF84846F, 0xFFD896FC, 0xFF9595FF, 0xFF93FFFF, 0xFF43FEA5, 0xFFFFFFFF
},
new uint [15]
{
0xFF9E8B49, 0xFF8B96A7, 0xFFB78786, 0xFF432121, 0xFF000000, 0xFFBF7E3E, 0xFFAFB0BC, 0xFFDDC9BF, 0xFF562945, 0xFF5B5B5B, 0xFFBBA85B, 0xFFB1C1D1, 0xFFE0CFA9, 0xFF8A5353, 0xFFFFFFFF
},
new uint [15]
{
0xFF003535, 0xFF00974B, 0xFF487776, 0xFFF5F5F5, 0xFF8C4600, 0xFF00773C, 0xFF02B78E, 0xFF95B5BF, 0xFFEAF1F2, 0xFFCF7625, 0xFF02B08D, 0xFF64AB03, 0xFFE1E1E1, 0xFFFFFFFF, 0xFFE6AD59
},
new uint [15]
{
0xFFA5ABBC, 0xFF002828, 0xFFCBA0BE, 0xFF392837, 0xFF000000, 0xFFBDC8D2, 0xFF44526A, 0xFFDBB0CF, 0xFF593349, 0xFF808080, 0xFFC6DDDD, 0xFF687D93, 0xFFE9C7C7, 0xFF8D6376, 0xFFFFFFFF
},
new uint [15]
{
0xFFBDA98A, 0xFF222200, 0xFFBCBCBC, 0xFF232332, 0xFF000000, 0xFFE6D6BD, 0xFF5C5C2E, 0xFFD2D7DB, 0xFF424D55, 0xFF808080, 0xFFEFE7E7, 0xFF7B7C56, 0xFFE9EAED, 0xFF6B6B6B, 0xFFFFFFFF
},
};
//Should probably convert other palette data to be like this, and just do palette * 16 + color_idx to find the color
public static uint[] NL_Palette_Data = new uint[256]
{
0xFFFFEFFF, 0xFFFF9AAD, 0xFFEF559C, 0xFFFF65AD, 0xFFFF0063, 0xFFBD4573, 0xFFCE0052, 0xFF9C0031, 0xFF522031, 0xFF000009, 0xFF00000A, 0xFF00000B, 0xFF00000C, 0xFF00000D, 0xFF00000E, 0xFFFFFFFF,
0xFFFFBACE, 0xFFFF7573, 0xFFDE3010, 0xFFFF5542, 0xFFFF0000, 0xFFCE6563, 0xFFBD4542, 0xFFBD0000, 0xFF8C2021, 0xFF000019, 0xFF00001A, 0xFF00001B, 0xFF00001C, 0xFF00001D, 0xFF00001E, 0xFFECECEC,
0xFFDECFBD, 0xFFFFCF63, 0xFFDE6521, 0xFFFFAA21, 0xFFFF6500, 0xFFBD8A52, 0xFFDE4500, 0xFFBD4500, 0xFF633010, 0xFF000029, 0xFF00002A, 0xFF00002B, 0xFF00002C, 0xFF00002D, 0xFF00002E, 0xFFDADADA,
0xFFFFEFDE, 0xFFFFDFCE, 0xFFFFCFAD, 0xFFFFBA8C, 0xFFFFAA8C, 0xFFDE8A63, 0xFFBD6542, 0xFF9C5531, 0xFF8C4521, 0xFF000039, 0xFF00003A, 0xFF00003B, 0xFF00003C, 0xFF00003D, 0xFF00003E, 0xFFC8C8C8,
0xFFFFCFFF, 0xFFEF8AFF, 0xFFCE65DE, 0xFFBD8ACE, 0xFFCE00FF, 0xFF9C659C, 0xFF8C00AD, 0xFF520073, 0xFF310042, 0xFF000049, 0xFF00004A, 0xFF00004B, 0xFF00004C, 0xFF00004D, 0xFF00004E, 0xFFB6B6B6,
0xFFFFBAFF, 0xFFFF9AFF, 0xFFDE20BD, 0xFFFF55EF, 0xFFFF00CE, 0xFF8C5573, 0xFFBD009C, 0xFF8C0063, 0xFF520042, 0xFF000059, 0xFF00005A, 0xFF00005B, 0xFF00005C, 0xFF00005D, 0xFF00005E, 0xFFA3A3A3,
0xFFDEBA9C, 0xFFCEAA73, 0xFF734531, 0xFFAD7542, 0xFF9C3000, 0xFF733021, 0xFF522000, 0xFF311000, 0xFF211000, 0xFF000069, 0xFF00006A, 0xFF00006B, 0xFF00006C, 0xFF00006D, 0xFF00006E, 0xFF919191,
0xFFFFFFCE, 0xFFFFFF73, 0xFFDEDF21, 0xFFFFFF00, 0xFFFFDF00, 0xFFCEAA00, 0xFF9C9A00, 0xFF8C7500, 0xFF525500, 0xFF000079, 0xFF00007A, 0xFF00007B, 0xFF00007C, 0xFF00007D, 0xFF00007E, 0xFF7F7F7F,
0xFFDEBAFF, 0xFFBD9AEF, 0xFF6330CE, 0xFF9C55FF, 0xFF6300FF, 0xFF52458C, 0xFF42009C, 0xFF210063, 0xFF211031, 0xFF000089, 0xFF00008A, 0xFF00008B, 0xFF00008C, 0xFF00008D, 0xFF00008E, 0xFF6D6D6D,
0xFFBDBAFF, 0xFF8C9AFF, 0xFF3130AD, 0xFF3155EF, 0xFF0000FF, 0xFF31308C, 0xFF0000AD, 0xFF101063, 0xFF000021, 0xFF000099, 0xFF00009A, 0xFF00009B, 0xFF00009C, 0xFF00009D, 0xFF00009E, 0xFF5B5B5B,
0xFF9CEFBD, 0xFF63CF73, 0xFF216510, 0xFF42AA31, 0xFF008A31, 0xFF527552, 0xFF215500, 0xFF103021, 0xFF002010, 0xFF0000A9, 0xFF0000AA, 0xFF0000AB, 0xFF0000AC, 0xFF0000AD, 0xFF0000AE, 0xFF484848,
0xFFDEFFBD, 0xFFCEFF8C, 0xFF8CAA52, 0xFFADDF8C, 0xFF8CFF00, 0xFFADBA9C, 0xFF63BA00, 0xFF529A00, 0xFF316500, 0xFF0000B9, 0xFF0000BA, 0xFF0000BB, 0xFF0000BC, 0xFF0000BD, 0xFF0000BE, 0xFF363636,
0xFFBDDFFF, 0xFF73CFFF, 0xFF31559C, 0xFF639AFF, 0xFF1075FF, 0xFF4275AD, 0xFF214573, 0xFF002073, 0xFF001042, 0xFF0000C9, 0xFF0000CA, 0xFF0000CB, 0xFF0000CC, 0xFF0000CD, 0xFF0000CE, 0xFF242424,
0xFFADFFFF, 0xFF52FFFF, 0xFF008ABD, 0xFF52BACE, 0xFF00CFFF, 0xFF429AAD, 0xFF00658C, 0xFF004552, 0xFF002031, 0xFF0000D9, 0xFF0000DA, 0xFF0000DB, 0xFF0000DC, 0xFF0000DD, 0xFF0000DE, 0xFF121212,
0xFFCEFFEF, 0xFFADEFDE, 0xFF31CFAD, 0xFF52EFBD, 0xFF00FFCE, 0xFF73AAAD, 0xFF00AA9C, 0xFF008A73, 0xFF004531, 0xFF0000E9, 0xFF0000EA, 0xFF0000EB, 0xFF0000EC, 0xFF0000ED, 0xFF0000EE, 0xFF000000,
0xFFADFFAD, 0xFF73FF73, 0xFF63DF42, 0xFF00FF00, 0xFF21DF21, 0xFF52BA52, 0xFF00BA00, 0xFF008A00, 0xFF214521, 0xFF0000F9, 0xFF0000FA, 0xFF0000FB, 0xFF0000FC, 0xFF0000FD, 0xFF0000FE, 0xFF0000FF
};
private static Color ColorFromUInt32(uint color)
{
return Color.FromArgb(0xFF, (byte)(color >> 16), (byte)(color >> 8), (byte)(color));
}
public static byte ClosestColor(uint color, int palette, uint[][] paletteData)
{
uint closestColor = paletteData[palette][0];
double diff = double.MaxValue;
Color c = ColorFromUInt32(color);
float targetHue = c.GetHue();
float targetSat = c.GetSaturation();
float targetBri = c.GetBrightness();
foreach (uint validColor in paletteData[palette])
{
Color checkColor = ColorFromUInt32(validColor);
float currentHue = checkColor.GetHue();
float currentSat = checkColor.GetSaturation();
float currentBri = checkColor.GetBrightness();
double currentDiff = Math.Pow(targetHue - currentHue, 2) + Math.Pow(targetSat - currentSat, 2) + Math.Pow(targetBri - currentBri, 2);
if (currentDiff < diff)
{
diff = currentDiff;
closestColor = validColor;
}
}
return (byte)(Array.IndexOf(paletteData[palette], closestColor) + 1);
}
}
public class Pattern
{
private Save Save_File;
private int Offset = 0;
public byte[] patternBitmapBuffer = new byte[4 * 32 * 32];
public byte[] rawPatternArray;
public string Name;
public string CreatorName;
public string TownName;
public byte Palette;
public byte Concept;
public Bitmap Pattern_Bitmap;
public Pattern(int patternOffset, Save save = null)
{
Offset = patternOffset;
Save_File = save;
Read();
}
//AC only
public void GeneratePatternBitmapFromImport(byte[] buffer)
{
int pos = 0;
for (int i = 0; i < buffer.Length; i++)
{
byte RightPixel = (byte)(buffer[i] & 0x0F);
byte LeftPixel = (byte)((buffer[i] & 0xF0) >> 4);
Buffer.BlockCopy(BitConverter.GetBytes(PatternData.AC_Palette_Data[Palette][LeftPixel - 1]), 0, patternBitmapBuffer, pos * 4, 4);
Buffer.BlockCopy(BitConverter.GetBytes(PatternData.AC_Palette_Data[Palette][RightPixel - 1]), 0, patternBitmapBuffer, (pos + 1) * 4, 4);
pos += 2;
}
Pattern_Bitmap = new Bitmap(32, 32, PixelFormat.Format32bppArgb);
BitmapData bitmapData = Pattern_Bitmap.LockBits(new Rectangle(0, 0, 32, 32), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); //Should probably switch to 24bit rgb since alpha channel isn't used
System.Runtime.InteropServices.Marshal.Copy(patternBitmapBuffer, 0, bitmapData.Scan0, patternBitmapBuffer.Length);
Pattern_Bitmap.UnlockBits(bitmapData);
rawPatternArray = buffer;
}
//AC only
public byte[] ConvertImport()
{
byte[] correctedBuffer = new byte[512];
if (rawPatternArray != null)
{
List<byte[]> Block_Data = new List<byte[]>();
for (int i = 0; i < 32; i ++)
{
byte[] block = new byte[16];
for (int x = 0; x < 4; x++)
{
int pos = (i % 4) * 4 + (i / 4) * 64 + x * 16;
Buffer.BlockCopy(rawPatternArray, pos, block, x * 4, 4);
}
Block_Data.Add(block);
}
List<byte[]> Sorted_Blocks = new List<byte[]>()
{
Block_Data[0], Block_Data[4], Block_Data[1], Block_Data[5], //0, 1, 2, 3|
Block_Data[2], Block_Data[6], Block_Data[3], Block_Data[7], //4, 5, 6, 7|
Block_Data[8], Block_Data[12], Block_Data[9], Block_Data[13], //8, 9, 10, 11|
Block_Data[10], Block_Data[14], Block_Data[11], Block_Data[15], //12, 13, 14, 15|
Block_Data[16], Block_Data[20], Block_Data[17], Block_Data[21], //16, 17, 18, 19
Block_Data[18], Block_Data[22], Block_Data[19], Block_Data[23], //20, 21, 22, 23
Block_Data[24], Block_Data[28], Block_Data[25], Block_Data[29], //24, 25, 26, 27
Block_Data[26], Block_Data[30], Block_Data[27], Block_Data[31], //28, 29, 30, 31
};
for (int i = 0; i < 32; i++)
Sorted_Blocks[i].CopyTo(correctedBuffer, i * 16);
}
return correctedBuffer;
}
public void AdjustPalette()
{
if (rawPatternArray == null)
GeneratePatternBitmap();
else
GeneratePatternBitmapFromImport(rawPatternArray);
}
public void GeneratePatternBitmap()
{
byte[] patternRawData = Save_File == null ? DataConverter.ReadDataRaw(Offset + 0x20, 0x200) : Save_File.ReadByteArray(Offset + 0x20, 0x200);
if (PatternData.AC_Palette_Data.Length >= Palette + 1)
{
byte[][] Block_Data = new byte[32][];
for (int block = 0; block < 32; block++)
{
byte[] Block = new byte[16];
Buffer.BlockCopy(patternRawData, block * 16, Block, 0, 16);
Block_Data[block] = Block;
}
byte[][] Sorted_Block_Data = new byte[32][]; // Ayy I finally derived the formula! (04/28/2017) Now to write the reverse equation (should just be reverse assigned)
for (int Grouped_Block = 0; Grouped_Block < 4; Grouped_Block++)
{
for (int Double_Block = 0; Double_Block < 4; Double_Block++)
{
for (int Block = 0; Block < 2; Block++)
{
Sorted_Block_Data[Grouped_Block * 8 + Double_Block + (Block % 2) * 4] = Block_Data[Grouped_Block * 8 + Double_Block * 2 + Block];
}
}
}
int pos = 0;
for (int i = 0; i < 8; i++)
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 16; x++)
{
byte RightPixel = (byte)(Sorted_Block_Data[i * 4 + x / 4][x % 4 + y * 4] & 0x0F);
byte LeftPixel = (byte)((Sorted_Block_Data[i * 4 + x / 4][x % 4 + y * 4] & 0xF0) >> 4);
Buffer.BlockCopy(BitConverter.GetBytes(PatternData.AC_Palette_Data[Palette][Math.Max(0, LeftPixel - 1)]), 0, patternBitmapBuffer, pos * 4, 4);
Buffer.BlockCopy(BitConverter.GetBytes(PatternData.AC_Palette_Data[Palette][Math.Max(0, RightPixel - 1)]), 0, patternBitmapBuffer, (pos + 1) * 4, 4);
pos += 2;
}
}
}
Pattern_Bitmap = new Bitmap(32, 32, PixelFormat.Format32bppArgb);
BitmapData bitmapData = Pattern_Bitmap.LockBits(new Rectangle(0, 0, 32, 32), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(patternBitmapBuffer, 0, bitmapData.Scan0, patternBitmapBuffer.Length);
Pattern_Bitmap.UnlockBits(bitmapData);
}
}
public void GenerateWWPatternBitmap()
{
byte[] Raw_Data = Save_File.ReadByteArray(Offset, 0x200);
byte[] Expanded_Data = new byte[0x400];
for (int i = 0; i < 0x200; i++)
{
Expanded_Data[i * 2] = (byte)(Raw_Data[i] & 0x0F); //Left is Right
Expanded_Data[i * 2 + 1] = (byte)((Raw_Data[i] & 0xF0) >> 4); //Right is Left
}
uint[] Palette_Array = PatternData.WW_Palette_Data[Palette];
//All colors are reversed in there... fix sometime pls
for (int i = 0; i < 0x400; i++)
{
int color_idx = Math.Max(0, Expanded_Data[i] - 1);
uint color = Palette_Array[color_idx];
byte[] color_bytes = BitConverter.GetBytes(color);
byte[] corrected_bytes = new byte[4] {color_bytes[2], color_bytes[1], color_bytes[0], 0xFF };
Buffer.BlockCopy(corrected_bytes, 0, patternBitmapBuffer, i * 4, 4);
}
Pattern_Bitmap = new Bitmap(32, 32, PixelFormat.Format32bppArgb);
BitmapData bitmapData = Pattern_Bitmap.LockBits(new Rectangle(0, 0, 32, 32), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(patternBitmapBuffer, 0, bitmapData.Scan0, patternBitmapBuffer.Length);
Pattern_Bitmap.UnlockBits(bitmapData);
}
//Add "pro" patterns (supports four patterns in one)
public void GenerateCFPatternBitmap()
{
byte[] Raw_Data = Save_File.ReadByteArray(Offset, 0x200);
{
List<byte[]> Block_Data = new List<byte[]>();
for (int block = 0; block < 32; block++)
{
byte[] Block = new byte[16];
Buffer.BlockCopy(Raw_Data, block * 16, Block, 0, 16);
Block_Data.Add(Block);
}
List<byte[]> Sorted_Block_Data = new List<byte[]>() //Too lazy to derive the actual formula to decode it, so I'll sort it manually
{
Block_Data[0], Block_Data[2], Block_Data[4], Block_Data[6],
Block_Data[1], Block_Data[3], Block_Data[5], Block_Data[7],
Block_Data[8], Block_Data[10], Block_Data[12], Block_Data[14],
Block_Data[9], Block_Data[11], Block_Data[13], Block_Data[15],
Block_Data[16], Block_Data[18], Block_Data[20], Block_Data[22],
Block_Data[17], Block_Data[19], Block_Data[21], Block_Data[23],
Block_Data[24], Block_Data[26], Block_Data[28], Block_Data[30],
Block_Data[25], Block_Data[27], Block_Data[29], Block_Data[31],
};
int pos = 0;
for (int i = 0; i < 8; i++)
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 16; x++)
{
byte RightPixel = (byte)(Sorted_Block_Data[i * 4 + x / 4][x % 4 + y * 4] & 0x0F);
byte LeftPixel = (byte)((Sorted_Block_Data[i * 4 + x / 4][x % 4 + y * 4] & 0xF0) >> 4);
Buffer.BlockCopy(BitConverter.GetBytes(PatternData.CF_Palette_Data[Palette][Math.Max(0, LeftPixel - 1)]), 0, patternBitmapBuffer, pos * 4, 4);
Buffer.BlockCopy(BitConverter.GetBytes(PatternData.CF_Palette_Data[Palette][Math.Max(0, RightPixel - 1)]), 0, patternBitmapBuffer, (pos + 1) * 4, 4);
pos += 2;
}
}
}
Pattern_Bitmap = new Bitmap(32, 32, PixelFormat.Format32bppArgb);
BitmapData bitmapData = Pattern_Bitmap.LockBits(new Rectangle(0, 0, 32, 32), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(patternBitmapBuffer, 0, bitmapData.Scan0, patternBitmapBuffer.Length);
Pattern_Bitmap.UnlockBits(bitmapData);
}
}
//NL Patterns have a custom palette, created by the user by choosing 15 colors
public void GenerateNLPatternBitmap()
{
//Add decoding of "Pro" patterns
byte[] Raw_Data = Save_File.ReadByteArray(Offset + 0x6C, 0x200); //32x32 doubled up pixels
byte[] Expanded_Data = new byte[0x400]; //32x32 expanded pixel buffer
byte[] Custom_Palette = Save_File.ReadByteArray(Offset + 0x58, 15); //New Leaf user selected palette data
//Expand data for working with
for (int i = 0; i < 0x200; i++)
{
Expanded_Data[i * 2] = (byte)(Raw_Data[i] & 0x0F);
Expanded_Data[i * 2 + 1] = (byte)((Raw_Data[i] >> 4) & 0x0F);
}
//Convert palette color index to argb color
for (int i = 0; i < 0x400; i++)
Buffer.BlockCopy(BitConverter.GetBytes(PatternData.NL_Palette_Data[Custom_Palette[Expanded_Data[i]]]), 0, patternBitmapBuffer, i * 4, 4);
//Create new bitmap
Pattern_Bitmap = new Bitmap(32, 32, PixelFormat.Format32bppArgb);
BitmapData bitmapData = Pattern_Bitmap.LockBits(new Rectangle(0, 0, 32, 32), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(patternBitmapBuffer, 0, bitmapData.Scan0, patternBitmapBuffer.Length);
Pattern_Bitmap.UnlockBits(bitmapData);
}
public void Read()
{
if (Save_File.Save_Type == SaveType.Animal_Crossing || Save_File.Save_Type == SaveType.Doubutsu_no_Mori_e_Plus || Save_File.Save_Type == SaveType.Doubutsu_no_Mori
|| Save_File.Save_Type == SaveType.Doubutsu_no_Mori_Plus)
{
Name = Save_File == null ? DataConverter.ReadString(Offset, 0x10).Trim() : new ACString(Save_File.ReadByteArray(Offset, 0x10)).Trim();
Palette = Save_File == null ? DataConverter.ReadData(Offset + 0x10, 0x1)[0] : Save_File.ReadByte(Offset + 0x10);
GeneratePatternBitmap();
}
else if (Save_File.Save_Type == SaveType.Wild_World)
{
TownName = new ACString(Save_File.ReadByteArray(Offset + 0x202, 8), SaveType.Wild_World).Trim();
CreatorName = new ACString(Save_File.ReadByteArray(Offset + 0x20C, 8), SaveType.Wild_World).Trim();
Name = new ACString(Save_File.ReadByteArray(Offset + 0x216, 16), SaveType.Wild_World).Trim();
Palette = (byte)((Save_File.ReadByte(Offset + 0x226) & 0xF0) >> 4);
Concept = (byte)(Save_File.ReadByte(Offset + 0x226) & 0x0F);
GenerateWWPatternBitmap();
}
else if (Save_File.Save_Type == SaveType.City_Folk)
{
TownName = new ACString(Save_File.ReadByteArray(Offset + 0x822, 16), SaveType.City_Folk).Trim();
CreatorName = new ACString(Save_File.ReadByteArray(Offset + 0x838, 16), SaveType.City_Folk).Trim();
Name = new ACString(Save_File.ReadByteArray(Offset + 0x84C, 32), SaveType.City_Folk).Trim();
Palette = Save_File.ReadByte(Offset + 0x86F);
GenerateCFPatternBitmap();
}
else if (Save_File.Save_Type == SaveType.New_Leaf || Save_File.Save_Type == SaveType.Welcome_Amiibo)
{
Name = new ACString(Save_File.ReadByteArray(Offset, 0x2A), SaveType.New_Leaf).Trim();
CreatorName = new ACString(Save_File.ReadByteArray(Offset + 0x2C, 0x14), SaveType.New_Leaf).Trim();
TownName = new ACString(Save_File.ReadByteArray(Offset + 0x42, 0x14), SaveType.New_Leaf).Trim();
//No specific palette in NL/WA
GenerateNLPatternBitmap();
}
else
MessageBox.Show("Patterns: Unknown Save Type");
}
public void Write()
{
DataConverter.WriteString(Offset, Name, 0x10);
DataConverter.WriteByte(Offset + 0x10, Palette);
if (rawPatternArray != null)
DataConverter.WriteByteArray(Offset + 0x20, ConvertImport(), false);
}
}
}

1035
Classes/Player.cs Normal file

File diff suppressed because it is too large Load diff

24
Classes/Program.cs Normal file
View file

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace ACSE
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new NewMainForm());
}
}
}

873
Classes/Save.cs Normal file
View file

@ -0,0 +1,873 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Globalization;
namespace ACSE
{
public enum SaveType
{
Unknown,
Doubutsu_no_Mori,
Doubutsu_no_Mori_Plus, //Possible to remove this? I can't even find a valid file on the internet... Perhaps I'll just buy a copy
Animal_Crossing,
Doubutsu_no_Mori_e_Plus,
Wild_World,
City_Folk,
New_Leaf,
Welcome_Amiibo
}
public struct Offsets
{
public int Save_Size;
public int Checksum;
public int Town_Name;
public int Player_Start;
public int Player_Size;
public int Town_Data;
public int Town_Data_Size;
public int Acre_Data;
public int Acre_Data_Size;
public int Buried_Data;
public int Buried_Data_Size;
public int Island_Acre_Data;
public int Island_World_Data;
public int Island_World_Size;
public int Island_Buried_Data;
public int Island_Buried_Size;
public int Island_Buildings;
public int House_Data;
public int House_Data_Size;
public int Villager_Data;
public int Villager_Size;
public int Islander_Data;
public int Debt; //Only global in WW
public int Buildings; //CF/NL
public int Buildings_Count;
public int Grass_Wear;
public int Grass_Wear_Size;
public int PWPs; //NL only
public int Past_Villagers;
public int[] CRC_Offsets;
}
public struct Save_Info
{
public bool Contains_Island;
public bool Has_Islander;
public int Pattern_Count;
public bool Player_JPEG_Picture;
public Offsets Save_Offsets;
public int Acre_Count;
public int X_Acre_Count;
public int Town_Acre_Count;
public int Town_Y_Acre_Start;
public int Island_Acre_Count;
public int Island_X_Acre_Count;
public int Villager_Count;
public string[] House_Rooms;
}
public enum SaveFileDataOffset
{
nafjfla = 0,
gafegci = 0x26040,
gafegcs = 0x26150,
admeduc = 0x1F4,
admedss = 0x1F4,
admedsv = 0,
admesav = 0,
ruuedat = 0,
edgedat = 0x80,
edgebin = 0, //RAM Dump
eaaedat = 0x80,
}
public static class SaveDataManager
{
public static Offsets Animal_Crossing_Offsets = new Offsets
{
Save_Size = 0x26000,
Town_Name = 0x9120,
Player_Start = 0x20,
Player_Size = 0x2440,
Villager_Data = 0x17438,
Villager_Size = 0x988,
Acre_Data = 0x173A8,
Acre_Data_Size = 0x8C,
Town_Data = 0x137A8,
Town_Data_Size = 0x3C00,
Buried_Data = 0x20F1C,
Buried_Data_Size = 0x3C0,
Island_World_Data = 0x22554,
Island_World_Size = 0x400,
Island_Buried_Data = 0x23DC8, //C9
Island_Buried_Size = 0x40,
Islander_Data = 0x23440,
House_Data = 0x9CE8,
House_Data_Size = 0x26B0,
Island_Acre_Data = 0x17420,
Buildings = -1,
Debt = -1,
Grass_Wear = -1,
Past_Villagers = -1,
PWPs = -1,
Island_Buildings = -1,
Checksum = 0x12
};
public static Offsets Wild_World_Offsets = new Offsets
{
Save_Size = 0x15FE0,
Town_Name = 0x0004,
Player_Start = 0x000C,
Player_Size = 0x228C,
Villager_Data = 0x8A3C,
Villager_Size = 0x700,
Acre_Data = 0xC330,
Acre_Data_Size = 0x24,
Town_Data = 0xC354,
Town_Data_Size = 0x2000,
Buried_Data = 0xE354,
Buried_Data_Size = 0x200,
House_Data = 0xE558,
House_Data_Size = 0x15A0,
Debt = 0xFAE8,
Buildings = -1,
Grass_Wear = -1,
Islander_Data = -1,
Island_Buried_Data = -1,
Island_World_Data = -1,
Past_Villagers = -1,
PWPs = -1,
Island_Acre_Data = -1,
Island_Buildings = -1,
Checksum = 0x15FDC
};
public static Offsets City_Folk_Offsets = new Offsets
{
Save_Size = 0x40F340,
Player_Start = 0,
Player_Size = 0x86C0,
Buildings = 0x5EB0A,
Buildings_Count = 0x33, //Not sure
Acre_Data = 0x68414, //Don't forget about the additional acres before?
Acre_Data_Size = 0x62,
Town_Name = 0x640E8,
Town_Data = 0x68476,
Town_Data_Size = 0x3200,
Buried_Data = 0x6B676,
Buried_Data_Size = 400,
Grass_Wear = 0x6BCB6,
Grass_Wear_Size = 0x1900,
House_Data = 0x6D5C0,
House_Data_Size = 0x15C0,
Checksum = -1,
Debt = -1,
Islander_Data = -1,
Island_Buried_Data = -1,
Island_World_Data = -1,
Past_Villagers = -1,
PWPs = -1,
Villager_Data = -1, //finish this sometime
Island_Acre_Data = -1,
Island_Buildings = -1,
};
public static Offsets New_Leaf_Offsets = new Offsets
{
Save_Size = 0x7F980,
Player_Start = 0x20,
Player_Size = 0x9F10,
Villager_Data = 0x27C90,
Villager_Size = 0x24F8,
Buildings = 0x49528,
Buildings_Count = 58, //TODO: Add island buildings (Island Hut & Loaner Gyroid at 59 and 60)
Acre_Data = 0x4DA04,
Acre_Data_Size = 0x54,
Town_Data = 0x4DA58,
Town_Data_Size = 0x5000,
Buried_Data = -1,
Town_Name = 0x5C73A,
Grass_Wear = 0x53E80,
Grass_Wear_Size = 0x3000, //Extra row of "Invisible" X Acres
Past_Villagers = 0x3F17E,
Island_Acre_Data = 0x6A408,
Island_World_Data = 0x6A428,
Island_Buildings = 0x6B428,
//Campsite_Villager = 0x3F1CA
};
public static Offsets Welcome_Amiibo_Offsets = new Offsets
{
Save_Size = 0x89A80,
Player_Start = 0x20,
Player_Size = 0xA480,
Villager_Data = 0x29250,
Villager_Size = 0x2518,
Buildings = 0x4BE08,
Buildings_Count = 58, //TODO: Add island buildings (Island Hut & Loaner Gyroid at 59 and 60)
Acre_Data = 0x53404,
Acre_Data_Size = 0x54,
Town_Data = 0x53458,
Town_Data_Size = 0x5000,
Buried_Data = -1,
Town_Name = 0x6213A,
Grass_Wear = 0x59880,
Grass_Wear_Size = 0x3000, //Extra row of "Invisible" X Acres
Past_Villagers = 0x4087A,
Island_Acre_Data = 0x6FE38,
Island_World_Data = 0x6FE58,
Island_Buildings = 0x70E58,
};
public static Save_Info Animal_Crossing = new Save_Info
{
Contains_Island = true,
Has_Islander = true,
Player_JPEG_Picture = false,
Pattern_Count = 8,
Save_Offsets = Animal_Crossing_Offsets,
Acre_Count = 70,
X_Acre_Count = 7,
Town_Acre_Count = 30,
Island_Acre_Count = 2,
Island_X_Acre_Count = 2,
Town_Y_Acre_Start = 1,
Villager_Count = 16,
House_Rooms = new string[3] { "Main Floor", "Upper Floor", "Basement" } //Don't forget about island house
};
public static Save_Info Wild_World = new Save_Info
{
Contains_Island = false,
Has_Islander = false,
Player_JPEG_Picture = false,
Pattern_Count = 8,
Save_Offsets = Wild_World_Offsets,
Acre_Count = 36,
X_Acre_Count = 6,
Town_Acre_Count = 16,
Town_Y_Acre_Start = 1,
Villager_Count = 8,
House_Rooms = new string[6] { "Main Floor", "Basement", "Upper Floor", "Left Wing", "Right Wing", "Back Wing" } //Confirm order
//6 drawers with 15 items per
};
public static Save_Info City_Folk = new Save_Info
{
Contains_Island = false,
Has_Islander = false,
Player_JPEG_Picture = false,
Pattern_Count = 8,
Save_Offsets = City_Folk_Offsets,
Acre_Count = 49,
X_Acre_Count = 7,
Town_Acre_Count = 25,
Town_Y_Acre_Start = 1,
Villager_Count = 10,
House_Rooms = new string[3] { "Main Floor", "Upper Floor", "Basement" }
};
public static Save_Info New_Leaf = new Save_Info
{
Contains_Island = true,
Has_Islander = false,
Player_JPEG_Picture = true,
Pattern_Count = 10,
Save_Offsets = New_Leaf_Offsets,
Acre_Count = 42,
X_Acre_Count = 7,
Town_Acre_Count = 20,
Town_Y_Acre_Start = 1,
Villager_Count = 10,
Island_Acre_Count = 16,
Island_X_Acre_Count = 4,
House_Rooms = new string[6] { "Main Floor", "Upper Floor", "Basement", "Left Wing", "Right Wing", "Back Wing" } //Check order
//3 drawers with 60 items per
};
public static Save_Info Welcome_Amiibo = new Save_Info
{
Contains_Island = true,
Has_Islander = false,
Player_JPEG_Picture = true,
Pattern_Count = 10,
Save_Offsets = Welcome_Amiibo_Offsets,
Acre_Count = 42,
X_Acre_Count = 7,
Town_Acre_Count = 20,
Town_Y_Acre_Start = 1,
Villager_Count = 10,
Island_Acre_Count = 16,
Island_X_Acre_Count = 4,
House_Rooms = new string[6] { "Main Floor", "Upper Floor", "Basement", "Left Wing", "Right Wing", "Back Wing" }
//3 drawers with 60 items per
};
/// <summary>
/// Used for Doubutsu no Mori. Every four bytes is reversed in the save, so we change it back.
/// </summary>
/// <param name="saveBuff"></param>
/// <returns></returns>
public static byte[] ByteSwap(byte[] saveBuff)
{
byte[] Corrected_Save = new byte[saveBuff.Length];
for (int i = 0; i < saveBuff.Length; i += 4)
{
byte[] Temp = new byte[4];
Buffer.BlockCopy(saveBuff, i, Temp, 0, 4);
Array.Reverse(Temp);
Temp.CopyTo(Corrected_Save, i);
}
return Corrected_Save;
}
public static SaveType GetSaveType(byte[] Save_Data)
{
if (Save_Data.Length == 0x20000)
return SaveType.Doubutsu_no_Mori;
else if (Save_Data.Length == 0x72040 || Save_Data.Length == 0x72150)
{
string Game_ID = Encoding.ASCII.GetString(Save_Data, Save_Data.Length == 0x72150 ? 0x110 : 0, 4);
if (Game_ID == "GAFE")
return SaveType.Animal_Crossing;
else if (Game_ID == "GAFJ")
return SaveType.Doubutsu_no_Mori_Plus;
else if (Game_ID == "GAEJ")
return SaveType.Doubutsu_no_Mori_e_Plus;
}
else if (Save_Data.Length == 0x4007A || Save_Data.Length == 0x401F4 || Save_Data.Length == 0x40000)
return SaveType.Wild_World;
else if (Save_Data.Length == 0x40F340 || Save_Data.Length == 0x47A0DA)
return SaveType.City_Folk;
else if (Save_Data.Length == 0x7FA00 || Save_Data.Length == 0x80000)
return SaveType.New_Leaf;
else if (Save_Data.Length == 0x89B00)
return SaveType.Welcome_Amiibo;
return SaveType.Unknown;
}
public static int GetSaveDataOffset(string Game_ID, string Extension)
{
if (Enum.TryParse(Game_ID + Extension, out SaveFileDataOffset Extension_Enum))
return (int)Extension_Enum;
return 0;
}
public static string GetGameID(SaveType Save_Type)
{
switch (Save_Type)
{
case SaveType.Doubutsu_no_Mori:
return "NAFJ";
case SaveType.Animal_Crossing:
return "GAFE";
case SaveType.Doubutsu_no_Mori_Plus:
return "GAFJ";
case SaveType.Doubutsu_no_Mori_e_Plus:
return "GAEJ";
case SaveType.Wild_World: //Currently only supporting the English versions of WW+
return "ADME";
case SaveType.City_Folk:
return "RUUE";
case SaveType.New_Leaf:
return "EDGE";
case SaveType.Welcome_Amiibo:
return "EAAE";
default:
return "Unknown";
}
}
public static Save_Info GetSaveInfo(SaveType Save_Type)
{
switch(Save_Type)
{
case SaveType.Animal_Crossing:
return Animal_Crossing;
case SaveType.Wild_World:
return Wild_World;
case SaveType.City_Folk:
return City_Folk;
case SaveType.New_Leaf:
return New_Leaf;
case SaveType.Welcome_Amiibo:
return Welcome_Amiibo;
default:
return Wild_World;
}
}
public static Dictionary<ushort, string> GetItemInfo(SaveType Save_Type, string Language = "en")
{
StreamReader Contents = null;
string Item_DB_Location = NewMainForm.Assembly_Location + "\\Resources\\";
if (Save_Type == SaveType.Wild_World)
Item_DB_Location += "WW_Items_" + Language + ".txt";
else if (Save_Type == SaveType.Animal_Crossing)
Item_DB_Location += "AC_Items_" + Language + ".txt";
else if (Save_Type == SaveType.City_Folk)
Item_DB_Location += "CF_Items_" + Language + ".txt";
else if (Save_Type == SaveType.New_Leaf)
Item_DB_Location += "NL_Items_" + Language + ".txt";
else if (Save_Type == SaveType.Welcome_Amiibo)
Item_DB_Location += "WA_Items_" + Language + ".txt";
try { Contents = File.OpenText(Item_DB_Location); }
catch (Exception e)
{
NewMainForm.Debug_Manager.WriteLine(string.Format("An error occured opening item database file:\n\"{0}\"\nError Info:\n{1}", Item_DB_Location, e.Message), DebugLevel.Error);
return null;
}
Dictionary<ushort, string> Item_Dictionary = new Dictionary<ushort, string>();
string Line;
while ((Line = Contents.ReadLine()) != null)
{
if (!Properties.Settings.Default.DebuggingEnabled && Line.Contains("//"))
MessageBox.Show("Now loading item type: " + Line.Replace("//", ""));
else if (Line.Contains("0x"))
{
string Item_ID_String = Line.Substring(0, 6), Item_Name = Line.Substring(7).Trim();
if (ushort.TryParse(Item_ID_String.Replace("0x", ""), NumberStyles.AllowHexSpecifier, null, out ushort Item_ID))
Item_Dictionary.Add(Item_ID, Item_Name);
else
NewMainForm.Debug_Manager.WriteLine("Unable to add item: " + Item_ID_String + " | " + Item_Name, DebugLevel.Error);
}
}
return Item_Dictionary;
}
public static Dictionary<byte, string> GetAcreInfo(SaveType Save_Type, string Language = "en")
{
StreamReader Contents = null;
string Acre_DB_Location = NewMainForm.Assembly_Location + "\\Resources\\";
if (Save_Type == SaveType.Wild_World)
Acre_DB_Location += "WW_Acres_" + Language + ".txt";
try { Contents = File.OpenText(Acre_DB_Location); }
catch (Exception e)
{
NewMainForm.Debug_Manager.WriteLine(string.Format("An error occured opening acre database file:\n\"{0}\"\nError Info:\n{1}", Acre_DB_Location, e.Message), DebugLevel.Error);
return null;
}
Dictionary<byte, string> Acre_Dictionary = new Dictionary<byte, string>();
string Line;
while ((Line = Contents.ReadLine()) != null)
{
if (!Properties.Settings.Default.DebuggingEnabled && Line.Contains("//"))
MessageBox.Show("Now loading Acre type: " + Line.Replace("//", ""));
else if (Line.Contains("0x"))
{
string Acre_ID_String = Line.Substring(0, 4), Acre_Name = Line.Substring(5);
if (byte.TryParse(Acre_ID_String.Replace("0x", ""), NumberStyles.AllowHexSpecifier, null, out byte Acre_ID))
Acre_Dictionary.Add(Acre_ID, Acre_Name);
else
NewMainForm.Debug_Manager.WriteLine("Unable to add Acre: " + Acre_ID_String + " | " + Acre_Name, DebugLevel.Error);
}
}
return Acre_Dictionary;
}
public static Dictionary<ushort, string> GetAcreInfoUInt16(SaveType Save_Type, string Language = "en")
{
StreamReader Contents = null;
string Acre_DB_Location = NewMainForm.Assembly_Location + "\\Resources\\";
if (Save_Type == SaveType.Animal_Crossing)
Acre_DB_Location += "AC_Acres_" + Language + ".txt";
else if (Save_Type == SaveType.City_Folk)
Acre_DB_Location += "CF_Acres_" + Language + ".txt";
else if (Save_Type == SaveType.New_Leaf)
Acre_DB_Location += "NL_Acres_" + Language + ".txt";
else if (Save_Type == SaveType.Welcome_Amiibo)
Acre_DB_Location += "WA_Acres_" + Language + ".txt";
try { Contents = File.OpenText(Acre_DB_Location); }
catch (Exception e)
{
NewMainForm.Debug_Manager.WriteLine(string.Format("An error occured opening acre database file:\n\"{0}\"\nError Info:\n{1}", Acre_DB_Location, e.Message), DebugLevel.Error);
return null;
}
Dictionary<ushort, string> Acre_Dictionary = new Dictionary<ushort, string>();
string Line;
while ((Line = Contents.ReadLine()) != null)
{
if (!Properties.Settings.Default.DebuggingEnabled && Line.Contains("//"))
MessageBox.Show("Now loading Acre type: " + Line.Replace("//", ""));
else if (Line.Contains("0x"))
{
string Acre_ID_String = Line.Substring(0, 6), Acre_Name = Line.Substring(7);
if (ushort.TryParse(Acre_ID_String.Replace("0x", ""), NumberStyles.AllowHexSpecifier, null, out ushort Acre_ID))
Acre_Dictionary.Add(Acre_ID, Acre_Name);
else
NewMainForm.Debug_Manager.WriteLine("Unable to add Acre: " + Acre_ID_String + " | " + Acre_Name, DebugLevel.Error);
}
}
return Acre_Dictionary;
}
public static Dictionary<string, List<byte>> GetFiledAcreData(SaveType Save_Type, string Language = "en")
{
StreamReader Contents = null;
string Acre_DB_Location = NewMainForm.Assembly_Location + "\\Resources\\";
if (Save_Type == SaveType.Wild_World)
Acre_DB_Location += "WW_Acres_" + Language + ".txt";
try { Contents = File.OpenText(Acre_DB_Location); }
catch (Exception e)
{
NewMainForm.Debug_Manager.WriteLine(string.Format("An error occured opening acre database file:\n\"{0}\"\nError Info:\n{1}", Acre_DB_Location, e.Message), DebugLevel.Error);
return null;
}
Dictionary<string, List<byte>> Filed_List = new Dictionary<string, List<byte>>();
string Line;
string Current_Acre_Type = "Unsorted";
while ((Line = Contents.ReadLine()) != null)
{
if (Line.Contains("//"))
{
if (Current_Acre_Type != "Unsorted")
{
if (!Filed_List.ContainsKey(Current_Acre_Type))
Filed_List.Add(Current_Acre_Type, new List<byte>());
}
Current_Acre_Type = Line.Replace("//", "");
}
else if (Line.Contains("0x"))
{
if (!Filed_List.ContainsKey(Current_Acre_Type))
Filed_List.Add(Current_Acre_Type, new List<byte>());
string Acre_ID_String = Line.Substring(0, 4), Acre_Name = Line.Substring(5);
if (byte.TryParse(Acre_ID_String.Replace("0x", ""), NumberStyles.AllowHexSpecifier, null, out byte Acre_ID))
Filed_List[Current_Acre_Type].Add(Acre_ID);
else
NewMainForm.Debug_Manager.WriteLine("Unable to add Acre: " + Acre_ID_String + " | " + Acre_Name, DebugLevel.Error);
}
}
return Filed_List;
}
public static Dictionary<string, Dictionary<ushort, string>> GetFiledAcreDataUInt16(SaveType Save_Type, string Language = "en")
{
StreamReader Contents = null;
string Acre_DB_Location = NewMainForm.Assembly_Location + "\\Resources\\";
if (Save_Type == SaveType.Animal_Crossing)
Acre_DB_Location += "AC_Acres_" + Language + ".txt";
else if (Save_Type == SaveType.City_Folk)
Acre_DB_Location += "CF_Acres_" + Language + ".txt";
else if (Save_Type == SaveType.New_Leaf)
Acre_DB_Location += "NL_Acres_" + Language + ".txt";
else if (Save_Type == SaveType.Welcome_Amiibo)
Acre_DB_Location += "WA_Acres_" + Language + ".txt";
try { Contents = File.OpenText(Acre_DB_Location); }
catch (Exception e)
{
NewMainForm.Debug_Manager.WriteLine(string.Format("An error occured opening acre database file:\n\"{0}\"\nError Info:\n{1}", Acre_DB_Location, e.Message), DebugLevel.Error);
return null;
}
Dictionary<string, Dictionary<ushort, string>> Filed_List = new Dictionary<string, Dictionary<ushort, string>>();
string Line;
string Current_Acre_Type = "Unsorted";
while ((Line = Contents.ReadLine()) != null)
{
if (Line.Contains("//"))
{
if (Current_Acre_Type != "Unsorted")
{
if (!Filed_List.ContainsKey(Current_Acre_Type))
Filed_List.Add(Current_Acre_Type, new Dictionary<ushort, string>());
}
Current_Acre_Type = Line.Replace("//", "");
}
else if (Line.Contains("0x"))
{
if (!Filed_List.ContainsKey(Current_Acre_Type))
Filed_List.Add(Current_Acre_Type, new Dictionary<ushort, string>());
string Acre_ID_String = Line.Substring(0, 6), Acre_Name = Line.Substring(7);
if (ushort.TryParse(Acre_ID_String.Replace("0x", ""), NumberStyles.AllowHexSpecifier, null, out ushort Acre_ID))
Filed_List[Current_Acre_Type].Add(Acre_ID, Line.Substring(7));
else
NewMainForm.Debug_Manager.WriteLine("Unable to add Acre: " + Acre_ID_String + " | " + Acre_Name, DebugLevel.Error);
}
}
return Filed_List;
}
public static void GetNibbles(byte Byte_to_Split, out byte Lower_Nibble, out byte Upper_Nibble)
{
Lower_Nibble = (byte)(Byte_to_Split & 0x0F);
Upper_Nibble = (byte)((Byte_to_Split & 0xF0) >> 4);
}
public static byte CondenseNibbles(byte Lower_Nibble, byte Upper_Nibble)
{
return (byte)(((Upper_Nibble & 0x0F) >> 4) + Lower_Nibble & 0x0F);
}
}
public class Save
{
public SaveType Save_Type;
public byte[] Original_Save_Data;
public byte[] Working_Save_Data;
public int Save_Data_Start_Offset;
public string Save_Path;
public string Save_Name;
public string Save_Extension;
public string Save_ID;
public bool Is_Big_Endian = true;
private FileStream Save_File;
private BinaryReader Save_Reader;
private BinaryWriter Save_Writer;
public Save(string File_Path)
{
if (File.Exists(File_Path))
{
if (Save_File != null)
{
Save_Reader.Close();
Save_File.Close();
}
bool Failed_to_Load = false;
try { Save_File = new FileStream(File_Path, FileMode.Open); } catch { Failed_to_Load = true; }
if (Save_File == null || Failed_to_Load || !Save_File.CanWrite)
{
MessageBox.Show(string.Format("Error: File {0} is being used by another process. Please close any process using it before editing!",
Path.GetFileName(File_Path)), "File Opening Error");
try { Save_File.Close(); } catch { };
return;
}
Save_Reader = new BinaryReader(Save_File);
Original_Save_Data = Save_Type == SaveType.Doubutsu_no_Mori ? SaveDataManager.ByteSwap(Save_Reader.ReadBytes((int)Save_File.Length)) : Save_Reader.ReadBytes((int)Save_File.Length);
Working_Save_Data = new byte[Original_Save_Data.Length];
Buffer.BlockCopy(Original_Save_Data, 0, Working_Save_Data, 0, Original_Save_Data.Length);
Save_Type = SaveDataManager.GetSaveType(Original_Save_Data);
Save_Name = Path.GetFileNameWithoutExtension(File_Path);
Save_Path = Path.GetDirectoryName(File_Path) + Path.DirectorySeparatorChar;
Save_Extension = Path.GetExtension(File_Path);
Save_ID = SaveDataManager.GetGameID(Save_Type);
Save_Data_Start_Offset = SaveDataManager.GetSaveDataOffset(Save_ID.ToLower(), Save_Extension.Replace(".", "").ToLower());
if (Save_Type == SaveType.Wild_World || Save_Type == SaveType.New_Leaf || Save_Type == SaveType.Welcome_Amiibo)
Is_Big_Endian = false;
Save_Reader.Close();
Save_File.Close();
}
else
MessageBox.Show("File doesn't exist!");
}
public void Flush()
{
string Full_Save_Name = Save_Path + Path.DirectorySeparatorChar + Save_Name + Save_Extension;
Save_File = new FileStream(Full_Save_Name, FileMode.OpenOrCreate);
Save_Writer = new BinaryWriter(Save_File);
if (Save_Type == SaveType.Animal_Crossing)
{
Write(Save_Data_Start_Offset + 0x12, Checksum.Calculate(Working_Save_Data.Skip(Save_Data_Start_Offset).Take(0x26000).ToArray(), 0x12), true);
Working_Save_Data.Skip(Save_Data_Start_Offset).Take(0x26000).ToArray().CopyTo(Working_Save_Data, Save_Data_Start_Offset + 0x26000); //Update second save copy
}
else if (Save_Type == SaveType.Wild_World)
{
Write(Save_Data_Start_Offset + 0x15FDC, Checksum.Calculate(Working_Save_Data.Skip(Save_Data_Start_Offset).Take(0x15FE0).ToArray(),
0x15FDC, true));
Working_Save_Data.Skip(Save_Data_Start_Offset).Take(0x15FE0).ToArray().CopyTo(Working_Save_Data, Save_Data_Start_Offset + 0x15FE0); //Update both save copies on WW
}
else if (Save_Type == SaveType.City_Folk)
{
for (int i = 0; i < 4; i++)
{
int Player_Data_Offset = Save_Data_Start_Offset + i * 0x86C0 + 0x1140;
uint Player_CRC32 = CRC32.GetCRC32(Working_Save_Data.Skip(Player_Data_Offset + 4).Take(0x759C).ToArray());
Write(Player_Data_Offset, Player_CRC32, true);
}
Write(Save_Data_Start_Offset + 0x5EC60, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x5EC64).Take(0x1497C).ToArray()), true);
Write(Save_Data_Start_Offset + 0x5EB04, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x5EB08).Take(0x152).ToArray(), 0x12141018), true);
Write(Save_Data_Start_Offset + 0x73600, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x73604).Take(0x19BD1C).ToArray()), true);
Write(Save_Data_Start_Offset, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 4).Take(0x1C).ToArray()), true);
Write(Save_Data_Start_Offset + 0x20, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x24).Take(0x111C).ToArray()), true);
}
else if (Save_Type == SaveType.New_Leaf)
{
Write(Save_Data_Start_Offset, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 4).Take(0x1C).ToArray()));
for (int i = 0; i < 4; i++)
{
int DataOffset = Save_Data_Start_Offset + 0x20 + i * 0x9F10;
Write(DataOffset, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(DataOffset + 4).Take(0x6B64).ToArray()));
int DataOffset2 = Save_Data_Start_Offset + 0x20 + 0x6B68 + i * 0x9F10;
Write(DataOffset2, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(DataOffset2 + 4).Take(0x33A4).ToArray()));
}
Write(Save_Data_Start_Offset + 0x27C60, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x27C60 + 4).Take(0x218B0).ToArray()));
Write(Save_Data_Start_Offset + 0x49520, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x49520 + 4).Take(0x44B8).ToArray()));
Write(Save_Data_Start_Offset + 0x4D9DC, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x4D9DC + 4).Take(0x1E420).ToArray()));
Write(Save_Data_Start_Offset + 0x6BE00, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x6BE00 + 4).Take(0x20).ToArray()));
Write(Save_Data_Start_Offset + 0x6BE24, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x6BE24 + 4).Take(0x13AF8).ToArray()));
}
else if (Save_Type == SaveType.Welcome_Amiibo)
{
Write(Save_Data_Start_Offset, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 4).Take(0x1C).ToArray()));
for (int i = 0; i < 4; i++)
{
int DataOffset = Save_Data_Start_Offset + 0x20 + i * 0xA480;
Write(DataOffset, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(DataOffset + 4).Take(0x6B84).ToArray()));
int DataOffset2 = Save_Data_Start_Offset + 0x20 + 0x6B88 + i * 0xA480;
Write(DataOffset2, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(DataOffset2 + 4).Take(0x38F4).ToArray()));
}
Write(Save_Data_Start_Offset + 0x29220, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x29220 + 4).Take(0x22BC8).ToArray()));
Write(Save_Data_Start_Offset + 0x4BE00, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x4BE00 + 4).Take(0x44B8).ToArray()));
Write(Save_Data_Start_Offset + 0x533A4, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x533A4 + 4).Take(0x1E4D8).ToArray()));
Write(Save_Data_Start_Offset + 0x71880, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x71880 + 4).Take(0x20).ToArray()));
Write(Save_Data_Start_Offset + 0x718A4, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x718A4 + 4).Take(0xBE4).ToArray()));
Write(Save_Data_Start_Offset + 0x738D4, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x738D4 + 4).Take(0x16188).ToArray()));
}
Save_Writer.Write(Save_Type == SaveType.Doubutsu_no_Mori ? SaveDataManager.ByteSwap(Working_Save_Data) : Working_Save_Data); //Doubutsu no Mori is dword byteswapped
Save_Writer.Flush();
Save_File.Flush();
Save_Writer.Close();
Save_File.Close();
}
public void Write(int offset, dynamic data, bool reversed = false, int stringLength = 0)
{
Type Data_Type = data.GetType();
NewMainForm.Debug_Manager.WriteLine(string.Format("Writing Data{2} of type {0} to offset {1}", Data_Type.Name, "0x" + offset.ToString("X"), //recasting a value shows it as original type?
Data_Type.IsArray ? "" : " with value 0x" + (data.ToString("X"))), DebugLevel.Debug);
if (!Data_Type.IsArray)
{
if (Data_Type == typeof(byte))
Working_Save_Data[offset] = (byte)data;
else if (Data_Type == typeof(string))
{
byte[] String_Byte_Buff = ACString.GetBytes((string)data, stringLength);
Buffer.BlockCopy(String_Byte_Buff, 0, Working_Save_Data, offset, String_Byte_Buff.Length);
}
else
{
byte[] Byte_Array = BitConverter.GetBytes(data);
if (reversed)
Array.Reverse(Byte_Array);
Buffer.BlockCopy(Byte_Array, 0, Working_Save_Data, offset, Byte_Array.Length);
}
}
else
{
dynamic Data_Array = data;
if (Data_Type == typeof(byte[]))
for (int i = 0; i < Data_Array.Length; i++)
Working_Save_Data[offset + i] = Data_Array[i];
else
{
int Data_Size = Marshal.SizeOf(Data_Array[0]);
for (int i = 0; i < Data_Array.Length; i++)
{
byte[] Byte_Array = BitConverter.GetBytes(Data_Array[i]);
if (reversed)
Array.Reverse(Byte_Array);
Byte_Array.CopyTo(Working_Save_Data, offset + i * Data_Size);
}
}
}
}
//Used for replacing instances of player/town names. Possibly other uses?
public void FindAndReplaceByteArray(int end, byte[] oldarr, byte[] newarr)
{
for (int i = Save_Data_Start_Offset; i < Save_Data_Start_Offset + end; i += 2) //Every? dword or larger is aligned
{
if (Enumerable.SequenceEqual(ReadByteArray(i, oldarr.Length), oldarr))
{
MessageBox.Show("Match found at offset: 0x" + i.ToString("X"));
Write(i, newarr, Is_Big_Endian);
}
}
}
public byte ReadByte(int offset)
{
return Working_Save_Data[offset];
}
public byte[] ReadByteArray(int offset, int count, bool reversed = false)
{
byte[] Data = new byte[count];
Buffer.BlockCopy(Working_Save_Data, offset, Data, 0, count);
if (reversed)
Array.Reverse(Data);
return Data;
}
public ushort ReadUInt16(int offset, bool reversed = false)
{
return BitConverter.ToUInt16(ReadByteArray(offset, 2, reversed), 0);
}
public ushort[] ReadUInt16Array(int offset, int count, bool reversed = false)
{
ushort[] Returned_Values = new ushort[count];
for (int i = 0; i < count; i++)
Returned_Values[i] = ReadUInt16(offset + i * 2, reversed);
return Returned_Values;
}
public uint ReadUInt32(int offset, bool reversed = false)
{
return BitConverter.ToUInt32(ReadByteArray(offset, 4, reversed), 0);
}
public uint[] ReadUInt32Array(int offset, int count, bool reversed = false)
{
uint[] Returned_Values = new uint[count];
for (int i = 0; i < count; i++)
Returned_Values[i] = ReadUInt32(offset + i * 4, reversed);
return Returned_Values;
}
public ulong ReadUInt64(int offset, bool reversed = false)
{
return BitConverter.ToUInt64(ReadByteArray(offset, 8, reversed), 0);
}
public string ReadString(int offset, int length)
{
return new ACString(ReadByteArray(offset, length), Save_Type).Trim();
}
public string[] ReadStringArray(int offset, int length, int count) //Only useful for strings of matching lengths, possibly "fix" this in the future
{
string[] String_Array = new string[count];
for (int i = 0; i < count; i++)
String_Array[i] = ReadString(offset + i * length, length);
return String_Array;
}
public string[] ReadStringArrayWithVariedLengths(int offset, int count, byte endCharByte, int maxLength = 10) // ^^ Fixed it ^^
{
string[] String_Array = new string[count];
int lastOffset = 0;
for (int i = 0; i < count; i++)
{
byte lastChar = 0;
int idx = 0;
while (lastChar != endCharByte && idx < maxLength)
{
lastChar = ReadByte(offset + lastOffset + idx);
idx++;
}
String_Array[i] = ReadString(offset + lastOffset, idx);
lastOffset += idx;
}
return String_Array;
}
}
}

362
Classes/StringUtil.cs Normal file
View file

@ -0,0 +1,362 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace ACSE
{
public static class StringUtil
{
public static readonly Dictionary<byte, string> AC_CharacterDictionary = new Dictionary<byte, string>()
{
{0x90, "" },
{0xCD, "\n" },
{0x2A, "~" },
{0xD0, ";" },
{0xD4, "⚷" },
{0xD1, "#" },
{0x85, "•" },
{0xA2, "Æ" },
{0xA0, "¯" },
{0xAE, "/" },
{0x97, "¦" },
{0xC0, "×" },
{0xC1, "÷" },
{0xA5, "»" },
{0xA6, "«" },
{0xAC, "∋" },
{0xAD, "∈" },
{0xB4, "+" },
{0x1D, "ß" },
{0x1E, "Þ" },
{0x86, "ð" },
{0x98, "§" },
{0x9B, "‖" },
{0x9C, "µ" },
{0xA1, "¬" },
{0x2B, "♥" },
{0xB9, "★" },
{0x2F, "♪" },
{0x3B, "🌢" },
{0x5C, "💢" },
{0xB8, "🍀"},
{0xC6, "🐾" },
{0xB6, "♂" },
{0xB7, "♀" },
{0xAF, "∞" },
{0xB0, "○" },
{0xB1, "🗙" },
{0xB2, "□" },
{0xB3, "△" },
{0xBA, "💀" },
{0xBB, "😮" },
{0xBC, "😄" },
{0xBD, "😣" },
{0xBE, "😠" },
{0xBF, "😃" },
{0xA7, "☀" },
{0xA8, "☁" },
{0xA9, "☂" },
{0xAB, "☃" },
{0xAA, "🌬" }, //Wind...
{0xB5, "⚡" },
{0xC2, "🔨" }, //Hammer??
{0xC3, "🎀" }, //Not sure wtf this is (put it as ribbon)
{0xC4, "✉" },
{0xC7, "🐶" },
{0xC8, "🐱" },
{0xC9, "🐰" },
{0xCA, "🐦" },
{0xCB, "🐮" },
{0xCC, "🐷" },
{0xC5, "💰" },
{0xCE, "🐟" },
{0xCF, "🐞" },
{0x7B, "è" },
{0x7C, "é" },
{0x7D, "ê" },
{0x7E, "ë" },
{0x93, "ý" },
{0x94, "ÿ" },
{0x8E, "ù" },
{0x8F, "ú" },
{0x91, "û" },
{0x92, "ü" },
{0x81, "ì" },
{0x82, "í" },
{0x83, "î" },
{0x84, "ï" },
{0x88, "ò" },
{0x89, "ó" },
{0x8A, "ô" },
{0x8B, "õ" },
{0x8C, "ö" },
{0x1F, "à" },
{0x23, "á" },
{0x24, "â" },
{0x5B, "ã" },
{0x5D, "ä" },
{0x5E, "å" },
{0x09, "È" },
{0x0A, "É" },
{0x0B, "Ê" },
{0x0C, "Ë" },
{0x96, "Ý" },
{0x19, "Ù" },
{0x1A, "Ú" },
{0x1B, "Û" },
{0x1C, "Ü" },
{0x0D, "Ì" },
{0x0E, "Í" },
{0x0F, "Î" },
{0x10, "Ï" },
{0x13, "Ò" },
{0x14, "Ó" },
{0x15, "Ô" },
{0x16, "Õ" },
{0x17, "Ö" },
{0x02, "Ä" },
{0x03, "À" },
{0x04, "Á" },
{0x05, "Â" },
{0x06, "Ã" },
{0x07, "Å" },
{0x11, "Ð" },
{0x08, "Ç" },
{0x12, "Ñ" },
{0x87, "ñ" },
{0x60, "ç" },
{0x95, "þ" },
{0x01, "¿" },
{0xA4, "„" },
{0xA3, "æ" }
};
public static readonly Dictionary<byte, string> WW_CharacterDictionary = new Dictionary<byte, string>()
{
{ 0x41, "Œ"},
{ 0x44, "œ"},
{ 0x47, "À"},
{ 0x48, "Á"},
{ 0x49, "Â"},
{ 0x4B, "Ä"},
{ 0x4E, "Ç"},
{ 0x4F, "È"},
{ 0x50, "É"},
{ 0x51, "Ê"},
{ 0x52, "Ë"},
{ 0x53, "Ì"},
{ 0x54, "Í"},
{ 0x55, "Î"},
{ 0x56, "Ï"},
{ 0x58, "Ñ"},
{ 0x59, "Ò"},
{ 0x5A, "Ó"},
{ 0x5B, "Ô"},
{ 0x5D, "Ö"},
{ 0x5F, "Ù"},
{ 0x60, "Ú"},
{ 0x61, "Û"},
{ 0x62, "Ü"},
{ 0x65, "ß"},
{ 0x66, "à"},
{ 0x67, "á"},
{ 0x68, "â"},
{ 0x6A, "ä"},
{ 0x6D, "ç"},
{ 0x6E, "è"},
{ 0x6F, "é"},
{ 0x70, "ê"},
{ 0x71, "ë"},
{ 0x72, "ì"},
{ 0x73, "í"},
{ 0x74, "î"},
{ 0x75, "ï"},
{ 0x77, "ñ"},
{ 0x78, "ò"},
{ 0x79, "ó"},
{ 0x7A, "ô"},
{ 0x7C, "ö"},
{ 0x7E, "ù"},
{ 0x7F, "ú"},
{ 0x80, "û"},
{ 0x81, "ü"},
{ 0x85, " "}, // "(space)"
{ 0x86, " "}, //breaking space
{ 0x87, "!" },
//{ 0x87, "\n"},
{ 0x8C, "&" },
{ 0x8D, "\"" }, // single quote
{ 0x8E, "(" },
{ 0x8F, ")" },
{ 0x91, "+" },
{ 0x92, "," },
{ 0x93, "-" },
{ 0x94, "." },
{ 0x96, ":" },
{ 0x97, ";" },
{ 0x98, "<" },
{ 0x99, "=" },
{ 0x9A, ">" },
{ 0x9B, "?" },
{ 0x9C, "@" },
{ 0x9D, "[" },
{ 0x9F, "]" },
{ 0xA1, "_" },
{ 0xA6, "~" },
{ 0xA7, "€"},
{ 0xB1, "'" },
{ 0xB3, "\"" },
{ 0xBB, "¡"}, //(i)??
{ 0xBC, "¢"},
{ 0xBD, "£"},
{ 0xD1, "•"},
{ 0xD9, "¿"},
{ 0xDA, "×"},
{ 0xDB, "÷"},
{ 0xDC, "💧"},
{ 0xDD, "★"},
{ 0xDE, "❤"},
{ 0xDF, "♪"},
};
public static int StringToMaxChars(string s)
{
TextElementEnumerator t = StringInfo.GetTextElementEnumerator(s);
int size = 0;
int chars = 0;
while (t.MoveNext())
{
chars++;
size += Encoding.UTF8.GetBytes(((string)(t.Current)).ToCharArray()).Length;
}
return size;
}
public static byte[] Fix_Wild_World_String(byte[] mangled_String_Bytes)
{
byte[] Fixed_String_Bytes = new byte[mangled_String_Bytes.Length];
for (int i = 0; i < mangled_String_Bytes.Length; i++)
{
byte Mangled_Char = mangled_String_Bytes[i];
if (Mangled_Char > 0 && Mangled_Char <= 0x1A)
Fixed_String_Bytes[i] = (byte)(Mangled_Char + 0x40);
else if (Mangled_Char >= 0x1B && Mangled_Char <= 0x34)
Fixed_String_Bytes[i] = (byte)(Mangled_Char + 0x46);
else if (Mangled_Char >= 0x35 && Mangled_Char <= 0x3E)
Fixed_String_Bytes[i] = (byte)(Mangled_Char - 0x5); //Char - 0x35 + 0x30 (0)
}
return Fixed_String_Bytes;
}
public static byte[] To_Wild_World_String(byte[] string_Bytes)
{
byte[] WW_String_Bytes = new byte[string_Bytes.Length];
for (int i = 0; i < WW_String_Bytes.Length; i++)
{
byte Char = string_Bytes[i];
if (Char > 0x40 && Char <= 0x5A)
WW_String_Bytes[i] = (byte)(Char - 0x40);
else if (Char >= 0x61 && Char <= 0x7A)
WW_String_Bytes[i] = (byte)(Char - 0x46);
else if (Char >= 0x30 && Char <= 0x39)
WW_String_Bytes[i] = (byte)(Char + 0x5);
else if (WW_CharacterDictionary.Values.Contains(Encoding.ASCII.GetString(new byte[1] { Char })))
WW_String_Bytes[i] = WW_CharacterDictionary.First(x => x.Value == Encoding.ASCII.GetString(new byte[1] { Char })).Key;
}
return WW_String_Bytes;
}
}
public class ACString
{
byte[] String_Bytes;
static SaveType Save_Type; //This won't be changing during our save, so a static cast is fine
public string String = "";
static Dictionary<byte, string> Char_Dictionary;
public ACString(byte[] stringBuffer, SaveType saveType = SaveType.Animal_Crossing)
{
Save_Type = saveType;
String_Bytes = stringBuffer;
Char_Dictionary = saveType == SaveType.Animal_Crossing ? StringUtil.AC_CharacterDictionary
: (saveType == SaveType.Wild_World ? StringUtil.WW_CharacterDictionary : null);
if (saveType == SaveType.Animal_Crossing || saveType == SaveType.Wild_World)
foreach (byte b in stringBuffer)
if (Char_Dictionary != null && Char_Dictionary.ContainsKey(b))
String += Char_Dictionary[b];
else
String += Encoding.UTF8.GetString(saveType == SaveType.Wild_World ? StringUtil.Fix_Wild_World_String(new byte[1] { b }) : new byte[1] { b });
else if (saveType == SaveType.City_Folk)
for (int i = 0; i < stringBuffer.Length; i += 2)
String += Encoding.Unicode.GetString(stringBuffer.Skip(i).Take(2).Reverse().ToArray());
else if (saveType == SaveType.New_Leaf || saveType == SaveType.Welcome_Amiibo)
{
String = Encoding.Unicode.GetString(stringBuffer);
}
}
public static byte[] GetBytes(string String, int maxSize = 0)
{
if (Save_Type == SaveType.Animal_Crossing)
{
byte[] returnedString = new byte[maxSize > 0 ? maxSize : String.Length];
TextElementEnumerator t = StringInfo.GetTextElementEnumerator(String);
int i = 0;
while (t.MoveNext() && i < returnedString.Length)
{
if (Char_Dictionary.ContainsValue((string)t.Current))
returnedString[i] = Char_Dictionary.FirstOrDefault(o => o.Value == (string)t.Current).Key;
else
returnedString[i] = Encoding.UTF8.GetBytes(new char[1] { String[t.ElementIndex] })[0];
i++;
}
for (int x = 0; x < returnedString.Length; x++)
if (returnedString[x] == 0)
returnedString[x] = 0x20;
return returnedString;
}
else if (Save_Type == SaveType.Wild_World)
{
byte[] String_Buffer = StringUtil.To_Wild_World_String(Encoding.UTF8.GetBytes(String));
if (maxSize > 0)
Array.Resize(ref String_Buffer, maxSize);
return String_Buffer;
}
else if (Save_Type == SaveType.City_Folk)
{
byte[] String_Buffer = new byte[maxSize > 0 ? maxSize : String.Length * 2]; //Characters are now unicode
byte[] String_Bytes = Encoding.Unicode.GetBytes(String);
for (int i = 0; i < String_Bytes.Length; i+=2)
Buffer.BlockCopy(String_Bytes.Skip(i).Take(2).Reverse().ToArray(), 0, String_Buffer, i, 2);
return String_Buffer;
}
else if (Save_Type == SaveType.New_Leaf || Save_Type == SaveType.Welcome_Amiibo)
{
byte[] String_Buffer = Encoding.Unicode.GetBytes(String);
if (maxSize > 0)
Array.Resize(ref String_Buffer, maxSize);
return String_Buffer;
}
else
{
NewMainForm.Debug_Manager.WriteLine(string.Format("StringUtil was passed an unknown SaveType enum. Received Type: {0}", Save_Type.ToString()), DebugLevel.Error);
return null;
}
}
public string Trim()
{
return String.Trim(' ');
}
public string Clean()
{
string Cleaned_String = Regex.Replace(String, "[\n]{3,}", "\n\n");
return Regex.Replace(Cleaned_String.Trim(' '), "[ ]{2,}", " ");
}
}
}

23
Classes/Utility.cs Normal file
View file

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ACSE
{
public static class Utility
{
public static void Scan_For_NL_Int32()
{
if (NewMainForm.Save_File != null && (NewMainForm.Save_File.Save_Type == SaveType.New_Leaf || NewMainForm.Save_File.Save_Type == SaveType.Welcome_Amiibo))
{
for (int i = 0; i < NewMainForm.Save_File.Working_Save_Data.Length; i += 4)
{
NL_Int32 Possible_NL_Int32 = new NL_Int32(NewMainForm.Save_File.ReadUInt32(i), NewMainForm.Save_File.ReadUInt32(i + 4));
if (Possible_NL_Int32.Valid)
System.Windows.Forms.MessageBox.Show(string.Format("Found Valid NL_Int32 at offset 0x{0} | Value: {1}", i.ToString("X"), Possible_NL_Int32.Value));
}
}
}
}
}

736
Classes/VillagerData.cs Normal file
View file

@ -0,0 +1,736 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Globalization;
namespace ACSE
{
class VillagerData
{
public static Dictionary<ushort, string> WA_Special_Villagers = new Dictionary<ushort, string>
{
{0x1000, "Copper"},
{0x1001, "Booker"},
{0x1002, "Jingle"},
{0x1003, "Jack"},
{0x1004, "Zipper"},
{0x1005, "Blanca"},
{0x1006, "Pavé"},
{0x1007, "Chip"},
{0x1008, "Nat"},
{0x1009, "Franklin"},
{0x100A, "Joan"},
{0x100B, "Wendell"},
{0x100C, "Pascal"},
{0x100D, "Gulliver"},
{0x100E, "Saharah"},
{0x2000, "Isabelle (1)"},
{0x2001, "Digby"},
{0x2002, "Reese"},
{0x2003, "Cyrus"},
{0x2004, "Tom Nook"},
{0x2005, "Lottie"},
{0x2006, "Mabel"},
{0x2007, "K.K. Slider"},
{0x2008, "Kicks"},
{0x2009, "Resetti"},
{0x200A, "Celeste"},
{0x200B, "Blathers"},
{0x200C, "Rover"},
{0x200D, "Timmy"},
{0x200E, "Kapp'n"},
{0x200F, "Wisp"},
{0x2010, "Isabelle (2)"}
};
public static BindingSource GetCaravanBindingSource()
{
Dictionary<ushort, SimpleVillager> WA_Database = VillagerInfo.GetVillagerDatabase(SaveType.Welcome_Amiibo);
if (WA_Database != null)
{
foreach (var v in WA_Special_Villagers)
{
SimpleVillager SpecialVillager = new SimpleVillager();
SpecialVillager.Villager_ID = v.Key;
SpecialVillager.Name = v.Value;
WA_Database.Add(v.Key, SpecialVillager);
}
return new BindingSource(WA_Database, null);
}
return new BindingSource(WA_Special_Villagers, null);
}
public static Dictionary<ushort, string> Villagers = new Dictionary<ushort, string>()
{
};
public static List<KeyValuePair<ushort, string>> VillagerDatabase = new List<KeyValuePair<ushort, string>>();
public static void CreateVillagerDatabase()
{
foreach (KeyValuePair<ushort, string> k in Villagers)
VillagerDatabase.Add(k);
}
public static string[] Personalities = new string[6]
{
"Lazy", "Normal", "Peppy", "Jock", "Cranky", "Snooty"
};
public static string GetVillagerName(ushort villagerId)
{
if (Villagers.ContainsKey(villagerId))
return Villagers[villagerId];
return villagerId == 0x0 ? "No Villager" : "Unknown";
}
public static string GetVillagerPersonality(int type)
{
return type < 6 ? Personalities[type] : "Lazy";
}
public static int GetVillagerPersonalityID(string personality)
{
return Array.IndexOf(Personalities, personality) > -1 ? Array.IndexOf(Personalities, personality) : 0;
}
public static ushort GetVillagerID(string villagerName)
{
if (Villagers.ContainsValue(villagerName))
return Villagers.FirstOrDefault(x => x.Value == villagerName).Key;
return 0xE000;
}
public static ushort GetVillagerIdByIndex(int i)
{
if (Villagers.Count > i)
return Villagers.Keys.ElementAt(i);
return 0xE000;
}
}
public class Villager
{
public ushort ID = 0;
public ushort TownIdentifier = 0;
public string Name = "";
public string Personality = "";
public byte PersonalityID = 0;
public int Index = 0;
public string Catchphrase = "";
public bool Exists = false;
public bool Modified = false;
public Item Shirt;
public byte[] House_Coords = new byte[4]; //X-Acre, Y-Acre, Y-Position, X-Position - 1 (This is actually the location of their sign, also dictates map location)
public Villager_Player_Entry[] Villager_Player_Entries = new Villager_Player_Entry[7];
public int Offset = 0;
public Villager(int idx)
{
Index = idx;
//Offset = Index == 16 ? MainForm.Islander_Offset : MainForm.VillagerData_Offset + (Index - 1) * 0x988;
ID = DataConverter.ReadUShort(Offset);
TownIdentifier = DataConverter.ReadUShort(Offset + 2);
Name = VillagerData.GetVillagerName(ID);
PersonalityID = DataConverter.ReadDataRaw(Offset + 0xD, 1)[0];
Personality = VillagerData.GetVillagerPersonality(PersonalityID);
Catchphrase = DataConverter.ReadString(Offset + 0x89D, 10).Trim();
Shirt = new Item(DataConverter.ReadUShort(Offset + 0x8E4));
House_Coords = DataConverter.ReadDataRaw(Offset + 0x899, 4); //Could make this WorldCoords class if used for other things
//House_Coords[2] = (byte)(House_Coords[2] + 1);
//House_Coords[3] = (byte)(House_Coords[3] + 1); //X-Position is the position of the Villager Name Sign, which is to the left of the house object, so we add one.
Exists = ID != 0x0000 && ID != 0xFFFF;
for (int i = 0; i < 7; i++)
{
int Entry_Offset = Offset + 0x10 + (i * 0x138); //Offset + 16 data bytes + entrynum * entrysize
uint Player_ID = DataConverter.ReadUInt(Entry_Offset + 0x10);
if (Player_ID < 0xFFFFFFFF && Player_ID >= 0xF0000000)
Villager_Player_Entries[i] = new Villager_Player_Entry(DataConverter.ReadDataRaw(Entry_Offset, 0x138), Entry_Offset);
}
}
public void Write()
{
//House_Coords[2] = (byte)(House_Coords[2] - 1);
//House_Coords[3] = (byte)(House_Coords[3] - 1);
DataConverter.Write(Offset, ID);
DataConverter.Write(Offset + 2, TownIdentifier);
//DataConverter.WriteString(Offset + 4, DataConverter.ReadString(MainForm.Town_Name_Offset, 8).Trim(), 8); //Set town name
DataConverter.WriteByte(Offset + 0xC, Index == 16 ? (byte)0xFF : (byte)(ID & 0x00FF)); //Normally same as villager identifier, but is 0xFF for islanders. This is likely the byte for what AI the villager will use.
DataConverter.WriteByte(Offset + 0xD, PersonalityID);
DataConverter.WriteString(Offset + 0x89D, Catchphrase, 10);
DataConverter.WriteByteArray(Offset + 0x899, House_Coords, false);
if (Shirt != null)
DataConverter.Write(Offset + 0x8E4, Shirt.ItemID);
if (!Exists && Modified)
{
DataConverter.WriteByteArray(Offset + 0x8EB, new byte[] { 0xFF, 0x01 }, false); //This byte might be the met flag. Setting it just in case
Exists = true;
if (Index < 16)
Add_House();
}
foreach (Villager_Player_Entry Entry in Villager_Player_Entries)
if (Entry != null && Entry.Exists)
Entry.Write(); //Update Player Entries
Modified = false;
//Second byte here is always a random number. This could be responsible for the Villager's AI, but I'm not sure. Just writing it for good measure.
//If the Villager's house location is out of bounds, (or just left 0xFFFF) the game will pick a random signboard as the new house location and write it on load.
}
public void Delete()
{
if (Index < 16) //Don't delete islander
{
//if (Properties.Settings.Default.ModifyVillagerHouse)
//Remove_House();
ID = 0;
TownIdentifier = 0xFFFF;
PersonalityID = 6;
Catchphrase = "";
House_Coords = new byte[4] { 0xFF, 0xFF, 0xFF, 0xFF };
Shirt = new Item(0);
Exists = false;
Modified = false;
}
}
public void Remove_House()
{
ushort House_ID = BitConverter.ToUInt16(new byte[] { (byte)(ID & 0x00FF), 0x50 }, 0);
/*ushort[] World_Buffer = DataConverter.ReadUShortArray(MainForm.AcreData_Offset, MainForm.AcreData_Size / 2);
for (int i = 0; i < World_Buffer.Length; i++)
{
if (World_Buffer[i] == House_ID)
{
for (int x = i - 17; x < i - 14; x++) //First Row
World_Buffer[x] = 0;
for (int x = i - 1; x < i + 2; x++) //Middle Row
World_Buffer[x] = 0;
for (int x = i + 15; x < i + 18; x++) //Final Row
World_Buffer[x] = 0;
World_Buffer[i] = BitConverter.ToUInt16(new byte[] { (byte)(new Random().Next(0x10, 0x25)), 0x58 }, 0); //New Signboard to replace house
//This is akin to actual game behavior
}
}*/
//DataConverter.Write(MainForm.AcreData_Offset, World_Buffer);
}
public void Add_House()
{
ushort House_ID = BitConverter.ToUInt16(new byte[] { (byte)(ID & 0x00FF), 0x50 }, 0);
/*ushort[] World_Buffer = DataConverter.ReadUShortArray(MainForm.AcreData_Offset, MainForm.AcreData_Size / 2);
if (House_Coords[0] > 5 || House_Coords[1] > 6 || House_Coords[2] > 15 || House_Coords[3] > 15) //Houses can't be on edge of acres
return;
int Position = (House_Coords[0] - 1) * 256 + (House_Coords[1] - 1) * 1280 + (House_Coords[2]) + (House_Coords[3] - 1) * 16; //X Acre + Y Acre + X Pos + Y Pos
if (Position > 0x1E00) //7,680 item spots per town (minus island acres) (5 * 6 * 16^2)
return;
for (int x = Position - 17; x < Position - 14; x++) //First Row
World_Buffer[x] = 0xFFFF;
for (int x = Position - 1; x < Position + 2; x++) //Middle Row
World_Buffer[x] = 0xFFFF;
for (int x = Position + 15; x < Position + 18; x++) //Final Row
World_Buffer[x] = 0xFFFF;
World_Buffer[Position] = House_ID;
World_Buffer[Position + 15] = 0xA012; //Add Nameplate
DataConverter.Write(MainForm.AcreData_Offset, World_Buffer);*/
}
public Villager_Player_Entry[] Get_Player_Entries(uint Matching_Player_ID)
{
return Villager_Player_Entries.Where(Entry => Entry.Player_ID == Matching_Player_ID).ToArray();
}
}
/*
Animal Crossing: Population Growing Villager Player Entry Structure:
Villager Player Entry Structure (Size: 0x138)
Player Name: 0x000 - 0x007
Town Name: 0x008 - 0x00F
Player ID: 0x010 - 0x013
Met Date: 0x014 - 0x01B
Met Town Name: 0x01C - 0x023
Met Town ID: 0x024 - 0x025
Padding??: 0x026 - 0x027
Unknown Data: 0x028 - 0x02F
Friendship: 0x030 (Min = 0 (1), Max = 7F (128))
Unknown Bytes: 0x031 - 0x032
Saved Message: 0x033? - 0x138
*/
public class Villager_Player_Entry
{
public bool Exists = false;
public int Offset;
//Struct Start
public string Player_Name;
public string Player_Town_Name;
public uint Player_ID;
public ACDate Met_Date;
public string Met_Town_Name;
public ushort Met_Town_ID;
public byte[] Garbage = new byte[8]; //I have no idea wtf these are for. Might investigate some day.
public sbyte Friendship;
public Mail Saved_Letter; //Going to have to change this to a custom class, as it strips most mail header data (Length is 0x100? Message part is still 0xF8)
//
public Villager_Player_Entry(byte[] entryData, int offset)
{
Exists = true;
Offset = offset;
byte[] playerNameBytes = new byte[8], playerTownName = new byte[8], metTownName = new byte[8], metDate = new byte[8], playerId = new byte[4], metTownId = new byte[2];
Buffer.BlockCopy(entryData, 0, playerNameBytes, 0, 8);
Buffer.BlockCopy(entryData, 8, playerTownName, 0, 8);
Buffer.BlockCopy(entryData, 0x1C, metTownName, 0, 8);
Buffer.BlockCopy(entryData, 0x10, playerId, 0, 4);
Buffer.BlockCopy(entryData, 0x14, metDate, 0, 8);
Buffer.BlockCopy(entryData, 0x24, metTownId, 0, 2);
Array.Reverse(playerId);
Array.Reverse(metTownId);
Player_Name = new ACString(playerNameBytes).Trim();
Player_Town_Name = new ACString(playerTownName).Trim();
Met_Town_Name = new ACString(metTownName).Trim();
Met_Date = new ACDate(metDate);
Player_ID = BitConverter.ToUInt32(playerId, 0);
Met_Town_ID = BitConverter.ToUInt16(metTownId, 0);
Friendship = (sbyte)entryData[0x30];
}
public void Max_Friendship()
{
Friendship = 0x7F;
}
public void Write()
{
//Player Name is handled by renaming the player
//DataConverter.WriteByteArray(Offset + 0x8, DataConverter.ReadDataRaw(MainForm.Town_Name_Offset, 8)); //Update Town Name
//if (DataConverter.ReadUShort(8) == Met_Town_ID)
// DataConverter.WriteByteArray(Offset + 0x1C, DataConverter.ReadDataRaw(MainForm.Town_Name_Offset, 8)); //Update Met Town Name
}
}
public struct VillagerOffsets
{
public int Villager_ID;
public int Catchphrase;
public int CatchphraseSize;
public int Nicknames;
public int NicknamesSize;
public int NicknamesCount;
public int Personality;
public int Town_ID;
public int Town_Name;
public int Town_NameSize;
public int Shirt;
public int Umbrella;
public int Song;
public int Carpet;
public int Wallpaper;
public int Furniture;
public int FurnitureCount;
public int House_Coordinates;
public int House_CoordinatesSize;
public int Status;
}
//Rename when VillagerData class is removed
public struct VillagerDataStruct
{
public ushort Villager_ID;
public string Catchphrase;
public string[] Nicknames;
public byte Personality;
public ushort Town_ID;
public string Town_Name;
public Item Shirt;
public Item Umbrella;
public Item Song;
public Item Carpet;
public Item Wallpaper;
public Item[] Furniture;
public byte[] House_Coordinates; //Animal Crossing only?
public byte Status;
//Player Entries?
}
public static class VillagerInfo
{
public static VillagerOffsets AC_Villager_Offsets = new VillagerOffsets
{
Villager_ID = 0,
Town_ID = 2,
Town_Name = 4,
Town_NameSize = 8,
Personality = 0xD,
House_Coordinates = 0x899,
House_CoordinatesSize = 4,
Catchphrase = 0x89D,
CatchphraseSize = 0xA,
Shirt = 0x8E4,
Status = -1, //Research
Umbrella = -1, //Research this as well
Furniture = -1, //No Furniture customization in AC
Carpet = -1,
Wallpaper = -1,
Nicknames = -1, //Inside of "Player Entries"
Song = -1,
//Add Player Entries (Relationships)
};
public static VillagerOffsets WW_Villager_Offsets = new VillagerOffsets
{
//0 = Relationships (0x68 bytes each)
//Pattern as well
Furniture = 0x6AC,
FurnitureCount = 0xA,
Personality = 0x6CA,
Villager_ID = 0x6CB,
Wallpaper = 0x6CC,
Carpet = 0x6CE,
Song = 0x6D0, //Check this
Shirt = 0x6EC,
Catchphrase = 0x6DE,
CatchphraseSize = 0xA,
//Finish rest of offsets
};
public static VillagerOffsets CF_Villager_Offsets = new VillagerOffsets
{
//Villagers in City Folk are interesting.
//The actual data structure is stored in the save file, allowing for customization of the entire villager.
//This includes name, textures, and what villager model it uses!
//That will mean a lot more work will have to go into this part of the villager editor, though.
//I'll have to finish it at a later date. Unfortunately, I can't find the source to NPC Tool, a tool that allowed all of these modifications to be done
//This means I'll probably have to reverse engineer the format myself
};
public static VillagerOffsets NL_Villager_Offsets = new VillagerOffsets
{
Villager_ID = 0,
Personality = 2,
Status = 0x24C4,
Catchphrase = 0x24A6,
CatchphraseSize = 0x16,
Town_Name = 0x24CE,
Town_NameSize = 0x12,
Town_ID = -1, // Research
Shirt = 0x244E,
Song = 0x2452,
Wallpaper = 0x2456,
Carpet = 0x245A,
Umbrella = 0x245E,
Furniture = 0x2462,
FurnitureCount = 16,
House_Coordinates = -1,
Nicknames = -1 //Research
};
public static VillagerOffsets WA_Villager_Offsets = new VillagerOffsets
{
Villager_ID = 0,
Personality = 2,
Status = 0x24E4,
Catchphrase = 0x24C6,
CatchphraseSize = 0x16,
Town_Name = 0x24CE,
Town_NameSize = 0x12,
Town_ID = -1, // Research
Shirt = 0x246E,
Song = 0x2472,
Wallpaper = 0x2476,
Carpet = 0x247A,
Umbrella = 0x247E,
Furniture = 0x2482,
FurnitureCount = 16,
House_Coordinates = -1,
Nicknames = -1 //Research
};
public static string[] AC_Personalities = new string[7]
{
"Normal (Female)", "Peppy (Female)", "Lazy (Male)", "Jock (Male)", "Cranky (Male)", "Snooty (Female)", "Not Set"
};
public static string[] WW_Personalities = new string[7]
{
"Lazy (Male)", "Jock (Male)", "Cranky (Male)", "Normal (Female)", "Peppy (Female)", "Snooty (Female)", "Not Set"
};
public static string[] NL_Personalities = new string[9]
{
"Lazy (Male)", "Jock (Male)", "Cranky (Male)", "Smug (Male)", "Normal (Female)", "Peppy (Female)", "Snooty (Female)", "Caring (Uchi) (Female)", "Not Set"
};
public static string[] GetPersonalities(SaveType Save_Type)
{
switch (Save_Type)
{
case SaveType.Animal_Crossing:
return AC_Personalities;
case SaveType.Wild_World:
return WW_Personalities;
case SaveType.New_Leaf:
return NL_Personalities;
case SaveType.Welcome_Amiibo:
return NL_Personalities;
}
return new string[0];
}
public static Dictionary<ushort, SimpleVillager> GetVillagerDatabase(SaveType Save_Type, string Language = "en")
{
Dictionary<ushort, SimpleVillager> Database = new Dictionary<ushort, SimpleVillager>();
StreamReader Contents = null;
string Database_Filename = NewMainForm.Assembly_Location + "\\Resources\\{0}_Villagers_" + Language + ".txt";
switch (Save_Type)
{
case SaveType.Animal_Crossing:
Database_Filename = string.Format(Database_Filename, "AC");
break;
case SaveType.Wild_World:
Database_Filename = string.Format(Database_Filename, "WW");
break;
case SaveType.New_Leaf:
Database_Filename = string.Format(Database_Filename, "NL");
break;
case SaveType.Welcome_Amiibo:
Database_Filename = string.Format(Database_Filename, "WA");
break;
}
try { Contents = File.OpenText(Database_Filename); }
catch (Exception e)
{
MessageBox.Show(string.Format("An error occured opening villager database file:\n\"{0}\"\nError Info:\n{1}", Database_Filename, e.Message));
return null;
}
string Line;
if (Save_Type == SaveType.New_Leaf || Save_Type == SaveType.Welcome_Amiibo)
{
while ((Line = Contents.ReadLine()) != null)
{
if (Line.Contains("0x"))
{
SimpleVillager Entry = new SimpleVillager();
string ID = Regex.Match(Line, @"ID = 0x....,").Value.Substring(7, 4);
Entry.Villager_ID = ushort.Parse(ID, NumberStyles.AllowHexSpecifier);
string Name_Str = Regex.Match(Line, @"Name = .+").Value.Substring(7);
Entry.Name = Name_Str.Substring(0, Name_Str.IndexOf(','));
string Personality = Regex.Match(Line, @"Personality = .").Value;
Entry.Personality = byte.Parse(Personality.Substring(Personality.Length - 1, 1));
Database.Add(Entry.Villager_ID, Entry);
//MessageBox.Show("ID: " + Entry.Villager_ID.ToString("X4") + " | Name: " + Entry.Name + " | Personality: " + Entry.Personality);
}
}
}
else if (Save_Type == SaveType.Wild_World)
{
while ((Line = Contents.ReadLine()) != null)
{
if (Line.Contains("0x"))
{
SimpleVillager Entry = new SimpleVillager();
Entry.Villager_ID = ushort.Parse(Line.Substring(2, 2), NumberStyles.AllowHexSpecifier);
Entry.Name = Line.Substring(6);
Database.Add(Entry.Villager_ID, Entry);
}
}
}
else if (Save_Type == SaveType.Animal_Crossing)
{
while ((Line = Contents.ReadLine()) != null)
{
if (Line.Contains("0x"))
{
SimpleVillager Entry = new SimpleVillager();
Entry.Villager_ID = ushort.Parse(Line.Substring(2, 4), NumberStyles.AllowHexSpecifier);
Entry.Name = Line.Substring(8);
Database.Add(Entry.Villager_ID, Entry);
}
}
}
return Database;
}
public static VillagerOffsets GetVillagerInfo(SaveType Save_Type)
{
switch(Save_Type)
{
case SaveType.Animal_Crossing:
return AC_Villager_Offsets;
case SaveType.Wild_World:
return WW_Villager_Offsets;
case SaveType.New_Leaf:
return NL_Villager_Offsets;
case SaveType.Welcome_Amiibo:
return WA_Villager_Offsets;
}
return new VillagerOffsets { };
}
}
public class SimpleVillager
{
public ushort Villager_ID;
public byte Personality;
public string Name;
public string Catchphrase;
public Item Shirt;
public Item[] Furniture;
//public uint AI (Last bytes in NL Villagers?)
public override string ToString()
{
return Name ?? "Unknown";
}
}
public class NewVillager
{
public VillagerOffsets Offsets;
public VillagerDataStruct Data;
public int Index;
public int Offset;
public string Name;
public bool Exists = false;
private Save SaveData;
public NewVillager(int offset, int idx, Save save)
{
SaveData = save;
Index = idx;
Offset = offset;
Offsets = VillagerInfo.GetVillagerInfo(save.Save_Type);
if (save.Save_Type == SaveType.Wild_World)
Exists = SaveData.ReadByte(offset + Offsets.Villager_ID) != 0 && SaveData.ReadByte(offset + Offsets.Villager_ID) != 0xFF;
else
Exists = SaveData.ReadUInt16(offset + Offsets.Villager_ID, save.Is_Big_Endian) != 0 && SaveData.ReadUInt16(offset + Offsets.Villager_ID, save.Is_Big_Endian) != 0xFFFF;
object BoxedData = new VillagerDataStruct();
foreach (var Field in typeof(VillagerOffsets).GetFields(BindingFlags.Public | BindingFlags.Instance))
if (Field.GetValue(Offsets) != null && !Field.Name.Contains("Count") && !Field.Name.Contains("Size"))
if (typeof(VillagerDataStruct).GetField(Field.Name) != null)
{
if (Field.FieldType == typeof(int) && (int)Field.GetValue(Offsets) != -1)
{
Type FieldType = typeof(VillagerDataStruct).GetField(Field.Name).FieldType;
int DataOffset = Offset + (int)Field.GetValue(Offsets);
if (Field.Name == "Villager_ID" && save.Save_Type == SaveType.Wild_World) //Villager IDs are only a byte in WW
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, SaveData.ReadByte(DataOffset));
else if (FieldType == typeof(byte))
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, SaveData.ReadByte(DataOffset));
else if (FieldType == typeof(byte[]) && typeof(VillagerOffsets).GetField(Field.Name + "Count") != null)
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, SaveData.ReadByteArray(DataOffset,
(int)typeof(VillagerOffsets).GetField(Field.Name + "Count").GetValue(Offsets)));
else if (FieldType == typeof(ushort))
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, SaveData.ReadUInt16(DataOffset, SaveData.Is_Big_Endian));
else if (FieldType == typeof(ushort[]))
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, SaveData.ReadUInt16Array(DataOffset,
(int)typeof(VillagerOffsets).GetField(Field.Name + "Count").GetValue(Offsets), SaveData.Is_Big_Endian));
else if (FieldType == typeof(uint))
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, SaveData.ReadUInt32(DataOffset, SaveData.Is_Big_Endian));
else if (FieldType == typeof(string))
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, new ACString(SaveData.ReadByteArray(DataOffset,
(int)typeof(VillagerOffsets).GetField(Field.Name + "Size").GetValue(Offsets)), SaveData.Save_Type).Trim());
else if (FieldType == typeof(string[])) { }
//Add logic
else if (FieldType == typeof(Item))
if (save.Save_Type == SaveType.New_Leaf || save.Save_Type == SaveType.Welcome_Amiibo)
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, new Item(SaveData.ReadUInt32(DataOffset, false)));
else
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, new Item(SaveData.ReadUInt16(DataOffset, SaveData.Is_Big_Endian)));
else if (FieldType == typeof(Item[]))
{
Item[] Collection = new Item[(int)typeof(VillagerOffsets).GetField(Field.Name + "Count").GetValue(Offsets)];
for (int i = 0; i < Collection.Length; i++)
{
if (save.Save_Type == SaveType.New_Leaf || save.Save_Type == SaveType.Welcome_Amiibo)
Collection[i] = new Item(SaveData.ReadUInt32(DataOffset + i * 4, false));
else
Collection[i] = new Item(SaveData.ReadUInt16(DataOffset + i * 2, SaveData.Is_Big_Endian));
}
typeof(VillagerDataStruct).GetField(Field.Name).SetValue(BoxedData, Collection);
}
}
}
Data = (VillagerDataStruct)BoxedData;
}
public override string ToString()
{
return Name ?? "Unknown";
}
public void Write()
{
//MessageBox.Show(string.Format("Writing Villager #{0} with data offset of 0x{1}", Index, Offset.ToString("X")));
Type VillagerOffsetData = typeof(VillagerOffsets);
Type VillagerDataType = typeof(VillagerDataStruct);
foreach (var Field in VillagerOffsetData.GetFields(BindingFlags.Public | BindingFlags.Instance))
{
if (Field.GetValue(Offsets) != null && !Field.Name.Contains("Count") && !Field.Name.Contains("Size"))
{
if (VillagerDataType.GetField(Field.Name) != null)
{
if (Field.FieldType == typeof(int) && (int)Field.GetValue(Offsets) != -1)
{
Type FieldType = VillagerDataType.GetField(Field.Name).FieldType;
int DataOffset = Offset + (int)Field.GetValue(Offsets);
//MessageBox.Show("Field Name: " + Field.Name + " | Data Offset: " + DataOffset.ToString("X"));
if (Field.Name == "Villager_ID")
{
if (SaveData.Save_Type == SaveType.Wild_World)
{
SaveData.Write(DataOffset, Convert.ToByte(VillagerDataType.GetField(Field.Name).GetValue(Data)));
}
else //Might not encompass City Folk
{
SaveData.Write(DataOffset, (ushort)VillagerDataType.GetField(Field.Name).GetValue(Data), SaveData.Is_Big_Endian);
}
}
else if (FieldType == typeof(string))
{
SaveData.Write(DataOffset, ACString.GetBytes((string)VillagerDataType.GetField(Field.Name).GetValue(Data),
(int)VillagerOffsetData.GetField(Field.Name + "Size").GetValue(Offsets)));
}
else if (FieldType == typeof(byte))
{
SaveData.Write(DataOffset, (byte)VillagerDataType.GetField(Field.Name).GetValue(Data));
}
else if (FieldType == typeof(ushort))
{
SaveData.Write(DataOffset, (ushort)VillagerDataType.GetField(Field.Name).GetValue(Data), SaveData.Is_Big_Endian);
}
else if (FieldType == typeof(Item))
{
if (SaveData.Save_Type == SaveType.New_Leaf || SaveData.Save_Type == SaveType.Welcome_Amiibo)
{
SaveData.Write(DataOffset, ItemData.EncodeItem((Item)VillagerDataType.GetField(Field.Name).GetValue(Data)), SaveData.Is_Big_Endian);
}
else
{
SaveData.Write(DataOffset, ((Item)VillagerDataType.GetField(Field.Name).GetValue(Data)).ItemID, SaveData.Is_Big_Endian);
}
}
}
}
}
}
// Special case here, since Villager_Data_Start + 0xC is always the same as the villager's ID. (Lower byte)
// TODO: Add check to see if the villager is an islander. If they are, use 0xFF instead.
if (SaveData.Save_Type == SaveType.Animal_Crossing)
{
SaveData.Write(Offset + 0xC, (byte)Data.Villager_ID);
}
// TODO: Add House Coordinate Saving/Updating (Also automatic placing/removing??) for the GC version
}
}
}

170
Forms/AboutBox2.Designer.cs generated Normal file
View file

@ -0,0 +1,170 @@
namespace ACSE
{
partial class AboutBox1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutBox1));
this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
this.logoPictureBox = new System.Windows.Forms.PictureBox();
this.labelProductName = new System.Windows.Forms.Label();
this.labelVersion = new System.Windows.Forms.Label();
this.labelCopyright = new System.Windows.Forms.Label();
this.okButton = new System.Windows.Forms.Button();
this.labelCompanyName = new System.Windows.Forms.Label();
this.tableLayoutPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit();
this.SuspendLayout();
//
// tableLayoutPanel
//
this.tableLayoutPanel.ColumnCount = 2;
this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33F));
this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 67F));
this.tableLayoutPanel.Controls.Add(this.logoPictureBox, 0, 0);
this.tableLayoutPanel.Controls.Add(this.labelProductName, 1, 0);
this.tableLayoutPanel.Controls.Add(this.labelVersion, 1, 1);
this.tableLayoutPanel.Controls.Add(this.labelCopyright, 1, 2);
this.tableLayoutPanel.Controls.Add(this.okButton, 1, 5);
this.tableLayoutPanel.Controls.Add(this.labelCompanyName, 1, 3);
this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel.Location = new System.Drawing.Point(9, 9);
this.tableLayoutPanel.Name = "tableLayoutPanel";
this.tableLayoutPanel.RowCount = 6;
this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F));
this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F));
this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F));
this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 43.70861F));
this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 5.298013F));
this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20.5298F));
this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel.Size = new System.Drawing.Size(417, 151);
this.tableLayoutPanel.TabIndex = 0;
//
// logoPictureBox
//
this.logoPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("logoPictureBox.Image")));
this.logoPictureBox.Location = new System.Drawing.Point(3, 3);
this.logoPictureBox.Name = "logoPictureBox";
this.tableLayoutPanel.SetRowSpan(this.logoPictureBox, 6);
this.logoPictureBox.Size = new System.Drawing.Size(128, 128);
this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.logoPictureBox.TabIndex = 12;
this.logoPictureBox.TabStop = false;
//
// labelProductName
//
this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelProductName.Location = new System.Drawing.Point(143, 0);
this.labelProductName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0);
this.labelProductName.MaximumSize = new System.Drawing.Size(0, 17);
this.labelProductName.Name = "labelProductName";
this.labelProductName.Size = new System.Drawing.Size(271, 15);
this.labelProductName.TabIndex = 19;
this.labelProductName.Text = "ACSE\r\n";
this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// labelVersion
//
this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelVersion.Location = new System.Drawing.Point(143, 15);
this.labelVersion.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0);
this.labelVersion.MaximumSize = new System.Drawing.Size(0, 17);
this.labelVersion.Name = "labelVersion";
this.labelVersion.Size = new System.Drawing.Size(271, 15);
this.labelVersion.TabIndex = 0;
this.labelVersion.Text = "Created By: Cuyler_36 (Jeremy Olsen)";
this.labelVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// labelCopyright
//
this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelCopyright.Location = new System.Drawing.Point(143, 30);
this.labelCopyright.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0);
this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 17);
this.labelCopyright.Name = "labelCopyright";
this.labelCopyright.Size = new System.Drawing.Size(271, 15);
this.labelCopyright.TabIndex = 21;
this.labelCopyright.Text = "Special Thanks:";
this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// okButton
//
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.okButton.Location = new System.Drawing.Point(339, 125);
this.okButton.Name = "okButton";
this.okButton.Size = new System.Drawing.Size(75, 23);
this.okButton.TabIndex = 24;
this.okButton.Text = "&OK";
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// labelCompanyName
//
this.labelCompanyName.AutoSize = true;
this.labelCompanyName.Location = new System.Drawing.Point(143, 45);
this.labelCompanyName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0);
this.labelCompanyName.Name = "labelCompanyName";
this.labelCompanyName.Size = new System.Drawing.Size(237, 52);
this.labelCompanyName.TabIndex = 22;
this.labelCompanyName.Text = "Kaphotics/kwsch - Item Bitmap Generation Code\r\nMarc Robledo - New Leaf Offsets/ID" +
"s\r\nVirus - City Folk Offets/IDs\r\nDsPet - Wild World Offsets/IDs";
this.labelCompanyName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// AboutBox1
//
this.AcceptButton = this.okButton;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(435, 169);
this.Controls.Add(this.tableLayoutPanel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "AboutBox1";
this.Padding = new System.Windows.Forms.Padding(9);
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "AboutBox1";
this.tableLayoutPanel.ResumeLayout(false);
this.tableLayoutPanel.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel;
private System.Windows.Forms.PictureBox logoPictureBox;
private System.Windows.Forms.Label labelProductName;
private System.Windows.Forms.Label labelVersion;
private System.Windows.Forms.Label labelCopyright;
private System.Windows.Forms.Label labelCompanyName;
private System.Windows.Forms.Button okButton;
}
}

104
Forms/AboutBox2.cs Normal file
View file

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
namespace ACSE
{
partial class AboutBox1 : Form
{
public AboutBox1()
{
InitializeComponent();
this.Text = String.Format("About {0}", AssemblyTitle);
}
#region Assembly Attribute Accessors
public string AssemblyTitle
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
if (attributes.Length > 0)
{
AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
if (titleAttribute.Title != "")
{
return titleAttribute.Title;
}
}
return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
}
}
public string AssemblyVersion
{
get
{
return Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}
public string AssemblyDescription
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyDescriptionAttribute)attributes[0]).Description;
}
}
public string AssemblyProduct
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyProductAttribute)attributes[0]).Product;
}
}
public string AssemblyCopyright
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCopyrightAttribute)attributes[0]).Copyright;
}
}
public string AssemblyCompany
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCompanyAttribute)attributes[0]).Company;
}
}
#endregion
private void okButton_Click(object sender, EventArgs e)
{
Hide();
}
}
}

545
Forms/AboutBox2.resx Normal file
View file

@ -0,0 +1,545 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="logoPictureBox.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
</value>
</data>
</root>

1732
Forms/NewMainForm.Designer.cs generated Normal file

File diff suppressed because it is too large Load diff

2519
Forms/NewMainForm.cs Normal file

File diff suppressed because it is too large Load diff

6326
Forms/NewMainForm.resx Normal file

File diff suppressed because it is too large Load diff

76
Forms/SecureValueForm.Designer.cs generated Normal file
View file

@ -0,0 +1,76 @@
namespace ACSE
{
partial class SecureValueForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(197, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 20);
this.button1.TabIndex = 0;
this.button1.Text = "Save";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(12, 12);
this.textBox1.MaxLength = 16;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(179, 20);
this.textBox1.TabIndex = 1;
this.textBox1.Text = "0000000000000000";
this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
//
// SecureValueForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 45);
this.ControlBox = false;
this.Controls.Add(this.textBox1);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Name = "SecureValueForm";
this.Text = "Secure_Value_Form";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBox1;
}
}

42
Forms/SecureValueForm.cs Normal file
View file

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ACSE
{
public partial class SecureValueForm : Form
{
public SecureValueForm()
{
InitializeComponent();
}
public void Set_Secure_NAND_Value(ulong value)
{
textBox1.Text = value.ToString("X16");
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
if (NewMainForm.Save_File != null && (NewMainForm.Save_File.Save_Type == SaveType.New_Leaf || NewMainForm.Save_File.Save_Type == SaveType.Welcome_Amiibo))
{
if (ulong.TryParse(textBox1.Text, NumberStyles.AllowHexSpecifier, null, out ulong Secure_NAND_Value))
{
NewMainForm.Save_File.Write(0, Secure_NAND_Value);
}
}
Hide();
}
}
}

120
Forms/SecureValueForm.resx Normal file
View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

125
Forms/SettingsMenuForm.Designer.cs generated Normal file
View file

@ -0,0 +1,125 @@
namespace ACSE
{
partial class SettingsMenuForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.imageSizeModeComboBox = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.doneButton = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.debugLevelComboBox = new System.Windows.Forms.ComboBox();
this.label3 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// imageSizeModeComboBox
//
this.imageSizeModeComboBox.FormattingEnabled = true;
this.imageSizeModeComboBox.Location = new System.Drawing.Point(125, 6);
this.imageSizeModeComboBox.Name = "imageSizeModeComboBox";
this.imageSizeModeComboBox.Size = new System.Drawing.Size(121, 21);
this.imageSizeModeComboBox.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(107, 13);
this.label1.TabIndex = 1;
this.label1.Text = "Image Resize Mode: ";
//
// doneButton
//
this.doneButton.Location = new System.Drawing.Point(317, 132);
this.doneButton.Name = "doneButton";
this.doneButton.Size = new System.Drawing.Size(75, 23);
this.doneButton.TabIndex = 2;
this.doneButton.Text = "Done";
this.doneButton.UseVisualStyleBackColor = true;
this.doneButton.Click += new System.EventHandler(this.doneButton_Click);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(252, 9);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(92, 13);
this.label2.TabIndex = 3;
this.label2.Text = "(Requires Restart)";
//
// debugLevelComboBox
//
this.debugLevelComboBox.FormattingEnabled = true;
this.debugLevelComboBox.Items.AddRange(new object[] {
"None",
"Error",
"Info",
"Debug"});
this.debugLevelComboBox.Location = new System.Drawing.Point(125, 33);
this.debugLevelComboBox.Name = "debugLevelComboBox";
this.debugLevelComboBox.Size = new System.Drawing.Size(121, 21);
this.debugLevelComboBox.TabIndex = 4;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(2, 36);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(117, 13);
this.label3.TabIndex = 5;
this.label3.Text = "Debug Message Level:";
//
// SettingsMenuForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(404, 167);
this.ControlBox = false;
this.Controls.Add(this.label3);
this.Controls.Add(this.debugLevelComboBox);
this.Controls.Add(this.label2);
this.Controls.Add(this.doneButton);
this.Controls.Add(this.label1);
this.Controls.Add(this.imageSizeModeComboBox);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "SettingsMenuForm";
this.Text = "ACSE Settings";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox imageSizeModeComboBox;
private System.Windows.Forms.Button doneButton;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.ComboBox debugLevelComboBox;
private System.Windows.Forms.Label label3;
}
}

44
Forms/SettingsMenuForm.cs Normal file
View file

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace ACSE
{
public partial class SettingsMenuForm : Form
{
public SettingsMenuForm()
{
InitializeComponent();
Array EnumItems = Enum.GetValues(typeof(InterpolationMode));
foreach (var Enum in EnumItems)
imageSizeModeComboBox.Items.Add(Enum.ToString());
imageSizeModeComboBox.SelectedIndex = Properties.Settings.Default.ImageResizeMode;
imageSizeModeComboBox.SelectedIndexChanged += new EventHandler((object o, EventArgs e) => ImageResizeMode_Changed());
debugLevelComboBox.SelectedIndex = (int)Properties.Settings.Default.DebugLevel;
debugLevelComboBox.SelectedIndexChanged += new EventHandler((object o, EventArgs e) => DebugLevel_Changed());
}
private void ImageResizeMode_Changed()
{
Properties.Settings.Default.ImageResizeMode = imageSizeModeComboBox.SelectedIndex;
//TODO: Redraw pictureboxes with the image mode, rather than wait to restart
}
private void DebugLevel_Changed()
{
Properties.Settings.Default.DebugLevel = (DebugLevel)Math.Max(0, debugLevelComboBox.SelectedIndex);
}
private void doneButton_Click(object sender, EventArgs e)
{
Properties.Settings.Default.Save();
Hide();
}
}
}

120
Forms/SettingsMenuForm.resx Normal file
View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ACSE")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ACSE")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("52b2adb4-812e-4b42-9955-9e8f1f14dbea")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

133
Properties/Resources.resx Normal file
View file

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="no_tpc" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Images\no_tpc.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="X" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Images\X.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Arrow" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Images\Arrow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Building" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Images\Building.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

103
Properties/Resources1.Designer.cs generated Normal file
View file

@ -0,0 +1,103 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ACSE.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ACSE.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Arrow {
get {
object obj = ResourceManager.GetObject("Arrow", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Building {
get {
object obj = ResourceManager.GetObject("Building", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap no_tpc {
get {
object obj = ResourceManager.GetObject("no_tpc", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap X {
get {
object obj = ResourceManager.GetObject("X", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View file

@ -0,0 +1,15 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="ACSE.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="DebuggingEnabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="ImageResizeMode" Type="System.Int32" Scope="User">
<Value Profile="(Default)">5</Value>
</Setting>
<Setting Name="DebugLevel" Type="ACSE.DebugLevel" Scope="User">
<Value Profile="(Default)">Info</Value>
</Setting>
</Settings>
</SettingsFile>

62
Properties/Settings1.Designer.cs generated Normal file
View file

@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ACSE.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.0.1.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool DebuggingEnabled {
get {
return ((bool)(this["DebuggingEnabled"]));
}
set {
this["DebuggingEnabled"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("5")]
public int ImageResizeMode {
get {
return ((int)(this["ImageResizeMode"]));
}
set {
this["ImageResizeMode"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Info")]
public global::ACSE.DebugLevel DebugLevel {
get {
return ((global::ACSE.DebugLevel)(this["DebugLevel"]));
}
set {
this["DebugLevel"] = value;
}
}
}
}

119
README.md Normal file
View file

@ -0,0 +1,119 @@
# ACSE - Animal Crossing Save Editor
ACSE is a save editor for the GameCube version of Animal Crossing.
## Features
* Player Editing
* Name
* Bells
* Debt
* Pockets
* House
* Acre Editing
* Town Editing
* Items
* Buildings
* Villager Editing
* Villagers
* Personalities
* Catchphrases
* Nicknames (Not Implemented)
## Extracting Save Files
### Dolphin Emulator
To extract save files from Dolphin, on the main form, click Tools > Memcard Manager (GC).
![Main Form](http://i.imgur.com/wH5OCQO.png)
Then click on Animal Crossing, and click the Export GCI button.
![Memcard Manager](http://i.imgur.com/t2GBonJ.png)
### Modded GameCube/Wii
Refer to the article here: https://wiki.dolphin-emu.org/index.php?title=Ripping_Games#Retrieving_Game_Saves
## Using the Editor
### Opening your Save File
Click on the File button, then click Open and select your save file!
![Open Save](https://puu.sh/toNcf/998c395bf9.png)
### Using the Main Editor Form
This contains the Players, Patterns, Town Name, and buttons to access the other editors! Simply change the values of the text/combo boxes to edit them.
![Main Editor](https://puu.sh/tIJV9/2db8da73fc.png)
### Using the Acre Editor Form
This form allows you to change your acre tiles! There is a 7x10 grid of acre tiles. To select an acre to place, click the "Check Tile" button, then left click on the desired acre. You can also simply click on one of the entries in the acre list to the right of the acre grid. Once selected, a preview image of the selected acre will appear on the bottom right of the screen, along with it's name and AcreID. To place an acre, click on the "Place Tile" button, then just left click over any acre tile on the grid!
![Acre Editor](https://puu.sh/tIJTI/cb72b4831e.png)
#### Acre Editor Precautions
Placing/Removing specific acres can damage your town. Here is a list of possible things that could break your game:
* Changing the top row of acres (Untested)
* Putting a non A-Acre in the A-Acre row (Also untested, but quite likely)
* Removing a Dump Acre, but not removing the dump in the Town Editor (This WILL cause your game to break, but only until you remove the dump or put a Dump Acre back)
* Placing regular land acres in the Ocean/Border acres, and dropping items in those acres. (The game doesn't have save data for those acres, and could possibly crash. You will definitely lose whatever you place in those acres, though)
* Not including at least one of each type of acre: Post Office, Dump (This will break your game), Nook's Shop Acre, Museum, Wishing Well, Police Station, Tailor's Shop, Lake & Beachfront w/ Dock (Also untested)
### Using the Town Editor Form
The Town Editor allows you to customize your town to the fullest extent. You can place/move/remove items, buildings, trees, rocks, decorative items, etc! To select an item to place, either select it in the combo box on the top, or right click on an item on the map. The combo box text will then change and the ItemID & buried checkbox should update to the right of it. To place an item, just left click on the map where you want the item placed. You can change whether or not the item is buried (minus outdoor objects like trees & buildings) by checking/unchecking the buried checkbox. You can also toggle the acre background display with the "Show Background" checkbox!
![Town Editor](http://i.imgur.com/18YlO3K.png)
#### Town Editor Precautions
As the case was with the Acre Editor, there are specific items you can place/remove that can possibly break your game. Here is a list of said items:
* Dumps (This is confirmed. It will break your game if you place it in a non A-Acre & a non Dump Acre. The Town Editor will confirm with you that you wish to place a dump in an incorrect acre, if you do. Otherwise, no warning will be shown!)
* Placing things in the top rows of the A-Acres that have "Occupied/Unavailable" as the item. (Not tested, I'm not sure what will happen if you change them. Feel free to, and let me know what happens!)
* Removing all instances of a building (Neighbor houses, Nook's Shop, Tailor's Shop, etc. could break your game. This is not certain, but it's definitely possible.)
* Placing multiple buildings/decorative items IS safe, as long as it is not a Dump.
### Using the Villager Editor Form
Using the Villager Editor for is fairly safe. There are a few possible game breaking things that will be discussed in the section below. To change a villager, all you have to do is select a different one in the drop down box! It's that easy, really. If you do change a villager, make sure you add the correct house for them in the Town Editor, though! You can also edit their Personality and Catchphrase!
![Villager Editor](http://i.imgur.com/XylZA3v.png)
#### Village Editor Precautions
There are a few cases where editing Villagers can cause strange results or break your game. The list is as follows:
* Adding any of the Villagers below Punchy (They are corrupted, and can cause your game to reset whenever you enter their acre. I added them in case people wanted to play around with them.)
* Not removing the old villagers house or not adding the new villagers house in the Town Editor (It's important that their house is removed/added. Where else would they live???)
* Changing an empty villager slot (No Villager) to another villager (Not 100% sure this can break your game, but it caused some weird AI glitches in mine. If you add their correct house, things might be fine.)
### Using the Shop Editor Form
This form allows you to edit Tom Nook's shop. It automatically detects which iteration of the shop exists in your town. You can change what is being sold, and how many bells you have spent/received from him.
![Shop Editor](https://puu.sh/tIKoj/e3b0269524.png)
### Using the Pocket Editor Form
Editing your pockets is very safe and probably the easiest part of this editor to grasp. You can place ANY item in your pocket. Items, Buildings, Trees, Rocks, etc. Same as before, right click or change the combo box selection to set the selected item. Left click to place in that spot. This form also contains the Dresser editor (See below section for more info about it.)
![Pocket Editor](https://puu.sh/tIJXx/8fbd037246.png)
#### Inventory/Pocket Editor Precautions
There is only one concern when using this editor.
* If you place furniture into the first spot in the dresser, it will appear on top of the dresser. This is due to how the items are stored. The first item is stored on top of the dresser, so it will cause the "Stacked Furniture Glitch" that many speed runners use to duplicate items.
### Using the House Editor Form
The House Editor is pretty simple as well. The floors are labeled for you. The top section is the "ground layer", where all furniture that goes on the floor should be placed. The section below it is the "top layer" where items that go on top of tables should be placed. This editor works exactly like the Town/Pocket Editors.
![House Editor](http://i.imgur.com/upNkKKz.png)
#### House Editor Precautions
There are only a few precautions:
* Placing outdoor objects (trees/buildings) in your house will not make them show up, and could break your game (although they just disappeared when I did it.)
* Placing furniture on the "top layer" with nothing below them will place them on the floor instead (Won't break your game or anything, but the save editor will notify you every time you try to do it.)
### Changing Settings
In the Settings Form, you can customize a few options that effect the save editor's behavior.
![Settings Form](https://puu.sh/tIK8r/3835737ec3.png)
### Saving Your Changes
Until you click File > Save, none of your changes will be commited. You must do this when you are ready to save your game. It will overwrite your old file, so make a backup if you're experimenting!
![Save File](https://puu.sh/toNoF/0a84b27f2c.png)
## Other Questions
Message me on Reddit (Cuyler_36) or on Github. I will do my best to help you with whatever you may need.
## Helping with the Editor
If you would like to contribute, I would appreciate it. Currently, I need someone to make graphics for the island acres, and possibly also for every acre. This would be nice, as it would give the user a feel of what the acre actually looks like.

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

BIN
Resources/ACSE_Logo_2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

52
Resources/AC_Acres_en.txt Normal file
View file

@ -0,0 +1,52 @@
//Building Acres
0x0118, Dump #1
0x0294, Dump #2
0x0298, Dump #3
0x0154, Train Station #1
0x02F0, Train Station #2
0x02F4, Train Station #3
0x034C, Police Station #1
0x0350, Police Station #2
0x0354, Police Station #3
0x0358, Player Houses #1
0x035C, Player Houses #2
0x0360, Player Houses #3
0x0364, Wishing Well #1
0x0368, Wishing Well #2
0x036C, Wishing Well #3
0x0370, Post Office #1
0x0380, Post Office #2
0x0384, Post Office #3
0x0374, Nook's Shop #1
0x0378, Nook's Shop #2
0x037C, Nook's Shop #3
0x0480, Museum #1
0x0484, Museum #2
0x0488, Museum #3
0x048C, Tailor's Shop #1
0x0490, Tailor's Shop #2
0x0494, Tailor's Shop #3
//Border Acres
0x0324, Upper Border Cliff (w/ Train Tracks)
0x0328, Upper Border Cliff (w/ River & Tracks)
0x032C, Left Border Cliff #1
0x0330, Left Border Cliff #1 <=> #2
0x0334, Left Border Cliff #2
0x0338, Right Border Cliff #1
0x033C, Right Border Cliff #1 <=> #2
0x0340, Right Border Cliff #2
0x0344, Left Border Cliff (w/ Train Tunnel) #2 <=> #3
0x0348, Right Border Cliff (w/ Train Tunnel) #2 <=> #3
0x03B4, Left Ocean Border Cliff
0x03B8, Right Ocean Border Cliff
//Grass Acres
0x0094, Grass Acre #1
0x0098, Grass Acre #2
0x0274, Grass Acre #3
0x0278, Grass Acre #4
0x027C, Grass Acre #5
0x0280, Grass Acre #6
0x0284, Grass Acre #7
0x0288, Grass Acre #8
0x028C, Grass Acre #9
0x0290, Grass Acre #10

2577
Resources/AC_Items_en.txt Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,239 @@
0x0000, No Villager
0xE000, Bob
0xE001, Olivia
0xE002, Mitzi
0xE003, Kiki
0xE004, Tangy
0xE005, Kabuki
0xE006, Tabby
0xE007, Monique
0xE008, Stinky
0xE009, Purrl
0xE00A, Kitty
0xE00B, Tom
0xE00C, Rosie
0xE00D, Nosegay
0xE00E, Zoe
0xE00F, Pango
0xE010, Cyrano
0xE011, Snooty
0xE012, Teddy
0xE013, Chow
0xE014, Dozer
0xE015, Nate
0xE016, Groucho
0xE017, Tutu
0xE018, Ursala
0xE019, Grizzly
0xE01A, Pinky
0xE01B, Jay
0xE01C, Twiggy
0xE01D, Anchovy
0xE01E, Piper
0xE01F, Admiral
0xE020, Otis
0xE021, Robin
0xE022, Midge
0xE023, Ace
0xE024, Twirp
0xE025, Chuck
0xE026, Stu
0xE027, Goose
0xE028, Betty
0xE029, Hector
0xE02A, Egbert
0xE02B, Ava
0xE02C, Hank
0xE02D, Leigh
0xE02E, Rhoda
0xE02F, Vladimir
0xE030, Murphy
0xE031, Cupcake
0xE032, Kody
0xE033, Maple
0xE034, Pudge
0xE035, Olive
0xE036, Poncho
0xE037, Bluebear
0xE038, Patty
0xE039, Petunia
0xE03A, Bessie
0xE03B, Belle
0xE03C, Alfonso
0xE03D, Boots
0xE03E, Liz
0xE03F, Biskit
0xE040, Goldie
0xE041, Daisy
0xE042, Lucky
0xE043, Portia
0xE044, Maddie
0xE045, Butch
0xE046, Bill
0xE047, Pompom
0xE048, Joey
0xE049, Scoot
0xE04A, Derwin
0xE04B, Freckles
0xE04C, Paolo
0xE04D, Dizzy
0xE04E, Axel
0xE04F, Emerald
0xE050, Tad
0xE051, Wart Jr.
0xE052, Cousteau
0xE053, Puddles
0xE054, Lily
0xE055, Jeremiah
0xE056, Huck
0xE057, Camofrog
0xE058, Ribbot
0xE059, Prince
0xE05A, Jambette
0xE05B, Billy
0xE05C, Chevere
0xE05D, Iggy
0xE05E, Gruff
0xE05F, Sven
0xE060, Velma
0xE061, Jane
0xE062, Cesar
0xE063, Louie
0xE064, Peewee
0xE065, Rollo
0xE066, Bubbles
0xE067, Bertha
0xE068, Elmer
0xE069, Winnie
0xE06A, Savannah
0xE06B, Ed
0xE06C, Cleo
0xE06D, Peaches
0xE06E, Buck
0xE06F, Carrie
0xE070, Mathilda
0xE071, Marcy
0xE072, Kitt
0xE073, Valise
0xE074, Astrid
0xE075, Sydney
0xE076, Gonzo
0xE077, Ozzie
0xE078, Yuka
0xE079, Huggy
0xE07A, Rex
0xE07B, Aziz
0xE07C, Leopold
0xE07D, Samson
0xE07E, Penny
0xE07F, Dora
0xE080, Chico
0xE081, Candi
0xE082, Rizzo
0xE083, Anicotti
0xE084, Limberg
0xE085, Carmen
0xE086, Octavian
0xE087, Sandy
0xE088, Sprocket
0xE089, Rio
0xE08A, Queenie
0xE08B, Apollo
0xE08C, Buzz
0xE08D, Quetzel
0xE08E, Amelia
0xE08F, Pierce
0xE090, Roald
0xE091, Aurora
0xE092, Hopper
0xE093, Cube
0xE094, Puck
0xE095, Gwen
0xE096, Friga
0xE097, Curly
0xE098, Truffles
0xE099, Spork
0xE09A, Hugh
0xE09B, Rasher
0xE09C, Sue E
0xE09D, Hambo
0xE09E, Lucy
0xE09F, Cobb
0xE0A0, Boris
0xE0A1, Bunnie
0xE0A2, Doc
0xE0A3, Gaston
0xE0A4, Coco
0xE0A5, Gabi
0xE0A6, Dotty
0xE0A7, Genji
0xE0A8, Snake
0xE0A9, Claude
0xE0AA, Tank
0xE0AB, Spike
0xE0AC, Tiara
0xE0AD, Vesta
0xE0AE, Filbert
0xE0AF, Hazel
0xE0B0, Peanut
0xE0B1, Pecan
0xE0B2, Ricky
0xE0B3, Static
0xE0B4, Mint
0xE0B5, Nibbles
0xE0B6, Tybalt
0xE0B7, Rolf
0xE0B8, Bangle
0xE0B9, Lobo
0xE0BA, Freya
0xE0BB, Chief
0xE0BC, Weber
0xE0BD, Mallary
0xE0BE, Wolfgang
0xE0BF, Hornsby
0xE0C0, Oxford
0xE0C1, T-Bone
0xE0C2, Biff
0xE0C3, Opal
0xE0C4, Bones
0xE0C5, Bea
0xE0C6, Bitty
0xE0C7, Rocco
0xE0C8, Lulu
0xE0C9, Blaire
0xE0CA, Sally
0xE0CB, Ellie
0xE0CC, Eloise
0xE0CD, Alli
0xE0CE, Pippy
0xE0CF, Eunice
0xE0D0, Baabara
0xE0D1, Fang
0xE0D2, Deena
0xE0D3, Pate
0xE0D4, Stella
0xE0D5, Cashmere
0xE0D6, Woolio
0xE0D7, Cookie
//Beginning of Islanders
0xE0D8, Maelle
0xE0D9, O'Hare
0xE0DA, Bliss
0xE0DB, Drift
0xE0DC, Bud
0xE0DD, Boomer
0xE0DE, Elina
0xE0DF, Flash
0xE0E0, Dobie
0xE0E1, Flossie
0xE0E2, Annalise
0xE0E3, Plucky
0xE0E4, Faith
0xE0E5, Yodel
0xE0E6, Rowan
0xE0E7, June
0xE0E8, Cheri
0xE0E9, Pigleg
0xE0EA, Ankha
//End of Islanders
0xE0EB, Punchy

374
Resources/CF_Acres_en.txt Normal file
View file

@ -0,0 +1,374 @@
//Transition Acres
0x0000, 0
0x0001, 1
0x0002, 2
0x0003, 3
0x0004, 4
0x0005, 5
0x0006, 6 (River EW)
0x0007, 7 (River EW)
0x0008, 8 (Ramp)
0x0009, 9 (Ramp)
0x000A, 10 (Ramp)
0x000B, 11 (Ramp)
0x000C, 12
0x000D, 13
0x000E, 14
0x000F, 15
0x0010, 16
0x0011, 17
0x0012, 18
0x0013, 19
0x0014, 20 (River NS)
0x0015, 21 (River NS)
0x0016, 22 (Ramp)
0x0017, 23 (Ramp)
0x0018, 24 (Ramp)
0x0019, 25 (Ramp)
0x001A, 26
0x001B, 27
0x001C, 28
0x001D, 29
0x001E, 30
0x001F, 31
0x0020, 32
0x0021, 33
0x0022, 34 (River NS)
0x0023, 35 (River NS)
0x0024, 36 (River NS)
0x0025, 37 (River NS)
0x0026, 38 (Ramp)
0x0027, 39 (Ramp)
0x0028, 40 (Ramp)
0x0029, 41 (Ramp)
0x002A, 42
0x002B, 43
0x002C, 44
0x002D, 45
0x002E, 46
0x002F, 47
0x0030, 48
0x0031, 49
0x0032, 50 (River NS)
0x0033, 51 (River NS)
0x0034, 52 (Ramp)
0x0035, 53 (Ramp)
0x0036, 54 (Ramp)
0x0037, 55 (Ramp)
0x0038, 56
0x0039, 57
0x003A, 58
0x003B, 59
0x003C, 60
0x003D, 61
0x003E, 62
0x003F, 63
0x0040, 64 (River NS)
0x0041, 65 (River NS)
0x0042, 66 (Ramp)
0x0043, 67 (Ramp)
0x0044, 68 (Ramp)
0x0045, 69 (Ramp)
0x0046, 70
0x0047, 71
0x0048, 72
0x0049, 73
0x004A, 74
0x004B, 75
0x004C, 76 (Ramp)
0x004D, 77 (Ramp)
0x004E, 78 (Ramp)
0x004F, 79 (Ramp)
0x0050, 80
0x0051, 81
0x0052, 82
0x0053, 83
0x0054, 84
0x0055, 85
0x0056, 86
0x0057, 87
0x0058, 88 (River NS)
0x0059, 89 (River NS)
0x005A, 90 (Ramp)
0x005B, 91 (Ramp)
0x005C, 92 (Ramp)
0x005D, 93 (Ramp)
0x005E, 94 (River EW)
0x005F, 95 (River EW)
//Grass Acres
0x0060, 0
0x0061, 1
0x0062, 2
0x0063, 3
0x0064, 4
0x0065, 5
0x0066, 6 (Pond)
0x0067, 7 (Pond)
0x0068, 8 (Pond)
0x0069, 9 (Pond)
0x006A, 10 (Pond)
0x006B, 11 (Pond)
//Building Acres
0x006C, 12 (Gate)
0x006D, 13 (Gate)
0x006E, 14 (Gate)
0x006F, 15 (Gate)
0x0070, 16 (Gate + Pond)
0x0071, 17 (Gate + Pond)
0x0072, 18 (Museum)
0x0073, 19 (Museum)
0x0074, 20 (Museum + Pond)
0x0075, 21 (Museum + Pond)
0x0076, 22 (Museum + Pond)
0x0077, 23 (Museum + Pond)
0x0078, 24 (Nook's)
0x0079, 25 (Nook's)
0x007A, 26 (Nook's)
0x007B, 27 (Nook's)
0x007C, 28 (Nook's + Pond)
0x007D, 29 (Nook's + Pond)
0x007E, 30 (Townhall)
0x007F, 31 (Townhall)
0x0080, 32 (Townhall)
0x0081, 33 (Townhall)
0x0082, 34 (Townhall)
0x0083, 35 (Townhall)
0x0084, 36 (Tailor)
0x0085, 37 (Tailor)
0x0086, 38 (Tailor + Pond)
0x0087, 39 (Tailor + Pond)
0x0088, 40 (Tailor + Pond)
0x0089, 41 (Tailor + Pond)
//Beachfront Acres
0x008A, 0
0x008B, 1
0x008C, 2
0x008D, 3
0x008E, 4
0x008F, 5
0x0090, 6
0x0091, 7
0x0092, 8
0x0093, 9
0x0094, 10
0x0095, 11
0x0096, 12 (River W)
0x0097, 13 (River W)
0x0098, 14 (River W)
0x0099, 15 (River W)
0x009A, 16 (River W + Bridge)
0x009B, 17 (River W + Bridge)
0x009C, 18 (River W + Bridge)
0x009D, 19 (River W + Bridge)
0x009E, 20 (River N)
0x009F, 21 (River N)
0x00A0, 22 (River N)
0x00A1, 23 (River N)
0x00A2, 24 (River N)
0x00A3, 25 (River N)
0x00A4, 26 (River N + Bridge)
0x00A5, 27 (River N + Bridge)
0x00A6, 28 (River N + Bridge)
0x00A7, 29 (River N + Bridge)
0x00A8, 30 (River N + Bridge)
0x00A9, 31 (River N + Bridge)
0x00AA, 32 (River NE)
0x00AB, 33 (River NE)
0x00AC, 34 (River NE)
0x00AD, 35 (River NE)
0x00AE, 36 (River NE + Bridge)
0x00AF, 37 (River NE + Bridge)
0x00B0, 38 (River NE + Bridge)
0x00B1, 39 (River NE + Bridge)
0x00B2, 40 (River NW)
0x00B3, 41 (River NW)
0x00B4, 42 (River NW)
0x00B5, 43 (River NW)
0x00B6, 44 (River NW + Bridge)
0x00B7, 45 (River NW + Bridge)
0x00B8, 46 (River NW + Bridge)
0x00B9, 47 (River NW + Bridge)
0x00BA, 48 (River E)
0x00BB, 49 (River E)
0x00BC, 50 (River E)
0x00BD, 51 (River E)
0x00BE, 52 (River E + Bridge)
0x00BF, 53 (River E + Bridge)
0x00C0, 54 (River E + Bridge)
0x00C1, 55 (River E + Bridge)
//Border Acres
0x00C2, 0 (Left)
0x00C3, 1 (Left)
0x00C4, 2 (Transition)
0x00C5, 3 (Transition)
0x00C6, 4 (Ocean Transition)
0x00C7, 5 (Ocean Transition)
0x00C8, 6 (Top)
0x00C9, 7 (Top)
0x00CA, 8 (Gate)
0x00CB, 9 (Gate)
0x00CC, 10 (Waterfall)
0x00CD, 11 (Waterfall)
0x00CE, 12 (Top Left)
0x00CF, 13 (Top Left)
0x00D0, 14 (Top Right)
0x00D1, 15 (Top Right)
0x00D2, 16 (Right)
0x00D3, 17 (Right)
0x00D4, 18 (Transition)
0x00D5, 19 (Transition)
0x00D6, 20 (Ocean Transition)
0x00D7, 21 (Ocean Transition)
0x00D8, 22 (Open Ocean)
0x00D9, 23 (Open Ocean)
//River Acres
0x00DA, 0 (EW)
0x00DB, 1 (EW)
0x00DC, 2 (EW)
0x00DD, 3 (EW)
0x00DE, 4 (EW)
0x00DF, 5 (EW)
0x00E0, 6 (EW + Bridge)
0x00E1, 7 (EW + Bridge)
0x00E2, 8 (EW + Bridge)
0x00E3, 9 (EW + Bridge)
0x00E4, 10 (EW + Bridge)
0x00E5, 11 (EW + Bridge)
0x00E6, 12 (EW + Lake)
0x00E7, 13 (EW + Lake)
0x00E8, 14 (EW + Lake)
0x00E9, 15 (EW + Lake)
0x00EA, 16 (SW)
0x00EB, 17 (SW)
0x00EC, 18 (SW)
0x00ED, 19 (SW)
0x00EE, 20 (SW)
0x00EF, 21 (SW)
0x00F0, 22 (SW)
0x00F1, 23 (SW)
0x00F2, 24 (SW + Bridge)
0x00F3, 25 (SW + Bridge)
0x00F4, 26 (SW)
0x00F5, 27 (SW + Bridge)
0x00F6, 28 (SW + Bridge)
0x00F7, 29 (SW + Bridge)
0x00F8, 30 (SW + Bridge)
0x00F9, 31 (SW + Bridge)
0x00FA, 32 (SW + Lake)
0x00FB, 33 (SW + Lake)
0x00FC, 34 (SW + Lake)
0x00FD, 35 (SW + Lake)
0x00FE, 36 (EWS)
0x00FF, 37 (EWS)
0x0100, 38 (NS)
0x0101, 39 (NS)
0x0102, 40 (NS)
0x0103, 41 (NS)
0x0104, 42 (NS)
0x0105, 43 (NS)
0x0106, 44 (NS + Bridge)
0x0107, 45 (NS + Bridge)
0x0108, 46 (NS + Bridge)
0x0109, 47 (NS + Bridge)
0x010A, 48 (NS + Bridge)
0x010B, 49 (NS + Bridge)
0x010C, 50 (Waterfall)
0x010D, 51 (Waterfall)
0x010E, 52 (Waterfall)
0x010F, 53 (Waterfall)
0x0110, 54 (Waterfall)
0x0111, 55 (Waterfall)
0x0112, 56 (NS + Lake)
0x0113, 57 (NS + Lake)
0x0114, 58 (NS + Lake)
0x0115, 59 (NS + Lake)
0x0116, 60 (NE)
0x0117, 61 (NE)
0x0118, 62 (NE)
0x0119, 63 (NE)
0x011A, 64 (NE)
0x011B, 65 (NE)
0x011C, 66 (NE)
0x011D, 67 (NE)
0x011E, 68 (NE + Bridge)
0x011F, 69 (NE + Bridge)
0x0120, 70 (NE + Bridge)
0x0121, 71 (NE + Bridge)
0x0122, 72 (NE + Bridge)
0x0123, 73 (NE + Bridge)
0x0124, 74 (NE + Bridge)
0x0125, 75 (NE + Bridge)
0x0126, 76 (NE + Lake)
0x0127, 77 (NE + Lake)
0x0128, 78 (NE + Lake)
0x0129, 79 (NE + Lake)
0x012A, 80 (NSE)
0x012B, 81 (NSE)
0x012C, 82 (NSE)
0x012D, 83 (NSE)
0x012E, 84 (NW)
0x012F, 85 (NW)
0x0130, 86 (NW)
0x0131, 87 (NW)
0x0132, 88 (NW)
0x0133, 89 (NW)
0x0134, 90 (NW)
0x0135, 91 (NW)
0x0136, 92 (NW + Bridge)
0x0137, 93 (NW + Bridge)
0x0138, 94 (NW + Bridge)
0x0139, 95 (NW + Bridge)
0x013A, 96 (NW + Bridge)
0x013B, 97 (NW + Bridge)
0x013C, 98 (NW + Bridge)
0x013D, 99 (NW + Bridge)
0x013E, 100 (NW + Lake)
0x013F, 101 (NW + Lake)
0x0140, 102 (NW + Lake)
0x0141, 103 (NW + Lake)
0x0142, 104 (EWN)
0x0143, 105 (EWN)
0x0144, 106 (EWN)
0x0145, 107 (EWN)
0x0146, 108 (NSW)
0x0147, 109 (NSW)
0x0148, 110 (NSW)
0x0149, 111 (NSW)
0x014A, 112 (EW)
0x014B, 113 (EW)
0x014C, 114 (EW)
0x014D, 115 (EW)
0x014E, 116 (EW)
0x014F, 117 (EW)
0x0150, 118 (EW + Bridge)
0x0151, 119 (EW + Bridge)
0x0152, 120 (EW + Bridge)
0x0153, 121 (EW + Bridge)
0x0154, 122 (EW + Bridge)
0x0155, 123 (EW + Bridge)
0x0156, 124 (EW + Lake)
0x0157, 125 (EW + Lake)
0x0158, 126 (EW + Lake)
0x0159, 127 (EW + Lake)
0x015A, 128 (SE)
0x015B, 129 (SE)
0x015C, 130 (SE)
0x015D, 131 (SE)
0x015E, 132 (SE)
0x015F, 133 (SE)
0x0160, 134 (SE)
0x0161, 135 (SE)
0x0162, 136 (SE + Bridge)
0x0163, 137 (SE + Bridge)
0x0164, 138 (SE + Bridge)
0x0165, 139 (SE + Bridge)
0x0166, 140 (SE + Bridge)
0x0167, 141 (SE + Bridge)
0x0168, 142 (SE + Bridge)
0x0169, 143 (SE + Bridge)
0x016A, 144 (SE + Lake)
0x016B, 145 (SE + Lake)
0x016C, 146 (SE + Lake)
0x016D, 147 (SE + Lake)
0x016E, 148 (EWS)
0x016F, 149 (EWS)

2822
Resources/CF_Items_en.txt Normal file

File diff suppressed because it is too large Load diff

BIN
Resources/Images/1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
Resources/Images/10.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

BIN
Resources/Images/100.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
Resources/Images/11.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
Resources/Images/12.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
Resources/Images/13.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
Resources/Images/14.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
Resources/Images/15.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
Resources/Images/16.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
Resources/Images/17.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
Resources/Images/18.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
Resources/Images/19.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
Resources/Images/2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
Resources/Images/20.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

BIN
Resources/Images/21.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
Resources/Images/22.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
Resources/Images/23.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

BIN
Resources/Images/24.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
Resources/Images/25.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
Resources/Images/26.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
Resources/Images/27.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
Resources/Images/28.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
Resources/Images/29.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
Resources/Images/3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
Resources/Images/30.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Resources/Images/31.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
Resources/Images/32.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
Resources/Images/33.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
Resources/Images/34.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
Resources/Images/35.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
Resources/Images/36.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
Resources/Images/37.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
Resources/Images/38.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
Resources/Images/39.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
Resources/Images/4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
Resources/Images/40.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
Resources/Images/41.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
Resources/Images/42.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
Resources/Images/43.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
Resources/Images/44.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
Resources/Images/45.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
Resources/Images/46.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
Resources/Images/47.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
Resources/Images/48.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
Resources/Images/49.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Resources/Images/5.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
Resources/Images/50.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
Resources/Images/51.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Resources/Images/52.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
Resources/Images/53.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
Resources/Images/54.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
Resources/Images/55.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Some files were not shown because too many files have changed in this diff Show more