/* ************************************************************************
*  file: shop.c , Shop module.                            Part of DIKUMUD *
*  Usage: Procedures handling shops and shopkeepers.                      *
*  Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
************************************************************************* */

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

#include "structs.h"
#include "comm.h"
#include "handler.h"
#include "db.h"
#include "interpreter.h"
#include "utils.h"

#define SHOP_FILE "tinyworld.shp"
#define MAX_TRADE 5
#define MAX_PROD 5

extern struct str_app_type str_app[];
extern struct index_data *mob_index;

char *fread_string(FILE *fl);

struct shop_data
{
	int producing[MAX_PROD];/* Which item to produce (virtual)      */
	float profit_buy;       /* Factor to multiply cost with.        */
	float profit_sell;      /* Factor to multiply cost with.        */
	byte type[MAX_TRADE];   /* Which item to trade.                 */
	char *no_such_item1;    /* Message if keeper hasn't got an item */
	char *no_such_item2;    /* Message if player hasn't got an item */
	char *missing_cash1;    /* Message if keeper hasn't got cash    */
	char *missing_cash2;    /* Message if player hasn't got cash    */
	char *do_not_buy;			/* If keeper dosn't buy such things. 	*/
	char *message_buy;      /* Message when player buys item        */
	char *message_sell;     /* Message when player sells item       */
	int temper1;           	/* How does keeper react if no money    */
	int temper2;           	/* How does keeper react when attacked  */
	int keeper;             /* The mobil who owns the shop (virtual)*/
	int with_who;		/* Who does the shop trade with?	*/
	int in_room;		/* Where is the shop?			*/
	int open1,open2;	/* When does the shop open?		*/
	int close1,close2;	/* When does the shop close?		*/
};


extern struct room_data *world;
extern struct time_info_data time_info;

struct shop_data *shop_index;
int number_of_shops;

int is_ok(struct char_data *keeper, struct char_data *ch, int shop_nr)
{
	if (shop_index[shop_nr].open1>time_info.hours){
		do_say(keeper,
		"Come back later!",17);
		return(FALSE);
	} else if (shop_index[shop_nr].close1<time_info.hours)
		if (shop_index[shop_nr].open2>time_info.hours){
			do_say(keeper,
			"Sorry, we have closed, but come back later.",17);
			return(FALSE);
		} else if (shop_index[shop_nr].close2<time_info.hours){
			do_say(keeper,
			"Sorry, come back tomorrow.",17);
			return(FALSE);
		};

	if(!(CAN_SEE(keeper,ch)))
	{
		do_say(keeper,
		"I don't trade with someone I can't see!",17);
		return(FALSE);
	};

	switch(shop_index[shop_nr].with_who){
		case 0 : return(TRUE);
		case 1 : return(TRUE);
		default : return(TRUE);
	};
}

int trade_with(struct obj_data *item, int shop_nr)
{
	int counter;

   if(item->obj_flags.cost < 1) return(FALSE);

	for(counter=0;counter<MAX_TRADE;counter++)
		if(shop_index[shop_nr].type[counter]==item->obj_flags.type_flag)
			return(TRUE);
	return(FALSE);
}

int shop_producing(struct obj_data *item, int shop_nr)
{
	int counter;

	if(item->item_number<0) return(FALSE);

	for(counter=0;counter<MAX_PROD;counter++)
		if (shop_index[shop_nr].producing[counter] == item->item_number)
			return(TRUE);
	return(FALSE);
}

void shopping_buy( char *arg, struct char_data *ch,
	 struct char_data *keeper, int shop_nr)
{
	char argm[100], buf[MAX_STRING_LENGTH];
	struct obj_data *temp1;
	struct char_data *temp_char;

	if(!(is_ok(keeper,ch,shop_nr)))
		return;
	

	one_argument(arg, argm);
	if(!(*argm))
	{
		sprintf(buf,
		"%s what do you want to buy??"
		,GET_NAME(ch));
		do_tell(keeper,buf,19);
		return;
	};
	if(!( temp1 = 
		get_obj_in_list_vis(ch,argm,keeper->carrying)))
	{
		sprintf(buf,
		shop_index[shop_nr].no_such_item1
		,GET_NAME(ch));
		do_tell(keeper,buf,19);
		return;
	}

	if(temp1->obj_flags.cost <= 0)
	{
		sprintf(buf,
		shop_index[shop_nr].no_such_item1
		,GET_NAME(ch));
		do_tell(keeper,buf,19);
		extract_obj(temp1);
		return;
	}

	if(GET_GOLD(ch) < (int) (temp1->obj_flags.cost*
		shop_index[shop_nr].profit_buy) && GET_LEVEL(ch)<22)
	{
		sprintf(buf,
		shop_index[shop_nr].missing_cash2,
		GET_NAME(ch));
		do_tell(keeper,buf,19);

		switch(shop_index[shop_nr].temper1)
		{
			case 0:
				do_action(keeper,GET_NAME(ch),30);
				return;
			case 1:
				do_emote(keeper,"smokes on his joint",36);
				return;
			default:
				return;
		}
	}
	
	if ((IS_CARRYING_N(ch) + 1 > CAN_CARRY_N(ch)))
	{
		sprintf(buf,"%s : You can't carry that many items.\n\r", 
			fname(temp1->name));
		send_to_char(buf, ch);
		return;
	}

	if ((IS_CARRYING_W(ch) + temp1->obj_flags.weight) > CAN_CARRY_W(ch))
	{
		sprintf(buf,"%s : You can't carry that much weight.\n\r", 
			fname(temp1->name));
		send_to_char(buf, ch);
		return;
	}


	act("$n buys $p.", FALSE, ch, temp1, 0, TO_ROOM);

	sprintf(buf,
		shop_index[shop_nr].message_buy,
		GET_NAME(ch),
		(int) (temp1->obj_flags.cost*
			shop_index[shop_nr].profit_buy));
	do_tell(keeper,buf,19);
	sprintf(buf,"You now have %s.\n\r",
		temp1->short_description);
	send_to_char(buf,ch);
   if(GET_LEVEL(ch)<22)
		GET_GOLD(ch) -= (int)(temp1->obj_flags.cost*
			shop_index[shop_nr].profit_buy);

   GET_GOLD(keeper) += (int)(temp1->obj_flags.cost*
      shop_index[shop_nr].profit_buy);

	/* Test if producing shop ! */
	if(shop_producing(temp1,shop_nr))
		temp1 = read_object(temp1->item_number, REAL);
	else
		obj_from_char(temp1);

	obj_to_char(temp1,ch);

	return; 
}

void shopping_sell( char *arg, struct char_data *ch,
	 struct char_data *keeper,int shop_nr)
{
	char argm[100], buf[MAX_STRING_LENGTH];
	struct obj_data *temp1;
	struct char_data *temp_char;

	if(!(is_ok(keeper,ch,shop_nr)))
		return;

	one_argument(arg, argm);

	if(!(*argm))
	{
		sprintf(buf,
		"%s What do you want to sell??"
		,GET_NAME(ch));
		do_tell(keeper,buf,19);
		return;
	}

	if(!( temp1 = get_obj_in_list_vis(ch,argm,ch->carrying)))
	{
		sprintf(buf,
		shop_index[shop_nr].no_such_item2
		,GET_NAME(ch));
		do_tell(keeper,buf,19);
		return;
	}

	if(!(trade_with(temp1,shop_nr))||(temp1->obj_flags.cost<1))
	{
		sprintf(buf,
		shop_index[shop_nr].do_not_buy,
		GET_NAME(ch));
		do_tell(keeper,buf,19);
		return;
	}

	if (GET_GOLD(keeper)<(int) (temp1->obj_flags.cost*
		shop_index[shop_nr].profit_sell)) {
		sprintf(buf,shop_index[shop_nr].missing_cash1
		,GET_NAME(ch));
		do_tell(keeper,buf,19);
		return;
	}

	act("$n sells $p.", FALSE, ch, temp1, 0, TO_ROOM);

	sprintf(buf,shop_index[shop_nr].message_sell,
		GET_NAME(ch),(int) (temp1->obj_flags.cost*
			shop_index[shop_nr].profit_sell));
	do_tell(keeper,buf,19);
	sprintf(buf,"The shopkeeper now has %s.\n\r",
		temp1->short_description);
	send_to_char(buf,ch);
	GET_GOLD(ch) += (int) (temp1->obj_flags.cost*
		shop_index[shop_nr].profit_sell);
	GET_GOLD(keeper) -= (int) (temp1->obj_flags.cost*
		shop_index[shop_nr].profit_sell);

	if((get_obj_in_list(argm,keeper->carrying)) || 
   (GET_ITEM_TYPE(temp1) == ITEM_TRASH))
		extract_obj(temp1);
	else
	{
		obj_from_char(temp1);
		obj_to_char(temp1,keeper);
	}

	return;
}

void shopping_value( char *arg, struct char_data *ch, 
	struct char_data *keeper, int shop_nr)
{
	char argm[100], buf[MAX_STRING_LENGTH];
	struct obj_data *temp1;

	if(!(is_ok(keeper,ch,shop_nr)))
		return;

	one_argument(arg, argm);

	if(!(*argm))
	{
		sprintf(buf,"%s What do you want me to valuate??",
			GET_NAME(ch));
		do_tell(keeper,buf,19);
		return;
	}

	if(!( temp1 = get_obj_in_list_vis(ch,argm,ch->carrying)))
	{
		sprintf(buf,shop_index[shop_nr].no_such_item2,
			GET_NAME(ch));
		do_tell(keeper,buf,19);
		return;
	}

	if(!(trade_with(temp1,shop_nr)))
	{
		sprintf(buf,
		shop_index[shop_nr].do_not_buy,
		GET_NAME(ch));
		do_tell(keeper,buf,19);
		return;
	}

	sprintf(buf,"%s I'll give you %d gold coins for that!",
		GET_NAME(ch),(int) (temp1->obj_flags.cost*
			shop_index[shop_nr].profit_sell));
	do_tell(keeper,buf,19);

	return;
}

void shopping_list( char *arg, struct char_data *ch,
	 struct char_data *keeper, int shop_nr)
{
	char buf[MAX_STRING_LENGTH], buf2[100],buf3[100];
	struct obj_data *temp1;
	extern char *drinks[];
	int found_obj;

	if(!(is_ok(keeper,ch,shop_nr)))
		return;

	strcpy(buf,"You can buy:\n\r");
	found_obj = FALSE;
		if(keeper->carrying)
	for(temp1=keeper->carrying;
		temp1; 
		temp1 = temp1->next_content)
			if((CAN_SEE_OBJ(ch,temp1)) && (temp1->obj_flags.cost>0))
		{
			found_obj = TRUE; 
			if(temp1->obj_flags.type_flag != ITEM_DRINKCON) 
				sprintf(buf2,"%s for %d gold coins.\n\r"
				,(temp1->short_description)
				,(int)(temp1->obj_flags.cost*
				shop_index[shop_nr].profit_buy));
			else {
				if (temp1->obj_flags.value[1])
					sprintf(buf3,"%s of %s",(temp1->short_description)
					,drinks[temp1->obj_flags.value[2]]);
				else
					sprintf(buf3,"%s",(temp1->short_description));
				sprintf(buf2,"%s for %d gold coins.\n\r",buf3,
				(int)(temp1->obj_flags.cost*shop_index[shop_nr].profit_buy));
			}
			strcat(buf,CAP(buf2));
		};

	if(!found_obj)
		strcat(buf,"Nothing!\n\r");

	send_to_char(buf,ch);
	return;
}

void shopping_kill( char *arg, struct char_data *ch,
	struct char_data *keeper, int shop_nr)
{
	char buf[100];

	switch(shop_index[shop_nr].temper2)
	{
		case 0:
			sprintf(buf,"%s Don't ever try that again!",
				GET_NAME(ch));
			do_tell(keeper,buf,19);
			return;

		case 1:
			sprintf(buf,"%s Scram - midget!",
				GET_NAME(ch));
			do_tell(keeper,buf,19);
			return;

		default :
			return;
	}
}


int shop_keeper(struct char_data *ch, int cmd, char *arg)
{
	char argm[100], buf[MAX_STRING_LENGTH];
	struct obj_data *temp1;
	struct char_data *temp_char;
	struct char_data *keeper;
	int shop_nr;

	keeper = 0;

	for (temp_char = world[ch->in_room].people; (!keeper) && (temp_char) ; 
		temp_char = temp_char->next_in_room)
	if (IS_MOB(temp_char))
		if (mob_index[temp_char->nr].func == shop_keeper)
			keeper = temp_char;

	for(shop_nr=0 ; shop_index[shop_nr].keeper != keeper->nr; shop_nr++);

	if((cmd == 56) && (ch->in_room == 
	   real_room(shop_index[shop_nr].in_room)))
	 /* Buy */
	{
		shopping_buy(arg,ch,keeper,shop_nr);
		return(TRUE);
	}

	if((cmd ==57 ) && (ch->in_room == 
	   real_room(shop_index[shop_nr].in_room)))
	 /* Sell */
	{
		shopping_sell(arg,ch,keeper,shop_nr);
		return(TRUE);
	}

	if((cmd == 58) && (ch->in_room == 
	   real_room(shop_index[shop_nr].in_room)))
	 /* value */
	{
		shopping_value(arg,ch,keeper,shop_nr);
		return(TRUE);
	}

	if((cmd == 59) && (ch->in_room == 
	   real_room(shop_index[shop_nr].in_room)))
	 /* List */
	{
		shopping_list(arg,ch,keeper,shop_nr);
		return(TRUE);
	}

	if ((cmd == 25) || (cmd==70))   /* Kill or Hit */
	{
		one_argument(arg, argm);

		if (keeper == get_char_room(argm,ch->in_room))
		{
			shopping_kill(arg,ch,keeper,shop_nr);
			return(TRUE);
		}
	} else if ((cmd==84) || (cmd==207) || (cmd==172)) {   /* Cast, recite, use */
		act("$N tells you 'No magic here - kid!'.", FALSE, ch, 0, keeper, TO_CHAR);
    return TRUE;
	}

	return(FALSE);
}

void boot_the_shops()
{
	char *buf;
	int temp;
	int count;
	FILE *shop_f;

	if (!(shop_f = fopen(SHOP_FILE, "r")))
	{
		perror("Error in boot shop\n");
		exit(0);
	}

	number_of_shops = 0;

	for(;;)
	{
		buf = fread_string(shop_f);
		if(*buf == '#')	/* a new shop */
		{
			if(!number_of_shops)	/* first shop */
				CREATE(shop_index, struct shop_data, 1);
			else
			  if(!(shop_index=
				(struct shop_data*) realloc(
				shop_index,(number_of_shops + 1)*
				sizeof(struct shop_data))))
				{
					perror("Error in boot shop\n");
					exit(0);
				}

			for(count=0;count<MAX_PROD;count++)
				{
					fscanf(shop_f,"%d \n", &temp);
					if (temp >= 0)
						shop_index[number_of_shops].producing[count]=
							real_object(temp);
					else
						shop_index[number_of_shops].producing[count]= temp;
				}
			fscanf(shop_f,"%f \n",
				&shop_index[number_of_shops].profit_buy);
			fscanf(shop_f,"%f \n",
				&shop_index[number_of_shops].profit_sell);
			for(count=0;count<MAX_TRADE;count++)
				{
					fscanf(shop_f,"%d \n", &temp);
					shop_index[number_of_shops].type[count] =
					(byte) temp;
				}
			shop_index[number_of_shops].no_such_item1 =
				fread_string(shop_f);
			shop_index[number_of_shops].no_such_item2 =
				fread_string(shop_f);
			shop_index[number_of_shops].do_not_buy =
				fread_string(shop_f);
			shop_index[number_of_shops].missing_cash1 =
				fread_string(shop_f);
			shop_index[number_of_shops].missing_cash2 =
				fread_string(shop_f);
			shop_index[number_of_shops].message_buy =
				fread_string(shop_f);
			shop_index[number_of_shops].message_sell =
				fread_string(shop_f);
			fscanf(shop_f,"%d \n",
				&shop_index[number_of_shops].temper1);
			fscanf(shop_f,"%d \n",
				&shop_index[number_of_shops].temper2);
			fscanf(shop_f,"%d \n",
				&shop_index[number_of_shops].keeper);

			shop_index[number_of_shops].keeper =
			  real_mobile(shop_index[number_of_shops].keeper);

			fscanf(shop_f,"%d \n",
				&shop_index[number_of_shops].with_who);
			fscanf(shop_f,"%d \n",
				&shop_index[number_of_shops].in_room);
			fscanf(shop_f,"%d \n",
				&shop_index[number_of_shops].open1);
			fscanf(shop_f,"%d \n",
				&shop_index[number_of_shops].close1);
			fscanf(shop_f,"%d \n",
				&shop_index[number_of_shops].open2);
			fscanf(shop_f,"%d \n",
				&shop_index[number_of_shops].close2);

			number_of_shops++;
		}
		else 
			if(*buf == '$')	/* EOF */
				break;
	}

	fclose(shop_f);
}

void assign_the_shopkeepers()
{
	int temp1;

	for(temp1=0 ; temp1<number_of_shops ; temp1++)
		mob_index[shop_index[temp1].keeper].func = shop_keeper;

}
