dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// mix.cpp - mixture code, Kerenos
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with the dawn license *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 **************************************************************************/
#include "include.h"
#include "db.h"

void mix_bsort( vn_int array[], sh_int num[], int size );
void empty_container( OBJ_DATA *container );

#define BADMIX_LVNUM 445
#define BADMIX_HVNUM 449
/**************************************************************************/
// semilocalized globals
extern mix_data	*mix_list;

/**************************************************************************/
void do_herbalism( char_data *ch, char *argument)
{
	mix_data	*m;
	OBJ_DATA	*container;
	OBJ_DATA	*obj;
	vn_int		vnum_elements[6], vtemp = 0;
	sh_int		num_elements[6];
	int			total_elements = 0;
	int			i;
	int			chance;
	int			level;
	bool		mFound = false;

	// see if they know how to mix herbs in the first place
	if ( get_skill( ch, gsn_herbalism ) == 0 )
	{
		ch->println( "You don't know the first thing about mixing herbs." );
		return;
	}

	if ( IS_NULLSTR( argument ))
	{
		ch->println( "You must specify a valid cauldron or mortar in which to mix your herbs." );
		return;
	}

	// start off easy, get the container obj
	if (( container = get_obj_carry( ch, argument )) == NULL )
	{
		ch->println( "You are not carrying that." );
		return;
	}

	// determine if it's a valid container
	switch ( container->item_type )
	{
	default:
		{
			ch->println( "You can't mix herbs in that." );
			return;
		}
	case ITEM_FLASK:
		{
			ch->println( "You can't mix herbs in that in this way, try using mixflask instead." );
			return;
		}
	case ITEM_MORTAR:
	case ITEM_CAULDRON:
		break;
	}

	// check for an empty container to crap out at the earliest point
	if ( container->contains == NULL )
	{
		ch->printlnf( "There is nothing in %s.", container->short_descr );
		return;
	}

	// initialize
	for ( i = 0; i < 5; i++ )
	{
		num_elements[i]  = 0;
		vnum_elements[i] = 0;
	}

	// main counting loop to catalogue all the items in the container
	for ( obj = container->contains; obj; obj = obj->next_content )
	{
		vtemp = obj->pIndexData->vnum;

		for ( i=0; i < 5; i++ )
		{
			// increment count of elements if same object found
			if ( vtemp == vnum_elements[i] )
			{
				num_elements[i]++;
				break;
			}
			else if ( vnum_elements[i] == 0 )
			{
				// found a new unique item
				vnum_elements[i] = vtemp;
				num_elements[i]++;
				total_elements++;
				break;
			}
		}
	}

	// finally catalogued all items in the container, time to sort'em
	mix_bsort( vnum_elements, num_elements, 5 );
	
	// time to compare the catalogued contents vs the mixture dbase
	// by now, both are sorted by this point for easier comparison
	for ( m = mix_list; m; m = m->next )
	{
		if ( m->type == MIXTYPE_HERBALISM )
		{
			for ( i = 0; i < 5; i++ )
			{
				mFound = false;
				if (!( vnum_elements[i] == m->ingredients[i] 
					&& num_elements[i]  == m->ingredients_num[i] ))
				{
					mFound = false;
					break;
				}
				mFound = true;
			}
		}
		if ( mFound )
			break;
	}

	// if we didn't find a matching mix, ditch all the ingredients
	if ( !mFound )
	{
		ch->println( "You try to combine the ingredients, but they yield no useful result." );
		empty_container( container );
		return;
	}

	level = UMAX(1, ch->level - (( 5 - modifier_table[m->difficulty].type ) * 3 ));
	if ( !IS_IMMORTAL(ch) && level > LEVEL_HERO ){
		level = LEVEL_HERO;
	}

	// VESSEL CHECK ?

	// skill check to see if the result will happen or not
	chance = (( get_skill( ch, gsn_herbalism ) - m->difficulty ) + ch->modifiers[STAT_IN] );
	if ( chance >= number_percent() )
	{
		OBJ_INDEX_DATA	*obj_template;
		OBJ_DATA		*result;
		
		// success, let's restring
		if (( obj_template = get_obj_index( m->vnum_template )) == NULL )
		{
			ch->printlnf( "Vnum %d is missing for the %s mix, write a note to realm/admin",
				m->vnum_template, m->name );
			return;
		}

		result = create_object( obj_template);

		replace_string( result->name,		 m->rname );
		replace_string( result->short_descr, m->rshort );
		replace_string( result->description, m->rlong  );

		result->level			= ch->level;
		result->item_type		= m->ritem_type;
		result->wear_flags		= m->rwear;
		
		for ( i = 1; i < 5; i++ ){
			result->value[i]	= m->rvalue[i];
		}
		result->value[0]		= level;

		ch->printlnf( "You mix the ingredients within %s and have concocted %s.",
			container->short_descr, m->rshort );
		act( "$n busies $mself and mixes a concoction within $p.", ch, container, NULL, TO_ROOM );
		empty_container( container );
		obj_to_obj( result, container );
		WAIT_STATE( ch, skill_table[gsn_herbalism].beats );
		check_improve( ch, gsn_herbalism, true, 3 );
	}
	// failed, create a bad result
	else
	{
		OBJ_INDEX_DATA	*obj_template;
		OBJ_DATA		*result;

		if (( obj_template = get_obj_index( number_range( BADMIX_LVNUM, BADMIX_HVNUM ))) == NULL )
		{
			ch->printlnf( "Vnum %d (between BADMIX_LVNUM and BADMIX_HVNUM) is missing for the %s mix, write a note to realm/admin",
				m->vnum_template, m->name );
			return;
		}
		result = create_object( obj_template);
		ch->printlnf( "You mix the ingredients within %s and have concocted %s.",
			container->short_descr, m->rshort );

		replace_string( result->name,		 m->rname );
		replace_string( result->short_descr, m->rshort );
		replace_string( result->description, m->rlong  );
		result->level= level;

		act( "$n busies $mself and mixes a concoction within $p.", ch, container, NULL, TO_ROOM );
		WAIT_STATE( ch, skill_table[gsn_herbalism].beats );
		check_improve( ch, gsn_herbalism, true, 3 );
		empty_container( container );
		obj_to_obj( result, container );
	}
};

/**************************************************************************/
// mixflask only version of herbalism - Kal, Sept 02
void do_mixflask( char_data *ch, char *argument)
{
	mix_data	*m;
	OBJ_DATA	*container;
	OBJ_DATA	*obj;
	vn_int		vnum_elements[6], vtemp = 0;
	sh_int		num_elements[6];
	int			total_elements = 0;
	int			i;
	int			chance;
	int			level;
	bool		mFound = false;

	if ( IS_NULLSTR( argument )){
		ch->println( "Syntax: mixflask <flask>   - to mix herbs in a flask.");
		ch->println( "This command requires the herbalism skill to use." );
		return;
	}

	// see if they know how to mix herbs in the first place
	if ( get_skill( ch, gsn_herbalism ) == 0 )
	{
		ch->println( "You don't know the first thing about mixing herbs." );
		return;
	}

	// start off easy, get the container obj
	if (( container = get_obj_carry( ch, argument )) == NULL )
	{
		ch->println( "You are not carrying that." );
		return;
	}

	// determine if it's a valid container
	switch ( container->item_type )
	{
	default:
		{
			ch->println( "You can't mix herbs in that." );
			return;
		}

	case ITEM_MORTAR:
	case ITEM_CAULDRON:
		{
			ch->println( "You can't use mixflask to mix herbs in that, try using herbalism!" );
			return;
		}

	case ITEM_FLASK:
		break;
	}

	// check for an empty container to crap out at the earliest point
	if ( container->contains == NULL ){
		ch->printlnf( "There is nothing in %s.", container->short_descr );
		return;
	}

	// initialize
	for ( i = 0; i < 5; i++ )
	{
		num_elements[i]  = 0;
		vnum_elements[i] = 0;
	}

	// main counting loop to catalogue all the items in the container
	for ( obj = container->contains; obj; obj = obj->next_content )
	{
		vtemp = obj->pIndexData->vnum;

		for ( i=0; i < 5; i++ )
		{
			// increment count of elements if same object found
			if ( vtemp == vnum_elements[i] )
			{
				num_elements[i]++;
				break;
			}
			else if ( vnum_elements[i] == 0 )
			{
				// found a new unique item
				vnum_elements[i] = vtemp;
				num_elements[i]++;
				total_elements++;
				break;
			}
		}
	}

	// finally catalogued all items in the container, time to sort'em
	mix_bsort( vnum_elements, num_elements, 5 );
	
	// time to compare the catalogued contents vs the mixture dbase
	// by now, both are sorted by this point for easier comparison
	for ( m = mix_list; m; m = m->next )
	{
		if ( m->type == MIXTYPE_HERBALISM )
		{
			for ( i = 0; i < 5; i++ )
			{
				mFound = false;
				if (!( vnum_elements[i] == m->ingredients[i] 
					&& num_elements[i]  == m->ingredients_num[i] ))
				{
					mFound = false;
					break;
				}
				mFound = true;
			}
		}
		if ( mFound )
			break;
	}

	// if we didn't find a matching mix, ditch all the ingredients
	if ( !mFound )
	{
		ch->println( "You try to combine the ingredients, but they yield no useful result." );
		empty_container( container );
		return;
	}

	level = UMAX(1, ch->level - (( 5 - modifier_table[m->difficulty].type ) * 3 ));
	if ( !IS_IMMORTAL(ch) && level > LEVEL_HERO ){
		level = LEVEL_HERO;
	}

	// VESSEL CHECK ?

	// skill check to see if the result will happen or not
	chance = (( get_skill( ch, gsn_herbalism ) - m->difficulty ) + ch->modifiers[STAT_IN] );
	if ( chance >= number_percent() )
	{
		OBJ_INDEX_DATA	*obj_template;
		OBJ_DATA		*result;
		
		// success, let's restring
		if (( obj_template = get_obj_index( m->vnum_template )) == NULL )
		{
			ch->printlnf( "Object vnum %d is missing for the %s mix (template object), "
				"write a note to realm/admin",
				m->vnum_template, m->name );
			return;
		}

		result = create_object( obj_template);

		replace_string( result->name,		 m->rname );
		replace_string( result->short_descr, m->rshort );
		replace_string( result->description, m->rlong  );

		result->level			= ch->level;
		result->item_type		= m->ritem_type;
		result->wear_flags		= m->rwear;
		
		for ( i = 1; i < 5; i++ ){
			result->value[i]	= m->rvalue[i];
		}
		result->value[0]		= level;

		ch->printlnf( "You mix the ingredients within %s and have concocted %s.",
			container->short_descr, m->rshort );
		act( "$n busies $mself and mixes a concoction within $p.", ch, container, NULL, TO_ROOM );
		extract_obj(container);		
		obj_to_char( result, ch);
		WAIT_STATE( ch, skill_table[gsn_herbalism].beats );
		check_improve( ch, gsn_herbalism, true, 3 );
	}
	// failed, create a bad result
	else
	{
		OBJ_INDEX_DATA	*obj_template;
		OBJ_DATA		*result;

		int badvnum=number_range( BADMIX_LVNUM, BADMIX_HVNUM );
		if (( obj_template = get_obj_index(badvnum)) == NULL )
		{
			ch->printlnf( "Vnum %d (between BADMIX_LVNUM(%d) and BADMIX_HVNUM(%d)) is missing for the %s mix, write a note to realm/admin",
				badvnum, BADMIX_LVNUM, BADMIX_HVNUM, m->name );
			return;
		}
		result = create_object( obj_template);
		ch->printlnf( "You mix the ingredients within %s and have concocted %s.",
			container->short_descr, m->rshort );

		replace_string( result->name,		 m->rname );
		replace_string( result->short_descr, m->rshort );
		replace_string( result->description, m->rlong  );
		result->level= level;

		act( "$n busies $mself and mixes a concoction within $p.", ch, container, NULL, TO_ROOM );
		WAIT_STATE( ch, skill_table[gsn_herbalism].beats );
		check_improve( ch, gsn_herbalism, true, 3 );
		extract_obj( container );
		obj_to_char( result, ch);
	}
};


/**************************************************************************/
void empty_container( OBJ_DATA *container )
{
	OBJ_DATA *obj;
	OBJ_DATA *obj_next;

	if ( container->contains == NULL )
		return;

	for ( obj = container->contains; obj; obj = obj_next )
	{
		obj_next = obj->next_content;
		extract_obj( obj );
	}
}
/**************************************************************************/