Adv 2.0 D&D Phase R R1: Legacy activity-loop deprecation

Retires the standalone !adventure dungeon/mine/forage/fish daily loop in
favor of !expedition. Gate intercepts legacy 1/2/3/4 + word-form input
and DMs a deprecation notice; town services (shop/blacksmith/rest/thom)
stay on !adventure.

- Delete dead resolveActivity (269 lines) + parseActivityLocation; add
  isLegacyActivityInput + renderLegacyActivityDeprecation.
- Morning-DM menu rewritten to point at !expedition and the !forage etc.
  harvest commands; writeAdvLocationLines removed (sole caller).
- New dnd_r1_migration.go runs archiveOrphanZoneRuns at Init: archives
  any active dnd_zone_run not linked to an active expedition (via
  exp.run_id or region_state.region_runs). Idempotent.
- Pre-existing flake in TestPickEveningRecap_BossOverridesAll fixed
  (E6c pool added entries without literal "boss"; widen substring set).
- Internal helpers (resolveAdvAction, advEligibleLocations, AdvLocation
  tier data, consumable drops) preserved — babysit/scheduler still use
  them passively.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-08 18:58:05 -07:00
parent c3083637ac
commit 8a1d9a16ce
5 changed files with 355 additions and 372 deletions

View File

@@ -353,20 +353,6 @@ func renderRivalNudge(char *AdventureCharacter) string {
rivalName, c.Round, c.Stake, hours)
}
// writeAdvLocationLines renders the eligible-location bullets shown in the
// morning DM. Each line surfaces both the downside (death %) and upside
// (exceptional %) so the menu teaches risk/reward, not just risk.
func writeAdvLocationLines(sb *strings.Builder, locs []AdvEligibleLocation) {
for _, el := range locs {
warn := ""
if el.InPenaltyZone {
warn = " ⚠️"
}
sb.WriteString(fmt.Sprintf(" • %s (Tier %d, ~%.0f%% death · ~%.0f%% exceptional%s)\n",
el.Location.Name, el.Location.Tier, el.DeathPct, el.ExceptionalPct, warn))
}
}
func renderAdvMorningDM(char *AdventureCharacter, equip map[EquipmentSlot]*AdvEquipment, balance float64, bonuses *AdvBonusSummary, holidayName string) string {
var sb strings.Builder
@@ -456,38 +442,26 @@ func renderAdvMorningDM(char *AdventureCharacter, equip map[EquipmentSlot]*AdvEq
sb.WriteString("\n")
}
// Location choices
// Phase R1 — the daily activity loop (dungeon/mine/forage/fish) has been
// retired in favor of the expedition system. The menu now shows the new
// entry points for adventuring and keeps the still-active town services.
sb.WriteString("**🗺️ Adventure** — head into a zone:\n")
sb.WriteString("• `!expedition` — overview & open expeditions\n")
sb.WriteString("• `!expedition start <zone>` — begin a new run\n")
sb.WriteString("• `!forage` · `!mine` · `!scavenge` · `!fish` · `!essence` · `!commune` — harvest in cleared rooms\n")
if inCoop {
sb.WriteString("**1⃣ Dungeon:** _(off in the Co-op, no solo combat — `!coop status` for run state)_\n")
} else if char.CanDoCombat(isHol) {
sb.WriteString("**1⃣ Dungeon:**\n")
writeAdvLocationLines(&sb, advEligibleLocations(char, equip, AdvActivityDungeon, bonuses))
} else {
sb.WriteString("**1⃣ Dungeon:** _(no combat actions remaining)_\n")
sb.WriteString(fmt.Sprintf("_(combat is locked while you're in Co-op #%d — `!coop status` for run state)_\n", coopRun.ID))
}
sb.WriteString("\n")
if char.CanDoHarvest(isHol) {
sb.WriteString("**2⃣ Mine:**\n")
writeAdvLocationLines(&sb, advEligibleLocations(char, equip, AdvActivityMining, bonuses))
sb.WriteString("**🏘️ In town:**\n")
sb.WriteString("• `5` / `shop` — buy/sell gear and loot\n")
sb.WriteString("• `6` / `blacksmith` — repair damaged equipment\n")
sb.WriteString("• `7` / `rest` — skip today, bank your luck\n")
sb.WriteString("• `!thom` — visit Krooke Realty 🏠\n\n")
sb.WriteString("**3⃣ Forage:**\n")
writeAdvLocationLines(&sb, advEligibleLocations(char, equip, AdvActivityForaging, bonuses))
sb.WriteString("**4⃣ Fish:**\n")
writeAdvLocationLines(&sb, advEligibleLocations(char, equip, AdvActivityFishing, bonuses))
} else {
sb.WriteString("**2⃣ Mine:** _(no harvest actions remaining)_\n")
sb.WriteString("**3⃣ Forage:** _(no harvest actions remaining)_\n")
sb.WriteString("**4⃣ Fish:** _(no harvest actions remaining)_\n")
}
sb.WriteString("**5⃣ Shop** — buy/sell gear and loot\n")
sb.WriteString("**6⃣ Blacksmith** — repair damaged equipment\n")
sb.WriteString("**7⃣ Rest** — skip today, bank your luck\n")
sb.WriteString("**8⃣ Thom** — `!thom` visit Krooke Realty 🏠\n\n")
sb.WriteString("Reply with the number and location, e.g: `1 Soggy Cellar`\n")
sb.WriteString("You have until midnight UTC to choose.")
sb.WriteString("Reply with a number for in-town services, or run an expedition command directly.\n")
sb.WriteString("You have until midnight UTC to rest.")
return sb.String()
}