1stMUD/corefiles/
1stMUD/gods/
1stMUD/player/
1stMUD/win32/
1stMUD/win32/ROM/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*     _/_/_/   _/      _/    _/           Devil's Lament MUD              *
*    _/   _/  _/      _/ _/ _/      (c) 1999-2002 by Ryan Jennings        *
*   _/   _/  _/      _/    _/          Telnet : <dlmud.com:3778>          *
*  _/_/_/   _/_/_/  _/    _/           E-Mail : <dlmud@dlmud.com>         *
*                                   Website: <http://www.dlmud.com/>      *
***************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if !defined(WIN32)
#include <unistd.h>
#endif
#include "merc.h"
#include "interp.h"
#include "recycle.h"
#include "olc.h"

DECLARE_DO_FUN (home_buy);
DECLARE_DO_FUN (home_add);
DECLARE_DO_FUN (home_furnish);
DECLARE_DO_FUN (home_unfurnish);
DECLARE_DO_FUN (home_sell);
DECLARE_DO_FUN (home_describe);
DECLARE_DO_FUN (home_name);
DECLARE_DO_FUN (home_evict);
DECLARE_DO_FUN (home_invite);
DECLARE_DO_FUN (home_accept);
DECLARE_DO_FUN (home_deny);
DECLARE_DO_FUN (do_get_key);
DECLARE_DO_FUN (home_help);
DECLARE_DO_FUN (home_link);
DECLARE_DO_FUN (home_unlink);
DECLARE_DO_FUN (do_gohome);

void unlink_reset (ROOM_INDEX_DATA * pRoom, RESET_DATA * pReset);

#define HOUSE_PRICE 5000000
#define ROOM_PRICE  3000000

#define H_NONE 0
#define H_OBJ  1
#define H_MOB  2

struct home_type
{
	vnum_t vnum;
	long cost;
	int quest;
	int tp;
	char *name;
	char *list;
	int type;
};

const struct home_type home_table[] = {
	{0, 125000, 10, 0, "healrate", "Up a rooms Heal Rate by 50", H_NONE},
	{0, 125000, 10, 0, "manarate", "Up a rooms Mana Rate by 50", H_NONE},
	/* examples
	   {HOME_VNUM_QUESTMASTER, 5000000, 10, 0, "questmaster", "A personal Questmaster.", H_MOB},
	   {HOME_VNUM_BED, 100000, 2, 0, "bed", "A double bed.", H_OBJ},
	 */
	{0, 0, 0, 0, NULL, NULL, 0}
};

int count_home (CHAR_DATA * ch)
{
	int i, count = 0;

	if (!ch || IS_NPC (ch))
		return 0;

	for (i = 0; i < MAX_HOUSE_ROOMS; i++)
		if (ch->pcdata->home[i] > 0
			&& get_room_index (ch->pcdata->home[i]) != NULL)
			count++;

	return count;
}

void reset_homes (CHAR_DATA * ch)
{
	int i;

	if (!ch || IS_NPC (ch))
		return;

	for (i = 0; i < MAX_HOUSE_ROOMS; i++)
		ch->pcdata->home[i] = -1;

	ch->pcdata->home_key = -1;
	return;
}

bool is_home_owner (CHAR_DATA * ch, ROOM_INDEX_DATA * pHome)
{
	int i;

	if (pHome == NULL)
		return FALSE;

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

	for (i = 0; i < MAX_HOUSE_ROOMS; i++)
		if (ch->pcdata->home[i] > 0
			&& get_room_index (ch->pcdata->home[i]) == pHome)
			return TRUE;

	return FALSE;
}

int tally_resets (ROOM_INDEX_DATA * pRoom, long cost, int trivia, int quest)
{
	RESET_DATA *pReset;
	int rcount = 0, i;

	if (pRoom == NULL)
		return 0;

	for (pReset = pRoom->reset_first; pReset != NULL; pReset = pReset->next)
	{
		if (pReset->command == 'O' || pReset->command == 'M')
		{
			for (i = 0; home_table[i].name != NULL; i++)
			{
				if (pReset->arg1 == home_table[i].vnum)
				{
					cost += home_table[i].cost / 3;
					trivia += home_table[i].tp / 3;
					quest += home_table[i].quest / 3;
					rcount++;
				}
			}
		}
	}
	return rcount;
}

int get_direction (const char *arg)
{
	if (!str_cmp (arg, "n") || !str_cmp (arg, "north"))
		return 0;
	if (!str_cmp (arg, "e") || !str_cmp (arg, "east"))
		return 1;
	if (!str_cmp (arg, "s") || !str_cmp (arg, "south"))
		return 2;
	if (!str_cmp (arg, "w") || !str_cmp (arg, "west"))
		return 3;
	if (!str_cmp (arg, "u") || !str_cmp (arg, "up"))
		return 4;
	if (!str_cmp (arg, "d") || !str_cmp (arg, "down"))
		return 5;

	return -1;
}

bool get_key (CHAR_DATA * ch)
{
	OBJ_INDEX_DATA *keyindex = NULL;
	OBJ_DATA *key = NULL;

	if (!ch || IS_NPC (ch) || ch->pcdata->home_key <= 0)
		return FALSE;

	if ((keyindex = get_obj_index (ch->pcdata->home_key)) == NULL)
	{
		chprintln (ch,
				   "Could not find your key, please have an immortal fix this.");
		return FALSE;
	}

	if (get_obj_here (ch, keyindex->name) != NULL)
	{
		chprintln (ch, "You already have a key to your home.");
		return TRUE;
	}

	if ((key = create_object (keyindex, 1)) == NULL)
		return FALSE;

	obj_to_char (key, ch);
	chprintln (ch, "A house key appears in your inventory.");

	return TRUE;
}

CH_CMD (do_get_key)
{
	get_key (ch);
}

CH_CMD (home_help)
{
	chprintln (ch, "Syntax(s):");
	if (ch->pcdata->home_invite != 0)
	{
		chprintln (ch, "Accept    - accept an invitation to someone's home");
		chprintln (ch,
				   "Deny      - turn down an invitation to someone's home");
	}
	if (count_home (ch) == 0)
		chprintln (ch,
				   "Buy       - purchase a home in <direction> (must be in the right area)");
	else
	{
		chprintln (ch,
				   "Sell      - sells your home completly for 1/3 the price");
		chprintln (ch,
				   "Add       - adds another room in <direction>, must be in your home");
		chprintln (ch,
				   "Describe  - describes a room using the string editor");
		chprintln (ch, "Name      - name or rename's a room");
		chprintln (ch,
				   "Furnish   - add objects or mobiles to a room in your home");
		chprintln (ch,
				   "Unfurnish - sells objects or mobiles placed in your home");
		chprintln (ch, "Key       - gets a replacement key for your home");
		chprintln (ch,
				   "Recall    - recalls you to your home (gohome for short)");
		chprintln (ch, "Evict     - kick's someone out of your home");
		chprintln (ch, "Invite    - invite someone to your home");
		chprintln (ch, "Link      - Link a room to a specified area");
		chprintln (ch, "Unlink    - Unlink an exit");
	}
}

CH_CMD (do_home)
{
	if (!ch)
		return;

	if (IS_NPC (ch))
	{
		chprintln (ch, "Mobiles don't have homes =).");
		return;
	}

	vinterpret (ch, argument, "buy", home_buy, "add", home_add, "sell",
				home_sell, "describe", home_describe, "name", home_name,
				"furnish", home_furnish, "unfurnish", home_unfurnish, "key",
				do_get_key, "recall", do_gohome, "evict", home_evict, "link",
				home_link, "unlink", home_unlink, "list", home_help, "invite",
				home_invite, "accept", home_accept, "deny", home_deny, NULL,
				home_help);
}

CH_CMD (home_buy)
{
	ROOM_INDEX_DATA *pRoom = NULL;
	OBJ_INDEX_DATA *pObj;
	AREA_DATA *pArea;
	EXIT_DATA *pExit;
	char buf[MSL];
	int door, rev, iHash;
	vnum_t i;

	if (!ch || IS_NPC (ch))
		return;

	pArea = ch->in_room->area;

	if (!pArea || !IS_SET (pArea->area_flags, AREA_PLAYER_HOMES))
	{
		chprintln (ch, "Player Homes are not allowed in this area.");
		return;
	}

	if (ch->gold < HOUSE_PRICE)
	{
		chprintlnf (ch, "{wIt costs %d gold to buy a home.", HOUSE_PRICE);
		return;
	}

	if (ch->pcdata->trivia < 40)
	{
		chprintln (ch, "It costs 40 trivia points to buy a house.");
		return;
	}

	if (count_home (ch) > 0)
	{
		chprintln (ch,
				   "{wYou already own a home, use HOME ADD or HOME FURNISH.");
		return;
	}

	if (!IS_SET (ch->in_room->room_flags, HOME_ENTRANCE))
	{
		chprintln (ch, "You must be at an entrance to a future home.");
		return;
	}

	if ((door = get_direction (argument)) == -1 || door > 3)
	{
		chprintln (ch,
				   "Which direction from here do you want to start your home?");
		return;
	}

	if (ch->in_room->exit[door])
	{
		chprintln (ch, "A room already exits in that location.");
		return;
	}

	for (i = pArea->min_vnum; i < pArea->max_vnum; i++)
	{
		if ((get_obj_index (i)) == NULL)
		{
			pObj = new_obj_index ();
			pObj->vnum = i;
			pObj->area = pArea;
			sprintf (buf, "key %s home", ch->name);
			replace_string (pObj->name, buf);
			sprintf (buf, "%s's key", capitalize (ch->name));
			replace_string (pObj->short_descr, buf);
			sprintf (buf, "The key to %s's home is here.",
					 capitalize (ch->name));
			replace_string (pObj->description, buf);
			pObj->item_type = ITEM_KEY;
			SET_BIT (pObj->wear_flags, ITEM_TAKE);
			SET_BIT (pObj->wear_flags, ITEM_HOLD);
			pObj->condition = -1;
			iHash = i % MAX_KEY_HASH;
			pObj->next = obj_index_hash[iHash];
			obj_index_hash[iHash] = pObj;
			ch->pcdata->home_key = pObj->vnum;
			break;
		}
	}

	for (i = pArea->min_vnum; i < pArea->max_vnum; i++)
	{
		if ((get_room_index (i)) == NULL)
		{
			// do the room
			pRoom = new_room_index ();
			pRoom->area = pArea;
			pRoom->vnum = i;
			pRoom->sector_type = SECT_INSIDE;
			sprintf (buf, "%s\'s Home", capitalize (ch->name));
			replace_string (pRoom->name, buf);
			replace_string (pRoom->description,
							"This is your desc. You can edit this with HOME DESCRIBE.\n\r");
			replace_string (pRoom->owner, ch->name);
			SET_BIT (pRoom->room_flags, ROOM_INDOORS);
			iHash = i % MAX_KEY_HASH;
			pRoom->next = room_index_hash[iHash];
			room_index_hash[iHash] = pRoom;
			// do the exit
			// first room
			ch->in_room->exit[door] = new_exit ();
			ch->in_room->exit[door]->u1.to_room = pRoom;
			ch->in_room->exit[door]->orig_door = door;
			SET_BIT (ch->in_room->exit[door]->rs_flags,
					 EX_ISDOOR | EX_CLOSED | EX_NOPASS | EX_PICKPROOF);
			ch->in_room->exit[door]->exit_info =
				ch->in_room->exit[door]->rs_flags;
			replace_string (ch->in_room->exit[door]->keyword, "door");
			sprintf (buf, "You see the door to %s's home.",
					 capitalize (ch->name));
			replace_string (ch->in_room->exit[door]->description, buf);
			// end first room              
			rev = rev_dir[door];
			// new room
			pExit = new_exit ();
			pExit->u1.to_room = ch->in_room;
			pExit->orig_door = rev;
			pRoom->exit[rev] = pExit;
			pRoom->exit[rev]->rs_flags = ch->in_room->exit[door]->rs_flags;
			pRoom->exit[rev]->exit_info = ch->in_room->exit[door]->exit_info;
			replace_string (pRoom->exit[rev]->keyword, "door");
			sprintf (buf, "You see the door to %s's home.",
					 capitalize (ch->name));
			replace_string (pRoom->exit[rev]->description, buf);
			// end new room
			// lock if key exits
			if (get_key (ch) == TRUE)
			{
				SET_BIT (ch->in_room->exit[door]->rs_flags, EX_LOCKED);
				ch->in_room->exit[door]->key = ch->pcdata->home_key;
				pRoom->exit[rev]->key = ch->pcdata->home_key;
			}
			save_area (pArea);
			break;
		}
	}

	if (!pRoom)
	{
		chprintln (ch,
				   "A new home could not be created for you. please contact an immortal.");
		return;
	}

	ch->pcdata->home[count_home (ch)] = pRoom->vnum;

	ch->gold -= HOUSE_PRICE;

	ch->pcdata->trivia -= 40;

	chprintln (ch, "Congratulations, you are now a proud home owner.");
	save_char_obj (ch);
	return;
}

CH_CMD (home_add)
{
	ROOM_INDEX_DATA *pRoom = NULL;
	AREA_DATA *pArea;
	EXIT_DATA *pExit;
	char buf[MSL];
	int door, rev, iHash;
	vnum_t i;

	if (!ch || IS_NPC (ch))
		return;

	pArea = ch->in_room->area;

	if (!pArea || !IS_SET (pArea->area_flags, AREA_PLAYER_HOMES))
	{
		chprintln (ch, "Player Homes are not allowed in this area.");
		return;
	}

	if (count_home (ch) == 0)
	{
		chprintln (ch, "Use HOME BUY to purchase a home first.");
		return;
	}

	if (ch->gold < ROOM_PRICE)
	{
		chprintln (ch, "{wYou don't have enough to buy a another room.");
		return;
	}

	if (ch->pcdata->questpoints < 200)
	{
		chprintln (ch, "{wYou need 200 questpoints to buy another room.");
		return;
	}

	if (count_home (ch) == MAX_HOUSE_ROOMS)
	{
		chprintln (ch, "{wYou have the max allowable rooms in your house.");
		return;
	}

	if (!is_home_owner (ch, ch->in_room))
	{
		chprintln (ch, "You must add only to your home!");
		return;
	}

	if ((door = get_direction (argument)) == -1 || door > 3)
	{
		chprintln (ch, "Which direction from here do you want the new room?");
		return;
	}

	if (ch->in_room->exit[door])
	{
		chprintln (ch, "A room already exits in that location.");
		return;
	}

	for (i = pArea->min_vnum; i < pArea->max_vnum; i++)
	{
		if ((get_room_index (i)) == NULL)
		{
			// do the room
			pRoom = new_room_index ();
			pRoom->area = pArea;
			pRoom->vnum = i;
			pRoom->sector_type = SECT_INSIDE;
			sprintf (buf, "%s\'s %d Room", capitalize (ch->name),
					 count_home (ch) + 1);
			replace_string (pRoom->name, buf);
			replace_string (pRoom->description,
							"This is your desc. You can edit this with HOME DESCRIBE.\n\r");
			replace_string (pRoom->owner, ch->name);
			SET_BIT (pRoom->room_flags, ROOM_INDOORS);
			iHash = i % MAX_KEY_HASH;
			pRoom->next = room_index_hash[iHash];
			room_index_hash[iHash] = pRoom;
			// do the exit
			ch->in_room->exit[door] = new_exit ();
			ch->in_room->exit[door]->u1.to_room = pRoom;
			ch->in_room->exit[door]->orig_door = door;
			rev = rev_dir[door];
			pExit = new_exit ();
			pExit->u1.to_room = ch->in_room;
			pExit->orig_door = rev;
			pRoom->exit[rev] = pExit;
			break;
		}
	}

	if (!pRoom)
	{
		chprintln (ch,
				   "A new room could not be created for you. please contact an immortal.");
		return;
	}

	ch->pcdata->home[count_home (ch)] = pRoom->vnum;

	ch->gold -= ROOM_PRICE;
	ch->pcdata->questpoints -= 200;

	chprintln
		(ch,
		 "The mayors hired contractors come and do additions to your home.");
	chprintlnf (ch, "Your home now contains %d rooms.", count_home (ch));
	save_char_obj (ch);
	save_area (pArea);
	return;
}

CH_CMD (home_sell)
{
	ROOM_INDEX_DATA *pRoom = NULL;
	int home, i = 0, rooms = 0;
	long cost = 0;
	int quest = 0;
	int tp = 0;
	char buf[MSL];

	if (!ch || IS_NPC (ch))
		return;

	if ((rooms = count_home (ch)) == 0)
	{
		chprintln (ch, "You don't have a home yet.");
		return;
	}

	if (IS_NULLSTR (argument))
	{
		chprintln (ch,
				   "This command allows you to sell your home.  The Mayors");
		chprintln (ch,
				   "contractors  will completly demolish your home when it is sold,");
		chprintln (ch,
				   "and you will be compensated half the cost of the home,");
		chprintln (ch, "including any items you have purchased.");
		chprintln (ch,
				   "{ROnce your home is sold, it cannot be brought back!!!{x");
		chprintln (ch, "\n\rSyntax: Home (sell) (confirm)");
		return;
	}
	else if (!str_cmp (argument, "confirm"))
	{
		sprintf (buf, "%ld", ch->pcdata->home_key);
		oedit_delete (NULL, buf);
		for (home = 0; home < MAX_HOUSE_ROOMS; home++)
		{
			if ((pRoom = get_room_index (ch->pcdata->home[home])) != NULL)
			{
				SET_BIT (pRoom->area->area_flags, AREA_CHANGED);
				i += tally_resets (pRoom, cost, tp, quest);
				sprintf (buf, "%ld", ch->pcdata->home[home]);
				if (redit_delete (NULL, buf))
					cost += ROOM_PRICE / 3;
			}
		}
		ch->gold += cost;
		ch->pcdata->trivia += tp;
		ch->pcdata->questpoints += quest;
		chprintlnf
			(ch,
			 "Your home {R(%d rooms) {G(%d furnishings){x has been sold and you are now {Y%ld{x gold coins richer!",
			 rooms, i, cost);
		reset_homes (ch);
		save_char_obj (ch);
		return;
	}
	else
	{
		home_sell (ch, str_empty);
		return;
	}
}

CH_CMD (home_describe)
{
	ROOM_INDEX_DATA *loc;
	char buf[MSL];
	int len;
	bool found = FALSE;

	loc = ch->in_room;

	if (!ch || IS_NPC (ch))
		return;

	if (count_home (ch) == 0)
	{
		chprintln (ch, "You have to BUY a home before you can describe it.");
		return;
	}
	if (!is_home_owner (ch, loc))
	{
		chprintln (ch, "But you do not own this room!");
		return;
	}
	if (IS_NULLSTR (argument))
	{
		chprintln (ch, "This command allows you to describe your home.");
		chprintln (ch, "You should not describe items that are in the room,");
		chprintln (ch,
				   "rather allowing the furnishing of the home to do that.");
		chprintln (ch,
				   "If you currently own this room, you will be placed into.");
		chprintln (ch,
				   "the room editor. Be warned that while in the room editor,");
		chprintln (ch,
				   "you are only allowed to type the description. If you are");
		chprintln (ch,
				   "unsure or hesitant about this, please note the Immortals,");
		chprintln (ch, "or better, discuss the how-to's with a Builder.");
		chprintln (ch,
				   "If Using the string editor bothers you type /q on a new line\n\r"
				   "and use the syntax: Home describe +/- <string>{x");
		string_append (ch, &loc->description);
		SET_BIT (loc->area->area_flags, AREA_CHANGED);
		return;
	}
	else
	{
		buf[0] = '\0';

		if (argument[0] == '-')
		{
			if (IS_NULLSTR (loc->description))
			{
				chprintln (ch, "No lines left to remove.");
				return;
			}

			strcpy (buf, loc->description);

			for (len = strlen (buf); len > 0; len--)
			{
				if (buf[len] == '\r')
				{
					if (!found)
					{

						if (len > 0)
							len--;
						found = TRUE;
					}
					else
					{

						buf[len + 1] = '\0';
						replace_string (loc->description, buf);
						chprintln (ch, "OK.");
						return;
					}
				}
			}
			buf[0] = '\0';
			replace_string (loc->description, buf);
			chprintln (ch, "Description cleared.");
			return;
		}
		if (argument[0] == '+')
		{
			if (loc->description != NULL)
				strcat (buf, loc->description);
			argument++;
			while (isspace (*argument))
				argument++;
		}

		if (strlen (buf) + strlen (argument) >= MSL - 2)
		{
			chprintln (ch, "Description too long.");
			return;
		}

		strcat (buf, argument);
		strcat (buf, "\n\r");
		replace_string (loc->description, buf);
		save_area (loc->area);
	}
	return;
}

CH_CMD (home_name)
{
	ROOM_INDEX_DATA *loc;

	loc = ch->in_room;

	if (!ch || IS_NPC (ch))
		return;

	if (count_home (ch) == 0)
	{
		chprintln (ch, "You have to BUY a home before you can rename it.");
		return;
	}
	if (!is_home_owner (ch, loc))
	{
		chprintln (ch, "But you do not own this room!");
		return;
	}

	if (IS_NULLSTR (argument))
	{
		chprintln (ch, "Change the this room title to what?");
		return;
	}

	if (strlen_color (argument) > 25)
	{
		chprintln (ch, "This is the name, not the description.");
		return;
	}

	replace_string (loc->name, argument);
	save_area (loc->area);
	return;
}

CH_CMD (home_furnish)
{
	RESET_DATA *loc_reset, *pReset;
	OBJ_DATA *furn = NULL;
	OBJ_INDEX_DATA *pObj = NULL;
	CHAR_DATA *moby = NULL;
	MOB_INDEX_DATA *pMob = NULL;
	int i;

	if (!ch || IS_NPC (ch))
		return;

	if (count_home (ch) == 0)
	{
		chprintln (ch, "You have to BUY a home before you can furnish it.");
		return;
	}

	if (!is_home_owner (ch, ch->in_room))
	{
		chprintln (ch, "But you do not own this room!");
		return;
	}

	if (IS_NULLSTR (argument) || !str_cmp (argument, "list"))
	{
		chprintln (ch, "This command allows you to furnish your home.");
		chprintln (ch,
				   "You must be standing in your home. You cannot have more");
		chprintln (ch, "than five items and five mobiles in your home.");
		chprintln (ch,
				   "Other things like heal/mana rate have a limit instead.");
		chprintln (ch, "Syntax: Home (furnish) (option)\n\r");
		for (i = 0; home_table[i].name != NULL; i++)
		{
			chprintlnf (ch, "\t%-15s - %ld gold, %dqp, %dtp",
						home_table[i].list, home_table[i].cost,
						home_table[i].quest, home_table[i].tp);
		}
		return;
	}
	else
	{

		for (i = 0; home_table[i].name != NULL; i++)
		{
			if (is_name (argument, home_table[i].name))
			{

				if (ch->gold < home_table[i].cost)
				{
					chprintlnf
						(ch, "You don't have enough gold for to buy a %s.",
						 home_table[i].name);
					return;
				}
				if (ch->pcdata->questpoints < home_table[i].quest)
				{
					chprintlnf (ch, "You need %d questpoints to buy a %s.",
								home_table[i].quest, home_table[i].name);
					return;
				}
				if (ch->pcdata->trivia < home_table[i].tp)
				{
					chprintlnf (ch, "You need %d trivia points to buy a %s.",
								home_table[i].quest, home_table[i].name);
					return;
				}
				if (home_table[i].type == H_NONE)
				{
					if (!str_cmp (home_table[i].name, "healrate"))
					{
						if (ch->in_room->heal_rate >= 200)
						{
							chprintln
								(ch,
								 "This rooms heal rate can't go any higher.");
							return;
						}
						ch->in_room->heal_rate =
							UMIN (ch->in_room->heal_rate + 50, 200);
					}
					if (!str_cmp (home_table[i].name, "manarate"))
					{
						if (ch->in_room->mana_rate >= 200)
						{
							chprintln
								(ch,
								 "This rooms mana rate can't go any higher.");
							return;
						}
						ch->in_room->mana_rate =
							UMIN (ch->in_room->mana_rate + 50, 200);
					}
				}
				else if (home_table[i].type == H_OBJ)
				{

					for (pReset = ch->in_room->reset_first; pReset != NULL;
						 pReset = pReset->next)
					{
						if (pReset->command == 'O'
							&& pReset->arg1 == home_table[i].vnum)
						{
							chprintln
								(ch,
								 "You already have one of those in this room.");
							return;
						}
					}
					if ((pObj = get_obj_index (home_table[i].vnum)) != NULL)
					{
						furn = create_object (pObj, pObj->level);
						loc_reset = new_reset_data ();
						loc_reset->command = 'O';
						loc_reset->arg1 = pObj->vnum;
						loc_reset->arg2 = 0;
						loc_reset->arg3 = ch->in_room->vnum;
						loc_reset->arg4 = 0;
						add_reset (ch->in_room, loc_reset, 0);
						obj_to_room (furn, ch->in_room);
					}
					else
						chprintln
							(ch,
							 "Cannot find that object, please contact an immortal.");
				}
				else if (home_table[i].type == H_MOB)
				{
					for (pReset = ch->in_room->reset_first; pReset != NULL;
						 pReset = pReset->next)
					{
						if (pReset->command == 'M'
							&& pReset->arg1 == home_table[i].vnum)
						{
							chprintln
								(ch,
								 "You already have one of those in this room.");
							return;
						}
					}

					if ((pMob = get_mob_index (home_table[i].vnum)) != NULL)
					{
						moby = create_mobile (pMob);
						loc_reset = new_reset_data ();
						loc_reset->command = 'M';
						loc_reset->arg1 = pMob->vnum;
						loc_reset->arg2 =
							ch->in_room->area->max_vnum -
							ch->in_room->area->min_vnum;
						loc_reset->arg3 = ch->in_room->vnum;
						loc_reset->arg4 = 1;
						add_reset (ch->in_room, loc_reset, 0);
						char_to_room (moby, ch->in_room);
					}
					else
						chprintln
							(ch,
							 "Cannot find that mobile, please contact an immortal.");
				}
				else
				{
					chprintln
						(ch,
						 "Unable to complete your request.  Please inform an Immortal.");
					return;
				}

				ch->gold -= home_table[i].cost;

				ch->pcdata->questpoints -= home_table[i].quest;
				ch->pcdata->trivia -= home_table[i].tp;

				chprintlnf
					(ch,
					 "You have been deducted %ld gold, %dqp and %dtp for your purchase.",
					 home_table[i].cost, home_table[i].quest,
					 home_table[i].tp);
				save_area (ch->in_room->area);
				return;
			}
		}
	}
}

CH_CMD (home_unfurnish)
{
	RESET_DATA *pReset = NULL;
	OBJ_DATA *obj, *obj_next;
	CHAR_DATA *mob, *mob_next;
	int i = 0;
	bool found = FALSE;

	if (!ch || IS_NPC (ch))
		return;

	if (count_home (ch) == 0)
	{
		chprintln (ch, "You have to BUY a home before you can furnish it.");
		return;
	}

	if (!ch->in_room || !is_home_owner (ch, ch->in_room))
	{
		chprintln (ch, "But you do not own this room!");
		return;
	}

	if (IS_NULLSTR (argument))
	{
		chprintln (ch, "Unfurnish which object?.");
		return;
	}
	else
	{
		for (i = 0; home_table[i].name != NULL; i++)
		{
			if (home_table[i].type == H_NONE || home_table[i].vnum <= 0)
				continue;

			if (is_name (argument, home_table[i].name))
			{
				for (pReset = ch->in_room->reset_first; pReset;
					 pReset = pReset->next)
				{
					if (pReset->command ==
						(home_table[i].type == H_OBJ ? 'O' : 'M')
						&& pReset->arg1 == home_table[i].vnum)
					{
						unlink_reset (ch->in_room, pReset);
						free_reset_data (pReset);
						ch->gold += home_table[i].cost / 3;
						ch->pcdata->questpoints += home_table[i].quest / 3;
						ch->pcdata->trivia += home_table[i].tp / 3;
						save_area (ch->in_room->area);
						found = TRUE;
						if (home_table[i].type == H_OBJ)
						{
							for (obj = ch->in_room->contents; obj != NULL;
								 obj = obj_next)
							{
								obj_next = obj->next_content;

								if (obj->pIndexData->vnum ==
									home_table[i].vnum)
									extract_obj (obj);
							}
						}
						else if (home_table[i].type == H_MOB)
						{
							for (mob = ch->in_room->people; mob != NULL;
								 mob = mob_next)
							{
								mob_next = mob->next_in_room;

								if (IS_NPC (mob)
									&& mob->pIndexData->vnum ==
									home_table[i].vnum)
									extract_char (mob, TRUE);
							}
						}
						chprintlnf
							(ch,
							 "You sell %s back to the mayor for %ld gold, %dqp and %dtp.",
							 home_table[i].list, home_table[i].cost / 3,
							 home_table[i].quest / 3, home_table[i].tp / 3);
					}
				}
			}
		}
		if (!found)
			chprintln (ch, "Unable to find your request.");
		return;
	}
}

CH_CMD (do_gohome)
{
	CHAR_DATA *victim;
	ROOM_INDEX_DATA *location = NULL;
	int i;

	if (!ch)
		return;

	if (IS_NPC (ch))
	{
		chprintln (ch, "Only players can go home.");
		return;
	}

	if (IS_SET (ch->in_room->room_flags, ROOM_ARENA))
	{
		chprintln (ch, "You can't recall while in the arena!");
		return;
	}

	act ("$n prays for $s mother to take $m home!", ch, 0, 0, TO_ROOM);

	for (i = 0; i < MAX_HOUSE_ROOMS; i++)
		if (ch->pcdata->home[i] > 0
			&& (location = get_room_index (ch->pcdata->home[i])) != NULL)
			break;

	if (location == NULL)
	{
		chprintln (ch, "You don't have a home *pout*.");
		return;
	}

	if (ch->in_room == location)
		return;

	if ((victim = ch->fighting) != NULL)
	{
		chprintln (ch, "You run home from combat!");
		stop_fighting (ch, TRUE);
	}

	ch->move -= ch->move / 5;
	act ("$n disappears.", ch, NULL, NULL, TO_ROOM);
	char_from_room (ch);
	char_to_room (ch, location);
	act ("$n appears in $s home.", ch, NULL, NULL, TO_ROOM);
	do_function (ch, &do_look, "auto");

	if (ch->pet != NULL)
	{
		act ("$n disappears.", ch, NULL, NULL, TO_ROOM);
		char_from_room (ch->pet);
		char_to_room (ch->pet, location);
		act ("$n appears in the room.", ch, NULL, NULL, TO_ROOM);
	}

	return;
}

CH_CMD (home_evict)
{
	CHAR_DATA *victim;

	if (count_home (ch) == 0)
	{
		chprintln (ch, "You don't have a home to kick them out of.");
		return;
	}

	if (IS_NULLSTR (argument))
	{
		chprintln (ch, "Syntax: home evict <char>");
		return;
	}

	if ((victim = get_char_world (ch, argument)) == NULL)
	{
		chprintln (ch, "They aren't here.");
		return;
	}

	if (IS_NPC (victim))
	{
		chprintln (ch, "No such player.");
		return;
	}

	if (victim == ch)
	{
		chprintln (ch, "What would be the point of that?");
		return;
	}

	if (ch->fighting != NULL)
	{
		chprintln (ch, "Your a little busy right now.");
		return;
	}

	if (!is_home_owner (ch, victim->in_room))
	{
		chprintln (ch, "They aren't in your home.");
		return;
	}

	if (victim->fighting != NULL)
		stop_fighting (victim, TRUE);

	char_from_room (victim);
	char_to_room (victim, get_room_index (ROOM_VNUM_TEMPLE));
	act ("$n has someone escort you out of $s home.", ch, NULL, victim,
		 TO_VICT);
	do_function (victim, &do_look, "auto");
	act ("You are no longer welcome in $n's home.", ch, NULL, victim,
		 TO_VICT);
	act ("$N is no longer welcome in your home.", ch, NULL, victim, TO_CHAR);
	return;
}

CH_CMD (home_link)
{
	int door;
	AREA_DATA *pArea;
	ROOM_INDEX_DATA *pRoom, *toRoom = NULL;
	char arg[MIL];
	vnum_t vnum;

	if (count_home (ch) == 0)
	{
		chprintln (ch, "Use HOME BUY to purchase a home first.");
		return;
	}

	if (ch->gold < ROOM_PRICE)
	{
		chprintln (ch, "{wYou don't have enough to buy a another room.");
		return;
	}

	if (ch->pcdata->questpoints < 125)
	{
		chprintln (ch,
				   "It costs 125 quest points to add a link to this room.");
		return;
	}

	if (!is_home_owner (ch, ch->in_room))
	{
		chprintln (ch, "You must add only to your home!");
		return;
	}

	argument = one_argument (argument, arg);

	if ((door = get_direction (arg)) == -1 || door > 5)
	{
		chprintln (ch, "Which direction from here do you want the new exit?");
		return;
	}

	pRoom = ch->in_room;

	if (pRoom->exit[door])
	{
		chprintln (ch, "An exit already exits in that location.");
		return;
	}

	if (IS_NULLSTR (argument))
	{
		chprintln (ch, "Invalid area to link to.");
		return;
	}

	for (pArea = area_first; pArea != NULL; pArea = pArea->next)
	{
		if (!str_prefix (argument, pArea->name))
			break;
	}

	if (pArea == NULL)
	{
		chprintln (ch, "Invalid area to link to.");
		return;
	}

	for (vnum = pArea->min_vnum; vnum < pArea->max_vnum; vnum++)
	{
		if ((toRoom = get_room_index (vnum)) != NULL)
			break;
	}

	if (toRoom == NULL)
	{
		chprintln (ch, "Unable to link to that area.");
		return;
	}

	pRoom->exit[door] = new_exit ();

	pRoom->exit[door]->u1.to_room = toRoom;

	pRoom->exit[door]->orig_door = door;

	SET_BIT (pRoom->area->area_flags, AREA_CHANGED);
	ch->gold -= ROOM_PRICE;
	ch->pcdata->questpoints -= 125;
	chprintlnf (ch, "Exit to %s added.", pArea->name);
}

CH_CMD (home_unlink)
{
	char arg[MIL];

	ROOM_INDEX_DATA *pRoom, *pToRoom;
	int rev, door;

	if (count_home (ch) == 0)
	{
		chprintln (ch, "You don't own a home.");
		return;
	}

	if (!is_home_owner (ch, ch->in_room))
	{
		chprintln (ch, "You don't own this room!");
		return;
	}

	argument = one_argument (argument, arg);

	if ((door = get_direction (arg)) == -1 || door > 5)
	{
		chprintln (ch,
				   "Which direction from here do you want to delete the exit?");
		return;
	}

	pRoom = ch->in_room;

	if (!pRoom->exit[door])
	{
		chprintln (ch, "There is no exit in that direction.");
		return;
	}

	rev = rev_dir[door];
	pToRoom = pRoom->exit[door]->u1.to_room;

	if (pToRoom->area == pRoom->area)
	{
		chprintln (ch, "You can't unlink that exit.");
		return;
	}
	free_exit (pRoom->exit[door]);
	pRoom->exit[door] = NULL;

	ch->gold += ROOM_PRICE / 3;
	ch->pcdata->questpoints += 125 / 3;
	SET_BIT (pRoom->area->area_flags, AREA_CHANGED);
	chprintln (ch, "Exit unlinked.");
	return;
}

CH_CMD (home_invite)
{
	CHAR_DATA *vch;

	if (IS_NULLSTR (argument))
	{
		chprintln (ch, "Syntax: home invite <person>");
		return;
	}

	if ((vch = get_char_world (ch, argument)) == NULL)
	{
		chprintln (ch, "They aren't online.");
		return;
	}

	if (IS_NPC (vch))
	{
		chprintln (ch, "You can't invite them.");
		return;
	}

	if (vch == ch)
	{
		chprintln (ch, "You can't invite yourself.");
		return;
	}
	if (vch->pcdata->home_invite != 0)
	{
		chprintln (ch, "They have already been invited somewhere.");
		return;
	}
	if (vch->fighting != NULL)
	{
		chprintln (ch, "They're a little busy right now.");
		return;
	}

	vch->pcdata->home_invite = ch->id;

	act
		("$n has invited you to $s home. Type HOME ACCEPT to accept the invitation\n\r"
		 "and be transfered to $s home, or type HOME DENY to cancel the invitation.",
		 ch, NULL, vch, TO_VICT);

	act ("Invitation sent to $N.", ch, NULL, vch, TO_CHAR);
}

CH_CMD (home_accept)
{
	CHAR_DATA *owner;
	ROOM_INDEX_DATA *pRoom;
	int i;

	if (ch->pcdata->home_invite == 0)
	{
		chprintln (ch, "You haven't been invited anywhere.");
		return;
	}

	if (ch->fighting != NULL || IS_IN_WAR (ch))
	{
		chprintln (ch, "You're a little busy right now.");
		return;
	}

	if ((owner = get_char_id (ch->pcdata->home_invite)) == NULL)
	{
		chprintln (ch,
				   "Hmm, seems the person who invited you isn't around anymore.");
		return;
	}

	pRoom = NULL;

	for (i = 0; i < MAX_HOUSE_ROOMS; i++)
		if ((pRoom = get_room_index (owner->pcdata->home[i])) != NULL)
			break;

	if (!pRoom)
	{
		chprintln (ch, "BUG: inviter doens't own a home!");
		return;
	}

	char_from_room (ch);
	char_to_room (ch, pRoom);
	act ("$n arrives.", ch, NULL, NULL, TO_ROOM);
	do_function (ch, &do_look, "auto");
	ch->pcdata->home_invite = 0;
	return;
}

CH_CMD (home_deny)
{
	CHAR_DATA *owner;

	if (ch->pcdata->home_invite == 0)
	{
		chprintln (ch, "You haven't been invited anywhere.");
		return;
	}

	owner = get_char_id (ch->pcdata->home_invite);

	if (owner)
	{
		act ("You turn down $N's invitation.", ch, NULL, owner, TO_CHAR);
		act ("$n turns down your invitation.", ch, NULL, owner, TO_VICT);
	}
	else
		chprintln (ch, "You turn down the invitation.");

	ch->pcdata->home_invite = 0;
}

void delete_home (CHAR_DATA * ch)
{
	int i;
	char buf[MSL];

	if (count_home (ch) > 0)
	{
		ROOM_INDEX_DATA *pRoom;
		AREA_DATA *pArea = NULL;

		for (i = 0; i < MAX_HOUSE_ROOMS; i++)
		{
			if ((pRoom = get_room_index (ch->pcdata->home[i])) != NULL)
			{
				pArea = pRoom->area;
				sprintf (buf, "%ld", ch->pcdata->home[i]);
				redit_delete (NULL, buf);
			}
		}
		sprintf (buf, "%ld", ch->pcdata->home_key);
		oedit_delete (NULL, buf);
		if (pArea)
			save_area (pArea);
	}
}