tinymux/mux/modules/engine/flags.cpp
Stephen Dennis 04541ed603 nls: do not translate decompile @set/@power command templates
decompile_flags and decompile_powers emit executable MUSH script for
@decompile replay, not player prose. Marking them M_() made LANGUAGE=xx
emit "[xx] @set Foo=WIZARD", which does not replay. Revert to T(); drop
the msgids from the catalogues.

Also reverts @power from #1671 — same decompile-script class. Flagged
on #1674 review.
2026-07-28 13:57:48 +00:00

1499 lines
50 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*! \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<UTF8*>(flag_name_entity->pOrigName);
const size_t flag_name_length = strlen(reinterpret_cast<const char*>(flag_name_entity->pOrigName));
vector<UTF8> 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<unsigned char>(*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<unsigned char>(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<int>(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<int>(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<int>(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<UTF8> 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<char *>(permstr), "any"))
{
fbe->handler = fh_any;
}
else if (!strcmp(reinterpret_cast<char *>(permstr), "dark"))
{
if (negate)
{
fbe->listperm &= ~CA_GOD;
}
else
{
fbe->listperm |= CA_GOD;
}
}
else if (!strcmp(reinterpret_cast<char *>(permstr), "hidden"))
{
if (negate)
{
fbe->listperm &= ~CA_WIZARD;
}
else
{
fbe->listperm |= CA_WIZARD;
}
}
else if (!strcmp(reinterpret_cast<char *>(permstr), "royalty"))
{
fbe->handler = fh_wizroy;
}
else if (!strcmp(reinterpret_cast<char *>(permstr), "wizard"))
{
fbe->handler = fh_wiz;
}
else if (!strcmp(reinterpret_cast<char *>(permstr), "god"))
{
fbe->handler = fh_god;
}
else if (!strcmp(reinterpret_cast<char *>(permstr), "restrict_player"))
{
fbe->handler = fh_restrict_player;
}
else if (!strcmp(reinterpret_cast<char *>(permstr), "privileged"))
{
fbe->handler = fh_privileged;
}
else if (!strcmp(reinterpret_cast<char *>(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<UTF8> 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<UTF8> 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<UTF8> 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<UTF8*>(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 cant 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;
}
}