Grettings,

I've found this snippet a while ago and I decided to implement it. It wasn't
hard and the code itself now works well, but I can't fix a problem that
happened after I put this code on. Everytime I fight something and this
thing die, the mud crashes, and I haven't found nothing in the grant code
related to a fighting/death problem... has anyone experienced this problem?

Thanks in advance, and sorry any mispelling.
/*                      Grant code version 1.1

   This code was written by Jaey of Crimson Souls MUD.  It 
   was written specificly for a ROM 2.4 MUD, and I am
   releasing it into the public domain.  Any credit given,
   while appreciated, is not necessary.

   Contact info:

       E-mail:  [EMAIL PROTECTED]
          Web:  http://www.cs.transy.edu/scarrico
Crimson Souls:  ns2.ka.net 6969
*/


Add the following to interp.h:

struct pair_type
{
    char * const        first;
    char * const       second;
    bool              one_way;
};

DECLARE_DO_FUN( do_grant        );
DECLARE_DO_FUN( do_gstat        );
DECLARE_DO_FUN( do_revoke       );
--------------------------------------------------------------------------
Add the following to merc.h:

typedef struct  grant_data              GRANT_DATA;

struct grant_data
{
    GRANT_DATA *        next;
    DO_FUN *            do_fun;
    char *              name;
    int                 duration;
    int                 level;
};

Add this to the pc_data structure:

    GRANT_DATA *        granted;

Add these function prototypes:

bool is_granted_name    args( ( CHAR_DATA *ch, char *argument ) );
bool    is_granted      args( ( CHAR_DATA *ch, DO_FUN *do_fun ) );

Only add this prototype if you don't already have it:

bool    is_exact_name   args( ( char *str, char *namelist ) );
--------------------------------------------------------------------------
Add the following to act_comm.c:

In function do_immtalk change the line:

             IS_IMMORTAL(d->character) &&

to:

           (is_granted_name(d->character,"immtalk") ||
            is_granted_name(d->character,":")) &&

If function do_channels change the line for the immtalk channel:

          if (IS_IMMORTAL(ch))

to:

          if (is_granted_name(ch,"immtalk") || is_granted_name(ch,":"))

In function do_order() add the variable declarations:

    int cmd;
    bool callow = TRUE;

then add the lines with a + next to them:

    if ( arg[0] == '\0' || argument[0] == '\0' )
    {
        send_to_char( "Order whom to do what?\n\r", ch );
        return;
    }

+   for ( cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
+   {
+     if ( arg2[0] == cmd_table[cmd].name[0]
+     &&   !str_prefix( arg2, cmd_table[cmd].name ) )
+     {
+       if (cmd_table[cmd].level >= LEVEL_IMMORTAL)
+       {
+         callow = FALSE;
+         break;
+       }
+     }
+   }

    if ( IS_AFFECTED( ch, AFF_CHARM ) )
    {
        send_to_char( "You feel like taking, not giving, orders.\n\r", ch );
        return;
    }

then, further down, change:

            interpret( och, argument );

to:

            if ( callow ) interpret( och, argument );
--------------------------------------------------------------------------
Add the following to act_info.c:

#include "interp.h"

bool is_command( char *arg )
{
int cmd;

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

return FALSE;
}

In function do_help:

/* 
   On some muds, the "pHelp->level" found below might just
   be "level".  If that is the case, change each reference
   to "pHelp->level" to just "level".
*/

change:

        if (pHelp->level > get_trust( ch ) )
            continue;

to:

        if ( pHelp->level > get_trust( ch )
        && ( ( pHelp->level < LEVEL_IMMORTAL
        && !is_granted_name(ch,pHelp->keyword) )
        || (pHelp->level >= LEVEL_IMMORTAL
        && !is_command( pHelp->keyword ) ) ) )
            continue;

      if (pHelp->level >= LEVEL_IMMORTAL && is_command( pHelp->keyword )
      && !is_granted_name(ch,pHelp->keyword)) continue;
--------------------------------------------------------------------------
Add the following to act_wiz.c:

#include "interp.h"

const   struct  pair_type        pair_table       [] =
{
  {"switch", "return",FALSE},
  {"reboo", "reboot",FALSE},
  {"shutdow", "shutdown",FALSE},
  {"sla", "slay",FALSE},
  {"", "",FALSE}
};

bool is_granted( CHAR_DATA *ch, DO_FUN *do_fun)
{
GRANT_DATA *gran;

if (ch->desc == NULL) return FALSE;

if (ch->desc->original != NULL) ch = ch->desc->original;

for (gran=ch->pcdata->granted; gran != NULL; gran=gran->next)
  if (do_fun == gran->do_fun)
    return TRUE;

return FALSE;
}

bool is_granted_name( CHAR_DATA *ch, char *name)
{
GRANT_DATA *gran;

if (ch->desc == NULL) return FALSE;

if (ch->desc->original != NULL) ch = ch->desc->original;

for (gran=ch->pcdata->granted; gran != NULL; gran=gran->next)
  if (is_exact_name(gran->name,name))
    return TRUE;

return FALSE;
}

int grant_duration(CHAR_DATA *ch, DO_FUN *do_fun)
{
GRANT_DATA *gran;

if (ch->desc->original != NULL) ch=ch->desc->original;

/*  Replace the x's in the line below with the name of
    a character that is allowed to grant commands to
    anyone, even if they don't have the command
    themselves.  This is useful when you add new
    imm commands, and need to give them to yourself.
    Additional names can be added as needed and
    should be seperated by spaces.  */

if (is_exact_name(ch->name,"xxxxxx"))
  return -1;

for (gran=ch->pcdata->granted; gran != NULL; gran=gran->next)
  if (gran->do_fun == do_fun)
    return gran->duration;

return 0;
}

void grant_add(CHAR_DATA *ch, char *name, DO_FUN *do_fun, int duration,
               int level)
{
GRANT_DATA *gran;

if (ch->desc->original != NULL) ch=ch->desc->original;

gran = alloc_mem(sizeof(*gran));
gran->name = str_dup(name);
gran->do_fun = do_fun;
gran->duration = duration;
gran->level = level;

gran->next = ch->pcdata->granted;
ch->pcdata->granted = gran;

return;
}

void grant_remove(CHAR_DATA *ch, DO_FUN *do_fun, bool mshow)
{
GRANT_DATA *p,*gran;
char buf[MAX_STRING_LENGTH];
CHAR_DATA *rch;

rch = ch->desc->original?ch->desc->original:ch;

p=NULL;
gran=rch->pcdata->granted;
if (gran->do_fun == do_fun)
  rch->pcdata->granted=gran->next;
else
  for (gran=rch->pcdata->granted; gran != NULL; gran=gran->next)
  {
    if (gran->do_fun == do_fun) break;
    p=gran;
  }

if (p != NULL) p->next=gran->next;
sprintf(buf,"You have lost access to the %s command.\n\r",gran->name);
if (mshow) send_to_char(buf,ch);
free_string(gran->name);
free_mem(gran,sizeof(*gran));
return;
}

void grant_level( CHAR_DATA *ch, CHAR_DATA *victim, int level, int duration )
{
int cmd;

for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
  if ( cmd_table[cmd].level == level
  && !is_granted(victim,cmd_table[cmd].do_fun)
  && grant_duration(ch,cmd_table[cmd].do_fun) == -1)
    grant_add(victim,cmd_table[cmd].name,cmd_table[cmd].do_fun,
              duration, cmd_table[cmd].level);
return;
}

void revoke_level( CHAR_DATA *ch, CHAR_DATA *victim, int level )
{
int cmd;

for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
  if ( cmd_table[cmd].level == level
  && is_granted(victim,cmd_table[cmd].do_fun)
  && grant_duration(ch,cmd_table[cmd].do_fun) == -1)
    grant_remove(victim,cmd_table[cmd].do_fun,FALSE);
return;
}

void do_grant( CHAR_DATA *ch, char *argument )
{
char buf[MAX_STRING_LENGTH];
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
char arg3[MAX_INPUT_LENGTH];
CHAR_DATA *victim=NULL,*rch,*rvictim=NULL;
int  dur,cmd,x;
bool found=FALSE;
DESCRIPTOR_DATA *d;

argument = one_argument(argument,arg1);
argument = one_argument(argument,arg2);
one_argument(argument,arg3);

rch = ch->desc->original?ch->desc->original:ch;

if (arg1[0] == '\0')
  {
    send_to_char("Grant who, what?\n\r",ch);
    return;
  }

for (d = descriptor_list; d != NULL; d = d->next)
{
  rvictim = d->original?d->original:d->character;

  if (rvictim == NULL) continue;

  if (!str_cmp(rvictim->name,arg1))
  {
     victim = d->character;
     break;
  }
}

if (victim == NULL && !str_cmp("self",arg1))
{
   rvictim = rch;
   victim = ch;
}

if (victim==NULL)
  {
    send_to_char("Victim not found.\n\r",ch);
    return;
  }

if (arg2[0] == '\0')
  {
    int col=0;
    int lvl;

    sprintf(buf,"%s has not been granted the following commands:\n\r",
            rvictim->name);
    send_to_char(buf,ch);

    for ( lvl = IM; lvl <= ( L1 + 1 ) ; lvl++ )
    for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
      if (cmd_table[cmd].level >= LEVEL_IMMORTAL
      && !is_granted(victim,cmd_table[cmd].do_fun)
      && cmd_table[cmd].level == lvl)
      {
        sprintf( buf,"[L%3d] %-12s", cmd_table[cmd].level, cmd_table[cmd].name 
);
        send_to_char(buf,ch);
        if ( ++col % 4 == 0 )
          send_to_char( "\n\r", ch );
      }
    if ( col % 4 != 0 )
      send_to_char( "\n\r", ch);
    return;
  }

dur = arg3[0]=='\0' ? -1 : is_number(arg3) ? atoi(arg3) : 0;

if (dur<1 && dur != -1)
  {
    send_to_char("Invalid duration!\n\r",ch);
    return;
  }

if (is_number(arg2))
  {
    if (atoi(arg2)<LEVEL_IMMORTAL || atoi(arg2)>MAX_LEVEL)
    {
      send_to_char("Invalid grant level.\n\r",ch);
      return;
    }
    grant_level(ch, victim, atoi(arg2), dur );
    sprintf(buf, "You have been granted level %d commands.\n\r", atoi(arg2));
    send_to_char("Ok.\n\r",ch);
    send_to_char(buf,victim);
    return;
  }

for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
  if ( arg2[0] == cmd_table[cmd].name[0]
  &&   is_exact_name( arg2, cmd_table[cmd].name ) )
  {
      found = TRUE;
      break;
  }

if (found)
  {
    if (cmd_table[cmd].level < LEVEL_IMMORTAL)
    {
      send_to_char("You can only grant immortal commands.\n\r",ch);
      return;
    }

    if (grant_duration(ch,cmd_table[cmd].do_fun) != -1)
    {
      send_to_char("You can't grant that!\n\r",ch);
      return;
    }

    if (is_granted(victim,cmd_table[cmd].do_fun))
    {
      send_to_char("They already have that command!\n\r",ch);
      return;
    }

    grant_add(victim,cmd_table[cmd].name,cmd_table[cmd].do_fun,
              dur, cmd_table[cmd].level);

    sprintf(buf,"%s has been granted the %s command.\n\r",rvictim->name,
            cmd_table[cmd].name);
    send_to_char(buf,ch);
    sprintf(buf,"%s has granted you the %s command.\n\r",rch->name,
            cmd_table[cmd].name);
    send_to_char(buf,victim);

    for (x=0; pair_table[x].first[0] != '\0'; x++)
      if (!str_cmp(arg2,pair_table[x].first)
      && !is_granted_name(victim,pair_table[x].second))
      {
        sprintf(buf,"%s %s %s",rvictim->name, pair_table[x].second, arg3);
        do_grant(ch,buf);
      }
      else if (!str_cmp(arg2,pair_table[x].second)
           && pair_table[x].one_way != TRUE
           && !is_granted_name(victim,pair_table[x].first))
      {
        sprintf(buf,"%s %s %s",rvictim->name,pair_table[x].first, arg3);
        do_grant(ch,buf);
      }

    return;
  }
  send_to_char("Command not found!\n\r",ch);
  return;
}

void do_revoke( CHAR_DATA *ch, char *argument )
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
CHAR_DATA *victim=NULL,*rvictim=NULL;
DESCRIPTOR_DATA *d;
int cmd,x;
bool had_return, found=FALSE;

argument = one_argument(argument,arg1);
one_argument(argument,arg2);

if (arg1[0] == '\0' )
  {
    send_to_char("Revoke who, what?\n\r",ch);
    return;
  }

for (d = descriptor_list; d != NULL; d = d->next)
{
  rvictim = d->original?d->original:d->character;

  if (rvictim == NULL) continue;

  if (!str_cmp(rvictim->name,arg1))
  {
     victim = d->character;
     break;
  }
}

if (victim == NULL && !str_cmp("self",arg1))
{
  rvictim = ch->desc->original ? ch->desc->original : ch;
  victim = ch;
}

if (victim==NULL)
  {
    send_to_char("Victim not found.\n\r",ch);
    return;
  }

had_return = is_granted_name(victim,"return");

if (arg2[0] == '\0')
  {
    int col=0,lvl;
    char buf[MAX_STRING_LENGTH];

    sprintf(buf,"%s has been granted the following commands:\n\r",
            rvictim->name);
    send_to_char(buf,ch);

    for ( lvl = IM; lvl <= ( L1 + 1 ) ; lvl++ )
    for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
      if (cmd_table[cmd].level >= LEVEL_IMMORTAL
      && is_granted(victim,cmd_table[cmd].do_fun)
      && cmd_table[cmd].level == lvl )
      {
        sprintf( buf,"[L%3d] %-12s", cmd_table[cmd].level, cmd_table[cmd].name 
);
        send_to_char(buf,ch);
        if ( ++col % 4 == 0 )
          send_to_char( "\n\r", ch );
      }
    if ( col % 4 != 0 )
      send_to_char( "\n\r", ch);
    return;
  }

if (is_number(arg2))
  {
    char buf[MAX_STRING_LENGTH];

    if (atoi(arg2)<LEVEL_IMMORTAL || atoi(arg2)>MAX_LEVEL)
    {
      send_to_char("Invalid revoke level.\n\r",ch);
      return;
    }
    revoke_level(ch, victim, atoi(arg2));
    sprintf(buf, "You have lost acess to level %d commands.\n\r", atoi(arg2));
    send_to_char("Ok.\n\r",ch);
    send_to_char(buf,victim);

    if (had_return && !is_granted_name(victim,"return") &&
        rvictim != victim) do_return(victim,"");

    return;
  }

for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
  if ( arg2[0] == cmd_table[cmd].name[0]
  &&   is_exact_name( arg2, cmd_table[cmd].name ) )
  {
      found = TRUE;
      break;
  }

if (found)
  {
    char buf[MAX_STRING_LENGTH];

    if (grant_duration(ch,cmd_table[cmd].do_fun) != -1)
    {
      send_to_char("You can't revoke that!\n\r",ch);
      return;
    }

    if (!is_granted(victim,cmd_table[cmd].do_fun))
    {
      send_to_char("They don't have that command!\n\r",ch);
      return;
    }

    grant_remove(victim,cmd_table[cmd].do_fun,TRUE);

    sprintf(buf,"%s has lost access to the %s command.\n\r",
             rvictim->name,cmd_table[cmd].name);
    send_to_char(buf,ch);

    for (x=0; pair_table[x].first[0] != '\0'; x++)
      if (!str_cmp(arg2,pair_table[x].first)
      && is_granted_name(victim,pair_table[x].second))
      {
        sprintf(buf,"%s %s",rvictim->name,pair_table[x].second);
        do_revoke(ch,buf);
      }
      else if (!str_cmp(arg2,pair_table[x].second)
           && pair_table[x].one_way != TRUE
           && is_granted_name(victim,pair_table[x].first))
      {
        sprintf(buf,"%s %s",rvictim->name,pair_table[x].first);
        do_revoke(ch,buf);
      }

    if (had_return && !is_granted_name(victim,"return") &&
        rvictim != victim) do_return(victim,"");

    return;
  }
  send_to_char("Command not found!\n\r",ch);
  return;
}


void do_gstat( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
char buf[MAX_STRING_LENGTH];
BUFFER *buffer;
GRANT_DATA *grant;
CHAR_DATA *victim;
int col=0;

one_argument(argument,arg);

if (arg[0] == '\0')
  {
    send_to_char("Gstat who?\n\r",ch);
    return;
  }

if ( ( victim = get_char_world( ch, arg ) ) == NULL )
  {
    send_to_char( "They aren't here.\n\r", ch );
    return;
  }

if (IS_NPC(victim))
  {
    send_to_char("Not on mobs.\n\r",ch);
    return;
  }

if (get_trust(ch)<get_trust(victim))
  {
    send_to_char("You can't do that.\n\r",ch);
    return;
  }

buffer=new_buf();

sprintf(buf,"Grant status for %s:\n\r\n\r",victim->name );

add_buf(buffer,buf);

for (grant=victim->pcdata->granted; grant!=NULL; grant=grant->next)
  {
    char ds[50],ss[25],s2[25];
    int x,sl;

    sprintf(ds,"%d",grant->duration);
    ss[0]='\0';
    sl = (int)((6-strlen(ds)) / 2);

    for (x=0; x<sl ;x++)
      strcat(ss," ");

    strcpy(s2,ss);

    if ((strlen(ss)+strlen(ds)) % 2 == 1) strcat(s2," ");

    if (grant->duration==-1)
      sprintf(buf,"[ perm ] %-11s",grant->name);
    else
      sprintf(buf,"[%s%d%s] %-11s",ss, grant->duration, s2, grant->name);

    add_buf(buffer,buf);

    col++;
    col %= 4;

    if (col==0) add_buf(buffer,"\n\r");
  }

if (col != 0) add_buf(buffer,"\n\r");

page_to_char(buf_string(buffer),ch);

free_buf(buffer);
return;
}

In do_force change:

    if (!str_cmp(arg2,"delete"))

to:

    if (!str_cmp(arg2,"delete") || is_name(arg2,"gran")
    || is_name(arg2,"rev"))

/*
    Here, "gran" and "rev" should be replaced, if necessary, with
    the mininum number of letters required to execute the "grant"
    and "revoke" commands on the mud.  If desired, you can change
    them to "grant" and "revoke" and add a "gran" and "revok"
    command in the same manner as the "delet" command.  If you
    take this course of action, you should add these new commands
    to the pair_table with:

        {"grant","gran",FALSE},
        {"revoke","revok",FALSE}
*/
--------------------------------------------------------------------------
Add the following to comm.c:

In function nanny change:

        if ( IS_IMMORTAL(ch) )
        {
            do_help( ch, "imotd" );
            d->connected = CON_READ_IMOTD;
        }

to:

        if (is_granted_name(ch,"imotd"))
        {
            do_help( ch, "imotd" );
            d->connected = CON_READ_IMOTD;
        }
--------------------------------------------------------------------------
Add the following function to handler.c, if you don't already have it:

bool is_exact_name( char *str, char *namelist )
{
    char name[MAX_INPUT_LENGTH];

    if (namelist == NULL)
        return FALSE;

    for ( ; ; )
    {
        namelist = one_argument( namelist, name );
        if ( name[0] == '\0' )
            return FALSE;
        if ( !str_cmp( str, name ) )
            return TRUE;
    }
}
--------------------------------------------------------------------------
Add the following to interp.c:

Add these commands to the command table:

    { "grant",          do_grant,       POS_DEAD,       ML,  LOG_ALWAYS, 1 },
    { "gstat",          do_gstat,       POS_DEAD,       L1,  LOG_NORMAL, 1 },
    { "revoke",         do_revoke,      POS_DEAD,       ML,  LOG_ALWAYS, 1 },

In the function interpret, look for where it searches through
the command table to see if the character has the command.

Remove the text:  

        &&  cmd_table[cmd].level <= trust

Then, down inside the braces of that same if statement, change:

            found = TRUE;
            break;

to:

            if (cmd_table[cmd].level<LEVEL_IMMORTAL)
            {
              if (cmd_table[cmd].level > trust) continue;
            }
            else
              if (ch->desc == NULL
              || !is_granted(ch,cmd_table[cmd].do_fun)) continue;

            found = TRUE;
            break;

In function do_wizhelp change the line:

        &&   cmd_table[cmd].level <= get_trust( ch )

to:

        &&   is_granted(ch,cmd_table[cmd].do_fun)
--------------------------------------------------------------------------
Add the following to recycle.c

In function free_pcdata:

GRANT_DATA *gran,*gran_next;

    for (gran = pcdata->granted; gran != NULL; gran = gran_next)
    {
        gran_next = gran->next;
        free_string(gran->name);
        free_mem(gran,sizeof(*gran));
    }
------------------------------------------------------------------------
Add the following to save.c:

#include "interp.h"

In function fwrite_char:

    GRANT_DATA *gran;

    for (gran=ch->pcdata->granted; gran != NULL; gran=gran->next)
      fprintf(fp,"Grant '%s' %d\n",gran->name, gran->duration);

/*  
    You should change the tag "Grant" used in the line above
    so that it is something that can't be easily guessed by
    someone attempting to exploit certain bugs for disruptive
    purposes.
*/

In function load_char_obj:

    ch->pcdata->granted                 = NULL;

In function fread_char:

/*
    The word "Grant" in the line below should be changed to the
    same tag that you chose to write out to the player file in
    the fwrite_char() function. *WARNING* Make sure that you
    add this code under the case that matches the first letter
    of the tag you chose.  Also, make sure that it is added
    before the "break" that causes the code to bail out of
    each case.
*/

            if ( !str_cmp( word, "Grant" ) )
            {
              GRANT_DATA *gran;
              int cmd;

              gran = alloc_mem(sizeof(*gran));
              gran->name = str_dup(fread_word(fp));
              gran->duration = fread_number(fp);
              gran->next = NULL;
              gran->do_fun = NULL;

              for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
                if ( gran->name[0] == cmd_table[cmd].name[0]
                   &&  is_exact_name( gran->name, cmd_table[cmd].name ) )
                {
                  gran->do_fun = cmd_table[cmd].do_fun;
                  gran->level = cmd_table[cmd].level;
                  break;
                }

              gran->next = ch->pcdata->granted;
              ch->pcdata->granted = gran;

              if (gran->do_fun == NULL)
              {
                sprintf(buf,"Grant: Command %s not found in pfile for %s",
                        gran->name,ch->name);
                log_string(buf);
              }  

              fMatch = TRUE;
            }
--------------------------------------------------------------------------
Add the following to update.c:

In function char_update:

Right before these comments:

        /*
         * Careful with the damages here,
         *   MUST NOT refer to ch after damage taken,
         *   as it may be lethal damage (on NPC).
         */

Add:

        if (!IS_NPC(ch) && ch->pcdata->granted != NULL)
        {
          GRANT_DATA *gran,*gran_next, *gran_prev;
          char buf[MAX_STRING_LENGTH];

          gran_prev=ch->pcdata->granted;

          for (gran=ch->pcdata->granted; gran != NULL; gran=gran_next)
          {
            gran_next = gran->next;
            if (gran->duration > 0) gran->duration--;
            if (gran->duration==0)
            {
              if (gran==ch->pcdata->granted)
                ch->pcdata->granted=gran_next;
              else
                gran_prev->next = gran->next;
              sprintf(buf,
                "Your time runs out on the %s command.\n\r",gran->name);
              send_to_char(buf,ch);
              free_string(gran->name);
              free_mem(gran,sizeof(*gran));
              gran = NULL;
            }
            if (gran != NULL) gran_prev=gran;
          }
        }
--------------------------------------------------------------------------
If desired, you can make the following optional changes to your code.
All this code deals with is limiting a players access to those little
perks given to immortals automaticly, such as being able to read
notes sent to immortal.

In merc.h change:

#define IS_IMMORTAL(ch)              (get_trust(ch) >= LEVEL_IMMORTAL)

to:

#define IS_IMMORTAL(ch) (ch->desc ? is_granted_name(ch,"immflag") : 
get_trust(ch) >= LEVEL_IMMORTAL)

In act_wiz.c add:

void do_immflag( CHAR_DATA *ch, char *argument )
{
send_to_char( "Huh?\n\r", ch );
return;
}

In interp.h add:

DECLARE_DO_FUN( do_immflag      );

In interp.c add to the command table:

 { "immflag",       do_immflag,     POS_SLEEPING,   IM,  LOG_NORMAL, 0 },
     This grant code was originaly written by Jaey of Crimson Souls MUD
for use by Crimson Souls MUD.  The purpose of this document is to list
the features of the grant code, and the steps necessary to maintain it
through mud expansion.  The original version of this code was completed
on December 6, 1996, and it has since gone through a series of bug
fixes and enhancements.  The decision to release this code to the
public was made in early March of 1998 and it was released soon after.
Any questions or bug reports relating to the grant code can be directed
to Steven Carrico via [EMAIL PROTECTED]

     The main purpose of the grant code is to allow greater versatility
in the delving out of immortal commands.  The standard ROM code gives
out immortal commands depending on the trusted level of a character,
and doesn't allow one to give out individual commands.  The problem with
this system comes to light when someone manages to exploit bugs in the
code to gain a high level character, and all the commands that come with
it.  A secondary purpose of the code then is to help prevent someone
from gaining unauthorized access to immortal commands.  This is
accomplished through a variety of methods which will be described
later.
---------------------------------------------------------------------------
     First of all, once you get the code in, you will need to add the
following line to your player file to get things started:

<keyword> 'grant' -1  

Where <keyword> should be the the word you have chosen to denote granted
commands, and should be something that can't be easily guessed.  When it
comes down to it <keyword> will act as a password to protect granted
commands from the same kind of attack used to hack a high level character.
This is the first line of defense used to prevent unauthorized access to
immortal commands.  Once this is done, you can log on to the MUD and give
yourself the rest of the commands by typing:

grant self 92
grant self 93
...
...
grant self 100

A quick note about the use of grant self.  Under normal conditions, a
player can only grant a command that they themselves have been granted
permanently.  The exceptions to this rule are the character names
hard coded into the grant_duration() function in act_wiz.c.  Only those
exceptions are allowed to grant commands that they don't already poses.
This cuts out the need to manualy edit a player file each time an
immortal command is added.  Once the grant structure has been
implemented, no imms will have commands until you give them to them.

    Here is a breakdown of the different syntax's for the grant and revoke  
commands:

grant <name> -- will list all the imm commands that <name> does NOT have.
                                                                                
grant <name> <command> -- will give <command> to <name>
                                                                                
grant <name> <level#> -- will give <name> all the level <level#> commands.

grant <name> <commands> <duration> -- will give <command> to <name> for
                                      <duration> ticks.

grant <name> <level#> <duration> -- will give <name> all the level
                                    <level#> commands for <duration>
                                    ticks.

If you don't specify a duration, the duration is set to permanent.

revoke <name> -- lists all the commands that <name> does have.

revoke <name> <command> -- Takes <command> away from <name>

revoke <name> <level#> -- Takes away all the level <level#> commands
                          from <name>

The same rules that apply to the grant command also apply to the
revoke command.  For both "grant" and "revoke", the full name of
the player is required.

     The modifications made to the help command for grant make it
so that players can only view help files for immortal commands
they have access to.  The normal level limits apply to any help
files that are not commands.

     One of the early enhancements to this code was the addition of
a less powerful command which could be used to view the duration
of the commands granted to a player.  I have included the code for
the "gstat" command along with the code for "grant" and "revoke"

     Another one of the enhancements to this code was the addition of
the pair table.  The pair table is there to make sure that commands
that belong together are granted together.  The format for a table
entry is {"command1","command2",one_way}

If one_way is set to FALSE then granting someone command1 will
auto-grant them command2, or granting someone command2 will auto-grant
them command1.

This method is useful for such things as the "switch" and "return"
commands or the "reboo" and "reboot" commands.

If one_way is set to TRUE then granting someone command1 will
auto-grant them command2, but granting someone command2 will NOT
auto-grant them command1.

This second method is useful if you have a general set command,
as well as individual set commands such as oset, mset, rset, and 
sset.  For example if you have:

{"set","oset",TRUE},
{"set","mset",TRUE},
{"set","rset",TRUE},
{"set","sset",TRUE}
                                                                                
grant <name> set will give <name> the set,oset,mset,rset, and sset
commands, while grant <name> mset will only give <name> the mset
command.

     Other small changes were made as time went on.  These include
the automatic return executed with the loss of the "return" command,
and the inability to use "force" on the "grant" command.

Reply via email to