% reduction systems in games
This blog post is inspired by this excellent video about asymptotic scaling in games, which landed on my youtube homepage at the perfect time. This post touches on most of the same points, with a couple of additions.
Percentage-based damage reduction systems in games can be pretty counterintuitive when scaled, and can lead to some nasty surprises if you aren't aware of the pitfalls. Briefly think about this scenario: your RPG character levels up, and gains an ability that makes them take 20% less damage. How much more damage does it take to kill your character, compared to before you gained the ability?
...
If you answered 20%, you've fallen into the trap of asymptotic scaling; 20% damage reduction actually means it takes 25% more damage to kill your character. While that's only a small difference, the gap widens significantly when you allow the player to stack these kinds of stats - then you can run into some real issues. This post goes into those issues and some potential solutions.
A motivating example
Say you're building a game where the player can equip various pieces of equipment that can grant (among other stats) X% damage reduction.1 Let's look at how this damage reduction stat impacts the survivability of a character with 100 HP:
- At 0% damage reduction, it takes 100 damage to kill the player
- At 20% damage reduction, it takes 125 damage to kill the player
- At 50% damage reduction, it takes 200 damage to kill the player
- At 80% damage reduction, it takes 500 damage to kill the player
Notice something? As damage reduction increases, the amount of damage it takes to kill the player increases way faster. There's a vast difference between the player with 50% damage reduction and the one with 80% damage reduction.2
This scaling behavior gets out of control pretty quickly. Take a look at the example above: if the player has 20% damage reduction breastplate and equips some boots that give them another 30% damage reduction, they've increased the amount of damage they can take without dying by 75. Their effective HP has increased from 125 to 200.
If they then also equip a 30% damage reduction hat (for a total of 80% reduction), they increase their effective HP from 200 to 500. That's a huge improvement, for an item that - on its face - is exactly as good as the boots!
Think about it: the boots in isolation provide 75 effective HP (and so would the hat), but equipping both items boosts our effective HP from 125 to 500 - an increase of 375 effective HP. Stacking damage reduction is massively powerful in this system, and as you gain damage reduction, each new point of damage reduction is vastly more valuable.3
A portion of your playerbase will realize this, and stack the stat accordingly. Other players will not realize this, and miss out on an opportunity that would make their character much stronger. Depending on the balance of your game, either end of that spectrum can become a problem.
What's going on here?
The key point here is that the actual output value of the system is a different value than you might be thinking. In our example, players don't particularly care damage they take from individual hits and how much that damage might be reduced; what they care about is how much damage they can take before they die. That's the actual output value of the system, which I will call the effective output value for the rest of this post.
Issues start to arise when the input stat of the system (my % damage reduction stat) and the effective output value (how much damage can I take until I die) have a nonlinear relationship. In the case of systems that reduce a value by a %, that's usually an asymptotically scaling relationship.
Identifying asymptotic scaling
While this blog post mostly uses damage reduction as an example, there are a lot of other asymptotically scaling stat systems: cooldown reduction, mana cost reduction, you name it. A good rule of thumb to identifying these is this: if your stat allows the player to scale some other value from its 'full' value to 0, there's a high likelihood it's an asymptotically scaling system and you'll want to take a closer look.
When you suspect you've got an asymptotically scaling system, plot out how the input stat value scales the effective output value. Just sample a few values from the full range of your input stat value; if you see any significant nonlinear scaling like in the examples in this post, you're probably dealing with asymptotic scaling.4
A brief bonus example for cooldown reduction
The key is always to identify the effective output value. For cooldown reduction, the effective output value is spells per second. For a spell with a cooldown of 1 second:- 50% cooldown reduction gives you 2 spells per second
- 90% cooldown reduction gives you 10 spells per second
- 100% cooldown reduction gives you infinite spells per second, presumably only limited by the rate at which you can mash the button to cast it
The math behind all this
When you really want to know what's going on, you need to look at the math behind your system. If you want to skip the math, feel free to skip to the possible solutions for dealing with asymptotic scaling, but I think the math is very instructive here.
Let's take a closer look at damage reduction. For our damage reduction system, damage is calculated like this:
In other words: as our damage reduction grows, we take less damage. If we have 20% damage reduction, we take damage, i.e. 80% of the incoming damage.
When the player is hit by an attack, what they care about is this:
In words: is the player's HP bigger than the amount of damage they take? What's interesting here is that and are controlled by the player, while is not. So let's do a bit of algebra to rewrite this inequality:
What the player wants to do is maximize the left side of that inequality, so that they survive even when has a high value. At this point, our predicament becomes clear: as the player increases their damage reduction, the denominator of that fraction approaches 0. And you might remember what looks like near :

So that's our issue: we've allowed our player to have control over the variable in the denominator, allowing them to scale their effective output value wildly out of control if they manage to get close to 0. So what can we do about it?
Taming these systems into linearly-scaling systems
There's a few ways to tame these asymptotically scaling systems and ensure they don't scale out of control in your game:
- Cap the input stat
- Add a layer of indirection that re-scales it back into the linear realm
- Reframe the input stat to be linear
What follows is a brief explanation of each of these solutions.
Capping the input stat
This is the simplest solution: simply don't allow the player to stack the stat beyond a certain value. The key insight here is that low amounts of the input stat are 'linear enough' not to cause any issues. For example, 20% damage reduction leading to 25% more effective HP probably won't ruin your game and the system's outcomes will still feel correct to players, even if they don't have a perfect understanding of how the numbers scale.
Implementing a hard cap to the input stat is a guaranteed way to prevent scaling issues. But if you're building a game revolving around complex stat systems and highly customizable builds, this solution feels pretty bad: a hard cap frequently means your stat just becomes a threshold to meet instead of an interesting decision for the player.5
You can also implement a soft cap by ensuring you never give the player the ability to acquire significant amounts of the input stat in the first place. In my opinion, you should reconsider if you want to keep the stat at all if you're going to take this route: if the player only ever gets tiny amounts of it, will they even feel the difference?6
Adding a layer of indirection
League of Legends adds a layer of indirection for its damage reduction system: players can't get damage reduction on items directly. Instead, items grant a stat called armor. Armor is then mapped to damage reduction using this formula:7
Why this formula? If we plug this back into our formula from earlier:
When we simplify this8, we get a linear formula that's surprisingly intuitive:
In words: every point of armor gets you 1% effective bonus HP. Notice how the denominator is a fixed value, not controlled by the player; this formula scales linearly with armor.9 That means we don't have to worry about how much armor we already have: we always get 1% effective bonus HP per point of armor we gain.
The trouble, of course, is explaining all this to players. You can get pretty far with tooltips, but very few players will arrive at a precise understanding of these formulas by themselves. If that's not an issue for you, this solution of adding indirection into the stat that rescales it is a good way of getting a linearly-scaling system.
Reframing the input stat to be linear
Sometimes, you can choose a slightly different input stat that completely avoids all these scaling issues. A prime example here is cooldown reduction: while cooldown reduction scales asymptotically, cooldown recovery speed scales linearly. By giving your players a slightly different stat to play with, you've prevented them from going off the rails with it.
The trick here is to give the player a stat that scales the effective output value linearly - like cooldown recovery speed.10 This results in a very intuitive system: it's pretty obvious to the player that their first 50% cooldown recovery speed item will result in casting 50% more spells per second. If the player already has 300% increased cooldown recovery speed, it's also clear that adding another 50% (for a total of 350%) is a comparatively small upgrade.
Of course, you have to make sure your replacement stat actually scales linearly. Ideally, you're looking for a stat with a domain of . Asymptotically scaling stats typically have a domain of , so look out for those.11
The downside of this solution is that you can't always find a workable replacement stat: you can replace damage reduction % with bonus HP %, but bonus HP feels pretty different even though it's just the same effect with different scaling properties. If you come up with an intuitive, linear replacement stat for damage reduction specifically, please let me know - it would really help me out!
Wrapping up
In case it needs to be said: asymptotically scaling stat systems are not inherently bad. Maybe you're building an incremental game where scaling out of control is the point; maybe you've built another asymptotically scaling system that counteracts the first one; maybe the stat is conditional in such a way that the player can only sometimes reap the rewards of their out-of-control stat. In all of those cases: go wild!
But for the other cases, I hope this was a useful post. If you have any thoughts on this, I would love if you let me know (via Bluesky or email). Cheers!
Note that this blog post only talks about percentage-based damage reduction systems (and similar, e.g. % cooldown reduction). Flat damage reduction behaves similarly when scaled, but adds some complications; its results depend on the number and size of the incoming attacks.↩
There's also the degenerate case: if the player ever reaches 100% damage reduction, they cannot die. Games usually guard against this already; the point of this post is that the issues with this damage reduction system start way before you reach 100%.↩
A fun exercise: calculate the effective HP provided by equipping further damage reduction items. As you near 100% damage reduction, the amount of effective HP provided by even the weakest items absolutely skyrockets.↩
Obviously, there's a lot of other types of scaling you can encounter when designing stat systems - but those are easier to identify at first glance, in my experience.↩
Path of Exile, a game known for the massive variety of possible character builds, caps their elemental resistances at 75%. As a result, there's comparatively few character builds that do something interesting with elemental resistances, and getting 75% of each resistance is simply a prerequisite for surviving the endgame.↩
The exception to this is one-off stats; if you give the player a 30% cooldown reduction bonus exactly once, the player gets a chunky improvement to their character and you can be sure it never scales out of control, because there's no way to stack more.↩
Thanks to the League of Legends wiki page on armor for the formula!↩
Don't ask me how, this is what Wolfram|Alpha is for.↩
Note that it still scales multiplicatively with HP, as did our original damage reduction system (and as do almost all damage reduction systems).↩
For cost reduction systems like mana cost reduction %, you can replace them with bonus resource generation %. Similar effect, linear scaling.↩
In fact, looking at the domain of your asymptotically scaling stat can be a helpful way of coming up with a linear replacement stat. If you reflect the domain of around 1 to , what stat do you get?↩