prev | toc | next

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.

@edit tinker.muf
1 999 d

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 !
    ourExit @ while
    ourExit @
    dup "_/de"  getpropstr not if
    dup "_/sc"  getpropstr not if
    dup "_/osc" getpropstr not if
    dup "_/odr" getpropstr not if
    ourExit @ next ourExit !

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

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