The value of the CLASS attribute may contain a list of classes separated by
spaces. This permits client output to be in the 'system' class as well as
more specific ones. That allows you to change all of these colors in one
shot if you are too lazy to change them each individually. For example, if
you define a style sheet that changes the background color, you might need to
redefine the various foreground colors like this:
In this example, the background color of the terminal will be aqua, normal
text from the server will be black, and all output from the client will be
bold and red, except echoed commands and expansion lists, which will be bold
and green. The more specific .command rule is placed after the general
.system rule so that its color takes precedence. This is how style sheets
are composed--you write general rules first followed by any exceptions.
The order in which rules are specified is one of the factors that determines
precedence of style sheet commands. The language is known as Cascading Style
Sheets because of its ability to handle several layers of stylistic rules,
intermingling the configurations of the user and the designer in an ordered
fashion.
Rules are selected by first finding all matching candidates for a given
attribute in the current HTML tag being processed. If there is more than
one, rules from a higher level style sheet take precedence over lower level
ones. That means the basic user configurable settings in DreamSeeker are
the lowest priority, followed by a style sheet in the user's
.dms
script file, followed by a style sheet from the designer's
client.script
setting, because that is the order in which these
are read by the style sheet manager.
Rules from the same style sheet are ordered by specificity. The selector
SPAN.chat
is more specific than .chat
and
.chat EM
is more specific than EM
. In general,
the more classes referenced by a selector, the more specific it is. When
that results in a tie, the selector with the greater number of tags takes
precedence.
If two rules about the same attribute come from the same sheet and have the
same specificity, the final one to be defined takes precedence.
In the rare event that a rule needs to break out of the normal order of
precedence, it can be flagged as important. In this case it will take
precedence over all other "unimportant" rules. However, if more than one
rule is important, the normal rules of precedence will be used to resolve
the conflict.
In the above example, only the background color is important, not the font
specification.
Style commands may also be inserted directly in an html tag to control
its appearance. This does not have the advantages of style sheets, which
separate content from presentation, but it does allow you to use the style
sheet syntax when formatting text.
tags (text)
- See also:
- entities (text)
- macros (text)
- style sheets
- text
Text tags (also known as elements by snooty HTML purists) control
how the text is formatted. HTML syntax is used, so all tags start with
<
and end with >
. The tags which are
currently supported by Dream Seeker, are listed below:
<A></A> // anchor (hyperlink)
<ACRONYM></ACRONYM> // acronym or abbreviation
<B></B> // bold text
<BIG></BIG> // one size bigger text
<BODY></BODY> // body of html document
<BR> // line break
<CITE></CITE> // citation reference
<CODE></CODE> // program source code
<DFN></DFN> // definition
<DIV></DIV> // used in conjunction with style sheets
<EM></EM> // emphasized text
<FONT></FONT> // font face, color, and size
<H1></H1> // heading level
<H2></H2>
<H3></H3>
<H4></H4>
<H5></H5>
<H6></H6>
<HEAD></HEAD> // document head section
<HTML></HTML> // html document
<I></I> // italic text
<IMG></IMG> // display icons
<KBD></KBD> // keyboard input
<P></P> // paragraph
<PRE></PRE> // pre-formatted text
<S></S> // overstrike text
<SAMP></SAMP> // sample output
<SMALL></SMALL> // one size smaller text
<SPAN></SPAN> // used in conjunction with style sheets
<STRONG></STRONG> // strongly emphasized text
<STYLE></STYLE> // contains a style sheet
<TITLE></TITLE> // document title
<TT></TT> // typewriter style
<U></U> // underline
<VAR></VAR> // variable name
<XMP></XMP> // preformatted (tags ignored)
In addition to these, the <BEEP>
tag, which is not
standard HTML, may be used to beep the terminal.
Some tags take additional parameters, known as attributes. The most common
ones are <FONT>
and <A>
.
The syntax for these is illustrated by the following two examples:
"How about this!"
"Click here!"
As many attributes may be specified as desired. The attribute value may
have quotes around it, but this is only necessary if the value contains
spaces. It is usually more convenient to use single quotes so you don't have
to escape the double quotes, but you can also embed the HTML in a
text document to avoid the need for escaping quotes.
Text colors may be specified by name or RGB value. The named colors and
their corresponding RGB value are listed in the following table:
The hexadecimal colors above are written with 8 bits (two hex digits) for
each color. It is also possible to use 4 bit values by using only one hex
digit per color. The full 8 bit color is produced by repeating each digit.
For example, #F00
(red) is the same as #FF0000
.
Text sizes range from 1 to 7, 1 being the smallest and 7 being the largest.
In addition to absolute sizes, relative sizes may be specified (like +1 for
one size bigger or -1 for one size smaller).
animate_movement var (movable atoms)
- See also:
- Move proc (movable atom)
- glide_size var (movable atoms)
- Gliding
- Default value:
- FORWARD_STEPS (1)
- Possible values:
- NO_STEPS (0)
- FORWARD_STEPS (1)
- SLIDE_STEPS (2)
- SYNC_STEPS (3)
Deprecated. This setting has no impact when used with pixel
movement. See Gliding for more details.
Setting this to 0 causes movement between two adjacent positions to be
displayed as a single discrete jump. Otherwise, objects will be made to glide
from one position to another, using the movement animation defined in the icon
file if one is defined.
By default, movement animation avoids cutting corners, since this can look
very bad in some games. If you want objects to take the shortest (and
smoothest) visual path when moving around, use SLIDE_STEPS instead of the
default FORWARD_STEPS. This also allows the object to be facing in a
different direction than it is moving, so make sure this is what you want.
SYNC_STEPS is intended for objects that move in unison as part of a larger
"conglomerate" object. You should set the movement animation to SYNC_STEPS on
all but a single "head" object, which will serve as the leader when choosing
pixel step sizes. If you do not use SYNC_STEPS, there are cases where the
pixel offsets of objects may get out of sync during motion, causing the object
to visually break up.
glide_size var (movable atoms)
- See also:
- animate_movement var (movable atoms)
- glide_size var (client)
- pixel_x var (atom)
- pixel_y var (atom)
- icon_size var (world)
- fps var (client)
- Gliding
- Default value:
- 0
This setting has no impact when used with pixel movement. See
Gliding for more details.
This controls the number of pixels an object is moved in each footstep
during animated movement. The default value of 0 chooses automated control
over this value, which generally results in a minimum footstep of 4 pixels
that is increased when necessary to keep up with motion on the turf grid.
Decimal values are allowed.
Be careful about using small glide sizes. Icons with high contrast
pixel-level detail can look pretty ugly when displaced by short distances.
The glide size is measured in server ticks. If you use a different client
tick rate by altering client.fps
or client.tick_lag
,
the actual glide used will be scaled appropriately. E.g., if your
client.fps
is 4 times greater than world.fps
, the
actual glide amount each client tick will be glide_size/4
.
This was renamed from pixel_step_size.
screen_loc var (movable atoms)
- See also:
- HUD / screen objects
- layer var (atom)
- screen var (client)
- view var (client)
- map_format var (world)
This is a text string that controls where an object that is listed in
client.screen will appear on the user's screen. The format is:
"x,y"
"x1,y1 to x2,y2"
The bottom left corner of the map viewport (southwest) is "1,1".
If the view is 11x11, then the top-right corner (northeast) is
"11,11". (Changing world.map_format
may change the range for screen_loc.)
A range of coordinates (the second format above) causes a square region to
be filled with the object at each position. The southwest and northeast
corners of the box are indicated in the screen_loc value.
Special keywords
The edges of the map may also be referenced by using directions, such as
"3,NORTH"
. For convenience, the order of coordinates is arbitrary
when using directions, so one may specify y before x as
in "NORTH,WEST"
. In expressions such as the latter, you may also
leave out the comma. Icon size is not taken into account, so a big icon with
a screen_loc of "SOUTHEAST"
will extend further to the right and
may create a border (see "Outside the map" below).
The CENTER keyword can also be used. This can be used alone to completely
center the object, or as either the x or y component. If the map covers an
even number of tiles in either direction, pixel offsets will be applied
automatically. Centering is relative to the regular map edges, and it does
not take the icon's size into account.
The LEFT, RIGHT, TOP, and BOTTOM keywords (also TOPLEFT, TOPRIGHT,
BOTTOMLEFT, BOTTOMRIGHT) can be used to anchor a screen object to the edge of
the map control if the map is zoomed in so that some pixels are cut off. When
you use these edge-alignment keywords, the icon size is taken into
account, and the alignment of the icon changes to fit whichever edge you use.
Because these keywords do not conform to the normal tile-based structure of
the HUD, they can't be used for a range of tiles with the "to"
format.
(Note: Letterboxing, the blank space to either side of the map if it doesn't
take up the whole map control, is not considered usable space. HUD objects
aligned to the control edge appear inside any letterboxing, not on top of it.)
Outside the map
In addition to objects inside of the map view, one may create border
objects. Borders are automatically created when screen objects are placed at
coordinates outside of the inner map view. For example, objects placed at y=0
fall on a border directly below the map and y=-1 is one tile below that. (The
CENTER keyword is based on normal viewport bounds and not any extra borders.)
A big icon placed towards the northeast end of the map, if it spills over
the edge, will create a border big enough for the whole icon to be shown. You
can avoid this by using the TILE_BOUND
appearance flag. Transforms on this atom are not taken into account when
determining whether to add a border.
Offsets
Offsets may be applied to screen_loc coordinates. For example,
"NORTH+1,WEST"
is in a border above the map.
"CENTER+2,CENTER-1"
will appear 2 units right, 1 unit down from
the center of the map. Non-integer offsets like 1.5 are allowed; the
fractional part will be counted towards a pixel offset.
Offsets may be specified in percentages as well. These effectively always
count as pixel offsets and will never be used to determine if a border should
be added. "WEST+100%"
and "100%"
are basically
identical to "EAST"
in most respects, and "WEST+50%"
is basically the same as "CENTER"
. If you're using the edge
keywords (LEFT, TOP, etc.), this percentage is relative to the control edge
and also factors in the icon size, so "LEFT+100%"
is equivalent
to "RIGHT"
.
It is also possible to specify a pixel offset. Screen objects do not use
pixel_x and pixel_y for this purpose, because it is intended that an object
could exist on the map and in the screen object list simultaneously, so
positioning must be independent. Pixel offsets are specified after a colon
like this: "1:16,1:16". In this case the object is shifted to the
northeast by 16 pixels.
Layering
Screen objects on a plane will appear above non-screen objects on the same
plane regardless of layer, except that BACKGROUND_LAYER or EFFECTS_LAYER may
be used to move the objects forward or back.
Secondary map controls
You can use HUD objects in any additional map controls that might appear in
game's skin file. If you have a second map named "map2" for instance, then you
can use "map2:1,1" or something similar as a screen_loc. If the map
control is set to automatically scale to fit its contents, it will try to show
every object you put there. (NOTE: You should not use the full window.control
name, just the name of the control itself. Map controls should always have
unique names.)
appearance_flags var (atom)
- See also:
- vars (atom)
- alpha var (atom)
- color var (atom)
- transform var (atom)
- color var (client)
- Gliding
- Default value:
- 0
- Possible values:
- Any combination of:
- LONG_GLIDE - Diagonal glides take as long as cardinal ones
- RESET_COLOR - If this is an overlay/image/etc., ignore the parent's color
- RESET_ALPHA - If this is an overlay/image/etc., ignore the parent's alpha value
- RESET_TRANSFORM - If this is an overlay/image/etc., ignore the parent's transform
- NO_CLIENT_COLOR - Ignore client.color
- KEEP_TOGETHER - Draw this icon along with its overlays and underlays, as one unit
- KEEP_APART - Detach from a parent icon that uses KEEP_TOGETHER
- PLANE_MASTER - Groups all other icons in the same plane
- TILE_BOUND - Avoids more accurate visibility calculations
- PIXEL_SCALE - Use point sampling when transforming this icon
The appearance_flags value controls miscellaneous behavior of an atom or
appearance that doesn't make sense to handle in any other var.
These values are bitflags, and can be combined with the + or | operator.
The NO_CLIENT_COLOR flag is inherited by overlays and images automatically
unless they have the RESET_COLOR flag.
KEEP_TOGETHER
This flag is used to force the overlays and underlays of this icon (its
"children") to be drawn with it all at once, not each icon individually. One
reason you might want to do this is if your player's icon uses overlays for
hair and equipment, and you want to change the alpha value to make them fade
out. With regular drawing, changing the parent icon's alpha means that each
individual icon becomes translucent; with KEEP_TOGETHER, the whole combination
fades as one unit. Because this incurs some small overhead, it should be
avoided for atoms that do not need it.
Any child appearances underneath KEEP_TOGETHER use NO_CLIENT_COLOR
automatically, and RESET_COLOR, RESET_ALPHA, and RESET_TRANSFORM become
meaningless. Use KEEP_APART with them if you want to use those flags.
Icons that are in a different plane from the parent icon will
automatically have KEEP_APART set and therefore won't be included.
KEEP_APART
If this appearance is a child of something that uses KEEP_TOGETHER, it will
be separated out from the main icon and drawn separately. This may be useful
for things such as health meters, for instance.
PLANE_MASTER
Use this flag to group all icons in the same plane and draw them on a
temporary surface the size of the whole screen, and then that image is drawn
over the existing scene. This is useful for post-processing effects, like
lighting. The plane master's icon is not drawn, but its color, transform, and
blend_mode are all taken into account when drawing.
Example
obj/lighting_plane
screen_loc = "1,1"
plane = 2
blend_mode = BLEND_MULTIPLY
appearance_flags = PLANE_MASTER | NO_CLIENT_COLOR
// use 20% ambient lighting; be sure to add full alpha
color = list(null,null,null,null,"#333f")
mouse_opacity = 0 // nothing on this plane is mouse-visible
image/spotlight
plane = 2
blend_mode = BLEND_ADD
icon = 'spotlight.dmi' // a 96x96 white circle
pixel_x = -32
pixel_y = -32
mob/Login()
..()
client.screen += new/obj/lighting_plane
overlays += /image/spotlight
In the example, all objects in plane 2 are lights. They're added together,
and then the whole image is put through the color matrix, then multiplied over
the rest of the scene below. This will darken everything that doesn't have a
spotlight overlay, but anywhere a spotlight exists will have a circle of
light.
The example also makes a point of adding full alpha to the plane, because a
PLANE_MASTER is fully transparent by default.
The mouse_opacity set by the plane master will determine how the mouse
interacts with objects on the plane. See
mouse_opacity for more info.
TILE_BOUND
There are many ways an object may be shifted out of the normal bounds of
the tile it's on: a large icon, pixel offsets, step offsets, and transform.
Ordinarily it's desirable to be able to see the object if it touches any
visible turf. However, in some cases it's more desirable to only show the
object if its actual loc is in view. The TILE_BOUND flag will accomplish
that. This flag is inherited by images and overlays.
PIXEL_SCALE
Normally if an icon is transformed via atom.transform, it uses bilinear
texture sampling which produces a nice smooth effect. If you want a granular
pixel-art effect instead, PIXEL_SCALE will do that for you. This flag is
inherited by images and overlays.
blend_mode var (atom)
- See also:
- vars (atom)
- alpha var (atom)
- color var (atom)
- Default value:
- 0 (none/overlay)
- Possible values:
- BLEND_DEFAULT (0)
- BLEND_OVERLAY
- BLEND_ADD
- BLEND_SUBTRACT*
- BLEND_MULTIPLY*
[* This blend type appears only when using graphics
hardware mode. It is also not visible in the map editor.]
Controls the way the atom's icon is blended onto the icons behind it. The
blend mode used by an atom is inherited by any attached overlays, unless they
override it. BLEND_DEFAULT will use the main atom's blend mode; for the atom
itself, it's the same as BLEND_OVERLAY.
BLEND_OVERLAY will draw an icon the normal way.
BLEND_ADD will do additive blending, so that the colors in the icon are
added to whatever is behind it. Light effects like explosions will tend to
look better in this mode.
BLEND_SUBTRACT is for subtractive blending. This may be useful for special
effects.
BLEND_MULTIPLY will multiply the icon's colors by whatever is behind it.
This is typically only useful for applying a colored light effect; for simply
darkening, using a translucent black icon with normal overlay blending is a
better option.
color var (atom)
- See also:
- vars (atom)
- alpha var (atom)
- appearance_flags var (atom)
- blend_mode var (atom)
- color var (client)
- rgb proc
- MapColors proc (icon)
- Default value:
- null (white)
- Possible values:
- null (white)
- any color generated by rgb() (e.g., "#00ff00" for green)
- a matrix (in list form)
Controls the color of the icon displayed on players' screens. This color
is multiplied by the icon, so that a white icon will become this color. The
color multiplier is also applied to maptext.
If you include an alpha component in the color, the atom's alpha var will
be set at the same time.
Overlays and images will also be multiplied by this color, unless they use
the RESET_COLOR value in appearance_flags.
The color value can be set to a
color matrix, which is a list of values.
This allows for more complex transformations such as adding or subtracting
color, inverting the color, turning to grayscale, shifting hue, etc. Using
an RGB-only color matrix will include the existing alpha value in the matrix.
When reading the color var, if it is a matrix it will be read out as a
list with 20 items (full RGBA format).
layer var (atom)
- See also:
- overlays var (atom)
- plane var (atom)
- z var (atom)
- map_format var (world)
- BACKGROUND_LAYER
- EFFECTS_LAYER
- TOPDOWN_LAYER
- Default value:
- 1 (AREA_LAYER)
- 2 (TURF_LAYER)
- 3 (OBJ_LAYER)
- 4 (MOB_LAYER)
This numerical value determines the layer in which the object is drawn on
the map. By default, the order is area, turf, obj, mob, followed by missiles
and images (in FLY_LAYER, which is 5).
Example:
turf
archway
layer = MOB_LAYER+1 //overhead
When making objects to be used as graphical overlays, you should also be
aware of the special FLOAT_LAYER value. This causes the overlay (or underlay)
to be in the same drawing layer as the base object, no matter how that layer
changes after the addition of the overlay. Otherwise, the overlay object's
own drawing layer is used.
The actual drawing order of icons may change depending on world.map_format.
An isometric map for instance has to display tiles that are "closer" to the
viewer in front of tiles that are in the back, so the layer var takes a
backseat to the needs of the map. If you use the TOPDOWN_MAP or TILED_ICON_MAP
map formats, the layer is more important.
If you are using a world.map_format that does not display topdown, such as
ISOMETRIC_MAP or SIDE_MAP, then you can use a special layer for showing certain
portions of the map in topdown mode. For those parts of the map, you can add
TOPDOWN_LAYER to every atom's layer to make the atom appear in topdown mode.
This is for special cases, like for instance a battle map in an RPG, where a
regular topdown view is preferable to the special mapping used by the rest of
the game. It is recommended that you use TOPDOWN_LAYER with every atom in that
portion of the map, since topdown and isometric maps for instance don't mix. If
you use TOPDOWN_LAYER, it is best to use a square size in world.icon_size if
any of these atoms will be moving around.
Another special layer, EFFECTS_LAYER, is also available. Icons that use this
layer will display above icons that don't. TOPDOWN_LAYER will then display
above that. This layer is useful for situations such as using a floating name
or health meter overlay on a mob in isometric mode. When using EFFECTS_LAYER,
other icons on the regular map won't cover the overlay. (It is preferable to
use atom.plane for this, when possible.)
Finally there is BACKGROUND_LAYER. Adding this to an atom's layer will make
it appear below any atoms that do not use BACKGROUND_LAYER. (It is preferable
to use atom.plane when possible.)
The atom.plane var takes priority over layer. This is the preferred method
of handling background and effects going forward.
overlays var (atom)
- See also:
- icon var (atom)
- layer var (atom)
- list
- underlays var (atom)
- Default value:
- empty list
This is a list of icons which are displayed on top of the object's main
icon.
The individual items in the list may not be directly accessed, since they
are stored in a special internal format. However, the list operators
+=
, -=
, and the procedures Add
,
Remove
, and Cut
work normally.
Example:
turf/verb/AddOverlay(I as icon)
overlays += I
turf/verb/RemoveOverlay(I as icon)
overlays -= I
The data types that may be used as overlays are icons, icon states (text
strings), objects, and object types. When an icon state is used, the
corresponding image in the object's icon is displayed. When another object is
used as an overlay, a static "snapshot" of the object is taken at the time
when the overlay is created. Future changes to the object will not change the
appearance of the overlay.
Overlays have their own independent drawing layer. It is normally the
special value FLOAT_LAYER, which makes them float above the base object. If
the overlay is a snapshot of another object, the drawing layer of that object
is used. The important advantage of using FLOAT_LAYER is that if the layer of
the base object changes, the overlays will move with it into the new layer.
Any negative number may be used in place of FLOAT_LAYER (which happens to
be -1). They all cause the same "floating" behavior. However, the overlays
are ordered amongst themselves according to their own relative layer values
(-2 below -1 and so on). This may be useful if you have several classes of
overlays that should always appear in a certain order, because you would not
have to worry about the order in which you add them to the list.
Example:
var/const
ARMOR_LAYER = FLOAT_LAYER-1
CLOTHES_LAYER = FLOAT_LAYER-2
obj/overlay
armor
icon = 'armor.dmi'
layer = ARMOR_LAYER
clothes
icon = 'clothes.dmi'
layer = CLOTHES_LAYER
mob/verb
wear_clothes()
overlays += /obj/overlay/clothes
wear_armor()
overlays += /obj/overlay/armor
remove_clothes()
overlays -= /obj/overlay/clothes
remove_armor()
overlays -= /obj/overlay/armor
That example used object types, but you can use instances of objects as
well. Rather than using different "float" layers, you can also just make your
own list of overlays with the order you want and assign that to the actual
overlays list.
Example:
mob/var
boots
clothes
armor
mob/proc
ShowOverlays()
var/L[0]
if(boots) L += boots
if(clothes) L += clothes
if(armor) L += armor
overlays = L
text var (atom)
- Default value:
- The first letter of the object's name.
This is the character used to represent the object on text clients.
Entering several characters produces a text movie (the state of the art!).
In that case, each character is displayed for a 10th of a second.
HTML tags in the text can be used to modify the colors of the text
characters. As a convenience, the <font> tag may include a
bgcolor
attribute, so you don't have to do a CSS style setting to
accomplish the same thing.
Example:
world
maxx = 10
maxy = 10
area
text = " "
turf
text = "......"
The example above produces a map with a blue background (from the area) and
turfs (depicted by ".") that flash from bright red to a shorter span of light
red.
Note that in order to see text icons, the user must switch to the text map
in Dream Seeker. If your DM code never does anything with the icon variable,
then this is the default configuration. Such applications are known as
advanced iconic text games:)
transform var (atom)
- See also:
- vars (atom)
- matrix
An atom can be made to appear rotated, scaled, and/or translated (moved)
by using affine transforms. This takes a matrix and multiplies the x and y
positions of the icon's corners like so:
a d 0
x y 1 * b e 0 = x' y' 1
c f 1
This is equivalent to:
x' = a*x + b*y + c
y' = d*x + e*y + f
You do not need to understand matrix math to use transforms, because you
can use the matrix datum to do this for you.
Transformations are relative to the center of the icon. They do not apply
to maptext.
Examples:
// Rotate the atom by 45° clockwise
src.transform = turn(src.transform, 45)
// OR
var/matrix/M = matrix()
M.Turn(45)
src.transform = M
// Scale the atom by 2x2
src.transform *= 2
// OR
var/matrix/M = matrix()
M.Scale(2,2)
src.transform = M
Whenever you read the atom.transform var, you will get a copy of
the atom's current transformation. Whenever you assign a value to the var,
you will update the transformation.
Assigning null to atom.transform will revert the atom to using no
transformation at all. It is also legal to assign a list with six values,
which is equivalent to using a matrix.
underlays var (atom)
- See also:
- icon var (atom)
- list
- overlays var (atom)
- Default value:
- empty list
This is a list of icons which are displayed underneath the object's main
icon.
The individual items in the list may not be directly accessed, since they
are stored in a special internal format. However, the list operators
+=
, -=
, and the procedures Add
,
Remove
, and Cut
work normally.
Example:
turf/verb/AddUnderlay(I as icon)
underlays += I
turf/verb/RemoveUnderlay(I as icon)
underlays -= I
The data types that may be used as underlays are icons, icon states (text
strings), objects, and object types. When an icon state is used, the
corresponding image in the object's icon is displayed. When another object is
used as an underlay, a static "snapshot" of that object is taken at the time
when the underlay is created. Future changes to the object will not change
the appearance of the underlay.
Underlays have their own independent drawing layer. It is normally the
special value FLOAT_LAYER, which makes them float directly below the base
object. If the underlay is a snapshot of another object, the drawing layer of
that object is used.
See the discussion of FLOAT_LAYER for overlays,
because the same applies here.
vis_contents var (atom)
- See also:
- vis_locs var (atom)
- image objects
- HUD / screen objects
- Default value:
- Empty list.
Turfs, movable atoms, and images can be given a list of atoms (limited to
turfs and movable atoms) that are attached to them visually, like an overlay
or image object, but act indepnendently and have their own identity. These are
"visual contents". The purpose of visual contents is to provide an alternative
system to overlays and images, with a little more flexibility for various
special effects.
For example, a mob with an obj in its visual contents will show the obj
as if it's following the mob around like an overlay, but clicking on the on
the obj will not--unlike an overlay or an image object--count as a click on
the mob. Likewise, the obj will retain its own separate mouse_opacity
setting, which is not true of regular overlays.
An atom that appears on the map normally can still be in the visual
contents of another atom. However it will not apply gliding and step offsets
here. Also, considerations like visibility will not apply.
If a turf is in an atom's visual contents, the turf and all of that turf's
contents will be displayed. (In the case of big atoms, or movable atoms with
step offsets, only atoms that actually have that turf as their loc will
appear. "Overhangers" will not.) Gliding and step offsets will be
applied to that turf's contents normally; but again visibility, opacity, etc.
will not be considered.
If multiple turfs are present in visual contents, they will be
offset as needed (relative to the southwest-most turf) to appear in the
correct positions. That is, pixel_x and pixel_y offsets will be applied
automatically, so if you add an entire block to visual contents (be aware
this will impact performance), you don't have to do anything else to make
the block appear normal.
Visual contents do not impact the results of view() or range(), or verb
availability, in any way. This is strictly a visual effect for special effect
purposes.
Being in a visual contents list counts as a reference
for anything in the list, the same way that being on the map or inside of a
movable counts as a reference.
z var (atom)
- See also:
- layer var (atom)
- loc var (atom)
- Default value:
- The z coordinate of the object on the map.
The z coordinate is how objects move between maps. When you include
several maps in a project, they are placed on different z levels so that the
full map is a single 3-dimensional space. It is also possible for a single
map file to contain multiple z levels.
Do not confuse this with drawing layer. The z coordinate moves an object
between different maps. The layer variable determines the order in which an
object is drawn graphically relative to other objects at the same position on
the map.
You may assign the coordinates of movable objects (mobs and objs), but this
is not advisable. It is better to compute the new location (with
locate()
) and move them to that. Then you can use the normal
Move()
procedure, which enables all the normal movement behavior.
For areas that are on the map, this is the coordinate of the turf with the
lowest z, y, and x coordinate (in that order) that is contained by the area.
Topic proc (client)
- See also:
- New proc (client)
- Topic proc (datum)
- link proc
- ref text macro
- Format:
- Topic(href,href_list[],hsrc)
- When:
- Called when a player connects to a world with a "connection topic" or
when the player runs a hyperlink in the current world by clicking one
embedded in text or generated by the link() instruction.
- Args:
- href: The topic text (everything after the '?' in the full href).
- href_list: List of key/value pairs in href (produced from params2list(href)).
- hsrc: The object referenced by the "src" parameter in href or null if none.
- Default action:
- Call the hsrc object's own Topic() proc.
The following example uses a very simple href value.
Example:
mob/Login()
src << "Click here to download the source code."
return ..()
client/Topic(href)
if(href == "source")
usr << file("world.dm")
usr << file("world.rsc")
else ..()
Be sure to call the default handler unless you want to prevent rerouting
of topics to other objects. For security reasons, you might want to control
which objects a player has access to, since a player could spoof a topic
link containing any arbitrary object reference. (Never trust those sneaky
players!)
The next example demonstrates an href that gets handled by another object.
This is how you would normally want to do things. It is best not to override
client/Topic() (as in the example above) unless you need to intervene in the
low-level details of routing the request to the right object.
You specify the object that will handle the request by using a parameter
called "src".
Example:
mob/Login()
src << "Click here to start."
return ..()
mob/Topic(href,href_list[])
switch(href_list["action"])
if("startgame")
usr << "Starting game..."
else
return ..()
Although it is slightly more complex, the use of the parameter list allows
you to easily include extra data and new functionality. Just remember that
the data in the list is always stored as text, so if you are expecting a
number or an object, you must convert it yourself (with text2num(), locate(),
or whatever).
authenticate var (client)
This value may be set to 0 at compile-time to disable BYOND hub-based
authentication of users. The default value is 1, which enables
authentication. Hub authentication provides an additional level of
assurance that the user is really the owner of the BYOND key in question.
When a world requests certification, Dream Seeker generates a random
password and passes it through the hub (for certification) to the world.
The certificate is saved for faster access in the future and for protection
against possible hub outages.
Some applications do not depend on the validity of the user's identity.
In that case, it would be more efficient to turn off the extra level of
authentication. In other situations, the hub may not be available, such as
from behind a firewall or on a LAN without internet access. In those cases,
all hub access (including authentication) can be disabled by entering the
command ".configuration hub-address none" in Dream Seeker.
Connections to worlds on the same machine are not hub-authenticated to
allow for convenient offline testing.
bounds var (client)
Also bound_x, bound_y, bound_width, and bound_height
- See also:
- bounds proc
The read-only bounds var returns the map coordinates, in pixels, covered
by the client's viewport when accounting for pixel offsets, eye, step, etc.
(The coordinates are only relevant to the default client.dir value of NORTH,
and the TOPDOWN_MAP or SIDE_MAP map formats.)
If the viewport is not currently on the map (for instance, when the eye is
at a null location), the var reads as null. Otherwise, it is a list with
five values (x, y, width, height, z) in the same form used by the bounds proc.
The alias vars bound_x, bound_y, bound_width, and bound_height can also
be used to retrieve the individual values from the list. They too will be
null if the viewport is not on the map.
command_text (client)
- See also:
- arguments (verb)
- Skin reference
- macros (client script)
- Default value:
- null
This text is placed onto the command line, to be followed by whatever the
user may type. It is usually the name of a verb followed by a space, such
as "say ". The user can clear this and enter a different command by hitting
backspace, escape, delete, or '/'.
(Note: In BYOND 4.0 this var is deprecated. The command
parameter for an Input control can be set to !command which does the
same thing. See the skin reference
for details.)
Example:
client
command_text = "say "
verb/say(T as text)
world << "[usr] says, '[T]'"
It is also possible to turn on macro mode, in which each keypress
executes a keyboard macro, by setting
command_text
to ".alt ". That stands for the Alt key,
which can be used to execute macros in normal mode.
This variable could also be used to create a specialized command prompt.
For example, a traditional style MUD command-line could be implemented like
this:
Example:
client
command_text = "> "
verb/command(C as command_text)
set name = ">"
usr << "Your command: [C]"
This example uses the command_text input type, which accepts raw
text, with no quoting, escaping, or translating, so that you can invent
whatever syntax you want.
control_freak (client)
- See also:
- Skin reference
- macros (client script)
- Default value:
- 0
This var lets you set flags to turn off options that are normally present
for the end user. You can combine these flags with the | operator. The value
1 is equivalent to CONTROL_FREAK_ALL and will disable everything.
- CONTROL_FREAK_ALL
- If this value is used, it affects all the options below.
- User-defined macros may not be used.
- Only the world's skin or the default BYOND skin will be loaded, not a user-customized version.
- The Options & Messages window in Dream Seeker is inaccessible. It will only come up while first connecting to a remotely hosted world, or if a world takes a long time to load. The .options command will not make it appear.
- The menu items from Options & Messages are unavailable in Dream Seeker's system menu.
- The default F2 macro for the .screenshot command is turned off. The command is then only accessible through the skin you create.
- CONTROL_FREAK_SKIN
- Toggles the ability to create a custom version of the skin.
- CONTROL_FREAK_MACROS
- Toggles the ability to use and define custom macros.
Using CONTROL_FREAK_ALL will default to disabling everything, and the other
flags will reenable only the features you want. For example, CONTROL_FREAK_MACROS
alone will disable the ability to use your own macros but nothing else.
CONTROL_FREAK_ALL | CONTROL_FREAK_MACROS will disable everything except
macros.
This value can be changed at runtime. However any changes made at runtime
will not affect users running old BYOND versions. Users whose versions only
recognize "all enabled" or "all disabled" will have everything disabled if you
use any value other than 0.
Important: If you define your own skin for the world, and disable the
ability to use a custom skin or user-defined macros, you must be sure to define
any macros your world may need. For instance, arrow keys may be needed for
movement.
eye var (client)
- See also:
- edge_limit var (client)
- lazy_eye var (client)
- mob var (client)
- perspective var (client)
- glide_size var (client)
- view var (client)
- virtual_eye var (client)
- view var (world)
- step_x var (movable atom)
- step_y var (movable atom)
- Default value:
- The connected mob, client.mob.
This value determines the center of the player's map. The default value
simply means that the visible region is normally centered on the player's mob.
Effects such as setting perspective
to
EDGE_PERSPECTIVE
or using lazy_eye
can move the map
off-center temporarily. The eye is the ideal center, not
necessarily the actual center; to find the actual center, use
virtual_eye
.
The eye's step_x/y vars, if present, are also used to allow smooth
scrolling of the map. These also obey lazy_eye and edge_limit.
Note that the visibility of objects is still computed from the point of
view of the mob rather than the eye. This allows the use of
lazy_eye
or similar effects that control the panning of the map
while still having the player see only what the mob can see. To determine
visibility from the eye, you can change the value of
client.perspective
.
If a player connects to a new mob M, client.eye automatically changes to M.
Example:
client
eye = locate(5,5,1)
This fixes the center of the player's map at the turf coordinate (5,5,1).
Since the eye is fixed, the map will not scroll even as the player's mob
moves out of the visible range.
lazy_eye var (client)
- See also:
- view var (client)
- view var (world)
- Default value:
- 0
This is the maximum "lag" between client.eye and client.mob. The mob can
stray up to this many tiles before the eye will move to keep it in view. The
default value of 0 means that the eye always moves as the mob moves, keeping
the mob at the center of the player's map.
Setting this value to a non-zero value automatically initializes client.eye
to client.mob.loc (or to the center of the full map if that is possible).
Thereafter, client.eye will stray from the mob as it moves about the map,
making one big jump to catch up whenever the mob gets out of range.
Example:
client
lazy_eye = 5
This setting allows client.mob to move onto the entire 11x11 visible
region without changing the value of client.eye. The moment it steps out of
this region, the entire region will shift 5 tiles in the direction of motion.
You can assign lazy_eye to any value valid as a view size, so, for example,
if you have a non-square setting for client.view, say, "17x11", you could
apply a similar setting to lazy_eye. You can even make one dimension lazy and
the other one strictly centered: "0x5".
preload_rsc var (client)
- Default value:
- 1.
This variable controls whether resource files (icons and sounds) are
automatically downloaded by Dream Seeker when first connecting, or whether
they should be downloaded as needed. Resource files are cached (in
byond.rsc) for future use, so this should only affect people who have not
played the game before or who have not played it for some time.
The three possible settings are:
- 0
- do not preload any resources
- 1
- preload compiled-in resources only
- 2
- preload all resources including those uploaded by players
- URL
- preload resources from specified file
Preloading resource files will eliminate delays later on, but may cause
a very long initial delay when logging in.
Resources may also be distributed from a website to save bandwidth on the
machine hosting the game. Simply zip up the .rsc file, upload it to a web
site, and put the URL here.
Example:
client/preload_rsc = "http://dan.byond.com/mygame_rsc.zip"
Instead of putting the .rsc file in the .zip, you can also put the
individual resource files there. This would allow you to select specific
files that you would like to be preloaded. For example, you could create a
different resource package for different parts of the game world and assign
client.preload_rsc dynamically as the player moves into each different area.
Once Dream Seeker has downloaded a resource package, it caches it and will
not download it again, even if you upload a new version of the file. This
allows you to make small changes without forcing a complete refresh. Any
files which are not found in the preload package are simply downloaded from
the game server directly.
If you want to force a complete refresh, simply change the name of the
resource package. For example, you could put a version number in the name of
the file: mygame_rsc_01.zip, mygame_rsc_02.zip, and so on.
script var (client)
- See also:
- #include directive
- PASSWORD_TRIGGER (client script)
- URL (client script)
- aliases (client script)
- browser configuration
- command_text (client)
- macros (client script)
- style sheets
- style sheets (in scripts)
- Default value:
- none
Client scripts are mini-programs used to configure the client. The
language they use is called DM Script, and will undoubtedly expand in the
future. Currently, client scripts can be used to define style sheets,
command aliases, and macros. When executed directly by a player, they can
also be used to specify an initial URL to open and a password trigger (for
some ancient telnet worlds that don't suppress password echo).
For the specific syntax of DM Script, see the relevant reference sections
listed above.
The client.script
variable may be assigned to script code in
a text string (double quotes) or in a file (single quotes). You can also
simply include the file in your project or explicitly use the
#include
statement. Files containing DM Script should have the
extension .dms
.
Example:
client/script = ""
This example selects a default monospace font for all output to the
terminal.
In addition to scripts loaded via client.script
, the player
may have client-side scripts. These are either called
connection scripts or post-connection scripts depending on
whether they are used to automatically connect to a world or whether they
are executed automatically after connecting to a world. In either case, the
player's scripts are always executed before the designer's
client.script
script, so style sheets from the designer have
higher precedence by default.
There are three post-connection client-side scripts for the three types
of worlds the client can connect to: byond.dms
,
telnet.dms
, and irc.dms
. These are automatically
executed if the player connects directly to a world without using a
connection script to do so. The intention is to load any standard
configurations such as style sheets and command aliases.
aliases (client script)
- See also:
- macros (client script)
- script var (client)
- verbs
Command aliases have a syntax similar to verbs. They define a command
and a series of arguments which can then be used to execute a new command.
The most common use for this is in a telnet world like a MUD. By defining
aliases corresponding to the MUD commands, the player can have primitive
command expansion and help.
The syntax of an alias definition is best illustrated by the following
example:
alias/say(msg as text)
set desc = "speak your mind"
return "say [msg]"
As you can see, it is just like a verb. Alias have all the same
properties as verbs, except the src
setting is always equal to
the player.
The value returned by an alias is executed as a command. In telnet mode,
the command to execute is often simply the same as the command that was
entered (since the alias was only defined to provide command expansion and
help). Since that is such a common case, the return value defaults to the
alias name followed by each of the arguments. The example above, for
instance, would have the same effect without an explicit return statement.
Note that commands executed via an alias are never interpreted as
aliases. Otherwise, examples such as the one above would result in an
infinite loop.
view var (client)
- See also:
- lazy_eye var (client)
- show_map var (client)
- view proc
- view var (world)
- Default value:
- world.view (which is 5 by default)
- Possible values:
- -1 to 34 or "WIDTHxHEIGHT"
This controls the size of the map window in Dream Seeker. Normally, you
would simply compile with world/view assigned to whatever you want, but in
some cases, you might want to customize the map size for different players,
such as admins or subscribed users.
Like all other view sizes in DM, this may either be a view depth
or an absolute size. A view depth is a single number that determines how far
from a center point the edges of a square viewable region extend. A value of
5 creates edges which are 2*5+1 = 11 tiles long.
The newer, more flexible syntax is a text string of the form
"WIDTHxHEIGHT". For example, a view depth of 5 corresponds to "11x11". Using
this syntax, you can create non-square views as well.
The maximum view size is about 5000 tiles, or roughly 70x70.
Add proc (database query)
- See also:
- database query datum
- Clear proc (database query)
- Format:
- Add(text, item1, item2, ...)
- Args:
- text: Text to add to the query
- item1, item2, etc.: Items that will replace question marks in text
Adds text to a database query. If this datum was already used to run a
query, Clear() will be called automatically.
If your text includes question marks, they will be replaced with the other
items listed in the proc arguments. If that item is a string, quotes will be
put around it for the query text. Files in the cache (such as icons) will be
added as BLOB values.
After the query has been built, call Execute() to run it.
Example:
var/database/db = new("mydb.db")
var/database/query/q = new
q.Add("INSERT INTO quests (name, quest, complete) VALUES (?,?,?)", usr.key, quest_name, 1)
q.Execute(db)
In the example above, the query text might look like this:
INSERT INTO quests (name, quest, complete) VALUES ('Tom','Save the Dog',1)
icon
- See also:
- icon procs
- icons
- image objects
An /icon object is created by loading an icon file into memory for direct
access and manipulation. In order to be displayed, an /icon object always
gets converted back into an icon file; this happens automatically when you
assign atom.icon to an /icon object, since that variable may only refer to a
static icon file, rather than a dynamic memory object.
To create an /icon object, simply use new/icon(), or the short-cut icon()
instruction. The following example loads an icon file, reddens it, and then
assigns it back to the player's icon, which implicitly creates a new icon
file.
Example:
mob/verb/test()
var/icon/I = new('player.dmi')
I.Blend(rgb(40,0,0))
usr.icon = I
Note that merely displaying different icon states or directions can
generally be achieved without any icon manipulation, which is good, because it
saves quite a bit of overhead. For example, the variables atom.icon_state and
atom.dir can be used to control how atom.icon is displayed, without any need
for generating a new icon file.
Blend proc (icon)
- See also:
- icon
- icon procs
- overlays var (atom)
- rgb proc
- Format:
- Blend(icon,function=ICON_ADD,x=1,y=1)
- Args:
- icon: an icon file, /icon object, or color
- function: the blending operation to use
- x, y: the position to blend the icon
The valid blending operations are:
- ICON_ADD
- ICON_SUBTRACT
- ICON_MULTIPLY
- ICON_OVERLAY
- ICON_AND
- ICON_OR
- ICON_UNDERLAY
The result is a combination of each corresponding pixel in the two icons.
In all but ICON_OVERLAY, ICON_UNDERLAY, and ICON_OR, the transparent regions of
the two icons are ORed together. That means if either icon is transparent on a
given pixel, the result will be transparent. With ICON_OVERLAY or ICON_UNDERLAY,
on the other hand, the original icon shows through wherever the top icon is
transparent, giving the same effect as an overlay object, but resulting in only a
single icon. In ICON_OR, the transparent regions are ANDed together; solid pixels
are added together where they exist in both icons, or just pass through if the
other icon is transparent at that pixel.
In addition to blending with an icon, an rgb() value may also be specified.
This is treated identically to an icon of that same solid color, except that the
x and y arguments will be ignored. Blending with a color blends the whole icon.
By default, the icons will line up at their lower left corners. If you want
to position the second icon in a different place for blending, use the x and y
arguments to specify where its lower left corner will be. 1,1 is the default,
which is the lower left. 11,1 for instance would be 10 pixels to the right,
and 1,21 would be 20 pixels up.
Insert proc (icon)
- See also:
- icon procs
- New proc
- map_format var (world)
- Big icons
- Tiled icons
- Format:
- Insert(new_icon,icon_state,dir,frame,moving,delay)
- (supports named arguments)
- Args:
- new_icon: an icon file or /icon object to insert
- icon_state: an optional text string, specifying a single icon state to
change or add to this icon
- dir: an optional direction; the inserted icon will only be added for this
direction
- frame: an optional animation frame (starting at 1); the inserted icon will
only be added for this frame
- moving: Non-zero to insert as a movement state, 0 for a regular non-movement
state
- delay: 0 or null to leave unchanged; positive to set delay for a frame and turn
rewind off; negative to set delay and rewind
This adds additional states or images to an existing icon, allowing you to
build directional, animated, and multi-state icons on the fly. If the state
you wish to insert already exists in the file, it will be altered; otherwise
it will be added. An animation may be built a piece at a time, for example by
inserting an icon into the NORTH direction for animation frame 3.
Example:
// start with a non-animated arrow icon
var/icon/I = new('arrow.dmi')
// make a new state called "blink"
var/icon/J = new('arrow.dmi')
I.Insert(J, "blink", delay=-1) // set rewind flag
// create darker shades of the arrow
var/n = 2
for(var/light=9, light>=5, light--)
J = new('arrow.dmi')
J.SetIntensity(light/10)
I.Insert(J, "blink", frame=n++)
// congratulations, you have a pulsating arrow
icon = I
The icon resulting from this example has two states: The original arrow,
and a new state called "blink" that pulsates between full and ½
luminance. To use the blinking state after that, set the atom's icon_state to
"blink".
(Note for animations: When building an animated icon_state from scratch,
you can only add 16 new animation frames at a time; i.e., frame<=total_frames+16.
Higher values for frame will be ignored. This is a safety precaution.)
If you insert an icon of a different size, the src icon will be resized to
match the size of new_icon. (The only exception is if you are using the TILED_ICON_MAP
map_format, and new_icon is a single tile being inserted as a chunk into a larger icon.
If icon_state, such as "2,0" or "open 0,0", already exists in src as one of its smaller
pieces, then new_icon will be inserted in its place.)
When inserting an individual animation frame, you can change the delay for
just that frame only. If you don't specify a delay, the nearest frame's delay
will be used. If this is the first frame being inserted into an icon, then
the delay will default to 1 tick. Remember, if your delay is positive, it will
turn off the rewind flag for that entire icon state; negative will turn it on.
MapColors proc (icon)
- See also:
- icon
- icon procs
- rgb proc
- Format:
- MapColors(rr, rg, rb, gr, gg, gb, br, bg, bb, r0=0, g0=0, b0=0)
or
MapColors(r_rgb, g_rgb, b_rgb, rgb0=rgb(0,0,0))
or
MapColors(rr, rg, rb, ra, gr, gg, gb, ga, br, bg, bb, ba, ar, ag, ab, aa, r0=0, g0=0, b0=0, a0=0)
or
MapColors(r_rgba, g_rgba, b_rgba, a_rgba, rgba0)
- Args:
- rr: portion of old red component -> new red component
- rg: portion of old red component -> new green component
- rb: portion of old red component -> new blue component
- ra: portion of old red component -> new alpha component
- r0: new base red component
- ...
- or
- r_rgb: red component is converted to this color
- g_rgb: green component is converted to this color
- b_rgb: blue component is converted to this color
- rgb0: this color is added to the result
This is used for complex color mapping that can be used for many special
effects. For the number form, values usually range from 0 to 1, but you can
use anything you like, including negative numbers. 1 means 100% of the
original color will be used. If rg=1, for example, then the amount of red in
the original icon becomes the same amount of green in the new icon's colors.
There is also an alternate form that can use rgb() values
instead, though it is less flexible. r_rgb is the color that will be used in
place of 100% red; any darker shades of red will become a darker shade of
that color. g_rgb converts green to another color, and b_rgb converts blue to
still another color, and all of them are added together.
Either of these calls change the icon to grayscale:
icon.MapColors(0.3,0.3,0.3, 0.59,0.59,0.59, 0.11,0.11,0.11, 0,0,0)
// or...
icon.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
The calculations are as follows:
- For any red in the original icon, add 30% gray to the output.
- For any green in the original icon, add 59% gray to the output.
- For any blue in the original icon, add 11% gray to the output.
- Add an additional 0% (nothing).
Or this will make a nice moonlight effect:
icon.MapColors(0.2,0.05,0.05, 0.1,0.3,0.2, 0.1,0.1,0.4, 0,0,0)
// or...
icon.MapColors(rgb(51,13,13), rgb(26,77,51), rgb(26,26,102), rgb(0,0,0))
- For any red in the original icon, add rgb(51,12.75,12.75) (dark pink) to the output.
- For any green in the original icon, add rgb(25.5,76.5,51) (dark bluish green) to the output.
- For any blue in the original icon, add rgb(25.5,25.5,102) (dark grayish blue) to the output.
- Add an additional 0% (nothing).
Or a negative icon (invert all colors):
MapColors(-1,0,0, 0,-1,0, 0,0,-1, 1,1,1)
The longer formats of MapColors() will allow you to also change alpha colors.
New proc (icon)
- See also:
- icon
- icon procs
- image proc
- new proc
- Format:
- New(icon,icon_state,dir,frame,moving)
- (supports named arguments)
- Args:
- icon: an icon file or /icon object
- icon_state: an optional text string, specifying a single icon state to load
- dir: an optional direction to extract
- frame: an optional animation frame to extract
- moving: Non-zero to extract only movement states, 0 for non-movement states,
or null (default) for both
You generally don't call this directly but via new(). The specified icon
file is loaded into memory for direct access and manipulation.
If the icon state is not specified, all icon states are loaded. Ditto for
the direction, animation frame, or preference for movement states. Animation
frames are numbered from 1 and up, so frame=4 is the 4th frame.
(Movement states are special versions of an existing icon_state with the
same name, but appear in the Dream Maker editor with an "M" indicator. These
states are used for animation when the atom using the icon_state moves from
one tile to the next; otherwise only the normal non-moving state is displayed.)
The following contrived example, loads the EAST facing default icon state
"" from the user's icon file, rotates that a bit, and then creates a new icon
file for the user.
Example:
mob/verb/test()
var/icon/I = new(usr.icon,icon_state = "",dir = EAST)
I.Turn(90) //rotate clockwise 90 degrees
usr.icon = I
Note that merely displaying different icon states or directions can
generally be achieved without any icon manipulation, which is good, because it
saves quite a bit of overhead. For example, the variables atom.icon_state and
atom.dir can be used to control how atom.icon is displayed, without any need
for generating a new icon file.
SwapColor proc (icon)
- See also:
- icon
- icon procs
- rgb proc
- Format:
- SwapColor(old_rgb,new_rgb)
or
SwapColor(old_rgba,new_rgba)
- Args:
- old_rgba: the old rgba value to be replaced
- new_rgba: the new rgba value to use in its place
This causes a color value in the icon's palette to be changed. You can use
null in place of an RGB or RGBA value.
If the old color is a full RGBA color with an alpha value, such as
rgb(1,2,3,4) or "#01020304", then that exact color is the only one changed.
If the old color is an RGB value with no alpha specified, such as
rgb(1,2,3) or "#010203", then that color will change to the new one
regardless of its alpha value, and the original icon's alpha will be kept
intact. (If the new color is totally transparent, however, then the old color
will be replaced with full transparency.)
image objects
- See also:
- icon var (atom)
- image proc
- image vars
- images var (client)
- overlays var (atom)
- override var (atom)
The /image type contains data used to create a virtual image. Unlike other
atomic objects, this object is a purely visual effect. It always appears
attached to some other object and it behaves in every way as though it were
part of that object (e.g. if the user clicks on it, this counts as a click on
the atomic object, not the image).
One reason for creating images is player-by-player control over visibility.
Images only become visible when they are explicitly output to players:
Example:
var/image/I = image('icon.dmi',usr) //make an image attached to usr
usr << I //allow usr to see it
Images are also useful in the creation of overlays. Overlays are like
images, since they are always attached to another object, but overlays obey
the normal rules of visibility, so they are more convenient when you do not
want to hide the effect from anybody. An overlay can be created directly from
an icon file (or icon state), but when one wishes to override some additional
parameter, the image() instruction is a convenient way to do it.
Example:
usr.overlays += image('shirt.dmi',icon_state = "red")
In the above example, the icon state of an overlay was set by creating the
overlay from an image with the desired icon state. Note that after the
creation of an overlay, no link remains between the overlay and the object
that was used to create it. If you change the image after that time, it will
not change the overlay, which is simply a "snapshot" of the original image.
list
- See also:
- list associations
- list proc
- procs (list)
- vars (list)
Lists are used to represent groups of objects. Like objects, they have
vars and procs associated with them. In order to access these attributes,
list vars must be declared of type /list. These may then be assigned to
existing lists, or used to create new lists.
Example:
var/list/L // list reference
L = world.contents // assign to existing list
L = new/list() // make a new list
L = new() // make a new list (implicit type)
L.Add("futz") // L contains: "futz"
del(L) // delete L
Lists created with 'new()' have a default length of 0; this can be
overridden by specifying the size; that is, new/list(size) creates a list
with size (null) elements.
The 'list()' proc may be used to more easily initialize list data.
Example:
var/list/L
L = list("futz",3) // L contains: ("futz", 3)
Alternatively, lists may be declared by using brackets, '[]'. Empty
brackets indicate a list reference, exactly as /list does, so list/L is
equivalent to L[]. Setting an initial size within the brackets, for
instance, L[10], creates a list of that initial size.
Example:
var/L[] // same as var/list/L: list reference
var/M[10] // initially empty list of size 10
L = M // L is now an empty list of size 10
Once a list L is declared, a specific item can be accessed by putting its
index in the brackets: L[index].
Indices range from 1 to len. If the length of the list is changed,
existing elements in the list will be preserved if they are less than the
new length. New elements in the list will be given the initial value of
null.
Example:
var/L[5] // initial length of 5
var/i
for(i=1, i<=L.len, i++)
L[i] = i
// L contains: (1,2,3,4,5)
L.len = 7 // expand list
// L contains: (1,2,3,4,5,null,null)
del(L) // destroy list
Multi-dimensional lists may be created by making a list of lists.
Example:
var/grid[10][5]
grid[1][1] = 1
grid[1][2] = 2
...
Such a list may also be created by using new(). As in the previous
example, the next one creates a list of 10 lists each having 5 elements.
Example:
var/grid = new/list(10,5)
list associations
- See also:
- list
- list proc
- list2params proc
- params var (world)
- params2list proc
- vars list var (datum)
Each unique text string or object in a list may be associated with another
value. This is done by using the item as an index into the list.
Example:
var/params[0]
params["player"] = "James Byond"
params["score"] = 2000
//List now contains ("player","score")
//These are associated with ("James Byond",2000)
usr << "Looping through list items:"
var/p
for(p in params)
usr << "[p] = [params[p]]"
usr << "Looping through array indices:"
var/i
for(i=1,i<=params.len,i++)
p = params[i]
usr << "[p] = [params[p]]"
The above example illustrates the typical way in which list associations
are managed. Note that an item in the list may be added by assigning its
associated value. The example could have started by doing
params.Add("player","score")
, but that would have been
redundant.
Both for
loops in the example have the same effect. The
first one loops through each item in the list, and displays it along with
its associated value. The second loop achieves the same thing by looping
through the numerical indices (referred to as array indices as
opposed to associative indices).
Since numerical indices are treated differently, you may not assign an
associated value to a numerical list item. Associations must have a text
string or object reference as the index item.
Associated values default to null if none is assigned. This is also the
value returned when the supplied index item does not exist in the list. The
list defined above, for example, would return null for
params["time"]
.
The list()
instruction may also be used to create associative
lists.
Example:
var/list/lst = list("player" = "James Byond", "score" = 2000)
When the index values happen to be text strings that satisfy all the
requirements for variable names, this may also be written in a convenient
short-hand:
var/list/lst = list(player = "James Byond", score = 2000)
In other words, this is exactly the same syntax as for
named arguments.
matrix
- See also:
- matrix operators
- matrix procs
- transform var (atom)
- matrix proc
To display rotation, scaling, and other transformations on atoms, DM uses
matrices. The /matrix datum is a convenient way of handling the numbers
involved, as it can be easily manipulated. There are six vars, a through f,
laid out like so:
a d 0
x y 1 * b e 0 = x' y' 1
c f 1
When an x,y point is multiplied by the matrix, it becomes the new point
x',y'. This is equivalent to:
x' = a*x + b*y + c
y' = d*x + e*y + f
The default matrix is:
1 0 0
0 1 0
0 0 1
Matrices are created with the matrix() proc, or by calling new/matrix().
(See the matrix() proc for examples.) They are also created as needed
whenever you read from atom.transform or use certain operators.
Manipulation of matrices can be done with operators, or with procs. You
can do the following with them:
- Multiply: Multiplying two matrices together will chain together
the transformations they represent. For instance, a scaling matrix
multiplied by a rotation matrix says: Scale, then rotate. Multiplication of
two matrices is sensitive to the order you use.
- Scale: A simple scale matrix uses only the a and e values, to
scale x and y by a certain amount.
- Rotate: A rotation matrix can rotate an atom by whatever amount
you like.
- Translate: Translation is like a pixel offset, changing the atom's
position.
- Interpolate: You can calculate a matrix that lies somewhere
between two other matrices, which can be helpful for animation.
When you've built your matrix, you can assign it to atom.transform to
change the way that atom is displayed.
The matrices supported by this datum are not the same kind used to
transform colors, as in the atom.color var and icon.MapColors() proc. For
color matrices, see color matrix.
?. operator
- See also:
- . operator
- : operator
- ?: operator
- operators
This is used to access the procs and vars of a prototyped object. It is
just like the . operator, but if the object is null, the access does not
happen and there will be no runtime error. (A runtime error can still happen
if the object is valid but is a different type that doesn't have the property
available.)
When used in an expression to read a value or call a proc from a null
object, the result of the expression is null. When used for assignment,
the assignment will not happen if the object is null.
Example:
var/mob/M // M is null by default
M?.name = "futz" // assignment is skipped because M is null
world << M?.name // M?.name reads as null because M is null
M?.Move(loc) // call Move() mob proc; again nothing happens
M = new
M?.name = "futz" // assignment is made because M is valid now
world << M?.name // outputs "futz"
M?.Move(loc) // call Move() mob proc for M
When reading A?.B
, it's equivalent to A && A.B
except that A
is only evalulated once, even if it's a complex
expression like a proc call. Making an assignment to A?.B
is
the same: A is evalulated only once, and if it's not null then an assignment
is made to its B var.
For a version of this operator that doesn't check at compile time if the
property is available, use the ?: operator instead.
If ?. is used after a proc call, a list lookup, or a complex expression
where the type can't be known, it will act like ?: instead.
?: operator
- See also:
- . operator
- : operator
- ?. operator
- operators
This is used to access the procs and vars of an object. It is just like
the : operator, but if the object is null, the access does not happen and
there will be no runtime error. (A runtime error can still happen if the
object is valid but the property is not available.)
When used in an expression to read a value or call a proc from a null
object, the result of the expression is null. When used for assignment,
the assignment will not happen if the object is null.
Example:
var/mob/M // M is null by default
M?:name = "futz" // assignment is skipped because M is null
world << M?:name // M?:name reads as null because M is null
M?:Move(loc) // call Move() mob proc; again nothing happens
M = new
M?:name = "futz" // assignment is made because M is valid now
world << M?:name // outputs "futz"
M?:Move(loc) // call Move() mob proc for M
When reading A?:B
, it's equivalent to A && A:B
except that A
is only evalulated once, even if it's a complex
expression like a proc call. Making an assignment to A?:B
is
the same: A is evalulated only once, and if it's not null then an assignment
is made to its B var.
This is identical to the ?. operator, except that ?. will check at compile
time if the property is valid for the object type (if known). For this
reason ?. is usually safer.
path operators
- See also:
- . path operator
- / path operator
- : path operator
- procs
- vars
A "path" in DM is a constant value that identifies a particular definition
in the code tree (i.e. an object, procedure, or variable definition). An
example of this is the default mob type for new players /mob
.
Paths are used in two contexts. One is to "get to" a particular point in
the code tree in order to modify the definition. The other is to reference a
particular definition made elsewhere in the code tree. The syntax of a path
is similar in both cases.
When you are making a definition, you simply put the path at the beginning
of a line like this:
obj/clothes/gloves
That automatically creates that path in the code tree if it does not
already exist. When starting at the beginning of the line (no indentation)
there is no need to begin the path with '/', but that is perfectly acceptable.
When making definitions, DM equates the path separator '/' with
indentation, so the above example is really just a more compact way of
writing:
obj
clothing
gloves
One generally uses indentation when you have several things to define with
a common parent path:
obj
clothing
gloves
sandals
An important element of DM is that you can get to the same path in the
code tree from multiple places in the source code. For example, given the
above definition of gloves
and sandals
, you could
modify a property of one of them from somewhere else using any path syntax you
like:
obj/clothing/sandals
name = "Winged Sandals"
While that was not a useful thing to do in this case, it can be a very
powerful tool when organizing source code in large projects. Also note that
the use of "/" can save your source code from getting too deeply indented,
which may sound mundane, but which is quite important!
The above examples used paths to make definitions. The other time when you
use paths is when you need to refer to a particular definition. Creation of
an object is one example:
mob/Login()
if(length(contents) == 0) //poor fellow has nothing
//create sandals in his contents list
new /obj/clothing/sandals (src)
return ..()
Another common use of paths is to declare the data type of a variable. In
DM, variable types do not affect what type of data the variable may
contain--variables that you define may contain any type of value. Instead,
the variable type affects what properties of the data you can attempt to
access.
The following example defines variables for clothing that is occupying
various positions on the body.
mob
var/clothing
feet
hands
torso
Since there were several variables of the same type, they were grouped
under var/clothing
. It can be done any number of ways, depending
on the situation. The same path syntax applies to variable definitions as
it does to anything else. This example produces the same effect:
mob/var/clothing/feet
mob/var
clothing
hands
torso
Provisos
Just do not make a mistake like the following:
mob/var
/clothing/feet
Beginning a path with '/' effectively ignores whatever indentation may
precede it. That is why it is called an absolute path. The above
example would therefore be the same as the following, which is not what you
want:
mob/var //empty variable definition
clothing/feet //definition of object type /clothing/feet
On a related note, parameter definitions in procedures should not begin
with a "/".
mob/Move(atom/Dest) //correct
src << "Moving to [Dest.x],[Dest.y]."
return ..()
mob/Move(var/atom/Dest) //ok
mob/Move(/atom/Dest) //WRONG
Essentially, "var/" is prepended to each entry in the parameter list.
Some operators cannot be overloaded. The = operator for direct assignment
is one. The ! operator is another. The == and != operators measure equality
and can't be overloaded, but ~= and ~! for equivalence can be. It would also
be meaningless to override the ternary ? : operator pair, and the . and :
family of operators for accessing vars and procs.
Comparison operators come in opposing pairs: ~= vs ~!, < vs >=,
> vs <=. You only need to override one operator from each pair; DM is
smart enough to know that !(A ~= B)
is the same as A ~! B
.
By the same logic, you don't have to define the assign-with-side-effect
operators like += if you don't want to. For instance if you override + but not
+=, then A += B will be handled internally as A = A + B, which means the value
of A after the statement may be a different datum than A was before. The value
of A can also change if you do overload += but the proc returns a value
other than null; its return value will be the new A.
If an overloaded proc is not available for an operator you try to use on
a datum, a runtime error may result.
The output and input operators are given special treatment. If no overload
is defined for the current left-hand-side value, the overload proc is looked
up under world
instead. The world overload proc is also a
fallback if ..() is called, and after that ..() does the default behavior.
These procs are always called with two arguments, to distinguish them from
bitwise shift operators.
.. proc
- See also:
- . proc
- Format:
- ..(Args)
- Returns:
- The return value of the parent proc.
- Args:
- The arguments to pass to the parent proc. This defaults to the
arguments to the current proc.
If object O is derived from object P, P is called the parent of O. If a
proc (or verb) is defined in both O and P, O can call P's version by using
..().
Example:
mob
P
verb/history()
world << "P"
O
history()
world << "O"
..() // call P.history()
Here O is derived from P. When P calls "history", his name is
displayed. When O calls "history", his name is displayed, followed by the
name of his parent, P.
If O overrides the same proc more than once, ..() will search for the
previous version and use that. For instance, you could have two O.history()
procs; the second overrides the first, but the original could still be called
via ..(). The original in turn could call ..() to reach P.history().
Overriding the same proc more than once in the same type should be avoided
wherever possible, because it incurs extra overhead, it makes the code
harder to read, and it isn't always clear which one gets called first.
(Usually, the only time you'll want this to happen is when using libraries.)
..() can also be used for predefined procs.
Example:
mob/Move() // override proc
world << "moving..."
return ..() // call default
This proc will print "moving..." whenever
the mob moves.
animate proc
- See also:
- vars (atom)
- Format:
- animate(Object, var1=new_value1, var2=new_value2, ..., time, loop, easing, flags)
- animate(var1=new_value1, var2=new_value2, ..., time, easing, flags)
- animate(Object)
- Args:
- Object: The atom, image, or client to animate.
- var1=new_value1, var2=new_value2, ...: Vars to change in the animation step.
- time: Time of this step, in 1/10s.
- loop: Number of times to show the animation, or -1 to loop forever
- easing: The "curve" followed by this animation step
- flags: Flags that impact how the animation acts
This proc creates an animation sequence that will be displayed to players.
Starting with an atom or image, you can change one or more vars that affect
its apprearance. This change will take place immediately, but will be
displayed to users as a gradual change over a period of time. The actual
interpolation between frames is all done on the client.
If the Object argument is left out, a new animation step will be created
for the last object that was animated. If all other arguments are left out,
this is tantamount to saying you want to start a new animation that does
nothing, effectively ending the animation entirely.
Example:
mob/proc/GrowAndFade()
// expand (scale by 2x2) and fade out over 1/2s
animate(src, transform = matrix()*2, alpha = 0, time = 5)
obj/spell/proc/Spin()
// cast a spell on a monster: make the icon spin
// this animation takes 3s total (6 ticks * 5)
animate(src, transform = turn(matrix(), 120), time = 2, loop = 5)
animate(transform = turn(matrix(), 240), time = 2)
animate(transform = null, time = 2)
The following vars will animate smoothly:
- alpha
- color
- infra_luminosity
- layer
- maptext_width
- maptext_height
- maptext_x
- maptext_y
- luminosity
- pixel_x
- pixel_y
- pixel_w
- pixel_z
- transform
These vars can be changed, but will change immediately on each step rather than smoothly:
- dir
- icon
- icon_state
- invisibility
- maptext
- suffix
Easing
Animation doesn't have to be strictly linear. Some changes look much better if they follow a curve. A cubic curve, for instance, will start slow, accelerate very quickly in the middle, and slow down again at the end. A sine curve could be used with a flip transformation to make a coin appear to spin. A text bubble can jump into place and bounce a little before it settles. The choice of curve you use is called easing, and you have several good choices to pick from.
- LINEAR_EASING: Default. Go from one value to another at a constant rate.
- SINE_EASING: The animation follows a sine curve, so it starts off and finishes slowly, with a quicker transition in the middle.
- CIRCULAR_EASING: Similar to a sine curve, but each half of the curve is shaped like a quarter circle.
- QUAD_EASING: A quadratic curve, good for gravity effects.
- CUBIC_EASING: A cubic curve, a little more pronounced than a sine curve.
- BOUNCE_EASING: This transitions quickly like a falling object, and bounces a few times. By default this includes EASE_OUT, unless you combine with EASE_IN, EASE_OUT, or both.
- ELASTIC_EASING: This transitions quickly and overshoots, rebounds, and finally settles down. By default this includes EASE_OUT, unless you combine with EASE_IN, EASE_OUT, or both.
- BACK_EASING: Goes a little bit backward at first, and overshoots a little at the end.
These can be combined with EASE_IN or EASE_OUT using the | operator, to use just the first or last part of the curve.
Example:
obj/coin/proc/Spin()
var/matrix/M = matrix()
M.Scale(-1, 1) // flip horizontally
animate(src, transform = M, time = 5, loop = 5, easing = SINE_EASING)
animate(transform = null, time = 5, easing = SINE_EASING)
obj/speech_bubble/New(newloc, msg)
icon = 'bubble.dmi'
var/obj/O = new
O.maptext = msg
O.maptext_width = width
O.maptext_height = height
overlays = O
// start below final position and jump into place
pixel_z = -100
alpha = 0
animate(src, pixel_z = 0, alpha = 255, time = 10, easing = ELASTIC_EASING)
Flags
Any combination of these flags may be used for animation (use + or | to
combine them):
- ANIMATION_END_NOW
- Normally if you interrupt another animation, it transitions from its
current state. This flag will start the new animation fresh by bringing
the old one to its conclusion. It is only meaningful on the first step
of a new animation.
- ANIMATION_LINEAR_TRANSFORM
- The transform var is interpolated in a way that preserves size during
rotation, by pulling the rotation step out. This flag forces linear
interpolation, which may be more desirable for things like beam effects,
mechanical arms, etc.
- ANIMATION_PARALLEL
- Start a parallel animation that runs alongside the current animation.
It may affect the same vars, or different vars. This can for instance
let you animate pixel_y in a separate way from pixel_x. (When using this
flag, the src var may be included, but it is optional.)
- ANIMATION_RELATIVE
- The vars specified are relative to the current state. This works for
maptext_x/y/width/height, pixel_x/y/w/z, glide_size, luminosity, layer,
plane, alpha, transform, and color. For transform and color, the current
value is multiplied by the new one. Vars not in this list are simply
changed as if this flag is not present.
Filters
Filters can be animated too. If you want to
animate a filter, you need to specify the filter to be animated. If the last
call to animate() used the same object as this filter, or a different filter
for that object, then this will be treated as a new step in the same
animation. Likewise, if the last animate() call was to a filter, and this call
is for the object that filter belonged to, again it will be treated as a
continuation.
Example:
atom/proc/BlurFade()
filters += filter(type = "blur", size = 0)
// Animating a filter of src
animate(filters[filters.len], size = 5, time = 10)
// Switching back to src to animate the next step
animate(src, alpha = 0, time = 2.5)
arglist proc
- See also:
- arguments (proc)
- call proc
- list proc
- Format:
- arglist(List)
- Args:
- List: a list to be used as the arguments to a procedure
Normally, if you were to pass a list directly to a procedure, it would only
come through as a singe argument to that procedure. In some cases, you might
instead want the items in the list to become the arguments to the procedure.
That is what arglist()
achieves.
If the items in the list are associations, these are treated as
named arguments. Each such list item is
matched against the names of the procedure arguments and its associated value
is assigned to that parameter.
Most built-in DM instructions do not support use of
arglist()
, but all user-defined procedures automatically
support it. The built-in instructions which support named arguments will also
support arglist()
.
The following example shows how to use arglist()
with both
positional parameters and named arguments. Both of these examples could be
replaced by a much simpler direct call without need for a list to hold the
arguments; this is just to illustrate the syntax.
Example:
proc/MyProc(a,b)
usr << "MyProc([a],[b])"
mob/verb/test()
var/lst = list(1,2)
MyProc(arglist(lst)) //MyProc(1,2)
lst = list(b=2,a=1) //just to illustrate that order does not matter
MyProc(arglist(lst)) //MyProc(b=2,a=1) --> MyProc(1,2)
named arguments (proc)
- See also:
- New proc (atom)
- arglist proc
- arguments (proc)
The parameters passed to a procedure are called arguments. These may
either be passed in positional order, or they can be passed as named
arguments. Not all procedures are defined with the intention of
supporting named arguments, so consult the documentation for the procedure in
question first. (This is mainly an issue of whether the argument names might
change in the future.)
The following example shows several ways of producing the same call to a
procedure.
Example:
mob/proc/MyProc(a,b,c)
src << "MyProc([a],[b],[c])"
mob/verb/test()
MyProc(1,2,3) //positional parameters
MyProc(a=1,b=2,c=3) //named arguments
MyProc(1,b=2,c=3) //positional and named arguments
MyProc(c=3,a=1,b=2) //named arguments can come in any order
To prevent silent errors, named arguments that do not match any of the
arguments of the procedure being called will generate a runtime error. This
is somewhat different from the behavior of positional arguments in DM where it
is perfectly acceptable to pass more arguments than were explicitly defined in
the procedure.
As always, arguments that are not assigned in the call will simply be given
the value null (or whatever default value is specified in the definition).
When an object procedure is overridden, the variable names in the new
definition are the ones that get matched against named arguments in a call to
that procedure. A procedure which is intended to support named arguments
should therefore be defined with care so as to conform to the interface
expected by users of the procedure. That doesn't stop you from changing that
interface when overriding a procedure, but the normal case would be to
preserve the argument names of the base procedure when overriding it.
The following example is not useful, but it illustrates a situation where a
procedure is overridden so as to preserve the same argument names and
positions. As mentioned above, you are not required to preserve
either the names or positions, but that is usually what you want.
Example:
mob
proc/MyProc(a,b,c)
usr << "mob.MyProc([a],[b],[c])"
mob/verb/test()
MyProc(a=1,b=2,c=3)
special_mob
MyProc(a,b,c,d)
if(d) ..() //pass in same order
else ..(c,b,a) //pass in reverse order
test()
MyProc(a=1,b=2,c=3,d=0) //normal order
MyProc(a=1,b=2,c=3,d=1) //reverse the order
This example merely used positional parameters in the call to
..()
, but one can use named arguments there too if it is
desirable.
The best time to use named arguments is when calling a procedure that takes
a lot of optional parameters. You can just name the ones that you want to
assign and leave the rest unspecified. Trying to do the same thing with
positional parameters can be much more awkward--especially when the arguments
you do want to assign are preceded by a number of ones that you don't care to
assign. It's easy to lose your place in the list or to forget what it does.
Since named arguments involve a slight amount of extra overhead, one should
avoid them in code that is highly cpu intensive due to being called many many
times. Otherwise, code clarity may be a bigger priority.
bounds proc
- See also:
- bound_x var (movable atom)
- bound_y var (movable atom)
- bound_width var (movable atom)
- bound_height var (movable atom)
- step_x var (movable atom)
- step_y var (movable atom)
- locs list var (movable atom)
- obounds proc
- Pixel movement
- bounds var (client)
- Format:
- bounds(Ref=src, Dist=0)
- bounds(Ref, x_offset, y_offset, extra_width=0, extra_height=0)
- bounds(x, y, width, height, z)
- Returns:
- A list of atoms within the given bounding box.
- Args:
- Ref: A turf, obj, or mob.
- Dist: A number (distance in pixels).
- x_offset, y_offset: Shift to bounding box position (from Ref's bounding box)
- extra_width, extra_height: Adjustment to bounding box size (from Ref's bounding box)
- x, y, z: Lower left corner of bounding box in absolute coords; x=1,y=1 is lower left of map
- width, height: Size of bounding box in absolute coords
To leave Ref out of the results, use obounds() instead.
Calling bounds() will default to bounds(src,0), if src is a turf, obj, or
mob. This returns all turfs, objs, and mobs (including src) within src's
bounding box.
Changing the distance will return all objects within that distance from the
bounding box. E.g., bounds(turf,12) will show you everything within 12 pixels
of that turf.
An object's bounding box can also be offset. bounds(src,-6,0) shows what src
would touching if it moved 6 pixels west. bounds(turf,-12,-12,24,24) is
equivalent to bounds(turf,12).
In the final form, bounds() can use absolute coordinates and does not need
an object to be Ref. Absolute coordinates start at 1,1 at the lower left corner
of the map, by tradition.
browse proc
- See also:
- << output operator
- browse_rsc proc
- file proc
- link proc
- run proc
- output proc
- Format:
- usr << browse(Body,Options)
- Args:
- Body: html text, file, or null to close the browser.
- Options: optional parameters
This sends the html text or file to the user and optionally displays it in
the web browser. The default action is to use the embedded browser panel in the Dream
Seeker window; specifying an alternate window name (see below) causes it to appear in a
popup window. Passing in 'null' for the html text causes the browser panel or named
window to be closed.
The option parameters should either be omitted or they should be in a text
string of the following format:
"window=name;file=name;display=1;
size=300x300;border=0;can_close=1;
can_resize=1;can_minimize=1;titlebar=1"
You may use commas (,), ampersands (&), or semicolons (;) as the
delimiter. Any or all of the parameters may be specified and they may be
included in any order.
General options
These control how to handle the text or file.
- window
- This is the name used to identify the popup window. It is not visible to
the user. Multiple calls to browse() with the same window name overwrite
previous contents of the same popup window. If window is not specified, the
embedded browser panel will be used.
- file
- When this is unspecified, the client will store the generated html file in the
user's byond "cache" directory with an appropriate name. If Body is a
text string, the client will generate a unique name. If it is a file, it will use
the name of the file. You can override this by setting this parameter. This is
only useful when you need to reference the file later, typically in tandem with the
display setting below.
- display
- This controls whether the browser actually displays Body in the web browser
or not. If it is turned off (display=0), the text or file is simply sent
to the user and expected to be referenced later. This might be useful, for instance, to first send an image to a user and then display a web page that uses that image:
usr << browse('monster.png',"display=0")
usr << browse("
A scary monster appears from the mist!")
Note that this performs the same function as the browse_rsc proc (preserved for legacy reasons). It is a little more powerful because you can use
it to send html text as well as files. In that case, you'll have to also supply the file=name argument so that you can reference the html text from within a later browse().
When display=0, all of the other arguments besides file are ignored.
Popup options
These control how the popup window initially appears. Setting these parameters for
an existing popup window or the embedded browser has no effect.
- border
- This is the width of the border between the edges of the dialogue and the window
content. The default value is 0, meaning that the entire window is filled with
html content.
- size
- This is the size of the popup window in pixels. The format is
WIDTHxHEIGHT
.
- can_close
- This specifies whether the window should be closable. The default value
is 1, which enables the standard "X" button for closing.
- can_resize
- This controls whether the window is resizable. The default value is 1,
enabling resizing and maximizing.
- can_minimize
- This controls whether the window is minimizable. The default value is 1,
enabling the standard minimization button.
- titlebar
- The default titlebar=1 enables the standard bar at the top of the window.
Turning it off disables can_close and can_minimize.
Note also that many display options can be controlled through the html
itself. For instance, to turn off the scrollbars, you can do:
<body scroll=no>
; to add a title, you can do:
<head><title>My Title</title></head>
; and so forth.
The following example displays a help page in a popup window.
Example:
var/const/help = {"
Help!
You are beyond help!
"}
client/verb/help()
usr << browse(help,"window=help")
You can use commands like