/* 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: scarrico@mail.transy.edu Web: http://www.transy.edu/~steven 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,":")) -------------------------------------------------------------------------- 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 },