Editor/Wall/ArchBalconyPart.cs
using System;
using Sandbox;

namespace Sunless.Architecture;

// A thing standing outside a room hangs off the BUILDING, like a ladder or a downpipe - not off the active
// room, which is whichever one the picker happened to be on. The wall it was placed against is its datum.
//
// Reach is the whole vocabulary: positive projects a slab, zero is a Juliet with nothing to stand on, and
// negative bites a loggia back into the elevation and becomes a cut whose bite re-derives every commit.
public sealed class ArchBalconyPart : IArchPainted, IArchNamed {
	public int Id { get; set; }
	public string Name { get; set; } = "Balcony";
	public Vector2 Anchor { get; set; }
	public Vector2 Outward { get; set; } = new( 1f, 0f );
	public float BaseHeight { get; set; }
	public float Width { get; set; } = 96f;
	public float Reach { get; set; } = 36f;
	public float Thickness { get; set; } = 5f;
	// The deck's height off the storey floor it hangs on. A datum offset rather than an extent, which is why it
	// is a typed number and not a handle - the same bargain the roof's eave drop makes.
	public float Lift { get; set; }
	public bool Rail { get; set; } = true;
	public BarrierStyle GuardStyle { get; set; } = BarrierStyle.Picket;
	// 0 takes the kit's own balustrade height.
	public float RailHeight { get; set; }
	public bool Coping { get; set; } = true;
	public ArchPalette Palette { get; set; } = new();

	public bool IsJuliet => MathF.Abs( Reach ) <= 0.01f;

	public bool IsRecessed => Reach < -0.01f;

	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 );
		}
	}
}