/***************************************************************************** * DikuMUD (C) 1990, 1991 by: * * Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen, * * and Katja Nyboe. * *---------------------------------------------------------------------------* * MERC 2.1 (C) 1992, 1993 by: * * Michael Chastain, Michael Quan, and Mitchell Tse. * *---------------------------------------------------------------------------* * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider. * * Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, * * gorog, Grishnakh, Nivek, Tricops, and Fireblade. * *---------------------------------------------------------------------------* * SMAUG 1.7 FUSS by: Samson and others of the SMAUG community. * * Their contributions are greatly appreciated. * *---------------------------------------------------------------------------* * LoP (C) 2006, 2007, 2008, 2009 by: the LoP team. * *---------------------------------------------------------------------------* * Player communication module * *****************************************************************************/ #include <ctype.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include "h/mud.h" /* Externals */ void send_friend_info( CHAR_DATA *ch, char *message ); void send_obj_page_to_char( CHAR_DATA *ch, OBJ_INDEX_DATA *idx, char page ); void send_room_page_to_char( CHAR_DATA *ch, ROOM_INDEX_DATA *idx, char page ); void send_page_to_char( CHAR_DATA *ch, MOB_INDEX_DATA *idx, char page ); void increase_gold( CHAR_DATA *ch, int amount ); void decrease_gold( CHAR_DATA *ch, int amount ); bool has_gold( CHAR_DATA *ch, int amount ); void remove_char_from_group( CHAR_DATA *ch ); void free_phistory( PER_HISTORY *phistory ) { if( !phistory ) return; STRFREE( phistory->text ); DISPOSE( phistory ); } /* Types: 0 = tell, 1 = say, 2 = yell, 3 = whisper */ void add_phistory( int type, CHAR_DATA *ch, char *argument ) { PER_HISTORY *phistory, *phistory_next, *phistory_remove = NULL, *history_start = NULL; int y = 0; if( !ch || is_npc( ch ) || !ch->pcdata || !argument || argument[0] == '\0' ) return; if( type < 0 || type > 3 ) return; if( type == 0 ) history_start = ch->pcdata->first_tell; else if( type == 1 ) history_start = ch->pcdata->first_say; else if( type == 2 ) history_start = ch->pcdata->first_yell; else if( type == 3 ) history_start = ch->pcdata->first_whisper; for( phistory = history_start; phistory; phistory = phistory_next ) { phistory_next = phistory->next; if( !phistory_remove ) phistory_remove = phistory; if( ++y >= 20 ) { if( type == 0 ) UNLINK( phistory_remove, ch->pcdata->first_tell, ch->pcdata->last_tell, next, prev ); else if( type == 1 ) UNLINK( phistory_remove, ch->pcdata->first_say, ch->pcdata->last_say, next, prev ); else if( type == 2 ) UNLINK( phistory_remove, ch->pcdata->first_yell, ch->pcdata->last_yell, next, prev ); else if( type == 3 ) UNLINK( phistory_remove, ch->pcdata->first_whisper, ch->pcdata->last_whisper, next, prev ); free_phistory( phistory_remove ); phistory_remove = NULL; y--; } } phistory = NULL; CREATE( phistory, PER_HISTORY, 1 ); smash_tilde( argument ); phistory->text = STRALLOC( argument ); phistory->chtime = current_time; if( type == 0 ) LINK( phistory, ch->pcdata->first_tell, ch->pcdata->last_tell, next, prev ); else if( type == 1 ) LINK( phistory, ch->pcdata->first_say, ch->pcdata->last_say, next, prev ); else if( type == 2 ) LINK( phistory, ch->pcdata->first_yell, ch->pcdata->last_yell, next, prev ); else if( type == 3 ) LINK( phistory, ch->pcdata->first_whisper, ch->pcdata->last_whisper, next, prev ); } LANG_DATA *get_lang( const char *name ) { LANG_DATA *lng; for( lng = first_lang; lng; lng = lng->next ) if( !str_cmp( lng->name, name ) ) return lng; return NULL; } /* percent = percent knowing the language. */ char *translate( int percent, const char *in, const char *name ) { LCNV_DATA *cnv; static char buf[256]; char buf2[256]; const char *pbuf; char *pbuf2 = buf2; LANG_DATA *lng; static char log_buf[MSL]; if( percent > 99 || !str_cmp( name, "common" ) ) { mudstrlcpy( log_buf, in, sizeof( log_buf ) ); return log_buf; } /* If we don't know this language... use "default" */ if( !( lng = get_lang( name ) ) ) if( !( lng = get_lang( "default" ) ) ) { mudstrlcpy( log_buf, in, sizeof( log_buf ) ); return log_buf; } for( pbuf = in; *pbuf; ) { for( cnv = lng->first_precnv; cnv; cnv = cnv->next ) { if( !str_prefix( cnv->old, pbuf ) ) { if( percent && ( rand( ) % 100 ) < percent ) { strncpy( pbuf2, pbuf, cnv->olen ); pbuf2[cnv->olen] = '\0'; pbuf2 += cnv->olen; } else { mudstrlcpy( pbuf2, cnv->lnew, 256 ); pbuf2 += cnv->nlen; } pbuf += cnv->olen; break; } } if( !cnv ) { if( isalpha( *pbuf ) && ( !percent || ( rand( ) % 100 ) > percent ) ) { *pbuf2 = lng->alphabet[LOWER( *pbuf ) - 'a']; if( isupper( *pbuf ) ) *pbuf2 = UPPER( *pbuf2 ); } else *pbuf2 = *pbuf; pbuf++; pbuf2++; } } *pbuf2 = '\0'; for( pbuf = buf2, pbuf2 = buf; *pbuf; ) { for( cnv = lng->first_cnv; cnv; cnv = cnv->next ) if( !str_prefix( cnv->old, pbuf ) ) { mudstrlcpy( pbuf2, cnv->lnew, 256 ); pbuf += cnv->olen; pbuf2 += cnv->nlen; break; } if( !cnv ) *( pbuf2++ ) = *( pbuf++ ); } *pbuf2 = '\0'; return buf; } char *drunk_speech( const char *argument, CHAR_DATA *ch ) { const char *arg = argument; static char buf[MIL * 2]; char buf1[MIL * 2], *txt, *txt1; short drunk; if( is_npc( ch ) || !ch->pcdata ) { mudstrlcpy( buf, argument, sizeof( buf ) ); return buf; } drunk = ch->pcdata->condition[COND_DRUNK]; if( drunk <= 0 ) { mudstrlcpy( buf, argument, sizeof( buf ) ); return buf; } buf[0] = '\0'; buf1[0] = '\0'; if( !argument ) { bug( "%s: NULL argument", __FUNCTION__ ); return (char *)""; } /* * if ( *arg == '\0' ) * return (char *) argument; */ txt = buf; txt1 = buf1; while( *arg != '\0' ) { if( toupper( *arg ) == 'T' ) { if( number_percent( ) < ( drunk * 2 ) ) /* add 'h' after an 'T' */ { *txt++ = *arg; *txt++ = 'h'; } else *txt++ = *arg; } else if( toupper( *arg ) == 'X' ) { if( number_percent( ) < ( drunk * 2 / 2 ) ) { *txt++ = 'c', *txt++ = 's', *txt++ = 'h'; } else *txt++ = *arg; } else if( number_percent( ) < ( drunk * 2 / 5 ) ) /* slurred letters */ { short slurn = number_range( 1, 2 ); short currslur = 0; while( currslur < slurn ) *txt++ = *arg, currslur++; } else *txt++ = *arg; arg++; }; *txt = '\0'; txt = buf; while( *txt != '\0' ) /* Let's mess with the string's caps */ { if( number_percent( ) < ( 2 * drunk / 2.5 ) ) { if( isupper( *txt ) ) *txt1 = tolower( *txt ); else if( islower( *txt ) ) *txt1 = toupper( *txt ); else *txt1 = *txt; } else *txt1 = *txt; txt1++, txt++; }; *txt1 = '\0'; txt1 = buf1; txt = buf; while( *txt1 != '\0' ) /* Let's make them stutter */ { if( *txt1 == ' ' ) /* If there's a space, then there's gotta be a */ { /* along there somewhere soon */ while( *txt1 == ' ' ) /* Don't stutter on spaces */ *txt++ = *txt1++; if( ( number_percent( ) < ( 2 * drunk / 4 ) ) && *txt1 != '\0' ) { short offset = number_range( 0, 2 ); short pos = 0; while( *txt1 != '\0' && pos < offset ) *txt++ = *txt1++, pos++; if( *txt1 == ' ' ) /* Make sure not to stutter a space after */ { /* the initial offset into the word */ *txt++ = *txt1++; continue; } pos = 0; offset = number_range( 2, 4 ); while( *txt1 != '\0' && pos < offset ) { *txt++ = *txt1; pos++; if( *txt1 == ' ' || pos == offset ) /* Make sure we don't stick */ { /* A hyphen right before a space */ txt1--; break; } *txt++ = '-'; } if( *txt1 != '\0' ) txt1++; } } else *txt++ = *txt1++; } *txt = '\0'; return buf; } CMDF( do_say ) { CHAR_DATA *vch; EXT_BV actflags; PER_HISTORY *phistory; char buf[MSL]; int speaking = -1, lang; if( !argument || argument[0] == '\0' ) { if( is_npc( ch ) ) send_to_char( "Say what?\r\n", ch ); else { if( ch->pcdata->first_say ) for( phistory = ch->pcdata->first_say; phistory; phistory = phistory->next ) send_to_char( phistory->text, ch ); else send_to_char( "You haven't seen anyone say anything.\r\n", ch ); } return; } for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( xIS_SET( ch->speaking, lang_array[lang] ) ) { speaking = lang; break; } } if( xIS_SET( ch->in_room->room_flags, ROOM_SILENCE ) ) { send_to_char( "You can't do that here.\r\n", ch ); return; } actflags = ch->act; if( is_npc( ch ) ) xREMOVE_BIT( ch->act, ACT_SECRETIVE ); MOBtrigger = false; for( vch = ch->in_room->first_person; vch; vch = vch->next_in_room ) { char *sbuf = argument; if( vch == ch ) continue; /* Check to see if character is ignoring speaker */ if( is_ignoring( vch, ch ) ) { /* continue unless speaker is an immortal */ if( !is_immortal( ch ) || get_trust( vch ) > get_trust( ch ) ) continue; else { set_char_color( AT_IGNORE, vch ); ch_printf( vch, "You attempt to ignore %s, but are unable to do so.\r\n", ch->name ); } } if( speaking != -1 ) { int speakswell = UMIN( knows_language( vch, speaking ), knows_language( ch, speaking ) ); if( speakswell < 75 ) sbuf = translate( speakswell, argument, lang_names[speaking] ); } sbuf = drunk_speech( sbuf, ch ); act( AT_SAY, "$n says ' $t &D'", ch, sbuf, vch, TO_VICT ); if( !is_npc( vch ) ) { snprintf( buf, sizeof( buf ), "&[say]%s said ' %s &D&[say]'\r\n", capitalize( is_npc( ch ) ? ch->short_descr : ch->name ), sbuf ); add_phistory( 1, vch, buf ); } } ch->act = actflags; act( AT_SAY, "You say ' $T &D'", ch, NULL, drunk_speech( argument, ch ), TO_CHAR ); MOBtrigger = true; if( xIS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { snprintf( buf, sizeof( buf ), "%s: %s", is_npc( ch ) ? ch->short_descr : ch->name, argument ); append_to_file( LOG_FILE, buf ); } mprog_speech_trigger( argument, ch ); if( char_died( ch ) ) return; oprog_speech_trigger( argument, ch ); if( char_died( ch ) ) return; rprog_speech_trigger( argument, ch ); } CMDF( do_whisper ) { CHAR_DATA *victim; PER_HISTORY *phistory; char arg[MIL], buf[MIL], *sbuf; int position; int speaking = -1, lang; argument = one_argument( argument, arg ); if( arg != NULL && arg[0] != '\0' && !is_npc( ch ) && !str_cmp( arg, "off" ) ) { xREMOVE_BIT( ch->act, PLR_WHISPEROFF ); send_to_char( "Whispsers are now turned off.\r\n", ch ); return; } if( arg == NULL || arg[0] == '\0' || !argument || argument[0] == '\0' ) { if( is_npc( ch ) ) send_to_char( "Whisper to whom what?\r\n", ch ); else { if( !ch->pcdata->first_whisper ) send_to_char( "No one has whispered anything to you.\r\n", ch ); else for( phistory = ch->pcdata->first_whisper; phistory; phistory = phistory->next ) send_to_char( phistory->text, ch ); } return; } if( !( victim = get_char_room( ch, arg ) ) ) { send_to_char( "They aren't here.\r\n", ch ); return; } if( ch == victim ) { send_to_char( "You have a nice little chat with yourself.\r\n", ch ); return; } if( !is_npc( victim ) && ( !victim->desc ) ) { send_to_char( "That player is link-dead.\r\n", ch ); return; } if( !is_npc( victim ) && xIS_SET( victim->act, PLR_AFK ) ) { send_to_char( "That player is afk.\r\n", ch ); return; } if( !is_npc( victim ) && xIS_SET( victim->act, PLR_WHISPEROFF ) && ( !is_immortal( ch ) || ( get_trust( ch ) < get_trust( victim ) ) ) ) { act( AT_PLAIN, "$E has $S whispers turned off.", ch, NULL, victim, TO_CHAR ); return; } for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( xIS_SET( ch->speaking, lang_array[lang] ) ) { speaking = lang; break; } } if( !is_npc( ch ) ) xREMOVE_BIT( ch->act, PLR_WHISPEROFF ); if( !is_npc( victim ) && xIS_SET( victim->act, PLR_SILENCE ) ) send_to_char( "That player is silenced. They will receive your message but can't respond.\r\n", ch ); if( victim->desc && victim->desc->connected == CON_EDITING && get_trust( ch ) < PERM_LEADER ) { act( AT_PLAIN, "$E is currently in a writing buffer. Please try again in a few minutes.", ch, 0, victim, TO_CHAR ); return; } /* Check to see if target of tell is ignoring the sender */ if( is_ignoring( victim, ch ) ) { /* If the sender is an imm then they can't be ignored */ if( !is_immortal( ch ) || get_trust( victim ) > get_trust( ch ) ) { set_char_color( AT_IGNORE, ch ); ch_printf( ch, "%s is ignoring you.\r\n", victim->name ); return; } else { set_char_color( AT_IGNORE, victim ); ch_printf( victim, "You attempt to ignore %s, but are unable to do so.\r\n", ch->name ); } } act( AT_WHISPER, "You whisper to $N ' $t &D'", ch, argument, victim, TO_CHAR ); position = victim->position; victim->position = POS_STANDING; sbuf = argument; if( speaking != -1 ) { int speakswell = UMIN( knows_language( victim, speaking ), knows_language( ch, speaking ) ); if( speakswell < 85 ) sbuf = translate( speakswell, argument, lang_names[speaking] ); } sbuf = drunk_speech( sbuf, ch ); act( AT_WHISPER, "$n whispers to you ' $t &D'", ch, sbuf, victim, TO_VICT ); if( !is_npc( victim ) ) { snprintf( buf, sizeof( buf ), "&[whisper]%s whispered to you ' %s &D&[whisper]'\r\n", capitalize( is_npc( ch ) ? ch->short_descr : ch->name ), sbuf ); add_phistory( 3, victim, buf ); } if( !xIS_SET( ch->in_room->room_flags, ROOM_SILENCE ) ) act( AT_WHISPER, "$n whispers something to $N.", ch, NULL, victim, TO_NOTVICT ); victim->position = position; if( xIS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { snprintf( buf, sizeof( buf ), "%s: %s (whisper to) %s.", is_npc( ch ) ? ch->short_descr : ch->name, argument, is_npc( victim ) ? victim->short_descr : victim->name ); append_to_file( LOG_FILE, buf ); } mprog_speech_trigger( argument, ch ); } CMDF( do_tell ) { CHAR_DATA *victim; char arg[MIL], buf[MIL], *sbuf; int position; int speaking = -1, lang; if( xIS_SET( ch->in_room->room_flags, ROOM_SILENCE ) ) { send_to_char( "You can't do that here.\r\n", ch ); return; } if( !is_npc( ch ) && ( xIS_SET( ch->act, PLR_SILENCE ) || xIS_SET( ch->act, PLR_NO_TELL ) ) ) { send_to_char( "You can't do that.\r\n", ch ); return; } argument = one_argument( argument, arg ); if( arg != NULL && arg[0] != '\0' && !is_npc( ch ) && !str_cmp( arg, "off" ) ) { xREMOVE_BIT( ch->act, PLR_TELLOFF ); send_to_char( "Tells are now turned off.\r\n", ch ); return; } if( arg == NULL || arg[0] == '\0' || !argument || argument[0] == '\0' ) { send_to_char( "Tell whom what?\r\n", ch ); return; } if( !( victim = get_char_world( ch, arg ) ) || ( is_npc( victim ) && victim->in_room != ch->in_room ) || ( !not_authed( ch ) && not_authed( victim ) && !is_immortal( ch ) ) ) { send_to_char( "They aren't here.\r\n", ch ); return; } if( ch == victim ) { send_to_char( "You have a nice little chat with yourself.\r\n", ch ); return; } if( not_authed( ch ) && !not_authed( victim ) && !is_immortal( victim ) ) { send_to_char( "They can't hear you because you aren't authorized.\r\n", ch ); return; } if( !is_npc( victim ) && ( !victim->desc ) ) { send_to_char( "That player is link-dead.\r\n", ch ); return; } if( !is_npc( victim ) && xIS_SET( victim->act, PLR_AFK ) ) { send_to_char( "That player is afk.\r\n", ch ); return; } if( !is_npc( victim ) && xIS_SET( victim->act, PLR_TELLOFF ) && ( !is_immortal( ch ) || ( get_trust( ch ) < get_trust( victim ) ) ) ) { act( AT_PLAIN, "$E has $S tells turned off.", ch, NULL, victim, TO_CHAR ); return; } for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( xIS_SET( ch->speaking, lang_array[lang] ) ) { speaking = lang; break; } } if( !is_npc( ch ) ) xREMOVE_BIT( ch->act, PLR_TELLOFF ); if( !is_npc( victim ) && xIS_SET( victim->act, PLR_SILENCE ) ) send_to_char( "That player is silenced. They will receive your message but can't respond.\r\n", ch ); if( ( !is_immortal( ch ) && !is_awake( victim ) ) ) { act( AT_PLAIN, "$E is too tired to discuss such matters with you now.", ch, 0, victim, TO_CHAR ); return; } if( !is_npc( victim ) && xIS_SET( victim->in_room->room_flags, ROOM_SILENCE ) ) { act( AT_PLAIN, "A magic force prevents your message from being heard.", ch, 0, victim, TO_CHAR ); return; } if( victim->desc /* make sure desc exists first -Thoric */ && victim->desc->connected == CON_EDITING && get_trust( ch ) < PERM_LEADER ) { act( AT_PLAIN, "$E is currently in a writing buffer. Please try again in a few minutes.", ch, 0, victim, TO_CHAR ); return; } /* Check to see if target of tell is ignoring the sender */ if( is_ignoring( victim, ch ) ) { /* If the sender is an imm then they can't be ignored */ if( !is_immortal( ch ) || get_trust( victim ) > get_trust( ch ) ) { set_char_color( AT_IGNORE, ch ); ch_printf( ch, "%s is ignoring you.\r\n", victim->name ); return; } else { set_char_color( AT_IGNORE, victim ); ch_printf( victim, "You attempt to ignore %s, but are unable to do so.\r\n", ch->name ); } } ch->retell = victim; /* Bug fix by guppy@wavecomputers.net */ MOBtrigger = false; act( AT_TELL, "You tell $N ' $t &D'", ch, argument, victim, TO_CHAR ); position = victim->position; victim->position = POS_STANDING; sbuf = argument; if( speaking != -1 ) { int speakswell = UMIN( knows_language( victim, speaking ), knows_language( ch, speaking ) ); if( speakswell < 85 ) sbuf = translate( speakswell, argument, lang_names[speaking] ); } sbuf = drunk_speech( sbuf, ch ); act( AT_TELL, "$n tells you ' $t &D'", ch, sbuf, victim, TO_VICT ); if( !is_npc( victim ) ) { snprintf( buf, sizeof( buf ), "&[tell]%s told you ' %s &D&[tell]'\r\n", capitalize( is_npc( ch ) ? ch->short_descr : ch->name ), sbuf ); add_phistory( 0, victim, buf ); } MOBtrigger = true; victim->position = position; victim->reply = ch; if( xIS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { snprintf( buf, sizeof( buf ), "%s: %s (tell to) %s.", is_npc( ch ) ? ch->short_descr : ch->name, argument, is_npc( victim ) ? victim->short_descr : victim->name ); append_to_file( LOG_FILE, buf ); } mprog_speech_trigger( argument, ch ); } CMDF( do_reply ) { CHAR_DATA *victim; char buf[MSL], *sbuf; int position; int speaking = -1, lang; if( xIS_SET( ch->in_room->room_flags, ROOM_SILENCE ) ) { send_to_char( "You can't do that here.\r\n", ch ); return; } if( !is_npc( ch ) && xIS_SET( ch->act, PLR_SILENCE ) ) { send_to_char( "Your message didn't get through.\r\n", ch ); return; } if( !( victim = ch->reply ) ) { send_to_char( "They aren't here.\r\n", ch ); return; } if( !is_npc( victim ) && ( !victim->desc ) ) { send_to_char( "That player is link-dead.\r\n", ch ); return; } if( !is_npc( victim ) && xIS_SET( victim->act, PLR_AFK ) ) { send_to_char( "That player is afk.\r\n", ch ); return; } if( !is_npc( victim ) && xIS_SET( victim->act, PLR_TELLOFF ) && ( !is_immortal( ch ) || ( get_trust( ch ) < get_trust( victim ) ) ) ) { act( AT_PLAIN, "$E has $S tells turned off.", ch, NULL, victim, TO_CHAR ); return; } if( ( !is_immortal( ch ) && !is_awake( victim ) ) || ( !is_npc( victim ) && xIS_SET( victim->in_room->room_flags, ROOM_SILENCE ) ) ) { act( AT_PLAIN, "$E can't hear you.", ch, NULL, victim, TO_CHAR ); return; } if( victim->desc /* make sure desc exists first -Thoric */ && victim->desc->connected == CON_EDITING && get_trust( ch ) < PERM_LEADER ) { act( AT_PLAIN, "$E is currently in a writing buffer. Please try again in a few minutes.", ch, NULL, victim, TO_CHAR ); return; } if( !argument || argument[0] == '\0' ) { act( AT_PLAIN, "What would you like to tell $M?", ch, NULL, victim, TO_CHAR ); return; } for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( xIS_SET( ch->speaking, lang_array[lang] ) ) { speaking = lang; break; } } if( !is_npc( ch ) ) xREMOVE_BIT( ch->act, PLR_TELLOFF ); /* Check to see if the receiver is ignoring the sender */ if( is_ignoring( victim, ch ) ) { /* If the sender is an imm they can't be ignored */ if( !is_immortal( ch ) || get_trust( victim ) > get_trust( ch ) ) { set_char_color( AT_IGNORE, ch ); ch_printf( ch, "%s is ignoring you.\r\n", victim->name ); return; } else { set_char_color( AT_IGNORE, victim ); ch_printf( victim, "You attempt to ignore %s, but are unable to do so.\r\n", ch->name ); } } act( AT_TELL, "You tell $N ' $t &D'", ch, argument, victim, TO_CHAR ); position = victim->position; victim->position = POS_STANDING; sbuf = argument; if( speaking != -1 ) { int speakswell = UMIN( knows_language( victim, speaking ), knows_language( ch, speaking ) ); if( speakswell < 85 ) sbuf = translate( speakswell, argument, lang_names[speaking] ); } sbuf = drunk_speech( sbuf, ch ); act( AT_TELL, "$n tells you ' $t &D'", ch, sbuf, victim, TO_VICT ); if( !is_npc( victim ) ) { snprintf( buf, sizeof( buf ), "&[tell]%s told you ' %s &D&[tell]'\r\n", capitalize( is_npc( ch ) ? ch->short_descr : ch->name ), sbuf ); add_phistory( 0, victim, buf ); } victim->position = position; victim->reply = ch; ch->retell = victim; if( xIS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { snprintf( buf, sizeof( buf ), "%s: %s (reply to) %s.", is_npc( ch ) ? ch->short_descr : ch->name, argument, is_npc( victim ) ? victim->short_descr : victim->name ); append_to_file( LOG_FILE, buf ); } mprog_speech_trigger( argument, ch ); } CMDF( do_retell ) { CHAR_DATA *victim; char buf[MIL], *sbuf; int position; int speaking = -1, lang; if( xIS_SET( ch->in_room->room_flags, ROOM_SILENCE ) ) { send_to_char( "You can't do that here.\r\n", ch ); return; } if( !is_npc( ch ) && ( xIS_SET( ch->act, PLR_SILENCE ) || xIS_SET( ch->act, PLR_NO_TELL ) ) ) { send_to_char( "You can't do that.\r\n", ch ); return; } if( !argument || argument[0] == '\0' ) { send_to_char( "What message do you wish to send?\r\n", ch ); return; } if( !( victim = ch->retell ) ) { send_to_char( "They aren't here.\r\n", ch ); return; } if( !is_npc( victim ) && ( !victim->desc ) ) { send_to_char( "That player is link-dead.\r\n", ch ); return; } if( !is_npc( victim ) && xIS_SET( victim->act, PLR_AFK ) ) { send_to_char( "That player is afk.\r\n", ch ); return; } if( !is_npc( victim ) && xIS_SET( victim->act, PLR_TELLOFF ) && ( !is_immortal( ch ) || ( get_trust( ch ) < get_trust( victim ) ) ) ) { act( AT_PLAIN, "$E has $S tells turned off.", ch, NULL, victim, TO_CHAR ); return; } for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( xIS_SET( ch->speaking, lang_array[lang] ) ) { speaking = lang; break; } } if( !is_npc( ch ) ) xREMOVE_BIT( ch->act, PLR_TELLOFF ); if( !is_npc( victim ) && xIS_SET( victim->act, PLR_SILENCE ) ) send_to_char( "That player is silenced. They will receive your message, but can't respond.\r\n", ch ); if( ( !is_immortal( ch ) && !is_awake( victim ) ) || ( !is_npc( victim ) && xIS_SET( victim->in_room->room_flags, ROOM_SILENCE ) ) ) { act( AT_PLAIN, "$E can't hear you.", ch, 0, victim, TO_CHAR ); return; } if( victim->desc && victim->desc->connected == CON_EDITING && get_trust( ch ) < PERM_LEADER ) { act( AT_PLAIN, "$E is currently in a writing buffer. Please " "try again in a few minutes.", ch, 0, victim, TO_CHAR ); return; } /* check to see if the target is ignoring the sender */ if( is_ignoring( victim, ch ) ) { /* if the sender is an imm then they can't be ignored */ if( !is_immortal( ch ) || get_trust( victim ) > get_trust( ch ) ) { set_char_color( AT_IGNORE, ch ); ch_printf( ch, "%s is ignoring you.\r\n", victim->name ); return; } else { set_char_color( AT_IGNORE, victim ); ch_printf( victim, "You attempy to ignore %s, but " "are unable to do so.\r\n", ch->name ); } } act( AT_TELL, "You tell $N ' $t &D'", ch, argument, victim, TO_CHAR ); position = victim->position; victim->position = POS_STANDING; sbuf = argument; if( speaking != -1 ) { int speakswell = UMIN( knows_language( victim, speaking ), knows_language( ch, speaking ) ); if( speakswell < 85 ) sbuf = translate( speakswell, argument, lang_names[speaking] ); } sbuf = drunk_speech( sbuf, ch ); act( AT_TELL, "$n tells you ' $t &D'", ch, sbuf, victim, TO_VICT ); if( !is_npc( victim ) ) { snprintf( buf, sizeof( buf ), "&[tell]%s told you ' %s &D&[tell]'\r\n", capitalize( is_npc( ch ) ? ch->short_descr : ch->name ), sbuf ); add_phistory( 0, victim, buf ); } victim->position = position; victim->reply = ch; if( xIS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { snprintf( buf, sizeof( buf ), "%s: %s (retell to) %s.", is_npc( ch ) ? ch->short_descr : ch->name, argument, is_npc( victim ) ? victim->short_descr : victim->name ); append_to_file( LOG_FILE, buf ); } mprog_speech_trigger( argument, ch ); } CMDF( do_repeat ) { PER_HISTORY *phistory; if( is_npc( ch ) ) { send_to_char( "Huh?\r\n", ch ); return; } if( !ch->pcdata->first_tell ) { send_to_char( "You haven't been told anything.\r\n", ch ); return; } set_char_color( AT_TELL, ch ); for( phistory = ch->pcdata->first_tell; phistory; phistory = phistory->next ) send_to_char( phistory->text, ch ); } CMDF( do_gemote ) { char buf[MSL], *plast; CHAR_DATA *vch; EXT_BV actflags; if( !is_npc( ch ) && xIS_SET( ch->act, PLR_NO_EMOTE ) ) { send_to_char( "You can't show your emotions.\r\n", ch ); return; } if( !argument || argument[0] == '\0' ) { send_to_char( "GEmote what?\r\n", ch ); return; } actflags = ch->act; if( is_npc( ch ) ) xREMOVE_BIT( ch->act, ACT_SECRETIVE ); for( plast = argument; *plast != '\0'; plast++ ) ; mudstrlcpy( buf, argument, sizeof( buf ) ); if( isalpha( plast[-1] ) ) mudstrlcat( buf, ".", sizeof( buf ) ); MOBtrigger = false; for( vch = first_char; vch; vch = vch->next ) { char *sbuf = buf; if( is_ignoring( vch, ch ) ) { if( !is_immortal( ch ) || get_trust( vch ) > get_trust( ch ) ) continue; else { set_char_color( AT_IGNORE, vch ); ch_printf( vch, "You attempt to ignore %s, but are unable to do so.\r\n", ch->name ); } } act( AT_ACTION, "[GEmote] $n $t", ch, sbuf, vch, ( vch == ch ? TO_CHAR : TO_VICT ) ); } MOBtrigger = true; ch->act = actflags; if( xIS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { snprintf( buf, sizeof( buf ), "%s %s (gemote)", is_npc( ch ) ? ch->short_descr : ch->name, argument ); append_to_file( LOG_FILE, buf ); } } void do_emote( CHAR_DATA *ch, char *argument ) { char buf[MSL], *plast; CHAR_DATA *vch; EXT_BV actflags; if( !is_npc( ch ) && xIS_SET( ch->act, PLR_NO_EMOTE ) ) { send_to_char( "You can't show your emotions.\r\n", ch ); return; } if( !argument || argument[0] == '\0' ) { send_to_char( "Emote what?\r\n", ch ); return; } actflags = ch->act; if( is_npc( ch ) ) xREMOVE_BIT( ch->act, ACT_SECRETIVE ); for( plast = argument; *plast != '\0'; plast++ ) ; mudstrlcpy( buf, argument, sizeof( buf ) ); if( isalpha( plast[-1] ) ) mudstrlcat( buf, ".", sizeof( buf ) ); MOBtrigger = false; for( vch = ch->in_room->first_person; vch; vch = vch->next_in_room ) { char *sbuf = buf; if( is_ignoring( vch, ch ) ) { if( !is_immortal( ch ) || get_trust( vch ) > get_trust( ch ) ) continue; else { set_char_color( AT_IGNORE, vch ); ch_printf( vch, "You attempt to ignore %s, but are unable to do so.\r\n", ch->name ); } } act( AT_ACTION, "$n $t", ch, sbuf, vch, ( vch == ch ? TO_CHAR : TO_VICT ) ); } MOBtrigger = true; ch->act = actflags; if( xIS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) ) { snprintf( buf, sizeof( buf ), "%s %s (emote)", is_npc( ch ) ? ch->short_descr : ch->name, argument ); append_to_file( LOG_FILE, buf ); } } void do_quit( CHAR_DATA *ch, char *argument ) { char log_buf[MSL]; int level; if( !ch ) return; if( is_npc( ch ) ) { send_to_char( "Mobiles can't just quit when they want to!\r\n", ch ); return; } if( ch->position == POS_FIGHTING || ch->position == POS_EVASIVE || ch->position == POS_DEFENSIVE || ch->position == POS_AGGRESSIVE || ch->position == POS_BERSERK ) { set_char_color( AT_RED, ch ); send_to_char( "No way! You're fighting.\r\n", ch ); return; } if( ch->position < POS_STUNNED ) { set_char_color( AT_BLOOD, ch ); send_to_char( "You're not DEAD yet.\r\n", ch ); return; } if( get_timer( ch, TIMER_RECENTFIGHT ) > 0 && !is_immortal( ch ) ) { set_char_color( AT_RED, ch ); send_to_char( "Your adrenaline is pumping too hard to quit now!\r\n", ch ); return; } if( ch->wimpy > ( int )( ch->max_hit / 2.25 ) ) do_wimpy( ch, (char *)"max" ); set_char_color( AT_WHITE, ch ); send_to_char( "Your surroundings begin to fade as a mystical swirling vortex of colors\r\nenvelops your body... When you come to, things aren't as they were.\r\n\r\n", ch ); act( AT_SAY, "A strange voice says, 'We await your return, $n...'", ch, NULL, NULL, TO_CHAR ); act( AT_BYE, "$n has left the game.", ch, NULL, NULL, TO_CANSEE ); set_char_color( AT_GRAY, ch ); level = get_trust( ch ); snprintf( log_buf, sizeof( log_buf ), "%s has quit (Room %d).", ch->name, ( ch->in_room ? ch->in_room->vnum : 0 ) ); { char message[MSL]; snprintf( message, sizeof( message ), "%s has quit.", ch->name ); send_friend_info( ch, message ); } quitting_char = ch; save_char_obj( ch ); quitting_char = ch; if( sysdata.save_pets && ch->pcdata->first_pet ) { CHAR_DATA *pet, *pet_next; for( pet = ch->pcdata->first_pet; pet; pet = pet_next ) { pet_next = pet->next_pet; act( AT_BYE, "$N follows $S master into the Void.", ch, NULL, pet, TO_ROOM ); extract_char( pet, true ); } } saving_char = NULL; quitting_char = NULL; extract_char( ch, true ); log_string_plus( log_buf, LOG_COMM, level ); } void send_ansi_title( CHAR_DATA *ch ) { FILE *rpfile; int num = 0; char BUFF[MSL * 2]; if( ( rpfile = fopen( ANSITITLE_FILE, "r" ) ) ) { while( ( BUFF[num] = fgetc( rpfile ) ) != EOF ) num++; fclose( rpfile ); BUFF[num] = 0; write_to_buffer( ch->desc, BUFF, num ); } } void send_ascii_title( CHAR_DATA *ch ) { FILE *rpfile; int num = 0; char BUFF[MSL]; if( ( rpfile = fopen( ASCTITLE_FILE, "r" ) ) ) { while( ( BUFF[num] = fgetc( rpfile ) ) != EOF ) num++; fclose( rpfile ); BUFF[num] = 0; write_to_buffer( ch->desc, BUFF, num ); } } CMDF( do_ansi ) { if( !ch || is_npc( ch ) ) return; xTOGGLE_BIT( ch->act, PLR_ANSI ); if( xIS_SET( ch->act, PLR_ANSI ) ) { set_char_color( AT_WHITE + AT_BLINK, ch ); send_to_char( "ANSI ON!!!\r\n", ch ); } else send_to_char( "ANSI OFF!!!\r\n", ch ); } CMDF( do_save ) { if( !ch || is_npc( ch ) ) return; if( ch->level < 2 ) { send_to_char( "&BYou must be at least second level to save.\r\n", ch ); return; } wait_state( ch, 2 ); /* For big muds with save-happy players, like RoD */ update_aris( ch ); /* update char affects and RIS */ save_char_obj( ch ); saving_char = NULL; send_to_char( "Saved...\r\n", ch ); } /* * Something from original DikuMUD that Merc yanked out. * Used to prevent following loops, which can cause problems if people * follow in a loop through an exit leading back into the same room * (Which exists in many maze areas) -Thoric */ bool circle_follow( CHAR_DATA *ch, CHAR_DATA *victim ) { CHAR_DATA *tmp; for( tmp = victim; tmp; tmp = tmp->master ) if( tmp == ch ) return true; return false; } CMDF( do_dismiss ) { CHAR_DATA *victim; if( !argument || argument[0] == '\0' ) { send_to_char( "Dismiss whom?\r\n", ch ); return; } if( !( victim = get_char_room( ch, argument ) ) ) { send_to_char( "They aren't here.\r\n", ch ); return; } if( ( IS_AFFECTED( victim, AFF_CHARM ) ) && ( is_npc( victim ) ) && ( victim->master == ch ) ) { stop_hating( victim, NULL, true ); stop_hunting( victim, NULL, true ); stop_fearing( victim, NULL, true ); stop_follower( victim ); act( AT_ACTION, "$n dismisses $N.", ch, NULL, victim, TO_NOTVICT ); act( AT_ACTION, "You dismiss $N.", ch, NULL, victim, TO_CHAR ); } else send_to_char( "You can't dismiss them.\r\n", ch ); } CMDF( do_follow ) { CHAR_DATA *victim; if( !argument || argument[0] == '\0' ) { send_to_char( "Follow whom?\r\n", ch ); return; } if( !( victim = get_char_room( ch, argument ) ) ) { send_to_char( "They aren't here.\r\n", ch ); return; } if( IS_AFFECTED( ch, AFF_CHARM ) && ch->master ) { act( AT_PLAIN, "But you'd rather follow $N!", ch, NULL, ch->master, TO_CHAR ); return; } if( victim == ch ) { if( !ch->master ) { send_to_char( "You already follow yourself.\r\n", ch ); return; } if( ch->group ) remove_char_from_group( ch ); stop_follower( ch ); return; } if( ( ch->level - victim->level < -10 || ch->level - victim->level > 10 ) && !is_avatar( ch ) && !( ch->level < 15 && !is_npc( victim ) && victim->pcdata->council && !str_cmp( victim->pcdata->council->name, "Newbie Council" ) ) ) { send_to_char( "You aren't of the right caliber to follow.\r\n", ch ); return; } if( circle_follow( ch, victim ) ) { send_to_char( "Following in loops is not allowed... sorry.\r\n", ch ); return; } if( ch->master ) stop_follower( ch ); if( ch->group ) remove_char_from_group( ch ); add_follower( ch, victim ); } void add_follower( CHAR_DATA *ch, CHAR_DATA *master ) { CHAR_DATA *pet; int count = 0; if( ch->master ) { bug( "%s: non-null master.", __FUNCTION__ ); return; } /* Support for saving pets --Shaddai */ if( is_npc( ch ) && xIS_SET( ch->act, ACT_PET ) && !is_npc( master ) ) { for( pet = master->pcdata->first_pet; pet; pet = pet->next_pet ) count++; if( count < sysdata.maxpet ) LINK( ch, master->pcdata->first_pet, master->pcdata->last_pet, next_pet, prev_pet ); else { if( can_see( master, ch ) ) act( AT_ACTION, "$n can't follow you because you already have to many pets.", ch, NULL, master, TO_VICT ); act( AT_ACTION, "You can't follow $N because $E already has to many pets.", ch, NULL, master, TO_CHAR ); return; } } ch->master = master; ch->leader = NULL; if( can_see( master, ch ) ) act( AT_ACTION, "$n now follows you.", ch, NULL, master, TO_VICT ); act( AT_ACTION, "You now follow $N.", ch, NULL, master, TO_CHAR ); } void stop_follower( CHAR_DATA *ch ) { if( !ch->master ) { bug( "%s: null master.", __FUNCTION__ ); return; } if( is_npc( ch ) && !is_npc( ch->master ) ) { CHAR_DATA *pet; for( pet = ch->master->pcdata->first_pet; pet; pet = pet->next_pet ) { if( pet != ch ) continue; UNLINK( ch, ch->master->pcdata->first_pet, ch->master->pcdata->last_pet, next_pet, prev_pet ); } } if( IS_AFFECTED( ch, AFF_CHARM ) ) { xREMOVE_BIT( ch->affected_by, AFF_CHARM ); affect_strip( ch, gsn_charm_person ); if( !is_npc( ch->master ) ) ch->master->pcdata->charmies--; } if( can_see( ch->master, ch ) ) if( is_npc( ch->master ) && !is_immortal( ch ) && is_immortal( ch->master ) ) act( AT_ACTION, "$n stops following you.", ch, NULL, ch->master, TO_VICT ); act( AT_ACTION, "You stop following $N.", ch, NULL, ch->master, TO_CHAR ); ch->master = NULL; ch->leader = NULL; } void die_follower( CHAR_DATA *ch ) { CHAR_DATA *fch; if( ch->master ) stop_follower( ch ); ch->leader = NULL; for( fch = first_char; fch; fch = fch->next ) { if( fch->master == ch ) stop_follower( fch ); if( fch->leader == ch ) fch->leader = fch; } } CMDF( do_order ) { char arg[MIL], argbuf[MIL], log_buf[MSL]; CHAR_DATA *victim, *och, *och_next; bool found, fAll; mudstrlcpy( argbuf, argument, sizeof( argbuf ) ); argument = one_argument( argument, arg ); if( arg == NULL || !argument || arg[0] == '\0' || argument[0] == '\0' ) { send_to_char( "Order whom to do what?\r\n", ch ); return; } if( IS_AFFECTED( ch, AFF_CHARM ) ) { send_to_char( "You feel like taking, not giving, orders.\r\n", ch ); return; } if( strstr( argument, "mp" ) ) { send_to_char( "No.. I don't think so.\r\n", ch ); return; } if( !str_cmp( arg, "all" ) ) { fAll = true; victim = NULL; } else { fAll = false; if( !( victim = get_char_room( ch, arg ) ) ) { send_to_char( "They aren't here.\r\n", ch ); return; } if( victim == ch ) { send_to_char( "Aye aye, right away!\r\n", ch ); return; } if( !IS_AFFECTED( victim, AFF_CHARM ) || victim->master != ch ) { send_to_char( "Do it yourself!\r\n", ch ); return; } } found = false; for( och = ch->in_room->first_person; och; och = och_next ) { och_next = och->next_in_room; if( IS_AFFECTED( och, AFF_CHARM ) && och->master == ch && ( fAll || och == victim ) && !is_immortal( och ) ) { found = true; act( AT_ACTION, "$n orders you to '$t'.", ch, argument, och, TO_VICT ); interpret( och, argument ); } } if( found ) { snprintf( log_buf, sizeof( log_buf ), "%s: order %s.", ch->name, argbuf ); log_string_plus( log_buf, LOG_NORMAL, get_trust( ch ) ); send_to_char( "Ok.\r\n", ch ); wait_state( ch, 12 ); } else send_to_char( "You have no followers here.\r\n", ch ); } GROUP_DATA *create_group( CHAR_DATA *ch ) { GROUP_DATA *group; if( !ch ) return NULL; if( ch->group ) return NULL; CREATE( group, GROUP_DATA, 1 ); if( !group ) { bug( "%s: group is NULL after CREATE.", __FUNCTION__ ); return NULL; } group->leader = NULL; group->first_char = NULL; group->last_char = NULL; return group; } void free_group( GROUP_DATA *group ) { CHAR_DATA *ch, *ch_next; if( !group ) return; for( ch = group->first_char; ch; ch = ch_next ) { ch_next = ch->next_in_group; if( ch == group->leader ) group->leader = NULL; UNLINK( ch, group->first_char, group->last_char, next_in_group, prev_in_group ); ch->group = NULL; send_to_char( "Your group has been disbanded.\r\n", ch ); } } void add_char_to_group( GROUP_DATA *group, CHAR_DATA *ch ) { if( !ch ) return; if( ch->group ) { send_to_char( "You are already in a group.\r\n", ch ); return; } if( !group ) group = create_group( ch ); if( !group ) { bug( "%s: no group to add %s to.", __FUNCTION__, ch->name ); return; } LINK( ch, group->first_char, group->last_char, next_in_group, prev_in_group ); ch->group = group; if( !group->leader ) group->leader = ch; send_to_char( "You've been added to the group.\r\n", ch ); } void remove_char_from_group( CHAR_DATA *ch ) { GROUP_DATA *group; if( !( group = ch->group ) ) return; UNLINK( ch, group->first_char, group->last_char, next_in_group, prev_in_group ); ch->group = NULL; if( group->leader == ch ) group->leader = group->first_char; send_to_char( "You've been removed from the group.\r\n", ch ); if( !group->first_char || group->first_char == group->last_char ) free_group( group ); } bool is_same_group( CHAR_DATA *ach, CHAR_DATA *bch ) { if( ach && bch && ach->group && bch->group && ach->group == bch->group ) return true; if( ach == bch ) return true; return false; } void free_all_groups( void ) { GROUP_DATA *group, *group_next; for( group = first_group; group; group = group_next ) { group_next = group->next; free_group( group ); } } CMDF( do_group ) { CHAR_DATA *victim, *gch; GROUP_DATA *group; char buf[MSL]; if( !argument || argument[0] == '\0' ) { set_char_color( AT_GROUP, ch ); if( !( group = ch->group ) ) { send_to_char( "You are not currently in a group.\r\n", ch ); return; } ch_printf( ch, "\r\nFollowing &[group2]%-12.12s &[group][ HP ] [ MP/BP ] [ Moves ] [ MST ]\r\n", PERS( group->leader, ch ) ); for( gch = group->first_char; gch; gch = gch->next_in_group ) { if( is_same_group( gch, ch ) ) { set_char_color( AT_DGREEN, ch ); if( gch->alignment > 750 ) snprintf( buf, sizeof( buf ), "%s", " G" ); else if( gch->alignment > 350 ) snprintf( buf, sizeof( buf ), "%s", "-G" ); else if( gch->alignment > 150 ) snprintf( buf, sizeof( buf ), "%s", "+N" ); else if( gch->alignment > -150 ) snprintf( buf, sizeof( buf ), "%s", " N" ); else if( gch->alignment > -350 ) snprintf( buf, sizeof( buf ), "%s", "-N" ); else if( gch->alignment > -750 ) snprintf( buf, sizeof( buf ), "%s", "+E" ); else snprintf( buf, sizeof( buf ), "%s", " E" ); ch_printf( ch, "&[group][&[group2]%-2d %2.2s %3.3s %3.3s&[group]]&[group2] ", gch->level, is_npc( gch ) ? "NA" : buf, is_npc( gch ) ? "Mob" : dis_race_name( gch->race ), is_npc( gch ) ? "Mob" : dis_main_class_name( gch ) ); ch_printf( ch, "%-12.12s ", capitalize( PERS( gch, ch ) ) ); if( !is_npc( gch ) && gch->hit < gch->max_hit / 4 ) set_char_color( AT_DANGER, ch ); else if( !is_npc( gch ) && gch->hit < gch->max_hit / 2.5 ) set_char_color( AT_HURT, ch ); else set_char_color( AT_GROUP2, ch ); if( !is_npc( gch ) ) ch_printf( ch, " %3d%% ", ( gch->hit > 0 ) ? ( ( 100 * gch->hit ) / gch->max_hit ) : 0 ); else ch_printf( ch, " %4s ", "-NA-" ); if( !is_npc( gch ) && is_vampire( gch ) ) set_char_color( AT_BLOOD, ch ); else set_char_color( AT_GROUP2, ch ); if( !is_npc( gch ) ) ch_printf( ch, " %3d%% ", ( gch->mana > 0 ) ? ( ( 100 * gch->mana ) / gch->max_mana ) : 0 ); else ch_printf( ch, " %4s ", "-NA-" ); if( !is_npc( gch ) && gch->move < gch->max_move / 2.5 ) set_char_color( AT_YELLOW, ch ); else set_char_color( AT_GROUP2, ch ); if( !is_npc( gch ) ) ch_printf( ch, " %3d%%", ( gch->move > 0 ) ? ( ( 100 * gch->move ) / gch->max_move ) : 0 ); else ch_printf( ch, " %4s", "-NA-" ); if( !is_npc( gch ) && ( gch->mental_state < -25 || gch->mental_state > 25 ) ) set_char_color( AT_YELLOW, ch ); else set_char_color( AT_GROUP2, ch ); ch_printf( ch, " %3.3s", is_npc( gch ) ? "-NA" : gch->mental_state > 75 ? "+++" : gch->mental_state > 50 ? "=++" : gch->mental_state > 25 ? "==+" : gch->mental_state > -25 ? "===" : gch->mental_state > -50 ? "-==" : gch->mental_state > -75 ? "--=" : "---" ); send_to_char( "\r\n", ch ); } } return; } if( !strcmp( argument, "disband" ) ) { if( ch->leader || ch->master ) { send_to_char( "You can't disband a group if you're following someone.\r\n", ch ); return; } if( !ch->group ) { send_to_char( "You can't disband a group if you aren't in one.\r\n", ch ); return; } free_group( ch->group ); return; } if( !strcmp( argument, "all" ) ) { int count = 0; if( !ch->group ) add_char_to_group( ch->group, ch ); for( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if( ch != gch && can_see( ch, gch ) && gch->master == ch && !ch->master && !ch->leader && abs( ch->level - gch->level ) < 9 && !is_same_group( gch, ch ) && is_pkill( ch ) == is_pkill( gch ) ) { gch->leader = ch; count++; add_char_to_group( ch->group, gch ); } } if( count == 0 ) { send_to_char( "You have no eligible group members.\r\n", ch ); if( ch->group && ch->group->first_char == ch->group->last_char ) free_group( ch->group ); } else { act( AT_ACTION, "$n groups $s followers.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You group your followers.\r\n", ch ); } return; } if( !( victim = get_char_room( ch, argument ) ) ) { send_to_char( "They aren't here.\r\n", ch ); return; } if( ch->master || ( ch->leader && ch->leader != ch ) ) { send_to_char( "But you're following someone else!\r\n", ch ); return; } if( victim->master != ch && ch != victim ) { act( AT_PLAIN, "$N isn't following you.", ch, NULL, victim, TO_CHAR ); return; } if( victim == ch ) { act( AT_PLAIN, "You can't group yourself.", ch, NULL, victim, TO_CHAR ); return; } if( is_same_group( victim, ch ) && ch != victim ) { victim->leader = NULL; remove_char_from_group( victim ); act( AT_ACTION, "$n removes $N from $s group.", ch, NULL, victim, TO_NOTVICT ); act( AT_ACTION, "$n removes you from $s group.", ch, NULL, victim, TO_VICT ); act( AT_ACTION, "You remove $N from your group.", ch, NULL, victim, TO_CHAR ); return; } if( ch->level - victim->level < -8 || ch->level - victim->level > 8 || ( is_pkill( ch ) != is_pkill( victim ) ) ) { act( AT_PLAIN, "$N can't join $n's group.", ch, NULL, victim, TO_NOTVICT ); act( AT_PLAIN, "You can't join $n's group.", ch, NULL, victim, TO_VICT ); act( AT_PLAIN, "$N can't join your group.", ch, NULL, victim, TO_CHAR ); return; } victim->leader = ch; if( !ch->group ) add_char_to_group( ch->group, ch ); add_char_to_group( ch->group, victim ); act( AT_ACTION, "$N joins $n's group.", ch, NULL, victim, TO_NOTVICT ); act( AT_ACTION, "You join $n's group.", ch, NULL, victim, TO_VICT ); act( AT_ACTION, "$N joins your group.", ch, NULL, victim, TO_CHAR ); } /* 'Split' originally by Gnort, God of Chaos. */ CMDF( do_split ) { char buf[MSL], arg[MSL]; CHAR_DATA *gch; int members, share, extra, amount; bool autosplit = false; if( !argument || argument[0] == '\0' ) { send_to_char( "Split how much?\r\n", ch ); return; } one_argument( argument, arg ); if( !str_cmp( arg, "auto" ) ) { autosplit = true; argument = one_argument( argument, arg ); } if( ( amount = atoi( argument ) ) < 0 ) { send_to_char( "Your group wouldn't like that.\r\n", ch ); return; } if( amount == 0 ) { send_to_char( "You hand out zero coins, but no one notices.\r\n", ch ); return; } if( !has_gold( ch, amount ) ) { send_to_char( "You don't have that much gold.\r\n", ch ); return; } members = 0; for( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if( autosplit && xIS_SET( ch->act, PLR_AUTOSPLIT ) && !xIS_SET( gch->act, PLR_AUTOSPLIT ) ) continue; if( is_same_group( gch, ch ) ) members++; } if( autosplit && xIS_SET( ch->act, PLR_AUTOSPLIT ) && members < 2 ) return; if( members < 2 ) { send_to_char( "Just keep it all.\r\n", ch ); return; } share = amount / members; extra = amount % members; if( share == 0 ) { send_to_char( "Don't even bother, cheapskate.\r\n", ch ); return; } decrease_gold( ch, amount ); increase_gold( ch, ( share + extra ) ); set_char_color( AT_GOLD, ch ); ch_printf( ch, "You split %d gold coins. Your share is %d gold coins.\r\n", amount, share + extra ); snprintf( buf, sizeof( buf ), "$n splits %d gold coins. Your share is %d gold coins.", amount, share ); for( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if( autosplit && xIS_SET( ch->act, PLR_AUTOSPLIT ) && !xIS_SET( gch->act, PLR_AUTOSPLIT ) ) continue; if( gch != ch && is_same_group( gch, ch ) ) { act( AT_GOLD, buf, ch, NULL, gch, TO_VICT ); increase_gold( gch, share ); } } } CMDF( do_gtell ) { CHAR_DATA *gch; GROUP_DATA *group; int speaking = -1, lang; for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( xIS_SET( ch->speaking, lang_array[lang] ) ) { speaking = lang; break; } } if( !argument || argument[0] == '\0' ) { send_to_char( "Tell your group what?\r\n", ch ); return; } if( xIS_SET( ch->act, PLR_NO_TELL ) ) { send_to_char( "Your message didn't get through!\r\n", ch ); return; } if( !( group = ch->group ) ) { send_to_char( "No group to tell anything to.\r\n", ch ); return; } /* Note use of send_to_char, so gtell works on sleepers. */ for( gch = group->first_char; gch; gch = gch->next_in_group ) { set_char_color( AT_GTELL, gch ); /* Groups unscrambled regardless of clan language. Other languages still garble though. -- Altrag */ if( speaking != -1 ) { int speakswell = UMIN( knows_language( gch, speaking ), knows_language( ch, speaking ) ); if( speakswell < 85 ) ch_printf( gch, "%s tells the group '%s'.\r\n", ch->name, translate( speakswell, argument, lang_names[speaking] ) ); else ch_printf( gch, "%s tells the group '%s'.\r\n", ch->name, argument ); } else ch_printf( gch, "%s tells the group '%s'.\r\n", ch->name, argument ); } } /* * Language support functions. -- Altrag * 07/01/96 * * Modified to return how well the language is known 04/04/98 - Thoric * Currently returns 100% for known languages... but should really return * a number based on player's wisdom (maybe 50+((25-wisdom)*2) ?) */ int knows_language( CHAR_DATA *ch, int language ) { short sn; if( !is_npc( ch ) && is_immortal( ch ) ) return 100; if( is_npc( ch ) && xIS_EMPTY( ch->speaks ) ) /* No langs = knows all for npcs */ return 100; if( is_npc( ch ) && xIS_SET( ch->speaks, language ) ) return 100; /* everyone KNOWS common tongue */ if( language == LANG_COMMON ) return 100; if( !is_npc( ch ) ) { int lang; if( xIS_SET( race_table[ch->race]->language, language ) ) return 100; for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( language == lang_array[lang] && xIS_SET( ch->speaks, lang_array[lang] ) ) { if( ( sn = skill_lookup( lang_names[lang] ) ) != -1 ) return ch->pcdata->learned[sn]; } } } return 0; } bool can_learn_lang( CHAR_DATA *ch, int language ) { int adept; if( is_npc( ch ) || is_immortal( ch ) ) return false; if( xIS_SET( race_table[ch->race]->language, language ) ) return false; if( xIS_SET( ch->speaks, language ) ) { int lang; for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( language & lang_array[lang] ) { int sn; if( !( VALID_LANGS & lang_array[lang] ) ) return false; if( ( sn = skill_lookup( lang_names[lang] ) ) < 0 ) { bug( "%s: valid language without sn: %d", __FUNCTION__, lang ); continue; } adept = get_adept( ch, sn ); if( ch->pcdata->learned[sn] >= adept ) return false; } } } if( VALID_LANGS & language ) return true; return false; } int countlangs( EXT_BV languages ) { int numlangs = 0; int looper; for( looper = 0; lang_array[looper] != LANG_UNKNOWN; looper++ ) { if( xIS_SET( languages, lang_array[looper] ) ) numlangs++; } return numlangs; } CMDF( do_speak ) { int langs; char arg[MIL]; argument = one_argument( argument, arg ); if( !str_cmp( arg, "all" ) && is_immortal( ch ) ) { for( langs = 0; lang_array[langs] != LANG_UNKNOWN; langs++ ) xSET_BIT( ch->speaking, lang_array[langs] ); send_to_char( "&[say]Now speaking all languages.\r\n", ch ); return; } for( langs = 0; lang_array[langs] != LANG_UNKNOWN; langs++ ) { if( !str_prefix( arg, lang_names[langs] ) && knows_language( ch, lang_array[langs] ) ) { xCLEAR_BITS( ch->speaking ); xSET_BIT( ch->speaking, lang_array[langs] ); set_char_color( AT_SAY, ch ); ch_printf( ch, "You now speak %s.\r\n", lang_names[langs] ); return; } } set_char_color( AT_SAY, ch ); send_to_char( "You do not know that language.\r\n", ch ); } CMDF( do_languages ) { CHAR_DATA *sch; char arg[MIL]; int lang, col = 0, sn, prct, prac, speaking = -1, langs, adept; if( is_npc( ch ) ) { send_to_char( "You have no reason to use languages.\r\n", ch ); return; } argument = one_argument( argument, arg ); if( arg == NULL || arg[0] == '\0' ) { for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( knows_language( ch, lang_array[lang] ) ) { if( xIS_SET( ch->speaking, lang_array[lang] ) ) set_char_color( AT_SAY, ch ); else set_char_color( AT_PLAIN, ch ); send_to_char( lang_names[lang], ch ); if( ++col == 4 ) { send_to_char( "\r\n", ch ); col = 0; } else send_to_char( " ", ch ); } } if( col != 0 ) send_to_char( "\r\n", ch ); return; } if( str_cmp( arg, "learn" ) ) { send_to_char( "Usage: languages [learn <language>]\r\n", ch ); return; } if( !argument || argument[0] == '\0' ) { send_to_char( "Learn which language?\r\n", ch ); return; } for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ ) { if( !str_prefix( argument, lang_names[lang] ) ) break; } if( lang_array[lang] == LANG_UNKNOWN ) { send_to_char( "That is not a language.\r\n", ch ); return; } if( !( VALID_LANGS & lang_array[lang] ) ) { send_to_char( "You may not learn that language.\r\n", ch ); return; } if( ( sn = skill_lookup( lang_names[lang] ) ) < 0 ) { send_to_char( "That is not a language.\r\n", ch ); return; } adept = get_adept( ch, sn ); if( ch->pcdata->learned[sn] >= adept ) { act( AT_PLAIN, "You're already fluent in $t.", ch, (char *)lang_names[lang], NULL, TO_CHAR ); return; } for( langs = 0; lang_array[langs] != LANG_UNKNOWN; langs++ ) { if( xIS_SET( ch->speaking, lang_array[langs] ) ) { speaking = langs; break; } } for( sch = ch->in_room->first_person; sch; sch = sch->next_in_room ) { if( is_npc( sch ) && xIS_SET( sch->act, ACT_SCHOLAR ) && ( speaking == -1 || knows_language( sch, speaking ) ) && knows_language( sch, lang_array[lang] ) ) break; } if( !sch ) { send_to_char( "There is no one who can teach that language here.\r\n", ch ); return; } if( countlangs( ch->speaks ) >= ( ch->level / 10 ) && ch->pcdata->learned[sn] <= 0 ) { act( AT_TELL, "$n tells you 'You may not learn a new language yet.'", sch, NULL, ch, TO_VICT ); ch->reply = sch; return; } /* 0..16 cha = 2 pracs, 17..25 = 1 prac. -- Altrag */ prac = urange( 1, ( ch->level - get_curr_cha( ch ) ), MAX_LEVEL ); if( ch->practice < prac ) { act( AT_TELL, "$n tells you 'You do not have enough practices.'", sch, NULL, ch, TO_VICT ); ch->reply = sch; return; } ch->practice -= prac; prct = 5 + ( get_curr_int( ch ) / 6 ) + ( get_curr_wis( ch ) / 7 ); ch->pcdata->learned[sn] += prct; ch->pcdata->learned[sn] = UMIN( ch->pcdata->learned[sn], adept ); xSET_BIT( ch->speaks, lang_array[lang] ); if( ch->pcdata->learned[sn] == prct ) act( AT_PLAIN, "You begin lessons in $t.", ch, (char *)lang_names[lang], NULL, TO_CHAR ); else if( ch->pcdata->learned[sn] >= adept ) act( AT_PLAIN, "You are now as fluent in $t as you can get.", ch, (char *)lang_names[lang], NULL, TO_CHAR ); else act( AT_PLAIN, "You continue lessons in $t.", ch, (char *)lang_names[lang], NULL, TO_CHAR ); }