Adv 2.0 L2: rip legacy arena combat path; boss flow is the only path

Cancels the planned ARENA_BOSS_FLOW soak. The boss flow is shipped
unconditionally with no legacy fallback — boss-flow errors now surface
to the player and abort the round rather than silently falling back to
the old CombatPower path.

Deleted:
- runArenaCombat (combat_bridge.go) — legacy CombatPower-vs-Lethality
  arena combat driver.
- RenderCombatLogArena, renderArenaOutcome (combat_narrative.go) — legacy
  arena renderers. RenderCombatLogArena was a thin alias for
  RenderCombatLog; renderArenaOutcome was already dead.
- renderArenaCombatFinalMessage (combat_bridge.go) — legacy "rewards +
  closer" trailing text.
- arenaWinCloser, arenaLoseCloser (adventure_arena_combat.go) — flavor
  helpers that only fed the deleted renderers. File now just holds
  arenaParticipationXP.
- arenaBossFlowEnabled + the ARENA_BOSS_FLOW env var (adventure_arena.go,
  .env.example). The env gate served only the now-removed fallback.
- sendArenaCombatMessages (adventure_arena.go) — wrapper that switched
  pacing between boss flow and legacy. Replaced with direct
  sendZoneCombatMessages calls at the three call sites.
- TestArenaBossFlowEnabled (bossflow test) and
  TestRenderCombatLogArena_ProducesPhaseMessages (narrative test).

Simplified resolveArenaRound / resolveArenaSurvival / resolveArenaDeath:
the bossNarr-vs-nil branches collapsed since narration is now always
produced by resolveArenaBoss. Equipment degradation and the death-save
reprieve hook are unchanged — both already worked off the boss-flow
CombatResult.

Migration doc (§4) updated to record the cancellation and the
remaining tuning approach (playtest-driven, no flag soak window).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-09 09:06:38 -07:00
parent 85a80e5c40
commit 3b4dfa44d3
9 changed files with 34 additions and 339 deletions

View File

@@ -70,11 +70,6 @@ func RenderCombatLog(result CombatResult, playerName, enemyName string) []string
return msgs
}
// RenderCombatLogArena is RenderCombatLog for arena fights.
func RenderCombatLogArena(result CombatResult, playerName, enemyName string) []string {
return RenderCombatLog(result, playerName, enemyName)
}
type phaseGroup struct {
Name string
Events []CombatEvent
@@ -297,35 +292,6 @@ func renderOutcome(result CombatResult, playerName, enemyName string, reward int
return sb.String()
}
func renderArenaOutcome(result CombatResult, playerName, enemyName string, reward int64, xp int, tier, round int) string {
var sb strings.Builder
if result.PlayerWon {
sb.WriteString(fmt.Sprintf("💀 **%s** has been defeated.\n", enemyName))
closer := arenaWinCloser(enemyName, round)
sb.WriteString(closer + "\n")
sb.WriteString(fmt.Sprintf("🏆 +%d XP | €%d earned", xp, reward))
} else {
sb.WriteString("The healers are already moving.\n")
sb.WriteString("💀 **Defeated.**\n")
closer := arenaLoseCloser(enemyName, round)
sb.WriteString(closer + "\n")
sb.WriteString(fmt.Sprintf("+%d XP (participation) | Back tomorrow.", arenaParticipationXP))
}
if result.SniperKilled {
sb.WriteString("\n" + pickRand(narrativeSniperKill))
}
if result.MistyHealed {
sb.WriteString("\n🌿 Misty's healing made the difference.")
}
if result.PetAttacked {
sb.WriteString("\n🐾 Your pet contributed to the fight.")
}
return sb.String()
}
func pickRand(pool []string) string {
return pool[rand.IntN(len(pool))]
}