atd/area/
atd/build/
atd/clans/
atd/log/
atd/player/store/
atd/site/
atd/src/bin/
	#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "build.h"

#define CMD_FILE DATA_DIR "commands.dat"

#define KEY( literal, field, value )                \
                                if ( !str_cmp( word, literal ) )        \
                {                                   \
                    field  = value;                 \
                    fMatch = TRUE;                  \
                    break;                          \
                                }

#define SKEY( string, field )                       \
    if ( !str_cmp( word, string ) )     \
    {                                   \
      free_string( field );           \
      field = fread_string( fp );     \
      fMatch = TRUE;                  \
      break;                          \
    }

void	load_commands( void );
void    save_commands( void );
struct cmd_list_type
{
    char *name;
    DO_FUN *function;
};

extern	bool		fBootDb;
int			MAX_CMD;

struct	cmd_type	*cmd_table;
void	  clear_table_commands args( ( void ) );



#if defined(COMMAND)
#undef COMMAND
#endif

#define COMMAND(cmd)	{	#cmd,	cmd	},

const	struct	cmd_list_type	cmd_list	[]	=
{
#include "commands.h"
	{	NULL,		NULL		}
};

#undef COMMAND
#define COMMAND(cmd)	DECLARE_DO_FUN(cmd);

const struct olc_cmd_type cmdedit_table[]	=
{
	{ "name",       cmdedit_name	 },
	{ "function",	cmdedit_function },
	{ "level",	cmdedit_level	 },
	{ "position",	cmdedit_position },
	{ "log",	cmdedit_log  	 },
	{ "new",	cmdedit_new	 },
	{ "delete",	cmdedit_delete	 },
	{ "list",	cmdedit_list	 },
	{ "show",	cmdedit_show	 },
	{ "commands",	show_commands	 },
        { "?",          show_help        },
        { "",		0		 }
};


char *	cmd_func_name( DO_FUN *command )
{
    int cmd;

    for ( cmd = 0; cmd_list[cmd].name; cmd++ )
        if ( cmd_list[cmd].function == command )
            return cmd_list[cmd].name;

    return "";
}

DO_FUN * cmd_func_lookup( char *arg )
{
    int cmd;

    for ( cmd = 0; cmd_list[cmd].name; cmd++ )
        if ( !str_cmp(cmd_list[cmd].name, arg) )
            return cmd_list[cmd].function;

    if ( fBootDb )
    {
        bugf( "Cmd_func_lookup : funcion %s non-exhistant.", arg );
        return do_nothing;
    }

    return NULL;
}

/*
 * Returns FALSE if not used in the cmd_table[cmd].function
 */
bool fun_lookup( DO_FUN *do_fun )
{
    int cmd;
    
    for( cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
    	if( cmd_table[cmd].do_fun == do_fun )
             return TRUE;
    return FALSE;
}

int cmd_lookup( char *arg )
{
    int cmd;

    for ( cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
        if ( LOWER(arg[0]) == LOWER(cmd_table[cmd].name[0])
             &&   !str_prefix( arg, cmd_table[cmd].name ) )
            return cmd;

    return -1;
}

void cmdedit( CHAR_DATA *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    char command[MAX_INPUT_LENGTH];
    struct cmd_type *pCmd;
    int cmd;

    EDIT_CMD( ch, pCmd );

    smash_tilde(argument);
    strcpy(arg, argument);
    argument = one_argument( argument, command);
    
    if( get_trust(ch) < LEVEL_JUDGE )
    {
        send_to_char("Insufficiant trust to edit commands.\n\r", ch);
        edit_done(ch);
        return;
    }
    
    if (command[0] == '\0')
    {
        cmdedit_show(ch, argument);
        return;
    }

    if (!str_cmp(command, "done") )
    {
        edit_done(ch);
        return;
    }

    if (!str_cmp(command, "save") )
    {
	send_to_char("Saving commands...", ch);
    	save_commands();
    	send_to_char("Done.\n\r", ch);
    	return;
    }

    /* Search Table and Dispatch Command. */
    for ( cmd = 0; *cmdedit_table[cmd].name; cmd++ )
    {
        if ( !str_prefix( command, cmdedit_table[cmd].name ) )
        {
            if ( (*cmdedit_table[cmd].olc_fun) ( ch, argument ) )
	    {
	        logf( NULL, "%s editing %s function.", 
			ch->name, pCmd->name );
                save_commands();
	    }
            return;
        }
    }

    if( ( cmd = flag_value( show_flags, arg ) ) != NO_FLAG )
    {
        TOGGLE_BIT( pCmd->show, cmd );
	send_to_char( "Done.\n\r", ch );
	save_commands();
	return;
    }

    interpret(ch, arg);
    return;
}

void do_cmdedit(CHAR_DATA *ch, char *argument)
{
    struct cmd_type *pCmd;
    char command[MSL];
    int comando;

    if ( IS_NPC(ch) )
    	return;

    if ( !argument || argument[0] == '\0' )
    {
    	send_to_char( "Syntax : CMDEdit [command]\n\r", ch );
    	return;
    }

    argument = one_argument( argument, command );

    if ( !str_cmp( command, "new" ) )
    {
	if ( cmdedit_new(ch, argument) )
            save_commands();
	return;
    }

    if ( !str_cmp( command, "delete" ) )
    {
    	if ( cmdedit_delete(ch, argument) )
    		save_commands();
    	return;
    }

    if( !str_cmp( command, "save_commands" ) )
    {
	save_commands();
	stc( "Done.\n\r", ch );
	return;
    }

    if ( (comando = cmd_lookup(command)) == -1 )
    {
    	send_to_char( "CMDEdit : Command non-exhistant.\n\r", ch );
    	return;
    }

    pCmd = &cmd_table[comando];

    set_editor( ch->desc, ED_CMD, pCmd );
    return;
}

CMDEDIT( cmdedit_show )
{
    struct	cmd_type *pCmd;
    char buf[MIL];

    EDIT_CMD( ch, pCmd );

    sprintf( buf, "{cName     {B: {n%s\n\r", pCmd->name );
    send_to_char( buf, ch );

    sprintf( buf, "{cFunction {B: {n%s\n\r",
		cmd_func_name(pCmd->do_fun) );
    send_to_char( buf, ch );

    sprintf( buf, "{cLevel    {B: {C[{n%d{C]\n\r",
		pCmd->level );
    send_to_char( buf, ch );

    sprintf( buf, "{cPosition {B: {C[{n%d{C]\n\r",
                pCmd->position );
    send_to_char( buf, ch );

    sprintf( buf, "{cLog      {B: {n%s\n\r",
             flag_string( log_flags, pCmd->log ) );
    send_to_char( buf, ch );

    sprintf( buf, "{cShowTo   {B: {n%s\n\r",
             flag_string( show_flags, pCmd->show ) );
    send_to_char( buf, ch );

    if( pCmd->disabled_by[0] != '\0' )
    {
	sprintf( buf, "{cDisabled  {B: {C%d {n%s\n\r",
		pCmd->disable_level, pCmd->disabled_by );
	send_to_char( buf, ch );
        
	send_to_char( "{cReason \n\r{n",ch );
        if( pCmd->reason )
		sprintf( buf, "%s\n\r", pCmd->reason );
	else
		sprintf( buf, "(None given)\n\r" );
	send_to_char( buf, ch );
    }
    return FALSE;
}

void list_functions( CHAR_DATA *ch )
{
    int i;
    char buf[MSL];

    sprintf( buf, "Num %-13.13s Num %-13.13s Num %-13.13s Num %-13.13s\n\r",
             "Func", "Func", "Func", "Func" );
    send_to_char(buf,ch);

    for ( i = 0; cmd_list[i].name; i++ )
    {
        sprintf( buf, "%3d %-13.13s", i, cmd_list[i].name );
        if ( i % 4 == 3 )
            strcat( buf, "\n\r" );
        else
            strcat( buf, " " );
        send_to_char( buf, ch );
    }

    if ( i % 4 != 0 )
        send_to_char( "\n\r", ch);
}

void used_functions( CHAR_DATA *ch )
{
    int i;
    char buf [ MAX_STRING_LENGTH ];
    bool found;
       
    sprintf( buf, "Num %-13.13s Num %-13.13s Num %-13.13s Num %-13.13s\n\r",
             "Func", "Func", "Func", "Func" );
    send_to_char(buf,ch);

    found = FALSE;
    for ( i = 0; cmd_list[i].name; i++ )
    {
	if( !fun_lookup( cmd_list[i].function ) )
	{
		found = TRUE;
	        sprintf( buf, "%3d %-13.13s", i, cmd_list[i].name );
        	if ( i % 4 == 3 )
	            strcat( buf, "\n\r" );
	        else
	            strcat( buf, " " );
	        send_to_char( buf, ch );
	}
    }

    if( !found )
	send_to_char( "There are no used functions in commands.h\n\r", ch );	
    else if ( i % 4 != 0 )
        send_to_char( "\n\r", ch);
    return;
}
         
void list_commands(CHAR_DATA *ch, int minlev, int maxlev)
{
    char buf[MSL];
    int i, cnt = 0;

    sprintf( buf, "Lvl %-12.12s %-13.13s Pos Log  Lvl %-12.12s %-13.13s Pos Log\n\r",
             "Name",	"Function",	"Name",	"Function" );
    send_to_char( buf, ch );

    for ( i = 0; i < MAX_CMD; ++i )
    {
        if ( cmd_table[i].level < minlev || cmd_table[i].level > maxlev )
            continue;

        sprintf( buf, "%2d %-12.12s %-13.13s %-3.3s %-3.3s",
                 cmd_table[i].level,
                 cmd_table[i].name,
                 cmd_func_name(cmd_table[i].do_fun),
                 flag_string( position_flags,  cmd_table[i].position ),
		 flag_string( log_flags,cmd_table[i].log));
        if ( cnt % 2 == 1 )
            strcat(buf,"\n\r");
        else
            strcat(buf," ");
        send_to_char( buf, ch );
        cnt++;
    }

    if ( cnt % 2 != 0 )
        stc("\n\r",ch);
    return;
}

CMDEDIT( cmdedit_list )
{
    char arg[MIL], arg2[MIL];
    int minlev, maxlev;

    argument = one_argument( argument, arg );

    if ( arg[0] == '\0' || !is_name(arg, "commands functions unused") )
    {
        send_to_char( "Syntax : list commands [level min] [level max]\n\r", ch );
	send_to_char( "         list functions\n\r", ch );
	send_to_char( "         list unused\n\r", ch );
        return FALSE;
    }

    minlev = 0;
    maxlev = MAX_LEVEL;

    if ( argument[0] != '\0' )
    {
        argument = one_argument( argument, arg2 );

        if ( !is_number( arg2 ) )
        {
            send_to_char( "CMDEdit : Argument must be a number.\n\r", ch );
            return FALSE;
        }

        minlev = atoi( arg2 );

        if ( argument[0] == '\0' )
            maxlev = atoi( argument );
        else
            maxlev = 0;

        if ( maxlev < 1 || maxlev > MAX_LEVEL )
            maxlev = minlev;
    }

    if ( !str_prefix(arg,"commands") )
        list_commands(ch,minlev,maxlev);
    else if ( !str_prefix(arg,"functions") )
        list_functions(ch);
    else if ( !str_prefix(arg,"unused" ) )
	used_functions(ch);	
    else
        send_to_char("Invalid.\n\r",ch);

    return FALSE;
}

void do_nothing( CHAR_DATA *ch, char *argument )
{
    return;
}

CMDEDIT( cmdedit_name )
{
    struct cmd_type *pCmd;
    int cmd;

    EDIT_CMD(ch,pCmd);

    if ( !argument || argument[0] == '\0' )
    {
        send_to_char( "Sintaxis : name [name]\n\r", ch );
        return FALSE;
    }

    if ( cmd_lookup(argument) != -1 )
    {
        send_to_char( "CMDEdit : Command already exhists.\n\r", ch );
        return FALSE;
    }

    free_string(pCmd->name);
    pCmd->name = str_dup( argument );

    clear_table_commands();

    cmd = cmd_lookup(argument);
    if ( cmd != -1 )
        ch->desc->pEdit = &cmd_table[cmd];
    else
        bugf( "Cmdedit_name : cmd_lookup returns -1 at %s!", argument );

    send_to_char( "Ok.\n\r", ch );
    return TRUE;
}

CMDEDIT( cmdedit_new )
{
    DESCRIPTOR_DATA *d;
    CHAR_DATA *tch;
    struct cmd_type *new_table;
    int cmd;

    if ( !argument || argument[0] == '\0' )
    {
        send_to_char( "Syntax : new [number of command]\n\r", ch );
        return FALSE;
    }

    cmd = cmd_lookup( argument );

    if (cmd != -1)
    {
        send_to_char ("CMDEdit : Command non-exhistant.\n\r",ch);
        return FALSE;
    }

    for ( d = descriptor_list; d; d = d->next )
    {
        if ( d->connected != CON_PLAYING
        || (tch = CH(d)) == NULL || tch->desc == NULL )
            continue;

        if ( tch->desc->editor == ED_CMD )
            edit_done(tch);
    }

    MAX_CMD++;
    new_table = realloc (cmd_table, sizeof(struct cmd_type) * (MAX_CMD + 1));

    if (!new_table) /* realloc failed */
    {
        send_to_char ("Failure to reallocate table. Prepare for the worse.\n\r",ch);
        return FALSE;
    }

    cmd_table = new_table;

    cmd_table[MAX_CMD-1].name		= str_dup (argument);
    cmd_table[MAX_CMD-1].do_fun		= do_nothing;
    cmd_table[MAX_CMD-1].position	= POS_STANDING;
    cmd_table[MAX_CMD-1].level		= ch->level;
    cmd_table[MAX_CMD-1].log		= LOG_ALWAYS;
    cmd_table[MAX_CMD-1].show           = CSHOW_NEVER;
    cmd_table[MAX_CMD-1].disabled_by    = str_dup( "" );
    cmd_table[MAX_CMD-1].reason         = str_dup( "" );
    cmd_table[MAX_CMD-1].disable_level  = 12;
    cmd_table[MAX_CMD].name		 = str_dup( "" );

    clear_table_commands();

    cmd = cmd_lookup(argument);
    if ( cmd != -1 )
        ch->desc->pEdit = &cmd_table[cmd];
    else
        bugf( "Cmdedit_new : cmd_lookup returned -1 with %s!", argument );

    ch->desc->editor	= ED_CMD;

    send_to_char ("Command created.\n\r",ch);
    return TRUE;
}

CMDEDIT( cmdedit_delete )
{
    DESCRIPTOR_DATA *d;
    CHAR_DATA *tch;
    int i,j,iCmd;
    struct cmd_type *new_table;

    if ( !argument || argument[0] == '\0' )
    {
        send_to_char( "Syntax : delete [number or command]\n\r", ch );
        return FALSE;
    }

    iCmd = cmd_lookup(argument);

    if (iCmd == -1)
    {
        send_to_char( "CMDEdit : Command non-exhistant.\n\r", ch );
        return FALSE;
    }

    for ( d = descriptor_list; d; d = d->next )
    {
        if ( d->connected != CON_PLAYING || (tch = CH(d)) == NULL || tch->desc == NULL )
            continue;

        if ( tch->desc->editor == ED_CMD )
            edit_done(tch);
    }

    new_table = malloc (sizeof(struct cmd_type) * MAX_CMD);

    if (!new_table)
    {
        send_to_char ("Memory allocation failed. Brace for impact...\n\r",ch);
        return FALSE;
    }

    for (i = 0, j = 0; i < MAX_CMD+1; i++)
        if (i != iCmd) /* copy, increase only if copied */
        {
            new_table[j] = cmd_table[i];
            j++;
        }

    free (cmd_table);
    cmd_table = new_table;

    MAX_CMD--; /* Important :() */

    clear_table_commands();
    send_to_char ("Command deleted\n\r",ch);
    return TRUE;
}

CMDEDIT( cmdedit_function )
{
    struct cmd_type *pCmd;
    DO_FUN *funcion;
	
    EDIT_CMD(ch,pCmd);

    if ( !argument || argument[0] == '\0' )
    {
        send_to_char( "Syntax : function [name-function]\n\r", ch );
        return FALSE;
    }

    if ( (funcion = cmd_func_lookup(argument)) == NULL )
    {
        send_to_char( "CMDEdit : Function inexistente.\n\r", ch );
        return FALSE;
    }

    pCmd->do_fun = funcion;
    send_to_char( "Ok.\n\r", ch );
    return TRUE;
}

CMDEDIT( cmdedit_level )
{
    struct cmd_type *pCmd;
    int niv;
	
    EDIT_CMD(ch,pCmd);

    if ( !argument || argument[0] == '\0')
    {
        ch_printf( ch, "Syntax : level [level]\n\r" );
        return FALSE;
    }
	
    if( is_number( argument ) )
        niv = atoi( argument );
    else
    if ( (niv = flag_value(level_flags, argument)) == NO_FLAG )
    {
        send_to_char( "CMDEdit : Level out of range.\n\r", ch );
        return FALSE;
    }

    if ( pCmd->level > ch->level )
    {
        send_to_char( "CMDEdit : Cannot create command higher then you.\n\r", ch );
        return FALSE;
    }

    pCmd->level = niv;
    send_to_char( "Ok.\n\r", ch );
    return TRUE;
}

CMDEDIT( cmdedit_log )
{
    struct cmd_type *pCmd;
    int value;
	
    EDIT_CMD(ch,pCmd);

    if ( !argument || argument[0] == '\0' )
    {
        ch_printf( ch, "Syntax : log [type/number]\n\r" );
        return FALSE;
    }

    if( is_number( argument ) )
        value = atoi( argument );
    else
        value = flag_value( log_flags, argument );
    
    if( value < 0 || value > 2 )
    {
        ch_printf( ch, "CMDEdit: Log %d is to large.\n\r", value );
        return FALSE;
    }

    pCmd->log = value;
    stc("Log toggled.\n\r", ch);
    return TRUE;
}

CMDEDIT( cmdedit_position )
{
    struct cmd_type *pCmd;
    int value;
	
    EDIT_CMD(ch,pCmd);

    if ( !argument || argument[0] == '\0' )
    {
        ch_printf( ch, "Syntax : log [type/number]\n\r" );
        return FALSE;
    }

    if( is_number( argument ) )
        value = atoi( argument );
    else
        value = flag_value( position_flags, argument );
    
    if( value < 0 || value > 9 )
    {
        ch_printf( ch, "CMDEdit: Position %d is invalid.\n\r", value );
        return FALSE;
    }

    pCmd->position = value;
    stc("Position set.\n\r", ch);
    return TRUE;
}

void fread_cmd( FILE *fp, struct cmd_type * pCmd )
{
    char buf[MAX_STRING_LENGTH];
    char *word;
    bool fMatch;

    pCmd->disabled_by = str_dup( "" );
    pCmd->reason      = str_dup( "" );
    pCmd->disable_level =  MAX_LEVEL;
    for ( ;; )
    {
        word   = feof( fp ) ? "End" : fread_word( fp );
	fMatch = FALSE;

	switch ( UPPER(word[0]) )
        {
        case '*':
	case '#':
            fMatch = TRUE;
            fread_to_eol( fp );
            break;
	
        case 'D':
	    if( !str_cmp( word, "D" ) )
	    {
	        fMatch = TRUE;
		pCmd->disable_level = fread_number( fp );
		free_string( pCmd->disabled_by );
		pCmd->disabled_by = fread_string( fp );
	        break;
	    }
	    break;
        case 'C':
	    if( !str_cmp( word, "C" ) )
	    {
		char * p;
		fMatch = TRUE;
		p = fread_string ( fp );
		pCmd->do_fun = cmd_func_lookup( p );
		free_string( p );
	        break;
	    }
	    break;

	case 'E':
	    if ( !str_cmp( word, "End" ) )
	    {
		if( pCmd->do_fun == do_nothing )
			SET_BIT( pCmd->show, CSHOW_NEVER );
                return;
	    }
	    break;

	case 'L':
	    KEY( "Lv",	pCmd->level,		fread_number(fp) );
	    KEY( "Lg", 	pCmd->log,		fread_number(fp) );
	    break;

	case 'N':
	    if( !str_cmp( word, "N" ) )
	    {
		 free_string( pCmd->name );
  		 pCmd->name = fread_string( fp );
		 fMatch = TRUE;
		 break;
	    }
	    break;

	case 'P':
            KEY( "P",	pCmd->position,	fread_number(fp) );
	    break;
	case 'R':
	    SKEY( "R", pCmd->reason );
	case 'S':
	    KEY( "S",   pCmd->show, fread_number(fp) );
	    break;
	}
	
	if ( !fMatch )
	{
            sprintf( buf, "Fread_command: no match: %s", word );
	    bug( buf, 0 );
	}
    }
}
    
void load_commands( void )
{
	FILE * fp;
extern	struct cmd_type *	cmd_table;
extern	int			MAX_CMD;
	int i = 0, large;

	fp = fopen( CMD_FILE, "r" );

        if ( !fp )
        {
            perror( "load_table_commands ");
            exit(1);
        }

	large = fread_number(fp);

	MAX_CMD = large;

        logf( NULL, "Creating cmd_table: large %d, size: %d", large + 1,
		sizeof(struct cmd_type) * (large + 1) );
	cmd_table = calloc( sizeof(struct cmd_type), large + 1);


        for( i = 0; i < MAX_CMD; i++ )
            fread_cmd( fp, &cmd_table[i] );

        logf( NULL, "Table of commands loaded." );
        fclose(fp);
        cmd_table[MAX_CMD].name = str_dup( "" ); /* Backwards compat */
        return;
}

void save_commands( void )
{
    FILE * fp;
    struct cmd_type * temp;
    extern	struct cmd_type * cmd_table;
    int cnt = 0;

    fp = fopen( CMD_FILE, "w" );

    if ( !fp )
    {
        perror( "save_table_commands" );
        return;
    }

    for ( MAX_CMD = 0; cmd_table[MAX_CMD].name[0]; MAX_CMD++ )
        ;

    fprintf( fp, "%d\n\n", MAX_CMD );

    for( cnt = 0; cnt < MAX_CMD; cnt++ )
    {
	temp = &cmd_table[cnt];
        fprintf( fp, "#COMAND\n" );
        fprintf( fp, "N  %s~\n", temp->name );
        fprintf( fp, "C  %s~\n", cmd_func_name(temp->do_fun) );
        fprintf( fp, "Lv %d\n", temp->level );
        fprintf( fp, "P  %d\n", temp->position );
        fprintf( fp, "Lg %d\n", temp->log );
        fprintf( fp, "S  %d\n", temp->show );
	if( temp->disabled_by[0] != '\0' )
	{
	   fprintf( fp, "D  %d %s~\n", 
			temp->disable_level,
			temp->disabled_by );
	   fprintf( fp, "R  %s~\n", strip_cr(temp->reason) );
	}
        fprintf( fp, "End\n\n" );
    }

    fclose(fp);
}