#include "path.h"
#include <talker.h>
#include <network.h>
#include <term.h>
#include <playtesters.h>
inherit "/std/effect_shadow";
int do_talker_control(mixed *args, string pattern);
int do_chat(string message, string pattern, string verb);
int handle_status_command(string mode, class talker_args args);
int handle_verbose_command(string mode, class talker_args args);
int handle_history_command(string channel, class talker_args args);
int handle_colour_list(mixed *colour_args, class talker_args args);
int handle_colour_command(string channel, string new_colour, class talker_args args);
int handle_colour_on_off_command( string str_status, class talker_args args);
int handle_colour_toggle_command( class talker_args args);
int handle_echo_command( string mode, class talker_args args);
void init() {
mixed args;
object where;
string channel;
where = environment(player);
#ifdef DEBUG
tell_creator("taffyd", "%O, %O, %O.\n", player, this_player(), where);
#endif
if (!living(where)) {
player->init();
return;
}
args = arg();
if (!classp(args)) {
args = new(class talker_args, status : 0, channels : ({ "one" }),
verbose : 1, local_echo : 0, colour : 0 );
set_arg(args);
}
where->add_command("talker", player,
({ ON_PATTERN,
VERBOSE_PATTERN,
CHANNEL_PATTERN,
DELETE_CHANNEL_PATTERN,
HISTORY_PATTERN,
HISTORY_CHANNEL_PATTERN,
LIST_PATTERN,
LIST_CHANNEL_PATTERN,
SET_COLOUR_PATTERN,
COLOUR_ON_OFF_PATTERN,
COLOUR_LIST,
TOGGLE_COLOUR_PATTERN,
NEW_CHANNEL_PATTERN,
ECHO_PATTERN,
"delete <string'channel'> from <direct:object'talker'>",
"help" }),
(: do_talker_control($4, $5) :) );
where->add_command("chat", player, ({ "<string'message'>",
"into <direct:object>" }), (: do_chat($4[0], $5, $6) :) );
/*
* If they've picked up a talker that's not theirs...
* nuke the channels.
*/
if ( !( EFFECTS + "talker" )->valid( args->channels, where ) ) {
args->channels = ({ "one" });
set_arg(args);
}
foreach (channel in args->channels) {
#ifdef DEBUG
tell_creator("taffyd", "Adding channel. %O.\n", channel);
#endif
where->add_command(lower_case(channel), player,
"<string'message'>", (: do_chat($4[0], $5, $6) :) );
}
player->init();
} /* init() */
int do_talker_control(mixed *args, string pattern) {
class talker_args t_args;
int position;
string full_name;
#ifdef DEBUG
tell_creator("taffyd", "Args to talker control is %O. Pattern is %O.\n",
args, pattern);
#endif
t_args = arg();
switch (pattern) {
case ON_PATTERN:
return handle_status_command(args[0], t_args);
case VERBOSE_PATTERN:
return handle_verbose_command(args[0], t_args);
case CHANNEL_PATTERN:
if ( !t_args->status ) {
tell_object(this_player(), "The eyes are asleep.\n");
return 1;
}
tell_object(this_player(), "You may use the following channels:\n" +
(string)( EFFECTS +"talker" )->channels() +
"You are on channel(s) " +
query_multiple_short( t_args->channels ) + ".\n" );
return 1;
break;
case ECHO_PATTERN:
return handle_echo_command( args[0], t_args );
case "delete <string'channel'> from <direct:object'talker'>":
add_succeeded_mess( ({ "", "" }) );
case DELETE_CHANNEL_PATTERN:
if ( !t_args->status ) {
tell_object(this_player(), "The eyes are asleep.\n");
return 1;
}
full_name = (EFFECTS + "talker")->normalise_name( args[ 0 ] );
if ( !(EFFECTS +"talker")->valid( full_name ) ) {
tell_object(this_player(), "The eyes are not aware of that "
"channel.\n");
return 1;
}
position = member_array(full_name, t_args->channels);
if (position == -1) {
tell_object(this_player(), "The eyes are not listening to "
"that channel.\n");
return 1;
}
if (sizeof(t_args->channels) > 1) {
t_args->channels = t_args->channels[0..position-1] +
t_args->channels[position+1..];
tell_object(this_player(), "The eyes sigh with relief as they "
"can now ignore what happens on "
"channel \"" + full_name + "\".\n");
}
else {
tell_object(this_player(), "The eyes are bored with not listening "
"to any channel at all, and add channel \"one\" to their "
"list again.\n");
t_args->channels = ({ "one" });
}
set_arg(t_args);
break;
case NEW_CHANNEL_PATTERN:
if ( !t_args->status ) {
tell_object(this_player(), "The eyes are asleep.\n");
return 1;
}
full_name = (EFFECTS + "talker")->normalise_name( args[ 0 ] );
(EFFECTS+"talker")->clear_cache(this_player()->query_name());
if ( ( EFFECTS +"talker" )->valid( full_name ) ) {
if ( member_array( full_name, t_args->channels ) != -1 ) {
tell_object(this_player(), "The eyes frown at you; they are "
"already listening to that channel.\n");
return 1;
}
tell_object(this_player(), "You whisper to " +
player->the_short() + " and the eyes add "
"channel \""+ full_name +"\" to the list.\n");
t_args->channels += ({ full_name });
set_arg(t_args);
this_object()->init();
}
else {
tell_object(this_player(), "You whisper to " +
player->the_short() + ", but the eyes "
"refuse to give you that channel.\n");
return 1;
}
break;
case SET_COLOUR_PATTERN:
case SET_COLOUR_FULL_PATTERN:
args[ 0 ] = (EFFECTS+"talker")->normalise_name( args[0] );
return handle_colour_command( args[0], args[1], t_args );
case COLOUR_ON_OFF_PATTERN:
return handle_colour_on_off_command( args[0], t_args );
case TOGGLE_COLOUR_PATTERN:
return handle_colour_toggle_command(t_args);
case COLOUR_LIST:
return handle_colour_list( args, t_args );
break;
case HISTORY_CHANNEL_PATTERN:
args[ 0 ] = (EFFECTS+"talker")->normalise_name( args[0] );
return handle_history_command(args[0], t_args);
case HISTORY_PATTERN:
return handle_history_command("one", t_args);
case LIST_PATTERN:
case LIST_CHANNEL_PATTERN:
if ( !t_args->status ) {
tell_object(this_player(), "The eyes are asleep.\n");
return 1;
}
// add_succeeded_mess("");
if (sizeof(args) == 1) {
args[ 0 ] = (EFFECTS + "talker")->normalise_name( args[ 0 ] );
tell_object(this_player(), "The following people are using "
"channel \""+ args[0] + "\":\n" +
(string)( EFFECTS +"talker" )->list( args[0] ) );
}
else
tell_object(this_player(), "The following people are using "
"talkers:\n" + (string)( EFFECTS +"talker" )->list() );
return 1;
break;
case "help":
default:
write( "Talker commands:\n\n"
"help : give this help file\n"
"on|off : switch talker on or off\n"
"brief : make talker use shorter messages\n"
"verbose : make talker use longer messages\n"
"channels : list valid channels\n"
"<channel> : switch to <channel> if valid\n"
"delete <channel> : switch <channel> off if valid\n"
"list [channel] : list users of the talker\n"
"history [channel] : show chat history of <channel>\n"
"Prefix commands with \"talker\" to use, e.g. "
"\"talker help\". For a more detailed description type "
"\"help talker\".\n" );
break;
}
return 1;
} /* do_talker_control() */
int handle_history_command(string channel, class talker_args args) {
mixed *history;
string result;
if (!args->status) {
tell_object(this_player(), "The eyes are asleep.\n");
return 1;
}
if (!channel)
channel = "one";
if ( !( EFFECTS +"talker" )->valid( channel ) ) {
tell_object(this_player(), "The eyes are not aware of that "
"channel.\n");
return 1;
}
// add_succeeded_mess("");
tell_object(this_player(), "You whisper to " + player->the_short() +
", asking for the last few chats on channel " + channel + ".\n");
history = HIST->query_chat_history(lower_case( channel ) );
if ( !arrayp( history ) || !sizeof( history ) ) {
tell_object(this_player(), "The eyes mutter that nothing has "
"been said on this channel, or it is not being remembered.\n" );
return 1;
}
result = "$P$Channel " + channel + "$P$The eyes mutter about your bad "
"memory.\n";
result += implode(map(history, (: "$I$5=$C$" + $1[0] + $1[1] +
"%^RESET%^" :)), "\n");
tell_object(this_player(), result);
return 1;
} /* handle_history_command() */
string query_colour_status( class talker_args args ) {
if ( !mappingp( args->colour ) ) {
return "off";
}
return args->colour[ "status" ];
} /* query_colour_status() */
int set_colour_status( class talker_args args, string status ) {
if ( !args->colour ) {
args->colour = DEFAULT_COLOUR_SETTINGS;
}
else {
if ( stringp( args->colour ) ) {
args->colour = DEFAULT_COLOUR_WITH( args->colour );
}
}
args->colour[ "status" ] = status;
set_arg( args );
return 1;
} /* set_colour_status() */
int set_channel_colour( class talker_args args, string channel, string colour ) {
if ( !channel || !colour )
return 0;
if ( !mappingp( args->colour ) ) {
args->colour = DEFAULT_COLOUR_WITH(colour);
}
args->colour[ channel ] = colour;
set_arg( args );
return 1;
} /* set_channel_colour() */
varargs string query_channel_colour( class talker_args args, string channel ) {
string colour;
if ( !mappingp( args ) ) {
return DEFAULT_COLOUR;
}
if ( colour = args->colour[ channel ] ) {
return colour;
}
else {
if ( colour = args->colour[ "default" ] ) {
return colour;
}
}
return DEFAULT_COLOUR;
} /* query_channel_colour() */
int handle_colour_toggle_command( class talker_args args ) {
if ( query_colour_status( args ) == "on" ) {
return handle_colour_on_off_command( "off", args );
}
return handle_colour_on_off_command( "on", args );
} /* handle_colour_toggle_command() */
int handle_colour_on_off_command( string str_status, class talker_args args ) {
string status;
status = query_colour_status( args );
switch( str_status ) {
case "on":
if ( status == "on" ) {
add_failed_mess( "Talker colours for $D are already on!\n" );
return -1;
}
set_colour_status( args, "on" );
add_succeeded_mess( ({ "The eyes on $D flash with " +
query_channel_colour( args, "default" ) + "colour%^RESET%^.\n", "" }) );
break;
case "off":
if ( status == "off" ) {
add_failed_mess( "Talker colours for $D have already been turned off!\n" );
return -1;
}
set_colour_status( args, "off" );
add_succeeded_mess( ({ "The eyes on $D blink sadly.\n", "" }) );
break;
default:
args->colour = DEFAULT_COLOUR_SETTINGS;
set_arg( args );
add_succeeded_mess( ({ "Talker colour settings for $D have been reset.\n", "" }) );
}
return 1;
} /* handle_colour_on_off_command() */
mapping create_valid_colours( string my_colours ) {
string *colours;
string *valid_colours = TERM_HANDLER->query_colour_codes();
colours = map( explode( my_colours, " " ),
(: upper_case( $1 ) :) );
return unique_mapping( colours,
(: member_array( $1, $(valid_colours) ) > -1 :) );
} /* create_valid_colours() */
int handle_colour_command(string channel, string new_colour, class talker_args args) {
mapping colours;
string valid_colour;
if ( !(EFFECTS + "talker")->valid( channel ) && channel != "default" ) {
tell_object( this_player(), "You cannot set that "
"channel! Use the channel name \"default\" to set "
"the default channel colour.\n" );
return 1;
}
colours = create_valid_colours( new_colour );
switch( sizeof( colours[ 0 ] ) ) {
case 0:
valid_colour = implode( map( colours[ 1 ], (: "%^" + $1 + "%^" :) ), "" );
set_channel_colour( args, channel, valid_colour );
add_succeeded_mess( ({ "The eyes flash with" + valid_colour +
" colour.%^RESET%^\n", "" }) );
return 1;
case 1:
add_failed_mess( "The colour $I is invalid.\n", colours[ 0 ] );
return -1;
default:
add_failed_mess( "The colours $I are invalid.\n", colours[ 0 ] );
return -1;
}
} /* handle_colour_command() */
int handle_status_command(string mode, class talker_args args) {
switch (mode) {
case "on" :
if ( args->status ) {
tell_object(this_player(), "The eyes are already alert "
"and listening to your every word.\n");
}
else {
tell_object(this_player(), "The eyes open and light up "
"eagerly, then dim to a dull glow.\n");
args->status = 1;
}
break;
case "off" :
if ( !args->status ) {
tell_object(this_player(), "You notice that the eyes are "
"already closed, so you wake them up again "
"in order to tell them to go to sleep.\n");
} else {
tell_object(this_player(), "The eyes slowly lose their "
"glow as they close.\n");
args->status = 0;
}
break;
}
set_arg(args);
return 1;
} /* handle_status_command() */
int handle_verbose_command(string mode, class talker_args args) {
if (!args->status) {
tell_object(this_player(), "The eyes are asleep.\n");
return 1;
}
switch (mode) {
case "brief":
if ( !args->verbose ) {
tell_object(this_player(), "The eyes ignore you completely.\n");
}
else {
tell_object(this_player(), "The eyes seem sad as they dim "
"slightly.\n");
args->verbose = 0;
}
break;
case "verbose":
if ( args->verbose ) {
tell_object(this_player(), "The eyes glitter at you "
"angrily. They already know that they are to "
"be verbose.\n");
}
else {
tell_object(this_player(), "The eyes light up happily for "
"a moment.\n");
args->verbose = 1;
}
break;
}
set_arg(args);
return 1;
} /* handle_verbose_command() */
void receive( string channel, string sender, string text ) {
class talker_args args;
string *ignoring;
object where;
string colour;
if ( !player || !environment( player ) )
return;
where = environment(player);
args = arg();
if (args && !classp(args))
return;
if (!args || !args->status || !living(where))
return;
/*
* If we're not listening to this channel, then don't receive the
* message.
*/
if (member_array(channel, map(args->channels,
(: lower_case($1) :)) ) == -1)
return;
/*
* Creators can their talker messages through the dwchat command,
* they don't need to hear it twice.
*/
if (channel == "intermud" && creatorp(where) )
return;
if ( file_name( previous_object( 1 ) ) == "/secure/cmds/creator/exe_c" ) {
if ( this_player(1) && creatorp(this_player(1)) &&
!this_player(1)->query_property( "talker cheat" ) ) {
user_event( "inform", this_player(1)->query_name() +
" illegally attempted make " + sender + " chat \"" +
text + "\" on channel " + channel, "cheat" );
this_player(1)->add_property( "talker cheat", 1, 3 );
return;
}
}
ignoring = where->query_property("ignoring");
if (ignoring && member_array(lower_case(sender), ignoring) != -1 )
return;
if ( args->verbose ) {
text = ( channel == "one" ? "" : "["+ channel +"] " ) +
sender +"'s wispy voice comes from " +
player->the_short()+", saying: "+ text;
}
else {
text = ( channel == "one" ? "" : "["+ channel +"] " ) +
sender +" wisps: " +text;
}
if ( stringp( args->colour ) ) {
colour = args->colour;
}
if ( mappingp( args->colour ) && query_colour_status( args ) == "on" ) {
if ( !( colour = args->colour[ channel ] ) ) {
if ( !(colour = args->colour[ (EFFECTS + "talker")->normalise_name( channel ) ] ) ) {
colour = args->colour[ "default" ];
/* Incase... */
if ( !colour ) {
colour = DEFAULT_COLOUR;
}
}
}
}
else {
colour = "";
}
tell_object( where, colour + "$I$5=$C$"+ text + "%^RESET%^\n" );
} /* receive() */
int do_chat(string message, string pattern, string verb) {
class talker_args args;
object *things;
string sender;
#ifdef DEBUG
tell_creator("taffyd", "Message is %s, pattern is %s, verb is "
"%s.\n", message, pattern, verb);
#endif
if (pattern == "into <direct:object>") {
add_succeeded_mess("$N whisper$s lovingly to $D.\n");
return 1;
}
args = arg();
if (!args->status) {
tell_object(this_player(), "The eyes are asleep.\n");
return 1;
}
/*
* Strip colours... makes sure players don't "embed" colour
* codes.
*/
while (strsrch(message, "%^") != -1) {
message = replace(message, ({ "%^", "" }) );
}
/*
* If we're not actually listening to this channel, then stop.
*/
if (member_array( verb, map(args->channels,
(: lower_case($1) :)) ) == -1 && verb != "chat") {
return 0;
}
if (this_player()->query_property("gagged")) {
add_failed_mess("You have been gagged! You cannot chat until "
"your gag is removed. Perhaps you should talk to a creator "
"about this.\n");
return 0;
}
if (environment(player) != this_player()) {
add_failed_mess("You're too far away from $D to whisper into it.\n");
return 0;
}
if (verb == "chat") {
if (member_array("one", args->channels) == -1) {
verb = args->channels[0];
}
else {
verb = "one";
}
}
sender = this_player()->query_cap_name();
/* Strip bell characters (*/
message = replace( message, sprintf( "%c", 7 ), "!" );
things = children( PATH + "talker" );
if ( args->local_echo ) {
things -= ({ find_object( PATH + "talker" ) });
}
else {
things -= ({ this_object(), find_object( PATH + "talker" ) });
}
things->receive( verb, sender, message );
if ( verb == "intermud" ) {
/*
* Rudimentary support for Intermud emotes. Not supported on
* the receiving end.
*/
if (message[0] == '@' || message[0] == ':') {
event( users(), "intermud_tell", sender + " ", message[1..], "dwchat" );
message = "$N " + message[1..];
SERVICES_D->eventSendChannel(sender, "discworld-chat", message, 1);
}
else {
/* Intermud "discworld_chat" channel support for players. */
SERVICES_D->eventSendChannel( sender, "discworld-chat", message, 0 );
event( users(), "intermud_tell", sender +": ", message, "dwchat" );
}
}
else {
if ( verb == "playtesters" ) {
if ( !playtesterp(TP) ) {
args->channels -= ({ "playtesters" });
set_arg(args);
add_failed_mess("You're no longer a playtester!\n");
return 0;
}
}
HIST->add_chat_history( verb , sender +" wisped: ", message );
}
tell_object(this_player(), "You whisper into " +
player->the_short() + ".\n");
return 1;
} /* do_chat() */
/**
* @ignore yes
* Tape did this.
*/
void remove_effect_shadow( int i ) {
if ( i == id ) {
if ( player && environment( player ) ) {
// This removes the add_command()s set up by the
// shadow (this_object()) from the guy who's
// carrying the talker. It's a bit hacky, but I
// can't think of any other way to do it.
environment( player )->remove_object2( player, 1 );
}
}
::remove_effect_shadow( i );
} /* remove_effect_shadow() */
/**
* @ignore yes
*/
protected string format_channel_colour( string colour ) {
return colour + lower_case( replace_string(
implode( explode( colour, "%^%^" ), " " ), "%^", "" ) ) + "%^RESET%^";
} /* format_channel_colour() */
int handle_colour_list(mixed *colour_args, class talker_args args) {
string channel;
if (!mappingp(args->colour) || query_colour_status( args ) == "off" ) {
add_failed_mess( "You currently have talker colours disabled. Use "
"\"talker colour on\" to turn them on.\n" );
return 0;
}
foreach( channel in args->channels ) {
if ( args->colour[ channel ] ) {
tell_object( this_player(),
"Channel " + channel + " is " + format_channel_colour(
args->colour[ channel ] ) + ".\n");
}
}
if ( args->colour[ "default" ] ) {
tell_object( this_player(),
"The default talker colour is " + format_channel_colour(
args->colour[ "default" ] ) + ".\n");
}
return 1;
} /* handle_colour_list() */
int handle_echo_command( string mode, class talker_args args) {
int current;
current = args->local_echo;
if ( current ) {
if ( mode == "on" ) {
add_failed_mess( "Talker echo is already on for $D!\n" );
return -1;
}
args->local_echo = 0;
add_succeeded_mess( ({ "The eyes on $D flash slowly.\n", "" }) );
}
else {
if ( mode == "off" ) {
add_failed_mess( "Talker echo is already off for $D!\n" );
return -1;
}
args->local_echo = 1;
add_succeeded_mess( ({ "The eyes on $D flash twice rapidly.\n",
"" }) );
}
set_arg( args );
return 1;
} /* handle_echo_command() */