Adv 2.0 D&D Phase 12 E5: Extraction & Resume

Voluntary !extract burns 1 day, flips status to 'extracting', keeps
all rewards, resumable for 7 real days. Forced extraction (Abyss
collapse, future HP-0/supply-0 hooks) flips to 'abandoned' and applies
the §10.2 20% coin tax via the cycle layer's euro handle. !resume
within the 7-day window repurchases supplies and restores threat &
temporal stacks as-is; expired rows demote to failed.

getActiveExpedition / briefing / recap loaders narrow to status='active'
so 'extracting' rows don't get phantom day rollovers. Reuses
flavor.ExtractionVoluntary, ExtractionForced, ExpeditionResume from
twinbee_expedition_flavor.go.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-08 16:36:05 -07:00
parent a199efd773
commit d179ca27a7
8 changed files with 461 additions and 9 deletions

View File

@@ -176,6 +176,7 @@ func startExpedition(userID id.UserID, zoneID ZoneID, runID string, supplies Exp
}
// getActiveExpedition returns the player's in-flight expedition, or (nil, nil).
// 'extracting' rows are post-extraction (resumable) — see getResumableExpedition.
func getActiveExpedition(userID id.UserID) (*Expedition, error) {
row := db.Get().QueryRow(`
SELECT expedition_id, user_id, zone_id, run_id, status,
@@ -186,7 +187,7 @@ func getActiveExpedition(userID id.UserID) (*Expedition, error) {
last_briefing_at, last_recap_at, last_activity, completed_at
FROM dnd_expedition
WHERE user_id = ?
AND status IN ('active', 'extracting')
AND status = 'active'
ORDER BY start_date DESC
LIMIT 1`, string(userID))
e, err := scanExpedition(row)