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/
/*
 * look.c -- commands which look at things 
 */

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

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

extern void ufun(char *, char *, int, int, int, dbref, dbref);

static void look_exits(dbref player, dbref loc, const char *exit_name)
{
	dbref thing, parent;
	char *buff, *e, *s, *buff1, *e1;
	int foundany, lev, key;

	/*
	 * make sure location has exits 
	 */

	if(!Good_obj(loc) || !Has_exits(loc))
		return;

	/*
	 * make sure there is at least one visible exit 
	 */

	foundany = 0;
	key = 0;
	if(Dark(loc))
		key |= VE_BASE_DARK;
	ITER_PARENTS(loc, parent, lev) {
		key &= ~VE_LOC_DARK;
		if(Dark(parent))
			key |= VE_LOC_DARK;
		DOLIST(thing, Exits(parent)) {
			if(exit_displayable(thing, player, key)) {
				foundany = 1;
				break;
			}
		}
		if(foundany)
			break;
	}

	if(!foundany)
		return;
	/*
	 * Display the list of exit names 
	 */

	notify(player, exit_name);
	e = buff = alloc_lbuf("look_exits");
	e1 = buff1 = alloc_lbuf("look_exits2");
	ITER_PARENTS(loc, parent, lev) {
		key &= ~VE_LOC_DARK;
		if(Dark(parent))
			key |= VE_LOC_DARK;
		if(Transparent(loc)) {
			DOLIST(thing, Exits(parent)) {
				if(exit_displayable(thing, player, key)) {
					StringCopy(buff, Name(thing));
					for(e = buff; *e && (*e != ';'); e++);
					*e = '\0';
					notify_printf(player, "%s leads to %s.", buff,
								  Name(Location(thing)));
				}
			}
		} else {
			DOLIST(thing, Exits(parent)) {
				if(exit_displayable(thing, player, key)) {
					e1 = buff1;
					/* Put the exit name in buff1 */
					/*
					 * chop off first * * 
					 * 
					 * * exit alias to *
					 * * * display 
					 */

					if(buff != e)
						safe_str((char *) "  ", buff, &e);
					for(s = Name(thing); *s && (*s != ';'); s++)
						safe_chr(*s, buff1, &e1);
					*e1 = 0;
					/* Copy the exit name into 'buff' */
					/* Append this exit to the list */
					safe_str(buff1, buff, &e);

				}
			}
		}
	}

	if(!(Transparent(loc))) {
		safe_str((char *) "\r\n", buff, &e);
		*e = 0;
		notify(player, buff);
	}
	free_lbuf(buff);
	free_lbuf(buff1);
}

#define CONTENTS_LOCAL  0
#define CONTENTS_NESTED 1
#define CONTENTS_REMOTE 2

static void look_contents(dbref player, dbref loc, const char *contents_name,
						  int style)
{
	dbref thing;
	dbref can_see_loc;
	char *buff;
	char remote_num[32];

	/*
	 * check to see if he can see the location 
	 */

	can_see_loc = (!Dark(loc) || (mudconf.see_own_dark &&
								  Examinable(player, loc)));

	/*
	 * check to see if there is anything there 
	 */

	DOLIST(thing, Contents(loc)) {
		if(can_see(player, thing, can_see_loc)) {

			/*
			 * something exists!  show him everything 
			 */

			notify(player, contents_name);
			DOLIST(thing, Contents(loc)) {
				if(can_see(player, thing, can_see_loc)) {
					buff = unparse_object(player, thing, 1);
					notify(player, buff);
					free_lbuf(buff);

				}
			}
			break;				/*
								 * we're done 
								 */
		}
	}
}

static void view_atr(dbref player, dbref thing, ATTR * ap, char *text,
					 dbref aowner, int aflags, int skip_tag)
{
	char *buf;
	char xbuf[6];
	char *xbufp;
	BOOLEXP *bool;

	if(ap->flags & AF_IS_LOCK) {
		bool = parse_boolexp(player, text, 1);
		text = unparse_boolexp(player, bool);
		free_boolexp(bool);
	}
	/*
	 * If we don't control the object or own the attribute, hide the * *
	 * * * attr owner and flag info. 
	 */

	if(!Controls(player, thing) && (Owner(player) != aowner)) {
		if(skip_tag && (ap->number == A_DESC))
			buf = text;
		else
			buf = tprintf("\033[1m%s:\033[0m %s", ap->name, text);
		notify(player, buf);
		return;
	}
	/*
	 * Generate flags 
	 */

	xbufp = xbuf;
	if(aflags & AF_LOCK)
		*xbufp++ = '+';
	if(aflags & AF_NOPROG)
		*xbufp++ = '$';
	if(aflags & AF_PRIVATE)
		*xbufp++ = 'I';
	if(aflags & AF_REGEXP)
		*xbufp++ = 'R';
	if(aflags & AF_VISUAL)
		*xbufp++ = 'V';
	if(aflags & AF_MDARK)
		*xbufp++ = 'M';
	if(aflags & AF_WIZARD)
		*xbufp++ = 'W';

	*xbufp = '\0';

	if((aowner != Owner(thing)) && (aowner != NOTHING)) {
		buf =
			tprintf("\033[1m%s [#%d%s]:\033[0m %s", ap->name, aowner, xbuf,
					text);
	} else if(*xbuf) {
		buf = tprintf("\033[1m%s [%s]:\033[0m %s", ap->name, xbuf, text);
	} else if(!skip_tag || (ap->number != A_DESC)) {
		buf = tprintf("\033[1m%s:\033[0m %s", ap->name, text);
	} else {
		buf = text;
	}
	notify(player, buf);
}

static void look_atrs1(dbref player, dbref thing, dbref othing,
					   int check_exclude, int hash_insert)
{
	dbref aowner;
	int ca, aflags;
	ATTR *attr, *cattr;
	char *as, *buf;

	cattr = (ATTR *) malloc(sizeof(ATTR));
	for(ca = atr_head(thing, &as); ca; ca = atr_next(&as)) {
		if((ca == A_DESC) || (ca == A_LOCK))
			continue;
		attr = atr_num(ca);
		if(!attr)
			continue;

		bcopy((char *) attr, (char *) cattr, sizeof(ATTR));

		/*
		 * Should we exclude this attr? 
		 */

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

		buf = atr_get(thing, ca, &aowner, &aflags);
		if(Read_attr(player, othing, attr, aowner, aflags)) {
			/* check_zone/atr_num overwrites attr!! */

			if(attr->number != cattr->number)
				bcopy((char *) cattr, (char *) attr, sizeof(ATTR));

			if(!(check_exclude && (aflags & AF_PRIVATE))) {
				if(hash_insert)
					nhashadd(ca, (int *) attr, &mudstate.parent_htab);
				view_atr(player, thing, attr, buf, aowner, aflags, 0);
			}
		}
		free_lbuf(buf);
	}
	free(cattr);
}

static void look_atrs(dbref player, dbref thing, int check_parents)
{
	dbref parent;
	int lev, check_exclude, hash_insert;

	if(!check_parents) {
		look_atrs1(player, thing, thing, 0, 0);
	} else {
		hash_insert = 1;
		check_exclude = 0;
		nhashflush(&mudstate.parent_htab, 0);
		ITER_PARENTS(thing, parent, lev) {
			if(!Good_obj(Parent(parent)))
				hash_insert = 0;
			look_atrs1(player, parent, thing, check_exclude, hash_insert);
			check_exclude = 1;
		}
	}
}

static void look_simple(dbref player, dbref thing, int obey_terse)
{
	int pattr;
	char *buff;

	/*
	 * Only makes sense for things that can hear 
	 */

	if(!Hearer(player))
		return;

	/*
	 * Get the name and db-number if we can examine it. 
	 */

	if(Examinable(player, thing)) {
		buff = unparse_object(player, thing, 1);
		notify(player, buff);
		free_lbuf(buff);

	}
	pattr = (obey_terse && Terse(player)) ? 0 : A_DESC;
	did_it(player, thing, pattr, "You see nothing special.", A_ODESC, NULL,
		   A_ADESC, (char **) NULL, 0);

	if(!mudconf.quiet_look && (!Terse(player) || mudconf.terse_look)) {
		look_atrs(player, thing, 0);
	}
}

static void show_a_desc(dbref player, dbref loc)
{
	char *got2;
	dbref aowner;
	int aflags, indent = 0;

	indent = (isRoom(loc) && mudconf.indent_desc && atr_get_raw(loc, A_DESC));

	if(indent)
		raw_notify_newline(player);
	did_it(player, loc, A_DESC, NULL, A_ODESC, NULL, A_ADESC,
		   (char **) NULL, 0);
	if(indent)
		raw_notify_newline(player);
	
}

static void show_desc(dbref player, dbref loc, int key)
{
	char *got;
	dbref aowner;
	int aflags;

	if((key & LK_OBEYTERSE) && Terse(player))
		did_it(player, loc, 0, NULL, A_ODESC, NULL, A_ADESC,
			   (char **) NULL, 0);
	else if((Typeof(loc) != TYPE_ROOM) && (key & LK_IDESC)) {
		if(*(got = atr_pget(loc, A_IDESC, &aowner, &aflags)))
			did_it(player, loc, A_IDESC, NULL, A_ODESC, NULL, A_ADESC,
				   (char **) NULL, 0);
		else
			show_a_desc(player, loc);
		free_lbuf(got);
	} else {
		show_a_desc(player, loc);
	}
}

void look_in(dbref player, dbref loc, int key)
{
	int pattr, oattr, aattr, is_terse, showkey;
	char *buff;

	is_terse = (key & LK_OBEYTERSE) ? Terse(player) : 0;

	/*
	 * Only makes sense for things that can hear 
	 */

	if(!Hearer(player))
		return;

	/*
	 * tell him the name, and the number if he can link to it 
	 */

	buff = unparse_object(player, loc, 1);
	notify(player, buff);
	free_lbuf(buff);

	if(!Good_obj(loc))
		return;					/*
								 * If we went to NOTHING et al,  skip the * * 
								 * 
								 * * rest 
								 */

	/*
	 * tell him the description 
	 */

	showkey = 0;
	if(loc == Location(player))
		showkey |= LK_IDESC;
	if(key & LK_OBEYTERSE)
		showkey |= LK_OBEYTERSE;
	show_desc(player, loc, showkey);

	/*
	 * tell him the appropriate messages if he has the key 
	 */

	if(Typeof(loc) == TYPE_ROOM) {
		if(could_doit(player, loc, A_LOCK)) {
			pattr = A_SUCC;
			oattr = A_OSUCC;
			aattr = A_ASUCC;
		} else {
			pattr = A_FAIL;
			oattr = A_OFAIL;
			aattr = A_AFAIL;
		}
		if(is_terse)
			pattr = 0;
		did_it(player, loc, pattr, NULL, oattr, NULL, aattr,
			   (char **) NULL, 0);
	}
	/*
	 * tell him the attributes, contents and exits 
	 */

	if((key & LK_SHOWATTR) && !mudconf.quiet_look && !is_terse)
		look_atrs(player, loc, 0);
	if(!is_terse || mudconf.terse_contents)
		look_contents(player, loc, "Contents:", CONTENTS_LOCAL);
	if((key & LK_SHOWEXIT) && (!is_terse || mudconf.terse_exits))
		look_exits(player, loc, "Obvious exits:");
}

void do_look(dbref player, dbref cause, int key, char *name)
{
	dbref thing, loc, look_key;

	look_key = LK_SHOWATTR | LK_SHOWEXIT;
	if(!mudconf.terse_look)
		look_key |= LK_OBEYTERSE;

	loc = Location(player);
	if(!name || !*name) {
		thing = loc;
		if(Good_obj(thing)) {
			if(key & LOOK_OUTSIDE) {
				if((Typeof(thing) == TYPE_ROOM) || Opaque(thing)) {
					notify_quiet(player, "You can't look outside.");
					return;
				}
				thing = Location(thing);
			}
			look_in(player, thing, look_key);
		}
		return;
	}
	/*
	 * Look for the target locally 
	 */

	thing = (key & LOOK_OUTSIDE) ? loc : player;
	init_match(thing, name, NOTYPE);
	match_exit_with_parents();
	match_neighbor();
	match_possession();
	if(Long_Fingers(player)) {
		match_absolute();
		match_player();
	}
	match_here();
	match_me();
	match_master_exit();
	thing = match_result();

	/*
	 * Not found locally, check possessive 
	 */

	if(!Good_obj(thing)) {
		thing =
			match_status(player, match_possessed(player,
												 ((key & LOOK_OUTSIDE) ? loc :
												  player), (char *) name,
												 thing, 0));
	}
	/*
	 * If we found something, go handle it 
	 */

	if(Good_obj(thing)) {
		switch (Typeof(thing)) {
		case TYPE_ROOM:
			look_in(player, thing, look_key);
			break;
		case TYPE_THING:
		case TYPE_PLAYER:
			look_simple(player, thing, !mudconf.terse_look);
			if(!Opaque(thing) && (!Terse(player) || mudconf.terse_contents)) {
				look_contents(player, thing, "Carrying:", CONTENTS_NESTED);
			}
			break;
		case TYPE_EXIT:
			look_simple(player, thing, !mudconf.terse_look);
			if(Transparent(thing) && (Location(thing) != NOTHING)) {
				look_key &= ~LK_SHOWATTR;
				look_in(player, Location(thing), look_key);
			}
			break;
		default:
			look_simple(player, thing, !mudconf.terse_look);
		}
	}
}

static void debug_examine(dbref player, dbref thing)
{
	dbref aowner;
	char *buf;
	int aflags, ca;
	BOOLEXP *bool;
	ATTR *attr;
	char *as, *cp;

	notify_printf(player, "Number  = %d", thing);
	if(!Good_obj(thing))
		return;

	notify_printf(player, "Name    = %s", Name(thing));
	notify_printf(player, "Location= %d", Location(thing));
	notify_printf(player, "Contents= %d", Contents(thing));
	notify_printf(player, "Exits   = %d", Exits(thing));
	notify_printf(player, "Link    = %d", Link(thing));
	notify_printf(player, "Next    = %d", Next(thing));
	notify_printf(player, "Owner   = %d", Owner(thing));
	notify_printf(player, "Pennies = %d", Pennies(thing));
	notify_printf(player, "Zone    = %d", Zone(thing));
	buf = flag_description(player, thing);
	notify_printf(player, "Flags   = %s", buf);
	free_mbuf(buf);
	buf = power_description(player, thing);
	notify_printf(player, "Powers  = %s", buf);
	free_mbuf(buf);
	buf = atr_get(thing, A_LOCK, &aowner, &aflags);
	bool = parse_boolexp(player, buf, 1);
	free_lbuf(buf);
	notify_printf(player, "Lock    = %s", unparse_boolexp(player, bool));
	free_boolexp(bool);

	buf = alloc_lbuf("debug_dexamine");
	cp = buf;
	safe_str((char *) "Attr list: ", buf, &cp);

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

		atr_get_info(thing, ca, &aowner, &aflags);
		if(Read_attr(player, thing, attr, aowner, aflags)) {
			if(attr) {			/*
								 * Valid attr. 
								 */
				safe_str((char *) attr->name, buf, &cp);
				safe_chr(' ', buf, &cp);
			} else {
				safe_str(tprintf("%d ", ca), buf, &cp);
			}
		}
	}
	*cp = '\0';
	notify(player, buf);
	free_lbuf(buf);

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

		buf = atr_get(thing, ca, &aowner, &aflags);
		if(Read_attr(player, thing, attr, aowner, aflags))
			view_atr(player, thing, attr, buf, aowner, aflags, 0);
		free_lbuf(buf);
	}
}

static void exam_wildattrs(dbref player, dbref thing, int do_parent)
{
	int atr, aflags, got_any;
	char *buf;
	dbref aowner;
	ATTR *ap;

	got_any = 0;
	for(atr = olist_first(); atr != NOTHING; atr = olist_next()) {
		ap = atr_num(atr);
		if(!ap)
			continue;

		if(do_parent && !(ap->flags & AF_PRIVATE))
			buf = atr_pget(thing, atr, &aowner, &aflags);
		else
			buf = atr_get(thing, atr, &aowner, &aflags);

		/*
		 * Decide if the player should see the attr: * If obj is * *
		 * * Examinable and has rights to see, yes. * If a player and 
		 * *  *  * * has rights to see, yes... *   except if faraway, 
		 * * * * attr=DESC, and *   remote DESC-reading is not turned 
		 * on. *  *  * *  * * If I own the attrib and have rights to
		 * see, yes... * * * * except if faraway, attr=DESC, and *
		 * remote * DESC-reading * * is not turned on. 
		 */

		if(Examinable(player, thing) &&
		   Read_attr(player, thing, ap, aowner, aflags)) {
			got_any = 1;
			view_atr(player, thing, ap, buf, aowner, aflags, 0);
		} else if((Typeof(thing) == TYPE_PLAYER) &&
				  Read_attr(player, thing, ap, aowner, aflags)) {
			got_any = 1;
			if(aowner == Owner(player)) {
				view_atr(player, thing, ap, buf, aowner, aflags, 0);
			} else if((atr == A_DESC) && (mudconf.read_rem_desc ||
										  nearby(player, thing))) {
				show_desc(player, thing, 0);
			} else if(atr != A_DESC) {
				view_atr(player, thing, ap, buf, aowner, aflags, 0);
			} else {
				notify(player, "<Too far away to get a good look>");
			}
		} else if(Read_attr(player, thing, ap, aowner, aflags)) {
			got_any = 1;
			if(aowner == Owner(player)) {
				view_atr(player, thing, ap, buf, aowner, aflags, 0);
			} else if((atr == A_DESC) && (mudconf.read_rem_desc ||
										  nearby(player, thing))) {
				show_desc(player, thing, 0);
			} else if(nearby(player, thing)) {
				view_atr(player, thing, ap, buf, aowner, aflags, 0);
			} else {
				notify(player, "<Too far away to get a good look>");
			}
		}
		free_lbuf(buf);
	}
	if(!got_any)
		notify_quiet(player, "No matching attributes found.");

}

void do_examine(dbref player, dbref cause, int key, char *name)
{
	dbref thing, content, exit, aowner, loc;
	char savec;
	char *temp, *buf, *buf2;
	BOOLEXP *bool;
	int control, aflags, do_parent;

	/*
	 * This command is pointless if the player can't hear. 
	 */

	if(!Hearer(player))
		return;

	do_parent = key & EXAM_PARENT;
	thing = NOTHING;
	if(!name || !*name) {
		if((thing = Location(player)) == NOTHING)
			return;
	} else {

		/* Check for obj/attr first */

		olist_push();
		if(parse_attrib_wild(player, name, &thing, do_parent, 1, 0)) {
			exam_wildattrs(player, thing, do_parent);
			olist_pop();
			return;
		}
		olist_pop();

		/* Look it up */

		init_match(player, name, NOTYPE);
		match_everything(MAT_EXIT_PARENTS);
		thing = noisy_match_result();
		if(!Good_obj(thing))
			return;
	}

	/*
	 * Check for the /debug switch 
	 */

	if(key == EXAM_DEBUG) {
		if(!Examinable(player, thing)) {
			notify_quiet(player, "Permission denied.");
		} else {
			debug_examine(player, thing);
		}
		return;
	}
	control = (Examinable(player, thing) || Link_exit(player, thing));

	if(control) {
		buf2 = unparse_object(player, thing, 0);
		notify(player, buf2);
		free_lbuf(buf2);
		if(mudconf.ex_flags) {
			buf2 = flag_description(player, thing);
			notify(player, buf2);
			free_mbuf(buf2);
		}
	} else {
		if((key == EXAM_DEFAULT) && !mudconf.exam_public) {
			if(mudconf.read_rem_name) {
				buf2 = alloc_lbuf("do_examine.pub_name");
				StringCopy(buf2, Name(thing));
				notify_printf(player, "%s is owned by %s", buf2,
							  Name(Owner(thing)));
				free_lbuf(buf2);
			} else {
				notify_printf(player, "Owned by %s", Name(Owner(thing)));
			}
			return;
		}
	}

	temp = alloc_lbuf("do_examine.info");

	if(control || mudconf.read_rem_desc || nearby(player, thing)) {
		temp = atr_get_str(temp, thing, A_DESC, &aowner, &aflags);
		if(*temp) {
			if(Examinable(player, thing) || (aowner == Owner(player))) {
				view_atr(player, thing, atr_num(A_DESC), temp, aowner,
						 aflags, 1);
			} else {
				show_desc(player, thing, 0);
			}
		}
	} else {
		notify(player, "<Too far away to get a good look>");
	}

	if(control) {

		/*
		 * print owner, key, and value 
		 */

		savec = mudconf.many_coins[0];
		mudconf.many_coins[0] = (islower(savec) ? toupper(savec) : savec);
		buf2 = atr_get(thing, A_LOCK, &aowner, &aflags);
		bool = parse_boolexp(player, buf2, 1);
		buf = unparse_boolexp(player, bool);
		free_boolexp(bool);
		StringCopy(buf2, Name(Owner(thing)));
		notify_printf(player, "Owner: %s  Key: %s %s: %d", buf2, buf,
					  mudconf.many_coins, Pennies(thing));
		free_lbuf(buf2);
		mudconf.many_coins[0] = savec;

		if(mudconf.have_zones) {
			buf2 = unparse_object(player, Zone(thing), 0);
			notify_printf(player, "Zone: %s", buf2);
			free_lbuf(buf2);
		}
		/*
		 * print parent 
		 */

		loc = Parent(thing);
		if(loc != NOTHING) {
			buf2 = unparse_object(player, loc, 0);
			notify_printf(player, "Parent: %s", buf2);
			free_lbuf(buf2);
		}
		buf2 = power_description(player, thing);
		notify(player, buf2);
		free_mbuf(buf2);

	}
	if(key != EXAM_BRIEF)
		look_atrs(player, thing, do_parent);

	/*
	 * show him interesting stuff 
	 */

	if(control) {

		/*
		 * Contents 
		 */

		if(Contents(thing) != NOTHING) {
			notify(player, "Contents:");
			DOLIST(content, Contents(thing)) {
				buf2 = unparse_object(player, content, 0);
				notify(player, buf2);
				free_lbuf(buf2);
			}
		}
		/*
		 * Show stuff that depends on the object type 
		 */

		switch (Typeof(thing)) {
		case TYPE_ROOM:

			/*
			 * tell him about exits 
			 */

			if(Exits(thing) != NOTHING) {
				notify(player, "Exits:");
				DOLIST(exit, Exits(thing)) {
					buf2 = unparse_object(player, exit, 0);
					notify(player, buf2);
					free_lbuf(buf2);
				}
			} else {
				notify(player, "No exits.");
			}

			/*
			 * print dropto if present 
			 */

			if(Dropto(thing) != NOTHING) {
				buf2 = unparse_object(player, Dropto(thing), 0);
				notify_printf(player, "Dropped objects go to: %s", buf2);
				free_lbuf(buf2);
			}
			break;
		case TYPE_THING:
		case TYPE_PLAYER:

			/*
			 * tell him about exits 
			 */

			if(Exits(thing) != NOTHING) {
				notify(player, "Exits:");
				DOLIST(exit, Exits(thing)) {
					buf2 = unparse_object(player, exit, 0);
					notify(player, buf2);
					free_lbuf(buf2);
				}
			} else {
				notify(player, "No exits.");
			}

			/*
			 * print home 
			 */

			loc = Home(thing);
			buf2 = unparse_object(player, loc, 0);
			notify_printf(player, "Home: %s", buf2);
			free_lbuf(buf2);

			/*
			 * print location if player can link to it 
			 */

			loc = Location(thing);
			if((Location(thing) != NOTHING) && (Examinable(player, loc) ||
												Examinable(player, thing)
												|| Linkable(player, loc))) {
				buf2 = unparse_object(player, loc, 0);
				notify_printf(player, "Location: %s", buf2);
				free_lbuf(buf2);
			}
			break;
		case TYPE_EXIT:
			buf2 = unparse_object(player, Exits(thing), 0);
			notify_printf(player, "Source: %s", buf2);
			free_lbuf(buf2);

			/*
			 * print destination 
			 */

			switch (Location(thing)) {
			case NOTHING:
				break;
			case HOME:
				notify(player, "Destination: *HOME*");
				break;
			default:
				buf2 = unparse_object(player, Location(thing), 0);
				notify_printf(player, "Destination: %s", buf2);
				free_lbuf(buf2);
				break;
			}
			break;
		default:
			break;
		}
	} else if(!Opaque(thing) && nearby(player, thing)) {
		if(Has_contents(thing))
			look_contents(player, thing, "Contents:", CONTENTS_REMOTE);
		if(Typeof(thing) != TYPE_EXIT)
			look_exits(player, thing, "Obvious exits:");
	}
	free_lbuf(temp);

	if(!control) {
		if(mudconf.read_rem_name) {
			buf2 = alloc_lbuf("do_examine.pub_name");
			StringCopy(buf2, Name(thing));
			notify_printf(player, "%s is owned by %s", buf2,
						  Name(Owner(thing)));
			free_lbuf(buf2);
		} else {
			notify_printf(player, "Owned by %s", Name(Owner(thing)));
		}
	}
}

void do_score(dbref player, dbref cause, int key)
{
	notify_printf(player, "You have %d %s.", Pennies(player),
				  (Pennies(player) ==
				   1) ? mudconf.one_coin : mudconf.many_coins);
}

void do_inventory(dbref player, dbref cause, int key)
{
	dbref thing;
	char *buff, *s, *e;

	thing = Contents(player);
	if(thing == NOTHING) {
		notify(player, "You aren't carrying anything.");
	} else {
		notify(player, "You are carrying:");
		DOLIST(thing, thing) {
			buff = unparse_object(player, thing, 1);
			notify(player, buff);
			free_lbuf(buff);
		}
	}

	thing = Exits(player);
	if(thing != NOTHING) {
		notify(player, "Exits:");
		e = buff = alloc_lbuf("look_exits");
		DOLIST(thing, thing) {
			/*
			 * chop off first exit alias to display 
			 */
			for(s = Name(thing); *s && (*s != ';'); s++)
				safe_chr(*s, buff, &e);
			safe_str((char *) "  ", buff, &e);
		}
		*e = 0;
		notify(player, buff);
		free_lbuf(buff);
	}
	do_score(player, player, 0);
}

void do_entrances(dbref player, dbref cause, int key, char *name)
{
	dbref thing, i, j;
	char *exit, *message;
	int control_thing, count, low_bound, high_bound;
	FWDLIST *fp;

	parse_range(&name, &low_bound, &high_bound);
	if(!name || !*name) {
		if(Has_location(player))
			thing = Location(player);
		else
			thing = player;
		if(!Good_obj(thing))
			return;
	} else {
		init_match(player, name, NOTYPE);
		match_everything(MAT_EXIT_PARENTS);
		thing = noisy_match_result();
		if(!Good_obj(thing))
			return;
	}

	if(!payfor(player, mudconf.searchcost)) {
		notify_printf(player, "You don't have enough %s.",
					  mudconf.many_coins);
		return;
	}
	message = alloc_lbuf("do_entrances");
	control_thing = Examinable(player, thing);
	count = 0;
	for(i = low_bound; i <= high_bound; i++) {
		if(control_thing || Examinable(player, i)) {
			switch (Typeof(i)) {
			case TYPE_EXIT:
				if(Location(i) == thing) {
					exit = unparse_object(player, Exits(i), 0);
					notify_printf(player, "%s (%s)", exit, Name(i));
					free_lbuf(exit);
					count++;
				}
				break;
			case TYPE_ROOM:
				if(Dropto(i) == thing) {
					exit = unparse_object(player, i, 0);
					notify_printf(player, "%s [dropto]", exit);
					free_lbuf(exit);
					count++;
				}
				break;
			case TYPE_THING:
			case TYPE_PLAYER:
				if(Home(i) == thing) {
					exit = unparse_object(player, i, 0);
					notify_printf(player, "%s [home]", exit);
					free_lbuf(exit);
					count++;
				}
				break;
			}

			/*
			 * Check for parents 
			 */

			if(Parent(i) == thing) {
				exit = unparse_object(player, i, 0);
				notify_printf(player, "%s [parent]", exit);
				free_lbuf(exit);
				count++;
			}
			/*
			 * Check for forwarding 
			 */

			if(H_Fwdlist(i)) {
				fp = fwdlist_get(i);
				if(!fp)
					continue;
				for(j = 0; j < fp->count; j++) {
					if(fp->data[j] != thing)
						continue;
					exit = unparse_object(player, i, 0);
					notify_printf(player, "%s [forward]", exit);
					free_lbuf(exit);
					count++;
				}
			}
		}
	}
	free_lbuf(message);
	notify_printf(player, "%d entrance%s found.", count,
				  (count == 1) ? "" : "s");
}

/*
 * check the current location for bugs 
 */

static void sweep_check(dbref player, dbref what, int key, int is_loc)
{
	dbref aowner, parent;
	int canhear, cancom, isplayer, ispuppet, isconnected, attr, aflags;
	int is_parent, lev;
	char *buf, *buf2, *bp, *as, *buff, *s;
	ATTR *ap;

	if(Dark(what) && !WizRoy(player) && !mudconf.sweep_dark)
		return;
	canhear = 0;
	cancom = 0;
	isplayer = 0;
	ispuppet = 0;
	isconnected = 0;
	is_parent = 0;

	if((key & SWEEP_LISTEN) && (((Typeof(what) == TYPE_EXIT) || is_loc) &&
								Audible(what))) {
		canhear = 1;
	} else if(key & SWEEP_LISTEN) {
		if(Monitor(what))
			buff = alloc_lbuf("Hearer");
		else
			buff = NULL;

		for(attr = atr_head(what, &as); attr; attr = atr_next(&as)) {
			if(attr == A_LISTEN) {
				canhear = 1;
				break;
			}
			if(Monitor(what)) {
				ap = atr_num(attr);
				if(!ap || (ap->flags & AF_NOPROG))
					continue;

				atr_get_str(buff, what, attr, &aowner, &aflags);

				/*
				 * Make sure we can execute it 
				 */

				if((buff[0] != AMATCH_LISTEN) || (aflags & AF_NOPROG))
					continue;

				/*
				 * Make sure there's a : in it 
				 */

				for(s = buff + 1; *s && (*s != ':'); s++);
				if(s) {
					canhear = 1;
					break;
				}
			}
		}
		if(buff)
			free_lbuf(buff);
	}
	if((key & SWEEP_COMMANDS) && (Typeof(what) != TYPE_EXIT)) {

		/*
		 * Look for commands on the object and parents too 
		 */

		ITER_PARENTS(what, parent, lev) {
			if(Commer(parent)) {
				cancom = 1;
				if(lev) {
					is_parent = 1;
					break;
				}
			}
		}
	}
	if(key & SWEEP_CONNECT) {
		if(Connected(what) || (Puppet(what) && Connected(Owner(what))) ||
		   (mudconf.player_listen && (Typeof(what) == TYPE_PLAYER) &&
			canhear && Connected(Owner(what))))
			isconnected = 1;
	}
	if(key & SWEEP_PLAYER || isconnected) {
		if(Typeof(what) == TYPE_PLAYER)
			isplayer = 1;
		if(Puppet(what))
			ispuppet = 1;
	}
	if(canhear || cancom || isplayer || ispuppet || isconnected) {
		buf = alloc_lbuf("sweep_check.types");
		bp = buf;

		if(cancom)
			safe_str((char *) "commands ", buf, &bp);
		if(canhear)
			safe_str((char *) "messages ", buf, &bp);
		if(isplayer)
			safe_str((char *) "player ", buf, &bp);
		if(ispuppet) {
			safe_str((char *) "puppet(", buf, &bp);
			safe_str(Name(Owner(what)), buf, &bp);
			safe_str((char *) ") ", buf, &bp);
		}
		if(isconnected)
			safe_str((char *) "connected ", buf, &bp);
		if(is_parent)
			safe_str((char *) "parent ", buf, &bp);
		bp[-1] = '\0';
		if(Typeof(what) != TYPE_EXIT) {
			notify_printf(player, "  %s is listening. [%s]", Name(what), buf);
		} else {
			buf2 = alloc_lbuf("sweep_check.name");
			StringCopy(buf2, Name(what));
			for(bp = buf2; *bp && (*bp != ';'); bp++);
			*bp = '\0';
			notify_printf(player, "  %s is listening. [%s]", buf2, buf);
			free_lbuf(buf2);
		}
		free_lbuf(buf);
	}
}

void do_sweep(dbref player, dbref cause, int key, char *where)
{
	dbref here, sweeploc;
	int where_key, what_key;

	where_key = key & (SWEEP_ME | SWEEP_HERE | SWEEP_EXITS);
	what_key =
		key & (SWEEP_COMMANDS | SWEEP_LISTEN | SWEEP_PLAYER | SWEEP_CONNECT);

	if(where && *where) {
		sweeploc = match_controlled(player, where);
		if(!Good_obj(sweeploc))
			return;
	} else {
		sweeploc = player;
	}

	if(!where_key)
		where_key = -1;
	if(!what_key)
		what_key = -1;
	else if(what_key == SWEEP_VERBOSE)
		what_key = SWEEP_VERBOSE | SWEEP_COMMANDS;

	/*
	 * Check my location.  If I have none or it is dark, check just me. 
	 */

	if(where_key & SWEEP_HERE) {
		notify(player, "Sweeping location...");
		if(Has_location(sweeploc)) {
			here = Location(sweeploc);
			if((here == NOTHING) || (Dark(here) && !mudconf.sweep_dark &&
									 !Examinable(player, here))) {
				notify_quiet(player,
							 "Sorry, it is dark here and you can't search for bugs");
				sweep_check(player, sweeploc, what_key, 0);
			} else {
				sweep_check(player, here, what_key, 1);
				for(here = Contents(here); here != NOTHING; here = Next(here))
					sweep_check(player, here, what_key, 0);
			}
		} else {
			sweep_check(player, sweeploc, what_key, 0);
		}
	}
	/*
	 * Check exits in my location 
	 */

	if((where_key & SWEEP_EXITS) && Has_location(sweeploc)) {
		notify(player, "Sweeping exits...");
		for(here = Exits(Location(sweeploc)); here != NOTHING;
			here = Next(here))
			sweep_check(player, here, what_key, 0);
	}
	/*
	 * Check my inventory 
	 */

	if((where_key & SWEEP_ME) && Has_contents(sweeploc)) {
		notify(player, "Sweeping inventory...");
		for(here = Contents(sweeploc); here != NOTHING; here = Next(here))
			sweep_check(player, here, what_key, 0);
	}
	/*
	 * Check carried exits 
	 */

	if((where_key & SWEEP_EXITS) && Has_exits(sweeploc)) {
		notify(player, "Sweeping carried exits...");
		for(here = Exits(sweeploc); here != NOTHING; here = Next(here))
			sweep_check(player, here, what_key, 0);
	}
	notify(player, "Sweep complete.");
}

/*
 * Output the sequence of commands needed to duplicate the specified
 * * object.  If you're moving things to another system, your milage
 * * will almost certainly vary.  (i.e. different flags, etc.)
 */

extern NAMETAB indiv_attraccess_nametab[];

void do_decomp(dbref player, dbref cause, int key, char *name, char *qual)
{
	BOOLEXP *bool;
	char *got, *thingname, *as, *ltext, *buff, *s;
	dbref aowner, thing;
	int val, aflags, ca, atr;
	ATTR *attr;
	NAMETAB *np;

	/* Check for obj/attr first */

	olist_push();
	if(parse_attrib_wild(player, name, &thing, 0, 1, 0)) {
		buff = alloc_mbuf("do_decomp.attr_name");
		thingname = alloc_lbuf("do_decomp");
		if(key & DECOMP_DBREF) {
			sprintf(thingname, "%d", (int) thing);
		} else {
			StringCopy(thingname, Name(thing));
		}
		for(atr = olist_first(); atr != NOTHING; atr = olist_next()) {
			if((atr == A_NAME || atr == A_LOCK))
				continue;
			attr = atr_num(atr);
			if(!attr)
				continue;

			got = atr_get(thing, atr, &aowner, &aflags);
			if(Read_attr(player, thing, attr, aowner, aflags)) {
				if(attr->flags & AF_IS_LOCK) {
					bool = parse_boolexp(player, got, 1);
					ltext = unparse_boolexp_decompile(player, bool);
					free_boolexp(bool);
					notify_printf(player, "@lock/%s %s=%s", attr->name,
								  strip_ansi(thingname), ltext);
				} else {
					StringCopy(buff, attr->name);
					for(s = thingname; *s; s++) {
						if(*s == EXIT_DELIMITER) {
							*s = '\0';
							break;
						}
					}
					notify_printf(player, "%c%s %s=%s",
								  ((atr < A_USER_START) ? '@' : '&'), buff,
								  strip_ansi(thingname), got);

					if(aflags & AF_LOCK) {
						notify_printf(player, "@lock %s/%s",
									  strip_ansi(thingname), buff);
					}

					for(np = indiv_attraccess_nametab; np->name; np++) {

						if((aflags & np->flag) &&
						   check_access(player, np->perm) &&
						   (!(np->perm & CA_NO_DECOMP))) {

							notify_printf(player, "@set %s/%s = %s",
										  strip_ansi(thingname), buff,
										  np->name);
						}
					}
				}
			}
			free_lbuf(got);
		}
		free_mbuf(buff);
		free_lbuf(thingname);
		olist_pop();
		return;
	}
	olist_pop();

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

	/*
	 * get result 
	 */
	if(thing == NOTHING)
		return;

	if(!Examinable(player, thing)) {
		notify_quiet(player,
					 "You can only decompile things you can examine.");
		return;
	}
	thingname = atr_get(thing, A_LOCK, &aowner, &aflags);
	bool = parse_boolexp(player, thingname, 1);

	/*
	 * Determine the name of the thing to use in reporting and then
	 * report the command to make the thing. 
	 */

	if(qual && *qual) {
		StringCopy(thingname, qual);
	} else {
		switch (Typeof(thing)) {
		case TYPE_THING:
			StringCopy(thingname, Name(thing));
			val = OBJECT_DEPOSIT(Pennies(thing));
			notify_printf(player, "@create %s=%d",
						  translate_string(thingname, 1), val);
			break;
		case TYPE_ROOM:
			StringCopy(thingname, "here");
			notify_printf(player, "@dig/teleport %s",
						  translate_string(Name(thing), 1));
			break;
		case TYPE_EXIT:
			StringCopy(thingname, Name(thing));
			notify_printf(player, "@open %s",
						  translate_string(Name(thing), 1));
			for(got = thingname; *got; got++) {
				if(*got == EXIT_DELIMITER) {
					*got = '\0';
					break;
				}
			}
			break;
		case TYPE_PLAYER:
			StringCopy(thingname, "me");
			break;
		}
	}

	/*
	 * Report the lock (if any) 
	 */

	if(bool != TRUE_BOOLEXP) {
		notify_printf(player, "@lock %s=%s", strip_ansi(thingname),
					  unparse_boolexp_decompile(player, bool));
	}
	free_boolexp(bool);

	/*
	 * Report attributes 
	 */

	buff = alloc_mbuf("do_decomp.attr_name");
	for(ca = atr_head(thing, &as); ca; ca = atr_next(&as)) {
		if((ca == A_NAME) || (ca == A_LOCK))
			continue;
		attr = atr_num(ca);
		if(!attr)
			continue;
		if((attr->flags & AF_NOCMD) && !(attr->flags & AF_IS_LOCK))
			continue;

		got = atr_get(thing, ca, &aowner, &aflags);
		if(Read_attr(player, thing, attr, aowner, aflags)) {
			if(attr->flags & AF_IS_LOCK) {
				bool = parse_boolexp(player, got, 1);
				ltext = unparse_boolexp_decompile(player, bool);
				free_boolexp(bool);
				notify_printf(player, "@lock/%s %s=%s", attr->name,
							  thingname, ltext);
			} else {
				StringCopy(buff, attr->name);
				notify_printf(player, "%c%s %s=%s",
							  ((ca < A_USER_START) ? '@' : '&'), buff,
							  strip_ansi(thingname), got);

				if(aflags & AF_LOCK) {
					notify_printf(player, "@lock %s/%s",
								  strip_ansi(thingname), buff);
				}
				for(np = indiv_attraccess_nametab; np->name; np++) {

					if((aflags & np->flag) &&
					   check_access(player, np->perm) &&
					   (!(np->perm & CA_NO_DECOMP))) {

						notify_printf(player, "@set %s/%s = %s",
									  strip_ansi(thingname), buff, np->name);
					}
				}
			}
		}
		free_lbuf(got);
	}
	free_mbuf(buff);

	decompile_flags(player, thing, thingname);
	decompile_powers(player, thing, thingname);

	/*
	 * If the object has a parent, report it 
	 */

	if(Parent(thing) != NOTHING)
		notify_printf(player, "@parent %s=#%d", strip_ansi(thingname),
					  Parent(thing));

	/*
	 * If the object has a zone, report it 
	 */
	if(Zone(thing) != NOTHING)
		notify_printf(player, "@chzone %s=#%d", strip_ansi(thingname),
					  Zone(thing));

	free_lbuf(thingname);
}