/*
 * OBJECT.C:
 *
 *	Routines that deal with objects and items.
 *
 *	Copyright (C) 1991, 1992, 1993 Brett J. Vickers
 *
 */

#include "mstruct.h"
#include "mextern.h"
#ifdef DMALLOC
  #include "/usr/local/include/dmalloc.h"
#endif

/**********************************************************************/
/*				add_obj_obj			      */
/**********************************************************************/

/* This function adds the object pointed to by the first parameter to  */
/* the contents of the object pointed to by the second parameter.  It  */
/* is done alphabetically.					       */

void add_obj_obj(obj_ptr1, obj_ptr2)
object	*obj_ptr1;
object	*obj_ptr2;
{
	otag	*op, *temp, *prev;

	obj_ptr1->parent_obj = obj_ptr2;
	obj_ptr1->parent_crt = 0;
	obj_ptr1->parent_rom = 0;

	op = (otag *)malloc(sizeof(otag));
	if(!op)
		merror("add_obj_obj", FATAL);
	op->obj = obj_ptr1;
	op->next_tag = 0;

	if(!obj_ptr2->first_obj) {
		obj_ptr2->first_obj = op;
		return;
	}

	temp = obj_ptr2->first_obj;
	if(strcmp(temp->obj->name, obj_ptr1->name) > 0 ||
	   (!strcmp(temp->obj->name, obj_ptr1->name) &&
	   temp->obj->adjustment > obj_ptr1->adjustment)) {
		op->next_tag = temp;
		obj_ptr2->first_obj = op;
		return;
	}

	while(temp) {
		if(strcmp(temp->obj->name, obj_ptr1->name) > 0 ||
		   (!strcmp(temp->obj->name, obj_ptr1->name) &&
		   temp->obj->adjustment > obj_ptr1->adjustment))
			break;
		prev = temp;
		temp = temp->next_tag;
	}
	op->next_tag = prev->next_tag;
	prev->next_tag = op;

}

/**********************************************************************/
/*				del_obj_obj			      */
/**********************************************************************/

/* This function removes the object pointed to by the first parameter */
/* from the object pointed to by the second.			      */

void del_obj_obj(obj_ptr1, obj_ptr2)
object	*obj_ptr1;
object	*obj_ptr2;
{
	otag 	*temp, *prev;

	obj_ptr1->parent_crt = 0;
	if(obj_ptr2->first_obj->obj == obj_ptr1) {
		temp = obj_ptr2->first_obj->next_tag;
		free(obj_ptr2->first_obj);
		obj_ptr2->first_obj = temp;
		return;
	}

	prev = obj_ptr2->first_obj;
	temp = prev->next_tag;
	while(temp) {
		if(temp->obj == obj_ptr1) {
			prev->next_tag = temp->next_tag;
			free(temp);
			return;
		}
		prev = temp;
		temp = temp->next_tag;
	}
}

/**********************************************************************/
/*				find_obj			      */
/**********************************************************************/

/* This function is used to search through a room's, creature's or	*/
/* object's inventory in order to look for a particular item.  The	*/
/* first parameter contains a pointer to the creature who is doing the	*/
/* search.  The second is a pointer to the first object tag in the 	*/
/* list to be searched.  The third parameter is a string that contains	*/
/* the name of the object being searched for.  The last parameter 	*/
/* contains the version of the string being searched for.		*/

object *find_obj(ply_ptr, first_ot, str, val)
creature	*ply_ptr;
otag		*first_ot;
char		*str;
int		val;
{
	otag	*op;
	int	match=0, found=0;

	if(!first_ot)
		return(0);
	op = first_ot;
	while(op) {
		if(EQUAL(op->obj, str) &&
		   (F_ISSET(ply_ptr, PDINVI) ?
		   1:!F_ISSET(op->obj, OINVIS))) {
			match++;
			if(match == val) {
				found = 1;
				break;
			}
		}
		op = op->next_tag;
	}

	if(found)
		return(op->obj);
	else
		return(0);
}

/**********************************************************************/
/*				list_obj			      */
/**********************************************************************/

/* This function produces a string which lists all the objects in a	*/
/* player's, room's or object's inventory.  The first parameter holds	*/
/* a pointer to the string which will be produced.  The second is a	*/
/* pointer to the player who is having the list produced.  The last	*/
/* is a pointer to the first object tag in the list of items that	*/
/* it being listed.							*/

int list_obj(str, ply_ptr, first_otag)
char		*str;
creature	*ply_ptr;
otag		*first_otag;
{
	otag	*op;
	int	m, n=0, flags=0;

	if(F_ISSET(ply_ptr, PDINVI))
		flags |= INV;
	if(F_ISSET(ply_ptr, PDMAGI))
		flags |= MAG;

	str[0] = 0;
	op = first_otag;
	while(op && strlen(str) < 2048) {
		if((F_ISSET(ply_ptr, PDINVI) ? 1:!F_ISSET(op->obj, OINVIS)) &&
		   !F_ISSET(op->obj, OHIDDN) && !F_ISSET(op->obj, OSCENE)) {
			m=1;
			while(op->next_tag) {
				if(!strcmp(op->next_tag->obj->name,
					   op->obj->name) &&
				   (op->next_tag->obj->adjustment ==
				   op->obj->adjustment ||
				   !F_ISSET(ply_ptr, PDMAGI)) &&
				   (F_ISSET(ply_ptr, PDINVI) ?
				   1:!F_ISSET(op->next_tag->obj, OINVIS)) &&
				   !F_ISSET(op->next_tag->obj, OHIDDN) &&
				   !F_ISSET(op->next_tag->obj, OSCENE)) {
					m++;
					op = op->next_tag;
				}
				else
					break;
			}
			strcat(str, obj_str(op->obj, m, flags));
			strcat(str, ", ");
			n++;
		}
		op = op->next_tag;
	}
	if(n) {
		str[strlen(str)-2] = 0;
		return(1);
	}
	else
		return(0);

}

/**********************************************************************/
/*				weight_obj			      */
/**********************************************************************/

/* This function computes the total amount of weight of an object and */
/* all its contents.						      */

int weight_obj(obj_ptr)
object	*obj_ptr;
{
	int	n;
	otag	*op;

	n = obj_ptr->weight;
	op = obj_ptr->first_obj;
	while(op) {
		if(!F_ISSET(op->obj, OWTLES))
			n += weight_obj(op->obj);
		op = op->next_tag;
	}

	return(n);

}


/************************************************************************/
/*				rand_enchant				*/
/************************************************************************/

/* This function randomly enchants an object if its random-enchant flag */
/* is set.								*/

void rand_enchant(obj_ptr)
object	*obj_ptr;
{
	char m;

	m = mrand(1,100);
	if(m > 98) {
		F_SET(obj_ptr, OENCHA);
		obj_ptr->adjustment = 3;
		obj_ptr->pdice += 3;
	}
	else if(m > 90) {
		F_SET(obj_ptr, OENCHA);
		obj_ptr->adjustment = 2;
		obj_ptr->pdice += 2;
	}
	else if(m > 50) {
		F_SET(obj_ptr, OENCHA);
		obj_ptr->adjustment = 1;
		obj_ptr->pdice += 1;
	}

	obj_ptr->pdice = MAX(obj_ptr->pdice, obj_ptr->adjustment);
}
