tinymux/mux/modules/engine/wiz.cpp
Stephen Dennis bc4cec252e fix(nls): plural morphology baked into msgids, and a fragment that could not be translated (#1717)
Found while translating mail (#1419).  The tell was a line wrong in English
before translation is even involved:

    MAIL: 1 messages in folder 0 [unnamed] (1 unread, 0 cleared).

MN_() exists for this (#1622) and #1655 converted the @mail/stats family;
this set was missed.  A translator cannot work around it -- the msgid has no
msgid_plural, so there is no second form for a catalogue to supply, and es
must pick one wording for all counts while ru and pl need three and can
express none of them.  The fix is in the C++, not the .po.

## Converted, 11 sites

mail.cpp, mail_mod.cpp   mailbox is full; URGENT MAIL urgent messages
walkdb.cpp               universe contains; objects @chowned; objects marked
object.cpp               objects @chowned to you
wiz.cpp                  You toaded ... objects @chowned
command.cpp              at most N players logged in

The mail module duplicates are converted alongside the engine's so the two
implementations do not drift (#1614).

## One was a different bug than the issue described

walkdb.cpp built its message as M_("%d objects %smarked") with %s = "" or
"un".  That is fragment assembly, not a missing plural: a translator handed
that %s cannot use it, because the prefix is English morphology rather than
a word.  Split into two whole sentences, each pluralised -- the #1575 /
#1588 rule.  Now renders "1 object marked" / "8 objects unmarked" instead of
a %s a catalogue has no way to fill.

## Two deliberately NOT converted

    MAIL: %d messages in folder %d [%s] (%d unread, %d cleared).
    %d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)

MN_(s, p, n) selects one form from one n.  Four independent counts are four
independent plural decisions, and in Russian each noun needs its own form.
These want rewording, which is a design call rather than a mechanical
conversion, so they are left and recorded rather than half-fixed.

## Catalogue fallout

.pot 18 -> 27 plural entries; all three catalogues msgmerge'd.

xx is `complete` policy, so its nine new entries had to be filled and
unfuzzied or the guard fails -- which it duly did, first try.  msgmerge had
copied the old singular-only text into BOTH forms, so msgstr[0] said
"messages"; each form is now prefixed from its own msgid.

es and ko received real translations for all nine.

    es.po  190 -> 198/976  (20.3%)
    ko.po  229 -> 236/976  (24.2%)

## Verified end to end, at n=1 and n>1

    en   1 object marked      8 objects marked
    es   1 objeto marcado     8 objetos marcados
    ko   사물 1개를 표시했습니다   사물 8개를 표시했습니다
    xx   [xx] 1 object marked [xx] 8 objects marked

Korean renders identically for both, which is correct: it declares
nplurals=1, so the catalogue's own rule is being honoured rather than
English's imposed on it.

The unconverted multi-count line still reads "1 messages", as documented.

make test: Smoke 1561 x3, tests/nls 7, ko 4, plural 43.  TESTEXIT=0.

Refs #1419, #1575, #1588, #1614, #1622, #1655, #1702.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 21:31:32 +00:00

912 lines
24 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 wiz.cpp
* \brief Wizard-only commands.
*
*/
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "externs.h"
#include "alloc.h"
static void do_teleport_single
(
dbref executor,
dbref caller,
dbref enactor,
int key,
dbref victim,
UTF8 *to
)
{
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
dbref loc;
int hush = 0;
// Validate type of victim.
//
if ( !Good_obj(victim)
|| isRoom(victim))
{
notify_quiet(executor, M_("You cant teleport that."));
return;
}
// Fail if we don't control the victim or the victim's location.
//
if ( !Controls(executor, victim)
&& !Controls(executor, isExit(victim) ? Exits(victim) : Location(victim))
&& !Tel_Anything(executor))
{
notify_quiet(executor, NOPERM_MESSAGE);
return;
}
// Check for teleporting home
//
if (!string_compare(to, T("home")))
{
if (isExit(victim))
{
notify_quiet(executor, M_("Bad destination."));
}
else
{
move_via_teleport(victim, HOME, enactor, 0);
}
return;
}
// Find out where to send the victim.
//
init_match(executor, to, NOTYPE);
match_everything(0);
dbref destination = match_result();
switch (destination)
{
case NOTHING:
notify_quiet(executor, M_("No match."));
return;
case AMBIGUOUS:
notify_quiet(executor, M_("I dont know which destination you mean!"));
return;
default:
if (victim == destination)
{
notify_quiet(executor, M_("Bad destination."));
return;
}
}
// If fascist teleport is on, you must control the victim's ultimate
// location (after LEAVEing any objects) or it must be JUMP_OK.
//
if (mudconf.fascist_tport)
{
if (isExit(victim))
{
loc = where_room(Home(victim));
}
else
{
loc = where_room(victim);
}
if ( !Good_obj(loc)
|| !isRoom(loc)
|| !( Controls(executor, loc)
|| Jump_ok(loc)
|| Tel_Anywhere(executor)))
{
notify_quiet(executor, NOPERM_MESSAGE);
return;
}
}
if ( isGarbage(destination)
|| ( Has_location(destination)
&& isGarbage(Location(destination))))
{
// @Teleporting into garbage is never permitted.
//
notify_quiet(executor, M_("Bad destination."));
return;
}
else if (Has_contents(destination))
{
// You must control the destination OR it must be a JUMP_OK where
// the victim passes its TELEPORT lock (exit victims have the
// additional requirement that the destination must be OPEN_OK and
// the victim must pass the destination's OPEN lock) OR you must be
// Tel_Anywhere.
//
// Only God may teleport exits into God.
//
if ( ( Controls(executor, destination)
|| Tel_Anywhere(executor)
|| ( Jump_ok(destination)
&& could_doit(victim, destination, A_LTPORT)
&& ( !isExit(victim)
|| ( Open_ok(destination)
&& could_doit(executor, destination, A_LOPEN)))))
&& ( !isExit(victim)
|| !God(destination)
|| God(executor)))
{
// We're OK, do the teleport.
//
if (key & TELEPORT_QUIET)
{
hush = HUSH_ENTER | HUSH_LEAVE;
}
if (move_via_teleport(victim, destination, enactor, hush))
{
if (executor != victim)
{
if (!Quiet(executor))
{
notify_quiet(executor, M_("Teleported."));
}
}
}
}
else
{
// Nope, report failure.
//
if (executor != victim)
{
notify_quiet(executor, NOPERM_MESSAGE);
}
did_it(victim, destination,
A_TFAIL, T("You cant teleport there!"),
A_OTFAIL, 0, A_ATFAIL, 0, nullptr, 0);
}
}
else if (isExit(destination))
{
if (isExit(victim))
{
if (executor != victim)
{
notify_quiet(executor, M_("Bad destination."));
}
did_it(victim, destination,
A_TFAIL, T("You cant teleport there!"),
A_OTFAIL, 0, A_ATFAIL, 0, nullptr, 0);
return;
}
else
{
if (Exits(destination) == Location(victim))
{
move_exit(victim, destination, false, T("You cant go that way."), 0);
}
else
{
notify_quiet(executor, M_("I cant find that exit."));
}
}
}
}
void do_teleport
(
dbref executor,
dbref caller,
dbref enactor,
int eval,
int key,
int nargs,
UTF8 *arg1,
UTF8 *arg2,
const UTF8 *cargs[],
int ncargs
)
{
UNUSED_PARAMETER(eval);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);
if ( ( Fixed(executor)
|| Fixed(Owner(executor)))
&& !Tel_Anywhere(executor))
{
notify(executor, mudconf.fixed_tel_msg);
return;
}
// Get victim.
//
if (nargs == 1)
{
// Teleport executor to given destination.
//
do_teleport_single(executor, caller, enactor, key, executor, arg1);
}
else if (nargs == 2)
{
// Teleport 3rd part(y/ies) to given destination.
//
if (key & TELEPORT_LIST)
{
// We have a space-delimited list of victims.
//
UTF8 *p;
string_token st(arg1, T(" "));
for (p = st.parse(); p; p = st.parse())
{
init_match(executor, p, NOTYPE);
match_everything(0);
dbref victim = noisy_match_result();
if (Good_obj(victim))
{
do_teleport_single(executor, caller, enactor, key, victim,
arg2);
}
}
}
else
{
init_match(executor, arg1, NOTYPE);
match_everything(0);
dbref victim = noisy_match_result();
if (Good_obj(victim))
{
do_teleport_single(executor, caller, enactor, key, victim,
arg2);
}
}
}
}
// ---------------------------------------------------------------------------
// do_force_prefixed: Interlude to do_force for the # command
//
void do_force_prefixed
(
dbref executor,
dbref caller,
dbref enactor,
int eval,
int key,
UTF8 *command,
const UTF8 *cargs[],
int ncargs
)
{
UTF8 *cp = parse_to(&command, ' ', 0);
if (!command)
{
return;
}
while (mux_isspace(*command))
{
command++;
}
if (*command)
{
do_force(executor, caller, enactor, eval, key, 2, cp, command, cargs, ncargs);
}
}
// ---------------------------------------------------------------------------
// do_force: Force an object to do something.
//
void do_force
(
dbref executor,
dbref caller,
dbref enactor,
int eval,
int key,
int nargs,
UTF8 *arg1,
UTF8 *arg2,
const UTF8 *cargs[],
int ncargs
)
{
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(nargs);
dbref victim = match_controlled(executor, arg1);
if (victim != NOTHING)
{
// Force victim to do command.
//
if (key & FORCE_NOW)
{
process_command(victim, caller, executor, eval, false, arg2, cargs, ncargs);
}
else
{
CLinearTimeAbsolute lta;
wait_que(victim, caller, executor, eval, false, lta, NOTHING, 0,
arg2,
ncargs, cargs,
mudstate.global_regs);
}
}
}
// ---------------------------------------------------------------------------
// do_toad: Turn a player into an object.
//
void do_toad
(
dbref executor,
dbref caller,
dbref enactor,
int eval,
int key,
int nargs,
UTF8 *toad,
UTF8 *newowner,
const UTF8 *cargs[],
int ncargs
)
{
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(eval);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);
dbref victim, recipient, loc, aowner;
UTF8 *buf;
int count, aflags;
init_match(executor, toad, TYPE_PLAYER);
match_neighbor();
match_absolute();
match_player();
if (!Good_obj(victim = noisy_match_result()))
{
return;
}
if (!isPlayer(victim))
{
notify_quiet(executor, M_("Try @destroy instead."));
return;
}
if (No_Destroy(victim))
{
notify_quiet(executor, M_("You cant toad that player."));
return;
}
if ( nargs == 2
&& *newowner )
{
init_match(executor, newowner, TYPE_PLAYER);
match_neighbor();
match_absolute();
match_player();
if ((recipient = noisy_match_result()) == NOTHING)
{
return;
}
}
else
{
if (mudconf.toad_recipient == NOTHING)
{
recipient = executor;
}
else
{
recipient = mudconf.toad_recipient;
}
}
STARTLOG(LOG_WIZARD, "WIZ", "TOAD");
log_name_and_loc(victim);
log_text(T(" was @toaded by "));
log_name(executor);
ENDLOG;
// Clear everything out.
//
if (key & TOAD_NO_CHOWN)
{
count = -1;
}
else
{
// You get it.
//
count = chown_all(victim, recipient, executor, CHOWN_NOZONE);
s_Owner(victim, recipient);
s_Zone(victim, NOTHING);
}
s_Flags(victim, FLAG_WORD1, TYPE_THING | HALT);
s_Flags(victim, FLAG_WORD2, 0);
s_Flags(victim, FLAG_WORD3, 0);
s_Pennies(victim, 1);
// Notify people.
//
loc = Location(victim);
buf = alloc_mbuf("do_toad");
const UTF8 *pVictimMoniker = Moniker(victim);
const UTF8 *pVictimName = Name(victim);
mux_sprintf(buf, MBUF_SIZE, M_("%s has been turned into a slimy toad!"),
pVictimMoniker);
notify_except2(loc, executor, victim, executor, buf);
mux_sprintf(buf, MBUF_SIZE, MN_("You toaded %s! (%d object @chowned)",
"You toaded %s! (%d objects @chowned)",
count + 1),
pVictimMoniker, count + 1);
notify_quiet(executor, buf);
// Zap the name from the name hash table.
//
mux_sprintf(buf, MBUF_SIZE, M_("a slimy toad named %s"), pVictimMoniker);
delete_player_name(victim, pVictimName, false);
s_Name(victim, buf);
free_mbuf(buf);
// Zap the alias, too.
//
{
LBuf alias = LBuf_Adopt(atr_pget(victim, A_ALIAS, &aowner, &aflags));
delete_player_name(victim, alias, true);
}
// Boot off.
//
count = boot_off(victim, T("You have been turned into a slimy toad!"));
// Release comsys and @mail resources.
//
ReleaseAllResources(victim);
// #1622: the count goes to the catalogue, not an English suffix.
buf = tprintf(MN_("%d connection closed.",
"%d connections closed.", count), count);
notify_quiet(executor, buf);
}
void do_newpassword
(
dbref executor,
dbref caller,
dbref enactor,
int eval,
int key,
int nargs,
UTF8 *name,
UTF8 *password,
const UTF8 *cargs[],
int ncargs
)
{
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(eval);
UNUSED_PARAMETER(key);
UNUSED_PARAMETER(nargs);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);
dbref victim = lookup_player(executor, name, false);
if (victim == NOTHING)
{
notify_quiet(executor, M_("No such player."));
return;
}
const UTF8 *pmsg;
if ( *password != '\0'
&& !ok_password(password, &pmsg))
{
// Can set null passwords, but not bad passwords.
//
notify_quiet(executor, pmsg);
return;
}
if (God(victim))
{
bool bCan = true;
if (God(executor))
{
// God can change her own password if it's missing.
//
int aflags;
dbref aowner;
LBuf target = LBuf_Adopt(atr_get("do_newpassword.474", executor, A_PASS, &aowner, &aflags));
if (target[0] != '\0')
{
bCan = false;
}
}
else
{
bCan = false;
}
if (!bCan)
{
notify_quiet(executor, M_("You cannot change that players password."));
return;
}
}
STARTLOG(LOG_WIZARD, "WIZ", "PASS");
log_name(executor);
log_text(T(" changed the password of "));
log_name(victim);
ENDLOG;
// It's ok, do it.
//
ChangePassword(victim, password);
notify_quiet(executor, M_("Password changed."));
LBuf buf = LBuf_Src("do_newpassword");
UTF8 *bp = buf;
safe_tprintf_str(buf, &bp, M_("Your password has been changed by %s."), Moniker(executor));
notify_quiet(victim, buf);
}
void do_boot(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *name, const UTF8 *cargs[], int ncargs)
{
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(eval);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);
if (!Can_Boot(executor))
{
notify(executor, NOPERM_MESSAGE);
return;
}
dbref victim;
int count;
if (key & BOOT_PORT)
{
if (is_integer(name, nullptr))
{
victim = mux_atoi64(name);
}
else
{
notify_quiet(executor, M_("Thats not a number!"));
return;
}
STARTLOG(LOG_WIZARD, "WIZ", "BOOT");
log_printf(T("Port %d"), victim);
log_text(T(" was @booted by "));
log_name(executor);
ENDLOG;
}
else
{
init_match(executor, name, TYPE_PLAYER);
match_neighbor();
match_absolute();
match_player();
if ((victim = noisy_match_result()) == NOTHING)
{
return;
}
if (God(victim))
{
notify_quiet(executor, M_("You cannot boot that player!"));
return;
}
if ( ( !isPlayer(victim)
&& !God(executor))
|| executor == victim)
{
notify_quiet(executor, M_("You can only boot off other players!"));
return;
}
STARTLOG(LOG_WIZARD, "WIZ", "BOOT");
log_name_and_loc(victim);
log_text(T(" was @booted by "));
log_name(executor);
ENDLOG;
notify_quiet(executor, tprintf(M_("You booted %s off!"), Moniker(victim)));
}
const UTF8 *buf;
if (key & BOOT_QUIET)
{
buf = nullptr;
}
else
{
buf = tprintf(M_("%s gently shows you the door."), Moniker(executor));
}
if (key & BOOT_PORT)
{
count = boot_by_port(victim, God(executor), buf);
}
else
{
count = boot_off(victim, buf);
}
notify_quiet(executor, tprintf(MN_("%d connection closed.",
"%d connections closed.", count), count));
}
// ---------------------------------------------------------------------------
// do_poor: Reduce the wealth of anyone over a specified amount.
//
void do_poor(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *arg1, const UTF8 *cargs[], int ncargs)
{
UNUSED_PARAMETER(executor);
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(eval);
UNUSED_PARAMETER(key);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);
if (!is_rational(arg1))
{
return;
}
// Clamp rather than narrow (#1402).
//
// The limit is compared against Pennies(), which is int, so a value outside
// int range cannot describe any wealth a player is able to hold -- an
// over-large limit reads as "reduce nobody" and must behave that way.
// `int amt = mux_atoi64(arg1)` instead wrapped, and turned the argument
// into its own opposite: measured before this change, `@poor 4294967296`
// truncated to 0 and set *every* player's money to zero, and
// `@poor 2147483648` truncated to INT_MIN and left every player holding
// -2147483648 pennies. is_rational() above accepts both, and nothing
// downstream range-checks, so the wrap was the whole of the arithmetic.
//
// Same shape as fun_shl's defeated `0 <= b && b < 64` in #1404: the
// truncation happens before anything can judge the value. Here there was
// no check at all to defeat, which is why it corrupted instead of erroring.
//
int64_t wanted = mux_atoi64(arg1);
if (INT_MAX < wanted)
{
wanted = INT_MAX;
}
else if (wanted < INT_MIN)
{
wanted = INT_MIN;
}
int amt = static_cast<int>(wanted);
int curamt;
dbref a;
DO_WHOLE_DB(a)
{
if (isPlayer(a))
{
curamt = Pennies(a);
if (amt < curamt)
{
s_Pennies(a, amt);
}
}
}
}
// ---------------------------------------------------------------------------
// do_cut: Chop off a contents or exits chain after the named item.
//
void do_cut(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *thing, const UTF8 *cargs[], int ncargs)
{
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(eval);
UNUSED_PARAMETER(key);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);
dbref object = match_controlled(executor, thing);
if (Good_obj(object))
{
s_Next(object, NOTHING);
notify_quiet(executor, M_("Cut."));
}
}
// --------------------------------------------------------------------------
// do_motd: Wizard-settable message of the day (displayed on connect)
//
void do_motd(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *message, const UTF8 *cargs[], int ncargs)
{
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(eval);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);
bool is_brief = false;
if (key & MOTD_BRIEF)
{
is_brief = true;
key = key & ~MOTD_BRIEF;
if (key == MOTD_ALL)
key = MOTD_LIST;
else if (key != MOTD_LIST)
key |= MOTD_BRIEF;
}
switch (key)
{
case MOTD_ALL:
mux_strncpy(mudconf.motd_msg, message, sizeof(mudconf.motd_msg)-1);
if (!Quiet(executor))
{
notify_quiet(executor, M_("Set: MOTD."));
}
break;
case MOTD_WIZ:
mux_strncpy(mudconf.wizmotd_msg, message, sizeof(mudconf.wizmotd_msg)-1);
if (!Quiet(executor))
{
notify_quiet(executor, M_("Set: Wizard MOTD."));
}
break;
case MOTD_DOWN:
mux_strncpy(mudconf.downmotd_msg, message, sizeof(mudconf.downmotd_msg)-1);
if (!Quiet(executor))
{
notify_quiet(executor, M_("Set: Down MOTD."));
}
break;
case MOTD_FULL:
mux_strncpy(mudconf.fullmotd_msg, message, sizeof(mudconf.fullmotd_msg)-1);
if (!Quiet(executor))
{
notify_quiet(executor, M_("Set: Full MOTD."));
}
break;
case MOTD_LIST:
if (Wizard(executor))
{
if (!is_brief)
{
notify_quiet(executor, M_("----- motd file -----"));
fcache_send(executor, FC_MOTD);
notify_quiet(executor, M_("----- wizmotd file -----"));
fcache_send(executor, FC_WIZMOTD);
notify_quiet(executor, M_("----- motd messages -----"));
}
notify_quiet(executor, tprintf(M_("MOTD: %s"), mudconf.motd_msg));
notify_quiet( executor,
tprintf(M_("Wizard MOTD: %s"), mudconf.wizmotd_msg) );
notify_quiet( executor,
tprintf(M_("Down MOTD: %s"), mudconf.downmotd_msg) );
notify_quiet( executor,
tprintf(M_("Full MOTD: %s"), mudconf.fullmotd_msg) );
}
else
{
if (Guest(executor))
{
fcache_send(executor, FC_CONN_GUEST);
}
else
{
fcache_send(executor, FC_MOTD);
}
notify_quiet(executor, mudconf.motd_msg);
}
break;
default:
notify_quiet(executor, M_("Illegal combination of switches."));
}
}
// ---------------------------------------------------------------------------
// do_enable: enable or disable global control flags
//
NAMETAB enable_names[] =
{
{T("building"), 1, CA_PUBLIC, CF_BUILD},
{T("checkpointing"), 2, CA_PUBLIC, CF_CHECKPOINT},
{T("cleaning"), 2, CA_PUBLIC, CF_DBCHECK},
{T("dequeueing"), 1, CA_PUBLIC, CF_DEQUEUE},
{T("idlechecking"), 2, CA_PUBLIC, CF_IDLECHECK},
{T("interpret"), 2, CA_PUBLIC, CF_INTERP},
{T("logins"), 3, CA_PUBLIC, CF_LOGIN},
{T("guests"), 2, CA_PUBLIC, CF_GUEST},
{T("eventchecking"), 2, CA_PUBLIC, CF_EVENTCHECK},
{ nullptr, 0, 0, 0}
};
void do_global(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *flag, const UTF8 *cargs[], int ncargs)
{
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(eval);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);
// Set or clear the indicated flag.
//
int flagvalue;
if (!search_nametab(executor, enable_names, flag, &flagvalue))
{
notify_quiet(executor, M_("I dont know about that flag."));
}
else if (key == GLOB_ENABLE)
{
// Check for CF_DEQUEUE
//
if (flagvalue == CF_DEQUEUE)
{
scheduler.SetMinPriority(PRIORITY_CF_DEQUEUE_ENABLED);
}
mudconf.control_flags |= flagvalue;
// Push control_flags (logins/guests/etc.) into the driver's g_dc
// basket so @enable/@disable take effect on the accept path without
// a restart. Same callback as cf_live_driver_int.
//
if (nullptr != g_driver_config_sync_fn)
{
g_driver_config_sync_fn();
}
STARTLOG(LOG_CONFIGMODS, "CFG", "GLOBAL");
log_name(executor);
log_text(T(" enabled: "));
log_text(flag);
ENDLOG;
if (!Quiet(executor))
{
notify_quiet(executor, M_("Enabled."));
}
}
else if (key == GLOB_DISABLE)
{
if (flagvalue == CF_DEQUEUE)
{
scheduler.SetMinPriority(PRIORITY_CF_DEQUEUE_DISABLED);
}
mudconf.control_flags &= ~flagvalue;
// See GLOB_ENABLE: keep g_dc.control_flags in sync for logins/guests.
//
if (nullptr != g_driver_config_sync_fn)
{
g_driver_config_sync_fn();
}
STARTLOG(LOG_CONFIGMODS, "CFG", "GLOBAL");
log_name(executor);
log_text(T(" disabled: "));
log_text(flag);
ENDLOG;
if (!Quiet(executor))
{
notify_quiet(executor, M_("Disabled."));
}
}
else
{
notify_quiet(executor, M_("Illegal combination of switches."));
}
}