eldhamud_2.3.3/clans/
eldhamud_2.3.3/councils/
eldhamud_2.3.3/doc/
eldhamud_2.3.3/doc/DIKU/
eldhamud_2.3.3/doc/DIKU/.svn/
eldhamud_2.3.3/doc/DIKU/.svn/prop-base/
eldhamud_2.3.3/doc/DIKU/.svn/text-base/
eldhamud_2.3.3/doc/MERC/
eldhamud_2.3.3/doc/MERC/.svn/
eldhamud_2.3.3/doc/SMAUG/.svn/
eldhamud_2.3.3/doc/SMAUG/mudprogs/
eldhamud_2.3.3/doc/SMAUG/mudprogs/.svn/
eldhamud_2.3.3/doc/mudprogs/
eldhamud_2.3.3/gods/
eldhamud_2.3.3/houses/
eldhamud_2.3.3/player/a/
/****************************************************************************
 *   Eldhamud Codebase V2.2        *
 * ------------------------------------------------------------------------ *
 *          EldhaMUD code (C) 2003-2008 by Robert Powell (Tommi)            *
 * ------------------------------------------------------------------------ *
 * Original SMAUG 1.4a written by Thoric (Derek Snider) with Altrag,        *
 * Blodkai, Haus, Narn, Scryn, Swordbearer, Tricops, Gorog, Rennard,        *
 * Grishnakh, Fireblade, and Nivek.                                         *
 *                                                                          *
 * Original MERC 2.1 code by Hatchet, Furey, and Kahn.                      *
 *                                                                          *
 * Original DikuMUD code by: Hans Staerfeldt, Katja Nyboe, Tom Madsen,      *
 * Michael Seifert, and Sebastian Hammer.                                   *
 * ------------------------------------------------------------------------ *
 *      Object manipulation module       *
 ****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "./Headers/mud.h"
#include "./Headers/bet.h"
/*double sqrt( double x );*/
/*
 * External functions
 */
void write_corpses args ( ( CHAR_DATA * ch, char *name, OBJ_DATA * objrem ) );
void do_token_redeem ( CHAR_DATA * ch, OBJ_DATA * obj );
/*
 * Local functions.
 */
void get_obj args ( ( CHAR_DATA * ch, OBJ_DATA * obj, OBJ_DATA * container ) );
bool remove_obj args ( ( CHAR_DATA * ch, int iWear, bool fReplace ) );
void wear_obj args ( ( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace, short wear_bit ) );
char *get_chance_verb args ( ( OBJ_DATA * obj ) );
char *get_ed_number args ( ( OBJ_DATA * obj, int number ) );
OBJ_DATA *recursive_note_find args ( ( OBJ_DATA * obj, char *argument ) );
/*
 * how resistant an object is to damage    -Thoric
 */
short get_obj_resistance ( OBJ_DATA * obj )
{
  short resist;
  resist = number_fuzzy ( MAX_ITEM_IMPACT );
  /*
   * magical items are more resistant
   */

  if ( IS_OBJ_STAT ( obj, ITEM_MAGIC ) )
    resist += number_fuzzy ( 12 );

  /*
   * metal objects are definately stronger
   */
  if ( IS_OBJ_STAT ( obj, ITEM_METAL ) )
    resist += number_fuzzy ( 5 );

  /*
   * organic objects are most likely weaker
   */
  if ( IS_OBJ_STAT ( obj, ITEM_ORGANIC ) )
    resist -= number_fuzzy ( 5 );

  /*
   * blessed objects should have a little bonus
   */
  if ( IS_OBJ_STAT ( obj, ITEM_BLESS ) )
    resist += number_fuzzy ( 5 );

  /*
   * lets make store inventory pretty tough
   */
  if ( IS_OBJ_STAT ( obj, ITEM_INVENTORY ) )
    resist += 20;

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

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

  return URANGE ( 10, resist, 99 );
}

void get_obj ( CHAR_DATA * ch, OBJ_DATA * obj, OBJ_DATA * container )
{
  CLAN_DATA *clan;
  int weight;
  int amt; /* gold per-race multipliers */

  if ( !CAN_WEAR ( obj, ITEM_TAKE ) && ( ch->level < sysdata.level_getobjnotake ) )
  {
    send_to_char ( "You can't take that.\n\r", ch );
    return;
  }

  if ( IS_SET ( obj->magic_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_color ( "\n\r&bA godly force freezes your outstretched hand.\n\r", ch );
        return;
      }
      else
      {
        REMOVE_BIT ( obj->magic_flags, ITEM_PKDISARMED );
        obj->value[5] = 0;
      }
    }
    else
    {
      send_to_char_color ( "\n\r&BA godly force freezes your outstretched hand.\n\r", ch );
      return;
    }
  }

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

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

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

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

  if ( 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 == NULL ) )
  {
    /*
     * if (!char_died) save_char_obj(ch);
     */
    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 )
  {
    amt = obj->value[0];
    /*
     *  The idea was to make some races more adroit at money handling,
     *  however, this resulted in elves dropping 1M gps and picking
     *  up 1.1M, repeating, and getting rich.  The only solution would
     *  be to fuzzify the "drop coins" code, but that seems like it'd
     *  lead to more confusion than it warrants.  -h
     *
     *  When you work on this again, make it so that amt is NEVER multiplied
     *  by more than 1.0.  Use less than 1.0 for ogre, orc, troll, etc.
     *  (Ie: a penalty rather than a bonus)
     */
#ifdef GOLD_MULT

    switch ( ch->race )
    {
      case ( 1 ) :
              amt *= 1.1;
        break;   /* elf */
      case ( 2 ) :
              amt *= 0.97;
        break;   /* dwarf */
      case ( 3 ) :
              amt *= 1.02;
        break;   /* halfling */
      case ( 4 ) :
              amt *= 1.08;
        break;   /* pixie */
      case ( 6 ) :
              amt *= 0.92;
        break;   /* half-ogre */
      case ( 7 ) :
              amt *= 0.94;
        break;   /* half-orc */
      case ( 8 ) :
              amt *= 0.90;
        break;   /* half-troll */
      case ( 9 ) :
              amt *= 1.04;
        break;   /* half-elf */
      case ( 10 ) :
              amt *= 1.06;
        break;   /* gith */
    }

#endif
    ch->gold += amt;

    extract_obj ( obj );
  }
  else
{
    obj = obj_to_char ( obj, ch );
  }

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

  oprog_get_trigger ( ch, obj );

  return;
}

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

  if ( is_number ( arg1 ) )
  {
    number = atoi ( arg1 );

    if ( number < 1 )
    {
      send_to_char ( "That was easy...\n\r", ch );
      return;
    }

    if ( ( ch->carry_number + number ) > can_carry_n ( ch ) )
    {
      send_to_char ( "You can't carry that many.\n\r", ch );
      return;
    }

    argument = one_argument ( argument, arg1 );
  }
  else
    number = 0;

  argument = one_argument ( argument, arg2 );

  /*
   * munch optional words
   */
  if ( !str_cmp ( arg2, "from" ) && argument[0] != STRING_NULL )
    argument = one_argument ( argument, arg2 );

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

  if ( ms_find_obj ( ch ) )
    return;

  if ( arg2[0] == STRING_NULL )
  {
    if ( number <= 1 && str_cmp ( arg1, "all" ) && str_prefix ( "all.", arg1 ) )
    {
      /*
       * 'get obj'
       */
      obj = get_obj_list ( ch, arg1, ch->in_room->first_content );

      if ( !obj )
      {
        act ( AT_PLAIN, "I see no $T here.", ch, NULL, arg1, TO_CHAR );
        return;
      }

      separate_obj ( obj );

      get_obj ( ch, obj, NULL );

      if ( char_died ( ch ) )
        return;

      save_house_by_vnum ( ch->in_room->vnum ); /* House Object Saving */

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

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

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

      /*
       * 'get all' or 'get all.obj'
       */
      found = FALSE;

      for ( obj = ch->in_room->last_content; obj; obj = obj_next )
      {
        obj_next = obj->prev_content;

        if ( ( fAll || nifty_is_name ( chk, obj->name ) ) && can_see_obj ( ch, obj ) )
        {
          if ( IS_OBJ_STAT ( obj, ITEM_ONMAP ) )
          {
            if ( ch->map != obj->map || ch->x != obj->x || ch->y != obj->y )
            {
              found = FALSE;
              continue;
            }
          }

          found = TRUE;

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

          cnt += obj->count;

          get_obj ( ch, obj, NULL );

          if ( char_died ( ch ) || ch->carry_number >= can_carry_n ( ch ) || ch->carry_weight >= can_carry_w ( ch ) || ( number && cnt >= number ) )
          {
            if ( IS_SET ( sysdata.save_flags, SV_GET ) && !char_died ( ch ) )
              save_char_obj ( ch );

            return;
          }
        }
      }

      if ( !found )
      {
        if ( fAll )
          send_to_char ( "I see nothing here.\n\r", ch );
        else
          act ( AT_PLAIN, "I see no $T here.", ch, NULL, chk, TO_CHAR );
      }
      else
      {
        save_house_by_vnum ( ch->in_room->vnum ); /* House Object Saving */

        if ( IS_SET ( sysdata.save_flags, SV_GET ) )
          save_char_obj ( ch );
      }
    }
  }
  else
  {
    /*
     * 'get ... container'
     */
    if ( !str_cmp ( arg2, "all" ) || !str_prefix ( "all.", arg2 ) )
    {
      send_to_char ( "You can't do that.\n\r", ch );
      return;
    }

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

    switch ( container->item_type )
    {

      default:

        if ( !IS_OBJ_STAT ( container, ITEM_COVERING ) )
        {
          send_to_char ( "That's not a container.\n\r", ch );
          return;
        }

        if ( ch->carry_weight + container->weight > can_carry_w ( ch ) )
        {
          send_to_char ( "It's too heavy for you to lift.\n\r", ch );
          return;
        }

        break;

      case ITEM_CONTAINER:

      case ITEM_CORPSE_NPC:

      case ITEM_KEYRING:

      case ITEM_QUIVER:
        break;

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

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

          pd = container->short_descr;

          pd = one_argument ( pd, name );
          pd = one_argument ( pd, name );
          pd = one_argument ( pd, name );
          pd = one_argument ( pd, name );

          if ( IS_OBJ_STAT ( container, ITEM_CLANCORPSE ) && !IS_NPC ( ch ) && ( get_timer ( ch, TIMER_PKILLED ) > 0 ) && str_cmp ( name, ch->name ) )
          {
            send_to_char ( "You cannot loot from that corpse...yet.\n\r", ch );
            return;
          }

          /*
           * 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] != STRING_NULL && 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.\n\r", 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.\n\r", ch );
            return;
          }

          if ( IS_OBJ_STAT ( container, ITEM_CLANCORPSE )
               && !IS_NPC ( ch ) && IS_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.\n\r", ch );
              return;
            }
          }
        }
    }

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

    if ( number <= 1 && str_cmp ( arg1, "all" ) && str_prefix ( "all.", arg1 ) )
    {
      /*
       * 'get obj container'
       */
      obj = get_obj_list ( ch, arg1, container->first_content );

      if ( !obj )
      {
        act ( AT_PLAIN, IS_OBJ_STAT ( container, ITEM_COVERING ) ?
              "I see nothing like that beneath the $T." : "I see nothing like that in the $T.", ch, NULL, arg2, TO_CHAR );
        return;
      }

      separate_obj ( obj );

      get_obj ( ch, obj, container );
      /*
       * Oops no wonder corpses were duping oopsie did I do that
       * * --Shaddai
       */

      if ( container->item_type == ITEM_CORPSE_PC )
        write_corpses ( NULL, container->short_descr + 14, NULL );

      check_for_trap ( ch, container, TRAP_GET );

      if ( char_died ( ch ) )
        return;

      if ( IS_SET ( sysdata.save_flags, SV_GET ) )
        save_char_obj ( ch );
    }
    else
    {
      int cnt = 0;
      bool fAll;
      char *chk;
      /*
       * 'get all container' or 'get all.obj container'
       */

      if ( IS_OBJ_STAT ( container, ITEM_DONATION ) )
      {
        send_to_char ( "The gods frown upon such an act of greed!\n\r", ch );
        return;
      }

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

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

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

      found = FALSE;

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

        if ( ( fAll || nifty_is_name ( chk, obj->name ) ) && can_see_obj ( ch, obj ) )
        {
          found = TRUE;

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

          cnt += obj->count;

          get_obj ( ch, obj, container );

          if ( char_died ( ch ) || 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 ( NULL, container->short_descr + 14, NULL );

            if ( found && IS_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 ( NULL, container->short_descr + 14, NULL );

      if ( found && IS_SET ( sysdata.save_flags, SV_GET ) )
        save_char_obj ( ch );
    }
  }

  return;
}

void do_put ( CHAR_DATA * ch, char *argument )
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  OBJ_DATA *container;
  OBJ_DATA *obj;
  OBJ_DATA *obj_next;
  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...\n\r", ch );
      return;
    }

    argument = one_argument ( argument, arg1 );
  }
  else
    number = 0;

  argument = one_argument ( argument, arg2 );

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

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

  if ( ms_find_obj ( ch ) )
    return;

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

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

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

  if ( IS_OBJ_STAT ( container, ITEM_COVERING ) )
  {
    if ( ch->carry_weight + container->weight > can_carry_w ( ch ) )
    {
      send_to_char ( "It's too heavy for you to lift.\n\r", ch );
      return;
    }
  }
  else
  {
    if ( container->item_type != ITEM_CONTAINER && container->item_type != ITEM_KEYRING && container->item_type != ITEM_QUIVER )
    {
      send_to_char ( "That's not a container.\n\r", ch );
      return;
    }

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

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

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

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

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

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

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

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

    separate_obj ( obj );

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

    if ( char_died ( ch ) )
      return;

    count = obj->count;

    obj->count = 1;

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

    obj->count = count;

    /*
     * Oops no wonder corpses were duping oopsie did I do that
     * * --Shaddai
     */

    if ( container->item_type == ITEM_CORPSE_PC )
      write_corpses ( NULL, container->short_descr + 14, NULL );

    if ( save_char )
      save_char_obj ( ch );

    /*
     * Clan storeroom check
     */
    if ( xIS_SET ( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) && container->carried_by == NULL )
    {
      /*
       * if (!char_died && !save_char ) save_char_obj(ch);
       */
      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 ) && 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 );
        }

        obj = obj_to_obj ( obj, container );

        found = TRUE;
        check_for_trap ( ch, container, TRAP_PUT );

        if ( char_died ( ch ) )
          return;

        if ( number && cnt >= number )
          break;
      }
    }

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

      return;
    }

    if ( save_char )
      save_char_obj ( ch );

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

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

  return;
}

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

  if ( is_number ( arg ) )
  {
    number = atoi ( arg );

    if ( number < 1 )
    {
      send_to_char ( "That was easy...\n\r", ch );
      return;
    }

    argument = one_argument ( argument, arg );
  }
  else
    number = 0;

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

  if ( ms_find_obj ( ch ) )
    return;

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

  if ( 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!\n\r", ch );
    set_char_color ( AT_TELL, ch );
    send_to_char ( "Someone tells you, 'No littering here!'\n\r", ch );
    return;
  }

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

      ch->gold -= number;

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

        switch ( obj->pIndexData->vnum )
        {

          case OBJ_VNUM_MONEY_ONE:
            number += 1;
            extract_obj ( obj );
            break;

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

      act ( AT_ACTION, "$n drops some gold.", ch, NULL, NULL, TO_ROOM );

      obj_to_room ( create_money ( number ), ch->in_room, ch );
      save_house_by_vnum ( ch->in_room->vnum ); /* House Object Saving */
      send_to_char ( "You let the gold slip from your hand.\n\r", ch );

      if ( IS_SET ( sysdata.save_flags, SV_DROP ) )
        save_char_obj ( ch );

      return;
    }
  }

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

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

    separate_obj ( obj );

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

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

    /*
     * Clan storeroom saving
     */
    if ( xIS_SET ( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) )
    {
      /*
       * if (!char_died) save_char_obj(ch);
       */
      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...\n\r", ch );
      return;
    }

    found = FALSE;

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

      if ( ( fAll || nifty_is_name ( chk, obj->name ) ) && can_see_obj ( ch, obj ) && obj->wear_loc == WEAR_NONE && can_drop_obj ( ch, obj ) )
      {
        found = TRUE;

        if ( HAS_PROG ( obj->pIndexData, DROP_PROG ) && obj->count > 1 )
        {
          ++cnt;
          separate_obj ( obj );
          obj_from_char ( obj );

          if ( !obj_next )
            obj_next = ch->first_carrying;
        }
        else
        {
          if ( number && ( cnt + obj->count ) > number )
            split_obj ( obj, number - cnt );

          cnt += obj->count;

          obj_from_char ( obj );
        }

        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, ch );
        oprog_drop_trigger ( ch, obj );  /* mudprogs */

        if ( char_died ( ch ) )
          return;

        if ( number && cnt >= number )
          break;
      }
    }

    if ( !found )
    {
      if ( fAll )
        act ( AT_PLAIN, "You are not carrying anything.", ch, NULL, NULL, TO_CHAR );
      else
        act ( AT_PLAIN, "You are not carrying any $T.", ch, NULL, chk, TO_CHAR );

      save_house_by_vnum ( ch->in_room->vnum ); /* House Object Saving */
    }
  }

  if ( IS_SET ( sysdata.save_flags, SV_DROP ) )
    save_char_obj ( ch ); /* duping protector */

  return;
}

void do_give ( CHAR_DATA * ch, char *argument )
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char buf[MAX_INPUT_LENGTH];
  CHAR_DATA *victim, *questman;
  OBJ_DATA *obj;
  argument = one_argument ( argument, arg1 );
  argument = one_argument ( argument, arg2 );

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

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

  if ( ms_find_obj ( ch ) )
    return;

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

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

    argument = one_argument ( argument, arg2 );

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

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

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

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

    ch->gold -= amount;

    victim->gold += amount;
    strcpy ( buf, "$n gives you " );
    strcat ( buf, arg1 );
    strcat ( buf, ( amount > 1 ) ? " coins." : " coin." );
    act ( AT_ACTION, buf, ch, NULL, victim, TO_VICT );
    act ( AT_ACTION, "$n gives $N some gold.", ch, NULL, victim, TO_NOTVICT );
    act ( AT_ACTION, "You give $N some gold.", ch, NULL, victim, TO_CHAR );
    mprog_bribe_trigger ( victim, ch, amount );

    if ( IS_SET ( sysdata.save_flags, SV_GIVE ) && !char_died ( ch ) )
      save_char_obj ( ch );

    if ( IS_SET ( sysdata.save_flags, SV_RECEIVE ) && !char_died ( victim ) )
      save_char_obj ( victim );

    return;
  }

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

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

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

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

  if ( obj->item_type == ITEM_QUESTTOKEN )
  {
    if ( !str_prefix ( "all.", arg1 ) )
    {
      send_to_char ( "You cannot give all.token, this is to stop a crash, will fix it soon as possible\n\r", ch );
      return;
    }

    for ( questman = ch->in_room->first_person; questman != NULL; questman = questman->next_in_room )
      if ( IS_NPC ( questman ) && xIS_SET ( questman->act, ACT_QUESTMASTER ) )
        break;

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

        if ( IS_SET ( sysdata.save_flags, SV_GIVE ) && !char_died ( ch ) )
          save_char_obj ( ch );

        if ( IS_SET ( sysdata.save_flags, SV_RECEIVE ) && !char_died ( victim ) )
          save_char_obj ( victim );

        do_token_redeem ( ch, obj );

        return;
      }
    }
  }

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

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

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

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

  separate_obj ( obj );

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

  if ( IS_SET ( sysdata.save_flags, SV_GIVE ) && !char_died ( ch ) )
    save_char_obj ( ch );

  if ( IS_SET ( sysdata.save_flags, SV_RECEIVE ) && !char_died ( victim ) )
    save_char_obj ( victim );

  return;
}

/*
 * Damage an object.      -Thoric
 * Affect player's AC if necessary.
 * Make object into scraps if necessary.
 * Send message about damaged object.
 */
obj_ret damage_obj ( OBJ_DATA * obj )
{
  CHAR_DATA *ch;
  obj_ret objcode;
  int random_number;
  ch = obj->carried_by;
  objcode = rNONE;
  separate_obj ( obj );

  if ( !IS_NPC ( ch ) && ( !IS_PKILL ( ch ) || ( IS_PKILL ( ch ) && !IS_SET ( ch->pcdata->flags, PCFLAG_GAG ) ) ) )
    act ( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_CHAR );
  else
    if ( obj->in_room && ( ch = obj->in_room->first_person ) != NULL )
    {
      act ( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_ROOM );
      act ( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_CHAR );
      ch = NULL;
    }

  if ( obj->item_type != ITEM_LIGHT )
    oprog_damage_trigger ( ch, obj );
  else
    if ( !in_arena ( ch ) )
      oprog_damage_trigger ( ch, obj );

  if ( obj_extracted ( obj ) )
    return global_objcode;

  switch ( obj->item_type )
  {

    default:
      make_scraps ( obj );
      objcode = rOBJ_SCRAPPED;
      break;

    case ITEM_CONTAINER:

      if ( --obj->value[3] <= 0 )
      {
        if ( !in_arena ( ch ) )
        {
          make_scraps ( obj );
          objcode = rOBJ_SCRAPPED;
        }
        else
          obj->value[3] = 1;
      }

    case ITEM_SHOVEL:

    case ITEM_KEYRING:

    case ITEM_QUIVER:

      if ( --obj->value[3] <= 0 )
      {
        if ( !in_arena ( ch ) )
        {
          make_scraps ( obj );
          objcode = rOBJ_SCRAPPED;
        }
        else
          obj->value[3] = 1;
      }

      break;

    case ITEM_LIGHT:

      if ( --obj->value[0] <= 0 )
      {
        if ( !in_arena ( ch ) )
        {
          make_scraps ( obj );
          objcode = rOBJ_SCRAPPED;
        }
        else
          obj->value[0] = 1;
      }

      break;

    case ITEM_ARMOR:
      random_number = number_range ( 0, 4 );

      if ( random_number == 1 )
      {
        if ( --obj->value[3] <= 0 )
        {
          make_scraps ( obj );
          objcode = rOBJ_SCRAPPED;
        }
      }

      break;

    case ITEM_WEAPON:
      random_number = number_range ( 0, 4 );

      if ( random_number == 1 )
      {
        if ( --obj->value[0] <= 0 )
        {
          make_scraps ( obj );
          objcode = rOBJ_SCRAPPED;
        }

        break;
      }
  }

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

  return objcode;
}

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

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

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

  if ( !fReplace )
    return FALSE;

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

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

  unequip_char ( ch, obj );

  act ( AT_ACTION, "$n stops using $p.", ch, obj, NULL, TO_ROOM );

  act ( AT_ACTION, "You stop using $p.", ch, obj, NULL, TO_CHAR );

  oprog_remove_trigger ( ch, obj );

  return TRUE;
}

/*
 * See if char could be capable of dual-wielding  -Thoric
 */
bool could_dual ( CHAR_DATA * ch )
{
  //  if( IS_NPC( ch ) || ch->pcdata->learned[gsn_dual_wield] )
  //     return TRUE;
  return FALSE;
}

/*
* Check for the ability to dual-wield under all conditions.  -Orion
*
* Original version by Thoric.
*/
bool can_dual ( CHAR_DATA * ch )
{
  /*
   * We must assume that when they come in, they are NOT wielding something. We
   * take care of the actual value later. -Orion
   */
  bool wielding[2], alreadyWielding = FALSE;
  wielding[0] = FALSE;
  wielding[1] = FALSE;
  /*
   * If they don't have the ability to dual-wield, why should we allow them to
   * do so? -Orion
   */

  if ( !could_dual ( ch ) )
    return FALSE;

  /*
   * Get that true wielding value I mentioned earlier. If they're wielding and
   * missile wielding, we can simply return FALSE. If not, set the values. -Orion
   */
  if ( get_eq_char ( ch, WEAR_WIELD ) && get_eq_char ( ch, WEAR_MISSILE_WIELD ) )
  {
    send_to_char ( "You are already wielding two weapons... grow some more arms!\n\r", ch );
    return FALSE;
  }
  else
  {
    /*
     * Wield position. -Orion
     */
    wielding[0] = get_eq_char ( ch, WEAR_WIELD ) ? TRUE : FALSE;
    /*
     * Missile wield position. -Orion
     */
    wielding[1] = get_eq_char ( ch, WEAR_MISSILE_WIELD ) ? TRUE : FALSE;
  }

  /*
   * Save some extra typing farther down. -Orion
   */
  if ( wielding[0] || wielding[1] )
    alreadyWielding = TRUE;

  /*
   * If wielding and dual wielding, then they can't wear another weapon. Return
   * FALSE. We can assume that dual wield will not be full if there is no wield
   * slot already filled. -Orion
   */
  if ( wielding[0] && get_eq_char ( ch, WEAR_DUAL_WIELD ) )
  {
    send_to_char ( "You are already wielding two weapons... grow some more arms!\n\r", ch );
    return FALSE;
  }

  /*
   * If wielding or missile wielding and holding a shield, then we can return
   * FALSE. -Orion
   */
  if ( alreadyWielding && get_eq_char ( ch, WEAR_SHIELD ) )
  {
    send_to_char ( "You cannot dual wield, you're already holding a shield!\n\r", ch );
    return FALSE;
  }

  /*
   * If wielding or missile wielding and holding something, then we can return
   * FALSE. -Orion
   */
  if ( alreadyWielding && get_eq_char ( ch, WEAR_HOLD ) )
  {
    send_to_char ( "You cannot hold another weapon, you're already holding something in that hand!\n\r", ch );
    return FALSE;
  }

  return TRUE;
}

/*
 * Check to see if there is room to wear another object on this location
 * (Layered clothing support)
 */
bool can_layer ( CHAR_DATA * ch, OBJ_DATA * obj, 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;
}

/*
 * Wear one object.
 * Optional replacement of existing objects.
 * Big repetitive code, ick.
 *
 * Restructured a bit to allow for specifying body location -Thoric
 * & Added support for layering on certain body locations
 */
void wear_obj ( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace, short wear_bit )
{
  char buf[MAX_STRING_LENGTH];
  OBJ_DATA *tmpobj = NULL;
  short bit, tmp;
  separate_obj ( obj );

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

  if ( !IS_IMMORTAL ( ch )
       && ( ( IS_OBJ_STAT ( obj, ITEM_ANTI_DEATH ) && ( ch->Class == CLASS_WU_JEN || ch->Class == CLASS_KENSEI ) )
            || ( IS_OBJ_STAT ( obj, ITEM_ANTI_LIFE ) && ( ch->Class == CLASS_BUSHI || ch->Class == CLASS_SHUGENJA ) )
            || ( IS_OBJ_STAT ( obj, ITEM_ANTI_DECAY ) && ( ch->Class == CLASS_HENSHIN || ch->Class == CLASS_IAIJUTSU ) )
            || ( IS_OBJ_STAT ( obj, ITEM_ANTI_GROWTH ) && ( ch->Class == CLASS_SOHEI || ch->Class == CLASS_KISHI ) ) ) )
  {
    act ( AT_MAGIC, "It goes against the nature of your class t use that item.", ch, NULL, NULL, TO_CHAR );
    act ( AT_ACTION, "$n tries to use $p, but is forbidden to do so.", ch, obj, NULL, TO_ROOM );
    return;
  }

  if ( !IS_IMMORTAL ( ch )
       && ( ( IS_OBJ_STAT ( obj, ITEM_ANTI_EVIL ) && ( ch->race == RACE_UNDEAD || ch->race == RACE_DEMON ) )
            || ( IS_OBJ_STAT ( obj, ITEM_ANTI_NEUTRAL ) && ( ch->race == RACE_NEZUMI || ch->race == RACE_SPIRIT ) )
            || ( IS_OBJ_STAT ( obj, ITEM_ANTI_GOOD ) && ( ch->Class == RACE_ANGEL || ch->race == RACE_VANARA ) ) ) )
  {
    act ( AT_MAGIC, "It goes against the nature of your race to use that item.", ch, NULL, NULL, TO_CHAR );
    act ( AT_ACTION, "$n tries to use $p, but is forbidden to do so.", ch, obj, NULL, TO_ROOM );
    return;
  }


  if ( wear_bit > -1 )
  {
    bit = wear_bit;

    if ( !CAN_WEAR ( obj, 1 << bit ) )
    {
      if ( fReplace )
      {
        switch ( 1 << bit )
        {

          case ITEM_HOLD:
            send_to_char ( "You cannot hold that.\n\r", ch );
            break;

          case ITEM_WIELD:

          case ITEM_MISSILE_WIELD:
            send_to_char ( "You cannot wield that.\n\r", ch );
            break;

          default:
            sprintf ( buf, "You cannot wear that on your %s.\n\r", w_flags[bit] );
            send_to_char ( buf, ch );
        }
      }

      return;
    }
  }
  else
  {
    for ( bit = -1, tmp = 1; tmp < 31; tmp++ )
    {
      if ( CAN_WEAR ( obj, 1 << tmp ) )
      {
        bit = tmp;
        break;
      }
    }
  }

  /*
   * currently cannot have a light in non-light position
   */
  if ( obj->item_type == ITEM_LIGHT )
  {
    if ( !remove_obj ( ch, WEAR_LIGHT, fReplace ) )
      return;

    if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
    {
      act ( AT_ACTION, "$n holds $p as a light.", ch, obj, NULL, TO_ROOM );
      act ( AT_ACTION, "You hold $p as your light.", ch, obj, NULL, TO_CHAR );
    }

    equip_char ( ch, obj, WEAR_LIGHT );

    oprog_wear_trigger ( ch, obj );
    return;
  }

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

    return;
  }

  switch ( 1 << bit )
  {

    default:
      bug ( "wear_obj: uknown/unused item_wear bit %d", bit );

      if ( fReplace )
        send_to_char ( "You can't wear, wield, or hold that.\n\r", ch );

      return;

    case ITEM_LODGE_RIB:
      act ( AT_ACTION, "$p strikes you and deeply imbeds itself in your ribs!", ch, obj, NULL, TO_CHAR );

      act ( AT_ACTION, "$p strikes $n and deeply imbeds itself in $s ribs!", ch, obj, NULL, TO_ROOM );

      equip_char ( ch, obj, WEAR_LODGE_RIB );

      break;

    case ITEM_LODGE_ARM:
      act ( AT_ACTION, "$p strikes you and deeply imbeds itself in your arm!", ch, obj, NULL, TO_CHAR );

      act ( AT_ACTION, "$p strikes $n and deeply imbeds itself in $s arm!", ch, obj, NULL, TO_ROOM );

      equip_char ( ch, obj, WEAR_LODGE_ARM );

      break;

    case ITEM_LODGE_LEG:
      act ( AT_ACTION, "$p strikes you and deeply imbeds itself in your leg!", ch, obj, NULL, TO_CHAR );

      act ( AT_ACTION, "$p strikes $n and deeply imbeds itself in $s leg!", ch, obj, NULL, TO_ROOM );

      equip_char ( ch, obj, WEAR_LODGE_LEG );

      break;

    case ITEM_WEAR_BODY:
      if ( !can_layer ( ch, obj, WEAR_BODY ) )
      {
        send_to_char ( "It won't fit overtop of what you're already wearing.\n\r", ch );
        return;
      }

      if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n fits $p on $s body.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You fit $p on your body.", ch, obj, NULL, TO_CHAR );
      }

      equip_char ( ch, obj, WEAR_BODY );

      oprog_wear_trigger ( ch, obj );
      return;

    case ITEM_WEAR_HEAD:

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

      if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n dons $p upon $s head.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You don $p upon your head.", ch, obj, NULL, TO_CHAR );
      }

      equip_char ( ch, obj, WEAR_HEAD );

      oprog_wear_trigger ( ch, obj );
      return;

    case ITEM_WEAR_LEGS:

      if ( !can_layer ( ch, obj, WEAR_LEGS ) )
      {
        send_to_char ( "It won't fit overtop of what you're already wearing.\n\r", ch );
        return;
      }

      if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n slips into $p.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You slip into $p.", ch, obj, NULL, TO_CHAR );
      }

      equip_char ( ch, obj, WEAR_LEGS );

      oprog_wear_trigger ( ch, obj );
      return;

    case ITEM_WEAR_FEET:

      if ( !can_layer ( ch, obj, WEAR_FEET ) )
      {
        send_to_char ( "It won't fit overtop of what you're already wearing.\n\r", ch );
        return;
      }

      if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n wears $p on $s feet.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You wear $p on your feet.", ch, obj, NULL, TO_CHAR );
      }

      equip_char ( ch, obj, WEAR_FEET );

      oprog_wear_trigger ( ch, obj );
      return;

    case ITEM_WEAR_HANDS:

      if ( !can_layer ( ch, obj, WEAR_HANDS ) )
      {
        send_to_char ( "It won't fit overtop of what you're already wearing.\n\r", ch );
        return;
      }

      if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n wears $p on $s hands.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You wear $p on your hands.", ch, obj, NULL, TO_CHAR );
      }

      equip_char ( ch, obj, WEAR_HANDS );

      oprog_wear_trigger ( ch, obj );
      return;

    case ITEM_WEAR_ARMS:

      if ( !can_layer ( ch, obj, WEAR_ARMS ) )
      {
        send_to_char ( "It won't fit overtop of what you're already wearing.\n\r", ch );
        return;
      }

      if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n wears $p on $s arms.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You wear $p on your arms.", ch, obj, NULL, TO_CHAR );
      }

      equip_char ( ch, obj, WEAR_ARMS );

      oprog_wear_trigger ( ch, obj );
      return;

    case ITEM_WEAR_BACK:

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

      if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n slings $p on $s back.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You sling $p on your back.", ch, obj, NULL, TO_CHAR );
      }

      equip_char ( ch, obj, WEAR_BACK );

      oprog_wear_trigger ( ch, obj );
      return;

    case ITEM_WEAR_SHIELD:

      if ( get_eq_char ( ch, WEAR_DUAL_WIELD ) || ( get_eq_char ( ch, WEAR_WIELD ) && get_eq_char ( ch, WEAR_MISSILE_WIELD ) ) )
      {
        send_to_char ( "You can't use a shield AND two weapons!\n\r", ch );
        return;
      }

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

      if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n uses $p as a shield.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You use $p as a shield.", ch, obj, NULL, TO_CHAR );
      }

      equip_char ( ch, obj, WEAR_SHIELD );

      oprog_wear_trigger ( ch, obj );
      return;

    case ITEM_MISSILE_WIELD:

    case ITEM_WIELD:

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

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

        tmpobj = NULL;
      }
      else
      {
        OBJ_DATA *mw, *dw, *hd, *sd;
        tmpobj = get_eq_char ( ch, WEAR_WIELD );
        mw = get_eq_char ( ch, WEAR_MISSILE_WIELD );
        dw = get_eq_char ( ch, WEAR_DUAL_WIELD );
        hd = get_eq_char ( ch, WEAR_HOLD );
        sd = get_eq_char ( ch, WEAR_SHIELD );

        if ( tmpobj )
        {
          if ( !can_dual ( ch ) )
            return;

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

          if ( mw || dw )
          {
            send_to_char ( "You're already wielding two weapons.\n\r", ch );
            return;
          }

          if ( hd || sd )
          {
            send_to_char ( "You're already wielding a weapon AND holding something.\n\r", ch );
            return;
          }

          if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
          {
            act ( AT_ACTION, "$n dual-wields $p.", ch, obj, NULL, TO_ROOM );
            act ( AT_ACTION, "You dual-wield $p.", ch, obj, NULL, TO_CHAR );
          }

          if ( 1 << bit == ITEM_MISSILE_WIELD )
            equip_char ( ch, obj, WEAR_MISSILE_WIELD );
          else
            equip_char ( ch, obj, WEAR_DUAL_WIELD );

          oprog_wear_trigger ( ch, obj );

          return;
        }

        if ( mw )
        {
          if ( !can_dual ( ch ) )
            return;

          if ( 1 << bit == ITEM_MISSILE_WIELD )
          {
            send_to_char ( "You're already wielding a missile weapon.\n\r", ch );
            return;
          }

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

          if ( tmpobj || dw )
          {
            send_to_char ( "You're already wielding two weapons.\n\r", ch );
            return;
          }

          if ( hd || sd )
          {
            send_to_char ( "You're already wielding a weapon AND holding something.\n\r", ch );
            return;
          }

          if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
          {
            act ( AT_ACTION, "$n wields $p.", ch, obj, NULL, TO_ROOM );
            act ( AT_ACTION, "You wield $p.", ch, obj, NULL, TO_CHAR );
          }

          equip_char ( ch, obj, WEAR_WIELD );

          oprog_wear_trigger ( ch, obj );
          return;
        }
      }

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

      if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n wields $p.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You wield $p.", ch, obj, NULL, TO_CHAR );
      }

      if ( 1 << bit == ITEM_MISSILE_WIELD )
        equip_char ( ch, obj, WEAR_MISSILE_WIELD );
      else
        equip_char ( ch, obj, WEAR_WIELD );

      oprog_wear_trigger ( ch, obj );

      return;

    case ITEM_HOLD:
      if ( get_eq_char ( ch, WEAR_DUAL_WIELD ) || ( get_eq_char ( ch, WEAR_WIELD ) && get_eq_char ( ch, WEAR_MISSILE_WIELD ) ) )
      {
        send_to_char ( "You cannot hold something AND two weapons!\n\r", ch );
        return;
      }

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

      if ( obj->item_type == ITEM_WAND
           || obj->item_type == ITEM_STAFF
           || obj->item_type == ITEM_FOOD
           || obj->item_type == ITEM_COOK
           || obj->item_type == ITEM_PILL
           || obj->item_type == ITEM_POTION
           || obj->item_type == ITEM_SCROLL
           || obj->item_type == ITEM_DRINK_CON
           || obj->item_type == ITEM_BLOOD
           || obj->item_type == ITEM_PIPE || obj->item_type == ITEM_HERB || obj->item_type == ITEM_KEY || !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) )
      {
        act ( AT_ACTION, "$n holds $p in $s hands.", ch, obj, NULL, TO_ROOM );
        act ( AT_ACTION, "You hold $p in your hands.", ch, obj, NULL, TO_CHAR );
      }

      equip_char ( ch, obj, WEAR_HOLD );

      oprog_wear_trigger ( ch, obj );
      return;
  }
}

void do_wear ( CHAR_DATA * ch, char *argument )
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  OBJ_DATA *obj;
  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] != STRING_NULL )
    argument = one_argument ( argument, arg2 );

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

  if ( ms_find_obj ( ch ) )
    return;

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

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

      if ( obj->wear_loc == WEAR_NONE && can_see_obj ( ch, obj ) )
      {
        wear_obj ( ch, obj, FALSE, -1 );

        if ( char_died ( ch ) )
          return;
      }
    }

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

    if ( arg2[0] != STRING_NULL )
      wear_bit = get_wflag ( arg2 );
    else
      wear_bit = -1;

    wear_obj ( ch, obj, TRUE, wear_bit );
  }

  return;
}

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

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

  if ( ms_find_obj ( ch ) )
    return;

  if ( !str_cmp ( arg, "all" ) )  /* SB Remove all */
  {
    for ( obj = ch->first_carrying; obj != NULL; obj = obj_next )
    {
      obj_next = obj->next_content;

      if ( obj->wear_loc != WEAR_NONE && can_see_obj ( ch, obj ) )
        remove_obj ( ch, obj->wear_loc, TRUE );
    }

    return;
  }

  if ( ( obj = get_obj_wear ( ch, arg ) ) == NULL )
  {
    send_to_char ( "You are not using that item.\n\r", ch );
    return;
  }

  if ( ( obj_next = get_eq_char ( ch, obj->wear_loc ) ) != obj )
  {
    act ( AT_PLAIN, "You must remove $p first.", ch, obj_next, NULL, TO_CHAR );
    return;
  }

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

  return;
}

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

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

  if ( ms_find_obj ( ch ) )
    return;

  shovel = FALSE;

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

  obj = get_obj_list_rev ( ch, arg, ch->in_room->last_content );

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

  separate_obj ( obj );

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

  switch ( ch->in_room->sector_type )
  {

    case SECT_CITY:

    case SECT_INSIDE:
      send_to_char ( "The floor is too hard to dig through.\n\r", ch );
      return;

    case SECT_WATER_SWIM:

    case SECT_WATER_NOSWIM:

    case SECT_UNDERWATER:
      send_to_char ( "You cannot bury something here.\n\r", ch );
      return;

    case SECT_AIR:
      send_to_char ( "What?  In the air?!\n\r", ch );
      return;
  }

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

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

  move = URANGE ( 2, move, 1000 );

  if ( move > ch->move )
  {
    send_to_char ( "You don't have the energy to bury something of that size.\n\r", ch );
    return;
  }

  ch->move -= move;

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

  act ( AT_ACTION, "You solemnly bury $p...", ch, obj, NULL, TO_CHAR );

  act ( AT_ACTION, "$n solemnly buries $p...", ch, obj, NULL, TO_ROOM );

  xSET_BIT ( obj->extra_flags, ITEM_BURIED );

  WAIT_STATE ( ch, URANGE ( 10, move / 2, 100 ) );

  return;
}

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

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

  if ( ms_find_obj ( ch ) )
    return;

  if ( !str_cmp ( arg, "all" ) )
  {
    if ( !ch->in_room->first_content )
    {
      send_to_char ( "All what? There's nothing here!\n\r", ch );
      return;
    }

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

      if ( !CAN_WEAR ( obj, ITEM_TAKE ) || !can_see_obj ( ch, obj ) )
      {
        continue;
      }

      if ( IS_SET ( obj->magic_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 )
          {
            continue;
          }
        }
      }

      if ( !IS_NPC ( ch ) && ch->pcdata->deity && ch->pcdata->deity->name[0] != STRING_NULL )
      {
        strcpy ( name, ch->pcdata->deity->name );
      }
      else
          if ( !IS_NPC ( ch ) && ch->pcdata->clan && ch->pcdata->clan->deity[0] != STRING_NULL )
          {
            strcpy ( name, ch->pcdata->clan->deity );
          }
          else
          {
            strcpy ( name, "The God's" );
          }

      ch->gold += 1;

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

      sprintf ( buf, "%s give you one gold coin for sacrificing %s.\n\r", name, obj->short_descr );

      send_to_char ( buf, ch );

      sprintf ( buf, "$n sacrifices $p to %s.", name );

      act ( AT_ACTION, buf, ch, obj, NULL, TO_ROOM );

      oprog_sac_trigger ( ch, obj );

      if ( obj_extracted ( obj ) )
        return;

      if ( cur_obj == obj->serial )
        global_objcode = rOBJ_SACCED;

      extract_obj ( obj );
    }

    return;
  }

  obj = get_obj_list_rev ( ch, arg, ch->in_room->last_content );

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

  separate_obj ( obj );

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

  if ( IS_SET ( obj->magic_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_color ( "\n\r&bA godly force freezes your outstretched hand.\n\r", ch );
        return;
      }
    }
  }

  if ( !IS_NPC ( ch ) && ch->pcdata->deity && ch->pcdata->deity->name[0] != STRING_NULL )
  {
    strcpy ( name, ch->pcdata->deity->name );
  }
    else
      if ( !IS_NPC ( ch ) && ch->pcdata->clan && ch->pcdata->clan->deity[0] != STRING_NULL )
      {
        strcpy ( name, ch->pcdata->clan->deity );
      }
      else
      {
        strcpy ( name, "The God's" );
      }

  ch->gold += 1;

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

  sprintf ( buf, "%s give you one gold coin for your sacrifice.\n\r", name );

  send_to_char ( buf, ch );

  sprintf ( buf, "$n sacrifices $p to %s.", name );

  act ( AT_ACTION, buf, ch, obj, NULL, TO_ROOM );

  oprog_sac_trigger ( ch, obj );

  if ( obj_extracted ( obj ) )
    return;

  if ( cur_obj == obj->serial )
    global_objcode = rOBJ_SACCED;

  separate_obj ( obj );

  extract_obj ( obj );

  save_house_by_vnum ( ch->in_room->vnum ); /* Prevent House Object Duplication */

  return;
}

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

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

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

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

  WAIT_STATE ( ch, 2 * PULSE_VIOLENCE );

  if ( staff->value[2] > 0 )
  {
    if ( !oprog_use_trigger ( ch, staff, NULL, NULL, NULL ) )
    {
      act ( AT_MAGIC, "$n brandishes $p.", ch, staff, NULL, TO_ROOM );
      act ( AT_MAGIC, "You brandish $p.", ch, staff, NULL, TO_CHAR );
    }

    for ( vch = ch->in_room->first_person; vch; vch = vch_next )
    {
      vch_next = vch->next_in_room;

      if ( !IS_NPC ( vch ) && xIS_SET ( vch->act, PLR_WIZINVIS ) && vch->pcdata->wizinvis >= LEVEL_IMMORTAL )
        continue;
      else
        switch ( skill_table[sn]->target )
        {

          default:
            bug ( "Do_brandish: bad target for sn %d.", sn );
            return;

          case TAR_IGNORE:

            if ( vch != ch )
              continue;

            break;

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

            break;

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

            break;

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

            break;
        }

      retcode = obj_cast_spell ( staff->value[3], staff->value[0], ch, vch, NULL );

      if ( retcode == rCHAR_DIED || retcode == rBOTH_DIED )
      {
        bug ( "do_brandish: char died", 0 );
        return;
      }
    }
  }

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

    if ( staff->serial == cur_obj )
      global_objcode = rOBJ_USED;

    extract_obj ( staff );
  }

  return;
}

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

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

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

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

  obj = NULL;

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

  WAIT_STATE ( ch, 1 * PULSE_VIOLENCE );

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

    retcode = obj_cast_spell ( wand->value[3], wand->value[0], ch, victim, obj );

    if ( retcode == rCHAR_DIED || retcode == rBOTH_DIED )
    {
      bug ( "do_zap: char died", 0 );
      return;
    }
  }

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

    if ( wand->serial == cur_obj )
      global_objcode = rOBJ_USED;

    extract_obj ( wand );
  }

  return;
}

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

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

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

  sprintf ( filename, "%s%s.vault", CLAN_DIR, clan->filename );

  if ( ( fp = fopen ( filename, "w" ) ) == NULL )
  {
    bug ( "save_clan_storeroom: fopen", 0 );
    perror ( filename );
  }
  else
  {
    templvl = ch->level;
    ch->level = LEVEL_HERO; /* make sure EQ doesn't get lost */
    contents = ch->in_room->last_content;

    if ( contents )
      fwrite_obj ( ch, contents, fp, 0, OS_CARRY, FALSE );

    fprintf ( fp, "#END\n" );

    ch->level = templvl;

    fclose ( fp );

    return;
  }

  return;
}

/* put an item on auction, or see the stats on the current item or bet */
void do_auction ( CHAR_DATA * ch, char *argument )
{
  OBJ_DATA *obj;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  int i;
  SKILLTYPE *sktmp;
  argument = one_argument ( argument, arg1 );
  argument = one_argument ( argument, arg2 );
  argument = one_argument ( argument, arg3 );
  set_char_color ( AT_LBLUE, ch );

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

  set_char_color ( AT_AUCTION, ch );

  if ( ch->level < 3 )
  {
    send_to_char ( "You must be at least level three to use the auction...\n\r", ch );
    return;
  }

  if ( ( time_info.hour > 18 || time_info.hour < 9 ) && auction->item == NULL && !IS_IMMORTAL ( ch ) )
  {
    send_to_char ( "\n\rThe auctioneer works between the hours of 9 AM and 6 PM\n\r", ch );
    return;
  }

  if ( arg1[0] == STRING_NULL )
  {
    if ( auction->item != NULL )
    {
      AFFECT_DATA *paf;
      obj = auction->item;
      /*
       * show item data here
       */
      send_to_char ( "&D--------------------------------------------------------------------------------\n\r", ch );
      ch_printf ( ch, "Object: &w'%s&D'\n\r",  obj->short_descr );
      send_to_char ( "&D--------------------------------------------------------------------------------\n\r", ch );
      ch_printf ( ch, "Item Type    : &w%s&D\n\r", item_type_name ( obj ) );

      if ( obj->item_type != ITEM_LIGHT && obj->wear_flags - 1 > 0 )
        ch_printf ( ch, "Wear location:&w %s&D\n\r", flag_string ( obj->wear_flags, w_flags ) );

      ch_printf ( ch, "Weight       :&w %d&D\n\r", obj->weight );

      ch_printf ( ch, "Level        :&w %d&D\n\r", obj->level );

      ch_printf ( ch, "Cost         :&w %d&D\n\r", obj->cost );

      ch_printf ( ch, "Flags        :&w %s&D\n\r", extra_bit_name ( &obj->extra_flags ) );

      switch ( obj->item_type )
      {

        case ITEM_CONTAINER:
          ch_printf ( ch, "&wCapacity     : %d&D items.\n\r", obj->value[0] );
          break;

        case ITEM_PILL:

        case ITEM_SCROLL:

        case ITEM_POTION:
          ch_printf ( ch, "Level %d spells of:", obj->value[0] );

          if ( obj->value[1] >= 0 && ( sktmp = get_skilltype ( obj->value[1] ) ) != NULL )
          {
            send_to_char ( " '", ch );
            send_to_char ( sktmp->name, ch );
            send_to_char ( "'", ch );
          }

          if ( obj->value[2] >= 0 && ( sktmp = get_skilltype ( obj->value[2] ) ) != NULL )
          {
            send_to_char ( " '", ch );
            send_to_char ( sktmp->name, ch );
            send_to_char ( "'", ch );
          }

          if ( obj->value[3] >= 0 && ( sktmp = get_skilltype ( obj->value[3] ) ) != NULL )
          {
            send_to_char ( " '", ch );
            send_to_char ( sktmp->name, ch );
            send_to_char ( "'", ch );
          }

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

          break;

        case ITEM_SALVE:
          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] ) ) != NULL )
          {
            send_to_char ( " '", ch );
            send_to_char ( sktmp->name, ch );
            send_to_char ( "'", ch );
          }

          if ( obj->value[5] >= 0 && ( sktmp = get_skilltype ( obj->value[5] ) ) != NULL )
          {
            send_to_char ( " '", ch );
            send_to_char ( sktmp->name, ch );
            send_to_char ( "'", ch );
          }

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

          break;

        case ITEM_WAND:

        case ITEM_STAFF:
          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] ) ) != NULL )
          {
            send_to_char ( " '", ch );
            send_to_char ( sktmp->name, ch );
            send_to_char ( "'", ch );
          }

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

          break;

        case ITEM_WEAPON:
          ch_printf ( ch, "Damage       : &w%d &Dto &w%d &D(average &w%d&D)\n\r", obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 );
          ch_printf ( ch, "Skill needed : &w%s&D\n\r", weapon_skills[obj->value[4]] );
          ch_printf ( ch, "Damage type  : &w%s&D\n\r", attack_table[obj->value[3]] );
          break;

        case ITEM_MISSILE_WEAPON:
          ch_printf ( ch, "Bonus damage added to projectiles is %d to %d (average %d).\n\r", obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 );
          ch_printf ( ch, "Skill needed:      %s\n\r", weapon_skills[obj->value[4]] );
          ch_printf ( ch, "Projectiles fired: %s\n\r", projectiles[obj->value[5]] );
          break;

        case ITEM_PROJECTILE:
          ch_printf ( ch, "Damage is %d to %d (average %d)%s\n\r",
                      obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2, IS_OBJ_STAT ( obj, ITEM_POISONED ) ? ", and is poisonous." : "." );
          ch_printf ( ch, "Damage type: %s\n\r", attack_table[obj->value[3]] );
          ch_printf ( ch, "Projectile type: %s\n\r", projectiles[obj->value[4]] );
          break;

        case ITEM_ARMOR:
          ch_printf ( ch, "Armor Class  : &w%d&D.\n\r", 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 );

      send_to_char ( "&D--------------------------------------------------------------------------------\n\r", ch );

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

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

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


      ch_printf ( ch, "Seller: &w%s&D.\n\r", auction->seller->name );

      ch_printf ( ch, "Bidder: &w%s&D.\n\r", auction->buyer->name );
      ch_printf ( ch, "Round : &w%d&D.\n\r", ( auction->going + 1 ) );
      ch_printf ( ch, "Time left in round: &w%d.&D\n\r", auction->pulse );

      if ( auction->bet > 0 )
        ch_printf ( ch, "\n\rCurrent bid on this item is %s gold.\n\r", num_punct ( auction->bet ) );
      else
        ch_printf ( ch, "\n\rNo bids on this item have been received.\n\r" );

      send_to_char ( "--------------------------------------------------------------------------------\n\r", ch );

      return;
    }
    else
    {
      set_char_color ( AT_LBLUE, ch );
      send_to_char ( "\n\rThere is nothing being auctioned right now.  What would you like to auction?\n\r", ch );
      return;
    }
  }

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

      if ( IS_SET ( sysdata.save_flags, SV_AUCTION ) )
        save_char_obj ( auction->seller );

      auction->item = NULL;

      if ( auction->buyer != NULL && auction->buyer != auction->seller ) /* return money to the buyer */
      {
        auction->buyer->gold += auction->bet;
        send_to_char ( "Your money has been returned.\n\r", auction->buyer );
      }

      return;
    }
  }

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

      if ( ch->level < auction->item->level )
      {
        send_to_char ( "This object's level is too high for your use.\n\r", ch );
        return;
      }

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

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

      newbet = parsebet ( auction->bet, arg2 );

      /*
       * ch_printf( ch, "Bid: %d\n\r",newbet);
       */

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

      /*
       * to avoid slow auction, use a bigger amount than 100 if the bet
       * is higher up - changed to 10000 for our high economy
       */
      if ( newbet < ( auction->bet ) )
      {
        send_to_char ( "You must at least bid  over the current bid.\n\r", ch );
        return;
      }

      if ( newbet > ch->gold )
      {
        send_to_char ( "You don't have that much money!\n\r", ch );
        return;
      }

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

      /*
       * Is it the item they really want to bid on? --Shaddai
       */
      if ( arg3[0] != STRING_NULL && !nifty_is_name ( arg3, auction->item->name ) )
      {
        send_to_char ( "That item is not being auctioned right now.\n\r", ch );
        return;
      }

      /*
       * the actual bet is OK!
       */
      /*
       * return the gold to the last buyer, if one exists
       */
      if ( auction->buyer != NULL && auction->buyer != auction->seller )
        auction->buyer->gold += auction->bet;

      ch->gold -= newbet;  /* substract the gold - important :) */

      if ( IS_SET ( sysdata.save_flags, SV_AUCTION ) )
        save_char_obj ( ch );

      auction->buyer = ch;

      auction->bet = newbet;

      auction->going = 0;

      auction->pulse = PULSE_AUCTION;  /* start the auction over again */

      sprintf ( buf, "A bid of %s gold has been received on %s.\n\r", num_punct ( newbet ), auction->item->short_descr );

      talk_auction ( buf );

      return;
    }
    else
    {
      send_to_char ( "There isn't anything being auctioned right now.\n\r", ch );
      return;
    }
  }

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

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

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

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

  /*
   * prevent repeat auction items
   */
  for ( i = 0; i < AUCTION_MEM && auction->history[i]; i++ )
  {
    if ( auction->history[i] == obj->pIndexData )
    {
      send_to_char ( "Such an item has been auctioned " "recently, try again later.\n\r", ch );
      return;
    }
  }

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

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

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

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

      default:
        act ( AT_TELL, "You cannot auction $Ts.", ch, NULL, item_type_name ( obj ), TO_CHAR );
        return;
        /*
         * insert any more item types here... items with a timer MAY NOT BE
         * AUCTIONED!
         */

      case ITEM_LIGHT:

      case ITEM_TREASURE:

      case ITEM_POTION:

      case ITEM_CONTAINER:

      case ITEM_KEYRING:

      case ITEM_QUIVER:

      case ITEM_DRINK_CON:

      case ITEM_FOOD:

      case ITEM_COOK:

      case ITEM_PEN:

      case ITEM_BOAT:

      case ITEM_PILL:

      case ITEM_PIPE:

      case ITEM_HERB_CON:

      case ITEM_INCENSE:

      case ITEM_FIRE:

      case ITEM_RUNEPOUCH:

      case ITEM_MAP:

      case ITEM_BOOK:

      case ITEM_RUNE:

      case ITEM_MATCH:

      case ITEM_HERB:

      case ITEM_WEAPON:

      case ITEM_MISSILE_WEAPON:

      case ITEM_ARMOR:

      case ITEM_STAFF:

      case ITEM_WAND:

      case ITEM_SCROLL:
        separate_obj ( obj );
        obj_from_char ( obj );

        if ( IS_SET ( sysdata.save_flags, SV_AUCTION ) )
          save_char_obj ( ch );

        auction->item = obj;

        auction->bet = 0;

        auction->buyer = ch;

        auction->seller = ch;

        auction->pulse = PULSE_AUCTION;

        auction->going = 0;

        auction->starting = atoi ( arg2 );

        /*
         * add the new item to the history
         */
        if ( AUCTION_MEM > 0 )
        {
          memmove ( ( char * ) auction->history + sizeof ( OBJ_INDEX_DATA * ), auction->history, ( AUCTION_MEM - 1 ) * sizeof ( OBJ_INDEX_DATA * ) );
          auction->history[0] = obj->pIndexData;
        }

        /*
         * reset the history timer
         */
        auction->hist_timer = 0;

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

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

        talk_auction ( buf );

        return;
    }  /* switch */
  else
  {
    act ( AT_TELL, "Try again later - $p is being auctioned right now!", ch, auction->item, NULL, TO_CHAR );

    if ( !IS_IMMORTAL ( ch ) )
      WAIT_STATE ( ch, PULSE_VIOLENCE );

    return;
  }
}

/* Make objects in rooms that are nofloor fall - Scryn 1/23/96 */
void obj_fall ( OBJ_DATA * obj, bool through )
{
  EXIT_DATA *pexit;
  ROOM_INDEX_DATA *to_room;
  static int fall_count;
  char buf[MAX_STRING_LENGTH];
  static bool is_falling; /* Stop loops from the call to obj_to_room()  -- Altrag */

  if ( !obj->in_room || is_falling )
    return;

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

  if ( xIS_SET ( obj->in_room->room_flags, ROOM_NOFLOOR ) && CAN_GO ( obj, 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 )
    {
      sprintf ( buf, "Object falling into same room, room %d", to_room->vnum );
      bug ( buf, 0 );
      extract_obj ( obj );
      return;
    }

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

    obj_from_room ( obj );

    is_falling = TRUE;
    obj = obj_to_room ( obj, to_room, NULL );
    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 = (int)9.81*sqrt(fall_count*2/9.81)*obj->weight/2;
       */
      int dam = fall_count * obj->weight / 2;
      /*
       * Damage players
       */

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

        for ( rch = obj->in_room->first_person; rch; rch = rch->next_in_room, chcnt++ )
          if ( number_range ( 0, chcnt ) == 0 )
            vch = rch;

        act ( AT_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;
}

/* Scryn, by request of Darkur, 12/04/98 */
/* Reworked recursive_note_find to fix crash bug when the note was left
 * blank.  7/6/98 -- Shaddai
 */
void do_findnote ( CHAR_DATA * ch, char *argument )
{
  OBJ_DATA *obj;

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

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

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

  if ( obj )
  {
    if ( obj->in_obj )
    {
      obj_from_obj ( obj );
      obj = obj_to_char ( obj, ch );
    }

    wear_obj ( ch, obj, TRUE, -1 );
  }
  else
    send_to_char ( "Note not found.\n\r", ch );

  return;
}

OBJ_DATA *recursive_note_find ( OBJ_DATA * obj, char *argument )
{
  OBJ_DATA *returned_obj;
  bool match = TRUE;
  char *argcopy;
  char *subject;
  char arg[MAX_INPUT_LENGTH];
  char subj[MAX_STRING_LENGTH];

  if ( !obj )
    return NULL;

  switch ( obj->item_type )
  {

    case ITEM_PAPER:

      if ( ( subject = get_extra_descr ( "_subject_", obj->first_extradesc ) ) == NULL )
        break;

      sprintf ( subj, "%s", strlower ( subject ) );

      subject = strlower ( subj );

      argcopy = argument;

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

        if ( arg[0] == STRING_NULL )
          break;

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

      if ( match )
        return obj;

      break;

    case ITEM_CONTAINER:

    case ITEM_CORPSE_NPC:

    case ITEM_CORPSE_PC:
      if ( obj->first_content )
      {
        returned_obj = recursive_note_find ( obj->first_content, argument );

        if ( returned_obj )
          return returned_obj;
      }

      break;

    default:
      break;
  }

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

void do_rolldie ( CHAR_DATA * ch, char *argument )
{
  OBJ_DATA *die;
  char output_string[MAX_STRING_LENGTH];
  char roll_string[MAX_STRING_LENGTH];
  char total_string[MAX_STRING_LENGTH];
  char *verb;
  /*
   * char* face_string = NULL;
   * char** face_table = NULL;
   */
  int rollsum = 0;
  int roll_count = 0;
  int numsides;
  int numrolls;
  bool *face_seen_table = NULL;

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

  if ( ( die = get_eq_char ( ch, WEAR_HOLD ) ) == NULL || die->item_type != ITEM_CHANCE )
  {
    ch_printf ( ch, "You must be holding an item of chance!\n\r" );
    return;
  }

  numrolls = ( is_number ( argument ) ) ? atoi ( argument ) : 1;

  verb = get_chance_verb ( die );

  if ( numrolls > 100 )
  {
    ch_printf ( ch, "You can't %s more than 100 times!\n\r", verb );
    return;
  }

  numsides = die->value[0];

  if ( numsides <= 1 )
  {
    ch_printf ( ch, "There is no element of chance in this game!\n\r" );
    return;
  }

  if ( die->value[3] == 1 )
  {
    if ( numrolls > numsides )
    {
      ch_printf ( ch, "Nice try, but you can only %s %d times.\n\r", verb, numsides );
      return;
    }

    face_seen_table = calloc ( numsides, sizeof ( bool ) );

    if ( !face_seen_table )
    {
      bug ( "do_rolldie: cannot allocate memory for face_seen_table array, terminating.\n\r", 0 );
      return;
    }
  }

  sprintf ( roll_string, " " );

  while ( roll_count++ < numrolls )
  {
    int current_roll;
    char current_roll_string[MAX_STRING_LENGTH];

    do
    {
      current_roll = number_range ( 1, numsides );
    }
    while ( die->value[3] == 1 && face_seen_table[current_roll - 1] == TRUE );

    if ( die->value[3] == 1 )
      face_seen_table[current_roll - 1] = TRUE;

    rollsum += current_roll;

    if ( roll_count > 1 )
      strcat ( roll_string, ", " );

    if ( numrolls > 1 && roll_count == numrolls )
      strcat ( roll_string, "and " );

    if ( die->value[1] == 1 )
    {
      char *face_name = get_ed_number ( die, current_roll );

      if ( face_name )
      {
        char *face_name_copy = strdup ( face_name ); /* Since I want to tokenize without modifying the original string */
        sprintf ( current_roll_string, "%s", strtok ( face_name_copy, "\n" ) );
        free ( face_name_copy );
      }
      else
        sprintf ( current_roll_string, "%d", current_roll );
    }
    else
      sprintf ( current_roll_string, "%d", current_roll );

    strcat ( roll_string, current_roll_string );
  }

  if ( numrolls > 1 && die->value[2] == 1 )
  {
    sprintf ( total_string, ", for a total of %d", rollsum );
    strcat ( roll_string, total_string );
  }

  strcat ( roll_string, ".\n\r" );

  sprintf ( output_string, "You %s%s", verb, roll_string );
  act ( AT_GREEN, output_string, ch, NULL, NULL, TO_CHAR );
  sprintf ( output_string, "$n %s%s", verb, roll_string );
  act ( AT_GREEN, output_string, ch, NULL, NULL, TO_ROOM );

  if ( face_seen_table )
    free ( face_seen_table );

  return;
}

char *get_ed_number ( OBJ_DATA * obj, int number )
{
  EXTRA_DESCR_DATA *ed;
  int count;

  for ( ed = obj->first_extradesc, count = 1; ed; ed = ed->next, count++ )
  {
    if ( count == number )
      return ed->description;
  }

  return NULL;
}

char *get_chance_verb ( OBJ_DATA * obj )
{
  return ( obj->action_desc[0] != STRING_NULL ) ? obj->action_desc : "roll$q";
}

/*dice chance deal throw*/
/* Junk command installed by Samson 1-13-98
 * Code courtesy of Stu, from the mailing list. Allows player to destroy an item in their inventory.
 * Debugged and cleaned up on 4-16-01 by Samson.
 */
void do_junk ( CHAR_DATA * ch, char *argument )
{
  OBJ_DATA *obj, *obj_next;
  bool found = FALSE;

  if ( !argument || argument[0] == STRING_NULL )
  {
    send_to_char ( "Junk what?\n\r", ch );
    return;
  }

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

    if ( ( nifty_is_name ( argument, obj->name ) ) && can_see_obj ( ch, obj ) && obj->wear_loc == WEAR_NONE )
    {
      found = TRUE;
      break;
    }
  }

  if ( found )
  {
    if ( !can_drop_obj ( ch, obj ) && ch->level < LEVEL_IMMORTAL )
    {
      send_to_char ( "You cannot junk that, it's cursed!\n\r", ch );
      return;
    }

    separate_obj ( obj );

    obj_from_char ( obj );
    extract_obj ( obj );
    act ( AT_ACTION, "$n junks $p.", ch, obj, NULL, TO_ROOM );
    act ( AT_ACTION, "You junk $p.", ch, obj, NULL, TO_CHAR );
  }

  return;
}

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

  if ( !argument || argument[0] == STRING_NULL )
  {
    send_to_char ( "Donate what?\n\r", ch );
    return;
  }

  if ( ch->position == POS_FIGHTING )
  {
    send_to_char ( "You cannot donate while fighting!\n\r", ch );
    return;
  }

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

  if ( !can_drop_obj ( ch, obj ) && ch->level < LEVEL_IMMORTAL )
  {
    send_to_char ( "You cannot donate that, it's cursed!\n\r", ch );
    return;
  }

  if ( ( obj->item_type == ITEM_CORPSE_NPC ) || ( obj->item_type == ITEM_CORPSE_PC ) )
  {
    send_to_char ( "You cannot donate corpses!\n\r", ch );
    return;
  }

  if ( obj->timer > 0 )
  {
    send_to_char ( "You cannot donate that.\n\r", ch );
    return;
  }
  if( xIS_SET( obj->extra_flags, ITEM_DONATION ) )
{
   send_to_char("You cannot donate a previously donated item\n\r", ch);
   return;
}

    if ( obj->item_type == ITEM_WEAPON )
    { 
      act ( AT_ACTION, "You donate $p, how generous of you!", ch, obj, NULL, TO_CHAR );
      obj->cost = 0;
      separate_obj ( obj );
      obj_from_char ( obj );
      obj_to_room ( obj, get_room_index ( ROOM_VNUM_WEAPON ), NULL );
      xSET_BIT ( obj->extra_flags, ITEM_DONATION );
      save_char_obj ( ch );
      return;
    }
    else if ( obj->item_type == ITEM_ARMOR )
    {
      act ( AT_ACTION, "You donate $p, how generous of you!", ch, obj, NULL, TO_CHAR );
      obj->cost = 0;
      separate_obj ( obj );
      obj_from_char ( obj );
      obj_to_room ( obj, get_room_index ( ROOM_VNUM_ARMOR ), NULL );
      xSET_BIT ( obj->extra_flags, ITEM_DONATION );
      save_char_obj ( ch );
      return;
    }
    else
    {
      act ( AT_ACTION, "You donate $p, how generous of you!", ch, obj, NULL, TO_CHAR );
      obj->cost = 0;
      separate_obj ( obj );
      obj_from_char ( obj );
      obj_to_room ( obj, get_room_index ( ROOM_VNUM_OTHER ), NULL );
      xSET_BIT ( obj->extra_flags, ITEM_DONATION );
      save_char_obj ( ch );
      return;
    }
 return;
}