/
//(Thought I was actually going to make a patch file? I don't have that kind of time ;)
//Newbie coders: I may be vague in my location specifications some times, so tough it out.
//And do note I start from the top of MY files and go down.

First off, place the secedit.c file in your src directory.
Then dump the secgroup.dat into your data folder.

<< In olc.h: >>
Find the other #define ED_XXX's and add:
#define ED_SECURITY	15
Replace 15 with whatever # is next in line in your code.

Under 'Interpreter Prototypes' put:
void	secedit		args( ( CHAR_DATA *ch, char *argument ) );

Now with all the other XXX_olc_comm_tables, put this:
extern	const	struct	olc_comm_type	security_olc_comm_table	[];

Under 'Editor Commands' put:
DECLARE_DO_FUN(	do_secedit		);

Now, down with the 'Editor prototypes' add this:
/*
 * Security Editor
 */
DECLARE_OLC_FUN( secedit_list 	);
DECLARE_OLC_FUN( secedit_show 	);
DECLARE_OLC_FUN( secedit_name 	);
DECLARE_OLC_FUN( secedit_bit 	);
DECLARE_OLC_FUN( secedit_cmd 	);
DECLARE_OLC_FUN( secedit_new 	);
DECLARE_OLC_FUN( secedit_delete	);

Down with the Macros place this:
#define EDIT_SECURITY(Ch, Sec)	( Sec = (SECURITY_DATA*)Ch->desc->pEdit )

<< In olc.c >>
At the top of the file, just under the:
MOB_INDEX_DATA		xMob;
OBJ_INDEX_DATA		xObj;
ROOM_INDEX_DATA		xRoom;
etc, etc, etc, put:
SECURITY_DATA	xSec;

In the run_olc_editor(), add this to the switch statement:
                case ED_SECURITY:
                        secedit (d->character, incomm);
                        break;

In the olc_ed_name(), add this to the switch statement:
                case ED_SECURITY:
                        sprintf (buf, "SecEdit");
                        break;

In the olc_ed_vnum(), add this to the switch statement:
                case ED_SECURITY:
                        pSec = (SECURITY_DATA *) ch->desc->pEdit;
                        sprintf( buf, "%s", pSec ? pSec->name : "" );
                        break;

In the get_olc_table(), add this to the switch statement:
                case ED_SECURITY:	return security_olc_comm_table;

In process_olc_commands(), add this in the list of variables:
       SECURITY_DATA *pSec;

Now add this in the switch in process_olc_commands()
                                case ED_SECURITY:
                                EDIT_SECURITY(ch, pSec);
                                if (table[temp].argument)
                                        puntero = (void *) ((int) table[temp].argument -                                     (int) &xSec + (int) pSec);
                                else
                                        puntero = NULL;
                                if ( (*table[temp].function) (table[temp].name, ch,                                              argument, puntero,
                                        table[temp].parameter ) )
                                        save_security_table();
                                return TRUE;
                                break;

<< In merc.h: >>
Place this with all the other typedefs:
typedef struct 	security_type 	SECURITY_DATA;

Now find a place somewhere in your merc.h to place this:
struct security_type
{
   char *   name;
   long     bit;
};

Now, find the pc_data struct and add this somewhere in it:
long		secgroups;  /* KJ: For SecEdit */

<< In interp.h: >>
Add this to your cmd_type struct:
long        secgroup;

<< In command.h: >>
Add this somewhere:
COMMAND( do_secedit     )
COMMAND( do_secgroup    )

<< In interp.c: >>
In the interpret(), find this part of the code and modify it to look like this:
/*
 * 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 ) )
    {
        if ( ( cmd_table[cmd].secgroup == 0 && cmd_table[cmd].level <= trust )
        || ( ch->pcdata != NULL && IS_SET(cmd_table[cmd].secgroup,                                           ch->pcdata->secgroups) ) )
        {
            found = TRUE;
            break;
        }
    }
 }
/*
 * Log and snoop.
 */

Now, replace your do_wizhelp with this one:
/*
 * Wizhelp. Modified by Ammaross Danan to work with SecEdit security
 */
void do_wizhelp( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];
    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].show )
    {
        if ( ( cmd_table[cmd].secgroup == 0
           && cmd_table[cmd].level <= get_trust( ch ) )
        || ( ch->pcdata != NULL && IS_SET(cmd_table[cmd].secgroup,
                                          ch->pcdata->secgroups) ) )
        {
            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;
}

<< In cmdedit.c: >>
At then end of your cmdedit_show(), just before the return FALSE;, add this:
        /* Displays what Security groups the command belongs to */
        if ( pCmd->secgroup != 0 )
        {
        BUFFER *pBuf;
        int i, j;
extern SECURITY_DATA	*security_table;

        send_to_char( "Security groups:\n\r", ch );
        pBuf = new_buf();
        sprintf( buf, "Num %-18.18s Num %-18.18s Num %-18.18s\n\r",
                        "Name", "Name", "Name" );
        add_buf( pBuf, buf );
        for ( i = 0, j = 0; !IS_NULLSTR(security_table[i].name); i++ )
        {
                if( IS_SET( pCmd->secgroup, security_table[i].bit ) )
                {
                        sprintf( buf, "%3d %-18.18s", ++j, security_table[i].name );
                        if ( j % 3 == 0 )
                                strcat( buf, "\n\r" );
                        else
                                strcat( buf, " " );
                        add_buf( pBuf, buf );
                }
        }
        if ( j % 3 != 0 )
                add_buf( pBuf, "\n\r" );
        page_to_char( buf_string(pBuf), ch );
        free_buf(pBuf);
        }

In your list_commands, change:
if ( cmd_table[i].level < minlev || cmd_table[i].level > maxlev )
to:
/* maxlev+1 so you can see commands that are part of security groups */
if ( cmd_table[i].level < minlev || cmd_table[i].level > maxlev+1 )

<< In tablesave.c: >>
Under:
struct cmd_type		cmd;
At the top of the file, add this:
SECURITY_DATA    sec;

Add this in the cmdsavetable[]:
{	"secgroup",	CAMPO_FLAGVECTOR,	(void *) &cmd.secgroup,
        NULL,	NULL		},

Add this just under cmdsavetable[]:
const struct savetable_type secsavetable [] =
{
        {	"name",		CAMPO_STRING,		(void *) &sec.name,
                NULL,		NULL		},
        {	"bit",		CAMPO_FLAGVECTOR,	(void *) &sec.bit,
                NULL,		NULL		},
        {	NULL,		0,			NULL,
                NULL,		NULL		}
};

Now at the bottom of the file place these:
#define	SEC_FILE	DATA_DIR "secgroup.dat"

/*
 * Ammaross Danan:
 * Used to save the security data table.
 */
void save_security_table( void )
{
        FILE * fp;
        SECURITY_DATA * temp;
        extern	SECURITY_DATA * security_table;

        int cnt = 0;

        fp = fopen( SEC_FILE, "w" );

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

        for ( temp = security_table; !IS_NULLSTR(temp->name); temp = temp++ )
                cnt++;

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

        for ( temp = security_table; !IS_NULLSTR(temp->name); temp = temp++ )
        {
                fprintf( fp, "#SECGROUP\n" );
                save_struct( fp, &sec, secsavetable, temp );
                fprintf( fp, "#END\n\n" );
        }

        fclose(fp);
}

/*
 * Ammaross Danan:
 * Used to load the security data table.
 */
void load_security( void )
{
        FILE * fp;
extern	SECURITY_DATA *	security_table;
static	SECURITY_DATA		emptycmd;
        int i = 0;
        int size = 0;
        char * word;

        fp = fopen( SEC_FILE, "r" );

        if ( fp == NULL )
        {
                perror( "load_security_table ");
                return;
        }

        size = fread_number(fp);

        logf( WORLD_ALL, "Created security_table of length %d, size %d", size + 1,
                sizeof(SECURITY_DATA) * (size + 1) );
        security_table = calloc( sizeof(SECURITY_DATA), size + 1);

        for ( i = 0; i <= size; i++ )
                security_table[i] = emptycmd; // initialize

        i = 0;
        while(TRUE)
        {
                word = fread_word(fp);

                if ( str_cmp(word, "#SECGROUP") )
                {
                        bugf( "load_security_table : word %s", word );
                        fclose(fp);
                        return;
                }

                load_struct( fp, &sec, secsavetable, &security_table[i++] );

                if ( i == size )
                {
                        log( "Security table loaded." );
                        fclose(fp);
                        security_table[i].name = NULL;
                        return;
                }
        }
}

<< In tablesave.h: >>
Add:
void load_security( void );
void save_security_table( void );

<< In save.c >>
Add this in fwrite char where ever you prefer (in is after the olc security fwrite):
    fprintf( fp, "SecGroup  %s\n", print_flags( ch->pcdata->secgroups ) );

Now add this in fread_char under the case 'S':
KEY( "SecGroup",	ch->pcdata->secgroups,	fread_flag( fp ) );

<< In db.c: >>
Add this in the boot_db() where all the other load_XXX for OLC are located:
    load_security();

<< In help.are: >>
Add this somewhere:
-1 SECEDIT SECURITY~
SecEdit is used to create groups of commands for security purposes.

secedit list              - List current security groups
secedit <name>            - Edits the group <name>
secedit new <name>        - Creates a new security group called <name>
secedit bit <bit letter>  - Sets the group to use <bit>. MUST SET BEFORE ADDING
                            COMMANDS.
secedit command add/remove <command> - Adds or removes a command from the group

SecEdit was written by Ammaross Danan (ammaross@crosswinds.net) of ArdenmoreMUD.
~

-1 GRANT~
Syntax: grant <player> <group>

Grant is used to grant users security groups.
~

Now do a clean make and cross your fingers.
*hopes he did not forget anything*

Now, I am sure you will want an explaination of how to use it and set it up?
Read the aftermath.txt.