message_doc
the message() client protocol
message
is the efun in MudOS/FluffOS 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 (mixed type, string message, mixed target, mixed exclude);
message calls receive_message(mixed type, string message)
in all message recipients (derived from the target list) excluding those in the exclude list. This basically tells the objects the message through the receive_message apply.
type
is the type of message (used for clients and such). An example would be 'combat', 'shout', 'emergency', 'system', 'room description', etc.
message
is a string containing the message to be sent.
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 "type". If used properly, you could use this field to implement a very simple version of earmuffs/filter, or to communicate intelligently with a custom client. The type defines the type of message that the string contains. Initial simple implementations would have the types "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 type, string message) {
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 *muffled = ({});
int muffle_type (string type)
{
muffled += ({ type });
}
void receive_message (string type, string msg)
{
if (member_array(type, muffled) == -1) {
receive(msg);
}
}
Now you can see, that if a particular type is muffled (say, "shout" for example), the text never gets displayed, but for other types 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 types is really needed to make message() truly useful. For the example given, let's say we make a new "broadcast" type. This message type would be used for important announcements that everyone should hear. Perhaps a restriction could even be made so that muffle prohibited blocking this type.
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" type 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 type. 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" type. 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" type, and a "stat" type, and a "room_description" type, and a "help" type as some examples. Before I get started, let's write a new version of receive_message().
int has_smart_client;
void receive_message (string type, string msg)
{
if (member_array(type, muffled) == -1) {
if (has_smart_client) {
receive(type + " : " + 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 type 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 type "room_name" when you enetered the room). You could make the heart_beat, pass a type "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 polygon-based 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
"type: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 types should be used and a client should be able to parse and use any messages using these types.
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 types to implement _
bitmap a generic bitmap message
bitmap*\* a specific type of bitmap
drawing a generic drawing message
drawing*\* a specific type of drawing