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

limits.c				Level advancement, stat gains, 
					etc.

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

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

#include "structures.h"
#include "mudlimits.h"
#include "utils.h"
#include "magic.h"
#include "comm.h"
#include "db.h"
#include "handler.h"
#include "bard.h"
#include "nature.h"
#include "fight.h"
#include "affect.h"
#include "lists.h"
#include "global.h"

extern int exp_table[NUM_CLASSES][MAX_LEVELS];

extern void check_autowiz(chdata *ch);

/* When age < 15 return the value p0 */
/* When age in 15..29 calculate the line between p1 & p2 */
/* When age in 30..44 calculate the line between p2 & p3 */
/* When age in 45..59 calculate the line between p3 & p4 */
/* When age in 60..79 calculate the line between p4 & p5 */
/* When age >= 80 return the value p6 */
int	graf(int age, int p0, int p1, int p2, int p3, int p4, int p5, int p6)
{
   if (age < 15)
      return(p0);						/* < 15   */
   else if (age <= 29)
      return (int) (p1 + (((age - 15) * (p2 - p1)) / 15));	/* 15..29 */
   else if (age <= 44)
      return (int) (p2 + (((age - 30) * (p3 - p2)) / 15));	/* 30..44 */
   else if (age <= 59)
      return (int) (p3 + (((age - 45) * (p4 - p3)) / 15));	/* 45..59 */
   else if (age <= 79)
      return (int) (p4 + (((age - 60) * (p5 - p4)) / 20));	/* 60..79 */
   else
      return(p6);						/* >= 80 */
}

/* manapoint gain pr. game hour */
int	mana_gain(chdata *ch)
{
   int	gain;

   if (IS_NPC(ch)) 
      gain = GET_LEVEL(ch) + ch->specials.mana_regen;
   else 
   {
      gain = graf(age(ch).year, 4, 8, 12, 16, 12, 10, 8);

      /* TEMP to see how it works RoA */
      gain += gain / 3;

      /* Race calculations  James Rhone */
      if (GET_CLASS(ch) == RACE_ELF)  /* elves regen quicker */
	 gain += (gain >> 2); /* Divide by 4 */

      /* Skill/Spell calculations */

      /* Position calculations    */
      switch (GET_POS(ch)) {
      case POS_SLEEPING:
	 gain <<= 1;
	 break;
      case POS_RESTING:
	 gain += (gain >> 1);  /* Divide by 2 */
	 break;
      case POS_SITTING:
	 gain += (gain >> 2); /* Divide by 4 */
	 break;
      }

      // add rangers to spellcasters  3/31/98 -jtrhone
      if (IS_MAGE(ch) || IS_CLERIC(ch) || IS_MADEPT(ch) || IS_DRUID(ch) ||
          IS_RANGER(ch))
	 gain <<= 1;
   }

   gain += ch->specials.mana_regen;

   // added ranger meditate  3/27/98 -jtrhone
   if (IS_RANGER(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	affected_by_spell(ch, SKILL_MEDITATE))
     gain = gain + (3 * gain/4);  /* 175 percent */

   if (IS_MONK(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	affected_by_spell(ch, SKILL_TRANCE))
     gain *= 2;  /* 200 percent */
   else
   if (IS_MONK(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	affected_by_spell(ch, SKILL_WA))
     gain = gain + (3 * gain/4);  /* 175 percent */
   else
   if (IS_MONK(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	affected_by_spell(ch, SKILL_MOK))
     gain += (gain/2); /* 150 percent */
   else
   if (IS_MONK(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	affected_by_spell(ch, SKILL_OM))
     gain += (gain/4); /* 125 percent */

   if (IS_AFFECTED(ch, AFF_POISON))
      gain >>= 2;

   if (IS_PC(ch))
     if ((GET_COND(ch, FULL) == 0) || (GET_COND(ch, THIRST) == 0))
        gain >>= 2;

   return (gain);
}


/* Hitpoint gain pr. game hour */
int	hit_gain(chdata *ch)
{
   int	gain;

   if (IS_NPC(ch))
      gain = GET_LEVEL(ch) + ch->specials.hit_regen;
   else 
   {
      gain = graf(age(ch).year, 8, 12, 20, 32, 16, 10, 4);
      /* TEMP to see how it works RoA */
      gain += gain / 2;

      /* Class/Level calculations */

      /* Race calculations  James Rhone */
      if (GET_CLASS(ch) == RACE_DWARF)  /* DWARFs regen quicker */
	 gain += (gain >> 2); /* Divide by 8 */

      /* Skill/Spell calculations */

      /* Position calculations    */

      switch (GET_POS(ch)) {
      case POS_SLEEPING:
	 gain += (gain >> 1); /* Divide by 2 */
	 break;
      case POS_RESTING:
	 gain += (gain >> 2);  /* Divide by 4 */
	 break;
      case POS_SITTING:
	 gain += (gain >> 3); /* Divide by 8 */
	 break;
      }

      if (IS_MAGE(ch) || IS_CLERIC(ch))
	gain >>= 1;
   }

   gain += ch->specials.hit_regen;

   // added ranger meditate  3/27/98 -jtrhone
   if (IS_RANGER(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	affected_by_spell(ch, SKILL_MEDITATE))
     gain = gain + (3 * gain/4);  /* 175 percent */

   if (IS_MONK(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	affected_by_spell(ch, SKILL_TRANCE))
     gain *= 2;  /* 200 percent */
   else
   if (IS_MONK(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	affected_by_spell(ch, SKILL_WA))
     gain = gain + (3 * gain/4);  /* 175 percent */
   else
   if (IS_MONK(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	GET_SKILL(ch, SKILL_MOK) > number(1, 101))
     gain+=(gain/2);  /* 150 percent */
   else
   if (IS_MONK(ch) && !IN_NOWHERE(ch) && ROOM_FLAGGED(ch->in_room, PEACEFUL) &&
	GET_SKILL(ch, SKILL_OM) > number(1, 101))
     gain+=(gain/4); /* 125 percent */

   if (IS_AFFECTED(ch, AFF_POISON))
      gain >>= 2;

   if (IS_PC(ch))
    if ((GET_COND(ch, FULL) == 0) || (GET_COND(ch, THIRST) == 0))
       gain >>= 2;

   return (gain);
}

/* move gain pr. game hour */
int	move_gain(chdata *ch)
{
   int	gain;

   if (IS_NPC(ch)) 
      gain = GET_LEVEL(ch) + ch->specials.move_regen;
   else 
   {
      gain = graf(age(ch).year, 16, 20, 24, 20, 16, 12, 10);
      /* TEMP to see how it works RoA */
      gain += gain / 2;

      /* Class/Level calculations */
      /* Race calculations  James Rhone */
      if (GET_CLASS(ch) == RACE_HALF_ELF ||
          GET_CLASS(ch) == RACE_PIXIE ||
          GET_CLASS(ch) == RACE_NIXIE)  /* half_elves regen quicker */
	 gain += (gain >> 3); /* Divide by 8 */

      gain += (GET_SKILL(ch, SKILL_WAR_ENDURANCE) / 10);

      /* Position calculations    */
      switch (GET_POS(ch)) {
      case POS_SLEEPING:
	 gain += (gain >> 1); /* Divide by 2 */
	 break;
      case POS_RESTING:
	 gain += (gain >> 2);  /* Divide by 4 */
	 break;
      case POS_SITTING:
	 gain += (gain >> 3); /* Divide by 8 */
	 break;
      }
   }

   gain += ch->specials.move_regen;

   if (IS_AFFECTED(ch, AFF_POISON))
      gain >>= 2;

   if (IS_PC(ch))
    if ((GET_COND(ch, FULL) == 0) || (GET_COND(ch, THIRST) == 0))
       gain >>= 2;

   return (gain);
}

// return this class's prime stat1
int prime_stat1(chdata *ch)
{
  if (IS_NPC(ch)) return (13);

  switch (GET_CLASS(ch)) {
    case CLASS_MAGE:
      return GET_INT(ch);
      break;
    case CLASS_CLERIC:
      return GET_WIS(ch);
      break;
    case CLASS_THIEF:
      return GET_DEX(ch);
      break;
    case CLASS_WARRIOR:
      return GET_STR(ch);
      break;
    case CLASS_SHAMAN:
      return GET_INT(ch);
      break;
    case CLASS_RANGER:
      return GET_STR(ch);
      break;
    case CLASS_BARD:
      return GET_INT(ch);
      break;
    case CLASS_WARLOCK:
      return GET_INT(ch);
      break;
    case CLASS_MONK:
      return GET_STR(ch);
      break;
    default: 
      return (13);
      break;
  };
}

// return this class's prime stat2
int prime_stat2(chdata *ch)
{
  if (IS_NPC(ch)) return (13);

  switch (GET_CLASS(ch)) {
    case CLASS_MAGE:
      return GET_DEX(ch);
      break;
    case CLASS_CLERIC:
      return GET_CON(ch);
      break;
    case CLASS_THIEF:
      return GET_INT(ch);
      break;
    case CLASS_WARRIOR:
      return GET_CON(ch);
      break;
    case CLASS_SHAMAN:
      return GET_CON(ch);
      break;
    case CLASS_RANGER:
      return GET_CON(ch);
      break;
    case CLASS_BARD:
      return GET_DEX(ch);
      break;
    case CLASS_WARLOCK:
      return GET_CON(ch);
      break;
    case CLASS_MONK:
      return GET_CON(ch);
      break;
    default: 
      return (13);
      break;
  };
}

// Gain various things per level, hit/mana/move/pracs -RoA
void	advance_level(chdata *ch)
{
   int i;
   int	add_hit = 0;
   int	add_mana = 0;
   int  add_move = 0;
   int num, size, add, stat;
   dsdata *jt;
   static struct die_roll_type {
     byte num_hit;  byte size_hit;  byte hit_add;
     byte num_mana; byte size_mana; byte mana_add;
     byte num_move; byte size_move; byte move_add;
   } die_rolls[NUM_CLASSES + 1] =
   {//   Hit        Mana       Move
     { 0, 0,  0,  0, 0, 0,   0, 0, 0}, // undefined
     { 2, 4, -1,  2, 8, 2,   0, 0, 0}, // mage
     { 2, 6,  0,  2, 7, 2,   0, 0, 0}, // cleric
     { 2, 5,  0,  0, 0, 0,   1, 2, 1}, // thief
     { 3, 5,  2,  0, 0, 0,   1, 2, 1}, // warrior
     { 2, 6,  1,  2, 4, 0,   1, 2, 0}, // shaman
     { 3, 4,  1,  2, 4, 1,   1, 4, 1}, // ranger(now gain mana 3/31/98 -jtrhone)
     { 2, 5,  1,  2, 5, 1,   0, 0, 0}, // bard
     { 2, 4,  0,  2, 7, 2,   0, 0, 0}, // warlock
     { 2, 5,  1,  2, 5, 1,   1, 4, 1}, // monshai
     { 2, 4, -1,  2, 8, 2,   0, 0, 0}, // madept
     { 2, 6,  0,  2, 7, 2,   2, 2, 0}  // druid
   };

   struct race_aff_type {
     byte hit;  byte mana;  byte move;
   } race_affs[NUM_RACES + 1] =
   {
    { 0,  0,  0},  // undefined
    { 0,  0,  0},  // human
    {-1,  1,  0},  // elven
    {-1,  0,  0},  // halfelven
    { 1, -1,  0},  // orc
    { 2, -2,  0},  // ogre
    {-1,  2,  0},  // drow
    { 1, -2,  0},  // dwarf
    {-1,  1,  1},  // pixie
    {-1,  1,  1},  // nixie
    { 2, -1,  1}   // drakyn
   };
   
   // first roll hit pt gain dice
   num  = die_rolls[(int)GET_CLASS(ch)].num_hit;
   size = die_rolls[(int)GET_CLASS(ch)].size_hit;
   add  = die_rolls[(int)GET_CLASS(ch)].hit_add;
   if (num && size)
     add_hit = dice(num, size) + add;
   else
     add_hit = add;

   // roll mana gain dice
   num  = die_rolls[(int)GET_CLASS(ch)].num_mana;
   size = die_rolls[(int)GET_CLASS(ch)].size_mana;
   add  = die_rolls[(int)GET_CLASS(ch)].mana_add;
   if (num && size)
     add_mana = dice(num, size) + add;
   else
     add_mana = add;

   // roll move gain dice
   num  = die_rolls[(int)GET_CLASS(ch)].num_move;
   size = die_rolls[(int)GET_CLASS(ch)].size_move;
   add  = die_rolls[(int)GET_CLASS(ch)].move_add;
   if (num && size)
     add_move = dice(num, size) + add;
   else
     add_move = add;

   // ok, now add race apply's
   add_hit += race_affs[(int)GET_RACE(ch)].hit;
   add_mana += race_affs[(int)GET_RACE(ch)].mana;
   add_move += race_affs[(int)GET_RACE(ch)].move;

   // con affects hit points
   stat = GET_CON(ch);
   add_hit += (stat - 13);

   // better of int/wis affects manma
   stat = MAX(GET_INT(ch), GET_WIS(ch));
   add_mana += (stat - 13) / 2;

   // better of str/dex affects movement
   stat = MAX(GET_DEX(ch), GET_STR(ch));
   add_move += (stat - 13) / 2;

   // change how ENDURANCE affects move gain per level  1/12/98  -jtrhone
   // warriors utilize endurance more...
   if (IS_NAT_WARRIOR(ch))
     i = 10;
   else
     i = 15;

   // add move based on endurance skill
   add_move += (GET_SKILL(ch, SKILL_ENDURANCE) / i);

   switch (GET_CLASS(ch)) 
   {
     case CLASS_MONK :
	/* every 5th level gain 1 pt of each if monk */
        if (!(GET_LEVEL(ch) % 5))
        {
	  GET_DAMROLL(ch)++;
	  GET_HITROLL(ch)++;
	  send_to_char("%BYour accuracy and damage has increased.%0\n\r",ch);
        }
	/* monks base AC drops 2 points per level */
        GET_AC(ch) -= 2;
        break;
      default: break;
    }

   GET_MAX_HIT(ch)  += MAX(1, add_hit);
   GET_MAX_MANA(ch) += MAX(0, add_mana);
   GET_MAX_MOVE(ch) += MAX(0, add_move);

   // tell them what they've won, bob  5/9/98 -jtrhone
   sprintf(buf, "%%BYou have gained %d hit, %d mana, and %d movement.%%0\n\r", 
           MAX(1, add_hit), MAX(0, add_mana), MAX(0, add_move));
   S2C();

   stat = GET_WIS(ch) - 13;
   SPELLS_TO_LEARN(ch) += MAX(1, stat);   // get at least 1 prac/level
   SPELLS_TO_LEARN(ch)  = MAX(0, MIN(SPELLS_TO_LEARN(ch), 100));

   // affect saving throws here...
   // race affects first
   if (IS_OGRE(ch) || IS_ORC(ch) || IS_HALF_ELF(ch))
     if (number(0,1) && number(0, 1)) // 25%
     {
       SAVING_THROW(ch, SV_HEAT) += 1;
       SAVING_THROW(ch, SV_COLD) += 1;
       send_to_char("%BYou have gained +1 resistance to heat and cold.%0\n\r", ch);
     }

   if (IS_DWARF(ch) || IS_DROW(ch) || IS_ELF(ch))
     if (number(0,1) && number(0, 1)) // 25%
     {
       SAVING_THROW(ch, SV_MAGIC) += 1;
       send_to_char("%BYou have gained +1 resistance to magic.%0\n\r", ch);
     }

   if (IS_DRAGON(ch))
     if (number(0,1) && number(0, 1)) // 25%
     {
       SAVING_THROW(ch, SV_BREATH) += 1;
       send_to_char("%BYou have gained +1 resistance to breath attacks.%0\n\r", ch);
     }

   if (IS_IMMORTAL(ch))
      for (i = 0; i < 3; i++)
	 GET_COND(ch, i) = (char) -1;

   save_char(ch, NOWHERE);

   /* do general mortlog here */
   if (!INCOG(ch))
   {
     for (jt = descriptor_list; jt; jt = jt->next) 
      if (D_CHECK(jt) && jt->character != ch &&
          PRF_FLAGGED(jt->character,PRF_MORTLOG) && SEND_OK(jt->character)) 
      {
	if (GET_LEVEL(ch) == 1)
	  sprintf(buf, "[ %%BEveryone welcome %s, a new adventurer!%%0 ]\n\r", GET_NAME(ch));
	else
          sprintf(buf, "[ %%B%s advanced to level %d.%%0 ]\n\r", GET_NAME(ch), GET_LEVEL(ch));
        send_to_char(buf, jt->character);
      }
   } /*if not incognito*/
   else 
   if (INCOG(ch)) 
   {
     for (jt = descriptor_list; jt; jt = jt->next) 
      if (D_CHECK(jt) && jt->character != ch && PRF_FLAGGED(jt->character,PRF_MORTLOG) && SEND_OK(jt->character)) 
      {
        sprintf(buf, "[ %%B%s has attained a higher level.%%0 ]\n\r", GET_NAME(ch));
        send_to_char(buf, jt->character);
      }
   } /*if is incognito*/

   sprintf(buf, "%s advanced to level %d", GET_NAME(ch), GET_LEVEL(ch));
   mudlog(buf, BRF, MAX(LEV_IMM, GET_INVIS_LEV(ch)), TRUE);
}

void	set_title(chdata *ch)
{
   if (GET_TITLE(ch))
      RECREATE(GET_TITLE(ch), char, MAX_POOFIN_LENGTH +1);
   else
      CREATE(GET_TITLE(ch), char, MAX_POOFIN_LENGTH +1);

   strcpy(GET_TITLE(ch), clarray[(int)GET_CLASS(ch)].default_title);
}

#define EXP_THIS_LEVEL(ch) \
		(exp_table[(int)GET_CLASS(ch) - 1][(int)GET_LEVEL(ch)+1] - \
		 exp_table[(int)GET_CLASS(ch) - 1][(int)GET_LEVEL(ch)])

#define GAIN_PERC(ch) (20 + ((int)GET_INT((ch)) - 13))

#define MAX_GAIN(ch) ((int)((float)EXP_THIS_LEVEL(ch) * (GAIN_PERC(ch)/100.0)))
 /* PCs should gain exp, not mobs... */
int	gain_exp(chdata *ch, int gain)
{
   int	i;
   extern int num_remorts(chdata *ch);

   /* why do mobs get exp anyways? RoA*/
   if (IS_NPC(ch)) return 0;

   if (GET_LEVEL(ch) > 0 && !IS_IMMORTAL(ch))
   {
      if (gain > 0) 
      {
         gain = MIN(gain, number(234543, 498547));
         gain = MIN(MAX_GAIN(ch), gain);

	 // if they have remorted, adjust exp accordingly
	 if ((i = num_remorts(ch)))
	 {
	   i *= 2;
	   gain /= i;
	 }

	 GET_EXP(ch) += gain;

	 for (i = 0; exp_table[GET_CLASS(ch)-1][i] <= GET_EXP(ch); i++) 
	 {
           if (i >= LEV_IMM)
           {
    		 send_to_char("You have attained enough experience to immort.\n\r",ch);
                 send_to_char("See an immortal about what to do next.\n\r",ch);
                 GET_EXP(ch) = exp_table[GET_CLASS(ch)-1][LEV_IMM] - 1;
           } 
	   else
           if (i > 1 && IS_NAT_MADEPT(ch) && !PRF2_FLAGGED(ch, PRF2_CHOSEN))
           {
             // must choose before going on to level 2...
             send_to_char("%BYou must choose thy path before advancing any further.%0\n\r",ch);
             send_to_char("%BType %5madept%0%B to chose...%0\n\r",ch);
             GET_EXP(ch) = exp_table[CLASS_MADEPT][2] - 1;
           }
           else
	   if (i > GET_LEVEL(ch)) 
	   {
	      send_to_char("%B%6You rise a level!%0\n\r", ch);
	      GET_LEVEL(ch) = i;
	      advance_level(ch);
	      check_autowiz(ch);
	   }
	 }
      }
      else
      if (gain < 0) 
      {
	 gain = MAX(-maxdeathexploss, gain);  /* Never loose more than 1/2 mil RoA*/
	 GET_EXP(ch) += gain;
	 GET_EXP(ch) = MAX(0, GET_EXP(ch));
      }
   }
  return gain;
}

void	gain_exp_regardless(chdata *ch, int gain)
{
   int	i;

   if (IS_PC(ch)) 
   {
      if (gain > 0) 
      {
	 GET_EXP(ch) += gain;
	 for (i = 0; (i <= LEV_IMPL) && 
		     (exp_table[GET_CLASS(ch)-1][i] <= GET_EXP(ch)); i++) 
	 {
	    if (i > GET_LEVEL(ch)) 
	    {
	       send_to_char("You rise a level!\n\r", ch);
	       GET_LEVEL(ch) = i;
	       advance_level(ch);
	       check_autowiz(ch);
	    }
	 }
      }
      if (gain < 0)
	 GET_EXP(ch) += gain;
      GET_EXP(ch) = MAX(0, GET_EXP(ch));
   }
}

void	gain_condition(chdata *ch, int condition, int value)
{
   BOOL intoxicated;
  
   if (IS_NPC(ch)) return;

   if (GET_COND(ch, condition) == -1) /* No change */
      return;

   intoxicated = (GET_COND(ch, DRUNK) > 0);

   GET_COND(ch, condition)  += value;

   GET_COND(ch, condition) = MAX(0, GET_COND(ch, condition));
   GET_COND(ch, condition) = MIN(24, GET_COND(ch, condition));

   if (GET_COND(ch, condition) || PLR_FLAGGED(ch, PLR_WRITING))
      return;

   switch (condition) {
   case FULL :
    if (!PLR_FLAGGED(ch, PLR_BUILDING))
      send_to_char("You are hungry.\n\r", ch);
      return;
   case THIRST :
    if (!PLR_FLAGGED(ch, PLR_BUILDING))
      send_to_char("You are thirsty.\n\r", ch);
      return;
   case DRUNK :
    if (!PLR_FLAGGED(ch, PLR_BUILDING))
      if (intoxicated)
	 send_to_char("You are now sober.\n\r", ch);
      return;
   default :
      break;
   }
}

int check_idling(chdata *ch)
{
   extern void save_char_objects(chdata *ch);
   extern void force_save(chdata *ch);

   if (++(ch->specials.timer) > 8)
      if (ch->specials.was_in_room == NOWHERE && ch->in_room != NOWHERE) 
      {
	 ch->specials.was_in_room = ch->in_room;
	 if (FIGHTING(ch)) 
	 {
	    if (FIGHTING(FIGHTING(ch)))
	      stop_fighting(FIGHTING(ch));
	    stop_fighting(ch);
	 }
	 act("$n disappears into the void.", TRUE, ch, 0, 0, TO_ROOM);
	 send_to_char("You have been idle, and are pulled into a void.\n\r", ch);
	 save_char(ch, NOWHERE);
	 save_char_objects(ch);
	 char_from_room(ch);
	 char_to_room(ch, 1);
	 return CHAR_OK;  // char still exists, return CHAR_OK
      } 
      else 
      if (ch->specials.timer > 48) 
      {
	 if (ch->in_room != NOWHERE) 
	    char_from_room(ch);
	 char_to_room(ch, 3);
	 if (ch->desc)
	    close_socket(ch->desc);
	 ch->desc = NULL;
	 force_save(ch);
	 eject_char(ch);
	 return CHAR_DIED;  // char was extracted! -roa
      }
  return CHAR_OK;  // normal idle check, not extracted
}

/* Update both PC's & NPC's and objects*/
void	point_update( void )
{
   void die(chdata *ch, BOOL akill);
   void	update_char_objects( chdata *ch ); /* handler.c */
   void	extract_obj(obdata *obj); /* handler.c */
   chdata *i, *next_dude;
   obdata *j, *next_thing, *jj, *next_thing2;
   extern char *song_names_cap[];
   extern struct song_type song_types[];
   struct room_affect_type *raf, *nxtraf;
   int cnt;
   int znums[NUM_ZONES];

   for (cnt = 0; cnt < NUM_ZONES; cnt++)
     znums[cnt] = 0;

   /* characters */
   for (i = character_list; i; i = next_dude) 
   {
      next_dude = i->next;

      if (IS_PC(i) && !INVALID_ROOM(i->in_room) && REAL_ZONE(world[i->in_room].zone))
	znums[world[i->in_room].zone]++;

      gain_condition(i, FULL, -1);
      gain_condition(i, DRUNK, -1);

      // if real hot, take some more wawa...1 sip for every 5 degrees above 80  -roa
      cnt = world[i->in_room].zone;
      if (ZONE_TEMP(cnt) > 80)
      {
        cnt = (ZONE_TEMP(cnt) - 80) / 5;
        gain_condition(i, THIRST, -cnt);
      }
      else
        gain_condition(i, THIRST, -1);
 
      if (GET_POS(i) >= POS_STUNNED) 
      {
	 GET_HIT(i)  = MIN(GET_HIT(i)  + hit_gain(i),  GET_MAX_HIT(i));
	 GET_MANA(i) = MIN(GET_MANA(i) + mana_gain(i), GET_MAX_MANA(i));
	 GET_MOVE(i) = MIN(GET_MOVE(i) + move_gain(i), GET_MAX_MOVE(i));
	 if (IS_AFFECTED(i, AFF_POISON))
	    if (damage(i, i, 2, SPELL_POISON, TRUE) == CHAR_DIED)
	      continue;
	 if (GET_POS(i) == POS_STUNNED)
	    update_pos(i);
      } 
      else 
      if (GET_POS(i) == POS_INCAP)
      {
	if (damage(i, i, 1, TYPE_SUFFERING, TRUE) == CHAR_DIED)
	  continue;
      }
      else 
      if ((GET_POS(i) == POS_MORTALLYW))
      {
	if (damage(i, i, 2, TYPE_SUFFERING, TRUE) == CHAR_DIED)
	  continue;
      }
      else
      if (GET_POS(i) == POS_DEAD)
      {
        die(i, FALSE);
      	continue;
      }

      if (IS_PC(i)) 
      {
	 /* check rooms and char affects for floating/sinking */
	 if (float_sink_char(i) == CHAR_DIED)
	   continue;

	 /* update all objects char has inv/eq */
	 update_char_objects(i);

	 // go BACK to the for loop if char was extracted -roa
	 if (GET_LEVEL(i) < LEV_AIMP && check_idling(i) == CHAR_DIED)
	   continue;

        /* lets look at songs and such for bards, RoA */
	 if (SINGING(i))
	 {
	   if (!(SONG_TIME(i)--) || (GET_MANA(i) < song_types[SINGING(i)].continuing_mana))
	   {
	     sprintf(buf, "You finish singing %%6%%B%s%%0.\n\r", song_names_cap[SINGING(i)]);
	     send_to_char(buf, i);
	     sprintf(buf, "$n finishes singing %%6%%B%s%%0.", song_names_cap[SINGING(i)]);
  	     act(buf, TRUE, i, 0, 0, TO_ROOM);
	     remove_song_from_world(i, SINGING(i));
	     SINGING(i) = 0;
	     SONG_TIME(i) = 0;
	   }
	   else
	   {
	     GET_MANA(i) -= song_types[SINGING(i)].continuing_mana;
	     SONG_TIME(i)--;
	   }
	 }
	 /* now look at if they is playin mon :P */
	 if (PLAYING(i))
	 {
	   if (!(PLAY_TIME(i)--) || (GET_MANA(i) < song_types[PLAYING(i)].continuing_mana))
	   {
	     sprintf(buf, "You finish playing %%6%%B%s%%0.\n\r", song_names_cap[PLAYING(i)]);
	     send_to_char(buf, i);
	     sprintf(buf, "$n finishes playing %%6%%B%s%%0.", song_names_cap[SINGING(i)]);
  	     act(buf, TRUE, i, 0, 0, TO_ROOM);
	     remove_song_from_world(i, PLAYING(i));
	     PLAYING(i) = 0;
	     PLAY_TIME(i) = 0;
	   }
	   else
	   {
	     GET_MANA(i) -= song_types[PLAYING(i)].continuing_mana;
	     PLAY_TIME(i)--;
	   }
	 }
      }
   } /* for */

   for (cnt = 0; cnt < NUM_ZONES; cnt++)
     if (znums[cnt] > zone_table[cnt].max_pcs)
       zone_table[cnt].max_pcs = znums[cnt];

   /* objects */
   for (j = object_list; j; j = next_thing) 
   {
      next_thing = j->next; 

      if (ITEM_TYPE(j) == ITEM_GATE)
      {
	 if (j->timer > 0)
	    j->timer--;

	 if (!j->timer) 
         {
	    if (!INVALID_ROOM(j->in_room) && world[j->in_room].people)
            {
	       act("$p winks out of existence.", TRUE, world[j->in_room].people, j, 0, TO_ROOM);
	       act("$p winks out of existence.", TRUE, world[j->in_room].people, j, 0, TO_CHAR);
	    }
	    extract_obj(j);
         }
	 continue;
      }

      // add ranger markings timeout... 3/27/98 -jtrhone
      if (GET_OBJ_VNUM(j) == 190)
      {
	 if (j->timer > 0)
	    j->timer--;

	 if (!j->timer) 
         {
	    if (!INVALID_ROOM(j->in_room) && world[j->in_room].people)
            {
	       act("$p slowly fades away.", TRUE, world[j->in_room].people, j, 0, TO_ROOM);
	       act("$p slowly fades away.", TRUE, world[j->in_room].people, j, 0, TO_CHAR);
	    }
	    extract_obj(j);
         }
	 continue;
      }

      if (IS_CORPSE(j)) 
      {
	 if (j->timer > 0)
	    j->timer--;

	 if (!j->timer) 
         {
	    if (j->carried_by)
	       act("$p decays in your hands.", FALSE, j->carried_by, j, 0, TO_CHAR);
	    else 
            if (!INVALID_ROOM(j->in_room) && world[j->in_room].people) 
            {
	       act("A quivering hoard of maggots consumes $p.",
	           TRUE, world[j->in_room].people, j, 0, TO_ROOM);
	       act("A quivering hoard of maggots consumes $p.",
	           TRUE, world[j->in_room].people, j, 0, TO_CHAR);
	    }

	    for (jj = j->contains; jj; jj = next_thing2) 
            {
	       next_thing2 = jj->next_content; /* Next in inventory */
	       obj_from_obj(jj);

	       if (j->in_obj)
		  obj_to_obj(jj, j->in_obj);
	       else if (j->carried_by)
		  float_sink_object(jj, j->carried_by->in_room);
	       else if (!INVALID_ROOM(j->in_room))
		  float_sink_object(jj, j->in_room);
	       else
		  log("SYSERR: object in NOWHERE in POINT_UPDATE");
	    }
	    extract_obj(j);
	    continue;
	 }
      }
   }  // end of object list updates


  // lets do the room updates now
  for (cnt = 0; cnt < top_of_world; cnt++)
    if (world[cnt].room_affects)
      for (raf = world[cnt].room_affects; raf; raf = nxtraf)
      {
	nxtraf = raf->next;
	if (raf->duration > 0)
	  raf->duration--;
	if (!raf->duration)
	  spell_affect_from_room(raf->spell, cnt);
      }
}