Programming by exploration guide

From ChatMUD Wiki
Revision as of 05:10, 12 September 2020 by Athlon (talk | contribs)
Jump to: navigation, search

There are a number of moo programming tutorials out there. This one aims to be a bit different from them. For one thing, it is ChatMUD-tailored, which is important to note because ChatMUD's codebase is a fair bit expanded from the one on lamda MOO. For another thing, this tutorial isn't supposed to be easy, and it won't teach you how to make an interesting object by the end. Instead, it will hopefully furnish you with knowledge of many basic concepts, a toolbox to help you remember common coding patterns, and exercises to help satiate your curiosity. Be prepared to struggle, read things repeatedly, and even go back and reread sections. The learning is the struggle, not the solution! The tutorial is set up so that sections build on each other, so it's a good idea to start from the beginning so you don't get lost while trying to digest new material. Also, the hope is that instead of just copying and pasting the example code and commands, you type them in yourself, which will help you engage more than just copying and pasting them.

If you have questions, feel free to ask on the dev channel. There is usually at least one or two people awake who can help you puzzle something out. Also see the end of this document for links to some of the other moo programming tutorials previously mentioned, which apply many of the same concepts discussed in a more problem-solving oriented way.

Some Basic Assumptions

We assume that you have created your ChatMUD character and gotten a programmer bit. This can be done by connecting to the progbits channel and sending the message "progbit" to it. We also assume that you know how to create and destroy objects, and that you know how to examine objects to see the possible verb commands you can use with them that way. Also, hopefully you are working on a computer, because programming on a mobile interface is usually quite laborious.

Conventions

If there is a single-line command for you type into the mud, it is proceeded by a > sign. Multi-line programs are block-quoted. You can copy and paste the text, including the beginning and ending line, to send all of this code to the mud, and it should work as expected.

Output from the moo is proceeded by two less than signs. <<

Execution tick counts are sometimes included as part of output. If you want to enable or disable them, use the command prog-o 3.

It's Literally this simple: single-line evaluation of literal variables

First let's evaluate some literal variables. The semicolon ; command begins a single-line evaluation. This lets you run simple snipets of code without programming a whole verb and having to delete it. It's also really nice for testing what verbs do, as you'll get the return value right there. The return value is the value immediately after the => in the output.

> ;5
<< => 5
<< [used -2 ticks, 0 seconds. Finished in 0 seconds.]

> 5+7
<< => 12
<< [used -2 ticks, 0 seconds. Finished in 0 seconds.]

> ;"hello world"
<< => "hello world"
<< [used -2 ticks, 0 seconds. Finished in 0 seconds.]


Nothing too weird here yet. Notice chatMUD adds 5+7 and instnatly returns 12. Also, notice the double quotes around hello world. Double quotes indicate a string. You must have double quotes around a string, because otherwise ChatMUD doesn't know it's a string. Try evaluating hello world without double quotes around it, to see what error you get. Be very mindful of where your quotation marks are! This is one of the most common pitfalls for any coder, even experienced ones.

>#2
<< => #2  (Sinistral)
<< [used -2 ticks, 0 seconds. Finished in 0 seconds.]

A number sign # followed by an object number will return that object, and ChatMUD is nice enough to tell you what its name is as well. Try evaluating random object numbers to see what you can find. Every time someone uses the @create command to make something, they make a new object, and it gets an object number. Every room, exit, and new player created also takes up an object number. To see the highest object number currently in use, run this command:

> ;max_object();
<< => #21183  ()
<< [used -1 ticks, 0 seconds. Finished in 0 seconds.]

The number will probably be different at any given time as objects are created and destroyed. The evaluation you just saw is a built-in function. ChatMUD has a number of built-in functions that make up the very lowest level and usually have easier ways of doing the same functionality built on top of them. These easier ways have the jargon word of wrappers. You will not be using many of them. For a full list, along with thousands of words of programming information that you probably don't care about, check out the full lamda moo + stunt programmers' manual.

Now let's evaluate some verbs. First, let's make the moo shout at us, by capitalizing any text we send over.

> ;$string_utils:uppercase("I like ChatMUD!");
<< => "I LIKE CHATMUD!"
<< [used 168 ticks, 0 seconds. Finished in 0 seconds.]

Remember, the string you send in must have quotes around it! Now, let's make ChatMUD calculate the greatest common divisor between 24 and 30, which is a problem you may remember from math class at school.

> ;$math_utils:gcd(30,24);
<< => 6
<< [used 21 ticks, 0 seconds. Finished in 0 seconds.]

Pretty neat, huh? These examples might seem contrived. How would anyone know what math_utils was, or that the gcd function was available? The first thing to know is that when you see a colon : symbol, and it's not part of a string, the thing on the left of the colon is an object, and the thing on the right is a verb. The verb is part of the object. Think of the object as a box, with verbs that work like levers to make things happen.

Try evaluating $math_utils now, and you will see that this evaluation is perfectly valid and will return object #26. $math_utils is just a convenient mnemonic to reference object #26, and this mnemonic is what is known as being corrified. Similarly, you can evaluate $string_utils. What object number do you get?

Note that these objects aren't supposed to be tangible things that you can pick up and manipulate, like the objects you may have been filling your area with. They are more of an organizational scheme to group similar sets of functions together. The math_utils object has a number of math-related algorithms, and the $string_utils object has many verbs to help you manipulate strings. Meanwhile the $object_utils object has a number of useful verbs for probing at the functionality of other objects. To get a full list of all of the utilities packages, type @kids $generic_utils. This command will show you all of the descendants of the generic utilities package. You can even make your own utilities package if you have ideas for useful functions for others to try; just make an object that is based off the $generic_utils package and go from there.

Let's explore what is available on the math and the string utilities objects. To do so, type the following:

>help $math_utils

You will get a long list of verbs that are available. Most of them provide adequate help information about how to use them. Type help $math_utils:verbname to see help for that particular verb. Now you can do the same for string utilities, and most of the other utilities packages.

Unfortunately, these help files are not automatically updated, so if a wizard adds a new verb to a utilities package, the help information is generally not updated to reflect the change. You can get an exhaustive list of verbs on a utility package by typing: @verbs <object>. Do this now to the string utilities object, and you will see several new verbs that were not listed in the help file. Try getting help on these new verbs. The results are mixed, but you will often be rewarded with information. If you are not, complain on the dev channel.

Stretch your thinking

The stretch your thinking sections contain some exploration questions to help you solidify what you learned, and stretch your thinking. There are no right or wrong answers here. But feel free to try things out while struggling with them. ChatMUD is built with security in mind, meaning it's very difficult to do permanent damage.

  1. Every object might have verbs on it, not just the utils packages. Use the @verbs command to probe some of the items in the player creations database to see what verbs they have.
  2. Can you add or subtract other kinds of literal values besides numbers? Try adding and subtracting strings. Try adding or subtracting objects.
  3. The multiplication, division, and modulus operators are *, /, and %, respectivly. These operators only work on numbers. They don't work on strings or objects. However, you might notice something weird with the division operator. What happens if you evaluate 32/4? What about 33/4? 31/4? Make a conjecture about why your results come up this way, and try some other division evaluations to see if it checks out.
  4. What happens if you send the wrong type of value to a verb? Well let's find out! Evaluate:
> ;$string_utils:lowercase(35);

When 1 + 1 doesn't equal 2: type conversions and inheritance hierarchies

If you worked through some of the stretch your thinking exercises, you may have realized that you can add strings together in order to make a much longer string. In programming jargon, this is called string concatenation. You will be using this technique often when you want to display messages to players. First of all, let's learn how to do a multiline evaluation, because this will let you do more complex exercises that involve more than single line of code to get the result. You have two options for multiline evaluation:

  • Send a line containing a single ; character. This will open a prompt where you can enter your entire multiline evaluation line by line. When you're finished, send a single . on its own line to get the result.
  • Do an evaluation like normal, but with two semicolons at the beginning, and send all the text on a single line. This method is a bit more convenient, but a little harder to read because of how cramped it is.

In this guide we'll be using the former method, with a ; as the the beginning of the program so you can just paste in the code to your own client and follow along without hassle. Let's do a multiline evaluation now.

;

str1="I like ";
str2="ChatMUD!";
return str1+str2;
.

<< => "I like ChatMUD"
<< [used 1 tick, 0 seconds. Finished in 0 seconds.]

This is a pretty simple program on the surface level. There are still some important syntactical points to notice. Each line of instructions has a semicolon after it. Not including it is incorrect, and ChatMUD will not be happy with you if you neglect semicolons, so be sure to include them. We have created two temporary variables, str1 and str2, to store our strings. These temporary variables are destroyed after the function finishes its work. In this function, this is done from the statement beginning with the word return, and in this case, we want to return the value of str1 followed by the value of str2. You can also run a program without a return statement, in which case it will run to the end and then return 0.

Imagine you want to code a verb where food is being eaten. Let's evaluate some code to show a bite being taken out of the food, and return a string showing how many bites are left.

;

bites=5;
bites=bites-1;
message="You take a bite out of the food, which now has "+bites+" bites left.";
return message;

.

<< Evaluated input( on line 3): Type mismatch (expected string; got integer)
<< Via eval()

First let's discuss what the programmer was intending. He first sets the value of the variable called bites to 5. If he were actually coding a verb for a food object, he would probably include the bites as a property on the object, but for the sake of example, he just writes the value 5 in. Then, he sets the value of bites to the value of bites minus 1, which in this case would be 4, indicating that there are only 4 bites left. In both cases, the = operator sets the variable or property on the left to whatever is returned from evaluating the right side. So since bites-1 is on the right, and bites was equal to 5, 5-1 = 4 and 4 is returned. 4 is then assigned as the value of bites. This right to left evaluation of the assignment operator is extremely important, as exercises increase in complexity. So remember it now.

The next line is also an assignment line. On the right side of the equals sign, we see the programmer attempting to concatenate a string with a number. MOO does not like this, and it stops the entire program with an error. The variable message, on the left side of the assignment operator, doesn't get any data at all, even though the first part of the message, the string part, looks fine. Later we will cover how to let the program keep running instead of just stopping when an error like this occurs. The final line would return the message if the programmer manages to diagnose and fix the error, which is what we will do now.

Your error line number may be slightly different, but the important part is the type mismatch error. You get this because you tried to add a number to a string, and MOO isn't smart enough to know that you just want to insert the number there. You can convert the number into its string representation with the built-in function tostr(). Make it a habit to convert any numeric values into strings when you display them as part of strings. It'll save you a lot of headaches later.

;

bites=5;
bites=bites-1;
message="You take a bite out of the food, which now has "+tostr(bites)+" bites left.";
return message;
.

 << => "you take a bite out of the food, which now has 4 bites left."
<< [used 2 ticks, 0 seconds. Finished in 0 seconds.]

You will come to know what operators can be used with which types as you continue to program more. For example, many of the functions in $math_utils require the float type, which is simply a number with a decimal point. Yes, 5 and 5.0 are very different in moo. You can't even add those two numbers together without getting a type mismatch error!

If you want to convert something to an int, use the toint() function. To convert to a float, use the tofloat() function. You will be using these a lot, so remember them! To convert a value into an object, use the toobj() function. For anything besides integer and floating point numbers, you get the system object, otherwise you get the object equivalent of the integer value. There is another universal conversion function called toliteral(), which converts whatever you send in to a string that you could send back to the evaluator in order to get the original value back. For example, the toliteral function puts quotes around strings whereas the tostr function does not.

There are a few other types that you will learn about later, including lists, maps, and errors. For now, just know that they exist, and that you can convert them all to literals with the toliteral() function.

Let's practice some type conversions, and notice some curious things as we do it!

> tostr(25)
<< => "25"
> ;"The sum of 5 and 8 is "+tostr(5+8)
<< => "The sum of 5 and 8 is 13"
> ;5.0+5.0+5.0
<< =>15.0;
> ; 32.0/4.0
<< => 8.0
> ;31.0/4.0
<< => 7.75
> ;tostr(#2)
<< => "#2"
; > toint(#5);
<< => 5
> toobj(20)
<< => #20  (string utilities)

Nothing should be overly surprising with these demos. You will notice that when you divide two floats, you get the full decimal value of the answer. Another thing to note: when you convert an object to a string, the # sign before the object number is preserved. But when you convert it to an integer or floating point, it goes away.

Now, let's discuss some more about objects. You may have heard about the player tell verb. To see it in action, let's send ourself a message.

> ;me:tell("I am legion");
<< I am legion
<< => 0
<< [used 676 ticks, 0 seconds. Finished in 0 seconds.]

The word "me" in the evaluation is what is known as an automatic variable. It references the player who is using that particular connection, and only can be used in evaluation code, not standard verb code. If you were to simply evaluate the word me, it would return your player object. Thus, me:tell calls the tell verb on your player object, which then sends you the message. The tell verb always returns 0. There are several other automatic variables that you'll learn about later.

Your player has verbs? Indeed it does, even though you haven't programmed them. They are inherited from your parent objects, and this is what is known as an inheritance hierarchy. To get the inheritance hierarchy of an object, use the @parents command. For example, @parents me will give you the inheritance hierarchy of yourself. You will see about a half dozen different objects, that all contribute verbs to your player. The :tell verb is part of the $root_class object, which you could find out by typing @verbs $root_class and perusing that dauntingly long list of verbs. So any object that is a child of $root_class has a tell verb inherited. Feel free to experiment with some other verbs in this inheritance hierarchy.

Caution

If you extrapolate a little, you will probably realize that other players have a :tell verb just like you. You can use this verb to tell them anything you want at any time. Don't abuse this! If your victim can't figure out who's sending the messages, they will probably ask a wizard to investigate, and this sort of anonymous harassment is against the rules, so you will most likely be reprimanded.

Stretch your Thinking

  1. Write a single-line evaluation that uses the player:tell verb to tell yourself the result of 17 to the power of 10. Do not use the multiplication operator. The evaluation should return 0. Hint: You may want to peruse the functions in $math_utils to help you.
  2. Write a single-line evaluation that would let you find the name of the object that was the sum of the wizard utilities and math utilities objects, which are #24 and #26 respectively. Your evaluation should return the reference to the object.
  3. Critical thinking: Integer division does not seem all that useful because it just drops the entire decimal value of the division operation. When might this property have actual utility?
  4. In many other programming languages, adding 3 and 5.0 would not give an error, but would quietly convert the value 3 to 3.0 before running the calculation. MOO is not designed to do these implicit type conversions. Imagine you would like to add this functionality to moo, and develop a list of rules denoting how the moo should implicitly convert values.

What really are verbs, properties, and abstraction? Beginning Object Design

When talking about objects, you will hear the terms "verbs" and "properties" very often. Academically, you know that verbs are actual programs, and properties are simply values stored on the object. Conceptually this might not really be clicking so let's think about how we would make something really simple, a virtual flower. We will do this by discussing some examples of how other objecst are made. You will begin the flower's design during this discussion and think through it more deeply in the exercises.

But before we start coding, it's important to think about what we actually want out of this virtual flower. For the sake of the example, we just want to be able to look at the flower. The flower color should be able to be changed with a property, because the only other way to change it is by modifying the code, and that's a lot more trouble and less reliable. In real life, a flower is not simply some object with a color that one looks at. Actual flowers are infinitely more complex, with various pollination methods, petals that can move depending on ambient sunlight, and photosynthesis abilities. This is why our virtual flower is an abstraction from the real flower: these other concepts are not important to us at this time.

The movement from the actual object to its abstraction presents a question: how much detail do you want your object to have? To see the very differing answers to this question, you can peruse the verbs and properties on various objects in the player creations database, with the @verbs <object> and @props <object> commands.

For example, let's start with the %guitar object. There is a single property, playing, and a single verb, play. To explore the play verb of the guitar to see how it works, use the command

> @list %guitar:play without numbers

This lists all the lines of code in the play verb of the guitar object. The "without numbers", which can be shortened to "wo n", suppresses the showing of line numbers for this listing. The code for this particular object is pretty self explanatory. There is a check to the .playing property so that you must wait for the guitar to finish playing before playing it a second time. If the guitar was not already being played, the program continues, with a couple unchanging messages before it's finally finished. The suspend() built-in function pauses execution of the entire program for the specified number of seconds. This description of how the play verb does leave out some details, but as you work through the guide you will probably understand it better.

Now let's look at another object, the %firework. Before you list its code, you may want to read the help file to see how the programmer intends you to use the firework. To do so, type help %firework. On the surface this seems pretty simple to use. Just drop and light it and boom! If we look at the code, we will see that the programmer put a good deal of thought in to the functionality of the object.

First let's start with the properties. There are quite a few of them. The properties ending in _msg are messages, which you may remember from working through the building guide. The @messages <object> command simply grabs all the properties ending in _msg that the object and all its parents have, and displays them after stripping off the _msg from each name. Try evaluating some of these properties. For example,

> ;%firework.types
<< => {"brocade", "cake", "chrysanthemum", "Crossette", "Dahlia", "falling leaves", "Farfalle", "Roman Candle", "palm tree", "pistil", "Salute", "spider", "strobe", "waterfall", "Tourbillion", "flower", "badger", "panda", "dog", "cat", "dragon", "hedge hog"}
<< [used -1 ticks, 0 seconds. Finished in 0 seconds.]

Notice how we evaluate properties: the object, followed by a . followed by the property name. Also notice the result of this particular evaluation. It looks like a number of strings separated by commas and surrounded by braces. The two braces represent a list. A list is another type of value in moo, similar to how integers, floats, strings, and objects are types. A list can contain 0 or more items, and the items are separated by commas. Lists can contain any type of item, including other lists. Evaluate some more of the firework's properties to familiarize yourself with doing it. Check out the verbs on the firework at your leisure, and you should be able to follow the code pretty well. Start with the light verb. You will see that the light verb calls the this:explode() verb.

The word this is another automatic variable referring to the object that is running the verb code, which in this case is the generic firework. Whenever someone makes their own firework, the value of this changes to be the firework they created, not the generic one. Always remember that functionality! This:moveto(#-1) simply moves the object to #-1, which simply means that the object is in the moo's concept of the void.

Since the code in %firework:light calls this:explode, you will probably want to take a look at the %firework:explode verb to see what happens. You will see several calls to this:outdoor_print(), and feel free to stop and peruse that verb. If you were to test the actual firework, you could infer that the outdoor_print verb is probably sending messages to nearby people who are outdoors. Don't be afraid to test objects to see what they do! Be inquisitive, because this is how you can figure out how things work. After the firework is finished exploding, it is returned to its owner's inventory (this:moveto(this.owner)).

Now, finally, we can begin to set up our virtual flower. Hopefully, as you have been reading about how these other objects work, you have been thinking about your flower as well. Besides a color, maybe you want to enhance it further. In fact, hopefully you do!

>@create $thing called a flower
<< You now have a flower (aka flower) with object number #21177 and parent generic thing (#5).
> @prop flower.color blue
<< Property added with value "blue".

Of course, your messages may differ slightly. The @create command should be familiar to you, and we inherit from the generic thing because it's simple. We then add a property called color on to the flower, and assign the default value of blue to it. Remember, the word blue is a string, so it must be quoted. We can easily change this later. Nothing too difficult here yet.

Now let's talk verbs. This is where people's eyes begin to glaze over, if they haven't already. Remember that the flower inherits all verbs and properties from the generic thing, and that you can use the @parents command to view the inheritance hierarchy. There is a verb on the root class called description() that is used whenever you look at an object. This description verb simply returns the description pproperty of the object, which you can change with the @describe command, and you can see this by listing the verb. It's so simple you might even glance right over it. But let's reprogram this verb for our flower so it returns something else.

> @verb flower:description this none this
<< Verb added (1).

This command creates a verb on the flower called description. When another program calls the :description verb on the flower, it will run this verb, not the description verb from the root class, because it's farther down the inheritance hierarchy. The phrase "this none this" after the verb name indicates the way that other players could call this verb. We'll talk about verb arguments in depth in a later section, but for now, know that this none this means that other players cannot actually use this verb. If you use the examine command to examine the flower, the description verb does not appear in the list of obvious verbs. Now let's program this verb.

@program flower:description

return "It is a pretty "+this.color+" flower.";
.

Now, look at the flower. You will see the generic description, "You see nothing special" has been replaced with the result of the verb we just entered. Pretty neat! Now, assign a different color to the flower using a single-line evaluation. Does the description change?

Stretch your thinking

  1. add some more description of the flower to it with the use of more properties. Does the flower have multiple colors? A certain aroma?
  2. List two or three other things you want your flower to do. Remember, they don't have to necessarily be limited to the abilities of a real-life flower, which are honestly limited. Do you want it to be able to move around the moo? No problem, just note it down now so it stays in your mind. Anything is possible in moo programming, even walking flowers!
  3. Evaluate a list containing the days of the week. There is a list utilities package called $list_utils. Try experimenting with some of the verbs on this package, by using your days of the week list. Of particular note are the reverse, randomly_permute, random_element, and make verbs. You will be using these utilities often!
  4. You can extract a single element of a list by using what is known as the index operator which is []. The first list item has an index of 1, and the indexes increase by 1 all the way up to the last item. The last item can also be referenced with the $ sign. To evaluate a list item, use the [] syntax, such as:
    > ;{2,4,6,8}[1]
    << =>2
    This creates a list of four even numbers, and extracts the first item of that list. IN this case, the value 2 would be returned. Work more with the index operator by extracting the final element of the list. The built-in function connected_players() returns a list of everyone currently connected, with the most recent connection as the first element. Which player was the 10th most recently connected? Which player has been connected the longest?
  5. Critical thinking: Why does the moo look for verbs on the lowest child in the object hierarchy first, then move up to the parent? What would happen if it searched for verb code starting with the parent first and moving down to the lowest child instead?
  6. What would you do if an object becomes so complex that there are too many properties and verbs to easily think about in your mind?

What Really happens when you press enter: demystifying verb arguments and the Command Parser

In the last section, you overloaded the description verb on your flower to change what you see when you enter the look command. Have you ever wondered what code executes when you type a command such as look flower? This is actually not an easy question. Instead, let's make things a little simpler and add a direct command to our flower, which should help us to begin to answer the question instead.

> @verb flower:smell this none none rd
<< verb added (2).

You have just defined a new verb on your flower, called smell. This verb has the arguments of "this none none", meaning that you only need to enter the verb name followed by the object. In this case, the verb is smell, and the object is flower. As long as you are holding a single flower, and there are no other flowers in the room you are currently located, the word flower will unambiguously refer to the flower you are holding. Otherwise, you'll have to use the object number to disambiguate, or move away from all other flowers in your vicinity to remove the confusion. Yes, it is overwhelming, but it's important to get this down pat. You may want to read this section several times if things seem confusing.

Thus, the command associated with this verb is simply "smell flower". To test that you can indeed smell the flower, type "smell flower" now. Nothing happens, and you should not receive an "I don't understand that" message, which means that the command parser successfully found and tried to run your verb. It currently has no code, which is why you saw nothing at all happen. But at least you know that the parser knew your intention, and intention is what counts!

But what's the command parser? The command parser is a set of rules that tries to figure out which verbs to run when you enter a command that ChatMUD would otherwise not understand. There are several kinds of commands that bypass the command parser, such as sending to channels, utilizing socials, or waiting for input from prompts. If the command you enter isn't in one of those contexts, there's a pretty good chance that the command parser is doing its best to figure out what you want.

Let's first talk about the structure of a command. There are five major structures that the command parser recognizes.

  1. verb
    This is a single word, with no arguments. Arguments for verbs of this type are always none none none, and can only be defined on the player, a player feature, or the room the player is currently standing. Remember, a verb may not necessarily be defined directly on the player or her room, but could also be defined on a parent of one of those. For example, the inventory verb, which lists all objects you are carrying, is defined on the generic player object (#6). It takes no arguments, meaning that to activate it, you just have to type inventory.
  2. Verb object
    Usually consisting of two words, this command is the form that the "smell flower" command is using. Arguments for this structure of verb are almost always "this none none". Many objects in the player creations database have this struccture, such as the light verb on %firework, which you studied in the last section. The verb parser looks for matching objects in your inventory and in the room you are standing in, unless you supply an object number, in which it will just use that specific object. If there are multiple objects with a verb of the name defined, the parser will be confused, so you will need to disambiguate by using the number of the desired object, or remove the other objects from your sight.
  3. Verb single-word
    This is an offshoot of the single verb structure. Again, it is almost always defined only on rooms, players, or player features. The verb arguments for this structure are always any none none. The any means that all text after the first word are available for processing during verb execution, and are written to the automatic variable dobjstr. We will talk about dobjstr and other automatic variables later.
  4. Verb object/other connection object/other
    Oh boy, what do we have here? This is by far the most complicated form of the command parser structures. The silver lining is that the verb always comes first. One of the any/other pairs must be the object on which the verb is defined. The connector is one of the words in the "preposition words" list below. The other object/other set can be anything.
    For an example of the structure with the object first, check out the %warpgun:fire verb. The arguments for this verb are %warpgun:point this at/to any. This means that the player could type something like: point warpgun at Athlon, which would point the warpgun at Athlon.
    An example of the structure with the object in the second position is the detach verb on %gun. The arguments for this verb are %gun:detach any from this. Thus, if you have a silencer and have attached it to your gun, you can type a command similar to detach silencer from gun, which will call this detach verb. If this still doesn't make much sense, you will be working with these verb structures as related to the flower, and that should help.
  5. Verb many-words
    Many-words represents any number of words after the verb. Again, this verb structure is seen mainly on rooms, players, or features, not on objects. Code inside the verb parses the many-words string, instead of the command parser.

Prepositions / Connector Words List

Here is a list of the supported connector words. Note that you only have to specify one of any pair of slashed words, and players can use any of the options in the slash to activate your verb. For example, if you set your verb preposition as at, the player also could use the word "to".

  • with/using
  • at/to
  • in front of
  • in/inside/into
  • on top of/on/onto/upon
  • out of/from inside/from
  • over
  • through
  • under/underneath/beneath
  • behind
  • beside
  • for/about
  • is
  • as
  • off/off of

You can also use the word any, to support any of the connector words. Note that players trying to use a connector word not in that list are out of luck; the command parser only recognizes that limited set of words and no other ones.

Now let's go back to our currently empty flower:smell verb. We'll program this verb to explore some automatic variables and commonly used verbs, such as room announce, which displays messages to everyone in the room.

@program flower:smell

player:tell("You take a deep virtual sniff of "+ddobj:title()+", and imagine that it smells good because this is just a virtual flower.");
player:room():announce(player:title()+" takes a deep sniff of "+dobj:title()+". How strange, it's not like it's a real flower!");

.

Notice some old concepts, such as string concatenation, the player:tell verb, semicolons at the end of instructions, and a few calls to other verbs on the player object. If you can't spot those, you should probably go back and read the earlier sections. The new verbs you may see are $root_class:room(), which returns the room object that the object is currently in, and $root_class:title() which returns the name of the object in question. The $root_class:room() verb is very useful for finding the room that any object is in, as it will drill down to find the room even if a player is holding it, or if a container being held by the player is holding the object in question. Evaluate the room verb on items in your inventory, other players on the moo, and objects they are holding to test its reliability.

The other new verb is the room:announce() verb. In this example, the call was to player:room():announce(). This is your first example of a verb calling chain. A calling chain is easy to detect by noticing the colon characters between each call. The chain is processed left to right. Let us analyze what's happening with the player:room():announce() chain now.

  • player:room() - this verb returns an object that is the room where the player is currently located. Imagine that this room is represented by the temporary hidden variable r.
  • r:announce(text) - R refers to a room, and all rooms have an announce verb. This verb is called, and the chain is complete.

Calling chains can be made even more confusing if they include properties as well as verbs. A good way to make call chains less daunting is to break the chain up into multiple calls, using temporary variables. For example, let's break up the following calling chain, which has three links to it, to make it more readable.

this.owner:room():titlec():uppercase()

To break this up, go left to right across the chain, and assign variables to each link until you hit the last one. You can then call this final verb with the last substituted variable. to make this even clearer, you can player:tell the temporary variable, which will tell you exactly what each link the chain is. Here is an example of how to do this. Player:tell lines are not included.

o=this.owner;
r=o:room();
t=r:titlec();
final=t:uppercase();

The value of final is the equivalent of the result of the entire calling chain. Splitting up confusing lines of code into easier parts is important to reading other people's code. Throughout this documentation you will learn other ways to break complicated code lines into more digestable pieces.

And we digress, once again, from this rather involved discussion of verb calling chains to try to get a little further in our discussion of the new smell verb on the flower. The automatic variable dobj is set to the flower's object, which is why you can use verbs like :title() on it. The dobj variable depends on the verb arguments though. If you have a verb that has arguments of "any with this", the value of dobj may be set to #-1. In this case, you would need to access the value of dobjstr which contains the actual text the player typed, instead of what the verb parser was able to figure out. In this case, the value of dobjstr is most likely flower. But if you were to type the command in a shorter way, such as smell flow, the value of dobjstr would be flow instead. Experiment with the values of dobj and dobjstr by using player:tell.

Let's program another verb on the flower to practice with the more complicated verb argument structure. This next verb will let us set the color property on the flower to whatever we would like. Since you set up the color property and programmed the description to take this property into account in the previous section, you can change the flower, then look at it to see the color change.

> @verb flower:color this as any rd
<< Verb added (3).

Your verb takes the verb + object + connector + other structure. The connector is the word as, the first object/other is the flower, and the second object/other is anything, meaning that the parser will not try to figure out what object you are referring to from the text you enter there.

@program flower:color

this.color=iobjstr;
player:tell(this:title()+" is now "+iobjstr+".");

.

Notice the use of the new automatic variable iobjstr. This is the indirect object string, which is the text you entered after the word as. The program sets the color property of the flower to this object string, then gives you a status message to let you know what you have done. Now look at the flower and see if its color really did change. If it didn't, you have done something wrong.

Here are a few other useful tidbits about verbs before we finish up:

  • A verb can have multiple names separated by spaces. In this case, any one of the individual names of the verb can be used to activate it. To add a name to an already existing verb, use the @addalias command. For example, @addalias sniff to flower:smell would allow you to use either smell or sniff to smell the flower.
  • A verb can allow shortened command words by adding a * before the part that may be left over. For example, changing the name of the flower:smell verb to sm*ell would allow a person to type sm flower, sme flower, smel flower, or smell flower in order to take a virtual whiff.
  • You may be wondering what the rd in the @verb command is used for. It is the permission bits for this verb. In this case, the verb is readable (r), and it prints out any tracebacks to you if it stops working (d). It is not executeable (x), meaning that other verbs cannot call it.

Stretch your Thinking

  1. create and program another verb on the flower using the verb + object/other + connector + object/other form, but make the flower the second object, rather than the first one.
  2. Create and program a verb on yourself that uses the verb any form. It should use the text you send it, either echoing it to yourself or the room you are in. To make it more interesting, use some of the verbs in $string_utils to manipulate the text before it is echoed. Why would this form of verb not work for an object you create?
  3. Create and program a verb on your room that uses the "verb" form, with no additional arguments. Right now you can have it do something simple like displaying a message, but as you continue through the guide, you may think of other ideas for what you could utilize room verbs for.
  4. Synthesis: Now that you understand how objects, properties, and command verbs work, you can start to design an object with the tools you now have. Since you've perused the creations database, you may already have some ideas on an object you want to make. Jot down the object, commands you want for the object, and any properties that the object will need to have. This is a living document, and you will want to update it as you continue and/or think of new ideas for your object. Most of the future sections will contain a synthesis question similar to this one.
  5. Critical Thinking: If you are trying to run a verb that requires an object as one of its arguments, the command parser searches for verbs on objects you are holding, objects in the room, the room itself, you, and any features you have installed. Would you add or remove any items to or from that list, and if so, which ones?
  6. Critical Thinking: There is another set of verb arguments that is very important. They are "this none this". Why is the command parser completely barred from accessing verbs with these arguments? What might they be used for if you can't use them like other command verbs? What are some examples of this none this, (TNT for short) verbs that we have used previously?

Searching for the truth: Booleans and Conditionals

It's time to talk about what's true and what's false. Luckily, truth and falsehood are a lot more clear cut in ChatMUD than in real life. Before we deal with truth and falsehood though, it's important to know why it matters. There are several kinds of statements, called flow control statements, that execute only if something is true or if it is false. A program can be taught to make decisions, and act differently as circumstances vary using these flow controllers. For example, you may want to show a message if a light is turned on, destroy an object if it becomes too damaged to be usable, restrict entry to a room based on what's trying to enter it, or something else.

Let's start with simple truth and false values. The following literals are false:

  • the int value 0
  • the float value 0.0
  • An empty string ""
  • the empty list {}
  • the empty map []
  • any object reference
  • Any error

All other values are true. Disregard the reference to maps and errors for now; they're included for the sake of completeness. In order to test the truth of these truth values for yourself, run this multiline evaluation, substituting whatever value you want to test for the value of the variable "test" in the program:

;

test=0;
if(test)
player:tell(test);
else
player:tell("this value is false");
endif

.

All of the values in the false values list should send the "this value is false" message when you run the program with them. Now let's look at some more complex truth value checks. Remember, if something evaluates to 0, it's false, and if something evaluates to 1, it's true.

> ;5>4
<< => 1
> ;5>6
<< => 0
> ;3+7==10
<< => 1

These expressions are the simplest comparison operators, also known as relational operators. The < operator checks to see if the value to the left of it is less than the value of the right of it. The greater than > operator does the opposite, and the == operator checks if both items are equal. But things aren't quite as simple as you may think, as you will learn in one of the stretch your thinking exercises.

> ;5<=5
<< => 1
> ;5<=12
<< =>1
> ;7<=-8
<< => 0
> ;"bottom"!="top"
<< =>1
> ;"hello"=="HELLO"
<< =>1
> ;"cucumber"=="turnip"
<< => 0
> ;#6==#35
<< => 0

As you can see, string equality checks are not case sensitive, as the HELLO in all caps was considered equal to the hello that was all in lowercase. You were also introduced to the greater than or equal to >=, less than or equal to <=, and not equal to != operators. These do what their names imply they would do. Those are all of the basic comparison operators to know. Let's up the complexity by one more level though, to really make things interesting.

The and && operator takes a truth value on each side. If they are both true, it returns a true value, otherwise it returns 0. The or || operator also takes two truth values, but in this case, it returns a true value if either value is true and 0 if both are false. The not ! operator takes the opposite of the truth value to its right, turning any true value into a 0, and any false value into a 1, which is true. Let's demo these operators now.

> ;5&&0;
<< => 0;
> ;2&&18
<< => 18
> ;8||0
<< => 8
> ;0||""
<< => "";
> ;!10
<< => 0;

Now let's combine the compound operators, &&, || and ! with the comparison operators to see if their truth values still make sense.

> ;6+2==7&&10+5==15
<< => 0
> ;"hello"=="goodbye"||4+5>2
<< =>1
> !(5!=7)
<< =>0

The last evaluation is probably a bit confusing, so let's unpack it real quick. When you see parentheses, you always want to expand the stuff inside them first. since 5!=7 is true, you can replace (5!=7) with 1. Thus you have !1, which is 0. not too hard.

You might be asking why 5!=7 had to be put in parentheses in the first place, and this is because of the order of operations. In moo, the not operator is evaluated first, meaning that the mud would have evaluated !5 and gotten 0. Then it would have had 0!=7, which is true, and thus it would have returned 1. By placing 5!=7 in parentheses, you force moo to evaluate that first.

The final idea to discuss about truth values is what is known as short circuiting. In the case of the && and || operators, there's something on the left and something on the right. If you are making an "and" comparison, and the value on the left is false, it would make sense to just stop working an say it's false without even considering what's on the right, since no matter whether the right side was true or false, it would be false anyway. In the case of the or operator, if the expression on the left is true, you can also stop evaluating, since the whole thing will be true regardless of the right side's truth value. This might appear to be an interesting, if not very useful, detail to know right now, but you may realize the usefulness later.

Now let's put these truth values to use. The quickest way is with the if statement, which you actually got to see when we were doing the initial truth value testing. The simplest if statement consists of

if(expression)
do-something;
endif

The expression in the parentheses can return anything. If it returns a true value, the statements between if and endif run. Otherwise, the moo jumps past the endif and continues from there. To practice this, let's add a verb to quickly tell if we are in an outdoors room. All rooms have a property called outdoors, which is inherited from the generic ChatMUD room with niceties, object #362. By the way, it is a good idea to get familiar with the properties and verbs on the ChatMUD room if you plan to program your rooms. If the value is 0, we are indoors, and if it is 1, we are outdoors. Since the values of outdoors correspond to the truth values that we studied, we can build an elegant verb with minimal fuss. Let's do so now.

> @verb me:outdoor*s none none none rd
<< verb added (5)

@program me:outdoor

if(player.location.outdoors)
player:tell("You are in an outdoors room.");
endif

.

Pretty neat! If you go to an outdoors room and run this verb, you should get the message, and if you are in an indoors room nothing should happen. But there is something you may have noticed if you were typing the verb in, and that would be the lack of semicolons. We don't put semicolons after what are known as flow control statements, because they aren't actually instructions. They are called control flow statements because they can decide what code runs and under what conditions. Without them, your program would just execute top to bottom, like a river, but by adding one, you can control what code executes next, hence the name.

Control flow statements include if/else/elseif/endif, while/endwhile, try/endtry, and fork/endfork. If you do put a semicolon after them by accident, it shouldn't hurt though, but it's bad programming practice and in many other languages, you will be punished for the bad habit. But let's add on some extra functionality to our outdoors verb via the elseif statement.

@program me:outdoor

if(player.location.outdoors)
player:tell("You are in an outdoors room.");
elseif(!player.location.outdoors)
player:tell("You are inside.");
endif

.

Try this verb and it should work as expected. If you turn out not to be in an outdoors room, the code after the if is skipped over, and moo looks for an elseif statement that evaluates to true. Since it finds one, it executes the code in that statement. If it hadn't found any true statements, it would have looked for an else statement, which runs if none of the if or elseif statements was true. Since the code ends after the endif flow control, it is finished.

Let's culminate the section by modifying the verb once more. We want the moo to address us with an honorific, just like a good mudservant ought to, when we ask it if we're outside. We'll base the honorific on what gender we are, since we can easily change genders to test it out.

@program me:outdoor

if(player.gender=="male")
honorific="my good sir";
elseif(player.gender=="female")
honorific="my dear madam";
else
honorific="whoever you are";
endif
if(player.location.outdoors)
player:tell("You are in an outdoors room, "+honorific+".");
else
player:tell("You are inside, "+honorific+".");
endif

.

In this verb we have two separate sets of conditional statements. The first one sets up the honorific, and the second one concatenates the honorific with the literal string to address us politely. To test it out, change your gender with the @gender <gender> command. You can see the list of available genders by just typing @gender without any arguments.

Stretch your thinking

  1. Try comparing some strings with the < and > operators, remembering that the comparisons are case insensitive. What is the rule that determines whether one string is greater than another? Hint: you will want to compare at least 8 groups of strings. If you think you have found a pattern, try to find a counterexample. It may not be what you think.
  2. If you try to evaluate whether two literals are less than, greater than, less than or equal to, or greater than or equal to each other and they are of different types, you will get a type mismatch error. What happens if you check equality of two literals of different types?
  3. No matter how powerful your graphing calculator is, it can't divide by 0, and neither can moo. If you don't believe me, try evaluating a number divided by 0. Perform a single line evaluation where you blatantly get away with writing division by 0 without causing an error.
  4. You can quickly switch a value from on to off with the not operator, which is !. For example, if an object has a property named lights_on that is set to 1 if they are on and 0 if they are off, you can quickly toggle the lights on and off from within its verbs with:
    this.lights_on=!this.lights_on;
    Create a property on your flower that represents whether the flower is wilting or not. Set up a new verb on the flower to toggle this property, and then modify the description verb to use an if statement to indicate the flower's state of health.
  5. You can also nest if statements. By nesting, I mean that you can put an if statement inside another one. To see an example of this, check out the light verb on the %fireplace object. Why does the programmer nest if statements this way? How could this verb be recoded without nested if statements? Would this be preferable? Is it always preferable to nest if statements, or avoid nesting them?
  6. Synthesis: The possibilities of if statements and the truth are exciting, and every interesting object has at least a few so that it doesn't work the same way all the time. Start planning how you will make your embrionic object more responsive with if statements.