btmux-0.6-rc4/doc/
btmux-0.6-rc4/event/
btmux-0.6-rc4/game/
btmux-0.6-rc4/game/maps/
btmux-0.6-rc4/game/mechs/
btmux-0.6-rc4/game/text/help/
btmux-0.6-rc4/game/text/help/cat_faction/
btmux-0.6-rc4/game/text/help/cat_inform/
btmux-0.6-rc4/game/text/help/cat_misc/
btmux-0.6-rc4/game/text/help/cat_mux/
btmux-0.6-rc4/game/text/help/cat_mux/cat_commands/
btmux-0.6-rc4/game/text/help/cat_mux/cat_functions/
btmux-0.6-rc4/game/text/help/cat_templates/
btmux-0.6-rc4/game/text/wizhelp/
btmux-0.6-rc4/include/
btmux-0.6-rc4/misc/
btmux-0.6-rc4/python/
btmux-0.6-rc4/src/hcode/btech/
btmux-0.6-rc4/tree/
/*
 * set.c -- commands which set parameters 
 */

#include "copyright.h"
#include "config.h"

#include "mudconf.h"
#include "config.h"
#include "db.h"
#include "match.h"
#include "interface.h"
#include "externs.h"
#include "flags.h"
#include "powers.h"
#include "attrs.h"
#include "alloc.h"
#include "ansi.h"
#include "p.comsys.h"

extern NAMETAB indiv_attraccess_nametab[];
extern void lower_xp(dbref, int);
extern char *silly_atr_get(int id, int flag);
extern void silly_atr_set(int id, int flag, char *dat);

dbref match_controlled(dbref player, char *name)
{
	dbref mat;

	init_match(player, name, NOTYPE);
	match_everything(MAT_EXIT_PARENTS);
	mat = noisy_match_result();
	if(Good_obj(mat) && !Controls(player, mat)) {
		notify_quiet(player, "Permission denied.");
		return NOTHING;
	} else {
		return (mat);
	}
}

dbref match_controlled_quiet(dbref player, char *name)
{
	dbref mat;

	init_match(player, name, NOTYPE);
	match_everything(MAT_EXIT_PARENTS);
	mat = match_result();
	if(Good_obj(mat) && !Controls(player, mat)) {
		return NOTHING;
	} else {
		return (mat);
	}
}

dbref match_affected(dbref player, char *name)
{
	dbref mat;

	init_match(player, name, NOTYPE);
	match_everything(MAT_EXIT_PARENTS);
	mat = noisy_match_result();
	if(mat != NOTHING && !Affects(player, mat)) {
		notify_quiet(player, "Permission denied.");
		return NOTHING;
	} else {
		return (mat);
	}
}

dbref match_examinable(dbref player, char *name)
{
	dbref mat;

	init_match(player, name, NOTYPE);
	match_everything(MAT_EXIT_PARENTS);
	mat = noisy_match_result();
	if(mat != NOTHING && !Examinable(player, mat)) {
		notify_quiet(player, "Permission denied.");
		return NOTHING;
	} else {
		return (mat);
	}
}

void do_chzone(dbref player, dbref cause, int key, char *name, char *newobj)
{
	dbref thing;
	dbref zone;

	if(!mudconf.have_zones) {
		notify(player, "Zones disabled.");
		return;
	}
	init_match(player, name, NOTYPE);
	match_everything(0);
	if((thing = noisy_match_result()) == NOTHING)
		return;

	if(!strcasecmp(newobj, "none"))
		zone = NOTHING;
	else {
		init_match(player, newobj, NOTYPE);
		match_everything(0);
		if((zone = noisy_match_result()) == NOTHING)
			return;

		if((Typeof(zone) != TYPE_THING) && (Typeof(zone) != TYPE_ROOM)) {
			notify(player, "Invalid zone object type.");
			return;
		}
	}

	if(!Wizard(player) && !(Controls(player, thing)) &&
	   !(check_zone_for_player(player, thing)) &&
	   !(db[player].owner == db[thing].owner)) {
		notify(player, "You don't have the power to shift reality.");
		return;
	}
	/*
	 * a player may change an object's zone to NOTHING or to an object he 
	 * 
	 * *  * *  * * owns 
	 */
	if((zone != NOTHING) && !Wizard(player) && !(Controls(player, zone))
	   && !(db[player].owner == db[zone].owner)) {
		notify(player, "You cannot move that object to that zone.");
		return;
	}
	/*
	 * only rooms may be zoned to other rooms 
	 */
	if((zone != NOTHING) && (Typeof(zone) == TYPE_ROOM) &&
	   Typeof(thing) != TYPE_ROOM) {
		notify(player, "Only rooms may have parent rooms.");
		return;
	}
	/*
	 * everything is okay, do the change 
	 */
	db[thing].zone = zone;
	if(Typeof(thing) != TYPE_PLAYER) {
		/*
		 * if the object is a player, resetting these flags is rather
		 * * * * * inconvenient -- although this may pose a bit of a * 
		 * *  * security * risk. Be careful when @chzone'ing wizard or 
		 * * * * royal players. 
		 */
		Flags(thing) &= ~WIZARD;
		Flags(thing) &= ~ROYALTY;
		Flags(thing) &= ~INHERIT;
#ifdef USE_POWERS
		Powers(thing) = 0;		/*
								 * wipe out all powers 
								 */
#endif
	}
	notify(player, "Zone changed.");
}

void do_name(dbref player, dbref cause, int key, char *name, char *newname)
{
	dbref thing;
	char *buff;
	char *buff2;

	if((thing = match_controlled(player, name)) == NOTHING)
		return;

	/*
	 * check for bad name 
	 */
	if((*newname == '\0') || (strlen(strip_ansi(newname)) == 0)) {
		notify_quiet(player, "Give it what new name?");
		return;
	}
	/*
	 * check for renaming a player 
	 */
	if(isPlayer(thing)) {

		buff = trim_spaces((char *) newname);
		if(!ok_player_name(buff) || !badname_check(buff)) {
			notify_quiet(player, "You can't use that name.");
			free_lbuf(buff);
			return;
		} else if(string_compare(buff, Name(thing)) &&
				  (lookup_player(NOTHING, buff, 0) != NOTHING)) {

			/*
			 * string_compare allows changing foo to Foo, etc. 
			 */

			notify_quiet(player, "That name is already in use.");
			free_lbuf(buff);
			return;
		}

		if(player == thing && In_Character(player) && !Wizard(player)) {
			buff2 = silly_atr_get(player, A_LASTNAME);
			if(!(buff2 && atoi(buff2) &&
				 ((atoi(buff2) + (mudconf.namechange_days * 86400)) <
				  mudstate.now)))
				lower_xp(player, 900);

			silly_atr_set(player, A_LASTNAME, tprintf("%u", mudstate.now));
		}
		/*
		 * everything ok, notify 
		 */
		STARTLOG(LOG_SECURITY, "SEC", "CNAME") {
			log_name(thing), log_text((char *) " renamed to ");
			log_text(buff);
			ENDLOG;
		}
		if(Suspect(thing)) {
			send_channel("Suspect", tprintf("%s renamed to %s",
											Name(thing), buff));
		}
		delete_player_name(thing, Name(thing));

		s_Name(thing, buff);
		add_player_name(thing, Name(thing));
		if(!Quiet(player) && !Quiet(thing))
			notify_quiet(player, "Name set.");
		free_lbuf(buff);
		return;
	} else {
		if(!ok_name(newname)) {
			notify_quiet(player, "That is not a reasonable name.");
			return;
		}
		/*
		 * everything ok, change the name 
		 */
		s_Name(thing, newname);
		if(!Quiet(player) && !Quiet(thing))
			notify_quiet(player, "Name set.");
	}
}

/*
 * ---------------------------------------------------------------------------
 * * do_alias: Make an alias for a player or object.
 */

void do_alias(dbref player, dbref cause, int key, char *name, char *alias)
{
	dbref thing, aowner;
	int aflags;
	ATTR *ap;
	char *oldalias, *trimalias;

	if((thing = match_controlled(player, name)) == NOTHING)
		return;

	/*
	 * check for renaming a player 
	 */

	ap = atr_num(A_ALIAS);
	if(isPlayer(thing)) {

		/*
		 * Fetch the old alias 
		 */

		oldalias = atr_pget(thing, A_ALIAS, &aowner, &aflags);
		trimalias = trim_spaces(alias);

		if(!Controls(player, thing)) {

			/*
			 * Make sure we have rights to do it.  We can't do *
			 * * * * the normal Set_attr check because ALIAS is * 
			 * only * * * writable by GOD and we want to keep *
			 * people * from * * doing &ALIAS and bypassing the * 
			 * player * name checks. 
			 */

			notify_quiet(player, "Permission denied.");
		} else if(!*trimalias) {

			/*
			 * New alias is null, just clear it 
			 */

			delete_player_name(thing, oldalias);
			atr_clr(thing, A_ALIAS);
			if(!Quiet(player))
				notify_quiet(player, "Alias removed.");
		} else if(lookup_player(NOTHING, trimalias, 0) != NOTHING) {

			/*
			 * Make sure new alias isn't already in use 
			 */

			notify_quiet(player, "That name is already in use.");
		} else if(!(badname_check(trimalias) && ok_player_name(trimalias))) {
			notify_quiet(player, "That's a silly name for a player!");
		} else {

			/*
			 * Remove the old name and add the new name 
			 */

			delete_player_name(thing, oldalias);
			atr_add(thing, A_ALIAS, trimalias, Owner(player), aflags);
			if(add_player_name(thing, trimalias)) {
				if(!Quiet(player))
					notify_quiet(player, "Alias set.");
			} else {
				notify_quiet(player,
							 "That name is already in use or is illegal, alias cleared.");
				atr_clr(thing, A_ALIAS);
			}
		}
		free_lbuf(trimalias);
		free_lbuf(oldalias);
	} else {
		atr_pget_info(thing, A_ALIAS, &aowner, &aflags);

		/*
		 * Make sure we have rights to do it 
		 */

		if(!Set_attr(player, thing, ap, aflags)) {
			notify_quiet(player, "Permission denied.");
		} else {
			atr_add(thing, A_ALIAS, alias, Owner(player), aflags);
			if(!Quiet(player))
				notify_quiet(player, "Set.");
		}
	}
}

/*
 * ---------------------------------------------------------------------------
 * * do_lock: Set a lock on an object or attribute.
 */

void do_lock(dbref player, dbref cause, int key, char *name, char *keytext)
{
	dbref thing, aowner;
	int atr, aflags;
	ATTR *ap;
	struct boolexp *okey;

	if(parse_attrib(player, name, &thing, &atr)) {
		if(atr != NOTHING) {
			if(!atr_get_info(thing, atr, &aowner, &aflags)) {
				notify_quiet(player, "Attribute not present on object.");
				return;
			}
			ap = atr_num(atr);

			/*
			 * You may lock an attribute if: * you could write *
			 * * * the attribute if it were stored on * yourself
			 * * * * * --and-- * you own the attribute or are a * 
			 * wizard as  *  * * long as * you are not #1 and are 
			 * 
			 * * trying to do * * something to #1. 
			 */

			if(ap && (God(player) || (!God(thing) &&
									  (Set_attr(player, player, ap, 0)
									   && (Wizard(player)
										   || aowner == Owner(player)))))) {
				aflags |= AF_LOCK;
				atr_set_flags(thing, atr, aflags);
				if(!Quiet(player) && !Quiet(thing))
					notify_quiet(player, "Attribute locked.");
			} else {
				notify_quiet(player, "Permission denied.");
			}
			return;
		}
	}
	init_match(player, name, NOTYPE);
	match_everything(MAT_EXIT_PARENTS);
	thing = match_result();

	switch (thing) {
	case NOTHING:
		notify_quiet(player, "I don't see what you want to lock!");
		return;
	case AMBIGUOUS:
		notify_quiet(player, "I don't know which one you want to lock!");
		return;
	default:
		if(!controls(player, thing)) {
			notify_quiet(player, "You can't lock that!");
			return;
		}
	}

	okey = parse_boolexp(player, keytext, 0);
	if(okey == TRUE_BOOLEXP) {
		notify_quiet(player, "I don't understand that key.");
	} else {

		/*
		 * everything ok, do it 
		 */

		if(!key)
			key = A_LOCK;
		atr_add_raw(thing, key, unparse_boolexp_quiet(player, okey));
		if(!Quiet(player) && !Quiet(thing))
			notify_quiet(player, "Locked.");
	}
	free_boolexp(okey);
}

/*
 * ---------------------------------------------------------------------------
 * * Remove a lock from an object of attribute.
 */

void do_unlock(dbref player, dbref cause, int key, char *name)
{
	dbref thing, aowner;
	int atr, aflags;
	ATTR *ap;

	if(parse_attrib(player, name, &thing, &atr)) {
		if(atr != NOTHING) {
			if(!atr_get_info(thing, atr, &aowner, &aflags)) {
				notify_quiet(player, "Attribute not present on object.");
				return;
			}
			ap = atr_num(atr);

			/*
			 * You may unlock an attribute if: * you could write
			 * * * * the attribute if it were stored on *
			 * yourself * * * * --and-- * you own the attribute
			 * or are a * wizard * as  * long as * you are not #1 
			 * and are * trying to * do * something to #1. 
			 */

			if(ap && (God(player) || ((!God(thing)) &&
									  (Set_attr(player, player, ap, 0)
									   && (Wizard(player)
										   || aowner == Owner(player)))))) {
				aflags &= ~AF_LOCK;
				atr_set_flags(thing, atr, aflags);
				if(Owner(player != Owner(thing)))
					if(!Quiet(player) && !Quiet(thing))
						notify_quiet(player, "Attribute unlocked.");
			} else {
				notify_quiet(player, "Permission denied.");
			}
			return;
		}
	}
	if(!key)
		key = A_LOCK;
	if((thing = match_controlled(player, name)) != NOTHING) {
		atr_clr(thing, key);
		if(!Quiet(player) && !Quiet(thing))
			notify_quiet(player, "Unlocked.");
	}
}

/*
 * ---------------------------------------------------------------------------
 * * do_unlink: Unlink an exit from its destination or remove a dropto.
 */

void do_unlink(dbref player, dbref cause, int key, char *name)
{
	dbref exit;

	init_match(player, name, TYPE_EXIT);
	match_everything(0);
	exit = match_result();

	switch (exit) {
	case NOTHING:
		notify_quiet(player, "Unlink what?");
		break;
	case AMBIGUOUS:
		notify_quiet(player, "I don't know which one you mean!");
		break;
	default:
		if(!controls(player, exit)) {
			notify_quiet(player, "Permission denied.");
		} else {
			switch (Typeof(exit)) {
			case TYPE_EXIT:
				s_Location(exit, NOTHING);
				if(!Quiet(player))
					notify_quiet(player, "Unlinked.");
				break;
			case TYPE_ROOM:
				s_Dropto(exit, NOTHING);
				if(!Quiet(player))
					notify_quiet(player, "Dropto removed.");
				break;
			default:
				notify_quiet(player, "You can't unlink that!");
				break;
			}
		}
	}
}

/*
 * ---------------------------------------------------------------------------
 * * do_chown: Change ownership of an object or attribute.
 */

void do_chown(dbref player, dbref cause, int key, char *name, char *newown)
{
	dbref thing, owner, aowner;
	int atr, aflags, do_it, cost, quota;
	ATTR *ap;

	if(parse_attrib(player, name, &thing, &atr)) {
		if(atr != NOTHING) {
			if(!*newown) {
				owner = Owner(thing);
			} else if(!(string_compare(newown, "me"))) {
				owner = Owner(player);
			} else {
				owner = lookup_player(player, newown, 1);
			}

			/*
			 * You may chown an attr to yourself if you own the * 
			 * 
			 * *  * *  * * object and the attr is not locked. *
			 * You * may * chown  * an attr to the owner of the
			 * object * if * * you own * the attribute. * To do
			 * anything * else you  * must be a  * wizard. * Only 
			 * #1 can * chown * attributes on #1. 
			 */

			if(!atr_get_info(thing, atr, &aowner, &aflags)) {
				notify_quiet(player, "Attribute not present on object.");
				return;
			}
			do_it = 0;
			if(owner == NOTHING) {
				notify_quiet(player, "I couldn't find that player.");
			} else if(God(thing) && !God(player)) {
				notify_quiet(player, "Permission denied.");
			} else if(Wizard(player)) {
				do_it = 1;
			} else if(owner == Owner(player)) {

				/*
				 * chown to me: only if I own the obj and * * 
				 * 
				 * *  * * !locked 
				 */

				if(!Controls(player, thing) || (aflags & AF_LOCK)) {
					notify_quiet(player, "Permission denied.");
				} else {
					do_it = 1;
				}
			} else if(owner == Owner(thing)) {

				/*
				 * chown to obj owner: only if I own attr * * 
				 * 
				 * *  * * and !locked 
				 */

				if((Owner(player) != aowner) || (aflags & AF_LOCK)) {
					notify_quiet(player, "Permission denied.");
				} else {
					do_it = 1;
				}
			} else {
				notify_quiet(player, "Permission denied.");
			}

			if(!do_it)
				return;

			ap = atr_num(atr);
			if(!ap || !Set_attr(player, player, ap, aflags)) {
				notify_quiet(player, "Permission denied.");
				return;
			}
			atr_set_owner(thing, atr, owner);
			if(!Quiet(player))
				notify_quiet(player, "Attribute owner changed.");
			return;
		}
	}
	init_match(player, name, TYPE_THING);
	match_possession();
	match_here();
	match_exit();
	match_me();
	if(Chown_Any(player)) {
		match_player();
		match_absolute();
	}
	switch (thing = match_result()) {
	case NOTHING:
		notify_quiet(player, "You don't have that!");
		return;
	case AMBIGUOUS:
		notify_quiet(player, "I don't know which you mean!");
		return;
	}

	if(!*newown || !(string_compare(newown, "me"))) {
		owner = Owner(player);
	} else {
		owner = lookup_player(player, newown, 1);
	}

	cost = 1;
	quota = 1;
	switch (Typeof(thing)) {
	case TYPE_ROOM:
		cost = mudconf.digcost;
		quota = mudconf.room_quota;
		break;
	case TYPE_THING:
		cost = OBJECT_DEPOSIT(Pennies(thing));
		quota = mudconf.thing_quota;
		break;
	case TYPE_EXIT:
		cost = mudconf.opencost;
		quota = mudconf.exit_quota;
		break;
	case TYPE_PLAYER:
		cost = mudconf.robotcost;
		quota = mudconf.player_quota;
	}

	if(owner == NOTHING) {
		notify_quiet(player, "I couldn't find that player.");
	} else if(isPlayer(thing) && !God(player)) {
		notify_quiet(player, "Players always own themselves.");
	} else if(((!controls(player, thing) && !Chown_Any(player) &&
				!Chown_ok(thing)) || (isThing(thing) &&
									  (Location(thing) != player)
									  && !Chown_Any(player)))
			  || (!controls(player, owner))) {
		notify_quiet(player, "Permission denied.");
	} else if(canpayfees(player, owner, cost, quota)) {
		giveto(Owner(thing), cost);
		if(mudconf.quotas)
			add_quota(Owner(thing), quota);
		if(God(player)) {
			s_Owner(thing, owner);
		} else {
			s_Owner(thing, Owner(owner));
		}
		atr_chown(thing);
		s_Flags(thing, (Flags(thing) & ~(CHOWN_OK | INHERIT)) | HALT);
		s_Powers(thing, 0);
		s_Powers2(thing, 0);
		halt_que(NOTHING, thing);
		if(!Quiet(player))
			notify_quiet(player, "Owner changed.");
	}
}

/*
 * ---------------------------------------------------------------------------
 * * do_set: Set flags or attributes on objects, or flags on attributes.
 */

void set_attr_internal(dbref player, dbref thing, int attrnum, char *attrtext,
					   int key)
{
	dbref aowner;
	int aflags, could_hear, have_xcode;
	ATTR *attr;

	attr = atr_num(attrnum);
	atr_pget_info(thing, attrnum, &aowner, &aflags);
	if(attr && Set_attr(player, thing, attr, aflags)) {
		if((attr->check != NULL) &&
		   (!(*attr->check) (0, player, thing, attrnum, attrtext)))
			return;
		have_xcode = Hardcode(thing);
		atr_add(thing, attrnum, attrtext, Owner(player), aflags);
		if(mudconf.have_specials)
			handle_xcode(player, thing, have_xcode, Hardcode(thing));
		if(!(key & SET_QUIET) && !Quiet(player) && !Quiet(thing))
			notify_printf(player, "%s/%s - %s", Name(thing),
						  attr->name, strlen(attrtext) ? "Set." : "Cleared.");
		could_hear = Hearer(thing);
		handle_ears(thing, could_hear, Hearer(thing));
	} else {
		notify_quiet(player, "Permission denied.");
	}
}

void do_set(dbref player, dbref cause, int key, char *name, char *flag)
{
	dbref thing, thing2, aowner;
	char *p, *buff;
	int atr, atr2, aflags, clear, flagvalue, could_hear, have_xcode;
	ATTR *attr, *attr2;

	/*
	 * See if we have the <obj>/<attr> form, which is how you set * * *
	 * attribute * flags. 
	 */

	if(parse_attrib(player, name, &thing, &atr)) {
		if(atr != NOTHING) {

			/*
			 * You must specify a flag name 
			 */

			if(!flag || !*flag) {
				notify_quiet(player, "I don't know what you want to set!");
				return;
			}
			/*
			 * Check for clearing 
			 */

			clear = 0;
			if(*flag == NOT_TOKEN) {
				flag++;
				clear = 1;
			}
			/*
			 * Make sure player specified a valid attribute flag 
			 */

			flagvalue =
				search_nametab(player, indiv_attraccess_nametab, flag);
			if(flagvalue < 0) {
				notify_quiet(player, "You can't set that!");
				return;
			}
			/*
			 * Make sure the object has the attribute present 
			 */

			if(!atr_get_info(thing, atr, &aowner, &aflags)) {
				notify_quiet(player, "Attribute not present on object.");
				return;
			}
			/*
			 * Make sure we can write to the attribute 
			 */

			attr = atr_num(atr);
			if(!attr || !Set_attr(player, thing, attr, aflags)) {
				notify_quiet(player, "Permission denied.");
				return;
			}
			/*
			 * Go do it 
			 */

			if(clear)
				aflags &= ~flagvalue;
			else
				aflags |= flagvalue;
			have_xcode = Hardcode(thing);
			atr_set_flags(thing, atr, aflags);

			/*
			 * Tell the player about it. 
			 */

			if(mudconf.have_specials)
				handle_xcode(player, thing, have_xcode, Hardcode(thing));
			if(!(key & SET_QUIET) && !Quiet(player) && !Quiet(thing)) {
				FLAGENT *fp;
				fp = find_flag(thing, flag);
				notify_printf(player, "%s/%s - %s %s", Name(thing),
							  attr->name, fp->flagname,
							  clear ? "cleared." : "set.");
			}
			could_hear = Hearer(thing);
			handle_ears(thing, could_hear, Hearer(thing));
			return;
		}
	}
	/*
	 * find thing 
	 */

	if((thing = match_controlled(player, name)) == NOTHING)
		return;

	/*
	 * check for attribute set first 
	 */
	for(p = flag; *p && (*p != ':'); p++);

	if(*p) {
		*p++ = 0;
		atr = mkattr(flag);
		if(atr <= 0) {
			notify_quiet(player, "Couldn't create attribute.");
			return;
		}
		attr = atr_num(atr);
		if(!attr) {
			notify_quiet(player, "Permission denied.");
			return;
		}
		atr_get_info(thing, atr, &aowner, &aflags);
		if(!Set_attr(player, thing, attr, aflags)) {
			notify_quiet(player, "Permission denied.");
			return;
		}
		buff = alloc_lbuf("do_set");

		/*
		 * check for _ 
		 */
		if(*p == '_') {
			StringCopy(buff, p + 1);
			if(!parse_attrib(player, p + 1, &thing2, &atr2) ||
			   (atr2 == NOTHING)) {
				notify_quiet(player, "No match.");
				free_lbuf(buff);
				return;
			}
			attr2 = atr_num(atr2);
			p = buff;
			atr_pget_str(buff, thing2, atr2, &aowner, &aflags);

			if(!attr2 || !See_attr(player, thing2, attr2, aowner, aflags)) {
				notify_quiet(player, "Permission denied.");
				free_lbuf(buff);
				return;
			}
		}
		/*
		 * Go set it 
		 */

		set_attr_internal(player, thing, atr, p, key);
		free_lbuf(buff);
		return;
	}
	/*
	 * Set or clear a flag 
	 */

	flag_set(thing, player, flag, key);
}

void do_power(dbref player, dbref cause, int key, char *name, char *flag)
{
	dbref thing;

	if(!flag || !*flag) {
		notify_quiet(player, "I don't know what you want to set!");
		return;
	}
	/*
	 * find thing 
	 */

	if((thing = match_controlled(player, name)) == NOTHING)
		return;

	power_set(thing, player, flag, key);
}

void do_setattr(dbref player, dbref cause, int attrnum, char *name,
				char *attrtext)
{
	dbref thing;

	init_match(player, name, NOTYPE);
	match_everything(MAT_EXIT_PARENTS);
	thing = noisy_match_result();

	if(thing == NOTHING)
		return;
	set_attr_internal(player, thing, attrnum, attrtext, 0);
}

void do_cpattr(dbref player, dbref cause, int key, char *oldpair,
			   char *newpair[], int nargs)
{
	int i;
	char *oldthing, *oldattr, *newthing, *newattr;

	if(!*oldpair || !**newpair || !oldpair || !*newpair)
		return;

	if(nargs < 1)
		return;

	oldattr = oldpair;
	oldthing = parse_to(&oldattr, '/', 1);

	for(i = 0; i < nargs; i++) {
		newattr = newpair[i];
		newthing = parse_to(&newattr, '/', 1);

		if(!oldattr) {
			if(!newattr) {
				do_set(player, cause, 0, newthing, tprintf("%s:_%s/%s",
														   oldthing, "me",
														   oldthing));
			} else {
				do_set(player, cause, 0, newthing, tprintf("%s:_%s/%s",
														   newattr, "me",
														   oldthing));
			}
		} else {
			if(!newattr) {
				do_set(player, cause, 0, newthing, tprintf("%s:_%s/%s",
														   oldattr, oldthing,
														   oldattr));
			} else {
				do_set(player, cause, 0, newthing, tprintf("%s:_%s/%s",
														   newattr, oldthing,
														   oldattr));
			}
		}
	}
}

void do_mvattr(dbref player, dbref cause, int key, char *what, char *args[],
			   int nargs)
{
	dbref thing, aowner, axowner;
	ATTR *in_attr, *out_attr;
	int i, anum, in_anum, aflags, axflags, no_delete;
	char *astr;

	/*
	 * Make sure we have something to do. 
	 */

	if(nargs < 2) {
		notify_quiet(player, "Nothing to do.");
		return;
	}
	/*
	 * FInd and make sure we control the target object. 
	 */

	thing = match_controlled(player, what);
	if(thing == NOTHING)
		return;

	/*
	 * Look up the source attribute.  If it either doesn't exist or isn't
	 * * * * * readable, use an empty string. 
	 */

	in_anum = -1;
	astr = alloc_lbuf("do_mvattr");
	in_attr = atr_str(args[0]);
	if(in_attr == NULL) {
		*astr = '\0';
	} else {
		atr_get_str(astr, thing, in_attr->number, &aowner, &aflags);
		if(!See_attr(player, thing, in_attr, aowner, aflags)) {
			*astr = '\0';
		} else {
			in_anum = in_attr->number;
		}
	}

	/*
	 * Copy the attribute to each target in turn. 
	 */

	no_delete = 0;
	for(i = 1; i < nargs; i++) {
		anum = mkattr(args[i]);
		if(anum <= 0) {
			notify_quiet(player,
						 tprintf
						 ("%s: That's not a good name for an attribute.",
						  args[i]));
			continue;
		}
		out_attr = atr_num(anum);
		if(!out_attr) {
			notify_quiet(player, tprintf("%s: Permission denied.", args[i]));
		} else if(out_attr->number == in_anum) {
			no_delete = 1;
		} else {
			atr_get_info(thing, out_attr->number, &axowner, &axflags);
			if(!Set_attr(player, thing, out_attr, axflags)) {
				notify_quiet(player, tprintf("%s: Permission denied.",
											 args[i]));
			} else {
				atr_add(thing, out_attr->number, astr, Owner(player), aflags);
				if(!Quiet(player))
					notify_printf(player, "%s/%s - Set.", Name(thing),
								  out_attr->name);
			}
		}
	}

	/*
	 * Remove the source attribute if we can. 
	 */

	if((in_anum > 0) && !no_delete) {
		in_attr = atr_num(in_anum);
		if(in_attr && Set_attr(player, thing, in_attr, aflags)) {
			atr_clr(thing, in_attr->number);
			if(!Quiet(player))
				notify_printf(player, "%s/%s - Cleared.", Name(thing),
							  in_attr->name);
		} else {
			if(in_attr)
				notify_quiet(player,
							 tprintf
							 ("%s: Could not remove old attribute.  Permission denied.",
							  in_attr->name));
		}
	}
	free_lbuf(astr);
}

/*
 * ---------------------------------------------------------------------------
 * * parse_attrib, parse_attrib_wild: parse <obj>/<attr> tokens.
 */

int parse_attrib(dbref player, char *str, dbref * thing, int *atr)
{
	ATTR *attr;
	char *buff;
	dbref aowner;
	int aflags;

	if(!str)
		return 0;

	/*
	 * Break apart string into obj and attr.  Return on failure 
	 */

	buff = alloc_lbuf("parse_attrib");
	StringCopy(buff, str);
	if(!parse_thing_slash(player, buff, &str, thing)) {
		free_lbuf(buff);
		return 0;
	}
	/*
	 * Get the named attribute from the object if we can 
	 */

	attr = atr_str(str);
	free_lbuf(buff);
	if(!attr) {
		*atr = NOTHING;
	} else {
		atr_pget_info(*thing, attr->number, &aowner, &aflags);
		if(!See_attr(player, *thing, attr, aowner, aflags)) {
			*atr = NOTHING;
		} else {
			*atr = attr->number;
		}
	}
	return 1;
}

static void find_wild_attrs(dbref player, dbref thing, char *str,
							int check_exclude, int hash_insert, int get_locks)
{
	ATTR *attr;
	char *as;
	dbref aowner;
	int ca, ok, aflags;

	/*
	 * Walk the attribute list of the object 
	 */

	for(ca = atr_head(thing, &as); ca; ca = atr_next(&as)) {
		attr = atr_num(ca);

		/*
		 * Discard bad attributes and ones we've seen before. 
		 */

		if(!attr)
			continue;

		if(check_exclude && ((attr->flags & AF_PRIVATE) ||
							 nhashfind(ca, &mudstate.parent_htab)))
			continue;

		/*
		 * If we aren't the top level remember this attr so we * * *
		 * exclude * it in any parents. 
		 */

		atr_get_info(thing, ca, &aowner, &aflags);
		if(check_exclude && (aflags & AF_PRIVATE))
			continue;

		if(get_locks)
			ok = Read_attr(player, thing, attr, aowner, aflags);
		else
			ok = See_attr(player, thing, attr, aowner, aflags);

		/*
		 * Enforce locality restriction on descriptions 
		 */

		if(ok && (attr->number == A_DESC) && !mudconf.read_rem_desc &&
		   !Examinable(player, thing) && !nearby(player, thing))
			ok = 0;

		if(ok && quick_wild(str, (char *) attr->name)) {
			olist_add(ca);
			if(hash_insert) {
				nhashadd(ca, (int *) attr, &mudstate.parent_htab);
			}
		}
	}
}

int parse_attrib_wild(dbref player, char *str, dbref * thing,
					  int check_parents, int get_locks, int df_star)
{
	char *buff;
	dbref parent;
	int check_exclude, hash_insert, lev;

	if(!str)
		return 0;

	buff = alloc_lbuf("parse_attrib_wild");
	StringCopy(buff, str);

	/*
	 * Separate name and attr portions at the first / 
	 */

	if(!parse_thing_slash(player, buff, &str, thing)) {

		/*
		 * Not in obj/attr format, return if not defaulting to * 
		 */

		if(!df_star) {
			free_lbuf(buff);
			return 0;
		}
		/*
		 * Look for the object, return failure if not found 
		 */

		init_match(player, buff, NOTYPE);
		match_everything(MAT_EXIT_PARENTS);
		*thing = match_result();

		if(!Good_obj(*thing)) {
			free_lbuf(buff);
			return 0;
		}
		str = (char *) "*";
	}
	/*
	 * Check the object (and optionally all parents) for attributes 
	 */

	if(check_parents) {
		check_exclude = 0;
		hash_insert = check_parents;
		nhashflush(&mudstate.parent_htab, 0);
		ITER_PARENTS(*thing, parent, lev) {
			if(!Good_obj(Parent(parent)))
				hash_insert = 0;
			find_wild_attrs(player, parent, str, check_exclude,
							hash_insert, get_locks);
			check_exclude = 1;
		}
	} else {
		find_wild_attrs(player, *thing, str, 0, 0, get_locks);
	}
	free_lbuf(buff);
	return 1;
}

/*
 * ---------------------------------------------------------------------------
 * * edit_string, edit_string_ansi, do_edit: Modify attributes.
 */

void edit_string(char *src, char **dst, char *from, char *to)
{
	char *cp;

	/*
	 * Do the substitution.  Idea for prefix/suffix from R'nice@TinyTIM 
	 */

	if(!strcmp(from, "^")) {
		/*
		 * Prepend 'to' to string 
		 */

		*dst = alloc_lbuf("edit_string.^");
		cp = *dst;
		safe_str(to, *dst, &cp);
		safe_str(src, *dst, &cp);
		*cp = '\0';
	} else if(!strcmp(from, "$")) {
		/*
		 * Append 'to' to string 
		 */

		*dst = alloc_lbuf("edit_string.$");
		cp = *dst;
		safe_str(src, *dst, &cp);
		safe_str(to, *dst, &cp);
		*cp = '\0';
	} else {
		/*
		 * replace all occurances of 'from' with 'to'.  Handle the *
		 * * * * special cases of from = \$ and \^. 
		 */

		if(((from[0] == '\\') || (from[0] == '%')) && ((from[1] == '$') ||
													   (from[1] == '^'))
		   && (from[2] == '\0'))
			from++;
		*dst = replace_string(from, to, src);
	}
}

void edit_string_ansi(char *src, char **dst, char **returnstr, char *from,
					  char *to)
{
	char *cp, *rp;

	/*
	 * Do the substitution.  Idea for prefix/suffix from R'nice@TinyTIM 
	 */

	if(!strcmp(from, "^")) {
		/*
		 * Prepend 'to' to string 
		 */

		*dst = alloc_lbuf("edit_string.^");
		cp = *dst;
		safe_str(to, *dst, &cp);
		safe_str(src, *dst, &cp);
		*cp = '\0';

		/*
		 * Do the ansi string used to notify 
		 */
		*returnstr = alloc_lbuf("edit_string_ansi.^");
		rp = *returnstr;
		safe_str(ANSI_HILITE, *returnstr, &rp);
		safe_str(to, *returnstr, &rp);
		safe_str(ANSI_NORMAL, *returnstr, &rp);
		safe_str(src, *returnstr, &rp);
		*rp = '\0';

	} else if(!strcmp(from, "$")) {
		/*
		 * Append 'to' to string 
		 */

		*dst = alloc_lbuf("edit_string.$");
		cp = *dst;
		safe_str(src, *dst, &cp);
		safe_str(to, *dst, &cp);
		*cp = '\0';

		/*
		 * Do the ansi string used to notify 
		 */

		*returnstr = alloc_lbuf("edit_string_ansi.$");
		rp = *returnstr;
		safe_str(src, *returnstr, &rp);
		safe_str(ANSI_HILITE, *returnstr, &rp);
		safe_str(to, *returnstr, &rp);
		safe_str(ANSI_NORMAL, *returnstr, &rp);
		*rp = '\0';

	} else {
		/*
		 * replace all occurances of 'from' with 'to'.  Handle the *
		 * * * * special cases of from = \$ and \^. 
		 */

		if(((from[0] == '\\') || (from[0] == '%')) && ((from[1] == '$') ||
													   (from[1] == '^'))
		   && (from[2] == '\0'))
			from++;

		*dst = replace_string(from, to, src);
		*returnstr =
			replace_string(from, tprintf("%s%s%s", ANSI_HILITE, to,
										 ANSI_NORMAL), src);
	}
}

void do_edit(dbref player, dbref cause, int key, char *it, char *args[],
			 int nargs)
{
	dbref thing, aowner;
	int attr, got_one, aflags, doit;
	char *from, *to, *result, *returnstr, *atext;
	ATTR *ap;

	/*
	 * Make sure we have something to do. 
	 */

	if((nargs < 1) || !*args[0]) {
		notify_quiet(player, "Nothing to do.");
		return;
	}
	from = args[0];
	to = (nargs >= 2) ? args[1] : (char *) "";

	/*
	 * Look for the object and get the attribute (possibly wildcarded) 
	 */

	olist_push();
	if(!it || !*it || !parse_attrib_wild(player, it, &thing, 0, 0, 0)) {
		notify_quiet(player, "No match.");
		olist_pop();
		return;
	}
	/*
	 * Iterate through matching attributes, performing edit 
	 */

	got_one = 0;
	atext = alloc_lbuf("do_edit.atext");

	for(attr = olist_first(); attr != NOTHING; attr = olist_next()) {
		ap = atr_num(attr);
		if(ap) {

			/*
			 * Get the attr and make sure we can modify it. 
			 */

			atr_get_str(atext, thing, ap->number, &aowner, &aflags);
			if(Set_attr(player, thing, ap, aflags)) {

				/*
				 * Do the edit and save the result 
				 */

				got_one = 1;
				edit_string_ansi(atext, &result, &returnstr, from, to);
				if(ap->check != NULL) {
					doit =
						(*ap->check) (0, player, thing, ap->number, result);
				} else {
					doit = 1;
				}
				if(doit) {
					atr_add(thing, ap->number, result, Owner(player), aflags);
					if(!Quiet(player))
						notify_quiet(player, tprintf("Set - %s: %s",
													 ap->name, returnstr));
				}
				free_lbuf(result);
				free_lbuf(returnstr);
			} else {

				/*
				 * No rights to change the attr 
				 */

				notify_quiet(player, tprintf("%s: Permission denied.",
											 ap->name));
			}

		}
	}

	/*
	 * Clean up 
	 */

	free_lbuf(atext);
	olist_pop();

	if(!got_one) {
		notify_quiet(player, "No matching attributes.");
	}
}

void do_wipe(dbref player, dbref cause, int key, char *it)
{
	dbref thing, aowner;
	int attr, got_one, aflags;
	ATTR *ap;
	char *atext;

	olist_push();
	if(!it || !*it || !parse_attrib_wild(player, it, &thing, 0, 0, 1)) {
		notify_quiet(player, "No match.");
		olist_pop();
		return;
	}
	/*
	 * Iterate through matching attributes, zapping the writable ones 
	 */

	got_one = 0;
	atext = alloc_lbuf("do_wipe.atext");
	for(attr = olist_first(); attr != NOTHING; attr = olist_next()) {
		ap = atr_num(attr);
		if(ap) {

			/*
			 * Get the attr and make sure we can modify it. 
			 */

			atr_get_str(atext, thing, ap->number, &aowner, &aflags);
			if(Set_attr(player, thing, ap, aflags)) {
				atr_clr(thing, ap->number);
				got_one++;
			}
		}
	}
	/*
	 * Clean up 
	 */

	if(!got_one) {
		notify_quiet(player, "No matching attributes.");
	} else {
		if(!Quiet(player))
			notify_printf(player, "%s - %d attribute(s) wiped.", Name(thing), got_one);
	}

	free_lbuf(atext);
	olist_pop();

}

void do_trigger(dbref player, dbref cause, int key, char *object,
				char *argv[], int nargs)
{
	dbref thing;
	int attrib;

	if(!parse_attrib(player, object, &thing, &attrib) || (attrib == NOTHING)) {
		notify_quiet(player, "No match.");
		return;
	}
	if(!controls(player, thing)) {
		notify_quiet(player, "Permission denied.");
		return;
	}
	did_it(player, thing, 0, NULL, 0, NULL, attrib, argv, nargs);

	/*
	 * XXX be more descriptive as to what was triggered? 
	 */
	if(!(key & TRIG_QUIET) && !Quiet(player))
		notify_quiet(player, "Triggered.");

}

void do_use(dbref player, dbref cause, int key, char *object)
{
	char *df_use, *df_ouse, *temp;
	dbref thing, aowner;
	int aflags, doit;

	init_match(player, object, NOTYPE);
	match_neighbor();
	match_possession();
	if(Wizard(player)) {
		match_absolute();
		match_player();
	}
	match_me();
	match_here();
	thing = noisy_match_result();
	if(thing == NOTHING)
		return;

	/*
	 * Make sure player can use it 
	 */

	if(!could_doit(player, thing, A_LUSE)) {
		did_it(player, thing, A_UFAIL,
			   "You can't figure out how to use that.", A_OUFAIL, NULL,
			   A_AUFAIL, (char **) NULL, 0);
		return;
	}
	temp = alloc_lbuf("do_use");
	doit = 0;
	if(*atr_pget_str(temp, thing, A_USE, &aowner, &aflags))
		doit = 1;
	else if(*atr_pget_str(temp, thing, A_OUSE, &aowner, &aflags))
		doit = 1;
	else if(*atr_pget_str(temp, thing, A_AUSE, &aowner, &aflags))
		doit = 1;
	free_lbuf(temp);

	if(doit) {
		df_use = alloc_lbuf("do_use.use");
		df_ouse = alloc_lbuf("do_use.ouse");
		sprintf(df_use, "You use %s", Name(thing));
		sprintf(df_ouse, "uses %s", Name(thing));
		did_it(player, thing, A_USE, df_use, A_OUSE, df_ouse, A_AUSE,
			   (char **) NULL, 0);
		free_lbuf(df_use);
		free_lbuf(df_ouse);
	} else {
		notify_quiet(player, "You can't figure out how to use that.");
	}
}

/*
 * ---------------------------------------------------------------------------
 * * do_setvattr: Set a user-named (or possibly a predefined) attribute.
 */

void do_setvattr(dbref player, dbref cause, int key, char *arg1, char *arg2)
{
	char *s;
	int anum;

	arg1++;						/*
								 * skip the '&' 
								 */
	for(s = arg1; *s && !isspace(*s); s++);	/*
											 * take to the space 
											 */
	if(*s)
		*s++ = '\0';			/*
								 * split it 
								 */

	anum = mkattr(arg1);		/*
								 * Get or make attribute 
								 */
	if(anum <= 0) {
		notify_quiet(player, "That's not a good name for an attribute.");
		return;
	}
	do_setattr(player, cause, anum, s, arg2);
}