/*! \file flags.cpp * \brief Flag manipulation routines. * */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "routing.h" using namespace std; /* --------------------------------------------------------------------------- * fh_any: set or clear indicated bit, no security checking */ static bool fh_any(dbref target, dbref player, FLAG flag, int fflags, bool reset) { // Never let God drop his/her own wizbit. // if ( God(target) && reset && flag == WIZARD && fflags == FLAG_WORD1) { notify(player, M_("You cannot make God mortal.")); return false; } // Otherwise we can go do it. // if (reset) { s_Flags(target, fflags, db[target].fs.word[fflags] & ~flag); } else { s_Flags(target, fflags, db[target].fs.word[fflags] | flag); } return true; } /* --------------------------------------------------------------------------- * fh_room_bit: only settable on rooms (TYPE_ROOM). */ static bool fh_room_bit(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!isRoom(target)) { return false; } bool result = fh_any(target, player, flag, fflags, reset); if (result) { route_invalidate(); } return result; } /* --------------------------------------------------------------------------- * fh_god: only GOD may set or clear the bit */ static bool fh_god(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!God(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_wiz: only WIZARDS (or GOD) may set or clear the bit */ static bool fh_wiz(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!Wizard(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_wizroy: only WIZARDS, ROYALTY, (or GOD) may set or clear the bit */ static bool fh_wizroy(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!WizRoy(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_restrict_player (renamed from fh_fixed): Only Wizards can set * * this on players, but ordinary players can set it on other types * * of objects. */ static bool fh_restrict_player ( dbref target, dbref player, FLAG flag, int fflags, bool reset ) { if ( isPlayer(target) && !Wizard(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* --------------------------------------------------------------------------- * fh_privileged: You can set this flag on a non-player object, if you * yourself have this flag and are a player who owns themselves (i.e., * no robots). Only God can set this on a player. */ static bool fh_privileged ( dbref target, dbref player, FLAG flag, int fflags, bool reset ) { if (!God(player)) { if ( isPlayer(target) || !isPlayer(player) || player != Owner(player) || (db[player].fs.word[fflags] & flag) == 0) { return false; } } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_inherit: only players may set or clear this bit. */ static bool fh_inherit(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!Inherits(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_dark_bit: manipulate the dark bit. Nonwizards may not set on players. */ static bool fh_dark_bit(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if ( !reset && isPlayer(target) && !( (target == player) && (Can_Hide(player) || Can_Dark(player))) && !Wizard(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_going_bit: manipulate the going bit. Non-gods may only clear. */ static bool fh_going_bit(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if ( Going(target) && reset && (Typeof(target) != TYPE_GARBAGE)) { notify(player, M_("Your object has been spared from destruction.")); return (fh_any(target, player, flag, fflags, reset)); } if (!God(player)) { return false; } // Even God should not be allowed set protected dbrefs GOING. // if ( !reset && ( target == 0 || God(target) || target == mudconf.start_home || target == mudconf.start_room || target == mudconf.default_home || target == mudconf.master_room)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_hear_bit: set or clear bits that affect hearing. */ static bool fh_hear_bit(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (isPlayer(target) && (flag & MONITOR)) { if (Can_Monitor(player)) { return (fh_any(target, player, flag, fflags, reset)); } else { return false; } } bool could_hear = Hearer(target); bool result = fh_any(target, player, flag, fflags, reset); handle_ears(target, could_hear, Hearer(target)); return result; } /* --------------------------------------------------------------------------- * fh_player_bit: Can set and reset this on everything but players. */ static bool fh_player_bit ( dbref target, dbref player, FLAG flag, int fflags, bool reset ) { if (isPlayer(target)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* --------------------------------------------------------------------------- * fh_staff: only STAFF, WIZARDS, ROYALTY, (or GOD) may set or clear * the bit. */ static bool fh_staff ( dbref target, dbref player, FLAG flag, int fflags, bool reset ) { if (!Staff(player) && !God(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_unicode: only players may set or clear this bit. */ static bool fh_unicode(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!isPlayer(target)) { return false; } if (fh_any(target, player, flag, fflags, reset)) { if (!reset) { set_player_encoding(target, CHARSET_UTF8); } else { reset_player_encoding(target); } return true; } return false; } /* * --------------------------------------------------------------------------- * * fh_ascii: only players may set or clear this bit. */ static bool fh_ascii(const dbref target, const dbref player, FLAG flag, int fflags, const bool reset) { if (!isPlayer(target)) { return false; } const bool result = fh_any(target, player, flag, fflags, reset); if (result) { if (!reset) { set_player_encoding(target, CHARSET_ASCII); } else { reset_player_encoding(target); } } return result; } static FLAGBITENT fbeAbode = { ABODE, 'A', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeAnsi = { ANSI, 'X', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeAudible = { HEARTHRU, 'a', FLAG_WORD1, 0, fh_hear_bit}; static FLAGBITENT fbeAuditorium = { AUDITORIUM, 'b', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeBlind = { BLIND, 'B', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeChownOk = { CHOWN_OK, 'C', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeColor256 = { COLOR256, ' ', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeTruecolor = { TRUECOLOR, ' ', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeConnected = { CONNECTED, 'c', FLAG_WORD2, CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeDark = { DARK, 'D', FLAG_WORD1, 0, fh_dark_bit}; static FLAGBITENT fbeDestroyOk = { DESTROY_OK, 'd', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeEnterOk = { ENTER_OK, 'e', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeFixed = { FIXED_FLAG, 'f', FLAG_WORD2, 0, fh_restrict_player}; static FLAGBITENT fbeFloating = { FLOATING, 'F', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeGagged = { GAGGED, 'j', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeGoing = { GOING, 'G', FLAG_WORD1, CA_NO_DECOMP, fh_going_bit}; static FLAGBITENT fbeHalted = { HALT, 'h', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeHasDaily = { HAS_DAILY, '*', FLAG_WORD2, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeHasForwardList = { HAS_FWDLIST, '&', FLAG_WORD2, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeHasListen = { HAS_LISTEN, '@', FLAG_WORD2, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeHasStartup = { HAS_STARTUP, '+', FLAG_WORD1, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeHaven = { HAVEN, 'H', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeHead = { HEAD_FLAG, '?', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeHtml = { HTML, '(', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeImmortal = { IMMORTAL, 'i', FLAG_WORD1, 0, fh_wiz}; static FLAGBITENT fbeInherit = { INHERIT, 'I', FLAG_WORD1, 0, fh_inherit}; static FLAGBITENT fbeJumpOk = { JUMP_OK, 'J', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeKeepAlive = { CKEEPALIVE, 'k', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeKey = { KEY, 'K', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeLight = { LIGHT, 'l', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeLinkOk = { LINK_OK, 'L', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeMonitor = { MONITOR, 'M', FLAG_WORD1, 0, fh_hear_bit}; static FLAGBITENT fbeMyopic = { MYOPIC, 'm', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeNoCommand = { NO_COMMAND, 'n', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeAscii = { ASCII , '~', FLAG_WORD2, 0, fh_ascii}; static FLAGBITENT fbeNoBleed = { NOBLEED, '-', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeNoSpoof = { NOSPOOF, 'N', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeOpaque = { MUX_OPAQUE, 'O', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeOpenOk = { OPEN_OK, 'z', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeParentOk = { PARENT_OK, 'Y', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbePlayerMails = { PLAYER_MAILS, ' ', FLAG_WORD2, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbePuppet = { PUPPET, 'p', FLAG_WORD1, 0, fh_hear_bit}; static FLAGBITENT fbeQuiet = { QUIET, 'Q', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeRobot = { ROBOT, 'r', FLAG_WORD1, 0, fh_player_bit}; static FLAGBITENT fbeRoyalty = { ROYALTY, 'Z', FLAG_WORD1, 0, fh_wiz}; static FLAGBITENT fbeSafe = { SAFE, 's', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeSlave = { SLAVE, 'x', FLAG_WORD2, CA_WIZARD, fh_wiz}; static FLAGBITENT fbeStaff = { STAFF, 'w', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeSticky = { STICKY, 'S', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeSuspect = { SUSPECT, 'u', FLAG_WORD2, CA_WIZARD, fh_wiz}; static FLAGBITENT fbeTalkMode = { TALKMODE, ' ', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeTerse = { TERSE, 'q', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeTrace = { TRACE, 'T', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeTransparent = { SEETHRU, 't', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeUnfindable = { UNFINDABLE, 'U', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeUnicode = { MUX_UNICODE, ' ', FLAG_WORD3, CA_NO_DECOMP, fh_unicode}; static FLAGBITENT fbeUninspected = { UNINSPECTED, 'g', FLAG_WORD2, 0, fh_wizroy}; static FLAGBITENT fbeVacation = { VACATION, '|', FLAG_WORD2, 0, fh_restrict_player}; static FLAGBITENT fbeVerbose = { VERBOSE, 'v', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeVisual = { VISUAL, 'V', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeWizard = { WIZARD, 'W', FLAG_WORD1, 0, fh_god}; static FLAGBITENT fbeAlone = { ALONE, ' ', FLAG_WORD3, 0, fh_wiz}; static FLAGBITENT fbeNoExamine = { NOEXAMINE, 'E', FLAG_WORD3, 0, fh_wizroy}; static FLAGBITENT fbeNoModify = { NOMODIFY, ' ', FLAG_WORD3, 0, fh_wizroy}; static FLAGBITENT fbeIndestructible = { INDESTRUCTIBLE, ' ', FLAG_WORD3, 0, fh_wizroy}; static FLAGBITENT fbeNoEval = { NOEVAL, ' ', FLAG_WORD3, 0, fh_any}; static FLAGBITENT fbeNavigable = { NAVIGABLE, ' ', FLAG_WORD3, 0, fh_room_bit}; static FLAGBITENT fbeSitemon = { SITEMON, '$', FLAG_WORD3, 0, fh_wiz}; #ifdef WOD_REALMS static FLAGBITENT fbeFae = { FAE, '0', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeChimera = { CHIMERA, '1', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbePeering = { PEERING, '2', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeUmbra = { UMBRA, '3', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeShroud = { SHROUD, '4', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeMatrix = { MATRIX, '5', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeObf = { OBF, '6', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeHss = { HSS, '7', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeMedium = { MEDIUM, '8', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeDead = { DEAD, '9', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeMarker0 = { MARK_0, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker1 = { MARK_1, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker2 = { MARK_2, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker3 = { MARK_3, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker4 = { MARK_4, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker5 = { MARK_5, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker6 = { MARK_6, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker7 = { MARK_7, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker8 = { MARK_8, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker9 = { MARK_9, ' ', FLAG_WORD3, 0, fh_god}; #else // WOD_REALMS static FLAGBITENT fbeMarker0 = { MARK_0, '0', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker1 = { MARK_1, '1', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker2 = { MARK_2, '2', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker3 = { MARK_3, '3', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker4 = { MARK_4, '4', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker5 = { MARK_5, '5', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker6 = { MARK_6, '6', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker7 = { MARK_7, '7', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker8 = { MARK_8, '8', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker9 = { MARK_9, '9', FLAG_WORD3, 0, fh_god}; #endif // WOD_REALMS FLAGNAMEENT gen_flag_names[] = { {T("ALONE"), true, &fbeAlone }, {T("ABODE"), true, &fbeAbode }, {T("ACCENTS"), false, &fbeAscii }, {T("ANSI"), true, &fbeAnsi }, {T("ASCII"), true, &fbeAscii }, {T("AUDIBLE"), true, &fbeAudible }, {T("AUDITORIUM"), true, &fbeAuditorium }, {T("BLEED"), false, &fbeNoBleed }, {T("BLIND"), true, &fbeBlind }, {T("COMMANDS"), false, &fbeNoCommand }, {T("CHOWN_OK"), true, &fbeChownOk }, {T("COLOR256"), true, &fbeColor256 }, {T("CONNECTED"), true, &fbeConnected }, {T("DARK"), true, &fbeDark }, {T("DESTROY_OK"), true, &fbeDestroyOk }, {T("ENTER_OK"), true, &fbeEnterOk }, {T("FIXED"), true, &fbeFixed }, {T("FLOATING"), true, &fbeFloating }, {T("GAGGED"), true, &fbeGagged }, {T("GOING"), true, &fbeGoing }, {T("HALTED"), true, &fbeHalted }, {T("HAS_DAILY"), true, &fbeHasDaily }, {T("HAS_FORWARDLIST"), true, &fbeHasForwardList }, {T("HAS_LISTEN"), true, &fbeHasListen }, {T("HAS_STARTUP"), true, &fbeHasStartup }, {T("HAVEN"), true, &fbeHaven }, {T("HEAD"), true, &fbeHead }, {T("HTML"), true, &fbeHtml }, {T("IMMORTAL"), true, &fbeImmortal }, {T("INDESTRUCTIBLE"), true, &fbeIndestructible }, {T("INHERIT"), true, &fbeInherit }, {T("JUMP_OK"), true, &fbeJumpOk }, {T("KEEPALIVE"), true, &fbeKeepAlive }, {T("KEY"), true, &fbeKey }, {T("LIGHT"), true, &fbeLight }, {T("LINK_OK"), true, &fbeLinkOk }, {T("MARKER0"), true, &fbeMarker0 }, {T("MARKER1"), true, &fbeMarker1 }, {T("MARKER2"), true, &fbeMarker2 }, {T("MARKER3"), true, &fbeMarker3 }, {T("MARKER4"), true, &fbeMarker4 }, {T("MARKER5"), true, &fbeMarker5 }, {T("MARKER6"), true, &fbeMarker6 }, {T("MARKER7"), true, &fbeMarker7 }, {T("MARKER8"), true, &fbeMarker8 }, {T("MARKER9"), true, &fbeMarker9 }, {T("MONITOR"), true, &fbeMonitor }, {T("MYOPIC"), true, &fbeMyopic }, {T("NAVIGABLE"), true, &fbeNavigable }, {T("NO_COMMAND"), true, &fbeNoCommand }, {T("NO_EXAMINE"), true, &fbeNoExamine }, {T("NOBLEED"), true, &fbeNoBleed }, {T("NOEVAL"), true, &fbeNoEval }, {T("NOEXAMINE"), true, &fbeNoExamine }, {T("NOMODIFY"), true, &fbeNoModify }, {T("NO_MODIFY"), true, &fbeNoModify }, {T("NOSPOOF"), true, &fbeNoSpoof }, {T("OPAQUE"), true, &fbeOpaque }, {T("OPEN_OK"), true, &fbeOpenOk }, {T("PARENT_OK"), true, &fbeParentOk }, {T("PLAYER_MAILS"), true, &fbePlayerMails }, {T("PUPPET"), true, &fbePuppet }, {T("QUIET"), true, &fbeQuiet }, {T("ROBOT"), true, &fbeRobot }, {T("ROYALTY"), true, &fbeRoyalty }, {T("SAFE"), true, &fbeSafe }, {T("SITEMON"), true, &fbeSitemon }, {T("SLAVE"), true, &fbeSlave }, {T("SPOOF"), false, &fbeNoSpoof }, {T("STAFF"), true, &fbeStaff }, {T("STICKY"), true, &fbeSticky }, {T("SUSPECT"), true, &fbeSuspect }, {T("TALKMODE"), true, &fbeTalkMode }, {T("TERSE"), true, &fbeTerse }, {T("TRACE"), true, &fbeTrace }, {T("TRANSPARENT"), true, &fbeTransparent }, {T("TRUECOLOR"), true, &fbeTruecolor }, {T("UNFINDABLE"), true, &fbeUnfindable }, {T("UNICODE"), true, &fbeUnicode }, {T("UNINSPECTED"), true, &fbeUninspected }, {T("VACATION"), true, &fbeVacation }, {T("VERBOSE"), true, &fbeVerbose }, {T("VISUAL"), true, &fbeVisual }, {T("WIZARD"), true, &fbeWizard }, #ifdef WOD_REALMS {T("FAE"), true, &fbeFae }, {T("CHIMERA"), true, &fbeChimera }, {T("PEERING"), true, &fbePeering }, {T("UMBRA"), true, &fbeUmbra }, {T("SHROUD"), true, &fbeShroud }, {T("MATRIX"), true, &fbeMatrix }, {T("OBF"), true, &fbeObf }, {T("HSS"), true, &fbeHss }, {T("MEDIUM"), true, &fbeMedium }, {T("DEAD"), true, &fbeDead }, #endif // WOD_REALMS {nullptr, false, nullptr} }; OBJENT object_types[8] = { {T("ROOM"), 'R', CA_PUBLIC, OF_CONTENTS|OF_EXITS|OF_DROPTO|OF_HOME}, {T("THING"), ' ', CA_PUBLIC, OF_CONTENTS|OF_LOCATION|OF_EXITS|OF_HOME|OF_SIBLINGS}, {T("EXIT"), 'E', CA_PUBLIC, OF_SIBLINGS}, {T("PLAYER"), 'P', CA_PUBLIC, OF_CONTENTS|OF_LOCATION|OF_EXITS|OF_HOME|OF_OWNER|OF_SIBLINGS}, {T("TYPE5"), '+', CA_GOD, 0}, {T("GARBAGE"), '-', CA_PUBLIC, OF_CONTENTS|OF_LOCATION|OF_EXITS|OF_HOME|OF_SIBLINGS}, {T("GARBAGE"), '#', CA_GOD, 0}, {T("GARBAGE"), '=', CA_GOD, 0} }; /* --------------------------------------------------------------------------- * init_flagtab: initialize flag hash tables. */ void init_flagtab(void) { for (FLAGNAMEENT *flag_name_entity = gen_flag_names; flag_name_entity->pOrigName; flag_name_entity++) { flag_name_entity->flagname = const_cast(flag_name_entity->pOrigName); const size_t flag_name_length = strlen(reinterpret_cast(flag_name_entity->pOrigName)); vector flag_name(flag_name_entity->pOrigName, flag_name_entity->pOrigName + flag_name_length); auto it = mudstate.flag_names_map.find(flag_name); if (it == mudstate.flag_names_map.end()) { mudstate.flag_names_map.insert(make_pair(flag_name, flag_name_entity)); } } } /* --------------------------------------------------------------------------- * display_flags: display available flags. */ void display_flagtab(dbref player) { FLAGNAMEENT *fp; LBuf buf = LBuf_Src("display_flagtab"); UTF8 *bp = buf.get(); safe_str(M_("Flags:"), buf, &bp); for (fp = gen_flag_names; fp->flagname; fp++) { FLAGBITENT *fbe = fp->fbe; if ( ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player))) { continue; } safe_chr(' ', buf, &bp); safe_str(fp->flagname, buf, &bp); if (fbe->flaglett != ' ') { safe_chr('(', buf, &bp); if (!fp->bPositive) { safe_chr('!', buf, &bp); } safe_chr(fbe->flaglett, buf, &bp); safe_chr(')', buf, &bp); } } *bp = '\0'; notify(player, buf); } UTF8 *MakeCanonicalFlagName ( const UTF8 *pName, int *pnName, bool *pbValid ) { thread_local UTF8 buff[SBUF_SIZE]; UTF8 *p = buff; int nName = 0; // Uppercase flag name one code point at a time (Unicode-aware). // while ('\0' != *pName) { size_t n = utf8_FirstByte[static_cast(*pName)]; if (n >= UTF8_CONTINUE) { *pnName = 0; *pbValid = false; return nullptr; } for (size_t j = 1; j < n; j++) { if ( '\0' == pName[j] || UTF8_CONTINUE != utf8_FirstByte[static_cast(pName[j])]) { *pnName = 0; *pbValid = false; return nullptr; } } bool bXor; const string_desc *qDesc = mux_toupper(pName, bXor); size_t m; if (nullptr == qDesc) { m = n; if (nName + static_cast(m) >= SBUF_SIZE) { break; } for (size_t j = 0; j < m; j++) { *p++ = pName[j]; } } else { m = qDesc->n_bytes; if ( bXor && m != n) { *pnName = 0; *pbValid = false; return nullptr; } if (nName + static_cast(m) >= SBUF_SIZE) { break; } if (bXor) { for (size_t j = 0; j < m; j++) { *p++ = pName[j] ^ qDesc->p[j]; } } else { for (size_t j = 0; j < m; j++) { *p++ = qDesc->p[j]; } } } nName += static_cast(m); pName += n; } *p = '\0'; if ( 0 < nName && nName < SBUF_SIZE) { *pnName = nName; *pbValid = true; return buff; } else { *pnName = 0; *pbValid = false; return nullptr; } } static FLAGNAMEENT* find_flag(const UTF8* input_flag_name) { // Convert input_flag_name to canonical lowercase format. // int flag_name_length; bool valid; UTF8* flag_name = MakeCanonicalFlagName(input_flag_name, &flag_name_length, &valid); if (valid) { const vector name(flag_name, flag_name + flag_name_length); const auto it = mudstate.flag_names_map.find(name); if (it != mudstate.flag_names_map.end()) { return it->second; } } return nullptr; } // --------------------------------------------------------------------------- // flag_set: Set or clear a specified flag on an object. // void flag_set(dbref target, dbref player, UTF8 *flag, int key) { bool bDone = false; do { // Trim spaces, and handle the negation character. // while (mux_isspace(*flag)) { flag++; } bool bNegate = false; if (*flag == '!') { bNegate = true; do { flag++; } while (mux_isspace(*flag)); } // Beginning of flag name is now 'flag'. // UTF8 *nflag = flag; while ( *nflag != '\0' && !mux_isspace(*nflag)) { nflag++; } if (*nflag == '\0') { bDone = true; } else { *nflag = '\0'; } // Make sure a flag name was specified. // if (*flag == '\0') { if (bNegate) { notify(player, M_("You must specify a flag to clear.")); } else { notify(player, M_("You must specify a flag to set.")); } } else { FLAGNAMEENT *fp = find_flag(flag); if (!fp) { notify(player, M_("I do not understand that flag.")); } else { FLAGBITENT *fbe = fp->fbe; bool bClearSet = bNegate; if (!fp->bPositive) { bNegate = !bNegate; } // Check if the flag is already in the desired state. // bool bCurrentlySet = (db[target].fs.word[fbe->flagflag] & fbe->flagvalue) != 0; if (bNegate == bCurrentlySet) { // State needs to change. Check NOMODIFY first. // if (NoModify(target) && !WizRoy(player)) { notify(player, NOPERM_MESSAGE); bDone = true; continue; } // Invoke the flag handler, and print feedback. // if (!fbe->handler(target, player, fbe->flagvalue, fbe->flagflag, bNegate)) { notify(player, NOPERM_MESSAGE); } else if (!(key & SET_QUIET) && !Quiet(player)) { notify(player, (bClearSet ? M_("Cleared.") : M_("Set."))); } } else if (!(key & SET_QUIET) && !Quiet(player)) { notify(player, (bClearSet ? M_("Already cleared.") : M_("Already set."))); } } } flag = nflag + 1; } while (!bDone); } /* * --------------------------------------------------------------------------- * * decode_flags: converts a flags word into corresponding letters. */ UTF8 *decode_flags(dbref player, FLAGSET *fs) { UTF8 *buf, *bp; buf = bp = alloc_sbuf("decode_flags"); *bp = '\0'; if (!Good_obj(player)) { mux_strncpy(buf, S_("#-2 ERROR"), SBUF_SIZE-1); return buf; } int flagtype = fs->word[FLAG_WORD1] & TYPE_MASK; bool bNeedColon = true; if (object_types[flagtype].lett != ' ') { safe_sb_chr(object_types[flagtype].lett, buf, &bp); bNeedColon = false; } FLAGNAMEENT *fp; for (fp = gen_flag_names; fp->flagname; fp++) { FLAGBITENT *fbe = fp->fbe; if ( !fp->bPositive || fbe->flaglett == ' ') { // Only look at positive-sense entries that have non-space flag // letters. // continue; } if (fs->word[fbe->flagflag] & fbe->flagvalue) { if ( ( (fbe->listperm & CA_STAFF) && !Staff(player)) || ( (fbe->listperm & CA_ADMIN) && !WizRoy(player)) || ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player))) { continue; } // Don't show CONNECT on hidden players to those who can't see // them. Test DARK alone -- that is what Hidden() means -- to // match has_flag() and flag_description(). Requiring WIZARD too // leaked the 'c' letter for every dark non-wizard: royalty, // staff, and any mortal able to set itself DARK (#1184). This // takes a FLAGSET rather than a dbref, so the test is on the // flagset the caller passed, which is the target's. // if ( flagtype == TYPE_PLAYER && fbe->flagflag == FLAG_WORD2 && fbe->flagvalue == CONNECTED && (fs->word[FLAG_WORD1] & DARK) != 0 && !See_Hidden(player)) { continue; } if ( bNeedColon && mux_isdigit(fbe->flaglett)) { // We can't allow numerical digits at the beginning. // safe_sb_chr(':', buf, &bp); } safe_sb_chr(fbe->flaglett, buf, &bp); bNeedColon = false; } } *bp = '\0'; return buf; } /* * --------------------------------------------------------------------------- * * has_flag: does object have flag visible to player? */ bool has_flag(dbref player, dbref it, const UTF8 *flagname) { FLAGNAMEENT *fp = find_flag(flagname); if (!fp) { return false; } FLAGBITENT *fbe = fp->fbe; if ( ( fp->bPositive && (db[it].fs.word[fbe->flagflag] & fbe->flagvalue)) || ( !fp->bPositive && (db[it].fs.word[fbe->flagflag] & fbe->flagvalue) == 0)) { if ( ( (fbe->listperm & CA_STAFF) && !Staff(player)) || ( (fbe->listperm & CA_ADMIN) && !WizRoy(player)) || ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player))) { return false; } // Don't show CONNECT on dark wizards to mortals // if ( isPlayer(it) && (fbe->flagvalue == CONNECTED) && (fbe->flagflag == FLAG_WORD2) && Hidden(it) && !See_Hidden(player)) { return false; } return true; } return false; } /* * --------------------------------------------------------------------------- * * flag_description: Return an mbuf containing the type and flags on thing. */ UTF8 *flag_description(dbref player, dbref target) { // Allocate the return buffer. // int otype = Typeof(target); UTF8 *buff = alloc_mbuf("flag_description"); UTF8 *bp = buff; // Store the header strings and object type. // safe_mb_str(T("Type: "), buff, &bp); safe_mb_str(object_types[otype].name, buff, &bp); safe_mb_str(T(" Flags:"), buff, &bp); if (object_types[otype].perm != CA_PUBLIC) { *bp = '\0'; return buff; } // Store the type-invariant flags. // FLAGNAMEENT *fp; for (fp = gen_flag_names; fp->flagname; fp++) { if (!fp->bPositive) { continue; } FLAGBITENT *fbe = fp->fbe; if (db[target].fs.word[fbe->flagflag] & fbe->flagvalue) { if ( ( (fbe->listperm & CA_STAFF) && !Staff(player)) || ( (fbe->listperm & CA_ADMIN) && !WizRoy(player)) || ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player))) { continue; } // Don't show CONNECT on dark wizards to mortals. // if ( isPlayer(target) && (fbe->flagvalue == CONNECTED) && (fbe->flagflag == FLAG_WORD2) && Hidden(target) && !See_Hidden(player)) { continue; } safe_mb_chr(' ', buff, &bp); safe_mb_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 */ UTF8 *unparse_object_numonly(dbref target) { LBuf buf = LBuf_Src("unparse_object_numonly"); if (target < 0) { mux_strncpy(buf, aszSpecialDBRefNames[-target], LBUF_SIZE-1); } else if (!Good_obj(target)) { mux_sprintf(buf, LBUF_SIZE, T("*ILLEGAL*(#%d)"), target); } else { mux_sprintf(buf, LBUF_SIZE, T("%s(#%d)"), PureName(target), target); } return buf.release(); } /* * --------------------------------------------------------------------------- * * Return an lbuf pointing to the object name and possibly the db# and flags */ UTF8 *unparse_object(dbref player, dbref target, bool obey_myopic) { LBuf buf = LBuf_Src("unparse_object"); if (NOPERM <= target && target < 0) { mux_strncpy(buf, aszSpecialDBRefNames[-target], LBUF_SIZE-1); } else if (!Good_obj(target)) { mux_sprintf(buf, LBUF_SIZE, T("*ILLEGAL*(#%d)"), target); } else { bool exam; if (obey_myopic) { exam = MyopicExam(player, target); } else { exam = Examinable(player, target); } // Leave and extra 100 bytes for the dbref and flags at the end and // color at the beginning if necessary.. // mux_field fldName = StripTabsAndTruncate( Moniker(target), buf, LBUF_SIZE-100, LBUF_SIZE-100); UTF8 *bp = buf + fldName.m_byte; if ( exam || (Flags(target) & (CHOWN_OK | JUMP_OK | LINK_OK | DESTROY_OK)) || (Flags2(target) & ABODE)) { // Show everything. // UTF8 *fp = decode_flags(player, &(db[target].fs)); safe_str(T("(#"), buf, &bp); safe_ltoa(target, buf, &bp); safe_str(fp, buf, &bp); safe_chr(')', buf, &bp); free_sbuf(fp); } *bp = '\0'; } return buf.release(); } /* --------------------------------------------------------------------------- * cf_flag_access: Modify who can set a flag. */ CF_HAND(cf_flag_access) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); string_token st(str, T(" \t=,")); UTF8 *fstr = st.parse(); UTF8 *permstr = st.parse(); if ( nullptr == fstr || '\0' == fstr[0] || nullptr == permstr || '\0' == permstr[0]) { return -1; } FLAGNAMEENT *fp; if ((fp = find_flag(fstr)) == nullptr) { cf_log_notfound(player, cmd, T("No such flag"), fstr); return -1; } FLAGBITENT *fbe = fp->fbe; // Don't change the handlers on special things. // if ( (fbe->handler != fh_any) && (fbe->handler != fh_wizroy) && (fbe->handler != fh_wiz) && (fbe->handler != fh_god) && (fbe->handler != fh_restrict_player) && (fbe->handler != fh_privileged)) { STARTLOG(LOG_CONFIGMODS, "CFG", "PERM"); log_text(T("Cannot change access for flag: ")); log_text(fp->flagname); ENDLOG; notify(player, M_("Special flags cannot be modified with flag_access.")); return -1; } bool negate = false; if ('!' == *permstr) { negate = true; permstr++; } if (!strcmp(reinterpret_cast(permstr), "any")) { fbe->handler = fh_any; } else if (!strcmp(reinterpret_cast(permstr), "dark")) { if (negate) { fbe->listperm &= ~CA_GOD; } else { fbe->listperm |= CA_GOD; } } else if (!strcmp(reinterpret_cast(permstr), "hidden")) { if (negate) { fbe->listperm &= ~CA_WIZARD; } else { fbe->listperm |= CA_WIZARD; } } else if (!strcmp(reinterpret_cast(permstr), "royalty")) { fbe->handler = fh_wizroy; } else if (!strcmp(reinterpret_cast(permstr), "wizard")) { fbe->handler = fh_wiz; } else if (!strcmp(reinterpret_cast(permstr), "god")) { fbe->handler = fh_god; } else if (!strcmp(reinterpret_cast(permstr), "restrict_player")) { fbe->handler = fh_restrict_player; } else if (!strcmp(reinterpret_cast(permstr), "privileged")) { fbe->handler = fh_privileged; } else if (!strcmp(reinterpret_cast(permstr), "staff")) { fbe->handler = fh_staff; } else { cf_log_notfound(player, cmd, T("Flag access"), permstr); return -1; } return 0; } /* * --------------------------------------------------------------------------- * * convert_flags: convert a list of flag letters into its bit pattern. * * Also set the type qualifier if specified and not already set. */ bool convert_flags(dbref player, UTF8 *flaglist, FLAGSET *fset, FLAG *p_type) { FLAG type = NOTYPE; FLAGSET flagmask; memset(&flagmask, 0, sizeof(flagmask)); int i; UTF8 *s; bool handled; for (s = flaglist; *s; s++) { handled = false; // Check for object type. // for (i = 0; i <= 7 && !handled; i++) { if ( object_types[i].lett == *s && !( ( (object_types[i].perm & CA_STAFF) && !Staff(player)) || ( (object_types[i].perm & CA_ADMIN) && !WizRoy(player)) || ( (object_types[i].perm & CA_WIZARD) && !Wizard(player)) || ( (object_types[i].perm & CA_GOD) && !God(player)))) { if ( type != NOTYPE && type != i) { UTF8 *p = tprintf(M_("%c: Conflicting type specifications."), *s); notify(player, p); return false; } type = i; handled = true; } } // Check generic flags. // if (handled) { continue; } FLAGNAMEENT *fp; for (fp = gen_flag_names; fp->flagname && !handled; fp++) { FLAGBITENT *fbe = fp->fbe; if ( !fp->bPositive || fbe->flaglett == ' ') { continue; } if ( fbe->flaglett == *s && !( ( (fbe->listperm & CA_STAFF) && !Staff(player)) || ( (fbe->listperm & CA_ADMIN) && !WizRoy(player)) || ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player)))) { flagmask.word[fbe->flagflag] |= fbe->flagvalue; handled = true; } } if (!handled) { notify(player, tprintf(M_("%c: Flag unknown or not valid for specified object type"), *s)); return false; } } // Return flags to search for and type. // *fset = flagmask; *p_type = type; return true; } /* * --------------------------------------------------------------------------- * * decompile_flags: Produce commands to set flags on target. */ void decompile_flags(dbref player, dbref thing, UTF8 *thingname) { // Report generic flags. // FLAGNAMEENT *fp; for (fp = gen_flag_names; fp->flagname; fp++) { FLAGBITENT *fbe = fp->fbe; // Only handle positive-sense entries. // Skip if we shouldn't decompile this flag. // Skip if this flag isn't set. // Skip if we can't see this flag. // if ( !fp->bPositive || (fbe->listperm & CA_NO_DECOMP) || (db[thing].fs.word[fbe->flagflag] & fbe->flagvalue) == 0 || !check_access(player, fbe->listperm)) { continue; } // Report this flag. // notify(player, tprintf(T("@set %s=%s"), thingname, fp->flagname)); } } // do_flag: Rename flags or remove flag aliases. // Based on RhostMUSH code. // static bool flag_rename(UTF8 *existing_flag_name, UTF8 *new_flag_name) { int existing_flag_name_length; bool valid; UTF8 *canonical_existing_flag_name = MakeCanonicalFlagName(existing_flag_name, &existing_flag_name_length, &valid); if (valid) { const vector existing_name(canonical_existing_flag_name, canonical_existing_flag_name + existing_flag_name_length); const auto it_existing = mudstate.flag_names_map.find(existing_name); if (it_existing != mudstate.flag_names_map.end()) { int new_flag_name_length; UTF8* canonical_new_flag_name = MakeCanonicalFlagName(new_flag_name, &new_flag_name_length, &valid); if (valid) { vector new_name(canonical_new_flag_name, canonical_new_flag_name + new_flag_name_length); const auto it_new = mudstate.flag_names_map.find(new_name); if ( it_new != mudstate.flag_names_map.end() && it_new->second == it_existing->second) { // New name is an alias for the same flag. // Remove the alias so the rename can proceed. // mudstate.flag_names_map.erase(it_new); } if (mudstate.flag_names_map.find(new_name) == mudstate.flag_names_map.end()) { FLAGNAMEENT* flag_name_entity = it_existing->second; mudstate.flag_names_map.insert(make_pair(new_name, flag_name_entity)); if (flag_name_entity->flagname != flag_name_entity->pOrigName) { MEMFREE(flag_name_entity->flagname); } flag_name_entity->flagname = StringCloneLen(canonical_new_flag_name, new_flag_name_length); return true; } } } } return false; } void do_flag(dbref executor, dbref caller, dbref enactor, int eval, int key, int nargs, UTF8 *existing_flag_name, UTF8 *new_flag_name, const UTF8 *cargs[], int ncargs) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (key & FLAG_REMOVE) { if (nargs == 2) { notify(executor, M_("Extra argument ignored.")); } int flag_name_length; bool valid; UTF8 *canonical_flag_name = MakeCanonicalFlagName(existing_flag_name, &flag_name_length, &valid); if (valid) { const vector name(canonical_flag_name, canonical_flag_name + flag_name_length); const auto it = mudstate.flag_names_map.find(name); if (it != mudstate.flag_names_map.end()) { FLAGNAMEENT* flag_name_entity = it->second; if ( flag_name_entity->flagname != flag_name_entity->pOrigName && mux_stricmp(flag_name_entity->flagname, canonical_flag_name) == 0) { MEMFREE(flag_name_entity->flagname); flag_name_entity->flagname = const_cast(flag_name_entity->pOrigName); mudstate.flag_names_map.erase(it); notify(executor, tprintf(M_("Flag name ‘%s’ removed from the hash table."), canonical_flag_name)); } else { notify(executor, M_("Error: You can’t remove the present flag name from the hash table.")); } } else { notify(executor, M_("Error: Bad flagname given or flag not found.")); } } else { notify(executor, M_("Error: Bad flagname given or flag not found.")); } } else { if (nargs < 2) { notify(executor, M_("You must specify a flag and a name.")); return; } if (flag_rename(existing_flag_name, new_flag_name)) { notify(executor, M_("Flag name changed.")); } else { notify(executor, M_("Error: Bad flagname given or flag not found.")); } } } /* --------------------------------------------------------------------------- * cf_flag_name: Rename a flag. Counterpart to @flag. */ CF_HAND(cf_flag_name) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); UNUSED_PARAMETER(player); UNUSED_PARAMETER(cmd); string_token st(str, T(" \t=,")); UTF8 *flagstr = st.parse(); UTF8 *namestr = st.parse(); if ( !flagstr || !*flagstr || !namestr || !*namestr) { return -1; } if (flag_rename(flagstr, namestr)) { return 0; } else { return -1; } }