rogue25b2/gods/
rogue25b2/player/
rogue25b2/space/planets/
rogue25b2/space/prototypes/
rogue25b2/space/ships/
rogue25b2/src/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments 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          *
 *  benefitting.  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			   *
***************************************************************************/

#include "merc.h"
#include "interp.h"
#include "recycle.h"
#include "staffcmds.h"

extern int nAllocPerm;
extern int nAllocString;

char	last_command[MAX_STRING_LENGTH];

bool	check_social	args( ( CHAR_DATA *ch, char *command,
			    char *argument ) );


/*
 * Log-all switch.
 */
bool				fLogAll		= FALSE;



/*
 * Command Table
 * Located:  rogue/data/commands.txt
 */

void order_table_com(void) {
    char letter;
    CMD_DATA *new_cmd_table, **temptable;
    int i, j, cnt, maxcnt = 0, cntl[27], ilet, calc;

    for (i = 0; i < 27; ++i)
	cntl[i] = 0;

    for (i = 0; i < 26; i++) {
	cnt = 0;

	for (j = 0; j < MAX_CMD; ++j) {
	    letter = LOWER(cmd_table[j].name[0]) - 'a';
	    if (i == (int)letter)
		cnt++;
	}

	if (cnt > maxcnt)
	    maxcnt = cnt;
    }

    temptable = (CMD_DATA **)calloc((maxcnt*27), sizeof(CMD_DATA *));

    for (i = 0; i < (maxcnt*27); ++i)
	temptable[i] = NULL;

    for (i = 0; i < MAX_CMD; ++i) {
	if (!isalpha(cmd_table[i].name[0]))
	    temptable[cntl[0]++] = &cmd_table[i];
	else {
	    letter = LOWER(cmd_table[i].name[0]);
	    ilet   = (int)letter;
	    ilet  -= 'a';
	    ilet++;
	    cntl[ilet]++;
	    calc = (maxcnt * ilet) + cntl[ilet];
	    temptable[calc] = &cmd_table[i];
	}
    }
    new_cmd_table = (CMD_DATA *)malloc(sizeof(CMD_DATA) * (MAX_CMD+1));

    i = cnt = 0;
    while (i < (maxcnt*27)) {
	if (temptable[i])
	    new_cmd_table[cnt++] = *temptable[i];
	i++;
    }

    new_cmd_table[MAX_CMD].name = str_dup("");
    free(temptable);
    free(cmd_table);
    cmd_table = new_cmd_table;
}

int num_letter[26];

void create_table_com(void) {
    int cmd;
    char letter;

    order_table_com();
    for (cmd = 0; cmd < 26; cmd++)
	num_letter[cmd] = -1;

    for (cmd = 0; *cmd_table[cmd].name != '\0'; ++cmd) {
	letter = LOWER(cmd_table[cmd].name[0]);

	if (!isalpha(letter))
	    continue;

	letter -= 'a';

	if (num_letter[(int)letter] == -1)
	    num_letter[(int)letter] = cmd;
    }
}

/*
 * The main entry point for executing commands.
 * Can be recursively called from 'at', 'order', 'force'.
 */
void interpret(CHAR_DATA *ch, char *argument) {
    bool found;
    int cmd, trust, length;
    char command[MAX_INPUT_LENGTH];
    char logline[MAX_INPUT_LENGTH];

    /*
     * 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 (PLR_FLAGGED(ch, PLR_FREEZE)) {
	send_to_char("You're totally frozen!\n\r", ch);
	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 [%d]: %s",
	RealName(ch), IN_ROOM(ch)->vnum, 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);

    /*
     * Look for command in command table.
     */
    found = FALSE;
    trust = get_trust(ch);
    length= strlen(command);
    for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++) {
	if ((command[0] == cmd_table[cmd].name[0])
	&& !strncmp(cmd_table[cmd].name, command, length)
	&& (length >= strlen(cmd_table[cmd].sort_as))
	&& (cmd_table[cmd].level <= trust)
	&& (!IS_STAFFCMD(cmd) || (cmd_table[cmd].staffcmd & STF_FLAGS(ch)))) {
	    found = TRUE;
	    break;
	}
    }

    /*
     * Log and snoop, readded - Mendanbar
     */
    if (IS_SET(cmd_table[cmd].log, LOG_NEVER))
	strcpy(logline, "");

    if (PLR_FLAGGED(ch, PLR_LOG) || fLogAll
    || (IS_SET(cmd_table[cmd].log, LOG_ALWAYS)))
	log("Log %s: %s", ch->name, logline);

    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))
	    send_to_char("Huh?\n\r", ch);
	return;
    }

    /*
     * Character not in position for command?
     */
    if ( ch->position < cmd_table[cmd].position )
    {
	switch( ch->position )
	{
	case POS_DEAD:
	    send_to_char( "Lie still; you are DEAD.\n\r", ch );
	    break;

	case POS_MORTAL:
	case POS_INCAP:
	    send_to_char( "You are hurt far too bad for that.\n\r", ch );
	    break;

	case POS_STUNNED:
	    send_to_char( "You are too stunned to do that.\n\r", ch );
	    break;

	case POS_SLEEPING:
	    send_to_char( "In your dreams, or what?\n\r", ch );
	    break;

	case POS_RESTING:
	    send_to_char( "Nah... You feel too relaxed...\n\r", ch);
	    break;

	case POS_SITTING:
	    send_to_char( "Better stand up first.\n\r",ch);
	    break;

	case POS_FIGHTING:
	    send_to_char( "No way!  You are still fighting!\n\r", ch);
	    break;

	}
	return;
    }

    if (ch->timer_event) {
	int tempsub = ch->substate;
	ch->substate = SUB_TIMER_DO_ABORT;
	(*ch->timer_func)(ch, "", 0);
//	(*ch->timer_func)(ch, ch->dest_buf, ch->timer_subcmd);
	if (ch->substate != SUB_TIMER_CANT_ABORT) {
	    ch->substate = tempsub;
	    ch->ExtractTimer();
	} else {
	    ch->substate = tempsub;
	    return;
	}
    }

    /*
     * Dispatch the command.
     */
    (*cmd_table[cmd].do_fun) (ch, argument, cmd_table[cmd].subcmd);

    tail_chain();
    return;
}

EVENTFUNC(timedCommandEvent) {
    CHAR_DATA *ch;
    TimedCommandEvent *TEData = (TimedCommandEvent *)event_obj;

    if (TEData == NULL || !(ch = TEData->ch))
	return 0;

    int tempsub = ch->substate;
    ch->substate = TEData->newstate;
    (*ch->timer_func)(ch, "", 0);
    ch->substate = tempsub;
    ch->timer_event = NULL;
    ch->ExtractTimer();
    return 0;
}

void CHAR_DATA::AddTimer(int time, DO_FUN *func, int newstate) {
    TimedCommandEvent *TEData;

    if (this->timer_event) {
	mudlogf(NRM, 103, TRUE, "%s had a timer attached at add_timer", RealName(this));
	this->timer_event->Cancel();
    }

    TEData = new TimedCommandEvent;

    TEData->ch = this;
    TEData->newstate = newstate;

    this->timer_event = new Event(timedCommandEvent, TEData, time);
    this->timer_func = func;
}

void CHAR_DATA::ExtractTimer(void) {
    if (this->timer_event) {
	this->timer_event->Cancel();
	this->timer_event = NULL;
    }
    this->timer_func = NULL;

    if (this->dest_buf)		FREE(this->dest_buf);
    if (this->dest_buf_2)	FREE(this->dest_buf_2);
}

/* function to keep argument safe in all commands -- no static strings */
/* ACMD(do_function) */
void do_function (CHAR_DATA *ch, DO_FUN *do_fun, char *argument, SInt32 subcmd) {
    char *command_string;
    
    /* copy the string */
    command_string = str_dup(argument);
    
    /* dispatch the command */
    (*do_fun) (ch, command_string, subcmd);

    /* free the string */
    free_string(command_string);
}

bool check_social( CHAR_DATA *ch, char *command, char *argument ) {
    int cmd, min_pos;
    bool found;
    OBJ_DATA *obj;
    CHAR_DATA *victim;
    char arg[MAX_INPUT_LENGTH];

    found = FALSE;
    for (cmd = 0; social_table[cmd].name[0] != '\0'; 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_MUTED)) {
	send_to_char( "You are anti-social!\n\r", ch );
	return TRUE;
    }
    if (GET_POS(ch) < (min_pos = social_table[cmd].min_pos)) {
	switch (ch->position) {
	case POS_DEAD:
		ch->Send("Lie still; you are DEAD.\n\r");
		return TRUE;
	case POS_INCAP:
	case POS_MORTAL:
		ch->Send("You are hurt far too bad for that.\n\r");
		return TRUE;
	case POS_STUNNED:
		ch->Send("You are too stunned to do that.\n\r");
		return TRUE;
	case POS_SLEEPING:
		ch->Send("In your dreams, or what?\n\r");
		return TRUE;
	case POS_RESTING:
		ch->Send("Nah... You feel too relaxed to do that..\n\r");
		return TRUE;
	case POS_SITTING:
		ch->Send("Maybe you should get on your feet?\n\r");
		return TRUE;
	case POS_FIGHTING:
		ch->Send("No way!  You're fighting for your life!\n\r");
		return TRUE;
	default:
		ch->Send("Ahh, you seem to be bugged, inform staff.\n\r");
		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_new(social_table[cmd].char_no_arg, ch, NULL, victim, TO_CHAR, min_pos, TRUE, FALSE);
    }
    else if (!(victim = get_char_room(ch, arg)))
    {
	if (*(social_table[cmd].char_obj_found) &&
	((obj = get_obj_list(ch, arg, IN_ROOM(ch)->contents)) ||
	(obj = get_obj_carry(ch, arg, ch)))) {
		act(social_table[cmd].others_obj_found, ch, obj, obj, TO_ROOM);
		act_new(social_table[cmd].char_obj_found, ch, obj, obj, TO_CHAR, min_pos, TRUE, FALSE);
	} else
		send_to_char( "They aren't here.\n\r", ch );
    }
    else if ( victim == ch )
    {
	act(social_table[cmd].others_auto, ch, NULL, victim, TO_ROOM);
	act_new(social_table[cmd].char_auto, ch, NULL, victim, TO_CHAR, min_pos, TRUE, FALSE);
    }
    else
    {
	act(social_table[cmd].others_found, ch, NULL, victim, TO_NOTVICT);
	act_new(social_table[cmd].char_found, ch, NULL, victim, TO_CHAR, min_pos, TRUE, FALSE);
	act_new(social_table[cmd].vict_found, ch, NULL, victim, TO_VICT, min_pos, TRUE, FALSE);
/*
	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_new(social_table[cmd].char_found,
		    victim, NULL, ch, TO_CHAR, min_pos, TRUE, FALSE);
		act_new(social_table[cmd].vict_found,
		    victim, NULL, ch, TO_VICT, min_pos, TRUE, FALSE);
		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 ( char *arg )
{
 
    if ( *arg == '\0' )
        return FALSE;
 
    if ( *arg == '+' || *arg == '-' )
        arg++;
 
    for ( ; *arg != '\0'; arg++ )
    {
        if ( !isdigit( *arg ) )
            return FALSE;
    }
 
    return TRUE;
}



/*
 * Given a string like 14.foo, return 14 and 'foo'
 */
int number_argument( char *argument, char *arg )
{
    char *pdot;
    int number;
    
    for ( pdot = argument; *pdot != '\0'; pdot++ )
    {
	if ( *pdot == '.' )
	{
	    *pdot = '\0';
	    number = atoi( argument );
	    *pdot = '.';
	    strcpy( arg, pdot+1 );
	    return number;
	}
    }

    strcpy( arg, argument );
    return 1;
}

/* 
 * Given a string like 14*foo, return 14 and 'foo'
*/
int mult_argument(char *argument, char *arg)
{
    char *pdot;
    int number;

    for ( pdot = argument; *pdot != '\0'; pdot++ )
    {
        if ( *pdot == '*' )
        {
            *pdot = '\0';
            number = atoi( argument );
            *pdot = '*';
            strcpy( arg, pdot+1 );
            return number;
        }
    }
 
    strcpy( arg, argument );
    return 1;
}

bool is_abbrev(const char *arg1, const char *arg2) {
        if (!*arg1 || !*arg2)
                return false;

        for (; *arg1 && *arg2; arg1++, arg2++)
                if (LOWER(*arg1) != LOWER(*arg2))
                        return false;

        if (!*arg1)     return true;
        else            return false;
}

char *any_one_arg(const char *argument, char *first_arg) {
  skip_spaces(argument);

  while (*argument && !isspace(*argument)) {
    *(first_arg++) = LOWER(*argument);
    argument++;
  }

  *first_arg = '\0';

  return const_cast<char *>(argument);
}

void half_chop(const char *string, char *arg1, char *arg2) {
  char *temp;

  temp = any_one_arg(string, arg1);
  skip_spaces(temp);
  strcpy(arg2, temp);
}

/*
 * Pick off one argument from a string and return the rest.
 * Understands quotes.
 */
char *one_argument( 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;
}

void skip_spaces(char *&string) {
	while (*string && isspace(*string))	string++;
}

void skip_spaces(const char *&string) {
	while (*string && isspace(*string))	string++;
}

char *two_arguments(char *argument, char *first_arg, char *second_arg) {
        return one_argument(one_argument(argument, first_arg), second_arg);
}

/*
 * Contributed by Alander.
 */
ACMD(do_commands) {
    int cmd, col;
    BUFFER *output=new_buf();
    char buf[MAX_STRING_LENGTH];
 
    col = 0;
    for ( cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
    {
        if ( cmd_table[cmd].level <  LVL_IMMORT && !IS_STAFFCMD(cmd)
	&&   cmd_table[cmd].level <= get_trust( ch ) 
	&&   cmd_table[cmd].show)
	{
	    sprintf( buf, "%-12s", cmd_table[cmd].name );
	    add_buf(output, buf);
	    if ( ++col % 6 == 0 )
		add_buf(output, "\n\r");
	}
    }
 
    if ( col % 6 != 0 )
	add_buf(output, "\n\r");
    page_to_char(buf_string(output), ch);
    free_buf(output);
    return;
}

ACMD(do_wizhelp) {
    CHAR_DATA *vict;
    char buf[MAX_STRING_LENGTH], arg[MIL];
    int cmd;
    int col;
 
    col = 0;
    argument = one_argument(argument, arg);

    if (arg[0] == '\0') vict = ch;
    else if (IS_IMMORTAL(ch)) {
	vict = get_char_world(ch, arg);
		if (!vict) {
			send_to_char("No such player.\r\n",ch);
			return;
		}
		if (get_trust(vict) > get_trust(ch))
		vict = ch;
	} else
		vict = ch;
	if (vict == NULL || IS_NPC(vict)) return;

    send_to_char("The following commands are allowed to you:\r\n",ch);
    for ( cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
    {
	if (((IS_STAFFCMD(cmd) && STF_FLAGGED(vict,cmd_table[cmd].staffcmd))
	|| (!IS_STAFFCMD(cmd) && (cmd_table[cmd].level >= LVL_IMMORT)
	&& (get_trust(vict) >= cmd_table[cmd].level)))
	&& cmd_table[cmd].show)
	{
	    sprintf( buf, "%-12s", cmd_table[cmd].name );
	    send_to_char( buf, ch );
	    if ( ++col % 6 == 0 )
		send_to_char( "\n\r", ch );
	}
    }
 
    if ( col % 6 != 0 )
	send_to_char( "\n\r", ch );
    return;
}