dbna/clans/
dbna/councils/
dbna/deity/
dbna/gods/
dbna/houses/
dbna/space/
/****************************************************************************
* [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
* -----------------------------------------------------------|   (0...0)   *
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
* -----------------------------------------------------------|    {o o}    *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
* Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
* Tricops and Fireblade                                      |             *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
* Chastain, Michael Quan, and Mitchell Tse.                                *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
* ------------------------------------------------------------------------ *
*			   Object manipulation module			    *
****************************************************************************/

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


#define MAX_ZENI 2100000000 //zeni protection code supports sac,give,get,auction(hopefully)


/*double sqrt( double x );*/

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

/*
 * Local functions.
 */
void get_obj args( ( CHAR_DATA * ch, OBJ_DATA * obj, OBJ_DATA * container ) );
bool remove_obj args( ( CHAR_DATA * ch, int iWear, bool fReplace ) );
void wear_obj args( ( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace, sh_int 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
 */
sh_int get_obj_resistance( OBJ_DATA * obj )
{
  sh_int resist;

  resist = number_fuzzy( MAX_ITEM_IMPACT );

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

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

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

  return URANGE( 10, resist, 99 );
}


void get_obj( CHAR_DATA * ch, OBJ_DATA * obj, OBJ_DATA * container )
{
//  CLAN_DATA *clan;
  int weight;
  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 ) )
  {
    save_clan_storeroom( ch );
  }

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

  if( obj->item_type == ITEM_MONEY )
  {

    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
    //zeni protection here!
    if( ch->gold > MAX_ZENI )
    {
      send_to_char( "You cant get anymore Zeni.\n\r", ch );
      return;
    }
    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;
  sh_int number;
  bool found;

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

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

  if( ms_find_obj( ch ) )
    return;

  if( arg2[0] == '\0' )
  {
    if( number <= 1 && str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
    {
      /*
       * 'get obj' 
       */
      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;
      }
      if( obj->item_type == ITEM_DRAGONBALL && IS_NPC( ch ) && !xIS_SET( ch->act, ACT_SECRETIVE ) )
      {
        ch_printf( ch, "NPC's cannot take dragonballs.\n\r" );
        do_say( ch, "I can't take that." );
        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 ) )
//      if ( IS_SET( sysdata.save_flags, SV_GIVE ) )
      save_char_obj( ch );
    }
    else
    {
      sh_int 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 ) )
        {
          found = TRUE;

          if( obj->item_type == ITEM_DRAGONBALL && IS_NPC( ch ) )
            continue;

          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)
            if(   /*IS_SET(sysdata.save_flags, SV_GIVE)
                   * && */ !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 ) )
//        if ( IS_SET( sysdata.save_flags, SV_GIVE ) )
        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] != '\0'
            && str_cmp( name, ch->name ) && str_cmp( container->action_desc, ch->name ) )
        {
          send_to_char( "You did not inflict the death blow upon this corpse.\n\r", ch );
          return;
        }

        if( IS_OBJ_STAT( container, ITEM_CLANCORPSE )
            && !IS_NPC( ch ) && str_cmp( name, ch->name ) && container->action_desc[0] == '\0' )
        {
          send_to_char( "You can not loot that 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 ) )
//      if ( IS_SET( sysdata.save_flags, SV_GIVE ) )
      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 ) )
            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 ) )
//      if ( found && IS_SET( sysdata.save_flags, SV_GIVE ) )
      if( found )
        save_char_obj( ch );
    }
  }
  return;
}



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

  argument = one_argument( argument, arg1 );
  if( is_number( arg1 ) )
  {
    number = atoi( arg1 );
    if( number < 1 )
    {
      send_to_char( "That was easy...\n\r", ch );
      return;
    }
    argument = one_argument( argument, arg1 );
  }
  else
    number = 0;
  argument = one_argument( argument, arg2 );
  /*
   * munch optional words 
   */
  if( ( !str_cmp( arg2, "into" ) || !str_cmp( arg2, "inside" )
        || !str_cmp( arg2, "in" ) || !str_cmp( arg2, "under" )
        || !str_cmp( arg2, "onto" ) || !str_cmp( arg2, "on" ) ) && argument[0] != '\0' )
    argument = one_argument( argument, arg2 );

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

  if( ms_find_obj( ch ) )
    return;

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

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

//  if ( !container->carried_by && IS_SET(sysdata.save_flags, SV_PUT) )
//  if ( !container->carried_by && IS_SET(sysdata.save_flags, SV_GIVE) )
  if( !container->carried_by )
    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( IS_OBJ_STAT( obj, ITEM_NOAUCTION ) )
    {
      send_to_char( "You can't seem to fit it into a container.\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 )
    {
      save_clan_storeroom( ch );
    }
  }
  else
  {
    bool found = FALSE;
    int cnt = 0;
    bool fAll;
    char *chk;

    if( !str_cmp( arg1, "all" ) )
      fAll = TRUE;
    else
      fAll = FALSE;
    if( number > 1 )
      chk = arg1;
    else
      chk = &arg1[4];

    separate_obj( container );
    /*
     * 'put all container' or 'put all.obj container' 
     */
    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 )
          && !IS_OBJ_STAT( obj, ITEM_NOAUCTION )
          && ( 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 )
    {
      save_clan_storeroom( ch );
    }
  }

  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] == '\0' )
  {
    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 )
	{
		if ( !str_cmp( arg, "coins" ) || !str_cmp( arg, "coin" ) || !str_cmp( arg, "zeni" ))
		{
			if ( ch->gold < number )
			{
				send_to_char( "You haven't got that many zeni.\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 zeni.", ch, NULL, NULL, TO_ROOM );
			obj_to_room( create_money( number ), ch->in_room );
			save_house_by_vnum(ch->in_room->vnum);
			send_to_char( "You let the zeni slip from your hand.\n\r", ch );
				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 );
    if( IS_OBJ_STAT( obj, ITEM_GROUNDROT ) )
    {
      extract_obj( obj );
      act( AT_BLOOD, "$p turns to dust upon touching the ground.", ch, obj, NULL, TO_CHAR );
      act( AT_BLOOD, "$p turns to dust upon touching the ground.", ch, obj, NULL, TO_ROOM );
    }
    else
    {
      obj = obj_to_room( obj, ch->in_room );
      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 ) )
    {
      save_clan_storeroom( ch );
    }

  }
  else
  {
    int cnt = 0;
    char *chk;
    bool fAll;

    if( !str_cmp( arg, "all" ) )
      fAll = TRUE;
    else
      fAll = FALSE;
    if( number > 1 )
      chk = arg;
    else
      chk = &arg[4];
    /*
     * 'drop all' or 'drop all.obj' 
     */
    if( 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 );
        if( IS_OBJ_STAT( obj, ITEM_GROUNDROT ) )
        {
          extract_obj( obj );
          act( AT_BLOOD, "$p turns to dust upon touching the ground.", ch, obj, NULL, TO_CHAR );
          act( AT_BLOOD, "$p turns to dust upon touching the ground.", ch, obj, NULL, TO_ROOM );
        }
        else
        {
          obj = obj_to_room( obj, ch->in_room );
          oprog_drop_trigger( ch, obj );  /* mudprogs */
        }
        if( char_died( ch ) )
          return;
        if( number && cnt >= number )
          break;
      }
    }

    if( !found )
    {
      if( fAll )
        act( AT_PLAIN, "You 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 ) )
//  if ( IS_SET( sysdata.save_flags, SV_GIVE ) )
  save_char_obj( ch );  /* duping protector */
  return;
}



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

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

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

  if( ms_find_obj( ch ) )
    return;

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

    amount = atoi( arg1 );
    if( amount <= 0 || ( str_cmp( arg2, "coins" ) && str_cmp( arg2, "coin" ) && str_cmp( arg2, "zeni" ) ) )
    {
      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] != '\0' )
      argument = one_argument( argument, arg2 );
    if( arg2[0] == '\0' )
    {
      send_to_char( "Give what to whom?\n\r", ch );
      return;
    }

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

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

    if( auction->item )
      if( !strcmp( auction->seller->name, ch->name ) )
      {
        send_to_char( "Tsk tsk, trying to avoid the auction fee.\n\r", ch );
        return;
      }

    if( victim->gold > MAX_ZENI )
    {
      if( str_cmp( arg2, "coins" ) && str_cmp( arg2, "coin" ) && str_cmp( arg2, "zeni" ) )
      {
        send_to_char( "He cant take Zeni anymore.\n\r", ch );
        return;
      }
    }

    ch->gold -= amount;
    victim->gold += amount;
    strcpy( buf, "$n gives you " );
    strcat( buf, arg1 );
    strcat( buf, ( amount > 1 ) ? " zeni." : " zeni." );

    act( AT_ACTION, buf, ch, NULL, victim, TO_VICT );
    act( AT_ACTION, "$n gives $N some zeni.", ch, NULL, victim, TO_NOTVICT );
    act( AT_ACTION, "You give $N some zeni.", ch, NULL, victim, TO_CHAR );
    mprog_bribe_trigger( victim, ch, amount );
//    if ( IS_SET( sysdata.save_flags, SV_GIVE ) && !char_died(ch) )
    if( !char_died( ch ) )
      save_char_obj( ch );
//    if ( IS_SET( sysdata.save_flags, SV_RECEIVE ) && !char_died(victim) )
//    if ( IS_SET( sysdata.save_flags, SV_GIVE ) && !char_died(victim) )
    if( !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( IS_OBJ_STAT( obj, ITEM_NOGIVE ) )
  {
    ch_printf( ch, "You can't give that.\n\r" );
    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) )
  if( !char_died( ch ) )
    save_char_obj( ch );
//  if ( IS_SET(sysdata.save_flags, SV_RECEIVE) && !char_died(victim) )
//  if ( IS_SET(sysdata.save_flags, SV_GIVE) && !char_died(victim) )
  if( !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;

  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:
    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:
      if( ch && obj->value[0] >= 1 )
        ch->armor += apply_ac( obj, obj->wear_loc );
      if( --obj->value[0] <= 0 )
      {
        if( !IS_PKILL( ch ) && !in_arena( ch ) )
        {
          make_scraps( obj );
          objcode = rOBJ_SCRAPPED;
        }
        else
        {
          obj->value[0] = 1;
          ch->armor -= apply_ac( obj, obj->wear_loc );
        }
      }
      else if( ch && obj->value[0] >= 1 )
        ch->armor -= apply_ac( obj, obj->wear_loc );
      break;
    case ITEM_WEAPON:
      if( --obj->value[0] <= 0 )
      {
        if( !IS_PKILL( ch ) && !in_arena( ch ) )
        {
          make_scraps( obj );
          objcode = rOBJ_SCRAPPED;
        }
        else
          obj->value[0] = 1;
      }
      break;
  }
  return objcode;
}


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

  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->pIndexData->vnum == 1337 && ch->hit < ch->max_hit )
  {
    act( AT_RED, "You can't remove that till your health returns to full.", 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;
}

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

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


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

  for( otmp = ch->first_carrying; otmp; otmp = otmp->next_content )
    if( otmp->wear_loc == wear_loc )
    {
      if( !otmp->pIndexData->layers )
        return FALSE;
      else
        bitlayers |= otmp->pIndexData->layers;
    }
  if( ( bitlayers && !objlayers ) || bitlayers > objlayers )
    return FALSE;
  if( !bitlayers || ( ( bitlayers & ~objlayers ) == bitlayers ) )
    return TRUE;
  return FALSE;
}

/*
 * 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, sh_int wear_bit )
{
  char buf[MAX_STRING_LENGTH];
  OBJ_DATA *tmpobj = NULL;
  sh_int bit, tmp;
  bool bypass = FALSE;

  separate_obj( obj );
  if( ch->exp < obj->level )
  {
    sprintf( buf, "You must have a powerlevel of %s to use this object.\n\r", num_punct_ld( obj->level ) );
    send_to_char( buf, ch );
    act( AT_ACTION, "$n tries to use $p, but is too weak.", ch, obj, NULL, TO_ROOM );
    return;
  }

  if( IS_OBJ_STAT( obj, ITEM_PROTOTYPE ) && ch->level < LEVEL_SAVIOR /*LEVEL_DEMI */  &&
      !IS_NPC( ch ) )
  {
    act( AT_MAGIC, "You are forbidden to use that item.", ch, NULL, NULL, TO_CHAR );
    act( AT_ACTION, "$n tries to use $p, but is forbidden to do so.", ch, obj, NULL, TO_ROOM );
    return;
  }

  if( wearing_sentient_chip( ch ) && ( IS_HC( ch ) ||
                                       ( !( IS_OBJ_STAT( obj, ITEM_ANTI_GOOD ) && IS_GOOD( ch ) ) &&
                                         !( IS_OBJ_STAT( obj, ITEM_ANTI_NEUTRAL ) && IS_NEUTRAL( ch ) ) &&
                                         !( IS_OBJ_STAT( obj, ITEM_ANTI_EVIL ) && IS_EVIL( ch ) ) ) ) )
  {
    if( !IS_OBJ_STAT( obj, ITEM_ANTI_ANDROID ) ||
        ( !IS_OBJ_STAT( obj, ITEM_ANTI_SAIYAN ) &&
          is_saiyan( ch ) ) ||
        ( !IS_OBJ_STAT( obj, ITEM_ANTI_HUMAN ) &&
          is_human( ch ) ) ||
        ( !IS_OBJ_STAT( obj, ITEM_ANTI_BIO_ANDROID ) &&
          is_bio( ch ) ) ||
        ( !IS_OBJ_STAT( obj, ITEM_ANTI_ICER ) &&
          is_icer( ch ) ) ||
        ( !IS_OBJ_STAT( obj, ITEM_ANTI_NAMEK ) &&
          is_namek( ch ) ) ||
        ( !IS_OBJ_STAT( obj, ITEM_ANTI_HUMAN ) &&
          is_kaio( ch ) ) ||
        ( !IS_OBJ_STAT( obj, ITEM_ANTI_HUMAN ) &&
          is_demon( ch ) ) ||
        ( !IS_OBJ_STAT( obj, ITEM_ANTI_MAJIN ) &&
          is_majin( ch ) ) ||
        ( !IS_OBJ_STAT( obj, ITEM_ANTI_SYMBIOTE ) &&
          is_symbiote( ch ) ) || ( !IS_OBJ_STAT( obj, ITEM_ANTI_TUFFLE ) && is_tuffle( ch ) ) )
    {
      bypass = TRUE;
    }
  }

  /*
   * cleaned up the uglyness from before -Goku 09.30.04 
   */
  if( !bypass )
    if( ( IS_OBJ_STAT( obj, ITEM_ONLY_SAIYAN ) && !is_saiyan( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_HUMAN ) && !is_human( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_HALFBREED ) && !is_hb( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_NAMEK ) && !is_namek( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_ANDROID ) && ( !is_android( ch ) && !is_superandroid( ch ) ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_ICER ) && !is_icer( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_BIO_ANDROID ) && !is_bio( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_MAJIN ) && !is_majin( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_DEMON ) && !is_demon( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_KAIO ) && !is_kaio( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_GENIE ) && !is_genie( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_HARDCORE ) && !IS_HC( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_SAIBAMAN ) && !is_saibaman( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_SYMBIOTE ) && !is_symbiote( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_TUFFLE ) && !is_tuffle( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ONLY_YARDRATIAN ) && !is_yardratian( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_SAIYAN ) && is_saiyan( ch ) )
        /*
         * LAME hack by someone, but it probably needs to be kept
         * * in for now.  I'll fix it later on -Goku 09.30.04 
         */
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_HUMAN ) && ( is_human( ch ) || is_kaio( ch ) || is_demon( ch ) ) )
//      || (IS_OBJ_STAT(obj, ITEM_ANTI_HUMAN) && is_human(ch))
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_HALFBREED ) && is_hb( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_NAMEK ) && is_namek( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_ANDROID ) && ( is_android( ch ) || is_superandroid( ch ) ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_ICER ) && is_icer( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_BIO_ANDROID ) && ( is_bio( ch ) || is_genie( ch ) ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_GENIE ) && is_genie( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_HARDCORE ) && IS_HC( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_MAJIN ) && is_majin( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_DEMON ) && is_demon( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_KAIO ) && is_kaio( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_GOOD ) && IS_GOOD( ch ) && !IS_HC( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_NEUTRAL ) && IS_NEUTRAL( ch ) && !IS_HC( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_EVIL ) && IS_EVIL( ch ) && !IS_HC( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_TUFFLE ) && is_tuffle( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_YARDRATIAN ) && is_yardratian( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANTI_SAIBAMAN ) && is_saibaman( ch ) )
        || ( IS_OBJ_STAT( obj, ITEM_ANDROID_CHIP ) && ( !is_android( ch ) && !is_superandroid( ch ) ) ) )
    {
      act( AT_MAGIC, "You are forbidden to use that item.", ch, NULL, NULL, TO_CHAR );
      act( AT_ACTION, "$n tries to use $p, but is forbidden to do so.", ch, obj, NULL, TO_ROOM );
      return;
    }

  if( CAN_WEAR( obj, ITEM_WEAR_PANEL ) && is_superandroid( ch ) && IS_AFFECTED( ch, AFF_SUPERANDROID ) )
  {
    act( AT_MAGIC, "You can't use chips while transformed.", ch, NULL, NULL, TO_CHAR );
    return;
  }

/* disabled to allow people to use shilds.  all chips *should* be
 * anti-everything anyways so this shouldn't be a problem -Goku 09.30.04 */
/*
	if( IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD) && !is_android(ch)
	    && !is_superandroid(ch) && obj->pIndexData->vnum != 1337 )
	{
	  act( AT_MAGIC, "You are forbidden to use that item.", ch, NULL, NULL, TO_CHAR );
          act( AT_ACTION, "$n tries to use $p, but is forbidden to do so.",
                     ch, obj, NULL, TO_ROOM );
          return;
	}
*/
  if( is_transformed( ch ) && obj->pIndexData->vnum == 1337 )
  {
    ch_printf( ch, "&BYou must power down completely first.\n\r" );
    return;
  }

  if( wearing_shield( ch ) && IS_SET( obj->wear_flags, ITEM_WEAR_SHIELD ) )
  {
    ch_printf( ch, "&wYou must remove the current chip/shield you are wearing first!\n\r" );
    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_WEAR_FINGER:
      if( get_eq_char( ch, WEAR_FINGER_L )
          && get_eq_char( ch, WEAR_FINGER_R )
          && !remove_obj( ch, WEAR_FINGER_L, fReplace ) && !remove_obj( ch, WEAR_FINGER_R, fReplace ) )
        return;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    case ITEM_WEAR_BACK:
      if( !can_layer( ch, obj, WEAR_BACK ) )
      {
        send_to_char( "It won't fit overtop of what you're already wearing.\n\r", ch );
        return;
      }
      if( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
      {
        act( AT_ACTION, "$n slings $p on $s back.", ch, obj, NULL, TO_ROOM );
        act( AT_ACTION, "You sling $p on your back.", ch, obj, NULL, TO_CHAR );
      }
      equip_char( ch, obj, WEAR_BACK );
      oprog_wear_trigger( ch, obj );
      return;

    case ITEM_WEAR_WAIST:
      /*
       * if ( !remove_obj( ch, WEAR_WAIST, fReplace ) )
       * return;
       */
      if( !can_layer( ch, obj, WEAR_WAIST ) )
      {
        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 about $s waist.", ch, obj, NULL, TO_ROOM );
        act( AT_ACTION, "You wear $p about your waist.", ch, obj, NULL, TO_CHAR );
      }
      equip_char( ch, obj, WEAR_WAIST );
      oprog_wear_trigger( ch, obj );
      return;

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

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

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

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

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

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

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

      bug( "Wear_obj: no free ankle.", 0 );
      send_to_char( "You already wear two ankle items.\n\r", ch );
      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_WEAR_PANEL:
      if( !is_android( ch ) && !is_superandroid( ch ) )
      {
        send_to_char( "That would hurt!\n\r", ch );
        return;
      }

      if( !remove_obj( ch, ITEM_WEAR_PANEL, fReplace ) )
        return;
      if( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
      {
        act( AT_ACTION, "$n installs $p.", ch, obj, NULL, TO_ROOM );
        act( AT_ACTION, "You installs $p.", ch, obj, NULL, TO_CHAR );
      }
      equip_char( ch, obj, ITEM_WEAR_PANEL );
      oprog_wear_trigger( ch, obj );
      return;

    case ITEM_WEAR_FOREHEAD:
      if( !remove_obj( ch, WEAR_FOREHEAD, fReplace ) )
        return;
      if( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
      {
        act( AT_ACTION, "$n applys $p to $s forehead.", ch, obj, NULL, TO_ROOM );
        act( AT_ACTION, "You apply $p onto your forehead.", ch, obj, NULL, TO_CHAR );
      }
      equip_char( ch, obj, WEAR_FOREHEAD );
      oprog_wear_trigger( ch, obj );
      return;

    case ITEM_WEAR_STANDING:
      if( !remove_obj( ch, WEAR_STANDING, fReplace ) )
        return;
      if( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
      {
        act( AT_ACTION, "$n steps ontop of $p.", ch, obj, NULL, TO_ROOM );
        act( AT_ACTION, "You step ontop of $p.", ch, obj, NULL, TO_CHAR );
      }
      equip_char( ch, obj, WEAR_STANDING );
      oprog_wear_trigger( ch, obj );
      return;

    case ITEM_WEAR_TAIL:
      if( !remove_obj( ch, WEAR_TAIL, fReplace ) )
        return;
      if( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
      {
        act( AT_ACTION, "$n straps $p around $s tail.", ch, obj, NULL, TO_ROOM );
        act( AT_ACTION, "You strap $p areound your tail.", ch, obj, NULL, TO_CHAR );
      }
      equip_char( ch, obj, WEAR_TAIL );
      oprog_wear_trigger( ch, obj );
      return;

    case ITEM_WEAR_ABOVEHEAD:
      if( !remove_obj( ch, WEAR_ABOVEHEAD, fReplace ) )
        return;
      if( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
      {
        act( AT_ACTION, "$n tosses $p above $s head.", ch, obj, NULL, TO_ROOM );
        act( AT_ACTION, "You toss $p above your head.", ch, obj, NULL, TO_CHAR );
      }
      equip_char( ch, obj, WEAR_ABOVEHEAD );
      oprog_wear_trigger( ch, obj );
      return;

    case ITEM_WEAR_SCOUTER:
      if( !remove_obj( ch, WEAR_SCOUTER, fReplace ) )
        return;
      if( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
      {
        act( AT_ACTION, "$n places $p over $s eye and gives it a click.", ch, obj, NULL, TO_ROOM );
        act( AT_ACTION, "You place $p over your eye and give it a click.", ch, obj, NULL, TO_CHAR );
      }
      equip_char( ch, obj, WEAR_SCOUTER );
      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;

        tmpobj = get_eq_char( ch, WEAR_WIELD );
        mw = get_eq_char( ch, WEAR_MISSILE_WIELD );
        dw = get_eq_char( ch, WEAR_DUAL_WIELD );
        if( tmpobj && ( mw || dw ) )
        {
          send_to_char( "You're already wielding two weapons.\n\r", ch );
          return;
        }
        hd = get_eq_char( ch, WEAR_HOLD );
        if( ( mw && hd ) || ( tmpobj && hd ) )
        {
          send_to_char( "You're already wielding a weapon AND holding something.\n\r", ch );
          return;
        }
      }

      if( tmpobj )
      {
        if( can_dual( ch ) )
        {
          if( get_obj_weight( obj ) + get_obj_weight( tmpobj ) > ( get_curr_str( ch ) / 2 ) )
          {
            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 dual-wields $p.", ch, obj, NULL, TO_ROOM );
            act( AT_ACTION, "You dual-wield $p.", ch, obj, NULL, TO_CHAR );
          }
          if( 1 << bit == ITEM_MISSILE_WIELD )
            equip_char( ch, obj, WEAR_MISSILE_WIELD );
          else
            equip_char( ch, obj, WEAR_DUAL_WIELD );
          oprog_wear_trigger( ch, obj );
        }
        return;
      }

      if( get_obj_weight( obj ) > ( get_curr_str( ch ) / 2 ) )
      {
        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;
  sh_int wear_bit;

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

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

  if( ms_find_obj( ch ) )
    return;

  if( xIS_SET( ( ch )->affected_by, AFF_OOZARU ) || xIS_SET( ( ch )->affected_by, AFF_GOLDEN_OOZARU ) )
  {
    ch_printf( ch, "You can't do that while in a beserked Oozaru state.\n\r" );
    return;
  }

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

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

  return;
}



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


  one_argument( argument, arg );

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

  if( ms_find_obj( ch ) )
    return;

  if( xIS_SET( ( ch )->affected_by, AFF_OOZARU ) || xIS_SET( ( ch )->affected_by, AFF_GOLDEN_OOZARU ) )
  {
    ch_printf( ch, "You can't do that while in a beserked Oozaru state.\n\r" );
    return;
  }

  if( ( vobj = get_obj_wear( ch, arg ) ) != NULL )
  {
    if( vobj->pIndexData->vnum == 50101 )
    {
      if( xIS_SET( ch->affected_by, AFF_T4 ) ||
          xIS_SET( ch->affected_by, AFF_T3 ) ||
          xIS_SET( ch->affected_by, AFF_T2 ) ||
          xIS_SET( ch->affected_by, AFF_T1 ) ||
          xIS_SET( ch->affected_by, AFF_OMEGA ) ||
          xIS_SET( ch->affected_by, AFF_VM1 ) ||
          xIS_SET( ch->affected_by, AFF_VM2 ) ||
          xIS_SET( ch->affected_by, AFF_SENT_CHIP ) || xIS_SET( ch->affected_by, AFF_SUPERANDROID ) )
      {
        ch_printf( ch, "&RYou can't remove the Sigma Virus while transformed.\n\r" );
        return;
      }
    }
  }

  if( !str_cmp( arg, "all" ) )  /* SB Remove all */
  {
    for( obj = ch->first_carrying; obj != NULL; obj = obj_next )
    {
      obj_next = obj->next_content;
      if( obj->wear_loc != WEAR_NONE && can_see_obj( ch, obj ) )
        remove_obj( ch, obj->wear_loc, TRUE );
    }
    return;
  }

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

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


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

  one_argument( argument, arg );

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

  if( ms_find_obj( ch ) )
    return;

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

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

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

  switch ( ch->in_room->sector_type )
  {
    case SECT_CITY:
    case SECT_INSIDE:
      send_to_char( "The floor is too hard to dig through.\n\r", ch );
      return;
    case SECT_WATER_SWIM:
    case SECT_WATER_NOSWIM:
    case SECT_UNDERWATER:
    case SECT_SPACE:
      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] == '\0' || !str_cmp( arg, ch->name ) )
  {
    act( AT_ACTION, "$n offers $mself to $s deity, who graciously declines.", ch, NULL, NULL, TO_ROOM );
    send_to_char( "Your deity appreciates your offer and may accept it later.\n\r", ch );
    return;
  }

  if( ms_find_obj( ch ) )
    return;

  obj = get_obj_list_rev( ch, arg, ch->in_room->last_content );
  if( !obj )
  {
    send_to_char( "You can't find it.\n\r", ch );
    return;
  }
  if( IS_OBJ_STAT( obj, ITEM_NOSAC ) )
  {
    act( AT_PLAIN, "$p cannot be destroyed.", ch, obj, 0, TO_CHAR );
    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] != '\0' )
   * {
   * strcpy( name, ch->pcdata->deity->name );
   * }
   * else if ( !IS_NPC( ch ) && IS_GUILDED(ch) && sysdata.guild_overseer[0] != '\0' )
   * {
   * strcpy( name, sysdata.guild_overseer );
   * }
   * else if ( !IS_NPC( ch ) && ch->pcdata->clan && ch->pcdata->clan->deity[0] != '\0' )
   * {
   * strcpy( name, ch->pcdata->clan->deity );
   * }
   * else
   * {
   */
  strcpy( name, "The Supreme Kai" );
  /*
   * }
   */


  if( ch->gold < MAX_ZENI ) //zeni protection
    ch->gold += 1;
  if( obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC )
    adjust_favor( ch, 5, 1 );

  if( ch->gold < MAX_ZENI ) //zeni protection (this one so it wont display get zeni msg)
    sprintf( buf, "%s gives you one zeni for your sacrifice.\n\r", name );
  else
    sprintf( buf, "%s cant give you any more zeni.\n\r", name );  //show this if he sacs and got more than 2.1b zeni.
  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] == '\0' && !ch->fighting )
  {
    send_to_char( "Zap whom or what?\n\r", ch );
    return;
  }

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

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

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

  WAIT_STATE( ch, 1 * PULSE_VIOLENCE );

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

    retcode = obj_cast_spell( wand->value[3], wand->value[0], ch, victim, obj );
    if( retcode == rCHAR_DIED || retcode == rBOTH_DIED )
    {
      bug( "do_zap: char died", 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 )
{
  FILE *fp;
  char filename[256];
  sh_int templvl;
  OBJ_DATA *contents;

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

  sprintf( filename, "%s%d.vault", STORAGE_DIR, ch->in_room->vnum );
  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;
    fprintf( fp, "#VNUM %d\n", ch->in_room->vnum );
//Karn's check. -Karn
    //      if (contents && !IS_OBJ_STAT( contents, ITEM_CLANOBJECT))
//    fwrite_obj(ch, contents, fp, 0, OS_CARRY );
    fprintf( fp, "#END\n" );
    ch->level = templvl;
    fclose( fp );
    return;
  }
  return;
}

/* put an item on auction, or see the stats on the current item or bet */
void do_auction( CHAR_DATA * ch, char *argument )
{
  OBJ_DATA *obj;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  int i;
  long double valueld = 0;
  long double range = 0;

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );
  argument = one_argument( argument, arg3 );

  set_char_color( AT_CYAN, ch );

  if( ch->pcdata->release_date != 0 )
  {
    send_to_char( "You can not use the auction command.\n\r", ch );
    return;
  }

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

  /*
   * if ( ( time_info.hour > 18 || time_info.hour < 9 )
   * && auction->item == NULL
   * && !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] == '\0' )
  {
    if( auction->item != NULL )
    {
      AFFECT_DATA *paf;
      obj = auction->item;

      /*
       * show item data here 
       */
      if( auction->bet > 0 )
        sprintf( buf, "\n\rCurrent bid on this item is %s zeni.\n\r", num_punct( auction->bet ) );
      else
        sprintf( buf, "\n\rNo bids on this item have been received.\n\r" );
      set_char_color( AT_CYAN, ch );
      send_to_char( buf, ch );
      /*
       * spell_identify (0, LEVEL_HERO - 1, ch, auction->item); 
       */

      sprintf( buf,
               "Object '&W%s&C' is %s\n\rSpecial properties: &W%s&C\n\rIts weight is &W%s&C, value is &W%s&C, and powerlevel is &W%s&C.\n\r",
               obj->short_descr, aoran( item_type_name( obj ) ), extra_bit_name( &obj->extra_flags ),
               /*
                * magic_bit_name( obj->magic_flags ), -- currently unused 
                */
               num_punct( obj->weight ), num_punct( obj->cost ), num_punct_ld( obj->level ) );
      set_char_color( AT_LBLUE, ch );
      send_to_char( buf, ch );
      if( obj->item_type != ITEM_LIGHT && obj->wear_flags - 1 > 0 )
        ch_printf( ch, "Item's wear location: &W%s&C\n\r", flag_string( obj->wear_flags - 1, w_flags ) );

      set_char_color( AT_BLUE, ch );

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

        case ITEM_PILL:
        case ITEM_SCROLL:
        case ITEM_POTION:
/*  Removed so that "special" senzu beans can be made -- Melora
 *					sprintf( buf, "Level %d spells of:", obj->value[0] );
 *					send_to_char( buf, ch );
 *
 *					if ( obj->value[1] >= 0 && obj->value[1] < top_sn )
 *					{
 *						send_to_char( " '", ch );
 *						send_to_char( skill_table[obj->value[1]]->name, ch );
 *						send_to_char( "'", ch );
 *					}
 *
 *					if ( obj->value[2] >= 0 && obj->value[2] < top_sn )
 *					{
 *						send_to_char( " '", ch );
 *						send_to_char( skill_table[obj->value[2]]->name, ch );
 *						send_to_char( "'", ch );
 *					}
 *
 *					if ( obj->value[3] >= 0 && obj->value[3] < top_sn )
 *					{
 *						send_to_char( " '", ch );
 *						send_to_char( skill_table[obj->value[3]]->name, ch );
 *						send_to_char( "'", ch );
 *					}
 *
 */
          send_to_char( ".\n\r", ch );
          break;

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

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

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

        case ITEM_MISSILE_WEAPON:
        case ITEM_WEAPON:
          sprintf( buf, "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 ) ? "\n\rThis weapon is poisoned." : "" );
          send_to_char( buf, ch );
          break;

        case ITEM_ARMOR:
          sprintf( buf, "Armor rating is %d/%d.\n\r", obj->value[4], obj->value[5] );
          send_to_char( buf, ch );
          break;

        case ITEM_SCOUTER:
          range = obj->value[2];
          range *= 100;
          sprintf( buf, "Scouter pl range is 1 to %s.\n\r", num_punct_ld( range ) );
          send_to_char( buf, ch );
          break;
        case ITEM_DRAGONBALL:
          sprintf( buf, "This is a real dragonball.\n\r" );
          send_to_char( buf, ch );
          break;
      }

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

      for( paf = obj->first_affect; paf; paf = paf->next )
        showaffect( ch, paf );
      if( ( obj->item_type == ITEM_CONTAINER || obj->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 );
      }

      if( IS_IMMORTAL( ch ) )
      {
        sprintf( buf, "&BSeller: &W%s&B.  Bidder: &W%s&B.  Round: &W%d&B.\n\r",
                 auction->seller->name, auction->buyer->name, ( auction->going + 1 ) );
        send_to_char( buf, ch );
        sprintf( buf, "Time left in round: &W%d&B.\n\r", auction->pulse );
        send_to_char( buf, ch );
      }
      return;
    }
    else
    {
      set_char_color( AT_CYAN, 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_CYAN, ch );
      sprintf( buf, "Sale of &C%s&c has been stopped by an Administrator.", 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, "que" ) )
  {
    if( auction->item != NULL )
      pager_printf_color( ch, "&C%s&c is currently being auctioned.\n\r", auction->item->short_descr );
    else
      pager_printf_color( ch, "&cNothing is currently being auctioned.\n\r" );

    pager_printf( ch, "&cQueued auctions:\n\r" );

    if( auction->freeQueSlot == -1 )
    {
      pager_printf( ch, "&c No items are currently in the auction que.\n\r" );
      return;
    }

    for( i = 0; i < auction->freeQueSlot; i++ )
    {
      if( auction->queued_obj[i] == NULL )
        continue;

      pager_printf( ch, "&c[&W%d&c] &C%s&c starting at &C%s zeni&c.\n\r",
                    ( i + 1 ), auction->queued_obj[i]->short_descr, num_punct( auction->queued_starting_bid[i] ) );
    }

    return;
  }


  if( !str_cmp( arg1, "limit" ) )
  {
    if( arg2[0] == '\0' )
    {
      send_to_char( "What do you want to set your auction level limit to?\n\r", ch );
      return;
    }

    if( !is_number( arg2 ) )
    {
      send_to_char( "You can't set it to that...\n\r", ch );
      return;
    }

    valueld = is_number( arg2 ) ? atof( arg2 ) : -1;
    if( atof( arg2 ) < -1 && valueld == -1 )
      valueld = atof( arg2 );

    if( valueld > ch->exp )
    {
      send_to_char( "You can't set it higher than your base power level.\n\r", ch );
      return;
    }
    ch->pcdata->auction_pl = valueld;
    pager_printf_color( ch, "Auction level limit set to %s.\n\r", num_punct_ld( valueld ) );
    return;
  }

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

      if( ch->exp < 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] == '\0' )
      {
        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 + ( auction->bet * 0.25 ) ) )
      {
        pager_printf_color( ch, "You must at least bid %s zeni over the current bid.\n\r",
                            num_punct( auction->bet * 0.25 ) );
        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 zeni.\n\r", ch );
        return;
      }

      if( newbet <= 0 )
      {
        send_to_char( "You can't bid 0 zeni.\n\r", ch );
        return;
      }
      /*
       * Is it the item they really want to bid on? --Shaddai 
       */
      if( arg3[0] != '\0' && !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 */

      if( ch->pcdata->auction_pl > auction->item->level )
      {
        ch->pcdata->auction_pl = auction->item->level;
        pager_printf_color( ch, "Auction level limit reset to %s.\n\r", num_punct_ld( ch->pcdata->auction_pl ) );
      }
      sprintf( buf, "A bid of &C%s zeni &chas been received on &C%s&c.", 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->carried_by != ch )
  {
    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 
   */
/*
	if (get_trust(ch) != MAX_LEVEL)
	{
		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( IS_OBJ_STAT( obj, ITEM_PROTOTYPE ) && !IS_NPC( ch ) )
  {
    send_to_char( "You can not auction prototype objects.\n\r", ch );
    return;
  }

  if( IS_OBJ_STAT( obj, ITEM_NOAUCTION ) )
  {
    send_to_char( "That item can't be auctioned.  Sorry.\n\r", ch );
    return;
  }
  //prevent from somone to start an auc if he got Over 2.1b zeni.. so his zeni wont reset..(zeni protection code)
  if( ch->gold > MAX_ZENI )
  {
    send_to_char( "You can not start an auction you have to much zeni!\n\r", ch );
    return;
  }

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

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

  if( atoi( arg2 ) < 0 )
  {
    send_to_char( "You can't auction something for less than 0 zeni!\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_SCOUTER:
      case ITEM_DRAGONRADAR:
      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: &C%s &cat &C%s zeni&c.", obj->short_descr,
                 num_punct( auction->starting ) );
        talk_auction( buf );

        return;

    } /* switch */
/*	else if (auction->freeQueSlot <= AUCTION_QUE)
	{
		switch (obj->item_type)
		{

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

			case ITEM_SCOUTER:
			case ITEM_DRAGONRADAR:
			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:

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

				auction->queued_obj[auction->freeQueSlot] = obj;
				auction->queued_char[auction->freeQueSlot] = ch;
				auction->queued_starting_bid[auction->freeQueSlot] = atoi(arg2);
				auction->freeQueSlot++;

				pager_printf_color(ch,"&C%s&c added to the auction que (que slot %d)",
					obj->short_descr, auction->freeQueSlot);

			return;
		}
	}
*/
  else
  {

    act( AT_TELL, "Try again later - &C$p&c is being auctioned right now and the que is full!", 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 );
    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, UMAX( 0, ( dam - ( vch->level * 2 ) ) ), 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] == '\0' )
  {
    send_to_char( "You must specify at least one keyword.\n\r", ch );
    return;
  }

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

  if( obj )
  {
    if( obj->in_obj )
    {
      obj_from_obj( obj );
      obj = obj_to_char( obj, ch );
    }
    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] == '\0' )
          break;

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


      if( match )
        return obj;
      break;

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

    default:
      break;
  }

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

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] != '\0' ) ? obj->action_desc : "roll$q";
}

/*dice chance deal throw*/