Phantasmal MUD Lib for DGD

Phantasmal Site > DGD > Skotos > Skotos Library

What is Known About the Skotos Libraries?

Skotos' current libraries are closed-source. However, some information has been released by the company about them. You can find some of the information in the Skotos articles, especially Shannon Appelcline's "Trials, Triumphs and Trivialities".

The Skotos library includes a web interface for administration and creation. The basic library includes everything one might need for the base of a next-generation mud. This includes true persistence, and a more extensive social expression mechanism than even MUSHes contain. The base Skotos library does not have game-specific systems like combat, though. Those are built individually, per-game.

There is also XML object import and export. You can see examples of an anvil and a rose rendered as XML from their Skotos LPC objects.

Skotos has provided an introduction to their Skotos Active Markup syntax. There's also a quick summary of all the tags for their markup.


From: Par Winzell
Date: Thu, 22 Jul 1999 14:19:11 -0700 (PDT)
To: DGD Mailing List
Subject: Re: [DGD]Melville Mudlib

In response to Dworkin's recent stirring posting about the interesting
times ahead and a new generation of mudlibs, here's an outline of some
of the constituent parts of the lib we're writing at Skotos, including
discussion and motivation.

By far the most influential factor on design has been persistence; the
idea of a state space that is cold-booted only once and then stays up,
potentially forever. Core support for this has been in DGD for a long
time; much of Dworkin's kernel library is designed with these demands
in mind, and people have been -talking- about peristent Muds for a long
time. So why aren't there any yet?

Well, it's damn hard. One of the basic problems, a recent topic on this
list, is program upgrading which requires LPC support in the form of a
object-database. More generally, the necessity of basic consistency is
upped brutally. If after a year of precious uptime you find some vital
datastructure to be corrupted, you're going to be very sad. When this
happens to the mudlib you wrote, you'll be glad you based it around the
kernel lib -- which still runs, and lets you do an emergency login and
poke at the guts of your broken world.

So we use the kernel library, unmodified. Easy decision to make.

Incidentally, the -game- effects of persistency are of course enormous.
That's another discussion entirely.

The ~System level is small. It has three major components -- the object
database; a second-level auto object which adds some protection against
destructing clonable objects that have clones; and some API translation
to the rest of the lib of kernel services which only ~System is allowed
to directly access.

The guts are in ~SkotOS. This means they get the benefit of the ~System
level restrictions and clone book-keeping. Here we have,

 * HTTP service. Text is great, but a browser interface can be used to
great advantage, especially for administration and development. This is
especially true in a persistent game, where manipulating state in one
way or another is much more important than in a rebooting Mud, where it
is the LPC (and save_object) files that really determine what the world
is. We're flirting with HTTP 1.1 compliance.

 * Standardized functionality for the export and import of object state
through XML. To use this system, the object describes its function-call
interface for query() and set() style operations. With this description
we are able not only to fetch the object state and transcribe it to XML
but also to generate for it a true DTD (Document Type Definition). With
the help of this DTD, which describes precisely the possible structures
of the state, external XML authoring software will be able to construct
word-processor quality GUI's for any object that uses the system.

 * An XML parser (and generator) which uses parse_string(). XML is just
a data storage format, so just parsing it does little. The data may be
object state as per above, destined to be squeezed back into an object
somewhere. In addition to this static structure, however, we use XML to
do an active mark-up of text fields. In SGML/XML terms this is "PCDATA".
   - In-game descriptions may be marked up to vary depending on server
state; for example, a room description may vary by light level relative
to the looker's night-vision stat, or variables associated with players
or rooms or other objects may be embedded in the text.
   - We also generate HTML from the XML, and thus automatically have a
powerful system for server-side generation of dynamic HTML. We'll ship
the lib with a set of such XML-HTML pages.

 * A decent command parser which should understand a sensible subset of
English. We have chosen to completely forbid guess-the-verb puzzles, by
centralizing the parser entirely. If a verb does something anywhere, it
does something everywhere. Successful commands are turned into actions
or sequences of actions taken by objects in the virtual world. We tried
for as much separation between client-interface and world as possible.
These sequences of actions could equally well be generated by clicking
on things in some isometric graphical client. While we try to keep that
door open, we're concentrating on text as the primary interface; though
we expect ambitious developers to allow for e.g. stat-showing graphical
client-side panes, scrolling (and clickable) maps, and more.

 * A pretty intricate system for expressive/emotive stuff; while there
is no emote-command, the social verbs are plentiful and come with lots
of adverbs. That's nothing new; the interesting stuff are stances and
poses, which are tied into the world simulation to a higher degree than
I have seen elsewhere. I am able to e.g. kneel before an altar in quiet
repose, or lie on a table, or stand next to Dworkin in a room with more
effect than a transient statement of fact -- these ways in which things
can relate to each other is used in describing the environment. Certain
socials break certain stances and poses.

 * There's the idea of a prox -- something one can be in the proximity
of. Dropped gear will be lying 'near Zell' instead of in the usual big
collective heap. If I walk away from my battle-axe, it simply lies on
the floor. One of the things we hope to do is to kill off this ancient
truth that LPMuds aren't very good for social Mudders.


Phew. Then, finally, there is the virtual world itself. We separate the
world objects from things like command parsing and text generation much
more than does e.g. 2.4.5; this helps the world state to be independent
of client interface, as discussed above. We just took a step further in
this direction and utterly slew the time-honoured sub-classing approach
to physical objects. There is now only the ur-thing, and it can be room
or sword or bag of gold -- or all three -- depending only on its state.
Thus everything is really a clone of /base/obj/thing, everything can be
eaten (possibly with great discomfort) or used as a weapon (possibly a
very bad weapon). Of couse, that effect is equally possible to achieve
with traditional sub-classing. The difference is again the trend toward
the data-driven, which seems to happen naturally around persistence.


It should not be difficult to tell that the early part of this document
details things that are pretty much settled, while the mutations of the
/base directory are recent and somewhat shocking.

So. When will all this be available to play with? I'm unsure. October?

Comments requested!


Zell

From: "Christopher Allen"
To: DGD Mailing List
Subject: RE: [DGD]Patches
Date: Tue, 11 Apr 2000 15:27:07 -0700

The line of demarcation is becoming more specific as we do some architectural
partitioning out of SkotOS -- we have a number of layers above the kernel
library:

 -------------------------------------------------------------
/                          Game                               \
\                          World                              /
 -------------------------------------------------------------
/                          Game                               \
\                     Specific Mechanics                      /
 =============================================================
 -------------------------------------   ---------------------
/                WorldLib             \ /       IFLib         \
|   inventory            stance pose   |                      |
|  proximity  details  faces  desc     |   socials     verbs  |
\    exits  gender  volition  physics / \   adverbs  errors   /
 --- - - - - - - - - - - - - - - - --- \ \ -- - - - - - - - --
/                 DevLib                \ /   ToolLib         \
|     Services             Interpreters  |                    |
|                                        |    sam  |   dtd    |
|  sid  | devd  ||  state | forms | sami |  xmlgen | xmlparse |
\  logd | helpd ||        |       |     / \                   /
 -------------------------------------------------------------
/                                                             \
|                               System                        |
|                               Library                       |
|        Object Services          ||      Net Services        |
|                                 ||                          |
|  initd | idd | progdbd |syslogd || nptd | httpd | devuserd@ |
\        |     |         |        ||      |       |           /
 -------------------------------------------------------------
/                                                             \
|                               Kernel                        |
|                               Library                       |
|                                                             |
|    security  ownership  resources  thread-local  logon      |
\                                       storage               /
 -------------------------------------------------------------
/                                                             \
|                                D G D 				|
|                                                             |
|  LPC Compiler  |  Run-Time  |  Database  |  I/O  |  Parser  |
\                |            |            |       |          /
 -------------------------------------------------------------

It is the game world and game specific mechanics (such as the specifics of
combat) that is the property of the developer using our libraries.


------------------------------------------------------------------------
. Christopher Allen                                 Skotos Tech Inc. ..
.                           1512 Walnut St., Berkeley, CA 94709-1513 ..
. <http://www.Skotos.net>               o510/649-4030  f510/649-4034 ..

From: dgd at list.imaginary.com (Christopher Allen)
Date: Sun Feb  2 12:38:06 2003
Subject: Re[2]: [DGD] Impressed with DGD

"Christopher Darque":
> If this game I am
> considering is proposed, and accepted, at Skotos then this
> might be a real possibility.

If you are considering a game for us, either using your own library (as
WAP does with Grendel's Revenge and TEC) or Skotos' own library (which
is used by Castle Marrach), then you'll have access to our clients
(ActiveX, Java, and Mozilla Javascript) which all use HTML font tags for
color inside the text window.

You can specify any color you want using hex codes, but the following
are the default named ones:

{ "black",    0x000000 },
{ "white",    0xffffff },
{ "green",    0x00ff00 },
{ "maroon",   0x800000 },
{ "olive",    0x008000 },
{ "navy",     0x000080 },
{ "purple",   0x800080 },
{ "gray",     0x808080 },
{ "red",      0xff0000 },
{ "yellow",   0xffff00 },
{ "blue",     0x0000ff },
{ "teal",     0x008080 },
{ "lime",     0x808000 },
{ "aqua",     0x00ffff },
{ "fuchsia",  0xff00ff },
{ "silver",   0xc0c0c0 },

In addition, the Alice ActiveX client supports some (but not all) of the
Pueblo commands:

        <br/>COMPLETELY FUNCTIONAL MARKUP
        <xch_page clear=text />
        <body bgcolor=silver text=black alink=red vlink=red link=red />
        <hr/>
        <br/>Testing xch_page clear=text Tag.
        <br/>Testing body Tag.
        <br/>Testing Header Rule.
        <br/>Testing img img xch_mode=text Tag <img xch_mode=text/>.
        <br/>Testing img img xch_mode=purehtml Tag <img
xch_mode=purehtml/>.
        <br/>Testing img img xch_mode=html Tag <img xch_mode=html/>.
        <br/>Testing bgcolor & text & *link Attributes in body Tag.
       <br/>Testing xch_mudtext <xch_mudtext>I'm using
Alice</xch_mudtext>
        <br/>Testing xch_cmd Attribute <a xch_cmd="scratch my
ring">Scratch me</a>.
        <br/>
        <br/>Pueblo Forms Test:
        <form method=xch_cmd >
                <br/><select name=sourceselect>
<option>Select 1</option>
<option selected>Select 2</option>
<option>Select 3</option>
<option>Select 4</option>
<option>Select 5</option>
<option>Select 6</option>
</select>
<br/><textarea name=sourcetextarea rows=5 cols=30 />
        <br/><input type=checkbox checked name=sourcecheckbox
value=checkbox />Checkbox 1
        <br/><input type=radio checked name=sourceradio
value=radio />Radio 1
        <br/><input type=number name=sourcenumber size=6
maxlength=6 />Number 1
        <br/><input type=text name=sourcetext size=12
maxlength=12 />Text 1
        <br/><input type=password name=sourcepassword size=12
maxlength=12 />Password 1
        <br/><input type=submit value="Send" />
        <br/><input type=reset value="Reset" />
        </form>
        <br/>Character Editing Elements:
        <br/>Testing <b>Bold</b>.
        <br/>Testing <i>Italic</i>.
        <br/>Testing <u>Underline</u>.
        <br/>Testing <strike>Strike</strike>.
        <br/>Testing <strong>Strong</strong>.
        <br/>Testing <em>Emphasis</em>.
        <br/>Testing <cite>Cite</cite>.
        <br/>Testing <tt>Typewriter</tt>.
        <br/>Testing <code>Code</code>.
        <br/>Testing <samp>Samp</samp>.
        <br/>
        <br/>Block Formatting Elements:
        <br/>Testing Header Rule:
<hr size=4 width=50% align=center />
        <br/>Testing Headers:
        <h1>Header 1</h1>
        <h2>Header 2</h2>
        <h3>Header 3</h3>
        <h4>Header 4</h4>
        <h5>Header 5</h5>
        <h6>Header 6</h6>
        <br/><quote>Quote: The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog. The quick brown fox jumped
over the lazy dog. </quote>
        <address>Address: The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog. The quick brown fox jumped
over the lazy dog.</address>
        <blockquote>Blockquote: The quick brown fox jumped over the lazy
dog. The quick brown fox jumped over the lazy dog. The quick brown fox
jumped over the lazy dog.</blockquote>
        Testing Ordered List:<ol>
       <li>List Item One</li>
       <li>List Item Two</li>
       </ol>
Testing Unordered List:<ul>
       <li>List Item One</li>
       <li>List Item Two</li>
       </ul>
Testing Directory List:<dir>
       <li>List Item One</li>
       <li>List Item Two</li>
       </dir>
Testing Menu List:<menu>
       <li>List Item One</li>
       <li>List Item Two</li>
       </menu>
Testing Definition List<dl>
<dt>definition term</dt>
       <dd>definition data</dd>
       </dl>
        Testing Font Color <font color=aqua>aqua</font>.
       <br/>Testing Font Color <font color=black>black</font>.
       <br/>Testing Font Color <font color=blue>blue</font>.
       <br/>Testing Font Color <font color=fuchsia>fuchsia</font>.
       <br/>Testing Font Color <font color=gray>gray</font>.
       <br/>Testing Font Color <font color=green>green</font>.
       <br/>Testing Font Color <font color=lime>lime</font>.
       <br/>Testing Font Color <font color=maroon>maroon</font>.
       <br/>Testing Font Color <font color=navy>navy</font>.
       <br/>Testing Font Color <font color=olive>olive</font>.
       <br/>Testing Font Color <font color=purple>purple</font>.
       <br/>Testing Font Color <font color=red>red</font>.
       <br/>Testing Font Color <font color=silver>silver</font>.
       <br/>Testing Font Color <font color=teal>teal</font>.
       <br/>Testing Font Color <font color=white>white</font>.
       <br/>Testing Font Color <font color=yellow>yellow</font>.
       <br/>Testing Font Multiset <font fgcolor=red bgcolor=white
size="+3">Test</font>.
        <br/>PARTIALLY FUNCTIONAL MARKUP
       <br/>Testing Paragraph Tags:
<br/><nobr>Testing Nobr. The quick brown fox jumped over the
lazy dog. The quick brown fox jumped over the lazy dog. The quick brown
fox jumped over the lazy dog. The quick brown fox jumped over the lazy
dog.</nobr>
<br/><base>Testing Base. The quick brown fox jumped over the
lazy dog. The quick brown fox jumped over the lazy dog. The quick brown
fox jumped over the lazy dog. The quick brown fox jumped over the lazy
dog.</base>
<br/><xmp>Testing Xmp. The quick brown fox jumped over the lazy
dog. The quick brown fox jumped over the lazy dog. The quick brown fox
jumped over the lazy dog. The quick brown fox jumped over the lazy
dog.</xmp>
<br/><listing>Testing Listing. The quick brown fox jumped over
the lazy dog. The quick brown fox jumped over the lazy dog. The quick
brown fox jumped over the lazy dog. The quick brown fox jumped over the
lazy dog.</listing>
<br/><plaintext>Testing Plaintext. The quick brown fox jumped
over the lazy dog. The quick brown fox jumped over the lazy dog. The
quick brown fox jumped over the lazy dog. The quick brown fox jumped
over the lazy dog.</plaintext>
<br/><pre>Testing Pre. The quick brown fox jumped over the lazy
dog. The quick brown fox jumped over the lazy dog. The quick brown fox
jumped over the lazy dog. The quick brown fox jumped over the lazy
dog.</pre>
        <hr/>
        NOT-FUNCTIONAL PUEBLO MARKUP
        <br/>Testing Font Color <font color=grey>grey</font>.
        <br/>Testing Font Color <font color=brown>brown</font>.
        <br/>Testing send Tag <send>touch my ring</send>.
        <br/>Testing xch_pane Tag <xch_pane action=open name=map
xch_panetitle="Map of the City" options="floating persistent fit
nonsizeable" vspace=5 hspace=5/>
        <br/>Testing xch_pane Tag <xch_pane action=open name=buttonbar
options="fit internal" align=bottom href="test.html"/>
        <br/>Testing href Attribute <a href="test" >Click me</a>.
        <br/>Testing img Tag <img src="test" />.
        <br/>Testing img Tag <img src=\$prop(this.img-url) />.
        <br/>Testing img img xch_alert Tag <img xch_alert/>.
        <br/>Testing xch_hint Attributes for xch_cmd links <a
xch_cmd="scratch my ring" xch_hint="scratch my ring">Scratch me</a>.
        <br/>Testing link vlink alink Attributes for xch_cmd links <a
xch_cmd="scratch my ring" link=red alink=red vlink=red >Scratch me</a>.
        <br/>Testing text Attributes for xch_cmd links <a
xch_cmd="scratch my ring" text=red >Scratch me</a>.
        <br/>Testing color Tag <color fore=green back=black > Green on
Black </color>.
        <hr/>

You can also send special SKOOT commands that will command the clients
to execute Javascript in the window that the client resides in.

The Marrach game uses colors (see the command PROFILE to set default
colours) and some the Pueblo specific tags (see the command EXITS).
Grendel's Revenge makes most use of the SKOOT commands. To see these
features you will need to be using our ActiveX client on Internet
Explorer.

-- Christopher Allen

------------------------------------------------------------------------
.. Christopher Allen                                 Skotos Tech Inc. ..
..                           1512 Walnut St., Berkeley, CA 94709-1513 ..
.. <http://www.skotos.net>           o510/647-2760x202  f510/647-2761 ..

From: dgd at list.imaginary.com (Christopher Allen)
Date: Sun Feb  2 20:03:01 2003
Subject: Re[2]: [DGD] Impressed with DGD

"Christopher Darque":
> > If you are considering a game for us, either using your own library
>
> First let me say thanks for the effort of cutting and pasting
> all that info, I appreciate it and I have saved it for serious
> study. I am fairly familiar with HTML and Pueblo, but I know
> very little about ActiveX.

You don't really need to know about the clients, just how to interface
with them. For instance, in our Marrach client, when an object is
dropped in a room, it also shows up in a popup menu to the right of the
of the text area. The way this works is that whenever an object arrives
in a room, a SKOOT event is sent, basically something like "SKOOT 15 a
rock". The web page recieves the SKOOT 15 messages, and sends it to
function 15, which in our case is the javascript:

function addObject(str) {
  var ix, pos, name;

  pos = str.indexOf(' ');
  if (pos >= 0) {
    ix = str.substring(0, pos);
    name = str.substring(pos+1);
    if (this["objectSet"] == null) {
        this["objectSet"] = new Object();
    }
    this["objectSet"][ix] = name;
    updateAll();
//    alert('object ' + name + ' added');
  }
}

The fact that we use 15 for addObject is not relevant -- WAP uses a
completely different set of SKOOT # messages that call Javascripts that
they wrote for their client. Whatever you can do in Javascript
dynamically (i.e. without refreshing the page) can be done using this
technique.

> Second, where might I find more technical docs on the Skotos
> systems?  If I do decide to propose this to your Company I
> would almost certainly use your Lib as the starting point.

There is quite a bit of documentation that you get when you are involved
with developing for us, however, I'd say though we have alot, is never
enough ;-)

> Your use of non-telnet clients does open up some interesting
> possibilities, such as a split screen with the room visual
> at the top and a scrolling text box below for everything
> else.

It is even possible to have the client be a 1x1 pixel client, and just
use it to control the dynamic web page.

-- Christopher Allen

------------------------------------------------------------------------
.. Christopher Allen                                 Skotos Tech Inc. ..
..                           1512 Walnut St., Berkeley, CA 94709-1513 ..
.. <http://www.skotos.net>           o510/647-2760x202  f510/647-2761 ..

From: DGD Mailing List (Christopher Allen)
Date: Thu Mar 25 10:36:01 2004
Subject: [DGD] Aliases & Stacked commands

Michael McKiel wrote:
> Shoulda asked in my last reply :P but anyways...
> I'm not sure I get the command/action distinction as defined by
> Skotos.
>
> As I previously stated, any object can potentially try to do a given
> command, and for most cases will be able to, non-livings limited to
> souls & 'talking' commands. And mobiles restricted from wiz-commands
> (that might change but don't think it should be needed.)
>
> Isn't the action(if we exclude wizard commands) primarily the message
> displayed from a given command, or a movement of one object into
>    another, ie: get/give/drop, move to another room, etc.
>
> Or does skotos make some other distinction that I am missing?

I'll give a specific example, the verb sip:

<object id="OBJ(Socials:Verbs:S:sip)">
  <context/>
  <Socials:Verb imp="sip" second="sip" third="sips" evoke="forbidden"
audible="false" private="false" secret="false" obscured="false"
target-abstracts="false" disabled="false">
    <Socials:SocialObjects>
      <Socials:SocialObject role="dob" direct="true" single="false" raw="false"
requirement="optional" distance="close"/>
      <Socials:SocialObject role="iob" direct="false" single="false" raw="false"
requirement="optional" distance="close">
        <Socials:SocObPreps>
          <Socials:SocObPrep prep="from"/>
        </Socials:SocObPreps>
      </Socials:SocialObject>
    </Socials:SocialObjects>
    <Socials:VerbActions>
      <Socials:VerbAction action="sense/taste"/>
      <Socials:VerbAction action="act/consume"/>
      <Socials:VerbAction action="act/drink/small"/>
    </Socials:VerbActions>
  </Socials:Verb>
</object>

Basically when someone sips a drink, the action "sense/taste" is triggered,
sending the signal "sense/taste" to all the appropriate nearby objects. This
allows the object to tell the actor "You taste a blend of warm milk and dark
bitter-sweet chocolate with a dash of cinnamon", but also could be used by the
actor to detect a poison. Next is the "act/consume" signal, which can be used by
objects to know that something was consumed, for instance, to notice that
someone was eating in the rectory, or to trigger the poison. Next, there is
"act/drink/small" which consumes a small amount of the liquid, as opposed to
guzzling it. Finally, there is a default "verb/sip" signal, for those odd cases
where use of the specific verb is significant.

Compare this to taste:

<object id="OBJ(Socials:Verbs:T:taste)">
  <context/>
  <Socials:Verb imp="taste" second="taste" third="tastes" evoke="forbidden"
audible="false" private="false" secret="false" obscured="false"
target-abstracts="false" disabled="false">
    <Socials:SocialObjects>
      <Socials:SocialObject role="dob" direct="true" single="false" raw="false"
requirement="optional" distance="close"/>
      <Socials:SocialObject role="iob" direct="false" single="false" raw="false"
requirement="optional" distance="close">
        <Socials:SocObPreps>
          <Socials:SocObPrep prep="from"/>
        </Socials:SocObPreps>
      </Socials:SocialObject>
    </Socials:SocialObjects>
    <Socials:VerbActions>
      <Socials:VerbAction action="sense/taste"/>
    </Socials:VerbActions>
  </Socials:Verb>
</object>

When someone tastes a drink, only "sense/taste" and "verb/taste" signals are
triggered, but not "act/consume" or any "act/drink". Thus the taste of the
mexican hot chocolate is given to the user, and the user could have a chance of
detecting the poison, but the poison itself would not be consumed (unless it was
so powerful that it was triggered by "sense/taste" in addition to
"act/consume").

There are several thousand of verbs in our library, but as a coder you don't
have to worry about the distinctions between consume, drain, gargle, gulp,
guzzle, imbibe, lap, lick, quaff, sip, slurp, suck, swig, swallow, swill, taste,
etc. You only have to code to "sense/taste", "act/consume", "act/drink".

It is also trivial for people to to add additional actions to a verb, for
instance, "act/touch" could be added to the verb "sip" and all the verbs where
touch is assumed, and now this signal would be available to players.

In addition to the verb signals, other signals can be sent, for instance, when
an NPC moves, there are signals sent to all who could observe it. If the lights
go off, a signal is sent. If someone becomes hungry, a signal is sent.

-- Christopher Allen

From: DGD Mailing List (Par Winzell)
Date: Tue Aug 31 06:51:01 2004
Subject: [DGD] SkotOS 2.0

> On Monday, August 30, 2004, 8:24:24 PM, Par Winzell wrote:
> PW> It should also be mentioned that the further we get towards 2.0, the
> PW> less of the code is pure LPC. Some of the modules are almost exclusively
> PW> Merry/SAM, especially the web-application ones. Not everybody will need
> PW> to be a hardcore LPC architect.
> 
> I'm curious about this, why implement a new interpreted imperative
> language (Merry) within LPC?  What benefit does it provide over
> straight LPC?

It's not interpreted in LPC. Merry is compiled into actual LPC. There is 
no significant speed loss. The benefits are not so much in the language 
itself but in the fact that it allows little snippets of code to be sent 
around as data, which is a natural way for us to hook logic onto events.

Zell

From: DGD Mailing List (Christopher Allen)
Date: Tue Aug 31 14:41:02 2004
Subject: [DGD] SkotOS 2.0
Message-ID: <2f9801c48f92$6134bd60$aa1351d1@artemis>

Par Winzell wrote:
> It's not interpreted in LPC. Merry is compiled into actual LPC. There
> is no significant speed loss. The benefits are not so much in the
> language itself but in the fact that it allows little snippets of
> code to be sent around as data, which is a natural way for us to hook
> logic onto events.

The name Merry comes from "Mediated Execution Registry Involving A 
Dialect Of C" -- which although somewhat a joke because it is the 
successor of Bilbo "Built In Language Between Object", but the acronym 
that Merry stands for actually does describe it well.

The key is the the "mediated" part -- this means that Merry is somewhat 
sandboxed -- not to the scale that Java is, but helpful. For instance, 
in Merry code we try to ensure that Merry scripts inside game objects 
only interact with objects that involve the virtual game world, not 
random other objects it has no business with. Only a limited number of 
functions can be called from Merry, and even then they are only allowed 
implicitly, like fetching/setting properties, Act(), etc. File system 
access is completely disabled, as well as things like starting things up 
or shutting down processes, and some communications functions.

In addition, the langage is run through a complex parse_string() 
grammar, which gives us the ability to add some useful synatactic sugar 
additions: constants, per-thread global $variables, $foo: <expr> 
function-parameters, you can directly access the property database for 
values through ${someobject}.property:name, and a few other useful 
things like the ability to do inline SAM (Skotos Active Markup) with 
$"{oneof:one|two|three}".

Independent of the Merry language itself, there are a large variety of 
useful game specific functions, such as EmitTo(), EmitIn(), Set(), etc.

Here is a small code example. A simple torch, which responds (i.e. the 
"react-") to the signal (what might be called an event) named 
"react-post:light-dob". This signal is sent to a direct object (i.e. 
-dob) immediately after (i.e. -post) a verb is used that might turn on a 
light in an object (such as the verbs light, ignite, etc.):
/* Standard Flame Scripts   */   
/* react-post:light-dob     */   
/* Example by ChristopherA  */   
      
   /* If flame-on was set during the reaction, turn trait:flame on */   
   /* and let setprop-post:trait:flame handle cleaning things up.  */   
   /* Note: we do this in react-post so that things look clean     */   
   /* during normal processing of the react:light-dob signal,      */   
   /* e.g. you don't get the result "You light the flaming torch." */   
   /* when it isn't actually flaming yet.                          */   
if ( Get(this,"trait:flame-on") ){       
      Set( this, "trait:flame", TRUE);       
      Set( this, "trait:flame-on", FALSE); 
      /* Now show everyone that a flame has appeared.              */    
  
      EmitTo ($actor, "The top of " + Describe($this, $actor, $actor) + 
" crackles alight.\n");     
      EmitIn(Get($actor, "base:environment"), "The top of " + 
Describe($this) + " crackles alight.\n", $actor); 
   }   
   
   /* This is a react-post, so no need to return TRUE; */Note the 
$actor, $this -- these are per-thread global variables passed to this 
script. They will be the same for all the signals that were initially 
caused by the first "light my torch" verb.

Next we have a signal that is sent to objects if a property is changed, 
called setprop-post. An example of use is when the torch is lit -- 
either someone interacted with the torch directly (for instance "light 
my torch" above) or something else lit it (put my torch in fireplace) -- 
either way, the trait:flame property is set to true and 
setprop-post:trait:flame is sent to the object.

/* Standard Flame Scripts    */
/* setprop-post:trait:flame  */
/* Example by ChristopherA   */

   if ($(hook-property) != "trait:flame") return TRUE;

   /* If a flame exists...   */
   if ( Get(this,"trait:flame") ){
      /* reveal the flame and change adjectives on the prime detail */
      Set( this, "details:flame:hidden", FALSE);
      Set( this, "details:smoke:hidden", FALSE);
      Set( this, "details:default:adjectives:flaming", TRUE);
      Set( this, "details:default:adjectives:lit", TRUE);
      Set( this, "details:default:adjectives:unlit", FALSE);

      /* if the torch has never been flamed before, scorch it.     */
      if ( ! (Get(this,"trait:flame:remains")) ) {
         Set(this, "trait:flame:remains", "It is slightly scorched.");
      }

      /* Now start the timer which will tick ever 90 seconds      */
      Set(this, "trait:flame:tick_id", Every("tick", 90));

   }
   /* ... if a flame does not exist, then hide the flame and      */
   /* change adjectives on the prime detail.                      */
   else {
      Set( this, "details:flame:hidden", TRUE);
      Set( this, "details:smoke:hidden", TRUE);
      Set( this, "details:default:adjectives:flaming", FALSE);
      Set( this, "details:default:adjectives:lit", FALSE);
      Set( this, "details:default:adjectives:unlit", TRUE);

      /* Now turn of the timer, so it will not tick. */
      Stop(Get(this, "trait:flame:tick_id"));
   }

   /* This is a setprop-post, so no need to return TRUE; */Finally, we 
need a way to emit messages periodically as the torch is burning, and to 
destroy the torch when it is used up:

/* Standard Flame Scripts    */ 
/* timer:tick                */ 
/* Example by ChristopherA   */ 
 
   /* timer:tick is called every X seconds (typically 60 or */ 
   /* 90 seconds) as set up in the Every() function in      */ 
   /* the setprop-post:trait:flame merry script.            */ 
 
   object env; object act; int tick; 
 
   /* We've been triggered, so increment our tick count     */ 
   tick = Get(this, "trait:flame:tick_cnt") + 1; 
   Set(this, "trait:flame:tick_cnt", tick); 
 
   /* set some variables because timer:tick exists in an    */ 
   /* an environment where there are very few arguments     */ 
   /* and you can't rely on where the item. It could be     */ 
   /* on the floor, in someones bag in the nil, or in       */ 
   /* the hands of the person who lit it.                   */ 
 
   /* If we are being held, we want our environment output  */ 
   /* to be in the room of the person who is holding us.    */

   if (env = Get(this, "base:environment")) { 
    env = Get(env, "base:environment"); 
   } 
 
   /* If we are being held, we want our actor output        */ 
   /* to be the person holding us, or the room if the item  */ 
   /* has been dropped.                                     */

   act = this."base:environment"; 
   if (act."base:environment") { 
      /* actor has an environment, all is well */ 
      env = act."base:environment"; 
   } else { 
      /* if act has no environment, we've been dropped and act = env! 
*/ 
      env = act; 
      act = nil; 
   } 
 
   /* For each tick, do different things...                 */ 
 
   /* ...partially burn out the item                        */ 
   if (tick == 5) { 
     Set(this, "trait:flame:remains", "It is about half burned out"); 
   } 
   /* ...mostly burn out the item                           */ 
   if (tick == 10) { 
      Set(this, "trait:flame:remains", "It is almost burned out."); 
   } 
   /* ...complete burn out the item                         */ 
   if (tick >= 12) { 
      if ( act != nil ) { 
          EmitTo(act, Describe(this, nil, act) + " sputters out.\n"); 
      } 
      if(this."base:environment") { 
         EmitIn(env, Describe(this, nil, nil) + " sputters out.\n", 
act); 
      } 
      Set(this, "trait:flame", FALSE); 
      Set(this, "trait:flame:flammable", FALSE); 
      Set(this, "trait:flame:remains", "It is completely burned out."); 
      Set( this, "details:default:adjectives:spent", TRUE); 
      /* stop us from ticking anymore                       */ 
      Stop(Get(this, "trait:flame:tick_id")); 
 
      /* Now return false, but set up a delay so that       */ 
      /* this object can decay in 86400 seconds (1 day)     */ 
      $delay(86400, FALSE, "4a8d"); 
 
      /* We have to re-establish our local variables, as    */ 
      /* they are incorrect after a delay.                  */ 
      Set(this, "trait:flame:tick_cnt", tick); 
      if (env = Get(this, "base:environment")) { 
    env = Get(env, "base:environment"); 
      } 
      act = this."base:environment"; 
      if (act."base:environment") { 
         env = act."base:environment"; 
      } else { 
         env = act; 
         act = nil; 
      } 
 
      /* If we are not in the nil, then tell people that    */ 
      /* we are disintegrating...                           */ 
      if ( act != nil ) { 
        EmitTo(act, Describe(this, nil, act) + " disintegrates from 
age.\n"); 
     } 
      if (this."base:environment") { 
         EmitIn(env, Describe(this, nil, nil) + " disintegrates from 
age.\n", act); 
     } 
    /* Ok, we are done. Bye.                              */ 
      Slay(this); 
      return FALSE; 
   } 
 
   /* For every tick, there is a 30% chance of a random emit*/ 
   switch(random(10)) { 
      /* Again, if we are not in the nil, do the emits      */ 
    case 0: { 
            if ( act != nil ) { 
               EmitTo(act, "A trail of smoke wisps upwards through the 
air from " + Describe(this, nil, act) + ".\n"); 
            } 
            if(this."base:environment") { 
            EmitIn(env, "A trail of smoke wisps upwards through the air 
from " + Describe(this, nil, nil) + ".\n", act); 
            } 
    } break; 
    case 1: { 
            if(this."base:environment") { 
               EmitTo(act, "There is a quiet fizzle of hot oil from " + 
Describe(this, nil, act) + ".\n"); 
            } 
            if(this."base:environment") { 
               EmitIn(env, "There is a quiet fizzle of hot oil from " + 
Describe(this, nil, nil) + ".\n", act); 
            } 
    } break; 
    case 2: { 
            if(this."base:environment") { 
               EmitTo(act, capitalize(Describe(this, nil, act) + " 
flickers.\n")); 
            } 
            if(this."base:environment") { 
               EmitIn(env, capitalize(Describe(this, nil, nil) + " 
flickers.\n"), act); 
            } 
    } break;
    default: break;
   }

The above is only three of about 8 different Merry scripts used by 
torches.

-- Christopher Allen

------------------------------------------------------------------------
.. Christopher Allen                                 Skotos Tech Inc. ..
..                2342 Shattuck Ave Ste #512, Berkeley, CA 94704-1517 ..
.. www.skotos.net  www.rpg.net       o510/647-2760   f510/849-1717 ..

From: "Christopher Allen"
Subject: RE: [DGD] DGD http daemon?
Date: Wed Feb  9 09:40:01 2005

On Tuesday, February 08, 2005 12:27 PM Stephen Schmidt <> wrote:
> I gather this daemon runs alongside of the mud, but the players still
> connect and play via the telnet protocol. 
> Could this daemon be extended so that the players played primarily
> through the http protocol, probably using the telnet side only for
> communications (which are hard to implement in http)?  
> 
> There are all kinds of design-related problems with using a primarily
> http interface for playing the game; those don't interest me so much.
> The question is really whether this daemon could be the basis for
> code support for such a design. If it is, then having a version for a
> general DGD kernel (or even a specific kernel that could be released
> as a package with the daemon) would be extremely useful.     

There are some advantages for simulating telnet through http -- you can then
work with proxies and such. We've had a lot of problems with players
attempting to connect from work, for instance. For now, many cheap firewalls
don't block port 443 (https) so that relieves some of the problem. I know of
at least one company that did that, faked http traffic enough that stateful
firewall proxies would pass it on, but to the user was just like telnet.

A different issue is interface in a web world. You should take a look at the
Zealous and Alice clients that we use at Skotos -- try out Castle Marrach
(free trial) using IE (for Alice) or Mozilla/Firebird (for Zealous) to see
how we use a combination of a telnet client embedded inside a web page, that
can call the web page and change it, and the web page can call the telnet
client as well. For one of the best examples of this, try Grendel's Revenge
(IE only for right now.)

I've said for a while elsewhere that we would be glad to share both clients.

-- Christopher Allen

From: Erwin Harte
Subject: [DGD] Re: DGD http daemon?
Date: Wed Feb  9 16:25:01 2005

On Wed, Feb 09, 2005 at 12:38:59AM -0800, Christopher Allen wrote:
[...]
> A different issue is interface in a web world. You should take a look at the
> Zealous and Alice clients that we use at Skotos -- try out Castle Marrach
> (free trial) using IE (for Alice) or Mozilla/Firebird (for Zealous) to see

You mean Firefox, its most recent incarnation. ;)  Zealous also works
with Netscape 7.2 (and newer, I would assume).

Cheers,

Erwin.
-- 
Erwin Harte

From: dgd@dworkin.nl (Par Winzell)
Date: Tue Mar 22 16:28:01 2005
Subject: [DGD] Question for programmers and builders

Noah Gibbs wrote:

>   Phantasmal gets a lot of flak for being gratuitously weird, by which I mean
> "not like 2.4.5".  And that's true, it really isn't.  Would people have an
> easier time with passing Phrases around if they looked like the markup strings
> above instead of looking like opaque LWO structures that you have to call
> functions on?

I think Felix already supplied the vital distinction here... Add, for 
example, a mudlib-wide interface for editable objects that specify 
something like

   string export_ascii_state();
and
   void import_ascii_state(string state);

and use these in any situation where a developer edits any object 
through any text-based interface (telnet, web, ...).

The Skotos mudlib does a lot of this. Merry scripts are stored in a 
half-compiled form (from which the original source can quickly be 
reconstructed for editing purposes).

SAM -- which is marked-up text much like what you're implementing -- is 
similarly a "binary" format internally and presented in a text form to 
the various user interfaces.

To demonstrate a final point in favour of the above, let me outline one 
of the Skotos mudlib decisions I wish we'd never made -- for out final 
output post-processing step -- the markup that is not evaluated until 
it's just about to be sent out to the user, and thus is 100% subjective 
to that user -- we foolishly opted to use LPC strings directly, 
marked-up with otherwise unused characters.

Thus if I exclaim something in Dwarfish, the resulting output for 
onlookers would be something like,

   TAG("Zell exclaims in Dwarfish, \'" +
           INLANG("My axe is my best friend!", "dwarfish") + "\"",
       "Social")

which turns not into an LWO or anything, but a rather confusing string:

   \000\003Social\001\000\206\dwarfish|7\001
   "My axe is my best friend!"\002\002

which is then sent to the user object, which does the final parsing and 
manipulation. The tags are looked up in the user's profile and turned 
into e.g. font colour settings -- so they can have all social emotes 
show up in blue, or whatever -- whereas the language data is used to 
garble the string depending on the proficiency in the language of the 
speaker as well as the proficiency of the listener.

The format is extremely quick to parse with parse_string() and it has 
the one advantage of letting developers continue to use string addition. 
  For us, its main advantage was that it could be grafted onto the 
existing mudlib structure without a massive rewrite.

Still, it was a bad idea. Passing these pseudo-strings off as real 
strings is very problematic. Given any string containing interesting 
data, a developer is always going to try to parse it or split it up or 
insert things into it, etc, and this sort of markup is very fragile. 
Passing interesting yet fragile data that looks like strings but isn't 
through developer hands is a recipe for disaster.

So. Always abstract the implementation from the interface.

Zell