Files
gogobee/internal/plugin/zone_graph_feywild_crossing.go
prosolis dcef2ba734 Branching zones G8f: Feywild Crossing woven forks
T4 zone, sixth authored graph. Shape: woven forks — two first-stage
forks each lead to a second-stage fork; hag_circle is shared between
both first-stage paths while time_eddy (grove-only) and
illusion_garden (marsh-only, secret) are exclusive to one side.
Captures the Feywild theme of "the path you walked is not the path
you arrived on."

First authored zone with LockStatCheck CHA, completing the stat
roster (CHA joins STR/DEX/INT/WIS in shipping zones). Also the first
zone where fork1 has no LockNone option — both first-stage edges are
locked (CHA DC 14 vs. Perception DC 14), forcing the player to commit
to whichever check they're stronger at.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 16:57:48 -07:00

82 lines
4.6 KiB
Go

package plugin
// Phase G8f — Feywild Crossing branching graph.
//
// T4 zone. Shape: woven forks — two first-stage forks each lead to a
// second-stage fork; the inner nodes partially overlap so the player's
// first choice does not fully determine which second-stage rooms they
// can reach. Captures the Feywild theme of "the path you walked is
// not the path you arrived on."
//
// entry → twilight_path → fork1
// ├─[CHA DC 14]── glamoured_grove ─┬─ hag_circle (elite) ─┐
// │ └─[DEX DC 15]── time_eddy ─┤
// │ ├── boss
// └─[Perception DC 14]── wisp_marsh ─┬─ hag_circle ──────────┤
// └─[Perception DC 16]── illusion_garden (secret) ─┘
//
// hag_circle is reachable from BOTH first-stage paths — the elite
// encounter is the "you'll meet her either way" room. time_eddy is
// only reachable via the grove (CHA path); illusion_garden is only
// reachable via the marsh (Perception path).
//
// First authored zone using LockStatCheck CHA — every prior secret/
// gate has been Perception/STR/INT/DEX. Both fork1 entries are locked
// (no LockNone option from fork1) which is the first instance of "no
// free choice"; the player must commit to the lock-check style they're
// stronger at.
func zoneFeywildCrossingGraph() ZoneGraph {
nodes := []ZoneNode{
{NodeID: "feywild_crossing.entry", Kind: NodeKindEntry, IsEntry: true,
Label: "Veil's Edge", PosX: 0, PosY: 2},
{NodeID: "feywild_crossing.twilight_path", Kind: NodeKindExploration,
Label: "Twilight Path", PosX: 1, PosY: 2},
{NodeID: "feywild_crossing.fork1", Kind: NodeKindFork,
Label: "The Bargain Crossroads", PosX: 2, PosY: 2},
{NodeID: "feywild_crossing.glamoured_grove", Kind: NodeKindFork,
Label: "Glamoured Grove", PosX: 3, PosY: 1},
{NodeID: "feywild_crossing.wisp_marsh", Kind: NodeKindFork,
Label: "Wisp Marsh", PosX: 3, PosY: 3},
{NodeID: "feywild_crossing.time_eddy", Kind: NodeKindExploration,
Label: "Time Eddy", PosX: 4, PosY: 0},
{NodeID: "feywild_crossing.hag_circle", Kind: NodeKindElite,
Label: "Hag Circle", PosX: 4, PosY: 2},
{NodeID: "feywild_crossing.illusion_garden", Kind: NodeKindSecret,
Label: "Illusion Garden", PosX: 4, PosY: 4,
Content: ZoneNodeContent{LootBias: 2.0}},
{NodeID: "feywild_crossing.boss", Kind: NodeKindBoss, IsBoss: true,
Label: "Court of the Antlered Queen", PosX: 5, PosY: 2},
}
edges := []ZoneEdge{
{From: "feywild_crossing.entry", To: "feywild_crossing.twilight_path", Lock: LockNone},
{From: "feywild_crossing.twilight_path", To: "feywild_crossing.fork1", Lock: LockNone},
// Fork1 — both options are locked (CHA vs. Perception).
{From: "feywild_crossing.fork1", To: "feywild_crossing.glamoured_grove",
Lock: LockStatCheck, LockData: map[string]any{"stat": "CHA", "dc": 14},
Hint: "a starlight creature offering a deal — you'd have to play along", Weight: 1},
{From: "feywild_crossing.fork1", To: "feywild_crossing.wisp_marsh",
Lock: LockPerception, LockData: map[string]any{"dc": 14},
Hint: "wisp-light flickering between two trees — they look like the same tree", Weight: 1},
// Grove → hag_circle (open) or time_eddy (DEX).
{From: "feywild_crossing.glamoured_grove", To: "feywild_crossing.hag_circle", Lock: LockNone, Weight: 1},
{From: "feywild_crossing.glamoured_grove", To: "feywild_crossing.time_eddy",
Lock: LockStatCheck, LockData: map[string]any{"stat": "DEX", "dc": 15},
Hint: "the seconds run sideways here — sidestep at the right one", Weight: 2},
// Marsh → hag_circle (shared) or illusion_garden (high Perception secret).
{From: "feywild_crossing.wisp_marsh", To: "feywild_crossing.hag_circle", Lock: LockNone, Weight: 1},
{From: "feywild_crossing.wisp_marsh", To: "feywild_crossing.illusion_garden",
Lock: LockPerception, LockData: map[string]any{"dc": 16},
Hint: "a garden visible only when you don't look directly at it", Weight: 2},
// All three second-stage nodes terminate at boss.
{From: "feywild_crossing.hag_circle", To: "feywild_crossing.boss", Lock: LockNone},
{From: "feywild_crossing.time_eddy", To: "feywild_crossing.boss", Lock: LockNone},
{From: "feywild_crossing.illusion_garden", To: "feywild_crossing.boss", Lock: LockNone},
}
return BuildGraph(ZoneFeywildCrossing, nodes, edges)
}
func init() {
registerZoneGraph(zoneFeywildCrossingGraph())
}