/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*************************************************************************** * ROM 2.4 is copyright 1993-1998 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@hypercube.org) * * Gabrielle Taylor (gtaylor@hypercube.org) * * Brian Moore (zump@rom.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * ***************************************************************************/ #include "merc.h" #include "interp.h" #include "recycle.h" #include "staffcmds.h" extern int nAllocPerm; extern int nAllocString; char last_command[MAX_STRING_LENGTH]; bool check_social args( ( CHAR_DATA *ch, char *command, char *argument ) ); /* * Log-all switch. */ bool fLogAll = FALSE; /* * Command Table * Located: rogue/data/commands.txt */ void order_table_com(void) { char letter; CMD_DATA *new_cmd_table, **temptable; int i, j, cnt, maxcnt = 0, cntl[27], ilet, calc; for (i = 0; i < 27; ++i) cntl[i] = 0; for (i = 0; i < 26; i++) { cnt = 0; for (j = 0; j < MAX_CMD; ++j) { letter = LOWER(cmd_table[j].name[0]) - 'a'; if (i == (int)letter) cnt++; } if (cnt > maxcnt) maxcnt = cnt; } temptable = (CMD_DATA **)calloc((maxcnt*27), sizeof(CMD_DATA *)); for (i = 0; i < (maxcnt*27); ++i) temptable[i] = NULL; for (i = 0; i < MAX_CMD; ++i) { if (!isalpha(cmd_table[i].name[0])) temptable[cntl[0]++] = &cmd_table[i]; else { letter = LOWER(cmd_table[i].name[0]); ilet = (int)letter; ilet -= 'a'; ilet++; cntl[ilet]++; calc = (maxcnt * ilet) + cntl[ilet]; temptable[calc] = &cmd_table[i]; } } new_cmd_table = (CMD_DATA *)malloc(sizeof(CMD_DATA) * (MAX_CMD+1)); i = cnt = 0; while (i < (maxcnt*27)) { if (temptable[i]) new_cmd_table[cnt++] = *temptable[i]; i++; } new_cmd_table[MAX_CMD].name = str_dup(""); free(temptable); free(cmd_table); cmd_table = new_cmd_table; } int num_letter[26]; void create_table_com(void) { int cmd; char letter; order_table_com(); for (cmd = 0; cmd < 26; cmd++) num_letter[cmd] = -1; for (cmd = 0; *cmd_table[cmd].name != '\0'; ++cmd) { letter = LOWER(cmd_table[cmd].name[0]); if (!isalpha(letter)) continue; letter -= 'a'; if (num_letter[(int)letter] == -1) num_letter[(int)letter] = cmd; } } /* * The main entry point for executing commands. * Can be recursively called from 'at', 'order', 'force'. */ void interpret(CHAR_DATA *ch, char *argument) { bool found; int cmd, trust, length; char command[MAX_INPUT_LENGTH]; char logline[MAX_INPUT_LENGTH]; /* * Strip leading spaces. */ while (isspace(*argument)) argument++; if (argument[0] == '\0') return; /* * No hiding. */ REMOVE_BIT(ch->affected_by, AFF_HIDE); /* * Implement freeze command. */ if (PLR_FLAGGED(ch, 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); sprintf(last_command, "%s in room [%d]: %s", RealName(ch), IN_ROOM(ch)->vnum, logline); 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. */ found = FALSE; trust = get_trust(ch); length= strlen(command); for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++) { if ((command[0] == cmd_table[cmd].name[0]) && !strncmp(cmd_table[cmd].name, command, length) && (length >= strlen(cmd_table[cmd].sort_as)) && (cmd_table[cmd].level <= trust) && (!IS_STAFFCMD(cmd) || (cmd_table[cmd].staffcmd & STF_FLAGS(ch)))) { found = TRUE; break; } } /* * Log and snoop, readded - Mendanbar */ if (IS_SET(cmd_table[cmd].log, LOG_NEVER)) strcpy(logline, ""); if (PLR_FLAGGED(ch, PLR_LOG) || fLogAll || (IS_SET(cmd_table[cmd].log, LOG_ALWAYS))) log("Log %s: %s", ch->name, logline); if (ch->desc != NULL && ch->desc->snoop_by != NULL) { 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 (!found) { /* Look for command in socials table. */ if (!check_social(ch, command, argument)) send_to_char("Huh?\n\r", ch); return; } /* * Character not in position for command? */ if ( ch->position < cmd_table[cmd].position ) { switch( ch->position ) { case POS_DEAD: send_to_char( "Lie still; 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( "Better stand up first.\n\r",ch); break; case POS_FIGHTING: send_to_char( "No way! You are still fighting!\n\r", ch); break; } return; } if (ch->timer_event) { int tempsub = ch->substate; ch->substate = SUB_TIMER_DO_ABORT; (*ch->timer_func)(ch, "", 0); // (*ch->timer_func)(ch, ch->dest_buf, ch->timer_subcmd); if (ch->substate != SUB_TIMER_CANT_ABORT) { ch->substate = tempsub; ch->ExtractTimer(); } else { ch->substate = tempsub; return; } } /* * Dispatch the command. */ (*cmd_table[cmd].do_fun) (ch, argument, cmd_table[cmd].subcmd); tail_chain(); return; } EVENTFUNC(timedCommandEvent) { CHAR_DATA *ch; TimedCommandEvent *TEData = (TimedCommandEvent *)event_obj; if (TEData == NULL || !(ch = TEData->ch)) return 0; int tempsub = ch->substate; ch->substate = TEData->newstate; (*ch->timer_func)(ch, "", 0); ch->substate = tempsub; ch->timer_event = NULL; ch->ExtractTimer(); return 0; } void CHAR_DATA::AddTimer(int time, DO_FUN *func, int newstate) { TimedCommandEvent *TEData; if (this->timer_event) { mudlogf(NRM, 103, TRUE, "%s had a timer attached at add_timer", RealName(this)); this->timer_event->Cancel(); } TEData = new TimedCommandEvent; TEData->ch = this; TEData->newstate = newstate; this->timer_event = new Event(timedCommandEvent, TEData, time); this->timer_func = func; } void CHAR_DATA::ExtractTimer(void) { if (this->timer_event) { this->timer_event->Cancel(); this->timer_event = NULL; } this->timer_func = NULL; if (this->dest_buf) FREE(this->dest_buf); if (this->dest_buf_2) FREE(this->dest_buf_2); } /* function to keep argument safe in all commands -- no static strings */ /* ACMD(do_function) */ void do_function (CHAR_DATA *ch, DO_FUN *do_fun, char *argument, SInt32 subcmd) { char *command_string; /* copy the string */ command_string = str_dup(argument); /* dispatch the command */ (*do_fun) (ch, command_string, subcmd); /* free the string */ free_string(command_string); } bool check_social( CHAR_DATA *ch, char *command, char *argument ) { int cmd, min_pos; bool found; OBJ_DATA *obj; CHAR_DATA *victim; char arg[MAX_INPUT_LENGTH]; found = FALSE; for (cmd = 0; social_table[cmd].name[0] != '\0'; cmd++) { if (command[0] == social_table[cmd].name[0] && !str_prefix( command, social_table[cmd].name)) { found = TRUE; break; } } if (!found) return FALSE; if (!IS_NPC(ch) && IS_SET(ch->comm, COMM_MUTED)) { send_to_char( "You are anti-social!\n\r", ch ); return TRUE; } if (GET_POS(ch) < (min_pos = social_table[cmd].min_pos)) { switch (ch->position) { case POS_DEAD: ch->Send("Lie still; you are DEAD.\n\r"); return TRUE; case POS_INCAP: case POS_MORTAL: ch->Send("You are hurt far too bad for that.\n\r"); return TRUE; case POS_STUNNED: ch->Send("You are too stunned to do that.\n\r"); return TRUE; case POS_SLEEPING: ch->Send("In your dreams, or what?\n\r"); return TRUE; case POS_RESTING: ch->Send("Nah... You feel too relaxed to do that..\n\r"); return TRUE; case POS_SITTING: ch->Send("Maybe you should get on your feet?\n\r"); return TRUE; case POS_FIGHTING: ch->Send("No way! You're fighting for your life!\n\r"); return TRUE; default: ch->Send("Ahh, you seem to be bugged, inform staff.\n\r"); return TRUE; } } one_argument( argument, arg ); victim = NULL; if ( arg[0] == '\0' ) { act(social_table[cmd].others_no_arg, ch, NULL, victim, TO_ROOM); act_new(social_table[cmd].char_no_arg, ch, NULL, victim, TO_CHAR, min_pos, TRUE, FALSE); } else if (!(victim = get_char_room(ch, arg))) { if (*(social_table[cmd].char_obj_found) && ((obj = get_obj_list(ch, arg, IN_ROOM(ch)->contents)) || (obj = get_obj_carry(ch, arg, ch)))) { act(social_table[cmd].others_obj_found, ch, obj, obj, TO_ROOM); act_new(social_table[cmd].char_obj_found, ch, obj, obj, TO_CHAR, min_pos, TRUE, FALSE); } else send_to_char( "They aren't here.\n\r", ch ); } else if ( victim == ch ) { act(social_table[cmd].others_auto, ch, NULL, victim, TO_ROOM); act_new(social_table[cmd].char_auto, ch, NULL, victim, TO_CHAR, min_pos, TRUE, FALSE); } else { act(social_table[cmd].others_found, ch, NULL, victim, TO_NOTVICT); act_new(social_table[cmd].char_found, ch, NULL, victim, TO_CHAR, min_pos, TRUE, FALSE); act_new(social_table[cmd].vict_found, ch, NULL, victim, TO_VICT, min_pos, TRUE, FALSE); /* if ( !IS_NPC(ch) && IS_NPC(victim) && !IS_AFFECTED(victim, AFF_CHARM) && IS_AWAKE(victim) && victim->desc == NULL) { switch ( number_bits( 4 ) ) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: act(social_table[cmd].others_found, victim, NULL, ch, TO_NOTVICT); act_new(social_table[cmd].char_found, victim, NULL, ch, TO_CHAR, min_pos, TRUE, FALSE); act_new(social_table[cmd].vict_found, victim, NULL, ch, TO_VICT, min_pos, TRUE, FALSE); break; case 9: case 10: case 11: case 12: act( "$n slaps $N.", victim, NULL, ch, TO_NOTVICT ); act( "You slap $N.", victim, NULL, ch, TO_CHAR ); act( "$n slaps you.", victim, NULL, ch, TO_VICT ); break; } } */ } return TRUE; } /* * Return true if an argument is completely numeric. */ bool is_number ( char *arg ) { if ( *arg == '\0' ) return FALSE; if ( *arg == '+' || *arg == '-' ) arg++; 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; } /* * Given a string like 14*foo, return 14 and 'foo' */ int mult_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; } bool is_abbrev(const char *arg1, const char *arg2) { if (!*arg1 || !*arg2) return false; for (; *arg1 && *arg2; arg1++, arg2++) if (LOWER(*arg1) != LOWER(*arg2)) return false; if (!*arg1) return true; else return false; } char *any_one_arg(const char *argument, char *first_arg) { skip_spaces(argument); while (*argument && !isspace(*argument)) { *(first_arg++) = LOWER(*argument); argument++; } *first_arg = '\0'; return const_cast<char *>(argument); } void half_chop(const char *string, char *arg1, char *arg2) { char *temp; temp = any_one_arg(string, arg1); skip_spaces(temp); strcpy(arg2, temp); } /* * Pick off one argument from a string and return the rest. * Understands quotes. */ char *one_argument( char *argument, char *arg_first ) { char cEnd; while ( isspace(*argument) ) argument++; cEnd = ' '; if ( *argument == '\'' || *argument == '"' ) cEnd = *argument++; while ( *argument != '\0' ) { if ( *argument == cEnd ) { argument++; break; } *arg_first = LOWER(*argument); arg_first++; argument++; } *arg_first = '\0'; while ( isspace(*argument) ) argument++; return argument; } void skip_spaces(char *&string) { while (*string && isspace(*string)) string++; } void skip_spaces(const char *&string) { while (*string && isspace(*string)) string++; } char *two_arguments(char *argument, char *first_arg, char *second_arg) { return one_argument(one_argument(argument, first_arg), second_arg); } /* * Contributed by Alander. */ ACMD(do_commands) { int cmd, col; BUFFER *output=new_buf(); char buf[MAX_STRING_LENGTH]; col = 0; for ( cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ ) { if ( cmd_table[cmd].level < LVL_IMMORT && !IS_STAFFCMD(cmd) && cmd_table[cmd].level <= get_trust( ch ) && cmd_table[cmd].show) { sprintf( buf, "%-12s", cmd_table[cmd].name ); add_buf(output, buf); if ( ++col % 6 == 0 ) add_buf(output, "\n\r"); } } if ( col % 6 != 0 ) add_buf(output, "\n\r"); page_to_char(buf_string(output), ch); free_buf(output); return; } ACMD(do_wizhelp) { CHAR_DATA *vict; char buf[MAX_STRING_LENGTH], arg[MIL]; int cmd; int col; col = 0; argument = one_argument(argument, arg); if (arg[0] == '\0') vict = ch; else if (IS_IMMORTAL(ch)) { vict = get_char_world(ch, arg); if (!vict) { send_to_char("No such player.\r\n",ch); return; } if (get_trust(vict) > get_trust(ch)) vict = ch; } else vict = ch; if (vict == NULL || IS_NPC(vict)) return; send_to_char("The following commands are allowed to you:\r\n",ch); for ( cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ ) { if (((IS_STAFFCMD(cmd) && STF_FLAGGED(vict,cmd_table[cmd].staffcmd)) || (!IS_STAFFCMD(cmd) && (cmd_table[cmd].level >= LVL_IMMORT) && (get_trust(vict) >= cmd_table[cmd].level))) && cmd_table[cmd].show) { sprintf( buf, "%-12s", cmd_table[cmd].name ); send_to_char( buf, ch ); if ( ++col % 6 == 0 ) send_to_char( "\n\r", ch ); } } if ( col % 6 != 0 ) send_to_char( "\n\r", ch ); return; }