mirror of
https://github.com/kwsch/NHSE.git
synced 2026-04-21 16:07:26 -05:00
310 lines
10 KiB
C#
310 lines
10 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.IO;
|
|
using System.Windows.Forms;
|
|
using NHSE.Core;
|
|
using NHSE.Sprites;
|
|
|
|
namespace NHSE.WinForms
|
|
{
|
|
public partial class TerrainEditor : Form
|
|
{
|
|
private readonly MainSave SAV;
|
|
private readonly Button[] Grid;
|
|
private readonly TerrainManager Terrain;
|
|
|
|
private const int SquareSize = 50;
|
|
|
|
public TerrainEditor(MainSave sav)
|
|
{
|
|
SAV = sav;
|
|
InitializeComponent();
|
|
|
|
Terrain = new TerrainManager(SAV.Terrain);
|
|
Grid = GenerateGrid(TerrainManager.GridWidth, TerrainManager.GridHeight);
|
|
|
|
foreach (var acre in Terrain.Acres)
|
|
CB_Acre.Items.Add(acre.Name);
|
|
|
|
PG_Tile.SelectedObject = new TerrainTile();
|
|
CB_Acre.SelectedIndex = 0;
|
|
ReloadMap();
|
|
}
|
|
|
|
private int AcreIndex => CB_Acre.SelectedIndex;
|
|
private void ChangeAcre(object sender, EventArgs e) => LoadGrid(AcreIndex);
|
|
|
|
private void LoadGrid(int index)
|
|
{
|
|
for (int i = 0; i < TerrainManager.AcreSize; i++)
|
|
{
|
|
var b = Grid[i];
|
|
var tile = Terrain.GetAcreTile(index, i);
|
|
RefreshTile(b, tile);
|
|
}
|
|
UpdateArrowVisibility(index);
|
|
ReloadMap();
|
|
}
|
|
|
|
private void ReloadMap()
|
|
{
|
|
var img = TerrainSprite.CreateMap(Terrain);
|
|
var map = ImageUtil.ResizeImage(img, img.Width * 2, img.Height * 2);
|
|
|
|
using var gfx = Graphics.FromImage(map);
|
|
using var pen = new Pen(Color.Red);
|
|
|
|
var acre = Terrain.Acres[AcreIndex];
|
|
gfx.DrawRectangle(pen, acre.X * TerrainManager.GridWidth * 2, acre.Y * TerrainManager.GridHeight * 2, TerrainManager.GridWidth * 2, TerrainManager.GridHeight * 2);
|
|
|
|
PB_Map.Image = map;
|
|
}
|
|
|
|
private void UpdateArrowVisibility(int index)
|
|
{
|
|
B_Up.Enabled = index > TerrainManager.AcreWidth;
|
|
B_Down.Enabled = index < TerrainManager.AcreWidth * (TerrainManager.AcreHeight - 1);
|
|
B_Left.Enabled = index % TerrainManager.AcreWidth != 0;
|
|
B_Right.Enabled = index % TerrainManager.AcreWidth != TerrainManager.AcreWidth - 1;
|
|
}
|
|
|
|
private Button[] GenerateGrid(int w, int h)
|
|
{
|
|
var grid = new Button[w * h];
|
|
int i = 0;
|
|
for (int y = 0; y < h; y++)
|
|
{
|
|
for (int x = 0; x < w; x++)
|
|
{
|
|
var item = GetGridItem(index: i, x, y);
|
|
FLP_Tile.Controls.Add(item);
|
|
grid[i++] = item;
|
|
}
|
|
|
|
var last = grid[i - 1];
|
|
FLP_Tile.SetFlowBreak(last, true);
|
|
}
|
|
|
|
return grid;
|
|
}
|
|
|
|
private Button GetGridItem(int index, int x, int y)
|
|
{
|
|
var button = new Button
|
|
{
|
|
Name = index.ToString(),
|
|
Text = $"{index:000} ({x},{y})",
|
|
Size = new Size(SquareSize, SquareSize),
|
|
Padding = Padding.Empty,
|
|
Margin = Padding.Empty,
|
|
ContextMenuStrip = CM_Click,
|
|
FlatStyle = FlatStyle.Flat,
|
|
};
|
|
|
|
button.Click += (sender, args) =>
|
|
{
|
|
GetTile(button, out var tile, out var obj);
|
|
switch (ModifierKeys)
|
|
{
|
|
default: ViewTile(tile); return;
|
|
case Keys.Shift: SetTile(tile, obj); return;
|
|
case Keys.Alt: DeleteTile(tile, obj); return;
|
|
}
|
|
};
|
|
return button;
|
|
}
|
|
|
|
private void ViewTile(TerrainTile tile)
|
|
{
|
|
var pgt = (TerrainTile)PG_Tile.SelectedObject;
|
|
pgt.CopyFrom(tile);
|
|
PG_Tile.SelectedObject = pgt;
|
|
}
|
|
|
|
private void SetTile(TerrainTile tile, Control obj)
|
|
{
|
|
var pgt = (TerrainTile)PG_Tile.SelectedObject;
|
|
tile.CopyFrom(pgt);
|
|
RefreshTile(obj, tile);
|
|
ReloadMap();
|
|
}
|
|
|
|
private void DeleteTile(TerrainTile tile, Control obj)
|
|
{
|
|
tile.Clear();
|
|
RefreshTile(obj, tile);
|
|
ReloadMap();
|
|
}
|
|
|
|
private void B_Cancel_Click(object sender, EventArgs e) => Close();
|
|
|
|
private void B_Save_Click(object sender, EventArgs e)
|
|
{
|
|
SAV.Terrain = Terrain.Tiles;
|
|
Close();
|
|
}
|
|
|
|
private void Menu_View_Click(object sender, EventArgs e)
|
|
{
|
|
GetTile(sender, out var tile, out _);
|
|
ViewTile(tile);
|
|
}
|
|
|
|
private void Menu_Set_Click(object sender, EventArgs e)
|
|
{
|
|
GetTile(sender, out var tile, out var obj);
|
|
SetTile(tile, obj);
|
|
}
|
|
|
|
private void Menu_Reset_Click(object sender, EventArgs e)
|
|
{
|
|
GetTile(sender, out var tile, out var obj);
|
|
DeleteTile(tile, obj);
|
|
}
|
|
|
|
private void GetTile(object sender, out TerrainTile tile, out Button obj)
|
|
{
|
|
obj = WinFormsUtil.GetUnderlyingControl<Button>(sender) ?? throw new ArgumentNullException(nameof(sender));
|
|
|
|
var index = Array.IndexOf(Grid, obj);
|
|
if (index < 0)
|
|
throw new ArgumentException(nameof(Button));
|
|
|
|
tile = Terrain.GetAcreTile(AcreIndex, index);
|
|
}
|
|
|
|
private static void RefreshTile(Control button, TerrainTile tile)
|
|
{
|
|
button.Text = TerrainSprite.GetTileName(tile);
|
|
button.BackColor = TerrainSprite.GetTileColor(tile);
|
|
}
|
|
|
|
private void B_Up_Click(object sender, EventArgs e) => CB_Acre.SelectedIndex -= TerrainManager.AcreWidth;
|
|
private void B_Left_Click(object sender, EventArgs e) => --CB_Acre.SelectedIndex;
|
|
private void B_Right_Click(object sender, EventArgs e) => ++CB_Acre.SelectedIndex;
|
|
private void B_Down_Click(object sender, EventArgs e) => CB_Acre.SelectedIndex += TerrainManager.AcreWidth;
|
|
|
|
private void B_ZeroElevation_Click(object sender, EventArgs e)
|
|
{
|
|
foreach (var t in Terrain.Tiles)
|
|
t.Elevation = 0;
|
|
LoadGrid(AcreIndex);
|
|
System.Media.SystemSounds.Asterisk.Play();
|
|
}
|
|
|
|
private void B_ClearAll_Click(object sender, EventArgs e)
|
|
{
|
|
foreach (var t in Terrain.Tiles)
|
|
t.Clear();
|
|
LoadGrid(AcreIndex);
|
|
System.Media.SystemSounds.Asterisk.Play();
|
|
}
|
|
|
|
private void B_DumpAcre_Click(object sender, EventArgs e)
|
|
{
|
|
using var sfd = new SaveFileDialog
|
|
{
|
|
Filter = "New Horizons Terrain (*.nht)|*.nht|All files (*.*)|*.*",
|
|
FileName = $"{CB_Acre.Text}.nht",
|
|
};
|
|
if (sfd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
var path = sfd.FileName;
|
|
var acre = AcreIndex;
|
|
var data = Terrain.DumpAcre(acre);
|
|
File.WriteAllBytes(path, data);
|
|
}
|
|
|
|
private void B_DumpAllAcres_Click(object sender, EventArgs e)
|
|
{
|
|
using var sfd = new SaveFileDialog
|
|
{
|
|
Filter = "New Horizons Terrain (*.nht)|*.nht|All files (*.*)|*.*",
|
|
FileName = $"{CB_Acre.Text}.nht",
|
|
};
|
|
if (sfd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
var path = sfd.FileName;
|
|
var data = Terrain.DumpAllAcres();
|
|
File.WriteAllBytes(path, data);
|
|
}
|
|
|
|
private void B_ImportAcre_Click(object sender, EventArgs e)
|
|
{
|
|
using var ofd = new OpenFileDialog
|
|
{
|
|
Filter = "New Horizons Terrain (*.nht)|*.nht|All files (*.*)|*.*",
|
|
FileName = "terrainAcres.nht",
|
|
};
|
|
if (ofd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
var path = ofd.FileName;
|
|
var fi = new FileInfo(path);
|
|
|
|
const int expect = TerrainManager.AcreSize * TerrainTile.SIZE;
|
|
if (fi.Length != expect)
|
|
{
|
|
WinFormsUtil.Error($"Expected size (0x{expect:X}) != Input size (0x{fi.Length:X}", path);
|
|
return;
|
|
}
|
|
|
|
var data = File.ReadAllBytes(path);
|
|
Terrain.ImportAcre(AcreIndex, data);
|
|
LoadGrid(AcreIndex);
|
|
System.Media.SystemSounds.Asterisk.Play();
|
|
}
|
|
|
|
private void B_ImportAllAcres_Click(object sender, EventArgs e)
|
|
{
|
|
using var ofd = new OpenFileDialog
|
|
{
|
|
Filter = "New Horizons Terrain (*.nht)|*.nht|All files (*.*)|*.*",
|
|
FileName = "terrainAcres.nht",
|
|
};
|
|
if (ofd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
var path = ofd.FileName;
|
|
var fi = new FileInfo(path);
|
|
|
|
const int expect = TerrainManager.TileCount * TerrainTile.SIZE;
|
|
if (fi.Length != expect)
|
|
{
|
|
WinFormsUtil.Error($"Expected size (0x{expect:X}) != Input size (0x{fi.Length:X}", path);
|
|
return;
|
|
}
|
|
|
|
var data = File.ReadAllBytes(path);
|
|
Terrain.ImportAllAcres(data);
|
|
LoadGrid(AcreIndex);
|
|
System.Media.SystemSounds.Asterisk.Play();
|
|
}
|
|
|
|
private void Menu_SavePNG_Click(object sender, EventArgs e)
|
|
{
|
|
var pb = WinFormsUtil.GetUnderlyingControl<PictureBox>(sender);
|
|
if (pb?.Image == null)
|
|
{
|
|
WinFormsUtil.Alert("No picture loaded.");
|
|
return;
|
|
}
|
|
|
|
const string name = "map";
|
|
var bmp = pb.Image;
|
|
using var sfd = new SaveFileDialog
|
|
{
|
|
Filter = "png file (*.png)|*.png|All files (*.*)|*.*",
|
|
FileName = $"{name}.png",
|
|
};
|
|
if (sfd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
bmp.Save(sfd.FileName, ImageFormat.Png);
|
|
}
|
|
}
|
|
}
|