mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 08:52:42 +00:00
Long expeditions D1-e: T5 zones to new 36-44 room band
Closes D1. Both T5 zones follow the D1-a/b/c/d pattern: extend the graph so the longest entry→boss walk lands in band, keep the zone's authored topology intact. Also backfills the missing per-node RegionID authoring against dnd_expedition_region.go — the D1-d deferral note flagged this as a prerequisite for T5. dragons_lair (T5): 12 → 47 nodes, longest 38 (band 36-44) abyss_portal (T5): 13 → 51 nodes, longest 39 (band 36-44) Topology preserved per zone: - Dragon's Lair: 4-region authoring (every node carries a valid RegionID); binary-converging fork1 (ash_bridge TRAP / treasure_vault Perception 15) still converges at the R3 wyrmlings_nest elite; capstone fork2 still 3-way (LockNone / CHA 16 / Perception 17 SECRET LootBias 2.5) with each spur preserving its own named capstone node. New R4 infernax_doors MERGE consolidates the long final hall instead of triplicating it. - Abyss Portal: 4-region authoring; three sequential forks preserved (binary / binary / ternary) — fork1 Perception 16, fork2 CON 16 (full STR/DEX/CON/INT/WIS/CHA roster still covered), fork3 capstone 3-way with reality_seam SECRET LootBias 3.0. New R4 belaxath_doors MERGE consolidates the final tear-approach. MinRooms/MaxRooms re-pitched 9-10 → 36-44 so the dice fallback also lands in band for any future graphless variant.
This commit is contained in:
@@ -7,19 +7,70 @@ func TestDragonsLairGraph_Registered(t *testing.T) {
|
||||
if !ok {
|
||||
t.Fatal("zoneDragonsLairGraph not registered")
|
||||
}
|
||||
if len(g.Nodes) != 12 {
|
||||
t.Errorf("nodes = %d, want 12", len(g.Nodes))
|
||||
// Long-expedition D1-e widened this zone from 12 → 47 nodes so the
|
||||
// longest entry→boss walk lands in the T5 [36,44] traversal band.
|
||||
if len(g.Nodes) != 47 {
|
||||
t.Errorf("nodes = %d, want 47", len(g.Nodes))
|
||||
}
|
||||
}
|
||||
|
||||
// TestDragonsLairGraph_Fork1Converges verifies the binary mid-fork
|
||||
// converges at wyrmlings_nest.
|
||||
func TestDragonsLairGraph_LongestPathInBand(t *testing.T) {
|
||||
g := zoneDragonsLairGraph()
|
||||
got := graphLongestPath(g)
|
||||
if got < 36 || got > 44 {
|
||||
t.Errorf("longest path = %d, want in T5 band [36,44]", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDragonsLairGraph_AllNodesHaveRegion confirms D1-e backfilled the
|
||||
// missing RegionID authoring per dnd_expedition_region.go: every node
|
||||
// carries a non-empty RegionID matching the registry.
|
||||
func TestDragonsLairGraph_AllNodesHaveRegion(t *testing.T) {
|
||||
g := zoneDragonsLairGraph()
|
||||
validRegions := map[string]bool{
|
||||
"dragons_lair_kobold_warrens": true,
|
||||
"dragons_lair_drake_pens": true,
|
||||
"dragons_lair_the_vault": true,
|
||||
"dragons_lair_infernax_chamber": true,
|
||||
}
|
||||
for id, n := range g.Nodes {
|
||||
if n.RegionID == "" {
|
||||
t.Errorf("node %s has empty RegionID — D1-e requires region authoring on every node", id)
|
||||
}
|
||||
if !validRegions[n.RegionID] {
|
||||
t.Errorf("node %s RegionID = %q, not in dnd_expedition_region.go registry", id, n.RegionID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDragonsLairGraph_AllFourRegionsRepresented confirms each authored
|
||||
// region has at least one node.
|
||||
func TestDragonsLairGraph_AllFourRegionsRepresented(t *testing.T) {
|
||||
g := zoneDragonsLairGraph()
|
||||
regions := map[string]int{}
|
||||
for _, n := range g.Nodes {
|
||||
regions[n.RegionID]++
|
||||
}
|
||||
for _, r := range []string{
|
||||
"dragons_lair_kobold_warrens",
|
||||
"dragons_lair_drake_pens",
|
||||
"dragons_lair_the_vault",
|
||||
"dragons_lair_infernax_chamber",
|
||||
} {
|
||||
if regions[r] == 0 {
|
||||
t.Errorf("region %q has no nodes — multi-region invariant broken", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDragonsLairGraph_Fork1Converges verifies the binary mid-fork's
|
||||
// two spurs both converge at wyrmlings_nest (R3 boundary).
|
||||
func TestDragonsLairGraph_Fork1Converges(t *testing.T) {
|
||||
g := zoneDragonsLairGraph()
|
||||
for _, mid := range []string{"dragons_lair.ash_bridge", "dragons_lair.treasure_vault"} {
|
||||
outs := g.outgoingEdges(mid)
|
||||
for _, spurTail := range []string{"dragons_lair.cinder_walk", "dragons_lair.vault_passage"} {
|
||||
outs := g.outgoingEdges(spurTail)
|
||||
if len(outs) != 1 || outs[0].To != "dragons_lair.wyrmlings_nest" {
|
||||
t.Errorf("%s outs = %+v, want single edge to wyrmlings_nest", mid, outs)
|
||||
t.Errorf("%s outs = %+v, want single edge to wyrmlings_nest", spurTail, outs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,9 +94,9 @@ func TestDragonsLairGraph_Fork2Capstone(t *testing.T) {
|
||||
}
|
||||
// Locks escalate: open / CHA 16 / Perception 17 (T5 secret bias).
|
||||
for _, e := range outs {
|
||||
if e.To == "dragons_lair.hoard_pillar" {
|
||||
if e.To == "dragons_lair.hidden_passage" {
|
||||
if dc := lockDataInt(e.LockData, "dc", 0); dc < 17 {
|
||||
t.Errorf("hoard_pillar DC = %d, want >= 17 (T5)", dc)
|
||||
t.Errorf("hoard_pillar spur DC = %d, want >= 17 (T5)", dc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user