Argila2.0/
Argila2.0/pp/
Argila2.0/pp/lib/save/objs/g/
Argila2.0/pp/lib/save/player/g/
Argila2.0/pp/regions/
Argila2.0/pp/regions/Lscripts/
Argila2.0/pp/src/lib/
/** 
*	\file money.c
*	Provides services for creating, spending, counting, and describing money
*
*	Description:  All matters dealing with coins, money and merchant actions
*
*	The purpose of this module is to provide services for creating, spending,
*	counting, and describing money, as well as receiving change, and putting
*	money in storerooms. Also actions involving merchants and vnpc buyers,
*	including sales, barter and re-sales.
*
*	Copyright 2005, Mary C. Huston, All rights reserved.
*	Copyright (C) 2004, Shadows of Isildur: Traithe	
*
*	The program(s) may be used and/or copied only with written
*	permission or in accordance with the terms and conditions
*	stipulated in the license from DIKU GAMMA (0.0) and SOI.
*
*	\author Mary Huston
*	\author Email:  auroness@gmail.com
*

******************************************************************************
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include "structs.h"
#include "protos.h"
#include "utils.h"
#include "decl.h"

/** Contains the ovnums for all currency items accepted by currency_type = 1 **/
extern const int coin_type1[];

/** Contains the ovnums for all currency items accepted by currency_type = 0 **/
extern const int coin_type0[];

/** money avaible to vnpc **/
#define VNPC_COPPER_PURSE	200


#define NO_SUCH_ITEM1 "Don't seem to have that in my inventory. Would you like to buy something else?"
#define NO_SUCH_ITEM2 "I don't see that particular item. Perhaps you misplaced it?"
#define MISSING_CASH1 "A little too expensive for me now -- why don't you try back later?"
#define MISSING_CASH2 "You're a little short on coin, I see; come back when you can afford it."
#define DO_NOT_BUY    "I don't buy those sorts of things, I'm afraid."


/**
 *  Function: do_count
 *
 *  Prepares to counts the number of currency items.
 *
 *
 *      \param ch The PC doing the counting.
 *      \param argument none.
 *      \param cmd none
 *
 *
 *		delay_type is set to DEL_COUNT_COIN. Actual counting takes place
 *		at the next time tick. 
 *
 *
 */
void do_count (CHAR_DATA *ch, char *argument, int cmd)
{
	char		buf [MAX_STRING_LENGTH] = {'\0'};
	OBJ_DATA	*obj = NULL;

	argument = one_argument (argument, buf);

	if ( is_dark (ch->room) && !get_affect(ch, MAGIC_AFFECT_INFRAVISION) && IS_MORTAL (ch) && !IS_SET (ch->affected_by, AFF_INFRAVIS)) {
		send_to_char ("It's too dark to count anything.\n", ch);
		return;
	}

	if ( !*buf ) {
		snprintf (buf, MAX_STRING_LENGTH,   "You begin searching through your belongings, taking a tally of your wealth.\n");
		send_to_char (buf, ch);
	}
	else {
		if ( !(obj = get_obj_in_list_vis (ch, buf, ch->right_hand)) &&
			!(obj = get_obj_in_list_vis (ch, buf, ch->left_hand)) ) {
			send_to_char ("I don't see that group of items.\n", ch);
			return;
		}

		if (!IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) {
			send_to_char ("That isn't money.\n", ch);
			return;
		}

		snprintf (buf, MAX_STRING_LENGTH,   "After a moment of sorting, you determine that there are %d items in the pile.", obj->count);
		act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
		return;
	}

    	ch->delay      = 10;

	ch->delay_type = DEL_COUNT_COIN;
	
	return;
}

/**
 *  Function: delayed_count_coin
 *
 *  Counts the number of currency items and adds up thier value.
 *
 *
 *      \param ch The PC doing the counting.
 *
 *
 *		A string is printed to the character with the count of currency
 *		items and thier value
 *
 *
 */
void delayed_count_coin (CHAR_DATA *ch)
{
	char		buf [MAX_STRING_LENGTH] = { '\0' };
	char		buf2 [MAX_STRING_LENGTH] = { '\0' };
	OBJ_DATA	*obj = NULL;
	OBJ_DATA	*tobj = NULL;
	int			money = 0;
	int			location = 0;
	char		*temp_arg = NULL;
	
	if ( ch->right_hand ) {
		if (IS_SET (ch->right_hand->obj_flags.extra_flags, ITEM_CAPITAL)) {
			money += ch->right_hand->coppers * ch->right_hand->count;
			tobj = ch->right_hand;
			snprintf (buf2 + strlen(buf2), MAX_STRING_LENGTH, "   %d of %s (right hand): %d coppers\n", tobj->count, tobj->short_description, (int)tobj->coppers*tobj->count);
		}
		else if ( (int)GET_ITEM_TYPE (ch->right_hand) == ITEM_CONTAINER ) {
			for ( tobj = ch->right_hand->contains; tobj; tobj = tobj->next_content ) {
				if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL)) {
					money += tobj->coppers*tobj->count;
					
					temp_arg = obj_short_desc(tobj->in_obj);
					snprintf (buf2 + strlen(buf2), MAX_STRING_LENGTH, "   %d of %s (%s): %d coppers\n", tobj->count, tobj->short_description, temp_arg, (int)tobj->coppers*tobj->count);
				}
			}
		}
	}

	if ( ch->left_hand ) {
		if (IS_SET (ch->left_hand->obj_flags.extra_flags, ITEM_CAPITAL)) {
			money += ch->left_hand->coppers * ch->left_hand->count;
			tobj = ch->left_hand;
			snprintf (buf2 + strlen(buf2), MAX_STRING_LENGTH, "   %d %s (left hand): %d coppers\n", tobj->count, tobj->short_description, (int)tobj->coppers*tobj->count);
		}
		else if ( GET_ITEM_TYPE (ch->left_hand) == ITEM_CONTAINER ) {
			for ( tobj = ch->left_hand->contains; tobj; tobj = tobj->next_content ) {
				if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL)) {
					money += tobj->coppers*tobj->count;
					
					temp_arg = obj_short_desc(tobj->in_obj);
					snprintf (buf2 + strlen(buf2), MAX_STRING_LENGTH, "   %d of %s (%s): %d coppers\n", tobj->count, tobj->short_description, temp_arg, (int)tobj->coppers*tobj->count);
				}
			}
		}
	}

	for ( location = 0; location < MAX_WEAR; location++ ) {
		if ( !(obj = get_equip (ch, location)) )
			continue;
		for ( tobj = obj->contains; tobj; tobj = tobj->next_content ) {
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL)) {
				money += tobj->coppers*tobj->count;
				
				temp_arg = obj_short_desc(obj);
				snprintf (buf2 + strlen(buf2), MAX_STRING_LENGTH, "   %d of %s (%s): %d coppers\n", tobj->count, tobj->short_description, temp_arg, (int)tobj->coppers*tobj->count);
			}
		}
	}

	if ( !money ) {
		send_to_char ("You don't seem to have any coin.\n", ch);
		return;
	}

	snprintf (buf, MAX_STRING_LENGTH,   "By your count, you have %d coppers' worth in coin:", money);
	act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
	send_to_char ("\n", ch);
	send_to_char (buf2, ch);
	
	return;
}

/**
 *  Function: stop_counting
 *
 *  Halts the counting of currency items
 *
 *
 *      \param ch The PC doing the counting.
 *
 *
 *     The delay is set to 0, and an echo is printed to character
 *
 *
 */
void stop_counting (CHAR_DATA *ch)
{
	send_to_char ("You bore of counting coins.\n", ch);

	ch->delay = 0;

	ch->delay_obj = NULL;
	
	return;
}

/**
 *  Function: make_change
 *
 *  Calculates the proper change and puts it where it belongs
 *
 *
 *      \param money amount of chnage to be made
 *		\param keeper shopkeep (if there is one)
 *		\param currency_type type of currency
 *		\param tobj a container object to put change into
 *		\param cmd	0 if the change is given to the character
 *		\param cmd	1 if the change goes to the keepers room
 *		\param ch character getting the change
 *
 *     Returns TRUE if change is made, FALSE otherwise.
 *
 *  	\sa keeper_money_to_char, subtract_money, money_to_storeroom,
 *		subtract_keeper_money
 *
 */
int make_change(int money, CHAR_DATA *keeper, int currency_type, OBJ_DATA *tobj, int cmd, CHAR_DATA *ch)
{
	OBJ_DATA	*obj = NULL;
	bool		coin_back = FALSE;
	int 		i = 0;
	int 		j = 0;
	int 		value = 0;
	int 		holder = 0;	
	int 		sorted_values[MAX_COIN];
	
	if (keeper){ /* we have a merchant */
		if (keeper->mob->currency_type == 0){
			for ( i = 0; i < MAX_COIN; i++){
				sorted_values[i] = coin_type0[i];
			}
		}
	
		if (keeper->mob->currency_type == 1) {
			for ( i = 0; i < MAX_COIN; i++){
				sorted_values[i] = coin_type1[i];
			}
		}
	}
	else { /* there is no merchant */
		if (currency_type == 0){
			for ( i = 0; i < MAX_COIN; i++){
				sorted_values[i] = coin_type0[i];
			}
		}
	
		if (currency_type == 1) {
			for ( i = 0; i < MAX_COIN; i++){
				sorted_values[i] = coin_type1[i];
			}
		}
	}
/****** sort array(vnum,value) on the second index *****/

	for (i = 0; i < MAX_COIN; i++){
		for (j = 0; j < MAX_COIN-1; j ++){
			if (!(sorted_values[j+1]) == 0){
				value = (vtoo(sorted_values[j]))->coppers; /* value of the coin */
	   			if (value > (vtoo(sorted_values[j+1]))->coppers){
	   				holder = sorted_values[j+1];
	   				sorted_values[j+1] = sorted_values[j];
	   				sorted_values[j] = holder;
				}
			}
    	}
    } /* end for */
 
 	
/******* end sort ********************/

	if (cmd == 0){ /* change given to the character */
		for (i = MAX_COIN-1; i >= 0; i--){
 			if ( !(sorted_values[i] == 0)) { 
        		obj = load_object(sorted_values [i]);
        		if (vtoo(sorted_values[i])->coppers > 0){
        			if (money/(int)(vtoo(sorted_values[i])->coppers) > 0){
	        			obj->count = money/(int)(vtoo(sorted_values [i])->coppers);
   						money = money % (int)(vtoo(sorted_values [i])->coppers);

						if (tobj){
							obj_to_obj (obj, tobj);
						}
						else {
							obj_to_char (obj, ch);
						}
						coin_back = TRUE;
					}
				}
			}
		}
		return (coin_back);
	}

	if (cmd == 1){ /* change sent to a room */
		for (i = MAX_COIN-1; i >= 0; i--){
 			if ( !(sorted_values[i] == 0)) { 
				obj = load_object(sorted_values[i]);
				if (vtoo(sorted_values[i])->coppers > 0){
					if (money/(int)(vtoo(sorted_values[i])->coppers) > 0){
		    			obj->count = money/(int)(vtoo(sorted_values[i])->coppers);
		    			money = money % (int)(vtoo(sorted_values[i])->coppers);
						obj_to_room (obj, keeper->shop->store_vnum);
		
						coin_back = TRUE;
					}
				}
			}
		}
		return (coin_back);
	}
	
	return (coin_back);
}
/**
 *  Function: keeper_has_money
 *
 *  Checks to determine if a shopkeeper has enough currency in his storeroom to
 *	cover a debit request.
 *
 *
 *      \param keeper The shopkeeper.
 *      \param cost amount to compare currency total to
 *
 *
 *     Returns 0 if currency available is less than the request, and 
 *	   returns 1 if there is not enough currency to cover the request
 *
 *
 */

int keeper_has_money (CHAR_DATA *keeper, int cost)
{
	ROOM_DATA	*store = NULL;
	OBJ_DATA	*obj = NULL;
	int		money = 0;

	if ( !keeper->shop )
		return 0;
	if ( !keeper->shop->store_vnum )
		return 0;
	if ( !(store = vtor(keeper->shop->store_vnum)) )
		return 0;

	if ( store->contents &&
		GET_ITEM_TYPE (store->contents) == ITEM_MONEY && 
		keeper_uses_currency_type (keeper->mob->currency_type, store->contents) ) {
		
		money = store->contents->coppers*store->contents->count;
	}
	
	for ( obj = store->contents; obj; obj = obj->next_content ) {
		if ( obj->next_content &&
			GET_ITEM_TYPE(obj->next_content) == ITEM_MONEY &&
			keeper_uses_currency_type (keeper->mob->currency_type, obj->next_content) ) {
			money += obj->next_content->coppers*obj->next_content->count;
		}
	}

	if ( money < cost )
		return 0;
	else return 1;
}


/**
 *  Function: keeper_uses_currency_type
 *
 *  Determines if object is in the list of vnums for the given currency_type.
 *
 *		\param currency_type the type of money used by the shopkeeper
 *		\param obj the object that may or may not be a currency unit
 *
 *     Returns 1 if the object is a currency unit that keeper uses, 
 *     returns a 0 if the object is NOT a currency unit.
 *
 *
 */
int keeper_uses_currency_type (int currency_type, OBJ_DATA *obj)
{

	int 	index = 0;
	
	if ( currency_type == 0 ) {
		while (coin_type0 [index]){
			if ((obj->virtual) == coin_type0 [index])
				return 1;
			index ++;
			
		}
	}
	else if (currency_type == 1){
		while (coin_type1 [index]){
			if ((obj->virtual) == coin_type1 [index])
				return 1;
			index ++;
			
		}
	}
	/*** item is not a recognized currency item **/
	return 0; 
}

/**
 *  Function: keeper_money_to_char
 *
 *  Gives money to character.
 *
 *		\param keeper the shopkeeper giving away the money
 *		\param ch the character getting the money
 *		\param money the value (in coppers) to be paid
 *
 *
 *     	Prints an echo to the character and calls make_change
 *
 *      
 *
 */

void keeper_money_to_char (CHAR_DATA *keeper, CHAR_DATA *ch, int money)
{
	OBJ_DATA	*obj = NULL;
	OBJ_DATA	*tobj = NULL;
	char		buf [MAX_STRING_LENGTH] = {'\0'};
	int			location = 0;
	char		*temp_arg = NULL;

	
	if ( ch->right_hand ) {
		if ((int)GET_ITEM_TYPE (ch->right_hand) == ITEM_CONTAINER ) {
			tobj = ch->right_hand;
		}
	}

	if ( ch->left_hand ) {
		if ( GET_ITEM_TYPE (ch->left_hand) == ITEM_CONTAINER ) {
			tobj = ch->left_hand;
		}
	}
	
	for ( location = 0; location < MAX_WEAR; location++ ) {
		if ( !(obj = get_equip (ch, location)) )
			continue;
		
		if ( GET_ITEM_TYPE (obj) != ITEM_CONTAINER )
			continue;
        
        if ( IS_SET(obj->o.container.flags, CONT_CLOSED) )
			continue;
		tobj = obj;		
	}
	
	if (tobj){
		temp_arg = obj_short_desc(tobj);
		snprintf (buf, MAX_STRING_LENGTH,   "$N gives you some coins in return, which you tuck away in %s.", temp_arg);
		(void)make_change(money, keeper, 0, tobj, 0, ch);
	}
	else {
		snprintf (buf, MAX_STRING_LENGTH,   "$N gives you some coins in return.");
		(void)make_change(money, keeper, 0, '\0', 0, ch);
	}
	
		
	act (buf, TRUE, ch, 0, keeper, TO_CHAR | TO_ACT_FORMAT);

	return;
}

/**
 *  Function: can_subtract_money
 *
 *  Checks to see if the character has enough money on him or in his gear.
 *
 *		\param ch character who is losing the money
 *		\param coppers_to_subtract amount to be removed
 *		\param currency_type type of currency items to be removed
 *     
 *
 *  	Returns a 0 if character doesn't have enough money, and 
 *		returns a 1 is there is enough money.
 *
 *
 */
int can_subtract_money (CHAR_DATA *ch, int coppers_to_subtract, int currency_type)
{
	OBJ_DATA	*obj = NULL;
	OBJ_DATA	*tobj = NULL;
	int			money = 0;
	int 		location = 0;
	int			index = 0;
	
	if ((obj = ch->right_hand) && 
		 (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&
		 (currency_type == 0)) {
		 while (coin_type0 [index]){
			if ((obj->virtual) == coin_type0 [index]){
				money += ch->right_hand->coppers * ch->right_hand->count;
			}
			index ++;
		}
	}

	
	if ( (obj = ch->right_hand) && 
		 (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&			
		 (currency_type == 1)) {
		index = 0;
		while (coin_type1 [index]){
			if ((obj->virtual) == coin_type1 [index]){
				money += ch->right_hand->coppers * ch->right_hand->count;
			}
			index ++;
		}
	}
	
	if ( (obj = ch->right_hand) && 	
		 ( GET_ITEM_TYPE (obj) == ITEM_CONTAINER )) { 
		for ( tobj = obj->contains; tobj; tobj = tobj->next_content ) {
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 0)) {
				index = 0;
				while (coin_type0 [index]){
					if ((tobj->virtual) == coin_type0 [index]){
						money += tobj->coppers * tobj->count;
					}
					index ++;
				}
			}
		
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 1)){
				index = 0;
				while (coin_type1 [index]){
					if ((tobj->virtual) == coin_type1 [index]){
						money += tobj->coppers * tobj->count;
					}
					index ++;
				}
			}
		}
	}
	
	if ( (obj = ch->left_hand) &&
		 (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&
		 (currency_type == 0)) {
		index = 0;
		while (coin_type0 [index]){
			if ((obj->virtual) == coin_type0 [index]){
				money += ch->left_hand->coppers * ch->left_hand->count;
			}
			index ++;
		}
	}
	
	if ( (obj = ch->left_hand) &&
		 (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&
		 (currency_type == 1)){
		index = 0;
		while (coin_type1 [index]){
			if ((obj->virtual) == coin_type1 [index]){
				money += ch->left_hand->coppers * ch->left_hand->count;
			}
			index ++;
		}
	}
		
		
	if ( (obj = ch->left_hand) &&
		 ( GET_ITEM_TYPE (obj) == ITEM_CONTAINER )) { 
		for ( tobj = obj->contains; tobj; tobj = tobj->next_content ) {
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 0)) {
				index = 0;
				while (coin_type0 [index]){
					if ((tobj->virtual) == coin_type0 [index]){
						money += tobj->coppers * tobj->count;
					}
					index ++;
				}
			}
					
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 1)){
				index = 0;
				while (coin_type1 [index]){
					if ((tobj->virtual) == coin_type1 [index]){
						money += tobj->coppers * tobj->count;
					}
					index ++;
				}
			}
		}
	}
		
	
	for ( location = 0; location < MAX_WEAR; location++ ) {
		if ( !(obj = get_equip (ch, location)) )
			continue;
		
		if ( GET_ITEM_TYPE (obj) != ITEM_CONTAINER )
			continue;
        
        if ( IS_SET(obj->o.container.flags, CONT_CLOSED) )
			continue;
		
		for ( tobj = obj->contains; tobj; tobj = tobj->next_content ) {
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 0)) {
				index = 0;
				while (coin_type0 [index]){
					if ((tobj->virtual) == coin_type0 [index]){
						money += tobj->coppers * tobj->count;
					}
					index ++;
				}
			}
			
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 1)){
				index = 0;
				while (coin_type1 [index]){
					if ((tobj->virtual) == coin_type1 [index]){
						money += tobj->coppers * tobj->count;
					}
					index ++;
				}
			}
		}
	}
		
	if ( money < coppers_to_subtract )
		return 0;

	return 1;
}
/**
 *  Function: subtract_money
 *
 *	Finds money on the character, then removes the amount needed  
 *
 *		\param ch the character paying the money
 *		\param coppers_to_subtract the amount to be removed
 *		\param currency_type the type of currency to look for
 *
 *
 *		Removes the money from the character, and prints an echo to the player
 *		and the room
 *
 *
 */

void subtract_money (CHAR_DATA *ch, int coppers_to_subtract, int currency_type)
{
	char		buf [MAX_STRING_LENGTH] = {'\0'};
	OBJ_DATA	*tobj = NULL;
	OBJ_DATA 	*obj = NULL;
	OBJ_DATA	*next_obj = NULL;
	bool		coin_back = FALSE;
	bool		container = FALSE;
	int			money = 0;
	int			location = 0;
	int			ind = 0;
	char		*temp_arg = NULL;

	ind = 0;
	for ( location = 0; location < MAX_WEAR; location++ ) {
		if ( !(obj = get_equip (ch, location)) )
			continue;
			
		if ( GET_ITEM_TYPE (obj) != ITEM_CONTAINER )
			continue;
            
        if ( IS_SET(obj->o.container.flags, CONT_CLOSED) )
			continue;
		
/*** obj is an open container on the character at this point ***/
/*** tobj is something inside the container ***/

		for ( tobj = obj->contains; tobj; tobj = next_obj ) {
			next_obj = tobj->next_content;
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 0)){ 
				ind = 0;
				while (coin_type0 [ind]){
					if ((tobj->virtual) == coin_type0 [ind]){
						money += tobj->coppers*tobj->count;
						obj_from_obj(&tobj, tobj->count);
						extract_obj (tobj);
						ch->delay_obj = obj;
						container = TRUE;
					}
					ind ++;
				}
			}
			
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 1)){ 
				ind = 0;
				while (coin_type1 [ind]){
					if ((tobj->virtual) == coin_type1 [ind]){
						money += tobj->coppers*tobj->count;
						obj_from_obj(&tobj, tobj->count);
						extract_obj (tobj);
						ch->delay_obj = obj;
						container = TRUE;
					}
					ind ++;
				}
			}
		}
	}  
/*** end wear location check **/

	if ((obj = ch->right_hand) && 
		 (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&
		 (currency_type == 0)) {
		ind = 0;
		while (coin_type0 [ind]){
			if ((obj->virtual) == coin_type0 [ind]){
				money += obj->coppers * obj->count;
				extract_obj (obj);
				ch->right_hand = NULL;
			}
			ind ++;
		}
	}
	
	if ( (obj = ch->right_hand) && 
		 (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&			
		 (currency_type == 1)) {
		ind = 0;
		while (coin_type1 [ind]){
			if ((obj->virtual) == coin_type1 [ind]){
				money += obj->coppers * obj->count;
				extract_obj (obj);
				ch->right_hand = NULL;
			}
			ind ++;
		}
	}
	
	
	if ( (obj = ch->right_hand) && 	
		 ( GET_ITEM_TYPE (obj) == ITEM_CONTAINER )) { 
		for ( tobj = obj->contains; tobj; tobj = tobj->next_content ) {
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 0)) {
				ind = 0;
				while (coin_type0 [ind]){
					if ((tobj->virtual) == coin_type0 [ind]){
						money += tobj->coppers*tobj->count;
						obj_from_obj(&tobj, tobj->count);
						extract_obj (tobj);
						ch->delay_obj = obj;
						container = TRUE;
					}
					ind ++;
				}
			}
		
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 1)){
				ind = 0;
				while (coin_type1 [ind]){
					if ((tobj->virtual) == coin_type1 [ind]){
						money += tobj->coppers*tobj->count;
						obj_from_obj(&tobj, tobj->count);
						extract_obj (tobj);
						ch->delay_obj = obj;
						container = TRUE;
					}
					ind ++;
				}
			}
		}
	} 
/*** end right hand check **/

	if ( (obj = ch->left_hand) &&
		 (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&
		 (currency_type == 0)) {
		ind = 0;
		while (coin_type0 [ind]){
			if ((obj->virtual) == coin_type0 [ind]){
				money += obj->coppers * obj->count;
				extract_obj (obj);
				ch->left_hand = NULL;
			}
			ind ++;
		}
	}
	
	if ( (obj = ch->left_hand) &&
		 (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&
		 (currency_type == 1)){
		ind = 0;
		while (coin_type1 [ind]){
			if ((obj->virtual) == coin_type1 [ind]){
				money += obj->coppers * obj->count;
				extract_obj (obj);
				ch->left_hand = NULL;
			}
			ind ++;
		}
	}
		
		
	if ( (obj = ch->left_hand) &&
		 ( GET_ITEM_TYPE (obj) == ITEM_CONTAINER )) { 
		for ( tobj = obj->contains; tobj; tobj = tobj->next_content ) {
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 0)) {
				ind = 0;
				while (coin_type0 [ind]){
					if ((tobj->virtual) == coin_type0 [ind]){
						money += tobj->coppers*tobj->count;
						obj_from_obj(&tobj, tobj->count);
						extract_obj (tobj);
						ch->delay_obj = obj;
						container = TRUE;
					}
					ind ++;
				}
			}	
					
			if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL) &&
				(currency_type == 1)){
				ind = 0;
				while (coin_type1 [ind]){
					if ((tobj->virtual) == coin_type1 [ind]){
						money += tobj->coppers*tobj->count;
						obj_from_obj(&tobj, tobj->count);
						extract_obj (tobj);
						ch->delay_obj = obj;
						container = TRUE;
					}
					ind ++;
				}
			}
		}
	}
/** end left hand **/

	money -= coppers_to_subtract;

	coin_back = make_change(money, '\0', currency_type, ch->delay_obj, 0, ch);

	obj = ch->delay_obj;
	ch->delay_obj = NULL;

	if ( container )
		send_to_char ("\nRifling through your belongings, you retrieve your coin.\n", ch);
	else send_to_char ("\nYou offer up the specified amount.\n", ch);

	if ( coin_back ) {
		if ( obj ){
			temp_arg = obj_short_desc(obj);
			snprintf (buf, MAX_STRING_LENGTH,   "Change is made, which you then deposit in %s.", temp_arg);
		}
  		else
			snprintf (buf, MAX_STRING_LENGTH,   "Change is made for the amount offered.");
		send_to_char ("\n", ch);
		act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
	}

	ch->delay_obj = NULL;
	
	return;
}

/**
 *  Function: do_list
 *
 *  Lists all sellable items in a keepers storeroom
 *
 *		\param	ch - The character asking for the list
 *		\param	argument - type of item and specific shopkeeper
 *		\param	cmd - not used 
 *
 *		Useage, 
 *		- <b>list tunic</b> will  list all tunics
 *		- <b>list copper</b> will list the items for the keeper with copper hair
 *		- <b>list tunic copper</b> will list all tunics from copper-haired man
 *
 *  	Prints a list of available items. Prevents players from buying back
 *		items they've sold, and prevents all others from buying a sold item for
 *		15 minutes to prevent abuse.
 *
 *
 */

void do_list (CHAR_DATA *ch, char *argument, int cmd)
{
	char				buf [MAX_STRING_LENGTH] = {'\0'};
	char				stock_buf [MAX_STRING_LENGTH] = {'\0'};
	char				buf2 [MAX_STRING_LENGTH] = {'\0'};
	char				output [MAX_STRING_LENGTH] = {'\0'};
	int					i = 0;
	float				val_in_coppers = 0;
	int					header_said = 0;
	float				markup = 0;
	CHAR_DATA			*keeper = NULL;
	CHAR_DATA			*tch = NULL;
	ROOM_DATA			*room = NULL;
	ROOM_DATA			*store = NULL;
	OBJ_DATA			*obj = NULL;
	OBJ_DATA			*tobj = NULL;
	NEGOTIATION_DATA	*neg = NULL;
	char				*temp_arg = NULL;

	room = ch->room;

	argument = one_argument (argument, buf);

	if ( *buf && (keeper = get_char_room_vis (ch, buf)) )
		argument = one_argument (argument, buf);

	else {
		for ( tch = room->people; tch; tch = tch->next_in_room )
			if ( tch != ch && IS_SET (tch->flags, FLAG_KEEPER) )
				break;

		keeper = tch;
	}

	if ( !keeper ) {
		send_to_char ("There is no merchant here.\n", ch);
		return;
	}

	if ( !GET_TRUST (ch) && !CAN_SEE (keeper, ch) ) {
		do_say (keeper, "Who's there?", 0);
		return;
	}

	if ( GET_POS (keeper) <= POSITION_SLEEPING ) {
		act ("$N is not conscious.", TRUE, ch, 0, keeper, TO_CHAR);
		return;
	}

	if ( GET_POS (keeper) == POSITION_FIGHTING ) {
		do_say (keeper, "Have you no eyes!  I'm fighting for my life!", 0);
		return;
	}

	if ( !keeper->shop || !IS_SET (keeper->flags, FLAG_KEEPER) ) {

		if ( keeper == ch )
			send_to_char ("You don't have a shop.\n", ch);
		else
			act ("$N isn't a shopkeeper.", FALSE, ch, 0, keeper, TO_CHAR);

		return;
	}

	if ( keeper->shop->shop_vnum &&
		 keeper->shop->shop_vnum != ch->in_room ) {
		do_say (keeper, "I'm sorry.  Please catch me when I'm in my shop.", 0);
		return;
	}

	if ( !(store = vtor (keeper->shop->store_vnum)) ) {
		do_say (keeper, "I've lost my business.  You'll have to go elsewhere.",
				0);
		return;
	}

	if ( !store->psave_loaded )
		load_save_room (store);

	if ( !store->contents ) {
		do_say (keeper, "I have nothing for sale at the moment.", 0);
		return;
	}

	i = 0;

	*output = '\0';

	for ( obj = store->contents; obj; obj = obj->next_content ) {

		i++;

		if ( (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) && keeper_uses_currency_type (keeper->mob->currency_type, obj) ) {
			i--;
			if ( obj->next_content ) {
				continue;
			} else break;
		}

		if ( *buf && !name_is (buf, obj->name) )
			continue;

		if ( !CAN_WEAR (obj, ITEM_TAKE) )
			continue;

/*** Prevent players from buying back items they've sold, and prevent all others from buying a sold item for 15 minutes to prevent abuse ***/

		if ( (obj->sold_by != ch->coldload_id && (time(0) - obj->sold_at <= 60 * 15)) ||
			(obj->sold_by == ch->coldload_id && (time(0) - obj->sold_at <= 60 * 60)) ) 
			continue;

		if ( !header_said ) {
			act ("$N describes $S inventory:", FALSE, ch, 0, keeper, TO_CHAR);
			send_to_char ("\n   #   retail cost    item\n", ch);
			send_to_char ("  ===  ===========    ====\n", ch);
			header_said = 1;
		}

		if ( !IS_SET (obj->obj_flags.extra_flags, ITEM_PC_SOLD) )
			markup = econ_markup (keeper, obj);
		else markup = econ_discount (keeper, obj);

		val_in_coppers = ( obj->coppers * markup );

		if ( GET_ITEM_TYPE (obj) == ITEM_DRINKCON &&
			 obj->o.drinkcon.volume > 0 &&
			 (tobj = vtoo (obj->o.drinkcon.liquid)) &&
			 GET_ITEM_TYPE (tobj) == ITEM_FLUID ) {
			if ( !IS_SET (obj->obj_flags.extra_flags, ITEM_PC_SOLD) )
				markup = econ_markup (keeper, tobj);
			else markup = econ_discount (keeper, tobj);
			val_in_coppers += (tobj->coppers * obj->o.drinkcon.volume * markup);
		}

		for ( neg = keeper->shop->negotiations; neg; neg = neg->next ) {
			if ( neg->ch_coldload_id == ch->coldload_id &&
				 neg->obj_vnum == obj->virtual )
				break;
		}

		if ( neg && neg->price_delta )
			val_in_coppers = val_in_coppers * 100.0 / (100.0 + neg->price_delta);
		
		*stock_buf = '\0';

		if ( !keeper_makes (keeper, obj->virtual) )
			snprintf (stock_buf, MAX_STRING_LENGTH, "(%d in stock)", obj->count);

		temp_arg = obj_short_desc (obj);
		snprintf (buf2, MAX_STRING_LENGTH,   "  #1%3d %8.02f cp%s  #2%-55.55s#0", i, val_in_coppers, "   ", temp_arg);

		if ( IS_WEARABLE (obj) || neg ) {
			temp_arg = obj_short_desc(obj);
			if ( strlen(temp_arg) > 40 ) {
				buf2 [62] = '.';
				buf2 [63] = '.';
				buf2 [64] = '.';
			}
			buf2 [65] = '\0';
			strcat (buf2, "#0");
		}
		else {
			temp_arg = obj_short_desc(obj);
			if ( strlen(temp_arg) > 52 ) {
				buf2 [74] = '.';
				buf2 [75] = '.';
				buf2 [76] = '.';
			}
			buf2 [77] = '\0';
			strcat (buf2, "#0");
		}

		if ( IS_WEARABLE (obj) ) {
			if ( obj->size )
				snprintf (buf2 + strlen (buf2), MAX_STRING_LENGTH, " (%s)", sizes_named [obj->size]);
			else if ( keeper_makes (keeper, obj->virtual) )
				snprintf (buf2 + strlen (buf2), MAX_STRING_LENGTH, " (all sizes)");
			else
				strcat (buf2, " (all sizes)");
		}

		if ( IS_SET (obj->obj_flags.extra_flags, ITEM_PC_SOLD) )
			strcat (buf2, " #6(used)#0");

		snprintf (buf2 + strlen(buf2), MAX_STRING_LENGTH, "%s", neg ? " (neg)" : "");

		strcat (buf2, "\n");

		if ( strlen(output) + strlen(buf2) > MAX_STRING_LENGTH )
			break;

		snprintf (output + strlen(output), MAX_STRING_LENGTH, "%s", buf2);
	}

	if ( !header_said ) {
		if ( *buf )
			act ("$N doesn't have any of those.",
						FALSE, ch, 0, keeper, TO_CHAR);
		else
			act ("Sadly, $N has nothing to sell.",
						FALSE, ch, 0, keeper, TO_CHAR);
	}
	else page_string (ch->desc, output);
	
	return;
}

/**
 *  Function: do_preview
 *
 *  Allows a character to see an itme for sale (read the object's full
 *	description.
 *
 *		\param	ch - character asking for the preview
 *		\param	argument - type of item and specific shopkeeper
 *		\param	cmd - not used  
 *				
 *		Useage: 
 *		- <b>preview tunic</b> will look at the first tunic
 *		- <b>preview 4</b> will look at the fourth item in the shop
 *		- <b>preview tunic copper</b> will look at the first tunic sold by
 *			the copper-haired man
 *			
 *		If found in the keepers inventory, the item will be shown to the
 *		character and he can see the long description of the item.
 *
 *
 */
void do_preview (CHAR_DATA *ch, char *argument, int cmd)
{
	int					i = 0;
	OBJ_DATA			*obj = NULL;
	CHAR_DATA			*keeper = NULL;
	CHAR_DATA			*tch = NULL;
	ROOM_DATA			*room = NULL;
	ROOM_DATA			*store = NULL;
	char				buf [MAX_STRING_LENGTH] = {'\0'};
	char				buf2 [MAX_STRING_LENGTH] = {'\0'};
	
	room = ch->room;

	argument = one_argument (argument, buf);

	if ( !*buf ) {
		send_to_char ("Preview what?\n", ch);
		return;
	}

	if ( (keeper = get_char_room_vis (ch, buf)) )
		argument = one_argument (argument, buf);

	else {
		for ( tch = room->people; tch; tch = tch->next_in_room )
			if ( tch != ch && IS_SET (tch->flags, FLAG_KEEPER) )
				break;

		keeper = tch;

		if ( !keeper ) {
			send_to_char ("There is no shopkeeper here.\n", ch);
			return;
		}

		if ( !*buf ) {
			act ("PREVIEW what from $N?", TRUE, ch, 0, keeper, TO_CHAR);
			return;
		}
	}

	if ( !keeper ) {
		send_to_char ("There is no merchant here.\n", ch);
		return;
	}

	if ( GET_POS (keeper) <= POSITION_SLEEPING ) {
		act ("$N is not conscious.", TRUE, ch, 0, keeper, TO_CHAR);
		return;
	}

	if ( GET_POS (keeper) == POSITION_FIGHTING ) {
		do_say (keeper, "Have you no eyes!  I'm fighting for my life!", 0);
		return;
	}

	if ( !keeper->shop ) {

		if ( keeper == ch )
			send_to_char ("You are not a shopkeeper.", ch);
		else
			act ("$N is not a keeper.", FALSE, ch, 0, keeper, TO_CHAR);

		return;
	}

	if ( keeper->shop->shop_vnum &&
		 keeper->shop->shop_vnum != ch->in_room ) {
		do_say (keeper, "I'm sorry.  Please catch me when I'm in my shop.", 0);
		return;
	}

	if ( !(store = vtor (keeper->shop->store_vnum)) ) {
		do_say (keeper, "I've lost my business.  You'll have to go elsewhere.",
				0);
		return;
	}

	if ( !store->psave_loaded )
		load_save_room (store);

	if ( !store->contents ) {
		do_say (keeper, "I have nothing for sale at the moment.", 0);
		return;
	}

	if ( store->contents && is_number (buf) ) {

		obj = store->contents;

		while ( obj && 
				(IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&
				keeper_uses_currency_type (keeper->mob->currency_type, obj))
				
			obj = obj->next_content;

		for ( i = 1;; i++ ) {	

			if ( !obj )
				break;

			if ( (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL))&& keeper_uses_currency_type (keeper->mob->currency_type, obj) ) {
				i--;
				if ( obj->next_content ) {
					obj = obj->next_content;
					continue;
				} else break;
			}

			if ( i == strtol (buf, NULL, 10) )
				break;

			obj = obj->next_content;
		}

		if ( !obj ) {
			name_to_ident (ch, buf2);
			snprintf (buf, MAX_STRING_LENGTH,   "%s %s", buf2, NO_SUCH_ITEM1);
			do_whisper (keeper, buf, 83);
			return;
		}
	}

	else if ( !(obj = get_obj_in_list_vis_not_money (ch, buf,
					vtor (keeper->shop->store_vnum)->contents)) ) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s %s", buf2, NO_SUCH_ITEM1);
		do_whisper (keeper, buf, 83);
		return;
	}

    	act ("$N shows you $p.", FALSE, ch, obj, keeper, TO_CHAR);

	send_to_char ("\n", ch);

	show_obj_to_char (obj, ch, 5);
	
	return;
}

/**
 *  Function: keeper_makes
 *
 *  Determines if the shopkeeper trades in the item specified.
 *
 *		\param	keeper - the shopkeeper in question
 *		\param	ovnum - the object in question
 *
 *  	Returns a 0 if the shopkeeper does not trade in that item, and
 *		a 1 if the item is traded by the merchant.
 *      
 *
 */
int keeper_makes (CHAR_DATA *keeper, int ovnum)
{
	int		i = 0;

	if ( !keeper->shop || !ovnum )
		return 0;

	for ( i = 0; i < MAX_TRADES_IN; i++ )
		if ( keeper->shop->delivery [i] == ovnum )
			return 1;

	return 0;
}

/**
 *  Function: money_to_storeoom
 *
 *  Takes money from the keeper and puts in in his storeroom.
 *
 *		\param keeper the keeper of the store
 *		\param amount the amount of money to transfer
 *
 *		Adds up all money in the storeroom, and in keepers possesion and puts
 *		it in the smallest amount of coins possible.
 *
 *
 *
 */
void money_to_storeroom (CHAR_DATA *keeper, int amount)
{
	OBJ_DATA	*obj = NULL;
	OBJ_DATA	*next_obj = NULL;
	ROOM_DATA	*store = NULL;
	int			money = 0;
	

	if ( !keeper->shop )
		return;
	if ( !keeper->shop->store_vnum )
		return;
	if ( !(store = vtor(keeper->shop->store_vnum)) )
		return;

	while ( keeper_has_money (keeper, 1) ) {
		for ( obj = store->contents; obj; obj = next_obj ) {
			next_obj = obj->next_content;
			
			if (keeper_uses_currency_type(keeper->mob->currency_type, obj)){
				if ( (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL))) {
					money += obj->coppers*obj->count;
					obj_from_room(&obj, 0);
					extract_obj (obj);
				}
			}
		}
	}

	money += amount;
	
	(void)make_change(money, keeper, 0, '\0', 1, '\0');
	
	return;       
}

/**
 *  Function: subtract_keeper_money
 *
 *  Subtracts money from a shopkeeper
 *
 *		\param keeper the keeper of the store
 *		\param cost the amount of money to transfer
 *
 *		Adds up all money in the storeroom, deducts the cost and puts
 *		it in the smallest amount of coins possible.
 *
 *
 */
void subtract_keeper_money (CHAR_DATA *keeper, int cost)
{
	OBJ_DATA	*obj= NULL;
	OBJ_DATA	*next_obj =  NULL;
	ROOM_DATA	*store = NULL;
	int 		money = 0;
	
	if ( !keeper->shop )
		return;
	if ( !keeper->shop->store_vnum )
		return;
	if ( !(store = vtor(keeper->shop->store_vnum)) )
		return;

	while ( keeper_has_money (keeper, 1) ) {
		for ( obj = store->contents; obj; obj = next_obj ) {
			next_obj = obj->next_content;
			if ( (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) && keeper_uses_currency_type (keeper->mob->currency_type, obj) ) {
				money += obj->coppers*obj->count;
				obj_from_room(&obj, 0);
				extract_obj (obj);
			}
		}
	}

	money -= cost;

	(void)make_change(money, keeper, 0, '\0', 1, '\0');


	return;   
}

/**
 *  Function: do_buy
 *
 *  Allows a character to purchase an item from a shopkeeper.
 *
 *		\param ch character doing the purchasing
 *		\param argument type of item, count, and specific shopkeeper
 *		\param cmd barter or confirming purchase  
 *
 * 		Useage:
 *			buy [keeper] [count] item [size | !] [ | 1 | 2]
 *		
 *		Item can be either a keyword or the number from the do_list.
 *		When buying sizes, use <b>!</b> if you want a size that you can't wear.
 *		cmd is sent by do_barter or do_accept with a value of 1 for barter,
 *		and 2 when confirming a purchase. Also, checks prevent players from
 *		buying back items they've sold, and prevents all others from buying a
 *		sold item for 15 minutes to prevent abuse 
 *
 *
 *
 */
void do_buy (CHAR_DATA *ch, char *argument, int cmd) 
{
	int					buy_count = 1;
	float				keepers_cost = 0;
	int					delivery_cost;
	int					i = 0;
	int					regardless = 0;
	int					wants_off_size = 0;
	int					size = -1;
	int					nobarter_flag = 0;
	int					discount = 0;
	float				markup = 0;
	int					keeper_success = 0;
	int					ch_success, flags = 0;
	int					orig_count = 0;
	OBJ_DATA			*obj = NULL;
	OBJ_DATA			*tobj = NULL;
	OBJ_DATA			*temp_obj = NULL;
	CHAR_DATA			*horse = NULL;
	CHAR_DATA			*keeper = NULL;
	CHAR_DATA			*tch = NULL;
	ROOM_DATA			*room = NULL;
	ROOM_DATA			*store = NULL;
	NEGOTIATION_DATA	*neg = NULL;
	char				name [MAX_STRING_LENGTH] = {'\0'};
	char				buf [MAX_STRING_LENGTH] = {'\0'};
	char				buf2 [MAX_STRING_LENGTH] = {'\0'};
	char				*temp_arg1 = NULL;
	char				*temp_arg2 = NULL;
	
	room = ch->room;

	argument = one_argument (argument, buf);

	if ( cmd != 2 ) {
		if ( !*buf ) {
			send_to_char ("Buy what?\n", ch);
			return;
		}

		if ( (keeper = get_char_room_vis (ch, buf)) && IS_SET (keeper->flags, FLAG_KEEPER) )
			argument = one_argument (argument, buf);

		else {
			for ( tch = room->people; tch; tch = tch->next_in_room )
				if ( tch != ch && IS_SET (tch->flags, FLAG_KEEPER) )
					break;
	
			keeper = tch;

			if ( !*buf ) {
				act ("Buy what from $N?", TRUE, ch, 0, keeper, TO_CHAR);
				return;
			}
		}

		argument = one_argument (argument, buf2);

			/*** buf is a count if buf2 is an object ***/

		if ( isdigit (*buf) && *buf2 &&
			 (isdigit (*buf2) || (keeper && keeper->shop && get_obj_in_list_vis_not_money (ch, buf2, vtor (keeper->shop->store_vnum)->contents))) ) {
			buy_count = strtol (buf, NULL, 10);
			if ( buy_count > 50 ) {
				send_to_char ("You can only buy up to 50 items at a time.\n", ch);
				return;
			}
			strcpy (buf, buf2);
			argument = one_argument (argument, buf2);
		}

		if ( *buf2 == '!' )
			regardless = 1;

		else if ( *buf2 ) {

			size = index_lookup (sizes_named, buf2);

			if ( size == -1 )
				size = index_lookup (sizes, buf2);

			wants_off_size = 1;
		}
	}
	else keeper = ch->delay_ch;

	if ( !keeper || keeper->room != ch->room ) {
		send_to_char ("There is no merchant here.\n", ch);
		return;
	}

	if ( keeper == ch ) {
		send_to_char ("You can't buy from yourself!\n", ch);
		return;
	}

	if ( GET_POS (keeper) <= POSITION_SLEEPING ) {
		act ("$N is not conscious.", TRUE, ch, 0, keeper, TO_CHAR);
		return;
	}

	if ( GET_POS (keeper) == POSITION_FIGHTING ) {
		do_say (keeper, "Have you no eyes!  I'm fighting for my life!", 0);
		return;
	}

	if ( !GET_TRUST (ch) && !CAN_SEE (keeper, ch) ) {
		do_say (keeper, "Who's there?", 0);
		return;
	}

	if ( !keeper->shop ) {

		if ( keeper == ch )
			send_to_char ("You are not a shopkeeper.", ch);
		else
			act ("$N is not a keeper.", FALSE, ch, 0, keeper, TO_CHAR);

		return;
	}

	if ( !keeper->shop || !IS_NPC(keeper) ) {
		send_to_char ("Are you sure they're a shopkeeper?\n", ch);
		return;
	}
	
	if ( keeper->shop->shop_vnum &&
		 keeper->shop->shop_vnum != ch->in_room ) {
		do_say (keeper, "I'm sorry.  Please catch me when I'm in my shop.", 0);
		return;
	}

	if ( !(store = vtor (keeper->shop->store_vnum)) ) {
		do_say (keeper, "I've lost my business.  You'll have to go elsewhere.",
				0);
		return;
	}

	if ( !store->psave_loaded )
		load_save_room (store);

	if ( !store->contents ) {
		do_say (keeper, "I have nothing for sale at the moment.", 0);
		return;
	}

	if ( cmd != 2 ) {
		if ( is_number (buf) ) {

			obj = store->contents;

			while 	(obj &&
					(IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) && 
					keeper_uses_currency_type (keeper->mob->currency_type, obj))
				obj = obj->next_content;

			for ( i = 1;; i++ ) {	

				if ( !obj )
					break;

				if ((IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)) &&
					keeper_uses_currency_type (keeper->mob->currency_type, obj) ) {
					i--;
					if ( obj->next_content ) {
						obj = obj->next_content;
						continue;
					} else {
						obj = NULL;
						break;
					}
				}

/*** Prevent players from buying back items they've sold, and prevents all others from buying a sold item for 15 minutes to prevent abuse ***/

				if ( (obj->sold_by != ch->coldload_id && (time(0) - obj->sold_at <= 60 * 15)) ||
					(obj->sold_by == ch->coldload_id && (time(0) - obj->sold_at <= 60 * 60)) ) {
					i--;
					if ( obj->next_content ) {
						obj = obj->next_content;
						continue;
					} else {
						obj = NULL;
						break;
					}
				}

				if ( i == strtol (buf, NULL, 10) )
					break;

				obj = obj->next_content;
			}

			if ( !obj ) {
				send_to_char ("There are not that many items in the keeper's "
							  "inventory.\n", ch);
				return;
			}
		}

		else if ( !(obj = get_obj_in_list_vis_not_money (ch, buf,
						vtor (keeper->shop->store_vnum)->contents)) ) {
			name_to_ident (ch, buf2);
			snprintf (buf, MAX_STRING_LENGTH,   "%s %s", buf2, NO_SUCH_ITEM1);
			do_whisper (keeper, buf, 83);
			return;
		}

		if ( IS_WEARABLE (obj) && wants_off_size ) {
			if ( obj->size && obj->size != size ) {
				act ("$p isn't that size.", FALSE, ch, obj, 0, TO_CHAR);
				return;
			}
		}

		else if ( IS_WEARABLE (obj) && obj->size &&
			 obj->size != get_size (ch) && !regardless && obj->size != size ) {
			act ("$p wouldn't fit you.",
					FALSE, ch, obj, 0, TO_CHAR);
			act ("(End the buy command with ! if you really want it.)",
					FALSE, ch, obj, 0, TO_CHAR);
			return;
		}

		if ( !keeper_makes (keeper, obj->virtual) && buy_count > obj->count ) {
			name_to_ident (ch, buf2);
			snprintf (buf, MAX_STRING_LENGTH,   "%s I only have %d of that in stock at the moment.", buf2, obj->count);
			do_whisper (keeper, buf, 83);
			return;
		}
		else if ( keeper_makes (keeper, obj->virtual) && buy_count > obj->count )
			obj->count = buy_count;

		if ( buy_count < 1 )
			buy_count = 1;
	}

/*** cmd==2 which means do_accept ***/
	else { 

		if ( ch->delay_type != DEL_PURCHASE_ITEM || !ch->delay_obj ) {
			send_to_char ("There is no purchase in progress, I'm afraid.\n", ch);
			ch->delay_type = 0;
			ch->delay_info1 = 0;
			ch->delay_obj = NULL;
			ch->delay_ch = NULL;
			return;
		}

		if ( (obj = ch->delay_obj) && obj->in_room != keeper->shop->store_vnum ) {
			send_to_char ("That item is no longer available for purchase.\n", ch);
			ch->delay_type = 0;
			ch->delay_info1 = 0;
			ch->delay_obj = NULL;
			ch->delay_ch = NULL;
			return;
		}
		else if ( !obj ) {
			send_to_char ("That item is no longer available for purchase.\n", ch);
			ch->delay_type = 0;
			ch->delay_info1 = 0;
			ch->delay_obj = NULL;
			ch->delay_ch = NULL;
			return;
		}

		buy_count = ch->delay_info1;

		if ( buy_count < 1 )
			buy_count = 1;

		ch->delay_type = 0;
		ch->delay_info1 = 0;
		ch->delay_obj = NULL;
		ch->delay_ch = NULL;
	}
/*** end do_accept ***/

	keepers_cost = obj->coppers;

	if ( !IS_SET (obj->obj_flags.extra_flags, ITEM_PC_SOLD) )
    		keepers_cost *= econ_markup (keeper, obj);
	else keepers_cost *= econ_discount (keeper, obj);

    	keepers_cost = keepers_cost * buy_count;

	if ( keepers_cost < 1 )
		keepers_cost = 1;

	if ( GET_ITEM_TYPE (obj) == ITEM_DRINKCON &&
		 obj->o.drinkcon.volume > 0 &&
		 (tobj = vtoo (obj->o.drinkcon.liquid)) &&
		 GET_ITEM_TYPE (tobj) == ITEM_FLUID ) {
		if ( !IS_SET (tobj->obj_flags.extra_flags, ITEM_PC_SOLD) )
			markup = econ_markup (keeper, tobj);
		else markup = econ_discount (keeper, tobj);;
		keepers_cost += (tobj->coppers * obj->o.drinkcon.volume * markup);
	}

	if ( IS_SET (ch->room->room_flags, LAWFUL) &&
		 IS_SET (obj->obj_flags.extra_flags, ITEM_ILLEGAL) ) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s Those are illegal.  I can't sell them.", buf2);
		do_whisper (keeper, buf, 83);
		return;
	}

	if ( GET_ITEM_TYPE(obj) == ITEM_NPC_OBJECT ) {
		if ( cmd != 2 ) {
			if ( !*buf2 ) {
				send_to_char ("You'll need to specify a name for your new NPC, e.g. \"buy horse Shadowfax\".\n", ch);
				return;
			}
		}
		else {
			snprintf (buf2, MAX_STRING_LENGTH,   "%s", ch->delay_who);
			mem_free (ch->delay_who);
		}
		if ( strlen(buf2) > 26 ) {
			send_to_char ("The NPC's name must be 26 letters or fewer in length.\n", ch);
			return;
		}
		for ( i = 0; i < strlen(buf2); i++ ) {
			if ( !isalpha (buf2[i]) ) {
				send_to_char ("Invalid characters in the proposed NPC name.\n", ch);
				return;
			}
		}
		snprintf (name, MAX_STRING_LENGTH, "%s", buf2);
	}
	
/*** passed by do_barter to do_buy for bartering ***/
	if ( cmd == 1 )	{	

		name_to_ident (ch, buf);

		if ( keepers_cost < 20 ) {
			strcat (buf, " This isn't worth haggling over.");
			do_whisper (keeper, buf, 0);
			return;
		}

		if ( IS_SET (obj->obj_flags.extra_flags, ITEM_PC_SOLD) ) {
			strcat (buf, " I won't haggle over a used piece of merchandse.");
			do_whisper (keeper, buf, 0);
			return;
		}

		nobarter_flag = index_lookup (econ_flags, "nobarter");

		if ( nobarter_flag != -1 &&
			 IS_SET (keeper->shop->nobuy_flags, 1 << nobarter_flag) ) {
			strcat (buf, " I'm sorry, but I will not haggle.  My prices "
						 "are fixed, take it or leave it.");
			do_whisper (keeper, buf, 0);
			return;
		}

		if ( nobarter_flag != -1 &&
			 IS_SET (obj->econ_flags, 1 << nobarter_flag) ) {
			strcat (buf, " I'm sorry, but I will not haggle over the price "
						 "of this item.");
			do_whisper (keeper, buf, 0);
			return;
		}

/*** Search for existing entry in keepers negotiations list ***/

		for ( neg = keeper->shop->negotiations; neg; neg = neg->next ) {
			if ( neg->ch_coldload_id == ch->coldload_id &&
				 neg->obj_vnum == obj->virtual &&
				 neg->true_if_buying )
				break;
		}

		if ( neg ) {
			if ( neg->price_delta > 0 ) {
				strcat (buf, " No, no, I cannot afford to lower the price on "
							 "that again.");
				do_whisper (keeper, buf, 0);
				return;
			}

			strcat (buf, " You're persistent, aren't you?  I said no, and I "
						 "meant no.");
			do_whisper (keeper, buf, 0);
			return;
		}

		keeper_success = combat_roll (keeper->skills [SKILL_BARTER]);
		ch_success = combat_roll (ch->skills [SKILL_BARTER]);

		if      ( ch_success == SUC_CS && keeper_success == SUC_MS )
			discount = 5;
		else if ( ch_success == SUC_CS && keeper_success == SUC_MF )
			discount = 10;
		else if ( ch_success == SUC_CS && keeper_success == SUC_CF )
			discount = 15;

		else if ( ch_success == SUC_MS && keeper_success == SUC_MS )
			discount = 0;
		else if ( ch_success == SUC_MS && keeper_success == SUC_MF )
			discount = 5;
		else if ( ch_success == SUC_MS && keeper_success == SUC_CF )
			discount = 10;

		else if ( ch_success == SUC_MF && keeper_success == SUC_MS )
			discount = 0;
		else if ( ch_success == SUC_MF && keeper_success == SUC_MF )
			discount = 0;
		else if ( ch_success == SUC_MF && keeper_success == SUC_CF )
			discount = 5;

		else
			discount = 0;	/* A CF by ch */

		neg = malloc (sizeof (NEGOTIATION_DATA));
		neg->ch_coldload_id = ch->coldload_id;
		neg->obj_vnum = obj->virtual;
		neg->time_when_forgotten = time (NULL) + 6 * 60 * 60;  /* 6 hours */
		neg->price_delta = discount;
		neg->transactions = 0;
		neg->true_if_buying = 1;
		neg->next = keeper->shop->negotiations;
		keeper->shop->negotiations = neg;

		if ( discount == 0 ) {
			strcat (buf, " The price is as stated.  Take it or leave it.");
			do_whisper (keeper, buf, 0);
			return;
		}

		else if ( discount == 5 )
			strcat (buf, " I like your face, you seem an honest and "
						 "trustworthy sort.  You can have it for ");
		else if ( discount == 10 )
			strcat (buf, " It's just not my day, is it?  All right, you win, "
						 "I'll sell at your price.  It's yours for ");
		else
			strcat (buf, " My word!  I need to learn to count!  At this rate, "
						 "I'll be out of business in a week.  Here, here, take "
						 "your ill-gotten gain and begone.  Take it away for ");

		keepers_cost = keepers_cost * 100 / (100 + discount);

		keepers_cost = (int) keepers_cost;

		snprintf (ADDBUF, MAX_STRING_LENGTH, "%d copper%s", (int) keepers_cost, (int) keepers_cost > 1 ? "s" : "");

		strcat (buf, ".");

		do_whisper (keeper, buf, 0);

		return;
	}

	if ( keepers_cost < 1 )
		keepers_cost = 1;

	keepers_cost = (int) keepers_cost;

		/*** Look up negotiations for this ch/obj on keeper ***/

	for ( neg = keeper->shop->negotiations; neg; neg = neg->next ) {
		if ( neg->ch_coldload_id == ch->coldload_id &&
			 neg->obj_vnum == obj->virtual &&
			 neg->true_if_buying )
			break;
	}

	if ( neg && neg->price_delta )
		keepers_cost = keepers_cost * 100 / (100 + neg->price_delta);

	keepers_cost = (int) keepers_cost;

	if ( cmd != 2 ) {
		orig_count = obj->count;
		obj->count = buy_count;
		if ( obj->in_room != keeper->shop->store_vnum )
			obj->in_room = keeper->shop->store_vnum;
		
		temp_arg1 = obj_short_desc (obj);
		snprintf (buf, MAX_STRING_LENGTH,   "You have opted to purchase %s, for a total of %d copper%s. To confirm, please use the ACCEPT command.", temp_arg1, (int) keepers_cost, (int) keepers_cost > 1 ? "s" : "");
		act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
		ch->delay_type = DEL_PURCHASE_ITEM;
		ch->delay_obj = obj;
		ch->delay_info1 = buy_count;
		if ( ch->delay_info1 < 1 )
			ch->delay_info1 = 1;
		ch->delay_ch = keeper;
		obj->count = orig_count;
		if ( GET_ITEM_TYPE(obj) == ITEM_NPC_OBJECT )
			ch->delay_who = str_dup (name);
		return;
	}

	if ( !can_subtract_money (ch, keepers_cost, keeper->mob->currency_type) ) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s %s", buf2, MISSING_CASH2);
		do_whisper (keeper, buf, 83);

		return;
	}

	if ( obj->morphTime ) {
		obj->clock = vtoo(obj->virtual)->clock;
		obj->morphTime = time(0) + obj->clock * 10 * 60;
	}

	tobj = obj;
	obj_from_room (&tobj, buy_count);

	if ( keeper_makes (keeper, obj->virtual) &&
		!get_obj_in_list_num (obj->virtual, vtor(keeper->shop->store_vnum)->contents) ) {


		tobj->count = buy_count;
		delivery_cost = obj->coppers;
		delivery_cost *= econ_markup (keeper, obj);
		delivery_cost *= .50;
		delivery_cost = (int) delivery_cost;

		if ( keeper_has_money (keeper, delivery_cost) ) {
			temp_obj = load_object(obj->virtual);
			obj_to_room (temp_obj, keeper->shop->store_vnum);
			subtract_keeper_money (keeper, delivery_cost);

		}
	}

	act ("$n buys $p.", FALSE, ch, tobj, 0, TO_ROOM);
	act ("$N sells you $p.", FALSE, ch, tobj, keeper, TO_CHAR);
	act ("You sell $N $p.", FALSE, keeper, tobj, ch, TO_CHAR);

	subtract_money (ch, keepers_cost, keeper->mob->currency_type);

	name_to_ident (ch, buf2);

	if ( ch->room->zone == 5 || ch->room->zone == 6 ) {
		snprintf (buf, MAX_STRING_LENGTH,   "%s You're lucky I gave it to you for %d copper%s, maggot.", buf2, (int) keepers_cost, (int) keepers_cost > 1 ? "s" : "");
	} else {
		snprintf (buf, MAX_STRING_LENGTH,   "%s A veritable steal at ", buf2);
       	 	snprintf (ADDBUF, MAX_STRING_LENGTH,
       	                "%d copper%s! Enjoy it, my friend.", (int) keepers_cost,
        	               (int) keepers_cost > 1 ? "s" : "");
	}

	do_whisper (keeper, buf, 83);

	money_to_storeroom (keeper, keepers_cost);

	if ( GET_ITEM_TYPE(tobj) == ITEM_NPC_OBJECT ) {
		*name = toupper (*name);
		if ( tobj->o.od.value[0] == 0 || !(horse = load_mobile(tobj->o.od.value[0])) ) {
			send_to_char ("There seems to be a problem. Please inform the staff.\n", ch);
			return;
		}
		send_to_room ("\n", keeper->in_room);
		
		temp_arg1 = char_short(horse);
		snprintf (buf, MAX_STRING_LENGTH,   "%s is released into your custody.", temp_arg1);
		*buf = toupper (*buf);
		snprintf (buf2, MAX_STRING_LENGTH,   "#3%s", buf);
		act (buf2, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);		
		
		temp_arg1 = char_short(horse);
		temp_arg2 = char_short(ch);
		snprintf (buf, MAX_STRING_LENGTH,   "%s#0 is released into #3%s#0's custody.", temp_arg1, temp_arg2);
		*buf = toupper (*buf);
		
		snprintf (buf2, MAX_STRING_LENGTH,   "#3%s", buf);
		act (buf2, FALSE, ch, 0, 0, TO_NOTVICT | TO_ACT_FORMAT);
		char_to_room (horse, ch->in_room);
		SET_BIT (horse->act, ACT_STAYPUT);
		
		snprintf (buf, MAX_STRING_LENGTH,   "%s %s", horse->name, name);
		mem_free (horse->name);
		horse->name = str_dup (buf);
		
		if ( get_clan (ch, "mm_denizens", &flags) ) {
			add_clan (horse, "mm_denizens", CLAN_MEMBER);
		} 
		else if ( get_clan (ch, "osgi_citizens", &flags) ) {
			add_clan (horse, "osgi_citizens", CLAN_MEMBER);
		}
		
		if ( IS_SET (horse->act, ACT_MOUNT) )
			hitch_char (ch, horse);
		
		if ( !IS_NPC (ch) ) {
			horse->mob->owner = str_dup (ch->tname);
			save_char (ch, TRUE);
		}
		return;
	}

	if ( GET_ITEM_TYPE(obj) == ITEM_LIGHT ) {
		tobj->o.od.value[1] = obj->o.od.value[1];
	}

	if ( IS_WEARABLE (tobj) ) {
		if ( size != -1 )
			tobj->size = size;
		else if ( !regardless || !tobj->size )
			tobj->size = get_size (ch);
	}

	if ( GET_ITEM_TYPE (tobj) == ITEM_CONTAINER && tobj->o.od.value[2] > 0 && vtoo (tobj->o.od.value[2]) && GET_ITEM_TYPE (vtoo(tobj->o.od.value[2])) == ITEM_KEY ) {
		obj = load_object (tobj->o.od.value[2]);
		obj->o.od.value[1] = tobj->coldload_id;
		obj_to_obj (obj, tobj);
		obj = load_object (tobj->o.od.value[2]);
		obj->o.od.value[1] = tobj->coldload_id;
		obj_to_obj (obj, tobj);
	}

	if ( ch->right_hand && ch->left_hand ) {
		snprintf (buf, MAX_STRING_LENGTH,   "%s Your hands seem to be full, so I'll just set this down for you to pick up when you've a chance.", ch->tname);
		send_to_char ("\n", ch);
		do_whisper (keeper, buf, 0);
		(void)one_argument (obj->name, buf2);
		send_to_char ("\n", ch);
		snprintf (buf, MAX_STRING_LENGTH,   ": sets *%s down nearby, nodding to ~%s.", buf2, ch->tname);
		command_interpreter (keeper, buf);
		obj_to_room (tobj, keeper->in_room);
	}
	else obj_to_char (tobj, ch);

	if ( neg )
		if ( !neg->transactions++ )
			skill_use (ch, SKILL_BARTER, 0);
			
	return;
}


/**
 *  Function: do_sell
 *
 *  Allows character to sell an item to a shopkeeper.
 *
 *		\param ch character doing the selling
 *		\param argument type of item, count, and specific shopkeeper
 *		\param cmd 1 if do_sell is called by do_barter command
 *
 * 		Useage:
 *			sell [count] item [keeper]
 *
 *		Removes the item from the charater, and gives money to them.
 *		The cost is removed from the keepers storeroom. 
 *
 *
 *
 */
void do_sell (CHAR_DATA *ch, char *argument, int cmd) 
{
	int					objs_in_storage = 0;
	int					sell_count = 1;
	int					nobarter_flag = 0;
	int					keeper_success = 0;
	int					ch_success = 0;
	int					discount = 0;
	int					same_obj = 0;
	float				liquid_discount = 0;
	float				keepers_cost = 0;
	char				buf [MAX_STRING_LENGTH] = {'\0'};
	char				buf2 [MAX_STRING_LENGTH] = {'\0'};
	OBJ_DATA			*obj = NULL;
	OBJ_DATA			*tobj = NULL;
	CHAR_DATA			*keeper = NULL;
	CHAR_DATA			*tch = NULL;
	ROOM_DATA			*room = NULL;
	NEGOTIATION_DATA	*neg = NULL;
	
	argument = one_argument (argument, buf);

	room = ch->room;

	if ( isdigit (*buf) ) {
		sell_count = strtol (buf, NULL, 10);
		argument = one_argument (argument, buf);
		if ( sell_count > 50 ) {
			send_to_char ("Sorry, but you can only sell up to 50 items at a time.\n", ch);
			return;
		}
	}

	if ( !*buf ) {
		send_to_char ("Sell what?\n", ch);
		return;
	}

	if ( (keeper = get_char_room_vis (ch, buf)) )
		argument = one_argument (argument, buf);

	else {
		for ( tch = room->people; tch; tch = tch->next_in_room )
			if ( tch != ch && IS_SET (tch->flags, FLAG_KEEPER) )
				break;

		keeper = tch;

		if ( !*buf ) {
			act ("Sell what to $N?", TRUE, ch, 0, keeper, TO_CHAR);
			return;
		}
	}

	if ( !keeper ) {
		send_to_char ("There is no merchant here.\n", ch);
		return;
	}

	if ( keeper == ch ) {
		send_to_char ("You can't sell to yourself!\n", ch);
		return;
	}

	if ( !keeper->shop || !IS_NPC (keeper) ) {
		act ("$N does not seem to be a shopkeeper.", TRUE, ch, 0, keeper, TO_CHAR | TO_ACT_FORMAT);
		return;
	}

	if ( GET_POS (keeper) <= POSITION_SLEEPING ) {
		act ("$N is not conscious.", TRUE, ch, 0, keeper, TO_CHAR);
		return;
	}

	if ( GET_POS (keeper) == POSITION_FIGHTING ) {
		do_say (keeper, "Have you no eyes!  I'm fighting for my life!", 0);
		return;
	}

	if ( !keeper->shop ||
		 (keeper->shop->shop_vnum &&
		  keeper->shop->shop_vnum != ch->in_room) ) {
		do_say (keeper, "I'm sorry.  Please catch me when I'm in my shop.", 0);
		return;
	}

	if ( !(room = vtor (keeper->shop->store_vnum)) ) {
		do_say (keeper, "I've lost my business.  You'll have to go elsewhere.",
				0);
		return;
	}

	if ( !room->psave_loaded )
		load_save_room (room);

	if ( !GET_TRUST (ch) && !CAN_SEE (keeper, ch) ) {
		do_say (keeper, "Who's there?", 0);
		return;
	}

	if ( !(obj = get_obj_in_list_vis (ch, buf, ch->right_hand)) &&
		!(obj = get_obj_in_list_vis (ch, buf, ch->left_hand)) ) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s %s", buf2, NO_SUCH_ITEM2);
		do_whisper (keeper, buf, 83);
		return;
	}

	if ( obj->count < sell_count )
		sell_count = obj->count;

	if ( sell_count < 1 )
		sell_count = 1;

	keepers_cost = obj->coppers;
    	keepers_cost *= econ_discount (keeper, obj);
    	keepers_cost = keepers_cost * sell_count;
	keepers_cost = (int) keepers_cost;

	if ( !keeper_makes (keeper, obj->virtual) ) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s %s", buf2, DO_NOT_BUY);
		do_whisper (keeper, buf, 83);
		return;
	}

	if ( obj->econ_flags & keeper->shop->nobuy_flags || (GET_ITEM_TYPE(obj) == ITEM_LIGHT && !obj->o.od.value[1])) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s No, I wouldn't even think of buying that.", buf2);
		do_whisper (keeper, buf, 83);
		return;
	}
				
	if ( IS_SET (ch->room->room_flags, LAWFUL) &&
		 IS_SET (obj->obj_flags.extra_flags, ITEM_ILLEGAL) ) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s I can't buy that.  It's illegal to possess.", buf2);
		do_whisper (keeper, buf, 83);
		return;
	}



	if ( vtor (keeper->shop->store_vnum) ) {

		objs_in_storage = 0;

		for ( tobj = vtor (keeper->shop->store_vnum)->contents;
			  tobj;
			  tobj = tobj->next_content ) {
			if ( !(IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL)) && IS_SET (tobj->obj_flags.extra_flags, ITEM_PC_SOLD) )
				objs_in_storage++;
			if ( tobj->virtual == obj->virtual )
				same_obj += tobj->count;
		}

		if ( (!IS_SET (obj->obj_flags.extra_flags, ITEM_STACK) && same_obj >= 6) || same_obj >= 24 ) {
			name_to_ident (ch, buf2);
			snprintf (buf, MAX_STRING_LENGTH,   "%s I have quite enough of those for now, thank you; try back again later.", buf2);
			do_whisper (keeper, buf, 83);
			return;
		}

		if ( objs_in_storage > 125 ) {
			name_to_ident (ch, buf2);
			snprintf (buf, MAX_STRING_LENGTH,   "%s I have too much stuff as it is.  Perhaps you'd like to purchase something instead?", buf2);
			do_whisper (keeper, buf, 83);
			return;
		}
	}

	if ( GET_ITEM_TYPE (obj) == ITEM_DRINKCON &&
		 obj->o.drinkcon.volume > 0 &&
		 (tobj = vtoo (obj->o.drinkcon.liquid)) &&
		 GET_ITEM_TYPE (tobj) == ITEM_FLUID ) {
		liquid_discount = econ_discount (keeper, tobj);
		keepers_cost += (tobj->coppers * obj->o.drinkcon.volume * liquid_discount);
	}

/*** passed by do_barter to do_sell for bartering ***/
	if ( cmd == 1 )	{
		if ( sell_count > 1 ) {
			send_to_char ("You can only barter for one item at a time.\n", ch);
			return;
		}

		name_to_ident (ch, buf);

		if ( keepers_cost < 20 ) {
			strcat (buf, " This isn't worth haggling over.");
			do_whisper (keeper, buf, 0);
			return;
		}

		nobarter_flag = index_lookup (econ_flags, "nobarter");

		if ( nobarter_flag != -1 &&
			 IS_SET (keeper->shop->nobuy_flags, 1 << nobarter_flag) ) {
			strcat (buf, " I'm sorry, but I will not haggle.  My prices "
						 "are fixed, take it or leave it.");
			do_whisper (keeper, buf, 0);
			return;
		}

                if ( IS_SET (obj->obj_flags.extra_flags, ITEM_PC_SOLD) ) {
                        strcat (buf, " I won't haggle over a used piece of merchandse.");
                        do_whisper (keeper, buf, 0);
                        return;
                }

		if ( nobarter_flag != -1 &&
			 IS_SET (obj->econ_flags, 1 << nobarter_flag) ) {
			strcat (buf, " I'm sorry, but I will not haggle over the price "
						 "of this item.");
			do_whisper (keeper, buf, 0);
			return;
		}

			/*** Search for existing entry in keepers negotiations list ***/

		for ( neg = keeper->shop->negotiations; neg; neg = neg->next ) {
			if ( neg->ch_coldload_id == ch->coldload_id &&
				 neg->obj_vnum == obj->virtual &&
				 !neg->true_if_buying )
				break;
		}

		if ( neg ) {
			if ( neg->price_delta > 0 ) {
				strcat (buf, " No, no, I will not pay any higher a price.");
				do_whisper (keeper, buf, 0);
				return;
			}

			strcat (buf, " Listen, as much as I like you, I simply cannot "
						 "offer you what you're asking.");
			do_whisper (keeper, buf, 0);
			return;
		}

		keeper_success = combat_roll (keeper->skills [SKILL_BARTER]);
		ch_success = combat_roll (ch->skills [SKILL_BARTER]);

		if      ( ch_success == SUC_CS && keeper_success == SUC_MS )
			discount = 5;
		else if ( ch_success == SUC_CS && keeper_success == SUC_MF )
			discount = 10;
		else if ( ch_success == SUC_CS && keeper_success == SUC_CF )
			discount = 15;

		else if ( ch_success == SUC_MS && keeper_success == SUC_MS )
			discount = 0;
		else if ( ch_success == SUC_MS && keeper_success == SUC_MF )
			discount = 5;
		else if ( ch_success == SUC_MS && keeper_success == SUC_CF )
			discount = 10;

		else if ( ch_success == SUC_MF && keeper_success == SUC_MS )
			discount = 0;
		else if ( ch_success == SUC_MF && keeper_success == SUC_MF )
			discount = 0;
		else if ( ch_success == SUC_MF && keeper_success == SUC_CF )
			discount = 5;

		else
		/*** A CF by ch ***/
			discount = 0;	

		neg = malloc (sizeof (NEGOTIATION_DATA));
		neg->ch_coldload_id = ch->coldload_id;
		neg->obj_vnum = obj->virtual;
		neg->time_when_forgotten = time (NULL) + 6 * 60 * 60; /* 6 hours */
		neg->price_delta = discount;
		neg->transactions = 0;
		neg->true_if_buying = 0;
		neg->next = keeper->shop->negotiations;
		keeper->shop->negotiations = neg;

		if ( discount == 0 ) {
			strcat (buf, " Sorry, but it's just not worth more than my "
						 "initial offer.");
			do_whisper (keeper, buf, 0);
			return;
		}

		else if ( discount == 5 )
			strcat (buf, " I've been looking for these.  It's a pleasure doing "
						 "business with you.  I'll pay you ");
		else if ( discount == 10 )
			strcat (buf, " Perhaps if I go back to bed now, I can salvage some "
						 "small part of my self respect.  I'll pay you ");
		else
			strcat (buf, " It is a dark day.  I'll have to sell my home and "
						 "business just to recoup what I've lost this day."
						 "  I'll give you ");

		keepers_cost = keepers_cost * (100 + discount) / 100;

		snprintf (ADDBUF, MAX_STRING_LENGTH, "%d copper%s", (int) keepers_cost, (int) keepers_cost > 1 ? "s" : "");

		strcat (buf, ".");

		do_whisper (keeper, buf, 0);

		return;
	}

		/* Look up negotiations for this ch/obj on keeper */

	for ( neg = keeper->shop->negotiations; neg; neg = neg->next ) {
		if ( neg->ch_coldload_id == ch->coldload_id &&
			 neg->obj_vnum == obj->virtual &&
			 !neg->true_if_buying )
			break;
	}

	keepers_cost = (int) keepers_cost;



	if ( keepers_cost < 1 ) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s Bah, that isn't even worth my time!", buf2);
		do_whisper (keeper, buf, 83);
		return;
	}

	if ( neg && neg->price_delta )
		keepers_cost = keepers_cost * (100 + neg->price_delta) / 100;




	if ( !keeper_has_money (keeper, keepers_cost) ) {

		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s %s", buf2, MISSING_CASH1);

		do_whisper (keeper, buf, 83);

		if ( !IS_SET (keeper->act, ACT_PCOWNED) ||
			 !vtor (keeper->shop->store_vnum) )
			return;

		return;
	}
	

	act ("$n sells $p.", FALSE, ch, obj, 0, TO_ROOM);
	act ("You sell $p.", FALSE, ch, obj, 0, TO_CHAR);
	send_to_char ("\n", ch);

	name_to_ident (ch, buf2);
	snprintf (buf, MAX_STRING_LENGTH, "%s Here's the amount we've agreed upon.", buf2);

			/*** Pay customer ***/

	do_whisper (keeper, buf, 83);

	subtract_keeper_money (keeper, keepers_cost);
	obj_from_char (&obj, sell_count);
	
	keeper_money_to_char (keeper, ch, keepers_cost);

	


	if ( keeper_makes (keeper, obj->virtual) )
		extract_obj (obj);
	else {
		SET_BIT (obj->obj_flags.extra_flags, ITEM_PC_SOLD);
		obj->sold_at = (int) time(0);
		obj->sold_by = ch->coldload_id;
		obj_to_room (obj, keeper->shop->store_vnum);
	}

	if ( neg )
		if ( !neg->transactions++ )
			skill_use (ch, SKILL_BARTER, 0);
			
	return;
}

/**
 *  Function: do_value
 *
 *  Determines the value of an item when selling to shopkeepers.
 *
  *		\param ch character asking the price
 *		\param argument item and the shopkeeper
 *		\param cmd not used
 *
 *		Useage:
 *			value item [keeper]
 *			
 *		Informs the character what the item would be worth to the shopkeeper,
 *		it was to be sold.
 *
 *
 */
void do_value (CHAR_DATA *ch, char *argument, int cmd) 
{
	float				keepers_cost = 0;
	float				discount = 0;
	char				buf [MAX_STRING_LENGTH] = {'\0'};
	char				buf2 [MAX_STRING_LENGTH] = {'\0'};
	char				buf3 [MAX_STRING_LENGTH] = {'\0'};
	OBJ_DATA			*obj = NULL;
	OBJ_DATA			*tobj = NULL;
	ROOM_DATA			*room = NULL;
	CHAR_DATA			*keeper = NULL;
	CHAR_DATA			*tch = NULL;
	NEGOTIATION_DATA	*neg = NULL;

	argument = one_argument (argument, buf);

	if ( !*buf ) {
		send_to_char ("Appraise what?\n", ch);
		return;
	}

	room = ch->room;

	if ( (keeper = get_char_room_vis (ch, buf)) )
		argument = one_argument (argument, buf);

	else {
		for ( tch = room->people; tch; tch = tch->next_in_room )
			if ( tch != ch && IS_SET (tch->flags, FLAG_KEEPER) )
				break;

		keeper = tch;

		if ( !*buf ) {
			act ("Have $N appraise what?", TRUE, ch, 0, keeper, TO_CHAR);
			return;
		}
	}

	if ( !keeper ) {
		send_to_char ("There is no merchant here.\n", ch);
		return;
	}

	if ( !keeper->shop ) {
		act ("$N does not seem to be a shopkeeper.", TRUE, ch, 0, keeper, TO_CHAR | TO_ACT_FORMAT);
		return;
	}

	if ( GET_POS (keeper) <= POSITION_SLEEPING ) {
		act ("$N is not conscious.", TRUE, ch, 0, keeper, TO_CHAR);
		return;
	}

	if ( GET_POS (keeper) == POSITION_FIGHTING ) {
		do_say (keeper, "Have you no eyes!  I'm fighting for my life!", 0);
		return;
	}

	if ( !(obj = get_obj_in_list_vis (ch, buf, ch->right_hand)) &&
		!(obj = get_obj_in_list_vis (ch, buf, ch->left_hand)) ) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s %s", buf2, NO_SUCH_ITEM2);
		do_whisper (keeper, buf, 83);
		return;
	}

	if ( !keeper_makes (keeper, obj->virtual)) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s %s", buf2, DO_NOT_BUY);
		do_whisper (keeper, buf, 83);
		return;
	}

	if (obj->econ_flags & keeper->shop->nobuy_flags ||
		(keepers_cost == 0 && (IS_SET (obj->obj_flags.extra_flags, ITEM_CAPITAL)))) {
		name_to_ident (ch, buf2);
		snprintf (buf, MAX_STRING_LENGTH,   "%s No, I wouldn't even think of buying that.", buf2);
		do_whisper (keeper, buf, 83);
		return;
	}

	if ( !GET_TRUST (ch) && !CAN_SEE (keeper, ch) ) {
		do_say (keeper, "Who's there?", 0);
		return;
	}

	keepers_cost = obj->coppers;
    keepers_cost *= econ_discount (keeper, obj);
	keepers_cost = (int) keepers_cost;

	if ( GET_ITEM_TYPE (obj) == ITEM_DRINKCON &&
		 obj->o.drinkcon.volume > 0 &&
		 (tobj = vtoo (obj->o.drinkcon.liquid)) &&
		 GET_ITEM_TYPE (tobj) == ITEM_FLUID ) {
		discount = econ_discount (keeper, tobj);
		keepers_cost += (tobj->coppers * obj->o.drinkcon.volume * discount);
	}

	for ( neg = keeper->shop->negotiations; neg; neg = neg->next ) {
		if ( neg->ch_coldload_id == ch->coldload_id &&
			 neg->obj_vnum == obj->virtual &&
			 !neg->true_if_buying )
			break;
	}

	if ( neg && neg->price_delta )
		keepers_cost = keepers_cost * (100 + neg->price_delta) / 100;

	name_to_ident (ch, buf2);

	*buf3 = '\0';

	snprintf (buf3, MAX_STRING_LENGTH, "%d copper%s", (int) keepers_cost,
				   (int) keepers_cost > 1 ? "s" : "");

	keepers_cost = (int) keepers_cost;

	if ( !keepers_cost )
		snprintf (buf, MAX_STRING_LENGTH,   "%s I'm afraid that isn't even worth my time...", buf2);
	else if ( neg && neg->price_delta )
		snprintf (buf, MAX_STRING_LENGTH,   "%s Remember, I said I'd buy it for %s?", buf2, buf3);
	else
		snprintf (buf, MAX_STRING_LENGTH,   "%s I'd buy %s for... %s.", buf2, obj->count > 1 ? "those" : "that", buf3);

	do_whisper (keeper, buf, 83);

	return;
}
/**
 *  Function: do_barter
 *
 *  Allows character to negotiate a better price for purchase or sale.
 *
 *		\param ch character doing the bartering
 *		\param argument sell or buy
 *		\param cmd not used
 *
 *  	Calls do_buy or do_sell with right arguments for bartering.
 *		Also prints a help line if command is in the wrong format.
 *
 */

void do_barter (CHAR_DATA *ch, char *argument, int cmd)
{
	char	buf [MAX_STRING_LENGTH] = {'\0'};

	if ( !real_skill (ch, SKILL_BARTER) ) {
		send_to_char ("You're not convincing enough to barter, unfortunately.\n", ch);
		return;
	}

	argument = one_argument (argument, buf);

	if ( is_abbrev (buf, "buy") )
		do_buy (ch, argument, 1);
	else if ( is_abbrev (buf, "sell") )
		do_sell (ch, argument, 1);
	else
		send_to_char ("barter sell ITEM    or\n barter buy ITEM\n", ch);
		
	return;
}


/**
 *  Function: vnpc_customer
 *
 *  Simulate vnpc purchase for a shopkeeper
 *
 *		\param keeper the keeper with the virtual business
 *		\param purse amount the vnpc has to spend
 *
 *  	Simulates a purchase of random items. Shopkeeper stock is depleted,
 *		and the money is added to his storeroom.
 *
 *
 *
 */
int vnpc_customer (CHAR_DATA *keeper, int purse)
{
	ROOM_DATA	*room = NULL;
	OBJ_DATA	*tobj = NULL;
	OBJ_DATA	*drink = NULL;
	char		buf [MAX_STRING_LENGTH] = {'\0'};
	int			items_in_list = 0;
	int			target_item = 0;
	int			i = 0;
	int			required_check = 0;
	int			item_cost = 0;
	int			delivery_cost = 0;
	OBJ_DATA	*temp_obj = NULL;

	if ( !IS_NPC (keeper) || !IS_SET (keeper->flags, FLAG_KEEPER) || !keeper->shop )
		return purse;

	if ( IS_SET (keeper->act, ACT_NOVNPC) )
		return purse;

	if ( !(room = vtor(keeper->shop->store_vnum)) )
		return purse;

	for ( tobj = room->contents; tobj; tobj = tobj->next_content ) {
		if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL))
			continue;
		items_in_list++;
	}

	if ( !items_in_list )
		return purse;

	if ( items_in_list == 1 )
		target_item = 1;
	else target_item = number(1, items_in_list);

	for ( tobj = room->contents; tobj; tobj = tobj->next_content ) {
		if (IS_SET (tobj->obj_flags.extra_flags, ITEM_CAPITAL))
			continue;
		i++;
		if ( i == target_item )
			break;			
	}

	if ( !tobj )
		return purse;

	item_cost = tobj->coppers;

	if ( !IS_SET (tobj->obj_flags.extra_flags, ITEM_PC_SOLD) )
		item_cost *= econ_markup(keeper, tobj);
    	else item_cost *= econ_discount (keeper, tobj);

	item_cost = MAX(1, item_cost);

	if ( GET_ITEM_TYPE (tobj) == ITEM_DRINKCON &&
		tobj->o.drinkcon.volume > 0 &&
		(drink = vtoo (tobj->o.drinkcon.liquid)) &&
		GET_ITEM_TYPE (drink) == ITEM_FLUID ) {
		item_cost += drink->coppers * tobj->o.drinkcon.volume;
		if ( !IS_SET (tobj->obj_flags.extra_flags, ITEM_PC_SOLD) )
			item_cost *= econ_markup (keeper, drink);
		else item_cost *= econ_discount (keeper, drink);
	}

	if ( item_cost > VNPC_COPPER_PURSE )
		return item_cost;

	required_check = 55 - (item_cost/4);
	required_check = MAX(3, required_check);

	if ( number(1,100) <= required_check ) {
		snprintf (buf, MAX_STRING_LENGTH,   "Item VNUM: %d Cost: %d Percent Chance: %d Sold!", tobj->virtual, item_cost, required_check);
               	delivery_cost = tobj->coppers;
               	delivery_cost *= econ_markup (keeper, tobj);
               	delivery_cost *= .75;
               	delivery_cost = (int) delivery_cost;
		target_item = tobj->virtual;
		if ( tobj->count > 1 )
			tobj->count--;
		else extract_obj (tobj);
		money_to_storeroom (keeper, item_cost);
        	if ( keeper_makes (keeper, target_item) && !get_obj_in_list_num (target_item, room->contents) ) {
        			temp_obj = load_object(target_item);
                	if ( keeper_has_money (keeper, delivery_cost) ) {
                       		subtract_keeper_money (keeper, delivery_cost);
                       		obj_to_room (temp_obj, keeper->shop->store_vnum);
                	}
        	}
	}
	else snprintf (buf, MAX_STRING_LENGTH,   "Item Cost: %d Percent Chance: %d Not Sold", item_cost, required_check);

	return item_cost;
}