cm3/
cm3/clans/
cm3/mudprogs/
cm3/player/a/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * 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 St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *			   Object manipulation module			    *
 ****************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"

/*
 * External functions
 */

bool check_social  args( ( CHAR_DATA *ch, char *command, char *argument ) );

void    show_list_to_char  args( ( OBJ_DATA *list, CHAR_DATA *ch,
				bool fShort, bool fShowNothing ) );
void    write_corpses   args( ( CHAR_DATA *ch, char *name, OBJ_DATA *objrem ) );

/*
 * Local functions.
 */
void	get_obj		args( ( CHAR_DATA *ch, OBJ_DATA *obj,
			    OBJ_DATA *container ) );

OBJ_DATA* recursive_note_find	args( ( OBJ_DATA *obj, char* argument) );

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

    resist = number_fuzzy(MAX_ITEM_IMPACT);

    /* magical items are more resistant */
    if ( IS_OBJ_STAT( obj, ITEM_MAGIC ) )
      resist += number_fuzzy(15);
    /* metal objects are definately stronger */
    if ( IS_OBJ_STAT( obj, ITEM_METAL ) )
      resist += number_fuzzy(10);
    /* organic objects are most likely weaker */
    if ( IS_OBJ_STAT( obj, ITEM_ORGANIC ) )
      resist -= number_fuzzy(10);
    /* blessed objects should have a little bonus */
    if ( IS_OBJ_STAT( obj, ITEM_BLESS ) )
      resist += number_fuzzy(10);
    /* lets make store inventory pretty tough */
    if ( IS_OBJ_STAT( obj, ITEM_INVENTORY ) )
      resist += 20;

    return URANGE(10, resist, 99);
}


void get_obj( CHAR_DATA *ch, OBJ_DATA *obj, OBJ_DATA *container )
{
    int weight;

    if ( IS_OBJ_STAT(obj, ITEM_NO_TAKE)
       && (IS_NPC(ch) || !IS_SET(ch->pcdata->permissions, PERMIT_BUILD)))
    {
	send_to_char( "You can't take that.\n\r", ch );
	return;
    }

    if ( IS_OBJ_STAT( obj, ITEM_PROTOTYPE )
    &&  !can_take_proto( ch ) )
    {
	send_to_char( "A godly force prevents you from getting close to it.\n\r", ch );
	return;
    }

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

    if ( IS_OBJ_STAT(obj, ITEM_COVERING) )
	weight = obj->weight;
    else
	weight = get_obj_weight( obj );

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

	if ( obj->item_type == ITEM_VEHICLE) {
		CHAR_DATA *rch;

		for (rch = ch->in_room->first_person;rch;rch = rch->next_in_room)
		{
			if (rch->in_obj == obj) {
				send_to_char("Not while somebody is in it!\n\r", ch);
				return;
			}
		}
	}

	/* Make it so players can pick up corpses and eat 'em! -- Scion */
	if ( obj->item_type == ITEM_CORPSE_NPC ) {
		dump_container(obj);
		act(AT_PLAIN, "You shake all the loose items and nasty crunchy bits off the corpse.", ch, NULL, NULL, TO_CHAR);
		act(AT_PLAIN, "$n shakes all the loose items off the corpse.", ch, NULL, NULL, TO_ROOM);
	}

    if ( container )
    {
	if ( container->item_type == ITEM_KEYRING && !IS_OBJ_STAT(container, ITEM_COVERING) )
	{
	    act( AT_ACTION, "You remove $p from $P", ch, obj, container, TO_CHAR );
	    act( AT_ACTION, "$n removes $p from $P", ch, obj, container, TO_ROOM );
	}
	else
	{
	    act( AT_ACTION, IS_OBJ_STAT(container, ITEM_COVERING) ?
		"You get $p from beneath $P." : "You get $p from $P.",
		ch, obj, container, TO_CHAR );
	    act( AT_ACTION, IS_OBJ_STAT(container, ITEM_COVERING) ?
		"$n gets $p from beneath $P." : "$n gets $p from $P.",
		ch, obj, container, TO_ROOM );
	}
	if ( !IS_NPC( ch ) && str_cmp( container->name+7, ch->name ) )
                container->value[5]++;
	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 );
    }

	if (IS_OBJ_STAT(obj, ITEM_ARTIFACT))
		obj->timer = 0;

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

	if ( obj->item_type == ITEM_MONEY ) {
  int gp;

   gp = obj->value[0];
   ch_printf( ch, "There were &C%d mithril, ", (int)gp/1000000 );
   gp = gp % 1000000;
   ch_printf( ch, "&Y%d gold, ", (int)gp/10000 );
   gp = gp % 10000;
   ch_printf( ch, "&W%d silver, ", (int)gp/100 );
   gp = gp % 100;
   ch_printf( ch, "and &O%d copper coins.\n\r", gp);
	ch->gold += 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);
    return;
}


void do_get( CHAR_DATA *ch, char *argument ) {
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    OBJ_DATA *container;
    sh_int number;
    bool found;

    argument = one_argument( argument, arg1 );
    if ( is_number(arg1) )
    {
	number = atoi(arg1);
	if ( number < 1 )
	{
	    send_to_char( "That was easy...\n\r", ch );
	    return;
	}
	if ( (ch->carry_number + number) > can_carry_n(ch) )
	{
	    send_to_char( "You can't carry that many.\n\r", ch );
	    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' )
    {
	send_to_char( "Get what?\n\r", ch );
	return;
    }

    if ( ms_find_obj(ch) )
	return;

	if ( arg2[0] == '\0' )
    {
	if ( number <= 1 && str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
	{

		/* 'get obj' */
    if (ch->in_room->pShop) {
	send_to_char("You can't get items without buying them when you are in a shop.\n\r", ch);
	return;
    }

	if (ch->in_obj)
	    obj = get_obj_list(ch, arg1, ch->in_obj->first_content);
	else
	    obj = get_obj_list( ch, arg1, ch->in_room->first_content );

	    if ( !obj )
	    {
		act( AT_PLAIN, "There is no $T you can reach from here.",
			ch, NULL, arg1, TO_CHAR );
		return;
	    }

	if (IS_NPC(ch) &&
	(obj->item_type == ITEM_CORPSE_NPC
	|| obj->item_type == ITEM_TREASURE)) return;

	if (obj->item_type == ITEM_FURNITURE
	&& count_users(obj) > 0) {
		send_to_char("Not when someone's on it!\n\r", ch);
		return;
	}

	if (IS_AFFECTED(ch, AFF_HAS_ARTI) && IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
		act(AT_ACTION, "$p evades your grasp.", ch, obj, NULL, TO_CHAR);
		act(AT_ACTION, "$p evades $n's grasp.", ch, obj, NULL, TO_ROOM);
		return;
	}

	if (IS_AFFECTED(ch, AFF_ETHEREAL)) {
		act(AT_ACTION, "Your hand passes through $p.", ch, obj, NULL, TO_CHAR);
		act(AT_ACTION, "$n's hand passes through $p.", ch, obj, NULL, TO_ROOM);
		return;
	}

	/* lets not make magic items hovering in nofloor rooms ungettable -keo */
	    if (IS_AFFECTED(ch, AFF_FLYING)
	    && (!IS_OBJ_STAT(obj, ITEM_HOVER)) ) {
		if (ch->curr_talent[TAL_MOTION] < 10) {
			send_to_char("You can't reach anything on the ground from up here.", ch);
			return;
		}
	    }
	/* sticky floor, chance of sticking -keo */
	    if (!IS_OBJ_STAT(obj, ITEM_NO_TAKE)
	    && IS_SET(ch->in_room->room_flags, ROOM_STICKY)
	    && (!IS_OBJ_STAT(obj, ITEM_HOVER))) {
		STRFREE(ch->last_taken);
		ch->last_taken = STRALLOC("trying to pry an item off the sticky floor");
		WAIT_STATE(ch, PULSE_VIOLENCE);
		if (number_range(1,100) > get_curr_str(ch)) {
			act(AT_ACTION, "$p is stuck to the floor, and you don't manage to pry it loose.", ch, obj, NULL, TO_CHAR);
			act(AT_ACTION, "$n tries to lift $p, but it is stuck to the floor.", ch, obj, NULL, TO_ROOM);
			return;
		} else {
			act(AT_ACTION, "$p is stuck to the floor, but you manage to pry it loose.", ch, obj, NULL, TO_CHAR);
			act(AT_ACTION, "$n pries $p off the sticky floor.", ch, obj, NULL, TO_ROOM);
		}
	    }
	    separate_obj(obj);
	    get_obj( ch, obj, obj->in_obj );
	    if ( char_died(ch) )
		return;
	    if ( IS_SET( sysdata.save_flags, SV_GET ) )
		save_char_obj( ch );
	}
	else
	{
	    sh_int cnt = 0;
	    bool fAll;
	    char *chk;

	    if ( IS_SET( ch->in_room->room_flags, ROOM_DONATION ) )
	    {
		send_to_char( "The gods frown upon such a display of greed!\n\r", ch );
		return;
	    }

		if (IS_AFFECTED(ch, AFF_FLYING)) {
			send_to_char("You can't reach anything on the ground from up here.\r\n", ch);
			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' */

    if (ch->in_room->pShop) {
	send_to_char("You can't get items without buying them when you are in a shop.\n\r", ch);
	return;
    }

	    found = FALSE;
	    for ( obj = ch->in_room->last_content; obj; obj = obj_next )
	    {
		obj_next = obj->prev_content;
		if ( ( fAll
		||   nifty_is_name_prefix( chk, obj->name) )
		&&  !IS_OBJ_STAT(obj, ITEM_ARTIFACT)
		&&  !IS_AFFECTED(ch, AFF_ETHEREAL)
		&&   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 >= can_carry_n( ch )
		    ||   ch->carry_weight >= can_carry_w( ch )
		    ||   (number && cnt >= number) )
		    {
			if ( IS_SET(sysdata.save_flags, SV_GET)
			&&  !char_died(ch) )
			    save_char_obj(ch);
			return;
		    }
		}
	    }

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

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

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

	case ITEM_CONTAINER:
	case ITEM_CORPSE_NPC:
	case ITEM_KEYRING:
	case ITEM_QUIVER:
	case ITEM_FURNITURE:
	case ITEM_VEHICLE:
	    break;

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

		if ( IS_NPC(ch) )
		{
		    send_to_char( "You can't do that.\n\r", ch );
		    return;
		}

		pd = container->short_descr;
		pd = one_argument( pd, name );
		pd = one_argument( pd, name );
		pd = one_argument( pd, name );
		pd = one_argument( pd, name );

		if ( str_cmp( name, ch->name ) )
		{
		    bool fGroup;

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

		}
	    }
	}

	if ( !IS_OBJ_STAT(container, ITEM_COVERING )
	&&    IS_SET(container->value[1], CONT_CLOSED)
	&&	 container->item_type != ITEM_CORPSE_NPC
	&&   container->item_type != ITEM_CORPSE_PC)
	{
	    act( AT_PLAIN, "The $d is closed.", ch, NULL, container->name, TO_CHAR );
	    return;
	}

	if ( number <= 1 && str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
	{
	    /* 'get obj container' */
	    obj = get_obj_list( ch, arg1, container->first_content );
	    if ( !obj )
	    {
		act( AT_PLAIN, IS_OBJ_STAT(container, ITEM_COVERING) ?
			"You see nothing like that beneath the $T." :
			"You see nothing like that in the $T.",
			ch, NULL, arg2, TO_CHAR );
		return;
	    }
        if (container->carried_by != ch && (IS_AFFECTED(ch, AFF_FLYING)) )
        {
                if (ch->curr_talent[TAL_MOTION] < 20) {
                        send_to_char("You can't reach anything on the ground from up here.\n\r", ch);
                        return;
                /* check if they can apport -keo */
                } else if (number_percent() > ch->curr_talent[TAL_MOTION]) {
                        act(AT_MAGIC, "$p shakes a little.",
                                ch, obj, NULL, TO_ROOM);
                        act(AT_MAGIC, "You attempt to lift $p but fail.",
                                ch, obj, NULL, TO_CHAR);
                        return;
                } else {
                        act(AT_MAGIC, "$p suddenly flies up toward $n.",
                                ch, obj, NULL, TO_ROOM);
                        act(AT_MAGIC, "You lift $p and bring it toward you.",
                                ch, obj, NULL, TO_CHAR);
                        learn_talent(ch, TAL_MOTION);
                        mana_from_char(ch, 25);
                }
        }

        if (IS_AFFECTED(ch, AFF_HAS_ARTI) && IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
                act(AT_ACTION, "$p evades your grasp.", ch, obj, NULL, TO_CHAR);
                act(AT_ACTION, "$p evades $n's grasp.", ch, obj, NULL, TO_ROOM);
                return;
        }

	if (IS_AFFECTED(ch, AFF_ETHEREAL)) {
		act(AT_ACTION, "Your hand passes through $p.", ch, obj, NULL, TO_CHAR);
		act(AT_ACTION, "$n's hand passes through $p.", ch, obj, NULL, TO_ROOM);
		return;
	}

	    separate_obj(obj);
	    get_obj( ch, obj, container );
	    check_for_trap( ch, container, TRAP_GET );
	    if ( char_died(ch) )
		return;
	    if ( IS_SET( sysdata.save_flags, SV_GET ) )
		save_char_obj( ch );
	}
	else
	{
	    int cnt = 0;
	    bool fAll;
	    char *chk;

	    /* 'get all container' or 'get all.obj container' */
	    if (IS_AFFECTED(ch, AFF_FLYING)
	    && !IS_OBJ_STAT( container, ITEM_MAGIC) ) {
		send_to_char("You can't reach items on the ground from up here.\n\r", ch);
		return;
	    }

	    if (container->item_type == ITEM_CORPSE_PC
	    && !nifty_is_name(ch->name, container->name) ) {
		send_to_char("Your adrenaline is pumping too hard to do that!\n\r", ch);
		return;
	    }

	    if ( !str_cmp(arg1, "all") )
		fAll = TRUE;
	    else
		fAll = FALSE;
	    if ( number > 1 )
		chk = arg1;
	    else
		chk = &arg1[4];
	    found = FALSE;
	    for ( obj = container->first_content; obj; obj = obj_next )
	    {
		obj_next = obj->next_content;
		if ( ( fAll || nifty_is_name_prefix( chk, obj->name ) )
		&&  !IS_OBJ_STAT(obj, ITEM_ARTIFACT)
		&&  !IS_AFFECTED(ch, AFF_ETHEREAL)
		&&   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 >= can_carry_n( ch )
		    ||   ch->carry_weight >= can_carry_w( ch )
		    ||   (number && cnt >= number) )
		      return;
		}
	    }

	    if ( !found )
	    {
		if ( fAll )
		{
		    if ( container->item_type == ITEM_KEYRING && !IS_OBJ_STAT(container, ITEM_COVERING) )
			act( AT_PLAIN, "The $T holds no keys.",
			    ch, NULL, arg2, TO_CHAR );
		    else
			act( AT_PLAIN, IS_OBJ_STAT(container, ITEM_COVERING) ?
			    "You see nothing beneath the $T." :
			    "You see nothing in the $T.",
			    ch, NULL, arg2, TO_CHAR );
		}
		else
		{
		    if ( container->item_type == ITEM_KEYRING && !IS_OBJ_STAT(container, ITEM_COVERING) )
			act( AT_PLAIN, "The $T does not hold that key.",
			    ch, NULL, arg2, TO_CHAR );
		    else
			act( AT_PLAIN, IS_OBJ_STAT(container, ITEM_COVERING) ?
			    "You see nothing like that beneath the $T." :
			    "You 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;
	    /* Oops no wonder corpses were duping oopsie did I do that
	     * --Shaddai
             */
	    if ( container->item_type == ITEM_CORPSE_PC )
		write_corpses( NULL, container->short_descr+14, NULL );
	    if ( found && IS_SET( sysdata.save_flags, SV_GET ) )
		save_char_obj( ch );
	}
    }
    return;
}



void do_put( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    OBJ_DATA *container;
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    sh_int	count;
    int		number;
    bool	save_char = FALSE;

    argument = one_argument( argument, arg1 );
    if ( is_number(arg1) )
    {
	number = atoi(arg1);
	if ( number < 1 )
	{
	    send_to_char( "That was easy...\n\r", ch );
	    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") || !str_cmp(arg2, "under")
    ||    !str_cmp(arg2, "onto") || !str_cmp(arg2, "on"))
    &&     argument[0] != '\0' )
	argument = one_argument( argument, arg2 );

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

    if ( ms_find_obj(ch) )
	return;

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

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

    if ( !container->carried_by && IS_SET(sysdata.save_flags, SV_PUT) )
	save_char = TRUE;

    if ( IS_OBJ_STAT(container, ITEM_COVERING) )
    {
	if ( ch->carry_weight + container->weight > can_carry_w(ch) )
	{
	    send_to_char( "It's too heavy for you to lift.\n\r", ch );
	    return;
	}
    }
    else
    {
	/* lets burn flammables -keo */
	if ( container->item_type == ITEM_FIRE ) {
            if ( (obj=get_obj_carry(ch, arg1)) == NULL )
            {
                send_to_char( "You do not have that item.\n\r", ch );
                return;
            }
	    if (!IS_OBJ_STAT(obj, ITEM_FLAMMABLE)
	    ||   IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
		act(AT_FIRE, "$p won't catch fire.", ch,obj, NULL,TO_CHAR);
		return;
	    }
	    act(AT_FIRE, "You put $p on $P, and it catches fire and burns.",
		ch, obj, container, TO_CHAR);
	    act(AT_FIRE, "$n puts $p on $P, and it catches fire and burns.",
		ch, obj, container, TO_ROOM);
	    if (container->timer > 0) container->timer += obj->weight*3;
	    obj_from_char(obj);
	    extract_obj(obj);
	    return;
	}

	if ( container->item_type != ITEM_CONTAINER
	&&   container->item_type != ITEM_FURNITURE
	&&   container->item_type != ITEM_KEYRING
	&&   container->item_type != ITEM_VEHICLE
	&&   container->item_type != ITEM_QUIVER )
	{
	    send_to_char( "That's not a container.\n\r", ch );
	    return;
	}

	if ( IS_SET(container->value[1], CONT_CLOSED)
		&& container->item_type != ITEM_CORPSE_NPC
		&& container->item_type != ITEM_CORPSE_PC)
	{
	    act( AT_PLAIN, "The $d is closed.", ch, NULL, container->name, 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 )
	{
	    send_to_char( "You do not have that item.\n\r", ch );
	    return;
	}

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

	if (IS_OBJ_STAT(obj, ITEM_ARTIFACT))
	{
	    act(AT_ACTION, "$p squirms refusing to let you put it in the container.", ch, obj, NULL, TO_CHAR);
	    act(AT_ACTION, "$p squirms as $n tries to put it in a container.", ch, obj, NULL, TO_ROOM);
	    return;
	}

	if ( container->item_type == ITEM_KEYRING && obj->item_type != ITEM_KEY )
	{
	    send_to_char( "That's not a key.\n\r", ch );
	    return;
	}

	if ( container->item_type == ITEM_QUIVER && obj->item_type != ITEM_PROJECTILE )
	{
	    send_to_char( "That's not a projectile.\n\r", ch );
	    return;
	}

	if ( (IS_OBJ_STAT(container, ITEM_COVERING)
	&&   (get_obj_weight(obj) * obj->count)
	  > ((get_real_obj_weight(container) * container->count))) )
	{
	    send_to_char( "It won't fit under there.\n\r", ch );
	    return;
	}

	/* note use of get_real_obj_weight */
	else if ( (get_real_obj_weight(obj) * obj->count)
	> ((container->item_type==ITEM_CONTAINER 
	? container->value[0] - get_real_obj_weight(container)
	: get_real_obj_weight(container)) * container->count))
	{
	    send_to_char( "It won't fit.\n\r", ch );
	    return;
	}

	separate_obj(obj);
	separate_obj(container);
	obj_from_char( obj );

	/* basketball? -keo */
	if (container->carried_by != ch && (IS_AFFECTED(ch, AFF_FLYING)) )
	{
		act(AT_PLAIN, "You throw the $t at the $T.", ch, myobj(obj), myobj(container), TO_CHAR);
		act(AT_PLAIN, "$n throws $p at the $T.", ch, obj, myobj(container), TO_ROOM);
		if ( (number_range(0,5)*100) < container->value[0] ) {
			act(AT_PLAIN, "Score! The $t lands in the $T.", ch, myobj(obj), myobj(container), TO_CHAR);
			act(AT_PLAIN, "$n scores! The $t lands in the $T.", ch, myobj(obj), myobj(container), TO_ROOM);
			obj = obj_to_obj( obj, container );
			return;
		} else {
			act(AT_PLAIN, "You missed! The $t lands on the ground.", ch, myobj(obj), NULL, TO_CHAR);
			act(AT_PLAIN, "$n misses! The $t lands on the ground.", ch, myobj(obj), NULL, TO_ROOM);
			obj_to_room(obj, ch->in_room);
			separate_obj(obj);
			damage_obj(obj);
			return;
		}
	}

	obj = obj_to_obj( obj, container );
	count = obj->count;
	obj->count = 1;
	if ( container->item_type == ITEM_KEYRING && !IS_OBJ_STAT(container, ITEM_COVERING) )
	{
	    act( AT_ACTION, "$n slips $p onto $P.", ch, obj, container, TO_ROOM );
	    act( AT_ACTION, "You slip $p onto $P.", ch, obj, container, TO_CHAR );
	}
	else
	{
	    act( AT_ACTION, IS_OBJ_STAT(container, ITEM_COVERING)
		? "$n hides $p beneath $P." : "$n puts $p in $P.",
		ch, obj, container, TO_ROOM );
	    act( AT_ACTION, IS_OBJ_STAT(container, ITEM_COVERING)
		? "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);
    }
    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];

        if (container->carried_by != ch && (IS_AFFECTED(ch, AFF_FLYING)) )
	{
		send_to_char("From up here? Do it one at a time!", ch);
		return;
	}

	separate_obj(container);
	/* 'put all container' or 'put all.obj container' */
	for ( obj = ch->first_carrying; obj; obj = obj_next )
	{
	    obj_next = obj->next_content;

	    if ( ( fAll || nifty_is_name_prefix( chk, obj->name ) )
	    &&   can_see_obj( ch, obj )
	    &&   obj->wear_loc == WEAR_NONE
	    &&   obj != ch->main_hand
	    &&   obj != ch->off_hand
	    &&   obj != container
	    &&  !IS_OBJ_STAT(obj, ITEM_ARTIFACT)
	    &&   can_drop_obj( ch, obj )
	    &&  (container->item_type != ITEM_KEYRING || obj->item_type == ITEM_KEY)
	    &&  (container->item_type != ITEM_QUIVER  || obj->item_type == ITEM_PROJECTILE)
	    &&   get_obj_weight( obj ) + get_real_obj_weight( container )
		 <= container->value[0] )
	    {
		if ( number && (cnt + obj->count) > number )
		    split_obj(obj, number - cnt);
		cnt += obj->count;
		obj_from_char(obj);
		if ( container->item_type == ITEM_KEYRING )
		{
		    act( AT_ACTION, "$n slips $p onto $P.", ch, obj, container, TO_ROOM );
		    act( AT_ACTION, "You slip $p onto $P.", ch, obj, container, TO_CHAR );
		}
		else
		{
		    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;

		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 that would fit.",
		    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);
    }

    return;
}


void do_drop( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    bool found;
    int number;

    if (ch->in_room->pShop) {
	send_to_char("You can't drop items without selling them when you are in a shop.\n\r", ch);
	return;
    }

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

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

    if ( ms_find_obj(ch) )
	return;

    if ( xIS_SET( ch->act, PLR_LITTERBUG ) )
    {
       set_char_color( AT_YELLOW, ch );
       send_to_char( "A godly force prevents you from dropping anything...\n\r", ch );
       return;
    }

    if ( IS_SET( ch->in_room->room_flags, ROOM_NODROP )
    &&   ch != supermob )
    {
       set_char_color( AT_MAGIC, ch );
       send_to_char( "A magical force stops you!\n\r", ch );
       set_char_color( AT_TELL, ch );
       send_to_char( "Someone tells you, 'No littering here!'\n\r", ch );
       return;
    }

    if ( number > 0 )
    {
	/* 'drop NNNN coins' */

	if (!str_cmp(arg, "mithril") || !str_cmp(arg, "gold")
	||  !str_cmp(arg, "silver")  || !str_cmp(arg, "copper")
	||  !str_cmp(arg, "coins")) {

        if (!str_cmp(arg, "mithril"))
                number *= 1000000;
        else if (!str_cmp(arg, "gold"))
                number *= 10000;
        else if (!str_cmp(arg, "silver"))
                number *= 100;

	if (number < 0) {
		send_to_char("And just how do you propose to do that?\n\r", ch);
		return;
	}

	    if ( ch->gold < number )
	    {
		send_to_char( "You haven't got that many coins.\n\r", ch );
		return;
	    }

	    ch->gold -= number;

	    for ( obj = ch->in_room->first_content; obj; obj = obj_next )
	    {
		obj_next = obj->next_content;

		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 coins.", ch, NULL, NULL, TO_ROOM );
	if (ch->in_obj)
	    obj_to_obj( create_money( number ), ch->in_obj);
	else
	    obj_to_room( create_money( number ), ch->in_room );
	    send_to_char( "You drop some coins.\n\r", ch );
	    if ( IS_SET( sysdata.save_flags, SV_DROP ) )
		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 )
	{
	    send_to_char( "You do not have that item.\n\r", ch );
	    return;
	}

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

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

	obj_from_char( obj );
	if (ch->in_obj)
		obj = obj_to_obj( obj, ch->in_obj );
	else
		obj = obj_to_room( obj, ch->in_room );
	oprog_drop_trigger ( ch, obj );   /* mudprogs */

	if (IS_OBJ_STAT(obj, ITEM_ARTIFACT) )
		obj->timer = 30;

	if (IS_OBJ_STAT(obj, ITEM_DREAMWORLD) ) {
		act( AT_ACTION, "The $t ripples and vanishes.",
			ch, myobj(obj), NULL, TO_CHAR);
		act( AT_ACTION, "$p ripples and vanishes.",
			ch, obj, NULL, TO_ROOM);
		extract_obj(obj);
	}

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

    }
    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 ( IS_SET( ch->in_room->room_flags, ROOM_NODROPALL ) )
	{
	    send_to_char( "You can't seem to do that here...\n\r", ch );
	    return;
	}
	found = FALSE;
	for ( obj = ch->first_carrying; obj; obj = obj_next )
	{
	    obj_next = obj->next_content;

	    if ( (fAll || nifty_is_name_prefix( chk, obj->name ) )
	    &&   can_see_obj( ch, obj )
	    &&   obj->wear_loc == WEAR_NONE
	    &&   can_drop_obj( ch, obj ) )
	    {
		found = TRUE;
		if ( HAS_PROG(obj->pIndexData, DROP_PROG) && obj->count > 1 )
		{
		   ++cnt;
		   separate_obj( obj );
		   obj_from_char( obj );
		   if ( !obj_next )
		     obj_next = ch->first_carrying;
		}
		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 the $t.", ch, myobj(obj), NULL, TO_CHAR );
		if (ch->in_obj)
			obj = obj_to_obj( obj, ch->in_obj );
		else
			obj = obj_to_room( obj, ch->in_room );

	if (IS_OBJ_STAT(obj, ITEM_ARTIFACT) )
		obj->timer = 30;

        if (IS_OBJ_STAT(obj, ITEM_DREAMWORLD) ) {
                act( AT_ACTION, "The $t ripples and vanishes.",
                        ch, myobj(obj), NULL, TO_CHAR);
                act( AT_ACTION, "$p ripples and vanishes.",
                        ch, obj, NULL, TO_ROOM);
                extract_obj(obj);
        }

		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 ( IS_SET( sysdata.save_flags, SV_DROP ) )
	save_char_obj( ch );	/* duping protector */
    return;
}



void do_give( CHAR_DATA *ch, char *argument )
{
    char arg1 [MAX_INPUT_LENGTH];
    char arg2 [MAX_INPUT_LENGTH];
    char buf  [MAX_INPUT_LENGTH];
    CHAR_DATA *victim;
    OBJ_DATA  *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' )
    {
	send_to_char( "Give what to whom?\n\r", ch );
	return;
    }

    if ( ms_find_obj(ch) )
	return;

    if ( is_number( arg1 ) )
    {
	/* 'give NNNN coins victim' */
	int amount;
	int gp;
	char buf2[MAX_STRING_LENGTH];

	amount   = atoi(arg1);
	if ( amount <= 0 ) {
	    send_to_char( "Well, that was easy!\n\r", ch );
	    return;
	}

	if (!str_cmp(arg2, "mithril"))
		amount *= 1000000;
	else if (!str_cmp(arg2, "gold"))
		amount *= 10000;
	else if (!str_cmp(arg2, "silver"))
		amount *= 100;
	else if (!str_cmp(arg2, "copper")
	||       !str_cmp(arg2, "coins"))
		amount *= 1;
	else {
		send_to_char("You can't do that.\n\r", ch);
		return;
	}

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

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

	if (amount < 0) {
		send_to_char("And just how do you propose to do that?\n\r", ch);
		return;
	}

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

	if (!IS_SAME_PLANE(ch, victim)) {
		send_to_char("Your hands pass right through them!", ch);
		return;
	}

	ch->gold     -= amount;
	victim->gold += amount;
        strcpy(buf, "$n gives you ");
   gp = amount;
   sprintf( buf2, "&C%d mithril, ", (int)gp/1000000 );
   strcat(buf, buf2);
   gp = gp % 1000000;
   sprintf( buf2, "&Y%d gold, ", (int)gp/10000 );
   strcat(buf, buf2);
   gp = gp % 10000;
   sprintf( buf2, "&W%d silver, ", (int)gp/100 );
   strcat(buf, buf2);
   gp = gp % 100;
   sprintf( buf2, "and &O%d copper coins.\n\r", gp);
   strcat(buf, buf2);

	act( AT_ACTION, buf, ch, NULL, victim, TO_VICT    );
	act( AT_ACTION, "$n gives $N some coins.",  ch, NULL, victim, TO_NOTVICT );
	act( AT_ACTION, "You give $N some coins.",  ch, NULL, victim, TO_CHAR );
	send_to_char( "OK.\n\r", ch );
	mprog_bribe_trigger( victim, ch, amount );
	if ( IS_SET( sysdata.save_flags, SV_GIVE ) && !char_died(ch) )
	    save_char_obj(ch);
	if ( IS_SET( sysdata.save_flags, SV_RECEIVE ) && !char_died(victim) )
	    save_char_obj(victim);
	return;
    }

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

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

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

	if (!IS_SAME_PLANE(ch, victim)) {
		send_to_char("Your hands pass right through them!", ch);
		return;
	}

    if (IS_AFFECTED(victim, AFF_HAS_ARTI) && IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
	act(AT_ACTION, "$p evades $n's grasp.", victim, obj, NULL, TO_ROOM);
	act(AT_ACTION, "$n tries to give you $p but it evades your grasp.", ch, obj, victim, TO_VICT);
	return;
    }

	if (IS_AFFECTED(ch, AFF_ETHEREAL)) {
		act(AT_ACTION, "$n tries to give you $p but your hand passes through it.", victim, obj, ch, TO_VICT);
		act(AT_ACTION, "$n's hand passes through $p.", victim, obj, NULL, TO_ROOM);
		return;
	}

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

    if ( victim->carry_weight + (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 (IS_OBJ_STAT( obj, ITEM_PROTOTYPE ) && !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 ( IS_SET(sysdata.save_flags, SV_GIVE) && !char_died(ch) )
	save_char_obj(ch);
    if ( IS_SET(sysdata.save_flags, SV_RECEIVE) && !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( OBJ_DATA *obj )
{
    CHAR_DATA *ch;
    obj_ret objcode;
    int chance = 50;

    ch = obj->carried_by;
    objcode = rNONE;

    separate_obj( obj );
    if (ch && !IS_NPC(ch) && !IS_SET(ch->pcdata->flags, PCFLAG_GAG))
	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;
    }

	if (IS_OBJ_STAT(obj, ITEM_METAL))
		chance += 20;

	if (IS_OBJ_STAT(obj, ITEM_ORGANIC))
		chance -= 20;

	if (IS_OBJ_STAT(obj, ITEM_BLESS))
		chance += 20;

	if (number_range(0, 100) >= chance)
		return rNONE;

	obj->condition -= number_range(1, 10);
	if (obj->condition <= 0) {
		make_scraps(obj);
		return rOBJ_SCRAPPED;
	}
    return objcode;
}


/*
 * See if char could be capable of dual-wielding		-Thoric
 */
bool could_dual( CHAR_DATA *ch )
{
	return TRUE;
}

/*
 * See if char can dual wield at this time			-Thoric
 */
bool can_dual( CHAR_DATA *ch )
{
    OBJ_DATA *obj;

    if ( !could_dual(ch) )
	return FALSE;

    if ((obj = get_eq_char( ch, WEAR_HAND)) && get_eq_char( ch, WEAR_HAND2) )
    {
	send_to_char( "You are already holding two items!\n\r", ch );
	return FALSE;
    }
    if ( xIS_SET(obj->extra_flags, ITEM_TWO_HANDED)) {
	send_to_char("You cannot dual wield with a two-handed weapon!\n\r", ch);
	return FALSE;
    }
    if ( get_eq_char( ch, WEAR_SHIELD ) )
    {
	send_to_char( "You cannot dual wield while holding a shield!\n\r", ch );
	return FALSE;
    }
    return TRUE;
}


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

    for ( otmp = ch->first_carrying; otmp; otmp = otmp->next_content )
		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;
}


void do_bury( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    bool shovel;
    sh_int move;

    one_argument( argument, arg );

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

    if ( ms_find_obj(ch) )
        return;

    shovel = FALSE;
    for ( obj = ch->first_carrying; obj; obj = obj->next_content )
      if ( obj->item_type == ITEM_SHOVEL )
      {
	  shovel = TRUE;
	  break;
      }

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

    separate_obj(obj);

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

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

    move = (obj->weight * 50 * (shovel ? 1 : 5)) / UMAX(1, can_carry_w(ch));
    move = URANGE( 2, move, 1000 );
    if ( move > ch->move )
    {
	send_to_char( "You don't have the energy to bury something of that size.\n\r", ch );
	return;
    }
    ch->move -= move;
    act( AT_ACTION, "You solemnly bury $p...", ch, obj, NULL, TO_CHAR );
    act( AT_ACTION, "$n solemnly buries $p...", ch, obj, NULL, TO_ROOM );
    xSET_BIT( obj->extra_flags, ITEM_BURIED );
    WAIT_STATE( ch, URANGE( 10, move / 2, 100 ) );
    return;
}


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

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

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

    if ( ( sn = staff->value[3] ) < 0
    ||   sn >= top_sn
    ||   skill_table[sn]->spell_fun == NULL )
    {
	bug( "Do_brandish: bad sn %d on object vnum %d.", sn, staff->pIndexData->vnum );
	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->in_room->first_person; vch; vch = vch_next )
	{
	    vch_next	= vch->next_in_room;
            if ( !IS_NPC( vch ) && xIS_SET( vch->act, PLR_WIZINVIS ))
                continue;
            else
	    switch ( skill_table[sn]->target )
	    {
	    default:
		bug( "Do_brandish: bad target for sn %d.", sn );
		return;

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

	    case TAR_CHAR_OFFENSIVE:
		if ( IS_NPC(ch) ? IS_NPC(vch) : !IS_NPC(vch) )
		    continue;
		break;

	    case TAR_CHAR_DEFENSIVE:
		if ( IS_NPC(ch) ? !IS_NPC(vch) : IS_NPC(vch) )
		    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 );
    }

    return;
}


/* Make objects in rooms that are nofloor fall - Scryn 1/23/96 */

void obj_fall( OBJ_DATA *obj, bool through )
{
    EXIT_DATA *pexit;
    ROOM_INDEX_DATA *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 > 80)
    {
    	bug( "object falling in loop more than 80 times", 0 );
	extract_obj(obj);
    	fall_count = 0;
	return;
     }

     if ( IS_SET( obj->in_room->room_flags, ROOM_NOFLOOR )
     &&   CAN_GO( obj, DIR_DOWN )
     &&   !IS_OBJ_STAT( obj, ITEM_HOVER ) )
     {

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

    	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 (!IS_SET( obj->in_room->room_flags, ROOM_NOFLOOR ) && through )
	{
		int dam = obj->weight*(fall_count/2);

		/* Damage players */
		if ( obj->in_room->first_person && number_percent() > 15 )
		{
			CHAR_DATA *rch;
			CHAR_DATA *vch = NULL;
			int chcnt = 0;

			for ( rch = obj->in_room->first_person; rch;
				rch = rch->next_in_room, 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 );
			lose_hp(vch, dam);
		}
    	/* 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;
}

/* Scryn, by request of Darkur, 12/04/98 */
/* Reworked recursive_note_find to fix crash bug when the note was left
 * blank.  7/6/98 -- Shaddai
 */

void do_findnote( CHAR_DATA *ch, char *argument )
{
  OBJ_DATA* obj;

  if ( IS_NPC(ch) )
  {
    send_to_char( "Huh?\n\r", ch );
    return;
  }

  if( argument[0] == '\0' )
  {
    send_to_char( "You must specify at least one keyword.\n\r", ch);
    return;
  }

  obj = recursive_note_find(ch->first_carrying, argument);

  if(obj)
  {
    if(obj->in_obj)
    {
      obj_from_obj(obj);
      obj = obj_to_char(obj, ch);
    }
  }
  else
    send_to_char("Note not found.\n\r", ch);
  return;
}

OBJ_DATA* recursive_note_find( OBJ_DATA *obj, char *argument )
{
  OBJ_DATA* returned_obj;
  bool match = TRUE;
  char* argcopy;
  char* subject;

  char arg[MAX_INPUT_LENGTH];
  char subj[MAX_STRING_LENGTH];

  if(!obj)
    return NULL;

  switch(obj->item_type)
  {
    case ITEM_PAPER:

      if ((subject = get_extra_descr( "_subject_", obj->first_extradesc))==NULL)
        break;
      sprintf(subj, "%s", strlower(subject) );
      subject = strlower(subj);

      argcopy = argument;

      while(match)
      {
	argcopy = one_argument(argcopy, arg);

        if(arg[0] == '\0')
          break;

	if(!strstr(subject, arg))
          match = FALSE;
      }


      if(match)
        return obj;
      break;

    case ITEM_CONTAINER:
    case ITEM_CORPSE_NPC:
    case ITEM_CORPSE_PC:
      if(obj->first_content)
      {
      	returned_obj = recursive_note_find(obj->first_content, argument);
        if(returned_obj)
          return returned_obj;
      }
      break;

    default:
      break;
  }

  return recursive_note_find(obj->next_content, argument);
}