Это 11 глава перевода оригинального руководства по Dream Maker от разработчиков.

Остальные главы руководства и статьи о программировании на коде BYOND от любителей на русском.

Оригинальная 11 глава руководства на английском языке

В разработке…


Jobeng.png
Данная статья помечена как неоконченная. Это означает, что статья находится на доработке, поэтому является неверной или неактуальной.

Вы можете помочь проекту Onyxyeye@256x256.png Onyx и сообществу Animus-logo.png SS13 в целом — зайдите на наш Bus Mainframes.gif Портал сообщества.
Также вы можете прочитать эту статью на зарубежном вики-проекте.


Глава 11

Ввод\вывод Пользователя

Взаимодействие с пользователем - это главная цель любых программ в Dream Maker и эта глава описывает основы языка, отвечающего за ввод и вывод информации.


Ввод

Есть два основных пути получения информации от игрока. Первый - ввод по запросу клиента(игрока), второй - ввод по запросу сервера(игры). Разница в том, посылает ли игрок информацию на обработку, или игра запрашивает необходимую информацию.


Операторы (verbs)

До сих пор весь ввод был со стороны пользователя. Игрок может написать команду, нажать кнопку управления, щёлкнуть на объект и т.д. Эти виды ввода информации однородны, так как ими управляют одинаковые операторы(verbs). То есть нажатие на кнопку влево вызывает определённый процесс и задаёт ему значение "кнопка влево".

Есть несколько заранее определённых операторов(verbs), принимающих ввод информации от игрока. Это кнопки направления\стрелки (напр. client.North()), щелчок мыши ((client.Click() и client.DblClick()) и ссылки топиков (client.Topic()). Все остальные операторы(verbs) задаются программистом.

Общий вид для определения оператора(verb) следующий:

verb/Name(Arg1 = default input-type in List,...)

Количество аргументов может быть любым. Каждый из них может иметь значение по умолчанию, тип ввода и список допустимых значений.

Инструкция ввода

Инструкция ввода - это то, что позволяет вам(со стороны игры) запросить у игрока информацию ввода. На ней построены все взаимоотношения сервера с клиентом. Она похожа на простой одиночный оператор(verb).

>input(User=usr,Message,Title,Default) input (User,Query,Title,Default) as input-type in List

User - это имя игрока(моба). Query - текст запроса ввода. Title - текст отображения запроса ввода. Default - значение по умолчанию для данного запроса. input-type - тип ввода информации. List - список возможных значений для данного запроса. Исполнение данного оператора задаёт значение введённое игроком.

Всё, кроме текста ввода - необязательные опциональные параметры. User ассоциируется с usr, и обращается к нему. Если input type не задано, то тип ввода информации будет текстовым по умолчанию.

Обратите внимание, что инструкция ввода не будет запрошена, пока пользователь не введёт значение. При поддержки многопользовательской системы ожидать ответа от одного пользователя невозможно, поэтому при запросе ввода информации в режим ожидания входит только текущая исполняемая процедура.

Инструкция ввода для игрока выглядит как запрос ответа на сложившуюся ситуацию. В таком случае простое применение оператора(verb) было бы слишком неточным для определения дальнейших действий игры. Следующий код показывается пример подобного случая:

mob/proc/Die()
if(!key) //NPC
del src
else //PC
loc = null //покидает игру
var/again = input("Играть снова?") in list("Да","Нет")
if(again == "Да")
Login() //возвращается в игру
else
del src

Когда вызвана процедура Die(), игрокам будет выдано сообщение - желают ли они продолжить игру. Если они отвечают "Да", то они возвращаются обратно в игру, в противном случае - нет. (Пример, конечно, довольно грубый, но вполне наглядный.)

Output

All output is generated by the << operator. This sends the specified output to one or more players.

Target << Output The target may be a single object or a list of objects. Any non-mob target will be replaced by its contents. This allows you to send output to a region on the map or to a room, and all the players inside will receive it.

There are several different types of output. In many cases, the way the output should be handled is automatically detected from the type of data provided. Several instructions for producing various types of output are listed in the following table. In addition to these instructions are some which further clarify how the output should be treated when the type of data alone is not enough to determine this.

Figure 11.16: Output Methods

text()

file() image() browse() sound() ftp() run() link() The first group of instructions produce various types of data for output or other purposes. The second group are only meaningful for directly producing output. All of these instructions are described individually in the following sections. The general format for using them is the same.

Target << Method(Output)

text output

A text output value is displayed in the client's scrolling terminal window. The text value may be the result of any expression. Frequently, it is a text string with embedded expressions inside it. Although it is not necessary to use the text instruction for this purpose, one reason for doing so is to use trailing rather than directly embedded expressions.

text (Text,Arg1,Arg2,...) Text is the text string with expression markers. Args are the expressions to insert. Returns text with arguments substituted in. The position in the text where a trailing argument will be inserted is marked with empty brackets [ ]. The substitution arguments are then listed in the same order as the expression markers.

For substituting short expressions into the text, it is convenient to simply embed them directly. However, many lengthy expressions embedded into a text string can make it difficult to read. In that case, trailing expressions may be the better choice. The two methods can be mixed as desired.

The following two versions of a look verb are equivalent.

mob

  var/money = 2
  verb/look1()
     set src in view()
     usr << "[src] has [contents.len] items and [money] buffalo chips."
  verb/look2()
     set src in view()
     usr << text("[src] has [] items and [] buffalo chips.",
                  contents.len,
                  money)

Note that the text instruction is not limited to being used as an output method. It may be used anywhere you wish to use trailing expressions with a text string.


browse output

The browse output method displays text output in a pop-up window. This is intended for viewing longer text documents. If treated as normal terminal output instead, the user might have to scroll back up to find the top of the message.

browse (Doc, Options) Doc is the message to display. Options are various window-specific options. Consult the reference for specifics. By default, each message replaces any previous message being displayed but the user can move back to previous messages stored in the client's memory. In many ways, the client terminal behaves like a telnet session and the browse window behaves like a web browser. One displays output sequentially in a continuous stream. The other displays it in discrete chunks--one document after another. The two are each useful in different situations.

The document is often a text string. However, it may be a file instead. The type of file will determine how it is handled. Files may reside in the resource cache or in the file system. As always, cached items may be specified by putting the file name in single quotes. An external file, on the other hand, is indicated using the file instruction described in section 11.2.7.

The browse output method is often used in conjunction with the message input type. One allows the composition of messages and the other displays them.

The following example defines a message scroll. Players can write poetry on it in moments of inspiration.

obj/scroll/verb

  write(msg as message)
     desc = msg
  read()
     usr << browse(desc)

sound output

The sound output method plays a sound to the player. Either wav or midi sound files may be used, usually for short noises and music respectively. Such files are treated this way by default, but the sound instruction can be used to control how the sound is played.

sound (File,Repeat) File is the sound file to play. Repeat is 1 to play sound repeatedly. A repeated sound is played in the background while other sounds are played in the foreground. Only one background sound and one foreground sound may be played at a time, so subsequent output replaces any previous sound with the same repeat setting. To stop a sound, specify null as the file.

Background music is often repeated while occasional noises play in the foreground. The following example defines a background sound for each area.

area

  var/music = 'default.midi'
  Enter()
     . = ..()
     if(.) usr << sound(music,1)

The line . = ..() is commonly used when you want to return the same value as the parent proc but you need to do something after finding out what that value is. That way, if the user is refused access to the area for some reason, the music will not be played.


image output

The image instruction is used to create a purely virtual object. It may appear at the specified location to selected players, but it corresponds to no real data object.

image (Icon,Loc) Icon is the icon or object type to use. Loc is the location of the image. Returns a reference to the image. If the location of the image is something movable like a mob, it will follow the object around. The image icon is displayed in a layer above everything else, so it is best suited for special effects like a selection box, burst of fire, etc.

The image instruction may be used outside the context of the output instruction. In this case it returns a reference to the image but does not actually display the image to any players. This reference can be sent as output and may be deleted later to destroy the image.

The following example allows the player to select an enemy by clicking on it. The currently selected enemy is outlined with an image.

mob/var

  mob/enemy
  enemy_marker

client/Click(mob/M)

  if(istype(M))
     del usr.enemy_marker
     usr.enemy = M
     usr.enemy_marker = image('outline.dmi',M)
     usr << usr.enemy_marker

The code works by first deleting any old enemy marker. A new one is then made and displayed to the user. No one else will see the image--only the player who clicked on the enemy.


ftp output

The ftp output method sends a file to the player. This complements the file input type which allows the player to send a file to the server. The terminology normally used is that a file is uploaded when it is input and downloaded when it is output.

ftp (File,Name) File is the file to send. Name is the optional suggested file name. The file to send may be either a resource file (in the cache) or a file in the file system. The difference is whether the file is specified in single or double quotes. A file in single quotes will be loaded into the resource cache at compile-time. A file in double quotes will be accessed from the file system (i.e. hard-disk) at run-time. The latter might be useful if you need to update the file periodically without recompiling.

The suggested file name defaults to the name of the file being sent. This is used as the default name when the player chooses where to store the file. If the player decides not to download the file, it is always possible to cancel at that point or during the transfer.

The following example sends a help file to players when they click on the appropriate topic.

client/Topic(T)

  if(T == "help")
     usr << ftp("help.txt")

mob/Login()

  ..()
  usr << "Download the  help file  if you are new here."

For this to work, the file "help.txt" must exist in the current directory of the server. This can be assured by putting it in the same place as the dmb file. Since the file was specified in double quotes, it will be accessed at run-time rather than compile-time. That means you are free to edit it at a later date.

The HTML tag <A HREF...> is used to embed a hyperlink in some output text. It will be described in section 11.4.3.


run file output

The run output method is like ftp except it displays or executes the specified file rather than saving it to disk. The action taken depends on the type of file. For example, HTML and jpeg files might be shown in the player's web browser.

run(File) Obviously it would be a severe security risk to players if executable files could be run without their authorization. Viruses and other malicious programs could be released onto their computer just by connecting to a game. For this reason, players are asked before executing any potentially dangerous file. That is the default behavior. The player can configure the client to always or never run files if they choose. A similar choice can be made about downloading files.

The previous example which gave the player a help file could easily be changed to instead display the file. If the player wishes, it would still be possible to save the file to disk.

client/Topic(T)

  if(T == "help")
     usr << run("help.txt")

file output

The file instruction returns a reference to a file object. It takes the file's path (in a text string) as an argument. The output methods browse, ftp, and run can all take a file reference as an argument. In the case of browse it is necessary to use file to distinguish between a text message and a file name. In the case of ftp and run it is not necessary to use file because the name of the file may simply be used directly. If no output method is specified for a file, it is implicitly handled by run.

file (Path) Path is the name of the file. Returns a reference to the file. The path may be absolute or relative to the server's working directory, which is the same directory that contains the world .dmb file. Since this is evaluated at run-time, the file need not exist until the statement is actually executed. This is different from cache file references (in single quotes) which are evaluated at compile-time. For more uses of the file object, see section 17.6.


link output

The link output method is like run except it executes a URL rather than a file. The URL could be a web address, a BYOND address, or a topic link.

link (url) url is the URL to execute. The beginning of the URL specifies the communication protocol. If the URL begins with "byond://" then it is treated as a BYOND address. This is the default protocol if none is specified. A URL beginning with "#" is a topic link. Other protocols (like "http://" are handled by the player's web browser.

A BYOND link causes the player's client to reconnect to the specified address. Topic links merely cause the specified topic to be accessed in the current world (by calling client.Topic()). A web link causes the web browser to switch to the specified URL.

The general format for a BYOND address includes a server address and topic.

byond://server#topic The topic is optional and is only used in rare cases like servers with multiple entry points. The server address may be either the name of a registered server or the network address in the form ip:port. The IP address would either be raw network numbers (e.g. 123.456.789.123) or the corresponding machine name (e.g. dantom.com). The port number is the network port on which the server is running. This is reported when the server starts up.

By default, players are asked whether they accept links activated in this manner. They can, however, configure the client to always or never accept them.

The link output method is very similar to the hyperlink text tag which has already been introduced. They both can take the same types of URLs and act upon them in the same manner. Hyperlinks embedded in text are normally used to provide access to optional information. The link output method, on the other hand, is useful when the player's action has already indicated desire to follow the link.

For example, a link from one world to another could be activated by entrance into a special turf.

turf/wormhole/Enter()

  usr << link("byond://WormWorld")
  return 1

This example assumes the existence of a world registered under the name "WormWorld". Running and registering a networked world will be discussed in chapter 12.


Text Macros

Both input and output text may contain special codes that are not displayed literally but which are replaced by some other text. These are called text macros and begin with a backslash \ and may end with a space (which is ignored). They are summarized in the following sections.


Expression Modifiers

Figure 11.17: Text Macros for use with Expressions

\the, \The

definite article if needed \a, \an, \A, \An indefinite article if needed \he, \He, \she, \She he, she, they, it \his, \His his, her, their, its \hers his, hers, theirs, its \him him, her, them, it \himself, \herself himself, herself, themself, itself \th 1st, 2nd, 3rd, ... \s 1 dog, 2 dogs, ... The first group of text macros work in conjunction with an embedded expression. The article macros precede the expression and the others follow it. Any amount of text and even inapplicable expressions may exist between the macro and its associated expression.

The articles and various pronouns work with object or text expressions. The plural and ordinal macros \s and \th are used with numerical expressions. If no expression of the appropriate type is found, these macros do nothing.

An embedded object is replaced by a definite article and its name. In other words, the following two are equivalent:

"[usr] smiles." "\The [usr] smiles." These could produce "Andrew smiles." or "The cat smiles." depending on the name of the user.

Note that the articles may be supplied in either capitalized or lowercase form. The implicit definite article is automatically chosen in capital form if preceded by a period. If that is incorrect, you can specify the desired form explicitly.

If an indefinite article is desired instead of the default definite one, it must be explicitly specified. If no article at all is desired, the name can be embedded directly in place of the object.

The following example uses an indefinite article instead of a definite one when a mob picks up an object.

obj/verb/get()

  set src in view(0)
  view() << "[usr] picks up \a [src]."
  Move(usr)

It doesn't matter whether you use "a" or "an" in the macro. The appropriate one will be chosen for the word that follows. It is common to use whichever one makes the code more readable.


Proper Nouns

There are two special text macros for controlling whether the name of an object is considered to be a proper noun or not. These are \proper and \improper. By default, if the object name is capitalized, it is assumed to be proper, and otherwise it is assumed to be improper. To override this, you can put \proper or \improper at the beginning of the object's name.

As you have seen in the preceding section, the difference between proper and improper nouns is that articles are suppressed in front of proper nouns. For example, if you had something called a "BYOND dime," you would need to use the \improper macro as follows:

obj/BD

  name = "\improper BYOND dime"

mob/verb/get(obj/O in view(0))

  usr << "You pick up \an [O]."
  O.Move(usr)

Since we used \improper in this example, somebody picking up a BYOND dime would see, "You pick up a BYOND dime." rather than "You pick up BYOND dime."


Numerical Expressions

There are macros which depend upon the preceding numerical expression. The \th macro produces the ordinal ending for the supplied number. For the number 1, it produces "st" to make "1st", for the number 2, "nd" and so on. From 4 and on it produces "th", which is where it gets its name.

The \s macro produces "s" if the preceding numerical expression is not equal to 1 and nothing otherwise. This is useful for making plurals like "You have [count] coin\s.".


Special Characters

Figure 11.18: Special Character Macros

\"

double quote \\ backslash \< less than \> greater than \& ampersand \n newline \... suppress newline at end \(space) skip a space There are a few special characters that may not be directly entered into a text string. These must be escaped by preceding them with a backslash. This forces the special meaning to be ignored and the literal character to be inserted instead.

The double quote, for example, must be escaped or it would prematurely end the text string.

mob/verb/say(msg as text)

  view() << "[usr] says, \"[msg]\""

Newlines

A newline may be inserted with the \n macro. The compiler does not allow direct insertion of newlines in a text string because this is often a mistake resulting from a missing end quote. You can continue a lengthy text string onto the next line by escaping the newline, but then the newline is entirely ignored.

There is an implicit newline inserted at the end of all output text. This means that instead of using the \n macro directly, the text can simply be broken up into individual lines which are output one at a time.

In some cases, you may want to suppress the implicit newline at the end of the text. This can be done with the \... macro. By putting it at the end of the text, subsequent output will start on the same line where the previous one left off.

A newline is actually an end-of-paragraph marker. It should not be used inside the paragraph to make lines fit the screen because not everyone's terminal will be the same width. It is best to let the terminal automatically handle word-wrap within paragraphs and reserve the newline for marking the end of it.


Text Formatting Tags

Text may be formatted by inserting HTML elements, more commonly known as tags, that control its appearance. DM understands a subset of HTML tags, consisting of the most commonly used elements.

A tag is surrounded by < > angle brackets. The first thing inside the brackets is the name of the tag. Many tags come in pairs--one to start an effect and another to end it. The end tag has the same name as the start tag except it starts with `/'. Tag names are not case sensitive.

The following example displays some text in bold.

"I am very mad!" The start tag turns on bold lettering and turns it off. For a complete list of tags understood by DM, see page 3 in the appendix. The most commonly used ones are listed in figure 11.19 for easy reference.

Figure 11.19: Common text tags

<A></A>

anchor (for hyperlinks) bold bigger text
line break font face, size, and color italic

paragraph

overstrike smaller text typewriter style underline

preformatted whitespace

<XMP></XMP> literally preformatted text <BEEP>

make a beeping sound

Whitespace

Whitespace refers to any spaces, tabs, or newlines. In standard HTML, whitespace serves merely to delimit words. The amount of space and whether it is a tab, space, or newline is irrelevant.

DM processes whitespace like standard HTML when it is inside of a pair of start and end tags. So, for example, inside of

and

, the paragraph markers, standard HTML rules are in effect; newlines, spaces, and tabs serve merely to delimit words. Note that an entire document could be surrounded by <HTML> and </HTML> to mark the whole thing as standard HTML.

Outside of all HTML tags, DM handles whitespace a little differently. Spaces still delimit words, but newlines (embedded with \n) mark the end of lines. In other words, the newline is automatically converted to
, the linebreak tag. That is convenient for use in messages composed by players when it would be annoying to write formal HTML with paragraph tags and so forth.


Fonts

The tag is used to control various characteristics of the font being used. It takes additional arguments in the form of attributes.

For example, to make the font much bigger, you could use the start tag . The name of the attribute in this case is SIZE, and its value is +3, which makes the font three sizes bigger. You can put quotes around the attribute value if it contains any spaces. In this case there was no need.

The attributes of are FACE, SIZE, and COLOR. You can use as many of these attributes in one tag as you like. Just separate each attribute assignment by some space like this: <FONT SIZE=+3 COLOR=red>. The nuances of these three tags are discussed in the following individual sections.


FACE attribute

The FACE attribute selects the name of the font you wish to use. It may be a single font (such as InnoDBl) or a comma-separated list (such as InnoDBl,Helvetica). If the user doesn't have a font with the same name on their system, the next font will be tried. Remember to put quotes around the attribute value if it contains any spaces.


SIZE attribute

The SIZE attribute changes the size of the text. It can be a relative change, like +3, or an absolute size, such as 5. Font sizes are numbered from 1 to 7, with 1 being the smallest and 7 being the largest. Each increment is roughly 1.5 times the apparent size of the previous one.


COLOR attribute

The COLOR attribute selects the foreground color of the text. It may be either a color name or a hexadecimal RGB value.

RGB stands for red, green, and blue, the three primary colors from which all the others can be produced. Hexadecimal is a base-16 number system commonly used by programmers for specifying binary values. The hexadecimal digits are 0 to 9 and A to F, a full four bits of information. Lowercase letters may be used as well.

Each primary color is given a range of eight bits. Therefore it takes exactly two hexadecimal digits to specify a single component and six digits to specify a complete color value. The first two digits are for red; the next two are for green; and the last two are for blue (hence RGB). The color black is 000000, which has all three colors turned off. The color white is FFFFFF with all three colors at their maximum intensity.

The following two lines are identical:

"This is red." "This is red." Notice that a # symbol is placed in front of the numeric color value to indicate that it is a hexadecimal value. Otherwise, a color name is expected. If you can't find the color you want in the list of named colors, find the closest one and tweak the intensities to your satisfaction.

Figure 11.20: Named Colors

black

  1. 000000

silver #C0C0C0 grey #808080 white #FFFFFF maroon

  1. 800000

red #FF0000 purple #800080 fuchsia #FF00FF green

  1. 00C000

lime #00FF00 olive #808000 yellow #FFFF00 navy

  1. 000080

blue #0000FF teal #008080 aqua #00FFFF It is also possible to enter color components as 4 rather than 8 bit numbers. In that case, only three hexadecimal digits are required rather than six. Internally, the color is converted to full 8 bit notation by repeating each digit. For example, black #000 becomes #000000, white #FFF becomes #FFFFFF, and red #F00 becomes FF0000.


Hyperlinks

The <A> tag is used to mark a particular spot (or anchor) in the text. In DM, you use it to insert a clickable hyperlink. To specify the destination URL of a link, use the HREF attribute.

"<A HREF='#topic'> click here </A> ..." The form of the URL is the same as the link output method described in section 11.2.8. It may be either a BYOND address, a topic link, or a web address.

The TITLE attribute may be assigned to a description of the link. It is made visible when the user holds the mouse over the link.


Style Sheets

HTML tags, such as may be used to directly format output text. Another approach, however, is to use HTML tags to specify purely structural information and use a style sheet to define how various elements within that structure should be treated. DM uses a subset of the Cascading Style Sheet (CSS) language, which was introduced for this purpose in HTML documents.

As an example of a style sheet, suppose one wanted combat and conversational messages to appear differently--perhaps using different colors. Instead of using the tag to color the text, you could use to mark the beginning and ending of the text and to specify what kind of message it is. The result might be text such as the following:

"[usr] spanks [targ]!" "[usr] says, '[msg]'"

The CLASS attribute may be used with any tag, but the generic containers SPAN and DIV are often convenient because they have no other side-effect. is for text within a single paragraph and
is for whole paragraphs. The way text belonging to a particular class is formatted may be controlled in a style sheet such as the following:


This says that text in the `combat' class should be colored red and text in the `chat' class should be colored green. These classes are not pre-defined; they were just made up to suit the situation. You can invent as many new classes as you like.

In order to make this style sheet take effect you have several options. One is to put it in a text string (double quotes) and assign it to client.script. This will load the style sheet when the player connects. You could accomplish the same thing by putting the style sheet in a file and assigning the file (in single quotes) to client.script. It is also possible for a player to put the style sheet in a client-side script file and load it that way. More will be said about DM Script, which encompasses more than just style sheets, in the appendix (page [4]).

The advantage of using style sheets instead of direct formatting tags is that you can cleanly separate structural information (such as combat and conversational messages) from formatting information (such as red and green text). By separating the two, you or the player can easily plug in different formatting schemes without changing any of the actual content.

A style sheet is composed of a list of rules, such as the two rules in the preceding example. Each rule contains one or more selectors followed by a body of attribute assignments (in braces). The selector specifies the context of the rule and the body specifies the format.


Context Selectors

A selector may specify a container tag (such as SPAN, BODY, or P) and a class. The above example could have been written with a selector of SPAN.chat. However, by leaving out the tag, it applies to any tag with CLASS=chat. It is also possible to only specify the tag and not the class. In that case, the selector applies to any matching tag, regardless of its class.

To specify a nested context, several simple selectors may be listed one after the other. For example, emphasized text within a combat message could be enlarged with the following rule:

.combat EM {font-size: larger} It is also possible to list several selectors separated by commas in order to make them all apply to the same body. For example, this next rule is equivalent to the two following ones:

.combat EM, .chat EM {font-size: larger}

.combat EM {font-size: larger} .chat EM {font-size: larger}

Style Attributes

The body of a style rule contains a list of attribute assignments, delimited by semicolons. Each assignment takes the form of an attribute name, followed by a colon, followed by the value of the attribute. Figure 11.21 summarizes the recognized attributes and sample values.

Figure 11.21: Style Attributes

color

  1. F00, #FF000, red

background same as color font-size 10pt, 1.5em, 150% font-style normal or italic font-weight normal, bold, lighter, darker, or 100 to 900 font-family monospace, sans-serif, serif, cursive, ... font style weight size family text-decoration none or underline text-align left, right, or center width 16px, 32px, auto height 16px, 32px, auto

Fonts

The font family may be a specific font name or a more general category such as monospace or sans-serif. Since not all users necessarily have the same fonts installed, it is a good idea to list alternate fonts. The desired font is placed first, followed by other possible fall-backs, each separated by a comma. Usually a general family such as monospace is listed last of all. Any font names containing a space should be enclosed in quotes.

The font attribute is a special short-hand for assigning font-size, font-style, font-weight, and font-family in one statement. Any properties that are not specified in the font statement are assigned to their default values.

The following example sets the font for the <BODY> tag. Even if you don't explicitly use <BODY> in output text, it is applied implicitly.

BODY {font: 12pt 'Times New Roman', sans-serif} This sets the font to 12 point and selects Times New Roman if it is available and otherwise falls back on a system-determined sans-serif font. This command also implicitly specifies not to use italics and normal font weight (not bold).

Font sizes may be specified in points (1pt = 1/72 of an inch), picas (1pc = 12pt), pixels (px), inches (in), centimeters (cm), and millimeters (mm). There are also various levels corresponding to the traditional 1 to 7 HTML scale. These are xx-small, x-small, small, medium, large, x-large, and xx-large. In addition to these absolute font sizes, it is possible to use a relative size, such as 150% or equivalently 1.5em. This scales the font relative to the currently active font setting.


Hyperlink Pseudo-Classes

In addition to regular stylistic classes, there are special pseudo-classes for handling embedded hyperlinks. These are specified in the selector with the class starting with a colon rather than a dot. They are :link, :visited, and :active. These only apply to the <A> tag. The :link class applies to hyperlinks in their normal state. Once a link has been clicked, it belongs instead to the :visited class. When the user holds the mouse over a link, it temporarily belongs to the :active class. The only attribute that may change in an active or visited link is the text color.


Canvas Background Color

The background attribute is only relevant to the <BODY> context. It causes the entire terminal background to change color. When doing this, it is usually necessary to change the foreground colors of text or it may become unreadable. The various standard classes of output generated by Dream Seeker are presented in figure 11.22.

Figure 11.22: System Colors

system notice

general notices from the client system command echo command echoing system command expansion command-line expansion list system pager pager messages system irc IRC command prefix 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:

BODY {background: aqua; color: black} .system {color: red; font-weight: bold} .command {color: green} 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.


Style Rule Precedence

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 Dream Seeker 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.

Finally, 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.

The important flag is applied after the attribute assignment like this:

BODY.background {

  background: white ! important;
  font: serif

} In the above example, only the background color is important, not the font specification.


The STYLE attribute

Style commands may also be inserted directly in an HTML tag to control its appearance. This does not have the advantages of independent style sheets, which separate content from presentation, but it does allow you to use the style sheet syntax when formatting text.

The following example uses the style attribute to color some text:

usr << "That HURT!" As you can see, the STYLE attribute of any tag can be assigned to a text string containing a list of attribute assignments. Just the body of the style rule is given, since no selector is needed to match the current context.


Inline Icons

The \icon text macro causes the following embedded expression to be interpreted as an icon rather than as text. For example, an object would be replaced by its icon rather than by its name.

The following example prefixes conversational text with the speaker's icon, making it easier to associate the message with the appropriate object on the map.

mob/verb/say(Msg as text)

  view() << "\icon[usr] [usr] says, '[Msg]'"

The \icon text macro expands internally to an <IMG> tag. The previous example, could be rewritten as follows:

mob/verb/say(Msg as text)

  view() << " \
             [usr] says, '[Msg]'"

From this, you can see that the object's current icon state is used. A reference to the icon itself is inserted using the \ref text macro, which generates a unique identifier corresponding to an object.

A final noteworthy point is that the image belongs to a style class called `icon'. This can be used to configure global properties of icons in the text terminal. For example, a full 32x32 pixel icon doesn't always fit in with surrounding text very well. A single style sheet rule takes care of that:

IMG.icon {height: 16px; width: 16px} This is, in fact, a built-in default rule, so you don't have to define it yourself. You could override it to get full 32x32 icons. You could even define special rules to allow icons in certain contexts to be different sizes. The and tags are ideal:

BIG IMG.icon {height: 32px; width: 32px} SMALL IMG.icon {height: 16px; width: 16px} Using the tag, you could then output a full-sized icon, even though the default is small. The following example does that when the DM speaks in order to satisfy an inflated ego.

mob/DM/say(Msg as text)

  view() << "\icon[usr] [usr] says, '[Msg]'"

Special Effects

There are a couple miscellaneous commands which create special output effects. Like the image instruction, they produce a purely visual result.


missile instruction

The missile instruction creates an image which moves from one location to another. It is often used as a symbolic indicator of the source and target of a projectile.

missile (Icon,Start,End) Icon is the image icon or object type. Start is the missile source. End is the missile destination. This could be used in a game of darts:

obj/dart

  verb/throw(mob/M)
     missile(src,usr,M)
     del src

If more realism is desired, a check could be made first to determine if there is a straight unobstructed path between the attacker and target. (However, realism (in my opinion) is much overrated. Don't let it spoil a good piece of code unless you really have to. I am sure there are many cases in which our own universe too is unrealistic because God couldn't resist a simpler way of implementing things here and there. The sky is a perfect example. I mean, it looks a bit fake sometimes, doesn't it?)


flick instruction

The flick instruction causes a temporary transition in the icon state of an object. It lasts until all the frames in that particular state have been played and then reverts to the true icon state.

flick (State,Obj) State is the icon or icon state to display. Obj is the target object. Note that it is possible to specify an entirely different icon file. Normally, however, just the state of the existing icon file is specified.

The flick instruction is often used for temporary animation sequences (like smiling, writhing in pain, etc.). These are different from changes of state which have a longer duration (like sleeping, flying, etc.). In those cases, one would simply assign the icon_state variable directly.

Sometimes, however, a flick is used in the transition between two permanent states. The following example defines a door turf which does exactly that.

turf/door

  icon = 'door.dmi'
  icon_state = "closed"
  density = 1
  opacity = 1
  verb/open()
     set src in view(1)
     if(!density) return //already open
     density = 0
     opacity = 0
     flick("opening",src)
     icon_state = "open"
  verb/close()
     set src in view(1)
     if(density) return //already closed
     density = 1
     opacity = 1
     flick("closing",src)
     icon_state = "closed"

The advantage of using icon states in this way is that the code remains very general. All the map designer has to do is plug in different icons with the same states and a variety of doors can be made from the one basic definition.

If the icon state specified by the flick instruction does not exist, it has no effect. In the above code, for example, a door icon could be used that did not have "opening" and "closing" states defined. Everything would work--only the transition would not be animated.