/
lib/objects/
lib/rooms/
lib/scripts/
lib/security/
src/banner/
src/util/
/*
 *
 *
 *
 * To calc last time online...
 *  computeminuteslast = (time(0)-st.last_update)/SECS_PER_REAL_MIN;
 *  computehourslast = (time(0)-st.last_update)/SECS_PER_REAL_HOUR;
 *  The last time you were on was %d minutes (%d hrs) ago according to rent.
    , computeminuteslast, computehourslast
*/


#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;

int     cur_depth=0;

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

void add_obj_cost(struct char_data *ch, struct char_data *re,
                  struct obj_data *obj, struct obj_cost *cost)
{
  char buf[MAX_INPUT_LENGTH];
  int  temp;
  
  /* 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)/2; 	/* 1/2 price rent */

      if (temp<=LIM_ITEM_COST_MIN)	/* Let's not charge for normal items */
	  temp=0;
	       
      cost->total_cost += temp;

      if (re) {
        sprintf(buf, "%30s : %d coins/day\n\r", obj->short_description, temp);
        send_to_char(buf, ch);
      }
      cost->no_carried++;
      add_obj_cost(ch, re, obj->contains, cost);
      add_obj_cost(ch, re, obj->next_content, cost);
    } 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;

        }
      }
  }
}


/* only time forcerent is true is when they idle off, in limits.c */
bool recep_offer(struct char_data *ch,  struct char_data *receptionist,
                 struct obj_cost *cost, int forcerent)
{
  int i,ii,limited_items=0;
  char buf[MAX_INPUT_LENGTH];
  struct obj_data *tmp, *tmp_next_obj;
  
  cost->total_cost = 100; /* Minimum cost */
  cost->no_carried = 0;
  cost->ok = TRUE; /* Use if any "-1" objects */

  if (forcerent) {
   sprintf(buf,"%s is being force rented!",GET_NAME(ch));
   log_sev(buf,3);
  }
  
  add_obj_cost(ch, receptionist, ch->carrying, cost);
  limited_items +=CountLims(ch->carrying);


  for(i = 0; i<MAX_WEAR; i++) {
    add_obj_cost(ch, receptionist, ch->equipment[i], cost);
    limited_items +=CountLims(ch->equipment[i]);
   }
  
  if (!cost->ok)
    return(FALSE);

  
  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 LIMITED_ITEMS
  if (limited_items > MaxLimited(GetMaxLevel(ch))) 
  {
    if (receptionist)
    {
      sprintf(buf,"$n tells you 'Sorry, but I can't store more than %d limited items.",
              MaxLimited(GetMaxLevel(ch)));
      act(buf,FALSE,receptionist,0,ch,TO_VICT);
      return(FALSE);
    } 

#if 1
                 /* auto renting a idle person, lets wack items they should not */
                 /* carry here! (limited items) */

if (!receptionist && forcerent) {
        i = (limited_items-MaxLimited(GetMaxLevel(ch))); 
                /* check carrying items first, least important */
        
        if (CountLims(ch->carrying)) {
        sprintf(buf,"Removing carryed items from %s in force rent.",
                GET_NAME(ch));
        log(buf);               
            for (tmp = ch->carrying;tmp;tmp = tmp_next_obj)
            {
                 tmp_next_obj = tmp->next_content;
              if (CountLims(tmp) && (i>0)) 
              {
                obj_from_char(tmp);
                extract_obj(tmp); /* could just drop it in that room... */
                i--;
               }
             } /* end for */
        }

        /* check equiped items next if still over max limited */
        
        if (i >MaxLimited(GetMaxLevel(ch))) 
         {
        sprintf(buf,"Removing equiped items from %s in force rent.",
                GET_NAME(ch));
        log(buf);
         for(ii = 0; ii<MAX_WEAR; ii++) 
          {
          if (CountLims(ch->equipment[ii]) && (i>0)) 
           {
                obj_from_char(ch->equipment[ii]);
                extract_obj(ch->equipment[ii]);
                i--;
           }
          } /* end EQ for */
         } 
         
        if (i >MaxLimited(GetMaxLevel(ch))) {
        sprintf(buf,
         "%s force rented and still had more limited items than suppose to.",
             GET_NAME(ch));
         log(buf);        
        } 
     } /* end remove limited on force rent */

#endif
     
  }
#endif


  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 (!IS_IMMORTAL(ch) && 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 NEW_RENT
    /* RENTAL COST ADJUSTMENT */
    cost->total_cost = 100;
#else
#endif
  
  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);

/* just a bit on informative coding, wasted space... msw */

if (limited_items <= 5)    
   sprintf(buf, "$n tells you 'You carry %d rare items.'",
            limited_items); else
if (limited_items <= 12)
   sprintf(buf, "$n tells you 'Hum, You carry %d rare items, nice.'",
            limited_items); else
if (limited_items < 18)
   sprintf(buf, "$n tells you 'You've got %d rare items, great job.'",
            limited_items);    else
if (limited_items >= 18)
   sprintf(buf, "$n tells you 'WOW! You carry %d rare items, super job!'",
            limited_items); 

    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) ) {

  if (forcerent) {
   sprintf(buf,"%s is being force rented and does not have gold!",GET_NAME(ch));
   log_sev(buf,3);
   slog(buf);
  }

     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);

#if 0

  /* this appears to fuck with saving for polies.. not exactly sure
   why.  (jdb)
   */

  if (IS_SET(ch->specials.act, ACT_POLYSELF))
    sprintf(buf, "rent/%s", lower(ch->desc->original->player.name));
  else 
#endif
    sprintf(buf, "rent/%s", lower(ch->player.name));

  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)
{
char buf[128];

  struct obj_data *obj;
  struct obj_data *in_obj[64],*last_obj;
  int tmp_cur_depth=0; 
  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];

/* item restoring */
      if(st->objects[i].depth>60) {
         log("weird! object have depth >60.\r\n");
         st->objects[i].depth=0;
      }
      if(st->objects[i].depth&&st->objects[i].wearpos) {
         sprintf(buf,"weird! object (%s) weared and in cointainer.\r\n",obj->name);
         log(buf);
         st->objects[i].depth=st->objects[i].wearpos=0;
      }
      if(st->objects[i].depth>tmp_cur_depth) {
         if(st->objects[i].depth!=tmp_cur_depth+1) {
            sprintf(buf,"weird! object depth changed from %d to %d",tmp_cur_depth,st->objects[i].depth);
            log(buf);
         }
         in_obj[tmp_cur_depth++]=last_obj;
      }
      else 
      if(st->objects[i].depth<tmp_cur_depth) {
         tmp_cur_depth--;
      }
      if(st->objects[i].wearpos) 
         equip_char(ch,obj,st->objects[i].wearpos-1);
      if(tmp_cur_depth && !st->objects[i].wearpos) 
         obj_to_obj(obj,in_obj[tmp_cur_depth-1]);
      else if(st->objects[i].wearpos==0) 
         obj_to_char(obj, ch);
      last_obj=obj;
    }
  }
}


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

/*
  load in aliases and poofs first
*/

  load_char_extra(ch);

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

  
  /* r+b is for Binary Reading/Writing */
  if (!(fl = fopen(tbuf, "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("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];

  oe->depth=cur_depth;
  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" */
#if 1
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;
}

  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);
    }*/
  }

  if(obj->contains) {
     cur_depth++;
     obj_to_store(obj->contains, st, ch, delete);
     cur_depth--;
  }
  obj_to_store(obj->next_content, st, ch, delete);
/* and now we can destroy object */
  if (delete) {
     if (obj->in_obj)
       obj_from_obj(obj);
     extract_obj(obj);
  }


}
#else
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);
    }
  }
}


#endif



/* 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? */

  cur_depth=0;

  for(i=0;i<MAX_OBJ_SAVE;i++) {
    st.objects[i].wearpos=0;
    st.objects[i].depth=0;
  }

  for(i=0; i<MAX_WEAR; i++)
    if (ch->equipment[i]) {
      st.objects[st.number].wearpos=i+1;
      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
            CountLimitedItems(&st);
#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);

            rewind(fl);
            WriteObjs(fl, &st);

            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;
                rewind(fl);
                WriteObjs(fl, &st);
                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);
              rewind(fl);
              WriteObjs(fl, &st);
              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) {
              if(obj->item_number<0) abort();
              obj_index[obj->item_number].number++;  
            } else {
#if 0    /* NEW_RENT, he used this to make almost all items rare */
              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++;  
              }
#endif
            }
            extract_obj(obj);
        }
    }
}


void PrintLimitedItems()
{
  int i; 
  char buf[200];
  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);
    }
  }
}


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



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 (IS_NPC(ch))
    return(FALSE);
  
  if ((cmd != 92) && (cmd != 93)) {
    if (!cmd) {
      if (recep->specials.fighting) {
        return(citizen(recep,0,"",mob,type));
      }
    }
    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,FALSE)) {
      
      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,FALSE);
    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, "email")) {  /* set up email finger info */
	 char tmp[256];
	 sprintf(tmp,"email %s",s);
	 do_set_flags(ch,tmp,0);      
        } else 
        if (!strcmp(p,"setsev")) {	/* setup severity level */
 		do_setsev(ch,s,0);
        } else
        if (!strcmp(p,"invislev") && GetMaxLevel(ch) > MAX_MORT) {
 		do_invis(ch,s,242);	/* setup wizinvis level */
        } else
	if (!strcmp(p, "prompt")) { /* setup prompt */
          if(strchr(s,'\n')!=NULL) *((char *)strchr(s,'\n'))=0;
          if(strchr(s,'\r')!=NULL) *((char *)strchr(s,'\r'))=0;
	  do_set_prompt(ch, s, 0);
        } 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);
    }
    if (ch->specials.email) {
		fprintf(fp, "email: %s\n",ch->specials.email);
	}
   if (ch->specials.sev) {
		fprintf(fp, "setsev: %d\n",ch->specials.sev);
	}	
   if (ch->invis_level) {
		fprintf(fp, "invislev: %d\n",ch->invis_level);
	}	
    fprintf(fp, "zone: %d\n", GET_ZONE(ch));
  }
  if( ch->specials.prompt) {
    fprintf(fp, "prompt: %s\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)
{

#ifdef SAVEWORLD

 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);
  }

#endif
}