/* * 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 log_buf[MAX_STRING_LENGTH]; char *origarg = argument; char *buf; TIMER *timer = NULL; CMDTYPE *cmd = NULL; int trust; int loglvl; bool found; struct timeval time_used; long tmptime; if( !ch ) { bug( "%s: null ch!", __FUNCTION__ ); return; } if( !ch->in_room ) { bug( "%s: null in_room!", __FUNCTION__ ); return; } found = FALSE; if( ch->substate == SUB_REPEATCMD ) { DO_FUN *fun; if( ( fun = ch->last_cmd ) == NULL ) { ch->substate = SUB_NONE; bug( "%s: SUB_REPEATCMD with NULL last_cmd", __FUNCTION__ ); 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( "%s: SUB_REPEATCMD: last_cmd invalid", __FUNCTION__ ); return; } snprintf( logline, MAX_INPUT_LENGTH, "(%s) %s", cmd->name, argument ); } } if( !cmd ) { /* * Changed the order of these ifchecks to prevent crashing. */ if( !argument || !strcmp( argument, "" ) ) { bug( "%s: null argument!", __FUNCTION__ ); 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!\r\n", ch ); return; } /* * Grab the command word. * Special parsing so ' can be a command, * also no spaces needed after punctuation. */ mudstrlcpy( logline, argument, MAX_INPUT_LENGTH ); if( !isalpha( argument[0] ) && !isdigit( 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_CANSEE ); } } /* * Log and snoop. */ snprintf( lastplayercmd, ( MAX_INPUT_LENGTH * 2 ), "%s used %s", ch->name, logline ); if( found && cmd->log == LOG_NEVER ) mudstrlcpy( logline, "XXXXXXXX XXXXXXXX XXXXXXXX", MAX_INPUT_LENGTH ); 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 ) snprintf( log_buf, MAX_STRING_LENGTH, "Log %s (%s): %s", ch->name, ch->desc->original->name, logline ); else snprintf( log_buf, MAX_STRING_LENGTH, "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; log_string_plus( log_buf, loglvl, get_trust( ch ) ); } if( ch->desc && ch->desc->snoop_by ) { snprintf( logname, MAX_INPUT_LENGTH, "%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, "\r\n", 2 ); } /* * 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; } } /* * Look for command in skill and socials table. */ if( !found ) { if( !check_skill( ch, command, argument ) && !check_ability( ch, command, argument ) // Racial Abilities Support - Kayle 7-8-07 && !rprog_command_trigger( ch, origarg ) && !mprog_command_trigger( ch, origarg ) && !oprog_command_trigger( ch, origarg ) && !check_social( ch, command, argument ) && !news_cmd_hook( ch, command, argument ) #ifdef IMC && !imc_command_hook( ch, command, argument ) #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.\r\n", ch ); return; } if( check_pos( ch, POS_STANDING ) ) move_char( ch, pexit, 0 ); return; } send_to_char( "Huh?\r\n", ch ); } 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..\r\n", 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.\r\n", 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 ) { log_printf_plus( LOG_NORMAL, get_trust( ch ), "[*****] 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 ); cmd->lag_count++; /* count the lag flags */ } tail_chain( ); }
void do_pick (CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *gch; OBJ_DATA *obj; int door; one_argument (argument, arg); if (arg[0] == '\0') { send_to_char ("Pick what?\n\r", ch); return; } WAIT_STATE (ch, skill_table[gsn_pick_lock].beats); /* look for guards */ for (gch = ch->in_room->people; gch; gch = gch->next_in_room) { if (IS_NPC (gch) && IS_AWAKE (gch) && ch->level + 5 < gch->level) { act ("$N is standing too close to the lock.", ch, NULL, gch, TO_CHAR); return; } } if (!IS_NPC (ch) && number_percent () > get_skill (ch, gsn_pick_lock)) { send_to_char ("You failed.\n\r", ch); return; } if ((obj = get_obj_here (ch, arg)) != NULL) { /* portal stuff */ if (obj->item_type == ITEM_PORTAL) { if (!IS_SET (obj->value[1], EX_ISDOOR)) { send_to_char ("You can't do that.\n\r", ch); return; } if (!IS_SET (obj->value[1], EX_CLOSED)) { send_to_char ("It's not closed.\n\r", ch); return; } if (obj->value[4] < 0) { send_to_char ("It can't be unlocked.\n\r", ch); return; } if (IS_SET (obj->value[1], EX_PICKPROOF)) { send_to_char ("You failed.\n\r", ch); return; } REMOVE_BIT (obj->value[1], EX_LOCKED); act ("You pick the lock on $p.", ch, obj, NULL, TO_CHAR); act ("$n picks the lock on $p.", ch, obj, NULL, TO_ROOM); return; } /* 'pick object' */ if (obj->item_type != ITEM_CONTAINER) { send_to_char ("That's not a container.\n\r", ch); return; } if (!IS_SET (obj->value[1], CONT_CLOSED)) { send_to_char ("It's not closed.\n\r", ch); return; } if (obj->value[2] < 0) { send_to_char ("It can't be unlocked.\n\r", ch); return; } if (!IS_SET (obj->value[1], CONT_LOCKED)) { send_to_char ("It's already unlocked.\n\r", ch); return; } if (IS_SET (obj->value[1], CONT_PICKPROOF)) { send_to_char ("You failed.\n\r", ch); return; } REMOVE_BIT (obj->value[1], CONT_LOCKED); act ("You pick the lock on $p.", ch, obj, NULL, TO_CHAR); act ("$n picks the lock on $p.", ch, obj, NULL, TO_ROOM); return; } if ((door = find_door (ch, arg)) >= 0) { /* 'pick door' */ ROOM_INDEX_DATA *to_room; EXIT_DATA *pexit; EXIT_DATA *pexit_rev; pexit = ch->in_room->exit[door]; if (!IS_SET (pexit->exit_info, EX_CLOSED) && !IS_IMMORTAL (ch)) { send_to_char ("It's not closed.\n\r", ch); return; } if (pexit->key < 0 && !IS_IMMORTAL (ch)) { send_to_char ("It can't be picked.\n\r", ch); return; } if (!IS_SET (pexit->exit_info, EX_LOCKED)) { send_to_char ("It's already unlocked.\n\r", ch); return; } if (IS_SET (pexit->exit_info, EX_PICKPROOF) && !IS_IMMORTAL (ch)) { send_to_char ("You failed.\n\r", ch); return; } REMOVE_BIT (pexit->exit_info, EX_LOCKED); send_to_char ("*Click*\n\r", ch); act ("$n picks the $d.", ch, NULL, pexit->keyword, TO_ROOM); /* pick the other side */ if ((to_room = pexit->u1.to_room) != NULL && (pexit_rev = to_room->exit[rev_dir[door]]) != NULL && pexit_rev->u1.to_room == ch->in_room) { REMOVE_BIT (pexit_rev->exit_info, EX_LOCKED); } } return; }
void do_unlock (CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; int door; one_argument (argument, arg); if (arg[0] == '\0') { send_to_char ("Unlock what?\n\r", ch); return; } if ((obj = get_obj_here (ch, arg)) != NULL) { /* portal stuff */ if (obj->item_type == ITEM_PORTAL) { if (!IS_SET (obj->value[1], EX_ISDOOR)) { send_to_char ("You can't do that.\n\r", ch); return; } if (!IS_SET (obj->value[1], EX_CLOSED)) { send_to_char ("It's not closed.\n\r", ch); return; } if (obj->value[4] < 0) { send_to_char ("It can't be unlocked.\n\r", ch); return; } if (!has_key (ch, obj->value[4])) { send_to_char ("You lack the key.\n\r", ch); return; } if (!IS_SET (obj->value[1], EX_LOCKED)) { send_to_char ("It's already unlocked.\n\r", ch); return; } REMOVE_BIT (obj->value[1], EX_LOCKED); act ("You unlock $p.", ch, obj, NULL, TO_CHAR); act ("$n unlocks $p.", ch, obj, NULL, TO_ROOM); return; } /* 'unlock object' */ if (obj->item_type != ITEM_CONTAINER) { send_to_char ("That's not a container.\n\r", ch); return; } if (!IS_SET (obj->value[1], CONT_CLOSED)) { send_to_char ("It's not closed.\n\r", ch); return; } if (obj->value[2] < 0) { send_to_char ("It can't be unlocked.\n\r", ch); return; } if (!has_key (ch, obj->value[2])) { send_to_char ("You lack the key.\n\r", ch); return; } if (!IS_SET (obj->value[1], CONT_LOCKED)) { send_to_char ("It's already unlocked.\n\r", ch); return; } REMOVE_BIT (obj->value[1], CONT_LOCKED); act ("You unlock $p.", ch, obj, NULL, TO_CHAR); act ("$n unlocks $p.", ch, obj, NULL, TO_ROOM); return; } if ((door = find_door (ch, arg)) >= 0) { /* 'unlock door' */ ROOM_INDEX_DATA *to_room; EXIT_DATA *pexit; EXIT_DATA *pexit_rev; pexit = ch->in_room->exit[door]; if (!IS_SET (pexit->exit_info, EX_CLOSED)) { send_to_char ("It's not closed.\n\r", ch); return; } if (pexit->key < 0) { send_to_char ("It can't be unlocked.\n\r", ch); return; } if (!has_key (ch, pexit->key)) { send_to_char ("You lack the key.\n\r", ch); return; } if (!IS_SET (pexit->exit_info, EX_LOCKED)) { send_to_char ("It's already unlocked.\n\r", ch); return; } REMOVE_BIT (pexit->exit_info, EX_LOCKED); send_to_char ("*Click*\n\r", ch); act ("$n unlocks the $d.", ch, NULL, pexit->keyword, TO_ROOM); /* unlock the other side */ if ((to_room = pexit->u1.to_room) != NULL && (pexit_rev = to_room->exit[rev_dir[door]]) != NULL && pexit_rev->u1.to_room == ch->in_room) { REMOVE_BIT (pexit_rev->exit_info, EX_LOCKED); } } return; }
void do_close (CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; int door; one_argument (argument, arg); if (arg[0] == '\0') { send_to_char ("Close what?\n\r", ch); return; } if ((obj = get_obj_here (ch, arg)) != NULL) { /* portal stuff */ if (obj->item_type == ITEM_PORTAL) { if (!IS_SET (obj->value[1], EX_ISDOOR) || IS_SET (obj->value[1], EX_NOCLOSE)) { send_to_char ("You can't do that.\n\r", ch); return; } if (IS_SET (obj->value[1], EX_CLOSED)) { send_to_char ("It's already closed.\n\r", ch); return; } SET_BIT (obj->value[1], EX_CLOSED); act ("You close $p.", ch, obj, NULL, TO_CHAR); act ("$n closes $p.", ch, obj, NULL, TO_ROOM); return; } /* 'close object' */ if (obj->item_type != ITEM_CONTAINER) { send_to_char ("That's not a container.\n\r", ch); return; } if (IS_SET (obj->value[1], CONT_CLOSED)) { send_to_char ("It's already closed.\n\r", ch); return; } if (!IS_SET (obj->value[1], CONT_CLOSEABLE)) { send_to_char ("You can't do that.\n\r", ch); return; } SET_BIT (obj->value[1], CONT_CLOSED); act ("You close $p.", ch, obj, NULL, TO_CHAR); act ("$n closes $p.", ch, obj, NULL, TO_ROOM); return; } if ((door = find_door (ch, arg)) >= 0) { /* 'close door' */ ROOM_INDEX_DATA *to_room; EXIT_DATA *pexit; EXIT_DATA *pexit_rev; pexit = ch->in_room->exit[door]; if (IS_SET (pexit->exit_info, EX_CLOSED)) { send_to_char ("It's already closed.\n\r", ch); return; } SET_BIT (pexit->exit_info, EX_CLOSED); act ("$n closes the $d.", ch, NULL, pexit->keyword, TO_ROOM); send_to_char ("Ok.\n\r", ch); /* close the other side */ if ((to_room = pexit->u1.to_room) != NULL && (pexit_rev = to_room->exit[rev_dir[door]]) != 0 && pexit_rev->u1.to_room == ch->in_room) { CHAR_DATA *rch; SET_BIT (pexit_rev->exit_info, EX_CLOSED); for (rch = to_room->people; rch != NULL; rch = rch->next_in_room) act ("The $d closes.", rch, NULL, pexit_rev->keyword, TO_CHAR); } } return; }
/* * Generic use ranged attack function -Thoric & Tricops */ ch_ret ranged_attack( char_data * ch, string argument, obj_data * weapon, obj_data * projectile, short dt, short range ) { string arg, arg1, temp; if( !argument.empty( ) && argument[0] == '\'' ) { one_argument( argument, temp ); argument = temp; } argument = one_argument( argument, arg ); argument = one_argument( argument, arg1 ); if( arg.empty( ) ) { ch->print( "Where? At who?\r\n" ); return rNONE; } /* * get an exit or a victim */ short dir = -1; exit_data *pexit; char_data *victim = nullptr; if( !( pexit = find_door( ch, arg, true ) ) ) { if( !( victim = ch->get_char_room( arg ) ) ) { ch->print( "Aim in what direction?\r\n" ); return rNONE; } else { if( ch->who_fighting( ) == victim ) { ch->print( "They are too close to release that type of attack!\r\n" ); return rNONE; } } } else dir = pexit->vdir; /* * check for ranged attacks from private rooms, etc */ if( !victim ) { if( ch->in_room->flags.test( ROOM_PRIVATE ) || ch->in_room->flags.test( ROOM_SOLITARY ) ) { ch->print( "You cannot perform a ranged attack from a private room.\r\n" ); return rNONE; } if( ch->in_room->tunnel > 0 ) { if( ( int )ch->in_room->people.size( ) >= ch->in_room->tunnel ) { ch->print( "This room is too cramped to perform such an attack.\r\n" ); return rNONE; } } } skill_type *skill = nullptr; if( IS_VALID_SN( dt ) ) skill = skill_table[dt]; if( pexit && !pexit->to_room ) { ch->print( "Are you expecting to fire through a wall!?\r\n" ); return rNONE; } /* * Check for obstruction */ if( pexit && IS_EXIT_FLAG( pexit, EX_CLOSED ) ) { if( IS_EXIT_FLAG( pexit, EX_SECRET ) || IS_EXIT_FLAG( pexit, EX_DIG ) ) ch->print( "Are you expecting to fire through a wall!?\r\n" ); else ch->print( "Are you expecting to fire through a door!?\r\n" ); return rNONE; } /* * Keeps em from firing through a wall but can still fire through an arrow slit or window, Marcus */ if( pexit ) { if( ( IS_EXIT_FLAG( pexit, EX_FORTIFIED ) || IS_EXIT_FLAG( pexit, EX_HEAVY ) || IS_EXIT_FLAG( pexit, EX_MEDIUM ) || IS_EXIT_FLAG( pexit, EX_LIGHT ) || IS_EXIT_FLAG( pexit, EX_CRUMBLING ) ) && !IS_EXIT_FLAG( pexit, EX_WINDOW ) && !IS_EXIT_FLAG( pexit, EX_ASLIT ) ) { ch->print( "Are you expecting to fire through a wall!?\r\n" ); return rNONE; } } char_data *vch = nullptr; if( pexit && !arg1.empty( ) ) { if( !( vch = scan_for_vic( ch, pexit, arg1 ) ) ) { ch->print( "You cannot see your target.\r\n" ); return rNONE; } /* * don't allow attacks on mobs that are in a no-missile room --Shaddai */ if( vch->in_room->flags.test( ROOM_NOMISSILE ) ) { ch->print( "You can't get a clean shot off.\r\n" ); return rNONE; } /* * can't properly target someone heavily in battle */ if( vch->num_fighting > MAX_FIGHT ) { ch->print( "There is too much activity there for you to get a clear shot.\r\n" ); return rNONE; } } if( vch ) { if( !vch->CAN_PKILL( ) || !ch->CAN_PKILL( ) ) { ch->print( "You can't do that!\r\n" ); return rNONE; } if( vch && is_safe( ch, vch ) ) return rNONE; } room_index *was_in_room = ch->in_room; const char *stxt = "burst of energy"; if( projectile ) { projectile->separate( ); if( pexit ) { if( weapon ) { act( AT_GREY, "You fire $p $T.", ch, projectile, dir_name[dir], TO_CHAR ); act( AT_GREY, "$n fires $p $T.", ch, projectile, dir_name[dir], TO_ROOM ); } else { act( AT_GREY, "You throw $p $T.", ch, projectile, dir_name[dir], TO_CHAR ); act( AT_GREY, "$n throw $p $T.", ch, projectile, dir_name[dir], TO_ROOM ); } } else { if( weapon ) { act( AT_GREY, "You fire $p at $N.", ch, projectile, victim, TO_CHAR ); act( AT_GREY, "$n fires $p at $N.", ch, projectile, victim, TO_NOTVICT ); act( AT_GREY, "$n fires $p at you!", ch, projectile, victim, TO_VICT ); } else { act( AT_GREY, "You throw $p at $N.", ch, projectile, victim, TO_CHAR ); act( AT_GREY, "$n throws $p at $N.", ch, projectile, victim, TO_NOTVICT ); act( AT_GREY, "$n throws $p at you!", ch, projectile, victim, TO_VICT ); } } } else if( skill ) { if( skill->noun_damage && skill->noun_damage[0] != '\0' ) stxt = skill->noun_damage; else stxt = skill->name; /* * a plain "spell" flying around seems boring */ if( !str_cmp( stxt, "spell" ) ) stxt = "magical burst of energy"; if( skill->type == SKILL_SPELL ) { if( pexit ) { act( AT_MAGIC, "You release $t $T.", ch, aoran( stxt ), dir_name[dir], TO_CHAR ); act( AT_MAGIC, "$n releases $s $t $T.", ch, stxt, dir_name[dir], TO_ROOM ); } else { act( AT_MAGIC, "You release $t at $N.", ch, aoran( stxt ), victim, TO_CHAR ); act( AT_MAGIC, "$n releases $s $t at $N.", ch, stxt, victim, TO_NOTVICT ); act( AT_MAGIC, "$n releases $s $t at you!", ch, stxt, victim, TO_VICT ); } } } else { bug( "%s: no projectile, no skill dt %d", __func__, dt ); return rNONE; } /* * victim in same room */ if( victim ) { check_illegal_pk( ch, victim ); check_attacker( ch, victim ); return ranged_got_target( ch, victim, weapon, projectile, 0, dt, stxt, AT_MAGIC ); } /* * assign scanned victim */ victim = vch; /* * reverse direction text from move_char */ const char *dtxt = rev_exit( pexit->vdir ); int dist = 0; while( dist <= range ) { ch->from_room( ); if( !ch->to_room( pexit->to_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ ); if( IS_EXIT_FLAG( pexit, EX_CLOSED ) ) { /* * whadoyahknow, the door's closed */ if( projectile ) ch->printf( "&wYou see your %s pierce a door in the distance to the %s.", projectile->myobj( ).c_str( ), dir_name[dir] ); else ch->printf( "&wYou see your %s hit a door in the distance to the %s.", stxt, dir_name[dir] ); if( projectile ) act_printf( AT_GREY, ch, projectile, nullptr, TO_ROOM, "$p flies in from %s and implants itself solidly in the %sern door.", dtxt, dir_name[dir] ); else act_printf( AT_GREY, ch, nullptr, nullptr, TO_ROOM, "%s flies in from %s and implants itself solidly in the %sern door.", aoran( stxt ), dtxt, dir_name[dir] ); break; } /* * no victim? pick a random one */ if( !victim ) { list < char_data * >::iterator ich; for( ich = ch->in_room->people.begin( ); ich != ch->in_room->people.end( ); ++ich ) { vch = *ich; if( ( ( ch->isnpc( ) && !vch->isnpc( ) ) || ( !ch->isnpc( ) && vch->isnpc( ) ) ) && number_bits( 1 ) == 0 ) { victim = vch; break; } } if( victim && is_safe( ch, victim ) ) { ch->from_room( ); if( !ch->to_room( was_in_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ ); return rNONE; } } /* * In the same room as our victim? */ if( victim && ch->in_room == victim->in_room ) { if( projectile ) act( AT_GREY, "$p flies in from $T.", ch, projectile, dtxt, TO_ROOM ); else act( AT_GREY, "$t flies in from $T.", ch, aoran( stxt ), dtxt, TO_ROOM ); /* * get back before the action starts */ ch->from_room( ); if( !ch->to_room( was_in_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ ); check_illegal_pk( ch, victim ); check_attacker( ch, victim ); return ranged_got_target( ch, victim, weapon, projectile, dist, dt, stxt, AT_GREY ); } if( dist == range ) { if( projectile ) { act( AT_GREY, "Your $t falls harmlessly to the ground to the $T.", ch, projectile->myobj( ).c_str( ), dir_name[dir], TO_CHAR ); act( AT_GREY, "$p flies in from $T and falls harmlessly to the ground here.", ch, projectile, dtxt, TO_ROOM ); if( projectile->in_obj ) projectile->from_obj( ); if( projectile->carried_by ) projectile->from_char( ); projectile->to_room( ch->in_room, ch ); } else { act( AT_MAGIC, "Your $t fizzles out harmlessly to the $T.", ch, stxt, dir_name[dir], TO_CHAR ); act( AT_MAGIC, "$t flies in from $T and fizzles out harmlessly.", ch, aoran( stxt ), dtxt, TO_ROOM ); } break; } if( !( pexit = ch->in_room->get_exit( dir ) ) ) { if( projectile ) { act( AT_GREY, "Your $t hits a wall and bounces harmlessly to the ground to the $T.", ch, projectile->myobj( ).c_str( ), dir_name[dir], TO_CHAR ); act( AT_GREY, "$p strikes the $Tsern wall and falls harmlessly to the ground.", ch, projectile, dir_name[dir], TO_ROOM ); if( projectile->in_obj ) projectile->from_obj( ); if( projectile->carried_by ) projectile->from_char( ); projectile->to_room( ch->in_room, ch ); } else { act( AT_MAGIC, "Your $t harmlessly hits a wall to the $T.", ch, stxt, dir_name[dir], TO_CHAR ); act( AT_MAGIC, "$t strikes the $Tsern wall and falls harmlessly to the ground.", ch, aoran( stxt ), dir_name[dir], TO_ROOM ); } break; } if( projectile ) act( AT_GREY, "$p flies in from $T.", ch, projectile, dtxt, TO_ROOM ); else act( AT_MAGIC, "$t flies in from $T.", ch, aoran( stxt ), dtxt, TO_ROOM ); ++dist; } ch->from_room( ); if( !ch->to_room( was_in_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ ); if( projectile->carried_by == ch ) projectile->extract( ); return rNONE; }
/* * The main entry point for executing commands. * Can be recursively called from 'at', 'order', 'force'. */ void interpret( CHAR_DATA * ch, const char *argument ) { char command[MAX_INPUT_LENGTH]; char logline[MAX_INPUT_LENGTH]; char logname[MAX_INPUT_LENGTH]; 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; } 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; timer = get_timerptr( ch, TIMER_DO_FUN ); /* * REMOVE_BIT( ch->affected_by, AFF_HIDE ); */ /* * Implement freeze command. */ if( !IS_NPC( ch ) && IS_SET( ch->act, PLR_FREEZE ) ) { send_to_char( "You're totally frozen!\r\n", ch ); return; } /* * 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] ) ) { 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->bestowments && ch->pcdata->bestowments[0] != '\0' && is_name( cmd->name, ch->pcdata->bestowments ) && cmd->level <= ( trust + 5 ) ) ) ) { found = TRUE; break; } /* * Turn off afk bit when any command performed. */ if( !IS_NPC( ch ) && IS_SET( ch->act, PLR_AFK ) && ( str_cmp( command, "AFK" ) ) ) { REMOVE_BIT( ch->act, PLR_AFK ); act( AT_GREY, "$n is no longer afk.", ch, NULL, NULL, TO_ROOM ); } } /* * Log and snoop. */ sprintf( lastplayercmd, "** %s: %s", ch->name, logline ); if( found && cmd->log == LOG_NEVER ) strcpy( logline, "XXXXXXXX XXXXXXXX XXXXXXXX" ); loglvl = found ? cmd->log : LOG_NORMAL; if( ( !IS_NPC( ch ) && IS_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 ) || !IS_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, "\r\n", 2 ); } if( timer ) { 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; } } /* * Look for command in skill and socials table. */ if( !found ) { if( !check_skill( ch, command, argument ) && !check_social( ch, command, argument ) #ifdef IMC && !imc_command_hook( ch, command, argument ) #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.\r\n", ch ); return; } move_char( ch, pexit, 0 ); return; } send_to_char( "Huh?\r\n", ch ); } 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 */ if( !str_cmp( cmd->name, "flee" ) && IS_AFFECTED( ch, AFF_BERSERK ) ) { send_to_char( "You aren't thinking very clearly..\r\n", 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 ) { 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, ( int )( time_used.tv_sec ), ( int )( time_used.tv_usec ) ); log_string_plus( log_buf, LOG_NORMAL, get_trust( ch ) ); } tail_chain( ); }