From 8afd9494fe09c96bb9a59a616cf9c6d868023398 Mon Sep 17 00:00:00 2001 From: prosolis <5590409+prosolis@users.noreply.github.com> Date: Sat, 9 May 2026 08:20:59 -0700 Subject: [PATCH] =?UTF-8?q?Adv=202.0=20Phase=20L2=20step=206:=20arena=20re?= =?UTF-8?q?nder=20reads=20=E2=86=92=20DnDCharacter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit renderArenaStreakEntry now takes *DnDCharacter and reads c.Level instead of AdventureCharacter.CombatLevel. renderArenaStatus drops its unused *AdventureCharacter arg. Callers in handleArenaMenu / handleArenaStatus updated; menu path uses ensureCharForDnDCmd to fetch (or auto-migrate) the sheet. Tests switched accordingly. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/plugin/adventure_arena.go | 11 +++++++---- internal/plugin/adventure_arena_render.go | 8 ++++---- internal/plugin/adventure_arena_test.go | 17 +++++++---------- internal/plugin/audit_fixes_test.go | 6 +++--- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/internal/plugin/adventure_arena.go b/internal/plugin/adventure_arena.go index dee715f..4a5c47b 100644 --- a/internal/plugin/adventure_arena.go +++ b/internal/plugin/adventure_arena.go @@ -101,7 +101,11 @@ func (p *AdventurePlugin) handleArenaMenu(ctx MessageContext) error { stats := loadArenaPersonalStats(ctx.Sender) monster := arenaGetMonster(1, 1) - text := renderArenaStreakEntry(char, stats, tier, monster) + dndChar, err := p.ensureCharForDnDCmd(ctx.Sender, char) + if err != nil { + return p.SendDM(ctx.Sender, "Failed to load character sheet.") + } + text := renderArenaStreakEntry(dndChar, stats, tier, monster) return p.SendDM(ctx.Sender, text) } @@ -297,8 +301,7 @@ func (p *AdventurePlugin) handleArenaBail(ctx MessageContext) error { } func (p *AdventurePlugin) handleArenaStatus(ctx MessageContext) error { - char, err := loadAdvCharacter(ctx.Sender) - if err != nil { + if _, err := loadAdvCharacter(ctx.Sender); err != nil { return p.SendDM(ctx.Sender, "No adventurer found.") } @@ -307,7 +310,7 @@ func (p *AdventurePlugin) handleArenaStatus(ctx MessageContext) error { return p.SendDM(ctx.Sender, "No active arena run. Start one with `!arena`.") } - return p.SendDM(ctx.Sender, renderArenaStatus(run, char)) + return p.SendDM(ctx.Sender, renderArenaStatus(run)) } func (p *AdventurePlugin) handleArenaStats(ctx MessageContext) error { diff --git a/internal/plugin/adventure_arena_render.go b/internal/plugin/adventure_arena_render.go index 38bedc0..a8858a5 100644 --- a/internal/plugin/adventure_arena_render.go +++ b/internal/plugin/adventure_arena_render.go @@ -8,18 +8,18 @@ import ( // ── Arena Tier Menu ───────────────────────────────────────────────────────── -func renderArenaStreakEntry(char *AdventureCharacter, stats *ArenaPersonalStats, tier *ArenaTier, firstMonster *ArenaMonster) string { +func renderArenaStreakEntry(c *DnDCharacter, stats *ArenaPersonalStats, tier *ArenaTier, firstMonster *ArenaMonster) string { var b strings.Builder b.WriteString("⚔️ **THE ARENA**\n\n") b.WriteString("The Arena is a streak. You start at Tier 1 and fight your way down.\n") b.WriteString("After each tier, you have 30 seconds to bail or you auto-advance.\n") b.WriteString("Death forfeits all accumulated rewards.\n\n") - b.WriteString(fmt.Sprintf("Combat Level: %d\n\n", char.CombatLevel)) + b.WriteString(fmt.Sprintf("Level: %d\n\n", c.Level)) for i := range arenaTiers { t := &arenaTiers[i] - eligible := char.CombatLevel >= t.MinLevel + eligible := c.Level >= t.MinLevel icon := "🔒" if eligible { icon = "⬚" @@ -91,7 +91,7 @@ func renderArenaDeath(tier *ArenaTier, round int, monster *ArenaMonster, lostEar // ── Status ────────────────────────────────────────────────────────────────── -func renderArenaStatus(run *ArenaRun, char *AdventureCharacter) string { +func renderArenaStatus(run *ArenaRun) string { tier := arenaGetTier(run.Tier) if tier == nil { return "No active arena run." diff --git a/internal/plugin/adventure_arena_test.go b/internal/plugin/adventure_arena_test.go index 6eac8a3..4421c20 100644 --- a/internal/plugin/adventure_arena_test.go +++ b/internal/plugin/adventure_arena_test.go @@ -274,7 +274,7 @@ func TestArenaDeathChance_Components(t *testing.T) { // ── Render Tests ──────────────────────────────────────────────────────────── func TestRenderArenaStreakEntry(t *testing.T) { - char := &AdventureCharacter{CombatLevel: 30} + char := &DnDCharacter{Level: 30} tier := arenaGetTier(1) monster := arenaGetMonster(1, 1) @@ -576,7 +576,7 @@ func TestArenaGearDropRates_Decreasing(t *testing.T) { // ── Render Tests (New/Updated) ───────────────────────────────────────────── func TestRenderArenaStreakEntry_ShowsMultipliers(t *testing.T) { - char := &AdventureCharacter{CombatLevel: 50} + char := &DnDCharacter{Level: 50} tier := arenaGetTier(1) monster := arenaGetMonster(1, 1) @@ -604,7 +604,7 @@ func TestRenderArenaStreakEntry_ShowsMultipliers(t *testing.T) { func TestRenderArenaStreakEntry_HighLevel_AllEligible(t *testing.T) { // T5 requires level 70, so use level 70+ to unlock everything - char := &AdventureCharacter{CombatLevel: 70} + char := &DnDCharacter{Level: 70} tier := arenaGetTier(1) monster := arenaGetMonster(1, 1) @@ -641,9 +641,8 @@ func TestRenderArenaRoundStart_ZeroEarnings(t *testing.T) { func TestRenderArenaStatus_Active(t *testing.T) { run := &ArenaRun{Tier: 2, Round: 3, Status: "active", Earnings: 8000, TierEarnings: 1500, RoundsSurvived: 6} - char := &AdventureCharacter{CombatLevel: 20} - text := renderArenaStatus(run, char) + text := renderArenaStatus(run) if !strings.Contains(text, "Streak") { t.Error("status should say Arena Streak") } @@ -660,9 +659,8 @@ func TestRenderArenaStatus_Active(t *testing.T) { func TestRenderArenaStatus_Awaiting(t *testing.T) { run := &ArenaRun{Tier: 3, Status: "awaiting", Earnings: 20000, TierEarnings: 0, RoundsSurvived: 12} - char := &AdventureCharacter{CombatLevel: 30} - text := renderArenaStatus(run, char) + text := renderArenaStatus(run) if !strings.Contains(text, "advancing shortly") { t.Error("awaiting status should mention advancing") } @@ -793,9 +791,8 @@ func TestRenderArenaLevelGate(t *testing.T) { func TestRenderArenaStatus(t *testing.T) { run := &ArenaRun{Tier: 3, Round: 2, Status: "active", Earnings: 5000, RoundsSurvived: 5} - char := &AdventureCharacter{CombatLevel: 30} - text := renderArenaStatus(run, char) + text := renderArenaStatus(run) if !strings.Contains(text, "Tier: 3") { t.Error("status should show tier") } @@ -1054,7 +1051,7 @@ func TestArenaStreakEuroMultiplier_Exact(t *testing.T) { // ── Streak Entry Shows Brim & Battle Sponsorship ────────────────────────── func TestArenaStreakEntry_Sponsorship(t *testing.T) { - char := &AdventureCharacter{CombatLevel: 1} + char := &DnDCharacter{Level: 1} tier := arenaGetTier(1) monster := arenaGetMonster(1, 1) diff --git a/internal/plugin/audit_fixes_test.go b/internal/plugin/audit_fixes_test.go index 5b87d46..08f55b6 100644 --- a/internal/plugin/audit_fixes_test.go +++ b/internal/plugin/audit_fixes_test.go @@ -141,7 +141,7 @@ func TestIndexDDL_ContainsNewIndexes(t *testing.T) { Earnings: 500, TierEarnings: 100, } - status := renderArenaStatus(run, &AdventureCharacter{}) + status := renderArenaStatus(run) if !strings.Contains(status, "Tier: 2") { t.Error("renderArenaStatus should show tier") } @@ -151,7 +151,7 @@ func TestIndexDDL_ContainsNewIndexes(t *testing.T) { // Awaiting state run.Status = "awaiting" - status = renderArenaStatus(run, &AdventureCharacter{}) + status = renderArenaStatus(run) if !strings.Contains(status, "bail") { t.Error("renderArenaStatus should show bail command for awaiting runs") } @@ -225,7 +225,7 @@ func TestRenderArenaStatus_NoInternalLeak(t *testing.T) { Earnings: 0, TierEarnings: 50, } - msg := renderArenaStatus(run, &AdventureCharacter{}) + msg := renderArenaStatus(run) for _, bad := range []string{"panic", "goroutine", "runtime.", "err="} { if strings.Contains(msg, bad) {