Editor/Services/ArchWingGeneration.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
namespace Sunless.Architecture;
public sealed class ArchWingGeneration {
readonly ArchPlan plan;
readonly ArchBuilding building;
readonly ArchKit kit;
int level;
float baseHeight;
Vector2 min;
Vector2 max;
SectionRoof choice;
float drop;
bool floor;
bool gutters;
RidgeRun ridge;
public ArchWingGeneration( ArchPlan plan, ArchBuilding building, ArchKit kit ) {
this.plan = plan;
this.building = building;
this.kit = kit;
}
public ArchWingGeneration On( int level, float baseHeight, Vector2 min, Vector2 max ) {
this.level = level;
this.baseHeight = baseHeight;
this.min = min;
this.max = max;
return this;
}
public ArchWingGeneration WithRoof( SectionRoof choice, float drop, bool gutters, RidgeRun ridge ) {
this.choice = choice;
this.drop = drop;
this.gutters = gutters;
this.ridge = ridge;
return this;
}
public ArchWingGeneration WithFloor( bool floor ) {
this.floor = floor;
return this;
}
public ArchSection Create() {
var resolved = new ArchBoundaryPlacement( plan, kit ).Outside( level, min, max, building );
if ( !resolved.IsUsable || !resolved.TouchesHost ) {
return null;
}
min = resolved.Min;
max = resolved.Max;
var placement = new ArchWingPlacement( building, kit, level );
var continuing = choice == SectionRoof.Continue;
var host = continuing ? placement.Host( min, max ) : null;
var merge = host is not null;
var wallHeight = merge
? MathF.Max( 32f, host.BaseHeight - baseHeight )
: MathF.Max( 32f, kit.WallHeight - (continuing ? 0f : MathF.Max( 0f, drop )) );
var party = new List<(Vector2 From, Vector2 To)>();
var wing = ArchBuild.CreateRoom( plan, building, $"Wing{building.Rooms.Count}", level, baseHeight, wallHeight, min, max, floor, party, kit.WallThickness );
var connections = new ArchConnections( plan, kit );
foreach ( var edge in party ) {
connections.OpenRooms( wing, building, edge.From, edge.To, wallHeight, wing.Floor );
}
// The breach took the host's wall out of the span, so the wing's own must not stand in its place.
foreach ( var (from, to) in party ) {
var partyWall = wing.Walls.FirstOrDefault( wall => SameRun( wall, from, to ) );
if ( partyWall is not null ) {
plan.Unfile( partyWall );
}
}
connections.NormalizeBoundaries();
if ( merge ) {
var merged = ArchFootprint.Merge( host.Outline(), ArchFootprint.Rect( min, max ) );
if ( merged is not null ) {
host.Reshape( merged );
host.Style = host.Style == RoofStyle.Flat ? RoofStyle.Flat : RoofStyle.Hip;
return new ArchSection { Room = wing, Roof = host, SharedWalls = party.Count, Merged = true };
}
}
if ( choice == SectionRoof.None ) {
return new ArchSection { Room = wing, SharedWalls = party.Count };
}
var roof = ArchBuild.Roof( plan, kit, level, ArchBuild.Winged( choice ), min, max, baseHeight + wallHeight, gutters, choice == SectionRoof.Capped, ridge );
plan.File( ArchKind.Roof, building, roof );
return new ArchSection { Room = wing, Roof = roof, SharedWalls = party.Count };
}
static bool SameRun( ArchWall wall, Vector2 from, Vector2 to ) {
return (wall.Start - from).Length <= 0.01f && (wall.End - to).Length <= 0.01f
|| (wall.Start - to).Length <= 0.01f && (wall.End - from).Length <= 0.01f;
}
}