Editor/Stair/ArchExteriorStairPart.cs

An editor-only data component describing an exterior stair part for architecture. It stores identifiers, geometry (anchor, outward direction, heights, width, reach, storey height), rail flag and a palette, and computes derived vectors Rise, Facing and Along.

Reflection
using System;
using Sandbox;

namespace Sunless.Architecture;

// A fire escape wants a BUILDING as its host and a wall as its datum, and it lands once per storey, so the part
// stores the ROUTING alone - an anchor, a rise and a landing per storey - and the module that owns the kind
// resolves legs and rails from it.
public sealed class ArchExteriorStairPart : IArchPainted, IArchNamed
{
	public int Id { get; set; }
	public string Name { get; set; } = "Exterior Stair";
	// The NEAR end of the assembly on the wall's outer face; it runs from here along the elevation.
	public Vector2 Anchor { get; set; }
	public Vector2 Outward { get; set; } = new( 1f, 0f );
	public float BaseHeight { get; set; }
	public float TopHeight { get; set; } = 128f;
	// The walking width, which for a flight running ALONG an elevation is how far it stands off the face.
	// 0 takes the kit's.
	public float Width { get; set; }
	// The landing's depth in the direction of travel - how much elevation each switchback turn eats. 0 takes
	// the kit's.
	public float Reach { get; set; }
	// 0 takes the building's own storey height, so a landing meets every floor it passes.
	public float StoreyHeight { get; set; }
	public bool Rail { get; set; } = true;
	public ArchPalette Palette { get; set; } = new();

	public float Rise => MathF.Max( 1f, TopHeight - BaseHeight );

	public Vector2 Facing => Outward.Length < 0.01f ? new Vector2( 1f, 0f ) : Outward.Normal;

	public Vector2 Along
	{
		get
		{
			var facing = Facing;

			return new Vector2( -facing.y, facing.x );
		}
	}
}