mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
R1: split "where am I" from "how far have I walked"
Backtracking (revisit R2) breaks the assumption every zone-run caller quietly relied on: that CurrentRoom == len(VisitedNodes)-1. Position and progress have been the same number only because navigation was forward-only. Split them. CurrentRoom is now the first-entry index of CurrentNode in VisitedNodes -- the room number the player was shown on the way in, and the salt that enemy/trap/harvest/encounter keys hash. A revisited room therefore resolves to the same room. RoomsTraversed is a new monotonic step counter, persisted, backfilled from visited_nodes for in-flight rows. The audit found only two progress-shaped reads. narrationCadence moves to RoomsTraversed so a backtracking player draws fresh flavor rather than replaying the entry-room lines. The other was a latent bug: zoneCmdGo labelled the room it moved into as CurrentRoom+1, which is only correct at the frontier; advanceZoneRunNode now returns the true path index. VisitedNodes becomes an ordered set and RoomsCleared becomes idempotent -- both no-ops while navigation is forward-only, both load-bearing after R2. No player-visible behavior change. Nothing to route off RoomsTraversed for threat/SU: verified at HEAD that movement charges neither. Threat comes from combat, supplies burn per day. The revisit plan's cost model claimed otherwise and has been corrected -- R2's "discount" is really a net-new cost decision.
This commit is contained in:
@@ -315,7 +315,7 @@ func recordRoomCleared(runID string) (*DungeonRun, error) {
|
||||
if !r.IsActive() {
|
||||
return nil, ErrNoActiveRun
|
||||
}
|
||||
cleared := append(r.RoomsCleared, r.CurrentRoom)
|
||||
cleared := appendClearedRoom(r.RoomsCleared, r.CurrentRoom)
|
||||
clearedJSON, _ := json.Marshal(cleared)
|
||||
if _, err := db.Get().Exec(`
|
||||
UPDATE dnd_zone_run
|
||||
@@ -376,28 +376,36 @@ func completeRunAtNode(runID string, boss bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// advanceZoneRunNode moves a run to nextNode: appends to visited_nodes,
|
||||
// sets current_node, and clears any pending fork prompt. Caller is
|
||||
// expected to have already called recordRoomCleared for the prior node.
|
||||
func advanceZoneRunNode(runID, nextNode string) error {
|
||||
// advanceZoneRunNode moves a run to nextNode: records the node entry in
|
||||
// visited_nodes, sets current_node, bumps the traversal counter, and clears
|
||||
// any pending fork prompt. Caller is expected to have already called
|
||||
// recordRoomCleared for the prior node.
|
||||
//
|
||||
// Returns the moved-to room's path index so callers can label it without
|
||||
// assuming CurrentRoom+1 — an assumption that only holds while the player
|
||||
// is walking the frontier.
|
||||
func advanceZoneRunNode(runID, nextNode string) (int, error) {
|
||||
r, err := getZoneRun(runID)
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
if r == nil {
|
||||
return ErrNoActiveRun
|
||||
return 0, ErrNoActiveRun
|
||||
}
|
||||
visited := append(r.VisitedNodes, nextNode)
|
||||
visited := appendVisited(r.VisitedNodes, nextNode)
|
||||
visitedJSON, _ := json.Marshal(visited)
|
||||
_, err = db.Get().Exec(`
|
||||
if _, err := db.Get().Exec(`
|
||||
UPDATE dnd_zone_run
|
||||
SET current_node = ?,
|
||||
visited_nodes = ?,
|
||||
node_choices = '{}',
|
||||
rooms_traversed = rooms_traversed + 1,
|
||||
last_action_at = CURRENT_TIMESTAMP
|
||||
WHERE run_id = ?`,
|
||||
nextNode, string(visitedJSON), runID)
|
||||
return err
|
||||
nextNode, string(visitedJSON), runID); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return pathIndexOf(visited, nextNode), nil
|
||||
}
|
||||
|
||||
// resolveForkChoice takes a 1-based choice index against a pending
|
||||
|
||||
Reference in New Issue
Block a user