crodo_mud/cnf/
crodo_mud/lib/
crodo_mud/lib/house/
crodo_mud/lib/misc/
crodo_mud/lib/plralias/F-J/
crodo_mud/lib/plralias/U-Z/
crodo_mud/lib/plrobjs/
crodo_mud/lib/plrvars/A-E/
crodo_mud/lib/plrvars/F-J/
crodo_mud/lib/plrvars/K-O/
crodo_mud/lib/plrvars/P-T/
crodo_mud/lib/plrvars/U-Z/
crodo_mud/lib/text/
crodo_mud/lib/text/help/
crodo_mud/lib/world/
crodo_mud/src/
/*************************************************************************
*   File: act.item.c                                    Part of CircleMUD *
*  Usage: object handling routines -- get/drop and container handling     *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */

#include "conf.h"
#include "sysdep.h"


#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"
#include "constants.h"
#include "dg_scripts.h"
#include "money.h"
#include "profs.h"

/* extern variables */
extern room_vnum donation_vnum[NUM_HOMETOWNS][3];
extern struct obj_data *obj_proto;
extern struct room_data *world;
extern char *pot_name;
extern struct index_data *obj_index;

/* local functions */
int can_take_obj(struct char_data * ch, struct obj_data * obj);
void get_check_money(struct char_data * ch, struct obj_data * obj);
int perform_get_from_room(struct char_data * ch, struct obj_data * obj);
void get_from_room(struct char_data * ch, char *arg, int amount);
void perform_give_gold(struct char_data * ch, struct char_data * vict, int amount, int type);
void perform_give(struct char_data * ch, struct char_data * vict, struct obj_data * obj);
int perform_drop(struct char_data * ch, struct obj_data * obj, byte mode, const char *sname, room_rnum RDR);
void perform_drop_gold(struct char_data * ch, int amount, int  type, byte mode, room_rnum RDR);
struct char_data *give_find_vict(struct char_data * ch, char *arg);
void weight_change_object(struct obj_data * obj, int weight);
void perform_put(struct char_data * ch, struct obj_data * obj, struct obj_data * cont);
void name_from_drinkcon(struct obj_data * obj);
void get_from_container(struct char_data * ch, struct obj_data * cont, char *arg, int mode, int amount);
void name_to_drinkcon(struct obj_data * obj, int type);
void wear_message(struct char_data * ch, struct obj_data * obj, int where);
void perform_wear(struct char_data * ch, struct obj_data * obj, int where);
int find_eq_pos(struct char_data * ch, struct obj_data * obj, char *arg);
void perform_get_from_container(struct char_data * ch, struct obj_data * obj, struct obj_data * cont, int mode);
void perform_remove(struct char_data * ch, int pos);
ACMD(do_remove);
ACMD(do_put);
ACMD(do_get);
ACMD(do_drop);
ACMD(do_give);
ACMD(do_drink);
ACMD(do_eat);
ACMD(do_pour);
ACMD(do_wear);
ACMD(do_wield);
ACMD(do_grab);
ACMD(do_compare);

void perform_put(struct char_data * ch, struct obj_data * obj,
		      struct obj_data * cont)
{
  struct obj_data *pile = NULL;

  /* Trigger Check */
  if (!drop_otrigger(obj, ch))
    return;

  if (GET_OBJ_WEIGHT(cont) + GET_OBJ_WEIGHT(obj) > GET_OBJ_VAL(cont, 0)) {
    act("$p won't fit in $P.", FALSE, ch, obj, cont, TO_CHAR);
    return; }

 /* Curse Check */
  if (IS_OBJ_STAT(obj, ITEM_NODROP) && (cont->carried_by != ch)) {
    act("You can't let go of $p, it must be CURSED!", FALSE, ch, obj, 0, TO_CHAR);
    return; }

    obj_from_char(obj);
    act("$n puts $p in $P.", TRUE, ch, obj, cont, TO_ROOM);

    /* Yes, I realize this is strange until we have auto-equip on rent. -gg */
    if (IS_OBJ_STAT(obj, ITEM_NODROP) && !IS_OBJ_STAT(cont, ITEM_NODROP)) {
      SET_BIT(GET_OBJ_EXTRA(cont), ITEM_NODROP);
      act("You get a strange feeling as you put $p in $P.", FALSE,
                ch, obj, cont, TO_CHAR);
    } else
      act("You put $p in $P.", FALSE, ch, obj, cont, TO_CHAR);

  if (GET_OBJ_TYPE(obj) == ITEM_MONEY) {
    pile = get_pile_in_list(cont->contains);
 
   if (pile != NULL) 
     add_money_to_pile(obj, pile);
   else
     obj_to_obj(obj, cont);

   return; }

    obj_to_obj(obj, cont);

}


/* The following put modes are supported by the code below:

	1) put <object> <container>
	2) put all.<object> <container>
	3) put all <container>

	<container> must be in inventory or on ground.
	all objects to be put into container must be in inventory.
*/

ACMD(do_put)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  struct obj_data *obj, *next_obj, *cont, *it_obj;
  struct char_data *tmp_char;
  int obj_dotmode, cont_dotmode, howmany = 1;
  char *theobj, *thecont;
  int type = -1, found = 0;

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

  if (*arg3 && is_number(arg1)) {
    howmany = atoi(arg1);
    theobj = arg2;
    thecont = arg3;
  } else {
    theobj = arg1;
    thecont = arg2;
  }

  obj_dotmode = find_all_dots(theobj);
  cont_dotmode = find_all_dots(thecont);

  if (!*theobj) {
    send_to_char("Put what in what?\r\n", ch);
    return; }

  if (cont_dotmode != FIND_INDIV) {
    send_to_char("You can only put things into one container at a time.\r\n", ch);
    return; } 

  if (!*thecont) {
    sprintf(buf, "What do you want to put %s in?\r\n",
	    ((obj_dotmode == FIND_INDIV) ? "it" : "them"));
    send_to_char(buf, ch);
    return;  }

    it_obj = GET_OBJ_IT(ch);
    generic_find(thecont, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &tmp_char, &cont);
    GET_OBJ_IT(ch) = it_obj;

    if (!cont) {
      sprintf(buf, "You don't see %s %s here.\r\n", AN(thecont), thecont);
      send_to_char(buf, ch);
    return; }

   if (GET_OBJ_TYPE(cont) != ITEM_CONTAINER) {
      act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
      return; }

    if (OBJVAL_FLAGGED(cont, CONT_CLOSED)) {
      send_to_char("You'd better open it first!\r\n", ch);
      return; }


      if (obj_dotmode == FIND_INDIV) {  /* put <obj> <container> */

        if (!(obj = get_obj_in_list_vis(ch, theobj, ch->carrying))) {
          sprintf(buf, "You aren't carrying %s %s.\r\n", AN(theobj), theobj);
          send_to_char(buf, ch);
          return; }
      
      if (obj == cont) {
      send_to_char("You attempt to fold it into itself, but fail.\r\n", ch);
        return; }

  /* Monetary system processing */
    if (GET_OBJ_TYPE(obj) == ITEM_MONEY) {
    type = get_money_type(obj);

     if (howmany > get_money(ch, type)) {
      send_to_char("You lack the funds to put there.\r\n", ch);
      return; }

          sub_cash_from_char(ch, howmany, type);
          obj = create_money(howmany, type);
	  obj_to_char(obj, ch);
          perform_put(ch, obj, cont); 
	  return; }
				
        /* put x obj processing */
          while(obj && howmany--) {
            next_obj = obj->next_content;
            perform_put(ch, obj, cont);
            it_obj = obj;
            obj = get_obj_in_list_vis(ch, theobj, next_obj);
            GET_OBJ_IT(ch) = it_obj;
          }

          return; }

        for (obj = ch->carrying; obj; obj = next_obj) {
          next_obj = obj->next_content;
          if (obj != cont && CAN_SEE_OBJ(ch, obj) &&
             (obj_dotmode == FIND_ALL || isname(theobj, obj->name))) {
	    found = 1;

         if (GET_OBJ_TYPE(obj) == ITEM_MONEY)
            GET_GOLD(ch) -= money_obj_value(obj);

            perform_put(ch, obj, cont);
            GET_OBJ_IT(ch) = obj;
          }
	}
	if (!found) {
	  if (obj_dotmode == FIND_ALL)
	   send_to_char("You don't seem to have anything to put into it.\r\n", ch);
	  else {
	   sprintf(buf, "You don't seem to have any %ss.\r\n", theobj);
	   send_to_char(buf, ch);
	       }    }
}

int can_take_obj(struct char_data * ch, struct obj_data * obj)
{
  if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) {
    act("$p: you can't carry that many items.", FALSE, ch, obj, 0, TO_CHAR);
    return (0);
  } else if ((IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(ch)) {
    act("$p: you can't carry that much weight.", FALSE, ch, obj, 0, TO_CHAR);
    return (0);
  } else if (!(CAN_WEAR(obj, ITEM_WEAR_TAKE))) {
    act("$p: you can't take that!", FALSE, ch, obj, 0, TO_CHAR);
    return (0);
  } else if (OBJ_FLAGGED(obj, ITEM_SEAT) && (GET_OBJ_VAL(obj, 1) > 0 )) {
    act("$p: there is someone sitting on it!", FALSE, ch, obj, 0, TO_CHAR);
    return (0);
  } else
    return (1);
}


void get_check_money(struct char_data * ch, struct obj_data * obj)
{
  int count = 0, i = 0;
  int value[NUM_COIN_TYPES + 1];

  if (GET_OBJ_TYPE(obj) != ITEM_MONEY)
    return;

 for (i = 0; i < NUM_COIN_TYPES; i++)
  value[i] = 0;

 /* Calculate and store cash values for later use. */

 for (i = 0; i < NUM_COIN_TYPES; i++) {
   count += GET_OBJ_VAL(obj, i);
   value[i] = GET_OBJ_VAL(obj, i); }

  obj_from_char(obj);
  extract_obj(obj);

  /* Move cash to the char */
  for (i = 0; i < NUM_COIN_TYPES; i++)
   if (value[i] > 0)
    add_cash_to_char(ch, value[i], i);

  if (count == 1)
    send_to_char("There was 1 coin.\r\n", ch);
  else {
    sprintf(buf, "There were %d coins.\r\n", count);
    send_to_char(buf, ch);
  }
}


void perform_get_from_container(struct char_data * ch, struct obj_data * obj,
				     struct obj_data * cont, int mode)
{
  if (mode == FIND_OBJ_INV || can_take_obj(ch, obj)) {
    if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch))
      act("$p: you can't hold any more items.", FALSE, ch, obj, 0, TO_CHAR);
     else if (get_otrigger(obj, ch)) {
      obj_from_obj(obj);
      obj_to_char(obj, ch);
      act("You get $p from $P.", FALSE, ch, obj, cont, TO_CHAR);
      act("$n gets $p from $P.", TRUE, ch, obj, cont, TO_ROOM);
      get_check_money(ch, obj);
    }
  }
}


void get_from_container(struct char_data * ch, struct obj_data * cont,
			     char *arg, int mode, int howmany)
{
  struct obj_data *obj, *next_obj, *it_obj, *obj_next;
  int obj_dotmode, found = 0;
  int type = -1;
  int cur_money = 0;

  obj_dotmode = find_all_dots(arg);
  type = parse_cash_type(arg);

  if (OBJVAL_FLAGGED(cont, CONT_CLOSED))
    act("$p is closed.", FALSE, ch, cont, 0, TO_CHAR);
  else if (obj_dotmode == FIND_INDIV) {

   if (type != -1) 
    obj = get_pile_in_list(cont->contains);
   else
    obj = get_obj_in_list_vis(ch, arg, cont->contains);

    if (obj == NULL) {
      sprintf(buf, "There doesn't seem to be %s %s in $p.", AN(arg), arg);
      act(buf, FALSE, ch, cont, 0, TO_CHAR);
      return; }

  /* Monetary system processing */

      if ( (GET_OBJ_TYPE(obj) == ITEM_MONEY) && (howmany > 0) && (type >= 0) ) {
        
      cur_money = GET_OBJ_VAL(obj, type);
 
     if (howmany > cur_money) {
      sprintf(buf, "There doesn't seem to be that many %s coins.\r\n", coin_types[type]);
      send_to_char(buf, ch);
      return; }

	sub_money_from_pile(obj, howmany, type);
        add_cash_to_char(ch, howmany, type);

	  act("$n gets some money from $P.", TRUE, ch, obj, cont, TO_ROOM);
	  act("You get some money from $P.", FALSE, ch, obj, cont, TO_CHAR);
          return;
		}

      while(obj && howmany--) {
        obj_next = obj->next_content;
        perform_get_from_container(ch, obj, cont, mode);
        it_obj = obj;
        obj = get_obj_in_list_vis(ch, arg, obj_next);
	GET_OBJ_IT(ch) = it_obj;
      }
  } else {
    if (obj_dotmode == FIND_ALLDOT && !*arg) {
      send_to_char("Get all of what?\r\n", ch);
      return;
    }
    for (obj = cont->contains; obj; obj = next_obj) {
      next_obj = obj->next_content;
      if (CAN_SEE_OBJ(ch, obj) &&
	  (obj_dotmode == FIND_ALL || isname(arg, obj->name))) {
	found = 1;
	perform_get_from_container(ch, obj, cont, mode);
        GET_OBJ_IT(ch) = obj;
      }
    }
    if (!found) {
      if (obj_dotmode == FIND_ALL)
	act("$p seems to be empty.", FALSE, ch, cont, 0, TO_CHAR);
      else {
	sprintf(buf, "You can't seem to find any %ss in $p.", arg);
	act(buf, FALSE, ch, cont, 0, TO_CHAR);
      }
    }
  }
}


int perform_get_from_room(struct char_data * ch, struct obj_data * obj)
{
    if (can_take_obj(ch, obj) && get_otrigger(obj, ch)) {
    obj_from_room(obj);
    obj_to_char(obj, ch);
    act("You get $p.", FALSE, ch, obj, 0, TO_CHAR);
    act("$n gets $p.", TRUE, ch, obj, 0, TO_ROOM);
    get_check_money(ch, obj);
    return (1);
  }
  return (0);
}

void get_from_room(struct char_data * ch, char *arg, int howmany)
{
  struct obj_data *obj, *next_obj;
  int dotmode, found = 0;

  dotmode = find_all_dots(arg);

  if (dotmode == FIND_INDIV) {
    if (!(obj = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents))) {
      sprintf(buf, "You don't see %s %s here.\r\n", AN(arg), arg);
      send_to_char(buf, ch);
    } else {
      struct obj_data *obj_next;
      while(obj && howmany--) {
	obj_next = obj->next_content;
        perform_get_from_room(ch, obj);
        obj = get_obj_in_list_vis(ch, arg, obj_next);
      }
    }
  } else {
    if (dotmode == FIND_ALLDOT && !*arg) {
      send_to_char("Get all of what?\r\n", ch);
      return;
    }
    for (obj = world[ch->in_room].contents; obj; obj = next_obj) {
      next_obj = obj->next_content;
      if (CAN_SEE_OBJ(ch, obj) &&
	  (dotmode == FIND_ALL || isname(arg, obj->name))) {
	found = 1;
	perform_get_from_room(ch, obj);
      }
    }
    if (!found) {
      if (dotmode == FIND_ALL)
	send_to_char("There doesn't seem to be anything here.\r\n", ch);
      else {
	sprintf(buf, "You don't see any %ss here.\r\n", arg);
	send_to_char(buf, ch);
      }
    }
  }
}



ACMD(do_get)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];

  int cont_dotmode, found = 0, mode;
  struct obj_data *cont, *it_obj;
  struct char_data *tmp_char;

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

  if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch))
    send_to_char("Your arms are already full!\r\n", ch);
  else if (!*arg1)
    send_to_char("Get what?\r\n", ch);
  else if (!*arg2)
    get_from_room(ch, arg1, 1);
  else if (is_number(arg1) && !*arg3)
    get_from_room(ch, arg2, atoi(arg1));
  else {
    int amount = 1;
    if (is_number(arg1)) {
      amount = atoi(arg1);
      strcpy(arg1, arg2);
      strcpy(arg2, arg3);
    }
    cont_dotmode = find_all_dots(arg2);
    if (cont_dotmode == FIND_INDIV) {
      it_obj = GET_OBJ_IT(ch);
      mode = generic_find(arg2, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &tmp_char, &cont);
      GET_OBJ_IT(ch) = it_obj;
      if (!cont) {
	sprintf(buf, "You don't have %s %s.\r\n", AN(arg2), arg2);
	send_to_char(buf, ch);
      } else if (GET_OBJ_TYPE(cont) != ITEM_CONTAINER)
	act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
      else
	get_from_container(ch, cont, arg1, mode, amount);
    } else {
      if (cont_dotmode == FIND_ALLDOT && !*arg2) {
	send_to_char("Get from all of what?\r\n", ch);
	return;
      }
      for (cont = ch->carrying; cont; cont = cont->next_content)
	if (CAN_SEE_OBJ(ch, cont) &&
	    (cont_dotmode == FIND_ALL || isname(arg2, cont->name))) {
	  if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER) {
	    found = 1;
	    get_from_container(ch, cont, arg1, FIND_OBJ_INV, amount);
	  } else if (cont_dotmode == FIND_ALLDOT) {
	    found = 1;
	    act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
	  }
	}
      for (cont = world[ch->in_room].contents; cont; cont = cont->next_content)
	if (CAN_SEE_OBJ(ch, cont) &&
	    (cont_dotmode == FIND_ALL || isname(arg2, cont->name))) {
	  if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER) {
	    get_from_container(ch, cont, arg1, FIND_OBJ_ROOM, amount);
	    found = 1;
	  } else if (cont_dotmode == FIND_ALLDOT) {
	    act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
	    found = 1;
	  }
	}
      if (!found) {
	if (cont_dotmode == FIND_ALL)
	  send_to_char("You can't seem to find any containers.\r\n", ch);
	else {
	  sprintf(buf, "You can't seem to find any %ss here.\r\n", arg2);
	  send_to_char(buf, ch);
	}
      }
    }
  }
}


void perform_drop_gold(struct char_data * ch, int amount, int type,
		            byte mode, room_rnum RDR)
{
  struct obj_data *obj, *donation_pot, *pile;

  if (amount <= 0) {
    send_to_char("Heh heh heh.. we are jolly funny today, eh?\r\n", ch);
    return; }

  if (get_money(ch, type) < amount) {
   sprintf(buf, "You are not carrying that many %s coins!\r\n", coin_types[type]); 
   send_to_char(buf, ch);
   return; }

      if (mode == SCMD_DONATE) {

        donation_pot = get_obj_in_list_vis(ch,pot_name,world[RDR].contents);

	send_to_char("You throw some money into the air where it disappears in a puff of smoke!\r\n", ch);
	act("$n throws some money into the air where it disappears in a puff of smoke!",
	    FALSE, ch, 0, 0, TO_ROOM);

        pile = get_pile_in_list(donation_pot->contains);        
        obj = create_money(amount, type);

       if (pile != NULL)
         add_money_to_pile(obj, pile);
        else
	 obj_to_obj(obj, donation_pot);        

        sub_cash_from_char(ch, amount, type);
        send_to_room("&mThe pot rings with a loud THUD! &n\r\n", RDR);      
        return;
        }

   if (mode == SCMD_JUNK) {
      WAIT_STATE(ch, PULSE_VIOLENCE);   /* to prevent coin-bombing */
      sprintf(buf, "$n tosses %s which disappears in a puff of smoke!",
              money_desc(amount, type));
      act(buf, FALSE, ch, 0, 0, TO_ROOM);
      sprintf(buf, "You toss some %s which disappears in a puff of smoke!\r\n", coin_types[type]);
      send_to_char(buf, ch);
      sub_cash_from_char(ch, amount, type);
      return;
    }

        WAIT_STATE(ch, PULSE_VIOLENCE);   /* to prevent coin-bombing */
        obj = create_money(amount, type);
  	sprintf(buf, "You drop %d %s coin%s.\r\n",
         amount, coin_types[type], amount == 1 ? "" : "s");
  	send_to_char(buf, ch);
	sprintf(buf, "$n drops %s.", money_desc(amount, type));
	act(buf, TRUE, ch, 0, 0, TO_ROOM);
	obj_to_room(obj, ch->in_room);
        sub_cash_from_char(ch, amount, type);
  }

#define VANISH(mode) ((mode == SCMD_DONATE || mode == SCMD_JUNK) ? \
		      "  It vanishes in a puff of smoke!" : "")

int perform_drop(struct char_data * ch, struct obj_data * obj,
		     byte mode, const char *sname, room_rnum RDR)
{
  int value, found = 0;
  struct obj_data *donation_pot, *pile;

  if (!drop_otrigger(obj, ch))
    return 0;
  if ((mode == SCMD_DROP) && !drop_wtrigger(obj, ch))
    return 0;

  if (IS_OBJ_STAT(obj, ITEM_NODROP)) {
    sprintf(buf, "You can't %s $p, it must be CURSED!", sname);
    act(buf, FALSE, ch, obj, 0, TO_CHAR);
    return (0);
  }

  sprintf(buf, "You %s $p.%s", sname, VANISH(mode));
  act(buf, FALSE, ch, obj, 0, TO_CHAR);
  sprintf(buf, "$n %ss $p.%s", sname, VANISH(mode));
  act(buf, TRUE, ch, obj, 0, TO_ROOM);
  obj_from_char(obj);

  if (GET_OBJ_TYPE(obj) == ITEM_MONEY)
    GET_GOLD(ch) -= money_obj_value(obj);

  if ((mode == SCMD_DONATE) && IS_OBJ_STAT(obj, ITEM_NODONATE))
    mode = SCMD_JUNK;

  switch (mode) {
  case SCMD_DROP:
    obj_to_room(obj, ch->in_room);
    return (0);
  case SCMD_DONATE:
    if (GET_OBJ_TYPE(obj) == ITEM_WEAPON) {
      RDR = real_room(donation_vnum[GET_HOME(ch)][0]); }
      else if (GET_OBJ_TYPE(obj) == ITEM_ARMOR || GET_OBJ_TYPE(obj) == ITEM_WORN) {
      RDR = real_room(donation_vnum[GET_HOME(ch)][1]); }
      else {RDR = real_room(donation_vnum[GET_HOME(ch)][2]); }
    if ((donation_pot = get_obj_in_list_vis(ch,pot_name,world[RDR].contents)))
    found = TRUE;
    if (found == TRUE) {
     if (GET_OBJ_TYPE(obj) == ITEM_MONEY) {
    pile = get_pile_in_list(donation_pot->contains);        
   if (pile != NULL)
     add_money_to_pile(obj, pile);
     else
    obj_to_obj(obj, donation_pot); }
     else
    obj_to_obj(obj, donation_pot);
    SET_BIT(obj->obj_flags.extra_flags, ITEM_NOSELL);
    send_to_room("&mThe pot rings with a loud THUD! &n\r\n", RDR);
    return (0); }
    else obj_to_room(obj, RDR);
    act("$p suddenly appears in a puff a smoke!", FALSE, 0, obj, 0, TO_ROOM);
    return (0);
  case SCMD_JUNK:
    value = MAX(1, MIN(200, GET_OBJ_COST(obj) / 16));
    extract_obj(obj);
    return (value);
  default:
    log("SYSERR: Incorrect argument %d passed to perform_drop.", mode);
    break;
  }

  return (0);
}



ACMD(do_drop)
{
  struct obj_data *obj, *next_obj;
  room_rnum RDR = 0;
  byte mode = SCMD_DROP;
  int dotmode, amount = 0, multi, type;
  const char *sname;

  switch (subcmd) {
  case SCMD_JUNK:
    sname = "junk";
    mode = SCMD_JUNK;
    break;
  case SCMD_DONATE:
    sname = "donate";
    mode = SCMD_DONATE;
    switch (number(0, 5)) {
    case 0:
      mode = SCMD_JUNK;
      break;
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
      RDR = real_room(donation_vnum[GET_HOME(ch)][2]);
      break;
    }
    if (RDR == NOWHERE) {
      send_to_char("Sorry, you can't donate anything right now.\r\n", ch);
      return;
    }
    break;
  default:
    sname = "drop";
    break;
  }

  argument = one_argument(argument, arg);

  if (!*arg) {
    sprintf(buf, "What do you want to %s?\r\n", sname);
    send_to_char(buf, ch);
    return;
  } else if (is_number(arg)) {
    multi = atoi(arg);
    one_argument(argument, arg);
    type = parse_cash_type(arg);

    if (type > -1)
      perform_drop_gold(ch, multi, type, mode, RDR);
    else if (multi <= 0)
      send_to_char("Yeah, that makes sense.\r\n", ch);
    else if (!*arg) {
      sprintf(buf, "What do you want to %s %d of?\r\n", sname, multi);
      send_to_char(buf, ch);
    } else if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
      sprintf(buf, "You don't seem to have any %ss.\r\n", arg);
      send_to_char(buf, ch);
    } else {
      do {
        next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
        amount += perform_drop(ch, obj, mode, sname, RDR);
        obj = next_obj;
      } while (obj && --multi);
    }
  } else {
    dotmode = find_all_dots(arg);

    /* Can't junk or donate all */
    if ((dotmode == FIND_ALL) && (subcmd == SCMD_JUNK || subcmd == SCMD_DONATE)) {
      if (subcmd == SCMD_JUNK)
	send_to_char("Go to the dump if you want to junk EVERYTHING!\r\n", ch);
      else
	send_to_char("Go do the donation room if you want to donate EVERYTHING!\r\n", ch);
      return;
    }
    if (dotmode == FIND_ALL) {
      if (!ch->carrying)
	send_to_char("You don't seem to be carrying anything.\r\n", ch);
      else
	for (obj = ch->carrying; obj; obj = next_obj) {
	  next_obj = obj->next_content;
	  amount += perform_drop(ch, obj, mode, sname, RDR);
	}
    } else if (dotmode == FIND_ALLDOT) {
      if (!*arg) {
	sprintf(buf, "What do you want to %s all of?\r\n", sname);
	send_to_char(buf, ch);
	return;
      }
      if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
	sprintf(buf, "You don't seem to have any %ss.\r\n", arg);
	send_to_char(buf, ch);
      }      
      while (obj) {
	next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
	amount += perform_drop(ch, obj, mode, sname, RDR);
	obj = next_obj;
      }
    } else {
      if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
	sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
	send_to_char(buf, ch);
      } else {

         if (GET_OBJ_TYPE(obj) == ITEM_MONEY) {
	perform_drop_gold(ch, 1, get_money_type(obj), mode, RDR);
	return; }

	amount += perform_drop(ch, obj, mode, sname, RDR); }
    }
  }

  if (amount && (subcmd == SCMD_JUNK)) {
    send_to_char("You have been rewarded by the gods!\r\n", ch);
    act("$n has been rewarded by the gods!", TRUE, ch, 0, 0, TO_ROOM);
    GET_EXP(ch) += 1;
  }
}


void perform_give(struct char_data * ch, struct char_data * vict,
		       struct obj_data * obj)  {

  if (IS_OBJ_STAT(obj, ITEM_NODROP)) {
    act("You can't let go of $p!!  Yeech!", FALSE, ch, obj, 0, TO_CHAR);
    return;
  }
  if (IS_CARRYING_N(vict) >= CAN_CARRY_N(vict)) {
    act("$N seems to have $S hands full.", FALSE, ch, 0, vict, TO_CHAR);
    return;
  }
  if (GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(vict) > CAN_CARRY_W(vict)) {
    act("$E can't carry that much weight.", FALSE, ch, 0, vict, TO_CHAR);
    return;
  }
  if ((ch == vict) && (GET_OBJ_TYPE(obj) != ITEM_MONEY)) {
    send_to_char("What's the point of that?\r\n",ch);
    return;
  }
  if (!give_otrigger(obj, ch, vict) || !receive_mtrigger(vict, ch, obj))
    return;

  act("You give $p to $N.", FALSE, ch, obj, vict, TO_CHAR);
  act("$n gives you $p.", FALSE, ch, obj, vict, TO_VICT);  
  act("$n gives $p to $N.", TRUE, ch, obj, vict, TO_NOTVICT);

  if (GET_OBJ_TYPE(obj) == ITEM_MONEY) {
    perform_give_gold(ch, vict, GET_OBJ_VAL(obj, get_money_type(obj)), get_money_type(obj));
    return;
  }

  obj_from_char(obj);
  obj_to_char(obj, vict);
}

/* utility function for give */
struct char_data *give_find_vict(struct char_data * ch, char *arg)
{
  struct char_data *vict;

  if (!*arg) {
    send_to_char("To who?\r\n", ch);
    return (NULL);
  } else if (!(vict = get_char_vis(ch, arg, FIND_CHAR_ROOM))) {
    send_to_char(NOPERSON, ch);
    return (NULL);
  } else if ((vict == ch) && (GET_LEVEL(ch)<LVL_IMMORT)) {
    send_to_char("What's the point of that?\r\n", ch);
    return (NULL);
  } else
    return (vict);
}


void perform_give_gold(struct char_data * ch, struct char_data * vict,
		            int amount, int type)
{
  if (amount <= 0) {
    send_to_char("Heh heh heh ... we are jolly funny today, eh?\r\n", ch);
    return;
  }
  if ((get_money(ch, type) < amount) && (GET_LEVEL(ch)<LVL_GOD)) {
    send_to_char("You don't have that many coins!\r\n", ch);
    return;
  }

  sprintf(buf, "You give %d %s coin%s to %s.\r\n",
          amount, coin_types[type], amount == 1 ? "" : "s",
	  GET_NAME(vict));
  if((GET_LEVEL(ch)>LVL_IMMORT) && (ch==vict)) {
    sprintf(buf, "You create %d %s coin%s.\r\n",
          amount, coin_types[type], amount == 1 ? "" : "s");
  }
  send_to_char(buf, ch);

  if(ch!=vict) {
    sprintf(buf, "$n gives you %d %s coin%s.", amount,
          coin_types[type], amount == 1 ? "" : "s");
    act(buf, FALSE, ch, 0, vict, TO_VICT);
  }

  sprintf(buf, "$n gives %s to $N.", money_desc(amount, type));
  if((GET_LEVEL(ch)>LVL_IMMORT) && (ch==vict)) { 
    sprintf(buf, "$n makes a strange magical gesture.\r\n$n has created %s.", money_desc(amount, type));
  }
  act(buf, TRUE, ch, 0, vict, TO_NOTVICT);

  if(GET_LEVEL(ch)<LVL_GOD)
    {  sub_cash_from_char(ch, amount, type); }
  add_cash_to_char(vict, amount, type);
  
  bribe_mtrigger(vict, ch, value_in_copper(amount, type));
}

ACMD(do_give)
{
  int amount, dotmode;
  int type = -1;  /* For Money System */
  struct char_data *vict;
  struct obj_data *obj, *next_obj;
  char obj_name[MAX_INPUT_LENGTH];
  char vict_name[MAX_INPUT_LENGTH];
  argument = one_argument(argument, arg);
 
  if (!*arg)
    send_to_char("Give what to who?\r\n", ch);
  else if (is_number(arg)) {
    amount = atoi(arg);
    argument = one_argument(argument, obj_name);
    type = parse_cash_type(obj_name);
    
     if (type != -1) {
      argument = one_argument(argument, vict_name);
      if ((vict = give_find_vict(ch, vict_name)) != NULL)
	perform_give_gold(ch, vict, amount, type);
      return;
    } else  {

     if (!*obj_name) {	/* Give multiple code. */
      sprintf(buf, "What do you want to give %d of?\r\n", amount);
      send_to_char(buf, ch);
      return; }

      if (!(obj = get_obj_in_list_vis(ch, obj_name, ch->carrying))) {
      sprintf(buf, "You don't seem to have any %ss.\r\n", arg);
      send_to_char(buf, ch);
      return; }

      argument = one_argument(argument, vict_name);
      if (!(vict = give_find_vict(ch, vict_name)))
      return;

      while (obj && amount--) {
	next_obj = get_obj_in_list_vis(ch, obj_name, obj->next_content);
	perform_give(ch, vict, obj);
	obj = next_obj;
      }
    }
  } else {
    one_argument(argument, buf1);
    if (!(vict = give_find_vict(ch, buf1)))
      return;
    dotmode = find_all_dots(arg);

   switch (dotmode) {

    case FIND_INDIV:
      if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
        sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
        send_to_char(buf, ch);
	return; }
      if (GET_OBJ_TYPE(obj) == ITEM_MONEY)
          perform_give_gold(ch, vict, 1, get_money_type(obj));
        else
        perform_give(ch, vict, obj);
    break;
    case FIND_ALLDOT:
     if (!*arg) {
       send_to_char("All of what?\r\n", ch);
        return;
      }
        if ((ch->carrying == NULL) || !(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
	    sprintf(buf, "You don't seem to have any %ss.\r\n", arg);
	    send_to_char(buf, ch);
	    return; }

        if (GET_OBJ_TYPE(obj) == ITEM_MONEY) {
          perform_give_gold(ch, vict, GET_OBJ_VAL(obj, get_money_type(obj)), 
	   		    get_money_type(obj));
	return; }

	for (obj = ch->carrying; obj; obj = next_obj) {
	  next_obj = obj->next_content;
	  if (CAN_SEE_OBJ(ch, obj) &&
	      ((dotmode == FIND_ALL || isname(arg, obj->name))))
	    perform_give(ch, vict, obj);
	}
    break;
    case FIND_ALL:
      if (!ch->carrying) 
        send_to_char("You don't seem to be carrying anything.\r\n", ch);
      else
        for (obj = ch->carrying; obj; obj = next_obj) {
          next_obj = obj->next_content;
          perform_give(ch, vict, obj);
        }
    break;
    }
  }
}



void weight_change_object(struct obj_data * obj, int weight)
{
  struct obj_data *tmp_obj;
  struct char_data *tmp_ch;

  if (obj->in_room != NOWHERE) {
    GET_OBJ_WEIGHT(obj) += weight;
  } else if ((tmp_ch = obj->carried_by)) {
    obj_from_char(obj);
    GET_OBJ_WEIGHT(obj) += weight;
    obj_to_char(obj, tmp_ch);
  } else if ((tmp_obj = obj->in_obj)) {
    obj_from_obj(obj);
    GET_OBJ_WEIGHT(obj) += weight;
    obj_to_obj(obj, tmp_obj);
  } else {
    log("SYSERR: Unknown attempt to subtract weight from an object.");
  }
}



void name_from_drinkcon(struct obj_data * obj)
{
  int i;
  char *new_name;

  for (i = 0; (*((obj->name) + i) != ' ') && (*((obj->name) + i) != '\0'); i++);

  if (*((obj->name) + i) == ' ') {
    new_name = str_dup((obj->name) + i + 1);
    if (GET_OBJ_RNUM(obj) < 0 || obj->name != obj_proto[GET_OBJ_RNUM(obj)].name)
      free(obj->name);
    obj->name = new_name;
  }
}



void name_to_drinkcon(struct obj_data * obj, int type)
{
  char *new_name;

  CREATE(new_name, char, strlen(obj->name) + strlen(drinknames[type]) + 2);
  sprintf(new_name, "%s %s", drinknames[type], obj->name);
  if (GET_OBJ_RNUM(obj) < 0 || obj->name != obj_proto[GET_OBJ_RNUM(obj)].name)
    free(obj->name);
  obj->name = new_name;
}



ACMD(do_drink)
{
  struct obj_data *temp;
  struct affected_type af;
  int amount, weight;
  int on_ground = 0;
  bool must_piss = FALSE;

  one_argument(argument, arg);

  if (IS_NPC(ch))	/* Cannot use GET_COND() on mobs. */
    return;

  must_piss = ((GET_COND(ch, THIRST) < 8) && (GET_COND(ch, THIRST) > 3));
  if (must_piss) {
    send_to_char("Your bladder is about to explode.\r\n The last thing on your mind is drinking!\n\r", ch);
    return;
  }

  if (!*arg) {
    send_to_char("Drink from what?\r\n", ch);
    return;
  }
  if (!(temp = get_obj_in_list_vis(ch, arg, ch->carrying))) {
    if (!(temp = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents))) {
      send_to_char("You can't find it!\r\n", ch);
      return;
    } else
      on_ground = 1;
  }
  if ((GET_OBJ_TYPE(temp) != ITEM_DRINKCON) &&
      (GET_OBJ_TYPE(temp) != ITEM_FOUNTAIN)) {
    send_to_char("You can't drink from that!\r\n", ch);
    return;
  }
  if (on_ground && (GET_OBJ_TYPE(temp) == ITEM_DRINKCON)) {
    send_to_char("You have to be holding that to drink from it.\r\n", ch);
    return;
  }
  if ((GET_COND(ch, DRUNK) > 10) && (GET_COND(ch, THIRST) > 0)) {
    /* The pig is drunk */
    send_to_char("You can't seem to get close enough to your mouth.\r\n", ch);
    act("$n tries to drink but misses $s mouth!", TRUE, ch, 0, 0, TO_ROOM);
    return;
  }
  if ((GET_COND(ch, FULL) > 20) && (GET_COND(ch, THIRST) > 0)) {
    send_to_char("Your stomach can't contain anymore!\r\n", ch);
    return;
  }
  if (!GET_OBJ_VAL(temp, 1)) {
    send_to_char("It's empty.\r\n", ch);
    return;
  }
  if (subcmd == SCMD_DRINK) {
    sprintf(buf, "$n drinks %s from $p.", drinks[GET_OBJ_VAL(temp, 2)]);
    act(buf, TRUE, ch, temp, 0, TO_ROOM);

    sprintf(buf, "You drink the %s.\r\n", drinks[GET_OBJ_VAL(temp, 2)]);
    send_to_char(buf, ch);

    if (drink_aff[GET_OBJ_VAL(temp, 2)][DRUNK] > 0)
      amount = (25 - GET_COND(ch, THIRST)) / drink_aff[GET_OBJ_VAL(temp, 2)][DRUNK];
    else
      amount = number(3, 10);

  } else {
    act("$n sips from $p.", TRUE, ch, temp, 0, TO_ROOM);
    sprintf(buf, "It tastes like %s.\r\n", drinks[GET_OBJ_VAL(temp, 2)]);
    send_to_char(buf, ch);
    amount = 1;
  }

  amount = MIN(amount, GET_OBJ_VAL(temp, 1));

  /* You can't subtract more than the object weighs */
  weight = MIN(amount, GET_OBJ_WEIGHT(temp));

  weight_change_object(temp, -weight);	/* Subtract amount */

  gain_condition(ch, DRUNK,
	 (int) ((int) drink_aff[GET_OBJ_VAL(temp, 2)][DRUNK] * amount) / 4);

  gain_condition(ch, FULL,
	  (int) ((int) drink_aff[GET_OBJ_VAL(temp, 2)][FULL] * amount) / 4);

  gain_condition(ch, THIRST,
	(int) ((int) drink_aff[GET_OBJ_VAL(temp, 2)][THIRST] * amount) / 4);

  if (GET_COND(ch, DRUNK) > 10)
    send_to_char("You feel drunk.\r\n", ch);

  if (GET_COND(ch, THIRST) > 20)
    send_to_char("You don't feel thirsty any more.\r\n", ch);

  if (GET_COND(ch, FULL) > 20)
    send_to_char("You are full.\r\n", ch);

  if (GET_OBJ_VAL(temp, 3)) {	/* The shit was poisoned ! */
    send_to_char("Oops, it tasted rather strange!\r\n", ch);
    act("$n chokes and utters some strange sounds.", TRUE, ch, 0, 0, TO_ROOM);

    af.type = SPELL_POISON;
    af.duration = amount * 3;
    af.modifier = 0;
    af.location = APPLY_NONE;
    af.bitvector = AFF_POISON;
    affect_join(ch, &af, FALSE, FALSE, FALSE, FALSE);
  }
  /* empty the container, and no longer poison. */
  GET_OBJ_VAL(temp, 1) -= amount;
  if (!GET_OBJ_VAL(temp, 1)) {	/* The last bit */
    GET_OBJ_VAL(temp, 2) = 0;
    GET_OBJ_VAL(temp, 3) = 0;
    name_from_drinkcon(temp);
  }
  return;
}



ACMD(do_eat)
{
  struct obj_data *food;
  struct affected_type af;
  int amount;

  one_argument(argument, arg);

  if (IS_NPC(ch))	/* Cannot use GET_COND() on mobs. */
    return;

  if (!*arg) {
    send_to_char("Eat what?\r\n", ch);
    return;
  }
  if (!(food = get_obj_in_list_vis(ch, arg, ch->carrying))) {
    sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
    send_to_char(buf, ch);
    return;
  }
  if (subcmd == SCMD_TASTE && ((GET_OBJ_TYPE(food) == ITEM_DRINKCON) ||
			       (GET_OBJ_TYPE(food) == ITEM_FOUNTAIN))) {
    do_drink(ch, argument, 0, SCMD_SIP);
    return;
  }
  if ((GET_OBJ_TYPE(food) != ITEM_FOOD) && (GET_LEVEL(ch) < LVL_GOD)) {
    send_to_char("You can't eat THAT!\r\n", ch);
    return;
  }
  if (GET_COND(ch, FULL) > 20) {/* Stomach full */
    send_to_char("You are too full to eat more!\r\n", ch);
    return;
  }
  if (subcmd == SCMD_EAT) {
    act("You eat $p.", FALSE, ch, food, 0, TO_CHAR);
    act("$n eats $p.", TRUE, ch, food, 0, TO_ROOM);
  } else {
    act("You nibble a little bit of $p.", FALSE, ch, food, 0, TO_CHAR);
    act("$n tastes a little bit of $p.", TRUE, ch, food, 0, TO_ROOM);
  }

  amount = (subcmd == SCMD_EAT ? GET_OBJ_VAL(food, 0) : 1);

  gain_condition(ch, FULL, amount);

  if (GET_COND(ch, FULL) > 20)
    send_to_char("You are full.\r\n", ch);

  if (GET_OBJ_VAL(food, 3) && (GET_LEVEL(ch) < LVL_IMMORT)) {
    /* The shit was poisoned ! */
    send_to_char("Oops, that tasted rather strange!\r\n", ch);
    act("$n coughs and utters some strange sounds.", FALSE, ch, 0, 0, TO_ROOM);

    af.type = SPELL_POISON;
    af.duration = amount * 2;
    af.modifier = 0;
    af.location = APPLY_NONE;
    af.bitvector = AFF_POISON;
    affect_join(ch, &af, FALSE, FALSE, FALSE, FALSE);
  }
  if (subcmd == SCMD_EAT)
    extract_obj(food);
  else {
    if (!(--GET_OBJ_VAL(food, 0))) {
      send_to_char("There's nothing left now.\r\n", ch);
      extract_obj(food);
    }
  }
}


ACMD(do_pour)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  struct obj_data *from_obj = NULL, *to_obj = NULL;
  int amount;

  two_arguments(argument, arg1, arg2);

  if (subcmd == SCMD_POUR) {
    if (!*arg1) {		/* No arguments */
      send_to_char("From what do you want to pour?\r\n", ch);
      return;
    }
    if (!(from_obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
      send_to_char("You can't find it!\r\n", ch);
      return;
    }
    if (GET_OBJ_TYPE(from_obj) != ITEM_DRINKCON) {
      send_to_char("You can't pour from that!\r\n", ch);
      return;
    }
  }
  if (subcmd == SCMD_FILL) {
    if (!*arg1) {		/* no arguments */
      send_to_char("What do you want to fill?  And what are you filling it from?\r\n", ch);
      return;
    }
    if (!(to_obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
      send_to_char("You can't find it!\r\n", ch);
      return;
    }
    if (GET_OBJ_TYPE(to_obj) != ITEM_DRINKCON) {
      act("You can't fill $p!", FALSE, ch, to_obj, 0, TO_CHAR);
      return;
    }
    if (!*arg2) {		/* no 2nd argument */
      act("What do you want to fill $p from?", FALSE, ch, to_obj, 0, TO_CHAR);
      return;
    }
    if (!(from_obj = get_obj_in_list_vis(ch, arg2, world[ch->in_room].contents))) {
      sprintf(buf, "There doesn't seem to be %s %s here.\r\n", AN(arg2), arg2);
      send_to_char(buf, ch);
      return;
    }
    if (GET_OBJ_TYPE(from_obj) != ITEM_FOUNTAIN) {
      act("You can't fill something from $p.", FALSE, ch, from_obj, 0, TO_CHAR);
      return;
    }
  }
  if (GET_OBJ_VAL(from_obj, 1) == 0) {
    act("The $p is empty.", FALSE, ch, from_obj, 0, TO_CHAR);
    return;
  }
  if (subcmd == SCMD_POUR) {	/* pour */
    if (!*arg2) {
      send_to_char("Where do you want it?  Out or in what?\r\n", ch);
      return;
    }
    if (!str_cmp(arg2, "out")) {
      act("$n empties $p.", TRUE, ch, from_obj, 0, TO_ROOM);
      act("You empty $p.", FALSE, ch, from_obj, 0, TO_CHAR);

      weight_change_object(from_obj, -GET_OBJ_VAL(from_obj, 1)); /* Empty */

      GET_OBJ_VAL(from_obj, 1) = 0;
      GET_OBJ_VAL(from_obj, 2) = 0;
      GET_OBJ_VAL(from_obj, 3) = 0;
      name_from_drinkcon(from_obj);

      return;
    }
    if (!(to_obj = get_obj_in_list_vis(ch, arg2, ch->carrying))) {
      send_to_char("You can't find it!\r\n", ch);
      return;
    }
    if ((GET_OBJ_TYPE(to_obj) != ITEM_DRINKCON) &&
	(GET_OBJ_TYPE(to_obj) != ITEM_FOUNTAIN)) {
      send_to_char("You can't pour anything into that.\r\n", ch);
      return;
    }
  }
  if (to_obj == from_obj) {
    send_to_char("A most unproductive effort.\r\n", ch);
    return;
  }
  if ((GET_OBJ_VAL(to_obj, 1) != 0) &&
      (GET_OBJ_VAL(to_obj, 2) != GET_OBJ_VAL(from_obj, 2))) {
    send_to_char("There is already another liquid in it!\r\n", ch);
    return;
  }
  if (!(GET_OBJ_VAL(to_obj, 1) < GET_OBJ_VAL(to_obj, 0))) {
    send_to_char("There is no room for more.\r\n", ch);
    return;
  }
  if (subcmd == SCMD_POUR) {
    sprintf(buf, "You pour the %s into the %s.",
	    drinks[GET_OBJ_VAL(from_obj, 2)], arg2);
    send_to_char(buf, ch);
  }
  if (subcmd == SCMD_FILL) {
    act("You gently fill $p from $P.", FALSE, ch, to_obj, from_obj, TO_CHAR);
    act("$n gently fills $p from $P.", TRUE, ch, to_obj, from_obj, TO_ROOM);
  }
  /* New alias */
  if (GET_OBJ_VAL(to_obj, 1) == 0)
    name_to_drinkcon(to_obj, GET_OBJ_VAL(from_obj, 2));

  /* First same type liq. */
  GET_OBJ_VAL(to_obj, 2) = GET_OBJ_VAL(from_obj, 2);

  /* Then how much to pour */
  GET_OBJ_VAL(from_obj, 1) -= (amount =
			 (GET_OBJ_VAL(to_obj, 0) - GET_OBJ_VAL(to_obj, 1)));

  GET_OBJ_VAL(to_obj, 1) = GET_OBJ_VAL(to_obj, 0);

  if (GET_OBJ_VAL(from_obj, 1) < 0) {	/* There was too little */
    GET_OBJ_VAL(to_obj, 1) += GET_OBJ_VAL(from_obj, 1);
    amount += GET_OBJ_VAL(from_obj, 1);
    GET_OBJ_VAL(from_obj, 1) = 0;
    GET_OBJ_VAL(from_obj, 2) = 0;
    GET_OBJ_VAL(from_obj, 3) = 0;
    name_from_drinkcon(from_obj);
  }
  /* Then the poison boogie */
  GET_OBJ_VAL(to_obj, 3) =
    (GET_OBJ_VAL(to_obj, 3) || GET_OBJ_VAL(from_obj, 3));

  /* And the weight boogie */
  weight_change_object(from_obj, -amount);
  weight_change_object(to_obj, amount);	/* Add weight */
}



void wear_message(struct char_data * ch, struct obj_data * obj, int where)
{
  const char *wear_messages[][2] = {
    {"$n lights $p and holds it.",
    "You light $p and hold it."},

    {"$n slides $p on to $s right ring finger.",
    "You slide $p on to your right ring finger."},

    {"$n slides $p on to $s left ring finger.",
    "You slide $p on to your left ring finger."},

    {"$n wears $p around $s neck.",
    "You wear $p around your neck."},

    {"$n wears $p around $s neck.",
    "You wear $p around your neck."},

    {"$n wears $p on $s body.",
    "You wear $p on your body."},

    {"$n wears $p on $s head.",
    "You wear $p on your head."},

    {"$n puts $p on $s legs.",
    "You put $p on your legs."},

    {"$n wears $p on $s feet.",
    "You wear $p on your feet."},

    {"$n puts $p on $s hands.",
    "You put $p on your hands."},

    {"$n wears $p on $s arms.",
    "You wear $p on your arms."},

    {"$n straps $p around $s arm as a shield.",
    "You start to use $p as a shield."},

    {"$n wears $p about $s body.",
    "You wear $p around your body."},

    {"$n wears $p around $s waist.",
    "You wear $p around your waist."},

    {"$n puts $p on around $s right wrist.",
    "You put $p on around your right wrist."},

    {"$n puts $p on around $s left wrist.",
    "You put $p on around your left wrist."},

    {"$n wields $p.",
    "You wield $p."},

    {"$n grabs $p.",
    "You grab $p."}
  };

  act(wear_messages[where][0], TRUE, ch, obj, 0, TO_ROOM);
  act(wear_messages[where][1], FALSE, ch, obj, 0, TO_CHAR);
}



void perform_wear(struct char_data * ch, struct obj_data * obj, int where)
{
  /*
   * ITEM_WEAR_TAKE is used for objects that do not require special bits
   * to be put into that position (e.g. you can hold any object, not just
   * an object with a HOLD bit.)
   */

  int wear_bitvectors[] = {
    ITEM_WEAR_TAKE, ITEM_WEAR_FINGER, ITEM_WEAR_FINGER, ITEM_WEAR_NECK,
    ITEM_WEAR_NECK, ITEM_WEAR_BODY, ITEM_WEAR_HEAD, ITEM_WEAR_LEGS,
    ITEM_WEAR_FEET, ITEM_WEAR_HANDS, ITEM_WEAR_ARMS, ITEM_WEAR_SHIELD,
    ITEM_WEAR_ABOUT, ITEM_WEAR_WAIST, ITEM_WEAR_WRIST, ITEM_WEAR_WRIST,
    ITEM_WEAR_WIELD, ITEM_WEAR_TAKE, ITEM_WEAR_SOUL
  };

  const char *already_wearing[] = {
    "You're already using a light.\r\n",
    "YOU SHOULD NEVER SEE THIS MESSAGE.  PLEASE REPORT.\r\n",
    "You're already wearing something on both of your ring fingers.\r\n",
    "YOU SHOULD NEVER SEE THIS MESSAGE.  PLEASE REPORT.\r\n",
    "You can't wear anything else around your neck.\r\n",
    "You're already wearing something on your body.\r\n",
    "You're already wearing something on your head.\r\n",
    "You're already wearing something on your legs.\r\n",
    "You're already wearing something on your feet.\r\n",
    "You're already wearing something on your hands.\r\n",
    "You're already wearing something on your arms.\r\n",
    "You're already using a shield.\r\n",
    "You're already wearing something about your body.\r\n",
    "You already have something around your waist.\r\n",
    "YOU SHOULD NEVER SEE THIS MESSAGE.  PLEASE REPORT.\r\n",
    "You're already wearing something around both of your wrists.\r\n",
    "You're already wielding a weapon.\r\n",
    "You're already holding something.\r\n",
    "You allready have a soul.\r\n"
  };

  /* first, make sure that the wear position is valid. */
  if (!CAN_WEAR(obj, wear_bitvectors[where])) {
    act("You can't wear $p there.", FALSE, ch, obj, 0, TO_CHAR);
    return;
  }
  /* for neck, finger, and wrist, try pos 2 if pos 1 is already full */
  if ((where == WEAR_FINGER_R) || (where == WEAR_NECK_1) || (where == WEAR_WRIST_R))
    if (GET_EQ(ch, where))
      where++;

  if (GET_EQ(ch, where)) {
    send_to_char(already_wearing[where], ch);
    return;
  			 }

  if (!wear_otrigger(obj, ch, where))
    return;

  wear_message(ch, obj, where);
  obj_from_char(obj);
  equip_char(ch, obj, where);
}

int find_eq_pos(struct char_data * ch, struct obj_data * obj, char *arg)
{
  int where = -1;

  /* \r to prevent explicit wearing. Don't use \n, it's end-of-array marker. */
  const char *keywords[] = {
    "\r!RESERVED!",
    "finger",
    "\r!RESERVED!",
    "neck",
    "\r!RESERVED!",
    "body",
    "head",
    "legs",
    "feet",

    "hands",
    "arms",
    "shield",
    "about",
    "waist",
    "wrist",
    "\r!RESERVED!",
    "\r!RESERVED!",
    "\r!RESERVED!",
    "\n"
  };

  if (!arg || !*arg) {
    if (CAN_WEAR(obj, ITEM_WEAR_FINGER))      where = WEAR_FINGER_R;
    if (CAN_WEAR(obj, ITEM_WEAR_NECK))        where = WEAR_NECK_1;
    if (CAN_WEAR(obj, ITEM_WEAR_BODY))        where = WEAR_BODY;
    if (CAN_WEAR(obj, ITEM_WEAR_HEAD))        where = WEAR_HEAD;
    if (CAN_WEAR(obj, ITEM_WEAR_LEGS))        where = WEAR_LEGS;
    if (CAN_WEAR(obj, ITEM_WEAR_FEET))        where = WEAR_FEET;
    if (CAN_WEAR(obj, ITEM_WEAR_HANDS))       where = WEAR_HANDS;
    if (CAN_WEAR(obj, ITEM_WEAR_ARMS))        where = WEAR_ARMS;
    if (CAN_WEAR(obj, ITEM_WEAR_SHIELD))      where = WEAR_SHIELD;
    if (CAN_WEAR(obj, ITEM_WEAR_ABOUT))       where = WEAR_ABOUT;
    if (CAN_WEAR(obj, ITEM_WEAR_WAIST))       where = WEAR_WAIST;
    if (CAN_WEAR(obj, ITEM_WEAR_WRIST))       where = WEAR_WRIST_R;
    if (CAN_WEAR(obj, ITEM_WEAR_SOUL))	      where = WEAR_SOUL;
  } else {
    if (((where = search_block(arg, keywords, FALSE)) < 0) || (*arg=='!')) {
      sprintf(buf, "'%s'?  What part of your body is THAT?\r\n", arg);
      send_to_char(buf, ch);
      return -1;
    }
  }

  return (where);
}

ACMD(do_wear)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  struct obj_data *obj, *next_obj;
  int where, dotmode, items_worn = 0;

  two_arguments(argument, arg1, arg2);

  if (!*arg1) {
    send_to_char("Wear what?\r\n", ch);
    return;
  }
  dotmode = find_all_dots(arg1);

  if (*arg2 && (dotmode != FIND_INDIV)) {
    send_to_char("You can't specify the same body location for more than one item!\r\n", ch);
    return;
  }
  if (dotmode == FIND_ALL) {
    for (obj = ch->carrying; obj; obj = next_obj) {
      next_obj = obj->next_content;
      if (CAN_SEE_OBJ(ch, obj) && (where = find_eq_pos(ch, obj, 0)) >= 0) {
	items_worn++;
	perform_wear(ch, obj, where);
      }
    }
    if (!items_worn)
      send_to_char("You don't seem to have anything wearable.\r\n", ch);
  } else if (dotmode == FIND_ALLDOT) {
    if (!*arg1) {
      send_to_char("Wear all of what?\r\n", ch);
      return;
    }
    if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
      sprintf(buf, "You don't seem to have any %ss.\r\n", arg1);
      send_to_char(buf, ch);
    } else
      while (obj) {
	next_obj = get_obj_in_list_vis(ch, arg1, obj->next_content);
	if ((where = find_eq_pos(ch, obj, 0)) >= 0)
	  perform_wear(ch, obj, where);
	else
	  act("You can't wear $p.", FALSE, ch, obj, 0, TO_CHAR);
	obj = next_obj;
      }
  } else {
    if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
      sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg1), arg1);
      send_to_char(buf, ch);
    } else if (GET_LEVEL(ch) < GET_OBJ_LEVEL(obj))
      send_to_char("You are not experienced enough to use that.\r\n", ch);
    else {
      if ((where = find_eq_pos(ch, obj, arg2)) >= 0)
	perform_wear(ch, obj, where);
      else if (!*arg2)
	act("You can't wear $p.", FALSE, ch, obj, 0, TO_CHAR);
    }
  }
}



ACMD(do_wield)
{
  struct obj_data *obj;

  one_argument(argument, arg);

  if (!*arg)
    send_to_char("Wield what?\r\n", ch);
  else if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
    sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
    send_to_char(buf, ch);
  } else {

    if (!CAN_WEAR(obj, ITEM_WEAR_WIELD)) {
      send_to_char("You can't wield that.\r\n", ch);
      return; }

    if (GET_OBJ_WEIGHT(obj) > str_app[STRENGTH_APPLY_INDEX(ch)].wield_w) {
      send_to_char("It's too heavy for you to use.\r\n", ch);
      return; }

      perform_wear(ch, obj, WEAR_WIELD);
  }
}


ACMD(do_grab)
{
  struct obj_data *obj;

  one_argument(argument, arg);

  if (!*arg) {
    send_to_char("Hold what?\r\n", ch);
    return; }

  /* chars are allowed to hold lights, even when it's dark */
  if ( (obj = get_obj_in_list(arg, ch->carrying)) &&
         (GET_OBJ_TYPE(obj) == ITEM_LIGHT) ) {   
         perform_wear(ch, obj, WEAR_LIGHT);
         return; }

  if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
    sprintf(buf, "You don't seem to have %s %s.\r\n", AN(arg), arg);
    send_to_char(buf, ch);
    return; }
  
      if (!CAN_WEAR(obj, ITEM_WEAR_HOLD) && GET_OBJ_TYPE(obj) != ITEM_WAND &&
      GET_OBJ_TYPE(obj) != ITEM_STAFF && GET_OBJ_TYPE(obj) != ITEM_SCROLL &&
	  GET_OBJ_TYPE(obj) != ITEM_POTION) {
	send_to_char("You can't hold that.\r\n", ch);
        return; }

/* Passed validity checks, hold the object */
	perform_wear(ch, obj, WEAR_HOLD);
}

void perform_remove(struct char_data * ch, int pos)
{
  struct obj_data *obj;

  if (!(obj = GET_EQ(ch, pos)))
    log("SYSERR: perform_remove: bad pos %d passed.", pos);
  else if (IS_OBJ_STAT(obj, ITEM_NODROP))
    act("You can't remove $p, it must be CURSED!", FALSE, ch, obj, 0, TO_CHAR);
  else if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch))
    act("$p: you can't carry that many items!", FALSE, ch, obj, 0, TO_CHAR);
  else {
    if (!remove_otrigger(obj, ch))
     return;
    obj_to_char(unequip_char(ch, pos), ch);
    GET_OBJ_IT(ch) = obj;
    act("You stop using $p.", FALSE, ch, obj, 0, TO_CHAR);
    act("$n stops using $p.", TRUE, ch, obj, 0, TO_ROOM);
  }
}



ACMD(do_remove)
{
  int i, dotmode, found;
  obj_data *obj;

  one_argument(argument, arg);

  if (!*arg) {
    send_to_char("Remove what?\r\n", ch);
    return;
  }
  dotmode = find_all_dots(arg);

  if (dotmode == FIND_ALL) {
    found = 0;
    for (i = 0; i < (NUM_WEARS - 1); i++)
      if (GET_EQ(ch, i)) {
	perform_remove(ch, i);
	found = 1;
      }
    if (!found)
      send_to_char("You're not using anything.\r\n", ch);
  } else if (dotmode == FIND_ALLDOT) {
    if (!*arg)
      send_to_char("Remove all of what?\r\n", ch);
    else {
      found = 0;
      for (i = 0; i < NUM_WEARS; i++)
	if (GET_EQ(ch, i) && CAN_SEE_OBJ(ch, GET_EQ(ch, i)) &&
	    isname(arg, GET_EQ(ch, i)->name)) {
	  perform_remove(ch, i);
	  found = 1;
	}
      if (!found) {
	sprintf(buf, "You don't seem to be using any %ss.\r\n", arg);
	send_to_char(buf, ch);
      }
    }
  } else {

     /* chars are allowed to remove lights, when dark or blind. */
     if ( (obj = GET_EQ(ch, 0)) && (isname(arg, obj->name))) {
     perform_remove(ch, 0);
     return; }

    /* Returns object pointer but we don't need it, just true/false. */
    if (!get_object_in_equip_vis(ch, arg, ch->equipment, &i)) {
      sprintf(buf, "You don't seem to be using %s %s.\r\n", AN(arg), arg);
      send_to_char(buf, ch);
    } else
      perform_remove(ch, i);
  }
}

ACMD(do_compare)
{
    char arg1[MAX_STRING_LENGTH];
    char arg2[MAX_STRING_LENGTH];
    struct obj_data *obj1;
    struct obj_data *obj2;
    int value1 = 0;
    int value2 = 0;
    char *msg = NULL;

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

    if (!(obj1 = get_obj_in_list_vis(ch, arg1, ch->carrying)))
    {
        send_to_char( "You do not have that item.\n\r", ch );
        return;
    }

    if (arg2[0] == '\0')
    {
        for (obj2 = ch->carrying; obj2; obj2 = obj2->next_content)
        {
            if ( !((obj2->obj_flags.type_flag == ITEM_WEAPON) ||
                   (obj2->obj_flags.type_flag == ITEM_FIREWEAPON) ||
                   (obj2->obj_flags.type_flag == ITEM_ARMOR) ||
                   (obj2->obj_flags.type_flag == ITEM_WORN))
            &&   CAN_SEE_OBJ(ch, obj2)
            &&   obj1->obj_flags.type_flag == obj2->obj_flags.type_flag
            && CAN_GET_OBJ(ch, obj2) )
                break;
        }

        if (!obj2)
        {
            send_to_char( "You aren't wearing anything comparable.\n\r", ch );
            return;
        }
    }
    else
    {
        if (!(obj2 = get_obj_in_list_vis(ch, arg2, ch->carrying)))
        {
            send_to_char( "You do not have that item.\n\r", ch );
            return;
        }
    }

    if (obj1 == obj2)
    {
        msg = "You compare $p to itself.  It looks about the same.";
    }
    else if ( obj1->obj_flags.type_flag != obj2->obj_flags.type_flag )
    {
        msg = "You can't compare $p and $P.";
    }
    else
    {
        switch (obj1->obj_flags.type_flag)
        {
        default:
            msg = "You can't compare $p and $P.";
            break;

        case ITEM_ARMOR:
            value1 = obj1->obj_flags.value[0];
            value2 = obj2->obj_flags.value[0];
            break;

        case ITEM_WEAPON:
            value1 = obj1->obj_flags.value[1] + obj1->obj_flags.value[2];
            value2 = obj2->obj_flags.value[1] + obj2->obj_flags.value[2];
            break;
        }
    }

    if (!msg)
    {
             if (value1 == value2) msg = "$p and $P look about the same.";
        else if (value1  > value2) msg = "$p looks better than $P.";
        else                         msg = "$p looks worse than $P.";
    }

    act(msg, FALSE, ch, obj1, obj2, TO_CHAR);
    return;
}