/
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/CMD/RCS/destroy.c,v 1.2 91/10/22 11:28:47 mjr Exp $";
#endif

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


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

static int	player_destroy();
static int	exit_destroy();
static int	room_destroy();
static int	object_destroy();

/*
Object destruction.
*/

/* ARGSUSED */
cmd_destroy(ac,av,who,aswho)
int	ac;
char	*av[];
char	*who;
char	*aswho;
{
	int	wiz;

	/* do help */
	if(ac == 2 && !strcmp(av[1],"help")) {
		say(who,av[0]," player player-obj\n",(char *)0);
		say(who,av[0]," exit exit-obj\n",(char *)0);
		say(who,av[0]," room room-obj\n",(char *)0);
		say(who,av[0]," object obj\n",(char *)0);
		return(0);
	}
		
	if( ac != 3 ) {
		say(who,"I don't understand that use of \"",av[0],"\"!\n",
		    (char *)0);
		return(1);
	}

	wiz = ut_flagged(aswho,var_wiz);

	if(!strcmp(av[1],"player"))
		return(player_destroy(who,aswho,av[2],wiz));
	else if(!strcmp(av[1],"exit"))
		return(exit_destroy(who,aswho,av[2],wiz));
	else if(!strcmp(av[1],"room"))
		return(room_destroy(who,aswho,av[2],wiz));
	else if(!strcmp(av[1],"object"))
		return(object_destroy(who,aswho,av[2],wiz));

	say(who,"I don't understand what you want me to destroy!\n",(char *)0);
	return(1);
}



/* destroy a player */
static player_destroy(who,aswho,ob,wiz)
char	*who;
char	*aswho;
char	*ob;
int	wiz;
{
	char	ply[MAXOID];
	char	*loc;
	char	*dp;
	char	nxtu[MAXOID];
	
	/* start with some checks */

	/* must be a wizard! */
	if(!wiz) {
		say(who,"Only wizards can destroy players\n",(char *)0);
		return(1);
	}

	/* find the player; unique, exact match required.  #num is OK. */
	if(matchplayers(who,ob,ut_loc(who),MTCH_UNIQ|MTCH_NONLOC,ply))
		return(1);

	/* lets make sure its a player! */
	if(!ut_flagged(ply,var_isplay)) {
		say(who,ut_name(ply)," is not a player\n",(char *)0);
		return(1);
	}

	/* can't destroy yourself */
	if(!strcmp(ply,aswho))
		/*
		 * gotos are only evil if used indiscriminately or
		 * if they branch backwards.
		 * Use for exception handling is kosher.
		 */
		goto fail;

	/* ensure that the player is logged off */
	say(ply,ut_name(who)," is destroying you.  Goodbye!\n",
	    (char *)0);
	/*
	 * note that "goodbye" must gracefully handle the
	 * player object not existing
	 */
	io_logoff(ply);

	/* ok.  fire away */

	/* remove the player from the player list of its location */
	loc = ut_loc(ply);

	/* move the objects in the players contents list to their homes */
	dp = ut_getatt(ply,0,typ_list,var_cont,(char *)0);
	if(dp != (char *)0) {
		while((dp = lstnext(dp,nxtu)) != (char *)0)
			if(home_object(who,nxtu,(char *)0,ply)) {
				goto fail;
			}
	}

	/* send the "use" object home */
	dp = ut_getatt(ply,0,typ_obj,var_using,(char *)0);
	if(dp != (char *)0 && (dp = lstnext(dp,nxtu)) != (char *)0)
		/* there is a "use" object */
		if(home_object(who,nxtu,(char *)0,ply))
			goto fail;
	
	if(ut_listdel(who,loc,var_ply,ply)) {
		plogf("destroy player %s: can't remove player from room %s\n",
		      ply,loc);
		goto fail;
	}

	/* save the name! */
	dp = ut_getatt(ply,0,typ_str,var_nam,(char *)0);
	if(dp != (char *)0) {
		strncpy(nxtu,dp,MAXOID);
		nxtu[MAXOID-1] = '\0';
	} else
		strcpy(nxtu,"An unidentifiable player");

	/* now delete the player (log and display error) */
	switch( cache_del(ply,0) ) {
	    case 1:
		/* DB couldn't delete the object */
		plogf("destroy player %s: couldn't delete the player\n",ply);
		goto fail;
	    case -1:
		/* DB not initialized */
		plogf("destroy player %s: no delete.  db not initted\n",ply);
		say(who,"couldn't delete player ",ply,"\n",(char *)0);
		goto fail;
	    case 0:
		/* either cache not initted, or object deleted ok */
		break;
	}

	plogf("player %s destroyed by %s\n",ply,who);

	/* send a message to all where they were */
	ut_roombcast(loc,(char *)0,nxtu," disintegrates before you!\n",
		     (char *)0);

	say(who,"You destroyed player ",ply,"\n",(char*)0);

	return(0);

fail:
	say(who,"Cannot destroy player ",ply,"\n",(char *)0);
	return(1);
}

static char ply_mesg[] =
	"You've been sent home as the room you were in was being destroyed\n";

/* utility routine to delete the exit */
static delete_xit(room,ex)
char	*room;
char	*ex;
{
	switch( cache_del(ex,0) ) {
	case 1:
		/* DB couldn't delete the object */
		plogf("destroy room %s: couldn't delete exit %s\n",room,ex);
		return(1);
	case 0:
		/* no problem */
		return(0);
	default:
	case -1:
		/* DB not initialized */
		plogf("destroy room %s: no delete.  db not initted\n",room);
		return(1);
	}
}




/* destroy a room */
static room_destroy(who,aswho,name,wiz)
char	*who;
char	*aswho;
char	*name;
int	wiz;
{
	char	room[MAXOID];
	char	*dp;
	char	nxtu[MAXOID];
	char	*limbo;
	
	/* start with some checks */

	/* find the room; unique, exact match required.  #num is OK.
	 *  Actually, #num is the *only* way to refer to a room */
	if(matchlocal(who,name,ut_loc(who),
		      MTCH_UNIQ|MTCH_MEOK|MTCH_NONLOC,room))
		return(1);

	/* check ownership */
	if(!wiz && !ut_isobjown(aswho,room)) {
		say(who,"You don't own ",name,"\n",(char *)0);
		return(1);
	}
		
	/* ensure the object is a room */
	if(!ut_flagged(room,var_isroom)) {
		say(who,ut_name(room)," is not a room\n",(char *)0);
		return(1);
	}

	limbo = ut_getatt(system_object,0,typ_obj,var_syslimbo,(char *)0);

	if(limbo == (char *)0) {
		plogf("destroy room %s: cannot find limbo!\n",room);
		goto fail;
	} else if(!strcmp(room,limbo)) {
		say(who,"You can't destroy the system limbo!\n",(char *)0);
		return(1);
	}
	
	
	/* send the players home */
	dp = ut_getatt(room,0,typ_list,var_ply,(char *)0);
	if(dp != (char *)0) {
		/* there are players */
		while((dp = lstnext(dp,nxtu)) != (char *)0){
			if(home_object(who,nxtu,ply_mesg,room)) {
				goto fail;
			}
			/* Do some messages, just for Moira */

			if(!ut_flagged(nxtu,var_isdark))
				ut_roombcast(ut_loc(nxtu),nxtu,ut_name(nxtu),
					" has arrived.\n",(char *)0);
			lookat(nxtu,ut_loc(nxtu),LOOK_NAME|LOOK_PLAY|LOOK_CONT);
		}
	}

	/* send the contents home */
	dp = ut_getatt(room,0,typ_list,var_cont,(char *)0);
	if(dp != (char *)0) {
		/* there are contents */
		while((dp = lstnext(dp,nxtu)) != (char *)0)
			if(home_object(who,nxtu,(char *)0,room)) {
				goto fail;
			}
	}
	
	/* destroy the exits */
	dp = ut_getatt(room,0,typ_list,var_xit,(char *)0);
	if(dp != (char *)0) {
		/* there are exits */
		while((dp = lstnext(dp,nxtu)) != (char *)0)
			/* delete the exit (log error) */
			if(delete_xit(room,nxtu)) {
				goto fail;
			} else
				/* ignore any error */
				(void)ut_listdel(who,room,var_xit,nxtu);
	}

	/* ignore error */
	(void)ut_unset(who,room,var_xit);

	/* otherwise, delete the room! */
	switch( cache_del(room,0) ) {
	    case 1:
		/* DB couldn't delete the object */
		plogf("destroy room %s: couldn't delete the room\n",room);
		goto fail;
	    case -1:
		/* DB not initialized */
		plogf("destroy room %s: no delete.  db not initted\n",room);
		goto fail;
	    case 0:
		/* either cache not initted, or object deleted ok */
		break;
	}

	say(who,"You destroyed room ",room,"\n",(char*)0);

	return(0);

fail:
	say(who,"Cannot destroy room ",room,"\n",(char*)0);
	return(1);
}

/* destroy an exit */
static exit_destroy(who,aswho,name,wiz)
char	*who;
char	*aswho;
char	*name;
int	wiz;
{
	char	ex[MAXOID];
	char	*loc;
	
	/* start with some checks */

	/* find the exit; unique match required.  #num is OK. */
	if(matchexit(who,name,ut_loc(who),MTCH_UNIQ|MTCH_NONLOC,ex))
		return(1);

	/* check ownership */
	if(!wiz && !ut_isobjown(aswho,ex)) {
		say(who,"You don't own ",name,"\n",(char *)0);
		return(1);
	}
		
	/* ensure the object is an exit */
	if(ut_getatt(ex,1,typ_obj,var_dest,(char *)0) == (char *)0) {
		say(who,ut_name(ex)," is not an exit\n",(char *)0);
		return(1);
	}

	/* where is the exit? */
	loc = ut_loc(ex);

	if(ut_listdel(who,loc,var_xit,ex)) {
		plogf("destroy exit %s: can't find in %s's xit list\n",
		      ex,loc);
		goto fail;
	}

	/* now delete the exit (log and display error) */
	switch( cache_del(ex,0) ) {
	    case 1:
		/* DB couldn't delete the object */
		plogf("destroy exit %s: couldn't delete the object\n",ex);
		goto fail;
	    case -1:
		/* DB not initialized */
		plogf("destroy exit %s: no delete.  db not initted\n",ex);
		goto fail;
	    case 0:
		/* either cache not initted, or object deleted ok */
		break;
	}

	say(who,"You destroyed exit ",ex,"\n",(char *)0);
	return(0);

fail:
	say(who,"Cannot destroy exit ",ex,"\n",(char*)0);
	return(1);
}

/* destroy a thing */
static object_destroy(who,aswho,name,wiz)
char	*who;
char	*aswho;
char	*name;
int	wiz;
{
	char	obj[MAXOID];
	char	*loc;
	char	*use;
	
	/* start with some checks */

	/* find the object; unique and exact match required.  #num is OK. */
	if(matchlocal(who,name,ut_loc(who),MTCH_UNIQ|MTCH_NONLOC,obj))
		return(1);

	/* check ownership */
	if(!wiz && !ut_isobjown(aswho,obj)) {
		say(who,"You don't own ",name,"\n",(char *)0);
		return(1);
	}
		
	/* ensure the object is not a player,room or exit */
	if(ut_flagged(obj,var_isplay) || ut_flagged(obj,var_isroom)
	   || ut_getatt(obj,1,typ_obj,var_dest,(char *)0) != (char *)0) {
		say(who,ut_name(obj)," is not an object\n",(char *)0);
		return(1);
	}

	/* where is the thing? */
	loc = ut_loc(obj);

	if(ut_flagged(loc,var_isplay) &&
	   (use = ut_getatt(loc,0,typ_obj,var_using,(char *)0))!= (char *)0
	   && !strcmp(use,obj)) {
		/* if object is used by a player, unset the using attr */
		if(ut_unset(who,loc,var_using))
			goto fail;
	} else if(ut_listdel(who,loc,var_cont,obj))
		/* if object is carried by a player or in a room,
		 * remove from contents */
		goto fail;

	/* 
	 * if objects can be inside objects, then you have to
	 * send the contents of this object home.
	 *
	 * Not currently implemented.
	 */

	/* now delete the thing (log and display error) */
	switch( cache_del(obj,0) ) {
	    case 1:
		/* DB couldn't delete the object */
		plogf("destroy object %s: couldn't delete the object\n",obj);
		goto fail;
	    case -1:
		/* DB not initialized */
		plogf("destroy object %s: no delete.  db not initted\n",obj);
		goto fail;
	    case 0:
		/* either cache not initted, or object deleted ok */
		break;
	}

	say(who,"You destroyed object ",obj,"\n",(char *)0);
	return(0);
fail:
	say(who,"Cannot destroy object ",obj,"\n",(char *)0);
	return(1);
}


static int
home_object(who,what,msg,notthere)
char	*who;
char	*what;
char	*msg;
char	*notthere;
{
	char	hm[MAXOID];
	char	*where;
	char	*dstlist;
	char	*p;

	if(!ut_home(what,hm))
		return(1);

	/* Use limbo if home == notthere */

	if(!strcmp(hm,notthere)){
		p = ut_getatt(system_object,0,typ_obj,var_syslimbo,(char *)0);
		if(p == (char *)0)
			return(1);
		strcpy(hm,p);
	}

	/* Figure out where it is, and get it out of there */

	if((where = ut_loc(what)) != (char *)0){
		if(ut_flagged(what,var_isplay)){
			/* It's a player */

			dstlist = var_ply;
			if(ut_listdel(what,where,var_ply,what))
				return(1);
		} else {
			/* It must be an object */

			dstlist = var_cont;
			if(ut_getatt(where,0,typ_obj,var_using,(char *)0) == what){
				/* Used object */

				if(ut_unset(who,where,var_using))
					return(1);
			} else {
				/* In contents list */

				if(ut_listdel(what,where,var_cont,what))
					return(1);
			}
		}
	}

	/* Put it where it's supposed to go */
	/* ignore return values and hope.   */

	(void)ut_listadd(who,hm,dstlist,what);
	(void)ut_set(who,what,typ_obj,var_loc,hm);

	/* Tell the thing */

	if(msg != (char *)0)
		say(what,msg,(char *)0);
	return(0);
}

/* Local Variables: */
/* c-indent-level: 8 */
/* c-continued-statement-offset: 8 */
/* End: */