Long expeditions D1-c: T3 zones to new 22-26 room band

Both T3 zones follow the D1-a/b pattern: extend the graph so the longest
entry→boss walk lands in band, keep the zone's authored topology intact.

  manor_blackspire (T3): 11 → 35 nodes, longest 23 (band 22-26)
  underforge       (T3): 10 → 31 nodes, longest 23 (band 22-26)

Topology preserved per zone:
- Manor: two-stacked-3-way forks identity + full lock-kind coverage
  (LockNone, LockPerception, LockStatCheck, LockLevelMin). Adds the
  missing Trap anchor (Cursed Threshold). All six spokes are 3 mid-nodes
  so route choice is loot/encounter character, not shortcut economics.
- Underforge: one-way-descent gauntlet identity preserved — 17-node
  linear preamble through the existing Cooling River (TRAP) and Magma
  Chamber (ELITE), single 3-way antechamber fork before boss. All three
  antechamber spokes are 4 mid-nodes.

MinRooms/MaxRooms re-pitched 7-9 → 22-26 so the dice fallback also lands
in band for any future graphless variant.
This commit is contained in:
prosolis
2026-05-27 17:46:38 -07:00
parent 89edc76829
commit bbc25fe958
5 changed files with 357 additions and 102 deletions

View File

@@ -7,23 +7,39 @@ func TestUnderforgeGraph_Registered(t *testing.T) {
if !ok {
t.Fatal("zoneUnderforgeGraph not registered")
}
if len(g.Nodes) != 10 {
t.Errorf("nodes = %d, want 10", len(g.Nodes))
// Long-expedition D1-c widened this zone from 10 → 31 nodes so the
// longest entry→boss walk lands in the T3 [22,26] traversal band.
if len(g.Nodes) != 31 {
t.Errorf("nodes = %d, want 31", len(g.Nodes))
}
}
// TestUnderforgeGraph_LinearPreamble locks in the gauntlet shape:
// the first five nodes after entry must each have exactly one outgoing
// edge (linear chain). If a future edit splits the preamble, this test
// catches it — that change should re-author the shape comment too.
// TestUnderforgeGraph_LinearPreamble locks in the gauntlet identity:
// every node from entry through resonance_passage has exactly one
// outgoing edge — the only decision in the zone is the antechamber
// 3-way at the very end. D1-c extends the chain but preserves the
// "one-way descent" intent ("Kharak Dûn is a one-way descent — there
// is no scenic route").
func TestUnderforgeGraph_LinearPreamble(t *testing.T) {
g := zoneUnderforgeGraph()
for _, id := range []string{
"underforge.entry",
"underforge.sealed_gate",
"underforge.sealed_threshold",
"underforge.wardstone_arch",
"underforge.forge_descent",
"underforge.vapor_steps",
"underforge.slag_warrens",
"underforge.cooling_river",
"underforge.bellows_chamber",
"underforge.cinder_walk",
"underforge.magma_chamber",
"underforge.emberforge_hall",
"underforge.ashfall_corridor",
"underforge.smelting_vault",
"underforge.foreman_landing",
"underforge.broken_crucible",
"underforge.great_anvil",
"underforge.resonance_passage",
} {
outs := g.outgoingEdges(id)
if len(outs) != 1 {