mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 17:02:42 +00:00
adventure: Tier 6 postgame "Mythic" dungeons (P1–P7 calibration)
Five post-game dungeons above the T5 ceiling, gated on both T5 bosses beaten + level 18. Opt-in endgame: deadly solo, clearable by a party with Pete + pets. - P1 gating: postgameUnlocked (T5 clears + level floor), zonesForLevel excludes T6 unconditionally; wired into startZoneRun, !zone/!expedition, party accept, boredom picker, and the list dividers. - P2 bestiary: 15 elites + 5 signature bosses (Layer-1 stat blocks). - P3 zone defs + 4-region registries; ZoneLootEntry.BossOnly. - P4 five zone graphs on a shared builder (44–52 rooms, no soft-lock; Ossuary secret Verse nodes). - P5 loot: BossOnly enforced; signature items are real registry magic items; five Thom pity recipes off the per-zone crafting anchors. - P6 narration/flavor (5 files), T6 achievements, Pete stays zone-parametric. - P7 (in progress): sim can now reach gated T6 (SimRunner.SeedPostgameUnlock + IsPostgameZone). First calibration pass on millenia — hardened ossuary + drowned_star, softened first_hoard + unplace; last_meridian in band. Fix: party members were refused from every T6 zone because expeditionCmdAccept ran the level gate (which excludes T6) before the postgame check — the intended party endgame was unreachable. Route T6 through postgameUnlocked. Regression tests added.
This commit is contained in:
61
internal/plugin/zone_graph_ossuary_ascendant_test.go
Normal file
61
internal/plugin/zone_graph_ossuary_ascendant_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package plugin
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestOssuaryAscendantGraph_Invariants(t *testing.T) {
|
||||
assertPostgameGraph(t, ZoneOssuaryAscendant, zoneOssuaryAscendantGraph)
|
||||
}
|
||||
|
||||
// TestOssuaryAscendantGraph_ThreeVerses verifies the signature set-piece:
|
||||
// three NodeKindSecret Verses, each reached through a LockPerception spur
|
||||
// edge (the gate rides the fork→threshold edge; the edge into the Verse
|
||||
// itself is unlocked).
|
||||
func TestOssuaryAscendantGraph_ThreeVerses(t *testing.T) {
|
||||
g := zoneOssuaryAscendantGraph()
|
||||
|
||||
verses := []string{"ossuary_ascendant.f1b2", "ossuary_ascendant.f2b2", "ossuary_ascendant.cap32"}
|
||||
for _, v := range verses {
|
||||
n, ok := g.Nodes[v]
|
||||
if !ok {
|
||||
t.Errorf("missing Verse node %s", v)
|
||||
continue
|
||||
}
|
||||
if n.Kind != NodeKindSecret {
|
||||
t.Errorf("Verse %s kind = %q, want secret", v, n.Kind)
|
||||
}
|
||||
}
|
||||
if got := countSecretNodes(g); got != 3 {
|
||||
t.Errorf("secret nodes = %d, want 3 (the Phylactery Verses)", got)
|
||||
}
|
||||
|
||||
// Each Verse's spur is entered through a Perception gate.
|
||||
percThresholds := map[string]bool{
|
||||
"ossuary_ascendant.f1b1": false,
|
||||
"ossuary_ascendant.f2b1": false,
|
||||
"ossuary_ascendant.cap31": false,
|
||||
}
|
||||
for _, outs := range g.Edges {
|
||||
for _, e := range outs {
|
||||
if e.Lock == LockPerception {
|
||||
if _, ok := percThresholds[e.To]; ok {
|
||||
percThresholds[e.To] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for th, gated := range percThresholds {
|
||||
if !gated {
|
||||
t.Errorf("Verse threshold %s is not behind a LockPerception edge", th)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func countSecretNodes(g ZoneGraph) int {
|
||||
n := 0
|
||||
for _, node := range g.Nodes {
|
||||
if node.Kind == NodeKindSecret {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
Reference in New Issue
Block a user