swr2.0/
swr2.0/area/
swr2.0/boards/
swr2.0/clans/
swr2.0/doc/
swr2.0/planets/
swr2.0/spacecraft/
#include <stdio.h>
#include <string.h>
#include "mud.h"

/*
 * Local functions.
 */
void get_obj( CHAR_DATA * ch, OBJ_DATA * obj, OBJ_DATA * container );
bool remove_obj( CHAR_DATA * ch, int iWear, bool fReplace );
void wear_obj( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace,
    short wear_bit );
bool job_trigger( CHAR_DATA * victim, CHAR_DATA * ch, OBJ_DATA * obj );
void wear_obj_dispatch_fun( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace,
    int wear_loc );
void write_corpses( const CHAR_DATA * ch, const char *name );

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

  /* magical items are more resistant */
  if( IS_OBJ_STAT( obj, ITEM_MAGIC ) )
    resist += number_fuzzy( 12 );
  /* 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;

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

  return URANGE( 10, resist, 99 );
}

char *obj_short( const OBJ_DATA * obj )
{
  static char buf[MAX_STRING_LENGTH];

  if( obj->count > 1 )
  {
    sprintf( buf, "%s (%d)", obj->short_descr, obj->count );
    return buf;
  }

  return obj->short_descr;
}

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

  if( !CAN_WEAR( obj, ITEM_TAKE ) && !IS_IMMORTAL( ch ) )
  {
    send_to_char( "You can't take that.\r\n", ch );
    return;
  }

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

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

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

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

      while( tobj->in_obj )
      {
	tobj = tobj->in_obj;
	inobj++;

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

      /* need to check weight if not carried by ch or in a magic container. */
      if( !tobj->carried_by || tobj->carried_by != ch || checkweight )
      {
	if( ( ch->carry_weight + weight ) > can_carry_w( ch ) )
	{
	  act( AT_PLAIN, "$d: you can't carry that much weight.", ch,
	      NULL, obj->name, TO_CHAR );
	  return;
	}
      }
    }
    else 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 )
  {
    act( AT_ACTION, IS_OBJ_STAT( container, ITEM_COVERING ) ?
	"You get $p from beneath $P." : "You get $p from $P",
	ch, obj, container, TO_CHAR );
    act( AT_ACTION, IS_OBJ_STAT( container, ITEM_COVERING ) ?
	"$n gets $p from beneath $P." : "$n gets $p from $P",
	ch, obj, container, TO_ROOM );
    obj_from_obj( obj );
  }
  else
  {
    act( AT_ACTION, "You get $p.", ch, obj, container, TO_CHAR );
    act( AT_ACTION, "$n gets $p.", ch, obj, container, TO_ROOM );
    obj_from_room( obj );
  }


  if( obj->item_type == ITEM_MONEY )
  {
    ch->gold += obj->value[0] * obj->count;
    extract_obj( obj );
  }
  else
  {
    obj = obj_to_char( obj, ch );
  }

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

  oprog_get_trigger( ch, obj );
}


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

  argument = one_argument( argument, arg1 );

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

  argument = one_argument( argument, arg2 );
  /* 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?\r\n", 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;
      }
      separate_obj( obj );
      get_obj( ch, obj, NULL );
      if( char_died( ch ) )
	return;
      if( IS_SET( sysdata.save_flags, SV_GET ) )
	save_char_obj( ch );
    }
    else
    {
      short cnt = 0;
      bool fAll = FALSE;
      char *chk = NULL;

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

      /* 'get all' or 'get all.obj' */
      found = FALSE;
      for( obj = ch->in_room->first_content; obj; obj = obj_next )
      {
	obj_next = obj->next_content;
	if( ( fAll || nifty_is_name( chk, obj->name ) )
	    && can_see_obj( ch, obj ) )
	{
	  found = TRUE;
	  if( number && ( cnt + obj->count ) > number )
	    split_obj( obj, number - cnt );
	  cnt += obj->count;
	  get_obj( ch, obj, NULL );
	  if( char_died( ch )
	      || ch->carry_number >= can_carry_n( ch )
	      || ch->carry_weight >= can_carry_w( ch )
	      || ( number && cnt >= number ) )
	  {
	    if( IS_SET( sysdata.save_flags, SV_GET )
		&& !char_died( ch ) )
	      save_char_obj( ch );
	    return;
	  }
	}
      }

      if( !found )
      {
	if( fAll )
	  send_to_char( "I see nothing here.\r\n", ch );
	else
	  act( AT_PLAIN, "I see no $T here.", ch, NULL, chk, TO_CHAR );
      }
      else if( IS_SET( sysdata.save_flags, SV_GET ) )
	save_char_obj( ch );
    }
  }
  else
  {
    /* 'get ... container' */
    if( !str_cmp( arg2, "all" ) || !str_prefix( "all.", arg2 ) )
    {
      send_to_char( "You can't do that.\r\n", 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.\r\n", ch );
	  return;
	}
	if( ch->carry_weight + container->weight > can_carry_w( ch ) )
	{
	  send_to_char( "It's too heavy for you to lift.\r\n", ch );
	  return;
	}
	break;

      case ITEM_CONTAINER:
      case ITEM_DROID_CORPSE:
      case ITEM_CORPSE_PC:
      case ITEM_CORPSE_NPC:
	break;
    }

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

      if( IS_SET( sysdata.save_flags, SV_GET ) )
	save_char_obj( ch );
    }
    else
    {
      int cnt = 0;
      bool fAll = FALSE;
      char *chk = NULL;

      /* 'get all container' or 'get all.obj container' */
      if( IS_OBJ_STAT( container, ITEM_DONATION ) )
      {
	send_to_char( "The gods frown upon such an act of greed!\r\n",
	    ch );
	return;
      }
      if( !str_cmp( arg1, "all" ) )
	fAll = TRUE;
      else
	fAll = FALSE;
      if( number > 1 )
	chk = arg1;
      else
	chk = &arg1[4];
      found = FALSE;
      for( obj = container->first_content; obj; obj = obj_next )
      {
	obj_next = obj->next_content;
	if( ( fAll || nifty_is_name( chk, obj->name ) )
	    && can_see_obj( ch, obj ) )
	{
	  found = TRUE;
	  if( number && ( cnt + obj->count ) > number )
	    split_obj( obj, number - cnt );
	  cnt += obj->count;
	  get_obj( ch, obj, container );
	  if( char_died( ch )
	      || ch->carry_number >= can_carry_n( ch )
	      || ch->carry_weight >= can_carry_w( ch ) || ( number
		&& cnt >=
		number ) )
	  {
	    if( container->item_type == ITEM_CORPSE_PC )
	      write_corpses( NULL, container->short_descr + 14 );
	    if( found && IS_SET( sysdata.save_flags, SV_GET ) )
	      save_char_obj( ch );
	    return;
	  }
	}
      }

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

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

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

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

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

  if( ms_find_obj( ch ) )
    return;

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

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

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

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

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

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

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

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

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

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

    separate_obj( obj );
    separate_obj( container );
    obj_from_char( obj );
    obj = obj_to_obj( obj, container );
    count = obj->count;
    obj->count = 1;
    act( AT_ACTION, IS_OBJ_STAT( container, ITEM_COVERING )
	? "$n hides $p beneath $P." : "$n puts $p in $P.",
	ch, obj, container, TO_ROOM );
    act( AT_ACTION, IS_OBJ_STAT( container, ITEM_COVERING )
	? "You hide $p beneath $P." : "You put $p in $P.",
	ch, obj, container, TO_CHAR );
    obj->count = count;

    if( save_char )
      save_char_obj( ch );
  }
  else
  {
    bool found = FALSE;
    int cnt = 0;
    bool fAll = FALSE;
    char *chk = NULL;

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

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

      if( ( fAll || nifty_is_name( chk, obj->name ) )
	  && can_see_obj( ch, obj )
	  && obj->wear_loc == WEAR_NONE
	  && obj != container
	  && can_drop_obj( ch, obj )
	  && get_obj_weight( obj ) + get_obj_weight( container )
	  <= container->value[0] )
      {
	if( number && ( cnt + obj->count ) > number )
	  split_obj( obj, number - cnt );
	cnt += obj->count;
	obj_from_char( obj );
	act( AT_ACTION, "$n puts $p in $P.", ch, obj, container,
	    TO_ROOM );
	act( AT_ACTION, "You put $p in $P.", ch, obj, container,
	    TO_CHAR );
	obj = obj_to_obj( obj, container );
	found = TRUE;

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

  return;
}


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

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

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

  if( ms_find_obj( ch ) )
    return;

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

    if( !str_cmp( arg, "credits" ) || !str_cmp( arg, "credit" ) )
    {
      if( ch->gold < number )
      {
	send_to_char( "You haven't got that many credits.\r\n", 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 credits.", ch, NULL, NULL, TO_ROOM );
      obj_to_room( create_money( number ), ch->in_room );
      send_to_char( "OK.\r\n", ch );
      if( IS_SET( sysdata.save_flags, SV_DROP ) )
	save_char_obj( ch );
      return;
    }
  }

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

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

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

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

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

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

    if( !str_cmp( arg, "all" ) )
      fAll = TRUE;
    else
      fAll = FALSE;
    if( number > 1 )
      chk = arg;
    else
      chk = &arg[4];
    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( obj->pIndexData->progtypes & DROP_PROG && obj->count > 1 )
	{
	  ++cnt;
	  separate_obj( obj );
	  obj_from_char( obj );
	  if( !obj_next )
	    obj_next = ch->first_carrying;
	}
	else
	{
	  if( number && ( cnt + obj->count ) > number )
	    split_obj( obj, number - cnt );
	  cnt += obj->count;
	  obj_from_char( obj );
	}
	act( AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM );
	act( AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR );
	obj = obj_to_room( obj, ch->in_room );
	oprog_drop_trigger( ch, obj );	/* mudprogs */
	if( char_died( ch ) )
	  return;
	if( number && cnt >= number )
	  break;
      }
    }


    if( !found )
    {
      if( fAll )
	act( AT_PLAIN, "You are not carrying anything.",
	    ch, NULL, NULL, TO_CHAR );
      else
	act( AT_PLAIN, "You are not carrying any $T.",
	    ch, NULL, chk, TO_CHAR );
    }
  }
  if( IS_SET( sysdata.save_flags, SV_DROP ) )
    save_char_obj( ch );	/* duping protector */
  return;
}



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

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

  if( ms_find_obj( ch ) )
    return;

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

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

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

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

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

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

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

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

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

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

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

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

  if( job_trigger( victim, ch, obj ) == FALSE )
    mprog_give_trigger( victim, ch, obj );

  if( IS_SET( sysdata.save_flags, SV_GIVE ) && !char_died( ch ) )
    save_char_obj( ch );
  if( IS_SET( sysdata.save_flags, SV_RECEIVE ) && !char_died( victim ) )
    save_char_obj( victim );
  return;
}

static obj_ret damage_obj_default( OBJ_DATA * obj )
{
  make_scraps( obj );
  return rOBJ_SCRAPPED;
}

static obj_ret damage_obj_armor( OBJ_DATA * obj )
{
  obj_ret objcode = rNONE;
  CHAR_DATA *ch = obj->carried_by;

  if( ch && obj->value[0] >= 1 )
  {
    ch->armor += apply_ac( obj, obj->wear_loc );
  }

  if( --obj->value[0] <= 0 )
  {
    make_scraps( obj );
    objcode = rOBJ_SCRAPPED;
  }
  else if( ch && obj->value[0] >= 1 )
  {
    ch->armor -= apply_ac( obj, obj->wear_loc );
  }

  return objcode;
}

static obj_ret damage_obj_container( OBJ_DATA * obj )
{
  obj_ret objcode = rNONE;

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

  return objcode;
}

static obj_ret damage_obj_weapon( OBJ_DATA * obj )
{
  obj_ret objcode = rNONE;

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

  return objcode;
}

/*
 * 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->carried_by;
  obj_ret objcode = rNONE;

  separate_obj( obj );

  if( ch )
  {
    act( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_CHAR );
  }
  else if( obj->in_room && ( ch = obj->in_room->first_person ) != NULL )
  {
    act( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_ROOM );
    act( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_CHAR );
    ch = NULL;
  }

  oprog_damage_trigger( ch, obj );

  if( obj_extracted( obj ) )
    return global_objcode;

  switch ( obj->item_type )
  {
    default:
      objcode = damage_obj_default( obj );
      break;

    case ITEM_CONTAINER:
      objcode = damage_obj_container( obj );
      break;

    case ITEM_ARMOR:
      objcode = damage_obj_armor( obj );
      break;

    case ITEM_WEAPON:
      objcode = damage_obj_weapon( obj );
      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 == get_eq_char( ch, WEAR_WIELD )
      && ( tmpobj = get_eq_char( ch, WEAR_DUAL_WIELD ) ) != NULL )
    tmpobj->wear_loc = WEAR_WIELD;

  unequip_char( ch, obj );

  act( AT_ACTION, "$n stops using $p.", ch, obj, NULL, TO_ROOM );
  act( AT_ACTION, "You stop using $p.", ch, obj, NULL, TO_CHAR );
  oprog_remove_trigger( ch, obj );
  return TRUE;
}

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

  if( character_skill_level( ch, gsn_dual_wield ) > 0 )
    return TRUE;

  return FALSE;
}

/*
 * See if char can dual wield at this time			-Thoric
 */
bool can_dual( CHAR_DATA * ch )
{
  bool wield = FALSE, nwield = FALSE;

  if( !could_dual( ch ) )
    return FALSE;
  if( get_eq_char( ch, WEAR_WIELD ) )
    wield = TRUE;
  /* Check for missile wield or dual wield */
  if( get_eq_char( ch, WEAR_MISSILE_WIELD )
      || get_eq_char( ch, WEAR_DUAL_WIELD ) )
    nwield = TRUE;
  if( wield && nwield )
  {
    send_to_char
      ( "You are already wielding two weapons... grow some more arms!\n\r",
	ch );
    return FALSE;
  }
  if( ( wield || nwield ) && get_eq_char( ch, WEAR_SHIELD ) )
  {
    send_to_char
      ( "You cannot dual wield, you're already holding a shield!\n\r", ch );
    return FALSE;
  }
  if( ( wield || nwield ) && get_eq_char( ch, WEAR_HOLD ) )
  {
    send_to_char
      ( "You cannot hold another weapon, you're already holding something in that hand!\n\r",
	ch );
    return FALSE;
  }
  return TRUE;
}


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

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

  if( ( bitlayers && !objlayers ) || bitlayers > objlayers )
    return FALSE;

  if( !bitlayers || ( ( bitlayers & ~objlayers ) == bitlayers ) )
    return TRUE;

  return FALSE;
}

static bool wear_obj_verify_layering( CHAR_DATA * ch, OBJ_DATA * obj,
    short loc )
{
  if( !can_layer( ch, obj, WEAR_BODY ) )
  {
    send_to_char
      ( "It won't fit overtop of what you're already wearing.\r\n", ch );
    return FALSE;
  }

  return TRUE;
}

static void generic_wear_obj( CHAR_DATA * ch, OBJ_DATA * obj, short wear_loc,
    const char *msg_toroom, const char *msg_tochar )
{
  if( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
  {
    if( !obj->action_desc || obj->action_desc[0] == '\0' )
    {
      act( AT_ACTION, msg_toroom, ch, obj, NULL, TO_ROOM );
      act( AT_ACTION, msg_tochar, ch, obj, NULL, TO_CHAR );
    }
    else
      actiondesc( ch, obj, NULL );
  }

  equip_char( ch, obj, wear_loc );
  oprog_wear_trigger( ch, obj );
}

static void wear_obj_light( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !remove_obj( ch, WEAR_LIGHT, fReplace ) )
    return;

  generic_wear_obj( ch, obj, WEAR_LIGHT, "$n holds $p as a light.",
      "You hold $p as your light." );
}

static void wear_obj_finger( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  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 ) )
  {
    generic_wear_obj( ch, obj, WEAR_FINGER_L,
	"$n slips $s left finger into $p.",
	"You slip your left finger into $p." );
    return;
  }

  if( !get_eq_char( ch, WEAR_FINGER_R ) )
  {
    generic_wear_obj( ch, obj, WEAR_FINGER_R,
	"$n slips $s right finger into $p.",
	"You slip your right finger into $p." );
    return;
  }

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

static void wear_obj_neck( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  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 ) )
  {
    generic_wear_obj( ch, obj, WEAR_NECK_1,
	"$n wears $p around $s neck.",
	"You wear $p around your neck." );
    return;
  }

  if( !get_eq_char( ch, WEAR_NECK_2 ) )
  {
    generic_wear_obj( ch, obj, WEAR_NECK_2,
	"$n wears $p around $s neck.",
	"You wear $p around your neck." );
    return;
  }

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

static void wear_obj_body( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !wear_obj_verify_layering( ch, obj, WEAR_BODY ) )
    return;

  generic_wear_obj( ch, obj, WEAR_BODY, "$n fits $p on $s body.",
      "You fit $p on your body." );
}

static void wear_obj_head( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !remove_obj( ch, WEAR_HEAD, fReplace ) )
    return;

  generic_wear_obj( ch, obj, WEAR_HEAD, "$n dons $p upon $s head.",
      "You don $p upon your head." );
}

static void wear_obj_eyes( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !remove_obj( ch, WEAR_EYES, fReplace ) )
    return;

  generic_wear_obj( ch, obj, WEAR_EYES,
      "$n places $p on $s eyes.",
      "You place $p on your eyes." );
}

static void wear_obj_ears( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !remove_obj( ch, WEAR_EARS, fReplace ) )
    return;

  generic_wear_obj( ch, obj, WEAR_EARS, "$n wears $p on $s ears.",
      "You wear $p on your ears." );
}

static void wear_obj_legs( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !wear_obj_verify_layering( ch, obj, WEAR_LEGS ) )
    return;

  generic_wear_obj( ch, obj, WEAR_LEGS, "$n slips into $p.",
      "You slip into $p." );
}

static void wear_obj_feet( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !wear_obj_verify_layering( ch, obj, WEAR_FEET ) )
    return;

  generic_wear_obj( ch, obj, WEAR_FEET, "$n wears $p on $s feet.",
      "You wear $p on your feet." );
}

static void wear_obj_hands( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !wear_obj_verify_layering( ch, obj, WEAR_HANDS ) )
    return;

  generic_wear_obj( ch, obj, WEAR_HANDS, "$n wears $p on $s hands.",
      "You wear $p on your hands." );
}

static void wear_obj_arms( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !wear_obj_verify_layering( ch, obj, WEAR_ARMS ) )
    return;

  generic_wear_obj( ch, obj, WEAR_ARMS, "$n wears $p on $s arms.",
      "You wear $p on your arms." );
}

static void wear_obj_about( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !wear_obj_verify_layering( ch, obj, WEAR_ABOUT ) )
    return;

  generic_wear_obj( ch, obj, WEAR_ABOUT, "$n wears $p about $s body.",
      "You wear $p about your body." );
}

static void wear_obj_waist( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !wear_obj_verify_layering( ch, obj, WEAR_WAIST ) )
    return;

  generic_wear_obj( ch, obj, WEAR_WAIST, "$n wears $p about $s waist.",
      "You wear $p about your waist." );
}

static void wear_obj_wrist( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  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 ) )
  {
    generic_wear_obj( ch, obj, WEAR_WRIST_L,
	"$n fits $p around $s left wrist.",
	"You fit $p around your left wrist." );
    return;
  }

  if( !get_eq_char( ch, WEAR_WRIST_R ) )
  {
    generic_wear_obj( ch, obj, WEAR_WRIST_R,
	"$n fits $p around $s right wrist.",
	"You fit $p around your right wrist." );
    return;
  }

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

static void wear_obj_shield( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  if( !remove_obj( ch, WEAR_SHIELD, fReplace ) )
    return;

  generic_wear_obj( ch, obj, WEAR_SHIELD, "$n uses $p as an energy shield.",
      "You use $p as an energy shield." );
}

static void wear_obj_wield( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  OBJ_DATA *tmpobj = NULL;

  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 );
    hd = get_eq_char( ch, WEAR_HOLD );

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

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

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

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

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

      equip_char( ch, obj, WEAR_DUAL_WIELD );
      oprog_wear_trigger( ch, obj );
      return;
    }

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

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

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

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

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

      equip_char( ch, obj, WEAR_WIELD );
      oprog_wear_trigger( ch, obj );
      return;
    }
  }

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

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

  equip_char( ch, obj, WEAR_WIELD );
  oprog_wear_trigger( ch, obj );
}

static void wear_obj_hold( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace )
{
  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_DEVICE
      || obj->item_type == ITEM_FOOD
      || obj->item_type == ITEM_DRINK_CON
      || !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 );
}


/*
 * Wear one object.
 * Optional replacement of existing objects.
 * Big repetitive code, ick.
 * Restructured a bit to allow for specifying body location	-Thoric
 *
 * Refactored by decomposing into smaller functions, and removed lots of
 * duplicate code. -Kai
 */
void wear_obj( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace, short wear_bit )
{
  char buf[MAX_STRING_LENGTH];
  short bit, tmp;

  separate_obj( obj );

  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.\r\n", ch );
	    break;
	  case ITEM_WIELD:
	    send_to_char( "You cannot wield that.\r\n", ch );
	    break;
	  default:
	    sprintf( buf, "You cannot wear that on your %s.\r\n",
		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 )
  {
    wear_obj_light( ch, obj, fReplace );
    return;
  }

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

  wear_obj_dispatch_fun( ch, obj, fReplace, 1 << bit );
}

void wear_obj_dispatch_fun( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace,
    int wear_loc )
{
  switch ( wear_loc )
  {
    default:
      bug( "wear_obj: uknown/unused item_wear bit %d", wear_loc );

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

      break;

    case ITEM_WEAR_FINGER:
      wear_obj_finger( ch, obj, fReplace );
      break;

    case ITEM_WEAR_NECK:
      wear_obj_neck( ch, obj, fReplace );
      break;

    case ITEM_WEAR_BODY:
      wear_obj_body( ch, obj, fReplace );
      break;

    case ITEM_WEAR_HEAD:
      wear_obj_head( ch, obj, fReplace );
      break;

    case ITEM_WEAR_EYES:
      wear_obj_eyes( ch, obj, fReplace );
      break;

    case ITEM_WEAR_EARS:
      wear_obj_ears( ch, obj, fReplace );
      break;

    case ITEM_WEAR_LEGS:
      wear_obj_legs( ch, obj, fReplace );
      break;

    case ITEM_WEAR_FEET:
      wear_obj_feet( ch, obj, fReplace );
      break;

    case ITEM_WEAR_HANDS:
      wear_obj_hands( ch, obj, fReplace );
      break;

    case ITEM_WEAR_ARMS:
      wear_obj_arms( ch, obj, fReplace );
      break;

    case ITEM_WEAR_ABOUT:
      wear_obj_about( ch, obj, fReplace );
      break;

    case ITEM_WEAR_WAIST:
      wear_obj_waist( ch, obj, fReplace );
      break;

    case ITEM_WEAR_WRIST:
      wear_obj_wrist( ch, obj, fReplace );
      break;

    case ITEM_WEAR_SHIELD:
      wear_obj_shield( ch, obj, fReplace );
      break;

    case ITEM_WIELD:
      wear_obj_wield( ch, obj, fReplace );
      break;

    case ITEM_HOLD:
      wear_obj_hold( ch, obj, fReplace );
      break;
  }
}


void do_wear( CHAR_DATA * ch, char *argument )
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  OBJ_DATA *obj = NULL;
  short wear_bit = 0;

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

  if( ms_find_obj( ch ) )
    return;

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

    for( obj = ch->first_carrying; obj; obj = obj_next )
    {
      obj_next = obj->next_content;
      if( obj->wear_loc == WEAR_NONE && can_see_obj( ch, obj ) )
	wear_obj( ch, obj, FALSE, -1 );
    }
    return;
  }
  else
  {
    if( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
    {
      send_to_char( "You do not have that item.\r\n", 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 = NULL, *obj_next = NULL;

  one_argument( argument, arg );

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

  if( ms_find_obj( ch ) )
    return;

  if( !str_cmp( arg, "all" ) )	/* SB Remove all */
  {
    for( obj = ch->first_carrying; obj != 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.\r\n", ch );
    return;
  }
  if( ( obj_next = get_eq_char( ch, obj->wear_loc ) ) != obj )
  {
    act( AT_PLAIN, "You must remove $p first.", ch, obj_next, NULL,
	TO_CHAR );
    return;
  }

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


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

  one_argument( argument, arg );

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

  if( ms_find_obj( ch ) )
    return;

  shovel = get_obj_type_char( ch, ITEM_SHOVEL ) ? TRUE : FALSE;
  obj = get_obj_list_rev( ch, arg, ch->in_room->last_content );

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

  separate_obj( obj );
  if( !CAN_WEAR( obj, ITEM_TAKE ) )
  {
    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.\r\n", ch );
      return;
    case SECT_WATER_SWIM:
    case SECT_WATER_NOSWIM:
    case SECT_UNDERWATER:
      send_to_char( "You cannot bury something here.\r\n", ch );
      return;
    case SECT_AIR:
      send_to_char( "What?  In the air?!\r\n", ch );
      return;
  }

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

  move =
    ( obj->weight * 50 * ( shovel ? 1 : 5 ) ) / UMAX( 1, can_carry_w( ch ) );
  move = URANGE( 2, move, 1000 );
  if( move > ch->move )
  {
    send_to_char
      ( "You don't have the energy to bury something of that size.\r\n",
	ch );
    return;
  }
  ch->move -= move;

  act( AT_ACTION, "You solemnly bury $p...", ch, obj, NULL, TO_CHAR );
  act( AT_ACTION, "$n solemnly buries $p...", ch, obj, NULL, TO_ROOM );
  SET_BIT( obj->extra_flags, ITEM_BURRIED );
  WAIT_STATE( ch, URANGE( 10, move / 2, 100 ) );
  return;
}

/* 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 = NULL;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];

  argument = one_argument( argument, arg1 );

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

  if( !IS_SET( ch->in_room->room_flags, ROOM_AUCTION ) )
  {
    set_char_color( AT_LBLUE, ch );
    send_to_char( "\r\nYou must go to an auction hall to do that!\r\n",
	ch );
    return;
  }

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

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

      /* show item data here */
      if( auction->bet > 0 )
	sprintf( buf, "Current bid on this item is %d credits.\r\n",
	    auction->bet );
      else
	sprintf( buf, "No bids on this item have been received.\r\n" );

      set_char_color( AT_BLUE, ch );
      send_to_char( buf, ch );
      /*          spell_identify (0, LEVEL_HERO - 1, ch, auction->item); */

      sprintf( buf,
	  "Object '%s' is %s, special properties: %s %s.\r\nIts weight is %d, value is %d.\r\n",
	  obj->name,
	  aoran( item_type_name( obj ) ),
	  extra_bit_name( obj->extra_flags ),
	  magic_bit_name( obj->magic_flags ),
	  obj->weight, obj->cost );
      set_char_color( AT_LBLUE, ch );
      send_to_char( buf, ch );

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

      set_char_color( AT_BLUE, ch );

      switch ( obj->item_type )
      {
	case ITEM_ARMOR:
	  ch_printf( ch,
	      "Current armor class is %d. ( based on current condition )\r\n",
	      obj->value[0] );
	  ch_printf( ch,
	      "Maximum armor class is %d. ( based on top condition )\r\n",
	      obj->value[1] );
	  break;
      }

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

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

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

      if( IS_IMMORTAL( ch ) )
      {
	sprintf( buf, "Seller: %s.  Bidder: %s.  Round: %d.\r\n",
	    auction->seller->name, auction->buyer->name,
	    ( auction->going + 1 ) );
	send_to_char( buf, ch );
	sprintf( buf, "Time left in round: %d.\r\n", auction->pulse );
	send_to_char( buf, ch );
      }

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

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

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

      auction->item = NULL;

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

      return;
    }
  }

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

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

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

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

      if( newbet < auction->starting )
      {
	send_to_char
	  ( "You must place a bid that is higher than the starting bet.\r\n",
	    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 + 10000 ) )
      {
	send_to_char
	  ( "You must at least bid 10000 credits over the current bid.\r\n",
	    ch );
	return;
      }

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

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

      /* the actual bet is OK! */

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

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

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

      auction->buyer = ch;
      auction->bet = newbet;
      auction->going = 0;
      auction->pulse = PULSE_AUCTION;	/* start the auction over again */

      sprintf( buf, "A bid of %d credits has been received on %s.\r\n",
	  newbet, auction->item->short_descr );
      talk_auction( buf );
      return;
    }
    else
    {
      send_to_char( "There isn't anything being auctioned right now.\r\n",
	  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.\r\n", ch );
    return;
  }

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

  argument = one_argument( argument, arg2 );

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

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

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

  if( auction->item == NULL )
  {
    switch ( obj->item_type )
    {
      default:
	act( AT_TELL, "You cannot auction $Ts.", ch, NULL,
	    item_type_name( obj ), TO_CHAR );
	return;

	/* insert any more item types here... items with a timer MAY NOT BE 
	   AUCTIONED! 
	   */
      case ITEM_LIGHT:
      case ITEM_RARE_METAL:
      case ITEM_CRYSTAL:
      case ITEM_FABRIC:
      case ITEM_ARMOR:
	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 );

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

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

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



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

void obj_fall( OBJ_DATA * obj, bool through )
{
  EXIT_DATA *pexit = NULL;
  ROOM_INDEX_DATA *to_room = NULL;
  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( IS_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 %ld",
	  to_room->vnum );
      bug( buf, 0 );
      extract_obj( obj );
      return;
    }

    if( obj->in_room->first_person )
    {
      act( AT_PLAIN, "$p falls far below...",
	  obj->in_room->first_person, obj, NULL, TO_ROOM );
      act( AT_PLAIN, "$p falls far below...",
	  obj->in_room->first_person, obj, NULL, TO_CHAR );
    }
    obj_from_room( obj );
    is_falling = TRUE;
    obj = obj_to_room( obj, to_room );
    is_falling = FALSE;

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

    if( !IS_SET( obj->in_room->room_flags, ROOM_NOFLOOR ) && through )
    {
      /*		int dam = (int)9.81*sqrt(fall_count*2/9.81)*obj->weight/2;
      */ int dam = fall_count * obj->weight /
      2;
      /* Damage players */
      if( obj->in_room->first_person && number_percent() > 15 )
      {
	CHAR_DATA *rch = NULL;
	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 );
	damage( vch, vch, dam * vch->top_level, TYPE_UNDEFINED );
      }
      /* Damage objects */
      switch ( obj->item_type )
      {
	case ITEM_WEAPON:
	case ITEM_ARMOR:
	  if( ( obj->value[0] - dam ) <= 0 )
	  {
	    if( obj->in_room->first_person )
	    {
	      act( AT_PLAIN, "$p is destroyed by the fall!",
		  obj->in_room->first_person, obj, NULL, TO_ROOM );
	      act( AT_PLAIN, "$p is destroyed by the fall!",
		  obj->in_room->first_person, obj, NULL, TO_CHAR );
	    }
	    make_scraps( obj );
	  }
	  else
	    obj->value[0] -= dam;
	  break;
	default:
	  if( ( dam * 15 ) > get_obj_resistance( obj ) )
	  {
	    if( obj->in_room->first_person )
	    {
	      act( AT_PLAIN, "$p is destroyed by the fall!",
		  obj->in_room->first_person, obj, NULL, TO_ROOM );
	      act( AT_PLAIN, "$p is destroyed by the fall!",
		  obj->in_room->first_person, obj, NULL, TO_CHAR );
	    }
	    make_scraps( obj );
	  }
	  break;
      }
    }
    obj_fall( obj, TRUE );
  }
  return;
}

bool job_trigger( CHAR_DATA * victim, CHAR_DATA * ch, OBJ_DATA * obj )
{
  char buf[MAX_STRING_LENGTH];

  if( !IS_NPC( victim ) || !victim->pIndexData )
    return FALSE;

  if( victim->pIndexData->vnum != MOB_VNUM_JOB_OFFICER )
    return FALSE;

  if( IS_NPC( ch ) || !ch->pcdata )
    return FALSE;

  if( !obj->pIndexData || obj->pIndexData->vnum != OBJ_VNUM_PACKAGE )
    return FALSE;

  if( !victim->in_room || !victim->in_room->area
      || !victim->in_room->area->planet )
    return FALSE;

  sprintf( buf, "package %s", victim->in_room->area->planet->name );

  if( str_cmp( buf, obj->name ) )
    return FALSE;

  snprintf( buf, MAX_STRING_LENGTH, "%s", "Thank you." );
  do_say( victim, buf );
  ch->gold += 1000;

  act( AT_GOLD, "$N gives you 1000 credits.", ch, NULL, victim, TO_CHAR );
  act( AT_GOLD, "$N gives $n some credits.", ch, NULL, victim, TO_NOTVICT );
  act( AT_GOLD, "You give $n some credits.", ch, NULL, victim, TO_VICT );

  separate_obj( obj );
  obj_from_char( obj );
  extract_obj( obj );

  return TRUE;
}