// /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;
}
}