skylib_mudos_v1/
skylib_mudos_v1/bin/
skylib_mudos_v1/bin/db/
skylib_mudos_v1/mudlib/banish/a/
skylib_mudos_v1/mudlib/banish/b/
skylib_mudos_v1/mudlib/banish/c/
skylib_mudos_v1/mudlib/banish/d/
skylib_mudos_v1/mudlib/banish/e/
skylib_mudos_v1/mudlib/banish/f/
skylib_mudos_v1/mudlib/banish/g/
skylib_mudos_v1/mudlib/banish/h/
skylib_mudos_v1/mudlib/banish/j/
skylib_mudos_v1/mudlib/banish/l/
skylib_mudos_v1/mudlib/banish/m/
skylib_mudos_v1/mudlib/banish/n/
skylib_mudos_v1/mudlib/banish/o/
skylib_mudos_v1/mudlib/banish/p/
skylib_mudos_v1/mudlib/banish/r/
skylib_mudos_v1/mudlib/banish/s/
skylib_mudos_v1/mudlib/banish/t/
skylib_mudos_v1/mudlib/banish/u/
skylib_mudos_v1/mudlib/banish/w/
skylib_mudos_v1/mudlib/cmds/
skylib_mudos_v1/mudlib/cmds/admin/
skylib_mudos_v1/mudlib/cmds/guild-race/
skylib_mudos_v1/mudlib/cmds/guild-race/crafts/
skylib_mudos_v1/mudlib/cmds/guild-race/magic/
skylib_mudos_v1/mudlib/cmds/guild-race/other/
skylib_mudos_v1/mudlib/cmds/living/broken/
skylib_mudos_v1/mudlib/cmds/player/group_cmds/
skylib_mudos_v1/mudlib/d/admin/
skylib_mudos_v1/mudlib/d/admin/room/
skylib_mudos_v1/mudlib/d/admin/room/we_care/
skylib_mudos_v1/mudlib/d/admin/save/
skylib_mudos_v1/mudlib/d/admin/text/
skylib_mudos_v1/mudlib/d/learning/TinyTown/buildings/
skylib_mudos_v1/mudlib/d/learning/TinyTown/map/
skylib_mudos_v1/mudlib/d/learning/TinyTown/roads/
skylib_mudos_v1/mudlib/d/learning/chars/
skylib_mudos_v1/mudlib/d/learning/functions/
skylib_mudos_v1/mudlib/d/learning/handlers/
skylib_mudos_v1/mudlib/d/learning/help_topics/
skylib_mudos_v1/mudlib/d/learning/help_topics/npcs/
skylib_mudos_v1/mudlib/d/learning/help_topics/objects/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/crowd/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/situations/
skylib_mudos_v1/mudlib/d/learning/save/
skylib_mudos_v1/mudlib/d/learning/school/
skylib_mudos_v1/mudlib/d/learning/school/add_sc/
skylib_mudos_v1/mudlib/d/learning/school/characters/
skylib_mudos_v1/mudlib/d/learning/school/general/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/basic_commands/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/edtutor/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_mudos_v1/mudlib/d/learning/school/items/
skylib_mudos_v1/mudlib/d/learning/school/npc_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/room_basic/
skylib_mudos_v1/mudlib/d/learning/school/room_school/situations/
skylib_mudos_v1/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_mudos_v1/mudlib/d/learning/text/
skylib_mudos_v1/mudlib/d/liaison/
skylib_mudos_v1/mudlib/d/mudlib/
skylib_mudos_v1/mudlib/d/mudlib/changes/
skylib_mudos_v1/mudlib/d/playtesters/
skylib_mudos_v1/mudlib/d/playtesters/effects/
skylib_mudos_v1/mudlib/d/playtesters/handlers/
skylib_mudos_v1/mudlib/d/playtesters/items/
skylib_mudos_v1/mudlib/d/sage/
skylib_mudos_v1/mudlib/doc/
skylib_mudos_v1/mudlib/doc/creator/
skylib_mudos_v1/mudlib/doc/driver/
skylib_mudos_v1/mudlib/doc/driver/efuns/arrays/
skylib_mudos_v1/mudlib/doc/driver/efuns/buffers/
skylib_mudos_v1/mudlib/doc/driver/efuns/compile/
skylib_mudos_v1/mudlib/doc/driver/efuns/filesystem/
skylib_mudos_v1/mudlib/doc/driver/efuns/floats/
skylib_mudos_v1/mudlib/doc/driver/efuns/functions/
skylib_mudos_v1/mudlib/doc/driver/efuns/general/
skylib_mudos_v1/mudlib/doc/driver/efuns/mappings/
skylib_mudos_v1/mudlib/doc/driver/efuns/mixed/
skylib_mudos_v1/mudlib/doc/driver/efuns/mudlib/
skylib_mudos_v1/mudlib/doc/driver/efuns/numbers/
skylib_mudos_v1/mudlib/doc/driver/efuns/parsing/
skylib_mudos_v1/mudlib/doc/known_command/
skylib_mudos_v1/mudlib/doc/login/
skylib_mudos_v1/mudlib/doc/lpc/basic_manual/
skylib_mudos_v1/mudlib/doc/lpc/intermediate/
skylib_mudos_v1/mudlib/doc/new/add_command/
skylib_mudos_v1/mudlib/doc/new/events/
skylib_mudos_v1/mudlib/doc/new/handlers/
skylib_mudos_v1/mudlib/doc/new/living/race/
skylib_mudos_v1/mudlib/doc/new/living/spells/
skylib_mudos_v1/mudlib/doc/new/object/
skylib_mudos_v1/mudlib/doc/new/player/
skylib_mudos_v1/mudlib/doc/new/room/guild/
skylib_mudos_v1/mudlib/doc/new/room/outside/
skylib_mudos_v1/mudlib/doc/new/room/storeroom/
skylib_mudos_v1/mudlib/doc/object/
skylib_mudos_v1/mudlib/doc/playtesters/
skylib_mudos_v1/mudlib/doc/policy/
skylib_mudos_v1/mudlib/doc/weapons/
skylib_mudos_v1/mudlib/global/
skylib_mudos_v1/mudlib/global/creator/
skylib_mudos_v1/mudlib/global/handlers/
skylib_mudos_v1/mudlib/global/virtual/setup_compiler/
skylib_mudos_v1/mudlib/include/cmds/
skylib_mudos_v1/mudlib/include/effects/
skylib_mudos_v1/mudlib/include/npc/
skylib_mudos_v1/mudlib/include/room/
skylib_mudos_v1/mudlib/include/shops/
skylib_mudos_v1/mudlib/net/daemon/
skylib_mudos_v1/mudlib/net/daemon/chars/
skylib_mudos_v1/mudlib/net/inherit/
skylib_mudos_v1/mudlib/net/obj/
skylib_mudos_v1/mudlib/obj/amulets/
skylib_mudos_v1/mudlib/obj/b_day/
skylib_mudos_v1/mudlib/obj/clothes/
skylib_mudos_v1/mudlib/obj/dwarmours/plate/
skylib_mudos_v1/mudlib/obj/dwclothes/transport/horse/
skylib_mudos_v1/mudlib/obj/dwscabbards/
skylib_mudos_v1/mudlib/obj/dwweapons/axes/
skylib_mudos_v1/mudlib/obj/dwweapons/chains/
skylib_mudos_v1/mudlib/obj/faith/symbols/
skylib_mudos_v1/mudlib/obj/fungi/
skylib_mudos_v1/mudlib/obj/gatherables/
skylib_mudos_v1/mudlib/obj/instruments/
skylib_mudos_v1/mudlib/obj/magic/
skylib_mudos_v1/mudlib/obj/media/
skylib_mudos_v1/mudlib/obj/misc/player_shop/
skylib_mudos_v1/mudlib/obj/monster/godmother/
skylib_mudos_v1/mudlib/obj/monster/transport/
skylib_mudos_v1/mudlib/obj/rings/
skylib_mudos_v1/mudlib/obj/spells/
skylib_mudos_v1/mudlib/obj/stationery/
skylib_mudos_v1/mudlib/obj/stationery/envelopes/
skylib_mudos_v1/mudlib/obj/stationery/papers/
skylib_mudos_v1/mudlib/obj/toys/
skylib_mudos_v1/mudlib/obj/vessels/
skylib_mudos_v1/mudlib/obj/weapons/swords/
skylib_mudos_v1/mudlib/save/autodoc/
skylib_mudos_v1/mudlib/save/leaflets/
skylib_mudos_v1/mudlib/save/mail/
skylib_mudos_v1/mudlib/save/new_soul/data/
skylib_mudos_v1/mudlib/save/parcels/
skylib_mudos_v1/mudlib/save/playerinfo/
skylib_mudos_v1/mudlib/save/players/d/
skylib_mudos_v1/mudlib/save/random_names/
skylib_mudos_v1/mudlib/save/random_names/data/
skylib_mudos_v1/mudlib/save/terrains/
skylib_mudos_v1/mudlib/save/terrains/tutorial_desert/
skylib_mudos_v1/mudlib/save/terrains/tutorial_grassy_field/
skylib_mudos_v1/mudlib/save/terrains/tutorial_mountain/
skylib_mudos_v1/mudlib/save/todo_lists/
skylib_mudos_v1/mudlib/secure/
skylib_mudos_v1/mudlib/secure/cmds/admin/
skylib_mudos_v1/mudlib/secure/cmds/lord/
skylib_mudos_v1/mudlib/secure/config/
skylib_mudos_v1/mudlib/secure/handlers/autodoc/
skylib_mudos_v1/mudlib/secure/handlers/intermud/
skylib_mudos_v1/mudlib/secure/include/global/
skylib_mudos_v1/mudlib/secure/save/
skylib_mudos_v1/mudlib/secure/save/handlers/
skylib_mudos_v1/mudlib/secure/std/classes/
skylib_mudos_v1/mudlib/secure/std/modules/
skylib_mudos_v1/mudlib/std/commands/
skylib_mudos_v1/mudlib/std/commands/shadows/
skylib_mudos_v1/mudlib/std/creator/
skylib_mudos_v1/mudlib/std/dom/
skylib_mudos_v1/mudlib/std/effects/
skylib_mudos_v1/mudlib/std/effects/external/
skylib_mudos_v1/mudlib/std/effects/fighting/
skylib_mudos_v1/mudlib/std/effects/priest/
skylib_mudos_v1/mudlib/std/effects/room/
skylib_mudos_v1/mudlib/std/environ/
skylib_mudos_v1/mudlib/std/guilds/
skylib_mudos_v1/mudlib/std/guilds/old/
skylib_mudos_v1/mudlib/std/languages/
skylib_mudos_v1/mudlib/std/languages/BACKUPS/
skylib_mudos_v1/mudlib/std/liquids/
skylib_mudos_v1/mudlib/std/npc/
skylib_mudos_v1/mudlib/std/npc/goals/
skylib_mudos_v1/mudlib/std/npc/goals/basic/
skylib_mudos_v1/mudlib/std/npc/goals/misc/
skylib_mudos_v1/mudlib/std/npc/plans/
skylib_mudos_v1/mudlib/std/npc/plans/basic/
skylib_mudos_v1/mudlib/std/npc/types/
skylib_mudos_v1/mudlib/std/npc/types/helper/
skylib_mudos_v1/mudlib/std/npcs/
skylib_mudos_v1/mudlib/std/outsides/
skylib_mudos_v1/mudlib/std/races/shadows/
skylib_mudos_v1/mudlib/std/room/basic/topography/
skylib_mudos_v1/mudlib/std/room/controller/
skylib_mudos_v1/mudlib/std/room/inherit/topography/
skylib_mudos_v1/mudlib/std/room/topography/area/
skylib_mudos_v1/mudlib/std/room/topography/iroom/
skylib_mudos_v1/mudlib/std/room/topography/milestone/
skylib_mudos_v1/mudlib/std/shadows/curses/
skylib_mudos_v1/mudlib/std/shadows/disease/
skylib_mudos_v1/mudlib/std/shadows/fighting/
skylib_mudos_v1/mudlib/std/shadows/healing/
skylib_mudos_v1/mudlib/std/shadows/magic/
skylib_mudos_v1/mudlib/std/shadows/poison/
skylib_mudos_v1/mudlib/std/shadows/rituals/
skylib_mudos_v1/mudlib/std/shadows/room/
skylib_mudos_v1/mudlib/std/shops/controllers/
skylib_mudos_v1/mudlib/std/shops/objs/
skylib_mudos_v1/mudlib/std/shops/player_shop/
skylib_mudos_v1/mudlib/std/socket/
skylib_mudos_v1/mudlib/std/soul/
skylib_mudos_v1/mudlib/std/soul/d/
skylib_mudos_v1/mudlib/std/soul/e/
skylib_mudos_v1/mudlib/std/soul/i/
skylib_mudos_v1/mudlib/std/soul/j/
skylib_mudos_v1/mudlib/std/soul/k/
skylib_mudos_v1/mudlib/std/soul/l/
skylib_mudos_v1/mudlib/std/soul/n/
skylib_mudos_v1/mudlib/std/soul/o/
skylib_mudos_v1/mudlib/std/soul/q/
skylib_mudos_v1/mudlib/std/soul/u/
skylib_mudos_v1/mudlib/std/soul/v/
skylib_mudos_v1/mudlib/std/soul/y/
skylib_mudos_v1/mudlib/std/soul/z/
skylib_mudos_v1/mudlib/std/stationery/
skylib_mudos_v1/mudlib/w/
skylib_mudos_v1/mudlib/w/default/
skylib_mudos_v1/mudlib/w/default/armour/
skylib_mudos_v1/mudlib/w/default/clothes/
skylib_mudos_v1/mudlib/w/default/item/
skylib_mudos_v1/mudlib/w/default/npc/
skylib_mudos_v1/mudlib/w/default/room/
skylib_mudos_v1/mudlib/w/default/weapon/
skylib_mudos_v1/mudlib/www/
skylib_mudos_v1/mudlib/www/download/
skylib_mudos_v1/mudlib/www/java/
skylib_mudos_v1/mudlib/www/secure/
skylib_mudos_v1/mudlib/www/secure/lpc/advanced/
skylib_mudos_v1/mudlib/www/secure/lpc/intermediate/
skylib_mudos_v1/v22.2b14-DSv10/
skylib_mudos_v1/v22.2b14-DSv10/ChangeLog.old/
skylib_mudos_v1/v22.2b14-DSv10/Win32/
skylib_mudos_v1/v22.2b14-DSv10/compat/
skylib_mudos_v1/v22.2b14-DSv10/compat/simuls/
skylib_mudos_v1/v22.2b14-DSv10/include/
skylib_mudos_v1/v22.2b14-DSv10/mudlib/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/clone/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/command/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/data/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/etc/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/include/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/master/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/log/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/compiler/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/efuns/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/operators/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/u/
skylib_mudos_v1/v22.2b14-DSv10/tmp/
skylib_mudos_v1/v22.2b14-DSv10/windows/
/**
 * This file contains the methods to make the npcs in game respond
 * to soul and says.  Allows for a level of NPC interation.
 * <p>
 * Code originaly by nimmox@igor.  Modified for discworld by Pinkfish.
 * <p>
 * @change Olorin Sep 97
 * event_soul does a convert_message on the mess first,
 * to avoid spurious matches caused by a message like eg.
 * "$the_short:/global/lord#64387$ $V$0=smiles,smile$V$ .... in soul
 * @change who knows when
 * changed to stop the responses when the npc is in /room/rubbish
 * @author Pinkfish
 * @see /std/npc.c
 */

#include <soul.h>
#include <language.h>

#define SPECIAL_DAY "/handlers/special_day"

mixed respond_to_with;
int stop_responding;
int use_regexp;

int match( string str, mixed str2 );
void event_soul( object per, string mess, object *avoid, string verb,
                 string last, mixed at );

void create() {
} /* create() */

/**
 * This method sets or clears the flag to use regular expressions instead of
 * the traditional arrays of words.  In addition, this flag inhibits
 * the usual stripping of non-alphanumerics from the input strings.
 * @param flag the new value of the flag: 1 says to use regular expressions,
 * 0 to not use them
 */
void set_response_mon_regexp( int flag ) { use_regexp = flag; }

/**
 * This method returns the current state of the flag that indicates whether
 * to use regular expressions instead of the traditional array of words.
 * @return 1 if using regular expressions, 0 if not
 */
int query_response_mon_regexp() { return use_regexp; }

/**
 * This method checks to see if the response monster code is in
 * debug mode.
 * @return 1 if in debug mode, 0 if not
 * @see set_response_mon_debug_mode()
 */
int query_response_mon_debug_mode() {
    return TO->query_property("respon mon debug");
} /* query_response_mon_debug_mode() */

/**
 * This method sets the current debug flag for the response monster
 * code.
 * @param flag the new value of the flag, 1 on, 0 off
 * @see query_response_mon_debug_mode()
 */
void set_response_mon_debug_mode( int flag ) {
   TO->add_property("respon mon debug", flag );
} /* set_response_mon_debug_mode() */

/**
 * This method allows the toggling of the responses of the npc.
 * If this is set to 1, then the npc will stop responding to
 * messages.
 * @param i 1 to make the npc not respond, 0 to make it respond again
 * @see query_stop_responding()
 */
void set_stop_responding( int i ) { stop_responding = i; }
/**
 * This method returns the flag determining the toggling of the
 * responses of the npc.
 * If this is set to 1, then the npc will stop responding to
 * messages.
 * @return 1 to the npc will not respond, 0 it is responding
 * @see query_stop_responding()
 */
int query_stop_responding() { return stop_responding; }

/**
 * This method sets whether or not we should respond to
 * non-interactives (ie. other NPCs).
 * @param i 1 if we should respond to other NPCs, 0 if not
 */
void set_respond_non_interactive( int i ) {
    if( i )
        TO->add_property("RNI", 1 );
    else
        TO->remove_property("RNI");
} /* set_respond_non_interactive() */

/**
 * This method returns whether or not we should respond to other NPCs.
 * @return 1 if we should respond to other NPCs, 0 if not
 */
int query_respond_non_interactive() { return TO->query_property("RNI"); }

/**
 * This method checks to see if the response is allowed for this object.
 * @param ob the object to check
 * @param response the response that is matched
 * @return 1 if the object is allowed, 0 if it is not
 */
int query_response_allowed( object ob, string *response ) {
    return 1;
} /* query_response_allowed() */

/**
 * This method sets the current responses for the npc.
 * This will overwrite the current responses in the npc.
 * Please use add_respond_to_with in your NPC's instead of
 * this function call, as it requires prior knowledge as to
 * the internal structure of the respond_to_with code that
 * add_respond_to_with handles nicely.
 * The array is of the formant:<pre>
 *   ({
 *      trigger1,
 *      response1,
 *      trigger2,
 *      response2,
 *      ...
 *    })
 * </pre>
 * @see add_respond_to_with()
 * @see query_respond_to_with()
 */
void set_respond_to_with( mixed map ) {
   mixed old_keys;
   int i;

   if( mapp( map ) ) {
       log_file("BAD_RESPONSE", "set_respond_to_with() called by %O (%s)\n",
                 PO, PO->query_name() );
       old_keys = keys(map);
       respond_to_with = allocate(sizeof(old_keys) * 2);
       for( i = sizeof(old_keys); i--; ) {
           respond_to_with[2*i] = old_keys[i];
           respond_to_with[2*i+1] = map[old_keys[i]];
       }
       return;
   }

   respond_to_with = map;

} /* set_respond_to_with() */

/**
 * This method returns the current responding to with array.
 * The array is of the formant:<pre>
 *   ({
 *      trigger1,
 *      response1,
 *      trigger2,
 *      response2,
 *      ...
 *    })
 * </pre>
 * @see add_respond_to_with()
 */
mixed query_respond_to_with() { return respond_to_with || ({ }); }

/**
 * This method adds a respond message to respond to into the
 * current array of responses.
 * <p>
 * If response_mon_regexp is not set, the trigger consists of an
 * array of words to be matched (in order) in the string.
 * If there is an array instead of a single word at one point
 * then any of the words in the array will be matched.
 * If response_mon_regexp is set, the trigger is a single string,
 * representing the regular expression to be matched in the string.
 * <p>
 * The response is either an array of things to execute
 * (in which case a random one will be chosen each time) or
 * a function pointer or a string.  If it is a string then
 * the command of that name will be executed, if the
 * string starts with a '#' then the function named after that
 * will be called on the npc.  That was exciting wasn't it?
 * If the string has a $hname$ name in it and it is not a
 * function call (starts with a #) then the $hname$ will be replaced
 * with the name of the triggering object.
 * <p>
 * In the case of a function call, two arguments are passed into
 * the function: the first is the person which triggered the effect
 * and the second in the message which triggered the effect.
 * <p>
 * Also possible with a format of "#filename:function" is calling
 * functions on other objects.  Those functions will be called
 * with the NPC (object) as the first argument, and the person
 * triggering the event as the second (object) argument.
 * <p>
 * NOTE: The NPC must explicitly know the language being spoken, even
 * if it's "common".  I don't know why.  That's just the way it is.  See
 * add_language().
 * @example
 * // Simple response
 * add_respond_to_with(({ "@say", "bing" }), "'Yes!  Bing bing bing!");
 * @example
 * // respond to someone saying 'frog' or 'toad'
 * add_respond_to_with(({ "@say", ({ "frog", "toad" }) }),
 *                     "'Frogs and toads are nice.");
 * @example
 * // Randomly say something or bing back at them
 * add_respond_to_with(({ "@say", "bing" }),
 *                     ({ "'Yes!  Bing bing bing!", "bing $hname$" }));
 * @example
 * // Call the function 'rabbit' on the npc.
 * add_respond_to_with(({ "@say", "bing" }), "#rabbit");
 * @example
 * // Do something cute with a function pointer
 * add_respond_to_with(({ "@bing" }),
 *                  (: do_command("'something wild for " + $1->a_short()) :));
 * @example
 * // Calling a function on a room for example
 * add_respond_to_with(({ "@bing" }), "#"+PUB+"pub:do_bing_response");
 * @param trigger the trigger to trigger the action on
 * @param response the response to the action
 * @see query_respond_to_with()
 * @see query_response_allowed()
 * @see set_response_mon_regexp()
 * @see query_response_mon_regexp()
 * @see regexp()
 * @see add_language()
 */
void add_respond_to_with( mixed trigger, mixed response ) {
   if( !pointerp(respond_to_with) )
       respond_to_with = ({ });
   respond_to_with += ({ trigger, response });
} /* add_response() */

/**
 * This method checks the subsequence of words to see if it matches
 * any of our current response sets.
 * @param words the words which are to be tested
 * @return the response to be executed
 * @see add_respond_to_with()
 */
protected mixed check_sub_sequence( string *words ) {
    int word_index;
    int format_index;
    int format_size;
    int word_size;
    int match_counter;
    int cu_format_size;
    string word_str;

    format_index = 0;
    word_size = sizeof( words );
    word_str = implode( words, " ");
    format_size = sizeof( respond_to_with );

    while( format_index < format_size ) {
        if( use_regexp ) {
            if( regexp( word_str, respond_to_with[format_index]) )
                return respond_to_with[format_index+1];
        } else {
            word_index = 0;
            match_counter = 0;
            cu_format_size = sizeof( respond_to_with[format_index] );
            while( word_index < word_size && match_counter < cu_format_size ) {
                match_counter += match( words[word_index],
                    respond_to_with[format_index][match_counter] );
                word_index++;
            }
            if( match_counter == (cu_format_size) )
                return respond_to_with[format_index+1];
        }
        format_index += 2;
    }

    return 0;

} /* check_sub_sequence() */

/**
 * @ignore yes
 * This method returns 1 if str matches the format...
 * see also the definitions in the example file...
 */
protected int match( string str, mixed format ) {
   if( pointerp(format) )
       return member_array( str, format ) != -1;
   if( str == format )
       return 1;
   return 0;
} /* match() */

/**
 * This method removes annoying read marks to make the string easier to
 * parse.  Basically it strips punctuation.
 * @param str the string to remove the punctuation from
 * @return the string without any punctuation
 */
protected string remove_read_marks( string str ) {
   int i, size;
   string result, temp;

   size = strlen(str);
   result = "";
   while( i < size ) {
     temp = str[i..i];
     if( ( temp >= "A" && temp <= "Z" ) ||
         ( temp >= "a" && temp <= "z" ) ||
         ( temp >= "0" && temp <= "9" ) || temp == " " ) {
         result += temp;
     } else {
         result += " ";
     }
     i++;
   }
   return result;
} /* remove_read_marks() */

/**
 * This method runs the command passed in, doing some substitution.
 * @param str the string to execute
 * @param per the person who triggered the command
 */
protected void senddstr( string str, object per ) {
   if( ENV(TO) ) {
       command( !per ? str : replace( str, ({
                             "$hname$", per->query_name(),
                             "$hcname$", per->query_cap_name()
                             }) ) );
   }
} /* sendstr() */

/*
 * Take care not to send to other monsters...
 * Infinite recursion problem...
 * Imagine two monsters chatting with each other...
 */
/**
 * This method executes the response to the matched string.
 * @param rep the response to execute
 * @param per the person who initiated the event
 * @param mess the message that was matched
 * @see add_respond_to_with()
 */
protected void exec_response( mixed rep, object per, string mess ) {
   string *rabbit;

   if( !per || ( !interactive(per) && !query_respond_non_interactive() ) )
       return 0;

   if( !TO->query_visible(per) )
       return 0;

   if( pointerp(rep) )
       return exec_response( rep[random(sizeof(rep))], per, mess );

   if( functionp(rep) ) {
       evaluate( rep, per, mess );
   } else if( stringp(rep) ) {
       if( rep[0..0] == "#" ) {
           if( sizeof( rabbit = explode( rep[1..], ":") ) == 2 ) {
               call_out( (: call_other( $1, $2, $3, $4 ) :), 0,
                            rabbit[0], rabbit[1], TO, per );
               return;
           }
           rabbit = explode(rep[1..], "#");
           if( sizeof(rabbit) > 1 ) {
               call_out( (: call_other( $1, $2, $3, $4 ) :), 0,
                            rabbit[0], rabbit[1], per, mess );
           } else {
               call_out( rabbit[0], 0, per, mess );
           }
       } else {
           call_out("senddstr", 0, rep, per );
       }
   }
} /* exec_response() */

/** @ignore yes */
private void do_delay_thingy( string *extra, string mess, object per ) {
   mixed response;

   mess = lower_case(mess);

   if( !use_regexp )
       mess = remove_read_marks(mess);

   if( query_response_mon_debug_mode() )
       tell_object( per, "Parsing the text: "+
           implode( extra, " ")+" "+mess+"\n");

   response = check_sub_sequence( extra + explode( mess, " ") );
   if( query_response_mon_debug_mode() )
       tell_object( per, sprintf("Responding with %O\n", response ) );

   if( response && query_response_allowed( per, response ) )
       exec_response( response, per, mess );

} /* do_delay_thingy() */

/** @ignore yes */
private void do_response( string *extra, string mess, object per ) {
   call_out( (: do_delay_thingy( $1, $2, $3 ) :), 2, extra, mess, per );
} /* do_response() */

/** @ignore yes */
void event_person_say( object per, string start, string mess, string lang ) {
  string skill;

  if( !per || per == TO || stop_responding || !sizeof(respond_to_with) ||
      ( !interactive(per) && !query_respond_non_interactive() ) )
      return;

  if( ENV(TO) == find_object("/room/rubbish") ||
      ENV(TO) == find_object("/room/void") )
      return;

  /*
   * I know this is a hack, if you can do better, do so,
   * don't just take it out or things will break come womans day.
   */
  skill = LANGUAGES->query_language_spoken_skill(lang);
  if( TO->query_skill(skill) < 90 || per->query_skill(skill) < 60 )
      return;

  do_response( ({"@say"}), mess, per );

} /* event_person_say() */

/** @ignore yes */
varargs void event_soul( object per, string mess, object *avoid, string verb,
                         string last, mixed at ) {

   if( per == find_object(SOUL_OBJECT) )
       per = previous_object(2);

  if( !per || per == TO || stop_responding || !sizeof(respond_to_with) ||
      ( !interactive(per) && !query_respond_non_interactive() ) )
      return;

  if( ENV(TO) == find_object("/room/rubbish") ||
      ENV(TO) == find_object("/room/void") ||
      member_array( TO, avoid ) != -1 )
      return;

   if( ( !objectp(at) || ( objectp(at) && at != TO ) ) &&
       ENV(per) != ENV(TO) )
       return;

   mess = TO->convert_message( mess );
   do_response( ( objectp(at) ? ({ "@" + verb, "#"+last, at->query_name() }) :
               ({ "@" + verb, "#"+last }) ), mess, per );

} /* event_soul() */

/** @ignore yes */
varargs void event_whisper( object per, string mess, object *obs, string lang,
                            object me ) {

  if( !per || per == TO || stop_responding || !sizeof(respond_to_with) ||
      ( !interactive(per) && !query_respond_non_interactive() ) )
      return;

  if( ENV(TO) == find_object("/room/rubbish") ||
      ENV(TO) == find_object("/room/void") )
      return;

   // Don't let them see the message unless it is actually directed at them.
   if( member_array( TO, obs ) == -1 ) {
       do_response( ({"@whisper"}) + map( obs, (: $1->query_name() :) ),
                      "", per );
   } else {
       mess = TO->convert_message( mess );
       do_response( ({"@whisper"}) + map( obs, (: $1->query_name() :) ),
                      mess, per );
   }
} /* event_whisper() */