sunder2.1/clan/
sunder2.1/class/
sunder2.1/class/bak/
sunder2.1/doc/ideas/
sunder2.1/gods/
sunder2.1/log/
sunder2.1/msgbase/
sunder2.1/src/o/
sunder2.1/time/
/**************************************************************************r
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/
/**********************************************************
 *************** S U N D E R M U D *** 2 . 0 **************
 **********************************************************
 * The unique portions of the SunderMud code as well as   *
 * the integration efforts for code from other sources is *
 * based primarily on the efforts of:                     *
 *                                                        *
 * Lotherius <aelfwyne@operamail.com> (Alvin W. Brinson)  *
 *    and many others, see "help sundermud" in the mud.   *
 **********************************************************/

/* Have removed several unused functions from this file */

#include "everything.h"



/* command procedures needed */
DECLARE_DO_FUN ( do_return );

AFFECT_DATA        *affect_free;

/*
 * Local functions.
 */
void affect_modify args ( ( CHAR_DATA * ch, AFFECT_DATA * paf, bool fAdd ) );

/* Counts Users on an Object. */
int count_users ( OBJ_DATA * obj )
{
     CHAR_DATA          *fch;
     int                 count = 0;

     if ( obj->in_room == NULL )
          return 0;

     for ( fch = obj->in_room->people; fch != NULL;
           fch = fch->next_in_room )
          if ( fch->on == obj )
               count++;

     return count;
}

/* returns material number */
int material_lookup ( const char *name )
{
     int                 counter;
     for ( counter = 0; counter <= MAX_MATERIAL; counter++ )
     {
          if ( !str_cmp ( material_table[counter].name, name ) )
               return material_table[counter].type;
     }
     return 0;
}

/* returns material name -- ROM OLC temp patch -- doesn't look very temp to me */
char *material_name ( sh_int num )
{
     int                 counter;
     for ( counter = 0; counter <= MAX_MATERIAL; counter++ )
     {
          if ( material_table[counter].type == num )
               return material_table[counter].name;
     }
     return "unknown";
}

/* returns material vulnerability flag */
long material_vuln ( sh_int num )
{
     int                 counter;
     for ( counter = 0; counter <= MAX_MATERIAL; counter++ )
     {
          if ( material_table[counter].type == num )
               return material_table[counter].vuln_flag;
     }
     return 0;
}

/* returns material durability flag */
long material_dura ( sh_int num )
{
     int                 counter;

     for ( counter = 0; counter <= MAX_MATERIAL; counter++ )
     {
          if ( material_table[counter].type == num )
               return material_table[counter].durable;
     }
     return 0;
}

/* returns material repair difficulty */
long material_repa ( sh_int num )
{
     int                 counter;

     for ( counter = 0; counter <= MAX_MATERIAL; counter++ )
     {
          if ( material_table[counter].type == num )
               return material_table[counter].difficult;
     }
     return 0;
}

/* Checks a flag from material flags. */
bool is_material ( sh_int num, long material_flag )
{
     int counter;
     for ( counter = 0; counter <= MAX_MATERIAL; counter++ )
     {
          if ( material_table[counter].type == num )
          {
               if IS_SET ( material_table[counter].flags, material_flag )
                    return TRUE;
               else
                    return FALSE;
          }
     }
     return FALSE;
}

/* returns race number */
int race_lookup ( const char *name )
{
     int                 race;

     for ( race = 0; race_table[race].name != NULL; race++ )
     {
          if ( LOWER ( name[0] ) == LOWER ( race_table[race].name[0] ) &&
               !str_prefix ( name, race_table[race].name ) )
               return race;
     }
     return 0;
}

/* returns race number for race's PCDATA */
int pcrace_lookup ( const char *name )
{
     int	pcrace;

     for ( pcrace = 0; pcrace < MAX_PCRACE; pcrace++ )
     {
          if ( LOWER ( name[0] ) == LOWER ( pc_race_table[pcrace].name[0] ) && !str_prefix ( name, pc_race_table[pcrace].name ) )
               return pcrace;
     }

     return 0;
}

/* returns class number */
int class_lookup ( const char *name )
{
     int                 class;

     for ( class = 0; class < MAX_CLASS; class++ )
     {
          if ( LOWER ( name[0] ) ==
               LOWER ( class_table[class].name[0] ) &&
               !str_prefix ( name, class_table[class].name ) )
               return class;
     }

     return -1;
}

/* for immunity, vulnerabiltiy, and resistant
   the 'globals' (magic and weapons) may be overriden
   three other cases -- wood, silver, and iron -- are checked in fight.c */

int check_immune ( CHAR_DATA * ch, int dam_type )
{
     int                 immune;
     int                 bit;

     immune = IS_NORMAL;

     if ( dam_type == DAM_NONE )
          return immune;

     if ( dam_type <= 3 )
     {
          if ( IS_SET ( ch->imm_flags, IMM_WEAPON ) )
               immune = IS_IMMUNE;
          else if ( IS_SET ( ch->res_flags, RES_WEAPON ) )
               immune = IS_RESISTANT;
          else if ( IS_SET ( ch->vuln_flags, VULN_WEAPON ) )
               immune = IS_VULNERABLE;
     }
     else			/* magical attack */
     {
          if ( IS_SET ( ch->imm_flags, IMM_MAGIC ) )
               immune = IS_IMMUNE;
          else if ( IS_SET ( ch->res_flags, RES_MAGIC ) )
               immune = IS_RESISTANT;
          else if ( IS_SET ( ch->vuln_flags, VULN_MAGIC ) )
               immune = IS_VULNERABLE;
     }

     /* set bits to check -- VULN etc. must ALL be the same or this will fail */
     switch ( dam_type )
     {
     case ( DAM_BASH ):
          bit = IMM_BASH;
          break;
     case ( DAM_PIERCE ):
          bit = IMM_PIERCE;
          break;
     case ( DAM_SLASH ):
          bit = IMM_SLASH;
          break;
     case ( DAM_FIRE ):
          bit = IMM_FIRE;
          break;
     case ( DAM_COLD ):
          bit = IMM_COLD;
          break;
     case ( DAM_LIGHTNING ):
          bit = IMM_LIGHTNING;
          break;
     case ( DAM_ACID ):
          bit = IMM_ACID;
          break;
     case ( DAM_POISON ):
          bit = IMM_POISON;
          break;
     case ( DAM_NEGATIVE ):
          bit = IMM_NEGATIVE;
          break;
     case ( DAM_HOLY ):
          bit = IMM_HOLY;
          break;
     case ( DAM_ENERGY ):
          bit = IMM_ENERGY;
          break;
     case ( DAM_MENTAL ):
          bit = IMM_MENTAL;
          break;
     case ( DAM_DISEASE ):
          bit = IMM_DISEASE;
          break;
     case ( DAM_DROWNING ):
          bit = IMM_DROWNING;
          break;
     case ( DAM_LIGHT ):
          bit = IMM_LIGHT;
          break;
     default:
          return immune;
     }

     if ( IS_SET ( ch->imm_flags, bit ) )
          immune = IS_IMMUNE;
     else if ( IS_SET ( ch->res_flags, bit ) )
          immune = IS_RESISTANT;
     else if ( IS_SET ( ch->vuln_flags, bit ) )
          immune = IS_VULNERABLE;

     return immune;
}

/*
 * See if a string is one of the names of an object.
 */

bool is_full_name ( const char *str, char *namelist )
{
     char                name[MAX_INPUT_LENGTH];

     for ( ;; )
     {
          namelist = one_argument ( namelist, name );
          if ( name[0] == '\0' )
               return FALSE;
          if ( !str_cmp ( str, name ) )
               return TRUE;
     }
}

/* for returning skill information */
int get_skill ( CHAR_DATA * ch, int sn )
{
     int                 skill;

     if ( sn == -1 )		/* shorthand for level based skills */
     {
          skill = ch->level * 5 / 2;
     }

     else if ( sn < -1 || sn > MAX_SKILL )
     {
          bugf ( "Bad sn %d in get_skill.", sn );
          skill = 0;
     }

     else if ( !IS_NPC ( ch ) )
     {
          if ( ch->level < skill_table[sn].skill_level[ch->pcdata->pclass] )
               skill = 0;
          else
               skill = ch->pcdata->learned[sn];
     }

     else			/* mobiles */
     {
          int pclass, sclass, slev;

          if (IS_SET(ch->act, ACT_CLERIC) )
          {
               pclass = CLASS_AVENGER;
               sclass = CLASS_DEFILER;
          }
          else if (IS_SET(ch->act, ACT_MAGE) )
          {
               pclass = CLASS_MAGE;
               sclass = CLASS_CHAOSMAGE;
          }
          else if (IS_SET(ch->act, ACT_THIEF) )
          {
               pclass = CLASS_THIEF;
               sclass = CLASS_THIEF;
          }
          else
          {
               pclass = CLASS_WARRIOR;
               sclass = CLASS_MONK;
          }

		/* Take the average of the 2 classes */

          slev = (skill_table[sn].skill_level[pclass] + skill_table[sn].skill_level[sclass]) /2;

          if (ch->level < slev )
               skill = 0;
          else
               skill = 35 + ch->level - slev;

     }

     if ( IS_AFFECTED ( ch, AFF_BERSERK ) )
          skill -= ch->level / 2;

     return URANGE ( 0, skill, 100 );
}

/* for returning weapon information */
int get_weapon_sn ( CHAR_DATA * ch, bool dual )
{
     OBJ_DATA           *wield;
     int                 sn;

     if ( !dual )
          wield = get_eq_char ( ch, WEAR_WIELD );
     else
          wield = get_eq_char ( ch, WEAR_WIELD2 );

     if ( wield == NULL || wield->item_type != ITEM_WEAPON )
          sn = gsn_hand_to_hand;
     else
          switch ( wield->value[0] )
          {
          default:
               sn = -1;
               break;
          case ( WEAPON_SWORD ):
               sn = gsn_sword;
               break;
          case ( WEAPON_DAGGER ):
               sn = gsn_dagger;
               break;
          case ( WEAPON_SPEAR ):
               sn = gsn_spear;
               break;
          case ( WEAPON_MACE ):
               sn = gsn_mace;
               break;
          case ( WEAPON_AXE ):
               sn = gsn_axe;
               break;
          case ( WEAPON_FLAIL ):
               sn = gsn_flail;
               break;
          case ( WEAPON_WHIP ):
               sn = gsn_whip;
               break;
          case ( WEAPON_POLEARM ):
               sn = gsn_polearm;
               break;
          }
     return sn;
}

int get_weapon_skill ( CHAR_DATA * ch, int sn )
{
     int                 skill;

    /* -1 is exotic */
     if ( IS_NPC ( ch ) )
     {
          if ( sn == -1 )
               skill = 3 * ch->level;
          else if ( sn == gsn_hand_to_hand )
               skill = 40 + 2 * ch->level;
          else
          {
               int pclass, sclass, slev;

               if (IS_SET(ch->act, ACT_CLERIC) )
               {
                    pclass = CLASS_AVENGER;
                    sclass = CLASS_DEFILER;
               }
               else if (IS_SET(ch->act, ACT_MAGE) )
               {
                    pclass = CLASS_MAGE;
                    sclass = CLASS_CHAOSMAGE;
               }
               else if (IS_SET(ch->act, ACT_THIEF) )
               {
                    pclass = CLASS_THIEF;
                    sclass = CLASS_THIEF;
               }
               else
               {
                    pclass = CLASS_WARRIOR;
                    sclass = CLASS_MONK;
               }

                /* Take the average of the 2 classes */

               slev = (skill_table[sn].skill_level[pclass] + skill_table[sn].skill_level[sclass]) /2;

/* Hack to avoid bad area design. All mobs given 40% in their weapon skills */
/* This is due to mobs that have weapons they shouldn't, so they don't miss continuously */

               if (ch->level >= slev )
                    skill = 40 + ch->level - slev;
               else
                    skill = 40;
          }

     }
     else
     {
          if ( sn == -1 )
               skill = 3 * ch->level;

          else
               skill = ch->pcdata->learned[sn];
     }

     return URANGE ( 0, skill, 100 );
}

/* used to de-screw characters */
/* Nice way of putting it.     */
void reset_char ( CHAR_DATA * ch )
{
     int                 loc, mod, stat;
     OBJ_DATA           *obj;
     AFFECT_DATA        *af;

     if ( IS_NPC ( ch ) )
          return;

     if ( ch->pcdata->perm_hit == 0
          || ch->pcdata->perm_mana == 0
          || ch->pcdata->perm_move == 0
          || ch->pcdata->last_level == 0 )
     {
	/* do a FULL reset */
          for ( loc = 0; loc < MAX_WEAR; loc++ )
          {
               obj = get_eq_char ( ch, loc );
               if ( obj == NULL )
                    continue;
               if ( !obj->enchanted )
                    for ( af = obj->pIndexData->affected; af != NULL;
                          af = af->next )
                    {
                         mod = af->modifier;
                         switch ( af->location )
                         {
                         case APPLY_SEX:
                              ch->sex -= mod;
                              if ( ch->sex < 0 || ch->sex > 2 )
                                   ch->sex = IS_NPC ( ch ) ?
                                   0 : ch->pcdata->true_sex;
                              break;
                         case APPLY_MANA:
                              ch->max_mana -= mod;
                              break;
                         case APPLY_HIT:
                              ch->max_hit -= mod;
                              break;
                         case APPLY_MOVE:
                              ch->max_move -= mod;
                              break;
                         }
                    }

               for ( af = obj->affected; af != NULL; af = af->next )
               {
                    mod = af->modifier;
                    switch ( af->location )
                    {
                    case APPLY_SEX:
                         ch->sex -= mod;
                         break;
                    case APPLY_MANA:
                         ch->max_mana -= mod;
                         break;
                    case APPLY_HIT:
                         ch->max_hit -= mod;
                         break;
                    case APPLY_MOVE:
                         ch->max_move -= mod;
                         break;
                    }
               }
          }
	/* now reset the permanent stats */
          ch->pcdata->perm_hit = ch->max_hit;
          ch->pcdata->perm_mana = ch->max_mana;
          ch->pcdata->perm_move = ch->max_move;
          ch->pcdata->last_level = ch->played / 3600;
          if ( ch->pcdata->true_sex < 0 || ch->pcdata->true_sex > 2 )
          {
               if ( ch->sex > 0 && ch->sex < 3 )
                    ch->pcdata->true_sex = ch->sex;
               else
                    ch->pcdata->true_sex = 0;
          }

     }

    /* now restore the character to his/her true condition */
     for ( stat = 0; stat < MAX_STATS; stat++ )
          ch->mod_stat[stat] = 0;

     if ( ch->pcdata->true_sex < 0 || ch->pcdata->true_sex > 2 )
          ch->pcdata->true_sex = 0;
     ch->sex = ch->pcdata->true_sex;
     ch->max_hit = ch->pcdata->perm_hit;
     ch->max_mana = ch->pcdata->perm_mana;
     ch->max_move = ch->pcdata->perm_move;

     //     for ( i = 0; i < 4; i++ )
     ch->armor = 0;

     ch->hitroll = 0;
     ch->damroll = 0;
     ch->saving_throw = 0;

    /* now start adding back the effects */
     for ( loc = 0; loc < MAX_WEAR; loc++ )
     {
          obj = get_eq_char ( ch, loc );
          if ( obj == NULL )
               continue;

          if ( !obj->enchanted )
               for ( af = obj->pIndexData->affected; af != NULL;
                     af = af->next )
               {
                    mod = af->modifier;
                    switch ( af->location )
                    {
                    case APPLY_STR:
                         ch->mod_stat[STAT_STR] += mod;
                         break;
                    case APPLY_DEX:
                         ch->mod_stat[STAT_DEX] += mod;
                         break;
                    case APPLY_INT:
                         ch->mod_stat[STAT_INT] += mod;
                         break;
                    case APPLY_WIS:
                         ch->mod_stat[STAT_WIS] += mod;
                         break;
                    case APPLY_CON:
                         ch->mod_stat[STAT_CON] += mod;
                         break;
                    case APPLY_SEX:
                         ch->sex += mod;
                         break;
                    case APPLY_MANA:
                         ch->max_mana += mod;
                         break;
                    case APPLY_HIT:
                         ch->max_hit += mod;
                         break;
                    case APPLY_MOVE:
                         ch->max_move += mod;
                         break;
                    case APPLY_AC:	// Magical AC
                         ch->armor += mod;
                         break;
                    case APPLY_HITROLL:
                         ch->hitroll += mod;
                         break;
                    case APPLY_DAMROLL:
                         ch->damroll += mod;
                         break;
                    case APPLY_SAVING_PARA:
                         ch->saving_throw += mod;
                         break;
                    case APPLY_SAVING_ROD:
                         ch->saving_throw += mod;
                         break;
                    case APPLY_SAVING_PETRI:
                         ch->saving_throw += mod;
                         break;
                    case APPLY_SAVING_BREATH:
                         ch->saving_throw += mod;
                         break;
                    case APPLY_SAVING_SPELL:
                         ch->saving_throw += mod;
                         break;
                    case APPLY_ENCUMBRANCE:
                         ch->encumbrance += mod;
                         break;
                    }
               }

          for ( af = obj->affected; af != NULL; af = af->next )
          {
               mod = af->modifier;
               switch ( af->location )
               {
               case APPLY_STR:
                    ch->mod_stat[STAT_STR] += mod;
                    break;
               case APPLY_DEX:
                    ch->mod_stat[STAT_DEX] += mod;
                    break;
               case APPLY_INT:
                    ch->mod_stat[STAT_INT] += mod;
                    break;
               case APPLY_WIS:
                    ch->mod_stat[STAT_WIS] += mod;
                    break;
               case APPLY_CON:
                    ch->mod_stat[STAT_CON] += mod;
                    break;
               case APPLY_SEX:
                    ch->sex += mod;
                    break;
               case APPLY_MANA:
                    ch->max_mana += mod;
                    break;
               case APPLY_HIT:
                    ch->max_hit += mod;
                    break;
               case APPLY_MOVE:
                    ch->max_move += mod;
                    break;
               case APPLY_AC:	// Magical AC
                    ch->armor += mod;
                    break;
               case APPLY_HITROLL:
                    ch->hitroll += mod;
                    break;
               case APPLY_DAMROLL:
                    ch->damroll += mod;
                    break;
               case APPLY_SAVING_PARA:
                    ch->saving_throw += mod;
                    break;
               case APPLY_SAVING_ROD:
                    ch->saving_throw += mod;
                    break;
               case APPLY_SAVING_PETRI:
                    ch->saving_throw += mod;
                    break;
               case APPLY_SAVING_BREATH:
                    ch->saving_throw += mod;
                    break;
               case APPLY_SAVING_SPELL:
                    ch->saving_throw += mod;
                    break;
               case APPLY_ENCUMBRANCE:
                    ch->saving_throw += mod;
                    break;
               }
          }
     }

    /* now add back spell effects */
     for ( af = ch->affected; af != NULL; af = af->next )
     {
          mod = af->modifier;
          switch ( af->location )
          {
          case APPLY_STR:
               ch->mod_stat[STAT_STR] += mod;
               break;
          case APPLY_DEX:
               ch->mod_stat[STAT_DEX] += mod;
               break;
          case APPLY_INT:
               ch->mod_stat[STAT_INT] += mod;
               break;
          case APPLY_WIS:
               ch->mod_stat[STAT_WIS] += mod;
               break;
          case APPLY_CON:
               ch->mod_stat[STAT_CON] += mod;
               break;
          case APPLY_SEX:
               ch->sex += mod;
               break;
          case APPLY_MANA:
               ch->max_mana += mod;
               break;
          case APPLY_HIT:
               ch->max_hit += mod;
               break;
          case APPLY_MOVE:
               ch->max_move += mod;
               break;
          case APPLY_AC:	// Magical AC               
               ch->armor += mod;
               break;
          case APPLY_HITROLL:
               ch->hitroll += mod;
               break;
          case APPLY_DAMROLL:
               ch->damroll += mod;
               break;
          case APPLY_SAVING_PARA:
               ch->saving_throw += mod;
               break;
          case APPLY_SAVING_ROD:
               ch->saving_throw += mod;
               break;
          case APPLY_SAVING_PETRI:
               ch->saving_throw += mod;
               break;
          case APPLY_SAVING_BREATH:
               ch->saving_throw += mod;
               break;
          case APPLY_SAVING_SPELL:
               ch->saving_throw += mod;
               break;
          case APPLY_ENCUMBRANCE:
               ch->saving_throw += mod;
               break;
          }
     }

    /* make sure sex is RIGHT!!!! */
     if ( ch->sex < 0 || ch->sex > 2 )
          ch->sex = ch->pcdata->true_sex;
}

/*
 * Retrieve a character's trusted level for permission checking.
 */
int get_trust ( CHAR_DATA * ch )
{
     if ( ch->desc != NULL && ch->desc->original != NULL )
          ch = ch->desc->original;

     if ( ch->trust != 0 )
          return ch->trust;

     /* Okay good, the following prevents an NPC from being able to
      * be ordered to do IMM commands...
      */
     if ( IS_NPC ( ch ) && ch->level >= LEVEL_HERO )
          return LEVEL_HERO - 1;
     else
          return ch->level;
}

/*
 * Retrieve a character's age.
 */
int get_age ( CHAR_DATA * ch )
{
     int                 age;

     if ( IS_NPC ( ch ) )
     {
          return 20; /* Well yeah, we'll assume they're all young punks */
     }

	 /* Start with 1 under base, then will add 1 if have had bday */

	 /* First year will automatically be base, since will have had bday */

     age = ( pc_race_table[ch->pcdata->pcrace].startage - 1 ) + ( time_info.year - ch->pcdata->startyear );

	 /*  check for a modifier */

     age -= ch->pcdata->age_mod;

	 /* check for birthdate yet this year */

     if ( ( time_info.month >= ch->pcdata->startmonth ) &&
          ( time_info.day >= ch->pcdata->startday ) )
     {
          age += 1;
     }

     return age;

}

/* command for retrieving stats */
int get_curr_stat ( CHAR_DATA * ch, int stat )
{
     int                 max;

     if ( IS_NPC ( ch ) || ch->level > LEVEL_IMMORTAL )
          max = 25;

     else
     {
          max = pc_race_table[ch->pcdata->pcrace].max_stats[stat] + 4;

          if ( class_table[ch->pcdata->pclass].attr_prime == stat )
               max += 2;

          if ( ch->pcdata->pcrace == pcrace_lookup ( "human" ) )
               max += 1;

          max = UMIN ( max, 25 );
     }

     return URANGE ( 3, ch->perm_stat[stat] + ch->mod_stat[stat], max );
}

/*
 * Retrieve a character's carry capacity.
 */
int can_carry_n ( CHAR_DATA * ch )
{
     if ( !IS_NPC ( ch ) && ch->level >= LEVEL_IMMORTAL )
          return 1000;

     if ( IS_NPC ( ch ) && IS_SET ( ch->act, ACT_PET ) )
          return 0;

/* followers can carry, pets can't */

     return MAX_WEAR + 2 * get_curr_stat ( ch, STAT_DEX ) + ch->level;
}

/*
 * Retrieve a character's carry capacity.
 */
int can_carry_w ( CHAR_DATA * ch )
{
     if ( !IS_NPC ( ch ) && ch->level >= LEVEL_IMMORTAL )
          return 1000000;

     if ( IS_NPC ( ch ) && IS_SET ( ch->act, ACT_PET ) )
          return 0;

     return str_app[get_curr_stat ( ch, STAT_STR )].carry +
          ch->level * 5 / 2;
}

/*
 * See if a string is one of the names of an object.
 */

bool is_name ( char *str, char *namelist )
{
     char                name[MAX_INPUT_LENGTH], part[MAX_INPUT_LENGTH];
     char               *list, *string;

     string = str;
	 /* we need ALL parts of string to match part of namelist */
     for ( ;; )			/* start parsing string */
     {
          str = one_argument ( str, part );

          if ( part[0] == '\0' )
               return TRUE;

		  /* check to see if this is part of namelist */
          list = namelist;
          for ( ;; )		/* start parsing namelist */
          {
               list = one_argument ( list, name );
               if ( name[0] == '\0' )	/* this name was not found */
                    return FALSE;

               if ( !str_cmp ( string, name ) )
                    return TRUE;	/* full pattern match */

               if ( !str_cmp ( part, name ) )
                    break;
          }
     }
}

bool is_name_abbv ( char *str, char *namelist )	/*Zeran, abbrev is_name */
{
     char                name[MAX_INPUT_LENGTH];
     char               *list, *string;

     if ( strstr ( namelist, str ) == namelist )	/* got partial match already */
          return TRUE;
     string = str;
    /* check to see if this is part of namelist */
     list = namelist;
     for ( ;; )			/* start parsing namelist */
     {
          list = one_argument ( list, name );
          if ( name[0] == '\0' )	/* this name was not found */
               return FALSE;

          if ( strstr ( name, string ) == name )	/*Zeran: hack for abbreviations */
               return TRUE;	/*abbreviated string, return a match */

     }
}

/*
 * Set some values on an affect
 * NOTICE: This function does no error checking. Be careful calling it.
 * All values must be specified, if you set NULL, then it will set NULL,
 * overwriting what was there before.
 */
void set_affect ( AFFECT_DATA *paf, sh_int type, sh_int level, sh_int duration,
                  sh_int location, sh_int modifier, sh_int where,
                  int bitvector, char *caster )
{
     paf->type = type;
     paf->level = level;
     paf->duration = duration;
     paf->location = location;
     paf->modifier = modifier;
     paf->where = where;
     paf->bitvector = bitvector;
}

/*
 * Apply or remove an affect to a character.
 *
 */

void affect_modify ( CHAR_DATA * ch, AFFECT_DATA * paf, bool fAdd )
{
     OBJ_DATA           *wield;
     OBJ_DATA           *objtmp;
     int		mod;
     bool                duplicate = FALSE;
     AFFECT_DATA        *tmp;

     mod = paf->modifier;

     if ( fAdd )
     {
          switch ( paf->where)
          {
          case TO_AFFECTS:
               SET_BIT (ch->affected_by, paf->bitvector);
               break;
          case TO_DETECTIONS:
               SET_BIT (ch->detections, paf->bitvector );
               break;
          case TO_PROTECTIONS:
               SET_BIT (ch->protections, paf->bitvector );
               break;
          }
     }

     else if ( paf->bitvector )	/* Zeran - can skip if bitvector is 0 */
     {
	/* check spells that were cast */

          for ( tmp = ch->affected; tmp != NULL; tmp = tmp->next )
          {
               if ( ( tmp != paf ) && ( tmp->bitvector ==  paf->bitvector ) && ( tmp->where == paf->where ) )
               {
                    duplicate = TRUE;
                    break;
               }
          }

	/* check against other worn objects if no duplicate found yet */
          if ( !duplicate )
               for ( objtmp = ch->carrying; objtmp != NULL; objtmp = objtmp->next_content )
               {
                    if ( objtmp->wear_loc != WEAR_NONE )	/*worn, check affects */
                    {
                         for ( tmp = objtmp->affected; tmp != NULL;  tmp = tmp->next )
                         {
                              if ( ( tmp != paf ) && ( tmp->bitvector == paf->bitvector ) && ( tmp->where == paf->where ) )
                                   duplicate = TRUE;
                              break;
                         }
                         for ( tmp = objtmp->pIndexData->affected;
                               tmp != NULL; tmp = tmp->next )
                         {
                              if ( ( tmp != paf ) && ( tmp->bitvector == paf->bitvector ) && ( tmp->where == paf->where ) )
                                   duplicate = TRUE;
                              break;
                         }
                    }
                    if ( duplicate )
                         break;
               }

          if ( !duplicate )
          {
               switch ( paf->where)
               {
               case TO_AFFECTS:
                    REMOVE_BIT (ch->affected_by, paf->bitvector);
		    ch->affected_by = ch->affected_by | race_table[ch->race].aff;
		    break;
               case TO_DETECTIONS:
                    REMOVE_BIT (ch->detections, paf->bitvector );
		    ch->detections = ch->detections | race_table[ch->race].detect;
		    break;
               case TO_PROTECTIONS:
                    REMOVE_BIT (ch->protections, paf->bitvector );
                    ch->detections = ch->detections | race_table[ch->race].protect;
		    break;
               }
          }
     }
     if ( !fAdd )
          mod = 0 - mod;
     switch ( paf->location )
     {
     default:
          bugf ( "Affect_modify: unknown location %d.", paf->location );
          return;

     case APPLY_NONE:							break;
     case APPLY_STR:		ch->mod_stat[STAT_STR] += mod;		break;
     case APPLY_DEX:		ch->mod_stat[STAT_DEX] += mod;		break;
     case APPLY_INT:		ch->mod_stat[STAT_INT] += mod;		break;
     case APPLY_WIS:		ch->mod_stat[STAT_WIS] += mod;		break;
     case APPLY_CON:		ch->mod_stat[STAT_CON] += mod;		break;
     case APPLY_SEX:		ch->sex += mod;				break;
     case APPLY_CLASS:							break;
     case APPLY_LEVEL:							break;
     case APPLY_AGE:							break;
     case APPLY_HEIGHT:							break;
     case APPLY_WEIGHT:							break;
     case APPLY_MANA:		ch->max_mana += mod;			break;
     case APPLY_HIT:		ch->max_hit += mod;			break;
     case APPLY_MOVE:		ch->max_move += mod;			break;
     case APPLY_GOLD:							break;
     case APPLY_EXP:							break;
     case APPLY_AC:             ch->armor += mod;                       break;
     case APPLY_HITROLL:	ch->hitroll += mod;			break;
     case APPLY_DAMROLL:	ch->damroll += mod;			break;
     case APPLY_SAVING_PARA:	ch->saving_throw += mod;		break;
     case APPLY_SAVING_ROD:	ch->saving_throw += mod;		break;
     case APPLY_SAVING_PETRI:	ch->saving_throw += mod;		break;
     case APPLY_SAVING_BREATH:	ch->saving_throw += mod;		break;
     case APPLY_SAVING_SPELL:	ch->saving_throw += mod;		break;
     case APPLY_ENCUMBRANCE:	ch->encumbrance += mod;			break;
     }

    /*
     * Check for weapon wielding.
     * Guard against recursion (for weapons with affects).
     */

     if ( !IS_NPC ( ch ) &&
          ( wield = get_eq_char ( ch, WEAR_WIELD ) ) != NULL &&
          get_obj_weight ( wield ) >
          str_app[get_curr_stat ( ch, STAT_STR )].wield )
     {
          static int          depth;

          if ( depth == 0 )
          {
               depth++;
               act ( "You drop $p.", ch, wield, NULL, TO_CHAR );
               act ( "$n drops $p.", ch, wield, NULL, TO_ROOM );
               obj_from_char ( wield );
               obj_to_room ( wield, ch->in_room );
               depth--;
          }
     }

    /* now check the dual wield weapon */
     if ( !IS_NPC ( ch ) &&
          ( wield = get_eq_char ( ch, WEAR_WIELD2 ) ) != NULL &&
          get_obj_weight ( wield ) >
          str_app[get_curr_stat ( ch, STAT_STR )].wield )
     {
          static int          depth2;

          if ( depth2 == 0 )
          {
               depth2++;
               act ( "You drop $p.", ch, wield, NULL, TO_CHAR );
               act ( "$n drops $p.", ch, wield, NULL, TO_ROOM );
               obj_from_char ( wield );
               obj_to_room ( wield, ch->in_room );
               depth2--;
          }
     }

     return;
}

/*
 * Give an affect to a char.
 */

void affect_to_char ( CHAR_DATA * ch, AFFECT_DATA * paf )
{
     AFFECT_DATA        *paf_new;

     if ( affect_free == NULL )
     {
          paf_new = alloc_perm ( sizeof ( *paf_new ), "paf_new:aff_to_ch" );
     }
     else
     {
          paf_new = affect_free;
          affect_free = affect_free->next;
     }

     *paf_new = *paf;

     paf_new->next = ch->affected;
     ch->affected = paf_new;
     affect_modify ( ch, paf_new, TRUE );

     return;
}

/* give an affect to an object */
void affect_to_obj ( OBJ_DATA * obj, AFFECT_DATA * paf )
{
     AFFECT_DATA        *paf_new;

     if ( affect_free == NULL )
     {
          paf_new = alloc_perm ( sizeof ( *paf_new ), "paf_new:aff_to_obj" );
     }
     else
     {
          paf_new = affect_free;
          affect_free = affect_free->next;
     }

     *paf_new = *paf;
     paf_new->next = obj->affected;
     obj->affected = paf_new;

     return;
}

/*
 * affect_to_room ??
 * What were ya thinkin' Z?
 * Neat idea though, so I'll leave it here, just commented since it is unused
 * and there's no code to support it -- Lotherius
 */

//void affect_to_room ( ROOM_INDEX_DATA * room, AFFECT_DATA * paf )
//{
//    AFFECT_DATA        *paf_new;
//
//    if ( affect_free == NULL )
//    {
//	paf_new = alloc_perm ( sizeof ( *paf_new ), "paf_new:aff_to_room" );
//    } else
//    {
//	paf_new = affect_free;
//	affect_free = affect_free->next;
//    }
//
//    *paf_new = *paf;
//    paf_new->next = room->affected;
//
//    room->affected = paf_new;
//
//    return;
//}

//void affect_remove_room ( ROOM_INDEX_DATA * room, AFFECT_DATA * paf )
//{
//    if ( room->affected == NULL )
//    {
//	bugf ( "Affect_remove_room: no affect." );
//	return;
//    }
//
//    if ( paf == room->affected )
//    {
//	room->affected = paf->next;
//    } else
//    {
//	AFFECT_DATA        *prev;
//
//	for ( prev = room->affected; prev != NULL;
//	      prev = prev->next )
//	{
//	    if ( prev->next == paf )
//	    {
//		prev->next = paf->next;
//		break;
//	    }
//	}
//
//	if ( prev == NULL )
//	{
//	    bugf ( "Affect_remove_room: cannot find paf." );
//	    return;
//	}
//    }
//
//    paf->next = affect_free;
//    affect_free = paf;
//    return;
//}

/*
 * Remove an affect from a char.
 */

void affect_remove ( CHAR_DATA * ch, AFFECT_DATA * paf )
{
     if ( ch->affected == NULL )
     {
          bugf ( "Affect_remove: no affect." );
          return;
     }

     affect_modify ( ch, paf, FALSE );

     if ( paf == ch->affected )
     {
          ch->affected = paf->next;
     }
     else
     {
          AFFECT_DATA        *prev;

          for ( prev = ch->affected; prev != NULL;
                prev = prev->next )
          {
               if ( prev->next == paf )
               {
                    prev->next = paf->next;
                    break;
               }
          }

          if ( prev == NULL )
          {
               bugf ( "Affect_remove: cannot find paf." );
               return;
          }
     }

     paf->next = affect_free;
     affect_free = paf;
     return;
}

void affect_remove_obj ( OBJ_DATA * obj, AFFECT_DATA * paf )
{
     if ( obj->affected == NULL )
     {
          bugf ( "Affect_remove_object: no affect." );
          return;
     }

     if ( obj->carried_by != NULL && obj->wear_loc != -1 )
          affect_modify ( obj->carried_by, paf, FALSE );

     if ( paf == obj->affected )
     {
          obj->affected = paf->next;
     }
     else
     {
          AFFECT_DATA        *prev;

          for ( prev = obj->affected; prev != NULL;
                prev = prev->next )
          {
               if ( prev->next == paf )
               {
                    prev->next = paf->next;
                    break;
               }
          }

          if ( prev == NULL )
          {
               bugf ( "Affect_remove_object: cannot find paf." );
               return;
          }
     }

     paf->next = affect_free;
     affect_free = paf;
     return;
}

/*
 * Strip all affects of a given sn.
 */

void affect_strip ( CHAR_DATA * ch, int sn )
{
     AFFECT_DATA        *paf;
     AFFECT_DATA        *paf_next;

     for ( paf = ch->affected; paf != NULL; paf = paf_next )
     {
          paf_next = paf->next;
          if ( paf->type == sn )
               affect_remove ( ch, paf );
     }

     return;
}

/*
 * Return true if a char is affected by a spell.
 */
bool is_affected ( CHAR_DATA * ch, int sn )
{
     AFFECT_DATA        *paf;

     for ( paf = ch->affected; paf != NULL; paf = paf->next )
     {
          if ( paf->type == sn )
               return TRUE;
     }

     return FALSE;
}

/*
 * Add or enhance an affect.
 */
void affect_join ( CHAR_DATA * ch, AFFECT_DATA * paf )
{
     AFFECT_DATA        *paf_old;
     bool                found;

     found = FALSE;
     for ( paf_old = ch->affected; paf_old != NULL;
           paf_old = paf_old->next )
     {
          if ( paf_old->type == paf->type )
          {
               paf->level = ( paf->level += paf_old->level ) / 2;
               paf->duration += paf_old->duration;
               paf->modifier += paf_old->modifier;
               affect_remove ( ch, paf_old );
               break;
          }
     }

     affect_to_char ( ch, paf );
     return;
}

/*
 * Move a char out of a room.
 */
void char_from_room ( CHAR_DATA * ch )
{
     OBJ_DATA           *obj;

     if ( ch->in_room == NULL )
     {
          bugf ( "Char_from_room: NULL." );
          return;
     }

     if ( !IS_NPC ( ch ) )
          --ch->in_room->area->nplayer;

     if ( ( obj = get_eq_char ( ch, WEAR_LIGHT ) ) != NULL
          && obj->item_type == ITEM_LIGHT
          && obj->value[2] != 0 && ch->in_room->light > 0 )
          --ch->in_room->light;

     if ( ch == ch->in_room->people )
     {
          ch->in_room->people = ch->next_in_room;
     }
     else
     {
          CHAR_DATA          *prev;

          for ( prev = ch->in_room->people; prev;
                prev = prev->next_in_room )
          {
               if ( prev->next_in_room == ch )
               {
                    prev->next_in_room = ch->next_in_room;
                    break;
               }
          }

          if ( prev == NULL )
               bugf ( "Char_from_room: ch not found." );
     }

     ch->in_room = NULL;
     ch->next_in_room = NULL;
     return;
}

/*
 * Move a char into a room.
 */

void char_to_room ( CHAR_DATA * ch, ROOM_INDEX_DATA * pRoomIndex )
{
     OBJ_DATA           *obj;

     if ( pRoomIndex == NULL )
     {
          bugf ( "Char_to_room: NULL." );
          return;
     }

     ch->in_room = pRoomIndex;
     ch->next_in_room = pRoomIndex->people;
     pRoomIndex->people = ch;

     if ( !IS_NPC ( ch ) )
     {
          if ( ch->in_room->area->empty )
          {
               ch->in_room->area->empty = FALSE;
               ch->in_room->area->age = 0;
          }
          ++ch->in_room->area->nplayer;
     }

     if ( ( obj = get_eq_char ( ch, WEAR_LIGHT ) ) != NULL
          && obj->item_type == ITEM_LIGHT && obj->value[2] != 0 )
          ++ch->in_room->light;

    /*
     * startup some music
     * music only sends data if the soundfile has changed
     * Areas with no sound, set the sound to "None"
     */

     if ( !IS_NPC(ch) )
     {
          if ( ch->in_room->area->soundfile[0] != '\0' )
          {
               music ( ch->in_room->area->soundfile, ch, TRUE );
          }
          else
          {
               free_string (ch->pcdata->mplaying);
               ch->pcdata->mplaying = str_dup ( "None" );
               stop_music ( ch->desc );
          }
     }

     if ( IS_AFFECTED ( ch, AFF_PLAGUE ) )
     {
          AFFECT_DATA        *af, plague;
          CHAR_DATA          *vch;
          int                 save;

          for ( af = ch->affected; af != NULL; af = af->next )
          {
               if ( af->type == gsn_plague )
                    break;
          }

          if ( af == NULL )
          {
               REMOVE_BIT ( ch->affected_by, AFF_PLAGUE );
               return;
          }

          if ( af->level == 1 )
               return;

          plague.type = gsn_plague;
          plague.level = af->level - 1;
          plague.duration = number_range ( 1, 2 * plague.level );
          plague.location = APPLY_STR;
          plague.modifier = -5;
          plague.bitvector = AFF_PLAGUE;

          for ( vch = ch->in_room->people; vch != NULL;
                vch = vch->next_in_room )
          {
               switch ( check_immune ( vch, DAM_DISEASE ) )
               {
               case ( IS_NORMAL ):
                    save = af->level - 4;
                    break;
               case ( IS_IMMUNE ):
                    save = 0;
                    break;
               case ( IS_RESISTANT ):
                    save = af->level - 8;
                    break;
               case ( IS_VULNERABLE ):
                    save = af->level;
                    break;
               default:
                    save = af->level - 4;
                    break;
               }

               if ( save != 0 && !saves_spell ( save, vch ) &&
                    !IS_IMMORTAL ( vch ) &&
                    !IS_AFFECTED ( vch, AFF_PLAGUE ) &&
                    number_bits ( 6 ) == 0 )
               {
                    send_to_char ( "You feel hot and feverish.\n\r", vch );
                    act ( "$n shivers and looks very ill.", vch, NULL,
                          NULL, TO_ROOM );
                    affect_join ( vch, &plague );
               }
          }
     }

     return;
}

/*
 * Give an obj to a char.
 */
void obj_to_char ( OBJ_DATA * obj, CHAR_DATA * ch )
{
     obj->next_content = ch->carrying;
     ch->carrying = obj;
     obj->carried_by = ch;
     obj->in_room = NULL;
     obj->in_obj = NULL;
     ch->carry_number += get_obj_number ( obj );
     ch->carry_weight += get_obj_weight ( obj );
}

/*
 * Take an obj from its character.
 */
void obj_from_char ( OBJ_DATA * obj )
{
     CHAR_DATA          *ch;

     if ( ( ch = obj->carried_by ) == NULL )
     {
          bugf ( "Obj_from_char: null ch. Fatal, exiting to avoid possible infinite loop." );
          /* This error must be fatal to avoid a horrendous loop */
          /* If you're getting this error you MUST fix something. */
          exit (1);
     }

     if ( obj->wear_loc != WEAR_NONE )
          unequip_char ( ch, obj );

     if ( ch->carrying == obj )
     {
          ch->carrying = obj->next_content;
     }
     else
     {
          OBJ_DATA           *prev;

          for ( prev = ch->carrying; prev != NULL;
                prev = prev->next_content )
          {
               if ( prev->next_content == obj )
               {
                    prev->next_content = obj->next_content;
                    break;
               }
          }

          if ( prev == NULL )
               bugf ( "Obj_from_char: obj not in list." );
     }

     obj->carried_by = NULL;
     obj->next_content = NULL;
     ch->carry_number -= get_obj_number ( obj );
     ch->carry_weight -= get_obj_weight ( obj );
     return;
}

/*
 * Find a piece of eq on a character.
 */
OBJ_DATA           *get_eq_char ( CHAR_DATA * ch, int iWear )
{
     OBJ_DATA           *obj;

     if ( ch == NULL )
          return NULL;

     for ( obj = ch->carrying; obj != NULL;
           obj = obj->next_content )
     {
          if ( obj->wear_loc == iWear )
               return obj;
     }

     return NULL;
}

/*
 * Equip a char with an obj.
 * Changed to a boolean function so the caller can see if the item was able to be
 * equipped.
 */
bool equip_char ( CHAR_DATA * ch, OBJ_DATA * obj, int iWear )
{
     AFFECT_DATA        *paf;

     if ( get_eq_char ( ch, iWear ) != NULL )
     {
          if (!IS_NPC(ch))
               bugf ( "Equip_char: already equipped (%d : %d : %s).", iWear,
                      ch->in_room->vnum, ch->name );
          else
               bugf ( "Equip_char: already equipped (%d : %d : %d).",
                      iWear, ch->in_room->vnum, ch->pIndexData->vnum );
          return FALSE;
     }

     if ( ( IS_OBJ_STAT(obj, ITEM_ANTI_EVIL)    && IS_EVIL(ch) )
          ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_GOOD)    && IS_GOOD(ch) )
          ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch) ) )
     {
	/*
	 * Thanks to Morgenes for the bug fix here!
	 */
          act ( "You are zapped by $p and drop it.", ch, obj, NULL, TO_CHAR );
          act ( "$n is zapped by $p and drops it.", ch, obj, NULL, TO_ROOM );
          obj_from_char ( obj );
          obj_to_room ( obj, ch->in_room );
          return FALSE;
     }

     obj->wear_loc = iWear;

     if ( !obj->enchanted )
     {
          for ( paf = obj->pIndexData->affected; paf != NULL; paf = paf->next )
          {
               affect_modify ( ch, paf, TRUE );
          }
     }

     for ( paf = obj->affected; paf != NULL; paf = paf->next )
     {
          affect_modify ( ch, paf, TRUE );
     }

     if ( obj->item_type == ITEM_LIGHT
          && obj->value[2] != 0 && ch->in_room != NULL )
          ++ch->in_room->light;

     return TRUE;
}

/*
 * Unequip a char with an obj.
 */
bool unequip_char ( CHAR_DATA * ch, OBJ_DATA * obj )
{
     AFFECT_DATA        *paf;

     if ( obj->wear_loc == WEAR_NONE )
     {
          bugf ( "Unequip_char: already unequipped." );
          return FALSE;
     }

     obj->wear_loc = -1;

     if ( !obj->enchanted )
          for ( paf = obj->pIndexData->affected; paf != NULL;
                paf = paf->next )
          {
               affect_modify ( ch, paf, FALSE );
          }
     for ( paf = obj->affected; paf != NULL; paf = paf->next )
     {
          affect_modify ( ch, paf, FALSE );
     }

     if ( obj->item_type == ITEM_LIGHT
          && obj->value[2] != 0
          && ch->in_room != NULL && ch->in_room->light > 0 )
          --ch->in_room->light;

     return TRUE;
}

/*
 * Move an obj out of a room.
 */
void obj_from_room ( OBJ_DATA * obj )
{
     ROOM_INDEX_DATA    *in_room;

     if ( ( in_room = obj->in_room ) == NULL )
     {
          bugf ( "obj_from_room: NULL." );
          return;
     }

     if ( obj == in_room->contents )
     {
          in_room->contents = obj->next_content;
     }
     else
     {
          OBJ_DATA           *prev;

          for ( prev = in_room->contents; prev;
                prev = prev->next_content )
          {
               if ( prev->next_content == obj )
               {
                    prev->next_content = obj->next_content;
                    break;
               }
          }

          if ( prev == NULL )
          {
               bugf ( "Obj_from_room: obj not found." );
               return;
          }
     }

     obj->in_room = NULL;
     obj->next_content = NULL;
     return;
}

/*
 * Move an obj into a room.
 */
void obj_to_room ( OBJ_DATA * obj, ROOM_INDEX_DATA * pRoomIndex )
{
     obj->next_content = pRoomIndex->contents;
     pRoomIndex->contents = obj;
     obj->in_room = pRoomIndex;
     obj->carried_by = NULL;
     obj->in_obj = NULL;
     return;
}

/*
 * Move an object into an object.
 */
void obj_to_obj ( OBJ_DATA * obj, OBJ_DATA * obj_to )
{
     obj->next_content = obj_to->contains;
     obj_to->contains = obj;
     obj->in_obj = obj_to;
     obj->in_room = NULL;
     obj->carried_by = NULL;
     if ( obj_to->pIndexData->vnum == OBJ_VNUM_PIT )
          obj->cost = 1;

     for ( ; obj_to != NULL; obj_to = obj_to->in_obj )
     {
          if ( obj_to->carried_by != NULL )
          {
               obj_to->carried_by->carry_number +=
                    get_obj_number ( obj );
               obj_to->carried_by->carry_weight +=
                    get_obj_weight ( obj );
          }
     }

     return;
}

/*
 * Move an object out of an object.
 */
void obj_from_obj ( OBJ_DATA * obj )
{
     OBJ_DATA           *obj_from;

     if ( ( obj_from = obj->in_obj ) == NULL )
     {
          bugf ( "Obj_from_obj: null obj_from." );
          return;
     }

     if ( obj == obj_from->contains )
     {
          obj_from->contains = obj->next_content;
     }
     else
     {
          OBJ_DATA           *prev;

          for ( prev = obj_from->contains; prev;
                prev = prev->next_content )
          {
               if ( prev->next_content == obj )
               {
                    prev->next_content = obj->next_content;
                    break;
               }
          }

          if ( prev == NULL )
          {
               bugf ( "Obj_from_obj: obj not found." );
               return;
          }
     }

     obj->next_content = NULL;
     obj->in_obj = NULL;

     for ( ; obj_from != NULL; obj_from = obj_from->in_obj )
     {
          if ( obj_from->carried_by != NULL )
          {
               obj_from->carried_by->carry_number -=
                    get_obj_number ( obj );
               obj_from->carried_by->carry_weight -=
                    get_obj_weight ( obj );
          }
     }

     return;
}

/*
 * Extract an obj from the world.
 */
void extract_obj ( OBJ_DATA * obj )
{
     CHAR_DATA          *ch = obj->carried_by;
     OBJ_DATA           *obj_content;
     OBJ_DATA           *obj_next;

     if ( obj->in_room != NULL )
          obj_from_room ( obj );
     else if ( obj->carried_by != NULL )
          obj_from_char ( obj );
     else if ( obj->in_obj != NULL )
          obj_from_obj ( obj );

     for ( obj_content = obj->contains; obj_content;
           obj_content = obj_next )
     {
          obj_next = obj_content->next_content;
          extract_obj ( obj->contains );
     }

     if ( object_list == obj )
     {
          object_list = obj->next;
     }
     else
     {
          OBJ_DATA           *prev;

          for ( prev = object_list; prev != NULL; prev = prev->next )
          {
               if ( prev->next == obj )
               {
                    prev->next = obj->next;
                    break;
               }
          }

          if ( prev == NULL && obj->pIndexData != NULL )
          {
               bugf ( "Extract_obj: obj %d not found.", obj->pIndexData->vnum );
               return;
          }
     }

     {
          AFFECT_DATA        *paf;
          AFFECT_DATA        *paf_next;

          for ( paf = obj->affected; paf != NULL; paf = paf_next )
          {
               paf_next = paf->next;
               paf->next = affect_free;
               affect_free = paf;
          }
     }

     {
          EXTRA_DESCR_DATA   *ed;
          EXTRA_DESCR_DATA   *ed_next;

          for ( ed = obj->extra_descr; ed != NULL; ed = ed_next )
          {
               ed_next = ed->next;
               free_string ( ed->description );
               free_string ( ed->keyword );
               ed->next = extra_descr_free;
               extra_descr_free = ed;
          }
     }

     free_string ( obj->name );
     free_string ( obj->description );
     free_string ( obj->short_descr );
     free_string ( obj->owner );
     if ( obj->pIndexData == NULL )
          bugf ( "Bug: (extract_obj)  NULL obj->pIndexData" );
     else			/*safe to decrement */
          --obj->pIndexData->count;
    /* Zeran - if obj was carried by a player who is quitting, then don't
     * decrement */
     if ( obj->reset != NULL )
     {
          if ( ch == NULL )
          {
               obj->reset->count--;
          }
          else if ( !ch->quitting )
          {
               obj->reset->count--;
          }
     }

     obj->reset = NULL;
     obj->next = obj_free;
     obj_free = obj;
     return;
}

/*
 * Extract a char from the world.
 */
void extract_char ( CHAR_DATA * ch, bool fPull )
{
     CHAR_DATA          *wch;
     OBJ_DATA           *obj;
     OBJ_DATA           *obj_next;

     if ( ch->in_room == NULL )
     {
          bugf ( "Extract_char: NULL." );
          return;
     }

     nuke_pets ( ch );
     ch->pet = NULL;		/* just in case */

     if ( fPull )
          die_follower ( ch );

     stop_fighting ( ch, TRUE );

     for ( obj = ch->carrying; obj != NULL; obj = obj_next )
     {
          extract_obj ( obj );
          obj_next = obj->next_content;
     }

     char_from_room ( ch );

     if ( !fPull )
     {
          char_to_room ( ch, get_room_index ( pc_race_table[ch->pcdata->pcrace].healer ) );
          return;
     }

     if ( IS_NPC ( ch ) )
     {
          --ch->pIndexData->count;
          if ( ch->reset != NULL )
               --ch->reset->count;	/* Zeran - added */
     }

     if ( ch->desc != NULL && ch->desc->original != NULL )
          do_return ( ch, "" );

     for ( wch = char_list; wch != NULL; wch = wch->next )
     {
          if ( wch->reply == ch )
               wch->reply = NULL;
          if ( ch->mprog_target == wch )
               wch->mprog_target = NULL;
     }

     if ( ch == char_list )
     {
          char_list = ch->next;
     }
     else
     {
          CHAR_DATA          *prev;

          for ( prev = char_list; prev != NULL; prev = prev->next )
          {
               if ( prev->next == ch )
               {
                    prev->next = ch->next;
                    break;
               }
          }

          if ( prev == NULL )
          {
               bugf ( "Extract_char: char not found." );
               return;
          }
     }

     if ( ch->desc )
          ch->desc->character = NULL;
     free_char ( ch );
     return;
}

/*
 * Find a char in the room.
 * Sortof the one with obj/roomprogs, but I had to modify it to fit some of the
 * modifications we'd already done here.
 */
CHAR_DATA *get_char_room( CHAR_DATA *ch, ROOM_INDEX_DATA *room, char *argument )
{
     char                arg[MAX_INPUT_LENGTH];
     CHAR_DATA          *rch;
     int                 number;
     int                 count;

     number = number_argument ( argument, arg );
     count = 0;
     if ( !str_cmp ( arg, "self" ) )
          return ch;

     if ( ch && room )
     {
          bugf ( "get_char_room received multiple types (ch/room)" );
          return NULL;
     }

     if ( ch )
          rch = ch->in_room->people;
     else
          rch = room->people;
     for ( ; rch != NULL; rch = rch->next_in_room )
     {
          if ( (ch && !can_see( ch, rch ))
               || ( !is_name( arg, rch->name )
                    && !is_name_abbv ( arg, rch->name ) ) )
               continue;
          if ( ++count == number )
               return rch;
     }
     return NULL;
}

/*
 * Find a char in the world.
 */
CHAR_DATA *get_char_world( CHAR_DATA *ch, char *argument )
{
     char                arg[MAX_INPUT_LENGTH];
     CHAR_DATA          *wch;
     int                 number;
     int                 count;

    /* Zeran - trying "self" alias for yourself */
     if ( !str_cmp ( "self", argument ) )
          return ch;

     if ( ch && ( wch = get_char_room( ch, NULL, argument ) ) != NULL )
          return wch;

     number = number_argument( argument, arg );
     count  = 0;
     for ( wch = char_list; wch != NULL ; wch = wch->next )
     {
          if ( wch->in_room == NULL || ( ch && !can_see( ch, wch ) )
               ||   ( !is_name( arg, wch->name )
                      && !is_name_abbv ( arg, wch->name ) ) )
               continue;
          if ( ++count == number )
               return wch;
     }
     return NULL;
}

/*
 * Find some object with a given index data.
 * Used by area-reset 'P' command.
 */
OBJ_DATA           *get_obj_type ( OBJ_INDEX_DATA * pObjIndex )
{
     OBJ_DATA           *obj;

     for ( obj = object_list; obj != NULL; obj = obj->next )
     {
          if ( obj->pIndexData == pObjIndex )
               return obj;
     }

     return NULL;
}

/*
 * Find an obj in a list.
 */
OBJ_DATA           *get_obj_list ( CHAR_DATA * ch, char *argument, OBJ_DATA * list )
{
     char                arg[MAX_INPUT_LENGTH];
     OBJ_DATA           *obj;
     int                 number;
     int                 count;

     number = number_argument ( argument, arg );
     count = 0;
     for ( obj = list; obj != NULL; obj = obj->next_content )
     {
          if ( can_see_obj ( ch, obj ) && ( is_name_abbv ( arg, obj->name ) || is_name ( arg, obj->name ) ) )
          {
               if ( ++count == number )
                    return obj;
          }
     }
     return NULL;
}

/*
 * Find an obj in player's inventory.
 */

OBJ_DATA *get_obj_carry( CHAR_DATA *ch, char *argument, CHAR_DATA *viewer )
{
     char arg[MAX_INPUT_LENGTH];
     OBJ_DATA *obj;
     int number;
     int count;

     number = number_argument( argument, arg );
     count  = 0;
     for ( obj = ch->carrying; obj != NULL; obj = obj->next_content )
     {
          if ( obj->wear_loc == WEAR_NONE
               &&   ( viewer ? can_see_obj( viewer, obj ) : TRUE )
               &&   ( is_name( arg, obj->name ) || is_name_abbv ( arg, obj->name ) ) )
          {
               if ( ++count == number )
                    return obj;
          }
     }
     return NULL;
}

/*
 * Find an obj in player's equipment.
 */
OBJ_DATA *get_obj_wear( CHAR_DATA *ch, char *argument, bool character )
{
     char arg[MAX_INPUT_LENGTH];
     OBJ_DATA *obj;
     int number;
     int count;

     number = number_argument( argument, arg );
     count  = 0;
     for ( obj = ch->carrying; obj != NULL; obj = obj->next_content )
     {
          if ( obj->wear_loc != WEAR_NONE
               &&  ( character ? can_see_obj( ch, obj ) : TRUE)
               &&   ( is_name( arg, obj->name ) || is_name_abbv ( arg, obj->name ) ) )
          {
               if ( ++count == number )
                    return obj;
          }
     }
     return NULL;
}

/*
 * Find an obj in the room or in inventory.
 */
OBJ_DATA *get_obj_here( CHAR_DATA *ch, ROOM_INDEX_DATA *room, char *argument )
{
     OBJ_DATA *obj;
     int number, count;
     char arg[MAX_INPUT_LENGTH];

     if ( ch && room )
     {
          bugf ( "get_obj_here received a ch and a room");
          return NULL;
     }

     number = number_argument( argument, arg );
     count = 0;

     if ( ch )
     {
          obj = get_obj_list( ch, argument, ch->in_room->contents );
          if ( obj != NULL )
               return obj;
          if ( ( obj = get_obj_carry( ch, argument, ch ) ) != NULL )
               return obj;
          if ( ( obj = get_obj_wear( ch, argument, TRUE ) ) != NULL )
               return obj;
     }
     else
     {
          for ( obj = room->contents; obj; obj = obj->next_content )
          {
               if ( !is_name( arg, obj->name ) && !is_name_abbv( arg, obj->name ) )
                    continue;
               if ( ++count == number )
                    return obj;
          }
     }

     return NULL;
}

/*
 * Find an obj in the world.
 */

OBJ_DATA *get_obj_world( CHAR_DATA *ch, char *argument )
{
     char arg[MAX_INPUT_LENGTH];
     OBJ_DATA *obj;
     int number;
     int count;

     if ( ch && ( obj = get_obj_here( ch, NULL, argument ) ) != NULL )
          return obj;

     number = number_argument( argument, arg );
     count  = 0;
     for ( obj = object_list; obj != NULL; obj = obj->next )
     {
          if ( ( ch && !can_see_obj( ch, obj ) )
               || ( !is_name( arg, obj->name ) && !is_name_abbv ( arg, obj->name ) ) )
               continue;
          if ( ++count == number )
               return obj;
     }
     return NULL;
}

/*
 * Create a 'money' obj.
 */
OBJ_DATA           *create_money ( int amount )
{
     char                buf[MAX_STRING_LENGTH];
     OBJ_DATA           *obj;

     if ( amount <= 0 )
     {
          bugf ( "Create_money: zero or negative money %d.", amount );
          amount = 1;
     }

     if ( amount == 1 )
     {
          obj =
               create_object ( get_obj_index ( OBJ_VNUM_MONEY_ONE ),
                               0 );
     }
     else
     {
          obj =
               create_object ( get_obj_index ( OBJ_VNUM_MONEY_SOME ),
                               0 );
          SNP ( buf, obj->short_descr, amount );
          free_string ( obj->short_descr );
          obj->short_descr = str_dup ( buf );
          obj->value[0] = amount;
          obj->cost = amount;
     }

     return obj;
}

/*
 * Return # of objects which an object counts as.
 * Thanks to Tony Chamberlain for the correct recursive code here.
 */
int get_obj_number ( OBJ_DATA * obj )
{
     int                 number;

     if ( obj->item_type == ITEM_CONTAINER ||
          obj->item_type == ITEM_MONEY )
          number = 0;
     else
          number = 1;

     for ( obj = obj->contains; obj != NULL;
           obj = obj->next_content )
          number += get_obj_number ( obj );

     return number;
}

/*
 * Return weight of an object, including weight of contents.
 */
int get_obj_weight ( OBJ_DATA * obj )
{
     int                 weight;

    /* Zeran - if object is a floating object, weight is irrelevant */
     if ( IS_SET ( obj->wear_flags, ITEM_WEAR_FLOAT ) )
          weight = 0;
     else
          weight = obj->weight;
     for ( obj = obj->contains; obj != NULL;
           obj = obj->next_content )
          weight += get_obj_weight ( obj );

     return weight;
}

/*
 * True if room is dark.
 */
bool room_is_dark ( ROOM_INDEX_DATA * pRoomIndex )
{
     if ( pRoomIndex->light > 0 )
          return FALSE;

     if ( IS_SET ( pRoomIndex->room_flags, ROOM_DARK ) )
          return TRUE;

     if ( pRoomIndex->sector_type == SECT_INSIDE
          || pRoomIndex->sector_type == SECT_CITY )
          return FALSE;

     if ( weather_info.sunlight == SUN_SET
          || weather_info.sunlight == SUN_DARK )
          return TRUE;

     return FALSE;
}

/*
 * True if room is private.
 */
bool room_is_private ( ROOM_INDEX_DATA * pRoomIndex )
{
     CHAR_DATA          *rch;
     int                 count;

     count = 0;
     for ( rch = pRoomIndex->people; rch != NULL;
           rch = rch->next_in_room )
          count++;

     if ( IS_SET ( pRoomIndex->room_flags, ROOM_PRIVATE ) &&
          count >= 2 )
          return TRUE;

     if ( IS_SET ( pRoomIndex->room_flags, ROOM_SOLITARY ) &&
          count >= 1 )
          return TRUE;

     return FALSE;
}

/* visibility on a room -- for entering and exits */
bool can_see_room ( CHAR_DATA * ch, ROOM_INDEX_DATA * pRoomIndex )
{
     if ( !pRoomIndex )
          return FALSE;		/* If the roomindex is NULL, must return false */
     
     if ( IS_RENTED ( pRoomIndex->lease ) )
     {
          if ( pRoomIndex->lease->owner_only )
          {
               if ( !str_cmp ( ch->name, pRoomIndex->lease->rented_by ) ) // Owners can always see their own room
                    return TRUE;
               else
                    return FALSE;
          }
     }

     if ( IS_NPC(ch) )
     {
          return TRUE;
     }

     if ( IS_SET ( pRoomIndex->room_flags, ROOM_IMP_ONLY ) && get_trust ( ch ) < MAX_LEVEL )
          return FALSE;

     if ( IS_SET ( pRoomIndex->room_flags, ROOM_GODS_ONLY ) && !IS_IMMORTAL ( ch ) )
          return FALSE;

     if ( IS_SET ( pRoomIndex->room_flags, ROOM_HEROES_ONLY ) && !IS_HERO ( ch ) )
          return FALSE;

     if ( IS_SET ( pRoomIndex->room_flags, ROOM_NEWBIES_ONLY ) && ch->level > 5 && !IS_IMMORTAL ( ch ) )
          return FALSE;

     return TRUE;
}

/*
 * True if char can see victim.
 */
bool can_see ( CHAR_DATA * ch, CHAR_DATA * victim )
{

/* RT changed so that WIZ_INVIS has levels */
     if ( ch == victim )
          return TRUE;

     if ( !IS_NPC ( victim )
          && IS_SET ( victim->act, PLR_WIZINVIS )
          && get_trust ( ch ) < victim->invis_level )
          return FALSE;

     if ( !IS_NPC ( victim )
          && IS_SET ( victim->act, PLR_CLOAK )
          && get_trust ( ch ) < victim->cloak_level
          && ch->in_room != victim->in_room )
          return FALSE;

     if ( ( !IS_NPC ( ch ) && IS_SET ( ch->act, PLR_HOLYLIGHT ) )
          || ( IS_NPC ( ch ) && IS_IMMORTAL ( ch ) ) )
          return TRUE;

     if ( IS_AFFECTED ( ch, AFF_BLIND ) )
          return FALSE;

     if ( room_is_dark ( ch->in_room ) &&
          !CAN_DETECT ( ch, DET_INFRARED ) )
          return FALSE;

     if ( IS_AFFECTED ( victim, AFF_INVISIBLE )
          && !CAN_DETECT ( ch, DET_INVIS ) )
          return FALSE;

     if ( IS_AFFECTED ( victim, AFF_HIDE )
          && !CAN_DETECT ( ch, DET_HIDDEN ) )
          return FALSE;

    /* sneaking */
     if ( IS_AFFECTED ( victim, AFF_SNEAK )
          && !CAN_DETECT ( ch, DET_HIDDEN )
          && victim->fighting == NULL
          && ( IS_NPC ( ch ) ? !IS_NPC ( victim ) :
               IS_NPC ( victim ) ) )
     {
          int                 chance;

          chance = get_skill ( victim, gsn_sneak );
          chance += get_curr_stat ( ch, STAT_DEX ) * 3 / 2;
          chance -= get_curr_stat ( ch, STAT_INT ) * 2;
          chance += ch->level - victim->level * 3 / 2;

          if ( number_percent (  ) < chance )
               return FALSE;
     }

     if ( IS_AFFECTED ( victim, AFF_HIDE )
          && !CAN_DETECT ( ch, DET_HIDDEN )
          && victim->fighting == NULL
          && ( IS_NPC ( ch ) ? !IS_NPC ( victim ) :
               IS_NPC ( victim ) ) )
          return FALSE;

     return TRUE;
}

/*
 * True if char can see obj.
 */
bool can_see_obj ( CHAR_DATA * ch, OBJ_DATA * obj )
{
     if ( !IS_NPC ( ch ) && IS_SET ( ch->act, PLR_HOLYLIGHT ) )
          return TRUE;

     if ( IS_SET ( obj->extra_flags, ITEM_VIS_DEATH ) )
          return FALSE;

     if ( IS_AFFECTED ( ch, AFF_BLIND ) &&
          obj->item_type != ITEM_POTION )
          return FALSE;

     if ( IS_SET ( obj->extra_flags, ITEM_CONCEALED ) &&
          !ch->searching )
          return FALSE;

     if ( obj->item_type == ITEM_LIGHT && obj->value[2] != 0 )
          return TRUE;

     if ( IS_SET ( obj->extra_flags, ITEM_INVIS )
          && !CAN_DETECT ( ch, DET_INVIS ) )
          return FALSE;

     if ( IS_OBJ_STAT ( obj, ITEM_GLOW ) )
          return TRUE;

     if ( room_is_dark ( ch->in_room ) &&
          !CAN_DETECT ( ch, DET_INFRARED ) )
          return FALSE;

     return TRUE;
}

/*
 * True if char can drop obj.
 */
bool can_drop_obj ( CHAR_DATA * ch, OBJ_DATA * obj )
{
     if ( !IS_SET ( obj->extra_flags, ITEM_NODROP ) )
          return TRUE;

     if ( !IS_NPC ( ch ) && ch->level >= LEVEL_IMMORTAL )
          return TRUE;

     return FALSE;
}

/*
 * Return ascii name of an item type.
 */
char               *item_type_name ( OBJ_DATA * obj )
{
     switch ( obj->item_type )
     {
     case ITEM_LIGHT:          return "light";
     case ITEM_SCROLL:         return "scroll";
     case ITEM_WAND:           return "wand";
     case ITEM_STAFF:          return "staff";
     case ITEM_WEAPON:         return "weapon";
     case ITEM_TREASURE:       return "treasure";
     case ITEM_ARMOR:          return "armor";
     case ITEM_POTION:         return "potion";
     case ITEM_FURNITURE:      return "furniture";
     case ITEM_TRASH:          return "trash";
     case ITEM_CONTAINER:      return "container";
     case ITEM_DRINK_CON:      return "drink container";
     case ITEM_KEY:            return "key";
     case ITEM_FOOD:           return "food";
     case ITEM_MONEY:          return "money";
     case ITEM_BOAT:           return "boat";
     case ITEM_CORPSE_NPC:     return "npc corpse";
     case ITEM_CORPSE_PC:      return "pc corpse";
     case ITEM_FOUNTAIN:       return "fountain";
     case ITEM_PILL:           return "pill";
     case ITEM_MAP:            return "map";
     case ITEM_PRIDE:          return "pride";
     case ITEM_COMPONENT:      return "component";
     case ITEM_PORTAL:         return "portal";
     }

     bugf ( "Item_type_name: unknown type %d.", obj->item_type );
     return "(unknown)";
}

/*
 * Return ascii name of an affect location.
 */
char               *affect_loc_name ( int location )
{
     switch ( location )
     {
     case APPLY_NONE:          return "none";
     case APPLY_STR:           return "strength";
     case APPLY_DEX:           return "dexterity";
     case APPLY_INT:           return "intelligence";
     case APPLY_WIS:           return "wisdom";
     case APPLY_CON:           return "constitution";
     case APPLY_SEX:           return "sex";
     case APPLY_CLASS:         return "class";
     case APPLY_LEVEL:         return "level";
     case APPLY_AGE:           return "age";
     case APPLY_MANA:          return "mana";
     case APPLY_HIT:           return "hp";
     case APPLY_MOVE:          return "moves";
     case APPLY_GOLD:          return "gold";
     case APPLY_EXP:           return "experience";
     case APPLY_AC:            return "armor class";
     case APPLY_HITROLL:       return "hit roll";
     case APPLY_DAMROLL:       return "damage roll";
     case APPLY_SAVING_PARA:   return "save vs paralysis";
     case APPLY_SAVING_ROD:    return "save vs rod";
     case APPLY_SAVING_PETRI:  return "save vs petrification";
     case APPLY_SAVING_BREATH: return "save vs breath";
     case APPLY_SAVING_SPELL:  return "save vs spell";
     case APPLY_ENCUMBRANCE:   return "encumbrance";
     }

     bugf ( "Affect_location_name: unknown location %d.", location );
     return "(unknown)";
}

/*
 * Return ascii name of an affect bit vector
 */

char               *affect_bit_name ( int vector )
{
     static char         buf[1024];

     buf[0] = '\0';
     if ( vector & AFF_BLIND         ) SLCAT ( buf, " blind"         );
     if ( vector & AFF_INVISIBLE     ) SLCAT ( buf, " invisible"     );
     if ( vector & AFF_MELD          ) SLCAT ( buf, " mind meld"     );
     if ( vector & AFF_FAERIE_FIRE   ) SLCAT ( buf, " faerie fire"   );
     if ( vector & AFF_CURSE         ) SLCAT ( buf, " curse"         );
     if ( vector & AFF_POISON        ) SLCAT ( buf, " poison"        );
     if ( vector & AFF_SLEEP         ) SLCAT ( buf, " sleep"         );
     if ( vector & AFF_SNEAK         ) SLCAT ( buf, " sneak"         );
     if ( vector & AFF_HIDE          ) SLCAT ( buf, " hide"          );
     if ( vector & AFF_CHARM         ) SLCAT ( buf, " charm"         );
     if ( vector & AFF_FLYING        ) SLCAT ( buf, " flying"        );
     if ( vector & AFF_PASS_DOOR     ) SLCAT ( buf, " pass door"     );
     if ( vector & AFF_BERSERK       ) SLCAT ( buf, " berserk"       );
     if ( vector & AFF_CALM          ) SLCAT ( buf, " calm"          );
     if ( vector & AFF_HASTE         ) SLCAT ( buf, " haste"         );
     if ( vector & AFF_PLAGUE        ) SLCAT ( buf, " plague"        );
     if ( vector & AFF_FEAR   	     ) SLCAT ( buf, " fear"          );
     if ( vector & AFF_REGENERATION  ) SLCAT ( buf, " regeneration"  );
     if ( vector & AFF_SWIM          ) SLCAT ( buf, " swim"          );
     if ( vector & AFF_POLY          ) SLCAT ( buf, " polymorph"     );
     return ( buf[0] != '\0' ) ? buf+1 : "none";
}

char               *detect_bit_name ( int vector )
{
     static char         buf[1024];
     buf[0] = '\0';
     if ( vector & AFF_SHIELD        ) SLCAT (buf, " shield" 		);
     if ( vector & AFF_MUTE          ) SLCAT (buf, " mute" 		);
     if ( vector & AFF_SLOW          ) SLCAT (buf, " slow" 		);
     if ( vector & AFF_CONFUSION     ) SLCAT (buf, " confusion" 	);
     if ( vector & AFF_RALLY         ) SLCAT (buf, " rally" 		);
     if ( vector & DET_EVIL          ) SLCAT( buf, " evil"   		);
     if ( vector & DET_INVIS         ) SLCAT( buf, " invis"  		);
     if ( vector & DET_MAGIC         ) SLCAT( buf, " magic"  		);
     if ( vector & DET_HIDDEN        ) SLCAT( buf, " hidden" 		);
     if ( vector & DET_DARK_VISION   ) SLCAT( buf, " dark vision"   	);
     if ( vector & DET_INFRARED      ) SLCAT( buf, " infrared"      	);
     return ( buf[0] != '\0' ) ? buf+1 : "none";
}

char		*protect_bit_name ( int vector )
{
     static char		buf[1024];

     buf[0] = '\0';
     if ( vector & PROT_EVIL          ) SLCAT ( buf, " evil"  	      );
     if ( vector & PROT_GOOD          ) SLCAT ( buf, " good"          );
     if ( vector & PROT_SANCTUARY     ) SLCAT ( buf, " sanctuary"     );
     if ( vector & PROT_ABSORB        ) SLCAT ( buf, " absorb"        );
     if ( vector & PROT_PHASED        ) SLCAT ( buf, " phased"        );
     return ( buf[0] != '\0' ) ? buf+1 : "none";
}

/*
 * Return ascii name of extra flags vector.
 */
char               *extra_bit_name ( int extra_flags )
{
     static char         buf[512];

     buf[0] = '\0';
     if ( extra_flags & ITEM_GLOW )          SLCAT ( buf, " glow" );
     if ( extra_flags & ITEM_HUM )           SLCAT ( buf, " hum" );
     if ( extra_flags & ITEM_DARK )          SLCAT ( buf, " dark" );
     if ( extra_flags & ITEM_LOCK )          SLCAT ( buf, " lock" );
     if ( extra_flags & ITEM_EVIL )          SLCAT ( buf, " evil" );
     if ( extra_flags & ITEM_INVIS )         SLCAT ( buf, " invis" );
     if ( extra_flags & ITEM_MAGIC )         SLCAT ( buf, " magic" );
     if ( extra_flags & ITEM_NODROP )        SLCAT ( buf, " nodrop" );
     if ( extra_flags & ITEM_BLESS )         SLCAT ( buf, " bless" );
     if ( extra_flags & ITEM_ANTI_GOOD )     SLCAT ( buf, " anti good" );
     if ( extra_flags & ITEM_ANTI_EVIL )     SLCAT ( buf, " anti evil" );
     if ( extra_flags & ITEM_ANTI_NEUTRAL )  SLCAT ( buf, " anti neutral" );
     if ( extra_flags & ITEM_NOREMOVE )      SLCAT ( buf, " noremove" );
     if ( extra_flags & ITEM_NO_SAC )        SLCAT ( buf, " no sacrifice" );
     if ( extra_flags & ITEM_NO_COND )       SLCAT ( buf, " no condition" );
     if ( extra_flags & ITEM_CONCEALED )     SLCAT ( buf, " concealed" );
     if ( extra_flags & ITEM_INVENTORY )     SLCAT ( buf, " inventory" );
     if ( extra_flags & ITEM_NOPURGE )       SLCAT ( buf, " nopurge" );
     if ( extra_flags & ITEM_VIS_DEATH )     SLCAT ( buf, " visibile at death" );
     if ( extra_flags & ITEM_ROT_DEATH )     SLCAT ( buf, " rot on death" );
     if ( extra_flags & ITEM_NODISP )        SLCAT ( buf, " no display" );
     return ( buf[0] != '\0' ) ? buf + 1 : "none";
}

/* return ascii name of an act vector */
char               *act_bit_name ( int act_flags )
{
     static char         buf[512];

     buf[0] = '\0';

     if ( IS_SET ( act_flags, ACT_IS_NPC ) )
     {
          SLCAT ( buf, " npc" );
          if ( act_flags & ACT_SENTINEL )        SLCAT ( buf, " sentinel" 	);
          if ( act_flags & ACT_SCAVENGER )       SLCAT ( buf, " scavenger" 	);
          if ( act_flags & ACT_AGGRESSIVE )      SLCAT ( buf, " aggressive" 	);
          if ( act_flags & ACT_STAY_AREA )       SLCAT ( buf, " stay area" 	);
          if ( act_flags & ACT_WIMPY )           SLCAT ( buf, " wimpy" 		);
          if ( act_flags & ACT_PET )             SLCAT ( buf, " pet" 		);
          if ( act_flags & ACT_FOLLOWER )        SLCAT ( buf, " follower" 	);
          if ( act_flags & ACT_PRACTICE )        SLCAT ( buf, " practice" 	);
          if ( act_flags & ACT_UNDEAD )          SLCAT ( buf, " undead" 	);
          if ( act_flags & ACT_CLERIC )          SLCAT ( buf, " cleric" 	);
          if ( act_flags & ACT_MAGE )            SLCAT ( buf, " mage" 		);
          if ( act_flags & ACT_THIEF )           SLCAT ( buf, " thief" 		);
          if ( act_flags & ACT_WARRIOR )         SLCAT ( buf, " warrior"        );
          if ( act_flags & ACT_NOALIGN )         SLCAT ( buf, " no align" 	);
          if ( act_flags & ACT_NOPURGE )         SLCAT ( buf, " no purge" 	);
          if ( act_flags & ACT_IS_HEALER )       SLCAT ( buf, " healer" 	);
          if ( act_flags & ACT_TELEPOP )         SLCAT ( buf, " telepop" 	);
          if ( act_flags & ACT_UPDATE_ALWAYS )   SLCAT ( buf, " update always"  );
          if ( act_flags & ACT_NORANDOM )	 SLCAT ( buf, " no random items");
          if ( act_flags & ACT_NOQUEST )	 SLCAT ( buf, " no quest" 	);
          if ( act_flags & ACT_FOLLOWER )	 SLCAT ( buf, " follower" 	);
          if ( act_flags & ACT_SOLDIER )         SLCAT ( buf, " soldier" 	);
          if ( act_flags & ACT_SKILLMASTER )	 SLCAT ( buf, " skillmaster" 	);
     }
     else
     {
          SLCAT ( buf, " player" );
          if ( act_flags & PLR_BOUGHT_PET )      SLCAT ( buf, " owner" );
          if ( act_flags & PLR_AUTOASSIST )      SLCAT ( buf, " autoassist" );
          if ( act_flags & PLR_AUTOEXIT )        SLCAT ( buf, " autoexit" );
          if ( act_flags & PLR_AUTOLOOT )        SLCAT ( buf, " autoloot" );
          if ( act_flags & PLR_AUTOSAC )         SLCAT ( buf, " autosac" );
          if ( act_flags & PLR_AUTOGOLD )        SLCAT ( buf, " autogold" );
          if ( act_flags & PLR_AUTOSPLIT )       SLCAT ( buf, " autosplit" );
          if ( act_flags & PLR_HOLYLIGHT )       SLCAT ( buf, " holy light" );
          if ( act_flags & PLR_WIZINVIS )        SLCAT ( buf, " wizinvis" );
          if ( act_flags & PLR_CANLOOT )         SLCAT ( buf, " can loot corpse" );
          if ( act_flags & PLR_NOSUMMON )        SLCAT ( buf, " nosummon" );
          if ( act_flags & PLR_NOFOLLOW )        SLCAT ( buf, " nofollow" );
          if ( act_flags & PLR_FREEZE )          SLCAT ( buf, " frozen" );
          if ( act_flags & PLR_THIEF )           SLCAT ( buf, " thief" );
          if ( act_flags & PLR_KILLER )          SLCAT ( buf, " killer" );
          if ( act_flags & PLR_QUESTOR )	 SLCAT ( buf, " questing" );
          if ( act_flags & PLR_XINFO )		 SLCAT ( buf, " x-info" );
          if ( act_flags & PLR_CURSOR )		 SLCAT ( buf, " cursor" );
          if ( act_flags & PLR_CLOAK )		 SLCAT ( buf, " cloak" );
     }
     return ( buf[0] != '\0' ) ? buf + 1 : "none";
}

char               *comm_bit_name ( int comm_flags )
{
     static char         buf[512];

     buf[0] = '\0';

     if ( comm_flags & COMM_QUIET )          SLCAT ( buf, " quiet" );
     if ( comm_flags & COMM_DEAF )           SLCAT ( buf, " deaf" );
     if ( comm_flags & COMM_NOWIZ )          SLCAT ( buf, " no_wiz" );
     if ( comm_flags & COMM_NOAUCTION )      SLCAT ( buf, " no_auction" );
     if ( comm_flags & COMM_NOGOSSIP )       SLCAT ( buf, " no_gossip" );
     if ( comm_flags & COMM_NOQUESTION )     SLCAT ( buf, " no_question" );
     if ( comm_flags & COMM_NOMUSIC )        SLCAT ( buf, " no_music" );
     if ( comm_flags & COMM_COMPACT )        SLCAT ( buf, " compact" );
     if ( comm_flags & COMM_FULLFIGHT )      SLCAT ( buf, " full battle" );
     if ( comm_flags & COMM_BRIEF )          SLCAT ( buf, " brief" );
     if ( comm_flags & COMM_PROMPT )         SLCAT ( buf, " prompt" );
     if ( comm_flags & COMM_COMBINE )        SLCAT ( buf, " combine" );
     if ( comm_flags & COMM_NOEMOTE )        SLCAT ( buf, " no_emote" );
     if ( comm_flags & COMM_NOSHOUT )        SLCAT ( buf, " no_shout" );
     if ( comm_flags & COMM_NOTELL )         SLCAT ( buf, " no_tell" );
     if ( comm_flags & COMM_NOCHANNELS )     SLCAT ( buf, " no_channels" );
     if ( comm_flags & COMM_NOCLANTELL )     SLCAT ( buf, " no_clantell" );
     if ( comm_flags & COMM_TELNET_GA )      SLCAT ( buf, " telnet_ga" );
     if ( comm_flags & COMM_DARKCOLOR )      SLCAT ( buf, " dark colors" );
     if ( comm_flags & COMM_NOFLASHY )       SLCAT ( buf, " no flashy" );
     if ( comm_flags & COMM_BEEP )           SLCAT ( buf, " beep" );
     if ( comm_flags & COMM_NODARKGREY )     SLCAT ( buf, " no dark grey" );
     if ( comm_flags & COMM_COLOUR )         SLCAT ( buf, " colour" );

     return ( buf[0] != '\0' ) ? buf + 1 : "none";
}

char               *imm_bit_name ( int imm_flags )
{
     static char         buf[512];

     buf[0] = '\0';

     if ( imm_flags & IMM_SUMMON )          SLCAT ( buf, " summon" );
     if ( imm_flags & IMM_CHARM )           SLCAT ( buf, " charm" );
     if ( imm_flags & IMM_MAGIC )           SLCAT ( buf, " magic" );
     if ( imm_flags & IMM_WEAPON )          SLCAT ( buf, " weapon" );
     if ( imm_flags & IMM_BASH )            SLCAT ( buf, " blunt" );
     if ( imm_flags & IMM_PIERCE )          SLCAT ( buf, " piercing" );
     if ( imm_flags & IMM_SLASH )           SLCAT ( buf, " slashing" );
     if ( imm_flags & IMM_FIRE )            SLCAT ( buf, " fire" );
     if ( imm_flags & IMM_COLD )            SLCAT ( buf, " cold" );
     if ( imm_flags & IMM_LIGHTNING )       SLCAT ( buf, " lightning" );
     if ( imm_flags & IMM_ACID )            SLCAT ( buf, " acid" );
     if ( imm_flags & IMM_POISON )          SLCAT ( buf, " poison" );
     if ( imm_flags & IMM_NEGATIVE )        SLCAT ( buf, " negative" );
     if ( imm_flags & IMM_HOLY )            SLCAT ( buf, " holy" );
     if ( imm_flags & IMM_ENERGY )          SLCAT ( buf, " energy" );
     if ( imm_flags & IMM_MENTAL )          SLCAT ( buf, " mental" );
     if ( imm_flags & IMM_DISEASE )         SLCAT ( buf, " disease" );
     if ( imm_flags & IMM_DROWNING )        SLCAT ( buf, " drowning" );
     if ( imm_flags & IMM_LIGHT )           SLCAT ( buf, " light" );
     if ( imm_flags & VULN_IRON )           SLCAT ( buf, " iron" );
     if ( imm_flags & VULN_WOOD )           SLCAT ( buf, " wood" );
     if ( imm_flags & VULN_SILVER )         SLCAT ( buf, " silver" );
     if ( imm_flags & VULN_STEEL )          SLCAT ( buf, " steel" );
     if ( imm_flags & VULN_ADAMANTITE )     SLCAT ( buf, " adamantite" );
     if ( imm_flags & VULN_MITHRIL )        SLCAT ( buf, " mithril" );

     return ( buf[0] != '\0' ) ? buf + 1 : "none";
}

char               *wear_bit_name ( int wear_flags )
{
     static char         buf[512];

     buf[0] = '\0';
     if ( wear_flags & ITEM_TAKE )          SLCAT ( buf, " take" );
     if ( wear_flags & ITEM_WEAR_FINGER )   SLCAT ( buf, " finger" );
     if ( wear_flags & ITEM_WEAR_NECK )     SLCAT ( buf, " neck" );
     if ( wear_flags & ITEM_WEAR_BODY )     SLCAT ( buf, " torso" );
     if ( wear_flags & ITEM_WEAR_HEAD )     SLCAT ( buf, " head" );
     if ( wear_flags & ITEM_WEAR_LEGS )     SLCAT ( buf, " legs" );
     if ( wear_flags & ITEM_WEAR_FEET )     SLCAT ( buf, " feet" );
     if ( wear_flags & ITEM_WEAR_HANDS )    SLCAT ( buf, " hands" );
     if ( wear_flags & ITEM_WEAR_ARMS )     SLCAT ( buf, " arms" );
     if ( wear_flags & ITEM_WEAR_SHIELD )   SLCAT ( buf, " shield" );
     if ( wear_flags & ITEM_WEAR_ABOUT )    SLCAT ( buf, " body" );
     if ( wear_flags & ITEM_WEAR_WAIST )    SLCAT ( buf, " waist" );
     if ( wear_flags & ITEM_WEAR_WRIST )    SLCAT ( buf, " wrist" );
     if ( wear_flags & ITEM_WIELD )         SLCAT ( buf, " wield" );
     if ( wear_flags & ITEM_HOLD )          SLCAT ( buf, " hold" );
     if ( wear_flags & ITEM_WEAR_PRIDE )    SLCAT ( buf, " pride" );
     if ( wear_flags & ITEM_WEAR_FACE )     SLCAT ( buf, " face" );
     if ( wear_flags & ITEM_WEAR_EARS )     SLCAT ( buf, " ears" );
     if ( wear_flags & ITEM_WEAR_FLOAT )    SLCAT ( buf, " float" );

     return ( buf[0] != '\0' ) ? buf + 1 : "none";
}

char               *form_bit_name ( int form_flags )
{
     static char         buf[512];

     buf[0] = '\0';
     if ( form_flags & FORM_POISON )          SLCAT ( buf, " poison" );
     else if ( form_flags & FORM_EDIBLE )     SLCAT ( buf, " edible" );
     if ( form_flags & FORM_MAGICAL )         SLCAT ( buf, " magical" );
     if ( form_flags & FORM_INSTANT_DECAY )   SLCAT ( buf, " instant_rot" );
     if ( form_flags & FORM_OTHER )           SLCAT ( buf, " other" );
     if ( form_flags & FORM_ANIMAL )          SLCAT ( buf, " animal" );
     if ( form_flags & FORM_SENTIENT )        SLCAT ( buf, " sentient" );
     if ( form_flags & FORM_UNDEAD )          SLCAT ( buf, " undead" );
     if ( form_flags & FORM_CONSTRUCT )       SLCAT ( buf, " construct" );
     if ( form_flags & FORM_MIST )            SLCAT ( buf, " mist" );
     if ( form_flags & FORM_INTANGIBLE )      SLCAT ( buf, " intangible" );
     if ( form_flags & FORM_BIPED )           SLCAT ( buf, " biped" );
     if ( form_flags & FORM_CENTAUR )         SLCAT ( buf, " centaur" );
     if ( form_flags & FORM_INSECT )          SLCAT ( buf, " insect" );
     if ( form_flags & FORM_SPIDER )          SLCAT ( buf, " spider" );
     if ( form_flags & FORM_CRUSTACEAN )      SLCAT ( buf, " crustacean" );
     if ( form_flags & FORM_WORM )            SLCAT ( buf, " worm" );
     if ( form_flags & FORM_BLOB )            SLCAT ( buf, " blob" );
     if ( form_flags & FORM_MAMMAL )          SLCAT ( buf, " mammal" );
     if ( form_flags & FORM_BIRD )            SLCAT ( buf, " bird" );
     if ( form_flags & FORM_REPTILE )         SLCAT ( buf, " reptile" );
     if ( form_flags & FORM_SNAKE )           SLCAT ( buf, " snake" );
     if ( form_flags & FORM_DRAGON )          SLCAT ( buf, " dragon" );
     if ( form_flags & FORM_AMPHIBIAN )       SLCAT ( buf, " amphibian" );
     if ( form_flags & FORM_FISH )            SLCAT ( buf, " fish" );
     if ( form_flags & FORM_COLD_BLOOD )      SLCAT ( buf, " cold_blooded" );

     return ( buf[0] != '\0' ) ? buf + 1 : "none";
}

char               *part_bit_name ( int part_flags )
{
     static char         buf[512];

     buf[0] = '\0';
     if ( part_flags & PART_HEAD )          SLCAT ( buf, " head" );
     if ( part_flags & PART_ARMS )          SLCAT ( buf, " arms" );
     if ( part_flags & PART_LEGS )          SLCAT ( buf, " legs" );
     if ( part_flags & PART_HEART )         SLCAT ( buf, " heart" );
     if ( part_flags & PART_BRAINS )        SLCAT ( buf, " brains" );
     if ( part_flags & PART_GUTS )          SLCAT ( buf, " guts" );
     if ( part_flags & PART_HANDS )         SLCAT ( buf, " hands" );
     if ( part_flags & PART_FEET )          SLCAT ( buf, " feet" );
     if ( part_flags & PART_FINGERS )       SLCAT ( buf, " fingers" );
     if ( part_flags & PART_EAR )           SLCAT ( buf, " ears" );
     if ( part_flags & PART_EYE )           SLCAT ( buf, " eyes" );
     if ( part_flags & PART_LONG_TONGUE )   SLCAT ( buf, " long_tongue" );
     if ( part_flags & PART_EYESTALKS )     SLCAT ( buf, " eyestalks" );
     if ( part_flags & PART_TENTACLES )     SLCAT ( buf, " tentacles" );
     if ( part_flags & PART_FINS )          SLCAT ( buf, " fins" );
     if ( part_flags & PART_WINGS )         SLCAT ( buf, " wings" );
     if ( part_flags & PART_TAIL )          SLCAT ( buf, " tail" );
     if ( part_flags & PART_CLAWS )         SLCAT ( buf, " claws" );
     if ( part_flags & PART_FANGS )         SLCAT ( buf, " fangs" );
     if ( part_flags & PART_HORNS )         SLCAT ( buf, " horns" );
     if ( part_flags & PART_SCALES )        SLCAT ( buf, " scales" );
     if ( part_flags & PART_HOOFS )         SLCAT ( buf, " hooves" );
     if ( part_flags & PART_NECK )          SLCAT ( buf, " neck" );
     if ( part_flags & PART_WAIST )         SLCAT ( buf, " waist" );
     if ( part_flags & PART_WRIST )         SLCAT ( buf, " wrist" );
     if ( part_flags & PART_FACE )          SLCAT ( buf, " face" );

     return ( buf[0] != '\0' ) ? buf + 1 : "none";
}

char               *weapon_bit_name ( int weapon_flags )
{
     static char        buf[512];

     buf[0] = '\0';
     if ( weapon_flags & WEAPON_FLAMING )      SLCAT ( buf, " {rflaming{x" );
     if ( weapon_flags & WEAPON_ACID )         SLCAT ( buf, " {Gacidic{x" );
     if ( weapon_flags & WEAPON_LIGHTNING )    SLCAT ( buf, " {Yelectric{x" );
     if ( weapon_flags & WEAPON_FROST )        SLCAT ( buf, " {Bfrost{x" );
     if ( weapon_flags & WEAPON_VAMPIRIC )     SLCAT ( buf, " {Mvampiric{x" );
     if ( weapon_flags & WEAPON_SHARP )        SLCAT ( buf, " {Wsharp{x" );
     if ( weapon_flags & WEAPON_VORPAL )       SLCAT ( buf, " {mvorpal{x" );
     if ( weapon_flags & WEAPON_TWO_HANDS )    SLCAT ( buf, " two-handed" );
     if ( weapon_flags & WEAPON_POISON )       SLCAT ( buf, " {gpoisoned{x" );

     return ( buf[0] != '\0' ) ? buf + 1 : "none";
}

char               *off_bit_name ( int off_flags )
{
     static char         buf[512];

     buf[0] = '\0';

     if ( off_flags & OFF_AREA_ATTACK )      SLCAT ( buf, " area attack" );
     if ( off_flags & OFF_BACKSTAB )         SLCAT ( buf, " backstab" );
     if ( off_flags & OFF_BASH )             SLCAT ( buf, " bash" );
     if ( off_flags & OFF_BERSERK )          SLCAT ( buf, " berserk" );
     if ( off_flags & OFF_DISARM )           SLCAT ( buf, " disarm" );
     if ( off_flags & OFF_DODGE )            SLCAT ( buf, " dodge" );
     if ( off_flags & OFF_FADE )             SLCAT ( buf, " fade" );
     if ( off_flags & OFF_FAST )             SLCAT ( buf, " fast" );
     if ( off_flags & OFF_KICK )             SLCAT ( buf, " kick" );
     if ( off_flags & OFF_KICK_DIRT )        SLCAT ( buf, " kick_dirt" );
     if ( off_flags & OFF_PARRY )            SLCAT ( buf, " parry" );
     if ( off_flags & OFF_RESCUE )           SLCAT ( buf, " rescue" );
     if ( off_flags & OFF_TAIL )             SLCAT ( buf, " tail" );
     if ( off_flags & OFF_TRIP )             SLCAT ( buf, " trip" );
     if ( off_flags & OFF_CRUSH )            SLCAT ( buf, " crush" );
     if ( off_flags & ASSIST_ALL )           SLCAT ( buf, " assist_all" );
     if ( off_flags & ASSIST_ALIGN )         SLCAT ( buf, " assist_align" );
     if ( off_flags & ASSIST_RACE )          SLCAT ( buf, " assist_race" );
     if ( off_flags & ASSIST_PLAYERS )       SLCAT ( buf, " assist_players" );
     if ( off_flags & ASSIST_GUARD )         SLCAT ( buf, " assist_guard" );
     if ( off_flags & ASSIST_VNUM )          SLCAT ( buf, " assist_vnum" );
     if ( off_flags & OFF_RACIST )           SLCAT ( buf, " racist" );

     return ( buf[0] != '\0' ) ? buf + 1 : "none";
}