skylib_fluffos_v3/
skylib_fluffos_v3/bin/
skylib_fluffos_v3/bin/db/
skylib_fluffos_v3/fluffos-2.9-ds2.04/
skylib_fluffos_v3/fluffos-2.9-ds2.04/ChangeLog.old/
skylib_fluffos_v3/fluffos-2.9-ds2.04/Win32/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/simuls/
skylib_fluffos_v3/fluffos-2.9-ds2.04/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/clone/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/command/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/data/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/etc/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/master/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/log/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/compiler/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/efuns/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/operators/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/u/
skylib_fluffos_v3/fluffos-2.9-ds2.04/tmp/
skylib_fluffos_v3/fluffos-2.9-ds2.04/windows/
skylib_fluffos_v3/mudlib/
skylib_fluffos_v3/mudlib/cmds/
skylib_fluffos_v3/mudlib/cmds/admin/
skylib_fluffos_v3/mudlib/cmds/guild-race/
skylib_fluffos_v3/mudlib/cmds/living/broken/
skylib_fluffos_v3/mudlib/cmds/player/group_cmds/
skylib_fluffos_v3/mudlib/cmds/playtester/
skylib_fluffos_v3/mudlib/d/admin/
skylib_fluffos_v3/mudlib/d/admin/room/
skylib_fluffos_v3/mudlib/d/admin/room/we_care/
skylib_fluffos_v3/mudlib/d/admin/save/
skylib_fluffos_v3/mudlib/d/admin/text/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/buildings/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/map/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/roads/
skylib_fluffos_v3/mudlib/d/learning/chars/
skylib_fluffos_v3/mudlib/d/learning/functions/
skylib_fluffos_v3/mudlib/d/learning/handlers/
skylib_fluffos_v3/mudlib/d/learning/help_topics/
skylib_fluffos_v3/mudlib/d/learning/help_topics/npcs/
skylib_fluffos_v3/mudlib/d/learning/help_topics/objects/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/crowd/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/situations/
skylib_fluffos_v3/mudlib/d/learning/save/
skylib_fluffos_v3/mudlib/d/learning/school/
skylib_fluffos_v3/mudlib/d/learning/school/add_sc/
skylib_fluffos_v3/mudlib/d/learning/school/characters/
skylib_fluffos_v3/mudlib/d/learning/school/general/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/basic_commands/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/edtutor/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_fluffos_v3/mudlib/d/learning/school/items/
skylib_fluffos_v3/mudlib/d/learning/school/npc_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/room_basic/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/situations/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_fluffos_v3/mudlib/d/learning/text/
skylib_fluffos_v3/mudlib/d/liaison/
skylib_fluffos_v3/mudlib/d/mudlib/
skylib_fluffos_v3/mudlib/d/mudlib/changes/
skylib_fluffos_v3/mudlib/d/playtesters/
skylib_fluffos_v3/mudlib/d/playtesters/effects/
skylib_fluffos_v3/mudlib/d/playtesters/handlers/
skylib_fluffos_v3/mudlib/d/playtesters/items/
skylib_fluffos_v3/mudlib/d/sage/
skylib_fluffos_v3/mudlib/doc/
skylib_fluffos_v3/mudlib/doc/creator/
skylib_fluffos_v3/mudlib/doc/driver/
skylib_fluffos_v3/mudlib/doc/driver/efuns/arrays/
skylib_fluffos_v3/mudlib/doc/driver/efuns/buffers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/calls/
skylib_fluffos_v3/mudlib/doc/driver/efuns/compile/
skylib_fluffos_v3/mudlib/doc/driver/efuns/filesystem/
skylib_fluffos_v3/mudlib/doc/driver/efuns/floats/
skylib_fluffos_v3/mudlib/doc/driver/efuns/functions/
skylib_fluffos_v3/mudlib/doc/driver/efuns/general/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mappings/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mixed/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mudlib/
skylib_fluffos_v3/mudlib/doc/driver/efuns/numbers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/parsing/
skylib_fluffos_v3/mudlib/doc/login/
skylib_fluffos_v3/mudlib/doc/lpc/basic_manual/
skylib_fluffos_v3/mudlib/doc/lpc/intermediate/
skylib_fluffos_v3/mudlib/doc/new/add_command/
skylib_fluffos_v3/mudlib/doc/new/events/
skylib_fluffos_v3/mudlib/doc/new/handlers/
skylib_fluffos_v3/mudlib/doc/new/living/race/
skylib_fluffos_v3/mudlib/doc/new/living/spells/
skylib_fluffos_v3/mudlib/doc/new/object/
skylib_fluffos_v3/mudlib/doc/new/player/
skylib_fluffos_v3/mudlib/doc/new/room/guild/
skylib_fluffos_v3/mudlib/doc/new/room/outside/
skylib_fluffos_v3/mudlib/doc/new/room/storeroom/
skylib_fluffos_v3/mudlib/doc/object/
skylib_fluffos_v3/mudlib/doc/playtesters/
skylib_fluffos_v3/mudlib/doc/policy/
skylib_fluffos_v3/mudlib/doc/weapons/
skylib_fluffos_v3/mudlib/global/
skylib_fluffos_v3/mudlib/global/creator/
skylib_fluffos_v3/mudlib/handlers/
skylib_fluffos_v3/mudlib/include/casino/
skylib_fluffos_v3/mudlib/include/cmds/
skylib_fluffos_v3/mudlib/include/effects/
skylib_fluffos_v3/mudlib/include/npc/
skylib_fluffos_v3/mudlib/include/room/
skylib_fluffos_v3/mudlib/include/shops/
skylib_fluffos_v3/mudlib/net/daemon/
skylib_fluffos_v3/mudlib/net/daemon/chars/
skylib_fluffos_v3/mudlib/net/inherit/
skylib_fluffos_v3/mudlib/net/obj/
skylib_fluffos_v3/mudlib/net/obj/BACKUPS/
skylib_fluffos_v3/mudlib/obj/amulets/
skylib_fluffos_v3/mudlib/obj/armours/plate/
skylib_fluffos_v3/mudlib/obj/b_day/
skylib_fluffos_v3/mudlib/obj/clothes/transport/horse/
skylib_fluffos_v3/mudlib/obj/faith/symbols/
skylib_fluffos_v3/mudlib/obj/fungi/
skylib_fluffos_v3/mudlib/obj/gatherables/
skylib_fluffos_v3/mudlib/obj/instruments/
skylib_fluffos_v3/mudlib/obj/media/
skylib_fluffos_v3/mudlib/obj/misc/player_shop/
skylib_fluffos_v3/mudlib/obj/monster/godmother/
skylib_fluffos_v3/mudlib/obj/monster/transport/
skylib_fluffos_v3/mudlib/obj/rings/
skylib_fluffos_v3/mudlib/obj/scabbards/
skylib_fluffos_v3/mudlib/obj/spells/
skylib_fluffos_v3/mudlib/obj/stationery/
skylib_fluffos_v3/mudlib/obj/stationery/envelopes/
skylib_fluffos_v3/mudlib/obj/toys/
skylib_fluffos_v3/mudlib/obj/vessels/
skylib_fluffos_v3/mudlib/obj/weapons/axes/
skylib_fluffos_v3/mudlib/obj/weapons/chains/
skylib_fluffos_v3/mudlib/obj/weapons/maces/BACKUPS/
skylib_fluffos_v3/mudlib/save/autodoc/
skylib_fluffos_v3/mudlib/save/book_handler/
skylib_fluffos_v3/mudlib/save/books/history/calarien/
skylib_fluffos_v3/mudlib/save/mail/
skylib_fluffos_v3/mudlib/save/new_soul/data/
skylib_fluffos_v3/mudlib/save/parcels/
skylib_fluffos_v3/mudlib/save/playerinfo/
skylib_fluffos_v3/mudlib/save/players/d/
skylib_fluffos_v3/mudlib/save/players/s/
skylib_fluffos_v3/mudlib/save/random_names/
skylib_fluffos_v3/mudlib/save/random_names/data/
skylib_fluffos_v3/mudlib/save/terrains/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_desert/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_grassy_field/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_mountain/
skylib_fluffos_v3/mudlib/save/todo_lists/
skylib_fluffos_v3/mudlib/secure/
skylib_fluffos_v3/mudlib/secure/cmds/admin/
skylib_fluffos_v3/mudlib/secure/cmds/lord/
skylib_fluffos_v3/mudlib/secure/config/
skylib_fluffos_v3/mudlib/secure/handlers/autodoc/
skylib_fluffos_v3/mudlib/secure/handlers/intermud/
skylib_fluffos_v3/mudlib/secure/include/global/
skylib_fluffos_v3/mudlib/secure/save/
skylib_fluffos_v3/mudlib/secure/save/handlers/
skylib_fluffos_v3/mudlib/secure/std/
skylib_fluffos_v3/mudlib/secure/std/classes/
skylib_fluffos_v3/mudlib/secure/std/modules/
skylib_fluffos_v3/mudlib/std/creator/
skylib_fluffos_v3/mudlib/std/dom/
skylib_fluffos_v3/mudlib/std/effects/
skylib_fluffos_v3/mudlib/std/effects/external/
skylib_fluffos_v3/mudlib/std/effects/fighting/
skylib_fluffos_v3/mudlib/std/effects/magic/
skylib_fluffos_v3/mudlib/std/effects/magic/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/other/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/priest/
skylib_fluffos_v3/mudlib/std/effects/room/
skylib_fluffos_v3/mudlib/std/environ/
skylib_fluffos_v3/mudlib/std/guilds/
skylib_fluffos_v3/mudlib/std/guilds/old/
skylib_fluffos_v3/mudlib/std/languages/
skylib_fluffos_v3/mudlib/std/liquids/
skylib_fluffos_v3/mudlib/std/npc/
skylib_fluffos_v3/mudlib/std/npc/goals/
skylib_fluffos_v3/mudlib/std/npc/goals/basic/
skylib_fluffos_v3/mudlib/std/npc/goals/misc/
skylib_fluffos_v3/mudlib/std/npc/plans/
skylib_fluffos_v3/mudlib/std/npc/plans/basic/
skylib_fluffos_v3/mudlib/std/npc/types/
skylib_fluffos_v3/mudlib/std/npc/types/helper/
skylib_fluffos_v3/mudlib/std/npcs/
skylib_fluffos_v3/mudlib/std/outsides/
skylib_fluffos_v3/mudlib/std/races/shadows/
skylib_fluffos_v3/mudlib/std/room/basic/BACKUPS/
skylib_fluffos_v3/mudlib/std/room/basic/topography/
skylib_fluffos_v3/mudlib/std/room/controller/
skylib_fluffos_v3/mudlib/std/room/inherit/topography/
skylib_fluffos_v3/mudlib/std/room/topography/area/
skylib_fluffos_v3/mudlib/std/room/topography/iroom/
skylib_fluffos_v3/mudlib/std/room/topography/milestone/
skylib_fluffos_v3/mudlib/std/shadows/curses/
skylib_fluffos_v3/mudlib/std/shadows/disease/
skylib_fluffos_v3/mudlib/std/shadows/fighting/
skylib_fluffos_v3/mudlib/std/shadows/healing/
skylib_fluffos_v3/mudlib/std/shadows/magic/
skylib_fluffos_v3/mudlib/std/shadows/poison/
skylib_fluffos_v3/mudlib/std/shadows/room/
skylib_fluffos_v3/mudlib/std/shops/controllers/
skylib_fluffos_v3/mudlib/std/shops/objs/
skylib_fluffos_v3/mudlib/std/shops/player_shop/
skylib_fluffos_v3/mudlib/std/socket/
skylib_fluffos_v3/mudlib/std/soul/d/
skylib_fluffos_v3/mudlib/std/soul/e/
skylib_fluffos_v3/mudlib/std/soul/i/
skylib_fluffos_v3/mudlib/std/soul/j/
skylib_fluffos_v3/mudlib/std/soul/k/
skylib_fluffos_v3/mudlib/std/soul/l/
skylib_fluffos_v3/mudlib/std/soul/n/
skylib_fluffos_v3/mudlib/std/soul/o/
skylib_fluffos_v3/mudlib/std/soul/q/
skylib_fluffos_v3/mudlib/std/soul/r/
skylib_fluffos_v3/mudlib/std/soul/u/
skylib_fluffos_v3/mudlib/std/soul/v/
skylib_fluffos_v3/mudlib/std/soul/y/
skylib_fluffos_v3/mudlib/std/soul/z/
skylib_fluffos_v3/mudlib/std/stationery/
skylib_fluffos_v3/mudlib/w/
skylib_fluffos_v3/mudlib/w/default/
skylib_fluffos_v3/mudlib/w/default/armour/
skylib_fluffos_v3/mudlib/w/default/clothes/
skylib_fluffos_v3/mudlib/w/default/item/
skylib_fluffos_v3/mudlib/w/default/npc/
skylib_fluffos_v3/mudlib/w/default/room/
skylib_fluffos_v3/mudlib/w/default/weapon/
skylib_fluffos_v3/mudlib/www/
skylib_fluffos_v3/mudlib/www/java/
skylib_fluffos_v3/mudlib/www/secure/
skylib_fluffos_v3/mudlib/www/secure/lpc/advanced/
skylib_fluffos_v3/mudlib/www/secure/lpc/intermediate/
skylib_fluffos_v3/win32/
/*
 * DS history.
 * 30/07/01, Shiannar: Added mail inform.
 * 05/08/01, Sandoz : Added refresh inform.
 * 31/01/02, Sandoz : Added someone/something expansion for darkness.
 */
/**
 * This file contains all the standard event handling code that players
 * need.  This will handle things like informs, shouts, says, tells,
 * whispers.  Everything!   It formats the message correctly and
 * sends it to the player.
 * @author Pinkfish
 */

#include <dirs.h>
#include <player.h>
#include <telnet.h>
#include <language.h>

#define SPACES "                                                              "

#ifdef OLD_THINGY
inherit "/global/player/play_parse_com";
#else
inherit "/global/player/new_parse";
#endif
inherit "/global/player/communicate";

private int earmuffs, cols, rows;
private mapping my_colours;

/*
 * This so that changeing the definitions gets fixed
 * when they log in again.  Also keeps the save
 * file smaller.
 */
private nosave mapping colour_map;
private string term_name = "network";
private string *inform_types;
private mixed tell_history;
private mixed say_history;
private nosave string _cur_term, _last_term;
private nosave object _where, *_had_shorts;
private nosave mixed _eemessages;
private nosave mixed _busy;
private nosave mapping _inform_colours = ([ "default"      : "WHITE",
                                            "logon"        : "GREEN",
                                            "death"        : "RED",
                                            "cheat"        : "RED",
                                            "multiplayer"  : "RED",
                                            "bad-password" : "RED",
                                            "link-death"   : "GREEN",
                                            "friend"       : "MAGENTA",
                                            ]);

void set_my_colours(string event_type, string colour);
mapping query_my_colours();

string find_rel(string word, int from);
private int set_our_rows(int num);
private int set_our_cols(int num);
private int do_busy(string str);
private int do_busy_player(object *players);
protected varargs int do_tell_his(string, int);
protected varargs int do_say_his(string, int);

void create() {
    languages = ({ "common" });
    cur_lang = "common";
    _eemessages = ({ });
    my_colours = ([ ]);
    inform_types = ({ });
#ifdef OLD_THINGY
    play_parse_com::create();
#else
    new_parse::create();
#endif
} /* create() */

/**
 * This method returns the current terminal name.  If this is set to
 * network then the network will be queried for the terminal type
 * (using telnet suboption negotiation).
 * @return the current terminal name
 * @see query_cur_term()
 * @see set_term_type()
 */
string query_term_name() { return term_name; }
/**
 * This method returns the current terminal type that is being used.  This
 * will be 0 if the terminal name is set to network and no response has
 * been gained from the remote site yet.  Otherwise it should be the
 * same value as the terminal name.
 * @return the current terminal type
 * @see query_term_name()
 * @see set_term_type()
 */
string query_cur_term() { return _cur_term; }
/**
 * This method tells us if the player currently has earmuffs turned on.
 * @return 1 if earmuffs are on, 0 if they are not
 * @see check_earmuffs()
 * @see toggle_earmuffs()
 */
int query_earmuffs() { return earmuffs; }

/**
 * This method returns the list of inform types this player can receive.
 * @return array of inform types
 */
string *query_inform_types() {
    string *types;

    types = ({"logon", "birthday", "mail", "friend"});

    if( creatorp(TO) ) {
        types += ({"link-death", "message", "death", "error", "guild",
                   "delete", "help", "combat", "skill", "quest",
                   "multiplayer", "bad-password", "club", "debug",
                   "changelog", "typolog", "refresh"});

        if( lordp(TO) )
            types += ({"lord", "enter", "dest", "xp", "rolls", "trans"});

        if( adminp(TO) )
            types += ({"force", "cheat", "cpu", "ftp", "admin", "calls"});

        if( adminp(TO) || DOMAIN_H->query_creator("library", TO->query_name() ) )
            types += ({"autodoc"});
    }

    return types;

} /* query_inform_types() */

/* This is pulled back into this object for security reasons... */
/**
 * This is the command to handle the inform stuff.
 * It does all the turning on/off and stuff things for the informs.
 * @param str the informs to listen to
 * @see event_inform()
 */
protected int do_inform(string str) {
    string type, *types, *on, *frog, *off, *failed;
    int i;

    types = query_inform_types();

    foreach( type in inform_types )
        if( member_array( type, types ) == -1 )
            inform_types -= ({ type });

    on = sort_array( inform_types || ({ }), 1 );

    if( !str )
        str = "";

    frog = explode( str, " ");

    if( !frog )
        frog = ({ });
    else
        frog -= ({"", 0 });

    if( !sizeof(frog) ) {
        if( TO->query_property("inform repressed") )
            write("Your informs are currently being repressed.\n");
        if( sizeof(on) )
            write("$I$5=You are being informed of "+
                query_multiple_short(on)+" events.\n");
        if( sizeof( types = sort_array( types -= on, 1 ) ) )
            write("$I$5=You are not being informed of "+
                query_multiple_short(types)+" events.\n");
        return 1;
    }

    if( sizeof(frog) == 1 ) {
        switch( frog[0] ) {
        case "on" :
          TO->remove_property("inform repressed");
          write("You are now being informed.  This is true!\n");
          write("$I$5=You will be informed of "+
              query_multiple_short(on)+" events.\n");
          return 1;
        case "off":
          TO->add_property("inform repressed", 1 );
          write("Informs are now repressed.\n");
          return 1;
        case "all":
          on = types;
          frog = frog[1..];
        break;
        case "none" :
          on = ({ });
          write("You will not be informed of anything.\n");
          frog = frog[1..];
          break;
        }
    }

    failed = off = ({ });

    for( i = 0; i < sizeof(frog); i++ ) {
        if( member_array( frog[i], types ) == -1 ) {
            failed += ({ frog[i] });
        } else {
            if( sizeof(frog) > i+1 ) {
                switch( frog[i+1] ) {
                  case "on" :
                    if( member_array( frog[i], on ) == -1 )
                        on += ({ frog[i] });
                    i++;
                  break;
                  case "off" :
                    off += ({ frog[i] });
                    i++;
                  break;
                  default :
                    if( member_array( frog[i], on ) == -1 )
                        on += ({ frog[i] });
                    else
                        off += ({ frog[i] });
                  break;
                }
            } else {
                if( member_array( frog[i], on ) == -1 )
                    on += ({ frog[i] });
                else
                    off += ({ frog[i] });
            }
        }
    }

    on -= off;

    if( sizeof(failed) )
        write("$I$5=There are no "+query_multiple_short(failed)+" events.\n");
    if( sizeof(off) )
        write("$I$5=You will now not be informed of "+
            query_multiple_short(off)+" events.\n");
    if( sizeof(on) )
        write("$I$5=You will now be informed of "+
            query_multiple_short(on)+" events.\n");

    inform_types = on;
    return 1;

} /* do_inform() */

/**
 * This method tests to see if the player can see octarine objects.
 * @return 1 if they can see octarine, 0 if they cannot
 */
int query_see_octarine() {
    if( creatorp(TO) )
        return 1;
    return 0;
} /* query_see_octarine() */

/**
 * This method will do the octarine checking for you on the message.
 * @param str the string to check
 * @see query_see_octarine()
 * @example
 * string query_long_bit() {
 *   return "Glinting and sharp looking, the long sword is an impressive "
 *          "weapon in the hands of someone knowledgeable.\n" +
 *          this_player()->octarine_message("It glows with a fluffy octarine "
 *                                          "aura.\n");
 * } /\* query_long_bit() *\/
 */
string octarine_message( string str ) {
    return ( query_see_octarine() ? str : "" );
} /* octarine_message() */

/**
 * This function returns the appropriate colour codes for the given event
 * type. It will return the players chosen colour if they've set one or
 * the default if not.
 *
 * @param event_type The type of event
 * @return a string of colour codes.
 */
string colour_event( string event_type, string default_colour ) {
    if( my_colours[event_type] )
        return replace( my_colours[event_type], " ", "" );
    return default_colour || "";
} /* colour_event() */

/**
 * This method handles the conversersions for the colour mapping which is
 * done on Discworld.  This also does octarine message expansion, if the
 * keyword %\^OCTARINE:message%\^ is embeded into a string then the
 * inside section will be replaced with a blank string if the player
 * cannot see octarine messages.
 * @param str the string to do the conversion on
 * @param width the width of the string
 * @param indent the size of the indent
 * @param args any other arguments
 * @return the fixed up string
 * @see efun::terminal_colour()
 */
varargs string fix_string( string str, int width, int indent, mixed args ... ) {
    string octmess, *bits, bit;
    int i;

    if( !stringp(str) || str == "" )
        return str;

    if( indent > width / 3 )
        indent = 4;

    if( !_cur_term )
        _cur_term = ( term_name != "network" ? term_name : "dumb" );

    if( !colour_map )
        colour_map = (mapping)TERM_H->set_term_type(_cur_term);

    if( sizeof(args) )
        str = sprintf( str, args ... );

    bits = explode( str, "%^OCTARINE:");
    foreach( bit in bits ) {
        i = strsrch( bit, "%^");
        if( i == -1 )
            continue;
        octmess = bit[0..i-1];
        if( query_see_octarine() ) {
            str = replace_string( str, sprintf("%%^OCTARINE:%s%%^", octmess ),
                octmess );
        } else {
            str = replace_string( str, sprintf("%%^OCTARINE:%s%%^",
                octmess ), "");
        }
    }

    str = terminal_colour( str, colour_map, width, indent );
    return str;

} /* fix_string() */

/* Send all the relevant junk down to get the information we want. */
/** @ignore yes */
void player_connected() {
    _last_term = 0;
    /* Turn on the option */
    printf("%c%c%c", IAC, DO, TELOPT_TTYPE );
    /* Get them to send us their first terminal type */
    printf("%c%c%c%c%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE );
    /* Get them to send us their window size */
    printf("%c%c%c", IAC, DO, TELOPT_NAWS );
} /* player_connected() */

/**
 * This method sets the current terminal type for the player.  If the type
 * is network, then the network will be queried for the terminal type
 * and that will be used.  This is the distiction between the current
 * terminal type and the terminal name.  The name will be the value that
 * is set by the player and the current type will be the information
 * garnered from the network (if the name is network) or the same as the
 * name.
 * @param str the new terminal type
 * @return 1 if the terminal was successful set, 0 if not
 * @see set_term()
 * @see query_term_name()
 * @see query_cur_term()
 */
int set_term_type( string str ) {
    if( !str )
        return notify_fail( sprintf("%-=*s", cols,
            "Syntax: "+query_verb()+" <term_type>\n"+
            "Where term type is one of the following: "+
            implode((string *)TERM_H->query_term_types(), ", ")+
            ".\nOr set it to \"network\", and the mud will try to "
            "figure it out itself.\n") );

    if( str != term_name ) {
        if( member_array( str, (string *)TERM_H->query_term_types() ) != -1 ||
            str == "network") {
            if( str != "network")
                colour_map = (mapping)TERM_H->set_term_type(str);
            else
                player_connected();
            term_name = str;
            _cur_term = 0;
            write("Ok, terminal type set to "+str+".\n");
            return 1;
        } else {
            return notify_fail("No such terminal type as "+str+".\n");
        }
    }

    return notify_fail("Terminal type unchanged as "+str+".\n");

} /* set_term_type() */

/** @ignore yes */
void set_term(string name) {
    term_name = name;
    _cur_term = 0;
} /* set_term() */

/**
 * This method handles the responses from the remote site informing
 * us of their terminal type.
 * @param name the terminal type gathered from the remote site
 * @return 0 if the type was not used, 1 if it was
 * @see set_term_type()
 * @see query_term_name()
 * @see query_cur_term()
 */
int set_network_terminal_type(string name) {
    if( term_name != "network")
        return 0;

    if( !name ) {
        _cur_term = "dumb";
        colour_map = 0;
    }

    if( colour_map = (mapping)TERM_H->set_network_term_type(name) ) {
        _cur_term = name;
        return 1;
    }

} /* set_network_terminal_type() */

/**
 * This method adds all the event commands onto the player.
 * This will be called in the player startup sequence.
 */
void event_commands() {
    add_command("rows", TO, "", (: set_our_rows(0) :) );
    add_command("cols", TO, "", (: set_our_cols(0) :) );
    add_command("rows", TO, "<number>", (: set_our_rows($4[0]) :) );
    add_command("cols", TO, "<number>", (: set_our_cols($4[0]) :) );
    add_command("term", TO, "{"+
      implode((string *)TERM_H->query_term_types() +
        ({"network"}), "|")+"}", (: set_term_type($4[0]) :) );
    add_command("term", TO, "", (: set_term_type(0) :) );
    add_command("inform", TO, "", (: do_inform(0) :) );
    add_command("inform", TO, "<string>", (: do_inform($4[0]) :) );

    if( creatorp(TO) ) {
        add_command("busy", TO, "{on|off}", (: do_busy($4[0]) :) );
        add_command("busy", TO, "<indirect:player>",
            (: do_busy_player($1) :) );
    }

} /* event_commands() */

/**
 * Return function pointer for do_tell_his, for history tell only.
 */
function get_htell_func() {
    if( file_name(PO) != "/cmds/player/hi_story" &&
        file_name(PO) != "/cmds/lord/hi_story")
        return 0;
    return (: do_tell_his :);
} /* get_htell_func() */

/**
 * This method is the command used to print a players tell history.
 */
protected varargs int do_tell_his(string str, int brief) {
    string ret;
    mixed bit, *filter_history;

    if( str != "")
        filter_history = filter( tell_history,
          (: strsrch( lower_case($1[0]), $(str) ) > -1 :) );
    else filter_history = tell_history;

    if( !pointerp(filter_history) || !sizeof(filter_history) )
        return notify_fail("You have not been told anything.\n");

    if( undefinedp(brief) )
        brief = 0;

    ret = "$P$Tell History$P$Your tell history is:\n";

    foreach( bit in filter_history ) {
        if( !brief )
            ret += "** "+ctime(bit[2])+" **\n";
        ret += fix_string("%s%s\n", cols, strlen(bit[0]), bit[0], bit[1] );
    }

    write(ret);
    return 1;

} /* do_tell_his() */

/**
 * Return function pointer for do_say_his, for history say only.
 */
function get_hsay_func() {
    if( file_name(PO) != "/cmds/player/hi_story" &&
        file_name(PO) != "/cmds/admin/hi_story")
        return 0;
    return (: do_say_his :);
} /* get_hsay_func() */

/**
 * This method is the command used to print a players say history.
 */
protected varargs int do_say_his(string str, int brief) {
    string ret;
    mixed bit, *filter_history;

    if( str != "")
        filter_history = filter( say_history,
          (: strsrch( lower_case($1[0]), $(str) ) > -1 :) );
    else
        filter_history = say_history;

    if( !pointerp(filter_history) || !sizeof(filter_history) )
        return notify_fail("Nobody has said anything.\n");

    if( undefinedp(brief) )
        brief = 0;

    ret = "$P$Say History$P$Your say history is:\n";

    foreach( bit in filter_history ) {
        if( !brief )
            ret += "** "+ctime(bit[2])+" **\n";
        ret += fix_string("%s%s\n", cols, strlen(bit[0]), bit[0], bit[1] );
    }

    write(ret);
    return 1;

} /* do_say_his() */

/**
 * This method handles setting the busy flag.  The busy flag can only
 * be set by liaisons and lords, why lords?  Just because :)  This
 * command was inspired by moonchild.
 * @param str the on or off string
 * @return 1 on success, 0 on failure
 */
int do_busy( string str ) {
    _busy = ( str == "on");
    write("Busy set to "+str+".\n");
    return 1;
} /* do_busy() */

/**
 * This method allows creators to set the player for whom they are currently
 * busy too.
 * @param obs the player to be busy with
 * @return 1 on success, 0 on failure
 */
int do_busy_player( object *obs ) {
    write("Ok, setting you as busy with "+query_multiple_short(obs)+".\n");
    _busy = obs;
    return 1;
} /* do_busy_player() */

/**
 * This method tells us if the player/creator/lord is currently in busy
 * mode.  This will be 1 if the creatopr is generaly busy, or
 * it will return the array of players they are busy with.
 * @return the busy mode flag
 */
mixed query_busy() {
    if( pointerp(_busy) )
        _busy -= ({ 0 });

    if( pointerp(_busy) && !sizeof(_busy) )
        _busy = 0;

    return _busy;

} /* query_busy() */

/**
 * This method will change the current value of the earmuffs on the player.
 * @see check_earmuffs()
 * @see query_earmuffs()
 */
void toggle_earmuffs() {
    earmuffs = !earmuffs;
} /* toggle_earmuffs() */

/**
 * This method checks to see if a particular event is earmuffed.
 * @param type the type of event to check
 * @return 1 if the event is earmuffed and 0 if it is not
 * @see toggle_earmuffs()
 * @see query_earmuffs()
 * @example
 *   obs = users();
 *   obs = filter( obs, (: $1->check_earmuffs("shout") :) );
 *   // Do the shout
 */
int check_earmuffs( string type ) {
    string *on;

    if( !earmuffs )
        return 0;

    on = (string *)TO->query_property("earmuffs");
    if( !on )
        return 0;

    return member_array( type, on ) != -1;

} /* check_earmuffs() */

/**
 * This method sets the number of rows on the players screen.
 * @param i the new number of rows
 * @see query_rows()
 */
void set_rows( int i ) {
    if( i < 5 )
        return;
    rows = i;
} /* set_rows() */

/**
 * This method returns the current number of rows the player has
 * set on their screen.
 * @return the number of rows on the screen
 * @see set_rows()
 */
int query_rows() { return rows; }

private int set_our_rows(int val) {
    if( !val )
        return notify_fail("Rows currently set to "+rows+
            ".\nrows <number> to set.\n");

    if( val <= 10 )
        return notify_fail("Invalid number of rows.\n");

    write("Rows set to "+val+".\n");
    rows = val;
    return 1;

} /* set_our_rows() */

/**
 * This method returns the current number of columns the player has
 * set on their screen.
 * @return the number of columns on the screen
 * @see set_cols()
 */
int query_cols() { return cols; }

/**
 * This method sets the current number of columns the player has set on
 * their screen.
 * @param i the new number of columns
 * @see query_cols()
 */
void set_cols( int i ) {
    if( i <= 10 || i > 999 )
        return;
    cols = i;
} /* set_cols() */

private int set_our_cols(int val) {
    if( !val )
        return notify_fail("Columns currently set to "+cols+
            ".\ncols <number> to set.\n");

    if( val <= 35 || val > 999 )
        return notify_fail("Invalid column size.\n");

    write("Columns set to "+val+".\n");
    cols = val;
    return 1;

} /* set_our_cols() */

/**
 * This method sets the colour codes for a given event.
 * @param event_type the type of event to set the colour for
 * @param colour the colour to set
 */
void set_my_colours( string event_type, string colour ) {
    if( colour == "default") {
        map_delete( my_colours, event_type );
        return;
    }

    if( colour == "none") {
        my_colours[event_type] = "";
        return;
    }

    my_colours[event_type] = colour;

} /* set_my_colours() */

/**
 * Return a players list of custom colours.
 * @return a mapping of the players custom colours for different events.
 */
mapping query_my_colours() { return my_colours; }

void set_looked( object thing ) { _where = thing; }

/**
 * This method does all those terrible things with messages and $'s
 * turning them into real strings.  It is a neat function if somewhat
 * complicated :)  It was written by Deutha.
 * <p>
 * The return array has two elements, the first being the reformed
 * message and the second being the reformed things array.
 * @param message the message to reform
 * @param things some bonus things to reform it with
 * @return an array consisting of two elements
 */
mixed reform_message( string message, mixed things ) {
    int last, number;
    string before, middle, after, info;

    last = -1;

    if( !things )
        things = ({ });

    if( !_where )
        _where = environment();

    after = message;

    while( sscanf( message, "%s$R$%s$R$%s", before, middle, after ) == 3 ) {
        if( sscanf( middle, "[%s]%s", info, middle ) != 2 )
            info = "";
        switch ( middle[ 0 ] ) {
          case '-' :
            number = 0;
            middle = middle[ 1 .. ];
          break;
          case '+' :
            number = 1;
            middle = middle[ 1 .. ];
          break;
          default :
            number = 2;
        }
        if( number == 2 || _where->query_relative( middle ) ) {
            if( creatorp(TO) ) {
                message = before + find_rel( middle, number ) +" ("+ middle +
                ")"+ after;
            } else {
                message = before + find_rel( middle, number ) + after;
            }
        } else {
            message = before + info + middle + after;
        }
    }

    after = message;

    while( sscanf( message, "%s$r$%s$r$%s", before, middle, after ) == 3 ) {
        if( sscanf( middle, "[%s]%s", info, middle ) != 2 )
            info = "";
        switch ( middle[ 0 ] ) {
          case '-' :
            number = 0;
            middle = middle[ 1 .. ];
          break;
          case '+' :
            number = 1;
            middle = middle[ 1 .. ];
          break;
          default :
            number = 2;
        }
        if( number == 2 || _where->query_relative( LENGTHEN[ middle ] ) ) {
            if( creatorp(TO) ) {
                message = before + SHORTEN[ find_rel( LENGTHEN[ middle ],
                    number ) ] +" ("+ middle + ")"+ after;
            } else {
                message = before + SHORTEN[ find_rel( LENGTHEN[ middle ],
                    number ) ] + after;
            }
        } else {
            message = before + info + middle + after;
        }
    }

    after = message;
    while( sscanf( after, "%s$%d$%s", before, number, after ) == 3 )
        last = number;

    while( sscanf( message, "%s$M$%s$M$%s", before, middle, after ) == 3 ) {
        last++;
        message = before +"$"+ last +"$"+ after;
        things += ({ ({ }) });
        if( strsrch(middle, "$") == -1 ) {
            things[ last ] += ({ middle });
            middle = 0;
        } else {
            while ( sscanf( middle, "$%s$%s", info, middle ) == 2 )
                things[ last ] += ({ "my_"+ info });
        }
    }

    after = message;
    message = "";

    while( sscanf( after, "%s$%s$%s", before, middle, after ) == 3 ) {
        if( sscanf( middle, "%s_short:%s", middle, info ) != 2 ) {
            message += before +"$"+ middle;
            after = "$"+ after;
            continue;
        }
        last++;
        message += before +"$"+ last +"$";
        things += ({ ({ "my_"+ middle +"_short:"+ info }) });
    }

    message += after;

    return ({ message, things });

} /* reform_message() */

/**
 * This adds a message into the current list of printable messages.  This
 * will be squided up together and printed out slightly later, this handles
 * the concatenating of enter messages, and soul messages.  Etc.
 * @param message the message to add
 * @param things the objects which are involved with the message
 * @see reform_message()
 */
void add_message( string message, mixed things ) {
    int last;
    mixed stuff;

    if( !interactive( TO ) )
        return;

    if( strsrch( message, "$" ) == -1 )
        stuff = ({ message, things });
    else
        stuff = reform_message( message, things );

    _where = 0;

    if( !sizeof( _eemessages ) ) {
        call_out( "print_messages", 2 );
        _eemessages = stuff;
    } else {
        last = sizeof( _eemessages ) - 2;
        if( stuff[ 0 ] == _eemessages[ last ] && sizeof( stuff[ 1 ] ) == 1 ) {
            if( sizeof( filter( stuff[ 1 ][ 0 ],
                (: member_array($1, $2) != -1 :),
                _eemessages[ last + 1 ][ 0 ] ) ) ) {
                _eemessages += stuff;
            } else {
                _eemessages[ last + 1 ][ 0 ] += stuff[ 1 ][ 0 ];
            }
        } else {
            _eemessages += stuff;
        }
    }

} /* add_message() */

/**
 * This method checks whether or not the room the
 * player is in is dark enough to use 'someone'
 * instead of regular shorts.
 */
int query_is_dark( object thing ) {
    if( !ENV(TO) || thing == ENV(TO) || ( ENV(thing) && ENV(thing) == TO ) ||
        TO->query_property("doing_soul") ||
        ( creatorp(TO) && !TO->query_property("always_dark") ) )
        return 0;

    return TO->check_dark( ENV(TO)->query_light() ) != 0;

} /* query_is_dark() */

/**
 * @ignore yes
 * This method is used for the reform_mesage stuff
 */
string get_pretty_short( object thing ) {
    if( !thing->query_visible( TO ) || TO->query_is_dark(thing) )
        return ( living( thing ) ? "someone" : "something" );
    return (string)thing->pretty_short( TO ) +
           (string)thing->hide_invis_string();
} /* get_pretty_short() */

/**
 * @ignore yes
 * This method is used for the reform_message stuff
 */
string get_pretty_plural( object thing ) {
    if( !thing->query_visible( TO ) || TO->query_is_dark(thing) )
        return ( living( thing ) ? "people" : "things" );
    return (string)thing->pretty_plural( TO ) +
           (string)thing->hide_invis_string();
} /* get_pretty_plural() */

/**
 * This is a special function for use with the reform message, it allows
 * the string to be echoed into the list instead of using the object's
 * value itself.  This is done specifically to handle objects with
 * variable shorts, so we get the short description correct at the
 * moment it is queried.
 */
string my_mirror_short( object thing, string arg ) {
    return arg;
} /* my_mirror_short() */

/**
 * @ignore yes
 * This method is used for the reform_mesage stuff
 */
string my_a_short( object thing ) {
    string article;

    if( !objectp( thing ) )
        return "an unknown object";

    // forget the article if it's dark.
    if( TO->query_is_dark( thing ) )
        return (string)TO->get_pretty_short( thing );

    if( !article = (string)thing->query_determinate( TO ) )
        return add_a( (string)TO->get_pretty_short( thing ) );

    return article + (string)TO->get_pretty_short( thing );

} /* my_a_short() */

/**
 * @ignore yes
 * This method is used for the reform_mesage stuff
 */
string my_the_short( object thing ) {
    string article;

    if( !objectp( thing ) )
        return "the unknown object";

    // forget the article if it's dark.
    if( TO->query_is_dark( thing ) )
        return (string)TO->get_pretty_short( thing );

    if( !( article = (string)thing->query_determinate( TO ) ) ||
        article == "a " || article == "an " )
        return "the "+ (string)TO->get_pretty_short( thing );

    return article + (string)TO->get_pretty_short( thing );

} /* my_the_short() */

/** @ignore yes */
int some_more( string word ) {
    return sizeof( filter( INV( _where ),
        (: $1->query_plural() == $(word) :) ) ) > 1;
} /* some_more() */

/**
 * @ignore yes
 * This method is used for the reform_mesage stuff
 */
string my_one_short( object thing ) {
    string article, its_plural;

    if( !objectp( thing ) )
        return "one of the unknown objects";

    _where = ( ENV(thing) && ENV( thing ) != ENV(TO) ? ENV(thing) :
               environment() );

    // forget the article if it's dark.
    if( TO->query_is_dark( thing ) )
        return (string)TO->get_pretty_short( thing );

    if( !( article = (string)thing->query_determinate( TO ) ) ||
        article == "a " || article == "an " ) {
        its_plural = (string)TO->get_pretty_plural( thing );
        if( some_more( its_plural ) )
            return "one of the "+ its_plural;
        return "the "+ (string)TO->get_pretty_short( thing );
    }

    return article + (string)TO->get_pretty_short( thing );

} /* my_one_short() */

/**
 * @ignore yes
 * This method is used for the reform_mesage stuff
 */
string my_poss_short( object thing ) {
    string article, its_plural, of_whom;

    if( !objectp( thing ) )
        return "an unknown object";

    if( living(thing) ) {
        if( thing == TO )
            return "your";
        _where = ( ENV( thing ) != ENV(TO) ? TO : environment() );
        return TO->my_one_short( thing ) + ( some_more(
            (string)TO->get_pretty_plural( thing ) ) ?
            ( TO->query_is_dark( thing ) ? "'s" : "'") : "'s" );
    }

    if( !_where = environment( thing ) )
        return my_a_short( thing );

    if( !living( _where ) && !_where->query_corpse() )
        return my_a_short( thing );

    if( _where == TO ) {
        of_whom = "your ";
    } else {
        // forget the owner if it's dark.
        if( TO->query_is_dark( thing ) )
            return (string)TO->get_pretty_short( thing );
        of_whom = ( member_array( _where, _had_shorts ) != -1 ?
                  (string)_where->query_possessive() :
                  my_the_short( _where ) +"'s" ) +" ";
    }

    if( !article || article == "a " || article == "an " ) {
        its_plural = (string)TO->get_pretty_plural( thing );
        if( thing->query_holder() ) {
            foreach( object ob in thing->query_holder()->query_holding() ) {
              if( ob && ob != thing &&
                  (string)TO->get_pretty_plural( ob ) == its_plural )
                  return "one of "+ of_whom + its_plural;
            }
            return of_whom + (string)TO->get_pretty_short( thing );
        }
        if( some_more( its_plural ) )
            return "one of "+ of_whom + its_plural;
    }

    return of_whom + (string)TO->get_pretty_short( thing );

} /* my_poss_short() */

/**
 * @ignore yes
 * This method is used for the reform_message stuff
 */
string calc_shorts( string *short_list ) {
    int i;
    string list, str, desc;
    object ob, *things;
    // These next two are tied.
    string *descs_str;
    mixed descs_ob;
    mixed parts;

    descs_str = ({ });
    descs_ob  = ({ });

    foreach( str in short_list ) {
        parts = explode( str, ":" );
        if( sizeof(parts) > 1 ) {
            ob = find_object( parts[ 1 ] );
        } else {
            ob = 0;
            parts += ({""});
        }

        if( ob )
            _had_shorts = ({ ob }) + _had_shorts;

        if( ob == TO )
            desc = ( parts[0] == "my_poss_short" ? "your" : "you" );
        else if( sizeof(parts) >= 2 )
            desc = (string)call_other( TO, parts[0], ob, parts[1] );
        else
            desc = ( sizeof(parts[0]) ? parts[0] : "something" );

        if( ( i = member_array( desc, descs_str ) ) == -1 ) {
            descs_str += ({ desc });
            descs_ob += ({ ({ ob }) });
        } else {
            descs_ob[i] += ({ ob });
        }
    }

    if( ( i = member_array( "you", descs_str ) ) != -1 &&
        i != sizeof(descs_str) - 1 ) {
        descs_str = descs_str[0..i-1] + descs_str[i+1..] + ({ "you" });
        descs_ob = descs_ob[0..i-1] +  descs_ob[i+1..] + descs_ob[i..i];
    }

    list = "";

    for( i = 0; i < sizeof( descs_str ); i++ ) {
        things = descs_ob[ i ];
        if( sizeof( things ) == 1 ) {
            list += descs_str[ i ];
        } else {
            things -= ({ 0 });
            if( sizeof(things) ) {
                list += query_num( sizeof( things ), 20 )+" "+
                    (string)TO->get_pretty_plural( things[ 0 ] );
            } else {
                list += query_num( sizeof( things ), 20 ) +" unknown objects";
            }
        }
        if( i == sizeof( descs_str ) - 1 )
            continue;
        list += ( i == sizeof( descs_str ) - 2 ? " and " : ", " );
    }

    return list;

} /* calc_shorts() */

/**
 * This method fits a message into a the current players screen size.  This
 * does all sorts of other evil stuff too, like handling indenting and
 * all sorts of things!  Most of which I do not understand so I won't
 * say anything about here.
 * @param message the message to fit in
 * @return the fitted message
 */
string fit_message( string message ) {
    int left, right, space;
    string *parts, part;
    mixed stuff;

    if( strlen( message ) < 6 )
        return message;

    if( message[0..2] != "$I$" )
        message = "$I$0=$C$" + message;

    parts = explode( message, "$C$" );
    parts = map( parts, (: CAP($1) :) );
    parts = explode( implode( parts, "" ), "$I$");

    message = "";

    foreach( part in parts ) {
        if( sscanf( part, "%s=%s", stuff, part ) != 2 ) {
            message += fix_string( "$I$"+part, cols );
            continue;
        }

        if( stuff == "") {
            message += fix_string( "$I$="+part, cols );
            continue;
        }

        if( stuff[0] == ' ' )
            space = !space;

        stuff = explode( stuff, "," );

        if( sizeof(stuff) && stuff[0] != "" ) {
            switch( stuff[0][0] ) {
            case '+' :
              if( space && left > 0 && part != "")
                  part = SPACES[0..left-1] + part;
              left += to_int( stuff[0][1..] );
            break;
            case '-' :
              left -= to_int( stuff[0][1..] );
              if( left < 0 )
                  left = 0;
              if( space && left > 0 && part != "")
                  part = SPACES[0..left-1] + part;
            break;
            default :
              left = to_int( stuff[0] );
            }
        } else {
            left = 0;
        }

        if( sizeof( stuff ) > 1 ) {
            switch( stuff[1][0] ) {
            case '+' :
              right += to_int( stuff[1][1..] );
            break;
            case '-' :
              right -= to_int( stuff[1][1..] );
              if( right < 0 )
                  right = 0;
            break;
            default :
              right = to_int( stuff[1] );
            }
        } else {
            right = 0;
        }

        message += ( left > 0 ?
            fix_string( part, cols - right, left ) :
            fix_string( part, cols - right ) );
    }

    return message;

} /* fit_message() */

/**
 * This method shows the message to the player.
 * @param message the message to show
 * @see fit_message()
 */
void show_message( string message ) {
    string bit;

    if( sscanf( message, "$P$%s$P$%s", bit, message ) == 2 ) {
        TO->more_string( fit_message( message ), bit, 1 );
        return;
    }

    efun::tell_object( TO, fit_message( message ) );

} /* show_message() */

/** @ignore yes */
protected void clear_had_shorts() { _had_shorts = ({ }); }

/**
 * This is the main evaluation routine.  This is the one that
 * co-ordinates the works...  It is used by the print_messages
 * routine to create the message to print out.
 * <p>
 * The input parameter contains two elements, the first is the
 * message and the second is the things array.  This corresponds to
 * the values returned by the fix_message method.
 * @param stuff the message to evaulate
 * @return the nice printed out string
 * @see print_messages()
 */
string evaluate_message( mixed stuff ) {
    int i;
    string message, start, finish, verb_sing, verb_plur;

    message = stuff[0];
    clear_had_shorts();

    for( i = 0; i < sizeof( stuff[1] ); i++ ) {
        // Things assume this ordering, so do not change.
        message = replace_string( message, "$"+i+"$",
            calc_shorts( stuff[1][i] ) );
        while( sscanf( message, "%s$V$"+ i +"=%s,%s$V$%s", start, verb_sing,
            verb_plur, finish ) == 4 ) {
            if( sizeof( stuff[1][i] ) == 1 && sizeof(_had_shorts) &&
                objectp( _had_shorts[0] ) ) {
                if( _had_shorts[0]->query_property("group object") ||
                    _had_shorts[0]->group_object() ) {
                    message = start+verb_plur+finish;
                } else {
                    message = start+verb_sing+finish;
                }
            } else {
                message = start+verb_plur+finish;
            }
        }
    }

    return message;

} /* evaluate_message() */

/**
 * This prints out the messages after the delay, printing out the
 * messages in a nice cute way.  It still retains the order of the
 * messages though.  This can be forced to occur by a message
 * occuring on the player object which requires something to
 * be printed.
 * @see evaluate_message()
 * @see show_message()
 */
void print_messages() {
    int i;
    string message;
    mixed messages;

    remove_call_out( "print_messages" );
    messages = _eemessages;
    _eemessages = ({ });

    for( i = 0; i < sizeof( messages ); i += 2 ) {
        message = messages[ i ];
        if( sizeof( messages[ i + 1 ] ) )
            message = evaluate_message( ({ message, messages[ i + 1 ] }) );
        show_message( message );
    }

    _where = 0;

} /* print_messages() */

/**
 * This method will handle doing exciting things to messages and
 * returning them as a usable format.
 * @param message the message to evaluate
 * @return the message in a printable (to the player) format
 * @see evaluate_message()
 */
string convert_message( string message ) {
    message = evaluate_message( reform_message( message, ({ }) ) );
    _where = 0;
    return message;
} /* convert_message() */

/**
 * This method is called when an inform event is called.
 * @param mess the message to print
 * @param which the type of inform
 * @parm thing the thing associated with the inform
 */
varargs void event_inform( object, mixed mess, string which, object thing ) {
    string *on, inform_col;
    int is_friend;

    on = inform_types || ({ });

    if( TO->query_property("inform repressed") || !sizeof( on ) )
        return;

    if( thing && creatorp(thing) && !thing->query_visible( TO ) )
        return;

    if( member_array( which, on ) == -1 )
        return;

    if( thing && member_array("friend", on ) != -1 &&
        TO->query_friend( thing->query_name() ) )
        is_friend = 1;

    if( which == "friend" && !is_friend )
        return;

    if( which == "logon" && is_friend )
        which = "friend";

    if( _inform_colours[which] )
        inform_col = colour_event( which, _inform_colours[which] );
    else
        inform_col = colour_event( which, _inform_colours["default"] );

    if( functionp(mess) )
        mess = evaluate( mess, TO );

    TO->add_message( "[%^"+ inform_col +"%^"+mess+"%^RESET%^]\n", ({ }) );

} /* event_inform() */

/**
 * This method is called when an object leaves or arrives in
 * the room.  It prints out
 * the message, well adds it to the queue of printable messages.
 * @param mess the message to print
 * @param thing the thing which is leaving/arriving
 * @param going if it is going
 */
protected void enter_exit_mess( string mess, object thing, int going ) {
    int i;
    string part, verb, *words;

    mess = replace_string( mess, "$N", "$0$" );
    words = explode( mess, " " );
    for ( i = sizeof( words ) - 1; i > -1; i-- ) {
        /*
         * If $s ends a word, it represents verb conjugation.
         * The test of the following letter is to check that it does end the word.
         */
        if ( ( sscanf( words[ i ], "%s$s%s", verb, part ) == 2 ) &&
          ( ( part[ 0 ] < 97 ) || ( part[ 0 ] > 122 ) ) ) {
            words[ i ] = "$V$0="+ pluralize( verb ) +","+ verb +"$V$"+ part;
        }
        /*
         * If we have %<verb>%, it represents verb conjugation.
         * This is unlikely to get confused with anything else...
         */
        if ( sscanf( words[ i ], "%%%s%%%s", verb, part ) == 3 ) {
            words[ i ] = "$V$0="+ pluralize( verb ) +","+ verb +"$V$"+ part;
        }
    }
    if( going ) {
        TO->add_message( implode( words, " " ) +"\n",
          ({ ({ "my_the_short:"+ file_name( thing ) }) }) );
    } else {
        TO->add_message( implode( words, " " ) +"\n",
          ({ ({ "my_a_short:"+ file_name( thing ) }) }) );
    }
} /* enter_exit_mess() */

/**
 * This method is called when an object enters the room.
 * @param thing the thing entering
 * @param mess the message to print on entering
 */
void event_enter( object thing, string mess, object ) {
    if( !stringp( mess ) )
        return;

    thing->sneak_task(TO);
    TO->perception_task(thing);

    if( !thing->query_visible( TO ) )
        return;

    enter_exit_mess( mess, thing, 0 );

} /* event_enter() */

/**
 * This method is printed when an object exits the room.
 * @param thing the object exiting
 * @param mess the message to print
 * @param to where the object is going to
 */
void event_exit( object thing, string mess, object to ) {
    ::event_exit( thing, mess, to );
    if( !stringp( mess ) )
        return;
    if( !thing->query_visible( TO ) )
        return;
    enter_exit_mess( mess, thing, 1 );
} /* event_exit() */

/** @ignore yes */
void event_death( object thing, object *, object killer,
                  string room_mess, string killer_mess ) {
    if( TO == thing )
        return;

    if( TO == killer && stringp( killer_mess ) ) {
        TO->add_message( replace( killer_mess,
            "$D",(string)thing->the_short() ), ({ }) );
        print_messages();
        return;
    }

    if( stringp( room_mess ) ) {
        if( objectp( killer ) ) {
            TO->add_message( replace( room_mess, ({
                "$D", (string)thing->the_short(),
                "$K", (string)killer->the_short() }) ), ({ }) );
        } else {
            TO->add_message( replace( room_mess, "$D",
                (string)thing->the_short() ), ({ }) );
        }
        print_messages();
    }
} /* event_death() */

/**
 * This method is called when the 'say' and 'tell_room' simul_efuns is used.
 * @param caller the object doing the say
 * @param str the message to print
 * @param avoid the people to avoid in the say
 */
void event_say(object caller, string str, mixed avoid) {
    if( pointerp(avoid) ) {
        if( member_array( TO, avoid ) != -1 )
            return;
    } else if( avoid == TO )
        return;

    if( !silenced(caller) )
        TO->add_message( str, ({ }) );

} /* event_say() */

void event_see( object caller, string words, object thing, mixed avoid ) {
    if( !thing->query_visible( TO ) )
        return;
    event_say( caller, words, avoid );
} /* event_see() */

/**
 * This method is called by the simul_efun 'write'.
 * @param caller the calling object
 * @param str the string to write
 */
void event_write( object caller, string str ) {
    TO->add_message( str, ({ }) );
    print_messages();
} /* event_write() */

/** @ignore yes */
void do_efun_write( string str ) { event_write( 0, str ); }

/**
 * This method is called by the soul to print out the soul messages.
 * @param ob the object doing the soul
 * @param str the string to print
 * @param avoid the people not to print the message to
 */
varargs void event_soul( object ob, string str, mixed avoid ) {
    int id;

    TO->add_property("doing_soul", 1 );

    if( ob != TO ) {
        if( silenced(ob) || ( sizeof(avoid) > 1 &&
            check_earmuffs("multiple-soul") ) )
            return ;

        if( !ob->query_visible(TO) )
            tell_object( ob, "Warning! "+TO->query_cap_name()+" cannot see "
                "you and will not be able to respond.\n");

        if( TO->query_property("afk") )
            tell_object( ob, TO->query_cap_name()+" is currently %^ORANGE%^"
                "AFK%^RESET%^"+( !TO->query_property("afk_string") ? "!" : " "
                "because : "+TO->query_property("afk_string") )+"\n");

        if( interactive(TO) && ( id = query_idle(TO) ) > TELL_WARN_TIME )
            tell_object( ob, TO->query_cap_name()+" has been idle for "+
                time_string(id)+".\n");

        event_say( ob, colour_event("soul", "")+"$C$"+str+"%^RESET%^",
                   avoid );
    } else
        event_write( ob, str+"%^RESET%^");

    TO->remove_property("doing_soul");

} /* event_soul() */

/**
 * This method is called when someone does an emote.
 * @param thing the object doing the emote
 * @param mess the emote to print
 */
void event_emote( object thing, string mess ) {
    if( thing == TO || silenced(thing) )
        return;
    TO->add_message( colour_event("emote", "%^CYAN%^")+mess+"%^RESET%^",
        ({ }) );
} /* event_emote() */

/**
 * @ignore yes
 * Use this on pain of death :)
 */
void add_say_history(string start, string mess) {
    if( !pointerp(say_history) )
        say_history = ({ });
    say_history +=  ({ ({ CAP(start), mess, time() }) });
    if( sizeof(say_history) > MAX_TELL_HIS )
        say_history = say_history[1..];
} /* add_say_history() */

/**
 * This method is called when someone says something.
 * @param ob the object doing the say
 * @param start the start message
 * @param mess the message to say
 * @param lang the language it is printed in
 */
void event_person_say( object ob, string start, string mess, string lang ) {
    string *args;

    if( ob == TO || silenced(ob) )
        return;

    if( lang != "common" )
        start = start[0..<3] + " in " + CAP(lang) + ": ";

    args = LANGUAGE_H->garble_say( lang, start, mess, TO, ob, SAY_TYPE );
    start = args[ 0 ];
    mess = args[ 1 ];

    add_say_history( TO->convert_message(start), TO->convert_message(mess) );

    TO->add_message("$I$5="+colour_event("say", "%^CYAN%^")+"$C$"+start+
        mess+"%^RESET%^\n", ({ }) );

} /* event_person_say() */

/**
 * @ignore yes
 * Use this on pain of death :)
 */
void add_tell_history(string start, string mess) {
    if( !pointerp(tell_history) )
        tell_history = ({ });
    tell_history +=  ({ ({ start, mess, time() }) });
    if( sizeof(tell_history) > MAX_TELL_HIS )
        tell_history = tell_history[1..];
} /* add_tell_history() */

/**
 * This method is called when a person is told something.
 * @param ob the object doing the tell
 * @param start the start bit of the message
 * @param mess the message itself
 */
void event_person_tell( object ob, string start, string mess ) {
    string *args;
    int id;

    if( silenced(ob) )
        return;

    if( ( args = TO->query_property("ignoring") ) &&
        member_array( ob->query_name(), args ) != -1 && !creatorp(ob) ) {
        tell_object( ob, TO->query_cap_name()+" is ignoring you and "
            "will not have heard what you said.\n");
        return;
    }

    if( TO->query_property("afk") )
        tell_object( ob, TO->query_cap_name()+" is currently %^ORANGE%^"
            "AFK%^RESET%^"+( !TO->query_property("afk_string") ? "!" : " "
            "because : "+TO->query_property("afk_string") )+"\n");

    start = convert_message(start);

    if( _busy && ( !pointerp(_busy) || member_array( ob, _busy ) == -1 ) ) {
        tell_object( ob, TO->query_cap_name()+" is currently busy with "
            "someone else, "+TO->HE+" has heard this message and will get "
            "back to you shortly.\n");
        start = "[BUSY] "+start;
    }

    add_tell_history( start, mess );

    efun::tell_object( TO, fix_string( replace( colour_event("tell",
        "%^YELLOW%^"), "%^", "%%^")+"%s%s%%^RESET%%^\n", cols, 5, CAP(start),
        SPEECH_BASE->mangle_tell( mess, ob ) ) );

    if( interactive(TO) && ( id = query_idle(TO) ) > TELL_WARN_TIME )
        write( TO->query_cap_name()+" has been idle for "+
               time_string(id)+".\n");

    if( TO->query_property( PASSED_OUT ) )
        write("Something tells you that "+TO->query_cap_name()+" will be "
            "unable to reply to you just yet.\n" );

} /* event_person_tell() */

/**
 * This method is called when the whisper even is generated.
 * @param ob the object whispering
 * @param start the start of the whisper message
 * @param mess the message to print
 * @param obs the objects to tell the message to
 * @param lang the lanaguage the whisper is in
 * @param me the object doing the whispering
 */
void event_whisper( object ob, string start, string mess,
                    object *obs, string lang, object me ) {
    string blue, *args;

    blue = "";
    if( me == TO || silenced(ob) )
        return;

    if( lang != "common")
        blue = " in "+lang;

    args = LANGUAGE_H->garble_say( lang, start, mess, TO, ob, WHISPER_TYPE );
    start = args[0];
    mess = args[1];

    if( member_array( TO, obs ) == -1 ) {
        TO->add_message("$I$5="+colour_event("whisper", "%^CYAN%^")+"$C$"+
            start+"to "+query_multiple_short( obs )+".%^RESET%^\n", ({ }) );
        return;
    }

    if( sizeof( obs ) == 1 ) {
        TO->add_message("$I$5="+colour_event("whisper", "%^CYAN%^")+"$C$"+
            start+"to you"+blue+": "+mess+"%^RESET%^\n", ({ }) );
        return;
    }

    TO->add_message("$I$5="+colour_event("whisper", "%^CYAN%^")+"$C$"+
        start+"to "+query_multiple_short( obs )+blue+": "+mess+
        "%^RESET%^\n", ({ }) );

} /* event_whisper() */

/**
 * This method is generated when a shout is done by a player.
 * @param thing the thing doing the shout
 * @param start the start string to print
 * @param mess the message to print
 * @param lang the language the shout is in
 * @param co_ord the co-ordinate of the shouter
 * @param range the range of the shout
 */
void event_person_shout( object thing, string start, string mess, string lang,
                         int *co_ord, int range ) {
    mixed args;

    if( TO == TP || silenced(thing) || check_earmuffs("shout") || !ENV(TO) ||
        ENV(TO)->query_property("shout zone") !=
        ENV(TP)->query_property("shout zone") ||
        sizeof( query_ignoring( ({ TP }) ) ) )
        return;

    if( lang != "common" )
        start += " in "+lang;

    args = LANGUAGE_H->garble_say( lang, start, mess, TO, thing, SHOUT_TYPE );
    start = args[0];
    mess = args[1];

    if( ENV(TO) == ENV(TP) ) {
        TO->add_message("$I$5="+colour_event("shout", "")+"$C$"+
            start+": "+mess+"%^RESET%^\n", ({ }) );
        return;
    }

    if( sizeof( co_ord ) != 3 )
        return;

    BROADCASTER->broadcast_event( ({ TO }), co_ord, start+": "+mess,
        range, 1, 0 );

} /* event_person_shout() */

/**
* This event is generated when a newbie chat event is done.
* @param thing the thing generateing the newbie chat
* @param message the message the newbie said
*/
void event_newbie( object thing, string message ) {
    if( TP == TO || check_earmuffs("newbie") ||
        sizeof( query_ignoring( ({ TP }) ) ) )
        return;

    efun::tell_object( TO, fix_string("%%^MAGENTA%%^(newbie)%%^RESET%%^ %s\n",
                       cols, 5, message ) );

} /* event_newbie() */

/**
 * This event is generated when a creator tell is done.
 * @param ob the object generating the event
 * @param start the start bit
 * @param mess the message bit
 * @param forced if it is forced to occur
 */
void event_creator_tell( object ob, string start, string mess, int forced ) {
    if( TP == TO || ob == TO || ( ( sizeof(TO->query_ignoring( ({ ob }) ) ) ||
        check_earmuffs("cre")) && !forced ) || !creatorp(TO) )
        return;

    efun::tell_object( TO, fix_string(replace(
        colour_event("cre", "%^CYAN%^"), "%^", "%%^")+
        "(cre) %s%s%%^RESET%%^\n", cols, 5, start, mess ) );

} /* event_creator_tell() */

/**
 * This event is generated when a creator tell is done.
 * @param ob the object generating the event
 * @param start the start bit
 * @param mess the message bit
 * @param forced if it is forced to occur
 */

void event_chat( object ob, string caller, string verb, string text,
                 int emote, int force ) {
    string hdr;
    object person;

    person = find_player( lower_case(caller) );

    hdr = ( emote ? "("+verb+") "+caller+" " :
      "("+( force ? "forced-" : "")+verb+") "+caller+": ");

    if( !force ) {
        if( TO->check_earmuffs("chat-channels") ||
            TO->query_property("allchat_off") ||
            TO->query_property(verb +"_off") )
            return;
        if( person )
            if( sizeof( TO->query_ignoring( ({ person }) ) ) )
                return;
    }

    efun::tell_object( ob, fix_string( replace( colour_event(
        verb, "%^CYAN%^"), "%^", "%%^")+"%s%s%%^RESET%%^\n",
        cols, strlen(verb)+2, hdr, text ) );

} /* event_chat() */

/**
 * This event is generated when a intermud creator tell is done.
 * @param ob the object generating the event
 * @param mname the name of the mud
 * @param pname the name of the player
 * @param mess the message
 * @param ig the ignore object
 * @param emote if it is an emote
 */
void event_inter_creator_tell( object ob, string mname, string pname,
                               string mess, object ig, int emote ) {

    if( !creatorp(TO) || check_earmuffs("inter-creator-tell") || TO == ig )
        return;

    efun::tell_object( TO, fix_string("%s@%s%s%s\n", cols,
        strlen(mname) + strlen(pname) + 3, pname, mname, ( emote ? " ": ": "),
        mess ) );

} /* event_inter_creator_tell() */

/**
 * This event is generated when a creator tell is done.
 * @param ob the object generating the event
 * @param mname the name of the mud
 * @param pname the name of the player
 * @param mess the message
 * @param ig the ignore object
 * @param emote if it is an emote
 */
void event_intermud_tell( object ob, string start, string mess, string channel,
                          object ig, int emote ) {

    if( TO->check_earmuffs("chat-channels") ||
        TO->query_property("allchat_off") ||
        TO->query_property(channel +"_off") )
        return;

    if( emote )
        efun::tell_object( TO, fix_string( replace( colour_event(
            channel, "%^CYAN%^"), "%^", "%%^")+"(%s): %s%s%%^RESET%%^\n",
            cols, strlen(start)+strlen(channel)+3, channel, start, mess ) );
    else
        efun::tell_object( TO, fix_string( replace( colour_event(
            channel, "%^CYAN%^"), "%^", "%%^")+"%s (%s): %s%%^RESET%%^\n",
            cols, strlen(start)+strlen(channel)+3, start, channel, mess ) );

} /* event_intermud_tell() */

/**
 * This method is called when an echo to is generated by the player.
 * @param ob the object doing the echo to
 * @param mess the message being printed
 * @param me the person generating the echo to
 */
void event_player_echo_to(object ob, string mess, object me) {
    if( lordp( (string)TO->query_name() ) )
        TO->add_message("$0$ echos to you:\n",
            ({ ({ "my_the_short:"+file_name( me ) }) }) );

    TO->add_message( colour_event("echo", "")+mess+"%^RESET%^", ({ }) );

} /* event_player_echo_to() */

/**
 * This method is called when an emoteall is generated by a player.
 * @param ob the object doing the emoteall
 * @param mess the message being printed
 */
void event_player_emote_all( object ob, string mess ) {
    if( ob == TO )
        return;

    if( lordp( (string)TO->query_name() ) )
        TO->add_message("$0$ emotes to all:\n",
            ({ ({ "my_the_short:"+file_name( ob ) }) }) );

    TO->add_message("$I$5=$C$"+replace_string( mess, "$N", "$0$"),
        ({ ({ "my_the_short:"+ file_name( ob ) }) }) );

} /* event_player_emote_all() */

/**
 * This method is called when an echo is generated by a player.
 * @param ob the object doing the echo
 * @param mess the message being printed
 */
void event_player_echo( object ob, string mess ) {
    if( ob == TO )
        return;

    if( lordp( (string)TO->query_name() ) )
        TO->add_message("$0$ echos:\n",
            ({ ({ "my_the_short:"+file_name( ob ) }) }) );

    TO->add_message( mess, ({ }) );

} /* event_player_echo() */

/**
 * This method is generated internally by the driver when this player is
 * snooping someone else.
 * @param mess the snoop message
 */
void receive_snoop( string mess ) {
    tell_object( TO, "] "+mess );
} /* receive_snoop() */

/**
 * This is a call back generated by the driver internally to tell us about
 * terminal types.
 * @param type the terminal type returned
 */
void terminal_type( string type ) {
    if( set_network_terminal_type(type) ) {
        tell_object( TO, "Setting your network terminal type to "
            "\""+type+"\".\n");
    } else {
        if( term_name == "network") {
            if( !_last_term || _last_term != type ) {
                _last_term = type;
                // Keep going until they repeat twice.
                // This is the end of the list.
                printf("%c%c%c%c%c%c", IAC, SB, TELOPT_TTYPE,
                    TELQUAL_SEND, IAC, SE );
            } else
                tell_object( TO, "Unknown terminal type \""+type+"\".\n");
        }
    }
} /* terminal_type() */

/**
 * This is a call back generated by the driver internally to tell us about
 * the window size of the remote machine.  This information in this is
 * only used if the terminal is a network type.
 * @param width the number of columns
 * @param height the number of rows
 */
void window_size( int width, int height ) {
    if( term_name == "network" ) {
        if( width > 10 && width < 256 )
            set_cols(width);
        if( height > 5 && height < 256 )
            set_rows(height);
        tell_object( TO, "Your machine told our machine that your "
            "terminal has "+height+" rows and "+width+" columns.\n");
    }
} /* window_size() */