/
teeny/db/
teeny/dbm/
teeny/doc/
teeny/includes/
#include <stdio.h>
#include <ctype.h>

#include "teeny.h"
#include "dbm.h"

/*
Copyright(C) 1990, Andrew Molitor, All Rights Reserved.
This software may be freely used, modified, and redistributed,
as long as this copyright message is left intact, and this
software is not used to develop any commercial product, or used
in any product that is provided on a pay-for-use basis.

No warranties whatsoever. This is not guaranteed to compile, nor,
in the event that it does compile to binaries, are these binaries
guaranteed to perform any function whatsoever.
*/

/*
	Implements the other db manager commands.
*/


struct nuked {
	int obj;
	struct nuked *next;
};


int pur_handle(p,ex,req)
char *p;
atom *ex;
int *req;
{
	int i;
	int flags;
	int ptr;   /* home, dest or dropto */

	struct nuked *nuked_list = NULL;
	struct nuked *tmp,*nuked_this;

	printf("Purging.\n");

	/* Make one pass over the db killing stuff, and keeping track */
	/* of what's been killed so far.                              */

	for(i = 0; i <db_top() ; i++){
		if(exists_object(i) && eval_expr(i,ex,*req)){
			recycle_obj(i,&nuked_list);
			nuked_this = (struct nuked *)
				ty_malloc(sizeof(struct nuked),"purge");
			nuked_this->next = nuked_list;
			nuked_this->obj = i;
			nuked_list = nuked_this;
		}
	}

	/* Another pass over the DB, checking destinations, and */
	/* Handling them as best we can. Reset homes to 0 and   */
	/* simply unlink exits/rooms pointed at nuked things.   */

	for(i = 0;i < db_top() ; i++){
		if(!exists_object(i))
			continue;

		/* This depends heavily on the fact that */
		/* Destination, Home, and DropTo are all */
		/* The same element of an object.        */

		if(get_int_elt(i,DESTINATION,&ptr) == -1)
			goto dropthru;

		/* See if the destination has been nuked. */

		for(tmp = nuked_list; tmp != NULL ; tmp = tmp->next){
			if(tmp->obj == ptr)
				break;
		}
		if(tmp == NULL)
			continue;

		/* If we get here, the dest HAS been nuked. */

		if(get_int_elt(i,FLAGS,&flags) == -1)
			goto dropthru;

		switch(flags & TYPE_MASK){
		case TYP_PLAYER:
		case TYP_THING:
			if(set_int_elt(i,DESTINATION,0) == -1)
				goto dropthru;
			break;
		case TYP_ROOM:
		case TYP_EXIT:
			if(set_int_elt(i,DESTINATION,-1) == -1)
				goto dropthru;
			break;
		}
	}
	free_nuked_list(nuked_list);
	return(0);
dropthru:
	printf("Bad DB reference in 2nd pass at object %d\n",i);
	free_nuked_list(nuked_list);
	return(-1);
}

free_nuked_list(nk)
struct nuked *nk;
{
	struct nuked *tmp;

	if(nk == NULL){
		return;
	}
	do{
		tmp = nk->next;
		free((char *)nk);
		nk = tmp;
	} while(tmp != NULL);
}

int cho_handle(p,ex,req)
char *p;
atom *ex;
int *req;
{
	int i,newowner;

	while(isspace(*p)) p++;
	if(*p++ != '#'){
		printf("Invalid object number for new owner.\n");
		return(0);
	}
	newowner = atoi(p);

	printf("Chowning selected objects to #%d\n",newowner);

	for(i = 0; i < db_top() ; i++){
		if(exists_object(i) && eval_expr(i,ex,*req)){
			if(set_int_elt(i,OWNER,newowner) == -1){
				printf("Bad object ref at %d\n",i);
				return(-1);
			}
		}
	}
	return(0);
}

int sum_handle(p,ex,req)
char *p;
atom *ex;
int *req;

{
	int i;
	char *name;
	int owner;
	char *ownername;
	int flags;

	for(i = 0; i <db_top() ; i++){
		if(exists_object(i) && eval_expr(i,ex,*req)){

			/* Summarize the data for this guy */

			if(get_str_elt(i,NAME,&name) == -1){
				printf("DB error at object #%d\n",i);
				continue;
			}
			if(get_int_elt(i,OWNER,&owner) == -1){
				printf("DB error at object #%d\n",i);
				continue;
			}
			if(get_str_elt(owner,NAME,&ownername) == -1){
				printf("DB error at object #%d\n",owner);
				continue;
			}
			if(get_int_elt(i,FLAGS,&flags) == -1){
				printf("DB error at object #%d\n",i);
				continue;
			}

			/* We've got the data. Write it out. */

			printf("(#%d) Name: %s\n",i,name);
			printf("Flags: %d Owner: %s\n",flags,ownername);
		}
	}
}

/*
	First pass of recycling. This does one object.
*/

recycle_obj(obj,nuke_list)
int obj;
struct nuked **nuke_list;  /* So we can add things to it. */

{
	int loc,flags,next,list;
	struct nuked *tmp;

	if(obj == 0){
		printf("Cannot recycle object Zero.\n");
		return;
	}
	if(get_int_elt(obj,FLAGS,&flags) == -1) goto bomb;
	if(get_int_elt(obj,LOC,&loc) == -1) goto bomb;

	switch(flags & TYPE_MASK){

	case TYP_PLAYER:  /* Get the player off the contents list. */
	                  /* Otherwise it's just like a room. */
		list_drop(obj,loc,1);
	case TYP_ROOM:

		/* Destroy all the exits in room/carried by player */

		if(get_int_elt(obj,EXITS,&list) == -1) goto bomb;
		while(list != -1){
			if(get_int_elt(list,NEXT,&next) == -1) goto bomb;

			tmp = (struct nuked *) ty_malloc(sizeof(struct nuked),
				"recycle_obj");
			tmp->next = *nuke_list;
			*nuke_list = tmp;
			tmp->obj = list;

			destroy_obj(list);
			list = next;
		}

		/* Try to send room contents/player inventory home. */

		if(get_int_elt(obj,CONTENTS,&list) == -1) goto bomb;
		while(list != -1){
			if(get_int_elt(list,NEXT,&next) == -1) goto bomb;
			send_home(list,obj);
			list = next;
		}

		/* Now nuke everything left -- i.e. stuff homed here */

		if(get_int_elt(obj,CONTENTS,&list) == -1) goto bomb;
		while(list != -1){
			if(get_int_elt(list,NEXT,&next) == -1) goto bomb;

			tmp = (struct nuked *) ty_malloc(sizeof(struct nuked),
				"recycle_obj");
			tmp->next = *nuke_list;
			*nuke_list = tmp;
			tmp->obj = list;

			destroy_obj(list);
			list = next;
		}

		/* nuke the room/player itself. */

		destroy_obj(obj);
		break;
	case TYP_EXIT:
		list_drop(obj,loc,0);
		destroy_obj(obj);
		break;
	case TYP_THING:
		list_drop(obj,loc,1);
		destroy_obj(obj);
		break;
	default:
		printf("Eeek! Unknown object type!\n");
		return;
	}
	return;
bomb:
	printf("Something bad happened. Good luck.\n");
	return;
}


/*

	Utility funtions.

*/


/* Drop an object from either a contents list or an exits list */

list_drop(elt,place,code)
int elt,place,code;
{
	int current,last,next;
	int listcode;

	if(code == 1){
		listcode = CONTENTS;
	} else {
		listcode = EXITS;
	}

	if(get_int_elt(place,listcode,&current) == -1){
		warning("list_drop","bad list reference.");
		return;
	}

	last = -1;
	while(current != elt && current != -1){
		last = current;
		if(get_int_elt(current,NEXT,&current) == -1){
			warning("list_drop","bad ref inside list");
			return;
		}
	}

	/* Post Mortem. */

	/* grab the next thing on the list anyway. */

	if(get_int_elt(current,NEXT,&next) == -1){
		warning("list_drop","bad ref inside list");
		return;
	}

	if(last == -1){ /* Was 1st thing on list */
		if(set_int_elt(place,listcode,next) == -1){
			warning("list_drop","bad list reference.");
			return;
		}
	} else {
		if(set_int_elt(last,NEXT,next) == -1){
			warning("list_drop","bad list reference.");
			return;
		}
	}
}

/* Sends an object home */

send_home(obj,loc)
int obj;
int loc;
{
	int home,next;

	if(get_int_elt(obj,HOME,&home) == -1){
		warning("sendhome","could not get home");
		return;
	}
	list_drop(obj,loc,1);  /* Drop it from contents list here */

	if(!exists_object(home)){
		home = 0; /* Fake it, eh? */
	}

	if(set_int_elt(obj,LOC,home) == -1){
		warning("sendhome","could not set location");
		return;
	}
	if(get_int_elt(home,CONTENTS,&next) == -1){
		warning("sendhome","could not get contents");
		return;
	}
	if(set_int_elt(obj,NEXT,next) == -1){
		warning("sendhome","could not set next");
		return;
	}
	if(set_int_elt(home,CONTENTS,obj) == -1){
		warning("sendhome","could not set contents");
		return;
	}
}