/***************************************************************************** * Chatmode.c - Merc-based confrence system. * * * * Full chat-mode setup for Merc based MUDS, or could be used separately if * * you cut and pasted the needed parts from Merc code. * * -- Altrag Dalosein, Lord of the Dragons.. * *****************************************************************************/ /*$Id*/ #if defined(macintosh) #include <types.h> #else #include <sys/types.h> #endif #include <ctype.h> #include <stdio.h> #include <string.h> #include <time.h> #include "merc.h" /* * Externals */ bool check_social args( ( CHAR_DATA *ch, char *command, char *argument ) ); extern int port; /* * Locals */ void start_chat_mode args( ( DESCRIPTOR_DATA *d ) ); void stop_chat_mode args( ( CHAR_DATA *ch ) ); void chat_interp args( ( CHAR_DATA *ch, char *argument ) ); void chat_command args( ( CHAR_DATA *ch, char command, char *argument ) ); #define CD CHAR_DATA * CD get_char_chat args( ( CHAR_DATA *ch, char *argument ) ); #undef CD void send_room_stuff args( ( CHAR_DATA *ch ) ); void init_chat args( ( void ) ); int num_color args( ( CHAR_DATA *ch ) ); char * get_color args( ( CHAR_DATA *ch ) ); struct chat_room { struct chat_room *next; ROOM_INDEX_DATA *pRoom; char *invited; }; void dispose_room( struct chat_room *room ); /* * Use pre-defined stuff, even though all parts aren't used for chat. * This eliminates the need for new functinos that are copies of old * functions, such as ACT or CHECK_SOCIAL. * -- Altrag */ struct chat_room *chat_rooms; struct chat_room *last_chat_room; CHAR_DATA *chat_list; CHAR_DATA *old_chars; void start_chat_mode( DESCRIPTOR_DATA *d ) { CHAR_DATA *ch; if ( !d || !d->character ) return; if ( !chat_rooms ) init_chat( ); if ( d->original ) do_return( d->character, "" ); if ( d->pEdit ) { d->pEdit = NULL; d->editor = 0; } if ( d->inEdit ) { d->inEdit = NULL; d->editin = 0; } if ( d->character == char_list ) char_list = char_list->next; else { for ( ch = char_list; ch; ch = ch->next ) if ( ch->next == d->character ) break; if ( ch ) ch->next = d->character->next; } if ( d->character->was_in_room ) { if ( !d->character->in_room ) char_to_room( d->character, d->character->was_in_room ); } if ( d->character->in_room ) { d->character->was_in_room = d->character->in_room; char_from_room( d->character ); } d->original = d->character; /* * These are the freaks who go link_dead (and lose their descriptor) * from inside chat mode. * -- Altrag */ d->character->next = old_chars; old_chars = d->character; ch = alloc_mem( sizeof( *ch ) ); /* *ch = *d->character;*/ ch->desc = d; ch->name = str_dup( d->character->name ); ch->act = d->character->act; ch->sex = d->character->sex; ch->position = POS_STANDING; ch->hit = 1; ch->max_hit = 1; ch->next = chat_list; chat_list = ch; /* char_to_room( ch, chat_rooms->pRoom );*/ /* * These are still stored on d->original. We don't need them here. * This will also stop any funky residue from the game. * -- Altrag */ /* ch->reply = NULL; ch->affected = NULL; ch->affected2 = NULL; ch->carrying = NULL; ch->master = NULL; ch->leader = NULL; ch->fighting = NULL; ch->hunting = NULL; ch->gspell = NULL; ch->pcdata = NULL; ch->phobia = NULL; ch->in_room = NULL; ch->was_in_room = NULL;*/ d->character = ch; d->connected = CON_CHATTING; char_to_room(ch, chat_rooms->pRoom); act(num_color(ch), "$n &Yhas entered the room.", ch, NULL, NULL, TO_ROOM); send_room_stuff( ch ); return; } void stop_chat_mode( CHAR_DATA *ch ) { DESCRIPTOR_DATA *d; struct chat_room *room; d = ch->desc; act(num_color(ch), "$n &Yhas left the room.", ch, NULL, NULL, TO_ROOM); char_from_room( ch ); if ( ch == chat_list ) chat_list = ch->next; else { CHAR_DATA *gch; for ( gch = chat_list; gch; gch = gch->next ) if ( gch->next == ch ) break; if ( gch ) gch->next = ch->next; } for ( room = chat_rooms; room; room = room->next ) if (!str_prefix( ch->name, room->pRoom->name ) || is_name( ch->name, room->pRoom->name )) break; if ( room ) { if ( room == chat_rooms ) chat_rooms = room->next; else { struct chat_room *rprev; for ( rprev = chat_rooms; rprev; rprev = rprev->next ) if ( rprev->next == room ) break; if ( rprev ) rprev->next = room->next; if ( !rprev->next ) last_chat_room = rprev; } dispose_room(room); } /* save_char_chat( ch );*/ free_ch( ch ); if ( !d ) { return; } if ( !d->original ) { close_socket( d ); return; } d->character = d->original; d->original = NULL; if ( d->character == old_chars ) old_chars = old_chars->next; else { CHAR_DATA *gch; for ( gch = old_chars; gch; gch = gch->next ) if ( gch->next == d->character ) break; if ( gch ) gch->next = d->character->next; } d->character->next = char_list; char_list = d->character; if ( d->character->was_in_room ) char_to_room(d->character, d->character->was_in_room); else char_to_room(d->character, get_room_index(ROOM_VNUM_TEMPLE) ); d->character->was_in_room = NULL; d->connected = CON_PLAYING; do_look(d->character, ""); return; } void chat_interp( CHAR_DATA *ch, char *argument ) { char command = 0; char arg[MAX_STRING_LENGTH]; while ( isspace(*argument) ) ++argument; if ( !*argument ) { send_room_stuff( ch ); return; } if ( *argument == '/' ) { argument++; while (isspace(*argument)) ++argument; command = *argument; argument++; while (isspace(*argument)) ++argument; } if ( command ) { chat_command( ch, command, argument ); return; } argument = one_argument( argument, arg ); if ( arg[0] == '.' && check_social( ch, arg + 1, argument ) ) return; act( num_color(ch), "$n: &G$t $T", ch, arg, argument, TO_ROOM ); send_to_char( AT_RED, "-- &CMessage sent &R--\n\r",ch); return; } void chat_command( CHAR_DATA *ch, char command, char *argument ) { char arg[MAX_STRING_LENGTH]; CHAR_DATA *victim = NULL; struct chat_room *room = NULL; int rcount = 0; arg[0] = '\0'; switch( UPPER(command) ) { case 'Q': stop_chat_mode( ch ); return; case 'P': argument = one_argument(argument, arg); while( isspace(*argument) ) argument++; if ( !*argument ) { send_to_char(C_DEFAULT, "Send what message?\n\r",ch); return; } if ( !(victim = get_char_chat(ch, arg)) ) { send_to_char(C_DEFAULT, "They aren't here.\n\r",ch); return; } sprintf(arg, "(&RPRIV&C)&%s$n: &Y$t", get_color(ch) ); act(AT_LBLUE, arg, ch, argument, victim, (ch == victim ? TO_CHAR : TO_VICT)); act(AT_RED,"-- &CMessage sent only to &$t$N &R--", ch, get_color(ch), victim, TO_CHAR); return; case 'J': argument = one_argument(argument, arg); if ( arg[0] == '\0' ) { bool ToMain = FALSE; if ( !str_prefix( ch->name, ch->in_room->name ) || is_name( ch->name, ch->in_room->name ) ) ToMain = TRUE; act( num_color(ch), "$n &Yhas left the room.", ch, NULL, NULL, TO_ROOM); char_from_room(ch); if ( ToMain ) { char_to_room( ch, chat_rooms->pRoom ); send_room_stuff(ch); act(num_color(ch), "$n &Yhas entered the room.", ch, NULL, NULL, TO_ROOM); return; } for ( room = chat_rooms; room; room = room->next ) { if ( is_name( ch->name, room->pRoom->name ) ) { char_to_room(ch, room->pRoom); send_room_stuff(ch); act( num_color(ch), "$n &Yhas entered the room.", ch, NULL, NULL, TO_ROOM); return; } } room = alloc_mem( sizeof( *room ) ); room->invited = str_dup(""); room->pRoom = alloc_mem( sizeof( *room->pRoom ) ); room->pRoom->name = str_dup( ch->name ); sprintf( arg, "%s'%s room.", ch->name, (ch->name[strlen(ch->name)-1] == 's' ? "" : "s" )); room->pRoom->description = str_dup( arg ); room->pRoom->people = NULL; last_chat_room->next = room; last_chat_room = room; char_to_room(ch, room->pRoom); send_to_char(AT_RED, "!! &CRoom Created &R!!\n\r", ch); send_room_stuff(ch); return; } if ( !str_prefix( arg, ch->name ) || is_name( arg, ch->name ) || !str_cmp( arg, "self" ) ) { chat_command( ch, 'j', "" ); return; } for ( room = chat_rooms; room; room = room->next ) if ( !str_prefix( arg, room->pRoom->name ) || is_name( arg, room->pRoom->name ) ) { act( num_color(ch), "$n &Yhas left the room.",ch, NULL, NULL, TO_ROOM); char_from_room(ch); char_to_room(ch, room->pRoom); send_room_stuff(ch); act( num_color(ch), "$n &Yhas entered the room.",ch,NULL,NULL,TO_ROOM); return; } send_to_char(AT_RED, "!! &WRoom does not exist &R!!\n\r",ch); return; case 'R': for ( room = chat_rooms; room; room = room->next ) { sprintf( arg+strlen(arg), "%-16s&R%s&C\n\r", room->pRoom->name, room->pRoom->description ); rcount++; } sprintf(arg+strlen(arg), "There %s %d active room%s.\n\r", (rcount == 1 ? "is" : "are"), rcount, (rcount == 1 ? "s" : "")); send_to_char( AT_LBLUE, arg, ch ); return; case 'T': for ( room = chat_rooms; room; room = room->next ) if ( room->pRoom == ch->in_room ) break; if ( !room ) return; if ( !is_name( ch->name, room->pRoom->name ) ) { send_to_char(AT_GREEN, "You are not in your room.\n\r",ch); return; } free_string(room->pRoom->description); room->pRoom->description = str_dup( argument ); act(num_color(ch), "$n has changed the topic to '$t'.",ch, argument, NULL, TO_ROOM ); return; case 'W': for ( victim = chat_list; victim; victim = victim->next ) { sprintf(arg+strlen(arg), "&%s%-16s&R%-13s&P%s&C\n\r", get_color(victim), victim->name, victim->in_room->name, victim->in_room->description); rcount++; } sprintf(arg+strlen(arg), "There %s %d %s in the conference.\n\r", (rcount == 1 ? "is" : "are"), rcount, (rcount == 1 ? "person" : "people")); send_to_char(AT_CYAN, arg, ch); return; case 'H': case '?': send_to_char(AT_LBLUE, "/h >his help screen\n\r", ch); send_to_char(AT_LBLUE, "/? &GSame as /h\n\r",ch); send_to_char(AT_LBLUE, "/j[] &GJoin a channel\n\r", ch); send_to_char(AT_LBLUE, "/p<> &GSend a private message\n\r",ch); send_to_char(AT_LBLUE, "/<> &GSame as /p\n\r",ch); send_to_char(AT_LBLUE, "/q &GQuit the conference\n\r",ch); send_to_char(AT_LBLUE, "/r &GList active rooms\n\r",ch); send_to_char(AT_LBLUE, "/t() &GSet room topic\n\r",ch); send_to_char(AT_LBLUE, "/w &GList people in conference\n\r\n\r",ch); send_to_char(AT_LBLUE, "[] &P= channel name; use /r for list\n\r",ch); send_to_char(AT_LBLUE, "<> &P= user name; use /w for list\n\r",ch); send_to_char(AT_LBLUE, "() &P= any character string\n\r",ch); return; default: /* sprintf(arg, "$n: &G/%c$t", command); act( num_color(ch), arg, ch, argument, NULL, TO_ROOM ); send_to_char( AT_RED, "-- &CMessage sent &R--\n\r",ch);*/ sprintf( arg, "%c%s", command, argument ); chat_command( ch, 'p', arg ); return; } return; } CHAR_DATA *get_char_chat( CHAR_DATA *ch, char *name ) { CHAR_DATA *vch; if ( !str_prefix( name, ch->name ) || is_name( name, ch->name ) ) return ch; for ( vch = ch->in_room->people; vch; vch = vch->next_in_room ) if ( !str_prefix( name, vch->name ) || is_name( name, vch->name ) ) return vch; for ( vch = chat_list; vch; vch = vch->next ) if ( !str_prefix( name, vch->name ) || is_name( name, vch->name ) ) return vch; return NULL; } void send_room_stuff( CHAR_DATA *ch ) { int width = 0; CHAR_DATA *vch; if ( !ch->in_room ) return; send_to_char( AT_WHITE, ch->in_room->name, ch ); send_to_char( C_DEFAULT, "\n\r", ch ); if ( ch->in_room->description[0] != '\0' ) send_to_char(AT_YELLOW, ch->in_room->description, ch ); send_to_char( C_DEFAULT, "\n\r", ch ); for ( vch = ch->in_room->people; vch; vch = vch->next_in_room ) { width += strlen( vch->name ); if ( width >= 79 ) { send_to_char(C_DEFAULT, "\n\r", ch ); width = 0; } send_to_char(num_color(vch), vch->name, ch ); send_to_char(C_DEFAULT, " ", ch ); } send_to_char(C_DEFAULT, "\n\r\n\r", ch ); return; } void do_conference( CHAR_DATA *ch, char *argument ) { if ( IS_NPC(ch) && (!ch->desc || !ch->desc->original ) ) return; if ( ch->fighting || ch->position == POS_FIGHTING ) { send_to_char( AT_WHITE, "No way! You are fighting!.\n\r",ch); return; } if ( ch->combat_timer ) { send_to_char(AT_WHITE, "You can't right now.\n\r",ch); return; } if ( ch->position < POS_STUNNED && ch->level < L_APP ) { send_to_char(AT_WHITE, "You're not DEAD yet!\n\r",ch); return; } if ( IS_SET( ch->act, PLR_QUESTOR ) ) REMOVE_BIT( ch->act, PLR_QUESTOR ); ch->hunting = NULL; save_char_obj( ch, FALSE ); start_chat_mode( ch->desc ); } void init_chat( void ) { if ( chat_rooms ) return; chat_rooms = alloc_mem( sizeof( *chat_rooms ) ); chat_rooms->pRoom = alloc_mem(sizeof(*chat_rooms->pRoom)); chat_rooms->invited = str_dup(""); chat_rooms->pRoom->name = str_dup( "Main" ); chat_rooms->pRoom->description = str_dup( "&GEye of the &BS&Ct&Wo&Cr&Bm " "&GMain teleconference channel" ); last_chat_room = chat_rooms; return; } int num_color( CHAR_DATA *ch ) { switch ( ch->sex ) { case SEX_NEUTRAL: return AT_GREEN; case SEX_MALE: return AT_BLUE; case SEX_FEMALE: return AT_RED; } return C_DEFAULT; } char *get_color( CHAR_DATA *ch ) { switch ( ch->sex ) { case SEX_NEUTRAL: return "G"; case SEX_MALE: return "B"; case SEX_FEMALE: return "R"; } return "w"; } /* * Update the chat_list and the old_chars lists. Just kicks out linkdeads * if this becomes too much lag, you could just make a modified version * of check_reconnect in comm.c to check those lists as well as the char_list * list. -- Altrag */ void chat_update( void ) { CHAR_DATA *ch; CHAR_DATA *ch_next; for ( ch = old_chars; ch; ch = ch_next ) { ch_next = ch->next; if ( !ch->desc ) /* i.e. They went into chat but dropped link */ { if ( ch == old_chars ) old_chars = ch->next; else { CHAR_DATA *och; for ( och = old_chars; och; och = och->next ) if ( och->next == ch ) break; if ( och ) och->next = ch->next; } ch->next = char_list; char_list = ch; if ( ch->was_in_room ) char_to_room( ch, ch->was_in_room ); } } for ( ch = chat_list; ch; ch = ch_next ) { ch_next = ch->next; if ( !ch->desc ) { stop_chat_mode( ch ); } } return; } void dispose_room( struct chat_room *room ) { CHAR_DATA *ch; CHAR_DATA *ch_next; for ( ch = room->pRoom->people; ch; ch = ch_next ) { ch_next = ch->next_in_room; chat_command(ch, 'j', "Main"); } free_string(room->pRoom->name); free_string(room->pRoom->description); free_mem(room->pRoom, sizeof(*room->pRoom)); free_string(room->invited); free_mem(room, sizeof(*room)); return; }