
the message() client protocol
-----------------------------

message is a new efun in MudOS designed to make communication efuns more 
generic and to provide a standard way of talking to clients intelligently.

Here is the manual page for message:

=====================================================================
void message (string msg, string class, mixed targets, mixed exclude);

message calls receive_message(string message, string class) in all message
recipients (derived from the target list) excluding those in the exclude list.
This basically tells the object the message.

Message is a string containing the message to be sent

Class is the type of message (used for clients and such). An example
would be 'combat', 'shout', 'emergency' etc.

target is a list of objects to be sent the message. This can be either a 
single object string or object pointer, or may be an array of either.
If a target is non living all objects in it's environment will receive
the message.

Exclude is a list of objects that should not receive the message. This
can either be a one or an array of object pointers.
======================================================================


Probably the most important element of this function is the "class".
If used properly, you could use this field to implement a very simple
version of earmuffs, or to communicate intelligently with a custom
client.  The class defines the type of message that the string
contains.  Initial simple implementations would have the classes
"shout", "say", "write", "tell_object" (which would be generated by
simul_efuns of the same name that replace the more traditional efuns).

Given this, let's say that you wanted to implment a quick and easy
earmuff ability. (the ability to mask shouts) In your user (player)
object, you would have the function receive_message.  Here's the
simplest implementation possible:

void receive_message (string msg, string class)
{
	receive(msg);
}

This simply takes all messages generated by the message efun and
displays them to the user.  However, you could imagine a simple
earmuffs implementation on top of this:

string *muffle = ({});

int muffle_class (string arg)
{
	muffle += ({arg});
}

void receive_message (string msg, string class)
{
	if (member_array(class,string) == -1)
		receive(msg);
}

Now you can see, that if a particular class is muffled (say, "shout"
for example), the text never gets displayed, but in other cases it
does.

However, not all uses of the shout() efun are really shouts, in the
traditional mud sense.  For example, let's say that the admin of the
mud wants to send a message to all users telling them that the system
is going to be shut down in 5 minutes.  To do this, they might use
echo, which in turn uses the shout() efun.  So all users who had
"shout" muffled would miss this important message. This means that a
broader number of classes is really needed to make message() truly
useful.  For the example given, let's say we make a new "broadcast"
class.  This message class would be used for important announcements
that everyone should hear.  Perhaps a restriction could even be made
so that muffle prohibited blocking this class.

Let's look at another example.  What if you're tired of all of the
millions of emotes (soul commands) that clutter your screen?  Wouldn't
it be nice to just muffle those?  Well, obviously a new "emote" class
is needed that all soul functions use.  Now you might be thinking to
yourself "hey... I don't want to have to use this really complex
message() efun every time I write a soul command.  write() and say()
are very simple, and I like using those."  Well, I couldn't agree with
you more.  To combat that problem, I make a simul_efun for each type
of commonly used message class. Like emote for example.  I made a new
simul_efun called emote() that in fact made writing soul commands
easier, and used message() with the "emote" class.  I won't show you
the code for the emote simul_efun, but here's the basic idea:

varargs int emote (object emoter, string self_message, string
	other_message, mixed emotee, string target_message, string modifier);

emoter - the object doing the emoting
self_message - the message displayed to the emoter
other_message - the message displayed to the whole room
emotee - the target of the emote (i.e. kick huthar)
target_message - the message displayed to the emotee
string modifier - any extra modifier to tack on to the end of the
	emote string. (i.e. adverbs: smiles happily, cheerfully, etc.) - only
	really complex soul commands need this (if they want to be able to
	control multiple modifiers to a single soul command)

At this point, some might be thinking, "ok... so you can do very
powerful selective muffling, big deal.  this seems like a lot of work
for nothing."  Good point.  Muffling was just a simple neat thing you
could do with message now.  Most of the real advantages from message
will come a bit down the line when someone gets around to writing a
smart client program.  Here's how that will work.

Basically the idea is to separate all of the messages sent to a user
by the content.  So you have a "combat" class, and a "stat" class, and
a "room_description" class, and a "help" class as some examples.
Before I get started, let's write a new version of receive_message().

int has_smart_client;

void receive_message (string msg, string class)
{
	if (member_array(class,muffle) == -1) {
		if (has_smart_client) 
			receive (class + " : " + msg);
		else
			receive (msg);
	}
}


Ok. Let's look at what this does.  If the user object has defined
has_smart_client to be > 0, then it prepends all messages with the
class name as well.  So if you were to write a smart client that
parsed messages like that, you could make it redirect room
descriptions into one window, conversation into another, combat into
yet another area, etc.  You could make a status line that always kept
your current room name (since it got passed as class "room_name" when
you enetered the room).  You could make the heart_beat, pass a class
"status" message which gives a constant readout of your hit points in
your status line.  All of this would be transparent to the end user.
It would just work.

In addition, you could do a simply graphical client using the same
technique.  The BSX graphical mud / client could easily be implemented
on top of MudOS using message().  Or you could pass around small
bitmaps rather than the simple line drawings of BSX.  The
possibilities are pretty wide open.

There is at least one major flaw with this argument so far.  Since
everyone has to implement this message protocol themselves, and since
nobody has written a smart client to take advantage of the protocol,
then when a client comes out, what's to guarantee that your mudlib
will even work with it?  Well, that's actually most of the point to
this document.  I'd like to outline a simple protocol that I hope
everyone will adopt, so that when a client finally comes out, it will
work with all mudlibs that adhere to this protocol.


The protocol:

all messages sent to the smart client are in the form

"class:msg_length:msg"

msg_len is the length of the msg string.  This is put in so that the
client can always know when it has received the entire message, and
when one starts and ends.

The following list of classes should be used and a client should be
able to parse and use any messages using these classes.

say			use of the "say" command or its equivalent
shout			use of the "shout" command or its equivalent
tell			use of the "tell" command or its equivalent
emote			a soul command or emote
broadcast		a broadcast message to everyone on the mud
combat			generic combat messages
combat_self		combat messages generated by the user's own attack
combat_other		combat messages generated by others
combat_*		all other specific combat messages
room_description	a long description of a room or location
room_name		a short name for a room or location
inventory		what you're carrying
item_description	a long description of the item
status			generic status messages
status_hp		current hit points
status_sp		current spell points
status_sobriety		current state of drunkeness
status_*		all other specific status messages
score			generic score messages
score_exp		experience points
score_money		the amount of coins or other money
developer		a broadcast message to all wizards/developers
class_fighter		a message to all fighters
class_mage		a message to all mages
class_thief		a message to all thieves
class_priest		a message to all priests
class_*			a message to the class specified
race_human		a message to all humans
race_elf		a message to all elves
race_dwarf		a message to all dwarves
race_*			a message to the race specified

*** optional classes to implement ***
bitmap			a generic bitmap message
bitmap_*		a specific type of bitmap
drawing			a generic drawing message
drawing_*		a specific type of drawing
