dotd-2.3.7/area/
dotd-2.3.7/clans/
dotd-2.3.7/classes/
dotd-2.3.7/councils/
dotd-2.3.7/deity/
dotd-2.3.7/dict/
dotd-2.3.7/doc/mudprogs/
dotd-2.3.7/player/a/
dotd-2.3.7/player/g/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.0 (C) 1994, 1995, 1996 by Derek Snider             |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh and Tricops  |~'~.VxvxV.~'~*
 * ------------------------------------------------------------------------ *
 * 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			    *
 ****************************************************************************/

/*
 * $Log: act_obj.c,v $
 * Revision 1.59  2004/04/06 22:00:08  dotd
 * use gcc __attribute__((format)) for custom printf functions, and fix all the resulting warnings (hundreds of them), thanks
 * to Samson for disconvering this nifty GCC extension
 *
 * Revision 1.58  2003/12/25 07:25:14  dotd
 * deity typos
 *
 * Revision 1.57  2003/12/21 17:20:53  dotd
 * cleaned up some compiler warnings from g++
 *
 * Revision 1.56  2003/12/06 01:14:34  dotd
 * clean up warnings generated by new -W compiler flags
 *
 * Revision 1.55  2003/08/29 03:56:02  dotd
 * don't count max carry number when picking up money, only weight
 *
 * Revision 1.54  2003/08/29 03:45:09  dotd
 * allow giving more than sh_int can hold
 *
 * Revision 1.53  2003/08/22 01:02:51  dotd
 * junk all really doesn't work, switch to junk all.really
 *
 * Revision 1.52  2003/07/29 23:08:13  dotd
 * auction currency fix from Vladaar
 *
 * Revision 1.51  2003/03/07 04:12:54  dotd
 * change some money logs from MONITOR to DEBUG
 *
 * Revision 1.50  2003/03/06 03:55:22  dotd
 * make 'junk all' tell people to do 'junk all really' so people don't wax
 * all their eq on accident
 *
 * Revision 1.49  2003/03/06 02:50:07  dotd
 * currency tweaks, horde type monies now have the horde calculation in
 *
 * Revision 1.48  2003/03/01 05:09:56  dotd
 * move a barb check to above the obj_to_char, so we don't have to futz with
 * it and cause problems, might fix a crash bug
 *
 * Revision 1.47  2003/01/26 23:43:53  dotd
 * some groundwork for db backend, add xxx_exists_index to replace
 * get_xxx_index (so the db can use an optimized query instead of returning
 * the whole structure), add vnum to char_data and obj_data so you don't need
 * to access the index (and thus you don't have to query the db), make
 * create_xxx take a vnum instead of an index (so create_xxx can query the db
 * or use a caching layer)
 *
 * Revision 1.46  2003/01/01 00:49:18  dotd
 * handle money weights in corpses/ground, let people pick up as much as they
 * can carry instead of nothing at all
 *
 * Revision 1.45  2002/12/31 00:10:17  dotd
 * removed some nasty dependencies by moving tables.h and magic.h into
 * tables.c, had to add function prototypes in a lot of places
 *
 * Revision 1.44  2002/10/27 20:39:05  dotd
 * don't use objindex affects for anything, instead copy them to new
 * instances of obj and use them there, this fixes the dispelling/enchanting
 * problem and just makes sense
 *
 * Revision 1.43  2002/10/12 20:06:08  dotd
 * ANSI C error fixes, almost everything compiles with -ansi and/or -pedantic
 * now.  Also removed some of the CVS log comments
 *
 * Revision 1.42  2002/08/11 16:45:00  dotd
 * anti class eq bits re-done another time, if hell exists i now know what it
 * will be for me
 *
 * Revision 1.41  2002/08/10 20:15:34  dotd
 * added function name to last_carried_by for better tracking
 *
 * Revision 1.40  2002/07/24 17:07:44  dotd
 * ego divide by zero fix
 *
 * Revision 1.39  2002/07/09 05:33:02  dotd
 * remove sacrifice inventory search
 *
 * Revision 1.38  2002/07/05 18:37:41  dotd
 * change progs to use extended bits from SMAUG1.4 so we can have more
 * added QUEST_PROG and quest triggers
 *
 * Revision 1.37  2002/07/03 00:54:40  dotd
 * char_ego update
 *
 * Revision 1.36  2002/06/26 22:53:46  dotd
 * solaris null var/printf fix
 *
 * Revision 1.35  2002/06/22 02:54:50  dotd
 * quest triggers hook points: objgive, objplace, mobkill
 *
 * Revision 1.34  2002/06/15 14:38:10  dotd
 * money_weight() function, use in get_obj to handle getting money
 *
 * Revision 1.33  2002/06/15 03:48:01  dotd
 * carry_n and carry_w funtions to replace ch->carry_number and
 * ch->carry_weight so that special weights like gold can be handled
 *
 * Revision 1.32  2002/06/12 01:03:47  dotd
 * can_wear_obj god please make this the last only_classs fix
 *
 * Revision 1.31  2002/06/11 23:41:43  dotd
 * barbarian magic check updated with glow, bless, hum, and invis checks
 *
 * Revision 1.30  2002/06/09 20:04:54  dotd
 * don't pass container (even though it's null) to act
 *
 * Revision 1.29  2002/06/09 15:36:22  dotd
 * brittle weapons scrap when used
 *
 * Revision 1.28  2002/06/09 15:15:40  dotd
 * make_scraps takes quiet argument to control displaying messages
 *
 * Revision 1.27  2002/02/09 16:34:03  dotd
 * added severity levels to log_prinf_plus()
 *
 * Revision 1.26  2002/02/09 15:48:21  dotd
 * added log severity to log_string()
 *
 * Revision 1.25  2002/02/09 00:05:57  dotd
 * update obj->last_carried_by on create_money's
 *
 * Revision 1.24  2002/02/06 02:01:51  dotd
 * *** empty log message ***
 *
 * Revision 1.23  2002/02/02 06:03:19  dotd
 * anti item flag updates, spellfail/skillfail tweaks, anticlass armor now
 * gives a bit more penalty to multis
 *
 * Revision 1.22  2002/01/22 04:17:20  dotd
 * *** empty log message ***
 *
 * Revision 1.21  2002/01/13 19:09:43  dotd
 * give carry weigth/number fix
 *
 * Revision 1.20  2002/01/13 06:35:41  dotd
 * *** empty log message ***
 *
 * Revision 1.19  2002/01/13 03:16:23  dotd
 * ItemSave returns bool instead of int
 *
 * Revision 1.18  2002/01/03 03:37:59  dotd
 * ItemSave, disintegrate updates
 *
 * Revision 1.17  2002/01/03 03:12:01  dotd
 * spell_disintegrate
 *
 * Revision 1.16  2002/01/01 22:29:46  dotd
 * split christen/currency/property stuff from mud.h into separate header
 * files, tweaks to currency functions
 *
 * Revision 1.15  2001/12/22 04:28:46  dotd
 * changed ch->pcdata->learned[sn] to LEARNED(ch, sn)
 *
 * Revision 1.14  2001/11/30 19:00:38  dotd
 * *** empty log message ***
 *
 * Revision 1.13  2001/06/12 04:47:26  dotd
 * fix to prevent mobs from scavenging too much money
 *
 * Revision 1.12  2001/06/09 18:18:21  dotd
 * misc changes
 *
 * Revision 1.11  2001/05/24 00:27:11  dotd
 * give gold fixed
 *
 * Revision 1.10  2001/05/22 02:57:35  dotd
 * removal of dead wood
 *
 * Revision 1.9  2001/05/09 01:25:12  dotd
 * revision touch
 *
 * Revision 1.7  2001/04/01 16:57:58  dotd
 * covering fix
 *
 * Revision 1.6  2001/03/11 01:39:39  dotd
 * litter check on npc's, they don't have litterbug flag
 *
 * Revision 1.5  2001/03/11 01:34:35  dotd
 * rewrote do_give so it handles all.obj and x obj and just plain all
 *
 * Revision 1.4  2001/02/18 01:15:29  dotd
 * missile weapon updates
 *
 * Revision 1.3  2001/02/18 01:02:58  dotd
 * missile weapon updates
 *
 * Revision 1.2  2001/02/17 16:11:17  dotd
 * notching missiles
 *
 * Revision 1.1.1.1  2001/02/03 04:23:42  dotd
 * DOTDII Sources
 *
 * Revision 1.15  1999/11/08 20:00:21  cvs
 * added default dale combat messages by race -heath
 *
 * Revision 1.14  1999/08/15 20:15:37  cvs
 * recycle lists, some misc bugs
 *
 * Revision 1.13  1999/06/29 04:35:38  cvs
 * donation room fixes
 *
 * Revision 1.12  1999/05/23 18:40:54  garil
 * *** empty log message ***
 *
 * Revision 1.11  1999/04/27 02:26:57  garil
 * currency updates
 *
 * Revision 1.10  1999/02/24 15:54:06  garil
 * *** empty log message ***
 *
 * Revision 1.9  1999/02/23 01:22:36  garil
 * major currency updates
 *
 * Revision 1.8  1999/02/08 00:56:56  garil
 * lots of misc bug fixes
 *
 * Revision 1.7  1999/01/04 20:14:17  dotd
 * removed the wizinvis flag
 *
 * Revision 1.6  1998/12/16 20:00:26  dotd
 * currency updates
 *
 * Revision 1.5  1998/12/16 19:10:00  dotd
 * added rcs id and log keywords
 *
 */

/*static char rcsid[] = "$Id: act_obj.c,v 1.59 2004/04/06 22:00:08 dotd Exp $";*/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"
#include "bet.h"
#include "gsn.h"
#include "currency.h"
#include "quest.h"

/*double sqrt( double x );*/

/*
 * Local functions.
 */
void	wear_obj	args( ( CHAR_DATA *ch, OBJ_DATA *obj, bool fReplace, sh_int wear_bit ) );

DECLARE_DO_FUN(do_donate);
DECLARE_DO_FUN(do_junk);
DECLARE_DO_FUN(do_drop);

/*
 * 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(12);
    /* metal objects are definately stronger */
    if ( IS_OBJ_STAT( obj, ITEM_METAL ) )
        resist += number_fuzzy(5);
    /* organic objects are most likely weaker */
    if ( IS_OBJ_STAT( obj, ITEM_ORGANIC ) )
        resist -= number_fuzzy(5);
    /* blessed objects should have a little bonus */
    if ( IS_OBJ_STAT( obj, ITEM_BLESS ) )
        resist += number_fuzzy(5);
    /* lets make store inventory pretty tough */
    if ( IS_OBJ_STAT( obj, ITEM_INVENTORY ) )
        resist += 20;

    /* okay... let's add some bonus/penalty for item level... */
    resist += (number_fuzzy(30) / 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;

    resist += 10;

    return URANGE(10, resist, 599);
}


bool ItemSave( OBJ_DATA *obj, int sn)
{
    AFFECT_DATA *paf;
    int num;

    if (obj->carried_by && in_arena(obj->carried_by))
        return(TRUE);

    /* obj fails save automatically it brittle */
    if (IS_OBJ_STAT2(obj, ITEM2_BRITTLE) && number_range(1,10)!=1)
        return(FALSE);

    /* this is to keep immune objects from getting dammaged */
    if (IS_OBJ_STAT2(obj, ITEM2_IMMUNE))
        return(TRUE);

    /* this is to give resistant magic items a better chance to save */
    if (IS_OBJ_STAT2(obj, ITEM2_RESISTANT) && number_percent()>50)
        return(TRUE);

    num = number_range(1,20);

    if (num <= 1)
        return(FALSE);
    if (num >= 20)
        return(TRUE);

    for (paf=obj->first_affect; paf; paf=paf->next)
    {
        if (paf->location == APPLY_SAVING_SPELL ||
            paf->location == APPLY_SAVING_ALL)
            num -= paf->modifier;

        if (paf->location != APPLY_NONE)
            num += 1;

        if (paf->location == APPLY_HITROLL)
            num += paf->modifier;
    }

    if (obj->item_type != ITEM_ARMOR)
        num += 1;

    if (IS_OBJ_STAT(obj, ITEM_METAL))
        num += 1;

    if (IS_OBJ_STAT(obj, ITEM_ORGANIC))
        num -= 1;

    if (IS_OBJ_STAT(obj, ITEM_MAGIC))
        num += 1;

    if (IS_OBJ_STAT(obj, ITEM_BLESS))
        num += 1;

    if (obj->christened)
        num += 1;

    if (num <= 1)
        return(FALSE);
    if (num >= 20)
        return(TRUE);

    if (num >= number_range(1,18))
        return(TRUE);

    return(FALSE);
}

bool barbarian_magic_check(CHAR_DATA *ch, OBJ_DATA *obj)
{
    if (IS_NPC(ch) ||
        IS_IMMORTAL(ch) ||
        !IS_ACTIVE(ch, CLASS_BARBARIAN))
        return(FALSE);

    if (IS_OBJ_STAT(obj, ITEM_MAGIC) ||
        IS_OBJ_STAT(obj, ITEM_GLOW) ||
        IS_OBJ_STAT(obj, ITEM_HUM) ||
        IS_OBJ_STAT(obj, ITEM_BLESS) ||
        IS_OBJ_STAT(obj, ITEM_INVIS))
        return(TRUE);

    return(FALSE);
}

void get_obj( CHAR_DATA *ch, OBJ_DATA *obj, OBJ_DATA *container )
{
    CLAN_DATA *clan;
    int weight, number = 0;

    if ( !CAN_WEAR(obj, ITEM_TAKE)
         && (GetMaxLevel(ch) < sysdata.level_getobjnotake )  )
    {
        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 (barbarian_magic_check(ch, obj))
    {
        act( AT_ACTION, "You sense magic on $p and drop it.", ch, obj, container, TO_CHAR );
        act( AT_ACTION, "$n recoils from $p and drops it.", ch, obj, container, TO_ROOM );
        return;
    }

    if ( obj->item_type != ITEM_MONEY &&
	carry_n(ch) + 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 ( carry_w(ch) + weight > can_carry_w( ch ) )
    {
        if ( obj->item_type == ITEM_MONEY )
            number = max_carry_money(ch, obj->value[2]);

        if ( !number )
        {
            act( AT_PLAIN, "$d: you can't carry that much weight.",
                 ch, NULL, obj->name, TO_CHAR );
            return;
        }
        else
        {
            /* Fix for money weight -Garil 12/31/2002
             * split the money into two new objects, extract the old,
             * and give the player one of the new objects
             */
            char buf[128];
            OBJ_DATA *new_obj;

            new_obj = create_money( obj->value[0]-number, obj->value[2] );
            snprintf(buf, 127, "get_obj1 %d %s", obj->vnum, obj->name);
            new_obj->last_carried_by = str_dup(buf);
            if (container)
                obj_to_obj( new_obj, container );
            else
                obj_to_room( new_obj, obj->in_room );

            new_obj = create_money( number, obj->value[2] );
            snprintf(buf, 127, "get_obj2 %d %s", obj->vnum, obj->name);
            new_obj->last_carried_by = str_dup(buf);
            if (container)
                obj_to_obj( new_obj, container );
            else
                obj_to_room( new_obj, obj->in_room );

            extract_obj( obj );

            obj = new_obj;
        }
    }

    if ( container )
    {
        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 );
        obj_from_obj( obj );
    }
    else
    {
        act( AT_ACTION, "You get $p.", ch, obj, NULL, TO_CHAR );
        act( AT_ACTION, "$n gets $p.", ch, obj, NULL, TO_ROOM );
        obj_from_room( obj );
    }

    /* Clan storeroom checks */
    if ( IS_SET(ch->in_room->room_flags, ROOM_CLANSTOREROOM)
         && (!container || container->carried_by == NULL) )
        for ( clan = first_clan; clan; clan = clan->next )
            if ( clan->storeroom == ch->in_room->vnum )
                save_clan_storeroom(ch, clan);

    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 value;

        if (obj->vnum == OBJ_VNUM_MONEY_ONE ||
            obj->vnum == OBJ_VNUM_MONEY_SOME)
            value = obj->value[0];
        else
            value = horde_worth(ch, obj->value[0]);

        if (value >= 10000)
            log_printf_plus(LOG_DEBUG, LEVEL_IMMORTAL, SEV_DEBUG, "%s got %d of type:%d coins (room %d, last carried by: %s)",
                            GET_NAME(ch), value, obj->value[2], ch->in_room->vnum, obj->last_carried_by?obj->last_carried_by:"nobody");

        GET_MONEY(ch, obj->value[2]) += value;
        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;
    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 ( (carry_n(ch) + 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 ( IS_DONATION(ch->in_room) )
                obj = get_obj_list( ch, arg1, DONATION_ROOM()->first_content );
            else
                obj = get_obj_list( ch, arg1, ch->in_room->first_content );
            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 ( 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 ( !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;
            for ( obj = ch->in_room->first_content; obj; obj = obj_next )
            {
                obj_next = obj->next_content;
                if ( ( fAll || nifty_is_name( chk, obj->name ) )
                     &&   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)
                         ||   carry_n(ch) >= can_carry_n( ch )
                         ||   carry_w(ch) >= 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( "I see nothing here.\n\r", ch );
                else
                    act( AT_PLAIN, "I 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, "I 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 ( carry_w(ch) + 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:
            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 ( IS_OBJ_STAT( container, ITEM_CLANCORPSE )
                     &&  !IS_NPC(ch) && (get_timer( ch, TIMER_PKILLED ) > 0 )
                     && str_cmp( name, ch->name ) )
                {
                    send_to_char( "You cannot loot from that corpse...yet.\n\r", ch );
                    return;
                }

                if ( IS_OBJ_STAT( container, ITEM_CLANCORPSE )
                     &&  !IS_NPC(ch) && IS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) )
                    break;

                if ( str_cmp( name, ch->name ) && !IS_IMMORTAL(ch) )
                {
                    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 ( !fGroup )
                    {
                        send_to_char( "That's someone else's corpse.\n\r", ch );
                        return;
                    }
                }
            }
        }

        if ( !IS_OBJ_STAT(container, ITEM_COVERING )
             &&    IS_SET(container->value[1], CONT_CLOSED) )
        {
            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) ?
                     "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 ( 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_OBJ_STAT( container, ITEM_DONATION ) )
            {
                send_to_char( "The gods frown upon such an act of greed!\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( chk, obj->name ) )
                     &&   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)
                         ||   carry_n(ch) >= can_carry_n( ch )
                         ||   carry_w(ch) >= can_carry_w( ch )
                         ||   (number && cnt >= number) )
                        return;
                }
            }

            if ( !found )
            {
                if ( fAll )
                    act( AT_PLAIN, IS_OBJ_STAT(container, ITEM_COVERING) ?
                         "I see nothing beneath the $T." :
                         "I see nothing in the $T.",
                         ch, NULL, arg2, TO_CHAR );
                else
                    act( AT_PLAIN, IS_OBJ_STAT(container, ITEM_COVERING) ?
                         "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 && 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;
    CLAN_DATA *clan;
    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"))
         &&   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, "I 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 ( carry_w(ch) + container->weight > can_carry_w( ch ) )
        {
            send_to_char( "It's too heavy for you to lift.\n\r", ch );
            return;
        }
    }
    else
    {
        if ( container->item_type != ITEM_CONTAINER )
        {
            send_to_char( "That's not a container.\n\r", ch );
            return;
        }

        if ( IS_SET(container->value[1], CONT_CLOSED) )
        {
            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 ( !can_drop_obj( ch, obj ) )
        {
            send_to_char( "You can't let go of it.\n\r", ch );
            return;
        }

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

        if ( (get_obj_weight( obj ) / obj->count)
             + (get_obj_weight( container ) / container->count)
             >  container->value[0] )
        {
            send_to_char( "It won't fit.\n\r", ch );
            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, 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);
        /* Clan storeroom check */
        if ( IS_SET(ch->in_room->room_flags, ROOM_CLANSTOREROOM)
             &&   container->carried_by == NULL)
            for ( clan = first_clan; clan; clan = clan->next )
                if ( clan->storeroom == ch->in_room->vnum )
                    save_clan_storeroom(ch, clan);
    }
    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' */
        for ( obj = ch->first_carrying; obj; obj = obj_next )
        {
            obj_next = obj->next_content;

            if ( ( fAll || nifty_is_name( chk, obj->name ) )
                 &&   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 ( IS_SET(ch->in_room->room_flags, ROOM_CLANSTOREROOM)
             && container->carried_by == NULL )
            for ( clan = first_clan; clan; clan = clan->next )
                if ( clan->storeroom == ch->in_room->vnum )
                    save_clan_storeroom(ch, clan);
    }

    return;
}


void do_drop( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH], buf[128];
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    ROOM_INDEX_DATA *room;
    bool found;
    CLAN_DATA *clan;
    int number;

    if ( ch->last_cmd == do_donate && DONATION_ROOM())
        room = DONATION_ROOM();
    else
        room = ch->in_room;

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

    if ( arg[0] == '\0' )
    {
        if ( ch->last_cmd == do_donate && DONATION_ROOM())
            send_to_char( "Donate what?\n\r", ch );
        else
        if ( ch->last_cmd == do_junk)
            send_to_char( "Junk what?\n\r", ch );
        else
            send_to_char( "Drop what?\n\r", ch );
        return;
    }

    if ( ms_find_obj(ch) )
        return;

    if ( ch->last_cmd != do_junk &&
         (IS_SET( room->room_flags, ROOM_NODROP ) ||
          (!IS_NPC(ch) && IS_SET( ch->act, PLR_LITTERBUG)) ) )
    {
        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 && !(ch->last_cmd == do_junk) )
    {
        int type;
        /* 'drop NNNN coins' */

        if ( (type=get_currency_type(arg)) )
        {
            if ( GET_MONEY(ch,type) < number )
            {
                ch_printf(ch, "You haven't got that much %s.\n\r", curr_types[type] );
                return;
            }

            GET_MONEY(ch,type) -= number;

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

                switch ( obj->vnum )
                {
                case OBJ_VNUM_MONEY_ONE:
                    if (obj->value[2]==type)
                    {
                        number += 1;
                        extract_obj( obj );
                    }
                    break;

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

            act( AT_ACTION, "$n drops some $T.", ch, NULL, curr_types[type], TO_ROOM );

            obj = create_money(number, type);
            snprintf(buf, 127, "drop %d %s", ch->vnum, ch->name);
            obj->last_carried_by = str_dup(buf);

            obj_to_room( obj, room );
            send_to_char( "Ok.\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 );
        if ( ch->last_cmd == do_donate && DONATION_ROOM())
        {
            act( AT_ACTION, "$n donates $p.", ch, obj, NULL, TO_ROOM );
            act( AT_ACTION, "You donate $p.", ch, obj, NULL, TO_CHAR );
        } else if ( ch->last_cmd == do_junk)
        {
            act( AT_ACTION, "$n junks $p.", ch, obj, NULL, TO_ROOM );
            act( AT_ACTION, "You junk $p.", ch, obj, NULL, TO_CHAR );
        } else {
            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 );
        if (ch->last_cmd == do_junk)
        {
           extract_obj(obj);
           return;
        }
        obj = obj_to_room( obj, room );

        quest_trigger_objplace(ch, obj, room);

        oprog_drop_trigger ( ch, obj );   /* mudprogs */

        if( char_died(ch) || obj_extracted(obj) )
            return;
        /* Clan storeroom saving */
        if ( IS_SET(room->room_flags, ROOM_CLANSTOREROOM) )
            for ( clan = first_clan; clan; clan = clan->next )
                if ( clan->storeroom == room->vnum )
                    save_clan_storeroom(ch, clan);
    }
    else
    {
        int cnt = 0;
        char *chk;
        bool fAll;

        if ( !str_cmp(arg, "all") )
        {
            if ( ch->last_cmd == do_junk )
            {
                send_to_char("Use 'junk all.really' if you're sure.\n\r", ch);
		return;
	    }
            fAll = TRUE;
        }
        else if ( !str_cmp(arg, "all.really") && ch->last_cmd == do_junk )
            fAll = TRUE;
        else
            fAll = FALSE;
        if ( number > 1 )
            chk = arg;
        else
            chk = &arg[4];
        /* 'drop all' or 'drop all.obj' */
        if ( IS_SET( room->room_flags, ROOM_NODROPALL )
             ||   IS_SET( room->room_flags, ROOM_CLANSTOREROOM ) )
        {
            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( 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 );
                }
                if ( ch->last_cmd == do_donate && DONATION_ROOM())
                {
                    act( AT_ACTION, "$n donates $p.", ch, obj, NULL, TO_ROOM );
                    act( AT_ACTION, "You donate $p.", ch, obj, NULL, TO_CHAR );
                } else if ( ch->last_cmd == do_junk)
                {
                    act( AT_ACTION, "$n junks $p.", ch, obj, NULL, TO_ROOM );
                    act( AT_ACTION, "You junk $p.", ch, obj, NULL, TO_CHAR );
                } else {
                    act( AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM );
                    act( AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR );
                }
                if (ch->last_cmd == do_junk)
                { extract_obj(obj);
                } else {
                obj = obj_to_room( obj, room );

                quest_trigger_objplace(ch, obj, room);

                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;
    int number;
    int type;
    OBJ_DATA *obj_next;
    bool fAll = FALSE, found = FALSE;
    char *chk;
    sh_int cnt = 0;


    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 );
    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 ( number && (type = get_currency_type(arg1)))
    {
        if ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
        {
            send_to_char( "They aren't here.\n\r", ch );
            return;
        }

        if ( victim == ch )
        {
            send_to_char("Riiiiight... give yourself money.\n\r", ch);
            return;
        }

        if ( GET_MONEY(ch,type) < number )
        {
            ch_printf(ch, "Very generous of you, but you haven't got that much %s.\n\r", curr_types[type] );
            return;
        }

        if ((money_weight(number, type)+carry_w(victim)) >= can_carry_w( victim ))
        {
            act( AT_ACTION, "$N can't carry any more.", ch, NULL, victim, TO_CHAR );
            return;
        }

        GET_MONEY(ch,type)     -= number;
        GET_MONEY(victim,type) += number;

        sprintf(buf, "$n gives you %d %s coins.", number, curr_types[type]);
        act( AT_ACTION, buf, ch, NULL, victim, TO_VICT    );
        sprintf(buf, "$n gives $N some %s coins.", curr_types[type]);
        act( AT_ACTION, buf,  ch, NULL, victim, TO_NOTVICT );
        sprintf(buf, "You give $N %d %s coins.", number, curr_types[type]);
        act( AT_ACTION, buf,  ch, NULL, victim, TO_CHAR    );
        send_to_char( "OK.\n\r", ch );
        mprog_bribe_trigger( victim, ch, number );
        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 ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
    {
        send_to_char( "They aren't here.\n\r", ch );
        return;
    }

    if ( victim == ch )
    {
        send_to_char("Riiiight.... give yourself stuff...\n\r", ch);
        return;
    }

    chk = arg1;
    if ( !str_cmp(arg1, "all") )
    {
        fAll = TRUE;
        number = 0;
    }
    else if ( !str_prefix("all.", arg1) )
    {
        chk = &arg1[4];
        number = 0;
    }
    else if ( !number)
        number = 1;

    for ( obj = ch->first_carrying; obj; obj = obj_next )
    {
        obj_next = obj->next_content;
        if ( ( fAll || nifty_is_name( chk, obj->name ) ) &&
             can_see_obj( ch, obj ) )
        {
            if ( !can_drop_obj( ch, obj ) )
            {
                act( AT_PLAIN, "You cannot let go of $p.", ch, obj, NULL, TO_CHAR );
                continue;
            }

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

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

            if (barbarian_magic_check(victim, obj))
            {
                act( AT_PLAIN, "$N refuses to take it.", ch, NULL, victim, TO_CHAR );
                act( AT_PLAIN, "$n tries to give $N $p but $E refuses to take it.", ch, obj, victim, TO_ROOM );
                act( AT_PLAIN, "$n tries to give you $p but you sense magic and refuse.", ch, obj, victim, TO_VICT );
                continue;
            }

            if ( IS_OBJ_STAT( obj, ITEM_PROTOTYPE ) && !can_take_proto( victim ) )
            {
                act( AT_PLAIN, "You cannot give $p to $N!", ch, obj, victim, TO_CHAR );
                continue;
            }

            if ((number+carry_n(victim)) >= can_carry_n( victim ) ||
                ((obj->weight*number)+carry_w(victim)) >= can_carry_w( victim ))
            {
                act( AT_ACTION, "$N can't carry any more.", ch, NULL, victim, TO_CHAR );
                return;
            }

            found = TRUE;
            if ( number && (cnt + obj->count) > number )
                split_obj( obj, number - cnt );
            cnt += obj->count;

            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 );

            quest_trigger_objgive(ch, 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);

            if (char_died(ch) || char_died(victim) ||
                (number && cnt >= number))
                return;
        }
    }

    if ( !found )
    {
        if ( fAll )
            send_to_char( "You had nothing to give them.\n\r", ch );
        else
            act(AT_PLAIN, "You have no $T.", ch, NULL, chk, TO_CHAR );
    }
}

/*
 * 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;

    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 rNONE;

    if (IS_OBJ_STAT2(obj, ITEM2_BRITTLE))
    {
        make_scraps( obj, FALSE );
        return rOBJ_SCRAPPED;
    }

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


/*
 * Remove an object.
 */
bool remove_obj( CHAR_DATA *ch, int iWear, bool fReplace )
{
    OBJ_DATA *obj, *tmpobj = NULL;

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

    if ( !fReplace
         &&   carry_n(ch) + 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 FALSE;
    }

    if ( !fReplace )
        return FALSE;

    if ( IS_OBJ_STAT(obj, ITEM_NOREMOVE) )
    {
        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( CHAR_DATA *ch )
{
    if ( IS_NPC(ch) )
        return TRUE;
    if ( LEARNED(ch, gsn_dual_wield) )
        return TRUE;

    return FALSE;
}

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

    if ( get_eq_char( ch, WEAR_DUAL_WIELD ) )
    {
        send_to_char( "You are already wielding two weapons!\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;
    }
    if ( get_eq_char( ch, WEAR_HOLD ) )
    {
        send_to_char( "You cannot dual wield while holding something!\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;
}

int item_ego( OBJ_DATA *obj )
{
    int obj_ego;

    obj_ego = obj->rent;

    if (
        strstr(obj->name,"scroll") ||
        strstr(obj->name,"potion") ||
        strstr(obj->name,"bag") ||
        strstr(obj->name,"key")
       )
    {
        return(0);
    }

    if (obj_ego < 0)
        obj_ego = 50000;

    if (obj_ego > 100000)
        obj_ego /= 250;
    else if (obj_ego < 5000)
        obj_ego /= 200;
    else
        obj_ego /= 500;

    return(obj_ego + number_range(1,6));
}

int char_ego( CHAR_DATA *ch )
{
    int p_ego, tmp;

    if (!IS_NPC(ch))
    {
        p_ego = GetMaxLevel(ch)+HowManyClasses(ch);

        if (p_ego>45) p_ego *= (p_ego-44);
        if (p_ego>40) p_ego += (p_ego-40);
        if (p_ego>30) p_ego += (p_ego-30);
        if (p_ego>20) p_ego += (p_ego-20);

/*
        if (p_ego > 40)
            p_ego += (p_ego-39);
        else if (p_ego > 20)
            p_ego += (p_ego-20);
*/
    }
    else
    {
        p_ego = 10000;
    }

    tmp = get_curr_int(ch)+get_curr_wis(ch)+get_curr_cha(ch);
    tmp /= 3;

    tmp *= GET_HIT(ch);
    tmp /= UMAX(1,GET_MAX_HIT(ch));

    return(p_ego + tmp + number_range(1,6));
}


bool obj_is_anti_class(CHAR_DATA *ch, OBJ_DATA *obj)
{
    sh_int i;
    bool cflag = FALSE;

    for (i = FIRST_CLASS; i < MAX_CLASS; i++)
    {
        if (IS_ACTIVE(ch, i))
        {
            cflag = FALSE;

            switch (i)
            {
            case CLASS_NONE:
            case LAST_CLASS:
                /* bugger */
                break;
            case CLASS_MAGE:
            case CLASS_SORCERER:
                if (IS_OBJ_STAT(obj, ITEM_ANTI_MAGE))          cflag = TRUE;
                break;
            case CLASS_CLERIC:
                if (IS_OBJ_STAT(obj, ITEM_ANTI_CLERIC))        cflag = TRUE;
                break;
            case CLASS_THIEF:
                if (IS_OBJ_STAT(obj, ITEM_ANTI_THIEF))         cflag = TRUE;
                break;
            case CLASS_WARRIOR:
                if (IS_OBJ_STAT(obj, ITEM_ANTI_WARRIOR))       cflag = TRUE;
                break;
            case CLASS_VAMPIRE:
                if (IS_OBJ_STAT(obj, ITEM_ANTI_VAMPIRE))       cflag = TRUE;
                break;
            case CLASS_DRUID:
                if (IS_OBJ_STAT(obj, ITEM_ANTI_DRUID))         cflag = TRUE;
                break;
            case CLASS_RANGER:
                if (IS_OBJ_STAT2(obj, ITEM2_ANTI_RANGER))      cflag = TRUE;
                break;
            case CLASS_AMAZON:
                if (IS_OBJ_STAT2(obj, ITEM2_ANTI_AMAZON))      cflag = TRUE;
                break;
            case CLASS_PALADIN:
                if (IS_OBJ_STAT2(obj, ITEM2_ANTI_PALADIN))     cflag = TRUE;
                break;
            case CLASS_BARBARIAN:
                if (IS_OBJ_STAT2(obj, ITEM2_ANTI_BARBARIAN))   cflag = TRUE;
                break;
            case CLASS_PSIONIST:
                if (IS_OBJ_STAT2(obj, ITEM2_ANTI_PSI))         cflag = TRUE;
                break;
            case CLASS_ARTIFICER:
                if (IS_OBJ_STAT2(obj, ITEM2_ANTI_ARTIFICER))   cflag = TRUE;
                break;
            case CLASS_MONK:
                if (IS_OBJ_STAT2(obj, ITEM2_ANTI_MONK))        cflag = TRUE;
                break;
            case CLASS_NECROMANCER:
                if (IS_OBJ_STAT2(obj, ITEM2_ANTI_NECROMANCER)) cflag = TRUE;
                break;
            case CLASS_ANTIPALADIN:
                if (IS_OBJ_STAT2(obj, ITEM2_ANTI_APALADIN))    cflag = TRUE;
                break;
            }

            if (cflag && IS_OBJ_STAT2(obj, ITEM2_ONLY_CLASS))
                return FALSE;

            if (!cflag && !IS_OBJ_STAT2(obj, ITEM2_ONLY_CLASS))
                return FALSE;
        }
    }
    return TRUE;
}


int can_wear_obj(CHAR_DATA *ch, OBJ_DATA *obj)
{
    if (ch->sex == SEX_MALE && IS_OBJ_STAT2(obj, ITEM2_ANTI_MEN))
	return FALSE;
    if (ch->sex == SEX_FEMALE && IS_OBJ_STAT2(obj, ITEM2_ANTI_WOMEN))
	return FALSE;
    if (ch->sex == SEX_NEUTRAL && IS_OBJ_STAT2(obj, ITEM2_ANTI_NEUTER))
	return FALSE;

    if (obj_is_anti_class(ch, obj))
        return FALSE;

    return TRUE;
}

/*
 * 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( CHAR_DATA *ch, OBJ_DATA *obj, bool fReplace, sh_int wear_bit )
{
    char buf[MAX_STRING_LENGTH];
    OBJ_DATA *tmpobj;
    sh_int bit, tmp;

    separate_obj( obj );

    if ( char_ego( ch ) < item_ego( obj ) )
    {
        sprintf( buf, "You can't figure out how to use it.\n\r" );
        send_to_char( buf, ch );
        act( AT_ACTION, "$n tries to use $p, but can't figure it out.",
             ch, obj, NULL, TO_ROOM );
        return;
    }

    if (barbarian_magic_check(ch, obj))
    {
        act( AT_PLAIN, "You sense magic on $p and drop it.", ch, obj, NULL, TO_CHAR );
        act( AT_PLAIN, "$n recoils from $p and drops it.", ch, obj, NULL, TO_ROOM );
        obj_from_char(obj);
        obj_to_room(obj, ch->in_room);
        return;
    }

    if ( !can_wear_obj(ch, obj))
    {
        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 ( !CAN_WEAR(obj, 1 << bit) )
        {
            if ( fReplace )
            {
                switch( 1 << bit )
                {
                case ITEM_HOLD:
                    send_to_char( "You cannot hold that.\n\r", ch );
                    break;
                case ITEM_MISSILE_WIELD:
                case ITEM_WIELD:
                    send_to_char( "You cannot wield that.\n\r", ch );
                    break;
                default:
                    sprintf( buf, "You cannot wear that on your %s.\n\r",
                             w_flags[bit] );
                    send_to_char( buf, ch );
                }
            }
            return;
        }
    }
    else
    {
        for ( bit = -1, tmp = 1; tmp < 31; tmp++ )
        {
            if ( CAN_WEAR(obj, 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 )
            send_to_char( "You can't wear, wield, or hold that.\n\r", ch );
        return;
    }

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

    case ITEM_WEAR_FINGER:
        if ( !HAS_BODYPART(ch, PART_FINGERS) )
           {
             send_to_char("How? You have no fingers!\n\r", ch);
             return;
           }

        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 ) &&
                 !actiondesc(ch,obj,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 ) &&
                 !actiondesc(ch,obj,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." );
        send_to_char( "You already wear something on both fingers.\n\r", ch );
        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 ( !HAS_BODYPART(ch, PART_HEAD) )
           {
             send_to_char("How? You have no neck, no head for that matter!\n\r", ch);
             return;
           }


        if ( !get_eq_char( ch, WEAR_NECK_1 ) )
        {
            if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
                 !actiondesc(ch,obj,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 ) &&
                 !actiondesc(ch,obj,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." );
        send_to_char( "You already wear two neck items.\n\r", ch );
        return;

    case ITEM_WEAR_BODY:
        /*
         if ( !remove_obj( ch, WEAR_BODY, fReplace ) )
         return;
         */

        if ( !can_layer( ch, obj, WEAR_BODY ) )
        {
            send_to_char( "It won't fit overtop of what you're already wearing.\n\r", ch );
            return;
        }
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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_BACK:
        /*
         if ( !remove_obj( ch, WEAR_BACK, fReplace ) )
         return;
         */
        if ( !can_layer( ch, obj, WEAR_BACK ) )
        {
            send_to_char( "It won't fit overtop of what you're already wearing.\n\r", ch );
            return;
        }
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,NULL) )
        {
            act( AT_ACTION, "$n fits $p on $s back.",   ch, obj, NULL, TO_ROOM );
            act( AT_ACTION, "You fit $p on your back.", ch, obj, NULL, TO_CHAR );
        }
        equip_char( ch, obj, WEAR_BACK );
        oprog_wear_trigger( ch, obj );
        return;

    case ITEM_WEAR_HEAD:
        if ( !HAS_BODYPART(ch, PART_HEAD) )
           {
             send_to_char("How? You have no head!\n\r", ch);
             return;
           }

        if ( !remove_obj( ch, WEAR_HEAD, fReplace ) )
            return;
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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 ( !HAS_BODYPART(ch, PART_EYE) && !HAS_BODYPART(ch, PART_EYESTALKS))
           {
             send_to_char("How? You have no eyes!\n\r", ch);
             return;
           }
        if ( !remove_obj( ch, WEAR_EYES, fReplace ) )
            return;
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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_NOSE:
        if ( !HAS_BODYPART(ch, PART_HEAD) && !HAS_BODYPART(ch, PART_BEAK))
           {
             send_to_char("How? You have no nose!\n\r", ch);
             return;
           }
        if ( !remove_obj( ch, WEAR_NOSE, fReplace ) )
            return;
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,NULL) )
        {
            act( AT_ACTION, "$n places $p in $s nose.",   ch, obj, NULL, TO_ROOM );
            act( AT_ACTION, "You place $p in your nose.", ch, obj, NULL, TO_CHAR );
        }
        equip_char( ch, obj, WEAR_NOSE );
        oprog_wear_trigger( ch, obj );
        return;

    case ITEM_WEAR_EARS:
        if ( !HAS_BODYPART(ch, PART_EAR) )
           {
             send_to_char("How? You have no ears!\n\r", ch);
             return;
           }
        if ( get_eq_char( ch, WEAR_EAR_L ) != NULL
             &&   get_eq_char( ch, WEAR_EAR_R ) != NULL
             &&   !remove_obj( ch, WEAR_EAR_L, fReplace )
             &&   !remove_obj( ch, WEAR_EAR_R, fReplace ) )
            return;

        if ( !get_eq_char( ch, WEAR_EAR_L ) )
        {
            if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
                 !actiondesc(ch,obj,NULL) )
            {
                act( AT_ACTION, "$n wears $p on $s ear.",   ch, obj, NULL, TO_ROOM );
                act( AT_ACTION, "You wear $p on your ear.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_EAR_L );
            oprog_wear_trigger( ch, obj );
            return;
        }

        if ( !get_eq_char( ch, WEAR_EAR_R ) )
        {
            if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
                 !actiondesc(ch,obj,NULL) )
            {
                act( AT_ACTION, "$n wears $p on $s ear.",   ch, obj, NULL, TO_ROOM );
                act( AT_ACTION, "You wear $p on your ear.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_EAR_R );
            oprog_wear_trigger( ch, obj );
            return;
        }

        bug( "Wear_obj: no free ear." );
        send_to_char( "You already wear two ear items.\n\r", ch );
        return;

    case ITEM_WEAR_LEGS:
        /*
         if ( !remove_obj( ch, WEAR_LEGS, fReplace ) )
         return;
         */
        if ( !HAS_BODYPART(ch, PART_LEGS) )
           {
             send_to_char("How? You have no legs!\n\r", ch);
             return;
           }
        if ( !can_layer( ch, obj, WEAR_LEGS ) )
        {
            send_to_char( "It won't fit overtop of what you're already wearing.\n\r", ch );
            return;
        }
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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 ( !HAS_BODYPART(ch, PART_FEET) )
           {
             send_to_char("How? You have no feet!\n\r", ch);
             return;
           }
        if ( !can_layer( ch, obj, WEAR_FEET ) )
        {
            send_to_char( "It won't fit overtop of what you're already wearing.\n\r", ch );
            return;
        }
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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 ( !HAS_BODYPART(ch, PART_HANDS) )
           {
             send_to_char("How? You have no hands!\n\r", ch);
             return;
           }
        if ( !can_layer( ch, obj, WEAR_HANDS ) )
        {
            send_to_char( "It won't fit overtop of what you're already wearing.\n\r", ch );
            return;
        }
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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 ( !HAS_BODYPART(ch, PART_ARMS) )
           {
             send_to_char("How? You have no arms!\n\r", ch);
             return;
           }
        if ( !can_layer( ch, obj, WEAR_ARMS ) )
        {
            send_to_char( "It won't fit overtop of what you're already wearing.\n\r", ch );
            return;
        }
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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 ) )
        {
            send_to_char( "It won't fit overtop of what you're already wearing.\n\r", ch );
            return;
        }
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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_WAIST:
        /*
         if ( !remove_obj( ch, WEAR_WAIST, fReplace ) )
         return;
         */
        if ( !can_layer( ch, obj, WEAR_WAIST ) )
        {
            send_to_char( "It won't fit overtop of what you're already wearing.\n\r", ch );
            return;
        }
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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 ( !HAS_BODYPART(ch, PART_ARMS) && !HAS_BODYPART(ch, PART_HANDS))
           {
             send_to_char("How? You have no wrists!\n\r", ch);
             return;
           }
        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 ) &&
                 !actiondesc(ch,obj,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 ) &&
                 !actiondesc(ch,obj,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." );
        send_to_char( "You already wear two wrist items.\n\r", ch );
        return;

    case ITEM_WEAR_SHIELD:
        if ( !HAS_BODYPART(ch, PART_HANDS) &&
             !HAS_BODYPART(ch, PART_CLAWS) )
           {
             send_to_char("How? You have no hands!\n\r", ch);
             return;
           }
        if ( get_eq_char( ch, WEAR_DUAL_WIELD ) ||
             (get_eq_char( ch, WEAR_WIELD ) && get_eq_char( ch, WEAR_MISSILE_WIELD)) )
        {
            send_to_char( "You can't use a shield AND two weapons!\n\r", ch );
            return;
        }
        if ( !remove_obj( ch, WEAR_SHIELD, fReplace ) )
            return;
        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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:
	{
            OBJ_DATA *fw;

            if (obj->item_type!=ITEM_PROJECTILE)
            {
                act(AT_PLAIN,"$p is not a valid missile.",ch,obj,NULL,TO_CHAR);
                return;
            }

            if ( !HAS_BODYPART(ch, PART_HANDS) )
            {
                send_to_char("How? You have no hands!\n\r", ch);
                return;
            }

            fw = get_eq_char(ch, WEAR_WIELD);

            if (!fw || fw->item_type != ITEM_MISSILE_WEAPON)
            {
                send_to_char("You must be wielding the projectile weapon you want to load.\n\r",ch);
                return;
            }

            if (get_curr_str(ch) < fw->value[0])
            {
                sprintf(log_buf,"(%s) can't load (%s) because it requires (%d) strength to wield",
                        GET_NAME(ch), fw->name, fw->value[0]);
                log_string_plus(log_buf, LOG_MONITOR, LEVEL_IMMORTAL, SEV_DEBUG);
                send_to_char("You aren't strong enough to draw such a mighty weapon.\n\r",ch);
                return;
            }

            if (obj->value[2] != fw->value[3])
            {
                act(AT_PLAIN,"You can't load $p in that sort of weapon.",ch,obj,NULL,TO_CHAR);
                return;
            }

            if ( !remove_obj( ch, WEAR_MISSILE_WIELD, fReplace ) )
                return;

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

            if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
                 !actiondesc(ch,obj,NULL) )
            {
                act( AT_ACTION, "$n loads $p.", ch, obj, NULL, TO_ROOM );
                act( AT_ACTION, "You load $p.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_MISSILE_WIELD );
            WAIT_STATE(ch, PULSE_VIOLENCE*3);
            oprog_wear_trigger( ch, obj );
            return;
        }

    case ITEM_WIELD:
        if ( !HAS_BODYPART(ch, PART_HANDS) )
        {
            send_to_char("How? You have no hands!\n\r", ch);
            return;
        }

        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) ) )
            {
                send_to_char( "You're already wielding something.\n\r", ch );
                return;
            }
        }

        if ( tmpobj )
        {
            if ( can_dual(ch) )
            {
                if ( get_obj_weight( obj ) + get_obj_weight( tmpobj ) > str_app[get_curr_str(ch)].wield )
                {
                    send_to_char( "It is too heavy for you to wield.\n\r", ch );
                    return;
                }
                if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
                     !actiondesc(ch,obj,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[get_curr_str(ch)].wield )
        {
            send_to_char( "It is too heavy for you to wield.\n\r", ch );
            return;
        }

        if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) &&
             !actiondesc(ch,obj,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_WEAR_ANKLE:
        if ( !HAS_BODYPART(ch, PART_LEGS) )
           {
             send_to_char("How? You have no ankles!\n\r", ch);
             return;
           }
        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 ) &&
                 !actiondesc(ch,obj,NULL) )
            {
                act( AT_ACTION, "$n slips $s left ankle into $p.", ch, obj, NULL, TO_ROOM );
                act( AT_ACTION, "You slip your left ankle into $p.", 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 ) &&
                 !actiondesc(ch,obj,NULL) )
            {
                act( AT_ACTION, "$n slips $s right ankle into $p.", ch, obj, NULL, TO_ROOM );
                act( AT_ACTION, "You slip your right ankle into $p.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_ANKLE_R );
            oprog_wear_trigger( ch, obj );
            return;
        }

        bug( "Wear_obj: no free ankle." );
        send_to_char( "You already wear something on both ankles.\n\r", ch );
        return;

    case ITEM_HOLD:
        if ( !HAS_BODYPART(ch, PART_HANDS)
           && !HAS_BODYPART(ch, PART_CLAWS) )
           {
             send_to_char("How? You have no hands!\n\r", ch);
             return;
           }
        if ( get_eq_char( ch, WEAR_DUAL_WIELD ) ||
             (get_eq_char( ch, WEAR_WIELD ) && get_eq_char( ch, WEAR_MISSILE_WIELD)) )
        {
            send_to_char( "You cannot hold something AND two weapons!\n\r", ch );
            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 ) )
        {
            if (!actiondesc(ch,obj,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 );
        return;
    }
}


void do_wear( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    sh_int 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' )
    {
        send_to_char( "Wear, wield, or hold what?\n\r", ch );
        return;
    }

    if ( ms_find_obj(ch) )
        return;

    if ( !str_cmp( arg1, "all" ) )
    {
        OBJ_DATA *obj_next;

        for ( obj = ch->first_carrying; obj; obj = obj_next )
        {
            obj_next = obj->next_content;
            if ( obj->wear_loc == WEAR_NONE && can_see_obj( ch, obj ) )
            {
                wear_obj( ch, obj, FALSE, -1 );
                if (char_died(ch))
                    return;
            }
        }
        return;
    }
    else
    {
        if ( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
        {
            send_to_char( "You do not have that item.\n\r", ch );
            return;
        }
        if ( arg2[0] != '\0' )
            wear_bit = get_wflag(arg2);
        else
            wear_bit = -1;
        wear_obj( ch, obj, TRUE, wear_bit );
    }

    return;
}



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


    one_argument( argument, arg );

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

    if ( ms_find_obj(ch) )
        return;

    if ( !str_cmp( arg, "all" ) )  /* SB Remove all */
    {
        for ( obj = ch->first_carrying; obj != NULL ; obj = obj_next )
        {
            obj_next = obj->next_content;
            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 )
    {
        send_to_char( "You are not using that item.\n\r", ch );
        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 );
    return;
}


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);
    if ( !CAN_WEAR(obj, ITEM_TAKE) )
    {
        if ( !IS_OBJ_STAT( obj, ITEM_CLANCORPSE )
             || IS_NPC(ch) || !IS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) )
        {
            act( AT_PLAIN, "You cannot bury $p.", ch, obj, 0, TO_CHAR );
            return;
        }
    }

    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 > GET_MOVE(ch) )
    {
        send_to_char( "You don't have the energy to bury something of that size.\n\r", ch );
        return;
    }
    GET_MOVE(ch) -= 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 );
    SET_BIT( obj->extra_flags, ITEM_BURRIED );
    WAIT_STATE( ch, URANGE( 10, move / 2, 100 ) );
    return;
}

void do_sacrifice( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];
    char name[50];
    OBJ_DATA *obj;

    one_argument( argument, arg );

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

    if ( ms_find_obj(ch) )
        return;

    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;
    }

    if ( !IS_NPC( ch ) && ch->pcdata->deity && ch->pcdata->deity->name[0] != '\0' )
    {
        strcpy( name, ch->pcdata->deity->name );
    }
    else if ( !IS_NPC( ch ) && IS_GUILDED(ch) && sysdata.guild_overseer[0] != '\0' )
    {
        strcpy( name, sysdata.guild_overseer );
    }
    else if ( !IS_NPC( ch ) && ch->pcdata->clan && ch->pcdata->clan->deity[0] != '\0' )
    {
        strcpy( name, ch->pcdata->clan->deity );
    }
    else
    {
        if (!IS_IMMORTAL(ch))
        {
            send_to_char("You do not have a deity to sacrifice it to.\n\r", ch);
            return;
        }
        strcpy( name, "Nobody");
    }

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

    GET_MONEY(ch,obj->currtype) += 1;
    if ( obj->item_type == ITEM_CORPSE_NPC ||
         obj->item_type == ITEM_CORPSE_PC )
        adjust_favor( ch, 5, 1 );
    sprintf( buf, "%s gives you one %s coin for your sacrifice.\n\r",
             name, curr_types[obj->currtype] );
    send_to_char( buf, ch );
    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) )
        return;
    separate_obj( obj );
    extract_obj( obj );
    return;
}

void do_use( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    CHAR_DATA *vch;
    OBJ_DATA *obj;
    ch_ret retcode;

    argument = one_argument( argument, arg1 );

    if ( !*arg1 )
    {
        send_to_char("Use what?\n\r", ch);
        return;
    }

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

    if ( !nifty_is_name( arg1, obj->name ) )
    {
        send_to_char( "You do not hold that in your hand.\n\r", ch );
        return;
    }

    if ( obj->item_type == ITEM_STAFF )
    {
        CHAR_DATA *vch_next;
        int sn;

        if ( ( sn = obj->value[3] ) < 0
             ||   sn >= top_sn
             ||   skill_table[sn]->spell_fun == NULL )
        {
            bug( "Do_use(staff): bad sn %d.", sn );
            return;
        }

        WAIT_STATE( ch, 2 * PULSE_VIOLENCE );

        if ( obj->value[2] > 0 )
        {
            if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
            {
                act( AT_MAGIC, "$n brandishes $p.", ch, obj, NULL, TO_ROOM );
                act( AT_MAGIC, "You brandish $p.",  ch, obj, NULL, TO_CHAR );
            }
            for ( vch = ch->in_room->first_person; vch; vch = vch_next )
            {
                vch_next	= vch->next_in_room;
                if ( !IS_NPC( vch ) && vch->pcdata->wizinvis >= LEVEL_IMMORTAL )
                    continue;
                else
                    switch ( skill_table[sn]->target )
                    {
                    default:
                        bug( "Do_use(staff): 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( obj->value[3], obj->value[0], ch, vch, NULL );
                if ( retcode == rCHAR_DIED || retcode == rBOTH_DIED )
                {
                    bug( "do_use(staff): char died" );
                    return;
                }
            }
        }

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

        return;
    }
    else if ( obj->item_type == ITEM_WAND )
    {
        char arg[MAX_INPUT_LENGTH];
        OBJ_DATA *obj2;

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

        obj2 = NULL;
        if ( arg[0] == '\0' )
        {
            if ( ch->fighting )
            {
                vch = who_fighting( ch );
            }
            else
            {
                send_to_char( "Zap whom or what?\n\r", ch );
                return;
            }
        }
        else
        {
            if ( ( vch  = get_char_room ( ch, arg ) ) == NULL
                 &&   ( obj2 = get_obj_here  ( ch, arg ) ) == NULL )
            {
                send_to_char( "You can't find it.\n\r", ch );
                return;
            }
        }

        WAIT_STATE( ch, 1 * PULSE_VIOLENCE );

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

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

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

        return;
    }

    send_to_char("You cannot use that.\n\r", ch);
}

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_HOLD ) ) == 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.", 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->in_room->first_person; vch; vch = vch_next )
        {
            vch_next	= vch->next_in_room;
	    if (char_died(vch))
		continue;
            if ( !IS_NPC( vch ) && vch->pcdata->wizinvis >= LEVEL_IMMORTAL )
                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" );
                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 );
        extract_obj( staff );
    }

    return;
}



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

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

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

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

    obj = NULL;
    if ( arg[0] == '\0' )
    {
        if ( ch->fighting )
        {
            victim = who_fighting( ch );
        }
        else
        {
            send_to_char( "Zap whom or what?\n\r", ch );
            return;
        }
    }
    else
    {
        if ( ( victim = get_char_room ( ch, arg ) ) == NULL
             &&   ( obj    = get_obj_here  ( ch, arg ) ) == NULL )
        {
            send_to_char( "You can't find it.\n\r", ch );
            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 );
        extract_obj( wand );
    }

    return;
}

/*
 * Save items in a clan storage room			-Scryn & Thoric
 */
void save_clan_storeroom( CHAR_DATA *ch, CLAN_DATA *clan )
{
    FILE *fp;
    char filename[256];
    /*    sh_int templvl; */
    OBJ_DATA *contents;

    if ( !clan )
    {
        bug( "save_clan_storeroom: Null clan pointer!" );
        return;
    }

    if ( !ch )
    {
        bug ("save_clan_storeroom: Null ch pointer!");
        return;
    }

    sprintf( filename, "%s%s.vault", CLAN_DIR, clan->filename );
    if ( ( fp = fopen( filename, "w" ) ) == NULL )
    {
        bug( "save_clan_storeroom: fopen" );
        perror( filename );
    }
    else
    {
        /*	templvl = ch->level;
         ch->level = LEVEL_HERO;	*/	/* make sure EQ doesn't get lost */
        contents = ch->in_room->last_content;
        if (contents)
            fwrite_obj(ch, contents, fp, 0, OS_CARRY );
        fprintf( fp, "#END\n" );
        /*	ch->level = templvl; */
        fclose( fp );
        return;
    }
    return;
}

/* put an item on auction, or see the stats on the current item or bet */
void do_auction (CHAR_DATA *ch, char *argument)
{
    OBJ_DATA *obj;
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];

    argument = one_argument (argument, arg1);

    if (IS_NPC(ch)) /* NPC can be extracted at any time and thus can't auction! */
        return;

    if ( ( time_info.hour > 18 || time_info.hour < 9 ) && auction->item == NULL )
    {
        set_char_color ( AT_LBLUE, ch );
        send_to_char ( "\n\rThe auctioneer has retired for the evening...\n\r", ch );
        return;
    }

    if (arg1[0] == '\0')
    {
        if (auction->item != NULL)
        {
            AFFECT_DATA *paf;
            obj = auction->item;

            /* show item data here */
            if (auction->bet > 0)
                sprintf (buf, "Current bid on this item is %d %s.\n\r",auction->bet,curr_types[auction->currtype]);
            else
                sprintf (buf, "No bids on this item have been received.\n\r");
            set_char_color ( AT_BLUE, ch );
            send_to_char (buf,ch);
            /*          spell_identify (0, LEVEL_HERO - 1, ch, auction->item); */

            sprintf( buf,
                     "Object '%s' is %s, special properties: %s %s %s.\n\rIts weight is %d, value is %d %s.\n\r",
                     obj->name,
                     aoran( item_type_name( obj ) ),
                     flag_string(obj->extra_flags, o_flags),
                     flag_string(obj->extra_flags2, o2_flags),
                     flag_string(obj->magic_flags, mag_flags),
                     obj->weight,
                     obj->cost,
                     curr_types[obj->currtype]);
            set_char_color( AT_LBLUE, ch );
            send_to_char( buf, ch );

            sprintf( buf, "Worn on: %s\n\r",
                     flag_string(obj->wear_flags -1, w_flags ) );
            send_to_char( buf, ch );

            set_char_color( AT_BLUE, ch );

            switch ( obj->item_type )
            {
            case ITEM_PILL:
            case ITEM_SCROLL:
            case ITEM_POTION:
                sprintf( buf, "Level %d spells of:", obj->value[0] );
                send_to_char( buf, ch );

                if ( obj->value[1] >= 0 && obj->value[1] < top_sn )
                {
                    send_to_char( " '", ch );
                    send_to_char( skill_table[obj->value[1]]->name, ch );
                    send_to_char( "'", ch );
                }

                if ( obj->value[2] >= 0 && obj->value[2] < top_sn )
                {
                    send_to_char( " '", ch );
                    send_to_char( skill_table[obj->value[2]]->name, ch );
                    send_to_char( "'", ch );
                }

                if ( obj->value[3] >= 0 && obj->value[3] < top_sn )
                {
                    send_to_char( " '", ch );
                    send_to_char( skill_table[obj->value[3]]->name, ch );
                    send_to_char( "'", ch );
                }

                send_to_char( ".\n\r", ch );
                break;

            case ITEM_WAND:
            case ITEM_STAFF:
                sprintf( buf, "Has %d(%d) charges of level %d",
                         obj->value[1], obj->value[2], obj->value[0] );
                send_to_char( buf, ch );

                if ( obj->value[3] >= 0 && obj->value[3] < top_sn )
                {
                    send_to_char( " '", ch );
                    send_to_char( skill_table[obj->value[3]]->name, ch );
                    send_to_char( "'", ch );
                }

                send_to_char( ".\n\r", ch );
                break;

            case ITEM_WEAPON:
                sprintf( buf, "Damage is %d to %d (average %d).\n\r",
                         obj->value[1], obj->value[2],
                         ( obj->value[1] + obj->value[2] ) / 2 );
                send_to_char( buf, ch );
                break;

            case ITEM_ARMOR:
                sprintf( buf, "Armor class is %d.\n\r", obj->value[0] );
                send_to_char( buf, ch );
                break;
            }

            /*
            for ( paf = obj->pIndexData->first_affect; paf; paf = paf->next )
                showaffect( ch, paf );
            */

            for ( paf = obj->first_affect; paf; paf = paf->next )
                showaffect( ch, paf );

            if ( ( obj->item_type == ITEM_CONTAINER ) && ( obj->first_content ) )
            {
                set_char_color( AT_OBJECT, ch );
                send_to_char( "Contents:\n\r", ch );
                show_list_to_char( obj->first_content, ch, TRUE, FALSE );
            }

            if (IS_IMMORTAL(ch))
            {
                sprintf(buf, "Seller: %s.  Bidder: %s.  Round: %d.\n\r",
                        auction->seller->name, auction->buyer->name,
                        (auction->going + 1));
                send_to_char(buf, ch);
                sprintf(buf, "Time left in round: %d.\n\r", auction->pulse);
                send_to_char(buf, ch);
            }
            return;
        }
        else
        {
            set_char_color ( AT_LBLUE, ch );
            send_to_char ( "\n\rThere is nothing being auctioned right now.  What would you like to auction?\n\r", ch );
            return;
        }
    }

    if ( IS_IMMORTAL(ch) && !str_cmp(arg1,"stop"))
    {
        if (auction->item == NULL)
        {
            send_to_char ("There is no auction to stop.\n\r",ch);
            return;
        }
        else /* stop the auction */
        {
            set_char_color ( AT_LBLUE, ch );
            sprintf (buf,"Sale of %s has been stopped by an Immortal.",
                     auction->item->short_descr);
            talk_auction (buf);
            obj_to_char (auction->item, auction->seller);
            if ( IS_SET( sysdata.save_flags, SV_AUCTION ) )
                save_char_obj(auction->seller);
            auction->item = NULL;
            if (auction->buyer != NULL && auction->buyer != auction->seller) /* return money to the buyer */
            {
                GET_MONEY(auction->buyer, auction->currtype) += auction->bet;
                send_to_char ("Your money has been returned.\n\r",auction->buyer);
            }
            return;
        }
    }

    if (!str_cmp(arg1,"bid") )
    {
        if (auction->item != NULL)
        {
            int newbet;

            if ( ch == auction->seller)
            {
                send_to_char("You can't bid on your own item!\n\r", ch);
                return;
            }

            /* make - perhaps - a bet now */
            if (argument[0] == '\0')
            {
                send_to_char ("Bid how much?\n\r",ch);
                return;
            }

            newbet = parsebet (auction->bet, argument);
            /*	    ch_printf( ch, "Bid: %d\n\r",newbet);	*/

            if (newbet < auction->starting)
            {
                send_to_char("You must place a bid that is higher than the starting bet.\n\r", ch);
                return;
            }

            /* to avoid slow auction, use a bigger amount than 100 if the bet
             is higher up - changed to 10000 for our high economy
             */

            if (newbet < (auction->bet + 1000))
            {
                send_to_char ("You must at least bid 10000 coins over the current bid.\n\r",ch);
                return;
            }

            if (newbet > GET_MONEY(ch,auction->currtype))
            {
                ch_printf(ch, "You don't have that much %s!\n\r",curr_types[auction->currtype]);
                return;
            }

            if (newbet > 2000000000)
            {
                send_to_char("You can't bid over 2 billion coins.\n\r", ch);
                return;
            }

            /* the actual bet is OK! */

            /* return the money to the last buyer, if one exists */
            if (auction->buyer != NULL && auction->buyer != auction->seller)
                GET_MONEY(auction->buyer,auction->currtype) += auction->bet;
            GET_MONEY(ch,auction->currtype) -= newbet; /* substract the money - important :) */
            if ( IS_SET( sysdata.save_flags, SV_AUCTION ) )
                save_char_obj(ch);
            auction->buyer = ch;
            auction->bet   = newbet;
            auction->going = 0;
            auction->pulse = PULSE_AUCTION; /* start the auction over again */

            sprintf (buf,"A bid of %d %s has been received on %s.\n\r",newbet,curr_types[auction->currtype],auction->item->short_descr);
            talk_auction (buf);
            return;
        }
        else
        {
            send_to_char ("There isn't anything being auctioned right now.\n\r",ch);
            return;
        }
    }

    /* finally... */
    if ( ms_find_obj(ch) )
        return;

    obj = get_obj_carry (ch, arg1); /* does char have the item ? */

    if (obj == NULL)
    {
        send_to_char ("You aren't carrying that.\n\r",ch);
        return;
    }

    if (obj->timer > 0)
    {
        send_to_char ("You can't auction objects that are decaying.\n\r", ch);
        return;
    }

    argument = one_argument (argument, arg2);

    if (arg2[0] == '\0')
    {
        auction->starting = 0;
        strcpy(arg2, "0");
    }

    if ( !is_number(arg2) )
    {
        send_to_char("You must input a number at which to start the auction.\n\r", ch);
        return;
    }

    if ( atoi(arg2) < 0 )
    {
        send_to_char("You can't auction something for less than 0 coins!\n\r", ch);
        return;
    }

    auction->currtype = get_currency_type(argument);

    if (auction->item == NULL)
        switch (obj->item_type)
        {

        default:
            act (AT_TELL, "You cannot auction $Ts.",ch, NULL, item_type_name (obj), TO_CHAR);
            return;

            /* insert any more item types here... items with a timer MAY NOT BE
             AUCTIONED!
             */
        case ITEM_LIGHT:
        case ITEM_TREASURE:
        case ITEM_POTION:
        case ITEM_CONTAINER:
        case ITEM_DRINK_CON:
        case ITEM_FOOD:
        case ITEM_PEN:
        case ITEM_BOAT:
        case ITEM_PILL:
        case ITEM_PIPE:
        case ITEM_HERB_CON:
        case ITEM_INCENSE:
        case ITEM_FIRE:
        case ITEM_RUNEPOUCH:
        case ITEM_MAP:
        case ITEM_BOOK:
        case ITEM_RUNE:
        case ITEM_MATCH:
        case ITEM_HERB:
        case ITEM_WEAPON:
        case ITEM_ARMOR:
        case ITEM_STAFF:
        case ITEM_WAND:
        case ITEM_SCROLL:
            separate_obj(obj);
            obj_from_char (obj);
            if ( IS_SET( sysdata.save_flags, SV_AUCTION ) )
                save_char_obj(ch);
            auction->item = obj;
            auction->bet = 0;
            if (auction->currtype == CURR_NONE)
                auction->currtype = obj->currtype;
            auction->buyer = ch;
            auction->seller = ch;
            auction->pulse = PULSE_AUCTION;
            auction->going = 0;
            auction->starting = atoi(arg2);

            if (auction->starting > 0)
                auction->bet = auction->starting;

            sprintf (buf, "A new item is being auctioned: %s at %d %s.", obj->short_descr, auction->starting, curr_types[auction->currtype]);
            talk_auction (buf);

            return;

        } /* switch */
    else
    {
        act (AT_TELL, "Try again later - $p is being auctioned right now!",ch,auction->item,NULL,TO_CHAR);
        WAIT_STATE( ch, 1.5 * PULSE_VIOLENCE );
        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 > 30)
    {
        bug( "object falling in loop more than 30 times" );
        extract_obj(obj);
        fall_count = 0;
        return;
    }

    if ( IS_SET( obj->in_room->room_flags, ROOM_NOFLOOR ) &&
         (pexit = get_exit(obj->in_room, DIR_DOWN)) &&
         !IS_OBJ_STAT( obj, ITEM_MAGIC ) )
    {
        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 = (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 )
             {
                 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_PLAIN, "$p falls on $n!", vch, obj, NULL, TO_ROOM );
                 act( AT_PLAIN, "$p falls on you!", vch, obj, NULL, TO_CHAR );
                 damage( vch, vch, dam*GetMaxLevel(vch), 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, TRUE);
                 }
                 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, TRUE);
                 }
                 break;
             }
        }
        obj_fall( obj, TRUE );
    }
    return;
}

void do_donate( CHAR_DATA *ch, char *argument )
{
    do_drop( ch, argument );
}

void do_junk( CHAR_DATA *ch, char *argument )
{
    do_drop( ch, argument );
}

void do_nickname( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;

    argument = one_argument( argument, arg1 );

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

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

    if ( argument[0] == '\0' )
    {
        send_to_char( "Give it what nickname?\n\r", ch );
        return;
    }

    if ( obj->nickname )
        STRFREE(obj->nickname);


    obj->nickname = STRALLOC(argument);

    act(AT_MAGIC, "You give $p the nickname '$T'", ch, obj, obj->nickname, TO_CHAR);
}