Stat Caps & Clamps

Where every stacking ceiling lives, and how to retune one

Overview

Stat ceilings are authored data, not numbers baked into the jar. One file per capped key under Server/MMOSkillTree/ModifierClamps/ says how far that key can stack, a content pack can overlay it, and the server owner has the last word in mods/mmoskilltree/ability-clamps.json. Nothing has to be recompiled to move a cap.

Clamp files shipped
19
Owner file
ability-clamps.json
Defense reduction cap
90%
Bounds per file
4
Content pack assetmods/mmoskilltree/ability-clamps.jsonServer/MMOSkillTree/ModifierClamps/*.json

The jar ships one clamp file per capped key. A pack can overlay a partial body; the owner file always wins. Every bound folds independently, so a file that mentions one bound inherits the other three.

defaults<pack<owner

The name says ability, the reach is wider

The owner file is called ability-clamps.json because the table started as the ability-modifier bound list. It is read at four other places besides a cast: the weapon swing, the gathering luck roll, the defense calculation, and the stat breakdown screen. Two of the shipped entries never touch an ability at all.

The four bounds

A clamp file carries up to four numbers. Two bound the value itself; two bound the summed percent bucket before it multiplies anything. Every one is optional, and an absent bound means that axis is unbounded.

FieldTypeDefaultDescription
MinnumberunboundedFloor on the folded value. Most shipped files set 0, so a stack of reductions cannot invert a stat into its opposite.
MaxnumberunboundedCeiling on the folded value. This is the runaway stop for a repeatable purchase.
MinTotalPercentnumberunboundedFloor on the summed percent bucket, as a fraction. -0.9 means the most that stacked reductions can take off is 90%.
MaxTotalPercentnumberunboundedCeiling on the summed percent bucket, as a fraction. 30 means percent bonuses stop compounding at 30x.
IsParamKeybooleantrueSet false on a file that only bounds an engine calculation. The bounds still apply, but an ability modifier naming that id is reported by the content audit instead of quietly doing nothing.
* required

Widen by writing a bigger number, not by deleting a line

Bounds merge one at a time. A file that leaves Max out inherits whatever the layer below it set, so removing a line does not lift a cap. To raise a ceiling, author the larger number.

Retuning a cap

Create or edit mods/mmoskilltree/ability-clamps.json. Each entry is keyed by the clamp id and takes the same fields the shipped file uses. Mention only what you are changing.

mods/mmoskilltree/ability-clamps.json
{
  "schemaVersion": 1,
  "clamps": {
    "DefenseReduction": { "Max": 0.75 },
    "Lifesteal": { "Max": 40.0 },
    "Damage": { "MaxTotalPercent": 12.0 }
  }
}

That file lowers the damage-reduction ceiling from 90% to 75%, stops lifesteal stacking at 40 health per swing, and caps compounding damage percent at 12x. Everything the entries did not mention keeps its shipped bound. Run /mmoconfig reload to pick the file up; an entry you deleted outright needs a restart, since the fold merges rather than replaces.

The two whole-pipeline caps

Two clamp files bound a calculation rather than a modifier key, and they are the ones most worth knowing about, because they bound every source at once: skill tree, mastery, gear, potions, and pack content together.

FileWhat it boundsShipped
HitDamageThe summed percent damage bonus on any weapon swing, from every source at onceMinTotalPercent -0.9, MaxTotalPercent 30
DefenseReductionThe total percent damage reduction a defender gets from defense, after armor penetrationMax 0.9

Defense reduction

The 90% ceiling is the convention every percent reduction in the mod follows: stacked defense can take a hit down to a tenth, never to nothing. Armor penetration is applied first, so penetration shrinks what defense grants and this ceiling is the outer bound nothing gets past. If the clamp file is missing entirely the mod falls back to 90% rather than running uncapped.

Per-school resistance carries its own matching 0.9 ceiling on the SchoolResist file, so no single damage school can be stacked into immunity either.

Hit damage

Every percent damage bonus that reaches a weapon swing lands in one bucket, and HitDamage bounds that bucket before it multiplies. Lower MaxTotalPercent here to flatten late-game damage across the board without touching a single skill tree node.

A separate ceiling sits above this one

maxPreDefenseMultiplier in skill-config.json (default 4.0) caps the compounded multiplier from armed buffs, marks, crits, and damage bonuses together, after the percent bucket has already been bounded. See the config reference.

Every shipped clamp

One file per key, ordered by where it folds: ability level (patched once per cast), body level (folded at the leaf that declares it), and seam (never touches an ability at all).

KeyGroupWhat it controlsShipped bounds
cooldownMsabilityAn ability cooldown, in millisecondsMin 0, Max 600000
costabilityMana or stamina an ability spendsMin 0, Max 100000
damagebodyDamage a body leaf dealsMin 0, Max 100000, MinTotalPercent -0.9, MaxTotalPercent 30
damageMultiplierbodyA multiplier applied to that damageMin 0, Max 50, MinTotalPercent -0.9, MaxTotalPercent 20
armMultiplierbodyWeapon-scaling multiplier on an armed hitMin 0, Max 50, MinTotalPercent -0.9, MaxTotalPercent 20
armFlatBonusbodyFlat bonus added to an armed hitMin 0, Max 1000, MinTotalPercent -0.9, MaxTotalPercent 10
damageRadiusbodyRadius of a damaging area, in blocksMin 0, Max 100, MinTotalPercent -0.9, MaxTotalPercent 10
radiusbodyRadius of a non-damaging area, in blocksMin 0, Max 100, MinTotalPercent -0.9, MaxTotalPercent 10
distancebodyRange, dash length, or projectile reachMin 0, Max 500, MinTotalPercent -0.9, MaxTotalPercent 10
durationMsbodyHow long an effect or zone lastsMin 0, Max 3600000, MinTotalPercent -0.9, MaxTotalPercent 10
iframesDurationMsbodyInvulnerability window on a dodge or dashMin 0, Max 10000, MinTotalPercent -0.9, MaxTotalPercent 10
pierceCountbodyHow many targets a projectile passes throughMin 0, Max 50
onHitHealPercentbodyShare of damage returned as healingMin 0, Max 1, MinTotalPercent -0.9, MaxTotalPercent 10
lifestealseamHealth returned per weapon swingMin 0, Max 100, MinTotalPercent -0.9, MaxTotalPercent 10
comboFinisherBonusseamExtra damage on a combo finisherMin 0, Max 500, MinTotalPercent -0.9, MaxTotalPercent 10
lootMultiplierseamMultiplier on a bonus-drop rollMin 0, Max 5
schoolResistseamPer-school damage resisted, as a fractionMin 0, Max 0.9

The file name is the key with a capital first letter: lifesteal is bounded by ModifierClamps/Lifesteal.json. For what each key means to an ability author, and how a pack declares a brand new one, see the ability authoring page.

Where each bound is enforced

The same table is read at five separate points in play.

FieldTypeDefaultDescription
Ability castper castoptionalEvery modifier folded into a cast is bounded by its key before the ability body fires.
Weapon swingper hitoptionalThe summed percent damage bonus is bounded by HitDamage, and lifesteal and combo finisher totals by their own keys.
Incoming damageper hitoptionalThe defender's total reduction is bounded by DefenseReduction after armor penetration, and per-school resistance by SchoolResist.
Gatheringper rolloptionalA bonus-drop multiplier is bounded by LootMultiplier.
Stat breakdown screendisplayoptionalThe displayed mastery total is bounded the same way the hit is, so the number a player reads is the number they get.
* required

Caps that live elsewhere

A handful of ceilings sit outside the clamp table, in their own config files.

FieldTypeDefaultDescription
maxPreDefenseMultipliernumber4.0In skill-config.json. The compounded pre-defense damage multiplier ceiling.
maxBoostMultipliernumber5.0In skill-config.json. The hard ceiling on stacked XP boosts. See XP boost stacking.
maxPersonalBoostsnumber3In skill-config.json. How many personal boosts one player can hold at once.
maxGlobalBoostsnumber3In skill-config.json. How many server-wide boosts can run at once.
maxActiveQuestsnumber10In skill-config.json. How many quests a player can carry.
Clamp.MinPower / MaxPowernumber1 / 200In power-level.json. The Power Level range. See Power Level.
Per-skill max levelnumber100In custom-skills.json or skill-config.json. See per-skill max levels.
* required

What carries no cap

Not every stat has a ceiling. These families are summed and read with nothing bounding the total, and there is no owner-facing setting that changes that today. Adding a clamp file for one of them declares the name but does not bound it, because nothing reads a clamp at those points.

Stat familyBehaviour
Critical chanceSums freely; at 100% every hit crits
Critical multiplierSums freely on top of the 1.5x base
LuckFeeds the bonus-drop roll with no ceiling of its own
Bonus XPSeparate from the XP boost stacking cap, and unbounded
Cooldown reductionThe stat is unbounded; the resulting cooldown still floors at 0ms
Effect durationSums freely

The stat files under Server/Entity/Stats are not a cap surface

Each MMO stat ships as a channel asset carrying a Min and a Max, which reads like a bound and is not one: the Max slot is where the folded value is stored. Editing it shifts the starting value of the stat instead of capping it. Caps live in ModifierClamps, and nowhere else.

Checking your work

/mmoconfig validate runs the content audit, which reports a modifier naming an unknown key, a modifier naming one of the two reserved ids, and per-school resistance authored at or above the ceiling the reconciler enforces. A cap you have lowered shows up there as soon as shipped content exceeds it.

The clamp table shipped in 1.6.0 Since 1.6.0 and the owner layer alongside it.