fbmuck-6.01/contrib/jresolver/
fbmuck-6.01/contrib/jresolver/org/
fbmuck-6.01/contrib/jresolver/org/fuzzball/
fbmuck-6.01/docs/devel/
fbmuck-6.01/game/
fbmuck-6.01/game/logs/
fbmuck-6.01/game/muf/
fbmuck-6.01/scripts/
fbmuck-6.01/src_docs/
/* $Header: /cvsroot/fbmuck/fbmuck/src/look.c,v 1.19 2003/06/23 00:13:48 revar Exp $ */

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

/* commands which look at things */

#include <ctype.h>
#include "db.h"
#include "tune.h"
#include "mpi.h"
#include "props.h"
#include "interface.h"
#include "match.h"
#include "dbsearch.h"
#include "externs.h"



#ifdef COMPRESS
extern const char *uncompress(const char *);

#endif							/* COMPRESS */

#define EXEC_SIGNAL '@'			/* Symbol which tells us what we're looking at
								   * is an execution order and not a message.    */

/* prints owner of something */
static void
print_owner(dbref player, dbref thing)
{
	char buf[BUFFER_LEN];

	switch (Typeof(thing)) {
	case TYPE_PLAYER:
		snprintf(buf, sizeof(buf), "%s is a player.", NAME(thing));
		break;
	case TYPE_ROOM:
	case TYPE_THING:
	case TYPE_EXIT:
	case TYPE_PROGRAM:
		snprintf(buf, sizeof(buf), "Owner: %s", NAME(OWNER(thing)));
		break;
	case TYPE_GARBAGE:
		snprintf(buf, sizeof(buf), "%s is garbage.", NAME(thing));
		break;
	}
	notify(player, buf);
}

void
exec_or_notify_prop(int descr, dbref player, dbref thing,
					const char *propname, const char *whatcalled)
{
	const char *message = get_property_class(thing, propname);
	int mpiflags = Prop_Blessed(thing, propname)? MPI_ISBLESSED : 0;

	if (message)
		exec_or_notify(descr, player, thing, message, whatcalled, mpiflags);
}

void
exec_or_notify(int descr, dbref player, dbref thing,
			   const char *message, const char *whatcalled,
			   int mpiflags)
{
	char *p;
	char *p2;
	char *p3;
	char buf[BUFFER_LEN];
	char tmpcmd[BUFFER_LEN];
	char tmparg[BUFFER_LEN];

#ifdef COMPRESS
	p = (char *) uncompress((char *) message);
#else							/* !COMPRESS */
	p = (char *) message;
#endif							/* COMPRESS */

	if (*p == EXEC_SIGNAL) {
		int i;

		if (*(++p) == REGISTERED_TOKEN) {
			strcpy(buf, p);
			for (p2 = buf; *p && !isspace(*p); p++) ;
			if (*p)
				p++;

			for (p3 = buf; *p3 && !isspace(*p3); p3++) ;
			if (*p3)
				*p3 = '\0';

			if (*p2) {
				i = (dbref) find_registered_obj(thing, p2);
			} else {
				i = 0;
			}
		} else {
			i = atoi(p);
			for (; *p && !isspace(*p); p++) ;
			if (*p)
				p++;
		}
		if (i < 0 || i >= db_top || (Typeof(i) != TYPE_PROGRAM)) {
			if (*p) {
				notify(player, p);
			} else {
				notify(player, "You see nothing special.");
			}
		} else {
			struct frame *tmpfr;

			strcpy(tmparg, match_args);
			strcpy(tmpcmd, match_cmdname);
			p = do_parse_mesg(descr, player, thing, p, whatcalled, buf, MPI_ISPRIVATE | mpiflags);
			strcpy(match_args, p);
			strcpy(match_cmdname, whatcalled);
			tmpfr = interp(descr, player, DBFETCH(player)->location, i, thing,
						   PREEMPT, STD_HARDUID, 0);
			if (tmpfr) {
				interp_loop(player, i, tmpfr, 0);
			}
			strcpy(match_args, tmparg);
			strcpy(match_cmdname, tmpcmd);
		}
	} else {
		p = do_parse_mesg(descr, player, thing, p, whatcalled, buf, MPI_ISPRIVATE | mpiflags);
		notify(player, p);
	}
}

static void
look_contents(dbref player, dbref loc, const char *contents_name)
{
	dbref thing;
	dbref can_see_loc;

	/* check to see if he can see the location */
	can_see_loc = (!Dark(loc) || controls(player, loc));

	/* check to see if there is anything there */
	DOLIST(thing, DBFETCH(loc)->contents) {
		if (can_see(player, thing, can_see_loc)) {
			/* something exists!  show him everything */
			notify(player, contents_name);
			DOLIST(thing, DBFETCH(loc)->contents) {
				if (can_see(player, thing, can_see_loc)) {
					notify(player, unparse_object(player, thing));
				}
			}
			break;				/* we're done */
		}
	}
}

static void
look_simple(int descr, dbref player, dbref thing)
{
	if (GETDESC(thing)) {
		exec_or_notify(descr, player, thing, GETDESC(thing), "(@Desc)",
				Prop_Blessed(thing, MESGPROP_DESC)? MPI_ISBLESSED : 0);
	} else {
		notify(player, "You see nothing special.");
	}
}

void
look_room(int descr, dbref player, dbref loc, int verbose)
{
	char obj_num[20];

	/* tell him the name, and the number if he can link to it */
	notify(player, unparse_object(player, loc));

	/* tell him the description */
	if (Typeof(loc) == TYPE_ROOM) {
		if (GETDESC(loc)) {
			exec_or_notify(descr, player, loc, GETDESC(loc), "(@Desc)",
				Prop_Blessed(loc, MESGPROP_DESC)? MPI_ISBLESSED : 0);
		}
		/* tell him the appropriate messages if he has the key */
		can_doit(descr, player, loc, 0);
	} else {
		if (GETIDESC(loc)) {
			exec_or_notify(descr, player, loc, GETIDESC(loc), "(@Idesc)",
				Prop_Blessed(loc, MESGPROP_IDESC)? MPI_ISBLESSED : 0);
		}
	}
	ts_useobject(loc);

	/* tell him the contents */
	look_contents(player, loc, "Contents:");
	if (tp_look_propqueues) {
		snprintf(obj_num, sizeof(obj_num), "#%d", loc);
		envpropqueue(descr, player, loc, player, loc, NOTHING, "_lookq", obj_num, 1, 1);
	}
}

void
do_look_around(int descr, dbref player)
{
	dbref loc;

	if ((loc = getloc(player)) == NOTHING)
		return;
	look_room(descr, player, loc, 1);
}

void
do_look_at(int descr, dbref player, const char *name, const char *detail)
{
	dbref thing;
	struct match_data md;
	/* int res; */
	char buf[BUFFER_LEN];
	char obj_num[20];

	if (*name == '\0' || !string_compare(name, "here")) {
		if ((thing = getloc(player)) != NOTHING) {
			look_room(descr, player, thing, 1);
		}
	} else {
		/* look at a thing here */
		init_match(descr, player, name, NOTYPE, &md);
		match_all_exits(&md);
		match_neighbor(&md);
		match_possession(&md);
		/* match_registered(&md); */
		if (Wizard(OWNER(player))) {
			match_absolute(&md);
			match_player(&md);
		}
		match_here(&md);
		match_me(&md);

		thing = match_result(&md);
		if (thing != NOTHING && thing != AMBIGUOUS && !*detail) {
			switch (Typeof(thing)) {
			case TYPE_ROOM:
				if (getloc(player) != thing && !can_link_to(player, TYPE_ROOM, thing)) {
					notify(player, "Permission denied.");
				} else {
					look_room(descr, player, thing, 1);
				}
				break;
			case TYPE_PLAYER:
				if (getloc(player) != getloc(thing)
					&& !controls(player, thing)) {
					notify(player, "Permission denied.");
				} else {
					look_simple(descr, player, thing);
					look_contents(player, thing, "Carrying:");
					if (tp_look_propqueues) {
						snprintf(obj_num, sizeof(obj_num), "#%d", thing);
						envpropqueue(descr, player, thing, player, thing,
									 NOTHING, "_lookq", obj_num, 1, 1);
					}
				}
				break;
			case TYPE_THING:
				if (getloc(player) != getloc(thing)
					&& getloc(thing) != player && !controls(player, thing)) {
					notify(player, "Permission denied.");
				} else {
					look_simple(descr, player, thing);
					if (!(FLAGS(thing) & HAVEN)) {
						look_contents(player, thing, "Contains:");
						ts_useobject(thing);
					}
					if (tp_look_propqueues) {
						snprintf(obj_num, sizeof(obj_num), "#%d", thing);
						envpropqueue(descr, player, thing, player, thing,
									 NOTHING, "_lookq", obj_num, 1, 1);
					}
				}
				break;
			default:
				look_simple(descr, player, thing);
				if (Typeof(thing) != TYPE_PROGRAM)
					ts_useobject(thing);
				if (tp_look_propqueues) {
					snprintf(obj_num, sizeof(obj_num), "#%d", thing);
					envpropqueue(descr, player, thing, player, thing,
								 NOTHING, "_lookq", obj_num, 1, 1);
				}
				break;
			}
		} else if (thing == NOTHING || (*detail && thing != AMBIGUOUS)) {
			int ambig_flag = 0;
			char propname[BUFFER_LEN];
			PropPtr propadr, pptr, lastmatch = NULL;

			if (thing == NOTHING) {
				thing = getloc(player);
				snprintf(buf, sizeof(buf), "%s", name);
			} else {
				snprintf(buf, sizeof(buf), "%s", detail);
			}

#ifdef DISKBASE
			fetchprops(thing, "/_details/");
#endif

			lastmatch = NULL;
			propadr = first_prop(thing, "_details/", &pptr, propname);
			while (propadr) {
				if (exit_prefix(propname, buf)) {
					if (lastmatch) {
						lastmatch = NULL;
						ambig_flag = 1;
						break;
					} else {
						lastmatch = propadr;
					}
				}
				propadr = next_prop(pptr, propadr, propname);
			}
			if (lastmatch && PropType(lastmatch) == PROP_STRTYP) {
#ifdef DISKBASE
				propfetch(thing, lastmatch);	/* DISKBASE PROPVALS */
#endif
				exec_or_notify(descr, player, thing, PropDataStr(lastmatch), "(@detail)",
					(PropFlags(lastmatch) & PROP_BLESSED)? MPI_ISBLESSED : 0);
			} else if (ambig_flag) {
				notify(player, AMBIGUOUS_MESSAGE);
			} else if (*detail) {
				notify(player, "You see nothing special.");
			} else {
				notify(player, NOMATCH_MESSAGE);
			}
		} else {
			notify(player, AMBIGUOUS_MESSAGE);
		}
	}
}

#ifdef VERBOSE_EXAMINE
static const char *
flag_description(dbref thing)
{
	static char buf[BUFFER_LEN];

	strcpy(buf, "Type: ");
	switch (Typeof(thing)) {
	case TYPE_ROOM:
		strcatn(buf, sizeof(buf), "ROOM");
		break;
	case TYPE_EXIT:
		strcatn(buf, sizeof(buf), "EXIT/ACTION");
		break;
	case TYPE_THING:
		strcatn(buf, sizeof(buf), "THING");
		break;
	case TYPE_PLAYER:
		strcatn(buf, sizeof(buf), "PLAYER");
		break;
	case TYPE_PROGRAM:
		strcatn(buf, sizeof(buf), "PROGRAM");
		break;
	case TYPE_GARBAGE:
		strcatn(buf, sizeof(buf), "GARBAGE");
		break;
	default:
		strcatn(buf, sizeof(buf), "***UNKNOWN TYPE***");
		break;
	}

	if (FLAGS(thing) & ~TYPE_MASK) {
		/* print flags */
		strcatn(buf, sizeof(buf), "  Flags:");
		if (FLAGS(thing) & WIZARD)
			strcatn(buf, sizeof(buf), " WIZARD");
		if (FLAGS(thing) & QUELL)
			strcatn(buf, sizeof(buf), " QUELL");
		if (FLAGS(thing) & STICKY)
			strcatn(buf, sizeof(buf), (Typeof(thing) == TYPE_PROGRAM) ? " SETUID" :
				   (Typeof(thing) == TYPE_PLAYER) ? " SILENT" : " STICKY");
		if (FLAGS(thing) & DARK)
			strcatn(buf, sizeof(buf), (Typeof(thing) != TYPE_PROGRAM) ? " DARK" : " DEBUGGING");
		if (FLAGS(thing) & LINK_OK)
			strcatn(buf, sizeof(buf), " LINK_OK");

		if (FLAGS(thing) & KILL_OK)
			strcatn(buf, sizeof(buf), " KILL_OK");

		if (MLevRaw(thing)) {
			strcatn(buf, sizeof(buf), " MUCKER");
			switch (MLevRaw(thing)) {
			case 1:
				strcatn(buf, sizeof(buf), "1");
				break;
			case 2:
				strcatn(buf, sizeof(buf), "2");
				break;
			case 3:
				strcatn(buf, sizeof(buf), "3");
				break;
			}
		}
		if (FLAGS(thing) & BUILDER)
			strcatn(buf, sizeof(buf), (Typeof(thing) == TYPE_PROGRAM) ? " BOUND" : " BUILDER");
		if (FLAGS(thing) & CHOWN_OK)
			strcatn(buf, sizeof(buf), (Typeof(thing) == TYPE_PLAYER) ? " COLOR" : " CHOWN_OK");
		if (FLAGS(thing) & JUMP_OK)
			strcatn(buf, sizeof(buf), " JUMP_OK");
		if (FLAGS(thing) & VEHICLE)
			strcatn(buf, sizeof(buf), (Typeof(thing) == TYPE_PROGRAM) ? " VIEWABLE" : " VEHICLE");

		if (FLAGS(thing) & XFORCIBLE) {
			if (Typeof(thing) == TYPE_EXIT) {
				strcatn(buf, sizeof(buf), " XPRESS");
			} else {
				strcatn(buf, sizeof(buf), " XFORCIBLE");
			}
		}
		if (FLAGS(thing) & ZOMBIE)
			strcatn(buf, sizeof(buf), " ZOMBIE");
		if (FLAGS(thing) & HAVEN)
			strcatn(buf, sizeof(buf),
			        (Typeof(thing) !=
					TYPE_PROGRAM) ? ((Typeof(thing) ==
									  TYPE_THING) ? " HIDE" : " HAVEN") : " HARDUID");
		if (FLAGS(thing) & ABODE)
			strcatn(buf, sizeof(buf),
			        (Typeof(thing) != TYPE_PROGRAM) ? (Typeof(thing) !=
													  TYPE_EXIT ? " ABODE" : " ABATE") :
				   " AUTOSTART");
	}
	return buf;
}

#endif							/* VERBOSE_EXAMINE */

int
listprops_wildcard(dbref player, dbref thing, const char *dir, const char *wild)
{
	char propname[BUFFER_LEN];
	char wld[BUFFER_LEN];
	char buf[BUFFER_LEN];
	char buf2[BUFFER_LEN];
	char *ptr, *wldcrd = wld;
	PropPtr propadr, pptr;
	int i, cnt = 0;
	int recurse = 0;

	strcpy(wld, wild);
	i = strlen(wld);
	if (i && wld[i - 1] == PROPDIR_DELIMITER)
		strcatn(wld, sizeof(wld), "*");
	for (wldcrd = wld; *wldcrd == PROPDIR_DELIMITER; wldcrd++) ;
	if (!strcmp(wldcrd, "**"))
		recurse = 1;

	for (ptr = wldcrd; *ptr && *ptr != PROPDIR_DELIMITER; ptr++) ;
	if (*ptr)
		*ptr++ = '\0';

	propadr = first_prop(thing, (char *) dir, &pptr, propname);
	while (propadr) {
		if (equalstr(wldcrd, propname)) {
			snprintf(buf, sizeof(buf), "%s%c%s", dir, PROPDIR_DELIMITER, propname);
			if (!Prop_System(buf) && ((!Prop_Hidden(buf) && !(PropFlags(propadr) & PROP_SYSPERMS))
				|| Wizard(OWNER(player)))) {
				if (!*ptr || recurse) {
					cnt++;
					displayprop(player, thing, buf, buf2, sizeof(buf2));
					notify(player, buf2);
				}
				if (recurse)
					ptr = "**";
				cnt += listprops_wildcard(player, thing, buf, ptr);
			}
		}
		propadr = next_prop(pptr, propadr, propname);
	}
	return cnt;
}


long
size_object(dbref i, int load)
{
	long byts;
	byts = sizeof(struct object);

	if (NAME(i)) {
		byts += strlen(NAME(i)) + 1;
	}
	byts += size_properties(i, load);

	if (Typeof(i) == TYPE_EXIT && DBFETCH(i)->sp.exit.dest) {
		byts += sizeof(dbref) * DBFETCH(i)->sp.exit.ndest;
	} else if (Typeof(i) == TYPE_PLAYER && PLAYER_PASSWORD(i)) {
		byts += strlen(PLAYER_PASSWORD(i)) + 1;
	} else if (Typeof(i) == TYPE_PROGRAM) {
		byts += size_prog(i);
	}
	return byts;
}


void
do_examine(int descr, dbref player, const char *name, const char *dir)
{
	dbref thing;
	char buf[BUFFER_LEN];
	dbref content;
	dbref exit;
	int i, cnt;
	struct match_data md;
	struct tm *time_tm;			/* used for timestamps */

	if (*name == '\0') {
		if ((thing = getloc(player)) == NOTHING)
			return;
	} else {
		/* look it up */
		init_match(descr, player, name, NOTYPE, &md);

		match_all_exits(&md);
		match_neighbor(&md);
		match_possession(&md);
		match_absolute(&md);
		match_registered(&md);

		/* only Wizards can examine other players */
		if (Wizard(OWNER(player)))
			match_player(&md);

		match_here(&md);
		match_me(&md);

		/* get result */
		if ((thing = noisy_match_result(&md)) == NOTHING)
			return;
	}

	if (!can_link(player, thing)) {
		print_owner(player, thing);
		return;
	}
	if (*dir) {
		/* show him the properties */
		cnt = listprops_wildcard(player, thing, "", dir);
		snprintf(buf, sizeof(buf), "%d propert%s listed.", cnt, (cnt == 1 ? "y" : "ies"));
		notify(player, buf);
		return;
	}
	switch (Typeof(thing)) {
	case TYPE_ROOM:
		snprintf(buf, sizeof(buf), "%.*s  Owner: %s  Parent: ",
				(BUFFER_LEN - strlen(NAME(OWNER(thing))) - 35),
				unparse_object(player, thing),
				NAME(OWNER(thing)));
		strcatn(buf, sizeof(buf), unparse_object(player, DBFETCH(thing)->location));
		break;
	case TYPE_THING:
		snprintf(buf, sizeof(buf), "%.*s  Owner: %s  Value: %d",
				(BUFFER_LEN - strlen(NAME(OWNER(thing))) - 35),
				unparse_object(player, thing),
				NAME(OWNER(thing)), THING_VALUE(thing));
		break;
	case TYPE_PLAYER:
		snprintf(buf, sizeof(buf), "%.*s  %s: %d  ", 
				(BUFFER_LEN - strlen(tp_cpennies) - 35),
				unparse_object(player, thing),
				tp_cpennies, PLAYER_PENNIES(thing));
		break;
	case TYPE_EXIT:
	case TYPE_PROGRAM:
		snprintf(buf, sizeof(buf), "%.*s  Owner: %s",
				(BUFFER_LEN - strlen(NAME(OWNER(thing))) - 35),
				unparse_object(player, thing),
				NAME(OWNER(thing)));
		break;
	case TYPE_GARBAGE:
		strcpy(buf, unparse_object(player, thing));
		break;
	}
	notify(player, buf);

#ifdef VERBOSE_EXAMINE
	notify(player, flag_description(thing));
#endif							/* VERBOSE_EXAMINE */

	if (GETDESC(thing))
		notify(player, GETDESC(thing));
	snprintf(buf, sizeof(buf), "Key: %s", unparse_boolexp(player, GETLOCK(thing), 1));
	notify(player, buf);

	snprintf(buf, sizeof(buf), "Chown_OK Key: %s",
			unparse_boolexp(player, get_property_lock(thing, "_/chlk"), 1));
	notify(player, buf);

	snprintf(buf, sizeof(buf), "Container Key: %s",
			unparse_boolexp(player, get_property_lock(thing, "_/clk"), 1));
	notify(player, buf);

	snprintf(buf, sizeof(buf), "Force Key: %s",
			unparse_boolexp(player, get_property_lock(thing, "@/flk"), 1));
	notify(player, buf);

	if (GETSUCC(thing)) {
		snprintf(buf, sizeof(buf), "Success: %s", GETSUCC(thing));
		notify(player, buf);
	}
	if (GETFAIL(thing)) {
		snprintf(buf, sizeof(buf), "Fail: %s", GETFAIL(thing));
		notify(player, buf);
	}
	if (GETDROP(thing)) {
		snprintf(buf, sizeof(buf), "Drop: %s", GETDROP(thing));
		notify(player, buf);
	}
	if (GETOSUCC(thing)) {
		snprintf(buf, sizeof(buf), "Osuccess: %s", GETOSUCC(thing));
		notify(player, buf);
	}
	if (GETOFAIL(thing)) {
		snprintf(buf, sizeof(buf), "Ofail: %s", GETOFAIL(thing));
		notify(player, buf);
	}
	if (GETODROP(thing)) {
		snprintf(buf, sizeof(buf), "Odrop: %s", GETODROP(thing));
		notify(player, buf);
	}

	if (tp_who_doing && GETDOING(thing)) {
		snprintf(buf, sizeof(buf), "Doing: %s", GETDOING(thing));
		notify(player, buf);
	}
	if (GETOECHO(thing)) {
		snprintf(buf, sizeof(buf), "Oecho: %s", GETOECHO(thing));
		notify(player, buf);
	}
	if (GETPECHO(thing)) {
		snprintf(buf, sizeof(buf), "Pecho: %s", GETPECHO(thing));
		notify(player, buf);
	}
	if (GETIDESC(thing)) {
		snprintf(buf, sizeof(buf), "Idesc: %s", GETIDESC(thing));
		notify(player, buf);
	}

	/* Timestamps */
	/* ex: time_tm = localtime((time_t *)(&(DBFETCH(thing)->ts.created))); */

	time_tm = localtime((&(DBFETCH(thing)->ts.created)));
	(void) format_time(buf, BUFFER_LEN, (char *) "Created:  %a %b %e %T %Z %Y", time_tm);
	notify(player, buf);
	time_tm = localtime((&(DBFETCH(thing)->ts.modified)));
	(void) format_time(buf, BUFFER_LEN, (char *) "Modified: %a %b %e %T %Z %Y", time_tm);
	notify(player, buf);
	time_tm = localtime((&(DBFETCH(thing)->ts.lastused)));
	(void) format_time(buf, BUFFER_LEN, (char *) "Lastused: %a %b %e %T %Z %Y", time_tm);
	notify(player, buf);
	if (Typeof(thing) == TYPE_PROGRAM) {
		snprintf(buf, sizeof(buf), "Usecount: %d     Instances: %d",
				DBFETCH(thing)->ts.usecount, PROGRAM_INSTANCES(thing));
	} else {
		snprintf(buf, sizeof(buf), "Usecount: %d", DBFETCH(thing)->ts.usecount);
	}
	notify(player, buf);

	notify(player, "[ Use 'examine <object>=/' to list root properties. ]");

	snprintf(buf, sizeof(buf), "Memory used: %ld bytes", size_object(thing, 1));
	notify(player, buf);

	/* show him the contents */
	if (DBFETCH(thing)->contents != NOTHING) {
		if (Typeof(thing) == TYPE_PLAYER)
			notify(player, "Carrying:");
		else
			notify(player, "Contents:");
		DOLIST(content, DBFETCH(thing)->contents) {
			notify(player, unparse_object(player, content));
		}
	}
	switch (Typeof(thing)) {
	case TYPE_ROOM:
		/* tell him about exits */
		if (DBFETCH(thing)->exits != NOTHING) {
			notify(player, "Exits:");
			DOLIST(exit, DBFETCH(thing)->exits) {
				notify(player, unparse_object(player, exit));
			}
		} else {
			notify(player, "No exits.");
		}

		/* print dropto if present */
		if (DBFETCH(thing)->sp.room.dropto != NOTHING) {
			snprintf(buf, sizeof(buf), "Dropped objects go to: %s",
					unparse_object(player, DBFETCH(thing)->sp.room.dropto));
			notify(player, buf);
		}
		break;
	case TYPE_THING:
		/* print home */
		snprintf(buf, sizeof(buf), "Home: %s", unparse_object(player, THING_HOME(thing)));	/* home */
		notify(player, buf);
		/* print location if player can link to it */
		if (DBFETCH(thing)->location != NOTHING && (controls(player, DBFETCH(thing)->location)
													|| can_link_to(player, NOTYPE,
																   DBFETCH(thing)->location))) {
			snprintf(buf, sizeof(buf), "Location: %s", unparse_object(player, DBFETCH(thing)->location));
			notify(player, buf);
		}
		/* print thing's actions, if any */
		if (DBFETCH(thing)->exits != NOTHING) {
			notify(player, "Actions/exits:");
			DOLIST(exit, DBFETCH(thing)->exits) {
				notify(player, unparse_object(player, exit));
			}
		} else {
			notify(player, "No actions attached.");
		}
		break;
	case TYPE_PLAYER:

		/* print home */
		snprintf(buf, sizeof(buf), "Home: %s", unparse_object(player, PLAYER_HOME(thing)));	/* home */
		notify(player, buf);

		/* print location if player can link to it */
		if (DBFETCH(thing)->location != NOTHING && (controls(player, DBFETCH(thing)->location)
													|| can_link_to(player, NOTYPE,
																   DBFETCH(thing)->location))) {
			snprintf(buf, sizeof(buf), "Location: %s", unparse_object(player, DBFETCH(thing)->location));
			notify(player, buf);
		}
		/* print player's actions, if any */
		if (DBFETCH(thing)->exits != NOTHING) {
			notify(player, "Actions/exits:");
			DOLIST(exit, DBFETCH(thing)->exits) {
				notify(player, unparse_object(player, exit));
			}
		} else {
			notify(player, "No actions attached.");
		}
		break;
	case TYPE_EXIT:
		if (DBFETCH(thing)->location != NOTHING) {
			snprintf(buf, sizeof(buf), "Source: %s", unparse_object(player, DBFETCH(thing)->location));
			notify(player, buf);
		}
		/* print destinations */
		if (DBFETCH(thing)->sp.exit.ndest == 0)
			break;
		for (i = 0; i < DBFETCH(thing)->sp.exit.ndest; i++) {
			switch ((DBFETCH(thing)->sp.exit.dest)[i]) {
			case NOTHING:
				break;
			case HOME:
				notify(player, "Destination: *HOME*");
				break;
			default:
				snprintf(buf, sizeof(buf), "Destination: %s",
						unparse_object(player, (DBFETCH(thing)->sp.exit.dest)[i]));
				notify(player, buf);
				break;
			}
		}
		break;
	case TYPE_PROGRAM:
		if (PROGRAM_SIZ(thing)) {
			struct timeval tv = PROGRAM_PROFTIME(thing);
			snprintf(buf, sizeof(buf), "Program compiled size: %d instructions", PROGRAM_SIZ(thing));
			notify(player, buf);
			snprintf(buf, sizeof(buf), "Cumulative runtime: %d.%06d seconds ", tv.tv_sec, tv.tv_usec);
			notify(player, buf);
		} else {
			snprintf(buf, sizeof(buf), "Program not compiled.");
			notify(player, buf);
		}

		/* print location if player can link to it */
		if (DBFETCH(thing)->location != NOTHING && (controls(player, DBFETCH(thing)->location)
													|| can_link_to(player, NOTYPE,
																   DBFETCH(thing)->location))) {
			snprintf(buf, sizeof(buf), "Location: %s", unparse_object(player, DBFETCH(thing)->location));
			notify(player, buf);
		}
		break;
	default:
		/* do nothing */
		break;
	}
}


void
do_score(dbref player)
{
	char buf[BUFFER_LEN];

	snprintf(buf, sizeof(buf), "You have %d %s.", PLAYER_PENNIES(player),
			PLAYER_PENNIES(player) == 1 ? tp_penny : tp_pennies);
	notify(player, buf);
}

void
do_inventory(dbref player)
{
	dbref thing;

	if ((thing = DBFETCH(player)->contents) == NOTHING) {
		notify(player, "You aren't carrying anything.");
	} else {
		notify(player, "You are carrying:");
		DOLIST(thing, thing) {
			notify(player, unparse_object(player, thing));
		}
	}

	do_score(player);
}

#define UPCASE(x) (toupper(x))

int
init_checkflags(dbref player, const char *flags, struct flgchkdat *check)
{
	char buf[BUFFER_LEN];
	char *cptr;
	int output_type = 0;
	int mode = 0;

	strcpy(buf, flags);
	for (cptr = buf; *cptr && (*cptr != '='); cptr++) ;
	if (*cptr == '=')
		*(cptr++) = '\0';
	flags = buf;
	while (*cptr && isspace(*cptr))
		cptr++;

	if (!*cptr) {
		output_type = 0;
	} else if (string_prefix("owners", cptr)) {
		output_type = 1;
	} else if (string_prefix("locations", cptr)) {
		output_type = 3;
	} else if (string_prefix("links", cptr)) {
		output_type = 2;
	} else if (string_prefix("count", cptr)) {
		output_type = 4;
	} else if (string_prefix("size", cptr)) {
		output_type = 5;
	} else {
		output_type = 0;
	}

	check->fortype = 0;
	check->istype = 0;
	check->isnotroom = 0;
	check->isnotexit = 0;
	check->isnotthing = 0;
	check->isnotplayer = 0;
	check->isnotprog = 0;
	check->setflags = 0;
	check->clearflags = 0;

	check->forlevel = 0;
	check->islevel = 0;
	check->isnotzero = 0;
	check->isnotone = 0;
	check->isnottwo = 0;
	check->isnotthree = 0;

	check->forlink = 0;
	check->islinked = 0;
	check->forold = 0;
	check->isold = 0;

	check->loadedsize = 0;
	check->issize = 0;
	check->size = 0;

	while (*flags) {
		switch (UPCASE(*flags)) {
		case '!':
			if (mode)
				mode = 0;
			else
				mode = 2;
			break;
		case 'R':
			if (mode) {
				check->isnotroom = 1;
			} else {
				check->fortype = 1;
				check->istype = TYPE_ROOM;
			}
			break;
		case 'T':
			if (mode) {
				check->isnotthing = 1;
			} else {
				check->fortype = 1;
				check->istype = TYPE_THING;
			}
			break;
		case 'E':
			if (mode) {
				check->isnotexit = 1;
			} else {
				check->fortype = 1;
				check->istype = TYPE_EXIT;
			}
			break;
		case 'P':
			if (mode) {
				check->isnotplayer = 1;
			} else {
				check->fortype = 1;
				check->istype = TYPE_PLAYER;
			}
			break;
		case 'F':
			if (mode) {
				check->isnotprog = 1;
			} else {
				check->fortype = 1;
				check->istype = TYPE_PROGRAM;
			}
			break;
		case '~':
		case '^':
			check->loadedsize = (Wizard(player) && *flags == '^');
			check->size = atoi(flags + 1);
			check->issize = !mode;
			while (isdigit(flags[1]))
				flags++;
			break;
		case 'U':
			check->forlink = 1;
			if (mode) {
				check->islinked = 1;
			} else {
				check->islinked = 0;
			}
			break;
		case '@':
			check->forold = 1;
			if (mode) {
				check->isold = 0;
			} else {
				check->isold = 1;
			}
			break;
		case '0':
			if (mode) {
				check->isnotzero = 1;
			} else {
				check->forlevel = 1;
				check->islevel = 0;
			}
			break;
		case '1':
			if (mode) {
				check->isnotone = 1;
			} else {
				check->forlevel = 1;
				check->islevel = 1;
			}
			break;
		case '2':
			if (mode) {
				check->isnottwo = 1;
			} else {
				check->forlevel = 1;
				check->islevel = 2;
			}
			break;
		case '3':
			if (mode) {
				check->isnotthree = 1;
			} else {
				check->forlevel = 1;
				check->islevel = 3;
			}
			break;
		case 'M':
			if (mode) {
				check->forlevel = 1;
				check->islevel = 0;
			} else {
				check->isnotzero = 1;
			}
			break;
		case 'A':
			if (mode)
				check->clearflags |= ABODE;
			else
				check->setflags |= ABODE;
			break;
		case 'B':
			if (mode)
				check->clearflags |= BUILDER;
			else
				check->setflags |= BUILDER;
			break;
		case 'C':
			if (mode)
				check->clearflags |= CHOWN_OK;
			else
				check->setflags |= CHOWN_OK;
			break;
		case 'D':
			if (mode)
				check->clearflags |= DARK;
			else
				check->setflags |= DARK;
			break;
		case 'H':
			if (mode)
				check->clearflags |= HAVEN;
			else
				check->setflags |= HAVEN;
			break;
		case 'J':
			if (mode)
				check->clearflags |= JUMP_OK;
			else
				check->setflags |= JUMP_OK;
			break;
		case 'K':
			if (mode)
				check->clearflags |= KILL_OK;
			else
				check->setflags |= KILL_OK;
			break;
		case 'L':
			if (mode)
				check->clearflags |= LINK_OK;
			else
				check->setflags |= LINK_OK;
			break;
		case 'Q':
			if (mode)
				check->clearflags |= QUELL;
			else
				check->setflags |= QUELL;
			break;
		case 'S':
			if (mode)
				check->clearflags |= STICKY;
			else
				check->setflags |= STICKY;
			break;
		case 'V':
			if (mode)
				check->clearflags |= VEHICLE;
			else
				check->setflags |= VEHICLE;
			break;
		case 'Z':
			if (mode)
				check->clearflags |= ZOMBIE;
			else
				check->setflags |= ZOMBIE;
			break;
		case 'W':
			if (mode)
				check->clearflags |= WIZARD;
			else
				check->setflags |= WIZARD;
			break;
		case 'X':
			if (mode)
				check->clearflags |= XFORCIBLE;
			else
				check->setflags |= XFORCIBLE;
			break;
		case ' ':
			if (mode)
				mode = 2;
			break;
		}
		if (mode)
			mode--;
		flags++;
	}
	return output_type;
}


int
checkflags(dbref what, struct flgchkdat check)
{
	if (check.fortype && (Typeof(what) != check.istype))
		return (0);
	if (check.isnotroom && (Typeof(what) == TYPE_ROOM))
		return (0);
	if (check.isnotexit && (Typeof(what) == TYPE_EXIT))
		return (0);
	if (check.isnotthing && (Typeof(what) == TYPE_THING))
		return (0);
	if (check.isnotplayer && (Typeof(what) == TYPE_PLAYER))
		return (0);
	if (check.isnotprog && (Typeof(what) == TYPE_PROGRAM))
		return (0);

	if (check.forlevel && (MLevRaw(what) != check.islevel))
		return (0);
	if (check.isnotzero && (MLevRaw(what) == 0))
		return (0);
	if (check.isnotone && (MLevRaw(what) == 1))
		return (0);
	if (check.isnottwo && (MLevRaw(what) == 2))
		return (0);
	if (check.isnotthree && (MLevRaw(what) == 3))
		return (0);

	if (FLAGS(what) & check.clearflags)
		return (0);
	if ((~FLAGS(what)) & check.setflags)
		return (0);

	if (check.forlink) {
		switch (Typeof(what)) {
		case TYPE_ROOM:
			if ((DBFETCH(what)->sp.room.dropto == NOTHING) != (!check.islinked))
				return (0);
			break;
		case TYPE_EXIT:
			if ((!DBFETCH(what)->sp.exit.ndest) != (!check.islinked))
				return (0);
			break;
		case TYPE_PLAYER:
		case TYPE_THING:
			if (!check.islinked)
				return (0);
			break;
		default:
			if (check.islinked)
				return (0);
		}
	}
	if (check.forold) {
		if (((((time(NULL)) - DBFETCH(what)->ts.lastused) < tp_aging_time) ||
			 (((time(NULL)) - DBFETCH(what)->ts.modified) < tp_aging_time))
			!= (!check.isold))
			return (0);
	}
	if (check.size) {
		if ((size_object(what, check.loadedsize) < check.size)
			!= (!check.issize)) {
			return 0;
		}
	}
	return (1);
}


void
display_objinfo(dbref player, dbref obj, int output_type)
{
	char buf[BUFFER_LEN];
	char buf2[BUFFER_LEN];

	strcpy(buf2, unparse_object(player, obj));

	switch (output_type) {
	case 1:					/* owners */
		snprintf(buf, sizeof(buf), "%-38.512s  %.512s", buf2, unparse_object(player, OWNER(obj)));
		break;
	case 2:					/* links */
		switch (Typeof(obj)) {
		case TYPE_ROOM:
			snprintf(buf, sizeof(buf), "%-38.512s  %.512s", buf2,
					unparse_object(player, DBFETCH(obj)->sp.room.dropto));
			break;
		case TYPE_EXIT:
			if (DBFETCH(obj)->sp.exit.ndest == 0) {
				snprintf(buf, sizeof(buf), "%-38.512s  %.512s", buf2, "*UNLINKED*");
				break;
			}
			if (DBFETCH(obj)->sp.exit.ndest > 1) {
				snprintf(buf, sizeof(buf), "%-38.512s  %.512s", buf2, "*METALINKED*");
				break;
			}
			snprintf(buf, sizeof(buf), "%-38.512s  %.512s", buf2,
					unparse_object(player, DBFETCH(obj)->sp.exit.dest[0]));
			break;
		case TYPE_PLAYER:
			snprintf(buf, sizeof(buf), "%-38.512s  %.512s", buf2, unparse_object(player, PLAYER_HOME(obj)));
			break;
		case TYPE_THING:
			snprintf(buf, sizeof(buf), "%-38.512s  %.512s", buf2, unparse_object(player, THING_HOME(obj)));
			break;
		default:
			snprintf(buf, sizeof(buf), "%-38.512s  %.512s", buf2, "N/A");
			break;
		}
		break;
	case 3:					/* locations */
		snprintf(buf, sizeof(buf), "%-38.512s  %.512s", buf2,
				unparse_object(player, DBFETCH(obj)->location));
		break;
	case 4:
		return;
	case 5:
		snprintf(buf, sizeof(buf), "%-38.512s  %ld bytes.", buf2, size_object(obj, 0));
		break;
	case 0:
	default:
		strcpy(buf, buf2);
		break;
	}
	notify(player, buf);
}


void
do_find(dbref player, const char *name, const char *flags)
{
	dbref i;
	struct flgchkdat check;
	char buf[BUFFER_LEN + 2];
	int total = 0;
	int output_type = init_checkflags(player, flags, &check);

	strcpy(buf, "*");
	strcatn(buf, sizeof(buf), name);
	strcatn(buf, sizeof(buf), "*");

	if (!payfor(player, tp_lookup_cost)) {
		notify_fmt(player, "You don't have enough %s.", tp_pennies);
	} else {
		for (i = 0; i < db_top; i++) {
			if ((Wizard(OWNER(player)) || OWNER(i) == OWNER(player)) &&
				checkflags(i, check) && NAME(i) && (!*name || equalstr(buf, (char *) NAME(i)))) {
				display_objinfo(player, i, output_type);
				total++;
			}
		}
		notify(player, "***End of List***");
		notify_fmt(player, "%d objects found.", total);
	}
}


void
do_owned(dbref player, const char *name, const char *flags)
{
	dbref victim, i;
	struct flgchkdat check;
	int total = 0;
	int output_type = init_checkflags(player, flags, &check);

	if (!payfor(player, tp_lookup_cost)) {
		notify_fmt(player, "You don't have enough %s.", tp_pennies);
		return;
	}
	if (Wizard(OWNER(player)) && *name) {
		if ((victim = lookup_player(name)) == NOTHING) {
			notify(player, "I couldn't find that player.");
			return;
		}
	} else
		victim = player;

	for (i = 0; i < db_top; i++) {
		if ((OWNER(i) == OWNER(victim)) && checkflags(i, check)) {
			display_objinfo(player, i, output_type);
			total++;
		}
	}
	notify(player, "***End of List***");
	notify_fmt(player, "%d objects found.", total);
}

void
do_trace(int descr, dbref player, const char *name, int depth)
{
	dbref thing;
	int i;
	struct match_data md;

	init_match(descr, player, name, NOTYPE, &md);
	match_absolute(&md);
	match_here(&md);
	match_me(&md);
	match_neighbor(&md);
	match_possession(&md);
	match_registered(&md);
	if ((thing = noisy_match_result(&md)) == NOTHING || thing == AMBIGUOUS)
		return;

	for (i = 0; (!depth || i < depth) && thing != NOTHING; i++) {
		if (controls(player, thing) || can_link_to(player, NOTYPE, thing))
			notify(player, unparse_object(player, thing));
		else
			notify(player, "**Missing**");
		thing = DBFETCH(thing)->location;
	}
	notify(player, "***End of List***");
}

void
do_entrances(int descr, dbref player, const char *name, const char *flags)
{
	dbref i, j;
	dbref thing;
	struct match_data md;
	struct flgchkdat check;
	int total = 0;
	int output_type = init_checkflags(player, flags, &check);

	if (*name == '\0') {
		thing = getloc(player);
	} else {
		init_match(descr, player, name, NOTYPE, &md);
		match_all_exits(&md);
		match_neighbor(&md);
		match_possession(&md);
		match_registered(&md);
		if (Wizard(OWNER(player))) {
			match_absolute(&md);
			match_player(&md);
		}
		match_here(&md);
		match_me(&md);

		thing = noisy_match_result(&md);
	}
	if (thing == NOTHING) {
		notify(player, "I don't know what object you mean.");
		return;
	}
	if (!controls(OWNER(player), thing)) {
		notify(player, "Permission denied.");
		return;
	}
	init_checkflags(player, flags, &check);
	for (i = 0; i < db_top; i++) {
		if (checkflags(i, check)) {
			switch (Typeof(i)) {
			case TYPE_EXIT:
				for (j = DBFETCH(i)->sp.exit.ndest; j--;) {
					if (DBFETCH(i)->sp.exit.dest[j] == thing) {
						display_objinfo(player, i, output_type);
						total++;
					}
				}
				break;
			case TYPE_PLAYER:
				if (PLAYER_HOME(i) == thing) {
					display_objinfo(player, i, output_type);
					total++;
				}
				break;
			case TYPE_THING:
				if (THING_HOME(i) == thing) {
					display_objinfo(player, i, output_type);
					total++;
				}
				break;
			case TYPE_ROOM:
				if (DBFETCH(i)->sp.room.dropto == thing) {
					display_objinfo(player, i, output_type);
					total++;
				}
				break;
			case TYPE_PROGRAM:
			case TYPE_GARBAGE:
				break;
			}
		}
	}
	notify(player, "***End of List***");
	notify_fmt(player, "%d objects found.", total);
}

void
do_contents(int descr, dbref player, const char *name, const char *flags)
{
	dbref i;
	dbref thing;
	struct match_data md;
	struct flgchkdat check;
	int total = 0;
	int output_type = init_checkflags(player, flags, &check);

	if (*name == '\0') {
		thing = getloc(player);
	} else {
		init_match(descr, player, name, NOTYPE, &md);
		match_me(&md);
		match_here(&md);
		match_all_exits(&md);
		match_neighbor(&md);
		match_possession(&md);
		match_registered(&md);
		if (Wizard(OWNER(player))) {
			match_absolute(&md);
			match_player(&md);
		}

		thing = noisy_match_result(&md);
	}
	if (thing == NOTHING)
		return;
	if (!controls(OWNER(player), thing)) {
		notify(player, "Permission denied.");
		return;
	}
	init_checkflags(player, flags, &check);
	DOLIST(i, DBFETCH(thing)->contents) {
		if (checkflags(i, check)) {
			display_objinfo(player, i, output_type);
			total++;
		}
	}
	switch (Typeof(thing)) {
	case TYPE_EXIT:
	case TYPE_PROGRAM:
	case TYPE_GARBAGE:
		i = NOTHING;
		break;
	case TYPE_ROOM:
	case TYPE_THING:
	case TYPE_PLAYER:
		i = DBFETCH(thing)->exits;
		break;
	}
	DOLIST(i, i) {
		if (checkflags(i, check)) {
			display_objinfo(player, i, output_type);
			total++;
		}
	}
	notify(player, "***End of List***");
	notify_fmt(player, "%d objects found.", total);
}

static int
exit_matches_name(dbref exit, const char *name, int exactMatch)
{
	char buf[BUFFER_LEN];
	char *ptr, *ptr2;

	strcpy(buf, NAME(exit));
	for (ptr2 = ptr = buf; *ptr; ptr = ptr2) {
		while (*ptr2 && *ptr2 != ';')
			ptr2++;
		if (*ptr2)
			*ptr2++ = '\0';
		while (*ptr2 == ';')
			ptr2++;
		if ((exactMatch ? !strcasecmp(name, ptr) : string_prefix(name, ptr)) &&
			DBFETCH(exit)->sp.exit.ndest &&
			Typeof((DBFETCH(exit)->sp.exit.dest)[0]) == TYPE_PROGRAM)
			return 1;
	}
	return 0;
}

int
exit_match_exists(dbref player, dbref obj, const char *name, int exactMatch)
{
	dbref exit;
	char buf[BUFFER_LEN];

	exit = DBFETCH(obj)->exits;
	while (exit != NOTHING) {
		if (exit_matches_name(exit, name, exactMatch)) {
			snprintf(buf, sizeof(buf), "  %ss are trapped on %.2048s", name, unparse_object(player, obj));
			notify(player, buf);
			return 1;
		}
		exit = DBFETCH(exit)->next;
	}
	return 0;
}

void
do_sweep(int descr, dbref player, const char *name)
{
	dbref thing, ref, loc;
	int flag, tellflag;
	struct match_data md;
	char buf[BUFFER_LEN];

	if (*name == '\0') {
		thing = getloc(player);
	} else {
		init_match(descr, player, name, NOTYPE, &md);
		match_me(&md);
		match_here(&md);
		match_all_exits(&md);
		match_neighbor(&md);
		match_possession(&md);
		match_registered(&md);
		if (Wizard(OWNER(player))) {
			match_absolute(&md);
			match_player(&md);
		}
		thing = noisy_match_result(&md);
	}
	if (thing == NOTHING) {
		notify(player, "I don't know what object you mean.");
		return;
	}

	if (*name && !controls(OWNER(player), thing)) {
		notify(player, "Permission denied.");
		return;
	}

	snprintf(buf, sizeof(buf), "Listeners in %s:", unparse_object(player, thing));
	notify(player, buf);

	ref = DBFETCH(thing)->contents;
	for (; ref != NOTHING; ref = DBFETCH(ref)->next) {
		switch (Typeof(ref)) {
		case TYPE_PLAYER:
			if (!Dark(thing) || online(ref)) {
				snprintf(buf, sizeof(buf), "  %s is a %splayer.",
						unparse_object(player, ref), online(ref) ? "" : "sleeping ");
				notify(player, buf);
			}
			break;
		case TYPE_THING:
			if (FLAGS(ref) & (ZOMBIE | LISTENER)) {
				tellflag = 0;
				snprintf(buf, sizeof(buf), "  %.255s is a", unparse_object(player, ref));
				if (FLAGS(ref) & ZOMBIE) {
					tellflag = 1;
					if (!online(OWNER(ref))) {
						tellflag = 0;
						strcatn(buf, sizeof(buf), " sleeping");
					}
					strcatn(buf, sizeof(buf), " zombie");
				}
				if ((FLAGS(ref) & LISTENER) &&
					(get_property(ref, "_listen") ||
					 get_property(ref, "~listen") || get_property(ref, "~olisten"))) {
					strcatn(buf, sizeof(buf), " listener");
					tellflag = 1;
				}
				strcatn(buf, sizeof(buf), " object owned by ");
				strcatn(buf, sizeof(buf), unparse_object(player, OWNER(ref)));
				strcatn(buf, sizeof(buf), ".");
				if (tellflag)
					notify(player, buf);
			}
			exit_match_exists(player, ref, "page", 0);
			exit_match_exists(player, ref, "whisper", 0);
			exit_match_exists(player, ref, "pose", 1) ||
				exit_match_exists(player, ref, "pos", 1) ||
				exit_match_exists(player, ref, "po", 1);
			exit_match_exists(player, ref, "say", 0);
			break;
		}
	}
	flag = 0;
	loc = thing;
	while (loc != NOTHING) {
		if (!flag) {
			notify(player, "Listening rooms down the environment:");
			flag = 1;
		}

		if ((FLAGS(loc) & LISTENER) &&
			(get_property(loc, "_listen") ||
				get_property(loc, "~listen") || get_property(loc, "~olisten"))) {
			snprintf(buf, sizeof(buf), "  %s is a listening room.", unparse_object(player, loc));
			notify(player, buf);
		}

		exit_match_exists(player, loc, "page", 0);
		exit_match_exists(player, loc, "whisper", 0);
		exit_match_exists(player, loc, "pose", 1) ||
			exit_match_exists(player, loc, "pos", 1) ||
			exit_match_exists(player, loc, "po", 1);
		exit_match_exists(player, loc, "say", 0);

		loc = getparent(loc);
	}
	notify(player, "**End of list**");
}