/
umud/DOC/
umud/DOC/U/
umud/DOC/U/U-examples/
umud/DOC/internals/
umud/DOC/wizard/
umud/MISC/
umud/MISC/dbchk/
umud/RWHO/rwhod/
/*
	Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/

#ifndef	lint
static	char	RCSid[] = "$Header: /home/mjr/hacks/umud/RCS/vars.c,v 1.12 92/05/17 23:32:46 mjr Exp $";
#endif

/* configure all options BEFORE including system stuff. */
#include	"config.h"

#include	<ctype.h>

#include	"mud.h"
#include	"vars.h"
#include	"sbuf.h"
#include	"match.h"

/* WARNING - globals will robinson, globals! */
char	typ_str[] =	"str";
char	typ_int[] =	"int";
char	typ_cmd[] =	"cmd";
char	typ_list[] =	"lst";
char	typ_bool[] =	"boo";
char	typ_obj[] =	"obj";
char	typ_flag[] =	"flg";
char	typ_u[] =	"U";


char	var_loc[] =	"loc";
char	var_cont[] =	"con";
char	var_xit[] =	"xit";
char	var_dest[] =	"dst";
char	var_dropto[] =	"drpto";
char	var_lock[] =	"lok";
char	var_jump[] =	"jmp";
char	var_link[] =	"lnk";
char	var_ply[] =	"ply";
char	var_owner[] =	"own";
char	var_nam[] =	"nam";
char	var_desc[] =	"desc";
char	var_text[] =	"txt";
char	var_pass[] =	"pass";
char	var_using[] =	"use";
char	var_wiz[] =	"_wz";
char	var_fail[] =	"fail";
char	var_ofail[] =	"ofail";
char	var_succ[] =	"succ";
char	var_osucc[] =	"osucc";
char	var_drop[] =	"drop";
char	var_odrop[] =	"odrop";
char	var_isplay[] =	"_pl";
char	var_isdark[] =	"dark";
char	var_isroom[] =	"_rm";
char	var_islocal[] =	"lcl";
char	var_newsart[] =	"newsarticle";
char	var_subive[] =	"subv";
char	var_Subve[] =	"Subv";
char	var_objive[] =	"objv";
char	var_Objve[] =	"Objv";
char	var_posive[] =	"posv";
char	var_Posve[] =	"Posv";
char	var_home[] =	"home";
char	var_linkmsg[] =	"linkmsg";
char	var_wearing[] =	"_wear";


#ifdef	COMBAT
char	var_strength[] =	"_stren";
char	var_Strength[] =	"_Stren";
char	var_endurance[] =	"_endur";
char	var_Endurance[] =	"_Endur";
char	var_willpower[] =	"_willp";
char	var_Willpower[] =	"_Willp";
char	var_agility[] =		"_dextr";
char	var_Agility[] =		"_Dextr";
char	var_magic[] =		"_magic";
char	var_Magic[] =		"_Magic";
char	var_action[] =		"_actup";
char	var_Action[] =		"_Actup";
char	var_power[] =		"_power";
char	var_counters[] =	"counter";
char	var_lastupd[] =		"_lupd";
char	var_lasthit[] =		"_lhit";
char	var_lastatt[] =		"_latt";
char	var_isdead[] =		"_dead";
char	var_weapon[] =		"_weapon";
/* flags */
char	var_isweapon[] = "_isweap";
char	var_isarmor[] = "_isarm";
#endif


/* system object related stuff. */
char	system_object[] =	"sysobj";
char	var_objcnt[] =		"_objcnt";
char	var_syslimbo[] =	"_syslimbo";
char	var_wizs[] =		"_wizards";
char	var_bsequence[] =	"_backupseq";


/* variable type table */
TypTab	ttab[] = {
typ_str,
typ_int,
typ_cmd,
typ_list,
typ_bool,
typ_obj,
typ_flag,
typ_u,
0
};

/* Newusers allowed flag? */
char newusers = 0;


/*
variable permissions and other whatnots table. these should be
roughly in order of preference, since "set" chooses based on first
match
*/
VarTab	vtab[] = {
var_desc,	"description",	typ_str,	VAR_LOC_PUBLIC,
	"description",

var_text,	"text",		typ_str,	VAR_LOC_PUBLIC,
	"text inscription",

var_fail,	"failure",	typ_str,	VAR_MTYP,
	"failure message/command",

var_ofail,	"ofailure",	typ_str,	VAR_MTYP,
	"other player failure message/command",

var_succ,	"success",	typ_str,	VAR_MTYP,
	"success message/command",

var_osucc,	"osuccess",	typ_str,	VAR_MTYP,
	"other player success message/command",

var_drop,	"drop",		typ_str,	VAR_MTYP,
	"drop message/command",

var_odrop,	"odrop",	typ_str,	VAR_MTYP,
	"other player drop message/command",

var_subive,	"subjective",	typ_str,	VAR_LOC_PUBLIC,
	"subjective pronoun",

var_Subve,	"Subjective",	typ_str,	VAR_LOC_PUBLIC,
	"subjective pronoun (capitalized)",

var_objive,	"objective",	typ_str,	VAR_LOC_PUBLIC,
	"objective pronoun",

var_Objve,	"Objective",	typ_str,	VAR_LOC_PUBLIC,
	"objective pronoun (capitalized)",

var_posive,	"possessive",	typ_str,	VAR_LOC_PUBLIC,
	"possessive pronoun",

var_Posve,	"Possessive",	typ_str,	VAR_LOC_PUBLIC,
	"possessive pronoun (capitalized)",


#ifdef	PLAYER_NAMECHANGING
var_nam,	"name",		typ_str,	VAR_PUBLIC,
	"name",
#else
var_nam,	"name",		typ_str,	VAR_PRIVPLY|VAR_PUBLIC,
	"name",
#endif


var_pass,	"password",	typ_str,	VAR_PRIV,
	"object's password",

var_owner,	"owners",	typ_list,	0,
	"object owner list",

var_ply,	"players",	typ_list,	VAR_LOC_PUBLIC|VAR_PRIV,
	"room player list",

var_cont,	"contents",	typ_list,	VAR_LOC_PUBLIC|VAR_PRIV,
	"contents list",

var_xit,	"exits",	typ_list,	VAR_PRIV,
	"room exit list",

var_wizs,	"wizardlist",	typ_list,	VAR_PRIV,
	"valid wizards",

var_loc,	"location",	typ_obj,	VAR_PRIV,
	"location of an object",

var_dest,	"destination",	typ_obj,	VAR_PRIV,
	"exit destination",

var_dropto,	"dropto",	typ_obj,	0,
	"dropto destination",

var_using,	"holding",	typ_obj,	VAR_PRIV,
	"object being held by player",

var_using,	"using",	typ_obj,	VAR_PRIV,
	"object being used by player",

var_home,	"home",		typ_obj,	0,
	"object's home location",

var_jump,	"jump",		typ_bool,	VAR_MTYP,
	"object access lock",

var_lock,	"lock",		typ_bool,	VAR_MTYP,
	"object access lock",

var_link,	"linkok",	typ_bool,	0,
	"link permissions",

var_isdark,	"isdark",	typ_flag,	0,
	"object is dark",

var_islocal,	"local",	typ_flag,	0,
	"object is local",

var_wiz,	"wizard",	typ_flag,	VAR_PRIV,
	"object is a wizard",

var_isplay,	"isplayer",	typ_flag,	VAR_PRIV,
	"object is a player",

var_isroom,	"isroom",	typ_flag,	VAR_PRIV,
	"object is a room",

var_newsart,	"newsarticle",	typ_int,	0,
	"last read news article",

var_linkmsg,	"linkmessage",	typ_str,	VAR_PRIV,
	"portal player moved through",

var_wearing,	"wearing",	typ_list,	VAR_PRIV,
	"player garments",

#ifdef	COMBAT
var_strength,	"strength",	typ_int,	VAR_PRIV,
	"player current strength",

var_Strength,	"Strength",	typ_int,	VAR_PRIV,
	"player maximum strength",

var_endurance,	"endurance",	typ_int,	VAR_PRIV,
	"player current endurance",

var_Endurance,	"Endurance",	typ_int,	VAR_PRIV,
	"player maximum endurance",

var_willpower,	"willpower",	typ_int,	VAR_PRIV,
	"player current willpower",

var_Willpower,	"Willpower",	typ_int,	VAR_PRIV,
	"player maximum willpower",

var_agility,	"agility",	typ_int,	VAR_PRIV,
	"player current agility",

var_Agility,	"Agility",	typ_int,	VAR_PRIV,
	"player maximum agility",

var_magic,	"magic",	typ_int,	VAR_PRIV,
	"player current magic level",

var_Magic,	"Magic",	typ_int,	VAR_PRIV,
	"player maximum magic level",

var_action,	"action",	typ_int,	VAR_PRIV,
	"player current action points",

var_Action,	"Action",	typ_int,	VAR_PRIV,
	"player maximum action points",

var_counters,	"counters",	typ_list,	0,
	"player counterattack list",

var_power,	"power",	typ_int,	VAR_PRIV,
	"player current power level",

var_lastupd,	"lastupd",	typ_str,	VAR_PRIV,
	"player last combat stats update time",

var_lasthit,	"lasthit",	typ_obj,	VAR_PRIV,
	"player last attacker that hit",

var_lastatt,	"lastatt",	typ_obj,	VAR_PRIV,
	"player last attacker",

var_isdead,	"isdead",	typ_flag,	VAR_PRIV,
	"player killed by something",

var_weapon,	"weapon",	typ_obj,	VAR_PRIV,
	"player weapon in use",

var_isweapon,	"isweapon",	typ_flag,	VAR_PRIV,
	"object is weapon flag",

var_isarmor,	"isarmor",	typ_flag,	VAR_PRIV,
	"object is armor flag",
#endif

0,		0,		0,		0,
	0
};




/* return nonzero if the variable is public */
int
var_ispublic(vn,who,aswho,what)
char	*vn;
char	*who;
char	*aswho;
char	*what;
{
	char *dst;
	int exitsees = 0;
	VarTab	*vp = vtab;

	/* If we're an exit, we can see also local_public at our dst */
	if(dst = ut_getatt(aswho,0,typ_obj,var_dest,(char *)0))
		exitsees = (!strcmp(ut_loc(what), dst));

	if(*vn == LOC_PUB_COOKIE) {
		return(!strcmp(ut_loc(who),ut_loc(what)) ||
			!strcmp(who,ut_loc(what)) ||
			!strcmp(ut_loc(who),what) || exitsees);
	}
	while(vp->vnam != (char *)0) {
		if(!strcmp(vp->vnam,vn)) {
			if(vp->flg & VAR_PUBLIC)
				return(1);
			if(vp->flg & VAR_LOC_PUBLIC) {
				if(ut_flagged(what,var_isdark))
					return(0);
				return(!strcmp(ut_loc(who),ut_loc(what)) ||
					!strcmp(who,ut_loc(what)) ||
					!strcmp(ut_loc(who),what) || exitsees);
			}
		}
		vp++;
	}
	return(0);
}




static	int
set_help(who)
char	*who;
{
	VarTab	*vp = vtab;
	TypTab	*tp = ttab;
	char	line[60];

	/* TODO - prettier format ? */
	say(who,"\nData types known to this MUD:\n",(char *)0);
	while(tp->tnam != (char *)0) {
		say(who,tp->tnam," ",(char *)0);
		tp++;
	}
	say(who,"\n\n",(char *)0);
	say(who,"Attributes known to this MUD:\n",(char *)0);
	say(who,"-long name- -(type :  shortname)-     -description-\n",(char *)0);
	while(vp->vnam != (char *)0) {
		sprintf(line,"%-13.13s(%-5.5s:%11.11s) %23.23s",
			vp->vlong,
			vp->deftyp,
			vp->vnam,
			vp->desc);
		say(who,line,(char *)0);
		if(vp->flg & VAR_PUBLIC)
			say(who," (public)",(char *)0);
		if(vp->flg & VAR_PRIV)
			say(who," (wiz-only)",(char *)0);
		if(vp->flg & VAR_MTYP)
			say(who," (multi-type)",(char *)0);
		if(vp->flg & VAR_PRIVPLY)
			say(who," (wiz-only on players)",(char *)0);
		say(who,"\n",(char *)0);
		vp++;
	}
	say(who,"\n",(char *)0);
	return(UERR_NONE);
}



VarTab	*
var_tabfind(nam)
char	*nam;
{
	VarTab	*vp = vtab;

	while(vp->vnam != (char *)0) {
		if(!strcmp(vp->vnam,nam) || !strcmp(vp->vlong,nam))
			return(vp);
		vp++;
	}
	return((VarTab *)0);
}



/* resolve a possible long-form name to short form */
char	*
var_namatch(nam)
char	*nam;
{
	VarTab	*vp;

	if((vp = var_tabfind(nam)) == (VarTab *)0)
		return((char *)0);
	return(vp->vnam);
}




/* ARGSUSED */
cmd_set(argc,argv,who,aswho)
int	argc;
char	*argv[];
char	*who;
char	*aswho;
{
	char	ob[MAXOID];
	char	*typp;
	char	*atpp;
	char	*vapp;

	if(argc == 2 && !strcmp(argv[1],"help"))
		return(set_help(who));

	if(argc < 3 || argc > 5) {
		say(who,"usage: set thing [type] attribute value\n",(char *)0);
		say(who,"or \"set help\" for help using \"set\"\n",(char *)0);
		return(UERR_ARGCNT);
	}

	if(matchlocal(who,argv[1],ut_loc(who),MTCH_UNIQ|MTCH_NONLOC|MTCH_MEOK,ob))
		return(UERR_NOMATCH);

	typp = (char *)0;
	atpp = argv[2];
	vapp = argv[3];

	/* type spec given ? */
	if(argc > 4) {
		typp = argv[2];
		atpp = argv[3];
		vapp = argv[4];
	}


	return(var_set_internal(who,aswho,ob,typp,atpp,vapp,1));
}




/*
internal set routine -
very gross!!  but all this gook has to fit someplace
called also from U-interpreter code.
*/
var_set_internal(who,aswho,ob,typp,atpp,vapp,vbose)
char	*who;
char	*aswho;
char	*ob;
char	*typp;
char	*atpp;
char	*vapp;
int	vbose;
{
	VarTab	*vp;
	int	izlist = 0;
	int	wiz;

	/* can we find a match in the variable table? */
	if((vp = var_tabfind(atpp)) != (VarTab *)0) {
			if(typp == (char *)0)
				typp = vp->deftyp;
			atpp = vp->vnam;
	}

	/* if it's not one of the known attributes, we need its type */
	if(typp == (char *)0) {
		if(vbose)
			say(who,"\"",atpp,"\" type unknown. Provide its type.\n",(char *)0);
		return(UERR_ILLASGN);
	}

	if (strlen(typp) == 0 || strlen(atpp) == 0 ||
	    index(typp, '=') != (char *) 0 || index(atpp, '=') != (char *)0) {
		if(vbose)
			say(who, "Attributes and types must be non-blank and contain no = characters.\n", (char *)0);
		return(UERR_ILLASGN);
	}

	/* is this a priv'd attribute? */
	wiz = ut_flagged(aswho,var_wiz);


	/* stamp out type clash - usually - only wizards may typeclash */
	if(vp != (VarTab *)0 && !wiz && !(vp->flg & VAR_MTYP) &&
		strcmp(typp,vp->deftyp)) {
		if(vbose)
			say(who,vp->vlong," is only a ",vp->deftyp,
				". You cannot set it to be a ",typp,".\n",(char *)0);
		return(UERR_ILLASGN);
	}


	/* priv'd attribute */
	if(vp != (VarTab *)0 && (vp->flg & VAR_PRIV) && !wiz) {
		if(vbose)
			say(who,"You must be a wizard to set ",vp->vlong,".\n",(char *)0);
		return(UERR_PERM);
	}


	/* check for wiz-only on player */
	if(vp != (VarTab *)0 && (vp->flg & VAR_PRIVPLY) && !wiz && ut_flagged(ob,var_isplay)) {
		if(vbose)
			say(who,"You must be a wizard to set ",vp->vlong," for a player.\n",(char *)0);
		return(UERR_PERM);
	}

	/* next: do we own the thang?? */
	if(!wiz && !ut_isobjown(aswho,ob)) {
		if(vbose)
			say(who,"You don't own ",ut_name(ob),".\n",(char *)0);
		return(UERR_PERM);
	}

	/* if the type is a flag, trap it here */
	if(!strcmp(typp,typ_flag)) {
		/* Special case for DARK */

		if(!wiz && !strcmp(atpp,var_isdark) && !ut_flagged(ob,var_isroom)){
			if(vbose)
				say(who,"You can't set a non-room dark!\n",(char *)0);
			return(UERR_ILLASGN);
		}
		if(ut_set(who,ob,typp,atpp,""))
			return(UERR_FATAL);
		if(vbose && run_level() == 0)
			say(who,"Set flag ",atpp,"\n",(char *)0);
		return(UERR_NONE);
	}

	/* at this point, we need another arg at least */
	if(vapp == (char *)0) {
		if(vbose)
			say(who,"Set ",typp," ",atpp," to what?\n",(char *)0);
		return(UERR_ARGCNT);
	}

	/* do not allow strings starting with '#' */
	if(!wiz && !strcmp(typp,typ_str) && vapp[0] == '#') {
		if(vbose)
			say(who,"You cannot start a string with '#'.\n",(char *)0);
		return(UERR_ILLASGN);
	}

	/* do re-writing and syntax checks on booleans */
	if(!strcmp(typp,typ_bool)) {
		Sbuf	suf;

		sbuf_initstatic(&suf);
		if(bool_rewrite(who,vapp,&suf)) {
			if(vbose)
				say(who,"Bad Boolean expression.\n",(char *)0);
			sbuf_freestatic(&suf);
			return(UERR_SYNTAX);
		}


		vapp = sbuf_buf(&suf);
		if(bool_syntax(who,vapp)) {
			sbuf_freestatic(&suf);
			return(UERR_SYNTAX);
		}
		if(ut_set(who,ob,typp,atpp,vapp)) {
			sbuf_freestatic(&suf);
			return(UERR_FATAL);
		}
		if(vbose && run_level() == 0)
			say(who,"Set ",atpp,".\n",(char *)0);
		sbuf_freestatic(&suf);
		return(UERR_NONE);
	}


	/* special case for lists and objects being set to NULL */
	izlist = !strcmp(typp,typ_list);
	if((izlist || !strcmp(typp,typ_obj)) && vapp[0] == '\0') {
		if(ut_unset(who,ob,atpp))
			return(UERR_FATAL);
		if(vbose)
			say(who,"Nulled out ",atpp,"\n",(char *)0);
		return(UERR_NONE);
	}


	/* special case for lists +thing and -thing */
	if(izlist && (vapp[0] == '+' || vapp[0] == '-')) {
		char	*thang;

		if(!strcmp("me",&vapp[1]))
			thang = aswho;
		else if(!strcmp("here",&vapp[1]))
			thang = ut_loc(who);
		else
			thang = &vapp[1];

		if(vapp[0] == '-') {
			if(ut_listdel(who,ob,atpp,thang))
				return(UERR_FATAL);
			if(vbose && run_level() == 0)
				say(who,"Dropped ",thang," from ",atpp,"\n",(char *)0);
			return(UERR_NONE);
		}

		/* Must be adding it. Special case owners list. Xtra chex.*/
		if(!strcmp(atpp,var_owner) &&
			(!ut_isgoodid(thang) || !cache_check(thang))){
			if(vbose && run_level() == 0)
				say(who,"Cannot add ",thang," to owners list.\n",(char *)0);
			return(UERR_BADOID);
		}

		/* add away */
		if(ut_listadd(who,ob,atpp,thang))
			return(UERR_FATAL);
		if(vbose && run_level() == 0)
			say(who,"Added ",thang," to ",atpp,"\n",(char *)0);
		return(UERR_NONE);
	}
	if(!wiz && izlist && vbose && run_level() == 0){
		say(who, "Use + or - to manipulate lists, please.\n",(char *)0);
		return(UERR_ILLASGN);
	}

	/* special case for droptos */
	if(!strcmp(atpp,var_dropto)){
		/* We setting this on a room? */
		if(!wiz && !ut_flagged(ob,var_isroom)){
			if(vbose)
				say(who,"Can't set a dropto on a non-room.\n",(char *)0);
			return(UERR_ILLASGN);
		}
		/* Can we link to that? */
		if(!wiz && strcmp(vapp,"home") && !ut_flagged(vapp,var_isroom)) {
			if(vbose)
				say(who,"Can't set a dropto to a non-room.\n",(char *)0);
			return(UERR_ILLASGN);
		}

		if(!wiz && strcmp(vapp,"home") && !ut_isobjown(aswho,vapp)
			&& bool_locked(aswho,vapp,ut_loc(aswho),var_link,1)) {
			if(vbose)
				say(who,"You can't link a dropto to ",vapp,".\n",(char *)0);
			return(UERR_ILLASGN);
		}
	}

	/* special case for homes */
	if(!strcmp(atpp,var_home)){
		char	hm[MAXOID];

		if(matchlocal(who,vapp,ut_loc(who),MTCH_UNIQ|MTCH_NONLOC|MTCH_MEOK,hm)){
			if(vbose)
				say(who,"I can't find ",vapp,".\n",(char *)0);
			return(UERR_NOMATCH);
		}
		/* Can we set the home to it? */
		if(!wiz &&!ut_isobjown(aswho,hm) && bool_locked(aswho,hm,ut_loc(aswho),var_link,1)) {
			if(vbose)
				say(who,"You can't set home to ",vapp,".\n",(char *)0);
			return(UERR_PERM);
		}
		if(!wiz && ut_flagged(ob,var_isplay)) {
			if(!ut_flagged(hm,var_isroom)) {
				if(vbose)
					say(who,vapp," isn't a room!\n",(char *)0);
				return(UERR_ILLASGN);
			}
		} else if (!wiz) {
			if(!ut_flagged(hm,var_isroom) && !ut_flagged(hm,var_isplay)) {
				if(vbose)
					say(who,"You can't set home to ",vapp,".\n",(char *)0);
				return(UERR_ILLASGN);
			}
		}
		if(index(hm,'@') == (char *)0){
			/* Flesh the object ID out fully */
			/* Be anal retentive about it    */
			if(strlen(hm) + strlen(mud_getname()) + 1 > MAXOID){
				if(vbose)
					say(who,"You can't set home to ",vapp,".\n",(char *)0);
				return(UERR_ILLASGN);
			}
			strcat(hm,"@");
			strcat(hm,mud_getname());
		}
		if(ut_set(who,ob,typp,atpp,hm))
			return(UERR_FATAL);
		if(vbose && run_level() == 0)
			say(who,"Set ",atpp,"\n",(char *)0);
		return(UERR_NONE);
	}


#ifdef	PLAYER_NAMECHANGING
	/* log name changes - why not ? */
	if(!wiz && !strcmp(atpp,var_nam) && ut_flagged(ob,var_isplay)) {
		if(index(vapp,'\'')||index(vapp,'\"')||index(vapp,';')) {
			if(vbose)
				say(who,"Illegal character in name.\n",(char *)0);
			return(UERR_ILLASGN);
		}
		plogf("%s changed %s name to %s\n",who,ob,vapp);
	}
#endif

	if(ut_set(who,ob,typp,atpp,vapp))
		return(UERR_FATAL);
	if(vbose && run_level() == 0)
		say(who,"Set ",atpp,"\n",(char *)0);
	return(UERR_NONE);
}





/* ARGSUSED */
cmd_unset(argc,argv,who,aswho)
int	argc;
char	*argv[];
char	*who;
char	*aswho;
{
	char	ob[MAXOID];

	if(matchlocal(who,argv[1],ut_loc(who),MTCH_UNIQ|MTCH_NONLOC|MTCH_MEOK,ob))
		return(UERR_NOMATCH);
	return(var_unset_internal(who,aswho,ob,argv[2],1));
}




var_unset_internal(who,aswho,ob,atpp,vbose)
char	*who;
char	*aswho;
char	*ob;
char	*atpp;
int	vbose;
{
	int	wiz;
	VarTab	*vp = vtab;

	while(vp->vnam != (char *)0) {
		if(!strcmp(vp->vnam,atpp))
			break;
		if(!strcmp(vp->vlong,atpp)) {
			atpp = vp->vnam;
			break;
		}
		vp++;
	}

	wiz = ut_flagged(aswho,var_wiz);
	if(vp->vnam != (char *)0 && (vp->flg & VAR_PRIV) && !wiz) {
		if(vbose)
			say(who,"You must be a wizard to unset ",vp->vlong,".\n",(char *)0);
		return(UERR_PERM);
	}


	if((vp->flg & VAR_PRIVPLY) && !wiz && ut_flagged(ob,var_isplay)) {
		if(vbose)
			say(who,"You must be a wizard to unset ",vp->vlong," for a player.\n",(char *)0);
		return(UERR_PERM);
	}
	    
	if(!wiz && !ut_isobjown(aswho,ob)) {
		if(vbose)
			say(who,"You don't own ",ut_name(ob),".\n",(char *)0);
		return(UERR_PERM);
	}

	if(ut_unset(who,ob,atpp))
		return(UERR_FATAL);
	if(vbose && run_level() == 0)
		say(who,"Unset ",atpp,"\n",(char *)0);
	return(UERR_NONE);
}





/* check if this is a known attribute and possibly */
/* get the long name (to use as a title) */
void
fndvnam(vt,buf,siz)
char	*vt;		/* the attribute */
char	*buf;		/* long name? */
int	siz;
{	
	VarTab	*vp;

	/* can we find a match in the variable table? */
	for(vp = vtab; vp->vnam != (char *)0; ++vp) {
		if(!strcmp(vp->vnam,vt)) {
			if(buf != (char *)0)
				strncpy(buf,vp->vlong,siz - 2);
			return;
		}
	}
	if(buf != (char *)0)
		strncpy(buf,vt,siz - 2);	/* gotta tell'em something... */
	buf[siz - 1] = '\0';
}



fndtyp(vt)
char	*vt;
{
	TypTab	*tp;

	for(tp = ttab; tp->tnam != (char *)0; tp++)
		if(!strcmp(vt,tp->tnam))
			return(1);
	return(0);
}