/* flags.c - flag manipulation routines */ #include "copyright.h" #include <stdio.h> #include <ctype.h> #include <string.h> #include "db.h" #include "mudconf.h" #include "externs.h" #include "command.h" #include "flags.h" /* --------------------------------------------------------------------------- * fh_any: set or clear indicated bit, no security checking */ int fh_any (dbref target, dbref player, int flag, int reset) { if (reset) s_Flags(target, Flags(target) & ~flag); else s_Flags(target, Flags(target) | flag); return 1; } /* --------------------------------------------------------------------------- * fh_od: only GOD may set or clear the bit */ int fh_god (dbref target, dbref player, int flag, int reset) { if (!God(player)) return 0; return (fh_any(target, player, flag, reset)); } /* --------------------------------------------------------------------------- * fh_wiz: only WIZARDS (or GOD) may set or clear the bit */ int fh_wiz (dbref target, dbref player, int flag, int reset) { if (!Wizard(player) & !God(player)) return 0; return (fh_any(target, player, flag, reset)); } /* --------------------------------------------------------------------------- * fh_player: only players may set or clear this bit. */ int fh_player (dbref target, dbref player, int flag, int reset) { if (Typeof(player) != TYPE_PLAYER) return 0; return (fh_any(target, player, flag, reset)); } /* --------------------------------------------------------------------------- * fh_wiz_bit: Only GOD may set/clear this bit on others. */ int fh_wiz_bit (dbref target, dbref player, int flag, int reset) { if (!God(player)) return 0; if (God(target) && reset) { notify(player, "You cannot make yourself mortal."); return 0; } return (fh_any(target, player, flag, reset)); } /* --------------------------------------------------------------------------- * fh_dark_bit: manipulate the dark bit. Nonwizards may not set on players. */ int fh_dark_bit (dbref target, dbref player, int flag, int reset) { if (!reset && (Typeof(target) == TYPE_PLAYER) && (!Wizard(player) && !God(player))) return 0; return (fh_any(target, player, flag, reset)); } /* --------------------------------------------------------------------------- * fh_going_bit: manipulate the going bit. Non-gods may only clear on rooms. */ int fh_going_bit (dbref target, dbref player, int flag, int reset) { if ((Typeof(target) == TYPE_ROOM) && (Flags(target) & GOING) && reset) { notify(player, "Your room has been spared from destruction."); return (fh_any(target, player, flag, reset)); } if (!God(player)) return 0; return (fh_any(target, player, flag, reset)); } /* --------------------------------------------------------------------------- * fh_puppet_bit: set or clear the puppet bit (extra feedback) */ int fh_hearing_bit (dbref target, dbref player, int flag, int reset) { int could_hear; could_hear = Hearer(target); fh_any(target, player, flag, reset); handle_ears(target, could_hear, Hearer(target)); return 1; } FLAGENT gen_flags[] = { {(char *)"WIZARD", WIZARD, 'W', 0, fh_wiz_bit}, {(char *)"LINK_OK", LINK_OK, 'L', 0, fh_any}, {(char *)"DARK", DARK, 'D', 0, fh_dark_bit}, {(char *)"STICKY", STICKY, 'S', 0, fh_any}, {(char *)"HAVEN", HAVEN, 'H', 0, fh_any}, {(char *)"QUIET", QUIET, 'Q', 0, fh_any}, {(char *)"HALTED", HALT, 'h', 0, fh_any}, {(char *)"GOING", GOING, 'G', 0, fh_going_bit}, {(char *)"PUPPET", PUPPET, 'p', 0, fh_hearing_bit}, {(char *)"CHOWN_OK", CHOWN_OK, 'C', 0, fh_any}, {(char *)"ENTER_OK", ENTER_OK, 'e', 0, fh_any}, {(char *)"MONITOR", MONITOR, 'M', 0, fh_hearing_bit}, {(char *)"VISUAL", VISUAL, 'V', 0, fh_any}, {(char *)"IMMORTAL", IMMORTAL, 'i', 0, fh_wiz}, {(char *)"STARTUP", STARTUP, 'z', CA_WIZARD, fh_god}, {(char *)"OPAQUE", OPAQUE, 'O', 0, fh_any}, {(char *)"VERBOSE", VERBOSE, 'v', 0, fh_any}, {(char *)"INHERIT", INHERIT, 'I', 0, fh_player}, {(char *)"NOSPOOF", NOSPOOF, 'N', 0, fh_any}, {(char *)"AUDIBLE", HEARTHRU, 'a', 0, fh_hearing_bit}, { NULL, 0, ' ', 0, NULL}}; FLAGENT exit_flags[] = { {(char *)"KEY", EXIT_KEY, 'K', 0, fh_any}, {(char *)"ROBOT", EXIT_ROBOT, 'r', 0, fh_any}, {(char *)"SAFE", EXIT_SAFE, 's', 0, fh_any}, {(char *)"TRANSPARENT", EXIT_SEETHRU, 't', 0, fh_any}, { NULL, 0, ' ', 0, NULL}}; FLAGENT thing_flags[] = { {(char *)"KEY", THING_KEY, 'K', 0, fh_any}, {(char *)"ROBOT", THING_ROBOT, 'r', 0, fh_wiz}, {(char *)"DESTROY_OK", THING_DEST_OK, 'd', 0, fh_any}, {(char *)"SAFE", THING_SAFE, 's', 0, fh_any}, { NULL, 0, ' ', 0, NULL}}; FLAGENT player_flags[] = { {(char *)"BUILDER", PLAYER_BUILD, 'B', 0, fh_wiz}, {(char *)"GAGGED", PLAYER_GAGGED, 'g', 0, fh_wiz}, {(char *)"CONNECTED", PLAYER_CONNECT, 'c', 0, fh_god}, {(char *)"ROBOT", PLAYER_ROBOT, 'r', 0, fh_wiz}, {(char *)"SLAVE", PLAYER_SLAVE, 's', 0, fh_wiz}, {(char *)"UNFINDABLE", PLAYER_UNFIND, 'U', 0, fh_any}, {(char *)"SUSPECT", PLAYER_SUSPECT, 'u', CA_WIZARD, fh_wiz}, { NULL, 0, ' ', 0, NULL}}; FLAGENT room_flags[] = { {(char *)"FLOATING", ROOM_FLOATING, 'F', 0, fh_any}, {(char *)"TEMPLE", ROOM_TEMPLE, 'T', 0, fh_wiz}, {(char *)"ABODE", ROOM_ABODE, 'A', 0, fh_any}, {(char *)"JUMP_OK", ROOM_JUMP_OK, 'J', 0, fh_any}, {(char *)"SAFE", ROOM_SAFE, 's', 0, fh_any}, { NULL, 0, ' ', 0, NULL}}; OBJENT object_types[8] = { {(char *)"ROOM", 'R', CA_PUBLIC, room_flags, &mudstate.r_flags_htab}, {(char *)"THING", ' ', CA_PUBLIC, thing_flags, &mudstate.t_flags_htab}, {(char *)"EXIT", 'E', CA_PUBLIC, exit_flags, &mudstate.e_flags_htab}, {(char *)"PLAYER", 'P', CA_PUBLIC, player_flags, &mudstate.p_flags_htab}, {(char *)"FREE", 'X', CA_WIZARD, NULL, NULL}, {(char *)"LOST", 'Z', CA_WIZARD, NULL, NULL}, {(char *)"TYPE6", '-', CA_GOD, NULL, NULL}, {(char *)"TYPE7", '-', CA_GOD, NULL, NULL}}; /* --------------------------------------------------------------------------- * init_flagtab: initialize flag hash tables. */ void init_flagtab() { FLAGENT *fp; char *nbuf, *np, *bp; hashinit(&mudstate.p_flags_htab, 67); hashinit(&mudstate.t_flags_htab, 67); hashinit(&mudstate.r_flags_htab, 67); hashinit(&mudstate.e_flags_htab, 67); nbuf=alloc_sbuf("init_flagtab"); for (fp=gen_flags; fp->flagname; fp++) { for (np=nbuf,bp=fp->flagname; *bp; np++,bp++) *np=ToLower(*bp); *np='\0'; hashadd(nbuf, (int *)fp, &mudstate.p_flags_htab); hashadd(nbuf, (int *)fp, &mudstate.t_flags_htab); hashadd(nbuf, (int *)fp, &mudstate.r_flags_htab); hashadd(nbuf, (int *)fp, &mudstate.e_flags_htab); } for (fp=player_flags; fp->flagname; fp++) { for (np=nbuf,bp=fp->flagname; *bp; np++,bp++) *np=ToLower(*bp); *np='\0'; hashadd(nbuf, (int *)fp, &mudstate.p_flags_htab); } for (fp=thing_flags; fp->flagname; fp++) { for (np=nbuf,bp=fp->flagname; *bp; np++,bp++) *np=ToLower(*bp); *np='\0'; hashadd(nbuf, (int *)fp, &mudstate.t_flags_htab); } for (fp=room_flags; fp->flagname; fp++) { for (np=nbuf,bp=fp->flagname; *bp; np++,bp++) *np=ToLower(*bp); *np='\0'; hashadd(nbuf, (int *)fp, &mudstate.r_flags_htab); } for (fp=exit_flags; fp->flagname; fp++) { for (np=nbuf,bp=fp->flagname; *bp; np++,bp++) *np=ToLower(*bp); *np='\0'; hashadd(nbuf, (int *)fp, &mudstate.e_flags_htab); } free_sbuf(nbuf); } /* --------------------------------------------------------------------------- * display_flagtable: display available flags. */ void display_flagtab (dbref player, FLAGENT *flagp, const char *prefix) { char *buf, *bp; FLAGENT *fp; bp = buf = alloc_lbuf("display_flagtab"); safe_str((char *)prefix, buf, &bp); for (fp=flagp; fp->flagname; fp++) { if ((fp->listperm & CA_WIZARD) && !Wizard(player)) continue; if ((fp->listperm & CA_GOD) && !God(player)) continue; safe_chr(' ', buf, &bp); safe_str(fp->flagname, buf, &bp); safe_chr('(', buf, &bp); safe_chr(fp->flaglett, buf, &bp); safe_chr(')', buf, &bp); } *bp='\0'; notify(player, buf); free_lbuf(buf); } FLAGENT *find_flag(dbref thing, char *flagname) { HASHTAB *hp; char *cp; /* Make sure that the object type can have flags */ hp = object_types[Typeof(thing)].flaghtab; if (hp == NULL) return NULL; /* Make sure the flag name is valid */ for (cp=flagname; *cp; cp++) *cp = ToLower(*cp); return (FLAGENT *)hashfind(flagname, hp); } /* --------------------------------------------------------------------------- * flag_set: Set or clear a specified flag on an object. */ void flag_set (dbref target, dbref player, char *flag) { FLAGENT *fp; int negate, result; /* Trim spaces, and handle the negation character */ negate = 0; while (*flag && isspace(*flag)) flag++; if (*flag == '!') { negate = 1; flag++; } while (*flag && isspace(*flag)) flag++; /* Make sure a flag name was specified */ if (*flag == '\0') { if (negate) notify(player, "You must specify a flag to clear."); else notify(player, "You must specify a flag to set."); return; } fp = find_flag(target, flag); if (fp == NULL) { notify(player, "I don't understand that flag."); return; } /* Invoke the flag handler, and print feedback */ result = fp->handler(target, player, fp->flagvalue, negate); if (!result) notify(player, "Permission denied."); else if (!Quiet(player)) notify(player, (negate ? "Cleared." : "Set.")); return; } /* --------------------------------------------------------------------------- * decode_flags: converts a flags word into corresponding letters. */ char *decode_flags (dbref player, FLAG flagword, int flagtype) { char *buf, *bp; FLAGENT *fp, *tfp; int operm; buf = bp = alloc_sbuf("decode_flags"); *bp = '\0'; if (!Good_obj(player)) { STARTLOG(LOG_PROBLEMS,"OBJ","RANGE") bp = alloc_mbuf("decode_flags.LOG"); sprintf(bp, "Object number (#%d) out of range in decode_flags", player); log_text(bp); free_mbuf(bp); ENDLOG strcpy(buf, "#-2 ERROR"); return buf; } operm = object_types[flagtype].perm; if (!((operm == CA_PUBLIC) || (operm == CA_WIZARD && Wizard(player)) || (operm == CA_GOD && God(player)))) return buf; if (object_types[flagtype].lett != ' ') safe_chr(object_types[flagtype].lett, buf, &bp); for (fp=gen_flags; fp->flagname; fp++) { if (flagword & fp->flagvalue) { if ((fp->listperm & CA_WIZARD) && !Wizard(player)) continue; if ((fp->listperm & CA_GOD) && !God(player)) continue; safe_chr(fp->flaglett, buf, &bp); } } tfp = object_types[flagtype].flaglist; if (tfp != NULL) for (fp=tfp; fp->flagname; fp++) { if (flagword & fp->flagvalue) { if ((fp->listperm & CA_WIZARD) && !Wizard(player)) continue; if ((fp->listperm & CA_GOD) && !God(player)) continue; /* don't show CONNECT flag on dark wizards to mortals */ if ((flagtype == TYPE_PLAYER) && (fp->flagvalue == PLAYER_CONNECT) && ((flagword & (WIZARD|DARK)) == (WIZARD|DARK)) && !Wizard(player)) continue; safe_chr(fp->flaglett, buf, &bp); } } *bp = '\0'; return buf; } /* --------------------------------------------------------------------------- * flag_description: Return an mbuf containing the type and flags on thing. */ char *flag_description(dbref player, dbref target) { char *buff, *bp; FLAGENT *fp, *tfp; int otype; /* Allocate the return buffer */ otype = Typeof(target); bp = buff = alloc_mbuf("flag_description"); /* Store the header strings and object type */ safe_str((char *)"Type: ", buff, &bp); safe_str(object_types[otype].name, buff, &bp); safe_str((char *)" Flags:", buff, &bp); if (object_types[otype].perm != CA_PUBLIC) { *bp = '\0'; return buff; } /* Store the type-invariant flags */ for (fp=gen_flags; fp->flagname; fp++) { if (Flags(target) & fp->flagvalue) { if ((fp->listperm & CA_WIZARD) && !Wizard(player)) continue; if ((fp->listperm & CA_GOD) && !God(player)) continue; safe_chr(' ', buff, &bp); safe_str(fp->flagname, buff, &bp); } } /* Store the type-specific flags */ tfp = object_types[otype].flaglist; if (tfp != NULL) for (fp=tfp; fp->flagname; fp++) { if (Flags(target) & fp->flagvalue) { if ((fp->listperm & CA_WIZARD) && !Wizard(player)) continue; if ((fp->listperm & CA_GOD) && !God(player)) continue; /* don't show CONNECT flag on dark wizards to mortals */ if ((otype == TYPE_PLAYER) && (fp->flagvalue == PLAYER_CONNECT) && ((Flags(target) & (WIZARD|DARK)) == (WIZARD|DARK)) && !Wizard(player)) continue; safe_chr(' ', buff, &bp); safe_str(fp->flagname, buff, &bp); } } /* Terminate the string, and return the buffer to the caller */ *bp = '\0'; return buff; } /* --------------------------------------------------------------------------- * Return an lbuf containing the name and number of an object */ char *unparse_object_numonly(dbref target) { char *buf; buf=alloc_lbuf("unparse_object_numonly"); if (target == NOTHING) { strcpy(buf, "*NOTHING*"); } else if (target == HOME) { strcpy(buf, "*HOME*"); } else if (!Good_obj(target)) { sprintf(buf, "*ILLEGAL*(#%d)", target); } else { sprintf(buf, "%s(#%d)", Name(target), target); } return buf; } /* --------------------------------------------------------------------------- * Return an lbuf pointing to the object name and possibly the db# and flags */ char *unparse_object(dbref player, dbref target) { char *buf, *fp; buf=alloc_lbuf("unparse_object"); if (target == NOTHING) { strcpy(buf, "*NOTHING*"); } else if (target == HOME) { strcpy(buf, "*HOME*"); } else if (!Good_obj(target)) { sprintf(buf, "*ILLEGAL*(#%d)", target); } else { if (Examinable(player, target) || Linkable(player, target) || Abode(target) || (Flags(target) & CHOWN_OK) || (IS(target, TYPE_THING, THING_DEST_OK)) || (IS(target, TYPE_ROOM, ROOM_JUMP_OK))) { /* show everything */ fp = unparse_flags(player, target); sprintf(buf, "%s(#%d%s)", Name(target), target, fp); free_sbuf(fp); } else { /* show only the name. */ strcpy(buf, Name(target)); } } return buf; }