Push Local Changes

Way too much to actually document
This commit is contained in:
Cuyler36 2020-03-08 03:36:08 -04:00
parent 1cdd0fd321
commit 42bd503e32
41 changed files with 1695 additions and 478 deletions

View file

@ -5,6 +5,10 @@
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Costura.Fody" Version="3.1.6" />
<PackageReference Include="Fody" Version="3.2.16">

View file

@ -21,12 +21,33 @@ public static class Catalog
{ 0x1173, 0xFC }
};
public static readonly Dictionary<int, byte> WildWorldCatalogBitmap = new Dictionary<int, byte>
{
{ 0x1BDD, 0x01 },
{ 0x1BDE, 0x00 },
{ 0x1BDF, 0x00 },
{ 0x1BE0, 0x00 },
{ 0x1BE1, 0x00 },
{ 0x1BE2, 0x00 },
{ 0x1BE3, 0x00 },
{ 0x1BE4, 0x00 },
{ 0x1BE5, 0x00 },
{ 0x1BE6, 0x00 },
{ 0x1BE7, 0x00 },
{ 0x1BE8, 0x00 },
{ 0x1BE9, 0x00 },
{ 0x1BEA, 0x00 },
{ 0x1BEB, 0xFE }
};
private static int GetCatalogBaseOffset(SaveType saveType)
{
switch (saveType)
{
case SaveType.AnimalCrossing:
return 0x1108;
case SaveType.WildWorld:
return 0x1B48;
case SaveType.NewLeaf:
return 0x6C70;
case SaveType.WelcomeAmiibo:
@ -42,6 +63,8 @@ private static int GetCatalogSize(SaveType saveType)
{
case SaveType.AnimalCrossing:
return 0xD4;
case SaveType.WildWorld:
return 0x124; // Needs verification.
case SaveType.NewLeaf:
return 0xE0;
case SaveType.WelcomeAmiibo:
@ -57,6 +80,8 @@ private static Dictionary<int, byte> GetNonCatalogFields(SaveType saveType)
{
case SaveType.AnimalCrossing:
return AnimalCrossingCatalogBitmap;
case SaveType.WildWorld:
return WildWorldCatalogBitmap;
default:
return null;
}

View file

@ -515,9 +515,9 @@ private struct data_combi
#region River Variables
// River Variables
private static readonly byte[] river1_album_data = new byte[7] { 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C };
private static readonly byte[] river2_album_data = new byte[7] { 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0xFF, 0xFF };
private static readonly byte[] river3_album_data = new byte[7] { 0x22, 0xFF, 0xFF, 0x23, 0x24, 0x25, 0x26 };
private static readonly byte[] river1_album_data = new byte[7] { 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C };
private static readonly byte[] river2_album_data = new byte[7] { 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0xFF, 0xFF };
private static readonly byte[] river3_album_data = new byte[7] { 0x22, 0xFF, 0xFF, 0x23, 0x24, 0x25, 0x26 };
private static readonly byte[] river_no_album_data = new byte[7] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
private static readonly byte[][] river_cliff_album_data = new byte[7][]
@ -699,6 +699,21 @@ private struct data_combi
0x53, 0x53, 0x53, 0x67, 0x67, 0x67, 0x67
};
// Unused 3-layer town layout found in DnM+. It was removed in the transition to Animal Crossing.
private static readonly byte[] step3_blocksD = new byte[70]
{
0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08,
0x09, 0x0c, 0x0c, 0x0b, 0x0c, 0x0d, 0x0a,
0x3d, 0x0f, 0x13, 0x0e, 0x2e, 0x2d, 0x04,
0x02, 0x27, 0x15, 0x0f, 0x16, 0x0f, 0x3e,
0x3d, 0x0f, 0x0f, 0x0f, 0x1a, 0x27, 0x04,
0x02, 0x27, 0x27, 0x27, 0x1c, 0x0f, 0x3e,
0x50, 0x27, 0x27, 0x27, 0x28, 0x27, 0x51,
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
0x53, 0x53, 0x53, 0x66, 0x62, 0x63, 0x66,
0x53, 0x53, 0x53, 0x67, 0x67, 0x67, 0x67
};
private static readonly byte[][] step3_blockss = new byte[10][]
{
step3_blocks3, step3_blocks7, step3_blocks7R, step3_blocks8,
@ -708,45 +723,45 @@ private struct data_combi
private static readonly Dictionary<byte, ushort[]> TownAcrePool = new Dictionary<byte, ushort[]>
{
{ 0x00, new ushort[] {0x0324} },
{ 0x01, new ushort[] {0x0328} },
{ 0x02, new ushort[] {0x032C} },
{ 0x00, new ushort[] {0x0324} }, // Upper Border Cliff
{ 0x01, new ushort[] {0x0328} }, // Upper Border Cliff w/ River
{ 0x02, new ushort[] {0x032C} }, // Left Border Cliff
// 0x03?
{ 0x04, new ushort[] {0x0338} },
{ 0x05, new ushort[] {0x0344} },
{ 0x04, new ushort[] {0x0338} }, // Right Border Cliff
{ 0x05, new ushort[] {0x0344} }, // Left Border Corner Cliff
// 0x06?
// 0x07?
{ 0x08, new ushort[] {0x0348} },
{ 0x09, new ushort[] {0x0334} },
{ 0x0A, new ushort[] {0x0340} },
{ 0x0B, new ushort[] {0x0154, 0x02F0, 0x02F4} },
{ 0x08, new ushort[] {0x0348} }, // Right Border Corner Cliff
{ 0x09, new ushort[] {0x0334} }, // Left Border Cliff w/ Tunnel
{ 0x0A, new ushort[] {0x0340} }, // Right Border Cliff w/ Tunnel
{ 0x0B, new ushort[] {0x0154, 0x02F0, 0x02F4} }, // Train Stations
{ 0x0C, new ushort[] {0x0118, 0x0294, 0x0298} }, // Dump Acres
{ 0x0D, new ushort[] {0x0070, 0x02B8, 0x02BC, 0x02C0, 0x02C4} },
{ 0x0E, new ushort[] {0x0358, 0x035C, 0x0360} },
{ 0x0F, new ushort[] {0x009C, 0x015C, 0x0160, 0x0164, 0x0168} },
{ 0x10, new ushort[] {0x00A8, 0x016C, 0x01F4} },
{ 0x11, new ushort[] {0x00AC, 0x01A0, 0x01F0} },
{ 0x12, new ushort[] {0x00B4, 0x01B0, 0x01EC} },
{ 0x13, new ushort[] {0x00C0, 0x01B4, 0x01E8} },
{ 0x14, new ushort[] {0x00CC, 0x01B8, 0x0218} },
{ 0x15, new ushort[] {0x00D4, 0x01A4, 0x021C} },
{ 0x16, new ushort[] {0x0084, 0x0200, 0x0204} },
{ 0x17, new ushort[] {0x008C, 0x0210} },
{ 0x18, new ushort[] {0x00B0, 0x019C} },
{ 0x19, new ushort[] {0x00B8, 0x01C4} },
{ 0x1A, new ushort[] {0x006C, 0x0214} },
{ 0x1B, new ushort[] {0x00D0, 0x0198} },
{ 0x1C, new ushort[] {0x0138, 0x01CC} },
{ 0x1D, new ushort[] {0x00A0, 0x01A8, 0x0208} },
{ 0x1E, new ushort[] {0x0090, 0x0244} },
{ 0x1F, new ushort[] {0x00F4, 0x0248} },
{ 0x20, new ushort[] {0x00BC, 0x01C8} },
{ 0x21, new ushort[] {0x00C4, 0x01D4} },
{ 0x22, new ushort[] {0x00A4, 0x01AC, 0x020C} },
{ 0x23, new ushort[] {0x013C, 0x01D8} },
{ 0x24, new ushort[] {0x00C8, 0x01E4} },
{ 0x25, new ushort[] {0x00FC} },
{ 0x26, new ushort[] {0x00F8, 0x0414} },
{ 0x0D, new ushort[] {0x0070, 0x02B8, 0x02BC, 0x02C0, 0x02C4} }, // Rivers w/ Train Track
{ 0x0E, new ushort[] {0x0358, 0x035C, 0x0360} }, // Player House Acres
{ 0x0F, new ushort[] {0x009C, 0x015C, 0x0160, 0x0164, 0x0168} }, // Horizontal Cliffs
{ 0x10, new ushort[] {0x00A8, 0x016C, 0x01F4} }, // Left Corner Cliffs
{ 0x11, new ushort[] {0x00AC, 0x01A0, 0x01F0} }, // Left Side Cliffs
{ 0x12, new ushort[] {0x00B4, 0x01B0, 0x01EC} }, // Left Side Inverted Cliffs
{ 0x13, new ushort[] {0x00C0, 0x01B4, 0x01E8} }, // Right Side Inverted Cliffs
{ 0x14, new ushort[] {0x00CC, 0x01B8, 0x0218} }, // Right Side Cliffs
{ 0x15, new ushort[] {0x00D4, 0x01A4, 0x021C} }, // Right Side Corner Cliffs
{ 0x16, new ushort[] {0x0084, 0x0200, 0x0204} }, // South Flowing Waterfall w/ Horizontal Cliff
{ 0x17, new ushort[] {0x008C, 0x0210} }, // South Flowing Waterfall w/ Left Corner Cliff
{ 0x18, new ushort[] {0x00B0, 0x019C} }, // South Flowing River (Upper) w/ Left Cliff
{ 0x19, new ushort[] {0x00B8, 0x01C4} }, // South Flowing River (Upper) w/ Left Inverted Corner Cliff
{ 0x1A, new ushort[] {0x006C, 0x0214} }, // South Flowing Waterfall w/ Right Inverted Corner Cliff
{ 0x1B, new ushort[] {0x00D0, 0x0198} }, // South Flowing River (Lower) w/ Right Cliff
{ 0x1C, new ushort[] {0x0138, 0x01CC} }, // South Flowing River (Lower) w/ Right Corner Cliff
{ 0x1D, new ushort[] {0x00A0, 0x01A8, 0x0208} }, // East Flowing River (Upper) w/ Horizontal Cliff
{ 0x1E, new ushort[] {0x0090, 0x0244} }, // East Flowing Waterfall w/ Left Corner Cliff
{ 0x1F, new ushort[] {0x00F4, 0x0248} }, // East Flowing Waterfall w/ Left Cliff
{ 0x20, new ushort[] {0x00BC, 0x01C8} }, // East Flowing River (Upper) w/ Inverted Left Corner Cliff
{ 0x21, new ushort[] {0x00C4, 0x01D4} }, // East Flowing River (Upper) w/ Inverted Right Corner Cliff
{ 0x22, new ushort[] {0x00A4, 0x01AC, 0x020C} }, // West Flowing River (Upper) w/ Horizontal Cliff
{ 0x23, new ushort[] {0x013C, 0x01D8} }, // West Flowing River (Upper) w/ Inverted Left Corner Cliff
{ 0x24, new ushort[] {0x00C8, 0x01E4} }, // West Flowing River (Upper) w/ Inverted Right Corner Cliff
{ 0x25, new ushort[] {0x00FC} }, // West Flowing Waterfall w/ Right Cliff
{ 0x26, new ushort[] {0x00F8, 0x0414} }, // West Flowing Waterfall w/ Right Corner Cliff
{ 0x27, new ushort[] {0x0094, 0x0098, 0x0274, 0x0278, 0x027C, 0x0280, 0x0284, 0x0288, 0x028C, 0x0290} }, // Grass acres
{ 0x28, new ushort[] {0x00D8, 0x0170, 0x0174, 0x0220} }, // River south
{ 0x29, new ushort[] {0x00DC, 0x01BC, 0x01DC, 0x0224} }, // River east

View file

@ -1,4 +1,5 @@
using System;
using System.Linq;
using ACSE.Core.Items;
using ACSE.Core.Patterns;
using ACSE.Core.Players;
@ -603,6 +604,10 @@ public static void SetHasBasement(bool enabled, House selectedHouse)
}
}
public static Player GetOwner(House house) => Save.SaveInstance?.Players.FirstOrNull(o =>
o.Exists && o.Data.Identifier == house.Data.OwningPlayerId &&
o.Data.Name == house.Data.OwningPlayerName);
public static House[] LoadHouses(Save saveFile)
{
var houseCount = saveFile.SaveGeneration == SaveGeneration.NDS ? 1 : 4;
@ -612,6 +617,7 @@ public static House[] LoadHouses(Save saveFile)
{
_houses[i] = new House(i, saveFile.SaveDataStartOffset + saveFile.SaveInfo.SaveOffsets.HouseData + i * saveFile.SaveInfo.SaveOffsets.HouseDataSize);
}
return _houses;
}
}

View file

@ -19,16 +19,16 @@ public enum AcItemFlag
public Item[] Items;
public Inventory(IReadOnlyList<ushort> inventoryData, Save save, Player player)
public Inventory(IReadOnlyList<ushort> inventoryData, Player player)
{
Items = new Item[inventoryData.Count];
for(var i = 0; i < inventoryData.Count; i++)
{
var item = new Item(inventoryData[i]);
if (save.SaveGeneration == SaveGeneration.GCN)
if (Save.SaveInstance.SaveGeneration == SaveGeneration.GCN)
{
item.ItemFlag = GetItemFlag(save, player, i);
item.ItemFlag = GetItemFlag(player, i);
}
Items[i] = item;
@ -127,34 +127,34 @@ public ushort[] GetItemIDs()
return ids;
}
public static AcItemFlag GetItemFlag(Save saveFile, Player player, int inventoryIdx)
public static AcItemFlag GetItemFlag(Player player, int inventoryIdx)
{
switch (saveFile.SaveType)
switch (Save.SaveInstance.SaveType)
{
case SaveType.AnimalCrossing:
return (AcItemFlag)(saveFile.ReadUInt32(player.Offset + 0x88, saveFile.IsBigEndian) >> (inventoryIdx << 1) & 3);
return (AcItemFlag)(Save.SaveInstance.ReadUInt32(player.Offset + 0x88, Save.SaveInstance.IsBigEndian) >> (inventoryIdx << 1) & 3);
case SaveType.DoubutsuNoMoriPlus:
case SaveType.DoubutsuNoMoriEPlus:
case SaveType.AnimalForestEPlus:
return (AcItemFlag)(saveFile.ReadUInt32(player.Offset + 0x84, saveFile.IsBigEndian) >> (inventoryIdx << 1) & 3);
return (AcItemFlag)(Save.SaveInstance.ReadUInt32(player.Offset + 0x84, Save.SaveInstance.IsBigEndian) >> (inventoryIdx << 1) & 3);
default:
return AcItemFlag.None;
}
}
public static void SetItemFlag(Save saveFile, Player player, AcItemFlag flag, int inventoryIdx)
public static void SetItemFlag(Player player, AcItemFlag flag, int inventoryIdx)
{
var flagIdx = inventoryIdx << 1;
var flagValue = (uint)flag & 3;
switch (saveFile.SaveType)
switch (Save.SaveInstance.SaveType)
{
case SaveType.AnimalCrossing:
saveFile.Write(player.Offset + 0x88, (saveFile.ReadUInt32(player.Offset + 0x88, saveFile.IsBigEndian) & ~(3 << flagIdx)) | (flagValue << flagIdx));
Save.SaveInstance.Write(player.Offset + 0x88, (Save.SaveInstance.ReadUInt32(player.Offset + 0x88, Save.SaveInstance.IsBigEndian) & ~(3 << flagIdx)) | (flagValue << flagIdx));
break;
case SaveType.DoubutsuNoMoriPlus:
case SaveType.DoubutsuNoMoriEPlus:
case SaveType.AnimalForestEPlus:
saveFile.Write(player.Offset + 0x84, (saveFile.ReadUInt32(player.Offset + 0x84, saveFile.IsBigEndian) & ~(3 << flagIdx)) | (flagValue << flagIdx));
Save.SaveInstance.Write(player.Offset + 0x84, (Save.SaveInstance.ReadUInt32(player.Offset + 0x84, Save.SaveInstance.IsBigEndian) & ~(3 << flagIdx)) | (flagValue << flagIdx));
break;
}
}

View file

@ -70,6 +70,8 @@ public Item(ushort itemId, byte flag1, byte flag2)
Type = ItemData.GetItemType(ItemId, Save.SaveInstance?.SaveType ?? SaveType.AnimalCrossing);
}
public override string ToString() => Name;
public uint ToUInt32()
{
return (uint)((Flag1 << 24) + (Flag2 << 16) + ItemId);

View file

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ACSE.Core.Messages.Mail
{
public struct AnimalForestEPlusMailHeader
{
}
}

View file

@ -1,5 +1,4 @@
using ACSE.Core.Items;
using ACSE.Core.Players;
using ACSE.Core.Saves;
namespace ACSE.Core.Messages.Mail
@ -22,13 +21,14 @@ public sealed class GCMailName
public ushort TownId;
public PersonType PersonType;
public GCMailName(Save saveFile, int offset)
public GCMailName(Save saveFile, int offset, int stringSize = 8)
{
Name = saveFile.ReadString(offset, 8);
TownName = saveFile.ReadString(offset + 8, 8);
PlayerId = saveFile.ReadUInt16(offset + 0x10, true);
TownId = saveFile.ReadUInt16(offset + 0x12, true);
PersonType = (PersonType) saveFile.ReadByte(offset + 0x14);
var stringSizeDoubled = stringSize * 2;
Name = saveFile.ReadString(offset, stringSize);
TownName = saveFile.ReadString(offset + stringSize, stringSize);
PlayerId = saveFile.ReadUInt16(offset + stringSizeDoubled, true);
TownId = saveFile.ReadUInt16(offset + stringSizeDoubled + 2, true);
PersonType = (PersonType) saveFile.ReadByte(offset + stringSizeDoubled + 4);
}
}
@ -41,33 +41,49 @@ public GCMailName(Save saveFile, int offset)
public LetterType LetterType;
public LetterSenderType SenderType;
public GcnPlayerMail(Save saveFile, Player owner, int index)
public GcnPlayerMail(Save saveFile, int offset, int index = -1)
{
Index = index;
Offset = offset;
var stringSize = -1;
switch (saveFile.SaveType)
{
case SaveType.DoubutsuNoMoriPlus:
break;
case SaveType.AnimalCrossing:
Offset = owner.Offset + 0x4E0 + index * 0x12A;
RecipientInfo = new GCMailName(saveFile, Offset);
SenderInfo = new GCMailName(saveFile, Offset + 0x16);
Present = new Item(saveFile.ReadUInt16(Offset + 0x2C, true)); // TODO: There has to be a flag that tells the game if the item is wrapped or a quest item.
LetterType = (LetterType) saveFile.ReadByte(Offset + 0x2E); // "Font"
HeaderReceipiantStartOffset = saveFile.ReadByte(Offset + 0x2F); // How many characters until the recipient's name should be inserted
SenderType = (LetterSenderType) saveFile.ReadByte(Offset + 0x30);
StationaryType = new Item((ushort)(0x2000 | saveFile.ReadByte(Offset + 0x31)));
stringSize = 8;
Header = saveFile.ReadString(Offset + 0x32, 0x18);
Contents = saveFile.ReadString(Offset + 0x4A, 0xC0);
Footer = saveFile.ReadString(Offset + 0x10A, 0x20);
break;
case SaveType.DoubutsuNoMoriEPlus:
case SaveType.AnimalForestEPlus:
stringSize = 6;
Header = saveFile.ReadString(Offset + 0x2A, 0xA);
Contents = saveFile.ReadString(Offset + 0x38, 0x60);
Footer = saveFile.ReadString(Offset + 0xA6, 0x10);
break;
}
var mailNameSize = stringSize * 2 + 6;
RecipientInfo = new GCMailName(saveFile, Offset);
SenderInfo = new GCMailName(saveFile, Offset + mailNameSize);
var mailInfoStart = Offset + mailNameSize * 2;
Present = new Item(saveFile.ReadUInt16(mailInfoStart, true));
LetterType = (LetterType) saveFile.ReadByte(mailInfoStart + 2);
HeaderReceipiantStartOffset = saveFile.ReadByte(mailInfoStart + 3);
SenderType = (LetterSenderType) saveFile.ReadByte(mailInfoStart + 4);
StationaryType = new Item((ushort) (0x2000 | saveFile.ReadByte(mailInfoStart + 5)));
}
public string GetFormattedMailString()
=> string.Format("{0}{1}{2}\n{3}\n{4}",
Header.Substring(0, HeaderReceipiantStartOffset), Receipiant, Header.Substring(HeaderReceipiantStartOffset), Contents, Footer);
=> $"{Header.Substring(0, HeaderReceipiantStartOffset)}{RecipientInfo.Name}{Header.Substring(HeaderReceipiantStartOffset)}\n{Contents}\n{Footer}";
public bool IsMailUsed => LetterType == LetterType.None;
}
}

View file

@ -326,7 +326,6 @@ public static byte ClosestColorRgb(uint color, uint[] paletteData, bool gen1 = f
public sealed class Pattern
{
private readonly Save _saveFile;
private readonly int _offset;
public readonly int Index;
public byte[] PatternBitmapBuffer = new byte[4 * 32 * 32];
@ -339,10 +338,9 @@ public sealed class Pattern
public Bitmap PatternBitmap;
public uint[] PaletteData;
public Pattern(int patternOffset, int index, Save save = null)
public Pattern(int patternOffset, int index)
{
_offset = patternOffset;
_saveFile = save;
Index = index;
Read(index);
}
@ -363,11 +361,11 @@ public uint[][] GetPaletteArray(SaveGeneration saveGeneration)
// AC / CF
public void GeneratePatternBitmap(byte[] importData = null, bool decode = true)
{
var patternRawData = importData ?? (_saveFile.SaveType == SaveType.CityFolk
? _saveFile.ReadByteArray(_offset, 0x200)
: _saveFile.ReadByteArray(_offset + 0x20, 0x200));
var patternRawData = importData ?? (Save.SaveInstance.SaveType == SaveType.CityFolk
? Save.SaveInstance.ReadByteArray(_offset, 0x200)
: Save.SaveInstance.ReadByteArray(_offset + 0x20, 0x200));
var paletteData = _saveFile.SaveType == SaveType.CityFolk
var paletteData = Save.SaveInstance.SaveType == SaveType.CityFolk
? PatternData.CfPaletteData
: PatternData.AcPaletteData;
@ -381,7 +379,7 @@ public void GeneratePatternBitmap(byte[] importData = null, bool decode = true)
public void GenerateWwPatternBitmap(byte[] importData = null, bool decode = true)
{
var rawData = importData ?? _saveFile.ReadByteArray(_offset, 0x200);
var rawData = importData ?? Save.SaveInstance.ReadByteArray(_offset, 0x200);
if (decode)
{
@ -411,8 +409,8 @@ public void GenerateWwPatternBitmap(byte[] importData = null, bool decode = true
public void GenerateNlPatternBitmap(byte[] importData = null, bool decode = true)
{
//Add decoding of "Pro" patterns
var rawData = importData ?? _saveFile.ReadByteArray(_offset + 0x6C, 0x200); //32x32 doubled up pixels
var customPalette = _saveFile.ReadByteArray(_offset + 0x58, 16); //New Leaf user selected palette data
var rawData = importData ?? Save.SaveInstance.ReadByteArray(_offset + 0x6C, 0x200); //32x32 doubled up pixels
var customPalette = Save.SaveInstance.ReadByteArray(_offset + 0x58, 16); //New Leaf user selected palette data
PaletteData = new uint[15];
// Generate Palatte Data
@ -444,11 +442,11 @@ public void GenerateNlPatternBitmap(byte[] importData = null, bool decode = true
public void Read(int index)
{
switch (_saveFile.SaveType)
switch (Save.SaveInstance.SaveType)
{
case SaveType.AnimalCrossing:
Name = new AcString(_saveFile.ReadByteArray(_offset, 0x10), _saveFile.SaveType).Trim();
Palette = _saveFile.ReadByte(_offset + 0x10);
Name = new AcString(Save.SaveInstance.ReadByteArray(_offset, 0x10), Save.SaveInstance.SaveType).Trim();
Palette = Save.SaveInstance.ReadByte(_offset + 0x10);
PaletteData = PatternData.AcPaletteData[Palette];
GeneratePatternBitmap();
break;
@ -456,33 +454,33 @@ public void Read(int index)
case SaveType.DoubutsuNoMori:
case SaveType.DoubutsuNoMoriPlus:
case SaveType.AnimalForestEPlus:
Name = new AcString(_saveFile.ReadByteArray(_offset, 0xA), _saveFile.SaveType).Trim();
Palette = _saveFile.ReadByte(_offset + 0xA);
Name = new AcString(Save.SaveInstance.ReadByteArray(_offset, 0xA), Save.SaveInstance.SaveType).Trim();
Palette = Save.SaveInstance.ReadByte(_offset + 0xA);
PaletteData = PatternData.AcPaletteData[Palette];
GeneratePatternBitmap();
break;
case SaveType.WildWorld:
TownName = new AcString(_saveFile.ReadByteArray(_offset + 0x202, 8), SaveType.WildWorld).Trim();
CreatorName = new AcString(_saveFile.ReadByteArray(_offset + 0x20C, 8), SaveType.WildWorld).Trim();
Name = new AcString(_saveFile.ReadByteArray(_offset + 0x216, 16), SaveType.WildWorld).Trim();
Palette = (byte)((_saveFile.ReadByte(_offset + 0x226) & 0xF0) >> 4);
Concept = (byte)(_saveFile.ReadByte(_offset + 0x226) & 0x0F);
TownName = new AcString(Save.SaveInstance.ReadByteArray(_offset + 0x202, 8), SaveType.WildWorld).Trim();
CreatorName = new AcString(Save.SaveInstance.ReadByteArray(_offset + 0x20C, 8), SaveType.WildWorld).Trim();
Name = new AcString(Save.SaveInstance.ReadByteArray(_offset + 0x216, 16), SaveType.WildWorld).Trim();
Palette = (byte)((Save.SaveInstance.ReadByte(_offset + 0x226) & 0xF0) >> 4);
Concept = (byte)(Save.SaveInstance.ReadByte(_offset + 0x226) & 0x0F);
PaletteData = PatternData.WwPaletteData[Palette];
GenerateWwPatternBitmap();
break;
case SaveType.CityFolk:
TownName = new AcString(_saveFile.ReadByteArray(_offset + 0x822, 16), SaveType.CityFolk).Trim();
CreatorName = new AcString(_saveFile.ReadByteArray(_offset + 0x838, 16), SaveType.CityFolk).Trim();
Name = new AcString(_saveFile.ReadByteArray(_offset + 0x84C, 32), SaveType.CityFolk).Trim();
Palette = _saveFile.ReadByte(_offset + 0x86F);
TownName = new AcString(Save.SaveInstance.ReadByteArray(_offset + 0x822, 16), SaveType.CityFolk).Trim();
CreatorName = new AcString(Save.SaveInstance.ReadByteArray(_offset + 0x838, 16), SaveType.CityFolk).Trim();
Name = new AcString(Save.SaveInstance.ReadByteArray(_offset + 0x84C, 32), SaveType.CityFolk).Trim();
Palette = Save.SaveInstance.ReadByte(_offset + 0x86F);
PaletteData = PatternData.CfPaletteData[Palette];
GeneratePatternBitmap();
break;
case SaveType.NewLeaf:
case SaveType.WelcomeAmiibo:
Name = new AcString(_saveFile.ReadByteArray(_offset, 0x2A), SaveType.NewLeaf).Trim();
CreatorName = new AcString(_saveFile.ReadByteArray(_offset + 0x2C, 0x14), SaveType.NewLeaf).Trim();
TownName = new AcString(_saveFile.ReadByteArray(_offset + 0x42, 0x14), SaveType.NewLeaf).Trim();
Name = new AcString(Save.SaveInstance.ReadByteArray(_offset, 0x2A), SaveType.NewLeaf).Trim();
CreatorName = new AcString(Save.SaveInstance.ReadByteArray(_offset + 0x2C, 0x14), SaveType.NewLeaf).Trim();
TownName = new AcString(Save.SaveInstance.ReadByteArray(_offset + 0x42, 0x14), SaveType.NewLeaf).Trim();
//No specific palette in NL/WA
GenerateNlPatternBitmap();
break;
@ -491,7 +489,7 @@ public void Read(int index)
public void RedrawBitmap()
{
switch (_saveFile.SaveGeneration)
switch (Save.SaveInstance.SaveGeneration)
{
case SaveGeneration.GCN:
case SaveGeneration.Wii:
@ -514,7 +512,7 @@ public void Import(uint[] bitmapBuffer)
// Convert to nibble map array of bytes
var patternBuffer = new byte[bitmapBuffer.Length / 2];
if (_saveFile.SaveGeneration == SaveGeneration.NDS || _saveFile.SaveGeneration == SaveGeneration.N3DS)
if (Save.SaveInstance.SaveGeneration == SaveGeneration.NDS || Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS)
{
for (var i = 0; i < patternBuffer.Length; i++)
{
@ -529,12 +527,12 @@ public void Import(uint[] bitmapBuffer)
for (var i = 0; i < convertedBuffer.Length; i++)
{
convertedBuffer[i] = PatternData.ClosestColorRgb(bitmapBuffer[i], PaletteData,
_saveFile.SaveGeneration == SaveGeneration.GCN);
Save.SaveInstance.SaveGeneration == SaveGeneration.GCN);
}
patternBuffer = PatternUtility.EncodeC4(convertedBuffer);
}
switch (_saveFile.SaveGeneration)
switch (Save.SaveInstance.SaveGeneration)
{
case SaveGeneration.GCN:
case SaveGeneration.Wii:
@ -553,36 +551,51 @@ public void Import(uint[] bitmapBuffer)
public void Write(byte[] newPatternData)
{
if (_saveFile.SaveGeneration == SaveGeneration.GCN)
if (Save.SaveInstance.SaveGeneration == SaveGeneration.GCN)
{
var patternNameSize = _saveFile.SaveType == SaveType.AnimalCrossing ? 0x10 : 0x0A;
_saveFile.Write(_offset, AcString.GetBytes(Name, patternNameSize));
_saveFile.Write(_offset + patternNameSize, Palette);
_saveFile.Write(_offset + 0x20, newPatternData);
var patternNameSize = Save.SaveInstance.SaveType == SaveType.AnimalCrossing ? 0x10 : 0x0A;
Save.SaveInstance.Write(_offset, AcString.GetBytes(Name, patternNameSize));
Save.SaveInstance.Write(_offset + patternNameSize, Palette);
Save.SaveInstance.Write(_offset + 0x20, newPatternData);
}
else switch (_saveFile.SaveType)
else switch (Save.SaveInstance.SaveType)
{
case SaveType.WildWorld:
_saveFile.Write(_offset, newPatternData);
Save.SaveInstance.Write(_offset, newPatternData);
// TODO: Town Name & Creator Name (Also for City Folk, New Leaf)
_saveFile.Write(_offset + 0x216, AcString.GetBytes(Name, 0x10));
_saveFile.Write(_offset + 0x226, (byte)(((Palette & 0x0F) << 4) | (Concept & 0x0F)));
Save.SaveInstance.Write(_offset + 0x216, AcString.GetBytes(Name, 0x10));
Save.SaveInstance.Write(_offset + 0x226, (byte)(((Palette & 0x0F) << 4) | (Concept & 0x0F)));
break;
case SaveType.CityFolk:
_saveFile.Write(_offset, newPatternData);
_saveFile.Write(_offset + 0x84C, AcString.GetBytes(Name, 0x20));
_saveFile.Write(_offset + 0x86F, Palette);
Save.SaveInstance.Write(_offset, newPatternData);
Save.SaveInstance.Write(_offset + 0x84C, AcString.GetBytes(Name, 0x20));
Save.SaveInstance.Write(_offset + 0x86F, Palette);
break;
default:
if (_saveFile.SaveGeneration == SaveGeneration.N3DS)
if (Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS)
{
_saveFile.Write(_offset, AcString.GetBytes(Name, 0x2A));
_saveFile.Write(_offset + 0x6C, newPatternData);
Save.SaveInstance.Write(_offset, AcString.GetBytes(Name, 0x2A));
Save.SaveInstance.Write(_offset + 0x6C, newPatternData);
// TODO: Write Palette (since it's customizable)
}
break;
}
}
public void Write()
{
switch (Save.SaveInstance.SaveGeneration)
{
case SaveGeneration.GCN:
case SaveGeneration.Wii:
Write(PatternUtility.EncodeC4(DecodedData));
break;
case SaveGeneration.NDS:
case SaveGeneration.N3DS:
Write(PatternUtility.CondenseNonBlockPattern(DecodedData));
break;
}
}
}
}

View file

@ -0,0 +1,39 @@
using System;
using ACSE.Core.Saves;
namespace ACSE.Core.Players.Flags
{
public static partial class Flags
{
// TODO: This will only work for gen1 games. The methods will have to check the save type when other games are supported.
public enum GoldenItemFlag
{
GoldenNet = 1,
GoldenAxe = 2,
GoldenShovel = 3,
GoldenRod = 4
}
private static int GetGoldenItemFlagsOffset(this Player player)
{
switch (Save.SaveInstance.SaveType)
{
case SaveType.DoubutsuNoMoriEPlus:
case SaveType.AnimalForestEPlus:
return player.Offset + 0x235A;
}
return -1;
}
private static byte GetGoldenItemFlags(this Player player) => GetGoldenItemFlagsOffset(player) == -1
? (byte) 0xFF
: Save.SaveInstance.ReadByte(GetGoldenItemFlagsOffset(player));
public static void ToggleGoldenItemRecievedFlag(this Player player, GoldenItemFlag flag, bool on) =>
Save.SaveInstance.Write(GetGoldenItemFlagsOffset(player), GetGoldenItemFlags(player).SetBit((byte) flag, on));
public static bool IsGoldenItemFlagSet(this Player player, GoldenItemFlag flag) =>
GetGoldenItemFlags(player).GetBit((byte) flag) == 1;
}
}

View file

@ -0,0 +1,59 @@
using System;
using ACSE.Core.Saves;
namespace ACSE.Core.Players.Flags
{
public static partial class Flags
{
private static readonly int[] mode_table_0 = {2, 4, 6};
private static readonly int[] mode_table_1 = {2, 3, 4, 5, 6, 7};
public enum ResetFlag : byte
{
UseGenericDialog = 5, // When unset, the dialog that is retrieved will be unique.
EnteredResetCenter = 6, // When unset, the unique dialog that is shown will be the dialog played when first entering the reset center.
MetDonResetti = 7 // When unset, the unique dialog that will be shown is Don & Resetti drama. Occurs after the 5th entry.
}
private static byte GetResetFlags(this Player player) => Save.SaveInstance.ReadByte(player.Offset + 0x235C);
public static int GetNextResetMode(this Player player)
{
var flags = player.GetResetFlags();
var type = flags & 0xF;
if (flags.GetBit(6) == 1)
{
if (player.Data.ResetCount < 5)
{
if (type >= 3)
{
type = 0;
}
return mode_table_0[type];
}
if (flags.GetBit(7) == 1)
{
if (type >= 6)
{
type = 0;
}
return mode_table_1[type];
}
return 1;
}
return 0;
}
public static void ToggleResetFlag(this Player player, ResetFlag resetFlag, bool on) =>
Save.SaveInstance.Write(player.Offset + 0x235C, player.GetResetFlags().SetBit((byte) resetFlag, on));
public static bool IsResetFlagEnabled(this Player player, ResetFlag resetFlag) =>
player.GetResetFlags().GetBit((byte) resetFlag) == 1;
}
}

View file

@ -19,15 +19,18 @@ public sealed class Player
public readonly int Index;
public readonly int Offset;
public bool Exists;
private readonly Save _saveData;
public Player(int offset, int idx, Save save)
public Player(int index)
{
Index = index;
}
public Player(int offset, int idx)
{
_saveData = save;
Index = idx;
Offset = offset;
Offsets = PlayerInfo.GetPlayerInfo(save.SaveType);
Exists = _saveData.ReadByte(offset + Offsets.Identifier) != 0 && _saveData.ReadByte(offset + Offsets.Identifier) != 0xFF;
Offsets = PlayerInfo.GetPlayerInfo(Save.SaveInstance.SaveType);
Exists = Save.SaveInstance.ReadByte(offset + Offsets.Identifier) != 0 && Save.SaveInstance.ReadByte(offset + Offsets.Identifier) != 0xFF;
if (!Exists) return;
var playerDataType = typeof(PlayerData);
@ -45,53 +48,53 @@ public Player(int offset, int idx, Save save)
switch (field.Name)
{
case "TownPassCardImage" when save.SaveGeneration == SaveGeneration.N3DS:
playerDataType.GetField("TownPassCardData").SetValue(boxedData, _saveData.ReadByteArray(dataOffset, 0x1400));
case "TownPassCardImage" when Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS:
playerDataType.GetField("TownPassCardData").SetValue(boxedData, Save.SaveInstance.ReadByteArray(dataOffset, 0x1400));
currentField.SetValue(boxedData,
ImageGeneration.GetTpcImage((byte[])playerDataType.GetField("TownPassCardData").GetValue(boxedData)));
break;
case "Reset" when save.SaveGeneration == SaveGeneration.GCN:
currentField.SetValue(boxedData, _saveData.ReadUInt32(dataOffset, _saveData.IsBigEndian) != 0);
case "Reset" when Save.SaveInstance.SaveGeneration == SaveGeneration.GCN:
currentField.SetValue(boxedData, Save.SaveInstance.ReadUInt32(dataOffset, Save.SaveInstance.IsBigEndian) != 0);
break;
default:
if (fieldType == typeof(byte))
currentField.SetValue(boxedData, _saveData.ReadByte(dataOffset));
currentField.SetValue(boxedData, Save.SaveInstance.ReadByte(dataOffset));
else if (fieldType == typeof(byte[]) && playerSaveInfoType.GetField(field.Name + "Count") != null)
currentField.SetValue(boxedData, _saveData.ReadByteArray(dataOffset,
currentField.SetValue(boxedData, Save.SaveInstance.ReadByteArray(dataOffset,
(int)playerSaveInfoType.GetField(field.Name + "Count").GetValue(Offsets)));
else if (fieldType == typeof(ushort))
currentField.SetValue(boxedData, _saveData.ReadUInt16(dataOffset, _saveData.IsBigEndian));
currentField.SetValue(boxedData, Save.SaveInstance.ReadUInt16(dataOffset, Save.SaveInstance.IsBigEndian));
else if (fieldType == typeof(ushort[]))
currentField.SetValue(boxedData, _saveData.ReadUInt16Array(dataOffset,
(int)playerSaveInfoType.GetField(field.Name + "Count").GetValue(Offsets), _saveData.IsBigEndian));
currentField.SetValue(boxedData, Save.SaveInstance.ReadUInt16Array(dataOffset,
(int)playerSaveInfoType.GetField(field.Name + "Count").GetValue(Offsets), Save.SaveInstance.IsBigEndian));
else if (fieldType == typeof(uint))
currentField.SetValue(boxedData, _saveData.ReadUInt32(dataOffset, _saveData.IsBigEndian));
currentField.SetValue(boxedData, Save.SaveInstance.ReadUInt32(dataOffset, Save.SaveInstance.IsBigEndian));
else if (fieldType == typeof(string))
currentField.SetValue(boxedData, new AcString(_saveData.ReadByteArray(dataOffset,
(int)playerSaveInfoType.GetField(field.Name + "Size").GetValue(Offsets)), _saveData.SaveType).Trim());
currentField.SetValue(boxedData, new AcString(Save.SaveInstance.ReadByteArray(dataOffset,
(int)playerSaveInfoType.GetField(field.Name + "Size").GetValue(Offsets)), Save.SaveInstance.SaveType).Trim());
else if (fieldType == typeof(Inventory))
if (save.SaveGeneration == SaveGeneration.N3DS)
currentField.SetValue(boxedData, new Inventory(_saveData.ReadUInt32Array(dataOffset,
if (Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS)
currentField.SetValue(boxedData, new Inventory(Save.SaveInstance.ReadUInt32Array(dataOffset,
(int)playerSaveInfoType.GetField(field.Name + "Count").GetValue(Offsets), false)));
else
currentField.SetValue(boxedData, new Inventory(_saveData.ReadUInt16Array(dataOffset,
(int)playerSaveInfoType.GetField(field.Name + "Count").GetValue(Offsets), _saveData.IsBigEndian), save, this));
currentField.SetValue(boxedData, new Inventory(Save.SaveInstance.ReadUInt16Array(dataOffset,
(int)playerSaveInfoType.GetField(field.Name + "Count").GetValue(Offsets), Save.SaveInstance.IsBigEndian), this));
else if (fieldType == typeof(Item))
if (save.SaveGeneration == SaveGeneration.N3DS)
currentField.SetValue(boxedData, new Item(_saveData.ReadUInt32(dataOffset, false)));
if (Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS)
currentField.SetValue(boxedData, new Item(Save.SaveInstance.ReadUInt32(dataOffset, false)));
else
currentField.SetValue(boxedData, new Item(_saveData.ReadUInt16(dataOffset, _saveData.IsBigEndian)));
currentField.SetValue(boxedData, new Item(Save.SaveInstance.ReadUInt16(dataOffset, Save.SaveInstance.IsBigEndian)));
else if (fieldType == typeof(Item[]))
{
if (field.Name.Equals("Dressers"))
{
switch (_saveData.SaveGeneration)
switch (Save.SaveInstance.SaveGeneration)
{
case SaveGeneration.NDS:
dataOffset = _saveData.SaveDataStartOffset + 0x15430 + 0xB4 * Index; // Terrible hack
dataOffset = Save.SaveInstance.SaveDataStartOffset + 0x15430 + 0xB4 * Index; // Terrible hack
break;
case SaveGeneration.Wii:
dataOffset = _saveData.SaveDataStartOffset + 0x1F3038 + 0x140 * Index;
dataOffset = Save.SaveInstance.SaveDataStartOffset + 0x1F3038 + 0x140 * Index;
break;
}
}
@ -99,28 +102,28 @@ public Player(int offset, int idx, Save save)
var itemArray = new Item[(int)playerSaveInfoType.GetField(field.Name + "Count").GetValue(Offsets)];
for (var i = 0; i < itemArray.Length; i++)
{
if (save.SaveGeneration == SaveGeneration.N3DS)
itemArray[i] = new Item(_saveData.ReadUInt32(dataOffset + i * 4, false));
if (Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS)
itemArray[i] = new Item(Save.SaveInstance.ReadUInt32(dataOffset + i * 4, false));
else
itemArray[i] = new Item(_saveData.ReadUInt16(dataOffset + i * 2, _saveData.IsBigEndian));
itemArray[i] = new Item(Save.SaveInstance.ReadUInt16(dataOffset + i * 2, Save.SaveInstance.IsBigEndian));
}
currentField.SetValue(boxedData, itemArray);
}
else if (fieldType == typeof(NewLeafInt32))
{
var intData = _saveData.ReadUInt32Array(dataOffset, 2);
var intData = Save.SaveInstance.ReadUInt32Array(dataOffset, 2);
currentField.SetValue(boxedData, new NewLeafInt32(intData[0], intData[1]));
}
else if (fieldType == typeof(AcDate) && dataOffset > 0)
{
currentField.SetValue(boxedData, new AcDate(_saveData.ReadByteArray(dataOffset,
currentField.SetValue(boxedData, new AcDate(Save.SaveInstance.ReadByteArray(dataOffset,
(int)playerSaveInfoType.GetField(field.Name + "Size").GetValue(Offsets))));
}
break;
}
}
Data = (PlayerData)boxedData;
switch (save.SaveType)
switch (Save.SaveInstance.SaveType)
{
case SaveType.WildWorld:
var condensedData = Data.HairColor;
@ -149,24 +152,24 @@ public Player(int offset, int idx, Save save)
{
Data.Patterns = new Pattern[Offsets.PatternCount];
for (var i = 0; i < Data.Patterns.Length; i++)
Data.Patterns[i] = new Pattern(offset + Offsets.Patterns + Offsets.PatternSize * i, i, save);
Data.Patterns[i] = new Pattern(offset + Offsets.Patterns + Offsets.PatternSize * i, i);
}
if (_saveData.SaveType == SaveType.CityFolk)
if (Save.SaveInstance.SaveType == SaveType.CityFolk)
{
Data.Reset = (_saveData.ReadByte(Offset + 0x8670) & 0x02) == 0x02;
Data.Reset = (Save.SaveInstance.ReadByte(Offset + 0x8670) & 0x02) == 0x02;
}
else if (_saveData.SaveType == SaveType.NewLeaf)
else if (Save.SaveInstance.SaveType == SaveType.NewLeaf)
{
Data.Reset = (_saveData.ReadByte(Offset + 0x5702) & 0x02) == 0x02;
Data.Reset = (Save.SaveInstance.ReadByte(Offset + 0x5702) & 0x02) == 0x02;
}
else if (_saveData.SaveType == SaveType.WelcomeAmiibo)
else if (Save.SaveInstance.SaveType == SaveType.WelcomeAmiibo)
{
Data.Reset = (_saveData.ReadByte(Offset + 0x570A) & 0x02) == 0x02;
Data.Reset = (Save.SaveInstance.ReadByte(Offset + 0x570A) & 0x02) == 0x02;
}
// Get the Player's House
House = HouseInfo.GetHouse(this, save.SaveType);
House = HouseInfo.GetHouse(this, Save.SaveInstance.SaveType);
if (House != null)
{
if (House.Data.Bed != null)
@ -178,11 +181,11 @@ public Player(int offset, int idx, Save save)
Console.WriteLine($"Player {Index}'s house = {House}");
// Mail Test
if (_saveData.SaveGeneration != SaveGeneration.GCN) return;
if (Save.SaveInstance.SaveGeneration != SaveGeneration.GCN) return;
{
for (var i = 0; i < 10; i++)
{
var mail = new GcnPlayerMail(_saveData, this, i);
//var mail = new GcnPlayerMail(Save.SaveInstance, this, i);
//System.Windows.Forms.MessageBox.Show(Mail.GetFormattedMailString());
}
}
@ -191,7 +194,7 @@ public Player(int offset, int idx, Save save)
public void Write()
{
// Set City Folk Bed first
if (_saveData.SaveGeneration == SaveGeneration.Wii && House != null && Data.Bed != null)
if (Save.SaveInstance.SaveGeneration == SaveGeneration.Wii && House != null && Data.Bed != null)
{
House.Data.Bed = Data.Bed;
Data.Bed = null;
@ -210,21 +213,21 @@ public void Write()
var dataOffset = Offset + (int)field.GetValue(Offsets);
switch (field.Name)
{
case "TownPassCardImage" when _saveData.SaveGeneration == SaveGeneration.N3DS:
_saveData.Write(dataOffset, Data.TownPassCardData);
case "TownPassCardImage" when Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS:
Save.SaveInstance.Write(dataOffset, Data.TownPassCardData);
break;
case "Reset" when _saveData.SaveGeneration == SaveGeneration.GCN:
_saveData.Write(dataOffset, Data.Reset ? (uint)0x250C : (uint)0 ,_saveData.IsBigEndian);
case "Reset" when Save.SaveInstance.SaveGeneration == SaveGeneration.GCN:
Save.SaveInstance.Write(dataOffset, Data.Reset ? (uint)0x250C : (uint)0 ,Save.SaveInstance.IsBigEndian);
break;
default:
if (fieldType == typeof(string))
{
_saveData.Write(dataOffset, AcString.GetBytes((string)playerDataType.GetField(field.Name).GetValue(Data),
Save.SaveInstance.Write(dataOffset, AcString.GetBytes((string)playerDataType.GetField(field.Name).GetValue(Data),
(int)playerSaveInfoType.GetField(field.Name + "Size").GetValue(Offsets)));
}
else if (fieldType == typeof(byte))
{
if (_saveData.SaveType == SaveType.WildWorld)
if (Save.SaveInstance.SaveType == SaveType.WildWorld)
{
switch (field.Name)
{
@ -232,85 +235,85 @@ public void Write()
{
var condensedData = (byte)(Data.HairColor & 0x0F); //Remove upper nibble just incase
condensedData += (byte)((Data.Tan & 0x0F) << 4); //Add in tan to the byte
_saveData.Write(dataOffset, condensedData);
Save.SaveInstance.Write(dataOffset, condensedData);
break;
}
case "HairType":
{
var condensedData = (byte)(Data.FaceType & 0x0F);
condensedData += (byte)((Data.HairType & 0x0F) << 4);
_saveData.Write(dataOffset, condensedData);
Save.SaveInstance.Write(dataOffset, condensedData);
break;
}
default:
_saveData.Write(dataOffset, (byte)playerDataType.GetField(field.Name).GetValue(Data));
Save.SaveInstance.Write(dataOffset, (byte)playerDataType.GetField(field.Name).GetValue(Data));
break;
}
}
else if (_saveData.SaveType == SaveType.CityFolk)
else if (Save.SaveInstance.SaveType == SaveType.CityFolk)
{
switch (field.Name)
{
case "Tan":
var shiftedData = (byte)(Data.Tan << 1); //ACToolkit does this
_saveData.Write(dataOffset, shiftedData);
Save.SaveInstance.Write(dataOffset, shiftedData);
break;
case "FaceType":
_saveData.Write(dataOffset, (byte)(Data.EyeColor + Data.FaceType));
Save.SaveInstance.Write(dataOffset, (byte)(Data.EyeColor + Data.FaceType));
break;
default:
_saveData.Write(dataOffset, (byte)playerDataType.GetField(field.Name).GetValue(Data));
Save.SaveInstance.Write(dataOffset, (byte)playerDataType.GetField(field.Name).GetValue(Data));
break;
}
}
else
{
_saveData.Write(dataOffset, (byte)playerDataType.GetField(field.Name).GetValue(Data));
Save.SaveInstance.Write(dataOffset, (byte)playerDataType.GetField(field.Name).GetValue(Data));
}
}
else if (fieldType == typeof(ushort))
{
_saveData.Write(dataOffset, (ushort)playerDataType.GetField(field.Name).GetValue(Data), _saveData.IsBigEndian);
Save.SaveInstance.Write(dataOffset, (ushort)playerDataType.GetField(field.Name).GetValue(Data), Save.SaveInstance.IsBigEndian);
}
else if (fieldType == typeof(uint))
{
_saveData.Write(dataOffset, (uint)playerDataType.GetField(field.Name).GetValue(Data), _saveData.IsBigEndian);
Save.SaveInstance.Write(dataOffset, (uint)playerDataType.GetField(field.Name).GetValue(Data), Save.SaveInstance.IsBigEndian);
}
else if (fieldType == typeof(Inventory))
{
if (_saveData.SaveGeneration == SaveGeneration.N3DS)
if (Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS)
{
var items = new uint[Offsets.PocketsCount];
for (var i = 0; i < items.Length; i++)
items[i] = ItemData.EncodeItem(Data.Pockets.Items[i]);
_saveData.Write(dataOffset, items);
Save.SaveInstance.Write(dataOffset, items);
}
else
{
var items = new ushort[Offsets.PocketsCount];
for (var i = 0; i < items.Length; i++)
items[i] = Data.Pockets.Items[i].ItemId;
_saveData.Write(dataOffset, items, _saveData.IsBigEndian);
Save.SaveInstance.Write(dataOffset, items, Save.SaveInstance.IsBigEndian);
}
}
else if (fieldType == typeof(Item))
{
var item = (Item)playerDataType.GetField(field.Name).GetValue(Data);
if (_saveData.SaveGeneration == SaveGeneration.N3DS)
if (Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS)
{
_saveData.Write(dataOffset, item.ToUInt32());
Save.SaveInstance.Write(dataOffset, item.ToUInt32());
}
else
{
if (field.Name.Equals("Shirt") &&
(_saveData.SaveGeneration == SaveGeneration.N64 || _saveData.SaveGeneration == SaveGeneration.GCN ||
_saveData.SaveGeneration == SaveGeneration.iQue)) // For some reason, the shirt lower byte is also stored before the actual item id.
(Save.SaveInstance.SaveGeneration == SaveGeneration.N64 || Save.SaveInstance.SaveGeneration == SaveGeneration.GCN ||
Save.SaveInstance.SaveGeneration == SaveGeneration.iQue)) // For some reason, the shirt lower byte is also stored before the actual item id.
{
_saveData.Write(dataOffset - 1, new[] { (byte)item.ItemId, (byte)(item.ItemId >> 8), (byte)item.ItemId }, _saveData.IsBigEndian);
Save.SaveInstance.Write(dataOffset - 1, new[] { (byte)item.ItemId, (byte)(item.ItemId >> 8), (byte)item.ItemId }, Save.SaveInstance.IsBigEndian);
}
else
{
_saveData.Write(dataOffset, item.ItemId, _saveData.IsBigEndian);
Save.SaveInstance.Write(dataOffset, item.ItemId, Save.SaveInstance.IsBigEndian);
}
}
}
@ -319,41 +322,41 @@ public void Write()
var itemArray = (Item[])playerDataType.GetField(field.Name).GetValue(Data);
if (field.Name.Equals("Dressers"))
{
switch (_saveData.SaveGeneration)
switch (Save.SaveInstance.SaveGeneration)
{
case SaveGeneration.NDS:
dataOffset = _saveData.SaveDataStartOffset + 0x15430 + 0xB4 * Index; // Terrible hack
dataOffset = Save.SaveInstance.SaveDataStartOffset + 0x15430 + 0xB4 * Index; // Terrible hack
break;
case SaveGeneration.Wii:
dataOffset = _saveData.SaveDataStartOffset + 0x1F3038 + 0x140 * Index;
dataOffset = Save.SaveInstance.SaveDataStartOffset + 0x1F3038 + 0x140 * Index;
break;
}
}
for (var i = 0; i < itemArray.Length; i++)
{
if (_saveData.SaveGeneration == SaveGeneration.N3DS)
_saveData.Write(dataOffset + i * 4, itemArray[i].ToUInt32());
if (Save.SaveInstance.SaveGeneration == SaveGeneration.N3DS)
Save.SaveInstance.Write(dataOffset + i * 4, itemArray[i].ToUInt32());
else
_saveData.Write(dataOffset + i * 2, itemArray[i].ItemId, _saveData.IsBigEndian);
Save.SaveInstance.Write(dataOffset + i * 2, itemArray[i].ItemId, Save.SaveInstance.IsBigEndian);
}
}
else if (fieldType == typeof(NewLeafInt32))
{
if (_saveData.SaveGeneration == SaveGeneration.NDS)
if (Save.SaveInstance.SaveGeneration == SaveGeneration.NDS)
{
var encryptedInt = (NewLeafInt32)playerDataType.GetField(field.Name).GetValue(Data);
_saveData.Write(dataOffset, encryptedInt.Int1);
_saveData.Write(dataOffset + 4, encryptedInt.Int2);
Save.SaveInstance.Write(dataOffset, encryptedInt.Int1);
Save.SaveInstance.Write(dataOffset + 4, encryptedInt.Int2);
}
}
else if (fieldType == typeof(AcDate) && (_saveData.SaveGeneration == SaveGeneration.GCN ||
_saveData.SaveGeneration == SaveGeneration.NDS ||
_saveData.SaveGeneration == SaveGeneration.Wii))
else if (fieldType == typeof(AcDate) && (Save.SaveInstance.SaveGeneration == SaveGeneration.GCN ||
Save.SaveInstance.SaveGeneration == SaveGeneration.NDS ||
Save.SaveInstance.SaveGeneration == SaveGeneration.Wii))
{
if (field.Name.Equals("Birthday"))
{
_saveData.Write(dataOffset, ((AcDate)playerDataType.GetField(field.Name).GetValue(Data)).ToMonthDayDateData());
Save.SaveInstance.Write(dataOffset, ((AcDate)playerDataType.GetField(field.Name).GetValue(Data)).ToMonthDayDateData());
}
}

View file

@ -108,6 +108,7 @@ public struct PlayerData
public AcDate RegisterDate;
public AcDate Birthday;
public bool Reset;
public byte ResetCount;
public byte Gender;
public byte HairType;
public byte HairColor;
@ -313,7 +314,7 @@ public static class PlayerInfo
TownIdentifierSize = 2,
Gender = 0x10, //
FaceType = 0x11, //
// ResetCounter = 0x13
ResetCount = 0x13,
Pockets = 0x64,
PocketsCount = 15,
Bells = 0x94,
@ -322,6 +323,7 @@ public static class PlayerInfo
HeldItem = 0x874,
InventoryBackground = 0xFF0,
Shirt = 0xFF6,
// Luck = 0x1014,
Birthday = 0x1018,
BirthdaySize = 2,
Reset = 0x1064,
@ -357,7 +359,6 @@ public static class PlayerInfo
NewLeafWallet = -1,
MeowCoupons = -1,
IslandMedals = -1,
ResetCount = -1,
IslandBox = -1,
};

View file

@ -1,7 +1,10 @@
using System;
using System.Security.Cryptography.X509Certificates;
using ACSE.Core.Players;
using ACSE.Core.Saves;
using ACSE.Core.Villagers;
namespace ACSE.Core.Villagers.Quests
namespace ACSE.Core.Quests
{
public enum QuestCategory
{
@ -51,6 +54,45 @@ public enum QuestContestType
public static class GCNQuests
{
// TODO: This should be moved to a generic quests class.
private static int GetErrandQuestInfoOffset()
{
switch (Save.SaveInstance.SaveType)
{
case SaveType.DoubutsuNoMori:
case SaveType.DongwuSenlin:
return 0xEE3C;
case SaveType.DoubutsuNoMoriPlus:
return 0x19804;
case SaveType.AnimalCrossing:
return 0x20550;
case SaveType.DoubutsuNoMoriEPlus:
case SaveType.AnimalForestEPlus:
return 0x22478;
default:
return -1;
}
}
public static bool IsPartTimeJobActive(this Player player)
{
var offset = GetErrandQuestInfoOffset();
return offset != -1 && Save.SaveInstance.ReadUInt32(offset, true, true).GetBit(player.Index + 2) == 1;
}
public static void SetPartTimeJobStatus(this Player player, bool enabled)
{
var offset = GetErrandQuestInfoOffset();
if (offset == -1) return;
var currentValue = Save.SaveInstance.ReadUInt32(offset, true, true);
Save.SaveInstance.Write(offset, currentValue.SetBit(player.Index + 2, enabled), true, true);
}
public static void GetCurrentQuest(Save save, Villager villager)
{
byte questInfo;

View file

@ -3,7 +3,11 @@
using System.IO;
using System.Text;
using ACSE.Core.Debug;
using ACSE.Core.Housing;
using ACSE.Core.Items;
using ACSE.Core.Players;
using ACSE.Core.Saves.Checksums;
using ACSE.Core.Town.Acres;
using ACSE.Core.Utilities;
namespace ACSE.Core.Saves
@ -46,10 +50,12 @@ public enum Region : byte
China
}
public class Save
public sealed class Save
{
public static Save SaveInstance { get; private set; }
// Publics
public readonly SaveType SaveType;
public readonly SaveGeneration SaveGeneration;
public readonly SaveInfo SaveInfo;
@ -63,6 +69,82 @@ public class Save
public readonly bool IsBigEndian = true;
public bool ChangesMade;
public readonly bool SuccessfullyLoaded = true;
// Public events
/// <summary>
/// Fires when the currently selected <see cref="Item"/> is changed.
/// </summary>
public event EventHandler<ItemChangedEventArgs> SelectedItemChanged;
/// <summary>
/// Fires when the currently selected <see cref="Player"/> is changed. The <see cref="EventHandler"/> contains a reference to the previously selected <see cref="Player"/>.
/// </summary>
public event EventHandler<Player> SelectedPlayerChanged;
/// <summary>
/// Fires when the currently selected <see cref="House"/> is changed. The <see cref="EventHandler"/> contains a reference to the previously selected <see cref="House"/>.
/// </summary>
public event EventHandler<House> SelectedHouseChanged;
/// <summary>
/// Fires when the currently selected <see cref="Acre"/> is changed. The <see cref="EventHandler"/> contains a reference to the previously selected <see cref="Acre"/>.
/// </summary>
public event EventHandler<Acre> SelectedAcreChanged;
// Public Game-related Info
public Player[] Players { get; private set; }
public Acre[] Acres { get; private set; }
public WorldAcre[] WorldAcres { get; private set; }
public House[] Houses { get; private set; }
private Item _selectedItem;
public Item SelectedItem
{
get => _selectedItem;
set
{
SelectedItemChanged?.Invoke(this, new ItemChangedEventArgs{ PreviousItem = _selectedItem, NewItem = value});
_selectedItem = value;
}
}
private Player _selectedPlayer;
public Player SelectedPlayer
{
get => _selectedPlayer;
set
{
SelectedPlayerChanged?.Invoke(this, _selectedPlayer);
_selectedPlayer = value;
}
}
private House _selectedHouse;
public House SelectedHouse
{
get => _selectedHouse;
set
{
SelectedHouseChanged?.Invoke(this, _selectedHouse);
_selectedHouse = value;
}
}
private Acre _selectedAcre;
public Acre SelectedAcre
{
get => _selectedAcre;
set
{
SelectedAcreChanged?.Invoke(this, _selectedAcre);
_selectedAcre = value;
}
}
// Privates
private FileStream _saveFile;
private readonly BinaryReader _saveReader;
private BinaryWriter _saveWriter;
@ -300,6 +382,8 @@ public void Close(bool save)
_saveFile?.Dispose();
}
// Data methods
public void Write(int offset, byte value, bool includeStartOffset = false)
{
if (includeStartOffset) offset += SaveDataStartOffset;
@ -494,8 +578,8 @@ public ulong ReadUInt64(int offset, bool reversed = false, bool includeStartOffs
return value;
}
public string ReadString(int offset, int length) =>
new AcString(ReadByteArray(offset, length), SaveType).Trim();
public string ReadString(int offset, int length, bool includeStartOffset = false) =>
new AcString(ReadByteArray(offset, length, false, includeStartOffset), SaveType).Trim();
public string ReadAsciiString(int offset, int length = -1, bool includeStartOffset = false)
{

View file

@ -114,7 +114,7 @@ public static class SaveDataManager
BuriedData = 0xF43C,
BuriedDataSize = 0x3C0,
Checksum = 0x12,
GrassType = -1, // Find
GrassType = -1, // Has no grass type.
};
public static readonly Offsets DoubutsuNoMoriPlusOffsets = new Offsets
@ -242,7 +242,7 @@ public static class SaveDataManager
BuriedData = 0xF43C,
BuriedDataSize = 0x3C0,
Checksum = 0x12,
GrassType = -1, // Find
GrassType = -1, // Has no grass types.
};
public static readonly Offsets WildWorldOffsets = new Offsets
@ -284,6 +284,8 @@ public static class SaveDataManager
SaveSize = 0x40F340,
PlayerStart = 0,
PlayerSize = 0x86C0,
VillagerData = 0x21B20,
VillagerSize = 0x3040,
Buildings = 0x5EB0A,
BuildingsCount = 0x33, //Not sure
AcreData = 0x68414, //Don't forget about the additional acres before?
@ -307,7 +309,6 @@ public static class SaveDataManager
IslandWorldData = -1,
PastVillagers = -1,
PublicWorkProjects = -1,
VillagerData = -1, //finish this sometime
IslandAcreData = -1,
IslandBuildings = -1,
TrainStationType = -1,

View file

@ -1,4 +1,5 @@
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using ACSE.Core.Debug;
@ -145,6 +146,22 @@ public bool SetItemBuried(Item item, bool buried, SaveGeneration generation)
return IsItemBuried(item, generation);
}
public bool FindItem(ushort requestedItem, out int x, out int y)
{
x = y = -1;
if (Items == null || Items.Any(i => i.ItemId == requestedItem) == false) return false;
for (var i = 0; i < 256; i++)
if (Items[i].ItemId == requestedItem)
{
x = i % 16;
y = i / 16;
return true;
}
return false;
}
/// <summary>
/// Loads the Acre's default <see cref="Item"/>s from a file.
/// </summary>
@ -188,5 +205,15 @@ public bool LoadDefaultItems(Save saveFile)
return false;
}
// TODO: Create an easier to use acre image manager to reduce memory footprint.
public Image AcreImage
{
get
{
return null;
}
set { }
}
}
}

View file

@ -29,7 +29,15 @@ public sealed class Island
private const int BuriedData = 0x15A0;
private const int IslandLeftAcreData = 0x15E0;
private const int IslandRightAcreData = 0x15E1;
private const int IslandGrassType = 0x15F8;
private const int IslandInfoFlag = 0x15FB;
// Info:
// 0x00000000 = Haven't spoken to islander yet.
// Current Year, Month, Day = Spoke to islander, wll build house on next reload.
// 0xFFFFFFFF = House has been built.
// 0x80008080 = Reset islander by importing a new islander via the wishing well after house is built.
private const int IslanderAppearYearMonthDay = 0x1600;
#endregion
@ -80,8 +88,8 @@ public Island(int offset, IEnumerable<Player> players, Save saveFile)
Cabana = new House(-1, offset + CottageData, 1, 0);
Cabana.Data.Rooms[0].Name = "Cabana";
FlagPattern = new Pattern(offset + FlagData, 0, saveFile);
Islander = new Villager(offset + IslanderData, 0, saveFile);
FlagPattern = new Pattern(offset + FlagData, 0);
Islander = new Villager(offset + IslanderData, 15, saveFile);
Purchased = IsPurchased();
IslandLeftAcreIndex = saveFile.ReadByte(offset + IslandLeftAcreData);
@ -123,10 +131,12 @@ private static ushort IslandAcreIndexToIslandAcreId(byte side, byte index)
}
}
// TODO: Make a toggle to enable/disable the island.
private bool IsPurchased()
=> (_saveFile.ReadByte(_offset + IslandInfoFlag) & 0x80) == 0x80;
public void SetPurchased(bool purchased)
=> _saveFile.Write(_offset + IslandInfoFlag, _saveFile.ReadByte(_offset + IslandInfoFlag).SetBit(7, purchased));
public ushort[] GetAcreIds()
{
return new[] { IslandAcreIndexToIslandAcreId(0, IslandLeftAcreIndex), IslandAcreIndexToIslandAcreId(1, IslandRightAcreIndex) };
@ -196,6 +206,31 @@ public bool SetItemBuried(WorldAcre acre, Item item, bool buried, SaveGeneration
return IsItemBuried(acre, item, generation);
}
private bool FindIslandItem(ushort itemId, out int acreX, out int x, out int y)
{
acreX = x = y = -1;
for (var i = 0; i < 2; i++)
if (Acres[i].FindItem(itemId, out x, out y))
{
acreX = 4 + i;
return true;
}
return false;
}
// NOTE: The "castaway" islander will not spawn if the house coordinates are not set.
public void ResetIslanderHasAppeared()
{
// Search for Islander House.
if (FindIslandItem(0x5851, out var acreX, out var x, out var y))
Acres[acreX - 4].Items[y * 16 + x] = new Item(0x5871); // Replace it with the islander sign.
else if (FindIslandItem(0x5871, out acreX, out x, out y) == false) return; // If we don't find the sign then return immediately.
Islander.Data.HouseCoordinates = new byte[] { (byte)acreX, 8, (byte)x, (byte)y }; // Update "House Coordinates", which point to the sign.
_saveFile.Write(_offset + IslanderAppearYearMonthDay, 0u, true); // Reset the "appear date" which is actually the date the house is built.
}
public void Write()
{
if (Owner != null)
@ -218,7 +253,8 @@ public void Write()
// Save Cottage
Cabana.Data.Rooms[0].Write();
// TODO: Save Islander
//Save Islander
Islander.Write(TownName);
// Save Buried Data
_saveFile.Write(_offset + BuriedData, BuriedDataArray);

View file

@ -33,8 +33,7 @@ public AcDate()
Year = (uint)now.Year;
IsPm = Hour >= 12;
DateTimeString =
$"{((Hour % 12) == 0 ? 12 : Hour % 12)}:{Minute:D2}:{Second:D2} {(IsPm ? "PM" : "AM")}, {Month}/{Day}/{Year}";
DateTimeString = Format("(h):(m):(s) (a), (M)/(d)/(y)");
}
public AcDate(byte[] dateData)
@ -78,6 +77,11 @@ public AcDate(byte[] dateData)
Day = dateData[0];
Month = dateData[1];
break;
case 3:
Day = dateData[0];
Month = dateData[1];
Year = 2000u + dateData[2];
break;
case 4:
case 8:
break;
@ -101,8 +105,7 @@ public AcDate(byte[] dateData)
}
IsPm = Hour >= 12;
DateTimeString =
$"{((Hour % 12) == 0 ? 12 : Hour % 12)}:{Minute:D2}:{Second:D2} {(IsPm ? "PM" : "AM")}, {Month}/{Day}/{Year}";
DateTimeString = Format("(h):(m):(s) (a), (M)/(d)/(y)");
}
public string Format(string formatString)
@ -114,11 +117,16 @@ public string Format(string formatString)
formatString = formatString.Replace("(d)", Day.ToString());
formatString = formatString.Replace("(D)", Day.ToString("D2"));
formatString = formatString.Replace("(w)", DayOfWeek.ToString());
formatString = formatString.Replace("(W)", Enum.GetName(typeof(DayOfWeek), DayOfWeek));
formatString = formatString.Replace("(mo)", Months[Month]);
formatString = formatString.Replace("(W)", ((DayOfWeek)DayOfWeek).ToString());
if (formatString.Contains("(mo)"))
{
formatString = formatString.Replace("(mo)", Months[Month]);
}
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("(Y)", Year.ToString("D4").Substring(2, 2));
formatString = formatString.Replace("(a)", IsPm ? "PM" : "AM");
formatString = formatString.Replace("(A)", IsPm ? "P.M." : "A.M.");
return formatString;
@ -159,6 +167,13 @@ public byte[] ToYearMonthDayDateData()
(byte)Month,
(byte)Day
};
case SaveGeneration.NDS:
return new[]
{
(byte)Day,
(byte)Month,
(byte)Year
};
case SaveGeneration.N3DS:
return new[]
{

View file

@ -102,14 +102,14 @@ internal static class CharacterSets
public static string[] DongwuSenlinCharacterSet =
{
"\0", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "矮", "C", "E", "F", "a",
" ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "矮", "C", "E", "F", "a",
"c", "g", "o", "—", "!", "P", ",", "?", "e", "A", "i", "m", "、", "r", "t", "u",
"\r", "安", "按", "吧", "白", "百", "板", "帮", "贝", "壁", "便", "不", "布", "场", "超", "沈",
" ", "安", "按", "吧", "白", "百", "板", "帮", "贝", "壁", "便", "不", "布", "场", "超", "沈",
"寸", "大", "到", "的", "地", "第", "点", "电", "对", "儿", "尔", "分", "服", "高", "个", "给",
"公", "好", "合", "很", "红", "后", "花", "会", "货", "级", "金", "卡", "可", "蓝", "老", "利",
"了", "鲁", "吗", "猫", "么", "没", "抹", "能", "你", "片", "钱", "球", "曲", "认", "色", "衫",
"上", "时", "什", "实", "识", "事", "是", "市", "收", "梳", "叔", "司", "我", "午", "西", "下",
"相", "以", "印", "有", "杂", "再", "这", "纸", "妆", "组", "俑", "咪", "小", "\n", "\t", "□",
"相", "以", "印", "有", "杂", "再", "这", "纸", "妆", "组", "俑", "咪", "小", "\n", " ", "□",
"G", "取", "消", "子", "衣", "鱼", "伞", "桌", "格", "椅", "机", "未", "柜", "确", "圣", "方",
"月", "节", "券", "奖", "抽", "橱", "彩", "绿", "毛", "号", "龙", "之", "音", "黄", "人", "发",
"黑", "沙", "雪", "钟", "名", "东", "草", "信", "床", "画", "爱", "诞", "致", "别", "条", "书",
@ -206,159 +206,159 @@ internal static class CharacterSets
"羡", "□", "故", "降", "铺", "蛮", "扩", "渐", "仅", "谓", "□", "砍", "腾", "况", "糊", "称",
"□", "乘", "柄", "圆", "哭", "限", "诚", "畅", "拾", "□", "队", "蒙", "俩", "□", "绍", "擦",
"搭", "貌", "饶", "养", "□", "郁", "岂", "淋", "领", "营", "联", "怜", "□", "□", "耍", "胆",
"禅", "□", "碌", "菜", "扰", "=", "+", "筋", "□", "湿", "酬", "责", "昆", "状", "闻", "□",
"□", "弯", "嘴", "她", "赢", "验", "犯", "牢", "副", "逃", "嘟", "祝", "怨", "悔", "佩", "□",
"□", "咱", "漆", "势", "悉", "剧", "肥", "引", "□", "假", "抵", "唬", "争", "窝", "另", "甩",
"□", "途", "严", "删", "愧", "咚", "聪", "产", "瞎", "□", "志", "追", "□", "邻", "某", "晃",
"岁", "眠", "址", "奏", "案", "斗", "泄", "欣", "汇", "倦", "□", "展", "摔", "", "缺", "哗",
"p", "乖", "暗", "制", "朵", "肿", "祟", "株", "", "扮", "暂", "塔", "□", "□", "元", "烈",
"汗", "劳", "嚯", "勉", "凭", "□", "鼻", "证", "□", "卧", "姐", "默", "搜", "签", "亳", "迢",
"船", "□", "敬", "振", "列", "共", "哩", "忧", "羞", "贪", "犹", "谈", "", "撒", "捣", "汉",
"环", "嗬", "废", "豫", "洋", "谎", "依", "避", "欲", "团", "笨", "创", "额", "兮", "泳", "速",
"伸", "挥", "疲", "锁", "铲", "核", "□", "余", "贺", "□", "显", "唉", "□", "刮", "虚", "吞",
"硬", "纯", "汤", "□", "勤", "拒", "攒", "套", "盯", "□", "呲", "测", "踢", "众", "增", "技",
"诀", "盘", "富", "肠", "属", "抢", "狠", "□", "嫌", "炮", "背", "氛", "九", "零", "b", "效",
"晒", "闯", "坑", "绑", "脖", "阴", "夸", "仿", "基", "盖", "帅", "政", "□", "恙", "佳", "□",
"私", "社", "纯", "奔", "缠", "咋", "炸", "撞", "率", "境", "透", "牙", "丰", "研", "摸", "缩",
"捷", "耶", "野", "恩", "叽", "呤", "判", "庞", "朗", "俯", "唏", "□", "擅", "揣", "妨", "携",
"杯", "淘", "□", "昏", "腻", "□", "握", "贴", "软", "逢", "咳", "荐", "符", "陪", "拥", "守",
"护", "啡", "腿", "沛", "户", "崇", "蠢", "嗒", "俱", "□", "孤", "败", "末", "舍", "从", "怦",
"竞", "□", "柔", "范", "滋", "踪", "肤", "幅", "票", "涵", "宠", "晕", "□", "仰", "□", "尤",
"词", "爷", "呦", "逞", "饥", "抬", "偿", "啷", "抖", "悄", "捡", "嗷", "暴", "省", "育", "窍",
"噫", "□", "序", "臊", "壮", "悲", "□", "魅", "秀", "敌", "脆", "供", "喳", "咐", "劝", "蕾",
"禁", "压", "嚷", "僵", "震", "农", "审", "睁", "评", "愚", "忒", "扬", "谜", "z", "聚", "妖",
"咬", "药", "迹", "喏", "吹", "垮", "呛", "踏", "敏", "衷", "恢", "廉", "翻", "叹", "森", "f",
"漉", "馋", "戴", "凶", "晾", "婚", "谱", "债", "粘", "擞", "资", "惹", "仗", "喊", "甚", "□",
"耻", "妒", "退", "恰", "尺", "防", "晓", "辆", "w", "码", "父", "嗓", "瞒", "□", "杀", "□",
"侧", "喋", "质", "荡", "哉", "甘", "刀", "嗑", "嘘", "勿", "煮", "偏", "吩", "泉", "倍", "幽",
"宁", "滴", "仇", "乏", "锅", "伐", "□", "含", "赌", "狂", "绩", "瞅", "跃", "悦", "耀", "升",
"彼", "浇", "钩", "砰", "遭", "漏", "脾", "绰", "屁", "咸", "伴", "患", "焕", "餐", "仍", "跌",
"惨", "扑", "绽", "顿", "润", "若", "弱", "卷", "斤", "□", "凑", "拖", "窜", "档", "牵", "烘",
"织", "谦", "执", "怒", "诺", "违", "噌", "委", "敲", "逊", "浑", "昂", "v", "吭", "冤", "稳",
"骂", "鉴", "堪", "治", "□", "抗", "茫", "盐", "辞", "皱", "冠", "饵", "触", "乌", "嘲", "□",
"腰", "穷", "阅", "扣", "桩", "恨", "锋", "权", "膀", "揭", "阶", "姿", "补", "群", "厕", "忽",
"催", "赠", "绕", "傲", "距", "遵", "辣", "栏", "宅", "疏", "呗", "傍", "狼", "泼", "哒", "婆",
"咻", "魄", "召", "蜇", "唧", "驾", "囊", "律", "戚", "挣", "捞", "胸", "雄", "沟", "覆", "",
"袖", "祷", "职", "络", "导", "厘", "予", "炫", "唯", "忑", "忐", "绪", "瞌", "吁", "罄", "菱",
"涕", "鞋", "协", "端", "填", "诱", "智", "宾", "轰", "J", "喉", "眯", "肩", "玉", "棍", "释",
"痴", "吐", "柱", "裹", "稽", "潦", "措", "榜", "吔", "述", "宣", "脱", "哆", "袜", "夺", "荣",
"吝", "芽", "筐", "允", "讶", "咽", "姜", "迫", "幕", "掩", "嘶", "躁", "啬", "□", "酒", "胃",
"纳", "呔", "吡", "洒", "槽", "沸", "捆", "哐", "宿", "契", "郊", "□", "唠", "狡", "嫉", "耗",
"啧", "欠", "喵", "喑", "略", "涨", "固", "啾", "奴", "遮", "嘎", "谊", "侦", "惫", "惧", "嗵",
"噗", "□", "婴", "杆", "忌", "嚷", "淌", "射", "逅", "邂", "辘", "", "促", "军", "励", "涌",
"慎", "盹", "植", "铛", "瘾", "巾", "剔", "蹑", "鲨", "例", "谨", "□", "拌", "屈", "渠", "勋",
"扯", "摊", "蒸", "□", "材", "坦", "疾", "栗", "喘", "躺", "串", "挤", "瓣", "沿", "肮", "济",
"纠", "捏", "德", "j", "泞", "扭", "遥", "搁", "恋", "稚", "□", "绷", "忠", "繁", "凡", "鸥",
"撩", "爬", "Z", "鄙", "毅", "裂", "颠", "益", "劣", "勾", "监", "惦", "拽", "姻", "刨", "煎",
"□", "培", "艰", "估", "赘", "啄", "堡", "映", "剪", "喷", "咙", "哨", "膨", "隆", "捧", "猾",
"畏", "申", "俊", "□", "伽", "编", "讪", "慰", "拗", "践", "幼", "叨", "匙", "嗡", "撇", "哀",
"棵", "咛", "缓", "咝", "芋", "渴", "咧", "哗", "茬", "悟", "唤", "咩", "哧", "恳", "逝", "芬",
"荒", "掺", "瀑", "欺", "焦", "蔼", "逗", "爆", "兵", "班", "颁", "钥", "献", "馅", "奉", "嗔",
"嘎", "截", "厢", "嗤", "嘀", "佛", "嘬", "潜", "瘩", "靡", "肖", "豁", "徼", "括", "沐", "潇",
"卑", "辈", "胁", "饲", "描", "翘", "烊", "秒", "苏", "敞", "腐", "侵", "碎", "撼", "锏", "耽",
"唆", "勃", "跤", "锁", "庆", "胀", "匪", "屎", "溅", "剥", "轧", "搏", "伦", "乍", "寡", "诈",
"颗", "江", "窄", "寿", "侗", "辗", "匠", "翔", "祥", "蚂", "孰", "", "淆", "暑", "蕉", "麦",
"歇", "驳", "翅", "镇", "岐", "脐", "懈", "控", "粹", "骄", "嚼", "症", "泣", "枝", "姓", "斥",
"妹", "汹", "迁", "堵", "殖", "峰", "捕", "皆", "□", "岸", "趾", "盔", "肃", "□", "畜", "竭",
"敷", "瞄", "呟", "得", "熏", "循", "旬", "筹", "驯", "蜡", "骤", "讯", "诸", "睬", "婪", "著",
"□", "臂", "赴", "胎", "彻", "淹", "础", "赋", "澈", "滩", "坛", "潭", "烙", "尘", "氧", "坠",
"拙", "琢", "茁", "碑", "痒", "炭", "邀", "乃", "孜", "拳", "宗", "残", "盎", "鲸", "馁", "阻",
"燃", "醉", "娥", "剂", "液", "凹", "径", "幢", "沥", "陂", "惕", "茱", "莞", "莨", "萸", "蕃",
"拧", "捺", "擀", "盗", "~", "腆", "溢", "纽", "炯", "帖", "哄", "筒", "绒", "冗", "彬", "岗",
"候", "锐", "吼", "策", "贾", "疙", "梆", "燎", "□", "湖", "骚", "尖", "洼", "瑟", "歪", "涩",
"唰", "层", "丸", "汪", "旺", "返", "狈", "拋", "贡", "贩", "凛", "呸", "嗳", "蔚", "胚", "捐",
"嘈", "喻", "捎", "赔", "裕", "秤", "龄", "芳", "掘", "吻", "犷", "忪", "奢", "惬", "惴", "憬",
"憧", "阙", "舌", "湫", "蜗", "漯", "倔", "吊", "烹", "邋", "嫦", "缪", "枸", "篷", "肴", "腼",
"污", "飒", "飕", "飚", "斓", "捂", "伍", "Ⅱ", "均", "菌", "陋", "沓", "晰", "赐", "僻", "耙",
"鹄", "痨", "篇", "褚", "矜", "尸", "蠡", "燥", "簌", "籁", "翩", "繇", "膝", "x", "蹶", "刊",
"贼", "鼹", "筛", "咀", "杉", "盲", "漾", "氓", "莽", "懊", "遁", "裳", "梢", "帽", "噎", "惑",
"眉", "芍", "页", "掖", "祸", "医", "逮", "庇", "箕", "羹", "姨", "抑", "攻", "亿", "糜", "垛",
"泌", "扒", "眷", "掸", "抉", "翌", "牲", "殷", "缉", "堕", "渺", "隐", "施", "辑", "蛾", "绸",
"鸣", "铭", "倡", "魔", "构", "佣", "君", "厄", "浚", "辟", "氏", "谋", "牟", "楷", "拇", "墓",
"慨", "佑", "募", "惮", "睦", "姑", "庶", "娜", "渔", "隅", "祭", "娱", "慷", "羽", "扛", "衰",
"疤", "亢", "罚", "坷", "御", "愈", "硕", "匿", "誉", "X", "逆", "寺", "伺", "溺", "援", "捻",
"雇", "娘", "尿", "嗽", "壳", "储", "靶", "贬", "辨", "隋", "啃", "垦", "遂", "砸", "隧", "灾",
"载", "浓", "笋", "梭", "辩", "忱", "蹬", "贯", "凳", "疟", "辫", "泽", "泛", "轨", "沤", "坊",
"帕", "灿", "兼", "栅", "笛", "攀", "矿", "旷", "畔", "涤", "叛", "奸", "膛", "盏", "倘", "崭",
"翟", "窥", "彰", "仓", "烫", "掏", "涛", "罩", "兆", "q", "帝", "糙", "辙", "槛", "斟", "针",
"廓", "枕", "阔", "淳", "腊", "嚏", "佃", "呈", "夯", "览", "怔", "凋", "蓬", "琅", "", "郎",
"坟", "披", "劈", "憋", "澄", "瘪", "徒", "姥", "貉", "涝", "勒", "鹤", "褪", "旨", "酱", "挚",
"掷", "儡", "屯", "峙", "垒", "瓶", "擂", "陀", "驮", "驼", "妥", "拓", "坡", "助", "瓦", "粥",
"轴", "咒", "颇", "钉", "泪", "棱", "逐", "烛", "顽", "瞩", "嘱", "楞", "腕", "俺", "亡", "蛀",
"筑", "枉", "仆", "埔", "痕", "爪", "曝", "册", "冯", "惟", "栖", "磅", "妻", "椎", "衡", "搅",
"俐", "粒", "祈", "矫", "酌", "尉", "企", "侥", "砌", "葱", "缴", "籽", "渍", "挝", "掐", "综",
"涡", "纵", "剿", "洽", "轿", "卒", "祖", "诅", "沃", "铅", "恫", "芜", "罪", "武", "囱", "丌",
"兀", "鬲", "禺", "夭", "氐", "亟", "乜", "孛", "粮", "嘏", "刺", "剡", "劁", "仡", "伧", "佗",
"伲", "窖", "佴", "俟", "倩", "偈", "偻", "僮", "儋", "遣", "蚌", "诒", "诙", "诤", "谙", "谯",
"阽", "枪", "挨", "隗", "郇", "叟", "廴", "凵", "圩", "圻", "坻", "坶", "垌", "埤", "馨", "艿",
"芫", "芸", "芾", "苣", "芘", "芴", "苴", "茆", "苕", "茜", "荑", "荛", "芘", "苞", "荞", "荠",
"荥", "荨", "莳", "荼", "莩", "莘", "脯", "疗", "桥", "菟", "菀", "萦", "葑", "葚", "蒉", "葭",
"蓼", "督", "蕻", "奘", "尢", "尬", "尴", "拚", "寥", "拶", "捋", "鞘", "掊", "掮", "揲", "摒",
"铣", "弋", "毒", "□", "碴", "吖", "虾", "霞", "暇", "呷", "侠", "狭", "厦", "呶", "戒", "掀",
"藉", "纤", "琳", "芥", "寝", "哕", "沁", "县", "柴", "咤", "哝", "哏", "倾", "顷", "傅", "侈",
"丘", "详", "腹", "撮", "啉", "啁", "啐", "巷", "削", "嚣", "啜", "蛆", "渡", "喁", "伶", "孝",
"羚", "凌", "襟", "蝎", "缚", "扳", "嗝", "翱", "邪", "嗌", "炔", "谐", "蟹", "嘞", "馏", "嘌",
"柳", "薪", "芯", "聋", "壤", "噱", "腥", "噻", "惺", "钙", "口", "囝", "圜", "帱", "峒", "峤",
"崴", "嶷", "仿", "徕", "浸", "彡", "犴", "搂", "猹", "獠", "夂", "饪", "镶", "廑", "逼", "版",
"怍", "怫", "怡", "庐", "惝", "仁", "慊", "膊", "驴", "阏", "嗅", "吕", "沌", "汨", "汶", "泷",
"浍", "浏", "浒", "淅", "渎", "渑", "晶", "溱", "潢", "泊", "溶", "蹲", "澹", "甯", "赣", "逵",
"遢", "遛", "敦", "揉", "孱", "屮", "娆", "娉", "媛", "缸", "孚", "骀", "骠", "纥", "纰", "绛",
"绠", "绨", "缏", "缥", "抡", "缯", "甾", "玢", "玟", "珩", "珲", "杓", "杈", "杳", "杵", "枞",
"杷", "辱", "栎", "桄", "梃", "栝", "桁", "桧", "楱", "椹", "槎", "槟", "樘", "乳", "戗", "臧",
"炅", "贲", "觑", "犍", "挲", "胺", "胧", "胗", "腌", "港", "朦", "纶", "歙", "慧", "询", "逻",
"毂", "杠", "於", "旄", "炀", "炜", "炖", "巡", "骆", "焖", "焯", "熨", "灬", "焘", "腮", "禧",
"晦", "迅", "皋", "戆", "鸭", "砉", "硌", "讳", "睢", "脾", "丫", "瞑", "瞟", "町", "钉", "钐",
"钿", "铍", "铒", "荤", "铤", "铫", "铮", "铴", "膏", "锔", "馏", "镗", "镝", "镦", "镩", "镪",
"穰", "涯", "鹳", "疸", "哑", "瘅", "瘥", "镐", "癞", "窨", "衩", "袢", "裎", "焉", "裼", "裨",
"褊", "褶", "咎", "覃", "颉", "颌", "颏", "虺", "蛄", "拘", "蛸", "蜚", "蝤", "螫", "莎", "砂",
"笮", "筝", "筠", "篝", "囤", "簸", "炎", "羧", "羯", "糁", "糗", "艮", "刹", "綮", "纱", "趄",
"酊", "酾", "醍", "趵", "跄", "跗", "跞", "跆", "衍", "踉", "踹", "燕", "蹊", "胳", "蹴", "躅",
"觜", "訾", "靓", "黾", "隽", "鲅", "秧", "鲭", "鳜", "鞅", "鹘", "谩", "麇", "煞", "赫", "妄",
"巍", "磷", "韦", "霖", "桅", "迭", "谍", "潍", "苇", "濒", "滨", "伪", "纬", "赁", "惩", "拎",
"玲", "鼎", "魏", "锭", "谓", "亨", "胞", "恒", "瘟", "蚊", "陵", "岭", "董", "紊", "摈", "瓮",
"栋", "鸿", "琉", "榴", "斡", "硫", "洪", "刘", "巫", "钨", "瘤", "宏", "诬", "弘", "梧", "吾",
"吴", "毋", "褒", "窿", "袄", "侮", "坞", "戊", "晤", "垄", "拢", "陇", "娄", "昔", "熙", "析",
"硒", "矽", "骋", "丙", "锡", "牺", "秉", "卢", "颅", "陡", "掳", "卤", "熄", "烯", "溪", "汐",
"犀", "檄", "袭", "媳", "虏", "隙", "麓", "葫", "赂", "潞", "匣", "禄", "辖", "戮", "峡", "狐",
"炳", "铝", "侣", "痘", "锨", "履", "屡", "缕", "贤", "衔", "舷", "弦", "弧", "氯", "□", "□",
"腺", "滤", "峦", "宪", "挛", "孪", "襄", "湘", "滦", "卵", "犊", "掠", "沪", "拔", "萧", "硝",
"霄", "弛", "哮", "睹", "仑", "宵", "沦", "驰", "槐", "徊", "啸", "锣", "揳", "箩", "骡", "裸",
"镀", "挟", "洛", "淮", "钵", "澳", "卸", "桓", "芭", "鲍", "泻", "屑", "铂", "痪", "锌", "迈",
"豢", "忻", "衅", "馒", "猩", "炽", "刑", "邢", "涣", "宦", "芒", "帛", "磺", "匈", "凰", "惶",
"锚", "矛", "朽", "铆", "锈", "卯", "煌", "墟", "戌", "缎", "幌", "恍", "枚", "徐", "蓄", "酗",
"旭", "酶", "舶", "恤", "絮", "婿", "媒", "轩", "喧", "镁", "悬", "玄", "昧", "癣", "寐", "薛",
"穴", "兑", "媚", "辉", "徽", "萌", "捌", "盟", "锰", "殉", "汛", "孟", "蛔", "醚", "墩", "吨",
"押", "卉", "弥", "觅", "¦", "幂", "蚜", "崖", "衙", "棉", "畴", "冕", "贿", "秽", "阉", "娩",
"缅", "烩", "踌", "蜒", "延", "阎", "藐", "稠", "奄", "诲", "绘", "堰", "渤", "砚", "雁", "唁",
"彦", "宴", "谚", "蔑", "殃", "央", "鸯", "抿", "杨", "皿", "佯", "疡", "盾", "悯", "闽", "螟",
"_", "掇", "谬", "=", "摹", "瑶", "尧", "膜", "窑", "姚", "跋", "舀", "哺", "躇", "墨", "霍",
"沫", "锄", "冶", "跺", "畸", "曳", "腋", "舵", "壹", "剁", "揖", "铱", "惰", "伊", "颐", "牡",
"胰", "亩", "沂", "滁", "暮", "彝", "蚁", "倚", "乙", "矣", "〉", "峨", "邑", "屹", "讥", "役",
"臆", "逸", "肄", "疫", "亦", "裔", "姬", "穆", "俄", "钠", "埠", "诣", "讹", "氖", "译", "簿",
"绎", "茵", "籍", "奈", "□", "挠", "吟", "淫", "寅", "尹", "扼", "淖", "遏", "缨", "莹", "汲",
"荧", "蝇", "妮", "霓", "盈", "倪", "拟", "鄂", "矗", "搐", "脊", "臃", "痈", "雍", "踊", "蛹",
"咏", "蔫", "拈", "碾", "恿", "撵", "钡", "蓟", "洱", "酿", "冀", "铀", "伎", "酉", "聂", "孽",
"釉", "啮", "镊", "镍", "迂", "淤", "盂", "榆", "虞", "涅", "舆", "贰", "俞", "逾", "狞", "渝",
"坝", "悸", "筏", "@", "川", "屿", "禹", "脓", "阀", "珐", "藩", "帆", "妓", "椽", "峪", "虐",
"枷", "挪", "狱", "懦", "糯", "寓", "樊", "矾", "殴", "驭", "鸳", "渊", "藕", "呕", "垣", "袁",
"荚", "辕", "颊", "趴", "猿", "钒", "钾", "苑", "¥", "稼", "曰", "徘", "湃", "焙", "嫁", "岳",
"粤", "潘", "歼", "耘", "郧", "匀", "磐", "蕴", "酝", "蔡", "韵", "孕", "匝", "疮", "佰", "笺",
"宰", "蚕", "皑", "耪", "惭", "赃", "咆", "葬", "炊", "凿", "藻", "枣", "蚤", "捶", "噪", "皂",
"灶", "袍", "缄", "茧", "肪", "柬", "裴", "碱", "憎", "硷", "锤", "俭", "渣", "札", "椿", "铡",
"闸", "醇", "纺", "榨", "抨", "唇", "澎", "彭", "苯", "斋", "棚", "硼", "稗", "寨", "瞻", "詹",
"贱", "沾", "诽", "斩", "鹏", "吠", "坯", "蘸", "栈", "湛", "砒", "樟", "霹", "漳", "批", "舰",
"杖", "丈", "账", "饯", "毗", "瘴", "障", "沼", "赵", "啤", "肺", "肇", "苍", "匹", "哲", "痞",
"涧", "锗", "蔗", "浙", "戳", "譬", "甄", "砧", "臻", "贞", "癌", "疵", "浆", "疹", "诊", "酚",
"疆", "瞥", "频", "贫", "聘", "坪", "征", "狰", "萍", "蒋", "桨", "拯", "茨", "帧", "雌", "郑",
"纷", "芝", "沧", "焚", "椒", "肢", "脂", "礁", "汾", "粕", "剖", "慈", "忿", "愤", "莆", "菩",
"娇", "圃", "浦", "粪", "崩", "铰", "嗞", "甭", "帜", "曹", "饺", "凄", "秩", "烽", "柒", "炙",
"痔", "滞", "沏", "窒", "蛊", "绞", "畦", "崎", "泵", "仲", "酵", "舟", "迸", "州", "谄", "祁",
"讽", "肘", "帚", "乞", "匆", "昼", "隘", "鞍", "迄", "诛", "醋", "秸", "讫", "拄", "孵", "扶",
"劫", "拂", "扦", "钎", "睫", "贮", "铸", "辐", "簇", "仟", "氟", "驻", "乾", "黔", "钳", "氨",
"撰", "伏", "篆", "谴", "堑", "嵌", "俘", "涪", "锥", "袱", "差", "蔷", "缀", "谆", "弗", "卓",
"疥", "诫", "届", "甫", "侨", "灼", "浊", "咨", "抚", "铺", "撬", "淄", "津", "峭", "滓", "俏",
"鬃", "蹿", "釜", "篡", "怯", "窃", "邹", "钦", "靳", "揍", "租", "晋", "秦", "腑", "芹", "擒",
"纂", "禽", "烬", "摧", "氢", "崔", "佐", "柞", "亍", "卿", "擎", "丐", "廿", "卅", "丕", "亘",
"禅", "□", "碌", "菜", "扰", "+", "筋", "□", "湿", "酬", "责", "昆", "状", "闻", "□", "□",
"弯", "嘴", "她", "赢", "验", "犯", "牢", "副", "逃", "嘟", "祝", "怨", "悔", "佩", "□", "□",
"咱", "漆", "势", "悉", "剧", "肥", "引", "□", "假", "抵", "唬", "争", "窝", "另", "甩", "□",
"途", "严", "删", "愧", "咚", "聪", "产", "瞎", "□", "志", "追", "□", "邻", "某", "晃", "岁",
"眠", "址", "奏", "案", "斗", "泄", "欣", "汇", "倦", "□", "展", "摔", "", "缺", "哗", "p",
"乖", "暗", "制", "朵", "肿", "祟", "株", "", "扮", "暂", "塔", "ベ", "ポ", "元", "烈", "汗",
"劳", "嚯", "勉", "凭", "l", "鼻", "证", "ガ", "卧", "姐", "默", "搜", "签", "亳", "迢", "船",
"", "敬", "振", "列", "共", "哩", "忧", "羞", "贪", "犹", "谈", "", "撒", "捣", "汉", "环",
"嗬", "废", "豫", "洋", "谎", "依", "避", "欲", "团", "笨", "创", "额", "兮", "泳", "速", "伸",
"挥", "疲", "锁", "铲", "核", "□", "余", "贺", "□", "显", "唉", "□", "刮", "虚", "吞", "硬",
"纯", "汤", "□", "勤", "拒", "攒", "套", "盯", "□", "呲", "测", "踢", "众", "增", "技", "诀",
"盘", "富", "肠", "属", "抢", "狠", "□", "嫌", "炮", "背", "氛", "九", "零", "b", "效", "晒",
"闯", "坑", "绑", "脖", "阴", "夸", "仿", "基", "盖", "帅", "政", "□", "恙", "佳", "□", "私",
"社", "纯", "奔", "缠", "咋", "炸", "撞", "率", "境", "透", "牙", "丰", "研", "摸", "缩", "捷",
"耶", "野", "恩", "叽", "呤", "判", "庞", "朗", "俯", "唏", "□", "擅", "揣", "妨", "携", "杯",
"淘", "□", "昏", "腻", "□", "握", "贴", "软", "逢", "咳", "荐", "符", "陪", "拥", "守", "护",
"啡", "腿", "沛", "户", "崇", "蠢", "嗒", "俱", "□", "孤", "败", "末", "舍", "从", "怦", "竞",
"□", "柔", "范", "滋", "踪", "肤", "幅", "票", "涵", "宠", "晕", "□", "仰", "□", "尤", "词",
"爷", "呦", "逞", "饥", "抬", "偿", "啷", "抖", "悄", "捡", "嗷", "暴", "省", "育", "窍", "噫",
"□", "序", "臊", "壮", "悲", "□", "魅", "秀", "敌", "脆", "供", "喳", "咐", "劝", "蕾", "禁",
"压", "嚷", "僵", "震", "农", "审", "睁", "评", "愚", "忒", "扬", "谜", "z", "聚", "妖", "咬",
"药", "迹", "喏", "吹", "垮", "呛", "踏", "敏", "衷", "恢", "廉", "翻", "叹", "森", "f", "漉",
"馋", "戴", "凶", "晾", "婚", "谱", "债", "粘", "擞", "资", "惹", "仗", "喊", "甚", "□", "耻",
"妒", "退", "恰", "尺", "防", "晓", "辆", "w", "码", "父", "嗓", "瞒", "□", "杀", "□", "侧",
"喋", "质", "荡", "哉", "甘", "刀", "嗑", "嘘", "勿", "煮", "偏", "吩", "泉", "倍", "幽", "宁",
"滴", "仇", "乏", "锅", "伐", "□", "含", "赌", "狂", "绩", "瞅", "跃", "悦", "耀", "升", "彼",
"浇", "钩", "砰", "遭", "漏", "脾", "绰", "屁", "咸", "伴", "患", "焕", "餐", "仍", "跌", "惨",
"扑", "绽", "顿", "润", "若", "弱", "卷", "斤", "□", "凑", "拖", "窜", "档", "牵", "烘", "织",
"谦", "执", "怒", "诺", "违", "噌", "委", "敲", "逊", "浑", "昂", "v", "吭", "冤", "稳", "骂",
"鉴", "堪", "治", "□", "抗", "茫", "盐", "辞", "皱", "冠", "饵", "触", "乌", "嘲", "□", "腰",
"穷", "阅", "扣", "桩", "恨", "锋", "权", "膀", "揭", "阶", "姿", "补", "群", "厕", "忽", "催",
"赠", "绕", "傲", "距", "遵", "辣", "栏", "宅", "疏", "呗", "傍", "狼", "泼", "哒", "婆", "咻",
"魄", "召", "蜇", "唧", "驾", "囊", "律", "戚", "挣", "捞", "胸", "雄", "沟", "覆", "", "袖",
"祷", "职", "络", "导", "厘", "予", "炫", "唯", "忑", "忐", "绪", "瞌", "吁", "罄", "菱", "涕",
"鞋", "协", "端", "填", "诱", "智", "宾", "轰", "J", "喉", "眯", "肩", "玉", "棍", "释", "痴",
"吐", "柱", "裹", "稽", "潦", "措", "榜", "吔", "述", "宣", "脱", "哆", "袜", "夺", "荣", "吝",
"芽", "筐", "允", "讶", "咽", "姜", "迫", "幕", "掩", "嘶", "躁", "啬", "□", "酒", "胃", "纳",
"呔", "吡", "洒", "槽", "沸", "捆", "哐", "宿", "契", "郊", "□", "唠", "狡", "嫉", "耗", "啧",
"欠", "喵", "喑", "略", "涨", "固", "啾", "奴", "遮", "嘎", "谊", "侦", "惫", "惧", "嗵", "噗",
"□", "婴", "杆", "忌", "嚷", "淌", "射", "逅", "邂", "辘", "\"", "促", "军", "励", "涌", "慎",
"盹", "植", "铛", "瘾", "巾", "剔", "蹑", "鲨", "例", "谨", "□", "拌", "屈", "渠", "勋", "扯",
"摊", "蒸", "□", "材", "坦", "疾", "栗", "喘", "躺", "串", "挤", "瓣", "沿", "肮", "济", "纠",
"捏", "德", "j", "泞", "扭", "遥", "搁", "恋", "稚", "□", "绷", "忠", "繁", "凡", "鸥", "撩",
"爬", "Z", "鄙", "毅", "裂", "颠", "益", "劣", "勾", "监", "惦", "拽", "姻", "刨", "煎", "□",
"培", "艰", "估", "赘", "啄", "堡", "映", "剪", "喷", "咙", "哨", "膨", "隆", "捧", "猾", "畏",
"申", "俊", "□", "伽", "编", "讪", "慰", "拗", "践", "幼", "叨", "匙", "嗡", "撇", "哀", "棵",
"咛", "缓", "咝", "芋", "渴", "咧", "哗", "茬", "悟", "唤", "咩", "哧", "恳", "逝", "芬", "荒",
"掺", "瀑", "欺", "焦", "蔼", "逗", "爆", "兵", "班", "颁", "钥", "献", "馅", "奉", "嗔", "嘎",
"截", "厢", "嗤", "嘀", "佛", "嘬", "潜", "瘩", "靡", "肖", "豁", "徼", "括", "沐", "潇", "卑",
"辈", "胁", "饲", "描", "翘", "烊", "秒", "苏", "敞", "腐", "侵", "碎", "撼", "锏", "耽", "唆",
"勃", "跤", "锁", "庆", "胀", "匪", "屎", "溅", "剥", "轧", "搏", "伦", "乍", "寡", "诈", "颗",
"江", "窄", "寿", "侗", "辗", "匠", "翔", "祥", "蚂", "孰", "'", "淆", "暑", "蕉", "麦", "歇",
"驳", "翅", "镇", "岐", "脐", "懈", "控", "粹", "骄", "嚼", "症", "泣", "枝", "姓", "斥", "妹",
"汹", "迁", "堵", "殖", "峰", "捕", "皆", "□", "岸", "趾", "盔", "肃", "□", "畜", "竭", "敷",
"瞄", "呟", "得", "熏", "循", "旬", "筹", "驯", "蜡", "骤", "讯", "诸", "睬", "婪", "著", "□",
"臂", "赴", "胎", "彻", "淹", "础", "赋", "澈", "滩", "坛", "潭", "烙", "尘", "氧", "坠", "拙",
"琢", "茁", "碑", "痒", "炭", "邀", "乃", "孜", "拳", "宗", "残", "盎", "鲸", "馁", "阻", "燃",
"醉", "娥", "剂", "液", "凹", "径", "幢", "沥", "陂", "惕", "茱", "莞", "莨", "萸", "蕃", "拧",
"捺", "擀", "盗", "~", "腆", "溢", "纽", "炯", "帖", "哄", "筒", "绒", "冗", "彬", "岗", "候",
"锐", "吼", "策", "贾", "疙", "梆", "燎", "□", "湖", "骚", "尖", "洼", "瑟", "歪", "涩", "唰",
"层", "丸", "汪", "旺", "返", "狈", "拋", "贡", "贩", "凛", "呸", "嗳", "蔚", "胚", "捐", "嘈",
"喻", "捎", "赔", "裕", "秤", "龄", "芳", "掘", "吻", "犷", "忪", "奢", "惬", "惴", "憬", "憧",
"阙", "舌", "湫", "蜗", "漯", "倔", "吊", "烹", "邋", "嫦", "缪", "枸", "篷", "肴", "腼", "污",
"飒", "飕", "飚", "斓", "捂", "伍", "Ⅱ", "均", "菌", "陋", "沓", "晰", "赐", "僻", "耙", "鹄",
"痨", "篇", "褚", "矜", "尸", "蠡", "燥", "簌", "籁", "翩", "繇", "膝", "x", "蹶", "刊", "贼",
"鼹", "筛", "咀", "杉", "盲", "漾", "氓", "莽", "懊", "遁", "裳", "梢", "帽", "噎", "惑", "眉",
"芍", "页", "掖", "祸", "医", "逮", "庇", "箕", "羹", "姨", "抑", "攻", "亿", "糜", "垛", "泌",
"扒", "眷", "掸", "抉", "翌", "牲", "殷", "缉", "堕", "渺", "隐", "施", "辑", "蛾", "绸", "鸣",
"铭", "倡", "魔", "构", "佣", "君", "厄", "浚", "辟", "氏", "谋", "牟", "楷", "拇", "墓", "慨",
"佑", "募", "惮", "睦", "姑", "庶", "娜", "渔", "隅", "祭", "娱", "慷", "羽", "扛", "衰", "疤",
"亢", "罚", "坷", "御", "愈", "硕", "匿", "誉", "X", "逆", "寺", "伺", "溺", "援", "捻", "雇",
"娘", "尿", "嗽", "壳", "储", "靶", "贬", "辨", "隋", "啃", "垦", "遂", "砸", "隧", "灾", "载",
"浓", "笋", "梭", "辩", "忱", "蹬", "贯", "凳", "疟", "辫", "泽", "泛", "轨", "沤", "坊", "帕",
"灿", "兼", "栅", "笛", "攀", "矿", "旷", "畔", "涤", "叛", "奸", "膛", "盏", "倘", "崭", "翟",
"窥", "彰", "仓", "烫", "掏", "涛", "罩", "兆", "q", "帝", "糙", "辙", "槛", "斟", "针", "廓",
"枕", "阔", "淳", "腊", "嚏", "佃", "呈", "夯", "览", "怔", "凋", "蓬", "琅", "", "郎", "坟",
"披", "劈", "憋", "澄", "瘪", "徒", "姥", "貉", "涝", "勒", "鹤", "褪", "旨", "酱", "挚", "掷",
"儡", "屯", "峙", "垒", "瓶", "擂", "陀", "驮", "驼", "妥", "拓", "坡", "助", "瓦", "粥", "轴",
"咒", "颇", "钉", "泪", "棱", "逐", "烛", "顽", "瞩", "嘱", "楞", "腕", "俺", "亡", "蛀", "筑",
"枉", "仆", "埔", "痕", "爪", "曝", "册", "冯", "惟", "栖", "磅", "妻", "椎", "衡", "搅", "俐",
"粒", "祈", "矫", "酌", "尉", "企", "侥", "砌", "葱", "缴", "籽", "渍", "挝", "掐", "综", "涡",
"纵", "剿", "洽", "轿", "卒", "祖", "诅", "沃", "铅", "恫", "芜", "罪", "武", "囱", "丌", "兀",
"鬲", "禺", "夭", "氐", "亟", "乜", "孛", "粮", "嘏", "刺", "剡", "劁", "仡", "伧", "佗", "伲",
"窖", "佴", "俟", "倩", "偈", "偻", "僮", "儋", "遣", "蚌", "诒", "诙", "诤", "谙", "谯", "阽",
"枪", "挨", "隗", "郇", "叟", "廴", "凵", "圩", "圻", "坻", "坶", "垌", "埤", "馨", "艿", "芫",
"芸", "芾", "苣", "芘", "芴", "苴", "茆", "苕", "茜", "荑", "荛", "芘", "苞", "荞", "荠", "荥",
"荨", "莳", "荼", "莩", "莘", "脯", "疗", "桥", "菟", "菀", "萦", "葑", "葚", "蒉", "葭", "蓼",
"督", "蕻", "奘", "尢", "尬", "尴", "拚", "寥", "拶", "捋", "鞘", "掊", "掮", "揲", "摒", "铣",
"弋", "毒", "□", "碴", "吖", "虾", "霞", "暇", "呷", "侠", "狭", "厦", "呶", "戒", "掀", "藉",
"纤", "琳", "芥", "寝", "哕", "沁", "县", "柴", "咤", "哝", "哏", "倾", "顷", "傅", "侈", "丘",
"详", "腹", "撮", "啉", "啁", "啐", "巷", "削", "嚣", "啜", "蛆", "渡", "喁", "伶", "孝", "羚",
"凌", "襟", "蝎", "缚", "扳", "嗝", "翱", "邪", "嗌", "炔", "谐", "蟹", "嘞", "馏", "嘌", "柳",
"薪", "芯", "聋", "壤", "噱", "腥", "噻", "惺", "钙", "口", "囝", "圜", "帱", "峒", "峤", "崴",
"嶷", "仿", "徕", "浸", "彡", "犴", "搂", "猹", "獠", "夂", "饪", "镶", "廑", "逼", "版", "怍",
"怫", "怡", "庐", "惝", "仁", "慊", "膊", "驴", "阏", "嗅", "吕", "沌", "汨", "汶", "泷", "浍",
"浏", "浒", "淅", "渎", "渑", "晶", "溱", "潢", "泊", "溶", "蹲", "澹", "甯", "赣", "逵", "遢",
"遛", "敦", "揉", "孱", "屮", "娆", "娉", "媛", "缸", "孚", "骀", "骠", "纥", "纰", "绛", "绠",
"绨", "缏", "缥", "抡", "缯", "甾", "玢", "玟", "珩", "珲", "杓", "杈", "杳", "杵", "枞", "杷",
"辱", "栎", "桄", "梃", "栝", "桁", "桧", "楱", "椹", "槎", "槟", "樘", "乳", "戗", "臧", "炅",
"贲", "觑", "犍", "挲", "胺", "胧", "胗", "腌", "港", "朦", "纶", "歙", "慧", "询", "逻", "毂",
"杠", "於", "旄", "炀", "炜", "炖", "巡", "骆", "焖", "焯", "熨", "灬", "焘", "腮", "禧", "晦",
"迅", "皋", "戆", "鸭", "砉", "硌", "讳", "睢", "脾", "丫", "瞑", "瞟", "町", "钉", "钐", "钿",
"铍", "铒", "荤", "铤", "铫", "铮", "铴", "膏", "锔", "馏", "镗", "镝", "镦", "镩", "镪", "穰",
"涯", "鹳", "疸", "哑", "瘅", "瘥", "镐", "癞", "窨", "衩", "袢", "裎", "焉", "裼", "裨", "褊",
"褶", "咎", "覃", "颉", "颌", "颏", "虺", "蛄", "拘", "蛸", "蜚", "蝤", "螫", "莎", "砂", "笮",
"筝", "筠", "篝", "囤", "簸", "炎", "羧", "羯", "糁", "糗", "艮", "刹", "綮", "纱", "趄", "酊",
"酾", "醍", "趵", "跄", "跗", "跞", "跆", "衍", "踉", "踹", "燕", "蹊", "胳", "蹴", "躅", "觜",
"訾", "靓", "黾", "隽", "鲅", "秧", "鲭", "鳜", "鞅", "鹘", "谩", "麇", "煞", "赫", "妄", "巍",
"磷", "韦", "霖", "桅", "迭", "谍", "潍", "苇", "濒", "滨", "伪", "纬", "赁", "惩", "拎", "玲",
"鼎", "魏", "锭", "谓", "亨", "胞", "恒", "瘟", "蚊", "陵", "岭", "董", "紊", "摈", "瓮", "栋",
"鸿", "琉", "榴", "斡", "硫", "洪", "刘", "巫", "钨", "瘤", "宏", "诬", "弘", "梧", "吾", "吴",
"毋", "褒", "窿", "袄", "侮", "坞", "戊", "晤", "垄", "拢", "陇", "娄", "昔", "熙", "析", "硒",
"矽", "骋", "丙", "锡", "牺", "秉", "卢", "颅", "陡", "掳", "卤", "熄", "烯", "溪", "汐", "犀",
"檄", "袭", "媳", "虏", "隙", "麓", "葫", "赂", "潞", "匣", "禄", "辖", "戮", "峡", "狐", "炳",
"铝", "侣", "痘", "锨", "履", "屡", "缕", "贤", "衔", "舷", "弦", "弧", "氯", "□", "□", "腺",
"滤", "峦", "宪", "挛", "孪", "襄", "湘", "滦", "卵", "犊", "掠", "沪", "拔", "萧", "硝", "霄",
"弛", "哮", "睹", "仑", "宵", "沦", "驰", "槐", "徊", "啸", "锣", "揳", "箩", "骡", "裸", "镀",
"挟", "洛", "淮", "钵", "澳", "卸", "桓", "芭", "鲍", "泻", "屑", "铂", "痪", "锌", "迈", "豢",
"忻", "衅", "馒", "猩", "炽", "刑", "邢", "涣", "宦", "芒", "帛", "磺", "匈", "凰", "惶", "锚",
"矛", "朽", "铆", "锈", "卯", "煌", "墟", "戌", "缎", "幌", "恍", "枚", "徐", "蓄", "酗", "旭",
"酶", "舶", "恤", "絮", "婿", "媒", "轩", "喧", "镁", "悬", "玄", "昧", "癣", "寐", "薛", "穴",
"兑", "媚", "辉", "徽", "萌", "捌", "盟", "锰", "殉", "汛", "孟", "蛔", "醚", "墩", "吨", "押",
"卉", "弥", "觅", "¦", "幂", "蚜", "崖", "衙", "棉", "畴", "冕", "贿", "秽", "阉", "娩", "缅",
"烩", "踌", "蜒", "延", "阎", "藐", "稠", "奄", "诲", "绘", "堰", "渤", "砚", "雁", "唁", "彦",
"宴", "谚", "蔑", "殃", "央", "鸯", "抿", "杨", "皿", "佯", "疡", "盾", "悯", "闽", "螟", "_",
"掇", "谬", "=", "摹", "瑶", "尧", "膜", "窑", "姚", "跋", "舀", "哺", "躇", "墨", "霍", "沫",
"锄", "冶", "跺", "畸", "曳", "腋", "舵", "壹", "剁", "揖", "铱", "惰", "伊", "颐", "牡", "胰",
"亩", "沂", "滁", "暮", "彝", "蚁", "倚", "乙", "矣", "〉", "峨", "邑", "屹", "讥", "役", "臆",
"逸", "肄", "疫", "亦", "裔", "姬", "穆", "俄", "钠", "埠", "诣", "讹", "氖", "译", "簿", "绎",
"茵", "籍", "奈", "□", "挠", "吟", "淫", "寅", "尹", "扼", "淖", "遏", "缨", "莹", "汲", "荧",
"蝇", "妮", "霓", "盈", "倪", "拟", "鄂", "矗", "搐", "脊", "臃", "痈", "雍", "踊", "蛹", "咏",
"蔫", "拈", "碾", "恿", "撵", "钡", "蓟", "洱", "酿", "冀", "铀", "伎", "酉", "聂", "孽", "釉",
"啮", "镊", "镍", "迂", "淤", "盂", "榆", "虞", "涅", "舆", "贰", "俞", "逾", "狞", "渝", "坝",
"悸", "筏", "@", "川", "屿", "禹", "脓", "阀", "珐", "藩", "帆", "妓", "椽", "峪", "虐", "枷",
"挪", "狱", "懦", "糯", "寓", "樊", "矾", "殴", "驭", "鸳", "渊", "藕", "呕", "垣", "袁", "荚",
"辕", "颊", "趴", "猿", "钒", "钾", "苑", "¥", "稼", "曰", "徘", "湃", "焙", "嫁", "岳", "粤",
"潘", "歼", "耘", "郧", "匀", "磐", "蕴", "酝", "蔡", "韵", "孕", "匝", "疮", "佰", "笺", "宰",
"蚕", "皑", "耪", "惭", "赃", "咆", "葬", "炊", "凿", "藻", "枣", "蚤", "捶", "噪", "皂", "灶",
"袍", "缄", "茧", "肪", "柬", "裴", "碱", "憎", "硷", "锤", "俭", "渣", "札", "椿", "铡", "闸",
"醇", "纺", "榨", "抨", "唇", "澎", "彭", "苯", "斋", "棚", "硼", "稗", "寨", "瞻", "詹", "贱",
"沾", "诽", "斩", "鹏", "吠", "坯", "蘸", "栈", "湛", "砒", "樟", "霹", "漳", "批", "舰", "杖",
"丈", "账", "饯", "毗", "瘴", "障", "沼", "赵", "啤", "肺", "肇", "苍", "匹", "哲", "痞", "涧",
"锗", "蔗", "浙", "戳", "譬", "甄", "砧", "臻", "贞", "癌", "疵", "浆", "疹", "诊", "酚", "疆",
"瞥", "频", "贫", "聘", "坪", "征", "狰", "萍", "蒋", "桨", "拯", "茨", "帧", "雌", "郑", "纷",
"芝", "沧", "焚", "椒", "肢", "脂", "礁", "汾", "粕", "剖", "慈", "忿", "愤", "莆", "菩", "娇",
"圃", "浦", "粪", "崩", "铰", "嗞", "甭", "帜", "曹", "饺", "凄", "秩", "烽", "柒", "炙", "痔",
"滞", "沏", "窒", "蛊", "绞", "畦", "崎", "泵", "仲", "酵", "舟", "迸", "州", "谄", "祁", "讽",
"肘", "帚", "乞", "匆", "昼", "隘", "鞍", "迄", "诛", "醋", "秸", "讫", "拄", "孵", "扶", "劫",
"拂", "扦", "钎", "睫", "贮", "铸", "辐", "簇", "仟", "氟", "驻", "乾", "黔", "钳", "氨", "撰",
"伏", "篆", "谴", "堑", "嵌", "俘", "涪", "锥", "袱", "差", "蔷", "缀", "谆", "弗", "卓", "疥",
"诫", "届", "甫", "侨", "灼", "浊", "咨", "抚", "铺", "撬", "淄", "津", "峭", "滓", "俏", "鬃",
"蹿", "釜", "篡", "怯", "窃", "邹", "钦", "靳", "揍", "租", "晋", "秦", "腑", "芹", "擒", "纂",
"禽", "", "烬", "摧", "氢", "崔", "佐", "柞", "亍", "卿", "擎", "丐", "廿", "卅", "丕", "亘",
"丞", "氰", "孬", "噩", "丨", "蓖", "丿", "匕", "乇", "荆", "爻", "卮", "琼", "囟", "胤", "馗",
"毓", "睾", "鼗", "", "兢", "鼐", "茎", "乩", "芈", "邱", "蔽", "酋", "仄", "厍", "厝", "厣",
"厥", "厮", "靥", "赝", "匚", "叵", "匦", "匮", "匾", "赜", "卣", "刂", "刈", "刎", "刭", "刳",
@ -541,7 +541,8 @@ internal static class CharacterSets
"骺", "骼", "髁", "髀", "髂", "髋", "髌", "髑", "阂", "魃", "魇", "魉", "魈", "魍", "魑", "飨",
"餍", "餮", "饕", "饔", "髟", "髡", "髯", "髫", "髻", "髭", "髹", "鬈", "鬏", "鬓", "鬟", "鬣",
"麽", "麾", "縻", "麂", "涸", "麈", "麋", "鏖", "麝", "黛", "黜", "黝", "黠", "黟", "黢", "黩",
"黧", "黥", "黪", "黯", "鼢", "鼬", "鼯", "猎", "鼷", "鼽", "鼾", "齄",
"黧", "黥", "黪", "黯", "鼢", "鼬", "鼯", "猎", "鼷", "鼽", "鼾", "齄", "`", "♥", "♪", "🌢",
"💢", "☺", "⚷", "√", "□", "△",
};
#endregion

View file

@ -33,6 +33,8 @@ public Villager(int offset, int idx, Save save)
if (save.SaveType == SaveType.WildWorld)
Exists = _saveData.ReadByte(offset + Offsets.VillagerId) != 0 && _saveData.ReadByte(offset + Offsets.VillagerId) != 0xFF;
else if (save.SaveType == SaveType.CityFolk)
Exists = _saveData.ReadByte(offset) != 0;
else
Exists = _saveData.ReadUInt16(offset + Offsets.VillagerId, save.IsBigEndian) != 0 &&
_saveData.ReadUInt16(offset + Offsets.VillagerId, save.IsBigEndian) != 0xFFFF;

View file

@ -235,12 +235,25 @@ public static class VillagerInfo
public static readonly VillagerOffsets CfVillagerOffsets = 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
VillagerId = 0x1824,
Shirt = 0x1826,
Carpet = 0x1828,
Wallpaper = 0x182A,
Umbrella = 0x182C,
Furniture = 0x182E,
FurnitureCount = 10,
Song = 0x1842,
// StoredName = 0x1858 // (US EN)
Catchphrase = 0x18EC, // EN US
CatchphraseSize = 20,
TownId = 0x224C,
TownName = 0x224E,
TownNameSize = 8,
Personality = 0x230A,
Status = 0x3030, // Moving State Flags?
HouseCoordinates = -1,
Nicknames = -1,
NameId = -1
};
public static readonly VillagerOffsets NlVillagerOffsets = new VillagerOffsets
@ -311,6 +324,7 @@ public static string[] GetPersonalities(SaveType saveType)
case SaveType.DongwuSenlin:
return AcPersonalities;
case SaveType.WildWorld:
case SaveType.CityFolk:
return WwPersonalities;
case SaveType.NewLeaf:
return NlPersonalities;
@ -318,8 +332,6 @@ public static string[] GetPersonalities(SaveType saveType)
return NlPersonalities;
case SaveType.Unknown:
break;
case SaveType.CityFolk:
break;
default:
throw new ArgumentOutOfRangeException(nameof(saveType), saveType, null);
}
@ -349,6 +361,9 @@ public static Dictionary<ushort, SimpleVillager> GetVillagerDatabase(SaveType sa
case SaveType.WildWorld:
databaseFilename = string.Format(databaseFilename, "WW");
break;
case SaveType.CityFolk:
databaseFilename = string.Format(databaseFilename, "CF");
break;
case SaveType.NewLeaf:
databaseFilename = string.Format(databaseFilename, "NL");
break;
@ -357,8 +372,6 @@ public static Dictionary<ushort, SimpleVillager> GetVillagerDatabase(SaveType sa
break;
case SaveType.Unknown:
break;
case SaveType.CityFolk:
break;
default:
throw new ArgumentOutOfRangeException(nameof(saveType), saveType, null);
}
@ -415,6 +428,7 @@ public static Dictionary<ushort, SimpleVillager> GetVillagerDatabase(SaveType sa
case SaveType.DoubutsuNoMoriEPlus:
case SaveType.AnimalForestEPlus:
case SaveType.DongwuSenlin:
case SaveType.CityFolk:
while ((line = contents.ReadLine()) != null)
{
if (!line.Contains("0x")) continue;
@ -429,8 +443,6 @@ public static Dictionary<ushort, SimpleVillager> GetVillagerDatabase(SaveType sa
break;
case SaveType.Unknown:
break;
case SaveType.CityFolk:
break;
default:
throw new ArgumentOutOfRangeException(nameof(saveType), saveType, null);
}
@ -458,14 +470,14 @@ public static VillagerOffsets GetVillagerInfo(SaveType saveType)
return DoubutsuNoMoriVillagerOffsets; // TEMP
case SaveType.WildWorld:
return WwVillagerOffsets;
case SaveType.CityFolk:
return CfVillagerOffsets;
case SaveType.NewLeaf:
return NlVillagerOffsets;
case SaveType.WelcomeAmiibo:
return WaVillagerOffsets;
case SaveType.Unknown:
break;
case SaveType.CityFolk:
break;
default:
throw new ArgumentOutOfRangeException(nameof(saveType), saveType, null);
}

View file

@ -9,12 +9,28 @@
<OutputType>WinExe</OutputType>
<RootNamespace>ACSE.WinForms</RootNamespace>
<AssemblyName>ACSE</AssemblyName>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -85,6 +101,12 @@
<Compile Include="Controls\ItemEditor.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Controls\MessageEditor.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Controls\MessageEditor.Designer.cs">
<DependentUpon>MessageEditor.cs</DependentUpon>
</Compile>
<Compile Include="Controls\OffsetablePictureBox.cs">
<SubType>Component</SubType>
</Compile>
@ -128,6 +150,12 @@
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="MailEditorForm\MailEditorForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MailEditorForm\MailEditorForm.Designer.cs">
<DependentUpon>MailEditorForm.cs</DependentUpon>
</Compile>
<Compile Include="SecureValueForm\SecureValueForm.cs">
<SubType>Form</SubType>
</Compile>
@ -161,9 +189,15 @@
<EmbeddedResource Include="AboutBox\AboutBox.resx">
<DependentUpon>AboutBox.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Controls\MessageEditor.resx">
<DependentUpon>MessageEditor.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="ItemColorEditor\ItemColorEditor.resx">
<DependentUpon>ItemColorEditor.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="MailEditorForm\MailEditorForm.resx">
<DependentUpon>MailEditorForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="SecureValueForm\SecureValueForm.resx">
<DependentUpon>SecureValueForm.cs</DependentUpon>
</EmbeddedResource>
@ -1398,6 +1432,9 @@
<Content Include="Resources\CF_Items_en.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\CF_Villagers_en.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\DBNM_e_Plus_Acres_en.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -5647,6 +5684,18 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.7">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.7 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>

View file

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="ACSE.WinForms.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="ACSE.WinForms.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
<userSettings>
<ACSE.WinForms.Properties.Settings>
@ -35,8 +35,8 @@
<value>True</value>
</setting>
<setting name="BackupLocation" serializeAs="String">
<value />
<value/>
</setting>
</ACSE.WinForms.Properties.Settings>
</userSettings>
</configuration>
</configuration>

View file

@ -0,0 +1,61 @@
namespace ACSE.WinForms.Controls
{
partial class MessageEditor
{
/// <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 Component 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.MessageContents = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// MessageContents
//
this.MessageContents.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.MessageContents.Location = new System.Drawing.Point(3, 59);
this.MessageContents.Multiline = true;
this.MessageContents.Name = "MessageContents";
this.MessageContents.Size = new System.Drawing.Size(344, 138);
this.MessageContents.TabIndex = 0;
//
// MessageEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.MessageContents);
this.Name = "MessageEditor";
this.Size = new System.Drawing.Size(350, 200);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox MessageContents;
}
}

View file

@ -0,0 +1,21 @@
using System.Windows.Forms;
using ACSE.Core.Messages.Mail;
namespace ACSE.WinForms.Controls
{
public partial class MessageEditor : UserControl
{
private PlayerMailBase _mailReference;
public MessageEditor()
{
InitializeComponent();
}
public void SetMailReference(PlayerMailBase mail)
{
_mailReference = mail;
MessageContents.Text = mail.Contents;
}
}
}

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

@ -32,13 +32,18 @@ public sealed class VillagerControl : FlowLayoutPanel
private readonly TextBox _nameBox;
private readonly Button _importDlcButton;
/// <summary>
/// This event fires when the villager has been changed to another.
/// </summary>
public event EventHandler<Villager> VillagerChanged;
/// <summary>
/// The index of the control.
/// </summary>
public readonly int Index;
private readonly Save _saveFile;
private readonly Villager _villager;
private Villager _villager;
private readonly Dictionary<ushort, SimpleVillager> _villagers;
private readonly string[] _villagerNames;
private readonly string[] _personalityTypes;
@ -79,7 +84,7 @@ public VillagerControl(MainForm mainFormReference, int index, Save saveFile, Vil
AutoSize = false,
Size = new Size(45, 32),
TextAlign = ContentAlignment.MiddleCenter,
Text = index == 15 ? "Islander" : (index + 1).ToString()
Text = saveFile.SaveGeneration == SaveGeneration.GCN && index == 15 ? "Islander" : (index + 1).ToString()
};
var margin = CalculateControlVerticalMargin(_indexLabel);
@ -246,7 +251,7 @@ public VillagerControl(MainForm mainFormReference, int index, Save saveFile, Vil
}
}
private void VillagerSelectionBoxChanged()
private void VillagerSelectionBoxChanged(bool fireChangedEvent = true)
{
if (_villagerSelectionBox.SelectedIndex < 0) return;
@ -322,6 +327,9 @@ private void VillagerSelectionBoxChanged()
: new Point(64 * ((_villager.Data.VillagerId & 0xFF) % 10),
64 * ((_villager.Data.VillagerId & 0xFF) / 10));
}
if (fireChangedEvent)
VillagerChanged?.Invoke(this, _villager);
}
private void PersonalityChanged()
@ -410,5 +418,12 @@ private void ImportDlcVillager()
private int CalculateControlVerticalMargin(Control c)
=> (int) (0.5f * (Height - c.Height));
public void RefreshData() => VillagerSelectionBoxChanged(false);
public void SetVillager(Villager villager)
{
_villager = villager;
RefreshData();
}
}
}

View file

@ -12,7 +12,7 @@ namespace ACSE.WinForms {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
internal sealed partial class ItemColorSettings : global::System.Configuration.ApplicationSettingsBase {
private static ItemColorSettings defaultInstance = ((ItemColorSettings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new ItemColorSettings())));

View file

@ -0,0 +1,60 @@
namespace ACSE.WinForms.MailEditorForm
{
partial class MailEditorForm
{
/// <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.listBox1 = new System.Windows.Forms.ListBox();
this.SuspendLayout();
//
// listBox1
//
this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Right)));
this.listBox1.FormattingEnabled = true;
this.listBox1.Location = new System.Drawing.Point(618, 12);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(170, 862);
this.listBox1.TabIndex = 0;
//
// MailEditorForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 887);
this.Controls.Add(this.listBox1);
this.Name = "MailEditorForm";
this.Text = "MailEditorForm";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ListBox listBox1;
}
}

View file

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ACSE.Core.Messages.Mail;
using ACSE.Core.Saves;
using ACSE.WinForms.Controls;
namespace ACSE.WinForms.MailEditorForm
{
public partial class MailEditorForm : Form
{
private readonly MessageEditor messageEditor;
public MailEditorForm()
{
// Load player mail
// TODO: Move this logic to ACSE.Core
var playerMail = new GcnPlayerMail[10];
for (var i = 0; i < 10; i++)
{
//playerMail[i] = new GcnPlayerMail();
}
InitializeComponent();
messageEditor = new MessageEditor();
//messageEditor.SetMailReference();
}
}
}

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

@ -33,11 +33,13 @@ private void InitializeComponent()
this.components = new System.ComponentModel.Container();
System.Windows.Forms.TabPage patternsTab;
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.patternNameTextBox = new System.Windows.Forms.PlaceholderTextBox();
this.paletteColorSelectedPictureBox = new System.Windows.Forms.PictureBox();
this.paletteIndexLabel = new System.Windows.Forms.Label();
this.palettePreviousButton = new System.Windows.Forms.Button();
this.paletteNextButton = new System.Windows.Forms.Button();
this.patternEditorPanel = new System.Windows.Forms.Panel();
this.patternEditorPictureBox = new ACSE.WinForms.Controls.PictureBoxWithInterpolationMode();
this.patternEditorPreviewPanel = new System.Windows.Forms.Panel();
this.patternGroupTabControl = new System.Windows.Forms.TabControl();
this.player1Tab = new System.Windows.Forms.TabPage();
@ -48,6 +50,7 @@ private void InitializeComponent()
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.openDolphinSaveFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.openCitraSaveFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.newLeafToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.eURToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@ -59,6 +62,7 @@ private void InitializeComponent()
this.uSAToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.jPNToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.kORToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
@ -269,17 +273,15 @@ private void InitializeComponent()
this.loadingPanel = new System.Windows.Forms.Panel();
this.label45 = new System.Windows.Forms.Label();
this.infoTip = new System.Windows.Forms.ToolTip(this.components);
this.itemIdTextBox = new System.Windows.Forms.PlaceholderTextBox();
this.itemIdLabel = new System.Windows.Forms.Label();
this.StatusLabel = new System.Windows.Forms.TextBox();
this.openDolphinSaveFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
this.itemIdTextBox = new System.Windows.Forms.PlaceholderTextBox();
this.patternNameTextBox = new System.Windows.Forms.PlaceholderTextBox();
this.patternEditorPictureBox = new ACSE.WinForms.Controls.PictureBoxWithInterpolationMode();
this.PartTimeJobCheckBox = new System.Windows.Forms.CheckBox();
patternsTab = new System.Windows.Forms.TabPage();
patternsTab.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.paletteColorSelectedPictureBox)).BeginInit();
this.patternEditorPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.patternEditorPictureBox)).BeginInit();
this.patternGroupTabControl.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.paletteSelectionPictureBox)).BeginInit();
this.menuStrip1.SuspendLayout();
@ -316,7 +318,6 @@ private void InitializeComponent()
this.pictureContextMenu.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.acreHeightTrackBar)).BeginInit();
this.loadingPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.patternEditorPictureBox)).BeginInit();
this.SuspendLayout();
//
// patternsTab
@ -337,6 +338,18 @@ private void InitializeComponent()
patternsTab.Text = "Patterns";
patternsTab.UseVisualStyleBackColor = true;
//
// patternNameTextBox
//
this.patternNameTextBox.Anchor = System.Windows.Forms.AnchorStyles.None;
this.patternNameTextBox.Location = new System.Drawing.Point(415, 538);
this.patternNameTextBox.MaxLength = 16;
this.patternNameTextBox.Name = "patternNameTextBox";
this.patternNameTextBox.PlaceholderText = "Pattern Name";
this.patternNameTextBox.PlaceholderTextColor = System.Drawing.Color.Gray;
this.patternNameTextBox.Size = new System.Drawing.Size(100, 20);
this.patternNameTextBox.TabIndex = 0;
this.patternNameTextBox.TextChanged += new System.EventHandler(this.PatternEditorNameBox_TextChanged);
//
// paletteColorSelectedPictureBox
//
this.paletteColorSelectedPictureBox.Anchor = System.Windows.Forms.AnchorStyles.None;
@ -389,6 +402,23 @@ private void InitializeComponent()
this.patternEditorPanel.Size = new System.Drawing.Size(513, 513);
this.patternEditorPanel.TabIndex = 16;
//
// patternEditorPictureBox
//
this.patternEditorPictureBox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.patternEditorPictureBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.patternEditorPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
this.patternEditorPictureBox.Location = new System.Drawing.Point(0, 0);
this.patternEditorPictureBox.Name = "patternEditorPictureBox";
this.patternEditorPictureBox.Size = new System.Drawing.Size(513, 513);
this.patternEditorPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.patternEditorPictureBox.TabIndex = 0;
this.patternEditorPictureBox.TabStop = false;
this.patternEditorPictureBox.UseInternalInterpolationSetting = false;
this.patternEditorPictureBox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.PatternEditorBoxMouseDown);
this.patternEditorPictureBox.MouseLeave += new System.EventHandler(this.PatternEditorBoxMouseLeave);
this.patternEditorPictureBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PatternEditorBoxMouseMove);
this.patternEditorPictureBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.PatternEditorBoxMouseUp);
//
// patternEditorPreviewPanel
//
this.patternEditorPreviewPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
@ -504,6 +534,13 @@ private void InitializeComponent()
this.openToolStripMenuItem.Text = "Open";
this.openToolStripMenuItem.Click += new System.EventHandler(this.OpenToolStripMenuItemClick);
//
// openDolphinSaveFileToolStripMenuItem
//
this.openDolphinSaveFileToolStripMenuItem.Name = "openDolphinSaveFileToolStripMenuItem";
this.openDolphinSaveFileToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
this.openDolphinSaveFileToolStripMenuItem.Text = "Open Dolphin Save File";
this.openDolphinSaveFileToolStripMenuItem.Click += new System.EventHandler(this.OpenDolphinSaveFileClick);
//
// openCitraSaveFileToolStripMenuItem
//
this.openCitraSaveFileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -591,6 +628,11 @@ private void InitializeComponent()
this.kORToolStripMenuItem1.Text = "KOR";
this.kORToolStripMenuItem1.Click += new System.EventHandler(this.KorToolStripMenuItem1Click);
//
// toolStripSeparator3
//
this.toolStripSeparator3.Name = "toolStripSeparator3";
this.toolStripSeparator3.Size = new System.Drawing.Size(193, 6);
//
// saveToolStripMenuItem
//
this.saveToolStripMenuItem.Enabled = false;
@ -833,6 +875,7 @@ private void InitializeComponent()
//
// playersTab
//
this.playersTab.Controls.Add(this.PartTimeJobCheckBox);
this.playersTab.Controls.Add(this.badgeGroupBox);
this.playersTab.Controls.Add(this.groupBox1);
this.playersTab.Controls.Add(this.censusMenuEnabled);
@ -2291,6 +2334,7 @@ private void InitializeComponent()
this.houseOwnerComboBox.Name = "houseOwnerComboBox";
this.houseOwnerComboBox.Size = new System.Drawing.Size(121, 21);
this.houseOwnerComboBox.TabIndex = 8;
this.houseOwnerComboBox.SelectedIndexChanged += new System.EventHandler(this.HouseOwnerComboBoxSelectedIndexChanged);
//
// label30
//
@ -2773,6 +2817,21 @@ private void InitializeComponent()
this.label45.TabIndex = 15;
this.label45.Text = "Loading...";
//
// itemIdTextBox
//
this.itemIdTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.itemIdTextBox.Enabled = false;
this.itemIdTextBox.Location = new System.Drawing.Point(132, 620);
this.itemIdTextBox.Name = "itemIdTextBox";
this.itemIdTextBox.PlaceholderText = "Item ID";
this.itemIdTextBox.PlaceholderTextColor = System.Drawing.Color.Gray;
this.itemIdTextBox.Size = new System.Drawing.Size(46, 20);
this.itemIdTextBox.TabIndex = 78;
this.itemIdTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.infoTip.SetToolTip(this.itemIdTextBox, "The hexadecimal Item ID. Example: A31C");
this.itemIdTextBox.TextChanged += new System.EventHandler(this.CurrentItemIdTextChanged);
this.itemIdTextBox.Leave += new System.EventHandler(this.CurrentItemIdLostFocus);
//
// itemIdLabel
//
this.itemIdLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
@ -2795,61 +2854,19 @@ private void InitializeComponent()
this.StatusLabel.TabIndex = 16;
this.StatusLabel.TabStop = false;
//
// openDolphinSaveFileToolStripMenuItem
// PartTimeJobCheckBox
//
this.openDolphinSaveFileToolStripMenuItem.Name = "openDolphinSaveFileToolStripMenuItem";
this.openDolphinSaveFileToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
this.openDolphinSaveFileToolStripMenuItem.Text = "Open Dolphin Save File";
this.openDolphinSaveFileToolStripMenuItem.Click += new System.EventHandler(this.OpenDolphinSaveFileClick);
//
// toolStripSeparator3
//
this.toolStripSeparator3.Name = "toolStripSeparator3";
this.toolStripSeparator3.Size = new System.Drawing.Size(193, 6);
//
// itemIdTextBox
//
this.itemIdTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.itemIdTextBox.Enabled = false;
this.itemIdTextBox.Location = new System.Drawing.Point(132, 620);
this.itemIdTextBox.Name = "itemIdTextBox";
this.itemIdTextBox.PlaceholderText = "Item ID";
this.itemIdTextBox.PlaceholderTextColor = System.Drawing.Color.Gray;
this.itemIdTextBox.Size = new System.Drawing.Size(46, 20);
this.itemIdTextBox.TabIndex = 78;
this.itemIdTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.infoTip.SetToolTip(this.itemIdTextBox, "The hexadecimal Item ID. Example: A31C");
this.itemIdTextBox.TextChanged += new System.EventHandler(this.CurrentItemIdTextChanged);
this.itemIdTextBox.Leave += new System.EventHandler(this.CurrentItemIdLostFocus);
//
// patternNameTextBox
//
this.patternNameTextBox.Anchor = System.Windows.Forms.AnchorStyles.None;
this.patternNameTextBox.Location = new System.Drawing.Point(415, 538);
this.patternNameTextBox.MaxLength = 16;
this.patternNameTextBox.Name = "patternNameTextBox";
this.patternNameTextBox.PlaceholderText = "Pattern Name";
this.patternNameTextBox.PlaceholderTextColor = System.Drawing.Color.Gray;
this.patternNameTextBox.Size = new System.Drawing.Size(100, 20);
this.patternNameTextBox.TabIndex = 0;
this.patternNameTextBox.TextChanged += new System.EventHandler(this.PatternEditorNameBox_TextChanged);
//
// patternEditorPictureBox
//
this.patternEditorPictureBox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.patternEditorPictureBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.patternEditorPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
this.patternEditorPictureBox.Location = new System.Drawing.Point(0, 0);
this.patternEditorPictureBox.Name = "patternEditorPictureBox";
this.patternEditorPictureBox.Size = new System.Drawing.Size(513, 513);
this.patternEditorPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.patternEditorPictureBox.TabIndex = 0;
this.patternEditorPictureBox.TabStop = false;
this.patternEditorPictureBox.UseInternalInterpolationSetting = false;
this.patternEditorPictureBox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.PatternEditorBoxMouseDown);
this.patternEditorPictureBox.MouseLeave += new System.EventHandler(this.PatternEditorBoxMouseLeave);
this.patternEditorPictureBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PatternEditorBoxMouseMove);
this.patternEditorPictureBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.PatternEditorBoxMouseUp);
this.PartTimeJobCheckBox.AutoSize = true;
this.PartTimeJobCheckBox.Enabled = false;
this.PartTimeJobCheckBox.Location = new System.Drawing.Point(772, 38);
this.PartTimeJobCheckBox.Name = "PartTimeJobCheckBox";
this.PartTimeJobCheckBox.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
this.PartTimeJobCheckBox.Size = new System.Drawing.Size(125, 17);
this.PartTimeJobCheckBox.TabIndex = 80;
this.PartTimeJobCheckBox.Text = ":Doing Part Time Job";
this.infoTip.SetToolTip(this.PartTimeJobCheckBox, "Toggles whether or not the Player is doing Nook\'s part time job.");
this.PartTimeJobCheckBox.UseVisualStyleBackColor = true;
this.PartTimeJobCheckBox.CheckedChanged += new System.EventHandler(this.PartTimeJobCheckBoxCheckChanged);
//
// MainForm
//
@ -2882,6 +2899,7 @@ private void InitializeComponent()
patternsTab.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.paletteColorSelectedPictureBox)).EndInit();
this.patternEditorPanel.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.patternEditorPictureBox)).EndInit();
this.patternGroupTabControl.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.paletteSelectionPictureBox)).EndInit();
this.menuStrip1.ResumeLayout(false);
@ -2929,7 +2947,6 @@ private void InitializeComponent()
((System.ComponentModel.ISupportInitialize)(this.acreHeightTrackBar)).EndInit();
this.loadingPanel.ResumeLayout(false);
this.loadingPanel.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.patternEditorPictureBox)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
@ -3180,5 +3197,6 @@ private void InitializeComponent()
private System.Windows.Forms.PictureBox townGatePictureBox;
private System.Windows.Forms.ToolStripMenuItem openDolphinSaveFileToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator3;
private System.Windows.Forms.CheckBox PartTimeJobCheckBox;
}
}

View file

@ -23,6 +23,7 @@
using ACSE.Core.Housing;
using ACSE.Core.Items;
using ACSE.Core.Modifiable;
using ACSE.Core.Quests;
using ACSE.Core.Patterns;
using ACSE.Core.Players;
using ACSE.Core.Saves;
@ -116,6 +117,7 @@ public sealed partial class MainForm : Form
private ItemEditor _islandBoxEditor;
private HouseControl _houseEditor;
private HouseControl _islandHouseEditor;
private VillagerControl _islanderEditor;
private StalkMarketEditor _stalkMarketEditor;
private List<AcreItemEditor> _acreItemEditors = new List<AcreItemEditor>();
private List<AcreItemEditor> _islandItemEditors = new List<AcreItemEditor>();
@ -587,6 +589,9 @@ private void EnableEditorControls(Save save)
reviveGrass.Enabled = true;
removeGrass.Enabled = true;
censusMenuEnabled.Enabled = save.SaveType == SaveType.WelcomeAmiibo;
PartTimeJobCheckBox.Enabled = save.SaveGeneration == SaveGeneration.N64 ||
save.SaveGeneration == SaveGeneration.GCN ||
save.SaveGeneration == SaveGeneration.iQue;
fillCatalogButton.Enabled = true;
clearCatalogButton.Enabled = true;
fillEncyclopediaButton.Enabled = true;
@ -1098,7 +1103,7 @@ await Task.Run(() =>
houseSizeComboBox.Enabled = houseSizeComboBox.Items.Count > 0;
//Load Villager Database
if (SaveFile.SaveType != SaveType.CityFolk) //City Folk has completely editable villagers! That's honestly a pain for editing...
//if (SaveFile.SaveType != SaveType.CityFolk) //City Folk has completely editable villagers! That's honestly a pain for editing...
{
_villagerDatabase = VillagerInfo.GetVillagerDatabase(SaveFile.SaveType);
_personalityDatabase = VillagerInfo.GetPersonalities(SaveFile.SaveType);
@ -1248,7 +1253,7 @@ await Task.Run(() =>
{
_players[i] = new Player(SaveFile.SaveDataStartOffset
+ CurrentSaveInfo.SaveOffsets.PlayerStart +
i * CurrentSaveInfo.SaveOffsets.PlayerSize, i, SaveFile);
i * CurrentSaveInfo.SaveOffsets.PlayerSize, i);
}
_selectedPlayer = _players.FirstOrNull(o => o.Exists);
@ -1286,7 +1291,7 @@ await Task.Run(() =>
// Grass Type Stuff
grassTypeBox.Items.Clear();
grassTypeBox.Enabled = true;
grassTypeBox.Enabled = save.SaveGeneration != SaveGeneration.N64 && save.SaveGeneration != SaveGeneration.iQue;
// Load islands if DnMe+
_selectedIsland = null;
@ -1392,7 +1397,7 @@ await Task.Run(() =>
}
// Load villagers
if (SaveFile.SaveType != SaveType.CityFolk)
//if (SaveFile.SaveType != SaveType.CityFolk)
{
await Task.Run(() => { LoadVillagers(save); });
CreateVillagerPanelControls();
@ -1956,6 +1961,7 @@ private void ReloadPlayer(Player player)
}
resettiCheckBox.Checked = player.Data.Reset;
PartTimeJobCheckBox.Checked = PartTimeJobCheckBox.Enabled && player.IsPartTimeJobActive();
if (SaveFile.SaveGeneration == SaveGeneration.N3DS)
{
@ -2637,6 +2643,22 @@ private void SetupMapPictureBoxes()
islandItemEditor.SetNewBackgroundImage(
GetAcreImage(selectedIslandAcreIds[idx]));
// TODO: This is not e+ only.
_islanderEditor?.Dispose();
_islanderEditor = new VillagerControl(this, 15, Save.SaveInstance, _selectedIsland.Islander,
_villagerDatabase, _villagerNames, _personalityDatabase)
{
Location = new Point(_townMapTotalSize * 2 + 20, 10)
};
// This part is e+ exclusive, though.
_islanderEditor.VillagerChanged += delegate
{
_selectedIsland?.ResetIslanderHasAppeared();
};
islandPanel.Controls.Add(_islanderEditor);
}
else
{
@ -2749,6 +2771,26 @@ private void House_Tab_Index_Changed(object sender, TabControlEventArgs e)
ReloadHouse(_selectedHouse);
}
private void HouseOwnerComboBoxSelectedIndexChanged(object sender, EventArgs e)
{
if (_loading || !houseOwnerComboBox.Enabled || _selectedHouse == null ||
houseOwnerComboBox.SelectedIndex < 0) return;
switch (houseOwnerComboBox.SelectedIndex)
{
case 0:
_selectedHouse.Owner = null;
_selectedHouse.Data.OwningPlayerId = 0xFFFF;
_selectedHouse.Data.OwningPlayerName = "";
break;
default:
_selectedHouse.Owner = _players[houseOwnerComboBox.SelectedIndex - 1];
_selectedHouse.Data.OwningPlayerId = _selectedHouse.Owner?.Data.Identifier ?? 0xFFFF;
_selectedHouse.Data.OwningPlayerName = _selectedHouse.Owner?.Data.Name ?? "";
break;
}
}
private void ReloadHouse(House selectedHouse)
{
if (selectedHouse == null) return;
@ -4586,6 +4628,12 @@ private void ResettiCheckBoxCheckedChanged(object sender, EventArgs e)
}
}
private void PartTimeJobCheckBoxCheckChanged(object sender, EventArgs e)
{
if (_loading || SaveFile == null || _selectedPlayer == null || !PartTimeJobCheckBox.Enabled) return;
_selectedPlayer.SetPartTimeJobStatus(PartTimeJobCheckBox.Checked);
}
private void ClearWeedsToolStripMenuItemClick(object sender, EventArgs e)
{
ClearWeedsButtonClick();
@ -5118,6 +5166,9 @@ private void IslandTabIndexChanged(object sender, TabControlEventArgs e)
if (_islandHouseEditor == null) return;
_islandHouseEditor.House = _selectedIsland.Cabana;
if (_islanderEditor == null) return;
_islanderEditor.SetVillager(_selectedIsland.Islander);
}
private void ReloadIslandItemPicture()

View file

@ -156,12 +156,18 @@
<metadata name="exportPatternFile.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>946, 17</value>
</metadata>
<metadata name="townToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>1090, 17</value>
</metadata>
<metadata name="acreToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>1210, 17</value>
</metadata>
<metadata name="villagerToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>1325, 17</value>
</metadata>
<metadata name="houseToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 41</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>

View file

@ -19,7 +19,7 @@ namespace ACSE.WinForms.Properties {
// 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", "15.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {

View file

@ -12,7 +12,7 @@ namespace ACSE.WinForms.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

View file

@ -561,7 +561,7 @@
0x12A8, Billiard Table
0x12AC, Famous Painting
0x12B0, Basic Painting
0x12B4, Scarying Painting
0x12B4, Scary Painting
0x12B8, Moving Painting
0x12BC, Flowery Painting
0x12C0, Common Painting
@ -1383,7 +1383,7 @@
0x1F80, T-rex D
0x1F84, Bronto D
0x1F88, Ptera D
0x1F8C, HUTABAD
0x1F8C, Plesio D
0x1F90, Mammoth D
0x1F94, Stego D
0x1F98, Stego D2
@ -2094,7 +2094,7 @@
0x251F, Present (Golden Net)
0x2520, Present (Golden Axe)
0x2521, Present (Golden Shovel)
0x2522, Present(Golden Rod)
0x2522, Present (Golden Rod)
0x2523, Exercise Card
0x2524, Exercise Card
0x2525, Exercise Card

View file

@ -0,0 +1,244 @@
// Anteaters
0x0000, Cyrano
0x0001, Antonio
0x0002, Pango
0x0003, Anabelle
// Bears
0x0004, Teddy
0x0005, Pinky
0x0006, Curt
0x0007, Chow
0x0008, Nate
0x0009, Groucho
0x000A, Tutu
0x000B, Grizzly
// Birds
0x000C, Jay
0x000D, Robin
0x000E, Anchovy
0x000F, Twiggy
0x0010, Jitters
0x0011, Midge
// Bulls
0x0012, Angus
0x0013, Rodeo
// Cats
0x0014, Bob
0x0015, Mitzi
0x0016, Rosie
0x0017, Olivia
0x0018, Kiki
0x0019, Tangy
0x001A, Punchy
0x001B, Purrl
0x001C, Moe
0x001D, Kabuki
0x001E, Kid Cat
0x001F, Monique
0x0020, Tabby
0x0021, Stinky
0x0022, Kitty
0x0023, Tom
0x0024, Merry
0x0025, Felicity
0x0026, Lolly
0x0027, Ankha
// Cubs
0x0028, Bluebear
0x0029, Maple
0x002A, Poncho
0x002B, Pudge
0x002C, Kody
0x002D, Stitches
0x002E, Vladimir
// Chickens
0x002F, Goose
0x0030, Benedict
0x0031, Egbert
0x0032, Becky
// Cows
0x0033, Patty
0x0034, Tipper
// Crocodiles
0x0035, Alfonso
0x0036, Alli
0x0037, Del
// Dogs
0x0038, Goldie
0x0039, Butch
0x003A, Lucky
0x003B, Biskit
0x003C, Bones
0x003D, Portia
0x003E, Walker
0x003F, Daisy
0x0040, Cookie
// Ducks
0x0041, Bill
0x0042, Joey
0x0043, Pate
0x0044, Maelle
0x0045, Deena
0x0046, Pompom
0x0047, Mallary
0x0048, Freckles
0x0049, Derwin
0x004A, Drake
0x004B, Scoot
0x004C, Miranda
// Elephants
0x004D, Opal
0x004E, Dizzy
0x004F, Big Top
0x0050, Eloise
0x0051, Margie
0x0052, Axel
// Frogs
0x0053, Lily
0x0054, Ribbot
0x0055, Frobert
0x0056, Camofrog
0x0057, Drift
0x0058, Wart Jr.
0x0059, Puddles
0x005A, Jeremiah
0x005B, Cousteau
0x005C, Prince
0x005D, Jambette
// Goats
0x005E, Chevre
0x005F, Nan
// Gorillas
0x0060, Cesar
0x0061, Peewee
0x0062, Boone
0x0063, Violet
// Hippos
0x0064, Rocco
0x0065, Harry
// Horses
0x0066, Buck
0x0067, Victoria
0x0068, Savannah
0x0069, Elmer
0x006A, Roscoe
0x006B, Winnie
0x006C, Ed
0x006D, Peaches
// Koalas
0x006E, Yuka
0x006F, Alice
0x0070, Melba
0x0071, Sydney
// Kangaroos
0x0072, Kit
0x0073, Mathilda
0x0074, Astrid
// Lions
0x0075, Bud
0x0076, Elvis
// Monkeys
0x0077, Champ
0x0078, Nana
0x0079, Simon
0x007A, Tammi
0x007B, Monty
0x007C, Elise
// Mice
0x007D, Dora
0x007E, Limberg
0x007F, Bella
0x0080, Bree
0x0081, Samson
0x0082, Rod
0x0083, Dizzo
0x0084, Broccolo
// Octopi
0x0085, Octavian
0x0086, Marina
// Ostriches
0x0087, Queenie
0x0088, Gladys
// Eagles
0x0089, Apollo
0x008A, Amelia
0x008B, Pierce
0x008C, Avery
// Penguins
0x008D, Aurora
0x008E, Roald
0x008F, Cube
0x0090, Hopper
0x0091, Friga
0x0092, Gwen
0x0093, Puck
0x0094, Boomer
// Pigs
0x0095, Curly
0x0096, Truffles
0x0097, Rasher
0x0098, Hugh
0x0099, Lucy
0x009A, Spork
0x009B, Peggy
// Rabbits
0x009C, Bunnie
0x009D, Dotty
0x009E, Coco
0x009F, Snake
0x00A0, Gaston
0x00A1, Gabi
0x00A2, Pippy
0x00A3, Tiffany
0x00A4, Genji
0x00A5, Ruby
0x00A6, Francine
0x00A7, Chrissy
// Rhinos
0x00A8, Tank
0x00A9, Rhonda
// Sheep
0x00AA, Vesta
0x00AB, Baabara
0x00AC, Eunice
0x00AD, Willow
// Squirrels
0x00AE, Peanut
0x00AF, Blaire
0x00B0, Filbert
0x00B1, Pecan
0x00B2, Nibbles
0x00B3, Agent S
0x00B4, Caroline
0x00B5, Sally
0x00B6, Static
0x00B7, Mint
// Tigers
0x00B8, Rolf
0x00B9, Rowan
// Wolves
0x00BA, Chief
0x00BB, Lobo
0x00BC, Wolfgang
0x00BD, Whitney
0x00BE, Freya
0x00BF, Fang
// Unorganized New Villagers
0x00C0, Poppy
0x00C1, Carmen
0x00C2, Clyde
0x00C3, Pekoe
0x00C4, Al
0x00C5, Iggly
0x00C6, Gala
0x00C7, Gloria
0x00C8, Moose
0x00C9, Chester
0x00CA, Mac
0x00CB, Mott
0x00CC, Gigi
0x00CD, Bettina
0x00CE, Wendy
0x00CF, Knox
0x00D0, Sterling
0x00D1, Marcel

View file

@ -1415,7 +1415,7 @@
0x1FC0, T-rex D
0x1FC4, Bronto D
0x1FC8, Ptera D
0x1FCC, HUTABAD
0x1FCC, Plesio D
0x1FD0, Mammoth D
0x1FD4, Stego D
0x1FD8, Stego D2
@ -2098,14 +2098,14 @@
0x24FE, Melon Gingham
0x24FF, Mannekin Shirt
0x2500, Quest Letter
0x2501, Quest Item
0x2502, Quest Money
0x2503, Videotape
0x2504, Organizer
0x2505, Pokémon Pikachu
0x2506, Comic Book
0x2507, Picture Book
0x2508, Game Boy
0x2501, Clothes
0x2502, Fishing Rod
0x2503, Net
0x2504, Shovel
0x2505, Axe
0x2506, Pinwheel
0x2507, Fan
0x2508, Gyroid
0x2509, Camera
0x250A, Watch
0x250B, Handkerchief
@ -3259,7 +3259,7 @@
0x586E, Signboard (34)
0x586F, Signboard (35)
0x5870, Signboard (36)
// Probably more Signboards
0x5871, Islander Signboard
0x8000, Beta Paper Airplane (Replicates Limitlessly)
0x8003, Beta Yellow/Brown Rotating Cube
0xA000, Upper Left House's Mailbox

View file

@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ACSE.Tests</RootNamespace>
<AssemblyName>ACSE.Tests</AssemblyName>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
@ -19,6 +19,7 @@
<TestProjectType>UnitTest</TestProjectType>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>