Game Balance and Formulae
Symposium 21/2/2000
Introduction
======================================================================
When you start out adding a new feature, spell or skill there is often a
value that you need to get based on a number of factors. Often you know what
you want and you can say approximately what values you want to get for a
certain set of conditions but you just can't find the right formula to relate
them all together.
This document outlines the methods that I use for obtaining a fine balance
between elements of the game through the complex formulae that relate certain
elements of the game to a probability or a value.
This information is not strict directions, rather it should be used as a
guide and a description of possible methods. If you are intending to tweak
game functions and parameters then this file might help fine tune those
formulae.
In this file a number of references to DalekenMUD in examples and in this
there may be a few parameters that don't exist on your own mud
implementation. The core ideas of the document remain the same, however, and
you should ignore these and take the concept not the actual formulae.
This Document
---
This contains information that is at times a little to mathematical. The
intention is to give information on all the mathematics that can be used. A
certain degree of understanding of mathematics is assumed, but sections that
require a little more knowledge can probably be safely ignored.
The formulas in this document use C style syntax for operators, except for
the power operator '^', so 'x' squared becomes: x ^ 2
Beginning - Defining the Problem
======================================================================
Whether you are creating a new skill or spell and you have no idea of how
much damage you need to deal or you are defining a probability for adding an
enchantment or you are doing a complete overhaul over the to hit/armour class
balance there are a number of things you should consider before you start.
--> First write down what the outcome should be. Is it a probability? Is it
a damage value for the skill/spell? Is it a number of hitpoints you should
give to a mobile?
e.g. fireball spell: damage outcome.
--> Next write down all the things that you think should affect the final
result.
e.g. fireball spell:
spell level, caster's intelligence, caster's fire magic skill,
victim's fire magic skill, victim's magic resistance.
--> Establish which of the values are most significant. Rank your options
loosely and give them some token weighting.
e.g. fireball spell:
spell level,
caster's intelligence,
caster's fire magic - victim's fire magic,
victim's magic resistance.
Some things to remember:
* Parameters on the same scale (such as the fire magic skills in the
example) can be directly added or subtracted to make a single value.
NOTE: The problem here is that they MUST be on the same scale. Often
different values may appear to be on a similar scale but in actual fact
extreme values are not on the right scale, causing these methods to
break.
* Some parameters may rely somewhat on the value of other parameters,
keep this in mind and you may be able to eliminate a parameter from
the equation.
* Some parameters may not be directly related to others but there may be
some effect. If this is the case, try to keep the default values
reasonable.
e.g. If you increase level, armour class is likely to drop also. So
make sure that for higher levels you use a reasonable armour
class.
* Remember that some values are absolute and others are relative to
another value, sometimes the same value in one context can be relative
and in others it is absolute. Keep this in mind when you are looking
at a value.
e.g. In the fireball spell, level is absolute. On the other hand,
when it comes to working out save vs. spell level is then
relative, to the victim's level.
--> Now write down a few samples with 'guessed values', fill in a few simple
parameters and guess at what you think the result should be. It is often a
good idea to pick the most important parameter and vary it all over it's
possible range (only 3-5 values are needed) leaving all the other values at
some standard value. These values will serve as a guide later on so you can
tweak your formula.
--> Choose a method, or combination of methods to scale, twist, add, divide
and warp the values you have into the value you want. Remember that any of
the following methods can be combined for maximum effect, this is left to the
reader to arrange.
Summing Parameters
======================================================================
Sometimes a particular parameter suggests a different shape to another
parameter. In this case, the easiest choice is to take each parameter and
formulate a function for it. Then take the result from this and all the
other parameters and add them together. This can be used in combination with
other methods.
Note: probability scaling does not always benefit from adding to a result as
it can result in a value outside the range of probability.
Base Value + Scaling
======================================================================
A very common option with spell damage and similar values where there are no
strict upper bounds on the value (capping doesn't count). A base value is
determined using one or two of the major parameters and the others are used
to apply a scaling factor to this base number.
The best example of this is the fireball spell. Here the most significant
value by far is spell level, so this is used to obtain a base value.
e.g. base = level * 5;
This is oversimplified (I will cover curve fitting later) but serves for this
example. From here a number of scaling factors are used to get a final value
based on all the required parameters.
Probabilities
---
Probabilities are different from the values that have been dealt with so far
in that they have a definite limit on both ends of the scale. This means
that applying a scaling factor using any of the methods above can give a
value outside the range, which may not be desired. This leads into the next
section which describes how to combine all your values into a single
coefficient which is mapped via a single function to obtain an outcome.
A better method of fitting probability dealt with in the next section.
Linear Scaling
---
This is by far the easiest method of applying a scaling factor, the base
value is simply multiplied or divided by the value of the parameter and then
normalised by dividing (or multiplying) by an 'average' value.
e.g. scaled = base * intelligence / 15;
This assumes a value of 15 is a reasonable average value for intelligence, it
is important to keep an average value in mind here as the scaling value
shouldn't change the base value if the scaling factor is equal to the
average. Of course the base value can be changed to accommodate this scaling
and integer truncation, but for now it is best not to think of those things.
Here the victim's intelligence could also be factored in:
e.g. scaled = base * intelligence / vintell;
(Note how this linear scaling can be applied twice on the same line, this is
not a whole lot different to having two different scalings.)
This method however presents some pretty wild results (refer to the section
on unusual scaling methods, under hyperbolas) and it might be safer to use a
more reasonable method to factor in a negative influence:
e.g. scaled = base * intelligence * ( 30 - vintell ) / 225;
This now presents the idea of adding an offset to the values to smooth out
the changes. If an offset value was added to each intelligence value then
the that value would only affect a part of the entire value:
e.g. scaled = base * ( 20 + intelligence ) * ( 50 - vintell ) / 1225;
Note: You should keep in mind the value that you expect the parameters to be,
it helps to write down any new formula and then try out the result on
extreme values. Often a formula can be found to be ridiculous when a
particularly high or low value is tested.
The method of continual refinement is one that should be used for all of the
following scaling methods. Often the correct pattern isn't found straight
away and several attempts are made before settling on the right method of
scaling even.
Quadratic and Quartic Scaling
---
This represents using a linear scaling more than once. Using a scaling
factor of a higher power than one is rare, as this tends to exaggerate the
differences away from the centre far too much and a change in value nearer to
the centre is not as noticed. This is due to the gradient of a power an N
squared function being zero about the origin. This method of scaling is
often discarded as giving too much of an advantage to those at the extremes.
Powers less than One
---
This is the opposite of Quadratic and Quartic scaling, where the power of the
scaling factor is reduced to a fractional value. This in mathematical terms
gives the highest gradient about the origin, which causes more difference to
be noticed about the central point. The problem with this method is a
reliance on complex arithmetic, which can be quite processor intensive.
*** Note that this method is possible on values that should be zero and are
never going to be negative.
Exponential Scaling
---
This method is used in a similar way to the linear scaling. Find a central
point that serves as a reference and values to one side are scaled towards an
asymptote (a value that is not possible to reach, but every step brings you
marginally closer) and on the opposite side the values are increased or
decreased in greater and greater amounts.
The basic form for an exponential function is a little more complex than a
linear scaling but they can give a slightly nicer curve in some situations.
scaled = base + ( asymptote - base ) * ( 1 + ef ) ^ ( sf - ref )
base - the unscaled value.
asymptote - the limit that should not be reached, this may be zero in a
large number of situations.
sf - the scaling factor, the value used to scale, this is compared to
the value of ref, and for every point of difference the result will
change.
ref - a reference value to match the scaling factor against. This value
should be as close to the average or typical value as you can
manage as this will greatly reduce the distortion that using this
style of scaling can cause.
ef - exponential factor. This value should be small, depending on the
range of possible values for 'sf'. If this is positive then the
asymptote will be approached when 'sf' is on the negative side of
'ref', if it is negative then a large value of 'sf' will cause the
result to tend to the asymptote.
- Note: this value can be any positive number and any number down to
-0.99999, but as the value gets larger (or closer to -1) the rate
of increase of the result increases dramatically. This means that
values of 'sf' even slightly different to 'ref' can cause values
that can be extremely large.
- To counter any problems ensure that this value is never too large.
Especially take note of the range of likely values of sf - ref and
reduce this value as this range increases.
- Tip: in order to simplify things, you can make this value always
positive, in order to reverse it's effect, simply reverse 'sf' and
'ref' in the formula.
- Tip: A good rule of thumb for this value is to never exceed 0.1 for
values of sf - ref that are small (less than 10). Values of about
0.002 should be used for a range in the 100s. A value of 0.03
gives a pretty good starting point for values in the range -12 to
12.
Unusual Scaling Functions
---
There are also a few unusual scaling methods possible. These can be
extremely useful in situations where there are strict constraints or a
precise shape is to be obtained.
--> Arc Tangent:
diff = ( scale_value - reference ) / stretch;
result = base * ( 2 * atan( diff ) / M_PI + 1 );
(M_PI - the value for PI = 3.141592636... in C use 'M_PI')
Here the scaling factor (scale_value) is compared to a reference value,
and about this value the result is scaled from 0 to 2 times its original
value. At a value of 'stretch' above the reference value the result is
1.5 times the base and at 'stretch' below the reference the result is 0.5
times the base.
The atan function is extremely useful in these applications but the
requirement for floating point arithmetic can be heavy on a processor if
it has to be used too often.
--> Sinusoids:
These are special cases and they can only be used in certain ranges due
to their oscillating properties. The use of these is rare but they do
have certain advantages if used properly.
--> Hyperbolas:
These functions have the scaling factor on the denominator (e.g. 1/x).
These are incredibly risky to use due to the fact that at certain points
they tend to be undefined, which can result in a SIGFPE or divide by zero
and a complete crash. However they can be used if care is taken to
exclude the special cases under which a divide by zero can occur,
normally by limiting the range over which they are used.
The most common method of using a hyperbolic function is to take the
inverse (1/x) of a value in order to gain the opposite effect of an
increase in its value.
e.g. On stock Diku muds any hitpoints above a current maximum stay
until they are removed forcibly. It seems more appropriate
however to make them drain away slowly. Thus find the amount
that would normally be regenerated and then if the current is
above maximum drain an amount away. Additionally, allow those
who would normally regenerate a large amount to have it drain
away more slowly. Thus the formula for drainage is:
drainage = -5000 / regen;
This formula is simple and it allows a higher number to
correspond to a lower number. Note here that a value of 0 for
regen would cause a fatal error, so the value should first be
tested.
The Primary Factor - Combining the parameters
---
This involves combining all of the parameters in the equation into one,
giving them all different weightings and ensuring that they are balanced
against each other. In some cases several of the key parameters can be
combined using this method and the less likely left to be used later to scale
the result.
Remember: This section is the most rough of the lot, and the method here
should only be used as a guide, if this method is followed, then
this section will have to be revisited a number of times. This
method, more than any other in this document, is meant as a
possible solution to the problem.
Once you have all of your parameters you should list them in order of
significance in a table with a relative weighting and a second value that
represents the relative significance of a change in value.
Note: Weighting is dependent on both the size and range of a value, range can
mean as much as the size of a number.
Note: Remember the note above about relative and absolute values, keep this
in mind in this case, much of this weighting depends on that.
A good start is to put the value of 100 in both fields for the highest
priority and then fill in all the other values with respect to this starting
value.
e.g. fireball spell:
value weight increase
spell level 100 100
intelligence 60 100
fire magic diff 40 50
magic resistance 40 40
Now take the values and apply the following formula to each:
total = ( value - offset ) * weight ^ ( increase / 100 )
This will give a full weighted value for each parameter, now all that is
required is to add these together. From this long formula a value can be
obtained that contains all of the parameters in question.
Note: The offset value here is most often zero when the correct weighting
factor is used, however this value can be used to reduce the total.
This value becomes more useful as the starting value is restricted to a
small range about a larger number. Remember that if such a factor is
used then the weighting should be changed accordingly.
Tip: It doesn't matter much if the end value is less than zero, but in this
case an increase value cannot be used. If you intend to use the
increase value, ensure that the offset is set so that the value cannot
be negative.
Now this can be used as is, but it involves a number of highly inefficient
power operations in floating point. One solution to this is to remove the
increase value from the equation, which in most cases is sufficient.
If a better method is required, some fiddling is required, often with
functions often seen in electrical control, with complex numbers and formulas
that have several factors on the denominator etc... In other words, methods
that are too complex to even bother with, when a simple weighting is normally
enough.
Testing this formula is as easy as thinking up a few combinations of the
parameters used and then ranking them in order of those that should get the
highest score. If the values obtained through using this formula are in a
different order to this order then this stage will have to be repeated.
Finding the Base Value (aka. Curve Fitting 101)
---
From here all factors have been combined into a single value, or a single
critical factor has been selected. This value then must be mapped into a
final value.
Here is where those values that were written down at the start come into
play. These results should be plotted against the main value (if a combined
value is being used that will have to be calculated for each situation).
From here a pattern is often observed and the trick then is to find what the
pattern is so it can be matched with the right formula.
Refer to the curve fitting section for information on curves and their
possible applications.
Summary of Method
---
1. Find all parameters.
2. Write down some reasonable values for the outcome in certain key
situations to be used as a guide for tweaking.
3. Rank the parameters.
4. Select the most important parameters, if there are more than one combine
these into a single figure.
5. Look at the values decided on for a reasonable outcome and attempt to find
a curve that matches the pattern. Map the curve to the main value or the
composite value.
6. Apply the remaining parameters as scaling factors.
7. Test the resulting formula on the values written down at Step 2. If the
formula is too far off, start tweaking.
The Second Method - Scaling the Parameters
======================================================================
Probabilities and Scaling the Primary Factor
---
These require a value in a certain range (often between 0 and 100) which will
be matched to a random number in that range. Thus for a probability curve,
the actual value is very difficult to scale properly whilst still remaining
within the bounds. This is where the second method comes into play. This
concentrates on a curve and finding the right value on the x axis to match
the wanted values.
Select the Shape
---
The first task is to find what the graph should look like. This requires
some tinkering and a few sketches on a piece of paper. Keep the following in
mind.
* How much effect should a big rise in "the parameters" do to the result,
should it be a similar large rise? should the change be linear? should
the change slow?
* Should the value reach zero? Should the value be zero when "the
parameters" are zero?
* Probabilities are different, should the chance ever get to 100% or 0%,
or should it be capped somehow?
This part requires a fair amount of tinkering until the concept is fixed.
Fitting the Parameters to the Graph
---
All that is now required is to take the parameters, starting at the most
significant, and finding where they should be.
* For each parameter define an average value for each value of the main
parameter.
* Take the main parameter and for several values along the entire range,
plot where this corresponds to the desired value on the graph. Keep in
mind that at this point, all the other values should be at their average.
e.g. fireball spell: You use level as the most significant, thus values
of magic are assumed to increase one point every 20 levels. So at
level 10 assume the fire magic to be 2, and at level 50 fire magic
is 4 for the purposes of this scaling.
* From this a trend can be seen and a rough scale can be formulated from
this primary value. This can help in scaling this value to be put in
the formula, so write down the formula with the correct scaling factored
in.
* Now for each of the other values in turn, take a few points around each
of the points used for the first value and plot a range of values around
this value. This should help determine how much, and in what shape, to
scale this value.
e.g. fireball spell: About the level 10 mark plot values for fire magic
of 0, 1, 3 and 4. These might have the same effect as two thirds
of a level each point.
* As each stage goes in, the formula should be tested against all the
'ideal' values.
Curve Fitting
======================================================================
This section deals with the possible functions that can be used, hopefully
the information will give an idea of what the advantages are in using each
different type.
* Straight Line
The easiest of all the graphs to apply and test, a straight line is
often best in formula that are performance sensitive, even though it
offers little flexibility. This is also a common choice for an
offensive spell as it offers the best relation between level and
power.
* Polynomial
This may include a straight line as a major component, but the major
difference is
atan, exponential, straight line, polynomial, square root...
Things Not Covered in this Document
======================================================================
'if' statements - These can greatly simplify formula creation, don't be
scared to use them, they often can avoid complex math and
they can also improve the general result.
Reasons NOT to Use these Methods
======================================================================
It's not exactly as you would like it to be, possibly not ever. This
document only shows a few of the possible means of obtaining a balanced
function. In the end it is best to have a very simple formula.
Tools of the Trade
======================================================================
You should have a few of these tools handy, they are invaluable aids.
* A pen and paper. Write formulae. Jot down tables of values. Draw
sketch graphs. Pretty much the single most important thing, without this
nothing happens.
* A calculator. Sometimes you need to find a value, the computer's
calculator is almost invariably inadequate, so a regular scientific
calculator becomes your friend.
* Gnuplot. This is not exactly mandatory but I find it extremely useful in
showing me exactly how the formula look. This is an extremely easy to
use package and it can plot those complex formula you have concocted
pretty easily, even doing surface plots where you have two independent
variables.
This program is especially handy when it comes to tweaking the formula,
as key values can be quickly adjusted and a plot quickly redrawn.
e.g. Recently the heal spell on Daleken got a revamp. When it was cast
a quantity of available mana was converted into extra healing. The
formula for the spell efficiency was found for both before and
after, these formula were entered into gnuplot and plotted against
each other. The following code sets up the two functions f(x) and
g(x) (x represents level in this case) and then plots them both over
a scale of 0 to 250.
gnuplot << EOF
f(x) = x / 50
g(x) = (x ** 2 / 25 + 4 * x) / (50 + x / 5)
plot [x=0:250] f(x),g(x)
EOF
This not only confirmed the theory that the addition was gradually
more efficient, but it also showed exactly how much healing would be
taking place, it turned out that the efficiency was far too high at
the higher levels, so the increase would have to be scaled back.