/****************************************************************************
* ResortMUD Version 5.0 was mainly programmed by Ntanel, Garinan, Josh, *
* Badastaz, Digifuzz, Senir, Kratas, Scion, Shogar and Tagith. *
* ------------------------------------------------------------------------ *
* Copyright (C) 1996 - 2001 Haslage Net Electronics: MudWorld of Lorain, *
* Ohio. ALL RIGHTS RESERVED See /doc/RMLicense.txt for more details. *
****************************************************************************/
/****************************************************************************
* [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 <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#include "mud.h"
/*
* Externals
*/
void subtract_times( struct timeval *etime, struct timeval *sttime );
bool check_disabled( CMDTYPE * cmd );
bool check_social( CHAR_DATA * ch, char *command, char *argument );
bool check_alias( CHAR_DATA * ch, char *command );
bool chan_alias( char *argument );
char *check_cmd_flags( 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, short position )
{
if( IS_NPC( ch ) && ch->position > 3 ) /*Band-aid alert? -- Blod */
return TRUE;
if( ch->position < position )
{
switch ( ch->position )
{
case POS_DEAD:
send_to_char( "A little difficult to do when you are DEAD...\r\n", ch );
break;
case POS_MORTAL:
case POS_INCAP:
send_to_char( "You are hurt far too bad for that.\r\n", ch );
break;
case POS_STUNNED:
send_to_char( "You are too stunned to do that.\r\n", ch );
break;
case POS_SLEEPING:
send_to_char( "In your dreams, or what?\r\n", ch );
break;
case POS_RESTING:
send_to_char( "Nah... You feel too relaxed...\r\n", ch );
break;
case POS_SITTING:
send_to_char( "You can't do that sitting down.\r\n", ch );
break;
case POS_FIGHTING:
if( position <= POS_EVASIVE )
{
send_to_char( "This fighting style is too demanding for that!\r\n", ch );
}
else
{
send_to_char( "No way! You are still fighting!\r\n", ch );
}
break;
case POS_DEFENSIVE:
if( position <= POS_EVASIVE )
{
send_to_char( "This fighting style is too demanding for that!\r\n", ch );
}
else
{
send_to_char( "No way! You are still fighting!\r\n", ch );
}
break;
case POS_AGGRESSIVE:
if( position <= POS_EVASIVE )
{
send_to_char( "This fighting style is too demanding for that!\r\n", ch );
}
else
{
send_to_char( "No way! You are still fighting!\r\n", ch );
}
break;
case POS_BERSERK:
if( position <= POS_EVASIVE )
{
send_to_char( "This fighting style is too demanding for that!\r\n", ch );
}
else
{
send_to_char( "No way! You are still fighting!\r\n", ch );
}
break;
case POS_EVASIVE:
send_to_char( "No way! You are still fighting!\r\n", 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\r\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\r\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 *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!\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( command && !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->council2
&& is_name( cmd->name, ch->pcdata->council2->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( xIS_SET( ch->act, PLR_AFK ) && !IS_NPC( ch ) )
{
xREMOVE_BIT( ch->act, PLR_AFK );
if( ch->pcdata->afkmsg )
{
STRFREE( ch->pcdata->afkmsg );
ch->pcdata->afkmsg = NULL;
}
act( AT_GREY, "$n is no longer away.", ch, NULL, NULL, TO_CANSEE );
send_to_char( "You are no longer flagged as being away.\r\n", ch );
}
}
/*
* Log and snoop.
*/
/*
sprintf( lastplayercmd, "** %s: %s", ch->name, logline );
*/
if( IS_NPC( ch ) )
sprintf( lastplayercmd, "(%d)%s, in room %d, used %s",
ch->pIndexData->vnum, ch->name, ch->in_room ? ch->in_room->vnum : 0, logline );
else
sprintf( lastplayercmd, "%s, in room %d, used %s", ch->name, ch->in_room ? ch->in_room->vnum : 0, logline );
if( found && cmd->log == LOG_NEVER )
strcpy( logline, "XXXXXXXX XXXXXXXX XXXXXXXX" );
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( check_disabled( cmd ) )
{
send_to_char( "That command is disabled.\r\n", ch );
return;
}
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;
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 );
}
/*
* 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_alias( ch, command )
&& !local_channel_hook( ch, command, argument )
&& !check_skill( ch, command, argument )
&& !check_social( ch, command, argument ) && !news_cmd_hook( ch, command, argument )
#ifdef I3
&& !I3_command_hook( ch, command, argument )
#endif
#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 they've set outputprefix, spam it here! -- Scion
*/
if( !IS_NPC( ch ) && ch->pcdata->outputprefix )
{
send_to_char( ch->pcdata->outputprefix, ch );
send_to_char( "\n", ch );
}
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 );
/*
* If they've set outputsuffix, spam it here! -- Scion
*/
if( !IS_NPC( ch ) && ch->pcdata->outputsuffix )
{
send_to_char( ch->pcdata->outputsuffix, ch );
send_to_char( "\n", ch );
}
return;
}
move_char( ch, pexit, 0 );
return;
}
no_find( ch );
}
return;
}
/*
* Character not in position for command?
*/
if( !check_pos( ch, cmd->position ) )
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;
}
/*
* If they've set outputprefix, spam it here! -- Scion
*/
if( !IS_NPC( ch ) && ch->pcdata->outputprefix )
{
send_to_char( ch->pcdata->outputprefix, ch );
send_to_char( "\n", ch );
}
/*
* 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 ) )
{
no_find( 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 );
/*
* Command's done, send the outputsuffix if they want it -- Scion
*/
if( !IS_NPC( ch ) && ch->pcdata->outputsuffix )
{
send_to_char( ch->pcdata->outputsuffix, ch );
send_to_char( "\n", ch );
}
/*
* 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:%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 );
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 they've set outputprefix, spam it here! -- Scion
*/
if( !IS_NPC( ch ) && ch->pcdata->outputprefix )
{
send_to_char( ch->pcdata->outputprefix, ch );
send_to_char( "\n", ch );
}
if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_NO_EMOTE ) )
{
send_to_char( "You are anti-social!\r\n", ch );
return TRUE;
}
switch ( ch->position )
{
case POS_DEAD:
send_to_char( "Lie still; you are DEAD.\r\n", ch );
return TRUE;
case POS_INCAP:
case POS_MORTAL:
send_to_char( "You are hurt far too bad for that.\r\n", ch );
return TRUE;
case POS_STUNNED:
send_to_char( "You are too stunned to do that.\r\n", 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?\r\n", 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.\r\n", 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.\r\n", victim->name );
break;
}
}
if( !victim )
{
if( ( ( victim = get_char_world( ch, arg ) ) == NULL ) || !IS_IMMORTAL( ch ) )
send_to_char( "They aren't here.\r\n", ch );
else
{
char buf[MAX_STRING_LENGTH];
sprintf( buf, "From afar, %s", social->char_found );
act( AT_SOCIAL, buf, ch, NULL, victim, TO_CHAR );
sprintf( buf, "From afar, %s", social->others_found );
act( AT_SOCIAL, buf, ch, NULL, victim, TO_ROOM );
act( AT_SOCIAL, buf, victim, NULL, ch, TO_ROOM );
sprintf( buf, "From afar, %s", social->vict_found );
act( AT_SOCIAL, buf, ch, NULL, victim, TO_VICT );
}
}
}
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
{
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 ) ) /* was IS_EVIL(ch) ||.... didn't make sense to me - FB */
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 );
}
/*
* If they've set outputsuffix, spam it here! -- Scion
*/
if( !IS_NPC( ch ) && ch->pcdata->outputsuffix )
{
send_to_char( ch->pcdata->outputsuffix, ch );
send_to_char( "\n", ch );
}
return TRUE;
}
typedef struct alias_var ALIAS_VAR;
/*
* Alias variable structure
*/
struct alias_var
{
char *value;
};
/*
* Alias Command Parser
* June 24, 1999 - Fixed rather annoying wait state bug in alias parser - Justice@AaernMUD
*/
bool check_alias( CHAR_DATA * ch, char *command )
{
ALIAS_DATA *alias;
ALIAS_QUEUE *queue;
ALIAS_QUEUE *new_queue;
ALIAS_QUEUE *first;
char buf[MAX_STRING_LENGTH];
int str = 0;
int i = 0;
int aliaslimit = 0; /* To prevent recursive alias stacking -- Scion */
if( IS_NPC( ch ) )
return FALSE;
for( alias = ch->pcdata->first_alias; alias; alias = alias->next )
{
if( !str_cmp( alias->name, command ) )
break;
}
if( !alias )
return FALSE;
queue = ch->pcdata->alias_queue;
first = ch->pcdata->alias_queue;
while( queue && queue->next )
queue = queue->next;
buf[0] = '\0';
for( str = 0; alias->alias[str] != '\0'; str++ )
{
aliaslimit++;
if( aliaslimit >= 1000 )
{
sprintf( buf, "Alias limit reached on character %s!", ch->name );
ch->pcdata->alias_queue = NULL;
return TRUE;
}
if( alias->alias[str] == ';' && strlen( buf ) > 0 )
{
if( sysdata.alias_wait != -1 )
WAIT_STATE( ch, sysdata.alias_wait + ch->wait );
else
WAIT_STATE( ch, 4 + ch->wait );
/*
* Add command to the alias queue -- Scion
*/
CREATE( new_queue, ALIAS_QUEUE, 1 );
new_queue->next = NULL;
new_queue->cmd = str_dup( buf );
i = 0;
if( queue )
{
queue->next = new_queue;
queue = queue->next;
}
else
{
queue = new_queue;
first = queue;
}
}
/*
* else if (alias->alias[str]=='%') {}
*/
else
{
buf[i] = alias->alias[str];
buf[i + 1] = '\0';
i++;
}
}
/*
* Add the last command to the alias queue -- Scion
*/
CREATE( new_queue, ALIAS_QUEUE, 1 );
new_queue->next = NULL;
new_queue->cmd = str_dup( buf );
i = 0;
if( queue )
{
queue->next = new_queue;
queue = queue->next;
}
else
{
queue = new_queue;
first = queue;
}
ch->pcdata->alias_queue = first;
return TRUE;
}
/*
* Return true if an argument is completely numeric.
*/
bool is_number( char *arg )
{
if( *arg == '\0' )
return FALSE;
for( ; *arg != '\0'; arg++ )
{
if( !isdigit( *arg ) )
return 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;
short count;
count = 0;
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 = '\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;
short count;
count = 0;
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 sttime;
struct timeval etime;
static bool timing;
extern CHAR_DATA *timechar;
char arg[MAX_INPUT_LENGTH];
send_to_char( "Timing\r\n", ch );
if( timing )
return;
one_argument( argument, arg );
if( !*arg )
{
send_to_char( "No command to time.\r\n", ch );
return;
}
if( !str_cmp( arg, "update" ) )
{
if( timechar )
send_to_char( "Another person is already timing updates.\r\n", ch );
else
{
timechar = ch;
send_to_char( "Setting up to record next update loop.\r\n", ch );
}
return;
}
set_char_color( AT_PLAIN, ch );
send_to_char( "Starting timer.\r\n", ch );
timing = TRUE;
gettimeofday( &sttime, NULL );
interpret( ch, argument );
gettimeofday( &etime, NULL );
timing = FALSE;
set_char_color( AT_PLAIN, ch );
send_to_char( "Timing complete.\r\n", ch );
subtract_times( &etime, &sttime );
ch_printf( ch, "Timing took %ld.%06ld seconds.\r\n", etime.tv_sec, etime.tv_usec );
return;
}
void start_timer( struct timeval *sttime )
{
if( !sttime )
{
bug( "Start_timer: NULL sttime.", 0 );
return;
}
gettimeofday( sttime, NULL );
return;
}
time_t end_timer( struct timeval * sttime )
{
struct timeval etime;
/*
* Mark etime before checking stime, so that we get a better reading..
*/
gettimeofday( &etime, NULL );
if( !sttime || ( !sttime->tv_sec && !sttime->tv_usec ) )
{
bug( "End_timer: bad sttime.", 0 );
return 0;
}
subtract_times( &etime, sttime );
/*
* stime becomes time used
*/
*sttime = 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.\r\n", vtime->num_uses );
ch_printf( ch, "Time (in secs): min %ld.%06ld; avg: %ld.%06ld; max %ld.%06ld\r\n",
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!\r\n", 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!\r\n", cmd->name );
else
cmd_flag_buf[0] = '\0';
return cmd_flag_buf;
}
void do_alias( CHAR_DATA * ch, char *argument )
{
ALIAS_DATA *alias = NULL;
char arg[MAX_INPUT_LENGTH];
if( IS_NPC( ch ) )
{
send_to_char( "Mobs can't use aliases.\r\n", ch );
return;
}
if( !argument || argument[0] == '\0' )
{
if( !ch->pcdata->first_alias )
{
send_to_char( "You don't have any aliases.\r\n", ch );
return;
}
else
{
int count = 0;
send_to_char( "You have the following aliases:\r\n", ch );
for( alias = ch->pcdata->first_alias; alias; alias = alias->next, count++ )
ch_printf( ch, "%s %s\r\n", alias->name, alias->alias );
ch_printf( ch, "You have %d alias%s.\r\n", count, count == 1 ? "" : "es" );
return;
}
}
argument = one_argument( argument, arg );
for( alias = ch->pcdata->first_alias; alias; alias = alias->next )
if( !str_cmp( arg, alias->name ) )
break;
if( !alias )
{
if( argument[0] == '\0' )
{
ch_printf( ch, "You don't have any alias called %s.\r\n", arg );
return;
}
CREATE( alias, ALIAS_DATA, 1 );
alias->name = strdup( arg );
alias->alias = strdup( argument );
LINK( alias, ch->pcdata->first_alias, ch->pcdata->last_alias, next, prev );
send_to_char( "Alias Added:\r\n", ch );
ch_printf( ch, "%s %s\r\n", alias->name, alias->alias );
return;
}
if( argument[0] == '\0' )
{
UNLINK( alias, ch->pcdata->first_alias, ch->pcdata->last_alias, next, prev );
DISPOSE( alias );
send_to_char( "Alias deleted.\r\n", ch );
return;
}
send_to_char( "Alias Changed.\r\n", ch );
alias->alias = strdup( argument );
ch_printf( ch, "%s %s\r\n", alias->name, alias->alias );
return;
}
void no_find( CHAR_DATA * ch )
{
switch ( number_range( 1, 10 ) )
{
default:
send_to_char( "Error: HUH?!?\r\n", ch );
return;
case 2:
send_to_char( "Error: That command could not be found.\r\n", ch );
return;
case 3:
send_to_char( "Error: Try spelling that in English next time.\r\n", ch );
return;
case 4:
send_to_char( "Error: No hablo Espaniol.\r\n", ch );
return;
case 5:
send_to_char( "Error: It is time for you to take up a typing class.\r\n", ch );
return;
case 6:
send_to_char( "Error: Wake Up! You are obviously sleeping at the keyboard.\r\n", ch );
return;
case 7:
send_to_char( "Error: I must have been absent the day that command was created.\r\n", ch );
return;
case 8:
send_to_char( "Error: Would you like fries with that?\r\n", ch );
return;
case 9:
send_to_char( "Error: Visit MudWorld at http://mudworld.inetsolve.com/.\r\n", ch );
return;
case 10:
send_to_char( "Error: ResortMUD is a product of Haslage Net Electronics MUD Division.\r\n", ch );
return;
}
}
bool chan_alias( char *argument )
{
char arg1[MIL];
/* char buf[MAX_STRING_LENGTH]; */
/* char buf[MSL]; */
argument = one_argument( argument, arg1 );
if( !str_cmp( arg1, "imm" ) || !str_cmp( arg1, "av" ) )
return TRUE;
else
return FALSE;
}