LOP/
LOP/area/
LOP/boards/
LOP/channels/
LOP/clans/
LOP/classes/
LOP/color/
LOP/councils/
LOP/deity/
LOP/races/
LOP/src/specials/
/*****************************************************************************
 * DikuMUD (C) 1990, 1991 by:                                                *
 *   Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen,   *
 *   and Katja Nyboe.                                                        *
 *---------------------------------------------------------------------------*
 * MERC 2.1 (C) 1992, 1993 by:                                               *
 *   Michael Chastain, Michael Quan, and Mitchell Tse.                       *
 *---------------------------------------------------------------------------*
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider.                    *
 *   Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
 *         gorog, Grishnakh, Nivek, Tricops, and Fireblade.                  *
 *---------------------------------------------------------------------------*
 * SMAUG 1.7 FUSS by: Samson and others of the SMAUG community.              *
 *                    Their contributions are greatly appreciated.           *
 *---------------------------------------------------------------------------*
 * LoP (C) 2006, 2007, 2008 by: the LoP team.                                *
 *---------------------------------------------------------------------------*
 *			   Object manipulation module			     *
 *****************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "h/mud.h"

/* External functions */
void write_corpses( OBJ_DATA *obj, bool dontsave );
void show_full_list_to_char( OBJ_DATA *list, CHAR_DATA *ch, bool fShort, bool fShowNothing );
void increase_gold( CHAR_DATA *ch, int amount );
void decrease_gold( CHAR_DATA *ch, int amount );
bool has_gold( CHAR_DATA *ch, int amount );
bool stop_obj_fishing( OBJ_DATA *obj );
OBJ_DATA *get_next_eq_hold( CHAR_DATA *ch, OBJ_DATA *oobj, int type );

int parsebet( const int currentbet, char *s )
{
   int number = 0, multi = 0;

   if( !s || s[0] == '\0' )
      return 0;
   if( s[0] == '+' )
   {
      if( s[1] == '\0' )
         return ( currentbet * 125 ) / 100;
      return ( currentbet * ( 100 + atoi( s + 1 ) ) ) / 100;
   }
   if( s[0] == '*' || s[0] == 'x' )
   {
      if( s[1] == '\0' )
         return ( currentbet * 2 );
      return ( currentbet * atoi( s + 1 ) );
   }
   while( s && s[0] != '\0' )
   {
      if( isdigit( s[0] ) )
      {
         if( !multi )
            number = ( number * 10 ) + ( *s - '0' );
         else
            number = ( number + ( ( *s - '0' ) * ( multi /= 10 ) ) );
      }
      else if( s[0] == 'k' || s[0] == 'K' )
         number *= ( multi = 1000 );
      else if( s[0] == 'm' || s[0] == 'M' )
         number *= ( multi = 1000000 );
      else if( s[0] == 'b' || s[0] == 'B' )
         number *= ( multi = 1000000000 );
      ++s;
      if( number < 0 )
         return -1;
   }
   return number;
}

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

   resist = number_range( 1, MAX_ITEM_IMPACT );

   /* magical items are more resistant */
   if( is_obj_stat( obj, ITEM_MAGIC ) )
      resist += number_range( 1, 12 );

   /* metal objects are definately stronger */
   if( is_obj_stat( obj, ITEM_METAL ) )
      resist += number_range( 1, 5 );

   /* organic objects are most likely weaker */
   if( is_obj_stat( obj, ITEM_ORGANIC ) )
      resist -= number_range( 1, 5 );

   /* blessed objects should have a little bonus */
   if( is_obj_stat( obj, ITEM_BLESS ) )
      resist += number_range( 1, 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 += ( obj->level / 10 ) - 2;

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

   return URANGE( 10, resist, 99 );
}

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

   if( can_wear( obj, ITEM_NO_TAKE ) && ( get_trust( ch ) < sysdata.perm_getobjnotake ) )
   {
      send_to_char( "You can't take that.\r\n", ch );
      return;
   }

   if( xIS_SET( obj->extra_flags, ITEM_PKDISARMED ) && !is_npc( ch ) )
   {
      if( can_pkill( ch ) && !get_timer( ch, TIMER_PKILLED ) )
      {
         if( ch->level - obj->value[5] > 5 || obj->value[5] - ch->level > 5 )
         {
            send_to_char( "\r\n&bA godly force freezes your outstretched hand.\r\n", ch );
            return;
         }
         else
         {
            xREMOVE_BIT( obj->extra_flags, ITEM_PKDISARMED );
            obj->value[5] = 0;
         }
      }
      else
      {
         send_to_char( "\r\n&BA godly force freezes your outstretched hand.\r\n", 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.\r\n", ch );
      return;
   }

   if( obj->item_type != ITEM_MONEY && ( ch->carry_number + get_obj_number( obj ) ) > can_carry_n( ch ) )
   {
      act( AT_PLAIN, "$T: you can't carry that many items.", ch, NULL, obj->short_descr, TO_CHAR );
      return;
   }

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

   /* Money weight shouldn't count */
   if( obj->item_type != ITEM_MONEY )
   {
      if( obj->in_obj )
      {
         OBJ_DATA *tobj = obj->in_obj;
         int inobj = 1;
         bool checkweight = false;

         /* need to make it check weight if its in a magic container */
         if( tobj->item_type == ITEM_CONTAINER && is_obj_stat( tobj, ITEM_MAGIC ) )
            checkweight = true;

         while( tobj->in_obj )
         {
            tobj = tobj->in_obj;
            inobj++;
            /* need to make it check weight if its in a magic container */
            if( tobj->item_type == ITEM_CONTAINER && is_obj_stat( tobj, ITEM_MAGIC ) )
               checkweight = true;
         }

         /* need to check weight if not carried by ch or in a magic container. */
         if( !tobj->carried_by || tobj->carried_by != ch || checkweight )
         {
            if( ( ch->carry_weight + weight ) > can_carry_w( ch ) )
            {
               act( AT_PLAIN, "$T: you can't carry that much weight.", ch, NULL, obj->short_descr, TO_CHAR );
               return;
            }
         }
      }
      else if( ( ch->carry_weight + weight ) > can_carry_w( ch ) )
      {
         act( AT_PLAIN, "$T: you can't carry that much weight.", ch, NULL, obj->short_descr, TO_CHAR );
         return;
      }

      if( obj->owner && strlen( obj->owner ) > 1 && str_cmp( obj->owner, ch->name ) )
      {
         send_to_char( "You can't get this object because your not the owner\n\r", ch );
         return;
      }
   }

   if( container )
   {
      if( container->item_type == ITEM_KEYRING && !is_obj_stat( container, ITEM_COVERING ) )
      {
         act( AT_ACTION, "You remove $p from $P", ch, obj, container, TO_CHAR );
         act( AT_ACTION, "$n removes $p from $P", ch, obj, container, TO_ROOM );
      }
      else
      {
         act( AT_ACTION, is_obj_stat( container, ITEM_COVERING ) ?
              "You get $p from beneath $P." : "You get $p from $P", ch, obj, container, TO_CHAR );
         act( AT_ACTION, is_obj_stat( container, ITEM_COVERING ) ?
              "$n gets $p from beneath $P." : "$n gets $p from $P", ch, obj, container, TO_ROOM );
      }
      if( is_obj_stat( container, ITEM_CLANCORPSE ) && !is_npc( ch ) && str_cmp( container->name + 7, ch->name ) )
         container->value[5]++;
      obj_from_obj( obj );
   }
   else
   {
      act( AT_ACTION, "You get $p.", ch, obj, container, TO_CHAR );
      act( AT_ACTION, "$n gets $p.", ch, obj, container, TO_ROOM );
      obj_from_room( obj );
   }

   /* Clan storeroom checks */
   if( xIS_SET( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) && ( !container || !container->carried_by ) )
   {
      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 ncount = obj->count;

      /*
       * Done like this because if you have a pile of gold with 2 billion in it and 20 piles
       * It doesn't work well the other way lol
       */
      while( ncount > 0 )
      {
         increase_gold( ch, obj->value[0] );
         if( xIS_SET( ch->act, PLR_AUTOSPLIT ) )
         {
            char buf1[MSL];

            snprintf( buf1, sizeof( buf1 ), "split auto %d", obj->value[0] );
            interpret( ch, buf1 );
         }
         ncount--;
      }
      extract_obj( obj );
   }
   else
      obj = obj_to_char( obj, ch );

   if( char_died( ch ) )
      return;
   oprog_get_trigger( ch, obj );
}

void show_obj( CHAR_DATA *ch, OBJ_DATA *obj )
{
   SKILLTYPE *sktmp;
   AFFECT_DATA *paf;
   int stat, cnt = 0;

   if( !ch || !obj )
   {
      bug( "%s: NULL ch or NULL obj", __FUNCTION__ );
      return;
   }

   set_char_color( AT_OBJECT, ch );
   ch_printf( ch, "\r\nObject '%s' is %s",
      obj->short_descr, aoran( o_types[ obj->item_type ] ) );
   if( !xIS_EMPTY( obj->wear_flags ) )
      ch_printf( ch, ", with wear location:  %s\r\n", ext_flag_string( &obj->wear_flags, w_flags ) );
   else
      send_to_char( ".\r\n", ch );

   ch_printf( ch, "Special properties:  %s\r\nIts weight is %d, value is %d.\r\n",
      ext_flag_string( &obj->extra_flags, o_flags ), obj->weight, obj->cost );

   ch_printf( ch, "Requirements:\r\n%12s: %3d ", "Level", obj->level );
   cnt = 1;
   for( stat = 0; stat < STAT_MAX; stat++ )
   {
      if( obj->stat_reqs[stat] <= 0 )
         continue;
      ch_printf( ch, "%12s: %3d", capitalize( stattypes[stat] ), obj->stat_reqs[stat] );
      if( ++cnt == 3 )
      {
         send_to_char( "\r\n", ch );
         cnt = 0;
      }
      else
         send_to_char( " ", ch );
   }
   if( cnt != 0 )
      send_to_char( "\r\n", ch );

   if( !xIS_EMPTY( obj->class_restrict ) )
   {
      cnt = 0;
      send_to_char( "&cClass Restrictions:\r\n&w ", ch );
      for( stat = 0; stat < MAX_PC_CLASS; stat++ )
      {
         if( class_table[stat] && xIS_SET( obj->class_restrict, stat ) )
         {
            ch_printf( ch, "%12s", class_table[stat]->name );
            if( ++cnt == 4 )
            {
               cnt = 0;
               send_to_char( "\r\n", ch );
            }
            else
               send_to_char( " ", ch );
         }
      }
      if( cnt != 0 )
         send_to_char( "\r\n", ch );
   }
   if( !xIS_EMPTY( obj->race_restrict ) )
   {
      cnt = 0;
      send_to_char( "&cRace Restrictions:\r\n&w ", ch );
      for( stat = 0; stat < MAX_PC_RACE; stat++ )
      {
         if( race_table[stat] && xIS_SET( obj->race_restrict, stat ) )
         {
            ch_printf( ch, "%12s", race_table[stat]->name );
            if( ++cnt == 4 )
            {
               cnt = 0;
               send_to_char( "\r\n", ch );
            }
            else
               send_to_char( " ", ch );
         }
      }
      if( cnt != 0 )
         send_to_char( "\r\n", ch );
   }

   set_char_color( AT_MAGIC, ch );

   switch( obj->item_type )
   {
      case ITEM_CONTAINER:
         ch_printf( ch, "%s appears to be %s.\r\n", capitalize( obj->short_descr ),
            obj->value[0] < 76 ? "of a small capacity" :
            obj->value[0] < 150 ? "of a small to medium capacity" :
            obj->value[0] < 300 ? "of a medium capacity" :
            obj->value[0] < 550 ? "of a medium to large capacity" :
            obj->value[0] < 751 ? "of a large capacity" : "of a giant capacity" );
         break;

      case ITEM_PILL:
      case ITEM_SCROLL:
      case ITEM_POTION:
         if( obj->value[1] >= 0 || obj->value[2] >= 0 || obj->value[3] >= 0 )
         {
            ch_printf( ch, "Level %d spells of:", obj->value[0] );
            if( obj->value[1] >= 0 && ( sktmp = get_skilltype( obj->value[1] ) ) )
               ch_printf( ch, " '%s'", sktmp->name );
            if( obj->value[2] >= 0 && ( sktmp = get_skilltype( obj->value[2] ) ) )
               ch_printf( ch, " '%s'", sktmp->name );
            if( obj->value[3] >= 0 && ( sktmp = get_skilltype( obj->value[3] ) ) )
               ch_printf( ch, " '%s'", sktmp->name );
            send_to_char( ".\r\n", ch );
         }
         else
            send_to_char( "Has no spells.\r\n", ch );
         break;

      case ITEM_SALVE:
         if( obj->value[4] >= 0 || obj->value[5] >= 0 )
         {
            ch_printf( ch, "Has %d(%d) applications of level %d", obj->value[1], obj->value[2], obj->value[0] );
            if( obj->value[4] >= 0 && ( sktmp = get_skilltype( obj->value[4] ) ) )
               ch_printf( ch, " '%s'", sktmp->name );
            if( obj->value[5] >= 0 && ( sktmp = get_skilltype( obj->value[5] ) ) )
               ch_printf( ch, " '%s'", sktmp->name );
            send_to_char( ".\r\n", ch );
         }
         else
            send_to_char( "Has no applications.\r\n", ch );
         break;

      case ITEM_WAND:
      case ITEM_STAFF:
         if( obj->value[3] >= 0 )
         {
            ch_printf( ch, "Has %d(%d) charges of level %d", obj->value[1], obj->value[2], obj->value[0] );
            if( obj->value[3] >= 0 && ( sktmp = get_skilltype( obj->value[3] ) ) )
               ch_printf( ch, " '%s'", sktmp->name );
            send_to_char( ".\r\n", ch );
         }
         else
            send_to_char( "Has no charges.\r\n", ch );
         break;

      case ITEM_WEAPON:
         ch_printf( ch, "Damage is %d to %d (average %d)%s\r\n",
            obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2,
            is_obj_stat( obj, ITEM_POISONED ) ? ", and is poisonous." : "." );
         break;

      case ITEM_ARMOR:
         ch_printf( ch, "Armor class is %d.\r\n", obj->value[0] );
         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 );
}

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

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

   argument = one_argument( argument, arg2 );

   /* Get type. */
   if( !arg1 || arg1[0] == '\0' )
   {
      send_to_char( "Get what?\r\n", ch );
      return;
   }

   if( ms_find_obj( ch ) )
      return;

   if( !arg2 || arg2[0] == '\0' )
   {
      if( number <= 1 && str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
      {
         /* 'get obj' */
         if( !( obj = get_obj_list( ch, arg1, ch->in_room->first_content ) ) )
         {
            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( xIS_SET( sysdata.save_flags, SV_GET ) )
            save_char_obj( ch );
      }
      else
      {
         short cnt = 0;
         bool fAll;
         char *chk;

         if( xIS_SET( ch->in_room->room_flags, ROOM_DONATION ) )
         {
            send_to_char( "The gods frown upon such a display of greed!\r\n", ch );
            return;
         }
         if( !str_cmp( arg1, "all" ) )
            fAll = true;
         else
            fAll = false;
         if( number > 1 )
            chk = arg1;
         else
            chk = &arg1[4];
         /* 'get all' or 'get all.obj' */
         found = false;
         for( obj = ch->in_room->last_content; obj; obj = obj_next )
         {
            obj_next = obj->prev_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 ) || ch->carry_number >= can_carry_n( ch )
               || ch->carry_weight >= can_carry_w( ch ) || ( number && cnt >= number ) )
               {
                  if( xIS_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.\r\n", ch );
            else
               act( AT_PLAIN, "I see no $T here.", ch, NULL, chk, TO_CHAR );
         }
         else if( xIS_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.\r\n", ch );
         return;
      }

      if( !( container = get_obj_here( ch, arg2 ) ) )
      {
         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.\r\n", ch );
               return;
            }
            if( ch->carry_weight + container->weight > can_carry_w( ch ) )
            {
               send_to_char( "It's too heavy for you to lift.\r\n", ch );
               return;
            }
            break;

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

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

            if( is_npc( ch ) )
            {
               send_to_char( "You can't do that.\r\n", 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 can't loot from that corpse...yet.\r\n", ch );
               return;
            }

            /*
             * Killer/owner loot only if die to pkill blow --Blod 
             * Added check for immortal so IMMS can get things out of
             * corpses --Shaddai 
             */
            if( is_obj_stat( container, ITEM_CLANCORPSE )
            && !is_npc( ch ) && !is_immortal( ch )
            && container->action_desc[0] != '\0'
            && str_cmp( name, ch->name )
            && str_cmp( container->action_desc, ch->name ) )
            {
               send_to_char( "You did not inflict the death blow upon this corpse.\r\n", ch );
               return;
            }

            if( is_obj_stat( container, ITEM_CLANCORPSE )
            && !is_npc( ch ) && str_cmp( name, ch->name ) && container->value[5] >= 3 )
            {
               send_to_char( "Frequent looting has left this corpse protected by the gods.\r\n", ch );
               return;
            }

            if( is_obj_stat( container, ITEM_CLANCORPSE )
            && !is_npc( ch ) && xIS_SET( ch->pcdata->flags, PCFLAG_DEADLY )
            && container->value[4] - ch->level < 6 && container->value[4] - ch->level > -6 )
               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.\r\n", 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 );
         /* Oops no wonder corpses were duping oopsie did I do that --Shaddai */
         if( container->item_type == ITEM_CORPSE_PC )
            write_corpses( container, false );
         check_for_trap( ch, container, TRAP_GET );
         if( char_died( ch ) )
            return;
         if( xIS_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!\r\n", ch );
            return;
         }

         if( is_obj_stat( container, ITEM_CLANCORPSE )
         && !is_immortal( ch ) && !is_npc( ch ) && str_cmp( ch->name, container->name + 7 ) )
         {
            send_to_char( "The gods frown upon such wanton greed!\r\n", 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 )
               || ch->carry_number >= can_carry_n( ch )
               || ch->carry_weight >= can_carry_w( ch ) || ( number && cnt >= number ) )
               {
                  if( container->item_type == ITEM_CORPSE_PC )
                     write_corpses( container, false );
                  if( found && xIS_SET( sysdata.save_flags, SV_GET ) )
                     save_char_obj( ch );
                  return;
               }
            }
         }

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

CMDF( do_put )
{
   char arg1[MIL], arg2[MIL];
   OBJ_DATA *container, *obj, *obj_next;
   CLAN_DATA *clan;
   short 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...\r\n", ch );
         return;
      }
      argument = one_argument( argument, arg1 );
   }
   else
      number = 0;

   argument = one_argument( argument, arg2 );

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

   if( !arg1 || arg1[0] == '\0' || !arg2 || arg2[0] == '\0' )
   {
      send_to_char( "Put what in what?\r\n", 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.\r\n", ch );
      return;
   }

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

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

   if( is_obj_stat( container, ITEM_COVERING ) )
   {
      if( ch->carry_weight + container->weight > can_carry_w( ch ) )
      {
         send_to_char( "It's too heavy for you to lift.\r\n", ch );
         return;
      }
   }
   else
   {
      if( container->item_type != ITEM_CONTAINER
      && container->item_type != ITEM_KEYRING
      && container->item_type != ITEM_QUIVER
      && container->item_type != ITEM_FIRE )
      {
         send_to_char( "That's not a container.\r\n", 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 ) ) )
      {
         send_to_char( "You do not have that item.\r\n", ch );
         return;
      }

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

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

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

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

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

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

      separate_obj( obj );
      separate_obj( container );
      obj_from_char( obj );
      count = obj->count;
      obj->count = 1;
      if( container->item_type == ITEM_KEYRING && !is_obj_stat( container, ITEM_COVERING ) )
      {
         act( AT_ACTION, "$n slips $p onto $P.", ch, obj, container, TO_ROOM );
         act( AT_ACTION, "You slip $p onto $P.", ch, obj, container, TO_CHAR );
      }
      else
      {
         act( AT_ACTION, is_obj_stat( container, ITEM_COVERING )
              ? "$n hides $p beneath $P." : "$n puts $p in $P.", ch, obj, container, TO_ROOM );
         act( AT_ACTION, is_obj_stat( container, ITEM_COVERING )
              ? "You hide $p beneath $P." : "You put $p in $P.", ch, obj, container, TO_CHAR );
      }

      /* handle put triggers for container and obj */
      oprog_put_trigger( ch, obj, container );
      check_for_trap( ch, container, TRAP_PUT );
      obj->count = count;
      if( container->item_type == ITEM_FIRE )
      {
         container->timer += number_range( 1, 5 );
         extract_obj( obj );
      }
      else
         obj = obj_to_obj( obj, container );
      if( char_died( ch ) )
         return;

      /* Oops no wonder corpses were duping oopsie did I do that --Shaddai */
      if( container->item_type == ITEM_CORPSE_PC )
         write_corpses( container, false );

      if( save_char )
         save_char_obj( ch );
      /* Clan storeroom check */
      if( xIS_SET( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) && !container->carried_by )
      {
         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 )
         && ( container->item_type != ITEM_KEYRING || obj->item_type == ITEM_KEY )
         && ( container->item_type != ITEM_QUIVER || obj->item_type == ITEM_PROJECTILE )
         && ( container->item_type == ITEM_FIRE || ( 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 );
            if( container->item_type == ITEM_KEYRING )
            {
               act( AT_ACTION, "$n slips $p onto $P.", ch, obj, container, TO_ROOM );
               act( AT_ACTION, "You slip $p onto $P.", ch, obj, container, TO_CHAR );
            }
            else
            {
               act( AT_ACTION, "$n puts $p in $P.", ch, obj, container, TO_ROOM );
               act( AT_ACTION, "You put $p in $P.", ch, obj, container, TO_CHAR );
            }
            found = true;
            oprog_put_trigger( ch, obj, container );
            check_for_trap( ch, container, TRAP_PUT );
            if( container->item_type == ITEM_FIRE )
            {
               container->timer += number_range( 1, 5 );
               extract_obj( obj );
            }
            else
               obj = obj_to_obj( obj, container );
            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 aren't carrying anything.", ch, NULL, NULL, TO_CHAR );
         else
            act( AT_PLAIN, "You aren't carrying any $T.", ch, NULL, chk, TO_CHAR );
         return;
      }

      if( save_char )
         save_char_obj( ch );

      /* Oops no wonder corpses were duping oopsie did I do that -- Shaddai */
      if( container->item_type == ITEM_CORPSE_PC )
         write_corpses( container, false );

      /* Clan storeroom check */
      if( xIS_SET( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) && !container->carried_by )
      {
         for( clan = first_clan; clan; clan = clan->next )
            if( clan->storeroom == ch->in_room->vnum )
               save_clan_storeroom( ch, clan );
      }
   }
}

CMDF( do_drop )
{
   char arg[MIL];
   OBJ_DATA *obj, *obj_next;
   bool found;
   CLAN_DATA *clan;
   int number;

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

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

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

   if( ms_find_obj( ch ) )
      return;

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

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

         if( number > 2000000000 )
         {
            send_to_char( "You can't drop more then 2 billion coins at once.\r\n", ch );
            return;
         }

         decrease_gold( ch, number );

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

            switch( obj->pIndexData->vnum )
            {
               case OBJ_VNUM_MONEY_ONE:
                  if( ( number + obj->value[0] ) > 2000000000 || ( number + obj->value[0] ) < 0 )
                     continue;
                  number += 1;
                  extract_obj( obj );
                  break;

               case OBJ_VNUM_MONEY_SOME:
                  if( ( number + obj->value[0] ) > 2000000000 || ( number + obj->value[0] ) < 0 )
                     continue;
                  number += obj->value[0];
                  extract_obj( obj );
                  break;
            }
         }

         act( AT_ACTION, "$n drops some gold.", ch, NULL, NULL, TO_ROOM );
         obj_to_room( create_money( number ), ch->in_room );
         send_to_char( "You let the gold slip from your hand.\r\n", ch );
         if( xIS_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 ) ) )
      {
         send_to_char( "You do not have that item.\r\n", ch );
         return;
      }

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

      separate_obj( obj );
      act( AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM );
      act( AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR );
      obj_from_char( obj );
      obj = obj_to_room( obj, ch->in_room );
      oprog_drop_trigger( ch, obj );   /* mudprogs */

      if( char_died( ch ) )
         return;

      /* Clan storeroom saving */
      if( xIS_SET( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) )
      {
         for( clan = first_clan; clan; clan = clan->next )
            if( clan->storeroom == ch->in_room->vnum )
               save_clan_storeroom( ch, clan );
      }
   }
   else
   {
      int cnt = 0;
      char *chk;
      bool fAll;

      if( !str_cmp( arg, "all" ) )
         fAll = true;
      else
         fAll = false;
      if( number > 1 )
         chk = arg;
      else
         chk = &arg[4];
      /* 'drop all' or 'drop all.obj' */
      if( xIS_SET( ch->in_room->room_flags, ROOM_NODROPALL )
      || xIS_SET( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) )
      {
         send_to_char( "You can't seem to do that here...\r\n", 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 );
            }
            act( AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM );
            act( AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR );
            obj = obj_to_room( obj, ch->in_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 aren't carrying anything.", ch, NULL, NULL, TO_CHAR );
         else
            act( AT_PLAIN, "You aren't carrying any $T.", ch, NULL, chk, TO_CHAR );
      }
   }
   if( xIS_SET( sysdata.save_flags, SV_DROP ) )
      save_char_obj( ch ); /* duping protector */
}

CMDF( do_give )
{
   char arg1[MIL], arg2[MIL], buf[MSL];
   CHAR_DATA *victim;
   OBJ_DATA *obj;

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

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

   if( ms_find_obj( ch ) )
      return;

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

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

      if( amount > 2000000000 )
      {
         send_to_char( "Sorry, you can't give more then 2 billion coins at once.\r\n", ch );
         return;
      }

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

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

      if( !has_gold( ch, amount ) )
      {
         send_to_char( "Very generous of you, but you haven't got that much gold.\r\n", ch );
         return;
      }

      increase_gold( victim, amount );
      decrease_gold( ch, amount );
      mudstrlcpy( buf, "$n gives you ", sizeof( buf ) );
      mudstrlcat( buf, arg1, sizeof( buf ) );
      mudstrlcat( buf, ( amount > 1 ) ? " coins." : " coin.", sizeof( buf ) );

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

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

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

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

   if( obj->owner && strlen( obj->owner ) > 1 && str_cmp( obj->owner, victim->name ) )
   {
      send_to_char("You can't give this object them because they are not the owner\n\r", ch);
      return;
   }

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

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

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

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

   if( is_obj_stat( obj, ITEM_PROTOTYPE ) && !can_take_proto( victim ) )
   {
      act( AT_PLAIN, "You can't give that to $N!", ch, NULL, victim, TO_CHAR );
      return;
   }

   separate_obj( obj );
   obj_from_char( obj );
   act( AT_ACTION, "$n gives $p to $N.", ch, obj, victim, TO_NOTVICT );
   act( AT_ACTION, "$n gives you $p.", ch, obj, victim, TO_VICT );
   act( AT_ACTION, "You give $p to $N.", ch, obj, victim, TO_CHAR );
   obj = obj_to_char( obj, victim );

   mprog_give_trigger( victim, ch, obj );
   if( xIS_SET( sysdata.save_flags, SV_GIVE ) && !char_died( ch ) )
      save_char_obj( ch );
   if( xIS_SET( sysdata.save_flags, SV_RECEIVE ) && !char_died( victim ) )
      save_char_obj( victim );
}

/*
 * Damage an object.						-Thoric
 * Affect player's AC if necessary.
 * Make object into scraps if necessary.
 * Send message about damaged object.
 */
void damage_obj( OBJ_DATA *obj )
{
   CHAR_DATA *ch;
   bool scrapobj = false;

   ch = obj->carried_by;

   /* No point in bothering with this if in_arena */
   if( ch && in_arena( ch ) )
      return;

   separate_obj( obj );

   if( ch && !is_npc( ch ) )
      act( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_CHAR );
   else if( obj->in_room && ( ch = obj->in_room->first_person ) )
   {
      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 );

   switch( obj->item_type )
   {
      default:
         if( !is_obj_stat( obj, ITEM_NOSCRAP ) )
            scrapobj = true;
         break;

      case ITEM_CONTAINER:
      case ITEM_KEYRING:
      case ITEM_QUIVER:
         if( --obj->value[3] <= 0 )
         {
            if( is_obj_stat( obj, ITEM_NOSCRAP ) )
               obj->value[3] = 1;
            else
               scrapobj = true;
         }
         break;

      case ITEM_LOCKPICK:
         if( --obj->value[0] <= 0 )
         {
            if( is_obj_stat( obj, ITEM_NOSCRAP ) )
               obj->value[0] = 1;
            else
               scrapobj = true;
         }
         break;

      case ITEM_AXE:
         if( --obj->value[0] <= 0 )
         {
            if( is_obj_stat( obj, ITEM_NOSCRAP ) )
               obj->value[0] = 1;
            else
               scrapobj = true;
         }
         break;

      case ITEM_LIGHT:
         if( --obj->value[0] <= 0 )
         {
            if( is_obj_stat( obj, ITEM_NOSCRAP ) )
               obj->value[0] = 1;
            else
               scrapobj = true;
         }
         break;

      case ITEM_ARMOR:
         if( ch && obj->value[0] >= 1 )
            apply_ac( ch, obj, obj->wear_loc, true );
         if( --obj->value[0] <= 0 )
         {
            if( is_obj_stat( obj, ITEM_NOSCRAP ) )
               obj->value[0] = 1;
            else
               scrapobj = true;
         }
         if( ch && obj->value[0] >= 1 )
            apply_ac( ch, obj, obj->wear_loc, false );
         break;

      case ITEM_WEAPON:
         if( --obj->value[0] <= 0 )
         {
            if( is_obj_stat( obj, ITEM_NOSCRAP ) )
               obj->value[0] = 1;
            else
               scrapobj = true;
         }
         break;
   }
   if( scrapobj )
      make_scraps( obj );

   if( ch )
      save_char_obj( ch ); /* Stop scrap duping - Samson 1-2-00 */
}

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

   if( !( obj = get_eq_char( ch, iWear ) ) )
      return true;

   if( !fReplace )
      return false;

   if( !fReplace && ch->carry_number + get_obj_number( obj ) > can_carry_n( ch ) )
   {
      act( AT_PLAIN, "$T: you can't carry that many items.", ch, NULL, obj->short_descr, TO_CHAR );
      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->item_type == ITEM_FISHINGPOLE )
      if( stop_obj_fishing( obj ) )
         send_to_char( "You pull your line out of the water.\r\n", ch );

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

/* Have a hand free to hold something? */
bool can_hold( CHAR_DATA *ch )
{
   if( get_eq_char( ch, WEAR_HOLD_B ) )
   {
      send_to_char( "You are already holding something that requires both hands!\r\n", ch );
      return false;
   }
   if( get_eq_char( ch, WEAR_HOLD_L ) && get_eq_char( ch, WEAR_HOLD_R ) )
   {
      send_to_char( "You are already holding something in each hand!\r\n", 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, short wear_loc )
{
   OBJ_DATA *otmp;
   short bitlayers = 0;
   short objlayers = obj->pIndexData->layers;

   for( otmp = ch->first_carrying; otmp; otmp = otmp->next_content )
      if( otmp->wear_loc == wear_loc )
      {
         if( !otmp->pIndexData->layers )
            return false;
         else
            bitlayers |= otmp->pIndexData->layers;
      }

   if( ( bitlayers && !objlayers ) || bitlayers > objlayers )
      return false;
   if( !bitlayers || ( ( bitlayers & ~objlayers ) == bitlayers ) )
      return true;
   return false;
}

void wear_obj( CHAR_DATA *ch, OBJ_DATA *obj, bool fReplace, short wear_bit )
{
   short bit, tmp;
   OBJ_DATA *dw, *lh, *rh;

   separate_obj( obj );
   if( wear_bit > -1 )
   {
      bit = wear_bit;
      if( !can_wear( obj, bit ) )
      {
         if( fReplace )
         {
            switch( bit )
            {
               case ITEM_WEAR_HOLD_B:
               case ITEM_WEAR_HOLD:
                  send_to_char( "You can't hold that.\r\n", ch );
                  break;
               default:
                  ch_printf( ch, "You can't wear that on your %s.\r\n", w_flags[bit] );
                  break;
            }
         }
         return;
      }
   }
   else
   {
      for( bit = -1, tmp = 1; tmp < ITEM_WEAR_MAX; tmp++ )
      {
         if( can_wear( obj, tmp ) )
         {
            bit = tmp;
            break;
         }
      }
   }

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

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

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

      case ITEM_WEAR_EARS:
      case ITEM_WEAR_EAR:
         if( ( get_eq_char( ch, WEAR_EARS ) && !can_layer( ch, obj, WEAR_EARS ) && !remove_obj( ch, WEAR_EARS, fReplace ) )
         || ( get_eq_char( ch, WEAR_EAR_L ) && get_eq_char( ch, WEAR_EAR_R )
         && !can_layer( ch, obj, WEAR_EAR_L ) && !can_layer( ch, obj, WEAR_EAR_R )
         && !remove_obj( ch, WEAR_EAR_L, fReplace ) && !remove_obj( ch, WEAR_EAR_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_EARS );
         lh = get_eq_char( ch, WEAR_EAR_L );
         rh = get_eq_char( ch, WEAR_EAR_R );

         if( ( dw && !can_layer( ch, obj, WEAR_EARS ) )
         || ( lh && !can_layer( ch, obj, WEAR_EAR_L ) && rh && !can_layer( ch, obj, WEAR_EAR_R ) ) )
         {
            send_to_char( "You're already wearing something on both ears.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_EARS )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_EAR_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_EAR_R ) ) )
            {
               send_to_char( "You need to have both your ears free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s ears.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your ears.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_EARS );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_EARS ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_EAR_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left ear.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left ear.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_EAR_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_EAR_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right ear.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right ear.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_EAR_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free ears.", __FUNCTION__ );
         send_to_char( "You already wear something on both ears.\r\n", ch );
         return;

      case ITEM_WEAR_EYES:
      case ITEM_WEAR_EYE:
         if( ( get_eq_char( ch, WEAR_EYES ) && !can_layer( ch, obj, WEAR_EYES ) && !remove_obj( ch, WEAR_EYES, fReplace ) )
         || ( get_eq_char( ch, WEAR_EYE_L ) && get_eq_char( ch, WEAR_EYE_R )
         && !can_layer( ch, obj, WEAR_EYE_L ) && !can_layer( ch, obj, WEAR_EYE_R )
         && !remove_obj( ch, WEAR_EYE_L, fReplace ) && !remove_obj( ch, WEAR_EYE_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_EYES );
         lh = get_eq_char( ch, WEAR_EYE_L );
         rh = get_eq_char( ch, WEAR_EYE_R );

         if( ( dw && !can_layer( ch, obj, WEAR_EYES ) )
         || ( lh && !can_layer( ch, obj, WEAR_EYE_L ) && rh && !can_layer( ch, obj, WEAR_EYE_R ) ) )
         {
            send_to_char( "You're already wearing something on both eyes.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_EYES )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_EYE_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_EYE_R ) ) )
            {
               send_to_char( "You need to have both your eyes free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s eyes.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your eyes.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_EYES );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_EYES ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_EYE_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left eye.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left eye.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_EYE_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_EYE_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right eye.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right eye.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_EYE_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free eyes.", __FUNCTION__ );
         send_to_char( "You already wear something on both eyes.\r\n", ch );
         return;

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

      case ITEM_WEAR_NECK:
         if( !can_layer( ch, obj, WEAR_NECK ) && !remove_obj( ch, WEAR_NECK, fReplace ) )
            return;
         if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
         {
            act( AT_ACTION, "$n wears $p around $s neck.", ch, obj, NULL, TO_ROOM );
            act( AT_ACTION, "You wear $p around your neck.", ch, obj, NULL, TO_CHAR );
         }
         equip_char( ch, obj, WEAR_NECK );
         oprog_wear_trigger( ch, obj );
         return;

      case ITEM_WEAR_SHOULDERS:
      case ITEM_WEAR_SHOULDER:
         if( ( get_eq_char( ch, WEAR_SHOULDERS ) && !can_layer( ch, obj, WEAR_SHOULDERS ) && !remove_obj( ch, WEAR_SHOULDERS, fReplace ) )
         || ( get_eq_char( ch, WEAR_SHOULDER_L ) && get_eq_char( ch, WEAR_SHOULDER_R )
         && !can_layer( ch, obj, WEAR_SHOULDER_L ) && !can_layer( ch, obj, WEAR_SHOULDER_R )
         && !remove_obj( ch, WEAR_SHOULDER_L, fReplace ) && !remove_obj( ch, WEAR_SHOULDER_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_SHOULDERS );
         lh = get_eq_char( ch, WEAR_SHOULDER_L );
         rh = get_eq_char( ch, WEAR_SHOULDER_R );

         if( ( dw && !can_layer( ch, obj, WEAR_SHOULDERS ) )
         || ( lh && !can_layer( ch, obj, WEAR_SHOULDER_L ) && rh && !can_layer( ch, obj, WEAR_SHOULDER_R ) ) )
         {
            send_to_char( "You're already wearing something on both shoulders.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_SHOULDERS )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_SHOULDER_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_SHOULDER_R ) ) )
            {
               send_to_char( "You need to have both your shoulders free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s shoulders.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your shoulders.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_SHOULDERS );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_SHOULDERS ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_SHOULDER_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left shoulder.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left shoulder.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_SHOULDER_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_SHOULDER_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right shoulder.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right shoulder.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_SHOULDER_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free shoulders.", __FUNCTION__ );
         send_to_char( "You already wear something on both shoulders.\r\n", ch );
         return;

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

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

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

      case ITEM_WEAR_ARMS:
      case ITEM_WEAR_ARM:
         if( ( get_eq_char( ch, WEAR_ARMS ) && !can_layer( ch, obj, WEAR_ARMS ) && !remove_obj( ch, WEAR_ARMS, fReplace ) )
         || ( get_eq_char( ch, WEAR_ARM_L ) && get_eq_char( ch, WEAR_ARM_R )
         && !can_layer( ch, obj, WEAR_ARM_L ) && !can_layer( ch, obj, WEAR_ARM_R )
         && !remove_obj( ch, WEAR_ARM_L, fReplace ) && !remove_obj( ch, WEAR_ARM_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_ARMS );
         lh = get_eq_char( ch, WEAR_ARM_L );
         rh = get_eq_char( ch, WEAR_ARM_R );

         if( ( dw && !can_layer( ch, obj, WEAR_ARMS ) )
         || ( lh && !can_layer( ch, obj, WEAR_ARM_L ) && rh && !can_layer( ch, obj, WEAR_ARM_R ) ) )
         {
            send_to_char( "You're already wearing something on both arms.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_ARMS )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_ARM_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_ARM_R ) ) )
            {
               send_to_char( "You need to have both your arms free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s arms.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your arms.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_ARMS );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_ARMS ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_ARM_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left arm.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left arm.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_ARM_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_ARM_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right arm.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right arm.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_ARM_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free arms.", __FUNCTION__ );
         send_to_char( "You already wear something on both arms.\r\n", ch );
         return;

      case ITEM_WEAR_WRISTS:
      case ITEM_WEAR_WRIST:
         if( ( get_eq_char( ch, WEAR_WRISTS ) && !can_layer( ch, obj, WEAR_WRISTS ) && !remove_obj( ch, WEAR_WRISTS, fReplace ) )
         || ( get_eq_char( ch, WEAR_WRIST_L ) && get_eq_char( ch, WEAR_WRIST_R )
         && !can_layer( ch, obj, WEAR_WRIST_L ) && !can_layer( ch, obj, WEAR_WRIST_R )
         && !remove_obj( ch, WEAR_WRIST_L, fReplace ) && !remove_obj( ch, WEAR_WRIST_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_WRISTS );
         lh = get_eq_char( ch, WEAR_WRIST_L );
         rh = get_eq_char( ch, WEAR_WRIST_R );

         if( ( dw && !can_layer( ch, obj, WEAR_WRISTS ) )
         || ( lh && !can_layer( ch, obj, WEAR_WRIST_L ) && rh && !can_layer( ch, obj, WEAR_WRIST_R ) ) )
         {
            send_to_char( "You're already wearing something on both wrists.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_WRISTS )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_WRIST_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_WRIST_R ) ) )
            {
               send_to_char( "You need to have both your wrists free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s wrists.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your wrists.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_WRISTS );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_WRISTS ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_WRIST_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left wrist.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left wrist.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_WRIST_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_WRIST_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right wrist.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right wrist.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_WRIST_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free wrists.", __FUNCTION__ );
         send_to_char( "You already wear something on both wrists.\r\n", ch );
         return;

      case ITEM_WEAR_HANDS:
      case ITEM_WEAR_HAND:
         if( ( get_eq_char( ch, WEAR_HANDS ) && !can_layer( ch, obj, WEAR_HANDS ) && !remove_obj( ch, WEAR_HANDS, fReplace ) )
         || ( get_eq_char( ch, WEAR_HAND_L ) && get_eq_char( ch, WEAR_HAND_R )
         && !can_layer( ch, obj, WEAR_HAND_L ) && !can_layer( ch, obj, WEAR_HAND_R )
         && !remove_obj( ch, WEAR_HAND_L, fReplace ) && !remove_obj( ch, WEAR_HAND_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_HANDS );
         lh = get_eq_char( ch, WEAR_HAND_L );
         rh = get_eq_char( ch, WEAR_HAND_R );

         if( ( dw && !can_layer( ch, obj, WEAR_HANDS ) )
         || ( lh && !can_layer( ch, obj, WEAR_HAND_L ) && rh && !can_layer( ch, obj, WEAR_HAND_R ) ) )
         {
            send_to_char( "You're already wearing something on both hands.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_HANDS )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_HAND_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_HAND_R ) ) )
            {
               send_to_char( "You need to have both your hands free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s hands.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your hands.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_HANDS );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_HANDS ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_HAND_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left hand.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left hand.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_HAND_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_HAND_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right hand.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right hand.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_HAND_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free ears.", __FUNCTION__ );
         send_to_char( "You already wear something on both hands.\r\n", ch );
         return;

      case ITEM_WEAR_FINGERS:
      case ITEM_WEAR_FINGER:
         if( ( get_eq_char( ch, WEAR_FINGERS ) && !can_layer( ch, obj, WEAR_FINGERS ) && !remove_obj( ch, WEAR_FINGERS, fReplace ) )
         || ( get_eq_char( ch, WEAR_FINGER_L ) && get_eq_char( ch, WEAR_FINGER_R )
         && !can_layer( ch, obj, WEAR_FINGER_L ) && !can_layer( ch, obj, WEAR_FINGER_R )
         && !remove_obj( ch, WEAR_FINGER_L, fReplace ) && !remove_obj( ch, WEAR_FINGER_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_FINGERS );
         lh = get_eq_char( ch, WEAR_FINGER_L );
         rh = get_eq_char( ch, WEAR_FINGER_R );

         if( ( dw && !can_layer( ch, obj, WEAR_FINGERS ) )
         || ( lh && !can_layer( ch, obj, WEAR_FINGER_L ) && rh && !can_layer( ch, obj, WEAR_FINGER_R ) ) )
         {
            send_to_char( "You're already wearing something on both fingers.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_FINGERS )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_FINGER_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_FINGER_R ) ) )
            {
               send_to_char( "You need to have both your fingers free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s fingers.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your fingers.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_FINGERS );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_FINGERS ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_FINGER_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left finger.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left finger.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_FINGER_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_FINGER_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right finger.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right finger.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_FINGER_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free fingers.", __FUNCTION__ );
         send_to_char( "You already wear something on both fingers.\r\n", ch );
         return;

      /* Don't think we need layering here...do we? */
      case ITEM_WEAR_HOLD_B:
      case ITEM_WEAR_HOLD:
         if( !can_hold( ch ) )
            return;
         if( get_eq_char( ch, WEAR_HOLD_B ) && !remove_obj( ch, WEAR_HOLD_B, fReplace )
         || ( get_eq_char( ch, WEAR_HOLD_L ) && get_eq_char( ch, WEAR_HOLD_R )
         && !remove_obj( ch, WEAR_HOLD_L, fReplace ) && !remove_obj( ch, WEAR_HOLD_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_HOLD_B );
         lh = get_eq_char( ch, WEAR_HOLD_L );
         rh = get_eq_char( ch, WEAR_HOLD_R );

         if( dw )
         {
            send_to_char( "You're already holding something that requires both hands.\r\n", ch );
            return;
         }
         if( lh && rh )
         {
            send_to_char( "You're already holding something in each hand.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_HOLD_B )
         {
            if( lh || rh )
            {
               send_to_char( "You need to have both your hands free for this.\r\n", ch );
               return;
            }
            if( get_obj_weight( obj ) > ( get_curr_str( ch ) / 8 ) )
            {
               send_to_char( "It is to heavy for you to hold...even using both hands.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n holds $p in both $s hands.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You hold $p in both your hands.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_HOLD_B );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( ( lh && ( get_obj_weight( obj ) + get_obj_weight( lh ) ) > ( get_curr_str( ch ) / 4 ) )
         || ( rh && ( get_obj_weight( obj ) + get_obj_weight( rh ) ) > ( get_curr_str( ch ) / 4 ) ) )
         {
            send_to_char( "It is too heavy for you to hold.\r\n", ch );
            return;
         }
         if( lh )
         {
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n holds $p in $s right hand.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You hold $p in your right hand.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_HOLD_R );
         }
         else
         {
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n holds $p in $s left hand.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You hold $p in your left hand.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_HOLD_L );
         }
         oprog_wear_trigger( ch, obj );
         return;

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

      case ITEM_WEAR_LEGS:
      case ITEM_WEAR_LEG:
         if( ( get_eq_char( ch, WEAR_LEGS ) && !can_layer( ch, obj, WEAR_LEGS ) && !remove_obj( ch, WEAR_LEGS, fReplace ) )
         || ( get_eq_char( ch, WEAR_LEG_L ) && get_eq_char( ch, WEAR_LEG_R )
         && !can_layer( ch, obj, WEAR_LEG_L ) && !can_layer( ch, obj, WEAR_LEG_R )
         && !remove_obj( ch, WEAR_LEG_L, fReplace ) && !remove_obj( ch, WEAR_LEG_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_LEGS );
         lh = get_eq_char( ch, WEAR_LEG_L );
         rh = get_eq_char( ch, WEAR_LEG_R );

         if( ( dw && !can_layer( ch, obj, WEAR_LEGS ) )
         || ( lh && !can_layer( ch, obj, WEAR_LEG_L ) && rh && !can_layer( ch, obj, WEAR_LEG_R ) ) )
         {
            send_to_char( "You're already wearing something on both legs.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_LEGS )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_LEG_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_LEG_R ) ) )
            {
               send_to_char( "You need to have both your legs free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s legs.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your legs.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_LEGS );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_LEGS ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_LEG_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left leg.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left leg.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_LEG_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_LEG_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right leg.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right leg.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_LEG_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free legs.", __FUNCTION__ );
         send_to_char( "You already wear something on both legs.\r\n", ch );
         return;

      case ITEM_WEAR_ANKLES:
      case ITEM_WEAR_ANKLE:
         if( ( get_eq_char( ch, WEAR_ANKLES ) && !can_layer( ch, obj, WEAR_ANKLES ) && !remove_obj( ch, WEAR_ANKLES, fReplace ) )
         || ( get_eq_char( ch, WEAR_ANKLE_L ) && get_eq_char( ch, WEAR_ANKLE_R )
         && !can_layer( ch, obj, WEAR_ANKLE_L ) && !can_layer( ch, obj, WEAR_ANKLE_R )
         && !remove_obj( ch, WEAR_ANKLE_L, fReplace ) && !remove_obj( ch, WEAR_ANKLE_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_ANKLES );
         lh = get_eq_char( ch, WEAR_ANKLE_L );
         rh = get_eq_char( ch, WEAR_ANKLE_R );

         if( ( dw && !can_layer( ch, obj, WEAR_ANKLES ) )
         || ( lh && !can_layer( ch, obj, WEAR_ANKLE_L ) && rh && !can_layer( ch, obj, WEAR_ANKLE_R ) ) )
         {
            send_to_char( "You're already wearing something on both ankles.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_ANKLES )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_ANKLE_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_ANKLE_R ) ) )
            {
               send_to_char( "You need to have both your ankles free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s ankles.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your ankles.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_ANKLES );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_ANKLES ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_ANKLE_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left ankle.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left ankle.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_ANKLE_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_ANKLE_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right ankle.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right ankle.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_ANKLE_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free ankles.", __FUNCTION__ );
         send_to_char( "You already wear something on both ankles.\r\n", ch );
         return;

      case ITEM_WEAR_FEET:
      case ITEM_WEAR_FOOT:
         if( ( get_eq_char( ch, WEAR_FEET ) && !can_layer( ch, obj, WEAR_FEET ) && !remove_obj( ch, WEAR_FEET, fReplace ) )
         || ( get_eq_char( ch, WEAR_FOOT_L ) && get_eq_char( ch, WEAR_FOOT_R )
         && !can_layer( ch, obj, WEAR_FOOT_L ) && !can_layer( ch, obj, WEAR_FOOT_R )
         && !remove_obj( ch, WEAR_FOOT_L, fReplace ) && !remove_obj( ch, WEAR_FOOT_R, fReplace ) ) )
            return;

         dw = get_eq_char( ch, WEAR_FEET );
         lh = get_eq_char( ch, WEAR_FOOT_L );
         rh = get_eq_char( ch, WEAR_FOOT_R );

         if( ( dw && !can_layer( ch, obj, WEAR_FEET ) )
         || ( lh && !can_layer( ch, obj, WEAR_FOOT_L ) && rh && !can_layer( ch, obj, WEAR_FOOT_R ) ) )
         {
            send_to_char( "You're already wearing something on both feet.\r\n", ch );
            return;
         }
         if( bit == ITEM_WEAR_FEET )
         {
            if( ( lh && !can_layer( ch, obj, WEAR_FOOT_L ) )
            || ( rh && !can_layer( ch, obj, WEAR_FOOT_R ) ) )
            {
               send_to_char( "You need to have both your feet free for this.\r\n", ch );
               return;
            }
            if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
            {
               act( AT_ACTION, "$n wears $p on $s feet.", ch, obj, NULL, TO_ROOM );
               act( AT_ACTION, "You wear $p on your feet.", ch, obj, NULL, TO_CHAR );
            }
            equip_char( ch, obj, WEAR_FEET );
            oprog_wear_trigger( ch, obj );
            return;
         }
         if( !dw || can_layer( ch, obj, WEAR_FEET ) )
         {
            if( !lh || can_layer( ch, obj, WEAR_FOOT_L ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s left foot.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your left foot.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_FOOT_L );
               oprog_wear_trigger( ch, obj );
               return;
            }
            if( !rh || can_layer( ch, obj, WEAR_FOOT_R ) )
            {
               if( !oprog_use_trigger( ch, obj, NULL, NULL ) )
               {
                  act( AT_ACTION, "$n wears $p on $s right foot.", ch, obj, NULL, TO_ROOM );
                  act( AT_ACTION, "You wear $p on your right foot.", ch, obj, NULL, TO_CHAR );
               }
               equip_char( ch, obj, WEAR_FOOT_R );
               oprog_wear_trigger( ch, obj );
               return;
            }
         }
         bug( "%s: no free feet.", __FUNCTION__ );
         send_to_char( "You already wear something on both feet.\r\n", ch );
         return;
   }
}

CMDF( do_wear )
{
   char arg1[MIL], arg2[MIL];
   OBJ_DATA *obj;
   short wear_bit;

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

   if( !arg1 || arg1[0] == '\0' )
   {
      send_to_char( "Wear what?\r\n", 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;
         }
      }
   }
   else
   {
      if( !( obj = get_obj_carry( ch, arg1 ) ) )
      {
         send_to_char( "You do not have that item.\r\n", ch );
         return;
      }
      if( arg2[0] != '\0' )
         wear_bit = get_flag( arg2, w_flags, ITEM_WEAR_MAX );
      else
         wear_bit = -1;
      wear_obj( ch, obj, true, wear_bit );
   }
}

CMDF( do_remove )
{
   char arg[MIL];
   OBJ_DATA *obj, *obj_next;

   one_argument( argument, arg );

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

   if( ms_find_obj( ch ) )
      return;

   if( !str_cmp( arg, "all" ) )  /* SB Remove all */
   {
      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 ) )
            remove_obj( ch, obj->wear_loc, true );
      }
      return;
   }

   if( !( obj = get_obj_wear( ch, arg ) ) )
   {
      send_to_char( "You aren't using that item.\r\n", 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 );
}

CMDF( do_bury )
{
   char arg[MIL];
   OBJ_DATA *obj;
   bool shovel;
   short move;

   one_argument( argument, arg );

   if( !arg || arg[0] == '\0' )
   {
      send_to_char( "What do you wish to bury?\r\n", 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;
      }
   }

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

   separate_obj( obj );
   if( can_wear( obj, ITEM_NO_TAKE ) )
   {
      if( !is_obj_stat( obj, ITEM_CLANCORPSE ) || is_npc( ch )
      || !xIS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) )
      {
         act( AT_PLAIN, "You can't bury $p.", ch, obj, 0, TO_CHAR );
         return;
      }
   }

   if( ch->in_room->sector_type == SECT_CITY || ch->in_room->sector_type == SECT_INSIDE )
   {
      send_to_char( "The floor is too hard to dig through.\r\n", ch );
      return;
   }
   if( ch->in_room->sector_type == SECT_WATER_SWIM
   || ch->in_room->sector_type == SECT_WATER_NOSWIM
   || ch->in_room->sector_type == SECT_UNDERWATER )
   {
      send_to_char( "You can't bury something here.\r\n", ch );
      return;
   }
   if( ch->in_room->sector_type == SECT_AIR )
   {
      send_to_char( "What?  In the air?!\r\n", 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.\r\n", ch );
      return;
   }

   move = ( obj->weight * 50 * ( shovel ? 1 : 5 ) ) / UMAX( 1, can_carry_w( ch ) );
   move = URANGE( 2, move, 1000 );
   if( move > ch->move )
   {
      send_to_char( "You don't have the energy to bury something of that size.\r\n", ch );
      return;
   }
   ch->move -= move;
   if( obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC )
      adjust_favor( ch, 4, 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 );
   xSET_BIT( obj->extra_flags, ITEM_BURIED );
   wait_state( ch, URANGE( 10, move / 2, 100 ) );
}

void sacrifice_object( CHAR_DATA *ch, OBJ_DATA *obj )
{
   char buf[MSL], name[50];
   int objcount = 0;

   if( can_wear( obj, ITEM_NO_TAKE ) )
   {
      act( AT_PLAIN, "$p is not an acceptable sacrifice.", ch, obj, 0, TO_CHAR );
      return;
   }
   if( xIS_SET( obj->extra_flags, ITEM_PKDISARMED ) && !is_npc( ch ) )
   {
      if( can_pkill( ch ) && !get_timer( ch, TIMER_PKILLED ) )
      {
         if( ch->level - obj->value[5] > 5 || obj->value[5] - ch->level > 5 )
         {
            send_to_char( "\r\n&bA godly force freezes your outstretched hand.\r\n", ch );
            return;
         }
      }
   }
   if( !is_npc( ch ) && ch->pcdata->deity && ch->pcdata->deity->name[0] != '\0' )
      mudstrlcpy( name, ch->pcdata->deity->name, sizeof( name ) );
   else
      mudstrlcpy( name, "Thoric", sizeof( name ) );
   objcount = obj->count;
   increase_gold( ch, objcount );
   if( obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC )
      adjust_favor( ch, 3, objcount );
   ch_printf( ch, "%s gives you %d gold coin%s for your sacrifice.\r\n", name, objcount, objcount != 1 ? "s" : "" );
   snprintf( buf, sizeof( buf ), "$n sacrifices $p to %s.", name );
   act( AT_ACTION, buf, ch, obj, NULL, TO_ROOM );
   oprog_sac_trigger( ch, obj );
   extract_obj( obj );
}

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

   one_argument( argument, arg );
   if( !arg || 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.\r\n", ch );
      return;
   }

   if( ms_find_obj( ch ) )
      return;

   if( !str_cmp( arg, "all" ) )
   {
      for( obj = ch->in_room->first_content; obj; obj = obj_next )
      {
         obj_next = obj->next_content;
         sacrifice_object( ch, obj );
         if( char_died( ch ) )
            return;
      }
      return;
   }
   if( !( obj = get_obj_list_rev( ch, arg, ch->in_room->last_content ) ) )
   {
      send_to_char( "You can't find it.\r\n", ch );
      return;
   }
   separate_obj( obj );
   sacrifice_object( ch, obj );
}

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

   if( ( sn = staff->value[3] ) < 0 || sn >= top_sn || !skill_table[sn]->spell_fun )
   {
      bug( "%s: bad sn (%d) for value[3] on object vnum [%d].", __FUNCTION__, sn, staff->pIndexData->vnum );
      return;
   }

   wait_state( ch, 2 * PULSE_VIOLENCE );

   if( staff->value[2] > 0 )
   {
      if( !oprog_use_trigger( ch, staff, NULL, NULL ) )
      {
         act( AT_MAGIC, "$n brandishes $p.", ch, staff, NULL, TO_ROOM );
         act( AT_MAGIC, "You brandish $p.", ch, staff, NULL, TO_CHAR );
      }
      for( vch = ch->in_room->first_person; vch; vch = vch_next )
      {
         vch_next = vch->next_in_room;
         if( !is_npc( vch ) && xIS_SET( vch->act, PLR_WIZINVIS ) && get_trust( ch ) < get_trust( vch ) )
            continue;
         else
            switch( skill_table[sn]->target )
            {
               default:
                  bug( "%s: bad target for sn %d.", __FUNCTION__, 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( "%s: char died", __FUNCTION__ );
            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 );
   }
}

CMDF( do_brandish )
{
   OBJ_DATA *staff;

   if( !( staff = get_eq_hold( ch, ITEM_STAFF ) ) )
   {
      send_to_char( "You need to be holding a staff to brandish.\r\n", ch );
      return;
   }

   brandish( ch, staff );

   /* See if there is another one to brandish */
   if( ( staff = get_next_eq_hold( ch, staff, ITEM_STAFF ) ) )
      brandish( ch, staff );
}

void zap( CHAR_DATA *ch, OBJ_DATA *wand, CHAR_DATA *victim, OBJ_DATA *obj )
{
   ch_ret retcode;

   wait_state( ch, 1 * PULSE_VIOLENCE );

   if( wand->value[2] > 0 )
   {
      if( victim )
      {
         if( !oprog_use_trigger( ch, wand, victim, 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 ) )
         {
            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( "%s: char died", __FUNCTION__ );
         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 );
   }
}

CMDF( do_zap )
{
   CHAR_DATA *victim;
   OBJ_DATA *wand, *obj = NULL;

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

   if( !( wand = get_eq_hold( ch, ITEM_WAND ) ) )
   {
      send_to_char( "You need to be holding a wand to zap.\r\n", ch );
      return;
   }

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

   zap( ch, wand, victim, obj );

   /* See if there is another wand to zap with */
   if( ( wand = get_next_eq_hold( ch, wand, ITEM_WAND ) ) )
      zap( ch, wand, victim, obj );
}

/* 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;
   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( "%s", "object falling in loop more than 30 times" );
      extract_obj( obj );
      fall_count = 0;
      return;
   }

   if( xIS_SET( obj->in_room->room_flags, ROOM_NOFLOOR ) && can_go( obj->in_room, DIR_DOWN ) && !is_obj_stat( obj, ITEM_MAGIC ) )
   {
      pexit = get_exit( obj->in_room, DIR_DOWN );
      to_room = pexit->to_room;

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

      if( obj->in_room == to_room )
      {
         bug( "Object falling into same room, room %d", to_room->vnum );
         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( !xIS_SET( obj->in_room->room_flags, ROOM_NOFLOOR ) && through )
      {
         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_WHITE, "$p falls on $n!", vch, obj, NULL, TO_ROOM );
            act( AT_WHITE, "$p falls on you!", vch, obj, NULL, TO_CHAR );

            if( is_npc( vch ) && xIS_SET( vch->act, ACT_HARDHAT ) )
               act( AT_WHITE, "$p bounces harmlessly off your head!", vch, obj, NULL, TO_CHAR );
            else
               damage( vch, vch, dam * vch->level, TYPE_UNDEFINED );
         }

         /* Damage objects */
         switch( obj->item_type )
         {
            case ITEM_WEAPON:
            case ITEM_ARMOR:
               if( ( obj->value[0] - dam ) <= 0 )
               {
                  if( obj->in_room->first_person )
                  {
                     act( AT_PLAIN, "$p is destroyed by the fall!", obj->in_room->first_person, obj, NULL, TO_ROOM );
                     act( AT_PLAIN, "$p is destroyed by the fall!", obj->in_room->first_person, obj, NULL, TO_CHAR );
                  }
                  make_scraps( obj );
               }
               else
                  obj->value[0] -= dam;
               break;
            default:
               if( ( dam * 15 ) > get_obj_resistance( obj ) )
               {
                  if( obj->in_room->first_person )
                  {
                     act( AT_PLAIN, "$p is destroyed by the fall!", obj->in_room->first_person, obj, NULL, TO_ROOM );
                     act( AT_PLAIN, "$p is destroyed by the fall!", obj->in_room->first_person, obj, NULL, TO_CHAR );
                  }
                  make_scraps( obj );
               }
               break;
         }
      }
      obj_fall( obj, true );
   }
   return;
}

CMDF( do_locate )
{
   OBJ_DATA *obj, *in_obj;
   bool found = false;

   if( !ch || is_npc( ch ) )
      return;
   for( obj = first_object; obj; obj = obj->next )
   {
      if( !can_see_obj( ch, obj ) || !obj->owner || str_cmp( ch->name, obj->owner ) )
         continue;
      found = true;
      for( in_obj = obj; in_obj->in_obj; in_obj = in_obj->in_obj );
      {
         separate_obj( obj );
         ch_printf( ch, "&W%s &D", obj->short_descr );
         if( in_obj->carried_by )
            ch_printf( ch, "&Wcarried by %s.&D\n\r", PERS( in_obj->carried_by, ch ) );
         else
            ch_printf( ch, "&Win %s.&D\n\r", in_obj->in_room == NULL ? "somewhere" : in_obj->in_room->name );
      }
   }
   if( !found )
      send_to_char( "You can't locate any items belonging to you.\n\r", ch );
}

CMDF( do_claim )
{
   OBJ_DATA *obj;

   if( !ch || is_npc( ch ) )
      return;
   if( !argument || argument[0] == '\0' )
   {
      send_to_char( "What object do you wish to claim ownership of?\n\r", ch );
      return;
   }
   if( !( obj = get_obj_carry( ch, argument ) ) )
   {
      send_to_char( "You are not carrying that item.\n\r", ch );
      return;
   }
   separate_obj( obj );
   if( obj->item_type == ITEM_MONEY || obj->item_type == ITEM_TREASURE )
   {
      send_to_char( "You can't claim that item.\n\r", ch );
      return;
   }
   if( obj->owner && strlen( obj->owner ) > 1 )
   {
      if( !str_cmp( ch->name, obj->owner ) )
         send_to_char( "But you already own it!\n\r", ch );
      else
         send_to_char( "Someone else has already claimed ownership of it.\n\r", ch );
      return;
   }
   STRSET( obj->owner, ch->name );
   save_char_obj( ch );
   act( AT_PLAIN, "You are now the owner of $p.", ch, obj, NULL, TO_CHAR );
   act( AT_PLAIN, "$n is now the owner of $p.", ch, obj, NULL, TO_ROOM );
}

CMDF( do_gift )
{
   char arg1[MIL], arg2[MIL];
   OBJ_DATA *obj;
   CHAR_DATA *victim;

   if( !ch || is_npc( ch ) )
      return;
   if( !argument || argument[0] == '\0' )
   {
      send_to_char( "Make a gift of which object to whom?\n\r", ch );
      return;
   }
   argument = one_argument( argument, arg1 );
   argument = one_argument( argument, arg2 );
   if( !arg1 || arg1[0] == '\0' || !arg2 || arg2[0] == '\0' )
   {
      send_to_char( "Make a gift of which object to whom?\n\r", ch );
      return;
   }
   if( !( obj = get_obj_carry( ch, arg1 ) ) )
   {
      send_to_char( "You are not carrying that item.\n\r", ch );
      return;
   }
   if( !( victim = get_char_room( ch, arg2 ) ) )
   {
      send_to_char( "Nobody here by that name.\n\r", ch );
      return;
   }
   if( is_npc( victim ) )
   {
      send_to_char( "Not on NPC's.\n\r", ch );
      return;
   }
   if( !obj->owner || strlen( obj->owner ) < 2 )
   {
      send_to_char( "That item has not yet been claimed.\n\r", ch );
      return;
   }
   if( str_cmp( ch->name,obj->owner ) )
   {
      send_to_char( "But you don't own it!\n\r", ch );
      return;
   }
   separate_obj( obj );
   STRSET( obj->owner, victim->name );
   act( AT_PLAIN, "You grant ownership of $p to $N.", ch, obj, victim, TO_CHAR );
   act( AT_PLAIN, "$n grants ownership of $p to $N.", ch, obj, victim, TO_NOTVICT );
   act( AT_PLAIN, "$n grants ownership of $p to you.", ch, obj, victim, TO_VICT );
   obj = obj_to_char( obj, victim );
   if( !is_npc( ch ) && !char_died( ch ) )
      save_char_obj( ch );
   if( !is_npc( victim ) && !char_died( victim ) )
      save_char_obj( victim );
}

CMDF( do_call )
{
   OBJ_DATA *obj, *in_obj;
   CHAR_DATA *victim = NULL;
   DESCRIPTOR_DATA *d;
   ROOM_INDEX_DATA *chroom, *objroom;
   bool found = false;

   if( !ch || is_npc( ch ) )
      return;
   wait_state( ch, 12 );
   for( obj = first_object; obj; obj = obj->next )
   {
      separate_obj( obj );

      if( !obj->owner || strlen( obj->owner ) < 2 || str_cmp( ch->name, obj->owner )
      || obj->item_type == ITEM_CORPSE_PC )
         continue;
      for( in_obj = obj; in_obj->in_obj; in_obj = in_obj->in_obj );
         if( in_obj->carried_by )
            if( in_obj->carried_by == ch )
               continue;
      found = true;
      if( obj->carried_by )
      {
         if( obj->carried_by == ch || !obj->carried_by->desc || obj->carried_by->desc->connected != CON_PLAYING )
            if( !is_npc( obj->carried_by ) )
               return;
         act( AT_PLAIN, "$p suddenly vanishes from your hands!", obj->carried_by, obj, NULL, TO_CHAR );
         act( AT_PLAIN, "$p suddenly vanishes from $n's hands!", obj->carried_by, obj, NULL, TO_ROOM );
         obj_from_char( obj );
      }
      else if( obj->in_room )
      {
         chroom = ch->in_room;
         objroom = obj->in_room;
         char_from_room( ch );
         char_to_room( ch, objroom );
         act( AT_PLAIN, "$p vanishes from the ground!", ch, obj, NULL, TO_ROOM );
         if( chroom == objroom )
            act( AT_PLAIN, "$p vanishes from the ground!", ch, obj, NULL, TO_CHAR );
         char_from_room( ch );
         char_to_room( ch, chroom );
         obj_from_room( obj );
      }
      else if( obj->in_obj )
         obj_from_obj( obj );
      else
         continue;
      obj_to_char( obj, ch );
      act( AT_PLAIN, "$p materializes in your hands.", ch, obj, NULL, TO_CHAR );
      act( AT_PLAIN, "$p materializes in $n's hands.", ch, obj, NULL, TO_ROOM );
   }

   if( !found )
   {
      send_to_char( "Nothing you own needs to be called back to you.\n\r", ch );
      return;
   }

   /* Save everyone */
   for( d = first_descriptor; d; d = d->next )
   {
      if( d->connected != CON_PLAYING )
         continue;
      if( !( victim = d->character ) )
         continue;
      if( is_npc( victim ) )
         continue;
      save_char_obj( victim );
   }
}

CHAR_DATA *find_undertaker( CHAR_DATA *ch )
{
   CHAR_DATA *undertaker = NULL;

   for( undertaker = ch->in_room->first_person; undertaker; undertaker = undertaker->next_in_room )
   {
      if( is_npc( undertaker ) && xIS_SET( undertaker->act, ACT_UNDERTAKER ) )
         break;
   }
   return undertaker;
}

CMDF( do_retrieve )
{
   char buf2[MSL];
   OBJ_DATA *obj;
   bool found, althere, charge;
   int cost = 0;
   CHAR_DATA *ut, *rch;

   if( is_npc( ch ) )
   {
      send_to_char( "Npcs have no reason to have someone else retrieve their corpse(s).\r\n", ch );
      return;
   }

   if( !( ut = find_undertaker( ch ) ) )
   {
      send_to_char( "You can't find anyone to retrieve your corpse.\r\n", ch );
      return;
   }

   cost = ( ch->level * 10 );
   if( !has_gold( ch, cost ) )
   {
      send_to_char( "You don't have enough gold to have your corpse(s) retrieved.\r\n", ch );
      return;
   }

   found = false;
   althere = false;
   charge = false;

   snprintf( buf2, sizeof( buf2 ), "the corpse of %s", ch->name );
   for( obj = first_object; obj; obj = obj->next )
   {
      if( obj->in_room && !str_cmp( buf2, obj->short_descr ) && ( obj->pIndexData->vnum == OBJ_VNUM_CORPSE_PC ) )
      {
         if( obj->in_room == ch->in_room )
         {
            althere = true;
            continue;
         }
         found = true;
         charge = true;
         if( ( rch = obj->in_room->first_person ) && !is_obj_stat( obj, ITEM_BURIED ) )
         {
            act( AT_ACTION, "$T is grabbed by an undertaker.", rch, NULL, buf2, TO_ROOM );
            act( AT_ACTION, "$T is grabbed by an undertaker.", rch, NULL, buf2, TO_CHAR );
         }
         act( AT_ACTION, "$N strolls in carrying your corpse and quickly drops it.", ch, NULL, ut, TO_CHAR );
         act( AT_ACTION, "$N strolls in carrying $n's corpse and quickly drops it.", ch, NULL, ut, TO_ROOM );
         obj_from_room( obj );
         obj = obj_to_room( obj, ch->in_room );
      }
   }
   if( !found )
   {
      if( !althere )
         send_to_char( "No corpse of yours litters the world...\r\n", ch );
      else
         send_to_char( "Your corpse(s) are already in this room...\r\n", ch );
      return;
   }

   if( charge )
      decrease_gold( ch, cost );
}