tmi2_fluffos_v2/
tmi2_fluffos_v2/bin/
tmi2_fluffos_v2/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/ChangeLog.old/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/Win32/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/simuls/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/clone/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/command/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/data/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/master/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/log/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/u/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/tmp/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/windows/
tmi2_fluffos_v2/lib/
tmi2_fluffos_v2/lib/adm/
tmi2_fluffos_v2/lib/adm/daemons/languages/
tmi2_fluffos_v2/lib/adm/daemons/network/I3/
tmi2_fluffos_v2/lib/adm/daemons/virtual/
tmi2_fluffos_v2/lib/adm/daemons/virtual/template/
tmi2_fluffos_v2/lib/adm/news/
tmi2_fluffos_v2/lib/adm/obj/
tmi2_fluffos_v2/lib/adm/obj/master/
tmi2_fluffos_v2/lib/adm/priv/
tmi2_fluffos_v2/lib/adm/shell/
tmi2_fluffos_v2/lib/adm/tmp/
tmi2_fluffos_v2/lib/cmds/
tmi2_fluffos_v2/lib/d/
tmi2_fluffos_v2/lib/d/Conf/
tmi2_fluffos_v2/lib/d/Conf/adm/
tmi2_fluffos_v2/lib/d/Conf/boards/
tmi2_fluffos_v2/lib/d/Conf/cmds/
tmi2_fluffos_v2/lib/d/Conf/data/
tmi2_fluffos_v2/lib/d/Conf/logs/
tmi2_fluffos_v2/lib/d/Conf/obj/
tmi2_fluffos_v2/lib/d/Conf/text/help/
tmi2_fluffos_v2/lib/d/Fooland/adm/
tmi2_fluffos_v2/lib/d/Fooland/data/
tmi2_fluffos_v2/lib/d/Fooland/data/attic/
tmi2_fluffos_v2/lib/d/Fooland/items/
tmi2_fluffos_v2/lib/d/TMI/
tmi2_fluffos_v2/lib/d/TMI/adm/
tmi2_fluffos_v2/lib/d/TMI/boards/
tmi2_fluffos_v2/lib/d/TMI/data/
tmi2_fluffos_v2/lib/d/TMI/rooms/
tmi2_fluffos_v2/lib/d/grid/
tmi2_fluffos_v2/lib/d/grid/adm/
tmi2_fluffos_v2/lib/d/grid/data/
tmi2_fluffos_v2/lib/d/std/
tmi2_fluffos_v2/lib/d/std/adm/
tmi2_fluffos_v2/lib/data/adm/
tmi2_fluffos_v2/lib/data/adm/daemons/
tmi2_fluffos_v2/lib/data/adm/daemons/doc_d/
tmi2_fluffos_v2/lib/data/adm/daemons/emoted/
tmi2_fluffos_v2/lib/data/adm/daemons/network/http/
tmi2_fluffos_v2/lib/data/adm/daemons/network/services/mail_q/
tmi2_fluffos_v2/lib/data/adm/daemons/network/smtp/
tmi2_fluffos_v2/lib/data/adm/daemons/news/archives/
tmi2_fluffos_v2/lib/data/attic/connection/
tmi2_fluffos_v2/lib/data/attic/user/
tmi2_fluffos_v2/lib/data/std/connection/b/
tmi2_fluffos_v2/lib/data/std/connection/l/
tmi2_fluffos_v2/lib/data/std/user/a/
tmi2_fluffos_v2/lib/data/std/user/b/
tmi2_fluffos_v2/lib/data/std/user/d/
tmi2_fluffos_v2/lib/data/std/user/f/
tmi2_fluffos_v2/lib/data/std/user/l/
tmi2_fluffos_v2/lib/data/std/user/x/
tmi2_fluffos_v2/lib/data/u/d/dm/working/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/smtp/
tmi2_fluffos_v2/lib/doc/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/interactive/
tmi2_fluffos_v2/lib/doc/driverdoc/concepts/
tmi2_fluffos_v2/lib/doc/driverdoc/driver/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/arrays/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/buffers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/compile/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/ed/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/filesystem/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/floats/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/functions/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/general/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/mappings/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/numbers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/parsing/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/constructs/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/preprocessor/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/types/
tmi2_fluffos_v2/lib/doc/driverdoc/platforms/
tmi2_fluffos_v2/lib/doc/mudlib/
tmi2_fluffos_v2/lib/ftp/
tmi2_fluffos_v2/lib/include/driver/
tmi2_fluffos_v2/lib/log/
tmi2_fluffos_v2/lib/log/driver/
tmi2_fluffos_v2/lib/obj/net/
tmi2_fluffos_v2/lib/obj/shells/
tmi2_fluffos_v2/lib/obj/tools/
tmi2_fluffos_v2/lib/std/adt/
tmi2_fluffos_v2/lib/std/board/
tmi2_fluffos_v2/lib/std/body/
tmi2_fluffos_v2/lib/std/fun/
tmi2_fluffos_v2/lib/std/living/
tmi2_fluffos_v2/lib/std/object/
tmi2_fluffos_v2/lib/std/shop/
tmi2_fluffos_v2/lib/std/socket/
tmi2_fluffos_v2/lib/std/user/
tmi2_fluffos_v2/lib/std/virtual/
tmi2_fluffos_v2/lib/student/
tmi2_fluffos_v2/lib/student/kalypso/
tmi2_fluffos_v2/lib/student/kalypso/armor/
tmi2_fluffos_v2/lib/student/kalypso/rooms/
tmi2_fluffos_v2/lib/student/kalypso/weapons/
tmi2_fluffos_v2/lib/u/l/leto/
tmi2_fluffos_v2/lib/u/l/leto/cmds/
tmi2_fluffos_v2/lib/www/errors/
tmi2_fluffos_v2/lib/www/gateways/
tmi2_fluffos_v2/lib/www/images/
tmi2_fluffos_v2/old/
tmi2_fluffos_v2/win32/
// /u/k/kinslayer/sr.c (smartresponce.c) smart responce inspired by
// Padron McCarthy at NannyMud.
//
// inherit this file to add smart responces to monsters, note this
// file inherits monster.c so it must be configured like a monster..
// 
// Kinslayer@Empris (13MAY94) Version 1.0.0

#pragma strict_types
#pragma save_binary

#include <mudlib.h>

inherit MONSTER;

/*-----------------------------------------------------------------*/
// Debugging stuff, to activate set_log_file() must be set to
// a dir that the UID has write access to, for most cases this should
// be the domain dir for the object, or the user dir.

string log_file_name;

void set_log_file(string str) {
  log_file_name = str;
}

string query_log_file() {
  return log_file_name;
}

void say_confused(string str) {
string junk;
 
    if (this_player() != this_object() && !this_player()->query("npc")) {
        junk = sprintf("%s (%O) tells you: I am confused: %s\n", this_object()->query("cap_name"), file_name(this_object()), str);
        tell_object(this_player(), junk);
    }
 
    else if (previous_object() != this_object() && living(previous_object()) &&!previous_object()->query("npc")) {
        junk = sprintf("%s (%O) tells you: I am confused: %s\n", this_object()->query("cap_name"), file_name(this_object()), str);
        tell_object(previous_object(), junk);
    } else
        say(sprintf("%s seems to be confused: %s\n", this_object()->query("cap_name"), str));
        junk = sprintf("%O : %s (%O) was confused: %s\n", ctime(time()), this_object()->query("cap_name"), file_name(this_object()), str);
        if(log_file_name != 0)
          write_file(log_file_name, junk);
} /* say_confused */
 

void say_error(string str) {
    string tell_message, log_message;
 
    tell_message = sprintf("%s (%O) tells you: ERROR! %s\n", this_object()->query("cap_name"), file_name(this_object()), str);
    log_message = sprintf("%O: %s (%O, creator: %O)   ERROR: %s\n", ctime(time()), this_object()->query("cap_name"), file_name(this_object()),creator_file(file_name(this_object())),str);
 
    if (this_player() != this_object())
        log_message += sprintf("this_player = %s (%O)\n", this_player()->query("cap_name"), file_name(this_player()));
 
    if (previous_object() != this_object())
        log_message += sprintf("previous_object() = %s\n",file_name(previous_object()));
 
    if (this_player() != this_object() && !this_player()->query("npc"))
        tell_object(this_player(), tell_message);
    else if (previous_object() != this_object() && living(previous_object()) && !previous_object()->query("npc"))
        tell_object(previous_object(), tell_message);
    else {
        say(sprintf("%s looks very confused: %s.\n", this_object()->query("cap_name"), str));
        if(log_file_name != 0)
        write_file(log_file_name, log_message);
   }
} /* say_error */
 

void debug_log(string str, int junk) {
string file_format;
  if(log_file_name != 0 && junk == 0) {
    file_format = sprintf(@FILEFORMAT

******************************************************************************
File_name: %O Cap_name: %s
Time: %O Location: %O

Debug message:
%s
FILEFORMAT
, file_name(this_object()), this_object()->query("name"), ctime(time()), environment(this_object()), str);

    write_file(log_file_name, file_format);
  } else if(log_file_name != 0 && junk != 0)
    write_file(log_file_name, str);

}

#define DEBUG_LOG(str, junk)       debug_log(str, junk)
#define SAY_CONFUSED(str)        say_confused(str)
#define SAY_ERROR(str)           say_error(str)

int handle_caught_texts;

void smartwrite(mixed something);


/*---------------------------------------------------------------------------*/

mixed response_object;  // The object in which to call the functions 
mixed *response_data;
 
//  response_data is an array of multiples of four elements, each of which is
//    the action the monster will respond to (a string),
//    the message to print in response to this action (a string),
//    an (optional) special messages to the "opponent" (also a string),
//    the chance for each response, if it matched (an integer 0..100)
//    If the "message to print" starts with '*' or '!',
//    it is used as a function to call or a command to give.
//    It could also be an array of actions to perform.
 
 
varargs void add_response(string act, mixed response, mixed arg3, mixed arg4) {
    string opponent_msg;
    int chance;
 
//      Usage:
//           add_response  ACTION  "REPLY-MESSAGE"  [ "PERSONAL-REPLY-MESSAGE" ]  [ CHANCE ]
//           add_response  ACTION  "*FUNCTION-NAME"  [ CHANCE ]
//           add_response  ACTION  "!COMMAND"  [ CHANCE ]
//           add_response  ACTION  ARRAY-OF-RESPONSES  [ CHANCE ]
     
 
    if (pointerp(response) || response[0] == '*' || response[0] == '!') {
        if (!intp(arg3) || arg4 != 0) {
            SAY_ERROR("Bad arguments (arg 3 or 4) to add_response.");
            return;
        }
        chance = arg3;
    }
    else if (!stringp(response)) {
        SAY_ERROR("Bad argument (response) to add_response.");
        return;
    }   
    else if ((stringp(arg3) || arg3 == 0) && intp(arg4)) {
        opponent_msg = arg3;
        chance = arg4;
    }
    else if (intp(arg3) && arg4 == 0) {
        chance = arg3;
    }
    else {
        SAY_ERROR("Bad arguments to add_response.");
        return;
    }
 
    if (chance == 0)
        chance = 100;
 
    if (response_data == 0)
        response_data = ({ });
    response_data += ({ act, response, opponent_msg, chance });
 
    handle_caught_texts = 1;
} /* add_response */
 
void set_responses(mixed *all_responses) {
    if (all_responses != 0 && !pointerp(all_responses)) {
        SAY_ERROR("Bad argument to set_responses.");
        return;
    }
    response_data = all_responses;
    if (response_data)
        handle_caught_texts = 1;
} /* set_responses */
 
mixed *query_responses() {
    return response_data;
} /* query_responses */
 
void set_response_object(mixed obj) {
    response_object = obj;
}
 
/*---------------------------------------------------------------------------*/
 
mixed *say_response_data;
 
//  say_response_data is an array of multiples of four elements, each of which is
//    the word or word the monster will respond to
//      (a string, or an array of strings or arrays of strings)
//    the message to print in response to this action (a string),
//    an (optional) special messages to the "opponent" (also a string),
//    the chance for each response, if it matched (an integer 0..100)
//    If the "message to print" starts with '*' or '!',
//    it is used as a function to call or a command to give.
//    It could also be an array of actions to perform.
 
 
varargs void add_say_response(mixed word, mixed response, mixed arg3, mixed arg4) {
    string opponent_msg;
    int chance;
 
//      Usage:
//          add_say_response  WORD  "REPLY-MESSAGE"  [ "PERSONAL-REPLY-MESSAGE" ]  [ CHANCE ]
//          add_say_response  WORD  "*FUNCTION-NAME"  [ CHANCE ]
//          add_say_response  WORD  "!COMMAND"  [ CHANCE ]
//          add_say_response  WORD  ARRAY-OF-RESPONSES  [ CHANCE ]
//          WORD can be either a string, or an array of strings or arrays of strings.
 
 
    if (pointerp(response) || response[0] == '*' || response[0] == '!') {
        if (!intp(arg3) || arg4 != 0) {
             SAY_ERROR("Bad arguments (arg 3 or 4) to add_say_response.");
            return;
        }
        chance = arg3;
    }
    else if (!stringp(response)) {
        SAY_ERROR("Bad argument (response) to add_say_response.");
        return;
    }   
    else if ((stringp(arg3) || arg3 == 0) && intp(arg4)) {
        opponent_msg = arg3;
        chance = arg4;
    }
    else if (intp(arg3) && arg4 == 0) {
        chance = arg3;
    }
    else {
        SAY_ERROR("Bad arguments to add_say_response.");
        return;
    }
 
    if (chance == 0)
        chance = 100;
 
    if (say_response_data == 0)
        say_response_data = ({ });
    say_response_data += ({ word, response, opponent_msg, chance });
 
    handle_caught_texts = 1;
} /* add_say_response */
 
void set_say_responses(mixed *all_say_responses) {
    if (all_say_responses != 0 && !pointerp(all_say_responses)) {
        SAY_ERROR("Bad argument to set_say_responses.");
        return;
    }
    say_response_data = all_say_responses;
    if (say_response_data)
        handle_caught_texts = 1;
} /* set_say_responses */
 
mixed *query_say_responses() {
    return say_response_data;
} /* query_say_responses */
/* Substitute "$OTHER" with the opponent's name */
string substitute_other(string str, string opponents_name) {
    string part1, part2;
 
    while (sscanf(str, "%s$OTHER%s", part1, part2) == 2)
        str = part1 + opponents_name + part2;
    while (sscanf(str, "%s$LOWOTHER%s", part1, part2) == 2)
        str = part1 + lower_case(opponents_name) + part2;
    return str;
} /* substitute_other */
 
/*  This function is called when the response is to be performed
 *  - i. e. it matched, and the dice rolled our way!
 */
void perform_response(string opponents_name, string what, string how,
                      mixed response, string opponent_msg)
{
 
    DEBUG_LOG("perform_response('" + opponents_name + "', '" + what + "', '" + how + "', ...)", 1);
 
    if (pointerp(response)) {
        /* This "response" is really an array of responses */
        if (opponent_msg) {
            SAY_ERROR("Bad argument (opponent_msg) to perform_response.");
            return;
        }
        else {
            int i, n;
 
            n = sizeof(response);
            for (i = 0; i < n; ++i)
                perform_response(opponents_name, what, how, response[i], 0);
        }
    }
    else if (!stringp(response)) {
        SAY_ERROR("Bad argument (response) to perform_response.");
        return;
    }
    else if (response[0] == '!') {
        string cmd;
        sscanf(response, "!%s", cmd);
        command(substitute_other(cmd, opponents_name));
    }
    else if (response[0] == '*') {
        string fun;
 
        sscanf(response, "*%s", fun);
        fun = substitute_other(fun, opponents_name);
 
        DEBUG_LOG("Calling " + fun + "(\"" + opponents_name +
                  "\", \"" + what + "\", \"" + how + "\")", 1);
 
        call_other(response_object, fun, opponents_name, what, how);
    }
    else {
        object opponent_obj;
 
        if (opponent_msg && opponents_name)
            opponent_obj = present(opponents_name);
 
        if (opponent_obj) {
            tell_object(opponent_obj, substitute_other(opponent_msg, opponents_name));
            say(substitute_other(response, opponents_name), opponent_obj);
        }
        else
            say(substitute_other(response, opponents_name));
    }
} /* perform_response */
 
/*---------------------------------------------------------------------------*/
 
int match_responses(string str) {
    string who, what, how, msg, opponent_msg, junk;
    int i, n;
    object opponent;
 
#ifdef MONSTER_COMPAT
    if (talk_ob)
        test_match(str);
#endif
 
    if (response_data == 0)
        return 0;
    n = sizeof(response_data);
    /* Backwards. New responses that are added should be tested before old ones. */
    for (i = n - 4; i >= 0; i -= 4) {
        what = response_data[i];
        /* how = ""; */
 
        /*  As it is now, the action "smiles" matches all of "X smiles\n",
         *  "X smiles.\n", "X smiles like a surgeon.\n" and "X smilesiglurps.\n".
         *  Maybe it should match "X smiles\n", "X smiles.\n"
         *  and "X smiles like a surgeon.\n" but not "X smilesiglurps.\n"?
         */
        if (   sscanf(str, "%s " + what + " %s\n", who, how) == 2
            || sscanf(str, "%s " + what, who) == 1) {
 
            if (random(100) < response_data[i + 3]) {
                msg = response_data[i + 1];
                opponent_msg = response_data[i + 2];
 
                /* The "who" from the last sscanf could be too long! */
                /* sscanf(who, "%s %s\n", who, junk); */
 
                if (how == 0)
                    how = "";
 
                perform_response(who, what, how, msg, opponent_msg);
                return 1;
            }
        } /* if this response matched */
    } /* for all stored responses */
    return 0;
} /* match_responses */
 
/*---------------------------------------------------------------------------*/
 
string *split_into_words(string str) {
    int wordstart, pos, afterpos;
    int c, nl;
    string *result;
 
    afterpos = strlen(str);
    result = ({ });
    pos = 0;
    nl = "\n"[0];  /* Grr! '\n' doesn't work! */
    while (pos < afterpos) {
        /* First, skip leading blanks and interpunctation. */
        while (   pos < afterpos
               && (((c = str[pos]) == ' ') || c == nl || c == '.'
                   || c == '?' || c == '!' || c == ',' || c == ':'))
            ++pos;
        wordstart = pos;
        /* If we haven't reached the end of the string,
         * take the word that starts here.
         */
        if (pos < afterpos) {
            while (   pos < afterpos
                   && ((c = str[pos]) != ' ') && c != nl && c != '.'
                   && c != '?' && c != '!' && c != ',' && c != ':')
                ++pos;
            result += ({ str[wordstart..pos-1] });
        }
    }
    return result;
} /* split_into_words */
 
/*---------------------------------------------------------------------------*/
 
int match_say_responses(object opponent, string who, string phrase) {
    mixed datawords;
    string msg, opponent_msg;
    int i, n, word_nr, nr_datawords;
    string *inputwords;
 
    if (say_response_data == 0)
        return 0;
    inputwords = split_into_words(lower_case(phrase));
    n = sizeof(say_response_data);
    /* Backwards. New responses that are added should be tested before old ones. */
    for (i = n - 4; i >= 0; i -= 4) {
        datawords = say_response_data[i];
        if (pointerp(datawords)) {
            /* "datawords" was an array of words. Match against each of them! */
            nr_datawords = sizeof(datawords);
            for (word_nr = 0; word_nr < nr_datawords; ++word_nr) {
                if (member_array(datawords[word_nr], inputwords) != -1) {
                    msg = say_response_data[i + 1];
                    opponent_msg = say_response_data[i + 2];
                    perform_response(who, "(says)", phrase, msg, opponent_msg);         
                    return 1;
                }
            } /* for each word in the array */
        }
        else {
            /* "datawords" was just a single word. Match against it! */
            if (member_array(datawords, inputwords) != -1) {
                msg = say_response_data[i + 1];
                opponent_msg = say_response_data[i + 2];
                perform_response(who, "(says)", phrase, msg, opponent_msg);             
                return 1;
            }
        }
    } /* for all stored say_responses */
    return 0;
} /* match_say_responses */
 
/*---------------------------------------------------------------------------*/
 
mixed say_handler_obj;  /* The object in which to call... */
string say_handler_fun; /* ...this function when the monster hears a "say" */
 
void set_say_handler(mixed obj, string fun) {
    if (obj)
        say_handler_obj = obj;
    else
        say_handler_obj = previous_object();
    if (fun)
        say_handler_fun = fun;
    else
        say_handler_fun = "handle_say";
    handle_caught_texts = 1;
} /* set_say_handler */
 
/*---------------------------------------------------------------------------*/
 
mixed tell_handler_obj;     /* The object in which to call... */
string tell_handler_fun;    /* ...this function when the monster hears a "tell" */
 
void set_tell_handler(mixed obj, string fun) {
    if (obj)
        tell_handler_obj = obj;
    else
        tell_handler_obj = previous_object();
    if (fun)
        tell_handler_fun = fun;
    else
        tell_handler_fun = "handle_tell";
    handle_caught_texts = 1;
} /* set_tell_handler */
 
/*---------------------------------------------------------------------------*/
 
mixed give_handler_obj;  /* The object in which to call... */
string give_handler_fun; /* ...this function when the monster is given an object */
 
void set_give_handler(mixed obj, string fun) {
    if (obj)
        give_handler_obj = obj;
    else
        give_handler_obj = previous_object();
    if (fun)
        give_handler_fun = fun;
    else
        give_handler_fun = "handle_give";
    handle_caught_texts = 1;
} /* set_give_handler */
 
/*---------------------------------------------------------------------------*/
 
mixed give_money_handler_obj;  /* The object in which to call... */
string give_money_handler_fun; /* ...this function when the monster is given some money */
 
void set_give_money_handler(mixed obj, string fun) {
    if (obj)
        give_money_handler_obj = obj;
    else
        give_money_handler_obj = previous_object();
    if (fun)
        give_money_handler_fun = fun;
    else
        give_money_handler_fun = "handle_give_money";
    handle_caught_texts = 1;
} /* set_give_money_handler */
 
/*---------------------------------------------------------------------------*/
 
mixed arrive_handler_obj;       /* The object in which to call... */
string arrive_handler_fun;      /* ...this function when someone arrives */
 
void set_arrive_handler(mixed obj, string fun) {
    if (obj)
        arrive_handler_obj = obj;
    else
        arrive_handler_obj = previous_object();
    if (fun)
        arrive_handler_fun = fun;
    else
        arrive_handler_fun = "handle_arrive";
    handle_caught_texts = 1;
} /* set_arrive_handler */
 
/*---------------------------------------------------------------------------*/
 
mixed leave_handler_obj;        /* The object in which to call... */
string leave_handler_fun;       /* ...this function when someone leaves */
 
void set_leave_handler(mixed obj, string fun) {
    if (obj)
        leave_handler_obj = obj;
    else
        leave_handler_obj = previous_object();
    if (fun)
        leave_handler_fun = fun;
    else
        leave_handler_fun = "handle_leave";
    handle_caught_texts = 1;
} /* set_leave_handler */
 
/*---------------------------------------------------------------------------*/
 
/* Maybe we should put "smartpresent" in 'obj/simul_efun.c' or somewhere? */
 
static object smartpresent2(mixed what, mixed where) {
    object obj, foundobj, *all_inv;
    string lwhat, lwhat2, junk;
    int i, n, the_number;
 
    if (what == 0)
        return 0;
    obj = present(what, where);
    if (obj || !stringp(what))
        return obj;
    lwhat = lower_case(what);
    obj = present(lwhat, where);
    if (obj)
        return obj;
    while (   sscanf(lwhat, "the %s", lwhat) == 1
           || sscanf(lwhat, "a %s", lwhat) == 1
           || sscanf(lwhat, "an %s", lwhat) == 1
           || sscanf(lwhat, "%s.", lwhat) == 1) {
        obj = present(lwhat, where);
        if (obj)
            return obj;
    }
    while (sscanf(lwhat, "%s %d", lwhat2, the_number) == 2) {
        if (where == 0)
            where = environment(this_object());
        all_inv = all_inventory(where);
        if (pointerp(all_inv)) {
            n = sizeof(all_inv);
            foundobj = 0;
            for (i = 0; i < n && the_number > 0; ++i) {
                if (all_inv[i]->id(lwhat2)) {
                    if (--the_number == 0)
                        return obj;
                    else if (!foundobj)
                        foundobj = all_inv[i];
                }
            }
            if (foundobj)
                return foundobj;
        }
        lwhat = lwhat2;
    }
    while (   sscanf(lwhat, "%s, %s", lwhat2, junk) == 2
           || sscanf(lwhat, "%s - %s", lwhat2, junk) == 2
           || sscanf(lwhat, "%s %s", lwhat2, junk) == 2) {
        obj = present(lwhat2, where);
        if (obj)
            return obj;
        lwhat = lwhat2;
    }
    return 0;
} /* smartpresent2 */
 
object smartpresent(mixed what, mixed where) {
    object foundobj;
 
    if (where == 0) {
        foundobj = smartpresent2(what, environment(this_object()));
        if (foundobj)
            return foundobj;
        foundobj = smartpresent2(what, this_object());
        return foundobj;
    }
    else
        return smartpresent2(what, where);
} /* smartpresent */
 
/*-----------------------------------------------------------------*/
int do_matching(string str) {
    string who, phrase, what, whom, how;
    object who_obj, what_obj;
    int the_number;
 
    DEBUG_LOG("do_matching(\"" + str + "\")", 1);
 
    /* Was this something that someone said? */
    if (   (say_handler_obj || say_response_data)
        && (   (sscanf(str, "%s says: %s\n", who, phrase) == 2)
            || (sscanf(str, "%s says \"%s\"\n", who, phrase) == 2))) {
        who_obj = smartpresent(who, environment(this_object()));
        if (who_obj) {
            if (say_response_data && match_say_responses(who_obj, who, str)) {
 
            }
            else if (say_handler_obj)
                call_other(say_handler_obj, say_handler_fun, who_obj, who, phrase);
        }
        else {
            SAY_CONFUSED(who + " said something, but doesn't seem to be here now.");
        }
    } /* if (say_handler_obj) */
 
    /* Was this something that someone told this monster? */
    if (   (tell_handler_obj || say_response_data)
        && (sscanf(str, "%s tells you: %s\n", who, phrase) == 2)) {
        who_obj = smartpresent(who, environment(this_object()));
        if (!who_obj)
            who_obj = find_living(lower_case(who));
        if (who_obj) {
            if (say_response_data && match_say_responses(who_obj, who, str)) {
 
            }
            else if (tell_handler_obj)
                call_other(tell_handler_obj, tell_handler_fun, who_obj, who, phrase);
        }
        else {
            SAY_CONFUSED(who + " told me something, but can't be found.");
        }
    } /* if (tell_handler_obj) */
 
    /* Did someone just give this monster some money? some editing may be needed here!*/
    if (   give_money_handler_obj
        && (sscanf(str, "%s gives you %d gold coins.\n", who, what) == 2)) {
        /* Ok, someone gave this monster some gold coins! Now: who? */
        who_obj = smartpresent(who, environment(this_object()));
        if (!who_obj) {
            SAY_CONFUSED(who + " gave me some gold, but doesn't seem to be here now.");
        }
        else
            call_other(give_money_handler_obj, give_money_handler_fun, who_obj, who, what);
    } /* if (give_money_handler_obj && ...) */
 
    /* Did someone just give this monster something? */
    if (   give_handler_obj
        && (sscanf(str, "%s gives %s to %s.\n", who, what, whom) == 3)
        && (   id(whom)
            || id(lower_case(whom))
            || (   (sscanf(whom, "%s %d", whom, the_number) == 2)
                && (id(whom) || id(lower_case(whom)))))) {
        /* Ok, someone gave this monster something! Now: who and what? */
        who_obj = smartpresent(who, environment(this_object()));
        if (!who_obj) {
            SAY_CONFUSED(who + " gave me something, but doesn't seem to be here now.");
        }
        else {
            /* Ok, a known someone gave this monster something! Now: what? */
            what_obj = smartpresent(what, this_object());
            if (what_obj)
                call_other(give_handler_obj, give_handler_fun, who_obj, who, what_obj, what);
            else {
                SAY_CONFUSED(who + " gave me '" + what + "', but I don't seem to have it now.");
            }
        }
    } /* if (give_handler_obj && ...) */
 
    /* Was this a message about someone arriving? */
    if (   arrive_handler_obj
        && (sscanf(str, "%s arrives%s.\n", who, how) == 2)) {
        who_obj = smartpresent(who, environment(this_object()));
        if (who_obj)
            call_other(arrive_handler_obj, arrive_handler_fun, who_obj, who, how);
        else {
            SAY_CONFUSED(who + " arrived, but doesn't seem to be here now.");
        }
    } /* if (arrive_handler_obj) */
 
    /* Was this a message about someone leaving? */
    if (   leave_handler_obj
        && (sscanf(str, "%s leaves %s.\n", who, how) == 2)) {
        call_other(leave_handler_obj, leave_handler_fun, 0, who, how);
    } /* if (leave_handler_obj) */
 
    if (response_data && match_responses(str))
        return 1;
    return 0;
} /* do_matching */
/*---------------------------------------------------------------------------*/
 
object fight_beat_obj;  /* The object in which to call... */
string fight_beat_fun;  /* ...this function each heartbeat when fighting */
 
void set_fight_beat(object obj, string fun) {
    if (obj)
        fight_beat_obj = obj;
    else
        fight_beat_obj = previous_object();
    if (fun)
        fight_beat_fun = fun;
    else
        fight_beat_fun = "fight_beat";
} /* set_fight_beat */
 
/*---------------------------------------------------------------------------*/
 
object peace_beat_obj;  /* The object in which to call... */
string peace_beat_fun;  /* ...this function each heartbeat when NOT fighting */
 
void set_peace_beat(object obj, string fun) {
    if (obj)
        peace_beat_obj = obj;
    else
        peace_beat_obj = previous_object();
    if (fun)
        peace_beat_fun = fun;
    else
        peace_beat_fun = "peace_beat";
} /* set_peace_beat */
 
/*-----------------------------------------------------------------*/

// queue_text() - here all texts that are received via receive_message()
// will be queued on the variable, "waiting_texts".

mixed waiting_texts;
int latest_receive_message_time;

void queue_text(string str) {
  if (waiting_texts == 0)
    waiting_texts = str;
  else if (stringp(waiting_texts))
    waiting_texts = ({ waiting_texts, str });
  else  waiting_texts += ({ str });
}

string get_queued_text() {
  string temp;

  if(stringp(waiting_texts)) {
    temp = waiting_texts;
    waiting_texts = 0;
  }
  else if (sizeof(waiting_texts) == 2) {
    temp = waiting_texts[0];
    waiting_texts = waiting_texts[1];
  }
  else { temp = waiting_texts[0];
    waiting_texts = waiting_texts[1..sizeof(waiting_texts)-1];
  }
  return temp;
}

int nr_waiting_texts() {
  if(waiting_texts == 0)
    return 0;
  else if (stringp(waiting_texts))
    return 1;
  else return sizeof(waiting_texts);
}

/*-----------------------------------------------------------------*/

// receive_message() - waiting_texts are queued here then on the next
// heart_beat the next waiting_text is processed.  If the newest addition
// to the queue is more than ten seconds old then the queue is dumped

void receive_message(string Class, string str) {
string junk;

  junk = sprintf("receive_message(Class: %s, string: %s);", Class, str);

  debug_log(junk, 0);
  if(previous_object() != this_object()) {

// Padron made a small error here in smartmonster ver 0.6.2 He did
// not put '()' around time() - latest_receive_message_time > 10
// so this condition was never used in his smartmonster version
// it was testing for && time() which is always true unless the date
// is Jan. 1, 1970 -Kinslayer

    if(waiting_texts && (time() - latest_receive_message_time > 10))
      waiting_texts = 0;
    latest_receive_message_time = time();

    queue_text(str);
  }
}
/*---------------------------------------------------------------------------*/
 
/*  Handle the texts on the queue.
 *  DON'T handle additional texts that may arrive now.
 */
void match_the_queue() {
    int i, n;
 
    n = nr_waiting_texts();
    for (i = 0; i < n; ++i)
        do_matching(get_queued_text());
} /* match_the_queue */
 
/*---------------------------------------------------------------------------*/
 
// this heart_beat() replaces the one in monster.c
 
void heart_beat() {
 
// If we're chasing someone, better go after him.
 
   if (query("in_pursuit")) {
      command("go "+query("in_pursuit")) ;
      if (present((object)query("pursued"),environment(this_object()))) {
         tell_object((object)query("pursued"),this_object()->query("cap_name")+" attacks you!\n") ;
         query("pursued")->kill_ob(this_object(),1) ;
      }
      delete ("in_pursuit") ;
      delete ("pursued") ;
   }
 
   if (query("moving")==1) move_around() ;
   if(random(100)+1 < query("chat_chance"))  monster_chat();
   if(waiting_texts) match_the_queue();
 
   heal_up();
 
   //  If no-one is around and fully healed, shut down the heartbeat
 
   if(!environment_check() && query("hit_points") == query("max_hp")) {
 
   if(query("max_sp") && query("max_sp") != query("spell_points"))
        return;
 
// If we're whanging on someone, best not to shut it down... :)
 
        if (sizeof(attackers)) return ;
 
   set_heart_beat(0);  hb_status = 0;  
   }
 
}