3.2 Overview: MUF (cont'd)
Putting it All Together
You make a MUF program do what it is supposed to by defining
functions and directing program flow with conditional statements and loops.
There are a number of fine points, but these are the heart of MUF
programming. Once you have a good grasp of these, you are past the hard part.
Now we will tinker with tinker.muf until it becomes a useful program,
along the way covering most of the issues you will face in
MUF. We will make tinker.muf into a program that checks all
the exits in a room and makes sure that they have @succ,
@osucc, @odrop, and @desc
properties.
First we'll do a rudimentary version with no error checking to
concentrate on new topics, then a final version. Enter the following
code in your program.
====================================
@q
@edit tinker.muf
1 999 d
i
lvar ourExit
: desctell
dup unparseobj " needs a description." .tell
;
: succtell
dup unparseobj " needs a success message." .tell
;
: osucctell
dup unparseobj " needs an osuccess message." .tell
;
: odroptell
dup unparseobj " needs an odrop message." .tell
;
: main
loc @ exits ourExit !
begin
ourExit @ while
ourExit @
dup "_/de" getpropstr not if
desctell
then
dup "_/sc" getpropstr not if
succtell
then
dup "_/osc" getpropstr not if
osucctell
then
dup "_/odr" getpropstr not if
odroptell
then
ourExit @ next ourExit !
repeat
;
.
c
q
====================================
The first line in function main uses the predefined
loc variable to put the dbref of the user's location on the
stack, and then uses the EXITS primitive to put the first exit in
the room onto the stack (the room's dbref is used up). The exit's dbref is then
stored in the local variable ourExit.
This is followed by a loop. The first line in the loop tests the exit
condition: while there is a value in the ourExit variable,
the loop will continue to execute.
The next line fetches the value out of ourExit and
places it on the stack. Then, the value is duplicated and tested four
times, once for each message we're interested in.
dup "_/de" getpropstr not if
desctell
then
DUP puts an extra copy of the exit's dbref on the stack,
to be used in an IF test, leaving the first copy on the
stack. Here, GETPROPSTR puts the value of the exit's
_/de property on the stack... the exit's desc. We want to
tell the user IF the exit doesn't have a desc, so
we reverse the truth value of the top item on the stack with
NOT . If the room does have a desc, the desc string
will be on the stack... and a string other than "" is true.
The NOT will replace this string with 0 zero,
and the IF test will be false... execution will jump to the
line following then. However, if the exit doesn't have a desc,
the top item on the stack will be a "" null string. The
NOT will replace this with a 1 one, for
`true'. In this case, the IF test will be true, and the
code between IF and its corresponding then
will execute: the program will execute the function
desctell.
The same process is then repeated for each of the messages we're
interested in: @succ, @osucc, and
@odrop.
Exiting this loop is controlled by the next primitive.
NEXT takes the dbref of an exit or thing, and returns the
next exit or thing in the room's inventory. So, the line...
ourExit @ next ourExit !
Fetches the dbref of the current exit, gets the next exit, and stores
that one in the ourExit variable.
Execution then jumps back to the top of the loop: while we still have
exits to check, the loop will continue to execute. But, when we run out
of exits, there will be nothing in the ourExit variable.
the WHILE test will be false, and execution will jump out
of the loop.
prev|
toc|
top|
next
|