thing

std
OBJECT
	/std/thing


LAST UPDATE
	Mateese, 12-Apr-98


SYNOPSIS
	#include <properties.h>

	inherit "/std/thing";


DESCRIPTION
	This is the general class for all LPC-objects used in
	OSB. From /std/base it inherits its general purpose
	property mechanism and extends it by a row of builtin
	properties and the possibility to move around.

	Besides the builtin properties described below, things
	normally feature following (mostly soft) properties:

	  mixed P_AUTOOBJECT   "AutoObject"
	    If the thing should be autoloading, the property has to be
	    set to a non-zero value. The value itself is stored over
	    logout and restored then again.

	  object P_EQUIPPED	"Equipped"
	    When set, it determines the carrying object of which this
	    thing is considered an equipment.
	    If a thing is carried by it's P_EQUIPPED object, it no
	    longer reacts on 'all' commands, but only on the 'really
	    all'-type.

	  string P_EXTRALOOK   "Extralook"
	    If set, the string is included after the P_LONG
	    description into the carriers description.

	  string P_INFO        "Info"
	  string P_VERSION     "Version"
	    You can put your name and a version number here.

	  mixed P_MAGIC        "Magic"
	    Describes a magic item.
	    Needs further specification yet.

	  int P_SIZE	       "Size"
	    This prop gives a rough estimate of the relative size of
	    an object.
	    Allowed values are defined in /sys/properties.h as
	      PSIZE_GENERIC = 0: this object fits alls sizes
	      PSIZE_SMALL   = 1: this object is a small one
	      PSIZE_NORMAL  = 2: this object is of its typical size
	      PSIZE_LARGE   = 3: this object is a large one
	    This is not an absolute value. Both a knife and a bihander
	    would qualify as 'PSIZE_NORMAL' as long as as human can
	    handle them. For a dwarf both would be too large to be
	    handled, for a giant too small. The function
	    'CompareSize()' in /std/thing/description helps with
	    comparisons.


	The top level file defines these functions:

	  void create ()
	    Initialises the thing, calls base::create().

	  int clean_up (int ref)
	    Performs the clean_up handling by calling
	    moving::clean_up().

	  void init ()
	    Might add commands and do other entrance specific stuff.
	    For now, this is here just for consistency.


	--- /std/thing/description ---

	  string * P_IDS   "Ids"
	    A list of ids the thing has to acknowledge.

	  string * P_ADS   "Ads"
	    A list of optional adjectives to be applied to the ids
	    when parsing a id() call.

	When set, both P_IDS and P_ADS are mapped to lower case, and
	all sequences of spaces are shrunk to just one space. It is
	however legal to have P_IDS or P_ADS with embedded spaces.

	  string * P_CLASS_IDS	 "ClassIds"
	  string * P_CLASS_ADS	 "ClassAds"
	    Similar to P_IDS and P_ADS, but these describe generic
	    features of a thing.
	    A torch would the specific identification 'heavy torch',
	    and the generic identification 'burnable thing'.

	  string (*) P_LONG    "Long"
	    Contains the long description of the thing.
	    This can be either a single string, or an array of two
	    strings, the first for the normal 'look at', the second
	    for the closer 'examine'.

	  string P_SHORT   "Short"
	    Return the short description of the thing.
	    This must be a single-lined string, starting with a
	    lowercase letter and ending without newline.
	    If the string is set to 0, the thing is invisible.

	  string P_READ_MSG  "ReadMsg"
	    The text which describes what the players sees when it
	    'reads' the thing, or a closure returning the text.
	    It can be 0.

	  string P_NOISE   "Noise"
	    A description of the noise the thing emits, or 0.

	  string P_SMELL   "Smell"
	    A description of the smell the thing emits, or 0.

	  mapping P_SUB_DETAILS  "SubDetails"
	    A mapping holding the descriptions of details on the
	    thing. Indices are the detail ids, values are the
	    description strings, resp. arrays of two strings
	    (look and examine description).
	    The details are identified as "<detailid> on <thing>"
	    and "<detailid> of <thing>".

	  mapping P_SUB_READMSGS  "SubReadMsgs"
	    A mapping holding the messages of readable details on
	    the thing. Indices are the detail ids, values are the
	    message strings.
	    The details are identified as "<detailid> on <thing>"
	    and "<detailid> of <thing>".

	To ease the specification of sub details and readmessages,
	auxiliary functions exist:
	
	  void AddSubDetail(string|string * det, mixed descr, void|mixed exa)
	  void AddSubDetail(string|string * det, mixed * descrs)
	    Add the subdetail <det> to the thing and describe it with
	    <descr>. If <exa> is specified, this is the description used for
	    "examine"s. Both descriptions may be combined into one array.
	    If <det> is given as array, the description(s) are set for each
	    of the single details.
	    It is possible to specify the <descr> as closure. In this case
	    this closure is called on need to return the description string.
	    It may also return an array with the "look"- and the "examine"-
	    description strings. The closure is called with the <det> string
	    as argument.
	    
	  void RemoveSubDetail(string|string * det)
	    Remove the detail description(s) for <det>.

	  void AddSubReadMsg(string|string * key, mixed msg)
	  void RemoveSubReadMsg(string|string * key)
	    Similar to the Add/RemoveSubDetail() functions.


	  string P_NOBUY       "NoBuy"
	    If set to a non-zero value, the thing can't be bought from
	    a shop.
	    If the value is a string, it is used as failure message.

	  string P_NOSELL      "NoSell"
	    If set to a non-zero value, the thing can't be sold to
	    a shop.
	    If the value is a string, it is used as failure message.

	  int P_VALUE	   "Value"
	    The value of the thing.

	  string P_INFO    "Info"
	    A string to contain a short technical description of the
	    thing and its author.

          string|closure P_HELP_MSG  "HelpMsg"
	    A string containing a short informational text about the
	    object (or room). It is queried by the player 'help' command.
	    Instead of a string, a closure may be used as value.
	    Upon query, the closure is executed and has to return the
	    informational text to be displayed.
	    If a player ask for help on an object with not P_HELP_MSG
	    set, a BUG report is generated. This can be avoided by
	    setting the P_HELP_MSG to the empty string (default for rooms).
	    In this case, the player will see a default text.

	To ease the specification of ids and ads, auxiliary functions
	exist:

	  string * AddId (string|string * id)
	    Adds <id> to P_IDS and returns the new value of P_IDS.
	    <id> may an array of strings as well.

	  string * RemoveId (string|string * id)
	    Removes <id> to P_IDS and returns the new value of P_IDS.
	    <id> may an array of strings as well.

	  string * AddAdjective (string|string * ad)
	  string * RemoveAdjective (string|string * ad)
	  string * AddClassId (string|string * id)
	  string * RemoveClassId (string|string * id)
	  string * AddClassAdj (string|string * ad)
	  string * RemoveClassAdj (string|string * ad)
	    Similar.

	To support 'unit'- or 'detail'-operations, the each call to
	id() (re)sets these  read/only properties:

	  string P_LAST_ID  "LastId"
	    The last recognized id string.

	  string P_LAST_VERB  "LastVerb"
	    The command verb of the last successful id().

	  object P_LAST_PLAYER	"LastPlayer"
	    The command giver of the last successful id().

	This data should be stored in the CmdData stack in the current player.

	If the object defines details (normal and readable), they are
	recognized in strings of the form "<detailid> on <thing>" and
	"<detailid> of <thing>". The detailid is stored in the player
	command data under the key "<filename_of_object>:subid".
	Long(), ExaLong() and Read() check this entry to return the correct
	text.

	The identification function itself is

	  int id (mixed try_id)

	and checks for both specific and class id.

	  int class_id (mixed try_id)

	just checks the class id (but allows combination with
	'specific' adjectives).

	Internally the id-matching mechanism operates using regular expressions:	the given ids and adjectives are compiled into a pattern, which is
	then used in id() and class_id() for the actual matching. This all
	happens automatically. Any change in the ids or adjectives erases
	the associated pattern, which is then recreated anew at the next
	call to id() or class_id(). For debugging purposes, the pattern are
	accessible through properties on their own:

	  string P_CLASS_PATTERN  "ClassPattern"
	    The regexp pattern used to match the class ids and adjectives.
	    When 0, the next call to class_id() recreates the pattern.

	  string P_ID_PATTERN  "IdPattern"
	    The regexp pattern used to match the normal ids and adjectives
	    as well as the class ids and adjectives.
	    When 0, the next call to id() recreates the pattern.

	The player objects do not query the physical description
	properties directly, but instead using these functions:

	  string Long (void|string what)
	    Returns the long description for a 'look at', either for
	    the object or for a detail.
	    This does never include any data from content or exits or
	    whatsoever.

	  string ExaLong (void|string what)
	    Returns the long description for an 'examine', either for
	    the object or for a detail.
	    If none is specified, "You see nothing special.\n"+Long(what)
	    is returned.
	    This does never include any data from content or exits or
	    whatsoever.

	  string Short (void|string what)
	    Returns the short description.
	    Default is P_SHORT.

	  string InvShort (void|string what)
	    Returns the Short() description capitalized;
	    or the empty string for invisible objects.
	    This is used for overall inventory listings.

	  string Noise (void|string what)
	    Returns the noise description. Default is P_NOISE.

	  string Smell (void|string what)
	    Returns the smell description. Default is P_SMELL.

	  string Read (void|string what)
	    Returns the read description, either of the object
	    or of a readable detail. Default is P_READ_MSG.

	The argument 'what' is either 0 if the player issued a general
	perception command (like 'look') or a string containing the
	object "<thing>" of a directed perception command (like 'smell
	<thing>').

	The value returned by these functions is in fact not just the
	property value, but instead the property value extended by the
	extra data (if any). The single extra data for these functions
	must be strings, which are concatenated to the value of the
	property before the result is returned.

	For the plain /std/thing these functions return just the
	contents of the associated properties (plus the extra data).
	This may not be valid for derived objects.
	For compability, the argument 'what' is passed to the
	underlying Query...() routines.


	There is a function helping in dealing with P_SIZE matters:

	  int CompareSize (int|object with)
	    Compare the P_SIZE of the object with the given size
	    <with>, resp. with the P_SIZE of the object <with>.
	    Results are:
	      < 0: this object is smaller than <with>
	      = 0: this object is of same P_SIZE as <with>
	      > 0: this object is larger than <with>

	The Extra Data is stored as a single mapping

	  mapping P_EXTRA_DESC	 "ExtraDesc"

	with the single extra data sets indexed by their key values.
	Each single data set must be a mapping, or a closure returning
	a mapping.
	The data set mapping then is primarily indexed by the property
	names it has additional data for - for the descriptional
	properties these data have to be strings.
	Again, closures returning the actual data might be stored
	instead of verbatim data.

	Following functions help dealing with the extra descriptions:

	  void SetExtra (mixed key, mapping|closure data)
	    Store the <data> set for the <key> value in P_EXTRA_DESC.

	  mapping|closure QueryExtra (mixed key)
	    Return the data set for the <key> value from P_EXTRA_DESC,
	    or 0 if there is none.

	  void RemoveExtra (mixed key)
	    Remove the data set for the <key> value from P_EXTRA_DESC.

	Single fields in one key's data set may be directly changed:

	  void SetExtraEntry (mixed key, mixed field, mixed data)
	    The entry indexed by <field> from the data set <key> in
	    P_EXTRA_DESC is set to <data>.
	    Example: SetExtraEntry("spraycan extra", P_SHORT, " (painted)");

	  void QueryExtraEntry (mixed key, mixed field)
	    Return the data indexed by <field> from the data set <key>
	    in P_EXTRA_DESC.

	  void RemoveExtraEntry (mixed key, mixed field)
	    Remove the data indexed by <field> from the data set <key>
	    in P_EXTRA_DESC.


	--- /std/thing/restrictions ---

	  int P_WEIGHT	   "Weight"
	    The weight of the thing. One unit is one gramm (one
	    old-NF-unit are 1000 gramm).

	  int P_BRIGHT	   "Bright"
	    The amount of light the thing emits on its own.

	  int P_LIGHT	   "Light"
	    The amount of light the things emits in total (including
	    light from contents).
	    When set, the thing's P_BRIGHT is changed to reach the
	    given total-value.

	For the light propagation, this function is used:

	  protected void emit_light (int l)
	    The object emits <l> more light. If the object has an
	    environment, its lfun light_from_inside() is called with
	    <l> as parameter, and increment P_LIGHT by <l>.
	    Do not call this function manually!


	--- /std/thing/moving ---

	The moving part implements a generic moving algorithm with
	flexible success checking.
	The lfun to call to move a thing is:

	  int move (string|object dest, void|int method, void|mixed data)
	    Move the thing into <dest> using <method> (default is
	    M_SILENT). <data> is additional according to <method>.
	    Result is a successcode.

	For a detailed discussion of methods, results and extra data,
	see /doc/concepts/moving.

	Any of the manual moves (take, drop, put) can be prevented by
	setting the according property to non-zero:

	  mixed P_NOGIVE   "NoGive"
	  mixed P_NOGET    "NoGet"    also #defined to be P_NOTAKE
	  mixed P_NODROP   "NoDrop"

	These properties are not checked by move() but instead by the
	initiating command function itself.
	If the preventing non-zero value is a string, it is used as
	the failure message to the player.
	For interactive objects == players, P_NOGET is always non-zero.

	/std/thing also implements the possibility of automatic
	following.
	The property

	  object * P_FOLLOWERS	 "Followers"

	contains the list of objects which follow this thing.
	For easier manipulation of the list exist the functions

	  object * AddFollower (object f)
	  object * RemoveFollower (object f)

	which add or remove the given object from/to P_FOLLOWERS
	and then return the new value of P_FOLLOWERS.

	Everytime the thing moves by move(), the lfun

	  void follow (string|object dest, void|int method, void|mixed data)

	is called with the arguments from the move() in every object
	noted in P_FOLLOWERS.

	On the other hand, if a thing sets

	  mixed P_NOFOLLOW   "NoFollow"

	to a non-zero value, it can't follow an other thing anymore
	(calls to its follow() are silently ignored).

	An additional property allows to identify 'followers', like
	familiars, as such. However, it is task of the follower-programming
	wizard to set this property, as the object can't do it on its
	own.

	  mixed P_IS_FOLLOWER  "IsFollower"
	    Value is non-zero if this object is (usually) following some
	    other object.
	    The value is automatically set by Set(P_FOLLOWERS) and
	    AddFollower() in the added objects, but it can't be reset
	    as automatically.

	Note: if a thing follows a player, the thing is informed about
	the players network status by calls by the player object to
	the things lfun PlayerNetdead(int isdead). The function is
	given 0 if the player revives from netdeath, and non-zero if
	the player just went netdead.

	  int clean_up (int ref)
	    Overloads the default handling of /std/base.

	The clean_up() handling is different from those of /std/base.
	If the thing is
	 - if P_CLEAN_UP is zero, the object stays and the function
	   returns 1 to be asked again later.
	 - a blueprint with no environment or asked by its environment
	   to clean up, it walks through its inventory and calls
	   clean_up() with -1 as argument in each object.
	   If this causes all objects to self destruct, the thing
	   destructs as well and returns 0; else it remains and
	   returns 1.
	 - a clone with no environment, it tries to 'remove()' all
	   contained objects (using a deep_inventory()) and then
	   selfdestructs.
	 - a used blueprint, or anything not covered before, it stays
	   and returns 1 to be asked again later.
	Things carried by players (netdead or not) never clean up.


BUGS
	The P_LAST_* data should be stored in the current player's
	CmdData stack.


INHERITANCE TREE
	thing
	  |-std/base
	  |-std/thing/moving
	  |-std/thing/properties
	  `-std/thing/description


SEE ALSO
	moving(C), properties(C), units(C), light(C), base(S)