FlCodebase3.1/
FlCodebase3.1/bounty/
FlCodebase3.1/challenge/
FlCodebase3.1/clans/
FlCodebase3.1/gods/
FlCodebase3.1/mobprogs/
FlCodebase3.1/player/
FlCodebase3.1/savemud/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  * 
 *                                                                         *
 *      ROM 2.4 is copyright 1993-1998 Russ Taylor                         *
 *      ROM has been brought to you by the ROM consortium                  *
 *          Russ Taylor (rtaylor@hypercube.org)                            *
 *          Gabrielle Taylor (gtaylor@hypercube.org)                       *
 *          Brian Moore (zump@rom.org)                                     *
 *      By using this code, you have agreed to follow the terms of the     *
 *      ROM license, in the file Rom24/doc/rom.license                     *
 *                                                                         *
 * Code Adapted and Improved by Abandoned Realms Mud                       *
 * and Aabahran: The Forsaken Lands Mud by Virigoth                        *
 *                                                                         *
 * Continued Production of this code is available at www.flcodebase.com    *
 ***************************************************************************/

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "merc.h"
#include "magic.h"
#include "interp.h"
#include "cabal.h"
#include "recycle.h"
#include "jail.h"

#define CD CHAR_DATA
CD *	find_keeper	args( (CHAR_DATA *ch ) );
CD *	find_history	args( (CHAR_DATA *ch ) );
#undef CD
#define OD OBJ_DATA
OD *    get_obj_keeper  args( (CHAR_DATA *ch,CHAR_DATA *keeper,char *argument));
#undef OD

void unadorn_obj (OBJ_DATA* socket, OBJ_DATA* obj, CHAR_DATA *ch);
extern char *target_name;
bool empty_obj(OBJ_DATA* obj)
{
  //check inv.
  if (obj->contains)
    {
      OBJ_DATA *t_obj, *next_obj;
      for (t_obj = obj->contains; t_obj != NULL; t_obj = next_obj)
        {
	  next_obj = t_obj->next_content;
	  obj_from_obj(t_obj);
	  if (obj->in_obj)
	    obj_to_obj(t_obj,obj->in_obj);
	  else if (obj->carried_by)
	    obj_to_char(t_obj,obj->carried_by);
	  else if (obj->in_room == NULL)
	    extract_obj(t_obj);
	  else
	    obj_to_room(t_obj,obj->in_room);
        }
      return TRUE;
    }
  return FALSE;
}

bool empty_char(CHAR_DATA* ch){
  OBJ_DATA* obj, *obj_next;
  if (!ch->carrying)
    return FALSE;

    for ( obj = ch->carrying; obj != NULL; obj = obj_next )
    {
	obj_next = obj->next_content;
	REMOVE_BIT(obj->extra_flags,ITEM_INVENTORY);
        obj_from_char( obj );
	obj_to_room( obj, ch->in_room );
    }
    return TRUE;
}

void get_obj( CHAR_DATA *ch, OBJ_DATA *obj, OBJ_DATA *container )
{
    CHAR_DATA *gch, *victim;
    OBJ_DATA* vobj, *vobj_next;
    int members;
    bool split = TRUE;
    char buffer[100];

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

    if ( ch->carry_number + get_obj_number( obj ) > can_carry_n( ch ) )
      {
        act( "$d: you can't carry that many items.",ch, NULL, obj->name, TO_CHAR );
	return;
      }
    if ((!obj->in_obj || obj->in_obj->carried_by != ch) 
	&& (get_carry_weight(ch) + get_obj_weight_char(ch, obj) >= can_carry_w(ch)))
      {
        act( "$d: you can't carry that much weight.",ch, NULL, obj->name, TO_CHAR );
	return;
      }
    if (is_affected_obj(obj, gsn_gravitate))
      {
	act( "$p seems to have the weight of a mountain!",ch, obj, NULL, TO_CHAR );
	return;
      }
/* trap check */
    if (trip_traps(ch, obj->traps))
      return;
    if ( container != NULL ) {
      if (trip_traps(ch, container->traps))
	return;
      if ( (container->item_type == ITEM_WEAPON 
	    || container->item_type == ITEM_ARMOR)
	   && IS_OBJ_STAT(container, ITEM_SOCKETABLE) ) {
	if (IS_OBJ_STAT(obj, ITEM_NOREMOVE) && !IS_IMMORTAL(ch)){
	  act("$p won't even budge!", ch, obj, NULL, TO_CHAR);
	  return;
	}
	obj_from_obj( obj );
	unadorn_obj(obj, container, ch);
	REMOVE_BIT(container->value[4],WEAPON_JEWELED); 
	
	/* Put it before the detach phrase, mainly for syntax reasons.*/
	act( "You detach $p from $P.", ch, obj, container, TO_CHAR);
	if (!IS_AFFECTED(ch,AFF_SNEAK) ) {
          act( "$n detaches $p from $P.", ch, obj, container,TO_ROOM);
	}
      }    
      else {
	if (container->pIndexData->vnum == OBJ_VNUM_PIT
	    && !CAN_WEAR(container, ITEM_TAKE) 
	    && !IS_OBJ_STAT(obj,ITEM_HAD_TIMER) 
	    && !IS_OBJ_STAT(container, ITEM_SOCKETABLE)) {
	  obj->timer = 0;
	}
        else{ 
	  act( "You get $p from $P.", ch, obj, container, TO_CHAR );
	  if (!IS_AFFECTED(ch,AFF_SNEAK) )
	    act( "$n gets $p from $P.", ch, obj, container, TO_ROOM );
	}
	REMOVE_BIT(obj->extra_flags,ITEM_HAD_TIMER);
	obj_from_obj( obj );
      }
    }
    else
      {
	act( "You get $p.", ch, obj, container, TO_CHAR );
	if (!IS_AFFECTED(ch,AFF_SNEAK))
	  act( "$n gets $p.", ch, obj, container, TO_ROOM );
	obj_from_room( obj );
      }
    if ( obj->item_type == ITEM_MONEY)
    {
    	if (ch->class == class_lookup("monk") && (ch->gold + obj->value[0]) > 20000)
    	{
	    int overflow = UMAX(1,ch->gold + obj->value[0] - 20000);
	    ch->gold = 20000;
	    obj->value[0] = overflow;
    	    send_to_char("You can't hold that much gold and drop it.\n\r",ch);
	    act( "$n drops some gold.", ch, NULL, NULL, TO_ROOM );
	    obj_to_room( obj,ch->in_room);
	    split = FALSE;
	}
        else if (ch->class == class_lookup("druid") && (ch->gold + obj->value[0]) > 20000)
        {
            int overflow = UMAX(1,ch->gold + obj->value[0] - 20000);
            ch->gold = 20000;
            obj->value[0] = overflow;
            send_to_char("You can't hold that much gold and drop it.\n\r",ch);
            act( "$n drops some gold.", ch, NULL, NULL, TO_ROOM );
            obj_to_room( obj,ch->in_room);
            split = FALSE;
        }
	else 
	  ch->gold += obj->value[0];
        if (IS_SET(ch->act,PLR_AUTOSPLIT) && split)
        {
            members = 0;
            for (gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room )
                if (!IS_AFFECTED(gch,AFF_CHARM) && is_same_group( gch, ch ) )
                    members++;
            if ( members > 1 && obj->value[0] > 1 )
            {
                sprintf(buffer,"%d",obj->value[0]);
                do_split(ch,buffer); 
            }
        }
	if (split)
	  extract_obj( obj );
    }
    else{
      obj_to_char( obj, ch );
    }
    if (!obj)
      return;
    /* OLD MPROG */
    for ( victim = ch->in_room->people; victim != NULL; victim=victim->next_in_room ){
      if (!IS_NPC(victim))
	continue; 
      if (victim->pIndexData->progtypes & GET_PROG)
	mprog_get_trigger( victim, ch, obj );
      if ( HAS_TRIGGER_MOB( victim, TRIG_GET ) )
	p_give_trigger( victim, NULL, NULL, ch, obj, TRIG_GET );
    }
    
    /* NEW PROG */
    for (vobj = ch->in_room->contents; vobj; vobj = vobj_next){
      vobj_next = vobj->next_content;
      if (vobj == obj)
	continue;
      if ( HAS_TRIGGER_OBJ( vobj, TRIG_GET ) )
	p_give_trigger( NULL, vobj, NULL, ch, obj, TRIG_GET );
    }
    if ( HAS_TRIGGER_OBJ( obj, TRIG_GET ) )
      p_give_trigger( NULL, obj, NULL, ch, container ? container : obj, TRIG_GET );
    if ( HAS_TRIGGER_ROOM( ch->in_room, TRIG_GET ) )
      p_give_trigger( NULL, NULL, ch->in_room, ch, obj, TRIG_GET );
}

void do_get( CHAR_DATA *ch, char *argument )
{
    char arg1[MIL], arg2[MIL];
    OBJ_DATA *obj, *obj_next, *container;
    bool found;
    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    if (!str_cmp(arg2,"from"))
	argument = one_argument(argument,arg2);
    if (IS_NPC(ch) && ch->pIndexData->vnum == MOB_VNUM_VAPOR)
	return;
    if ( arg1[0] == '\0' )
    {
	send_to_char( "Get what?\n\r", ch );
	return;
    }

/* This is a BUG check. Basically, it will only allow you to socket
   items and detach items IN your inventory, to prefent people from
   getting infintine affects from sockets.
*/


//Wolf form check
    if (is_affected(ch, gsn_wolf_form) 
	|| is_affected(ch, gsn_bat_form) 
	|| is_affected(ch,gsn_mist_form)
	|| is_affected(ch,gsn_weretiger)	
	|| is_affected(ch,gsn_werewolf)	
	|| is_affected(ch,gsn_werebear)	
	|| is_affected(ch,gsn_werefalcon)){
      send_to_char("You have no where to put that item your current state.\n\r", ch);
      return;
    }


    if ( arg2[0] == '\0' )
    {
	if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
	{
	    obj = get_obj_list( ch, arg1, ch->in_room->contents );
	    if ( obj == NULL )
	    {
		sendf(ch, "I see no %s here.\n\r", arg1);
		return;
	    }
	    get_obj( ch, obj, NULL );
	}
	else
	{
	    found = FALSE;
	    for ( obj = ch->in_room->contents; obj != NULL; obj = obj_next )
	    {
	      obj_next = obj->next_content;
	      //safety check due to traps/oprogs etc.
	      if (obj->in_room == NULL || obj->in_room != ch->in_room)
		continue;
		if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) ) && can_see_obj( ch, obj ) )
		{
		    found = TRUE;
                    if (!IS_IMMORTAL(ch) && (obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC))
                        continue;
		    if (!CAN_WEAR(obj, ITEM_TAKE))
			continue;
		    get_obj( ch, obj, NULL );
		}
	    }
	    if ( !found ) 
	    {
		if ( arg1[3] == '\0' )
		    send_to_char( "I see nothing here.\n\r", ch );
		else
		    sendf(ch, "I see no %s here.\n\r", &arg1[4]);
	    }
	}
    }
    else
    {
	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, NULL, arg2 ) ) == NULL )
	{
	    sendf(ch, "I see no %s here.\n\r", arg2);
	    return;
	}
	switch ( container->item_type )	{
	default:
	    send_to_char( "That's not a container.\n\r", ch );
	    return;
	case ITEM_CONTAINER:
        case ITEM_ARMOR:
        case ITEM_WEAPON:
	case ITEM_CORPSE_NPC:
	    break;
	case ITEM_CORPSE_PC:
	    if (ch->id != container->owner)
	    {
	      if (container->level < 15 && !IS_IMMORTAL(ch) )
	    	{
	    	    send_to_char("You can't loot from that corpse.\n\r",ch);
		    return;
	    	}

		if (ch->level < 15)
		{
		    send_to_char("You can't loot corpses yet.\n\r",ch);
		    return;
		}

		/* Vulture check, for first 2 ticks only following can loot the corpse: *
		 * Thiefs, Those in PK of victim, Those in group of victim, IMMS	*/
		/* Get original owner of the corpse */
		if (!can_loot(ch, container)){
		    act("$g's power shields $p from your greedy fingers.", ch, container, NULL, TO_CHAR);
		    return;
		}
		set_delay(ch, NULL);
		/* LOOT CRIME CHECK */
		if (ch->in_room && ch->id != container->owner && is_crime(ch->in_room, CRIME_LOOT, NULL)){
		  set_crime(ch, NULL, ch->in_room->area, CRIME_LOOT);
		}
	    }
	    break;
        }
	if (IS_SET(container->value[1], CONT_CLOSED)
	    && container->item_type != ITEM_WEAPON 
	    && container->item_type != ITEM_ARMOR){
	    act( "The $d is closed.", ch, NULL, container->name, TO_CHAR );
	    return;
	}

	if (IS_OBJ_STAT(container, ITEM_SOCKETABLE) && 
	    ((obj = get_obj_carry( ch, arg2, ch)) == NULL )) {
	  send_to_char( "You can only detach sockets from items in your inventory.\n\r" ,ch);
	  return;
	}

	if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
	{
	    obj = get_obj_list( ch, arg1, container->contains );
	    if ( obj == NULL )
	    {
		sendf(ch, "I see nothing like that in the %s.\n\r", arg2);
		return;
	    }
	    if (IS_SET(obj->wear_flags, ITEM_HAS_OWNER)
		&& !is_owner(obj, ch)
		&& !IS_IMMORTAL(ch) )
	      act("You cannot touch $p safely.", ch, obj, NULL, TO_CHAR);
	    else
	      get_obj( ch, obj, container );
	}
	else
	{
	    found = FALSE;
            if (container->pIndexData->vnum == OBJ_VNUM_PIT && !IS_IMMORTAL(ch))
	    {
		send_to_char("Don't be so greedy!\n\r",ch);
		return;
            }
	    for ( obj = container->contains; obj != NULL; obj = obj_next )
	    {
		obj_next = obj->next_content;
		//safety check due to traps/oprogs etc.
		if (obj->in_obj == NULL || obj->in_obj != container)
		  continue;
		if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) ) && can_see_obj( ch, obj ))
		{
		    found = TRUE;
		    if (IS_SET(obj->wear_flags, ITEM_HAS_OWNER)
			&& !is_owner(obj, ch)
			&& !IS_IMMORTAL(ch) )
		      act("You cannot touch $p safely.", ch, obj, NULL, TO_CHAR);
		    else
		      get_obj( ch, obj, container );

		    /* check for traps */
		    if (ch == NULL)
		      break;
		}
	    }
	    if ( !found )
	    {
		if ( arg1[3] == '\0' )
                    sendf(ch, "I see nothing in the %s.\n\r", arg2);
		else
                    sendf(ch, "I see nothing like that in the %s.\n\r", arg2);
	    }
	}
    }
}

/***** Removes strings from socketed weapons - Crypt ****/
void unadorn_obj (OBJ_DATA* socket, OBJ_DATA* obj, CHAR_DATA *ch) {
  AFFECT_DATA *paf = NULL, *paf_list = NULL, *paf_tmp = NULL, *paf_next = NULL;
  char item_buf[MIL];
  char * loc;

/* test for right item */
  if (socket->item_type != ITEM_SOCKET){
    bug("unadorn_obj: socket passed was not ITEM_SOCKET.",
	socket->pIndexData->vnum);
    return;
  }
   
  if (!IS_OBJ_STAT(obj, ITEM_SOCKETABLE)){
    bug("unadorn_obj: obj passed was not socketable.", 
	obj->pIndexData->vnum);
    return;
  }

/* replace descriptions and names (the hard way) */ 

  /* short descr */
  sprintf(item_buf, "%s", obj->short_descr);
  loc = strstr (item_buf, " adorned with");
  if (loc)
    *(loc) = '\0';
  free_string (obj->short_descr);
  obj->short_descr = str_dup (item_buf); 

  /* long descr */
  sprintf(item_buf, "%s is lying here.", obj->short_descr);
  free_string( obj->description );
  obj->description = str_dup(item_buf);

  /* name */
  sprintf(item_buf, "%s", obj->name);
  loc = strstr (item_buf, socket->name);
  if (loc)
    *(loc) = '\0';
  free_string (obj->name);
  obj->name = str_dup(item_buf);


/* replace descriptions and names (easy way)
    free_string (obj->short_descr);
    obj->short_descr = str_dup( obj->pIndexData->short_descr ); 
    free_string (obj->description); 
    obj->description = str_dup( obj->pIndexData->description ); 
    free_string (obj->name); 
    obj->name = str_dup( obj->pIndexData->name ); 
*/

/* first remove affects that are adding things to the object */
    for (paf = obj->affected; paf != NULL; paf = paf_next) {
      paf_next = paf->next;
      if (paf->type == skill_lookup("socketed object")
	  && (paf->where == TO_OBJECT || paf->where == TO_WEAPON) )
	affect_remove_obj(obj, paf);
    }

/* goal: remove gem added affects from the object */
  for (paf = obj->affected; paf != NULL; paf = paf_next) {
    paf_next = paf->next;
    if (paf->type != skill_lookup("socketed object")) {
      paf_tmp = paf_list;
      if (paf_tmp == NULL) {
	paf_list = paf;
	paf->next = NULL;
	continue;
      }
      while (paf_tmp->next != NULL) {
	paf_tmp = paf_tmp->next;
      }
      paf_tmp->next = paf;
      paf->next = NULL;
      continue;
    }
    free_affect(paf);
  }
  obj->affected = paf_list;
  paf_list = NULL;

}

/***** Adds strings to socketed weapons - Crypt ****/
void adorn_obj (OBJ_DATA* socket, OBJ_DATA* obj, CHAR_DATA *ch)
{
    AFFECT_DATA *paf;
    AFFECT_DATA *af_new;
    char name[MIL], item_buf[MIL], socket_buf[MIL];
    /* test for right item */
    if (socket->item_type != ITEM_SOCKET){
      bug("adorn_obj: socket passed was not ITEM_SOCKET.",
          socket->pIndexData->vnum);
      return;
    }
    if (!IS_OBJ_STAT(obj, ITEM_SOCKETABLE)){
      bug("adorn_obj: obj passed was not socketable.", 
	  obj->pIndexData->vnum);
      return;
    }
/* change name only for non-holy weapons 
    if (obj->pIndexData->vnum != OBJ_VNUM_HOLY_WEAPON
	&& obj->pIndexData->vnum != OBJ_VNUM_HOLY_ARMOR
	&& obj->pIndexData->vnum != OBJ_VNUM_MAL_WEAPON){
*/
    if (obj->item_type == ITEM_WEAPON){
      sprintf(item_buf, "%s", obj->short_descr);
    }
    else{
      sprintf(item_buf, "%s", obj->short_descr);
    }
    sprintf(socket_buf, "%s", socket->short_descr); 
      
    /* replace short desc */ 
    free_string( obj->short_descr );
    sprintf(name, "%s adorned with %s", item_buf, socket_buf);
    obj->short_descr = str_dup(name);
      
    /* replace long desc */
    free_string( obj->description );
    sprintf(name, "%s adorned with %c%s", item_buf + 2, 
	    tolower (socket->description[0]), socket->description + 1);
    obj->description = str_dup(name);
      
    /* Add both object names to one object. */
      
    sprintf (name, "%s %s", obj->name, socket->name); 
    obj->name = str_dup(name); 

/* GOAL: swap gem affects onto the weapon */
/* if the obj had previous enchants, copy them over so we dont lose */
    if (!obj->enchanted) {
      AFFECT_DATA *af_new;
      obj->enchanted = TRUE;
      for (paf = obj->pIndexData->affected; paf != NULL; paf = paf->next) {
	af_new = new_affect();
	af_new->next = obj->affected;
	obj->affected = af_new;
	af_new->duration = paf->duration;
	af_new->level = paf->level;
	af_new->where = paf->where;
	af_new->bitvector = paf->bitvector;
	af_new->location = paf->location;
	af_new->modifier = paf->modifier;
	af_new->has_string = paf->has_string;
	af_new->string = paf->string;
	if ( obj->item_type == ITEM_WEAPON ){
	  af_new->type = UMAX(skill_lookup("enchant weapon"),paf->type);
	}
	else{
	  af_new->type = UMAX(skill_lookup("enchant armor"),paf->type);
	}
      }
    }
    
/* loop over the affects on the gem to object*/
    for ( paf = socket->pIndexData->affected; paf != NULL; paf = paf->next ) {
      
/* - for each affect, apply the same affect to the weapon */
      af_new = new_affect();
      af_new->next = obj->affected;
      obj->affected = af_new;
      
      af_new->type = skill_lookup ("socketed object");
      af_new->level = paf->level;
      af_new->duration = -1;
      
      af_new->location = paf->location;	
      af_new->modifier = paf->modifier;
      af_new->where = paf->where;
      af_new->bitvector = paf->bitvector;
/*  	sendf( ch, "Adding affect: %s by %d, level %d.\n\r", (af_new->where == TO_SKILL ?  */
/*  		skill_table[af_new->location].name : affect_loc_name(af_new->location )),  */
/*  		af_new->modifier, af_new->level ); */
      
/* dont forget to set the obj enchanted! */
      obj->enchanted = TRUE;
    }
/* move over the extra and weapon flags if any on the socket */
    {
      int flag = 0;
      AFFECT_DATA af;

      af.type = skill_lookup ("socketed object");
      af.level = socket->level;
      af.duration = -1;
      af.where = TO_OBJECT;
      af.location = 0;
      af.modifier = 0;

      if (socket->value[1]){
	for (flag = 0; extra_flags[flag].name != NULL; flag++){
	  int bit = extra_flags[flag].bit;
	  /* we check if the particular bit is set on the socket 
	   * and NOT set on the object we are socketing
	   */
	  if (IS_SET(socket->value[1], bit) && !IS_SET(obj->extra_flags, bit)){
	    af.bitvector = bit;
	    affect_to_obj(obj, &af);
	  }
	}
      }
/* do same for weapon flags */
      if (socket->value[4] && obj->item_type == ITEM_WEAPON){
	af.where = TO_WEAPON;
	for (flag = 0; weapon_type2[flag].name != NULL; flag++){
	  int bit = weapon_type2[flag].bit;
	  /* we check if the particular bit is set on the socket 
	   * and NOT set on the object we are socketing
	   */
	  if (IS_SET(socket->value[4], bit) && !IS_SET(obj->value[4], bit)){
	    af.bitvector = bit;
	    affect_to_obj(obj, &af);
	  }
	}
      }
    }
}

void do_put( CHAR_DATA *ch, char *argument )
{
    char arg1[MIL], arg2[MIL];
    OBJ_DATA *container, *obj_next, *things ;
    OBJ_DATA *obj = NULL, *vobj, *vobj_next;
    CHAR_DATA* victim;
    int things_in_container = 0;
    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    if (!str_cmp(arg2,"in") || !str_cmp(arg2,"on"))
	argument = one_argument(argument,arg2);
//Form check
    if (is_affected(ch, gsn_wolf_form) 
	|| is_affected(ch, gsn_bat_form) 
	|| is_affected(ch, gsn_mist_form)
	|| is_affected(ch,gsn_weretiger)	
	|| is_affected(ch,gsn_werewolf)	
	|| is_affected(ch,gsn_werebear)	
	|| is_affected(ch,gsn_werefalcon)){
      send_to_char("Huh?\n\r", ch);
      return;
    }
    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "Put what in what?\n\r", 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, NULL, arg2 ) ) == NULL )
    {
	sendf(ch, "I see no %s here.\n\r", arg2);
	return;
    }
    /* trap check */
    if (trip_traps(ch, container->traps))
      return;
/* START THE SOCKET PART - Crypt */
    if (( container->item_type == ITEM_WEAPON ) 
	|| (container->item_type == ITEM_ARMOR)){
      if ( IS_OBJ_STAT(container, ITEM_SOCKETABLE)) {
	if ( ( obj = get_obj_carry( ch, arg1, ch ) ) == NULL )
	{
	    send_to_char( "You do not have that item.\n\r", ch );
	    return;
	}
        if (obj->item_type != ITEM_SOCKET)
        {
            send_to_char("That is not a socketable item.\n\r", ch);
	    return;
	}
        if ( IS_WEAPON_STAT(container,WEAPON_JEWELED) )
        {
            send_to_char("There is already something in the socket.\n\r",ch);
	    return;
	}
	if ( ( container = get_obj_carry( ch, arg2, ch ) ) == NULL ) {
	  send_to_char( "You can only socket items in your inventory.\n\r", ch);
	  return;
	} 
	if ( (IS_LIMITED(obj) || obj->pIndexData->pCabal)
	     && !IS_LIMITED(container) 
	     && !container->pIndexData->pCabal){
	  act("$p seems to be far too intricate to fit properly.", ch, obj, NULL, TO_CHAR);
	  return;
	}
	if (!IS_SOC_STAT(obj, SOCKET_ARMOR)
	    && container->item_type == ITEM_ARMOR){
	  act("$p cannot be affixed to armors.", ch, obj, NULL, TO_CHAR);
	  return;
	}
	if (!IS_SOC_STAT(obj, SOCKET_WEAPON)
	    && IS_SOC_STAT(obj, SOCKET_ARMOR)
	    && container->item_type == ITEM_WEAPON){
	  act("$p cannot be affixed to weapons.", ch, obj, NULL, TO_CHAR);
	  return;
	}
        obj_from_char( obj );
        obj_to_obj( obj, container );
	act( "You affix $p to $P.", ch, obj, container, TO_CHAR );
	if (!IS_AFFECTED(ch,AFF_SNEAK)) {
	  act( "$n affixes $p to $P.", ch, obj, container, TO_ROOM );
	}
        adorn_obj(obj, container, ch); 
        SET_BIT(container->value[4],WEAPON_JEWELED); 
	return;
      }
    } 

/* END SOCKET PART - Crypt */

    if ( container->item_type != ITEM_CONTAINER )
    {
	send_to_char( "That's not a container.\n\r", ch );
	return;
    }
    if ( IS_SET(container->value[1], CONT_CLOSED) )
    {
	act( "The $d is closed.", ch, NULL, container->name, TO_CHAR );
	return;
    }
    if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
    {
	if ( ( obj = get_obj_carry( ch, arg1, ch ) ) == 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 (WEIGHT_MULT(obj) != 100)
    	{
            send_to_char("You have a feeling that would be a bad idea.\n\r",ch);
            return;
        }
	if (is_affected_obj( obj, gen_malform) || is_affected_obj( obj, gen_hwep)){
	  send_to_char("You can not put such a powerful item in a container.\n\r",ch);
	  return;
	}
	if ( (IS_OBJ_STAT(obj, ITEM_HOLDS_RARE) || IS_LIMITED(obj))
	     && !IS_OBJ_STAT(container,ITEM_HOLDS_RARE)){
	  send_to_char("You can not put such a powerful item in a container.\n\r",ch);
	  return;
	}
	if (IS_SET(obj->wear_flags, ITEM_HAS_OWNER)){
	  send_to_char("You can not put such a powerful item in a container.\n\r",ch);
	  return;
	}
	/* changed for now: Viri
	if (IS_OBJ_STAT(obj,ITEM_MELT_DROP))
	{
	    send_to_char("That item is too worthless to put in a container.\n\r",ch);
	    return;
	}
	*/
	for ( things = container->contains; things != NULL; 
	      things = things->next_content ) {
	  things_in_container++;
	}

        if (get_obj_weight(container) > (container->value[0] * 10)){
	  send_to_char("Its too heavy to be put in there.\n\r", ch);
	  return;
	}
        if ( things_in_container >= container->value[3]){
	    send_to_char( "It won't fit.\n\r", ch );
	    return;
	}
	if (IS_OBJ_STAT (container, ITEM_HOLDS_RARE)) {
	  if (obj->item_type != ITEM_WEAPON) {
	    send_to_char ( "That item is not a weapon.\n\r", ch);
	    return;
	  }
	}
	if (container->pIndexData->vnum == OBJ_VNUM_PIT && !CAN_WEAR(container,ITEM_TAKE))
        {
	    if (obj->timer)
		SET_BIT(obj->extra_flags,ITEM_HAD_TIMER);
	    else
	        obj->timer = number_range(100,200);
        }
	obj_from_char( obj );
	obj_to_obj( obj, container );
	if (IS_SET(container->value[1],CONT_PUT_ON))
	{
    	    act("You put $p on $P.",ch,obj,container, TO_CHAR);
	    if (!IS_AFFECTED(ch,AFF_SNEAK) )
            	act("$n puts $p on $P.",ch,obj,container, TO_ROOM);
	}
	else
	{
	    act( "You put $p in $P.", ch, obj, container, TO_CHAR );
	    if (!IS_AFFECTED(ch,AFF_SNEAK) )
	    	act( "$n puts $p in $P.", ch, obj, container, TO_ROOM );
	}
	/* NEW PROG */
	for ( victim = ch->in_room->people; victim; victim = victim->next_in_room ){
	  if (!IS_NPC(victim))
	    continue; 
	  if ( HAS_TRIGGER_MOB( victim, TRIG_PUT ) )
	    p_give_trigger( victim, NULL, NULL, ch, obj, TRIG_PUT );
	}

	for (vobj = ch->in_room->contents; vobj; vobj = vobj_next){
	  vobj_next = vobj->next_content;
	  if (vobj == obj)
	    continue;
	  if ( HAS_TRIGGER_OBJ( vobj, TRIG_PUT ) )
	    p_give_trigger( NULL, vobj, NULL, ch, obj, TRIG_PUT );
	}
	if ( HAS_TRIGGER_OBJ( obj, TRIG_PUT ) )
	  p_give_trigger( NULL, obj, NULL, ch, container ? container : obj, TRIG_PUT );
	if ( HAS_TRIGGER_ROOM( ch->in_room, TRIG_PUT ) )
	  p_give_trigger( NULL, NULL, ch->in_room, ch, obj, TRIG_PUT );
    }
/* group put */
    else{
      int count = 0;
      for ( things = container->contains; things != NULL; 
	    things = things->next_content ) {
	count++;
      }
      for ( obj = ch->carrying; obj != NULL; obj = obj_next ){
	obj_next = obj->next_content;
	if ( ( arg1[3] == '\0' 
	       || is_name( &arg1[4], obj->name ) ) 
	     && can_see_obj( ch, obj ) 
	     && WEIGHT_MULT(obj) == 100
	     && !IS_LIMITED(obj) 
	     /* Changed for now: Viri
		&& !IS_OBJ_STAT(obj,ITEM_MELT_DROP) 
	     */
	     && obj->wear_loc == WEAR_NONE
	     && obj != container 
	     && can_drop_obj( ch, obj ) 
	     && get_obj_weight( container ) < (container->value[0] * 10)
	     && str_cmp(obj->material,"warflesh")){
	    
	  if (container->pIndexData->vnum == OBJ_VNUM_PIT && !CAN_WEAR(obj, ITEM_TAKE) ){
	    if (obj->timer)
	      SET_BIT(obj->extra_flags,ITEM_HAD_TIMER);
	    else
	      obj->timer = number_range(100,200);
	  }
	  if (++count >= container->value[3])
	    break;
	  obj_from_char( obj );
	  obj_to_obj( obj, container );
	  if (IS_SET(container->value[1],CONT_PUT_ON))
	    {
	      act("You put $p on $P.",ch,obj,container, TO_CHAR);
	      if (!IS_AFFECTED(ch,AFF_SNEAK) )
		act("$n puts $p on $P.",ch,obj,container, TO_ROOM);
	    }
	  else
	    {
	      act( "You put $p in $P.", ch, obj, container, TO_CHAR );
	      if (!IS_AFFECTED(ch,AFF_SNEAK) )
		act( "$n puts $p in $P.", ch, obj, container, TO_ROOM );
	    }
	  /* NEW PROG */
	  for ( victim = ch->in_room->people; victim; victim = victim->next_in_room ){
	    if (!IS_NPC(victim))
	      continue; 
	    if ( HAS_TRIGGER_MOB( victim, TRIG_PUT ) )
	      p_give_trigger( victim, NULL, NULL, ch, obj, TRIG_PUT );
	  }
	  
	  for (vobj = ch->in_room->contents; vobj; vobj = vobj_next){
	    vobj_next = vobj->next_content;
	    if (vobj == obj)
	      continue;
	    if ( HAS_TRIGGER_OBJ( vobj, TRIG_PUT ) )
	      p_give_trigger( NULL, vobj, NULL, ch, obj, TRIG_PUT );
	  }
	  if ( HAS_TRIGGER_OBJ( obj, TRIG_PUT ) )
	    p_give_trigger( NULL, obj, NULL, ch, obj, TRIG_PUT );
	  if ( HAS_TRIGGER_ROOM( ch->in_room, TRIG_PUT ) )
	    p_give_trigger( NULL, NULL, ch->in_room, ch, obj, TRIG_PUT );
	}
      }
    }
}

OBJ_DATA* get_proj(OBJ_DATA* omit, OBJ_DATA* list, int vnum, char* name, int spec){
  OBJ_DATA*  obj, *vobj;
  
  if (list == NULL)
    return NULL;

  for (obj = list; obj != NULL; obj = obj->next_content){
    if (omit && obj == omit)
      continue;
    if (obj->item_type == ITEM_PROJECTILE){
    /* if name is specified then it takes priority */
      if (!IS_NULLSTR(name) && !is_auto_name(name, obj->name) && !is_name(name, obj->name))
	continue;
      if (IS_SET(spec, obj->value[0])
	  || (vnum > 0 && obj->pIndexData->vnum == vnum))
	return obj;
    }
    if (obj->contains && (vobj = get_proj(omit, obj->contains, vnum, name, spec)) != NULL)
      return vobj;
  }
  return NULL;
}


/* returns a first projectile in char's inventory */
OBJ_DATA* get_projectile(CHAR_DATA* ch, OBJ_DATA* container){
  int vnum = 0;
  char* name = "";

  /* specific reload */
  if (container->contains){
    vnum = container->contains->pIndexData->vnum;
    name = container->contains->name;
  }
  else if (container->value[3])
    vnum = container->value[3];

  /* search for first specific or matching ammo type */
  return get_proj(container, ch->carrying, vnum, name, container->value[0]);
}


/* unloads a ranged item putting items into a charac. inventory */
void unload (CHAR_DATA* ch, OBJ_DATA* container){
  OBJ_DATA* obj, *obj_next;

  for (obj = container->contains; obj != NULL; obj = obj_next){
    obj_next = obj->next_content;
    obj_from_obj( obj );
    obj_to_ch( obj, ch );
  }
  act("You unload $p.", ch, container, NULL, TO_CHAR);
  if (!IS_AFFECTED(ch,AFF_SNEAK) 
      && !IS_AFFECTED(ch, AFF_HIDE)
      && !IS_AFFECTED2(ch, AFF_CAMOUFLAGE))
    act( "$n unloads $p.", ch, container, NULL, TO_ROOM );
}


void do_drop( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    OBJ_DATA *obj, *obj_next;
    CHAR_DATA *victim;
    OBJ_DATA* vobj, *vobj_next;
    bool found;
    argument = one_argument( argument, arg );
//Form check
    if (is_affected(ch, gsn_wolf_form) 
	|| is_affected(ch, gsn_bat_form) 
	|| is_affected(ch, gsn_mist_form)
	|| is_affected(ch,gsn_weretiger)	
	|| is_affected(ch,gsn_werewolf)	
	|| is_affected(ch,gsn_werebear)	
	|| is_affected(ch,gsn_werefalcon)){
      send_to_char("Huh?\n\r", ch);
      return;
    }
    if ( arg[0] == '\0' )
    {
	send_to_char( "Drop what?\n\r", ch );
	return;
    }
    if ( is_number( arg ) )
    {
        int amount;
	amount   = atoi(arg);
	argument = one_argument( argument, arg );
        if ( amount <= 0 || ( str_cmp( arg, "coins" ) && str_cmp( arg, "coin" ) && str_cmp( arg, "gold"  ) ) )
	{
	    send_to_char( "Sorry, you can't do that.\n\r", ch );
	    return;
	}
        if (ch->gold < amount)
        {
            send_to_char("You don't have that much gold.\n\r",ch);
            return;
        }
        ch->gold -= amount;
	for ( obj = ch->in_room->contents; obj != NULL; obj = obj_next )
	{
	    obj_next = obj->next_content;
	    switch ( obj->pIndexData->vnum )
	    {
            case OBJ_VNUM_GOLD_ONE:
                amount += 1;
                extract_obj( obj );
		break;
            case OBJ_VNUM_GOLD_SOME:
                amount += obj->value[0];
                extract_obj( obj );
		break;
	    }
	}
        obj_to_room( create_money( amount ), ch->in_room );
	if (!IS_AFFECTED(ch,AFF_SNEAK))
            act( "$n drops some gold.", ch, NULL, NULL, TO_ROOM );
	send_to_char( "OK.\n\r", ch );
	return;
    }
    if ( str_cmp( arg, "all" ) && str_prefix( "all.", arg ) )
    {
	if ( ( obj = get_obj_carry( ch, arg, ch ) ) == 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;
	}
	obj_from_char( obj );
	obj_to_room( obj, ch->in_room );
	if (!IS_AFFECTED(ch,AFF_SNEAK))
	    act( "$n drops $p.", ch, obj, NULL, TO_ROOM );
	act( "You drop $p.", ch, obj, NULL, TO_CHAR );

	/* OLD MOBPROG */
	for ( victim = ch->in_room->people; victim != NULL; victim=victim->next_in_room ){
	  if (!IS_NPC(victim))
	    continue;
	  if (victim->pIndexData->progtypes & DROP_PROG)
	    mprog_drop_trigger( victim, ch, obj );
	  if ( HAS_TRIGGER_MOB( victim, TRIG_DROP ) )
	    p_give_trigger( victim, NULL, NULL, ch, obj, TRIG_DROP );
	}

	/* PROGS */
	for (vobj = ch->in_room->contents; vobj; vobj = vobj_next){
	  vobj_next = vobj->next_content;
	  if (vobj == obj)
	    continue;
	  if ( HAS_TRIGGER_OBJ( vobj, TRIG_DROP ) )
	    p_give_trigger( NULL, vobj, NULL, ch, obj, TRIG_DROP );
	}
        if ( HAS_TRIGGER_OBJ( obj, TRIG_DROP ) )
	  p_give_trigger( NULL, obj, NULL, ch, obj, TRIG_DROP );
        if ( HAS_TRIGGER_ROOM( ch->in_room, TRIG_DROP ) )
	  p_give_trigger( NULL, NULL, ch->in_room, ch, obj, TRIG_DROP );

	if ((!str_cmp(obj->material,"glass")) 
	    || (!str_cmp(obj->material,"crystal")))
	{
	  act("$p shatters into a million pieces!", ch, obj, NULL,TO_ALL);
	  extract_obj(obj);
	  obj = create_object( get_obj_index(OBJ_VNUM_GLASS), 50);
	  obj->timer = 3;
	  obj_to_room(obj, ch->in_room); 
	}

	if (IS_OBJ_STAT(obj,ITEM_MELT_DROP))
	{
	    act("$p dissolves into smoke.",ch,obj,NULL,TO_ALL);
            extract_obj(obj);
	}
    }
    else
    {
	found = FALSE;
	for ( obj = ch->carrying; obj != NULL; obj = obj_next )
	{
	    obj_next = obj->next_content;
	    if ( ( arg[3] == '\0' || is_name( &arg[4], obj->name ) )
            && can_see_obj( ch, obj ) && obj->wear_loc == WEAR_NONE && can_drop_obj( ch, obj ) )
	    {
		found = TRUE;
		obj_from_char( obj );
		obj_to_room( obj, ch->in_room );
		act( "$n drops $p.", ch, obj, NULL, TO_ROOM );
		act( "You drop $p.", ch, obj, NULL, TO_CHAR );
	        for ( victim = ch->in_room->people; victim != NULL; victim=victim->next_in_room )
		    if (IS_NPC(victim) && victim->pIndexData->progtypes & DROP_PROG)
		        mprog_drop_trigger( victim, ch, obj );
         	if ((!str_cmp(obj->material,"glass")) || (!str_cmp(obj->material,"crystal")))
        	{
            	    act("$p shatters into a million pieces!",ch,obj,NULL,TO_ALL);
            	    extract_obj(obj);
		    obj = create_object( get_obj_index(OBJ_VNUM_GLASS), obj->level);
		    obj->timer = 3; 
		    obj_to_room(obj,ch->in_room); 
        	}   
	       	if (IS_OBJ_STAT(obj,ITEM_MELT_DROP))
        	{
            	    act("$p dissolves into smoke.",ch,obj,NULL,TO_ALL);
                    extract_obj(obj);
        	}
	    }
	}
	if ( !found )
	{
	    if ( arg[3] == '\0' )
                act( "You are not carrying anything.",ch, NULL, arg, TO_CHAR );
	    else
                sendf(ch, "You are not carrying any %s.\n\r", &arg[4]);
	}
    }
}

void do_give( CHAR_DATA *ch, char *argument )
{
    char arg1 [MIL], arg2 [MIL], buf[MSL];
    CHAR_DATA *victim;
    OBJ_DATA  *obj;
    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "Give what to whom?\n\r", ch );
	return;
    }
    if ( is_number( arg1 ) )
    {
	int amount;
	amount   = atoi(arg1);
        if ( amount <= 0 || ( str_cmp( arg2, "coins" ) && str_cmp( arg2, "coin" ) && str_cmp( arg2, "gold"  ) ) )
	{
	    send_to_char( "Sorry, you can't do that.\n\r", ch );
	    return;
	}
	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, NULL, arg2 ) ) == NULL )
	{
	    send_to_char( "They aren't here.\n\r", ch );
	    return;
	}

        if ( ch->gold < amount )
	{
            send_to_char( "You haven't got that much gold.\n\r", ch );
	    return;
	}
	if (victim->class == class_lookup("monk") && (victim->gold + amount) > 20000)
	{
	    act("$N can't hold that much gold.",ch,NULL,victim,TO_CHAR);
	    return;
    	}
        ch->gold     -= amount;
	victim->gold += amount;
        sprintf(buf,"$n gives you %d gold.",amount);
	act( buf, ch, NULL, victim, TO_VICT    );
        act( "$n gives $N some gold.",  ch, NULL, victim, TO_NOTVICT );
        sprintf(buf,"You give $N %d gold.",amount);
        act( buf, ch, NULL, victim, TO_CHAR    );

	/* mirrors and decoys cant recive gold */
	if (IS_NPC(victim) && victim->pIndexData->vnum == MOB_VNUM_DUMMY)
	  {
	    act("The coins spill out of $n's hands.",victim, NULL, NULL, TO_ROOM);
	    send_to_char("You cannot recive gold.\n\r", victim);
	    obj_to_room(create_money(amount),victim->in_room); 
	    victim->gold -= amount;
	  }

        if (IS_NPC(victim)){
	  if (victim->pIndexData->progtypes & BRIBE_PROG)
	    mprog_bribe_trigger( victim, ch, amount );
	  if (HAS_TRIGGER_MOB(victim, TRIG_BRIBE))
	    p_bribe_trigger( victim, ch,  amount );
	}
        return;
    }
    if ( ( obj = get_obj_carry( ch, arg1, ch ) ) == 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, NULL, arg2 ) ) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

// change back
    if (IS_NPC(victim) && victim->pIndexData->pShop != NULL && obj->pIndexData->vnum != 775)
    {
	sendf(ch,"%s tells you '`2Sorry, you'll have to sell that.``'\n\r",PERS(victim,ch));
	ch->reply = victim;
	return;
    }
    if ( !can_drop_obj( ch, obj ) )
    {
	send_to_char( "You can't let go of it.\n\r", ch );
	return;
    }
    if ( victim->carry_number + get_obj_number( obj ) > can_carry_n( victim ) )
    {
	act( "$N has $S hands full.", ch, NULL, victim, TO_CHAR );
	return;
    }
    if (get_carry_weight(victim) + get_obj_weight_char(ch, obj) > can_carry_w( victim ) )
    {
	sendf(ch, "%s can't carry that much weight.\n\r", PERS(victim,ch));
	return;
    }
    if ( !can_see_obj( victim, obj ) )
    {
	sendf(ch, "%s can't see it.\n\r", PERS(victim,ch));
	return;
    }

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

    if (obj->pIndexData->vnum == OBJ_VNUM_GOLD_SOME && !IS_NPC(victim)){
      victim->gold += obj->value[0];
      extract_obj(obj);
      return;
    }

    /* PROGS */
    if ( HAS_TRIGGER_OBJ( obj, TRIG_GIVE ) )
      p_give_trigger( NULL, obj, NULL, ch, obj, TRIG_GIVE );
    if ( HAS_TRIGGER_ROOM( ch->in_room, TRIG_GIVE ) )
      p_give_trigger( NULL, NULL, ch->in_room, ch, obj, TRIG_GIVE );

    /* OLD/NEW MOBPROG */
    if (IS_NPC(victim)){
      if (HAS_TRIGGER_MOB(victim, TRIG_GIVE))
	p_give_trigger( victim, NULL, NULL, ch, obj, TRIG_GIVE);
      if (victim->pIndexData->progtypes & GIVE_PROG)
        mprog_give_trigger( victim, ch, obj );
    }
}

void do_preserve( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    OBJ_DATA *obj;
    argument = one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
        send_to_char( "What did you want to preserve?\n\r", ch );
        return;
    }
    if ((ch->class == class_lookup("thief")) || (ch->class == class_lookup("ninja")))   
    {   
      if ( str_cmp( arg, "all" ) && str_prefix( "all.", arg ) )
    	{
	  if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
	    {
	      send_to_char( "You do not have that item.\n\r", ch );
	      return;
	    }
	  if (obj->item_type != ITEM_HERB)
	    {
	      send_to_char( "You can't preserve that.\n\r",ch);
	      return;
	    }
	  if (!IS_AFFECTED(ch,AFF_SNEAK))
	    act( "$n wraps $p to preserve it.", ch, obj, NULL, TO_ROOM );
	  act( "You wrap $p carefully, preserving it.", ch, obj, NULL, TO_CHAR );
	  obj->timer = -1;
/* The have to have SOME lag. */
	  WAIT_STATE2(ch, PULSE_VIOLENCE * 2); 
    	}
    }
    else
      {
	send_to_char( "You have no idea how to preserve things.\n\r",ch);
	return;
      }
}

void do_fill( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    OBJ_DATA *obj, *fountain;
    bool found = FALSE;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Fill what?\n\r", ch );
	return;
    }
    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
    {
	send_to_char( "You do not have that item.\n\r", ch );
	return;
    }
    for ( fountain = ch->in_room->contents; fountain != NULL; fountain = fountain->next_content )
	if ( fountain->item_type == ITEM_FOUNTAIN )
	{
	    found = TRUE;
	    break;
	}
    if ( !found )
    {
	send_to_char( "There is no fountain here!\n\r", ch );
	return;
    }
    if ( obj->item_type != ITEM_DRINK_CON )
    {
	send_to_char( "You can't fill that.\n\r", ch );
	return;
    }
    if ( obj->value[1] != 0 && obj->value[2] != fountain->value[2] )
    {
	send_to_char( "There is already another liquid in it.\n\r", ch );
	return;
    }
    if ( obj->value[1] >= obj->value[0] )
    {
	send_to_char( "Your container is full.\n\r", ch );
	return;
    }
    sprintf(buf,"You fill $p with %s from $P.",liq_table[fountain->value[2]].liq_name);
    act( buf, ch, obj,fountain, TO_CHAR );
    sprintf(buf,"$n fills $p with %s from $P.",liq_table[fountain->value[2]].liq_name);
    act(buf,ch,obj,fountain,TO_ROOM);
    obj->value[2] = fountain->value[2];
    obj->value[1] = obj->value[0];
    obj->value[3] = fountain->value[3];
}

void do_pour (CHAR_DATA *ch, char *argument)
{
    char arg[MSL], buf[MSL];
    OBJ_DATA *out, *in;
    CHAR_DATA *vch = NULL;
    int amount;
    argument = one_argument(argument,arg);
    if (arg[0] == '\0' || argument[0] == '\0')
    {
	send_to_char("Pour what into what?\n\r",ch);
	return;
    }
    if ((out = get_obj_carry(ch,arg, ch)) == NULL)
    {
	send_to_char("You don't have that item.\n\r",ch);
	return;
    }
    if (out->item_type != ITEM_DRINK_CON)
    {
	send_to_char("That's not a drink container.\n\r",ch);
	return;
    }
    if (out->value[1] < 0){
      send_to_char("You cannot do that with this item.\n\r",ch);
      return;
    }
    if (!str_cmp(argument,"out"))
    {
	if (out->value[1] == 0)
	{
	    send_to_char("It's already empty.\n\r",ch);
	    return;
	}
	out->value[1] = 0;
	out->value[3] = 0;
        sprintf(buf,"You invert $p, spilling %s all over the ground.",liq_table[out->value[2]].liq_name);
	act(buf,ch,out,NULL,TO_CHAR);
        sprintf(buf,"$n inverts $p, spilling %s all over the ground.",liq_table[out->value[2]].liq_name);
	act(buf,ch,out,NULL,TO_ROOM);
	return;
    }
    if ((in = get_obj_here(ch, NULL, argument)) == NULL)
    {
	vch = get_char_room(ch, NULL, argument);
	if (vch == NULL)
	{
	    send_to_char("Pour into what?\n\r",ch);
	    return;
	}
	in = get_eq_char(vch,WEAR_HOLD);
	if (in == NULL)
	{
	    send_to_char("They aren't holding anything.",ch);
 	    return;
	}
    }
    if (in->item_type != ITEM_DRINK_CON)
    {
	send_to_char("You can only pour into other drink containers.\n\r",ch);
	return;
    }
    if (in == out)
    {
	send_to_char("You cannot change the laws of physics!\n\r",ch);
	return;
    }
    if (in->value[1] > 0 && in->value[2] != out->value[2])
    {
	send_to_char("They don't hold the same liquid.\n\r",ch);
	return;
    }
    if (out->value[1] == 0)
    {
	act("There's nothing in $p to pour.",ch,out,NULL,TO_CHAR);
	return;
    }
    if (in->value[1] >= in->value[0])
    {
	act("$p is already filled to the top.",ch,in,NULL,TO_CHAR);
	return;
    }
    amount = UMIN(out->value[1],in->value[0] - in->value[1]);
    in->value[1] += amount;
    out->value[1] -= amount;
    in->value[2] = out->value[2];
    if (vch == NULL)
    {
        sprintf(buf,"You pour %s from $p into $P.",liq_table[out->value[2]].liq_name);
    	act(buf,ch,out,in,TO_CHAR);
        sprintf(buf,"$n pours %s from $p into $P.",liq_table[out->value[2]].liq_name);
    	act(buf,ch,out,in,TO_ROOM);
    }
    else
    {
        sprintf(buf,"You pour some %s for $N.",liq_table[out->value[2]].liq_name);
        act(buf,ch,NULL,vch,TO_CHAR);
        sprintf(buf,"$n pours you some %s.",liq_table[out->value[2]].liq_name);
	act(buf,ch,NULL,vch,TO_VICT);
        sprintf(buf,"$n pours some %s for $N.",liq_table[out->value[2]].liq_name);
        act(buf,ch,NULL,vch,TO_NOTVICT);
    }
}

void do_drink( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    OBJ_DATA *obj;
    int amount, liquid;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	for ( obj = ch->in_room->contents; obj; obj = obj->next_content )
	    if ( obj->item_type == ITEM_FOUNTAIN )
		break;
	if ( obj == NULL )
	{
	    send_to_char( "Drink what?\n\r", ch );
	    return;
	}
    }
    else
	if ( ( obj = get_obj_here( ch, NULL, arg ) ) == NULL )
	{
	    send_to_char( "You can't find it.\n\r", ch );
	    return;
	}

    if ( !IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK] > 50 )
      {
	send_to_char( "You fail to reach your mouth.  *Hic*\n\r", ch );
	return;
      }
    if (is_affected(ch,gsn_fasting))
    {
	send_to_char("You are fasting! You don't feel like drinking.\n\r",ch);
	return;
    }
    if (is_affected(ch, gsn_gag)){
      send_to_char("The gag stops you from drinking.\n\r", ch);
      return;
    }
    switch ( obj->item_type )
    {
    default:
	send_to_char( "You can't drink from that.\n\r", ch );
	return;
    case ITEM_FOUNTAIN:
        if ( ( liquid = obj->value[2] )  < 0 )
        {
            bug( "Do_drink: bad liquid number %d.", liquid );
            liquid = obj->value[2] = 0;
        }
	amount = liq_table[liquid].liq_affect[4] * 3;
	break;
    case ITEM_DRINK_CON:
	if ( obj->value[1] <= 0 && obj->value[1] != -1 )
	{
	    send_to_char( "It is already empty.\n\r", ch );
	    return;
	}
	if ( ( liquid = obj->value[2] )  < 0)
	{
	    bug( "Do_drink: bad liquid number %d.", liquid );
	    liquid = obj->value[2] = 0;
	}
        amount = liq_table[liquid].liq_affect[4];
	if (obj->value[1] != -1)
	  amount = UMIN(amount, obj->value[1]);
	break;
    }
    WAIT_STATE2(ch, PULSE_VIOLENCE / 3);
    act( "$n drinks $T from $p.",ch, obj, liq_table[liquid].liq_name, TO_ROOM );
    act( "You drink $T from $p.",ch, obj, liq_table[liquid].liq_name, TO_CHAR );
    if (trip_traps(ch, obj->traps))
      return;
    if (IS_UNDEAD(ch) && !is_affected(ch, gen_unlife)){
      if ( !str_cmp(liq_table[liquid].liq_name,"holy water"))
	{
	  send_to_char("The water burns in your mouth!\n\r",ch);
	  damage( ch, ch, ch->level, gsn_curse, DAM_HOLY ,TRUE);
	  spell_curse(gsn_curse, ch->level, ch, (void *) ch, TARGET_CHAR);
	}
      else if ( !str_cmp(liq_table[liquid].liq_name,"blood") && ch->race == race_lookup("vampire")){
	send_to_char("Aaaah, the sweet taste of blood.\n\r",ch);
	gain_condition( ch, COND_HUNGER, 5 );
	if ( !IS_NPC(ch) && ch->pcdata->condition[COND_HUNGER] > 40 )
	  send_to_char( "You are full.\n\r", ch );
      }
      else{
	send_to_char("It's tastless.\n\r", ch);
	return;
      }
    }
    else
    {
    gain_condition( ch, COND_DRUNK,amount * liq_table[liquid].liq_affect[COND_DRUNK] / 36 );
    gain_condition( ch, COND_THIRST,amount * liq_table[liquid].liq_affect[COND_THIRST] / 10 );
    if (!is_affected(ch,skill_lookup("dysentery")))
    	gain_condition(ch, COND_HUNGER,amount * liq_table[liquid].liq_affect[COND_HUNGER] / 2 );
    if (!is_affected(ch,skill_lookup("nausea")))
        gain_condition(ch, COND_HUNGER,amount * liq_table[liquid].liq_affect[COND_HUNGER] / 2 );
    if ( !IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK]  > 10 )
	send_to_char( "You feel drunk.\n\r", ch );
    if ( !IS_NPC(ch) && ch->pcdata->condition[COND_HUNGER] > 40 )
	send_to_char( "You are full.\n\r", ch );
    if ( !IS_NPC(ch) && ch->pcdata->condition[COND_THIRST] > 40 )
	send_to_char( "Your thirst is quenched.\n\r", ch );
    if ( !str_cmp(liq_table[liquid].liq_name,"holy water"))
    {
	if (ch->alignment == 750)
	{
	    send_to_char("The sweetness of the water uplifts your spirits.\n\r",ch);
	    spell_bless(skill_lookup("bless"), ch->level/2, ch, (void *) ch, TARGET_CHAR);
	    send_to_char("You feel a little better!\n\r",ch);
	    ch->hit = UMIN( ch->hit + ch->level/10, ch->max_hit ); 
	}
	if (ch->alignment == -750)
	{
	    send_to_char("The water burns in your mouth!\n\r",ch);
	    damage( ch, ch, ch->level/2, gsn_curse, DAM_HOLY ,TRUE);
	    spell_curse(gsn_curse, ch->level, ch, (void *) ch, TARGET_CHAR);
	}
    }
    if ( obj->value[3] != 0 )
    {
	AFFECT_DATA af;
	act( "$n chokes and gags.", ch, NULL, NULL, TO_ROOM );
	send_to_char( "You choke and gag.\n\r", ch );
	af.where     = TO_AFFECTS;
	af.type      = gsn_poison;
        af.level     = number_fuzzy(amount); 
	af.duration  = UMAX(3, obj->level / 4);
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_POISON;
	if (!is_affected(ch, af.type)){
	  AFFECT_DATA* paf = affect_to_char( ch, &af );
	  if (!IS_NPC(ch))
	    string_to_affect( paf, ch->name );
	}
    }
    }
    if (obj->value[0] > 0 && obj->value[0] != -1){
      obj->value[1] = UMAX(obj->value[1] - amount, 0);
    }
	
}

void do_eat( CHAR_DATA *ch, char *argument )
{
  CHAR_DATA* vch = NULL;
  char arg[MIL];
  OBJ_DATA *obj;
  int flevel = 0;
  one_argument( argument, arg );
  if ( arg[0] == '\0' )
    {
      send_to_char( "Eat what?\n\r", ch );
      return;
    }
  if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
    {
      send_to_char( "You do not have that item.\n\r", ch );
      return;
    }
  
  if ( !IS_IMMORTAL(ch) )
    {
      if ( obj->item_type != ITEM_FOOD && obj->item_type != ITEM_PILL )
	{
	  send_to_char( "That's not edible.\n\r", ch );
	  return;
	}
      if (is_affected(ch,gsn_fasting))
	{
	  send_to_char("You are fasting! You don't feel like eating.\n\r",ch);
	  return;
	}
      if (!IS_NPC(ch) && ch->pcdata->condition[COND_HUNGER] > 40 && ch->class != class_lookup("vampire"))
        {
	  send_to_char("You are too full to eat more.\n\r",ch);
	  return;
        }
      if (IS_NPC(ch) && ch->pIndexData->vnum == MOB_VNUM_PHOENIX 
	  && ch->practice > 20)
	return;
      if (is_affected(ch, gsn_gag)){
	send_to_char("The gag stops you from eating.\n\r", ch);
	return;
      }
      if (is_affected(ch,skill_lookup("dysentery")))
	{
	  send_to_char("I don't think you should be eating while you have dysentery.\n\r",ch);
	  ch->position = POS_SITTING;
	  update_pos(ch);
	  act("You crouch on the ground as $p is ejected from your rear.",ch,obj,NULL,TO_CHAR);
	  act("$n crouchs on the ground wincing with agonizing pain.",ch,NULL,NULL,TO_ROOM);
	  if (obj->item_type == ITEM_FOOD)
	    damage(ch,ch,obj->value[1],skill_lookup("dysentery"),DAM_OTHER,TRUE);
	  defecate(ch);
	  extract_obj( obj );
	  return;
	}
    }
  WAIT_STATE2(ch, PULSE_VIOLENCE / 3);
  if (trip_traps(ch, obj->traps))
    return;
  act( "$n eats $p.",  ch, obj, NULL, TO_ROOM );
  act( "You eat $p.", ch, obj, NULL, TO_CHAR );
  switch ( obj->item_type )
    {
    case ITEM_FOOD:
      if (IS_UNDEAD(ch) && !is_affected(ch, gen_unlife)){
	send_to_char("It's tasteless.\n\r", ch);
	break;
      }

      if ( !IS_NPC(ch) )
	{
	  int condition;
	  int base = obj->value[1];
	  condition = ch->pcdata->condition[COND_HUNGER];
	  
	  /* adjust for size */
	  base = 2 * base / UMAX(1, ch->size );

	  if (IS_PERK(ch, PERK_UNDERWEIGHT))
	    base = 4 * base / 3;

	  /* Illithids prefer brains */
	  if (ch->race == race_lookup("illithid")){
	    if (obj->pIndexData->vnum == OBJ_VNUM_BRAINS
		|| !str_prefix("brain", obj->material)){
	      send_to_char("Mmm, brains...\n\r", ch);
	      gain_condition( ch, COND_HUNGER, 3 * base);
	    }
	    else{
	      act("You feed on $p with disgust.", ch, obj, NULL, TO_CHAR);
	      gain_condition( ch, COND_HUNGER, base / 4);
	    }
	  }
	  else{
	    for (vch = ch->in_room->people; vch; vch = vch->next_in_room){
	      if (!IS_NPC(vch) && is_same_group(vch, ch)
		  && is_affected(vch, gsn_preserve)){
		break;
	      }
	    }//END character loop
	  }
	  /* preservation effect */
	  if (vch){
	    if (vch == ch)
	      act("Your skills of preservation pay off as you marvel at the taste.", ch, obj, vch, TO_CHAR);
	    else
	      act("$N's skills of preservation pay off as you marvel at the taste.", ch, obj, vch, TO_CHAR);
	    gain_condition( ch, COND_HUNGER, 3 * base);
	  }
	  else
	    gain_condition( ch, COND_HUNGER, base);

	  if ( condition <= 0 && ch->pcdata->condition[COND_HUNGER] > 0 )
	    send_to_char( "You are no longer hungry.\n\r", ch );
	  else if ( ch->pcdata->condition[COND_HUNGER] > 40 )
	    send_to_char( "You are full.\n\r", ch );
	}
      else if (ch->pIndexData->vnum == MOB_VNUM_PHOENIX)
	{
	  ch->practice += obj->value[1];
	  ch->train    += obj->value[1];
    	}
      if ( obj->value[3] != 0 
	   && (obj->pIndexData->vnum != OBJ_VNUM_BRAINS
	       || ch->race != race_lookup("illithid")) )
	{
	  AFFECT_DATA af;
	  act( "$n chokes and gags.", ch, NULL, NULL, TO_ROOM );
	  act( "You choke and gag.", ch, NULL, NULL, TO_CHAR );
	  af.where     = TO_AFFECTS;
	  af.type      = gsn_poison;
	  af.level     = number_fuzzy(obj->value[0]);
	  af.duration  = UMIN(3, obj->value[0] / 5);
	  af.location  = APPLY_NONE;
	  af.modifier  = 0;
	  af.bitvector = AFF_POISON;
	  if (!is_affected(ch, af.type))
	    affect_to_char( ch, &af );
	}
      break;
    case ITEM_PILL:
      WAIT_STATE(ch,6);
      if (ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)){
	if (!str_cmp(obj->material,"warflesh"))
	  flevel = ch->level - 3;
	else{
	  send_to_char("You are not allowed to use magic!\n\r", ch);
	  return;
	}
      }
      else
	flevel = obj->value[0];
      obj_cast_spell( obj->value[1], flevel, ch, ch, NULL );
      if (ch == NULL)
	return;
      obj_cast_spell( obj->value[2], flevel, ch, ch, NULL );
      if (ch == NULL)
	return;
      obj_cast_spell( obj->value[3], flevel, ch, ch, NULL );
      if (ch == NULL)
	return;
      break;
    case ITEM_HERB:
      if (ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)){
	if (!str_cmp(obj->material,"warflesh"))
	  flevel = ch->level - 3;
	else{
	  send_to_char("You are not allowed to use magic!\n\r", ch);
	  return;
	}
      }
      WAIT_STATE(ch,6);
      obj_cast_spell( obj->value[1], obj->level, ch, ch, NULL );
      break;
    }
  extract_obj( obj );
}

void do_smoke( CHAR_DATA *ch, char *argument ){
  AFFECT_DATA af;
  char arg[MIL];
  OBJ_DATA *obj;
  const int dur = 24;
  int level = 0;

  one_argument( argument, arg );

  if ( arg[0] == '\0' ){
    send_to_char( "Smoke what?\n\r", ch );
    return;  
  }
  if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL ){
    send_to_char( "You do not have that item.\n\r", ch );
    return;
  }
  if ( obj->item_type != ITEM_HERB ){
    send_to_char( "You can't smoke that.\n\r", ch );
    return;
  }

  WAIT_STATE2(ch, PULSE_VIOLENCE / 2);
  act( "$n lights $p and smokes it.",  ch, obj, NULL, TO_ROOM );
  act( "You light $p and begin to smoke it.", ch, obj, NULL, TO_CHAR );  

  if (IS_UNDEAD(ch)){
    send_to_char("Its tasteless.\n\r", ch);
    return;
  }
  if (ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC) && !str_cmp(obj->material,"warflesh"))
    level = ch->level - 3;
  else
    level = obj->level + 10;  

  obj_cast_spell( obj->value[4], UMIN(47, level), ch, ch, NULL );   

  af.where     = TO_AFFECTS;
  af.type      = gsn_drug_use;
  af.level     = dur;
  af.duration  = number_fuzzy(obj->value[0]);        
  af.location  = APPLY_NONE;
  af.modifier  = 0;
  af.bitvector = 0;

  affect_strip( ch, af.type );
  affect_to_char( ch, &af );

  spell_drug_use(gsn_drug_use, ch->level, ch, (void *) ch, TARGET_CHAR);
  extract_obj( obj );
} 

/* checks if class can double sheath a given object */
bool can_doublesheath(CHAR_DATA* ch, OBJ_DATA* obj, bool fSilent ){

  if(ch->class == class_lookup("thief") 
     && obj->value[0] != WEAPON_DAGGER){
    if (!fSilent)
      send_to_char("You may only double sheath daggers.\n\r", ch);
    return FALSE;
  }
  else if (ch->class == class_lookup("ninja") 
	   && obj->value[0] != WEAPON_EXOTIC){
    if (!fSilent)
      send_to_char("You may only double sheath exotics.\n\r", ch);
    return FALSE;
  }
  return TRUE;
}

bool check_sheath(CHAR_DATA* ch, int iWear){
  OBJ_DATA* obj;

/* check for weapon equip with sheaths */
  if (iWear == WEAR_WIELD && (obj = get_eq_char(ch, WEAR_SHEATH_L)) != NULL){
    if (obj->item_type != ITEM_WEAPON){
      send_to_char("You may only sheath weapons.\n\r", ch);
      return FALSE;
    }
    if (get_skill(ch, gsn_sheath) < 1){
      send_to_char("You already have a weapon sheathed.\n\r", ch);
      return FALSE;
    }
    if (!can_doublesheath(ch, obj, FALSE)){
      return FALSE;
    }
  }
  /* secondary is more complicated */
  if (iWear == WEAR_SECONDARY 
      || iWear == WEAR_SHIELD 
      || iWear == WEAR_HOLD){
    /* check if we have something sheathed near secondary arm */
    if ((obj = get_eq_char(ch, WEAR_SHEATH_R)) != NULL){
      /* check if we are advanced enough to allowed this */
      int pos = sheath_lookup(class_table[ch->class].name);
      if (obj->item_type != ITEM_WEAPON){
	send_to_char("You may only sheath weapons.\n\r", ch);
	return FALSE;
      }
      if (get_skill(ch, gsn_sheath) < 1 || !sheath_table[pos].both){
	send_to_char("Your sheathed weapon gets in the way.\n\r", ch);
	return FALSE;
      }
      if (!can_doublesheath(ch, obj, FALSE)){
	return FALSE;
      }
    }
  }
  return TRUE;
}

bool remove_obj( CHAR_DATA *ch, int iWear, bool fReplace )
{
    OBJ_DATA *obj;

    if ( ( obj = get_eq_char( ch, iWear ) ) == NULL )
	return TRUE;
    if ( !fReplace )
      return FALSE;
    if (CAN_WEAR(obj, ITEM_WEAR_TATTOO) && ch->tattoo>0)
        return FALSE;
    if (( !IS_IMMORTAL(ch) && IS_SET(obj->extra_flags, ITEM_NOREMOVE)) || (iWear == WEAR_WIELD && is_affected(ch, gsn_graft_weapon)) )
    {
	act( "You can't remove $p.", ch, obj, NULL, TO_CHAR );
	return FALSE;
    }
    unequip_char( ch, obj );
    act( "$n stops using $p.", ch, obj, NULL, TO_ROOM );
    act( "You stop using $p.", ch, obj, NULL, TO_CHAR );
    if ( obj->pIndexData->message )
    {
        act( obj->pIndexData->message->offself, ch, obj, NULL, TO_CHAR );
        act( obj->pIndexData->message->offother,  ch, obj, NULL, TO_ROOM );
    }
    return TRUE;
}

bool check_secondary( CHAR_DATA* ch, OBJ_DATA* obj, OBJ_DATA* wield){
  int obj_w = 0;
  int wie_w = 0;
  bool fMino = FALSE;

  if (ch->race == race_lookup("minotaur") 
      && wield->value[0] == WEAPON_AXE 
      && obj->value[0] == WEAPON_AXE){
    send_to_char("You managed to wield both axes in your hands.\n\r",ch);
    fMino = TRUE;
  }
  else if ((IS_WEAPON_STAT(obj,WEAPON_TWO_HANDS) 
	    || obj->value[0] == WEAPON_STAFF 
	    || obj->value[0] == WEAPON_POLEARM 
	    || obj->item_type == ITEM_INSTRUMENT) 
	   && (IS_WEAPON_STAT(wield,WEAPON_TWO_HANDS) 
	       || wield->value[0] == WEAPON_STAFF 
	       || wield->value[0] == WEAPON_POLEARM 
	       || wield->item_type == ITEM_INSTRUMENT))
    {
      send_to_char("There's no way you can dual-wield two two-handed weapons!\n\r",ch);
      return FALSE;
    }
  else if ((ch->size < SIZE_LARGE && 
	    (IS_WEAPON_STAT(obj,WEAPON_TWO_HANDS) 
	     || IS_WEAPON_STAT(wield,WEAPON_TWO_HANDS)))
	   || obj->value[0] == WEAPON_STAFF 
	   || obj->item_type == ITEM_INSTRUMENT 
	   || wield->item_type == ITEM_INSTRUMENT 
	   || obj->value[0] == WEAPON_POLEARM 
	   || wield->value[0] == WEAPON_STAFF 
	   || wield->value[0] == WEAPON_POLEARM 
	   || is_affected(ch,gsn_double_grip))
    {
      if (wield->value[0] == WEAPON_POLEARM 
	  || obj->value[0] == WEAPON_POLEARM )
	send_to_char("A polearm cannot be dual wieled with any other weapon.\n\r",ch);
      else
	send_to_char("You need two hands free for that weapon.\n\r",ch);
      return FALSE;
    }
  obj_w = get_obj_weight(obj);
  wie_w = get_obj_weight(wield);

  //if obj is between wie_w and 0.75 wie_w and obj is light or person has bladework skill allow it.
  if (obj_w <= wie_w
      && obj_w >= 3 * wie_w / 4 
      && (obj_w <= 100 || get_skill(ch, gsn_bladework) > 2))
    return TRUE;
  //if obj is smaller then 0.75 wie_w allow it always
  else if (obj_w < 3 * wie_w / 4)
    return TRUE;
  else if (!fMino){
    act("$p is too heavy to be used as a secondary weapon.",ch, obj, NULL, TO_CHAR);
    return FALSE;
  }
  else 
    return TRUE;
}

void wear_obj( CHAR_DATA *ch, OBJ_DATA *obj, bool fReplace, bool twohands )
{
  /* race check */
  if (!IS_NPC(ch) 
      && obj->race && obj->race != ch->race){
    act("Its size and style make it useless to you.", ch, NULL, NULL, TO_CHAR);
    return;
  }
  /* class */
  if (!IS_NPC(ch) 
      && obj->class >= 0 && obj->class != ch->class){
    act("Its size and style make it useless to you.", ch, NULL, NULL, TO_CHAR);
    return;
  }
  if ( obj->pIndexData ->vnum == OBJ_VNUM_PRAYER_BEADS && ch->class != class_lookup("monk"))
      {
	act( "Only monks may hold prayer beads.",ch, NULL, NULL, TO_CHAR);
        return;
      }
    if (is_affected(ch,gsn_tiger) 
	|| is_affected(ch,gsn_crane) 
	|| is_affected(ch,gsn_monkey)
 	|| is_affected(ch,gsn_dragon) 
	|| is_affected(ch,gsn_horse) 
	|| is_affected(ch,gsn_buddha) 
	|| is_affected(ch,gsn_drunken))
      {
	int loc = wear_loc(obj->wear_flags, 1);
	if (get_obj_weight(obj) > get_monk(loc)){
	  act("$p will encumber you too much while in a stance.", ch, obj, NULL, TO_CHAR);
	  return;
	}
      }
    if ( obj->item_type == ITEM_LIGHT )
    {
      if (ch->class == class_lookup("vampire"))
	{
	    act("You prefer to stay in the shadows.",ch, NULL, NULL, TO_CHAR);
	    return;
	}
      if ( !remove_obj( ch, WEAR_LIGHT, fReplace ) )
	return;
      act( "$n lights $p and holds it.", ch, obj, NULL, TO_ROOM );
      act( "You light $p and hold it.",  ch, obj, NULL, TO_CHAR );
      equip_char( ch, obj, WEAR_LIGHT );
      return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_FINGER ) )
      {
	if ( get_eq_char( ch, WEAR_FINGER_L ) != NULL && get_eq_char( ch, WEAR_FINGER_R ) != NULL
	     && !remove_obj( ch, WEAR_FINGER_L, fReplace ) && !remove_obj( ch, WEAR_FINGER_R, fReplace ) )
	  return;
	if ( get_eq_char( ch, WEAR_FINGER_L ) == NULL )
	  {
	    act( "$n slips $p on to $s left finger.",    ch, obj, NULL, TO_ROOM );
	    act( "You slip $p on to your left finger.",  ch, obj, NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_FINGER_L );
	    return;
	  }
	if ( get_eq_char( ch, WEAR_FINGER_R ) == NULL )
	  {
	    act( "$n slips $p on to $s right finger.",   ch, obj, NULL, TO_ROOM );
	    act( "You slip $p on to your right finger.", ch, obj, NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_FINGER_R );
	    return;
	  }
	bug( "Wear_obj: no free finger.", 0 );
	send_to_char( "You already wear two rings.\n\r", ch );
	return;
    }
    if ( CAN_WEAR( obj, 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 ) == NULL )
	{
	  act( "$n wears $p around $s neck.",   ch, obj, NULL, TO_ROOM );
	  act( "You wear $p around your neck.", ch, obj, NULL, TO_CHAR );
	  equip_char( ch, obj, WEAR_NECK_1 );
	  return;
	}
	if ( get_eq_char( ch, WEAR_NECK_2 ) == NULL )
	  {
	    act( "$n wears $p around $s neck.",   ch, obj, NULL, TO_ROOM );
	    act( "You wear $p around your neck.", ch, obj, NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_NECK_2 );
	    return;
	  }
	bug( "Wear_obj: no free neck.", 0 );
	act( "You already wear two neck items.", ch, NULL, NULL, TO_CHAR );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_BODY ) )
    {
	if ( !remove_obj( ch, WEAR_BODY, fReplace ) )
	    return;
	act( "$n slides $p over $s torso.",   ch, obj, NULL, TO_ROOM );
	act( "You slide $p over your torso.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_BODY );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_HEAD ) )
    {
	if ( !remove_obj( ch, WEAR_HEAD, fReplace ) )
	    return;
	act( "$n wears $p on $s head.",   ch, obj, NULL, TO_ROOM );
	act( "You wear $p on your head.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_HEAD );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_FACE ) )    
    {
        if ( !remove_obj( ch, WEAR_FACE, fReplace ) )            return;
        act( "$n wears $p on $s face.",   ch, obj, NULL, TO_ROOM );
        act( "You wear $p on your face.", ch, obj, NULL, TO_CHAR );
        equip_char( ch, obj, WEAR_FACE );        
        return;    
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_LEGS ) )
    {
	if ( !remove_obj( ch, WEAR_LEGS, fReplace ) )
	    return;
	act( "$n wears $p on $s legs.",   ch, obj, NULL, TO_ROOM );
	act( "You wear $p on your legs.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_LEGS );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_FEET ) )
    {
	if ( !remove_obj( ch, WEAR_FEET, fReplace ) )
	    return;
	act( "$n ties $p on $s feet.",   ch, obj, NULL, TO_ROOM );
	act( "You tie $p on your feet.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_FEET );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_HANDS ) )
    {
	if ( !remove_obj( ch, WEAR_HANDS, fReplace ) )
	    return;
	act( "$n slips $p on to $s hands.",   ch, obj, NULL, TO_ROOM );
	act( "You slip $p on to your hands.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_HANDS );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_ARMS ) )
    {
	if ( !remove_obj( ch, WEAR_ARMS, fReplace ) )
	    return;
	act( "$n wears $p on $s arms.",   ch, obj, NULL, TO_ROOM );
	act( "You wear $p on your arms.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_ARMS );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_ABOUT ) )
    {
	if ( !remove_obj( ch, WEAR_ABOUT, fReplace ) )
	    return;
	act( "$n wears $p about $s body.",   ch, obj, NULL, TO_ROOM );
	act( "You wear $p about your body.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_ABOUT );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_WAIST ) )
    {
	if ( !remove_obj( ch, WEAR_WAIST, fReplace ) )
	    return;
	act( "$n buckles $p around $s waist.",   ch, obj, NULL, TO_ROOM );
	act( "You buckle $p around your waist.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_WAIST );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_WRIST ) )
    {
	if ( get_eq_char( ch, WEAR_WRIST_L ) != NULL && get_eq_char( ch, WEAR_WRIST_R ) != NULL
        && !remove_obj( ch, WEAR_WRIST_L, fReplace ) && !remove_obj( ch, WEAR_WRIST_R, fReplace ) )
	    return;
	if ( get_eq_char( ch, WEAR_WRIST_L ) == NULL )
	{
            act( "$n wears $p around $s left wrist.", ch, obj, NULL, TO_ROOM );
            act( "You wear $p around your left wrist.", ch, obj, NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_WRIST_L );
	    return;
	}
	if ( get_eq_char( ch, WEAR_WRIST_R ) == NULL )
	{
            act( "$n wears $p around $s right wrist.", ch, obj, NULL, TO_ROOM );
            act( "You wear $p around your right wrist.", ch, obj, NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_WRIST_R );
	    return;
	}
	bug( "Wear_obj: no free wrist.", 0 );
	act( "You already wear two wrist items.", ch, NULL, NULL, TO_CHAR );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_SHIELD ) )
    {
	OBJ_DATA *weapon;
	if ( is_affected(ch,gsn_body_weaponry))
	{
	    act("Your hands can't hold a shield.",ch, NULL, NULL, TO_CHAR);
	    return;
	}
	if (!check_sheath(ch, WEAR_SHIELD))
	  return;
	if ( !remove_obj( ch, WEAR_SHIELD, fReplace ) )
	    return;
	weapon = get_eq_char(ch,WEAR_WIELD);
        if ( !IS_NPC(ch) && get_obj_weight_char(ch, obj) > (str_app[get_curr_stat(ch,STAT_STR)].wield * 12))
	{
	  act( "It is too heavy for you to wield.", ch, NULL, NULL, TO_CHAR );
	  return;
	}
        if (get_eq_char( ch, WEAR_SECONDARY) != NULL
	    && !remove_obj( ch, WEAR_SECONDARY, fReplace)){
	  act("You can't use a shield and two weapons.", ch, NULL, NULL, TO_CHAR);
	  return;
	}
        if (weapon != NULL 
	    && ((IS_WEAPON_STAT(weapon,WEAPON_TWO_HANDS) 
		 && (ch->size < SIZE_LARGE || obj->value[0] == WEAPON_STAFF))
		|| weapon->value[0] == WEAPON_POLEARM 
		|| weapon->item_type == ITEM_INSTRUMENT 
		|| is_affected(ch,gsn_double_grip)))
	  {
	    if (is_affected(ch, gsn_double_grip)){
	      act("Your hands are tied up!", ch, NULL, NULL, TO_CHAR);
	      return;
	    }
	    else if ( !remove_obj( ch, WEAR_WIELD, fReplace ) )
	      return;
	    act("`!You are now without primary weapon!``", ch, NULL, NULL, TO_CHAR);
	}
        if (weapon != NULL && get_eq_char(ch, WEAR_HOLD) != NULL)
	  {
	    if ( !remove_obj( ch, WEAR_HOLD, fReplace ) )
	    return;
        }
	if ( !remove_obj( ch, WEAR_RANGED, fReplace ) ){
	  act("You cannot use a shield and a ranged weapon.", ch, NULL, NULL, TO_CHAR);
	  return;
	}
	act( "$n wears $p as a shield.", ch, obj, NULL, TO_ROOM );
	act( "You wear $p as a shield.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_SHIELD );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WIELD ) )
    {
	int sn, skill, weight;
	OBJ_DATA *second;

	if (ch->race == race_lookup("illithid"))
	{
	  act("You cannot wield anything!", ch, NULL, NULL, TO_CHAR);
	  return;
	}
	if (is_affected(ch, gen_holy_hands))
	  {
	    act("But your hands are empowered!", ch, NULL, NULL, TO_CHAR);
	    return;
	  }
	if ( is_affected(ch,gsn_body_weaponry))
	{
	  act("Your hands can't hold anything.", ch, NULL, NULL, TO_CHAR);
	  return;
	}
	if ( is_affected(ch,gsn_graft_weapon) && obj->item_type == ITEM_WEAPON)
	{
	  act("You already have a weapon grafted to your hands.", ch, NULL, NULL, TO_CHAR);
	  return;
	}
	if (!check_sheath(ch, WEAR_WIELD))
	  return ;
	if ( is_affected(ch,gsn_double_grip) && !twohands)
	{
	  act( "You're holding your weapon too tight to replace it.", ch, NULL, NULL, TO_CHAR);
	  return;
	}
	weight = (str_app[get_curr_stat(ch,STAT_STR)].wield * 10);
        if ((IS_WEAPON_STAT(obj,WEAPON_TWO_HANDS) 
	     && (ch->size < SIZE_LARGE || obj->value[0] == WEAPON_STAFF))
	     || obj->value[0] == WEAPON_POLEARM 
	     || obj->item_type == ITEM_INSTRUMENT 
	     || twohands)
	    weight = 3 * weight /2;
	if (obj->item_type == ITEM_WEAPON
	    && get_skill(ch, gsn_2h_handling) > 0
	    && (IS_WEAPON_STAT(obj,WEAPON_TWO_HANDS) 
		|| is_affected(ch, gsn_double_grip)) )
	weight = 3 * weight / 2;
        if ( !IS_NPC(ch) && get_obj_weight_char(ch, obj) > weight)
	{
	  act( "It is too heavy for you to wield.", ch, NULL, NULL, TO_CHAR);
	  return;
	}
	
        if ( ((IS_WEAPON_STAT(obj,WEAPON_TWO_HANDS) 
	       && (ch->size < SIZE_LARGE || obj->value[0] == WEAPON_STAFF))
	       || obj->value[0] == WEAPON_POLEARM 
	       || obj->item_type == ITEM_INSTRUMENT) 
	      && get_eq_char(ch,WEAR_SHIELD) != NULL)
	{
	  if ( !remove_obj( ch, WEAR_SHIELD, fReplace ) )
	    return;
	}
        if (((IS_WEAPON_STAT(obj,WEAPON_TWO_HANDS) 
	      && (ch->size < SIZE_LARGE || obj->value[0] == WEAPON_STAFF))
	      || obj->value[0] == WEAPON_POLEARM 
	      || obj->item_type == ITEM_INSTRUMENT) 
	     && get_eq_char(ch,WEAR_HOLD) != NULL)
	{
	  if ( !remove_obj( ch, WEAR_HOLD, fReplace ) )
	    return;
	}
        if (get_eq_char(ch, WEAR_HOLD) != NULL && get_eq_char(ch, WEAR_SHIELD) != NULL)
        {
	  act("You're already holding two items.", ch, NULL, NULL, TO_CHAR);
	  return;
        }
        second = get_eq_char(ch,WEAR_SECONDARY);
        if (second ){
	  /* check for dual wielding restrictions */
	  if (!check_secondary(ch, second, obj)
	      && !remove_obj( ch, WEAR_SECONDARY, fReplace))
	    return;
//safety for no-remove seconds.
	  if (!IS_IMMORTAL(ch) 
	      && IS_SET(obj->extra_flags, ITEM_NOREMOVE)){
	    act("You need to be able to remove $p before wielding that.", ch, second, NULL, TO_CHAR);
	    return;
	  }
	}
	if ( !remove_obj( ch, WEAR_WIELD, fReplace ) )
	  return;
	if (IS_NPC(ch) || ch->pcdata->wep_pos == WEPPOS_NORMAL){
	  act( "$n wields $p.", ch, obj, NULL, TO_ROOM );
	  act( "You wield $p.", ch, obj, NULL, TO_CHAR );
	}
	else if (ch->pcdata->wep_pos == WEPPOS_HIGH){
	  act( "$n wields $p and holds it high.", ch, obj, NULL, TO_ROOM );
	  act( "You wield $p and hold it high.", ch, obj, NULL, TO_CHAR );
	}
	else if (ch->pcdata->wep_pos == WEPPOS_LOW){
	  act( "$n wields $p and holds it low.", ch, obj, NULL, TO_ROOM );
	  act( "You wield $p and hold it low.", ch, obj, NULL, TO_CHAR );
	}
	else{
	  act( "$n wields $p.", ch, obj, NULL, TO_ROOM );
	  act( "You wield $p.", ch, obj, NULL, TO_CHAR );
	}
	equip_char( ch, obj, WEAR_WIELD );
        sn = get_weapon_sn(ch, FALSE);
	if (sn == gsn_hand_to_hand)
	   return;
        skill = get_weapon_skill_obj(ch, obj);

/* Viri: disabled to cut down on spam
         if (skill > 112) act("No mortal can match you with $p in your hand.",ch,obj,NULL,TO_CHAR);
        else if (skill > 100) act("Your skill with $p is unmatched in the land.",ch,obj,NULL,TO_CHAR);
        else if (skill > 95) act("$p feels like a part of you!",ch,obj,NULL,TO_CHAR);
        else if (skill > 85) act("You feel quite confident with $p.",ch,obj,NULL,TO_CHAR);
        else if (skill > 70) act("You are skilled with $p.",ch,obj,NULL,TO_CHAR);
        else if (skill > 50) act("Your skill with $p is adequate.",ch,obj,NULL,TO_CHAR);
        else if (skill > 25) act("$p feels a little clumsy in your hands.",ch,obj,NULL,TO_CHAR);
        else if (skill > 1)  act("You fumble and almost drop $p.",ch,obj,NULL,TO_CHAR);
        else                 act("You don't even know which end is up on $p.",ch,obj,NULL,TO_CHAR);
*/
        if (!str_cmp(obj->material,"practice"))
	  act("You feel that you can improve upon your skills with such a fine practice weapon.", ch, NULL, NULL, TO_CHAR);
	return;
    }
    if ( CAN_WEAR( obj, ITEM_HOLD ) )
    {
	OBJ_DATA *weapon;
	if ( is_affected(ch,gsn_body_weaponry))
	{
	  act("Your hands can't hold anything.", ch, NULL, NULL, TO_CHAR);
	  return;
	}
	if (!check_sheath(ch, WEAR_HOLD))
	  return ;
        if ( !remove_obj( ch, WEAR_HOLD, fReplace ) )
	    return;
	weapon = get_eq_char(ch,WEAR_WIELD);
        if (get_eq_char(ch, WEAR_SECONDARY) != NULL)
        {
	  act("You can't hold an item and use two weapons.", ch, NULL, NULL, TO_CHAR);
	  return;
        }
	if (weapon != NULL 
	    && ((IS_WEAPON_STAT(weapon,WEAPON_TWO_HANDS)
		 && (ch->size < SIZE_LARGE || obj->value[0] == WEAPON_STAFF))
		|| weapon->value[0] == WEAPON_POLEARM 
		|| weapon->item_type == ITEM_INSTRUMENT 
		|| is_affected(ch,gsn_double_grip)))
	  {
	    act("Your hands are tied up!", ch, NULL, NULL, TO_CHAR);
	    return;
	  }
        if (weapon != NULL && get_eq_char(ch, WEAR_SHIELD) != NULL)
	  {
            act("You're already holding two items.", ch, NULL, NULL, TO_CHAR);
            return;
	  }
	act( "$n holds $p in $s hand.",   ch, obj, NULL, TO_ROOM );
	act( "You hold $p in your hand.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_HOLD );
	return;
    }
    if ( CAN_WEAR(obj,ITEM_WEAR_FLOAT) )
    {
      if (!remove_obj(ch,WEAR_FLOAT, fReplace) )
	return;
      if (!remove_obj(ch,WEAR_RANGED, fReplace) )
	return;
      act("$n releases $p to float next to $m.",ch,obj,NULL,TO_ROOM);
      act("You release $p and it floats next to you.",ch,obj,NULL,TO_CHAR);
      equip_char(ch,obj,WEAR_FLOAT);
      return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_SHROUD ) && (ch->class == class_lookup("necromancer") || IS_IMMORTAL(ch)))
    {
        if ( !remove_obj( ch, WEAR_SHROUD, fReplace ) )
	    return;
        act( "$n releases the $p.", ch, obj, NULL, TO_ROOM );
        act( "You release $p.",  ch, obj, NULL, TO_CHAR );
        equip_char( ch, obj, WEAR_SHROUD );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_EARRING ) )
    {
	if ( !remove_obj( ch, WEAR_EARRING, fReplace ) )
	    return;
	act( "$n attaches $p to $s earlobes.",   ch, obj, NULL, TO_ROOM );
	act( "You attach $p to your earlobes.", ch, obj, NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_EARRING );
	return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_RANGED) )
    {
      if ( !remove_obj( ch, WEAR_SHIELD, fReplace ) ){
	act("You cannot use a ranged weapon with a shield in hand.",ch, obj, NULL, TO_CHAR);
	return;
      }
      if ( !remove_obj( ch, WEAR_FLOAT, fReplace ) ){
	act("You cannot use a ranged weapon with an item floating about.",ch, obj, NULL, TO_CHAR);
	return;
      }
      if ( !remove_obj( ch, WEAR_RANGED, fReplace ) )
	return;
      act( "$n slings $p across $s back.",   ch, obj, NULL, TO_ROOM );
      act( "You sling $p across your back.", ch, obj, NULL, TO_CHAR );
      equip_char( ch, obj, WEAR_RANGED );

      if (obj->level > ch->level && ch->level < 50)
	act("You're not quite sure how to handle $p properly.", ch, obj, NULL, TO_CHAR);
      return;
    }
    if ( CAN_WEAR( obj, ITEM_WEAR_QUIVER) )
    {
      OBJ_DATA* ammo = get_eq_char( ch, WEAR_QUIVER );

      /* check if we can add */
      if (ammo && ammo->vnum == obj->vnum && !str_cmp( ammo->name, obj->name) && ammo->condition < 100){
	int transfer = UMIN(obj->condition, 100 - ammo->condition);
	ammo->condition += transfer;
	obj->condition -= transfer;
      }
      else{
	if ( !remove_obj( ch, WEAR_QUIVER, fReplace ) )
	  return;
	equip_char( ch, obj, WEAR_QUIVER );
      }
      act( "$n put $p in $s quiver.",   ch, obj, NULL, TO_ROOM );
      act( "You put $p in your quiver.", ch, obj, NULL, TO_CHAR );
      
      if (obj->level > ch->level)
	act("You're not quite sure how to handle $p properly.", ch, obj, NULL, TO_CHAR);

      if (obj->condition < 1)
	extract_obj( obj );
      
      return;
    }
    if ( fReplace )
      act( "You can't wear, wield, or hold that.", ch, NULL, NULL, TO_CHAR);
}

void do_wear( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    OBJ_DATA *obj;
    one_argument( argument, arg );
    if (is_affected(ch,gsn_bat_form) 
	|| is_affected(ch,gsn_wolf_form) 
	|| is_affected(ch,gsn_mist_form)
	|| is_affected(ch,gsn_weretiger)	
	|| is_affected(ch,gsn_werewolf)	
	|| is_affected(ch,gsn_werebear)	
	|| is_affected(ch,gsn_werefalcon)){
      send_to_char("Not while you're morphed.\n\r",ch);
      return;
    }
    if ( arg[0] == '\0' )
    {
	send_to_char( "Wear, wield, or hold what?\n\r", ch );
	return;
    }
    if ( !str_cmp( arg, "all" ) )
    {
	OBJ_DATA *obj_next;
	for ( obj = ch->carrying; obj != NULL; obj = obj_next )
	{
	    obj_next = obj->next_content;
	    if ( obj->wear_loc == WEAR_NONE && can_see_obj( ch, obj ) )
		wear_obj( ch, obj, FALSE, FALSE );
	}
	return;
    }
    else
    {
	if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
	{
	    send_to_char( "You do not have that item.\n\r", ch );
	    return;
	}
	wear_obj( ch, obj, TRUE, FALSE );
    }
}

void do_remove( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    OBJ_DATA *obj;
    one_argument( argument, arg );
    if (is_affected(ch,gsn_bat_form) 
	|| is_affected(ch,gsn_wolf_form) 
	|| is_affected(ch,gsn_mist_form)
	|| is_affected(ch,gsn_weretiger)	
	|| is_affected(ch,gsn_werewolf)	
	|| is_affected(ch,gsn_werebear)	
	|| is_affected(ch,gsn_werefalcon)){
      send_to_char("Not while you're morphed.\n\r",ch);
      return;
    }
    if ( arg[0] == '\0' )
    {
	send_to_char( "Remove what?\n\r", ch );
	return;
    }
    if ( !str_cmp( arg, "all" ) )
    {
        OBJ_DATA *obj, *temp = get_eq_char( ch, WEAR_WIELD );
        int iWear;
        for ( iWear = 0; iWear < MAX_WEAR; iWear++ )
	{
            if ( !( obj = get_eq_char( ch, iWear ) ) )
                continue;
            remove_obj( ch, obj->wear_loc, TRUE );
	}
        if ( ( obj = get_eq_char( ch, WEAR_WIELD ) ) != NULL && obj != temp)
            remove_obj( ch, obj->wear_loc, TRUE );
	return;
    }
    if ( ( obj = get_obj_wear( ch, arg, ch) ) == NULL )
    {
	send_to_char( "You do not have that item.\n\r", ch );
	return;
    }
    remove_obj( ch, obj->wear_loc, TRUE );
}

void do_sacrifice( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buffer[100];

    OBJ_DATA *obj;
    CHAR_DATA* och;
    AFFECT_DATA* paf;

    int gold, members = 0;
    bool split = TRUE;
    bool fOwnerProt = FALSE;
    CHAR_DATA *gch;
    one_argument( argument, arg );
    if ( arg[0] == '\0' || !str_cmp( arg, ch->name ) )
    {
      if (ch->tattoo)
	{

	  act( "$n offers $mself to $t, who graciously declines.",ch, deity_table[ch->tattoo].god, NULL, TO_ROOM );
	  act( "$t appreciates your offer and may accept it later.",ch, deity_table[ch->tattoo].god, NULL, TO_CHAR );
	}
      else
	{
	  act( "$n offers $mself to $g, who graciously declines.",ch,NULL, NULL, TO_ROOM );
	  act( "$g appreciates your offer and may accept it later.",ch,NULL, NULL, TO_CHAR );
	}
      
      return;
    }
    obj = get_obj_list( ch, arg, ch->in_room->contents );
    if ( obj == NULL )
      {
	send_to_char( "You can't find it.\n\r", ch );
	return;
    }
    if ( obj->item_type == ITEM_CORPSE_PC )
    {
      if (ch->tattoo)
        sendf(ch, "%s wouldn't like that.\n\r",deity_table[ch->tattoo].god);
      else
	act( "$g wouldn't like that.",ch, NULL, NULL, TO_CHAR);
      return;
    }
    /* check for owner being ghost */
    if (IS_SET(obj->wear_flags, ITEM_HAS_OWNER)
	&& (paf = affect_find(obj->affected, gen_has_owner)) != NULL
	&& (paf->has_string 
	    && (och = get_char(paf->string)) != NULL)
	&& (is_ghost(och, 600) 
	    || (obj->in_obj && obj->in_obj->in_room->pCabal)
	    || (obj->in_room->pCabal) )
	&& !IS_IMMORTAL(ch))
      fOwnerProt = TRUE;
	  
    if ( !CAN_WEAR(obj, ITEM_TAKE) || CAN_WEAR(obj, ITEM_NO_SAC) || fOwnerProt)
    {
      act( "You feel $g's anger even as you think about it.", ch, obj, 0, TO_CHAR );
      return;
    }
    if ((obj->item_type == ITEM_CORPSE_NPC 
	 || obj->item_type == ITEM_CONTAINER) 
	&& obj->contains)
    {
        OBJ_DATA *t_obj, *next_obj;
        for (t_obj = obj->contains; t_obj != NULL; t_obj = next_obj)
        {
            next_obj = t_obj->next_content;
            obj_from_obj(t_obj);
            if (obj->in_obj)
                obj_to_obj(t_obj,obj->in_obj);
            else if (obj->in_room == NULL)
                extract_obj(t_obj);
	    else if (IS_OBJ_STAT(t_obj,ITEM_MELT_DROP))
	    {
	        act("$p dissolves into smoke.",ch,t_obj,NULL,TO_ALL);
	        extract_obj(t_obj);
	    }
            else
                obj_to_room(t_obj,obj->in_room);
        }
    }
    gold = UMAX(1,obj->level * 2);
    if (obj->item_type != ITEM_CORPSE_NPC && obj->item_type != ITEM_CORPSE_PC)
        gold = UMIN(gold,obj->cost);
    if (IS_PERK(ch, PERK_PIOUS))
      gold = 3 * gold / 2;
    if (gold == 1)
      {
	if (ch->tattoo)
	  sendf(ch, "%s gives you one gold coin for your sacrifice.\n\r",deity_table[ch->tattoo].god);
	else
	  act("$g gives you one gold coin for your sacrifice.",ch, NULL, NULL, TO_CHAR);
      }
    else
      {
	if (ch->tattoo)
	  sendf(ch,"%s gives you %d gold coins for your sacrifice.\n\r",deity_table[ch->tattoo].god,gold);
	else
	  sendf(ch,"%s gives you %d gold coins for your sacrifice.\n\r",(IS_NPC(ch)? "The One God": (ch->pcdata->deity[0] == '\0'? "The One God" : ch->pcdata->deity)),gold);
      }
    if (ch->class == class_lookup("monk") && (ch->gold + gold) > 20000 && gold > 0)
    {
	int overflow = UMAX(1,ch->gold + gold - 20000);
	ch->gold = 20000;
	send_to_char("You can't hold that much gold and drop it.\n\r",ch);
	obj_to_room( create_money( overflow ), ch->in_room );
	split = FALSE;
    }
    else
    	ch->gold += gold;
    if (ch->tattoo)
      act( "$n sacrifices $p to $T.", ch, obj, deity_table[ch->tattoo].god, TO_ROOM );
    else
      act( "$n sacrifices $p in the name of $T.", ch, obj, path_table[deity_table[IS_NPC(ch) ? 0 : ch->pcdata->way].path].name, TO_ROOM );
    if (IS_SET(ch->act,PLR_AUTOSPLIT) && split)
    {
        for (gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room )
            if ( is_same_group( gch, ch ) )
                members++;
        if ( members > 1 && gold > 1)
	{
            sprintf(buffer,"%d",gold);
	    do_split(ch,buffer);	
	}
    }
    extract_obj( obj );
}

void do_quaff( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *vch, *vch_next;
    char arg[MIL];
    OBJ_DATA *obj;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Quaff what?\n\r", ch );
	return;
    }
    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL && ( obj = get_obj_wear( ch, arg, ch) ) == NULL )
    {
	send_to_char( "You do not have that potion.\n\r", ch );
	return;
    }
    if (is_affected(ch, gsn_bat_form) || is_affected(ch, gsn_mist_form) ){
      send_to_char("You cannot do that while morphed.\n\r", ch);
      return;
    }
    /* trap check */
    if (trip_traps(ch, obj->traps)){
      WAIT_STATE2(ch, 4);
      return;
    }
    if ( obj->item_type != ITEM_POTION )
    {
	send_to_char( "You can quaff only potions.\n\r", ch );
	return;
    }
    if ( ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC))
    {
        send_to_char("You are not allowed to use magic!\n\r", ch);
        return;
    }
    /* race check */
    if (!IS_NPC(ch) 
	&& obj->race && obj->race != ch->race){
      act("Its size and style make it useless to you.", ch, NULL, NULL, TO_CHAR);
      return;
    }
    /* class */
    if (!IS_NPC(ch) 
	&& obj->class >= 0 && obj->class != ch->class){
      act("Its size and style make it useless to you.", ch, NULL, NULL, TO_CHAR);
      return;
    }
    if (is_affected(ch, gsn_gag)){
      send_to_char("The gag stops you from drinking.\n\r", ch);
      return;
    }
    if ( ch->fighting != NULL )
    {
	bool found = FALSE;
	for ( vch = char_list; vch != NULL; vch = vch_next )
	{
	    vch_next = vch->next;
	    if (vch->fighting == ch)
	    {
		found=TRUE;
		continue;
	    }
	}
	if (found)
	{
    	    if ( ( obj = get_obj_wear( ch, arg, ch) ) != NULL )
	    {
		if ( obj->item_type != ITEM_POTION)
	    	{
		    send_to_char( "You need to hold the potion in order to quaff it while being attacked.\n\r", ch);
	    	    return;
		}
		else if (number_percent() >= (get_curr_stat(ch,STAT_DEX) * 4) )
		{
		    WAIT_STATE(ch,6);
		    send_to_char("You fumble and drop the potion, spilling its contents.\n\r",ch);
		    obj_from_char(obj);
		    return;
		}
	    }
	    else
	    {		
		send_to_char( "You need to hold the potion in order to quaff it while being attacked.\n\r", ch);
	    	return;
	    }
	}
    }
    WAIT_STATE(ch,4);
    act( "$n quaffs $p.", ch, obj, NULL, TO_ROOM );
    act( "You quaff $p.", ch, obj, NULL ,TO_CHAR );
    obj_cast_spell( obj->value[1], obj->value[0], ch, ch, NULL );
    obj_cast_spell( obj->value[2], obj->value[0], ch, ch, NULL );
    obj_cast_spell( obj->value[3], obj->value[0], ch, ch, NULL );
    extract_obj( obj );
}

void do_recite( CHAR_DATA *ch, char *argument )
{
  char arg1[MIL];
    CHAR_DATA *victim, *vch, *vch_next;
    OBJ_DATA *scroll, *obj;
    argument = one_argument( argument, arg1 );

    if ( ch->pCabal && IS_CABAL(get_parent(ch->pCabal), CABAL_NOMAGIC))
    {
        send_to_char("That is not how a Warlord should behave!\n\r", ch);
        return;
    }
    if ( ch->fighting != NULL )
    {
	send_to_char("You can't concentrate enough.",ch);
	return;
    }
    if ( (scroll = get_obj_carry( ch, arg1, ch ) ) == NULL )
    {
	send_to_char( "You do not have that scroll.\n\r", ch );
	return;
    }
    if ( scroll->item_type != ITEM_SCROLL )
    {
	send_to_char( "You can recite only scrolls.\n\r", ch );
	return;
    }
    if ( (!IS_NPC(ch) && ch->level < scroll->level) || (IS_NPC(ch) && get_trust(ch) < scroll->level) )
    {
        send_to_char("This scroll is too complex for you to comprehend.\n\r",ch);
	return;
    }
    obj = NULL;
    if ( IS_NULLSTR(argument))
      victim = ch;
    else if ( ( victim = get_char_room ( ch, NULL, argument ) ) == NULL 
	      && ( obj = get_obj_here( ch, NULL, argument ) ) == NULL )
      {
        send_to_char( "You can't find it.\n\r", ch );
        return;
    }
    target_name = argument;

    if (obj != NULL && CAN_WEAR(obj,ITEM_WEAR_TATTOO))
    {
	send_to_char( "You can't find it.\n\r",ch);
	return;
    }
    if ( ch->fighting != NULL )
    {
	bool found = FALSE;
	for ( vch = char_list; vch != NULL; vch = vch_next )
	{
	    vch_next = vch->next;
	    if (vch->fighting == ch)
	    {
		found = TRUE;
		continue;
	    }
	}
	if (found)
	{
	    send_to_char( "You cannot recite scrolls while being attacked.\n\r", ch);
	    return;
	}
    }
    if ( get_skill(ch,gsn_scrolls) == 0)
    {
	send_to_char("You do not possess the skill to use scrolls.\n\r",ch);
	return;
    }
    if (trip_traps(ch, scroll->traps))
      return;
    act( "$n recites $p.", ch, scroll, NULL, TO_ROOM );
    act( "You recite $p.", ch, scroll, NULL, TO_CHAR );
    WAIT_STATE(ch,8);
    if (number_percent() - (get_curr_stat(ch,STAT_LUCK)-16) >= 20 + get_skill(ch,gsn_scrolls) * 4/5)
    {
	send_to_char("You mispronounce a syllable.\n\r",ch);
	check_improve(ch,gsn_scrolls,FALSE, 20);
    }
    else
    {
    	obj_cast_spell( scroll->value[1], scroll->value[0], ch, victim, obj );
    	obj_cast_spell( scroll->value[2], scroll->value[0], ch, victim, obj );
    	obj_cast_spell( scroll->value[3], scroll->value[0], ch, victim, obj );
	check_improve(ch,gsn_scrolls,TRUE, 5);
    }
    extract_obj( scroll );
}

void do_brandish( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *vch, *vch_next;
    OBJ_DATA *staff, *obj;
    int sn;
    int chance = get_skill(ch,gsn_staves);

    if ( ch->pCabal && IS_CABAL(get_parent(ch->pCabal), CABAL_NOMAGIC))
    {
        send_to_char("You are not allowed to use magic!\n\r", ch);
        return;
    }
    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 >= MAX_SKILL || skill_table[sn].spell_fun == 0 )
    {
	bug( "Do_brandish: bad sn %d.", sn );
	return;
    }
    if (IS_OBJ_STAT(staff, ITEM_USE))
      chance = UMIN(3 * ch->level, 95);

    if ( chance == 0)
    {
	send_to_char("You do not possess the skill to use staves.\n\r",ch);
	return;
    }
    WAIT_STATE( ch, 18 );
    if (trip_traps(ch, staff->traps))
      return;
    if ( staff->value[2] > 0 || staff->value[2] == -1 )
    {
	act( "$n brandishes $p.", ch, staff, NULL, TO_ROOM );
	act( "You brandish $p.",  ch, staff, NULL, TO_CHAR );
        if ( ch->level < staff->level || number_percent() - (get_curr_stat(ch,STAT_LUCK)-16) >= 20 + chance * 4/5)
 	{
	    act ("You fail to invoke $p.",ch,staff,NULL,TO_CHAR);
	    act ("...and nothing happens.",ch,NULL,NULL,TO_ROOM);
	    check_improve(ch,gsn_staves,FALSE,20);
	}
	else for ( vch = ch->in_room->people; vch; vch = vch_next )
	{
	    vch_next	= vch->next_in_room;
	    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_same_group(ch,vch))
		    continue;
		if ( vch->pCabal && IS_CABAL(get_parent(vch->pCabal), CABAL_NOMAGIC))
		  continue;
		break;
	    case TAR_CHAR_SELF:
		if ( vch != ch )
		    continue;
		break;
	    case TAR_OBJ_INV:
	      if (IS_NULLSTR(argument)){
		send_to_char("Brandish on what?\n\r", ch);
		return;
	      }
	      else if ( (obj = get_obj_carry(ch, argument, ch)) == NULL){
		send_to_char("You do carry that.\n\r", ch);
		return;
	      }
	      obj_cast_spell( staff->value[3], staff->value[0], ch, NULL, obj );
	      check_improve(ch,gsn_staves,TRUE,5);	      
	      if ( staff->value[2] != -1 && --staff->value[2] <= 0 )
		{
		  act( "$n's $p blazes bright and is gone.", ch, staff, NULL, TO_ROOM );
		  act( "Your $p blazes bright and is gone.", ch, staff, NULL, TO_CHAR );
		  extract_obj( staff );
		}
	      return;
	    }
	    obj_cast_spell( staff->value[3], staff->value[0], ch, vch, NULL );
	    check_improve(ch,gsn_staves,TRUE,5);
	}
    }
    if ( staff->value[2] != -1 && --staff->value[2] <= 0 )
      {
	act( "$n's $p blazes bright and is gone.", ch, staff, NULL, TO_ROOM );
	act( "Your $p blazes bright and is gone.", ch, staff, NULL, TO_CHAR );
	extract_obj( staff );
      }
}

void do_use( CHAR_DATA *ch, char *argument ){
  char name[MIL];
  OBJ_DATA *wand;

  argument = one_argument( argument, name );
  if (IS_NULLSTR(name)){
    send_to_char("syntax: use <object> [target]\n\r", ch);
    return;
  }
  /*
    check in following order:
    - held item
    - worn item
    - item in room
  */
  if ( ( wand = get_eq_char( ch, WEAR_HOLD ) ) != NULL 
       && is_name(name, wand->name)){
/* TRAP check */
    if (trip_traps(ch, wand->traps))
      return;
    if ( wand->item_type == ITEM_WAND )
      do_zap(ch, argument);
    else if ( wand->item_type == ITEM_STAFF)
      do_brandish(ch, argument);
    else if ( wand && HAS_TRIGGER_OBJ( wand, TRIG_USE ) ){
      p_percent_trigger( NULL, wand, NULL, ch, NULL, NULL, TRIG_USE );
      WAIT_STATE2( ch, PULSE_VIOLENCE);
    }
    else
      send_to_char("This item cannot be used in such way.\n\r", ch);
    return;
  }
  /* check for worn object */
  if ( (wand = get_obj_wear( ch, name, ch )) != NULL){
    act("You attempt to use $p.", ch, wand, NULL, TO_CHAR);
    act("$n attempts to use $p.", ch, wand, NULL, TO_ROOM);
/* TRAP check */
    if (trip_traps(ch, wand->traps))
      return;
    if ( wand && HAS_TRIGGER_OBJ( wand, TRIG_USE ) )
      p_percent_trigger( NULL, wand, NULL, ch, NULL, NULL, TRIG_USE );
    WAIT_STATE2( ch, PULSE_VIOLENCE);
  }
  /* check room for object */
  else if ( (wand = get_obj_list( ch, name, ch->in_room->contents )) != NULL){
    act("You attempt to use $p.", ch, wand, NULL, TO_CHAR);
    act("$n attempts to use $p.", ch, wand, NULL, TO_ROOM);
/* TRAP check */
    if (trip_traps(ch, wand->traps))
      return;
    if ( wand && HAS_TRIGGER_OBJ( wand, TRIG_USE ) )
      p_percent_trigger( NULL, wand, NULL, ch, NULL, NULL, TRIG_USE );
    WAIT_STATE2( ch, PULSE_VIOLENCE);
  }
  else if ( (wand = get_obj_carry( ch, name, ch )) != NULL){
    send_to_char("You may only use objects that are worn or are on the ground.\n\r", ch);
    return;
  }
  else
    send_to_char("You don't see that here.\n\r", ch);
}

void do_zap( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    CHAR_DATA *victim;
    OBJ_DATA *wand, *obj;
    int chance = get_skill(ch, gsn_wands);
    argument = one_argument( argument, arg );

    if ( ch->pCabal && IS_CABAL(get_parent(ch->pCabal), CABAL_NOMAGIC))
    {
        send_to_char("You are not allowed to use magic!\n\r", ch);
        return;
    }
    if ( arg[0] == '\0' && ch->fighting == NULL )
    {
	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 != NULL )
	    victim = ch->fighting;
	else
	{
	    send_to_char( "Zap whom or what?\n\r", ch );
	    return;
	}
    }
    else if ( ( victim = get_char_room ( ch, NULL, arg ) ) == NULL && ( obj = get_obj_here( ch, NULL, arg ) ) == NULL )
    {
        send_to_char( "You can't find it.\n\r", ch );
        return;
    }
    if (IS_OBJ_STAT(wand, ITEM_USE))
      chance = UMIN(3 * ch->level, 95);

    if ( chance == 0)
    {
	send_to_char("You do not possess the skill to use wands.\n\r",ch);
	return;
    }
    WAIT_STATE( ch, PULSE_VIOLENCE / 2);
    if (trip_traps(ch, wand->traps))
      return;
    if ( wand->value[2] > 0  || wand->value[2] == -1 )
    {
	if ( victim != NULL )
	{
	    act( "$n zaps $N with $p.", ch, wand, victim, TO_NOTVICT );
	    act( "You zap $N with $p.", ch, wand, victim, TO_CHAR );
	    act( "$n zaps you with $p.",ch, wand, victim, TO_VICT );
	}
	else
	{
	    act( "$n zaps $P with $p.", ch, wand, obj, TO_ROOM );
	    act( "You zap $P with $p.", ch, wand, obj, TO_CHAR );
	}
        if (ch->level < wand->level || number_percent() - (get_curr_stat(ch,STAT_LUCK)-16) >= 20 + chance * 4/5) 
	{
            act( "Your efforts with $p produce only smoke and sparks.",ch,wand,NULL,TO_CHAR);
            act( "$n's efforts with $p produce only smoke and sparks.",ch,wand,NULL,TO_ROOM);
	    check_improve(ch,gsn_wands,FALSE, 20);
	}
	else
	{
	    obj_cast_spell( wand->value[3], wand->value[0], ch, victim, obj );
	    check_improve(ch,gsn_wands,TRUE,5);
	}
    }
    if ( wand->value[2] != -1 && --wand->value[2] <= 0 )
    {
	act( "$n's $p explodes into fragments.", ch, wand, NULL, TO_ROOM );
	act( "Your $p explodes into fragments.", ch, wand, NULL, TO_CHAR );
	extract_obj( wand );
    }
}

void do_steal( CHAR_DATA *ch, char *argument )
{
    char buf[MSL], arg1[MIL], arg2[MIL];
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    int percent;
    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    if ((percent = get_skill(ch,gsn_steal)) == 0)
    {
	send_to_char("You're in the wrong profession.\n\r",ch);
	return;
    }
    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "Steal what from whom?\n\r", ch );
	return;
    }
    if ( ( victim = get_char_room( ch, NULL, arg2 ) ) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }
    if ( IS_NPC(victim) && IS_SET(victim->act,ACT_TOO_BIG) )
    {
	sendf(ch, "%s is too alert for you to steal from them.\n\r", PERS2(victim));
	return;
    }
    if ( victim == ch )
    {
	send_to_char( "That's pointless.\n\r", ch );
	return;
    }
    if (is_safe(ch,victim))
	return;
    if (!IS_NPC(victim) && victim->level < 15)
    {
	send_to_char("Not that victim.\n\r", ch);
	return;
    }
    if (!IS_NPC(victim) && ch->level < 15)
    {
	send_to_char("Not at your stage.\n\r", ch);
	return;
    }
    if (victim->position == POS_FIGHTING)
    {
        send_to_char( "You'd better not -- you might get hit.\n\r",ch);
	return;
    }
    /* THEFT CRIME CHECK */
    if (ch->in_room && is_crime(ch->in_room, CRIME_THEFT, victim)){
      set_crime(ch, victim, ch->in_room->area, CRIME_THEFT);
    }
    if (IS_NPC(victim) && !IS_AWAKE(victim) && victim->pIndexData->pShop != NULL)
    {
	send_to_char( "Oops.\n\r", ch );
	act( "$n tried to steal from $N.\n\r",  ch, NULL, victim, TO_NOTVICT );
        victim->position = POS_STANDING;
        act("$n wakes up, $s face a mask of rage.",victim,NULL,NULL,TO_ROOM);
        sprintf( buf, "Keep your hands out of there, %s!", PERS(ch,victim));
	REMOVE_BIT(victim->comm,COMM_NOCHANNELS);
	REMOVE_BIT(victim->comm,COMM_NOYELL);
	j_yell(victim,buf);
	SET_BIT(victim->comm,COMM_NOYELL);
	SET_BIT(victim->comm,COMM_NOCHANNELS);
	multi_hit(victim,ch,TYPE_UNDEFINED);
    	return;
    }
    WAIT_STATE( ch, skill_table[gsn_steal].beats );
    percent = 3 * percent /4;
    if (!IS_AWAKE(victim))
      percent = 100;
    else if (!can_see(victim,ch))
      percent += 15;
    percent += 2*(get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));
    if (is_affected(victim, gen_watchtower)){
      sendf( ch, "%s is shielded within the Watchtower.\n\r", PERS(victim, ch ));
      sendf( victim, "%s just tried to steal from you.\n\r", PERS2(ch));
      percent = 0;
    }

    if ( (ch->level + 8 < victim->level ) || ( !IS_NPC(ch) && number_percent() > percent) )
      {
	send_to_char( "Oops.\n\r", ch );
	do_visible(ch, "");
	act( "$n tried to steal from you.\n\r", ch, NULL, victim, TO_VICT    );
	act( "$n tried to steal from $N.\n\r",  ch, NULL, victim, TO_NOTVICT );
	switch(number_range(0,3)){
	case 0 :
	  sprintf( buf, "%s is a lousy thief!", PERS(ch,victim));
	  break;
        case 1 :
	  sprintf( buf, "%s couldn't rob %s way out of a paper bag!",PERS(ch,victim),(ch->sex == 2) ? "her" : "his");
	  break;
	case 2 :
	  sprintf( buf,"%s tried to rob me!",PERS(ch,victim));
	  break;
	case 3 :
	  sprintf(buf,"Keep your hands out of there, %s!",PERS(ch,victim));
	  break;
        }
	if (IS_AWAKE(victim)){
	  if (IS_NPC(victim)){
	    REMOVE_BIT(victim->comm,COMM_NOCHANNELS);
	    REMOVE_BIT(victim->comm,COMM_NOYELL);
	    j_yell(victim,buf);
	    SET_BIT(victim->comm,COMM_NOYELL);
	    SET_BIT(victim->comm,COMM_NOCHANNELS);
	  }	    
	  else
	    j_yell(victim, buf );
	}
	if ( !IS_NPC(ch) ){
	  if ( IS_NPC(victim) ){
	    check_improve(ch,gsn_steal,FALSE,2);
	    do_murder(victim, ch->name);
	  }
	  else{
	    sprintf(buf,"$N tried to steal from %s.",victim->name);
	    wiznet(buf,ch,NULL,WIZ_FLAGS,0,0);
	  }
	}
	if (!IS_NPC(victim))
	  set_delay(ch,victim);
	return;
      }
    set_delay(ch,NULL);
    if ( !str_cmp( arg1, "coin"  ) || !str_cmp( arg1, "coins" ) || !str_cmp( arg1, "gold"  ) )
      {
        int amount;
        amount = victim->gold * number_range(1, ch->level) / 100;
        if ( amount <= 0 )
	  {
            send_to_char( "You couldn't get any gold.\n\r", ch );
	    return;
	  }
        ch->gold        += amount;
        victim->gold    -= amount;
        sendf( ch, "Bingo!  You got %d gold coins.\n\r",amount);
	check_improve(ch,gsn_steal,TRUE,2);
	return;
      }
    if ( ( obj = get_obj_carry( victim, arg1, ch ) ) == NULL )
      {
	send_to_char( "You can't find it.\n\r", ch );
	return;
      }
    if ( !can_drop_obj( ch, obj ) || IS_SET(obj->extra_flags, ITEM_INVENTORY) )
    {
	send_to_char( "You can't pry it away.\n\r", ch );
	return;
    }
    if ( ch->carry_number + get_obj_number( obj ) > can_carry_n( ch ) )
    {
	send_to_char( "You have your hands full.\n\r", ch );
	return;
    }
    if ( ch->carry_weight + get_obj_weight_char(ch, obj ) > can_carry_w( ch ) )
    {
	send_to_char( "You can't carry that much weight.\n\r", ch );
	return;
    }
    obj_from_char( obj );
    obj_to_char( obj, ch );
    check_improve(ch,gsn_steal,TRUE,2);
    send_to_char( "Got it!\n\r", ch );
}

void do_request( CHAR_DATA *ch, char *argument )
{
    char buf [MSL];
    char arg1 [MIL], arg2 [MIL];
    CHAR_DATA *victim;
    AFFECT_DATA af;
    AFFECT_DATA* paf;

    /* 
LAG TIME:
the const. are base amounts, beyond that we add +1 for each 3 level above ch or
- 1 for each level below.
    */

//const    
    const int reg_lag = 2;
    const int rare_lag = 4;
    const int uniq_lag = 6;
    const int high_mod = 3;//divisor for positive elvel dif.
    const int low_mod = 10;//divisor for negative level diff.
//data
    int lag_time = 0;
    int level_dif = 0;

    OBJ_DATA *obj, *obj2;
    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    if (IS_NPC(ch))
	return;
    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "Request what from whom?\n\r", ch );
	return;
    }
    if ( ( victim = get_char_room( ch, NULL, arg2 ) ) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }
    if ( victim == ch )
    {
	send_to_char( "That's pointless.\n\r", ch );
	return;
    }
    if (!IS_NPC(victim))
    {
	send_to_char("Why don't you just try asking.\n\r",ch);
	return;
    }

    if (victim->position == POS_FIGHTING)
    {
	sendf(ch, "%s is a bit occupied at the moment.\n\r", PERS2(victim));
	return;
    }
    if (!IS_AWAKE(victim))
    {
	sendf(ch, "%s is asleep right now.\n\r", PERS2(victim));
	return;
    }
    act("$n attempts to request from $N.",ch,NULL,victim,TO_ROOM);
    if (!can_see(victim,ch))
    {
	do_say(victim, "Eh?  Who's there?");
	return;
    }
    WAIT_STATE(ch, 12);
    if (!IS_GOOD(victim))
    {
	do_say(victim,"I'm not about to give you anything!");
	return;
    }
    if (!IS_GOOD(ch))
    {
	do_say(victim, "I won't give anything to someone so impure.");
	return;
    }
    if (ch->hit < 3 * (ch->level / 2) || ch->move < (50 + ch->level))
    {
	do_say(victim, "You look a bit tired, why don't you rest for a while.");
	return;
    }
    if ( (ch->level + 9 < victim->level && ch->level < 50) || victim->level >= ch->level *2) 
    {
	do_say(victim, "In due time my child.");
	return;
    }
    //check for item on char.    

    if ( ( obj = get_obj_wear( victim, arg1, victim) ) == NULL)
    {

      if   ( ( obj = get_obj_carry(victim, arg1, ch)) == NULL)
	{
	  do_say(victim, "Sorry, I'm afraid I don't have that item.");
	  return; 
	}
    }
    if (IS_NPC(victim) && victim->pIndexData->pShop != NULL
	&& IS_OBJ_STAT(obj,ITEM_INVENTORY)){
      do_say(victim, "You will have to buy it from me.");
      return;
    }
    if ( ch->carry_number + get_obj_number( obj ) > can_carry_n( ch ) )
    {
	do_say(victim, "Your hands are full.");
	return;
    }
    if ( ch->carry_weight + get_obj_weight_char(ch, obj ) > can_carry_w( ch ) )
    {
	do_say(victim, "You are carrying too much weight.");
	return;
    }
    if (!can_see_obj(ch, obj))
    {
	do_say(victim, "But you can't see it!");
	return;
    }
    if (CAN_WEAR(obj, ITEM_UNIQUE) || CAN_WEAR(obj, ITEM_RARE)){
      if (obj->wear_loc != WEAR_NONE)
	unequip_char(victim, obj);
      obj2 = obj;
    }
    else
      obj2 = create_object( obj->pIndexData, obj->level );

    act("$N places $p on the ground before $n and mutters a blessing.",ch,obj2,victim,TO_ROOM);
    act("$N places $p on the ground before you and blesses it.",ch,obj2,victim,TO_CHAR);
    sprintf(buf, "May %s find you worthy of my gift.", (ch->pcdata->deity[0] == '\0'? "The One God": ch->pcdata->deity));

    do_say(victim, buf);

    //we set the owner, including the deity.
    set_owner(ch, obj2, ch->pcdata->deity);

    //calculate the base lag
    if (CAN_WEAR(obj2, ITEM_UNIQUE))
      lag_time = uniq_lag;
    else if (CAN_WEAR(obj2, ITEM_RARE))
      lag_time = rare_lag;
    else
      lag_time = reg_lag;
    //include factores for lvl diff.

    level_dif = victim->level - ch->level;
    lag_time += (level_dif > 0? level_dif / high_mod : level_dif / low_mod);

    //we set the request gen on the character.
    af.type = gen_request;
    af.where = TO_NONE;
    af.location = APPLY_NONE;
    af.modifier = 0;
    af.duration = UMAX(0, lag_time);
    af.level = victim->level;
    af.bitvector = 0;


    //now we set tings on the bitvector if needed.
    if (obj2->timer > 0)
      {
	af.level = obj2->timer;
	SET_BIT(af.bitvector, ITEM_HAD_TIMER);
      }
    /* Not needed : Viri
    else
      obj2->timer = lag_time * 2;
    */

    if (CAN_WEAR(obj2, ITEM_NO_SAC))
      SET_BIT(af.bitvector, ITEM_NO_SAC);
    else
      SET_BIT(obj2->wear_flags, ITEM_NO_SAC);

    //now we begin request on character.
    paf = affect_to_char(ch, &af);
    //and we enter the name of obj2,
    if (paf != NULL)
      string_to_affect(paf, obj2->name);

    if (obj2->carried_by){
      obj_from_char( obj2 );
    }
      obj_to_room( obj2, ch->in_room );
}

CHAR_DATA *find_keeper( CHAR_DATA *ch )
{
    char buf[MSL];
    CHAR_DATA *keeper;
    SHOP_DATA *pShop;
    pShop = NULL;
    for ( keeper = ch->in_room->people; keeper; keeper = keeper->next_in_room )
	if ( IS_NPC(keeper) && IS_AWAKE(keeper) && (pShop = keeper->pIndexData->pShop) != NULL)
	    break;
    if ( pShop == NULL )
    {
	send_to_char( "You can't do that here.\n\r", ch );
	return NULL;
    }
    if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_WANTED) 
	 && keeper->in_room && IS_SET(keeper->in_room->area->area_flags, AREA_LAWFUL)
	 && !is_same_cabal(keeper->pCabal, ch->pCabal))
    {
      if (guard_fade_check(ch))
	send_to_char("You manage to fade into shadows and avoid detection.\n\r", ch);
      else{
	sprintf(buf,"Criminals are not welcome!" );
        do_say( keeper, buf);
        sprintf( buf, "%s the criminal is over here!\n\r", ch->name );
        REMOVE_BIT(keeper->comm,COMM_NOYELL);
	j_yell( keeper, buf );
        SET_BIT(keeper->comm,COMM_NOYELL);
	return NULL;
      }
    }
    if ( mud_data.time_info.hour < pShop->open_hour )
    {
	if (IS_AWAKE(keeper))
	{
	    sprintf(buf, "Sorry, I am closed. Come back later." );
	    do_say( keeper,buf); 
	}
	return NULL;
    }
    if ( mud_data.time_info.hour > pShop->close_hour )
    {
	if (IS_AWAKE(keeper))
	{
	    sprintf(buf,"Sorry, I am closed. Come back tomorrow." );
	    do_say( keeper, buf);
	}
	return NULL;
    }
    if ( !can_see( keeper, ch ) && !IS_IMMORTAL(ch))
    {
	sprintf(buf,"I don't trade with folks I can't see." );
	do_say( keeper, buf);
	return NULL;
    }
    return keeper;
}

CHAR_DATA *find_history( CHAR_DATA *ch )
{
    char buf[MSL];
    CHAR_DATA *keeper;
    for ( keeper = ch->in_room->people; keeper; keeper = keeper->next_in_room )
	if ( IS_NPC(keeper) && IS_AWAKE(keeper) && IS_SET(keeper->act2,ACT_HISTORY))
	    break;
    if ( keeper == NULL )
    {
	send_to_char( "You can't do that here.\n\r", ch );
	return NULL;
    }
    if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_WANTED) 
	 && !is_same_cabal(keeper->pCabal,ch->pCabal) )
    {
      if (guard_fade_check(ch))
	send_to_char("You manage to fade into shadows and avoid detection.\n\r", ch);
      else{
	sprintf( buf,"Criminals are not welcome!" );
        do_say( keeper, buf);
        sprintf( buf, "%s the criminal is over here!\n\r", ch->name );
        REMOVE_BIT(keeper->comm,COMM_NOYELL);
	j_yell( keeper, buf );
        SET_BIT(keeper->comm,COMM_NOYELL);
	return NULL;
      }
    }
    if ( !can_see( keeper, ch ) && !IS_IMMORTAL(ch))
    {
	sprintf(buf,"I don't talk to folks I can't see." );
	do_say( keeper, buf);
	return NULL;
    }
    return keeper;
}

void obj_to_keeper( OBJ_DATA *obj, CHAR_DATA *ch )
{
    OBJ_DATA *t_obj, *t_obj_next;
    for (t_obj = ch->carrying; t_obj != NULL; t_obj = t_obj_next)
    {
	t_obj_next = t_obj->next_content;
	if (obj->pIndexData == t_obj->pIndexData && !str_cmp(obj->short_descr,t_obj->short_descr))
	{
	    if (IS_OBJ_STAT(t_obj,ITEM_INVENTORY))
	    {
		extract_obj(obj);
		return;
	    }
            obj->cost = t_obj->cost;
	    break;
	}
    }
    if (t_obj == NULL)
    {
	obj->next_content = ch->carrying;
	ch->carrying = obj;
    }
    else
    {
	obj->next_content = t_obj->next_content;
	t_obj->next_content = obj;
    }
    obj->carried_by      = ch;
    obj->in_room         = NULL;
    obj->in_obj          = NULL;
    if (obj->vnum != OBJ_VNUM_LOCKER){
      ch->carry_number    += get_obj_number( obj );
      ch->carry_weight    += get_obj_weight_char(ch, obj );
    }
}

OBJ_DATA *get_obj_keeper( CHAR_DATA *ch, CHAR_DATA *keeper, char *argument)
{
    char arg[MIL];
    OBJ_DATA *obj;
    int number = number_argument( argument, arg ), count = 0;

    for ( obj = keeper->carrying; obj != NULL; obj = obj->next_content )
        if (obj->wear_loc == WEAR_NONE 
	    && can_see_obj( keeper, obj ) 
	    && can_see_obj(ch,obj) 
	    && (is_name(arg, obj->name) || is_auto_name( arg, obj->name )) ){
	  if ( ++count == number )
	    return obj;
	  while (obj->next_content != NULL 
		 && obj->pIndexData == obj->next_content->pIndexData
		 && !str_cmp(obj->short_descr,obj->next_content->short_descr))
	    obj = obj->next_content;
        }
    return NULL;
}

int get_cost( CHAR_DATA *keeper, OBJ_DATA *obj, bool fBuy )
{
    SHOP_DATA *pShop;
    int cost = 0;
    if ( obj == NULL || ( pShop = keeper->pIndexData->pShop ) == NULL )
	return 0;
    if ( fBuy ){
	cost = obj->cost * pShop->profit_buy  / 100;
	/* Global Cabal modification */
	if (keeper->group)
	  cost = UMAX(1, CABAL_PROFIT * cost / 100);
    }
    else
    {
	OBJ_DATA *obj2;
	int itype;
	for ( itype = 0; itype < MAX_TRADE; itype++ )
	    if ( obj->item_type == pShop->buy_type[itype] )
	    {
		cost = obj->cost * pShop->profit_sell / 100;
		break;
	    }
	if (!IS_OBJ_STAT(obj,ITEM_SELL_EXTRACT))
	    for ( obj2 = keeper->carrying; obj2; obj2 = obj2->next_content )
	    	if ( obj->pIndexData == obj2->pIndexData && !str_cmp(obj->short_descr,obj2->short_descr) )
                {
	 	    if (IS_OBJ_STAT(obj2,ITEM_INVENTORY))
			cost /= 2;
		    else
                    	cost = cost * 3 / 4;
                }
	/* cant sell cabal items */
	if (obj->pIndexData->pCabal)
	  return 0 ;
    }
    if ( obj->item_type == ITEM_STAFF || obj->item_type == ITEM_WAND )
    {
	if (obj->value[1] == 0)
	    cost /= 4;
	else
	    cost = cost * obj->value[2] / obj->value[1];
    }
    return cost;
}

void pet_shop(CHAR_DATA *ch, char *argument ){
  char arg[MIL], buf[MIL];
  CHAR_DATA *pet;
  ROOM_INDEX_DATA *pRoomIndexNext, *in_room;
  int cost;
  int roll = number_percent();

  if ( IS_NPC(ch) )
    return;
  else if (is_exiled(ch, ch->in_room->area->vnum )){
    char buf[MIL];
      sprintf( buf, "No one will deal with you in %s!", ch->in_room->area->name);
      send_to_char(buf, ch );
      return;
  }
  argument = one_argument(argument,arg);
  if (ch->in_room->vnum == 9621)
    pRoomIndexNext = get_room_index(9706);
  else
    pRoomIndexNext = get_room_index( ch->in_room->vnum + 1 );
  if ( pRoomIndexNext == NULL )
    {
      bug( "Do_buy: bad pet shop at vnum %d.", ch->in_room->vnum );
      send_to_char( "Sorry, you can't buy that here.\n\r", ch );
      return;
    }
  in_room     = ch->in_room;
  ch->in_room = pRoomIndexNext;
  pet         = get_char_room( ch, NULL, arg );
  ch->in_room = in_room;
  if ( pet == NULL || !IS_SET(pet->act, ACT_PET) )
    {
      send_to_char( "Sorry, you can't buy that here.\n\r", ch );
      return;
    }
  if ( ch->pet != NULL )
    {
      send_to_char("You already own a pet.\n\r",ch);
      return;
    }
  
  if (ch->pcdata->familiar)
    {
	act("You already have $N as a personal follower.\n\r", ch, NULL, ch->pcdata->familiar, TO_CHAR);
	return;
    }
  
    cost = 10 * pet->level * pet->level;
    if ( ch->gold < cost )
      {
	send_to_char( "You can't afford it.\n\r", ch );
	return;
      }
    if ( ch->level < pet->level )
      {
	send_to_char("You're not powerful enough to master this pet.\n\r", ch );
	return;
      }
    if (get_charmed_by(ch) >= 3)
      {
	send_to_char("Are you sure you need a whole army at your command?\n\r", ch);
	return;
      }
    if (roll < get_skill(ch,gsn_haggle))
      {
	cost = cost / 2 + (cost * roll / 200);
	sendf(ch, "You haggle the price down to %d coins.\n\r",cost);
	check_improve(ch,gsn_haggle,TRUE,1);
      }
    ch->gold           -= cost;
    pet			= create_mobile( pet->pIndexData );
    SET_BIT(pet->act, ACT_PET);
    SET_BIT(pet->affected_by, AFF_CHARM);
    pet->comm = COMM_NOTELL|COMM_NOYELL|COMM_NOCHANNELS;
    sprintf( buf, "%sA neck tag says 'I belong to %s'.\n\r", pet->description, ch->name );
    free_string( pet->description );
    pet->description = str_dup( buf );
    char_to_room( pet, ch->in_room );
    add_follower( pet, ch );
    pet->leader = ch;
    pet->summoner = ch;
    ch->pet = pet;
    send_to_char( "Enjoy your pet.\n\r", ch );
    act( "$n bought $N as a pet.", ch, NULL, pet, TO_ROOM );
}

void do_sell( CHAR_DATA *ch, char *argument ){
  char buf[MSL], arg[MIL];
  CHAR_DATA *keeper;
  OBJ_DATA *obj;
  int cost, roll = number_percent();
  one_argument( argument, arg );

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

    if ( ( keeper = find_keeper( ch ) ) == NULL )
      return;
    else if (is_exiled(ch, keeper->in_room->area->vnum )){
      char buf[MIL];
      sprintf( buf, "No one in %s will deal with you %s!", keeper->in_room->area->name, PERS2(ch));
      do_say( keeper, buf );
      return;
    }
    else if ( keeper->pCabal && !_is_cabal( ch->pCabal, keeper->pCabal )){
      char buf[MIL];
      sprintf( buf, "You must be a member of %s`# to shop here %s.", keeper->pCabal->who_name, PERS2( ch ));
      do_say( keeper, buf );
      return;
    }

    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL ){
      sendf(ch, "%s tells you '`2You don't have that item.``'\n\r", PERS(keeper,ch));
      return;
    }
    else if ( !can_drop_obj( ch, obj ) ){
      send_to_char( "You can't let go of it.\n\r", ch );
      return;
    }
    else if (!can_see_obj(keeper,obj)){
      sendf(ch, "%s doesn't see what you are offering.\n\r",PERS(keeper,ch));
      return;
    }
    else if (IS_LIMITED(obj) || IS_SET(obj->wear_flags, ITEM_HAS_OWNER)){
      sendf(ch, "%s tells you '`2I am not worthy to own such a powerful item.``'\n\r", PERS(keeper,ch));
      return;
    }
    else if ( ( cost = get_cost( keeper, obj, FALSE ) ) <= 0 ){
      act( "$n looks uninterested in $p.", keeper, obj, ch, TO_VICT );
      return;
    }
    else if ( cost > keeper->gold ){
      act( "$n tells you '`2I'm afraid I don't have enough gold to buy $p.``'", keeper,obj,ch,TO_VICT);
      return;
    }
    roll -= 2 * (get_curr_stat(ch,STAT_LUCK) - 14);
    if (is_song_affected(ch,gsn_reputation))
      roll -= 20;
    roll = UMAX(1,roll);
    act( "$n sells $p.", ch, obj, NULL, TO_ROOM );

    if (!IS_OBJ_STAT(obj,ITEM_SELL_EXTRACT) 
	&& roll < get_skill(ch,gsn_haggle)){
      send_to_char("You haggle with the shopkeeper for a better price.\n\r",ch);
      int haggle_cost = UMAX(0, roll * (obj->cost - cost) / 100);
      cost += haggle_cost;
      cost = UMIN(cost, keeper->gold);
      check_improve(ch,gsn_haggle,TRUE,0);
    }
    sprintf( buf, "You sell $p for %d gold piece%s.", cost, cost == 1 ? "" : "s" );
    act( buf, ch, obj, NULL, TO_CHAR );
    if (ch->class == class_lookup("monk") && (ch->gold + cost) > 20000 && cost > 0)
      {
	int overflow = UMAX(1,ch->gold + cost - 20000);
	ch->gold = 20000;
        send_to_char("You can't hold that much gold and drop it.\n\r",ch);
	act( "$n drops some gold.", ch, NULL, NULL, TO_ROOM );
	obj_to_room( create_money( overflow ), ch->in_room );
      }
    else
      ch->gold     += cost;
    keeper->gold -= cost;
    if ( keeper->gold < 0 )
      keeper->gold = 0;
    if ( obj->item_type == ITEM_TRASH || IS_OBJ_STAT(obj,ITEM_SELL_EXTRACT))
      extract_obj( obj );
    else
      {
	obj_from_char( obj );
	if (obj->timer)
	  SET_BIT(obj->extra_flags,ITEM_HAD_TIMER);
	else
	  obj->timer = number_range(50,100);
	obj_to_keeper( obj, keeper );
      }
}


void do_buy( CHAR_DATA *ch, char *argument ){
  CHAR_DATA *keeper;
  OBJ_DATA *obj, *tobj;
  char buf[MIL], *item, buf1[MIL], buf2[MIL];
  int cost, roll, extort_chance, i;
  int amount;
  
  item = one_argument( argument, buf );

  if ( IS_NULLSTR(buf)){
    send_to_char( "Buy what or how many of what item?\n\r", ch );
    return;
  }
  else if ( (amount = atoi(buf)) > 0){
    argument = item;
  }
  else
    amount = 1;

  /* get haggle roll */
  roll = number_percent();
  roll -= 2* ( get_curr_stat(ch,STAT_LUCK) - 14 );
    
  if (!IS_NULLSTR(mud_data.questor) 
      && mud_data.questor[0] ==  ch->name[0] 
      && !str_cmp( ch->name, mud_data.questor))
    roll -= 50;
  else if(is_song_affected(ch,gsn_reputation))
    roll -= 20;

  roll = UMAX(1, roll);

  /* PET SHOP */    
  if ( IS_SET(ch->in_room->room_flags, ROOM_PET_SHOP) ){
    pet_shop( ch, argument );
    return;
  }
  /* NORMAL ITEMS */
  if ( ( keeper = find_keeper( ch ) ) == NULL )
    return;
  else if (is_exiled(ch, keeper->in_room->area->vnum )){
    char buf[MIL];
    sprintf( buf, "No one in %s will deal with you %s!", keeper->in_room->area->name, PERS2(ch));
    do_say( keeper, buf );
    return;
  }
  /* CABAL CHECK */
  if ( keeper->pCabal && !_is_cabal( ch->pCabal, keeper->pCabal )){
    char buf[MIL];
    sprintf( buf, "You must be a member of %s`# to shop here %s.", keeper->pCabal->who_name, PERS2( ch ));
    do_say( keeper, buf );
    return;
  }

  if ( (obj  = get_obj_keeper( ch, keeper, argument )) == NULL){
    sendf(ch, "%s tells you '`2I don't sell that -- try 'list'.``'\n\r",PERS(keeper,ch));
    return;
  }
  /* count if we have enough objects in case of non-reset items*/
  if (!IS_SET( obj->extra_flags, ITEM_INVENTORY ) ){
    int counter = 0;
    for (tobj = keeper->carrying; tobj; tobj = tobj->next_content){
      if (tobj->pIndexData == obj->pIndexData)
	counter++;
    }
    amount = UMIN(amount, counter);
  }

  cost = amount * get_cost( keeper, obj, TRUE );

  if ( cost <= 0 || !can_see_obj( ch, obj ) ){
    sendf(ch, "%s tells you '`2I don't sell that -- try 'list'.``'\n\r",PERS(keeper,ch));
    return;
  }
  else if ( obj->level > ch->level ){
    act( "$n tells you '`2You can't use $p yet.``'", keeper, obj, ch, TO_VICT );
    return;
  }
  else if (ch->carry_number + amount * get_obj_number(obj) > can_carry_n(ch)){
    int num = can_carry_n(ch) - ch->carry_number;
    if (num == 0)
      send_to_char( "You can't carry any more items.\n\r", ch );
    else
      sendf(ch, "You can carry only %d more items.\n\r", num);
    return;
  }
  else if ( ch->carry_weight + amount * get_obj_weight_char(ch, obj) > can_carry_w(ch)){
    int num = (can_carry_w( ch ) - ch->carry_weight) / UMAX(1, get_obj_weight_char( ch, obj ));
    if (num == 0)
      send_to_char( "You lack the strength to hold more of these items.\n\r", ch );
    else
      sendf(ch, "You only have the strength to carry %d more.\n\r", num);
    return;
  }
  /* TEST FOR COST */
  else if ((obj->pIndexData->pCabal? GET_CP(ch) :  ch->gold) < cost ){
    sprintf( buf, "$n tells you '`2You can't afford %d %s%s to buy $p.``'",
	     cost, 
	     obj->pIndexData->pCabal ? obj->pIndexData->pCabal->currency: "gold",
	     obj->pIndexData->pCabal ? "s": "");
    act( buf, keeper, obj, ch, TO_VICT );
    return;
  }
  /* Cant extort/haggle cabal items */
  extort_chance = get_skill(ch,gsn_extort);
  extort_chance = extort_chance / UMAX(3, cost / (ch->level * 8 * amount));

  if (!obj->pIndexData->pCabal && roll < extort_chance){
    cost = 0;
    act( "You intimidate $N into handing over $p.",ch,obj,keeper,TO_CHAR);
    act( "$n intimidates $N with $s threats.",ch,NULL,keeper,TO_ROOM);
    check_improve(ch,gsn_extort,TRUE,1);
    act( "$n extorts $p from $N.", ch, obj, keeper, TO_ROOM );
    act( "You extort $p from $N.", ch, obj, keeper, TO_CHAR );
  }	    
  else {
    if (!IS_OBJ_STAT(obj,ITEM_SELL_EXTRACT) 
	&& roll < get_skill(ch,gsn_haggle)
	&& !obj->pCabal){
      int sell_cost = amount * get_cost(keeper, obj, FALSE);
      int save = UMAX(0, roll * (cost - sell_cost ) / 100);

      cost -= save;
      sendf(ch,"You haggle the price down to %d coins.\n\r",cost);
      check_improve(ch,gsn_haggle,TRUE,1);
    }

    if (amount > 1){
      sprintf( buf, "%s", obj->short_descr );
      item = strchr( buf, ' ');

      if (item){
	*item++ = 0;
	if (str_cmp(buf, "a") && str_cmp(buf, "an") && str_cmp(buf, "the") )
	  item = buf;
      }
      else
	item = buf;
      sprintf( buf1, "You buy %d $ts.", amount );
      sprintf( buf2, "$n buys %d $ts.", amount );
      
    }
    else{
      item = obj->short_descr;
      sprintf( buf1, "You buy $t." );
      sprintf( buf2, "$n buys $t." );
    }
    act( buf1 , ch, item, NULL, TO_CHAR );
    act( buf2, ch, item, NULL, TO_ROOM );
  }
  if (obj->pIndexData->pCabal)
    CP_GAIN(ch, -cost, TRUE);
  else{
    ch->gold     -= cost;
    keeper->gold += cost;
  }
  for (i = 0; i < amount; i++){
    if ( IS_SET( obj->extra_flags, ITEM_INVENTORY ) )
      tobj = create_object( obj->pIndexData, obj->level);
    else if ( (tobj = get_obj_keeper( ch, keeper, obj->name )) != NULL)
      obj_from_char( tobj );
    else
      continue;

    if (tobj->timer > 0 
	&& !IS_OBJ_STAT(tobj,ITEM_HAD_TIMER) 
	&& tobj->item_type != ITEM_FOOD)
      tobj->timer = 0;
    REMOVE_BIT(tobj->extra_flags,ITEM_HAD_TIMER);
    obj_to_char( tobj, ch );
    if (cost / amount < tobj->cost)
      tobj->cost = cost / amount;
  }
}



void do_browse( CHAR_DATA *ch, char *argument ){
  CHAR_DATA *keeper;
  OBJ_DATA *obj;
  char buf[MIL];

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

  /* PET SHOP */    
  if ( IS_SET(ch->in_room->room_flags, ROOM_PET_SHOP) ){
    send_to_char("There is nothing to gain by browsing pets.\n\r", ch);
    return;
  }
  if ( ( keeper = find_keeper( ch ) ) == NULL )
    return;
  /* NORMAL ITEMS */
  if ( keeper->pCabal && !_is_cabal( ch->pCabal, keeper->pCabal )){
    char buf[MIL];
    sprintf( buf, "You must be a member of %s`# to shop here %s.", keeper->pCabal->who_name, PERS2( ch ));
    do_say( keeper, buf );
    return;
  }

  /* get the object we are talking about*/
  obj  = get_obj_keeper( ch, keeper, argument );

  if (!obj || !can_see_obj( ch, obj ) ){
    sendf(ch, "%s tells you '`2I don't sell that -- try 'list'.``'\n\r",PERS(keeper,ch));
    ch->reply = keeper;
    return;
  }
  
  obj = create_object( obj->pIndexData, obj->level);
  obj_to_ch( obj, ch );
  strcpy (buf, obj->name);

  /* check which skill to use */
    if (get_skill(ch, gsn_identify) > 1){
      send_to_char("You try to identify it..\n\r", ch);
      spell_identify(gsn_identify, ch->level, ch, obj, 0);
    }
    else if (get_skill(ch, skill_lookup("lore")) > 1){
      do_lore(ch, buf);
    }
    else{
      do_examine(ch, buf);
    }

    if (obj){
      obj_from_char( obj );
      extract_obj( obj );
    }
    
}

void do_list( CHAR_DATA *ch, char *argument )
{
    /* used for sorting */
    const int MAX_ITEM = 256;
    char list[MAX_ITEM] [MIL];
    int key[MAX_ITEM];
    int end_key[MAX_ITEM];
    int last = 0;
    int i, j;

    /* SHOP */
    if ( IS_SET(ch->in_room->room_flags, ROOM_PET_SHOP) )
    {
	ROOM_INDEX_DATA *pRoomIndexNext;
	CHAR_DATA *pet;
	bool found = FALSE;
        if (ch->in_room->vnum == 9621)
            pRoomIndexNext = get_room_index(9706);
        else
            pRoomIndexNext = get_room_index( ch->in_room->vnum + 1 );
	if ( pRoomIndexNext == NULL )
	{
	    bug( "Do_list: bad pet shop at vnum %d.", ch->in_room->vnum );
	    send_to_char( "You can't do that here.\n\r", ch );
	    return;
	}
	for ( pet = pRoomIndexNext->people; pet; pet = pet->next_in_room ){
	  if ( IS_SET(pet->act, ACT_PET) ){
	    if ( !found ){
	      found = TRUE;
	      send_to_char( "Pets for sale:\n\r", ch );
	    }

	    sprintf( list[last], "[%2d] %8d - %s\n\r", 
		     pet->level, 10 * pet->level * pet->level, 
		     pet->short_descr );
	    key[last++] = 10 * pet->level * pet->level;
	    if (last >= MAX_ITEM)
	      last = MAX_ITEM - 1;
	  }
	}
	if ( !found )
	  send_to_char( "Sorry, we're out of pets right now.\n\r", ch );
    }
    else{
      CHAR_DATA *keeper;
      OBJ_DATA *obj;
      int cost, count;
      bool found = FALSE;
      char arg[MIL];
      if ( ( keeper = find_keeper( ch ) ) == NULL )
	return;

      if ( keeper->pCabal && !_is_cabal( ch->pCabal, keeper->pCabal )){
	char buf[MIL];
	sprintf( buf, "You must be a member of %s`# to shop here %s.", keeper->pCabal->who_name, PERS2( ch ));
	do_say( keeper, buf );
	return;
      }
      
      one_argument(argument,arg);
      for ( obj = keeper->carrying; obj; obj = obj->next_content ){
	if ( obj->wear_loc == WEAR_NONE && can_see_obj( ch, obj )
	     && ( cost = get_cost( keeper, obj, TRUE ) ) > 0 && ( arg[0] == '\0' || is_name(arg,obj->name) )){
	  if ( !found ){
	    found = TRUE;
	    sendf( ch, "[Lv Price Coin Qty] Item\n\r");
	  }
	  if (IS_OBJ_STAT(obj,ITEM_INVENTORY)){
	    sprintf(list[last], "[%2d %5d %s  -- ] %s\n\r", 
		    obj->level,
		    cost,
		    (obj->pIndexData->pCabal? " CP" : " GO"),
		    obj->short_descr);
	    key[last++] = cost;
	    if (last >= MAX_ITEM)
	      last = MAX_ITEM - 1;
	  }
	  else{
	    count = 1;
	    while (obj->next_content != NULL && obj->pIndexData == obj->next_content->pIndexData
		   && !str_cmp(obj->short_descr, obj->next_content->short_descr))
	      {
		obj = obj->next_content;
		count++;
	      }
	    sprintf(list[last], "[%2d %5d %s  %2d ] %s\n\r", 
		    obj->level,
		    cost,
		    (obj->pIndexData->pCabal? " Cp" : " Go"),
		    count,
		    obj->short_descr);
	    key[last++] = cost;
	    if (last >= MAX_ITEM)
	      last = MAX_ITEM - 1;
	  }
	}
      }
      if ( !found )
	send_to_char( "You can't buy anything here.\n\r", ch );
    }
/* prepare endkey for sorting */
    for (i = 0; i < last; i++)
      end_key[i] = i;
/* sort the list with good ole bubble sort */
    for (i = 0; i < last; i ++){
      for (j = 0; j < last - 1; j++){
	if (key[j] < key[j + 1]){
	  int buf = key[j];
	  key[j] = key[j + 1];
	  key [j + 1] = buf;
	  buf = end_key[j];
	  end_key[j] = end_key[j + 1];
	  end_key[j + 1] = buf;
	}
      }
    }
/* show the list */
    for(i = 0; i < last; i ++){
      send_to_char(list[end_key[i]], ch);
    }
      

}

void do_value( CHAR_DATA *ch, char *argument )
{
    char buf[MSL], arg[MIL];
    CHAR_DATA *keeper;
    OBJ_DATA *obj;
    int cost;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Value what?\n\r", ch );
	return;
    }
    if ( ( keeper = find_keeper( ch ) ) == NULL )
	return;
    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
    {
        sendf(ch, "%s tells you '`2You don't have that item.``'\n\r",PERS(keeper,ch));
	ch->reply = keeper;
	return;
    }
    if (!can_see_obj(keeper,obj))
    {
        sendf(ch, "%s doesn't see what you are offering.\n\r",PERS(keeper,ch));
        return;
    }
    if ( !can_drop_obj( ch, obj ) )
    {
	send_to_char( "You can't let go of it.\n\r", ch );
	return;
    }
    if ( ( cost = get_cost( keeper, obj, FALSE ) ) <= 0 )
    {
	act( "$n looks uninterested in $p.", keeper, obj, ch, TO_VICT );
	return;
    }
    sprintf( buf, "$n tells you '`2I'll give you %d gold coins for $p.``'", cost);
    act( buf, keeper, obj, ch, TO_VICT );
}


void secondary(CHAR_DATA* ch, OBJ_DATA* obj){
  OBJ_DATA* wield = get_eq_char(ch,WEAR_WIELD);
  int sn, skill;
  if (obj == NULL)
    {
      send_to_char("You do not have that weapon.\n\r",ch);
      return;
    }
  /* race check */
  if (!IS_NPC(ch) 
      && obj->race && obj->race != ch->race){
    send_to_char("Its size and style make it useless to you.\n\r", ch);
    return;
  }
  /* class */
  if (!IS_NPC(ch) 
      && obj->class >= 0 && obj->class != ch->class){
    send_to_char("Its size and style make it useless to you.\n\r", ch);
    return;
  }
  if (!check_sheath(ch, WEAR_SECONDARY))
    return ;
  if ((get_eq_char(ch,WEAR_SHIELD) != NULL 
       && !remove_obj(ch, WEAR_SHIELD, TRUE)) 
      || (get_eq_char(ch,WEAR_HOLD) != NULL
	  && !remove_obj(ch, WEAR_HOLD, TRUE)) )
    {
      send_to_char("You cannot use a secondary weapon while using a shield or holding an item.\n\r",ch);
      return;
    }
  if (wield == NULL)
    {
      send_to_char("You need to wield a primary weapon, before using a secondary one.\n\r",ch);
      return;
    }
  if (!check_secondary(ch, obj, wield)){
    return;
  }
  if (!remove_obj(ch,WEAR_SECONDARY,TRUE))
    return;
  if ( CAN_WEAR( obj, ITEM_WIELD ) ){
      act("$n wields $p in $s off-hand.",ch,obj,NULL,TO_ROOM);
      act("You wield $p in your off-hand.",ch,obj,NULL,TO_CHAR);
      equip_char(ch,obj,WEAR_SECONDARY);
      sn = get_weapon_sn(ch, TRUE);
      if (sn == gsn_hand_to_hand)
           return;
      skill = get_skill(ch,sn);

/*
  if    (skill >= 100) act("$p feels like a part of you!",ch,obj,NULL,TO_CHAR);
  else if (skill > 85) act("You feel quite confident with $p.",ch,obj,NULL,TO_CHAR);
  else if (skill > 70) act("You are skilled with $p.",ch,obj,NULL,TO_CHAR);
  else if (skill > 50) act("Your skill with $p is adequate.",ch,obj,NULL,TO_CHAR);
  else if (skill > 25) act("$p feels a little clumsy in your hands.",ch,obj,NULL,TO_CHAR);
  else if (skill > 1)  act("You fumble and almost drop $p.",ch,obj,NULL,TO_CHAR);
  else                 act("You don't even know which end is up on $p.",ch,obj,NULL,TO_CHAR);
*/
  }
  else{
    act("$p cannot be wielded.", ch, obj, NULL, TO_CHAR);
  }
}

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

  if (is_affected(ch,gsn_bat_form) 
      || is_affected(ch,gsn_wolf_form) 
      || is_affected(ch,gsn_mist_form)
      || is_affected(ch,gsn_weretiger)	
      || is_affected(ch,gsn_werewolf)	
      || is_affected(ch,gsn_werebear)	
      || is_affected(ch,gsn_werefalcon)){
    send_to_char("Not while you're morphed.\n\r",ch);
    return;
  }
  if (get_skill(ch,gsn_dual_wield)  <= 1 && get_skill(ch, gsn_bladework) < 2){
    send_to_char("You do not possess enough fighting prowess to dual wield.\n\r",ch);
    return;
  }
  if (argument[0] == '\0')
    {
      send_to_char( "Wear which weapon in your off-hand?\n\r",ch);
      return;
    }
  obj = get_obj_carry(ch,argument, ch);
  secondary(ch, obj );
}

void do_outfit ( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj;
    bool found = FALSE;
    int iWear;

// Jindrak - disabled this - not check to see if objects exist.
    return;

    if (ch->level > 5 || IS_NPC(ch))
    {
	send_to_char("Find it yourself!\n\r",ch);
	return;
    }
    for ( iWear = 0; iWear < MAX_WEAR; iWear++ )
	if ( ( obj = get_eq_char( ch, iWear ) ) != NULL && iWear != WEAR_TATTOO)
	    found = TRUE;
    if (found)
    {
	send_to_char("You must be totally naked to be outfitted.\n\r",ch);
	return;
    }
    if ( ch->carry_number + 4 > can_carry_n( ch ) )
    {
	send_to_char("Your hands are too full.\n\r",ch);
	return;
    }
    if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) == NULL )
    {
        obj = create_object( get_obj_index(OBJ_VNUM_SCHOOL_BANNER), 0);
	obj->cost = 0;
        obj_to_char( obj, ch );
        equip_char( ch, obj, WEAR_LIGHT );
    }
    if ( ( obj = get_eq_char( ch, WEAR_BODY ) ) == NULL )
    {
        obj = create_object( get_obj_index(OBJ_VNUM_SCHOOL_VEST), 0);
	obj->cost = 0;
        obj_to_char( obj, ch );
        equip_char( ch, obj, WEAR_BODY );
    }
    if (ch->pcdata->start_wep >= 0 
	&& (obj = get_eq_char(ch,WEAR_WIELD)) == NULL){
      obj = create_object( get_obj_index(weapon_table[ch->pcdata->start_wep].vnum), 0);
     	obj_to_char(obj,ch);
    	equip_char(ch,obj,WEAR_WIELD);
    }
    if (((obj = get_eq_char(ch,WEAR_WIELD)) == NULL  
	 || !IS_WEAPON_STAT(obj,WEAPON_TWO_HANDS)) 
    && (obj = get_eq_char( ch, WEAR_SHIELD ) ) == NULL )
    {
        obj = create_object( get_obj_index(OBJ_VNUM_SCHOOL_SHIELD), 0);
	obj->cost = 0;
        obj_to_char( obj, ch );
        equip_char( ch, obj, WEAR_SHIELD );
    }
    obj = create_object( get_obj_index(OBJ_VNUM_VALMIRAN_MAP), 0);
    obj_to_char( obj, ch );
    obj = create_object( get_obj_index(OBJ_VNUM_RHEYDIN_MAP), 0);
    obj_to_char( obj, ch );
    obj = create_object( get_obj_index(OBJ_VNUM_E_THERA_MAP), 0);
    obj_to_char( obj, ch );
    obj = create_object( get_obj_index(OBJ_VNUM_W_THERA_MAP), 0);
    obj_to_char( obj, ch );
    if (ch->class == class_lookup("bard"))
    {
    	obj = create_object( get_obj_index(OBJ_VNUM_SCHOOL_RECORDER), 0);
    	obj_to_char( obj, ch );
    }
    send_to_char("You have been equipped by the Gods.\n\r",ch);
}

void defecate( CHAR_DATA *ch )
{
    char buf[MSL];
    char *name;
    OBJ_DATA *obj;
    if ( IS_NPC(ch) )
	name = str_dup(ch->short_descr);
    else
	name = str_dup(ch->name);
    obj = create_object( get_obj_index(OBJ_VNUM_FECES), ch->level);
    obj->level = ch->level;
    sprintf(buf, "%s %s",obj->name,name);
    free_string( obj->name );
    obj->name = str_dup(buf);
    obj->timer = 3;
    sprintf(buf, "A swarm of flies circle around a pile of %s's dung.",name);
    free_string( obj->description );
    obj->description = str_dup(buf);
    sprintf(buf, "a pile of %s's dung",name);
    free_string( obj->short_descr );
    obj->short_descr = str_dup(buf);
    obj_to_room(obj,ch->in_room);
}

void do_defecate( CHAR_DATA *ch, char *argument )
{
    AFFECT_DATA af;
    if (ch->in_room == NULL)
	return;
    if (IS_NPC(ch))
    {
        send_to_char("You squat down and drop your load.\n\r",ch);
        act("$n squats down and drops $s load.",ch,NULL,NULL,TO_ROOM);
        defecate(ch);
	return;
    }
    if (is_affected(ch,gsn_defecate))
    {
	send_to_char("You don't feel the urge to relieve yourself yet.\n\r",ch);
	return;
    }
    if (ch->fighting != NULL)
    {
	send_to_char("Not while you are fighting!\n\r",ch);
	return;
    }
    if (ch->pcdata->condition[COND_HUNGER] < 15)
    {
	send_to_char("You are not full enough to take a dump.\n\r",ch);
	return;
    }
    send_to_char("You squat down and drop your load.\n\r",ch);
    act("$n squats down and drops $s load.",ch,NULL,NULL,TO_ROOM);
    WAIT_STATE(ch,12);
    ch->position = POS_SITTING;
    update_pos(ch);
    defecate(ch);
    if (!IS_IMMORTAL(ch))
    {
    	ch->pcdata->condition[COND_HUNGER] -= 10;
    	af.where     = TO_AFFECTS;
    	af.type      = gsn_defecate;
    	af.level     = ch->level;
    	af.duration  = 24;
    	af.location  = 0;
    	af.modifier  = 0;
    	af.bitvector = 0;
    	affect_to_char( ch, &af );
    }
}

void vomit( CHAR_DATA *ch )
{
    char buf[MSL];
    char *name;
    OBJ_DATA *obj;
    if ( IS_NPC(ch) )
        name = str_dup(ch->short_descr);
    else
        name = str_dup(ch->name);
    obj = create_object( get_obj_index(OBJ_VNUM_VOMIT), ch->level);  
    obj->level = ch->level;
    sprintf(buf, "%s %s",obj->name,name);
    free_string( obj->name );
    obj->name = str_dup(buf);
    obj->timer = 3;
    sprintf(buf, "A foul, acrid stench surrounds a pile of %s's vomit.",name);
    free_string( obj->description );
    obj->description = str_dup(buf);
    sprintf(buf, "a reeking pile of %s's vomit",name);
    free_string( obj->short_descr ); 
        obj->short_descr = str_dup(buf);
    obj_to_room(obj,ch->in_room);
}   

void do_vomit( CHAR_DATA *ch, char *argument )
{
    AFFECT_DATA af;
    int level= 2 * ch->level / 3;

    if (level < 0) {
      level = 0;
    }

    if (ch->in_room == NULL)
    {
        return;
    }
    if (IS_NPC(ch))  
    {
        send_to_char("You stick your finger down your throat and spew vomit everywhere!\n\r",ch);
        act("$n sticks $s finger down $n throat and vomits.",ch,NULL,NULL,TO_ROOM);
        vomit(ch);
        return;
    }
    if (is_affected(ch,gsn_vomit))
    {
        send_to_char("You don't feel much like vomiting again.\n\r",ch);
        return;
    }
    if (ch->fighting != NULL)
    {
        send_to_char("Not while you are fighting!\n\r",ch);
        return;
    }
    if (ch->pcdata->condition[COND_HUNGER] < 15)  
    {
        send_to_char("There is nothing in your stomach to vomit out.\n\r",ch);
        return;
    }
    send_to_char("You drop to your knees and vomit violently!\n\r",ch);
    act("$n drops to $s knees and vomits.",ch,NULL,NULL,TO_ROOM);
    WAIT_STATE(ch,12);
    ch->position = POS_SITTING;
    update_pos(ch);
    vomit(ch);

    if (check_dispel(level,ch,gsn_poison))
    {
        act_new("You manage to vomit out the poison.",ch,NULL,NULL,TO_CHAR,POS_DEAD);
        act("$n looks much better.",ch,NULL,NULL,TO_ROOM);
    }

    if (!IS_IMMORTAL(ch))
    {
        ch->pcdata->condition[COND_HUNGER] -= 10;
        af.where     = TO_AFFECTS;
        af.type      = gsn_vomit;
        af.level     = ch->level;
        af.duration  = 24;
        af.location  = 0;
        af.modifier  = 0;
        af.bitvector = 0;
        affect_to_char( ch, &af );
    }
}

void do_drain( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    OBJ_DATA *obj; 
    one_argument( argument, arg );
    if (ch->class != class_lookup("vampire"))
    {
	send_to_char("Huh?\n\r",ch);
	return;
    }
    if ( arg[0] == '\0' )
    {
        send_to_char( "Drain what?\n\r", ch );
        return;
    }
    if ( ( obj = get_obj_here( ch, NULL, arg ) ) == NULL )
    {
        send_to_char( "You can't find it.\n\r", ch );
        return;
    }
    if ( ( obj->item_type != ITEM_CORPSE_PC && obj->item_type != ITEM_CORPSE_NPC)
	 || obj->condition < 2)
    {
	send_to_char( "There is no blood in that.\n\r",ch);
	return;
    }
    if (obj->item_type == ITEM_CORPSE_PC && obj->level < 15 && !IS_IMMORTAL(ch))
    {
        send_to_char("Not that corpse.\n\r",ch);
        return;
    }
    if (obj->pIndexData->vnum == OBJ_VNUM_FAKE_CORPSE)
    {
        send_to_char("Not that corpse.\n\r",ch);
        return;
    }
    if (is_affected(ch, gsn_gag)){
      send_to_char("The gag stops you from feeding.\n\r", ch);
      return;
    }
    act("You drain the blood from $p.",ch,obj,NULL,TO_CHAR);
    act("$n drains the blood from $p.",ch,obj,NULL,TO_ROOM);
    if ( !IS_NPC(ch) )
    {
        int condition; 
        condition = ch->pcdata->condition[COND_HUNGER];
        gain_condition( ch, COND_HUNGER,(30*obj->level)/ch->level);
        if ( condition <= 0 && ch->pcdata->condition[COND_HUNGER] > 0 )
            send_to_char( "You are no longer hungry.\n\r", ch );
        else if ( ch->pcdata->condition[COND_HUNGER] > 40 )
             send_to_char( "You are full.\n\r", ch );
    }
    act("You feel a little better.", ch,NULL,NULL,TO_CHAR);
    ch->hit = UMIN( ch->hit + number_range(obj->level, 3*obj->level), ch->max_hit );
    update_pos( ch );
    free_string(obj->description);
    obj->description = str_dup("An eviscerated corpse lies here.");
    obj->condition = 1;
}

/* function does the drawing of weapon */
bool draw(CHAR_DATA* ch, bool fLeft){
  OBJ_DATA* obj;
  int pos = fLeft ? WEAR_SHEATH_L : WEAR_SHEATH_R;

  if (ch == NULL)
    return FALSE;

  if ( (obj = get_eq_char(ch, pos)) == NULL){
    return FALSE;
  }
  unequip_char(ch, obj);
  if (!fLeft)
    secondary(ch, obj);
  else
    wear_obj(ch, obj, TRUE, FALSE);
  return TRUE;
}
/* function that does the sheathing */
bool sheath(CHAR_DATA* ch, OBJ_DATA* obj, bool fLeft){
  int pos = fLeft ? WEAR_SHEATH_L : WEAR_SHEATH_R;

  if (ch == NULL || obj == NULL)
    return FALSE;

  if (get_eq_char(ch, pos) != NULL){
    bug("sheath: tried sheathing into a full sheath.", 0);
    return FALSE;
  }
  if (obj->wear_loc != WEAR_NONE)
    unequip_char(ch, obj);
  equip_char(ch, obj, pos);
  return TRUE;
}

/* does the simple case of drawing weapons, used again
in fight.c do draw weapon when needed.
returns TRUE if change of weapons took place
*/
bool do_combatdraw(CHAR_DATA* ch, OBJ_DATA* prim, OBJ_DATA* sec){
  char buf[MIL];
  OBJ_DATA* left = NULL;
  OBJ_DATA* right = NULL;

  bool fPrim = prim == NULL;
  bool fSec = sec == NULL;
  int count = 0;
  int slots = 0;
/* check for left sheath holding something */
  if (get_eq_char(ch, WEAR_SHIELD) != NULL)
    slots++;
  if (get_eq_char(ch, WEAR_HOLD) != NULL)
    slots++;
      
  /* two handed check */
  if ( prim){
    if ( (ch->size < SIZE_LARGE && IS_WEAPON_STAT(prim,WEAPON_TWO_HANDS))
	 || prim->value[0] == WEAPON_STAFF 
	 || prim->value[0] == WEAPON_POLEARM 
	 || is_affected(ch,gsn_double_grip)){
      fSec = FALSE;
    }
  }


  left = get_eq_char(ch, WEAR_SHEATH_L);
  /* right needs check for shield etc */
  if ( fSec && (right = get_eq_char(ch, WEAR_SHEATH_R)) != NULL){
    if (slots > 0)
      fSec = FALSE;
  }
  if ( fPrim && (left = get_eq_char(ch, WEAR_SHEATH_L)) != NULL){
    if (slots > 1)
      fPrim = FALSE;
  }
  /* count total for message */
  count = (fPrim && left) + (fSec && right);

  if (count){
    sprintf(buf, "weapon%s", count > 1 ? "s" : "");
    act("You draw your $t.", ch, buf, NULL, TO_CHAR);
    if (!IS_AFFECTED(ch, AFF_SNEAK))
      act("$n draws $s $t.", ch, buf, NULL, TO_ROOM);
    if (fPrim && left)
      draw(ch, TRUE);
    if (fSec && right)
      draw(ch, FALSE);
    return TRUE;
  }
  return FALSE;
}

/* draws the weapons in sheaths */
void do_draw( CHAR_DATA *ch, char *argument ){
  OBJ_DATA* left = get_eq_char(ch, WEAR_SHEATH_L);
  OBJ_DATA* right = get_eq_char(ch, WEAR_SHEATH_R);

  int count = 0;

  bool fPrim = FALSE;
  bool fSec = FALSE;

  const int sn = gsn_sheath;
  const int pos = sheath_lookup(class_table[ch->class].name);
  bool fAdv = get_skill(ch, sn);

  if (!left && !right){
    send_to_char("You have no sheathed weapons to draw!\n\r", ch);
    return;
  }
  /* normal case */
  if (!fAdv){
    char buf[MIL];
    /* check which spots are empty */
    if (get_eq_char(ch, WEAR_WIELD) == NULL
	&& (get_eq_char(ch, WEAR_SHIELD) == NULL
	    || get_eq_char(ch, WEAR_HOLD) == NULL))
      fPrim = TRUE;
    if (get_eq_char(ch, WEAR_SECONDARY) == NULL
	&& get_eq_char(ch, WEAR_SHIELD) == NULL
	&& get_eq_char(ch, WEAR_HOLD) == NULL)
      fSec = TRUE;
    /* count total for message */
    count = (fPrim && left) + (fSec && right);
    if (count){
      sprintf(buf, "weapon%s", count > 1 ? "s" : "");
      act("You draw your $t.", ch, buf, NULL, TO_CHAR);
      if (!IS_AFFECTED(ch, AFF_SNEAK))
	act("$n draws $s $t.", ch, buf, NULL, TO_ROOM);
    }
    if (fPrim && left)
      draw(ch, TRUE);
    if (fSec && right)
      draw(ch, FALSE);
    return;
  }
  else{
    OBJ_DATA* prim = NULL, *sec = NULL;
    char buf[MIL];

/* for advanced case we simply check if we have weapons and attempt to */
/* rotate */
    /* count total for message */
    count = (left != NULL) + (right !=NULL  && sheath_table[pos].both);
    if (count){
      sprintf(buf, "weapon%s", count > 1 ? "s" : "");
      act("You draw your $t.", ch, buf, NULL, TO_CHAR);
      if (!IS_AFFECTED(ch, AFF_SNEAK))
	act("$n draws $s $t.", ch, buf, NULL, TO_ROOM);
    }
    /* remove both primary weapons */
    if ( (prim = get_eq_char(ch, WEAR_WIELD)) != NULL){
      unequip_char( ch, prim);
    }
    /* remove secondary weapons */
    if ( (sec = get_eq_char(ch, WEAR_SECONDARY)) != NULL
	 || (sec = get_eq_char(ch, WEAR_SHIELD)) != NULL
	 || (sec = get_eq_char(ch, WEAR_HOLD)) != NULL){
      unequip_char( ch, sec);
    }

    /* both prim/sec slots are now empty if possible, put sheathed weapons there */
    if (get_eq_char(ch, WEAR_WIELD) == NULL){
      draw(ch, TRUE);
    }
    if (get_eq_char(ch, WEAR_SECONDARY) == NULL){
      draw(ch, FALSE);
    }

    /* put original weapons in sheaths if possible */
    if (prim && get_eq_char(ch, WEAR_SHEATH_L) == NULL
	&& can_doublesheath(ch, prim, FALSE)){
      sheath(ch, prim, TRUE);
    }
    if (sec 
	&& sec->item_type == ITEM_WEAPON
	&& get_eq_char(ch, WEAR_SHEATH_R) == NULL
	&& can_doublesheath(ch, sec, FALSE)){
      sheath(ch, sec, FALSE);
    }
    return;
  }
}


/* sheaths your weapons, or specific weapon */
/* anyone can do nullstring part, only people 
skilled in sheath can select items */
void do_sheath( CHAR_DATA *ch, char *argument ){
  OBJ_DATA* obj;
  int count = 0;
  int w_loc = 0;

  const int sn = gsn_sheath;
  const int pos = sheath_lookup(class_table[ch->class].name);
  int fAdv = get_skill(ch, sn);

  /* check for things that might prevent this */
  if (is_affected(ch, gsn_graft_weapon)
      || is_affected(ch, gsn_holy_hands)
      || is_affected(ch, gsn_body_weaponry)){
    return;
  }
  /* two modes, normal, and advanced */
  if (IS_NULLSTR(argument) || !fAdv){
    char buf[MIL];
    obj = get_eq_char(ch, WEAR_WIELD);
    if (sheath(ch, obj, TRUE))
      count ++;
    obj = get_eq_char(ch, WEAR_SECONDARY);
    if (sheath(ch, obj, FALSE))
      count ++;
    if (count){
      sprintf(buf, "weapon%s", count > 1 ? "s" : "");
      act("You sheath your $t.", ch, buf, NULL, TO_CHAR);
      if (!IS_AFFECTED(ch, AFF_SNEAK))
	act("$n sheathes $s $t.", ch, buf, NULL, TO_ROOM);
    }
    return;
  }/* END NORMAL*/
  else{
    char arg1[MIL];
    bool fDouble = FALSE;
    argument = one_argument(argument, arg1);

    /* check if this is double sheath or just sheathing */
    w_loc = IS_NULLSTR(argument) ? WEAR_SHEATH_L : WEAR_SHEATH_R;
    if (w_loc == WEAR_SHEATH_L && get_eq_char(ch, WEAR_WIELD) != NULL){
      fDouble = TRUE;
    }
    else if (w_loc == WEAR_SHEATH_R 
	     && (get_eq_char(ch, WEAR_WIELD) != NULL
		 || get_eq_char(ch, WEAR_SHIELD) != NULL
		 || get_eq_char(ch, WEAR_SECONDARY) != NULL)){
      fDouble = TRUE;
    }
    /* check for secondary */
    if (fDouble && w_loc == WEAR_SHEATH_R && !sheath_table[pos].both){
      send_to_char("You are incapable of double sheathing secondary weapons.\n\r", ch);
      return;
    }

    if ( (obj = get_obj_carry(ch, arg1, ch)) == NULL){
      sendf(ch, "You do not seem to be carrying %s.\n\r", arg1);
      return;
    }
    if (obj->item_type != ITEM_WEAPON){
      send_to_char("You can only sheath a weapon.\n\r", ch);
      return;
    }

    if (fDouble && !can_doublesheath(ch, obj, FALSE))
      return;
    /* check for empty sheaths */
    if (get_eq_char(ch, w_loc) != NULL){
      send_to_char("You are already storing a weapon there!\n\r", ch);
      return;
    }
    /* skill check */
    if (fDouble && number_percent() > 4 * fAdv / 5){
      send_to_char("Your weapon gets in the way and you fail.\n\r", ch);
      return;
    }
    /* sheath it */
    if (sheath(ch, obj, w_loc == WEAR_SHEATH_L)){
      act("You $tsheath your weapon.", 
	  ch, fDouble ? "double" : "", NULL, TO_CHAR);
      act("$n $tsheathes $s weapon.", 
	  ch, fDouble ? "double" : "", NULL, TO_ROOM);
    }
  }
}

//05-01 10:15 GO: commented out fasting
//11-25 15:30 ATH: Added code to deal with "holdsrare" flag on containers 
//01-08 15:30 ATH: Added cant put non-rare holdsrare items in sacs