Editor/UI/ArchGuidesWritten.cs
using System.Collections.Generic;
namespace Sunless.Architecture;
// The prose. One entry per tool complex enough that its sidebar cannot say the whole story in a line - and no
// entry at all for a tool whose one gesture is obvious, because a chip on that tool would only teach the author
// that the chip is not worth pressing.
public static class ArchGuidesWritten {
public static IEnumerable<ArchGuide> Standing() {
yield return Stair();
yield return Brackets();
yield return Porch();
yield return Fence();
yield return Road();
yield return Bridge();
yield return Tunnel();
}
static ArchGuide Stair() => new() {
Ident = "subtool_stair",
Title = "Stair",
Lead = "Four different climbs stand under one tool. Pick the kind in step 1 and the rest of the sequence "
+ "becomes that kind's own questions — a walked stair is asked six things, a carved flight two.",
Chapters = new[]
{
new ArchGuideChapter
{
Heading = "Walking a stair",
Picture = "stair_walk",
Body = new[]
{
"A walked stair is CLICKED, not dragged. Every leg between two clicks is a flight, and every "
+ "turn drops a landing in at the height the two flights meet.",
"Click the floor above rather than a point on this one and it works the rest of the climb out "
+ "itself, arriving level with that storey. Start on a standing stair's head instead and you "
+ "are walking that one further — the new flights turn against the one below them."
},
Steps = new[]
{
"Click the foot, where the bottom riser stands.",
"Click each point the stair turns or arrives at.",
"Press Enter to build it, or Escape to throw the walk away."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "stair_straight", Glyph = "straighten", Caption = "One flight" },
new ArchGuidePlate { Slug = "stair_landing", Glyph = "stairs", Caption = "One turn" },
new ArchGuidePlate { Slug = "stair_switchback", Glyph = "u_turn_left", Caption = "Switchback" }
}
},
new ArchGuideChapter
{
Heading = "Pinning a step",
Body = new[]
{
"A flight divides its climb evenly across its risers, which is the right answer nearly always "
+ "and never the answer for a stair that has to land on something.",
"Select the stair and pull a step's LIFT ARROW to pin that one riser where you want it. Three "
+ "risers onto a broad landing, fourteen more after it, and the rest share whatever climb is "
+ "left over — the flight re-divides around every pin you set."
}
},
new ArchGuideChapter
{
Heading = "To the top",
Body = new[]
{
"To the top punches the shaft the rest of the way up: the same flights and the same well, "
+ "repeated through every storey standing over the one you walked.",
"Walk the bottom flight until it reads right, then press it once. It is a document action rather "
+ "than a property of the next drag, which is why it sits above the numbered steps."
}
},
new ArchGuideChapter
{
Heading = "The other three kinds",
Body = new[]
{
"CONCRETE STEPS cut a flight out of a platform that already stands, so the riser bends to the "
+ "platform's own rise and the flight always arrives level with its coping. For a free-standing "
+ "concrete stair, walk a shaft instead and build it of Solid.",
"FOUNDATION STEPS climb from grade onto the plinth at a door. Drag the footprint anywhere outside "
+ "and it snaps square onto the nearest wall: across the wall is the going, along it is the "
+ "width, and the rise is however high the plinth happens to stand.",
"A DRIVEWAY RAMP is the same gesture at a garage. Its spline form starts on an exterior wall or a "
+ "street edge, takes clicked control points, and ends on the other connection — select the "
+ "result afterwards to widen it node by node."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "stair_carve", Glyph = "content_cut", Caption = "Carved" },
new ArchGuidePlate { Slug = "approach_steps", Glyph = "stairs_2", Caption = "Foundation" },
new ArchGuidePlate { Slug = "approach_ramp", Glyph = "trending_up", Caption = "Ramp" }
}
}
}
};
static ArchGuide Brackets() => new() {
Ident = "subtool_bracket",
Title = "Brackets",
Lead = "A row of hangers under a bundle of services. Nothing about it is typed twice: the box says where "
+ "the row runs and how often, and every member is sized off the runs actually crossing it.",
Chapters = new[]
{
new ArchGuideChapter
{
Heading = "Dragging the row",
Picture = "bracket_box",
Body = new[]
{
"Drag a box across the runs you want held. It fills with hangers at the spacing you set, and each "
+ "one is cut to whatever crosses it — so a pipe added to the bundle later widens the "
+ "cross-piece with no second edit anywhere.",
"A box holding nothing yet still builds, to its own extents. That is how to stand a rack before "
+ "the services that will hang off it exist."
},
Steps = new[]
{
"Choose what the row mounts on — a ceiling, a floor, a wall, or whichever face you drag against.",
"Drag the box across the corridor the runs take.",
"Pull the box's handles afterwards to lengthen the row; the hanger count follows."
}
},
new ArchGuideChapter
{
Heading = "Which runs it picks up",
Body = new[]
{
"A hanger holds every run standing INSIDE its box and nothing outside it. Widen the box to take "
+ "one more pipe in; narrow it to drop one.",
"Order matters where two rows overlap. Drag the bracket's row below a run in Plan Layers to pick "
+ "that run up — the stack IS the answer to what holds what."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "bracket_trapeze", Glyph = "table_rows", Caption = "Trapeze" },
new ArchGuidePlate { Slug = "bracket_rod", Glyph = "vertical_align_bottom", Caption = "Rod" },
new ArchGuidePlate { Slug = "bracket_clamp", Glyph = "radio_button_unchecked", Caption = "Clamp" },
new ArchGuidePlate { Slug = "bracket_strap", Glyph = "horizontal_rule", Caption = "Strap" }
}
},
new ArchGuideChapter
{
Heading = "Depth, clearance and overhang",
Body = new[]
{
"Depth is how far the row stands clear of the face it hangs from, before any run is considered. "
+ "It is the one number that decides whether a bundle clears a beam or fouls it.",
"Clearance is the air left under the cross-piece; overhang is how far the member runs past the "
+ "outermost pipe. Neither is a size — both are margins around what the box already found."
}
}
}
};
static ArchGuide Porch() => new() {
Ident = "subtool_porch",
Title = "Porch",
Lead = "A deck, the posts holding its head up, and optionally a roof over the lot. One drag makes all "
+ "three, and the shell it leans on is subtracted out of the way.",
Chapters = new[]
{
new ArchGuideChapter
{
Heading = "Dragging the deck",
Picture = "porch_drag",
Body = new[]
{
"Drag the deck over the wall it hangs off. Cover a corner and it wraps that corner into two legs; "
+ "touch a porch already standing and the drag joins that one rather than making a second.",
"Dragged wholly inside a room it stands free instead, with no wall to lean on — which is how a "
+ "verandah in the middle of a yard is made."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "porch_against", Glyph = "home", Caption = "Against" },
new ArchGuidePlate { Slug = "porch_free", Glyph = "crop_free", Caption = "Free" }
}
},
new ArchGuideChapter
{
Heading = "Deck drop and head height",
Body = new[]
{
"Deck drop is how far the deck stands above grade. It also decides whether the porch can have "
+ "steps at all — under four inches there is nothing for a flight to climb.",
"Head height is where the posts stop and the beam starts, measured off the deck. The roof section "
+ "is re-cut from where the legs actually stand on every commit, and tucks under whatever eave "
+ "already hangs over it."
}
},
new ArchGuideChapter
{
Heading = "Adding a way down",
Body = new[]
{
"A flight cannot be added while the porch is still a drag — there is no plan to file it into. "
+ "Select the standing porch and add it from its own sheet.",
"Each flight becomes a REAL layer with its own row, handles and sheet, and the railing reads its "
+ "gap back off the flight. So a second way down needs nothing else said anywhere: add it, "
+ "then drag it along the deck to where it belongs."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "opt_porch_deck", Glyph = "layers", Caption = "Deck" },
new ArchGuidePlate { Slug = "opt_railing", Glyph = "fence", Caption = "Railing" },
new ArchGuidePlate { Slug = "opt_porch_roof", Glyph = "roofing", Caption = "Roof" },
new ArchGuidePlate { Slug = "opt_porch_door", Glyph = "door_front", Caption = "Door" }
}
}
}
};
static ArchGuide Fence() => new() {
Ident = "subtool_fence",
Title = "Fence",
Lead = "A clicked line that becomes a boundary: precast slabs, palisade, picket, guardrail, catenary, a "
+ "plastered parapet or a retaining wall. One run, one style, bays divided along it.",
Chapters = new[]
{
new ArchGuideChapter
{
Heading = "Laying the line",
Picture = "fence_line",
Steps = new[]
{
"Click each point the line turns at.",
"Click the first node again to close the run into a loop.",
"Or press Finish in the footer to leave it open, Cancel to throw it away."
},
Body = new[]
{
"Follow terrain drapes every node onto the ground under it, which is what a boundary wall on a "
+ "sloping plot needs. Turn it off and the run lies flat on the storey instead."
}
},
new ArchGuideChapter
{
Heading = "How the ground is taken",
Body = new[]
{
"The run's ground rule decides what happens between two nodes at different heights. STEP keeps "
+ "every bay level and drops between them, which is how a precast wall is really built. RAKE "
+ "tilts each bay to follow the slope. LEVEL ignores the fall altogether."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "ground_step", Glyph = "stairs", Caption = "Step" },
new ArchGuidePlate { Slug = "ground_rake", Glyph = "landscape", Caption = "Rake" },
new ArchGuidePlate { Slug = "ground_level", Glyph = "horizontal_rule", Caption = "Level" }
}
},
new ArchGuideChapter
{
Heading = "Gates, topping and wear",
Body = new[]
{
"A zero-width gate is no gate, so the width IS the switch. Set where along the run it falls and "
+ "how wide it opens, and the bays part around it.",
"Electric topping hangs live strands off brackets over the head. It needs at least one bracket to "
+ "stand on, so the bracket count is what turns it on at all.",
"Disrepair is judged after a run is standing rather than before it is drawn, which is why it opens "
+ "folded. Seed re-rolls which panels are worn; wear and broken decide how many."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "barrier_precastslab", Glyph = "view_week", Caption = "Precast" },
new ArchGuidePlate { Slug = "barrier_palisade", Glyph = "density_medium", Caption = "Palisade" },
new ArchGuidePlate { Slug = "barrier_solid", Glyph = "rectangle", Caption = "Parapet" },
new ArchGuidePlate { Slug = "barrier_retaining", Glyph = "foundation", Caption = "Retaining" }
}
}
}
};
static ArchGuide Road() => new() {
Ident = "subtool_road",
Title = "Road",
Lead = "A clicked centreline carrying a whole section with it — carriageway, kerbs, pavements, markings and "
+ "an optional barrier down either side. Everything else in this shell hangs off a road.",
Chapters = new[]
{
new ArchGuideChapter
{
Heading = "Laying the centreline",
Picture = "road_line",
Steps = new[]
{
"Click each node of the centreline.",
"Click the first node again to close a loop.",
"Or press Finish in the footer to leave the run open-ended."
},
Body = new[]
{
"Tangent mode is per NODE, not per road, so a run can turn a hard corner and then curve away from "
+ "it. Switch between spline and straight mid-run and only the nodes clicked afterwards change."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "road_spline", Glyph = "gesture", Caption = "Spline" },
new ArchGuidePlate { Slug = "road_straight", Glyph = "timeline", Caption = "Straight" }
}
},
new ArchGuideChapter
{
Heading = "Deck height",
Body = new[]
{
"Deck height lifts the nodes clicked after it clear of the ground. Raise it before the middle "
+ "nodes to carry a run over something, drop it again for the far end, then span the raised "
+ "stretch with the Bridge tool.",
"Nothing else in the shell can put a centreline in the air — a bridge deck IS the road's own "
+ "surface, so its height is whatever height its nodes were clicked at."
}
},
new ArchGuideChapter
{
Heading = "Ground",
Body = new[]
{
"FOLLOW TERRAIN drapes the centreline over the ground as it is clicked. STAMP TERRAIN pushes the "
+ "ground to meet the road once it stands. They are independent: a road can follow a hill "
+ "without flattening it, or ignore it and cut through.",
"Neither height lands on the grid ladder. A rung is coarser than the whole ride and would round "
+ "the camber away, which is a road laid in the ground rather than on it."
}
}
}
};
static ArchGuide Bridge() => new() {
Ident = "subtool_bridge",
Title = "Bridge",
Lead = "A span over a gap, with piers standing down to the terrain and clear of whatever runs beneath. It "
+ "is dragged onto roads, never into open ground.",
Chapters = new[]
{
new ArchGuideChapter
{
Heading = "Two drags, two meanings",
Picture = "bridge_span",
Body = new[]
{
"Drag from one road to ANOTHER and the two are joined into one run and the gap between them "
+ "spanned. The near road keeps its name and its section; the far one is absorbed, and the "
+ "easing through the join belongs to neither centreline until it exists.",
"Drag along a SINGLE road instead and it bridges that stretch of it — the way a viaduct carries a "
+ "road that was already continuous over the valley under it."
}
},
new ArchGuideChapter
{
Heading = "Where the deck sits",
Body = new[]
{
"The deck IS the road's surface, so its height is the height its nodes are at. A bridge does not "
+ "lift a road: raise the road's deck height with the Road tool first, then span it.",
"Piers are placed down the span and cut to the ground under each one, stepping clear of any road "
+ "crossing beneath. A span too short to carry piers is refused outright rather than built flat."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "pier_columns", Glyph = "circle", Caption = "Columns" },
new ArchGuidePlate { Slug = "pier_piers", Glyph = "view_column", Caption = "Piers" },
new ArchGuidePlate { Slug = "pier_blade", Glyph = "vertical_shades", Caption = "Blade" }
}
},
new ArchGuideChapter
{
Heading = "Types and live editing",
Body = new[]
{
"A bridge IS its structure, so picking a type REPLACES it whole rather than merging fields into "
+ "it. Types are read from .bridgetype.json on disk and can be reloaded without a restart.",
"The span you just made stays live: the controls keep pointing at it until you author something "
+ "else, at which point they go back to seeding the next drag. The panel says which."
}
}
}
};
static ArchGuide Tunnel() => new() {
Ident = "subtool_tunnel",
Title = "Tunnel",
Lead = "A bore through the ground between two ends of road, with portals standing in the bank rather than "
+ "in the open. The same two drags as the Bridge tool, aimed downward.",
Chapters = new[]
{
new ArchGuideChapter
{
Heading = "Two drags, two meanings",
Picture = "tunnel_bore",
Body = new[]
{
"Drag from one road to ANOTHER to join them and bore through everything between. The near road "
+ "keeps its name and section; the far one is absorbed into it.",
"Drag along a SINGLE road to tunnel a stretch of one that already runs through the hill.",
"Both ends then walk INWARD to where the hill actually starts, so the portals end up standing in "
+ "the bank instead of out in the open air at the coordinates you dragged to."
}
},
new ArchGuideChapter
{
Heading = "Bored, or cut and cover",
Body = new[]
{
"BORED leaves the hill standing over the span when the terrain is stamped, and the hole through "
+ "it is yours to paint in the terrain editor. That is a real tunnel.",
"Turn it off and the ground is carved down to the road instead — a box in a cutting, which is what "
+ "an underpass actually is. The note on the drag says how much cover the crown has, and says "
+ "so plainly when there is none."
},
Plates = new[]
{
new ArchGuidePlate { Slug = "bore_box", Glyph = "crop_square", Caption = "Box" },
new ArchGuidePlate { Slug = "bore_arch", Glyph = "arch", Caption = "Arch" },
new ArchGuidePlate { Slug = "opt_bored", Glyph = "landslide", Caption = "Bored" }
}
},
new ArchGuideChapter
{
Heading = "Portals and walkways",
Body = new[]
{
"Portals are the headwalls and wing walls at both mouths — the collar, hood and coping that make a "
+ "bore read as built rather than drilled. They are the part seen from the street, which is "
+ "why they carry their own row of numbers under the tick.",
"Walkways run inside the bore down either side, raised off the invert. Their width eats into the "
+ "clearance the carriageway gets, so a narrow bore with both walkways is a tight one."
}
},
new ArchGuideChapter
{
Heading = "Types and live editing",
Body = new[]
{
"A tunnel IS its structure: picking a type replaces it whole and never merges fields. Any bays "
+ "carved off the bore belong to the bore rather than to its kind, so re-typing keeps them.",
"The bore you just drove stays live until you author something else, at which point the controls "
+ "go back to seeding the next drag."
}
}
}
};
}