/
umud/DOC/
umud/DOC/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.15 91/10/28 21:35:15 mjr Exp $";
#endif

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

#include	<ctype.h>

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


/* variable flags */
#define	VAR_PRIV	001	/* wiz-only can set */
#define	VAR_MTYP	002	/* can be more than one type */
#define	VAR_PRIVPLY	004	/* only wizzes can set this for players */
#define	VAR_PUBLIC	010	/* can be seen with $thing.attrib */
#define	VAR_LOC_PUBLIC	020	/* can be seen with $thing.attrib, if it's
					nearby */

#define LOC_PUB_COOKIE '+'	/* Attributes starting with this char are
					automagically LOC_PUBLIC */

/* 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	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_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";


#ifdef	COMBAT
char	var_strength[] =	"_stren";
char	var_Strength[] =	"_Stren";
char	var_endurance[] =	"_endur";
char	var_Endurance[] =	"_Endur";
char	var_willpowr[] =	"_willp";
char	var_Willpowr[] =	"_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_Power[] =		"_Power";
char	var_lastupd[] =		"_lupd";
char	var_lasthit[] =		"_lhit";
char	var_lastatt[] =		"_latt";
char	var_armor[] =		"_armor";
char	var_defend[] =		"_defend";
char	var_attack[] =		"_attack";
#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 */
static	struct	typtab	{
	char	*tnam;
} ttab[] = {
typ_str,
typ_int,
typ_cmd,
typ_list,
typ_bool,
typ_obj,
typ_flag,
0
};



/*
variable permissions and other whatnots table. these should be
roughly in order of preference, since "set" chooses based on first
match
*/
static struct	vartab	{
	char	*vnam;		/* actual attribute name */
	char	*vlong;		/* long "readable" name */
	char	*deftyp;	/* default type (unless specified) */
	int	flg;		/* various flags */
	char	*desc;		/* description of attribute */
} 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_PRIV,
	"room player list",

var_cont,	"contents",	typ_list,	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_lock,	"lock",		typ_bool,	0,
	"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",

0,		0,		0,		0,
	0
};




/* return nonzero if the variable is writeable only by The Big Guy */
int
var_ispriv(vn)
char	*vn;
{
	struct	vartab	*vp = vtab;

	/* any/all variable starting with underscore are reserved */
	if(*vn == '_')
		return(1);

	while(vp->vnam != (char *)0) {
		if(!strcmp(vp->vnam,vn))
			return((vp->flg & VAR_PRIV));
		vp++;
	}
	return(0);
}




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

	if(*vn == LOC_PUB_COOKIE){
			/* Order the checks in the 'best' way? */

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

			if(vp->flg & VAR_LOC_PUBLIC){
				/* Order the checks in the 'best' way? */

				return(!strcmp(ut_loc(who),ut_loc(what)) ||
					!strcmp(who,ut_loc(what)) ||
					!strcmp(ut_loc(who),what));
				
			}
		}
		vp++;
	}
	return(0);
}




static	int
set_help(who)
char	*who;
{
	struct	vartab	*vp = vtab;
	struct	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(0);
}




/* resolve a possible long-form name to short form */
char	*
var_namatch(nam)
char	*nam;
{
	struct	vartab	*vp = vtab;

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




/* ARGSUSED */
cmd_set(argc,argv,who,aswho)
int	argc;
char	*argv[];
char	*who;
char	*aswho;
{
	char	*typp;
	char	*atpp;
	char	*vapp;
	struct	vartab	*vp = vtab;
	char	ob[MAXOID];
	int	izlist = 0;
	int	wiz;

	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(1);
	}

	if(argc > 4) {
		typp = argv[2];
		atpp = argv[3];
		vapp = argv[4];
	} else {
		typp = (char *)0;
		atpp = argv[2];
		vapp = argv[3];
	}

	/* can we find a match in the variable table? */
	while(vp->vnam != (char *)0) {
		if(!strcmp(vp->vnam,atpp)) {
			if(typp == (char *)0)
				typp = vp->deftyp;
			break;
		}
		if(!strcmp(vp->vlong,atpp)) {
			if(typp == (char *)0)
				typp = vp->deftyp;
			atpp = vp->vnam;
			break;
		}
		vp++;
	}

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

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

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

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

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

	/* next step: what should we be setting this attribute in? */
	if(matchlocal(who,argv[1],ut_loc(who),MTCH_UNIQ|MTCH_NONLOC|MTCH_MEOK,ob))
		return(1);

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

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

	/* 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)){
			say(who,"You can't set a non-room dark!\n",(char *)0);
			return(1);
		}
		if(ut_set(who,ob,typp,atpp,""))
			return(1);
		if(run_level() == 0)
			say(who,"Set flag ",atpp,"\n",(char *)0);
		return(0);
	}

	/* at this point, we need another arg at least */
	if(argc < 4) {
		say(who,"Set ",typp," ",atpp," to what?\n",(char *)0);
		return(1);
	}

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

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

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


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


	/* 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(1);
		say(who,"Nulled out ",atpp,"\n",(char *)0);
		return(0);
	}


	/* 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(1);
			if(run_level() == 0)
				say(who,"Dropped ",thang," from ",atpp,"\n",(char *)0);
			return(0);
		}

		/* Must be adding it. Special case owners list. Xtra chex.*/

		if(!strcmp(atpp,var_owner) &&
					(!ut_isgoodid(thang) || !cache_check(thang))){
			if(run_level() == 0)
				say(who,"Cannot add ",thang," to owners list.\n",(char *)0);
			return(1);
		}

		/* add away */

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

	/* special case for droptos */

	if(!strcmp(atpp,var_dropto)){
		/* We setting this on a room? */

		if(!wiz && !ut_flagged(ob,var_isroom)){
			say(who,"Can't set a dropto on a non-room.\n",(char *)0);
			return(1);
		}
		/* Can we link to that? */

		if(!wiz && strcmp(vapp,"home") && !ut_flagged(vapp,var_isroom)){
			say(who,"Can't set a dropto to a non-room.\n",(char *)0);
			return(1);
		}

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

	/* 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)){
			say(who,"I can't find ",vapp,".\n",(char *)0);
			return(1);
		}
		/* Can we set the home to it? */

		if(!wiz &&!ut_isobjown(aswho,hm) && bool_locked(aswho,hm,ut_loc(aswho),var_link,1)){
			say(who,"You can't set home to ",vapp,".\n",(char *)0);
			return(1);
		}
		if(!wiz && ut_flagged(ob,var_isplay)){
			if(!ut_flagged(hm,var_isroom)){
				say(who,vapp," isn't a room!\n",(char *)0);
				return(1);
			}
		} else if (!wiz) {
			if(!ut_flagged(hm,var_isroom) && !ut_flagged(hm,var_isplay)){
				say(who,"You can't set home to ",vapp,".\n",(char *)0);
				return(1);
			}
		}
		if(index(hm,'@') == (char *)0){
			/* Flesh the object ID out fully */
			/* Be anal retentive about it    */

			if(strlen(hm) + strlen(mud_getname()) + 1 > MAXOID){
				say(who,"You can't set home to ",vapp,".\n",(char *)0);
				return(1);
			}
			strcat(hm,"@");
			strcat(hm,mud_getname());
		}
		if(ut_set(who,ob,typp,atpp,hm))
			return(1);
		if(run_level() == 0)
			say(who,"Set ",atpp,"\n",(char *)0);
		return(0);
	}

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





/* ARGSUSED */
cmd_unset(argc,argv,who,aswho)
int	argc;
char	*argv[];
char	*who;
char	*aswho;
{
	char	*atpp;
	struct	vartab	*vp = vtab;
	char	ob[MAXOID];
	int	wiz;

	atpp = argv[2];

	if (strlen(atpp) == 0 || index(atpp, '=') != (char *)0) {
		say(who, "Attributes must be non-blank and contain no = characters.\n", (char *)0);
		return (1);
	}
	
	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) {
		say(who,"You must be a wizard to unset ",vp->vlong,".\n",(char *)0);
		return(1);
	}


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


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

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


/* check if this is a known attribute and possibly */
/* get the long name (to use as a title) */
fndvnam(vt,buf)
char	*vt;		/* the attribute */
char	*buf;		/* long name? */
{	
	struct	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,MAXOID - 1);
			}
			return(1);
		}
	}
	if(buf != (char *)0)
		strncpy(buf,vt,MAXOID - 1);	/* gotta tell'em something... */
	return(0);
}