empiremud/cnf/
empiremud/doc/
empiremud/lib/boards/
empiremud/lib/etc/
empiremud/lib/misc/
empiremud/lib/plralias/F-J/
empiremud/lib/plralias/K-O/
empiremud/lib/plralias/P-T/
empiremud/lib/plralias/U-Z/
empiremud/lib/plrobjs/
empiremud/lib/plrobjs/F-J/
empiremud/lib/plrobjs/K-O/
empiremud/lib/plrobjs/P-T/
empiremud/lib/plrobjs/U-Z/
empiremud/lib/world/
empiremud/lib/world/mob/
empiremud/lib/world/obj/
empiremud/log/
/* ************************************************************************
*   File: act.item.c                                     EmpireMUD AD 1.0 *
*  Usage: object handling routines -- get/drop and container handling     *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Code base by Paul Clarke.  EmpireMUD Project, a tbgMUD Production.     *
*  Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson.        *
*                                                                         *
*  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 "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "skills.h"
#include "empire.h"
#include "vnums.h"


/* extern variables */
extern const char *drinks[];
extern const int room_capacity[];
extern const int building_capacity[];
extern const int closed_monument_capacity[];
extern int drink_aff[][3];

/* extern functions */
void gain_condition(Creature ch, int condition, int value);
void perform_remove(Creature ch, int pos, bool swap);


int perform_put(Creature ch, Object obj, Object cont) {
	if (GET_OBJ_WEIGHT(cont) + GET_OBJ_WEIGHT(obj) > GET_OBJ_VAL(cont, 0)) {
		act("$p won't fit in $P.", FALSE, ch, obj, cont, TO_CHAR);
		return 0;
		}
	else if (IS_OBJ_STAT(obj, ITEM_LARGE) && !IS_OBJ_STAT(cont, ITEM_LARGE))
		act("$p is far too large to fit in $P.", FALSE, ch, obj, cont, TO_CHAR);
	else {
		obj_to_obj(obj, cont);

		act("$n puts $p in $P.", TRUE, ch, obj, cont, TO_ROOM);

		act("You put $p in $P.", FALSE, ch, obj, cont, TO_CHAR);
		}
	return 1;
	}


/* The following put modes are supported by the code below:
	1) put <object> <container>
	2) put all.<object> <container>
	3) put all <container>

	<container> must be in inventory or on ground.
	all objects to be put into container must be in inventory.
*/

ACMD(do_put) {
	char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH], arg3[MAX_INPUT_LENGTH];
	Object obj, next_obj, cont;
	Creature tmp_char;
	int obj_dotmode, cont_dotmode, found = 0, howmany = 1;
	char *theobj, *thecont;

	argument = two_arguments(argument, arg1, arg2);
	one_argument(argument, arg3);

	if (*arg3 && is_number(arg1)) {
		howmany = atoi(arg1);
		theobj = arg2;
		thecont = arg3;
		}
	else {
		theobj = arg1;
		thecont = arg2;
		}
	obj_dotmode = find_all_dots(theobj);
	cont_dotmode = find_all_dots(thecont);

	if (!*theobj)
		send_to_char("Put what in what?\r\n", ch);
	else if (cont_dotmode != FIND_INDIV)
		send_to_char("You can only put things into one container at a time.\r\n", ch);
	else if (!*thecont) {
		sprintf(buf, "What do you want to put %s in?\r\n", ((obj_dotmode == FIND_INDIV) ? "it" : "them"));
		send_to_char(buf, ch);
		}
	else {
		generic_find(thecont, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &tmp_char, &cont);
		if (!cont) {
			sprintf(buf, "You don't see %s %s here.\r\n", AN(thecont), thecont);
			send_to_char(buf, ch);
			}
		else if (GET_OBJ_TYPE(cont) != ITEM_CONTAINER && GET_OBJ_TYPE(cont) != ITEM_CART)
			act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
		else if (OBJVAL_FLAGGED(cont, CONT_CLOSED) && GET_OBJ_TYPE(cont) == ITEM_CONTAINER)
			send_to_char("You'd better open it first!\r\n", ch);
		else {
			if (obj_dotmode == FIND_INDIV) {	/* put <obj> <container> */
				if (!(obj = get_obj_in_list_vis(ch, theobj, ch->carrying))) {
					sprintf(buf, "You aren't carrying %s %s.\r\n", AN(theobj), theobj);
					send_to_char(buf, ch);
					}
				else if (obj == cont)
					send_to_char("You attempt to fold it into itself, but fail.\r\n", ch);
				else {
					Object next_obj;
					while(obj && howmany--) {
						next_obj = obj->next_content;
						if (!perform_put(ch, obj, cont))
							break;
						obj = get_obj_in_list_vis(ch, theobj, next_obj);
						}
					}
				}
			else {
				for (obj = ch->carrying; obj; obj = next_obj) {
					next_obj = obj->next_content;
					if (obj != cont && CAN_SEE_OBJ(ch, obj) && (obj_dotmode == FIND_ALL || isname(theobj, obj->name))) {
						found = 1;
						if (!perform_put(ch, obj, cont))
							break;
						}
					}
				if (!found) {
					if (obj_dotmode == FIND_ALL)
						send_to_char("You don't seem to have anything to put in it.\r\n", ch);
					else {
						sprintf(buf, "You don't seem to have any %ss.\r\n", theobj);
						send_to_char(buf, ch);
						}
					}
				}
			}
		}
	}


int can_take_obj(Creature ch, Object obj) {
	if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) {
		act("$p: you can't carry that many items.", FALSE, ch, obj, 0, TO_CHAR);
		return (0);
		}
	else if (!(CAN_WEAR(obj, ITEM_WEAR_TAKE))) {
		act("$p: you can't take that!", FALSE, ch, obj, 0, TO_CHAR);
		return (0);
		}
	else if ((IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(ch)) {
		act("$p: you can't carry that much weight.", FALSE, ch, obj, 0, TO_CHAR);
		return (0);
		}
	return (1);
	}


int perform_get_from_container(Creature ch, Object obj, Object cont, int mode) {
	if (mode == FIND_OBJ_INV || can_take_obj(ch, obj)) {
		if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) {
			act("$p: you can't hold any more items.", FALSE, ch, obj, 0, TO_CHAR);
			return 0;
			}
		else {
			obj_to_char(obj, ch);
			act("You get $p from $P.", FALSE, ch, obj, cont, TO_CHAR);
			act("$n gets $p from $P.", TRUE, ch, obj, cont, TO_ROOM);
			return 1;
			}
		}
	return 0;
	}


void get_from_container(Creature ch, Object cont, char *arg, int mode, int howmany) {
	Object obj, next_obj;
	int obj_dotmode, found = 0;

	obj_dotmode = find_all_dots(arg);

	if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER && OBJVAL_FLAGGED(cont, CONT_CLOSED))
		act("$p is closed.", FALSE, ch, cont, 0, TO_CHAR);
	else if (obj_dotmode == FIND_INDIV) {
		if (!(obj = get_obj_in_list_vis(ch, arg, cont->contains))) {
			sprintf(buf, "There doesn't seem to be %s %s in $p.", AN(arg), arg);
			act(buf, FALSE, ch, cont, 0, TO_CHAR);
			}
		else {
			Object obj_next;
			while(obj && howmany--) {
				obj_next = obj->next_content;
				if (!perform_get_from_container(ch, obj, cont, mode))
					break;
				obj = get_obj_in_list_vis(ch, arg, obj_next);
				}
			}
		}
	else {
		if (obj_dotmode == FIND_ALLDOT && !*arg) {
			send_to_char("Get all of what?\r\n", ch);
			return;
			}
		for (obj = cont->contains; obj; obj = next_obj) {
			next_obj = obj->next_content;
			if (CAN_SEE_OBJ(ch, obj) && (obj_dotmode == FIND_ALL || isname(arg, obj->name))) {
				found = 1;
				if (!perform_get_from_container(ch, obj, cont, mode))
					break;
				}
			}
		if (!found) {
			if (obj_dotmode == FIND_ALL)
				act("$p seems to be empty.", FALSE, ch, cont, 0, TO_CHAR);
			else {
				sprintf(buf, "You can't seem to find any %ss in $p.", arg);
				act(buf, FALSE, ch, cont, 0, TO_CHAR);
				}
			}
		}
	}


int perform_get_from_room(Creature ch, Object obj) {
	if (!CAN_USE_ROOM(ch, ch->in_room, 0))
		if (IS_NPC(ch) || ww_dice(GET_DEXTERITY(ch) + GET_LARCENY(ch), 8) < 2) {
			if (real_empire(world[HOME_ROOM(ch->in_room)].owner) != -1)
				log_to_empire(real_empire(world[HOME_ROOM(ch->in_room)].owner), "Theft attempt at (%d, %d)", X_COORD(ch->in_room), Y_COORD(ch->in_room));
			msg_to_char(ch, "You can't seem to steal items from here!\r\n");
			return 0;
			}
	if (can_take_obj(ch, obj)) {
		obj_to_char(obj, ch);
		act("You get $p.", FALSE, ch, obj, 0, TO_CHAR);
		act("$n gets $p.", TRUE, ch, obj, 0, TO_ROOM);
		return (1);
		}
	return (0);
	}


void get_from_room(Creature ch, char *arg, int howmany) {
	Object obj, next_obj;
	int dotmode, found = 0;

	dotmode = find_all_dots(arg);

	if (dotmode == FIND_INDIV) {
		if (!(obj = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents))) {
			sprintf(buf, "You don't see %s %s here.\r\n", AN(arg), arg);
			send_to_char(buf, ch);
			}
		else {
			Object obj_next;
			while(obj && howmany--) {
				obj_next = obj->next_content;
				if (!perform_get_from_room(ch, obj))
					break;
				obj = get_obj_in_list_vis(ch, arg, obj_next);
				}
			}
		}
	else {
		if (dotmode == FIND_ALLDOT && !*arg) {
			send_to_char("Get all of what?\r\n", ch);
			return;
			}
		for (obj = world[ch->in_room].contents; obj; obj = next_obj) {
			next_obj = obj->next_content;
			if (CAN_SEE_OBJ(ch, obj) && (dotmode == FIND_ALL || isname(arg, obj->name))) {
				found = 1;
				if (!perform_get_from_room(ch, obj))
					break;
				}
			}
		if (!found) {
			if (dotmode == FIND_ALL)
				send_to_char("There doesn't seem to be anything here.\r\n", ch);
			else {
				sprintf(buf, "You don't see any %ss here.\r\n", arg);
				send_to_char(buf, ch);
				}
			}
		}
	}


ACMD(do_get) {
	char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH], arg3[MAX_INPUT_LENGTH];
	int cont_dotmode, found = 0, mode;
	Object cont;
	Creature tmp_char;

	argument = two_arguments(argument, arg1, arg2);
	one_argument(argument, arg3);

	if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch))
		send_to_char("Your arms are already full!\r\n", ch);
	else if (!*arg1)
		send_to_char("Get what?\r\n", ch);
	else if (!*arg2)
		get_from_room(ch, arg1, 1);
	else if (is_number(arg1) && !*arg3)
		get_from_room(ch, arg2, atoi(arg1));
	else {
		int amount = 1;
		if (is_number(arg1)) {
			amount = atoi(arg1);
			strcpy(arg1, arg2);
			strcpy(arg2, arg3);
			}
		cont_dotmode = find_all_dots(arg2);
		if (cont_dotmode == FIND_INDIV) {
			mode = generic_find(arg2, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &tmp_char, &cont);
			if (!cont) {
				sprintf(buf, "You don't have %s %s.\r\n", AN(arg2), arg2);
				send_to_char(buf, ch);
				}
			else if (GET_OBJ_TYPE(cont) != ITEM_CONTAINER && GET_OBJ_TYPE(cont) != ITEM_CART && !IS_CORPSE(cont))
				act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
			else
				get_from_container(ch, cont, arg1, mode, amount);
			}
		else {
			if (cont_dotmode == FIND_ALLDOT && !*arg2) {
				send_to_char("Get from all of what?\r\n", ch);
				return;
				}
			for (cont = ch->carrying; cont; cont = cont->next_content)
				if (CAN_SEE_OBJ(ch, cont) && (cont_dotmode == FIND_ALL || isname(arg2, cont->name))) {
					if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER || GET_OBJ_TYPE(cont) == ITEM_CART || IS_CORPSE(cont)) {
						found = 1;
						get_from_container(ch, cont, arg1, FIND_OBJ_INV, amount);
						}
					else if (cont_dotmode == FIND_ALLDOT) {
						found = 1;
						act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
						}
					}
			for (cont = world[ch->in_room].contents; cont; cont = cont->next_content)
				if (CAN_SEE_OBJ(ch, cont) && (cont_dotmode == FIND_ALL || isname(arg2, cont->name))) {
					if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER || GET_OBJ_TYPE(cont) == ITEM_CART || IS_CORPSE(cont)) {
						get_from_container(ch, cont, arg1, FIND_OBJ_ROOM, amount);
						found = 1;
						}
					else if (cont_dotmode == FIND_ALLDOT) {
						act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
						found = 1;
						}
					}
			if (!found) {
				if (cont_dotmode == FIND_ALL)
					send_to_char("You can't seem to find any containers.\r\n", ch);
				else {
					sprintf(buf, "You can't seem to find any %ss here.\r\n", arg2);
					send_to_char(buf, ch);
					}
				}
			}
		}
	}


#define VANISH(mode) (mode == SCMD_JUNK ? "  It vanishes in a puff of smoke!" : "")

int perform_drop(Creature ch, Object obj, byte mode, const char *sname) {
	int value;

	sprintf(buf, "You %s $p.%s", sname, VANISH(mode));
	act(buf, FALSE, ch, obj, 0, TO_CHAR);
	sprintf(buf, "$n %ss $p.%s", sname, VANISH(mode));
	act(buf, TRUE, ch, obj, 0, TO_ROOM);

	switch (mode) {
		case SCMD_DROP:
			obj_to_room(obj, ch->in_room);
			return (0);
		case SCMD_JUNK:
			value = MAX(1, MIN(200, GET_OBJ_COST(obj) / 16));
			extract_obj(obj);
			return (value);
		default:
			log("SYSERR: Incorrect argument %d passed to perform_drop.", mode);
			break;
		}

	return (0);
	}


ACMD(do_drop) {
	Object obj, next_obj;
	byte mode = SCMD_DROP;
	int dotmode, amount = 0, multi;
	const char *sname;

	switch (subcmd) {
		case SCMD_JUNK:
			sname = "junk";
			mode = SCMD_JUNK;
			break;
		default:
			sname = "drop";
			break;
		}

	argument = one_argument(argument, arg);

	if (!*arg) {
		sprintf(buf, "What do you want to %s?\r\n", sname);
		send_to_char(buf, ch);
		return;
		}
	else if (is_number(arg)) {
		multi = atoi(arg);
		one_argument(argument, arg);
		if (multi <= 0)
			send_to_char("Yeah, that makes sense.\r\n", ch);
		else if (!*arg) {
			sprintf(buf, "What do you want to %s %d of?\r\n", sname, multi);
			send_to_char(buf, ch);
			}
		else if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
			sprintf(buf, "You don't seem to have any %ss.\r\n", arg);
			send_to_char(buf, ch);
			}
		else {
			do {
				next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
				if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_INSIDE && ROOM_WEIGHT(ch->in_room) >= room_capacity[(int) world[ch->in_room].type]) {
					msg_to_char(ch, "The room is full.\r\n");
					break;
					}
				if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_MONUMENT_CLOSED && ROOM_WEIGHT(ch->in_room) >= closed_monument_capacity[(int) world[ch->in_room].type]) {
					msg_to_char(ch, "The room is full.\r\n");
					break;
					}
				if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_BUILDING && ROOM_WEIGHT(ch->in_room) >= building_capacity[(int) world[ch->in_room].type]) {
					if (building_capacity[(int) world[ch->in_room].type] == 0)
						msg_to_char(ch, "You can't drop anything here.\r\n");
					else
						msg_to_char(ch, "The building is full.\r\n");
					break;
					}
				amount += perform_drop(ch, obj, mode, sname);
				obj = next_obj;
				} while (obj && --multi);
			}
		}
	else {
		dotmode = find_all_dots(arg);

		/* Can't junk all */
		if ((dotmode == FIND_ALL) && (subcmd == SCMD_JUNK)) {
			send_to_char("Go to the dump if you want to junk EVERYTHING!\r\n", ch);
			return;
			}
		if (dotmode == FIND_ALL) {
			if (!ch->carrying)
				send_to_char("You don't seem to be carrying anything.\r\n", ch);
			else
				for (obj = ch->carrying; obj; obj = next_obj) {
					next_obj = obj->next_content;
					if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_INSIDE && ROOM_WEIGHT(ch->in_room) >= room_capacity[(int) world[ch->in_room].type]) {
						msg_to_char(ch, "The room is full.\r\n");
						break;
						}
					if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_MONUMENT_CLOSED && ROOM_WEIGHT(ch->in_room) >= closed_monument_capacity[(int) world[ch->in_room].type]) {
						msg_to_char(ch, "The room is full.\r\n");
						break;
						}
					if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_BUILDING && ROOM_WEIGHT(ch->in_room) >= building_capacity[(int) world[ch->in_room].type]) {
						if (building_capacity[(int) world[ch->in_room].type] == 0)
							msg_to_char(ch, "You can't drop anything here.\r\n");
						else
							msg_to_char(ch, "The building is full.\r\n");
						break;
						}
					amount += perform_drop(ch, obj, mode, sname);
					}
			}
		else if (dotmode == FIND_ALLDOT) {
			if (!*arg) {
				sprintf(buf, "What do you want to %s all of?\r\n", sname);
				send_to_char(buf, ch);
				return;
				}
			if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
				sprintf(buf, "You don't seem to have any %ss.\r\n", arg);
				send_to_char(buf, ch);
				}
			while (obj) {
				next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
				if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_INSIDE && ROOM_WEIGHT(ch->in_room) >= room_capacity[(int) world[ch->in_room].type]) {
					msg_to_char(ch, "The room is full.\r\n");
					break;
					}
				if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_MONUMENT_CLOSED && ROOM_WEIGHT(ch->in_room) >= closed_monument_capacity[(int) world[ch->in_room].type]) {
					msg_to_char(ch, "The room is full.\r\n");
					break;
					}
				if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_BUILDING && ROOM_WEIGHT(ch->in_room) >= building_capacity[(int) world[ch->in_room].type]) {
					if (building_capacity[(int) world[ch->in_room].type] == 0)
						msg_to_char(ch, "You can't drop anything here.\r\n");
					else
						msg_to_char(ch, "The building is full.\r\n");
					break;
					}
				amount += perform_drop(ch, obj, mode, sname);
				obj = next_obj;
				}
			}
		else {
			if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
				sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
				send_to_char(buf, ch);
				}
			else if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_INSIDE && ROOM_WEIGHT(ch->in_room) >= room_capacity[(int) world[ch->in_room].type])
				msg_to_char(ch, "The room is full.\r\n");
			else if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_MONUMENT_CLOSED && ROOM_WEIGHT(ch->in_room) >= closed_monument_capacity[(int) world[ch->in_room].type])
				msg_to_char(ch, "The room is full.\r\n");
			else if (mode == SCMD_DROP && SECT(ch->in_room) == SECT_BUILDING && ROOM_WEIGHT(ch->in_room) >= building_capacity[(int) world[ch->in_room].type]) {
				if (building_capacity[(int) world[ch->in_room].type] == 0)
					msg_to_char(ch, "You can't drop anything here.\r\n");
				else
					msg_to_char(ch, "The building is full.\r\n");
				}
			else
				amount += perform_drop(ch, obj, mode, sname);
			}
		}
	}


void perform_give(Creature ch, Creature vict, Object obj) {
	if (IS_CARRYING_N(vict) >= CAN_CARRY_N(vict)) {
		act("$N seems to have $S hands full.", FALSE, ch, 0, vict, TO_CHAR);
		return;
		}
	if (GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(vict) > CAN_CARRY_W(vict)) {
		act("$E can't carry that much weight.", FALSE, ch, 0, vict, TO_CHAR);
		return;
		}
	obj_to_char(obj, vict);
	act("You give $p to $N.", FALSE, ch, obj, vict, TO_CHAR);
	act("$n gives you $p.", FALSE, ch, obj, vict, TO_VICT);
	act("$n gives $p to $N.", TRUE, ch, obj, vict, TO_NOTVICT);
	}

/* utility function for give */
Creature give_find_vict(Creature ch, char *arg) {
	Creature vict;

	if (!*arg)
		send_to_char("To who?\r\n", ch);
	else if (!(vict = get_char_vis(ch, arg, FIND_CHAR_ROOM)))
		send_to_char(NOPERSON, ch);
	else if (vict == ch)
		send_to_char("What's the point of that?\r\n", ch);
	else
		return (vict);
	return NULL;
	}


ACMD(do_give) {
	int amount, dotmode;
	Creature vict;
	Object obj, next_obj;

	argument = one_argument(argument, arg);

	if (!*arg)
		send_to_char("Give what to who?\r\n", ch);
	else if (is_number(arg)) {
		amount = atoi(arg);
		argument = one_argument(argument, arg);
		if (!*arg) {	/* Give multiple code. */
			sprintf(buf, "What do you want to give %d of?\r\n", amount);
			send_to_char(buf, ch);
			}
		else if (!(vict = give_find_vict(ch, argument))) {
			return;
			}
		else if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
			sprintf(buf, "You don't seem to have any %ss.\r\n", arg);
			send_to_char(buf, ch);
			}
		else {
			while (obj && amount--) {
				next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
				perform_give(ch, vict, obj);
				obj = next_obj;
				}
			}
		}
	else {
		one_argument(argument, buf1);
		if (!(vict = give_find_vict(ch, buf1)))
			return;
		dotmode = find_all_dots(arg);
		if (dotmode == FIND_INDIV) {
			if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
				sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
				send_to_char(buf, ch);
				}
			else
				perform_give(ch, vict, obj);
			}
		else {
			if (dotmode == FIND_ALLDOT && !*arg) {
				send_to_char("All of what?\r\n", ch);
				return;
				}
			if (!ch->carrying)
				send_to_char("You don't seem to be holding anything.\r\n", ch);
			else
				for (obj = ch->carrying; obj; obj = next_obj) {
					next_obj = obj->next_content;
					if (CAN_SEE_OBJ(ch, obj) && ((dotmode == FIND_ALL || isname(arg, obj->name))))
						perform_give(ch, vict, obj);
				}
			}
		}
	}


void weight_change_object(Object obj, int weight) {
	Object tmp_obj;
	Creature tmp_ch;

	if (obj->in_room != NOWHERE) {
		GET_OBJ_WEIGHT(obj) += weight;
	 	}
	 else if ((tmp_ch = obj->carried_by)) {
		GET_OBJ_WEIGHT(obj) += weight;
		obj_to_char(obj, tmp_ch);
		}
	else if ((tmp_obj = obj->in_obj)) {
		GET_OBJ_WEIGHT(obj) += weight;
		obj_to_obj(obj, tmp_obj);
		}
	else {
		log("SYSERR: Unknown attempt to subtract weight from an object.");
		}
	}


#define drink_WELL			0
#define drink_FOUNTAIN		1
#define drink_RIVER_SAME	2
#define drink_RIVER_ADJ		3
#define drink_OASIS			4


bool can_drink_from_room(Creature ch, byte type) {
	if (type == drink_WELL) {
		if (!IS_COMPLETE(ch->in_room))
			msg_to_char(ch, "The well isn't finished!\r\n");
		else if (!GET_BUILD_VALUE(ch->in_room))
			msg_to_char(ch, "The well has gone dry!\r\n");
		else
			return TRUE;
		return FALSE;
		}
	if (type == drink_FOUNTAIN) {
		if (!IS_COMPLETE(ch->in_room))
			msg_to_char(ch, "The fountain isn't finished!\r\n");
		else
			return TRUE;
		return FALSE;
		}
	return FALSE;
	}


int drink_message(Creature ch, Object obj, byte type, bool sip, int *liq) {
	*liq = LIQ_WATER;

	switch (type) {
		case -1:
			sprintf(buf, "$n %s %s from $p.", sip ? "sips" : "drinks", drinks[GET_OBJ_VAL(obj, 2)]);
			act(buf, TRUE, ch, obj, 0, TO_ROOM);
			msg_to_char(ch, "You %s the %s.\r\n", sip ? "sip" : "drink", drinks[GET_OBJ_VAL(obj, 2)]);

			*liq = GET_OBJ_VAL(obj, 2);
			break;
		case drink_WELL:
			GET_BUILD_VALUE(ch->in_room)--;
			msg_to_char(ch, "You drink cool water from the well.\r\n");
			act("$n drinks cool water from the well.", TRUE, ch, 0, 0, TO_ROOM);
			break;
		case drink_FOUNTAIN:
			msg_to_char(ch, "You take a drink from the fountain.\r\n");
			act("$n takes a drink from the fountain.", TRUE, ch, 0, 0, TO_ROOM);
			break;
		case drink_RIVER_SAME:
			msg_to_char(ch, "You bend over and drink from the river.\r\n");
			act("$n bends over and drinks from the river.", TRUE, ch, 0, 0, TO_ROOM);
			break;
		case drink_RIVER_ADJ:
			msg_to_char(ch, "You drink from the river's edge.\r\n");
			act("$n drinks from the river's edge.", TRUE, ch, 0, 0, TO_ROOM);
			break;
		case drink_OASIS:
			msg_to_char(ch, "You take a drink from the oasis.\r\n");
			act("$n takes a drink from the oasis.", TRUE, ch, 0, 0, TO_ROOM);
			break;
		}

	if (sip) {
		msg_to_char(ch, "It tastes like %s.\r\n", drinks[*liq]);
		return 1;
		}

	if (drink_aff[*liq][DRUNK] > 0)
		return MAX(1, GET_COND(ch, THIRST) / drink_aff[*liq][DRUNK]);
	else
		return number(45, 150);

	return 1;
	}


ACMD(do_drink) {
	Object temp;
	int amount, small_amount, weight, i, liquid;
	byte type = -1;

	one_argument(argument, arg);

	if (REAL_NPC(ch))		/* Cannot use GET_COND() on mobs. */
		return;

	if (!*arg) {
		if (SECT(ch->in_room) == SECT_RIVER)
			type = drink_RIVER_SAME;
		else if (SECT(ch->in_room) == SECT_OASIS)
			type = drink_OASIS;
		else if (SECT(ch->in_room) == SECT_FOUNTAIN) {
			if (!can_drink_from_room(ch, (type = drink_FOUNTAIN)))
				return;
			}
		else if (SECT(ch->in_room) == SECT_WELL) {
			if (!can_drink_from_room(ch, (type = drink_WELL)))
				return;
			}
		msg_to_char(ch, "Drink from what?\r\n");
		return;
		}

	if (!(temp = get_obj_in_list_vis(ch, arg, ch->carrying))) {
		if (is_abbrev(arg, "river") || is_abbrev(arg, "water")) {
			if (SECT(ch->in_room) == SECT_RIVER)
				type = drink_RIVER_SAME;
			else if (IS_OUTDOORS(ch)) {
				for (i = 0; i < NUM_2D_DIRS; i++)
					if (SECT(real_shift(ch->in_room, shift_dir[i][0], shift_dir[i][1])) == SECT_RIVER)
						type = drink_RIVER_ADJ;
				}
			}
		if (is_abbrev(arg, "oasis") || is_abbrev(arg, "water"))
			if (SECT(ch->in_room) == SECT_OASIS)
				type = drink_OASIS;
		if ((is_abbrev(arg, "well") || is_abbrev(arg, "water")) && SECT(ch->in_room) == SECT_WELL)
			if (!can_drink_from_room(ch, (type = drink_WELL)))
				return;
		if ((is_abbrev(arg, "fountain") || is_abbrev(arg, "water")) && SECT(ch->in_room) == SECT_FOUNTAIN)
			if (!can_drink_from_room(ch, (type = drink_FOUNTAIN)))
				return;

		if (type == -1) {
			send_to_char("You can't find it!\r\n", ch);
			return;
			}
		}

	if (temp && GET_OBJ_TYPE(temp) != ITEM_DRINKCON) {
		send_to_char("You can't drink from that!\r\n", ch);
		return;
		}

		/* The pig is drunk */
	if (GET_COND(ch, DRUNK) > 150 && GET_COND(ch, THIRST) < 345) {
		if (type >= 0)
			msg_to_char(ch, "You're so inebriated that you don't dare get that close to the water.\r\n");
		else {
			msg_to_char(ch, "You can't seem to get close enough to your mouth.\r\n");
			act("$n tries to drink but misses $s mouth!", TRUE, ch, 0, 0, TO_ROOM);
			}
		return;
		}

	if (GET_COND(ch, THIRST) < 10 && GET_COND(ch, THIRST) != -1) {
		msg_to_char(ch, "You're too full to drink anymore!\r\n");
		return;
		}

	if (GET_COND(ch, FULL) < 75 && GET_COND(ch, FULL) != -1 && GET_COND(ch, THIRST) < 345 && GET_COND(ch, THIRST) != -1) {
		send_to_char("Your stomach can't contain anymore!\r\n", ch);
		return;
		}

	if (temp && !GET_OBJ_VAL(temp, 1)) {
		send_to_char("It's empty.\r\n", ch);
		return;
		}

	if (subcmd == SCMD_DRINK)
		amount = drink_message(ch, temp, type, 0, &liquid);
	else
		amount = drink_message(ch, temp, type, 1, &liquid);

	small_amount = MAX(1, amount / 4);

	if (temp) {
		small_amount = MIN(small_amount, GET_OBJ_VAL(temp, 1));
		amount = small_amount * 4;

		/* You can't subtract more than the object weighs */
		weight = MIN(small_amount, GET_OBJ_WEIGHT(temp));

		weight_change_object(temp, -weight);	/* Subtract amount */

		if (liquid == LIQ_BLOOD)
			GET_BLOOD(ch) = MIN(GET_MAX_BLOOD(ch), GET_BLOOD(ch) + small_amount);
		}

	gain_condition(ch, DRUNK, (int) ((int) drink_aff[liquid][DRUNK] * amount) * 15 / 4);
	gain_condition(ch, FULL, -1 * (int) ((int) drink_aff[liquid][FULL] * amount) * 15/ 4);
	gain_condition(ch, THIRST, -1 * (int) ((int) drink_aff[liquid][THIRST] * amount) * 15 / 4);

	if (GET_COND(ch, DRUNK) > 150)
		send_to_char("You feel drunk.\r\n", ch);

	if (GET_COND(ch, THIRST) < 75)
		send_to_char("You don't feel thirsty any more.\r\n", ch);

	if (GET_COND(ch, FULL) < 75)
		send_to_char("You are full.\r\n", ch);

	if (temp) {
		GET_OBJ_VAL(temp, 1) -= small_amount;
		if (GET_OBJ_VAL(temp, 1) <= 0) {	/* The last bit */
			GET_OBJ_VAL(temp, 2) = 0;
			}
		}
	}


ACMD(do_eat) {
	Object food;
	int amount;

	one_argument(argument, arg);

	if (REAL_NPC(ch))		/* Cannot use GET_COND() on mobs. */
		return;

	if (!*arg) {
		send_to_char("Eat what?\r\n", ch);
		return;
		}
	if (!(food = get_obj_in_list_vis(ch, arg, ch->carrying)))
		if (!(food = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents))) {
			sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
			send_to_char(buf, ch);
			return;
			}
	if (subcmd == SCMD_TASTE && GET_OBJ_TYPE(food) == ITEM_DRINKCON) {
		do_drink(ch, argument, 0, SCMD_SIP);
		return;
		}
	if ((GET_OBJ_TYPE(food) != ITEM_FOOD) && !IS_CORPSE(food) && (GET_LEVEL(ch) < LVL_START_IMM)) {
		send_to_char("You can't eat THAT!\r\n", ch);
		return;
		}
	if (GET_COND(ch, FULL) < 75 && GET_COND(ch, FULL) != -1) {	/* Stomach full */
		send_to_char("You are too full to eat more!\r\n", ch);
		return;
		}
	if (subcmd == SCMD_EAT) {
		act("You eat some of $p.", FALSE, ch, food, 0, TO_CHAR);
		act("$n eats some of $p.", TRUE, ch, food, 0, TO_ROOM);
		}
	else {
		act("You nibble a little bit of $p.", FALSE, ch, food, 0, TO_CHAR);
		act("$n tastes a little bit of $p.", TRUE, ch, food, 0, TO_ROOM);
		}

	amount = (subcmd == SCMD_EAT ? IS_CORPSE(food) ? MIN(180, GET_OBJ_VAL(food, 1) * 15) : GET_OBJ_VAL(food, 0) * 15 : 15);
	amount = MIN(GET_COND(ch, FULL), amount);

	gain_condition(ch, FULL, -1 * amount);

	if (GET_COND(ch, FULL) < 75)
		send_to_char("You are full.\r\n", ch);

	if (IS_CORPSE(food)) {
		GET_OBJ_VAL(food, 1) -= amount;
		SET_BIT(GET_OBJ_VAL(food, 2), CORPSE_EATEN);
		}
	else
		GET_OBJ_VAL(food, 0) -= amount;

	if (GET_OBJ_VAL(food, IS_CORPSE(food) ? 1 : 0) <= 0) {
		send_to_char("There's nothing left now.\r\n", ch);
		extract_obj(food);
		}
	}


void do_fill_from_room(Creature ch, Object obj) {
	int amount = GET_OBJ_VAL(obj, 0) - GET_OBJ_VAL(obj, 1);

	if ((GET_OBJ_VAL(obj, 1) != 0) && GET_OBJ_VAL(obj, 2) != LIQ_WATER) {
		send_to_char("There is already another liquid in it!\r\n", ch);
		return;
		}
	if (amount <= 0) {
		send_to_char("There is no room for more.\r\n", ch);
		return;
		}
	if (SECT(ch->in_room) == SECT_WELL) {
		if (!IS_COMPLETE(ch->in_room)) {
			msg_to_char(ch, "The well isn't completely build yet.\r\n");
			return;
			}
		if (GET_BUILD_VALUE(ch->in_room) <= 0) {
			msg_to_char(ch, "The well is dry.\r\n");
			return;
			}
		act("You gently fill $p from the well.", FALSE, ch, obj, 0, TO_CHAR);
		act("$n gently fills $p from the well.", TRUE, ch, obj, 0, TO_ROOM);
		GET_BUILD_VALUE(ch->in_room) -= 1;
		}
	else if (SECT(ch->in_room) == SECT_FOUNTAIN) {
		if (!IS_COMPLETE(ch->in_room)) {
			msg_to_char(ch, "The fountain isn't finished yet.\r\n");
			return;
			}
		act("You gently fill $p from the fountain.", FALSE, ch, obj, 0, TO_CHAR);
		act("$n gently fills $p from the fountain.", TRUE, ch, obj, 0, TO_ROOM);
		}
	else if (SECT(ch->in_room) == SECT_OASIS) {
		act("You gently fill $p from the oasis.", FALSE, ch, obj, 0, TO_CHAR);
		act("$n gently fills $p from the oasis.", TRUE, ch, obj, 0, TO_ROOM);
		}
	else {
		act("You gently fill $p from the river.", FALSE, ch, obj, 0, TO_CHAR);
		act("$n gently fills $p from the river.", TRUE, ch, obj, 0, TO_ROOM);
		}

	/* First same type liq. */
	GET_OBJ_VAL(obj, 2) = LIQ_WATER;

	GET_OBJ_VAL(obj, 1) = GET_OBJ_VAL(obj, 0);

	/* And the weight boogie */
	weight_change_object(obj, amount);	/* Add weight */
	}


/* When a trench fills up by "pour out" or by rain, this happens */
void fill_trench(room_rnum room) {
	Creature c, next_c;

	if (world[room].people)
		act("The trench is full.", FALSE, world[room].people, 0, 0, TO_CHAR | TO_ROOM);
	SECT(room) = SECT_RIVER;
	GET_BUILD_VALUE(room) = 0;
	for (c = world[room].people; c; c = next_c) {
		next_c = c->next_in_room;
		if (REAL_NPC(c)) {
			msg_to_char(c, "You are swept away in the current.\r\n");
			act("$n is swept away in the water.", FALSE, c, 0, 0, TO_ROOM);
			extract_char(c);
			}
		}
	}


ACMD(do_pour) {
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	Object from_obj = NULL, to_obj = NULL;
	int amount, i;

	two_arguments(argument, arg1, arg2);

	if (subcmd == SCMD_POUR) {
		if (!*arg1) {		/* No arguments */
			send_to_char("From what do you want to pour?\r\n", ch);
			return;
			}
		if (!(from_obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
			send_to_char("You can't find it!\r\n", ch);
			return;
			}
		if (GET_OBJ_TYPE(from_obj) != ITEM_DRINKCON) {
			send_to_char("You can't pour from that!\r\n", ch);
			return;
			}
		}
	if (subcmd == SCMD_FILL) {
		if (!*arg1) {		/* no arguments */
			send_to_char("What do you want to fill?  And from what are you filling it?\r\n", ch);
			return;
			}
		if (!(to_obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
			send_to_char("You can't find it!\r\n", ch);
			return;
			}
		if (GET_OBJ_TYPE(to_obj) != ITEM_DRINKCON) {
			act("You can't fill $p!", FALSE, ch, to_obj, 0, TO_CHAR);
			return;
			}
		if (!*arg2) {		/* no 2nd argument */
			act("From what would you like to fill $p?", FALSE, ch, to_obj, 0, TO_CHAR);
			return;
			}
		if (is_abbrev(arg2, "fountain") && SECT(ch->in_room) == SECT_FOUNTAIN) {
			do_fill_from_room(ch, to_obj);
			return;
			}
		if (is_abbrev(arg2, "well") && SECT(ch->in_room) == SECT_WELL) {
			do_fill_from_room(ch, to_obj);
			return;
			}
		if (is_abbrev(arg2, "oasis") || is_abbrev(arg2, "water")) {
			if (SECT(ch->in_room) == SECT_OASIS) {
				do_fill_from_room(ch, to_obj);
				return;
				}
			}
		if (is_abbrev(arg2, "river") || is_abbrev(arg2, "water")) {
			if (SECT(ch->in_room) == SECT_RIVER) {
				do_fill_from_room(ch, to_obj);
				return;
				}
			else if (IS_OUTDOORS(ch)) {
				for (i = 0; i < NUM_2D_DIRS; i++)
					if (SECT(real_shift(ch->in_room, shift_dir[i][0], shift_dir[i][1])) == SECT_RIVER) {
						do_fill_from_room(ch, to_obj);
						return;
						}
				}
			msg_to_char(ch, "There doesn't seem to be %s %s here.\r\n", AN(arg2), arg2);
			return;
			}
		sprintf(buf, "There doesn't seem to be %s %s here.\r\n", AN(arg2), arg2);
		send_to_char(buf, ch);
		return;
		}
	if (GET_OBJ_VAL(from_obj, 1) == 0) {
		act("The $p is empty.", FALSE, ch, from_obj, 0, TO_CHAR);
		return;
		}
	if (subcmd == SCMD_POUR) {	/* pour */
		if (!*arg2) {
			send_to_char("Where do you want it?  Out or in what?\r\n", ch);
			return;
			}
		if (!str_cmp(arg2, "out")) {
			act("$n empties $p.", TRUE, ch, from_obj, 0, TO_ROOM);
			act("You empty $p.", FALSE, ch, from_obj, 0, TO_CHAR);

			weight_change_object(from_obj, -GET_OBJ_VAL(from_obj, 1)); /* Empty */

			/* If it's a trench, fill her up */
			if (GET_OBJ_VAL(from_obj, 2) == LIQ_WATER && SECT(ch->in_room) == SECT_TRENCH && GET_BUILD_VALUE(ch->in_room) >= 0) {
				GET_BUILD_VALUE(ch->in_room) += GET_OBJ_VAL(from_obj, 1);
				if (GET_BUILD_VALUE(ch->in_room) >= 2000)
					fill_trench(ch->in_room);
				}

			GET_OBJ_VAL(from_obj, 1) = 0;
			GET_OBJ_VAL(from_obj, 2) = 0;

			return;
			}
		if (!(to_obj = get_obj_in_list_vis(ch, arg2, ch->carrying))) {
			send_to_char("You can't find it!\r\n", ch);
			return;
			}
		if ((GET_OBJ_TYPE(to_obj) != ITEM_DRINKCON)) {
			send_to_char("You can't pour anything into that.\r\n", ch);
			return;
			}
		}
	if (to_obj == from_obj) {
		send_to_char("A most unproductive effort.\r\n", ch);
		return;
		}
	if ((GET_OBJ_VAL(to_obj, 1) != 0) && (GET_OBJ_VAL(to_obj, 2) != GET_OBJ_VAL(from_obj, 2))) {
		send_to_char("There is already another liquid in it!\r\n", ch);
		return;
		}
	if (!(GET_OBJ_VAL(to_obj, 1) < GET_OBJ_VAL(to_obj, 0))) {
		send_to_char("There is no room for more.\r\n", ch);
		return;
		}
	if (subcmd == SCMD_POUR) {
		sprintf(buf, "You pour the %s into the %s.", drinks[GET_OBJ_VAL(from_obj, 2)], arg2);
		send_to_char(buf, ch);
		}
	if (subcmd == SCMD_FILL) {
		act("You gently fill $p from $P.", FALSE, ch, to_obj, from_obj, TO_CHAR);
		act("$n gently fills $p from $P.", TRUE, ch, to_obj, from_obj, TO_ROOM);
		}

	/* First same type liq. */
	GET_OBJ_VAL(to_obj, 2) = GET_OBJ_VAL(from_obj, 2);

	/* Then how much to pour */
	GET_OBJ_VAL(from_obj, 1) -= (amount = (GET_OBJ_VAL(to_obj, 0) - GET_OBJ_VAL(to_obj, 1)));

	GET_OBJ_VAL(to_obj, 1) = GET_OBJ_VAL(to_obj, 0);

	if (GET_OBJ_VAL(from_obj, 1) < 0) {	/* There was too little */
		GET_OBJ_VAL(to_obj, 1) += GET_OBJ_VAL(from_obj, 1);
		amount += GET_OBJ_VAL(from_obj, 1);
		GET_OBJ_VAL(from_obj, 1) = 0;
		GET_OBJ_VAL(from_obj, 2) = 0;
		}

	/* And the weight boogie */
	weight_change_object(from_obj, -amount);
	weight_change_object(to_obj, amount);	/* Add weight */
	}


void wear_message(Creature ch, Object obj, int where) {
	const char *wear_messages[][2] = {
		{"$n wears $p on $s head.",
		 "You wear $p on your head."},

		{"$n pins $p onto $s ears.",
		 "You pin $p onto your ears."},

		{"$n wears $p around $s neck.",
		 "You wear $p around your neck."},

		{"$n wears $p on $s body.",
		 "You wear $p on your body."},

		{"$n wears $p as armor.",
		 "You wear $p as armor."},

		{"$n wears $p about $s body.",
		 "You wear $p around your body."},

		{"$n wears $p over $s shoulder.",
		 "You wear $p over your shoulder."},

		{"$n wears $p on $s arms.",
		 "You wear $p on your arms."},

		{"$n puts $p on $s hands.",
		 "You put $p on your hands."},

		{"$n slides $p on to $s right ring finger.",
		 "You slide $p on to your right ring finger."},

		{"$n slides $p on to $s left ring finger.",
		 "You slide $p on to your left ring finger."},

		{"$n wears $p around $s waist.",
		 "You wear $p around your waist."},

		{"$n attaches $p to $P.",
		 "You attach $p to $P."},

		{"$n sheaths $p.",
		 "You sheath $p."},

		{"$n attaches $p to $P.",
		 "You attach $p to $P."},

		{"$n sheaths $p.",
		 "You sheath $p."},

		{"$n attaches $p to $P.",
		 "You attach $p to $P."},

		{"$n sheaths $p.",
		 "You sheath $p."},

		{"$n puts $p on $s legs.",
		 "You put $p on your legs."},

		{"$n wears $p on $s feet.",
		 "You wear $p on your feet."},

		{"$n wields $p.",
		 "You wield $p."},

		{"$n grabs $p.",
		 "You grab $p."}
		};

	/* WEAR_WAIST is used for sheaths, which attach to belt.  It's already checked, don't worry */
	act(wear_messages[where][0], TRUE, ch, obj, GET_EQ(ch, WEAR_WAIST), TO_ROOM);
	act(wear_messages[where][1], FALSE, ch, obj, GET_EQ(ch, WEAR_WAIST), TO_CHAR);
	}


void perform_wear(Creature ch, Object obj, int where) {
	int i;

	/*
	 * ITEM_WEAR_TAKE is used for objects that do not require special bits
	 * to be put into that position (e.g. you can hold any object, not just
	 * an object with a HOLD bit.)
	 */

	int wear_bitvectors[] = {
		ITEM_WEAR_HEAD, ITEM_WEAR_EARS, ITEM_WEAR_NECK,
		ITEM_WEAR_BODY,	ITEM_WEAR_ARMOR, ITEM_WEAR_ABOUT,
		ITEM_WEAR_QUIVER, ITEM_WEAR_ARMS, ITEM_WEAR_HANDS,
		ITEM_WEAR_FINGER, ITEM_WEAR_FINGER, ITEM_WEAR_WAIST,
		ITEM_WEAR_SHEATH, ITEM_WEAR_WIELD, ITEM_WEAR_SHEATH,
		ITEM_WEAR_WIELD,	ITEM_WEAR_SHEATH,
		ITEM_WEAR_WIELD,	ITEM_WEAR_LEGS,	ITEM_WEAR_FEET,
		ITEM_WEAR_WIELD,	ITEM_WEAR_TAKE
		};

	const char *already_wearing[] = {
		"You're already wearing something on your head.\r\n",
		"You're already wearing something on your ears.\r\n",
		"You can't wear anything else around your neck.\r\n",
		"You're already wearing something on your body.\r\n",
		"You're already wearing armor.\r\n",
		"You're already wearing something about your body.\r\n",
		"You've already equipped a quiver.\r\n",
		"You're already wearing something on your arms.\r\n",
		"You're already wearing something on your hands.\r\n",
		"YOU SHOULD NEVER SEE THIS MESSAGE.  PLEASE REPORT.\r\n",
		"You're already wearing something on both of your ring fingers.\r\n",
		"You already have something around your waist.\r\n",
		"You've already attached something to your belt.\r\n",
		"You've already got something sheathed.\r\n",
		"You've already attached something to your belt.\r\n",
		"You've already got something sheathed.\r\n",
		"You've already attached something to your belt.\r\n",
		"You've already got something sheathed.\r\n",
		"You're already wearing something on your legs.\r\n",
		"You're already wearing something on your feet.\r\n",
		"You're already wielding a weapon.\r\n",
		"You're already holding something.\r\n"
		};

	/* first, make sure that the wear position is valid. */
	if (!CAN_WEAR(obj, wear_bitvectors[where])) {
		act("You can't wear $p there.", FALSE, ch, obj, 0, TO_CHAR);
		return;
		}
	/* for finger, try pos 2 if pos 1 is already full */
	if (where == WEAR_FINGER_R && GET_EQ(ch, where))
			where = WEAR_FINGER_L;

	/* if sheath, rotate */
	if (where == WEAR_SHEATH_1 && GET_EQ(ch, where))
		where = WEAR_SHEATH_2;
	if (where == WEAR_SHEATH_2 && GET_EQ(ch, where))
		where = WEAR_SHEATH_3;

	if (DSC_FLAGGED(ch, DSC_TALONS_OF_THE_BEAST) && (where == WEAR_FINGER_R || where == WEAR_FINGER_L || where == WEAR_HANDS)) {
		act("You can't wear $p with your talons extended!", FALSE, ch, obj, 0, TO_CHAR);
		return;
		}

	for (i = 0; i < MAX_OBJ_AFFECT; i++)
		if ((obj->affected[i].location == APPLY_STRENGTH && GET_STRENGTH(ch) + obj->affected[i].modifier < 1) || (obj->affected[i].location == APPLY_STAMINA && GET_STAMINA(ch) + obj->affected[i].modifier < 1) || (obj->affected[i].location == APPLY_DEXTERITY && GET_DEXTERITY(ch) + obj->affected[i].modifier < 1)) {
			act("You can't use $p, it's too heavy!", FALSE, ch, obj, 0, TO_CHAR);
			return;
			}

	if ((where == WEAR_SHEATH_1 || where == WEAR_SHEATH_2 || where == WEAR_SHEATH_3) && !GET_EQ(ch, WEAR_WAIST)) {
		act("You need a belt to attach $p to.", FALSE, ch, obj, 0, TO_CHAR);
		return;
		}

	if (GET_EQ(ch, where)) {
		send_to_char(already_wearing[where], ch);
		return;
		}
	wear_message(ch, obj, where);
	equip_char(ch, obj, where);
	}


int find_eq_pos(Creature ch, Object obj, char *arg) {
	int where = -1;

	/* \r to prevent explicit wearing. Don't use \n, it's end-of-array marker. */
	const char *keywords[] = {
		"head",
		"ears",
		"neck",
		"body",
		"armor",
		"about",
		"quiver",
		"arms",
		"hands",
		"finger",
		"\r!RESERVED!",
		"waist",
		"sheath",
		"\r!RESERVED!",
		"\r!RESERVED!",
		"\r!RESERVED!",
		"\r!RESERVED!",
		"\r!RESERVED!",
		"legs",
		"feet",
		"\r!RESERVED!",
		"\r!RESERVED!",
		"\n"
		};

	if (!arg || !*arg) {
		if (CAN_WEAR(obj, ITEM_WEAR_FINGER))		where = WEAR_FINGER_R;
		if (CAN_WEAR(obj, ITEM_WEAR_EARS))			where = WEAR_EARS;
		if (CAN_WEAR(obj, ITEM_WEAR_NECK))			where = WEAR_NECK;
		if (CAN_WEAR(obj, ITEM_WEAR_QUIVER))		where = WEAR_QUIVER;
		if (CAN_WEAR(obj, ITEM_WEAR_BODY))			where = WEAR_BODY;
		if (CAN_WEAR(obj, ITEM_WEAR_ARMOR))			where = WEAR_ARMOR;
		if (CAN_WEAR(obj, ITEM_WEAR_HEAD))			where = WEAR_HEAD;
		if (CAN_WEAR(obj, ITEM_WEAR_LEGS))			where = WEAR_LEGS;
		if (CAN_WEAR(obj, ITEM_WEAR_FEET))			where = WEAR_FEET;
		if (CAN_WEAR(obj, ITEM_WEAR_HANDS))			where = WEAR_HANDS;
		if (CAN_WEAR(obj, ITEM_WEAR_ARMS))			where = WEAR_ARMS;
		if (CAN_WEAR(obj, ITEM_WEAR_ABOUT))			where = WEAR_ABOUT;
		if (CAN_WEAR(obj, ITEM_WEAR_WAIST))			where = WEAR_WAIST;
		if (CAN_WEAR(obj, ITEM_WEAR_SHEATH))		where = WEAR_SHEATH_1;
		}
	else {
		if ((where = search_block(arg, keywords, FALSE)) < 0) {
			sprintf(buf, "'%s'?  What part of your body is THAT?\r\n", arg);
			send_to_char(buf, ch);
			}
		}

	return (where);
	}


ACMD(do_wear) {
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	Object obj, next_obj;
	int where, dotmode, items_worn = 0;

	two_arguments(argument, arg1, arg2);

	if (!*arg1) {
		send_to_char("Wear what?\r\n", ch);
		return;
		}
	dotmode = find_all_dots(arg1);

	if (*arg2 && (dotmode != FIND_INDIV)) {
		send_to_char("You can't specify the same body location for more than one item!\r\n", ch);
		return;
		}
	if (dotmode == FIND_ALL) {
		for (obj = ch->carrying; obj; obj = next_obj) {
			next_obj = obj->next_content;
			if (CAN_SEE_OBJ(ch, obj) && (where = find_eq_pos(ch, obj, 0)) >= 0) {
				items_worn++;
				perform_wear(ch, obj, where);
				}
			}
		if (!items_worn)
			send_to_char("You don't seem to have anything wearable.\r\n", ch);
		}
	else if (dotmode == FIND_ALLDOT) {
		if (!*arg1) {
			send_to_char("Wear all of what?\r\n", ch);
			return;
			}
		if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
			sprintf(buf, "You don't seem to have any %ss.\r\n", arg1);
			send_to_char(buf, ch);
			}
		else
			while (obj) {
				next_obj = get_obj_in_list_vis(ch, arg1, obj->next_content);
				if ((where = find_eq_pos(ch, obj, 0)) >= 0)
					perform_wear(ch, obj, where);
				else
					act("You can't wear $p.", FALSE, ch, obj, 0, TO_CHAR);
				obj = next_obj;
				}
		}
	else {
		if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
			sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg1), arg1);
			send_to_char(buf, ch);
			}
		else {
			if ((where = find_eq_pos(ch, obj, arg2)) >= 0)
				perform_wear(ch, obj, where);
			else if (!*arg2)
				act("You can't wear $p.", FALSE, ch, obj, 0, TO_CHAR);
			}
		}
	}


ACMD(do_wield) {
	Object obj;

	one_argument(argument, arg);

	if (!*arg)
		send_to_char("Wield what?\r\n", ch);
	else if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
		sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
		send_to_char(buf, ch);
		}
	else {
		if (!CAN_WEAR(obj, ITEM_WEAR_WIELD))
			send_to_char("You can't wield that.\r\n", ch);
		else if (GET_OBJ_WEIGHT(obj) > str_app[GET_STRENGTH(ch)].wield_w)
			send_to_char("It's too heavy for you to use.\r\n", ch);
		else {
			if (GET_EQ(ch, WEAR_WIELD))
				perform_remove(ch, WEAR_WIELD, TRUE);
			perform_wear(ch, obj, WEAR_WIELD);
			}
		}
	}


ACMD(do_grab) {
	Object obj;

	one_argument(argument, arg);

	if (!*arg)
		send_to_char("Hold what?\r\n", ch);
	else if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
		sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
		send_to_char(buf, ch);
		}
	else {
		if (!CAN_WEAR(obj, ITEM_WEAR_HOLD))
			send_to_char("You can't hold that.\r\n", ch);
		else if (GET_OBJ_WEIGHT(obj) > str_app[GET_STRENGTH(ch)].wield_w)
			send_to_char("It's too heavy for you to use.\r\n", ch);
		else {
			if (GET_EQ(ch, WEAR_HOLD))
				perform_remove(ch, WEAR_HOLD, TRUE);
			perform_wear(ch, obj, WEAR_HOLD);
			}
		}
	}


ACMD(do_swap) {
	Object wield, hold;

	if (!(wield = GET_EQ(ch, WEAR_WIELD)))
		msg_to_char(ch, "You're not even wielding anything to swap!\r\n");
	else if (!(hold = GET_EQ(ch, WEAR_HOLD)))
		msg_to_char(ch, "You're not even holding anything to swap!\r\n");
	else if (!CAN_WEAR(wield, ITEM_WEAR_HOLD))
		act("You can't hold $p.", FALSE, ch, wield, 0, TO_CHAR);
	else if (!CAN_WEAR(hold, ITEM_WEAR_WIELD))
		act("You can't wield $p.", FALSE, ch, hold, 0, TO_CHAR);
	else {
		obj_to_char(unequip_char(ch, WEAR_WIELD), ch);
		obj_to_char(unequip_char(ch, WEAR_HOLD), ch);
		perform_wear(ch, hold, WEAR_WIELD);
		perform_wear(ch, wield, WEAR_HOLD);
		}
	}


ACMD(do_draw) {
	Object obj = NULL;
	int loc = 0;

	one_argument(argument, arg);

	if (!*arg) {
		msg_to_char(ch, "Draw what?\r\n");
		return;
		}

	if ((obj = GET_EQ(ch, WEAR_IN_SHEATH_1)) && isname(arg, obj->name))
		loc = WEAR_IN_SHEATH_1;
	else if ((obj = GET_EQ(ch, WEAR_IN_SHEATH_2)) && isname(arg, obj->name))
		loc = WEAR_IN_SHEATH_2;
	else if ((obj = GET_EQ(ch, WEAR_IN_SHEATH_3)) && isname(arg, obj->name))
		loc = WEAR_IN_SHEATH_3;
	else {
		msg_to_char(ch, "You have nothing by that name sheathed!\r\n");
		return;
		}

	if (GET_EQ(ch, WEAR_WIELD))
		msg_to_char(ch, "You're already wielding a weapon!\r\n");
	else {
		obj_to_char(unequip_char(ch, loc), ch);
		perform_wear(ch, obj, WEAR_WIELD);
		}
	}


/* Val 0, 1, or 2 of the sheath must match the weapon type */
ACMD(do_sheath) {
	Object obj;
	int loc = 0;

	if (!(obj = GET_EQ(ch, WEAR_WIELD))) {
		msg_to_char(ch, "You aren't even wielding anything!\r\n");
		return;
		}

	/* do they have one at all? */
	if (!GET_EQ(ch, WEAR_SHEATH_1) && !GET_EQ(ch, WEAR_SHEATH_2) && !GET_EQ(ch, WEAR_SHEATH_3)) {
		msg_to_char(ch, "You aren't wearing any type of sheath!\r\n");
		return;
		}

	/* are any of them even open? */
	if ((!GET_EQ(ch, WEAR_SHEATH_1) || GET_EQ(ch, WEAR_IN_SHEATH_1)) && (!GET_EQ(ch, WEAR_SHEATH_2) || GET_EQ(ch, WEAR_IN_SHEATH_2)) && (!GET_EQ(ch, WEAR_SHEATH_3) || GET_EQ(ch, WEAR_IN_SHEATH_3))) {
		msg_to_char(ch, "You have no empty sheaths!\r\n");
		return;
		}

	/* 1 must be free.. test sheath 1 */
	if (GET_EQ(ch, WEAR_SHEATH_1) && !GET_EQ(ch, WEAR_IN_SHEATH_1)) {
		if ((GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_1), 0) != -1 && GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_1), 0) == GET_OBJ_VAL(obj, 2))
				|| (GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_1), 1) != -1 && GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_1), 1) == GET_OBJ_VAL(obj, 2))
				|| (GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_1), 2) != -1 && GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_1), 2) == GET_OBJ_VAL(obj, 2)))
			loc = WEAR_IN_SHEATH_1;
		}

	/* .. test sheath 2 */
	if (GET_EQ(ch, WEAR_SHEATH_2) && !GET_EQ(ch, WEAR_IN_SHEATH_2)) {
		if ((GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_2), 0) != -1 && GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_2), 0) == GET_OBJ_VAL(obj, 2))
				|| (GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_2), 1) != -1 && GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_2), 1) == GET_OBJ_VAL(obj, 2))
				|| (GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_2), 2) != -1 && GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_2), 2) == GET_OBJ_VAL(obj, 2)))
			loc = WEAR_IN_SHEATH_2;
		}

	/* .. test sheath 3 */
	if (GET_EQ(ch, WEAR_SHEATH_3) && !GET_EQ(ch, WEAR_IN_SHEATH_3)) {
		if ((GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_3), 0) != -1 && GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_3), 0) == GET_OBJ_VAL(obj, 2))
				|| (GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_3), 1) != -1 && GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_3), 1) == GET_OBJ_VAL(obj, 2))
				|| (GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_3), 2) != -1 && GET_OBJ_VAL(GET_EQ(ch, WEAR_SHEATH_3), 2) == GET_OBJ_VAL(obj, 2)))
			loc = WEAR_IN_SHEATH_3;
		}

	/* oops.. no matching types */
	if (loc == 0) {
		act("You can't sheath $p in any sheath you're using!", FALSE, ch, obj, 0, TO_CHAR);
		return;
		}

	obj_to_char(unequip_char(ch, WEAR_WIELD), ch);
	perform_wear(ch, obj, loc);
	}


void perform_remove(Creature ch, int pos, bool swap) {
	Object obj;

	/* If swap == TRUE, we're swapping weapons, ignore weight */

	if (!(obj = GET_EQ(ch, pos)))
		log("SYSERR: perform_remove: bad pos %d passed.", pos);
	else if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) && !swap)
		act("$p: you can't carry that many items!", FALSE, ch, obj, 0, TO_CHAR);
	else {
		if (pos == WEAR_SHEATH_1 && GET_EQ(ch, WEAR_IN_SHEATH_1))
			perform_remove(ch, WEAR_IN_SHEATH_1, 0);
		if (pos == WEAR_SHEATH_2 && GET_EQ(ch, WEAR_IN_SHEATH_2))
			perform_remove(ch, WEAR_IN_SHEATH_2, 0);
		if (pos == WEAR_SHEATH_3 && GET_EQ(ch, WEAR_IN_SHEATH_3))
			perform_remove(ch, WEAR_IN_SHEATH_3, 0);

		if (pos == WEAR_WAIST && GET_EQ(ch, WEAR_SHEATH_1))
			perform_remove(ch, WEAR_SHEATH_1, 0);
		if (pos == WEAR_WAIST && GET_EQ(ch, WEAR_SHEATH_2))
			perform_remove(ch, WEAR_SHEATH_2, 0);
		if (pos == WEAR_WAIST && GET_EQ(ch, WEAR_SHEATH_3))
			perform_remove(ch, WEAR_SHEATH_3, 0);

		obj_to_char(unequip_char(ch, pos), ch);
		act("You stop using $p.", FALSE, ch, obj, 0, TO_CHAR);
		act("$n stops using $p.", TRUE, ch, obj, 0, TO_ROOM);
		}
	}


ACMD(do_remove) {
	extern int board_loaded;
	void init_boards(void);
	extern int find_board(Creature ch);
	extern int Board_remove_msg(int board_type, Creature ch, char *arg, Object board);
	int i, dotmode, found;
	int board_type;
	Object board;

	one_argument(argument, arg);

	if (isdigit(*arg)) {
		for (board = world[ch->in_room].contents; board; board = board->next_content)
			if (GET_OBJ_TYPE(board) == ITEM_BOARD)
				break;
		if (board && ch->desc) {
			if (!board_loaded) {
				init_boards();
				board_loaded = 1;
				}
			if ((board_type = find_board(ch)) != -1)
				if (Board_remove_msg(board_type, ch, argument, board))
					return;
			}
		}

	if (!*arg) {
		send_to_char("Remove what?\r\n", ch);
		return;
		}
	dotmode = find_all_dots(arg);

	if (dotmode == FIND_ALL) {
		found = 0;
		for (i = 0; i < NUM_WEARS; i++)
			if (GET_EQ(ch, i)) {
				perform_remove(ch, i, FALSE);
				found = 1;
				}
		if (!found)
			send_to_char("You're not using anything.\r\n", ch);
		}
	else if (dotmode == FIND_ALLDOT) {
		if (!*arg)
			send_to_char("Remove all of what?\r\n", ch);
		else {
			found = 0;
			for (i = 0; i < NUM_WEARS; i++)
				if (GET_EQ(ch, i) && CAN_SEE_OBJ(ch, GET_EQ(ch, i)) && isname(arg, GET_EQ(ch, i)->name)) {
					perform_remove(ch, i, FALSE);
					found = 1;
					}
			if (!found) {
				sprintf(buf, "You don't seem to be using any %ss.\r\n", arg);
				send_to_char(buf, ch);
				}
			}
		}
	else {
		/* Returns object pointer but we don't need it, just true/false. */
		if (!get_object_in_equip_vis(ch, arg, ch->equipment, &i)) {
			sprintf(buf, "You don't seem to be using %s %s.\r\n", AN(arg), arg);
			send_to_char(buf, ch);
			}
		else
			perform_remove(ch, i, FALSE);
		}
	}


/* Data structure for STORE_BUILDINGs */
struct storage_data_structure {
	obj_vnum vnum;
	int building_type, room_type;
	int spec;
	} storage_data[] = {
		{ o_TREE,		BUILDING_LUMBER_YARD,	-2,				0	},
		{ o_LOG,		BUILDING_LUMBER_YARD,	-2,				0	},
		{ o_STICK,		BUILDING_LUMBER_YARD,	-2,				0	},

		{ o_ROCK,		BUILDING_GRAVEL_PIT,	-2,				0	},
		{ o_FLINT,		BUILDING_GRAVEL_PIT,	-2,				0	},

		{ o_WHEAT,		BUILDING_GRANARY,		-2,				0	},
		{ o_CORN,		BUILDING_GRANARY,		-2,				0	},

		{ o_APPLES,		BUILDING_CANNERY,		-2,				0	},

		{ o_IRON,		BUILDING_FOUNDRY,		-2,				0	},

		{ o_ARROW,		BUILDING_ARSENAL,		-2,				0	},

		{ o_SKIN,		BUILDING_TANNERY,		-2,				0	},

		{ o_WAX,		BUILDING_APIARY,		-2,				0	},

		{ o_CHAIR,		-2,						RTYPE_STORAGE,	0	},
		{ o_BENCH,		-2,						RTYPE_STORAGE,	0	},
		{ o_TABLE,		-2,						RTYPE_STORAGE,	0	},
		{ o_STOOL,		-2,						RTYPE_STORAGE,	0	},

		{ o_SHIELD,		-2,						RTYPE_SHIELD_RACKS,	0	},
		{ f_SHIELD,		-2,						RTYPE_SHIELD_RACKS,	0	},
		{ f_KITE,		-2,						RTYPE_SHIELD_RACKS,	0	},
		{ f_TOWER,		-2,						RTYPE_SHIELD_RACKS,	0	},

		{ f_BELT,		-2,						RTYPE_ARMOR_STORAGE,	0	},
		{ f_BREASTPLATE,-2,						RTYPE_ARMOR_STORAGE,	0	},
		{ f_RING,		-2,						RTYPE_ARMOR_STORAGE,	0	},
		{ f_CHAIN,		-2,						RTYPE_ARMOR_STORAGE,	0	},
		{ f_PLATE,		-2,						RTYPE_ARMOR_STORAGE,	0	},
		{ f_FULL_PLATE, -2,						RTYPE_ARMOR_STORAGE,	0	},
		{ f_HELM,		-2,						RTYPE_ARMOR_STORAGE,	0	},
		{ f_GREAT_HELM,	-2,						RTYPE_ARMOR_STORAGE,	0	},

		{ f_DIRK,		-2,						RTYPE_ARMORY,	0	},
		{ f_AXE,		-2,						RTYPE_ARMORY,	0	},
		{ f_SHORTSWORD,	-2,						RTYPE_ARMORY,	0	},
		{ f_DAGGER,		-2,						RTYPE_ARMORY,	0	},
		{ f_RAPIER,		-2,						RTYPE_ARMORY,	0	},
		{ f_MACE,		-2,						RTYPE_ARMORY,	0	},
		{ f_SWORD,		-2,						RTYPE_ARMORY,	0	},
		{ f_SCIMITAR,	-2,						RTYPE_ARMORY,	0	},
		{ f_PIKE,		-2,						RTYPE_ARMORY,	0	},
		{ f_HALBERT,	-2,						RTYPE_ARMORY,	0	},
		{ f_MAUL,		-2,						RTYPE_ARMORY,	0	},
		{ f_POLEAXE,	-2,						RTYPE_ARMORY,	0	},
		{ f_BROADSWORD,	-2,						RTYPE_ARMORY,	0	},
		{ f_CLAYMORE,	-2,						RTYPE_ARMORY,	0	},
		{ f_FLAMBERGE,	-2,						RTYPE_ARMORY,	0	},
		{ o_WHIP,		-2,						RTYPE_ARMORY,	0	},
		{ o_SHORTBOW,	-2,						RTYPE_ARMORY,	0	},
		{ o_LONGBOW,	-2,						RTYPE_ARMORY,	0	},
		{ o_SCABBARD,	-2,						RTYPE_ARMORY,	0	},
		{ o_SHEATH,		-2,						RTYPE_ARMORY,	0	},
		{ o_BELTLOOP,	-2,						RTYPE_ARMORY,	0	},

		{ f_HAMMER,		BUILDING_TOOLS,			-2,				0	},
		{ f_PICK,		BUILDING_TOOLS,			-2,				0	},
		{ f_AXE,		BUILDING_TOOLS,			-2,				0	},
		{ f_SHOVEL,		BUILDING_TOOLS,			-2,				0	},
		{ f_SCYTHE,		BUILDING_TOOLS,			-2,				0	},

		{ o_SHAWL,		-2,						RTYPE_CLOSET,	0	},
		{ o_HOOD,		-2,						RTYPE_CLOSET,	0	},
		{ o_CLOAK,		-2,						RTYPE_CLOSET,	0	},
		{ o_GLOVES,		-2,						RTYPE_CLOSET,	0	},
		{ o_SHOES,		-2,						RTYPE_CLOSET,	0	},
		{ o_CAPE,		-2,						RTYPE_CLOSET,	0	},
		{ o_PANTS,		-2,						RTYPE_CLOSET,	0	},
		{ o_TUNIC,		-2,						RTYPE_CLOSET,	0	},
		{ o_SHIRT,		-2,						RTYPE_CLOSET,	0	},
		{ o_BLOUSE,		-2,						RTYPE_CLOSET,	0	},
		{ o_TOGA,		-2,						RTYPE_CLOSET,	0	},
		{ o_GAUNTLETS,	-2,						RTYPE_CLOSET,	0	},
		{ o_BOOTS,		-2,						RTYPE_CLOSET,	0	},
		{ o_JACKET,		-2,						RTYPE_CLOSET,	0	},
		{ o_DRESS,		-2,						RTYPE_CLOSET,	0	},
		{ o_HAT,		-2,						RTYPE_CLOSET,	0	},
		{ o_BRACERS,	-2,						RTYPE_CLOSET,	0	},
		{ o_RIDINGBOOTS,-2,						RTYPE_CLOSET,	0	},
		{ o_BELT,		-2,						RTYPE_CLOSET,	0	},
		{ o_SASH,		-2,						RTYPE_CLOSET,	0	},

		{ o_SILVER,			-2,					RTYPE_VAULT,	1	},
		{ o_SILVER_DISC,	-2,					RTYPE_VAULT,	1	},
		{ o_SILVER_BAR,		-2,					RTYPE_VAULT,	1	},
		{ o_GOLD,			-2,					RTYPE_VAULT,	1	},
		{ o_GOLD_DISC,		-2,					RTYPE_VAULT,	1	},
		{ o_GOLD_BAR,		-2,					RTYPE_VAULT,	1	},

		{ NOTHING, -2, -2, 0 }
		};


/* determines if a room/building stores stuff */
bool STORE_BUILDING(room_rnum room) {
	int i;

	for (i = 0; storage_data[i].vnum != NOTHING; i++)
		if (BUILDING_TYPE(room) == storage_data[i].building_type || ROOM_TYPE(room) == storage_data[i].room_type)
			return TRUE;

	return FALSE;
	}


/* find a stored resource */
struct empire_storage_data *find_stored_resource(int emp, obj_vnum vnum) {
	struct empire_storage_data *store;

	for (store = empire[emp].store; store; store = store->next)
		if (store->vnum == vnum)
			return store;
	return NULL;
	}


/* store an object to an empire */
int store_resource(Creature ch, int emp, Object obj) {
	struct empire_storage_data *store;
	int amt = 1;

	/* skins have a special amount */
	if (GET_OBJ_VNUM(obj) == o_SKIN)
		amt = GET_OBJ_VAL(obj, 0);

	/* find/create a storage slot */
	if (!(store = find_stored_resource(emp, GET_OBJ_VNUM(obj)))) {
		CREATE(store, struct empire_storage_data, 1);
		store->next = empire[emp].store;
		empire[emp].store = store;

		store->vnum = GET_OBJ_VNUM(obj);
		}

	/* store the object */
	store->amount += amt;

	act("You store $p.", FALSE, ch, obj, 0, TO_CHAR);
	act("$n stores $p.", TRUE, ch, obj, 0, TO_ROOM);
	extract_obj(obj);
	return 1;
	}


/* remove a resource */
bool retrieve_resource(Creature ch, int emp, int loc) {
	struct empire_storage_data *store, *temp;
	Object obj;

	if (!(store = find_stored_resource(emp, storage_data[loc].vnum)))
		return FALSE;

	obj = read_object(storage_data[loc].vnum, VIRTUAL);

	if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch)) {
		msg_to_char(ch, "Your arms are full.\r\n");
		extract_obj(obj);
		return FALSE;
		}

	if (GET_OBJ_VNUM(obj) == o_SKIN) {
		GET_OBJ_VAL(obj, 0) = MIN(100, store->amount);
		store->amount -= GET_OBJ_VAL(obj, 0);
		}
	else
		store->amount -= 1;

	/* remove the storage entry it it's low */
	if (store->amount <= 0) {
		REMOVE_FROM_LIST(store, empire[emp].store, next);
		}

	obj_to_char(obj, ch);
	act("You retrieve $p.", FALSE, ch, obj, 0, TO_CHAR);
	act("$n retrieves $p.", TRUE, ch, obj, 0, TO_ROOM);
	return TRUE;
	}


/* This is always called by do_inventory */
void inventory_store_building(Creature ch) {
	int i, e;
	bool found = 0;
	struct empire_storage_data *store;

	/* Must be in an empire */
	if ((e = real_empire(GET_LOYALTY(ch))) < 0)
		return;

	msg_to_char(ch, "\r\nStored here:\r\n");

	for (i = 0; storage_data[i].vnum != NOTHING; i++) {
		if (BUILDING_TYPE(ch->in_room) != storage_data[i].building_type && ROOM_TYPE(ch->in_room) != storage_data[i].room_type)
			continue;

		if (!(store = find_stored_resource(e, storage_data[i].vnum)))
			continue;

		msg_to_char(ch, "(%4d) %s\r\n", store->amount, GET_OBJ_NAME_BY_PROTO(real_object(store->vnum)));
		found = TRUE;
		}

	if (!found)
		msg_to_char(ch, " Nothing.\r\n");
	}


ACMD(do_store) {
	struct empire_storage_data *store;
	Object obj, next_obj;
	int count = 0, total = 1, done = 0, i, dotmode, emp;
	bool full = 0;

	if (!IS_COMPLETE(ch->in_room)) {
		msg_to_char(ch, "You'll need to finish the building first.\r\n");
		return;
		}

	if ((emp = real_empire(GET_LOYALTY(ch))) < 0) {
		msg_to_char(ch, "You can't store or retrieve resources unless you're a member of an empire.\r\n");
		return;
		}

	two_arguments(argument, arg, buf);

	/* This goes first because I want it to move buf to arg */
	if (*arg && is_number(arg)) {
		total = atoi(arg);
		if (total < 1) {
			msg_to_char(ch, "You have to store at least 1.\r\n");
			return;
			}
		strcpy(arg, buf);
		}

	if (!*arg) {
		msg_to_char(ch, "What would you like to store?\r\n");
		return;
		}

	dotmode = find_all_dots(arg);

	if (dotmode == FIND_ALL) {
		if (!ch->carrying) {
			send_to_char("You don't seem to be carrying anything.\r\n", ch);
			return;
			}
		for (obj = ch->carrying; obj; obj = next_obj) {
			next_obj = obj->next_content;

			/* match room/building type and obj vnum to an entry */
			for (i = 0; storage_data[i].vnum != NOTHING; i++) {
				if (BUILDING_TYPE(ch->in_room) != storage_data[i].building_type && ROOM_TYPE(ch->in_room) != storage_data[i].room_type)
					continue;
				if (GET_OBJ_VNUM(obj) == storage_data[i].vnum)
					break;
				}

			if (storage_data[i].vnum == NOTHING)
				continue;

			if ((store = find_stored_resource(emp, storage_data[i].vnum)))
				if (store->amount >= 100000) {
					full = 1;
					continue;
					}

			done += store_resource(ch, emp, obj);
			}
		if (!done) {
			if (full)
				msg_to_char(ch, "It's full.\r\n");
			else
				msg_to_char(ch, "You don't have anything that can be stored here.\r\n");
			}
		}
	else {
		if (!*arg) {
			msg_to_char(ch, "What do you want to store all of?\r\n");
			return;
			}
		if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
			msg_to_char(ch, "You don't seem to have any %ss.\r\n", arg);
			return;
			}
		while (obj && (dotmode == FIND_ALLDOT || count < total)) {
			next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);

			/* match room/building type and obj vnum to an entry */
			for (i = 0; storage_data[i].vnum != NOTHING; i++) {
				if (BUILDING_TYPE(ch->in_room) != storage_data[i].building_type && ROOM_TYPE(ch->in_room) != storage_data[i].room_type)
					continue;
				if (GET_OBJ_VNUM(obj) == storage_data[i].vnum)
					break;
				}

			if (storage_data[i].vnum == NOTHING) {
				obj = next_obj;
				continue;
				}

			if ((store = find_stored_resource(emp, storage_data[i].vnum)))
				if (store->amount >= 100000) {
					full = 1;
					obj = next_obj;
					continue;
					}

			done += store_resource(ch, emp, obj);
			count++;
			obj = next_obj;
			}
		if (!done) {
			if (full)
				msg_to_char(ch, "It's full.\r\n");
			else
				msg_to_char(ch, "You can't store that here!\r\n");
			}
		}

	/* save the empire */
	save_empire(emp);
	read_empire_territory();
	}


ACMD(do_retrieve) {
	struct empire_storage_data *store;
	Object obj;
	int count = 0, total = 1, i = 0, emp;
	bool found = 0, full = 0;

	if (!STORE_BUILDING(ch->in_room)) {
		msg_to_char(ch, "Nothing is stored here!\r\n");
		return;
		}
	if (!IS_COMPLETE(ch->in_room)) {
		msg_to_char(ch, "You'll need to finish the building first.\r\n");
		return;
		}
	if ((emp = real_empire(GET_LOYALTY(ch))) < 0) {
		msg_to_char(ch, "You can't store or retrieve resources unless you're a member of an empire.\r\n");
		return;
		}
	if (!CAN_USE_ROOM(ch, ch->in_room, 0)) {
		msg_to_char(ch, "I don't think they'd appreciate you borrowing their resources.\r\n");
		return;
		}

	two_arguments(argument, arg, buf);

	if (*arg && is_number(arg)) {
		total = atoi(arg);
		if (total < 1) {
			msg_to_char(ch, "You have to retrieve at least 1.\r\n");
			return;
			}
		strcpy(arg, buf);
		}

	if (!*arg) {
		msg_to_char(ch, "What would you like to retrieve?\r\n");
		return;
		}

	/* they hit "ret all" */
	if (!str_cmp(arg, "all")) {
		for (i = 0; storage_data[i].vnum != NOTHING; i++) {
			if (BUILDING_TYPE(ch->in_room) != storage_data[i].building_type && ROOM_TYPE(ch->in_room) != storage_data[i].room_type)
				continue;

			if (!(store = find_stored_resource(emp, storage_data[i].vnum)))
				continue;

			switch (storage_data[i].spec) {
				case 1:
					if (GET_RANK(ch) < empire[emp].priv[PRIV_WITHDRAW]) {
						msg_to_char(ch, "You can't withdraw that!\r\n");
						return;
						}
					break;
				}

			/* retrieve as much as possible.. */
			while (store->amount > 0) {
				if (retrieve_resource(ch, emp, i))
					count++;
				else {
					full = 1;
					break;
					}
				}
			}
		}		
	else {
		for (i = 0; storage_data[i].vnum != NOTHING; i++) {
			if (BUILDING_TYPE(ch->in_room) != storage_data[i].building_type && ROOM_TYPE(ch->in_room) != storage_data[i].room_type)
				continue;

			/* never mind if there aren't even any stored */
			if (!(store = find_stored_resource(emp, storage_data[i].vnum)))
				continue;

			obj = read_object(storage_data[i].vnum, VIRTUAL);
			if (isname(arg, obj->name)) {
				extract_obj(obj);
				found = 1;

				switch (storage_data[i].spec) {
					case 1:
						if (GET_RANK(ch) < empire[emp].priv[PRIV_WITHDRAW]) {
							msg_to_char(ch, "You can't withdraw that!\r\n");
							return;
							}
						break;
					}

				/* found it!  retrive now! */
				while (count < total && store->amount > 0) {
					if (retrieve_resource(ch, emp, i))
						count++;
					else {
						full = 1;
						break;
						}
					}

				break;
				}
			extract_obj(obj);
			}

		if (!found) {
			msg_to_char(ch, "Nothing like that is stored here!\r\n");
			return;
			}
		}

	if (count == 0 && !full)
		msg_to_char(ch, "There is nothing stored here!\r\n");

	/* save the empire */
	save_empire(emp);
	read_empire_territory();
	}


/* table for lighting */
obj_vnum light_list[][2] = {
	{ o_STICK,		o_TORCH			},
	{ o_HANDLE,		o_TORCH			},
	{ o_TREE,		o_FIRE			},
	{ o_LOG,		o_FIRE			},
	{ o_CATAPULT,	o_BONFIRE		},
	{ o_CART,		o_BONFIRE		},
	{ o_CARRIAGE,	o_BONFIRE		},
	{ o_WAGON,		o_BONFIRE		},
	{ o_CHAIR,		o_FIRE			},
	{ o_BENCH,		o_FIRE			},
	{ o_TABLE,		o_FIRE			},
	{ o_STOOL,		o_FIRE			},
	{ o_ARROW,		o_FIRE_ARROW	},
	{ o_CANDLE,		o_CANDLE_LIT	},
	{ o_LANTERN,	o_LANTERN_LIT	},

	{ NOTHING,		NOTHING		}
	};


/* returns the table entry if it can be lit, or -1 */
int can_light(Object obj) {
	int i;

	for (i = 0; light_list[i][0] != NOTHING; i++)
		if (GET_OBJ_VNUM(obj) == light_list[i][0])
			return i;

	return -1;
	}


/* returns the lighted version of the object, which is given */
Object light_obj(Object obj, int list_entry) {
	Creature ch = NULL;
	Object o, next_o;
	bool to_char = TRUE;
	room_rnum to_room;

	if ((to_room = obj->in_room) != NOWHERE)
		to_char = FALSE;
	else if (!(ch = obj->carried_by))
		return NULL;

	/* Empty the object */
	for (o = obj->contains; o; o = next_o) {
		next_o = o->next_content;
		if (GET_OBJ_MATERIAL(o) == ITEM_MAT_WOOD || GET_OBJ_MATERIAL(o) == ITEM_MAT_FLESH)
			extract_obj(o);
		else if (to_char)
			obj_to_char(o, ch);
		else
			obj_to_room(o, to_room);
		}

	extract_obj(obj);

	obj = read_object(light_list[list_entry][1], VIRTUAL);

	if (CAN_WEAR(obj, ITEM_WEAR_TAKE) && to_char)
		obj_to_char(obj, ch);
	else
		obj_to_room(obj, to_room);

	return obj;
	}


ACMD(do_light) {
	Object obj, flint;
	int i;

	one_argument(argument, arg);

	for (flint = ch->carrying; flint; flint = flint->next_content)
		if (GET_OBJ_VNUM(flint) == o_FLINT_SET && CAN_SEE_OBJ(ch, flint))
			break;

	if (!*arg)
		msg_to_char(ch, "Light what?\r\n");
	else if (!flint)
		msg_to_char(ch, "You don't have a flint set to light that with.\r\n");
	else if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying)) && !(obj = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents)))
		msg_to_char(ch, "You don't have a %s.\r\n", arg);
	else if ((i = can_light(obj)) == NOTHING)
		msg_to_char(ch, "You can't light that!\r\n");
	else {
		act("You strike $p and light $P.", FALSE, ch, flint, obj, TO_CHAR);
		act("$n strikes $p and lights $P.", FALSE, ch, flint, obj, TO_ROOM);

		light_obj(obj, i);
		}
	}