Man selection
From LSWiki
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)