It might be only a dream after all, part and parcel of this magic house of dreams.
Players have several ways to interact with their world. They can move around with the arrow keys, select objects with the mouse, and type commands (or select them from a menu). In DM, the commands you define for players to use are called verbs. They form a sort of player language.
Verbs are always attached to some object. This is done by putting the verb
inside the object definition. This object is called the source of the
verb. The simplest case, is a verb attached to the player's mob.
This example defines a verb called
As you can see, the definition goes inside a node called verb and is
followed by parentheses. The name of the verb itself (like any node)
follows the same rules as an object type name. It is case sensitive,
consists of letters, digits, and underscores, and must not start with a
digit.
Just as with object types, you can override the actual name of the verb (as
seen by the user) to overcome the limitations of the node name. This is
done with the set command. Example:
The reason the verb node could not be directly specified in lowercase is
that there is a reserved word break that prevents
this. Capitalization is a simple way to avoid conflicts with reserved words
because they never begin with a capital letter. (If you are
curious about the meaning of break hang on until chapter
6.)
Notice the condensed style using slashes in place of stair-step indentation.
The use of the set command distinguishes between an assignment of
the object's name and an assignment of the verb's name. Also note that the
name assignment is said to take place at compile-time rather than
run-time. Otherwise, like the assignment of luminosity, it would not
happen until the verb was executed by the player.
There are other properties of a verb that can be configured using the
set command. They are presented in the following list.
As you have already seen, this is the name of the verb as seen by the user.
It defaults to the node name with any underscores replaced by spaces.
A description of the verb. Players can see this by typing the verb name and
pressing F1. Another way is to hold the mouse over it in the verb
panel. The syntax is described for you, by default, but if you wish to
override the way individual arguments appear, you can do so inside
parentheses at the beginning of the text. See page [4.5.1] for an
example.
Verbs can be grouped by assigning a category name of your choosing. They
will show up accordingly in the verb panels.
This is 1 or 0 to indicate if the verb is secret. A hidden verb will not
appear in the panels and will not be expanded on the command line. As a
slight variation of this, verbs beginning with a dot are like hidden verbs
except they expand once at least the dot has been typed. You might, for
example, have a large number of social commands that you don't want
cluttering up the normal verb menus. In that case you would probably want
to use the dot prefix to hide them.
This is where you define the relationship between the user and the source of
the verb. The effect is to control who has access to the verb. See the
explanation in the next section.
One of the most important aspects of a verb is what it is attached to and
who may use it. The intangibility verb seen earlier in this chapter is
attached to a mob and accessible to the mob's player alone. You can use your
own intangibility verb and other people can use their own intangibility verbs,
but you can't use each other's verbs. If you could, it would be possible to
turn each other intangible.
Of course, in some cases, you might actually want people to be able to use
each other's verbs. To do that, you need to override the default
accessibility settings. Before we get into that, you need to understand how
the defaults work.
When a verb is attached to a mob, the default accessibility setting is
Here is a commonly used verb which allows people to turn each other into
potatoes.
Instead of the default accessibility (
Also note that in this example an underscore was used in the name of the
verb. This will be automatically converted into a space in the name of the
command. However, when the user types it in, a `-' will be inserted on the
command line instead of a space. That is because spaces are only allowed on
the command line between arguments or inside of quotes. The user doesn't
have to worry--the substitution of a dash happens automatically.
Consider instead a verb that is attached to an obj.
The verb
Try this example on a suitable map with some torches scattered about. If
you move up to a torch and type "extinguish torch" it will go
out (see figure 4.5).
You need not worry about players having to deal with typing lengthy
commands. Dream Seeker provides many convenient ways to ease the burden
on the users' fingers. For example, there are several methods for
a player to access the aforementioned
You may have noticed a subtle difference between the
Suppose one practices a religion in which praying must be done in the
vicinity of a torch. We don't want the command to be "pray torch"
but just "pray". In other words, we want an implicit source, not
an explicit one.
Whether the source syntax is implicit or explicit depends on how the
src setting is specified. If src is assigned (e.g.
Return to the example of torch enabled prayers. Since we want an implicit
source, we use = to assign the source rather than in, which
would merely limit it.
In general, one uses an implicit source when the mere presence of an object
gives the user some ability that is otherwise independent of the source
object. Another case (like
For convenience, verbs attached to different object types have different
default accessibilities. These are summarized in figure
4.6.
Note that the default obj accessibility is really an abbreviation for
In the case of both turf and area, the default accessibility is
Making use of this convenient default, suppose we wanted a dark area to have
a magical trigger that would turn on the lights at the sound of clapping
hands. You could do it like this:
Abracadabra!
There are a limited number of possible settings for a verb's source access
list. They are compiled in figure 4.7.
Two of these (namely, usr and usr.loc) are not lists of
objects but instead refer to an individual item. For that reason, they
behave a little differently when used in an assignment versus an in
clause. Don't let that confuse you--it's really quite simple. When used in
an assignment, they are treated as a single object. When used with
in they represent the list of objects that they contain.
The rest of the src access settings are all lists. The view
instruction has already been mentioned, but it requires a little more
description so that you can understand the related oview
instruction.
The view() list contains all objects seen by the user up to a
specified distance. The list starts with objects in the user's inventory,
followed by the user herself, objects at her feet, then in neighboring
squares, and so forth proceeding radially outward. A distance of 0
therefore includes the turf (and area) the user is standing on and its
contents. A distance of 1 adds the neighboring eight squares and their
contents. The maximum distance is 5, since that includes the entire visible
map on the player's screen. (You will see how to change the map
viewport size in chapter 14.) Because this is often the desired
range, it is the default when no range is specified. The special range of
-1 includes only the user and contents.
The related instruction oview() stands for `other' or `outside'
view. It is identical to view() except it doesn't include the usr
or the usr's contents. In other words, it excludes objects in
view(-1), the so-called private or personal range.
As an example of using usr and usr.loc, consider a pair of
verbs to allow picking up and dropping objects.
To see how oview() might come in handy, suppose there was a magical
torch that one could summon from a greater distance than provided by the
standard
Making use of the default range, torches can be summoned from anywhere in
the player's view. If we had used view() instead of
oview(), objects already inside the user's inventory could be
summoned, which wouldn't make much sense.
The variable names follow the same rules as everything else in the
language. Case matters, and it may consist of letters, numbers, and the
underscore.
The possible input types are listed in figure 4.8.
The first group are the constant input types. They all represent
different types of data that the user can insert. They may be used
individually or in combination. To combine several types, put
| between them like this:
icon|sound.
The text input type accepts a short (one-line) string from the
player. For a longer composition, the message input type is used.
Numbers are handled by the num input type. These, just like numbers
in the language, may be positive or negative, integer or floating point, and
may even be specified in scientific notation.
There are three input types for resource files: icon,
sound, and file. The last one, file, will take
any type of file as an argument, whereas the other two take only icons and
sounds, respectively. The related input type key takes a key entry
from the player and is only used in obscure situations.
The null input type is used in conjunction with other types. It
indicates that the argument is optional. Otherwise, the user is required to
enter a value before executing the command.
The last group are the object input types. They are used to allow the
player to select an item from a list of objects. More will be said on lists
of objects in section 4.8. By default, the list is composed of
all objects in view of the player.
Using the various input types, it is possible to compose verbs that give the
player control over his own appearance. For example, using the text
input type, the name can be specified.
In the client, one could therefore enter a command like the following:
Notice in this example that the help text for the verb has been defined.
First the syntax is described in parentheses and then the purpose of the
command is stated. (The reason there are backslashes in front of
the double quotes inside the text is to prevent them from being mistaken for
the end of the description. This is called escaping and will be
discussed in more detail in section 11.3.2.) If you position the
mouse over the verb, the help text will be displayed. It will look
something like this:
If we had not specified the syntax help (in parentheses), it would have
given a generic description of the syntax like this:
Each type of argument has a different default appearance. Generally
speaking, it involves the name of the input type. If you think that will
confuse the players, override it with your own text.
As a slight variation on the previous example, we could make a scroll object
on which one can write a message.
Notice that players must be within arm's reach to inscribe a message. We
assume that everyone has good eyesight so the complementary
It is amazingly simple to do for the player's icon what we just did for the
description. Here is a verb that does the trick.
The command on the client could be issued something like this:
Here, single quotes surround the file name. As with text arguments, the
final quote is optional when there are no additional parameters.
The simplicity of the
Speaking of multi-media, here is an example that makes use of the sound
input type.
This plays a sound file (either wav or midi) to everyone
in view. The << operator in this context is used to
send output to a mob or list of mobs. In this case, everyone in the list
computed by the view() instruction receives a sound file. (To be precise, only those people who need a copy of the sound file will
receive it. If they don't have sound turned on or if they already have the
file, it won't be transmitted.) If their machine is capable of playing
sounds and their client is configured to allow it, the sound will
automatically play for them. Not bad for two lines of code!
The output operator << opens up all sorts of
possibilities. For example, you can say things.
Usually, however, you would want some indication of who is doing the
talking. To do that, you need a new piece of magic called an embedded text
expression. It allows you to display text containing variables.
In this example, the variables usr and
We can now make use of the object input types. For example, you can wink at
people with the following verb.
The possibilities for intrigue and secrecy increase with a covert version of
the
This example uses two arguments to achieve its purpose. The first one is
the target of the message. The second is the text to transmit.
If you are paying close attention, a thought may have occurred to you.
Couldn't these verbs that take an object as an argument be written using that
object as the source rather than an argument? The answer is yes. For
example,
Instead of taking a mob as an argument, this verb defines a public verb on
mobs that is accessible to others in view, allowing them to wink at the
mob. From the user's point of view, these two cases are identical. From
the programmer's view, however, it is sometimes more convenient to use one
technique over the other.
Suppose you wanted to make a special type of mob that when winked at would
reveal a magic word. In that case, the best way to do things would be to
have the target of the wink be the source of the verb. Then you can
override the wink verb for the special mob type like this:
When winked at, the guard mob whispers back the magic word. Notice the line
that executes the .. (dot-dot) procedure. That is a special name that
corresponds to the previous (inherited) version of a verb (called the
parent or super verb). This saved us from having to rewrite
the line that generated the wink output. That is what is meant by re-usable
code in object-oriented programming. With complicated procedures it can
save you a lot of trouble.
If, instead, we had used the original version of
In a different situation, the reverse might be the best strategy. For
example, you might want a special mob who kills people by winking at them.
(If looks could kill...)
To do the nasty deed, we used the del instruction, which deletes an
object. In this case, we have assumed the existence of the first definition
of
Of course you might have even more complicated scenarios in which you want
to do both variations--that is, having code specific to the type of target
and the user. It can still be handled without violating good
object-oriented design, but you would need some tools I haven't fully
described yet. (For example, you could define a second procedure that
carries out a mob's response to being winked at and invoke that from within
a private
However, don't get too carried away trying to blindly adhere to
object-oriented or any other philosophy of code design. At the root of all
such theories is the basic and more important principle of keeping things
simple. The simpler things are, the less likely you are to make mistakes
and the easier it is to fix the errors you do make.
The reason the object-oriented approach tries to confine code about an
object to that object is ultimately just organizational. When you want to
change the magic word spoken by the guard, you know where to go in the code
to do it. And more importantly, if you want to change the guard to an elf,
you don't have to remember to also go and modify the wink verb to make elves
speak the magic word rather than guards--a seemingly unrelated task.
But such possibilities are hypothetical and should not take precedence over
your own knowledge about what future developments are actually probable. In
some situations, the simplest structure might be to confine all code having
to do with winking to one place--a single wink verb that handles every
special case. That would be procedure-oriented programming, an aged
methodology (though tried and true). But who cares what the theory is. Get
the job done with clear, concise code. That's what matters in the end.
(Of course every true programmer knows that there is no such thing as an
end. At best there is a level of completeness that one approaches
asymptotically. At worst ... well, never mind the worst, those dark
skeletons, cadaverous parasitic programs that suck at the soul until one
yields again, hammering out another thousand lines of tangled spaghetti code,
writhing like a nest of tapeworms, and long sleepless nights turn into
weeks, years, and still no sign of completion! Or so I am told. Being one
of the cheery daytime programmers, in bed before midnight and up to milk at
dawn, I wouldn't know whether such horror stories are true. If it happens to
you, I can give a few pointers on keeping a cow.)
Notice how in the previous section, there was a slight asymmetry in the two
versions of
As it happens, arguments can be limited in much the same way as the source
of a verb.
For example, here is a verb for prodding your neighbor.
The use of the in clause in the argument definition limits the user's
choice to mobs in neighboring positions. You can use any list
expression to define the set of possible values. The most common ones are
those available for defining the range of a verb source (section
4.3.3). When no in clause is used, the default list for
mob, obj, turf, and area input types is
view().
For example, here is a verb to communicate (by frequency modulated
electromagnetic waves) with any other player in the game.
Actually, world is an individual object, but in this context it is
treated as a list and is therefore an abbreviation for
world.contents, a list of every object in the game.
If a default value is specified, the null input type is
automatically applied, since that is necessary to make the argument optional.
This example defines a verb that controls the player's density. If no
arguments are given, the mob will be made dense; otherwise the value
specified by the player will be used.
1. Defining a Verb
mob
verb
intangible()
density = 0 //now we can walk through walls!
intangible
. A player who has
executed this command can walk through other dense objects like walls.
2. Setting Verb Properties
obj/lamp/verb/Break()
set name = "break"
luminosity = 0
3. Verb Accessibility
set src = usr
. That means the source of the verb must be equal to
the user of the verb. Nobody else is allowed to use it (or even see it).
This statement makes use of two special pre-defined variables. The variable
src refers to the object containing the verb--that is, the source
object. The variable usr refers to the mob (of the player) who is
using the verb.
mob/verb/make_potato()
set src in view()
name = "potato"
desc = "Mmm. Where's the sour cream?"
icon = 'potato.dmi'
src = usr
) this verb uses
src in view()
. That means anyone within view of the user can be
turned into a potato. The view procedure computes a list of
everything which is visible to the user.
obj/torch/verb/extinguish()
set src in view(1)
luminosity = 0
extinguish
in this example causes a torch to stop shining. It
again makes use of the view instruction, but this time an
additional parameter is specified to limit the range. In this case, the
range is 1, so the torch must be in the user's turf or an adjacent one for
the verb to be accessible. Somebody standing across the room will not be
able to extinguish the torch.
Figure 4.5: Look Ma, no hands! (and other ways to avoid typing...)
extinguish torch
verb:
extinguish
" entry in the on-screen verb
panels.
extinguish
verb may be selected.
extinguish
verb
and the intangible
verb seen earlier. In one case we just had to type
"intangible" and in the other "extinguish torch". In the
first case we didn't have to specify the verb source and in the second case
we did. The term for this difference is an implicit versus an explicit
source.
3.1 Explicit versus Implicit Source
set src=usr
or even set src=view(1)
) the computer
automatically picks the source from the available possibilities. On the
other hand, if src is not assigned but just limited to anything in
a list (e.g. set src in view(1)
) it is up to the user to specify the
source--even if there is only one choice. This gives the designer control
over the command syntax.
obj/torch/verb/pray()
set src = view(1)
//God fills in this part!
set src=usr
) is when the source object
is always unique. Verbs in this latter case are called private verbs
because they are only accessible to the mob itself.
3.2 Default Accessibility
Figure 4.6: Default Verb Accessibilities
mob src = usr
obj src in usr
turf src = view(0)
area src = view(0)
src in usr.contents
, which means the contents (or inventory) of the
user's mob. As you shall see later on, the in operator always treats
the right-hand side as a list--hence usr is treated as
usr.contents in this context.
view(0)
and is implicit. Since the range is zero, this gives the
player access to the verbs of the turf and area in which the mob is standing.
area/dark/verb/clap()
luminosity = 1
3.3 Possible Access Settings
Figure 4.7: Possible Source Access Settings
usr
usr.loc
usr.contents
usr.group
view()
oview()
obj/verb
get()
set src in usr.loc
loc = usr
drop()
set src in usr //actually this is the default
loc = usr.loc
get
verb.
obj/torch/verb/summon()
set src in oview()
loc = usr //presto!
VerbName(Var1 as Type1,Var2 as Type2,...)
5.1 Parameter Input Types
Figure 4.8: Parameter Input Types
text
message
num
icon
sound
file
key
null
mob
obj
turf
area
anything
mob/verb/set_name(N as text)
set desc = "(\"new name\") Change your name."
name = N
set-name "Dan The Man
usage: set-name "new name" (Change your name.)
usage: set-name "text" (Change your name.)
obj/scroll/verb
write(msg as message)
set src in view(0)
desc = msg
read()
set src in view()
usr << desc
read
command works as long as the scroll is within view.
mob/verb/set_icon(i as icon)
set name = "set icon"
icon = i
set-icon 'me.dmi
6. Generating Output
set_icon
verb hides the power behind it. Think
about what happens when you use it. You enter the name of an icon file
through the client and it magically appears on the map. In a game running
over the network with multiple users, it works just the same. Behind the
scenes, the file you specify gets transported to the server, which then
automatically distributes it to all the other clients. Transmitting
multi-media files across the network is an elementary operation in DM,
little different than entering some numbers or text.
mob/verb/play(snd as sound)
view() << snd
mob/verb/say(msg as text)
view() << msg
6.1 Variables in Text
mob/verb/say(msg as text)
view() << "[usr] says, '[msg]'"
msg
are substituted
into the text before it is displayed. The result could be something like
"Ug says, 'gimme back my club!'". As you can see, the brackets
[ ] inside of the text are used to surround the variables. Such a
construct is called an embedded expression. It is buried right inside the
text but it gets replaced at run-time by its value. More details will be
revealed on that subject in section 11.3.
mob/verb/wink(M as mob)
view() << "[usr] winks at [M]."
say
command.
mob/verb/whisper(M as mob,msg as text)
M << "[usr] whispers, '[msg]'"
7. Flexibility in Choice of the Source
wink
could be rewritten like this:
mob/verb/wink()
set src in view()
view() << "[usr] winks at [src]."
mob/guard/wink()
..()
usr << "[src] whispers, 'drow cigam!'"
wink
which had the
target mob as an argument, we would have had to insert code in the general
wink verb to check if the target was a guard and act accordingly. In
general, good object-oriented design attempts to confine code that is
specific to a particular type of object inside the definition of that
object. This was achieved in the above example by making the target the
source of the wink verb.
mob/DM/wink(M as mob)
set desc = "This kills people, so be careful!"
..()
del M //poof!
wink()
which takes a mob argument. By organizing things this way,
we were able to isolate the special code to the object it applied to, in this
case the DM.
wink
verb.)
8. A Choice of Arguments
wink
. In one case the target was a mob argument and in the
other it was the source. In the latter case, we specified that the source
could be anywhere in view of the user, but in the case of the argument we
never said anything about the range. What if we wanted to restrict winking
to a shorter distance in that case?
VerbName(Var1 as Type1 in List1,Var2 as Type2 in List2,...)
mob/verb/poke(M as mob in view(1))
view() << "[usr] pokes [M]!"
mob/verb/commune(M as mob in world,txt as text)
M << "[usr] communes to you, '[txt]'"
mob/DM
verb
set_density(d=1 as num)
set name = "set density"
density = d