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

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


extern int top_exit;
extern int top_ed;
extern int top_affect;
extern int cur_qobjs;
extern int cur_qchars;
extern CHAR_DATA *gch_prev;
extern OBJ_DATA *gobj_prev;

CHAR_DATA *cur_char;
ROOM_INDEX_DATA *cur_room;
bool cur_char_died;
ch_ret global_retcode;

int saving_mount_on_quit;
int cur_obj;
int cur_obj_serial;
int top_map_mob;
bool cur_obj_extracted;
obj_ret global_objcode;

OBJ_DATA *group_object(OBJ_DATA * obj1, OBJ_DATA * obj2);
bool in_magic_container(OBJ_DATA * obj);

/* Strlen_color by Rusty, useful for skipping over colors */
int strlen_color(char *argument)
{
   char *str;
   int i, length;

   str = argument;
   if (argument == NULL)
      return 0;

   for (length = i = 0; i < strlen(argument); ++i)
   {
      if ((str[i] != '&') && (str[i] != '^'))
         ++length;
      if ((str[i] == '&') || (str[i] == '^'))
      {
         if ((str[i] == '&') && (str[i + 1] == '&'))
            length = 2 + length;
         else if ((str[i] == '^') && (str[i + 1] == '^'))
            length = 2 + length;
         else
            --length;
      }
   }

   return length;
}

/*
 * Retrieve a character's trusted level for permission checking.
 */
sh_int get_trust(CHAR_DATA * ch)
{
   if (IS_NPC(ch))
      return LEVEL_PC;
   if (ch->desc && ch->desc->original)
      ch = ch->desc->original;
   if (ch->trust != 0)
      return ch->trust;
   if (ch->level >= LEVEL_IMMORTAL && IS_RETIRED(ch)) /* Tracker1 */
      return LEVEL_IMMORTAL; /* Tracker1 */

   return ch->level;
}

/*
 * New FLevel trust return, for use of the flevel attribute. - Xerves 3-12-98
 */
sh_int get_ftrust(CHAR_DATA * ch)
{
   if (ch->desc && ch->desc->original)
      ch = ch->desc->original;

   if (IS_NPC(ch))
      return ch->level;

   if (IS_RETIRED(ch))
      return LEVEL_IMMORTAL; /* Tracker1 */

   if (ch->level > ch->pcdata->flevel)
      return ch->level;

   return ch->pcdata->flevel;
}


/*
 * Retrieve a character's age.
 */
sh_int get_age(CHAR_DATA * ch)
{
   if (IS_NPC(ch))
      return 17;
   return 17 + (ch->played + (current_time - ch->pcdata->logon)) / 72000;
}



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

   max = 25;

   return URANGE(3, ch->perm_str + URANGE(-4, ch->mod_str, 4), max);
}



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

   max = 25;

   return URANGE(3, ch->perm_int + URANGE(-4, ch->mod_int, 4), max);
}



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

   max = 25;

   return URANGE(3, ch->perm_wis + URANGE(-4, ch->mod_wis, 4), max);
}



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

   max = 25;

   return URANGE(3, ch->perm_dex + URANGE(-4, ch->mod_dex, 4), max);
}



/*
 * Retrieve character's current constitution.
 */
sh_int get_curr_con(CHAR_DATA * ch)
{
   sh_int max;

   max = 25;

   return URANGE(3, ch->perm_con + URANGE(-4, ch->mod_con, 4), max);
}

/*
 * Retrieve character's current charisma.
 */
sh_int get_curr_cha(CHAR_DATA * ch)
{
   sh_int max;

   max = 25;

   return URANGE(3, ch->perm_cha + URANGE(-4, ch->mod_cha, 4), max);
}

/*
 * Retrieve character's current luck.
 */
sh_int get_curr_lck(CHAR_DATA * ch)
{
   sh_int max;

   max = 25;

   return URANGE(3, ch->perm_lck + URANGE(-4, ch->mod_lck, 4), max);
}

sh_int get_curr_agi(CHAR_DATA * ch)
{
   sh_int max;

   max = 100;

   return URANGE(10, ch->perm_agi + URANGE(-15, ch->mod_agi, 15), max);
}

/* Below 2 functions are used to return points and masteries of spells.  Mainly to
   compute an estimated value for mobs -- Xerves 2/00 */
sh_int get_mastered_value(CHAR_DATA *ch, int sn)
{
   if (!IS_NPC(ch))
   {
      return URANGE(0, ch->pcdata->ranking[sn], MAX_RANKING);
   }
   else
   {
      if (ch->max_hit <= 28)
         return get_mastery_value(ch, sn, 0, SPOWER_MIN);
      else if (ch->max_hit <= 77)
         return get_mastery_value(ch, sn, 0, SPOWER_LOW);
      else if (ch->max_hit <= 200)
         return get_mastery_value(ch, sn, 0, SPOWER_MED);
      else if (ch->max_hit <= 694)
         return get_mastery_value(ch, sn, 0, SPOWER_HI);
      else if (ch->max_hit <= 1022)
         return get_mastery_value(ch, sn, 0, SPOWER_GREAT);
      else if (ch->max_hit <= 3000)
         return get_mastery_value(ch, sn, 0, SPOWER_GREATER);
      else
         return get_mastery_value(ch, sn, 0, SPOWER_GREATEST);
   }
}
sh_int get_learned_value(CHAR_DATA *ch, int sn)
{
   if (!IS_NPC(ch))
   {
      return URANGE(0, ch->pcdata->learned[sn], MAX_SKPOINTS);
   }
   else
   {
      if (ch->max_hit <= 28)
         return get_point_value(ch, sn, 0, SPOWER_MIN);
      else if (ch->max_hit <= 77)
         return get_point_value(ch, sn, 0, SPOWER_LOW);
      else if (ch->max_hit <= 200)
         return get_point_value(ch, sn, 0, SPOWER_MED);
      else if (ch->max_hit <= 694)
         return get_point_value(ch, sn, 0, SPOWER_HI);
      else if (ch->max_hit <= 1022)
         return get_point_value(ch, sn, 0, SPOWER_GREAT);   
      else if (ch->max_hit <= 3000)
         return get_point_value(ch, sn, 0, SPOWER_GREATER);
      else
         return get_point_value(ch, sn, 0, SPOWER_GREATEST);
   }
}

/* Below 2 functions are used to return points and masteries of spells.  Mainly to
   compute an estimated value for mobs -- Xerves 2/00 */
sh_int get_point_value(CHAR_DATA * ch, int sn, int isobj, int lv)
{
   if (!IS_NPC(ch) && isobj == 0 && ch->pcdata->learned[sn] > 1)
      return ch->pcdata->learned[sn];
   else if (lv >= SPOWER_MIN)
   {
      if (lv == SPOWER_MIN)
         return number_range(1, 2);
      if (lv == SPOWER_LOW)
         return number_range(2, 4);
      if (lv == SPOWER_MED)
         return number_range(3, 6);
      if (lv == SPOWER_HI)
         return number_range(5, 8);        
      if (lv == SPOWER_GREAT)
         return number_range(7, 10);
      if (lv == SPOWER_GREATER)
         return number_range(8, 12);
      if (lv == SPOWER_GREATEST)
         return number_range(10, 14);
   }
   else if (IS_NPC(ch) && isobj == 0)
   {
      if (ch->max_hit <= 28)
         return get_point_value(ch, sn, 0, SPOWER_MIN);
      else if (ch->max_hit <= 77)
         return get_point_value(ch, sn, 0, SPOWER_LOW);
      else if (ch->max_hit <= 200)
         return get_point_value(ch, sn, 0, SPOWER_MED);
      else if (ch->max_hit <= 694)
         return get_point_value(ch, sn, 0, SPOWER_HI);
      else if (ch->max_hit <= 1022)
         return get_point_value(ch, sn, 0, SPOWER_GREAT);   
      else if (ch->max_hit <= 3000)
         return get_point_value(ch, sn, 0, SPOWER_GREATER);
      else
         return get_point_value(ch, sn, 0, SPOWER_GREATEST);
   }
   return 1;
}

sh_int get_mastery_value(CHAR_DATA * ch, int sn, int isobj, int lv)
{
   int di;

   if (!IS_NPC(ch) && isobj == 0 && ch->pcdata->ranking[sn] > 1)
      return ch->pcdata->ranking[sn];
   else if (lv >= SPOWER_MIN)
   {
      //mob or obj
      di = dice(1, 20);
      
      if (lv == SPOWER_MIN)
         return 1;
      if (lv == SPOWER_LOW)
      {
         if (di >= 15)
            return 2;
         else
            return 1;
      }
      if (lv == SPOWER_MED)
      {
         if (di >= 14)
            return 2;
         else
            return 1;
      }
      if (lv == SPOWER_HI)
      {
         if (di >= 12)
            return 3;
         else
            return 2;
      }            
      if (lv == SPOWER_GREAT)
      {
         if (di >= 4)
            return 4;
         else
            return 3;
      }
      if (lv == SPOWER_GREATER)
      {
         if (di <= 15)
            return 4;
         else
            return 5;
      }
      if (lv == SPOWER_GREATEST)
      {
         if (di <= 5)
            return 4;
         else if (di >= 16)
            return 6;
         else
            return 5;
      }
   }
   else if (IS_NPC(ch) && isobj == 0)
   {
      if (ch->max_hit <= 28)
         return get_mastery_value(ch, sn, 0, SPOWER_MIN);
      else if (ch->max_hit <= 77)
         return get_mastery_value(ch, sn, 0, SPOWER_LOW);
      else if (ch->max_hit <= 200)
         return get_mastery_value(ch, sn, 0, SPOWER_MED);
      else if (ch->max_hit <= 694)
         return get_mastery_value(ch, sn, 0, SPOWER_HI);
      else if (ch->max_hit <= 1022)
         return get_mastery_value(ch, sn, 0, SPOWER_GREAT);
      else if (ch->max_hit <= 3000)
         return get_mastery_value(ch, sn, 0, SPOWER_GREATER);
      else
         return get_mastery_value(ch, sn, 0, SPOWER_GREATEST);
   }
   return 1;
}

/* Below 6 handler functions are used in information obtaining in the new skill system.
   There are other functions in act_info.c and in mud_comm.c -- Xerves 2/00 */
// Retreives a Mastery name from its Number.
char *get_mastery_name(int mastery)
{
   switch (mastery)
   {
      default:
         return "Unknown";
      case 1:
         return "Beginner";
      case 2:
         return "Novice";
      case 3:
         return "Expert";
      case 4:
         return "Master";
      case 5:
         return "Elite";
      case 6:
         return "Flawless";
   }
}

char *get_tier_name(int mastery)
{
   switch (mastery)
   {
      default:
         return "Unknown";
      case 1:
         return "Tier 1";
      case 2:
         return "Tier 2";
      case 3:
         return "Tier 3";
      case 4:
         return "Tier 4";
   }
}

char *get_wplevel(int power)
{
   switch (power)
   {
      default:
         return "None";
      case SPOWER_MIN:
         return "Minimum";
      case SPOWER_LOW:
         return "Low";
      case SPOWER_MED:
         return "Medium";
      case SPOWER_HI:
         return "High";
      case SPOWER_GREAT:
         return "Great";
      case SPOWER_GREATER:
         return "Greater";
      case SPOWER_GREATEST:
         return "Greatest";
   }
}

char *get_sphere_name2(int sphere)
{
   switch(sphere)
   {
      default:
         return "Unknown";
      case 1:
         return "Combat";
      case 2:
         return "Agent";
      case 3:
         return "Wizardry";
      case 4:
         return "Divine";
      case 5:
         return "Spiritual";
   }
}

char *get_sphere_name(int sphere)
{
   switch(sphere)
   {
      default:
         return "  Unknown   ";
      case 1:
         return "   Combat   ";
      case 2:
         return "   Agent    ";
      case 3:
         return "  Wizardry  ";
      case 4:
         return "   Divine   ";
      case 5:
         return " Spiritual  ";
   }
}

/*
 * Retreives a Group name from its Number. -- Xerves 1/00
 */
char *get_group_name(int group)
{
   switch (group)
   {
      default:
         return "Unknown";
      case 1:
         return "Air";
      case 2:
         return "Earth";
      case 3:
         return "Energy";
      case 4:
         return "Fire";
      case 5:
         return "Water";
      case 6:
         return "Divine";
      case 7:
         return "Strikes";
      case 8:
         return "Body";
      case 9:
         return "Mind";
      case 10:
         return "-------";
      case 11:
         return "Survival";
      case 12:
         return "Stealth";
      case 13:
         return "Thieving";
      case 14:
         return "Battle Skills";
      case 15:
         return "-------";
      case 16:
         return "Tactical";
      case 17:
         return "Styles";
      case 18:
         return "-------";
   }
}

/*
 * Retreives a Group name from its Number.  Should be used in do_skills only since it
 * includes extra values to break up Fire for Cleric and Fire for Mage
 */
char *get_group_name2(int group)
{
   switch (group)
   {
      default:
         return "Unknown";
      case 1:
         return "Air";
      case 2:
         return "Earth";
      case 3:
         return "Energy";
      case 4:
         return "Fire";
      case 5:
         return "Water";
      case 6:
         return "Divine";
      case 7:
         return "Strikes";
      case 8:
         return "Body";
      case 9:
         return "Mind";
      case 10:
         return "-------";
      case 11:
         return "Survival";
      case 12:
         return "Stealth";
      case 13:
         return "Thieving";
      case 14:
         return "Battle Skills";
      case 15:
         return "--------";
      case 16:
         return "Tactical";
      case 17:
         return "Styles";
      case 18:
         return "-------";
      case 19:
         return "Air";
      case 20:
         return "Earth";
      case 21:
         return "Energy";
      case 22:
         return "Fire";
      case 23:
         return "Water";
   }
}

//Used in do_skills to determine percents
int is_part_sphere(int sphere, int group)
{  
   if (sphere == 1) //Warrior
      if (group == 14 || group == 16 || group == 17)
         return 1;
   if (sphere == 2) //Thief
      if (group == 11 || group == 12 || group == 13)
         return 1;
   if (sphere == 3) //Mage
      if (group == 1 || group == 2 || group == 3 || group == 4 || group == 5)
         return 1;
   if (sphere == 4) //Cleric
      if (group == 6 || group == 19 || group == 20 || group == 21 || group == 22 || group == 23)
         return 1;   
   if (sphere == 5) //Hand to Hand
      if (group == 7 || group == 8 || group == 9)
         return 1;
   return 0;
}
// Returns Mastery number for the name
int get_mastery_num(char *mastery)
{
   char buf[MSL];

   sprintf(buf, mastery);
   buf[0] = UPPER(buf[0]);

   if (!str_cmp(buf, "Beginner"))
      return 1;
   if (!str_cmp(buf, "Novice") || !str_prefix(buf, "Apprentice"))
      return 2;
   if (!str_cmp(buf, "Expert"))
      return 3;
   if (!str_cmp(buf, "Master"))
      return 4;
   if (!str_cmp(buf, "Elite"))
      return 5;
   if (!str_cmp(buf, "Flawless"))
      return 6;

   return -1;
}

// Get sphere number from sphere name -- Xerves 7/04
sh_int issphere(char *argument)
{
   sh_int sphere = -1;
   if (!str_cmp(argument, "Combat"))
      sphere = 1;
   if (!str_cmp(argument, "Agent"))
      sphere = 2;
   if (!str_cmp(argument, "Wizardry"))
      sphere = 3;
   if (!str_cmp(argument, "Divine"))
      sphere = 4;
   if (!str_cmp(argument, "Spiritual"))
      sphere = 5;
      
   return sphere;
}
 
/* Get group number from group name -- Xerves 1/00 */
sh_int isgroup(char *argument)
{
   sh_int group = -1;
   if (!str_cmp(argument, "Air"))
      group = 1;
   if (!str_cmp(argument, "Earth"))
      group = 2;
   if (!str_cmp(argument, "Energy"))
      group = 3;
   if (!str_cmp(argument, "Fire"))
      group = 4;
   if (!str_cmp(argument, "Water"))
      group = 5;
   if (!str_cmp(argument, "Divine"))
      group = 6;
   if (!str_cmp(argument, "Strikes"))
      group = 7;
   if (!str_cmp(argument, "Body"))
      group = 8;
   if (!str_cmp(argument, "Mind"))
      group = 9;
   if (!str_cmp(argument, "-------"))
      group = 10;
   if (!str_cmp(argument, "Survival"))
      group = 11;
   if (!str_cmp(argument, "Stealth"))
      group = 12;
   if (!str_cmp(argument, "Thieving"))
      group = 13;
   if (!str_cmp(argument, "Battle Skills"))
      group = 14;
   if (!str_cmp(argument, "--------"))
      group = 15;
   if (!str_cmp(argument, "Tactical"))
      group = 16;
   if (!str_cmp(argument, "Styles"))
      group = 17;
   if (!str_cmp(argument, "-------"))
      group = 18;
      
   return group;
}

//Movement lag, more lag the more tired you get (adding in later running, etc)
int movement_lag(CHAR_DATA *ch, int beats)
{
   int percent;
   int level;
   
   if (beats < 0)
      beats = 1;
   
   percent = ch->move * 100 / 1000;
   
   if (IS_NPC(ch) || LEARNED(ch, gsn_shadowfoot) >= 1)
   {
      if (percent >= 70)
         beats = 1;
      else if (percent >= 60)
         beats = beats * 3 / 10;
      else if (percent >= 50)
         beats = beats * 5 / 10;
      else if (percent >= 40)
         beats = beats * 8 / 10;
      else if (percent >= 30)
         beats = beats * 11 / 10;
      else if (percent >= 15)
         beats = beats * 15 / 10;
      else if (percent < 15)
         beats = beats * 20 / 10;
   }
   else
   {
      if (percent >= 80)
         beats = 1;
      else if (percent >= 70)
         beats = beats * 5 / 10;
      else if (percent >= 60)
         beats = beats * 8 / 10;
      else if (percent >= 50)
         beats = beats * 12 / 10;
      else if (percent >= 40)
         beats = beats * 15 / 10;
      else if (percent >= 15)
         beats = beats * 20 / 10;
      else if (percent < 15)
         beats = beats * 30 / 10;
   }   
   level = POINT_LEVEL(LEARNED(ch, gsn_featherfoot), MASTERED(ch, gsn_featherfoot));
   if (level > 0 && !IS_NPC(ch))
   {
      beats = beats * (100-(level/2)) / 100;
   }
   if (beats < 1)
      beats = 1;
   if (!IS_NPC(ch) && LEARNED(ch, gsn_featherfoot) >= 1)
      learn_from_success(ch, gsn_featherfoot, NULL);
   if (!IS_NPC(ch) && LEARNED(ch, gsn_featherback) >= 1)
      learn_from_success(ch, gsn_featherback, NULL);
   return UMIN(20, beats); //5 seconds max, anything over is just evil
}

void update_movement_points(CHAR_DATA *ch, int move)
{
   int mv;
   
   if (IS_NPC(ch))
   {
      if (!xIS_SET(ch->act, ACT_MOUNTSAVE))
         return;
   }
   
   if (!IS_NPC(ch))
   {
      mv = number_range(move*.15, move*.3);
      if (sysdata.stat_gain <= 3)
         mv = number_range(move*.25, move*.5);
      else if (sysdata.stat_gain >= 5)
         mv = number_range(move*.4, move*.8);
      
   
      if (ch->mover >= 35 && ch->mover < 45)
         mv *= .8;
      else if (ch->mover < 55)
         mv *= .6;
      else if (ch->mover < 65)
         mv *= .5;
      else if (ch->mover <= 74)
         mv *= .3;
      else if (ch->mover < 94)
         mv *= .25;
      else
         mv *= .2;
      
      if (mv == 0)
         mv = 1;
      
      if (ch->mover >= (74+get_talent_increase(ch, 8)) && ch->pcdata->per_move >= 300)
         mv = 0;
            
      ch->pcdata->per_move += mv;
         
      if (ch->pcdata->per_move > 1000)
      {
         ch->mover++;
         send_to_char("&C*****************************************\n\r", ch);
         send_to_char("&C******You Gain 1 Point in Endurance******\n\r", ch);
         send_to_char("&C*****************************************\n\r", ch);
         ch->pcdata->per_move = 0;
      }  
      if (ch->pcdata->per_move < 0)
      {
         ch->mover--;
         send_to_char("&c*****************************************\n\r", ch);
         send_to_char("&c******You Lose 1 Point in Endurance******\n\r", ch);
         send_to_char("&c*****************************************\n\r", ch);
         ch->pcdata->per_move = 999;
      }
   }
   else
   {  
      mv = number_range(move*.1, move*.25);
      if (sysdata.stat_gain <= 3)
         mv = number_range(move*.2, move*.4);
      else if (sysdata.stat_gain >= 5)
         mv = number_range(move*.35, move*.7);
   
   
      if (ch->mover >= 65 && ch->mover < 75)
         mv *= .7;
      else if (ch->mover < 85)
         mv *= .5;
      else if (ch->mover < 95)
         mv *= .3;
      else if (ch->mover < 105)
         mv *= .2;
      else if (ch->mover < 115)
         mv *= .15;
      else if (ch->mover < 125)
         mv *= .1;
      else if (ch->mover < 135)
         mv *= .07;
      
      if (mv == 0)
         mv = 1;
      
      if (ch->mover == 135 && ch->m1 >= 300)
         mv = 0;
            
      ch->m1 += mv;
         
      if (ch->m1 > 1000)
      {
         ch->mover++;
         send_to_char("&C*************************************************\n\r", ch);
         send_to_char("&C******Your Mount Gains 1 Point in Endurance******\n\r", ch);
         send_to_char("&C*************************************************\n\r", ch);
         ch->m1 = 0;
      }  
   }
}

void str_load_increase(CHAR_DATA *ch, int load)
{
   int mstr = 0;
   int str = ch->perm_str;
   int bstr;
   
   if (load >= 51 && load <= 55)
      mstr += number_range(0, 2);
   else if (load >= 56 && load <= 60)
      mstr += number_range(1, 2);
   else if (load >= 61 && load <= 65)
      mstr += number_range(2, 3);
   else if (load >= 66 && load <= 70)
      mstr += number_range(2, 4);
   else if (load >= 71 && load <= 75)
      mstr += number_range(3, 4);
   else if (load >= 76 && load <= 80)
      mstr += number_range(3, 5);
   else if (load >= 81 && load <= 85)
      mstr += number_range(4, 5);
   else if (load >= 86 && load <= 90)
      mstr += number_range(4, 6);
   else if (load >= 91 && load <= 96)
      mstr += number_range(5, 6);
   else
      mstr += number_range(6, 7);
      
   if (sysdata.stat_gain <= 3)
      mstr = number_range(150*mstr/100, 180*mstr/100);
   else if (sysdata.stat_gain >= 5)
      mstr = number_range(250*mstr/100, 300*mstr/100);
      
   bstr = 14 + race_table[ch->race]->str_plus;
   if (str == bstr - 4)
      mstr *= 2;
   if (str == bstr - 3)
      mstr *= 1.7;
   if (str == bstr - 2)
      mstr *= 1.5;
   if (str == bstr - 1)
      mstr *= 1.2;
   if (str == bstr)
      mstr *= 1;
   if (str == bstr + 1)
      mstr *= .85;
   if (str == bstr + 2)
      mstr *= .7;
   if (str == bstr + 3)
      mstr *= .6;
   if (str == bstr + 4)
      mstr *= .4;
   if (str == bstr + 5)
      mstr *= .3;
   if (str > bstr + 5) //Base + 5 should be the max unless you screwed it up
      mstr = 0;
   else
   {
      if (mstr == 0)
         mstr = 1;
   }
      
   if (ch->perm_str == (14 + race_table[ch->race]->str_plus + race_table[ch->race]->str_range) && ch->pcdata->per_str >= 3000)
      mstr = 0;
   ch->pcdata->per_str += mstr;
   if (ch->pcdata->per_str > 10000)
   {
      ch->perm_str++;
      send_to_char("&R**************************************\n\r", ch);
      send_to_char("&R*****You Gain 1 Point of Strength*****\n\r", ch);
      send_to_char("&R**************************************\n\r", ch);
      ch->pcdata->per_str = 0;
   }
}

int calculate_movement_cost(int move, CHAR_DATA *ch)
{
   int load;
   int weight;
   int level;
   int addmove = 0;
   
   if (ch->con_lleg <= -1)
      addmove += UMAX(1, number_range(move*1.5, move*2.3));
   else if (ch->con_lleg <= 10)
      addmove += UMAX(1, number_range(move*1.3, move*1.5));
   else if (ch->con_lleg <= 30)
      addmove += UMAX(1, number_range(move*1.15, move*1.3));
   else if (ch->con_lleg <= 50)
      addmove += UMAX(1, number_range(move*1.05, move*1.15));
      
   if (ch->con_rleg <= -1)
      addmove += UMAX(1, number_range(move*1.5, move*2.3));
   else if (ch->con_rleg <= 10)
      addmove += UMAX(1, number_range(move*1.3, move*1.5));
   else if (ch->con_rleg <= 30)
      addmove += UMAX(1, number_range(move*1.15, move*1.3));
   else if (ch->con_rleg <= 50)
      addmove += UMAX(1, number_range(move*1.05, move*1.15));
   
   move+=addmove;
   
   if ((IS_NPC(ch) && !xIS_SET(ch->act, ACT_MOUNTSAVE)) || IS_IMMORTAL(ch))
      return 1; //for now
   else
   {
      if (ch->mover < 15)
         move = move * (5 - (.1 * (ch->mover-5)));
      else if (ch->mover < 25)
         move = move * (4 - (.1 * (ch->mover-15)));
      else if (ch->mover < 35)
         move = move * (3 - (.1 * (ch->mover-25)));
      else if (ch->mover < 45)
         move = move * (2 - (.1 * (ch->mover-35)));
      else if (ch->mover < 55)
         move = move * (1.3 - (.07 * (ch->mover-45)));
      else if (ch->mover < 65)
         move = move * (.95 - (.035 * (ch->mover-55)));
      else if (ch->mover < 75)
         move = move * (.8 - (.015 * (ch->mover-65)));
      else if (ch->mover < 85)
         move = move * (.7 - (.01 * (ch->mover-75)));
      else if (ch->mover < 95)
         move = move * (.6 - (.01 * (ch->mover-85)));
      else if (ch->mover < 105)
         move = move * (.5 - (.01 * (ch->mover-95)));
      else if (ch->mover < 115)
         move = move * (.4 - (.01 * (ch->mover-105)));
      else if (ch->mover < 125)
         move = move * (.3 - (.01 * (ch->mover-115)));
      else if (ch->mover < 135)
         move = move * (.2 - (.01 * (ch->mover-125)));
      else if (ch->mover >= 135)
         move = move * .1;
         
      if (!IS_NPC(ch) && ch->pcdata->learned[gsn_shadowfoot] > 0)
      {
         level = POINT_LEVEL(GET_POINTS(ch, gsn_shadowfoot, 0, 1), GET_MASTERY(ch, gsn_shadowfoot, 0, 1));  
         move = move * (100 - (15+level/2)) / 100;
         learn_from_success(ch, gsn_shadowfoot, NULL);
      }
      if (move < 1)
         move = 1;
      
      if (!IS_NPC(ch))
         weight = get_ch_carry_weight(ch);
      else
      {
         if (ch->master)
            weight = get_ch_carry_weight(ch->master);
         else
            weight = 1;
      }
      
      load = 100 * weight / can_carry_w(ch);   
      if (load > 50)
      {
         if (!IS_NPC(ch))
            str_load_increase(ch, load);
         if (!IS_NPC(ch) && ch->pcdata->learned[gsn_strongfoot] > 0)
         {
            level = POINT_LEVEL(GET_POINTS(ch, gsn_strongfoot, 0, 1), GET_MASTERY(ch, gsn_strongfoot, 0, 1));  
            load = load - (level*2/5);
            learn_from_success(ch, gsn_strongfoot, NULL);
         }
         if (load <= 50)
            ;
         else if (load >= 51 && load <= 55)
            move *= 1.1;
         else if (load >= 56 && load <= 60)
            move *= 1.3;
         else if (load >= 61 && load <= 65)
            move *= 1.5;
         else if (load >= 66 && load <= 70)
            move *= 1.7;
         else if (load >= 71 && load <= 75)
            move *= 2;
         else if (load >= 76 && load <= 80)
            move *= 2.3;
         else if (load >= 81 && load <= 85)
            move *= 2.6;
         else if (load >= 86 && load <= 90)
            move *= 3;
         else if (load >= 91 && load <= 96)
            move *= 4;
         else
            move *= 5;
      }
   }
   if (ch->rider)
      move *= 2;
   return move;
}

/* Below are hitroll/damroll checks to get the hitroll normally plus bonuses based
   on mastery */
int get_hit_roll(CHAR_DATA * ch)
{
   int hitroll;

   hitroll = ch->hitroll + str_app[get_curr_str(ch)].tohit + (2 - (abs(ch->mental_state) / 10));

   return hitroll;
}

int get_dam_roll(CHAR_DATA * ch)
{
   int damroll;


   damroll = ch->damroll + ch->damplus + str_app[get_curr_str(ch)].todam;

   if (ch->mental_state > 5 && ch->mental_state < 15)
      damroll++;
   return damroll;
}

//Defines what the room is, 1 is safe, 2 is noloot, 3 is anitem, 4 is freekill                       
//Default is noloot      
int check_room_pk(CHAR_DATA * ch)
{
   //Do the Wilderness first
   //Wilderness checks, the room itself should ALWAYS be set to noloot
   if (IN_WILDERNESS(ch))
   {
      int stx, sty, endx, endy, x, y;

      if (sysdata.resetgame)
         return 4;
      stx = ch->coord->x - 5;
      sty = ch->coord->y - 5;
      endx = ch->coord->x + 5;
      endy = ch->coord->y + 5;

      if (stx < 1)
         stx = 1;
      if (sty < 1)
         sty = 1;
      if (endx > MAX_X)
         endx = MAX_X;
      if (endy > MAX_Y)
         endy = MAX_Y;
      for (y = sty; y < endy + 1; y += 1)
      {
         for (x = stx; x < endx + 1; x += 1)
         {
            if (map_sector[ch->map][x][y] == SECT_ROAD)
               return 2;
            if (map_sector[ch->map][x][y] == SECT_BRIDGE)
               return 2;
            if (map_sector[ch->map][x][y] == SECT_PATH)
            {
               if (abs(ch->coord->y - y) <= 3 && abs(ch->coord->x - x) <= 3)
                  return 2;
            }
         }
      }
      return 3;
   }
   //A safe room is a safe room no matter what.
   if (xIS_SET(ch->in_room->room_flags, ROOM_TSAFE))
      return 1;
   if (xIS_SET(ch->in_room->room_flags, ROOM_SAFE))
      return 1;
   if (xIS_SET(ch->in_room->room_flags, ROOM_FREEKILL))
      return 4;
   if (xIS_SET(ch->in_room->room_flags, ROOM_ANITEM))
      return 3;
   if (xIS_SET(ch->in_room->room_flags, ROOM_NOLOOT))
      return 2;

   //Check areas next, room goes before area in priority
   if (IS_SET(ch->in_room->area->flags, AFLAG_NOKILL))
      return 1;
   if (IS_SET(ch->in_room->area->flags, AFLAG_NOLOOT))
      return 2;
   if (IS_SET(ch->in_room->area->flags, AFLAG_ANITEM))
      return 3;
   if (IS_SET(ch->in_room->area->flags, AFLAG_FREEKILL))
      return 4;

   if (sysdata.resetgame)
      return 4;
   else
      return 2;
}

bool in_same_room(CHAR_DATA * ch, CHAR_DATA * victim)
{
   if (IN_WILDERNESS(ch))
   {
      if (ch->coord->x == victim->coord->x && ch->coord->y == victim->coord->y
         && ch->map == victim->map)
         return TRUE;
   }
   else
   {
      if (ch->in_room == victim->in_room)
         return TRUE;
   }
   return FALSE;
}

bool in_hellmaze(CHAR_DATA * ch)
{
   return FALSE;
}

// Send out message, doesn't use a channel, don't want to spam poor players
void hunt_message(CHAR_DATA * ch, CHAR_DATA * victim, int range)
{
   DESCRIPTOR_DATA *d;
   CHAR_DATA *tochar;
   int message = 1;
   char buf[MSL];
   char buf2[MSL];

   for (d = first_descriptor; d; d = d->next)
   {

      if (d->connected == CON_PLAYING && d->character->in_room && d->newstate != 2)
         tochar = d->character;
      else
         continue;

      if (tochar->coord->x > -1 || tochar->coord->y > -1 || tochar->map > -1)
      {
         if (abs(ch->coord->x - tochar->coord->x) <= range && abs(ch->coord->y - tochar->coord->y) <= range)
         {
            message = number_range(1, 6);
            if (message == 1)
               sprintf(buf, "My first target has escaped, so &R[%s&R]%s will DIE instead.", victim->name, char_color_str(AT_GOSSIP, tochar));
            else if (message == 2)
               sprintf(buf, "I seek more battles, and &R[%s&R]%s looks like an easy target.", victim->name, char_color_str(AT_GOSSIP, tochar));
            else if (message == 3)
               sprintf(buf, "&R[%s&R]%s shall die today, I will take delight in my victory.", victim->name, char_color_str(AT_GOSSIP, tochar));
            else if (message == 4)
               sprintf(buf, "Come here &R[%s&R]%s, I wish to introduce you to your maker.", victim->name, char_color_str(AT_GOSSIP, tochar));
            else if (message == 5)
               sprintf(buf, "Poor &R[%s&R]%s, today was just not a good day to step outside.", victim->name, char_color_str(AT_GOSSIP, tochar));
            else
               sprintf(buf, "Life shall end for &R[%s&R]%s today, how sad.", victim->name, char_color_str(AT_GOSSIP, tochar));

            sprintf(buf2, "&c&w%s [&cyells&c&w] %s'%s'", ch->short_descr, char_color_str(AT_GOSSIP, tochar), buf);
            act(AT_GOSSIP, buf2, ch, NULL, tochar, TO_VICT);
         }
      }
   }
   return;
}

void find_next_target(CHAR_DATA * ch)
{
   CHAR_DATA *victim;
   int range, num, count, npeace, ht, x;
   CHAR_DATA *pvictim = NULL;
   int eqlevel = 8;

   if (xIS_SET(ch->miflags, KM_ATTACKN) || xIS_SET(ch->miflags, KM_ATTACKE) || xIS_SET(ch->miflags, KM_ATTACKA))
   {  
      count = x = 0;

      range = ch->m6;

      if (xIS_SET(ch->miflags, KM_ATTACKN))
         npeace = 1;
      else if (xIS_SET(ch->miflags, KM_ATTACKE))
         npeace = 0;
      else
         npeace = -1;

      for (victim = ch->in_room->first_person; victim; victim = victim->next_in_room)
      {
         if (victim->coord->x > -1 || victim->coord->y > -1 || victim->map > -1)
         {
            if (abs(ch->coord->x - victim->coord->x) <= range && abs(ch->coord->y - victim->coord->y) <= range)
            {
               if (IS_NPC(victim))
                  ht = victim->m4;
               else
                  ht = victim->pcdata->hometown; 

               if (victim->map == ch->map && victim->level < LEVEL_IMMORTAL && can_see(ch, victim) && ch->m4 != ht 
               && (npeace == -1 || kingdom_table[ch->m4]->peace[ht] <= npeace) && !xIS_SET(victim->act, ACT_PACIFIST))
               {
                  if (!get_eq_char(victim, WEAR_NECK))
                  {
                     pvictim = victim;
                     eqlevel = 1;
                  }
                  if (!get_eq_char(victim, WEAR_HEAD) && eqlevel > 2)
                  {
                     pvictim = victim;
                     eqlevel = 2;
                  }
                  if (!get_eq_char(victim, WEAR_ARM_R) && eqlevel > 3)
                  {
                     pvictim = victim;
                     eqlevel = 3;
                  }
                  if (!get_eq_char(victim, WEAR_ARM_L) && eqlevel > 4)
                  {
                     pvictim = victim;
                     eqlevel = 4;
                  }
                  if (!get_eq_char(victim, WEAR_LEG_R) && eqlevel > 5)
                  {
                     pvictim = victim;
                     eqlevel = 5;
                  }
                  if (!get_eq_char(victim, WEAR_LEG_L) && eqlevel > 6)
                  {
                     pvictim = victim;
                     eqlevel = 6;
                  }
                  if (!get_eq_char(victim, WEAR_BODY) && eqlevel > 7)
                  {
                     pvictim = victim;
                     eqlevel = 7;
                  }
                  if (!pvictim)
                     pvictim = victim;
               }
            }
         }
      }
      if (!pvictim)
      {
         stop_hating(ch);
         stop_hunting(ch);
         do_yell(ch, "Lost my target, no new ones sited, standing down.");
         return;
      }
      else
      {
         hunt_message(ch, pvictim, range + 1);
         start_hunting(ch, pvictim);
         return;
      }
   }
   if (xIS_SET(ch->miflags, KM_ATTACKC) || xIS_SET(ch->miflags, KM_ATTACKH))
   {
      count = x = 0;
      for (victim = ch->in_room->first_person; victim; victim = victim->next_in_room)
      {
         if ((xIS_SET(ch->miflags, KM_ATTACKC) && get_wear_cloak(victim)) || 
             (xIS_SET(ch->miflags, KM_ATTACKH) && get_wear_hidden_cloak(victim)))
         {
            if (IN_SAME_ROOM(ch, victim))
            {
               if (IS_NPC(victim))
                  ht = victim->m4;
               else
                  ht = victim->pcdata->hometown;
               if (can_see_map(ch, victim) && !is_safe(ch, victim) && ch->m4 != ht && !IS_IMMORTAL(victim))
               {
                  count++;
               }
            }
         }
      }
      if (count == 0)
      {
         stop_hating(ch);
         stop_hunting(ch);
         do_yell(ch, "Lost my target, no new ones sited, standing down.");
         return;
      }
      num = number_range(1, count);
      for (victim = ch->in_room->first_person; victim; victim = victim->next_in_room)
      {
         if ((xIS_SET(ch->miflags, KM_ATTACKC) && get_wear_cloak(victim)) || 
             (xIS_SET(ch->miflags, KM_ATTACKH) && get_wear_hidden_cloak(victim)))
         {
            if (IN_SAME_ROOM(ch, victim))
            {
               if (IS_NPC(victim))
                  ht = victim->m4;
               else
                  ht = victim->pcdata->hometown;
               if (x == num && can_see_map(ch, victim) && !is_safe(ch, victim) && ch->m4 != ht && !IS_IMMORTAL(victim))
               {
                  hunt_message(ch, victim, 3);
                  start_hunting(ch, victim);
                  return;
               }
               else
               {
                  if (can_see_map(ch, victim) && !is_safe(ch, victim) && ch->m4 != ht && !IS_IMMORTAL(victim))
                     x++;
               }
            }
         }
      }
   }   
}

// 0 is out of Battle, 1 is while on map, range is different
void find_next_hunt(CHAR_DATA * ch, int type)
{
   DESCRIPTOR_DATA *d;
   CHAR_DATA *victim;
   int count = 0;
   int x = 1;
   int num;
   int range;

   if (type == 0)
      range = 10;
   else
      range = 10;

   if (xIS_SET(ch->act, ACT_MILITARY)) //They hunt mobs too, different function
   {
      find_next_target(ch);
      return;
   }

   for (d = first_descriptor; d; d = d->next)
   {
      if (d->connected == CON_PLAYING && d->character->in_room && d->newstate != 2)
         victim = d->character;
      else
         continue;

      if (victim->coord->x > -1 || victim->coord->y > -1 || victim->map > -1)
      {
         if (abs(ch->coord->x - victim->coord->x) <= range && abs(ch->coord->y - victim->coord->y) <= range)
         {
            if (victim->map == ch->map && can_see(ch, victim) && victim->level < LEVEL_IMMORTAL)
            {
               count++;
            }
         }
      }
   }
   if (count == 0)
   {
      extract_char(ch, TRUE);
      return;
   }
   num = number_range(1, count);
   for (d = first_descriptor; d; d = d->next)
   {
      if (d->connected == CON_PLAYING && d->character->in_room && d->newstate != 2)
         victim = d->character;
      else
         continue;

      if (victim->coord->x > -1 || victim->coord->y > -1 || victim->map > -1)
      {
         if (abs(ch->coord->x - victim->coord->x) <= range && abs(ch->coord->y - victim->coord->y) <= range)
         {
            if (x == num && (ch->map == victim->map && victim->level < LEVEL_IMMORTAL && can_see(ch, victim)) )
            {
               hunt_message(ch, victim, range + 1);
               start_hunting(ch, victim);
               start_hating(ch, victim);
               return;
            }
            else
            {
               if (ch->map == victim->map && victim->level < LEVEL_IMMORTAL && can_see(ch, victim))
                  x++;
            }
         }
      }
   }
}

bool find_sector(CHAR_DATA * ch, int sector)
{
   if (IS_ONMAP_FLAG(ch))
   {
      if (map_sector[ch->map][ch->coord->x][ch->coord->y] == sector)
      {
         return TRUE;
      }
   }
   else
   {
      if (ch->in_room->sector_type == sector)
      {
         return TRUE;
      }
   }

   return FALSE;
}

/*
 * Retrieve a character's carry capacity.
 * Vastly reduced (finally) due to containers		-Thoric
 */
int can_carry_n(CHAR_DATA * ch)
{
   int penalty = 0;

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

   if (IS_NPC(ch) && (xIS_SET(ch->act, ACT_PET) || xIS_SET(ch->act, ACT_MOUNTSAVE)))
      return 0;

   if (IS_NPC(ch) && xIS_SET(ch->act, ACT_IMMORTAL))
      return 1000;

   if (get_eq_char(ch, WEAR_WIELD))
      ++penalty;
   if (get_eq_char(ch, WEAR_DUAL_WIELD))
      ++penalty;
   if (get_eq_char(ch, WEAR_MISSILE_WIELD))
      ++penalty;
   if (get_eq_char(ch, WEAR_NOCKED))
      ++penalty;
   if (get_eq_char(ch, WEAR_SHIELD))
      ++penalty;
   return URANGE(8, 8 + get_curr_dex(ch) - 12 - penalty, 20);
}



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

   if (IS_NPC(ch) && xIS_SET(ch->act, ACT_MOUNTSAVE))
      return str_app[get_curr_str(ch)].carry*2;

   if (IS_NPC(ch) && xIS_SET(ch->act, ACT_IMMORTAL))
      return 1000000;

   weight = str_app[get_curr_str(ch)].carry;
   if (level > 0)
   {
      weight += weight * UMIN(40, level/2) / 100;
   }
   return weight;
}


/*
 * See if a player/mob can take a piece of prototype eq		-Thoric
 */
bool can_take_proto(CHAR_DATA * ch)
{
   if (IS_IMMORTAL(ch))
      return TRUE;
   else if (IS_NPC(ch) && xIS_SET(ch->act, ACT_PROTOTYPE))
      return TRUE;
   else
      return FALSE;
}


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

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

/* Will count users on furniture -- Xerves */
int count_users(OBJ_DATA * obj)
{
   CHAR_DATA *fch;
   int count = 0;

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

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

   return count;
}

int max_weight(OBJ_DATA * obj)
{
   CHAR_DATA *fch;
   int weight = 0;

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

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

   return weight;
}

bool is_name_prefix(const char *str, char *namelist)
{
   char name[MIL];

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

/*
 * See if a string is one of the names of an object.		-Thoric
 * Treats a dash as a word delimiter as well as a space
 */
bool is_name2(const char *str, char *namelist)
{
   char name[MIL];

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

bool is_name2_prefix(const char *str, char *namelist)
{
   char name[MIL];

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

/*								-Thoric
 * Checks if str is a name in namelist supporting multiple keywords
 */
bool nifty_is_name(char *str, char *namelist)
{
   char name[MIL];

   if (!str || str[0] == '\0')
      return FALSE;

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

bool nifty_is_name_prefix(char *str, char *namelist)
{
   char name[MIL];

   if (!str || str[0] == '\0')
      return FALSE;

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

void room_affect(ROOM_INDEX_DATA * pRoomIndex, AFFECT_DATA * paf, bool fAdd)
{
   if (fAdd)
   {
      switch (paf->location)
      {
         case APPLY_ROOMFLAG:
         case APPLY_SECTORTYPE:
            break;
         case APPLY_ROOMLIGHT:
            pRoomIndex->light += paf->modifier;
            break;
         case APPLY_TELEVNUM:
         case APPLY_TELEDELAY:
            break;
      }
   }
   else
   {
      switch (paf->location)
      {
         case APPLY_ROOMFLAG:
         case APPLY_SECTORTYPE:
            break;
         case APPLY_ROOMLIGHT:
            pRoomIndex->light -= paf->modifier;
            break;
         case APPLY_TELEVNUM:
         case APPLY_TELEDELAY:
            break;
      }
   }
}

/*
 * Modify a skill (hopefully) properly			-Thoric
 *
 * On "adding" a skill modifying affect, the value set is unimportant
 * upon removing the affect, the skill it enforced to a proper range.
 */
void modify_skill(CHAR_DATA * ch, int sn, int mod, bool fAdd)
{
   if (!IS_NPC(ch))
   {
      if (fAdd)
         ch->pcdata->learned[sn] += mod;
      else
         ch->pcdata->learned[sn] = URANGE(0, ch->pcdata->learned[sn] + mod, MAX_SKPOINTS);
   }
}

int base_resis_values(CHAR_DATA *ch, int type)
{
   int fire, water, air, earth, energy, holy, unholy, nonmagic, magic, poison, paralysis;
   
   fire=water=air=earth=energy=holy=unholy=nonmagic=magic=poison=paralysis=100;
   
   if (IS_SET(ch->elementb, ELEMENT_FIRE))
   {
      fire -=25;
      water +=50;
   }
   if (IS_SET(ch->elementb, ELEMENT_WATER))
   {
      fire +=35;
      water -=20;
   }
   if (IS_SET(ch->elementb, ELEMENT_AIR))
   {
      air -=35;
      earth +=50;
   }
   if (IS_SET(ch->elementb, ELEMENT_EARTH))
   {
      air +=35;
      earth -=25;
   }
   if (IS_SET(ch->elementb, ELEMENT_ENERGY))
   {
      energy -=40;
      air +=15;
      earth +=15;
      fire +=15;
      water +=15;
   }
   if (IS_SET(ch->elementb, ELEMENT_DIVINE))
   {
      holy -=60;
      unholy +=200;
      energy -= 10;
      air -=10;
      earth -=10;
      fire -=10;
      water -=10;
   }
   if (IS_SET(ch->elementb, ELEMENT_UNHOLY))
   {
      unholy -=60;
      holy +=200;
      energy -= 10;
      air -=10;
      earth -=10;
      fire -=10;
      water -=10;
   }        
   if (ch->race == RACE_OGRE)
   {
      nonmagic -= 20;
      fire -= 25;
      water -= 30;
      magic += 100;
      poison -= 30;
      paralysis -= 30;
   }
   if (ch->race == RACE_DWARF)
   {  
      water -= 25;
   }
   if (ch->race == RACE_HOBBIT)
   {   
      fire -= 25;
   }
   if (ch->race == RACE_FAIRY)
   {
      magic -= 35;
      nonmagic += 50;
   }         
   if (type == 1)
      return fire; 
   if (type == 2)
      return water;
   if (type == 3)
      return air;
   if (type == 4)
      return earth;
   if (type == 5)
      return energy;
   if (type == 6)
      return holy;
   if (type == 7)
      return unholy;
   if (type == 8)
      return nonmagic;
   if (type == 9)
      return magic;
   if (type == 10)
      return poison;
   if (type == 11)
      return paralysis;
      
   return 100;
}     

/*
 * Apply or remove an affect to a character.
 */
void affect_modify(CHAR_DATA * ch, AFFECT_DATA * paf, sh_int fAdd)
{
   OBJ_DATA *wield;
   int mod;
   sh_int eq = 0;
   struct skill_type *skill;
   ch_ret retcode;
   int resist;
   int susc;
   int diff;
   //AFFECT_DATA *saf;

   mod = paf->modifier;

   if (fAdd > 1)
   {
      fAdd -= 2;
      eq = 1;
   }


   if (fAdd)
   {
      xSET_BITS(ch->affected_by, paf->bitvector);
      if (paf->location % REVERSE_APPLY == APPLY_RECURRINGSPELL)
      {
         mod = abs(mod);
         if (IS_VALID_SN(mod) && (skill = skill_table[mod]) != NULL && skill->type == SKILL_SPELL)
            xSET_BIT(ch->affected_by, AFF_RECURRINGSPELL);
         else
            bug("affect_modify(%s) APPLY_RECURRINGSPELL with bad sn %d", ch->name, mod);
         return;
      }
   }
   else
   {
      xREMOVE_BITS(ch->affected_by, paf->bitvector);
      /*
       * might be an idea to have a duration removespell which returns
       * the spell after the duration... but would have to store
       * the removed spell's information somewhere...  -Thoric
       * (Though we could keep the affect, but disable it for a duration)
       */
      if ((paf->location % REVERSE_APPLY) == APPLY_REMOVESPELL)
         return;

      if (paf->location % REVERSE_APPLY == APPLY_RECURRINGSPELL)
      {
         mod = abs(mod);
         if (!IS_VALID_SN(mod) || (skill = skill_table[mod]) == NULL || skill->type != SKILL_SPELL)
            bug("affect_modify(%s) APPLY_RECURRINGSPELL with bad sn %d", ch->name, mod);
         xREMOVE_BIT(ch->affected_by, AFF_RECURRINGSPELL);
         return;
      }

      switch (paf->location % REVERSE_APPLY)
      {
         case APPLY_AFFECT:
            REMOVE_BIT(ch->affected_by.bits[0], mod);
            return;
         case APPLY_EXT_AFFECT:
            xREMOVE_BIT(ch->affected_by, mod);
            return;
         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;
         case APPLY_WEARSPELL: /* affect only on wear */
            return;
         case APPLY_REMOVE:
            SET_BIT(ch->affected_by.bits[0], mod);
            return;
      }
      mod = 0 - mod;
   }

   switch (paf->location % REVERSE_APPLY)
   {
      default:
         bug("Affect_modify: unknown location %d.", paf->location);
         return;

      case APPLY_NONE:
         break;
      case APPLY_ARMOR:
         ch->apply_armor += mod;
         break;
      case APPLY_SHIELD:
         ch->apply_shield += mod;
         break;
      case APPLY_STONE:
         ch->apply_stone += mod;
         break;
      case APPLY_SANCTIFY:
         ch->apply_sanctify += mod;
         break;
      case APPLY_WMOD:
         if (!fAdd)
         {
            if (mod == -ch->apply_wmod)
               ch->apply_wmod += mod;
            if (ch->apply_wmod < 0)
               ch->apply_wmod = 0;
         }
         else
         {
            if (mod < ch->apply_wmod || ch->apply_wmod == 0)
            {
               ch->apply_wmod = mod;
            }
         }
         break;
         
      case APPLY_RENERGY:
         resist = (ch->apply_res_energy[1] == 0 ? 100 : ch->apply_res_energy[1]);
         susc = (ch->apply_res_energy[2] == 0 ? 100 : ch->apply_res_energy[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_energy[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_energy[1])
                  ch->apply_res_energy[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_energy[2])
                  ch->apply_res_energy[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_energy[1] = 100;
               diff = base_resis_values(ch, 5)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_energy[2]) //Susc
            {
               ch->apply_res_energy[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_energy[1]) //Resist
            {
               ch->apply_res_energy[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_energy[1] = -500;
         }
         resist = (ch->apply_res_energy[1] == 0 ? 100 : ch->apply_res_energy[1]);
         susc = (ch->apply_res_energy[2] == 0 ? 100 : ch->apply_res_energy[2]);
         if (ch->apply_res_energy[1] == -500)
            ch->apply_res_energy[0] = -500;
         else
            ch->apply_res_energy[0] = 100 + diff - (100-resist) + (susc-100);
         break;  
         
      case APPLY_RWATER:
         resist = (ch->apply_res_water[1] == 0 ? 100 : ch->apply_res_water[1]);
         susc = (ch->apply_res_water[2] == 0 ? 100 : ch->apply_res_water[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_water[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_water[1])
                  ch->apply_res_water[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_water[2])
                  ch->apply_res_water[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_water[1] = 100;
               diff = base_resis_values(ch, 2)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_water[2]) //Susc
            {
               ch->apply_res_water[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_water[1]) //Resist
            {
               ch->apply_res_water[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_water[1] = -500;
         }
         resist = (ch->apply_res_water[1] == 0 ? 100 : ch->apply_res_water[1]);
         susc = (ch->apply_res_water[2] == 0 ? 100 : ch->apply_res_water[2]);
         if (ch->apply_res_water[1] == -500)
            ch->apply_res_water[0] = -500;
         else
            ch->apply_res_water[0] = 100 + diff - (100-resist) + (susc-100);
         break;   
         
      case APPLY_REARTH:
         resist = (ch->apply_res_earth[1] == 0 ? 100 : ch->apply_res_earth[1]);
         susc = (ch->apply_res_earth[2] == 0 ? 100 : ch->apply_res_earth[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_earth[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_earth[1])
                  ch->apply_res_earth[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_earth[2])
                  ch->apply_res_earth[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_earth[1] = 100;
               diff = base_resis_values(ch, 4)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_earth[2]) //Susc
            {
               ch->apply_res_earth[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_earth[1]) //Resist
            {
               ch->apply_res_earth[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_earth[1] = -500;
         }
         resist = (ch->apply_res_earth[1] == 0 ? 100 : ch->apply_res_earth[1]);
         susc = (ch->apply_res_earth[2] == 0 ? 100 : ch->apply_res_earth[2]);
         if (ch->apply_res_earth[1] == -500)
            ch->apply_res_earth[0] = -500;
         else
            ch->apply_res_earth[0] = 100 + diff - (100-resist) + (susc-100);
         break;
         
      case APPLY_RAIR:
         resist = (ch->apply_res_air[1] == 0 ? 100 : ch->apply_res_air[1]);
         susc = (ch->apply_res_air[2] == 0 ? 100 : ch->apply_res_air[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_air[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_air[1])
                  ch->apply_res_air[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_air[2])
                  ch->apply_res_air[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_air[1] = 100;
               diff = base_resis_values(ch, 3)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_air[2]) //Susc
            {
               ch->apply_res_air[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_air[1]) //Resist
            {
               ch->apply_res_air[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_air[1] = -500;
         }
         resist = (ch->apply_res_air[1] == 0 ? 100 : ch->apply_res_air[1]);
         susc = (ch->apply_res_air[2] == 0 ? 100 : ch->apply_res_air[2]);
         if (ch->apply_res_air[1] == -500)
            ch->apply_res_air[0] = -500;
         else
            ch->apply_res_air[0] = 100 + diff - (100-resist) + (susc-100);
         break;
         
      case APPLY_RFIRE:
         resist = (ch->apply_res_fire[1] == 0 ? 100 : ch->apply_res_fire[1]);
         susc = (ch->apply_res_fire[2] == 0 ? 100 : ch->apply_res_fire[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_fire[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_fire[1])
                  ch->apply_res_fire[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_fire[2])
                  ch->apply_res_fire[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_fire[1] = 100;
               diff = base_resis_values(ch, 1)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_fire[2]) //Susc
            {
               ch->apply_res_fire[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_fire[1]) //Resist
            {
               ch->apply_res_fire[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_fire[1] = -500;
         }
         resist = (ch->apply_res_fire[1] == 0 ? 100 : ch->apply_res_fire[1]);
         susc = (ch->apply_res_fire[2] == 0 ? 100 : ch->apply_res_fire[2]);
         if (ch->apply_res_fire[1] == -500)
            ch->apply_res_fire[0] = -500;
         else
            ch->apply_res_fire[0] = 100 + diff - (100-resist) + (susc-100);
         break;
         
      case APPLY_RMAGIC:
         resist = (ch->apply_res_magic[1] == 0 ? 100 : ch->apply_res_magic[1]);
         susc = (ch->apply_res_magic[2] == 0 ? 100 : ch->apply_res_magic[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_magic[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_magic[1])
                  ch->apply_res_magic[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_magic[2])
                  ch->apply_res_magic[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_magic[1] = 100;
               diff = base_resis_values(ch, 9)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_magic[2]) //Susc
            {
               ch->apply_res_magic[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_magic[1]) //Resist
            {
               ch->apply_res_magic[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_magic[1] = -500;
         }
         resist = (ch->apply_res_magic[1] == 0 ? 100 : ch->apply_res_magic[1]);
         susc = (ch->apply_res_magic[2] == 0 ? 100 : ch->apply_res_magic[2]);
         if (ch->apply_res_magic[1] == -500)
            ch->apply_res_magic[0] = -500;
         else
            ch->apply_res_magic[0] = 100 + diff - (100-resist) + (susc-100);
         break;
         
      case APPLY_RNONMAGIC:
         resist = (ch->apply_res_nonmagic[1] == 0 ? 100 : ch->apply_res_nonmagic[1]);
         susc = (ch->apply_res_nonmagic[2] == 0 ? 100 : ch->apply_res_nonmagic[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_nonmagic[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_nonmagic[1])
                  ch->apply_res_nonmagic[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_nonmagic[2])
                  ch->apply_res_nonmagic[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_nonmagic[1] = 100;
               diff = base_resis_values(ch, 8)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_nonmagic[2]) //Susc
            {
               ch->apply_res_nonmagic[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_nonmagic[1]) //Resist
            {
               ch->apply_res_nonmagic[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_nonmagic[1] = -500;
         }
         resist = (ch->apply_res_nonmagic[1] == 0 ? 100 : ch->apply_res_nonmagic[1]);
         susc = (ch->apply_res_nonmagic[2] == 0 ? 100 : ch->apply_res_nonmagic[2]);
         if (ch->apply_res_nonmagic[1] == -500)
            ch->apply_res_nonmagic[0] = -500;
         else
            ch->apply_res_nonmagic[0] = 100 + diff - (100-resist) + (susc-100);
         break;
         
      case APPLY_RBLUNT:
         resist = (ch->apply_res_blunt[1] == 0 ? 100 : ch->apply_res_blunt[1]);
         susc = (ch->apply_res_blunt[2] == 0 ? 100 : ch->apply_res_blunt[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_blunt[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_blunt[1])
                  ch->apply_res_blunt[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_blunt[2])
                  ch->apply_res_blunt[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_blunt[1] = 100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_blunt[2]) //Susc
            {
               ch->apply_res_blunt[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_blunt[1]) //Resist
            {
               ch->apply_res_blunt[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_blunt[1] = -500;
         }
         resist = (ch->apply_res_blunt[1] == 0 ? 100 : ch->apply_res_blunt[1]);
         susc = (ch->apply_res_blunt[2] == 0 ? 100 : ch->apply_res_blunt[2]);
         if (ch->apply_res_blunt[1] == -500)
            ch->apply_res_blunt[0] = -500;
         else
            ch->apply_res_blunt[0] = 100 + diff - (100-resist) + (susc-100);
         break;  
         
      case APPLY_RPIERCE:
         resist = (ch->apply_res_pierce[1] == 0 ? 100 : ch->apply_res_pierce[1]);
         susc = (ch->apply_res_pierce[2] == 0 ? 100 : ch->apply_res_pierce[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_pierce[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_pierce[1])
                  ch->apply_res_pierce[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_pierce[2])
                  ch->apply_res_pierce[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_pierce[1] = 100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_pierce[2]) //Susc
            {
               ch->apply_res_pierce[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_pierce[1]) //Resist
            {
               ch->apply_res_pierce[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_pierce[1] = -500;
         }
         resist = (ch->apply_res_pierce[1] == 0 ? 100 : ch->apply_res_pierce[1]);
         susc = (ch->apply_res_pierce[2] == 0 ? 100 : ch->apply_res_pierce[2]);
         if (ch->apply_res_pierce[1] == -500)
            ch->apply_res_pierce[0] = -500;
         else
            ch->apply_res_pierce[0] = 100 + diff - (100-resist) + (susc-100);
         break;  
         
     case APPLY_RSLASH:
         resist = (ch->apply_res_slash[1] == 0 ? 100 : ch->apply_res_slash[1]);
         susc = (ch->apply_res_slash[2] == 0 ? 100 : ch->apply_res_slash[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_slash[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_slash[1])
                  ch->apply_res_slash[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_slash[2])
                  ch->apply_res_slash[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_slash[1] = 100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_slash[2]) //Susc
            {
               ch->apply_res_slash[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_slash[1]) //Resist
            {
               ch->apply_res_slash[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_slash[1] = -500;
         }
         resist = (ch->apply_res_slash[1] == 0 ? 100 : ch->apply_res_slash[1]);
         susc = (ch->apply_res_slash[2] == 0 ? 100 : ch->apply_res_slash[2]);
         if (ch->apply_res_slash[1] == -500)
            ch->apply_res_slash[0] = -500;
         else
            ch->apply_res_slash[0] = 100 + diff - (100-resist) + (susc-100);
         break;      
         
      case APPLY_RPOISON:
         resist = (ch->apply_res_poison[1] == 0 ? 100 : ch->apply_res_poison[1]);
         susc = (ch->apply_res_poison[2] == 0 ? 100 : ch->apply_res_poison[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_poison[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_poison[1])
                  ch->apply_res_poison[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_poison[2])
                  ch->apply_res_poison[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_poison[1] = 100;
               diff = base_resis_values(ch, 10)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_poison[2]) //Susc
            {
               ch->apply_res_poison[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_poison[1]) //Resist
            {
               ch->apply_res_poison[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_poison[1] = -500;
         }
         resist = (ch->apply_res_poison[1] == 0 ? 100 : ch->apply_res_poison[1]);
         susc = (ch->apply_res_poison[2] == 0 ? 100 : ch->apply_res_poison[2]);
         if (ch->apply_res_poison[1] == -500)
            ch->apply_res_poison[0] = -500;
         else
            ch->apply_res_poison[0] = 100 + diff - (100-resist) + (susc-100);
         break;      
         
      case APPLY_RPARALYSIS:
         resist = (ch->apply_res_paralysis[1] == 0 ? 100 : ch->apply_res_paralysis[1]);
         susc = (ch->apply_res_paralysis[2] == 0 ? 100 : ch->apply_res_paralysis[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_paralysis[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_paralysis[1])
                  ch->apply_res_paralysis[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_paralysis[2])
                  ch->apply_res_paralysis[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_paralysis[1] = 100;
               diff = base_resis_values(ch, 11)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_paralysis[2]) //Susc
            {
               ch->apply_res_poison[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_paralysis[1]) //Resist
            {
               ch->apply_res_paralysis[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_paralysis[1] = -500;
         }
         resist = (ch->apply_res_paralysis[1] == 0 ? 100 : ch->apply_res_paralysis[1]);
         susc = (ch->apply_res_paralysis[2] == 0 ? 100 : ch->apply_res_paralysis[2]);
         if (ch->apply_res_paralysis[1] == -500)
            ch->apply_res_paralysis[0] = -500;
         else
            ch->apply_res_paralysis[0] = 100 + diff - (100-resist) + (susc-100);
         break;      
         
      case APPLY_RHOLY:
         resist = (ch->apply_res_holy[1] == 0 ? 100 : ch->apply_res_holy[1]);
         susc = (ch->apply_res_holy[2] == 0 ? 100 : ch->apply_res_holy[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_holy[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_holy[1])
                  ch->apply_res_holy[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_holy[2])
                  ch->apply_res_holy[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_holy[1] = 100;
               diff = base_resis_values(ch, 6)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_holy[2]) //Susc
            {
               ch->apply_res_holy[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_holy[1]) //Resist
            {
               ch->apply_res_holy[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_holy[1] = -500;
         }
         resist = (ch->apply_res_holy[1] == 0 ? 100 : ch->apply_res_holy[1]);
         susc = (ch->apply_res_holy[2] == 0 ? 100 : ch->apply_res_holy[2]);
         if (ch->apply_res_holy[1] == -500)
            ch->apply_res_holy[0] = -500;
         else
            ch->apply_res_holy[0] = 100 + diff - (100-resist) + (susc-100);
         break; 
         
      case APPLY_RUNHOLY:
         resist = (ch->apply_res_unholy[1] == 0 ? 100 : ch->apply_res_unholy[1]);
         susc = (ch->apply_res_unholy[2] == 0 ? 100 : ch->apply_res_unholy[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_unholy[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_unholy[1])
                  ch->apply_res_unholy[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_unholy[2])
                  ch->apply_res_unholy[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_unholy[1] = 100;
               diff = base_resis_values(ch, 7)-100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_unholy[2]) //Susc
            {
               ch->apply_res_unholy[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_unholy[1]) //Resist
            {
               ch->apply_res_unholy[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_unholy[1] = -500;
         }
         resist = (ch->apply_res_unholy[1] == 0 ? 100 : ch->apply_res_unholy[1]);
         susc = (ch->apply_res_unholy[2] == 0 ? 100 : ch->apply_res_unholy[2]);
         if (ch->apply_res_unholy[1] == -500)
            ch->apply_res_unholy[0] = -500;
         else
            ch->apply_res_unholy[0] = 100 + diff - (100-resist) + (susc-100);
         break;  
         
      case APPLY_RUNDEAD:
         resist = (ch->apply_res_undead[1] == 0 ? 100 : ch->apply_res_undead[1]);
         susc = (ch->apply_res_undead[2] == 0 ? 100 : ch->apply_res_undead[2]);
         //Getting the natural "susc/resist" to add back in later...
         diff = (ch->apply_res_undead[0] + (100-resist) - (susc-100)) - 100;
         if (!fAdd)
         {
            if (mod == 0 || mod == -1) //0 and 1 will not work
               ;
            if (mod > -100) //Resist
            {
               if (mod == -ch->apply_res_undead[1])
                  ch->apply_res_undead[1] = 100;
            }
            if (mod < -100) //Susc
            {
               if (mod == -ch->apply_res_undead[2])
                  ch->apply_res_undead[2] = 100;   
            }
            if (mod == 1) //Immune
            {
               ch->apply_res_undead[1] = 100;
            }
         }
         else
         {
            if (mod > 100 && mod > ch->apply_res_undead[2]) //Susc
            {
               ch->apply_res_undead[2] = mod;
            }
            if (mod < 100 && mod > 1 && mod < ch->apply_res_undead[1]) //Resist
            {
               ch->apply_res_undead[1] = mod;
            }
            if (mod == -1) //Immune
               ch->apply_res_undead[1] = -500;
         }
         resist = (ch->apply_res_undead[1] == 0 ? 100 : ch->apply_res_undead[1]);
         susc = (ch->apply_res_undead[2] == 0 ? 100 : ch->apply_res_undead[2]);
         if (ch->apply_res_undead[1] == -500)
            ch->apply_res_undead[0] = -500;
         else
            ch->apply_res_undead[0] = 100 + diff - (100-resist) + (susc-100);
         break;        
         
      case APPLY_MANAFUSE:
         if (mod > ch->apply_manafuse)
         {
            ch->apply_manafuse = mod;
         }
         if (mod < 0 && mod + ch->apply_manafuse == 0)
            ch->apply_manafuse = 0;
         break;
      case APPLY_FASTING:
         if (mod > ch->apply_fasting)
         {
            ch->apply_fasting = mod;
         }
         if (mod < 0 && mod + ch->apply_fasting == 0)
            ch->apply_fasting = 0;
         break;
      case APPLY_MANASHELL:
         if (mod > ch->apply_manashell)
         {
            ch->apply_manashell = mod;
         }
         if (mod < 0 && mod + ch->apply_manashell == 0)
            ch->apply_manashell = 0;
         break;
      case APPLY_MANASHIELD:
         if (mod > ch->apply_manashield)
         {
            ch->apply_manashield = mod;
         }
         if (mod < 0 && mod + ch->apply_manashield == 0)
            ch->apply_manashield = 0;
         break;
      case APPLY_MANAGUARD:
         if (mod > ch->apply_managuard)
         {
            ch->apply_managuard = mod;
         }
         if (mod < 0 && mod + ch->apply_managuard == 0)
            ch->apply_managuard = 0;
         break;
         
      case APPLY_MANABURN:
         if (mod > ch->apply_manaburn)
         {
            ch->apply_manaburn = mod;
         }
         if (mod < 0 && mod + ch->apply_manaburn == 0)
            ch->apply_manaburn = 0;
         break;
      case APPLY_WEAPONCLAMP:
         if (mod > ch->apply_weaponclamp)
         {
            ch->apply_weaponclamp = mod;
         }
         if (mod < 0 && mod + ch->apply_weaponclamp == 0)
            ch->apply_weaponclamp = 0;
         break;  
      case APPLY_ARROWCATCH:
         if (mod > ch->apply_arrowcatch)
         {
            ch->apply_arrowcatch = mod;
         }
         if (mod < 0 && mod + ch->apply_arrowcatch == 0)
            ch->apply_arrowcatch = 0;
         break;  
      case APPLY_BRACING:
         if (mod > ch->apply_bracing)
         {
            ch->apply_bracing = mod;
         }
         if (mod < 0 && mod + ch->apply_bracing == 0)
            ch->apply_bracing = 0;
         break;    
      case APPLY_HARDENING:
         if (mod > ch->apply_hardening)
         {
            ch->apply_hardening = mod;
         }
         if (mod < 0 && mod + ch->apply_hardening == 0)
            ch->apply_hardening = 0;
         break;   
      case APPLY_TOHIT:
         ch->apply_tohit += mod;
         break;
      case APPLY_MANATICK:
         if (mod > ch->managen)
         {
            ch->managen = mod;
         }
         if (mod < 0 && mod + ch->managen == 0)
            ch->managen = 0;
         break;
      case APPLY_HPTICK:
         if (mod > ch->hpgen)
         {
            ch->hpgen = mod;
         }
         if (mod < 0 && mod + ch->hpgen == 0)
            ch->hpgen = 0;
         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_CHA:
         ch->mod_cha += mod;
         break;
      case APPLY_LCK:
         ch->mod_lck += mod;
         break;
      case APPLY_AGI:
         ch->mod_agi += mod;
         break;
      case APPLY_SEX:
         ch->sex = (ch->sex + mod) % 3;
         if (ch->sex < 0)
            ch->sex += 2;
         ch->sex = URANGE(0, ch->sex, 2);
         break;

         /*
          * These are unused due to possible problems.  Enable at your own risk.
          */
      case APPLY_CLASS:
         break;
      case APPLY_LEVEL:
         break;
      case APPLY_AGE:
         break;
      case APPLY_GOLD:
         break;
      case APPLY_EXP:
         break;

         /*
          * Regular apply types
          */
      case APPLY_HEIGHT:
         ch->height += mod;
         break;
      case APPLY_WEIGHT:
         ch->weight += mod;
         break;
      case APPLY_MANA:
         /*if (mod > ch->max_mana)
            mod = paf->modifier = ch->max_mana;
         for (saf = ch->first_affect; saf; saf = saf->next)
         {
            if ((saf->location % REVERSE_APPLY) == APPLY_MANA && saf != paf && fAdd)
               paf->modifier = mod = 0;
         }*/
         ch->max_mana += mod;
         break;
      case APPLY_HIT:
         /*if (mod > ch->max_hit)
            mod = paf->modifier = ch->max_hit; 
         for (saf = ch->first_affect; saf; saf = saf->next)
         {
            if ((saf->location % REVERSE_APPLY) == APPLY_HIT && saf != paf && fAdd)
               paf->modifier = mod = 0;
         } */
         ch->max_hit += mod;
         break;
      case APPLY_MOVE:
         ch->max_move += mod;
         break;
      case APPLY_HITROLL:
         ch->hitroll += mod;
         break;
      case APPLY_DAMROLL:
         ch->damroll += mod;
         break;
      case APPLY_SAVING_POISON:
         ch->saving_poison_death += mod;
         break;
      case APPLY_SAVING_ROD:
         ch->saving_wand += mod;
         break;
      case APPLY_SAVING_PARA:
         ch->saving_para_petri += mod;
         break;
      case APPLY_SAVING_BREATH:
         ch->saving_breath += mod;
         break;
      case APPLY_SAVING_SPELL:
         ch->saving_spell_staff += mod;
         break;

         /*
          * Bitvector modifying apply types
          */
      case APPLY_AFFECT:
         SET_BIT(ch->affected_by.bits[0], mod);
         break;
      case APPLY_EXT_AFFECT:
         xSET_BIT(ch->affected_by, mod);
         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_WEAPONSPELL: /* see fight.c */
         break;
      case APPLY_REMOVE:
         REMOVE_BIT(ch->affected_by.bits[0], mod);
         break;

         /*
          * Player condition modifiers
          */
      case APPLY_FULL:
         if (!IS_NPC(ch))
            ch->pcdata->condition[COND_FULL] = URANGE(0, ch->pcdata->condition[COND_FULL] + mod, 48);
         break;

      case APPLY_THIRST:
         if (!IS_NPC(ch))
            ch->pcdata->condition[COND_THIRST] = URANGE(0, ch->pcdata->condition[COND_THIRST] + mod, 48);
         break;

      case APPLY_DRUNK:
         if (!IS_NPC(ch))
            ch->pcdata->condition[COND_DRUNK] = URANGE(0, ch->pcdata->condition[COND_DRUNK] + mod, 48);
         break;

      case APPLY_BLOOD:
         if (!IS_NPC(ch))
            ch->pcdata->condition[COND_BLOODTHIRST] = URANGE(0, ch->pcdata->condition[COND_BLOODTHIRST] + mod, ch->level + 10);
         break;

      case APPLY_MENTALSTATE:
         ch->mental_state = URANGE(-100, ch->mental_state + mod, 100);
         break;
      case APPLY_EMOTION:
         ch->emotional_state = URANGE(-100, ch->emotional_state + mod, 100);
         break;


         /*
          * Specialty modfiers
          */
      case APPLY_CONTAGIOUS:
         break;
      case APPLY_ODOR:
         break;
      case APPLY_STRIPSN:
         if (IS_VALID_SN(mod))
            affect_strip(ch, mod);
         else
            bug("affect_modify: APPLY_STRIPSN invalid sn %d", mod);
         break;

/* spell cast upon wear/removal of an object	-Thoric */
      case APPLY_WEARSPELL:
      case APPLY_REMOVESPELL:
         if (xIS_SET(ch->in_room->room_flags, ROOM_NO_MAGIC) || wIS_SET(ch, ROOM_NO_MAGIC) || is_immune(ch, -1, RIS_MAGIC) 
         ||  saving_char == ch /* so save/quit doesn't trigger */  || loading_char == ch) /* so loading doesn't trigger */
            return;

         mod = abs(mod);
         if (IS_VALID_SN(mod) && (skill = skill_table[mod]) != NULL && skill->type == SKILL_SPELL)
         {
            if (skill->target == TAR_IGNORE || skill->target == TAR_OBJ_INV || skill->target == TAR_OBJ_ROOM)
            {
               bug("APPLY_WEARSPELL trying to apply bad target spell.  SN is %d.", mod);
               return;
            }
            if ((retcode = (*skill->spell_fun) (mod, ch->level, ch, ch)) == rCHAR_DIED || char_died(ch))
               return;
         }
         break;


         /*
          * Skill apply types
          */
      case APPLY_PALM: /* not implemented yet */
         break;
      case APPLY_TRACK:
         modify_skill(ch, gsn_track, mod, fAdd);
         break;
      case APPLY_HIDE:
         modify_skill(ch, gsn_hide, mod, fAdd);
         break;
      case APPLY_STEAL:
         modify_skill(ch, gsn_steal, mod, fAdd);
         break;
      case APPLY_SNEAK:
         modify_skill(ch, gsn_sneak, mod, fAdd);
         break;
      case APPLY_PICK:
         modify_skill(ch, gsn_pick_lock, mod, fAdd);
         break;
      case APPLY_BACKSTAB:
         modify_skill(ch, gsn_backstab, mod, fAdd);
         break;
      case APPLY_DETRAP:
         modify_skill(ch, gsn_detrap, mod, fAdd);
         break;
      case APPLY_DODGE:
         modify_skill(ch, gsn_dodge, mod, fAdd);
         break;
      case APPLY_PEEK:
         modify_skill(ch, gsn_peek, mod, fAdd);
         break;
      case APPLY_SCAN:
         modify_skill(ch, gsn_scan, mod, fAdd);
         break;
      case APPLY_GOUGE:
         modify_skill(ch, gsn_gouge, mod, fAdd);
         break;
      case APPLY_SEARCH:
         modify_skill(ch, gsn_search, mod, fAdd);
         break;
      case APPLY_DIG:
         modify_skill(ch, gsn_dig, mod, fAdd);
         break;
      case APPLY_MOUNT:
         break;
      case APPLY_DISARM:
         modify_skill(ch, gsn_disarm, mod, fAdd);
         break;
      case APPLY_KICK:
         break;
      case APPLY_PARRY:
         modify_skill(ch, gsn_parry, mod, fAdd);
         break;
      case APPLY_BASH:
         break;
      case APPLY_STUN:
         modify_skill(ch, gsn_stun, mod, fAdd);
         break;
      case APPLY_PUNCH:
         break;
      case APPLY_CLIMB:
         modify_skill(ch, gsn_climb, mod, fAdd);
         break;
      case APPLY_GRIP:
         modify_skill(ch, gsn_grip, mod, fAdd);
         break;
      case APPLY_SCRIBE:
         modify_skill(ch, gsn_scribe, mod, fAdd);
         break;
      case APPLY_BREW:
         modify_skill(ch, gsn_brew, mod, fAdd);
         break;
      case APPLY_COOK:
         modify_skill(ch, gsn_cook, mod, fAdd);
         break;

         /*
          * Room apply types
          */
      case APPLY_ROOMFLAG:
      case APPLY_SECTORTYPE:
      case APPLY_ROOMLIGHT:
      case APPLY_TELEVNUM:
         break;

         /*
          * Object apply types
          */
   }

   /*
    * Check for weapon wielding.
    * Guard against recursion (for weapons with affects).
    */
   if (!IS_NPC(ch) && saving_char != ch && (wield = get_eq_char(ch, WEAR_WIELD)) != NULL && get_obj_weight(wield) > str_app[get_curr_str(ch)].wield)
   {
      static int depth;

      if (depth == 0)
      {
         depth++;
         act(AT_ACTION, "You notice your strength decrease thus taking more time to swing your weapon!", ch, wield, NULL, TO_CHAR);
         depth--;
      }
   }

   return;
}



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

   if (!ch)
   {
      bug("Affect_to_char(NULL, %d)", paf ? paf->type : 0);
      return;
   }

   if (!paf)
   {
      bug("Affect_to_char(%s, NULL)", ch->name);
      return;
   }

   CREATE(paf_new, AFFECT_DATA, 1);
   LINK(paf_new, ch->first_affect, ch->last_affect, next, prev);
   paf_new->type = paf->type;
   paf_new->duration = paf->duration;
   paf_new->location = paf->location;
   paf_new->modifier = paf->modifier;
   paf_new->bitvector = paf->bitvector;

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


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

   affect_modify(ch, paf, FALSE);

   UNLINK(paf, ch->first_affect, ch->last_affect, next, prev);
   DISPOSE(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->first_affect; paf; 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->first_affect; paf; paf = paf->next)
      if (paf->type == sn)
         return TRUE;

   return FALSE;
}


/*
 * Add or enhance an affect.
 * Limitations put in place by Thoric, they may be high... but at least
 * they're there :)
 */
void affect_join(CHAR_DATA * ch, AFFECT_DATA * paf)
{
   AFFECT_DATA *paf_old;

   for (paf_old = ch->first_affect; paf_old; paf_old = paf_old->next)
      if (paf_old->type == paf->type)
      {
         paf->duration = UMIN(1000000, paf->duration + paf_old->duration);
         if (paf->modifier < 0)
         {
            if (paf_old->modifier < paf->modifier)
               paf->modifier = paf_old->modifier;
         }
         else if (paf->modifier > 0)
         {
            if (paf_old->modifier > paf->modifier)
               paf->modifier = paf_old->modifier;
         }
         affect_remove(ch, paf_old);
         break;
      }

   affect_to_char(ch, paf);
   return;
}


/*
 * Apply only affected and RIS on a char
 */
void aris_affect(CHAR_DATA * ch, AFFECT_DATA * paf)
{
   xSET_BITS(ch->affected_by, paf->bitvector);
   switch (paf->location % REVERSE_APPLY)
   {
      case APPLY_AFFECT:
         SET_BIT(ch->affected_by.bits[0], paf->modifier);
         break;
      case APPLY_EXT_AFFECT:
         xSET_BIT(ch->affected_by, paf->modifier);
         
      case APPLY_RESISTANT:
         SET_BIT(ch->resistant, paf->modifier);
         break;
      case APPLY_IMMUNE:
         SET_BIT(ch->immune, paf->modifier);
         break;
      case APPLY_SUSCEPTIBLE:
         SET_BIT(ch->susceptible, paf->modifier);
         break;
   }
}

/*
 * Update affecteds and RIS for a character in case things get messed.
 * This should only really be used as a quick fix until the cause
 * of the problem can be hunted down. - FB
 * Last modified: June 30, 1997
 *
 * Quick fix?  Looks like a good solution for a lot of problems.
 */

/* Temp mod to bypass immortals so they can keep their mset affects,
 * just a band-aid until we get more time to look at it -- Blodkai */
void update_aris(CHAR_DATA * ch)
{
   AFFECT_DATA *paf;
   OBJ_DATA *obj;
   int hiding;

   if (IS_NPC(ch) || IS_IMMORTAL(ch))
      return;

   /* So chars using hide skill will continue to hide */
   hiding = IS_AFFECTED(ch, AFF_HIDE);

   xCLEAR_BITS(ch->affected_by);
   ch->resistant = 0;
   ch->immune = 0;
   ch->susceptible = 0;
   xCLEAR_BITS(ch->no_affected_by);
   ch->no_resistant = 0;
   ch->no_immune = 0;
   ch->no_susceptible = 0;

   /* Add in effects from race */
   xSET_BITS(ch->affected_by, race_table[ch->race]->affected);
   SET_BIT(ch->resistant, race_table[ch->race]->resist);
   SET_BIT(ch->susceptible, race_table[ch->race]->suscept);

   /* Add in effects from deities */
   if (ch->pcdata->deity)
   {
      if (ch->pcdata->favor > ch->pcdata->deity->affectednum)
         xSET_BITS(ch->affected_by, ch->pcdata->deity->affected);
      if (ch->pcdata->favor > ch->pcdata->deity->elementnum)
         SET_BIT(ch->resistant, ch->pcdata->deity->element);
      if (ch->pcdata->favor < ch->pcdata->deity->susceptnum)
         SET_BIT(ch->susceptible, ch->pcdata->deity->suscept);
   }

   /* Add in effect from spells */
   for (paf = ch->first_affect; paf; paf = paf->next)
      aris_affect(ch, paf);

   /* Add in effects from equipment */
   for (obj = ch->first_carrying; obj; obj = obj->next_content)
   {
      if (obj->wear_loc != WEAR_NONE)
      {
         for (paf = obj->first_affect; paf; paf = paf->next)
            aris_affect(ch, paf);

         for (paf = obj->pIndexData->first_affect; paf; paf = paf->next)
            aris_affect(ch, paf);
      }
   }

   /* Add in effects from the room */
   if (ch->in_room) /* non-existant char booboo-fix --TRI */
      for (paf = ch->in_room->first_affect; paf; paf = paf->next)
         aris_affect(ch, paf);

   /* Add in effects for polymorph */
   if (ch->morph)
   {
      xSET_BITS(ch->affected_by, ch->morph->affected_by);
      SET_BIT(ch->immune, ch->morph->immune);
      SET_BIT(ch->resistant, ch->morph->resistant);
      SET_BIT(ch->susceptible, ch->morph->suscept);
      /* Right now only morphs have no_ things --Shaddai */
      xSET_BITS(ch->no_affected_by, ch->morph->no_affected_by);
      SET_BIT(ch->no_immune, ch->morph->no_immune);
      SET_BIT(ch->no_resistant, ch->morph->no_resistant);
      SET_BIT(ch->no_susceptible, ch->morph->no_suscept);
   }

   /* If they were hiding before, make them hiding again */
   if (hiding)
      xSET_BIT(ch->affected_by, AFF_HIDE);

   return;
}


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

   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_LIGHT)) != NULL && obj->item_type == ITEM_LIGHT && obj->value[2] != 0 && ch->in_room->light > 0)
      --ch->in_room->light;

   /*
    * Character's affect on the room
    */
   for (paf = ch->first_affect; paf; paf = paf->next)
      room_affect(ch->in_room, paf, FALSE);

   if (!IS_NPC(ch) && xIS_SET(ch->act, PLR_MAPWINDOW) && ch->in_room->vnum == OVERLAND_SOLAN)
   {
      ch_printf(ch, "%s", MXPTAG("FRAME Map CLOSE"));
      ch->pcdata->xsize = 0;
      ch->pcdata->ysize = 0;
   }

   /*
    * Room's affect on the character
    */
   if (!char_died(ch))
   {
      for (paf = ch->in_room->first_affect; paf; paf = paf->next)
         affect_modify(ch, paf, FALSE);

      if (char_died(ch)) /* could die from removespell, etc */
         return;
   }
   if (IS_NPC(ch))
   {
      for (mch = first_wilderchar; mch; mch = mch->next)
      {
         if (mch->mapch == ch && (mch->mapch->coord->x == ch->coord->x && mch->mapch->coord->y == ch->coord->y && mch->mapch->map == ch->map))
         {
            UNLINK(mch, first_wilderchar, last_wilderchar, next, prev);
            top_map_mob--;
         }
      }
   }

   UNLINK(ch, ch->in_room->first_person, ch->in_room->last_person, next_in_room, prev_in_room);
   ch->was_in_room = ch->in_room;
   ch->in_room = NULL;
   ch->next_in_room = NULL;
   ch->prev_in_room = NULL;

   if (!IS_NPC(ch) && get_timer(ch, TIMER_SHOVEDRAG) > 0)
      remove_timer(ch, TIMER_SHOVEDRAG);

   return;
}

/*
 * Enough resources to build? Docks if needed -- Xerves 12/99
 */
bool enough_resources(CHAR_DATA * ch, int hometown, int needed, int ctype)
{
   if (needed > ch->pcdata->town->lumber)
   {
      ch_printf(ch, "You need %d units, your hometown cannot afford that.\n\r", needed);
      return FALSE;
   }
   if (ctype == 0)
      ch->pcdata->town->lumber -= needed;
   return TRUE;
}

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

   if (!ch)
   {
      bug("Char_to_room: NULL ch!", 0);
      return;
   }
   if (!pRoomIndex)
   {
      bug("Char_to_room: %s -> NULL room!  Putting char in limbo (%d)", ch->name, ROOM_VNUM_LIMBO);
      /*
       * This used to just return, but there was a problem with crashing
       * and I saw no reason not to just put the char in limbo.  -Narn
       */
      pRoomIndex = get_room_index(ROOM_VNUM_LIMBO);
   }

   ch->in_room = pRoomIndex;
   LINK(ch, pRoomIndex->first_person, pRoomIndex->last_person, next_in_room, prev_in_room);

   if (IS_NPC(ch) && ch->in_room->vnum == OVERLAND_SOLAN)
   {
      CREATE(mch, CMAP_DATA, 1);
      mch->mapch = ch;
      LINK(mch, first_wilderchar, last_wilderchar, next, prev);
      top_map_mob++;
   }

   if (!IS_NPC(ch))
      if (++pRoomIndex->area->nplayer > pRoomIndex->area->max_players)
         pRoomIndex->area->max_players = pRoomIndex->area->nplayer;

   if ((obj = get_eq_char(ch, WEAR_LIGHT)) != NULL && obj->item_type == ITEM_LIGHT && obj->value[2] != 0)
      ++pRoomIndex->light;
      
   if (ch->pcdata && ch->pcdata->quest && ch->pcdata->quest->questarea == ch->in_room->area 
   && ch->pcdata->quest->timeleft > 0 && ch->pcdata->quest->mission == 2)
   {
      int x;
      CHAR_DATA *gch;
      
      ch->pcdata->quest->killed++;
      if (ch->pcdata->quest->traveltime > -1)
         ch->pcdata->quest->traveltime = 0;
      if (pRoomIndex->vnum == pRoomIndex->area->hi_r_vnum) //Win
      {
         for (x = 0; x <= 5; x++)
         {
            if (ch->pcdata->quest->player[x] == ch->pcdata->pid)
            {
               ch_printf(ch, "\n\r^r&CYou have completed your quest, your reward is %d QP^x\n\r\n\r", ch->pcdata->quest->qp[x]);
               ch->pcdata->quest_curr += ch->pcdata->quest->qp[x];
               ch->pcdata->quest_accum += ch->pcdata->quest->qp[x];
               ch->pcdata->quest_wins++;
            }
         }
         for (gch = first_char; gch; gch = gch->next)
         {
            if (IS_NPC(gch))
               continue;
            if (gch == ch)
               continue;
            if (!gch->pcdata->quest)
               continue;
            if (gch->pcdata->quest->questarea != ch->in_room->area)
               continue;
            if (gch->pcdata->quest != ch->pcdata->quest)
               continue;
            for (x = 0; x <= 5; x++)
            {
               if (gch->pcdata->quest->player[x] == gch->pcdata->pid)
               {
                  ch_printf(gch, "\n\r^r&CYou have completed your quest, your reward is %d QP^x\n\r\n\r", gch->pcdata->quest->qp[x]);
                  gch->pcdata->quest_curr += gch->pcdata->quest->qp[x];
                  gch->pcdata->quest_accum += gch->pcdata->quest->qp[x];
                  gch->pcdata->quest_wins++;
                  gch->pcdata->quest->timeleft = -1;
                  gch->pcdata->quest->tillnew = 25;
               }
            }
         }
         ch->pcdata->quest->timeleft = -1;
         ch->pcdata->quest->tillnew = 25;
      }
   }      

   /*
    * Room's effect on the character
    */
   if (!char_died(ch))
   {
      for (paf = pRoomIndex->first_affect; paf; paf = paf->next)
         affect_modify(ch, paf, TRUE);

      if (char_died(ch)) /* could die from a wearspell, etc */
         return;
   }

   /*
    * Character's effect on the room
    */
   for (paf = ch->first_affect; paf; paf = paf->next)
      room_affect(pRoomIndex, paf, TRUE);


   if (!IS_NPC(ch) && (check_room_pk(ch) == 1))
   {
      if (get_timer(ch, TIMER_SHOVEDRAG) > 0)
         remove_timer(ch, TIMER_SHOVEDRAG);
      add_timer(ch, TIMER_SHOVEDRAG, 4, NULL, 0);/*-12 Seconds-*/
   }

   /*
    * Delayed Teleport rooms     -Thoric
    * Should be the last thing checked in this function
    */
   if (xIS_SET(pRoomIndex->room_flags, ROOM_TELEPORT) && pRoomIndex->tele_delay > 0)
   {
      TELEPORT_DATA *tele;

      for (tele = first_teleport; tele; tele = tele->next)
         if (tele->room == pRoomIndex)
            return;

      CREATE(tele, TELEPORT_DATA, 1);
      LINK(tele, first_teleport, last_teleport, next, prev);
      tele->room = pRoomIndex;
      tele->timer = pRoomIndex->tele_delay;
   }
   if (ch->on)
   {
      ch->on = NULL;
      ch->position = POS_STANDING;
   }
   if (ch->mount)
   {
      ch->mount->on = NULL;
      ch->mount->position = POS_STANDING;
   }
   if (!ch->was_in_room)
      ch->was_in_room = ch->in_room;
   return;
}

//Checks carrying weight/number, replaced the integer due to it being inaccurate at times
float get_ch_carry_weight(CHAR_DATA *ch)
{
   OBJ_DATA *obj;
   float weight = 0;
   
   for (obj = ch->first_carrying; obj; obj = obj->next_content) 
   {
      weight += get_obj_weight(obj);
   }
   if (ch->rider)
   {
      weight += (float)ch->rider->weight;
      weight += get_ch_carry_weight(ch->rider);
   }
   return weight;
}
int get_ch_carry_number(CHAR_DATA *ch)
{
   OBJ_DATA *obj;
   int weight = 0;
   
   for (obj = ch->first_carrying; obj; obj = obj->next_content) 
   {
      if (obj->wear_loc == WEAR_NONE)
         weight += get_obj_number(obj);
   }
   return weight;
}

OBJ_DATA *bank_to_char(OBJ_DATA * obj, CHAR_DATA *ch)
{
   if (ch != NULL)
   {
      if (IN_WILDERNESS(ch))
      {
         SET_OBJ_STAT(obj, ITEM_ONMAP);
         obj->map = ch->map;
         obj->coord->x = ch->coord->x;
         obj->coord->y = ch->coord->y;
      }
      else
      {
         REMOVE_OBJ_STAT(obj, ITEM_ONMAP);
         obj->map = -1;
         obj->coord->x = -1;
         obj->coord->y = -1;
      }
   }
   else
   {
      REMOVE_OBJ_STAT(obj, ITEM_ONMAP);
      obj->map = -1;
      obj->coord->x = -1;
      obj->coord->y = -1;
   }   
   UNLINK(obj, ch->pcdata->first_bankobj, ch->pcdata->last_bankobj, next_content, prev_content);
   obj->carried_by = NULL;
   obj->in_room = NULL;
   obj->in_obj = NULL;
   return obj;
}

OBJ_DATA *townbank_to_char(OBJ_DATA * obj, TOWN_DATA *town, CHAR_DATA *ch)
{
   if (ch != NULL)
   {
      if (IN_WILDERNESS(ch))
      {
         SET_OBJ_STAT(obj, ITEM_ONMAP);
         obj->map = ch->map;
         obj->coord->x = ch->coord->x;
         obj->coord->y = ch->coord->y;
      }
      else
      {
         REMOVE_OBJ_STAT(obj, ITEM_ONMAP);
         obj->map = -1;
         obj->coord->x = -1;
         obj->coord->y = -1;
      }
   }
   else
   {
      REMOVE_OBJ_STAT(obj, ITEM_ONMAP);
      obj->map = -1;
      obj->coord->x = -1;
      obj->coord->y = -1;
   }   
   UNLINK(obj, town->first_bankobj, town->last_bankobj, next_content, prev_content);
   obj->carried_by = NULL;
   obj->in_room = NULL;
   obj->in_obj = NULL;
   return obj;
}
   

OBJ_DATA *obj_to_bank(OBJ_DATA * obj, CHAR_DATA *ch)
{
   OBJ_DATA *otmp;
   OBJ_DATA *oret = NULL;
   int grouped = FALSE;
   
   REMOVE_OBJ_STAT(obj, ITEM_ONMAP);
   obj->map = -1;
   obj->coord->x = -1;
   obj->coord->y = -1;
   
   for (otmp = ch->pcdata->first_bankobj; otmp; otmp = otmp->next_content)
   {
      if ((oret = group_object(otmp, obj)) == otmp)  
      {
         grouped = TRUE;
         break;
      }
   }
   if (!grouped)      
   {
      LINK(obj, ch->pcdata->first_bankobj, ch->pcdata->last_bankobj, next_content, prev_content);
      obj->carried_by = NULL;
      obj->in_room = NULL;
      obj->in_obj = NULL;
      return obj;
   }
   else
      return oret;
}

OBJ_DATA *obj_to_townbank(OBJ_DATA * obj, TOWN_DATA *town)
{
   OBJ_DATA *otmp;
   OBJ_DATA *oret = NULL;
   int grouped = FALSE;
   
   REMOVE_OBJ_STAT(obj, ITEM_ONMAP);
   obj->map = -1;
   obj->coord->x = -1;
   obj->coord->y = -1;
   
   for (otmp = town->first_bankobj; otmp; otmp = otmp->next_content)
   {
      if ((oret = group_object(otmp, obj)) == otmp)  
      {
         grouped = TRUE;
         break;
      }
   }
   if (!grouped)      
   {
      LINK(obj, town->first_bankobj, town->last_bankobj, next_content, prev_content);
      obj->carried_by = NULL;
      obj->in_room = NULL;
      obj->in_obj = NULL;
      return obj;
   }
   else
      return oret;
}      
/*
 * Give an obj to a char.
 */
OBJ_DATA *obj_to_char(OBJ_DATA * obj, CHAR_DATA * ch)
{
   OBJ_DATA *otmp;
   OBJ_DATA *oret = obj;
   bool skipgroup, grouped;
   int x;
   CHAR_DATA *gch;

   skipgroup = FALSE;
   grouped = FALSE;
   
   if (obj->trap && !IS_NPC(ch))
   {
      if (obj->trap->uid < START_INV_TRAP)
         copy_trap(obj->trap, obj);
   }

   if (IS_OBJ_STAT(obj, ITEM_PROTOTYPE))
   {
      if (!IS_IMMORTAL(ch) && (IS_NPC(ch) && !xIS_SET(ch->act, ACT_PROTOTYPE)))
         return obj_to_room(obj, ch->in_room, ch);
   }

   if (ch != NULL)
   {
      if (IN_WILDERNESS(ch))
      {
         SET_OBJ_STAT(obj, ITEM_ONMAP);
         obj->map = ch->map;
         obj->coord->x = ch->coord->x;
         obj->coord->y = ch->coord->y;
      }
      else
      {
         REMOVE_OBJ_STAT(obj, ITEM_ONMAP);
         obj->map = -1;
         obj->coord->x = -1;
         obj->coord->y = -1;
      }
   }
   else
   {
      REMOVE_OBJ_STAT(obj, ITEM_ONMAP);
      obj->map = -1;
      obj->coord->x = -1;
      obj->coord->y = -1;
   }

   if (loading_char == ch)
   {
      int x, y;

      for (x = 0; x < MAX_WEAR; x++)
         for (y = 0; y < MAX_LAYERS; y++)
            if (save_equipment[x][y] == obj)
            {
               skipgroup = TRUE;
               break;
            }
   }
   if (!skipgroup)
      for (otmp = ch->first_carrying; otmp; otmp = otmp->next_content)
         if ((oret = group_object(otmp, obj)) == otmp)
         {
            grouped = TRUE;
            break;
         }
   if (!grouped)
   {
      if (!IS_NPC(ch) || !ch->pIndexData->pShop)
      {
         LINK(obj, ch->first_carrying, ch->last_carrying, next_content, prev_content);
         obj->carried_by = ch;
         obj->in_room = NULL;
         obj->in_obj = NULL;
      }
      else
      {
         /* If ch is a shopkeeper, add the obj using an insert sort */
         for (otmp = ch->first_carrying; otmp; otmp = otmp->next_content)
         {
            if (obj->level > otmp->level)
            {
               INSERT(obj, otmp, ch->first_carrying, next_content, prev_content);
               break;
            }
            else if (obj->level == otmp->level && strcmp(obj->short_descr, otmp->short_descr) < 0)
            {
               INSERT(obj, otmp, ch->first_carrying, next_content, prev_content);
               break;
            }
         }

         if (!otmp)
         {
            LINK(obj, ch->first_carrying, ch->last_carrying, next_content, prev_content);
         }

         obj->carried_by = ch;
         obj->in_room = NULL;
         obj->in_obj = NULL;
      }
   }
   if (obj->item_type == ITEM_QTOKEN)
   {
      if (!xIS_SET(obj->extra_flags, ITEM_QTOKEN_LOOTED))
      {
         if (!ch->in_room || (IS_NPC(ch) && ch->pIndexData->vnum >= ch->in_room->area->low_r_vnum && ch->pIndexData->vnum <= ch->in_room->area->hi_r_vnum))
            ;
         else
            xSET_BIT(obj->extra_flags, ITEM_QTOKEN_LOOTED);
         if (!IS_NPC(ch) && ch->pcdata->quest && ch->pcdata->quest->questarea == ch->in_room->area 
         && ch->pcdata->quest->timeleft > 0 && ch->pcdata->quest->mission == 4)
         {
            ch->pcdata->quest->killed += obj->count;
            if (ch->pcdata->quest->traveltime > -1)
               ch->pcdata->quest->traveltime = -1;
            if (ch->pcdata->quest->killed >= ch->pcdata->quest->tokill) //Win
            {
               for (x = 0; x <= 5; x++)
               {
                  if (ch->pcdata->quest->player[x] == ch->pcdata->pid)
                  {
                     ch_printf(ch, "\n\r^r&CYou have completed your quest, your reward is %d QP^x\n\r\n\r", ch->pcdata->quest->qp[x]);
                     ch->pcdata->quest_curr += ch->pcdata->quest->qp[x];
                     ch->pcdata->quest_accum += ch->pcdata->quest->qp[x];
                     ch->pcdata->quest_wins++;
                  }
               }
               for (gch = first_char; gch; gch = gch->next)
               {
                  if (IS_NPC(gch))
                     continue;
                  if (gch == ch)
                     continue;
                  if (!gch->pcdata->quest)
                     continue;
                  if (gch->pcdata->quest->questarea != ch->in_room->area)
                     continue;
                  if (gch->pcdata->quest != ch->pcdata->quest)
                     continue;
                  for (x = 0; x <= 5; x++)
                  {
                     if (gch->pcdata->quest->player[x] == gch->pcdata->pid)
                     {
                        ch_printf(gch, "\n\r^r&CYou have completed your quest, your reward is %d QP^x\n\r\n\r", gch->pcdata->quest->qp[x]);
                        gch->pcdata->quest_curr += gch->pcdata->quest->qp[x];
                        gch->pcdata->quest_accum += gch->pcdata->quest->qp[x];
                        gch->pcdata->quest_wins++;
                        gch->pcdata->quest->timeleft = -1;
                        gch->pcdata->quest->tillnew = 25;
                     }
                  }
               }
               ch->pcdata->quest->timeleft = -1;
               ch->pcdata->quest->tillnew = 25;
            }
         }
      }
   }
   return (oret ? oret : obj);
}

void check_time_resets(OBJ_DATA *obj)
{
   AREA_DATA *pArea;
   RESET_DATA *pReset = NULL;
   
   if (xIS_SET(obj->extra_flags, ITEM_TIMERESET))
   {
      if (obj->carried_by && obj->carried_by->in_room)
         pArea = obj->carried_by->in_room->area;
      else if (obj->in_obj && obj->in_obj->carried_by && obj->in_obj->carried_by->in_room)
         pArea = obj->in_obj->carried_by->in_room->area;
      else if (obj->in_room)
         pArea = obj->in_room->area;
      else if (obj->in_obj && obj->in_obj->in_room)
         pArea = obj->in_obj->in_room->area;
      else
      {
         //if no one "was" carrying it, start looping
         for (pArea = first_area; pArea; pArea = pArea->next)
         {
             for (pReset = pArea->first_reset; pReset; pReset = pReset->next)
             {
                if (pReset->resettime > 0 && (pReset->command == 'O' || pReset->command == 'P' || pReset->command == 'E' || pReset->command == 'G') && pReset->arg1 == obj->pIndexData->vnum )
                {
                   break;
                }
             }
             if (pReset)
                break;
         }     
      }
      if (!pReset && pArea)
      {
         for (pReset = pArea->first_reset; pReset; pReset = pReset->next)
         {
             if (pReset->resettime > 0 && (pReset->command == 'O' || pReset->command == 'P' || pReset->command == 'E' || pReset->command == 'G') && pReset->arg1 == obj->pIndexData->vnum)
                break;
         } 
      } 
      if (!pArea || (pArea && !pReset))
      {
         if (!pArea)
            bug("Could not find the area to fit obj %d's reset.", obj->pIndexData->vnum);
         else
            bug("Could not find the proper Reset for obj %d", obj->pIndexData->vnum);
      }
      else
      {;
         pReset->resetlast = time(0);  
         xREMOVE_BIT(obj->extra_flags, ITEM_TIMERESET);
         bug("TIMERESET LOOTED:  %d has been looted.", obj->pIndexData->vnum); //just in case some brainful player says an item loaded that did not
         fold_area(pArea, pArea->filename, FALSE, 1); 
      }
   }   
      
   if (xIS_SET(obj->extra_flags, ITEM_NORESET))
   {
      if (obj->carried_by && obj->carried_by->in_room)
         pArea = obj->carried_by->in_room->area;
      else if (obj->in_obj && obj->in_obj->carried_by && obj->in_obj->carried_by->in_room)
         pArea = obj->in_obj->carried_by->in_room->area;
      else if (obj->in_room)
         pArea = obj->in_room->area;
      else if (obj->in_obj && obj->in_obj->in_room)
         pArea = obj->in_obj->in_room->area;
      else
      {
         //if no one "was" carrying it, start looping
         for (pArea = first_area; pArea; pArea = pArea->next)
         {
             for (pReset = pArea->first_reset; pReset; pReset = pReset->next)
             {
                if (pReset->resettime == -1 && (pReset->command == 'O' || pReset->command == 'P' || pReset->command == 'E' || pReset->command == 'G') && pReset->arg1 == obj->pIndexData->vnum )
                {
                   break;
                }
             }
             if (pReset)
                break;
         }     
      }
      if (!pReset && pArea)
      {
         for (pReset = pArea->first_reset; pReset; pReset = pReset->next)
         {
             if (pReset->resettime == -1 && (pReset->command == 'O' || pReset->command == 'P' || pReset->command == 'E' || pReset->command == 'G') && pReset->arg1 == obj->pIndexData->vnum)
                break;
         } 
      } 
      if (!pArea || (pArea && !pReset))
      {
         if (!pArea)
            bug("Could not find the area to fit obj %d's reset.", obj->pIndexData->vnum);
         else
            bug("Could not find the proper Reset for obj %d", obj->pIndexData->vnum);
      }
      else
      {
         delete_reset(pArea, pReset);
         xREMOVE_BIT(obj->extra_flags, ITEM_NORESET);
         bug("NORESET LOOTED:  %d has been looted.", obj->pIndexData->vnum); //just in case some brainful player says an item loaded that did not
         fold_area(pArea, pArea->filename, FALSE, 1); 
      }
   }
}      

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

   if ((ch = obj->carried_by) == NULL)
   {
      bug("Obj_from_char: null ch.", 0);
      return;
   }

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

   /* obj may drop during unequip... */
   if (!obj->carried_by)
      return;

   UNLINK(obj, ch->first_carrying, ch->last_carrying, next_content, prev_content);

   if (IS_OBJ_STAT(obj, ITEM_COVERING) && obj->first_content)
      empty_obj(obj, NULL, NULL);

   check_time_resets(obj);

   obj->in_room = NULL;
   obj->carried_by = NULL;
   obj->possessed_by = NULL;
   return;
}


/*
 * Find the ac value of an obj, including position effect.
 */
int apply_ac(OBJ_DATA * obj, int iWear)
{
   return 0;
}



/*
 * Find a piece of eq on a character.
 * Will pick the top layer if clothing is layered.		-Thoric
 */
OBJ_DATA *get_eq_char(CHAR_DATA * ch, int iWear)
{
   OBJ_DATA *obj, *maxobj = NULL;

   for (obj = ch->first_carrying; obj; obj = obj->next_content)
   {
      if (obj->wear_loc == iWear)
      {
         if (!obj->pIndexData->layers)
         {
            return obj;
         }
         else
         {
            if (!maxobj || obj->pIndexData->layers > maxobj->pIndexData->layers)
               maxobj = obj;
         }
      }
   }

   return maxobj;
}



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

   if ((otmp = get_eq_char(ch, iWear)) != NULL && (!otmp->pIndexData->layers || !obj->pIndexData->layers))
   {
      if (global_drop_equip_message == 0)
         bug("Equip_char: already equipped (%d).", iWear);
      return;
   }
   if (IS_OBJ_STAT(obj, ITEM_KINGDOMEQ) && !IS_OBJ_STAT(obj, ITEM_LODGED))
   {
      if (!IS_NPC(ch) || (IS_NPC(ch) && !xIS_SET(ch->act, ACT_MILITARY)))
      {
         send_to_char("Cannot equip this item, it is kingdom eq\n\r", ch);
         return;
      }
   }

   separate_obj(obj); /* just in case */ 
   obj->wear_loc = iWear;

   for (paf = obj->pIndexData->first_affect; paf; paf = paf->next)
      affect_modify(ch, paf, 3);
   for (paf = obj->first_affect; paf; paf = paf->next)
      affect_modify(ch, paf, 3);
   if (obj->item_type == ITEM_LIGHT && obj->value[2] != 0 && ch->in_room)
      ++ch->in_room->light;
   check_for_trap(ch, obj, -1, NEW_TRAP_WEAROBJ);
   return;
}



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

   if (obj->wear_loc == WEAR_NONE)
   {
      if (global_drop_equip_message == 0)
         bug("Unequip_char: already unequipped.", 0);
      return;
   }
   
   if (obj->item_type == ITEM_PROJECTILE)
      REMOVE_OBJ_STAT(obj, ITEM_LODGED);

   obj->wear_loc = -1;

   for (paf = obj->pIndexData->first_affect; paf; paf = paf->next)
      affect_modify(ch, paf, 2);
   if (obj->carried_by)
      for (paf = obj->first_affect; paf; paf = paf->next)
         affect_modify(ch, paf, 2);

   update_aris(ch);

   if (!obj->carried_by)
   {
      bug("here");
      return;
   }

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

   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 = 0;

   for (obj = list; obj; obj = obj->next_content)
   {
      if (obj->pIndexData->vnum == pObjIndex->vnum)
      {
         if (obj->count > 1)
            nMatch += obj->count;
         else
            nMatch++;
      }
   }
   return nMatch;
}

int count_mob_in_room(MOB_INDEX_DATA * pMobIndex, ROOM_INDEX_DATA * room)
{
   CHAR_DATA *mob;
   int nMatch = 0;

   for (mob = room->first_person; mob; mob = mob->next_in_room)
      if (IS_NPC(mob) && mob->pIndexData->vnum == pMobIndex->vnum)
         nMatch++;

   return nMatch;
}



/*
 * Move an obj out of a room.
 */
void write_corpses args((CHAR_DATA * ch, char *name, OBJ_DATA * objrem));

int falling;

void obj_from_room(OBJ_DATA * obj)
{
   ROOM_INDEX_DATA *in_room;
   AFFECT_DATA *paf;
   OMAP_DATA *omap;

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

   for (paf = obj->first_affect; paf; paf = paf->next)
      room_affect(in_room, paf, FALSE);

   for (paf = obj->pIndexData->first_affect; paf; paf = paf->next)
      room_affect(in_room, paf, FALSE);

   if (obj->pIndexData->vnum != OBJ_VNUM_MONEY_ONE && obj->pIndexData->vnum != OBJ_VNUM_MONEY_SOME)
   {
      for (omap = first_wilderobj; omap; omap = omap->next)
      {
         if (omap->mapobj == obj)
            UNLINK(omap, first_wilderobj, last_wilderobj, next, prev);
      }
   }

   UNLINK(obj, in_room->first_content, in_room->last_content, next_content, prev_content);



   /* uncover contents */
   if (IS_OBJ_STAT(obj, ITEM_COVERING) && obj->first_content)
      empty_obj(obj, NULL, obj->in_room);

   if (obj->item_type == ITEM_FIRE)
      obj->in_room->light -= obj->count;
      
   check_time_resets(obj);

   obj->carried_by = NULL;
   obj->possessed_by = NULL;
   obj->in_obj = NULL;
   obj->in_room = NULL;
   if (obj->pIndexData->vnum == OBJ_VNUM_CORPSE_PC && falling < 1)
      write_corpses(NULL, obj->short_descr + 14, obj);
   return;
}

/*
 * Move an obj into a room.
 */
OBJ_DATA *obj_to_room(OBJ_DATA * obj, ROOM_INDEX_DATA * pRoomIndex, CHAR_DATA * ch)
{
   OBJ_DATA *otmp, *oret;
   sh_int count = obj->count;
   sh_int item_type = obj->item_type;
   AFFECT_DATA *paf;
   OMAP_DATA *omap;

   if (IS_OBJ_STAT(obj, ITEM_GROUNDROT))
   {
      xREMOVE_BIT(obj->extra_flags, ITEM_GROUNDROT);
      obj->timer = 1;
   }

   for (paf = obj->first_affect; paf; paf = paf->next)
      room_affect(pRoomIndex, paf, TRUE);

   for (paf = obj->pIndexData->first_affect; paf; paf = paf->next)
      room_affect(pRoomIndex, paf, TRUE);

   for (otmp = pRoomIndex->first_content; otmp; otmp = otmp->next_content)
      if ((oret = group_object(otmp, obj)) == otmp)
      {
         if (item_type == ITEM_FIRE)
            pRoomIndex->light += count;
         return oret;
      }
   LINK(obj, pRoomIndex->first_content, pRoomIndex->last_content, next_content, prev_content);

   if (obj->pIndexData->vnum != OBJ_VNUM_MONEY_ONE && obj->pIndexData->vnum != OBJ_VNUM_MONEY_SOME &&
      pRoomIndex->vnum == OVERLAND_SOLAN)
   {
      CREATE(omap, OMAP_DATA, 1);
      omap->mapobj = obj;
      LINK(omap, first_wilderobj, last_wilderobj, next, prev);
   }

   obj->in_room = pRoomIndex;
   obj->carried_by = NULL;
   obj->in_obj = NULL;
   if (item_type == ITEM_FIRE)
      pRoomIndex->light += count;
   falling++;
   obj_fall(obj, FALSE);
   falling--;

/* Hoping that this will cover all instances of objects from character to room - Samson 8-22-99 */
   if (ch != NULL)
   {
      if (IN_WILDERNESS(ch))
      {
         SET_OBJ_STAT(obj, ITEM_ONMAP);
         obj->map = ch->map;
         obj->coord->x = ch->coord->x;
         obj->coord->y = ch->coord->y;
      }
      else
      {
         REMOVE_OBJ_STAT(obj, ITEM_ONMAP);
         obj->map = -1;
         obj->coord->x = -1;
         obj->coord->y = -1;
      }
   }
   if (obj->pIndexData->vnum == OBJ_VNUM_CORPSE_PC && falling < 1)
      write_corpses(NULL, obj->short_descr + 14, NULL);

   return obj;
}


/*
 * Who's carrying an item -- recursive for nested objects	-Thoric
 */
CHAR_DATA *carried_by(OBJ_DATA * obj)
{
   if (obj->in_obj)
      return carried_by(obj->in_obj);

   return obj->carried_by;
}


/*
 * Move an object into an object.
 */
OBJ_DATA *obj_to_obj(OBJ_DATA * obj, OBJ_DATA * obj_to)
{
   OBJ_DATA *otmp, *oret;

   if (obj == obj_to)
   {
      bug("Obj_to_obj: trying to put object inside itself: vnum %d", obj->pIndexData->vnum);
      return obj;
   }
      
   for (otmp = obj_to->first_content; otmp; otmp = otmp->next_content)
      if ((oret = group_object(otmp, obj)) == otmp)
         return oret;

   LINK(obj, obj_to->first_content, obj_to->last_content, next_content, prev_content);

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

/* This will hopefully cover all objs going into containers on maps - Samson 8-22-99 */
   if (IN_WILDERNESS_OBJ(obj_to))
   {
      SET_OBJ_STAT(obj, ITEM_ONMAP);
      obj->map = obj_to->map;
      obj->coord->x = obj_to->coord->x;
      obj->coord->y = obj_to->coord->y;
   }

   return obj;
}


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

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

   magic = in_magic_container(obj_from);

   UNLINK(obj, obj_from->first_content, obj_from->last_content, next_content, prev_content);

   /* uncover contents */
   if (IS_OBJ_STAT(obj, ITEM_COVERING) && obj->first_content)
      empty_obj(obj, obj->in_obj, NULL);
      
   check_time_resets(obj);

   obj->in_obj = NULL;
   obj->in_room = NULL;
   obj->carried_by = NULL;

/* This will hopefully cover all objs coming from containers going to the maps - Samson 8-22-99 */
   if (IN_WILDERNESS_OBJ(obj_from))
   {
      SET_OBJ_STAT(obj, ITEM_ONMAP);
      obj->map = obj_from->map;
      obj->coord->x = obj_from->coord->x;
      obj->coord->y = obj_from->coord->y;
   }
   return;
}




/*
 * Extract an obj from the world.
 */
void extract_obj(OBJ_DATA * obj)
{
   OBJ_DATA *obj_content;
   DESCRIPTOR_DATA *d;

   if (obj_extracted(obj))
   {
      bug("extract_obj: obj %d already extracted!", obj->pIndexData->vnum);
      return;
   }

   if (obj->item_type == ITEM_PORTAL)
      remove_portal(obj);

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

   while ((obj_content = obj->last_content) != NULL)
      extract_obj(obj_content);

   /* remove affects */
   {
      AFFECT_DATA *paf;
      AFFECT_DATA *paf_next;

      for (paf = obj->first_affect; paf; paf = paf_next)
      {
         paf_next = paf->next;
         DISPOSE(paf);
      }
      obj->first_affect = obj->last_affect = NULL;
   }
   
   // Remove traps
   if (obj->trap)
   {
      if (obj->trap->uid >= START_INV_TRAP)
      {
         UNLINK(obj->trap, first_trap, last_trap, next, prev);
         DISPOSE(obj->trap);   
         obj->trap = NULL;
         save_trap_file(NULL, NULL);
      }
      else
      {
         obj->trap->area = NULL;
         obj->trap->obj = NULL;
         obj->trap = NULL;
      }
   }

   /* remove extra descriptions */
   {
      EXTRA_DESCR_DATA *ed;
      EXTRA_DESCR_DATA *ed_next;

      for (ed = obj->first_extradesc; ed; ed = ed_next)
      {
         ed_next = ed->next;
         STRFREE(ed->description);
         STRFREE(ed->keyword);
         DISPOSE(ed);
      }
      obj->first_extradesc = obj->last_extradesc = NULL;
   }

   if (obj == gobj_prev)
      gobj_prev = obj->prev;

   for (d = first_descriptor; d; d = d->next)
   {
      OBJ_DATA *dobj;
      if (d->character && d->character->substate && d->character->dest_buf)
      {
         dobj = d->character->dest_buf;
         if ((d->character->substate == SUB_RESTRICTED || d->character->substate == SUB_REPEATCMD)
         &&  dobj == obj)
         {
            send_to_char("Your obj you are modifying is being deleted, please type done to get out of this mode.\n\r", d->character);
            d->character->substate = SUB_NONE;
            d->character->dest_buf = NULL;
            if (d->character->pcdata && d->character->pcdata->subprompt)
            {
               STRFREE(d->character->pcdata->subprompt);
               d->character->pcdata->subprompt = NULL;
               if (xIS_SET(d->character->act, PLR_OSET)) /* oset flags, Crash no like -- Xerves */
                  xREMOVE_BIT(d->character->act, PLR_OSET);
            }
         }
      }
   }

   UNLINK(obj, first_object, last_object, next, prev);

   /* shove onto extraction queue */
   queue_extracted_obj(obj);

   obj->pIndexData->count -= obj->count;
   numobjsloaded -= obj->count;
   --physicalobjects;
   if (obj->serial == cur_obj)
   {
      cur_obj_extracted = TRUE;
      if (global_objcode == rNONE)
         global_objcode = rOBJ_EXTRACTED;
   }
   return;
}

void check_aff_learn(CHAR_DATA *ch, char *skillname, int sn, CHAR_DATA *victim, int success)
{
   if (IS_NPC(ch))
      return;
   if (sn < 1)
      sn = skill_lookup(skillname);
   if (sn < 1)
      return;
   if (LEARNED(ch, sn) <= 0)
      return;
   if (success)
      learn_from_success(ch, sn, victim);
   else
      learn_from_failure(ch, sn, victim);
   return;
}

bool check_npc(CHAR_DATA *ch)
{
   if (IS_NPC(ch))
   {
      send_to_char("This is not for a NPC to use.\n\r", ch);
      return TRUE;
   }
   return FALSE;
}


/*
 * Extract a char from the world.
 */
void extract_char(CHAR_DATA * ch, bool fPull)
{
   CHAR_DATA *wch;
   OBJ_DATA *obj;
   char buf[MSL];
   ROOM_INDEX_DATA *location;
   AREA_DATA *pArea;
   TOWN_DATA *town;
   AGGRO_DATA *aggro;
   AGGRO_DATA *naggro;

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

   if (!ch->in_room)
   {
      bug("Extract_char: %s in NULL room.", ch->name ? ch->name : "???");
      return;
   }

   if (ch == supermob)
   {
      bug("Extract_char: ch == supermob!", 0);
      return;
   }

   if (char_died(ch))
   {
      bug("extract_char: %s already died!", ch->name);
      return;
   }

   if (ch == cur_char)
      cur_char_died = TRUE;

   /* shove onto extraction queue */
   queue_extracted_char(ch, fPull);

   if (gch_prev == ch)
      gch_prev = ch->prev;

/* DELETE LATER SHADDAI
    if ( fPull && !xIS_SET(ch->act, ACT_POLYMORPHED))
*/
   if (fPull)
      die_follower(ch);

   stop_fighting(ch, TRUE);
   
   pArea = ch->in_room->area;

   if (xIS_SET(ch->in_room->room_flags, ROOM_ARENA))
   {
      ch->hit = ch->max_hit;
      ch->mana = ch->max_mana;
      ch->move = ch->max_move;
   }

   if (ch->rider)
   {
      act(AT_SOCIAL, "Since you are leaving it is a good time for $N to get off of you", ch, NULL, ch->rider, TO_CHAR);
      act(AT_SOCIAL, "$n is leaving, time for your free ride to stop.", ch, NULL, ch->rider, TO_VICT);
      act(AT_PLAIN, "$n is leaving, sadly $N must hop off of $s back.", ch, NULL, ch->rider, TO_ROOM);
      ch->rider->position = POS_STANDING;
      ch->rider->riding = NULL;
      ch->rider = NULL;
   }
   if (ch->riding)
   {
      act(AT_SOCIAL, "You hop off the back of $N before taking your leave.", ch, NULL, ch->riding, TO_CHAR);
      act(AT_SOCIAL, "$n hops off the back of $N before leaving.", ch, NULL, ch->riding, TO_VICT);
      act(AT_PLAIN, "$n hops off the back of $N before departing.", ch, NULL, ch->riding, TO_ROOM);
      ch->rider->riding = NULL;
      ch->rider = NULL;    
      ch->position = POS_STANDING;
   }
   if (ch->mount)
   {
      xREMOVE_BIT(ch->mount->act, ACT_MOUNTED);
      ch->mount = NULL;
      ch->position = POS_STANDING;
   }

   if (IS_NPC(ch))
   {
      if (xIS_SET(ch->act, ACT_MILITARY))
      {
         bug("%s of kingdom %s is being extracted.", ch->name, kingdom_table[ch->m4]->name);
         town = get_town_tpid(ch->m4, ch->m1);
         if (town)
         {
            write_kingdom_file(ch->m4);
         }
      }
      if (xIS_SET(ch->act, ACT_EXTRACTMOB))
      {
         bug("%s of kingdom %s is being extracted.", ch->name, kingdom_table[ch->m4]->name);
         town = get_town_tpid(ch->m4, ch->m7);
         if (town)
         {
            write_kingdom_file(ch->m4);
         }
      }
   }

   /*
    * check if this NPC was a mount or a pet
    */
   if (IS_NPC(ch))
   {
      for (wch = first_char; wch; wch = wch->next)
      {
         if (wch->mount == ch)
         {
            wch->mount = NULL;
            wch->position = POS_STANDING;
            if (wch->in_room == ch->in_room && saving_mount_on_quit == 0)
            {
               act(AT_SOCIAL, "Your faithful mount, $N collapses beneath you...", wch, NULL, ch, TO_CHAR);
               act(AT_SOCIAL, "Sadly you dismount $M for the last time.", wch, NULL, ch, TO_CHAR);
               act(AT_PLAIN, "$n sadly dismounts $N for the last time.", wch, NULL, ch, TO_ROOM);
            }
         }
         if (wch->pcdata && wch->pcdata->pet == ch)
         {
            wch->pcdata->pet = NULL;
            if (wch->in_room == ch->in_room)
               act(AT_SOCIAL, "You mourn for the loss of $N.", wch, NULL, ch, TO_CHAR);
         }
         if (wch->pcdata && wch->pcdata->mount == ch)
         {
            wch->pcdata->mount = NULL;
            if (wch->in_room == ch->in_room && saving_mount_on_quit == 0)
               act(AT_SOCIAL, "You mourn for the loss of $N, but it had to be....", wch, NULL, ch, TO_CHAR);
         }
         if (wch->pcdata && wch->pcdata->aimtarget == ch)
            wch->pcdata->aimtarget = NULL;
      }
   }
   xREMOVE_BIT(ch->act, ACT_MOUNTED);

   while ((obj = ch->last_carrying) != NULL)
      extract_obj(obj);

   if (fPull)
      char_from_room(ch);

   if (!fPull)
   {
      location = NULL;

      if (!IS_NPC(ch) && ch->pcdata->clan)
         location = get_room_index(ch->pcdata->clan->recall);

      if (!IS_NPC(ch) && ch->pcdata->caste < 2)
         location = get_room_index(5644);

      if (!location && !IS_NPC(ch) && ch->pcdata->town)
         location = get_room_index(OVERLAND_SOLAN);

      if (!location)
         location = get_room_index(ROOM_VNUM_ALTAR);

      if (!location)
         location = get_room_index(1);

      if (IS_ONMAP_FLAG(ch))
      {
         REMOVE_ONMAP_FLAG(ch);
         REMOVE_PLR_FLAG(ch, PLR_MAPEDIT); /* Just in case they were editing */

         ch->coord->x = -1;
         ch->coord->y = -1;
         ch->map = -1;
      }

      if (ch->pcdata->mount)
      {

         char_from_room(ch->pcdata->mount);
         SET_ONMAP_FLAG(ch->pcdata->mount);

         ch->pcdata->mount->coord->x = -1;
         ch->pcdata->mount->coord->y = -1;
         ch->pcdata->mount->map = -1;
         char_to_room(ch->pcdata->mount, location);
         ch->pcdata->mount->position = POS_STANDING;
      }
      char_from_room(ch);
      char_to_room(ch, location);
      
      if (location->vnum == OVERLAND_SOLAN)
      {
         ch->coord->x = ch->pcdata->town->death[0];
         ch->coord->y = ch->pcdata->town->death[1];
         ch->map = ch->pcdata->town->death[2];
         SET_ONMAP_FLAG(ch);
         if (ch->pcdata->mount)
         {
            SET_ONMAP_FLAG(ch->pcdata->mount);
            ch->pcdata->mount->coord->x = ch->coord->x;
            ch->pcdata->mount->coord->y = ch->coord->y;
            ch->pcdata->mount->map = ch->map;
         }
      }
      update_objects(ch, ch->map, ch->coord->x, ch->coord->y);
      /*
       * Make things a little fancier    -Thoric
       */
      if ((wch = get_char_room_new(ch, "healer", 1)) != NULL)
      {
         act(AT_MAGIC, "$n mutters a few incantations, waves $s hands and points $s finger.", wch, NULL, NULL, TO_ROOM);
         act(AT_MAGIC, "$n appears from some strange swirling mists!", ch, NULL, NULL, TO_ROOM);
         sprintf(buf, "Welcome back to the land of the living, %s", capitalize(ch->name));
         do_tell(wch, buf);
      }
      else
         act(AT_MAGIC, "$n appears from some strange swirling mists!", ch, NULL, NULL, TO_ROOM);
      ch->position = POS_RESTING;
      return;
   }
   if (!IS_NPC(ch))
   {
      while ((obj = ch->pcdata->last_bankobj) != NULL)
      {
         bank_to_char(obj, ch);
         extract_obj(obj);   
      }
   }

   if (IS_NPC(ch))
   {
      RESET_DATA *pReset;
      DESCRIPTOR_DATA *d;
      
      for (d = first_descriptor; d; d = d->next)
      {
         CHAR_DATA *dch;
         if (d->character && d->character->substate && d->character->dest_buf)
         {
            dch = d->character->dest_buf;
            if ((d->character->substate == SUB_RESTRICTED || d->character->substate == SUB_REPEATCMD)
            &&  dch == ch)
            {
               send_to_char("The mobile you are modifying is being deleted, please type done to get out of this mode.\n\r", d->character);
               d->character->substate = SUB_NONE;
               d->character->dest_buf = NULL;
               if (d->character->pcdata && d->character->pcdata->subprompt)
               {
                  STRFREE(d->character->pcdata->subprompt);
                  d->character->pcdata->subprompt = NULL;
                  if (xIS_SET(d->character->act, PLR_MSET)) /* oset flags, Crash no like -- Xerves */
                     xREMOVE_BIT(d->character->act, PLR_MSET);
               }
            }
         }
      }
   
      --ch->pIndexData->count;
      --nummobsloaded;
      if (xIS_SET(ch->act, ACT_NORESET)) //remove the reset....
      {          
         for (pReset = pArea->first_reset; pReset; pReset = pReset->next)
         {
            if (pReset->command == 'M' && pReset->serial == ch->serial)
               break;
         }
         if (!pReset)
         {
            bug("Mobile %d in Area %s cannot find the proper reset to remove itself (No reset mob)", ch->pIndexData->vnum, pArea->name);
         }
         else
         {
            delete_reset(pArea, pReset);
            fold_area(pArea, pArea->filename, FALSE, 1); 
         }
      }
      if (xIS_SET(ch->act, ACT_TIMERESET)) //adjust the looted bit
      {
         for (pReset = pArea->first_reset; pReset; pReset = pReset->next)
         {
            if (pReset->command == 'M' && pReset->serial == ch->serial)
               break;
         }
         if (!pReset)
         {
            bug("Mobile %d in Area %s cannot find the proper reset to remove itself (No reset mob)", ch->pIndexData->vnum, pArea->name);
         }
         else
         {
            pReset->resetlast = time(0);  
            fold_area(pArea, pArea->filename, FALSE, 1); 
         }
      }
      serial_list[ch->serial] = FALSE;
   }

   /* Not sure this should stay or not Shaddai */
/*
    if ( ch->morph )
        do_unmorph( ch );
*/

   if (ch->desc && ch->desc->original)
      do_return(ch, "");
      
   for (aggro = first_global_aggro; aggro; aggro = naggro)
   {
      naggro = aggro->next_global;
      if (aggro->ch == ch)
      {
         UNLINK(aggro, first_global_aggro, last_global_aggro, next_global, prev_global);
         UNLINK(aggro, aggro->owner->first_aggro, aggro->owner->last_aggro, next, prev);
         DISPOSE(aggro);
      }
   }

   for (wch = first_char; wch; wch = wch->next)
   {
      if (wch->reply == ch)
         wch->reply = NULL;
      if (wch->retell == ch)
         wch->retell = NULL;
   }
   /*
      if (IS_NPC(ch))
      {
      for (mch = first_wilderchar; mch; mch = mch->next)
      {
      if (mch->mapch->coord->x == ch->coord->x && mch->mapch->coord->y == ch->coord->y && mch->mapch->map == ch->map)
      {
      UNLINK( mch, first_wilderchar, last_wilderchar, next, prev );
      top_map_mob--;
      }
      }
      }   */

   UNLINK(ch, first_char, last_char, next, prev);



   if (ch->desc)
   {
      if (ch->desc->character != ch)
         bug("Extract_char: char's descriptor points to another char", 0);
      else
      {
         ch->desc->character = NULL;
         close_socket(ch->desc, FALSE);
         ch->desc = NULL;
      }
   }

   return;
}

/*
 * Find a char in the room.
 */
//use get_char_room unless you need to call get_char_room_new for the type (wilderness check)
CHAR_DATA *get_char_room_new(CHAR_DATA * ch, char *argument, int type)
{
   char arg[MIL];
   CHAR_DATA *rch;
   int number, count, vnum;

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

   if (get_trust(ch) >= LEVEL_IMM && is_number(arg)) /* Tracker1 */
      vnum = atoi(arg);
   else
      vnum = -1;

   count = 0;

   for (rch = ch->in_room->first_person; rch; rch = rch->next_in_room)
      if (can_see_map(ch, rch) && (nifty_is_name(arg, PERS_MAP_NAME(rch, ch)) || (IS_NPC(rch) && vnum == rch->pIndexData->vnum)))
      {
         if (type == 1)
         {
            if (IS_ONMAP_FLAG(ch) && IS_ONMAP_FLAG(rch))
            {
               if (ch->map != rch->map || ch->coord->x != rch->coord->x || ch->coord->y != rch->coord->y)
                  continue;
            }
         }
         if (number == 0 && !IS_NPC(rch))
            return rch;
         else if (++count == number)
            return rch;
      }

   if (vnum != -1)
      return NULL;

   /*
    * If we didn't find an exact match, run through the list of characters
    * again looking for prefix matching, ie gu == guard.
    * Added by Narn, Sept/96
    */
   count = 0;
   for (rch = ch->in_room->first_person; rch; rch = rch->next_in_room)
   {
      if (!can_see_map(ch, rch) || !nifty_is_name_prefix(arg, PERS_MAP_NAME(rch, ch)))
         continue;
      if (type == 1)
      {
         if (IS_ONMAP_FLAG(ch) && IS_ONMAP_FLAG(rch))
         {
            if (ch->map != rch->map || ch->coord->x != rch->coord->x || ch->coord->y != rch->coord->y)
               continue;
         }
      }
      if (number == 0 && !IS_NPC(rch))
         return rch;
      else if (++count == number)
         return rch;
   }

   return NULL;
}

//Checks Wilderness by default now
CHAR_DATA *get_char_room(CHAR_DATA * ch, char *argument)
{
   return get_char_room_new(ch, argument, 1);
}

CHAR_DATA *get_char_wilder(CHAR_DATA * ch, char *argument)
{
   return get_char_room_new(ch, argument, -1);
}




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

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

   /*
    * Allow reference by vnum for saints+   -Thoric
    */
   if (get_trust(ch) >= LEVEL_IMM && is_number(arg)) /* Tracker1 */
      vnum = atoi(arg);
   else
      vnum = -1;

   /* check the room for an exact match */
   for (wch = ch->in_room->first_person; wch; wch = wch->next_in_room)
      if (can_see_map(ch, wch) && (nifty_is_name(arg, PERS_MAP_NAME(wch, ch)) || (IS_NPC(wch) && vnum == wch->pIndexData->vnum)))
      {
         if (number == 0 && !IS_NPC(wch))
            return wch;
         else if (++count == number)
            return wch;
      }

   count = 0;



   /* check the world for an exact match */
   for (wch = first_char; wch; wch = wch->next)
      if (can_see_map(ch, wch) && (nifty_is_name(arg, PERS_MAP_NAME(wch, ch)) || (IS_NPC(wch) && vnum == wch->pIndexData->vnum)))
      {
         if (number == 0 && !IS_NPC(wch))
            return wch;
         else if (++count == number)
            return wch;
      }

   /* bail out if looking for a vnum match */
   if (vnum != -1)
      return NULL;

   /*
    * If we didn't find an exact match, check the room for
    * for a prefix match, ie gu == guard.
    * Added by Narn, Sept/96
    */
   count = 0;
   for (wch = ch->in_room->first_person; wch; wch = wch->next_in_room)
   {
      if (!can_see_map(ch, wch) || !nifty_is_name_prefix(arg, PERS_MAP_NAME(wch, ch)))
         continue;
      if (number == 0 && !IS_NPC(wch))
         return wch;
      else if (++count == number)
         return wch;
   }

   /*
    * If we didn't find a prefix match in the room, run through the full list
    * of characters looking for prefix matching, ie gu == guard.
    * Added by Narn, Sept/96
    */
   count = 0;
   for (wch = first_char; wch; wch = wch->next)
   {
      if (!can_see_map(ch, wch) || !nifty_is_name_prefix(arg, PERS_MAP_NAME(wch, ch)))
         continue;
      if (number == 0 && !IS_NPC(wch))
         return wch;
      else if (++count == number)
         return wch;
   }

   return NULL;
}



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

   for (obj = last_object; obj; obj = obj->prev)
      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[MIL];
   OBJ_DATA *obj;
   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) && nifty_is_name(arg, obj->name))
         if ((count += obj->count) >= number)
            return obj;

   /*
    * If we didn't find an exact match, run through the list of objects
    * again looking for prefix matching, ie swo == sword.
    * Added by Narn, Sept/96
    */
   count = 0;
   for (obj = list; obj; obj = obj->next_content)
      if (can_see_obj(ch, obj) && nifty_is_name_prefix(arg, obj->name))
         if ((count += obj->count) >= number)
            return obj;

   return NULL;
}

/*
 * Find an obj in a list...going the other way			-Thoric
 */
OBJ_DATA *get_obj_list_rev(CHAR_DATA * ch, char *argument, OBJ_DATA * list)
{
   char arg[MIL];
   OBJ_DATA *obj;
   int number;
   int count;

   number = number_argument(argument, arg);
   count = 0;
   for (obj = list; obj; obj = obj->prev_content)
      if (can_see_obj(ch, obj) && nifty_is_name(arg, obj->name))
         if ((count += obj->count) >= number)
            return obj;

   /*
    * If we didn't find an exact match, run through the list of objects
    * again looking for prefix matching, ie swo == sword.
    * Added by Narn, Sept/96
    */
   count = 0;
   for (obj = list; obj; obj = obj->prev_content)
      if (can_see_obj(ch, obj) && nifty_is_name_prefix(arg, obj->name))
         if ((count += obj->count) >= number)
            return obj;

   return NULL;
}

/*
 * Find an obj in player's inventory or wearing via a vnum -Shaddai
 */

OBJ_DATA *get_obj_vnum(CHAR_DATA * ch, int vnum)
{
   OBJ_DATA *obj;

   for (obj = ch->last_carrying; obj; obj = obj->prev_content)
      if (can_see_obj(ch, obj) && obj->pIndexData->vnum == vnum)
         return obj;
   return NULL;
}

/*
 * Find an obj in player's inventory.
 */
OBJ_DATA *get_obj_carry(CHAR_DATA * ch, char *argument)
{
   char arg[MIL];
   OBJ_DATA *obj;
   int number, count, vnum;

   number = number_argument(argument, arg);
   if (get_trust(ch) >= LEVEL_IMM && is_number(arg)) /* Tracker1 */
      vnum = atoi(arg);
   else
      vnum = -1;

   count = 0;
   for (obj = ch->last_carrying; obj; obj = obj->prev_content)
      if (obj->wear_loc == WEAR_NONE && can_see_obj(ch, obj) && (nifty_is_name(arg, obj->name) || obj->pIndexData->vnum == vnum))
         if ((count += obj->count) >= number)
            return obj;

   if (vnum != -1)
      return NULL;

   /*
    * If we didn't find an exact match, run through the list of objects
    * again looking for prefix matching, ie swo == sword.
    * Added by Narn, Sept/96
    */
   count = 0;
   for (obj = ch->last_carrying; obj; obj = obj->prev_content)
      if (obj->wear_loc == WEAR_NONE && can_see_obj(ch, obj) && nifty_is_name_prefix(arg, obj->name))
         if ((count += obj->count) >= number)
            return obj;

   return NULL;
}



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

   number = number_argument(argument, arg);

   if (get_trust(ch) >= LEVEL_IMM && is_number(arg)) /* Tracker1 */
      vnum = atoi(arg);
   else
      vnum = -1;

   count = 0;
   for (obj = ch->last_carrying; obj; obj = obj->prev_content)
      if (obj->wear_loc != WEAR_NONE && can_see_obj(ch, obj) && (nifty_is_name(arg, obj->name) || obj->pIndexData->vnum == vnum))
         if (++count == number)
            return obj;

   if (vnum != -1)
      return NULL;

   /*
    * If we didn't find an exact match, run through the list of objects
    * again looking for prefix matching, ie swo == sword.
    * Added by Narn, Sept/96
    */
   count = 0;
   for (obj = ch->last_carrying; obj; obj = obj->prev_content)
      if (obj->wear_loc != WEAR_NONE && can_see_obj(ch, obj) && nifty_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_rev(ch, argument, ch->in_room->last_content);
   if (obj)
      return obj;

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

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

   return NULL;
}



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

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

   number = number_argument(argument, arg);

   /*
    * Allow reference by vnum for saints+   -Thoric
    */
   if (get_trust(ch) >= LEVEL_IMM && is_number(arg)) /* Tracker1 */
      vnum = atoi(arg);
   else
      vnum = -1;

   count = 0;
   for (obj = first_object; obj; obj = obj->next)
      if (can_see_obj_map(ch, obj) && (nifty_is_name(arg, obj->name) || vnum == obj->pIndexData->vnum))
         if ((count += obj->count) >= number)
            return obj;

   /* bail out if looking for a vnum */
   if (vnum != -1)
      return NULL;

   /*
    * If we didn't find an exact match, run through the list of objects
    * again looking for prefix matching, ie swo == sword.
    * Added by Narn, Sept/96
    */
   count = 0;
   for (obj = first_object; obj; obj = obj->next)
      if (can_see_obj_map(ch, obj) && nifty_is_name_prefix(arg, obj->name))
         if ((count += obj->count) >= number)
            return obj;

   return NULL;
}

/*
 * Find an obj only if it is on a mob...
 */
OBJ_DATA *get_obj_mobworld(CHAR_DATA * ch, char *argument)
{
   char arg[MIL];
   OBJ_DATA *obj;
   OBJ_DATA *mobj; /* Check to see if item is same as in inv */
   int number, count, vnum;

   if ((obj = get_obj_here(ch, argument)) != NULL)
      mobj = obj;
   else
      mobj = NULL;

   number = number_argument(argument, arg);

   /*
    * Allow reference by vnum for saints+   -Thoric
    */
   if (get_trust(ch) >= LEVEL_IMM && is_number(arg)) /* Tracker1 */
      vnum = atoi(arg);
   else
      vnum = -1;

   count = 0;
   for (obj = first_object; obj; obj = obj->next)
   {
      if (can_see_obj_map(ch, obj) && (nifty_is_name(arg, obj->name) || vnum == obj->pIndexData->vnum))
         if ((count += obj->count) >= number)
            if ((obj->carried_by != NULL) && (mobj != NULL))
            {
               if ((IS_NPC(obj->carried_by)) && (obj->name == mobj->name) && (obj->pIndexData->vnum > 99))
                  return obj;
            }
   }
   /* bail out if looking for a vnum */
   if (vnum != -1)
      return NULL;

   /*
    * If we didn't find an exact match, run through the list of objects
    * again looking for prefix matching, ie swo == sword.
    * Added by Narn, Sept/96
    */
   count = 0;
   for (obj = first_object; obj; obj = obj->next)
   {
      if (can_see_obj_map(ch, obj) && nifty_is_name_prefix(arg, obj->name))
         if ((count += obj->count) >= number)
            if ((obj->carried_by != NULL) && (mobj != NULL))
            {
               if ((IS_NPC(obj->carried_by)) && (obj->name == mobj->name) && (obj->pIndexData->vnum > 99))
                  return obj;
            }
   }
   return NULL;
}

/*
 * How mental state could affect finding an object		-Thoric
 * Used by get/drop/put/quaff/recite/etc
 * Increasingly freaky based on mental state and drunkeness
 */
bool ms_find_obj(CHAR_DATA * ch)
{
   int ms = ch->mental_state;
   int drunk = IS_NPC(ch) ? 0 : ch->pcdata->condition[COND_DRUNK];
   char *t;

   /*
    * we're going to be nice and let nothing weird happen unless
    * you're a tad messed up
    */
   drunk = UMAX(1, drunk);
   if (abs(ms) + (drunk / 3) < 30)
      return FALSE;
   if ((number_percent() + (ms < 0 ? 15 : 5)) > abs(ms) / 2 + drunk / 4)
      return FALSE;
   if (ms > 15) /* range 1 to 20 -- feel free to add more */
      switch (number_range(UMAX(1, (ms / 5 - 15)), (ms + 4) / 5))
      {
         default:
         case 1:
            t = "As you reach for it, you forgot what it was...\n\r";
            break;
         case 2:
            t = "As you reach for it, something inside stops you...\n\r";
            break;
         case 3:
            t = "As you reach for it, it seems to move out of the way...\n\r";
            break;
         case 4:
            t = "You grab frantically for it, but can't seem to get a hold of it...\n\r";
            break;
         case 5:
            t = "It disappears as soon as you touch it!\n\r";
            break;
         case 6:
            t = "You would if it would stay still!\n\r";
            break;
         case 7:
            t = "Whoa!  It's covered in blood!  Ack!  Ick!\n\r";
            break;
         case 8:
            t = "Wow... trails!\n\r";
            break;
         case 9:
            t = "You reach for it, then notice the back of your hand is growing something!\n\r";
            break;
         case 10:
            t = "As you grasp it, it shatters into tiny shards which bite into your flesh!\n\r";
            break;
         case 11:
            t = "What about that huge dragon flying over your head?!?!?\n\r";
            break;
         case 12:
            t = "You stratch yourself instead...\n\r";
            break;
         case 13:
            t = "You hold the universe in the palm of your hand!\n\r";
            break;
         case 14:
            t = "You're too scared.\n\r";
            break;
         case 15:
            t = "Your mother smacks your hand... 'NO!'\n\r";
            break;
         case 16:
            t = "Your hand grasps the worst pile of revoltingness that you could ever imagine!\n\r";
            break;
         case 17:
            t = "You stop reaching for it as it screams out at you in pain!\n\r";
            break;
         case 18:
            t = "What about the millions of burrow-maggots feasting on your arm?!?!\n\r";
            break;
         case 19:
            t = "That doesn't matter anymore... you've found the true answer to everything!\n\r";
            break;
         case 20:
            t = "A supreme entity has no need for that.\n\r";
            break;
      }
   else
   {
      int sub = URANGE(1, abs(ms) / 2 + drunk, 60);

      switch (number_range(1, sub / 10))
      {
         default:
         case 1:
            t = "In just a second...\n\r";
            break;
         case 2:
            t = "You can't find that...\n\r";
            break;
         case 3:
            t = "It's just beyond your grasp...\n\r";
            break;
         case 4:
            t = "...but it's under a pile of other stuff...\n\r";
            break;
         case 5:
            t = "You go to reach for it, but pick your nose instead.\n\r";
            break;
         case 6:
            t = "Which one?!?  I see two... no three...\n\r";
            break;
      }
   }
   send_to_char(t, ch);
   return TRUE;
}


/*
 * Generic get obj function that supports optional containers.	-Thoric
 * currently only used for "eat" and "quaff".
 */
OBJ_DATA *find_obj(CHAR_DATA * ch, char *argument, bool carryonly)
{
   char arg1[MIL];
   char arg2[MIL];
   OBJ_DATA *obj = NULL;

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

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

   if (arg2[0] == '\0')
   {
      if (carryonly && (obj = get_obj_carry(ch, arg1)) == NULL)
      {
         send_to_char("You do not have that item.\n\r", ch);
         return NULL;
      }
      else if (!carryonly && (obj = get_obj_here(ch, arg1)) == NULL)
      {
         act(AT_PLAIN, "I see no $T here.", ch, NULL, arg1, TO_CHAR);
         return NULL;
      }
      return obj;
   }
   else
   {
      OBJ_DATA *container = NULL;

      if (carryonly && (container = get_obj_carry(ch, arg2)) == NULL && (container = get_obj_wear(ch, arg2)) == NULL)
      {
         send_to_char("You do not have that item.\n\r", ch);
         return NULL;
      }
      if (!carryonly && (container = get_obj_here(ch, arg2)) == NULL)
      {
         act(AT_PLAIN, "I see no $T here.", ch, NULL, arg2, TO_CHAR);
         return NULL;
      }

      if (!IS_OBJ_STAT(container, ITEM_COVERING) && IS_SET(container->value[1], CONT_CLOSED))
      {
         act(AT_PLAIN, "The $d is closed.", ch, NULL, container->name, TO_CHAR);
         return NULL;
      }

      obj = get_obj_list(ch, arg1, container->first_content);
      if (!obj)
         act(AT_PLAIN, IS_OBJ_STAT(container, ITEM_COVERING) ?
            "I see nothing like that beneath $p." : "I see nothing like that in $p.", ch, container, NULL, TO_CHAR);
      return obj;
   }
   return NULL;
}

int get_obj_number(OBJ_DATA * obj)
{
   return obj->count;
}

/*
 * Return TRUE if an object is, or nested inside a magic container
 */
bool in_magic_container(OBJ_DATA * obj)
{
   if (obj->item_type == ITEM_CONTAINER && IS_OBJ_STAT(obj, ITEM_MAGIC))
      return TRUE;
   if (obj->in_obj)
      return in_magic_container(obj->in_obj);
   return FALSE;
}

int objonchar;

void search_container_for_obj(OBJ_DATA * obj, OBJ_DATA * pobj)
{
   OBJ_DATA *cobj;
   
   for (cobj = obj->first_content; cobj; cobj = cobj->next_content)
   {
      if (objonchar == 1)
         break;
      if ((cobj->pIndexData->vnum == pobj->pIndexData->vnum && pobj->pIndexData->vnum != OBJ_VNUM_QUESTOBJ)
      ||  (cobj->pIndexData->vnum == pobj->pIndexData->vnum && pobj->pIndexData->vnum == OBJ_VNUM_QUESTOBJ
      &&   !str_cmp(cobj->name, pobj->name)))
      {
         objonchar = 1;
         break;
      }
      if (cobj->first_content)
         search_container_for_obj(cobj, pobj);
   }
}
         
int get_obj_on_char(CHAR_DATA *ch, OBJ_DATA * pobj)
{
   OBJ_DATA *obj;
   objonchar = 0;
   
   if (IS_NPC(ch))
      return 0;
   
   if (xIS_SET(pobj->extra_flags, ITEM_UNIQUE))
   {
      for (obj = ch->first_carrying; obj; obj = obj->next_content) 
      {
         if (objonchar == 1)
            break;
         if ((obj->pIndexData->vnum == pobj->pIndexData->vnum && pobj->pIndexData->vnum != OBJ_VNUM_QUESTOBJ)
         ||  (obj->pIndexData->vnum == pobj->pIndexData->vnum && pobj->pIndexData->vnum == OBJ_VNUM_QUESTOBJ
         &&   !str_cmp(obj->name, pobj->name)))
         {
            objonchar = 1;
            break;
         }
         if (obj->first_content)
            search_container_for_obj(obj, pobj);
      }   
      for (obj = ch->pcdata->first_bankobj; obj; obj = obj->next_content) 
      {
         if (objonchar == 1)
            break;
         if ((obj->pIndexData->vnum == pobj->pIndexData->vnum && pobj->pIndexData->vnum != OBJ_VNUM_QUESTOBJ)
         ||  (obj->pIndexData->vnum == pobj->pIndexData->vnum && pobj->pIndexData->vnum == OBJ_VNUM_QUESTOBJ
         &&   !str_cmp(obj->name, pobj->name)))
         {
            objonchar = 1;
            break;
         }
         if (obj->first_content)
            search_container_for_obj(obj, pobj);
      }   
   }
   if (pobj->first_content)
   {
      for (obj = pobj->first_content; obj; obj = obj->next_content)
      {
         if (objonchar == 1)
            break;
         if (IS_UNIQUE(ch, obj))
            objonchar = 1;
      }
   }
   return objonchar;
}

/*
 * Return weight of an object, including weight of contents (unless magic).
 */
float get_obj_weight(OBJ_DATA * obj)
{
   float weight;
   float reduction = 100;
   CHAR_DATA *ch = obj->carried_by;

   weight = (float)obj->count * obj->weight;
   
   if (obj->item_type == ITEM_CONTAINER)
   {
      if (ch && ch->apply_wmod > 0)
         reduction = reduction * URANGE(30, (float)ch->apply_wmod, 200) / 100;
         
      weight = weight * reduction / 100;
      
      if (obj->value[2] > 0)
         reduction = (float)obj->value[2];
   }
   else
   {
      if (ch && ch->apply_wmod > 0)
         reduction = reduction * URANGE(30, (float)ch->apply_wmod, 200) / 100;   
      weight = weight * reduction / 100;
   }
   
   /* magic containers */
   for (obj = obj->first_content; obj; obj = obj->next_content)
      weight += get_obj_weight(obj) * reduction / 100;

   return weight;
}

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

   weight = obj->count * obj->weight;

   for (obj = obj->first_content; obj; obj = obj->next_content)
      weight += get_real_obj_weight(obj);

   return weight;
}



/*
 * True if room is dark.
 */
bool room_is_dark(ROOM_INDEX_DATA * pRoomIndex)
{
   if (!pRoomIndex)
   {
      bug("room_is_dark: NULL pRoomIndex", 0);
      return TRUE;
   }

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

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

   if (pRoomIndex->sector_type == SECT_INSIDE || pRoomIndex->sector_type == SECT_CITY || pRoomIndex->sector_type == SECT_ROAD)
      return FALSE;
      
   if (pRoomIndex->vnum == OVERLAND_SOLAN)
      return FALSE;
      
   if (pRoomIndex->sector_type == SECT_UNDERWATER || pRoomIndex->sector_type == SECT_OCEANFLOOR || pRoomIndex->sector_type == SECT_UNDERGROUND)
      return TRUE;

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

   return FALSE;
}

//True if room is private for wilderness
bool room_is_private_wilderness(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex, int x, int y, int map)
{
   CHAR_DATA *rch;
   int count;
   int rvalue;
   int oldx, oldy, oldmap;
   ROOM_INDEX_DATA *oldroom;

   if (!pRoomIndex)
   {
      bug("room_is_private: NULL pRoomIndex", 0);
      return FALSE;
   }
   
   oldx = ch->coord->x;
   oldy = ch->coord->y;
   oldmap = ch->map;
   oldroom = ch->in_room;
   
   ch->coord->x = x;
   ch->coord->y = y;
   ch->map = map;
   ch->in_room = pRoomIndex;
   
   if (ch->in_room->vnum == OVERLAND_SOLAN)
      SET_ONMAP_FLAG(ch);
   else
      REMOVE_ONMAP_FLAG(ch);   
   
   if (!IN_WILDERNESS(ch))
   {
      ch->coord->x = oldx;
      ch->coord->y = oldy;
      ch->map = oldmap;
      ch->in_room = oldroom;
      if (ch->in_room->vnum == OVERLAND_SOLAN)
         SET_ONMAP_FLAG(ch);
      else
         REMOVE_ONMAP_FLAG(ch);
      return FALSE;
   }
      
   count = 0;
   for (rch = pRoomIndex->first_person; rch; rch = rch->next_in_room)
   {
      if (rch->coord->x == x && rch->coord->y == y && rch->map == map)
         count++;
   }

   if (wIS_SET(ch, ROOM_PRIVATE) && count >= 2)
      rvalue = TRUE;
   else if (wIS_SET(ch, ROOM_SOLITARY) && count >= 1)
      rvalue = TRUE;
   else
      rvalue = FALSE;
   
   ch->coord->x = oldx;
   ch->coord->y = oldy;
   ch->map = oldmap;
   ch->in_room = oldroom;
   if (ch->in_room->vnum == OVERLAND_SOLAN)
      SET_ONMAP_FLAG(ch);
   else
      REMOVE_ONMAP_FLAG(ch);
   return FALSE;
}
/*
 * True if room is private.
 */
bool room_is_private(ROOM_INDEX_DATA * pRoomIndex)
{
   CHAR_DATA *rch;
   int count;

   if (!pRoomIndex)
   {
      bug("room_is_private: NULL pRoomIndex", 0);
      return FALSE;
   }

   count = 0;
   for (rch = pRoomIndex->first_person; rch; rch = rch->next_in_room)
      count++;

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

   if (xIS_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 (!ch)
   {
      if (IS_AFFECTED(victim, AFF_INVISIBLE) || IS_AFFECTED(victim, AFF_STALK) || IS_AFFECTED(victim, AFF_HIDE) || xIS_SET(victim->act, PLR_WIZINVIS))
         return FALSE;
      else
         return TRUE;
   }

   if (ch == victim)
      return TRUE;

   if (!IS_NPC(victim) && xIS_SET(victim->act, PLR_WIZINVIS) && get_trust(ch) < victim->pcdata->wizinvis)
      return FALSE;

   /* SB */
   if (IS_NPC(victim) && xIS_SET(victim->act, ACT_MOBINVIS) && get_trust(ch) <= LEVEL_GUEST)
      return FALSE;

   if (!IS_NPC(victim))
   {
      if (!IS_NPC(ch))
      {
         if (IN_WILDERNESS(ch) || IN_WILDERNESS(victim))
         {
            if (ch->map != victim->map
               || ch->coord->x != victim->coord->x
               || ch->coord->y != victim->coord->y)
               return FALSE;
         }
      }
      else
      {
         if (IN_WILDERNESS(ch) || IN_WILDERNESS(victim))
         {
            if (ch->map != victim->map
               || ch->coord->x != victim->coord->x
               || ch->coord->y != victim->coord->y)
               return FALSE;
         }
      }
   }
   else
   {
      if (!IS_NPC(ch))
      {
         if (IN_WILDERNESS(ch) || IN_WILDERNESS(victim))
         {
            if (ch->map != victim->map
               || ch->coord->x != victim->coord->x
               || ch->coord->y != victim->coord->y)
               return FALSE;
         }
      }
      else
      {
         if (IN_WILDERNESS(ch) || IN_WILDERNESS(victim))
         {
            if (ch->map != victim->map
               || ch->coord->x != victim->coord->x
               || ch->coord->y != victim->coord->y)
               return FALSE;
         }
      }
   }


   if (!IS_NPC(ch) && xIS_SET(ch->act, PLR_HOLYLIGHT))
      return TRUE;
   if (IS_AFFECTED(victim, AFF_STALK))
      return FALSE;
   /* The miracle cure for blindness? -- Altrag */
   if (!IS_AFFECTED(ch, AFF_TRUESIGHT))
   {
      if (IS_AFFECTED(ch, AFF_BLIND))
         return FALSE;

      if (room_is_dark(ch->in_room) && !IS_AFFECTED(ch, AFF_INFRARED))
         return FALSE;

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

      if (IS_AFFECTED(victim, AFF_HIDE)
         && !IS_AFFECTED(ch, AFF_DETECT_HIDDEN))
         return FALSE;
   }

   /* Redone by Narn to let newbie council members see pre-auths. */
   if (NOT_AUTHED(victim))
   {
      if (NOT_AUTHED(ch) || IS_IMMORTAL(ch) || IS_NPC(ch))
         return TRUE;

      if (ch->pcdata->council && !str_cmp(ch->pcdata->council->name, "Newbie Council"))
         return TRUE;

      return FALSE;
   }

/* Commented out for who list purposes
    if (!NOT_AUTHED(victim) && NOT_AUTHED(ch) && !IS_IMMORTAL(victim)
    && !IS_NPC(victim))
   	return FALSE;*/
   return TRUE;
}

//Global can_see check, like below but used mob_index, don't want to load mobiles that aren't going to attack (etc)
bool can_see_index(MOB_INDEX_DATA *ch, CHAR_DATA *victim)
{
   if (IS_NPC(victim) && ch == victim->pIndexData)
      return TRUE;
    
   if (!IS_NPC(victim) && xIS_SET(victim->act, PLR_WIZINVIS))
      return FALSE;

   /* SB */
   if (IS_NPC(victim) && xIS_SET(victim->act, ACT_MOBINVIS))
      return FALSE;   

   /* The miracle cure for blindness? -- Altrag */
   if (!xIS_SET(ch->affected_by, AFF_TRUESIGHT))
   {
      if (xIS_SET(ch->affected_by, AFF_BLIND))
         return FALSE;

      if (IS_AFFECTED(victim, AFF_INVISIBLE) && !xIS_SET(ch->affected_by, AFF_DETECT_INVIS))
         return FALSE;

      if (IS_AFFECTED(victim, AFF_HIDE)
         && !xIS_SET(ch->affected_by, AFF_DETECT_HIDDEN))
         return FALSE;
   }
   return TRUE;
}
   
   
/* Like can_see, but is used for global things like who */
bool can_see_map(CHAR_DATA * ch, CHAR_DATA * victim)
{
   if (!ch)
   {
      if (IS_AFFECTED(victim, AFF_INVISIBLE) || IS_AFFECTED(victim, AFF_HIDE) || xIS_SET(victim->act, PLR_WIZINVIS))
         return FALSE;
      else
         return TRUE;
   }

   if (ch == victim)
      return TRUE;

   if (!IS_NPC(victim) && xIS_SET(victim->act, PLR_WIZINVIS) && get_trust(ch) < victim->pcdata->wizinvis)
      return FALSE;

   /* SB */
   if (IS_NPC(victim) && xIS_SET(victim->act, ACT_MOBINVIS) && get_trust(ch) <= LEVEL_GUEST)
      return FALSE;

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

   /* The miracle cure for blindness? -- Altrag */
   if (!IS_AFFECTED(ch, AFF_TRUESIGHT))
   {
      if (IS_AFFECTED(ch, AFF_BLIND))
         return FALSE;

      if (room_is_dark(ch->in_room) && !IS_AFFECTED(ch, AFF_INFRARED))
         return FALSE;

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

      if (IS_AFFECTED(victim, AFF_HIDE)
         && !IS_AFFECTED(ch, AFF_DETECT_HIDDEN))
         return FALSE;
   }

   /* Redone by Narn to let newbie council members see pre-auths. */
   /*
   if (NOT_AUTHED(victim))
   {
      if (NOT_AUTHED(ch) || IS_IMMORTAL(ch) || IS_NPC(ch))
         return TRUE;

      if (ch->pcdata->council && !str_cmp(ch->pcdata->council->name, "Newbie Council"))
         return TRUE;

      return FALSE;
   } */

   return TRUE;
}

/*
 * True if char can see obj.
 */
bool can_see_obj(CHAR_DATA * ch, OBJ_DATA * obj)
{

   if (ch->coord->x > 0 || ch->coord->y > 0 || ch->map > -1
   ||  obj->coord->x > 0 || obj->coord->y > 0 || obj->map > -1)
   {
      if (ch->map != obj->map
         || ch->coord->x != obj->coord->x
         || ch->coord->y != obj->coord->y)
         return FALSE;
   }

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

   if (IS_NPC(ch) && ch->pIndexData->vnum == 3)
      return TRUE;

   if (IS_OBJ_STAT(obj, ITEM_BURIED))
      return FALSE;

   if (IS_AFFECTED(ch, AFF_TRUESIGHT))
      return TRUE;

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

   if (IS_OBJ_STAT(obj, ITEM_HIDDEN))
      return FALSE;

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

   if (room_is_dark(ch->in_room) && !IS_AFFECTED(ch, AFF_INFRARED))
      return FALSE;

   if (IS_OBJ_STAT(obj, ITEM_INVIS) && !IS_AFFECTED(ch, AFF_DETECT_INVIS))
      return FALSE;

   return TRUE;
}

/* Check for global obj checks on the map */
bool can_see_obj_map(CHAR_DATA * ch, OBJ_DATA * obj)
{
   /*  if ( IS_OBJ_STAT( obj, ITEM_ONMAP ) )
      {
      if( ch->map != obj->map
      || ch->coord->x != obj->coord->x
      || ch->coord->y != obj->coord->y )
      return FALSE;
      }   */

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

   if (IS_NPC(ch) && ch->pIndexData->vnum == 3)
      return TRUE;

   if (IS_OBJ_STAT(obj, ITEM_BURIED))
      return FALSE;

   if (IS_AFFECTED(ch, AFF_TRUESIGHT))
      return TRUE;

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

   if (IS_OBJ_STAT(obj, ITEM_HIDDEN))
      return FALSE;

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

   if (room_is_dark(ch->in_room) && !IS_AFFECTED(ch, AFF_INFRARED))
      return FALSE;

   if (IS_OBJ_STAT(obj, ITEM_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;

   if (IS_NPC(ch) && ch->pIndexData->vnum == 3)
      return TRUE;

   return FALSE;
}

// Need Color too -- 12/00
char *get_caste_color(int caste)
{
   if (caste >= 1 && caste <= 10)
      return "&Y";
   if (caste >= 11 && caste <= 20)
      return "&P";
   if (caste >= 21 && caste <= 28)
      return "&C";
   if (caste >= 29 && caste <= 30)
      return "&O";
   if (caste >= 31 && caste <= 35)
      return "&G&W";

   return "&z";
}

/*
 * Was getting tired of doing this manually -- Xerves 12/99
 */
char *get_caste_name(int caste, int sex)
{
   if (caste > MAX_CASTE)
   {
      bug("get_caste_name: A caste that exceeded the max was found.", 0);
      return "Casteless";
   }
   if (caste == 1)
      return "Serf";
   else if (caste == 2)
      return "Peasant";
   else if (caste == 3)
      return "Laborer";
   else if (caste == 4)
      return "Apprentice";
   else if (caste == 5)
      return "Journeyman";
   else if (caste == 6)
      return "Master";
   else if (caste == 7)
      return "Merchant";
   else if (caste == 8)
      return "Trader";
   else if (caste == 9 && sex == 0)
      return "Businessman";
   else if (caste == 9 && sex == 1)
      return "Businessman";
   else if (caste == 9 && sex == 2)
      return "Businesswoman";

   else if (caste == 10)
      return "Mayor";

   else if (caste == 11)
      return "Page";
   else if (caste == 12)
      return "Squire";
   else if (caste == 13)
      return "Knight";
   else if (caste == 14)
      return "Baronet";
   else if (caste == 15)
      return "Baron";
   else if (caste == 16)
      return "Earl";
   else if (caste == 17)
      return "Viscount";
   else if (caste == 18)
      return "Count";
   else if (caste == 19)
      return "Duke";
   else if (caste == 20)
      return "Marquis";

   else if (caste == 21)
      return "Vassal";
   else if (caste == 22)
      return "Lord-Vassal";
   else if (caste == 23)
      return "Lord";
   else if (caste == 24)
      return "Hi-Lord";
   else if (caste == 25)
      return "Captain";
   else if (caste == 26)
      return "Minister";
   else if (caste == 27 && sex == 0)
      return "Prince";
   else if (caste == 27 && sex == 1)
      return "Prince";
   else if (caste == 27 && sex == 2)
      return "Princess";
   else if (caste == 28 && sex == 0)
      return "King";
   else if (caste == 28 && sex == 1)
      return "King";
   else if (caste == 28 && sex == 2)
      return "Queen";
   else if (caste == 29)
      return "Avatar";
   else if (caste == 30)
      return "Legend";

   else if (caste == 31)
      return "Ascender";
   else if (caste == 32)
      return "Immortal";
   else if (caste == 33)
      return "Being";
   else if (caste == 34)
      return "Staff";
   else if (caste == 35)
      return "Admin";
   else
      return "Casteless";
}

/*
 * Return ascii name of an item type.
 */
char *item_type_name(OBJ_DATA * obj)
{
   if (obj->item_type < 1 || obj->item_type > MAX_ITEM_TYPE)
   {
      bug("Item_type_name: unknown type %d.", obj->item_type);
      return "(unknown)";
   }

   return o_types[obj->item_type];
}



/*
 * Return ascii name of an affect location.
 */
char *affect_loc_name(int location)
{
   switch (location)
   {
      case APPLY_NONE:
         return "none";
      case APPLY_ARMOR:
         return "armor class";
      case APPLY_SHIELD:
         return "shield";
      case APPLY_STONE:
         return "stone skin";
      case APPLY_SANCTIFY:
         return "damage";
      case APPLY_WMOD:
         return "weightmod";
      case APPLY_MANAFUSE:
         return "manafuse";
      case APPLY_FASTING:
         return "fasting";
      case APPLY_MANASHELL:
         return "manashell";   
      case APPLY_MANASHIELD:
         return "manashield"; 
      case APPLY_MANAGUARD:
         return "managuard"; 
      case APPLY_MANABURN:
         return "manaburn"; 
      case APPLY_WEAPONCLAMP:
         return "weaponclamp"; 
      case APPLY_ARROWCATCH:
         return "arrowcatch"; 
      case APPLY_RFIRE:
         return "rfire"; 
      case APPLY_RWATER:
         return "rwater"; 
      case APPLY_RAIR:
         return "rair"; 
      case APPLY_REARTH:
         return "rearth"; 
      case APPLY_RENERGY:
         return "renergy"; 
      case APPLY_RMAGIC:
         return "rmagic"; 
      case APPLY_RNONMAGIC:
         return "rnonmagic";    
      case APPLY_RBLUNT:
         return "rblunt";  
      case APPLY_RPIERCE:
         return "rpierce";  
      case APPLY_RSLASH:
         return "rslash";
      case APPLY_RPOISON:
         return "rpoison";  
      case APPLY_RPARALYSIS:
         return "rparalysis";  
      case APPLY_RHOLY:
         return "rholy";  
      case APPLY_RUNHOLY:
         return "runholy";  
      case APPLY_RUNDEAD:
         return "rundead";  
      case APPLY_BRACING:
         return "bracing"; 
      case APPLY_HARDENING:
         return "hardening"; 
      case APPLY_TOHIT:
         return "tohit";
      case APPLY_MANATICK:
         return "managen";
      case APPLY_HPTICK:
         return "hpgen";
      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_CHA:
         return "charisma";
      case APPLY_LCK:
         return "luck";
      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 "----------";
      case APPLY_HITROLL:
         return "hit roll";
      case APPLY_DAMROLL:
         return "damage roll";
      case APPLY_SAVING_POISON:
         return "save vs poison";
      case APPLY_SAVING_ROD:
         return "save vs rod";
      case APPLY_SAVING_PARA:
         return "save vs paralysis";
      case APPLY_SAVING_BREATH:
         return "save vs breath";
      case APPLY_SAVING_SPELL:
         return "save vs spell";
      case APPLY_HEIGHT:
         return "height";
      case APPLY_WEIGHT:
         return "weight";
      case APPLY_AFFECT:
         return "affected_by";
      case APPLY_EXT_AFFECT:
         return "xaffected_by";
      case APPLY_RESISTANT:
         return "resistant";
      case APPLY_IMMUNE:
         return "immune";
      case APPLY_SUSCEPTIBLE:
         return "susceptible";
      case APPLY_BACKSTAB:
         return "backstab";
      case APPLY_PICK:
         return "pick";
      case APPLY_TRACK:
         return "track";
      case APPLY_STEAL:
         return "steal";
      case APPLY_SNEAK:
         return "sneak";
      case APPLY_HIDE:
         return "hide";
      case APPLY_PALM:
         return "palm";
      case APPLY_DETRAP:
         return "detrap";
      case APPLY_DODGE:
         return "dodge";
      case APPLY_PEEK:
         return "peek";
      case APPLY_SCAN:
         return "scan";
      case APPLY_GOUGE:
         return "gouge";
      case APPLY_SEARCH:
         return "search";
      case APPLY_MOUNT:
         return "mount";
      case APPLY_DISARM:
         return "disarm";
      case APPLY_KICK:
         return "kick";
      case APPLY_PARRY:
         return "parry";
      case APPLY_BASH:
         return "bash";
      case APPLY_STUN:
         return "stun";
      case APPLY_PUNCH:
         return "punch";
      case APPLY_CLIMB:
         return "climb";
      case APPLY_GRIP:
         return "grip";
      case APPLY_SCRIBE:
         return "scribe";
      case APPLY_BREW:
         return "brew";
      case APPLY_COOK:
         return "cook";
      case APPLY_WEAPONSPELL:
         return "weapon spell";
      case APPLY_WEARSPELL:
         return "wear spell";
      case APPLY_REMOVESPELL:
         return "remove spell";
      case APPLY_MENTALSTATE:
         return "mental state";
      case APPLY_EMOTION:
         return "emotional state";
      case APPLY_STRIPSN:
         return "dispel";
      case APPLY_REMOVE:
         return "remove";
      case APPLY_DIG:
         return "dig";
      case APPLY_FULL:
         return "hunger";
      case APPLY_THIRST:
         return "thirst";
      case APPLY_DRUNK:
         return "drunk";
      case APPLY_BLOOD:
         return "blood";
      case APPLY_RECURRINGSPELL:
         return "recurring spell";
      case APPLY_CONTAGIOUS:
         return "contagious";
      case APPLY_ODOR:
         return "odor";
      case APPLY_ROOMFLAG:
         return "roomflag";
      case APPLY_SECTORTYPE:
         return "sectortype";
      case APPLY_ROOMLIGHT:
         return "roomlight";
      case APPLY_TELEVNUM:
         return "teleport vnum";
      case APPLY_TELEDELAY:
         return "teleport delay";
      case APPLY_AGI:
         return "agility";  
   };

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



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

   buf[0] = '\0';
   if (xIS_SET(*vector, AFF_BLIND))
      strcat(buf, " blind");
   if (xIS_SET(*vector, AFF_INVISIBLE))
      strcat(buf, " invisible");
   if (xIS_SET(*vector, AFF_DETECT_EVIL))
      strcat(buf, " detect_evil");
   if (xIS_SET(*vector, AFF_DETECT_INVIS))
      strcat(buf, " detect_invis");
   if (xIS_SET(*vector, AFF_DETECT_MAGIC))
      strcat(buf, " detect_magic");
   if (xIS_SET(*vector, AFF_DETECT_HIDDEN))
      strcat(buf, " detect_hidden");
   if (xIS_SET(*vector, AFF_HOLD))
      strcat(buf, " hold");
   if (xIS_SET(*vector, AFF_SANCTUARY))
      strcat(buf, " sanctuary");
   if (xIS_SET(*vector, AFF_FAERIE_FIRE))
      strcat(buf, " faerie_fire");
   if (xIS_SET(*vector, AFF_INFRARED))
      strcat(buf, " infrared");
   if (xIS_SET(*vector, AFF_CURSE))
      strcat(buf, " curse");
   if (xIS_SET(*vector, AFF_FLAMING))
      strcat(buf, " flaming");
   if (xIS_SET(*vector, AFF_POISON))
      strcat(buf, " poison");
   if (xIS_SET(*vector, AFF_PROTECT))
      strcat(buf, " protect");
   if (xIS_SET(*vector, AFF_PARALYSIS))
      strcat(buf, " paralysis");
   if (xIS_SET(*vector, AFF_SLEEP))
      strcat(buf, " sleep");
   if (xIS_SET(*vector, AFF_SNEAK))
      strcat(buf, " sneak");
   if (xIS_SET(*vector, AFF_HIDE))
      strcat(buf, " hide");
   if (xIS_SET(*vector, AFF_CHARM))
      strcat(buf, " charm");
   if (xIS_SET(*vector, AFF_POSSESS))
      strcat(buf, " possess");
   if (xIS_SET(*vector, AFF_FLYING))
      strcat(buf, " flying");
   if (xIS_SET(*vector, AFF_PASS_DOOR))
      strcat(buf, " pass_door");
   if (xIS_SET(*vector, AFF_FLOATING))
      strcat(buf, " floating");
   if (xIS_SET(*vector, AFF_TRUESIGHT))
      strcat(buf, " true_sight");
   if (xIS_SET(*vector, AFF_DETECTTRAPS))
      strcat(buf, " detect_traps");
   if (xIS_SET(*vector, AFF_SCRYING))
      strcat(buf, " scrying");
   if (xIS_SET(*vector, AFF_FIRESHIELD))
      strcat(buf, " fireshield");
   if (xIS_SET(*vector, AFF_SHOCKSHIELD))
      strcat(buf, " shockshield");
   if (xIS_SET(*vector, AFF_ICESHIELD))
      strcat(buf, " iceshield");
   if (xIS_SET(*vector, AFF_BERSERK))
      strcat(buf, " berserk");
   if (xIS_SET(*vector, AFF_AQUA_BREATH))
      strcat(buf, " aqua_breath");
   if (xIS_SET(*vector, AFF_RECURRINGSPELL))
      strcat(buf, " recurringspell");
   if (xIS_SET(*vector, AFF_CONTAGIOUS))
      strcat(buf, " contagious");
   if (xIS_SET(*vector, AFF_WIZARDEYE))
      strcat(buf, " wizardeye");
   if (xIS_SET(*vector, AFF_E_WIZARDEYE))
      strcat(buf, " wizardeye");
   if (xIS_SET(*vector, AFF_M_WIZARDEYE))
      strcat(buf, " wizardeye");
   if (xIS_SET(*vector, AFF_BALANCE))
      strcat(buf, " balance");
   if (xIS_SET(*vector, AFF_NOHUNGER))
      strcat(buf, " nohunger");
   if (xIS_SET(*vector, AFF_NOTHIRST))
      strcat(buf, " nothirst");
   if (xIS_SET(*vector, AFF_GAGGED))
      strcat(buf, " gagged");
   if (xIS_SET(*vector, AFF_REZ))
      strcat(buf, " rez");
   if (xIS_SET(*vector, AFF_WEB))
      strcat(buf, " web");
   if (xIS_SET(*vector, AFF_SNARE))
      strcat(buf, " snare");
   if (xIS_SET(*vector, AFF_NERVEPINCH))
      strcat(buf, " nervepinch");
   if (xIS_SET(*vector, AFF_NYIJI))
      strcat(buf, " nyiji");
   if (xIS_SET(*vector, AFF_STALK))
      strcat(buf, " stalk");
   return (buf[0] != '\0') ? buf + 1 : "none";
}



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

   buf[0] = '\0';
   if (xIS_SET(*extra_flags, ITEM_GLOW))
      strcat(buf, " glow");
   if (xIS_SET(*extra_flags, ITEM_HUM))
      strcat(buf, " hum");
   if (xIS_SET(*extra_flags, ITEM_DARK))
      strcat(buf, " dark");
   if (xIS_SET(*extra_flags, ITEM_LOYAL))
      strcat(buf, " loyal");
   if (xIS_SET(*extra_flags, ITEM_EVIL))
      strcat(buf, " evil");
   if (xIS_SET(*extra_flags, ITEM_INVIS))
      strcat(buf, " invis");
   if (xIS_SET(*extra_flags, ITEM_MAGIC))
      strcat(buf, " magic");
   if (xIS_SET(*extra_flags, ITEM_NODROP))
      strcat(buf, " nodrop");
   if (xIS_SET(*extra_flags, ITEM_BLESS))
      strcat(buf, " bless");
   if (xIS_SET(*extra_flags, ITEM_ANTI_GOOD))
      strcat(buf, " anti-good");
   if (xIS_SET(*extra_flags, ITEM_ANTI_EVIL))
      strcat(buf, " anti-evil");
   if (xIS_SET(*extra_flags, ITEM_ANTI_NEUTRAL))
      strcat(buf, " anti-neutral");
   if (xIS_SET(*extra_flags, ITEM_NOREMOVE))
      strcat(buf, " noremove");
   if (xIS_SET(*extra_flags, ITEM_INVENTORY))
      strcat(buf, " inventory");
   if (xIS_SET(*extra_flags, ITEM_DEATHROT))
      strcat(buf, " deathrot");
   if (xIS_SET(*extra_flags, ITEM_GROUNDROT))
      strcat(buf, " groundrot");
   if (xIS_SET(*extra_flags, ITEM_ANTI_MAGE))
      strcat(buf, " anti-mage");
   if (xIS_SET(*extra_flags, ITEM_ANTI_THIEF))
      strcat(buf, " anti-thief");
   if (xIS_SET(*extra_flags, ITEM_ANTI_WARRIOR))
      strcat(buf, " anti-warrior");
   if (xIS_SET(*extra_flags, ITEM_ANTI_CLERIC))
      strcat(buf, " anti-cleric");
   if (xIS_SET(*extra_flags, ITEM_ANTI_DRUID))
      strcat(buf, " anti-druid");
   if (xIS_SET(*extra_flags, ITEM_ANTI_VAMPIRE))
      strcat(buf, " anti-vampire");
   if (xIS_SET(*extra_flags, ITEM_ANTI_PALADIN))
      strcat(buf, " anti-paladin");
   if (xIS_SET(*extra_flags, ITEM_ANTI_MONK))
      strcat(buf, " anti-monk");
   if (xIS_SET(*extra_flags, ITEM_ANTI_AUGURER))
      strcat(buf, " anti-augurer");
   if (xIS_SET(*extra_flags, ITEM_ANTI_RANGER))
      strcat(buf, " anti-ranger");
   if (xIS_SET(*extra_flags, ITEM_ORGANIC))
      strcat(buf, " organic");
   if (xIS_SET(*extra_flags, ITEM_METAL))
      strcat(buf, " metal");
   if (xIS_SET(*extra_flags, ITEM_DONATION))
      strcat(buf, " donation");
   if (xIS_SET(*extra_flags, ITEM_CLANOBJECT))
      strcat(buf, " clan");
   if (xIS_SET(*extra_flags, ITEM_CLANCORPSE))
      strcat(buf, " clanbody");
   if (xIS_SET(*extra_flags, ITEM_PROTOTYPE))
      strcat(buf, " prototype");
   if (xIS_SET(*extra_flags, ITEM_NOGIVE))
      strcat(buf, " nogive");
   if (xIS_SET(*extra_flags, ITEM_NOPURGE))
      strcat(buf, " nopurge");
   return (buf[0] != '\0') ? buf + 1 : "none";
}

/*
 * Return ascii name of magic flags vector. - Scryn
 */
char *magic_bit_name(int magic_flags)
{
   static char buf[512];

   buf[0] = '\0';
   if (magic_flags & ITEM_RETURNING)
      strcat(buf, " returning");
   return (buf[0] != '\0') ? buf + 1 : "none";
}

/*
 * Return ascii name of pulltype exit setting.
 */
char *pull_type_name(int pulltype)
{
   if (pulltype >= PT_FIRE)
      return ex_pfire[pulltype - PT_FIRE];
   if (pulltype >= PT_AIR)
      return ex_pair[pulltype - PT_AIR];
   if (pulltype >= PT_EARTH)
      return ex_pearth[pulltype - PT_EARTH];
   if (pulltype >= PT_WATER)
      return ex_pwater[pulltype - PT_WATER];
   if (pulltype < 0)
      return "ERROR";

   return ex_pmisc[pulltype];
}

/*
 * Set off a trap (obj) upon character (ch)			-Thoric
 */
ch_ret spring_trap(CHAR_DATA * ch, OBJ_DATA * obj, TRAP_DATA *trap)
{
   int dam;
   int typ;
   int lev;
   char *txt;
   char buf[MSL];
   ch_ret retcode;
   CHAR_DATA *victim;
   CHAR_DATA *victim_next;

   if (trap)
   { 
      typ = trap->type;
      lev = (trap->damlow + trap->damhigh) / 2;
      lev = URANGE(3, lev, 90);
   }
   else
   {  
      typ = obj->value[1];
      lev = obj->value[2];
   }

   retcode = rNONE;

   switch (typ)
   {
      default:
         txt = "hit by a trap";
         break;
      case TRAP_TYPE_POISON_GAS:
         txt = "surrounded by a green cloud of gas";
         break;
      case TRAP_TYPE_POISON_DART:
         txt = "hit by a dart";
         break;
      case TRAP_TYPE_POISON_NEEDLE:
         txt = "pricked by a needle";
         break;
      case TRAP_TYPE_POISON_DAGGER:
         txt = "stabbed by a dagger";
         break;
      case TRAP_TYPE_POISON_ARROW:
         txt = "struck with an arrow";
         break;
      case TRAP_TYPE_BLINDNESS_GAS:
         txt = "surrounded by a red cloud of gas";
         break;
      case TRAP_TYPE_SLEEPING_GAS:
         txt = "surrounded by a yellow cloud of gas";
         break;
      case TRAP_TYPE_FLAME:
         txt = "struck by a burst of flame";
         break;
      case TRAP_TYPE_EXPLOSION:
         txt = "hit by an explosion";
         break;
      case TRAP_TYPE_ACID_SPRAY:
         txt = "covered by a spray of acid";
         break;
      case TRAP_TYPE_ELECTRIC_SHOCK:
         txt = "suddenly shocked";
         break;
      case TRAP_TYPE_BLADE:
         txt = "sliced by a razor sharp blade";
         break;
      case TRAP_TYPE_SEX_CHANGE:
         txt = "surrounded by a mysterious aura";
         break;
   }
   if (trap)
      dam = number_range(trap->damlow, trap->damhigh);
   else
      dam = number_range(obj->value[2], obj->value[2] * 2);
   sprintf(buf, "You are %s!", txt);
   act(AT_RED, buf, ch, NULL, NULL, TO_CHAR);
   sprintf(buf, "$n is %s!", txt);
   act(AT_RED, buf, ch, NULL, NULL, TO_ROOM);
   if (trap)
   {
      RESET_DATA *pReset;
      int rfound = 0;
      
      --trap->charges;
      if (trap->onetime == 1 && trap->area)
      {
         for (pReset = trap->area->first_reset; pReset; pReset = pReset->next)
         {
            if (pReset->command == 'A' && pReset->arg1 == trap->uid)
            {
               delete_reset(trap->area, pReset);
               fold_area(trap->area, trap->area->filename, FALSE, 1);
               trap->obj->trap = NULL;
               trap->obj = NULL;
               trap->area = NULL;
               rfound = 1;
               break;
            }
         }
         if (!rfound)
            bug("Trap of uid %d was flagged onetime but could not be found to delete reset.", trap->uid);
      }
   }
   else
   {
      --obj->value[0];
      if (obj->value[0] <= 0)
         extract_obj(obj);
   }
   //spring it on others in the room, disable room fire then re-enable it
   if (trap && trap->room == 1)
   {     
      int charges;
      
      charges = trap->charges;
      trap->room = 0;
      for (victim = ch->in_room->first_person; victim; victim = victim_next)
      {
         victim_next = victim->next_in_room;
         if (IN_SAME_ROOM(ch, victim) && victim != ch)
            spring_trap(victim, NULL, trap);
      }
      trap->charges = charges;
      trap->room = 1;
   }
             
   switch (typ)
   {
      default:
      case TRAP_TYPE_POISON_DART:
      case TRAP_TYPE_POISON_NEEDLE:
      case TRAP_TYPE_POISON_DAGGER:
      case TRAP_TYPE_POISON_ARROW:
         /* hmm... why not use spell_poison() here? */
         retcode = obj_cast_spell(gsn_poison, lev, ch, ch, NULL);
         if (retcode == rNONE)
            retcode = damage(ch, ch, dam, TYPE_UNDEFINED, 0, number_range(LM_BODY, LM_NECK));
         break;
      case TRAP_TYPE_POISON_GAS:
         retcode = obj_cast_spell(gsn_poison, lev, ch, ch, NULL);
         break;
      case TRAP_TYPE_BLINDNESS_GAS:
         retcode = obj_cast_spell(gsn_blindness, lev, ch, ch, NULL);
         break;
      case TRAP_TYPE_SLEEPING_GAS:
         retcode = obj_cast_spell(skill_lookup("sleep"), lev, ch, ch, NULL);
         break;
      case TRAP_TYPE_SEX_CHANGE:
         break;
      case TRAP_TYPE_ACID_SPRAY:
      case TRAP_TYPE_FLAME:
      case TRAP_TYPE_EXPLOSION:;
      case TRAP_TYPE_ELECTRIC_SHOCK:
      case TRAP_TYPE_BLADE:
         retcode = damage(ch, ch, dam, TYPE_UNDEFINED, 0, number_range(LM_BODY, LM_NECK));
   }
   return retcode;
}

ch_ret pre_spring_trap(CHAR_DATA * ch, OBJ_DATA * obj, TRAP_DATA *trap, OBJ_DATA *trapobj)
{
   int frag = 0;
   if (trap)
   {
      if (trap->frag)
      {
         if (number_range(1, 100) <= trap->frag)
         {
            act(AT_DGREY, "The trap armed on $p fires.  The force of the trap shatters $p into pieces", ch, trapobj, NULL, TO_ROOM);
            act(AT_DGREY, "The trap armed on $p fires.  The force of the trap shatters $p into pieces", ch, trapobj, NULL, TO_CHAR);
            frag = 1;
         }
      }
      global_retcode = spring_trap(ch, obj, trap);
      if (trap->charges <= 0 && trap->uid >= START_INV_TRAP)
      {
         UNLINK(trap, first_trap, last_trap, next, prev);
         trapobj->trap = NULL;
         DISPOSE(trapobj->trap);   
         save_trap_file(NULL, NULL);
      }
      if (frag == 1)
      {
         extract_obj(trapobj);
         global_retcode = rOBJ_SCRAPPED;
      }
   }
   else
   {
      global_retcode = spring_trap(ch, obj, obj->trap);
   }
   return global_retcode;   
}

/*
 * Check an object for a trap					-Thoric
 */
ch_ret check_for_trap(CHAR_DATA * ch, OBJ_DATA * obj, int flag, int newflag)
{
   OBJ_DATA *check;
   ch_ret retcode;

   global_retcode = rNONE;
   
   if (obj->trap)
   {
      if (newflag == -1)
         return rNONE;
      if (obj->trap->charges < 1)
         return rNONE;
      if (xIS_SET(obj->trap->trapflags, newflag))
      {
         if (newflag == NEW_TRAP_GET)
         {
            act(AT_RED, "As $n attempts to get something from $p, a trap is fired.", ch, obj, NULL, TO_ROOM);
            act(AT_RED, "As you attempt to get something from $p, a trap is fired.", ch, obj, NULL, TO_CHAR);
         }
         return pre_spring_trap(ch, NULL, obj->trap, obj);
      }
      else
         return rNONE;
   }
   
   if (flag == -1)
      return rNONE;

   if (!obj->first_content)
      return rNONE;

   retcode = rNONE;

   for (check = obj->first_content; check; check = check->next_content)
      if (check->item_type == ITEM_TRAP && IS_SET(check->value[3], flag))
      {
         retcode = spring_trap(ch, check, NULL);
         if (retcode != rNONE)
            return retcode;
      }
   return retcode;
}

/*
 * Check the room for a trap					-Thoric
 */
ch_ret check_room_for_traps(CHAR_DATA * ch, int flag)
{
   OBJ_DATA *check;
   ch_ret retcode;

   retcode = rNONE;

   if (!ch)
      return rERROR;
   if (!ch->in_room || !ch->in_room->first_content)
      return rNONE;

   for (check = ch->in_room->first_content; check; check = check->next_content)
   {
      if (check->item_type == ITEM_TRAP && IS_SET(check->value[3], flag))
      {
         retcode = spring_trap(ch, check, NULL);
         if (retcode != rNONE)
            return retcode;
      }
   }
   return retcode;
}

/*
 * return TRUE if an object contains a trap			-Thoric
 */
bool is_trapped(OBJ_DATA * obj)
{
   OBJ_DATA *check;

   if (obj->trap)
   {
      if (obj->trap->charges > 0)
         return TRUE;
   }

   if (!obj->first_content)
      return FALSE;

   for (check = obj->first_content; check; check = check->next_content)
      if (check->item_type == ITEM_TRAP)
         return TRUE;

   return FALSE;
}

/*
 * If an object contains a trap, return the pointer to the trap	-Thoric
 */
OBJ_DATA *get_trap(OBJ_DATA * obj)
{
   OBJ_DATA *check;

   if (!obj->first_content)
      return NULL;

   for (check = obj->first_content; check; check = check->next_content)
      if (check->item_type == ITEM_TRAP)
         return check;

   return NULL;
}

/*
 * Return a pointer to the first object of a certain type found that
 * a player is carrying/wearing
 */
OBJ_DATA *get_objtype(CHAR_DATA * ch, sh_int type)
{
   OBJ_DATA *obj;

   for (obj = ch->first_carrying; obj; obj = obj->next_content)
      if (obj->item_type == type)
         return obj;

   return NULL;
}

/*
 * Remove an exit from a room					-Thoric
 */
void extract_exit(ROOM_INDEX_DATA * room, EXIT_DATA * pexit)
{
   UNLINK(pexit, room->first_exit, room->last_exit, next, prev);
   if (pexit->rexit)
      pexit->rexit->rexit = NULL;
   STRFREE(pexit->keyword);
   STRFREE(pexit->description);
   if (pexit->coord)
      DISPOSE(pexit->coord);
   DISPOSE(pexit);
}

/*
 * Remove a room
 */
void extract_room(ROOM_INDEX_DATA * room)
{
   bug("extract_room: not implemented", 0);
   /*
      (remove room from hash table)
      clean_room( room )
      DISPOSE( room );
    */
   return;
}

/*
 * clean out a room (leave list pointers intact )		-Thoric
 */
void clean_room(ROOM_INDEX_DATA * room)
{
   EXTRA_DESCR_DATA *ed, *ed_next;
   EXIT_DATA *pexit, *pexit_next;

   STRFREE(room->description);
   STRFREE(room->name);
   for (ed = room->first_extradesc; ed; ed = ed_next)
   {
      ed_next = ed->next;
      STRFREE(ed->description);
      STRFREE(ed->keyword);
      DISPOSE(ed);
      top_ed--;
   }
   room->first_extradesc = NULL;
   room->last_extradesc = NULL;
   for (pexit = room->first_exit; pexit; pexit = pexit_next)
   {
      pexit_next = pexit->next;
      STRFREE(pexit->keyword);
      STRFREE(pexit->description);
      DISPOSE(pexit);
      top_exit--;
   }
   room->first_exit = NULL;
   room->last_exit = NULL;
   xCLEAR_BITS(room->room_flags);
   room->sector_type = 0;
   room->light = 0;
}

/*
 * clean out an object (index) (leave list pointers intact )	-Thoric
 */
void clean_obj(OBJ_INDEX_DATA * obj)
{
   AFFECT_DATA *paf;
   AFFECT_DATA *paf_next;
   EXTRA_DESCR_DATA *ed;
   EXTRA_DESCR_DATA *ed_next;

   STRFREE(obj->name);
   STRFREE(obj->short_descr);
   STRFREE(obj->description);
   STRFREE(obj->action_desc);
   obj->item_type = 0;
   xCLEAR_BITS(obj->extra_flags);
   obj->wear_flags = 0;
   obj->count = 0;
   obj->weight = 0;
   obj->cost = 0;
   obj->value[0] = 0;
   obj->value[1] = 0;
   obj->value[2] = 0;
   obj->value[3] = 0;
   for (paf = obj->first_affect; paf; paf = paf_next)
   {
      paf_next = paf->next;
      DISPOSE(paf);
      top_affect--;
   }
   obj->first_affect = NULL;
   obj->last_affect = NULL;
   for (ed = obj->first_extradesc; ed; ed = ed_next)
   {
      ed_next = ed->next;
      STRFREE(ed->description);
      STRFREE(ed->keyword);
      DISPOSE(ed);
      top_ed--;
   }
   obj->first_extradesc = NULL;
   obj->last_extradesc = NULL;
}

/*
 * clean out a mobile (index) (leave list pointers intact )	-Thoric
 */
void clean_mob(MOB_INDEX_DATA * mob)
{
   MPROG_DATA *mprog, *mprog_next;

   STRFREE(mob->player_name);
   STRFREE(mob->short_descr);
   STRFREE(mob->long_descr);
   STRFREE(mob->description);
   mob->spec_fun = NULL;
   mob->pShop = NULL;
   mob->rShop = NULL;
   xCLEAR_BITS(mob->progtypes);

   for (mprog = mob->mudprogs; mprog; mprog = mprog_next)
   {
      mprog_next = mprog->next;
      STRFREE(mprog->arglist);
      STRFREE(mprog->comlist);
      DISPOSE(mprog);
   }
   mob->count = 0;
   mob->killed = 0;
   mob->sex = 0;
   mob->level = 0;
   xCLEAR_BITS(mob->act);
   xCLEAR_BITS(mob->affected_by);
   mob->alignment = 0;
   mob->mobthac0 = 0;
   mob->ac = 0;
   mob->hitnodice = 0;
   mob->hitsizedice = 0;
   mob->hitplus = 0;
   mob->damnodice = 0;
   mob->damsizedice = 0;
   mob->damplus = 0;
   mob->gold = 0;
   mob->position = 0;
   mob->defposition = 0;
   mob->height = 0;
   mob->weight = 0; /* mob->vnum  = 0; */
   xCLEAR_BITS(mob->attacks);
   xCLEAR_BITS(mob->defenses);
}

extern int top_reset;

/*
 * Remove all resets from an area				-Thoric
 */
void clean_resets(AREA_DATA * tarea)
{
   RESET_DATA *pReset, *pReset_next;

   for (pReset = tarea->first_reset; pReset; pReset = pReset_next)
   {
      pReset_next = pReset->next;
      DISPOSE(pReset);
      --top_reset;
   }
   tarea->first_reset = NULL;
   tarea->last_reset = NULL;
}


/*
 * "Roll" players stats based on the character name		-Thoric
 */
 /*
    void name_stamp_stats( CHAR_DATA *ch )
    {
    int x, a, b, c;

    for ( x = 0; x < strlen(ch->name); x++ )
    {
    c = ch->name[x] + x;
    b = c % 14;
    a = (c % 1) + 1;
    switch (b)
    {
    case  0:
    ch->perm_str = UMIN( 18, ch->perm_str + a );
    break;
    case  1:
    ch->perm_dex = UMIN( 18, ch->perm_dex + a );
    break;
    case  2:
    ch->perm_wis = UMIN( 18, ch->perm_wis + a );
    break;
    case  3:
    ch->perm_int = UMIN( 18, ch->perm_int + a );
    break;
    case  4:
    ch->perm_con = UMIN( 18, ch->perm_con + a );
    break;
    case  5:
    ch->perm_cha = UMIN( 18, ch->perm_cha + a );
    break;
    case  6:
    ch->perm_lck = UMIN( 18, ch->perm_lck + a );
    break;
    case  7:
    ch->perm_agi = UMIN( 18, ch->perm_agi + a);
    break;
    case  8:
    ch->perm_str = UMAX(  9, ch->perm_str - a );
    break;
    case  9:
    ch->perm_dex = UMAX(  9, ch->perm_dex - a );
    break;
    case  10:
    ch->perm_wis = UMAX(  9, ch->perm_wis - a );
    break;
    case 11:
    ch->perm_int = UMAX(  9, ch->perm_int - a );
    break;
    case 12:
    ch->perm_con = UMAX(  9, ch->perm_con - a );
    break;
    case 13:
    ch->perm_cha = UMAX(  9, ch->perm_cha - a );
    break;
    case 14:
    ch->perm_lck = UMAX(  9, ch->perm_lck - a );
    break;
    case 15:
    ch->perm_agi = UMAX(  9, ch->perm_agi - a );
    break;
    }
    }

    }
    --Removed for Stat rolling Xerves */

/*
 * "Roll" players stats based on the character name             -Thoric
 */
/* Rewritten by Whir. Thanks to Vor/Casteele for help 2-1-98 */
/* Racial bonus calculations moved to this function and removed
   from comm.c - Samson 2-2-98 */
/* Updated to AD&D standards by Samson 9-5-98 */
/* Changed to use internal random number generator instead of
   OS dependant random() function - Samson 9-5-98 */
/* OOH long list, Added support for Prime Stats, and adding
   some HP/Mana/Prac/Train support also -- Xerves 8-1-99*/
// More Changes for 2.0 the comments GROW!!!! -- Xerves 6-01

void name_stamp_stats(CHAR_DATA * ch)
{
   ch->perm_str = 14 + race_table[ch->race]->str_plus;
   ch->perm_dex = 14 + race_table[ch->race]->dex_plus;	
   ch->perm_wis = 14 + race_table[ch->race]->wis_plus;
   ch->perm_int = 14 + race_table[ch->race]->int_plus;
   ch->perm_con = 14 + race_table[ch->race]->con_plus;
   ch->perm_lck = 14 + race_table[ch->race]->lck_plus;
   ch->perm_agi = race_table[ch->race]->agi_start;
   ch->perm_cha = 14;
   ch->pcdata->lore = dice(5, 2);
   ch->max_hit = 18 + dice(3, 3);
   ch->max_mana = 50 + dice(5, 5);
   ch->max_move = 1000;
   ch->gold = 12000 + dice(200, 10);
   ch->max_hit += race_table[ch->race]->hit;
   ch->max_mana += race_table[ch->race]->mana;
   ch->move = ch->max_move;
   ch->hit = ch->max_hit;
   ch->mana = ch->max_mana;

}

/*
 * "Fix" a character's stats					-Thoric
 */
void fix_char(CHAR_DATA * ch)
{
   AFFECT_DATA *aff;
   CHAR_DATA *temp;
   OBJ_DATA *carry[200]; //if they have more than this they need to have them removed
   OBJ_DATA *obj;
   int x, ncarry;

   de_equip_char(ch);

   ncarry = 0;
   while ((obj = ch->first_carrying) != NULL)
   {
      if (ncarry >= 200)
      {
         bug("%s has too many objects in his/her inventory.", ch->name);
         break;
      }
      carry[ncarry++] = obj;
      obj_from_char(obj);
   }
   

   for (aff = ch->first_affect; aff; aff = aff->next)
      affect_modify(ch, aff, FALSE);

   xCLEAR_BITS(ch->affected_by);
   xSET_BITS(ch->affected_by, race_table[ch->race]->affected);
   ch->mental_state = -10;
   ch->hit = UMAX(1, ch->hit);
   ch->mana = UMAX(1, ch->mana);
   ch->move = UMAX(1, ch->move);
   ch->armor = 0;
   ch->mod_str = 0;
   ch->mod_dex = 0;
   ch->mod_wis = 0;
   ch->mod_int = 0;
   ch->mod_con = 0;
   ch->mod_cha = 0;
   ch->mod_lck = 0;
   ch->mod_agi = 0;
   ch->damroll = 0;
   ch->hitroll = 0;
   ch->alignment = URANGE(-1000, ch->alignment, 1000);
   ch->saving_breath = 0;
   ch->saving_wand = 0;
   ch->saving_para_petri = 0;
   ch->saving_spell_staff = 0;
   ch->saving_poison_death = 0;

   for (aff = ch->first_affect; aff; aff = aff->next)
      affect_modify(ch, aff, TRUE);

   for (x = 0; x < ncarry; x++)
   {
      temp = loading_char;
      loading_char = ch;
      obj_to_char(carry[x], ch);
      loading_char = temp;
   }

   re_equip_char(ch);
}

char *specgem_loc_name(int type)
{
   //1000 - Damage  1001 - Durability  1002 - TohitBash  1003 - TohitStab   1004 - TohitSlash
//1005 - Weight  1006 - Shieldlag   1007 - Blocking % 1008 - Proj Range  1009 - Parry Chance 1010 - Stop Parry
//1011 - SpellSN 1012 - SpellStr    1013 - Unbeakable 1014 - Nodisarm    1015 - Sanctified 1016 - Change Size
   if (type == 1000)
      return "Spec Damage";
   else if (type == 1001)
      return "Spec Durability";
   else if (type == 1002)
      return "Spec ToHitBash";
   else if (type == 1003)
      return "Spec ToHitStab";
   else if (type == 1004)
      return "Spec ToHitSlash";
   else if (type == 1005)
      return "Spec Weight";
   else if (type == 1006)
      return "Spec Shieldlag";
   else if (type == 1007)
      return "Spec Blocking Percent";
   else if (type == 1008)
      return "Spec Projectile Range";
   else if (type == 1009)
      return "Spec Parry Chance";
   else if (type == 1010)
      return "Spec Stop Parry";
   else if (type == 1011)
      return "Spec Spell";
   else if (type == 1012)
      return "Spec Spell Strength";
   else if (type == 1013)
      return "Spec Unbreakable Flag";
   else if (type == 1014)
      return "Spec Nodisarm Flag";
   else if (type == 1015)
      return "Spec Sanctified Flag";
   else if (type == 1016)
      return "Spec Change Size";
   else if (type == 1017)
      return "Spec Saves";
   else
      return "Unknown Spec";
}

/*
 * Show an affect verbosely to a character			-Thoric
 */
char *showgemaff(CHAR_DATA * ch, OBJ_DATA *obj, int passbuf, IMBUE_DATA *imbue)
{
   char buf[MSL];
   static char pbuf[MSL];
   char buf2[MSL];
   int x;
   int cnt;
   int v1, v2, v3, v4;

   strcpy(pbuf, "");
   if (!obj && !imbue)
   {
      bug("showgemaff: NULL obj and imbue", 0);
      return NULL;
   }
   for (cnt = 0; cnt < 12; cnt+=4)
   {
      strcpy(buf, "");
      if (obj)
      {
         v1 = obj->value[cnt];
         v2 = obj->value[cnt+1];
         v3 = obj->value[cnt+2];
         v4 = obj->value[cnt+3];
      }
      else
      {
         if (cnt == 0)
         {
            v1 = imbue->type;
            v2 = imbue->sworth;
            v3 = imbue->lowvalue;
            v4 = imbue->highvalue;
         }
         else if (cnt == 4)
         {
            v1 = imbue->type2;
            v2 = imbue->sworth2;
            v3 = imbue->lowvalue2;
            v4 = imbue->highvalue2;
         }
         else
         {
            v1 = imbue->type3;
            v2 = imbue->sworth3;
            v3 = imbue->lowvalue3;
            v4 = imbue->highvalue3;
         }
      }
      if (v1 != APPLY_NONE && v3 != 0)
      {
         switch (v1)
         {
            default:
               if (v1 >= 1000)
               {            
                  if (v1 == 1011)
                  {
                     sprintf(buf, "    Adds %s %s (%d Sworth).\n\r", specgem_loc_name(v1),  skill_table[v3]->name, 
                        v2);
                  }
                  else if (v1 == 1012)
                  {
                     sprintf(buf, "    Adds %s %s from %s (%d Sworth).\n\r", specgem_loc_name(v1), get_wplevel(v3), 
                        get_wplevel(v4), v2);
                  }
                  else
                  {
                     sprintf(buf, "    Adds %s by %d to %d (%d Sworth).\n\r", specgem_loc_name(v1), v3, 
                        v4, v2);
                  }
               }
               else
               {
                  sprintf(buf, "    Adds %s by %d to %d (%d Sworth).\n\r", affect_loc_name(v1), v3, 
                     v4, v2);
               }
               break;
            case APPLY_EXT_AFFECT:
               sprintf(buf, "     Adds %s by %s (%d Sworth).\n\r", affect_loc_name(v1), a_flags[v3], v2);
               break;
            case APPLY_AFFECT:
               sprintf(buf, "    Adds %s by", affect_loc_name(v1));
               for (x = 0; x < 32; x++)
                  if (IS_SET(v3, 1 << x))
                  {
                     strcat(buf, " ");
                        strcat(buf, a_flags[x]);
                  }
               sprintf(buf2, " (%d Sworth)", v2);
               strcat(buf, buf2);
               strcat(buf, "\n\r");
               break;
            case APPLY_WEAPONSPELL:
            case APPLY_WEARSPELL:
            case APPLY_REMOVESPELL:
               sprintf(buf, "    Adds spell '%s' (%d Sworth)\n\r", IS_VALID_SN(v3) ? skill_table[v3]->name : "unknown",
                  v2);
               break;
            case APPLY_RESISTANT:
            case APPLY_IMMUNE:
            case APPLY_SUSCEPTIBLE:
               sprintf(buf, "    Adds %s by", affect_loc_name(v1));
               for (x = 0; x < 32; x++)
                  if (IS_SET(v3, 1 << x))
                  {
                     strcat(buf, " ");
                     strcat(buf, ris_flags[x]);
                  }
               sprintf(buf2, " (%d Sworth)", v2);
               strcat(buf, buf2);
               strcat(buf, "\n\r");
               break;
         }
      }
      strcat(pbuf, buf);
   }
   if (!passbuf)
      send_to_char(pbuf, ch);
    else
      return pbuf;
   return NULL;
}


/*
 * Show an affect verbosely to a character			-Thoric
 */
char *showaffect(CHAR_DATA * ch, AFFECT_DATA * paf, int passbuf)
{
   static char buf[MSL];
   int x;

   strcpy(buf, "");
   if (!paf)
   {
      bug("showaffect: NULL paf", 0);
      return NULL;
   }
   if (paf->location != APPLY_NONE && paf->modifier != 0)
   {
      switch (paf->location)
      {
         default:
            sprintf(buf, "Affects %s by %d.\n\r", affect_loc_name(paf->location), paf->modifier);
            break;
         case APPLY_EXT_AFFECT:
            sprintf(buf, "Affects %s by %s.\n\r", affect_loc_name(paf->location), a_flags[paf->modifier]);
            break;
         case APPLY_AFFECT:
            sprintf(buf, "Affects %s by", affect_loc_name(paf->location));
            for (x = 0; x < 32; x++)
               if (IS_SET(paf->modifier, 1 << x))
               {
                  strcat(buf, " ");
                  strcat(buf, a_flags[x]);
               }
            strcat(buf, "\n\r");
            break;
         case APPLY_WEAPONSPELL:
         case APPLY_WEARSPELL:
         case APPLY_REMOVESPELL:
            sprintf(buf, "Casts spell '%s'\n\r", IS_VALID_SN(paf->modifier) ? skill_table[paf->modifier]->name : "unknown");
            break;
         case APPLY_RESISTANT:
         case APPLY_IMMUNE:
         case APPLY_SUSCEPTIBLE:
            sprintf(buf, "Affects %s by", affect_loc_name(paf->location));
            for (x = 0; x < 32; x++)
               if (IS_SET(paf->modifier, 1 << x))
               {
                  strcat(buf, " ");
                  strcat(buf, ris_flags[x]);
               }
            strcat(buf, "\n\r");
            break;
      }
      if (!passbuf)
         send_to_char(buf, ch);
      else
         return buf;
   }
   return NULL;
}

/*
 * Set the current global object to obj				-Thoric
 */
void set_cur_obj(OBJ_DATA * obj)
{
   cur_obj = obj->serial;
   cur_obj_extracted = FALSE;
   global_objcode = rNONE;
}

/*
 * Check the recently extracted object queue for obj		-Thoric
 */
bool obj_extracted(OBJ_DATA * obj)
{
   OBJ_DATA *cod;

   if (obj->serial == cur_obj && cur_obj_extracted)
      return TRUE;

   for (cod = extracted_obj_queue; cod; cod = cod->next)
      if (obj == cod)
         return TRUE;
   return FALSE;
}

/*
 * Stick obj onto extraction queue
 */
void queue_extracted_obj(OBJ_DATA * obj)
{

   ++cur_qobjs;
   obj->next = extracted_obj_queue;
   extracted_obj_queue = obj;
}

/*
 * Clean out the extracted object queue
 */
void clean_obj_queue()
{
   OBJ_DATA *obj;

   while (extracted_obj_queue)
   {
      obj = extracted_obj_queue;
      extracted_obj_queue = extracted_obj_queue->next;
      STRFREE(obj->name);
      STRFREE(obj->description);
      STRFREE(obj->short_descr);
      STRFREE(obj->action_desc);
      if (obj->coord)
         DISPOSE(obj->coord);
      DISPOSE(obj);
      --cur_qobjs;
   }
}

/*
 * Set the current global character to ch			-Thoric
 */
void set_cur_char(CHAR_DATA * ch)
{
   cur_char = ch;
   cur_char_died = FALSE;
   cur_room = ch->in_room;
   global_retcode = rNONE;
}

/*
 * Check to see if ch died recently				-Thoric
 */
bool char_died(CHAR_DATA * ch)
{
   EXTRACT_CHAR_DATA *ccd;

   if (ch == cur_char && cur_char_died)
      return TRUE;

   for (ccd = extracted_char_queue; ccd; ccd = ccd->next)
      if (ccd->ch == ch)
         return TRUE;
   return FALSE;
}

/*
 * Add ch to the queue of recently extracted characters		-Thoric
 */
void queue_extracted_char(CHAR_DATA * ch, bool extract)
{
   EXTRACT_CHAR_DATA *ccd;

   if (!ch)
   {
      bug("queue_extracted char: ch = NULL", 0);
      return;
   }
   CREATE(ccd, EXTRACT_CHAR_DATA, 1);
   ccd->ch = ch;
   ccd->room = ch->in_room;
   ccd->extract = extract;
   if (ch == cur_char)
      ccd->retcode = global_retcode;
   else
      ccd->retcode = rCHAR_DIED;
   ccd->next = extracted_char_queue;
   extracted_char_queue = ccd;
   cur_qchars++;
}

/*
 * clean out the extracted character queue
 */
void clean_char_queue()
{
   EXTRACT_CHAR_DATA *ccd;

   for (ccd = extracted_char_queue; ccd; ccd = extracted_char_queue)
   {
      extracted_char_queue = ccd->next;
      if (ccd->extract)
         free_char(ccd->ch);
      DISPOSE(ccd);
      --cur_qchars;
   }
}

/*
 * Add a timer to ch						-Thoric
 * Support for "call back" time delayed commands
 */
void add_timer(CHAR_DATA * ch, sh_int type, sh_int count, DO_FUN * fun, int value)
{
   TIMER *timer;

   for (timer = ch->first_timer; timer; timer = timer->next)
      if (timer->type == type)
      {
         timer->count = count;
         timer->do_fun = fun;
         timer->value = value;
         break;
      }
   if (!timer)
   {
      CREATE(timer, TIMER, 1);
      timer->count = count;
      timer->type = type;
      timer->do_fun = fun;
      timer->value = value;
      LINK(timer, ch->first_timer, ch->last_timer, next, prev);
   }
}

void add_obj_timer( OBJ_DATA *obj, sh_int type, sh_int count, DO_FUN *fun, int value )
{
    TIMER *timer;
 
    for ( timer = obj->first_timer; timer; timer = timer->next )
        if ( timer->type == type )
        {
           timer->count  = count;
           timer->do_fun = fun;
           timer->value  = value;
           break;
        }
    if ( !timer )
    {
        CREATE( timer, TIMER, 1 );
        timer->count    = count;
        timer->type     = type;
        timer->do_fun   = fun;
        timer->value    = value;
        LINK( timer, obj->first_timer, obj->last_timer, next, prev );
    }
}   

TIMER *get_timerptr(CHAR_DATA * ch, sh_int type)
{
   TIMER *timer;

   for (timer = ch->first_timer; timer; timer = timer->next)
      if (timer->type == type)
         return timer;
   return NULL;
}


TIMER *get_obj_timerptr( OBJ_DATA *obj, sh_int type )
{
    TIMER *timer;
 
    for ( timer = obj->first_timer; timer; timer = timer->next )
      if ( timer->type == type )
        return timer;
    return NULL;
}    

sh_int get_timer(CHAR_DATA * ch, sh_int type)
{
   TIMER *timer;

   if ((timer = get_timerptr(ch, type)) != NULL)
      return timer->count;
   else
      return 0;
}

sh_int get_obj_timer( OBJ_DATA *obj, sh_int type )
{
    TIMER *timer;
 
    if ( (timer = get_obj_timerptr( obj, type )) != NULL )
      return timer->count;
    else
      return 0;
}    

void extract_timer(CHAR_DATA * ch, TIMER * timer)
{
   if (!timer)
   {
      bug("extract_timer: NULL timer", 0);
      return;
   }

   UNLINK(timer, ch->first_timer, ch->last_timer, next, prev);
   DISPOSE(timer);
   return;
}

void extract_obj_timer( OBJ_DATA *obj, TIMER *timer )
{
    if ( !timer )
    {
        bug( "extract_timer: NULL timer", 0 );
        return;
    }
    separate_obj(obj);
    UNLINK( timer, obj->first_timer, obj->last_timer, next, prev );
    DISPOSE( timer );
    return;
}     

void remove_timer(CHAR_DATA * ch, sh_int type)
{
   TIMER *timer;

   for (timer = ch->first_timer; timer; timer = timer->next)
      if (timer->type == type)
         break;

   if (timer)
      extract_timer(ch, timer);
}

void remove_obj_timer( OBJ_DATA *obj, sh_int type )
{
    TIMER *timer;
 
    for ( timer = obj->first_timer; timer; timer = timer->next )
       if ( timer->type == type )
         break;
 
    if ( timer )
      extract_obj_timer( obj, timer );
} 

bool in_soft_range(CHAR_DATA * ch, AREA_DATA * tarea)
{
   if (IS_IMMORTAL(ch))
      return TRUE;
   else if (IS_NPC(ch))
      return TRUE;
   else if (ch->level >= tarea->low_soft_range || ch->level <= tarea->hi_soft_range)
      return TRUE;
   else
      return FALSE;
}    

bool can_astral(CHAR_DATA * ch, CHAR_DATA * victim)
{
   if (victim == ch
      || !victim->in_room
      || xIS_SET(victim->in_room->room_flags, ROOM_PRIVATE)
      || wIS_SET(victim, ROOM_PRIVATE)
      || xIS_SET(victim->in_room->room_flags, ROOM_SOLITARY)
      || wIS_SET(victim, ROOM_SOLITARY)
      || xIS_SET(victim->in_room->room_flags, ROOM_NO_ASTRAL)
      || wIS_SET(victim, ROOM_NO_ASTRAL)
      || xIS_SET(victim->in_room->room_flags, ROOM_DEATH)
      || xIS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
      || (IS_NPC(victim) && xIS_SET(victim->act, ACT_PROTOTYPE)) || (IS_NPC(victim) && saves_spell_staff(ch->level, victim)))
      return FALSE;
   else
      return TRUE;
}

bool in_hard_range(CHAR_DATA * ch, AREA_DATA * tarea)
{
   if (IS_IMMORTAL(ch))
      return TRUE;
   else if (IS_NPC(ch))
      return TRUE;
   else if (ch->level >= tarea->low_hard_range && ch->level <= tarea->hi_hard_range)
      return TRUE;
   else
      return FALSE;
}


/*
 * Scryn, standard luck check 2/2/96
 */
bool chance(CHAR_DATA * ch, sh_int percent)
{
/*  sh_int clan_factor, ms;*/
   sh_int deity_factor, ms;

   if (!ch)
   {
      bug("Chance: null ch!", 0);
      return FALSE;
   }

   if (IS_DEVOTED(ch))
      deity_factor = ch->pcdata->favor / -500;
   else
      deity_factor = 0;

   ms = 10 - abs(ch->mental_state);

   if ((number_percent() - get_curr_lck(ch) + 13 - ms) + deity_factor <= percent)
      return TRUE;
   else
      return FALSE;
}

bool chance_attrib(CHAR_DATA * ch, sh_int percent, sh_int attrib)
{
/* Scryn, standard luck check + consideration of 1 attrib 2/2/96*/
   sh_int deity_factor;

   if (!ch)
   {
      bug("Chance: null ch!", 0);
      return FALSE;
   }

   if (IS_DEVOTED(ch))
      deity_factor = ch->pcdata->favor / -500;
   else
      deity_factor = 0;

   if (number_percent() - get_curr_lck(ch) + 13 - attrib + 13 + deity_factor <= percent)
      return TRUE;
   else
      return FALSE;

}


/*
 * Make a simple clone of an object (no extras...yet)		-Thoric
 */
OBJ_DATA *clone_object(OBJ_DATA * obj)
{
   OBJ_DATA *clone;
   EXTRA_DESCR_DATA *ed, *ced;
   AFFECT_DATA *paf, *cpaf;

   CREATE(clone, OBJ_DATA, 1);
   clone->pIndexData = obj->pIndexData;
   clone->name = QUICKLINK(obj->name);
   clone->short_descr = QUICKLINK(obj->short_descr);
   clone->description = QUICKLINK(obj->description);
   clone->action_desc = QUICKLINK(obj->action_desc);
   clone->item_type = obj->item_type;
   clone->extra_flags = obj->extra_flags;
   clone->magic_flags = obj->magic_flags;
   clone->wear_flags = obj->wear_flags;
   clone->wear_loc = obj->wear_loc;
   clone->weight = obj->weight;
   clone->cost = obj->cost;
   clone->level = obj->level;
   clone->timer = obj->timer;
   clone->cident = obj->cident;
   CREATE(clone->coord, COORD_DATA, 1);
   clone->map = obj->map;
   clone->coord->x = obj->coord->x;
   clone->coord->y = obj->coord->y;
   clone->value[0] = obj->value[0];
   clone->value[1] = obj->value[1];
   clone->value[2] = obj->value[2];
   clone->value[3] = obj->value[3];
   clone->value[4] = obj->value[4];
   clone->value[5] = obj->value[5];
   clone->value[6] = obj->value[6];
   clone->value[7] = obj->value[7];
   clone->value[8] = obj->value[8];
   clone->value[9] = obj->value[9];
   clone->value[10] = obj->value[10];
   clone->value[11] = obj->value[11];
   clone->value[12] = obj->value[12];
   clone->value[13] = obj->value[13];
   clone->count = 1;
   for (ced = obj->first_extradesc; ced; ced = ced->next)
   {
      CREATE(ed, EXTRA_DESCR_DATA, 1);
      ed->keyword = QUICKLINK(ced->keyword);
      ed->description = QUICKLINK(ced->description);
      LINK(ed, clone->first_extradesc, clone->last_extradesc, next, prev);
      top_ed++;
   }
   for (cpaf = obj->first_affect; cpaf; cpaf = cpaf->next)
   {
      CREATE(paf, AFFECT_DATA, 1);
      paf->type = cpaf->type;
      paf->duration = cpaf->duration;
      paf->location = cpaf->location;
      paf->modifier = cpaf->modifier;
      paf->bitvector = cpaf->bitvector;
      LINK(paf, clone->first_affect, clone->last_affect, next, prev);
      top_affect++;
   }   
   ++obj->pIndexData->count;
   ++numobjsloaded;
   ++physicalobjects;
   cur_obj_serial = UMAX((cur_obj_serial + 1) & (BV30 - 1), 1);
   clone->serial = clone->pIndexData->serial = cur_obj_serial;
   LINK(clone, first_object, last_object, next, prev);
   return clone;
}

/*
 * If possible group obj2 into obj1				-Thoric
 * This code, along with clone_object, obj->count, and special support
 * for it implemented throughout handler.c and save.c should show improved
 * performance on MUDs with players that hoard tons of potions and scrolls
 * as this will allow them to be grouped together both in memory, and in
 * the player files.
 */
OBJ_DATA *group_object(OBJ_DATA * obj1, OBJ_DATA * obj2)
{
   if (!obj1 || !obj2)
      return NULL;
   if (obj1 == obj2)
      return obj1;

   if (obj1->pIndexData == obj2->pIndexData
/*
    &&	!obj1->pIndexData->mudprogs
    &&  !obj2->pIndexData->mudprogs
*/
      && QUICKMATCH(obj1->name, obj2->name)
      && QUICKMATCH(obj1->short_descr, obj2->short_descr)
      && QUICKMATCH(obj1->description, obj2->description)
      && QUICKMATCH(obj1->action_desc, obj2->action_desc)
      && obj1->item_type == obj2->item_type
      && xSAME_BITS(obj1->extra_flags, obj2->extra_flags)
      && obj1->magic_flags == obj2->magic_flags
      && obj1->wear_flags == obj2->wear_flags
      && obj1->wear_loc == obj2->wear_loc
      && obj1->weight == obj2->weight
      && obj1->cost == obj2->cost
      && obj1->level == obj2->level
      && obj1->timer == obj2->timer
      && obj1->value[0] == obj2->value[0]
      && obj1->value[1] == obj2->value[1]
      && obj1->value[2] == obj2->value[2]
      && obj1->value[3] == obj2->value[3]
      && obj1->value[4] == obj2->value[4]
      && obj1->value[5] == obj2->value[5]
      && obj1->value[6] == obj2->value[6]
      && obj1->value[7] == obj2->value[7]
      && obj1->value[8] == obj2->value[8]
      && obj1->value[9] == obj2->value[9]
      && obj1->value[10] == obj2->value[10]
      && obj1->value[11] == obj2->value[11]
      && obj1->value[12] == obj2->value[12]
      && obj1->value[13] == obj2->value[13]
      && !obj1->first_extradesc && !obj2->first_extradesc
      && !obj1->first_affect && !obj2->first_affect && !obj1->first_content && !obj2->first_content && obj1->count + obj2->count > 0 /* prevent count overflow */
      && obj1->map == obj2->map
      && obj1->coord->x == obj2->coord->x
      && obj1->coord->y == obj2->coord->y
      && !obj1->trap && !obj2->trap)
   {
      obj1->count += obj2->count;
      obj1->pIndexData->count += obj2->count; /* to be decremented in */
      numobjsloaded += obj2->count; /* extract_obj */
      extract_obj(obj2);
      return obj1;
   }
   return obj2;
}

/*
 * Split off a grouped object					-Thoric
 * decreased obj's count to num, and creates a new object containing the rest
 */
OBJ_DATA *split_obj(OBJ_DATA * obj, int num)
{
   int count = obj->count;
   OBJ_DATA *rest;

   if (count <= num || num == 0)
      return NULL;

   rest = clone_object(obj);
   --obj->pIndexData->count; /* since clone_object() ups this value */
   --numobjsloaded;
   rest->count = obj->count - num;
   obj->count = num;

   if (obj->carried_by)
   {
      LINK(rest, obj->carried_by->first_carrying, obj->carried_by->last_carrying, next_content, prev_content);
      rest->carried_by = obj->carried_by;
      rest->possessed_by = obj->possessed_by;
      rest->in_room = NULL;
      rest->in_obj = NULL;
   }
   else if (obj->in_room)
   {
      LINK(rest, obj->in_room->first_content, obj->in_room->last_content, next_content, prev_content);
      rest->carried_by = NULL;
      rest->possessed_by = NULL;
      rest->in_room = obj->in_room;
      rest->in_obj = NULL;
   }
   else if (obj->in_obj)
   {
      LINK(rest, obj->in_obj->first_content, obj->in_obj->last_content, next_content, prev_content);
      rest->in_obj = obj->in_obj;
      rest->in_room = NULL;
      rest->carried_by = NULL;
      rest->possessed_by = NULL;
   }
   return rest;
}

OBJ_DATA *separate_obj(OBJ_DATA * obj)
{
   return split_obj(obj, 1);
}

/*
 * Empty an obj's contents... optionally into another obj, or a room
 */
bool empty_obj(OBJ_DATA * obj, OBJ_DATA * destobj, ROOM_INDEX_DATA * destroom)
{
   OBJ_DATA *otmp, *otmp_next;
   CHAR_DATA *ch = obj->carried_by;
   bool movedsome = FALSE;

   if (!obj)
   {
      bug("empty_obj: NULL obj", 0);
      return FALSE;
   }
   if (destobj || (!destroom && !ch && (destobj = obj->in_obj) != NULL))
   {
      for (otmp = obj->first_content; otmp; otmp = otmp_next)
      {
         otmp_next = otmp->next_content;
         /* only keys on a keyring */
         if (destobj->item_type == ITEM_KEYRING && otmp->item_type != ITEM_KEY)
            continue;
         if (destobj->item_type == ITEM_QUIVER && otmp->item_type != ITEM_PROJECTILE)
            continue;
         if ((destobj->item_type == ITEM_CONTAINER || destobj->item_type == ITEM_KEYRING
               || destobj->item_type == ITEM_QUIVER) && get_real_obj_weight(otmp) + get_real_obj_weight(destobj) > destobj->value[0])
            continue;
         obj_from_obj(otmp);
         obj_to_obj(otmp, destobj);
         movedsome = TRUE;
      }
      return movedsome;
   }
   if (destroom || (!ch && (destroom = obj->in_room) != NULL))
   {
      for (otmp = obj->first_content; otmp; otmp = otmp_next)
      {
         otmp_next = otmp->next_content;
         if (ch && HAS_PROG(otmp->pIndexData, DROP_PROG) && otmp->count > 1)
         {
            separate_obj(otmp);
            obj_from_obj(otmp);
            if (!otmp_next)
               otmp_next = obj->first_content;
         }
         else
            obj_from_obj(otmp);
         otmp = obj_to_room(otmp, destroom, ch);
         if (ch)
         {
            oprog_drop_trigger(ch, otmp); /* mudprogs */
            if (char_died(ch))
               ch = NULL;
         }
         movedsome = TRUE;
      }
      return movedsome;
   }
   if (ch)
   {
      for (otmp = obj->first_content; otmp; otmp = otmp_next)
      {
         otmp_next = otmp->next_content;
         obj_from_obj(otmp);
         obj_to_char(otmp, ch);
         movedsome = TRUE;
      }
      return movedsome;
   }
   bug("empty_obj: could not determine a destination for vnum %d", obj->pIndexData->vnum);
   return FALSE;
}

/*
 * Improve mental state						-Thoric
 */
void better_mental_state(CHAR_DATA * ch, int mod)
{
   int c = URANGE(0, abs(mod), 20);
   int con = get_curr_con(ch);

   c += number_percent() < con ? 1 : 0;

   if (ch->mental_state < 0)
      ch->mental_state = URANGE(-100, ch->mental_state + c, 0);
   else if (ch->mental_state > 0)
      ch->mental_state = URANGE(0, ch->mental_state - c, 100);
}

/*
 * Deteriorate mental state					-Thoric
 */
void worsen_mental_state(CHAR_DATA * ch, int mod)
{
   int c = URANGE(0, abs(mod), 20);
   int con = get_curr_con(ch);

   c -= number_percent() < con ? 1 : 0;
   if (c < 1)
      return;

   /* Nuisance flag makes state worsen quicker. --Shaddai */
   if (!IS_NPC(ch) && ch->pcdata->nuisance && ch->pcdata->nuisance->flags > 2)
      c += .4 * ((ch->pcdata->nuisance->flags - 2) * ch->pcdata->nuisance->power);

   if (ch->mental_state < 0)
      ch->mental_state = URANGE(-100, ch->mental_state - c, 100);
   else if (ch->mental_state > 0)
      ch->mental_state = URANGE(-100, ch->mental_state + c, 100);
   else
      ch->mental_state -= c;
}


/*
 * Add gold to an area's economy				-Thoric
 */
void boost_economy(AREA_DATA * tarea, int gold)
{
   while (gold >= 1000000000)
   {
      ++tarea->high_economy;
      gold -= 1000000000;
   }
   tarea->low_economy += gold;
   while (tarea->low_economy >= 1000000000)
   {
      ++tarea->high_economy;
      tarea->low_economy -= 1000000000;
   }
}

/*
 * Take gold from an area's economy				-Thoric
 */
void lower_economy(AREA_DATA * tarea, int gold)
{
   while (gold >= 1000000000)
   {
      --tarea->high_economy;
      gold -= 1000000000;
   }
   tarea->low_economy -= gold;
   while (tarea->low_economy < 0)
   {
      --tarea->high_economy;
      tarea->low_economy += 1000000000;
   }
}

/*
 * Check to see if economy has at least this much gold		   -Thoric
 */
bool economy_has(AREA_DATA * tarea, int gold)
{
   int hasgold = ((tarea->high_economy > 0) ? 1 : 0) * 1000000000 + tarea->low_economy;

   if (hasgold >= gold)
      return TRUE;
   return FALSE;
}

/*
 * Used in db.c when resetting a mob into an area		    -Thoric
 * Makes sure mob doesn't get more than 10% of that area's gold,
 * and reduces area economy by the amount of gold given to the mob
 */
void economize_mobgold(CHAR_DATA * mob)
{
   int gold;
   AREA_DATA *tarea;

   /* make sure it isn't way too much */
   mob->gold = UMIN(mob->gold, 100000);
   if (!mob->in_room)
      return;
   tarea = mob->in_room->area;

   gold = ((tarea->high_economy > 0) ? 1 : 0) * 1000000000 + tarea->low_economy;
   mob->gold = URANGE(0, mob->gold, gold / 10);
   if (mob->gold)
      lower_economy(tarea, mob->gold);
}


/*
 * Add another notch on that there belt... ;)
 * Keep track of the last so many kills by vnum			-Thoric
 */
void add_kill(CHAR_DATA * ch, CHAR_DATA * mob)
{
   int x;
   sh_int vnum, track;

   if (IS_NPC(ch))
   {
      bug("add_kill: trying to add kill to npc", 0);
      return;
   }
   if (!IS_NPC(mob))
   {
      bug("add_kill: trying to add kill non-npc", 0);
      return;
   }
   vnum = mob->pIndexData->vnum;
   track = MAX_KILLTRACK;
   for (x = 0; x < track; x++)
      if (ch->pcdata->killed[x].vnum == vnum)
      {
         if (ch->pcdata->killed[x].count < 50)
            ++ch->pcdata->killed[x].count;
         return;
      }
      else if (ch->pcdata->killed[x].vnum == 0)
         break;
   memmove((char *) ch->pcdata->killed + sizeof(KILLED_DATA), ch->pcdata->killed, (track - 1) * sizeof(KILLED_DATA));
   ch->pcdata->killed[0].vnum = vnum;
   ch->pcdata->killed[0].count = 1;
   if (track < MAX_KILLTRACK)
      ch->pcdata->killed[track].vnum = 0;
}

void update_pkpower(CHAR_DATA * ch)
{
   //Boost the power if they reach a certain point
   if (ch->pcdata->pranking >= 15 && ch->pcdata->pkpower < 1)
   {
      act(AT_RED, "$n flashes with a &BBlue&R Light as power flows through $s vains.", ch, NULL, NULL, TO_CANSEE);
      act(AT_RED, "Your body twitches as a &BBlue&R Light pulsates throughout your vains.", ch, NULL, NULL, TO_CHAR);
      ch->pcdata->pkpower++;
      ch->max_hit += 75;
      ch->max_mana += 75;
      ch->hit += 75;
      ch->move += 75;
      ch->mana += 75;
      ch->perm_agi += 5;
   }
   if (ch->pcdata->pranking >= 35 && ch->pcdata->pkpower < 2)
   {
      act(AT_RED, "$n flashes with a &GGreen&R Light as power flows through $s vains.", ch, NULL, NULL, TO_CANSEE);
      act(AT_RED, "Your body twitches as a &GGreen&R Light pulsates throughout your vains.", ch, NULL, NULL, TO_CHAR);
      ch->pcdata->pkpower++;
      ch->max_hit += 100;
      ch->max_mana += 100;
      ch->hit += 100;
      ch->move += 100;
      ch->mana += 100;
      ch->perm_agi += 10;
   }
   if (ch->pcdata->pranking >= 60 && ch->pcdata->pkpower < 3)
   {
      act(AT_RED, "$n flashes with a &G&WPURE WHITE&R Light as power flows through $s vains.", ch, NULL, NULL, TO_CANSEE);
      act(AT_RED, "Your body twitches as a &G&WPURE WHITE&R Light pulsates throughout your vains.", ch, NULL, NULL, TO_CHAR);
      ch->pcdata->pkpower++;
      ch->max_hit += 150;
      ch->max_mana += 150;
      ch->hit += 150;
      ch->move += 150;
      ch->mana += 150;
      ch->perm_agi += 20;
   }

   //now take it away if they go below it
   if (ch->pcdata->pranking < 15 && ch->pcdata->pkpower == 1)
   {
      act(AT_RED, "$n flashes with a &BBlue&R Light as power flows from $s vains.", ch, NULL, NULL, TO_CANSEE);
      act(AT_RED, "Your body twitches as a &BBlue&R Light leaves your body.", ch, NULL, NULL, TO_CHAR);
      ch->pcdata->pkpower--;
      ch->max_hit -= 75;
      ch->max_mana -= 75;
      ch->perm_agi -= 5;
   }
   if (ch->pcdata->pranking < 35 && ch->pcdata->pkpower == 2)
   {
      act(AT_RED, "$n flashes with a &GGreen&R Light as power flows from $s vains.", ch, NULL, NULL, TO_CANSEE);
      act(AT_RED, "Your body twitches as a &GGreen&R Light leaves your body.", ch, NULL, NULL, TO_CHAR);
      ch->pcdata->pkpower--;
      ch->max_hit -= 100;
      ch->max_mana -= 100;
      ch->perm_agi -= 10;
   }
   if (ch->pcdata->pranking < 60 && ch->pcdata->pkpower == 3)
   {
      act(AT_RED, "$n flashes with a &G&WPURE WHITE&R Light as power flows from $s vains.", ch, NULL, NULL, TO_CANSEE);
      act(AT_RED, "Your body twitches as a &G&WPURE WHITE&R Light leaves your body.", ch, NULL, NULL, TO_CHAR);
      ch->pcdata->pkpower--;
      ch->max_hit -= 150;
      ch->max_mana -= 150;
      ch->perm_agi -= 20;
   }

   //For those who just die a lot, zap them for a few, must be over level 20
   if (ch->pcdata->pranking < -20 && ch->pcdata->pkpower >= 0)
   {
      act(AT_ORANGE, "$n flashes with a &rBLOOD RED&O as $e is punished for $s defeats.", ch, NULL, NULL, TO_CANSEE);
      act(AT_ORANGE, "Your body shakes as a &rBLOOD RED&O Light enters your defeated body.", ch, NULL, NULL, TO_CHAR);
      ch->pcdata->pkpower--;
      ch->max_hit -= 60;
      ch->max_mana -= 60;
      ch->perm_agi -= 15;
   }
   //Now just fix em
   if (ch->pcdata->pranking >= -20 && ch->pcdata->pkpower == -1)
   {
      act(AT_ORANGE, "$n flashes with a &rBLOOD RED&O Light as the curse leaves $s body.", ch, NULL, NULL, TO_CANSEE);
      act(AT_ORANGE, "Your body shakes as a &rBLOOD RED&O Light leaves your body.", ch, NULL, NULL, TO_CHAR);
      ch->pcdata->pkpower++;
      ch->max_hit += 60;
      ch->max_mana += 60;
      ch->perm_agi += 15;
      ch->hit += 60;
      ch->mana += 60;
   }
}

//Update the pranking (pkill Ranking) for a kill
void update_pranking(CHAR_DATA * ch, CHAR_DATA * victim)
{
   PKILLED_DATA *pkl;
   int cnt = 0;
   int camt, vamt, diff;

   camt = vamt = 0;
   
   //For now I don't want to add any pranking
   return;

   if (IN_ARENA(ch) || IN_ARENA(victim))
      return;
   camt = 1;
   vamt = 1;
   //Tack on an extra point for every 5 points of power difference
   diff = victim->pcdata->pranking - ch->pcdata->pranking;
   for (cnt = 5; cnt <= diff; cnt += 5)
   {
      camt++;
      vamt++;
   }
   cnt = 0;
   for (pkl = ch->pcdata->first_pkilled; pkl; pkl = pkl->next)
   {
      if (!str_cmp(pkl->name, victim->name))
         cnt++;
   }
   if (cnt > 4)
      camt = 0;

   if (diff < -20)
      camt = 0;

   ch->pcdata->pranking += camt;
   victim->pcdata->pranking -= vamt;

   if (victim->pcdata->pranking < -30)
      victim->pcdata->pranking = -30;

   update_pkpower(ch);
   update_pkpower(victim);
}

//Add the name of the victim to the pkill list on the player 
void add_pkill(CHAR_DATA * ch, CHAR_DATA * victim)
{
   PKILLED_DATA *pkl;

   if (IS_NPC(victim))
   {
      bug("add_pkill: %s is trying to add %s to the pkill listing", ch->name, victim->name);
      return;
   }
   if (IS_NPC(ch))
   {
      bug("add_pkill: %s is a NPC trying to add a PC to its listing", ch->name);
      return;
   }
   if (ch->pcdata->pkilled < MAX_PKILLTRACK)
   {
      CREATE(pkl, PKILLED_DATA, 1);
      pkl->name = STRALLOC(victim->name);
      LINK(pkl, ch->pcdata->first_pkilled, ch->pcdata->last_pkilled, next, prev);
      ch->pcdata->pkilled++;
   }
   else
   {
      pkl = ch->pcdata->first_pkilled;
      UNLINK(pkl, ch->pcdata->first_pkilled, ch->pcdata->last_pkilled, next, prev);
      STRFREE(pkl->name);
      DISPOSE(pkl);

      CREATE(pkl, PKILLED_DATA, 1);
      pkl->name = STRALLOC(victim->name);
      LINK(pkl, ch->pcdata->first_pkilled, ch->pcdata->last_pkilled, next, prev);
   }
}

/*
 * Return how many times this player has killed this mob	-Thoric
 * Only keeps track of so many (MAX_KILLTRACK), and keeps track by vnum
 */
int times_killed(CHAR_DATA * ch, CHAR_DATA * mob)
{
   int x;
   sh_int vnum, track;

   if (IS_NPC(ch))
   {
      bug("times_killed: ch is not a player", 0);
      return 0;
   }
   if (!IS_NPC(mob))
   {
      bug("add_kill: mob is not a mobile", 0);
      return 0;
   }

   vnum = mob->pIndexData->vnum;
   track = MAX_KILLTRACK;
   for (x = 0; x < track; x++)
      if (ch->pcdata->killed[x].vnum == vnum)
         return ch->pcdata->killed[x].count;
      else if (ch->pcdata->killed[x].vnum == 0)
         break;
   return 0;
}

/*
 * returns area with name matching input string
 * Last Modified : July 21, 1997
 * Fireblade
 */
AREA_DATA *get_area(char *name)
{
   AREA_DATA *pArea;

   if (!name)
   {
      bug("get_area: NULL input string.");
      return NULL;
   }

   for (pArea = first_area; pArea; pArea = pArea->next)
   {
      if (nifty_is_name(name, pArea->name))
         break;
   }

   if (!pArea)
   {
      for (pArea = first_build; pArea; pArea = pArea->next)
      {
         if (nifty_is_name(name, pArea->name))
            break;
      }
   }

   return pArea;
}

/* Hometown Ivan Code -- Xerves */
int get_hometown(char *argument)
{
   int i = 0;

   while (i < sysdata.max_kingdom)
   {
      if (!str_cmp(argument, kingdom_table[i]->name))
         return i;
      i++;
   }
   return -1;
}