[MUD-Dev] Dynamic Descriptions

Christopher Allen ChristopherA at skotos.net
Fri Mar 25 18:37:33 CET 2005


On Wednesday, March 23, 2005 1:12 AM Bernard Graham <> wrote:

> Has anyone ever created a workable dynamic description-solution
> for their muds.  I am delving into this and would like to get some
> pointers and ideas.

> Things I have started to think about include having weather, time
> of day and seasons affect the description.  Also, how would you
> properly implement smells and even things like the size of a room,
> for example, if you are in a small room it might feel
> claustrophobic, whereas if you are on a road inside a town it
> might feel "open".

> If anybody has any interesting ideas I would like to hear about
> it.

We do this at Skotos through something called SAM, or skotos active
markup.  Here are two of our developer documents on SAM, we have a
number more internally, including how to create SAM tags with Merry
(our sandboxed version of LPC).

-- Christopher Allen

------------------------------------------------------------------------
.. Christopher Allen                                 Skotos Tech Inc. ..
.. <ChristopherA at skotos dot net>         2342 Shattuck Ave Ste 512 ..
.. www.skotos.net  www.rpg.net                Berkeley, CA 94704-1517 ..
.. office 510/649-4030         fax 510/849-1717     main 510-647-2760 ..


Introduction to SAM: Skotos Active Markup

The Problem of Dynamic Text

The Problem

SkotOS is largely concerned with presenting text to users. In a
dynamic, interactive system such as ours, environments and
occurances are forever changing, yet they must be described in
consistent ways, even artistic ways, to the inhabitants of the
virtual world:

   You are kneeling next to Fred in a dingy hut.  Jane stands near
   the door.  A long, black sword lies at her feet. The rain pours
   down outside.

This is a description which is clearly associated with the hut in
which we are kneeling, yet refers to current occupants, items on the
floor, and the weather outside: the description mingles static text
with dynamic data. The system's ability to do this well is
absolutely vital to making the user's experience in the world a good
one.

A Solution

Since the program that serves the user with the description is the
same one in which the dynamic data resides, there is a simple
solution to the quandry above. Let the descriptive text contain
special codes that instruct the world server to calculate and embed
dynamic descriptions. This could be part of the description of a
statue you find in a room:

   "The statue appears to be $(this.expression) at you."

This statue is alive, it turns out, and can either frown at you or
smile, depending on whether or not you've kept up your sacrifices to
the local dark lord. Thus when a user looks at the statue, the
server knows to query the expression property of the statue. The
definition of this property in the statue includes some logic that
investigates the user staring at it, and sends back either
'frowning' or 'smiling'.

This is the core of SAM: the developer writes static descriptions
that contain active markup. The markup is evaluated by the server at
each time the user actually observes the description. The perceived
description is populated with current data.

SAM Everywhere

Once we came up with this idea of marked-up text, a whole world of
possibilities opened up before us. We look further than description;
since web pages are essentially text, why not use this same system
to generate web pages on the fly, populated with up-to-date world
data:

   Welcome to Sir John's village status page!

   Johnsville currently has 612 inhabitants. The weather is cold and
   sunny. Thirty-one cows graze the fields. Alewife Christina made
   her latest batch of ale approximately nine hours ago.

The SAM in this case would underlie HTML rather than straight text,
but to the server there is no difference.

More Power

The more we play with SAM, the more its potential power became
apparant to us, and the more we added to it. Early on we decided to
add conditional functionality:

   This is a long black sword with intricate carvings.
   <if val="$(greaterthan lhs='$looker.skill:weapon-lore' rhs='5')">
      <true>
         . You recognize the make as Alvatian.
      </true>
      <false>
         It is nighttime.
      </false>
   </if>

where the user will only be told of the sword's make if he has studied his
weapon lore.

We also add iteration, e.g.

   Welcome to Sir John's cow status page! Here's who's grazing
   the fields today:
   <for var="cow" val="$(Cows)">
      $(Cow.CapitalizedName) is grazing in $(Cow.Pasture) and is
      feeling $(Cow.Contendedness).
   </for>

where $(Cows) is an array of, yes, cows, and the SAM within the for
loop is executed once for each element of this array. The result is
a list of cows, their whereabouts, and how happy they are at the
moment.

We've introduced new syntax here; readers may recognize it as
similar to HTML. It is in fact XML, a close relative, and it is the
syntactic model we have chosen to express SAM.

Shortcuts for SAM

As we used more and more SAM, the extra "text" in the shortcuts
required for XML often made reading descriptions more difficult. To
address this, we created SAM Shortcuts. These are alternative ways
to use SAM but with shorter tags, making it descriptions easier to
read.

For example, in the Black Sword example above, the following SAM
shortcut works exactly the same way:

   This is a long black sword with intricate carvings.
   {? greaterthen | $looker.skill:weapon-lore | 5 |
      . You recognize the make as Alvatian.|
      .}

Technically this is not XML markup, but internally SkotOS converts
this to XML.

Existing Approaches

(We need someone to write up how LPMuds and other MUDs have tried to
do this in the past)

Problems Solved by Skotos SAM System

(TBW)

State of Development

The SAM System is relatively mature and complete. Much of the
fundamental power of it was proven in Castle Marrach, and now is
being used more fully in various Skotos-Seven games, and is now also
used for dynamic web pages and for our web client.

Open Issues in the SAM System

There are very few major issues with SAM itself, due to its maturity
and several years of development. However, there are some related
systems that have weaknesses that affect SAM:

    - Right now brief/glance/look/examine descriptions (and their
    all/dark/dim/bright/superbright variants) are not actually
    socials, so they do not get as many arguments as do the social
    tags. Useful information that is lacking includes which verb was
    used, the distance the actor is from the detail being viewed,
    etc. As soon as these commands are converted to Merry, all of
    these useful arguments will be available to these descriptions
    as well.

    - There are quite a few commands that are not converted to Merry
    yet, so can't be used with signal descriptions written in SAM.

    - The combinables system may have impact on SAM tags, as not all
    'objects' will be single objects anymore.

=============

Quick Summary of the Skotos SAM System

SAM (Skotos Active Markup) allows text in descriptions (see Quick
Summary: Description System) to be dynamic.

OneOf

The simplest SAM is the OneOf -- basically using a OneOf in your
text allows you to randomize the output.

   Look: [
      You are inside {a large|an oversize|a} tent.
   ]
   Output(s):
      > look at tent
      You are inside a large tent.
      > look at tent
      You are inside an oversize tent
      > look at tent
      You are inside a tent.
      >

Output a Property

You can also output the value of a property very easily.

   Look: [
      The gem is $(this.gemcolor).
   ]
   Output(s):
      > look at gem
      The gem is blue.
      > +setp gem "gemcolor green
      Setting 'gemcolor' in <[Examples:complete:sam:gem]#4544> to "green".
      > look at gem
      The gem is green.
      >

In the above example, $(this) refers to the object itself, the gem
itself.  $(this.gemcolor) refers to the value of the property
"gemcolor" inside the gem.

Arguments

$(this) is only one of many 'arguments' that SAM knows about that is
different depending on the circumstance that the SAM is executed.

In almost every situation, the following arguments are available:

    - $(actor) -- The object executing the action, e.g. whomever is
    taking the sword

    - $(action) -- The name of the action currently executing,
    e.g. take

    - $(this) -- The object containing the SAM itself, e.g. the
    sword

    - $(target) -- The detail of the object that is the target of
    the action.

In addition, in many situations, the following additional arguments
are available:

    - $(verb) -- The verb used in the action, e.g. 'polish' in
    "polish the sword with my cloth"

    - $(dob) -- The object that is the direct object of the action,
    e.g. the sword

    - $(using) -- the object that is the indirect object of the
    action, e.g.  the cloth

References

In addition to arguments, you can also reference specific objects.

    - $(Full:Woe:Name) -- the object with the woe name
    "Full:Woe:Name"

    - $[${Full:Woe:Name}] -- the object that is currently named
    "Full:Woe:Name", and if the object is renamed, the reference
    will change with it.

Property References

Once you have object defined, either by argument $this or by
reference $(Full:Woe:Name) or $[${Full:Woe:Name}], you can directly
output the value of properties that are in these objects into your
descriptions, just by adding a period followed by the property name:

    - $(this.trait:variant)

    - $(actor.trait:variant)

    - $(Full:Woe:Name.trait:variant)

    - $[${Full:Woe:Name.trait:variant}]

Some commonly used properties that output text:

    - $(this.base:possessive) -- possessive pronoun e.g. 'his'

    - $(this.base:objective) -- objective pronoun e.g. 'him'

    - $(this.base:pronoun) -- basic pronoun e.g. 'he'

    - $(this.base:light-category) -- object's luminosity,
    e.g. "dark", "dim", or "bright"

    - $(this.details:default:description:brief) -- object's default
    brief description

Examples of use:

   Look: [

      $(this.base:pronoun) looks very fierce. A scar runs from
      $(this.base:possessive) cheek to $(this.base:possessive) chin,
      which doesn't seem to bother $(this.base:objective).
   ]
   Output:

      > look at warrior
      She looks very fierce. A scar runs from her cheek to her chin,
      which doesn't seem to bother her.
      >

   Look: [
      You are in a $(this.base:light-category) room.
   ]

   Output:

      > look
      You are in a dim room.
      >

Some property references don't output text, but instead refer to
other objects:

    - $(this.base:environment) -- object's environment

    - $(this.base:worn-by) -- object's wearer (same as wielded-by)

    - $(this.base:wielded-by -- object's wielder (same as wielded-by)

These are not that useful to use directly, but in turn you can then
use properties with these:

    - $(this.base:environment.base:possessive) -- object's
    environment possessive pronoun

    - $(this.base:worn-by.base:pronoun) -- object's wearer's basic
    pronoun

Details of objects can be output:

  - $("this.details:default:descriptions:look") -- the prime
  detail's look description

  - $("this.details:lamp:descriptions:brief") -- the lamp detail's
  brief description

Some detail IDs have spaces in them. The way to refer to a SAM
reference with a space in it is to put it in quotes -- e.g.

    - $("this.details:exit west:descriptions:look") -- the look description
of exit west

rather than

    - $(room.details:exit west:descriptions:look) -- won't work

XHTML Tags

There are some XHTML formatting tags that can be useful are are available in
SAM

    - <br/> -- a line break, a single newline

    - <sbr> -- single break, inserts <br/> when used in a webpage,
    or a newline when used elsewhere.

    - <p/> -- a paragraph break, two newlines

    - <pre>text</pre> -- will output the text in a monospace font,
    without formatting

Common Sam Tags

There are various times when you need specific output that is not
easily available in a property, or the property is in the wrong
form. These SAM tags can be useful in these cases:

These are Sam Tags for describing things:

    - <describe what="$(this)"/> -- This will output the brief of
    $(this) object, e.g. "a sword"

    - <describemany what="$(this.base:inventory)"/> -- Describe many
    will output multiple briefs, as if in an inventory, of the
    objects in $(this.base:inventory).

    - <describe-holder what="$(this)"/> -- Equivalent to <describe
    what="$(foo.base:holder)"/>'s except when the person's name ends
    in 's' or 'x' in which case it does the right thing and just
    adds the apostrophe without a trailing s.

    - <describe-poss what="$(this)"> -- Describes $(this) in the
    possessive form, e.g. "his sword"

    - <describe-prop this="$(this)" what="property:name"/> -- Adds
    "a" "the" "an" to the text of the property appropriately.

    - *<describe-view view="$(this)" cap/> -- Will give the full
    description of the object, including any visible
    inventory. e.g. "A tall orc, weilding his sword."

    - <capitalize what="lower"> -- will initial capitalize the text
    "lower" into "Lower"

    - <eaten what="$(this)"/> -- will output how much of the item
    has been consumed.

Most of these description Sam Tags have a variety of options, see
SamSystem for details, but one of the most useful ones is the 'cap'
option, which will capitalize the output. For instance:

    - <describe what="$(this)"/> -- This will output the brief of
    $(this) object, e.g. "A sword"

Client Sam

The following SAM tags are useful for special features in the Alice
and Zealous clients:

    - <atag tag="command"> text that you want themed with the color
    in the 'command' theme </atag>

    - <acmd tag="command" cmd="open west door">click here to open
    the west door.</acmd>

Simple If Comparison

A simple if statement allows you to output one text if something is
true, a different text if false.

   Look: [
      A statue of a man. The statue's face {? this.trait:expression |appears
to be $(this.trait:expression) at you. |is expressionless. }
   ]

   Result(s):

      > look at statue
      A statue of a man. The statue's face is expressionless.
      > +setp statue "trait:expression similing
      Setting 'trait:expression' in
      <[Examples:complete:sam:statue]#4586> to "smiling".
      > look at statue
      A statue of a man. The statue's face appears to be smiling at you.
      >

In this example, if the property trait:expression doesn't exist
(i.e.  false), then "is expressionless" is output. If it does exist
(true) then it is "appears to be smiling at you" will be output.

Other Comparisons

There are quite a few inds of comparisons you can do in SAM:

BOOLEAN

    {? | $this.trait:variant |
        true text output |
        false text output }

    {? not | $this.trait:variant |
        true text output |
        false text output }
    {? equal | $this.trait:variant | ordinary |
        true text output |
        false text output }

    {? notequal | $this.trait:variant | ordinary |
        true text output |
        false text output }

    {? lessthen | $this.trait:variant | ordinary |
        true text output |
        false text output }

    {? lessthenorequal | $this.trait:variant | ordinary |
        true text output |
        false text output }

    {? greaterthen | $this.trait:variant | ordinary |
        true text output |
        false text output }

    {? greaterthenorequal | $this.trait:variant | ordinary |
        true text output |
        false text output }

    {? range | $this.trait:variant | lowervalue | uppervalue |
        true text output |
        false text output }

    Comment: range is exclusive, i.e.
         {? range | 1 | 3 | 6 | true | false }"
            1   false
            2   false
            3   false
            3.1 true
            4   true
            5   true
            6   true
            6.1 false
            7   false
            8   false
            9   false


    {? when | $this.trait.variant |
        value1 | value1 equal $this.trait:variant |
        value2 | value2 equal $this.trait:variant |
        value3 | value2 equal $this.trait:variant |
        *      | any other value }

Inline Merry

You can put Merry scripts inside of of SAM as follows:

   Look: [
      You are on a road. There are $[this.stars_in_sky +
      this.moons_in_sky] celestial bodies above you.
   ]

If the piece of Merry does not end in a semi-colon or a right-brace,
it is assumed to be a 'statement' rather than an 'expression'. This
means the code needs to explicitly return a value. For example,

   You are on a road. There are
     $[
         if (this.stars_in_sky > 5) {
             return "lots of";
         }
         if (this.stars_in_sky > 0) {
             return "a few";
         }
         return "no";
      ]
   stars in the sky.

Inline Merry and Text

It can often be useful in SAM to manipulate text, so there are some
very simple inline Merry functions that can perform this for you.

Text related:

    - $[capitalize("this is a test")] -- result: "This is a test"

    - $[proper("This is a test")] -- result: "This Is A Test"

    - $[decapitalize("This Is A Test")] -- result: "this Is A Test"

    - $[upper_case("This Is A Test")] -- result: "THIS IS A TEST"

    - $[lower_case("this Is A Test")] -- result: "this is a test"

Number related:

    - $[desc_cardinal(128)] -- result: "one hundred twenty-eight"

    - $[desc_ordinal(128)] -- result: "one hundred twenty-eighth"

    - $[comma(1024)] -- result: "1,024"

Inline Merry and Comparisons

You can combine arbitrary Merry expressions for tests to use in
comparisons, to make very sophisticated output. For example:

    {? | $[this.foo == "bar"] |
        true text output |
        false text output }

    {? | $[random(100)] |
        true one in 100 times. |
        false text output }

    {? | $[random(6)+random(6)+random(6)+3 == 18] |
        You rolled 3 sixes! |
        You didn't roll 3 sixes. }

    {? range | $[random(100)] | 25 | 75 |
        You rolled in the middle of the range. |
        You rolled outside the range. }

These can be quite sophisticated, for instance:

    {? | $[sizeof(Match($actor, "cigarette"))] |
    Actor has a cigarette. | Actor doesn't have cigarette. }
       Actor has a cigarette.
       Actor doesn't have a cigarette


Common Inline Merry Uses

There are many things you can do in SAM by using inline Merry, but
these are some of the most common:

    - $[Set($this, "my:property:name", 1);] -- Sets the property
    my:property:name in object $this to 1.

    - $[Set($this, "my:property:name", Get($this, "my:property:name)
    + 1); ] -- Adds 1 to property my:property:name on object $this


You look at <describe what=$(this)> and your surroundings change!

   $[ EmitIn(Get($actor, "base:environment"),
                 Describe($actor) + "looks at " + Describe($dbob) + " and disappears!\n",
                 $actor);
      $actor."base:environment" = ${Examples:complete:desc:room-go-nowhere};
      $actor."base:proximity" = NewNRef(${Examples:complete:desc:room-go-nowhere}, "floor");
      $actor."base:stancestring" = "lying";
      $actor."base:prepositionstring" = "on";
      EmitIn(Get($actor, "base:environment"), Describe($actor) + "appears out of nowhere lying on the floor!\n", $actor);
   ]
_______________________________________________
MUD-Dev mailing list
MUD-Dev at kanga.nu
https://kanga.nu/lists/listinfo/mud-dev



More information about the mud-dev-archive mailing list