/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

objects.c				Activities dealing with the
					manipulation of objects are in
					this file... get/put/eat/etc

		******** Heavily modified and expanded ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** Heavily modified and expanded ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
*************************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "acmd.h"
#include "handler.h"
#include "db.h"
#include "magic.h"
#include "mudlimits.h"
#include "fight.h"
#include "affect.h"
#include "quest.h"
#include "lists.h"
#include "global.h"
#include "boards.h"
#include "htown.h"
#include "plshop.h"
#include "nature.h"
#include "darkenelf.h"

/* extern variables */
extern struct str_app_type str_app[];
extern struct htown_data htowns[];
extern char	*drinks[];
extern int	drink_aff[][3];
extern char	*dirs[NUM_OF_DIRS];
extern char	*comm_dirs[NUM_OF_DIRS];
extern char	*rev_dir_str[NUM_OF_DIRS];

// external functions
void do_room_dump(chdata *ch, obdata *obj);
int check_room_affects(chdata *ch, int room);
int ManyObjs(char *arg, char *ptr);

/* (RoA) for obj_hits  decrements hit total on object, checks if
         object has been rendered useless and unequips if so */
void damage_object(obdata *ob, chdata *ch)
{
   int slot;

   if (!ob) return;
   if (MAX_OBJ_HITS(ob) == -1) return;  /* indestructable */

   if (OBJ_HITS(ob)-- > 0) 
   {
     // should send message notifying ch that obj has been damaged
     return;
   }

   /* else the object is <= 1 hits */
   OBJ_HITS(ob) = 0;

   if (ch)  /* a player is carrying or has it as eq */
   {
     if (ob->carried_by && ob->carried_by != ch)
     {
        log("SYSERR: Invalid carrier in damage_object.");
        return;
     }

     if (ob->carried_by) /* in inventory */
     {
        act("%B$p has been damaged beyond repair!%0", TRUE, ch, ob, 0,TO_CHAR);
        return;
     }
     else
     {
        for (slot = 0; slot < MAX_WEAR; slot++)
          if (ob == EQ(ch, slot))
             break;

        if (slot == MAX_WEAR)
        {
          log("SYSERR: Invalid equipment slot in damage_object.");
          return;
        }

        act("%B$p has been damaged beyond repair!%0", TRUE, ch, ob, 0,TO_CHAR);
        obj_to_char(unequip_char(ch, slot, TRUE), ch);
     }
   }
   else  /* its lying around on the ground */
   {
      act("$p decays into nothingness.",TRUE,0,ob,0,TO_ROOM);
      extract_obj(ob);
   }
}

ACMD(do_quaff)
{
   obdata *temp;
   int  i;
   BOOL equipped = FALSE;

   one_argument(argument, buf);

   if (!(temp = get_obj_in_list_vis(ch, buf, ch->carrying))) {
      temp = EQ(ch, W_HOLD);
      equipped = TRUE;
      if (!temp || !isname(buf, temp->name)) {
         act("You do not have that item.", FALSE, ch, 0, 0, TO_CHAR);
         return;
      }
   }

   if (temp->type_flag != ITEM_POTION) {
      act("You can only quaff potions.", FALSE, ch, 0, 0, TO_CHAR);
      return;
   }

   act("$n quaffs $p.", TRUE, ch, temp, 0, TO_ROOM);
   act("You quaff $p which dissolves.", FALSE, ch, temp, 0, TO_CHAR);

   for (i = 1; i < 4; i++)
     if (temp->value[i] >= 1)
     {
       if (number(1, 101) < SUCCESS_RATE(temp))
         do_cast_spell(temp->value[i], ch, "", SPELL_TYPE_POTION, ch, NULL);
       else
        act("$p has no affect on you.", FALSE, ch, temp, 0, TO_CHAR);
     }

   if (equipped)
      unequip_char(ch, W_HOLD, TRUE);

   extract_obj(temp);
}


ACMD(do_recite)
{
   obdata *scroll, *obj;
   chdata *victim;
   int  i, bits;
   BOOL equipped = FALSE;
   BOOL passed = TRUE;

   obj = 0;
   victim = 0;
   argument = one_argument(argument, buf);

   if (!(scroll = get_obj_in_list_vis(ch, buf, ch->carrying)))
   {
      scroll = EQ(ch, W_HOLD);
      equipped = TRUE;

      if ((scroll == 0) || !isname(buf, scroll->name)) {
         act("You do not have that item.", FALSE, ch, 0, 0, TO_CHAR);
         return;
      }
   }

   if (scroll->type_flag != ITEM_SCROLL) {
      act("Recite is normally used for scrolls.", FALSE, ch, 0, 0, TO_CHAR);
      return;
   }

   if (ROOM_FLAGGED(ch->in_room, NO_MAGIC))
   {
     send_to_char("The atmosphere surrounding you prevents the use of magic.\n\r",ch);
     return;
   }

   if (*argument) 
   {
      bits = generic_find(argument, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP | FIND_CHAR_ROOM, ch, &victim, &obj);
      if (!bits) {
         send_to_char("No such thing around to recite the scroll on.\n\r", ch);
         return;
      }
   } 
   else
     victim = ch;

   act("$n recites $p.", TRUE, ch, scroll, 0, TO_ROOM);
   act("You recite $p which dissolves.", FALSE, ch, scroll, 0, TO_CHAR);

   if (equipped)
      unequip_char(ch, W_HOLD, TRUE);

   for (i = 1; i < 4; i++)
      if (scroll->value[i] >= 1)
      {
       passed = TRUE;
       if (SPELL_FLAGGED(scroll->value[i], S_VIOLENT))
       {

        if (ROOM_FLAGGED(ch->in_room, PEACEFUL))
        {
           send_to_char("A force beyond comprehension counteracts violence in this area.\n\r",ch);
           passed = FALSE;
        }

        if (GET_GSKILL(ch, GSKILL_RUNIC) < number(1, 101))
        {
           act("You fail to decipher $p.", FALSE, ch, scroll, 0, TO_CHAR);
           passed = FALSE;
        }

        if (ch && victim && passed)
        {
          passed = check_truce(ch, victim);
          if (IS_PC(victim) && IS_PC(ch) && !IN_ARENA(ch) && (!IS_ASSASSIN(victim) || !IS_ASSASSIN(ch)))
          {
            send_to_char("%1Assassin vs Assassin ONLY%0.\n\r",ch);
            passed = FALSE;
          }
        }
       }
        /* made it through the checks ok */
       if (passed && spell_info[scroll->value[i]].spell_pointer)
       {
         if (number(1, 101) < SUCCESS_RATE(scroll))
           do_cast_spell(scroll->value[i], ch, "", SPELL_TYPE_SCROLL, victim, obj);
         else
          act("$p fails.", FALSE, ch, scroll, victim, TO_CHAR);
       }
      }

   extract_obj(scroll);
}

// moved here from misc... since use is primarily objects... 6/30/98 -jtrhone
// split up a bit as well... 6/30/98 -jtrhone
void do_use_staff(chdata *ch, obdata *stick)
{
  act("$n taps $p three times on the ground.", TRUE, ch, stick, 0, TO_ROOM);
  act("You tap $p three times on the ground.", FALSE, ch, stick, 0, TO_CHAR);
  if (stick->value[2] > 0)   /* Is there any charges left? */
  {
    /* check if spell is violent here */
    if (SPELL_FLAGGED(stick->value[3], S_VIOLENT) && ROOM_FLAGGED(ch->in_room, PEACEFUL))
      {
        send_to_char("Violence is not allowed here.\n\r",ch);
        return;
      }

    stick->value[2]--;
    if (number(1, 101) < SUCCESS_RATE(stick))
      do_cast_spell(stick->value[3], ch, "", SPELL_TYPE_STAFF, 0, 0);
    else
      act("$p fails.", FALSE, ch, stick, 0, TO_CHAR);

    /* delay character a bit to eliminate machinegun affect */
    WAIT_STATE(ch, (PULSE_VIOLENCE * 2));
  }
  else
    act("$p seems powerless.", TRUE, ch, stick, 0, TO_CHAR);
}

void do_use_wand(chdata *ch, obdata *stick, char *arg)
{
  chdata *tch;
  obdata *tob;
  int bits;

  bits = generic_find(arg, FIND_CHAR_ROOM | FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &tch, &tob);
  if (bits)
  {
    if (bits == FIND_CHAR_ROOM)
    {
      act("$n points $p at $N.", TRUE, ch, stick, tch, TO_ROOM);
      act("You point $p at $N.", FALSE, ch, stick, tch, TO_CHAR);
    }
    else
    {
      act("$n points $p at $P.", TRUE, ch, stick, tob, TO_ROOM);
      act("You point $p at $P.", FALSE, ch, stick, tob, TO_CHAR);
    }

    if (stick->value[2] > 0) /* Is there any charges left? */
    {
      /* check if spell is violent here */
      if (SPELL_FLAGGED(stick->value[3], S_VIOLENT))
      {
        if (ROOM_FLAGGED(ch->in_room, PEACEFUL))
        {
          send_to_char("This area is strangely protected against violence.\n\r", ch);
          return;
        }

        if (tch && IS_PC(tch))
          if (!IS_ASSASSIN(ch) || !IS_ASSASSIN(tch))
          {
            send_to_char("You must be an assassin.\n\r",ch);
            return;
          }
      }

      stick->value[2]--;
      if (number(1, 101) < SUCCESS_RATE(stick))
        do_cast_spell(stick->value[3], ch, "", SPELL_TYPE_WAND, tch, tob);
      else
        act("$p fails.", FALSE, ch, stick, 0, TO_CHAR);

      /* delay character a bit to eliminate machinegun affect */
      WAIT_STATE(ch, (PULSE_VIOLENCE * 2));
    }
    else
      act("$p seems powerless.", TRUE, ch, stick, 0, TO_CHAR);
  }
  else
    send_to_char("What should the wand be pointed at?\n\r", ch);
}

void do_use_portal(chdata *ch, obdata *stick)
{
  int rnum;

  if (FIGHTING(ch) || GET_POS(ch) == POS_FIGHTING)
  {
    act("You cannot concentrate enough while fighting!", FALSE, ch, 0, 0, TO_CHAR);
    return;
  }

  act("$n calls forth the power of $p.", TRUE, ch, stick, 0, TO_ROOM);
  act("You call forth the power of $p.", FALSE, ch, stick, 0, TO_CHAR);

  if (ROOM_FLAGGED(ch->in_room, NO_RECALL) || IN_ARENA(ch))
  {
    send_to_char("The atmosphere surrounding you prevents teleportation.\n\r",ch);
    return;
  }

  /* are there any charges left? */
  if (stick->value[2] > 0 && (rnum = real_room(stick->value[3])) > 0)
  {
    if (ZONE_FLAGGED(world[rnum].zone, Z_LOCKED | Z_CLOSED))
    {
      send_to_char("Sorry, destination down for construction.\n\r",ch);
      return;
    }

    stick->value[2]--;
    if (number(1, 101) < SUCCESS_RATE(stick))
    {
      act("$n suddenly vanishes!", TRUE, ch, 0, 0, TO_ROOM);
      char_from_room(ch);
      char_to_room(ch, rnum);
      act("$n suddenly arrives grasping $p!", TRUE, ch, stick, 0, TO_ROOM);
      act("Using $p has teleported you!", FALSE, ch, stick, 0, TO_CHAR);
      do_look_at_room(ch, 0, 0);
      if (check_room_affects(ch, ch->in_room) == CHAR_DIED)
        return;
      if (check_death_trap(ch, NULL))
        return;
      float_sink_char(ch);
    }
    else
      act("$p fails.", FALSE, ch, stick, 0, TO_CHAR);
  }
  else
    act("$p seems powerless.", TRUE, ch, stick, 0, TO_CHAR);
}

void do_use_gem(chdata *ch, obdata *stick)
{
  int num, size;

  if (FIGHTING(ch) || GET_POS(ch) == POS_FIGHTING)
  {
    act("You cannot concentrate enough while fighting!", FALSE, ch, 0, 0, TO_CHAR);
    return;
  }

  act("$n calls forth the power of $p.", TRUE, ch, stick, 0, TO_ROOM);
  act("You call forth the power of $p.", FALSE, ch, stick, 0, TO_CHAR);

  /* are there any charges left? */
  if (stick->value[1] > 0)
  {
    stick->value[1]--;
    if (number(1, 101) < SUCCESS_RATE(stick))
    {
      num = MAX(1, stick->value[2]);
      size = MAX(1, stick->value[3]);
      GET_MANA(ch) += dice(num, size);
      GET_MANA(ch) = MIN(GET_MANA(ch), GET_MAX_MANA(ch));

      act("$p %B%6glows%0 briefly in your hands!", TRUE, ch, stick, 0, TO_CHAR);
      act("$p %B%6glows%0 briefly in $n's hands!", TRUE, ch, stick, 0, TO_ROOM);
    }
    else
      act("$p fails.", FALSE, ch, stick, 0, TO_CHAR);
  }
  else
    act("$p seems powerless.", TRUE, ch, stick, 0, TO_CHAR);

  // for now, one use only on harmonic gems
  stick = unequip_char(ch, W_HOLD, FALSE);
  extract_obj(stick);
}

// to teach madepts (and similar classes eventually) skills/spells
void do_use_tome(chdata *ch, obdata *stick)
{
  int i, num, learned;

  if (FIGHTING(ch) || GET_POS(ch) == POS_FIGHTING)
  {
    act("You cannot concentrate enough while fighting!", FALSE, ch, 0, 0, TO_CHAR);
    return;
  }

  // must be a class which can aquire along the way, eventually all?
  if (!IS_NAT_MADEPT(ch) && !IS_IMMORTAL(ch))
  {
    act("You gain nothing from studying $p.", TRUE, ch, stick, 0, TO_CHAR);
    return;
  }

  act("You study $p.", TRUE, ch, stick, 0, TO_CHAR);
  act("$n studies $p.", TRUE, ch, stick, 0, TO_ROOM);

  // scan all 4 skill slots, learn each based on success rate (and soon runic skill)
  for (num = learned = i = 0; i < 4; i++)
    if (stick->value[i] > 0 && stick->value[i] < MAX_SKILLS)
    {
      num++;
      if (!ch->skills[stick->value[i]].learned || IS_IMMORTAL(ch))
      {
        learned++;

        if (number(1, 101) < SUCCESS_RATE(stick))
        {
          sprintf(buf, "You learn %%B%%6%s%%0 from $p.", skill_names[stick->value[i]]);
          act(buf, FALSE, ch, stick, 0, TO_CHAR);
          act("$n's eyes widen slightly as $e studies $p.", TRUE, ch, stick, 0, TO_ROOM);
    
          // set skill to learned 
          ch->skills[stick->value[i]].learned = TRUE;
        }
 
        // then wax that one off tome
        stick->value[i] = 0;
      }
    }

  if (!num)
    act("$p seems useless.", TRUE, ch, stick, 0, TO_CHAR);
  else
  if (!learned)
    act("You learn nothing new from $p.", TRUE, ch, stick, 0, TO_CHAR);
  else
  if (num == learned) // they learned everything possible...
  {
    act("$p crumbles into nothingness.", TRUE, ch, stick, 0, TO_CHAR);
    stick = unequip_char(ch, W_HOLD, FALSE);
    extract_obj(stick);
  }
}

ACMD(do_use)
{
  obdata *stick = 0;
  char *argu = argument;

  skip_spaces(&argu);
  one_argument(argu, arg);

  if (!EQ(ch, W_HOLD) || !isname(arg, EQ(ch, W_HOLD)->name))
  {
     act("You do not hold that item in your hand.", FALSE, ch, 0, 0, TO_CHAR);
     return;
  }

  if (ROOM_FLAGGED(ch->in_room, NO_MAGIC))
  {
    send_to_char("The atmosphere surrounding you prevents the use of magic.\n\r",ch);
    return;
  }

  stick = EQ(ch, W_HOLD);
  switch(ITEM_TYPE(stick)) {
     case ITEM_STAFF:
       do_use_staff(ch, stick);
       break;

     case ITEM_WAND:
       do_use_wand(ch, stick, argu);
       break;

     case ITEM_PORTAL:
       do_use_portal(ch, stick);
       break;

     case ITEM_GEM:
       do_use_gem(ch, stick);
       break;

     case ITEM_TOME:
       do_use_tome(ch, stick);
       break;

     default:
       send_to_char("That item fails to respond.\n\r", ch);
       break;
  }
}


void perform_put(chdata *ch, obdata *obj, obdata *container)
{
   if (GET_OBJ_WEIGHT(container) + GET_OBJ_WEIGHT(obj) > container->value[0])
      act("$p won't fit in $P.", FALSE, ch, obj, container, TO_CHAR);
   else {
      obj_from_char(obj);
      obj_to_obj(obj, container);
      act("You put $p in $P.", FALSE, ch, obj, container, TO_CHAR);
      act("$n puts $p in $P.", TRUE, ch, obj, container, TO_ROOM);
   }
}

void perform_silent_put(chdata *ch, obdata *obj, obdata *container)
{
   if (GET_OBJ_WEIGHT(container) + GET_OBJ_WEIGHT(obj) > container->value[0])
      act("$p won't fit in $P.", FALSE, ch, obj, container, TO_CHAR);
   else {
      obj_from_char(obj);
      obj_to_obj(obj, container);
   }
}

// Reworked to handle ManyObjs() func. 08/10/98 -callahan
ACMD(do_put)
{
   char	arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH],
     multarg[MAX_INPUT_LENGTH];
   obdata *obj, *next_obj, *container;
   chdata *tmp_char;
   int	obj_dotmode, cont_dotmode, amount;

   two_arguments(argument, arg1, arg2);
   obj_dotmode = find_all_dots(arg1);
   cont_dotmode = find_all_dots(arg2);

   if (cont_dotmode != FIND_INDIV)
      send_to_char("You can only put things into one container at a time.\n\r", ch);
   else if (!*arg1)
      send_to_char("Put what in what?\n\r", ch);
   else if (!*arg2) {
      sprintf(buf, "What do you want to put %s in?\n\r",
	      ((obj_dotmode != FIND_INDIV) ? "them" : "it"));
      S2C();
   } 
   else 
   {
      generic_find(arg2, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP,
		   ch, &tmp_char, &container);
      if (!container) {
	 sprintf(buf, "You don't see a %s here.\n\r", arg2);
	 S2C();
      } else if (ITEM_TYPE(container) != ITEM_CONTAINER) {
	 act("$p is not a container.", FALSE, ch, container, 0, TO_CHAR);
      } else if (IS_SET(container->value[1], CONT_CLOSED)) {
	 send_to_char("You'd better open it first!\n\r", ch);
      } else {
	 if (obj_dotmode == FIND_ALL) {	    /* "put all <container>" case */
	    /* check and make sure the guy has something first */
	    if (container == ch->carrying && !ch->carrying->next_content)
	       send_to_char("You don't seem to have anything to put in it.\n\r", ch);
	    else for (obj = ch->carrying; obj; obj = next_obj) {
	       next_obj = obj->next_content;
	       if (obj != container)
		  perform_put(ch, obj, container);
	    }
	 } else if (obj_dotmode == FIND_ALLDOT) {  /* "put all.x <cont>" case */
	    if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
	       sprintf(buf, "You don't seem to have any %ss.\n\r", arg1);
	       S2C();
	    } else while (obj) {
	       next_obj = get_obj_in_list_vis(ch, arg1, obj->next_content);
	       if (obj != container)
		  perform_put(ch, obj, container);
	       obj = next_obj;
	    }
	 } else {		    /* "put <thing> <container>" case */
           if ((amount = ManyObjs(arg1, multarg)) != 0) {
             strcpy(arg1, multarg);

             while (amount) {
               if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
                 SendChar(tprintf("You aren't carrying %s %s.\n\r",
                                  AN(arg1), arg1), ch);
                 return;
               }

               perform_put(ch, obj, container);
               amount--;
             }
           } else {
	    if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
	       sprintf(buf, "You aren't carrying %s %s.\n\r", AN(arg1), arg1);
	       S2C();
	    } else if (obj == container)
	       send_to_char("You cannot put that in itself :).\n\r", ch);
	    else
	       perform_put(ch, obj, container);
          }
	 }
      }
   }
}

int	can_take_obj(chdata *ch, obdata *obj)
{
   if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) {
      act("You cannot carry that many items.",FALSE, ch, obj, 0,TO_CHAR);
      return FALSE;
   } else if ((IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(ch)) {
      act("You cannot carry that much weight.",FALSE, ch, obj, 0,TO_CHAR);
      return FALSE;
   } else if (!(CAN_WEAR(obj, ITEM_TAKE))) {
      act("You are unable to take $p.",FALSE, ch, obj, 0, TO_CHAR);
      return FALSE;
   }
   return TRUE;
}

void	get_check_money(chdata *ch, obdata *obj)
{
   if ((ITEM_TYPE(obj) == ITEM_MONEY) && (obj->value[0] > 0)) 
   {
      obj_from_char(obj);

      if (obj->value[0] > 1) 
      {
	 sprintf(buf, "There were %d %s.\n\r", obj->value[0], currency_name_plural);
	 S2C();
      }

      GET_GOLD(ch) += obj->value[0];
      extract_obj(obj);
   }
}

void	perform_get_from_container(chdata *ch, obdata *obj,obdata *cont, int mode)
{
   if (mode == FIND_OBJ_INV || can_take_obj(ch, obj)) {
      if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch))
	 sprintf(buf, "%s: You can't hold any more items.\n\r", OBJS(obj, ch));
      else {
         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);

	 if (IS_CORPSE(cont) && (cont->plr_num > 0) && 
	     (IS_PC(ch) || (IS_NPC(ch) && CHARMED(ch))) &&
	     cont->plr_num != GET_IDNUM(ch))
	 {
	   sprintf(buf, "PLRUPD: %s looted %s at %d.",GET_NAME(ch),
		   cont->shdesc, world[ch->in_room].number);
 	   mudlog(buf, BRF, LEV_IMM, TRUE);
	 }

	 // check object they just got in case of immediate quest reward
  	 qcheck_obj_get(ch, obj);
      }
   }
}

// Reworked to handle ManyObjs() func. 08/10/98 -callahan
void	get_from_container(chdata *ch, obdata *cont, char *arg, int mode)
{
   obdata *obj, *next_obj;
   int obj_dotmode, found = 0, amount;
   char multarg[MAX_STRING_LENGTH];

   obj_dotmode = find_all_dots(arg);

   if (IS_SET(cont->value[1], CONT_CLOSED))
      act("$p is closed.", FALSE, ch, cont, 0, TO_CHAR);
   else if (obj_dotmode == FIND_ALL) {
      for (obj = cont->contains; obj; obj = next_obj) {
	 next_obj = obj->next_content;
	 if (CAN_SEE_OBJ(ch, obj)) {
	    found = TRUE;
	    perform_get_from_container(ch, obj, cont, mode);
	 }
      }
      if (!found)
	 act("$p seems to be empty.", FALSE, ch, cont, 0, TO_CHAR);
   } else if (obj_dotmode == FIND_ALLDOT) {
      if (!*arg) {
	 send_to_char("Get all of what?\n\r", ch);
	 return;
      }
      obj = get_obj_in_list_vis(ch, arg, cont->contains);
      while (obj) {
         next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
	 if (CAN_SEE_OBJ(ch, obj)) {
	    found = TRUE;
	    perform_get_from_container(ch, obj, cont, mode);
	 }
	 obj = next_obj;
      }
      if (!found) {
	 sprintf(buf, "You can't find any %ss in $p.", arg);
	 act(buf, FALSE, ch, cont, 0, TO_CHAR);
      }
   } else {
     if ((amount = ManyObjs(arg, multarg)) != 0) {
       strcpy(arg, multarg);

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

         perform_get_from_container(ch, obj, cont, mode);
         amount--;
       }
     } else {
       if (!(obj = get_obj_in_list_vis(ch, arg, cont->contains))) {
	 sprintf(buf, "There doesn't seem to be %s %s in $p.", AN(arg), arg);
	 act(buf, FALSE, ch, cont, 0, TO_CHAR);
     } else
	 perform_get_from_container(ch, obj, cont, mode);
    }
  }
}

int perform_get_from_room(chdata *ch, obdata *obj)
{
  if (can_take_obj(ch, obj) && !INVALID_ROOM(obj->in_room))
  {
    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);

    // check object they just got in case of immediate quest reward
    qcheck_obj_get(ch, obj);
    return TRUE;
  }
  return FALSE;
}

// Modified for ManyObjs() func. 08/10/98 -callahan
void get_from_room(chdata *ch, char *arg)
{
  obdata *obj, *next_obj;
  int	dotmode, found = 0, amount;
  char multarg[MAX_INPUT_LENGTH];

  dotmode = find_all_dots(arg);

  if (dotmode == FIND_ALL) {
    for (obj = world[ch->in_room].contents; obj; obj = next_obj) {
      next_obj = obj->next_content;

      if (CAN_SEE_OBJ(ch, obj)) {
        found = TRUE;
        perform_get_from_room(ch, obj);
      }
    }

    if (!found)
      SendChar("There doesn't seem to be anything here.\n\r", ch);
  } else if (dotmode == FIND_ALLDOT) {
    if (!*arg) {
      SendChar("Get all of what?\n\r", ch);
      return;
    }

    if (!(obj = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents))) {
      sprintf(buf, "You don't see any %ss here.\n\r", arg);
      S2C();
    } else while (obj) {
      next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
      perform_get_from_room(ch, obj);
      obj = next_obj;
    }
  } else {
    if ((amount = ManyObjs(arg, multarg)) != 0) {
      strcpy(arg, multarg);

      while (amount) {
        if (!(obj = get_obj_in_list_vis(ch, arg, world[InRoom(ch)].contents))) {
          SendChar(tprintf("You don't see %s %s here.\n\r", AN(arg), arg), ch);
          return;
        }

        perform_get_from_room(ch, obj);
        amount--;
      }
    } else {
      if (!(obj = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents))) {
	sprintf(buf, "You don't see %s %s here.\n\r", AN(arg), arg);
	S2C();
      } else
        perform_get_from_room(ch, obj);
    }
  }
}


ACMD(do_get)
{
  char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
  int	cont_dotmode, found = 0, mode;
  obdata *cont, *next_cont;
  chdata *tmp_char;

  if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) 
    send_to_char("Your arms are already full!\n\r", ch);
  else {
    two_arguments(argument, arg1, arg2);

    if (!*arg1)
      send_to_char("Get what?\n\r", ch);
    else {
      if (!*arg2)
        get_from_room(ch, arg1);
      else {
        cont_dotmode = find_all_dots(arg2);

        /* use all in inv. and on ground */
        if (cont_dotmode == FIND_ALL) { 
          for (cont = ch->carrying; cont; cont = cont->next_content)
             if (ITEM_TYPE(cont) == ITEM_CONTAINER) {
               found = TRUE;
	       get_from_container(ch, cont, arg1, FIND_OBJ_INV);
	     }

	  for (cont = world[ch->in_room].contents; cont;
               cont = cont->next_content)
            if (CAN_SEE_OBJ(ch, cont) && ITEM_TYPE(cont) == ITEM_CONTAINER) {
              found = TRUE;
	      get_from_container(ch, cont, arg1, FIND_OBJ_ROOM);
	    }

	  if (!found)
	    SendChar("You can't seem to find any containers.\n\r", ch);
	} else if (cont_dotmode == FIND_ALLDOT) {
          if (!*arg2) {
 	    SendChar("Get from all of what?\n\r", ch);
	    return;
	  }
	  cont = get_obj_in_list_vis(ch, arg2, ch->carrying);

	  while (cont) {
	    found = TRUE;
	    next_cont = get_obj_in_list_vis(ch, arg2, cont->next_content);

	    if (ITEM_TYPE(cont) != ITEM_CONTAINER)
	      act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
	    else
	      get_from_container(ch, cont, arg1, FIND_OBJ_INV);

 	    cont = next_cont;
          }
          cont = get_obj_in_list_vis(ch, arg2, world[ch->in_room].contents);

          while (cont) {
  	    found = TRUE;
	    next_cont = get_obj_in_list_vis(ch, arg2, cont->next_content);

	    if (ITEM_TYPE(cont) != ITEM_CONTAINER)
	      act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
	    else
	      get_from_container(ch, cont, arg1, FIND_OBJ_ROOM);

	    cont = next_cont;
          }

          if (!found) {
            sprintf(buf, "You can't seem to find any %ss here.\n\r", arg2);
	    S2C();
	  }
        } else { 
          /* get <items> <container> (no all or all.x) */
 	  mode = generic_find(arg2, 
			      FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP,
 	                      ch, &tmp_char, &cont);
          if (!cont) {
            sprintf(buf, "You don't have %s %s.\n\r", AN(arg2), arg2);
	    S2C();
	  } else if (ITEM_TYPE(cont) != ITEM_CONTAINER)
	    act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
	  else
	    get_from_container(ch, cont, arg1, mode);
        }
      }
    }
  }
}

// modified for runtime currency names  11/28/97 -jtrhone
void	perform_drop_gold(chdata *ch, int amount, byte mode, int don_room)
{
   obdata *obj;

   if (amount <= 0)
      send_to_char("Heh heh heh.. we are jolly funny today, eh?\n\r", ch);
   else 
   if (GET_GOLD(ch) < amount)
      send_to_char("You don't have that much!\n\r", ch);
   else 
   {
      if (mode != SCMD_JUNK) 
      {
	 obj = create_money(amount);
	 if (mode == SCMD_DONATE) 
         {
            sprintf(buf, "You donate some %s!\n\r", currency_name_plural);
            S2C();

            sprintf(buf, "$n donates some %s!", currency_name_plural);
	    act(buf, FALSE, ch, 0, 0, TO_ROOM);

            sprintf(buf, "Some %s suddenly fade into view!\n\r", currency_name_plural);
            send_to_room_not_busy(buf, don_room);

            /* log this here JRhone */
            if (IS_IMMORTAL(ch))
            {
   		sprintf(buf, "%s has donated %d %s.",GET_NAME(ch),amount, currency_name_plural);
  		mudlog(buf, BRF, MAX(LEV_IMM, GET_INVIS_LEV(ch)), TRUE);
	    }
	    obj_to_room(obj, don_room);

	 } 
         else // mode == SCMD_DROP
         {
            sprintf(buf, "You drop some %s.\n\r", currency_name_plural);
            S2C();
            sprintf(buf, "$n drops some %s.", currency_name_plural);
	    act(buf, FALSE, ch, 0, 0, TO_ROOM);

            if (IS_IMMORTAL(ch))
            {
   	       sprintf(buf, "%s has dropped %d %s.",GET_NAME(ch), amount, currency_name_plural);
   	       mudlog(buf, BRF, MAX(LEV_IMM, GET_INVIS_LEV(ch)), TRUE);
 	    }

	    if (ROOM_FLAGGED2(ch->in_room, DUMP))
	      do_room_dump(ch, obj);
	    else
	      float_sink_gold(obj, ch->in_room);
	 }
      } 
      else // mode == SCMD_JUNK
      {
         sprintf(buf, "$n junks some %s?!?", currency_name_plural);
	 act(buf, FALSE, ch, 0, 0, TO_ROOM);

         sprintf(buf, "You junk some %s?!?\n\r", currency_name_plural);
         S2C();
      }

      GET_GOLD(ch) -= amount;
   }
}

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

int perform_drop(chdata *ch, obdata *obj, byte mode, char *sname, sh_int RDR)
{
   int value;
   int vnum = GET_OBJ_VNUM(obj);

   if (IS_SET(OBJ_EXTRAS(obj), ITEM_NODROP) && GET_LEVEL(ch) < LEV_IMM) {
      sprintf(buf, "You can't %s %s, it must be CURSED!\n\r", sname, OBJS(obj, ch));
      S2C();
      return 0;
   }

   if ((mode == SCMD_DONATE) && IS_SET(OBJ_EXTRAS(obj), ITEM_NODONATE)) {
      sprintf(buf, "You can't donate %s.\n\r", OBJS(obj, ch));
      S2C();
      return 0;
   }

   sprintf(buf, "You %s %s.%s\n\r", sname, OBJS(obj, ch), VANISH(mode));
   S2C();
   sprintf(buf, "$n %ss $p.%s", sname, VANISH(mode));
   act(buf, TRUE, ch, obj, 0, TO_ROOM);

   obj_from_char(obj);

   switch(mode) {
   case SCMD_DROP:
      if (ROOM_FLAGGED2(ch->in_room, DUMP))
      {
	do_room_dump(ch, obj);
	return 0;
      }
      float_sink_object(obj, ch->in_room);  /* replaces obj_to_room RoA*/
      if (IS_IMMORTAL(ch)) {
        sprintf(buf, "%s dropped [%d] %s at %d.",GET_NAME(ch),vnum, obj->shdesc, 
                world[ch->in_room].number);
        mudlog(buf, BRF, MAX(LEV_IMM, GET_INVIS_LEV(ch)), TRUE);
      }
      return 0;
      break;
   case SCMD_DONATE:
      SET_BIT(OBJ_EXTRAS2(obj), ITEM_NOAUCTION);
      obj_to_room(obj, RDR);
      /* log this here JRhone */
      if (IS_IMMORTAL(ch)) {
        sprintf(buf, "%s donated [%d] %s.",GET_NAME(ch),vnum,obj->shdesc);
        mudlog(buf, BRF, MAX(LEV_IMM, GET_INVIS_LEV(ch)), TRUE);
      }
      send_to_room("Something suddenly appears amidst a flash of light!\n\r", RDR);
      return 0;
      break;
   case SCMD_JUNK:
      value = MAX(1, MIN(200, obj->cost >> 4));
      extract_obj(obj);
      return value;
      break;
   default:
      log("SYSERR: Incorrect argument passed to perform_drop");
      break;
   }
   return 0;
}

ACMD(do_drop)
{
  obdata *obj, *next_obj;
  byte	mode = SCMD_DROP;
  int	dotmode, amount = 0, num;
  char	*sname, multarg[MAX_INPUT_LENGTH];
  int don_room = 0, home_don_room = 0;
  int don_count = 0, don_num = 0, i;

  switch (subcmd) {
   case SCMD_JUNK:
      sname = "junk";
      mode = SCMD_JUNK;
      break;

   case SCMD_DONATE:
      if (IS_NPC(ch)) return;
      sname = "donate";
      mode = SCMD_DONATE;

      for (i = 0; i < top_of_world; i++)
	if (!ZONE_FLAGGED(world[i].zone, Z_CLOSED) && !ZONE_IDLE(world[i].zone) && 
            !ZONE_FREED(world[i].zone) && !ZONE_FLAGGED(world[i].zone, Z_LOCKED) && 
            ROOM_FLAGGED2(i, DONATION))
	{
	  if ((htowns[GET_HTOWN(ch)].rvnum / 100) == world[i].zone)
	    home_don_room = i; 
	  don_count++;
	}

      if (don_count <= 0) 
      {
	 send_to_char("Sorry, you can't donate anything right now.\n\r", ch);
	 return;
      }

      if (!(don_room = home_don_room))
      {
	don_num = number(1, don_count);

        for(i = 0, don_count = 0; i < top_of_world; i++)
	  if (!ZONE_FLAGGED(world[i].zone, Z_CLOSED) && !ZONE_IDLE(world[i].zone) && 
              !ZONE_FREED(world[i].zone) && !ZONE_FLAGGED(world[i].zone, Z_LOCKED) &&
	      ROOM_FLAGGED2(i, DONATION))
	  {
	    don_count++;
	    if (don_count == don_num)
		break;
	  }
	don_room = i;
      }

      break;
   default:
      sname = "drop";
      break;
   }

   argument = one_argument(argument, arg);

   if (!*arg) {
      sprintf(buf, "What do you want to %s?\n\r", sname);
      S2C();
      return;
   } else if (is_number(arg)) {
      amount = atoi(arg);
      argument = one_argument(argument, arg);
      if (!str_cmp(currency_name_plural, arg) || !str_cmp(currency_name, arg))
         perform_drop_gold(ch, amount, mode, don_room);
      else {
	 /* code to drop multiple items.  anyone want to write it? -je */
	 send_to_char("Sorry, you can't do that (yet)...\n\r", ch);
      }
      return;
   } 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("To protect you from accidents, you cannot junk everything.\n\r", ch);
         else 
	    send_to_char("You cannot donate everything in your inventory.\n\r", ch);
         return;
      }

      if (dotmode == FIND_ALL) {
         if (!ch->carrying)
	    send_to_char("You don't seem to be carrying anything.\n\r", ch);
	 else
            for (obj = ch->carrying; obj; obj = next_obj) {
               next_obj = obj->next_content;
	       amount += perform_drop(ch, obj, mode, sname, don_room);
	    }
      } else if (dotmode == FIND_ALLDOT) {
	 if (!*arg) {
	    sprintf(buf, "What do you want to %s all of?\n\r", sname);
	    S2C();
	    return;
	 }
         if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
            sprintf(buf, "You don't seem to have any %ss.\n\r", arg);
	    S2C();
	 }
         while (obj) {
	    next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
	    amount += perform_drop(ch, obj, mode, sname, don_room);
	    obj = next_obj;
	 }
      } else {
        if ((num = ManyObjs(arg, multarg)) != 0) {
          strcpy(arg, multarg);

          while (num) {
            if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
              SendChar(tprintf("You don't seem to have %s %s.\n\r",
                               AN(arg), arg), ch);
              return;
            }

            amount += perform_drop(ch, obj, mode, sname, don_room);
            num--;
          }
        } else {
         if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
	    sprintf(buf, "You don't seem to have %s %s.\n\r", AN(arg), arg);
	    S2C();
	 } else
	    amount += perform_drop(ch, obj, mode, sname, don_room);
       }
      }
   }

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

// The actual give -roa
// 9/21/97, check for character quests on gives -roa
void	perform_give(chdata *ch, chdata *vict, obdata *obj, BOOL calc_weight)
{
  int vnum = GET_OBJ_VNUM(obj);
  plshop *ptr;

  if (IS_SET(OBJ_EXTRAS(obj), ITEM_NODROP) && !IS_IMMORTAL(ch)) {
    act("You can't let go of $p!!  Yeech!", FALSE, ch, obj, 0, TO_CHAR);
    return;
  }

  // updated to not always check #, and weight 1/22/98 -jtrhone
  if (calc_weight)
  {
    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 (IS_PC(vict) && PRF2_FLAGGED(vict, PRF2_NOGIVE))
  {
    send_to_char("Some unknown force prevents you from doing that.\n\r",ch);
    sprintf(buf, "SYSUPD: %s failed giving %s to %s.",GET_NAME(ch), obj->shdesc, GET_NAME(vict));
    mudlog(buf, BUG, LEV_IMM, TRUE);
    return;
  }

  if (MOB_FLAGGED(vict, MOB_PLSHOPKEEP))
  {
    if (!(ptr = in_own_shop(ch)) || (GET_MOB_VNUM(vict) != ptr->shopkeep_vnum))
    {
      send_to_char("Some unknown force prevents you from doing that.\n\r",ch);
      sprintf(buf, "SYSUPD: %s failed giving %s to %s.",GET_NAME(ch), obj->shdesc, GET_NAME(vict));
      mudlog(buf, BUG, LEV_IMM, TRUE);
      return;
    }
  }

  obj_from_char(obj);
  obj_to_char(obj, vict);
  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);

  // check to see if they just gave quest object back to questor mob -roa
  qcheck_obj_give(ch, vict, obj);

  // check object they just got in case of immediate quest reward
  qcheck_obj_get(ch, obj);

  /* log this here -roa */
  if (IS_IMMORTAL(ch)) 
  {
    sprintf(buf, "%s gave [%d] %s to %s at %d.",GET_NAME(ch),vnum,
            obj->shdesc, GET_NAME(vict), world[ch->in_room].number);
    mudlog(buf, BRF, MAX(LEV_IMM, GET_INVIS_LEV(ch)), TRUE);
  }
}

/* utility function for give */
chdata *give_find_vict(chdata *ch, char *arg1)
{
  chdata *vict;
  char arg2[MAX_INPUT_LENGTH];

  strcpy(buf, arg1);
  two_arguments(buf, arg1, arg2);
  if (!*arg1) {
    send_to_char("Give what to who?\n\r", ch);
    return NULL;
  } else 
  if (!*arg2) {
    send_to_char("To who?\n\r", ch);
    return NULL;
  } else 
  if (!(vict = get_char_room_vis(ch, arg2))) {
    send_to_char("No-one by that name here.\n\r", ch);
    return NULL;
  } else 
  if (vict == ch) {
    send_to_char("What's the point of that?\n\r", ch);
    return NULL;
  } else
    return vict;
}

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

  if ((GET_GOLD(ch) < amount) && (IS_NPC(ch) || (GET_LEVEL(ch) < LEV_GOD))) {
     send_to_char("You haven't got that much!\n\r", ch);
     return;
  }

  sprintf(buf, "You give $M %d %s.", amount, currency_name_plural);
  act(buf, TRUE, ch, 0, vict, TO_CHAR);

  sprintf(buf, "%s gives you %d %s.\n\r", PERS(ch, vict), amount, currency_name_plural);
  send_to_char(buf, vict);

  sprintf(buf, "$n gives some %s to $N.", currency_name_plural);
  act(buf, TRUE, ch, 0, vict, TO_NOTVICT);

  if (IS_NPC(ch) || (GET_LEVEL(ch) < LEV_GOD))
    GET_GOLD(ch) -= amount;

  GET_GOLD(vict) += amount;
}

// Reworked for ManyObjs() func. 08/10/98 -callahan
ACMD(do_give)
{
   char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH],
     multarg[MAX_INPUT_LENGTH];
   int	amount = 0, dotmode, num;
   chdata *vict;
   obdata *obj, *next_obj;

   half_chop(argument, arg1, arg2);

   if (!*arg1)
   {
     send_to_char("Give what to who?\n\r", ch);
     return;
   }
   else 
   if (is_number(arg1)) 
   {
      amount = atoi(arg1);
      if (!(vict = give_find_vict(ch, arg2)))
      {
        send_to_char("Give what to who?\n\r", ch);
        return;
      }

      // cannot give normally to shopkeep mob
      if (!IS_IMMORTAL(ch) && MOB_FLAGGED(vict, MOB_PLSHOPKEEP))
      {
        send_to_char("Use shopdeposit and shopwithdraw for gold transfers.\n\r", ch);
        return;
      }

      if (!str_cmp(currency_name_plural, arg2) || !str_cmp(currency_name, arg2))
         perform_give_gold(ch, vict, amount);
      else 
      {
	 /* code to give multiple items.  anyone want to write it? -je */
	 send_to_char("Sorry, you can't do that (yet)...\n\r", ch);
	 return;
      }
   } 
   else 
   {
      if (!(vict = give_find_vict(ch, argument)))
      {
        send_to_char("Give what to who?\n\r", ch);
	return;
      }

      // cannot give normally to shopkeep mob
      if (!IS_IMMORTAL(ch) && MOB_FLAGGED(vict, MOB_PLSHOPKEEP))
      {
        send_to_char("Use shopgive and shoptake for item transfers.\n\r", ch);
        return;
      }

      dotmode = find_all_dots(argument);
      if (dotmode == FIND_ALL) 
      {
	 if (!ch->carrying)
	    send_to_char("You don't seem to be holding anything.\n\r", ch);
	 else 
         for (obj = ch->carrying; obj; obj = next_obj) 
         {
	    next_obj = obj->next_content;
	    perform_give(ch, vict, obj, TRUE);
	 }
      } 
      else 
      if (dotmode == FIND_ALLDOT) 
      {
	 if (!*argument) 
         {
	    send_to_char("All of what?\n\r", ch);
	    return;
	 }

	 if (!(obj = get_obj_in_list_vis(ch, argument, ch->carrying))) 
         {
	    sprintf(buf, "You don't seem to have any %ss.\n\r", argument);
	    S2C();
	 } 
         else 
         while (obj) 
         {
	    next_obj = get_obj_in_list_vis(ch, argument, obj->next_content);
	    perform_give(ch, vict, obj, TRUE);
	    obj = next_obj;
	 }
      } else {
        if ((num = ManyObjs(argument, multarg)) != 0) {
          strcpy(argument, multarg);

          while (num) {
            if (!(obj = get_obj_in_list_vis(ch, argument, ch->carrying))) {
              SendChar(tprintf("You don't seem to have %s %s.\n\r", 
                               AN(argument), argument), ch);
              return;
            }

            perform_give(ch, vict, obj, TRUE);
            num--;
          }
        } else {
          if (!(obj = get_obj_in_list_vis(ch, argument, ch->carrying))) {
            sprintf(buf, "You don't seem to have %s %s.\n\r", 
                    AN(argument), argument);
 	    S2C();
          } else
	    perform_give(ch, vict, obj, TRUE);
       }
      }
   }
}

// *_*_*_*_*_*_*_*_*_* OLD act.obj2.c starts here *_*_*_*_*_*_*_*_*

void	weight_change_object(obdata *obj, int weight)
{
   obdata *tmp_obj;
   chdata *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.");
   }
}

// pull the first name from an objects alias list
void	name_from_drinkcon(obdata *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 || GET_OBJ_RNUM(obj) >= top_of_objt || 
	  obj->name != obj_proto[GET_OBJ_RNUM(obj)].name)
	 free_log(obj->name, "name_from_drinkcon");
      obj->name = new_name;
   }
}

// add a name to the front of the objects alias list.
void	name_to_drinkcon(obdata *obj, int type)
{
   char	*new_name;
   extern char	*drinknames[];

   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 || GET_OBJ_RNUM(obj) >= top_of_objt || 
       obj->name != obj_proto[GET_OBJ_RNUM(obj)].name)
     free_log(obj->name, "name_to_drinkcon");

   obj->name = new_name;
}

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

   one_argument(argument, arg);

   if (!*arg) {
      send_to_char("Drink from what?\n\r", 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)))
      {
	 act("You can't find it!", FALSE, ch, 0, 0, TO_CHAR);
	 return;
      } 
      else
	on_ground = TRUE;
   }

   if ((ITEM_TYPE(temp) != ITEM_DRINKCON) && (ITEM_TYPE(temp) != ITEM_FOUNTAIN))
   {
      send_to_char("You can't drink from that!\n\r", ch);
      return;
   }

   if (on_ground && (ITEM_TYPE(temp) == ITEM_DRINKCON)) {
      send_to_char("You have to be holding that to drink from it.\n\r", ch);
      return;
   }

   if (IS_PC(ch))
   if ((GET_COND(ch, DRUNK) > 10) && (GET_COND(ch, THIRST) > 0)) 
   {
      send_to_char("You can't seem to get close enough to your mouth.\n\r", ch);
      act("$n tries to drink but misses $s mouth!", TRUE, ch, 0, 0, TO_ROOM);
      return;
   }

   if (IS_PC(ch))
   if ((GET_COND(ch, FULL) > 20) && (GET_COND(ch, THIRST) > 0)) {
      send_to_char("Your stomach can't contain anymore!\n\r", ch);
      return;
   }

   if (!temp->value[1]) {
      send_to_char("It's empty.\n\r", ch);
      return;
   }

   if (subcmd == SCMD_DRINK) 
   {
      if (temp->type_flag != ITEM_FOUNTAIN) {
         sprintf(buf, "$n drinks %s from $p.", drinks[temp->value[2]]);
         act(buf, TRUE, ch, temp, 0, TO_ROOM);
      }

      sprintf(buf, "You drink the %s.\n\r", drinks[temp->value[2]]);
      S2C();

      if (IS_PC(ch))
      if (drink_aff[temp->value[2]][DRUNK] > 0)
         amount = (25-GET_COND(ch, THIRST)) / drink_aff[temp->value[2]][DRUNK];
      else
         amount = number(3, 10);
   } 
   else 
   {
      act("$n sips from the $o.", TRUE, ch, temp, 0, TO_ROOM);
      sprintf(buf, "It tastes like %s.\n\r", drinks[temp->value[2]]);
      S2C();
      amount = 1;
   }

   amount = MIN(amount, temp->value[1]);

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

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

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

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

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

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

   if (IS_PC(ch))
   if (GET_COND(ch, THIRST) > 20)
      send_to_char("You are no longer thirsty.\n\r", ch);

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

   /* if it was poisoned ! */
   if (temp->value[3]) 
   { 
      send_to_char("Oops, that tasted rather strange!\n\r", ch);
      act("$n chokes and utters some strange sounds.", TRUE, ch, 0, 0, TO_ROOM);

      if (!affected_by_spell(ch, SKILL_CLEANSE))
      {
        af.type = SPELL_POISON;
        af.duration = amount * 3;
        af.modifier = 0;
        af.location = APPLY_NONE;
        af.bitvector = AFF_POISON;
        af.bitvector2 = 0;
        affect_join(ch, &af, FALSE, FALSE);
      }
      else
      {
	act("You resist the poison!",TRUE, ch, 0, 0, TO_CHAR);
	act("$n resists the poison!",TRUE, ch, 0, 0, TO_ROOM);
      }
   }

   /* empty the container, and no longer poison. */
   temp->value[1] -= amount;
   if (!temp->value[1]) 
   {  
      temp->value[2] = 0;
      temp->value[3] = 0;
      name_from_drinkcon(temp);
   }
}

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

   one_argument(argument, arg);

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

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

   if (subcmd == SCMD_TASTE && ((ITEM_TYPE(food) == ITEM_DRINKCON) ||
      (ITEM_TYPE(food) == ITEM_FOUNTAIN))) {
         do_drink(ch, argument, 0, SCMD_SIP);
	 return;
   }

   if ((ITEM_TYPE(food) != ITEM_FOOD) && (GET_LEVEL(ch) < LEV_GOD)) {
      send_to_char("You can't eat THAT!\n\r", ch);
      return;
   }

   if (IS_PC(ch))
   if (GET_COND(ch, FULL) > 20) { /* Stomach full */
      act("You are too full to eat more!", FALSE, ch, 0, 0, TO_CHAR);
      return;
   }

   if (subcmd == SCMD_EAT) {
      act("You eat the $o.", FALSE, ch, food, 0, TO_CHAR);
      act("$n eats $p.", TRUE, ch, food, 0, TO_ROOM);
   } else {
      act("You nibble a little bit of the $o.", FALSE, ch, food, 0, TO_CHAR);
      act("$n tastes a little bit of $p.", TRUE, ch, food, 0, TO_ROOM);
   }

   amount = (subcmd == SCMD_EAT ? food->value[0] : 1);

   gain_condition(ch, FULL, amount);

   if (IS_PC(ch))
   if (GET_COND(ch, FULL) > 20)
      act("You are full.", FALSE, ch, 0, 0, TO_CHAR);

   if (food->value[3] && (GET_LEVEL(ch) < LEV_IMM)) 
   {
      /* The food was poisoned ! */
      send_to_char("Oops, that tasted rather strange!\n\r", 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;
      af.bitvector2 = 0;
      affect_join(ch, &af, FALSE, FALSE);
   }
  
   if (IS_IMMORTAL(ch))
     {
  	sprintf(buf, "%s ate -> [%d] %s",GET_NAME(ch), obj_index[food->item_number].vnum, 
                food->shdesc);
       mudlog(buf, NRM, GET_LEVEL(ch),TRUE);
     }

   if (subcmd == SCMD_EAT)
      extract_obj(food);
   else 
   if (!(--food->value[0])) 
   {
     send_to_char("There's nothing left now.\n\r", ch);
     extract_obj(food);
   }
}

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

   two_arguments(argument, arg1, arg2);

   if (subcmd == SCMD_POUR) {
      if (!*arg1) /* No arguments */ {
	 act("What do you want to pour from?", FALSE, ch, 0, 0, TO_CHAR);
	 return;
      }

      if (!(from_obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
	 act("You can't find it!", FALSE, ch, 0, 0, TO_CHAR);
	 return;
      }

      if (from_obj->type_flag != ITEM_DRINKCON) {
	 act("You can't pour from that!", FALSE, ch, 0, 0, TO_CHAR);
	 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?\n\r", ch);
	 return;
      }

      if (!(to_obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
	 send_to_char("You can't find it!\n\r", ch);
	 return;
      }

      if (ITEM_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 any '%s' here.\n\r", arg2);
	 S2C();
	 return;
      }

      if (ITEM_TYPE(from_obj) != ITEM_FOUNTAIN) {
	 act("You can't fill something from $p.", FALSE, ch, from_obj, 0, TO_CHAR);
	 return;
      }
   }

   if (from_obj->value[1] == 0) {
      act("$p is empty.", FALSE, ch, from_obj, 0, TO_CHAR);
      return;
   }

   if (subcmd == SCMD_POUR) /* pour */ {
      if (!*arg2) {
	 act("Where do you want it?  Out or in what?", FALSE, ch, 0, 0, TO_CHAR);
	 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, -from_obj->value[1]); /* Empty */

	 from_obj->value[1] = 0;
	 from_obj->value[2] = 0;
	 from_obj->value[3] = 0;
	 name_from_drinkcon(from_obj);

	 return;
      }

      if (!(to_obj = get_obj_in_list_vis(ch, arg2, ch->carrying))) {
	 act("You can't find it!", FALSE, ch, 0, 0, TO_CHAR);
	 return;
      }

      if ((to_obj->type_flag != ITEM_DRINKCON) && 
          (to_obj->type_flag != ITEM_FOUNTAIN)) {
	 act("You can't pour anything into that.", FALSE, ch, 0, 0, TO_CHAR);
	 return;
      }
   }

   if (to_obj == from_obj) {
      act("A most unproductive effort.", FALSE, ch, 0, 0, TO_CHAR);
      return;
   }

   if ((to_obj->value[1] != 0) && 
       (to_obj->value[2] != from_obj->value[2])) {
      act("There is already another liquid in it!", FALSE, ch, 0, 0, TO_CHAR);
      return;
   }

   if (!(to_obj->value[1] < to_obj->value[0])) {
      act("There is no room for more.", FALSE, ch, 0, 0, TO_CHAR);
      return;
   }

   if (subcmd == SCMD_POUR) {
      sprintf(buf, "You pour the %s into the %s.",
          drinks[from_obj->value[2]], arg2);
      S2C();
   }

   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 (to_obj->value[1] == 0)
      name_to_drinkcon(to_obj, from_obj->value[2]);

   /* First same type liq. */
   to_obj->value[2] = from_obj->value[2];

   /* Then how much to pour */
   from_obj->value[1] -= (amount = 
       (to_obj->value[0] - to_obj->value[1]));

   to_obj->value[1] = to_obj->value[0];

   if (from_obj->value[1] < 0) {  /* There was too little */
      to_obj->value[1] += from_obj->value[1];
      amount += from_obj->value[1];
      from_obj->value[1] = 0;
      from_obj->value[2] = 0;
      from_obj->value[3] = 0;
      name_from_drinkcon(from_obj);
   }

   /* Then the poison boogie */
   to_obj->value[3] =
      (to_obj->value[3] || from_obj->value[3]);

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

   return;
}

// updated for slot revamp 5/28/98 -jtrhone
void	wear_message(chdata *ch, obdata *obj, int where)
{
   char *wear_messages[][2] = {
      { "$n wears $p on $s head.",
	"You wear $p on your head." },
      { "$n covers $s face with $p.",
	"You cover your face with $p." },
      { "$n wears $p on $s right ear.",
	"You wear $p on your right ear." },
      { "$n wears $p on $s left ear.",
	"You wear $p on your left ear." },
      { "$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 around $s waist.",
	"You wear $p around your waist." },
      { "$n wears $p about $s body." ,
	"You wear $p around your body." },
      { "$n wears $p on $s arms.",
	"You wear $p on your arms." },
      { "$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 puts $p on $s hands.",
	"You put $p on your hands." },
      { "$n slides $p onto $s right hand.",
	"You slide $p onto your right hand." },
      { "$n slides $p onto $s right hand.",
	"You slide $p onto your right hand." },
      { "$n slides $p onto $s left hand.",
	"You slide $p onto your left hand." },
      { "$n slides $p onto $s left hand.",
	"You slide $p onto your left hand." },
      { "$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 wields $p.",
        "You wield $p." },
      { "$n grabs $p.",
	"You grab $p." }
   };

   if (obj->wear_mesg && str_cmp(obj->wear_mesg, "BLANK"))
    act(obj->wear_mesg, TRUE, ch, obj, 0, TO_ROOM);
   else
     act(wear_messages[where][0], TRUE, ch, obj, 0, TO_ROOM);

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

// tighened up in anticipation of eq slot revamp 5/28/98 -jtrhone
// and updated 5/28/98 -jtrhone
BOOL	perform_wear(chdata *ch, obdata *obj, int where)
{
   extern int monk_restricts[MAX_WEAR];
   int vnum = 0;
   int i;

   // what flags need to be set on obj to wear in this position
   int wear_bitvectors[] = {
      ITEM_WEAR_HEAD, 
      ITEM_WEAR_FACE, 
      ITEM_WEAR_EARS, 
      ITEM_WEAR_EARS, 
      ITEM_WEAR_NECK,
      ITEM_WEAR_NECK, 
      ITEM_WEAR_BODY, 
      ITEM_WEAR_WAIST, 
      ITEM_WEAR_ABOUT, 
      ITEM_WEAR_ARMS, 
      ITEM_WEAR_WRIST, 
      ITEM_WEAR_WRIST,
      ITEM_WEAR_HANDS, 
      ITEM_WEAR_FINGER, 
      ITEM_WEAR_FINGER, 
      ITEM_WEAR_FINGER, 
      ITEM_WEAR_FINGER, 
      ITEM_WEAR_LEGS,
      ITEM_WEAR_FEET, 
      ITEM_WIELD, 
      ITEM_TAKE 
   };

   // updated to support wvectors
   char *already_wearing[] = {
      "You're already wearing something on your head.\n\r",
      "You're already wearing something on your face.\n\r",
      "You're already wearing something on both of your ears.\n\r",
      "You're already wearing something on both of your ears.\n\r",
      "You can't wear anything else around your neck.\n\r",
      "You can't wear anything else around your neck.\n\r",
      "You're already wearing something on your body.\n\r",
      "You already have something around your waist.\n\r",
      "You're already wearing something about your body.\n\r",
      "You're already wearing something on your arms.\n\r",
      "You're already wearing something around both of your wrists.\n\r",
      "You're already wearing something around both of your wrists.\n\r",
      "You're already wearing something on your hands.\n\r",
      "Your fingers are full of rings.\n\r",
      "Your fingers are full of rings.\n\r",
      "Your fingers are full of rings.\n\r",
      "Your fingers are full of rings.\n\r",
      "You're already wearing something on your legs.\n\r",
      "You're already wearing something on your feet.\n\r",
      "You're already wielding a weapon.\n\r",
      "You already have something in your offhand.\n\r"
   };

   /* first, make sure that the object can be worn there*/
   if (!CAN_WEAR(obj, wear_bitvectors[where])) {
      act("You can't wear $p there.", FALSE, ch, obj, 0, TO_CHAR);
      return FALSE;
   }

   /* CHECK TO SEE IF OBJECT IS VALID OBJECT FROM AN OPEN ZONE >> ROA */
   vnum = GET_OBJ_VNUM(obj);
 
   if (GET_LEVEL(ch) < LEV_IMM && IS_PC(ch))
   if (!vnum || ZONE_FLAGGED((vnum/100), Z_CLOSED))
   {
      send_to_char("That object is an %6INVALID%0 object.\n\r",ch);
      send_to_char("Please note where and how you got it and immediatly\n\r",ch);
      send_to_char("report it to a GOD+... Thanx.\n\r",ch);
      sprintf(buf, "%s has an INVALID object: [%d] %s", GET_NAME(ch), vnum, obj->shdesc);
      mudlog(buf, BRF, LEV_IMM, TRUE);
      return FALSE;
   }
      
   // updated to support wvectors  5/28/98 -jtrhone

   /* for neck, ear, and wrist, try pos 2 if pos 1 is already full */
   switch (where) {
     case W_EAR_R:
     case W_NECK_1:
     case W_WRIST_R:
       if (EQ(ch, where) || WV_FLAGGED(ch, (1 << where)))
         where++;

     default: break;
   }

   // for rings now, scan for empty slot
   if (where == W_FINGER_R1 && (EQ(ch, where) || WV_FLAGGED(ch, (1 << where))))
     if (EQ(ch, ++where) || WV_FLAGGED(ch, (1 << where)))   // FINGER_R2
       if (EQ(ch, ++where) || WV_FLAGGED(ch, (1 << where)))   // FINGER_L1
         where++;

   // cannot where if already something there
   if (EQ(ch, where) || WV_FLAGGED(ch, (1 << where))) 
   {
     send_to_char(already_wearing[where], ch);
     return FALSE;
   }

   // also check wvflags on object to see if char has something there...
   for (i = 0; i < MAX_WEAR; i++)
     if (WV_FLAGGED(obj, (1 << i)) && (EQ(ch, i) || WV_FLAGGED(ch, (1 << i))))
     {
       send_to_char(already_wearing[i], ch);
       return FALSE;
     }

   /* check level for object ROA James Rhone */
   if (GET_LEVEL(ch) < obj->min_level)
   {
      send_to_char("That object is too powerful for you to use.\n\r",ch);
      return FALSE;
   }

   /* lets check restricts on monshai -roa */
   if (IS_NAT_MONK(ch) && !IS_IMMORTAL(ch))
     if (GET_LEVEL(ch) >= monk_restricts[where])
     {
       send_to_char("You, Monshai, are not allowed to do such.\n\r",ch);
       return FALSE;
     }

   if (IS_NAT_MONK(ch) && !IS_IMMORTAL(ch) && ITEM_TYPE(obj) == ITEM_WEAPON && where == W_HOLD)
   {
       send_to_char("You, Monshai, are not allowed to do such.\n\r",ch);
       return FALSE;
   }

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

    // equip_char will set wvector flags on char...
   if (equip_char(ch, obj, where, TRUE))
   {
     // only light if in held spot...  6/4/98 -jtrhone
     if (obj == EQ(ch, W_HOLD) && OBJ_LIGHT(obj) && LIGHT_TIME(obj))
       do_light(ch, "", 0, 0);
     return TRUE;
   }
   else 
     return FALSE;
}

int find_eq_pos(chdata *ch, obdata *obj, char *arg)
{
   int where = -1;

   static char	*keywords[] = {
      "head",
      "face",
      "ear",
      "!RESERVED!",
      "neck",
      "!RESERVED!",
      "body",
      "waist",
      "about",
      "arms",
      "wrist",
      "!RESERVED!",
      "hands",
      "finger",
      "!RESERVED!",
      "!RESERVED!",
      "!RESERVED!",
      "legs",
      "feet",
      "!RESERVED!",
      "!RESERVED!",
      "\n"
   };

   // if they didnt supply an argument, pick a best fit
   if (!arg || !*arg) 
   {
      if (CAN_WEAR(obj, ITEM_WEAR_HEAD))	where = W_HEAD;
      if (CAN_WEAR(obj, ITEM_WEAR_FACE))	where = W_FACE;
      if (CAN_WEAR(obj, ITEM_WEAR_EARS))	where = W_EAR_R;
      if (CAN_WEAR(obj, ITEM_WEAR_NECK))	where = W_NECK_1;
      if (CAN_WEAR(obj, ITEM_WEAR_BODY))	where = W_BODY;
      if (CAN_WEAR(obj, ITEM_WEAR_WAIST))	where = W_WAIST;
      if (CAN_WEAR(obj, ITEM_WEAR_ABOUT))	where = W_ABOUT;
      if (CAN_WEAR(obj, ITEM_WEAR_ARMS))	where = W_ARMS;
      if (CAN_WEAR(obj, ITEM_WEAR_WRIST))	where = W_WRIST_R;
      if (CAN_WEAR(obj, ITEM_WEAR_HANDS))	where = W_HANDS;
      if (CAN_WEAR(obj, ITEM_WEAR_FINGER))	where = W_FINGER_R1;
      if (CAN_WEAR(obj, ITEM_WEAR_LEGS))	where = W_LEGS;
      if (CAN_WEAR(obj, ITEM_WEAR_FEET))	where = W_FEET;
   } 
   else 
     if ((where = search_block(arg, keywords, FALSE)) < 0) 
     {
       sprintf(buf, "'%s'?  What part of your body is THAT?\n\r", arg);
       S2C();
     }

   return where;
}

// tighened up in anticipation of eq slot revamp 5/28/98 -jtrhone
ACMD(do_wear)
{
   char	arg1[MAX_INPUT_LENGTH];
   char	arg2[MAX_INPUT_LENGTH];
   obdata *obj, *next_obj;
   int	where, dotmode, items_worn = 0;
 
   two_arguments(argument, arg1, arg2);
   if (!*arg1) 
   {
      send_to_char("Wear what?\n\r", 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!\n\r", ch);
      return;
   }

   if (dotmode == FIND_ALL) 
   {
      for (obj = ch->carrying; obj; obj = next_obj) 
      {
	 next_obj = obj->next_content;
	 if ((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.\n\r", ch);
   } 
   else 
   if (dotmode == FIND_ALLDOT)
   {
      if (!*arg1) 
      {
	 send_to_char("Wear all of what?\n\r", ch);
	 return;
      }

      if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) 
      {
	 sprintf(buf, "You don't seem to have any %ss.\n\r", arg1);
	 S2C();
      } 
      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.\n\r", AN(arg1), arg1);
	 S2C();
      } 
      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);
      }
   }
}

// tighened up in anticipation of eq slot revamp 5/28/98 -jtrhone
ACMD(do_wield)
{
  obdata *obj;

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

  if (!(obj = get_obj_in_list(arg, ch->carrying))) 
  {
    sprintf(buf, "You don't seem to have %s %s.\n\r", AN(arg), arg);
    S2C();
    return;
  } 


  if (!CAN_WEAR(obj, ITEM_WIELD)) 
    send_to_char("You can't wield that.\n\r", ch);
  else 
  if (GET_OBJ_WEIGHT(obj) > str_app[TRUE_STRENGTH(ch)].wield_w)
    send_to_char("It's too heavy for you to use.\n\r", ch);
  else
    perform_wear(ch, obj, W_WIELD);
}

// tighened up in anticipation of eq slot revamp 5/28/98 -jtrhone
ACMD(do_grab)
{
  obdata *obj;

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

  if (!(obj = get_obj_in_list(arg, ch->carrying))) 
  {
    sprintf(buf, "You don't seem to have %s %s.\n\r", AN(arg), arg);
    S2C();
    return;
  } 

  if (CAN_WEAR(obj, ITEM_HOLD) || (IS_THIEF(ch) && OBJ_FLAGGED(obj, ITEM_THIEF_HOLD)))
  {
    if (!CAN_WEAR(obj, ITEM_HOLD))
    {
      sprintf(buf, "You use %s as a secondary weapon.\n\r",obj->shdesc);
      S2C();
    }

    perform_wear(ch, obj, W_HOLD);
  } 
  else
    send_to_char("That item may not be held in an offhand.\n\r",ch);
}

// remove a particular object from ch inventory... updated to deal with poisons/thieves
// 4/17/98 -jtrhone
void	perform_remove(chdata *ch, int pos)
{
   obdata *obj;

   if (!(obj = EQ(ch, pos))) {
      log("Error in perform_remove: bad pos passed.");
      return;
   }

   if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch))
      act("$p: your inventory is too full!", FALSE, ch, obj, 0, TO_CHAR);
   else 
   {
      // if they remove their instrument, they cant play anymore...
      if (OBJ_FLAGGED(obj, ITEM_INSTRUM) && PLAYING(ch))
        do_finish(ch, " tune", 0, 0);

      // if they remove their poison, they have to stop brewing
      if (pos == W_HOLD && IS_LIQCONT(obj) && affected_by_spell(ch, SKILL_BREW))
        affect_from_char(ch, SKILL_BREW);

      act("You stop using $p.", FALSE, ch, obj, 0, TO_CHAR);

      if (obj->rem_mesg && str_cmp(obj->rem_mesg, "BLANK"))
	act(obj->rem_mesg, TRUE, ch, obj, 0, TO_ROOM);
      else
        act("$n stops using $p.", TRUE, ch, obj, 0, TO_ROOM);

      obj_to_char(unequip_char(ch, pos, TRUE), ch);
   }
}

// former do_remove, now do_unqeuip  4/14/98 -jtrhone
ACMD(do_unequip)
{
  obdata *obj;
  int	i, dotmode, found;

  one_argument(argument, arg);

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

  dotmode = find_all_dots(arg);

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

ACMD(do_throw)
{
  int num, size, plus, dam, wasin, toroom, dir;
  chdata *victim;
  obdata *obj;
  char *argu = argument;
  char dirstr[MAX_INPUT_LENGTH], tarstr[MAX_INPUT_LENGTH];
  BOOL same_room = FALSE;
  extern int successful_hit(chdata *ch, chdata *vict);
  extern int spell_adjust_damage(chdata *vict, int dam);

  if (!(obj = EQ(ch, W_WIELD)))
  {
    send_to_char("You must be wielding something first!\n\r",ch);
    return;
  }

  if (!THROWABLE(obj))
  {
    act("Unfortunately, you cannot throw $p.",FALSE,ch,obj,0,TO_CHAR);
    return;
  }

  skip_spaces(&argu);
  if (!*argu)
  {
    act("Usage: throw <direction> <target>.",FALSE,ch,0,0,TO_CHAR);
    return;
  }

  if (strlen(argu) >= MAX_INPUT_LENGTH)
  {
    act("Argument too long, please rephrase.",FALSE,ch,0,0,TO_CHAR);
    return;
  }

  half_chop(argu, dirstr, tarstr);
  if (!*tarstr)
  {
    // could mean to throw it at target in room -roa 
    if (!(victim = get_char_room_vis(ch, dirstr)))
    {
      act("Usage: throw <direction> <target>.",FALSE,ch,0,0,TO_CHAR);
      act("       throw <target>.",FALSE,ch,0,0,TO_CHAR);
      return;
    }
    else 
      same_room = TRUE;
  }

  if (!same_room)
  { 
    dir = search_block(dirstr, comm_dirs, FALSE);

    if (dir < 0 || dir > NUM_OF_DIRS)
    {
      act("Usage: throw <direction> <target>.",FALSE,ch,0,0,TO_CHAR);
      return;
    }

    if (!EXIT(ch, dir) || EXIT(ch, dir)->to_room <= NOWHERE || EXIT_CLOSED(EXIT(ch, dir)))
    {
      act("You cannot throw anything in that direction.",FALSE,ch,0,0,TO_CHAR);
      return;
    }

    toroom = EXIT(ch, dir)->to_room;
    wasin = ch->in_room;

    char_from_room(ch);
    char_to_room(ch, toroom);

    victim = get_char_room_vis(ch, tarstr);

    char_from_room(ch);
    char_to_room(ch, wasin);

    if (!victim) 
    {
      act("Throw at whom?",FALSE,ch,0,0,TO_CHAR);
      return;
    }
  }

  if (!check_mortal_combat(ch, victim))
    return;
  if (!check_truce(ch, victim))
    return;

  if (MOB_FLAGGED(victim, MOB_MEMORY))
    remember(victim, ch);

  if (IS_NPC(victim))
    HUNTING(victim) = ch;

  num = obj->throw_numdam;
  size = obj->throw_sizedam;
  plus = obj->throw_plusdam;

  num = MAX(1, num);
  size = MAX(1, size);
  plus = MAX(0, plus);

  dam = dice(num, size) + plus;
  dam = spell_adjust_damage(victim, dam);

  if (!same_room)
  {
    // send messages to both rooms
    sprintf(buf, "$n throws $p %s at $N.",dirs[dir]);
    act(buf,TRUE,ch,obj,victim,TO_ROOM);
    sprintf(buf, "You throw $p %s at $N.",dirs[dir]);
    act(buf,TRUE,ch,obj,victim,TO_CHAR);
  }
  else
  {
    act("You throw $p at $N!",TRUE,ch,obj,victim,TO_CHAR);
    act("$n throws $p at $N!",TRUE,ch,obj,victim,TO_ROOM);
  }

  obj = unequip_char(ch, W_WIELD, FALSE);

  if (successful_hit(ch, victim))
  {
    obj_to_char(obj, victim); 
    act("$p hits $N!",TRUE,ch,obj,victim,TO_NOTVICT);
    if (!same_room)
    {
      sprintf(buf, "$n gets hit by $p from %s!", rev_dir_str[dir]);
      act(buf, TRUE,victim,obj,0,TO_ROOM);
      sprintf(buf, "You get hit by $p from %s!", rev_dir_str[dir]);
      act(buf, TRUE,victim,obj,0,TO_CHAR);
    }
    else
    {
      act("$n hits you with $p!",TRUE,ch,obj,victim,TO_VICT);
    }

    GET_HIT(victim) -= dam;
    update_pos(victim);
    if (GET_POS(victim) == POS_DEAD)
      die(victim, FALSE);
  }
  else
  {
    if (!same_room)
    {
      obj_to_room(obj, toroom);
      sprintf(buf, "$p flies by $n from %s!", rev_dir_str[dir]);
      act(buf, TRUE,victim,obj,0,TO_ROOM);
      sprintf(buf, "$p flies by you from %s!", rev_dir_str[dir]);
      act(buf, TRUE,victim,obj,0,TO_CHAR);
    }
    else
    {
      obj_to_room(obj, ch->in_room);
      act("$p misses $N!",TRUE,ch,obj,victim,TO_NOTVICT);
    }
  }
}