deltamud/deltamud/
deltamud/deltamud/bin/
deltamud/deltamud/cnf/
deltamud/deltamud/lib/
deltamud/deltamud/lib/etc/
deltamud/deltamud/lib/misc/
deltamud/deltamud/lib/plrobjs/
deltamud/deltamud/lib/text/
deltamud/deltamud/lib/text/help/
deltamud/deltamud/lib/world/
deltamud/deltamud/lib/world/trg/
/* ************************************************************************
   *   File: house.c                                       Part of CircleMUD *
   *  Usage: Handling of player houses                                       *
   *                                                                         *
   *  All rights reserved.  See license.doc for complete information.        *
   *                                                                         *
   *  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
   *  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
   ************************************************************************ */

#include "conf.h"
#include "sysdep.h"

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

extern char *dirs[];
extern struct room_data *world;
extern int top_of_world;
extern const int rev_dir[];
extern struct index_data *obj_index;
extern struct descriptor_data *descriptor_list;

void write_aliases(struct char_data *ch);
void Crash_rentsave (struct char_data *ch, int cost);
int  Crash_is_unrentable (struct obj_data *obj);


struct obj_data *Obj_from_store (struct obj_file_elem object);
int Obj_to_store (struct obj_data *obj, FILE * fl);

struct house_control_rec house_control[MAX_HOUSES];
int num_of_houses = 0;


/* First, the basics: finding the filename; loading/saving objects */

/* Return a filename given a house vnum */
int 
House_get_filename (int vnum, char *filename)
{
  if (vnum < 0)
    return 0;

  sprintf (filename, "house/%d.house", vnum);
  return 1;
}


/* Load all objects for a house */
int 
House_load (room_vnum vnum)
{
  FILE *fl;
  char fname[MAX_STRING_LENGTH];
  struct obj_file_elem object;
  struct obj_data *tobj;
  room_rnum rnum;

  sprintf (buf, "Loading house %d (real_room %d)", (int) vnum, real_room(vnum));
  mudlog(buf,NRM, LVL_IMMORT, TRUE);
  if ((rnum = real_room (vnum)) == -1)
    return 0;
  if (!House_get_filename (vnum, fname))
    return 0;
  if (!(fl = fopen (fname, "r+b")))
    {
      /* no file found */
      return 0;
    }
  while (!feof (fl))
    {
      fread (&object, sizeof (struct obj_file_elem), 1, fl);
      if (ferror (fl))
	{
	  perror ("Reading house file: House_load.");
	  fclose (fl);
	  return 0;
	}
      if (!feof (fl)){
	/* obj_to_room (Obj_from_store (object), rnum);*/
	tobj = Obj_from_store (object);
	if (tobj != NULL){
	  if (!((GET_OBJ_TYPE (tobj) == ITEM_KEY) || 
		(IS_OBJ_STAT (tobj, ITEM_NORENT))))
	    obj_to_room (tobj, rnum);
	}
      }
    }

  fclose (fl);

  return 1;
}


/* Save all objects for a house (recursive; initial call must be followed
   by a call to House_restore_weight)  Assumes file is open already. */
int 
House_save (struct obj_data *obj, FILE * fp)
{
  struct obj_data *tmp;
  int result;

  if (obj)
    {
      House_save (obj->contains, fp);
      House_save (obj->next_content, fp);
      result = Obj_to_store (obj, fp);
      if (!result)
	return 0;

      for (tmp = obj->in_obj; tmp; tmp = tmp->in_obj)
	GET_OBJ_WEIGHT (tmp) -= GET_OBJ_WEIGHT (obj);
    }
  return 1;
}


/* restore weight of containers after House_save has changed them for saving */
void 
House_restore_weight (struct obj_data *obj)
{
  if (obj)
    {
      House_restore_weight (obj->contains);
      House_restore_weight (obj->next_content);
      if (obj->in_obj)
	GET_OBJ_WEIGHT (obj->in_obj) += GET_OBJ_WEIGHT (obj);
    }
}


/* Save all objects in a house */
void 
House_crashsave (room_vnum vnum)
{
  int rnum;
  char buf[MAX_STRING_LENGTH];
  FILE *fp;

  if ((rnum = real_room (vnum)) == -1)
    return;
  if (!House_get_filename (vnum, buf))
    return;
  if (!(fp = fopen (buf, "wb")))
    {
      perror ("SYSERR: Error saving house file");
      return;
    }
  if (!House_save (world[rnum].contents, fp))
    {
      fclose (fp);
      return;
    }
  fclose (fp);
  House_restore_weight (world[rnum].contents);
  REMOVE_BIT (ROOM_FLAGS (rnum), ROOM_HOUSE_CRASH);
}


/* Delete a house save file */
void 
House_delete_file (int vnum)
{
  char buf[MAX_INPUT_LENGTH], fname[MAX_INPUT_LENGTH];
  FILE *fl;

  if (!House_get_filename (vnum, fname))
    return;
  if (!(fl = fopen (fname, "rb")))
    {
      if (errno != ENOENT)
	{
	  sprintf (buf, "SYSERR: Error deleting house file #%d. (1)", vnum);
	  perror (buf);
	}
      return;
    }
  fclose (fl);
  if (unlink (fname) < 0)
    {
      sprintf (buf, "SYSERR: Error deleting house file #%d. (2)", vnum);
      perror (buf);
    }
}


/* List all objects in a house file */
void 
House_listrent (struct char_data *ch, room_vnum vnum)
{
  FILE *fl;
  char fname[MAX_STRING_LENGTH];
  char buf[MAX_STRING_LENGTH];
  struct obj_file_elem object;
  struct obj_data *obj;


  if (!House_get_filename (vnum, fname))
    return;
  if (!(fl = fopen (fname, "rb")))
    {
      sprintf (buf, "No objects on file for house #%d.\r\n", (int) vnum);
      send_to_char (buf, ch);
      return;
    }
  *buf = '\0';
  while (!feof (fl))
    {
      fread (&object, sizeof (struct obj_file_elem), 1, fl);
      if (ferror (fl))
	{
	  fclose (fl);
	  return;
	}
      if (!feof (fl) && (obj = Obj_from_store (object)) != NULL)
	{
	  sprintf (buf, "%s [%5d] (%5dau) %s\r\n", buf,
		   GET_OBJ_VNUM (obj), GET_OBJ_RENT (obj),
		   obj->short_description);
	  free_obj (obj);
	}
    }

  send_to_char (buf, ch);
  fclose (fl);
}




/******************************************************************
 *  Functions for house administration (creation, deletion, etc.  *
 *****************************************************************/

int 
find_house (room_vnum vnum)
{
  int i;

  for (i = 0; i < num_of_houses; i++)
    if (house_control[i].vnum == vnum)
      return i;

  return -1;
}



/* Save the house control information */
void 
House_save_control (void)
{
  FILE *fl;

  if (!(fl = fopen (HCONTROL_FILE, "wb")))
    {
      perror ("SYSERR: Unable to open house control file");
      return;
    }
  /* write all the house control recs in one fell swoop.  Pretty nifty, eh? */
  fwrite (house_control, sizeof (struct house_control_rec), num_of_houses, fl);

  fclose (fl);
}


/* call from boot_db - will load control recs, load objs, set atrium bits */
/* should do sanity checks on vnums & remove invalid records */
void 
House_boot (void)
{
  struct house_control_rec temp_house;
  long real_house, real_atrium=-1;
  FILE *fl;

  memset ((char *) house_control, 0, sizeof (struct house_control_rec) * MAX_HOUSES);

  if (!(fl = fopen (HCONTROL_FILE, "rb"))){
    log ("House control file does not exist.");
    return;
  }
  while (!feof (fl) && num_of_houses < MAX_HOUSES){
    fread (&temp_house, sizeof (struct house_control_rec), 1, fl);
    
    if (feof (fl))
      break;
    
    if ((real_house = real_room (temp_house.vnum)) < 0)
      continue;		/* this vnum doesn't exist -- skip */
    
    if ((find_house (temp_house.vnum)) >= 0)
      continue;		/* this vnum is already a hosue -- skip */
    

    if (temp_house.owner != -1){
      if (get_name_by_id (temp_house.owner) == NULL){
	log("DEBUG: House owner does not exist?!");
	continue;		/* owner no longer exists -- skip */
      }
      
      if ((real_atrium = real_room (temp_house.atrium)) < 0){
	log("DEBUG: House atrium does not exist?!");
	continue;		/* house doesn't have an atrium -- skip */
      }

      if (temp_house.exit_num < 0 || temp_house.exit_num >= NUM_OF_DIRS){
	log("DEBUG: House has invalid exit num?!");
	continue;		/* invalid exit num -- skip */
      }

      if (TOROOM (real_house, temp_house.exit_num) != real_atrium){
	log("DEBUG: House exit num mismatch?!");
	continue;		/* exit num mismatch -- skip */
      }
    }
    house_control[num_of_houses++] = temp_house;
    
    SET_BIT (ROOM_FLAGS (real_house), ROOM_HOUSE | ROOM_PRIVATE);
    if (real_atrium!=-1) SET_BIT (ROOM_FLAGS (real_atrium), ROOM_ATRIUM);
    House_load (temp_house.vnum);
    }
  
  fclose (fl);
  House_save_control ();
}



/* "House Control" functions */

char *HCONTROL_FORMAT =
"Usage: hcontrol build <house vnum> <exit direction> <player name>\r\n"
"       hcontrol destroy <house vnum>\r\n"
"       hcontrol update <house vnum> <exit direction> [player name]\r\n"
"       hcontrol pay <house vnum>\r\n"
"       hcontrol show <guests>\r\n"
"       hcontrol crashsave <house vnum>\r\n"
"       hcontrol guests\n";

#define NAME(x) ((temp = get_name_by_id(x)) == NULL ? "<UNDEF>" : temp)

void 
hcontrol_list_houses (struct char_data *ch, int showguests)
{
  int i, j;
  char *timestr, *temp;
  char built_on[128], last_pay[128], own_name[128];

  if (!num_of_houses)
    {
      send_to_char ("No houses have been defined.\r\n", ch);
      return;
    }
  strcpy (buf, "Address  Atrium  Build Date  Guests  Owner        Last Paymt\r\n");
  strcat (buf, "-------  ------  ----------  ------  ------------ ----------\r\n");

  for (i = 0; i < num_of_houses; i++)
    {
      if (house_control[i].built_on)
	{
	  timestr = asctime (localtime (&(house_control[i].built_on)));
	  *(timestr + 10) = 0;
	  strcpy (built_on, timestr);
	}
      else
	strcpy (built_on, "Unknown");

      if (house_control[i].last_payment)
	{
	  timestr = asctime (localtime (&(house_control[i].last_payment)));
	  *(timestr + 10) = 0;
	  strcpy (last_pay, timestr);
	}
      else
	strcpy (last_pay, "None");

      if (house_control[i].owner != -1)
	strcpy (own_name, NAME (house_control[i].owner));
      else
	strcpy (own_name, "HCRSH");

      sprintf (buf, "%s%7d %7d  %-10s    %2d    %-12s %s\r\n", buf,
	       (int) house_control[i].vnum, (int) house_control[i].atrium, built_on,
	       house_control[i].num_of_guests, CAP (own_name), last_pay);

      if ((house_control[i].num_of_guests) && showguests)
	{
	  strcat (buf, "     Guests: ");
	  for (j = 0; j < house_control[i].num_of_guests; j++)
	    {
	      sprintf (buf2, "%s ", NAME (house_control[i].guests[j]));
	      strcat (buf, CAP (buf2));
	    }
	  strcat (buf, "\r\n");
	}
    }
  send_to_char (buf, ch);
}

void 
hcontrol_list_houses_guests (struct char_data *ch)
{
  int i, j, count;
  char *temp;
  char own_name[128];

  if (!num_of_houses)
    {
      send_to_char ("No houses have been defined.\r\n", ch);
      return;
    }
  strcpy (buf, "Address  Owner        # Guests     \r\n");
  strcat (buf, "-------  ------       - ---------- \r\n");

  for (i = 0; i < num_of_houses; i++)
    {
      if (house_control[i].owner != -1)
	strcpy (own_name, NAME (house_control[i].owner));
      else
	strcpy (own_name, "HCRSH");

      sprintf (buf, "%s%7d %-12s %2d ", buf,
	       (int) house_control[i].vnum, CAP (own_name),
	       house_control[i].num_of_guests);

      if (house_control[i].num_of_guests)
	{
	  count = 0;
	  for (j = 0; j < house_control[i].num_of_guests; j++)
	    {
	      if ((++count > 5) 
		  && (j != (house_control[i].num_of_guests + 1))){
		count = 0;
		strcat(buf, "\r\n                        ");
	      }
	      sprintf (buf2, "%s ", NAME (house_control[i].guests[j]));
	      strcat (buf, CAP (buf2));
	    }
	}
      strcat (buf, "\r\n");
	  
    }
  send_to_char (buf, ch);
}



void 
hcontrol_build_house (struct char_data *ch, char *arg)
{
  char arg1[MAX_INPUT_LENGTH];
  struct house_control_rec temp_house;
  long virt_house, real_house, real_atrium, virt_atrium, exit_num;
  long owner;

  if (num_of_houses >= MAX_HOUSES)
    {
      send_to_char ("Max houses already defined.\r\n", ch);
      return;
    }

  /* first arg: house's vnum */
  arg = one_argument (arg, arg1);
  if (!*arg1)
    {
      send_to_char (HCONTROL_FORMAT, ch);
      return;
    }
  virt_house = atoi (arg1);
  if ((real_house = real_room (virt_house)) < 0)
    {
      send_to_char ("No such room exists.\r\n", ch);
      return;
    }
  if ((find_house (virt_house)) >= 0)
    {
      send_to_char ("House already exists.\r\n", ch);
      return;
    }

  /* second arg: direction of house's exit */
  arg = one_argument (arg, arg1);
  if (!*arg1)
    {
      send_to_char (HCONTROL_FORMAT, ch);
      return;
    }
  if ((exit_num = search_block (arg1, (const char **) dirs, FALSE)) < 0)
    {
      sprintf (buf, "'%s' is not a valid direction.\r\n", arg1);
      send_to_char (buf, ch);
      return;
    }
  if (TOROOM (real_house, exit_num) == NOWHERE)
    {
      sprintf (buf, "There is no exit %s from room %d.\r\n", dirs[exit_num],
	       (int) virt_house);
      send_to_char (buf, ch);
      return;
    }

  real_atrium = TOROOM (real_house, exit_num);
  virt_atrium = world[real_atrium].number;

  if (TOROOM (real_atrium, rev_dir[exit_num]) != real_house)
    {
      send_to_char ("A house's exit must be a two-way door.\r\n", ch);
      return;
    }

  /* third arg: player's name */
  arg = one_argument (arg, arg1);
  if (!*arg1)
    {
      send_to_char (HCONTROL_FORMAT, ch);
      return;
    }
  if ((owner = get_id_by_name (arg1)) < 0)
    {
      sprintf (buf, "Unknown player '%s'.\r\n", arg1);
      send_to_char (buf, ch);
      return;
    }

  temp_house.mode = HOUSE_PRIVATE;
  temp_house.vnum = virt_house;
  temp_house.atrium = virt_atrium;
  temp_house.exit_num = exit_num;
  temp_house.built_on = time (0);
  temp_house.last_payment = 0;
  temp_house.owner = owner;
  temp_house.num_of_guests = 0;

  house_control[num_of_houses++] = temp_house;

  SET_BIT (ROOM_FLAGS (real_house), ROOM_HOUSE | ROOM_PRIVATE);
  SET_BIT (ROOM_FLAGS (real_atrium), ROOM_ATRIUM);
  House_crashsave (virt_house);

  send_to_char ("House built.  Mazel tov!\r\n", ch);
  House_save_control ();
}


void 
hcontrol_crashsave_house (struct char_data *ch, char *arg)
{
  char arg1[MAX_INPUT_LENGTH];
  struct house_control_rec temp_house;
  long virt_house, real_house;

  if (num_of_houses >= MAX_HOUSES)
    {
      send_to_char ("Max crashsaveables/houses already defined.\r\n", ch);
      return;
    }

  /* first arg: house's vnum */
  arg = one_argument (arg, arg1);
  if (!*arg1)
    {
      send_to_char (HCONTROL_FORMAT, ch);
      return;
    }
  virt_house = atoi (arg1);
  if ((real_house = real_room (virt_house)) < 0)
    {
      send_to_char ("No such room exists.\r\n", ch);
      return;
    }
  if ((find_house (virt_house)) >= 0)
    {
      send_to_char ("House already exists.\r\n", ch);
      return;
    }

  /* second arg: direction of house's exit */
  /* NOT NEEDED ?
  arg = one_argument (arg, arg1);
  if (!*arg1)
    {
      send_to_char (HCONTROL_FORMAT, ch);
      return;
    }
  if ((exit_num = search_block (arg1, dirs, FALSE)) < 0)
    {
      sprintf (buf, "'%s' is not a valid direction.\r\n", arg1);
      send_to_char (buf, ch);
      return;
    }
  if (TOROOM (real_house, exit_num) == NOWHERE)
    {
      sprintf (buf, "There is no exit %s from room %d.\r\n", dirs[exit_num],
	       (int) virt_house);
      send_to_char (buf, ch);
      return;
    }

  real_atrium = TOROOM (real_house, exit_num);
  virt_atrium = world[real_atrium].number;

  if (TOROOM (real_atrium, rev_dir[exit_num]) != real_house)
    {
      send_to_char ("A house's exit must be a two-way door.\r\n", ch);
      return;
    }
  */
  
  /* third arg: player's name */
  /* NOT NEEDED ?
  arg = one_argument (arg, arg1);
  if (!*arg1)
    {
      send_to_char (HCONTROL_FORMAT, ch);
      return;
    }
  if ((owner = get_id_by_name (arg1)) < 0)
    {
      sprintf (buf, "Unknown player '%s'.\r\n", arg1);
      send_to_char (buf, ch);
      return;
    }
  */

  temp_house.mode = HOUSE_OPEN;
  temp_house.vnum = virt_house;
  temp_house.atrium = 0;
  temp_house.exit_num = 0;
  temp_house.built_on = time (0);
  temp_house.last_payment = 0;
  temp_house.owner = -1;
  temp_house.num_of_guests = 0;

  house_control[num_of_houses++] = temp_house;

  SET_BIT (ROOM_FLAGS (real_house), ROOM_HOUSE | ROOM_PRIVATE);
  /* SET_BIT (ROOM_FLAGS (real_atrium), ROOM_ATRIUM); */
  House_crashsave (virt_house);

  send_to_char ("Crashsaveable room built.  Mazel tov!\r\n", ch);
  House_save_control ();
}



void 
hcontrol_destroy_house (struct char_data *ch, char *arg)
{
  int i, j;
  long real_atrium, real_house;

  if (!*arg)
    {
      send_to_char (HCONTROL_FORMAT, ch);
      return;
    }
  if ((i = find_house (atoi (arg))) < 0)
    {
      send_to_char ("Unknown house.\r\n", ch);
      return;
    }
  if ((real_atrium = real_room (house_control[i].atrium)) < 0)
    log ("SYSERR: House had invalid atrium!");
  else
    REMOVE_BIT (ROOM_FLAGS (real_atrium), ROOM_ATRIUM);

  if ((real_house = real_room (house_control[i].vnum)) < 0)
    log ("SYSERR: House had invalid vnum!");
  else
    REMOVE_BIT (ROOM_FLAGS (real_house),
		ROOM_HOUSE | ROOM_PRIVATE | ROOM_HOUSE_CRASH);

  House_delete_file (house_control[i].vnum);

  for (j = i; j < num_of_houses - 1; j++)
    house_control[j] = house_control[j + 1];

  num_of_houses--;

  send_to_char ("House deleted.\r\n", ch);
  House_save_control ();

  /*
   * Now, reset the ROOM_ATRIUM flag on all existing houses' atriums,
   * just in case the house we just deleted shared an atrium with another
   * house.  --JE 9/19/94
   */
  for (i = 0; i < num_of_houses; i++)
    if ((real_atrium = real_room (house_control[i].atrium)) >= 0)
      SET_BIT (ROOM_FLAGS (real_atrium), ROOM_ATRIUM);
}


void 
hcontrol_pay_house (struct char_data *ch, char *arg)
{
  int i;

  if (!*arg)
    send_to_char (HCONTROL_FORMAT, ch);
  else if ((i = find_house (atoi (arg))) < 0)
    send_to_char ("Unknown house.\r\n", ch);
  else
    {
      sprintf (buf, "Payment for house %s collected by %s.", arg, GET_NAME (ch));
      mudlog (buf, NRM, MAX (LVL_IMMORT, GET_INVIS_LEV (ch)), TRUE);

      house_control[i].last_payment = time (0);
      House_save_control ();
      send_to_char ("Payment recorded.\r\n", ch);
    }
}

void 
hcontrol_update_house (struct char_data *ch, char *arg)
{
  int house;
  char arg1[MAX_INPUT_LENGTH];
  long virt_house, real_house, real_atrium, virt_atrium, exit_num;
  long owner;

  /* first arg: house's vnum */
  arg = one_argument (arg, arg1);

  if (!*arg1){
    send_to_char (HCONTROL_FORMAT, ch);
    return;
  }else if ((house = find_house (atoi (arg1))) < 0){
    send_to_char ("Unknown house.\r\n", ch);
    return;
  }
  virt_house = atoi(arg1);
  real_house = real_room(virt_house);

  /* second arg: direction of house's exit */
  arg = one_argument (arg, arg1);
  if (!*arg1){
    send_to_char (HCONTROL_FORMAT, ch);
    return;
  }
  if ((exit_num = search_block (arg1, (const char **) dirs, FALSE)) < 0) {
    sprintf (buf, "'%s' is not a valid direction.\r\n", arg1);
    send_to_char (buf, ch);
    return;
  }
  if (TOROOM (real_house, exit_num) == NOWHERE) {
    sprintf (buf, "There is no exit %s from room %d.\r\n", dirs[exit_num],
	     (int) virt_house);
    send_to_char (buf, ch);
    return;
  }

  real_atrium = TOROOM (real_house, exit_num);
  virt_atrium = world[real_atrium].number;

  if (TOROOM (real_atrium, rev_dir[exit_num]) != real_house) {
    send_to_char ("A house's exit must be a two-way door.\r\n", ch);
    return;
  }

  /* third arg: player's name */
  arg = one_argument (arg, arg1);
  if (!*arg1){
    owner = -1;
  }else if ((owner = get_id_by_name (arg1)) < 0){
    sprintf (buf, "Unknown player '%s'.\r\n", arg1);
    send_to_char (buf, ch);
    return;
  }
  /* Not needed 
  temp_house.mode = HOUSE_PRIVATE;
  temp_house.vnum = virt_house;
  temp_house.atrium = virt_atrium;
  temp_house.exit_num = exit_num;
  temp_house.built_on = time (0);
  temp_house.last_payment = 0;
  temp_house.owner = owner;
  temp_house.num_of_guests = 0;
  */

  house_control[house].atrium = virt_atrium;
  house_control[house].exit_num = exit_num;
  if (owner != -1)
    house_control[house].owner = owner;

  SET_BIT (ROOM_FLAGS (real_house), ROOM_HOUSE | ROOM_PRIVATE);
  SET_BIT (ROOM_FLAGS (real_atrium), ROOM_ATRIUM);
  House_crashsave (virt_house);
  
  send_to_char ("House Updated!\r\n", ch);
  House_save_control ();
}

/* The hcontrol command itself, used by imms to create/destroy houses */
ACMD (do_hcontrol)
{
  char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];

  half_chop (argument, arg1, arg2);

  if (is_abbrev (arg1, "build"))
    hcontrol_build_house (ch, arg2);
  else if (is_abbrev (arg1, "crashsave"))
    hcontrol_crashsave_house (ch, arg2);
  else if (is_abbrev (arg1, "destroy"))
    hcontrol_destroy_house (ch, arg2);
  else if (is_abbrev (arg1, "pay"))
    hcontrol_pay_house (ch, arg2);
  else if (is_abbrev (arg1, "update"))
    hcontrol_update_house (ch, arg2);
  else if (is_abbrev (arg1, "show")){
    if (is_abbrev (arg2, "guests"))
      hcontrol_list_houses (ch, TRUE);
    else
      hcontrol_list_houses (ch, FALSE);
  } else if (is_abbrev (arg1, "guests"))
    hcontrol_list_houses_guests (ch);
  else
    send_to_char (HCONTROL_FORMAT, ch);
}


/* The house command, used by mortal house owners to assign guests */
ACMD (do_house)
{
  int i, j, id;
  char *temp;

  one_argument (argument, arg);

  if (!IS_SET (ROOM_FLAGS (ch->in_room), ROOM_HOUSE))
    send_to_char ("You must be in your house to set guests.\r\n", ch);
  else if ((i = find_house (world[ch->in_room].number)) < 0)
    send_to_char ("Um.. this house seems to be screwed up.\r\n", ch);
  else if (GET_IDNUM (ch) != house_control[i].owner)
    send_to_char ("Only the primary owner can set guests.\r\n", ch);
  else if (!*arg)
    {
      send_to_char ("Guests of your house:\r\n", ch);
      if (house_control[i].num_of_guests == 0)
	send_to_char ("  None.\r\n", ch);
      else
	for (j = 0; j < house_control[i].num_of_guests; j++)
	  {
	    strcpy (buf, NAME (house_control[i].guests[j]));
	    send_to_char (strcat (CAP (buf), "\r\n"), ch);
	  }
    }
  else if ((id = get_id_by_name (arg)) < 0)
    send_to_char ("No such player.\r\n", ch);
  else
    {
      for (j = 0; j < house_control[i].num_of_guests; j++)
	if (house_control[i].guests[j] == id)
	  {
	    for (; j < house_control[i].num_of_guests; j++)
	      house_control[i].guests[j] = house_control[i].guests[j + 1];
	    house_control[i].num_of_guests--;
	    House_save_control ();
	    send_to_char ("Guest deleted.\r\n", ch);
	    return;
	  }
      j = house_control[i].num_of_guests++;
      house_control[i].guests[j] = id;
      House_save_control ();
      send_to_char ("Guest added.\r\n", ch);
    }
}

int 
Crash_report_unbedables (struct char_data *ch, struct obj_data *obj)
{
  char buf[128];
  int has_nobeds = 0;

  if (obj)
    {
      if (Crash_is_unrentable (obj))
	{
	  has_nobeds = 1;
	  sprintf (buf, "You cannot go to bed with %s.\r\n", OBJS (obj, ch));
	  /* act (buf, FALSE, recep, 0, ch, TO_VICT); */
	  send_to_char(buf, ch);
	}
      has_nobeds += Crash_report_unbedables (ch, obj->contains);
      has_nobeds += Crash_report_unbedables (ch, obj->next_content);
    }
  return (has_nobeds);
}


ACMD (do_bed)
{
  int i, nobed;
  long save_room;
  struct descriptor_data *d, *next_d;
 
  if (!IS_SET (ROOM_FLAGS (ch->in_room), ROOM_HOUSE))
    send_to_char ("You must be in your house to go to bed.\r\n", ch);
  else if ((i = find_house (world[ch->in_room].number)) < 0)
    send_to_char ("Um.. this house seems to be screwed up.\r\n", ch);
  else if (GET_IDNUM (ch) != house_control[i].owner)
    send_to_char ("Only the primary owner can go to bed in the house.\r\n", 
		  ch);
  else {
    nobed = Crash_report_unbedables (ch, ch->carrying);
    for (i = 0; i < NUM_WEARS; i++)
      nobed += Crash_report_unbedables (ch, GET_EQ (ch, i));
    if (nobed)
      return;
    write_aliases(ch);
    REMOVE_BIT (PRF2_FLAGS (ch), PRF2_LOCKOUT);      
    Crash_rentsave (ch, 0);

// this was annoying, removed 8/23/98 --Mulder
//    if(GET_LEVEL(ch) < LVL_IMMORT)
//      {
//	sprintf (buf, "&m[&YINFO&m]&n %s has left Deltania. (bed)\r\n", 
//		 GET_NAME (ch));
//	send_to_all (buf);
//      }
     act("$n has quit the game. (bed)", TRUE, ch, 0, 0, TO_ROOM);
    save_room = ch->in_room;
    extract_char (ch);
    save_char (ch, save_room);
    for (d = descriptor_list; d; d = next_d)
      {
	next_d = d->next;
	if (d == ch->desc)
	  continue;
	if (d->character && (GET_IDNUM (d->character) == GET_IDNUM (ch)))
	  close_socket (d);
      }

  }

}

/* Misc. administrative functions */


/* crash-save all the houses */
void 
House_save_all (void)
{
  int i;
  long real_house;

  for (i = 0; i < num_of_houses; i++)
    if ((real_house = real_room (house_control[i].vnum)) != NOWHERE)
      if (IS_SET (ROOM_FLAGS (real_house), ROOM_HOUSE_CRASH))
	House_crashsave (house_control[i].vnum);
}


/* note: arg passed must be house vnum, so there. */
int 
House_can_enter (struct char_data *ch, room_vnum house)
{
  int i, j;

  if (GET_LEVEL (ch) >= LVL_GRGOD || (i = find_house (house)) < 0)
    return 1;

  switch (house_control[i].mode)
    {
    case HOUSE_PRIVATE:
      if (GET_IDNUM (ch) == house_control[i].owner)
	return 1;
      for (j = 0; j < house_control[i].num_of_guests; j++)
	if (GET_IDNUM (ch) == house_control[i].guests[j])
	  return 1;
      return 0;
      break;
    case HOUSE_OPEN:
      return 1;
    }

  return 0;
}