/************************************************************************** * 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-2002 by Ryan Jennings * * http://1stmud.dlmud.com/ <r-jenn@shaw.ca> * ***************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #if !defined(WIN32) #include <unistd.h> #endif #include <time.h> #include "merc.h" #include "interp.h" bool check_social args((CHAR_DATA * ch, char *command, const char *argument)); bool check_disabled(const struct cmd_type *command); #define END_MARKER "END" /* for load_disabled() and save_disabled() */ /* * Log-all switch. */ char last_command[MAX_STRING_LENGTH]; char last_command2[MAX_INPUT_LENGTH]; DESCRIPTOR_DATA *last_descriptor; CH_CMD(do_null) { chprintln(ch, "This is not a command, notify the immortals."); return; } /* * 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; int trust; bool found; /* * 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 (!IS_NPC(ch) && IS_SET(ch->act, PLR_FREEZE)) { chprintln(ch, "You're totally frozen!"); 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[%ld]: %s.", ch->name, ch->in_room->vnum, argument); if (ch->desc != NULL) { sprintf(last_command2, "%s", argument); last_descriptor = ch->desc; } else { last_command2[0] = '\0'; } 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); for (cmd = command_hash[LOWER(command[0]) % 126]; cmd; cmd = cmd->next_hash) { if (!str_prefix(command, cmd->name) && cmd->level <= trust) { found = TRUE; break; } } /* * Log and snoop. */ if (found) { if (cmd->log == LOG_NEVER) strcpy(logline, ""); if ((!IS_NPC(ch) && IS_SET(ch->act, PLR_LOG)) || fLogAll || 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) { 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)) chprintln(ch, "Huh?"); return; } else if (check_disabled(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; } return; } /* * Dispatch the command. */ (*cmd->do_fun) (ch, argument); 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; } one_argument(argument, arg); victim = NULL; if (arg[0] == '\0') { 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 { 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; cmd; cmd = cmd->next) { if (cmd->level < LEVEL_HERO && cmd->level <= get_trust(ch) && 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; cmd; cmd = cmd->next) { if (cmd->level >= LEVEL_HERO && cmd->level <= get_trust(ch) && 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; if (IS_NPC(ch)) { chprintln(ch, "RETURN first."); return; } if (!argument[0]) /* 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"); for (p = disabled_first; p; p = p->next) { chprintlnf(ch, "%-12s %5d %-12s", p->command->name, p->level, p->disabled_by); } return; } /* command given */ /* First check if it is one of the disabled commands */ for (p = disabled_first; p; p = p->next) if (!str_cmp(argument, 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_mem(p); /* free node */ save_disabled(); /* save to disk */ chprintln(ch, "Command enabled."); } else /* not a disabled command, check if that command exists */ { /* IQ test */ if (!str_cmp(argument, "disable")) { chprintln(ch, "You cannot disable the disable command."); return; } /* 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; } /* 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->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(const struct cmd_type * command) { DISABLED_DATA *p; for (p = disabled_first; p; p = p->next) if (p->command->do_fun == command->do_fun) return TRUE; return FALSE; } /* Load disabled commands */ void load_disabled() { FILE *fp; DISABLED_DATA *p; char *name; CMD_DATA *i; disabled_first = NULL; fp = file_open(DISABLED_FILE, "r"); if (!fp) /* No disabled file.. no disabled commands : */ return; name = fread_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.", 0); fread_number(fp); /* level */ fread_word(fp); /* disabled_by */ } else /* add new disabled command */ { alloc_mem(p, DISABLED_DATA, 1); p->command = i; p->level = fread_number(fp); p->disabled_by = str_dup(fread_word(fp)); LINK(p, disabled_first, disabled_last, next, prev); } name = fread_word(fp); } file_close(fp); } /* Save disabled commands */ void save_disabled() { FILE *fp; DISABLED_DATA *p; if (!disabled_first) /* delete file if no commands are disabled */ { unlink(DISABLED_FILE); return; } fp = file_open(DISABLED_FILE, "w"); if (!fp) { bug("Could not open " DISABLED_FILE " for writing", 0); return; } for (p = disabled_first; p; p = p->next) fprintf(fp, "%s %d %s\n", p->command->name, p->level, p->disabled_by); fprintf(fp, "%s\n", END_MARKER); file_close(fp); }