From 1f46556664b5d40783e3c115aa2bdd4b616f8268 Mon Sep 17 00:00:00 2001 From: Kurt Date: Sun, 17 Jan 2021 18:36:29 -0800 Subject: [PATCH] Add item[]->field item column/offset for injection --- .../Editing/FieldItem/FieldItemColumn.cs | 24 ++++ .../Editing/FieldItem/FieldItemDropper.cs | 103 ++++++++++++++++++ NHSE.Core/Structures/Item/Item.cs | 15 +-- 3 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 NHSE.Core/Editing/FieldItem/FieldItemColumn.cs create mode 100644 NHSE.Core/Editing/FieldItem/FieldItemDropper.cs diff --git a/NHSE.Core/Editing/FieldItem/FieldItemColumn.cs b/NHSE.Core/Editing/FieldItem/FieldItemColumn.cs new file mode 100644 index 0000000..ae5fe7d --- /dev/null +++ b/NHSE.Core/Editing/FieldItem/FieldItemColumn.cs @@ -0,0 +1,24 @@ +namespace NHSE.Core +{ + public sealed class FieldItemColumn + { + /// X Coordinate within the Field Item Layer + public readonly int X; + + /// Y Coordinate within the Field Item Layer + public readonly int Y; + + /// Offset relative to the start of the Field Item Layer + public readonly int Offset; + + public readonly byte[] Data; + + public FieldItemColumn(int x, int y, int offset, byte[] data) + { + X = x; + Y = y; + Offset = offset; + Data = data; + } + } +} diff --git a/NHSE.Core/Editing/FieldItem/FieldItemDropper.cs b/NHSE.Core/Editing/FieldItem/FieldItemDropper.cs new file mode 100644 index 0000000..eed06e0 --- /dev/null +++ b/NHSE.Core/Editing/FieldItem/FieldItemDropper.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace NHSE.Core +{ + /// + /// Converts into columns of writable Item tiles. + /// + public static class FieldItemDropper + { + private const int MapHeight = FieldItemLayer.FieldItemHeight; + private const int MapWidth = FieldItemLayer.FieldItemWidth; + + // Each dropped item is a 2x2 square, with the top left tile being the root node, and the other 3 being extensions pointing back to the root. + + public static bool CanFitDropped(int x, int y, int count, int vStride) + { + if (2 * (Math.Max(16, y) + vStride) > MapHeight - 32) + return false; + + var xStride = count / vStride; + if (2 * (Math.Max(16, x) + xStride) > MapWidth - 32) + return false; + + return count < (MapHeight * MapWidth / 32); + } + + public static IReadOnlyList InjectItemsAsDropped(int mapX, int mapY, IReadOnlyList item) + { + int yStride = (item.Count > 16) ? 16 : item.Count; + return InjectItemsAsDropped(mapX, mapY, item, yStride); + } + + public static IReadOnlyList InjectItemsAsDropped(int mapX, int mapY, IReadOnlyList item, int yStride) + { + var xStride = item.Count / yStride; + List result = new(yStride * xStride); + for (int i = 0; i < xStride; i++) + { + var x = mapX + (i * 2); + var y = mapY; + var itemSlice = item.Skip(i * yStride).Take(yStride).ToArray(); + + // Root+ExtensionY + var offset = GetTileOffset(x, y); + var data = GetColumnRoot(itemSlice); + var column = new FieldItemColumn(x, y, offset, data); + result.Add(column); + + // Ex X/XY + ++x; + offset = GetTileOffset(x, y); + data = GetColumnExtension(itemSlice); + column = new FieldItemColumn(x, y, offset, data); + result.Add(column); + } + return result; + } + + private static byte[] GetColumnRoot(Item[] items) + { + var col = new Item[items.Length * 2]; + for (int i = 0; i < items.Length; i++) + { + var item = items[i]; + var idx = i * 2; + col[idx] = GetDroppedItem(item); + col[idx + 1] = GetExtension(item, 0, 1); + } + return Item.SetArray(col); + } + + private static byte[] GetColumnExtension(Item[] items) + { + var col = new Item[items.Length * 2]; + for (int i = 0; i < items.Length; i++) + { + var item = items[i]; + var idx = i * 2; + col[idx] = GetExtension(item, 1, 0); + col[idx + 1] = GetExtension(item, 1, 1); + } + return Item.SetArray(col); + } + + private static int GetTileOffset(int x, int y) + { + return Item.SIZE * (y + (x * MapHeight)); + } + + private static Item GetDroppedItem(Item item) + { + var copy = new Item(); + copy.CopyFrom(item); + copy.ClearFlags(); + copy.IsDropped = true; + return copy; + } + + private static Item GetExtension(Item item, byte x, byte y) => new(Item.EXTENSION) { ExtensionItemId = item.ItemId, ExtensionX = x, ExtensionY = y }; + } +} diff --git a/NHSE.Core/Structures/Item/Item.cs b/NHSE.Core/Structures/Item/Item.cs index 5270a53..5604758 100644 --- a/NHSE.Core/Structures/Item/Item.cs +++ b/NHSE.Core/Structures/Item/Item.cs @@ -23,13 +23,14 @@ public class Item : ICopyableItem [field: FieldOffset(3)] public byte AdditionalParam { get; set; } [field: FieldOffset(4)] public int FreeParam { get; set; } - public int Rotation => SystemParam & 3; - public bool IsBuried => (SystemParam & 4) != 0; - public bool Is_08 => (SystemParam & 0x08) != 0; - public bool Is_10 => (SystemParam & 0x10) != 0; - public bool IsDropped => (SystemParam & 0x20) != 0; - public bool Is_40 => (SystemParam & 0x40) != 0; - public bool Is_80 => (SystemParam & 0x80) != 0; + public void ClearFlags() => SystemParam = 0; + public int Rotation { get => SystemParam & 3; set => SystemParam = (byte)((SystemParam & ~3) | (value & 3)); } + public bool IsBuried { get => (SystemParam & 0x04) != 0; set => SystemParam = (byte) ((SystemParam & ~0x04) | (value ? 0x04 : 0)); } + public bool Is_08 { get => (SystemParam & 0x08) != 0; set => SystemParam = (byte) ((SystemParam & ~0x08) | (value ? 0x08 : 0)); } + public bool Is_10 { get => (SystemParam & 0x10) != 0; set => SystemParam = (byte) ((SystemParam & ~0x10) | (value ? 0x10 : 0)); } + public bool IsDropped { get => (SystemParam & 0x20) != 0; set => SystemParam = (byte) ((SystemParam & ~0x20) | (value ? 0x20 : 0)); } + public bool Is_40 { get => (SystemParam & 0x40) != 0; set => SystemParam = (byte) ((SystemParam & ~0x40) | (value ? 0x40 : 0)); } + public bool Is_80 { get => (SystemParam & 0x80) != 0; set => SystemParam = (byte) ((SystemParam & ~0x80) | (value ? 0x80 : 0)); } #region Flag1 (Wrapping / Etc) public bool IsWrapped