/
Crimson/
Crimson/lib/PFILE-BACKUPS/
Crimson/lib/areas/
Crimson/lib/boards/
Crimson/lib/rentfiles/A-E/
Crimson/lib/rentfiles/F-J/
Crimson/lib/rentfiles/P-T/
/**************************************************************************
*  file: reception.c, Special module for Inn's.           Part of DIKUMUD *
*  Usage: Procedures handling saving/loading of player objects            *
*  Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
***************************************************************************/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>

#include "structs.h"
#include "utility.h"
#include "comm.h"
#include "db.h"
#include "handler.h"
#include "interpreter.h"
#include "spells.h"
#include "constants.h"
#include "act.h"
#include "ansi.h"

#include "reception.h"

/**************************************************************************
* NEW STUFF HERE                                                          *
***************************************************************************/

int Rent_get_filename(char *orig_name, char *filename)
{
  char *ptr, name[30];

  if (!*orig_name)
    return 0;

  strcpy(name, orig_name);
  for (ptr = name; *ptr; ptr++)
    *ptr = tolower(*ptr);

  switch (tolower(*name)) {
  case 'a': case 'b': case 'c': case 'd': case 'e':
    sprintf(filename, "rentfiles/A-E/%s.objs", name); break;
  case 'f': case 'g': case 'h': case 'i': case 'j':
    sprintf(filename, "rentfiles/F-J/%s.objs", name); break;
  case 'k': case 'l': case 'm': case 'n': case 'o':
    sprintf(filename, "rentfiles/K-O/%s.objs", name); break;
  case 'p': case 'q': case 'r': case 's': case 't':
    sprintf(filename, "rentfiles/P-T/%s.objs", name); break;
  case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
    sprintf(filename, "rentfiles/U-Z/%s.objs", name); break;
  default:
    sprintf(filename, "rentfiles/ZZZ/%s.objs", name); break;
  }

  return 1;
}

int Rent_delete_file(char *name)
{
  char filename[50];
  char buf1[256];
  FILE *fl;

  if (!Rent_get_filename(name, filename))
    return 0;
  if (!(fl = fopen(filename, "rb"))) {
    if (errno != ENOENT) { /* if it fails but NOT because of no file */
      sprintf(buf1, "SYSERR: deleting crash file %s (1)", filename);
      perror(buf1);
    }
    return 0;
  }
  fclose(fl);

  if (unlink(filename) < 0) {
    if (errno != ENOENT) { /* if it fails, NOT because of no file */
      sprintf(buf1, "SYSERR: deleting crash file %s (2)", filename);
      perror(buf1);
    }
  }

  return(1);
}

/**************************************************************************
* Routines used for the "Offer"                                           *
***************************************************************************/

/* redone for new system, will refuse to store items with rent < 0 */

void add_obj_cost(struct char_data *ch, struct char_data *re,
		  struct obj_data *obj, struct obj_cost *cost)
{
  char buf[MAX_STRING_LENGTH];

  /* Add cost for an item and it's contents, and next->contents */

  if (obj) {
    if ((obj->item_number > -1) && (cost->ok) 
	&& (obj->obj_flags.cost_per_day>0)) {
      cost->no_carried++;
      cost->total_cost += MAXV(0, obj->obj_flags.cost_per_day);
      sprintf(buf,"$n tells you '$p will cost %d per day.'",obj->obj_flags.cost_per_day);
      act(buf,FALSE,re,obj,ch,TO_VICT);
      add_obj_cost(ch, re, obj->contains, cost);
      add_obj_cost(ch, re, obj->next_content, cost);
    } else
      if (cost->ok) {
	if (ch->desc) {
		act("$n tells you 'I refuse to store $p.'",FALSE,re,obj,ch,TO_VICT);
		cost->ok = FALSE;
		sprintf(buf,"%s tried to rent out with %s.", GET_NAME(ch), fname(obj->name));
		log(buf);
	} else {
	        /* For auto rent, just strip the object */
	        extract_obj(obj);
		cost->ok = TRUE;
	        sprintf(buf,"%s was taken away from %s at auto rent.", fname(obj->name), GET_NAME(ch));
		log(buf);
	}	
      }
  }
}

/* much the same, okay for new system */

bool recep_offer(struct char_data *ch,  struct char_data *receptionist,
		 struct obj_cost *cost)
{
  int i;
  char buf[MAX_STRING_LENGTH];
  struct obj_data *obj;

  if (GET_LEVEL(ch) <= 5)
    cost->total_cost = 100; /* Minimum cost */
  else if (GET_LEVEL(ch) <= 9)
    cost->total_cost = 5000;
  else if (GET_LEVEL(ch) <= 19)
    cost->total_cost = 20000;
  else if (GET_LEVEL(ch) <= 29)
    cost->total_cost = 50000;
  else if (GET_LEVEL(ch) <= 40)
    cost->total_cost = 100000;
  else if (GET_LEVEL(ch) <= 41)
    cost->total_cost = 150000;
  else
    cost->total_cost = 1000;

  cost->no_carried = 0;
  cost->ok = TRUE; /* Use if any "-1" objects */
  sprintf(buf, "$n tells you, 'Your room has a base price of %d coins.'", cost->total_cost); 
  act(buf,FALSE,receptionist,0,ch,TO_VICT);

  add_obj_cost(ch, receptionist, ch->carrying, cost);

  for(i = 0; i<MAX_WEAR; i++) {
/*    Only carried items are charged */
/*    add_obj_cost(ch, receptionist, ch->equipment[i], cost); */
    obj = ch->equipment[i];
    if (obj) {
      if (obj->obj_flags.cost_per_day < 0) {
	if (ch->desc) {
	  act("$n tells you 'I refuse to store $p.'",FALSE,receptionist,ch->equipment[i],ch,TO_VICT);
	  sprintf(buf,"%s tried to rent out with %s.", GET_NAME(ch), 
fname(obj->name));
	  log(buf);
	  cost->ok = FALSE;
	} else {
	  /* for auto-rent, just strip the object */
	  extract_obj(obj);
	  sprintf(buf,"%s was taken from %s at auto-rent.", fname(obj->name),GET_NAME(ch));
	  log(buf);
	}
      } else
	cost->no_carried++;
    }
  }


  if (!cost->ok)
    return(FALSE);
   
  if (cost->no_carried == 0) {
    ansi_act("$n tells you, 'But you are not carrying anything?'",
	     FALSE,receptionist,0,ch,TO_VICT,CLR_COMM);
    return(FALSE);
  }
   
  if (GET_LEVEL(ch) <= 5) {
    cost->total_cost = MAXV(2, cost->total_cost - 1000);
    sprintf(buf, "\n$n tells you 'Tell you what kid, I'll only charge you %d coins.'", cost->total_cost);
    act(buf,FALSE,receptionist,0,ch,TO_VICT);
  }  else {
    sprintf(buf, "\n$n tells you, 'It will cost you %d coins.'", cost->total_cost);
    ansi_act(buf,FALSE,receptionist,0,ch,TO_VICT,CLR_COMM);
  }

  if (cost->total_cost > GET_GOLD(ch) + ch->points.bank) {
    if (GET_LEVEL(ch) < IMO_LEV3)
      ansi_act("$n tells you, 'Which I can see you can't afford'",
	       FALSE,receptionist,0,ch,TO_VICT,CLR_COMM);
    else {
      ansi_act("$n tells you, 'Well, since you're a God, I guess it's okay.'",
	       FALSE,receptionist,0,ch,TO_VICT,CLR_COMM);
      cost->total_cost = 0;
    }
  }

  if ( cost->total_cost > GET_GOLD(ch) )
    return(FALSE);
  else
    return(TRUE);
}

/**************************************************************************
* Routines used to load a characters equipment from disk                  *
***************************************************************************/

void obj_store_to_char(struct char_data *ch, struct obj_file_elem *st)
{
  struct obj_data *obj;
  int j;

  void obj_to_char(struct obj_data *object, struct char_data *ch);

  if (st->item_number > -1) {
    if (real_object(st->item_number) > -1) {
      obj = read_object(st->item_number, VIRTUAL);

      obj->obj_flags.value[0] = st->value[0];
      obj->obj_flags.value[1] = st->value[1];
      obj->obj_flags.value[2] = st->value[2];
      obj->obj_flags.value[3] = st->value[3];

      obj->obj_flags.extra_flags = st->extra_flags;
      obj->obj_flags.weight      = st->weight;
      obj->obj_flags.timer       = st->timer;
      obj->obj_flags.bitvector   = st->bitvector;

      for(j=0; j<MAX_OBJ_AFFECT; j++)
	obj->affected[j] = st->affected[j];

      obj_to_char(obj, ch);
    }
  }
}

void del_char_objs(struct char_data *ch)
{
  extern int terminate;

  if ((!IS_NPC(ch)) && (!terminate))
    Rent_delete_file(GET_NAME(ch)); 
}

void load_char_objs(struct char_data *ch)
{
  FILE *fl;
  char buf[256], fname[128];
  float timegold;
  struct obj_file_u    theHeader;
  struct obj_file_elem st; /* stored item var */
 
  /* r+b is for Binary Reading/Writing */
  if (!Rent_get_filename(GET_NAME(ch), fname))
    return; /* char has no name ?!? */
  if (!(fl = fopen(fname, "r+b"))) {
    if (errno != ENOENT) { /* if it fails, NOT because of no file */
      sprintf(buf, "SYSERR: READING OBJECT FILE %s (5)", fname);
      perror(buf);
      send_to_char("\n\r********************* NOTICE *********************\n\r"
		   "There was a problem loading your objects from disk.\n\r"
		   "Contact a God for assistance.\n\r", ch);
    }
    sprintf(buf, "%s entering game with no equipment.", GET_NAME(ch));
    log(buf);
    return;
  }
  sprintf(buf, "%s entering game. (recovered equip ok)", GET_NAME(ch));
  log(buf);

  fread(&theHeader, sizeof(struct obj_file_u), 1, fl);
  if (str_cmp(theHeader.owner, GET_NAME(ch))){
    sprintf(buf, "%s's rent file was saved for char %s?!?",
	    GET_NAME(ch), theHeader.owner);
    log(buf);
  }
  while (!feof(fl)) {
    fread(&st, sizeof(struct obj_file_elem), 1, fl);
    if (!feof(fl)) obj_store_to_char(ch, &st);
  }

  /* calculate the chars gold, max one days worth of rent */
  timegold = (((float) MINV( 3*SECS_PER_REAL_DAY,
			    (time(0) - theHeader.last_update)))
	      / SECS_PER_REAL_DAY * theHeader.total_cost);
  GET_GOLD(ch) = (int) (GET_GOLD(ch) - timegold);
  if (GET_GOLD(ch) < 0)
    GET_GOLD(ch) = 0;
  if (ch->points.bank < 0)
    ch->points.bank = 0;
 
  fclose(fl); /* close up the file now that we're done */

  /* Save char, to avoid strange data if crashing */
  save_char(ch, NOWHERE);
}

/**************************************************************************
* Routines used to save a characters equipment to disk                    *
***************************************************************************/

/* Puts object in store */
void put_obj_in_store(struct obj_data *obj, struct obj_file_elem *st)
{
  int j;
   
  st->item_number = obj_index[obj->item_number].virtual;
  st->value[0] = obj->obj_flags.value[0];
  st->value[1] = obj->obj_flags.value[1];
  st->value[2] = obj->obj_flags.value[2];
  st->value[3] = obj->obj_flags.value[3];

  st->extra_flags = obj->obj_flags.extra_flags;
  st->weight  = obj->obj_flags.weight;
  st->timer  = obj->obj_flags.timer;
  st->bitvector  = obj->obj_flags.bitvector;
  for(j=0; j<MAX_OBJ_AFFECT; j++)
    st->affected[j] = obj->affected[j];
}

/* Destroy inventory after transferring it to store */
void obj_to_store(FILE *fl, struct obj_data *obj, struct obj_file_elem *st,
		  struct char_data *ch)
{
  static char buf[256];
  struct obj_data *tmp_obj;

  if (obj) {
    obj_to_store(fl, obj->contains, st, ch);
    obj_to_store(fl, obj->next_content, st, ch);

    if ((obj->obj_flags.timer < 0) && (obj->obj_flags.timer != OBJ_NOTIMER)) {
      sprintf(buf, "You're told: 'The %s is just old junk, I'll throw it away for you.'\n\r",
	      fname(obj->name));
      send_to_char(buf, ch);
    } else {
      for (tmp_obj = obj->in_obj; tmp_obj; tmp_obj = tmp_obj->in_obj)
	GET_OBJ_WEIGHT(tmp_obj) -= GET_OBJ_WEIGHT(obj);
      /* thats for containers */
      put_obj_in_store(obj, st);

      /* WRITE ST TO FILE HERE */
      if (fwrite(st, sizeof(struct obj_file_elem), 1, fl) < 1) {
	sprintf(buf, "Error creating rent file for %s.", GET_NAME(ch));
	log(buf);
      }
    }
  }
}

void obj_restore_weight(struct obj_data *obj) 
{
  if (obj) {
    obj_restore_weight(obj->contains);
    obj_restore_weight(obj->next_content);
    if (obj->in_obj)
      GET_OBJ_WEIGHT(obj->in_obj) += GET_OBJ_WEIGHT(obj);
  }
}

void extract_all_objs(struct obj_data *obj) 
{
  if (obj) {
    extract_all_objs(obj->contains);
    extract_all_objs(obj->next_content);
    extract_obj(obj);
  }
}

void del_objs(struct char_data *ch) 
{
  int i;

  for(i=0; i<MAX_WEAR; i++)
    if (ch->equipment[i]) {
      obj_to_char(unequip_char(ch, i), ch);
    }
  if (ch->carrying) {
    extract_all_objs(ch->carrying);
    ch->carrying = 0;
  }
}

/******************************************************************
* WRITE THE OBJ DATA FILE OUT, SAVE EVERYTHING NO QUESTIONS ASKED *
*******************************************************************/

/* write the vital data of a player to the player file */
void save_obj(struct char_data *ch, struct obj_cost *cost)
{
  struct obj_file_u    theHeader;
  struct obj_file_elem st; /* stored item var */
  FILE *fl;
  int i;
  static char buf[512];
 
  for(i=0; i<20; i++)
    theHeader.owner[i] = 0;
  strcpy(theHeader.owner, GET_NAME(ch));
  theHeader.gold_left = GET_GOLD(ch);
  theHeader.total_cost = cost->total_cost;
  theHeader.last_update = time(0);
  theHeader.rent_flags = 0;

  /* open the file */
  if (IS_NPC(ch)) /* cheap insurance cant happen but cant hurt */
    return;
  if (!Rent_get_filename(GET_NAME(ch), buf))
    return;
  del_char_objs(ch); /* turf old file if any */
  if (!(fl = fopen(buf, "wb")))
    return;

  /* Write the header out */
  if (fwrite(&theHeader, sizeof(struct obj_file_u), 1, fl) < 1) {
    sprintf(buf, "Error creating rent file for %s.", GET_NAME(ch));
    log(buf);
  }
 
  /* write out all the equipment */
  obj_to_store(fl, ch->carrying, &st, ch);
  obj_restore_weight(ch->carrying);
  
  for(i=0; i<MAX_WEAR; i++)
    if (ch->equipment[i]) {
      obj_to_store(fl, ch->equipment[i], &st, ch);
    }
  /* now rewrite the header with updated information? */
  /* nah not necessary */

  fclose(fl); /* close up shop */
}

/**************************************************************************
* Routines used to update object file, upon boot time                     *
***************************************************************************/

/* time independant rent file now, temporarily disable */
void update_obj_file(void)
{
  /* will be used again ! - will prevent player from renting out forever
     FILE *fl, *char_file;
     struct obj_file_u st;
     struct char_file_u ch_st;
     struct char_data tmp_char;
     int pos, no_read, player_i;
     long days_passed, secs_lost;
     char buf[MAX_STRING_LENGTH];

     int find_name(char *name);
     extern struct player_index_element *player_table;
     */
}

/**************************************************************************
* Routine Receptionist                                                    *
***************************************************************************/

int receptionist(struct char_data *ch, int cmd, char *arg)
{
  char buf[240];
  struct obj_cost cost;
  struct char_data *recep = 0;
  struct char_data *temp_char;
  sh_int save_room;
  sh_int action_tabel[9] = {
    CMD_SMILE,
    CMD_DANCE,
    CMD_SIGH,
    CMD_BLUSH,
    CMD_BURP,
    CMD_COUGH,
    CMD_FART,
    CMD_WHISTLE,
    CMD_YAWN
    };
  int amount, tax;
  
  void do_action(struct char_data *ch, char *arg, int cmd);
  int number(int from, int to);
  
  if (!ch->desc)
    return(FALSE); /* You've forgot FALSE - NPC couldn't leave */
  
  for (temp_char = world[ch->in_room].people; (temp_char) && (!recep);
       temp_char = temp_char->next_in_room)
    if (IS_MOB(temp_char))
      if (mob_index[temp_char->nr].func == receptionist)
	recep = temp_char;

  if (!recep) {
    log("no receptionist in room.\n\r");
    exit(1);
  }

  if (IS_NPC(ch))
    return(FALSE);

  if ((cmd != 92) && (cmd != 93) && (cmd != 220)&& (cmd != 221)&& (cmd != 219))
    {
      if (!number(0, 30))
	do_action(recep, "", action_tabel[number(0,8)]);
      return(FALSE);
    }

  if (!AWAKE(recep)) {
    act("$e isn't able to talk to you...", FALSE, recep, 0, ch, TO_VICT);
    return(TRUE);
  }

  if (!CAN_SEE(recep, ch)) {
    act("$n says, 'I don't deal with people I can't see!'", 
	FALSE, recep, 0, 0, TO_ROOM);
    return(TRUE);
  }
  if (cmd == 92) { /* Rent  */
    if (recep_offer(ch, recep, &cost)) {
      act("$n stores your stuff in the safe, and helps you into your chamber.",
	  FALSE, recep, 0, ch, TO_VICT);
      act("$n helps $N into $S private chamber.",FALSE, recep,0,ch,TO_NOTVICT);
      save_obj(ch, &cost);
      del_objs(ch);
      save_room = ch->in_room;
      extract_char(ch);
      ch->in_room = world[save_room].number;
      save_char(ch, ch->in_room);
    }
  } else if (cmd == 93) {         /* Offer */
    recep_offer(ch, recep, &cost);
    act("$N gives $n an offer.", FALSE, ch, 0, recep, TO_ROOM);
  } else if (cmd == 219) {   /* withdraw */
    arg=one_argument(arg, buf);
    if (is_number(buf)) {
      amount = atoi(buf);
      if (amount < 0) {
	send_to_char("Ha ha ha... nice try.\n\r",ch);
	return(TRUE);
      } else if (amount > ch->points.bank) {
	send_to_char("I'm afraid you don't have that much in your account.\n\r", ch);
      } else {
	act("$n hands you your money.", FALSE, recep, 0, ch, TO_VICT);
	act("$n gives $N some money.",FALSE, recep,0,ch,TO_NOTVICT);
	ch->points.gold += amount;
	ch->points.bank -= amount;
      }
    }
  } else if (cmd == 220) {   /* deposit */
    arg=one_argument(arg, buf);
    if (is_number(buf)) {
      amount = atoi(buf);
      tax = amount / 20;
      if (amount < 0) {
	send_to_char("Ha ha ha... nice try\n\r",ch);
	return(TRUE);
      } else if (amount > ch->points.gold) {
	send_to_char("I'm afraid you don't have that much.\n\r", ch);
      } else {
	sprintf(buf, "I'm afraid the tax on this transaction comes to %d.\n\r", tax);
	send_to_char(buf, ch);
	act("$n takes your money.", FALSE, recep, 0, ch, TO_VICT);
	act("$n takes some money from $N.",FALSE, recep,0,ch,TO_NOTVICT);
	ch->points.gold -= amount;
	amount -= tax;
	ch->points.bank += amount;
      }
    }
  } else if (cmd == 221) {   /* balance */
    sprintf(buf, "You have %d coins on account.\n\r", ch->points.bank);
    send_to_char(buf, ch);
  }
  
  return(TRUE);
}