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) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-04-28 22:36:17 -07:00
parent 07ca5288c3
commit d93dc4faa4
2 changed files with 15 additions and 4 deletions

View File

@@ -603,11 +603,22 @@ func advCheckBrokenEquipment(equip map[EquipmentSlot]*AdvEquipment) []EquipmentS
// advOverlevelMultiplier returns a multiplier (0.051.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

View File

@@ -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 {