Add item[]->field item column/offset for injection

This commit is contained in:
Kurt
2021-01-17 18:36:29 -08:00
parent d7b46726a0
commit 1f46556664
3 changed files with 135 additions and 7 deletions

View File

@@ -0,0 +1,24 @@
namespace NHSE.Core
{
public sealed class FieldItemColumn
{
/// <summary> X Coordinate within the Field Item Layer </summary>
public readonly int X;
/// <summary> Y Coordinate within the Field Item Layer </summary>
public readonly int Y;
/// <summary> Offset relative to the start of the Field Item Layer </summary>
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;
}
}
}

View File

@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace NHSE.Core
{
/// <summary>
/// Converts <see cref="Item"/> into columns of writable Item tiles.
/// </summary>
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<FieldItemColumn> InjectItemsAsDropped(int mapX, int mapY, IReadOnlyList<Item> item)
{
int yStride = (item.Count > 16) ? 16 : item.Count;
return InjectItemsAsDropped(mapX, mapY, item, yStride);
}
public static IReadOnlyList<FieldItemColumn> InjectItemsAsDropped(int mapX, int mapY, IReadOnlyList<Item> item, int yStride)
{
var xStride = item.Count / yStride;
List<FieldItemColumn> 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 };
}
}

View File

@@ -23,13 +23,14 @@ public class Item : ICopyableItem<Item>
[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