Go to the first, previous, next, last section, table of contents.


Using Locks With Objects

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.

Command: @lock object with key expression
Set a lock on object to restrict its use.
Command: @unlock object
Clear any lock that might exist on the given object.
Command: @lock_for_open container with key expression
Set the lock on container which restricts who can open it.
Command: @unlock_for_open container
Clears the lock which restricts who may open container.

Keys

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.

Key Representation

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.