/************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvements 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 * * benefiting. 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 * *************************************************************************** * 1stMUD ROM Derivative (c) 2001-2003 by Ryan Jennings * * http://1stmud.dlmud.com/ <r-jenn@shaw.ca> * ***************************************************************************/ #include "merc.h" #include "interp.h" #include "signals.h" PROTOTYPE(bool check_social, (CHAR_DATA *, char *, const char *)); PROTOTYPE(bool check_disabled, (CHAR_DATA *, CMD_DATA *)); #define END_MARKER "END" /* for load_disabled() and save_disabled() */ /* * Log-all switch. */ CH_CMD(do_null) { chprintln(ch, "This is not a command, notify the immortals."); return; } bool cmd_level_ok(CHAR_DATA * ch, CMD_DATA * cmd) { return (get_trust(ch) >= cmd->level); } /* * The main entry point for executing commands. * Can be recursively called from 'at', 'order', 'force'. */ void interpret(CHAR_DATA * ch, const char *argument) { char command[MAX_INPUT_LENGTH]; char logline[MAX_INPUT_LENGTH]; CMD_DATA *cmd; /* * Strip leading spaces. */ while (isspace(*argument)) argument++; if (IS_NULLSTR(argument)) return; /* * No hiding. */ REMOVE_BIT(ch->affected_by, AFF_HIDE); /* * Implement freeze command. */ if (!IS_NPC(ch) && IS_SET(ch->act, PLR_FREEZE)) { chprintln(ch, "You're totally frozen!"); return; } strcpy(logline, argument); crash_info.desc = ch->desc; strcpy(crash_info.shrt_cmd, logline); sprintf(crash_info.long_cmd, "[%5ld] %s in [%5ld] %s: %s", IS_NPC(ch) ? ch->pIndexData->vnum : 0, IS_NPC(ch) ? ch->short_descr : ch->name, ch->in_room ? ch->in_room->vnum : 0, ch->in_room ? ch->in_room->name : "(not in a room)", logline); crash_info.cmd_status = 2; /* * Grab the command word. * Special parsing so ' can be a command, * also no spaces needed after punctuation. */ 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. */ for (cmd = command_hash[LOWER(command[0]) % 126]; cmd; cmd = cmd->next_hash) { if (!str_prefix(command, cmd->name) && cmd_level_ok(ch, cmd)) break; } /* * Log and snoop. */ if (cmd) { if (cmd->log == LOG_NEVER) strcpy(logline, ""); if ((!IS_NPC(ch) && IS_SET(ch->act, PLR_LOG)) || IS_SET(mud_info.mud_flags, MUD_LOGALL) || cmd->log == LOG_ALWAYS) { sprintf(log_buf, "Log %s: %s", ch->name, logline); wiznet(log_buf, ch, NULL, WIZ_SECURE, 0, get_trust(ch)); log_string(log_buf); } } if (ch->desc != NULL && ch->desc->snoop_by != NULL) { d_print(ch->desc->snoop_by, "% ", 2); d_println(ch->desc->snoop_by, logline, 0); } if (!cmd) { /* * Look for command in socials table. */ if (!check_social(ch, command, argument)) chprintln(ch, "Huh?"); return; } else if (check_disabled(ch, cmd)) { chprintln(ch, "This command has been temporarily disabled."); return; } /* * Character not in position for command? */ if (ch->position < cmd->position) { switch (ch->position) { case POS_DEAD: chprintln(ch, "Lie still; you are DEAD."); break; case POS_MORTAL: case POS_INCAP: chprintln(ch, "You are hurt far too bad for that."); break; case POS_STUNNED: chprintln(ch, "You are too stunned to do that."); break; case POS_SLEEPING: chprintln(ch, "In your dreams, or what?"); break; case POS_RESTING: chprintln(ch, "Nah... You feel too relaxed..."); break; case POS_SITTING: chprintln(ch, "Better stand up first."); break; case POS_FIGHTING: chprintln(ch, "No way! You are still fighting!"); break; default: break; } return; } crash_info.cmd_status = 1; /* * Dispatch the command. */ (*cmd->do_fun) (ch, argument); crash_info.cmd_status = 3; strcat(crash_info.shrt_cmd, " (Finished)"); strcat(crash_info.long_cmd, " (Finished)"); crash_info.cmd_status = 0; tail_chain(); return; } /* function to keep argument safe in all commands -- no static strings */ void do_function(CHAR_DATA * ch, DO_FUN * do_fun, const char *argument) { const char *command_string; /* copy the string */ command_string = str_dup(argument); /* dispatch the command */ (*do_fun) (ch, command_string); /* free the string */ free_string(command_string); } SOCIAL_DATA *find_social(const char *command) { SOCIAL_DATA *social; int hash; if (LOWER(command[0]) < 'a' || LOWER(command[0]) > 'z') hash = 0; else hash = (LOWER(command[0]) - 'a') + 1; for (social = social_hash[hash]; social; social = social->next_hash) { if (!str_prefix(command, social->name)) return social; } return NULL; } bool check_social(CHAR_DATA * ch, char *command, const char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; SOCIAL_DATA *cmd; if ((cmd = find_social(command)) == NULL) return FALSE; if (!IS_NPC(ch) && IS_SET(ch->comm, COMM_NOEMOTE)) { chprintln(ch, "You are anti-social!"); return TRUE; } switch (ch->position) { case POS_DEAD: chprintln(ch, "Lie still; you are DEAD."); return TRUE; case POS_INCAP: case POS_MORTAL: chprintln(ch, "You are hurt far too bad for that."); return TRUE; case POS_STUNNED: chprintln(ch, "You are too stunned to do that."); 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(cmd->name, "snore")) break; chprintln(ch, "In your dreams, or what?"); return TRUE; default: break; } one_argument(argument, arg); victim = NULL; if (IS_NULLSTR(arg)) { act(cmd->others_no_arg, ch, NULL, victim, TO_ROOM); act(cmd->char_no_arg, ch, NULL, victim, TO_CHAR); } else if ((victim = get_char_room(ch, NULL, arg)) == NULL) { chprintln(ch, "They aren't here."); } else if (victim == ch) { act(cmd->others_auto, ch, NULL, victim, TO_ROOM); act(cmd->char_auto, ch, NULL, victim, TO_CHAR); } else { if (is_ignoring(victim, ch->name, IGNORE_SOCIALS)) { act("$N is ignoring socials from you.", ch, NULL, victim, TO_CHAR); return TRUE; } act(cmd->others_found, ch, NULL, victim, TO_NOTVICT); act(cmd->char_found, ch, NULL, victim, TO_CHAR); act(cmd->vict_found, ch, NULL, victim, TO_VICT); 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(cmd->others_found, victim, NULL, ch, TO_NOTVICT); act(cmd->char_found, victim, NULL, ch, TO_CHAR); act(cmd->vict_found, victim, NULL, ch, TO_VICT); 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(const char *arg) { if (*arg == '\0') return FALSE; if (*arg == '+' || *arg == '-') arg++; for (; *arg != '\0'; arg++) { if (!isdigit(*arg)) return FALSE; } return TRUE; } static unsigned int x_argument(const char *argument, char arg[MAX_INPUT_LENGTH], char c) { char *p; char *q; int number; p = strchr(argument, c); if (p == NULL) { strcpy(arg, argument); return 1; } number = strtoul(argument, &q, 0); if (q != p) number = 0; strncpy(arg, p + 1, MAX_INPUT_LENGTH); return number; } /* * Given a string like 14.foo, return 14 and 'foo' */ unsigned int number_argument(const char *argument, char *arg) { return x_argument(argument, arg, '.'); } /* * Given a string like 14*foo, return 14 and 'foo' */ unsigned int mult_argument(const char *argument, char *arg) { return x_argument(argument, arg, '*'); } /* * Pick off one argument from a string and return the rest. * Understands quotes. */ const char *one_argument(const 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; } /* * Contributed by Alander. */ CH_CMD(do_commands) { CMD_DATA *cmd; int col; col = 0; for (cmd = cmd_first_sorted; cmd; cmd = cmd->next_sort) { if (cmd->level < LEVEL_HERO && cmd_level_ok(ch, cmd) && cmd->show) { chprintf(ch, "%-12s", cmd->name); if (++col % 6 == 0) chprintln(ch, ""); } } if (col % 6 != 0) chprintln(ch, ""); return; } CH_CMD(do_wizhelp) { CMD_DATA *cmd; int col; col = 0; for (cmd = cmd_first_sorted; cmd; cmd = cmd->next_sort) { if (cmd->level >= LEVEL_HERO && cmd_level_ok(ch, cmd) && cmd->show) { chprintf(ch, "%-12s", cmd->name); if (++col % 6 == 0) chprintln(ch, ""); } } if (col % 6 != 0) chprintln(ch, ""); return; } /* Syntax is: disable - shows disabled commands disable <command> - toggles disable status of command */ CH_CMD(do_disable) { CMD_DATA *i; DISABLED_DATA *p; char arg[MIL]; if (IS_NPC(ch)) { chprintln(ch, "RETURN first."); return; } argument = one_argument(argument, arg); if (IS_NULLSTR(arg)) /* Nothing specified. Show disabled commands. */ { if (!disabled_first) /* Any disabled at all ? */ { chprintln(ch, "There are no commands disabled."); return; } chprintln(ch, "Disabled commands:\n\r" "Command Level Disabled by Disabled for"); for (p = disabled_first; p; p = p->next) { chprintlnf(ch, "%-12s %5d %-12s %s", p->command->name, p->level, p->disabled_by, p->disabled_for); } return; } /* command given */ /* First check if it is one of the disabled commands */ for (p = disabled_first; p; p = p->next) if (!str_cmp(arg, p->command->name)) break; if (p) /* this command is disabled */ { /* Optional: The level of the imm to enable the command must equal or exceed level of the one that disabled it */ if (get_trust(ch) < p->level) { chprintln(ch, "This command was disabled by a higher power."); return; } /* Remove */ UNLINK(p, disabled_first, disabled_last, next, prev); free_string(p->disabled_by); /* free name of disabler */ free_string(p->disabled_for); free_mem(p); /* free node */ save_disabled(); /* save to disk */ chprintln(ch, "Command enabled."); } else /* not a disabled command, check if that command exists */ { /* Search for the command */ for (i = command_hash[LOWER(argument[0]) % 126]; i; i = i->next_hash) if (!str_cmp(i->name, argument)) break; /* Found? */ if (!i) { chprintln(ch, "No such command."); return; } /* IQ test */ if (i->do_fun == do_disable) { chprintln(ch, "You cannot disable the disable command."); return; } /* Can the imm use this command at all ? */ if (i->level > get_trust(ch)) { chprintln(ch, "You don't have access to that command; you cannot disable it."); return; } /* Disable the command */ alloc_mem(p, DISABLED_DATA, 1); p->command = i; p->disabled_by = str_dup(ch->name); /* save name of disabler */ p->disabled_for = str_dup(argument); p->level = get_trust(ch); /* save trust */ LINK(p, disabled_first, disabled_last, next, prev); chprintln(ch, "Command disabled."); save_disabled(); /* save to disk */ } } /* Check if that command is disabled Note that we check for equivalence of the do_fun pointers; this means that disabling 'chat' will also disable the '.' command */ bool check_disabled(CHAR_DATA * ch, CMD_DATA * command) { DISABLED_DATA *p; for (p = disabled_first; p; p = p->next) if (p->command->do_fun == command->do_fun) break; if (!p) return FALSE; if (!ch || IS_NULLSTR(p->disabled_for)) return TRUE; return is_exact_name(ch->name, p->disabled_for); } /* Load disabled commands */ void load_disabled() { READ_DATA *fp; DISABLED_DATA *p; char *name; CMD_DATA *i; disabled_first = NULL; fp = open_read(DISABLED_FILE); if (!fp) /* No disabled file.. no disabled commands : */ return; name = read_word(fp); while (str_cmp(name, END_MARKER)) /* as long as name is NOT END_MARKER :) */ { /* Find the command in the table */ for (i = command_hash[LOWER(name[0]) % 126]; i; i = i->next_hash) if (!str_cmp(i->name, name)) break; if (!i) /* command does not exist? */ { bug("Skipping uknown command in " DISABLED_FILE " file."); read_to_eol(fp); } else /* add new disabled command */ { alloc_mem(p, DISABLED_DATA, 1); p->command = i; p->level = read_number(fp); p->disabled_by = str_dup(read_word(fp)); p->disabled_for = read_string(fp); LINK(p, disabled_first, disabled_last, next, prev); } name = read_word(fp); } close_read(fp); } /* Save disabled commands */ void save_disabled() { WRITE_DATA *fp; DISABLED_DATA *p; if (!disabled_first) /* delete file if no commands are disabled */ { unlink(DISABLED_FILE); return; } fp = open_write(DISABLED_FILE); if (!fp) { bug("Could not open " DISABLED_FILE " for writing"); return; } for (p = disabled_first; p; p = p->next) fprintf(fp->stream, "'%s' %d '%s' %s~\n", p->command->name, p->level, p->disabled_by, p->disabled_for); fprintf(fp->stream, "%s\n", END_MARKER); close_write(fp); }