MOO Pepsi Tutorial
(Written by Mark Horan)
A MOO Programming Tutorial Vol 1.
This tutorial will help the
reader write a "drink" verb on a can of text-virtual pepsi. The verb will
display a drink message each time it is invoked, until the contents of the
pepsi are exhausted. In the first example listing, each gulp of pepsi will
decrement the original volume of pepsi in the can by 20%. In the second
example listing, the size of gulps of pepsi will be randomly selected.
This tutorial is not designed to answer any question about MOO programming
in a definitive manner; It is designed as a quick-start, a help toward
getting started with a few basics when one finds oneself, as many
beginners do, without a clue concerning where to begin. So this tutorial
will provide help on getting started. Some important MOO programming
structures will be implemented, and the basics of using the verb editor
will be explained.
It is assumed that the reader will have already
requested programmer status at KccMOO, and that their programmer bit has
been set to true.
BEGIN TUTORIAL:
First create an object
upon which to define verbs and properties with:
@create $thing
named pepsi
You have now created a child instance of the generic
thing object #5. Your can of pepsi inherits all the functionality of
$thing; namely, it can be picked up and dropped and, provided you set its
.description property, it can be looked at. However, it cannot yet be
drunk from. Note: There are a number of key MOO objects that can be
referenced via the "$" syntax. This is simply a convienence, providing a
mechanism for MOO programmers to reference commonly used objects without
needed to remember their exact database references; e.g., The generic room
#3 can be referenced with $room, the generic exit #7 can be
referenced
with $exit and the generic player #6 can be referenced with
$player.
Next create a verb on the pepsi called "drink" with:
@verb pepsi:drink this none none
Note: The three items, "this none
none", define the command line arguments for invoking this verb. Since the
verb will be invoked with the command, "drink pepsi", the "this" argument,
or direct object, refers to the object itself. The second argument is
reserved for prepositions, and the third argument is reserved for an
indirect object. Thus, one can define a verb's command line arguments such
that it might be invoked with "give pepsi to charles". In this case, the
verb would be declared with: "@verb pepsi:give this to any". And the
programmer, in the body of his/her code, would be responsible for checking
to see that the value of the built-in variable iobjstr ( indirect object
string ) is the name of an actual player object named Charles. However, in
the case of our "drink" verb, we only need to inform the server that we
are specifying our pepsi thing itself, as a direct object, with the
identity variable, "this".
Next we define a property on the pepsi,
called "remaining", which will hold a value representing the amount of
pepsi remaining in the can. A property is a MOO variable which is
allocated more or less permanent storage in the database; that is, it is a
named slot in the database whose value tends to survive beyond the run of
whatever verbs use or minipulate it. This particular property,
pepsi.remaining, will be
initialized to 100, or 100%. Type the
following command:
@property pepsi.remaining 100
Now we
will invoke the verb editor and write the actual code which implements the
"drink pepsi" command, so type the following:
@edit
pepsi:drink
This command teleports you to a room called the verb
editor, and loads it with the verb you've specified. At this point, the
verb is empty; It contains no lines of code. In the verb editor, you enter
lines of code as if you were speaking MOO wise, to someone in the room;
which is to say, you precede each line with the word or, alternatively,
with <">. Some other useful commands are as follows:
----------
Useful Verb Editor Commands ----------
"com"
to compile your code
listing. Your verb will not run until it is compiled. Enter this command
after you have entered the complete listing of your verb. You will
receive either a success message, or an error message. If you have an
error, use the following commands to move around in the verb editor to
correct you mistakes:
"ins _"
to insert a line after the
specified line number.
"ins ^"
to insert a line before the
specified line number.
"del "
to delete the specified line
number.
As well, you can type "look" while in the editor to learn
about additional commands and options. You can also type "help editors"
and "help @edit". They are many more verb editor commands and options, but
you don't really need to learn them if you'd rather not bother. The above
list will serve you well. Note: If you don't like putting double quotes at
the beginning of each line of code, you can give the editor command
"enter", and the editor will then accept multiple lines of code, each
terminated by hitting the key; however, to get out of the "enter" mode,
you must enter a line of text consisting of only a period "."
as its
first and only character.
When you have entered in all your
code, type 'com' to compile it. You'll see a message informing you of
success if all went well, otherwise you'll see an error message. Usually
this will entail a syntax error, such as forgetting a semi-colon at the
end of a statement, or forgetting to surround a string with two sets of
double quotes. You can develop a sort of perverse talent for spotting
these sorts of errors, but the following code listing should work as
advertised. Enter it into the verb editor exactly as shown. If you get
errors, which is normal enough, use the above listed editing commands to
move about in the listing to delete and insert appropriate lines of text.
When you have successfully compiled your verb, type 'quit' to quit
the
editor.
Now, here is a listing for the "drink"
verb:
(Remember, the variable this stands for the pepsi object itself.)
BEGIN Example 1
=======================
""-- check to see if
player has the pepsi --";
"if ( this.location != player )
"
player:tell("You need to be holding the pepsi to drink it!");
"
return;
"endif
""-- check to see if there is even any pepsi to drink
--";
"if ( this.remaining == 0 )
" player:tell("The can of pepsi
is empty.");
" return;
"endif
""-- drink twenty percent of
original volume --";
"this.remaining = this.remaining - 20;
"if (
this.remaining == 0 )
" player:tell("You finish off the last of the
pepsi.");
"else
" player:tell("You take a cool, thirst-quenching
gulp of pepsi.");
"endif
===============================
END
Example 1
Note: In the above listing, and in the one below, you
will see lines of code preceded by two double quotes, such as the first
line in example 1. This line is a comment line. Its purpose is for
communicating with human beings; The compiler will ignore it entirely.
Remember, the first double quote tells the verb editor that you are
entering a line of code. The second double quote defines the line as a
comment line. Notice also the double quote at the end of this line, just
before the semi-colon. This double quote is also necessary to specify a
comment line. As well, a comment is a MOO code statement, and like all MOO
code statements, it must be terminated with a semi-colon.
Now that
you've defined a verb on your can of pepsi, try it out!
Type: 'drink
pepsi'
Now here is the code listing for Example 2. You can enter
the verb editor again with '@edit pepsi:drink' and delete all the lines
you put there, or you might create a new child of $thing, called 'coke'
maybe, and define Example 2 on it.
BEGIN Example
2
==============================
""-- check to see if player
has the pepsi --";
"if ( this.location != player )
"
player:tell("You need to be holding the pepsi to drink it!");
"
return;
"endif
"-- check to see if there is even any pepsi to drink
--";
"if ( this.remaining == 0 )
" player:tell("The can of pepsi is
empty.");
" return;
"endif
""-- get a gulp --";
"gulps = { 5,
10 ,15, 20 };
"cool = 0;
"while (!cool)
"
$command_utils:suspend_if_needed(0);
" gulp =
random(length(gulps));
" if ( gulps[gulp] <= this.remaining )
"
cool = 1;
" endif
"endwhile
"-- drink the gulp
--";
"this.remaining = this.remaining - gulps[gulp];
"if (
this.remaining == 0 )
" player:tell("You gulp down the last of the
pepsi.");
"elseif ( gulps[gulp] == 5 || gulps[gulp] == 10 )
"
player:tell("You take a sip of pepsi.");
"else
" player:tell("You
take a cool, thirst-quenching gulp of pepsi.");
"endif
==========================
End Example 2
Note: Lines of
code which define programming structures do not end in a semi-colon. These
exceptions include "if (condition)/else/endif" statements, and while
(condition)/endwhile statements.
BTW: Here's a nicer-looking
alternative to the while loop in example 2. These lines can replace
everything between and including the 'while' and 'endwhile':
"if (
this.remaining >= 20 )
" gulp = random(4);
"elseif ( this.remaining
>= 15 )
" gulp = random(3);
"elseif ( this.remaining >= 10 )
"
gulp = random(2);
"else
" gulp = 1;
"endif
When the
can of pepsi is empty, you can type:
@set pepsi.remaining to
100
This will fill the can back up with pepsi, or you can write a
verb that performs this task. In fact the conclusion of this tutorial will
include just that: We will write a callable verb which implements the
"fork()" statement, to reset the pepsi to a full state.
Note: The
line in Example 2, "$command_utils:suspend_if_needed(0);", is a call to a
verb, suspend_if_needed, defined on the command utilities object. The
utilities are a collection of objects which comprise a library of useful,
callable functions, or verbs, which are not listed or explained in the
LambdaMOO Programmer's Manual. You can type "help utilities" to begin
learning more about this library.
Some explanation of terms used
in Example 2:
!= means "is not equal to"
== means "is equal
to"
>= means "is greater than or equal to"
|| means "or"
{ 5,
10, 15, 20 }is a list of four numbers
""-- get a gulp --"; is a
comment line ( ignored when verb is invoked )
Refer to the
LambdaMOO Programmer's manual for more explanation of MOO programming
terms. If you are going to do MOO programming, you must have the
manual.
Or the manual is available for downloading from
parcftp.xerox.com, in /pub/MOO. The file you want is called
ProgrammersManual.txt. You also access this file using your favorite web
browser, by goto'ing this URL:
ftp://parcftp.xerox.com/pub/MOO/ProgrammersManual.txt
It's
important to know how to call one verb from another. In this way a
programmer can write modules of code, each with relatively specialized
functions, and get them to work together to produce desired results.
A
typical program might have three modules, a module designed to get some
sort of user input, a module designed to process that input in some way,
and a module designed to display or output the results of
data
processing. And there is likely a fourth, or main module designed
to coordinate the behaviors of the other three in some fashion, usually to
keep doing these three things until told, somehow, to quit doing
them.
Such a main module might look like this:
done =
0;
while (!done )
input = this:get_input();
result =
this:process_input(input);
this:display_results(result);
if (
!$command_utils:yes_or_no("Do you want to process another?"))
player:tell("You decide not to process anymore data.");
done =
1;
endif
endwhile
So we will declare and define a verb
to be called upon by another verb, namely our Example 1 listed above,
although our new, "called" module, which we are going to write, could just
as easily be called from example 2. Its purpose will be to reset the value
of pepsi.remaining to 100, or 100%, after an appropriate amount of time
has elapsed since it was emptied; say, five minutes.
First declare
a verb, on the pepsi object, called "reset":
@verb pepsi:reset
this none this
Note: The arguments 'this none this' are a special
format to be used with callable verbs. The form 'this none none' would
work just as well, but then you would have this verb being displayed when
users type 'exam pepsi', which is unnecessary as it is not a command, but
an object-internal process. By using the form 'this none this', the server
will know not to tell users about this verb when they use the 'exam'
command.
Now we need to change the permission string on this verb
to include the character which will allow it to be called from another
verb:
@chmod pepsi:reset +x
Refer to the Programmers
Manual for a more detailed treatment of object, verb and property
permissions.
Now the listing for the "reset" verb can be loaded
into the editor as before. Here is the listing:
"fork(5*60)
"
this.remaining = 100;
"endfork
Enter these three lines into the
verb editor and compile as before.
That's all. The fork statement
begins a separate process at the time specified ( 5 times 60 seconds, or 5
minutes ). The statement which resets pepsi.remaining to 100 is not
processed until that time; however,
control passes immediately to the
line "endfork" and, since this is the end of the verb listing, control is
passed back to the calling verb ( pepsi:drink ), with the statement(s)
within the fork remaining to be
executed at the time scheduled. If
you'd like to keep matters a little simpler, just omit the lines
'fork(5*60)' and 'endfork', in which case the remaining statement,
'this.remaining = 100', will be executed by our called-upon verb
immediately.
Now we only need to add a single line of code to
example listing 1, which will call upon the verb we've just written:
"this:reset();". Note the syntax, with the parentheses at the end. In OOP
speak ( Object Oriented
Programming ), you are saying, "call reset, a
member function of "this", the identity variable which, in this case,
refers to our can of pepsi. The empty parentheses '()' show that the verb
is being called with no arguments. You will eventually want to write some
callable verbs so that they can be called with arguments; which is to say,
data that your callable verbs need in order to do their jobs. But that is
beyond the scope of this tutorial. If you have questions concerning
anything this tutorial doesn't illuminate entirely, or that the Programmer
Manual doesn't make clear, post them to *programmeurs ( *prog ).
Now here is the modified listing of Example 1:
BEGIN listing
of modified Example 1 code
================================
""-- check to see if player has the pepsi --";
"if ( this.location
!= player )
" player:tell("You need to be holding the pepsi to drink
it!");
" return;
"endif
"-- check to see if there is even any
pepsi to drink --";
"if ( this.remaining == 0 )
" player:tell("The
can of pepsi is empty.");
" return;
"endif
""-- drink twenty
percent of original volume --";
"this.remaining = this.remaining -
20;
"if ( this.remaining == 0 )
" player:tell("You finish off the
last of the pepsi.");
" this:reset();
"else
" player:tell("You
take a cool, thirst-quenching gulp of pepsi.");
"endif
=====================================
END listing of modified
Example 1 code
Notice the fourth line from the bottom. This is the
call to the callable verb we just wrote, which contained the forked
statement resetting the value of pepsi.remaining to 100 after five minutes
have elapsed.
Hopefully, this little tutorial has provided a
useful introduction to MOO programming. The example listings are
relatively simple, and you can create objects with these verbs defined on
them, interact with
these objects, observe their behavior, and study
the code which produces that behavior. You can generally do this with most
objects throughout the moo; that is, interact with them, observe their
behavior, and study
the associated code. Some useful commands for doing
this are:
examine
Shows information about specified
object
@verbes
Shows all the verbs defined on an
object.
@d .
Shows all properties on an object. Note the
period after the object name. If I want to see all the properties defined
on my own player object, I can type '@d me.'
@d :
Shows
information on all of an object's verbs. Note the colon.
@show
Shows information about an object.
@show obj.property_name
Shows the specified property
@list obj:verb
Shows the
source listing for the specified verb
@dump
Shows all
properties and verbs on an object with values and listings.
Additionally, beginning programmers should make sure they are
subscribed to *prog. If you have questions regarding MOO programming, ask
a programmer or wizard, and/or post it to *prog. It is quite likely that
your question will serve the concerns of other programmers too, either now
or later.