Man rarity

From LSWiki

Jump to: navigation, search

Contents

Files

   /lib/rarity.h
   /mod/global/rarity.c

Description

This document describes the lib's rarity mechanics. These are mainly used in applications of the selection parser (see 'man selection'), but can be employed by other code as well.

Rarity Levels

rarity.h defines nine rarity levels, as follows:

   Very Common
   Common
   Unusual
   Very Unusual
   Rare
   Very Rare
   Exotic
   Very Exotic
   Special

The last level, Special, is not a true rarity level. It is used for things that should never be selected in any random pool, but nonetheless need a rarity associated with them. Some materials, for example, set this rarity so that they will never show up randomly.

The other levels indicate progressively increasing rarity. The relationships between the levels are as follows:

   Common is half as likely as Very Common
   Unusual is half as likely as Common
   Very Unusual is two-fifths as likely as Unusual
   Rare is half as likely as Very Unusual
   Very Rare is half as likely as Rare
   Exotic is one-fifth as likely as Very Rare
   Very Exotic is half as likely as Exotic

If you had a pool of at least one thing from each rarity level, with no likelihood adjustments, the percentage chance of getting the thing from each rarity level would be:

   Very Common                     51.74%
   Common                          25.87%
   Unusual                         12.93%
   Very Unusual                     5.17%
   Rare                             2.58%
   Very Rare                        1.29%
   Exotic                           0.25%
   Very Exotic                      0.12%

When working with pools that do not include all the rarity levels, the base probabilities shift, according to the relative likelihood of each level. For instance, if you had only Very Common and Common things in your pool, you would get a Very Common thing 2/3 of the time and a Common thing the other 1/3. If you had only items of Unusual rarity and above, the percentages would be:

   Unusual                         57.80%
   Very Unusual                    23.12%
   Rare                            11.56%
   Very Rare                        5.78%
   Exotic                           1.15%
   Very Exotic                      0.57%

If you had only things of Rare rarity and above:

   Rare                            60.60%
   Very Rare                       30.30%
   Exotic                           6.06%
   Very Exotic                      3.03%

Rarity Processing

Rarity processing is handled by /daemon/rarity, which publishes various functions as services. Always use the macros for these functions, as shown below. These functions are:

mixed Rarity_Select(mapping select, mapping adjust)

   Returns a randomly selected element of the mapping provided as the first
   argument, which should look something like this:
       ([
           some_value           : Rarity_Common,
           some_other_value     : Rarity_Unusual,
           yet_another_value    : Rarity_Unusual,
       ])
   The optional second argument (supply 0 if none) is a mapping that defines
   adjustments to the final likelihoods of individual elements, as described
   later on.  It might look like this:
       ([
           some_value           : 1.5,
           some_other_value     : 0.1,
       ])

mixed Rarity_Distribution(mapping select, mapping adjust, status allow_array)

   Takes the same arguments as rarity_select() and returns the final mapping
   of elements to likelihoods.  "Likelihoods" are integer proportions, after
   the fashion used by random_element(); the mapping returned by this function
   is suitable to be passed directly to random_element().
   If the third argument is true, then rarity_distribution() will be allowed
   to select randomly from among the rarity levels in its distribution and
   return the array of items from that level, rather than returning a full
   distribution.  This can only be done when no adjustment values are being
   provided.

mapping Rarity_Analyze_Distribution(mapping distribution)

   Takes an argument of a mapping containing values mapped to likelihoods
   (integer proportions), as returned by rarity_distribution() or macros like
   Selected_Materials_Distribution(), or as generally used with the function
   random_element().  The return value is a mapping of the argument's keys
   values mapped to float percentage chances of the value being selected by
   random_element().  Useful for getting an idea of the actual percentages
   you're winding up with from a likelihood distribution.

mixed Rarity_Distribution_Relative(mapping select, mapping adjust)

   Similar to rarity_distribution(), but rather than returning a mapping with
   integer proportions defining absolute weights, returns a mapping with
   float proportions defining relative weights.  The smallest proportion is
   arbitrarily assigned the value of 1.0, and the other proportions have
   values indicating their magnitude relative to that proportion.  This is
   mainly useful in cases where a rarity distribution is being used in
   conjunction with functions like distribute_proportionally(), and the
   values in play are large enough to potentially cause overflow errors if
   integers are used.

mixed Rarity_Select_Simple(mapping select, mapping adjust)

   Similar to Rarity_Select(), but does a simple distribution as described
   below.

mixed Rarity_Distribution_Simple(mapping select, mapping adjust)

   Similar to Rarity_Distribution(), but does a simple distribution as
   described below.

mixed Rarity_Distribution_Simple_Relative(mapping select, mapping adjust)

   Similar to Rarity_Distribution_Relative(), but does a simple distribution
   as described below.

How Rarity Becomes Likelihood

When rarity_distribution() turns a mapping of values to rarities into a mapping of values to likelihoods, it normally does so in a way that gives results that may be counterintuitive until you understand what it's doing.

The first thing to understand is that, before adjustments are taken into account, the chance of a value of a given rarity being selected is held constant. This means that no matter how many Common values you have in your mapping, you have the same chance of getting a Common item. You can think of this almost as if the mechanism were selecting a rarity level first, and then randomly selecting a value from within that rarity level only.

One thing this means is that, when looking at final percentages (as when using analyze_distribution()), you can actually wind up with individual values of Exotic rarity being more likely than individual values of Rare rarity, because there are relatively few Exotic values and relatively many Rare values. The overall likelihood of the Rare category winds up being split enough ways that the likelihood of individual values in the category falls below the likelihood of individual Exotic values.

This becomes more complex when likelihood adjustments are present, as our next section explores.

The exception to this is when using the "simple" distribution functions. In these cases, the rarity values are simply used as weights, with no attempt to hold the probability of rarity levels constant with respect to each other. This is most appropriate when you are dealing with a small set of items in your rarity distribution, which would cause somewhat distorted behavior when the probability manipulations described above are used.

Likelihood Adjustments

The optional second argument to rarity_select() and rarity_distribution() allows you to tune the likelihood of individual values in your rarity map. The adjustment argument is a map of values to float multipliers for the value's likelihood, as shown above in the documentation for the rarity_select() function. If a value does not appear in the map, its likelihood is not adjusted.

The manipulations performed by the adjustment map violate the principle of relative likelihood of rarity levels being held constant. If you have one Common value and one Unusual value, and adjust the Unusual value's likelihood by 2.0, you wind up with the two values having the same likelihood. This is intentional, and done so that adjustments remain meaningful across rarity levels.

[ Example ]

A quick example of a way you might use a rarity-based selection:

   void configure() {
       string adj = Rarity_Select(([
           "happy" : Rarity_Common,
           "sad"   : Rarity_Uncommon,
           "angry" : Rarity_Rare,
       ]), 0);
       alter_identity(Identity_Adjectives, ({ adj }), True);
   }

For a more involved example, look at the randomize_ring_craft() function in /std/app/rings/ordinary.c. That shows a way you might use an adjustment map set up according to situational factors to alter a basic rarity map.

See Also

random_element(sefun), selection(mechanisms), selection_core(mechanisms)

Personal tools