Editor/Carve/ArchCutManifest.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;

namespace Sunless.Architecture;

public sealed class ArchCutManifest : ArchKindManifest<ArchCutPart> {
	public override ArchKind Kind => ArchKind.Cut;

	public override string Slot => "Cuts";

	// A cut is world-space and a road carries its own, so every unit files them - which is why ArchPlan.AllCuts
	// walks Units rather than Buildings.
	public override IEnumerable<Type> Hosts => new[] { typeof( ArchUnit ) };

	public override string Label => "Cut";

	public override string Glyph => "content_cut";

	public override string Subtool => ArchSubtools.Bool;

	public override int DirectRank => 14;

	// A bite that wears damage finishes the surface it took; one that opens a shaft voids it, and only the part
	// knows which, so a bare kind falls to Void.
	public override ArchLayerStage Stage( object payload ) {
		return payload is ArchCutPart zone && zone.Mode != ArchZoneMode.Carve ? ArchLayerStage.Finish : ArchLayerStage.Void;
	}

	public override bool File( object host, object payload ) {
		if ( payload is not ArchCutPart cut ) {
			return false;
		}

		// Nesting a cut under a porch says what the bite belongs to, the way a walkway's deck record does, and
		// moves nothing the generator reads.
		if ( host is ArchPorchPart ) {
			return true;
		}

		if ( host is not ArchBuilding building ) {
			return false;
		}

		building.Cuts.Add( cut );

		return true;
	}

	public override bool Unfile( ArchPlan plan, object payload ) {
		return payload is ArchCutPart cut && plan.Buildings.Any( building => building.Cuts.Remove( cut ) );
	}

	public override IReadOnlyList<List<Vector2>> Loops( object payload ) {
		return payload is ArchCutPart cut ? cut.Outlines().ToList() : base.Loops( payload );
	}

	public override float Height( object payload, float fallback ) {
		return payload is ArchCutPart cut && cut.Segments.Count > 0 ? cut.Segments[0].TopHeight : fallback;
	}
}