Man selection

From LSWiki

Revision as of 17:25, 11 June 2007; Laine (Talk | contribs)
(diff) ←Older revision | Current revision | Newer revision→ (diff)
Jump to: navigation, search

Contents

Files

/lib/rarity.h
/lib/selection.h
/mod/global/rarity.c
/daemon/materials.c
/daemon/races.c

Description

This is a basic description of how to use the lib's general, flexible mechanism for selection from a pool of things, as implemented at the core level for random characters, items, locations, materials, and races. For the rest of this document, an element of the pool you're selecting from will be called an 'item', though it could be anything.

A quick example to give you the flavor of the thing:

#include <item.h>
void configure() {
    ::configure();
    object material = Random_Material(({
        Select_Include_Property(Prop_Metal),
        Select_Exclude_Phase(Matter_Phase_Liquid),
    }));
}

This would select a material (the object definition is returned) from the pool of materials which are metals but not liquids.

Selection Definitions

Selection definitions are arrays like that shown above. Within selection definitions, three kinds of element occur: operators, designators, and modifiers.

Operators

The operators, which define the type of operation you are doing, are:

Include: Your Includes define the items you are selecting from. If you do not have any Includes, you cannot select anything.

Exclude: Your Excludes define a set of items you do not ever want to select. Includes and Excludes are processed in the order given, so an Exclude will override a previous Include, and an Include will override a previous Exclude.

Require: Requires can be thought of as an "exclude-not" shorthand; that is, they Exclude items which do *not* have the designator specified. It is important to understand that they do not Include anything, only Exclude.

Adjust: Adjusts alter the probability of a given item in the pool occurring. The basic likelihood of encountering any given item is controlled by the rarity level defined for it, using the macros from /lib/rarity.h. Any Adjust operation receives an extra argument of a numeric value that the item's likelihood is multiplied by, or a closure that should return a numeric value to multiply likelihood by (see 'Closure Arguments' below regarding the arguments it receives). For instance, a value of 2.5 makes the item 2.5 times as likely to occur, and a value of 0.5 makes it half as likely to occur. Adjust operators MUST occur AFTER all Include operators, as they operate only on items that have been Included and not Excluded (for efficiency).

Option: For setting special options. You usually won't need this, so it's covered in a separate section, Parser Options, below.

Designators

The chart below shows the various designators and the contexts in which they apply. Afterward, the designators are described in detail.

/--------------------------------\ /-----\ /-----\ /-----\ /-----\ /-----\
| Designator                      | Chars | Items | Locat | Matls | Races |
>---------------------------------+-------+-------+-------+-------+-------<
|   All                           |   *   |   *   |   *   |   *   |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Anatomy                       |   *   |       |       |       |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Anatomy Component             |   *   |       |       |       |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Category                      |   *   |   *   |       |       |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Custom                        |   *   |   *   |   *   |   *   |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Danger                        |   *   |   *   |   *   |       |       |
>---------------------------------+-------+-------+-------+-------+-------<
|   Density                       |   *   |   *   |       |   *   |       |
>---------------------------------+-------+-------+-------+-------+-------<
|   Egress                        |       |       |   *   |       |       |
>---------------------------------+-------+-------+-------+-------+-------<
|   Exposure                      |       |       |   *   |       |       |
>---------------------------------+-------+-------+-------+-------+-------<
|   Material                      |   *   |   *   |       |   *   |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Name                          |   *   |   *   |   *   |   *   |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Phase                         |   *   |   *   |       |   *   |       |
>---------------------------------+-------+-------+-------+-------+-------<
|   Plane                         |   *   |       |   *   |       |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Property                      |   *   |   *   |       |   *   |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Race                          |   *   |   *   |       |       |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Rarity                        |   *   |   *   |   *   |   *   |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Realm                         |   *   |       |   *   |       |       |
>---------------------------------+-------+-------+-------+-------+-------<
|   Sentience                     |   *   |   *   |       |       |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Sex                           |   *   |       |       |       |   *   |
>---------------------------------+-------+-------+-------+-------+-------<
|   Specialty                     |   *   |       |       |       |   *   | 
>---------------------------------+-------+-------+-------+-------+-------<
|   Terrain                       |   *   |       |   *   |       |       |
>---------------------------------+-------+-------+-------+-------+-------<
|   Value                         |       |   *   |       |   *   |       |
\--------------------------------/ \-----/ \-----/ \-----/ \-----/ \------/ 
All: Selects the entire potential pool of items (or, in the case of
   Adjust operations, the pool of Included items).  Unlike the others,
   this designator only exists in the forms Select_Include_All (with
   no arguments) and Select_Adjust_All().  It would be meaningless
   for Exclude operations.
Anatomy: Based on the item's anatomy.  Takes as an argument the string
   anatomy name; matches only precisely that anatomy.
   Characters: Uses query_anatomy() in the character blueprint object.
   Races: Uses query_anatomy() in the race definition.
Anatomy Component: Based on the item's anatomy.  Takes as an argument
   a string which can appear anywhere in an item's anatomy for a match.
   Characters: Uses query_anatomy() in the character blueprint object.
   Races: Uses query_anatomy() in the race definition.
Category: Based on the categories defined for the item.
   Characters: Uses the categories set in the character blueprint object's
       race.
   Items: Uses the item categories, as defined for item descriptors,
       with which the item was published for random selection use.
       The value is expected to be an integer bitmask; if the bitmask
       is made up of more than one category combined with bitwise-or,
       items will be selected if they are in any of the categories.
       (See /txt/doc/descriptors/item.)
   Races: Uses the categories set in the race definition.  An error will
       be raised if a category name is specified that has not been used
       by any race definitions.  The value is expected to be a string
       category name.

Custom: Based on a custom filtering function. Takes as an argument the

   closure you want to use.  See 'Closure Arguments' below regarding
   the arguments the closure receives.

Danger: Based on a comparison of the danger information defined for the

   item.  Takes two arguments, the first being the closure of the function
   you want to use for comparison.
   Characters: Compares with the Character_Dangers flags defined for the
       character in its character descriptor.  Typically, the closure
       sent for comparison is bitwise-and, #'&.
   Items: Compares with the Item_Dangers flags defined for the item in
       its item descriptor.  Typically, the closure sent for comparison
       is bitwise-and, #'&.
   Locations: Compares with the Location_Danger field defined for the
       item in its location descriptor.

Density: Based on a comparison of the item's value. Takes two arguments,

   the first being the closure of the function you want to use for
   comparing densities, e.g. #'>, #'<=, the second being the density
   (float or int) you want to compare with.
   Characters: Uses query_density() in the character blueprint object.
   Items: Uses query_density() in the item blueprint object.
   Materials: Uses query_material_density() in the material definition.

Egress: Based on a comparison of the egress information defined for the

   item.  Takes two arguments, the first being the closure of the function
   you want to use for comparison.
   Locations: Compares with the Location_Egress field defined for the
       item in its location descriptor.

Exposure: Based on a comparison of the exposure setting in the item. Takes

   two arguments, the first being the closure of the function you want to
   use for comparison.
   Locations: Compares with the set_exposure() in the room object.

Material: Based on the presence of a material. Takes as an argument the

   relevant material, or an array of materials.  (Right now there is no
   way for this to specify material source, e.g. coats and so on.  This
   will presumably be rectified in the future.)
   Characters: Uses query_material() in the character blueprint object.
   Items: Uses query_material() in the item blueprint object.
   Materials: Affects only the specified materials; does not check
       material composition.
   Races: Checks based on the race's material settings.

Name: Based on the item's names. Takes a string argument of the relevant

   identifier.
   Characters: Uses id() in the character blueprint object.  The character
       daemon is sent as the observer argument, which normally means
       the character's "known" IDs are used.
   Items: Uses id() in the item blueprint object.  The item daemon is sent
       as the observer argument, which normally means the item's "known"
       IDs are used.
   Locations: Looks for the identifier as a substring of the room's
       query_short().
   Materials: Compares with the material's name and aliases.
   Races: Compares to the race's name.

Phase: Based on the item's matter phase (as defined by physics.h). Takes

   an argument of the relevant phase.
   Characters: Checks against query_phase() in the blueprint object.
   Items: Checks against query_phase() in the blueprint object.
   Materials: Checks against query_material_phase().

Plane: Based on the planes associated with the item. Takes an argument

   of the relevant plane.\
   Characters: Checks for the presence of the argument in the
       query_race_native_planes() for the character blueprint object's
       race.
   Locations: Checks against query_plane().
   Races: Checks for presence in query_race_native_planes().

Property: Based on the presence of a property. Takes as an argument

   the relevant property, or an array of properties which behaves the
   same way as with query_property() -- the first level of the array
   functions as an "or", the second level as an "and".
   Characters: Uses query_property() in the blueprint object.
   Items: Uses query_property() in the blueprint object.
   Materials: Uses the material's defined property list.
   Races: Checks based on the properties defined by the race's
       property and material settings.

Race: Based on the race set in the item.

   Characters: Uses query_race() in the blueprint object.
   Items: For items which have a race setting (armour, at the moment),
       compares with their race setting; others are not selected.
   Races: Uses the race's name.  Names that do not appear in /def/race
       can be used here.

Rarity: Based on the item's rarity level. Takes two arguments, the first

   being the closure of the function you want to use for comparing
   rarities, e.g. #'>, #'<=, the second being the rarity you want to
   compare with.
   Characters: Uses the rarity set for the character in its character
       descriptor.
   Items: Uses the rarity set for the item in its item descriptor.
   Locations: Uses the rarity set for the location in its location
       descriptor.
   Materials: Uses the material's query_material_rarity().
   Races: Uses the race's query_race_rarity().

Realm: Based on the realms set in the item. Takes as an argument the

   string realm to use.
   Characters: Compares with the query_realms() set in the character
       blueprint object.
   Locations: Uses query_realm() in the room object.

Sentience: Based on the sentience setting in the item. Takes the

   desired sentient value, True or False, for an argument.
   Characters: Uses query_sentient() in the blueprint object.
   Items: Uses query_sentient() in the blueprint object.
   Races: Uses the sentience setting in the race definition.

Sex: Based on the item's sex settings.

   Characters: Compares the argument with the character's sex.  In
       the case of abstract sex settings like Sex_Any_Racial and
       Sex_Typical_Racial, the designator will match if the argument
       given matches any of the possible sexes for the chracter.
   Races: Looks for the argument in the race's query_sexes().

Specialty: Based on the skill specialty configuration for the item.

   The argument is the skill to check for a specialty in.
   Characters: Checks query_specialty() in the blueprint object with
       respect to the specified skill; this means it evaluates as true
       if the blueprint has any specialty degree in that skill.
   Races: Checks query_race_required_specialty() in the race definition;
       this means it evaluates true if the race requires any degree of
       specialization in that skill.

Terrain: Based on the terrains set in the item.

   Locations: Uses query_terrain() in the room object.

Value: Based on a comparison of the item's value. Takes two arguments,

   the first being the closure of the function you want to use for
   comparing values, e.g. #'>, #'<=, the second being the value you want
   to compare with.
   Items: Uses query_real_value() in the object blueprint object.
   Materials: Uses the material's query_material_value().

If you use a designator that doesn't apply to a given type of item -- for instance, if you send the materials daemon a selection specification that includes Select_Include_Terrain() -- an error will be raised.

Modifiers

Modifiers alter the behavior of a designator in some way. To understand how to use modifiers, you need to understand that the macros used so far are actually constructed from other macros that can be used independently. For example, writing Select_Include_Property(Prop_Metal) is the same as Select_Include(Select_Property(Prop_Metal)). Once a macro is broken down this way, you can apply modifiers to the designator, as you will see below. The modifiers are:

And: Takes as its argument an array of designators, each of which must apply in order for an item to be designated. For example:

   Select_Exclude(Select_And(({
       Select_Property(Prop_Sturdy),
       Select_Value(#'>, 50),
   })))

This excludes only items that are sturdy and have a value over 50.

Or: Takes as its argument an array of designators, any of which can apply in order for an item to be designated. This is usually not useful, since in most circumstances you can simply add another operation to accomplish the same thing, but it may be necessary for some particularly tortured logic structures, so it's available. No example is provided so as to discourage people who don't need it from using it.

Not: Reverses the meaning of its argument. For example:

   Select_Adjust(Select_And(({
       Select_Property(Prop_Gemstone),
       Select_Not(Select_Property(Prop_Transparent)),
   })), 10.0)

This makes items which are gemstone but are not transparent ten times as likely to occur.

As you can see in the last example, modifiers can modify each other.

Examples

A more complex example that uses several of these capabilities:

   #include <item.h>
   void configure() {
       ::configure();
       object material = Random_Material(({
           Select_Include_Property(Prop_Metal),
           Select_Include_Material(Material_Granite),
           Select_Exclude_Property(Prop_Liquid),
           Select_Exclude_Material(Material_Sodium),
           Select_Exclude_Rarity(Rarity_Extremely_Rare),
           Select_Exclude_Value(#'>, 50),
           Select_Adjust_Property(Prop_Fragile, 0.5),
           Select_Adjust_Value(#'<=, 10, 3.0),
       }));
   }

This example selects from a pool made up of all the non-liquid metallic materials except sodium, plus granite, with any extremely rare materials or materials with a value (per dekan of mass) over 50 excluded. It then halves the likelihood of each fragile material, and makes materials with a value of 10 or less three times as likely.

   #include <item.h>
   void configure() {
       ::configure();
       object material = Random_Material(({
           Select_Include_All,
           Select_Exclude(Select_And(({
               Select_Property(Prop_Metal),
               Select_Property(Prop_Brittle),
           }))),
           Select_Exclude(Select_And(({
               Select_Property(Prop_Stone),
               Select_Property(Prop_Fragile),
           }))),
           Select_Adjust(Select_And(({
               Select_Property(Prop_Ferrous),
               Select_Value(#'>, 10),
           })), 5.0),
       }));
   }

This example selects from the pool of all materials except brittle metal and fragile stone, while making ferrous materials with a value over 10 five times as likely to occur.

Closure Arguments

Any closure specified as a Custom designator or as a closure Adjust argument receives a set of arguments depending on the context, as follows:

Characters

   The character's blueprint object
   The character descriptor for the character
   The parser's options mapping

Items

   The item's blueprint object
   The item descriptor for the character
   The parser's options mapping

Locations

   A sample room object for the location
   The location descriptor for the location
   The parser's options mapping

Materials

   The material definition object
   The parser's options mapping

Races

   The string race name
   The race definition object
   The parser's options mapping

Header Files

The header files to include in order to get the macros for working with selection in each context are:

Characters: random_characters.h

Items: random_items.h

Locations: random_locations.h

Materials: materials.h

Races: races.h

Selection Macros

The examples above use the macro Random_Material(), which is a specific form of Random_X(), where X could be Character, Item, Material, Race, or Location. There are several other selection macros you can use for different purposes. The full list is:

Random_X(), e.g. Random_Material()

   Has one argument, a selection definition.  Selects one item out of
   its pool and returns it.  If the pool is empty, returns 0.

Random_Xs(), e.g. Random_Materials()

   Has two arguments, a selection definition and a number.  Selects
   the number of items indicated from its pool and returns them in an
   array.  If the pool is empty, returns an empty array.

Random_Xs_Unique(), e.g. Random_Materials_Unique()

   Has two arguments, a selection definition and a number.  Selects
   the number of items indicated from its pool, without repeating any
   items, and returns them in an array.  If the pool is empty, returns
   an empty array.  If there are not enough unique items in the pool
   to satisfy the amount requested, returns an array of all the items
   in the pool.

Selected_Xs(), e.g. Selected_Materials()

   Has one argument, a selection definition.  Returns an array of all
   the items in its pool.

Selected_Xs_Distribution(), e.g. Selected_Materials_Distribution()

   Has one argument, a selection definition.  Returns a mapping of all
   the items in its pool to their respective likelihoods.  This is a
   mapping suitable for use with random_element().

Note that an item can drop out of the selection pool by being Excluded, by having its likelihood Adjusted to the point that it winds up with a zero likelihood, or if its rarity setting is Rarity_Special or invalid.

Your code should be prepared for the eventuality that it will get an empty result or a smaller result than it expects, according the conditions given above for each macro.

Note also that /lib/items.h defines a large number of convenience macros that allow you to easily select from various commonly used object pools without having to write your own selection statement.

Parser Options

The Option operation, described briefly above, is used for setting options that affect the operation of the engine that parses your selection information. Unlike the other operations, Option does not work alongside designators, and only has one relevant macro, Select_Option. The macro takes two arguments, the string option name and the mixed-type value to pass for it.

Parser-level options are only employed by the parser daemons for items, locations, and characters, and they use the same options. These are:

   output: Selects the type of output you wish the parser to produce.
   The values you may select are macros defined in selection.h, as
   follows:
       Select_Output_Item_Name: The output item will be the string
       object name of the item blueprint.  You may need to check
       query_unique() in the blueprint to determine whether to clone
       it for use.
       Select_Output_Item_Blueprint: The output item will be the
       blueprint object.  You may need to check query_unique() in this
       object to determine whether to clone it for use.
       Select_Output_Item_Object: The output will be a final object
       (cloned if necessary), ready for use as randomly generated
       content.  For items and locations that reference a group of
       objects, this will be randomly selected from among the group,
       whereas Select_Output_Item_Blueprint will always be the same
       reference object.  For items and characters, may not be used
       with the Selected_Xs() or Selected_Xs_Distribution() macros.
       Select_Output_Item_Descriptor: The output will be the descriptor
       defining the item's selection setup.
   suppress_unique: Causes the parser to remove unique items (NPCs,
   in the case of characters) from its selection pool.

You can also define your own options; the namespace of options that begin with "user_" is reserved so you can set options that will be passed to any closures you use, as described in Closure Arguments above. So, if you have Select_Option("user_signal", True) in your selection definition, your closures will receive as one of their arguments a mapping that looks like ([ "user_signal" : True ]). Note that options are parsed in the sequence given; so if you have a select definition like this:

({
    Select_Option("user_signal", True),
    Select_Custom(#'select_specially),
    Select_Option("user_signal", False),
    Select_Custom(#'select_specially),
})

Then select_specially() will receive an options mapping with the "user_signal" option set to True the first set of times it is called and a mapping with "user_signal" set to False the second set of times. The uses for this are perhaps obscure, but it's there if you need it.

Return Values

Exactly what an item consists of, and therefore what the selection macros can be expected to return, varies according to context, as shown:

Characters: Varies according to the setting of the output option, as described above. The default is Select_Output_Item_Object when using the Random_Character(), Random_Characters(), and Random_Characters_Unique() macros, and Select_Output_Item_Blueprint when using Selected_Characters() or Selected_Characters_Distribution().

Items: Varies according to the setting of the output option. The default is Select_Output_Item_Object when using the Random_Item(), Random_Items(), and Random_Items_Unique() macros, and Select_Output_Item_Blueprint when using Selected_Items() or Selected_Items_Distribution().

Locations: Varies according to the setting of the output option. The default is Select_Output_Item_Object.

Materials: Items are object material definitions.

Races: Items are string race names.

Miscellaneous Notes

When working with this mechanism, use the macros in the fashion specified. Use literal values out of selection.h on pain of my severest displeasure.

To see this mechanism in action with materials, take a look at the rings in /obj/armour and the class they're based on, /std/app/rings/ordinary.c. For races, see /d/Almeria/Temple/mon/reveller.c.

When using Adjust statements, specifying large probability-increasing adjustments (values > 1) will unfortunately often cause integer overflow errors to occur, since the numeric values used as the basis of probability weights are large. The proper way to deal with this is simple: rather than specifying a probability-increasing adjustment for your target class, specify a probability-decreasing adjustment (value < 1) for everything else. For example, rather than an Adjust of 100.0 for swords, use an Adjust of 0.01 for everything except swords.

See Also

descriptors(mechanisms), item(descriptors), location(descriptors), character(descriptors), rarity(mechanisms), selection_core(mechanisms)

Personal tools