It is frequently useful to restrict the use of some object. For example, one might want to keep people from using a particular exit unless they're carrying a bell, a book, and a candle. Alternatively, one might allow anyone to use the exit unless they're carrying that huge golden coffin in the corner. LambdaMOO supports a general locking mechanism designed to make such restrictions easy to implement, usually without any programming. Every object supports a notion of being locked with respect to certain other objects. For example, the exit above might be locked for any object that was carrying the coffin object but unlocked for all other objects. In general, if some object `A' is locked for another object, `B', then `B' is usually prevented from using `A'. Of course, the meaning of use in this context depends upon the kind of object. The various standard classes of objects use locking as follows:
There are two sides to locking:
Note that these two questions are entirely independent: one could invent a brand-new way to specify locking, but the effect of an exit being locked would be unchanged. Programmers should note that the interface between these two sides is the verb
x:is_unlocked_for(y)
which is called by x to determine if it
is locked for the object y. The way in which
:is_unlocked_for
is implemented is entirely independent of the
ways in which x uses its results. Note that you can play on
either side of this interface with your own objects, either defining new
implementations of :is_unlocked_for
that match your particular
circumstances or having your objects interpret their being locked in new
ways.
The following commands are used to specify locks on objects.
LambdaMOO supports a simple but powerful notation for specifying locks on objects, encryption on notes, and other applications. The idea is to describe a constraint that must be satisfied concerning what some object must be or contain in order to use some other object. The constraint is given in the form of a logical expression, made up of object numbers connected with the operators `and', `or', and `not' (written `&&', `||', and `!', for compatibility with the MOO programming language). When writing such expressions, though, one usually does not use object numbers directly, but rather gives their names, as with most MOO commands. These logical expressions (called key expressions) are always evaluated in the context of some particular candidate object, to see if that object meets the constraint. To do so, we consider the candidate object, along with every object it contains (and the ones those objects contain, and so on), to be `true' and all other objects to be `false'. As an example, suppose the player blip wanted to lock the exit leading to his home so that only he and the holder of his magic wand could use it. Further, suppose that blip was object #999 and the wand was #1001. blip would use the '@lock' command to lock the exit with the following key expression:
me || magic wand
and the system would understand this to mean
#999 || #1001
That is, players could only use the exit if they were (or were carrying) either #999 or #1001. To encrypt a note so that it could only be read by blip or someone carrying his book, his bell, and his candle, blip would use the `encrypt' command with the key expression
me || (bell && book && candle)
Finally, to keep players from taking a large gold coffin through a particularly narrow exit, blip would use this key expression:
! coffin
That is, the expression would be false for any object that was or was carrying the coffin. There is one other kind of clause that can appear in a key expression:
? object
This is evaluated by testing whether the given object is unlocked for the candidate object; if so, this clause is true, and otherwise, it is false. This allows you to have several locks all sharing some single other one; when the other one is changed, all of the locks change their behavior simultaneously. The internal representation of key expressions, as stored in .key on every object, for example, is very simple and easy to construct on the fly.
The representation of key expressions is very simple and makes it easy to construct new keys on the fly. Objects are represented by their object numbers and all other kinds of key expressions are represented by lists. These lists have as their first element a string drawn from the following set:
"&&" "||" "!" "?"
For the first two of these, the list should be three elements long; the second and third elements are the representations of the key expressions on the left- and right-hand sides of the appropriate operator. In the third case, `!', the list should be two elements long; the second element is again a representation of the operand. Finally, in the `?' case, the list is also two elements long but the second element must be an object number. As an example, the key expression
#45 && ?#46 && (#47 || !#48)
would be represented as follows:
{"&&", {"&&", #45, {"?", #46}}, {"||", #47, {"!", #48}}}
Go to the first, previous, next, last section, table of contents.