So I was thinking about critical hits, where some attacks do much more damage than others. Normally, this is just a 2x or 3x bonus. But what if you wanted occasional 30 or 200 times the damage? And what if you wanted to use this system for more than just damage? City sizes and skill checks and so forth. The random number generator would need to be on a continuous scale, instead of occasional discrete bonuses.
And more importantly, how would you balance this? It wouldn’t be fair if critical attacks greatly boosted DPS. Or if skill checks that were bursty gave an advantage.
So, basically, I wanted a random number generator with a consistent average value, and a variable range, without going negative. For simplicity, I used an exponential system. So, if the variance is 2, you can get numbers anywhere between 1/2 (0.5) and 2, with an average of 1. Or, if the variance is 471, you’ll get values between 1/471 (0.0021231…) and 471, but the average value will still be 1.
The idea is you could have, for example, a very reliable attack with a low variance (1.2 or something). What happens when you face a foe with DR? In normal damage systems, you’re just sunk. There’s no way to charge up your attacks, or boost the peaks to jump over the wall. Well, you could modify the attack with the “frantic” skill that would raise the variance (to, say, 5) without altering the long-term average performance of the attack. You’ll still be doing the same DPS, but the peaks will be higher, to punch through the DR, giving you a fighting chance!
That’s the idea anyway, and the math for that is simple enough. The value is the variance raised to the power of some random number between -1 and 1. That gets us numbers across the whole range, but it doesn’t hit the average. Since the default random number is linearly distributed (like rolling a die, there’s an equal likelihood of hitting any particular number) the probability of getting big numbers is just as high as getting low numbers, so the average skews high. So, maybe the math isn’t that straightforward after all. We’d need to use a non-linear noise distribution.
Turns out the beta distribution is the one we’re looking for! By using an alpha based on the log of the variance, and a beta of 2, we get a distribution which properly skews low and maintains the average for any variance value greater than 1. In Python syntax, this looks like:
alpha = 0.5 * math.log( variance ) + 2
rndfac = 1 – 2 * random.betavariate( alpha, 2 )
ResultingRandomValue = variance ** rndfac
Of course, it’s not even that simple. Turns out that, while statistically speaking the math holds up, practically speaking the average plunges at higher variance numbers, because the outliers are so uncommon that you never see them. So I ran a few million tests and came up with a correction table which helps to offset this skew at larger variance values.
All of this is included in the python file. And, really, all it is is a convenient wrapper on the beta distribution. But I figured it out, and maybe you will find it useful! I’m planning on using this system in my own Role Playing experiments in the future. I’ll let you know how it goes!