/
umud/DOC/
umud/DOC/examples/
umud/DOC/internals/
umud/DOC/wizard/
umud/MISC/
umud/MISC/dbchk/
umud/RWHO/rwhod/
/*
	TinyMUD-like teleportation. We hope. Permissions, somewhat complex,
are handled by building up some bit vectors of things that are true about the
present situation, and then using them to verify that the teleport is legal.

*/


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


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


/* Some flags that can be set in bit vectors. For checking perms */
#define	TEL_WHAT_PLAY		0001
#define	TEL_WHAT_OBJ		0002
#define	TEL_WHAT_OWNED		0004
#define	TEL_WHAT_LINKOK		0010
#define	TEL_WHAT_ME		0020

#define TEL_TO_OWNED		0001
#define TEL_TO_LINKOK		0002
#define TEL_TO_ROOM	   	0004
#define TEL_TO_PLAY		0010
#define TEL_TO_HOME		0020
#define TEL_TO_ME		0040
#define TEL_TO_HERE		0100
#define TEL_TO_ACTOR		0200

#define TEL_FRM_OWNED		0001
#define TEL_FRM_HERE		0002
#define TEL_FRM_ME		0004
#define TEL_FRM_CONT		0010
#define TEL_FRM_PLY		0020
#define TEL_FRM_ROOM		0040
#define TEL_FRM_USED		0100

static	int		wiz;
static	int		whatflg;
static	int		fromflg;
static	int		toflg;


/* ARGSUSED */
cmd_telep(ac,av,who,aswho)
int	ac;
char	*av[];
char	*who;
char	*aswho;
{
	char	what[MAXOID];
	char	*here;
	char	*from;
	char	*to;
	char	*listvar;
	char	hm[MAXOID];

	wiz = ut_flagged(aswho,var_wiz);
	here = ut_loc(run_actor());
	whatflg = fromflg = toflg = 0;

	/* Figure out what it is we're supposed to move */
	if(matchlocal(who,av[1],here,MTCH_MEOK|MTCH_UNIQ|MTCH_QUIET,what) &&
			matchlocal(who,av[1],here,MTCH_FRST|MTCH_QUIET,what) &&
			matchlocal(who,av[1],here,MTCH_NONLOC,what)) {
		say(aswho,"I can't see any ",av[1]," here\n",(char *)0);
		return(0);
	}

	/* And where it's supposed to go */
	if(!strcmp("home",av[2])) {
		if(!ut_home(what,hm)) {
			say(aswho,"I can't figure out how to home ",av[1],".\n",(char *)0);
			return(0);
		}
		to = hm;
		toflg |= TEL_TO_HOME;
	}
	else if(!strcmp("here",av[2]))
		to = here;
	else if(!strcmp("me",av[2]))
		to = aswho;
	else if(!strcmp("actor",av[2]))
		to = run_actor();
	else
		to = av[2];

	/* Figure out where and what it is */
	from = ut_loc(what);
	if(!strcmp(here,from))
		fromflg |= TEL_FRM_HERE;

	if(!strcmp(aswho,from))
		fromflg |= TEL_FRM_ME;

	/* Figure out what sort of thing this is */
	if(!strcmp(what,aswho))
		whatflg |= TEL_WHAT_ME;

	if(ut_listchk(from,listvar = var_ply,what)) {
		whatflg |= TEL_WHAT_PLAY;
		fromflg |= TEL_FRM_PLY;
	}
	else if(ut_listchk(from,listvar = var_cont,what)) {
		whatflg |= TEL_WHAT_OBJ;
		fromflg |= TEL_FRM_CONT;
	}
	else {
		char	*used = ut_getatt(from,0,typ_obj,var_using,(char *)0);
		
		if(used != (char *)0 && !strcmp(what,used)) {
			whatflg |= TEL_WHAT_OBJ;
			fromflg |= TEL_FRM_USED;
		} else {
			say(aswho,av[1]," must be an exit or something.\n",(char *)0);
			return(0);
		}
	}

	/* Other misc stuff about the thing to 'port */
	if(ut_isobjown(aswho,what))
		whatflg |= TEL_WHAT_OWNED;

	if(!bool_locked(aswho,what,here,var_link,1))
		whatflg |= TEL_WHAT_LINKOK;

	/* Now gather up remaining fact(s) about where this is coming from */
	if(ut_isobjown(aswho,from))
		fromflg |= TEL_FRM_OWNED;

	if(ut_flagged(from,var_isroom))
		fromflg |= TEL_FRM_ROOM;

	/* Finally gather data on where it's supposed to go */
	if(ut_isobjown(aswho,to))
		toflg |= TEL_TO_OWNED;

	if(!bool_locked(aswho,to,here,var_link,1))
		toflg |= TEL_TO_LINKOK;

	if(ut_flagged(to,var_isroom))
		toflg |= TEL_TO_ROOM;

	if(ut_flagged(to,var_isplay))
		toflg |= TEL_TO_PLAY;

	if(!strcmp(aswho,to))
		toflg |= TEL_TO_ME;

	if(!strcmp(here,to))
		toflg |= TEL_TO_HERE;

	if(!strcmp(run_actor(),to))
		toflg |= TEL_TO_ACTOR;

	/* OK. Now we know everything, right? (heh. we have a headache. -mjr) */
	if(!telep_ok(aswho,to,from,what)) {
		say(aswho,"You can't do that!\n",(char *)0);
		return(0);
	}

	/* Get it out of here */
	if(fromflg & TEL_FRM_USED) {
		if(ut_unset(aswho,from,var_using)) {
			say(aswho,"Teleport failed.\n",(char *)0);
			return(0);
		}
	} else {
		if(ut_listdel(aswho,from,listvar,what)) {
			say(aswho,"Teleport failed.\n",(char *)0);
			return(0);
		}
	}

	/* Droptos DO matter */
	if(whatflg & TEL_WHAT_OBJ) {
		char	work[MAXOID]; /* Work buffer demanded by ut_dropto() */
		to = ut_dropto(what,to,work);
	}

	/* And in to there */
	if(ut_listadd(aswho,to,listvar,what)) {
		say(aswho,"Teleport failed.\n",(char *)0);
		return(0);
	}

	/* and change its location */
	if(ut_set(aswho,what,typ_obj,var_loc,to)) {
		say(aswho,"Teleport failed.\n",(char *)0);
		return(0);
	}

	/* In certain cases, deal with inventories. Send contents home, */
	/* leave used object alone. (On all non-wiz 'ports of players.  */
	if(!wiz && (whatflg & TEL_WHAT_PLAY)) {
		char	*list;
		char	next[MAXOID];
		char	ohom[MAXOID];

		list = ut_getatt(what,0,typ_list,var_cont,(char *)0);
		if(list != (char *)0) {

			while((list = lstnext(list,next)) != (char *)0) {
				if(!ut_home(next,ohom))
					continue;

				/*
				Ignore return values.
				There's *nothing* we can do
				*/
				(void)ut_listdel(aswho,what,var_cont,next);
				(void)ut_listadd(aswho,ohom,var_cont,next);
				(void)ut_set(aswho,next,typ_obj,var_loc,ohom);
			}
		}
		list = ut_getatt(what,0,typ_obj,var_using,(char *)0);
		if(list != (char *)0 && ut_home(list,ohom) && strcmp(ohom,what)) {
			(void)ut_listadd(aswho,ohom,var_cont,list);
			(void)ut_set(aswho,list,typ_obj,var_loc,ohom);
			(void)ut_unset(aswho,what,var_using);
		}
	}


	/* And now tell everyone what they need to hear */
	if((whatflg & TEL_WHAT_PLAY) && (!ut_flagged(what,var_isdark))){
		ut_roombcast(from,what,ut_name(what)," has left.\n",(char *)0);
		ut_roombcast(to,what,ut_name(what)," has arrived.\n",(char *)0);
		say(what,"You feel a wrenching sensation....\n",(char *)0);
		lookat(what,to,LOOK_NAME|LOOK_PLAY|LOOK_CONT);
	}
	say(aswho,"Teleported.\n",(char *)0);
	return(0);
}




/* It is here that we code up the teleport rules */
telep_ok(who,to,from,what)
char	*who;
char	*to;
char	*from;
char	*what;
{
	/* Wizards can send stuff anywhere thats reasonable */
	if(wiz) {
		return(((whatflg & TEL_WHAT_PLAY) &&
			(toflg & TEL_TO_ROOM)) ||
			((whatflg & TEL_WHAT_OBJ) &&
			(toflg & (TEL_TO_ROOM|TEL_TO_PLAY))));
	}
	/* Only another wiz can do this and we eliminated that possibility */
	if(ut_flagged(what,var_wiz))
		return(0);

	/* Find out about who is doing this, and check the rules */
	if(ut_flagged(who,var_isplay)) {
		if(whatflg & TEL_WHAT_PLAY) {
			if(whatflg & (TEL_WHAT_ME|TEL_WHAT_OWNED|TEL_WHAT_LINKOK)) {
				return(((toflg & TEL_TO_ROOM) &&
					(toflg & (TEL_TO_OWNED|TEL_TO_LINKOK))) ||
					(toflg & TEL_TO_HOME));
			}
			return((fromflg & TEL_FRM_HERE) &&
				(fromflg & TEL_FRM_OWNED) &&
				(toflg & TEL_TO_HOME));
		}
		
		if(whatflg & TEL_WHAT_OBJ) {
			if(whatflg & (TEL_WHAT_OWNED|TEL_WHAT_LINKOK)) {
				return((toflg & (TEL_TO_ME|TEL_TO_ACTOR)) ||
					((toflg & (TEL_TO_ROOM|TEL_TO_PLAY)) &&
					(toflg & (TEL_TO_OWNED|TEL_TO_LINKOK))) ||
					(toflg & TEL_TO_HOME));
			}

			if(((fromflg & TEL_FRM_ROOM) &&
				(fromflg & TEL_FRM_OWNED)) ||
				(fromflg & TEL_FRM_ME))
					return(toflg & TEL_TO_HOME);
		}
		return(0);
	}

	if(ut_flagged(who,var_isroom)) {
		if((whatflg & TEL_WHAT_OBJ) &&
			(whatflg & (TEL_WHAT_OWNED|TEL_WHAT_LINKOK))) {
			return((toflg & (TEL_TO_ME|TEL_TO_ACTOR)) ||
				((toflg & (TEL_TO_ROOM|TEL_TO_PLAY)) &&
				(toflg & (TEL_TO_OWNED|TEL_TO_LINKOK))) ||
				(toflg & TEL_TO_HOME));
		}
		if((whatflg & TEL_WHAT_PLAY) && (fromflg & TEL_FRM_ME)){
			return((toflg & TEL_TO_HOME) ||
				((whatflg & (TEL_WHAT_OWNED|TEL_WHAT_LINKOK))&&
				(toflg & (TEL_TO_OWNED|TEL_TO_LINKOK)))
			);
		}
		return(0);
	}

	/* Must be an exit or a thing */
	if(lstlook(ut_getatt(who,0,typ_list,var_loc,var_xit,(char *)0),who)) {
		if((whatflg & TEL_WHAT_OBJ) &&
			(whatflg & (TEL_WHAT_OWNED|TEL_WHAT_LINKOK))) {
			return(((toflg & (TEL_TO_ROOM|TEL_TO_PLAY)) &&
				(toflg & (TEL_TO_OWNED|TEL_TO_LINKOK))) ||
				(toflg & TEL_TO_HOME));
		}
		return(0);
	}

	/* Must be a thing. We hope so, anyway. */
	if((whatflg & TEL_WHAT_PLAY) &&	!strcmp(run_actor(),what)) {
		return(((toflg & TEL_TO_ROOM) &&
			(toflg & (TEL_TO_OWNED|TEL_TO_LINKOK))) ||
			(toflg & TEL_TO_HOME));
	}

	if((whatflg & TEL_WHAT_OBJ) &&
		(whatflg & (TEL_WHAT_ME|TEL_WHAT_OWNED|TEL_WHAT_LINKOK))) {
		return((toflg & TEL_TO_ACTOR) ||
			((toflg & (TEL_TO_ROOM|TEL_TO_PLAY)) &&
			(toflg & (TEL_TO_OWNED|TEL_TO_LINKOK))) ||
			(toflg & TEL_TO_HOME));
	}
	return(0);
}