Editor-side model for a porch architectural part. Defines ArchPorchPart with properties controlling appearance and components (legs, stairs, pillars, trims, palette, roof/doors, structural flags) and small supporting types PorchStanding and ArchPorchLeg.
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
namespace Sunless.Architecture;
// A wrap-around is several of these sharing one deck level and one roof.
public sealed class ArchPorchLeg
{
public Vector2 Min { get; set; }
public Vector2 Max { get; set; }
}
// What the deck leans on. Against subtracts the storey's shell, which is the veranda wrapping a house;
// Free keeps the drag whole, which is the only way a deck stands inside a room or out in a yard.
public enum PorchStanding
{
Against,
Free
}
// A porch is a HOST, exactly as a room is: its flights, columns and runs are real child layers with their
// own rows, handles, palettes and delete, rather than pieces baked into one generator. RoofId is only
// where the section the cover pass made is standing - Roofed is the authored intent it re-derives from.
public sealed class ArchPorchPart : IArchCollides, IArchPainted, IArchNamed
{
// Overrides the kit for THIS part alone: one wall that needs its exact holes, one tower that needs none.
public ArchCollisionMode? Collision { get; set; }
public int Id { get; set; }
public string Name { get; set; } = "Porch";
public List<ArchPorchLeg> Legs { get; set; } = new();
public PorchStanding Standing { get; set; }
public float BaseHeight { get; set; }
public float GradeHeight { get; set; }
public float HeadHeight { get; set; } = 100f;
public bool Plinth { get; set; } = true;
// Off, the same part is a canopy over whatever ground is there.
public bool Deck { get; set; } = true;
public bool Posts { get; set; } = true;
public float PostSpacing { get; set; } = 96f;
public bool Beam { get; set; } = true;
public bool Rafters { get; set; }
// Under a postless canopy they are the only thing carrying it.
public bool Braces { get; set; }
public bool Railings { get; set; } = true;
// Seeds one flight when the porch is placed. The list is the truth afterwards - delete the row and it
// stays deleted, drag another in and both stand.
public bool Steps { get; set; } = true;
// A porch is an entrance, so it stands the door in the wall it fronts rather than leaving it as a second
// drag to remember - ArchPorchAffector owns it and re-derives which elevation it lands on every commit.
public bool Door { get; set; } = true;
// Blank takes the kit's first door.
public string DoorPreset { get; set; } = "";
public bool Roofed { get; set; } = true;
// 0 takes the porch's shallow default.
public float Pitch { get; set; }
public int RoofId { get; set; }
public List<ArchStairPart> Stairs { get; set; } = new();
public List<ArchPillarPart> Pillars { get; set; } = new();
public List<ArchTrimPart> Trims { get; set; } = new();
public ArchPalette Palette { get; set; } = new();
public float DeckDrop => MathF.Max( 0f, BaseHeight - GradeHeight );
public IEnumerable<object> Children => Stairs.Cast<object>().Concat( Pillars ).Concat( Trims );
}