/
/*
  SillyMUD Distribution V1.1b             (c) 1993 SillyMUD Developement
 
  See license.doc for distribution terms.   SillyMUD is based on DIKUMUD
*/

#include <stdio.h>
#include <sys/time.h>

#include "protos.h"

#define OBJ_SAVE_FILE "pcobjs.obj"
#define OBJ_FILE_FREE "\0\0\0"

extern struct room_data *world;
extern struct index_data *mob_index;
extern struct index_data *obj_index;
extern int top_of_objt;
extern struct player_index_element *player_table;
extern int top_of_p_table;



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

int add_obj_cost(struct char_data *ch, struct char_data *re,
                  struct obj_data *obj, struct obj_cost *cost, int hoarder)
{
  char buf[MAX_INPUT_LENGTH];
  int  temp;
  struct obj_data *hobj;

  if((cost->total_cost == 100) && (cost->no_carried == 0)) {
    hobj = obj;
      /* Add cost for an item and it's contents, and next->contents */
  }

  if (obj) {
    if ((obj->item_number > -1) && (cost->ok) && ItemEgoClash(ch,obj,0) >-5 ) {
      temp = MAX(0, obj->obj_flags.cost_per_day);
      cost->total_cost += temp;
      if (re) {
#if  0
	sprintf(buf, "%30s : %d coins/day\n\r", obj->short_description, temp);
	send_to_char(buf, ch);
#endif	
      }
      cost->no_carried++;
      hoarder = add_obj_cost(ch, re, obj->contains, cost, hoarder);
      hoarder = add_obj_cost(ch, re, obj->next_content, cost, hoarder);
    } else {
      if(ItemEgoClash(ch,obj,0) < 0 && obj->obj_flags.cost_per_day > 0) { 
	if (re) 
	  act("$p refuses to be rented with a wimp like you!",
	      TRUE,ch,obj,0,TO_CHAR);
	cost->ok = FALSE;
      }	else if (cost->ok) {
	if (re) {
	  act("$n tells you 'I refuse storing $p'",FALSE,re,obj,ch,TO_VICT);
	  cost->ok = FALSE;
	} else {
#if NODUPLICATES
#else
	  act("Sorry, but $p don't keep in storage.",FALSE,ch,obj,0,TO_CHAR);
#endif
	  cost->ok = FALSE;

	}
      }
    }
  }

return(hoarder);
  
}


bool recep_offer(struct char_data *ch,	struct char_data *receptionist,
		 struct obj_cost *cost)
{
  int i;
  char buf[MAX_INPUT_LENGTH];
  int hoarder = 0;
  
  cost->total_cost = 0; /* Minimum cost */
  cost->no_carried = 0;
  cost->ok = TRUE; /* Use if any "-1" objects */
  
  hoarder = add_obj_cost(ch, receptionist, ch->carrying, cost, hoarder);
  
  for(i = 0; i<MAX_WEAR; i++)
    hoarder = add_obj_cost(ch, receptionist, ch->equipment[i], cost, hoarder);
  
  if (!cost->ok)
    return(FALSE);

#if NEW_RENT
  cost->total_cost = 0;
#endif

  if(hoarder) {
    cost->total_cost += (int) (ch->points.gold + ch->points.bankgold)/10;
  }
  
  if (cost->no_carried == 0) {
    if (receptionist)
      act("$n tells you 'But you are not carrying anything?'",FALSE,receptionist,0,ch,TO_VICT);
    return(FALSE);
  }
  
  if (cost->no_carried > MAX_OBJ_SAVE) {
    if (receptionist) {
      sprintf(buf,"$n tells you 'Sorry, but I can't store more than %d items.",
	      MAX_OBJ_SAVE);
      act(buf,FALSE,receptionist,0,ch,TO_VICT);
    }
    return(FALSE);
  }
  
  if (HasClass(ch, CLASS_MONK)) {
    if (cost->no_carried > 20) {
      send_to_char("Your vows forbid you to carry more than 20 items\n\r", ch);
      return(FALSE);
    }
  }
  
  if (receptionist) {

    sprintf(buf, "$n tells you 'It will cost you %d coins per day'",
	    cost->total_cost);
    act(buf,FALSE,receptionist,0,ch,TO_VICT);
  
    if (cost->total_cost > GET_GOLD(ch)) {
      if (GetMaxLevel(ch) < LOW_IMMORTAL)
	act("$n tells you 'Which I can see you can't afford'",
	    FALSE,receptionist,0,ch,TO_VICT);
      else {
	act("$n tells you 'Well, since you're a God, I guess it's okay'",
	    FALSE,receptionist,0,ch,TO_VICT);
	cost->total_cost = 0;
      }
    }
  }
  
  if ( cost->total_cost > GET_GOLD(ch) )
    return(FALSE);
  else
    return(TRUE);
}


/* ************************************************************************
* General save/load routines                                              *
************************************************************************* */

void update_file(struct char_data *ch, struct obj_file_u *st)
{
  FILE *fl;
  char buf[200];

  /*
    write the aliases and bamfs:

    */
  write_char_extra(ch);
  sprintf(buf, "rent/%s", lower(ch->player.name));
#if 0
  for(p=buf;*p && *p != ' ';p++);
  *p = '\0';
  log("buf");
#endif
  if (!(fl = fopen(buf, "w")))  {
    perror("saving PC's objects");
    assert(0);  
  }
  
  rewind(fl);

  strcpy(st->owner, GET_NAME(ch));

  WriteObjs(fl, st);

  fclose(fl);
  
}


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

void obj_store_to_char(struct char_data *ch, struct obj_file_u *st)
{
  struct obj_data *obj;
  int i, j;
  
  void obj_to_char(struct obj_data *object, struct char_data *ch);
  
  for(i=0; i<st->number; i++) {
    if (st->objects[i].item_number > -1 && 
	real_object(st->objects[i].item_number) > -1) {
      obj = read_object(st->objects[i].item_number, VIRTUAL);
      obj->obj_flags.value[0] = st->objects[i].value[0];
      obj->obj_flags.value[1] = st->objects[i].value[1];
      obj->obj_flags.value[2] = st->objects[i].value[2];
      obj->obj_flags.value[3] = st->objects[i].value[3];
      obj->obj_flags.extra_flags = st->objects[i].extra_flags;
      obj->obj_flags.weight      = st->objects[i].weight;
      obj->obj_flags.timer       = st->objects[i].timer;
      obj->obj_flags.bitvector   = st->objects[i].bitvector;

/*  new, saving names and descrips stuff o_s_t_c*/
      if (obj->name)
	free(obj->name);
      if (obj->short_description)
         free(obj->short_description);
      if (obj->description)
         free(obj->description);

      obj->name = (char *)malloc(strlen(st->objects[i].name)+1);
      obj->short_description = (char *)malloc(strlen(st->objects[i].sd)+1);
      obj->description = (char *)malloc(strlen(st->objects[i].desc)+1);

      strcpy(obj->name, st->objects[i].name);
      strcpy(obj->short_description, st->objects[i].sd);
      strcpy(obj->description, st->objects[i].desc);
/* end of new, possibly buggy stuff */
      
      for(j=0; j<MAX_OBJ_AFFECT; j++)
	obj->affected[j] = st->objects[i].affected[j];
      
      obj_to_char(obj, ch);
    }
  }
}


void load_char_objs(struct char_data *ch)
{
  FILE *fl;
  bool found = FALSE;
  float timegold;
  struct obj_file_u st;
  char buf[200];


/*
  load in aliases and poofs first
*/

  load_char_extra(ch);

  
  sprintf(buf, "rent/%s", lower(ch->player.name));

  
  /* r+b is for Binary Reading/Writing */
  if (!(fl = fopen(buf, "r+b")))  {
    log("Char has no equipment");
    return;
  }

  rewind(fl);

  if (!ReadObjs(fl, &st)) {
    log("No objects found");
    fclose(fl);
    return;
  }

  if (str_cmp(st.owner, GET_NAME(ch)) != 0) {
    log("Hmm.. bad item-file write. someone is losing thier objects");
    fclose(fl);
    return;
  }

/*
  if the character has been out for 12 real hours, they are fully healed
  upon re-entry.  if they stay out for 24 full hours, all affects are
  removed, including bad ones.
*/

    if (st.last_update + 12*SECS_PER_REAL_HOUR < time(0))
      RestoreChar(ch);

    if (st.last_update + 24*SECS_PER_REAL_HOUR < time(0))
      RemAllAffects(ch);
    
    if (ch->in_room == NOWHERE &&
	st.last_update + 1*SECS_PER_REAL_HOUR > time(0)) {
	/* you made it back from the crash in time, 1 hour grace period. */
      log("Character reconnecting.");
      found = TRUE;
    } else {
      char	buf[MAX_STRING_LENGTH];
      if (ch->in_room == NOWHERE)
	log("Char reconnecting after autorent");
#if NEW_RENT
      timegold = (int) ((100*((float)time(0) - st.last_update)) / 
			(SECS_PER_REAL_DAY));
#else
      timegold = (int) ((st.total_cost*((float)time(0) - st.last_update)) / 
			(SECS_PER_REAL_DAY));
#endif
      sprintf(buf, "Char ran up charges of %g gold in rent", timegold);
      log(buf);
      sprintf(buf, "You ran up charges of %g gold in rent.\n\r", timegold);
      send_to_char(buf, ch);
      GET_GOLD(ch) -= timegold;
      found = TRUE;    
      if (GET_GOLD(ch) < 0) {
	log("Char ran out of money in rent");
        send_to_char("You ran out of money, you deadbeat.\n\r", ch);
	GET_GOLD(ch) = 0;
	found = FALSE;
      }
    }

  fclose(fl);

  if (found)
      obj_store_to_char(ch, &st);
  else {
    ZeroRent(GET_NAME(ch));
  }
  
  /* Save char, to avoid strange data if crashing */
  save_char(ch, AUTO_RENT);


  
}


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

/* Puts object in store, at first item which has no -1 */
void put_obj_in_store(struct obj_data *obj, struct obj_file_u *st)
{
  int j;
  struct obj_file_elem *oe;
  char buf[256];

  if (st->number>=MAX_OBJ_SAVE) {
    printf("holy shit, you want to rent more than %d items?!\n", st->number);
    return;
  }

  oe = st->objects + st->number;
  
  oe->item_number = obj_index[obj->item_number].virtual;
  oe->value[0] = obj->obj_flags.value[0];
  oe->value[1] = obj->obj_flags.value[1];
  oe->value[2] = obj->obj_flags.value[2];
  oe->value[3] = obj->obj_flags.value[3];
  
  oe->extra_flags = obj->obj_flags.extra_flags;
  oe->weight  = obj->obj_flags.weight;
  oe->timer  = obj->obj_flags.timer;
  oe->bitvector  = obj->obj_flags.bitvector;

/*  new, saving names and descrips stuff */
      if (obj->name)
         strcpy(oe->name, obj->name);
      else {
	sprintf(buf, "object %d has no name!", obj_index[obj->item_number].virtual);
	log(buf);
	
      }
	
      if (obj->short_description)
         strcpy(oe->sd, obj->short_description);
      else
	*oe->sd = '\0';
      if (obj->description)
         strcpy(oe->desc, obj->description);
      else 
	*oe->desc = '\0';

/* end of new, possibly buggy stuff */


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

  st->number++;
}

int contained_weight(struct obj_data *container)
{
  struct obj_data *tmp;
  int	rval = 0;

  for (tmp = container->contains; tmp; tmp = tmp->next_content)
    rval += GET_OBJ_WEIGHT(tmp);
  return rval;
}

/* Destroy inventory after transferring it to "store inventory" */
void obj_to_store(struct obj_data *obj, struct obj_file_u *st,
                  struct char_data * ch, int delete)
{
  static char buf[240];
  
  if (!obj)
    return;

  obj_to_store(obj->contains, st, ch, delete);
  obj_to_store(obj->next_content, st, ch, delete);
    
  if ((obj->obj_flags.timer < 0) && (obj->obj_flags.timer != OBJ_NOTIMER)) {
#if NODUPLICATES
#else
    sprintf(buf, "You're told: '%s is just old junk, I'll throw it away for you.'\n\r", obj->short_description);
    send_to_char(buf, ch);
#endif
  } else if (obj->obj_flags.cost_per_day < 0) {

#if NODUPLICATES
#else
    if(ch != NULL) {
      sprintf(buf, "You're told: '%s is just old junk, I'll throw it away for you.'\n\r", obj->short_description);
      send_to_char(buf, ch);
    }
#endif

    if (delete) {
       if (obj->in_obj) 
	 obj_from_obj(obj);
       extract_obj(obj);
     }
  } else if (obj->item_number == -1) {
    if (delete) {
       if (obj->in_obj) 
	 obj_from_obj(obj);
       extract_obj(obj);
     }
  }else {
    int weight = contained_weight(obj);
          GET_OBJ_WEIGHT(obj) -= weight;
    put_obj_in_store(obj, st);
    GET_OBJ_WEIGHT(obj) += weight;
    if (delete) {
      if (obj->in_obj)
	obj_from_obj(obj);
      extract_obj(obj);
    }
  }
}



/* write the vital data of a player to the player file */
void save_obj(struct char_data *ch, struct obj_cost *cost, int delete)
{
  static struct obj_file_u st;
  int i;
  char buf[128];
    
  st.number = 0;
  st.gold_left = GET_GOLD(ch);

  sprintf(buf, "saving %s:%d", fname(ch->player.name), GET_GOLD(ch));
  slog(buf);

  st.total_cost = cost->total_cost;
  st.last_update = time(0);
  st.minimum_stay = 0; /* XXX where does this belong? */
  
  for(i=0; i<MAX_WEAR; i++)
    if (ch->equipment[i]) {
      if (delete) {
	obj_to_store(unequip_char(ch, i), &st, ch, delete);
      } else {
	obj_to_store(ch->equipment[i], &st, ch, delete);
      }
    }
  
  obj_to_store(ch->carrying, &st, ch, delete);
  if (delete)
    ch->carrying = 0;
  
  update_file(ch, &st);
  
}



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

void update_obj_file()
{
  FILE *fl, *char_file;
  struct obj_file_u st;
  struct char_file_u ch_st;
  long i;
  long days_passed, secs_lost;
  char buf[200];
  
  int find_name(char *name);
  extern int errno;


  if (!(char_file = fopen(PLAYER_FILE, "r+"))) {
    perror("Opening player file for reading. (reception.c, update_obj_file)");
    assert(0);
  }
  
  for (i=0; i<= top_of_p_table; i++) {
    sprintf(buf, "rent/%s", lower(player_table[i].name));
    /* r+b is for Binary Reading/Writing */
    if ((fl = fopen(buf, "r+b")) != NULL) {

      if (ReadObjs(fl, &st)) {
	if (str_cmp(st.owner, player_table[i].name) != 0) {
       sprintf(buf, "Ack!  Wrong person written into object file! (%s/%s)", st.owner, player_table[i].name);
	  log(buf);
	  abort();
	} else {
	  sprintf(buf, "   Processing %s[%d].", st.owner, i);
	  log(buf);
	  days_passed = ((time(0) - st.last_update) / SECS_PER_REAL_DAY);
	  secs_lost = ((time(0) - st.last_update) % SECS_PER_REAL_DAY);
	  
	  fseek(char_file, (long) (player_table[i].nr *
				   sizeof(struct char_file_u)), 0);
	  fread(&ch_st, sizeof(struct char_file_u), 1, char_file);
	 
          if (ch_st.load_room == AUTO_RENT) {  /* this person was autorented */
	    ch_st.load_room = NOWHERE;
	    st.last_update = time(0)+3600;  /* one hour grace period */

	    sprintf(buf, "   Deautorenting %s", st.owner);
	    log(buf);

#if LIMITED_ITEMS
	    fprintf(stderr, "Counting limited items\n");
	    CountLimitedItems(&st);
	    fprintf(stderr, "Done\n");
#endif
            fseek(char_file, (long) (player_table[i].nr *
					 sizeof(struct char_file_u)), 0);
	    fwrite(&ch_st, sizeof(struct char_file_u), 1, char_file);
#if 0
	    rewind(fl);
	    WriteObjs(fl, &st);
#endif
	    fclose(fl);
	  } else {
 
	    if (days_passed > 0) {
	      
	      if ((st.total_cost*days_passed) > st.gold_left) {
		
		sprintf(buf, "   Dumping %s from object file.", ch_st.name);
		log(buf);
		
		ch_st.points.gold = 0;
		ch_st.load_room = NOWHERE;
		fseek(char_file, (long) (player_table[i].nr *
					 sizeof(struct char_file_u)), 0);
		fwrite(&ch_st, sizeof(struct char_file_u), 1, char_file);
		
		fclose(fl);
		ZeroRent(ch_st.name);
		
	      } else {
		
		sprintf(buf, "   Updating %s", st.owner);
		log(buf);
		st.gold_left  -= (st.total_cost*days_passed);
		st.last_update = time(0)-secs_lost;
#if 0
		rewind(fl);
		WriteObjs(fl, &st);
#endif
		fclose(fl);
#if LIMITED_ITEMS
		CountLimitedItems(&st);
#endif
		
	      }
	    } else {
	      
#if LIMITED_ITEMS
	      CountLimitedItems(&st);
#endif
	      sprintf(buf, "  same day update on %s", st.owner);
	      log(buf);
#if 0
	      rewind(fl);
	      WriteObjs(fl, &st);
#endif
	      fclose(fl);
	    }
	  }
	}
      }
    } else {
      /* do nothing */
    }
  }
  fclose(char_file);
}


void CountLimitedItems(struct obj_file_u *st)
{
    int i, cost_per_day;
    struct obj_data *obj;

    if (!st->owner[0]) return;  /* don't count empty rent units */

    for(i=0; i<st->number; i++) {
      if (st->objects[i].item_number > -1 && 
          real_object(st->objects[i].item_number) > -1) {
	    /*
            ** eek.. read in the object, and then extract it.
	    ** (all this just to find rent cost.)  *sigh*
            */
            obj = read_object(st->objects[i].item_number, VIRTUAL);
	    cost_per_day = obj->obj_flags.cost_per_day;
	    /*
            **  if the cost is > LIM_ITEM_COST_MIN, then mark before extractin
            */
	    if (cost_per_day > LIM_ITEM_COST_MIN) {
	      obj_index[obj->item_number].number++;  
	    } else {
	      if (IS_OBJ_STAT(obj, ITEM_MAGIC) ||
		  IS_OBJ_STAT(obj, ITEM_GLOW) ||
		  IS_OBJ_STAT(obj, ITEM_HUM) ||
		  IS_OBJ_STAT(obj, ITEM_INVISIBLE) ||
		  IS_OBJ_STAT(obj, ITEM_BLESS)) {
		obj_index[obj->item_number].number++;  
	      }
	    }
	}
    }
}


void PrintLimitedItems()
{
/*  int i; */
  char buf[200];
#if 0
  for (i=0;i<=top_of_objt;i++) {
    if (obj_index[i].number > 0) {
      sprintf(buf, "item> %d [%d]", obj_index[i].virtual, obj_index[i].number);
      log(buf);
    }
  }
#endif
}



/* ************************************************************************
* Routine Receptionist                                                    *
************************************************************************* */
#define DONATION_ROOM 99

int receptionist(struct char_data *ch, int cmd, char *arg, struct char_data *mob, int type)
{
  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];
  
  
  if (!ch->desc)
    return(FALSE); /* You've forgot FALSE - NPC couldn't leave */

   action_tabel[0] = 23;
   action_tabel[1] = 24;
   action_tabel[2] = 36;
   action_tabel[3] = 105;
   action_tabel[4] = 106;
   action_tabel[5] = 109;
   action_tabel[6] = 111;
   action_tabel[7] = 142;
   action_tabel[8] = 147;

  
  for (temp_char = real_roomp(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.\n\r");
    assert(0);
  }
  
  if(!number(0,2))
    
    for (temp_char = real_roomp(ch->in_room)->people; (temp_char);
	 temp_char = temp_char->next_in_room)
      if(temp_char != recep)
	if (IS_MOB(temp_char)) {
	  
	  struct room_direction_data    *exitp;
	  int   going_to,door;
	  struct room_data      *rp;
	  
	  act("$n pushes a button on $s desk.  A trap door opens!",TRUE,recep,
	      0,0,TO_ROOM);
	  send_to_char("You fall through!\n\r\n\r",temp_char);
	  act("$N falls through the trap door!",TRUE,recep,0,temp_char,TO_NOTVICT);
	  act("$n mutters something about not liking monsters in $s inn.",TRUE,
	      recep,0,0,TO_ROOM);
	  
	  door = 5;			/* down */
	  exitp = EXIT(temp_char, door);
	  if(exit_ok(exitp, &rp)) {	
	    going_to = exitp->to_room;
	    
	    char_from_room(temp_char);
	    char_to_room(temp_char,going_to);
	    do_look(temp_char,"",0);
	  } else {			/* must be some other direction */
	    int k;
	    for(k=0;k<5;k++) {
	      exitp = EXIT(temp_char, k);
	      if(exit_ok(exitp, &rp)) {
		going_to = exitp->to_room;
		
		char_from_room(temp_char);
		char_to_room(temp_char,going_to);
		do_look(temp_char,"",0);
	      }
	    }
	  }
	  return(FALSE);
	}
  
  if ((cmd != 92) && (cmd != 93)) {
    if (!cmd) {
      if (recep->specials.fighting) {
	return(citizen(recep,0,"",mob,type));
      }
    }

    if(!number(0,2)) {
      struct obj_data *i;
      for (i = real_roomp(ch->in_room)->contents; i; i = i->next_content) {
	if (IS_SET(i->obj_flags.wear_flags, ITEM_TAKE)) {
	  act("$n sweeps some trash into the donation room.",TRUE,recep,0,0,
	      TO_ROOM);
	  obj_from_room(i);
	  obj_to_room(i,DONATION_ROOM);
	  break;
	} 
      }
    }

    

    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 just can't deal with people I can't see!'", FALSE, recep, 0, 0, TO_ROOM);
      act("$n bursts into tears", 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,1);
      save_room = ch->in_room;

      if (ch->specials.start_room != 2) /* hell */
	ch->specials.start_room = save_room;

      extract_char(ch);  /* you don't delete CHARACTERS when you extract
			    them */
      save_char(ch, save_room);
      ch->in_room = save_room;

    }
    
  } else {         /* Offer */
    recep_offer(ch, recep, &cost);
    act("$N gives $n an offer.", FALSE, ch, 0, recep, TO_ROOM);
  }
  
  return(TRUE);
}


/*
    removes a player from the list of renters
*/

void zero_rent( struct char_data *ch) 
{

  if (IS_NPC(ch))
    return;

  ZeroRent(GET_NAME(ch));

}

void ZeroRent( char *n)
{
  FILE *fl;
  char buf[200];

  sprintf(buf, "rent/%s", lower(n));

  if (!(fl = fopen(buf, "w"))) {
    perror("saving PC's objects");
    assert(0);
  }
  
  fclose(fl);
  return;
  
}

int ReadObjs( FILE *fl, struct obj_file_u *st)
{
  int i;
  char buf[128];

  if (feof(fl)) {
    fclose(fl);
    return(FALSE);
  }

  fread(st->owner, sizeof(st->owner), 1, fl);
  if (feof(fl)) {
    fclose(fl);
    return(FALSE);
  }
  fread(&st->gold_left, sizeof(st->gold_left), 1, fl);
  if (feof(fl)) {
    fclose(fl);
    return(FALSE);
  }
  fread(&st->total_cost, sizeof(st->total_cost), 1, fl);
  if (feof(fl)) {
    fclose(fl);
    return(FALSE);
  }
  fread(&st->last_update, sizeof(st->last_update), 1, fl);
  if (feof(fl)) {
    fclose(fl);
    return(FALSE);
  }
  fread(&st->minimum_stay, sizeof(st->minimum_stay), 1, fl);
  if (feof(fl)) {
    fclose(fl);
    return(FALSE);
  }
  fread(&st->number, sizeof(st->number), 1, fl);
  if (feof(fl)) {
    fclose(fl);
    return(FALSE);
  }
   
  for (i=0;i<st->number;i++) {
     fread(&st->objects[i], sizeof(struct obj_file_elem), 1, fl);
  }

}

int WriteObjs( FILE *fl, struct obj_file_u *st)
{
  int i;
  char buf[128];

  fwrite(st->owner, sizeof(st->owner), 1, fl);
  fwrite(&st->gold_left, sizeof(st->gold_left), 1, fl);
  fwrite(&st->total_cost, sizeof(st->total_cost), 1, fl);
  fwrite(&st->last_update, sizeof(st->last_update), 1, fl);
  fwrite(&st->minimum_stay, sizeof(st->minimum_stay), 1, fl);
  fwrite(&st->number, sizeof(st->number), 1, fl);
   
  for (i=0;i<st->number;i++) {
     fwrite(&st->objects[i], sizeof(struct obj_file_elem), 1, fl);
  }
}


void load_char_extra(struct char_data *ch)
{
  FILE *fp;
  char buf[80];
  char line[260];
  char  tmp[260];
  char *p, *s, *chk;
  int n;

  sprintf(buf, "rent/%s.aux", GET_NAME(ch));

  /*
    open the file.. read in the lines, use them as the aliases and
    poofin and outs, depending on tags:

    format:

    <id>:string

  */

  if ((fp = fopen(buf, "r")) == NULL) {
    return;  /* nothing to look at */
  }

  while (!feof(fp)) {
    chk = fgets(line, 260, fp);

    if (chk) {
      p = (char *)strtok(line, ":");
      s = (char *)strtok(0, "\0");
      if (p) {
	if (!strcmp(p,"out")) { /*setup bamfout */
	  do_bamfout(ch, s, 0);
	} else if (!strcmp(p, "in")) { /* setup bamfin */
	  do_bamfin(ch, s, 0);
	} else if (!strcmp(p, "zone")) { /* set zone permisions */
          GET_ZONE(ch) = atoi(s);
	} else if (!strcmp(p, "loot")) {
	  ch->specials.loot = atoi(s);
	} else if (!strcmp(p, "split")) {
	  ch->specials.split = atoi(s);
	} else if (!strcmp(p,"sev")) {
	  ch->specials.sev = atoi(s);
	} else if (!strcmp(p, "flee")) {
	  ch->specials.flee = atoi(s);
	} else if (!strcmp(p, "prompt")) {
	  ch->specials.prompt = atoi(s);
	} else {
	  if (s) {
	    s[strlen(s)]= '\0';
	    n = atoi(p);
	    if (n >=0 && n <= 9) {  /* set up alias */
	      sprintf(tmp, "%d %s", n, s+1);
	      do_alias(ch, tmp, 260);
	    }
	  }
	}
      }
    } else {
      break;
    }
  }
  fclose(fp);
}

void write_char_extra( struct char_data *ch)
{
  FILE *fp;
  char buf[80];
  int i;

  sprintf(buf, "rent/%s.aux", GET_NAME(ch));

  /*
    open the file.. read in the lines, use them as the aliases and
    poofin and outs, depending on tags:

    format:

    <id>:string

  */

  if ((fp = fopen(buf, "w")) == NULL) {
    return;  /* nothing to write */
  }

  if (IS_IMMORTAL(ch)) {
    if (ch->specials.poofin) {
      fprintf(fp, "in: %s\n", ch->specials.poofin);
    }
    if (ch->specials.poofout) {
      fprintf(fp, "out: %s\n", ch->specials.poofout);
    }
    fprintf(fp, "zone: %d\n", GET_ZONE(ch));
    fprintf(fp, "sev: %d\n", ch->specials.sev);
  }

  fprintf(fp, "loot: %d\n", ch->specials.loot);
  fprintf(fp, "split: %d\n",ch->specials.split);
  fprintf(fp, "flee: %d\n", ch->specials.flee);
  fprintf(fp, "prompt: %d\n",ch->specials.prompt);

  if (ch->specials.A_list) {
    for (i=0;i<10;i++) {
      if (GET_ALIAS(ch, i)) {
	fprintf(fp, "%d: %s\n", i, GET_ALIAS(ch, i));
      }
    }
  }
  fclose(fp);
}


void obj_store_to_room(int room, struct obj_file_u *st)
{
  struct obj_data *obj;
  int i, j;
  
  
  for(i=0; i<st->number; i++) {
    if (st->objects[i].item_number > -1 && 
	real_object(st->objects[i].item_number) > -1) {
      obj = read_object(st->objects[i].item_number, VIRTUAL);
      obj->obj_flags.value[0] = st->objects[i].value[0];
      obj->obj_flags.value[1] = st->objects[i].value[1];
      obj->obj_flags.value[2] = st->objects[i].value[2];
      obj->obj_flags.value[3] = st->objects[i].value[3];
      obj->obj_flags.extra_flags = st->objects[i].extra_flags;
      obj->obj_flags.weight      = st->objects[i].weight;
      obj->obj_flags.timer       = st->objects[i].timer;
      obj->obj_flags.bitvector   = st->objects[i].bitvector;

/*  new, saving names and descrips stuff o_s_t_r */
      if (obj->name)
	free(obj->name);
      if (obj->short_description)
	free(obj->short_description);
      if (obj->description)
	free(obj->description);

      obj->name = (char *)malloc(strlen(st->objects[i].name)+1);
      obj->short_description = (char *)malloc(strlen(st->objects[i].sd)+1);
      obj->description = (char *)malloc(strlen(st->objects[i].desc)+1);

      strcpy(obj->name, st->objects[i].name);
      strcpy(obj->short_description, st->objects[i].sd);
      strcpy(obj->description, st->objects[i].desc);
/* end of new, possibly buggy stuff */
      
      for(j=0; j<MAX_OBJ_AFFECT; j++)
	obj->affected[j] = st->objects[i].affected[j];
      
      obj_to_room2(obj, room);
    }
  }
  /* bug report -  this is a static array, shouldn't be freed */
#if 0
  free(st->objects);
#endif
}

void load_room_objs(int room)
{
  FILE *fl;
  struct obj_file_u st;
  char buf[200];
  
  sprintf(buf, "world/%d", room);

  
  /* r+b is for Binary Reading/Writing */
  if (!(fl = fopen(buf, "r+b")))  {
    log("Room has no equipment");
    return;
  }

  rewind(fl);

  if (!ReadObjs(fl, &st)) {
    log("No objects found");
    fclose(fl);
    return;
  }

  fclose(fl);

  obj_store_to_room(room, &st);
  save_room(room);
}

void save_room(int room)
{
 struct obj_file_u st;
 struct obj_data *obj;
 struct room_data *rm = 0;
 char buf[255];
 static int last_room = -1;
 static FILE *f1 = 0;

 rm = real_roomp(room);

 obj = rm->contents;
 sprintf(buf, "world/%d", room);
 st.number = 0;

 if(obj) {
   if (room != last_room) {
     if (f1)
       fclose(f1);
     f1 = fopen(buf, "w");
   }
   if (!f1) 
     return;

   rewind(f1);
   obj_to_store(obj, &st, NULL, 0);
   sprintf(buf, "Room %d", room);
   strcpy(st.owner, buf);
   st.gold_left = 0;
   st.total_cost = 0;
   st.last_update = 0;
   st.minimum_stay = 0;
   WriteObjs(f1, &st);
  }
}