Addendum for BYOND 3.0

Since the time of its publication, the DM language has been under active development. Fortunately, the core syntax of the language is unchanged. A few aspects of DM have been extended and generalized, and new features have been added for ease of use and in order to accomplish things that were not possible before.

This addendum covers the most noteworthy changes and additions that have been made since the first edition of the Guide, which comprehensively covers BYOND 2.0--still the fundamental core of the DM language.


Contents

Changed Behaviors
Topic URLs
client/Import()
Del()
visibility
view
New Features
atom, datum, and parent_type
Named Arguments
Mouse Interaction
Screen Objects
Pixel-Level Graphics
View Size
Drawing Layer
Vision
Icon Manipulation
BYOND Hub
client.CheckPassport
Modified Types
Resource File Transmission
Index of Changes

Changes

A few minor syntax changes had to be made in order to improve the language. In most cases, the old syntax is still accepted, but in a few cases, the compiler will issue a warning and recommend the use of the new preferred syntax. These changes are discussed in the following sections.

URL syntax

Hyperlinks may be embedded in text so that when the user clicks on them, Topic(href) gets called (page 78 section 7.6). Previously, the "href" text that got submitted back to client/Topic() was specified in the hyperlink using '#' as the delimiter like this:

" click here "

The preferred syntax is now to use '?' in place of '#':

" click here"

This has proven to be a better standard now that DM can be used to create pure web applications (see BYOND web programming).

In addition to that minor change, better support has been added for multi-valued href parameters. Previously, it was up to the programmer to parse the href text in Topic() and extract multiple values that might be packed together there. Now the href text is automatically passed through params2list() and the result is provided as an additional argument to Topic(href,href_list[]).

In order to take advantage of that, all you have to do is use the standard form for "query" URLs. The portion after the '?' (the "href" portion) has the following "key=value" form:

"key1=value1&key2=value2&..."

In DM, the '&' may be used interchangeably with ';' as the delimiter, since this is also the new recommended standard on the web.

The final change to preferred URL syntax is in how the "src" of Topic() is encoded in the href text. Previously, the object intended to handle the Topic() call was embedded directly at the beginning of the href text like this (page 78 section 7.6):

"#\ref[Object]..."

Now, it may be passed anywhere in the href text, using the new key=value parameter list syntax:

"?key1=value1&...&src=\ref[Object]&..."

As before, if no src is specified, client/Topic() is expected to handle it. Otherwise, the default behavior of client/Topic() is to call the specified object's Topic() procedure.

It is worth mentioning that one very handy way of generating these key=value text strings is to use list2params(). It now automatically applies \ref to object values, so things such as the following are possible:

mob/verb/test()
   var/href[0]
   var/url

   href["src"] = src  //call my Topic()
   href["data"] = ...

   url = "byond://?[ list2params(href) ]"
   usr << "Click  here  to win!"

client-side savefiles

The procedures client.Import() and client.Export() may be used to store data on the player's computer for possible shared use by different worlds (page 139 section 12.5). These procedures have been generalized to handle other things, including files stored centrally in BYOND hub for shared use by multiple people (see hublib).

In order to support arbitrary file types, a slight change had to be made to the old behavior in which Import() returned an open savefile. It now simply returns a reference to the file data, which can then be opened as a savefile like this:

var/savefile/F = new(client.Import())

That makes it possible to store any type of file; it used to only work with savefiles.

Del()

The Del() procedure (page 73 section 7.2.2) has changed in the way it treats the contents of the object being deleted. Previously, it dumped these objects to the location of the container object. It now simply deletes these objects. It is a simple matter to achieve the old behavior if that is indeed desired:

mob/Del()
   var/O
   for(O in contents) O:Move(loc)
   return ..()

visibility

The visibility variable (a true/false value) has been replaced by one called invisibility, which has a range of 0 to 100. Old code continues to work, but conversion is recommended. See vision for more details.

view

The view() instruction used to ignore any special visual capabilities (or incapacities) of the mob, and it ignored invisibility of objects altogether. It now takes these into account. To get the old behavior, simply do view(usr.loc) instead of view(usr). See vision for more information.


New Features

A number of important features have been added to the DM language. The intention was to freeze development for a while after BYOND 2.0 came out, but nothing could be further from what actually took place!

atom, datum, and parent_type

From the standpoint of elegance, the most important development has been the addition of object types that bring together all of the built-in DM objects.

Since the atomic objects /area, /turf, /obj, and /mob are all defined at the "top" of the inheritance tree, a new construct had to be invented to allow all of these to share a common ancestor. This is a variable named parent_type. It allows an object type to be derived from some other point in the type tree.

This naturally lead to the creation of various "ancestors" in the type tree. The new entries are listed below:

datum  //ancestor of all objects

atom   //ancestor of all atomic objects
   parent_type = /datum

atom/movable //ancestor of movable objects

area
   parent_type = /atom
turf
   parent_type = /atom
obj
   parent_type = /atom/movable
mob
   parent_type = /atom/movable

All object types at the top level are implicitly derived from /datum unless parent_type is pointed to something else. In the code above, therefore, the statement atom/parent_type = /datum is actually redundant.

Of course, types at lower levels of inheritance are still derived from the type "above" them, just like they used to be, unless parent_type is applied. For example, there was no need in the above code to make the statement atom/movable/parent_type = /atom.

The upshot of all this is that you can add properties to all objects, all atomic objects, or all movable objects by simply defining new procedures or variables in the ancestor object types. Previously, one sometimes had to resort to defining the same procedure once per atomic object type, which was silly.

It also allows you to create new atomic objects that behave as "siblings" of the built-in ones. For example, you might want to have separate /player and /monster types:

player
   parent_type = /mob
monster
   parent_type = /mob

In general, this allows you to choose between the hierarchical type tree and a more flattened out approach with more top-level or near top-level types.

Named Arguments

Another important advance in DM syntax since BYOND 2.0 is the addition of named arguments. The normal method of passing arguments to a procedure is to use positional arguments. However, procedures with many independent optional arguments can become rather awkward to use.

The solution is to pass the arguments by name rather than by position. In general, you may pass any number of positional arguments first (typically the required ones) followed by any number of named arguments.

A good example of this is the image() procedure. It used to just take an icon and a location for the purpose of displaying a particular icon to selected users. It now takes additional arguments, allowing you to override the default icon state, drawing layer, and direction.

mob/var
   image/shield_image

mob/verb/shields_up()
   shield_image = image('shield.dmi',loc = usr,icon_state = "high power")
   usr << shield_image

mob/verb/shield_off()
   del shield_image

As you can see, the named arguments are passed by simply assigning the name of the parameter to the value you wish to pass. They may be passed in any order, since the name rather than the position is used to identify the argument.

Mouse Interaction

A significant amount of extra mouse control has been added. In BYOND 2.0, just Click() and DblClick() were defined. Now there is support for drag-and-drop, custom mouse cursors, pixel-level clicking, mouse-over detection, and extra mouse "opacity" control.

The reference contains a good overview of all of the mouse-related features.

Screen Objects

One of the best developments since BYOND 2.0 allows for much greater freedom in the graphical interface. You can create objects that appear in and around the map display in Dream Seeker, such as toolbar objects, graphical stats, and fancy frames. See screen.

In addition, a couple variables have been added to allow you to turn off aspects of Dream Seeker's interface that you do not want visible. See show_verb_panel and show_map.

Pixel-Level Graphics

BYOND now allows objects to have pixel offsets. This means that they need not be confined to a single-tile, as in previous versions. This is strictly a visual effect, but it can greatly improved the graphics. See pixel_x and pixel_y.

View Size

The map view size may now be set on a player-by-player basis and it is no longer restricted to being square. For example, the following sets the default view size to 17x13:

world/view = "17x13"

See client.view and world.view for more information.

Drawing Layer

The layer in which an object's icon is drawn used to be fixed by the type of object, but it is now configurable via the layer variable. This allows for nifty effects such as turfs with "arch" overlays that appear over the top of people as they walk underneath.

See layer in the DM Reference for details.

Vision

A number of extra controls have been added to the vision system, including a full range of invisibility levels, infravision, night vision, independent verb visibility, and a choice between "mob" and "eye" perspectives in the player's view.

More information:

As noted already, view() has been modified to take mob visual capabilities into account, which is consistent with how it works in the player interface. If client.eye is not the same as client.mob (often true when using client.lazy_eye), this still might result in a different list of objects than what are truly visible to the player. You can take client.eye and other client-specific settings into account by doing view(usr.client) rather than just view(usr).

To get the old behavior in which view() ignored visual capabilities of the mob, simply do view(usr.loc) instead of view(usr), however, in most situations like that, you would probably want to use the new procedures viewers() or hearers(), which take into account the ability of other mobs to perceive the center mob, rather than the ability of the center mob to perceive the others.

Icon Manipulation

A new /icon object type has been added. This may be used to load icon data into memory for direct access and manipulation. This makes it possible to dynamically modify colors for multi-player games and a host of other effects. See /icon in the DM Reference.

BYOND Hub

DM contains built-in features that allow you to easily link up to a centralized database known as BYOND Hub. It is by no means a requirement that this be used, but it has turned out to be an enormously important capability.

You must register your world with BYOND Hub to take advantage of the hub features. Your game is then identified by a "hub path" of the form YourKey.GameTitle. This text string is case insensitive, and all punctuation and spaces except for "." are also not significant.

By assigning world.hub to the hub path of your game, you make it possible for players to easily broadcast announcements of live games to other viewers of the hub. A system of channels exists in the hub, allowing a game to be published to different audiences, and the default channel(s) in which live games are broadcast automatically conforms to the publication settings and, of course, the user's membership in the channel itself.

client.CheckPassport()

The hub also provides a subscription database. You can configure your hub entry to support BYOND Passport, in which case, users who subscribe (or who you invite), can be identified in a game by doing a passport check.

When you enable BYOND Passport, a master passport ID is assigned to you. You simply pass that to client.CheckPassport() to find out if a user has a subscription:

mob/var
   full_access

mob/Login()
   if(client.CheckPassport("0123456789abcdef"))
      full_access = 1
   else
      usr << "For full access, subscribe!"
   return ..()

This is a very versatile mechanism, since you can choose to do whatever you want in response to a subscription. It's also possible to distribute software directly through the hub and, of course, that gives you the additional option of limiting who may download the game based on subscription, a more traditional approach to paid software usage.

Modified Types

Another generalization of DM syntax is the addition of modified types. Anywhere that you can use a type value in DM (shuch as in new() or newlist()), you can make simple initializations of variables using the following syntax:

path {var1 = val1; var2 = val2}

Example:

mob/contents = newlist(
   /obj/scroll/readme {
      name = "Introduction"
      desc = "The fate of Bracolia depends on you ..."
   }
)

This syntax is the same as that used in .dmm files for object instances that are edited in the map editor. As stated, these initializations must be "simple" expressions, but, in general, DM's definition of a "simple" initialization has expanded quite a bit since BYOND 2.0. For example, it now supports initialization to a new object or list.

Resource File Transmission

Another major area of development since BYOND 2.0 has been an improvement in the resource file transmission system. Icon and sound files can be downloaded by Dream Seeker on demand, all at once, or some combination of the two. It is also possible to create resource packs that are distributed from a web server, rather than from the game server itself, saving bandwidth on the machine hosting the game.

All of this is accomplished through a variable called client.preload_rsc, which you can read about in the DM Reference.

Index of Changes

All changes of note to the DM Reference since BYOND 2.0 are listed below:

DM
garbage
icon
mouse
pointers
__MAIN__
atom
movable
proc
var
animate_movement
pixel_step_size
screen_loc
proc
Entered
Exited
MouseDown
MouseDrag
MouseDrop
MouseEntered
MouseExited
MouseUp
var
infra_luminosity
invisibility
layer
mouse_drag_pointer
mouse_drop_pointer
mouse_drop_zone
mouse_opacity
mouse_over_pointer
pixel_x
pixel_y
client
proc
CheckPassport
Export
Import
MouseDown
MouseDrag
MouseDrop
MouseEntered
MouseExited
MouseUp
SendPage
Topic
var
CGI
authenticate
command_prompt
command_text
default_verb_category
images
lazy_eye
mouse_pointer_icon
perspective
pixel_step_size
preload_rsc
screen
show_map
show_verb_panel
view
datum
icon
proc
Blend
Flip
IconStates
New
SetIntensity
Shift
SwapColor
Turn
image
mob
var
see_in_dark
see_infrared
see_invisible
sight
operator
>
<
proc
ASSERT
CRASH
alert
arccos
arcsin
arglist
arguments
named
browse
browse_rsc
cos
fcopy_rsc
fexists
hearers
image
input
ispath
istype
list
pick
roll
sin
time2text
typesof
view
viewers
savefile
proc
ExportText
ImportText
Lock
Unlock
verb
arguments
set
category
invisibility
popup_menu
world
proc
Export
GetConfig
IsBanned
OpenPort
SetConfig
var
byond_version
cache_lifespan
executor
hub
log
status
system_type
url
view
visibility