Skip to content

Scaling Curves

Scaling curves limit late-game stat inflation. When an attribute exceeds a threshold, only the exceeding part is reduced by a curve. This keeps progression valuable while preventing equipment, gems, strengthening, and sets from breaking combat balance.

Apply scaling curves first to:

  • Main damage attributes: physical_attack, projectile_attack, spell_attack.
  • Defense attributes: physical_defense, projectile_defense, spell_defense.
  • Probability attributes such as critical chance, dodge chance, and lifesteal chance.
  • Resource caps such as health and mana.
  • Penetration, damage reduction, cooldown reduction, or other attributes near hard caps.

Configuration

Scaling curves are configured in config.yml. The section is empty by default, so no decay applies until you add a rule.

yaml
scaling_curves:
  physical_attack_cap:
    attribute: "physical_attack"
    threshold: 500
    curve_type: "logarithmic"
    factor: 100

The entry key is the rule id. When attribute is omitted the key itself is used as the attribute id, so the rule above can also be written as physical_attack: {threshold: 500, factor: 100}.

FieldDescription
attributeAttribute id affected by this rule.
thresholdValue where diminishing returns begin; negative values are treated as 0.
curve_typelogarithmic (default), sqrt, or piecewise_linear (alias linear). Unrecognized values fall back to logarithmic and are reported by the config precheck.
factorCurve factor; exact meaning depends on curve type. logarithmic / sqrt divide by it, so values <= 0 are treated as 1. piecewise_linear uses it as a retention ratio, where 0 is valid and drops the whole excess.

Final value can be understood as:

text
final = threshold + reduced_excess

Curve types

logarithmic

Good for main damage and defense attributes. Growth continues after the threshold but slows down smoothly.

sqrt

Also has a decreasing slope. Suitable for defense, mitigation, or resource caps.

CAUTION

Two caveats:

  1. At the same factor, sqrt is actually weaker than logarithmic (with factor: 100 and an excess of 500, logarithmic yields 179 while sqrt yields 224). For stricter control, use logarithmic or lower factor substantially.
  2. It is implemented as sqrt(factor * excess), so when the excess is smaller than factor the result exceeds the excess, amplifying instead of reducing. With factor: 80, a raw value of 440 (excess 40) resolves to 400 + 56.6 = 456.6. Keep factor below the smallest excess you care about to stay out of that range.

piecewise_linear

Keeps a fixed ratio of the excess part. Useful for probability attributes or rules that should be easy to reason about.

NOTE

Despite the name, this is a single excess * factor discount and does not support multiple segments. The name is kept for compatibility with existing configs.

yaml
scaling_curves:
  crit_rate_cap:
    attribute: "physical_crit_rate"
    threshold: 80
    curve_type: "piecewise_linear"
    factor: 0.3

If the raw value is 100, the final value is about 80 + (20 * 0.3) = 86.

Relationship with attribute value limits

Scaling curves run first; the min_value / max_value / allow_negative limits from the attribute definition run after. The full order is: aggregate all sources → scaling curves → derived attributes → value limits.

A curve result is therefore still bound by the attribute's own range. The 86 above sits inside physical_crit_rate's [0, 100] range and is unaffected, but if a loose curve still leaves the value above max_value, the final value is pushed back to max_value. The two layers complement each other: curves keep growth smooth, ranges enforce the hard cap.

Tuning notes

  • Set thresholds near reasonable endgame values, not beginner values.
  • Avoid multiple curve rules for the same attribute unless you have a clear reason.
  • Test low, mid, endgame, and extreme-stacked characters after changing curves.
  • If growth feels too weak, increase threshold or factor; if too strong, lower them or use a stronger curve.