/***************************************************************************
* STAR WARS REALITY 1.0 *
*--------------------------------------------------------------------------*
* Star Wars Reality Code Additions and changes from the Smaug Code *
* copyright (c) 1997 by Sean Cooper *
* -------------------------------------------------------------------------*
* Starwars and Starwars Names copyright(c) Lucas Film Ltd. *
*--------------------------------------------------------------------------*
* SMAUG 1.0 (C) 1994, 1995, 1996 by Derek Snider *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, *
* Scryn, Rennard, Swordbearer, Gorog, Grishnakh and Tricops *
* ------------------------------------------------------------------------ *
* 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 <sys/time.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"
/*
* Externals
*/
void subtract_times( struct timeval *etime, struct timeval *stime );
void refresh_page( CHAR_DATA *ch );
bool check_social args( ( CHAR_DATA *ch, char *command, char *argument ) );
void make_preg args( ( CHAR_DATA *mother, CHAR_DATA *father ) );
bool check_xsocial args( ( CHAR_DATA *ch, char *command, char *argument ) );
bool is_immune args( ( CHAR_DATA *ch, sh_int damtype ) );
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 */
XSOCIALTYPE *xsocial_index[27]; /* hash table for socials */
/*
* Character not in position for command?
*/
bool check_pos( CHAR_DATA *ch, sh_int position )
{
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:
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\r",
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\r",
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;
}
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!\n\r", 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;
}*/
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 ) )
|| ( !IS_NPC(ch) && ch->pcdata->bestowments && ch->pcdata->bestowments[0] != '\0'
&& is_name( cmd->name, ch->pcdata->bestowments ) ) ) )
{
found = TRUE;
break;
}
/*
* Turn off afk bit when any command performed.
*/
if ( 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 );
*/
act( AT_GREY, "$n is no longer afk.", ch, NULL, NULL, TO_CANSEE );
}
}
/*
* Log and snoop.
*/
/*
sprintf( lastplayercmd, "** %s: %s", ch->name, logline );
*/
sprintf( lastplayercmd, "%s used %s", ch->name, 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 ( ( !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, "\n\r", 2 );
}
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 socials table.
*/
if ( !found )
{
if ( !check_skill( ch, command, argument )
&& !check_social( ch, command, argument )
&& !check_xsocial( ch, command, argument ) )
{
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;
}
send_to_char( "Huh?\n\r", 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..\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 )
{
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 ( !IS_NPC(ch) && IS_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
{
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)
&& !IS_SET( victim->pIndexData->progtypes, ACT_PROG ) )
{
switch ( number_bits( 4 ) )
{
case 0:
if ( !xIS_SET(ch->in_room->room_flags, ROOM_SAFE )
|| IS_EVIL(ch) )
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 )
{
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;
sh_int 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;
sh_int 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;
}*/
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
cmd_flag_buf[0] = '\0';
return cmd_flag_buf;
}
XSOCIALTYPE *find_xsocial( char *command )
{
XSOCIALTYPE *xsocial;
int hash;
if ( command[0] < 'a' || command[0] > 'z' )
hash = 0;
else
hash = (command[0] - 'a') + 1;
for ( xsocial = xsocial_index[hash]; xsocial; xsocial = xsocial->next )
if ( !str_prefix( command, xsocial->name ) )
return xsocial;
return NULL;
}
bool check_xsocial( CHAR_DATA *ch, char *command, char *argument )
{
char arg[MAX_STRING_LENGTH];
CHAR_DATA *victim;
int stage;
int amount;
bool is_ok = FALSE;
bool one = FALSE;
bool two = FALSE;
char * const male_female[4] = { "Neutral", "Man", "Woman", "Man or Woman" };
XSOCIALTYPE *xsocial;
if ( (xsocial=find_xsocial(command)) == NULL )
return FALSE;
if (IS_NPC(ch))
return FALSE;
if ( !IS_NPC(ch) && IS_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:
send_to_char( "In your dreams, or what?\n\r", ch );
return TRUE;
}
one_argument( argument, arg );
victim = NULL;
if ( arg[0] == '\0' )
{
act( AT_XSOCIAL, xsocial->others_no_arg, ch, NULL, victim, TO_ROOM );
act( AT_XSOCIAL, xsocial->char_no_arg, ch, NULL, victim, TO_CHAR );
}
else if ( ( victim = get_char_room( ch, arg ) ) == NULL )
send_to_char( "They aren't here.\n\r", ch );
else if ( victim == ch )
{
act( AT_XSOCIAL, xsocial->others_auto, ch, NULL, victim, TO_ROOM );
act( AT_XSOCIAL, xsocial->char_auto, ch, NULL, victim, TO_CHAR );
}
else if (IS_NPC(victim))
send_to_char("You can only perform xsocials on players.\n\r",ch);
else if (ch->sex != SEX_MALE && ch->sex != SEX_FEMALE)
send_to_char("You must be either male or female to use these socials.\n\r",ch);
else if (victim->sex != SEX_MALE && victim->sex != SEX_FEMALE)
send_to_char("They must be either male or female for these socials.\n\r",ch);
else if (victim->sex != xsocial->genderto && xsocial->genderto != 0)
send_to_char("Please use this xsocial on a different gender.\n\r",ch);
else
{
if (xsocial->gender == SEX_MALE && ch->sex != SEX_MALE)
send_to_char("Only men can perform this type of social.\n\r",ch);
else if (xsocial->gender == SEX_FEMALE && ch->sex != SEX_FEMALE)
send_to_char("Only women can perform this type of social.\n\r",ch);
else if (xsocial->gender == ch->sex
&& ( xsocial->genderto != victim->sex && xsocial->genderto != 0 ) )
ch_printf( ch, "You can only perform this social on a %s.\n\r",
male_female[xsocial->genderto] );
else if ( !nifty_is_name( ch->name, victim->pcdata->x_partner)
|| !nifty_is_name( victim->name, ch->pcdata->x_partner ))
send_to_char("You cannot perform an xsocial on someone without their CONSENT.\n\r",ch);
else if (xsocial->stage == 0 && ch->pcdata->stage[0] < 1
&& ch->pcdata->stage[2] > 0 && ch->sex == SEX_MALE)
send_to_char("You have not yet recovered from last time!\n\r",ch);
else if (xsocial->stage == 0 && victim->pcdata->stage[0] < 1
&& victim->pcdata->stage[2] > 0 && victim->sex == SEX_MALE)
send_to_char("They have not yet recovered from last time!\n\r",ch);
else if (xsocial->stage > 0 && ch->pcdata->stage[0] < 100)
send_to_char("You are not sufficiently aroused.\n\r",ch);
else if (xsocial->stage > 0 && victim->pcdata->stage[0] < 100)
send_to_char("They are not sufficiently aroused.\n\r",ch);
else if (xsocial->stage > 1 && ch->pcdata->stage[1] < 1)
send_to_char("You are not in the right position.\n\r",ch);
else if (xsocial->stage > 1 && victim->pcdata->stage[1] < 1)
send_to_char("They are not in the right position.\n\r",ch);
else
{
act( AT_XSOCIAL, xsocial->others_found, ch, NULL, victim, TO_NOTVICT);
act( AT_XSOCIAL, xsocial->char_found, ch, NULL, victim, TO_CHAR );
act( AT_XSOCIAL, xsocial->vict_found, ch, NULL, victim, TO_VICT );
if (xsocial->chance)
{
if (ch->sex == SEX_FEMALE && !IS_SET(ch->act2, EXTRA_PREGNANT) )
{
if ( number_percent() <= 10 )
make_preg(ch,victim);
}
else if (victim->sex == SEX_FEMALE && !IS_SET(victim->act2, EXTRA_PREGNANT))
{
if ( number_percent() <= 10 )
make_preg(victim,ch);
}
}
if (xsocial->stage == 1)
{
ch->pcdata->stage[1] = xsocial->position;
victim->pcdata->stage[1] = xsocial->position;
if (!IS_SET(ch->act2, EXTRA_DONE))
{
SET_BIT(ch->act2, EXTRA_DONE);
if (ch->sex == SEX_FEMALE)
{
act(AT_XSOCIAL, "You feel $n bleed as you enter $m.",ch,NULL,victim,TO_VICT);
act(AT_XSOCIAL, "You feel yourself bleed as $N enters you.",ch,NULL,victim,TO_CHAR);
}
}
if (!IS_SET(victim->act2, EXTRA_DONE))
{
SET_BIT(victim->act2, EXTRA_DONE);
if (victim->sex == SEX_FEMALE)
{
act(AT_XSOCIAL, "You feel $N bleed as you enter $M.",ch,NULL,victim,TO_CHAR);
act(AT_XSOCIAL, "You feel yourself bleed as $n enters you.",ch,NULL,victim,TO_VICT);
}
}
stage = 2;
}
else stage = xsocial->stage;
if (stage == 2) amount = ch->pcdata->stage[1];
else amount = 100;
if (xsocial->self > 0)
{
is_ok = FALSE;
if (ch->pcdata->stage[stage] >= amount) is_ok = TRUE;
ch->pcdata->stage[stage] += xsocial->self;
if (!is_ok && ch->pcdata->stage[stage] >= amount)
{
stage_update(ch,victim,stage);
one = TRUE;
}
}
if (xsocial->other > 0)
{
is_ok = FALSE;
if (victim->pcdata->stage[stage] >= amount) is_ok = TRUE;
victim->pcdata->stage[stage] += xsocial->other;
if (!is_ok && victim->pcdata->stage[stage] >= amount)
{
stage_update(victim,ch,stage);
two = TRUE;
}
}
if ( one && two )
{
ch->pcdata->stage[0] = 0;
victim->pcdata->stage[0] = 0;
if (!IS_SET(ch->act2, EXTRA_EXP))
{
send_to_char("Congratulations on achieving a simultanious orgasm! Recieve 100000 exp!\n\r",ch);
SET_BIT(ch->act2, EXTRA_EXP);
ch->exp += 100000;
}
if (!IS_SET(victim->act2, EXTRA_EXP))
{
send_to_char("Congratulations on achieving a simultanious orgasm! Recieve 100000 exp!\n\r",victim);
SET_BIT(victim->act2, EXTRA_EXP);
victim->exp += 100000;
}
}
}
}
return TRUE;
}
void stage_update( CHAR_DATA *ch, CHAR_DATA *victim, int stage )
{
if (IS_NPC(ch) || IS_NPC(victim)) return;
if (stage == 0)
{
if (ch->sex == SEX_MALE)
{
send_to_char("You feel yourself harden.\n\r",ch);
act(AT_XSOCIAL, "You feel $n harden.",ch,NULL,victim,TO_VICT);
return;
}
else if (ch->sex == SEX_FEMALE)
{
send_to_char("You feel moist.\n\r",ch);
act(AT_XSOCIAL, "You feel $n dampen.",ch,NULL,victim,TO_VICT);
return;
}
}
else if (stage == 2)
{
if (ch->sex == SEX_MALE)
{
act(AT_XSOCIAL, "You clench your teeth as you cum in $M.",ch,NULL,victim,TO_CHAR);
act(AT_XSOCIAL, "$n clenches $s teeth as $e cums in you.",ch,NULL,victim,TO_VICT);
act(AT_XSOCIAL, "$n clenches $s teeth as $e cums in $N.",ch,NULL,victim,TO_NOTVICT);
make_cum(ch);
make_cum(victim);
ch->pcdata->stage[0] = 0;
ch->pcdata->stage[1] = 0;
ch->pcdata->genes[8] += 1;
victim->pcdata->genes[8] += 1;
save_char_obj( ch );
save_char_obj( victim );
if (ch->pcdata->stage[0] <= 250) ch->pcdata->stage[0] = 0;
else victim->pcdata->stage[0] -= 250;
victim->pcdata->stage[1] = 0;
if (victim->sex == SEX_FEMALE && !IS_SET(victim->act2, EXTRA_PREGNANT) /* && number_percent() <= 15 */ )
{
if ( number_percent() <= 10 )
make_preg(victim,ch);
}
return;
}
else if (ch->sex == SEX_FEMALE)
{
act(AT_XSOCIAL, "You wimper as you cum.",ch,NULL,victim,TO_CHAR);
act(AT_XSOCIAL, "$n wimpers as $e cums.",ch,NULL,victim,TO_ROOM);
if (victim->pcdata->stage[2] < 1 || victim->pcdata->stage[2] >= 250)
{
ch->pcdata->stage[2] = 0;
if (ch->pcdata->stage[0] >= 200) ch->pcdata->stage[0] -= 100;
}
else ch->pcdata->stage[2] = 200;
return;
}
}
return;
}
void make_preg( CHAR_DATA *mother, CHAR_DATA *father )
{
char buf [MAX_STRING_LENGTH];
if ( number_percent() > 50 ) return;
if ( IS_SET(mother->pcdata->cyber, CYBER_STERILE) || IS_SET(father->pcdata->cyber,CYBER_STERILE)) return;
if (IS_NPC(mother) || IS_NPC(father)) return;
if (IS_AFFECTED(mother, AFF_CONTRACEPTION)) return;
if (IS_AFFECTED(father, AFF_CONTRACEPTION)) return;
bug("%s is pregnant",mother->name,0);
mother->pcdata->pregnacy.hour = time_info.hour;
mother->pcdata->pregnacy.day = time_info.day;
mother->pcdata->pregnacy.month = time_info.month;
mother->pcdata->pregnacy.year = time_info.year;
sprintf(buf,"%s %s",mother->name,father->name);
STRFREE(mother->pcdata->cparents);
mother->pcdata->cparents = STRALLOC(buf);
SET_BIT(mother->act2, EXTRA_PREGNANT);
mother->pcdata->genes[1] = 0;
mother->pcdata->genes[2] = 0;
mother->pcdata->genes[3] = 0;
mother->pcdata->genes[4] = number_range(1,2); /* Babies Sex */
if (mother->race != father->race)
mother->pcdata->genes[5] = 23; /* Babies Race */
else
mother->pcdata->genes[5] = mother->race; /* Babies Race */
mother->pcdata->genes[0] = 0; /* mana */
mother->pcdata->genes[6] = 0; /* frc ability */
if ( mother->main_ability == father->main_ability )
mother->pcdata->genes[7] = mother->main_ability; /* Ability */
else
mother->pcdata->genes[7] = number_range(0,MAX_ABILITY); /* Ability */
return;
}
float percent(int part1, int part2)
{
if ( part2 == 0 )
{
/*bug("Divide By Zero");*/
return 0;
}
return ((part1*100)/part2);
}