mirror of
https://github.com/prosolis/gogobee.git
synced 2026-09-14 10:51:09 +00:00
zones: make locked doors openable and stop autopilot stalling on them
Locks were fully implemented as pass/fail gates and nothing else. A Perception or stat check rolls once per (run, edge), seeded so it can't be reload-scummed — that half shipped in G5, the counterweight never did. A bad roll simply deleted a branch of the graph for the rest of the run, worst for a solo low-WIS character who quietly loses routes they never learn existed. Three changes, one theme: a die roll should not be able to permanently wall a player. Party's best stat answers the check. evaluateEdgeLock read only the acting character's mods, which made a party's rogue and its hired scout decorative at every lock. Fold the whole roster — Pete included, since excluding him would make hiring a scout worth less than the coins it costs — and credit whoever got it open in the fork menu. Thieves' tools as the escape hatch. A utility item (not a ConsumableDef, or the fight engine would spend them for you) sold on Luigi's supplies shelf, consumed by `!zone unlock <n>`. Deliberately not a skeleton key: tools answer the two dice-driven locks only. A key lock is a quest token, a level-min lock is progression, a region-clear lock is structure — none of those are "you rolled badly", so none of them are pickable. Autopilot picks a route instead of parking. The fork timeout was 8h, which reads as "the player gets first say" and behaves as "the expedition stops for a third of a day, at every fork" — a multi-day expedition crosses a lot of forks. 30m keeps a genuine first say for anyone at the keyboard. It now ranks by unvisited-then-edge-weight rather than taking whatever the graph author happened to list first, spends tools when every route is locked, and backtracks a room when it can't do even that, rather than idling into the 24h reaper and losing the player days of progress to a roll they never saw. Sim A/B, same seeds, 90 runs/arm: 43.3% -> 42.2% clear, a single run flipping and well inside the documented noise floor. A party+companion+pet arm runs 31/32 clean through the new roster-folding path.
This commit is contained in:
@@ -188,6 +188,17 @@ func (p *AdventurePlugin) zoneCmdGo(ctx MessageContext, rest string) error {
|
||||
if cerr != nil {
|
||||
return p.SendDM(ctx.Sender, cerr.Error())
|
||||
}
|
||||
return p.commitForkChoice(ctx, run, chosen, "")
|
||||
}
|
||||
|
||||
// commitForkChoice advances the run onto an already-validated fork option and
|
||||
// emits the arrival teaser. Split out of zoneCmdGo so `!zone unlock` — which
|
||||
// reaches the same place by paying for it — cannot drift from the plain
|
||||
// `!zone go` arrival: same region-transition hook, same camp strike, same
|
||||
// boss/elite prompt. header, if set, is printed above the move.
|
||||
func (p *AdventurePlugin) commitForkChoice(
|
||||
ctx MessageContext, run *DungeonRun, chosen pendingChoice, header string,
|
||||
) error {
|
||||
nextIdx, aerr := advanceZoneRunNode(run.RunID, chosen.To)
|
||||
if aerr != nil {
|
||||
return p.SendDM(ctx.Sender, "Couldn't advance: "+aerr.Error())
|
||||
@@ -200,6 +211,7 @@ func (p *AdventurePlugin) zoneCmdGo(ctx MessageContext, rest string) error {
|
||||
fireGraphRegionTransition(run.UserID, fromNode, nextNode)
|
||||
nextRoom := nodeKindToRoomType(nextNode.Kind)
|
||||
var b strings.Builder
|
||||
b.WriteString(header)
|
||||
if kind := autoBreakCampOnMove(ctx.Sender); kind != "" {
|
||||
b.WriteString(fmt.Sprintf("⛺ Camp struck (**%s**) — the party moved on.\n\n", kind))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user