/* $Header: /cvsroot/fbmuck/fbmuck/src/set.c,v 1.19 2003/06/23 00:13:48 revar Exp $ */
#include "copyright.h"
#include "config.h"
/* commands which set parameters */
#include <stdio.h>
#include <ctype.h>
#include "fbstrings.h"
#include "db.h"
#include "params.h"
#include "tune.h"
#include "props.h"
#include "match.h"
#include "interface.h"
#include "externs.h"
#ifdef COMPRESS
#define alloc_compressed(x) alloc_string(compress(x))
#else /* COMPRESS */
#define alloc_compressed(x) alloc_string(x)
#endif /* COMPRESS */
static dbref
match_controlled(int descr, dbref player, const char *name)
{
dbref match;
struct match_data md;
init_match(descr, player, name, NOTYPE, &md);
match_absolute(&md);
match_everything(&md);
match = noisy_match_result(&md);
if (match != NOTHING && !controls(player, match)) {
notify(player, "Permission denied.");
return NOTHING;
} else {
return match;
}
}
void
do_name(int descr, dbref player, const char *name, char *newname)
{
dbref thing;
char *password;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
/* check for bad name */
if (*newname == '\0') {
notify(player, "Give it what new name?");
return;
}
/* check for renaming a player */
if (Typeof(thing) == TYPE_PLAYER) {
/* split off password */
for (password = newname; *password && !isspace(*password); password++) ;
/* eat whitespace */
if (*password) {
*password++ = '\0'; /* terminate name */
while (*password && isspace(*password))
password++;
}
/* check for null password */
if (!*password) {
notify(player, "You must specify a password to change a player name.");
notify(player, "E.g.: name player = newname password");
return;
} else if (!check_password(thing, password)) {
notify(player, "Incorrect password.");
return;
} else if (string_compare(newname, NAME(thing))
&& !ok_player_name(newname)) {
notify(player, "You can't give a player that name.");
return;
}
/* everything ok, notify */
log_status("NAME CHANGE: %s(#%d) to %s\n", NAME(thing), thing, newname);
delete_player(thing);
if (NAME(thing)) {
free((void *) NAME(thing));
}
ts_modifyobject(thing);
NAME(thing) = alloc_string(newname);
add_player(thing);
notify(player, "Name set.");
return;
} else {
if (!ok_name(newname)) {
notify(player, "That is not a reasonable name.");
return;
}
}
/* everything ok, change the name */
if (NAME(thing)) {
free((void *) NAME(thing));
}
ts_modifyobject(thing);
NAME(thing) = alloc_string(newname);
notify(player, "Name set.");
DBDIRTY(thing);
if (Typeof(thing) == TYPE_EXIT && MLevRaw(thing)) {
SetMLevel(thing, 0);
notify(player, "Action priority Level reset to zero.");
}
}
}
void
do_describe(int descr, dbref player, const char *name, const char *description)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETDESC(thing, description);
if(description && *description) {
notify(player, "Description set.");
} else {
notify(player, "Description cleared.");
}
}
}
void
do_idescribe(int descr, dbref player, const char *name, const char *description)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETIDESC(thing, description);
if(description && *description) {
notify(player, "Description set.");
} else {
notify(player, "Description cleared.");
}
}
}
void
do_doing(int descr, dbref player, const char *name, const char *mesg)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETDOING(thing, mesg);
if(mesg && *mesg) {
notify(player, "Doing set.");
} else {
notify(player, "Doing cleared.");
}
}
}
void
do_fail(int descr, dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETFAIL(thing, message);
if(message && *message) {
notify(player, "Message set.");
} else {
notify(player, "Message cleared.");
}
}
}
void
do_success(int descr, dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETSUCC(thing, message);
if(message && *message) {
notify(player, "Message set.");
} else {
notify(player, "Message cleared.");
}
}
}
/* sets the drop message for player */
void
do_drop_message(int descr, dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETDROP(thing, message);
if(message && *message) {
notify(player, "Message set.");
} else {
notify(player, "Message cleared.");
}
}
}
void
do_osuccess(int descr, dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETOSUCC(thing, message);
if(message && *message) {
notify(player, "Message set.");
} else {
notify(player, "Message cleared.");
}
}
}
void
do_ofail(int descr, dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETOFAIL(thing, message);
if(message && *message) {
notify(player, "Message set.");
} else {
notify(player, "Message cleared.");
}
}
}
void
do_odrop(int descr, dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETODROP(thing, message);
if(message && *message) {
notify(player, "Message set.");
} else {
notify(player, "Message cleared.");
}
}
}
void
do_oecho(int descr, dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETOECHO(thing, message);
if(message && *message) {
notify(player, "Message set.");
} else {
notify(player, "Message cleared.");
}
}
}
void
do_pecho(int descr, dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
SETPECHO(thing, message);
if(message && *message) {
notify(player, "Message set.");
} else {
notify(player, "Message cleared.");
}
}
}
/* sets a lock on an object to the lockstring passed to it.
If the lockstring is null, then it unlocks the object.
this returns a 1 or a 0 to represent success. */
int
setlockstr(int descr, dbref player, dbref thing, const char *keyname)
{
struct boolexp *key;
if (*keyname != '\0') {
key = parse_boolexp(descr, player, keyname, 0);
if (key == TRUE_BOOLEXP) {
return 0;
} else {
/* everything ok, do it */
ts_modifyobject(thing);
SETLOCK(thing, key);
return 1;
}
} else {
ts_modifyobject(thing);
CLEARLOCK(thing);
return 1;
}
}
void
do_conlock(int descr, dbref player, const char *name, const char *keyname)
{
dbref thing;
struct boolexp *key;
struct match_data md;
PData mydat;
init_match(descr, player, name, NOTYPE, &md);
match_absolute(&md);
match_everything(&md);
switch (thing = match_result(&md)) {
case NOTHING:
notify(player, "I don't see what you want to set the container-lock on!");
return;
case AMBIGUOUS:
notify(player, "I don't know which one you want to set the container-lock on!");
return;
default:
if (!controls(player, thing)) {
notify(player, "You can't set the container-lock on that!");
return;
}
break;
}
if (!*keyname) {
mydat.flags = PROP_LOKTYP;
mydat.data.lok = TRUE_BOOLEXP;
set_property(thing, "_/clk", &mydat);
ts_modifyobject(thing);
notify(player, "Container lock cleared.");
} else {
key = parse_boolexp(descr, player, keyname, 0);
if (key == TRUE_BOOLEXP) {
notify(player, "I don't understand that key.");
} else {
/* everything ok, do it */
mydat.flags = PROP_LOKTYP;
mydat.data.lok = key;
set_property(thing, "_/clk", &mydat);
ts_modifyobject(thing);
notify(player, "Container lock set.");
}
}
}
void
do_flock(int descr, dbref player, const char *name, const char *keyname)
{
dbref thing;
struct boolexp *key;
struct match_data md;
PData mydat;
init_match(descr, player, name, NOTYPE, &md);
match_absolute(&md);
match_everything(&md);
switch (thing = match_result(&md)) {
case NOTHING:
notify(player, "I don't see what you want to set the force-lock on!");
return;
case AMBIGUOUS:
notify(player, "I don't know which one you want to set the force-lock on!");
return;
default:
if (!controls(player, thing)) {
notify(player, "You can't set the force-lock on that!");
return;
}
break;
}
if (force_level) {
notify(player, "You can't use @flock from an @force or {force}.");
return;
}
if (!*keyname) {
mydat.flags = PROP_LOKTYP;
mydat.data.lok = TRUE_BOOLEXP;
set_property(thing, "@/flk", &mydat);
ts_modifyobject(thing);
notify(player, "Force lock cleared.");
} else {
key = parse_boolexp(descr, player, keyname, 0);
if (key == TRUE_BOOLEXP) {
notify(player, "I don't understand that key.");
} else {
/* everything ok, do it */
mydat.flags = PROP_LOKTYP;
mydat.data.lok = key;
set_property(thing, "@/flk", &mydat);
ts_modifyobject(thing);
notify(player, "Force lock set.");
}
}
}
void
do_chlock(int descr, dbref player, const char *name, const char *keyname)
{
dbref thing;
struct boolexp *key;
struct match_data md;
PData mydat;
init_match(descr, player, name, NOTYPE, &md);
match_absolute(&md);
match_everything(&md);
switch (thing = match_result(&md)) {
case NOTHING:
notify(player, "I don't see what you want to set the chown-lock on!");
return;
case AMBIGUOUS:
notify(player, "I don't know which one you want to set the chown-lock on!");
return;
default:
if (!controls(player, thing)) {
notify(player, "You can't set the chown-lock on that!");
return;
}
break;
}
if (!*keyname) {
mydat.flags = PROP_LOKTYP;
mydat.data.lok = TRUE_BOOLEXP;
set_property(thing, "_/chlk", &mydat);
ts_modifyobject(thing);
notify(player, "Chown lock cleared.");
} else {
key = parse_boolexp(descr, player, keyname, 0);
if (key == TRUE_BOOLEXP) {
notify(player, "I don't understand that key.");
} else {
/* everything ok, do it */
mydat.flags = PROP_LOKTYP;
mydat.data.lok = key;
set_property(thing, "_/chlk", &mydat);
ts_modifyobject(thing);
notify(player, "Chown lock set.");
}
}
}
void
do_lock(int descr, dbref player, const char *name, const char *keyname)
{
dbref thing;
struct boolexp *key;
struct match_data md;
init_match(descr, player, name, NOTYPE, &md);
match_absolute(&md);
match_everything(&md);
switch (thing = match_result(&md)) {
case NOTHING:
notify(player, "I don't see what you want to lock!");
return;
case AMBIGUOUS:
notify(player, "I don't know which one you want to lock!");
return;
default:
if (!controls(player, thing)) {
notify(player, "You can't lock that!");
return;
}
break;
}
if(keyname && *keyname) {
key = parse_boolexp(descr, player, keyname, 0);
if (key == TRUE_BOOLEXP) {
notify(player, "I don't understand that key.");
} else {
/* everything ok, do it */
SETLOCK(thing, key);
ts_modifyobject(thing);
notify(player, "Locked.");
}
} else
do_unlock(descr, player, name);
}
void
do_unlock(int descr, dbref player, const char *name)
{
dbref thing;
if ((thing = match_controlled(descr, player, name)) != NOTHING) {
ts_modifyobject(thing);
CLEARLOCK(thing);
notify(player, "Unlocked.");
}
}
int
controls_link(dbref who, dbref what)
{
switch (Typeof(what)) {
case TYPE_EXIT:
{
int i = DBFETCH(what)->sp.exit.ndest;
while (i > 0) {
if (controls(who, DBFETCH(what)->sp.exit.dest[--i]))
return 1;
}
if (who == OWNER(DBFETCH(what)->location))
return 1;
return 0;
}
case TYPE_ROOM:
{
if (controls(who, DBFETCH(what)->sp.room.dropto))
return 1;
return 0;
}
case TYPE_PLAYER:
{
if (controls(who, PLAYER_HOME(what)))
return 1;
return 0;
}
case TYPE_THING:
{
if (controls(who, THING_HOME(what)))
return 1;
return 0;
}
case TYPE_PROGRAM:
default:
return 0;
}
}
/* like do_unlink, but if quiet is true, then only error messages are
printed. */
void
_do_unlink(int descr, dbref player, const char *name, int quiet)
{
dbref exit;
struct match_data md;
init_match(descr, player, name, TYPE_EXIT, &md);
match_absolute(&md);
match_player(&md);
match_everything(&md);
switch (exit = match_result(&md)) {
case NOTHING:
notify(player, "Unlink what?");
break;
case AMBIGUOUS:
notify(player, "I don't know which one you mean!");
break;
default:
if (!controls(player, exit) && !controls_link(player, exit)) {
notify(player, "Permission denied.");
} else {
switch (Typeof(exit)) {
case TYPE_EXIT:
if (DBFETCH(exit)->sp.exit.ndest != 0) {
PLAYER_ADD_PENNIES(OWNER(exit), tp_link_cost);
DBDIRTY(OWNER(exit));
}
ts_modifyobject(exit);
DBSTORE(exit, sp.exit.ndest, 0);
if (DBFETCH(exit)->sp.exit.dest) {
free((void *) DBFETCH(exit)->sp.exit.dest);
DBSTORE(exit, sp.exit.dest, NULL);
}
if(!quiet)
notify(player, "Unlinked.");
if (MLevRaw(exit)) {
SetMLevel(exit, 0);
DBDIRTY(exit);
if(!quiet)
notify(player, "Action priority Level reset to 0.");
}
break;
case TYPE_ROOM:
ts_modifyobject(exit);
DBSTORE(exit, sp.room.dropto, NOTHING);
if(!quiet)
notify(player, "Dropto removed.");
break;
case TYPE_THING:
ts_modifyobject(exit);
THING_SET_HOME(exit, OWNER(exit));
DBDIRTY(exit);
if(!quiet)
notify(player, "Thing's home reset to owner.");
break;
case TYPE_PLAYER:
ts_modifyobject(exit);
PLAYER_SET_HOME(exit, tp_player_start);
DBDIRTY(exit);
if(!quiet)
notify(player, "Player's home reset to default player start room.");
break;
default:
notify(player, "You can't unlink that!");
break;
}
}
}
}
void
do_unlink(int descr, dbref player, const char *name)
{
/* do a regular, non-quiet unlink. */
_do_unlink(descr, player, name, 0);
}
void
do_unlink_quiet(int descr, dbref player, const char *name)
{
_do_unlink(descr, player, name, 1);
}
/*
* do_relink()
*
* re-link an exit object. FIXME: this shares some code with do_link() which
* should probably be moved into a separate function (is_link_ok() or
* something like that).
*
*/
void
do_relink(int descr, dbref player, const char *thing_name, const char *dest_name)
{
dbref thing;
dbref dest;
dbref good_dest[MAX_LINKS];
struct match_data md;
int ndest;
init_match(descr, player, thing_name, TYPE_EXIT, &md);
match_all_exits(&md);
match_neighbor(&md);
match_possession(&md);
match_me(&md);
match_here(&md);
match_absolute(&md);
match_registered(&md);
if (Wizard(OWNER(player))) {
match_player(&md);
}
if ((thing = noisy_match_result(&md)) == NOTHING)
return;
/* first of all, check if the new target would be valid, so we can
avoid breaking the old link if it isn't. */
switch (Typeof(thing)) {
case TYPE_EXIT:
/* we're ok, check the usual stuff */
if (DBFETCH(thing)->sp.exit.ndest != 0) {
if(!controls(player, thing)) {
notify(player, "Permission denied.");
return;
}
} else {
if(!Wizard(OWNER(player)) && (PLAYER_PENNIES(player) < (tp_link_cost + tp_exit_cost))) {
notify_fmt(player, "It costs %d %s to link this exit.",
(tp_link_cost + tp_exit_cost),
(tp_link_cost + tp_exit_cost == 1) ? tp_penny : tp_pennies);
return;
} else if (!Builder(player)) {
notify(player, "Only authorized builders may seize exits.");
return;
}
}
/* be anal: each and every new links destination has
to be ok. Detailed error messages are given by
link_exit_dry(). */
ndest = link_exit_dry(descr, player, thing, (char *) dest_name, good_dest);
if(ndest == 0) {
notify(player, "Invalid target.");
return;
}
break;
case TYPE_THING:
case TYPE_PLAYER:
init_match(descr, player, dest_name, TYPE_ROOM, &md);
match_neighbor(&md);
match_absolute(&md);
match_registered(&md);
match_me(&md);
match_here(&md);
if (Typeof(thing) == TYPE_THING)
match_possession(&md);
if ((dest = noisy_match_result(&md)) == NOTHING)
return;
if (!controls(player, thing)
|| !can_link_to(player, Typeof(thing), dest)) {
notify(player, "Permission denied.");
return;
}
if (parent_loop_check(thing, dest)) {
notify(player, "That would cause a parent paradox.");
return;
}
break;
case TYPE_ROOM: /* room dropto's */
init_match(descr, player, dest_name, TYPE_ROOM, &md);
match_neighbor(&md);
match_possession(&md);
match_registered(&md);
match_absolute(&md);
match_home(&md);
if ((dest = noisy_match_result(&md)) == NOTHING)
return;
if (!controls(player, thing) || !can_link_to(player, Typeof(thing), dest)
|| (thing == dest)) {
notify(player, "Permission denied.");
return;
}
break;
case TYPE_PROGRAM:
notify(player, "You can't link programs to things!");
return;
default:
notify(player, "Internal error: weird object type.");
log_status("PANIC: weird object: Typeof(%d) = %d\n", thing, Typeof(thing));
return;
}
do_unlink_quiet(descr, player, thing_name);
notify(player, "Attempting to relink...");
do_link(descr, player, thing_name, dest_name);
}
void
do_chown(int descr, dbref player, const char *name, const char *newowner)
{
dbref thing;
dbref owner;
struct match_data md;
if (!*name) {
notify(player, "You must specify what you want to take ownership of.");
return;
}
init_match(descr, player, name, NOTYPE, &md);
match_everything(&md);
match_absolute(&md);
if ((thing = noisy_match_result(&md)) == NOTHING)
return;
if (*newowner && string_compare(newowner, "me")) {
if ((owner = lookup_player(newowner)) == NOTHING) {
notify(player, "I couldn't find that player.");
return;
}
} else {
owner = OWNER(player);
}
if (!Wizard(OWNER(player)) && OWNER(player) != owner) {
notify(player, "Only wizards can transfer ownership to others.");
return;
}
if (!Wizard(OWNER(player))) {
if (Typeof(thing) != TYPE_EXIT ||
(DBFETCH(thing)->sp.exit.ndest && !controls_link(player, thing))) {
if (!(FLAGS(thing) & CHOWN_OK) ||
Typeof(thing) == TYPE_PROGRAM || !test_lock(descr, player, thing, "_/chlk")) {
notify(player, "You can't take possession of that.");
return;
}
}
}
if (tp_realms_control && !Wizard(OWNER(player)) && TrueWizard(thing) &&
Typeof(thing) == TYPE_ROOM) {
notify(player, "You can't take possession of that.");
return;
}
switch (Typeof(thing)) {
case TYPE_ROOM:
if (!Wizard(OWNER(player)) && DBFETCH(player)->location != thing) {
notify(player, "You can only chown \"here\".");
return;
}
ts_modifyobject(thing);
OWNER(thing) = OWNER(owner);
break;
case TYPE_THING:
if (!Wizard(OWNER(player)) && DBFETCH(thing)->location != player) {
notify(player, "You aren't carrying that.");
return;
}
ts_modifyobject(thing);
OWNER(thing) = OWNER(owner);
break;
case TYPE_PLAYER:
notify(player, "Players always own themselves.");
return;
case TYPE_EXIT:
case TYPE_PROGRAM:
ts_modifyobject(thing);
OWNER(thing) = OWNER(owner);
break;
case TYPE_GARBAGE:
notify(player, "No one wants to own garbage.");
return;
}
if (owner == player)
notify(player, "Owner changed to you.");
else {
char buf[BUFFER_LEN];
snprintf(buf, sizeof(buf), "Owner changed to %s.", unparse_object(player, owner));
notify(player, buf);
}
DBDIRTY(thing);
}
/* Note: Gender code taken out. All gender references are now to be handled
by property lists...
Setting of flags and property code done here. Note that the PROP_DELIMITER
identifies when you're setting a property.
A @set <thing>= :clear
will clear all properties.
A @set <thing>= type:
will remove that property.
A @set <thing>= propname:string
will add that string property or replace it.
A @set <thing>= propname:^value
will add that integer property or replace it.
*/
void
do_set(int descr, dbref player, const char *name, const char *flag)
{
dbref thing;
const char *p;
object_flag_type f;
/* find thing */
if ((thing = match_controlled(descr, player, name)) == NOTHING)
return;
/* move p past NOT_TOKEN if present */
for (p = flag; *p && (*p == NOT_TOKEN || isspace(*p)); p++) ;
/* Now we check to see if it's a property reference */
/* if this gets changed, please also modify boolexp.c */
if (index(flag, PROP_DELIMITER)) {
/* copy the string so we can muck with it */
char *type = alloc_string(flag); /* type */
char *pname = (char *) index(type, PROP_DELIMITER); /* propname */
char *x; /* to preserve string location so we can free it */
char *temp;
int ival = 0;
x = type;
while (isspace(*type) && (*type != PROP_DELIMITER))
type++;
if (*type == PROP_DELIMITER) {
/* clear all properties */
for (type++; isspace(*type); type++) ;
if (string_compare(type, "clear")) {
notify(player, "Use '@set <obj>=:clear' to clear all props on an object");
free((void *)x);
return;
}
remove_property_list(thing, Wizard(OWNER(player)));
ts_modifyobject(thing);
notify(player, "All user-owned properties removed.");
free((void *) x);
return;
}
/* get rid of trailing spaces and slashes */
for (temp = pname - 1; temp >= type && isspace(*temp); temp--) ;
while (temp >= type && *temp == '/')
temp--;
*(++temp) = '\0';
pname++; /* move to next character */
/* while (isspace(*pname) && *pname) pname++; */
if (*pname == '^' && number(pname + 1))
ival = atoi(++pname);
if (Prop_System(type) || (!Wizard(OWNER(player)) && (Prop_SeeOnly(type) || Prop_Hidden(type)))) {
notify(player, "Permission denied.");
free((void *)x);
return;
}
if (!(*pname)) {
ts_modifyobject(thing);
remove_property(thing, type);
notify(player, "Property removed.");
} else {
ts_modifyobject(thing);
if (ival) {
add_property(thing, type, NULL, ival);
} else {
add_property(thing, type, pname, 0);
}
notify(player, "Property set.");
}
free((void *) x);
return;
}
/* identify flag */
if (*p == '\0') {
notify(player, "You must specify a flag to set.");
return;
} else if ((!string_compare("0", p) || !string_compare("M0", p)) ||
((string_prefix("MUCKER", p)) && (*flag == NOT_TOKEN))) {
if (!Wizard(OWNER(player))) {
if ((OWNER(player) != OWNER(thing)) || (Typeof(thing) != TYPE_PROGRAM)) {
notify(player, "Permission denied.");
return;
}
}
if (force_level) {
notify(player, "Can't set this flag from an @force or {force}.");
return;
}
SetMLevel(thing, 0);
notify(player, "Mucker level set.");
return;
} else if (!string_compare("1", p) || !string_compare("M1", p)) {
if (!Wizard(OWNER(player))) {
if ((OWNER(player) != OWNER(thing)) || (Typeof(thing) != TYPE_PROGRAM)
|| (MLevRaw(player) < 1)) {
notify(player, "Permission denied.");
return;
}
}
if (force_level) {
notify(player, "Can't set this flag from an @force or {force}.");
return;
}
SetMLevel(thing, 1);
notify(player, "Mucker level set.");
return;
} else if ((!string_compare("2", p) || !string_compare("M2", p)) ||
((string_prefix("MUCKER", p)) && (*flag != NOT_TOKEN))) {
if (!Wizard(OWNER(player))) {
if ((OWNER(player) != OWNER(thing)) || (Typeof(thing) != TYPE_PROGRAM)
|| (MLevRaw(player) < 2)) {
notify(player, "Permission denied.");
return;
}
}
if (force_level) {
notify(player, "Can't set this flag from an @force or {force}.");
return;
}
SetMLevel(thing, 2);
notify(player, "Mucker level set.");
return;
} else if (!string_compare("3", p) || !string_compare("M3", p)) {
if (!Wizard(OWNER(player))) {
if ((OWNER(player) != OWNER(thing)) || (Typeof(thing) != TYPE_PROGRAM)
|| (MLevRaw(player) < 3)) {
notify(player, "Permission denied.");
return;
}
}
if (force_level) {
notify(player, "Can't set this flag from an @force or {force}.");
return;
}
SetMLevel(thing, 3);
notify(player, "Mucker level set.");
return;
} else if (!string_compare("4", p) || !string_compare("M4", p)) {
notify(player, "To set Mucker Level 4, set the Wizard bit.");
return;
} else if (string_prefix("WIZARD", p)) {
if (force_level) {
notify(player, "Can't set this flag from an @force or {force}.");
return;
}
f = WIZARD;
} else if (string_prefix("ZOMBIE", p)) {
f = ZOMBIE;
} else if (string_prefix("VEHICLE", p)
|| string_prefix("VIEWABLE", p)) {
if (*flag == NOT_TOKEN && Typeof(thing) == TYPE_THING) {
dbref obj = DBFETCH(thing)->contents;
for (; obj != NOTHING; obj = DBFETCH(obj)->next) {
if (Typeof(obj) == TYPE_PLAYER) {
notify(player, "That vehicle still has players in it!");
return;
}
}
}
f = VEHICLE;
} else if (string_prefix("LINK_OK", p)) {
f = LINK_OK;
} else if (string_prefix("XFORCIBLE", p) || string_prefix("XPRESS", p)) {
if (force_level) {
notify(player, "Can't set this flag from an @force or {force}.");
return;
}
if (Typeof(thing) == TYPE_EXIT) {
if (!Wizard(OWNER(player))) {
notify(player, "Permission denied.");
return;
}
}
f = XFORCIBLE;
} else if (string_prefix("KILL_OK", p)) {
f = KILL_OK;
} else if ((string_prefix("DARK", p)) || (string_prefix("DEBUG", p))) {
f = DARK;
} else if ((string_prefix("STICKY", p)) || (string_prefix("SETUID", p)) ||
(string_prefix("SILENT", p))) {
f = STICKY;
} else if (string_prefix("QUELL", p)) {
f = QUELL;
} else if (string_prefix("BUILDER", p) || string_prefix("BOUND", p)) {
f = BUILDER;
} else if (string_prefix("CHOWN_OK", p) || string_prefix("COLOR", p)) {
f = CHOWN_OK;
} else if (string_prefix("JUMP_OK", p)) {
f = JUMP_OK;
} else if (string_prefix("HAVEN", p) || string_prefix("HARDUID", p)) {
f = HAVEN;
} else if ((string_prefix("ABODE", p)) ||
(string_prefix("AUTOSTART", p)) || (string_prefix("ABATE", p))) {
f = ABODE;
} else {
notify(player, "I don't recognize that flag.");
return;
}
/* check for restricted flag */
if (restricted(player, thing, f)) {
notify(player, "Permission denied.");
return;
}
/* check for stupid wizard */
if (f == WIZARD && *flag == NOT_TOKEN && thing == player) {
notify(player, "You cannot make yourself mortal.");
return;
}
/* else everything is ok, do the set */
if (*flag == NOT_TOKEN) {
/* reset the flag */
ts_modifyobject(thing);
FLAGS(thing) &= ~f;
DBDIRTY(thing);
notify(player, "Flag reset.");
} else {
/* set the flag */
ts_modifyobject(thing);
FLAGS(thing) |= f;
DBDIRTY(thing);
notify(player, "Flag set.");
}
}
void
do_propset(int descr, dbref player, const char *name, const char *prop)
{
dbref thing, ref;
char *p, *q;
char buf[BUFFER_LEN];
char *type, *pname, *value;
struct match_data md;
struct boolexp *lok;
PData mydat;
/* find thing */
if ((thing = match_controlled(descr, player, name)) == NOTHING)
return;
while (isspace(*prop))
prop++;
strcpy(buf, prop);
type = p = buf;
while (*p && *p != PROP_DELIMITER)
p++;
if (*p)
*p++ = '\0';
if (*type) {
q = type + strlen(type) - 1;
while (q >= type && isspace(*q))
*(q--) = '\0';
}
pname = p;
while (*p && *p != PROP_DELIMITER)
p++;
if (*p)
*p++ = '\0';
value = p;
while (*pname == PROPDIR_DELIMITER || isspace(*pname))
pname++;
if (*pname) {
q = pname + strlen(pname) - 1;
while (q >= pname && isspace(*q))
*(q--) = '\0';
}
if (!*pname) {
notify(player, "I don't know which property you want to set!");
return;
}
if (Prop_System(pname) || (!Wizard(OWNER(player)) && (Prop_SeeOnly(pname) || Prop_Hidden(pname)))) {
notify(player, "Permission denied.");
return;
}
if (!*type || string_prefix("string", type)) {
add_property(thing, pname, value, 0);
} else if (string_prefix("integer", type)) {
if (!number(value)) {
notify(player, "That's not an integer!");
return;
}
add_property(thing, pname, NULL, atoi(value));
} else if (string_prefix("float", type)) {
if (!ifloat(value)) {
notify(player, "That's not a floating point number!");
return;
}
mydat.flags = PROP_FLTTYP;
mydat.data.fval = strtod(value, NULL);
set_property(thing, pname, &mydat);
} else if (string_prefix("dbref", type)) {
init_match(descr, player, value, NOTYPE, &md);
match_absolute(&md);
match_everything(&md);
if ((ref = noisy_match_result(&md)) == NOTHING)
return;
mydat.flags = PROP_REFTYP;
mydat.data.ref = ref;
set_property(thing, pname, &mydat);
} else if (string_prefix("lock", type)) {
lok = parse_boolexp(descr, player, value, 0);
if (lok == TRUE_BOOLEXP) {
notify(player, "I don't understand that lock.");
return;
}
mydat.flags = PROP_LOKTYP;
mydat.data.lok = lok;
set_property(thing, pname, &mydat);
} else if (string_prefix("erase", type)) {
if (*value) {
notify(player, "Don't give a value when erasing a property.");
return;
}
remove_property(thing, pname);
notify(player, "Property erased.");
return;
} else {
notify(player, "I don't know what type of property you want to set!");
notify(player, "Valid types are string, integer, float, dbref, lock, and erase.");
return;
}
notify(player, "Property set.");
}
void
set_flags_from_tunestr(dbref obj, const char* tunestr)
{
const char *p = tunestr;
object_flag_type f = 0;
for (;;) {
char pcc = toupper(*p);
if (pcc == '\0' || pcc == '\n' || pcc == '\r') {
break;
} else if (pcc == '0') {
SetMLevel(obj, 0);
} else if (pcc == '1') {
SetMLevel(obj, 1);
} else if (pcc == '2') {
SetMLevel(obj, 2);
} else if (pcc == '3') {
SetMLevel(obj, 3);
} else if (pcc == 'A') {
f = ABODE;
} else if (pcc == 'B') {
f = BUILDER;
} else if (pcc == 'C') {
f = CHOWN_OK;
} else if (pcc == 'D') {
f = DARK;
} else if (pcc == 'H') {
f = HAVEN;
} else if (pcc == 'J') {
f = JUMP_OK;
} else if (pcc == 'K') {
f = KILL_OK;
} else if (pcc == 'L') {
f = LINK_OK;
} else if (pcc == 'M') {
SetMLevel(obj, 2);
} else if (pcc == 'Q') {
f = QUELL;
} else if (pcc == 'S') {
f = STICKY;
} else if (pcc == 'V') {
f = VEHICLE;
} else if (pcc == 'W') {
/* f = WIZARD; This is very bad to auto-set. */
} else if (pcc == 'X') {
f = XFORCIBLE;
} else if (pcc == 'Z') {
f = ZOMBIE;
}
FLAGS(obj) |= f;
p++;
}
ts_modifyobject(obj);
DBDIRTY(obj);
}