Previous Next Title Page Contents

PROGRAMMING

So you want to become a MOO[3] programmer? Run, do not walk, to the LambdaMOO ftp site and get the latest text version of the LambdaMOO Programmer’s Manual. You will need to continually reference this book. If you want to print it out, get the postscript version, but I also recommend keeping the text version on your personal computer so that you can refer to it and do searches on it. I’m only going to talk about the basics of MOO programming here. You'll need the official manual as a reference, and you should read through it at least once.

Inside the MOO, help programming and help prog-index will give you a list of topics that might interest you. The command @classes utilities will give you a list of all the built-in utility objects available for programming. There’s a special discussion group for programmers on Valhalla called *Universe.[4]

BECOMING A PROGRAMMER

In order to become a programmer, you need to talk to a friendly wizard. Most likely, you will be given a new player to use as a programmer, and you will keep your current player so that you can use it as a guinea pig for your new creations.

PROPERTIES

You’re already quite familiar with properties. The messages you’ve been setting are properties, as is your name and your description. Most of the properties you’ve dealt with so far have been string properties. There are four basic kinds of properties in MOO.

Strings

Numbers

Objects

Lists

VERBS

Verbs are the ‘commands’ of the MOO. You’ve been using verbs left and right. When you ‘look’ or ‘go’, when you talk, emote, page, or whisper, you’re using verbs.

Classes of Objects

Verbs must be attached to objects, whether the object is a player, a room, or some thing. Verbs should be attached to appropriate objects. If you have a cat named Lucretia, and you want people to be able to kick it, you should attach the kick verb to Lucretia, and not the room you happen to be in. People are going to want to kick your cat no matter where they find it. A kick verb on a room might be appropriate if the room is a kick-boxing arena.

MOO is an object oriented programming language. This means that it has classes of objects. When you look at the parents of an object, you’re looking at the classes that the object belongs to.

@parents Lucretia

Lucretia(#392) generic cat(#259) generic animal (#258) generic thing(#5) Root Class(#1)

Lucretia is a member of the class generic cat. Cats, in general, are members of the class generic animal, which are members of the class generic thing. Everything in the MOO is based on the Root Class.

Suppose you type kick Lucretia. Assuming that there is no kick verb on you or on the room you are in[5], the MOO looks to see if Lucretia has a kick verb. If she does, the MOO ‘runs’ that kick verb. If not, the MOO checks to see if cats can be kicked; then, it checks animals, and then things, and finally the Root Class.

This order of verb-searching means that higher-order objects can override verbs in lower-order objects. If both generic thing and generic cat have a kick verb, only the verb on generic cat is used by the MOO.

Sentence Structure

There are three basic sentence forms in MOOs:

verb

verb direct-object

verb direct-object preposition indirect object

When you create a verb, you need to tell the MOO what kind of sentence the verb belongs in, and what kind of direct or indirect objects are allowed. For example,

@verb here:cough none none none

creates a cough verb in the current room. The cough verb only works if the player doesn't type anything except ‘cough’.

@verb staff:swing this at any

creates a swing verb on the staff. This verb needs the direct object to be the staff (this), the preposition to be at[6], and the player must swing it at something, although this something can be anything.

The LambdaMOO Programmer’s Manual discusses verbs in much more detail. The important thing to remember here is that, when the MOO starts looking for a verb, it basically ignores any verbs whose sentence structure doesn't match what the player typed. If the player types cough loudly, the MOO will not use the cough verb we created above. If the player types swing staff in time, the MOO will not use the swing verb we created.

In both cases, if the MOO doesn't find an appropriate verb/sentence structure combination, it will make suggestions to the player. In the above examples, we might expect:

cough loudly

I don't understand that.

Try this instead: cough

swing staff in time

I don't understand that.

Try this instead: swing staff to time

EDITING PROPERTIES AND VERBS

Properties: Notedit

You can edit string properties, or lists properties that are lists of strings, with the @notedit verb: @notedit object.property. For example, if you want to give the current room a description that has more than one line—i.e, that is a ‘list’ of strings—use @notedit:

@notedit here.description

The property editor works just like the mail editor, except that you use save when you’re finished, instead of send. Save saves the changes you’ve made to the property. When you’re done editing and want to exit the editor, use done. The done verb doesn’t save the changes you’ve made—that’s what save is for—but it does keep track of what you’ve done if you haven’t saved. You can return to your editing by typing @notedit without anything else.

Verbs: Edit

When you need to edit a verb, you use @edit object:verb. It’s the standard editor that you’ve used to send mail and possibly to edit properties. When you’re ready to save the changes you’ve made, type compile. You will be told if there are any ‘syntax’ problems in the verb, and what line these problems are in. Use done to leave the editor.

THE GENERIC SWINGING WEAPON

Even though I’m going to leave the majority of programming instruction to the official manual, I’m a firm believer that you can never have too many examples. This is Valhalla. Lots of gods with short tempers. We will have swords, staves, and hammers coming out of (and into) our ears. Let's make a generic swinging weapon to base them all on.

@create $thing named generic swinging weapon,swinger

@describe swinger as "a nondescript weapon of untold power; be careful with it: you might knock someone's eye out!

We need a verb of some sort so that we can hit people with it. What are the possibilities?

hit Jack with sword

strike Thor with staff

There is a big problem with both of these. Remember the order of searching? The MOO is going to look at Jack and Thor (the direct objects) before it looks at sword or staff. If I bother them too much, they’ll create a swing verb on themselves:

@verb me:"Hit Strike" any with this

@edit me:Hit

"player:tell("You miss.");

"player.location:announce($string_utils:pronoun_subs("%N strikes at %d with %p %i. %D dodges nimbly, and %n strikes the ground, leaving %r embarrassed and revealing %p utter incompetence."));

compile

done

Since the MOO will get to this verb before it gets to ours, whenever we try to hit or strike Thor, we'll see:

You miss.

And everyone else will see:

Balder strikes at Thor with his staff. Thor dodges nimbly, and Balder strikes the ground, leaving himself embarrassed and revealing his utter incompetence.

Do we really want that? How about, since this is a generic swinging weapon:

swing staff at Thor

Okay.

@verb swinger:swing this at any

@edit swinger:swing

The @verb creates the verb ‘swing’ on ‘swinger’. And then @edit allows us to edit it, and add instructions:

"if (valid(iobj))

If the player typed a valid object—something that exists—do the rest of this. Otherwise, Valhalla will jump down to the ‘else’ a couple lines down.

"player:tell("You hit ",iobj.name," with your ",this.name,".");

"player.location:announce_all_but({player,iobj}, $string_utils:pronoun_sub("%N hits %i with %p %d. It is a crushing blow."));

Here, we first tell the player who swung the weapon that the weapon (‘this.name’) hit the target (‘iobj.name’). ‘Name’ in each case is a property of the object referred to by ‘this’ and ‘iobj’. You refer to object properties with object.property. Tell is a verb that exists on player. We use it by typing player:tell. Announce_all_but is a verb that exists on the room that the player is in. We know the room because it is in the player’s property location. So, player.location:announce_all_but uses that verb. First, Valhalla interprets ‘player.location’, and then looks for the verb announce_all_but on that location. This is how we refer to verbs: object:verb(information for the verb).

Then, we tell everybody in the room—except the player, who we already told, and the target (‘iobj’), who we’ll tell in a moment—the same thing. Notice that we also call the pronoun_sub verb to interpret all those ‘%’ things. The pronoun_sub verb is on an object called $string_utils.

"if ($object_utils:has_callable_verb(iobj,"tell"))

"iobj:tell($string_utils:pronoun_sub("%N swings %p %d at you and deals an ugly wound. Good lord, %i, are you going to stand for that?"));

"endif

Here’s a complete if statement. If the target (‘iobj’) has a verb that we can use called ‘tell’, Valhalla will use the verb after the if statement and before the endif statement. In this case, it tells the iobj that it has been hit by the player swinging the weapon.

"else

"player:tell("I don't see any ",iobjstr," here. Feeling a little troubled?");

"player.location:announce($string_utils:pronoun_sub("%N appears to be developing an interesting rapport with %p %d"));

"endif

This else and endif belong to the first ‘if’ at the beginning of this verb. The part between the else and the endif here will only be used if the if (valid(iobj)) comes back and says “no, the player didn’t refer to a valid object.” In other words, the MOO uses the first part (between the if and the else) if the statement valid(iobj) is ‘true’; else it uses the second part (between the else and the endif).

And what we’ve decided to do is, first, tell the player that we couldn’t find any ‘iobjstr’ to swing at, and, second, announce to everyone in the room that the player is doing something strange. Iobjstr is the text after the first preposition. It’s like iobj, except that it’s text instead of an object number. Announce is a verb that all rooms have, and it tells everyone in the room—except for the player who called the verb—whatever we put between the parentheses. In this case, that the player “appears to be developing an interesting rapport with” a generic weapon.

compile

Compile tells the MOO to check the verb for errors, and then save the verb so that it can be used. You must compile your verbs before what you typed can be used.

done

Done returns you to wherever you were before you started editing the verb.

@chparent staff to swinger

Balder already created a staff in order to demonstrate creating objects. The @chparent command makes that staff a child of swinger, as if Balder had originally created it with @create swinger named staff. The staff now can do anything that a generic weapon can.

swing staff at Captain Video

You swing the staff at Captain Video

Everyone else (except Captain Video) sees:

Balder hits Captain Video with his staff. It is a crushing blow.

And Captain Video sees:

Balder swings his staff at you and deals an ugly wound. Good lord, Captain Video, are you going to stand for that?

Now, this isn’t really that interesting of a generic. You can @create all the staves, swords, and maces you want, they’ll still all “hit” and “deal ugly wounds”. At the end of this section, I’ll show you a better form of generic, that includes messages—properties that the owner can change, like all of the messages we fooled around with in Advanced Building.

The Advantages of Being Object-Oriented

Let’s make a present for Thor. First, we need to complete one more thing on the generic swinging weapon. We need to make it fertile.

@chmod swinger to +f

This adds ‘fertility’ to the swinger. Until an object is fertile, only the owner can make children from it. Anyone can make children from a fertile object. Now that swinger is fertile, anyone in Valhalla can @create swingers named whatever they want.

@create swinger named "Thor's Hammer",hammer,Mjolnir

Now, as anyone who reads comics—I mean, studied Norse mythology—knows, Thor’s Hammer is not your average weapon. One of its biggest properties is that it returns to Thor after Thor throws it.

Right now, Thor’s hammer can be ‘thrown’ just like any other object. It’s a $thing, and all $things have a throw verb which allows them to be thrown. Because Valhalla is object-oriented, we can override the basic throw verb with our own:

@show hammer:throw

Object #98 does not define that verb, but its ancestor #5 does.

#5:"dr*op th*row"

Owner: Thor (#2)

Permissions: rxd

Direct Object: this

Preposition: none

Indirect Object: none

I use the @show command to find out what the exact syntax for throw is. If I don’t copy it exactly, my ‘throw’ may not override all instances that players will use.

@verb hammer:th*row" this none none

@edit hammer:throw

"if (player != this.owner)

"pass(@args);

"else

"player:tell("You fling the ",dobjstr," across the sky.");

"player.location:announce(player.name," flings ",player.pp," ",dobjstr," out of sight!");

"player.location:announce("The ",dobjstr," flips back around and returns to ",player.name,".");

"player:tell("Your ",dobjstr," returns to your grasp.");

"endif

compile

done

The important thing to look at here is the pass(@args); verb. This passes the sentence to the parent verb. If anyone other than the hammer’s owner throws the hammer, it throws normally. If the owner (Thor) throws it, we take control and send out our special messages. By passing control on to the parent verb when we do want the hammer to be thrown normally, we don’t have to worry about what goes on in throwing an object, and, if the administrators ever improve their ‘throw’ verb, our own ‘throw’ verb will reflect these improvements.

Also, the original ‘throw’ verb is combined with drop. We didn’t override drop at all, so if Thor drops his hammer, it won’t return to him.

If you have any other questions about the statements in this verb, see the LambdaMOO Programmer's Manual, available at all fine virtual bookstores.

A Better Generic Swinging Weapon

@create $thing named generic swinging weapon:generic swinging weapon,swinger

@describe swinger as "a nondescript weapon of untold power; be careful with it: you might knock someone's eye out!"

@prop swinger."swing_msg" "You &hit %i with your %d, &wounds."

@prop swinger.tswing_msg "%N &ohits you with %p %d, &wounds. &tcomment"

@prop swinger.oswing_msg "%N &ohits %i with %p %d, &wounds."

@prop swinger.wounds_msg "dealing a deadly wound"

@prop swinger.no_target_msg "I don't see any %i here. Feeling a little troubled?"

@prop swinger.ono_target_msg "%N appears to be developing an interesting rapport with %p %d."

@prop swinger.hit_msg "hit"

@prop swinger.ohits_msg "hits"

@prop swinger.tcomment_msg "Good Lord, %i, are you going to stand for this?"

@prop swinger.help_msg ""

@notedit swinger.help_msg

"The generic swinging weapon has the following messages:

" tswing: What the target sees when the weapon is swung.

" swing: What the swinger sees when the weapon is swung.

" oswing: What others see when the weapon is swung.

" no_target: What the swinger sees when the weapon is swung at a target that doesn't exist.

" ono_target: What others see when the weapon is swung at a target that doesn't exist.

"

"In addition, the following 'ampersand' substitutions can be placed in the above messages:

" &wounds: Should be set to the kind of wounds the weapon does as a phrase: "dealing a deadly wound"

" &hit: What the weapon does when it hits as the swinger sees it: "hit"

" &ohit: What the weapon does when it hits as others see it: "hits"

" &tcomment: An extra comment for the target. Should be a complete sentence. "Good Lord, %i, are you going to stand for this?"

"

"For the current state of the above messages, use the @messages verb.

"

"Remember to be careful what you do with this thing! We don't want any ownerless eyeballs floating around Valhalla.

@verb swinger:swing this at any

@program swinger:swing

if (valid(iobj))

player:tell($string_utils:pronoun_sub(this:hitting_sub(this.swing_msg)));

player.location:announce_all_but({player, iobj}, $string_utils:pronoun_sub(this:hitting_sub(this.oswing_msg)));

if ($object_utils:has_callable_verb(iobj, "tell"))

iobj:tell($string_utils:pronoun_sub(this:hitting_sub(this.tswing_msg)));

endif

else

player:tell($string_utils:pronoun_sub(this:hitting_sub(this.no_target_msg)));

player.location:announce($string_utils:pronoun_sub(this:hitting_sub(this.ono_target_msg)));

endif

.

@verb swinger:hitting_sub this none this

@program swinger:hitting_sub

The_Message = args[1];

Substitute_List = {{"&hit", this.hit_msg}, {"&ohits", this.ohits_msg}, {"&wounds", this.wounds_msg}, {"&tcomment", this.tcomment_msg}};

Munged_Message = $string_utils:substitute(The_Message, Substitute_List);

return Munged_Message;

FORKS AND TASKS

Let's go back to Thor's hammer. We're not really letting him throw his hammer. We just tell everybody he threw it, which is almost the same thing. But we can also have the hammer actually be thrown, and then return after a short bit of time. We’ll re-write throw so that when Thor throws his hammer, it waits a bit at the destination, and then sails through the air back into his hand.

MOOs do not allow long-playing verbs. Any verb that takes too much time is terminated abruptly, with nary a polite goodbye. If your verb needs to wait before doing something, you have to tell it to go to sleep.

USING FILES

The File Utilities Object


[3]From now on, I'm going to talk about MOOs in general, rather than specifically Valhalla.

[4]You can still read this even if you’re not a programmer. However, only programmers can @send messages to the group.

[5]Remember the order that the MOO looks for verbs: player, room, direct object, indirect object.

[6]Because prepositions are applied in groups, to will also work. To is part of the same group as at.


Previous Next Title Page Contents