editor/AdvancedMappingTools/Architecture/DrawbridgeEditor.cs

Editor stamp tool that builds a drawbridge from two piers, two bascule leaves, and optional chains using MeshKit primitives. Leaves pivot at the piers and lift as RaiseAngle increases.

namespace AdvancedMappingTools;

/// <summary>
/// A drawbridge: two piers, two bascule leaves, chains and counterweights. The leaves are
/// closed at Raise 0 and lift up as the angle grows.
/// </summary>
[ToolCategory( "Tunnels & Bridges" )]
[Title( "Drawbridge" ), Icon( "door_sliding" )]
public sealed class DrawbridgeEditor( PrimitiveTool tool ) : StampEditor( tool )
{
	[Property, Group( "Drawbridge" ), Range( 32, 2048, slider: false ), WideMode]
	public float Span { get; set; } = 256.0f;

	[Property, Group( "Drawbridge" ), Range( 16, 512, slider: false ), WideMode]
	public float Width { get; set; } = 96.0f;

	[Property, Group( "Drawbridge" ), Title( "Deck" ), Range( 1, 64, slider: false ), WideMode]
	public float Deck { get; set; } = 8.0f;

	[Property, Group( "Drawbridge" ), Title( "Pier Height" ), Range( 8, 512, slider: false ), WideMode]
	public float PierHeight { get; set; } = 64.0f;

	[Property, Group( "Drawbridge" ), Title( "Raise Angle" ), Range( 0, 80 ), WideMode]
	public float RaiseAngle { get; set; } = 0.0f;

	[Property, Group( "Drawbridge" ), Title( "Chains" ), WideMode]
	public bool Chains { get; set; } = true;

	protected override void Stamp( MeshKit kit, Transform frame, Random random )
	{
		var span = MathF.Max( Span, 32.0f );
		var width = MathF.Max( Width, 16.0f );
		var deck = Math.Clamp( Deck, 1.0f, 64.0f );
		var pier = MathF.Max( PierHeight, 8.0f );
		var half = span * 0.5f;
		var w = width * 0.5f;
		var raise = Math.Clamp( RaiseAngle, 0.0f, 80.0f );
		var leaf = half;

		foreach ( var side in new[] { -1.0f, 1.0f } )
		{
			var x = half * side;

			kit.Box( new Vector3( x - 12, -w - 8, -pier ), new Vector3( x + 12, w + 8, deck ) );
			kit.Box( new Vector3( x - 8, -w, deck ), new Vector3( x + 8, w, deck + 8 ) );

			kit.Frame = frame.ToWorld( new Transform( new Vector3( x, 0, deck ), Rotation.From( raise * side, 0, 0 ) * Rotation.FromYaw( side < 0 ? 0 : 180 ) ) );
			kit.Box( new Vector3( 0, -w, 0 ), new Vector3( leaf, w, deck * 0.5f ) );

			var tipWorld = kit.Frame.PointToWorld( new Vector3( leaf, 0, 0 ) );
			kit.Frame = frame;

			if ( !Chains ) continue;

			kit.Beam( new Vector3( x, 0, deck + 8 ), frame.PointToLocal( tipWorld ), 2.0f, 2.0f );
		}
	}
}