Thursday, December 18, 2014

[IndieDev] Vive les Résistances: Models for Stacking Stats Like Resists

Currently I'm working on implementing resistances in our game, Eon Altar, and while chatting with our designers the question came up of how do you stack resistances?

I mean, we're not like D&D 4th Edition where an attack could have every possible elemental keyword (looking at you, Tiamat, and your Fire Electric Acid Cold Poison breath), so we don't need to worry about an attack doing both Cold and Fire damage, for example. However, we do need to worry about multiple sources of the same resistance--30% Fire from a skill, and 20% Fire from a buff--as well as when different types overlap--say, a Melee Fire attack against someone with a big shield so they resist damage from the front and perhaps also resist Fire damage.

Stacking A Single Resist

Let's pretend you're Freddie the Fire Mage (note: not an actual character in our game), and you've decided that it'd be a good idea to stack Cold resist, because, well, who likes being cold? So you went down your skill tree and picked up a natural resistance to Cold of 20%. You also decided that this Frost Dragon looks nasty, so you popped a Potion giving you 30% Cold resist. Oh, and Penny the Paladin has an aura giving you another 20%.

So you have 20%, 30%, and 20% from three sources. There's a few ways you can go about this:


You can just add them up and call it a day. In Freddie's case, that's just a total of 70% Cold resistance. The good thing is it's super easy for players to grok; you don't need to have a minor in mathematics to intuit the results. The potentially bad thing is once you hit 100%, you're immune. Further boosts are wasted, and complete immunity to a mechanic may allow players to find a way to cheese your game if you're not careful. This can be mitigated somewhat by putting an artificial cap on it (i.e.: Diablo II's 75% element resist cap), or by ensuring a player doesn't have enough sources of a given stat to stack it too high.

Once you hit 4 sources of 30% Cold resist, everything else would be wasted. Heck, you wasted 2/3rds of the 4th source anyhow.


Another way is to just take the biggest source. In Freddie's case, that would be 30%. It heavily punishes stacking because rather than having the natural Cold resist or Penny's aura, Freddie could've just popped a potion and used those skill points on other abilities. Players are instead encouraged to be generalist about their stats rather than giving the option of specializing. But it's easy to balance because you can ensure an absolute maximum a player can have because it'll only ever count a single source.

No matter how many 30% Cold resist sources you had, you'd still only ever have 30% Cold resist.


The third way is multiplicative. Multiplying the effects together amplifies the effects. So for Freddie, his 30%, 20%, 30% resists becomes 87.2% (1.3 x 1.2 x 1.3 = 1.872 and subtract 1 for 0.872), which is clearly greater than the additive 70%. Movement in WoW, until recently, used multiplicative. This rewards stacking multiple sources, even if they're small sources, as each source amplifies the other sources. This ends up creating an exponential curve, nearly requiring players to specialize to be optimal. Frankly, in my mind, it would also be hell to balance because runaway numbers.

It's hard to tell because we're capped at 100% for this example, but we'd be already at 119.7% resist at 3 sources of 30%, which is the start of a decently steep exponential curve.
If we didn't cap it at 100%, this is what it would look like. Note the scale on the left going to 1200%+. Exponential scale indeed.

Inverted Multiplicative

A fourth way is inverted multiplicative. That is, invert the semantic, then multiply each effect with each other. This creates diminishing returns, where each additional stacked source has slightly less effect. In Freddie's example, you have 20% Cold resist from the first source; 44% combined Cold resist from the first and second sources; and 55.2% combined Cold resist from all three sources.

The math for this is a little bit funny, because resists are like saying "not damage", so instead of saying 20%, 30%, 20% resist, you say 80% damage, 70% damage, 80% damage, multiply them together (0.8 x 0.7 x 0.8 = 0.448), then subtract 1 and drop the sign (0.552).

Final Fantasy XIII actually performs stacking single resistance calculations this way. The con, of course, is the math is tricky for your average player. The pro is that you'll never hit complete immunity (without something giving you complete immunity which would be a multiplication by 0), allowing players to specialize if they so choose, but also allowing the players to decide where the limit of stacking return is.

Every 30% Cold resist source still gives you resistance, but each one has less effect than the one before. Makes a nice pretty curve, too.

We're currently leaning towards the first method for stacking a single resist. The ability for players to just math it out in their head is immense, and not to be underestimated. We also don't have too many sources of stats, so I doubt a player will be able to stack a large number of a single stat. We'll see if I have to eat my words later, though.

Additive as Increase

Thanks to Balkoth for this one (see his comment below). This one is similar to inverted multiplicative, but the formula is basically 100 / (100 + AdditiveBonus). This one has a much steeper drop off than Inverted Multiplicative, so takes more than twice as many sources as inverted multiplicative to get the same result. Probably a good choice if you have lots of sources and want to keep stacking sources to just a couple buffs, regardless of how many possible sources you have.

Our curve for this plateaus a fair bit earlier than multiplicative increase, making it attractive if you have lots of different sources possible and want to limit player stacking further.

Stacking Different Resists

So say Penny the Paladin has 20% Fire resist, but thanks to her shield, she also resists 30% of direct frontal Melee attacks. We now have two different resists, and basically the same problem as above, but with slightly different consequences.

Adding the two doesn't make much sense. If we cranked those numbers up to 50% each, that means a direct frontal Melee Fire attack would do 0 damage, which doesn't make much intuitive sense when you think about resisting half the damage. However, for smaller numbers (less than 50%), I think it works just okay.

We could take the largest, but like previously, this punishes players for stacking resistances. A player would game that by just attempting to ensure that Penny always took attacks from the front, and screw any other contingencies, devaluing her 20% Fire resist.

We could take the smallest (or the intersection) of the two, but that potentially sucks because then a Cold melee attack would basically do full damage, ignoring her 30% direct frontal Melee attack resistance, because she has 0% Cold resist.

Multiplicative is problematic for the same reason additive is: if makes little sense for each resist to be amplifying other resists. On the other hand, it would reward diversification of stats, making a jack-of-all-resists much more attractive, at the expense of stacking.

Which really just leaves inverted multiplicative for different sources, which would give Penny 44% resistance from frontal Melee Fire attacks. It doesn't punish her unduly for not having every type of resistance, and in my opinion--strangely--makes more intuitive sense than adding them, especially for larger numbers. This is the route we're choosing for multiple different resistances simultaneously applying.

So Why Percentages?

Finally, there's another option entirely: use flat values. Similar to how D&D works, we could use flat values (you resist 20 Fire damage), but this is harder to balance and scale. Percentages scale by virtue of being, well, percentages. We don't need to rejigger numbers for resistances every time we change the scale of our combat. If today at level 1 Freddie is doing 10 damage on average, and tomorrow Freddie is doing 20, we'd also have to rebalance resistances if they were flat. As percentages, they have the same relative effect.

We also don't have the MMO problem of constantly having to put out new expansions and worrying about nerfing percentages the way WoW does--because what does 300% Haste mean? Nope, gotta reset those percentages every 10 levels. Assuming we have enough different things for players to choose as they level, there's no danger of percentages becoming silly (not to mention our additive cap on a single resist of 100%).

On the other hand, flat values make big single attacks more valuable, but devalues multiple smaller attacks. If you're a dual-wielder, and your opponent resists 20 damage, they really get to resist 40 damage because you performed two attacks, not one. Percentages don't have that issue (or bonus, depending on how you balance your game).

Note that I'm not saying that the choices we made are the best objectively. They're what we believe will work for our system. We'll see how these work in practice, as I'm still actually implementing them, but it was a neat discussion. Things can still change if we decide to go a different route, as well! #IndieDev, #EonAltar, #GameDesign


  1. You're also forgetting another version: additive as increase, for lack of a better term.

    To illustrate, let's imagine we're using additive bonuses and we pick up an ability that adds 20% damage, another ability that adds 50% damage, and a final ability that adds 30% damage. 100% more if you add them up, so you expect to DOUBLE your damage output.

    The same logic holds true for defense -- a 20% reduction, 50% reduction, and 30% reduction should DOUBLE your defense. But that's not a 100% reduction, that's a 50% reduction!

    Specifically, your formula is 100/(100 + bonus). A 50% increase in defense is a 33.3% (repeating, of course) damage reduction. A 200% increase in defense is a 66.6% (also repeating, of course) damage reduction.

    And while it has a diminishing return percentage wise (getting a eleventh 10% increase in damage is only a 5% bonus overall ) it does not give a diminishing return in raw value. If a 5% offensive bonus gives 10 more DPS, it always gives 10 more DPS. If a 5% defensive bonus lets you live 6 more seconds, it always lets you live 6 more seconds.

    But yes, this is an interesting problem in general.

    I don't think inverted multiplicative is as confusing as you think. It's literally just saying "You take 20% less damage. Then the 30% bonus means you take 30% less damage of that previous number. Then you take 20% less damage of that second number." It's no different than saying something like "Okay, my company and another company have been hired for a job that pays $100. The companies split the pay equally and then I will get 15% of the money my company receives -- which is 15% of $50 or $7.50 overall."

    P.S. One of the thing that frustrates me slightly in NWN is that it does the additive immunity which means many modules hinge on just being completely immune to types of damage. Fortunately I can code the system to apply a bonus to the player using either method mentioned in my post as a buff rather than relying on the default item properties.

    1. Oh, that's a good one too. Super good one! I added a section and charted it out in the post above.

      That's a good analogy for the inverted multiplicative. I still posit that it's too much for many people to grok intuitively. They're going to look at the numbers and not get it.

      As to your PS, yup. Additive definitely makes it hard to balance around immunities. You kinda just have to assume your players will cheese your game. :(

    2. Thought of another potential benefit for the method I mentioned if your goal is avoiding something being unintuitive -- the sources don't matter, only the final number.

      In WoW, for example, if you had a choice between

      50% more fire damage
      21% more fire damage


      35% more fire damage
      35% more fire damage

      You'd probably figure the first is better (1% more total, right?)...but in fact the second option is 0.4% more damage overall.

      P.S. While we're on the subject, additive also poses major problems for people not cheesing. If you expect the player to resist 95% of damage and they only resist 85%, then they're taking TRIPLE the damage expected. For what intuitively only seems a 10% difference.