bast/
bast/area/
bast/backup/
bast/clans/
bast/doc/MSP/
bast/doc/OLC11/
bast/doc/OLC11/doc/
bast/doc/OLC11/options/
bast/log/
bast/mobprogs/
bast/player/
/***************************************************************************
 *  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.                              *
 *                                                                         *
 *  Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David   *
 *  Love, Guilherme 'Willie' Arnold, and Mitchell Tse.                     *
 *                                                                         *
 *  EnvyMud 2.0 improvements copyright (C) 1995 by Michael Quan and        *
 *  Mitchell Tse.                                                          *
 *                                                                         *
 *  EnvyMud 2.2 improvements copyright (C) 1996, 1997 by Michael Quan.     *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

#if defined( macintosh )
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"



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



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

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

    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 )
{
    return 17 + ( ch->played + (int) ( current_time - ch->logon ) ) / 428400;

    /* 428400 assumes 30 secs/mud hour * 24 hours/day * 35 days/month *
       17 months/year - Kahn */
}

/*
 * Retrieve character's current strength.
 */
int get_curr_str( CHAR_DATA *ch )
{
    int mod;

    mod   = race_table[ch->race].str_mod;

    return URANGE( 1, (ch->perm_str * mod / 100 ) +
                        ch->mod_str, 250 );
}

/*
 * Retrieve character's maximum strength.
 */
int get_max_str( CHAR_DATA *ch )
{
    return race_table[ch->race].str_mod;
}

/*
 * Retrieve character's current intelligence.
 */
int get_curr_int( CHAR_DATA *ch )
{
    int mod;

    mod   = race_table[ch->race].int_mod;

    return URANGE( 1, (ch->perm_int * mod / 100) +
                        ch->mod_int, 250 );
}

/*
 * Retrieve character's maximum intelligence.
 */
int get_max_int( CHAR_DATA *ch )
{
    return race_table[ch->race].int_mod;
}

/*
 * Retrieve character's current wisdom.
 */
int get_curr_wis( CHAR_DATA *ch )
{
    int mod;

    mod   = race_table[ch->race].wis_mod;

    return URANGE( 1, (ch->perm_wis * mod / 100) +
                        ch->mod_wis, 250 );
}

/*
 * Retrieve character's maximum wisdom.
 */
int get_max_wis( CHAR_DATA *ch )
{
    return race_table[ch->race].wis_mod;
}

/*
 * Retrieve character's current dexterity.
 */
int get_curr_dex( CHAR_DATA *ch )
{
    int mod;

    mod   = race_table[ch->race].dex_mod;

    return URANGE( 1, (ch->perm_dex * mod / 100) +
                        ch->mod_dex, 250 );
}

/*
 * Retrieve character's maximum dexterity.
 */
int get_max_dex( CHAR_DATA *ch )
{
    return race_table[ch->race].dex_mod;
}

/*
 * Retrieve character's current constitution
 */
int get_curr_con( CHAR_DATA *ch )
{
    int mod;

    mod   = race_table[ch->race].con_mod;

    return URANGE( 1, (ch->perm_con * mod / 100) +
                        ch->mod_con, 250 );
}

/*
 * Retrieve character's maximum constitution
 */
int get_max_con( CHAR_DATA *ch )
{
    return race_table[ch->race].con_mod;
}

/*
 * Retrieve character's current agility - Veygoth.
 */
int get_curr_agi( CHAR_DATA *ch )
{
    int mod;

    mod   = race_table[ch->race].agi_mod;

    return URANGE( 1, (ch->perm_agi * mod / 100) +
                        ch->mod_agi, 250 );
}

/*
 * Retrieve character's maximum agility - Veygoth.
 */
int get_max_agi( CHAR_DATA *ch )
{
    return race_table[ch->race].agi_mod;
}

/*
 * Retrieve character's current charisma - Veygoth.
 */
int get_curr_cha( CHAR_DATA *ch )
{
    int mod;

    mod   = race_table[ch->race].cha_mod;

    return URANGE( 1, (ch->perm_cha * mod / 100) +
                        ch->mod_cha, 250 );
}

/*
 * Retrieve character's maximum charisma - Veygoth.
 */
int get_max_cha( CHAR_DATA *ch )
{
    return race_table[ch->race].cha_mod;
}

/*
 * Retrieve character's current power - Veygoth.
 */
int get_curr_pow( CHAR_DATA *ch )
{
    int mod;

    mod   = race_table[ch->race].pow_mod;

    return URANGE( 1, (ch->perm_pow * mod / 100) +
                        ch->mod_pow, 250 );
}

/*
 * Retrieve character's maximum power - Veygoth.
 */
int get_max_pow( CHAR_DATA *ch )
{
    return race_table[ch->race].pow_mod;
}

/*
 * Retrieve character's current luck - Veygoth.
 */
int get_curr_luk( CHAR_DATA *ch )
{
    int mod;

    mod   = race_table[ch->race].luk_mod;

    return URANGE( 1, ( ch->perm_luk * mod / 100) +
                         ch->mod_luk, 250 );
}

/*
 * Retrieve character's maximum luck - Veygoth.
 */
int get_max_luk( CHAR_DATA *ch )
{
    return race_table[ch->race].luk_mod;
}

/*
 * Retrieve character's current hitroll for given weapon location
 */
int get_hitroll( CHAR_DATA *ch, int wpn )
{
    OBJ_DATA    *other_wield;
    AFFECT_DATA *paf;
    int          other_wpn;
    int          hitroll;

    if ( wpn == WEAR_HAND)
        other_wpn = WEAR_HAND_2;
    else if ( wpn == WEAR_HAND_2 )
        other_wpn = WEAR_HAND;
    else
    {
        char buf [ MAX_STRING_LENGTH ];
        sprintf( buf, "get_hitroll: Invalid weapon location %d on %s.",
		wpn, ch->name );
        bug( buf, 0 );
        return 0;
    }

    hitroll = ch->hitroll + str_app[get_curr_str( ch )].tohit;
    if ( !( other_wield = get_eq_char( ch, other_wpn ) ) )
        return hitroll;

    if( other_wield->item_type != TYPE_WEAPON )
        return hitroll;

    for( paf = other_wield->pIndexData->affected; paf; paf = paf->next )
        if ( paf->location == APPLY_HITROLL )
            hitroll -= paf->modifier;
    for( paf = other_wield->affected; paf; paf = paf->next )
        if ( paf->location == APPLY_HITROLL )
            hitroll -= paf->modifier;

    return hitroll;
}



/*
 * Retrieve character's current damroll for given weapon location
 */
int get_damroll( CHAR_DATA *ch, int wpn )
{
    OBJ_DATA    *other_wield;
    AFFECT_DATA *paf;
    int          other_wpn;
    int          damroll;

    if ( wpn == WEAR_HAND)
        other_wpn = WEAR_HAND_2;
    else if ( wpn == WEAR_HAND_2 )
        other_wpn = WEAR_HAND;
    else
    {
        char buf [ MAX_STRING_LENGTH ];
        sprintf( buf, "get_damroll: Invalid weapon location %d on %s.",
		wpn, ch->name );
        bug( buf, 0 );
        return 0;
    }

    damroll = ch->damroll + str_app[get_curr_str( ch )].todam;
    if ( !( other_wield = get_eq_char( ch, other_wpn ) ) )
        return damroll;

    if( other_wield->item_type != TYPE_WEAPON )
        return damroll;

    for( paf = other_wield->pIndexData->affected; paf; paf = paf->next )
        if ( paf->location == APPLY_DAMROLL )
            damroll -= paf->modifier;
    for( paf = other_wield->affected; paf; paf = paf->next )
        if ( paf->location == APPLY_DAMROLL )
            damroll -= paf->modifier;

    return damroll;
}



/*
 * 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;

    return MAX_WEAR + 2 * get_curr_dex( ch ) / 2;
}



/*
 * 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_str( ch )].carry;
}



/*
 * See if a string is one of the names of an object.
 * New is_name sent in by Alander.
 */
bool is_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;
    }
}


/*
 * See if a string is prefix of one of the names of an object.
 */
bool is_name_prefix( const char *str, char *namelist )
{
    char name [ MAX_INPUT_LENGTH ];

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


/*
 * Apply or remove an affect to a character.
 */
void affect_modify( CHAR_DATA *ch, AFFECT_DATA *paf, bool fAdd )
{
    OBJ_DATA *wield;
    OBJ_DATA *wield2;
    char      buf [ MAX_STRING_LENGTH ];
    int       mod;
    int       count;

    mod = paf->modifier;

    if ( fAdd )
    {
        for( count = 0; count < NUM_AFFECT_VECTORS; count++ )
        {
	SET_BIT ( ch->affected_by[count], paf->bitvector[count] );
        }
    }
    else
    {
        for( count = 0; count < NUM_AFFECT_VECTORS; count++ )
        {
	REMOVE_BIT ( ch->affected_by[count], paf->bitvector[count] );
        }
	switch ( paf->location )
	{
	case APPLY_RESISTANT:	REMOVE_BIT( ch->resistant, mod );	return;
	case APPLY_IMMUNE:	REMOVE_BIT( ch->immune, mod );		return;
	case APPLY_SUSCEPTIBLE:	REMOVE_BIT( ch->susceptible, mod );	return;
	}
	mod = 0 - mod;
    }

    switch ( paf->location )
    {
    default:
        sprintf( buf, "Affect_modify: unknown location %d on %s.",
		paf->location, ch->name );
	bug ( buf, 0 );
	return;

    case APPLY_NONE:						break;
    case APPLY_STR:
	    ch->mod_str += mod;                         break;
    case APPLY_DEX:
	    ch->mod_dex += mod;                         break;
    case APPLY_INT:
	    ch->mod_int += mod;                         break;
    case APPLY_WIS:
	    ch->mod_wis += mod;                         break;
    case APPLY_CON:
	    ch->mod_con += mod;                         break;
    case APPLY_AGI:
	    ch->mod_agi += mod;                         break;
    case APPLY_CHA:
	    ch->mod_cha += mod;                         break;
    case APPLY_POW:
	    ch->mod_pow += mod;                         break;
    case APPLY_LUK:
	    ch->mod_luk += 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[0]       += mod; break;
    case APPLY_SAVING_ROD:    ch->saving_throw[1]       += mod; break;
    case APPLY_SAVING_PETRI:  ch->saving_throw[2]       += mod; break;
    case APPLY_SAVING_BREATH: ch->saving_throw[3]       += mod; break;
    case APPLY_SAVING_SPELL:  ch->saving_throw[4]       += mod; break;
    case APPLY_MAX_STR:						break;
    case APPLY_MAX_DEX:						break;
    case APPLY_MAX_INT:						break;
    case APPLY_MAX_WIS:						break;
    case APPLY_MAX_CON:						break;
    case APPLY_MAX_AGI:						break;
    case APPLY_MAX_POW:						break;
    case APPLY_MAX_CHA:						break;
    case APPLY_MAX_LUK:						break;
    case APPLY_RACE_STR:					break;
    case APPLY_RACE_DEX:					break;
    case APPLY_RACE_INT:					break;
    case APPLY_RACE_WIS:					break;
    case APPLY_RACE_CON:					break;
    case APPLY_RACE_AGI:					break;
    case APPLY_RACE_POW:					break;
    case APPLY_RACE_CHA:					break;
    case APPLY_RACE_LUK:					break;
    case APPLY_CURSE:						break;
    case APPLY_RESISTANT:     SET_BIT( ch->resistant, mod );    break;
    case APPLY_IMMUNE:        SET_BIT( ch->immune, mod );       break;
    case APPLY_SUSCEPTIBLE:   SET_BIT( ch->susceptible, mod );  break;
    case APPLY_RACE:          ch->race                  += mod; break;
    }

    /* Remove the excess general stats */
    ch->hit  = UMIN( ch->hit, ch->max_hit );
    ch->mana = UMIN( ch->mana, ch->max_mana );
    ch->move = UMIN( ch->move, ch->max_move );

    if ( IS_NPC( ch ) )
        return;

    /*
     * Check for PC weapon wielding.
     * Guard against recursion (for weapons with affects).
     * If more than one weapon, drop weapon 2 first, then recheck.
     * And yes, it does work.  :)  --- Thelonius (Monk)
     */
    if ( ( wield  = get_eq_char( ch, WEAR_HAND ) ) )
    {
	if ( ( wield2 = get_eq_char( ch, WEAR_HAND_2 ) ) )
	{
	    if ( ( ( get_obj_weight( wield ) + get_obj_weight( wield2 ) )
		  > str_app[get_curr_str( ch )].wield )
		|| !IS_SET( race_table[ ch->race ].race_abilities,
			   RACE_WEAPON_WIELD ) )
	    {
		static int depth;

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

	    }
	}
	else
	if ( ( get_obj_weight( wield ) > str_app[get_curr_str( ch )].wield )
	    || !IS_SET( race_table[ ch->race ].race_abilities,
		       RACE_WEAPON_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--;
	    }

	}
    }
    else if ( ( wield2 = get_eq_char( ch, WEAR_HAND_2 ) )
             && ( get_obj_weight( wield2 ) > str_app[get_curr_str( ch )].wield
		 || !IS_SET( race_table[ ch->race ].race_abilities,
			    RACE_WEAPON_WIELD ) ) )
    {
	static int depth;

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

    }

    return;
}



/*
 * Give an affect to a char.
 */
void affect_to_char( CHAR_DATA *ch, AFFECT_DATA *paf )
{
    AFFECT_DATA *paf_new;

    paf_new		= new_affect();

    *paf_new		= *paf;
    paf_new->deleted    = FALSE;
    paf_new->next	= ch->affected;
    ch->affected	= paf_new;

    affect_modify( ch, paf_new, TRUE );
    return;
}



/*
 * Remove an affect from a char.
 */
void affect_remove( CHAR_DATA *ch, AFFECT_DATA *paf )
{
    if ( !ch->affected )
    {
	bug( "Affect_remove: no affect.", 0 );
	return;
    }

    affect_modify( ch, paf, FALSE );

    paf->deleted = TRUE;

    return;
}



/*
 * Strip all affects of a given sn.
 */
// This is now designed to take two arguments, a skill and a spell
// argument, in that order.  One of the values must be zero.
// -- Veygoth
void affect_strip( CHAR_DATA *ch, int skl, int spl )
{
    AFFECT_DATA *paf;
    int sn;

    if( skl != 0 && spl != 0 )
    {
       bug( "Invalid call to affect_strip!  Must pass one null value!", 0 );
       return;
    }

    if( skl )
    {
        sn = skl;
    }
    else if( spl )
    {
        sn = spl;
    }
    else
    {
       bug( "Invalid call to affect_strip!  Must pass one non-null value!", 0 );
       return;
    }

    for ( paf = ch->affected; paf; paf = paf->next )
    {
        if ( paf->deleted )
	    continue;
	if ( paf->skill == sn )
	    affect_remove( ch, paf );
    }

    return;
}



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

    if( skl != 0 && spl != 0 )
    {
       bug( "Invalid call to is_affected!  Must pass one null value!", 0 );
       return FALSE;
    }

    if( !(skl > 0) && !(spl > 0))
    {
       bug( "Invalid call to is_affected!  Must pass one positive non-null value!", 0 );
       return FALSE;
    }

    if( skl )
    {
      for ( paf = ch->affected; paf; paf = paf->next )
      {
        if ( paf->deleted )
	    continue;
	if ( paf->skill == skl )
	    return TRUE;
      }
    }
    else
    {
      for ( paf = ch->affected; paf; paf = paf->next )
      {
        if ( paf->deleted )
	    continue;
	if ( paf->spell == spl )
	    return TRUE;
      }
    }

    return FALSE;
}



/*
 * Add or enhance an affect.
 */
// Checks to see if both skills and spells match.
// hopefully if one set matches nonzero values the
// other set will be zeros. - Veygoth
void affect_join( CHAR_DATA *ch, AFFECT_DATA *paf )
{
    AFFECT_DATA *paf_old;

    for ( paf_old = ch->affected; paf_old; paf_old = paf_old->next )
    {
        if ( paf_old->deleted )
	    continue;
	if ( paf_old->skill == paf->skill && paf_old->spell == paf_old->spell)
	{
	    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 )
    {
	bug( "Char_from_room: NULL.", 0 );
	return;
    }

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

    if ( ( obj = get_eq_char( ch, WEAR_HAND ) )
	&& obj->item_type == TYPE_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 )
	    bug( "Char_from_room: ch not found.", 0 );
    }

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

    if ( ch->riding )
	char_from_room( ch->riding );

    return;
}



/*
 * Move a char into a room.
 */
void char_to_room( CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex )
{
    OBJ_DATA *obj;

    if ( !pRoomIndex )
    {
	bug( "Char_to_room: NULL pRoomIndex.", 0 );
	return;
    }

    if( !ch )
    {
        bug( "Char_to_room: NULL ch.", 0 );
        return;
    }

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

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

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

    if ( ch->riding )
	char_to_room( ch->riding, pRoomIndex );

    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 ) )
    {
	bug( "Obj_from_char: null ch.", 0 );
	return;
    }

    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; prev = prev->next_content )
	{
	    if ( prev->next_content == obj )
	    {
		prev->next_content = obj->next_content;
		break;
	    }
	}

	if ( !prev )
	    bug( "Obj_from_char: obj not in list.", 0 );
    }

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



/*
 * Find the ac value of an obj, including position effect.
 */
int apply_ac( OBJ_DATA *obj, int iWear )
{
    if ( obj->item_type != TYPE_ARMOR && obj->item_type != TYPE_CLOTHING )
	return 0;

    if( obj->item_type == TYPE_SHIELD && ((iWear == WEAR_HAND) 
        || (iWear == WEAR_HAND_2)))
    {
	return     obj->value[0];
    }

    switch ( iWear )
    {
    case WEAR_BODY:     return     obj->value[0];
    case WEAR_HEAD:	return     obj->value[0];
    case WEAR_LEGS:	return     obj->value[0];
    case WEAR_FEET:	return     obj->value[0];
    case WEAR_HANDS:	return     obj->value[0];
    case WEAR_ARMS:	return     obj->value[0];
    case WEAR_FINGER_L:	return     obj->value[0];
    case WEAR_FINGER_R: return     obj->value[0];
    case WEAR_NECK_1:	return     obj->value[0];
    case WEAR_NECK_2:	return     obj->value[0];
    case WEAR_ABOUT:	return     obj->value[0];
    case WEAR_WAIST:	return     obj->value[0];
    case WEAR_WRIST_L:	return     obj->value[0];
    case WEAR_WRIST_R:	return     obj->value[0];
    case WEAR_EYES:     return     obj->value[0];
    case WEAR_FACE:     return     obj->value[0];
    case WEAR_EAR_L:    return     obj->value[0];
    case WEAR_EAR_R:	return     obj->value[0];
    case WEAR_BADGE:    return     obj->value[0];
    case WEAR_QUIVER:   return     obj->value[0];
    case WEAR_ONBACK:   return     obj->value[0];
    }

    return 0;
}



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

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

    return NULL;
}



/*
 * Equip a char with an obj.
 */
void equip_char( CHAR_DATA *ch, OBJ_DATA *obj, int iWear )
{
    AFFECT_DATA *paf;
    char         buf [ MAX_STRING_LENGTH ];

    if ( get_eq_char( ch, iWear ) )
    {
        sprintf( buf, "Equip_char: %s already equipped at %d.",
		ch->name, iWear );
	bug( buf, 0 );
	return;
    }

    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;
    }

    ch->armor      	-= apply_ac( obj, iWear );
    obj->wear_loc	 = iWear;

    for ( paf = obj->pIndexData->affected; paf; paf = paf->next )
	affect_modify( ch, paf, TRUE );
    for ( paf = obj->affected; paf; paf = paf->next )
	affect_modify( ch, paf, TRUE );

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

    return;
}



/*
 * Unequip a char with an obj.
 */
void unequip_char( CHAR_DATA *ch, OBJ_DATA *obj )
{
    AFFECT_DATA *paf;
    char         buf [ MAX_STRING_LENGTH ];

    if ( obj->wear_loc == WEAR_NONE )
    {
        sprintf( buf, "Unequip_char: %s already unequipped with %d.",
		ch->name, obj->pIndexData->vnum );
	bug( buf, 0 );
	return;
    }

    ch->armor		+= apply_ac( obj, obj->wear_loc );
    obj->wear_loc	 = -1;

    for ( paf = obj->pIndexData->affected; paf; paf = paf->next )
	affect_modify( ch, paf, FALSE );
    for ( paf = obj->affected; paf; paf = paf->next )
	affect_modify( ch, paf, FALSE );

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

    return;
}



/*
 * Count occurrences of an obj in a list.
 */
int count_obj_list( OBJ_INDEX_DATA *pObjIndex, OBJ_DATA *list )
{
    OBJ_DATA *obj;
    int       nMatch;

    nMatch = 0;
    for ( obj = list; obj; obj = obj->next_content )
    {
        if ( obj->deleted )
	    continue;
	if ( obj->pIndexData == pObjIndex )
	    nMatch++;
    }

    return nMatch;
}



/*
 * 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 ) )
    {
	bug( "obj_from_room: NULL.", 0 );
	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 )
	{
	    bug( "Obj_from_room: obj not found.", 0 );
	    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 )
{
    if ( obj_to->deleted )
    {
	bug( "Obj_to_obj:  Obj_to already deleted", 0 );
        return;
    }

    obj->next_content		= obj_to->contains;
    obj_to->contains		= obj;
    obj->in_obj			= obj_to;
    obj->in_room		= NULL;
    obj->carried_by		= NULL;

    for ( ; obj_to; obj_to = obj_to->in_obj )
    {
        if ( obj_to->deleted )
	    continue;
	if ( obj_to->carried_by )
	{
	    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 ) )
    {
	bug( "Obj_from_obj: null obj_from.", 0 );
	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 )
	{
	    bug( "Obj_from_obj: obj not found.", 0 );
	    return;
	}
    }

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

    for ( ; obj_from; obj_from = obj_from->in_obj )
    {
        if ( obj_from->deleted )
	    continue;
	if ( obj_from->carried_by )
	{
	    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 )
{
           OBJ_DATA *obj_content;
           OBJ_DATA *obj_next;
    extern bool      delete_obj;

    if ( obj->deleted )
    {
	bug( "Extract_obj:  Obj already deleted", 0 );
	return;
    }

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

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

    obj->deleted = TRUE;

    delete_obj   = TRUE;
    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;
    extern bool       delete_char;

    if ( !ch->in_room )
    {
	bug( "Extract_char: NULL.", 0 );
	return;
    }

    if ( ch->fighting )
        stop_fighting( ch, TRUE );

    if ( fPull )
    {
	char* name;

	if ( IS_NPC ( ch ) )
	    name = ch->short_descr;
	else
	    name = ch->name;

	die_follower( ch, name );

	/* Get rid of weapons _first_ 
	   - from Erwin Andreasen <erwin@pip.dknet.dk> */

	{
	    OBJ_DATA *obj, *obj2;

	    obj  = get_eq_char( ch, WEAR_HAND   );
	    obj2 = get_eq_char( ch, WEAR_HAND_2 );

	    if ( obj )
	        extract_obj( obj );

	    /* Now kill obj2 if it exists no matter if on body or floor */
	    if ( obj2 )
	        extract_obj( obj2 );

	}

	for ( obj = ch->carrying; obj; obj = obj_next )
	{
	    obj_next = obj->next_content;
	    if ( obj->deleted )
	      continue;
	    extract_obj( obj );
	}
     }
    
    char_from_room( ch );

    forget_all( ch );

    if ( !fPull )
    {
        ROOM_INDEX_DATA *location;

        if( !IS_NPC( ch ) && (ch->race < MAX_PC_RACE) && (ch->class < MAX_CLASS))
        {
	  if ( !( location = get_room_index( repop_point[ch->race][ch->class] ) ) )
	  {
	    bug( "Starting room does not exist for class %d of player's race!", ch->class );
	    char_to_room( ch, get_room_index( ROOM_VNUM_ALTAR ) );
	  }
        }
	else
        {
	  if ( !( location = get_room_index( ROOM_VNUM_START ) ) )
	  {
	    bug( "Starting room %d does not exist!", ROOM_VNUM_START );
	    char_to_room( ch, get_room_index( ROOM_VNUM_ALTAR ) );
	  }
          else
	    char_to_room( ch, get_room_index( ROOM_VNUM_START) );
        }
	return;
    }

    if ( IS_NPC( ch ) )
    {
	--ch->pIndexData->count;
    }
    else
    {
        ch->pcdata->consent = NULL;
        ch->pcdata->guarding = NULL;
    }

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

    for ( wch = char_list; wch; wch = wch->next )
    {
	if ( wch->reply == ch )
	    wch->reply = NULL;
        if ( !IS_NPC( wch ) && wch->pcdata->consent == ch )
        {
            wch->pcdata->consent = NULL;
            act( "You stop consenting $N&n.", wch, NULL, ch, TO_CHAR );
        }
        if ( !IS_NPC( wch ) && wch->pcdata->guarding == ch )
        {
            wch->pcdata->guarding = NULL;
            act( "You stop guarding $N&n.", wch, NULL, ch, TO_CHAR );
        }
    }

    ch->deleted = TRUE;

    if ( ch->desc )
	ch->desc->character = NULL;

    delete_char = TRUE;
    return;
}



/*
 * Find a char in the room.
 */
// Veygoth - made "me" another alias for "self"
CHAR_DATA *get_char_room( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *rch;
    char       arg [ MAX_INPUT_LENGTH ];
    int        number;
    int        count;

    number = number_argument( argument, arg );
    count  = 0;
    if ( !str_cmp( arg, "self" ) || !str_cmp( arg, "me" ) )
	return ch;
    for ( rch = ch->in_room->people; rch; rch = rch->next_in_room )
    {
	if ( !can_see( ch, rch ) || !is_name( arg, rch->name ) )
	    continue;
	if ( ++count == number )
	    return rch;
    }

    return NULL;
}




/*
 * Find a char in an area.
 */
CHAR_DATA *get_char_area( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *ach;
    char       arg [ MAX_INPUT_LENGTH ];
    int        number;
    int        count;

    if ( ( ach = get_char_room( ch, argument ) ) )
	return ach;

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

    return NULL;
}

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

    if ( ( wch = get_char_room( ch, argument ) ) )
	return wch;

    number = number_argument( argument, arg );
    count  = 0;
    for ( wch = char_list; wch ; wch = wch->next )
    {
	if ( !can_see( ch, wch ) || !is_name( 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; obj = obj->next )
    {
        if ( obj->deleted )
	    continue;

	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 )
{
    OBJ_DATA *obj;
    char      arg [ MAX_INPUT_LENGTH ];
    int       number;
    int       count;

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

    count  = 0;
    for ( obj = list; obj; obj = obj->next_content )
    {
	if ( can_see_obj( ch, obj ) && is_name_prefix( 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 )
{
    OBJ_DATA *obj;
    char      arg [ MAX_INPUT_LENGTH ];
    int       number;
    int       count;

    number = number_argument( argument, arg );
    count  = 0;
    for ( obj = ch->carrying; obj; obj = obj->next_content )
    {
	if ( obj->wear_loc == WEAR_NONE
	    && can_see_obj( ch, obj )
	    && is_name( arg, obj->name ) )
	{
	    if ( ++count == number )
		return obj;
	}
    }

    count  = 0;
    for ( obj = ch->carrying; obj; obj = obj->next_content )
    {
	if ( obj->wear_loc == WEAR_NONE
	    && can_see_obj( ch, obj )
	    && is_name_prefix( 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 )
{
    OBJ_DATA *obj;
    char      arg [ MAX_INPUT_LENGTH ];
    int       number;
    int       count;

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

    count  = 0;
    for ( obj = ch->carrying; obj; obj = obj->next_content )
    {
	if ( obj->wear_loc != WEAR_NONE
	    && can_see_obj( ch, obj )
	    && is_name_prefix( 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, char *argument )
{
    OBJ_DATA *obj;

    obj = get_obj_list( ch, argument, ch->in_room->contents );
    if ( obj )
	return obj;

    if ( ( obj = get_obj_carry( ch, argument ) ) )
	return obj;

    if ( ( obj = get_obj_wear( ch, argument ) ) )
	return obj;

    return NULL;
}



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

    if ( ( obj = get_obj_here( ch, argument ) ) )
	return obj;

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

    count  = 0;
    for ( obj = object_list; obj; obj = obj->next )
    {
	if ( can_see_obj( ch, obj ) && is_name_prefix( arg, obj->name ) )
	{
	    if ( ++count == number )
		return obj;
	}
    }

    return NULL;
}



/*
 * Create a 'money' obj.
 */
OBJ_DATA *create_money( int copper, int silver, int gold, int platinum )
{
    OBJ_DATA *obj;

    int amount;

    amount = copper + silver + gold + platinum;

    if ( copper < 0 || silver < 0 || gold < 0 || platinum < 0 || amount == 0)
    {
	bug( "Create_money: zero or negative money %d.", amount );
        copper = 1;
        silver = 0;
        gold = 0;
        platinum = 0;
        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 );
    }

    obj->value[0]		= copper;
    obj->value[1]               = silver;
    obj->value[2]               = gold;
    obj->value[3]               = platinum;
    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;

    number = 0;
    if ( obj->item_type == TYPE_CONTAINER )
        for ( obj = obj->contains; obj; obj = obj->next_content )
	{
	    if ( obj->deleted )
	        continue;
	    number += get_obj_number( obj );
	}
    else
	number = 1;

    return number;
}



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

    weight = obj->weight;
    for ( obj = obj->contains; obj; obj = obj->next_content )
    {
	if ( obj->deleted )
	    continue;
	weight += get_obj_weight( obj );
    }

    return weight;
}



/*
 * True if room is dark.
 */
bool room_is_dark( ROOM_INDEX_DATA *pRoomIndex )
{
    OBJ_DATA *obj;

    if( !pRoomIndex )
    {
        bug( "Error in room_is_dark: Null pRoomIndex", 0 );
        return FALSE;
    }

    if ( pRoomIndex->light > 0 )
	return FALSE;

    // Magic light overcomes magic darkness.  May want to cause
    // these flags to cancel each other out if both are set - Veygoth
    if ( IS_SET( pRoomIndex->room_flags, ROOM_MAGICLIGHT ) )
	return FALSE;

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

    // You can always see in a twilight room - Veygoth
    if ( IS_SET( pRoomIndex->room_flags, ROOM_TWILIGHT ) )
	return FALSE;

    for ( obj = pRoomIndex->contents; obj; obj = obj->next_content )
    {
	if ( obj->deleted )
	    continue;
	if ( obj->item_type == TYPE_LIGHT && obj->value[2] != 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; rch = rch->next_in_room )
    {
	if ( rch->deleted )
	    continue;

	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;
}



/*
 * True if char can see victim.
 */
bool can_see( CHAR_DATA *ch, CHAR_DATA *victim )
{
    if ( victim->deleted )
        return FALSE;

    if ( ch == victim )
	return TRUE;

    /* All mobiles cannot see wizinvised immorts */
    if ( IS_NPC( ch )
	&& !IS_NPC( victim ) && IS_SET( victim->act, PLR_WIZINVIS ) )
        return FALSE;
	
    if ( !IS_NPC( victim )
	&& IS_SET( victim->act, PLR_WIZINVIS )
	&& get_trust( ch ) < get_trust( victim ) )
	return FALSE;

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

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

    if ( room_is_dark( ch->in_room )
	&& !IS_SET( race_table[ ch->race ].race_abilities, RACE_ULTRAVISION )
	&& !IS_AFFECTED( ch, AFF_ULTRAVISION )
	&& !IS_SET( race_table[ ch->race ].race_abilities, RACE_INFRAVISION )
	&& !IS_AFFECTED( ch, AFF_INFRARED ) )
	return FALSE;

    if ( victim->position == POS_DEAD )
        return TRUE;

    if ( IS_AFFECTED( victim, AFF_INVISIBLE )
	&& !IS_SET( race_table[ ch->race ].race_abilities, RACE_DETECT_INVIS )
	&& !IS_AFFECTED( ch, AFF_DETECT_INVIS ) )
	return FALSE;

    if ( IS_AFFECTED( victim, AFF_HIDE )
	&& !IS_SET( race_table[ ch->race ].race_abilities, RACE_DETECT_HIDDEN )
	&& !IS_AFFECTED( ch, AFF_DETECT_HIDDEN )
	&& !victim->fighting )
	return FALSE;

    return TRUE;
}



/*
 * True if char can see obj.
 */
bool can_see_obj( CHAR_DATA *ch, OBJ_DATA *obj )
{
    if ( obj->deleted )
        return FALSE;

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

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

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

    if ( room_is_dark( ch->in_room )
	&& !IS_SET( race_table[ ch->race ].race_abilities, RACE_ULTRAVISION )
	&& !IS_AFFECTED( ch, AFF_ULTRAVISION ) )
	return FALSE;

    if ( IS_OBJ_STAT( obj, ITEM_INVIS )
	&& !IS_SET( race_table[ ch->race ].race_abilities, RACE_DETECT_INVIS )
	&& !IS_AFFECTED( ch, AFF_DETECT_INVIS ) )
	return FALSE;

    return TRUE;
}



/*
 * True if char can drop obj.
 */
bool can_drop_obj( CHAR_DATA *ch, OBJ_DATA *obj )
{
    if ( !IS_OBJ_STAT( obj, 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 )
{
    OBJ_DATA *in_obj;
    char      buf [ MAX_STRING_LENGTH ];

    switch ( obj->item_type )
    {
    case TYPE_LIGHT:		return "light";
    case TYPE_SCROLL:		return "scroll";
    case TYPE_WAND:		return "wand";
    case TYPE_STAFF:		return "staff";
    case TYPE_WEAPON:		return "weapon";
    case TYPE_TREASURE:		return "treasure";
    case TYPE_ARMOR:		return "armor";
    case TYPE_POTION:		return "potion";
    case TYPE_OTHER:		return "other";
    case TYPE_TRASH:		return "trash";
    case TYPE_CONTAINER:	return "container";
    case TYPE_DRINK_CON:	return "drink container";
    case TYPE_KEY:		return "key";
    case TYPE_FOOD:		return "food";
    case TYPE_MONEY:		return "money";
    case TYPE_BOAT:		return "boat";
    case TYPE_CORPSE_NPC:	return "npc corpse";
    case TYPE_CORPSE_PC:        return "pc corpse";
    case TYPE_FOUNTAIN:		return "fountain";
    case TYPE_PILL:		return "pill";
    case TYPE_PORTAL:		return "portal";
    case TYPE_CLOTHING:		return "clothing";
    }

    for ( in_obj = obj; in_obj->in_obj; in_obj = in_obj->in_obj )
      ;

    if ( in_obj->carried_by )
      sprintf( buf, "Item_type_name: unknown type %d from %s owned by %s.",
	      obj->item_type, obj->name, obj->carried_by->name );
    else
      sprintf( buf,
	      "Item_type_name: unknown type %d from %s owned by (unknown).",
	      obj->item_type, obj->name );

    bug( buf, 0 );
    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_HEIGHT:          return "height";
    case APPLY_WEIGHT:          return "weight";
    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 FIRE_PROT:		return "fire protection";
    case APPLY_AGI:             return "agility";
    case APPLY_CHA:             return "charisma";
    case APPLY_POW:             return "power";
    case APPLY_LUK:             return "luck";
    case APPLY_MAX_STR:		return "max strength";
    case APPLY_MAX_DEX:		return "max dexterity";
    case APPLY_MAX_INT:		return "max intelligence";
    case APPLY_MAX_WIS:		return "max wisdom";
    case APPLY_MAX_CON:		return "max constitution";
    case APPLY_MAX_AGI:		return "max agility";
    case APPLY_MAX_POW:		return "max power";
    case APPLY_MAX_CHA:		return "max charisma";
    case APPLY_MAX_LUK:		return "max luck";
    case APPLY_RACE_STR:	return "racial strength";
    case APPLY_RACE_DEX:	return "racial dexterity";
    case APPLY_RACE_INT:	return "racial intelligence";
    case APPLY_RACE_WIS:	return "racial wisdom";
    case APPLY_RACE_CON:	return "racial constitution";
    case APPLY_RACE_AGI:	return "racial agility";
    case APPLY_RACE_POW:	return "racial power";
    case APPLY_RACE_CHA:	return "racial charisma";
    case APPLY_RACE_LUK:	return "racial luck";
    case APPLY_CURSE:		return "curse";
    case APPLY_RESISTANT:	return "resistant";
    case APPLY_IMMUNE:		return "immune";
    case APPLY_SUSCEPTIBLE:	return "susceptible";
    case APPLY_RACE:		return "race";
    }

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



/*
 * Return ascii name of an affect bit vector.
 */
char *affect_bit_name( int vector[NUM_AFFECT_VECTORS] )
{
    static char buf [ 512 ];

    buf[0] = '\0';
    if ( vector[AFF_BLIND.group] & AFF_BLIND.vector )
	 strcat( buf, " blind" );
    if ( vector[AFF_AWARE.group] & AFF_AWARE.vector )
         strcat( buf, " aware" );
    if ( vector[AFF_ULTRAVISION.group] & AFF_ULTRAVISION.vector )
         strcat( buf, " ultravision" );
    if ( vector[AFF_IS_FLEEING.group] & AFF_IS_FLEEING.vector )
         strcat( buf, " fleeing" );
    if ( vector[AFF_LEVITATE.group] & AFF_LEVITATE.vector )
	 strcat( buf, " levitate" );
    if ( vector[AFF_SKL_AWARE.group] & AFF_SKL_AWARE.vector )
         strcat( buf, " skl_aware" );
    if ( vector[AFF_STONESKIN.group] & AFF_STONESKIN.vector )
         strcat( buf, " stoneskin" );
/* JPG    if ( vector[AFF_SUMMONED.group] & AFF_SUMMONED.vector )
         strcat( buf, " summoned" ); removed until added to bit.c */
    if ( vector[AFF_PLAGUE.group] & AFF_PLAGUE.vector )
         strcat( buf, " plague" );
    if ( vector[AFF_INVISIBLE.group] & AFF_INVISIBLE.vector )
	 strcat( buf, " invisible"      );
    if ( vector[AFF_DETECT_EVIL.group] & AFF_DETECT_EVIL.vector )
	 strcat( buf, " detect_evil"    );
    if ( vector[AFF_DETECT_GOOD.group] & AFF_DETECT_GOOD.vector )
	 strcat( buf, " detect_good"    );
    if ( vector[AFF_DETECT_INVIS.group] & AFF_DETECT_INVIS.vector )
	 strcat( buf, " detect_invis"   );
    if ( vector[AFF_DETECT_MAGIC.group] & AFF_DETECT_MAGIC.vector )
	 strcat( buf, " detect_magic"   );
    if ( vector[AFF_DETECT_HIDDEN.group] & AFF_DETECT_HIDDEN.vector )
	 strcat( buf, " detect_hidden"  );
    if ( vector[AFF_HOLD.group] & AFF_HOLD.vector )
	 strcat( buf, " hold"           );
    if ( vector[AFF_SANCTUARY.group] & AFF_SANCTUARY.vector )
	 strcat( buf, " sanctuary"      );
    if ( vector[AFF_FAERIE_FIRE.group] & AFF_FAERIE_FIRE.vector )
	 strcat( buf, " faerie_fire"    );
    if ( vector[AFF_INFRARED.group] & AFF_INFRARED.vector )
	 strcat( buf, " infrared"       );
    if ( vector[AFF_CURSE.group] & AFF_CURSE.vector )
	 strcat( buf, " curse"          );
    if ( vector[AFF_CHANGE_SEX.group] & AFF_CHANGE_SEX.vector )
	 strcat( buf, " change_sex"     );
    if ( vector[AFF_POISON.group] & AFF_POISON.vector )
	 strcat( buf, " poison"         );
    if ( vector[AFF_PROTECT_EVIL.group] & AFF_PROTECT_EVIL.vector )
	 strcat( buf, " protect_evil"   );
    if ( vector[AFF_PROTECT_GOOD.group] & AFF_PROTECT_GOOD.vector )
	 strcat( buf, " protect_good"   );
    if ( vector[AFF_POLYMORPH.group] & AFF_POLYMORPH.vector )
	 strcat( buf, " polymorph"      );
    if ( vector[AFF_SLEEP.group] & AFF_SLEEP.vector )
	 strcat( buf, " sleep"          );
    if ( vector[AFF_SNEAK.group] & AFF_SNEAK.vector )
	 strcat( buf, " sneak"          );
    if ( vector[AFF_HIDE.group] & AFF_HIDE.vector )
	 strcat( buf, " hide"           );
    if ( vector[AFF_CHARM.group] & AFF_CHARM.vector )
	 strcat( buf, " charm"          );
    if ( vector[AFF_FLYING.group] & AFF_FLYING.vector )
	 strcat( buf, " flying"         );
    if ( vector[AFF_PASS_DOOR.group] & AFF_PASS_DOOR.vector )
	 strcat( buf, " pass_door"      );
    if ( vector[AFF_MUTE.group] & AFF_MUTE.vector )
	 strcat( buf, " mute"           );
    if ( vector[AFF_GILLS.group] & AFF_GILLS.vector )
	 strcat( buf, " gills"          );
    if ( vector[AFF_VAMP_BITE.group] & AFF_VAMP_BITE.vector )
	 strcat( buf, " vampiric curse" );
    if ( vector[AFF_GHOUL.group] & AFF_GHOUL.vector )
	 strcat( buf, " ghoulic curse"  );
    if ( vector[AFF_FLAMING.group] & AFF_FLAMING.vector )
	 strcat( buf, " flaming shield" );
/* JPG    if ( vector[AFF_WATERWALK.group] & AFF_WATERWALK.vector )
         strcat( buf, " waterwalk" ); removed until added to bit.c */

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



/*
 * Return ascii name of extra flags vector.
 * 
 * These have not yet been updated to the new bit system.
 */
char *extra_bit_name( OBJ_DATA *obj )
{
    static char buf [ 512 ];

    buf[0] = '\0';
    if ( IS_OBJ_STAT( obj, ITEM_GLOW )) strcat( buf, " glow" );
    if ( IS_OBJ_STAT( obj, ITEM_HUM )) strcat( buf, " hum" );
    if ( IS_OBJ_STAT( obj, ITEM_EVIL )) strcat( buf, " evil" );
    if ( IS_OBJ_STAT( obj, ITEM_INVIS )) strcat( buf, " invis" );
    if ( IS_OBJ_STAT( obj, ITEM_MAGIC )) strcat( buf, " magic" );
    if ( IS_OBJ_STAT( obj, ITEM_NODROP )) strcat( buf, " nodrop" );
    if ( IS_OBJ_STAT( obj, ITEM_BLESS )) strcat( buf, " bless" );
    if ( IS_OBJ_STAT( obj, ITEM_ANTI_GOOD )) strcat( buf, " anti-good" );
    if ( IS_OBJ_STAT( obj, ITEM_ANTI_EVIL )) strcat( buf, " anti-evil" );
    if ( IS_OBJ_STAT( obj, ITEM_ANTI_NEUTRAL )) strcat( buf, " anti-neutral" );
    if ( IS_OBJ_STAT( obj, ITEM_INVENTORY )) strcat( buf, " inventory" );
    if ( IS_OBJ_STAT( obj, ITEM_POISONED )) strcat( buf, " poisoned" );
    if ( IS_OBJ_STAT( obj, ITEM_BLESS )) strcat( buf, " bless" );
    return ( buf[0] != '\0' ) ? buf+1 : "none";
}

/*
 * Return ascii name of parts vector.
 */
char *parts_bit_name( int vector )
{
    static char buf [ 512 ];

    buf[0] = '\0';
    if ( vector & PART_HEAD         ) strcat( buf, " head"           );
    if ( vector & PART_ARMS         ) strcat( buf, " arms"           );
    if ( vector & PART_LEGS         ) strcat( buf, " legs"           );
    if ( vector & PART_HEART        ) strcat( buf, " heart"          );
    if ( vector & PART_BRAINS       ) strcat( buf, " brains"         );
    if ( vector & PART_GUTS         ) strcat( buf, " guts"           );
    if ( vector & PART_HANDS        ) strcat( buf, " hands"          );
    if ( vector & PART_FEET         ) strcat( buf, " feet"           );
    if ( vector & PART_FINGERS      ) strcat( buf, " fingers"        );
    if ( vector & PART_EAR          ) strcat( buf, " ears"           );
    if ( vector & PART_EYE          ) strcat( buf, " eyes"           );
    if ( vector & PART_LONG_TONGUE  ) strcat( buf, " tongue"    );
    if ( vector & PART_EYESTALKS    ) strcat( buf, " eyestalks"      );
    if ( vector & PART_TENTACLES    ) strcat( buf, " tentacles"      );
    if ( vector & PART_FINS         ) strcat( buf, " fins"           );
    if ( vector & PART_WINGS        ) strcat( buf, " wings"          );
    if ( vector & PART_TAIL         ) strcat( buf, " tail"           );
    if ( vector & PART_CLAWS        ) strcat( buf, " claws"          );
    if ( vector & PART_FANGS        ) strcat( buf, " fangs"          );
    if ( vector & PART_HORNS        ) strcat( buf, " horns"          );
    if ( vector & PART_SCALES       ) strcat( buf, " scales"         );
    if ( vector & PART_TUSKS        ) strcat( buf, " tusks"          );

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



/*
 * Return ascii name of a ris vector.
 */
char *ris_bit_name( int vector )
{
    static char buf [ 512 ];

    buf[0] = '\0';
    if ( vector & RIS_FIRE          ) strcat( buf, " fire"           );
    if ( vector & RIS_COLD          ) strcat( buf, " cold"           );
    if ( vector & RIS_ELECTRICITY   ) strcat( buf, " electricity"    );
    if ( vector & RIS_ENERGY        ) strcat( buf, " energy"         );
    if ( vector & RIS_ACID          ) strcat( buf, " acid"           );
    if ( vector & RIS_POISON        ) strcat( buf, " poison"         );
    if ( vector & RIS_CHARM         ) strcat( buf, " charm"          );
    if ( vector & RIS_MENTAL        ) strcat( buf, " mental"         );
    if ( vector & RIS_WHITE_MANA    ) strcat( buf, " white_mana"     );
    if ( vector & RIS_BLACK_MANA    ) strcat( buf, " black_mana"     );
    if ( vector & RIS_DISEASE       ) strcat( buf, " disease"        );
    if ( vector & RIS_DROWNING      ) strcat( buf, " drowning"       );
    if ( vector & RIS_LIGHT         ) strcat( buf, " light"          );
    if ( vector & RIS_SOUND         ) strcat( buf, " sound"          );
    if ( vector & RIS_MAGIC         ) strcat( buf, " magic"          );
    if ( vector & RIS_NONMAGIC      ) strcat( buf, " nonmagic"       );
    if ( vector & RIS_SILVER        ) strcat( buf, " silver"         );
    if ( vector & RIS_IRON          ) strcat( buf, " iron"           );
    if ( vector & RIS_WOOD          ) strcat( buf, " wood"           );
    if ( vector & RIS_WEAPON        ) strcat( buf, " weapon"         );
    if ( vector & RIS_BASH          ) strcat( buf, " bash"           );
    if ( vector & RIS_PIERCE        ) strcat( buf, " pierce"         );
    if ( vector & RIS_SLASH         ) strcat( buf, " slash"          );

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



CHAR_DATA *get_char( CHAR_DATA *ch )
{
    if ( !ch->pcdata )
        return ch->desc->original;
    else
        return ch;
}

bool longstring( CHAR_DATA *ch, char *argument )
{
    if ( strlen( argument) > 60 )
    {
	send_to_char( "No more than 60 characters in this field.\n\r", ch );
	return TRUE;
    }
    else
        return FALSE;
}

bool authorized( CHAR_DATA *ch, char *skllnm )
{

    char buf [ MAX_STRING_LENGTH ];

    if ( ( !IS_NPC( ch ) && str_infix( skllnm, ch->pcdata->immskll ) )
	||  IS_NPC( ch ) )
    {
        sprintf( buf, "Sorry, you are not authorized to use %s.\n\r", skllnm );
	send_to_char( buf, ch );
	return FALSE;
    }

    return TRUE;

}

void end_of_game( void )
{
    DESCRIPTOR_DATA *d;
    DESCRIPTOR_DATA *d_next;

    for ( d = descriptor_list; d; d = d_next )
    {
	d_next = d->next;
	if ( d->connected == CON_PLAYING )
	{
	    if ( d->character->position == POS_FIGHTING )
	      interpret( d->character, "save" );
	    else
	      do_quit( d->character, "" );
	}
	else
	    close_socket( d );
    }

    return;

}

int race_lookup( const char *race )
{
    int index;

    for ( index = 0; index < MAX_RACE; index++ )
        if ( !str_prefix( race, race_table[index].name ) )
	    return index;

    return -1;

}

int race_key_lookup( const char *race )
{
    int index;

    for ( index = 0; index < MAX_RACE; index++ )
        if ( !str_cmp( race, race_table[index].key ) )
	    return index;

    return -1;

}

int race_full_lookup( const char *race )
{
    int index;

    for ( index = 0; index < MAX_RACE; index++ )
        if ( !str_cmp( race, race_table[index].name ) )
            return index;

    return NO_FLAG;

}

int skill_affect_lookup( const char *affectname )
{
    int index;

    for ( index = 0; index < MAX_SKILL; index++ )
	if ( !str_cmp( affectname, skills_table[index].name ) )
	    return index;

    return -1;

}

int spell_affect_lookup( const char *affectname )
{
    int index;

    for ( index = 0; index < MAX_SPELL; index++ )
	if ( !str_cmp( affectname, spells_table[index].name ) )
	    return index;

    return -1;

}

/*
 * Lookup a clan by name.
 */
CLAN_DATA *clan_lookup( const char *name )
{
    CLAN_DATA *clan;

    for ( clan = clan_first ; clan; clan = clan->next )
    {
	if ( !clan->name )
	    break;
	if ( LOWER( name[0] ) == LOWER( clan->name[0] )
	    && !str_prefix( name, clan->name ) )
	    return clan;
    }

    return NULL;
}

/*
  14k42 = 14 * 1000 + 14 * 100 + 2 * 10 = 14420

  Of course, it only pays off to use that notation when you can skip many 0's.
  There is not much point in writing 66k666 instead of 66666, except maybe
  when you want to make sure that you get 66,666.

  More than 3 (in case of 'k') or 6 ('m') digits after 'k'/'m' are automatically
  disregarded. Example:

  14k1234 = 14,123

  If the number contains any other characters than digits, 'k' or 'm', the
  function returns 0. It also returns 0 if 'k' or 'm' appear more than
  once.

  the pointer to buffer stuff is not really necessary, but originally I
  modified the buffer, so I had to make a copy of it. What the hell, it
  works :) (read: it seems to work :)
*/
int advatoi( const char *s )
{
    int number		= 0;
    int multiplier	= 0;

    /*
     * as long as the current character is a digit add to current number.
     */
    while ( isdigit( s[0] ) )
        number = ( number * 10 ) + ( *s++ - '0' );

    switch (UPPER(s[0]))
    {
        case 'K'  : number *= ( multiplier = 1000 );      ++s; break;
        case 'M'  : number *= ( multiplier = 1000000 );   ++s; break;
        case '\0' : break;
        default   : return 0; /* not k nor m nor NULL - return 0! */
    }

    /* if any digits follow k/m, add those too */
    while ( isdigit( s[0] ) && ( multiplier > 1 ) )
    {
        /* the further we get to right, the less the digit 'worth' */
        multiplier /= 10;
        number = number + ( ( *s++ - '0' ) * multiplier );
    }

    /* return 0 if non-digit character was found, other than NULL */
    if ( s[0] != '\0' && !isdigit( s[0] ) )
        return 0;

    /* anything left is likely extra digits (ie: 14k4443  -> 3 is extra) */

    return number;
}

/*
 * For resistant, immune, and susceptible.
 * The 'globals' (magic and weapons) may be overriden.
 * Three other cases -- wood, silver, and iron -- will be checked in fight.c
 * RIS was mostly based from ROM2.4 code by Russ Taylor <rtaylor@efn.org>
 */
int check_ris( CHAR_DATA *ch, int dam_type )
{
    int ris;
    int def;
    int bit;
    int resistant;
    int immune;
    int susceptible;


    ris = -1;
    def = IS_NORMAL;

    if ( dam_type == DAM_NONE )
        return ris;

    resistant   = ch->resistant   | race_table[ ch->race ].resistant;
    immune      = ch->immune      | race_table[ ch->race ].immune;
    susceptible = ch->susceptible | race_table[ ch->race ].susceptible;

    if ( dam_type < DAM_OTHER )
    {
	     if ( IS_SET( resistant, RIS_WEAPON ) )
	    def = IS_RESISTANT;
	else if ( IS_SET( immune, RIS_WEAPON ) )
	    def = IS_IMMUNE;
	else if ( IS_SET( susceptible, RIS_WEAPON ) )
	    def = IS_SUSCEPTIBLE;
    }
    else
    {
	     if ( IS_SET( resistant, RIS_MAGIC ) )
	    def = IS_RESISTANT;
	else if ( IS_SET( immune, RIS_MAGIC ) )
	    def = IS_IMMUNE;
	else if ( IS_SET( susceptible, RIS_MAGIC ) )
	    def = IS_SUSCEPTIBLE;
    }

    switch ( dam_type )
    {
    default:			return def;
    case DAM_FIRE:		bit = RIS_FIRE;		break;
    case DAM_COLD:		bit = RIS_COLD;		break;
    case DAM_ELECTRICITY:	bit = RIS_ELECTRICITY;	break;
    case DAM_ACID:		bit = RIS_ACID;		break;
    case DAM_POISON:		bit = RIS_POISON;	break;
    case DAM_CHARM:		bit = RIS_CHARM;	break;
    case DAM_MENTAL:		bit = RIS_MENTAL;	break;
    case DAM_ENERGY:		bit = RIS_ENERGY;	break;
    case DAM_WHITE_MANA:	bit = RIS_WHITE_MANA;	break;
    case DAM_BLACK_MANA:	bit = RIS_BLACK_MANA;	break;
    case DAM_DISEASE:		bit = RIS_DISEASE;	break;
    case DAM_DROWNING:		bit = RIS_DROWNING;	break;
    case DAM_LIGHT:		bit = RIS_LIGHT;	break;
    case DAM_SOUND:		bit = RIS_SOUND;	break;
    case DAM_BASH:		bit = RIS_BASH;		break;
    case DAM_PIERCE:		bit = RIS_PIERCE;	break;
    case DAM_SLASH:		bit = RIS_SLASH;	break;
    }

         if ( IS_SET( immune, bit ) )
	ris = IS_IMMUNE;
    else if ( IS_SET( resistant, bit ) && ris != IS_IMMUNE )
	ris = IS_RESISTANT;
    else if ( IS_SET( susceptible, bit ) )
    {
	switch ( ris )
	{
	default:		ris = IS_SUSCEPTIBLE;	break;
	case IS_IMMUNE:		ris = IS_RESISTANT;	break;
	case IS_RESISTANT:	ris = IS_NORMAL;	break;
	}
    }

    if ( ris == -1 )
        return def;
    else
        return ris;
}

int get_ac( CHAR_DATA *ch )
{
    int ac;

    ac = ch->armor;

    // Yes, people with an agility of 18 or less actually
    // have a little *better* armor class while asleep.
    // I'm not gonna worry about it. - Veygoth

    if( IS_AWAKE( ch ))
      ac += agi_app[get_curr_dex(ch)].defensive;

    switch( ch->position )
    {
      case POS_SLEEPING:
      case POS_INCAP:
      case POS_STUNNED:
      case POS_DEAD:
      case POS_MORTAL:
         ac += 30;
         break;
      case POS_RECLINING:
         ac += 25;
         break;
      case POS_RESTING:
         ac += 20;
         break;
      case POS_SITTING:
         ac += 15;
         break;
      case POS_KNEELING:
         ac += 10;
         break;
      case POS_FIGHTING:
      case POS_STANDING:
         break;
    }

    return ac;
}