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:
@@ -136,6 +136,30 @@ func (s *SimRunner) BuildCharacter(uid id.UserID, class DnDClass, level int) (*D
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// SeedPostgameUnlock makes the synthetic user satisfy postgameUnlocked's
|
||||
// T5-clear gate by writing two completed, boss-defeated dnd_expedition rows
|
||||
// (dragons_lair + abyss_portal) into the sim's throwaway DB. Without this the
|
||||
// P1 gate in startZoneRun rejects every T6 zone ("did not persist after start")
|
||||
// and the sim can't reach post-game content. Sim/test-only — the live gate is
|
||||
// unchanged. Idempotent enough for a fresh per-run DB; call once after
|
||||
// BuildCharacter/PrepareRealCharacter when the target zone IsPostgameZone.
|
||||
func (s *SimRunner) SeedPostgameUnlock(uid id.UserID) error {
|
||||
for i, z := range []ZoneID{ZoneDragonsLair, ZoneAbyssPortal} {
|
||||
if _, err := db.Get().Exec(
|
||||
`INSERT INTO dnd_expedition (expedition_id, user_id, zone_id, status, boss_defeated)
|
||||
VALUES (?, ?, ?, ?, 1)`,
|
||||
fmt.Sprintf("sim-unlock-%s-%d", uid, i), string(uid), string(z), ExpeditionStatusComplete,
|
||||
); err != nil {
|
||||
return fmt.Errorf("seed T5 clear %s: %w", z, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsPostgameZone exports the T6 predicate so the sim binary (a separate
|
||||
// package) can decide whether to call SeedPostgameUnlock before a run.
|
||||
func IsPostgameZone(id ZoneID) bool { return isPostgameZone(id) }
|
||||
|
||||
// PrepareRealCharacter readies an already-persisted character (loaded from a
|
||||
// copy of the prod DB) for a headless run. Unlike BuildCharacter it fabricates
|
||||
// nothing: the character keeps its real race/class/subclass/level, ability
|
||||
|
||||
Reference in New Issue
Block a user