/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// * * -----------------------------------------------------------| (0...0) * * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( * * -----------------------------------------------------------| {o o} * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~* * Tricops and Fireblade | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Command interpretation module * ****************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <string.h> #include <time.h> #define __retms__ #include "mud.h" /* * Externals */ void refresh_page(CHAR_DATA * ch); void subtract_times(struct timeval *etime, struct timeval *stime); bool check_social args((CHAR_DATA * ch, char *command, char *argument)); char *check_cmd_flags args((CHAR_DATA * ch, CMDTYPE * cmd)); void displayFightTimer(CHAR_DATA *ch) { if (ch->fight_timer % 2 == 1) ch_printf(ch, "You can't move that fast! Wait %d and a half more seconds...\n\r", ch->fight_timer/2); else ch_printf(ch, "You can't move that fast! Wait %d more seconds...\n\r", ch->fight_timer/2); } /* * Log-all switch. */ bool fLogAll = FALSE; CMDTYPE *command_hash[126]; /* hash table for cmd_table */ SOCIALTYPE *social_index[27]; /* hash table for socials */ /* * Character not in position for command? */ bool check_pos(CHAR_DATA * ch, sh_int position) { if (IS_NPC(ch) && ch->position > 3) /*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...\n\r", ch); break; case POS_MORTAL: case POS_INCAP: send_to_char("You are hurt far too bad for that.\n\r", ch); break; case POS_STUNNED: send_to_char("You are too stunned to do that.\n\r", ch); break; case POS_SLEEPING: send_to_char("In your dreams, or what?\n\r", ch); break; case POS_RESTING: send_to_char("Nah... You feel too relaxed...\n\r", ch); break; case POS_SITTING: send_to_char("You can't do that sitting down.\n\r", ch); break; case POS_FIGHTING: if (position <= POS_EVASIVE) { send_to_char("This fighting style is too demanding for that!\n\r", ch); } else { send_to_char("No way! You are still fighting!\n\r", ch); } break; case POS_DEFENSIVE: if (position <= POS_EVASIVE) { send_to_char("This fighting style is too demanding for that!\n\r", ch); } else { send_to_char("No way! You are still fighting!\n\r", ch); } break; case POS_AGGRESSIVE: if (position <= POS_EVASIVE) { send_to_char("This fighting style is too demanding for that!\n\r", ch); } else { send_to_char("No way! You are still fighting!\n\r", ch); } break; case POS_BERSERK: if (position <= POS_EVASIVE) { send_to_char("This fighting style is too demanding for that!\n\r", ch); } else { send_to_char("No way! You are still fighting!\n\r", ch); } break; case POS_EVASIVE: send_to_char("No way! You are still fighting!\n\r", ch); break; } return FALSE; } return TRUE; } extern char lastplayercmd[MIL * 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[MIL], buf[MSL]; 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; } void parse_mxp_version(CHAR_DATA *ch, char *argument) { char arg[MIL]; char client[MSL]; char version[MSL]; int x; int y; int after = 0; float fversion; if (!ch->desc) return; argument = one_argument(argument, arg); //Secure tag argument = one_argument(argument, arg); //Mxp Version tag argument = one_argument(argument, arg); //Client tag y = 0; for (x = 0;;x++) { if (arg[x] == '\0') { client[y] = '\0'; break; } if (arg[x] == '=') { after = 1; continue; } if (after) client[y++] = arg[x]; } argument = one_argument(argument, arg); //version tag y = after = 0; for (x = 0;;x++) { if (arg[x] == '\0' || arg[x] == '>') { version[y] = '\0'; break; } if (arg[x] == '=') { after = 1; continue; } if (after) version[y++] = arg[x]; } fversion = atof(version); if (ch->desc->mxpclient) STRFREE(ch->desc->mxpclient); ch->desc->mxpclient = STRALLOC(client); ch->desc->mxpversion = fversion; 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[MIL]; char logline[MIL]; char logname[MIL]; 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; } if (!str_infix("VERSION MXP", argument)) { parse_mxp_version(ch, argument); return; } found = FALSE; if (ch->substate == SUB_REPEATCMD) { DO_FUN *fun; if ((fun = ch->last_cmd) == NULL) { ch->substate = SUB_NONE; bug("interpret: SUB_REPEATCMD with NULL last_cmd", 0); return; } else { int x; /* * yes... we lose out on the hashing speediness here... * but the only REPEATCMDS are wizcommands (currently) */ for (x = 0; x < 126; x++) { for (cmd = command_hash[x]; cmd; cmd = cmd->next) if (cmd->do_fun == fun) { found = TRUE; break; } if (found) break; } if (!found) { cmd = NULL; bug("interpret: SUB_REPEATCMD: last_cmd invalid", 0); return; } sprintf(logline, "(%s) %s", cmd->name, argument); } } if (!cmd) { /* Changed the order of these ifchecks to prevent crashing. */ if (!argument || !strcmp(argument, "")) { bug("interpret: null argument!", 0); return; } /* * Strip leading spaces. */ while (isspace(*argument)) argument++; if (argument[0] == '\0') return; /* xREMOVE_BIT( ch->affected_by, AFF_HIDE ); */ /* * Implement freeze command. */ if (!IS_NPC(ch) && xIS_SET(ch->act, PLR_FREEZE)) { send_to_char("You're totally frozen!\n\r", ch); return; } /* * 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->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; } // Remove Away bit too -- Xerves if (xIS_SET(ch->act, PLR_AWAY)) { xREMOVE_BIT(ch->act, PLR_AWAY); act(AT_GREY, "$n is no longer away.", ch, NULL, NULL, TO_CANSEE); } /* * Turn off afk bit when any command performed. */ if (xIS_SET(ch->act, PLR_AFK) && (str_cmp(command, "AFK"))) { xREMOVE_BIT(ch->act, PLR_AFK); /* act( AT_GREY, "$n is no longer afk.", ch, NULL, NULL, TO_ROOM ); */ act(AT_GREY, "$n is no longer afk.", ch, NULL, NULL, TO_CANSEE); } } /* * Log and snoop. */ /* sprintf( lastplayercmd, "** %s: %s", ch->name, logline ); */ 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) && xIS_SET(ch->act, PLR_LOG)) || fLogAll || loglvl == LOG_BUILD || loglvl == LOG_HIGH || loglvl == LOG_ALWAYS) { /* Added by Narn to show who is switched into a mob that executes a logged command. Check for descriptor in case force is used. */ if (ch->desc && ch->desc->original) sprintf(log_buf, "Log %s (%s): %s", ch->name, ch->desc->original->name, logline); else sprintf(log_buf, "Log %s: %s", ch->name, logline); /* * Make it so a 'log all' will send most output to the log * file only, and not spam the log channel to death -Thoric */ if (fLogAll && loglvl == LOG_NORMAL && (IS_NPC(ch) || !xIS_SET(ch->act, PLR_LOG))) loglvl = LOG_ALL; /* This is handled in get_trust already */ /* if ( ch->desc && ch->desc->original ) log_string_plus( log_buf, loglvl, ch->desc->original->level ); else*/ log_string_plus(log_buf, loglvl, get_trust(ch)); } if (ch->desc && ch->desc->snoop_by) { sprintf(logname, "%s", ch->name); write_to_buffer(ch->desc->snoop_by, logname, 0); write_to_buffer(ch->desc->snoop_by, "% ", 2); write_to_buffer(ch->desc->snoop_by, logline, 0); write_to_buffer(ch->desc->snoop_by, "\n\r", 2); } /* 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_alias(ch, command, argument) && !check_social(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; } //Used with flee timer, don't remove the npc check if(!ch->fighting && !IS_NPC(ch)) ch->fight_timer = 0; if(ch->fight_timer > 0 && cmd->fcommand == 1 && !IS_NPC(ch)) { displayFightTimer(ch); return; } /* * Dispatch the command. */ ch->prev_cmd = ch->last_cmd; /* haus, for automapping */ ch->last_cmd = cmd->do_fun; start_timer(&time_used); (*cmd->do_fun) (ch, argument); end_timer(&time_used); /* * Update the record of how many times this command has been used (haus) */ update_userec(&time_used, &cmd->userec); tmptime = UMIN(time_used.tv_sec, 19) * 1000000 + time_used.tv_usec; /* laggy command notice: command took longer than 1.5 seconds */ if (tmptime > 1500000) { #ifdef TIMEFORMAT sprintf(log_buf, "[*****] LAG: %s: %s %s (R:%d S:%ld.%06ld)", ch->name, cmd->name, (cmd->log == LOG_NEVER ? "XXX" : argument), ch->in_room ? ch->in_room->vnum : 0, time_used.tv_sec, time_used.tv_usec); #else sprintf(log_buf, "[*****] LAG: %s: %s %s (R:%d S:%d.%06d)", ch->name, cmd->name, (cmd->log == LOG_NEVER ? "XXX" : argument), ch->in_room ? ch->in_room->vnum : 0, time_used.tv_sec, time_used.tv_usec); #endif log_string_plus(log_buf, LOG_NORMAL, get_trust(ch)); cmd->lag_count++; /* count the lag flags */ } tail_chain(); } CMDTYPE *find_command(char *command) { CMDTYPE *cmd; int hash; hash = LOWER(command[0]) % 126; for (cmd = command_hash[hash]; cmd; cmd = cmd->next) if (!str_prefix(command, cmd->name)) return cmd; return NULL; } SOCIALTYPE *find_social(char *command) { SOCIALTYPE *social; int hash; if (command[0] < 'a' || command[0] > 'z') hash = 0; else hash = (command[0] - 'a') + 1; for (social = social_index[hash]; social; social = social->next) if (!str_prefix(command, social->name)) return social; return NULL; } bool check_social(CHAR_DATA * ch, char *command, char *argument) { char arg[MIL]; char buf[MSL]; CHAR_DATA *victim; CHAR_DATA *victim2; SOCIALTYPE *social; CHAR_DATA *remfirst, *remlast, *remtemp; /* for ignore cmnd */ int away = 0; /* Gsocial check this is to easy -- Xerves */ if ((social = find_social(command)) == NULL) return FALSE; if (!IS_NPC(ch) && xIS_SET(ch->act, PLR_NO_EMOTE)) { send_to_char("You are anti-social!\n\r", ch); return TRUE; } switch (ch->position) { case POS_DEAD: send_to_char("Lie still; you are DEAD.\n\r", ch); return TRUE; case POS_INCAP: case POS_MORTAL: send_to_char("You are hurt far too bad for that.\n\r", ch); return TRUE; case POS_STUNNED: send_to_char("You are too stunned to do that.\n\r", ch); return TRUE; case POS_SLEEPING: /* * I just know this is the path to a 12" 'if' statement. :( * But two players asked for it already! -- Furey */ if (!str_cmp(social->name, "snore")) break; send_to_char("In your dreams, or what?\n\r", ch); return TRUE; } remfirst = NULL; remlast = NULL; remtemp = NULL; /* Search room for chars ignoring social sender and */ /* remove them from the room until social has been */ /* completed */ for (victim = ch->in_room->first_person; victim; victim = victim->next_in_room) { if (is_ignoring(victim, ch)) { if (!IS_IMMORTAL(ch) || get_trust(victim) > get_trust(ch)) { char_from_room(victim); LINK(victim, remfirst, remlast, next_in_room, prev_in_room); } else { set_char_color(AT_IGNORE, victim); ch_printf(victim, "You attempt to ignore %s," " but are unable to do so.\n\r", PERS_MAP(ch, victim)); } } } 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_new(ch, arg, 1)) == 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", PERS_MAP(victim, ch)); break; } } if ((victim2 = get_char_world(ch, arg)) == NULL) send_to_char("They aren't here.\n\r", ch); if (victim2 != NULL && IS_NPC(victim2)) send_to_char("They aren't here.\n\r", ch); if ((victim == NULL) && (victim2 != NULL) && (!IS_NPC(victim2))) { away = 1; victim = victim2; } if (away == 1) { sprintf(buf, "From a distance....%s", social->char_found); act(AT_SOCIAL, buf, ch, NULL, victim, TO_CHAR); sprintf(buf, "From a distance....%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_safe(victim, ch)) one_hit(victim, ch, TYPE_UNDEFINED, LM_BODY); 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; } void do_timecmd(CHAR_DATA * ch, char *argument) { struct timeval stime; struct timeval etime; static bool timing; extern CHAR_DATA *timechar; char arg[MIL]; 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[MSL]; 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; }