1stMud/CVS/
1stMud/area/CVS/
1stMud/backup/CVS/
1stMud/bin/
1stMud/bin/CVS/
1stMud/bin/extras/
1stMud/bin/extras/CVS/
1stMud/data/CVS/
1stMud/data/i3/CVS/
1stMud/doc/1stMud/
1stMud/doc/1stMud/CVS/
1stMud/doc/CVS/
1stMud/doc/Diku/
1stMud/doc/Diku/CVS/
1stMud/doc/MPDocs/CVS/
1stMud/doc/Merc/CVS/
1stMud/doc/Rom/
1stMud/doc/Rom/CVS/
1stMud/log/CVS/
1stMud/notes/
1stMud/notes/CVS/
1stMud/player/CVS/
1stMud/player/backup/CVS/
1stMud/player/deleted/CVS/
1stMud/src/CVS/
1stMud/src/config/CVS/
1stMud/src/h/CVS/
1stMud/src/o/CVS/
1stMud/win/CVS/
/**************************************************************************
*  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-2004 by Markanth                *
*            http://www.firstmud.com/  <markanth@firstmud.com>            *
*         By using this code you have agreed to follow the term of        *
*             the 1stMud license in ../doc/1stMud/LICENSE                 *
***************************************************************************/


#include "merc.h"
#include "interp.h"
#include "data_table.h"
#include "recycle.h"
#include "tables.h"

Proto (bool check_social, (CharData *, char *, const char *));
Proto (bool check_disabled, (CharData *, CmdData *));



Do_Fun (do_null)
{
  chprintln (ch, "This command is nullified, please notify the immortals.");
  return;
}

bool
cmd_level_ok (CharData * ch, CmdData * cmd)
{
  return (get_trust (ch) >= cmd->level);
}


void
interpret (CharData * ch, const char *argument)
{
  char command[MAX_INPUT_LENGTH];
  char logline[MAX_INPUT_LENGTH];
  CmdData *cmd;


  while (isspace (*argument))
    argument++;
  if (NullStr (argument))
    return;


  RemBit (ch->affected_by, AFF_HIDE);


  if (!IsNPC (ch) && IsSet (ch->act, PLR_FREEZE))
    {
      chprintln (ch, "You're totally frozen!");
      return;
    }

  crash_info.status = CRASH_PRE_PROCESSING;
  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",
	   IsNPC (ch) ? ch->pIndexData->vnum : 0, IsNPC (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);


  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);
    }


  for (cmd = command_hash[tolower (command[0]) % MAX_CMD_HASH]; cmd;
       cmd = cmd->next_hash)
    {
      if (IsSet (cmd->flags, CMD_NOPREFIX) ? !str_cmp (command, cmd->name)
	  : !str_prefix (command, cmd->name) && cmd_level_ok (ch, cmd))
	break;
    }


  if (cmd)
    {
      if (ch->master && IsSet (cmd->flags, CMD_NO_ORDER))
	{
	  act ("You can't order $N to do that!", ch->master, NULL, ch,
	       TO_CHAR);
	  return;
	}

      if (cmd->log == LOG_NEVER)
	strcpy (logline, "");

      if ((!IsNPC (ch) && IsSet (ch->act, PLR_LOG))
	  || IsSet (mud_info.mud_flags, MUD_LOGALL) || cmd->log == LOG_ALWAYS)
	{
	  new_wiznet (ch, logline, WIZ_SECURE, true, get_trust (ch),
		      "Log $N: $t");
	}

    }

  if (ch->desc != NULL && ch->desc->snoop_by != NULL)
    {
      d_printlnf (ch->desc->snoop_by, "> %s", ch->name, logline);
    }
  if (!cmd)
    {

      if (!check_social (ch, command, argument)
#ifndef DISABLE_I3
	  && !I3_command_hook (ch, command, argument)
#endif
	)
	{
	  char *const huh_message[] = {
	    "Huh?",
	    "Pardon?",
	    "What is command '%s'?",
	    "Input error.",
	    "Try again.",
	    "I do not understand.",
	    "Type commands for a list of commands."
	  };

	  chprintlnf (ch, huh_message[number_range (0,
						    (sizeof (huh_message) /
						     sizeof (huh_message[0]) -
						     1))], command);
	}
      return;
    }
  else if (check_disabled (ch, cmd))
    {
      chprintlnf (ch, "%s has been temporarily disabled.", Upper (cmd->name));
      return;
    }


  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.status = CRASH_LIKELY;


  (*cmd->do_fun) (cmd->name, ch, argument);

  crash_info.status = CRASH_POST_PROCESSING;

  strcat (crash_info.shrt_cmd, " (Finished)");
  strcat (crash_info.long_cmd, " (Finished)");

  crash_info.status = CRASH_UNLIKELY;

  tail_chain ();
  return;
}


void
do_function (CharData * ch, Do_F * do_fun, const char *argument)
{
  const char *command_string;


  command_string = str_dup (argument);


  (*do_fun) (cmd_name (do_fun), ch, command_string);


  free_string (command_string);
}

SocialData *
find_social (const char *command)
{
  SocialData *social;
  int hash;

  if (tolower (command[0]) < 'a' || tolower (command[0]) > 'z')
    hash = 0;
  else
    hash = (tolower (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 (CharData * ch, char *command, const char *argument)
{
  char arg[MAX_INPUT_LENGTH];
  CharData *victim;
  SocialData *cmd;

  if ((cmd = find_social (command)) == NULL)
    return false;

  if (!IsNPC (ch) && IsSet (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:

      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 (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 (!IsNPC (ch) && IsNPC (victim) &&
	  !IsAffected (victim, AFF_CHARM) && IsAwake (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;
}


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;
}


unsigned int
number_argument (const char *argument, char *arg)
{
  return x_argument (argument, arg, '.');
}


unsigned int
mult_argument (const char *argument, char *arg)
{
  return x_argument (argument, arg, '*');
}


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 = tolower (*argument);
      arg_first++;
      argument++;
    }
  *arg_first = '\0';

  while (isspace (*argument))
    argument++;

  return argument;
}


Do_Fun (do_commands)
{
  CmdData *cmd;
  int i = 0;
  Buffer *b;
  Column Cd;
  int cat = NO_FLAG;

  if (!NullStr (argument)
      && (cat = (int) flag_value (cmd_categories, argument)) == NO_FLAG)
    {
      cmd_syntax (ch, NULL, n_fun, "<flag>", NULL);
      chprintln (ch, "Valid flags are:");
      show_flags (ch, cmd_categories);
      return;
    }

  b = new_buf ();
  set_cols (&Cd, ch, 6, COLS_BUF, b);

  for (cmd = cmd_first_sorted; cmd; cmd = cmd->next_sort)
    {
      if (cmd->level <= LEVEL_HERO && cmd_level_ok (ch, cmd) &&
	  cmd->category != CMDCAT_NOSHOW && (cat == NO_FLAG ||
					     cmd->category == (cmd_cat) cat))
	{
	  i++;
	  print_cols (&Cd, "%3d. %s", i, cmd->name);
	}
    }

  cols_nl (&Cd);

  if (i == 0)
    {
      if (cat != NO_FLAG)
	bprintlnf (b, "No commands found in the '%s' category.",
		   flag_string (cmd_categories, cat));
      else
	bprintln (b, "No commands found.");
    }

  sendpage (ch, buf_string (b));
  free_buf (b);
  return;
}

Do_Fun (do_wizhelp)
{
  CmdData *cmd;
  int i = 0;
  Column Cd;
  Buffer *b;

  b = new_buf ();
  set_cols (&Cd, ch, 6, COLS_BUF, b);

  for (cmd = cmd_first_sorted; cmd; cmd = cmd->next_sort)
    {
      if (cmd->level >= LEVEL_HERO && cmd_level_ok (ch, cmd) &&
	  cmd->category != CMDCAT_NOSHOW)
	{
	  i++;
	  print_cols (&Cd, "%3d. %s", i, cmd->name);
	}
    }

  cols_nl (&Cd);
  sendpage (ch, buf_string (b));
  free_buf (b);
  return;
}



Do_Fun (do_disable)
{
  CmdData *i;
  DisabledData *p;
  char arg[MIL];

  if (IsNPC (ch))
    {
      chprintln (ch, "RETURN first.");
      return;
    }

  argument = one_argument (argument, arg);

  if (NullStr (arg))
    {
      if (!disabled_first)
	{
	  chprintln (ch, "There are no commands disabled.");
	  return;
	}

      chprintln (ch, "Disabled commands:" NEWLINE
		 "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;
    }




  for (p = disabled_first; p; p = p->next)
    if (!str_cmp (arg, p->command->name))
      break;

  if (p)
    {


      if (get_trust (ch) < p->level)
	{
	  chprintln (ch, "This command was disabled by a higher power.");
	  return;
	}


      UnLink (p, disabled, next, prev);
      free_disabled (p);
      rw_disabled_data (act_write);
      chprintln (ch, "Command enabled.");
    }
  else
    {



      for (i = command_hash[tolower (arg[0]) % MAX_CMD_HASH]; i;
	   i = i->next_hash)
	if (!str_cmp (i->name, arg))
	  break;

      if (!i)
	{
	  chprintln (ch, "No such command.");
	  return;
	}


      if (i->do_fun == do_disable)
	{
	  chprintln (ch, "You cannot disable the disable command.");
	  return;
	}


      if (i->level > get_trust (ch))
	{
	  chprintln (ch,
		     "You don't have access to that command; you cannot disable it.");
	  return;
	}


      p = new_disabled ();
      p->command = i;
      p->disabled_by = str_dup (ch->name);
      p->disabled_for = str_dup (argument);
      p->level = get_trust (ch);
      Link (p, disabled, next, prev);

      chprintln (ch, "Command disabled.");
      rw_disabled_data (act_write);
    }
}


bool
check_disabled (CharData * ch, CmdData * command)
{
  DisabledData *p;

  for (p = disabled_first; p; p = p->next)
    if (p->command->do_fun == command->do_fun)
      break;

  if (!p)
    return false;

  if (!ch || NullStr (p->disabled_for))
    return true;

  return is_exact_name (ch->name, p->disabled_for);
}


void
cmd_syntax (CharData * ch, const char *title, const char *n_fun, ...)
{
  va_list args;
  char *str;
  size_t i;

  if (NullStr (n_fun) || !ch || !ch->desc)
    return;

  va_start (args, n_fun);

  str = va_arg (args, char *);

  if (str == NULL)
    return;

  if (NullStr (title))
    {
      if (ch->desc->editor != ED_NONE)
	title = olc_ed_name (ch->desc);
      else
	{
	  switch (number_range (1, 3))
	    {
	    default:
	    case 1:
	      title = "Syntax";
	      break;
	    case 2:
	      title = "Usage";
	      break;
	    case 3:
	      title = "Type";
	      break;
	    }
	}
    }

  i = strlen (title) + 1;

  chprintlnf (ch, "{W%s: {w%s %s{x", Upper (title), n_fun, str);

  while ((str = va_arg (args, char *)) != NULL)
      chprintlnf (ch, "{W%*c {w%s %s{x", i, ':', n_fun, str);

  va_end (args);
}

const char *
cmd_name (Do_F * dofun)
{
  CmdData *c;

  for (c = cmd_first; c; c = c->next)
    if (c->do_fun == dofun)
      return c->name;

  return "unknown";
}