Merge branch 'kwsch:master' into master

This commit is contained in:
wuyx0914 2026-02-06 16:50:41 +08:00 committed by GitHub
commit 8d93e0a45e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
78 changed files with 1316 additions and 1155 deletions

View File

@ -46,33 +46,33 @@ private static Color GetRiverColor(TerrainUnitModel mdl, LandAngles landAngle, i
return mdl switch
{
// River0A single "hole" of water land all sides. Rotation does nothing
River0A when (relativeX < 4 || relativeX >= 12 || relativeY < 4 || relativeY >= 12) =>
River0A when (relativeX is (< 4 or >= 12) || relativeY is (< 4 or >= 12)) =>
Grass,
// River1A narrow channel end opening on bottom, land on other sides
River1A => landAngle switch
{
Default when relativeX < 4 || relativeX >= 12 || relativeY < 4 => Grass,
Rotate90ClockAnverse when relativeX < 4 || relativeY < 4 || relativeY >= 12 => Grass,
Rotate180ClockAnverse when relativeX < 4 || relativeX >= 12 || relativeY >= 12 => Grass,
Rotate270ClockAnverse when relativeY < 4 || relativeY >= 12 || relativeX >= 12 => Grass,
Default when relativeX is (< 4 or >= 12) || relativeY < 4 => Grass,
Rotate90ClockAnverse when relativeX < 4 || relativeY is (< 4 or >= 12) => Grass,
Rotate180ClockAnverse when relativeX is (< 4 or >= 12) || relativeY >= 12 => Grass,
Rotate270ClockAnverse when relativeY is (< 4 or >= 12) || relativeX >= 12 => Grass,
_ => River
},
// River2A narrow water channel opening on top and bottom, land left and right
River2A => landAngle switch
{
Default when relativeX is < 4 or >= 12 => Grass,
Rotate90ClockAnverse when relativeY is >= 12 or < 4 => Grass,
Rotate180ClockAnverse when relativeX is < 4 or >= 12 => Grass,
Rotate270ClockAnverse when relativeY is < 4 or >= 12 => Grass,
Default when relativeX is (< 4 or >= 12) => Grass,
Rotate90ClockAnverse when relativeY is (< 4 or >= 12) => Grass,
Rotate180ClockAnverse when relativeX is (< 4 or >= 12) => Grass,
Rotate270ClockAnverse when relativeY is (< 4 or >= 12) => Grass,
_ => River
},
// River2B narrow 45 channel angled land top left with nub bottom right
River2B => landAngle switch
{
Default when IsPointInMultiTriangle(relativeX, relativeY, new(4, 15), new(0, 0), new(15, 4), new(0, 15), new(15, 0)) || IsNubOnBottomRight(relativeX, relativeY) || relativeX < 4 || relativeY < 4 => Grass,
Rotate90ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, new(4, 0), new(0, 15), new(15, 12), new(0, 0), new(15, 15)) || IsNubOnTopRight(relativeX, relativeY) || relativeX < 4 || relativeY >= 12 => Grass,
Rotate180ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, new(0, 12), new(15, 15), new(12, 0), new(0, 15), new(15, 0)) || IsNubOnTopLeft(relativeX, relativeY) || relativeX >= 12 || relativeY >= 12 => Grass,
Rotate270ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, new(0, 4), new(15, 0), new(12, 15), new(0, 0), new(15, 15)) || IsNubOnBottomLeft(relativeX, relativeY) || relativeX >= 12 || relativeY < 4 => Grass,
Default when IsPointInMultiTriangle(relativeX, relativeY, (4, 15), (0, 0), (15, 4), (0, 15), (15, 0)) || IsNubOnBottomRight(relativeX, relativeY) || relativeX < 4 || relativeY < 4 => Grass,
Rotate90ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, (4, 0), (0, 15), (15, 12), (0, 0), (15, 15)) || IsNubOnTopRight(relativeX, relativeY) || relativeX < 4 || relativeY >= 12 => Grass,
Rotate180ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, (0, 12), (15, 15), (12, 0), (0, 15), (15, 0)) || IsNubOnTopLeft(relativeX, relativeY) || relativeX >= 12 || relativeY >= 12 => Grass,
Rotate270ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, (0, 4), (15, 0), (12, 15), (0, 0), (15, 15)) || IsNubOnBottomLeft(relativeX, relativeY) || relativeX >= 12 || relativeY < 4 => Grass,
_ => River
},
// River2C narrow 90 channel corner land top left with nub bottom right
@ -96,10 +96,10 @@ private static Color GetRiverColor(TerrainUnitModel mdl, LandAngles landAngle, i
// River3B river 45 corner angled land top left, no nub
River3B => landAngle switch
{
Default when IsPointInMultiTriangle(relativeX, relativeY, new(4, 15), new(0, 0), new(15, 4), new(0, 15), new(15, 0)) => Grass,
Rotate90ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, new(4, 0), new(0, 15), new(15, 12), new(0, 0), new(15, 15)) => Grass,
Rotate180ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, new(0, 12), new(15, 15), new(12, 0), new(0, 15), new(15, 0)) => Grass,
Rotate270ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, new(0, 4), new(15, 0), new(12, 15), new(0, 0), new(15, 15)) => Grass,
Default when IsPointInMultiTriangle(relativeX, relativeY, (4, 15), (0, 0), (15, 4), (0, 15), (15, 0)) => Grass,
Rotate90ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, (4, 0), (0, 15), (15, 12), (0, 0), (15, 15)) => Grass,
Rotate180ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, (0, 12), (15, 15), (12, 0), (0, 15), (15, 0)) => Grass,
Rotate270ClockAnverse when IsPointInMultiTriangle(relativeX, relativeY, (0, 4), (15, 0), (12, 15), (0, 0), (15, 15)) => Grass,
_ => River
},
// River3C river 90 corner corner land top left, no nub
@ -182,10 +182,10 @@ private static Color GetRiverColor(TerrainUnitModel mdl, LandAngles landAngle, i
};
}
private static bool IsNubOnTopLeft(int relativeX, int relativeY) => IsPointInTriangle(relativeX, relativeY, new(0, 4), new(0, 0), new(4, 0));
private static bool IsNubOnTopRight(int relativeX, int relativeY) => IsPointInTriangle(relativeX, relativeY, new(12, 0), new(15, 0), new(15, 4));
private static bool IsNubOnBottomLeft(int relativeX, int relativeY) => IsPointInTriangle(relativeX, relativeY, new(0, 12), new(0, 15), new(4, 15));
private static bool IsNubOnBottomRight(int relativeX, int relativeY) => IsPointInTriangle(relativeX, relativeY, new(12, 15), new(15, 15), new(15, 12));
private static bool IsNubOnTopLeft(int relativeX, int relativeY) => IsPointInTriangle(relativeX, relativeY, (0, 4), (0, 0), (4, 0));
private static bool IsNubOnTopRight(int relativeX, int relativeY) => IsPointInTriangle(relativeX, relativeY, (12, 0), (15, 0), (15, 4));
private static bool IsNubOnBottomLeft(int relativeX, int relativeY) => IsPointInTriangle(relativeX, relativeY, (0, 12), (0, 15), (4, 15));
private static bool IsNubOnBottomRight(int relativeX, int relativeY) => IsPointInTriangle(relativeX, relativeY, (12, 15), (15, 15), (15, 12));
private static bool IsPointInMultiTriangle(int px, int py, Coordinate a, Coordinate b, Coordinate c, Coordinate vortexA, Coordinate vortexB)
{
@ -196,7 +196,7 @@ private static bool IsPointInMultiTriangle(int px, int py, Coordinate a, Coordin
private static bool IsPointInTriangle(int px, int py, Coordinate a, Coordinate b, Coordinate c)
{
Coordinate p = new(px, py);
Coordinate p = (px, py);
float areaTotal = GetTriangleArea(a, b, c);
float area1 = GetTriangleArea(p, b, c);
float area2 = GetTriangleArea(a, p, c);
@ -212,7 +212,10 @@ private static float GetTriangleArea(Coordinate a, Coordinate b, Coordinate c)
(c.X * (a.Y - b.Y))) / 2.0f);
}
private readonly record struct Coordinate(int X, int Y);
private readonly record struct Coordinate(int X, int Y)
{
public static implicit operator Coordinate((int X, int Y) tuple) => new(tuple.X, tuple.Y);
}
private static readonly Color CliffBase = ColorUtil.Blend(Grass, Color.Black, 0.6d);

View File

@ -41,8 +41,7 @@ public bool IsWrapped
{
if (AdditionalParam == 0)
return false;
var id = DisplayItemId;
return id != MessageBottle && id != MessageBottleEgg;
return DisplayItemId is not (MessageBottle or MessageBottleEgg);
}
}

View File

@ -45,4 +45,9 @@ public interface ILayerFieldItemFlag
/// </summary>
/// <param name="src">Source span containing the flags to import.</param>
void Import(Span<byte> src);
/// <summary>
/// Fetched for exporting operations.
/// </summary>
ReadOnlySpan<byte> ExistingData { get; }
}

View File

@ -32,6 +32,8 @@ public void SetIsActive(int relX, int relY, bool value)
public void Import(Span<byte> src) => src.CopyTo(Data);
public ReadOnlySpan<byte> ExistingData => Data;
public bool IsInLayer(int tileX, int tileY) => !((uint)tileX >= width || (uint)tileY >= height);
/// <summary>

View File

@ -12,7 +12,7 @@ public abstract record LayerItem : AcreSelectionGrid
public Item[] Tiles { get; }
#pragma warning disable CA1857
protected LayerItem(Item[] tiles, [ConstantExpected] byte w, [ConstantExpected] byte h) : this(tiles, new(w, h, w, h))
protected LayerItem(Item[] tiles, [ConstantExpected] byte w, [ConstantExpected] byte h) : this(tiles, new(w, h, 1, 1))
#pragma warning restore CA1857
{
}

View File

@ -289,8 +289,8 @@ public int GetTileColor(ushort acre, TerrainTile tile, int relX, int relY, int i
public ushort GetAcreTemplate(int relX, int relY)
{
// Acres are 16x16 tiles, and the acre data has a 1-acre deep-sea border around it.
var acreX = 1 + (relX / 16);
var acreY = 1 + (relY / 16);
var acreX = (16 + relX) / 16;
var acreY = (16 + relY) / 16;
var acreIndex = ((CountAcreWidth + 2) * acreY) + acreX;
var span = GetBaseAcreSpan(acreIndex);

View File

@ -8,9 +8,10 @@ public sealed record MapMutator
public required MapTileManager Manager { get; init; }
// Mutability State Tracking
public uint ItemLayerIndex { get; set => field = value & 1; }
public uint ItemLayerIndex => (uint)View.ItemLayerIndex;
public LayerFieldItem CurrentLayer => ItemLayerIndex == 0 ? Manager.FieldItems.Layer0 : Manager.FieldItems.Layer1;
public ILayerFieldItemFlag CurrentLayerFlags => ItemLayerIndex == 0 ? Manager.LayerItemFlag0 : Manager.LayerItemFlag1;
/// <inheritdoc cref="ModifyFieldItems(Func{int,int,int,int,int},in bool,LayerFieldItem)"/>
public int ModifyFieldItems(Func<int, int, int, int, int> action, in bool wholeMap)

View File

@ -1,41 +0,0 @@
using System;
namespace NHSE.Injection;
public static class Decoder
{
private static bool IsNum(char c) => (uint)(c - '0') <= 9;
private static bool IsHexUpper(char c) => (uint)(c - 'A') <= 5;
public static byte[] ConvertHexByteStringToBytes(ReadOnlySpan<byte> bytes)
{
var dest = new byte[bytes.Length / 2];
LoadHexBytesTo(bytes, dest, 2);
return dest;
}
public static void LoadHexBytesTo(ReadOnlySpan<byte> str, Span<byte> dest, int tupleSize)
{
// The input string is 2-char hex values optionally separated.
// The destination array should always be larger or equal than the bytes written. Let the runtime bounds check us.
// Iterate through the string without allocating.
for (int i = 0, j = 0; i < str.Length; i += tupleSize)
dest[j++] = DecodeTuple((char)str[i + 0], (char)str[i + 1]);
}
private static byte DecodeTuple(char _0, char _1)
{
return (byte)(DecodeChar(_0) << 4 | DecodeChar(_1));
static int DecodeChar(char x)
{
if (char.IsAsciiDigit(x))
return (byte)(x - '0');
if (char.IsAsciiHexDigitUpper(x))
return (byte)(x - 'A' + 10);
if (char.IsAsciiHexDigitLower(x))
return (byte)(x - 'a' + 10);
throw new ArgumentOutOfRangeException(nameof(_0));
}
}
}

View File

@ -1,4 +1,5 @@
using System.Net.Sockets;
using System;
using System.Net.Sockets;
using System.Threading;
namespace NHSE.Injection;
@ -60,7 +61,7 @@ public byte[] ReadBytes(uint offset, int length)
Thread.Sleep((length / 256) + 100);
var buffer = new byte[(length * 2) + 1];
_ = ReadInternal(buffer);
return Decoder.ConvertHexByteStringToBytes(buffer);
return Convert.FromHexString(buffer.AsSpan(0, buffer.Length - 1));
}
}

View File

@ -24,7 +24,7 @@ public bool Connect()
//SwDevice = UsbDevice.OpenUsbDevice(SwFinder);
foreach (UsbRegistry ur in UsbDevice.AllDevices)
{
if (ur.Vid == 1406 && ur.Pid == 12288)
if (ur is { Vid: 1406, Pid: 12288 })
SwDevice = ur.Device;
}
//SwDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
@ -144,7 +144,6 @@ public byte[] ReadBytes(uint offset, int length)
var buffer = new byte[length];
_ = ReadInternal(buffer);
//return Decoder.ConvertHexByteStringToBytes(buffer);
return buffer;
}
}

View File

@ -108,13 +108,15 @@ private static void LoadViewport(LayerItem layer, in LayerPositionConfig cfg, Sp
var tileY = relY + y;
for (int x = 0; x < width; x++)
{
var index = baseIndex + x;
var tileX = relX + x;
if (!cfg.IsCoordinateValidRelative(tileX, tileY))
{
data[index] = 0;
continue;
}
var tile = layer.GetTile(tileX, tileY);
var color = FieldItemColor.GetItemColor(tile).ToArgb();
var index = baseIndex + x;
data[index] = color;
}
}

View File

@ -115,14 +115,14 @@ public Bitmap UpdateViewportItems(int transparency)
/// <summary>
/// Updates the viewport terrain bitmap.
/// </summary>
/// <param name="f">Font to use for building labels.</param>
/// <param name="textFont">Font to use for building labels.</param>
/// <param name="transparencyBuilding">Transparency for building shapes drawn on terrain.</param>
/// <param name="transparencyTerrain">Transparency for terrain layer.</param>
/// <param name="selectedBuildingIndex">Index of building to highlight, or -1 for none.</param>
/// <returns></returns>
public Bitmap UpdateViewportTerrain(Font f, byte transparencyBuilding, byte transparencyTerrain, int selectedBuildingIndex = -1)
public Bitmap UpdateViewportTerrain(Font textFont, byte transparencyBuilding, byte transparencyTerrain, int selectedBuildingIndex = -1)
{
TerrainSprite.LoadViewport(ViewportTerrainImage, Map, f, ViewportTerrain1, ViewportTerrainX, selectedBuildingIndex, transparencyBuilding, transparencyTerrain);
TerrainSprite.LoadViewport(ViewportTerrainImage, Map, textFont, ViewportTerrain1, ViewportTerrainX, selectedBuildingIndex, transparencyBuilding, transparencyTerrain);
return ViewportTerrainImage;
}

View File

@ -12,7 +12,7 @@ public static class TerrainSprite
{
private static readonly Brush Selected = Brushes.Red;
private static readonly Brush Others = Brushes.Yellow;
private static readonly Brush Text = Brushes.White;
private static readonly Brush Text = Brushes.Black;
private static readonly Brush Tile = Brushes.Black;
private static readonly Brush Plaza = Brushes.RosyBrown;
private static readonly Color PlazaColor = Color.RosyBrown;
@ -75,8 +75,8 @@ public static Bitmap GetMapWithBuildings(Bitmap map, MapEditor m, Span<int> scal
using var gfx = Graphics.FromImage(map);
var plaza = m.Mutator.Manager.Plaza;
gfx.DrawMapPlaza(m, (ushort)plaza.X, (ushort)plaza.Z, imgScale);
gfx.DrawMapBuildings(m, m.Buildings.Buildings, imgScale, buildingIndex);
gfx.DrawMapPlaza((ushort)plaza.X, (ushort)plaza.Z, imgScale);
gfx.DrawMapBuildings(m.Buildings.Buildings, imgScale, buildingIndex);
return map;
}
@ -90,7 +90,7 @@ public static Bitmap GetMapWithBuildings(Bitmap map, MapEditor m, Span<int> scal
/// </remarks>
/// <param name="img">The bitmap onto which the viewport will be drawn.</param>
/// <param name="m">The map editor instance providing map data, building information, and viewport configuration.</param>
/// <param name="f">The font used to render building and terrain tile names within the viewport.</param>
/// <param name="textFont">The font used to render building and terrain tile names within the viewport.</param>
/// <param name="scale1">A span representing the primary scaling factors for rendering terrain pixels.</param>
/// <param name="scaleX">A span used for horizontal scaling and pixel data manipulation during rendering.</param>
/// <param name="selectedBuildingIndex">
@ -105,7 +105,7 @@ public static Bitmap GetMapWithBuildings(Bitmap map, MapEditor m, Span<int> scal
/// The transparency level to apply when rendering terrain tile names.
/// A value of 0xFF is fully opaque; lower values increase transparency.
/// </param>
public static void LoadViewport(Bitmap img, MapEditor m, Font f,
public static void LoadViewport(Bitmap img, MapEditor m, Font textFont,
Span<int> scale1, Span<int> scaleX,
int selectedBuildingIndex, byte transparencyBuilding, byte transTerrain)
{
@ -132,28 +132,35 @@ public static Bitmap GetMapWithBuildings(Bitmap map, MapEditor m, Span<int> scal
// Switch back to graphics mode
img.SetBitmapData(scaleX);
// Draw Text of Terrain Tile Names
if (transTerrain != 0)
gfx.DrawViewTerrainTileNames(m.Terrain, cfg, textFont, relX, relY, m.ViewScale * 2, transTerrain);
// Draw Text of Building Names
if (transparencyBuilding != 0)
gfx.DrawViewBuildingNames(m, textFont, transparencyBuilding);
// Done.
}
private static void DrawViewBuildingNames(this Graphics gfx, MapEditor m, Font textFont, byte transparency)
{
var brush = Text;
if (transparency != byte.MaxValue)
brush = new SolidBrush(Color.FromArgb(transparency, Color.Black));
foreach (var b in m.Buildings.Buildings)
{
var (x, y) = m.GetViewCoordinatesBuilding(b.X, b.Y);
const int cellsAbove = 2; // Show label above the building, 2 cells up.
const int cellsAbove = -2; // Show label inside the building square, 2 cells inside.
y -= (m.ViewScale * cellsAbove);
// Don't bother drawing if not in view.
if (!m.Mutator.View.IsWithinView(m.ViewScale, x, y))
continue;
var type = b.BuildingType;
var name = type.ToString();
var labelPosition = new PointF(x, y - (m.ViewScale * 2));
gfx.DrawString(name, f, Text, labelPosition, BuildingTextFormat);
gfx.DrawString(name, textFont, brush, labelPosition, BuildingTextFormat);
}
// Draw Text of Terrain Tile Names
if (transTerrain != 0)
gfx.DrawViewTerrainTileNames(m.Terrain, cfg, f, relX, relY, m.ViewScale * 2, transTerrain);
// Done.
}
private static void DrawViewBuildings(this Graphics gfx, MapEditor m, int selectedBuildingIndex, byte transBuild)
@ -170,7 +177,7 @@ private static void DrawViewBuildings(this Graphics gfx, MapEditor m, int select
var orig = ((SolidBrush)pen).Color;
pen = new SolidBrush(Color.FromArgb(transBuild, orig));
}
gfx.DrawViewBuilding(m, b, pen, m.ViewScale, Text);
gfx.DrawViewBuilding(m, b, pen, m.ViewScale);
}
}
@ -197,9 +204,36 @@ private static void LoadTerrainPixels(LayerTerrain mgr, LayerPositionConfig cfg,
pixels[offset] = color;
}
}
var mapHeight = cfg.MapTotalHeight;
// Render each exterior acre, just in case it was changed from a sea acre.
// If the acre (x,y) is a customizable terrain acre, skip it since we already did it above.
for (int y = 0; y < mapHeight; y += TileScale)
{
for (int x = 0; x < mapWidth; x += TileScale)
{
var (relX, relY) = cfg.GetCoordinatesRelative(x, y);
if (cfg.IsCoordinateValidRelative(relX, relY))
continue; // already done
// Render the acre template (usually sea).
var acreTemplate = mgr.GetAcreTemplate(relX, relY);
for (int tileY = 0; tileY < TileScale; tileY++)
{
for (int tileX = 0; tileX < TileScale; tileX++)
{
var color = AcreTileColor.GetAcreTileColor(acreTemplate, tileX, tileY);
if (color == -0x1000000) // transparent (dynamic)
color = Color.ForestGreen.ToArgb(); // just in case; it's invalid anyway.
var offset = ((y + tileY) * mapWidth) + (x + tileX);
pixels[offset] = color;
}
}
}
}
}
private static void DrawMapPlaza(this Graphics gfx, MapEditor map, ushort px, ushort py, int imgScale)
private static void DrawMapPlaza(this Graphics gfx, ushort px, ushort py, int imgScale)
{
var (x, y) = (px, py);
@ -209,7 +243,7 @@ private static void DrawMapPlaza(this Graphics gfx, MapEditor map, ushort px, us
gfx.FillRectangle(Plaza, x, y, width, height);
}
private static void DrawMapBuildings(this Graphics gfx, MapEditor m, IReadOnlyList<Building> buildings, int imgScale, int selectedBuildingIndex = -1)
private static void DrawMapBuildings(this Graphics gfx, IReadOnlyList<Building> buildings, int imgScale, int selectedBuildingIndex = -1)
{
for (int i = 0; i < buildings.Count; i++)
{
@ -223,8 +257,7 @@ private static void DrawMapBuildings(this Graphics gfx, MapEditor m, IReadOnlyLi
}
}
private static void DrawViewBuilding(this Graphics gfx, MapEditor m, Building b, Brush bBrush,
int imgScale, Brush textBrush, Font? textFont = null)
private static void DrawViewBuilding(this Graphics gfx, MapEditor m, Building b, Brush bBrush, int imgScale)
{
var (x, y) = m.GetViewCoordinatesBuilding(b.X, b.Y);
var type = b.BuildingType;
@ -234,14 +267,6 @@ private static void DrawMapBuildings(this Graphics gfx, MapEditor m, IReadOnlyLi
// Draw the building.
gfx.FillRectangle(bBrush, x, y, width * imgScale * 2, height * imgScale * 2);
if (textFont == null)
return;
// Draw the text label above it.
const int cellsAbove = 2;
var name = type.ToString();
gfx.DrawString(name, textFont, textBrush, new PointF(x, y - (imgScale * cellsAbove)), BuildingTextFormat);
}
private static void SetViewTerrainPixels(LayerTerrain t, LayerPositionConfig cfg, int relX, int relY, Span<int> data, Span<int> scaleX, int imgScale)
@ -255,18 +280,28 @@ private static void GetViewTerrain1(LayerTerrain t, LayerPositionConfig cfg, int
for (int tileY = 0; tileY < TilesPerViewport; tileY++)
{
var actY = tileY + relY;
for (int x = 0; x < TilesPerViewport; x++)
for (int tileX = 0; tileX < TilesPerViewport; tileX++)
{
var actX = relX + x;
var actX = relX + tileX;
var acreTemplate = t.GetAcreTemplate(actX, actY);
if (!cfg.IsCoordinateValidRelative(actX, actY))
{
// Fill tile's square with a solid color.
// Ensure coordinates are positive (for modulo later).
if (actX < 0)
actX += TilesPerViewport;
if (actY < 0)
actY += TilesPerViewport;
for (int pixelY = 0; pixelY < TileScale; pixelY++)
{
var index = (tileY * TileScale + pixelY) * (TilesPerViewport * TileScale) + x * TileScale;
var index = (tileY * TileScale + pixelY) * (TilesPerViewport * TileScale) + tileX * TileScale;
for (int pixelX = 0; pixelX < TileScale; pixelX++)
{
data[index] = ColorOcean;
var color = AcreTileColor.GetAcreTileColor(acreTemplate, actX % 16, actY % 16);
if (color == -0x1000000) // transparent (dynamic)
color = Color.ForestGreen.ToArgb(); // just in case; it's invalid anyway.
data[index] = color;
index++;
}
}
@ -274,11 +309,10 @@ private static void GetViewTerrain1(LayerTerrain t, LayerPositionConfig cfg, int
else
{
// Fill tile's square from terrain data.
var acreTemplate = t.GetAcreTemplate(actX, actY);
var tile = t.GetTile(actX, actY);
for (int pixelY = 0; pixelY < TileScale; pixelY++)
{
var index = (tileY * TileScale + pixelY) * (TilesPerViewport * TileScale) + x * TileScale;
var index = (tileY * TileScale + pixelY) * (TilesPerViewport * TileScale) + tileX * TileScale;
for (int pixelX = 0; pixelX < TileScale; pixelX++)
{
data[index] = t.GetTileColor(acreTemplate, tile, actX, actY, pixelX, pixelY);

View File

@ -26,37 +26,39 @@ public static class ImageUtil
extension(Bitmap bmp)
{
public Span<byte> GetBitmapData(out BitmapData bmpData, PixelFormat format = PixelFormat.Format32bppArgb, byte bpp = 4)
public Span<byte> GetBitmapData(out BitmapData bmpData)
{
var format = bmp.PixelFormat;
bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, format);
var bpp = Image.GetPixelFormatSize(format) / 8;
return GetSpan(bmpData.Scan0, bmp.Width * bmp.Height * bpp);
}
public void GetBitmapData(Span<byte> data, PixelFormat format = PixelFormat.Format32bppArgb, byte bpp = 4)
public void GetBitmapData(Span<byte> data)
{
var span = bmp.GetBitmapData(out var bmpData, format, bpp);
var span = bmp.GetBitmapData(out var bmpData);
span.CopyTo(data);
bmp.UnlockBits(bmpData);
}
public void GetBitmapData(Span<int> data, PixelFormat format = PixelFormat.Format32bppArgb, byte bpp = 4)
public void GetBitmapData(Span<int> data)
{
var span = bmp.GetBitmapData(out var bmpData, format, bpp);
var span = bmp.GetBitmapData(out var bmpData);
var src = MemoryMarshal.Cast<byte, int>(span);
src.CopyTo(data);
bmp.UnlockBits(bmpData);
}
public void SetBitmapData(ReadOnlySpan<byte> data, PixelFormat format = PixelFormat.Format32bppArgb, byte bpp = 4)
public void SetBitmapData(ReadOnlySpan<byte> data)
{
var span = bmp.GetBitmapData(out var bmpData, format, bpp);
var span = bmp.GetBitmapData(out var bmpData);
data.CopyTo(span);
bmp.UnlockBits(bmpData);
}
public void SetBitmapData(Span<int> data, PixelFormat format = PixelFormat.Format32bppArgb, byte bpp = 4)
public void SetBitmapData(Span<int> data)
{
var span = bmp.GetBitmapData(out var bmpData, format, bpp);
var span = bmp.GetBitmapData(out var bmpData);
var dest = MemoryMarshal.Cast<byte, int>(span);
data.CopyTo(dest);
bmp.UnlockBits(bmpData);
@ -78,13 +80,6 @@ public static Bitmap GetBitmap(ReadOnlySpan<byte> data, int width, int height, P
return bmp;
}
public static Bitmap GetBitmap(Span<byte> data, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb)
{
var bmp = new Bitmap(width, height, format);
bmp.SetBitmapData(data, format);
return bmp;
}
private static Span<byte> GetSpan(IntPtr ptr, int length)
=> MemoryMarshal.CreateSpan(ref Unsafe.AddByteOffset(ref Unsafe.NullRef<byte>(), ptr), length);

View File

@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.Linq;
using NHSE.Core;
using static NHSE.Villagers.Properties.Resources;
@ -35,6 +36,6 @@ public static VillagerData GetVillager(string villagerName)
Debug.Assert(bv.Length == Villager2.SIZE);
Debug.Assert(bh.Length == VillagerHouse2.SIZE);
return new VillagerData(bv, bh);
return new VillagerData(bv.ToArray(), bh.ToArray());
}
}

View File

@ -14,8 +14,8 @@ private static VillagerData AdaptVillager(VillagerInfo exist, VillagerData repla
{
var ov = exist.Villager;
var oh = exist.House;
var nv = new Villager2(replace.Villager.ToArray());
_ = new VillagerHouse1(replace.House.ToArray()) {NPC1 = oh.NPC1, NPC2 = oh.NPC2, BuildPlayer = oh.BuildPlayer};
var nv = new Villager2(replace.Villager);
_ = new VillagerHouse1(replace.House) {NPC1 = oh.NPC1, NPC2 = oh.NPC2, BuildPlayer = oh.BuildPlayer};
// Copy Memories
var om = nv.GetMemory(0);

View File

@ -0,0 +1,117 @@
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows.Forms;
namespace NHSE.WinForms;
/// <summary>
/// Application settings stored as JSON.
/// </summary>
public sealed class ApplicationSettings
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = true,
Converters = { new JsonStringEnumConverter() },
};
/// <summary>
/// Last opened save file path.
/// </summary>
public string LastFilePath { get; set; } = string.Empty;
/// <summary>
/// SysBot connection and RAM editing settings.
/// </summary>
public SysBotSettings SysBot { get; set; } = new();
/// <summary>
/// Whether to automatically backup save files.
/// </summary>
public bool AutomaticBackup { get; set; } = true;
/// <summary>
/// Whether the backup prompt has been shown.
/// </summary>
public bool BackupPrompted { get; set; }
/// <summary>
/// UI language code (e.g., "en", "de", "jp").
/// </summary>
public string Language { get; set; } = "en";
/// <summary>
/// Dark mode setting.
/// </summary>
public SystemColorMode DarkMode { get; set; } = SystemColorMode.System;
/// <summary>
/// Loads settings from disk, or creates default settings if the file doesn't exist.
/// </summary>
/// <param name="path">Full path to the settings file.</param>
public static ApplicationSettings Load(string path)
{
if (!File.Exists(path))
return new ApplicationSettings();
try
{
var json = File.ReadAllText(path);
return JsonSerializer.Deserialize<ApplicationSettings>(json, JsonOptions) ?? new ApplicationSettings();
}
catch
{
// If deserialization fails, return defaults
return new ApplicationSettings();
}
}
/// <summary>
/// Saves the current settings to disk.
/// </summary>
/// <param name="path">Full path to the settings file.</param>
public void Save(string path)
{
try
{
var json = JsonSerializer.Serialize(this, JsonOptions);
File.WriteAllText(path, json);
}
catch
{
// Silently fail if we can't save settings
}
}
}
/// <summary>
/// SysBot connection and RAM editing settings.
/// </summary>
public sealed class SysBotSettings
{
/// <summary>
/// SysBot IP address.
/// </summary>
public string IP { get; set; } = "192.168.0.1";
/// <summary>
/// SysBot port number.
/// </summary>
public int Port { get; set; } = 6000;
/// <summary>
/// Whether the SysBot prompt has been shown.
/// </summary>
public bool Prompted { get; set; }
/// <summary>
/// RAM offset for pouch editing.
/// </summary>
public uint PouchOffset { get; set; }
/// <summary>
/// RAM offset for generic editing.
/// </summary>
public uint GenericOffset { get; set; }
}

View File

@ -63,7 +63,7 @@ private void InitializeComponent()
// AchievementRow
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.AutoSize = true;
this.Controls.Add(this.L_Threshold);
this.Controls.Add(this.CHK_Read);

View File

@ -921,7 +921,7 @@ private void InitializeComponent()
// ItemEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.Controls.Add(this.FLP_Controls);
this.Name = "ItemEditor";
this.Size = new System.Drawing.Size(222, 681);

View File

@ -33,7 +33,7 @@ private void InitializeComponent()
// ItemGrid
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.Name = "ItemGrid";
this.ResumeLayout(false);

View File

@ -305,7 +305,7 @@ private void InitializeComponent()
// ItemGridEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.Controls.Add(this.FLP_Controls);
this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.Name = "ItemGridEditor";

View File

@ -79,7 +79,7 @@ private void InitializeComponent()
// RestrictedItemSelect
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.Controls.Add(this.CHK_CustomItem);
this.Controls.Add(this.NUD_CustomItem);
this.Controls.Add(this.CB_ItemID);

View File

@ -349,7 +349,7 @@ private void InitializeComponent()
// VillagerEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.Controls.Add(this.B_ReplaceVillager);
this.Controls.Add(this.B_SetPhraseOriginal);
this.Controls.Add(this.B_EditHouses);

View File

@ -286,13 +286,14 @@ private void B_ReplaceVillager_Click(object sender, EventArgs e)
return;
}
var internalName = Clipboard.GetText();
var internalName = Clipboard.GetText().Trim();
if (!VillagerResources.IsVillagerDataKnown(internalName))
{
var clip = internalName;
internalName = GameInfo.Strings.VillagerMap.FirstOrDefault(z => string.Equals(z.Value, internalName, StringComparison.InvariantCultureIgnoreCase)).Key;
if (internalName is null)
{
WinFormsUtil.Error(string.Format(MessageStrings.MsgVillagerReplaceUnknownName, internalName));
WinFormsUtil.Error(string.Format(MessageStrings.MsgVillagerReplaceUnknownName, clip));
return;
}
}

View File

@ -914,7 +914,7 @@ private void InitializeComponent()
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
MaximizeBox = false;
Name = "Editor";
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "NHSE";
Menu_Editor.ResumeLayout(false);
Menu_Editor.PerformLayout();

View File

@ -1,7 +1,6 @@
using NHSE.Core;
using NHSE.Injection;
using NHSE.Sprites;
using NHSE.WinForms.Properties;
using System;
using System.Drawing;
using System.Drawing.Imaging;
@ -24,8 +23,6 @@ public sealed partial class Editor : Form
public Editor(HorizonSave file)
{
WinFormsUtil.SetApplicationTheme(int.Parse(Settings.Default.DarkMode));
InitializeComponent();
SAV = file;
@ -35,7 +32,7 @@ public Editor(HorizonSave file)
LoadMain();
var lang = Settings.Default.Language;
var lang = Program.Settings.Language;
var index = GameLanguage.GetLanguageIndex(lang);
Menu_Language.SelectedIndex = index; // triggers translation
// this.TranslateInterface(GameInfo.CurrentLanguage);
@ -43,6 +40,12 @@ public Editor(HorizonSave file)
Text = SAV.GetSaveTitle("NHSE");
}
protected override void OnLoad(EventArgs e)
{
CenterToParent();
base.OnLoad(e);
}
private void Menu_Settings_Click(object sender, EventArgs e)
{
using var editor = new SettingsEditor();
@ -57,9 +60,7 @@ private void Menu_Language_SelectedIndexChanged(object sender, EventArgs e)
var lang = GameInfo.SetLanguage2Char(Menu_Language.SelectedIndex);
this.TranslateInterface(lang);
var settings = Settings.Default;
settings.Language = lang;
settings.Save();
Program.Settings.Language = lang;
Task.Run(() =>
{
@ -139,12 +140,13 @@ private void Menu_RAMEdit_Click(object sender, EventArgs e)
var exist = WinFormsUtil.FirstFormOfType<SysBotRAMEdit>();
if (exist != null)
{
exist.Show();
exist.Show(this);
exist.BringToFront();
return;
}
var sysbot = new SysBotRAMEdit(InjectionType.Generic);
sysbot.Show();
sysbot.Show(this);
}
private void Menu_Sync_Click(object sender, EventArgs e)
@ -162,37 +164,38 @@ private void Menu_ItemImages_Click(object sender, EventArgs e)
var exist = WinFormsUtil.FirstFormOfType<ImageFetcher>();
if (exist != null)
{
exist.Show();
exist.Show(this);
exist.BringToFront();
return;
}
var imgfetcher = new ImageFetcher();
imgfetcher.Show();
imgfetcher.Show(this);
}
private void Menu_Theme_System_Click(object sender, EventArgs e)
{
Menu_Options.DropDown.Close();
ThemeChangeDialog(1);
ThemeChangeDialog(SystemColorMode.System);
}
private void Menu_Theme_Classic_Click(object sender, EventArgs e)
{
Menu_Options.DropDown.Close();
ThemeChangeDialog(0);
ThemeChangeDialog(SystemColorMode.Classic);
}
private void Menu_Theme_Dark_Click(object sender, EventArgs e)
{
Menu_Options.DropDown.Close();
ThemeChangeDialog(2);
ThemeChangeDialog(SystemColorMode.Dark);
}
private void ThemeChangeDialog(int theme)
private void ThemeChangeDialog(SystemColorMode theme)
{
TaskDialogButton yesButton = new(MessageStrings.MsgDialogButtonYes) { Tag = DialogResult.Yes };
TaskDialogButton noButton = new(MessageStrings.MsgDialogButtonNo) { Tag = DialogResult.No };
TaskDialogButton cancelButton = new(MessageStrings.MsgDialogButtonCancel) { Tag = DialogResult.Cancel };
var yesButton = new TaskDialogButton(MessageStrings.MsgDialogButtonYes) { Tag = DialogResult.Yes };
var noButton = new TaskDialogButton(MessageStrings.MsgDialogButtonNo) { Tag = DialogResult.No };
var cancelButton = new TaskDialogButton(MessageStrings.MsgDialogButtonCancel) { Tag = DialogResult.Cancel };
var buttons = new TaskDialogButtonCollection
{
yesButton,
@ -209,7 +212,7 @@ private void ThemeChangeDialog(int theme)
Buttons = buttons
};
TaskDialogButton resultButton = TaskDialog.ShowDialog(this, page);
var resultButton = TaskDialog.ShowDialog(this, page);
if (resultButton == yesButton)
{
SaveAll();
@ -223,14 +226,19 @@ private void ThemeChangeDialog(int theme)
return;
}
WinFormsUtil.Alert(MessageStrings.MsgSaveDataExportSuccess);
WinFormsUtil.SetApplicationTheme(theme);
Application.Restart();
}
else if (resultButton == noButton)
{
WinFormsUtil.SetApplicationTheme(theme);
Application.Restart();
// Don't save.
}
else
{
// Abort
return;
}
Program.Settings.DarkMode = theme;
Program.SaveSettings();
Application.Restart();
}
private void ReloadAll()

View File

@ -45,6 +45,8 @@ private void InitializeComponent()
// Main
//
AllowDrop = true;
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
ClientSize = new System.Drawing.Size(306, 121);
Controls.Add(B_Open);
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;

View File

@ -1,11 +1,9 @@
using System;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using NHSE.Core;
using NHSE.Injection;
using NHSE.Sprites;
using NHSE.WinForms.Properties;
namespace NHSE.WinForms;
@ -14,16 +12,8 @@ namespace NHSE.WinForms;
/// </summary>
public partial class Main : Form
{
public const string BackupFolderName = "bak";
public const string ItemFolderName = "items";
public static readonly string WorkingDirectory = Application.StartupPath;
public static readonly string BackupPath = Path.Combine(WorkingDirectory, BackupFolderName);
public static readonly string ItemPath = Path.Combine(WorkingDirectory, ItemFolderName);
public Main()
{
WinFormsUtil.SetApplicationTheme(int.Parse(Settings.Default.DarkMode));
InitializeComponent();
// Flash to front
@ -32,32 +22,18 @@ public Main()
Show();
WindowState = FormWindowState.Normal;
var args = Environment.GetCommandLineArgs();
var args = Environment.GetCommandLineArgs().AsSpan(1); // skip exe path
foreach (var arg in args)
{
if (Directory.Exists(arg))
Open(arg);
if (Directory.Exists(arg) || File.Exists(arg))
TryOpenSaveFile(arg);
}
}
private static void Open(HorizonSave file)
protected override void OnFormClosing(FormClosingEventArgs e)
{
bool sized = file.ValidateSizes();
if (!sized)
{
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MessageStrings.MsgSaveDataSizeMismatch, MessageStrings.MsgAskContinue);
if (prompt != DialogResult.Yes)
return;
}
var isAnyHashBad = file.GetInvalidHashes().Any();
if (isAnyHashBad)
{
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MessageStrings.MsgSaveDataHashMismatch, MessageStrings.MsgAskContinue);
if (prompt != DialogResult.Yes)
return;
}
new Editor(file).Show();
Program.SaveSettings();
base.OnFormClosing(e);
}
private void Main_DragEnter(object sender, DragEventArgs e)
@ -71,9 +47,9 @@ private void Main_DragEnter(object sender, DragEventArgs e)
private void Main_DragDrop(object sender, DragEventArgs e)
{
var files = (string[]?)e.Data?.GetData(DataFormats.FileDrop);
if (files == null || files.Length == 0)
if (files is not { Length: not 0 })
return;
Open(files[0]);
TryOpenSaveFile(files[0]);
e.Effect = DragDropEffects.Copy;
}
@ -85,10 +61,10 @@ private void Menu_Open(object sender, EventArgs e)
}
else if ((ModifierKeys & Keys.Shift) != 0)
{
var path = Settings.Default.LastFilePath;
var path = Program.Settings.LastFilePath;
if (Directory.Exists(path))
{
Open(path);
TryOpenSaveFile(path);
return;
}
}
@ -98,81 +74,7 @@ private void Menu_Open(object sender, EventArgs e)
ofd.Filter = "New Horizons Save File (main.dat)|main.dat";
ofd.FileName = "main.dat";
if (ofd.ShowDialog() == DialogResult.OK)
Open(ofd.FileName);
}
private static void Open(string path)
{
#if !DEBUG
try
#endif
{
OpenFileOrPath(path);
}
#if !DEBUG
catch (Exception ex)
{
WinFormsUtil.Error(ex.Message);
}
#endif
}
private static void OpenFileOrPath(string path)
{
if (Directory.Exists(path))
{
OpenSaveFile(path);
return;
}
// Load zip files differently
var ext = Path.GetExtension(path);
if (ext.Equals(".zip", StringComparison.OrdinalIgnoreCase) && new FileInfo(path).Length < 20 * 1024 * 1024) // less than 20MB
{
var file = HorizonSave.FromZip(path);
Open(file);
return;
}
var dir = Path.GetDirectoryName(path);
if (dir is null || !Directory.Exists(dir)) // ya never know
{
WinFormsUtil.Error(MessageStrings.MsgSaveDataImportFail, MessageStrings.MsgSaveDataImportSuggest);
return;
}
OpenSaveFile(dir);
}
private static void OpenSaveFile(string path)
{
var file = HorizonSave.FromFolder(path);
Open(file);
var settings = Settings.Default;
settings.LastFilePath = path;
if (!settings.BackupPrompted)
{
settings.BackupPrompted = true;
var line1 = string.Format(MessageStrings.MsgBackupCreateLocation, BackupFolderName);
var line2 = MessageStrings.MsgBackupCreateQuestion;
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, line1, line2);
settings.AutomaticBackup = prompt == DialogResult.Yes;
}
if (settings.AutomaticBackup)
BackupSaveFile(file, path, BackupPath);
settings.Save();
}
private static void BackupSaveFile(HorizonSave file, string path, string bak)
{
Directory.CreateDirectory(bak);
var dest = Path.Combine(bak, file.GetBackupFolderTitle());
if (!Directory.Exists(dest))
FileUtil.CopyFolder(path, dest);
TryOpenSaveFile(ofd.FileName);
}
private void Main_KeyDown(object sender, KeyEventArgs e)
@ -217,4 +119,13 @@ private void Main_KeyDown(object sender, KeyEventArgs e)
}
}
}
private bool TryOpenSaveFile(string path)
{
if (!SaveFileLoader.TryGetSaveFile(path, out var sav))
return false;
var editor = new Editor(sav);
editor.Show(this);
return true;
}
}

View File

@ -26,11 +26,6 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>

View File

@ -1,31 +1,158 @@
using NHSE.WinForms.Properties;
using System;
using System;
using System.IO;
using System.Windows.Forms;
#if !DEBUG
using System.Diagnostics.CodeAnalysis;
using System.Threading;
#endif
namespace NHSE.WinForms;
internal static class Program
{
/// <summary>
/// Directory where the executable is located.
/// </summary>
public static readonly string WorkingDirectory = Path.GetDirectoryName(Environment.ProcessPath) ?? "";
/// <summary>
/// Settings file name.
/// </summary>
private const string ConfigFileName = "settings.json";
/// <summary>
/// Full path to the settings file.
/// </summary>
private static string PathConfig => Path.Combine(WorkingDirectory, ConfigFileName);
/// <summary>
/// Application settings, loaded at startup.
/// </summary>
public static ApplicationSettings Settings { get; }
/// <summary>
/// Static constructor to load settings as early as possible.
/// </summary>
static Program()
{
#if !DEBUG
Application.ThreadException += UIThreadException;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
#endif
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Settings = ApplicationSettings.Load(PathConfig);
Application.SetColorMode(Settings.DarkMode);
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
private static void Main() => Application.Run(new Main());
var args = Environment.GetCommandLineArgs();
if (args.Length > 1)
public static void SaveSettings() => Settings.Save(PathConfig);
#if !DEBUG
private static void Error(string msg) => MessageBox.Show(msg, "NHSE Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
private static void UIThreadException(object sender, ThreadExceptionEventArgs t)
{
DialogResult result;
try
{
if (args.Contains("-dark"))
{
WinFormsUtil.SetApplicationTheme(2);
Settings.Default.DarkMode = "2";
Settings.Default.Save();
}
var e = t.Exception;
string errorMessage = GetErrorMessage(e);
Error(errorMessage);
result = DialogResult.OK;
}
catch (Exception reportingException)
{
HandleReportingException(t.Exception, reportingException);
result = DialogResult.Abort;
}
Application.Run(new Main());
if (result == DialogResult.Abort)
Application.Exit();
}
private static string GetErrorMessage(Exception e)
{
Console.WriteLine(e);
return e.StackTrace ?? e.Message;
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = e.ExceptionObject as Exception;
try
{
if (IsCoreMissing(ex))
{
Error("You have installed NHSE incorrectly. Please ensure you have unzipped all files before running.");
}
else if (ex is not null)
{
Error(GetErrorMessage(ex));
}
else
{
Error("A fatal non-UI error has occurred in NHSE, and the details could not be displayed. Please report this to the author.");
}
}
catch (Exception reportingException)
{
HandleReportingException(ex, reportingException);
}
}
private static void HandleReportingException(Exception? ex, Exception reportingException)
{
try
{
EmergencyErrorLog(ex, reportingException);
}
catch
{
// Ignore.
}
if (reportingException is FileNotFoundException x && x.FileName?.StartsWith("NHSE.Core") == true)
{
Error("Could not locate NHSE.Core.dll. Make sure you're running NHSE together with its code library. Usually caused when all files are not extracted.");
return;
}
try
{
Error("A fatal non-UI error has occurred in NHSE, and there was a problem displaying the details. Please report this to the author.");
}
finally
{
Application.Exit();
}
}
private static bool EmergencyErrorLog(Exception? originalException, Exception errorHandlingException)
{
try
{
var message = (originalException?.ToString() ?? "null first exception") + Environment.NewLine + errorHandlingException;
File.WriteAllText($"NHSE_Error_Report {DateTime.Now:yyyyMMddHHmmss}.txt", message);
}
catch (Exception ex)
{
Console.WriteLine(errorHandlingException);
Console.WriteLine(ex);
return false;
}
return true;
}
private static bool IsCoreMissing([NotNullWhen(true)] Exception? ex)
{
return ex is FileNotFoundException { FileName: { } n } && n.Contains("NHSE.Core");
}
#endif
}

View File

@ -1,149 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace NHSE.WinForms.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string LastFilePath {
get {
return ((string)(this["LastFilePath"]));
}
set {
this["LastFilePath"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("192.168.0.1")]
public string SysBotIP {
get {
return ((string)(this["SysBotIP"]));
}
set {
this["SysBotIP"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("6000")]
public int SysBotPort {
get {
return ((int)(this["SysBotPort"]));
}
set {
this["SysBotPort"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool SysBotPrompted {
get {
return ((bool)(this["SysBotPrompted"]));
}
set {
this["SysBotPrompted"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public uint SysBotPouchOffset {
get {
return ((uint)(this["SysBotPouchOffset"]));
}
set {
this["SysBotPouchOffset"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public uint SysBotGenericOffset {
get {
return ((uint)(this["SysBotGenericOffset"]));
}
set {
this["SysBotGenericOffset"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool AutomaticBackup {
get {
return ((bool)(this["AutomaticBackup"]));
}
set {
this["AutomaticBackup"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool BackupPrompted {
get {
return ((bool)(this["BackupPrompted"]));
}
set {
this["BackupPrompted"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("en")]
public string Language {
get {
return ((string)(this["Language"]));
}
set {
this["Language"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("1")]
public string DarkMode
{
get
{
return ((string)(this["DarkMode"]));
}
set
{
this["DarkMode"] = value;
}
}
}
}

View File

@ -1,33 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="NHSE.WinForms.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="LastFilePath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="SysBotIP" Type="System.String" Scope="User">
<Value Profile="(Default)">192.168.0.1</Value>
</Setting>
<Setting Name="SysBotPort" Type="System.Int32" Scope="User">
<Value Profile="(Default)">6000</Value>
</Setting>
<Setting Name="SysBotPrompted" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="SysBotPouchOffset" Type="System.UInt32" Scope="User">
<Value Profile="(Default)">2890343376</Value>
</Setting>
<Setting Name="SysBotGenericOffset" Type="System.UInt32" Scope="User">
<Value Profile="(Default)">2890343376</Value>
</Setting>
<Setting Name="AutomaticBackup" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="BackupPrompted" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="Language" Type="System.String" Scope="User">
<Value Profile="(Default)">en</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -0,0 +1,138 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using NHSE.Core;
namespace NHSE.WinForms;
/// <summary>
/// Loader for <see cref="HorizonSave"/> files.
/// </summary>
public static class SaveFileLoader
{
private const string BackupFolderName = "bak";
private static string BackupPath => Path.Combine(Program.WorkingDirectory, BackupFolderName);
/// <summary>
/// Attempts to load a <see cref="HorizonSave"/> file from the specified path.
/// </summary>
/// <param name="path">The file system path to the save file to load.</param>
/// <param name="sav">When this method returns, contains the initialized save file if the operation succeeds.</param>
/// <returns><see langword="true"/> if the save file was loaded successfully; otherwise, <see langword="false"/>.</returns>
public static bool TryGetSaveFile(string path, [NotNullWhen(true)] out HorizonSave? sav)
{
#if !DEBUG
try
#endif
{
return TryGetSaveFileInternal(path, out sav);
}
#if !DEBUG
catch (Exception ex)
{
sav = null;
WinFormsUtil.Error(ex.Message);
return false;
}
#endif
}
private static bool TryGetSaveFileInternal(string path, [NotNullWhen(true)] out HorizonSave? sav)
{
if (Directory.Exists(path))
return OpenSaveFile(path, out sav);
// Load zip files differently
var ext = Path.GetExtension(path);
if (ext.Equals(".zip", StringComparison.OrdinalIgnoreCase))
{
var length = new FileInfo(path).Length;
const int maxSize = 20 * 1024 * 1024;
if (length < maxSize)
{
sav = HorizonSave.FromZip(path);
return TryValidateSaveFile(sav);
}
}
// Try loading from the parent folder if it's the .dat file
else if (ext.Equals(".dat", StringComparison.OrdinalIgnoreCase))
{
var dir = Path.GetDirectoryName(path);
if (Directory.Exists(dir))
return OpenSaveFile(dir, out sav);
}
// Nice try, we failed.
WinFormsUtil.Error(MessageStrings.MsgSaveDataImportFail, MessageStrings.MsgSaveDataImportSuggest);
sav = null;
return false;
}
private static bool OpenSaveFile(string path, [NotNullWhen(true)] out HorizonSave? sav)
{
sav = HorizonSave.FromFolder(path);
if (!TryValidateSaveFile(sav))
return false;
var settings = Program.Settings;
settings.LastFilePath = path;
CheckBackupPrompt(settings);
if (settings.AutomaticBackup)
BackupSaveFile(sav, path, BackupPath);
return true;
}
private static void CheckBackupPrompt(ApplicationSettings settings)
{
if (settings.BackupPrompted)
return;
settings.BackupPrompted = true;
if (Directory.Exists(BackupFolderName))
{
settings.AutomaticBackup = true; // previously enabled, settings reset?
return;
}
// Prompt user to enable automatic backups
settings.AutomaticBackup = PromptBackupEnable(BackupFolderName);
}
private static bool PromptBackupEnable(string destFolder)
{
var line1 = string.Format(MessageStrings.MsgBackupCreateLocation, destFolder);
var line2 = MessageStrings.MsgBackupCreateQuestion;
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, line1, line2);
return prompt == DialogResult.Yes;
}
private static bool TryValidateSaveFile(HorizonSave file)
{
if (!file.ValidateSizes())
{
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MessageStrings.MsgSaveDataSizeMismatch, MessageStrings.MsgAskContinue);
if (prompt != DialogResult.Yes)
return false;
}
if (file.GetInvalidHashes().Any())
{
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MessageStrings.MsgSaveDataHashMismatch, MessageStrings.MsgAskContinue);
if (prompt != DialogResult.Yes)
return false;
}
return true;
}
private static void BackupSaveFile(HorizonSave file, string path, string bak)
{
Directory.CreateDirectory(bak);
var dest = Path.Combine(bak, file.GetBackupFolderTitle());
if (!Directory.Exists(dest))
FileUtil.CopyFolder(path, dest);
}
}

View File

@ -81,7 +81,7 @@ private void InitializeComponent()
// BuildingHelp
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(251, 107);
this.Controls.Add(this.L_StructureValues);
this.Controls.Add(this.CB_StructureValues);
@ -91,7 +91,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "BuildingHelp";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Building Help";
this.ResumeLayout(false);
this.PerformLayout();

View File

@ -223,7 +223,7 @@ private void InitializeComponent()
// BulkSpawn
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(136, 235);
this.Controls.Add(this.CB_SpawnArrange);
this.Controls.Add(this.L_DIYStop);
@ -245,7 +245,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "BulkSpawn";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Bulk Spawn";
((System.ComponentModel.ISupportInitialize)(this.NUD_SpawnX)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_SpawnY)).EndInit();

View File

@ -248,7 +248,7 @@ private void InitializeComponent()
Icon = Properties.Resources.icon;
MaximizeBox = false;
Name = "CampsiteEditor";
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "Campsite Editor";
((System.ComponentModel.ISupportInitialize)PB_Villager).EndInit();
((System.ComponentModel.ISupportInitialize)NUD_Variant).EndInit();

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,8 @@
using System;
using NHSE.Core;
using NHSE.Sprites;
using NHSE.WinForms.Subforms.Map;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
@ -6,9 +10,6 @@
using System.IO;
using System.Linq;
using System.Windows.Forms;
using NHSE.Core;
using NHSE.Sprites;
using NHSE.WinForms.Subforms.Map;
namespace NHSE.WinForms;
@ -237,16 +238,23 @@ private void OmniTileTerrain(MouseEventArgs e)
List<TerrainTile> selectedTiles = [];
int radius = tbeForm.Slider_thickness.Value;
int threshold = (radius * radius) / 2;
var cfg = Editor.Mutator.Manager.ConfigTerrain;
for (int i = -radius; i < radius; i++)
{
for (int j = -radius; j < radius; j++)
{
if ((i * i) + (j * j) < threshold)
selectedTiles.Add(Editor.Terrain.GetTile(relX + i, relY + j));
{
var x = relX + i;
var y = relY + j;
if (cfg.IsCoordinateValidRelative(x, y))
selectedTiles.Add(Editor.Terrain.GetTile(x, y));
}
}
}
SetTiles(selectedTiles);
if (selectedTiles.Count != 0)
SetTiles(selectedTiles);
}
private void OmniTile(Item tile, int relX, int relY)
@ -349,7 +357,7 @@ private bool GetTile(MouseEventArgs e, LayerTerrain layerField, [NotNullWhen(tru
private bool GetTile(LayerTerrain layerField, int absX, int absY, [NotNullWhen(true)] out TileCheck<TerrainTile>? item)
{
var cfg = Editor.Mutator.Manager.ConfigItems;
var cfg = Editor.Mutator.Manager.ConfigTerrain;
var (relX, relY) = cfg.GetCoordinatesRelative(absX, absY);
if (!cfg.IsCoordinateValidRelative(relX, relY))
{
@ -375,17 +383,21 @@ private void UpdateHoveredCoordinates(MouseEventArgs e)
private void ViewportMouseMove(object sender, MouseEventArgs e)
{
var l = CurrentLayer;
if (e.Button == MouseButtons.Left && CHK_MoveOnDrag.Checked)
if (e.Button == MouseButtons.Left)
{
MoveDrag(e);
return;
}
if (e.Button == MouseButtons.Left && tbeForm?.IsBrushSelected == true)
{
OmniTileTerrain(e);
if (tbeForm?.IsBrushSelected == true)
{
OmniTileTerrain(e);
return;
}
if (CHK_MoveOnDrag.Checked)
{
MoveDrag(e);
return;
}
}
var l = CurrentLayer;
// Update hover tooltip if it is a different tile
// Can't compare coordinates if redirection of extension tiles hijacks to return the root tile.
// Just check the (root) tile returns for each.
@ -642,22 +654,31 @@ private void B_Save_Click(object sender, EventArgs e)
private void Menu_View_Click(object sender, EventArgs e)
{
var (absX, absY) = GetAbsoluteCoordinatesHover();
var cfg = Editor.Mutator.Manager.ConfigItems;
var (relX, relY) = cfg.GetCoordinatesRelative(absX, absY);
if (!cfg.IsCoordinateValidRelative(relX, relY))
{
System.Media.SystemSounds.Asterisk.Play();
return;
}
if (RB_Item.Checked)
{
var (absX, absY) = GetAbsoluteCoordinatesHover();
var cfg = Editor.Mutator.Manager.ConfigItems;
var (relX, relY) = cfg.GetCoordinatesRelative(absX, absY);
if (!cfg.IsCoordinateValidRelative(relX, relY))
{
System.Media.SystemSounds.Asterisk.Play();
return;
}
var tile = CurrentLayer.GetTile(relX, relY);
ViewTile(tile, relX, relY);
}
else if (RB_Terrain.Checked)
{
var (absX, absY) = GetAbsoluteCoordinatesHoverTerrain();
var cfg = Editor.Mutator.Manager.ConfigTerrain;
var (relX, relY) = cfg.GetCoordinatesRelative(absX, absY);
if (!cfg.IsCoordinateValidRelative(relX, relY))
{
System.Media.SystemSounds.Asterisk.Play();
return;
}
var tile = Editor.Terrain.GetTile(relX, relY);
ViewTile(tile);
}
@ -752,6 +773,9 @@ private void CM_Click_Opening(object sender, System.ComponentModel.CancelEventAr
private void Menu_Activate_Click(object sender, EventArgs e)
{
if (!RB_Item.Checked) // not in Item edit mode, therefore no "Activate Flag" menu
return;
var (absX, absY) = GetAbsoluteCoordinatesHover();
var cfg = Editor.Mutator.Manager.ConfigItems;
var (relX, relY) = cfg.GetCoordinatesRelative(absX, absY);
@ -821,6 +845,19 @@ private void B_ImportAllAcres_Click(object sender, EventArgs e)
System.Media.SystemSounds.Asterisk.Play();
}
private void B_DumpAllAcresFlag_Click(object sender, EventArgs e)
=> MapDumpHelper.DumpLayerAllFlag(Editor.Mutator.CurrentLayerFlags, Editor.Mutator.ItemLayerIndex);
private void B_ImportAllAcresFlag_Click(object sender, EventArgs e)
{
var layer = Editor.Mutator.CurrentLayerFlags;
var index = Editor.Mutator.ItemLayerIndex;
if (!MapDumpHelper.ImportToLayerAllFlag(layer, index))
return;
ChangeViewToAcre(ExteriorAcreIndex);
System.Media.SystemSounds.Asterisk.Play();
}
private void B_DumpBuildings_Click(object sender, EventArgs e) => MapDumpHelper.DumpBuildings(Editor.Buildings.Buildings);
private void B_ImportBuildings_Click(object sender, EventArgs e)
@ -1235,14 +1272,13 @@ private void Menu_Bulk_Click(object sender, EventArgs e)
private void B_TerrainBrush_Click(object sender, EventArgs e)
{
tbeForm = new TerrainBrushEditor(PG_TerrainTile, this);
tbeForm.Show();
if (tbeForm is null || tbeForm.IsDisposed)
tbeForm = new TerrainBrushEditor(PG_TerrainTile, this);
tbeForm.Show(this);
tbeForm.BringToFront();
}
private void FieldItemEditor_FormClosed(object sender, FormClosedEventArgs e)
{
tbeForm?.Close();
}
private void FieldItemEditor_FormClosed(object sender, FormClosedEventArgs e) => tbeForm?.Close();
}
public interface IItemLayerEditor

View File

@ -129,12 +129,12 @@
<metadata name="CM_Remove.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>465, 17</value>
</metadata>
<metadata name="CM_DLField.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>620, 17</value>
</metadata>
<metadata name="CM_DLBuilding.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>930, 17</value>
</metadata>
<metadata name="CM_DLField.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>620, 17</value>
</metadata>
<metadata name="CM_DLMapAcres.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 56</value>
</metadata>

View File

@ -159,7 +159,7 @@ private void InitializeComponent()
Icon = Properties.Resources.icon;
MaximizeBox = false;
Name = "FruitsFlowersEditor";
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "Fruits Flowers Editor";
ResumeLayout(false);
PerformLayout();

View File

@ -126,7 +126,7 @@ private void InitializeComponent()
// LandFlagEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.B_Load);
this.Controls.Add(this.B_Dump);
@ -139,7 +139,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "LandFlagEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Flag Editor";
((System.ComponentModel.ISupportInitialize)(this.NUD_Count)).EndInit();
this.ResumeLayout(false);

View File

@ -190,7 +190,7 @@ public static bool ImportBuildings(IReadOnlyList<Building> buildings)
const int expect = Building.SIZE * MainSaveOffsets.BuildingCount; // 46
const int oldSize = Building.SIZE * 40;
if (fi.Length != expect && fi.Length != oldSize)
if (fi.Length is not (expect or oldSize))
{
WinFormsUtil.Error(string.Format(MessageStrings.MsgDataSizeMismatchImport, fi.Length, expect));
return false;
@ -237,4 +237,43 @@ public static bool ImportMapAcresAll(Span<byte> data)
modified.CopyTo(data);
return true;
}
public static bool DumpLayerAllFlag(ILayerFieldItemFlag layer, uint layerIndex)
{
using var sfd = new SaveFileDialog();
sfd.Filter = "New Horizons Field Item Layer Flags (*.nhlf)|*.nhl|All files (*.*)|*.*";
sfd.FileName = $"flags-{layerIndex}.nhlf";
if (sfd.ShowDialog() != DialogResult.OK)
return false;
var data = layer.ExistingData;
File.WriteAllBytes(sfd.FileName, data);
return true;
}
public static bool ImportToLayerAllFlag(ILayerFieldItemFlag layer, uint layerIndex)
{
using var ofd = new OpenFileDialog();
ofd.Filter = "New Horizons Field Item Layer Flags (*.nhlf)|*.nhl|All files (*.*)|*.*";
ofd.FileName = $"flags-{layerIndex}.nhlf";
if (ofd.ShowDialog() != DialogResult.OK)
return false;
var path = ofd.FileName;
var fi = new FileInfo(path);
var exist = layer.ExistingData;
var expect = exist.Length;
if (fi.Length != expect && !FieldItemUpgrade.IsUpdateNeeded(fi.Length, expect))
{
WinFormsUtil.Error(string.Format(MessageStrings.MsgDataSizeMismatchImport, fi.Length, expect));
return false;
}
var data = File.ReadAllBytes(path);
FieldItemUpgrade.DetectUpdate(ref data, expect);
layer.Import(data);
return true;
}
}

View File

@ -173,7 +173,7 @@ private void InitializeComponent()
// MuseumEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(444, 417);
this.Controls.Add(this.B_Tools);
this.Controls.Add(this.ItemEdit);
@ -187,7 +187,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "MuseumEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Flag Editor";
((System.ComponentModel.ISupportInitialize)(this.NUD_Player)).EndInit();
this.CM_Tools.ResumeLayout(false);

View File

@ -179,7 +179,7 @@ private void InitializeComponent()
// PatternEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(592, 328);
this.Controls.Add(this.PB_Palette);
this.Controls.Add(this.L_PatternName);
@ -192,7 +192,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PatternEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Pattern Editor";
((System.ComponentModel.ISupportInitialize)(this.PB_Palette)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.PB_Pattern)).EndInit();

View File

@ -218,7 +218,7 @@ private void InitializeComponent()
// PatternEditorPRO
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(592, 328);
this.Controls.Add(this.PB_Sheet3);
this.Controls.Add(this.PB_Sheet2);
@ -234,7 +234,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PatternEditorPRO";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Pro Design Editor";
((System.ComponentModel.ISupportInitialize)(this.PB_Palette)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.PB_Sheet0)).EndInit();

View File

@ -323,7 +323,7 @@ private void InitializeComponent()
// PlayerHouseEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(1051, 577);
this.Controls.Add(this.B_LoadRoom);
this.Controls.Add(this.B_DumpRoom);
@ -349,7 +349,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PlayerHouseEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Player House Editor";
((System.ComponentModel.ISupportInitialize)(this.PB_Room)).EndInit();
this.CM_Click.ResumeLayout(false);

View File

@ -126,7 +126,7 @@ private void InitializeComponent()
// PlayerHouseFlagEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.B_Load);
this.Controls.Add(this.B_Dump);
@ -139,7 +139,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PlayerHouseFlagEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Flag Editor";
((System.ComponentModel.ISupportInitialize)(this.NUD_Count)).EndInit();
this.ResumeLayout(false);

View File

@ -694,7 +694,7 @@ private void InitializeComponent()
// TerrainBrushEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(511, 486);
this.Controls.Add(this.cb_tileVariation);
this.Controls.Add(this.tabControl1);

View File

@ -1,6 +1,7 @@
using NHSE.Core;
using System;
using System.Windows.Forms;
using static NHSE.Core.TerrainUnitModel;
namespace NHSE.WinForms.Subforms.Map;
@ -20,265 +21,84 @@ public TerrainBrushEditor(PropertyGrid pG_TerrainTile, FieldItemEditor fieWindow
PG_TerrainTile = pG_TerrainTile;
FIEWindow = fieWindow;
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
}
protected override void OnLoad(EventArgs e)
{
CenterToParent();
base.OnLoad(e);
}
#region Tiles buttons
#region Dirt tiles
private void NW_Rounded_Tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff3B,
LandMakingAngle = 0,
Elevation = (ushort)slider_elevation.Value,
};
private void NW_Rounded_Tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff3B);
private void N_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff5B, 3);
private void NE_rounded_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff3B, 3);
private void W_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff5B);
private void Middle_tile_Click(object sender, EventArgs e) => SelectTerrainTile();
private void E_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff5B, 2);
private void SW_rounded_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff3B, 1);
private void S_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff5B, 1);
private void SE_rounded_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff3B, 2);
private void NW_angular_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff3C);
private void NE_angular_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff3C, 3);
private void SW_angular_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff3C, 1);
private void SE_angular_tile_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff3C, 2);
private void N_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff5B,
LandMakingAngle = 3,
Elevation = (ushort)slider_elevation.Value,
};
private void NE_rounded_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff3B,
LandMakingAngle = 3,
Elevation = (ushort)slider_elevation.Value,
};
private void W_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff5B,
LandMakingAngle = 0,
Elevation = (ushort)slider_elevation.Value,
};
private void Middle_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
Elevation = (ushort)slider_elevation.Value,
};
private void E_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff5B,
LandMakingAngle = 2,
Elevation = (ushort)slider_elevation.Value,
};
private void SW_rounded_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff3B,
LandMakingAngle = 1,
Elevation = (ushort)slider_elevation.Value,
};
private void S_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff5B,
LandMakingAngle = 1,
Elevation = (ushort)slider_elevation.Value,
};
private void SE_rounded_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff3B,
LandMakingAngle = 2,
Elevation = (ushort)slider_elevation.Value,
};
private void NW_angular_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff3C,
Elevation = (ushort)slider_elevation.Value,
};
private void NE_angular_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff3C,
LandMakingAngle = 3,
Elevation = (ushort)slider_elevation.Value,
};
private void SW_angular_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff3C,
LandMakingAngle = 1,
Elevation = (ushort)slider_elevation.Value,
};
private void SE_angular_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff3C,
LandMakingAngle = 2,
Elevation = (ushort)slider_elevation.Value,
};
private void TR_dirt_inside_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff7A,
LandMakingAngle = 2,
Elevation = (ushort)slider_elevation.Value,
};
private void DL_dirt_inside_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff7A,
Elevation = (ushort)slider_elevation.Value,
};
private void DR_dirt_inside_Click(object sender, EventArgs e)
{
PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff7A,
LandMakingAngle = 1,
Elevation = (ushort)slider_elevation.Value,
};
}
private void TR_dirt_inside_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff7A, 2);
private void DL_dirt_inside_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff7A);
private void DR_dirt_inside_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff7A, 1);
#endregion Dirt tiles
#region Water tiles
private void NW_diagonal_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River3B,
Elevation = (ushort)slider_elevation.Value,
};
private void N_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River5B,
LandMakingAngle = 3,
Elevation = (ushort)slider_elevation.Value,
};
private void NE_diagonal_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River3B,
LandMakingAngle = 3,
Elevation = (ushort)slider_elevation.Value,
};
private void W_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River5B,
Elevation = (ushort)slider_elevation.Value,
};
private void Center_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River8A,
Elevation = (ushort)slider_elevation.Value,
};
private void e_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River5B,
LandMakingAngle = 2,
Elevation = (ushort)slider_elevation.Value,
};
private void sw_diagonal_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River3B,
LandMakingAngle = 1,
Elevation = (ushort)slider_elevation.Value,
};
private void s_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River5B,
LandMakingAngle = 1,
Elevation = (ushort)slider_elevation.Value,
};
private void SE_diagonal_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River3B,
LandMakingAngle = 2,
Elevation = (ushort)slider_elevation.Value,
};
private void NW_angular_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River3C,
Elevation = (ushort)slider_elevation.Value,
};
private void NE_angular_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River3C,
LandMakingAngle = 3,
Elevation = (ushort)slider_elevation.Value,
};
private void SW_angular_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River3C,
LandMakingAngle = 1,
Elevation = (ushort)slider_elevation.Value,
};
private void SE_angular_water_tile_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River3C,
LandMakingAngle = 2,
Elevation = (ushort)slider_elevation.Value,
};
private void TL_dirt_inside_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.Cliff7A,
LandMakingAngle = 3,
Elevation = (ushort)slider_elevation.Value,
};
private void TL_water_inside_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River7A,
LandMakingAngle = 3,
Elevation = (ushort)slider_elevation.Value,
};
private void TR_water_inside_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River7A,
LandMakingAngle = 2,
Elevation = (ushort)slider_elevation.Value,
};
private void DL_water_inside_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River7A,
Elevation = (ushort)slider_elevation.Value,
};
private void DR_water_inside_Click(object sender, EventArgs e) => PG_TerrainTile.SelectedObject = new TerrainTile
{
UnitModel = TerrainUnitModel.River7A,
LandMakingAngle = 1,
Elevation = (ushort)slider_elevation.Value,
};
private void NW_diagonal_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River3B);
private void N_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River5B, 3);
private void NE_diagonal_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River3B, 3);
private void W_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River5B);
private void Center_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River8A);
private void e_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River5B, 2);
private void sw_diagonal_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River3B, 1);
private void s_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River5B, 1);
private void SE_diagonal_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River3B, 2);
private void NW_angular_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River3C);
private void NE_angular_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River3C, 3);
private void SW_angular_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River3C, 1);
private void SE_angular_water_tile_Click(object sender, EventArgs e) => SelectTerrainTile(River3C, 2);
private void TL_dirt_inside_Click(object sender, EventArgs e) => SelectTerrainTile(Cliff7A, 3);
private void TL_water_inside_Click(object sender, EventArgs e) => SelectTerrainTile(River7A, 3);
private void TR_water_inside_Click(object sender, EventArgs e) => SelectTerrainTile(River7A, 2);
private void DL_water_inside_Click(object sender, EventArgs e) => SelectTerrainTile(River7A);
private void DR_water_inside_Click(object sender, EventArgs e) => SelectTerrainTile(River7A, 1);
#endregion Water tiles
#endregion Tiles buttons
private void SliderThicknessValueChanged(object sender, EventArgs e)
{
lbl_size_count.Text = slider_thickness.Value.ToString();
}
private void SliderThicknessValueChanged(object sender, EventArgs e) => lbl_size_count.Text = slider_thickness.Value.ToString();
private void SliderElevationValueChanged(object sender, EventArgs e)
{
lbl_elevation_count.Text = slider_elevation.Value.ToString();
TerrainTile currentTile = (TerrainTile)PG_TerrainTile.SelectedObject!;
var currentTile = (TerrainTile)PG_TerrainTile.SelectedObject!;
currentTile.Elevation = (ushort)slider_elevation.Value;
PG_TerrainTile.SelectedObject = currentTile;
}
private TerrainTile CreateTerrainTile(TerrainUnitModel unitModel = Base, ushort landMakingAngle = 0) => new()
{
Elevation = (ushort)slider_elevation.Value,
UnitModel = unitModel,
LandMakingAngle = landMakingAngle
};
private void SelectTerrainTile(TerrainUnitModel unitModel = Base, ushort landMakingAngle = 0)
=> PG_TerrainTile.SelectedObject = CreateTerrainTile(unitModel, landMakingAngle);
private void B_Brush_Click(object sender, EventArgs e) => IsBrushSelected = true;
private void TerrainBrushEditor_FormClosed(object sender, FormClosedEventArgs e) => IsBrushSelected = false;
private void B_Normal_Click(object sender, EventArgs e) => IsBrushSelected = false;

View File

@ -108,7 +108,7 @@ private void InitializeComponent()
// VillagerHouseEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(484, 283);
this.Controls.Add(this.B_LoadHouse);
this.Controls.Add(this.B_DumpHouse);
@ -120,7 +120,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "VillagerHouseEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Villager House Editor";
this.ResumeLayout(false);

View File

@ -226,7 +226,7 @@ private void InitializeComponent()
// AchievementEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(589, 261);
this.Controls.Add(this.B_Max);
this.Controls.Add(this.B_ClearAll);
@ -248,7 +248,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "AchievementEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Record Editor";
((System.ComponentModel.ISupportInitialize)(this.NUD_Count)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_Unk)).EndInit();

View File

@ -138,7 +138,7 @@ private void InitializeComponent()
// FlagEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.B_Copy);
this.Controls.Add(this.B_Load);
@ -152,7 +152,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FlagEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Flag Editor";
((System.ComponentModel.ISupportInitialize)(this.NUD_Count)).EndInit();
this.ResumeLayout(false);

View File

@ -215,7 +215,7 @@ private void InitializeComponent()
// ItemReceivedEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(815, 473);
this.Controls.Add(this.CB_VariantBodiesOnly);
this.Controls.Add(this.CLB_Remake);
@ -229,7 +229,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ItemReceivedEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Received Item List Editor";
this.CM_Buttons.ResumeLayout(false);
this.ResumeLayout(false);

View File

@ -205,7 +205,7 @@ private void InitializeComponent()
MaximizeBox = false;
MinimizeBox = false;
Name = "MiscPlayerEditor";
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "Misc Player Detail Editor";
((System.ComponentModel.ISupportInitialize)NUD_BirthMonth).EndInit();
((System.ComponentModel.ISupportInitialize)NUD_BirthDay).EndInit();

View File

@ -83,7 +83,7 @@ private void InitializeComponent()
// ReactionEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(331, 287);
this.Controls.Add(this.B_GiveAll);
this.Controls.Add(this.PG_Manpu);
@ -93,7 +93,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ReactionEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Reaction List Editor";
this.ResumeLayout(false);

View File

@ -177,7 +177,7 @@ private void InitializeComponent()
// RecipeListEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(404, 381);
this.Controls.Add(this.B_CraftAll);
this.Controls.Add(this.B_ClearAll);
@ -195,7 +195,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "RecipeListEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Recipe List Editor";
this.ResumeLayout(false);

View File

@ -29,110 +29,106 @@ protected override void Dispose(bool disposing)
/// </summary>
private void InitializeComponent()
{
this.B_Cancel = new System.Windows.Forms.Button();
this.B_Save = new System.Windows.Forms.Button();
this.B_Dump = new System.Windows.Forms.Button();
this.B_Load = new System.Windows.Forms.Button();
this.PAN_Items = new System.Windows.Forms.Panel();
this.B_Inject = new System.Windows.Forms.Button();
this.ItemEditor = new NHSE.WinForms.ItemEditor();
this.SuspendLayout();
B_Cancel = new System.Windows.Forms.Button();
B_Save = new System.Windows.Forms.Button();
B_Dump = new System.Windows.Forms.Button();
B_Load = new System.Windows.Forms.Button();
PAN_Items = new System.Windows.Forms.Panel();
B_Inject = new System.Windows.Forms.Button();
ItemEditor = new ItemEditor();
SuspendLayout();
//
// B_Cancel
//
this.B_Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.B_Cancel.Location = new System.Drawing.Point(772, 398);
this.B_Cancel.Name = "B_Cancel";
this.B_Cancel.Size = new System.Drawing.Size(72, 23);
this.B_Cancel.TabIndex = 5;
this.B_Cancel.Text = "Cancel";
this.B_Cancel.UseVisualStyleBackColor = true;
this.B_Cancel.Click += new System.EventHandler(this.B_Cancel_Click);
B_Cancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
B_Cancel.Location = new System.Drawing.Point(840, 398);
B_Cancel.Name = "B_Cancel";
B_Cancel.Size = new System.Drawing.Size(72, 23);
B_Cancel.TabIndex = 5;
B_Cancel.Text = "Cancel";
B_Cancel.UseVisualStyleBackColor = true;
B_Cancel.Click += B_Cancel_Click;
//
// B_Save
//
this.B_Save.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.B_Save.Location = new System.Drawing.Point(850, 398);
this.B_Save.Name = "B_Save";
this.B_Save.Size = new System.Drawing.Size(72, 23);
this.B_Save.TabIndex = 4;
this.B_Save.Text = "Save";
this.B_Save.UseVisualStyleBackColor = true;
this.B_Save.Click += new System.EventHandler(this.B_Save_Click);
B_Save.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
B_Save.Location = new System.Drawing.Point(918, 398);
B_Save.Name = "B_Save";
B_Save.Size = new System.Drawing.Size(72, 23);
B_Save.TabIndex = 4;
B_Save.Text = "Save";
B_Save.UseVisualStyleBackColor = true;
B_Save.Click += B_Save_Click;
//
// B_Dump
//
this.B_Dump.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.B_Dump.Location = new System.Drawing.Point(9, 398);
this.B_Dump.Name = "B_Dump";
this.B_Dump.Size = new System.Drawing.Size(90, 23);
this.B_Dump.TabIndex = 7;
this.B_Dump.Text = "Dump";
this.B_Dump.UseVisualStyleBackColor = true;
this.B_Dump.Click += new System.EventHandler(this.B_Dump_Click);
B_Dump.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
B_Dump.Location = new System.Drawing.Point(9, 398);
B_Dump.Name = "B_Dump";
B_Dump.Size = new System.Drawing.Size(90, 23);
B_Dump.TabIndex = 7;
B_Dump.Text = "Dump";
B_Dump.UseVisualStyleBackColor = true;
B_Dump.Click += B_Dump_Click;
//
// B_Load
//
this.B_Load.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.B_Load.Location = new System.Drawing.Point(105, 398);
this.B_Load.Name = "B_Load";
this.B_Load.Size = new System.Drawing.Size(90, 23);
this.B_Load.TabIndex = 8;
this.B_Load.Text = "Load";
this.B_Load.UseVisualStyleBackColor = true;
this.B_Load.Click += new System.EventHandler(this.B_Load_Click);
B_Load.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
B_Load.Location = new System.Drawing.Point(105, 398);
B_Load.Name = "B_Load";
B_Load.Size = new System.Drawing.Size(90, 23);
B_Load.TabIndex = 8;
B_Load.Text = "Load";
B_Load.UseVisualStyleBackColor = true;
B_Load.Click += B_Load_Click;
//
// PAN_Items
//
this.PAN_Items.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.PAN_Items.Location = new System.Drawing.Point(9, 12);
this.PAN_Items.Name = "PAN_Items";
this.PAN_Items.Size = new System.Drawing.Size(727, 380);
this.PAN_Items.TabIndex = 9;
PAN_Items.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
PAN_Items.Location = new System.Drawing.Point(9, 12);
PAN_Items.Name = "PAN_Items";
PAN_Items.Size = new System.Drawing.Size(795, 380);
PAN_Items.TabIndex = 9;
//
// B_Inject
//
this.B_Inject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.B_Inject.Location = new System.Drawing.Point(420, 398);
this.B_Inject.Name = "B_Inject";
this.B_Inject.Size = new System.Drawing.Size(90, 23);
this.B_Inject.TabIndex = 10;
this.B_Inject.Text = "Inject";
this.B_Inject.UseVisualStyleBackColor = true;
this.B_Inject.Click += new System.EventHandler(this.B_Inject_Click);
B_Inject.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
B_Inject.Location = new System.Drawing.Point(420, 398);
B_Inject.Name = "B_Inject";
B_Inject.Size = new System.Drawing.Size(90, 23);
B_Inject.TabIndex = 10;
B_Inject.Text = "Inject";
B_Inject.UseVisualStyleBackColor = true;
B_Inject.Click += B_Inject_Click;
//
// ItemEditor
//
this.ItemEditor.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.ItemEditor.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.ItemEditor.Location = new System.Drawing.Point(742, 12);
this.ItemEditor.Name = "ItemEditor";
this.ItemEditor.Size = new System.Drawing.Size(180, 380);
this.ItemEditor.TabIndex = 6;
ItemEditor.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
ItemEditor.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
ItemEditor.Location = new System.Drawing.Point(810, 12);
ItemEditor.Name = "ItemEditor";
ItemEditor.Size = new System.Drawing.Size(180, 380);
ItemEditor.TabIndex = 6;
//
// PlayerItemEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(934, 431);
this.Controls.Add(this.B_Inject);
this.Controls.Add(this.PAN_Items);
this.Controls.Add(this.B_Load);
this.Controls.Add(this.B_Dump);
this.Controls.Add(this.ItemEditor);
this.Controls.Add(this.B_Cancel);
this.Controls.Add(this.B_Save);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = global::NHSE.WinForms.Properties.Resources.icon;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PlayerItemEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Inventory Editor";
this.ResumeLayout(false);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
ClientSize = new System.Drawing.Size(1002, 431);
Controls.Add(B_Inject);
Controls.Add(B_Load);
Controls.Add(B_Dump);
Controls.Add(ItemEditor);
Controls.Add(B_Cancel);
Controls.Add(B_Save);
Controls.Add(PAN_Items);
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
Icon = Properties.Resources.icon;
MaximizeBox = false;
MinimizeBox = false;
Name = "PlayerItemEditor";
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "Inventory Editor";
ResumeLayout(false);
}

View File

@ -93,7 +93,7 @@ private void B_Inject_Click(object sender, EventArgs e)
var exist = WinFormsUtil.FirstFormOfType<SysBotUI>();
if (exist != null)
{
exist.Show();
exist.Show(this);
exist.BringToFront();
exist.CenterToForm(this);
return;
@ -120,7 +120,7 @@ static void AfterWrite(InjectionResult r)
ItemGrid.ItemChanged = () => ai.Write();
var sysbot = new SysBotUI(ai, sb, aiUSB, ub);
sysbot.Show();
sysbot.Show(this);
}
private void ItemEditor_DragEnter(object? sender, DragEventArgs e)

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->

View File

@ -118,7 +118,7 @@ private void InitializeComponent()
// ImageFetcher
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(407, 235);
this.Controls.Add(this.L_FileSize);
this.Controls.Add(this.L_ImgStatus);
@ -131,7 +131,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ImageFetcher";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Item Images";
this.ResumeLayout(false);
this.PerformLayout();

View File

@ -31,6 +31,12 @@ public ImageFetcher()
CheckFileStatusLabel();
}
protected override void OnLoad(EventArgs e)
{
CenterToParent();
base.OnLoad(e);
}
private static string[] LoadHosts()
{
var hosts = Properties.Resources.hosts_images;

View File

@ -42,7 +42,7 @@ private void InitializeComponent()
// SettingsEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(322, 310);
this.Controls.Add(this.PG_Settings);
this.Icon = global::NHSE.WinForms.Properties.Resources.icon;
@ -50,7 +50,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SettingsEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Settings Editor";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SettingsEditor_FormClosing);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.SettingsEditor_KeyDown);

View File

@ -1,22 +1,18 @@
using System.Windows.Forms;
using NHSE.WinForms.Properties;
namespace NHSE.WinForms;
public partial class SettingsEditor : Form
{
private readonly Settings obj;
public SettingsEditor()
{
obj = Settings.Default;
InitializeComponent();
PG_Settings.SelectedObject = obj;
PG_Settings.SelectedObject = Program.Settings;
}
private void SettingsEditor_FormClosing(object sender, FormClosingEventArgs e)
{
obj.Save();
// Settings are saved when Main form closes
}
private void SettingsEditor_KeyDown(object sender, KeyEventArgs e)

View File

@ -66,7 +66,7 @@ private void InitializeComponent()
// SingleItemEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(179, 279);
this.Controls.Add(this.ItemEditor);
this.Controls.Add(this.B_Cancel);
@ -75,7 +75,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SingleItemEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Item Editor";
this.ResumeLayout(false);

View File

@ -70,7 +70,7 @@ private void InitializeComponent()
// SingleObjectEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(324, 421);
this.Controls.Add(this.PG_Item);
this.Controls.Add(this.B_Cancel);
@ -79,7 +79,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SingleObjectEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Property Editor";
this.ResumeLayout(false);

View File

@ -149,7 +149,7 @@ private void InitializeComponent()
// BatchEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(394, 254);
this.Controls.Add(this.L_PropValue);
this.Controls.Add(this.L_PropType);
@ -165,7 +165,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "BatchEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Batch Editor";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SysBotRAMEdit_FormClosing);
this.ResumeLayout(false);

View File

@ -62,7 +62,7 @@ private void InitializeComponent()
// SimpleHexEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(384, 343);
this.Controls.Add(this.B_Update);
this.Controls.Add(this.RTB_RAM);

View File

@ -1,17 +1,17 @@
using System;
using System.Windows.Forms;
using NHSE.Injection;
using NHSE.WinForms.Properties;
namespace NHSE.WinForms;
public sealed class SysBotController(InjectionType type)
{
public readonly SysBot Bot = new();
private readonly Settings _settings = Settings.Default;
public string IP => _settings.SysBotIP;
public string Port => _settings.SysBotPort.ToString();
private static SysBotSettings Config => Program.Settings.SysBot;
public string IP => Config.IP;
public string Port => Config.Port.ToString();
public bool Connect(string ip, string port)
{
@ -28,17 +28,16 @@ public bool Connect(string ip, string port)
return false;
}
_settings.SysBotIP = ip;
_settings.SysBotPort = p;
_settings.Save();
Config.IP = ip;
Config.Port = p;
return true;
}
public uint GetDefaultOffset() => type switch
{
InjectionType.Generic => _settings.SysBotGenericOffset,
InjectionType.Pouch => _settings.SysBotPouchOffset,
InjectionType.Generic => Config.GenericOffset,
InjectionType.Pouch => Config.PouchOffset,
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null),
};
@ -46,11 +45,10 @@ public void SetOffset(uint value)
{
switch (type)
{
case InjectionType.Generic: _settings.SysBotGenericOffset = value; break;
case InjectionType.Pouch: _settings.SysBotPouchOffset = value; break;
case InjectionType.Generic: Config.GenericOffset = value; break;
case InjectionType.Pouch: Config.PouchOffset = value; break;
default: return;
}
_settings.Save();
}
public void HexEdit(uint offset, int length)
@ -78,12 +76,11 @@ public void HexEdit(uint offset, int length)
public void PopPrompt()
{
if (_settings.SysBotPrompted)
if (Config.Prompted)
return;
WinFormsUtil.Alert(MessageStrings.MsgSysBotInfo, MessageStrings.MsgSysBotRequired);
_settings.SysBotPrompted = true;
_settings.Save();
Config.Prompted = true;
}
public void WriteBytes(byte[] data, uint offset)

View File

@ -163,7 +163,7 @@ private void InitializeComponent()
// SysBotRAMEdit
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(234, 140);
this.Controls.Add(this.GB_Inject);
this.Controls.Add(this.B_Connect);
@ -176,7 +176,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SysBotRAMEdit";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "SysBotUI";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SysBotRAMEdit_FormClosing);
this.GB_Inject.ResumeLayout(false);

View File

@ -21,6 +21,12 @@ public SysBotRAMEdit(InjectionType type)
Bot.PopPrompt();
}
protected override void OnLoad(EventArgs e)
{
CenterToParent();
base.OnLoad(e);
}
private void B_Connect_Click(object sender, EventArgs e)
{
if (!Bot.Connect(TB_IP.Text, TB_Port.Text))

View File

@ -270,7 +270,7 @@ private void InitializeComponent()
// SysBotUI
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(245, 342);
this.Controls.Add(this.GB_USB);
this.Controls.Add(this.GB_Inject);
@ -285,7 +285,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SysBotUI";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "SysBotUI";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SysBotUI_FormClosing);
this.GB_Inject.ResumeLayout(false);

View File

@ -22,7 +22,9 @@ public SysBotUI(AutoInjector injector, SysBotController c, AutoInjector injector
InjectorUSB = injectorUSB;
var offset = Bot.GetDefaultOffset();
offset = offset > 0 ? offset : StringUtil.GetHexValue(RamOffset.Text);
Injector.SetWriteOffset(offset);
RamOffset.Text = offset.ToString("X8");
RamOffsetUSB.Text = offset.ToString("X8");
@ -34,6 +36,12 @@ public SysBotUI(AutoInjector injector, SysBotController c, AutoInjector injector
TIM_Interval.Tick += (s, e) => injector.Read();
}
protected override void OnLoad(EventArgs e)
{
CenterToParent();
base.OnLoad(e);
}
private void B_Connect_Click(object sender, EventArgs e)
{
if (!Bot.Connect(TB_IP.Text, TB_Port.Text))

View File

@ -276,7 +276,7 @@ private void InitializeComponent()
// SaveRoomFloorWallEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(257, 194);
this.Controls.Add(this.L_FloorDirection);
this.Controls.Add(this.L_FloorDesign);
@ -299,7 +299,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SaveRoomFloorWallEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Room Editor";
((System.ComponentModel.ISupportInitialize)(this.NUD_DesignAccent)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_DirAccent)).EndInit();

View File

@ -113,7 +113,7 @@ private void InitializeComponent()
// VillagerDIYTimerEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(245, 142);
this.Controls.Add(this.B_Cancel);
this.Controls.Add(this.B_Save);
@ -127,7 +127,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "VillagerDIYTimerEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Villager DIY Editor";
this.ResumeLayout(false);
this.PerformLayout();

View File

@ -126,7 +126,7 @@ private void InitializeComponent()
// VillagerFlagEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.B_Load);
this.Controls.Add(this.B_Dump);
@ -139,7 +139,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "VillagerFlagEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Flag Editor";
((System.ComponentModel.ISupportInitialize)(this.NUD_Count)).EndInit();
this.ResumeLayout(false);

View File

@ -469,7 +469,7 @@ private void InitializeComponent()
// VillagerMemoryEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(506, 359);
this.Controls.Add(this.TB_Island);
this.Controls.Add(this.LBL_IslandName);
@ -485,7 +485,7 @@ private void InitializeComponent()
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "VillagerMemoryEditor";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Villager Player Memory Editor";
((System.ComponentModel.ISupportInitialize)(this.NUD_Count)).EndInit();
this.TC_Memory.ResumeLayout(false);

View File

@ -4,7 +4,6 @@
using System.Linq;
using System.Windows.Forms;
using NHSE.Core;
using NHSE.WinForms.Properties;
namespace NHSE.WinForms;
#if DEBUG
@ -66,7 +65,7 @@ private static void UpdateTranslations()
private static void LoadSpecialForms()
{
// For forms that require more complete initialization (dynamically added user controls)
var path = Settings.Default.LastFilePath;
var path = Program.Settings.LastFilePath;
var sav = HorizonSave.FromFolder(path);
using var editor = new Editor(sav);
using var so = new SingleObjectEditor<object>(new object(), PropertySort.NoSort, false);

View File

@ -1,5 +1,4 @@
using NHSE.WinForms.Properties;
using System;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Linq;
@ -84,34 +83,13 @@ internal static DialogResult Prompt(MessageBoxButtons btn, params string[] lines
/// </summary>
/// <param name="child"></param>
/// <param name="parent"></param>
internal static void CenterToForm(this Control child, Control parent)
internal static void CenterToForm(this Control child, Control parent) => child.Location = GetCenterLocation(child, parent);
internal static Point GetCenterLocation(Control child, Control parent)
{
int x = parent.Location.X + ((parent.Width - child.Width) / 2);
int y = parent.Location.Y + ((parent.Height - child.Height) / 2);
child.Location = new Point(Math.Max(x, 0), Math.Max(y, 0));
}
/// <summary>
/// Sets the application color mode based on the <paramref name="theme"/> <typeparamref name="int"/> passed to it and stores it in the application <see cref="Settings"/>.
/// </summary>
/// <param name="theme"></param>
public static void SetApplicationTheme(int theme)
{
switch (theme)
{
case 0:
Application.SetColorMode(SystemColorMode.Classic);
break;
case 1:
Application.SetColorMode(SystemColorMode.System);
break;
case 2:
Application.SetColorMode(SystemColorMode.Dark);
break;
}
var settings = Settings.Default;
settings.DarkMode = theme.ToString();
settings.Save();
var location = new Point(Math.Max(x, 0), Math.Max(y, 0));
return location;
}
}