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

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

extern int start_marketpid;

/*double sqrt( double x );*/
int sacall = 0;

/*
 * External functions
 */

void show_list_to_char args((OBJ_DATA * list, CHAR_DATA * ch, bool fShort, bool fShowNothing, const int iDefaultAction));
void write_corpses args((CHAR_DATA * ch, char *name, OBJ_DATA * objrem));

/*
 * Local functions.
 */
void get_obj args((CHAR_DATA * ch, OBJ_DATA * obj, OBJ_DATA * container));

OBJ_DATA *recursive_note_find args((OBJ_DATA * obj, char *argument));

/*
 * how resistant an object is to damage				-Thoric
 */
sh_int get_obj_resistance(OBJ_DATA * obj, CHAR_DATA *ch)
{
   int resist;

   if (obj->item_type == ITEM_WEAPON)
      resist = obj->value[10];
   else
      resist = obj->value[4];  

   /* magical items are more resistant */
   if (IS_OBJ_STAT(obj, ITEM_MAGIC))
      resist += number_range(1, 2);
   /* glowing objects should have a little bonus */
   if (IS_OBJ_STAT(obj, ITEM_GLOW))
      resist += 1;
   /* lets make store inventory pretty tough */
   if (IS_OBJ_STAT(obj, ITEM_INVENTORY))
      resist += 3;
   
   resist += ch->apply_armor;

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

   return URANGE(1, resist, 20);
}

bool is_kingdom_chest(OBJ_DATA * obj)
{
   KCHEST_DATA *kchest;

   for (kchest = first_kchest; kchest; kchest = kchest->next)
   {
      if (kchest->obj == obj)
         return TRUE;
   }
   return FALSE;
}

void get_obj(CHAR_DATA * ch, OBJ_DATA * obj, OBJ_DATA * container)
{
   CLAN_DATA *clan;
   int weight;
   int amt; /* gold per-race multipliers */
   char *pd;
   char name[MIL];
   CHAR_DATA *fch;

   if (!CAN_WEAR(obj, ITEM_TAKE) && (ch->level < sysdata.level_getobjnotake))
   {
      send_to_char("You can't take that.\n\r", ch);
      return;
   }
   if (obj->in_room)
   {
      for(fch = obj->in_room->first_person; fch != NULL; fch = fch->next_in_room)
      {
         if (fch->on == obj)
         {
            send_to_char("You cannot pick up a piece of furniture with someone on it.\n\r", ch);
            return;
         }
      }
   }

   if (IS_SET(obj->magic_flags, ITEM_PKDISARMED))
   {
      REMOVE_BIT(obj->magic_flags, ITEM_PKDISARMED);
      obj->value[5] = 0;
   }
   
   if (container && container->item_type == ITEM_CORPSE_PC && IS_OBJ_STAT(obj, ITEM_NOGIVE) && !sysdata.resetgame)
   {
      pd = container->short_descr;
      pd = one_argument(pd, name);
      pd = one_argument(pd, name);
      pd = one_argument(pd, name);
      pd = one_argument(pd, name);
      if (IS_NPC(ch) || str_cmp(name, ch->name))
      {
         send_to_char("A nogive item cannot be looted from a corpse.\n\r", ch);
         return;
      }
   }
   
   if (IS_UNIQUE(ch, obj) && container && container->carried_by && container->carried_by == ch)
   {
      ;
   }
   else if (IS_UNIQUE(ch, obj))
   {
      send_to_char("That item is unique and you already have one on you.\n\r", ch);
      return;
   }

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

   if (get_ch_carry_number(ch) + get_obj_number(obj) > can_carry_n(ch))
   {
      act(AT_PLAIN, "$d: you can't carry that many items.", ch, NULL, obj->name, TO_CHAR);
      return;
   }

   if (IS_OBJ_STAT(obj, ITEM_COVERING))
      weight = obj->weight;
   else
      weight = get_obj_weight(obj);

   if (get_ch_carry_weight(ch) + weight > can_carry_w(ch))
   {
      act(AT_PLAIN, "$d: you can't carry that much weight.", ch, NULL, obj->name, TO_CHAR);
      return;
   }

   if (container)
   {
      if (container->item_type == ITEM_KEYRING && !IS_OBJ_STAT(container, ITEM_COVERING))
      {
         act(AT_ACTION, "You remove $p from $P", ch, obj, container, TO_CHAR);
         act(AT_ACTION, "$n removes $p from $P", ch, obj, container, TO_ROOM);
      }
      else
      {
         act(AT_ACTION, IS_OBJ_STAT(container, ITEM_COVERING) ? "You get $p from beneath $P." : "You get $p from $P", ch, obj, container, TO_CHAR);
         act(AT_ACTION, IS_OBJ_STAT(container, ITEM_COVERING) ? "$n gets $p from beneath $P." : "$n gets $p from $P", ch, obj, container, TO_ROOM);
      }
      if (IS_OBJ_STAT(container, ITEM_CLANCORPSE) && !IS_NPC(ch) && str_cmp(container->name + 7, ch->name))
         container->value[5]++;
      obj_from_obj(obj);
   }
   else
   {
      act(AT_ACTION, "You get $p.", ch, obj, container, TO_CHAR);
      act(AT_ACTION, "$n gets $p.", ch, obj, container, TO_ROOM);
      obj_from_room(obj);
   }
   check_for_trap(ch, obj, -1, NEW_TRAP_GETOBJ);
   if (char_died(ch))
      return;
   if (global_retcode == rOBJ_SCRAPPED)
      return;
   // Check to see if it is a kingdom chest
   if (container && is_kingdom_chest(container))
      save_kingdom_chests(ch);
   /* Clan storeroom checks */
   if (xIS_SET(ch->in_room->room_flags, ROOM_CLANSTOREROOM) && (!container || container->carried_by == NULL))
   {
/*	if (!char_died) save_char_obj(ch); */
      for (clan = first_clan; clan; clan = clan->next)
         if (clan->storeroom == ch->in_room->vnum)
            save_clan_storeroom(ch, clan);
   }

   if (obj->item_type == ITEM_MONEY)
   {

      amt = obj->value[0];

/*
 *  The idea was to make some races more adroit at money handling,
 *  however, this resulted in elves dropping 1M gps and picking 
 *  up 1.1M, repeating, and getting rich.  The only solution would
 *  be to fuzzify the "drop coins" code, but that seems like it'd
 *  lead to more confusion than it warrants.  -h
 *
 *  When you work on this again, make it so that amt is NEVER multiplied
 *  by more than 1.0.  Use less than 1.0 for ogre, orc, troll, etc.
 *  (Ie: a penalty rather than a bonus)
 */
#ifdef GOLD_MULT
      switch (ch->race)
      {
         case (1):
            amt *= 1.1;
            break; /* elf */
         case (2):
            amt *= 0.97;
            break; /* dwarf */
         case (3):
            amt *= 1.02;
            break; /* halfling */
         case (4):
            amt *= 1.08;
            break; /* pixie */
         case (6):
            amt *= 0.92;
            break; /* half-ogre */
         case (7):
            amt *= 0.94;
            break; /* half-orc */
         case (8):
            amt *= 0.90;
            break; /* half-troll */
         case (9):
            amt *= 1.04;
            break; /* half-elf */
         case (10):
            amt *= 1.06;
            break; /* gith */
      }
#endif
   
      ch->gold += amt;
      if (xIS_SET(ch->act, PLR_AUTOSPLIT))
      {
         char buf1[20];
         sprintf(buf1, "%d", amt);
         do_split(ch, buf1);
      }
      extract_obj(obj);
   }
   else
   {
      obj = obj_to_char(obj, ch);
   }

   if (char_died(ch) || obj_extracted(obj))
      return;
   oprog_get_trigger(ch, obj);
   return;
}


void do_get(CHAR_DATA * ch, char *argument)
{
   char arg1[MIL];
   char arg2[MIL];
   OBJ_DATA *obj;
   OBJ_DATA *obj_next;
   OBJ_DATA *container;
   sh_int number;
   bool found;

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

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

   if (ms_find_obj(ch))
      return;
      
   if (IS_NPC(ch) && xIS_SET(ch->act, ACT_MILITARY))
   {
      send_to_char("You cannot do that.\n\r", ch);
      return;
   }

   if (arg2[0] == '\0')
   {
      if (number <= 1 && str_cmp(arg1, "all") && str_prefix("all.", arg1))
      {
         /* 'get obj' */
         obj = get_obj_list(ch, arg1, ch->in_room->first_content);
         if (!obj)
         {
            act(AT_PLAIN, "I see no $T here.", ch, NULL, arg1, TO_CHAR);
            return;
         }
         separate_obj(obj);
         get_obj(ch, obj, NULL);
         if (char_died(ch))
            return;
         if (IS_SET(sysdata.save_flags, SV_GET))
            save_char_obj(ch);
      }
      else
      {
         sh_int cnt = 0;
         bool fAll;
         char *chk;

         if (xIS_SET(ch->in_room->room_flags, ROOM_DONATION))
         {
            send_to_char("The gods frown upon such a display of greed!\n\r", ch);
            return;
         }
         if (!str_cmp(arg1, "all"))
            fAll = TRUE;
         else
            fAll = FALSE;
         if (number > 1)
            chk = arg1;
         else
            chk = &arg1[4];
         /* 'get all' or 'get all.obj' */
         found = FALSE;
         for (obj = ch->in_room->last_content; obj; obj = obj_next)
         {
            obj_next = obj->prev_content;
            if ((fAll || nifty_is_name(chk, obj->name)) && can_see_obj(ch, obj))
            {

               if (IS_OBJ_STAT(obj, ITEM_ONMAP))
               {
                  if (ch->map != obj->map
                     || ch->coord->x != obj->coord->x
                     || ch->coord->y != obj->coord->y)
                  {
                     found = FALSE;
                     continue;
                  }
               }
               found = TRUE;
               if (number && (cnt + obj->count) > number)
                  split_obj(obj, number - cnt);
               cnt += obj->count;
               get_obj(ch, obj, NULL);
               if (char_died(ch) || get_ch_carry_number(ch) >= can_carry_n(ch) || get_ch_carry_weight(ch) >= can_carry_w(ch) || (number && cnt >= number))
               {
                  if (IS_SET(sysdata.save_flags, SV_GET) && !char_died(ch))
                     save_char_obj(ch);
                  return;
               }
            }
         }

         if (!found)
         {
            if (fAll)
               send_to_char("I see nothing here.\n\r", ch);
            else
               act(AT_PLAIN, "I see no $T here.", ch, NULL, chk, TO_CHAR);
         }
         else if (IS_SET(sysdata.save_flags, SV_GET))
            save_char_obj(ch);
      }
   }
   else
   {
      /* 'get ... container' */
      if (!str_cmp(arg2, "all") || !str_prefix("all.", arg2))
      {
         send_to_char("You can't do that.\n\r", ch);
         return;
      }

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

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

         case ITEM_CONTAINER:
         case ITEM_CORPSE_NPC:
         case ITEM_KEYRING:
         case ITEM_QUIVER:
         case ITEM_SHEATH:
            break;

         case ITEM_CORPSE_PC:
            {
               bool fGroup;
               char name[MIL];
               CHAR_DATA *gch;
               char *pd;

               fGroup = FALSE;

               if (IS_NPC(ch))
               {
                  send_to_char("You can't do that.\n\r", ch);
                  return;
               }

               pd = container->short_descr;
               pd = one_argument(pd, name);
               pd = one_argument(pd, name);
               pd = one_argument(pd, name);
               pd = one_argument(pd, name);

               /* Killer/owner loot only if die to pkill blow --Blod */
               if (IS_OBJ_STAT(container, ITEM_CLANCORPSE)
                  && !IS_NPC(ch)
                  && container->action_desc[0] != '\0'
                  && str_cmp(name, ch->name) && str_cmp(container->action_desc, ch->name) && container->timer > 2878)
               {
                  send_to_char("The corpse is too fresh to loot at this moment..\n\r", ch);
                  return;
               }

               if (IS_OBJ_STAT(container, ITEM_CLANCORPSE)
                  && !IS_NPC(ch) && container->action_desc[0] != '\0' && !str_cmp(container->action_desc, ch->name))
               {
                  if (check_room_pk(ch) == 4)
                     fGroup = TRUE;
               }

               if (IS_OBJ_STAT(container, ITEM_CLANCORPSE) && container->timer < 2879)
               {
                  if (check_room_pk(ch) == 4)
                     fGroup = TRUE;
               }

               if (str_cmp(name, ch->name) && !IS_IMMORTAL(ch))
               {
                  for (gch = first_char; gch; gch = gch->next)
                  {
                     if (!IS_NPC(gch) && is_same_group(ch, gch) && !str_cmp(name, gch->name))
                     {
                        fGroup = TRUE;
                        break;
                     }
                  }

                  if (!fGroup)
                  {
                     send_to_char("That's someone else's corpse.\n\r", ch);
                     return;
                  }
               }
            }
      }
      if (container->item_type == ITEM_CONTAINER || container->item_type == ITEM_QUIVER)
      {
         if (!IS_OBJ_STAT(container, ITEM_COVERING) && IS_SET(container->value[1], CONT_CLOSED))
         {
            act(AT_PLAIN, "The $d is closed.", ch, NULL, container->name, TO_CHAR);
            return;
         }
      }

      if (number <= 1 && str_cmp(arg1, "all") && str_prefix("all.", arg1))
      {
         /* 'get obj container' */
         obj = get_obj_list(ch, arg1, container->first_content);
         if (!obj)
         {
            act(AT_PLAIN, IS_OBJ_STAT(container, ITEM_COVERING) ?
               "I see nothing like that beneath the $T." : "I see nothing like that in the $T.", ch, NULL, arg2, TO_CHAR);
            return;
         }
         separate_obj(obj);
         check_for_trap(ch, container, TRAP_GET, NEW_TRAP_GET);
         if (char_died(ch))
            return;
         if (global_retcode == rOBJ_SCRAPPED)
            return;
         get_obj(ch, obj, container);
         /* Oops no wonder corpses were duping oopsie did I do that
          * --Shaddai
          */
         if (container->item_type == ITEM_CORPSE_PC)
            write_corpses(NULL, container->short_descr + 14, NULL);
         if (IS_SET(sysdata.save_flags, SV_GET))
            save_char_obj(ch);
      }
      else
      {
         int cnt = 0;
         bool fAll;
         char *chk;

         /* 'get all container' or 'get all.obj container' */
         if (IS_OBJ_STAT(container, ITEM_DONATION))
         {
            send_to_char("The gods frown upon such an act of greed!\n\r", ch);
            return;
         }

         if (!str_cmp(arg1, "all"))
            fAll = TRUE;
         else
            fAll = FALSE;
         if (number > 1)
            chk = arg1;
         else
            chk = &arg1[4];
         found = FALSE;
         check_for_trap(ch, container, TRAP_GET, NEW_TRAP_GET);
         if (char_died(ch))
            return;
         if (global_retcode == rOBJ_SCRAPPED)
            return;
         for (obj = container->first_content; obj; obj = obj_next)
         {
            obj_next = obj->next_content;
            if ((fAll || nifty_is_name(chk, obj->name)) && can_see_obj(ch, obj))
            {
               found = TRUE;
               if (number && (cnt + obj->count) > number)
                  split_obj(obj, number - cnt);
               cnt += obj->count;
               get_obj(ch, obj, container);
               if (char_died(ch) || get_ch_carry_number(ch) >= can_carry_n(ch) || get_ch_carry_weight(ch) >= can_carry_w(ch) || (number && cnt >= number))
                  return;
            }
         }

         if (!found)
         {
            if (fAll)
            {
               if (container->item_type == ITEM_KEYRING && !IS_OBJ_STAT(container, ITEM_COVERING))
                  act(AT_PLAIN, "The $T holds no keys.", ch, NULL, arg2, TO_CHAR);
               else
                  act(AT_PLAIN, IS_OBJ_STAT(container, ITEM_COVERING) ?
                     "I see nothing beneath the $T." : "I see nothing in the $T.", ch, NULL, arg2, TO_CHAR);
            }
            else
            {
               if (container->item_type == ITEM_KEYRING && !IS_OBJ_STAT(container, ITEM_COVERING))
                  act(AT_PLAIN, "The $T does not hold that key.", ch, NULL, arg2, TO_CHAR);
               else
                  act(AT_PLAIN, IS_OBJ_STAT(container, ITEM_COVERING) ?
                     "I see nothing like that beneath the $T." : "I see nothing like that in the $T.", ch, NULL, arg2, TO_CHAR);
            }
         }
         /* Oops no wonder corpses were duping oopsie did I do that
          * --Shaddai
          */
         if (container && container->item_type == ITEM_CORPSE_PC)
            write_corpses(NULL, container->short_descr + 14, NULL);
         if (found && IS_SET(sysdata.save_flags, SV_GET))
            save_char_obj(ch);
      }
   }
   return;
}



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

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

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

   if (ms_find_obj(ch))
      return;

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

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

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

   if (IS_OBJ_STAT(container, ITEM_COVERING))
   {
      if (get_ch_carry_weight(ch) + container->weight > can_carry_w(ch))
      {
         send_to_char("It's too heavy for you to lift.\n\r", ch);
         return;
      }
   }
   else
   {
      if (container->item_type != ITEM_CONTAINER
         && container->item_type != ITEM_KEYRING && container->item_type != ITEM_QUIVER && container->item_type != ITEM_SHEATH)
      {
         send_to_char("That's not a container.\n\r", ch);
         return;
      }
      if (container->item_type == ITEM_CONTAINER || container->item_type == ITEM_QUIVER)
      {
         if (IS_SET(container->value[1], CONT_CLOSED))
         {
            act(AT_PLAIN, "The $d is closed.", ch, NULL, container->name, TO_CHAR);
            return;
         }
      }
   }

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

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

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

/* Check to see if they are trying to cheat by putting the item in a container --Xerves 3/24/99 */


      if ((IS_OBJ_STAT(obj, ITEM_NOGIVE) && !IS_OBJ_STAT(container, ITEM_NOGIVE))
         || (IS_OBJ_STAT(container, ITEM_NOGIVE) && !IS_OBJ_STAT(obj, ITEM_NOGIVE)))
      {
         send_to_char("You failed again my friend!\n\r", ch);
         return;
      }
      
      if (container && (IS_UNIQUE(ch, container) || IS_UNIQUE(ch, obj)) && obj->item_type == ITEM_CONTAINER)
      {
         send_to_char("You cannot put a unique container in any kind of container.\n\r", ch);
         return;
      }

      if (container->item_type == ITEM_KEYRING && obj->item_type != ITEM_KEY)
      {
         send_to_char("That's not a key.\n\r", ch);
         return;
      }

      if (container->item_type == ITEM_QUIVER && obj->item_type != ITEM_PROJECTILE)
      {
         send_to_char("That's not a projectile.\n\r", ch);
         return;
      }
      if (container->item_type == ITEM_SHEATH && (container->value[1] != obj->value[3]))
      {
         send_to_char("You can only put a weapon made for the sheath in the sheath.\n\r", ch);
         return;
      }
      if (container->item_type == ITEM_SHEATH && ((container->value[2] != obj->pIndexData->vnum) && container->value[2] != 0))
      {
         send_to_char("Your sheath was made for only one weapon and the weapon you have it not it.\n\r", ch);
         return;
      }
      if ((IS_OBJ_STAT(container, ITEM_COVERING)
            && (get_obj_weight(obj) / obj->count) > ((get_obj_weight(container) / container->count) - container->weight)))
      {
         send_to_char("It won't fit under there.\n\r", ch);
         return;
      }

      /* note use of get_real_obj_weight */
      if ((get_real_obj_weight(obj) / obj->count) + (get_real_obj_weight(container) / container->count) > container->value[0])
      {
         send_to_char("It won't fit.\n\r", ch);
         return;
      }
      /* Don't need all of this, but will probably use it later on containers --Xerves */
      if (container->item_type == ITEM_SHEATH)
      {
         count = 0;
         if (container->first_content)
         {
            for (sheath = container->first_content; sheath; sheath = sheath->next_content)
               count++;
         }

         if (count == 1)
         {
            send_to_char("Sheath's only fit one weapon, remove the one in it first.\n\r", ch);
            return;
         }
      }
      separate_obj(obj);
      separate_obj(container);
      obj_from_char(obj);
      obj = obj_to_obj(obj, container);
      count = obj->count;
      obj->count = 1;
      if (container->item_type == ITEM_KEYRING && !IS_OBJ_STAT(container, ITEM_COVERING))
      {
         act(AT_ACTION, "$n slips $p onto $P.", ch, obj, container, TO_ROOM);
         act(AT_ACTION, "You slip $p onto $P.", ch, obj, container, TO_CHAR);
      }
      else
      {
         act(AT_ACTION, IS_OBJ_STAT(container, ITEM_COVERING) ? "$n hides $p beneath $P." : "$n puts $p in $P.", ch, obj, container, TO_ROOM);
         act(AT_ACTION, IS_OBJ_STAT(container, ITEM_COVERING) ? "You hide $p beneath $P." : "You put $p in $P.", ch, obj, container, TO_CHAR);
      }
      obj->count = count;
      check_for_trap(ch, container, TRAP_PUT, NEW_TRAP_PUT);
      if (char_died(ch))
         return;
      if (global_retcode == rOBJ_SCRAPPED)
         return;
      check_for_trap(ch, obj, -1, NEW_TRAP_PUTOBJ);
      if (char_died(ch))
         return;
      if (global_retcode == rOBJ_SCRAPPED)
         return;
      /* Oops no wonder corpses were duping oopsie did I do that
       * --Shaddai
       */
      if (container->item_type == ITEM_CORPSE_PC)
         write_corpses(NULL, container->short_descr + 14, NULL);

      if (save_char)
         save_char_obj(ch);

      // Check to see if it is a kingdom chest
      if (container && is_kingdom_chest(container))
         save_kingdom_chests(ch);
      /* Clan storeroom check */
      if (xIS_SET(ch->in_room->room_flags, ROOM_CLANSTOREROOM) && container->carried_by == NULL)
      {
/*	   if (!char_died && !save_char ) save_char_obj(ch); */
         for (clan = first_clan; clan; clan = clan->next)
            if (clan->storeroom == ch->in_room->vnum)
               save_clan_storeroom(ch, clan);
      }
   }
   else
   {
      bool found = FALSE;
      int cnt = 0;
      bool fAll;
      char *chk;

      if (container->item_type == ITEM_SHEATH)
      {
         send_to_char("You cannot put all your items in a sheath, only one weapon.\n\r", ch);
         return;
      }

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

      separate_obj(container);
      check_for_trap(ch, container, TRAP_PUT, NEW_TRAP_PUT);
      if (char_died(ch))
         return;
      if (global_retcode == rOBJ_SCRAPPED)
         return; 
      /* 'put all container' or 'put all.obj container' */
      for (obj = ch->first_carrying; obj; obj = obj_next)
      {
         obj_next = obj->next_content;

         if ((fAll || nifty_is_name(chk, obj->name))
            && can_see_obj(ch, obj)
            && obj->wear_loc == WEAR_NONE
            && obj != container
            && can_drop_obj(ch, obj)
            && (container->item_type != ITEM_KEYRING || obj->item_type == ITEM_KEY)
            && (container->item_type != ITEM_QUIVER || obj->item_type == ITEM_PROJECTILE)
            && get_obj_weight(obj) + get_obj_weight(container) <= container->value[0])
         {
            found = TRUE;
            if ((IS_OBJ_STAT(obj, ITEM_NOGIVE) && !IS_OBJ_STAT(container, ITEM_NOGIVE))
            || (IS_OBJ_STAT(container, ITEM_NOGIVE) && !IS_OBJ_STAT(obj, ITEM_NOGIVE)))
               continue;
      
            if (container && (IS_UNIQUE(ch, container) || IS_UNIQUE(ch, obj)) && obj->item_type == ITEM_CONTAINER)
               continue; 
            if (number && (cnt + obj->count) > number)
               split_obj(obj, number - cnt);
            cnt += obj->count;
            obj_from_char(obj);
            if (container->item_type == ITEM_KEYRING)
            {
               act(AT_ACTION, "$n slips $p onto $P.", ch, obj, container, TO_ROOM);
               act(AT_ACTION, "You slip $p onto $P.", ch, obj, container, TO_CHAR);
            }
            else
            {
               act(AT_ACTION, "$n puts $p in $P.", ch, obj, container, TO_ROOM);
               act(AT_ACTION, "You put $p in $P.", ch, obj, container, TO_CHAR);
            }
            obj = obj_to_obj(obj, container);
            check_for_trap(ch, obj, -1, NEW_TRAP_PUTOBJ);
            if (char_died(ch))
               return;
            if (global_retcode == rOBJ_SCRAPPED)
               return;
            if (number && cnt >= number)
               break;
         }
      }
      check_for_trap(ch, container, TRAP_PUT, NEW_TRAP_PUT);
      if (char_died(ch))
         return;
      if (global_retcode == rOBJ_SCRAPPED)
         return;
      /*
       * Don't bother to save anything if nothing was dropped   -Thoric
       */
      if (!found)
      {
         if (fAll)
            act(AT_PLAIN, "You are not carrying anything.", ch, NULL, NULL, TO_CHAR);
         else
            act(AT_PLAIN, "You are not carrying any $T.", ch, NULL, chk, TO_CHAR);
         return;
      }
      else
      {
         send_to_char("Done.\n\r", ch);
      }
      
      if (save_char)
         save_char_obj(ch);
      /* Oops no wonder corpses were duping oopsie did I do that
       * --Shaddai
       */
      if (container->item_type == ITEM_CORPSE_PC)
         write_corpses(NULL, container->short_descr + 14, NULL);
      // Check to see if it is a kingdom chest
      if (container && is_kingdom_chest(container))
         save_kingdom_chests(ch);
      /* Clan storeroom check */
      if (xIS_SET(ch->in_room->room_flags, ROOM_CLANSTOREROOM) && container->carried_by == NULL)
      {
/*	  if (!char_died && !save_char) save_char_obj(ch); */
         for (clan = first_clan; clan; clan = clan->next)
            if (clan->storeroom == ch->in_room->vnum)
               save_clan_storeroom(ch, clan);
      }
   }

   return;
}


void do_drop(CHAR_DATA * ch, char *argument)
{
   char arg[MIL];
   OBJ_DATA *obj;
   OBJ_DATA *obj_next;
   bool found;
   CLAN_DATA *clan;
   int number;

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

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

   if (ms_find_obj(ch))
      return;

   if (xIS_SET(ch->act, PLR_LITTERBUG))
   {
      set_char_color(AT_YELLOW, ch);
      send_to_char("A godly force prevents you from dropping anything...\n\r", ch);
      return;
   }
   
   if (IS_NPC(ch) && xIS_SET(ch->act, ACT_MILITARY))
   {
      send_to_char("You cannot do that.\n\r", ch);
      return;
   }

   if ((wIS_SET(ch, ROOM_NODROP) || xIS_SET(ch->in_room->room_flags, ROOM_NODROP)) && ch != supermob)
   {
      set_char_color(AT_MAGIC, ch);
      send_to_char("A magical force stops you!\n\r", ch);
      set_char_color(AT_TELL, ch);
      send_to_char("Someone tells you, 'No littering here!'\n\r", ch);
      return;
   }

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

      if (!str_cmp(arg, "coins") || !str_cmp(arg, "coin"))
      {
         if (ch->gold < number)
         {
            send_to_char("You haven't got that many coins.\n\r", ch);
            return;
         }

         ch->gold -= number;

         for (obj = ch->in_room->first_content; obj; obj = obj_next)
         {
            obj_next = obj->next_content;

            if (ch->coord->x != obj->coord->x || ch->coord->y != obj->coord->y || ch->map != obj->map)
               continue;

            switch (obj->pIndexData->vnum)
            {
               case OBJ_VNUM_MONEY_ONE:
                  number += 1;
                  extract_obj(obj);
                  break;

               case OBJ_VNUM_MONEY_SOME:
                  number += obj->value[0];
                  extract_obj(obj);
                  break;
            }
         }

         act(AT_ACTION, "$n drops some gold.", ch, NULL, NULL, TO_ROOM);
         obj_to_room(create_money(number), ch->in_room, ch);
         send_to_char("OK.\n\r", ch);
         if (IS_SET(sysdata.save_flags, SV_DROP))
            save_char_obj(ch);
         return;
      }
   }

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

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

      separate_obj(obj);
      act(AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM);
      act(AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR);
         
      obj_from_char(obj);
      obj = obj_to_room(obj, ch->in_room, ch);
      check_for_trap(ch, obj, -1, NEW_TRAP_DROPOBJ);
      if (char_died(ch))
         return;
      if (global_retcode == rOBJ_SCRAPPED)
         return; 
      oprog_drop_trigger(ch, obj); /* mudprogs */

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

      /* Clan storeroom saving */
      if (xIS_SET(ch->in_room->room_flags, ROOM_CLANSTOREROOM))
      {
/*	   if (!char_died) save_char_obj(ch); */
         for (clan = first_clan; clan; clan = clan->next)
            if (clan->storeroom == ch->in_room->vnum)
               save_clan_storeroom(ch, clan);
      }
   }
   else
   {
      int cnt = 0;
      char *chk;
      bool fAll;

      if (!str_cmp(arg, "all"))
         fAll = TRUE;
      else
         fAll = FALSE;
      if (number > 1)
         chk = arg;
      else
         chk = &arg[4];
      /* 'drop all' or 'drop all.obj' */
      if (wIS_SET(ch, ROOM_NODROPALL) || xIS_SET(ch->in_room->room_flags, ROOM_NODROPALL) 
      ||  xIS_SET(ch->in_room->room_flags, ROOM_CLANSTOREROOM))
      {
         send_to_char("You can't seem to do that here...\n\r", ch);
         return;
      }
      found = FALSE;
      for (obj = ch->first_carrying; obj; obj = obj_next)
      {
         obj_next = obj->next_content;

         if ((fAll || nifty_is_name(chk, obj->name)) && can_see_obj(ch, obj) && obj->wear_loc == WEAR_NONE && can_drop_obj(ch, obj))
         {
            found = TRUE;
            if (HAS_PROG(obj->pIndexData, DROP_PROG) && obj->count > 1)
            {
               ++cnt;
               separate_obj(obj);
               obj_from_char(obj);
               if (!obj_next)
                  obj_next = ch->first_carrying;
            }
            else
            {
               if (number && (cnt + obj->count) > number)
                  split_obj(obj, number - cnt);
               cnt += obj->count;
               obj_from_char(obj);
            }
            act(AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM);
            act(AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR);
            obj = obj_to_room(obj, ch->in_room, ch);
            check_for_trap(ch, obj, -1, NEW_TRAP_DROPOBJ);
            if (char_died(ch))
               return;
            if (global_retcode == rOBJ_SCRAPPED)
               return;
            oprog_drop_trigger(ch, obj); /* mudprogs */
            if (char_died(ch))
               return;
            if (number && cnt >= number)
               break;
         }
      }

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



void do_give(CHAR_DATA * ch, char *argument)
{
   char arg1[MIL];
   char arg2[MIL];
   char buf[MIL];
   CHAR_DATA *victim;
   OBJ_DATA *obj;
   SLAB_DATA *slab;
   int cnt;

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

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

   if (ms_find_obj(ch))
      return;

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

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

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

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

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

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

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

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

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

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

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

   /* Prevents giving of special items (rare items) -- Xerves 3/24/99 */
   if (IS_OBJ_STAT(obj, ITEM_NOGIVE) && !IS_IMMORTAL(ch) && !IS_IMMORTAL(victim))
   {
      send_to_char("You cannot give this item to another, it is special.\n\r", ch);
      return;
   }
   if (IS_UNIQUE(victim, obj))
   {
      send_to_char("That item is unique and your target already has one.\n\r", ch);
      return;
   }
   if (IS_NPC(victim))
   {
      if (xIS_SET(victim->act, ACT_CASTEMOB))
      {
         send_to_char("Sorry, I do not accept donations.\n\r", ch);
         return;
      }
      if (xIS_SET(victim->act, ACT_MILITARY))
      {
         send_to_char("You cannot give objects to a military mobile.\n\r", ch);
         return;
      }
   }
   if (get_ch_carry_number(victim) + (get_obj_number(obj) / obj->count) > can_carry_n(victim))
   {
      act(AT_PLAIN, "$N has $S hands full.", ch, NULL, victim, TO_CHAR);
      return;
   }

   if (get_ch_carry_weight(victim) + (get_obj_weight(obj) / obj->count) > can_carry_w(victim))
   {
      act(AT_PLAIN, "$N can't carry that much weight.", ch, NULL, victim, TO_CHAR);
      return;
   }

   if (!can_see_obj(victim, obj))
   {
      act(AT_PLAIN, "$N can't see it.", ch, NULL, victim, TO_CHAR);
      return;
   }

   if (IS_OBJ_STAT(obj, ITEM_PROTOTYPE) && !can_take_proto(victim))
   {
      act(AT_PLAIN, "You cannot give that to $N!", ch, NULL, victim, TO_CHAR);
      return;
   }
   cnt = 1;
   if (isdigit(argument[0]) && IS_IMMORTAL(ch) && xIS_SET(obj->extra_flags, ITEM_FORGEABLE))
   {
      for (slab = first_slab; slab ; slab = slab->next) 
      {
         if (atoi(argument) == cnt)
            break;
         cnt++;
      }
      if (!slab)
      {
         send_to_char("There is no such ore (type forge ores)\n\r", ch);
         return;
      }
      obj->value[6] = slab->vnum;
      ch_printf(ch, "That item will now load as %s.\n\r", slab->adj);
   }

   separate_obj(obj);
   act(AT_ACTION, "$n gives $p to $N.", ch, obj, victim, TO_NOTVICT);
   act(AT_ACTION, "$n gives you $p.", ch, obj, victim, TO_VICT);
   act(AT_ACTION, "You give $p to $N.", ch, obj, victim, TO_CHAR);
   obj_from_char(obj);
   obj = obj_to_char(obj, victim);
   mprog_give_trigger(victim, ch, obj);
   if (IS_SET(sysdata.save_flags, SV_GIVE) && !char_died(ch))
      save_char_obj(ch);
   if (IS_SET(sysdata.save_flags, SV_RECEIVE) && !char_died(victim))
      save_char_obj(victim);
   check_for_trap(ch, obj, -1, NEW_TRAP_GIVEOBJ);
   if (char_died(ch))
      return;
   if (global_retcode == rOBJ_SCRAPPED)
      return;
   return;
}

/*
 * Damage an object.						-Thoric
 * Affect player's AC if necessary.
 * Make object into scraps if necessary.
 * Send message about damaged object.
 */
obj_ret damage_obj(OBJ_DATA * obj, CHAR_DATA * attacker, int proj, int dam)
{
   CHAR_DATA *ch;
   OBJ_DATA *wpn;
   obj_ret objcode;
   int durability;

   ch = obj->carried_by;
   objcode = rNONE;

   // Promote that carnage!!!  -- Xerves
   if (in_arena(ch))
   {
      act(AT_OBJECT, "(Xerves magically prevents $p from being damaged)", ch, obj, NULL, TO_CHAR);
      return objcode;
   }

   if (IS_OBJ_STAT(obj, ITEM_NOBREAK))
   {

      if (obj->item_type != ITEM_LIGHT)
         oprog_damage_trigger(ch, obj);
      else if (!in_arena(ch))
         oprog_damage_trigger(ch, obj);

      return objcode;
   }

   separate_obj(obj);

   if (obj->item_type != ITEM_LIGHT)
      oprog_damage_trigger(ch, obj);
   else if (!in_arena(ch))
      oprog_damage_trigger(ch, obj);

   if (obj_extracted(obj))
      return global_objcode;

   switch (obj->item_type)
   {
      default:
         make_scraps(obj, attacker);
         objcode = rOBJ_SCRAPPED;
         break;
      case ITEM_CONTAINER:
      case ITEM_KEYRING:
      case ITEM_QUIVER:
      case ITEM_SHEATH:
         if (--obj->value[3] <= 0)
         {
            if (!in_arena(ch))
            {
               make_scraps(obj, attacker);
               objcode = rOBJ_SCRAPPED;
            }
            else
               obj->value[3] = 1;
         }
         break;
      case ITEM_LIGHT:
         if (--obj->value[0] <= 0)
         {
            if (!in_arena(ch))
            {
               make_scraps(obj, attacker);
               objcode = rOBJ_SCRAPPED;
            }
            else
               obj->value[0] = 1;
         }
         break;
      case ITEM_WEAPON:
         if (attacker && !in_arena(ch))
         {  
            durability = UMAX(1, obj->value[10]);
            dam = dam * 2 / durability;
            if (proj == 1) //Less wear on the actual bows
               dam /= 3;
            if (dam < 1)
               dam = 1;
            obj->value[0] -= dam;
            
            if (obj->value[0] <= 0)
            {
               make_scraps(obj, attacker);
               objcode = rOBJ_SCRAPPED;
            }
            else if (obj->value[0] < 200)
            {
               act(AT_RED, "$p is almost broken, you need to fix it immediately!", ch, obj, NULL, TO_CHAR);
            }
            else if (obj->value[0] < 400)
            {
               act(AT_WHITE, "$p is damaged, you need to fix it immediately!", ch, obj, NULL, TO_CHAR);
            }
            break;
         }
      case ITEM_ARMOR:
         durability = UMAX(1, obj->value[4]);
         if (attacker && !in_arena(ch))
         {
            if (IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
            {
               dam = number_range(dam*5/10, dam*7/10);
               if (proj == 1)
                  dam /= 3;
               if (dam < 1)
                  dam = 1;
               obj->value[0] -= dam;
            
               if (obj->value[0] <= 0)
               {
                  make_scraps(obj, attacker);
                  objcode = rOBJ_SCRAPPED;
               }
               break;
            }
            if (proj == 0)
               wpn = get_eq_char(attacker, WEAR_WIELD);
            else
               wpn = get_eq_char(attacker, WEAR_MISSILE_WIELD);
               
            if (proj == 1) //Stab
            {
               dam = dam * 6 / durability/ 10;
               obj->value[3] -= URANGE(1, dam, 40);
            }
            else
            {
               if (attacker->grip == GRIP_BASH)
               {
                  dam = dam * 6 / durability;
                  obj->value[3] -= URANGE(2, dam, 60);
               }
               if (attacker->grip == GRIP_STAB)
               {
                  dam = dam * 2 / durability;
                  obj->value[3] -= URANGE(1, dam, 30);
               }
               if (attacker->grip == GRIP_SLASH)
               {
                  dam = dam * 4 / durability;
                  obj->value[3] -= URANGE(1, dam, 40);
               }
            }
         }
         else
         {
            dam = dam / (1+(durability/5));
            obj->value[3] -= UMAX(1, dam);   
         }
         if (obj->value[3] <= 0)
         {
            make_scraps(obj, attacker);
            objcode = rOBJ_SCRAPPED;
         }
         else if (obj->value[3] < 200 && !IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
         {
            act(AT_RED, "$p is almost broken, you need to fix it immediately!", ch, obj, NULL, TO_CHAR);
         }
         else if (obj->value[3] < 400 && !IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
         {
            act(AT_WHITE, "$p is damaged, you need to fix it immediately!", ch, obj, NULL, TO_CHAR);
         }
         else if (obj->value[1] && obj->value[0] * 1000 / obj->value[1] < 200 && IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
         {
            act(AT_RED, "$p is almost broken, you need to fix it immediately!", ch, obj, NULL, TO_CHAR);
         }
         else if (obj->value[1] && obj->value[0] * 1000 / obj->value[1] < 400 && IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
         {
            act(AT_WHITE, "$p is damaged, you need to fix it immediately!", ch, obj, NULL, TO_CHAR);
         }
         break;
   }
   return objcode;
}


/*
 * Remove an object.
 * Added support to check only and not remove, it is fReplace 2, 0 and 1 are FALSE/TRUE
 */
bool remove_obj(CHAR_DATA * ch, int iWear, sh_int fReplace)
{
   OBJ_DATA *obj, *tmpobj;

   obj = get_eq_char(ch, iWear);
   if (!obj)
   {
      return TRUE;
   }

   if (!fReplace && get_ch_carry_number(ch) + get_obj_number(obj) > can_carry_n(ch))
   {
      act(AT_PLAIN, "$d: you can't carry that many items.", ch, NULL, obj->name, TO_CHAR);
      return FALSE;
   }

   if (!fReplace)
      return FALSE;
   
   if (IS_OBJ_STAT(obj, ITEM_NOREMOVE))
   {
      act(AT_PLAIN, "You can't remove $p.", ch, obj, NULL, TO_CHAR);
      return FALSE;
   }
   if (ch->fighting)
   {
      if (IS_SET(obj->wear_flags, ITEM_LODGE_RIB) || IS_SET(obj->wear_flags, ITEM_LODGE_ARM) || IS_SET(obj->wear_flags, ITEM_LODGE_LEG))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 1;
      }
      if (IS_SET(obj->wear_flags, ITEM_WIELD) || IS_SET(obj->wear_flags, ITEM_DUAL_WIELD) || IS_SET(obj->wear_flags, ITEM_MISSILE_WIELD)
      ||  IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 2;
      }
      if (IS_SET(obj->wear_flags, ITEM_WEAR_FINGER) || IS_SET(obj->wear_flags, ITEM_WEAR_ABOUT_NECK) || IS_SET(obj->wear_flags, ITEM_WEAR_BACK)
      ||  IS_SET(obj->wear_flags, ITEM_WEAR_WAIST))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 2;
      }
      if (IS_SET(obj->wear_flags, ITEM_WEAR_HEAD) || IS_SET(obj->wear_flags, ITEM_WEAR_NECK) || IS_SET(obj->wear_flags, ITEM_WEAR_ARMS))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 3;
      }
      if (IS_SET(obj->wear_flags, ITEM_WEAR_LEGS))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 4;
      }
      if (IS_SET(obj->wear_flags, ITEM_WEAR_BODY))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 6;
      }
   }  
   if (fReplace == 2)
      return TRUE;
   else
   {
      if (obj == get_eq_char(ch, WEAR_WIELD) && (tmpobj = get_eq_char(ch, WEAR_DUAL_WIELD)) != NULL)
         tmpobj->wear_loc = WEAR_WIELD;
      unequip_char(ch, obj);

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

/*
 * See if char could be capable of dual-wielding		-Thoric
 */
bool could_dual(CHAR_DATA * ch)
{
   if (IS_NPC(ch) || (ch->pcdata->learned[gsn_dual_wield] && ch->pcdata->ranking[gsn_dual_wield]))
      return TRUE;

   return FALSE;
}

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

   if (get_eq_char(ch, WEAR_DUAL_WIELD))
   {
      send_to_char("You are already wielding two weapons!\n\r", ch);
      return FALSE;
   }
   if (get_eq_char(ch, WEAR_SHIELD))
   {
      send_to_char("You cannot dual wield while holding a shield!\n\r", ch);
      return FALSE;
   }
   if (ch->con_rarm == -1 || ch->con_larm == -1)
   {
      send_to_char("You cannot dual wield without the use of an arm\n\r", ch);
      return FALSE;
   }
   return TRUE;
}


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

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

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

   return FALSE;
}

/*
 * Wear one object.
 * Optional replacement of existing objects.
 * Big repetitive code, ick.
 *
 * Restructured a bit to allow for specifying body location	-Thoric
 * & Added support for layering on certain body locations
 */
void wear_obj(CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace, sh_int wear_bit)
{
   char buf[MSL];
   char *wbuf;
   char name[MSL];
   OBJ_DATA *tmpobj = NULL;
   sh_int bit, tmp;
   int race = -1;

   separate_obj(obj);
   if (get_trust(ch) < obj->level && !IS_OBJ_STAT(obj, ITEM_LODGED))
   {
      sprintf(buf, "You must be level %d to use this object.\n\r", obj->level);
      send_to_char(buf, ch);
      act(AT_ACTION, "$n tries to use $p, but is too inexperienced.", ch, obj, NULL, TO_ROOM);
      return;
   }
   
   if (IS_OBJ_STAT(obj, ITEM_KINGDOMEQ) && !IS_OBJ_STAT(obj, ITEM_LODGED))
   {
      if (!IS_NPC(ch) || (IS_NPC(ch) && !xIS_SET(ch->act, ACT_MILITARY)))
      {
         send_to_char("Cannot equip this item, it is kingdom eq\n\r", ch);
         return;
      }
   }
   
   wbuf = obj->name;
   wbuf = one_argument(wbuf, name);
   wbuf = one_argument(wbuf, name);
       
   name[0] = UPPER(name[0]);
   if (!str_cmp(name, "Fairy"))
      race = 5;
   else if (!str_cmp(name, "Hobbit"))
      race = 4;
   else if (!str_cmp(name, "Ogre"))
      race = 3;
   else if (!str_cmp(name, "Dwarven"))
      race = 2;
   else if (!str_cmp(name, "Elven"))
      race = 1;
   else if (!str_cmp(name, "Human"))
      race = 0;
   else
   {
      if (xIS_SET(obj->extra_flags, ITEM_FORGEABLE))
      {
         bug("wear_obj: Invalid Race Name %s, on player %s", name, ch->name);
         send_to_char("Error: Invalid Race Name, tell an immortal.\n\r", ch);
         return;
      }
   }
   
   if (xIS_SET(obj->extra_flags, ITEM_FORGEABLE) && ch->race != race && obj->item_type == ITEM_ARMOR)
   {
      ch_printf(ch, "That item is %s in nature and you are not that race.\n\r", name);
      return;
   }
   if (race > -1 && ch->race != race && obj->item_type == ITEM_ARMOR)
   {
      ch_printf(ch, "That item is %s in nature and you are not that race.\n\r", name);
      return;
   }
   if (obj->item_type == ITEM_ARMOR && obj->value[5] >= ASIZE_HEAVY && ch->race == RACE_HOBBIT)
   {
      ch_printf(ch, "Hobbits cannot wear heavy armor.\n\r");
      return;
   }  
   
   if (obj->sworthrestrict > player_stat_worth(ch))
   {
      send_to_char("You are not powerful enough to use this.\n\r", ch);
      return;
   }
   
   if (ch->fighting)
   {
      if (IS_SET(obj->wear_flags, ITEM_LODGE_RIB) || IS_SET(obj->wear_flags, ITEM_LODGE_ARM) || IS_SET(obj->wear_flags, ITEM_LODGE_LEG))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 1;
      }
      if (IS_SET(obj->wear_flags, ITEM_WIELD) || IS_SET(obj->wear_flags, ITEM_DUAL_WIELD) || IS_SET(obj->wear_flags, ITEM_MISSILE_WIELD)
      ||  IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 2;
      }
      if (IS_SET(obj->wear_flags, ITEM_WEAR_FINGER) || IS_SET(obj->wear_flags, ITEM_WEAR_ABOUT_NECK) || IS_SET(obj->wear_flags, ITEM_WEAR_BACK)
      ||  IS_SET(obj->wear_flags, ITEM_WEAR_WAIST))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 2;
      }
      if (IS_SET(obj->wear_flags, ITEM_WEAR_HEAD) || IS_SET(obj->wear_flags, ITEM_WEAR_NECK) || IS_SET(obj->wear_flags, ITEM_WEAR_ARMS))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 3;
      }
      if (IS_SET(obj->wear_flags, ITEM_WEAR_LEGS))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 4;
      }
      if (IS_SET(obj->wear_flags, ITEM_WEAR_BODY))
      {
         if (!IS_NPC(ch))
            ch->fight_timer = 6;
      }
   }  

   if (wear_bit > -1)
   {
      bit = wear_bit;
      if (!CAN_WEAR(obj, 1 << bit))
      {
         if (fReplace)
         {
            switch (1 << bit)
            {
               case ITEM_WIELD:
               case ITEM_MISSILE_WIELD:
                  send_to_char("You cannot wield that.\n\r", ch);
                  break;
               case ITEM_WEAR_NOCKED:
                  send_to_char("You cannot nock that.\n\r", ch);
                  break;
               default:
                  sprintf(buf, "You cannot wear that on your %s.\n\r", w_flags[bit]);
                  send_to_char(buf, ch);
            }
         }
         return;
      }
   }
   else
   {
      for (bit = -1, tmp = 1; tmp < 31; tmp++)
      {
         if (CAN_WEAR(obj, 1 << tmp))
         {
            bit = tmp;
            break;
         }
      }
   }

   /* currently cannot have a light in non-light position */
   if (obj->item_type == ITEM_LIGHT)
   {
      if (!remove_obj(ch, WEAR_LIGHT, fReplace))
         return;
      if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
      {
         act(AT_ACTION, "$n holds $p as a light.", ch, obj, NULL, TO_ROOM);
         act(AT_ACTION, "You hold $p as your light.", ch, obj, NULL, TO_CHAR);
      }
      equip_char(ch, obj, WEAR_LIGHT);
      oprog_wear_trigger(ch, obj);
      return;
   }

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

   switch (1 << bit)
   {
      default:
         bug("wear_obj: uknown/unused item_wear bit %d", bit);
         if (fReplace)
            send_to_char("You can't wear, wield, or hold that.\n\r", ch);
         return;

      case ITEM_WEAR_NOCKED:
         if (!remove_obj(ch, WEAR_NOCKED, fReplace))
            return;
         if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
         {
            act(AT_ACTION, "$n nocks $p upon $s weapon.", ch, obj, NULL, TO_ROOM);
            act(AT_ACTION, "You nock $p upon your weapon.", ch, obj, NULL, TO_CHAR);
         }
         equip_char(ch, obj, WEAR_NOCKED);
         oprog_wear_trigger(ch, obj);
         return;
   
      case ITEM_WEAR_FINGER:
         if (get_eq_char(ch, WEAR_FINGER_L) != NULL
            && get_eq_char(ch, WEAR_FINGER_R) != NULL && !remove_obj(ch, WEAR_FINGER_L, fReplace) && !remove_obj(ch, WEAR_FINGER_R, fReplace))
            return;

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

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

         bug("Wear_obj: no free finger.", 0);
         send_to_char("You already wear two finger items.\n\r", ch);
         return;
  
      case ITEM_WEAR_ABOUT_NECK:
         if (!remove_obj(ch, WEAR_ABOUT_NECK, fReplace))
            return;
         if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
         {
            act(AT_ACTION, "$n clamps $p around $s neck.", ch, obj, NULL, TO_ROOM);
            act(AT_ACTION, "You clamp $p around your neck.", ch, obj, NULL, TO_CHAR);
         }
         equip_char(ch, obj, WEAR_ABOUT_NECK);
         oprog_wear_trigger(ch, obj);
         return;

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

      case ITEM_WEAR_ARMS:
         if (get_eq_char(ch, WEAR_ARM_L) != NULL
            && get_eq_char(ch, WEAR_ARM_R) != NULL && !remove_obj(ch, WEAR_ARM_L, fReplace) && !remove_obj(ch, WEAR_ARM_R, fReplace))
            return;

         if (!get_eq_char(ch, WEAR_ARM_L) && ch->con_larm != -1)
         {
            if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
            {
               act(AT_ACTION, "$n slides $p around $s left arm.", ch, obj, NULL, TO_ROOM);
               act(AT_ACTION, "You slide $p around your left arm.", ch, obj, NULL, TO_CHAR);
            }
            equip_char(ch, obj, WEAR_ARM_L);
            oprog_wear_trigger(ch, obj);
            return;
         }

         if (!get_eq_char(ch, WEAR_ARM_R) && ch->con_rarm != -1)
         {
            if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
            {
               act(AT_ACTION, "$n slides $p around $s right arm.", ch, obj, NULL, TO_ROOM);
               act(AT_ACTION, "You slide $p around your right arm.", ch, obj, NULL, TO_CHAR);
            }
            equip_char(ch, obj, WEAR_ARM_R);
            oprog_wear_trigger(ch, obj);
            return;
         }
         
         if ((ch->con_rarm == -1 || ch->con_larm == -1) && (!get_eq_char(ch, WEAR_ARM_R) || !get_eq_char(ch, WEAR_ARM_L)))
         {
            send_to_char("You cannot wear that around your arm because you arm is broken off.\n\r", ch);
            return;
         } 

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

      case ITEM_WEAR_LEGS:
         if (get_eq_char(ch, WEAR_LEG_L) != NULL
            && get_eq_char(ch, WEAR_LEG_R) != NULL && !remove_obj(ch, WEAR_LEG_L, fReplace) && !remove_obj(ch, WEAR_LEG_R, fReplace))
            return;

         if (!get_eq_char(ch, WEAR_LEG_L) && ch->con_lleg != -1)
         {
            if (ch->con_lleg == -1)
            {
               send_to_char("You cannot wear that around your leg because you leg is broken off.\n\r", ch);
               return;
            }
            if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
            {
               act(AT_ACTION, "$n slides $p around $s left leg.", ch, obj, NULL, TO_ROOM);
               act(AT_ACTION, "You slide $p around your left leg.", ch, obj, NULL, TO_CHAR);
            }
            equip_char(ch, obj, WEAR_LEG_L);
            oprog_wear_trigger(ch, obj);
            return;
         }

         if (!get_eq_char(ch, WEAR_LEG_R) && ch->con_rleg != -1)
         {
            if (ch->con_rleg == -1)
            {
               send_to_char("You cannot wear that around your leg because you leg is broken off.\n\r", ch);
               return;
            }
            if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
            {
               act(AT_ACTION, "$n slides $p around $s right leg.", ch, obj, NULL, TO_ROOM);
               act(AT_ACTION, "You slide $p around your right leg.", ch, obj, NULL, TO_CHAR);
            }
            equip_char(ch, obj, WEAR_LEG_R);
            oprog_wear_trigger(ch, obj);
            return;
         }
         
         if ((ch->con_rleg == -1 || ch->con_lleg == -1) && (!get_eq_char(ch, WEAR_LEG_R) || !get_eq_char(ch, WEAR_LEG_L)))
         {
            send_to_char("You cannot wear that around your arm because you arm is broken off.\n\r", ch);
            return;
         } 

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


      case ITEM_WEAR_BODY:
         if (!remove_obj(ch, WEAR_BODY, fReplace))
            return;
         //I hate layering, bye -- Xerves
         if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
         {
            act(AT_ACTION, "$n fits $p on $s body.", ch, obj, NULL, TO_ROOM);
            act(AT_ACTION, "You fit $p on your body.", ch, obj, NULL, TO_CHAR);
         }
         equip_char(ch, obj, WEAR_BODY);
         oprog_wear_trigger(ch, obj);
         return;

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

      case ITEM_LODGE_RIB:
         if (!remove_obj(ch, WEAR_LODGE_RIB, fReplace))
            return;
         if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
         {
            act(AT_ACTION, "$p lodges itself in $n's ribs.", ch, obj, NULL, TO_ROOM);
            sprintf(buf, "$p &G&W[&RLODGES&G&W]%s itself in your ribs.", char_color_str(AT_ACTION, ch));
            act(AT_ACTION, buf, ch, obj, NULL, TO_CHAR);
         }
         equip_char(ch, obj, WEAR_LODGE_RIB);
         oprog_wear_trigger(ch, obj);
         return;


      case ITEM_LODGE_ARM:
         if (!remove_obj(ch, WEAR_LODGE_ARM, fReplace))
            return;
         if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
         {
            act(AT_ACTION, "$p lodges itself in $n's ribs.", ch, obj, NULL, TO_ROOM);
            sprintf(buf, "$p &G&W[&RLODGES&G&W]%s itself in your arm.", char_color_str(AT_ACTION, ch));
            act(AT_ACTION, buf, ch, obj, NULL, TO_CHAR);
         }
         equip_char(ch, obj, WEAR_LODGE_ARM);
         oprog_wear_trigger(ch, obj);
         return;

      case ITEM_LODGE_LEG:
         if (!remove_obj(ch, WEAR_LODGE_LEG, fReplace))
            return;
         if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
         {
            act(AT_ACTION, "$p lodges itself in $n's ribs.", ch, obj, NULL, TO_ROOM);
            sprintf(buf, "$p &G&W[&RLODGES&G&W]%s itself in your leg.", char_color_str(AT_ACTION, ch));
            act(AT_ACTION, buf, ch, obj, NULL, TO_CHAR);
         }
         equip_char(ch, obj, WEAR_LODGE_LEG);
         oprog_wear_trigger(ch, obj);
         return;

         //Only layerable slot for now because of sheaths    
      case ITEM_WEAR_WAIST:
/*
	    if ( !remove_obj( ch, WEAR_WAIST, fReplace ) )
	      return;
*/
         if (!can_layer(ch, obj, WEAR_WAIST))
         {
            send_to_char("It won't fit overtop of what you're already wearing.\n\r", ch);
            return;
         }
         if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
         {
            act(AT_ACTION, "$n buckles $p about $s waist.", ch, obj, NULL, TO_ROOM);
            act(AT_ACTION, "You buckle $p about your waist.", ch, obj, NULL, TO_CHAR);
         }
         equip_char(ch, obj, WEAR_WAIST);
         oprog_wear_trigger(ch, obj);
         return;

      case ITEM_WEAR_SHIELD:
         if (get_eq_char(ch, WEAR_DUAL_WIELD) || (get_eq_char(ch, WEAR_WIELD) && get_eq_char(ch, WEAR_MISSILE_WIELD)))
         {
            send_to_char("You can't use a shield AND two weapons!\n\r", ch);
            return;
         }
         if (get_eq_char(ch, WEAR_WIELD) && (ch->con_rarm == -1 || ch->con_larm == -1))
         {
            send_to_char("You don't have an available hand seeing how it is broken off.\n\r", ch);
            return;
         }
         if ((tmpobj = (get_eq_char(ch, WEAR_MISSILE_WIELD))) != NULL)
         {
            if (IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
            {
               if (IS_NPC(ch) || ch->pcdata->learned[gsn_inhuman_strength] <= 0)
               {
                  send_to_char("The weapon you are wielding now is two-handed.\n\r", ch);
                  return;
               }
            }
         }
         if ((tmpobj = (get_eq_char(ch, WEAR_WIELD))) != NULL)
         {
            if (IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
            {
               if (IS_NPC(ch) || ch->pcdata->learned[gsn_inhuman_strength] <= 0)
               {
                  send_to_char("The weapon you are wielding now is two-handed.\n\r", ch);
                  return;
               }
            }
         }
         if (IS_OBJ_STAT(obj, ITEM_TWOHANDED))
         {
            if (get_eq_char(ch, WEAR_WIELD) || get_eq_char(ch, WEAR_DUAL_WIELD) || get_eq_char(ch, WEAR_MISSILE_WIELD))
            {
               send_to_char("That shield is two-handed.  You cannot wield a weapon with it.\n\r", ch);
               return;
            }
         }
         if (ch->con_rarm == -1 && ch->con_larm == -1)
         {
            send_to_char("You have no available hands to hold a shield because you have no hands.\n\r", ch);
            return;
         }
         if (!remove_obj(ch, WEAR_SHIELD, fReplace))
            return;
         if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
         {
            act(AT_ACTION, "$n uses $p as a shield.", ch, obj, NULL, TO_ROOM);
            act(AT_ACTION, "You use $p as a shield.", ch, obj, NULL, TO_CHAR);
         }
         equip_char(ch, obj, WEAR_SHIELD);
         oprog_wear_trigger(ch, obj);
         return;

      case ITEM_MISSILE_WIELD:
      case ITEM_WIELD:
         if (!could_dual(ch))
         {
            if (!remove_obj(ch, WEAR_MISSILE_WIELD, fReplace))
               return;
            if (!remove_obj(ch, WEAR_WIELD, fReplace))
               return;
            if ((tmpobj = get_eq_char(ch, WEAR_SHIELD)) != NULL && IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
            {
               send_to_char("The Shield you are holding requires two hands.\n\r", ch);
               return;
            }
            if (IS_OBJ_STAT(obj, ITEM_TWOHANDED) && tmpobj)
            {
               if (IS_NPC(ch) || ch->pcdata->learned[gsn_inhuman_strength] <= 0)
               {
                  send_to_char("If you want to use that two-handed weapon, remove your shield first.\n\r", ch);
                  return;
               }
            }
            tmpobj = NULL;
            if ((tmpobj = get_eq_char(ch, WEAR_SHIELD)) != NULL && IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
            {
               send_to_char("The Shield you are holding requires two hands.\n\r", ch);
               return;
            }
            if (get_eq_char(ch, WEAR_SHIELD) && (ch->con_rarm == -1 || ch->con_larm == -1))
            {
               send_to_char("Hard to wield something when one hand is chopped off.\n\r", ch);
               return;
            }
            if (ch->con_rarm == -1 && ch->con_larm == -1)
            {
               send_to_char("Hard to wield something when you have NO hands to wield it with.\n\r", ch);
               return;
            }
            tmpobj = NULL;
         }
         else
         {
            if ((tmpobj = get_eq_char(ch, WEAR_SHIELD)) != NULL && IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
            {
               send_to_char("The Shield you are holding requires two hands.\n\r", ch);
               return;
            }
            if (IS_OBJ_STAT(obj, ITEM_TWOHANDED) && tmpobj)
            {
               if (IS_NPC(ch) || ch->pcdata->learned[gsn_inhuman_strength] <= 0)
               {
                  send_to_char("If you want to use that two-handed weapon, remove your shield first.\n\r", ch);
                  return;
               }
            }
            tmpobj = NULL;
            if ((tmpobj = get_eq_char(ch, WEAR_WIELD)) != NULL && (get_eq_char(ch, WEAR_MISSILE_WIELD) || get_eq_char(ch, WEAR_DUAL_WIELD)))
            {
               send_to_char("You're already wielding two weapons.\n\r", ch);
               return;
            }
            if (IS_OBJ_STAT(obj, ITEM_TWOHANDED) && get_eq_char(ch, WEAR_MISSILE_WIELD))
            {
               send_to_char("That weapon is two-handed and you are weilding a missile weapon.\n\r", ch);
               return;
            }
            if (get_eq_char(ch, WEAR_MISSILE_WIELD))
            {
               if ((tmpobj = get_eq_char(ch, WEAR_MISSILE_WIELD)) != NULL && IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
               {
                  send_to_char("You are wielding a two-handed missile weapon!\n\r", ch);
                  return;
               }
            }
            if (get_eq_char(ch, WEAR_WIELD))
            {
               if ((tmpobj = get_eq_char(ch, WEAR_WIELD)) != NULL && get_eq_char(ch, WEAR_SHIELD))
               {
                  send_to_char("You must first remove that shield you are holding.\n\r", ch);
                  return;
               }
            }
            if (get_eq_char(ch, WEAR_WIELD) && (ch->con_rarm == -1 || ch->con_larm == -1))
            {
               send_to_char("You do not have availability of one hand because it is chopped off.\n\r", ch);
               return;
            }
            if (!tmpobj && ch->con_rarm == -1 && ch->con_larm == -1)
            {
               send_to_char("Hard to wield something when you have no hands.\n\r", ch);
               return;
            }
         }

         if (tmpobj)
         {
            if (can_dual(ch))
            {
               if (get_obj_weight(obj) + get_obj_weight(tmpobj) > str_app[get_curr_str(ch)].wield)
               {
                  send_to_char("&RWielding such heavy weapons is going to slow you down!!&w.\n\r", ch);
               }
               /* New Weapon Handling code -- Xerves 6/1/99 */
               if (!IS_NPC(ch))
               {
                  if (obj->value[3] < race_table[ch->race]->weaponmin)
                  {
                     act(AT_ACTION, "You try to wield $p, but you cannot grasp it with your hands.", ch, obj, NULL, TO_CHAR);
                     return;
                  }
                  if (obj->value[3] > race_table[ch->race]->weaponmax)
                  {
                     act(AT_ACTION, "You try to wield $p, but you cannot even lift it off the ground.", ch, obj, NULL, TO_CHAR);
                     return;
                  }
               }
               if (IS_OBJ_STAT(obj, ITEM_TWOHANDED))
               {
                  send_to_char("That weapon requires two hands to wield.\n\r", ch);
                  return;
               }
               if (IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
               {
                  send_to_char("The weapon you are wielding now is two-handed.\n\r", ch);
                  return;
               }
                   
               if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
               {
                  act(AT_ACTION, "$n dual-wields $p.", ch, obj, NULL, TO_ROOM);
                  act(AT_ACTION, "You dual-wield $p.", ch, obj, NULL, TO_CHAR);
               }
               if (1 << bit == ITEM_MISSILE_WIELD)
                  equip_char(ch, obj, WEAR_MISSILE_WIELD);
               else
                  equip_char(ch, obj, WEAR_DUAL_WIELD);
               oprog_wear_trigger(ch, obj);
            }
            return;
         }
         if (get_obj_weight(obj) > str_app[get_curr_str(ch)].wield)
         {
            send_to_char("&RWielding such a heavy weapon is going to slow you down!!&w.\n\r", ch);
         }
         /* New weapon handling code -- Xerves 6/1/90 */
         if (!IS_NPC(ch))
         {
            if (obj->value[3] < race_table[ch->race]->weaponmin)
            {
               act(AT_ACTION, "You try to wield $p, but you cannot grasp it with your hands.", ch, obj, NULL, TO_CHAR);
               return;
            }
            if (obj->value[3] > race_table[ch->race]->weaponmax)
            {
               act(AT_ACTION, "You try to wield $p, but you cannot even lift it off the ground.", ch, obj, NULL, TO_CHAR);
               return;
            }
         }
         if (!IS_NPC(ch))
         {
            if ((ch->pcdata->righthanded == 0 && ch->con_larm == -1) || (ch->pcdata->righthanded == 1 && ch->con_rarm == -1))
            {
               if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
               {
                   act(AT_ACTION, "$n wields $p with $s off-hand.", ch, obj, NULL, TO_ROOM);
                   act(AT_ACTION, "You wield $p with your off-hand.", ch, obj, NULL, TO_CHAR);
               }
            }
            else
            {
               if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
               {
                  act(AT_ACTION, "$n wields $p.", ch, obj, NULL, TO_ROOM);
                  act(AT_ACTION, "You wield $p.", ch, obj, NULL, TO_CHAR);
               }   
            }
         }
         else
         {
            if (ch->con_rarm == -1)
            {
               if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
               {
                   act(AT_ACTION, "$n wields $p with $s off-hand.", ch, obj, NULL, TO_ROOM);
                   act(AT_ACTION, "You wield $p with your off-hand.", ch, obj, NULL, TO_CHAR);
               }
            }
            else
            {
               if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL))
               {
                  act(AT_ACTION, "$n wields $p.", ch, obj, NULL, TO_ROOM);
                  act(AT_ACTION, "You wield $p.", ch, obj, NULL, TO_CHAR);
               }   
            }   
         }
         if (1 << bit == ITEM_MISSILE_WIELD)
            equip_char(ch, obj, WEAR_MISSILE_WIELD);
         else
            equip_char(ch, obj, WEAR_WIELD);
         oprog_wear_trigger(ch, obj);
         if (ch->fighting)
         {
            SET_BIT(ch->fight_state, FSTATE_WIELD);
            if (ch->fight_timer <= 2)
               ch->fight_timer = 2;
         }
         return;
   }
}

// Used to unequip a weapon and put it back in a sheath.
// You sheath going from DUAL to Primary
void do_sheath(CHAR_DATA * ch, char *argument)
{
   OBJ_DATA *sheath;
   OBJ_DATA *weapon = NULL;
   char buf[MSL];
   int found = 0;
   int rev = 0;
   int count = 0;

   if (!str_cmp(argument, "go reverse"))
      rev = 1;

   if (!str_cmp(argument, "go reverse again"))
      rev = 2;

   if (ms_find_obj(ch))
      return;

   if (get_eq_char(ch, WEAR_DUAL_WIELD))
   {
      weapon = get_eq_char(ch, WEAR_DUAL_WIELD);
   }
   else
   {
      if (get_eq_char(ch, WEAR_WIELD))
      {
         weapon = get_eq_char(ch, WEAR_WIELD);
      }
   }
   if (!weapon)
   {
      send_to_char("You need to be wielding a weapon to sheath it.\n\r", ch);
      return;
   }
   if (IS_OBJ_STAT(weapon, ITEM_NOREMOVE))
   {
      act(AT_PLAIN, "You can't remove $p.", ch, weapon, NULL, TO_CHAR);
      return;
   }
   /* Total of 3 possible sheath locations, will loop through three times to find
      a good one if it has to */
   for (sheath = ch->first_carrying; sheath; sheath = sheath->next_content)
   {
      if (sheath->item_type == ITEM_SHEATH && sheath->wear_loc == WEAR_WAIST)
      {
         found = 1;
         if (rev != count)
         {
            count++;
            continue;
         }
         if (sheath->value[1] == weapon->value[3] && get_obj_weight(weapon) <= sheath->value[0] && !sheath->first_content)
         {
            if (sheath->value[2] != 0 && sheath->value[2] == weapon->pIndexData->vnum)
               break;
            else
            {
               if (sheath->value[2] == 0)
                  break;
               else
                  continue;
            }

            break;
         }
      }
   }
   if (found == 0)
   {
      send_to_char("You need to be wearing a sheath before you can sheath a weapon.\n\r", ch);
      return;
   }
   if (!sheath)
   {
      send_to_char("You have an improper sheath or it is full, help sheath for more info.\n\r", ch);
      return;
   }
   if (IS_OBJ_STAT(weapon, ITEM_NOGIVE) && !IS_OBJ_STAT(sheath, ITEM_NOGIVE))
   {
      if (rev == 0)
      {
         do_sheath(ch, "go reverse");
         return;
      }
      else if (rev == 1)
      {
         do_sheath(ch, "go reverse again");
         return;
      }
      else
      {
         send_to_char("Your container needs to be nogive if your weapon is nogive.\n\r", ch);
         return;
      }
   }
   if (IS_OBJ_STAT(sheath, ITEM_NOGIVE) && !IS_OBJ_STAT(weapon, ITEM_NOGIVE))
   {
      if (rev == 0)
      {
         do_sheath(ch, "go reverse");
         return;
      }
      else if (rev == 1)
      {
         do_sheath(ch, "go reverse again");
         return;
      }
      else
      {
         send_to_char("Your weapon needs to be nogive if your container is nogive.\n\r", ch);
         return;
      }
   }
   if ((weapon->pIndexData->vnum != sheath->value[2]) && sheath->value[2] != 0)
   {
      if (rev == 0)
      {
         do_sheath(ch, "go reverse");
         return;
      }
      else if (rev == 1)
      {
         do_sheath(ch, "go reverse again");
         return;
      }
      else
      {
         send_to_char("Your sheath was made for a certain weapon and this one is not it.\n\r", ch);
         return;
      }
   }
   if (HAS_WAIT(ch))
   {
      send_to_char("You are too busy in battle to do that.\n\r", ch);
      return;
   }
   sprintf(buf, "'%s'", weapon->name);
   do_remove(ch, buf);
   sprintf(buf, "'%s' '%s'", weapon->name, sheath->name);
   do_put(ch, buf);

   if (!sheath->first_content)
   {
      sprintf(buf, "'%s'", weapon->name);
      do_wear(ch, buf);
   }
   return;
}

// Used to draw a weapon from a sheath for combat.
void do_draw(CHAR_DATA * ch, char *argument)
{
   OBJ_DATA *sheath;
   OBJ_DATA *weapon = NULL;
   OBJ_DATA *tmpobj;
   char buf[MSL];
   char arg[MIL];
   int found = 0;
   int sn;
   int limb;

   if (ms_find_obj(ch))
      return;

   for (sheath = ch->first_carrying; sheath; sheath = sheath->next_content)
   {
      if (sheath->item_type == ITEM_SHEATH && sheath->wear_loc == WEAR_WAIST)
      {
         found = 1;
         if (sheath->first_content)
         {
            weapon = sheath->first_content;
            break;
         }
      }
   }
   if (found == 0)
   {
      send_to_char("You need to be wearing a sheath on your waist in order to draw.\n\r", ch);
      return;
   }
   if (!weapon)
   {
      send_to_char("You don't have anything in your sheath to wield you fool.\n\r", ch);
      return;
   }
   /* Quick checks to see if it is wieldable before removing, will safe some text spam on the
      player plus problems */
   
   if (!could_dual(ch))
   {
      if (!remove_obj(ch, WEAR_MISSILE_WIELD, 2))
         return;
      if (!remove_obj(ch, WEAR_WIELD, 2))
         return;
      if ((tmpobj = get_eq_char(ch, WEAR_SHIELD)) != NULL && IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
      {
         if (IS_NPC(ch) || ch->pcdata->learned[gsn_inhuman_strength] <= 0)
            return;
      }
      if (get_eq_char(ch, WEAR_SHIELD) && (ch->con_rarm == -1 || ch->con_larm == -1))
      {
         return;
      }
      if (ch->con_rarm == -1 && ch->con_larm == -1)
      {
         return;
      }
      tmpobj = NULL;   
       
      if (get_obj_weight(weapon) > str_app[get_curr_str(ch)].wield)
      {
         send_to_char("&RWielding such a heavy weapon is going to slow you down!!&w.\n\r", ch);
      }
   }   
   else
   {
      if ((tmpobj = get_eq_char(ch, WEAR_SHIELD)) != NULL && IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
      {
         return;
      }
      if (IS_OBJ_STAT(weapon, ITEM_TWOHANDED) && tmpobj)
      {
         if (IS_NPC(ch) || ch->pcdata->learned[gsn_inhuman_strength] <= 0)
            return;
      }
      tmpobj = NULL;
      if ((tmpobj = get_eq_char(ch, WEAR_WIELD)) != NULL && (get_eq_char(ch, WEAR_MISSILE_WIELD) || get_eq_char(ch, WEAR_DUAL_WIELD)))
         return;

      if (IS_OBJ_STAT(weapon, ITEM_TWOHANDED) && get_eq_char(ch, WEAR_MISSILE_WIELD))
      {
         return;
      }
      if (get_eq_char(ch, WEAR_MISSILE_WIELD))
      {
         if ((tmpobj = get_eq_char(ch, WEAR_MISSILE_WIELD)) != NULL && IS_OBJ_STAT(tmpobj, ITEM_TWOHANDED))
         {
            return;
         }
      }
      if (get_eq_char(ch, WEAR_WIELD))
      {
         if ((tmpobj = get_eq_char(ch, WEAR_WIELD)) != NULL && get_eq_char(ch, WEAR_SHIELD))
         {
            return;
         }
      }
      if (get_eq_char(ch, WEAR_WIELD) && (ch->con_rarm == -1 || ch->con_larm == -1))
      {
         return;
      }
      if (!tmpobj && ch->con_rarm == -1 && ch->con_larm == -1)
      {
         return;
      }
      if (tmpobj)
      {
         if (get_obj_weight(weapon) + get_obj_weight(tmpobj) > str_app[get_curr_str(ch)].wield)
         {
            send_to_char("&RWielding such heavy weapons is going to slow you down!!&w.\n\r", ch);
         }
      } 
      else
      {
         if (get_obj_weight(weapon) > str_app[get_curr_str(ch)].wield)
         {
            send_to_char("&RWielding such a heavy weapon is going to slow you down!!&w.\n\r", ch);
         }
      }
   }
   /* New Weapon Handling code -- Xerves 6/1/99 */
   if (!IS_NPC(ch))
   {
      if (weapon->value[3] < race_table[ch->race]->weaponmin)
      {
         act(AT_ACTION, "You try to wield $p, but you cannot grasp it with your hands.", ch, weapon, NULL, TO_CHAR);
         return;
      }
      if (weapon->value[3] > race_table[ch->race]->weaponmax)
      {
         act(AT_ACTION, "You try to wield $p, but you cannot even lift it off the ground.", ch, weapon, NULL, TO_CHAR);
         return;
      }
   }
   if ((IS_OBJ_STAT(weapon, ITEM_NOGIVE) && !IS_OBJ_STAT(sheath, ITEM_NOGIVE))
      || (IS_OBJ_STAT(sheath, ITEM_NOGIVE) && !IS_OBJ_STAT(weapon, ITEM_NOGIVE)))
   {
      send_to_char("Either the weapon or sheath has a nogive flag, bug reported\n\r", ch);
      bug("%s has a nogive flag weapon or container, trying to draw", ch->name);
      return;
   }
   if (HAS_WAIT(ch))
   {
      send_to_char("You are too busy in battle to do that.\n\r", ch);
      return;
   }
   sprintf(buf, "'%s' '%s'", weapon->name, sheath->name);
   do_get(ch, buf);
   sprintf(buf, "'%s'", weapon->name);
   do_wear(ch, buf);
   if (weapon->wear_loc != WEAR_WIELD && weapon->wear_loc != WEAR_MISSILE_WIELD && weapon->wear_loc != WEAR_DUAL_WIELD)
   {
      sprintf(buf, "'%s' '%s'", weapon->name, sheath->name);
      do_put(ch, buf);
   }
   if (argument[0] != '\0')
   {
      CHAR_DATA *victim;

      argument = one_argument(argument, arg);

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

      if (IS_NPC(victim) && victim->morph)
      {
         send_to_char("This creature appears strange to you.  Look upon it more closely before attempting to kill it.", ch);
         return;
      }

      if (victim == ch)
      {
         send_to_char("You hit yourself.  Ouch!\n\r", ch);
         return;
      }

      if (is_safe(ch, victim))
         return;

      if (IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim)
      {
         act(AT_PLAIN, "$N is your beloved master.", ch, NULL, victim, TO_CHAR);
         return;
      }

      if (ch->position == POS_FIGHTING
         || ch->position == POS_EVASIVE || ch->position == POS_DEFENSIVE || ch->position == POS_AGGRESSIVE || ch->position == POS_BERSERK)
      {
         send_to_char("You do the best you can!\n\r", ch);
         return;
      }
      if (argument[0] == '\0')
      {
         send_to_char("Need to choose a limb: rarm, larm, rleg, lleg, body, head, neck.\n\r", ch);
         return;
      }
      if (!str_cmp(argument, "rarm"))
         limb = LM_RARM;
      else if (!str_cmp(argument, "larm"))
         limb = LM_LARM;
      else if (!str_cmp(argument, "rleg"))
         limb = LM_RLEG;
      else if (!str_cmp(argument, "lleg"))
         limb = LM_LLEG;
      else if (!str_cmp(argument, "body"))
         limb = LM_BODY;
      else if (!str_cmp(argument, "head"))
         limb = LM_HEAD;
      else if (!str_cmp(argument, "neck"))
         limb = LM_NECK;
      else
      {
         send_to_char("Need to choose a limb: rarm, larm, rleg, lleg, body, head, neck.\n\r", ch);
         return;
      }  
      check_attacker(ch, victim);
      one_hit(ch, victim, gsn_unsheath, limb);
      sn = sheath->value[4];
      if (sn > 0)
      {
         if (IS_VALID_SN(sn) && skill_table[sn]->spell_fun)
         {
            if (sheath->value[5] > 0)
            {
               if (number_range(1, 100) > sheath->value[5])
                  return;
            }
            else
            {
               if (number_range(1, 100) > 25)
                  return;
            }
            (*skill_table[sn]->spell_fun) (sn, 1, ch, victim);
            if (char_died(ch) || char_died(victim))
               return;
         }
      }
      return;
   }
   if (ch->fighting && ch->fighting->who != ch)
   {
      check_attacker(ch, ch->fighting->who);
      if (argument[0] == '\0')
      {
         send_to_char("Need to choose a limb: rarm, larm, rleg, lleg, body, head, neck\n\r", ch);
         return;
      }
      if (!str_cmp(argument, "rarm"))
         limb = LM_RARM;
      else if (!str_cmp(argument, "larm"))
         limb = LM_LARM;
      else if (!str_cmp(argument, "rleg"))
         limb = LM_RLEG;
      else if (!str_cmp(argument, "lleg"))
         limb = LM_LLEG;
      else if (!str_cmp(argument, "body"))
         limb = LM_BODY;
      else if (!str_cmp(argument, "head"))
         limb = LM_HEAD;
      else if (!str_cmp(argument, "neck"))
         limb = LM_NECK;
      else
      {
         send_to_char("Need to choose a limb: rarm, larm, rleg, lleg, body, head, neck", ch);
         return;
      }  
      one_hit(ch, ch->fighting->who, gsn_unsheath, limb);
   }
   sn = sheath->value[4];
   if (sn > 0)
   {
      if (IS_VALID_SN(sn) && skill_table[sn]->spell_fun && ch->fighting && ch->fighting->who != ch)
      {
         if (sheath->value[5] > 0)
         {
            if (number_range(1, 100) > sheath->value[5])
               return;
         }
         else
         {
            if (number_range(1, 100) > 25)
               return;
         }
         (*skill_table[sn]->spell_fun) (sn, 1, ch, ch->fighting->who);
         if (char_died(ch) || char_died(ch->fighting->who))
            return;
      }
   }
   return;
}
void do_wear(CHAR_DATA * ch, char *argument)
{
   char arg1[MIL];
   char arg2[MIL];
   OBJ_DATA *obj;
   sh_int wear_bit;

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

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

   if (ms_find_obj(ch))
      return;

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

      for (obj = ch->first_carrying; obj; obj = obj_next)
      {
         obj_next = obj->next_content;
         if (IS_SET(obj->wear_flags, ITEM_LODGE_RIB) || IS_SET(obj->wear_flags, ITEM_LODGE_ARM) || IS_SET(obj->wear_flags, ITEM_LODGE_LEG))
            continue;

         if (obj->wear_loc == WEAR_NONE && can_see_obj(ch, obj))
         {
            wear_obj(ch, obj, FALSE, -1);
            if (char_died(ch))
               return;
         }
      }
      return;
   }
   else
   {
      if ((obj = get_obj_carry(ch, arg1)) == NULL)
      {
         send_to_char("You do not have that item.\n\r", ch);
         return;
      }
      if (IS_SET(obj->wear_flags, ITEM_LODGE_RIB) || IS_SET(obj->wear_flags, ITEM_LODGE_ARM) || IS_SET(obj->wear_flags, ITEM_LODGE_LEG))
      {
         send_to_char("I do not think you want to wear that.\n\r", ch);
         return;
      }
      if (arg2[0] != '\0')
         wear_bit = get_wflag(arg2);
      else
         wear_bit = -1;
      wear_obj(ch, obj, TRUE, wear_bit);
   }

   return;
}



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


   one_argument(argument, arg);

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

   if (ms_find_obj(ch))
      return;

   if (!str_cmp(arg, "all")) /* SB Remove all */
   {
      act(AT_PLAIN, "$n starts to remove it all.", ch, NULL, NULL, TO_ROOM);
      for (obj = ch->first_carrying; obj != NULL; obj = obj_next)
      {
         obj_next = obj->next_content;
         if (IS_SET(obj->wear_flags, ITEM_LODGE_RIB) || IS_SET(obj->wear_flags, ITEM_LODGE_ARM) || IS_SET(obj->wear_flags, ITEM_LODGE_LEG))
            continue;

         if (obj->wear_loc != WEAR_NONE && can_see_obj(ch, obj))
            remove_obj(ch, obj->wear_loc, TRUE);
      }
      return;
   }

   if ((obj = get_obj_wear(ch, arg)) == NULL)
   {
      send_to_char("You are not using that item.\n\r", ch);
      return;
   }
   if ((obj_next = get_eq_char(ch, obj->wear_loc)) != obj)
   {
      act(AT_PLAIN, "You must remove $p first.", ch, obj_next, NULL, TO_CHAR);
      return;
   }
   if (IS_SET(obj->wear_flags, ITEM_LODGE_RIB) || IS_SET(obj->wear_flags, ITEM_LODGE_ARM) || IS_SET(obj->wear_flags, ITEM_LODGE_LEG))
   {
      send_to_char("You cannot remove those kind items, use dislodge.\n\r", ch);
      return;
   }

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


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

   one_argument(argument, arg);

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

   if (ms_find_obj(ch))
      return;

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

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

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

   switch (ch->in_room->sector_type)
   {
      case SECT_CITY:
      case SECT_INSIDE:
         send_to_char("The floor is too hard to dig through.\n\r", ch);
         return;
      case SECT_WATER_SWIM:
      case SECT_WATER_NOSWIM:
      case SECT_UNDERWATER:
         send_to_char("You cannot bury something here.\n\r", ch);
         return;
      case SECT_AIR:
         send_to_char("What?  In the air?!\n\r", ch);
         return;
   }

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

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

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

void do_sacrifice(CHAR_DATA * ch, char *argument)
{
   char arg[MIL];
   char buf[MSL];
   char name[50];
   OBJ_DATA *obj;
   OBJ_DATA *obj_prev;
   int x;

   one_argument(argument, arg);
   
   if (argument[0] == '\0')
   {
      send_to_char("Syntax:  sacrifice <name of object>\n\r", ch);
      send_to_char("Syntax:  sacrifice all\n\r", ch);
      return;
   }

   if (!str_cmp(arg, "all"))
   {
      sacall = 1;
      for (x = 1; x <= 15; x++) //Due to separate obj this needs to be run a few times to clean up the mess
      {
         for (obj = ch->in_room->last_content; obj; obj = obj_prev)
         {
            obj_prev = obj->prev_content;
            if (IN_SAME_ROOM_OBJ(ch, obj))
            {
               sprintf(buf, "%s", obj->name);
               do_sacrifice(ch, buf);
            }
         }
      }
      sacall = 0;
      return;
   }

   if (!str_cmp(arg, ch->name))
   {
      act(AT_ACTION, "$n offers $mself to $s deity, who graciously declines.", ch, NULL, NULL, TO_ROOM);
      send_to_char("Your deity appreciates your offer and may accept it later.\n\r", ch);
      return;
   }

   if (ms_find_obj(ch))
      return;

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

   separate_obj(obj);
   if (!CAN_WEAR(obj, ITEM_TAKE))
   {
      if (sacall == 0)
         act(AT_PLAIN, "$p is not an acceptable sacrifice.", ch, obj, 0, TO_CHAR);
      return;
   }
   if (!IS_NPC(ch) && ch->pcdata->deity && ch->pcdata->deity->name[0] != '\0')
   {
      strcpy(name, ch->pcdata->deity->name);
   }
   else if (!IS_NPC(ch) && IS_GUILDED(ch) && sysdata.guild_overseer[0] != '\0')
   {
      strcpy(name, sysdata.guild_overseer);
   }
   else if (!IS_NPC(ch) && ch->pcdata->clan && ch->pcdata->clan->deity[0] != '\0')
   {
      strcpy(name, ch->pcdata->clan->deity);
   }
   else
   {
      strcpy(name, "Xerves");
   }
   ch->gold += 1;
   if (obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC)
      adjust_favor(ch, 5, 1);
   sprintf(buf, "%s gives you one gold coin for your sacrifice.\n\r", name);
   send_to_char(buf, ch);
   sprintf(buf, "$n sacrifices $p to %s.", name);
   act(AT_ACTION, buf, ch, obj, NULL, TO_ROOM);
   oprog_sac_trigger(ch, obj);
   if (obj_extracted(obj))
      return;
   if (cur_obj == obj->serial)
      global_objcode = rOBJ_SACCED;
   check_for_trap(ch, obj, -1, NEW_TRAP_SACOBJ);
   if (global_retcode == rOBJ_SCRAPPED)
      return;   
   if (obj)
      extract_obj(obj);
   return;
}

//Used on runes, for now, just for moving to a portal
void do_rub(CHAR_DATA * ch, char *argument)
{
   OBJ_DATA *rune;
   char arg1[MIL];
   int p, x, y, map;
   int count = 0;
   int found = 0;
   int targetRoomVnum;
   ROOM_INDEX_DATA *targetRoom;

   p = 0;

   if (IS_NPC(ch))
   {
      send_to_char("This command is for PCs only, sorry.\n\r", ch);
      return;
   }
   if (argument[0] == '\0')
   {
      send_to_char("rub <rune> <portal>\n\r", ch);
      return;
   }
   argument = one_argument(argument, arg1);

   if ((rune = get_obj_carry(ch, arg1)) == NULL)
   {
      send_to_char("You do not have that item in your inventory.\n\r", ch);
      return;
   }
   if (rune->item_type != ITEM_RUNE)
   {
      send_to_char("You can only rub runes.\n\r", ch);
      return;
   }
   if (rune->value[0] != 1)
   {
      send_to_char("You try to rub the rune, but it appears to not be enchanted.\n\r", ch);
      return;
   }
   if (can_use_portal(ch, 3) == FALSE)
      return;

   WAIT_STATE(ch, 3 * PULSE_VIOLENCE);

   if (isdigit(argument[0]))
   {
      for (p = 0; p < sysdata.last_portal; p++)
      {
         if (xIS_SET(ch->pcdata->portalfnd, p))
         {
            count++;
         }
         if (count == atoi(argument))
         {
            found = 1;
            break;
         }
      }
   }
   if (!str_cmp(argument, "home"))
   {
      if (ch->in_room->vnum == ROOM_VNUM_PORTAL)
      {
         send_to_char("You cannot use the rune to portal to a portal you are at.\n\r", ch);
         return;
      }
      else
         count = 10000; //Should be enough, god forbid 10000 portal spots -- Xerves
   }
   if (found == 0 && count < 10000)
   {
      send_to_char("Your rune will only work with portals on your list, or 'home' or 'newbie'.\n\r", ch);
      return;
   }
   if (count == 0)
   {
      send_to_char("You have no portals to goto.\n\r", ch);
      return;
   }
   if (count == 10000)
      targetRoomVnum = ROOM_VNUM_PORTAL;
   else
      targetRoomVnum = OVERLAND_SOLAN;

   if (count != 10000 && count != 10001)
   {
      x = portal_show[p]->x;
      y = portal_show[p]->y;
      map = portal_show[p]->map;
      if (ch->coord->x == x && ch->coord->y == y && ch->map == map)
      {
         send_to_char("You cannot use the rune to portal to a portal you are at.\n\r", ch);
         return;
      }
   }
   else
   {
      x = -1;
      y = -1;
      map = -1;
      if (ch->in_room->vnum == targetRoomVnum)
      {
         send_to_char("You cannot use the rune to portal to a portal you are at.\n\r", ch);
         return;
      }
   }
   targetRoom = get_room_index(targetRoomVnum);
   if (x > -1 || y > -1 || map > -1)
   {
      SET_ONMAP_FLAG(ch);
      ch->coord->x = x;
      ch->coord->y = y;
      ch->map = map;
      char_from_room(ch);
      char_to_room(ch, targetRoom);
      update_objects(ch, x, y, ch->map);
      if (ch->rider)
      {
         SET_ONMAP_FLAG(ch->rider);
         ch->rider->coord->x = x;
         ch->rider->coord->y = y;
         ch->rider->map = map;
         char_from_room(ch->rider);
         char_to_room(ch->rider, targetRoom); 
         update_objects(ch->rider, x, y, ch->map);  
      }
   }
   else
   {
      REMOVE_ONMAP_FLAG(ch);
      ch->coord->x = -1;
      ch->coord->y = -1;
      ch->map = -1;
      char_from_room(ch);
      char_to_room(ch, targetRoom);
      update_objects(ch, x, y, ch->map);
      if (ch->rider)
      {
         REMOVE_ONMAP_FLAG(ch->rider);
         ch->rider->coord->x = -1;
         ch->rider->coord->y = -1;
         ch->rider->map = -1;
         char_from_room(ch->rider);
         char_to_room(ch->rider, targetRoom);
         update_objects(ch->rider, x, y, ch->map);
      }
   }
   if (ch->on)
   {
      ch->on = NULL;
      ch->position = POS_STANDING;
   }
   if (ch->position != POS_STANDING)
   {
      ch->position = POS_STANDING;
   }
   act(AT_MAGIC, "$n appears in a flash of light!", ch, NULL, NULL, TO_ROOM);
   do_look(ch, "auto");

   if (--rune->value[1] <= 0)
   {
      act(AT_MAGIC, "$p lights up and suddenly and vanishes from $n", ch, rune, NULL, TO_ROOM);
      act(AT_MAGIC, "$p lights up and suddenly and vanishes from your inventory.", ch, rune, NULL, TO_CHAR);
      if (rune->serial == cur_obj)
         global_objcode = rOBJ_USED;
      separate_obj(rune);
      extract_obj(rune);
   }
   return;
}


void do_brandish(CHAR_DATA * ch, char *argument)
{
   CHAR_DATA *victim = NULL;
   OBJ_DATA *staff;
   int value = 0;
   ch_ret retcode;
   static char extra[MSL];
   int passarg = 0;
   int sn;

   if ((staff = get_eq_char(ch, WEAR_WIELD)) == NULL)
   {
      send_to_char("You not wielding anything to brandish.\n\r", ch);
      return;
   }

   if ((sn = staff->value[4]) < 0 || sn >= top_sn || skill_table[sn]->spell_fun == NULL)
   {
      bug("Do_brandish: bad sn %d.", sn);
      return;
   }

   if (HAS_WAIT(ch))
   {
      send_to_char("You are too busy in battle to do that.\n\r", ch);
      return;
   }
   if (ch->fighting)
      ch->fight_timer = staff->value[5] - SPOWER_MIN + 2;
   else
      WAIT_STATE(ch, staff->value[5] - SPOWER_MIN + 2);

   if (staff->value[5] > 0)
   {
      if (!oprog_use_trigger(ch, staff, NULL, NULL, NULL))
      {
         act(AT_MAGIC, "$n brandishes $p.", ch, staff, NULL, TO_ROOM);
         act(AT_MAGIC, "You brandish $p.", ch, staff, NULL, TO_CHAR);
      }
      if (skill_table[sn]->target == TAR_CHAR_OFFENSIVE && ch->fighting)
         victim = ch->fighting->who;
      if (skill_table[sn]->target == TAR_CHAR_DEFENSIVE)
         victim = ch;
      if (staff->value[4] != skill_lookup("word of recall"))
      {
         if (argument[0] != '\0')
         {
            if ((victim=get_char_room(ch, argument)) == NULL)
            {
               send_to_char("Your target is not in this room.\n\r", ch);
               return;
            }
         }
      }
      else
      {
         victim = ch;
         sprintf(extra, argument);
         target_name = extra;
         passarg = 1;
      }
      if (skill_table[sn]->target == TAR_CHAR_SELF)
         victim = ch;
      if (skill_table[sn]->target != TAR_IGNORE)
      {
         if (!victim)
         {
            send_to_char("You need a target to brandish your weapon on.\n\r", ch);
            return;
         }
      }
      if (victim && !IS_NPC(victim) && xIS_SET(victim->act, PLR_WIZINVIS) && victim->pcdata->wizinvis >= LEVEL_IMMORTAL)
      {
         send_to_char("Your target is not in this room.\n\r", ch);
         return;
      }
      switch (skill_table[sn]->target)
      {
         case TAR_CHAR_SELF:
            if (victim != ch)
            {
               send_to_char("Can only target yourself with this weapon.\n\r", ch);
               return;
            }
      }
      if (staff->value[5] < SPOWER_MIN || staff->value[5] > SPOWER_GREATEST)
      {
         staff->value[5] = SPOWER_MIN;
         bug("Spower on object %s on %s is bad.", staff->name, ch->name);
      }
      if (!passarg)
         retcode = obj_cast_spell(staff->value[4], staff->value[5], ch, victim, staff);
      else
         retcode = obj_cast_spell(staff->value[4]+10000, staff->value[5], ch, victim, staff);
      if (retcode == rCHAR_DIED || retcode == rBOTH_DIED)
      {
         bug("do_brandish: char died", 0);
         return;
      }

      if (staff->value[5] == SPOWER_MIN)
         value = 15;
      if (staff->value[5] == SPOWER_LOW)
         value = 25;
      if (staff->value[5] == SPOWER_MED)
         value = 40;
      if (staff->value[5] == SPOWER_HI)
         value = 60;
      if (staff->value[5] == SPOWER_GREAT)
         value = 90;
      if (staff->value[5] == SPOWER_GREATER)
         value = 130;
      if (staff->value[5] == SPOWER_GREATEST)
         value = 180;
      value = value * (100-(staff->value[10]*4)) / 100;
      staff->value[0] -= number_range(value*80/100, value*120/100);
      if (staff->value[0] <= 0)
      {
         act(AT_MAGIC, "$p blazes bright and vanishes from $n's hands!", ch, staff, NULL, TO_ROOM);
         act(AT_MAGIC, "$p blazes bright and is gone!", ch, staff, NULL, TO_CHAR);
         if (staff->serial == cur_obj)
            global_objcode = rOBJ_USED;
         extract_obj(staff);
      }
   }

   return;
}


//No reason, just use brandish
void do_zap(CHAR_DATA * ch, char *argument)
{
   do_brandish(ch, argument);
   return;
}

/*
 * Save items in a clan storage room			-Scryn & Thoric
 */
void save_clan_storeroom(CHAR_DATA * ch, CLAN_DATA * clan)
{
   FILE *fp;
   char filename[256];
   OBJ_DATA *contents;

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

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

   sprintf(filename, "%s%s.vault", CLAN_DIR, clan->filename);
   if ((fp = fopen(filename, "w")) == NULL)
   {
      bug("save_clan_storeroom: fopen", 0);
      perror(filename);
   }
   else
   {
      fprintf(fp, "#VERSION\n");
      fprintf(fp, "Version    %d\n", SAVEVERSION);
      fprintf(fp, "End\n\n");
      contents = ch->in_room->last_content;
      if (contents)
      {
         fwrite_obj(ch, contents, fp, 0, OS_CARRY);
      }
      fprintf(fp, "#END\n");
      fclose(fp);
      return;
   }
   return;
}

/* put an item on , or see the stats on the current item or bet */
void do_auction(CHAR_DATA * ch, char *argument)
{
   OBJ_DATA *obj;
   char arg1[MIL];
   char arg2[MIL];
   char arg3[MIL];
   char buf[MSL];
   int i;

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

   set_char_color(AT_LBLUE, ch);

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

   /*  I pity the foo that doesn't work nights....
   if ((gethour() > 18 || gethour() < 9) && auction->item == NULL && !IS_IMMORTAL(ch))
   {
      send_to_char("\n\rThe auctioneer works between the hours of 9 AM and 6 PM\n\r", ch);
      return;
   } */

   if (arg1[0] == '\0')
   {
      if (auction->item != NULL)
      {

         obj = auction->item;

         /* show item data here */
         if (auction->bet > 0)
            sprintf(buf, "\n\rCurrent bid on this item is %d gold.\n\r", auction->bet);
         else
            sprintf(buf, "\n\rNo bids on this item have been received.\n\r");
         set_char_color(AT_BLUE, ch);
         send_to_char(buf, ch);

         code_identify(ch, obj, NULL, 1, NULL);

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

         if (IS_IMMORTAL(ch))
         {
            sprintf(buf, "Seller: %s.  Bidder: %s.  Round: %d.\n\r", auction->seller->name, auction->buyer->name, (auction->going + 1));
            send_to_char(buf, ch);
            sprintf(buf, "Time left in round: %d.\n\r", auction->pulse);
            send_to_char(buf, ch);
         }
         return;
      }
      else
      {
         set_char_color(AT_LBLUE, ch);
         send_to_char("\n\rThere is nothing being auctioned right now.  What would you like to auction?\n\r", ch);
         return;
      }
   }

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

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

         if (ch->level < auction->item->level)
         {
            send_to_char("This object's level is too high for your use.\n\r", ch);
            return;
         }

         if (ch == auction->seller)
         {
            send_to_char("You can't bid on your own item!\n\r", ch);
            return;
         }
         
         if (IS_UNIQUE(ch, auction->item))
         {
            send_to_char("That item is unique and you already have one.\n\r", ch);
            return;
         }

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

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

         if (newbet < auction->starting)
         {
            send_to_char("You must place a bid that is higher than the starting bet.\n\r", ch);
            return;
         }

         /* to avoid slow auction, use a bigger amount than 100 if the bet
            is higher up - changed to 10000 for our high economy
          */
         /* Blah, changed it back -- Xerves 11/99 */

         if (newbet < (auction->bet + 100))
         {
            send_to_char("You must at least bid 100 coins over the current bid.\n\r", ch);
            return;
         }

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

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

         /* Is it the item they really want to bid on? --Shaddai */
         if (arg3[0] != '\0' && !nifty_is_name(arg3, auction->item->name))
         {
            send_to_char("That item is not being auctioned right now.\n\r", ch);
            return;
         }
         /* the actual bet is OK! */

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

         ch->gold -= newbet; /* substract the gold - important :) */
         if (IS_SET(sysdata.save_flags, SV_AUCTION))
            save_char_obj(ch);
         auction->buyer = ch;
         auction->bet = newbet;
         auction->going = 0;
         auction->pulse = PULSE_AUCTION; /* start the auction over again */

         sprintf(buf, "A bid of %d gold has been received on %s.\n\r", newbet, auction->item->short_descr);
         talk_auction(buf);
         return;


      }
      else
      {
         send_to_char("There isn't anything being auctioned right now.\n\r", ch);
         return;
      }
   }
   /* finally... */
   if (ms_find_obj(ch))
      return;

   obj = get_obj_carry(ch, arg1); /* does char have the item ? */

   if (obj == NULL)
   {
      send_to_char("You aren't carrying that.\n\r", ch);
      return;
   }

   if (obj->timer > 0)
   {
      send_to_char("You can't auction objects that are decaying.\n\r", ch);
      return;
   }
   if (get_timer(ch, TIMER_AUCTION) >= 1)
   {
      send_to_char("There is a 30 second wait after you auction an item, please wait.\n\r", ch);
      return;
   }

   /* prevent repeat auction items */
   for (i = 0; i < AUCTION_MEM && auction->history[i]; i++)
   {
      if (auction->history[i] == obj->pIndexData)
      {
         send_to_char("Such an item has been auctioned " "recently, try again later.\n\r", ch);
         return;
      }
   }


   if (arg2[0] == '\0')
   {
      auction->starting = obj->cost;
      sprintf(arg2, "%d", obj->cost);
   }
   
   if (!str_cmp(arg2, "lowest"))
   {
      auction->starting = UMAX(1, obj->cost/10);
      sprintf(arg2, "%d", UMAX(1, obj->cost/10));
   }

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

   if (atoi(arg2) < UMAX(1,obj->cost/10))
   {
      send_to_char("You can't auction something for less than 1/10 cost of the object!\n\r", ch);
      return;
   }

/* Cannot auction a nogive item, another block --Xerves 3/24/99 */
   if (IS_OBJ_STAT(obj, ITEM_NOGIVE))
   {
      send_to_char("Please give up!  You cannot auction this item!n\r", ch);
      return;
   }

   if (auction->item == NULL)
      switch (obj->item_type)
      {

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

/* insert any more item types here... items with a timer MAY NOT BE
   AUCTIONED!
*/
         case ITEM_LIGHT:
         case ITEM_TREASURE:
         case ITEM_POTION:
         case ITEM_CONTAINER:
         case ITEM_KEYRING:
         case ITEM_QUIVER:
         case ITEM_DRINK_CON:
         case ITEM_FOOD:
         case ITEM_COOK:
         case ITEM_PEN:
         case ITEM_BOAT:
         case ITEM_PIPE:
         case ITEM_INCENSE:
         case ITEM_FIRE:
         case ITEM_RUNEPOUCH:
         case ITEM_MAP:
         case ITEM_BOOK:
         case ITEM_RUNE:
         case ITEM_TGEM:
         case ITEM_MATCH:
         case ITEM_WEAPON:
         case ITEM_ARMOR:
         case ITEM_SCROLL:
            separate_obj(obj);
            obj_from_char(obj);
            if (IS_SET(sysdata.save_flags, SV_AUCTION))
               save_char_obj(ch);
            auction->item = obj;
            auction->bet = 0;
            auction->buyer = ch;
            auction->seller = ch;
            auction->pulse = PULSE_AUCTION;
            auction->going = 0;
            auction->starting = atoi(arg2);

            /* add the new item to the history */
            if (AUCTION_MEM > 0)
            {
               memmove((char *) auction->history + sizeof(OBJ_INDEX_DATA *), auction->history, (AUCTION_MEM - 1) * sizeof(OBJ_INDEX_DATA *));
               auction->history[0] = obj->pIndexData;
            }

            /* reset the history timer */
            auction->hist_timer = 0;


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

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

            return;

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

//EQ like Bazaar.  Will allow players to put up equipment to sell.  There will
//be a fee though and you don't have to sit around to sell the objects.
void do_market(CHAR_DATA *ch, char *argument)
{
   char arg1[MIL];
   char arg2[MIL];
   char arg3[MIL];
   char arg4[MIL];
   char buf[MSL];
   char buf2[MSL];
   int count = 0;
   int price = 0;
   int sellname = 0;
   OBJ_DATA *obj;
   OBJ_DATA *rest;
   MARKET_DATA *market;
   MARKET_DATA *marketnext;
   int num = 0;
   
   if (check_npc(ch))
      return;
   if (!xIS_SET(ch->in_room->room_flags, ROOM_MARKETPLACE))
   {
      send_to_char("You can only use this command at a marketplace.\n\r", ch);
      return;
   }
   if (argument[0] == '\0')
   {
      send_to_char("Syntax:  market list [search option] [value]\n\r", ch);
      send_to_char("Syntax:  market sell <name of item> [count|all] [cost|lowest] [list seller name <yes|no>]\n\r", ch);
      send_to_char("Syntax:  market buy <number> <count|all>\n\r", ch);
      send_to_char("Syntax:  market edit <number> <list|cost> <new value>\n\r", ch);
      send_to_char("Syntax:  market view <number>\n\r", ch);
      send_to_char("Syntax:  market claim\n\r", ch);
      send_to_char("Syntax:  seach options: all name maxcost mincost rangecost itemtype\n\r", ch);
      return;
   }
   argument = one_argument(argument, arg1);
   if (!str_cmp(arg1, "claim"))
   {
      for (market = first_market; market; market = marketnext)
      {
         marketnext = market->next;
         if (market->count < market->scount && market->pid == ch->pcdata->pid)
         {
            price = market->cost * (market->scount - market->count);
            ch->gold += price - (price * 5 / 100);  
            num++;
            ch_printf(ch, "You sold %d of %d of %s and you earned %d (fee of %d)\n\r", 
               market->scount - market->count, market->scount, market->obj->short_descr, 
               price - (price * 5 / 100), price * 5 / 100);
            if (market->count == 0)
            {
               STRFREE(market->name);
               extract_obj(market->obj);
               UNLINK(market, first_market, last_market, next, prev);
               DISPOSE(market);
            }
            else
            {
               market->scount = market->count;
            }
         }
      }
      if (num == 0)
      {
         send_to_char("None of your goods have sold yet.\n\r", ch);
         return;
      }
      else
      {
         save_market_data();
         return;
      }
   }
   if (!str_cmp(arg1, "edit"))
   {
      argument = one_argument(argument, arg2);
      argument = one_argument(argument, arg3);  
      for (market = first_market; market; market = market->next)
      {
         num++;
         if (market->mpid == atoi(arg2))
            break;
      }
      if (!market)
      {
         send_to_char("That item number does not exist.\n\r", ch);
         return;
      } 
      if (market->pid != ch->pcdata->pid)
      {
         send_to_char("This object does not belong to you.\n\r", ch);
         return;
      }
      if (!str_cmp(arg3, "cost"))
      {
         if (atoi(argument) < market->obj->cost)
         {
            send_to_char("Asking price cannot be lower than the cost of the object.\n\r", ch);
            return;
         }   
         market->cost = atoi(argument);
         ch_printf(ch, "Changed the cost on item %d to %d\n\r", atoi(arg2), atoi(argument));
         save_market_data();
         return;
      }
      if (!str_cmp(arg3, "list"))
      {
         if (!str_cmp(argument, "no"))
         {
            if (market->name)
               STRFREE(market->name);
            market->name = STRALLOC("Unlisted");
         }
         else if (!str_cmp(argument, "yes"))
         {
            if (market->name)
               STRFREE(market->name);
            market->name = STRALLOC(ch->name);
         }
         else
         {
            do_market(ch, "");
            return;
         }
         send_to_char("Changed your name listing to what you provided.\n\r", ch);
         save_market_data();
         return;
      }
      do_market(ch, "");
      return;
   }
   if (!str_cmp(arg1, "view"))
   {
      for (market = first_market; market; market = market->next)
      {
         num++;
         if (market->mpid == atoi(argument))
            break;
      }
      if (!market)
      {
         send_to_char("That item number does not exist.\n\r", ch);
         return;
      }
      code_identify(ch, market->obj, NULL, 1, NULL);
      return;
   }
   if (!str_cmp(arg1, "buy"))
   {
      argument = one_argument(argument, arg2);
      if (atoi(arg2) <= 0)
      {
         send_to_char("You must specify the number of the item you wish to purchase.\n\r", ch);
         return;
      }
      for (market = first_market; market; market = market->next)
      {
         if (market->mpid == atoi(arg2))
            break;
      }
      if (!market)
      {
         send_to_char("That item number does not exist.\n\r", ch);
         return;
      }
      if (atoi(argument) > 0)
      {
         if (market->count < atoi(argument))
         {
            ch_printf(ch, "There is only %d of those for sale.\n\r", market->count);
            return;
         }
         if (market->count == atoi(argument))
            count = -1;
         else
            count = atoi(argument);
      }
      else if (!str_cmp(argument, "all"))
      {
         count = -1;
      }
      else
      {
         send_to_char("Invalid option.\n\r", ch);
         return;
      }
      if (count == -1)
         price = market->count * market->cost;
      else
         price = market->cost * count;
      if (price > ch->gold)
      {
         send_to_char("You do not have enough gold to pay for that.\n\r", ch);
         return;
      }
      if (count == -1)
      {  
         if (get_ch_carry_weight(ch) + (get_obj_weight(market->obj) * market->count) > can_carry_w(ch))
         {
            send_to_char("You cannot carry that much weight.\n\r", ch);
            return;
         }
         if (get_ch_carry_number(ch) + market->count > can_carry_n(ch))
         {
            send_to_char("You cannot carry that many items.\n\r", ch);
            return;
         }
         obj = clone_object(market->obj);
         count = market->count;
         obj->count = market->count;
         market->count = 0;
         obj_to_char(obj, ch);
      }
      else
      {
         if (get_ch_carry_weight(ch) + (get_obj_weight(market->obj) * count) > can_carry_w(ch))
         {
            send_to_char("You cannot carry that much weight.\n\r", ch);
            return;
         }
         if (get_ch_carry_number(ch) + count > can_carry_n(ch))
         {
            send_to_char("You cannot carry that many items.\n\r", ch);
            return;
         }
         obj = clone_object(market->obj);
         obj->count = count;
         market->count -= count;
         obj_to_char(obj, ch);
      }
      ch->gold -= price;
      save_market_data();
      ch_printf(ch, "You have purchased %d of %s\n\r", count, obj->short_descr);
      return;
   }
      
   if (!str_cmp(arg1, "list"))
   {
      argument = one_argument(argument, arg2);
      if (!str_cmp(arg2, "name"))
      {
         ch_printf(ch, "&w&RNum      Item Name                       Cnt Cost       Asking     Itemtype        Seller\n\r----------------------------------------------------------------------------------------------\n\r", ch);
         for (market = first_market; market; market = market->next)
         {
            num++;
            if (market->count)
            {
               if (nifty_is_name(argument, market->obj->name))
               {
                  sprintf(buf2, "%d", market->mpid);
                  sprintf(buf, MXPFTAG("Command 'market view %d' desc='Click here to id this item'", "%d", "/Command") "%s", 
                     market->mpid, market->mpid, add_space(strlen(buf2), 6));
                  ch_printf(ch, "&c&w%s>  " MXPFTAG("PCommand 'market buy %d 1' desc='Click here to buy this item'", "&w&W%s", "/PCommand") 
                     "%s&w&W  %-2d  &w&c%-10d &w&C%-10d ", 
                     buf, market->mpid, market->obj->short_descr, add_wspace(strlen_color(market->obj->short_descr), 30),
                     market->count, market->obj->cost, market->cost);   
                  ch_printf(ch, MXPFTAG("Command 'market list itemtype %s' desc='Click here to view other items of this itemtype'", "&w&G%s", "/Command")
                     "%s  &w&O%-15s\n\r", item_type_name(market->obj), item_type_name(market->obj), 
                     add_wspace(strlen(item_type_name(market->obj)), 14), market->name);
                }
            }
         }
         return;
      }   
      if (!str_cmp(arg2, "mincost"))
      {
         ch_printf(ch, "&w&RNum      Item Name                       Cnt Cost       Asking     Itemtype        Seller\n\r----------------------------------------------------------------------------------------------\n\r", ch);
         for (market = first_market; market; market = market->next)
         {
            num++;
            if (market->count)
            {
               if (market->cost >= atoi(argument))
               {
                  sprintf(buf2, "%d", market->mpid);
                  sprintf(buf, MXPFTAG("Command 'market view %d' desc='Click here to id this item'", "%d", "/Command") "%s", 
                     market->mpid, market->mpid, add_space(strlen(buf2), 6));
                  ch_printf(ch, "&c&w%s>  " MXPFTAG("PCommand 'market buy %d 1' desc='Click here to buy this item'", "&w&W%s", "/PCommand") 
                     "%s&w&W  %-2d  &w&c%-10d &w&C%-10d ", 
                     buf, market->mpid, market->obj->short_descr, add_wspace(strlen_color(market->obj->short_descr), 30),
                     market->count, market->obj->cost, market->cost);   
                  ch_printf(ch, MXPFTAG("Command 'market list itemtype %s' desc='Click here to view other items of this itemtype'", "&w&G%s", "/Command")
                     "%s  &w&O%-15s\n\r", item_type_name(market->obj), item_type_name(market->obj), 
                     add_wspace(strlen(item_type_name(market->obj)), 14), market->name);
                }
            }
         }
         return;
      }   
      if (!str_cmp(arg2, "rangecost"))
      {
         argument = one_argument(argument, arg3);
         if (atoi(arg3) > atoi(argument))
         {
            send_to_char("The first value in the range has to be less than the second.\n\r", ch);
            return;
         }
         ch_printf(ch, "&w&RNum      Item Name                       Cnt Cost       Asking     Itemtype        Seller\n\r----------------------------------------------------------------------------------------------\n\r", ch);
         for (market = first_market; market; market = market->next)
         {
            num++;
            if (market->count)
            {
               if (market->cost >= atoi(arg3) && market->cost <= atoi(argument))
               {
                  sprintf(buf2, "%d", market->mpid);
                  sprintf(buf, MXPFTAG("Command 'market view %d' desc='Click here to id this item'", "%d", "/Command") "%s", 
                     market->mpid, market->mpid, add_space(strlen(buf2), 6));
                  ch_printf(ch, "&c&w%s>  " MXPFTAG("PCommand 'market buy %d 1' desc='Click here to buy this item'", "&w&W%s", "/PCommand") 
                     "%s&w&W  %-2d  &w&c%-10d &w&C%-10d ", 
                     buf, market->mpid, market->obj->short_descr, add_wspace(strlen_color(market->obj->short_descr), 30),
                     market->count, market->obj->cost, market->cost);   
                  ch_printf(ch, MXPFTAG("Command 'market list itemtype %s' desc='Click here to view other items of this itemtype'", "&w&G%s", "/Command")
                     "%s  &w&O%-15s\n\r", item_type_name(market->obj), item_type_name(market->obj), 
                     add_wspace(strlen(item_type_name(market->obj)), 14), market->name);
                }
            }
         }
         return;
      }
      if (!str_cmp(arg2, "maxcost"))
      {
         ch_printf(ch, "&w&RNum      Item Name                       Cnt Cost       Asking     Itemtype        Seller\n\r----------------------------------------------------------------------------------------------\n\r", ch);
         for (market = first_market; market; market = market->next)
         {
            num++;
            if (market->count)
            {
               if (market->cost <= atoi(argument))
               {
                  sprintf(buf2, "%d", market->mpid);
                  sprintf(buf, MXPFTAG("Command 'market view %d' desc='Click here to id this item'", "%d", "/Command") "%s", 
                     market->mpid, market->mpid, add_space(strlen(buf2), 6));
                  ch_printf(ch, "&c&w%s>  " MXPFTAG("PCommand 'market buy %d 1' desc='Click here to buy this item'", "&w&W%s", "/PCommand") 
                     "%s&w&W  %-2d  &w&c%-10d &w&C%-10d ", 
                     buf, market->mpid, market->obj->short_descr, add_wspace(strlen_color(market->obj->short_descr), 30),
                     market->count, market->obj->cost, market->cost);   
                  ch_printf(ch, MXPFTAG("Command 'market list itemtype %s' desc='Click here to view other items of this itemtype'", "&w&G%s", "/Command")
                     "%s  &w&O%-15s\n\r", item_type_name(market->obj), item_type_name(market->obj), 
                     add_wspace(strlen(item_type_name(market->obj)), 14), market->name);
                }
            }
         }
         return;
      }
      if (!str_cmp(arg2, "itemtype"))
      {
         int ivalue = get_otype(argument);
         if (ivalue < 1)
         {
            ch_printf(ch, "Unknown type: %s\n\r", argument);
            return;
         }
         ch_printf(ch, "&w&RNum      Item Name                       Cnt Cost       Asking     Itemtype        Seller\n\r----------------------------------------------------------------------------------------------\n\r", ch);
         for (market = first_market; market; market = market->next)
         {
            num++;
            if (market->count)
            {
               if (market->obj->item_type == ivalue)
               {
                  sprintf(buf2, "%d", market->mpid);
                  sprintf(buf, MXPFTAG("Command 'market view %d' desc='Click here to id this item'", "%d", "/Command") "%s", 
                     market->mpid, market->mpid, add_space(strlen(buf2), 6));
                  ch_printf(ch, "&c&w%s>  " MXPFTAG("PCommand 'market buy %d 1' desc='Click here to buy this item'", "&w&W%s", "/PCommand") 
                     "%s&w&W  %-2d  &w&c%-10d &w&C%-10d ", 
                     buf, market->mpid, market->obj->short_descr, add_wspace(strlen_color(market->obj->short_descr), 30),
                     market->count, market->obj->cost, market->cost);   
                  ch_printf(ch, MXPFTAG("Command 'market list itemtype %s' desc='Click here to view other items of this itemtype'", "&w&G%s", "/Command")
                     "%s  &w&O%-15s\n\r", item_type_name(market->obj), item_type_name(market->obj), 
                     add_wspace(strlen(item_type_name(market->obj)), 14), market->name);
                }
            }
         }
         return;
      }
      if (!str_cmp(arg2, "all"))
      {
         ch_printf(ch, "&w&RNum      Item Name                       Cnt Cost       Asking     Itemtype        Seller\n\r---------------------------------------------------------------------------------------------\n\r", ch);
         for (market = first_market; market; market = market->next)
         {
            num++;
            if (market->count)
            {
               sprintf(buf2, "%d", market->mpid);
               sprintf(buf, MXPFTAG("Command 'market view %d' desc='Click here to id this item'", "%d", "/Command") "%s", 
                  market->mpid, market->mpid, add_space(strlen(buf2), 6));
               ch_printf(ch, "&c&w%s>  " MXPFTAG("PCommand 'market buy %d 1' desc='Click here to buy this item'", "&w&W%s", "/PCommand") 
                  "%s&w&W  %-2d  &w&c%-10d &w&C%-10d ", 
                  buf, market->mpid, market->obj->short_descr, add_wspace(strlen_color(market->obj->short_descr), 30),
                  market->count, market->obj->cost, market->cost);   
               ch_printf(ch, MXPFTAG("Command 'market list itemtype %s' desc='Click here to view other items of this itemtype'", "&w&G%s", "/Command")
                  "%s  &w&O%-15s\n\r", item_type_name(market->obj), item_type_name(market->obj), 
                  add_wspace(strlen(item_type_name(market->obj)), 14), market->name);
            }
         }
         return;
      }
      send_to_char("Your options are: all name maxcost mincost rangecost itemtype\n\r", ch);
      return;
   }
   if (!str_cmp(arg1, "sell"))
   {
      argument = one_argument(argument, arg2);
      argument = one_argument(argument, arg3);  
      argument = one_argument(argument, arg4);  
      if ((obj = get_obj_carry(ch, arg2)) == NULL)
      {
         send_to_char("You don't have that item in your inventory.\n\r", ch);
         return;
      }
      if (IS_OBJ_STAT(obj, ITEM_NOGIVE) || IS_OBJ_STAT(obj, ITEM_NODROP) || IS_OBJ_STAT(obj, ITEM_ARTIFACT))
      {
         send_to_char("You cannot attempt to sell an item with a nogive/nodrop/artifact flag on it.\n\r", ch);
         return;
      }
      if (obj->first_content)
      {
         send_to_char("You cannot sell a container with something in it.\n\r", ch);
         return;
      }
      if (atoi(arg3) <= 0 && str_cmp(arg3, "all"))
      {
         send_to_char("You need to specify a number of the item to sell or type all.\n\r", ch);
         return;
      }
      if (arg3[0] == '\0')
      {
         count = 1;
      }
      else
      {
         if (atoi(arg3) > 0)
         {
            if (obj->count < atoi(arg3))
            {
               ch_printf(ch, "You only have %d of those.  Turn off combine in config to see how they are matched.\n\r", obj->count);
               return;
            }
            if (obj->count == atoi(arg3))
               count = -1;
            else
               count = atoi(arg3);
         }
         else if (!str_cmp(arg3, "all"))
         {
            count = -1;
         }
         else
         {
            send_to_char("Invalid option.\n\r", ch);
            return;
         }
      }
      if (arg4[0] == '\0')
      {
         price = obj->cost;
      }
      else
      {
         if (!str_cmp(arg4, "lowest"))
         {
            price = UMAX(1, obj->cost/10);
         }
         else if (atoi(arg4) < UMAX(1, obj->cost/10))
         {
            send_to_char("Asking price cannot be lower than 1/10 the cost of the object.\n\r", ch);
            return;
         }
         else
         {
           price = atoi(arg4);
         }
      }
      if (!str_cmp(argument, "yes"))
         sellname = 1;
      CREATE(market, MARKET_DATA, 1);
      market->mpid = ++start_marketpid;
      market->cost = price;
      if (count == -1)
         market->count = obj->count;
      else
         market->count = count;
      market->pid = ch->pcdata->pid;
      if (sellname)
         market->name = STRALLOC(ch->name);
      else
         market->name = STRALLOC("Unlisted");
      if (count == -1)
      {  
         obj_from_char(obj);
         obj->count = 1;
         market->obj = obj;
      }
      else
      {
         rest = separate_obj(obj);
         obj_from_char(obj);
         obj->count = 1;
         market->obj = obj;
         rest->count = rest->count - market->count + 1;
      }
      market->scount = market->count;
      LINK(market, first_market, last_market, next, prev);
      save_market_data();
      ch_printf(ch, "You have put up %d of %s for sale.\n\r", market->count, market->obj->short_descr);
      return;
   }
   do_market(ch, "");
   return;
}     

/* Make objects in rooms that are nofloor fall - Scryn 1/23/96 */
void obj_fall(OBJ_DATA * obj, bool through)
{
   EXIT_DATA *pexit;
   ROOM_INDEX_DATA *to_room;
   static int fall_count;
   char buf[MSL];
   static bool is_falling; /* Stop loops from the call to obj_to_room()  -- Altrag */

   if (!obj->in_room || is_falling)
      return;

   if (fall_count > 30)
   {
      bug("object falling in loop more than 30 times", 0);
      extract_obj(obj);
      fall_count = 0;
      return;
   }

   if (xIS_SET(obj->in_room->room_flags, ROOM_NOFLOOR) && CAN_GO(obj, DIR_DOWN) && !IS_OBJ_STAT(obj, ITEM_MAGIC))
   {

      pexit = get_exit(obj->in_room, DIR_DOWN);
      to_room = pexit->to_room;

      if (through)
         fall_count++;
      else
         fall_count = 0;

      if (obj->in_room == to_room)
      {
         sprintf(buf, "Object falling into same room, room %d", to_room->vnum);
         bug(buf, 0);
         extract_obj(obj);
         return;
      }

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

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

      if (!xIS_SET(obj->in_room->room_flags, ROOM_NOFLOOR) && through)
      {
/*		int dam = (int)9.81*sqrt(fall_count*2/9.81)*obj->weight/2;
*/ int dam = fall_count * obj->weight / 2;

         /* Damage players */
         if (obj->in_room->first_person && number_percent() > 15)
         {
            CHAR_DATA *rch;
            CHAR_DATA *vch = NULL;
            int chcnt = 0;

            for (rch = obj->in_room->first_person; rch; rch = rch->next_in_room, chcnt++)
               if (number_range(0, chcnt) == 0)
                  vch = rch;
            act(AT_WHITE, "$p falls on $n!", vch, obj, NULL, TO_ROOM);
            act(AT_WHITE, "$p falls on you!", vch, obj, NULL, TO_CHAR);
            damage(vch, vch, dam, TYPE_UNDEFINED, 0, -1);
         }
      }
      obj_fall(obj, TRUE);
   }
   return;
}

/* Scryn, by request of Darkur, 12/04/98 */
/* Reworked recursive_note_find to fix crash bug when the note was left 
 * blank.  7/6/98 -- Shaddai
 */

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

   if (IS_NPC(ch))
   {
      send_to_char("Huh?\n\r", ch);
      return;
   }

   if (argument[0] == '\0')
   {
      send_to_char("You must specify at least one keyword.\n\r", ch);
      return;
   }

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

   if (obj)
   {
      if (obj->in_obj)
      {
         obj_from_obj(obj);
         obj = obj_to_char(obj, ch);
      }
      wear_obj(ch, obj, TRUE, -1);
   }
   else
      send_to_char("Note not found.\n\r", ch);
   return;
}

OBJ_DATA *recursive_note_find(OBJ_DATA * obj, char *argument)
{
   OBJ_DATA *returned_obj;
   bool match = TRUE;
   char *argcopy;
   char *subject;

   char arg[MIL];
   char subj[MSL];

   if (!obj)
      return NULL;

   switch (obj->item_type)
   {
      case ITEM_PAPER:

         if ((subject = get_extra_descr("_subject_", obj->first_extradesc)) == NULL)
            break;
         sprintf(subj, "%s", strlower(subject));
         subject = strlower(subj);

         argcopy = argument;

         while (match)
         {
            argcopy = one_argument(argcopy, arg);

            if (arg[0] == '\0')
               break;

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


         if (match)
            return obj;
         break;

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

      default:
         break;
   }

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

/* Junk command installed by Shai'tan 7-25-99
   Code courtesy of Stu, from the mailing list. Allows player to
   destroy item in inventory. */

void do_junk(CHAR_DATA * ch, char *argument)
{
   OBJ_DATA *obj, *obj_next;
   char arg[MIL];
   char *chk;
   bool found = FALSE;

   argument = one_argument(argument, arg);

   if (arg[0] == '\0')
   {
      send_to_char("Junk what?\n\r", ch);
      return;
   }
   chk = arg;
   
   if (IS_NPC(ch) && xIS_SET(ch->act, ACT_MILITARY))
   {
      send_to_char("You cannot do that.\n\r", ch);
      return;
   }

   found = FALSE;
   for (obj = ch->first_carrying; obj; obj = obj_next)
   {
      obj_next = obj->next_content;

      if ((nifty_is_name(chk, obj->name)) && can_see_obj(ch, obj) && obj->wear_loc == WEAR_NONE)
      {
         found = TRUE;
         break;
      }
   }
   if (found == TRUE)
   {
      separate_obj(obj);
      obj_from_char(obj);
      extract_obj(obj);
      act(AT_ACTION, "$n junks $p.", ch, obj, NULL, TO_ROOM);
      act(AT_ACTION, "You junk $p.", ch, obj, NULL, TO_CHAR);
   }
   return;
}

int get_used_imbueslots(OBJ_DATA *obj)
{
   int cnt = 0;
   IMBUE_DATA *imbue;
   
   for (imbue = obj->first_imbue; imbue; imbue = imbue->next)
   {
      if (imbue->plevel == -1)
         continue;
      if (imbue->plevel == 0)
         cnt++;
      else
         cnt += imbue->plevel;
   }   
   return cnt;
}

extern int top_affect;
void save_sysdata args((SYSTEM_DATA sys));


//1000 - Damage  1001 - Durability  1002 - TohitBash  1003 - TohitStab   1004 - TohitSlash
//1005 - Weight  1006 - Shieldlag   1007 - Blocking % 1008 - Proj Range  1009 - Parry Chance 1010 - Stop Parry
//1011 - SpellSN 1012 - SpellStr    1013 - Unbeakable 1014 - Nodisarm    1015 - Sanctified 1016 - Change Size
//1017 - Saves
void set_otheraff_gem(int type, int value, OBJ_DATA *obj, int gemnum)
{
   AFFECT_DATA *paf;
   
   if (type == 1000)
   {
      if (obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_PROJECTILE || obj->item_type == ITEM_MISSILE_WEAPON)
      {
         obj->value[1] += value;
         obj->value[2] += value;
      }
   }
   if (type == 1001)
   {
      if (obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_MISSILE_WEAPON)   
      {
         obj->value[10] = UMIN(25, obj->value[10]+value);
      }
      if (obj->item_type == ITEM_ARMOR && !IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
      {
         obj->value[4] = UMIN(25, obj->value[4]+value);
      }
      if (obj->item_type == ITEM_ARMOR && IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
      {
         obj->value[1] += obj->value[1] * value / 50;
      }
   }
   if (type == 1002)
   {
      if (obj->item_type == ITEM_WEAPON)   
      {
         obj->value[7] += value;
      }
      if (obj->item_type == ITEM_ARMOR && !IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
      {
         obj->value[0] += value;
      }   
   }
   if (type == 1003)
   {
      if (obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_PROJECTILE || obj->item_type == ITEM_MISSILE_WEAPON)   
      {
         obj->value[9] += value;
      }
      if (obj->item_type == ITEM_ARMOR && !IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
      {
         obj->value[2] += value;
      }   
   }
   if (type == 1004)
   {
      if (obj->item_type == ITEM_WEAPON)   
      {
         obj->value[8] += value;
      }
      if (obj->item_type == ITEM_ARMOR && !IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
      {
         obj->value[1] += value;
      }   
   }
   if (type == 1005)
      obj->weight = UMAX(.01, obj->weight-=abs(value));
   if (type == 1006)
   {
      if (obj->item_type == ITEM_ARMOR && IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
         obj->value[3] = UMAX(0, obj->value[3]-abs(value));
   }
   if (type == 1007)
   {
      if (obj->item_type == ITEM_ARMOR && IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD))
         obj->value[2] += value;
   }
   if (type == 1008)
   {
      if (obj->item_type == ITEM_MISSILE_WEAPON)
         obj->value[4] += value;
   }
   if (type == 1009)
   {
      if (obj->item_type == ITEM_WEAPON)
         obj->value[12] += value;
   }
   if (type == 1010)
   {
      if (obj->item_type == ITEM_WEAPON)
         obj->value[13] += value;
   }
   if (type == 1011)
   {
      if (obj->item_type == ITEM_WEAPON)
         obj->value[4] = value;
   }
   if (type == 1012)
   {
      if (obj->item_type == ITEM_WEAPON)
         obj->value[5] = value;
   }
   if (type == 1013)
   {
      xSET_BIT(obj->extra_flags, ITEM_NOBREAK);
   }
   if (type == 1014)
   {
      xSET_BIT(obj->extra_flags, ITEM_NODISARM);
   }
   if (type == 1015)
   {
      xSET_BIT(obj->extra_flags, ITEM_SANCTIFIED);
   }
   if (type == 1016)
   {
      if (obj->item_type == ITEM_WEAPON)
         obj->value[3] = URANGE(1, obj->value[3]+value, 12);
   }
   if (type == 1017)
   {
      CREATE(paf, AFFECT_DATA, 1);
      paf->type = -1;
      paf->duration = -1;
      paf->location = 20;
      paf->modifier = value;
      paf->gemnum = gemnum;
      xCLEAR_BITS(paf->bitvector);
      paf->next = NULL;
      LINK(paf, obj->first_affect, obj->last_affect, next, prev);
      ++top_affect;
      CREATE(paf, AFFECT_DATA, 1);
      paf->type = -1;
      paf->duration = -1;
      paf->location = 21;
      paf->modifier = value;
      paf->gemnum = gemnum;
      xCLEAR_BITS(paf->bitvector);
      paf->next = NULL;
      LINK(paf, obj->first_affect, obj->last_affect, next, prev);
      ++top_affect;
      CREATE(paf, AFFECT_DATA, 1);
      paf->type = -1;
      paf->duration = -1;
      paf->location = 22;
      paf->modifier = value;
      paf->gemnum = gemnum;
      xCLEAR_BITS(paf->bitvector);
      paf->next = NULL;
      LINK(paf, obj->first_affect, obj->last_affect, next, prev);
      ++top_affect;
      CREATE(paf, AFFECT_DATA, 1);
      paf->type = -1;
      paf->duration = -1;
      paf->location = 23;
      paf->modifier = value;
      paf->gemnum = gemnum;
      xCLEAR_BITS(paf->bitvector);
      paf->next = NULL;
      LINK(paf, obj->first_affect, obj->last_affect, next, prev);
      ++top_affect;
      CREATE(paf, AFFECT_DATA, 1);
      paf->type = -1;
      paf->duration = -1;
      paf->location = 24;
      paf->modifier = value;
      paf->gemnum = gemnum;
      xCLEAR_BITS(paf->bitvector);
      paf->next = NULL;
      LINK(paf, obj->first_affect, obj->last_affect, next, prev);
      ++top_affect;
   }
}


/* Connect pieces of an ITEM -- Originally from ACK!  *
 * Modified for Smaug by Zarius 5/19/2000             *
 *						      *
 * Zarius' connect-item code altered for	      *
 * Rafermand mini-nodes by Skan 1/26/02		      *
 * 						      *
 * do_connect altered... changed to do_setgem         */
//Changed altogether for something else -- Xerves
 
void do_setgem(CHAR_DATA * ch, char *argument)
{
   OBJ_DATA *first_obj;
   OBJ_DATA *second_obj;
   IMBUE_DATA *imbue;
   AFFECT_DATA *paf;
   int usedslots;

   char arg1[MSL], arg2[MAX_STRING_LENGTH];

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

   if (arg1[0] == '\0' || arg2[0] == '\0')
   {
      send_to_char("Syntax: setgem <gem> <item receiving gem>.\n\r", ch);
      return;
   }

   if ((first_obj = get_obj_carry(ch, arg1)) == NULL)
   {
      send_to_char("You must be holding both parts!!\n\r", ch);
      return;
   }
   separate_obj(first_obj);

   if ((second_obj = get_obj_carry(ch, arg2)) == NULL)
   {
      send_to_char("You mus be holding both parts!!\n\r", ch);
      return;
   }
   separate_obj(second_obj);

   if (first_obj->item_type != ITEM_TGEM)
   {
      send_to_char("The first item is not a gem.\n\r", ch);
      return;
   }
   
   if (first_obj->value[12] == -1)
      usedslots = 0;
   else if (first_obj->value[12] == 0)
      usedslots = 1;
   else
      usedslots = first_obj->value[12];
      
   if (get_used_imbueslots(second_obj)+usedslots > second_obj->imbueslots)
   {
      send_to_char("The item is already full and cannot be imbued anymore.\n\r", ch);
      return;
   }
   CREATE(imbue, IMBUE_DATA, 1);
   LINK(imbue, second_obj->first_imbue, second_obj->last_imbue, next, prev);
   imbue->type = first_obj->value[0];
   imbue->sworth = first_obj->value[1];
   imbue->lowvalue = first_obj->value[2];
   imbue->highvalue = first_obj->value[3];
   imbue->value = number_range(imbue->lowvalue, imbue->highvalue);
   imbue->type2 = first_obj->value[4];
   imbue->sworth2 = first_obj->value[5];
   imbue->lowvalue2 = first_obj->value[6];
   imbue->highvalue2 = first_obj->value[7];
   imbue->value2 = number_range(imbue->lowvalue2, imbue->highvalue2);
   imbue->type3 = first_obj->value[8];
   imbue->sworth3 = first_obj->value[9];
   imbue->lowvalue3 = first_obj->value[10];
   imbue->highvalue3 = first_obj->value[11];
   imbue->value3 = number_range(imbue->lowvalue3, imbue->highvalue3);
   imbue->plevel = first_obj->value[12];
   imbue->gemnum = ++sysdata.top_gem_num;
   save_sysdata(sysdata);
   second_obj->sworthrestrict += imbue->sworth;
   second_obj->sworthrestrict += imbue->sworth2;
   second_obj->sworthrestrict += imbue->sworth3;
   
   if (imbue->type > 0 && imbue->type < 1000)
   {
      CREATE(paf, AFFECT_DATA, 1);
      paf->type = -1;
      paf->duration = -1;
      paf->location = imbue->type;
      paf->modifier = imbue->value;
      paf->gemnum = imbue->gemnum;
      xCLEAR_BITS(paf->bitvector);
      paf->next = NULL;
      LINK(paf, second_obj->first_affect, second_obj->last_affect, next, prev);
      ++top_affect;
   }
   if (imbue->type >= 1000)
   {
      set_otheraff_gem(imbue->type, imbue->value, second_obj, imbue->gemnum);
   }
   if (imbue->type2 > 0 && imbue->type2 < 1000)
   {
      CREATE(paf, AFFECT_DATA, 1);
      paf->type = -1;
      paf->duration = -1;
      paf->location = imbue->type2;
      paf->modifier = imbue->value2;
      paf->gemnum = imbue->gemnum;
      xCLEAR_BITS(paf->bitvector);
      paf->next = NULL;
      LINK(paf, second_obj->first_affect, second_obj->last_affect, next, prev);
      ++top_affect;
   }
   if (imbue->type2 >= 1000)
   {
      set_otheraff_gem(imbue->type2, imbue->value2, second_obj, imbue->gemnum);
   }
   if (imbue->type3 > 0 && imbue->type3 < 1000)
   {
      CREATE(paf, AFFECT_DATA, 1);
      paf->type = -1;
      paf->duration = -1;
      paf->location = imbue->type3;
      paf->modifier = imbue->value3;
      paf->gemnum = imbue->gemnum;
      xCLEAR_BITS(paf->bitvector);
      paf->next = NULL;
      LINK(paf, second_obj->first_affect, second_obj->last_affect, next, prev);
      ++top_affect;
   }
   if (imbue->type3 >= 1000)
   {
      set_otheraff_gem(imbue->type3, imbue->value3, second_obj, imbue->gemnum);
   }
      
   act(AT_ACTION, "$n sets $p in $P.", ch, first_obj, second_obj, TO_ROOM);
   act(AT_ACTION, "You set $p in $P.", ch, first_obj, second_obj, TO_CHAR);   
   extract_obj(first_obj);
   return;
}
/*Start Alchemy Section - Corellon - 7/15/02*/
 int get_alch_success(CHAR_DATA *ch, OBJ_DATA *obj)
 {
        return URANGE(30, (30 + 2*get_curr_int(ch) + get_curr_wis(ch) + obj->value[0] + URANGE(-6, get_curr_lck(ch)-14, 6)), 90);
 }
 void do_mixpotion(CHAR_DATA *ch, char *argument)
 {
 	char		arg[MIL];
 	char		arg2[MIL];
 	char		arg3[MIL];
 	char		arg4[MIL];
 	char		buf1[MSL];
 	char		buf2[MSL];
 	char		buf3[MSL];
 	OBJ_DATA	*obj;
 	OBJ_DATA	*obj2;
 	OBJ_DATA	*obj3;
 	OBJ_DATA 	*obj4;
 	int 		mod;
 	int			perm;
 	
 	argument = one_argument(argument,arg);
 	argument = one_argument(argument,arg2);
 	argument = one_argument(argument,arg3);
 	argument = one_argument(argument,arg4);
 	
 	if (IS_NPC(ch))
 	{
 	   send_to_char("Not for NPCs.\n\r", ch);
 	   return;
 	}
 	if(arg[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0' || arg4[0] == '\0')
 	{
 		send_to_char("Usage: mixpotion <power reagant> <affecting reagant> <flask> <mortar>\n\r",ch);
 		return;
 	}
 	if((obj = get_obj_carry(ch,arg)) == NULL)
 	{
 		send_to_char("You don't have the specified power reagant.\n\r",ch);
 		send_to_char("Usage: mixpotion <power reagant> <affecting reagant> <flask> <mortar>\n\r",ch);
 		return;
 	}
 	if((obj2 = get_obj_carry(ch,arg2)) == NULL)
 	{
 		send_to_char("You don't have the specified affect reagant.\n\r",ch);
 		send_to_char("Usage: mixpotion <power reagant> <affecting reagant> <flask> <mortar>\n\r",ch);
 		return;
 	}
 	if((obj3 = get_obj_carry(ch,arg3)) == NULL)
 	{
 		send_to_char("You don't have that container.\n\r",ch);
 		send_to_char("Usage: mixpotion <power reagant> <affecting reagant> <flask> <mortar>\n\r",ch);
 		return;
 	}
 	if((obj4 = get_obj_carry(ch,arg4)) == NULL)
 	{
 		send_to_char("You don't have that mortar and pestle\n\r",ch);
 		send_to_char("Usage: mixpotion <power reagant> <affecting reagant> <flask> <mortar>\n\r",ch);
 		return;
 	}
 	if( obj3->pIndexData->vnum != OBJ_VNUM_FLASK_BREWING || obj3->value[1] != -1)
 	{
 		send_to_char( "You must be holding an empty flask to mix a potion.\n\r", ch );
 		return;
 	}
 	
 	if (!xIS_SET(obj->extra_flags,ITEM_POWREAG))
 	{
 		send_to_char( "That's not a proper power reagant!\n\r",ch);
 		return;
 	}
 	if (!xIS_SET(obj2->extra_flags,ITEM_AFFREAG))
 	{
 	    send_to_char( "That's not a proper reagant!\n\r", ch );
 	    return;
 	}
 	if(!xIS_SET(obj4->extra_flags,ITEM_MORTAR))
 	{
 		send_to_char("Not a mortar\n\r",ch);
 		return;
 	}
 	if(obj->value[5] >= 1008 && xIS_SET(obj2->extra_flags,ITEM_PERMREAG))
 	{
 		perm = TRUE;
 	}
 	else if((obj->value[5] >= 1008 && !xIS_SET(obj2->extra_flags,ITEM_PERMREAG)) || (obj->value[5] < 1008 && xIS_SET(obj2->extra_flags,ITEM_PERMREAG)))
 	{
 		perm = FALSE;
 	}
 	else 
 	{
 		perm = 2;
 	}
 	if(get_alch_success(ch,obj4) < number_range(1,100))
 	{
 		separate_obj(obj3);
 			/* create the potion */
 		mod = obj2->value[1]; // set spell - will be expanded later to account for adding in new skills
 		obj3->value[1] = mod;
 		if(perm==TRUE) //is it perm?
 		{
 			obj3->item_type = ITEM_TREASURE;
 			obj3->value[0] = obj2->value[0];
 			xTOGGLE_BIT(obj3->extra_flags,ITEM_MIXED);
 			STRFREE(obj3->description);
 			sprintf(buf2,"A flask labelled 'permanent' contains a strange mixed liquid");
 			obj3->description = STRALLOC(buf2);
 			STRFREE(obj3->short_descr);
 			sprintf(buf1, "permanent potion");
 			obj3->short_descr = STRALLOC( aoran(buf1));
 			STRFREE(obj3->name);
 			sprintf(buf3, "flask permanent");
 			obj3->name = STRALLOC(buf3);
 			separate_obj(obj2);
 			extract_obj(obj2);
 			separate_obj(obj);
 			extract_obj(obj);
 			return;
 		}
 		else if(perm==2)
 		{
 			obj3->value[5] = obj->value[5];
 			sprintf(buf1, "%s potion", skill_table[mod]->name);
 			STRFREE(obj3->short_descr);
 			obj3->short_descr = STRALLOC( aoran(buf1) );
 	
 			sprintf(buf2, "A flask labelled '%s' contains a strange, mixed liquid.", skill_table[mod]->name);
 			STRFREE(obj3->description);
 			obj3->description = STRALLOC(buf2);
 	
 			sprintf(buf3, "flask potion %s", skill_table[mod]->name);
 			STRFREE(obj3->name);
 			obj3->name = STRALLOC(buf3);
 		}
 		else
 		{
 			send_to_char("You are trying to mix a non-permanent and a permanent reagant. BAD PLAYER, BAD!!\n\r",ch);
 			return;
 		}
 	}
 	else
 	{
 		if(perm==FALSE)
 		{
 		        send_to_char("You are trying to mix a non-permanent and a permanent reagant. BAD PLAYER, BAD!!\n\r",ch);
 			return;
 		}
 		send_to_char("You failed.\n\r",ch);
 	}
 	/* remove the reagants from inventory */
 	separate_obj(obj2);
 	extract_obj(obj2);
 	separate_obj(obj);
 	extract_obj(obj);
 	return;
 
 }
 void do_enhance(CHAR_DATA *ch, char *argument)
 {
 	char		arg[MIL];
 	char		arg2[MIL];
 	char		arg3[MIL];
 	OBJ_DATA	*obj;
 	OBJ_DATA	*obj2;
 	OBJ_DATA  	*obj3;
 	AFFECT_DATA	*paf;
 	argument = one_argument(argument,arg);
 	argument = one_argument(argument,arg2);
 	argument = one_argument(argument,arg3);
 	
 	if (IS_NPC(ch))
 	{
 	   send_to_char("Not for NPCs.\n\r", ch);
 	   return;
 	}
 		
 	if((obj = get_obj_carry(ch,arg)) == NULL)
 	{
 		send_to_char("Usage: modweapon <enhancer> <weapon> <mortar>\n\r",ch);
 		return;
 	}
 	if((obj2 = get_obj_carry(ch,arg2)) == NULL)
 	{
 		send_to_char("Usage: modweapon <enhancer> <weapon> <mortar> \n\r",ch);
 		return;
 	}
 	if((obj3 = get_obj_carry(ch,arg3)) == NULL)
 	{
 		send_to_char("Usage: modweapon <enhancer> <weapon> <mortar> \n\r",ch);
 			return;
 	}
 		
 	if(!xIS_SET(obj->extra_flags,ITEM_MIXED))
 	{
 		send_to_char("That is not potion with weapon enhancing power\n\r",ch);
 		return;
 	}
 	if(xIS_SET(obj2->extra_flags,ITEM_MAGIC))
 	{
 		send_to_char("This item is magical and cannot be enhanced.\n\r",ch);
 		return;
 	}
 	if(!xIS_SET(obj3->extra_flags,ITEM_MORTAR))
 	{
 		send_to_char("Usage: modweapon <enhancer> <weapon> <mortar> \n\r",ch);
 		return;
 	}
 	/* Add the appropriate affects */
 	if(get_alch_success(ch,obj3) < number_range(1,100))
 	{
 		
 		CREATE(paf, AFFECT_DATA, 1);
 		paf->type = -1;
 		paf->duration = -1;
 		if(obj->value[0] == 0 || obj->value[0] > 18) // If number is out of range, default to wearspell
 		{	
 			paf->location = APPLY_WEARSPELL;
 		}	
 		else
 		{
 			paf->location = obj->value[0];
 		}
 		paf->modifier = obj->value[1];
 		LINK(paf, obj2->first_affect, obj2->last_affect, next, prev);
 		send_to_char("You have enhanced your weapon.\n\r", ch);
 		xTOGGLE_BIT(obj2->extra_flags,ITEM_MAGIC);
 	}
 	else
 	{
 		send_to_char("You failed.\n\r",ch);
 	}
 	separate_obj(obj);		//remove items
 	extract_obj(obj);
 	return;
}