/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/set.c,v 1.13 90/09/18 08:02:06 rearl Exp $ */
/*
* $Log: set.c,v $
* Revision 1.13 90/09/18 08:02:06 rearl
* Player hash table mods, took out FILTER.
*
* Revision 1.12 90/09/16 04:42:56 rearl
* Preparation code added for disk-based MUCK.
*
* Revision 1.11 90/09/10 02:23:11 rearl
* Took out get_string call.
*
* Revision 1.10 90/08/27 03:33:18 rearl
* Fixed bug involving NULL player password entries.
*
* Revision 1.9 90/08/11 04:10:15 rearl
* *** empty log message ***
*
* Revision 1.8 90/08/06 03:51:35 rearl
* Redid @chown thing = me, the easy way...
*
* Revision 1.7 90/08/06 02:51:18 rearl
* Added restricted() routine from predicates.c, any restricted
* flags should be checked in there from now on.
*
* Revision 1.6 90/08/05 03:20:01 rearl
* Redid matching routines.
*
* Revision 1.5 90/08/02 18:51:26 rearl
* Enabled @chown <thing> = me in addition to @chown <thing>.
*
* Revision 1.4 90/07/29 17:43:30 rearl
* Allows players to capitalize/decapitalize their names, added support
* for setting programs DEBUG (DARK).
*
*
* Revision 1.3 90/07/21 16:31:50 casie
* added log_misc
*
* Revision 1.2 90/07/21 05:32:41 casie
* Changed player chown to allow rooms and exits as well as things.
*
* Revision 1.1 90/07/19 23:04:09 casie
* Initial revision
*
*
*/
#include "copyright.h"
#include "config.h"
/* commands which set parameters */
#include <stdio.h>
#include <ctype.h>
#include "strings.h"
#include "db.h"
#include "params.h"
#include "match.h"
#include "interface.h"
#include "externs.h"
dbref match_controlled(dbref player, const char *name)
{
dbref match;
struct match_data md;
init_match(player, name, NOTYPE, &md);
match_everything(&md);
match = noisy_match_result(&md);
if(match != NOTHING && !(controls(player, match) || player == OWNER(match))
&& !God(player)) {
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) {
/* 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(strcmp(password, DoNull(DBFETCH(thing)->sp.player.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));
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));
}
NAME(thing) = alloc_string(newname);
notify(player, "Name set.");
DBDIRTY(thing);
}
}
void do_attr(dbref player, const char *name, const char *what,
const char *value)
{
dbref thing;
if((thing = match_controlled(player, what)) != NOTHING) {
char *attribute = (char *) calloc(strlen(name) + 2, sizeof(char));
*attribute = PROP_WIZARD;
strcat(attribute, name);
if(value && *value) {
add_property(thing, attribute, value);
sprintf(buf,"%s -- %c%s set to \"%s\"", NAME(thing), PROP_WIZARD, name,
value);
notify(player, buf);
} else {
remove_property(thing, attribute);
sprintf(buf,"%s -- %c%s removed.", NAME(thing), PROP_WIZARD, name);
notify(player, buf);
}
free((void *) attribute);
}
}
void do_lock(dbref player, const char *name, const char *keyname)
{
dbref thing;
struct boolexp *key;
struct match_data md;
init_match(player, name, NOTYPE, &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;
}
key = parse_boolexp(player, keyname);
if(key == TRUE_BOOLEXP) {
notify(player, "I don't understand that key.");
} else {
/* everything ok, do it */
free_boolexp(DBFETCH(thing)->key);
DBSTORE(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(DBFETCH(thing)->key);
DBSTORE(thing, key, TRUE_BOOLEXP);
notify(player, "Unlocked.");
}
}
void do_unlink(dbref player, const char *name)
{
dbref exit;
struct match_data md;
init_match(player, name, TYPE_EXIT, &md);
match_all_exits(&md);
match_here(&md);
match_absolute(&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)) {
notify(player, "Permission denied.");
} else {
switch(Typeof(exit)) {
case TYPE_EXIT:
if(DBFETCH(exit)->sp.exit.ndest != 0) {
DBFETCH(OWNER(exit))->sp.player.pennies += LINK_COST;
DBDIRTY(OWNER(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);
}
notify(player, "Unlinked.");
break;
case TYPE_ROOM:
DBSTORE(exit, link, 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;
struct match_data md;
if (!*name) {
notify(player, "You must specify what you want to take ownership of.");
return;
}
init_match(player, name, NOTYPE, &md);
match_everything(&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 = player;
}
if(!Wizard(player) && player != owner) {
notify(player, "Only wizards can transfer ownership to others.");
return;
}
if (!Wizard(player) && (!(FLAGS(thing) & CHOWN_OK)
|| Typeof(thing) == TYPE_PROGRAM)) {
notify(player, "You can't take possession of that.");
return;
}
switch (Typeof(thing)) {
case TYPE_ROOM:
if (!Arch(player) && DBFETCH(player)->location != thing) {
notify(player, "You can only chown \"here\".");
return;
}
OWNER(thing) = owner;
break;
case TYPE_THING:
if (!Arch(player) && DBFETCH(thing)->location != player) {
notify(player, "You aren't carrying that.");
return;
}
if (Typeof(player) == TYPE_PLAYER)
OWNER(thing) = owner;
FLAGS(thing) |= HALTED; /* halted... igg */
halt_long(thing);
break;
case TYPE_PLAYER:
if(!Wizard(player) || Wizard(thing)) {
notify(player, "Players always own themselves.");
return;
}
DBFETCH(thing)->owner = owner; /* gotta do it w/o OWNER, cause owner */
break; /* is messed up for players. */
case TYPE_EXIT:
OWNER(thing) = owner;
break;
#ifdef RECYCLE
case TYPE_GARBAGE:
notify(player, "No one wants to own garbage.");
return;
#endif
default:
if(!Arch(player)) {
notify(player,"Permission denied.");
return;
}
OWNER(thing) = owner;
break;
}
if (owner == player)
notify(player, "Owner changed to you.");
else {
char buf[BUFFER_LEN];
sprintf(buf, "Owner changed to %s.", unparse_object(player, owner));
notify(player, buf);
}
DBDIRTY(thing);
}
#else /* without PLAYER_CHOWN */
void do_chown(dbref player, const char *name, const char *newowner)
{
dbref thing;
dbref owner;
struct match_data md;
if(!Arch(player)) {
notify(player, "Permission denied.");
return;
}
init_match(player, name, NOTYPE, &md);
match_everything(&md);
if((thing = noisy_match_result(&md)) == NOTHING) return;
if((owner = lookup_player(newowner)) == NOTHING) {
notify(player, "I couldn't find that player.");
return;
}
switch (Typeof(thing)) {
case TYPE_PLAYER:
notify(player, "Players always own themselves.");
return;
case TYPE_ROOM:
case TYPE_THING:
case TYPE_EXIT:
case TYPE_PROGRAM:
OWNER(thing) = owner;
#ifdef RECYCLE
case TYPE_GARBAGE:
notify(player, "No one wants to own garbage.");
return;
#endif
}
notify(player, "Owner changed.");
DBDIRTY(thing);
}
#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;
int did_hear; /* hmm.... whether it heard before we
* did a set on it. */
/* 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++);
/* 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 *class = (char *)index(type, PROP_DELIMITER); /* class */
char *x; /* to preserve string location so we can free it */
char *temp;
struct plist *prop, *last;
x = type;
while (isspace(*type) && (*type != PROP_DELIMITER))
type++;
if ((*type == PROP_DELIMITER) || ((*type == PROP_WIZARD)
&& (*(type + 1) == PROP_DELIMITER)))
{
did_hear = can_hear(thing);
if(*type == PROP_DELIMITER) {
prop = DBFETCH(thing)->properties;
} else {
prop = DBFETCH(thing)->attributes;
}
/* clear all properties */
if(prop) {
for (last = prop -> next; last; last = prop -> next)
{
prop -> next = last -> next;
free_prop(last);
}
if(*type == PROP_DELIMITER) {
notify(player, "All properties removed.");
DBSTORE(thing, properties, NULL);
} else {
notify(player, "All attributes removed.");
DBSTORE(thing, attributes, NULL);
}
free_prop(prop);
} else { /* No properties to remove. */
if(*type == PROP_DELIMITER)
notify(player, "No properties to remove.");
else
notify(player, "No attributes to remove.");
}
free((void *) x);
if(can_hear(thing) && !did_hear)
grow_ears(thing);
if(!can_hear(thing) && did_hear)
lose_ears(thing);
return;
}
else
{
/* get rid of trailing spaces */
for (temp = class - 1; isspace(*temp); temp--)
;
temp++;
*temp = '\0';
}
class++; /* move to next character */
while (isspace(*class) && *class)
class++;
if (!(*class))
{
remove_property(thing, type);
sprintf(buf, "%s -- %s removed.", NAME(thing), type);
notify(player, buf);
}
else
{
if(*type == PROP_WIZARD && !Wizard(player))
{
notify(player, "Permission denied.");
free ((void *) x);
return;
}
add_property(thing, type, class);
sprintf(buf, "%s -- %s set to \"%s\"", NAME(thing), type, class);
notify(player, buf);
}
free((void *) x);
return;
}
did_hear = can_hear(thing);
/* identify flag */
f = lookup_flag(p);
if(f <= 0) {
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 && !God(player)) {
notify(player, "You cannot make yourself mortal.");
return;
}
/* else everything is ok, do the set */
if(*flag == NOT_TOKEN) {
/* reset the flag */
FLAGS(thing) &= ~f;
DBDIRTY(thing);
notify(player, "Flag reset.");
} else {
/* set the flag */
FLAGS(thing) |= f;
DBDIRTY(thing);
notify(player, "Flag set.");
}
if(can_hear(thing) && !did_hear)
grow_ears(thing);
if(!can_hear(thing) && did_hear)
lose_ears(thing);
}
void do_field(dbref player, const char *name, const char *flag, dbref cause)
{
dbref thing;
const char *p;
/* 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++);
/* 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 *rest = (char *)index(type, PROP_DELIMITER); /* class */
char *x; /* to preserve string location so we can free it */
char *temp;
char *old;
char new[BUFFER_LEN];
x = type;
while (isspace(*type) && (*type != PROP_DELIMITER))
type++;
if (*type == PROP_DELIMITER)
{
notify(player, "Usage: @field <object>=<property>:<old>,<new>");
free((void *) x);
return;
}
else
{
/* get rid of trailing spaces */
for (temp = rest - 1; isspace(*temp); temp--)
;
temp++;
*temp = '\0';
}
if(get_property_class(thing, type)) {
old = (char *)
calloc(strlen(get_property_class(thing, type)) + 1, sizeof(char));
strcpy(old, get_property_class(thing, type));
}
else {
notify(player, "No such property.");
free((void *) x);
return;
}
rest++; /* move to next character */
while (isspace(*rest) && *rest)
rest++;
if (!(*rest))
{
notify(player, "Nothing to change.");
free((void *) x);
return;
}
else
{
const char *delimit = ",";
char *arg1 = (char *) parse_up(&rest, delimit);
char *arg2 = (char *) parse_up(&rest, delimit);
arg1 = check_arg(arg1, player, cause);
arg2 = check_arg(arg2, player, cause);
if(!arg1 || !(*arg1)) {
notify(player, "Nothing to change.");
free((void *) x);
return;
}
else {
int len = strlen(arg1);
int d;
const char *r = (arg2 ? arg2 : (char *) "");
for (d = 0; (d < BUFFER_LEN) && *old;)
if (strncmp(arg1, old, len) == 0) {
if ((d + strlen(r)) < BUFFER_LEN) {
strcpy(new + d, r);
d += strlen(r);
old += len;
} else
new[d++] = *old++;
} else
new[d++] = *old++;
new[d++] = 0;
free((void *) old);
if(new && *new) {
add_property(thing, type, new);
sprintf(buf,"%s -- %s set to \"%s\"", NAME(thing), type, new);
}
else {
remove_property(thing, type);
sprintf(buf,"%s -- %s removed.", NAME(thing), type);
}
notify(player, buf);
}
}
free((void *) x);
}
else
notify(player, "Usage: @field <object>=<old>,<new>");
}