From d93dc4faa4ca9c9ef2b244d867eecc9d09f2a651 Mon Sep 17 00:00:00 2001 From: prosolis <5590409+prosolis@users.noreply.github.com> Date: Tue, 28 Apr 2026 22:36:17 -0700 Subject: [PATCH] Adventure: skip overlevel penalty when no higher tier is accessible Previously, advOverlevelMultiplier penalized every action where the player's effective level exceeded the location's MinLevel by 4+, with no escape valve. That punished players grinding at their max-available tier (e.g., a level 50 character at the highest mining location they qualify for, with nothing higher unlocked). Now: the multiplier short-circuits to 1.0 when no accessible higher-tier location of the same activity exists for that player. Signature changed from (effectiveLevel, minLevel) to (effectiveLevel, *AdvLocation) so the helper can scan the activity's location list. combat_bridge.go updated to match. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/plugin/adventure_activities.go | 17 ++++++++++++++--- internal/plugin/combat_bridge.go | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/internal/plugin/adventure_activities.go b/internal/plugin/adventure_activities.go index e4814be..8934f43 100644 --- a/internal/plugin/adventure_activities.go +++ b/internal/plugin/adventure_activities.go @@ -603,11 +603,22 @@ func advCheckBrokenEquipment(equip map[EquipmentSlot]*AdvEquipment) []EquipmentS // advOverlevelMultiplier returns a multiplier (0.05–1.0) that reduces XP and // loot when a character's effective level far exceeds the location's minimum. // Gap 0-3: no penalty. Gap 4+: −15% per level over 3, floor 5%. -func advOverlevelMultiplier(effectiveLevel, minLevel int) float64 { - gap := effectiveLevel - minLevel +// No penalty if no higher-tier location of the same activity is accessible. +func advOverlevelMultiplier(effectiveLevel int, loc *AdvLocation) float64 { + gap := effectiveLevel - loc.MinLevel if gap <= 3 { return 1.0 } + hasHigherAccessible := false + for _, other := range allAdvLocations(loc.Activity) { + if other.MinLevel > loc.MinLevel && other.MinLevel <= effectiveLevel { + hasHigherAccessible = true + break + } + } + if !hasHigherAccessible { + return 1.0 + } mult := 1.0 - 0.15*float64(gap-3) return math.Max(0.05, mult) } @@ -644,7 +655,7 @@ func resolveAdvAction(char *AdventureCharacter, equip map[EquipmentSlot]*AdvEqui // Overlevel penalty — reduces loot and XP for farming low-tier content skillLevel := advEffectiveSkill(char, loc.Activity, bonuses) - overlevelMult := advOverlevelMultiplier(skillLevel, loc.MinLevel) + overlevelMult := advOverlevelMultiplier(skillLevel, loc) // Roll outcome roll := rand.Float64() * 100 diff --git a/internal/plugin/combat_bridge.go b/internal/plugin/combat_bridge.go index ab84295..1de75d4 100644 --- a/internal/plugin/combat_bridge.go +++ b/internal/plugin/combat_bridge.go @@ -524,7 +524,7 @@ func (p *AdventurePlugin) resolveDungeonAction( // Overlevel penalty skillLevel := advEffectiveSkill(char, loc.Activity, bonuses) - overlevelMult := advOverlevelMultiplier(skillLevel, loc.MinLevel) + overlevelMult := advOverlevelMultiplier(skillLevel, loc) // Loot on success/exceptional if result.Outcome == AdvOutcomeSuccess || result.Outcome == AdvOutcomeExceptional {