/* $Header: set.c,v 2.0 90/05/05 12:45:42 lachesis Exp $
* $Log: set.c,v $
* Revision 2.0 90/05/05 12:45:42 lachesis
* Incorporated ABODE and HAVEN flags (remembering to convert FireFoot's
* usage of those flags to ours).
* Added Examine of objects that don't belong to you, added GOD_PRIV.
*
* Revision 1.3 90/04/21 17:20:48 lachesis
* Added property lists.
*
* Revision 1.2 90/04/20 14:06:51 lachesis
* Added @odrop && @drop.
*
* Revision 1.1 90/04/14 14:56:51 lachesis
* Initial revision
*
*/
#include "copyright.h"
/* commands which set parameters */
#include "os.h"
#include "db.h"
#include "config.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 (dbref player, const char *name)
{
dbref match;
init_match (player, name, NOTYPE);
match_everything ();
match = noisy_match_result ();
if (match != NOTHING && !controls (player, match)) {
notify (player, "Permission denied.");
return NOTHING;
} else {
return match;
}
}
void do_name (dbref player, const char *name, char *newname)
{
dbref thing;
char *password;
if ((thing = match_controlled (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) {
if (!db[thing].sp.player.password) {
notify (player, "Sorry");
return;
}
/* split off password */
for (password = newname; *password && !isspace (*password); password++)
/*EMPTY*/;
/* 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 (strcmp (password, db[thing].sp.player.password)) {
notify (player, "Incorrect password.");
return;
} else if (string_compare (newname, db[thing].name)
&& !ok_player_name (newname)) {
notify (player, "You can't give a player that name.");
return;
}
/* everything ok, notify */
fprintf (stderr, "NAME CHANGE: %s(#%d) to %s\n",
db[thing].name, thing, newname);
delete_player (player);
if (db[thing].name) {
free ((void *) db[thing].name);
}
db[thing].name = alloc_string (newname);
add_player (player);
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 (db[thing].name) {
free ((void *) db[thing].name);
}
db[thing].name = alloc_string (newname);
notify (player, "Name set.");
}
}
void do_describe (dbref player, const char *name, const char *description)
{
dbref thing;
if ((thing = match_controlled (player, name)) != NOTHING) {
if (db[thing].description) {
free ((void *) db[thing].description);
}
db[thing].description = alloc_compressed (description);
notify (player, "Description set.");
}
}
void do_fail (dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled (player, name)) != NOTHING) {
if (db[thing].fail_message) {
free ((void *) db[thing].fail_message);
}
db[thing].fail_message = alloc_compressed (message);
notify (player, "Message set.");
}
}
void do_success (dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled (player, name)) != NOTHING) {
if (db[thing].succ_message) {
free ((void *) db[thing].succ_message);
}
db[thing].succ_message = alloc_compressed (message);
notify (player, "Message set.");
}
}
/* sets the drop message for player */
void do_drop_message (dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled (player, name)) != NOTHING) {
if (db[thing].drop_message) {
free ((void *) db[thing].drop_message);
}
db[thing].drop_message = alloc_compressed (message);
notify (player, "Message set.");
}
}
void do_osuccess (dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled (player, name)) != NOTHING) {
if (db[thing].osuccess) {
free ((void *) db[thing].osuccess);
}
db[thing].osuccess = alloc_compressed (message);
notify (player, "Message set.");
}
}
void do_ofail (dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled (player, name)) != NOTHING) {
if (db[thing].ofail) {
free ((void *) db[thing].ofail);
}
db[thing].ofail = alloc_compressed (message);
notify (player, "Message set.");
}
}
void do_odrop (dbref player, const char *name, const char *message)
{
dbref thing;
if ((thing = match_controlled (player, name)) != NOTHING) {
if (db[thing].odrop) {
free ((void *) db[thing].odrop);
}
db[thing].odrop = alloc_compressed (message);
notify (player, "Message set.");
}
}
void do_lock (dbref player, const char *name, const char *keyname)
{
dbref thing;
struct boolexp *key;
init_match (player, name, NOTYPE);
match_everything ();
switch (thing = match_result ()) {
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;
}
key = parse_boolexp (player, keyname);
if (key == TRUE_BOOLEXP) {
notify (player, "I don't understand that key.");
} else {
/* everything ok, do it */
free_boolexp (db[thing].key);
db[thing].key = key;
notify (player, "Locked.");
}
}
void do_unlock (dbref player, const char *name)
{
dbref thing;
if ((thing = match_controlled (player, name)) != NOTHING) {
free_boolexp (db[thing].key);
db[thing].key = TRUE_BOOLEXP;
notify (player, "Unlocked.");
}
}
void do_unlink (dbref player, const char *name)
{
dbref exit;
init_match (player, name, TYPE_EXIT);
match_all_exits ();
match_here ();
if (Wizard (player)) {
match_absolute ();
}
switch (exit = match_result ()) {
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)) {
notify (player, "Permission denied.");
} else {
switch (Typeof (exit)) {
case TYPE_EXIT:
db[exit].sp.exit.ndest = 0;
if (db[exit].sp.exit.dest)
free (db[exit].sp.exit.dest);
db[exit].sp.exit.dest = 0;
notify (player, "Unlinked.");
break;
case TYPE_ROOM:
db[exit].sp.room.dropto = NOTHING;
notify (player, "Dropto removed.");
break;
default:
notify (player, "You can't unlink that!");
break;
}
}
}
}
#ifdef PLAYER_CHOWN
void do_chown (dbref player, const char *name, const char *newowner)
{
dbref thing;
dbref owner;
if (!*name) {
notify (player, "You must specify what you want to take ownership of.");
return;
}
#if 0
if (!Wizard (player) && *newowner) {
notify (player, "Only wizards can transfer ownership to others.");
return;
}
#endif
init_match (player, name, NOTYPE);
match_everything ();
if ((thing = noisy_match_result ()) == 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 = player;
}
if (!Wizard (player) && (!(db[thing].flags & CHOWN_OK) ||
!could_doit (player, thing))) {
notify (player, "You can't take possession of that.");
return;
}
switch (Typeof (thing)) {
case TYPE_ROOM:
if (!Wizard (player) && (db[player].location != thing)) {
notify (player, "You cannot chown another room.");
return;
}
db[thing].sp.room.owner = owner;
break;
case TYPE_THING:
db[thing].sp.thing.owner = owner;
break;
case TYPE_EXIT:
db[thing].sp.exit.owner = owner;
break;
case TYPE_PLAYER:
notify (player, "Players always own themselves.");
return;
#ifdef RECYCLE
case TYPE_GARBAGE:
notify (player, "No one wants to own garbage.");
return;
#endif
}
if (owner == player)
notify (player, "Owner changed to you.");
else
notify (player, "Owner changed.");
}
#else /* without PLAYER_CHOWN */
void do_chown (dbref player, const char *name, const char *newowner)
{
dbref thing;
dbref owner;
if (!Wizard (player)) {
notify (player, "Permission denied.");
return;
}
init_match (player, name, NOTYPE);
match_everything ();
if ((thing = noisy_match_result ()) == NOTHING)
return;
if ((owner = lookup_player (newowner)) == NOTHING) {
notify (player, "I couldn't find that player.");
return;
}
switch (Typeof (thing)) {
case TYPE_ROOM:
db[thing].sp.room.owner = owner;
break;
case TYPE_THING:
db[thing].sp.thing.owner = owner;
break;
case TYPE_EXIT:
db[thing].sp.exit.owner = owner;
break;
case TYPE_PLAYER:
notify (player, "Players always own themselves.");
return;
#ifdef RECYCLE
case TYPE_GARBAGE:
notify (player, "No one wants to own garbage.");
return;
#endif
}
notify (player, "Owner changed.");
}
#endif /* PLAYER_CHOWN */
/* 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>= :
will clear all properties.
A @set <thing>= type:
will remove that property.
A @set <thing>= type: class
will add that property or replace it. */
void do_set (dbref player, const char *name, const char *flag)
{
dbref thing;
const char *p;
object_flag_type f;
/* find thing */
if ((thing = match_controlled (player, name)) == NOTHING)
return;
/* move p past NOT_TOKEN if present */
for (p = flag; *p && (*p == NOT_TOKEN || isspace (*p)); p++)
/*EMPTY*/;
/* 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 = get_string (flag); /* type */
char *class = index (type, PROP_DELIMITER); /* class */
char *x = type; /* to preserve string location so we can free it */
char *temp;
struct plist *prop, *last;
while (isspace (*type) && (*type != PROP_DELIMITER))
type++;
if (*type == PROP_DELIMITER) {
/* clear all properties */
for (last = prop = db[thing].properties; prop; prop = last) {
last = prop->next;
free_prop (prop);
}
notify (player, "All properties removed.");
free ((void *) x);
db[thing].properties = 0;
return;
} else {
/* get rid of trailing spaces */
for (temp = class - 1; isspace (*temp); temp--)
/*EMPTY*/;
temp++;
*temp = '\0';
}
class++; /* move to next character */
while (isspace (*class) && *class)
class++;
if (!(*class)) {
remove_property (thing, type);
notify (player, "Property removed.");
} else {
/* remove trailing spaces */
for (temp = class + strlen (class);
isspace (*temp) && temp > class; temp--)
/*EMPTY*/;
*temp = '\0';
add_property (thing, type, class, 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_prefix ("LINK_OK", p)) {
f = LINK_OK;
} else if (string_prefix ("DARK", p)) {
f = DARK;
} else if (string_prefix ("STICKY", p)) {
f = STICKY;
} else if (string_prefix ("WIZARD", p)) {
f = WIZARD;
} else if (string_prefix ("TEMPLE", p)) {
f = TEMPLE;
#ifdef RESTRICTED_BUILDING
} else if (string_prefix ("BUILDER", p)) {
f = BUILDER;
#endif /* RESTRICTED_BUILDING */
#ifdef PLAYER_CHOWN
} else if (string_prefix ("CHOWN_OK", p)) {
f = CHOWN_OK;
#endif /* PLAYER_CHOWN */
} else if (string_prefix ("JUMP_OK", p)) {
f = JUMP_OK;
#ifdef HAVEN
} else if (string_prefix ("HAVEN", p)) {
f = HAVEN;
#endif /* HAVEN */
#ifdef ABODE
} else if (string_prefix ("ABODE", p)) {
f = ABODE;
#endif /* ABODE */
} else {
notify (player, "I don't recognize that flag.");
return;
}
/* check for restricted flag */
if (!Wizard (player)
&& (f == WIZARD
#ifdef RESTRICTED_BUILDING
|| f == BUILDER
#endif /* RESTRICTED_BUILDING */
|| f == TEMPLE || f == DARK && Typeof (thing) != TYPE_ROOM)) {
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;
}
#ifdef GOD_PRIV
if (f == WIZARD && *flag == NOT_TOKEN && God (thing)) {
notify (player, "Even wizards can't make God mortal.");
return;
}
#endif /* GOD_PRIV */
/* else everything is ok, do the set */
if (*flag == NOT_TOKEN) {
/* reset the flag */
db[thing].flags &= ~f;
notify (player, "Flag reset.");
} else {
/* set the flag */
db[thing].flags |= f;
notify (player, "Flag set.");
}
}