mirror of
https://github.com/kwsch/NHSE.git
synced 2026-04-25 07:37:02 -05:00
stash
working on it, untested. decoupled 99% of the logic, need to ensure the rendering uses the correct item grid which now includes deepsea L+R sides for 3.0.0
This commit is contained in:
parent
d276527404
commit
766e58ffec
|
|
@ -7,10 +7,12 @@ namespace NHSE.Core;
|
|||
/// <summary>
|
||||
/// Converts <see cref="Item"/> into columns of writable Item tiles.
|
||||
/// </summary>
|
||||
public static class FieldItemDropper
|
||||
/// <param name="AcreWidth">Field item acre width. 7 on pre-3.0.0 saves, 9 on 3.0.0+</param>
|
||||
/// <param name="AcreHeight">Always 6.</param>
|
||||
public sealed record FieldItemDropper(int AcreWidth, int AcreHeight = 6)
|
||||
{
|
||||
private const int MapHeight = FieldItemLayer.FieldItemHeight;
|
||||
private const int MapWidth = FieldItemLayer.FieldItemWidth;
|
||||
private int MapHeight => AcreWidth * FieldItemLayer.TilesPerAcreDim;
|
||||
private int MapWidth => AcreHeight * FieldItemLayer.TilesPerAcreDim;
|
||||
|
||||
// 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.
|
||||
|
||||
|
|
@ -21,7 +23,7 @@ public static class FieldItemDropper
|
|||
/// <param name="yCount">Count of items tall the overall spawn-rectangle is.</param>
|
||||
/// <param name="borderX">Excluded outer tile count. Useful for enforcing that beach acre tiles are skipped.</param>
|
||||
/// <param name="borderY">Excluded outer tile count. Useful for enforcing that beach acre tiles are skipped.</param>
|
||||
public static bool CanFitDropped(int x, int y, int totalCount, int yCount, int borderX, int borderY)
|
||||
public bool CanFitDropped(int x, int y, int totalCount, int yCount, int borderX, int borderY)
|
||||
{
|
||||
return CanFitDropped(x, y, totalCount, yCount, borderX, borderX, borderY, borderY);
|
||||
}
|
||||
|
|
@ -39,7 +41,7 @@ public static bool CanFitDropped(int x, int y, int totalCount, int yCount, int b
|
|||
/// <param name="topY">Excluded outer tile count. Useful for enforcing that beach acre tiles are skipped.</param>
|
||||
/// <param name="botY">Excluded outer tile count. Useful for enforcing that beach acre tiles are skipped.</param>
|
||||
/// <returns>True if can fit, false if not.</returns>
|
||||
public static bool CanFitDropped(int x, int y, int totalCount, int yCount, int leftX, int rightX, int topY, int botY)
|
||||
public bool CanFitDropped(int x, int y, int totalCount, int yCount, int leftX, int rightX, int topY, int botY)
|
||||
{
|
||||
var xCount = totalCount / yCount;
|
||||
if (x < leftX || (x + (xCount * 2)) > MapWidth - rightX)
|
||||
|
|
@ -50,13 +52,13 @@ public static bool CanFitDropped(int x, int y, int totalCount, int yCount, int l
|
|||
return totalCount < (MapHeight * MapWidth / 32);
|
||||
}
|
||||
|
||||
public static IReadOnlyList<FieldItemColumn> InjectItemsAsDropped(int mapX, int mapY, IReadOnlyList<Item> item)
|
||||
public 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)
|
||||
public IReadOnlyList<FieldItemColumn> InjectItemsAsDropped(int mapX, int mapY, IReadOnlyList<Item> item, int yStride)
|
||||
{
|
||||
var xStride = item.Count / yStride;
|
||||
List<FieldItemColumn> result = new(yStride * xStride);
|
||||
|
|
@ -108,10 +110,7 @@ private static byte[] GetColumnExtension(ReadOnlySpan<Item> items)
|
|||
return Item.SetArray(col);
|
||||
}
|
||||
|
||||
private static int GetTileOffset(int x, int y)
|
||||
{
|
||||
return Item.SIZE * (y + (x * MapHeight));
|
||||
}
|
||||
private int GetTileOffset(int x, int y) => Item.SIZE * (y + (x * MapHeight));
|
||||
|
||||
private static Item GetDroppedItem(Item item)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -157,7 +157,8 @@ public Museum Museum
|
|||
set => value.Data.CopyTo(Data[Offsets.Museum..]);
|
||||
}
|
||||
|
||||
public const int AcreWidth = 7 + (2 * 1); // 1 on each side cannot be traversed
|
||||
// Acre Layout/Selection of which baselayer is selected for an acre.
|
||||
private const int AcreWidth = 7 + (2 * 1); // 1 on each side cannot be traversed
|
||||
private const int AcreHeight = 6 + (2 * 1); // 1 on each side cannot be traversed
|
||||
private const int AcreMax = AcreWidth * AcreHeight;
|
||||
private const int AcreSizeAll = AcreMax * 2;
|
||||
|
|
@ -185,7 +186,14 @@ public void SetAcreBytes(ReadOnlySpan<byte> data)
|
|||
data.CopyTo(Data[Offsets.OutsideField..]);
|
||||
}
|
||||
|
||||
public TerrainTile[] GetTerrainTiles() => TerrainTile.GetArray(Data.Slice(Offsets.LandMakingMap, MapGrid.MapTileCount16x16 * TerrainTile.SIZE));
|
||||
public byte FieldItemAcreWidth => Offsets.FieldItemAcreWidth; // 3.0.0 updated from 7 => 9
|
||||
public byte FieldItemAcreHeight => 6; // always 6
|
||||
private int FieldItemAcreCount => FieldItemAcreWidth * FieldItemAcreHeight;
|
||||
|
||||
private const int TotalTerrainTileCount = TerrainLayer.TilesPerAcreDim * TerrainLayer.TilesPerAcreDim * (7 * 6);
|
||||
private int TotalFieldItemTileCount => FieldItemLayer.TilesPerAcreDim * FieldItemLayer.TilesPerAcreDim * FieldItemAcreCount;
|
||||
|
||||
public TerrainTile[] GetTerrainTiles() => TerrainTile.GetArray(Data.Slice(Offsets.LandMakingMap, TotalTerrainTileCount * TerrainTile.SIZE));
|
||||
public void SetTerrainTiles(IReadOnlyList<TerrainTile> array) => TerrainTile.SetArray(array).CopyTo(Data[Offsets.LandMakingMap..]);
|
||||
|
||||
public const int MapDesignNone = 0xF800;
|
||||
|
|
@ -202,8 +210,8 @@ public void SetMapDesignTiles(ReadOnlySpan<ushort> value)
|
|||
cast.CopyTo(Data[Offsets.MyDesignMap..]);
|
||||
}
|
||||
|
||||
private const int FieldItemLayerSize = MapGrid.MapTileCount32x32 * Item.SIZE;
|
||||
private const int FieldItemFlagSize = MapGrid.MapTileCount32x32 / 8; // bitflags
|
||||
private int FieldItemLayerSize => TotalFieldItemTileCount * Item.SIZE;
|
||||
private int FieldItemFlagSize => TotalFieldItemTileCount / sizeof(byte); // bitflags
|
||||
|
||||
private int FieldItemLayer1 => Offsets.FieldItem;
|
||||
private int FieldItemLayer2 => Offsets.FieldItem + FieldItemLayerSize;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public abstract class MainSaveOffsets
|
|||
public abstract int PlayerHouseSize { get; }
|
||||
public abstract int PlayerRoomSize { get; }
|
||||
|
||||
public virtual int AcreColumnCount => 7;
|
||||
public virtual byte FieldItemAcreWidth => 7;
|
||||
|
||||
public abstract IVillager ReadVillager(Memory<byte> data);
|
||||
public abstract IVillagerHouse ReadVillagerHouse(Memory<byte> data);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class MainSaveOffsets30 : MainSaveOffsets
|
|||
public const int GSaveMainFieldStart = GSaveLandStart + 0x22f3f0;
|
||||
|
||||
// Map size increased to accommodate the Hotel, by adding 2 columns of acres!
|
||||
public override int AcreColumnCount => 9; // from 7 to 9
|
||||
public override byte FieldItemAcreWidth => 9; // from 7 to 9
|
||||
// does this actually impact anything? We'll eventually find out if so; I hope it is just 2 columns of unused.
|
||||
|
||||
// Layer0: 54000 => 6C000
|
||||
|
|
|
|||
23
NHSE.Core/Structures/Map/AcreSelectionGrid.cs
Normal file
23
NHSE.Core/Structures/Map/AcreSelectionGrid.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
namespace NHSE.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Basic logic implementation for interacting with the manipulatable map grid.
|
||||
/// </summary>
|
||||
public abstract record AcreSelectionGrid(TileGridViewport TileInfo)
|
||||
{
|
||||
protected int GetAcreTileIndex(int acreIndex, int tileIndex)
|
||||
{
|
||||
var acre = AcreCoordinate.Acres[acreIndex];
|
||||
var x = (tileIndex % TileInfo.ViewWidth);
|
||||
var y = (tileIndex / TileInfo.ViewHeight);
|
||||
return TileInfo.GetTileIndex(acre.X, acre.Y, x, y);
|
||||
}
|
||||
|
||||
public int GetAcre(int x, int y) => (x / TileInfo.ViewWidth) + ((y / TileInfo.ViewHeight) * TileInfo.Columns);
|
||||
|
||||
public void GetViewAnchorCoordinates(int acre, out int x, out int y)
|
||||
{
|
||||
x = (acre % TileInfo.Columns) * TileInfo.ViewWidth;
|
||||
y = (acre / TileInfo.Columns) * TileInfo.ViewHeight;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,22 +3,19 @@
|
|||
|
||||
namespace NHSE.Core;
|
||||
|
||||
public class FieldItemLayer : ItemLayer
|
||||
public sealed record FieldItemLayer(Item[] Tiles, byte AcreWidth, byte AcreHeight)
|
||||
: ItemLayer(Tiles, GetViewport(AcreWidth, AcreHeight))
|
||||
{
|
||||
private static TileGridViewport GetViewport(byte width, byte height) => new(TilesPerAcreDim, TilesPerAcreDim, width, height);
|
||||
|
||||
public const int TilesPerAcreDim = 32;
|
||||
public const int FieldItemWidth = TilesPerAcreDim * AcreWidth;
|
||||
public const int FieldItemHeight = TilesPerAcreDim * AcreHeight;
|
||||
|
||||
public FieldItemLayer(Item[] tiles) : base(tiles, FieldItemWidth, FieldItemHeight, TilesPerAcreDim, TilesPerAcreDim)
|
||||
{
|
||||
}
|
||||
|
||||
public Item GetTile(int acreX, int acreY, int gridX, int gridY) => this[GetTileIndex(acreX, acreY, gridX, gridY)];
|
||||
public Item GetTile(int acreX, int acreY, int gridX, int gridY) => this[TileInfo.GetTileIndex(acreX, acreY, gridX, gridY)];
|
||||
public Item GetAcreTile(int acreIndex, int tileIndex) => this[GetAcreTileIndex(acreIndex, tileIndex)];
|
||||
|
||||
public byte[] DumpAcre(int acre)
|
||||
{
|
||||
int count = GridTileCount;
|
||||
int count = TileInfo.ViewCount;
|
||||
var result = new byte[Item.SIZE * count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
|
|
@ -31,7 +28,7 @@ public byte[] DumpAcre(int acre)
|
|||
|
||||
public void ImportAcre(int acre, ReadOnlySpan<byte> data)
|
||||
{
|
||||
int count = GridTileCount;
|
||||
int count = TileInfo.ViewCount;
|
||||
var tiles = Item.GetArray(data);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
|
|
@ -40,10 +37,10 @@ public void ImportAcre(int acre, ReadOnlySpan<byte> data)
|
|||
}
|
||||
}
|
||||
|
||||
public int ClearFieldPlanted(Func<FieldItemKind, bool> criteria) => ClearFieldPlanted(0, 0, MaxWidth, MaxHeight, criteria);
|
||||
public int RemoveAll(Func<Item, bool> criteria) => RemoveAll(0, 0, MaxWidth, MaxHeight, criteria);
|
||||
public int RemoveAll(HashSet<ushort> items) => RemoveAll(0, 0, MaxWidth, MaxHeight, z => items.Contains(z.DisplayItemId));
|
||||
public int RemoveAll(ushort item) => RemoveAll(0, 0, MaxWidth, MaxHeight, z => z.DisplayItemId == item);
|
||||
public int ClearFieldPlanted(Func<FieldItemKind, bool> criteria) => ClearFieldPlanted(0, 0, TileInfo.TotalWidth, TileInfo.TotalHeight, criteria);
|
||||
public int RemoveAll(Func<Item, bool> criteria) => RemoveAll(0, 0, TileInfo.TotalWidth, TileInfo.TotalHeight, criteria);
|
||||
public int RemoveAll(HashSet<ushort> items) => RemoveAll(0, 0, TileInfo.TotalWidth, TileInfo.TotalHeight, z => items.Contains(z.DisplayItemId));
|
||||
public int RemoveAll(ushort item) => RemoveAll(0, 0, TileInfo.TotalWidth, TileInfo.TotalHeight, z => z.DisplayItemId == item);
|
||||
|
||||
public int ClearFieldPlanted(int xmin, int ymin, int width, int height, Func<FieldItemKind, bool> criteria)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,23 +1,24 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace NHSE.Core;
|
||||
|
||||
public abstract class ItemLayer : MapGrid
|
||||
public abstract record ItemLayer : AcreSelectionGrid
|
||||
{
|
||||
public readonly Item[] Tiles;
|
||||
|
||||
protected ItemLayer(Item[] tiles, int w, int h) : this(tiles, w, h, w, h)
|
||||
protected ItemLayer(Item[] tiles, [ConstantExpected] byte w, [ConstantExpected] byte h) : this(tiles, new(w, h, w, h))
|
||||
{
|
||||
}
|
||||
|
||||
protected ItemLayer(Item[] tiles, int w, int h, int gw, int gh) : base(gw, gh, w, h)
|
||||
protected ItemLayer(Item[] tiles, TileGridViewport tileTileInfo) : base(tileTileInfo)
|
||||
{
|
||||
Tiles = tiles;
|
||||
Debug.Assert(MaxWidth * MaxHeight == tiles.Length);
|
||||
Debug.Assert(TileInfo.TotalWidth * TileInfo.TotalHeight == tiles.Length);
|
||||
}
|
||||
|
||||
public Item GetTile(in int x, in int y) => this[GetTileIndex(x, y)];
|
||||
public Item GetTile(in int x, in int y) => this[TileInfo.GetTileIndex(x, y)];
|
||||
|
||||
public Item this[int index]
|
||||
{
|
||||
|
|
@ -101,10 +102,10 @@ private void GetTileWidthHeight(Item tile, int x, int y, out int w, out int h)
|
|||
(w, h) = (h, w);
|
||||
|
||||
// Clamp to grid bounds
|
||||
if (x + w - 1 >= MaxWidth)
|
||||
w = MaxWidth - x;
|
||||
if (y + h - 1 >= MaxHeight)
|
||||
h = MaxHeight - y;
|
||||
if (x + w - 1 >= TileInfo.TotalWidth)
|
||||
w = TileInfo.TotalWidth - x;
|
||||
if (y + h - 1 >= TileInfo.TotalHeight)
|
||||
h = TileInfo.TotalHeight - y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -120,9 +121,9 @@ public PlacedItemPermission IsOccupied(Item tile, in int x, in int y)
|
|||
if ((tile.Rotation & 1) == 1)
|
||||
(w, h) = (h, w);
|
||||
|
||||
if (x + w - 1 >= MaxWidth)
|
||||
if (x + w - 1 >= TileInfo.TotalWidth)
|
||||
return PlacedItemPermission.OutOfBounds;
|
||||
if (y + h - 1 >= MaxHeight)
|
||||
if (y + h - 1 >= TileInfo.TotalHeight)
|
||||
return PlacedItemPermission.OutOfBounds;
|
||||
|
||||
for (byte ix = 0; ix < w; ix++)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
namespace NHSE.Core;
|
||||
|
||||
public class RoomItemLayer : ItemLayer
|
||||
public sealed record RoomItemLayer : ItemLayer
|
||||
{
|
||||
public const int SIZE = Width * Height * Item.SIZE;
|
||||
private const int Width = 20;
|
||||
private const int Height = 20;
|
||||
private const byte Width = 20;
|
||||
private const byte Height = 20;
|
||||
|
||||
public RoomItemLayer(ReadOnlySpan<byte> data) : this(Item.GetArray(data)) { }
|
||||
public RoomItemLayer(Item[] tiles) : base(tiles, Width, Height) { }
|
||||
|
|
|
|||
|
|
@ -7,20 +7,27 @@ namespace NHSE.Core;
|
|||
/// <summary>
|
||||
/// Grid of <see cref="TerrainTile"/>
|
||||
/// </summary>
|
||||
public class TerrainLayer : MapGrid
|
||||
public sealed record TerrainLayer : AcreSelectionGrid
|
||||
{
|
||||
public TerrainTile[] Tiles { get; init; }
|
||||
public byte[] BaseAcres { get; init; }
|
||||
public Memory<byte> BaseAcres { get; init; }
|
||||
|
||||
public TerrainLayer(TerrainTile[] tiles, byte[] acres) : base(16, 16, AcreWidth * 16, AcreHeight * 16)
|
||||
public const byte TilesPerAcreDim = 16;
|
||||
|
||||
private const byte CountAcreWidth = 7;
|
||||
private const byte CountAcreHeight = 6;
|
||||
|
||||
private static TileGridViewport Viewport => new(TilesPerAcreDim, TilesPerAcreDim, CountAcreWidth, CountAcreHeight);
|
||||
|
||||
public TerrainLayer(TerrainTile[] tiles, Memory<byte> acres) : base(Viewport)
|
||||
{
|
||||
BaseAcres = acres;
|
||||
Tiles = tiles;
|
||||
Debug.Assert(MaxTileCount == tiles.Length);
|
||||
Debug.Assert(TileInfo.TotalCount == tiles.Length);
|
||||
}
|
||||
|
||||
public TerrainTile GetTile(int x, int y) => this[GetTileIndex(x, y)];
|
||||
public TerrainTile GetTile(int acreX, int acreY, int gridX, int gridY) => this[GetTileIndex(acreX, acreY, gridX, gridY)];
|
||||
public TerrainTile GetTile(int x, int y) => this[TileInfo.GetTileIndex(x, y)];
|
||||
public TerrainTile GetTile(int acreX, int acreY, int gridX, int gridY) => this[TileInfo.GetTileIndex(acreX, acreY, gridX, gridY)];
|
||||
public TerrainTile GetAcreTile(int acreIndex, int tileIndex) => this[GetAcreTileIndex(acreIndex, tileIndex)];
|
||||
|
||||
public TerrainTile this[int index]
|
||||
|
|
@ -39,7 +46,7 @@ public byte[] DumpAll()
|
|||
|
||||
public byte[] DumpAcre(int acre)
|
||||
{
|
||||
int count = GridTileCount;
|
||||
int count = TileInfo.ViewCount;
|
||||
var result = new byte[TerrainTile.SIZE * count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
|
|
@ -60,7 +67,7 @@ public void ImportAll(ReadOnlySpan<byte> data)
|
|||
|
||||
public void ImportAcre(int acre, ReadOnlySpan<byte> data)
|
||||
{
|
||||
int count = GridTileCount;
|
||||
int count = TileInfo.ViewCount;
|
||||
var tiles = TerrainTile.GetArray(data);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
|
|
@ -74,10 +81,10 @@ public void SetAll(TerrainTile tile, in bool interiorOnly)
|
|||
if (interiorOnly)
|
||||
{
|
||||
// skip outermost ring of tiles
|
||||
int xmin = GridWidth;
|
||||
int ymin = GridHeight;
|
||||
int xmax = MaxWidth - GridWidth;
|
||||
int ymax = MaxHeight - GridHeight;
|
||||
int xmin = TileInfo.ViewWidth;
|
||||
int ymin = TileInfo.ViewHeight;
|
||||
int xmax = TileInfo.TotalWidth - TileInfo.ViewWidth;
|
||||
int ymax = TileInfo.TotalHeight - TileInfo.ViewHeight;
|
||||
for (int x = xmin; x < xmax; x++)
|
||||
{
|
||||
for (int y = ymin; y < ymax; y++)
|
||||
|
|
@ -96,10 +103,10 @@ public void SetAllRoad(TerrainTile tile, in bool interiorOnly)
|
|||
if (interiorOnly)
|
||||
{
|
||||
// skip outermost ring of tiles
|
||||
int xmin = GridWidth;
|
||||
int ymin = GridHeight;
|
||||
int xmax = MaxWidth - GridWidth;
|
||||
int ymax = MaxHeight - GridHeight;
|
||||
int xmin = TileInfo.ViewWidth;
|
||||
int ymin = TileInfo.ViewHeight;
|
||||
int xmax = TileInfo.TotalWidth - TileInfo.ViewWidth;
|
||||
int ymax = TileInfo.TotalHeight - TileInfo.ViewHeight;
|
||||
for (int x = xmin; x < xmax; x++)
|
||||
{
|
||||
for (int y = ymin; y < ymax; y++)
|
||||
|
|
@ -117,7 +124,7 @@ public void GetBuildingCoordinate(ushort bx, ushort by, int scale, out int x, ou
|
|||
{
|
||||
// Although there is terrain in the Top Row and Left Column, no buildings can be placed there.
|
||||
// Adjust the building coordinates down-right by an acre.
|
||||
int buildingShift = GridWidth;
|
||||
int buildingShift = TileInfo.ViewWidth;
|
||||
x = (int)(((bx / 2f) - buildingShift) * scale);
|
||||
y = (int)(((by / 2f) - buildingShift) * scale);
|
||||
}
|
||||
|
|
@ -131,10 +138,10 @@ public void GetBuildingRelativeCoordinates(int topX, int topY, int acreScale, us
|
|||
|
||||
public bool IsWithinGrid(int acreScale, int relX, int relY)
|
||||
{
|
||||
if ((uint)relX >= GridWidth * acreScale)
|
||||
if ((uint)relX >= TileInfo.ViewWidth * acreScale)
|
||||
return false;
|
||||
|
||||
if ((uint)relY >= GridHeight * acreScale)
|
||||
if ((uint)relY >= TileInfo.ViewHeight * acreScale)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
@ -159,8 +166,8 @@ private ushort GetTileAcre(int x, int y)
|
|||
var acreX = 1 + (x / 16);
|
||||
var acreY = 1 + (y / 16);
|
||||
|
||||
var acreIndex = ((AcreWidth + 2) * acreY) + acreX;
|
||||
var acreIndex = ((CountAcreWidth + 2) * acreY) + acreX;
|
||||
var ofs = acreIndex * 2;
|
||||
return ReadUInt16LittleEndian(BaseAcres.AsSpan(ofs));
|
||||
return ReadUInt16LittleEndian(BaseAcres.Span[ofs..]);
|
||||
}
|
||||
}
|
||||
|
|
@ -23,11 +23,22 @@ public class FieldItemManager
|
|||
/// </summary>
|
||||
public readonly MainSave SAV;
|
||||
|
||||
public readonly int FieldAcreWidth;
|
||||
public readonly int FieldAcreHeight;
|
||||
public readonly int FieldItemWidth;
|
||||
public readonly int FieldItemHeight;
|
||||
|
||||
public FieldItemManager(MainSave sav)
|
||||
{
|
||||
Layer1 = new FieldItemLayer(sav.GetFieldItemLayer1());
|
||||
Layer2 = new FieldItemLayer(sav.GetFieldItemLayer2());
|
||||
var (aWidth, aHeight) = (sav.FieldItemAcreWidth, sav.FieldItemAcreHeight);
|
||||
Layer1 = new FieldItemLayer(sav.GetFieldItemLayer1(), aWidth, aHeight);
|
||||
Layer2 = new FieldItemLayer(sav.GetFieldItemLayer2(), aWidth, aHeight);
|
||||
SAV = sav;
|
||||
|
||||
FieldAcreWidth = aWidth;
|
||||
FieldAcreHeight = aHeight;
|
||||
FieldItemWidth = Layer1.TileInfo.TotalWidth;
|
||||
FieldItemHeight = Layer1.TileInfo.TotalHeight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -46,12 +57,12 @@ public void Save()
|
|||
/// Lists out all coordinates of tiles present in <see cref="Layer2"/> that don't have anything underneath in <see cref="Layer1"/> to support them.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<string> GetUnsupportedTiles()
|
||||
public List<string> GetUnsupportedTiles(int totalWidth, int totalHeight)
|
||||
{
|
||||
var result = new List<string>();
|
||||
for (int x = 0; x < FieldItemLayer.FieldItemWidth; x++)
|
||||
for (int x = 0; x < totalWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < FieldItemLayer.FieldItemHeight; y++)
|
||||
for (int y = 0; y < totalHeight; y++)
|
||||
{
|
||||
var tile = Layer2.GetTile(x, y);
|
||||
if (tile.IsNone)
|
||||
|
|
@ -73,9 +84,9 @@ private void SetTileActiveFlags(ItemLayer tiles, int ofs)
|
|||
|
||||
// Although the Tiles are arranged y-column (y-x) based, the 'isActive' flags are arranged x-row (x-y) based.
|
||||
// We can turn the isActive flag off if the item is not a root or the item cannot be animated.
|
||||
for (int x = 0; x < FieldItemLayer.FieldItemWidth; x++)
|
||||
for (int x = 0; x < FieldItemWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < FieldItemLayer.FieldItemHeight; y++)
|
||||
for (int y = 0; y < FieldItemHeight; y++)
|
||||
{
|
||||
var tile = tiles.GetTile(x, y);
|
||||
var isActive = GetIsActive(ofs, x, y);
|
||||
|
|
@ -92,8 +103,8 @@ private void SetTileActiveFlags(ItemLayer tiles, int ofs)
|
|||
public bool GetIsActive(bool baseLayer, int x, int y) => GetIsActive(baseLayer ? SAV.FieldItemFlag1 : SAV.FieldItemFlag2, x, y);
|
||||
public void SetIsActive(bool baseLayer, int x, int y, bool value) => SetIsActive(baseLayer ? SAV.FieldItemFlag1 : SAV.FieldItemFlag2, x, y, value);
|
||||
|
||||
private bool GetIsActive(int ofs, int x, int y) => FlagUtil.GetFlag(SAV.Data, ofs, (y * FieldItemLayer.FieldItemWidth) + x);
|
||||
private void SetIsActive(int ofs, int x, int y, bool value) => FlagUtil.SetFlag(SAV.Data, ofs, (y * FieldItemLayer.FieldItemWidth) + x, value);
|
||||
private bool GetIsActive(int ofs, int x, int y) => FlagUtil.GetFlag(SAV.Data, ofs, (y * FieldItemWidth) + x);
|
||||
private void SetIsActive(int ofs, int x, int y, bool value) => FlagUtil.SetFlag(SAV.Data, ofs, (y * FieldItemWidth) + x, value);
|
||||
|
||||
public bool IsOccupied(int x, int y) => !Layer1.GetTile(x, y).IsNone || !Layer2.GetTile(x, y).IsNone;
|
||||
}
|
||||
|
|
@ -35,9 +35,9 @@ public List<string> GetUnsupportedTiles()
|
|||
var lBase = Layers[(int)RoomLayerSurface.Floor];
|
||||
var lSupport = Layers[(int)RoomLayerSurface.FloorSupported];
|
||||
var result = new List<string>();
|
||||
for (int x = 0; x < lBase.MaxWidth; x++)
|
||||
for (int x = 0; x < lBase.TileInfo.TotalWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < lBase.MaxHeight; y++)
|
||||
for (int y = 0; y < lBase.TileInfo.TotalHeight; y++)
|
||||
{
|
||||
var tile = lSupport.GetTile(x, y);
|
||||
if (tile.IsNone)
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
namespace NHSE.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Basic logic implementation for interacting with the manipulatable map grid.
|
||||
/// </summary>
|
||||
public abstract class MapGrid : TileGrid
|
||||
{
|
||||
public static readonly AcreCoordinate[] Acres = AcreCoordinate.GetGrid(AcreWidth, AcreHeight);
|
||||
|
||||
public const int AcreWidth = 7;
|
||||
public const int AcreHeight = 6;
|
||||
public const int AcreCount = AcreWidth * AcreHeight;
|
||||
|
||||
public const int MapTileCount16x16 = 16 * 16 * AcreCount;
|
||||
public const int MapTileCount32x32 = 32 * 32 * AcreCount;
|
||||
|
||||
protected MapGrid(int gw, int gh, int mw, int mh) : base(gw, gh, mw, mh) { }
|
||||
|
||||
protected int GetTileIndex(int acreX, int acreY, int gridX, int gridY)
|
||||
{
|
||||
var x = (acreX * GridWidth) + gridX;
|
||||
var y = (acreY * GridHeight) + gridY;
|
||||
return GetTileIndex(x, y);
|
||||
}
|
||||
|
||||
protected int GetAcreTileIndex(int acreIndex, int tileIndex)
|
||||
{
|
||||
var acre = Acres[acreIndex];
|
||||
var x = (tileIndex % GridWidth);
|
||||
var y = (tileIndex / GridHeight);
|
||||
return GetTileIndex(acre.X, acre.Y, x, y);
|
||||
}
|
||||
|
||||
public int GetAcre(int x, int y) => (x / GridWidth) + ((y / GridHeight) * AcreWidth);
|
||||
|
||||
public void GetViewAnchorCoordinates(int acre, out int x, out int y)
|
||||
{
|
||||
x = (acre % AcreWidth) * GridWidth;
|
||||
y = (acre / AcreWidth) * GridHeight;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +1,52 @@
|
|||
namespace NHSE.Core;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace NHSE.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Navigation metadata for acre coordinates.
|
||||
/// </summary>
|
||||
public class AcreCoordinate
|
||||
[DebuggerDisplay("{Name} ({X}, {Y})")]
|
||||
public readonly record struct AcreCoordinate(char XChar, char YChar, byte X, byte Y)
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly int X, Y;
|
||||
public const int CountTerrainAcreWidth = 7;
|
||||
public const int CountTerrainAcreHeight = 6;
|
||||
public const int CountAcreExteriorWidth = 9;
|
||||
public const int CountAcreExteriorHeight = 8;
|
||||
|
||||
public AcreCoordinate(int x, int y) : this((char)('0' + x), (char)('A' + y), x, y) { }
|
||||
/// <summary>
|
||||
/// Terrain Acre grid coordinates.
|
||||
/// </summary>
|
||||
public static readonly AcreCoordinate[] Acres = GetGrid(CountTerrainAcreWidth, CountTerrainAcreHeight);
|
||||
|
||||
public AcreCoordinate(char xName, char yName, int x, int y)
|
||||
{
|
||||
Name = $"{yName}{xName}";
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
/// <summary>
|
||||
/// Entire grid including exterior acre coordinates (bordered by acres of deep sea->shoreline=>terrain).
|
||||
/// </summary>
|
||||
public static readonly AcreCoordinate[] Exterior = GetGridWithExterior(CountAcreExteriorWidth, CountAcreExteriorHeight);
|
||||
|
||||
public static AcreCoordinate[] GetGrid(int width, int height)
|
||||
public string Name => $"{YChar}{XChar}";
|
||||
|
||||
private AcreCoordinate(byte x, byte y) : this((char)('0' + x), (char)('A' + y), x, y) { }
|
||||
|
||||
private static AcreCoordinate[] GetGrid([ConstantExpected] byte width, [ConstantExpected] byte height)
|
||||
{
|
||||
var result = new AcreCoordinate[width * height];
|
||||
int i = 0;
|
||||
for (int y = 0; y < height; y++)
|
||||
for (byte y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
for (byte x = 0; x < width; x++)
|
||||
result[i++] = new AcreCoordinate(x, y);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static AcreCoordinate[] GetGridWithExterior(int width, int height)
|
||||
private static AcreCoordinate[] GetGridWithExterior([ConstantExpected] int width, [ConstantExpected] int height)
|
||||
{
|
||||
var result = new AcreCoordinate[width * height];
|
||||
int i = 0;
|
||||
for (int y = 0; y < height; y++)
|
||||
for (byte y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
for (byte x = 0; x < width; x++)
|
||||
{
|
||||
var xn = (x == 0) ? '<' : x == width - 1 ? '>' : (char)('0' + x - 1);
|
||||
var yn = (y == 0) ? '^' : y == height - 1 ? 'V' : (char)('A' + y - 1);
|
||||
|
|
|
|||
|
|
@ -1,76 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace NHSE.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Basic logic implementation for interacting with the manipulatable tile grid.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Certain <see cref="TileGrid"/> use this as a viewport on a subsection of the entire tile-set.
|
||||
/// </remarks>
|
||||
public abstract class TileGrid
|
||||
{
|
||||
/// <summary> Amount of viewable tiles wide </summary>
|
||||
public readonly int GridWidth;
|
||||
|
||||
/// <summary> Amount of viewable tiles high </summary>
|
||||
public readonly int GridHeight;
|
||||
|
||||
/// <summary> Max amount of tiles wide the entire grid is </summary>
|
||||
public readonly int MaxWidth;
|
||||
|
||||
/// <summary> Max amount of tiles high the entire grid is </summary>
|
||||
public readonly int MaxHeight;
|
||||
|
||||
protected TileGrid(in int gw, in int gh, in int mw, in int mh)
|
||||
{
|
||||
GridWidth = gw;
|
||||
GridHeight = gh;
|
||||
MaxWidth = mw;
|
||||
MaxHeight = mh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Amount of tiles present in the grid.
|
||||
/// </summary>
|
||||
public int GridTileCount => GridWidth * GridHeight;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of ALL tiles present in the entire grid (including the grid).
|
||||
/// </summary>
|
||||
public int MaxTileCount => MaxWidth * MaxHeight;
|
||||
|
||||
protected int GetTileIndex(in int x, in int y) => (MaxHeight * x) + y;
|
||||
|
||||
public void ClampCoordinatesInsideGrid(ref int x, ref int y) => ClampCoordinatesTo(ref x, ref y, MaxWidth - 1, MaxHeight - 1);
|
||||
|
||||
public void ClampCoordinatesTopLeft(ref int x, ref int y)
|
||||
{
|
||||
int maxX = MaxWidth - GridWidth;
|
||||
int maxY = MaxHeight - GridHeight;
|
||||
ClampCoordinatesTo(ref x, ref y, maxX, maxY);
|
||||
}
|
||||
|
||||
private static void ClampCoordinatesTo(ref int x, ref int y, int maxX, int maxY)
|
||||
{
|
||||
x = Math.Max(0, Math.Min(x, maxX));
|
||||
y = Math.Max(0, Math.Min(y, maxY));
|
||||
}
|
||||
|
||||
public void GetViewAnchorCoordinates(ref int x, ref int y, in bool centerReticle)
|
||||
{
|
||||
// If we aren't snapping the reticle to the nearest acre
|
||||
// we want to put the middle of the reticle rectangle where the cursor is.
|
||||
// Adjust the view coordinate
|
||||
if (!centerReticle)
|
||||
{
|
||||
// Reticle size is GridWidth, center = /2
|
||||
x -= GridWidth / 2;
|
||||
y -= GridWidth / 2;
|
||||
}
|
||||
|
||||
// Clamp to viewport dimensions, and center to nearest acre if desired.
|
||||
// Clamp to boundaries so that we always have 16x16 to view.
|
||||
ClampCoordinatesTopLeft(ref x, ref y);
|
||||
}
|
||||
}
|
||||
82
NHSE.Core/Structures/Map/TileGridViewport.cs
Normal file
82
NHSE.Core/Structures/Map/TileGridViewport.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace NHSE.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Basic configuration of a narrow view for interacting with the larger manipulatable tile grid.
|
||||
/// </summary>
|
||||
/// <param name="ViewWidth">Viewable amount of viewable tiles wide</param>
|
||||
/// <param name="ViewHeight">Viewable amount of viewable tiles high</param>
|
||||
/// <param name="Columns">Columns of view available</param>
|
||||
/// <param name="Rows">Rows of view available</param>
|
||||
public readonly record struct TileGridViewport([ConstantExpected] byte ViewWidth, [ConstantExpected] byte ViewHeight, byte Columns, byte Rows)
|
||||
{
|
||||
/// <summary>
|
||||
/// Total width of the entire grid (including the view).
|
||||
/// </summary>
|
||||
public int TotalWidth => Columns * ViewWidth;
|
||||
|
||||
/// <summary>
|
||||
/// Total height of the entire grid (including the view).
|
||||
/// </summary>
|
||||
public int TotalHeight => Rows * ViewHeight;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of tiles present in the grid.
|
||||
/// </summary>
|
||||
public int ViewCount => ViewWidth * ViewHeight;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of ALL tiles present in the entire grid (including the grid).
|
||||
/// </summary>
|
||||
public int TotalCount => TotalWidth * TotalHeight;
|
||||
|
||||
public int GetTileIndex(int acreX, int acreY, int gridX, int gridY)
|
||||
{
|
||||
var x = (acreX * ViewWidth) + gridX;
|
||||
var y = (acreY * ViewHeight) + gridY;
|
||||
return GetTileIndex(x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the absolute index of the absolute tile in the grid based on the x/y coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x">Absolute x coordinate of the tile in the grid</param>
|
||||
/// <param name="y">Absolute y coordinate of the tile in the grid</param>
|
||||
/// <returns>Absolute index of the tile in the grid</returns>
|
||||
public int GetTileIndex(in int x, in int y) => (TotalHeight * x) + y;
|
||||
|
||||
public void ClampInside(ref int x, ref int y) => ClampCoordinatesTo(ref x, ref y, TotalWidth - 1, TotalHeight - 1);
|
||||
|
||||
private static void ClampCoordinatesTo(ref int x, ref int y, int maxX, int maxY)
|
||||
{
|
||||
x = Math.Clamp(x, 0, maxX);
|
||||
y = Math.Clamp(y, 0, maxY);
|
||||
}
|
||||
|
||||
public void GetViewAnchorCoordinates(ref int x, ref int y, in bool centerReticle)
|
||||
{
|
||||
// If we aren't snapping the reticle to the nearest acre
|
||||
// we want to put the middle of the reticle rectangle where the cursor is.
|
||||
// Adjust the view coordinate
|
||||
if (!centerReticle)
|
||||
{
|
||||
// Reticle size is GridWidth, center = /2
|
||||
x -= ViewWidth / 2;
|
||||
y -= ViewWidth / 2;
|
||||
}
|
||||
|
||||
// Clamp to viewport dimensions, and center to nearest acre if desired.
|
||||
// Clamp to boundaries so that we always have a full grid to view.
|
||||
SetTopLeftNearest(ref x, ref y);
|
||||
}
|
||||
|
||||
private void SetTopLeftNearest(ref int x, ref int y)
|
||||
{
|
||||
int maxX = TotalWidth - ViewWidth;
|
||||
int maxY = TotalHeight - ViewHeight;
|
||||
ClampCoordinatesTo(ref x, ref y, maxX, maxY);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,17 +4,12 @@
|
|||
|
||||
namespace NHSE.Core;
|
||||
|
||||
public class MapManager : MapTerrainStructure
|
||||
public class MapManager(MainSave sav) : MapTerrainStructure(sav)
|
||||
{
|
||||
public readonly FieldItemManager Items;
|
||||
public readonly FieldItemManager Items = new(sav);
|
||||
|
||||
public int MapLayer { get; set; } // 0 or 1
|
||||
|
||||
public MapManager(MainSave sav) : base(sav)
|
||||
{
|
||||
Items = new FieldItemManager(sav);
|
||||
}
|
||||
|
||||
public FieldItemLayer CurrentLayer => MapLayer == 0 ? Items.Layer1 : Items.Layer2;
|
||||
|
||||
public static void ClearDesignTiles(MainSave sav)
|
||||
|
|
@ -41,19 +36,11 @@ public static void ImportDesignTiles(MainSave sav, ReadOnlySpan<byte> result)
|
|||
}
|
||||
}
|
||||
|
||||
public class MapTerrainStructure
|
||||
public class MapTerrainStructure(MainSave sav)
|
||||
{
|
||||
public readonly TerrainLayer Terrain;
|
||||
public readonly IReadOnlyList<Building> Buildings;
|
||||
public readonly TerrainLayer Terrain = new(sav.GetTerrainTiles(), sav.GetAcreBytes());
|
||||
public readonly IReadOnlyList<Building> Buildings = sav.Buildings;
|
||||
|
||||
public uint PlazaX { get; set; }
|
||||
public uint PlazaY { get; set; }
|
||||
|
||||
public MapTerrainStructure(MainSave sav)
|
||||
{
|
||||
Terrain = new TerrainLayer(sav.GetTerrainTiles(), sav.GetAcreBytes());
|
||||
Buildings = sav.Buildings;
|
||||
PlazaX = sav.EventPlazaLeftUpX;
|
||||
PlazaY = sav.EventPlazaLeftUpZ;
|
||||
}
|
||||
public uint PlazaX { get; set; } = sav.EventPlazaLeftUpX;
|
||||
public uint PlazaY { get; set; } = sav.EventPlazaLeftUpZ;
|
||||
}
|
||||
|
|
@ -22,9 +22,9 @@ protected MapView(MapManager m, int scale = 16)
|
|||
}
|
||||
|
||||
public bool CanUp => Y != 0;
|
||||
public bool CanDown => Y < Map.CurrentLayer.MaxHeight - Map.CurrentLayer.GridHeight;
|
||||
public bool CanDown => Y < Map.CurrentLayer.TileInfo.TotalHeight - Map.CurrentLayer.TileInfo.ViewHeight;
|
||||
public bool CanLeft => X != 0;
|
||||
public bool CanRight => X < Map.CurrentLayer.MaxWidth - Map.CurrentLayer.GridWidth;
|
||||
public bool CanRight => X < Map.CurrentLayer.TileInfo.TotalWidth - Map.CurrentLayer.TileInfo.ViewWidth;
|
||||
|
||||
public bool ArrowUp()
|
||||
{
|
||||
|
|
@ -44,7 +44,7 @@ public bool ArrowLeft()
|
|||
|
||||
public bool ArrowRight()
|
||||
{
|
||||
if (X >= Map.CurrentLayer.MaxWidth - 2)
|
||||
if (X >= Map.CurrentLayer.TileInfo.TotalWidth - 2)
|
||||
return false;
|
||||
X += ViewInterval;
|
||||
return true;
|
||||
|
|
@ -52,7 +52,7 @@ public bool ArrowRight()
|
|||
|
||||
public bool ArrowDown()
|
||||
{
|
||||
if (Y >= Map.CurrentLayer.MaxHeight - ViewInterval)
|
||||
if (Y >= Map.CurrentLayer.TileInfo.TotalHeight - ViewInterval)
|
||||
return false;
|
||||
Y += ViewInterval;
|
||||
return true;
|
||||
|
|
@ -61,8 +61,8 @@ public bool ArrowDown()
|
|||
public bool SetViewTo(in int x, in int y)
|
||||
{
|
||||
var info = Map.CurrentLayer;
|
||||
var newX = Math.Max(0, Math.Min(x, info.MaxWidth - info.GridWidth));
|
||||
var newY = Math.Max(0, Math.Min(y, info.MaxHeight - info.GridHeight));
|
||||
var newX = Math.Max(0, Math.Min(x, info.TileInfo.TotalWidth - info.TileInfo.ViewWidth));
|
||||
var newY = Math.Max(0, Math.Min(y, info.TileInfo.TotalHeight - info.TileInfo.ViewHeight));
|
||||
bool diff = X != newX || Y != newY;
|
||||
X = newX;
|
||||
Y = newY;
|
||||
|
|
@ -80,16 +80,16 @@ public int ModifyFieldItems(Func<int, int, int, int, int> action, in bool wholeM
|
|||
{
|
||||
var layer = Map.CurrentLayer;
|
||||
return wholeMap
|
||||
? action(0, 0, layer.MaxWidth, layer.MaxHeight)
|
||||
: action(X, Y, layer.GridWidth, layer.GridHeight);
|
||||
? action(0, 0, layer.TileInfo.TotalWidth, layer.TileInfo.TotalHeight)
|
||||
: action(X, Y, layer.TileInfo.ViewWidth, layer.TileInfo.ViewHeight);
|
||||
}
|
||||
|
||||
public int ReplaceFieldItems(Item oldItem, Item newItem, in bool wholeMap)
|
||||
{
|
||||
var layer = Map.CurrentLayer;
|
||||
return wholeMap
|
||||
? layer.ReplaceAll(oldItem, newItem, 0, 0, layer.MaxWidth, layer.MaxHeight)
|
||||
: layer.ReplaceAll(oldItem, newItem, X, Y, layer.GridWidth, layer.GridHeight);
|
||||
? layer.ReplaceAll(oldItem, newItem, 0, 0, layer.TileInfo.TotalWidth, layer.TileInfo.TotalHeight)
|
||||
: layer.ReplaceAll(oldItem, newItem, X, Y, layer.TileInfo.ViewWidth, layer.TileInfo.ViewHeight);
|
||||
}
|
||||
|
||||
public void GetCursorCoordinates(in int mX, in int mY, out int x, out int y)
|
||||
|
|
@ -102,6 +102,6 @@ public void GetViewAnchorCoordinates(int mX, int mY, out int x, out int y, bool
|
|||
{
|
||||
GetCursorCoordinates(mX, mY, out x, out y);
|
||||
var layer = Map.Items.Layer1;
|
||||
layer.GetViewAnchorCoordinates(ref x, ref y, centerReticle);
|
||||
layer.TileInfo.GetViewAnchorCoordinates(ref x, ref y, centerReticle);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ public static class ItemLayerSprite
|
|||
public static Bitmap GetBitmapItemLayer(ItemLayer layer)
|
||||
{
|
||||
var items = layer.Tiles;
|
||||
var height = layer.MaxHeight;
|
||||
var height = layer.TileInfo.TotalHeight;
|
||||
var width = items.Length / height;
|
||||
|
||||
var bmpData = new int[width * height];
|
||||
|
|
@ -34,7 +34,7 @@ private static void LoadBitmapLayer(ReadOnlySpan<Item> items, Span<int> bmpData,
|
|||
|
||||
private static void LoadPixelsFromLayer(ItemLayer layer, int x0, int y0, int width, Span<int> bmpData)
|
||||
{
|
||||
var stride = layer.GridWidth;
|
||||
var stride = layer.TileInfo.ViewWidth;
|
||||
|
||||
for (int y = 0; y < stride; y++)
|
||||
{
|
||||
|
|
@ -52,8 +52,8 @@ private static void LoadPixelsFromLayer(ItemLayer layer, int x0, int y0, int wid
|
|||
// non-allocation image generator
|
||||
public static Bitmap GetBitmapItemLayerViewGrid(ItemLayer layer, int x0, int y0, int scale, Span<int> acre1, int[] acreScale, Bitmap dest, int transparency = -1, int gridlineColor = 0)
|
||||
{
|
||||
var w = layer.GridWidth;
|
||||
var h = layer.GridHeight;
|
||||
int w = layer.TileInfo.ViewWidth;
|
||||
int h = layer.TileInfo.ViewHeight;
|
||||
LoadPixelsFromLayer(layer, x0, y0, w, acre1);
|
||||
w *= scale;
|
||||
h *= scale;
|
||||
|
|
@ -75,9 +75,9 @@ public static Bitmap GetBitmapItemLayerViewGrid(ItemLayer layer, int x0, int y0,
|
|||
|
||||
private static void DrawDirectionals(Span<int> data, ItemLayer layer, int w, int x0, int y0, int scale)
|
||||
{
|
||||
for (int x = x0; x < x0 + layer.GridWidth; x++)
|
||||
for (int x = x0; x < x0 + layer.TileInfo.ViewWidth; x++)
|
||||
{
|
||||
for (int y = y0; y < y0 + layer.GridHeight; y++)
|
||||
for (int y = y0; y < y0 + layer.TileInfo.ViewHeight; y++)
|
||||
{
|
||||
var tile = layer.GetTile(x, y);
|
||||
if (tile.IsNone)
|
||||
|
|
@ -234,20 +234,20 @@ public static void DrawGrid(Span<int> data, int w, int h, int scale, int gridlin
|
|||
|
||||
public static Bitmap GetBitmapItemLayer(ItemLayer layer, int x, int y, int[] data, Bitmap dest, int transparency = -1)
|
||||
{
|
||||
LoadBitmapLayer(layer.Tiles, data, layer.MaxWidth, layer.MaxHeight);
|
||||
LoadBitmapLayer(layer.Tiles, data, layer.TileInfo.TotalWidth, layer.TileInfo.TotalHeight);
|
||||
if (transparency >>> 24 != 0xFF)
|
||||
ImageUtil.ClampAllTransparencyTo(data, transparency);
|
||||
ImageUtil.SetBitmapData(dest, data);
|
||||
return DrawViewReticle(dest, layer, x, y);
|
||||
return DrawViewReticle(dest, layer.TileInfo, x, y);
|
||||
}
|
||||
|
||||
private static Bitmap DrawViewReticle(Bitmap map, TileGrid g, int x, int y, int scale = 1)
|
||||
private static Bitmap DrawViewReticle(Bitmap map, TileGridViewport g, int x, int y, int scale = 1)
|
||||
{
|
||||
using var gfx = Graphics.FromImage(map);
|
||||
using var pen = new Pen(Color.Red);
|
||||
|
||||
int w = g.GridWidth * scale;
|
||||
int h = g.GridHeight * scale;
|
||||
int w = g.ViewWidth * scale;
|
||||
int h = g.ViewHeight * scale;
|
||||
gfx.DrawRectangle(pen, x * scale, y * scale, w, h);
|
||||
return map;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,13 @@ public sealed class MapViewer : MapView, IDisposable
|
|||
public MapViewer(MapManager m, int scale) : base(m, scale)
|
||||
{
|
||||
var l1 = m.Items.Layer1;
|
||||
PixelsItemAcre1 = new int[l1.GridWidth * l1.GridHeight];
|
||||
var info = l1.TileInfo;
|
||||
PixelsItemAcre1 = new int[info.ViewWidth * info.ViewHeight];
|
||||
PixelsItemAcreX = new int[PixelsItemAcre1.Length * AcreScale * AcreScale];
|
||||
ScaleAcre = new Bitmap(l1.GridWidth * AcreScale, l1.GridHeight * AcreScale);
|
||||
ScaleAcre = new Bitmap(info.ViewWidth * AcreScale, info.ViewHeight * AcreScale);
|
||||
|
||||
PixelsItemMap = new int[l1.MaxWidth * l1.MaxHeight * MapScale * MapScale];
|
||||
MapReticle = new Bitmap(l1.MaxWidth * MapScale, l1.MaxHeight * MapScale);
|
||||
PixelsItemMap = new int[info.TotalWidth * info.TotalHeight * MapScale * MapScale];
|
||||
MapReticle = new Bitmap(info.TotalWidth * MapScale, info.TotalHeight * MapScale);
|
||||
|
||||
PixelsBackgroundAcre1 = new int[(int)Math.Pow(16, 4)];
|
||||
PixelsBackgroundAcreX = new int[PixelsItemAcreX.Length];
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ public static class TerrainSprite
|
|||
public static void CreateMap(TerrainLayer mgr, Span<int> pixels)
|
||||
{
|
||||
int i = 0;
|
||||
for (int y = 0; y < mgr.MaxHeight; y++)
|
||||
for (int y = 0; y < mgr.TileInfo.TotalHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < mgr.MaxWidth; x++, i++)
|
||||
for (int x = 0; x < mgr.TileInfo.TotalWidth; x++, i++)
|
||||
{
|
||||
pixels[i] = mgr.GetTileColor(x, y, x, y);
|
||||
}
|
||||
|
|
@ -38,20 +38,20 @@ public static Bitmap CreateMap(TerrainLayer mgr, Span<int> scale1, int[] scaleX,
|
|||
if (acreIndex < 0)
|
||||
return map;
|
||||
|
||||
var acre = MapGrid.Acres[acreIndex];
|
||||
var x = acre.X * mgr.GridWidth;
|
||||
var y = acre.Y * mgr.GridHeight;
|
||||
var acre = AcreCoordinate.Acres[acreIndex];
|
||||
var x = acre.X * mgr.TileInfo.ViewWidth;
|
||||
var y = acre.Y * mgr.TileInfo.ViewHeight;
|
||||
|
||||
return DrawReticle(map, mgr, x, y, scale);
|
||||
return DrawReticle(map, mgr.TileInfo, x, y, scale);
|
||||
}
|
||||
|
||||
private static Bitmap DrawReticle(Bitmap map, TileGrid mgr, int x, int y, int scale)
|
||||
private static Bitmap DrawReticle(Bitmap map, TileGridViewport mgr, int x, int y, int scale)
|
||||
{
|
||||
using var gfx = Graphics.FromImage(map);
|
||||
using var pen = new Pen(Color.Red);
|
||||
|
||||
int w = mgr.GridWidth * scale;
|
||||
int h = mgr.GridHeight * scale;
|
||||
int w = mgr.ViewWidth * scale;
|
||||
int h = mgr.ViewHeight * scale;
|
||||
gfx.DrawRectangle(pen, x * scale, y * scale, w, h);
|
||||
return map;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ private static int SpawnItems(ItemLayer layer, IReadOnlyList<Item> items, int x,
|
|||
var permission = layer.IsOccupied(item, x, y);
|
||||
switch (permission)
|
||||
{
|
||||
case PlacedItemPermission.OutOfBounds when y >= layer.MaxHeight:
|
||||
case PlacedItemPermission.OutOfBounds when y >= layer.TileInfo.TotalHeight:
|
||||
return ctr;
|
||||
case PlacedItemPermission.OutOfBounds:
|
||||
case PlacedItemPermission.Collision when noOverwrite:
|
||||
|
|
|
|||
|
|
@ -57,11 +57,9 @@ public FieldItemEditor(MainSave sav)
|
|||
|
||||
private void LoadComboBoxes()
|
||||
{
|
||||
foreach (var acre in MapGrid.Acres)
|
||||
foreach (var acre in AcreCoordinate.Acres)
|
||||
CB_Acre.Items.Add(acre.Name);
|
||||
|
||||
var exterior = AcreCoordinate.GetGridWithExterior(9, 8);
|
||||
foreach (var acre in exterior)
|
||||
foreach (var acre in AcreCoordinate.Exterior)
|
||||
CB_MapAcre.Items.Add(acre.Name);
|
||||
|
||||
CB_MapAcreSelect.DisplayMember = nameof(ComboItem.Text);
|
||||
|
|
@ -349,8 +347,8 @@ private void ViewTile(Item tile, int x, int y)
|
|||
if (CHK_RedirectExtensionLoad.Checked && tile.IsExtension)
|
||||
{
|
||||
var l = Map.CurrentLayer;
|
||||
var rx = Math.Max(0, Math.Min(l.MaxWidth - 1, x - tile.ExtensionX));
|
||||
var ry = Math.Max(0, Math.Min(l.MaxHeight - 1, y - tile.ExtensionY));
|
||||
var rx = Math.Max(0, Math.Min(l.TileInfo.TotalWidth - 1, x - tile.ExtensionX));
|
||||
var ry = Math.Max(0, Math.Min(l.TileInfo.TotalHeight - 1, y - tile.ExtensionY));
|
||||
var redir = l.GetTile(rx, ry);
|
||||
if (redir.IsRoot && redir.ItemId == tile.ExtensionItemId)
|
||||
tile = redir;
|
||||
|
|
@ -511,7 +509,8 @@ private void DeleteTile(TerrainTile tile)
|
|||
|
||||
private void B_Save_Click(object sender, EventArgs e)
|
||||
{
|
||||
var unsupported = Map.Items.GetUnsupportedTiles();
|
||||
var view = View.Map.Items.Layer1.TileInfo;
|
||||
var unsupported = Map.Items.GetUnsupportedTiles(view.TotalWidth, view.TotalHeight);
|
||||
if (unsupported.Count != 0)
|
||||
{
|
||||
var err = MessageStrings.MsgFieldItemUnsupportedLayer2Tile;
|
||||
|
|
@ -524,7 +523,7 @@ private void B_Save_Click(object sender, EventArgs e)
|
|||
Map.Items.Save();
|
||||
SAV.SetTerrainTiles(Map.Terrain.Tiles);
|
||||
|
||||
SAV.SetAcreBytes(Map.Terrain.BaseAcres);
|
||||
SAV.SetAcreBytes(Map.Terrain.BaseAcres.Span);
|
||||
SAV.OutsideFieldTemplateUniqueId = (ushort)NUD_MapAcreTemplateOutside.Value;
|
||||
SAV.MainFieldParamUniqueID = (ushort)NUD_MapAcreTemplateField.Value;
|
||||
|
||||
|
|
@ -616,7 +615,7 @@ private void Menu_Activate_Click(object sender, EventArgs e)
|
|||
private void B_Up_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ModifierKeys == Keys.Shift)
|
||||
CB_Acre.SelectedIndex = Math.Max(0, CB_Acre.SelectedIndex - MapGrid.AcreWidth);
|
||||
CB_Acre.SelectedIndex = Math.Max(0, CB_Acre.SelectedIndex - View.Map.Items.Layer1.TileInfo.Columns);
|
||||
else if (View.ArrowUp())
|
||||
LoadItemGridAcre();
|
||||
}
|
||||
|
|
@ -640,7 +639,7 @@ private void B_Right_Click(object sender, EventArgs e)
|
|||
private void B_Down_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ModifierKeys == Keys.Shift)
|
||||
CB_Acre.SelectedIndex = Math.Min(CB_Acre.SelectedIndex + MapGrid.AcreWidth, CB_Acre.Items.Count - 1);
|
||||
CB_Acre.SelectedIndex = Math.Min(CB_Acre.SelectedIndex + View.Map.Items.Layer1.TileInfo.Columns, CB_Acre.Items.Count - 1);
|
||||
else if (View.ArrowDown())
|
||||
LoadItemGridAcre();
|
||||
}
|
||||
|
|
@ -989,7 +988,7 @@ private void NUD_BuildingType_ValueChanged(object sender, EventArgs e)
|
|||
|
||||
private void CB_MapAcre_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
var acre = Map.Terrain.BaseAcres[CB_MapAcre.SelectedIndex * 2];
|
||||
var acre = Map.Terrain.BaseAcres.Span[CB_MapAcre.SelectedIndex * 2];
|
||||
CB_MapAcreSelect.SelectedValue = (int)acre;
|
||||
|
||||
// Jump view if available
|
||||
|
|
@ -1005,7 +1004,7 @@ private void CB_MapAcreSelect_SelectedValueChanged(object sender, EventArgs e)
|
|||
var index = CB_MapAcre.SelectedIndex;
|
||||
var value = WinFormsUtil.GetIndex(CB_MapAcreSelect);
|
||||
|
||||
var span = Map.Terrain.BaseAcres.AsSpan(index * 2, 2);
|
||||
var span = Map.Terrain.BaseAcres.Span.Slice(index * 2, 2);
|
||||
var oldValue = span[0];
|
||||
if (value == oldValue)
|
||||
return;
|
||||
|
|
@ -1016,7 +1015,7 @@ private void CB_MapAcreSelect_SelectedValueChanged(object sender, EventArgs e)
|
|||
|
||||
private void B_DumpMapAcres_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!MapDumpHelper.DumpMapAcresAll(Map.Terrain.BaseAcres))
|
||||
if (!MapDumpHelper.DumpMapAcresAll(Map.Terrain.BaseAcres.Span))
|
||||
return;
|
||||
ReloadBuildingsTerrain();
|
||||
System.Media.SystemSounds.Asterisk.Play();
|
||||
|
|
@ -1024,7 +1023,7 @@ private void B_DumpMapAcres_Click(object sender, EventArgs e)
|
|||
|
||||
private void B_ImportMapAcres_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!MapDumpHelper.ImportMapAcresAll(Map.Terrain.BaseAcres))
|
||||
if (!MapDumpHelper.ImportMapAcresAll(Map.Terrain.BaseAcres.Span))
|
||||
return;
|
||||
ReloadBuildingsTerrain();
|
||||
System.Media.SystemSounds.Asterisk.Play();
|
||||
|
|
@ -1108,7 +1107,7 @@ private void Menu_Bulk_Click(object sender, EventArgs e)
|
|||
{
|
||||
var editor = new BatchEditor(SpawnLayer.Tiles, ItemEdit.SetItem(new Item()));
|
||||
editor.ShowDialog();
|
||||
SpawnLayer.ClearDanglingExtensions(0, 0, SpawnLayer.MaxWidth, SpawnLayer.MaxHeight);
|
||||
SpawnLayer.ClearDanglingExtensions(0, 0, SpawnLayer.TileInfo.TotalWidth, SpawnLayer.TileInfo.TotalHeight);
|
||||
LoadItemGridAcre();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public static bool ImportToLayerAcreSingle(FieldItemLayer layer, int acreIndex,
|
|||
var path = ofd.FileName;
|
||||
var fi = new FileInfo(path);
|
||||
|
||||
int expect = layer.GridTileCount * Item.SIZE;
|
||||
int expect = layer.TileInfo.ViewCount * Item.SIZE;
|
||||
if (fi.Length != expect)
|
||||
{
|
||||
WinFormsUtil.Error(string.Format(MessageStrings.MsgDataSizeMismatchImport, fi.Length, expect));
|
||||
|
|
@ -42,7 +42,7 @@ public static bool ImportToLayerAcreAll(FieldItemLayer layer)
|
|||
var path = ofd.FileName;
|
||||
var fi = new FileInfo(path);
|
||||
|
||||
int expect = layer.MaxTileCount * Item.SIZE;
|
||||
int expect = layer.TileInfo.TotalCount * Item.SIZE;
|
||||
if (fi.Length != expect)
|
||||
{
|
||||
WinFormsUtil.Error(string.Format(MessageStrings.MsgDataSizeMismatchImport, fi.Length, expect));
|
||||
|
|
@ -91,7 +91,7 @@ public static bool ImportTerrainAcre(TerrainLayer m, int acreIndex, string acre)
|
|||
var path = ofd.FileName;
|
||||
var fi = new FileInfo(path);
|
||||
|
||||
int expect = m.GridTileCount * TerrainTile.SIZE;
|
||||
int expect = m.TileInfo.ViewCount * TerrainTile.SIZE;
|
||||
if (fi.Length != expect)
|
||||
{
|
||||
WinFormsUtil.Error(string.Format(MessageStrings.MsgDataSizeMismatchImport, fi.Length, expect));
|
||||
|
|
@ -114,7 +114,7 @@ public static bool ImportTerrainAll(TerrainLayer m)
|
|||
var path = ofd.FileName;
|
||||
var fi = new FileInfo(path);
|
||||
|
||||
int expect = m.MaxTileCount * TerrainTile.SIZE;
|
||||
int expect = m.TileInfo.TotalCount * TerrainTile.SIZE;
|
||||
if (fi.Length != expect)
|
||||
{
|
||||
WinFormsUtil.Error(string.Format(MessageStrings.MsgDataSizeMismatchImport, fi.Length, expect));
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ private void SetHoveredItem(MouseEventArgs e)
|
|||
GetCoordinates(e, out HoverX, out HoverY);
|
||||
|
||||
// Mouse event may fire with a slightly too large x/y; clamp just in case.
|
||||
Manager.Layers[0].ClampCoordinatesInsideGrid(ref HoverX, ref HoverY);
|
||||
Manager.Layers[0].TileInfo.ClampInside(ref HoverX, ref HoverY);
|
||||
}
|
||||
|
||||
private static void GetCoordinates(MouseEventArgs e, out int x, out int y)
|
||||
|
|
@ -164,8 +164,8 @@ private void ReloadManager(IPlayerHouse house)
|
|||
|
||||
private void DrawRoom(ItemLayer layer)
|
||||
{
|
||||
var w = layer.MaxWidth;
|
||||
var h = layer.MaxHeight;
|
||||
var w = layer.TileInfo.TotalWidth;
|
||||
var h = layer.TileInfo.TotalHeight;
|
||||
Span<int> scale1 = stackalloc int[w * h];
|
||||
int[] scaleX = new int[scale * scale * scale1.Length];
|
||||
var bmp = new Bitmap(scale * w, scale * h);
|
||||
|
|
@ -240,8 +240,8 @@ private void ViewTile(Item tile, int x, int y)
|
|||
if (CHK_RedirectExtensionLoad.Checked && tile.IsExtension)
|
||||
{
|
||||
var l = CurrentLayer;
|
||||
var rx = Math.Max(0, Math.Min(l.MaxWidth - 1, x - tile.ExtensionX));
|
||||
var ry = Math.Max(0, Math.Min(l.MaxHeight - 1, y - tile.ExtensionY));
|
||||
var rx = Math.Max(0, Math.Min(l.TileInfo.TotalWidth - 1, x - tile.ExtensionX));
|
||||
var ry = Math.Max(0, Math.Min(l.TileInfo.TotalHeight - 1, y - tile.ExtensionY));
|
||||
var redir = l.GetTile(rx, ry);
|
||||
if (redir.IsRoot && redir.ItemId == tile.ExtensionItemId)
|
||||
tile = redir;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user