1stMud4.5.3/
1stMud4.5.3/backup/
1stMud4.5.3/bin/
1stMud4.5.3/bin/extras/
1stMud4.5.3/data/i3/
1stMud4.5.3/doc/1stMud/
1stMud4.5.3/doc/Diku/
1stMud4.5.3/doc/MPDocs/
1stMud4.5.3/doc/Rom/
1stMud4.5.3/notes/
/**************************************************************************
*  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;
	}

	strcpy(logline, argument);

	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?{x",
				"{?Pardon?{x",
				"{?What is command '%s'?{x",
				"{?Input error.{x",
				"{?Try again.{x",
				"{?I do not understand.{x",
				"{?Type commands for a list of commands.{x"
			};

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

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

	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 | TO_SOCIALS);
		act(cmd->char_no_arg, ch, NULL, victim, TO_CHAR | TO_SOCIALS);
	}
	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 | TO_SOCIALS);
		act(cmd->char_auto, ch, NULL, victim, TO_CHAR | TO_SOCIALS);
	}
	else
	{
		if (is_ignoring(victim, ch->name, IGNORE_SOCIALS))
		{
			act("$N is ignoring socials from you.", ch, NULL, victim,
				TO_CHAR | TO_SOCIALS);
			return true;
		}
		act(cmd->others_found, ch, NULL, victim, TO_NOTVICT | TO_SOCIALS);
		act(cmd->char_found, ch, NULL, victim, TO_CHAR | TO_SOCIALS);
		act(cmd->vict_found, ch, NULL, victim, TO_VICT | TO_SOCIALS);

		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 | TO_SOCIALS);
					act(cmd->char_found, victim, NULL, ch,
						TO_CHAR | TO_SOCIALS);
					act(cmd->vict_found, victim, NULL, ch,
						TO_VICT | TO_SOCIALS);
					break;

				case 9:
				case 10:
				case 11:
				case 12:
					act("$n slaps $N.", victim, NULL, ch,
						TO_NOTVICT | TO_SOCIALS);
					act("You slap $N.", victim, NULL, ch,
						TO_CHAR | TO_SOCIALS);
					act("$n slaps you.", victim, NULL, ch,
						TO_VICT | TO_SOCIALS);
					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";
}