/* ************************************************************************
*  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 "os.h"

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

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

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))
  {
    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)) {
    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, "rb"))) {
    perror ("Error in boot shop\n");
    WIN32CLEANUP
    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");
        WIN32CLEANUP
        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;

}