Password Recovery

Intro to MPI

From Tapestries MUCK

Revision as of 05:38, 26 April 2007 by Kles (Talk | contribs)
Jump to: navigation, search


The goal of this section is to provide a basic understanding of how to use MPI to accomplish things. In the interest in keeping this a usefully consise thing, it is important that you understand the following before getting started:

  • What a list and property are
  • How to use @set
  • Enough understanding of lsedit to be able to open a list, delete it's contents, and save it with new stuff.
  • You need to make an object for us to haunt, type @create A dollhouse==dollhouse

Some of the things done in this little tutorial might intentionally be done the long way. While this will not be the case in every example, it will be done on occasion. The reason for this is because the goal is to learn how to use more MPI commands that will come in handy when making more useful projects. As a final introductory note, @mpi {somecode} can be used to test a string of MPI on the muck. A lot of the examples in here will be placed inside various propdirs like _mpi, _cmds, and _color, only _msgmacs and _details are special propdirs.

Most of the longer MPI statements will be placed inside a list and called with lexec (MPI). This is done for two readability as well as to prevent problems with some muck clients. On the readability front, it's much easier to read a few lines of MPI sectioned off somewhat meaningfully... 6 months from now if you need to edit it you will be glad. On the problems side, a lot of muck clients do strange things when confronted with long strings of text. By breaking it up into smaller chunks we help prevent those sort of problems. When dealing with strings that wrap across more than one line, generally @set stuff, remember not to insert extra linebreaks when you send it to the muck.

As of now, the document covers how to handle some of the basic core parts of and tricks of MPI used to make some more involved and complex bits of code. All of the code was written on the fly while writing this document, with two exceptions. The exception of basecmd and obasecmd in the Multiple Choice Commands section were written as part of another project of mine. To clear up any questions, all code is given free of charge or restrictions on use, do what you wish with the code.

If statements

if (MPI) statements are used any time you have a situation where you want to check if something is true, and do one of two things depending on the result of that check. You can nest multiple if (MPI) statements inside each other for situations where you want more than two outcomes.

The syntax for an if (MPI) statement is pretty simple, just:

{if:check,do true,do false}

A full list of checks is available in Category:Logical Functions (MPI), but probably the most common one is eq (MPI). The eq (MPI) statement will take two variables and return a 1 if they are the same, or a 0 if they are different. Lets make one and put it on the dollhouse you made at the top of the page.

{if:  «- Here we start the if
{eq:{sex:me},female}   «- Here we set the check to me's sex being female or not
,  «- The comma tells the if statement you are moving past the check and into true
When you think about it\, your doll moves to sit on the nest in the attic
, «- The comma tells the if statement to start doing false
When you think about it\, your doll stands restlessly over the unattented nest in the attic
} «- Here we end the if statement

One important thing in the MPI above is the \, in the true part of the if statement. Certain characters are special in MPI, the comma is one of them. By placing a \ in front of these special characters, you indicate that it's not to be interpreted and should just be printed out as it is.

While the above example is pretty nice, we are going to expand on it when we actually put it on the dollhouse. Right now all we do is check if someone is a female and if not we don't let them on the nest; we aren't accounting for all the strange inbetweens and not at all's that inhabit Tapestries. Go ahead and @set dollhouse=_details/mydoll:{lexec:_mpi/nest} then put this on a list called _mpi/nest on the dollhouse.

When you think about it\, your doll moves to sit on the nest in the attic,
When you think about it\, your doll stands restlessly over the unattented nest in the attic,
When you think about it\, your doll moves to awkwardly tend to the abandoned nest in the attic}}

Now we have a situation where it puts you on the nest if your character if a female, it makes you stand there if a male, and if something else it tries to do something good enough. Although we are going to stop here with this section, there is nothing preventing you from including more and more if statements until you bump into a limit on recursion.

Parse Statements

Now that we figured out how to do a conditional thing, lets work on a repeating thing. There are situations where you have a bunch of variables, but want to be able to run the same code against each of them. Although there are several different ways you can do this, and each of them in Category:Looping Functions (MPI) handle things a little differently, we are going to focus on the simple to understand parse (MPI).

The syntax for a basic parse statement is pretty simple and shown below. There are two optional seperator commands that can be added to the end, but we are going to skip that for now. The variable entry is defined by you, and is simply a name you give the the variable it uses.


Eventually we want our dollhouse to do lots of things, so lets start off with something we will use in the next section.

There are several dolls scattered in the house\r\r
{parse:people «- Here we start the parse and set the variable to {&people}
, «- Here we tell it the list is coming
{mklist:{contents:here,player}} «- Here we grab everyone in the room, but filter it to only players
, «- This tells the parse to start doing some work
A {sex:{&people}} {species:{&people}} looking like {name:{&people}}
} «- Here we end the parse.

Go ahead and put that code on a list named _mpi/who on the dollhouse then @set dollhouse=_details/who:{lexec:_mpi/who}. Now invite some friends over, set it on the ground, and lookat dollhouse who and it will show you everyone there.

Putting it Together

Now that we learned how to make an if statement, and how to make a loop with parse, lets put it together into something a fair bit more advanced. We want this to be a haunted dollhouse, and we can't exactly have a haunted dollhouse without a creepy description that does some spooky stuff. So, go ahead and make a list called description on your dollhouse, set the description with @desc dollhouse={eval:{list:description}}, and put this inside that list (don't forget the space on that linebreak)

The dollhouse modled after an old Victorian era {prop:_colors/housecolor} house, except it's several feet across and absolutely huge for a doll house. Once opened up you can see a kitchen with {prop:_colors/wallcolor} walls and a {prop:_colors/floorcolor} floor. Sitting around the kitchen table playing cards are several dolls\, with a few seeming rather familiar.

In the garage you can see a few more dolls clustered around a barbeque grill making {prop:_food/bbq}.
The various dolls are\r{lexec:_mpi/where}

Now if you look at the dollhouse, you get a screenfull of garbage errors; with any luck it's your first. This is the MUCK telling you that it has problems with your code. Don't worry though, it's expected. Lets look at some of the differences though. Up until now we have always used lexec (MPI) when we want to run the MPI in a list, but this time we are using eval (MPI) as well as the lexec. The reason for this change is because lexec strips all sorts of formatting making it good for executing raw code, but bad for when you have a formatted list you just want to run MPI inside. By using eval (MPI) we can keep the formatting and evaluate the MPI. I'm not going to comment the next example, but see if you can understand what everything does. You might have guessed already, but it's going inside a list called _mpi/where on the dollhouse.

{if:{eq:{name:{&kazoo}},{name:me}},you\, only ghostly and not fully formed by the front door
,{if:{eq:{sex:{&kazoo}},female},A doll that looks like {name:{&kazoo}} in a pink dress.
,A doll that looks like {name:{&kazoo}} only in blue overalls.

Notice how this time we named the variable kazoo instead of people. This was to show that it doesn't have to be anything meaningful, but it does help. Some variables, such as &arg and &cmd are restricted because they are already defined for other uses. Now lets go ahead and set all those colors and such, we are going to need them for the next section.

@set dollhouse=_colors/housecolor:white
@set dollhouse=_colors/floorcolor:yellow
@set dollhouse=_colors/wallcolor:beige
@set dollhouse=_food/bbq:barbeque ribs

look at your dollhouse... and... see how spiffy it is.

Making it Interactive

In this section we are going to take our dollhouse, and make it interactive with the help of an action. Those colors and things we set in the last section are going to come into play here. We won't be going into too much detail about what an action is, since you can get that from the action entry, but in a nutshell it's a command you can create and allow others to access by placing it somewhere they can see it (i.e. in the room with them, or on something they are holding)

First we want to find out what the dbref of your dollhouse is, this is important because it's a good idea to understand what a dbref is and how to use them. You can either type @mpi {ref:dollhouse}, or you can type examine dollhouse. The first method will simply return the dbref the second one will return a lot of stuff, but the part you want is the first line where it says A dollhouse(#1234). From here on, you want to replace #1234 with the dbref of your dollhouse or you will get pretty errors.

Now that we know the dbref of your dollhouse, we want to run the following commands minus the comments.

@action bbqfood=#1234=changestuff  «- Here we create the action and attach it to the dollhouse
@link bbqfood=$nothing  «- You need to do this for it to work
@succ bbqfood={Exec!:_cmds/{&cmd}}  «- Here we tell the action to execute this command for the user
@osucc bbqfood={Exec!:_cmds/o{&cmd}}  «- This tells the action to print something to everyone else
@set bbqfood=_cmds/bbqfood:You change the barbeque grill to cook {store:{&arg},_food/bbq,#1234}
@set bbqfood=_cmds/obbqfood:changes the barbeque to cook {&arg}

Now we have an action that lets us change the food on the barbeque, but we are still missing one for everything else. There is also the fact that we only want people to be able to put one word in place of the colors. The store (MPI) function is used to store text on a property or prop for short. Lets write up how we would restrict that store (MPI) to only take the first word.

{sublist:{&arg},1,1, }

The space on the end of that sublist (MPI) function will tell it to use a space instead of a linebreak to count things by. The 1,1 before that tells it to start at the first word and end at the first word. A positive number will count that make sublist (MPI) start at the beginning, a negative number will make it start at the end and count that many back. Lets go ahead and apply our new code now.

@set $changestuff=_cmds/housecolor:You change the dollhouse color to {store:{store:{sublist:{&arg},1,1, },_colors/housecolor,#1234}
@set $changestuff=_cmds/ohousecolor:changes the dollhouse color to {&arg}
@set $changestuff=_cmds/floorcolor:You change the kitchen floor color to {store:{store:{sublist:{&arg},1,1, },_colors/floorcolor,#1234}
@set $changestuff=_cmds/ofloorcolor:changes the kitchen floor color to {&arg}
@set $changestuff=_cmds/kitchencolor:You change the kitchen wall color to {store:{store:{sublist:{&arg},1,1, },_colors/wallcolor,#1234}
@set $changestuff=_cmds/okitchenfood:changes the kitchen wall color to {&arg}

Notice how this time we are using @set $changestuff= instead of @set bbqfood=? We set our action to answer to $changestuff when we created it. This can be useful, but remember that you don't want to use it in your MPI since it only works for you.

Unfortunately, we still can't access those new commands. In order to do that, we are going to have to rename our action using the @name command. To do that, type @name bbqfood=bbqfood;housecolor;floorcolor;wallcolor;house Now you can housecolor green, wallcolor blue, floorcolor brick because they are fun and get a green dollhouse with blue walls and a brick floor.

Multiple Choice Commands

In the last section we made three seperate commands simply to change the color of different things and a fourth to change what the barbeque grill is cooking. While not a big deal, we could have done the whole thing on a single command with some better planning and slightly more advanced code. Remember, there is a limit to how long that line can be, eventually we would run out of room to string semicolons and names.

There are a few ways we could do this, but we are going to use two of them. First we are going to change the way we handle {&cmd}. Instead of just looking in _cmds/{&cmd}, we are going to break {&arg} into {&command} {&arg1} and {&arg2} then look in _cmds/{&cmd}/{&arg1}. Second, in the case of colors, we are going to specify what is going to be colored in the command itself and let the code sort it out. Finally, we are going to add some security by removing the ability to inject any MPI with the use of these commands.

We are going to make use macros (MPI) as part of doing this. There really isn't much to a macro, at it's core you just have a prop in a special directory. Once you have the prop created, you can just use {propname} to reference it. For example, ours is going to be {basecmd}.

@set $changestuff=_msgmacs/obasecmd:{lexec:_mpi/msgmacs/obasecmd}{obasecommand}
@set $changestuff=_msgmacs/basecmd:{lexec:_mpi/msgmacs/basecmd}{basecommand}
@set $changestuff=_cmds/house:{basecmd}
@set $changestuff=_cmds/ohouse:{obasecmd}

Although it looks funny, the {basecommand} and {obasecommand} is actually there because we are going to define it as a function using func (MPI). Unlike the past examples, the code for this will actually be commented in the code itself as well.

Stick this on $changestuff in a list at the following location: _mpi/msgmacs/obasecmd

{with:command,{sublist:{&arg},1,1, },{null:pull the first word from &arg and name it command}
{with:arg1,{sublist:{&arg},2,2, },{null:pull the second word from &arg name it arg}
{with:arg2,{sublist:{&arg},3,-1, },{null:pull the third word from &arg all the way to the end and name it arg2}
{null:if statement to grab null &arg}
{null:if statement to grab null /arg1/oarg2s}
{if:{prop:_cmds/{&command}/{&arg1}/o{sublist:{&arg2},1,1, }},
{eval:{prop:_cmds/{&command}/{&arg1}/{sublist:{&arg2},1,1, }}}
{null:start do command}
}{null:end if for checking if _cmds/command/arg1 exists}
{null:end do command}
}{null:end if statement}
}{null:end if statement}
}{null:end command with statement}
}{null:end arg2 with statement}
}{null:end arg1 with statement}
}{null:end obasecmd function}

Now you want to put this one on in _mpi/msgmacs/basecmd on $changestuff

{with:command,{sublist:{&arg},1,1, },{null:pull the first word from &arg and name it command}
{with:arg1,{sublist:{&arg},2,2, },{null:pull the second word from &arg name it arg}
{with:arg2,{sublist:{&arg},3,-1, },{null:pull the third word from &arg all the way to the end and name it arg2}
{null:if statement to grab null &command}
{if:{eq:{&arg},{null}},Try {&cmd} help.,
{null:if statement to grab handle command/arg1/arg2 entries}
{if:{prop:_cmds/{&command}/{&arg1}/{sublist:{&arg2},1,1, }
},{eval:{prop:_cmds/{&command}/{&arg1}/{sublist:{&arg2},1,1, }}},
{null:start do command}
Sorry\, that does not appear to be a valid command.\rTry {&cmd} help.}
}{null:end if for checking if _cmds/command/1arg exists}
{null:end do command}
}{null:end if statement}
}{null:end if statement}
}{null:end command with statement}
}{null:end arg2 with statement}
}{null:end arg1 with statement}
}{null:end basecmd function}

Now if you type the house command you get a big black nothing, exciting eh? What it's actually doing is looking for a command that doesn't exist and doing nothing when it fails to find it. Lets start out by making a command that lets us see what's going on behind the scenes.

@set $changestuff=_cmds/expandit:What once was \{&arg\} as "{&arg}"\, is now\r\{&command\} as "{&command}"\r\{&arg1\} as "{&arg1}"\r\{&arg2\} as "{&arg2}"

Now if you type house expandit this is an example of how it works for you to see, you will get a nice output showing all the newly defined variables and how they were broken up.

Lets go ahead and start working on the command to change what's on the barbeque grill since it's going to be the simpler of the commands. The command itself is going to be almost exactly the same as before, except we are going to change { and } to [ and ]. Put the following on $changestuff in a list called _mpi/bbqfood then @set

@set $changestuff=_cmds/bbqgrill:You change the grill to cook {lexec:_mpi/bbqfood}
@set] $changestuff=_cmds/obbqgrill:changes the grill to cook {prop:_food/bbq,#1234}

{sublist:{&arg},2,-1, }

Now you can type house bbqfood soylent green patties and change the barbeque grill to be cooking soylent green patties instead.

We are still going to keep the command to change colors using almost the same code as the code that changes what's on the barbeque grill, but we are going to expand it to prevent problems. We could take the easy way out and simply allow the code to write to {&arg1}color, but then you can have people creating brand new props through typo's and experimentation. We could also filter based on a list of acceptable values for {&arg1} with something like {eq:{lcommon:{list:AcceptableWords},{mklist:{&arg1}}}} in an if statement. We don't want to have to come back to the code later if we expand on what can be colored in the house however. Because of that, we are going to check that _colors/{&arg1}color exists on #1234 and write or error based on that.

{ne:{prop:_colors/{&arg1}color,#1234},{null:prop doesn't exist}}
,{null:store it}
,1,1, }
{null:end store it}
,Try as you mght\, the color won't come off {&arg1}

The above example is using ne (MPI) to check if the value for _colors/{&arg1}color on #1234 (our dollhouse) is any value other than nothing (null (MPI)). If it's something other than nothing then it must exist, so we continue with the if (MPI) statement from there. Stick the code above in _mpi/colorchange, then @set the props below, then your all seet!

@set $changestuff=_cmds/color:You change the {&arg1} to {lexec:_mpi/colorchange}
@set $changestuff=_cmds/ocolor:changes the {&arg1} to {prop:_colors/{&arg1}color,#1234}

We have something functional but it relies entirely on memory. Lets add some basic information to help with using it, first stick something like this in a list named _help/help on $changestuff:

You can use the "house" commands to change things about the haunted house.
To learn about changing colors, type "house color help"
To learn about changing what's for dinner, type "house bbqgrill help"

Now you want to @set some things like what we have below:

@set $changestuff=_cmds/color/help:Syntax is {&cmd} color <location> <New-Color>\rValid locations are: floor, house, and wall.
@set $changestuff=_cmds/bbqgrill/help:Syntax is {&cmd} bbqgrill <new food>
@set $changestuff=_cmds/help:{list:_help/help}
Personal tools