Doe's Inform 6 Primer

Apple & Orange. Contents this "Lesson:"
  1. Attributes and properties -- apples and oranges.
    The difference between attributes and properties, global/local properties, and avoiding vile zero errors from hell.
  2. 1, 2, 3, 4 - Before, After, React_After, React_Before
    Using the before, after, react_after, and react_before routines to affect actions.

    Second Homework Assignment Solutions

  1. Attributes and Properties -- Apples and Oranges

    Attributes and properties are usually associated with objects. This primer doesn't really cover objects -- see the DM.

    Attributes = True/False

    Attributes are boolean flags, which means they can only be either true or false, on or off. They are true/false characteristics which can be assigned to objects:  locations, objects, and characters.

     general   <- true/on
     ~general  <- false/off
    Many built-in Inform library routines rely on pre-defined attributes, such as:  light, which determines whether a location has light (true) or is in the dark (false), and animate, which determines whether a character can have a life routine and be conversed with.

    Properties = Anything

    Properties are variables. Variable means their contents can vary, so they can hold any value (a number, a string, a routine, or an array, such as an array of strings -- more about arrays under arrays). Basically, property strings describe an object, and property routines perform actions on/by an object.

    Object chair "chair"
         has supporter enterable
         with name "chair" "plastic" "ordinary",           <--- array of strings
         description "It's an ordinary, plastic chair.",   <--- string
         number 0,                                         <--- number
         before                                            <--- routine
         [; Enter : if (man in chair)
                       "It seems to be occupied.";
    Has & With

    Has assigns an attribute/attributes to an object. With assigns a property/properties to an object. Both are only used once with the first attribute or property. Additional attributes and properties use the previously declared has or with.

    has supporter enterable                        <- same has for both attributes
    with name "chair" "plastic" "ordinary",        <- description uses the same with as name
    description "It's an ordinary, plastic chair.",     

    A Doe Crib Note:
    Thoroughly familiarize yourself with the pre-declared attributes and properties in linklpa.h -- pages 409-411 DM 4.

    You can, of course, add your own attributes and properties to your Inform game.

    A Doe Crib Note:
    General is a built-in all-purpose attribute that does not mean anything specific, so it can come in handy when keeping track of daemons and timers. Following the order of:   StartDaemon(object);, give object general;, StopDaemon(object);, give object ~general; -- provides a way to tell when a daemon is still running.
    if (object has general)  daemon is still running

    Global Attributes and Global Properties

    Global means "known to all." Global attributes and properties can be accessed anywhere in your game.

    All attributes are global. To create one of your own, declare it at the top of your code before including parser.h:

    Attribute animal;
    Properties already declared in the Inform library (before, after, etc.) are all global variables. You can also add your own. The following declares a global property (also at top of code, before including parser.h).

    Property intelligence 0;
    Each game object is considered to have all the global attributes and properties, both Inform library and author-created attributes/properites, whether they have been deliberately assigned to that object or not.

    Attributes are negative by default. So to turn an attribute on for a particular object, you have to specifically assign it to that object.

    Object man "man"
        has animate male
    Now man will test true for both animate and male. Before assignment the man object would have tested false for animate and male.

    Global properties have a default value of 0. For instance, every object is considered to have a before routine. If no before routine for that object actually exists, its value is 0. Thus, when a before routine is included for a object, its value is usually 1 (true).

    Object chair "chair"
        has supporter enterable
        with name "chair",
        [; Enter : if ((child(self)~=0) && (child(self) has animate))
                        "The chair seems to be occupied.";
    The before routine of the chair will test true for before/Enter and false for other verbs.

    The advantage of a global property is that all objects are automatically assigned that property with either zero or the initial value that you gave it. So testing an object for that property, an object for which you did not include a specific instant of that property, will never cause an error.

    if (RunRoutines(chair,after)~=0) rtrue;
    For instance, since after is a global property, RunRoutines(object, after) will always return true or false (if the object exists) regardless of whether that object has an after routine or not. If it doesn't have an after routine, it will return 0, but not an error.

    But all properties don't need to be global.

    Local Properties

    Local properties are declared within an object itself, not elsewhere in your code. (Note that only properties may be local, since attributes are automatically global.)

    Object man "man"
       has animate male
       with name "man",
       intelligence 2;
    Local means "keep confined to the object in which it is declared." No other object automatically has a local property and if you test for it in another object which does not have it, Inform will return an error. You can, however, use the same (the same is defined by having the same name) local property in several objects.

    Object dog "dog"
       has animate animal neuter
       with name "dog",
       intelligence 1;
    Note the difference in value -- remember because properties are variables, their content can vary.

    The advantage of a local property is that it is "object-oriented" and keeps information from being globally accessed (I also suspect they use less memory, but can't swear to it). Also, while there is limit on the number of global properties (the maximum depending on the game size), there is none on local properties. HOWEVER, you must remember NOT to test other objects for the value of that local property...

    if ((second~=0) && (second.intelligence==1))
       "Smart enough to fetch a map, but not read it.";
    ...without first testing if an object has that local property.
    if ((second~=0) && (second provides intelligence))
    { if (second.intelligence == 2)
         "Smart enough to read a map, but not to ask for one when lost.";
    Provides is the way to test for the existence of a local property. You need to test if an object has a particular local property before accessing/testing its value or, as stated, an error will result.

    A Doe Crib Note:
    Since the maximum number of attributes can be reached fairly quickly, if (object provides localproperty) can make a nice substitute for if (object has attribute).

    Noun and second are generalized ways to test an object without using a specific object name. Noun is the direct object in a sentence, and second is the indirect object.

    A Doe Crib Note:
    Always test SECOND first to see that it isn't zero before testing it for anything else. Inadvertently condition checking second when it is zero...
    if (second has general) etc; the biggest cause of vile zero errors from hell.

    The simple error check shown above
    if ((second~=0) && (second provides intelligence))
    relies on the fact that if the first part of an if statement is false...
    if ((second~=0) <- a false evaluation would mean it IS zero
    ...then the second half of the statement is never executed. Tedious, yes, but that way you will avoid most (99%) of the vile zero errors from hell. I wish I always remembered to do it.

    (The reason this is one of the biggest causes of vile zero errors from hell is because noun will just about always have a value, but second may not. Many verbs can be used either way, with only a direct object or with both a direct and an indirect object. Thus, sometimes the indirect object, second, will have no value, so it is safer to assume it won't.)

    I didn't really cover the commands concerning attributes and properties, I figured you'd pick that up somewhere else. But a brief summary...

    Command Example
    (assigns an attribute to an object -- it is only used once for
    the first attribute, even if multiple attributes are assigned)
    Object dog "dog"
      has animate neuter general
      with name "dog";
    (tests if an object's attribute is true)
    if (dog has general)
    (tests if an object's attribute is false -- note that it cannot
    have an apostrophe)
    if (dog hasnt general)
    give object attribute
    (turns on/assigns an attribute to an object)
    give dog general;
    give object ~attribute
    (turns off an attribute for an object)
    give dog ~general;

    When give object attribute assigns an attribute to an object, that attribute does not need to be declared in the object itself.


    Global Properties
    Command Example
    (assigns a property to an object -- it is only used once for
    the first property, even if multiple properties are assigned)
    Object dog "dog"
      has animate neuter general
      with name "dog",
      intelligence 1;
    if ( == value)
    (tests the value of an object's property)
    if (dog.intelligence == 1) = value
    (assigns a value to an object's property)
    dog.intelligence = 0;

    Local Properties

    Local properties use the same commands as global properties, except also included is...

    Command Example
    (tests if an object has a local property)
    if (dog provides intelligence)

    Note that when testing the value of a property outside of the object it is assigned to, the property name is preceded by a period and the object name. Inside the object itself, it is preceeded by self, such as Self can be used inside an object to refer to itself. It can also be used in a class declaration to refer to objects/members of that class.

    A Doe Crib Note:
    To anyone familiar with Pascal, using a period will not look strange. In fact, it might help to think of an object as a "record" and the properties as "fields."

    A Doe Crib Note:
    An incredibly easy mistake to make when testing property values (both global and local) is to accidentally leave off the preceding object name.
    if (intelligence == 1)  should be  if (object.intelligence == 1)
                            or         if (self.intelligence == 1)

    You can probably see why, instead of creating new attributes and/or global properties, it is often a good idea, maximum limit-wise (and possibly memory-wise), to create new local properties instead. However, sometimes you really need globals, so the decision of whether to create global or local properties also depends on how you plan to use them.

    Creating new properties is not done that frequently. 80-90% of the time most Inform programmers just use the default Inform properties.


  2. 1, 2, 3, 4 -- Before, After, React_After, React_Before

Previous Page - Sections 1-3 and First Homework Assignment    Next Page - Sections 7 & 8 and Third Homework Assignment

Top of Page    Infotips    Interactive Fiction Main Page

If this primer has been of any use to you I wouldn't mind hearing about it.