/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// * * -----------------------------------------------------------| (0...0) * * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( * * -----------------------------------------------------------| {o o} * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~* * Tricops and Fireblade | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Command interpretation module * ****************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <string.h> #include <time.h> #include "mud.h" #ifdef USE_IMC #include "icec-mercbase.h" #endif #ifdef timerclear #else #define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 #endif #define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) #ifdef timercmp #else #define timercmp(tvp, uvp, cmp) ((tvp)->tv_sec == (uvp)->tv_sec) ? ((tvp)->tv_usec cmp (uvp)->tv_usec) : ((tvp)->tv_sec cmp (uvp)->tv_sec) #endif /* Externals */ void refresh_page( CHAR_DATA * ch ); void subtract_times( struct timeval *etime, struct timeval *stime ); bool check_social args( ( CHAR_DATA * ch, char *command, char *argument ) ); char *check_cmd_flags args( ( CHAR_DATA * ch, CMDTYPE * cmd ) ); /* * Log-all switch. */ bool fLogAll = FALSE; CMDTYPE *command_hash[126]; /* hash table for cmd_table */ SOCIALTYPE *social_index[27]; /* hash table for socials */ /* * Character not in position for command? */ bool check_pos( CHAR_DATA * ch, sh_int position ) { if( IS_NPC( ch ) && ch->position > 3 ) return TRUE; if( ch->position < position ) { switch ( ch->position ) { case POS_DEAD: send_to_char( "A little difficult to do when you are DEAD...\n\r", ch ); break; case POS_MORTAL: case POS_INCAP: send_to_char( "You are hurt far too bad for that.\n\r", ch ); break; case POS_STUNNED: send_to_char( "You are too stunned to do that.\n\r", ch ); break; case POS_SLEEPING: send_to_char( "In your dreams, or what?\n\r", ch ); break; case POS_RESTING: send_to_char( "Nah... You feel too relaxed...\n\r", ch ); break; case POS_SITTING: send_to_char( "You can't do that sitting down.\n\r", ch ); break; case POS_FIGHTING: if( position <= POS_EVASIVE ) { send_to_char( "This fighting style is too demanding for that!\n\r", ch ); } else { send_to_char( "No way! You are still fighting!\n\r", ch ); } break; case POS_DEFENSIVE: if( position <= POS_EVASIVE ) { send_to_char( "This fighting style is too demanding for that!\n\r", ch ); } else { send_to_char( "No way! You are still fighting!\n\r", ch ); } break; case POS_AGGRESSIVE: if( position <= POS_EVASIVE ) { send_to_char( "This fighting style is too demanding for that!\n\r", ch ); } else { send_to_char( "No way! You are still fighting!\n\r", ch ); } break; case POS_BERSERK: if( position <= POS_EVASIVE ) { send_to_char( "This fighting style is too demanding for that!\n\r", ch ); } else { send_to_char( "No way! You are still fighting!\n\r", ch ); } break; case POS_EVASIVE: send_to_char( "No way! You are still fighting!\n\r", ch ); break; } return FALSE; } return TRUE; } extern char lastplayercmd[MAX_INPUT_LENGTH * 2]; /* * Determine if this input line is eligible for writing to a watch file. * We don't want to write movement commands like (n, s, e, w, etc.) */ bool valid_watch( char *logline ) { int len = strlen( logline ); char c = logline[0]; if( len == 1 && ( c == 'n' || c == 's' || c == 'e' || c == 'w' || c == 'u' || c == 'd' ) ) return FALSE; if( len == 2 && c == 'n' && ( logline[1] == 'e' || logline[1] == 'w' ) ) return FALSE; if( len == 2 && c == 's' && ( logline[1] == 'e' || logline[1] == 'w' ) ) return FALSE; return TRUE; } /* * Write input line to watch files if applicable */ void write_watch_files( CHAR_DATA * ch, CMDTYPE * cmd, char *logline ) { WATCH_DATA *pw; FILE *fp; char fname[MAX_INPUT_LENGTH], buf[MAX_STRING_LENGTH]; struct tm *t = localtime( ¤t_time ); if( !first_watch ) /* no active watches */ return; /* if we're watching a command we need to do some special stuff */ /* to avoid duplicating log lines - relies upon watch list being */ /* sorted by imm name */ if( cmd ) { char *cur_imm; bool found; pw = first_watch; while( pw ) { found = FALSE; for( cur_imm = pw->imm_name; pw && !strcmp( pw->imm_name, cur_imm ); pw = pw->next ) { if( !found && ch->desc && get_trust( ch ) < pw->imm_level && ( ( pw->target_name && !strcmp( cmd->name, pw->target_name ) ) || ( pw->player_site && !str_prefix( pw->player_site, ch->desc->host ) ) ) ) { sprintf( fname, "%s%s", WATCH_DIR, strlower( pw->imm_name ) ); if( !( fp = fopen( fname, "a+" ) ) ) { sprintf( buf, "%s%s", "Write_watch_files: Cannot open ", fname ); bug( buf, 0 ); perror( fname ); return; } sprintf( buf, "%.2d/%.2d %.2d:%.2d %s: %s\n", t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, ch->name, logline ); fputs( buf, fp ); fclose( fp ); found = TRUE; } } } } else { for( pw = first_watch; pw; pw = pw->next ) if( ( ( pw->target_name && !str_cmp( pw->target_name, ch->name ) ) || ( pw->player_site && !str_prefix( pw->player_site, ch->desc->host ) ) ) && get_trust( ch ) < pw->imm_level && ch->desc ) { sprintf( fname, "%s%s", WATCH_DIR, strlower( pw->imm_name ) ); if( !( fp = fopen( fname, "a+" ) ) ) { sprintf( buf, "%s%s", "Write_watch_files: Cannot open ", fname ); bug( buf, 0 ); perror( fname ); return; } sprintf( buf, "%.2d/%.2d %.2d:%.2d %s: %s\n", t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, ch->name, logline ); fputs( buf, fp ); fclose( fp ); } } return; } /* * The main entry point for executing commands. * Can be recursively called from 'at', 'order', 'force'. */ void interpret( CHAR_DATA * ch, char *argument ) { char command[MAX_INPUT_LENGTH]; char logline[MAX_INPUT_LENGTH]; char logname[MAX_INPUT_LENGTH]; char newcommand[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; char *buf; TIMER *timer = NULL; CMDTYPE *cmd = NULL; int trust; int loglvl; bool found; struct timeval time_used; long tmptime; if( !ch ) { bug( "interpret: null ch!", 0 ); return; } if( !ch->in_room ) { bug( "interpret: null in_room!", 0 ); return; } found = FALSE; if( ch->substate == SUB_REPEATCMD ) { DO_FUN *fun; if( ( fun = ch->last_cmd ) == NULL ) { ch->substate = SUB_NONE; bug( "interpret: SUB_REPEATCMD with NULL last_cmd", 0 ); return; } else { int x; /* * yes... we lose out on the hashing speediness here... * but the only REPEATCMDS are wizcommands (currently) */ for( x = 0; x < 126; x++ ) { for( cmd = command_hash[x]; cmd; cmd = cmd->next ) if( cmd->do_fun == fun ) { found = TRUE; break; } if( found ) break; } if( !found ) { cmd = NULL; bug( "interpret: SUB_REPEATCMD: last_cmd invalid", 0 ); return; } sprintf( logline, "(%s) %s", cmd->name, argument ); } } if( !cmd ) { /* * Changed the order of these ifchecks to prevent crashing. */ if( !argument || !strcmp( argument, "" ) ) { bug( "interpret: null argument!", 0 ); return; } /* * Strip leading spaces. */ while( isspace( *argument ) ) argument++; if( argument[0] == '\0' ) return; /* * xREMOVE_BIT( ch->affected_by, AFF_HIDE ); */ /* * Implement freeze command. */ if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_FREEZE ) ) { send_to_char( "You're totally frozen!\n\r", ch ); return; } if( !IS_NPC( ch ) && fusion_stasis( ch ) ) { ch_printf( ch, "&g&wYou fused with someone, so this character is locked out!\n\r" ); return; } if( !IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) ) { ch_printf( ch, "&g&wYou struggle to break your bonds but fail!\n\r" ); return; } if( !IS_NPC( ch ) && ch->tmystic == 1 ) { ch_printf( ch, "You have interrupted the process of teaching mystic.\n\r" ); ch->tmystic = 0; if( ch->teaching ) { ch->teaching->mysticlearn = 0; ch->teaching->tmystic = 0; ch->teaching->teaching = NULL; ch_printf( ch->teaching, "%s has interrupted the process of teaching you mystic.\n\r", ch->name ); ch->teaching = NULL; } } if( !IS_NPC( ch ) && ch->tmystic > 1 ) { ch_printf( ch, "You have interrupted the process of learning mystic.\n\r" ); ch->tmystic = 0; ch->mysticlearn = 0; if( ch->teaching ) { ch->teaching->tmystic = 0; ch->teaching->teaching = NULL; ch_printf( ch->teaching, "%s has interrupted the process of learning mystic.\n\r", ch->name ); ch->teaching = NULL; } } /* * Grab the command word. * Special parsing so ' can be a command, * also no spaces needed after punctuation. */ strcpy( logline, argument ); /* if ( !isalpha(argument[0]) && !isdigit(argument[0]) && !str_cmp( argument[0], "'" ) ) { command[0] = argument[0]; command[1] = '\0'; argument++; while ( isspace(*argument) ) argument++; } else */ argument = one_argument( argument, command ); /* * Look for command in command table. * Check for council powers and/or bestowments */ trust = get_trust( ch ); for( cmd = command_hash[LOWER( command[0] ) % 126]; cmd; cmd = cmd->next ) if( !str_prefix( command, cmd->name ) && ( cmd->level <= trust || ( !IS_NPC( ch ) && ch->pcdata->council && is_name( cmd->name, ch->pcdata->council->powers ) && cmd->level <= ( trust + MAX_CPD ) ) || ( !IS_NPC( ch ) && ch->pcdata->bestowments && ch->pcdata->bestowments[0] != '\0' && is_name( cmd->name, ch->pcdata->bestowments ) && cmd->level <= ( trust + sysdata.bestow_dif ) ) ) ) { found = TRUE; break; } /* * Turn off afk bit when any command performed. */ if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_AFK ) && ( str_cmp( command, "AFK" ) ) ) { xREMOVE_BIT( ch->act, PLR_AFK ); /* act( AT_GREY, "$n is no longer afk.", ch, NULL, NULL, TO_ROOM ); */ act( AT_GREY, "$n is no longer afk.", ch, NULL, NULL, TO_CANSEE ); } } /* * Log and snoop. */ /* sprintf( lastplayercmd, "** %s: %s", ch->name, logline ); */ if( found && cmd->log == LOG_NEVER ) strcpy( logline, "XXXXXXXX XXXXXXXX XXXXXXXX" ); sprintf( lastplayercmd, "%s used %s", ch->name, logline ); // if( !IS_NPC( ch ) ) // { // if( found && cmd->log != LOG_NEVER ) // { // log_string_plus( lastplayercmd, LOG_HIGH, LEVEL_LESSER ); // } // } loglvl = found ? cmd->log : LOG_NORMAL; /* * Write input line to watch files if applicable */ if( !IS_NPC( ch ) && ch->desc && valid_watch( logline ) ) { if( found && IS_SET( cmd->flags, CMD_WATCH ) ) write_watch_files( ch, cmd, logline ); else if( IS_SET( ch->pcdata->flags, PCFLAG_WATCH ) ) write_watch_files( ch, NULL, logline ); } if( ( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_LOG ) ) || fLogAll || loglvl == LOG_BUILD || loglvl == LOG_HIGH || loglvl == LOG_ALWAYS ) { /* * Added by Narn to show who is switched into a mob that executes * a logged command. Check for descriptor in case force is used. */ if( ch->desc && ch->desc->original ) sprintf( log_buf, "Log %s (%s): %s", ch->name, ch->desc->original->name, logline ); else sprintf( log_buf, "Log %s: %s", ch->name, logline ); /* * Make it so a 'log all' will send most output to the log * file only, and not spam the log channel to death -Thoric */ if( fLogAll && loglvl == LOG_NORMAL && ( IS_NPC( ch ) || !xIS_SET( ch->act, PLR_LOG ) ) ) loglvl = LOG_ALL; /* * This is handled in get_trust already */ /* if ( ch->desc && ch->desc->original ) log_string_plus( log_buf, loglvl, ch->desc->original->level ); else*/ log_string_plus( log_buf, loglvl, get_trust( ch ) ); } if( ch->desc && ch->desc->snoop_by ) { sprintf( logname, "%s", ch->name ); write_to_buffer( ch->desc->snoop_by, logname, 0 ); write_to_buffer( ch->desc->snoop_by, "% ", 2 ); write_to_buffer( ch->desc->snoop_by, logline, 0 ); write_to_buffer( ch->desc->snoop_by, "\n\r", 2 ); } /* * BUILD INTERFACE (start) */ if( ch->inter_type == OBJ_TYPE ) { MENU_DATA *m_data = NULL; int i; switch ( ch->inter_page ) { case OBJ_PAGE_A: m_data = obj_page_a_data; break; case OBJ_PAGE_B: m_data = obj_page_b_data; break; case OBJ_PAGE_C: m_data = obj_page_c_data; break; case OBJ_PAGE_D: m_data = obj_page_d_data; break; case OBJ_PAGE_E: m_data = obj_page_e_data; break; case OBJ_HELP_PAGE: m_data = obj_help_page_data; break; } if( m_data ) { for( i = 0; m_data[i].ptrType != ( int )NULL; i++ ) { /* * IF 1st char matches && 2nd CHAR MATCHES... */ if( !strcmp( m_data[i].sectionNum, command ) ) { if( !strncmp( m_data[i].charChoice, argument, 1 ) ) /* just check the 1st char */ { /* * ...then MAKE NEW_COMMAND, and */ switch ( m_data[i].cmdArgs ) { case 1: sprintf( newcommand, m_data[i].cmdString, ch->inter_editing ); break; case 2: argument = one_argument( argument, arg2 ); sprintf( newcommand, m_data[i].cmdString, ch->inter_editing, argument ); break; case 0: default: sprintf( newcommand, m_data[i].cmdString ); } send_to_char( newcommand, ch ); send_to_char( "\n\r", ch ); /* * ... interpret NEW_COMMAND */ interpret( ch, newcommand ); refresh_page( ch ); return; } } } if( !strcmp( "+", command ) && get_obj_world( ch, argument ) ) { sprintf( newcommand, "omenu %s %c", argument, ch->inter_page ); send_to_char( newcommand, ch ); send_to_char( "\n\r", ch ); interpret( ch, newcommand ); refresh_page( ch ); return; } } } if( ch->inter_type == MOB_TYPE ) { MENU_DATA *m_data = NULL; int i; switch ( ch->inter_page ) { case MOB_PAGE_A: m_data = mob_page_a_data; break; case MOB_PAGE_B: m_data = mob_page_b_data; break; case MOB_PAGE_C: m_data = mob_page_c_data; break; case MOB_PAGE_D: m_data = mob_page_d_data; break; case MOB_PAGE_E: m_data = mob_page_e_data; break; case MOB_PAGE_F: m_data = mob_page_f_data; /* 7/19 */ break; case MOB_HELP_PAGE: m_data = mob_help_page_data; break; } if( m_data ) { for( i = 0; m_data[i].ptrType != ( int )NULL; i++ ) { /* * IF 1st char matches && 2nd CHAR MATCHES... */ if( !strcmp( m_data[i].sectionNum, command ) ) { if( !strncmp( m_data[i].charChoice, argument, 1 ) ) /* just check the 1st char */ { /* * ...then MAKE NEW_COMMAND, and */ switch ( m_data[i].cmdArgs ) { case 1: sprintf( newcommand, m_data[i].cmdString, ch->inter_editing ); break; case 2: argument = one_argument( argument, arg2 ); sprintf( newcommand, m_data[i].cmdString, ch->inter_editing, argument ); break; case 0: default: sprintf( newcommand, m_data[i].cmdString ); } send_to_char( newcommand, ch ); send_to_char( "\n\r", ch ); /* * ... interpret NEW_COMMAND */ interpret( ch, newcommand ); refresh_page( ch ); return; } } } if( !strcmp( "+", command ) && get_char_world( ch, argument ) ) { sprintf( newcommand, "mmenu %s %c", argument, ch->inter_page ); send_to_char( newcommand, ch ); send_to_char( "\n\r", ch ); interpret( ch, newcommand ); refresh_page( ch ); return; } } } if( ch->inter_type == ROOM_TYPE ) { MENU_DATA *m_data = NULL; int i; switch ( ch->inter_page ) { case ROOM_PAGE_A: m_data = room_page_a_data; break; case ROOM_PAGE_B: m_data = room_page_b_data; break; case ROOM_PAGE_C: m_data = room_page_c_data; break; case ROOM_HELP_PAGE: m_data = room_help_page_data; break; } if( m_data ) { for( i = 0; m_data[i].ptrType != ( int )NULL; i++ ) { /* * IF 1st char matches && 2nd CHAR MATCHES... */ if( !strcmp( m_data[i].sectionNum, command ) ) { if( !strncmp( m_data[i].charChoice, argument, 1 ) ) /* just check the 1st char */ { /* * ...then MAKE NEW_COMMAND, and */ switch ( m_data[i].cmdArgs ) { case 1: argument = one_argument( argument, arg2 ); /* new */ argument = one_argument( argument, arg2 ); /* new */ sprintf( newcommand, m_data[i].cmdString, argument ); /* different than mobs */ break; /* on purpose */ case 2: argument = one_argument( argument, arg2 ); sprintf( newcommand, m_data[i].cmdString, ch->inter_editing, argument ); break; case 0: default: sprintf( newcommand, m_data[i].cmdString ); } send_to_char( newcommand, ch ); send_to_char( "\n\r", ch ); /* * ... interpret NEW_COMMAND */ interpret( ch, newcommand ); refresh_page( ch ); return; } } } } } /* * BUILD INTERFACE ( end ) */ /* * check for a timer delayed command (search, dig, detrap, etc) */ if( ( timer = get_timerptr( ch, TIMER_DO_FUN ) ) != NULL ) { int tempsub; tempsub = ch->substate; ch->substate = SUB_TIMER_DO_ABORT; ( timer->do_fun ) ( ch, "" ); if( char_died( ch ) ) return; if( ch->substate != SUB_TIMER_CANT_ABORT ) { ch->substate = tempsub; extract_timer( ch, timer ); } else { ch->substate = tempsub; return; } } /* * Goku's timer stuff :) */ if( ch->timerDo_fun ) { int tempsub; tempsub = ch->substate; ch->substate = SUB_TIMER_DO_ABORT; ( ch->timerDo_fun ) ( ch, "" ); if( char_died( ch ) ) return; } /* * Look for command in skill and socials table. */ if( !found ) { if( !check_skill( ch, command, argument ) && !check_ability( ch, command, argument ) && !check_social( ch, command, argument ) #ifdef USE_IMC && !icec_command_hook( ch, command, argument ) ) #else ) #endif { EXIT_DATA *pexit; /* * check for an auto-matic exit command */ if( ( pexit = find_door( ch, command, TRUE ) ) != NULL && IS_SET( pexit->exit_info, EX_xAUTO ) ) { if( IS_SET( pexit->exit_info, EX_CLOSED ) && ( !IS_AFFECTED( ch, AFF_PASS_DOOR ) || IS_SET( pexit->exit_info, EX_NOPASSDOOR ) ) ) { if( !IS_SET( pexit->exit_info, EX_SECRET ) ) act( AT_PLAIN, "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR ); else send_to_char( "You cannot do that here.\n\r", ch ); return; } move_char( ch, pexit, 0 ); return; } switch ( number_range( 0, 8 ) ) { default: case 0: case 1: case 2: send_to_char( "&wHuh?!?\r\n", ch ); return; break; case 3: send_to_char( "&wFool, that's not a word!\r\n", ch ); return; break; case 4: send_to_char( "&wLast time I checked that wasn't a command!\r\n", ch ); return; break; case 5: send_to_char( "&wI no hough too spel, joust lic yu!\r\n", ch ); return; break; case 6: send_to_char( "&wTry a real command.\r\n", ch ); return; break; case 7: send_to_char( "&wMaking up words again, huh?\r\n", ch ); return; break; case 8: send_to_char( "&wComputer: &W$500. &wKeyboard: &W$20. &wzMUD: &W$25&w. Learning to type: &WPRICELESS&w.\r\n", ch ); return; break; } } return; } /* * Character not in position for command? */ if( !check_pos( ch, cmd->position ) ) return; /* * Berserk check for flee.. maybe add drunk to this?.. but too much * hardcoding is annoying.. -- Altrag * This wasn't catching wimpy --- Blod * if ( !str_cmp(cmd->name, "flee") && * IS_AFFECTED(ch, AFF_BERSERK) ) * { * send_to_char( "You aren't thinking very clearly..\n\r", ch); * return; * } */ /* * So we can check commands for things like Posses and Polymorph * * But still keep the online editing ability. -- Shaddai * * Send back the message to print out, so we have the option * * this function might be usefull elsewhere. Also using the * * send_to_char_color so we can colorize the strings if need be. --Shaddai */ buf = check_cmd_flags( ch, cmd ); if( buf[0] != '\0' ) { send_to_char_color( buf, ch ); return; } /* * Nuisance stuff -- Shaddai */ if( !IS_NPC( ch ) && ch->pcdata->nuisance && ch->pcdata->nuisance->flags > 9 && number_percent( ) < ( ( ch->pcdata->nuisance->flags - 9 ) * 10 * ch->pcdata->nuisance->power ) ) { send_to_char( "You can't seem to do that just now.\n\r", ch ); return; } /* * Dispatch the command. */ ch->prev_cmd = ch->last_cmd; /* haus, for automapping */ ch->last_cmd = cmd->do_fun; start_timer( &time_used ); ( *cmd->do_fun ) ( ch, argument ); end_timer( &time_used ); /* * Update the record of how many times this command has been used (haus) */ update_userec( &time_used, &cmd->userec ); tmptime = UMIN( time_used.tv_sec, 19 ) * 1000000 + time_used.tv_usec; /* * laggy command notice: command took longer than 1.5 seconds */ if( tmptime > 1500000 ) { #ifdef TIMEFORMAT sprintf( log_buf, "[*****] LAG: %s: %s %s (R:%d S:%ld.%06ld)", ch->name, cmd->name, ( cmd->log == LOG_NEVER ? "XXX" : argument ), ch->in_room ? ch->in_room->vnum : 0, time_used.tv_sec, time_used.tv_usec ); #else sprintf( log_buf, "[*****] LAG: %s: %s %s (R:%d S:%d.%06d)", ch->name, cmd->name, ( cmd->log == LOG_NEVER ? "XXX" : argument ), ch->in_room ? ch->in_room->vnum : 0, time_used.tv_sec, time_used.tv_usec ); #endif log_string_plus( log_buf, LOG_NORMAL, get_trust( ch ) ); cmd->lag_count++; /* count the lag flags */ } tail_chain( ); } CMDTYPE *find_command( char *command ) { CMDTYPE *cmd; int hash; hash = LOWER( command[0] ) % 126; for( cmd = command_hash[hash]; cmd; cmd = cmd->next ) if( !str_prefix( command, cmd->name ) ) return cmd; return NULL; } SOCIALTYPE *find_social( char *command ) { SOCIALTYPE *social; int hash; if( command[0] < 'a' || command[0] > 'z' ) hash = 0; else hash = ( command[0] - 'a' ) + 1; for( social = social_index[hash]; social; social = social->next ) if( !str_prefix( command, social->name ) ) return social; return NULL; } bool check_social( CHAR_DATA * ch, char *command, char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; SOCIALTYPE *social; CHAR_DATA *remfirst, *remlast, *remtemp; /* for ignore cmnd */ if( ( social = find_social( command ) ) == NULL ) return FALSE; if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_NO_EMOTE ) ) { send_to_char( "You are anti-social!\n\r", ch ); return TRUE; } switch ( ch->position ) { case POS_DEAD: send_to_char( "Lie still; you are DEAD.\n\r", ch ); return TRUE; case POS_INCAP: case POS_MORTAL: send_to_char( "You are hurt far too bad for that.\n\r", ch ); return TRUE; case POS_STUNNED: send_to_char( "You are too stunned to do that.\n\r", ch ); return TRUE; case POS_SLEEPING: /* * I just know this is the path to a 12" 'if' statement. :( * But two players asked for it already! -- Furey */ if( !str_cmp( social->name, "snore" ) ) break; send_to_char( "In your dreams, or what?\n\r", ch ); return TRUE; } remfirst = NULL; remlast = NULL; remtemp = NULL; /* * Search room for chars ignoring social sender and */ /* * remove them from the room until social has been */ /* * completed */ for( victim = ch->in_room->first_person; victim; victim = victim->next_in_room ) { if( is_ignoring( victim, ch ) ) { if( !IS_IMMORTAL( ch ) || get_trust( victim ) > get_trust( ch ) ) { char_from_room( victim ); LINK( victim, remfirst, remlast, next_in_room, prev_in_room ); } /* else * { * set_char_color(AT_IGNORE, victim); * ch_printf(victim, "You attempt to ignore %s," * " but are unable to do so.\n\r", ch->name); * } */ } } one_argument( argument, arg ); victim = NULL; if( arg[0] == '\0' ) { act( AT_SOCIAL, social->others_no_arg, ch, NULL, victim, TO_ROOM ); act( AT_SOCIAL, social->char_no_arg, ch, NULL, victim, TO_CHAR ); } else if( ( victim = get_char_room( ch, arg ) ) == NULL ) { /* * If they aren't in the room, they may be in the list of */ /* * people ignoring... */ for( victim = remfirst; victim; victim = victim->next_in_room ) { if( nifty_is_name( victim->name, arg ) || nifty_is_name_prefix( arg, victim->name ) ) { set_char_color( AT_IGNORE, ch ); ch_printf( ch, "%s is ignoring you.\n\r", victim->name ); break; } } if( !victim ) send_to_char( "They aren't here.\n\r", ch ); } else if( victim == ch ) { act( AT_SOCIAL, social->others_auto, ch, NULL, victim, TO_ROOM ); act( AT_SOCIAL, social->char_auto, ch, NULL, victim, TO_CHAR ); } else if( is_ignoring( ch, victim ) ) { send_to_char( "You're ignoring them, so go bother someone else.\n\r", ch ); } else { act( AT_SOCIAL, social->others_found, ch, NULL, victim, TO_NOTVICT ); act( AT_SOCIAL, social->char_found, ch, NULL, victim, TO_CHAR ); act( AT_SOCIAL, social->vict_found, ch, NULL, victim, TO_VICT ); if( !IS_NPC( ch ) && IS_NPC( victim ) && !IS_AFFECTED( victim, AFF_CHARM ) && IS_AWAKE( victim ) && !HAS_PROG( victim->pIndexData, ACT_PROG ) ) { switch ( number_bits( 4 ) ) { case 0: /* if (IS_EVIL(ch) && !is_safe(victim, ch, TRUE)) multi_hit( victim, ch, TYPE_UNDEFINED ); else */ if( IS_NEUTRAL( ch ) ) { act( AT_ACTION, "$n slaps $N.", victim, NULL, ch, TO_NOTVICT ); act( AT_ACTION, "You slap $N.", victim, NULL, ch, TO_CHAR ); act( AT_ACTION, "$n slaps you.", victim, NULL, ch, TO_VICT ); } else { act( AT_ACTION, "$n acts like $N doesn't even exist.", victim, NULL, ch, TO_NOTVICT ); act( AT_ACTION, "You just ignore $N.", victim, NULL, ch, TO_CHAR ); act( AT_ACTION, "$n appears to be ignoring you.", victim, NULL, ch, TO_VICT ); } break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: act( AT_SOCIAL, social->others_found, victim, NULL, ch, TO_NOTVICT ); act( AT_SOCIAL, social->char_found, victim, NULL, ch, TO_CHAR ); act( AT_SOCIAL, social->vict_found, victim, NULL, ch, TO_VICT ); break; case 9: case 10: case 11: case 12: act( AT_ACTION, "$n slaps $N.", victim, NULL, ch, TO_NOTVICT ); act( AT_ACTION, "You slap $N.", victim, NULL, ch, TO_CHAR ); act( AT_ACTION, "$n slaps you.", victim, NULL, ch, TO_VICT ); break; } } } /* * Replace the chars in the ignoring list to the room */ /* * note that the ordering of the players in the room */ /* * might change */ for( victim = remfirst; victim; victim = remtemp ) { remtemp = victim->next_in_room; char_to_room( victim, ch->in_room ); } return TRUE; } /* * Return true if an argument is completely numeric. */ bool is_number( char *arg ) { bool first = TRUE; if( *arg == '\0' ) return FALSE; for( ; *arg != '\0'; arg++ ) { if( first && *arg == '-' ) { first = FALSE; continue; } if( !isdigit( *arg ) ) return FALSE; first = FALSE; } return TRUE; } /* * Given a string like 14.foo, return 14 and 'foo' */ int number_argument( char *argument, char *arg ) { char *pdot; int number; for( pdot = argument; *pdot != '\0'; pdot++ ) { if( *pdot == '.' ) { *pdot = '\0'; number = atoi( argument ); *pdot = '.'; strcpy( arg, pdot + 1 ); return number; } } strcpy( arg, argument ); return 1; } /* * Pick off one argument from a string and return the rest. * Understands quotes. */ char *one_argument( char *argument, char *arg_first ) { char cEnd; sh_int count; count = 0; if( !argument || argument[0] == '\0' ) { arg_first[0] = '\0'; return argument; } while( isspace( *argument ) ) argument++; cEnd = ' '; if( *argument == '\'' || *argument == '"' ) cEnd = *argument++; while( *argument != '\0' || ++count >= 255 ) { if( *argument == cEnd ) { argument++; break; } //*arg_first = LOWER(*argument); *arg_first = *argument; arg_first++; argument++; } *arg_first = '\0'; while( isspace( *argument ) ) argument++; return argument; } /* * Pick off one argument from a string and return the rest. * Understands quotes. Delimiters = { ' ', '-' } */ char *one_argument2( char *argument, char *arg_first ) { char cEnd; sh_int count; count = 0; if( !argument || argument[0] == '\0' ) { arg_first[0] = '\0'; return argument; } while( isspace( *argument ) ) argument++; cEnd = ' '; if( *argument == '\'' || *argument == '"' ) cEnd = *argument++; while( *argument != '\0' || ++count >= 255 ) { if( *argument == cEnd || *argument == '-' ) { argument++; break; } *arg_first = LOWER( *argument ); arg_first++; argument++; } *arg_first = '\0'; while( isspace( *argument ) ) argument++; return argument; } void do_timecmd( CHAR_DATA * ch, char *argument ) { struct timeval stime; struct timeval etime; static bool timing; extern CHAR_DATA *timechar; char arg[MAX_INPUT_LENGTH]; send_to_char( "Timing\n\r", ch ); if( timing ) return; one_argument( argument, arg ); if( !*arg ) { send_to_char( "No command to time.\n\r", ch ); return; } if( !str_cmp( arg, "update" ) ) { if( timechar ) send_to_char( "Another person is already timing updates.\n\r", ch ); else { timechar = ch; send_to_char( "Setting up to record next update loop.\n\r", ch ); } return; } set_char_color( AT_PLAIN, ch ); send_to_char( "Starting timer.\n\r", ch ); timing = TRUE; gettimeofday( &stime, NULL ); interpret( ch, argument ); gettimeofday( &etime, NULL ); timing = FALSE; set_char_color( AT_PLAIN, ch ); send_to_char( "Timing complete.\n\r", ch ); subtract_times( &etime, &stime ); ch_printf( ch, "Timing took %d.%06d seconds.\n\r", etime.tv_sec, etime.tv_usec ); return; } void start_timer( struct timeval *stime ) { if( !stime ) { bug( "Start_timer: NULL stime.", 0 ); return; } gettimeofday( stime, NULL ); return; } time_t end_timer( struct timeval * stime ) { struct timeval etime; /* * Mark etime before checking stime, so that we get a better reading.. */ gettimeofday( &etime, NULL ); if( !stime || ( !stime->tv_sec && !stime->tv_usec ) ) { bug( "End_timer: bad stime.", 0 ); return 0; } subtract_times( &etime, stime ); /* * stime becomes time used */ *stime = etime; return ( etime.tv_sec * 1000000 ) + etime.tv_usec; } void send_timer( struct timerset *vtime, CHAR_DATA * ch ) { struct timeval ntime; int carry; if( vtime->num_uses == 0 ) return; ntime.tv_sec = vtime->total_time.tv_sec / vtime->num_uses; carry = ( vtime->total_time.tv_sec % vtime->num_uses ) * 1000000; ntime.tv_usec = ( vtime->total_time.tv_usec + carry ) / vtime->num_uses; ch_printf( ch, "Has been used %d times this boot.\n\r", vtime->num_uses ); ch_printf( ch, "Time (in secs): min %d.%0.6d; avg: %d.%0.6d; max %d.%0.6d" "\n\r", vtime->min_time.tv_sec, vtime->min_time.tv_usec, ntime.tv_sec, ntime.tv_usec, vtime->max_time.tv_sec, vtime->max_time.tv_usec ); return; } void update_userec( struct timeval *time_used, struct timerset *userec ) { userec->num_uses++; if( !timerisset( &userec->min_time ) || timercmp( time_used, &userec->min_time, < ) ) { userec->min_time.tv_sec = time_used->tv_sec; userec->min_time.tv_usec = time_used->tv_usec; } if( !timerisset( &userec->max_time ) || timercmp( time_used, &userec->max_time, > ) ) { userec->max_time.tv_sec = time_used->tv_sec; userec->max_time.tv_usec = time_used->tv_usec; } userec->total_time.tv_sec += time_used->tv_sec; userec->total_time.tv_usec += time_used->tv_usec; while( userec->total_time.tv_usec >= 1000000 ) { userec->total_time.tv_sec++; userec->total_time.tv_usec -= 1000000; } return; } /* * This function checks the command against the command flags to make * sure they can use the command online. This allows the commands to be * edited online to allow or disallow certain situations. May be an idea * to rework this so we can edit the message sent back online, as well as * maybe a crude parsing language so we can add in new checks online without * haveing to hard-code them in. -- Shaddai August 25, 1997 */ /* Needed a global here */ char cmd_flag_buf[MAX_STRING_LENGTH]; char *check_cmd_flags( CHAR_DATA * ch, CMDTYPE * cmd ) { if( IS_AFFECTED( ch, AFF_POSSESS ) && IS_SET( cmd->flags, CMD_FLAG_POSSESS ) ) sprintf( cmd_flag_buf, "You can't %s while you are possessing someone!\n\r", cmd->name ); else if( ch->morph != NULL && IS_SET( cmd->flags, CMD_FLAG_POLYMORPHED ) ) sprintf( cmd_flag_buf, "You can't %s while you are polymorphed!\n\r", cmd->name ); else if( IS_NPC( ch ) && is_splitformed( ch ) && IS_SET( cmd->flags, CMD_FLAG_POSSESS ) ) sprintf( cmd_flag_buf, "Clones can't do %s\n\r", cmd->name ); else cmd_flag_buf[0] = '\0'; return cmd_flag_buf; }