/************************************************************************** * 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); DISABLED_DATA *disabled_first; #define END_MARKER "END" /* for load_disabled() and save_disabled() */ /* * Log-all switch. */ bool fLogAll = FALSE; char last_command[MAX_STRING_LENGTH]; char last_command2[MAX_INPUT_LENGTH]; DESCRIPTOR_DATA *last_descriptor; struct cmd_type *cmd_table; 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]; int 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 = 0; cmd_table[cmd].name[0] != '\0'; cmd++) { if (command[0] == cmd_table[cmd].name[0] && !str_prefix (command, cmd_table[cmd].name) && cmd_table[cmd].level <= trust) { found = TRUE; break; } } /* * Log and snoop. */ if (cmd_table[cmd].log == LOG_NEVER) strcpy (logline, ""); if ((!IS_NPC (ch) && IS_SET (ch->act, PLR_LOG)) || fLogAll || cmd_table[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_table[cmd])) { chprintln (ch, "This command has been temporarily disabled."); return; } /* * Character not in position for command? */ if (ch->position < cmd_table[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_table[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); } bool check_social (CHAR_DATA * ch, char *command, const char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; int cmd; bool found; found = FALSE; for (cmd = 0; social_table[cmd].name != NULL; 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_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 (social_table[cmd].name, "snore")) break; chprintln (ch, "In your dreams, or what?"); 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 (social_table[cmd].char_no_arg, ch, NULL, victim, TO_CHAR); } else if ((victim = get_char_room (ch, arg)) == NULL) { chprintln (ch, "They aren't here."); } else if (victim == ch) { act (social_table[cmd].others_auto, ch, NULL, victim, TO_ROOM); act (social_table[cmd].char_auto, ch, NULL, victim, TO_CHAR); } else { act (social_table[cmd].others_found, ch, NULL, victim, TO_NOTVICT); act (social_table[cmd].char_found, ch, NULL, victim, TO_CHAR); act (social_table[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 (social_table[cmd].others_found, victim, NULL, ch, TO_NOTVICT); act (social_table[cmd].char_found, victim, NULL, ch, TO_CHAR); act (social_table[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) { int cmd; int col; col = 0; for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++) { if (cmd_table[cmd].level < LEVEL_HERO && cmd_table[cmd].level <= get_trust (ch) && cmd_table[cmd].show) { chprintf (ch, "%-12s", cmd_table[cmd].name); if (++col % 6 == 0) chprintln (ch, ""); } } if (col % 6 != 0) chprintln (ch, ""); return; } CH_CMD (do_wizhelp) { int cmd; int col; col = 0; for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++) { if (cmd_table[cmd].level >= LEVEL_HERO && cmd_table[cmd].level <= get_trust (ch) && cmd_table[cmd].show) { chprintf (ch, "%-12s", cmd_table[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) { int i; DISABLED_DATA *p, *q; 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 */ if (disabled_first == p) /* node to be removed == head ? */ disabled_first = p->next; else /* Find the node before this one */ { for (q = disabled_first; q->next != p; q = q->next); /* empty for */ q->next = p->next; } 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 = 0; cmd_table[i].name[0] != '\0'; i++) if (!str_cmp (cmd_table[i].name, argument)) break; /* Found? */ if (cmd_table[i].name[0] == '\0') { chprintln (ch, "No such command."); return; } /* Can the imm use this command at all ? */ if (cmd_table[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 = &cmd_table[i]; p->disabled_by = str_dup (ch->name); /* save name of disabler */ p->level = get_trust (ch); /* save trust */ p->next = disabled_first; disabled_first = p; /* add before the current first element */ 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; int 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 = 0; cmd_table[i].name[0]; i++) if (!str_cmp (cmd_table[i].name, name)) break; if (!cmd_table[i].name[0]) /* 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 = &cmd_table[i]; p->level = fread_number (fp); p->disabled_by = str_dup (fread_word (fp)); p->next = disabled_first; disabled_first = p; } 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); }