Contents this "Lesson:"
general <- true/on ~general <- false/offMany 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.
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 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.",
| Thoroughly familiarize yourself with the pre-declared attributes and properties in linklpa.h -- pages 409-411 DM 4. |
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 |
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.
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.
Object chair "chair"
has supporter enterable
with name "chair",
before
[; 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.
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.
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.
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.
| 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). |
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;...is the biggest cause of vile zero errors from hell. |
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.
| Command | Example |
|---|---|
|
has
(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"; |
|
has
(tests if an object's attribute is true) |
if (dog has general) |
|
hasnt
(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; |
| Command | Example |
|---|---|
|
with
(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 (object.property == value)
(tests the value of an object's property) |
if (dog.intelligence == 1) |
|
object.property = value
(assigns a value to an object's property) |
dog.intelligence = 0; |
| Command | Example |
|---|---|
|
provides
(tests if an object has a local property) |
if (dog provides intelligence) |
| 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." |
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)
|