Skip to content

Commit

Permalink
Push Local Changes
Browse files Browse the repository at this point in the history
Way too much to actually document
  • Loading branch information
Cuyler36 committed Mar 8, 2020
1 parent 1cdd0fd commit 42bd503
Show file tree
Hide file tree
Showing 41 changed files with 1,695 additions and 478 deletions.
4 changes: 4 additions & 0 deletions ACSE.Core/ACSE.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
25 changes: 25 additions & 0 deletions ACSE.Core/BitFields/Catalog/Catalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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;
}
Expand Down
91 changes: 53 additions & 38 deletions ACSE.Core/Generators/GCNGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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][]
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
6 changes: 6 additions & 0 deletions ACSE.Core/Housing/HouseData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using ACSE.Core.Items;
using ACSE.Core.Patterns;
using ACSE.Core.Players;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
}
Expand Down
22 changes: 11 additions & 11 deletions ACSE.Core/Items/Inventory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
Expand Down
2 changes: 2 additions & 0 deletions ACSE.Core/Items/Item.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions ACSE.Core/Messages/Mail/GCN.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace ACSE.Core.Messages.Mail
{
public struct AnimalForestEPlusMailHeader
{

}
}
52 changes: 34 additions & 18 deletions ACSE.Core/Messages/Mail/GCNPlayerMail.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using ACSE.Core.Items;
using ACSE.Core.Players;
using ACSE.Core.Saves;

namespace ACSE.Core.Messages.Mail
Expand All @@ -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);
}
}

Expand All @@ -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;
}
}
Loading

0 comments on commit 42bd503

Please sign in to comment.