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
80%
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. Several 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 raises the damage-reduction ceiling from 80% to 75% (expect to lower mob damage to match), 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; a bound you delete from the file goes back to the shipped value on the same reload. The Modifier Clamps page in /mmoadmin edits the same bounds in game and writes this file for you.

The whole-pipeline caps

The clamp files below bound a calculation rather than a modifier key, and they are the ones most worth knowing about, because each one bounds every source that feeds it at once: skill tree, mastery, gear, potions, and pack content together.

FileWhat it boundsShipped
HitDamageThe summed global, per-skill and per-ability percent damage bonus on any weapon swing (a per-school bonus is not in it)MinTotalPercent -0.9, MaxTotalPercent 60
DefenseReductionThe total percent damage reduction a defender gets from defense, after armor penetrationMax 0.8

Defense reduction

The defense stat takes at most 80% off a hit. Since 1.7.1 the shipped caps are safety rails, set well above what shipped content reaches, so they stop a runaway stack rather than set the balance. Worn armor's own resistance applies first and multiplies with it. Base-game armor resists nothing elemental, so on an elemental hit the defense stat alone leaves at least 20% of it, before any school resistance. Armor penetration is applied before the cap, so penetration shrinks what defense grants and this ceiling is the outer bound nothing gets past. If the clamp file is missing, the mod falls back to a built-in ceiling and never runs uncapped.

School resistance

Resistance to any one damage type stops at 80% (Max 0.8, a fraction, in the SchoolResist file). Since 1.7.2 a skill-tree node, mastery, enhanced gear and any item, from this mod or another, all add onto the DamageResist_<Type> stats from Ziggfreed's CommonLib, one total per type. CommonLib mirrors each total into one of the game's own resistance effects, so it adds to your armor's resistance to that type. The cap bounds each type on its own, never the sum of two, and worn armor's own resistance is not counted against it.

CommonLib ships its own per-type ceiling, the DamageResistMax stat. On a server running MMO Skill Tree the SchoolResist clamp takes its place, so retune the cap here or in ability-clamps.json: a DamageResistMax file or an item that raises it changes nothing while this mod is installed.

Critical chance

Critical chance has no clamp since 1.7.1: a hit rolls once, so a chance past 1 already crits every hit, and the old CritChance file is retired. An owner's CritChance override in ability-clamps.json now does nothing. Critical damage is a separate stat with no cap of its own.

Hit damage

Every global, per-skill and per-ability 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. Since 1.7.1 a per-school damage bonus is not in that bucket: it applies after armor, through the per-type damage step in Ziggfreed's CommonLib, multiplies with the bucket, and has no cap.

A separate ceiling sits above this one

maxPreDefenseMultiplier in skill-config.json (default 4.0) caps the compounded multiplier from an armed buff and a mark on the same hit. It does not touch crits or damage bonuses: the percent bucket has its own bound in HitDamage, and a school bonus has no cap. 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 1200000
costabilityMana or stamina an ability spendsMin 0, Max 200000
damagebodyDamage a body leaf dealsMin 0, Max 200000, MinTotalPercent -0.9, MaxTotalPercent 60
damageMultiplierbodyA multiplier applied to that damageMin 0, Max 100, MinTotalPercent -0.9, MaxTotalPercent 40
armMultiplierbodyWeapon-scaling multiplier on an armed hitMin 0, Max 100, MinTotalPercent -0.9, MaxTotalPercent 40
armFlatBonusbodyFlat bonus added to an armed hitMin 0, Max 2000, MinTotalPercent -0.9, MaxTotalPercent 20
damageRadiusbodyRadius of a damaging area, in blocksMin 0, Max 200, MinTotalPercent -0.9, MaxTotalPercent 20
radiusbodyRadius of a non-damaging area, in blocksMin 0, Max 200, MinTotalPercent -0.9, MaxTotalPercent 20
distancebodyRange, dash length, or projectile reachMin 0, Max 1000, MinTotalPercent -0.9, MaxTotalPercent 20
durationMsbodyHow long an effect or zone lastsMin 0, Max 7200000, MinTotalPercent -0.9, MaxTotalPercent 20
iframesDurationMsbodyInvulnerability window on a dodge or dashMin 0, Max 20000, MinTotalPercent -0.9, MaxTotalPercent 20
pierceCountbodyHow many targets a projectile passes throughMin 0, Max 100
onHitHealPercentbodyShare of damage returned as healingMin 0, Max 2, MinTotalPercent -0.9, MaxTotalPercent 20
lifestealseamHealth returned per weapon swingMin 0, Max 200, MinTotalPercent -0.9, MaxTotalPercent 20
comboFinisherBonusseamExtra damage on a combo finisherMin 0, Max 1000, MinTotalPercent -0.9, MaxTotalPercent 20
lootMultiplierseamMultiplier on a bonus-drop rollMin 0, Max 10
schoolResistseamPer-school damage resisted, as a fractionMin 0, Max 0.8

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 each damage type's resistance by SchoolResist, which CommonLib holds the player to as it keeps their resistance in step.
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 chanceNo clamp since 1.7.1: a chance past 100% already crits every hit
School damage bonusNo cap since 1.7.1: applies after armor and multiplies with the global and per-skill bonus
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, but a cooldown never drops below 5% of its base
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 reserved ids above, and skill-tree School Resistance nodes for one school that add up to the SchoolResist ceiling or past it. 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.