[Tutorials Copyright 2002 Jekteir]


Tutorials: building, actions, mpi, lsedit


To start off your bulding, you should think about where you are. If you are in, say, Chaos, or Recreations, at the time, you will not be able to build, as the parent is set so that you can't. However, if you are in anywhere in the OOC MUCK Area (go to the portal and then go through the [O]OC exit) or in FreeForm (Portal then [F]ree[F]orm), you can start building!

So, to start building, just use the command '@dig', with a room name. E.g.: '@dig My Bedroom'. This will create a room, named 'My Bedroom', owned by you. The MUCK will automatically set the 'parent' of the room to the OOC Environment Room, or to the parent of the room you are standing in when you build it. The MUCK will also tell you the room number of the room you have just built (Tip: To see the numbers and names of everything you own, use '@own').

Now, you can jump to your room, using 'j [room number you were told it had]'. If you are not sure what the number is, but you don't want to use @own, you can use '@find My bedroom', or '@find [room-name]'. (Tip: If the numbers do not appear next to the names when you use @find or @own, type: '@set me=!S'. This will show you the number of things you own when you see them.)

Now that you are in your room, you can start to set it up. You may want to start by setting the room so that when you log onto the MUCK, you wake up there. This is done by linking yourself to the room. Use: '@link me=here'. (Note: Once you have linked yourself there, you can use 'gohome' to send you straight to your room.)

Now, you will probably want to start describing your room (setting what you will see when you enter it, or when you type 'look' or 'look here'). To do this, use '@desc here=[description]'. (Tip: To put those ====== lines above and below the description of the room like it is in Staff-built areas, use '@hd [description]'. Use '+help @hd' for details.)

So, you have jumped to your room, given your room a description, and linked yourself there. You may well want to set up a couple of handy extras to finish off your fine job. You might for instance want to allow others to set their homes to your room as well. To allow them to link themselves there, you must use '@set here=A'. The reason you don't have to set it 'abode' (the 'A' flag) to link yourself there is because you own it. You may also want to set the room so only you can jump to it. To do this, use '@set here=!J'. [Advice: read 'help flags' to learn more about using @set.]

Now, your first room is pretty much done! The next part is creating more, and then setting up exits between them. To create another room, use the same method. Now that you have got your second room, and are standing in it, you can create exits between them.

To create an exit from one room you own to another, you use @open, followed by the exit name, followed by a semicolon ( ; ) then the letters needed to type to go through the exit, then = , then the room number that you are creating the exit to. So, if I were creating an exit from one of my rooms to My Bedroom, which was #1234, I might use: @open [M]y Bedroom;m=#1234

As long as the letter(s) in brackets in the exit name ( [M]y Bedroom ) correspond to the letter(s) after the semicolon, then the exit is easy to use. For example, using the exit just mentioned, you would only have to type 'm' to go through the exit. Note: It is a good idea to have only one letter in the brackets, because it means exits are quicker to type in, and it is also good practice to make sure the exits aren't the same as system actions (like [L]eafy Road would mean that anyone typing in 'l' for 'look' would move to the road instead).

Now, you can go through the exit, and create an exit from the other side, leading back (E.g: @open [Fr]ont Hall;fr=#9273). [Tip: You can use the program @door to create double exits in one go, but it can be hard to use, and it is recommended that you stick to the method just taught. However, you may see '+help @door' for more information.] (Note: Creating exits: Creating an exit is called linking to a room.)

How to get out of your rooms and back into the rest of the MUCK: You can use 'ooc' to send you back to the OOC area, and from there you can use 'ic' to go to the portal. However, you may well want to get permission to create an exit from your home to a room elsewhere, so that you do not have to go through this. There are two ways of doing this: 1): Go to the Residential Area from OOC; 2): Rent an apartment in an IC area.

Back to the top


To create an action, you use '@action [action]=[where it is used from]'. In your own rooms, you can attach an action to the room itself, e.g: '@action [name]=here'. However, when you are creating an action you can use wherever you go, you will want to link it to yourself: '@action [name]=me'.

Now your action will need to be linked to a program. An action should be linked to $nothing [If you wish to, use 'exp' for an explanation]. If it isn't, you will get a 'You can't go that way' if you try to use the action. To link the action to $nothing, use '@link [name]=$nothing'.

So, if you try using your action, so will see that although there is no error message, nothing happens! This is the fun part. First off, you will want to get an acknowledgement that something has happened when you use your action. For this, we use a 'success' message. To set this, use '@succ [action-name]=[message]'. An example would be: '@succ belch=You belch loudly, and glancing around you, apologise profusely.' So now, if you try using your action, you will get the message sent back to you.

However, at this stage, using your action will only tell you something - others will be blissfully unaware that you have 'done' anything at all. To set what they see, we use the 'osuccess' message. This is the success message that others see, and hence 'osucc'. So, for example, '@osucc grin=grins merrily'. Note how your name is omitted from before the message. This is because the action program will automatically put your name in front, so what others will see will actually be: '[your-name] grins merrily'.

Back to the top


[Note: This tutorial does not include information on lsedit, or lists. See the lsedit tutorial about this.] MPI rocks: It's a better programming language than MUF, although it has less power. You can be a lot more detailed with it, and in truth, anything you can do 'for real' in MUF, like make an object or room with a command, you can simulate with MPI, in your own environment. Just as the MUF-made objects on this game aren't real outside of this game, the MPI objects and rooms etc. are 'real' within any MPI environment you choose to make. Don't worry if you don't get it: this doesn't matter, I'm just rambling. Go on to learn the easiest and coolest MUCK stuff there is.

First thing: MPI commands be used in all the major aspects of the game which you can make. You can put MPI commands in descriptions, and action or exit @succs (and osuccs, drops, fails etc). They will not, however, work in 'say' messages, or action messages. If you don't know how to make actions or build and describe rooms, it would be a good idea to go see those tutorials before continuing, as MPI can only be used within rooms or actions. To try out most of the commands in this tutorial, you will be able to use the '@mpi' command, but there will be points where you will need to make and @succ an action, or even @dig and @hd a room.

To test a command here, use '@mpi [whatever]'. Try out '@mpi {name:me}'. This returns the name of the user. So, if you @succ'ed an action to, 'Hi there, {name:me}!', and then used it, it would return, 'Hi there, [user's name]!'. It won't return the name of the owner of the action. It returns the name of the user, or viewer for a description.

Similar commands to {name:me} are {ref:me}, and {loc:me}. To get help on MPI commands, you can use 'mpi category' for a list of all commands, or 'mpi [name]' for help on one specific command. This allows you to explore new commands when you wish to do something further than this course teaches.

Mathematics commands. Pretty simple. Try out {add:1,5}, or {div:20,4}, or {mult:2,3}, or {subt:10,7} to get the idea. Note the order in {div} and {subt}: it makes a difference which around they go for those. 20 divided by 4 is 5, but 4 divided by 20 is 0.2 . Also note: MPI mathematics does not work with decimal points, only with whole numbers.

The next step is a big one. It will take you some time to grasp if you're new to this, so bear with me, because it just so happens to be the best thing about MPI - the thing which allows you to do the most. Props. Props are little files with names, organised into categories, which have a 'value' given to them. These props are 'stored' on objects (rooms, players, things, actions/exits, programs [that's MUF ones]). What this means is that a prop can be accessed by referring to its name, and what object it is 'stored' on. You can also view the props on a object. Okay, time for examples.

Props contain all the special information which you set by using programs. Your description, sex, species, pinfo and all other things like that are stored on these. The props can be changed, removed, and stored by MPI. 1): You can change and view props on yourself and things you own without writing programs. They've already been done for you. To see what props currently exist on an object, use 'ex [name]=/', e.g. 'ex me=/'. Note: other information is given by using 'ex [name]'. Ex is short for examine; see 'help examine' for more. You will note when you try 'ex me=/' that a prop called 'sex' has a value which is your sex, etc. 2): To set a prop, use the '@set' command. You also use this to set flags on yourself. See help flags and help @set for information on them. All you need to know here is that you can set props by using '@set [name]=[prop name]:[value]'. So, to change your sex prop, you'd use '@set me=sex:[whatever]', e.g. '@set me=sex:Male'.

One other thing about props. They work in directories, defined by / slashes. This makes viewing and separating props easier. E.g. you could use '@set me=testprops/test1:This is test 1.' and '@set me=testprops/test2:This is the second test.', and when you use 'ex me=/' you would see, as one of the props, 'dir /testprops/:(no value)'. This means: a): 'testprops' is a directory, hence 'dir'; b): it has no value itself, only values contained inside the directory. To see the props and their values inside the directory, you need to use 'ex me=testprops/'. These layers of props can continue as deep as you like, e.g. there's a prop I use for the OOC channel command, which is, '~/channels/off/ooc', and whose value is 'yes' if you've turned off the OOC channel.

Now the MPI of props. To set a prop on an object, the object either has to be owned by the owner of the program (action, with the MPI in the @succ message of the action), or owned by the user of the program. These are the 'permissions' required to allow you to set props. We won't worry about these during the tutorial: when you go out and try MPI, you'll get a feel for what you can and cannot do. Simple action. Setting a prop, viewing it, removing it. Make an action on yourself, link it to $nothing, and then @succ it like so: '@succ [name]={null:{store:{&arg},temprop,me}}You've stored the prop.{nl}The prop's value is {prop:temprop,me}.{nl}{delprop:temprop,me}You've removed the prop.' That's it. Try it out. When using the action, use '[action_name] [intended_prop_value]', e.g. 'propaction This is a testprop!'. Continue for the explanation.

This is how your action works. Use '@succ [actionname]' to view the MPI, if you want to check up on what it looks like while I explain. First off, {&arg} is simple. That's whatever you typed in after the command name of the action when you used it. So with '[actioname] This is the prop.', 'This is the prop.' would be the {&arg}. Now, the {store} command takes the {&arg}, and 'stores' it on a prop called 'temprop', on you. The {null} bit around the store command is needed because without it, the {&arg} you were storing would be shown to you as you used the action. Feel free to try removing it etc. to see what it would look like. Experiment. {null:{store:{&arg},temprop,me}} is the same as '@set me=temprop:[whatever you typed in]'. See mpi store for more, and mpi &arg. Then the action tells the user, 'You've stored the prop'. The {nl} is simple - it means 'new line', which means that the next piece of text will be shown to you on the next line.

So, on the next line, you're told 'The prop's value is {prop:temprop,me}.' The {prop} command is pretty simple too. It goes, {prop:[propname],[object where it's stored]}. So, it calls up the value of the prop temprop, which you just stored, and shows it to you. New line. {delprop:temprop,me}. You can probably already guess what this means. It's the same as '@set me=temprop:'. It removes the prop from you. Then the action tells you, still on the new line, 'You've removed the prop.' Simple, eh? The reason you don't need {null} around the {delprop} is that it never gives a value when it's used, and the reason you don't need one around {prop} is because it's already telling you something. I'm not going to talk very much about {null} from here on, either: you'll get a feel for that too. You should get the idea, roughly, what it means now. See 'mpi null' for more, but don't get confused.

Okay, so, with {&arg} and {store} and {prop}, you can actually do quite a lot now. There's 2 other major aspects of MPI to discuss. One is the absolutely most crucial part of MPI, and the other is nearly as useful. These arer {if} and {tell}. First, {if}. Once you understand this, I'll be able to show you some great programs to work on and adapt, and learn from. {if} checks whether a statement is true or not. If it is, it does one thing. If it isn't, it does something else. It works like this: {if:{[statement to check]},[do this if true],[do this if false]}. For a very simple test, you can try '@mpi {if:{eq:1,2},1 and 2 are equal.,1 and 2 are not equal.}'. The {eq:1,2} part is the statement to be checked. It means, are 1 and 2 numerically equal? And they aren't. Since they aren't equal, the bit after the second comma, [do this if false], is shown to you, and you see '1 and 2 are not equal'. Remember, @mpi is just a way of checking out MPI strings without out writing an action to stick it in, but it won't work when you want the MPI to use {&arg}. Just remember that. Let's see what other 'checking' statements there are, and exactly how they work.

In the last example, you saw '{eq:1,2}'. This is the checking statement, and it means, 'see if these are equal'. It can compare numbers, or 'strings'. 'Strings' mean bits of text. A string is 'Hello there!', as is 'This is a string which has number 1 in it'. If you were comparing strings, you might try '{eq:{&arg},yes}'. This checks whether the 'argument' you put in, that is, what you typed after the action name, is 'yes'. Other 'checking functions' apart from {eq} are: {ne}, 'is the first thing not the same as the second?', {gt}, 'is the first thing greater than the second?', {lt}, 'is the first thing less than the second?', {ge}, 'is the first thing greater than or equal to the second?', {le}, 'is the first thing less than or equal to the second?'. If any of these are true, then the [do this if true] bit is run. Note: The things to be compared are separated by a comma, as are the [do this if true] and [do this if false] bits of the {if} function.

Now, what's actually happening? It's simple. The checking part sees if a statement, like {gt:3,1} is true. If it is true, the checking statement tells the 'if' function that it is true. The if function then 'evaluates' (runs the MPI in) the part of the if function which is after comma after the checking part, and before the next comma. This explains why commas are soo important. They sort out which part of the function is which. So, {if:{eq:{&arg},yes},You typed 'yes'.,You didn't type 'yes'.}' sorts out whether you typed 'yes' after the action name. If you did, it goes past the '{eq:{&arg},yes}', and past the comma right after that, to 'You typed 'yes'.,You didn't type 'yes'.}'. Then it separates this by the comma in the middle, so that the bit which it evaluates is 'You typed 'yes'.' And that's what it tells you, the user of the action.

To put in commas into what you want to be evaluated, you need to make it clear that they aren't part of the MPI itself, or else the program gets confused and ends in an error. Misplaced or extra commas, or ones which aren't intended to be part of the programming, are the most common MPI mistakes there are. If you wanted the last program explained to tell you 'You said 'yes', I've just checked.' if they did type yes, you'd need to make sure that the comma in the middle of that part was not part of the program itself. To do this, you put a \ slash in front of it. This means that it is not counted as part of the MPI. Incidentally, that's how I can show you all this MPI in these room descriptions - normally all this would be evaluated every time someone looked at the description, but I've put \ slashes before each { and } bracket. I don't need to put \ slashes before the commas if I do that, because they aren't inside MPI brackets. Now, the last part of the tutorial, and then examples.

The last important thing before you can do a lot of stuff is {tell}. This tells a player a message. It's used by {tell:[message],[player]}. Again, if there are any commas in the message you're sending, you'll need to put slashes before them, otherwise, they'll be mistaken for the comma separating the message and player name, and then you'll get an error, and everything won't work. Now, the 'permissions' are quite important with {tell}, because you can't just use any player name at the end, and expect the message to be told to that player. If a player isn't in the room the user of the program is in, you'll get an error message when you try to use that player's name in the program. You can use a player reference # in {tell} functions, and the permissions apply. The only difference is, if the dbref# is that of the owner of the program, and the owner isn't in the room, the owner can still be notified.

{tell} is another one of those functions where you'll usually want {null} brackets around it, otherwise it will tell the user player the message it's sending to the other player as it sends it. Note: you can also use {tell:[message],me} to tell the user messages, but you won't generally want to do that, as you can just input the message to be told in plain text, and it will be told to the user because the text is in the success/description/drop etc. message. The {otell} function is simple. It works, {otell:[message],[room # or 'here']}. This tells the message to everyone in that room except for the user of the program. The room is specified either with a room dbref#, or 'here', which means the room where the user is when using the program.

Now we'll have a room of miscellaneous MPI functions, which you will be able to use in context with all your knowledge so far, then a couple of rooms of examples, and then some extra 'advanced MPI' rooms, and that'll be that. I'll also link up some 'frequently asked questions' rooms from here, when people start complaining about how pathetic my tutorial is, and how it doesn't tell them anything :) You need to recognise that what I've given you here is the tip of an iceberg. With MPI _solely_, I've created boats (controllable ones, with docks where the boats can be called from and to, with varying times etc.); elevators; spells; surprisingly complex 'who' lists for areas, and much more. You can create your own interractive areas in 'Recreations' with this MPI, as well as anything in other countries, or in OOC homes. Major functions to be discussed later on in the advanced tutorial are delays, looping functions *shudder*, the 'for' and the 'parse' functions (very useful for advanced MPI).


{contents:[room/player/'here'/'this'/object](,[type])} See 'mpi contents'.


{and} {or} {not} These are similar things. See 'mpi [name]'.






These are all simple enough for you to figure out with 'mpi [name]'. They can be useful. Please note: 'lists', list items, the lsedit program, and all other MPI (e.g. {lrand}) to do with lists is discussed in the lsedit tutorial.

MPI Examples:

1: The blackboard. So simple, you'll cry. But worth putting here. '@create Blackboard', 'drop blackboard' (not here), '@desc blackboard=It reads: "{prop:written,this}"', '@action write=blackboard', '@link write=$nothing', '@succ write={if:{eq:{&arg},},Write what on the blackboard?,You write "{&arg}" on the blackboard.{null:{store:{&arg},written,blackboard}}}'. That's it. Work it through: the description of the blackboard shows whatever's written on it by bringing up the 'written' prop on it. The 'write' action checks if what you've put after the action name is equal to nothing (i.e. you've only done 'write', with nothing after). If it is, it asks you what you want to write. If it isn't, it stores what you've said to the 'written' prop, and if you look at the blackboard, it'll be there.

A 'hit' action. '@action hit=me', '@link hit=$nothing', '@succ hit={if:{eq:{&arg},},Hit whom?,You hit {&arg}.{null:{otell:{name:me} HITS {&arg}!,here}}}'. Nice and simple.

Back to the top


This is the lsedit tutorial. The lsedit program lets you edit 'lists'. These can contain more text than such things as descriptions, and so what you can do is to write a really long description inside the lsedit program, and then put this list inside your description with some simple MPI. You can also do a lot more cool stuff with lists with very simple MPI, which I'll show you here. The MPI you'll need will be discussed here, and not in the MPI tutorial.

First things first. Before I explain how you use lists, I'd better explain the editor for making/deleting/editing lists, otherwise you might do something silly, like getting in the editor and not know how to get out. Lists have names, and are 'stored' on objects which you own. To edit a certain list, you use 'lsedit [object name or #, or 'here' or 'me']=[listname]'. To get out of the editor, saving your work, use '.end'. Don't miss out the . at the beginning of these commands, otherwise the editor will just take what you're typing and add it to the list you're editing. To get out of the editor without saving, use '.abort'. Now, what are lists? And how do you use them? And why do lines in the list matter? WHAT'S THIS ALL ABOUT?!

For a technical explanation of what lists actually are, type 'technical'. The test for this is whether you can spell technical correctly :) You don't need to read that to know how to use lists - it's purely for information. If you're new to MUCKs/MPI the technical explanation may mean nothing, and you might not want to bother reading it. Now, what are lists all about? a): Lists can contain a lot more text than descriptions, or action @succ's. This is why, if you've got a really long description, or a really long action @success message (in which MPI may or may not be included), you may want to make a list to fit all of the text in. Using very simple MPI, you then load that list into the description or the @succ, and there you go.

Take an example. Your description. If you don't have one, make a short, simple one up, and use '@desc me=[description]' to set it. You use 'look me' or 'l me' to see it. Now, we'll do the same thing, but we'll put the text in a list instead, and then load the list into your description.

1): Do 'lsedit me=[whatever list name you want]'.

2): Type in the description. Do it one line at a time, pressing the enter/return button between lines.

3): Do '.end' to exit and save the list.

Remember, anything you type in whilst editing goes into the list. To delete a line, use '.del [line number, e.g. 2]'. To see all lines, use '.l'.To look at one line in particular, use '.l [number]'. To see all the lines with their numbers beside them, use '.p'. To delete all the lines, use '.del 1 1000' (this delete all lines from 1 to 1000). To insert a line before another, use '.i [number]'. That will place where you're inserting from at that line, and then you can start inputting lines.

You've done your list, you've saved and exited. Now, to put it into your description. Describe yourself, with '@desc me={list:[listname]}'. This will put the list into your description. The MPI function {list} simply takes the name of the list and the object on which it is stored, and produces that list. However, since the description is yours, and the list is stored on you, you don't need to specify yourself as the object on which the list is stored, you can just give the name. If you didn't get that, don't worry. If you've got a list with MPI which you'd like to be run when someone accesses your description/action @succ, you need to change the {list} function to {lexec}. It works the same, but it evaluates MPI, whereas {list} does not.

When you use {lexec}, the lines follow directly on from each other without new lines being formed unless there is an {nl} to do it. Sometimes spaces between lines are cut off, and this means that, if you had the first line of your description reading 'This is a very big, very frightening fox, who ' (note the space after 'who'), and the second line reading 'likes to kill and eat small, frightened animals.', what might happen is that when the list is read in your description, it will come out as 'This is a very big, very frightening fox, wholikes to kill and eat small, frightened animals.' To correct this, you can use {lit: } at the end of the first line. This ensures that a space will appear after the first line. Please note that this problem should only occur with {lexec} list-reading, and if you put {lit: } in a {list}-read list, it will just appear as {lit: } because it is not evaluating MPI.

You should also note that an list's 'line' does not, in fact, have to be what we would consider a line. It is whatever text is inputted at the same time. So if you type 'This is a dog.' [ENTER] 'This is a list line which is actually longer than a line on my MUD client but that doesn't matter because the lsedit program doesn't think of lines that way.' [ENTER], although the first line is very short, and the second line actually longer than a line, they are both lsedit 'lines'. There is a limit to how long one line can be, in lsedit. However, you can split a line that is too long up into smaller lines, and then input them, and that'll be fine. It's best not to input too much text for each line. Now that you know what an lsedit 'line' is, we can go onto the next part: Some cool list MPI.

The MPI functions to do with lists are: {list} and {lexec}; {rand} and {lrand}; {lremove}, {commas}, {count}, {lcommon}, {lmember}, {lsort}, {lunion}, {lunique}, {mklist}, and {sublist}. We'll be exploring {rand}, {lrand}, {lremove}, and {mklist}. Please note: for MPI help files on any list function (or any function, for that matter), use 'mpi [name]'. You will most likely need to understand basic MPI before proceeding any further.

{rand} and {lrand}: Not too hard to grasp. {rand:[listname],[object #]} returns a randomly picked 'line' from that list. If you find Sulfras, he may show you his JP-quote-machine, which shows you randomly selected lines from a huge list of quotations from the film Jurassic Park. {lrand} is similar: it can also use a 'separator', however. You could use it like this: {lrand:[list],[separator]}. You can use this in 2 ways: either by typing the list into the {lrand}, like {lrand:1-2-3-4,-}, which would randomly select either 1, 2, 3, or 4, or by loading alist within it, like {lrand:{list:[name],[object #]},[separator]}. The separator is simply what separates what can be picked randomly. So the list could be 'this is one item[this is two[and there's three[and so on'. If you used a separator '[' on that, you would randomly get one of those four sentences. If you wanted to randomly have a line of MPI from a list evaluated, you'd use {eval:{lrand:{list:[list],[object #]},[separator]}}. You would not use {lexec} instead of {list}. If you did, every line in the list would be evaluated. The {eval} here means that once one line has been selected, that line _only_ will be evaluated for MPI.

{lremove} and {mklist} are basic functions that you use in bigger programs. {mklist} simply takes a group of strings separated by commas, and turns them into a group of values separated by {nl}s (i.e. a new line for each list item). Note: This does not magically lsedit a list onto anything, it just temporarily gives a list-like feel to a group of values. Note: the max no. of values which can be {mklist}ed are 9. {lremove} again is not magical, it doesn't edit and change lists. You use {lremove:[list],[list2]}. This removes any items in list2 which are also in list1 from list1, and then gives you list1 with those items removed. This is an example of how you could you {mklist}: you could use {lremove:{mklist:1,2,3},{mklist:1,2}}, and this would return '3'. Or, {lremove:{contents:here,player},{mklist:*{name:me},*Bob}}, which would return a list of all players in the room except for you and Bob.

Back to the top