SmaugWizard/Backup/
SmaugWizard/Backup/L/
SmaugWizard/Boards/
SmaugWizard/Building/
SmaugWizard/Corpses/
SmaugWizard/Councils/
SmaugWizard/Deity/
SmaugWizard/Gods/
SmaugWizard/MudProgs/
SmaugWizard/Player/L/
SmaugWizard/Src/
SmaugWizard/Src/res/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |				*
 * -----------------------------------------------------------|   \\._.//	*
 * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version)   |   (0...0)	*
 * -----------------------------------------------------------|    ).:.(	*
 * SMAUG (C) 1994, 1995, 1996 by Derek Snider                 |    {o o}	*
 * -----------------------------------------------------------|   / ' ' \	*
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |~'~.VxvxV.~'~*
 * Scryn, Swordbearer, Rennard, Tricops, and Gorog.           |				*
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe.    *
 ****************************************************************************/

#include	"stdafx.h"
#include	"smaug.h"
#include	"bitvector.h"
#include	"SysData.h"
#include	"skill.h"
#include	"objects.h"
#include	"rooms.h"
#include	"deity.h"
#include	"Exits.h"
#include	"SmaugFiles.h"
#include	"descriptor.h"
#include	"character.h"

// double sqrt (double x);

// External functions
void    show_list_to_char (CObjData *list, CCharacter *ch,
				BOOL fShort, BOOL fShowNothing);
// Local functions.
void	get_obj (CCharacter *ch, CObjData *obj, CObjData *container);
BOOL	remove_obj (CCharacter *ch, int iWear, BOOL fReplace);
void	wear_obj (CCharacter *ch, CObjData *obj, BOOL fReplace,
			short wear_bit);


// how resistant an object is to damage				-Thoric
short get_obj_resistance (CObjData *obj)
{
    short resist;

    resist = number_fuzzy (MAX_ITEM_IMPACT);

    /* magical items are more resistant */
    if (obj->IsMagic ())
      resist += number_fuzzy (12);
    /* metal objects are definately stronger */
    if (obj->IsMetal ())
      resist += number_fuzzy (5);
    /* organic objects are most likely weaker */
    if (obj->IsOrganic ())
      resist -= number_fuzzy (5);
    /* blessed objects should have a little bonus */
    if (obj->IsBlessed ())
      resist += number_fuzzy (5);
    /* lets make store inventory pretty tough */
    if (obj->IsInventory ())
      resist += 20;

    /* okay... let's add some bonus/penalty for item level... */
    resist +=  (obj->level / 10) - 2;

    /* and lasty... take armor or weapon's condition into consideration */
    if (obj->item_type == ITEM_ARMOR || obj->item_type == ITEM_WEAPON)
      resist +=  (obj->value[0] / 2) - 2;

    return URANGE (10, resist, 99);
}


void get_obj (CCharacter *ch, CObjData *obj, CObjData *container)
{
	int			weight;

	if (! obj->CanWear (ITEM_TAKE)
	  && (ch->GetLevel () < SysData.GetObjNoTakeLevel)) {
		ch->SendText ("You can't take that.\n\r");
		return;
	}

	if (obj->IsPrototype () && ! can_take_proto (ch)) {
		ch->SendText ("A godly force prevents you from getting close to it.\n\r");
		return;
	}

	if (ch->carry_number + get_obj_number (obj) > ch->GetMaxItems ()) {
		act (AT_PLAIN, "$d: you can't carry that many items.",
			ch, NULL, obj->GetName (), TO_CHAR);
		return;
	}

	if (obj->IsCovering ())
		weight = obj->weight;
	else
		weight = get_obj_weight (obj);

	if (ch->GetCarryWeight () + weight > can_carry_w (ch)) {
		act (AT_PLAIN, "$d: you can't carry that much weight.",
			ch, NULL, obj->GetName (), TO_CHAR);
		return;
	}

	if (container) {
		act (AT_ACTION, container->IsCovering () ? 
			"You get $p from beneath $P." : "You get $p from $P",
			ch, obj, container, TO_CHAR);
		act (AT_ACTION, container->IsCovering () ?
			"$n gets $p from beneath $P." : "$n gets $p from $P",
			ch, obj, container, TO_ROOM);
		obj_from_obj (obj);
	} else {
		act (AT_ACTION, "You get $p.", ch, obj, container, TO_CHAR);
		act (AT_ACTION, "$n gets $p.", ch, obj, container, TO_ROOM);
		obj_from_room (obj);
	}

	// Clan storeroom checks
	if (ch->GetInRoom ()->IsClanStoreRoom () 
	  && (!container || container->carried_by == NULL)) {
		POSITION	pos = ClanList.GetHeadPosition ();
		while (pos) {
			CClanData	*clan = ClanList.GetNext (pos);
			if (clan->storeroom == ch->GetInRoom ()->vnum)
				clan->SaveStoreroom (ch);
		}
	}

	if (obj->item_type != ITEM_CONTAINER)
		check_for_trap (ch, obj, TRAP_GET);

	if (char_died (ch))
		return;

	if (obj->item_type == ITEM_MONEY) {
		ch->AddGold (obj->value[0]);
		extract_obj (obj);
	}
	else obj = obj_to_char (obj, ch);

	if (char_died (ch) || obj_extracted (obj))
		return;

	oprog_get_trigger (ch, obj);
}


void do_get (CCharacter *ch, char *argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	CObjData	*obj;
	CObjData	*container;
	short		number;
	BOOL		found;

    argument = one_argument (argument, arg1);
    if (is_number (arg1))
    {
	number = atoi (arg1);
	if (number < 1)
	{
	    ch->SendText ("That was easy...\n\r");
	    return;
	}
	if ((ch->carry_number + number) > ch->GetMaxItems ())
	{
	    ch->SendText ("You can't carry that many.\n\r");
	    return;
	}
	argument = one_argument (argument, arg1);
    }
    else
	number = 0;
    argument = one_argument (argument, arg2);
    /* munch optional words */
    if (!str_cmp (arg2, "from") && argument[0] != '\0')
	argument = one_argument (argument, arg2);

    /* Get type. */
    if (arg1[0] == '\0')
    {
	ch->SendText ("Get what?\n\r");
	return;
    }

    if (ms_find_obj (ch))
	return;

    if (arg2[0] == '\0')
    {
	if (number <= 1 && str_cmp (arg1, "all") && str_prefix ("all.", arg1))
	{
	    /* 'get obj' */
	    obj = get_obj_list (ch, arg1, ch->GetInRoom ()->GetContentList ());
	    if (!obj)
	    {
		act (AT_PLAIN, "I see no $T here.", ch, NULL, arg1, TO_CHAR);
		return;
	    }
	    separate_obj (obj);
	    get_obj (ch, obj, NULL);
	    if (char_died (ch))
			return;
	    if (SysData.IsSaveOnGet ())
			save_char_obj (ch);
	} else {
	    short cnt = 0;
	    BOOL fAll;
	    char *chk;

	    if (ch->GetInRoom ()->IsDonationRoom ())
	    {
		ch->SendText ("The gods frown upon such a display of greed!\n\r");
		return;
	    }
	    if (!str_cmp (arg1, "all"))
		fAll = TRUE;
	    else
		fAll = FALSE;
	    if (number > 1)
		chk = arg1;
	    else
		chk = &arg1[4];
	    /* 'get all' or 'get all.obj' */
	    found = FALSE;
		POSITION	Rpos = ch->GetInRoom ()->GetHeadContentPos ();
		while (obj = ch->GetInRoom ()->GetNextContent (Rpos)) {
			if ((fAll || nifty_is_name (chk, obj->GetName ()))
			  && can_see_obj (ch, *obj)) {
				found = TRUE;
				if (number && (cnt + obj->count) > number)
					split_obj (obj, number - cnt);
				cnt += obj->count;
				get_obj (ch, obj, NULL);
				if (char_died (ch)
				  || ch->carry_number >= ch->GetMaxItems ()
				  || ch->GetCarryWeight () >= can_carry_w (ch)
				  || (number && cnt >= number)) {
					if (SysData.IsSaveOnGet () && !char_died (ch))
						save_char_obj (ch);
					return;
				}
			}
		}

	    if (!found)
	    {
		if (fAll)
		  ch->SendText ("I see nothing here.\n\r");
		else
		  act (AT_PLAIN, "I see no $T here.", ch, NULL, chk, TO_CHAR);
	    }
	    else if (SysData.IsSaveOnGet ())
			save_char_obj (ch);
	}
    }
    else
    {
	/* 'get ... container' */
	if (!str_cmp (arg2, "all") || !str_prefix ("all.", arg2))
	{
	    ch->SendText ("You can't do that.\n\r");
	    return;
	}

	if ((container = get_obj_here (ch, arg2)) == NULL)
	{
	    act (AT_PLAIN, "I see no $T here.", ch, NULL, arg2, TO_CHAR);
	    return;
	}

	switch  (container->item_type)
	{
	default:
	    if (! container->IsCovering ())
	    {
		ch->SendText ("That's not a container.\n\r");
		return;
	    }
	    if (ch->GetCarryWeight () + container->weight > can_carry_w (ch))
	    {
		ch->SendText ("It's too heavy for you to lift.\n\r");
		return;
	    }
	    break;

	case ITEM_CONTAINER:
	case ITEM_CORPSE_NPC:
	    break;

	case ITEM_CORPSE_PC:
	    {
		char name[MAX_INPUT_LENGTH];
		CCharacter *gch;
		const char *pd;

		if (ch->IsNpc ())
		{
		    ch->SendText ("You can't do that.\n\r");
		    return;
		}

		pd = container->GetShortDescr ();
		pd = one_argument (pd, name);
		pd = one_argument (pd, name);
		pd = one_argument (pd, name);
		pd = one_argument (pd, name);
		
		if (container->IsClanCorpse ()
		&&  !ch->IsNpc () &&  (get_timer (ch, TIMER_PKILLED) > 0)
		&& str_cmp (name, ch->GetName ()))
		{
		   ch->SendText ("You cannot loot from that corpse...yet.\n\r");
		   return;
		}

		if (container->IsClanCorpse ()
		&&  !ch->IsNpc () && ch->IsPkiller ())
		   break;
		
		if (str_cmp (name, ch->GetName ()) && !ch->IsImmortal ())
		{
		    BOOL fGroup;

		    fGroup = FALSE;
		    for (gch = first_char; gch; gch = gch->GetNext ())
		    {
			if (!gch->IsNpc ()
			&&   is_same_group (ch, gch)
			&&   !str_cmp (name, gch->GetName ()))
			{
			    fGroup = TRUE;
			    break;
			}
		    }

		    if (!fGroup)
		    {
			ch->SendText ("That's someone else's corpse.\n\r");
			return;
		    }
		}
	    }
	}

	if (! container->IsCovering ()
	&&    IS_SET (container->value[1], CONT_CLOSED))
	{
	    act (AT_PLAIN, "The $d is closed.", ch, NULL, container->GetName (), TO_CHAR);
	    return;
	}

	if (number <= 1 && str_cmp (arg1, "all") && str_prefix ("all.", arg1))
	{
	    /* 'get obj container' */
	    obj = get_obj_list (ch, arg1, container->GetContentList ());
	    if (!obj)
	    {
		act (AT_PLAIN, container->IsCovering () ?
			"I see nothing like that beneath the $T." :
			"I see nothing like that in the $T.",
			ch, NULL, arg2, TO_CHAR);
		return;
	    }
	    separate_obj (obj);
	    get_obj (ch, obj, container);

	    check_for_trap (ch, container, TRAP_GET);
	    if (char_died (ch))
	      return;
	    if (SysData.IsSaveOnGet ())
			save_char_obj (ch);
	}
	else
	{
	    int cnt = 0;
	    BOOL fAll;
	    char *chk;

	    /* 'get all container' or 'get all.obj container' */
	    if (container->IsDonation ())
	    {
		ch->SendText ("The gods frown upon such an act of greed!\n\r");
		return;
	    }
	    if (!str_cmp (arg1, "all"))
		fAll = TRUE;
	    else
		fAll = FALSE;
	    if (number > 1)
		chk = arg1;
	    else
		chk = &arg1[4];
	    found = FALSE;
		POSITION	Cpos = container->GetHeadContentPos ();
		while (obj = container->GetNextContent (Cpos)) {
			if ((fAll || nifty_is_name (chk, obj->GetName ()))
			  && can_see_obj (ch, *obj)) {
				found = TRUE;
				if (number && (cnt + obj->count) > number)
					split_obj (obj, number - cnt);
				cnt += obj->count;
				get_obj (ch, obj, container);
				if (char_died (ch)
					|| ch->carry_number >= ch->GetMaxItems ()
					|| ch->GetCarryWeight () >= can_carry_w (ch)
					|| (number && cnt >= number))
						return;
			}
		}

	    if (!found)
	    {
		if (fAll)
		  act (AT_PLAIN, container->IsCovering () ?
			"I see nothing beneath the $T." :
			"I see nothing in the $T.",
			ch, NULL, arg2, TO_CHAR);
		else
		  act (AT_PLAIN, container->IsCovering () ?
			"I see nothing like that beneath the $T." :
			"I see nothing like that in the $T.",
			ch, NULL, arg2, TO_CHAR);
	    }
	    else
	      check_for_trap (ch, container, TRAP_GET);
	    if (char_died (ch))
		return;
	    if (found && (SysData.IsSaveOnGet ()))
		save_char_obj (ch);
	}
    }
    return;
}


void do_put (CCharacter *ch, char *argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	CObjData	*container;
	CObjData	*obj;
	short		count;
	int			number;
	BOOL		save_char = FALSE;

	argument = one_argument (argument, arg1);
	if (is_number (arg1)) {
		number = atoi (arg1);
		if (number < 1) {
			ch->SendText ("That was easy...\n\r");
			return;
		}
		argument = one_argument (argument, arg1);
	}
	else number = 0;

	argument = one_argument (argument, arg2);

	// munch optional words
	if ((!str_cmp (arg2, "into") || !str_cmp (arg2, "inside")
		|| !str_cmp (arg2, "in")) && argument [0] != '\0')
			argument = one_argument (argument, arg2);

	if (arg1 [0] == '\0' || arg2 [0] == '\0') {
		ch->SendText ("Put what in what?\n\r");
		return;
	}

	if (ms_find_obj (ch))
		return;

	if (! str_cmp (arg2, "all") || ! str_prefix ("all.", arg2)) {
		ch->SendText ("You can't do that.\n\r");
		return;
	}

	if ((container = get_obj_here (ch, arg2)) == NULL) { 
		act (AT_PLAIN, "I see no $T here.", ch, NULL, arg2, TO_CHAR);
		return;
	}

	if (! container->carried_by && (SysData.IsSaveOnPut ()))
		save_char = TRUE;

	if (container->IsCovering ()) {
		if (ch->GetCarryWeight () + container->weight > can_carry_w (ch)) {
			ch->SendText ("It's too heavy for you to lift.\n\r");
			return;
		}
	} else {
		if (container->item_type != ITEM_CONTAINER) {
			ch->SendText ("That's not a container.\n\r");
			return;
		}

		if (IS_SET (container->value[1], CONT_CLOSED)) {
			act (AT_PLAIN, "The $d is closed.", ch, NULL,
				container->GetName (), TO_CHAR);
			return;
		}
	}

	if (number <= 1 && str_cmp (arg1, "all") && str_prefix ("all.", arg1)) {
		// 'put obj container'
		if ((obj = get_obj_carry (ch, arg1)) == NULL) {
			ch->SendText ("You do not have that item.\n\r");
			return;
		}

		if (obj == container) {
			ch->SendText ("You can't fold it into itself.\n\r");
			return;
		}

		if (!can_drop_obj (ch, obj)) {
			ch->SendText ("You can't let go of it.\n\r");
			return;
		}

		if ((container->IsCovering ()
		  && (get_obj_weight (obj) / obj->count)
		  > ((get_obj_weight (container) / container->count)
		  - container->weight))) {
			ch->SendText ("It won't fit under there.\n\r");
			return;
		}

		if ((get_obj_weight (obj) / obj->count)
		  + (get_obj_weight (container) / container->count)
		  > container->value [0]) {
			ch->SendText ("It won't fit.\n\r");
			return;
		}

		separate_obj (obj);
		separate_obj (container);
		obj_from_char (obj);
		obj = obj_to_obj (obj, container);
		check_for_trap  (ch, container, TRAP_PUT);

		if (char_died (ch))
			return;

		count = obj->count;
		obj->count = 1;
		act (AT_ACTION, container->IsCovering ()
			? "$n hides $p beneath $P." : "$n puts $p in $P.",
			ch, obj, container, TO_ROOM);
		act (AT_ACTION, container->IsCovering ()
			? "You hide $p beneath $P." : "You put $p in $P.",
			ch, obj, container, TO_CHAR);
		obj->count = count;

		if (save_char)
			save_char_obj (ch);

		// Clan storeroom check
		if (ch->GetInRoom ()->IsClanStoreRoom () 
		  && container->carried_by == NULL) {
			POSITION	pos = ClanList.GetHeadPosition ();
			while (pos) {
				CClanData	*clan = ClanList.GetNext (pos);
				if (clan->storeroom == ch->GetInRoom ()->vnum)
					ch, clan->SaveStoreroom (ch);
			}
		}
	} else {
		BOOL	found = FALSE;
		int		cnt = 0;
		BOOL	fAll;
		char	*chk;

		if (! str_cmp (arg1, "all"))
			fAll = TRUE;
		else
			fAll = FALSE;

		if (number > 1)
			chk = arg1;
		else
			chk = &arg1 [4];

		separate_obj (container);
		// 'put all container' or 'put all.obj container'
		POSITION	pos = ch->GetHeadCarryPos ();
		while (obj = ch->GetNextCarrying (pos)) {
			if ((fAll || nifty_is_name (chk, obj->GetName ()))
			  && can_see_obj (ch, *obj)
			  && obj->wear_loc == WEAR_NONE
			  && obj != container
			  && can_drop_obj (ch, obj)
			  && get_obj_weight (obj) + get_obj_weight (container)
			  <= container->value [0]) {
				if (number && (cnt + obj->count) > number)
					split_obj (obj, number - cnt);

				cnt += obj->count;
				obj_from_char (obj);
				act (AT_ACTION, "$n puts $p in $P.", ch, obj, container, TO_ROOM);
				act (AT_ACTION, "You put $p in $P.", ch, obj, container, TO_CHAR);
				obj = obj_to_obj (obj, container);
				found = TRUE;

				check_for_trap (ch, container, TRAP_PUT);
				if (char_died (ch))
					return;
				if (number && cnt >= number)
					break;
			}
		}

		// Don't bother to save anything if nothing was dropped   -Thoric
		if (! found) {
			if (fAll)
				act (AT_PLAIN, "You are not carrying anything.",
					ch, NULL, NULL, TO_CHAR);
			else
				act (AT_PLAIN, "You are not carrying any $T.",
					ch, NULL, chk, TO_CHAR);
			return;
		}

		if (save_char)
			save_char_obj (ch);

		// Clan storeroom check
		if (ch->GetInRoom ()->IsClanStoreRoom () 
		  && container->carried_by == NULL) {
			POSITION	pos = ClanList.GetHeadPosition ();
			while (pos) {
				CClanData	*clan = ClanList.GetNext (pos);
				if (clan->storeroom == ch->GetInRoom ()->vnum)
					clan->SaveStoreroom (ch);
			}
		}
	}
}


void do_drop (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CObjData	*obj;
	BOOL		found;
	int			number;

	argument = one_argument (argument, arg);
	if (is_number (arg)) {
		number = atoi (arg);
		if (number < 1) {
			ch->SendText ("That was easy...\n\r");
			return;
		}
		argument = one_argument (argument, arg);
	}
	else number = 0;

	if (arg [0] == '\0') {
		ch->SendText ("Drop what?\n\r");
		return;
	}

	if (ms_find_obj (ch))
		return;

	if (ch->GetInRoom ()->IsNoDrop ()
	  || (! ch->IsNpc () && ch->IsLitterBug ())) {
		set_char_color (AT_MAGIC, ch);
		ch->SendText ("A magical force stops you!\n\r");
		set_char_color (AT_TELL, ch);
		ch->SendText ("Someone tells you, 'No littering here!'\n\r");
		return;
	}

	if (number > 0) {
		// 'drop NNNN coins'
		if (! str_cmp (arg, "coins") || !str_cmp (arg, "coin")) {
			if (ch->GetGold () < number) {
				ch->SendText ("You haven't got that many coins.\n\r");
				return;
			}

			ch->AddGold (-number);

			POSITION	Rpos = ch->GetInRoom ()->GetHeadContentPos ();
			while (obj = ch->GetInRoom ()->GetNextContent (Rpos)) {
				switch (obj->pIndexData->vnum) {
				  case OBJ_VNUM_MONEY_ONE:
					number += 1;
					extract_obj (obj);
					break;

				  case OBJ_VNUM_MONEY_SOME:
					number += obj->value[0];
					extract_obj (obj);
					break;
				}
			}

			act (AT_ACTION, "$n drops some gold.", ch, NULL, NULL, TO_ROOM);
			obj_to_room (create_money (number), ch->GetInRoom ());
			ch->SendText ("OK.\n\r");
			if (SysData.IsSaveOnDrop ())
				save_char_obj (ch);
			return;
		}
	}

	if (number <= 1 && str_cmp (arg, "all") && str_prefix ("all.", arg)) {
		// 'drop obj'
		if ((obj = get_obj_carry (ch, arg)) == NULL) {
			ch->SendText ("You do not have that item.\n\r");
			return;
		}

		if (! can_drop_obj (ch, obj)) {
			ch->SendText ("You can't let go of it.\n\r");
			return;
		}

		separate_obj (obj);
		act (AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM);
		act (AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR);

		obj_from_char (obj);
		obj = obj_to_room (obj, ch->GetInRoom ());
		oprog_drop_trigger  (ch, obj);				// mudprogs

		if (char_died (ch) || obj_extracted (obj))
			return;

		// Clan storeroom saving
		if (ch->GetInRoom ()->IsClanStoreRoom ()) {
			POSITION	pos = ClanList.GetHeadPosition ();
			while (pos) {
				CClanData	*clan = ClanList.GetNext (pos);
				if (clan->storeroom == ch->GetInRoom ()->vnum)
					clan->SaveStoreroom (ch);
			}
		}
	} else {
		int		cnt = 0;
		char	*chk;
		BOOL	fAll;

		if (!str_cmp (arg, "all"))
			fAll = TRUE;
		else
			fAll = FALSE;

		if (number > 1)
			chk = arg;
		else
			chk = &arg[4];

		// 'drop all' or 'drop all.obj'
		if (ch->GetInRoom ()->IsNoDropAll () 
		  || ch->GetInRoom ()->IsClanStoreRoom ()) {
			ch->SendText ("You can't seem to do that here...\n\r");
			return;
		}

		found = FALSE;
		POSITION	pos = ch->GetHeadCarryPos ();
		while (obj = ch->GetNextCarrying (pos)) {
			if ((fAll || nifty_is_name (chk, obj->GetName ()))
			  && can_see_obj (ch, *obj)
			  && obj->wear_loc == WEAR_NONE
			  && can_drop_obj (ch, obj)) {
				found = TRUE;
				if (obj->pIndexData->HasDropProg () && obj->count > 1) {
					++cnt;
					separate_obj (obj);
					obj_from_char (obj);
					if (! pos)
						pos = ch->GetHeadCarryPos ();
				} else {
					if (number &&  (cnt + obj->count) > number)
						split_obj (obj, number - cnt);
					cnt += obj->count;
					obj_from_char (obj);
				}
				act (AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM);
				act (AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR);
				obj = obj_to_room (obj, ch->GetInRoom ());
				oprog_drop_trigger (ch, obj);		// mudprogs
				if (char_died (ch))
					return;
				if (number && cnt >= number)
					break;
			}
		}

		if (! found) {
			if (fAll)
				act (AT_PLAIN, "You are not carrying anything.",
					ch, NULL, NULL, TO_CHAR);
			else
				act (AT_PLAIN, "You are not carrying any $T.",
					ch, NULL, chk, TO_CHAR);
		}
	}
	if (SysData.IsSaveOnDrop ())
	save_char_obj (ch);					// duping protector
}


void do_give (CCharacter *ch, char *argument)
{
    char arg1 [MAX_INPUT_LENGTH];
    char arg2 [MAX_INPUT_LENGTH];
    char buf  [MAX_INPUT_LENGTH];
    CCharacter *victim;
    CObjData  *obj;

    argument = one_argument (argument, arg1);
    argument = one_argument (argument, arg2);
    if (!str_cmp (arg2, "to") && argument[0] != '\0')
	argument = one_argument (argument, arg2);

    if (arg1[0] == '\0' || arg2[0] == '\0')
    {
	ch->SendText ("Give what to whom?\n\r");
	return;
    }

    if (ms_find_obj (ch))
	return;

    if (is_number (arg1))
    {
	/* 'give NNNN coins victim' */
	int amount;

	amount   = atoi (arg1);
	if (amount <= 0
	||  (str_cmp (arg2, "coins") && str_cmp (arg2, "coin")))
	{
	    ch->SendText ("Sorry, you can't do that.\n\r");
	    return;
	}

	argument = one_argument (argument, arg2);
	if (!str_cmp (arg2, "to") && argument[0] != '\0')
	  argument = one_argument (argument, arg2);
	if (arg2[0] == '\0')
	{
	    ch->SendText ("Give what to whom?\n\r");
	    return;
	}

	if ((victim = get_char_room (ch, arg2)) == NULL)
	{
	    ch->SendText ("They aren't here.\n\r");
	    return;
	}

	if (ch->GetGold () < amount)
	{
	    ch->SendText ("Very generous of you, but you haven't got that much gold.\n\r");
	    return;
	}

	ch->AddGold (-amount);
	victim->AddGold (amount);
        strcpy (buf, "$n gives you ");
        strcat (buf, arg1);
        strcat (buf,  (amount > 1) ? " coins." : " coin.");

	act (AT_ACTION, buf, ch, NULL, victim, TO_VICT   );
	act (AT_ACTION, "$n gives $N some gold.",  ch, NULL, victim, TO_NOTVICT);
	act (AT_ACTION, "You give $N some gold.",  ch, NULL, victim, TO_CHAR   );
	ch->SendText ("OK.\n\r");
	mprog_bribe_trigger (victim, ch, amount);
	if (SysData.IsSaveOnGive () && !char_died (ch))
	  save_char_obj (ch);
	if (SysData.IsSaveOnReceive () && !char_died (victim))
	  save_char_obj (victim);
	return;
    }

    if ((obj = get_obj_carry (ch, arg1)) == NULL)
    {
	ch->SendText ("You do not have that item.\n\r");
	return;
    }

    if (obj->wear_loc != WEAR_NONE)
    {
	ch->SendText ("You must remove it first.\n\r");
	return;
    }

    if ((victim = get_char_room (ch, arg2)) == NULL)
    {
	ch->SendText ("They aren't here.\n\r");
	return;
    }

    if (!can_drop_obj (ch, obj))
    {
	ch->SendText ("You can't let go of it.\n\r");
	return;
    }

    if (victim->carry_number +  (get_obj_number (obj)/obj->count) > victim->GetMaxItems ())
    {
	act (AT_PLAIN, "$N has $S hands full.", ch, NULL, victim, TO_CHAR);
	return;
    }

    if (victim->GetCarryWeight () +  (get_obj_weight (obj)/obj->count) > can_carry_w (victim))
    {
	act (AT_PLAIN, "$N can't carry that much weight.", ch, NULL, victim, TO_CHAR);
	return;
    }

    if (!can_see_obj (victim, *obj))
    {
	act (AT_PLAIN, "$N can't see it.", ch, NULL, victim, TO_CHAR);
	return;
    }

    if (obj->IsPrototype () && !can_take_proto (victim))
    {
	act (AT_PLAIN, "You cannot give that to $N!", ch, NULL, victim, TO_CHAR);
	return;
    }

    separate_obj (obj);
    obj_from_char (obj);
    act (AT_ACTION, "$n gives $p to $N.", ch, obj, victim, TO_NOTVICT);
    act (AT_ACTION, "$n gives you $p.",   ch, obj, victim, TO_VICT   );
    act (AT_ACTION, "You give $p to $N.", ch, obj, victim, TO_CHAR   );
    obj = obj_to_char (obj, victim);
    mprog_give_trigger (victim, ch, obj);
    if (SysData.IsSaveOnGive () && !char_died (ch))
	save_char_obj (ch);
    if (SysData.IsSaveOnReceive () && !char_died (victim))
	save_char_obj (victim);
    return;
}

/*
 * Damage an object.						-Thoric
 * Affect player's AC if necessary.
 * Make object into scraps if necessary.
 * Send message about damaged object.
 */
obj_ret damage_obj (CObjData *obj)
{
    CCharacter *ch;
    obj_ret objcode;

    ch = obj->carried_by;
    objcode = rNONE;
  
    separate_obj (obj);
    if (ch)
      act (AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_CHAR);
    else
    if (obj->in_room &&  (ch = obj->in_room->first_person) != NULL)
    {
	act (AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_ROOM);
	act (AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_CHAR);
	ch = NULL;
    }

    oprog_damage_trigger (ch, obj);
    if (obj_extracted (obj))
      return global_objcode;

    switch (obj->item_type)
    {
	default:
	  make_scraps (obj);
	  objcode = rOBJ_SCRAPPED;
	  break;
	case ITEM_CONTAINER:
	  if (--obj->value[3] <= 0) 
	  {
		make_scraps (obj);
		objcode = rOBJ_SCRAPPED;
	  }
	  break;
	case ITEM_ARMOR:
	  if (ch && obj->value[0] >= 1)
	    ch->AddArmor (apply_ac (obj, obj->wear_loc));
	  if (--obj->value[0] <= 0)
	  {
	    if (! ch->IsPkiller () && !in_arena (ch))
	    {
		make_scraps (obj);
		objcode = rOBJ_SCRAPPED;
	    }
	    else
		obj->value[0] = 1;
	  }
	  else
	  if (ch && obj->value[0] >= 1)
	    ch->AddArmor (-apply_ac (obj, obj->wear_loc));
	  break;
	case ITEM_WEAPON:
	  if (--obj->value[0] <= 0)
	  {
	     if (! ch->IsPkiller () && !in_arena (ch))
	     {
		make_scraps (obj);
		objcode = rOBJ_SCRAPPED;
	     }
	     else
		obj->value[0] = 1;
	  }
	  break;
    }
    return objcode;
}


/*
 * Remove an object.
 */
BOOL remove_obj (CCharacter *ch, int iWear, BOOL fReplace)
{
    CObjData *obj, *tmpobj;

    if ((obj = get_eq_char (ch, iWear)) == NULL)
	return TRUE;

    if (!fReplace
    &&   ch->carry_number + get_obj_number (obj) > ch->GetMaxItems ())
    {
	act (AT_PLAIN, "$d: you can't carry that many items.",
	    ch, NULL, obj->GetName (), TO_CHAR);
	return FALSE;
    }

    if (!fReplace)
	return FALSE;

    if (obj->IsNoRemove ())
    {
	act (AT_PLAIN, "You can't remove $p.", ch, obj, NULL, TO_CHAR);
	return FALSE;
    }

    if (obj == get_eq_char (ch, WEAR_WIELD)
    &&  (tmpobj = get_eq_char (ch, WEAR_DUAL_WIELD)) != NULL)
       tmpobj->wear_loc = WEAR_WIELD;

    unequip_char (ch, obj);

    act (AT_ACTION, "$n stops using $p.", ch, obj, NULL, TO_ROOM);
    act (AT_ACTION, "You stop using $p.", ch, obj, NULL, TO_CHAR);
    oprog_remove_trigger (ch, obj);
    return TRUE;
}


// See if char could be capable of dual-wielding		-Thoric
BOOL could_dual (CCharacter *ch)
{
	if (ch->IsNpc ())
		return TRUE;
	if (ch->GetPcData ()->learned [gsn_dual_wield])
		return TRUE;

	return FALSE;
}

/*
 * See if char can dual wield at this time			-Thoric
 */
BOOL can_dual (CCharacter *ch)
{
   if (!could_dual (ch))
     return FALSE;

   if (get_eq_char (ch, WEAR_DUAL_WIELD))
   {
	ch->SendText ("You are already wielding two weapons!\n\r");
	return FALSE;
   }
   if (get_eq_char (ch, WEAR_SHIELD))
   {
	ch->SendText ("You cannot dual wield while holding a shield!\n\r");
	return FALSE;
   }
   if (get_eq_char (ch, WEAR_HOLD))
   {
	ch->SendText ("You cannot dual wield while holding something!\n\r");
	return FALSE;
   }
   return TRUE;
}


// Check to see if there is room to wear another object on this location
// (Layered clothing support)
BOOL can_layer (CCharacter *ch, CObjData *obj, short wear_loc)
{
	CObjData	*otmp;
	short		bitlayers = 0;
	short		objlayers = obj->pIndexData->layers;

	POSITION	pos = ch->GetHeadCarryPos ();
	while (otmp = ch->GetNextCarrying (pos))
		if (otmp->wear_loc == wear_loc)
			if (! otmp->pIndexData->layers)
				return FALSE;
			else
				bitlayers |= otmp->pIndexData->layers;

	if ((bitlayers && !objlayers) || bitlayers > objlayers)
		return FALSE;
	if (!bitlayers || ((bitlayers & ~objlayers) == bitlayers))
		return TRUE;

	return FALSE;
}


// Wear one object.
// Optional replacement of existing objects.
// Big repetitive code, ick.
// Restructured a bit to allow for specifying body location	-Thoric
void wear_obj (CCharacter *ch, CObjData *obj, BOOL fReplace, short wear_bit)
{
	char		buf [MAX_STRING_LENGTH];
	CObjData	*tmpobj;
	short		bit, tmp;

	separate_obj (obj);
	if (ch->GetTrustLevel () < obj->level) {
		sprintf (buf, "You must be level %d to use this object.\n\r",
			obj->level);
		ch->SendText (buf);
		act (AT_ACTION, "$n tries to use $p, but is too inexperienced.",
			ch, obj, NULL, TO_ROOM);
		return;
	}

//	int		Class = ch->GetClass ();
	if (! ch->IsImmortal () && obj->IsAntiClass (ch->GetClass ())) {
		act (AT_MAGIC, "You are forbidden to use that item.", ch, NULL, NULL, TO_CHAR);
		act (AT_ACTION, "$n tries to use $p, but is forbidden to do so.",
		ch, obj, NULL, TO_ROOM);
		return;
	}

	if (wear_bit > -1) {
		bit = wear_bit;
		if (! obj->CanWear (1 << bit)) {
			if (fReplace) {
				switch (1 << bit) {
				  case ITEM_HOLD:
					ch->SendText ("You cannot hold that.\n\r");
					break;
				  case ITEM_WIELD:
				  case ITEM_MISSILE_WIELD:
					ch->SendText ("You cannot wield that.\n\r");
					break;
				  default:
					ch->SendTextf ("You cannot wear that on your %s.\n\r",
						w_flags [bit]);
				}
			}
			return;
		}
	} else {
		for (bit = -1, tmp = 1; tmp < 31; tmp++) {
			if (obj->CanWear (1 << tmp)) {
				bit = tmp;
				break;
			}
		}
	}

	// currently cannot have a light in non-light position
	if (obj->item_type == ITEM_LIGHT) {
		if (! remove_obj (ch, WEAR_LIGHT, fReplace))
			return;
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n holds $p as a light.", ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You hold $p as your light.",  ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_LIGHT);
		oprog_wear_trigger (ch, obj);
		return;
	}

	if (bit == -1) {
		if (fReplace)
			ch->SendText ("You can't wear, wield, or hold that.\n\r");
		return;
	}

	switch  (1 << bit) {
	  default:
		bug ("wear_obj: uknown/unused item_wear bit %d", bit);
		if (fReplace)
			ch->SendText ("You can't wear, wield, or hold that.\n\r");
		return;

	  case ITEM_WEAR_FINGER:
		if (get_eq_char (ch, WEAR_FINGER_L)
			&& get_eq_char (ch, WEAR_FINGER_R)
			&& !remove_obj (ch, WEAR_FINGER_L, fReplace)
			&& !remove_obj (ch, WEAR_FINGER_R, fReplace))
				return;

		if (! get_eq_char (ch, WEAR_FINGER_L)) {
			if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
				act (AT_ACTION, "$n slips $s left finger into $p.",
					ch, obj, NULL, TO_ROOM);
				act (AT_ACTION, "You slip your left finger into $p.",
					ch, obj, NULL, TO_CHAR);
			}
			equip_char (ch, obj, WEAR_FINGER_L);
			oprog_wear_trigger (ch, obj);
			return;
		}

		if (! get_eq_char (ch, WEAR_FINGER_R)) {
			if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
				act (AT_ACTION, "$n slips $s right finger into $p.",
					ch, obj, NULL, TO_ROOM);
				act (AT_ACTION, "You slip your right finger into $p.",
					ch, obj, NULL, TO_CHAR);
			}
			equip_char (ch, obj, WEAR_FINGER_R);
			oprog_wear_trigger (ch, obj);
			return;
		}

		bug ("Wear_obj: no free finger.");
		ch->SendText ("You already wear something on both fingers.\n\r");
		return;

	  case ITEM_WEAR_NECK:
		if (get_eq_char (ch, WEAR_NECK_1) != NULL
			&& get_eq_char (ch, WEAR_NECK_2) != NULL
			&& !remove_obj (ch, WEAR_NECK_1, fReplace)
			&& !remove_obj (ch, WEAR_NECK_2, fReplace))
				return;

		if (! get_eq_char (ch, WEAR_NECK_1)) {
			if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
				act (AT_ACTION, "$n wears $p around $s neck.",
					ch, obj, NULL, TO_ROOM);
				act (AT_ACTION, "You wear $p around your neck.",
					ch, obj, NULL, TO_CHAR);
			}
			equip_char (ch, obj, WEAR_NECK_1);
			oprog_wear_trigger (ch, obj);
			return;
		}

		if (! get_eq_char (ch, WEAR_NECK_2)) {
			if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
				act (AT_ACTION, "$n wears $p around $s neck.",
					ch, obj, NULL, TO_ROOM);
				act (AT_ACTION, "You wear $p around your neck.",
					ch, obj, NULL, TO_CHAR);
			}
			equip_char (ch, obj, WEAR_NECK_2);
			oprog_wear_trigger (ch, obj);
			return;
		}

		bug ("Wear_obj: no free neck.");
		ch->SendText ("You already wear two neck items.\n\r");
		return;

	  case ITEM_WEAR_BODY:
		// if (! remove_obj (ch, WEAR_BODY, fReplace))
		// return;
		if (! can_layer (ch, obj, WEAR_BODY)) {
			ch->SendText ("It won't fit overtop of what you're already wearing.\n\r");
			return;
		}
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n fits $p on $s body.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You fit $p on your body.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_BODY);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_HEAD:
		if (! remove_obj (ch, WEAR_HEAD, fReplace))
			return;
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n dons $p upon $s head.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You don $p upon your head.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_HEAD);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_EYES:
		if (! remove_obj (ch, WEAR_EYES, fReplace))
			return;
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n places $p on $s eyes.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You place $p on your eyes.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_EYES);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_FACE:
		if (! remove_obj (ch, WEAR_FACE, fReplace))
			return;
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n places $p on $s face.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You place $p on your face.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_FACE);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_EARS:
		if (! remove_obj (ch, WEAR_EARS, fReplace))
			return;
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n wears $p on $s ears.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You wear $p on your ears.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_EARS);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_LEGS:
		// if (!remove_obj (ch, WEAR_LEGS, fReplace))
		// return;
		if (! can_layer (ch, obj, WEAR_LEGS)) {
			ch->SendText ("It won't fit overtop of what you're already wearing.\n\r");
			return;
		}
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n slips into $p.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You slip into $p.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_LEGS);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_FEET:
		// if (!remove_obj (ch, WEAR_FEET, fReplace))
		// return;
		if (! can_layer (ch, obj, WEAR_FEET)) {
			ch->SendText ("It won't fit overtop of what you're already wearing.\n\r");
			return;
		}
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n wears $p on $s feet.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You wear $p on your feet.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_FEET);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_HANDS:
		// if (!remove_obj (ch, WEAR_HANDS, fReplace))
		// return;
		if (! can_layer (ch, obj, WEAR_HANDS)) {
			ch->SendText ("It won't fit overtop of what you're already wearing.\n\r");
			return;
		}
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n wears $p on $s hands.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You wear $p on your hands.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_HANDS);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_ARMS:
		// if (!remove_obj (ch, WEAR_ARMS, fReplace))
		// return;
		if (! can_layer (ch, obj, WEAR_ARMS)) {
			ch->SendText ("It won't fit overtop of what you're already wearing.\n\r");
			return;
		}
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n wears $p on $s arms.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You wear $p on your arms.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_ARMS);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_ABOUT:
		// if (!remove_obj (ch, WEAR_ABOUT, fReplace))
		// return;
		if (! can_layer (ch, obj, WEAR_ABOUT)) {
			ch->SendText ("It won't fit overtop of what you're already wearing.\n\r");
			return;
		}
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n wears $p about $s body.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You wear $p about your body.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_ABOUT);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_BACK:
		if (! remove_obj (ch, WEAR_BACK, fReplace))
			return;
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n slings $p on $s back.", ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You sling $p on your back.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_BACK);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_WAIST:
		// if (!remove_obj (ch, WEAR_WAIST, fReplace))
		// return;
		if (! can_layer (ch, obj, WEAR_WAIST)) {
			ch->SendText ("It won't fit overtop of what you're already wearing.\n\r");
			return;
		}
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n wears $p about $s waist.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You wear $p about your waist.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_WAIST);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_WEAR_WRIST:
		if (get_eq_char (ch, WEAR_WRIST_L)
			&& get_eq_char (ch, WEAR_WRIST_R)
			&& !remove_obj (ch, WEAR_WRIST_L, fReplace)
			&& !remove_obj (ch, WEAR_WRIST_R, fReplace))
				return;

		if (! get_eq_char (ch, WEAR_WRIST_L)) {
			if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
				act (AT_ACTION, "$n fits $p around $s left wrist.",
					ch, obj, NULL, TO_ROOM);
				act (AT_ACTION, "You fit $p around your left wrist.",
					ch, obj, NULL, TO_CHAR);
			}
			equip_char (ch, obj, WEAR_WRIST_L);
			oprog_wear_trigger (ch, obj);
			return;
		}

		if (! get_eq_char (ch, WEAR_WRIST_R)) {
			if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
				act (AT_ACTION, "$n fits $p around $s right wrist.",
					ch, obj, NULL, TO_ROOM);
				act (AT_ACTION, "You fit $p around your right wrist.",
					ch, obj, NULL, TO_CHAR);
			}
			equip_char (ch, obj, WEAR_WRIST_R);
			oprog_wear_trigger (ch, obj);
			return;
		}

		bug ("Wear_obj: no free wrist.");
		ch->SendText ("You already wear two wrist items.\n\r");
		return;

	  case ITEM_WEAR_ANKLE:
		if (get_eq_char (ch, WEAR_ANKLE_L)
			&& get_eq_char (ch, WEAR_ANKLE_R)
			&& ! remove_obj (ch, WEAR_ANKLE_L, fReplace)
			&& ! remove_obj (ch, WEAR_ANKLE_R, fReplace))
				return;

		if (! get_eq_char (ch, WEAR_ANKLE_L)) {
			if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
				act (AT_ACTION, "$n fits $p around $s left ankle.",
					ch, obj, NULL, TO_ROOM);
				act (AT_ACTION, "You fit $p around your left ankle.",
					ch, obj, NULL, TO_CHAR);
			}
			equip_char (ch, obj, WEAR_ANKLE_L);
			oprog_wear_trigger (ch, obj);
			return;
		}

		if (! get_eq_char (ch, WEAR_ANKLE_R)) {
			if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
				act (AT_ACTION, "$n fits $p around $s right ankle.",
					ch, obj, NULL, TO_ROOM);
				act (AT_ACTION, "You fit $p around your right ankle.",
					ch, obj, NULL, TO_CHAR);
			}
			equip_char (ch, obj, WEAR_ANKLE_R);
			oprog_wear_trigger (ch, obj);
			return;
		}

		bug ("Wear_obj: no free ankle.");
		ch->SendText ("You already wear two ankle items.\n\r");
		return;

	  case ITEM_WEAR_SHIELD:
		if (get_eq_char (ch, WEAR_DUAL_WIELD)
	      || (get_eq_char (ch, WEAR_WIELD)
		  && get_eq_char (ch, WEAR_MISSILE_WIELD))) {
			ch->SendText ("You can't use a shield AND two weapons!\n\r");
			return;
		}
		if (! remove_obj (ch, WEAR_SHIELD, fReplace))
			return;
		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n uses $p as a shield.", ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You use $p as a shield.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_SHIELD);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_MISSILE_WIELD:
	  case ITEM_WIELD:
		if (! could_dual (ch)) {
			if (! remove_obj (ch, WEAR_MISSILE_WIELD, fReplace))
				return;
			if (! remove_obj (ch, WEAR_WIELD, fReplace))
				return;
			tmpobj = NULL;
		} else {
			if ((tmpobj = get_eq_char (ch, WEAR_WIELD)) != NULL
			  && (get_eq_char (ch, WEAR_MISSILE_WIELD) ||
			  get_eq_char (ch, WEAR_DUAL_WIELD))){
				ch->SendText ("You're already wielding two weapons.\n\r");
				return;
			}
		}

		if (tmpobj) {
			if (can_dual (ch)) {
				if (get_obj_weight (obj) + get_obj_weight (tmpobj)
				  > str_app [ch->GetCurrentStrength ()].wield) {
					ch->SendText ("It is too heavy for you to wield.\n\r");
					return;
				}
				if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
					act (AT_ACTION, "$n dual-wields $p.", ch, obj, NULL, TO_ROOM);
					act (AT_ACTION, "You dual-wield $p.", ch, obj, NULL, TO_CHAR);
				}
				if (1 << bit == ITEM_MISSILE_WIELD)
					equip_char (ch, obj, WEAR_MISSILE_WIELD);
				else
					equip_char (ch, obj, WEAR_DUAL_WIELD);
				oprog_wear_trigger (ch, obj);
			}
			return;
		}

		if (get_obj_weight (obj) > str_app [ch->GetCurrentStrength ()].wield){
			ch->SendText ("It is too heavy for you to wield.\n\r");
			return;
		}

		if (! oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n wields $p.", ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You wield $p.", ch, obj, NULL, TO_CHAR);
		}
	    if (1 << bit == ITEM_MISSILE_WIELD)
			equip_char (ch, obj, WEAR_MISSILE_WIELD);
		else
			equip_char (ch, obj, WEAR_WIELD);
		oprog_wear_trigger (ch, obj);
		return;

	  case ITEM_HOLD:
		if (get_eq_char (ch, WEAR_DUAL_WIELD)
	      || (get_eq_char (ch, WEAR_WIELD)
		  && get_eq_char (ch, WEAR_MISSILE_WIELD))) {
			ch->SendText ("You cannot hold something AND two weapons!\n\r");
			return;
		}
		if (! remove_obj (ch, WEAR_HOLD, fReplace))
			return;
		if (obj->item_type == ITEM_WAND
		  || obj->item_type == ITEM_STAFF
		  || obj->item_type == ITEM_FOOD 
		  || obj->item_type == ITEM_COOK
		  || obj->item_type == ITEM_PILL
		  || obj->item_type == ITEM_POTION
		  || obj->item_type == ITEM_SCROLL
		  || obj->item_type == ITEM_DRINK_CON 
		  || obj->item_type == ITEM_BLOOD
		  || obj->item_type == ITEM_PIPE
		  || obj->item_type == ITEM_HERB
		  || obj->item_type == ITEM_KEY
		  || !oprog_use_trigger (ch, obj, NULL, NULL, NULL)) {
			act (AT_ACTION, "$n holds $p in $s hands.",   ch, obj, NULL, TO_ROOM);
			act (AT_ACTION, "You hold $p in your hands.", ch, obj, NULL, TO_CHAR);
		}
		equip_char (ch, obj, WEAR_HOLD);
		oprog_wear_trigger (ch, obj);
	}
}


void do_wear (CCharacter *ch, char *argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	CObjData	*obj;
	short		wear_bit;

	argument = one_argument (argument, arg1);
	argument = one_argument (argument, arg2);
	if ((! str_cmp (arg2, "on") || ! str_cmp (arg2, "upon")
		|| ! str_cmp (arg2, "around")) && argument [0] != '\0')
			argument = one_argument (argument, arg2);

	if (arg1 [0] == '\0') {
		ch->SendText ("Wear, wield, or hold what?\n\r");
		return;
	}

	if (ms_find_obj (ch))
		return;

	if (! str_cmp (arg1, "all")) {
		POSITION	pos = ch->GetHeadCarryPos ();
		while (obj = ch->GetNextCarrying (pos))
			if (obj->wear_loc == WEAR_NONE && can_see_obj (ch, *obj))
				wear_obj (ch, obj, FALSE, -1);

	} else {

		if ((obj = get_obj_carry (ch, arg1)) == NULL) {
			ch->SendText ("You do not have that item.\n\r");
			return;
		}
		if (arg2 [0] != '\0')
			wear_bit = get_wflag (arg2);
		else
			wear_bit = -1;
		wear_obj (ch, obj, TRUE, wear_bit);
	}
}


void do_remove (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CObjData	*obj, *obj_next;


	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Remove what?\n\r");
		return;
	}

	if (ms_find_obj (ch))
		return;

	if (! str_cmp (arg, "all")) {			// SB Remove all
		POSITION	pos = ch->GetHeadCarryPos ();
		while (obj = ch->GetNextCarrying (pos)) {
			if (obj->wear_loc != WEAR_NONE && can_see_obj  (ch, *obj))
				remove_obj  (ch, obj->wear_loc, TRUE);
		}
		return;
	}

	if ((obj = get_obj_wear (ch, arg)) == NULL) {
		ch->SendText ("You are not using that item.\n\r");
		return;
	}
	if ((obj_next=get_eq_char (ch, obj->wear_loc)) != obj) {
		act (AT_PLAIN, "You must remove $p first.", ch, obj_next, NULL, TO_CHAR);
		return;
	}

	remove_obj (ch, obj->wear_loc, TRUE);
}


void do_bury (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CObjData	*obj;
	BOOL		shovel;
	short		move;

	one_argument (argument, arg);

	if (arg [0] == '\0') {    
		ch->SendText ("What do you wish to bury?\n\r");
		return;
	}

	if (ms_find_obj (ch))
		return;

	shovel = FALSE;
	POSITION	pos = ch->GetHeadCarryPos ();
	while (obj = ch->GetNextCarrying (pos))
		if (obj->item_type == ITEM_SHOVEL) {
			shovel = TRUE;
			break;
		}

	obj = get_obj_list_rev (ch, arg, ch->GetInRoom ()->GetContentList ());
	if (! obj) {
		ch->SendText ("You can't find it.\n\r");
		return;
	}

	separate_obj (obj);
	if (! obj->CanWear (ITEM_TAKE)) {
		if (! obj->IsClanCorpse ()
		  || ch->IsNpc () || ! ch->IsPkiller ()) {	
			act (AT_PLAIN, "You cannot bury $p.", ch, obj, 0, TO_CHAR);
			return;
		}
	}

	switch (ch->GetInRoom ()->sector_type) {
	  case SECT_CITY:
	  case SECT_INSIDE:
		ch->SendText ("The floor is too hard to dig through.\n\r");
		return;
	  case SECT_WATER_SWIM:
	  case SECT_WATER_NOSWIM:
	  case SECT_UNDERWATER:
		ch->SendText ("You cannot bury something here.\n\r");
		return;
	  case SECT_AIR:
		ch->SendText ("What?  In the air?!\n\r");
		return;
	}

	if (obj->weight > (UMAX (5,  (can_carry_w (ch) / 10))) && !shovel) {
		ch->SendText ("You'd need a shovel to bury something that big.\n\r");
		return;
	}

	move = (obj->weight * 50 *  (shovel ? 1 : 5)) / UMAX (1, can_carry_w (ch));
	move = URANGE (2, move, 1000);

	if (move > ch->GetMove ()) {
		ch->SendText (
			"You don't have the energy to bury something of that size.\n\r");
		return;
	}
	ch->AddMove (-move);
	if (obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC)
		adjust_favor (ch, 6, 1);

	act (AT_ACTION, "You solemnly bury $p...", ch, obj, NULL, TO_CHAR);
	act (AT_ACTION, "$n solemnly buries $p...", ch, obj, NULL, TO_ROOM);
	obj->SetBuried ();
	WAIT_STATE (ch, URANGE (10, move / 2, 100));
}


void do_sacrifice (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	char		buf [MAX_STRING_LENGTH];
	CString		Name;
	CObjData	*obj;

    one_argument (argument, arg);

	if (arg [0] == '\0' || !str_cmp (arg, ch->GetName ())) {
		act (AT_ACTION, "$n offers $mself to $s deity, who graciously declines.",
			ch, NULL, NULL, TO_ROOM);
		ch->SendText ("Your deity appreciates your offer and may accept it later.");
		return;
	}

	if (ms_find_obj (ch))
		return;

	obj = get_obj_list_rev (ch, arg, ch->GetInRoom ()->GetContentList ());
	if (! obj) {
		ch->SendText ("You can't find it.\n\r");
		return;
	}

	separate_obj (obj);
	if (! obj->CanWear (ITEM_TAKE)) {
		act (AT_PLAIN, "$p is not an acceptable sacrifice.", ch, obj, 0, TO_CHAR);
		return;
	}

	if (! ch->IsNpc () && ch->GetPcData ()->deity
		&& ch->GetPcData ()->deity->IsValidName ())
			Name = ch->GetPcData ()->deity->GetName ();

	else if (! ch->IsNpc () && ch->IsGuilded () && SysData.pGuildOverseer[0] != '\0') 
		Name = SysData.pGuildOverseer;

	else if (! ch->IsNpc () && ch->GetPcData ()->GetClan ()
		&& ch->GetPcData ()->GetClan ()->deity[0] != '\0')
			Name = ch->GetPcData ()->GetClan ()->deity;

	else Name = SysData.GetSupremeEntity ();

	ch->AddGold (1);
	if (obj->item_type == ITEM_CORPSE_NPC
		|| obj->item_type == ITEM_CORPSE_PC)
			adjust_favor (ch, 5, 1);

	ch->SendTextf ("%s gives you one gold coin for your sacrifice.\n\r", Name);
	sprintf (buf, "$n sacrifices $p to %s.", Name);
	act (AT_ACTION, buf, ch, obj, NULL, TO_ROOM);
	oprog_sac_trigger (ch, obj);

	if (! obj_extracted (obj)) {
		if (cur_obj == obj->serial)
			global_objcode = rOBJ_SACCED;
		extract_obj (obj);
	}
}


void do_brandish (CCharacter *ch, char *argument)
{
	CCharacter	*vch;
	CCharacter	*vch_next;
	CObjData	*staff;
	ch_ret		retcode;
	int			sn;

	if ((staff = get_eq_char (ch, WEAR_HOLD)) == NULL) {
		ch->SendText ("You hold nothing in your hand.\n\r");
		return;
	}

	if (staff->item_type != ITEM_STAFF) {
		ch->SendText ("You can brandish only with a staff.\n\r");
		return;
	}

	if ((sn = staff->value[3]) < 0 || sn >= SkillTable.GetCount ()
	  || SkillTable.GetSpellFunction (sn) == NULL) {
		bug ("Do_brandish: bad sn %d.", sn);
		return;
	}

	WAIT_STATE (ch, 2 * PULSE_VIOLENCE);

	if (staff->value [2] > 0) {
		if (! oprog_use_trigger (ch, staff, NULL, NULL, NULL)) {
			act (AT_MAGIC, "$n brandishes $p.", ch, staff, NULL, TO_ROOM);
			act (AT_MAGIC, "You brandish $p.",  ch, staff, NULL, TO_CHAR);
		}
		for (vch = ch->GetInRoom ()->first_person; vch; vch = vch_next) {
			vch_next = vch->GetNextInRoom ();
			if (! vch->IsNpc () && vch->IsWizInvis () 
				&& vch->GetPcData ()->wizinvis >= LEVEL_IMMORTAL)
					continue;
			else
				switch (SkillTable.GetTarget (sn)) {
				default:
					bug ("Do_brandish: bad target for sn %d.", sn);
					return;

				case TAR_IGNORE:
					if (vch != ch)
					continue;
					break;

				case TAR_CHAR_OFFENSIVE:
					if (ch->IsNpc () ? vch->IsNpc () : !vch->IsNpc ())
					continue;
					break;

				case TAR_CHAR_DEFENSIVE:
					if (ch->IsNpc () ? !vch->IsNpc () : vch->IsNpc ())
					continue;
					break;

				case TAR_CHAR_SELF:
					if (vch != ch)
					continue;
					break;
				}

			retcode = obj_cast_spell (staff->value[3], staff->value[0], ch, vch, NULL);
			if (retcode == rCHAR_DIED || retcode == rBOTH_DIED) {
				bug ("do_brandish: char died", 0);
				return;
			}  
		}
	}

	if (--staff->value [2] <= 0) {
		act (AT_MAGIC, "$p blazes bright and vanishes from $n's hands!",
			ch, staff, NULL, TO_ROOM);
		act (AT_MAGIC, "$p blazes bright and is gone!", ch, staff, NULL, TO_CHAR);
		if (staff->serial == cur_obj)
			global_objcode = rOBJ_USED;
		extract_obj (staff);
	}
}


void do_zap (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;
	CObjData	*wand;
	CObjData	*obj;
	ch_ret		retcode;

	one_argument (argument, arg);
	if (arg [0] == '\0' && ! ch->GetFightData ()) {
		ch->SendText ("Zap whom or what?\n\r");
		return;
	}

	if ((wand = get_eq_char (ch, WEAR_HOLD)) == NULL) {
		ch->SendText ("You hold nothing in your hand.\n\r");
		return;
	}

	if (wand->item_type != ITEM_WAND) {
		ch->SendText ("You can zap only with a wand.\n\r");
		return;
	}

	obj = NULL;
	if (arg [0] == '\0') {
		if (ch->GetFightData ())
			victim = ch->GetFightWho ();
		else {
			ch->SendText ("Zap whom or what?\n\r");
			return;
		}
	} else {
		if ((victim = get_char_room  (ch, arg)) == NULL
		  && (obj = get_obj_here   (ch, arg)) == NULL) {
			ch->SendText ("You can't find it.\n\r");
			return;
		}
	}

	WAIT_STATE (ch, 1 * PULSE_VIOLENCE);

	if (wand->value [2] > 0) {
		if (victim) {
			if (! oprog_use_trigger (ch, wand, victim, NULL, NULL)) {
				act (AT_MAGIC, "$n aims $p at $N.", ch, wand, victim, TO_ROOM);
				act (AT_MAGIC, "You aim $p at $N.", ch, wand, victim, TO_CHAR);
			}
		} else {
			if (! oprog_use_trigger (ch, wand, NULL, obj, NULL)) {
				act (AT_MAGIC, "$n aims $p at $P.", ch, wand, obj, TO_ROOM);
				act (AT_MAGIC, "You aim $p at $P.", ch, wand, obj, TO_CHAR);
			}
		}

		retcode = obj_cast_spell (wand->value [3], wand->value [0],
			ch, victim, obj);
		if (retcode == rCHAR_DIED || retcode == rBOTH_DIED) {
			bug ("do_zap: char died");
			return;
		}
	}

	if (--wand->value [2] <= 0) {
		act (AT_MAGIC, "$p explodes into fragments.", ch, wand, NULL, TO_ROOM);
		act (AT_MAGIC, "$p explodes into fragments.", ch, wand, NULL, TO_CHAR);
		if (wand->serial == cur_obj)
			global_objcode = rOBJ_USED;
		extract_obj (wand);
	}
}


// Make objects in rooms that are nofloor fall - Scryn 1/23/96
void obj_fall (CObjData *obj, BOOL through)
{
    CExitData *pexit;
    CRoomIndexData *to_room;
    static int fall_count;
    char buf[MAX_STRING_LENGTH];
    static BOOL is_falling; /* Stop loops from the call to obj_to_room ()  -- Altrag */
	
    if (!obj->in_room || is_falling)
    	return;

    if (fall_count > 30)
    {
    	bug ("object falling in loop more than 30 times", 0);
	extract_obj (obj);
    	fall_count = 0;
	return;
     }

     if (obj->in_room->HasNoFloor ()
       && obj->CanGo (DIR_DOWN)
       && ! obj->IsMagic ())
     {

	pexit = get_exit (obj->in_room, DIR_DOWN);
    	to_room = pexit->GetToRoom ();

    	if (through)
	  fall_count++;
	else
	  fall_count = 0;

	if (obj->in_room == to_room)
	{
	    sprintf (buf, "Object falling into same room, room %d",
		to_room->vnum);
	    bug (buf, 0);
	    extract_obj (obj);
            return;
	}

	if (obj->in_room->first_person)
	{
	  	act (AT_PLAIN, "$p falls far below...",
			obj->in_room->first_person, obj, NULL, TO_ROOM);
		act (AT_PLAIN, "$p falls far below...",
			obj->in_room->first_person, obj, NULL, TO_CHAR);
	}
	obj_from_room (obj);
	is_falling = TRUE;
	obj = obj_to_room (obj, to_room);
	is_falling = FALSE;

	if (obj->in_room->first_person)
	{
	  	act (AT_PLAIN, "$p falls from above...", 
			obj->in_room->first_person, obj, NULL, TO_ROOM);
		act (AT_PLAIN, "$p falls from above...",
			obj->in_room->first_person, obj, NULL, TO_CHAR);
	}

 	if (! obj->in_room->HasNoFloor () && through)
	{
/*		int dam =  (int)9.81*sqrt (fall_count*2/9.81)*obj->weight/2;
*/		int dam = fall_count*obj->weight/2;
		/* Damage players */
		if (obj->in_room->first_person && number_percent () > 15)
		{
			CCharacter *rch;
			CCharacter *vch = NULL;
			int chcnt = 0;
			
			for (rch = obj->in_room->first_person; rch;
				rch = rch->GetNextInRoom (), chcnt++)
				if (number_range (0, chcnt) == 0)
					vch = rch;
			act (AT_WHITE, "$p falls on $n!", vch, obj, NULL, TO_ROOM);
			act (AT_WHITE, "$p falls on you!", vch, obj, NULL, TO_CHAR);
			damage (vch, vch, dam*vch->GetLevel (), TYPE_UNDEFINED);
		}
    	/* Damage objects */
	    switch (obj->item_type)
     	    {
	     	case ITEM_WEAPON:
		case ITEM_ARMOR:
		    if ((obj->value[0] - dam) <= 0)
 		    {
   			if (obj->in_room->first_person)
			{
			act (AT_PLAIN, "$p is destroyed by the fall!", 
				obj->in_room->first_person, obj, NULL, TO_ROOM);
			act (AT_PLAIN, "$p is destroyed by the fall!",
				obj->in_room->first_person, obj, NULL, TO_CHAR);
			}
			make_scraps (obj);
	 	    }
		    else
	           	obj->value[0] -= dam;
		    break;
		default:
		    if ((dam*15) > get_obj_resistance (obj))
		    {
	              if (obj->in_room->first_person)
		      {
 			    act (AT_PLAIN, "$p is destroyed by the fall!",
			    	obj->in_room->first_person, obj, NULL, TO_ROOM);
			    act (AT_PLAIN, "$p is destroyed by the fall!",
		    		obj->in_room->first_person, obj, NULL, TO_CHAR);
		      }
		      make_scraps (obj);
		    }
		    break;
	    }
     	}
     	obj_fall (obj, TRUE);
    }
    return;
}