mirror of
https://github.com/kwsch/NHSE.git
synced 2026-08-03 08:20:17 -05:00
Add more fielditem manipulation logic
32x32 because we have 2x2 metatiles -- items can be placed at half-coordinates relative to tile coordinates.
This commit is contained in:
parent
2ce535c67c
commit
25a162c187
|
|
@ -62,9 +62,12 @@ public void SetAcreBytes(byte[] data)
|
|||
data.CopyTo(Data, Offsets.Acres);
|
||||
}
|
||||
|
||||
public TerrainTile[] GetTerrain() => TerrainTile.GetArray(Data.Slice(Offsets.Terrain, MapGrid.MapTileCount * TerrainTile.SIZE));
|
||||
public TerrainTile[] GetTerrain() => TerrainTile.GetArray(Data.Slice(Offsets.Terrain, MapGrid.MapTileCount16x16 * TerrainTile.SIZE));
|
||||
public void SetTerrain(IReadOnlyList<TerrainTile> array) => TerrainTile.SetArray(array).CopyTo(Data, Offsets.Terrain);
|
||||
|
||||
public FieldItem[] GetFieldItems() => FieldItem.GetArray(Data.Slice(Offsets.FieldItem, MapGrid.MapTileCount32x32 * FieldItem.SIZE));
|
||||
public void SetFieldItems(IReadOnlyList<FieldItem> array) => FieldItem.SetArray(array).CopyTo(Data, Offsets.FieldItem);
|
||||
|
||||
public uint PlazaX
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, Offsets.Acres + AcreSizeAll + 4);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public abstract class MainSaveOffsets
|
|||
|
||||
public abstract int TurnipExchange { get; }
|
||||
|
||||
public abstract int FieldItem { get; }
|
||||
public abstract int Acres { get; }
|
||||
public abstract int Terrain { get; }
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ public class MainSaveOffsets10 : MainSaveOffsets
|
|||
{
|
||||
public override int Villager => 0x110;
|
||||
public override int Patterns => 0x1D72F0;
|
||||
public override int FieldItem => 0x2018FC;
|
||||
public override int Terrain => Buildings - 0x24C00; // dunno where exactly it starts???
|
||||
public override int Buildings => 0x2D0EFC;
|
||||
public override int Acres => 0x2D1294;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ public class MainSaveOffsets11 : MainSaveOffsets
|
|||
{
|
||||
public override int Villager => 0x120;
|
||||
public override int Patterns => 0x1D7310; // +0x20 from v1.0
|
||||
public override int FieldItem => 0x20191C; // +0x20 from v1.0
|
||||
public override int Terrain => Buildings - 0x24C00; // dunno where exactly it starts??? // +0x20 from v1.0
|
||||
public override int Buildings => 0x2D0F1C; // +0x20 from v1.0
|
||||
public override int Acres => 0x2D12B4; // +0x20 from v1.0
|
||||
|
|
|
|||
25
NHSE.Core/Structures/Acres/Terrain/FieldItemLayer.cs
Normal file
25
NHSE.Core/Structures/Acres/Terrain/FieldItemLayer.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace NHSE.Core
|
||||
{
|
||||
public class FieldItemLayer : MapGrid
|
||||
{
|
||||
public readonly FieldItem[] Tiles;
|
||||
|
||||
public FieldItemLayer(FieldItem[] tiles) : base(32, 32)
|
||||
{
|
||||
Tiles = tiles;
|
||||
Debug.Assert(MapTileCount == tiles.Length);
|
||||
}
|
||||
|
||||
public FieldItem GetTile(int x, int y) => this[GetTileIndex(x, y)];
|
||||
public FieldItem GetTile(int acreX, int acreY, int gridX, int gridY) => this[GetTileIndex(acreX, acreY, gridX, gridY)];
|
||||
public FieldItem GetAcreTile(int acreIndex, int tileIndex) => this[GetAcreTileIndex(acreIndex, tileIndex)];
|
||||
|
||||
public FieldItem this[int index]
|
||||
{
|
||||
get => Tiles[index];
|
||||
set => Tiles[index] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
NHSE.Core/Structures/Acres/Terrain/FieldItemManager.cs
Normal file
36
NHSE.Core/Structures/Acres/Terrain/FieldItemManager.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
|
||||
namespace NHSE.Core
|
||||
{
|
||||
public class FieldItemManager
|
||||
{
|
||||
public readonly FieldItemLayer Layer1;
|
||||
public readonly FieldItemLayer Layer2;
|
||||
|
||||
public FieldItemManager(FieldItem[] layer1, FieldItem[] layer2)
|
||||
{
|
||||
Layer1 = new FieldItemLayer(layer1);
|
||||
Layer2 = new FieldItemLayer(layer2);
|
||||
}
|
||||
|
||||
public FieldItemManager(FieldItem[] items, int layers = 2) // Two halves; split and assign.
|
||||
: this(items.Slice(0, items.Length / 2), items.SliceEnd(items.Length / 2))
|
||||
{
|
||||
if (layers != 2)
|
||||
throw new ArgumentOutOfRangeException(nameof(layers));
|
||||
}
|
||||
|
||||
public FieldItem GetTile(int layer, int x, int y) => GetLayer(layer).GetTile(x, y);
|
||||
public FieldItem GetTile(int layer, int acreX, int acreY, int gridX, int gridY) => GetLayer(layer).GetTile(acreX, acreY, gridX, gridY);
|
||||
public FieldItem GetAcreTile(int layer, int acreIndex, int tileIndex) => GetLayer(layer).GetAcreTile(acreIndex, tileIndex);
|
||||
|
||||
public FieldItemLayer GetLayer(int layer)
|
||||
{
|
||||
if ((uint) layer >= 2)
|
||||
throw new ArgumentOutOfRangeException(nameof(layer));
|
||||
return layer == 0 ? Layer1 : Layer2;
|
||||
}
|
||||
|
||||
public bool IsOccupied(int x, int y) => !Layer1.GetTile(x, y).IsNone || !Layer2.GetTile(x, y).IsNone;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,27 +9,37 @@ public abstract class MapGrid
|
|||
{
|
||||
public static readonly AcreCoordinate[] Acres = AcreCoordinate.GetGrid(AcreWidth, AcreHeight);
|
||||
|
||||
public const int GridWidth = 16;
|
||||
public const int GridHeight = 16;
|
||||
protected MapGrid(int gw, int gh)
|
||||
{
|
||||
GridWidth = gw;
|
||||
GridHeight = gh;
|
||||
}
|
||||
|
||||
public readonly int GridWidth;
|
||||
public readonly int GridHeight;
|
||||
|
||||
public const int AcreWidth = 7;
|
||||
public const int AcreHeight = 6;
|
||||
public const int AcreTileCount = GridWidth * GridHeight;
|
||||
public const int AcreCount = AcreWidth * AcreHeight;
|
||||
|
||||
public const int MapHeight = AcreHeight * GridHeight; // 96
|
||||
public const int MapWidth = AcreWidth * GridWidth; // 112
|
||||
public const int MapTileCount = MapWidth * MapHeight; // 0x2A00 bytes for
|
||||
public int AcreTileCount => GridWidth * GridHeight;
|
||||
public int MapHeight => AcreHeight * GridHeight; // 96 (when 16x16)
|
||||
public int MapWidth => AcreWidth * GridWidth; // 112 (when 16x16)
|
||||
public int MapTileCount => MapWidth * MapHeight; // 0x2A00 bytes (when 16x16)
|
||||
|
||||
protected static int GetTileIndex(int x, int y) => (MapHeight * x) + y;
|
||||
public const int MapTileCount16x16 = 16 * 16 * AcreCount;
|
||||
public const int MapTileCount32x32 = 32 * 32 * AcreCount;
|
||||
|
||||
protected static int GetTileIndex(int acreX, int acreY, int gridX, int gridY)
|
||||
protected int GetTileIndex(int x, int y) => (MapHeight * x) + y;
|
||||
|
||||
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 static int GetAcreTileIndex(int acreIndex, int tileIndex)
|
||||
protected int GetAcreTileIndex(int acreIndex, int tileIndex)
|
||||
{
|
||||
var acre = Acres[acreIndex];
|
||||
var x = (tileIndex % GridWidth);
|
||||
|
|
@ -37,9 +47,9 @@ protected static int GetAcreTileIndex(int acreIndex, int tileIndex)
|
|||
return GetTileIndex(acre.X, acre.Y, x, y);
|
||||
}
|
||||
|
||||
public static int GetAcre(int x, int y) => (x / GridWidth) + ((y / GridHeight) * AcreWidth);
|
||||
public int GetAcre(int x, int y) => (x / GridWidth) + ((y / GridHeight) * AcreWidth);
|
||||
|
||||
public static void GetViewAnchorCoordinates(ref int x, ref int y, bool centerReticle)
|
||||
public void GetViewAnchorCoordinates(ref int x, ref int y, 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.
|
||||
|
|
@ -53,13 +63,13 @@ public static void GetViewAnchorCoordinates(ref int x, ref int y, bool centerRet
|
|||
|
||||
// Clamp to viewport dimensions, and center to nearest acre if desired.
|
||||
// Clamp to boundaries so that we always have 16x16 to view.
|
||||
const int maxX = ((AcreWidth - 1) * GridWidth);
|
||||
const int maxY = ((AcreHeight - 1) * GridHeight);
|
||||
int maxX = ((AcreWidth - 1) * GridWidth);
|
||||
int maxY = ((AcreHeight - 1) * GridHeight);
|
||||
x = Math.Max(0, Math.Min(x, maxX));
|
||||
y = Math.Max(0, Math.Min(y, maxY));
|
||||
}
|
||||
|
||||
public static void GetViewAnchorCoordinates(int acre, out int x, out int y)
|
||||
public void GetViewAnchorCoordinates(int acre, out int x, out int y)
|
||||
{
|
||||
x = (acre % AcreWidth) * GridWidth;
|
||||
y = (acre / AcreWidth) * GridHeight;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ public class TerrainManager : MapGrid
|
|||
{
|
||||
public readonly TerrainTile[] Tiles;
|
||||
|
||||
public TerrainManager(TerrainTile[] tiles)
|
||||
public TerrainManager(TerrainTile[] tiles) : base(16, 16)
|
||||
{
|
||||
Tiles = tiles;
|
||||
Debug.Assert(MapTileCount == tiles.Length);
|
||||
|
|
@ -32,7 +32,7 @@ public byte[] DumpAllAcres()
|
|||
|
||||
public byte[] DumpAcre(int acre)
|
||||
{
|
||||
const int count = AcreTileCount;
|
||||
int count = AcreTileCount;
|
||||
var result = new byte[TerrainTile.SIZE * count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
|
|
@ -52,7 +52,7 @@ public void ImportAllAcres(byte[] data)
|
|||
|
||||
public void ImportAcre(int acre, byte[] data)
|
||||
{
|
||||
const int count = AcreTileCount;
|
||||
int count = AcreTileCount;
|
||||
var tiles = TerrainTile.GetArray(data);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,9 +9,12 @@ public class FieldItemSpriteDrawer
|
|||
public int Width { get; set; } = 8;
|
||||
public int Height { get; set; } = 8;
|
||||
|
||||
public Bitmap GetImage(FieldItem item) => FieldItemSprite.GetImage(item, Width, Height);
|
||||
|
||||
public Bitmap GetBitmapLayer(FieldItemLayer layer) => GetItemArray(layer.Tiles, layer.MapHeight);
|
||||
|
||||
public Bitmap GetItemArray(IReadOnlyList<FieldItem> items, int height)
|
||||
{
|
||||
//var items = FieldItem.GetArray(SAV.Main.Data.Slice(0x20191C, 0xA8000));
|
||||
var width = items.Count / height;
|
||||
|
||||
var png = new Bitmap(width * Width, height * Height);
|
||||
|
|
|
|||
|
|
@ -41,10 +41,10 @@ public static string GetTileName(TerrainTile tile)
|
|||
|
||||
public static Bitmap CreateMap(TerrainManager mgr)
|
||||
{
|
||||
var bmp = new Bitmap(MapGrid.MapWidth, MapGrid.MapHeight);
|
||||
for (int x = 0; x < MapGrid.MapWidth; x++)
|
||||
var bmp = new Bitmap(mgr.MapWidth, mgr.MapHeight);
|
||||
for (int x = 0; x < mgr.MapWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < MapGrid.MapHeight; y++)
|
||||
for (int y = 0; y < mgr.MapHeight; y++)
|
||||
{
|
||||
var tile = mgr.GetTile(x, y);
|
||||
var color = GetTileColor(tile);
|
||||
|
|
@ -59,7 +59,7 @@ public static Bitmap CreateMap(TerrainManager mgr, int scale, int x, int y)
|
|||
{
|
||||
var img = CreateMap(mgr);
|
||||
var map = ImageUtil.ResizeImage(img, img.Width * scale, img.Height * scale);
|
||||
return DrawReticle(map, x, y, scale);
|
||||
return DrawReticle(map, mgr, x, y, scale);
|
||||
}
|
||||
|
||||
public static Bitmap CreateMap(TerrainManager mgr, int scale, int acreIndex = -1)
|
||||
|
|
@ -71,19 +71,19 @@ public static Bitmap CreateMap(TerrainManager mgr, int scale, int acreIndex = -1
|
|||
return map;
|
||||
|
||||
var acre = MapGrid.Acres[acreIndex];
|
||||
var x = acre.X * MapGrid.GridWidth;
|
||||
var y = acre.Y * MapGrid.GridHeight;
|
||||
var x = acre.X * mgr.GridWidth;
|
||||
var y = acre.Y * mgr.GridHeight;
|
||||
|
||||
return DrawReticle(map, x, y, scale);
|
||||
return DrawReticle(map, mgr, x, y, scale);
|
||||
}
|
||||
|
||||
private static Bitmap DrawReticle(Bitmap map, int x, int y, int scale)
|
||||
private static Bitmap DrawReticle(Bitmap map, TerrainManager mgr, int x, int y, int scale)
|
||||
{
|
||||
using var gfx = Graphics.FromImage(map);
|
||||
using var pen = new Pen(Color.Red);
|
||||
|
||||
int w = MapGrid.GridWidth * scale;
|
||||
int h = MapGrid.GridHeight * scale;
|
||||
int w = mgr.GridWidth * scale;
|
||||
int h = mgr.GridHeight * scale;
|
||||
gfx.DrawRectangle(pen, x * scale, y * scale, w, h);
|
||||
return map;
|
||||
}
|
||||
|
|
@ -93,15 +93,15 @@ public static Bitmap GetMapWithBuildings(TerrainManager mgr, IReadOnlyList<Build
|
|||
var map = CreateMap(mgr, scale);
|
||||
using var gfx = Graphics.FromImage(map);
|
||||
|
||||
gfx.DrawPlaza(plazaX, plazaY, scale);
|
||||
gfx.DrawBuildings(buildings, f, scale, index);
|
||||
gfx.DrawPlaza(mgr, plazaX, plazaY, scale);
|
||||
gfx.DrawBuildings(mgr, buildings, f, scale, index);
|
||||
return map;
|
||||
}
|
||||
|
||||
private static void DrawPlaza(this Graphics gfx, ushort px, ushort py, int scale)
|
||||
private static void DrawPlaza(this Graphics gfx, MapGrid g, ushort px, ushort py, int scale)
|
||||
{
|
||||
var plaza = Brushes.RosyBrown;
|
||||
GetBuildingCoordinate(px, py, scale, out var x, out var y);
|
||||
GetBuildingCoordinate(g, px, py, scale, out var x, out var y);
|
||||
|
||||
var width = scale * 2 * 6;
|
||||
var height = scale * 2 * 5;
|
||||
|
|
@ -109,7 +109,7 @@ private static void DrawPlaza(this Graphics gfx, ushort px, ushort py, int scale
|
|||
gfx.FillRectangle(plaza, x, y, width, height);
|
||||
}
|
||||
|
||||
private static void DrawBuildings(this Graphics gfx, IReadOnlyList<Building> buildings, Font f, int scale, int index = -1)
|
||||
private static void DrawBuildings(this Graphics gfx, MapGrid g, IReadOnlyList<Building> buildings, Font f, int scale, int index = -1)
|
||||
{
|
||||
var selected = Brushes.Red;
|
||||
var others = Brushes.Yellow;
|
||||
|
|
@ -121,7 +121,7 @@ private static void DrawBuildings(this Graphics gfx, IReadOnlyList<Building> bui
|
|||
var b = buildings[i];
|
||||
if (b.BuildingType == 0)
|
||||
continue;
|
||||
GetBuildingCoordinate(b.X, b.Y, scale, out var x, out var y);
|
||||
GetBuildingCoordinate(g,b.X, b.Y, scale, out var x, out var y);
|
||||
|
||||
var pen = index == i ? selected : others;
|
||||
gfx.FillRectangle(pen, x - scale, y - scale, scale * 2, scale * 2);
|
||||
|
|
@ -131,11 +131,11 @@ private static void DrawBuildings(this Graphics gfx, IReadOnlyList<Building> bui
|
|||
}
|
||||
}
|
||||
|
||||
private static void GetBuildingCoordinate(ushort bx, ushort by, int scale, out int x, out int y)
|
||||
private static void GetBuildingCoordinate(MapGrid g, ushort bx, ushort by, int scale, out int x, out int y)
|
||||
{
|
||||
// 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.
|
||||
const int buildingShift = MapGrid.GridWidth;
|
||||
int buildingShift = g.GridWidth;
|
||||
x = (int) (((bx / 2f) - buildingShift) * scale);
|
||||
y = (int) (((by / 2f) - buildingShift) * scale);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ public partial class TerrainEditor : Form
|
|||
private readonly Button[] Grid;
|
||||
private readonly TerrainManager Terrain;
|
||||
|
||||
private const int GridWidth = MapGrid.GridWidth;
|
||||
private const int GridHeight = MapGrid.GridHeight;
|
||||
private int GridWidth => Terrain.GridWidth;
|
||||
private int GridHeight => Terrain.GridHeight;
|
||||
|
||||
private const int SquareSize = 50;
|
||||
private const int MapScale = 2;
|
||||
|
|
@ -45,7 +45,7 @@ public TerrainEditor(MainSave sav)
|
|||
|
||||
private void ChangeViewToAcre(int acre)
|
||||
{
|
||||
MapGrid.GetViewAnchorCoordinates(acre, out X, out Y);
|
||||
Terrain.GetViewAnchorCoordinates(acre, out X, out Y);
|
||||
LoadGrid(X, Y);
|
||||
UpdateArrowVisibility(acre);
|
||||
}
|
||||
|
|
@ -261,7 +261,7 @@ private void B_ImportAcre_Click(object sender, EventArgs e)
|
|||
var path = ofd.FileName;
|
||||
var fi = new FileInfo(path);
|
||||
|
||||
const int expect = MapGrid.AcreTileCount * TerrainTile.SIZE;
|
||||
int expect = Terrain.AcreTileCount * TerrainTile.SIZE;
|
||||
if (fi.Length != expect)
|
||||
{
|
||||
WinFormsUtil.Error($"Expected size (0x{expect:X}) != Input size (0x{fi.Length:X}", path);
|
||||
|
|
@ -287,7 +287,7 @@ private void B_ImportAllAcres_Click(object sender, EventArgs e)
|
|||
var path = ofd.FileName;
|
||||
var fi = new FileInfo(path);
|
||||
|
||||
const int expect = MapGrid.MapTileCount * TerrainTile.SIZE;
|
||||
int expect = Terrain.AcreTileCount * TerrainTile.SIZE;
|
||||
if (fi.Length != expect)
|
||||
{
|
||||
WinFormsUtil.Error($"Expected size (0x{expect:X}) != Input size (0x{fi.Length:X}", path);
|
||||
|
|
@ -331,7 +331,7 @@ private void ClickMapAt(MouseEventArgs e, bool skipLagCheck)
|
|||
bool centerReticle = CHK_SnapToAcre.Checked;
|
||||
GetViewAnchorCoordinates(mX, mY, out var x, out var y, centerReticle);
|
||||
|
||||
var acre = MapGrid.GetAcre(x, y);
|
||||
var acre = Terrain.GetAcre(x, y);
|
||||
bool sameAcre = AcreIndex == acre;
|
||||
if (!skipLagCheck)
|
||||
{
|
||||
|
|
@ -366,10 +366,10 @@ private static void GetCursorCoordinates(int mX, int mY, out int x, out int y)
|
|||
y = mY / MapScale;
|
||||
}
|
||||
|
||||
private static void GetViewAnchorCoordinates(int mX, int mY, out int x, out int y, bool centerReticle)
|
||||
private void GetViewAnchorCoordinates(int mX, int mY, out int x, out int y, bool centerReticle)
|
||||
{
|
||||
GetCursorCoordinates(mX, mY, out x, out y);
|
||||
MapGrid.GetViewAnchorCoordinates(ref x, ref y, centerReticle);
|
||||
Terrain.GetViewAnchorCoordinates(ref x, ref y, centerReticle);
|
||||
}
|
||||
|
||||
private void PB_Map_MouseMove(object sender, MouseEventArgs e)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user