The first step to mastery in the lands of sleep is the realization, without waking, that one dreams. In the day worlds, mastery begins by forgetting, without dreaming, that one is awake.
DM is a programming language for the creation of multi-user worlds. By `world' I mean a virtual multi-media environment where people assume personae through which they interact with one another and computer-controlled objects. This could take the form of a competitive game, a role-playing adventure, a discussion board, or something we haven't even imagined.
Frequently, the terminology of a role-playing game is most suitable: humans are PCs (playing characters) and computer-controlled personalities are NPCs (non-playing characters). The virtual embodiment of a player is often called an avatar. The game rules are written in DM and faithfully carried out by the computer. These define what actions players may instruct their avatar to perform, what effect these will have in the game, and any other events that may happen as time progresses.
To understand the mechanics of the system fully, it is helpful to know a few simple terms. Computer programs that operate over a network are often divided into two parts: a client and a server. In this case, the client is the program that players use to enter commands and see what happens as a result. In other words, the client handles input and output. The server is the program that runs the game, carrying out the rules defined in the DM language. The game designer writes these rules in a third program called the compiler. This reads the DM program (known as the source code by programmers), checks it for grammatical errors, and generates a more compact, computer friendly, file known as the byte code or binary. It is this file which the server reads to see how to run the game.
So there are three main programs: the client, server, and compiler. We call these Dream Seeker, Dream Daemon, and Dream Maker, respectively. (The word daemon is just another (more fantastical) word for server.) As a whole, we refer to this collection of software as BYOND, which stands for Build Your Own Net Dream--an apt description of its purpose and also of how far it has wandered beyond our original plans. But that is another story!
Every introduction to a programming language must begin with the same example. Call it destiny, inevitability, or pure chance; it is rather uncanny that the name of the universal introductory example is hello world. Spooky, no? That's exactly what happens in this example--we say hello to the world.
In DM you write it like this:
mob Login() world << "Hello, world!"
If you have any prior programming experience, the last line probably looks vaguely sensible. It outputs the text inside the double quotes to the whole world. But what on earth is a mob and why is each line indented like stair-steps? All in good time. For now, simply understand that the player's avatar in the game is a mob. When a player logs in, the server is instructed to output the message "Hello, world" to everybody.
Compile and run this program (see figure 1.1). If all goes according to plan, you should see the words, "Hello, world" magically appear on Dream Seeker's output screen. Voila! You have created your first BYOND world.
Now you know the basic steps for designing worlds. You write some DM code, compile it, and run it. But this world didn't have anything for the player to do. That's next.
This first world serves not only as an introduction to the DM language, but to the Dream Maker editor/compiler as well. Fortunately, the system has been designed to be quite simple to use, and with just a few steps you should be on your way to BYOND programming wizardry!
Dream Maker refers to the collection of files comprising the project as the world environment. When you make a new project, you create a single environment file, which has the name "[worldname].dme". This file may contain source code, but in general it will only be comprised of automatically generated references to other files in the project. This is best seen by example, so let's stop talking, and get coding!
mob Login() world << "Hello, world!"
Consider the Hello World example again. The DM code says that when a player logs in, a message should be displayed. We can do a similar thing for other types of actions. For example, if the player types a command, a message could be displayed.
In DM, commands are called verbs. A verb is defined in the following example:
mob verb smile() world << "[usr] grins."
Notice the funny stair-step indentation again! That will be explained in a
little bit. For now, read this example from top to bottom. Once again we
are defining a property of a mob (the player's avatar). In this case
we are adding a verb, an action that the player can instruct the mob
to perform. The name of the verb is smile. The final line displays a
message when the mob smiles. Notice the
[usr] in the message; as you
may have guessed, that is not displayed literally but is replaced by the
name of the user, the player who initiates the command.
Run this example. Once you have logged in, try typing smile and pressing enter. You should see the grinning message with your login name substituted into it. Amazing! Fantastic! But playing god is a serious business. Don't let anyone catch you grinning.
For variety, you could add some more verbs. Here are a few:
mob verb smile() world << "[usr] grins." giggle() world << "[usr] giggles." cry() world << "[usr] cries \his heart out."
Now the stair-step pattern has been broken because all three verbs smile, giggle, and cry are at the same level of indentation. In DM, indentation at the beginning of a line serves to group things together. Here, smile, giggle, and cry are all grouped together as verbs belonging to mob. Each of these verbs has it's own contents indented beneath it.
Notice the use of
\his in the cry verb. This
macro is replaced by the appropriate possessive pronoun. It could be
his, her, its, or their, depending on the
gender. DM provides a few other useful macros like this one to make life
So far nothing has been said (because you never asked) about the empty parentheses after the verb names in the above examples. They were in the first example after Login too. These are the mark of a procedure definition. The verbs and Login are all examples of procedures, which are a sequence of instructions to be carried out. In the examples so far each procedure consisted of only one line--an instruction to display some text. They can, of course, become much more complicated than that.
There are two general categories of procedures: those that show up as player commands and those that do not. These are called verbs and procs respectively. By that definition, Login in the Hello World example was a proc.
The parentheses after a procedure name are more than decorative. They can be used to define procedure parameters. This allows for providing additional information to the procedure. The information is stored in a variable, that is, a piece of memory with a name. To confuse matters, a programmer will often call such variables, which serve as the parameters to procedures, arguments. Why? Well, just for the sake of argument.
Here is an example of a verb that takes a parameter--in this case a short message to be broadcast to the world.
mob verb say(msg as text) world << "[usr] says, [msg]"
In these few short lines are the bare bones of a chat world. Users can log in and start gabbing using the say verb. Try it out. Your session might look something like the following:
say "hello world!" Dan says, hello world!
The main point of interest in the DM code is inside the parentheses where
msg is defined. It could have been called anything; the
variable name is arbitrary. The statement
as text indicates that a
short message supplied by the user will be stored in the variable. This
message is then inserted into the final output at the position marked by the
So far I have casually introduced mobs, verbs, procs, and arguments. Now it is time for a formal (tediously exciting) description of the DM syntax. It may take several multi-clausal sentences to get through this, so don't hold your breath.
DM code is structured like a tree. The top of the tree is called the root. The various types of virtual objects (mobs being one) branch off of the root and may in turn give rise to additional strains that branch down from them.
If you haven't noticed, the code tree terminology is upside down. Of course, so is the file-system on your hard-drive, and every other informational tree in existence. It is quite possible that the vast majority of computer scientists have never actually seen a real tree. The sheer weight of their ignorance keeps the jargon from flipping right side up, and we are stuck with trees having a root at the top and leaf nodules at the bottom. Or it might just be standard obfuscation. That's why I do it.
It is time for an example. One particularly interesting type of virtual object is a turf. It is a building block used to make graphical maps that players can walk around on. Suppose we wanted to make a maze. That would require two types of turfs: floors and walls. Here's how you would define them:
turf floor wall
All we did was branch two new types of objects off of the basic turf. One
floor and the other
wall. The terminology of a family
tree is often used to describe the relationship of the various objects
defined here. Turf is the parent of floor and wall. The two children are
siblings of each other. A child inherits all the properties of its parent
and adds some of its own to distinguish it from its siblings. Both floor
and wall are turfs because they are derived from the turf object type.
To make a maze, we need to specify a few properties of floors and walls: what they look like and whether you can walk through them. While we're at it, the appearance of a player should be defined too. This is how it is done:
turf floor icon = 'floor.dmi' wall icon = 'wall.dmi' density = 1 mob icon = 'player.dmi'
Several assignments have been made. These take the form of a variable on the left-hand side and a value on the right. In the case of the icons, the value is the name of an icon file inside single quotes. In the case of density, the value should be 1 or 0 to indicate if it is dense or not. A dense turf will not allow other dense objects (like mobs) to walk through them.
For most programs, adding graphic support is a massive chore. The facilities in Dream Maker, however, make this task quite simple. For our example, we'll just draw a couple of icons and put them on a map.
turf floor icon = 'floor.dmi' wall icon = 'wall.dmi' density = 1 mob icon = 'player.dmi'
walltile in the tree (it's underneath
turf), and draw them on the map by left-clicking the mouse. You can remove tiles by right-clicking. The map editor has considerable functionality; you can learn about it by reading the included documentation.
The reason we did not have to set the density of the floor to 0 is that the default density of a turf is 0. Since the floor is derived from a turf, it inherits all the default properties of one. This sort of inheritance of characteristics is one of the important elements of object-oriented languages like DM. Ultimately, it is just a compact way of describing closely related things.
Before you test this example, you will need to design the icons and the maze itself. Fortunately, this process is a natural part of Dream Maker's functionality (see figure 1.2).
When you are done making the map, you can compile and test the world. When you log in, you should be able to walk around in the maze you designed by using the arrow keys. Amazing!
Of course there are always small details that one doesn't think about until after the fact. For example, where is the starting point in the maze? We never specified, so players are just dumped onto the map in the first available spot. Here is one way to do it:
turf floor icon = 'floor.dmi' start icon = 'start.dmi' wall icon = 'wall.dmi' density = 1 mob icon = 'player.dmi' Login() loc = locate(/turf/start)
You will have to make a new icon for the
start turf and then edit the
map to mark the starting position with it.
The code that makes the initial placement of the mob is in the
Login proc. It sets the location of the mob (loc) to the
position of the start turf. This is done by using the locate()
instruction--one of the many built-in procedures in DM (see figure
1.3). It computes the position of an object type (in this
Notice how the object type
/turf/start is specified. This notation is
called a type path because of the way you specify the path (starting
from the root) down to the specific type of object you want.
Now suppose you forgot to put a start turf on the map. What would happen? The locate() instruction would fail and the player would not get placed on the map and therefore wouldn't even be able to see the maze after logging in. A total disaster! Wouldn't it be nice to fall back on the default behavior of at least putting the mob somewhere on the map? In other words, we have to somehow run the default Login proc as well as the one we defined, just in case there is no start turf. Here is how to do it:
mob Login() loc = locate(/turf/start) ..()
The final line does the job. It invokes a procedure with a strange name: just two dots. That is the name DM uses for the default procedure, more generally known as the parent or super procedure. In the case of Login, the default proc checks to see if the mob is somewhere already. If not, it finds a vacant spot on the map, which is just what we wanted.
Now you can begin to see the general flavor of DM programming. There are a number of events (Login being one) which are handled by procedures. When necessary, you can override the default procedure with one of your own to make things work exactly how you want.
This is another important component of object oriented programming. Each type of object can respond to events differently. The way in which they respond is inherited from their parents by default, but can be redefined and augmented as needed.
This introduction has just scratched the surface of DM. You should begin to see some interesting possibilities. At the same time, you should have a lot of unanswered questions. Keep both of those in mind; they will be your guide through the more detailed exploration of the language that follows.
No programming environment is complete without a comprehensive, accessible reference. Dream Maker provides this in the form of a searchable index of topics and built-in properties. You may access this by selecting Help On... in the menu, or by hitting the F1 key. If the cursor is positioned on a word (such as "locate"), help will be found for that topic.