1stMUD/corefiles/
1stMUD/gods/
1stMUD/notes/
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, NULL, 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;
			LINK_SINGLE(pObj, next, obj_index_hash[iHash]);
			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;
			LINK_SINGLE(pRoom, next, room_index_hash[iHash]);
			// 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;
			LINK_SINGLE(pRoom, next, room_index_hash[iHash]);
			// 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->first_content; 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->first_person; 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 doesn'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);
	}
}