/* -*- LPC -*- */
/*
* $Locker: $
* $Id: events.c,v 1.136 2003/10/29 18:25:27 pinkfish Exp $
*/
/**
* 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 <living.h>
#include <player.h>
#include <telnet.h>
#include <term.h>
#include <tune.h>
#include <language.h>
#include <broadcaster.h>
#include <cmds/options.h>
#include <newbiehelpers.h>
#include <playerinfo.h>
#define DEBUG
// #define USE_ROLE_PLAYING_SHORTS
#define BROADCASTER "/obj/handlers/broadcaster"
#define SPACES " "
#define INFORM_COLOURS ([ "default":"WHITE", "logon":"GREEN", "death":"RED", \
"cheat":"RED", "multiplayer":"RED", \
"bad-password" : "RED", "link-death":"GREEN", \
"new-player" : "BOLD%^%^MAGENTA", \
"gag" : "BOLD%^%^RED", "alert" : "GREEN" ])
#ifdef OLD_THINGY
inherit "/global/play_parse_com";
#else
inherit "/global/new_parse";
#endif
inherit "/global/communicate";
inherit "/global/friends";
inherit "/global/options_control";
/*
* This contains the event related global variables.
* We are very short on global variables and this reduces our need for them.
*/
class event_info {
mapping colour_map;
string cur_term;
string last_term;
object where;
object *had_shorts;
mixed *eemessages;
mixed busy;
}
private nosave class event_info _event_info;
private int earmuffs;
private int cols;
private int 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 string term_name = "network";
private string *inform_types;
private mixed *tell_history;
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, int test);
private int do_busy(string str);
private int do_busy_player(object *players);
protected varargs int do_tell_his(string, int);
mixed query_property(string name);
string query_nationality_accent_ob();
void create() {
friends::create();
_event_info = new(class event_info,
eemessages : ({ }));
my_colours = ([ ]);
inform_types = ({ });
#ifdef OLD_THINGY
play_parse_com::create();
#else
new_parse::create();
#endif
} /* create() */
#if !efun_defined(has_mxp)
private int has_mxp(object ob) {
return 0;
}
#endif
/**
* 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 _event_info->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", "new-player", "birthday", "council", "friend" });
if (this_object()->query_creator()) {
types += ({ "link-death", "message", "death",
"guild", "delete", "help", "combat-debug", "skill", "quest",
"multiplayer", "bad-password", "club", "debug", "gag",
"alert" });
if (master()->query_lord((string)this_object()->query_name())) {
types += ({ "force", "enter", "dest", "cheat", "xp", "calls",
"cpu", "ftp" });
}
} else if ( load_object(NEWBIEHELPERS_HANDLER)->query_helper_access(this_object())
) {
types += ({ "guild" });
}
if( this_object()->query_guild_ob() == "/std/guilds/witch" ||
this_object()->query_creator() ) {
types += ({ "mockery" });
}
return 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()
*/
nomask 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 = inform_types;
if (!on) {
on = ({ });
}
if (!str) {
str = "";
}
frog = explode(str, " ");
if (!frog) {
frog = ({ });
} else {
frog -= ({ "", 0 });
}
if (!sizeof(frog)) {
/* show status */
if (this_object()->query_property("inform repressed")) {
write("Your informs are currently being repressed.\n");
}
if (sizeof(on)) {
write("$I$5=You will be informed of "+ query_multiple_short(on)+
" events.\n");
}
types -= on;
if (sizeof(types)) {
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" :
this_object()->remove_property("inform repressed");
write("You are now being informed. This is true!\n");
if (sizeof(on)) {
write("$I$5=You will be informed of "+ query_multiple_short(on)+
" events.\n");
} else {
write("$I$5=Although you are not currently being informed of "
"any events.\n");
}
return 1;
case "off":
this_object()->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=I don't know about "+ 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() {
string guild;
if ( this_object()->query_creator() )
return 1;
if(!(guild = (string)this_object()->query_guild_ob())) return 0;
return (int)guild->query_see_octarine();
} /* 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) {
if (query_see_octarine())
return str;
return "";
} /* 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], " ", "");
}
if (!default_colour) {
return "";
}
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, int padding, mixed *args ...) {
string octmess, *bits, bit;
int i;
if (!stringp(str) || str == "") {
return str;
}
if(indent > width / 3) {
indent = 4;
}
if (!_event_info->cur_term) {
if (term_name != "network") {
_event_info->cur_term = term_name;
} else {
_event_info->cur_term = "dumb";
}
}
if (!_event_info->colour_map) {
_event_info->colour_map = (mapping)TERM_HANDLER->set_term_type(_event_info->cur_term, query_property(PLAYER_ALLOW_COLOURED_SOULS));
}
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), "");
}
}
// If someone has mxp then we can do the formatting in a different
// way.
if (is_mxp_enabled()) {
//if (query_name() == "greenland") {
str = terminal_colour(str, _event_info->colour_map);
} else {
str = terminal_colour(str, _event_info->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() {
_event_info->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) {
notify_fail(sprintf("%-=*s", cols,
"Syntax: "+query_verb()+" <term_type>\n"+
"Where term type is one of the following: "+
implode((string *)TERM_HANDLER->query_term_types(), ", ")+
".\nOr set it to \"network\", and the mud will try to "
"figure it out itself.\n"));
return 0;
}
if(str != term_name) {
if (member_array(str, (string *)TERM_HANDLER->query_term_types()) != -1 ||
str == "network") {
if (str != "network") {
_event_info->colour_map = (mapping)TERM_HANDLER->set_term_type(str, query_property(PLAYER_ALLOW_COLOURED_SOULS));
} else { /* Get em to send us our terminal type */
player_connected();
}
term_name = str;
_event_info->cur_term = 0;
write("Ok, terminal type set to "+str+".\n");
return 1;
} else {
notify_fail("No such terminal type as " + str + ".\n");
return 0;
}
} else {
notify_fail("Terminal type unchanged as " + str + ".\n");
return 0;
}
} /* set_term_type() */
/** @ignore yes */
void set_term(string name) {
term_name = name;
_event_info->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) {
_event_info->cur_term = "dumb";
_event_info->colour_map = 0;
}
if (_event_info->colour_map =
(mapping)TERM_HANDLER->set_network_term_type(name, query_property(PLAYER_ALLOW_COLOURED_SOULS))) {
_event_info->cur_term = name;
return 1;
}
} /* set_network_terminal_type() */
/**
* This method resets the colour map information on the player. THis is
* called when some change is made to the terminal data and it needs to
* be updated.
*/
void reset_colour_map() {
_event_info->colour_map = 0;
}
/*
mapping query_debug_colour_map() {
return _event_info->colour_map;
}
*/
/**
* 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", this_object(), "", (: set_our_rows(0) :));
add_command("cols", this_object(), "", (: set_our_cols(0, 0) :));
add_command("rows", this_object(), "<number>", (: set_our_rows($4[0]) :));
add_command("cols", this_object(), "<number>", (: set_our_cols($4[0], 0) :));
add_command("cols", this_object(), "test <number>", (: set_our_cols($4[0], 1) :));
add_command("term", this_object(), "{" +
implode((string *)TERM_HANDLER->query_term_types() +
({ "network" }), "|")+"}", (: set_term_type($4[0]) :));
add_command("term", this_object(), "", (: set_term_type(0) :));
add_command("inform", this_object(), "", (: do_inform(0) :));
add_command("inform", this_object(), "<string>", (: do_inform($4[0]) :));
/* If a liaison or a lord... */
if (this_object()->query_creator()) {
add_command("busy", this_object(), "{on|off}", (: do_busy($4[0]) :));
add_command("busy", this_object(), "<indirect:player>",
(: do_busy_player($1) :));
}
}
/**
* Return function pointer for do_tell_his, for htell only.
*/
function get_htell_func(){
if(file_name(previous_object()) != "/cmds/player/ht_ell")
return 0;
return (:do_tell_his:);
}
/**
* 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]), 0, bit[0], bit[1]);
}
write(ret);
return 1;
} /* do_tell_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) {
if (str == "on") {
_event_info->busy = 1;
} else {
_event_info->busy = 0;
}
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");
_event_info->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(_event_info->busy)) {
_event_info->busy -= ({ 0 });
}
if (pointerp(_event_info->busy) && !sizeof(_event_info->busy)) {
_event_info->busy = 0;
}
return _event_info->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 will set the system to allow friends to punch through
* earmuffs.
* @see check_earmuffs()
* @see query_earmuffs()
*/
void set_allow_friends_earmuffs() {
earmuffs = PLAYER_ALLOW_FRIENDS_EARMUFF;
} /* toggle_earmuffs() */
/**
* This method checks to see if a particular event is earmuffed.
* @param type the type of event to check
* @param person the person who is being checked for the earmuffing of
* @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", this_player()) :) );
* // Do the shout
*/
int check_earmuffs(string type, object person) {
string *on;
if (!earmuffs) {
return 0;
}
on = (string *)this_object()->query_property(PLAYER_EARMUFF_PROP);
if (!on) {
return 0;
}
if (member_array(type, on) == -1) {
return 0;
}
// If they are a friend they punch through
if (!person) {
person = this_player();
}
if (person && earmuffs == PLAYER_ALLOW_FRIENDS_EARMUFF) {
if (is_friend(person->query_name())) {
return 0;
}
}
return 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) {
notify_fail("Rows currently set to " + rows + ".\nrows <number> to set.\n");
return 0;
}
if (val <= 10) {
notify_fail("Invalid number of rows.\n");
return 0;
}
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, int test) {
int cur;
if(!val) {
notify_fail("Columns currently set to " + cols + ".\ncols <number> to set.\n");
return 0;
}
if(val <= 35 || val > 999) {
notify_fail("Invalid column size.\n");
return 0;
}
if (test) {
cur = cols;
cols = val;
/* Watch this.... */
write(implode(allocate(val, (: sprintf("%d", ($1 + 1) % 10) :)), "") + "\n");
call_out((: cols = $(cur) :), 3);
return 1;
}
write("Columns set to " + val + ".\n");
cols = val;
return 1;
} /* set_our_cols() */
/**
* set the colour codes for a given event
*/
void set_my_colours(string event_type, string colour) {
if(colour == "default") {
map_delete(my_colours, event_type);
} else if(colour == "none") {
my_colours[event_type] = "";
} else {
my_colours[event_type] = colour;
}
}
/**
* 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 ) { _event_info->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 = ({ });
} else {
last = sizeof(things) - 1;
}
if ( !_event_info->where ) {
_event_info->where = environment();
}
if (strsrch(message, "$L$") != -1) {
while ( sscanf( message, "%s$L$%s$L$%s", before, middle, after ) == 3 ) {
if (sscanf( middle, "[%s]%s", info, middle) == 2) {
if (info[0..4] == "read:") {
middle = LANGUAGE_HAND->garble_text(info[5..], middle, 0, this_object());
} else {
middle = LANGUAGE_HAND->garble_text_say(middle, info, this_object());
}
}
message = sprintf("%s%s%s", before, middle, after);
}
}
if (strsrch(message, "$R$") != -1) {
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 ) || _event_info->where->query_relative( middle ) ) {
if ( this_object()->query_creator() ) {
message = sprintf("%s%s (%s)%s", before, find_rel(middle, number),
middle, after);
} else {
message = sprintf("%s%s%s", before, find_rel(middle, number),
after);
}
} else {
message = sprintf("%s%s%s%s", before, info, middle, after);
}
}
}
if (strsrch(message, "$r$") != -1) {
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 ) || _event_info->where->query_relative( LENGTHEN[ middle ] ) ) {
if ( this_object()->query_creator() ) {
message = sprintf("%s%s (%s)%s", before,
SHORTEN[find_rel(LENGTHEN[middle], number)],
middle, after);
} else {
message = sprintf("%s%s%s", before,
SHORTEN[find_rel(LENGTHEN[middle], number)],
after);
}
} else {
message = sprintf("%s%s%s%s", before, info, middle, after);
}
}
}
#ifdef DEBUG
if ( this_object()->query_property( "see eemessages" ) )
efun::tell_object( this_object(), "Looking at "+ message +".\n" );
#endif
if (strsrch(message, "$M$") != -1) {
while ( sscanf( message, "%s$M$%s$M$%s", before, middle, after ) == 3 ) {
#ifdef DEBUG
if ( this_object()->query_property( "see eemessages" ) )
efun::tell_object( this_object(), "Expanding "+ middle +".\n" );
#endif
last++;
message = sprintf("%s$%d$%s", before, last, after);
things += ({ ({ }) });
if (strsrch(middle, "$") == -1) {
things[ last ] += ({ middle });
middle = 0;
} else {
while ( sscanf( middle, "$%s$%s", info, middle ) == 2 ) {
#ifdef DEBUG
if ( this_object()->query_property( "see eemessages" ) ) {
efun::tell_object( this_object(), "Found "+ info +".\n" );
}
#endif
things[ last ] += ({ "my_"+ info });
}
}
}
}
if (strsrch(message, "$") != -1) {
after = message;
message = "";
while ( sscanf( after, "%s$%s$%s", before, middle, after ) == 3 ) {
#ifdef DEBUG
if ( this_object()->query_property( "see eemessages" ) )
efun::tell_object( this_object(), "Trying "+ middle +".\n" );
#endif
if ( sscanf( middle, "%s_short:%s", middle, info ) != 2 ) {
message = sprintf("%s%s$%s", message, before, middle);
after = sprintf("$%s", after);
continue;
}
last++;
message = sprintf("%s%s$%d$", message, before, last);
things += ({ ({ sprintf("my_%s_short:%s", middle, 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( this_object() ) ) {
return;
}
if ( strsrch( message, "$" ) == -1 ) {
stuff = ({ message, things });
} else {
stuff = reform_message( message, things );
}
_event_info->where = 0;
if ( !sizeof( _event_info->eemessages ) ) {
_event_info->eemessages = stuff;
} else {
last = sizeof( _event_info->eemessages ) - 2;
if ( ( stuff[ 0 ] == _event_info->eemessages[ last ] ) &&
( sizeof( stuff[ 1 ] ) == 1 ) ) {
if ( sizeof( filter( stuff[ 1 ][ 0 ], (: member_array($1, $2) != -1 :),
_event_info->eemessages[ last + 1 ][ 0 ] ) ) ) {
_event_info->eemessages += stuff;
} else {
_event_info->eemessages[ last + 1 ][ 0 ] += stuff[ 1 ][ 0 ];
}
} else {
_event_info->eemessages += stuff;
}
}
#ifdef DEBUG
if ( this_object()->query_property( "see eemessages" ) )
efun::tell_object( this_object(), sprintf( "%O\n", _event_info->eemessages ) );
#endif
} /* add_message() */
/**
* @ignore yes
* This method is used for the reform_mesage stuff
*/
string get_pretty_short( object thing, int dark ) {
if (dark && environment(thing) != this_object()) {
if (living(thing) && thing->query_race_ob() &&
(thing->query_race_ob())->query_humanoid()) {
return "someone";
} else {
return "something";
}
}
if ( !thing->query_visible( this_object() ) ) {
if (living(thing) && thing->query_race_ob() &&
(thing->query_race_ob())->query_humanoid()) {
return "someone";
} else {
return "something";
}
}
#ifdef USE_ROLE_PLAYING_SHORTS
if(interactive(thing) &&
this_object()->query_role_playing() &&
!this_object()->is_friend(thing->query_name())) {
return thing->query_short_desc();
}
#endif
return (string)thing->pretty_short( this_object() ) +
(string)thing->hide_invis_string();
} /* get_pretty_short() */
/**
* @ignore yes
* This method is used for the reform_mesage stuff
*/
string get_pretty_plural( object thing, int dark ) {
if (dark && environment(thing) != this_object()) {
if (living(thing)) {
return "people";
} else {
return "things";
}
}
if ( !thing->query_visible( this_object() ) ) {
return "things";
}
#ifdef USE_ROLE_PLAYING_SHORTS
if(interactive(thing) &&
this_object()->query_role_playing() &&
!this_object()->is_friend(thing->query_name())) {
return thing->query_plural_desc();
}
#endif
return (string)thing->pretty_plural( this_object() ) +
(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) {
if (objectp(thing) && userp(thing))
return thing->short(0, 0);
return arg;
} /* my_mirror_short() */
/**
* @ignore yes
* This method is used for the reform_mesage stuff
*/
string my_a_short( object thing, string arg, int dark) {
string article;
if (!thing) {
return "something";
}
if (dark && environment(thing) != this_object()) {
// Allow remote shorts to work.
if (living(thing) && thing->query_race_ob() &&
(thing->query_race_ob())->query_humanoid()) {
if (environment(thing) != environment()) {
return "someone";
}
} else {
return "something";
}
}
if ( !objectp( thing ) ) {
return "an unknown object";
}
article = (string)thing->query_determinate( this_object() );
if ( !article ) {
return add_a( (string)this_object()->get_pretty_short( thing, dark ) );
}
return article + (string)this_object()->get_pretty_short( thing, dark );
} /* my_a_short() */
/**
* @ignore yes
* This method is used for the reform_mesage stuff
*/
string my_the_short( object thing, string arg, int dark ) {
string article;
if (dark && environment(thing) != this_object()) {
// Allow remote shorts to work.
if (living(thing) && thing->query_race_ob() &&
(thing->query_race_ob())->query_humanoid()) {
if (environment(thing) == environment()) {
return "someone";
}
} else {
return "something";
}
}
if ( !objectp( thing ) ) {
return "the unknown object";
}
article = (string)thing->query_determinate( this_object() );
if ( !article || ( article == "a " ) || ( article == "an " ) )
return "the "+ (string)this_object()->get_pretty_short( thing, dark );
return article + (string)this_object()->get_pretty_short( thing, dark );
} /* my_the_short() */
int some_more( string word ) {
return sizeof( filter( all_inventory( _event_info->where ),
(: $1->query_plural() == $(word) &&
$1->query_visible(this_object()) :))) > 1;
} /* some_more() */
/**
* @ignore yes
* This method is used for the reform_mesage stuff
*/
string my_one_short( object thing, string arg, int dark ) {
string article, its_plural;
if (dark && environment(thing) != this_object()) {
// Allow remote shorts to work.
if (living(thing) && thing->query_race_ob() &&
(thing->query_race_ob())->query_humanoid()) {
if (environment(thing) == environment()) {
return "someone";
}
} else {
return "something";
}
}
if ( !objectp( thing ) ) {
return "one of the unknown objects";
}
if ( environment( thing ) != environment() ) {
_event_info->where = this_object();
} else {
_event_info->where = environment();
}
/* return my_a_short( thing ); */
article = (string)thing->query_determinate( this_object() );
if ( !article || ( article == "a " ) || ( article == "an " ) ) {
its_plural = (string)this_object()->get_pretty_plural( thing, dark );
if ( some_more( its_plural ) ) {
return "one of the "+ its_plural;
}
return "the "+ (string)this_object()->get_pretty_short( thing, dark );
}
return article + (string)this_object()->get_pretty_short( thing, dark );
} /* my_one_short() */
/**
* @ignore yes
* This method is used for the reform_mesage stuff
*/
string my_poss_short(object thing, string arg, int dark) {
string its_plural;
string article;
string of_whom;
if (dark && environment(thing) != this_object()) {
// Allow remote shorts to work.
if (living(thing) && thing->query_race_ob() &&
(thing->query_race_ob())->query_humanoid()) {
if (environment(thing) == environment()) {
return "someone";
}
} else {
return "something";
}
}
if ( !objectp( thing ) ) {
return "an unknown object";
}
if(living(thing)) {
if (thing == this_object()) {
return "your";
} else {
of_whom = this_object()->get_pretty_short( thing, dark );
if(of_whom[<1] == 's')
of_whom = of_whom + "'";
else
of_whom = of_whom +"'s";
return of_whom;
}
}
_event_info->where = environment( thing );
if ( !_event_info->where ) {
return my_a_short( thing, arg, dark );
}
if ( !living( _event_info->where ) && !_event_info->where->query_corpse() ) {
return my_a_short( thing, arg, dark );
}
#ifdef DEBUG
if ( this_object()->query_property( "see eemessages" ) )
efun::tell_object( this_object(), sprintf( "%O\n", _event_info->had_shorts ) );
#endif
if ( _event_info->where == this_object() ) {
of_whom = "your ";
} else {
if ( member_array( _event_info->where, _event_info->had_shorts ) != -1 ) {
of_whom = (string)_event_info->where->query_possessive() +" ";
} else {
of_whom = my_the_short( _event_info->where, arg, dark );
if(of_whom[<1] == 's') {
of_whom = of_whom + "' ";
} else {
of_whom = of_whom +"'s ";
}
}
}
if ( !article || ( article == "a " ) || ( article == "an " ) ) {
its_plural = (string)this_object()->get_pretty_plural( thing, dark );
if ( some_more( its_plural ) ) {
return "one of "+ of_whom + its_plural;
}
}
return of_whom + (string)this_object()->get_pretty_short( thing, dark );
}
/**
* @ignore yes
* This method is used for the reform_mesage stuff
*/
string my_the_poss_short(object thing, string arg, int dark) {
string its_plural;
string article;
string of_whom;
if (dark && environment(thing) != this_object()) {
// Allow remote shorts to work.
if (living(thing)) {
if (environment(thing) == environment()) {
return "someone's";
}
} else {
return "something's";
}
}
if ( !objectp( thing ) ) {
return "an unknown object's";
}
article = (string)thing->query_determinate(this_object());
if(!article || (article == "a " || article == "an "))
article = "the ";
if(living(thing)) {
if (thing == this_object()) {
return "your";
} else {
of_whom = this_object()->get_pretty_short( thing, dark );
if(of_whom[<1] == 's')
of_whom = of_whom + "'";
else
of_whom = of_whom +"'s";
return article + of_whom;
}
}
_event_info->where = environment( thing );
if ( !_event_info->where ) {
return my_the_short( thing, arg, dark );
}
if ( !living( _event_info->where ) && !_event_info->where->query_corpse()) {
return my_the_short(thing, arg, dark);
}
#ifdef DEBUG
if ( this_object()->query_property( "see eemessages" ) )
efun::tell_object(this_object(), sprintf("%O\n",
_event_info->had_shorts));
#endif
if ( _event_info->where == this_object() ) {
of_whom = "your ";
} else {
if(member_array( _event_info->where, _event_info->had_shorts ) != -1) {
debug_printf("Had shorts");
of_whom = (string)_event_info->where->query_possessive() +" ";
} else {
of_whom = my_the_short(_event_info->where, arg, dark);
if(of_whom[<1] == 's') {
of_whom = of_whom + "' ";
} else {
of_whom = of_whom +"'s ";
}
}
}
its_plural = (string)this_object()->get_pretty_plural( thing, dark );
if(some_more(its_plural))
return "one of "+ article + of_whom + its_plural;
return of_whom + article + this_object()->get_pretty_short(thing, dark);
}
/** @ignore yes */
protected void clear_event_info_had_shorts() { _event_info->had_shorts = ({ }); }
/**
* @ignore yes
* This method is used for the reform_mesage stuff
*/
varargs string calc_shorts( string *short_list, int exact ) {
int i;
int dark;
string list;
string str;
string desc;
object ob;
object *things;
//mapping shorts;
// These next two are tied.
string *descs_str;
mixed *descs_ob;
mixed *parts;
function number;
descs_str = ({ });
descs_ob = ({ });
if (!_event_info->had_shorts) clear_event_info_had_shorts();
if (exact) {
number = (: query_num($1) :);
} else {
number = (: query_num($1, 20) :);
}
if (environment()) {
dark = this_object()->check_dark(environment()->query_light());
}
foreach (str in short_list) {
parts = explode( str, ":" );
if (sizeof(parts) == 2) {
ob = find_object( parts[ 1 ] );
} else if (sizeof(parts) > 2) {
parts[1] = implode(parts[ 1.. ], ":");
ob = find_object( parts[1] );
} else {
ob = 0;
parts += ({ "" });
}
#ifdef DEBUG
if ( this_object()->query_property( "see eemessages" ) )
efun::tell_object( this_object(), sprintf( "%O\n", ob ) );
#endif
if (ob) {
_event_info->had_shorts = ({ ob }) + _event_info->had_shorts;
}
if ( ob == this_object() ) {
if (parts[0] == "my_poss_short" || parts[0] == "my_the_poss_short") {
desc = "your";
} else {
desc = "you";
}
} else if (sizeof(parts) >= 2) {
#ifdef DISBALED
// We were crashing a lot in this call so the code below is a
// workaround attempt to see if we can prevent the crashing.
desc = (string)call_other( this_object(), parts[0], ob, parts[1], dark);
#else
switch(parts[0]) {
case "my_mirror_short":
desc = my_mirror_short(ob, parts[1]);
break;
case "my_a_short":
desc = my_a_short(ob, parts[1], dark);
break;
case "my_the_short":
desc = my_the_short(ob, parts[1], dark);
break;
case "my_one_short":
desc = my_one_short(ob, parts[1], dark);
break;
case "my_poss_short":
desc = my_poss_short(ob, parts[1], dark);
break;
case "my_the_poss_short":
desc = my_the_poss_short(ob, parts[1], dark);
break;
}
#endif
} else {
if (sizeof(parts[0])) {
desc = parts[0];
} else {
desc = "something";
}
}
i = member_array(desc, descs_str);
if (i == -1) {
descs_str += ({ desc });
descs_ob += ({ ({ ob }) });
} else {
descs_ob[i] += ({ ob });
}
}
i = member_array( "you", descs_str );
if ( i != -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 = "";
/*
if (dark) {
if(sizeof(short_list) > 1) {
list = "somethings";
} else {
if(descs_ob[0] && living(descs_ob[0])) {
list = "someone";
} else {
list = "something";
}
}
} else */ {
for ( i = 0; i < sizeof( descs_str ); i++ ) {
things = descs_ob[ i ];
if ( sizeof( things ) == 1 ) {
if (exact) {
if (things[0]) {
list += "one " + things[0]->short();
} else {
list += descs_str[i];
}
} else {
list += descs_str[ i ];
}
} else {
things -= ({ 0 });
if ( sizeof(things) ) {
list += evaluate(number, sizeof(things)) + " " +
this_object()->get_pretty_plural( things[ 0 ], dark );
} else {
list += evaluate(number, sizeof(things)) + " unknown objects";
}
}
if ( i == sizeof( descs_str ) - 1 ) {
continue;
}
if ( i == sizeof( descs_str ) - 2 ) {
list += " and ";
} else {
list += ", ";
}
}
}
return list;
} /* calc_shorts() */
/**
* This method handles doing the indenting of the input string, fitting it
* correctly to the width of the column.
* @param part the column to do stuff with.
*/
string indent_column(string column, int width, int pad) {
int left;
int right;
int space;
string *parts;
string part;
mixed stuff;
string ret;
ret = "";
if ( column[ 0 .. 2 ] != "$I$" ) {
column = "$I$0=$C$"+ column;
}
parts = explode( column, "$C$" );
parts = parts[0..0] + map(parts[1..], (: capitalize($1) :));
parts = explode( implode(parts, ""), "$I$" );
foreach ( part in parts) {
sscanf( part, "%s=%s", stuff, part );
if ( stuff[ 0 ] == ' ' ) {
space = !space;
}
stuff = explode( stuff, "," );
if ( 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;
}
#ifdef DEBUG
if ( this_object()->query_property( "see eemessages" ) )
efun::tell_object( this_object(), part +"\n"+
left +", "+ right +", "+ cols +"\n" );
#endif
// Need to change the terminal_colour efun to allow padding.
if ( left > 0 ) {
ret += fix_string( part, width - right, left, pad);
} else {
ret += fix_string( part, width - right, 0, pad );
}
}
return ret;
}
/**
* 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. The $C$ does capitalization, $I$<num>=
* does indenting of all the following lines of <num> spaces. The
* message automatically has $I$0=$C$ prepended to the message if it
* does not start with $I$. SO if you start a message with $I$ then it
* will not capitalize the first letter of the message.
* @param message the message to fit in
* @return the fitted message
*/
string fit_message( string message ) {
int i;
int j;
int size;
int width;
int ok;
string* columns;
string num;
mixed* stuff;
string ret;
if ( strlen( message ) < 6 ) {
return message;
}
// The way the columns work, there is a <num>= after the column
// definition that handles setting how wide the column is, the
// last column may have the <num> bit blank.
columns = explode( message, "$COLUMN$" );
if (sizeof(columns) > 1) {
stuff = allocate(sizeof(columns), ({ }));
width = cols;
for (i = 0; i < sizeof(columns) - 1; i++) {
if (sscanf(columns[i], "%s=%s", num, columns[i]) == 2) {
size = to_int(num);
} else {
size = 10;
columns[i] += "\nMust specify a column size.\n";
}
width -= size;
stuff[i] = ({ size }) + explode(indent_column(columns[i], size, 1), "\n");
}
stuff[<1] = ({ width }) + explode(indent_column(columns[<1], width, 0), "\n");
// Now merge them together.
j = 1;
ret = "";
do {
// Keep going till the bits run out.
ok = 0;
for (i = 0; i < sizeof(stuff); i++) {
if (sizeof(stuff[i]) > j) {
// Check the colours.
if (sizeof(stuff[i]) > j + 1) {
ok = 1;
}
ret += stuff[i][j];
} else if (i < sizeof(stuff) -1) {
// Need to pad it out.
ret += sprintf("%*s ", stuff[i][0] - 1, "");
}
}
j++;
ret += "\n";
ret = fix_string(ret);
} while (ok);
} else {
ret = indent_column(columns[0], cols, 0);
}
return ret;
} /* fit_message() */
/**
* This method does any extra mxp processing on the output string
* so it will work with the client correctly.
* @param input the input string
* @return the output string with mangling
*/
string fix_for_mxp(string input) {
return replace(input, ({
"&", "&",
"<", "<", ">", ">",
"\n", mxp_next_secure(this_object()) + "<BR>",
"MXP<", "<", "MXP>", ">" }));
}
/**
* 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 ) {
this_object()->more_string( fit_message( message ), bit, 1 );
} else {
// In here we do some mxp processing if need be.
if (has_mxp(this_object())) {
efun::tell_object( this_object(), fix_for_mxp( fit_message( message ) ));
} else {
efun::tell_object( this_object(), fit_message( message ) );
}
}
} /* show_message() */
/**
* 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_event_info_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(_event_info->had_shorts) &&
objectp( _event_info->had_shorts[ 0 ] ) ) {
if ( _event_info->had_shorts[ 0 ]->query_property( "group object" ) ||
_event_info->had_shorts[ 0 ]->group_object() ) {
message = sprintf("%s%s%s", start, verb_plur, finish);
} else {
message = sprintf("%s%s%s", start, verb_sing, finish);
}
} else {
message = sprintf("%s%s%s", 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;
messages = _event_info->eemessages;
_event_info->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 );
}
_event_info->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 ) {
if(message)
message = evaluate_message( reform_message( message, ({ }) ) );
_event_info->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
*/
nomask varargs void event_inform( object, mixed mess, string which,
object thing ) {
string *on, inform_col;
int add_friend_later;
on = inform_types;
if (!on) {
on = ({ });
}
if(this_object()->query_property( "inform repressed" ) || !sizeof( on))
return;
if(thing && thing->query_creator() && !thing->query_visible(this_object()))
return;
if (which == "logon" && is_friend(thing->query_name()) &&
member_array("friend", on) != -1 ) {
which = "friend";
} else if ( ( which == "logon" || which == "link-death" ) &&
PLAYERINFO_HANDLER->query_alerts_for(thing->query_name()) &&
member_array("alert", on) != -1 ) {
which = "alert";
} else if(member_array(which, on) == -1 ) {
return;
}
if(INFORM_COLOURS[which]) {
inform_col = colour_event(which, INFORM_COLOURS[which]);
} else {
inform_col = colour_event(which, INFORM_COLOURS["default"]);
}
if(which == "friend") {
// check for a friend.
add_friend_later = 0;
if(!mess) {
mess = " -- " + query_friend_tag(thing->query_name());
} else if ( stringp( mess ) ) {
mess += " -- " + query_friend_tag(thing->query_name());
} else {
add_friend_later = 1;
}
if (INFORM_COLOURS["friend"]) {
inform_col = colour_event(which, INFORM_COLOURS["friend"]);
}
}
if (functionp(mess)) {
mess = evaluate(mess, this_object());
if ( stringp( mess ) && add_friend_later ) {
mess += "%^RESET%^%^" + inform_col + "%^ -- " +
query_friend_tag(thing->query_name());
}
}
if(which == "logon" && this_object()->query_lord() &&
!check_earmuffs("verbose-logon", this_object()) &&
strsrch(mess, "enters") != -1)
mess += " %^RESET%^%^" + inform_col + "%^" + query_ip_name(thing);
this_object()->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 ) {
this_object()->add_message( implode( words, " " ) +"\n",
({ ({ "my_the_short:"+ file_name( thing ) }) }) );
} else {
this_object()->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(this_object());
this_object()->perception_task(thing);
if ( !thing->query_visible( this_object() ) ) {
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( this_object() ) )
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 ( this_object() == thing ) {
return;
}
// Take dead people out of the attacker list
//this_object()->remove_attacker_list(thing);
if ( ( this_object() == killer ) && stringp( killer_mess ) ) {
this_object()->add_message( replace( killer_mess, "$D",
(string)thing->the_short() ), ({ }) );
print_messages();
return;
}
if ( stringp( room_mess ) ) {
if ( objectp( killer ) ) {
this_object()->add_message( replace( room_mess,
({ "$D", (string)thing->the_short(),
"$K", (string)killer->the_short() }) ), ({ }) );
} else {
this_object()->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, string language) {
if (pointerp(avoid)) {
if (member_array(this_object(), avoid) != -1) {
return ;
}
} else if (avoid == this_object()) {
return ;
}
if (language) {
this_object()->add_message( LANGUAGE_HAND->garble_text_say(str,
language, this_object()), ({ }) );
} else {
this_object()->add_message( str, ({ }) );
}
} /* event_say() */
void event_see( object caller, string words, object thing, mixed avoid ) {
if ( !thing->query_visible( this_object() ) )
return;
event_say( caller, words, avoid, 0 );
} /* event_see() */
/**
* This method is called by the simul_efun 'write'.
* @param caller the calling object
* @param str the string to write, can be a pointer to two strings with a language
* @param language the language to write with
*/
void event_write(object caller, string str, string language) {
if (language) {
this_object()->add_message( LANGUAGE_HAND->garble_text_say(str,
language, this_object()), ({ }) );
} else {
this_object()->add_message( str, ({ }) );
}
print_messages();
} /* event_write() */
/** @ignore yes */
void do_efun_write( string str, string language ) {
event_write( 0, str, language );
}
/**
* 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) {
//str = replace(str, "%^", " ");
if (ob != this_object()) {
if (strsrch(str, "%^") != -1) {
if (!query_property(PLAYER_ALLOW_COLOURED_SOULS)) {
str = strip_colours(str);
}
}
if (sizeof(avoid) > 1 && check_earmuffs("multiple-soul", ob)) {
return ;
}
event_say(ob, colour_event("soul", "") + "$C$" + str + "%^RESET%^", avoid, 0);
} else {
event_write( ob, str + "%^RESET%^", 0 );
}
} /* 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 == this_object() )
return;
this_object()->add_message( colour_event("emote", "%^CYAN%^") + mess + "%^RESET%^", ({ }) );
} /* event_emote() */
/**
* 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
* @param accent the accent object to use
*/
void event_person_say(object ob, string start, string mess, string lang,
string accent) {
string *args, astr, tstr;
int mangle_accent;
if(ob == this_object() )
return;
if (accent) {
if (query_nationality_accent_ob() != accent) {
if (query_mangle_accent()) {
mangle_accent = 2;
} else {
mangle_accent = 1;
}
}
}
if((lang != query_default_language() && lang != "general") ||
(accent && mangle_accent == 1)) {
tstr = start[0..<3];
if(lang != query_default_language() && lang != "general")
tstr += " in " + cap_words(lang);
if(accent && mangle_accent == 1) {
astr = accent->query_accent_name();
if(astr[0] == 'a' || astr[0] == 'e' || astr[0] == 'i' ||
astr[0] == 'o' || astr[0] == 'u')
astr = "an " + astr;
else
astr = "a " + astr;
tstr += " with " + astr + " accent";
}
start = tstr + ": ";
}
if(this_object()->query_property(SHORTHAND_OUTPUT_PROP)) {
mess = LANGUAGES->fix_shorthand(mess);
}
args = LANGUAGE_HAND->garble_say(lang, start, mess, this_object(),
ob, SAY_TYPE);
start = args[ 0 ];
mess = args[ 1 ];
if (accent && mangle_accent == 2) {
mess = accent->garble_say(mess, this_object(), ob, SAY_TYPE,
query_default_language());
}
this_object()->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, int remote) {
if (!pointerp(tell_history)) {
tell_history = ({ });
}
tell_history += ({ ({ start, mess, time(), remote }) });
if (sizeof(tell_history) > MAX_TELL_HIS) {
tell_history = tell_history[1..];
}
} /* add_tell_history() */
/* Modification by Pinkfish 8th of August 1995
* on Grampa's request to remove the nomask.
*/
/**
* 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
* @param lang the language it was spoken in
*/
/* nomask */ void event_person_tell( object ob, string start, string mess) {
int id;
string *args;
string tmp;
if ( this_object()->query_property( "ignoring" ) ) {
if ( member_array( (string)ob->query_name(),
(string *)this_object()->query_property( "ignoring" ) ) != -1 &&
!ob->query_creator()) {
tell_object(ob,this_object()->query_name()+" is ignoring you and "
"will not have heard what you said.\n");
return;
}
}
if(this_object()->query_property(SHORTHAND_OUTPUT_PROP))
mess = LANGUAGES->fix_shorthand(mess);
if (_event_info->busy && (!pointerp(_event_info->busy) ||
member_array(ob, _event_info->busy) == -1)) {
tell_object(ob, this_object()->query_cap_name() +
" is currently busy with "
"someone else, " + this_object()->query_pronoun() +
" has heard this message and will get back to "
"you shortly.\n");
start = "[BUSY] " + start;
}
add_tell_history(start, mess, 0);
tmp = fix_string(replace(colour_event("tell", "%^YELLOW%^"),
"%^", "%%^") +
"%s%s%%^RESET%%^\n",
cols, 5, 0, capitalize(start), mess);
if (has_mxp(this_object())) {
efun::tell_object(this_object(), fix_for_mxp(tmp));
} else {
efun::tell_object(this_object(), tmp);
}
if (userp(this_object()) && interactive( this_object() ) &&
(id = query_idle(this_object())) > TELL_WARN_TIME) {
args = ({ });
if (id/(60*60))
args += ({ (id/(60*60))+" hours" });
if ((id/60)%60)
args += ({ ((id/60)%60)+" minutes" });
if (id%60)
args += ({ (id%60)+" seconds" });
write(this_object()->query_name()+" has been idle for "+
query_multiple_short(args)+".\n");
}
if ( this_object()->query_property( PASSED_OUT ) ) {
write( "Something tells you that $C$"+
(string)this_object()->query_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;
string *args;
blue = "";
if (me == this_object())
return;
if (lang != query_default_language() && lang != "general")
blue = " in " + cap_words(lang);
if(this_object()->query_property(SHORTHAND_OUTPUT_PROP))
mess = LANGUAGES->fix_shorthand(mess);
if ( member_array( this_object(), obs ) == -1) {
if(ob->query_visible(this_object()))
this_object()->add_message( "$I$5=" +
colour_event("whisper", "%^CYAN%^") + "$C$"+
start +
query_multiple_short( obs ) +
".%^RESET%^\n", ({ }) );
} else {
args = LANGUAGE_HAND->garble_say(lang, start, mess, this_object(),
ob, WHISPER_TYPE);
start = args[ 0 ];
mess = args[ 1 ];
if ( sizeof( obs ) == 1 ) {
this_object()->add_message( "$I$5=" +
colour_event("whisper", "%^CYAN%^") +
"$C$"+ start +"you"+
blue +": "+ mess +"%^RESET%^\n", ({ }) );
} else {
this_object()->add_message( "$I$5=" +
colour_event("whisper", "%^CYAN%^") +
"$C$"+ start +
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 ) {
/*string garbler; */
mixed *args;
if ( this_object() == this_player() ) {
return;
}
if ( check_earmuffs( "shout", thing ) ) {
return;
}
if ( !environment() ) {
return;
}
if ( environment()->query_property( "shout zone" ) !=
environment( this_player() )->query_property( "shout zone" ) ) {
return;
}
if (lang != query_default_language() && lang != "general") {
start += " in " + capitalize(lang);
}
//
// Put in a check so you don't see shouts from people you are
// ignoring.
//
if (sizeof(query_ignoring(({ this_player() }))) ) {
return ;
}
args = LANGUAGE_HAND->garble_say(lang, start, mess, this_object(),
thing, SHOUT_TYPE);
start = args[ 0 ];
mess = args[ 1 ];
if(this_object()->query_property(SHORTHAND_OUTPUT_PROP))
mess = LANGUAGES->fix_shorthand(mess);
if ( environment() == environment( this_player() ) ) {
this_object()->add_message( "$I$5=" + colour_event("shout", "") + "$C$"+
start +": "+ mess +"%^RESET%^\n", ({ }) );
return;
}
if ( sizeof( co_ord ) != 3 ) {
return;
}
BROADCASTER->broadcast_event( ({ this_object() }), 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) {
string tmp;
if((this_player() == this_object() ) ||
check_earmuffs("newbie", this_player())) {
return;
}
if (sizeof(query_ignoring(({ this_player() }))) ) {
return ;
}
if(this_object()->query_property(SHORTHAND_OUTPUT_PROP))
message = LANGUAGES->fix_shorthand(message);
tmp = fix_string(replace(colour_event("newbie", "%^MAGENTA%^"),
"%^", "%%^") +
"(newbie)%%^RESET%%^ %s\n",
cols, 5, 0, message);
if (has_mxp(this_object())) {
efun::tell_object(this_object(), fix_for_mxp(tmp));
} else {
efun::tell_object(this_object(), tmp);
}
}
/**
* This event is generated when a newbiehelpers chat event is done.
* @param thing the thing generateing the newbiehelpers chat
* @param message the message the newbiehelper said
*/
void event_newbiehelpers(object thing, string message) {
string tmp;
if((this_player() == this_object() ) ||
check_earmuffs("newbiehelpers", this_player()) ||
!NEWBIEHELPERS_HANDLER->query_helper_access(this_object())) {
return 0;
}
if (sizeof(query_ignoring(({ this_player() }))) ) {
return 0;
}
if(this_object()->query_property(SHORTHAND_OUTPUT_PROP))
message = LANGUAGES->fix_shorthand(message);
tmp = fix_string(replace(colour_event("newbiehelpers",
"%^YELLOW%^"), "%^", "%%^") +
"(newbiehelpers)%%^RESET%%^ %s\n",
cols, 5, 0, message);
if (has_mxp(this_object())) {
efun::tell_object(this_object(), fix_for_mxp(tmp));
} else {
efun::tell_object(this_object(), tmp);
}
}
/**
* This event is generated when a combat message occurs.
* @param thing the thing generateing the event.
* @param message the message to be displayed.
* @param exclude objects not to show this message to.
* @param verbose is the message considered verbose?
*/
void event_combat(object thing, string message, object *exclude, int verbose) {
if(member_array(this_object(), exclude) != -1)
return;
if(verbose && !this_object()->query_verbose("combat"))
return;
this_object()->add_message(colour_event("combat", "%^WHITE%^") + "$C$" +
message + "%^RESET%^", ({ }));
this_object()->print_messages();
}
/**
* 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
* @param channel the creator channel to talk on
*/
nomask void event_creator_tell(object ob, string start, string mess,
int forced, string channel) {
string tmp;
if (!channel)
channel = "cre";
if (ob == this_object() ||
((sizeof(this_object()->query_ignoring( ({ ob }) ) ) ||
check_earmuffs( channel, ob )) && !forced) ||
!this_object()->query_creator()) {
return;
}
// Permissions checks.
if(member_array(channel, this_object()->channel_list()) == -1)
return;
if(this_object()->query_property(SHORTHAND_OUTPUT_PROP))
mess = LANGUAGES->fix_shorthand(mess);
tmp = fix_string(replace(colour_event(channel, "%^CYAN%^"),
"%^", "%%^") +
"(" + channel + ") %s%s%%^RESET%%^\n",
cols, 5, 0, start, mess);
if (has_mxp(this_object())) {
efun::tell_object(this_object(), fix_for_mxp(tmp));
} else {
efun::tell_object(this_object(), tmp);
}
}
/**
* This event is generated when a lord 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
*/
nomask void event_lord_tell( object ob, string start, string mess,
int forced ) {
string tmp;
if ( this_player() == this_object() ) {
HIST_HANDLER->add_lord_history(start, mess);
return;
}
if (ob == this_object()
|| (check_earmuffs("lord", ob) && !forced) ||
!master()->query_lord((string)this_object()->query_name()))
return;
if(this_object()->query_property(SHORTHAND_OUTPUT_PROP))
mess = LANGUAGES->fix_shorthand(mess);
tmp = fix_string(replace(colour_event("lord", "%^YELLOW%^"),
"%^", "%%^") +
"(lord) %s%s%%^RESET%%^\n",
cols, 5, 0, start, mess);
if (has_mxp(this_object())) {
efun::tell_object(this_object(), fix_for_mxp(tmp));
} else {
efun::tell_object(this_object(), tmp);
}
} /* event_lord_tell() */
/**
* 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) {
string tmp;
if (!this_object()->query_creator() || check_earmuffs("inter-creator-tell", 0)
|| this_object() == ig)
return ;
tmp = fix_string("%s@%s%s%s\n", cols, strlen(mname) + strlen(pname) + 3,
0, pname, mname, (emote?" ":": "), mess);
if (has_mxp(this_object())) {
efun::tell_object(this_object(), fix_for_mxp(tmp));
} else {
efun::tell_object(this_object(), tmp);
}
} /* 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) {
string tmp;
if (!this_object()->query_creator() || check_earmuffs("intermud-all", 0)
|| check_earmuffs(channel, 0) || this_object() == ig) {
return ;
}
tmp = fix_string("%%^MAGENTA%%^(%s)%%^RESET%%^ %s%s\n", cols,
strlen(start)+ strlen(channel)+ 3, 0, channel, start,
mess);
if (has_mxp(this_object())) {
efun::tell_object(this_object(), fix_for_mxp(tmp));
} else {
efun::tell_object(this_object(), tmp);
}
} /* 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 ( master()->query_lord( (string)this_object()->query_name() ) )
this_object()->add_message( "$0$ echos to you:\n", ({ ({ "my_the_short:"+
file_name( me ) }) }) );
this_object()->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 == this_object()) {
return;
}
if ( master()->query_lord( (string)this_object()->query_name() ) ) {
this_object()->add_message( "$0$ emotes to all:\n", ({ ({ "my_the_short:"+
file_name( ob ) }) }) );
}
mess = this_object()->colour_event( "emoteall" ) + mess + "%^RESET%^";
this_object()->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 == this_object()) {
return;
}
if ( master()->query_lord( (string)this_object()->query_name() ) ) {
this_object()->add_message( "$0$ echos:\n", ({ ({ "my_the_short:"+
file_name( ob ) }) }) );
}
this_object()->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(this_object(), "] "+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(this_object(), "Setting your network terminal type to \""+
type+"\".\n");
} else {
if (term_name == "network") {
if (!_event_info->last_term || _event_info->last_term != type) {
_event_info->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(this_object(), "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(this_object(), "Your machine told our machine that your "
"terminal has "+height+" rows and "+width+" columns.\n");
}
} /* window_size() */
/**
* This is a callback generated by the driver to deal with mxp related
* stuff.
*/
void mxp_enable() {
// Send down some code to turn on the suboption
efun::tell_object(this_object(),
sprintf("%c%c%c%c%c%c", IAC, SB, TELOPT_MXP, IAC, SE, 0) +
sprintf("%c[1z", 27) +
replace_string(read_file("/doc/login/mxp_setup"), "\n", "") + "\n");
}