Branching zones G7: Crypt of Valdris POC graph

Hand-authored zoneCryptValdrisGraph() (8 nodes incl. fork +
Perception DC 15 secret reliquary) self-registers at init. Two
surgical bridges so new runs traverse the authored graph when
GOGOBEE_BRANCHING_ZONES=1: startZoneRun seeds current_node from
g.Entry, and DungeonRun.CurrentRoomType resolves via the live
node's kind so divergent paths (secret_chamber) dispatch through
the right resolver. Gate off is bit-identical to pre-G7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-09 15:28:58 -07:00
parent 893d3dacad
commit 90ff7666bd
4 changed files with 234 additions and 8 deletions

View File

@@ -85,8 +85,24 @@ func (r *DungeonRun) IsActive() bool {
}
// CurrentRoomType returns the type of the room the player is currently
// standing in (CurrentRoom is 0-indexed). Returns "" if out of range.
// standing in. In gated graph mode (GOGOBEE_BRANCHING_ZONES=1) with a
// hand-authored ZoneGraph registered for the run's zone, the live
// CurrentNode's kind is authoritative — that's the only way side paths
// (e.g. the Crypt of Valdris secret chamber) resolve to the right
// room-type when the player diverges from the canonical RoomSeq. The
// legacy RoomSeq fallback covers gate-off runs and runs in zones whose
// graph is still the linear-compiled one. Returns "" if no resolution
// is possible.
func (r *DungeonRun) CurrentRoomType() RoomType {
if branchingZonesEnabled() && r.CurrentNode != "" {
if _, authored := zoneGraphRegistry[r.ZoneID]; authored {
if g, ok := loadZoneGraph(r.ZoneID); ok {
if n, exists := g.Nodes[r.CurrentNode]; exists {
return nodeKindToRoomType(n.Kind)
}
}
}
}
if r.CurrentRoom < 0 || r.CurrentRoom >= len(r.RoomSeq) {
return ""
}
@@ -212,8 +228,16 @@ func startZoneRun(userID id.UserID, zoneID ZoneID, dndLevel int, rng *rand.Rand)
}
// G4 dual-write: persist the entry node id and seed visited_nodes
// with it, so navigation surfaces in G5 can read graph state without
// further migration.
// further migration. G7: when graph mode is on AND the zone has a
// hand-authored graph, start at that graph's Entry node so the player
// actually traverses the authored topology rather than falling off
// into the legacy `<zone>.r1` namespace.
entryNode := deriveLegacyNodeID(zoneID, 0)
if branchingZonesEnabled() {
if g, ok := zoneGraphRegistry[zoneID]; ok {
entryNode = g.Entry
}
}
visitedJSON, _ := json.Marshal([]string{entryNode})
run.CurrentNode = entryNode
run.VisitedNodes = []string{entryNode}