/
Archipelago/
Archipelago/doc/
Archipelago/lib/misc/
Archipelago/lib/plrobjs/
Archipelago/lib/plrobjs/P-T/
Archipelago/lib/world/mob/
Archipelago/lib/world/obj/
Archipelago/lib/world/shp/
Archipelago/lib/world/wld/
Archipelago/lib/world/zon/
Archipelago/slave/
/* ************************************************************************
*   File: limits.c                                      Part of CircleMUD *
*  Usage: limits & gain funcs for HMV, exp, hunger/thirst, idle time      *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Copyright (C) 1993 by the Trustees of the Johns Hopkins University     *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */
/* Archipelago changes by Alastair J. Neil Copyright (C) 1993, 94, 95, 96 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include "structs.h"
#include "limits.h"
#include "utils.h"
#include "spells.h"
#include "comm.h"
#include "db.h"
#include "handler.h"

extern struct char_data *character_list;
extern struct obj_data *object_list;
extern struct room_data *world;
extern struct weather_data weather_info;
extern struct time_info_data time_info;	/* the infomation about the time   */
void    unhitch(struct char_data *ch, struct obj_data *cart, struct char_data *vict, char quiet);
void    rem_healing_bon(struct char_data *i);
void    poison_vict(struct char_data *i);
void    gain_social_standing(struct char_data *ch, struct char_data *vict,int mode);
/* 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 */
}
int *ilev,il;


/* The hit_limit, mana_limit, and move_limit functions are gone.  They
   added an unnecessary level of complexity to the internal structure,
   weren't particularly useful, and led to some annoying bugs.  From the
   players' point of view, the only difference the removal of these
   functions will make is that a character's age will now only affect
   the HMV gain per tick, and _not_ the HMV maximums.
*/


void assign_levels()
{
ilev = &levels_table[0];
*ilev = 0;
ilev++;
for(il=1;il<=5;il++) {
     *ilev= (1 << (il-1))*750;
     ilev++;}
for(il=6;il<=25;il++){
     *ilev = 4000*((il-4)*(il-4)) + 9000;
     ilev++;}
for(il=26;il<=250;il++){
     *ilev = 7813*((il-10)*(il-10));
     ilev++;}
}


int	hit_gain(struct char_data *ch)
/* Hitpoint gain pr. game hour */
{
  int	gain;
  struct affected_type *aff;
  
  if (IS_NPC(ch)) {
      gain = GET_LEVEL(ch);
      /* Neat and fast */
   } else {

      gain = graf(age(ch).year, 8, 12, 20, 32, 16, 10, 4);

      /* Class/Level calculations */

      /* Skill/Spell calculations */

      /* Position calculations    */
      gain += (GET_CON(ch) - GET_RAW_CON(ch));
      
      switch (GET_POS(ch)) {
      case POSITION_SLEEPING:
	 gain += (gain/2); /* Divide by 2 */
	 break;
      case POSITION_RESTING:
	 gain += (gain/4);  /* Divide by 4 */
	 break;
      case POSITION_SITTING:
	 gain += (gain/8); /* Divide by 8 */
	 break;
      }
      if (GET_CON(ch) < 15)
	 gain /= 2;
      if (GET_CON(ch) > 20)
	 gain += gain/2;
   }
   
   if (GET_LEVEL(ch) > 10){
       if (((float)GET_HIT(ch))/ ((float)(MAX(1,GET_MAX_HIT(ch)))) > .7)
	   gain += gain/2;
       if (((float)GET_HIT(ch))/ ((float)(MAX(1,GET_MAX_HIT(ch)))) < .4)
	   gain -= gain/2;
       if (((float)GET_HIT(ch))/ ((float)(MAX(1,GET_MAX_HIT(ch)))) < .2)
	   gain -= gain/2;
       if (((float)GET_HIT(ch))/ ((float)(MAX(1,GET_MAX_HIT(ch)))) < .1)
	   gain -= gain/2;
   }

   if (IS_AFFECTED(ch, AFF_POISON))
      gain /= 4;

   if ((GET_COND(ch, FULL) == 0) || (GET_COND(ch, THIRST) == 0))
      gain /= 4;

   if (IS_SET(world[ch->in_room].room_flags, FAST_HP_GAIN))
       gain <<= 1;
   if (ch->specials.fighting && GET_LEVEL(ch) > 10)
       gain = 0;
   
   if (IS_AFFECTED(ch, AFF_HEALING))
     gain *= 2;
   for (aff = ch->affected; aff; aff = aff->next)
     if (aff->type == SPELL_BODY_MADE_WHOLE)
       gain = MAX(gain,(GET_MAX_HIT(ch) - GET_HIT(ch))/5);
   return (gain);
}



int	move_gain(struct char_data *ch)
/* move gain pr. game hour */
{
  int	gain;
  struct affected_type *aff;
  
  if (IS_NPC(ch)) {
    return(GET_LEVEL(ch));
    /* Neat and fast */
  } else {
      gain = graf(age(ch).year, 16, 20, 24, 20, 16, 12, 10);

      /* Class/Level calculations */

      /* Skill/Spell calculations */

      gain += 2*(GET_CON(ch) - GET_RAW_CON(ch));
      /* Position calculations    */
      switch (GET_POS(ch)) {
      case POSITION_SLEEPING:
	 gain += (gain/2); /* Divide by 2 */
	 break;
      case POSITION_RESTING:
	 gain += (gain/4);  /* Divide by 4 */
	 break;
      case POSITION_SITTING:
	 gain += (gain/8); /* Divide by 8 */
	 break;
      }
   }

   if (GET_LEVEL(ch) > 10){
       if (((float)GET_MOVE(ch))/ ((float)(MAX(1,GET_MAX_MOVE(ch)))) > .7)
	   gain += gain/2;
       if (((float)GET_MOVE(ch))/ ((float)(MAX(1,GET_MAX_MOVE(ch)))) < .3)
	   gain -= gain/8;
       if (((float)GET_MOVE(ch))/ ((float)(MAX(1,GET_MAX_MOVE(ch)))) < .2)
	 gain -= gain/6;
       if (((float)GET_MOVE(ch))/ ((float)(MAX(1,GET_MAX_MOVE(ch)))) < .1)
	   gain -= gain/4;
   }
   if ((GET_MOVE(ch) < 0 ) && (GET_POS(ch) == POSITION_SLEEPING))
     gain *= 3;
   
   if (IS_AFFECTED(ch, AFF_POISON))
      gain /= 4;

   if ((GET_COND(ch, FULL) == 0) || (GET_COND(ch, THIRST) == 0))
      gain /= 4;

   if (IS_SET(world[ch->in_room].room_flags, FAST_MOVE_GAIN))
       gain *= 2;
   if (ch->specials.fighting && GET_LEVEL(ch) > 10)
       gain = 0;   
   if (IS_AFFECTED(ch, AFF_HEALING))
     gain *= 2;
   for (aff = ch->affected; aff; aff = aff->next)
     if (aff->type == SPELL_BODY_MADE_WHOLE)
       gain = MAX(gain,(GET_MAX_MOVE(ch) - GET_MOVE(ch))/5);
   return (gain);
}


/* Gain maximum in various points */
void	advance_level(struct char_data *ch)
{
   int	add_hp, i,add_move;

   extern struct con_app_type con_app[];

   add_hp = con_app[GET_RAW_CON(ch)].hitp;


   add_hp += number(GET_RAW_CON(ch)/3,GET_RAW_CON(ch)/2);
   add_move = number((GET_RAW_CON(ch)/8 + GET_RAW_DEX(ch)/8 + GET_RAW_STR(ch)/4),(GET_RAW_CON(ch)/4 + GET_RAW_DEX(ch)/4 + GET_RAW_STR(ch)/2))/4;


   ch->points.max_hit += MAX(5, add_hp);
   if ((GET_LEVEL(ch) != 1) && (ch->points.max_move < 1000)) 
     ch->points.max_move = ch->points.max_move + (sh_int)add_move;

   SPELLS_TO_LEARN(ch) += 20*number(1, MAX(2,(GET_RAW_INT(ch)*2/3 
					+ GET_RAW_WIS(ch)*2/3)/10));
   SPELLS_TO_LEARN(ch) += 20*number(1, MAX(2,(GET_RAW_STR(ch)*2/3 
					+ GET_RAW_DEX(ch)*2/3)/10));
   SPELLS_TO_LEARN(ch) += 10*number(1, MAX(2,(GET_RAW_GUI(ch)*2/3 
					+ GET_RAW_CHR(ch)*2/3)/10));
   SPELLS_TO_LEARN(ch) += 10*number(1, MAX(2,(GET_RAW_PER(ch)*2/3 
					+ GET_RAW_CON(ch)*2/3)/10));
   SPELLS_TO_LEARN(ch) += 20*number(1, MAX(2,(GET_RAW_DEV(ch)*2/3 
					+ GET_RAW_FOC(ch)*2/3)/10));   
   SPELLS_TO_LEARN(ch) += number(1,GET_RAW_LUC(ch))/2;

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

   save_char(ch, NOWHERE);

   sprintf(buf, "%s advanced to level %d", GET_NAME(ch), GET_LEVEL(ch));
   mudlog(buf, BRF, MAX(LEVEL_BUILDER, GET_INVIS_LEV(ch)), TRUE);
}
void	loose_level(struct char_data *ch)
{
   int	add_move, add_hp, i;

   extern struct con_app_type con_app[];

   add_hp = con_app[GET_RAW_CON(ch)].hitp;


   add_hp += number( GET_RAW_CON(ch)/3,GET_RAW_CON(ch)/2);
   add_move = number((GET_RAW_CON(ch)/8 + GET_RAW_DEX(ch)/8 + GET_RAW_STR(ch)/4),(GET_RAW_CON(ch)/4 + GET_RAW_DEX(ch)/4 + GET_RAW_STR(ch)/2))/4;

   SPELLS_TO_LEARN(ch) -= 20*number(1, MAX(2,(GET_RAW_INT(ch)*2/3 
					+ GET_RAW_WIS(ch)*2/3)/10));
   SPELLS_TO_LEARN(ch) -= 20*number(1, MAX(2,(GET_RAW_STR(ch)*2/3 
					+ GET_RAW_DEX(ch)*2/3)/10));
   SPELLS_TO_LEARN(ch) -= 10*number(1, MAX(2,(GET_RAW_GUI(ch)*2/3 
					+ GET_RAW_CHR(ch)*2/3)/10));
   SPELLS_TO_LEARN(ch) -= 10*number(1, MAX(2,(GET_RAW_PER(ch)*2/3 
					+ GET_RAW_CON(ch)*2/3)/10));
   SPELLS_TO_LEARN(ch) -= 20*number(1, MAX(2,(GET_RAW_DEV(ch)*2/3 
					+ GET_RAW_FOC(ch)*2/3)/10));   
   SPELLS_TO_LEARN(ch) -= number(1,GET_RAW_LUC(ch))/2;

   ch->points.max_hit -= MAX(5, add_hp);
   ch->points.max_hit = MAX(10,ch->points.max_hit);
   ch->points.max_move = ch->points.max_move - (sh_int)add_move;
   ch->points.max_move = MAX(50,ch->points.max_move);

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

   save_char(ch, NOWHERE);

   sprintf(buf, "%s reduced to level %d", GET_NAME(ch), GET_LEVEL(ch));
   mudlog(buf, BRF, MAX(LEVEL_BUILDER, GET_INVIS_LEV(ch)), TRUE);
}
void	advance_sub_level(struct char_data *ch, int sublev)
{
   int	add_hp, i;
   int	add_move,add_pracs;

   extern struct con_app_type con_app[];

   add_hp = con_app[GET_RAW_CON(ch)].hitp;
   add_hp += number(GET_RAW_CON(ch)/3,GET_RAW_CON(ch)/2);
   add_move = number((GET_RAW_CON(ch)/8 + GET_RAW_DEX(ch)/8 + GET_RAW_STR(ch)/4),(GET_RAW_CON(ch)/4 + GET_RAW_DEX(ch)/4 + GET_RAW_STR(ch)/2))/4;

   add_pracs = 20*number(1, MAX(2,(GET_RAW_INT(ch)*2/3 
					+ GET_RAW_WIS(ch)*2/3)/10));
   add_pracs += 20*number(1, MAX(2,(GET_RAW_STR(ch)*2/3 
					+ GET_RAW_DEX(ch)*2/3)/10));
   add_pracs += 10*number(1, MAX(2,(GET_RAW_GUI(ch)*2/3 
					+ GET_RAW_CHR(ch)*2/3)/10));
   add_pracs += 10*number(1, MAX(2,(GET_RAW_PER(ch)*2/3 
					+ GET_RAW_CON(ch)*2/3)/10));
   add_pracs += 20*number(1, MAX(2,(GET_RAW_DEV(ch)*2/3 
					+ GET_RAW_FOC(ch)*2/3)/10));   
   add_pracs += number(1,GET_RAW_LUC(ch))/2;
   if (sublev%2){
   ch->points.max_hit += MAX(1, add_hp/4);
   ch->points.max_move += MAX(2,(sh_int)add_move/4);
   }
   else 
     SPELLS_TO_LEARN(ch) += add_pracs/5;

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

   save_char(ch, NOWHERE);

}
void	loose_sub_level(struct char_data *ch, int sublev)
{
   int	add_hp, i;
   int	add_move,add_pracs;

   extern struct con_app_type con_app[];

   add_hp = con_app[GET_RAW_CON(ch)].hitp;
   add_hp += number(GET_RAW_CON(ch)/3,GET_RAW_CON(ch)/2);
   add_move = number((GET_RAW_CON(ch)/8 + GET_RAW_DEX(ch)/8 + GET_RAW_STR(ch)/4),(GET_RAW_CON(ch)/4 + GET_RAW_DEX(ch)/4 + GET_RAW_STR(ch)/2))/4;

   add_pracs = 20*number(1, MAX(2,(GET_RAW_INT(ch)*2/3 
					+ GET_RAW_WIS(ch)*2/3)/10));
   add_pracs += 20*number(1, MAX(2,(GET_RAW_STR(ch)*2/3 
					+ GET_RAW_DEX(ch)*2/3)/10));
   add_pracs += 10*number(1, MAX(2,(GET_RAW_GUI(ch)*2/3 
					+ GET_RAW_CHR(ch)*2/3)/10));
   add_pracs += 10*number(1, MAX(2,(GET_RAW_PER(ch)*2/3 
					+ GET_RAW_CON(ch)*2/3)/10));
   add_pracs += 20*number(1, MAX(2,(GET_RAW_DEV(ch)*2/3 
					+ GET_RAW_FOC(ch)*2/3)/10));   
   add_pracs += number(1,GET_RAW_LUC(ch))/2;
   if (sublev%2){
     ch->points.max_hit -= MAX(1, add_hp/4);
     ch->points.max_move -= MAX(2,(sh_int)add_move/4);
   }
   else 
     SPELLS_TO_LEARN(ch) -= add_pracs/5;

   save_char(ch, NOWHERE);

}


void	set_title(struct char_data *ch)
{
   if (GET_TITLE(ch))
     return;
   else
      CREATE(GET_TITLE(ch), char, strlen("%n the newbie %c visits %r") +1);

   strcpy(GET_TITLE(ch), "%n the newbie %c visits %r");
}


void check_autowiz(struct char_data *ch)
{
   char	buf[100];
   extern int	use_autowiz;
   extern int	min_wizlist_lev;

   if (use_autowiz && GET_LEVEL(ch) >= LEVEL_BUILDER) {
      sprintf(buf, "nice ../bin/autowiz %d %s %d %s %d &", min_wizlist_lev,
         WIZLIST_FILE, LEVEL_BUILDER, IMMLIST_FILE, getpid());
      mudlog("Initiating autowiz.", CMP, LEVEL_BUILDER, FALSE);
      system(buf);
   }
}

void    gain_social_standing(struct char_data *ch, struct char_data *vict,int mode){
  
  if (IS_NPC(ch))
    return;
  switch(mode){
  case MODE_KILL:
    if (IS_NPC(vict))
      GET_FAME(ch) -= (GET_FAME(vict)*GET_LEVEL(vict))/MAX(1,GET_LEVEL(ch));
    else 
      if ((GET_LEVEL(vict) <= 10) && (GET_LEVEL(ch) > 10))
	GET_FAME(ch) -= 500;
      else
	GET_FAME(ch) -= (GET_FAME(vict)*GET_LEVEL(vict))/MAX(1,GET_LEVEL(ch));
    break;
  case MODE_FLEE:
    GET_FAME(ch) -= abs(GET_FAME(vict)*GET_LEVEL(vict))/MAX(1,5*GET_LEVEL(ch));
    break;
  case MODE_STEAL:
    GET_FAME(ch) -= abs(GET_FAME(vict)*GET_LEVEL(vict))/MAX(1,5*GET_LEVEL(ch));
    break;    
    
    
  }
}

void	gain_exp(struct char_data *ch, int gain,int mode)
{
  int	i, sub_level, incr, sincr;
   
  if (!IS_NPC(ch)
      && ((GET_LEVEL(ch) < LEVEL_BUILDER-1) && (GET_LEVEL(ch) > 0))) {
    if (gain > 0) {
      gain = MIN(3000*(MAX(1,GET_LEVEL(ch))), gain);
      i = GET_LEVEL(ch);
      sub_level = GET_SUB_LEVEL(ch);
      sincr = (levels_table[i+1] - levels_table[i])/10;
      while (gain){
	 incr = MIN(gain, sincr);
	 GET_EXP(ch) += incr;
	 gain -= incr;
	 
	 while(GET_EXP(ch) >= (levels_table[i] + (sub_level + 1)*sincr)){
	   advance_sub_level(ch, sub_level);
	   sub_level++;
	   GET_SUB_LEVEL(ch) += 1;
	   if (sub_level > 9){
	     sub_level = 0;
	     GET_SUB_LEVEL(ch) = 0;	     
	     i++;
	     if (GET_LEVEL(ch) < LEVEL_BUILDER -1)
	       GET_LEVEL(ch) += 1;
	     sincr = (levels_table[i+1] - levels_table[i])/10;
	   }
	 }
      }
    }
    if (gain < 0) {
      gain = MAX(-6000*GET_LEVEL(ch), gain);
      i = GET_LEVEL(ch);
      sub_level = GET_SUB_LEVEL(ch);
      sincr = (levels_table[i+1] - levels_table[i])/10;
      while (gain < 0){
	incr = MAX(gain, -1*sincr);
	GET_EXP(ch) += incr;
	gain -= incr;
	if (GET_EXP(ch) < 750){
	  GET_EXP(ch) = 750;
	  GET_SUB_LEVEL(ch) = 0;
	  return;
	}
	while (GET_EXP(ch) <= (levels_table[i] + sub_level*sincr)){
	  loose_sub_level(ch, sub_level);
	  sub_level--;
	   GET_SUB_LEVEL(ch) -= 1;
	   if (sub_level < 0){
	     sub_level = 9;
	     GET_SUB_LEVEL(ch) = 9;	     
	     i--;
	     GET_LEVEL(ch) -= 1;
	     if (GET_LEVEL(ch) < 1)
	       GET_LEVEL(ch) = 1;
	     sincr = (levels_table[i+1] - levels_table[i])/10;
	   }
	}
      }
    }
    
  }
}


void	gain_exp_regardless(struct char_data *ch, int gain, int mode)
{
   int	i, incr, sincr, sub_level;

   if (!IS_NPC(ch)) {
      if (gain > 0) {

       i = GET_LEVEL(ch);
       sub_level = GET_SUB_LEVEL(ch);
       sincr = (levels_table[i+1] - levels_table[i])/10;
       while (gain){
	 incr = MIN(gain, sincr);
	 GET_EXP(ch) += incr;
	 gain -= incr;
	 
	 while(GET_EXP(ch) >= (levels_table[i] + (sub_level + 1)*sincr)){
	   advance_sub_level(ch, sub_level);
	   sub_level++;
	   GET_SUB_LEVEL(ch) += 1;
	   if (sub_level > 9){
	     sub_level = 0;
	     GET_SUB_LEVEL(ch) = 0;	     
	     i++;
	     GET_LEVEL(ch) += 1;
	     sincr = (levels_table[i+1] - levels_table[i])/10;
	   }
	 }
       }
	
      }
      else if (gain < 0){
	i = GET_LEVEL(ch);
	sub_level = GET_SUB_LEVEL(ch);
	sincr = (levels_table[i+1] - levels_table[i])/10;
	while (gain < 0){
	  incr = MAX(gain, -1*sincr);
	  GET_EXP(ch) += incr;
	  gain -= incr;
	  if (GET_EXP(ch) < 750){
	    GET_EXP(ch) = 750;
	    GET_SUB_LEVEL(ch) = 0;
	    return;
	  }
	  while (GET_EXP(ch) <= (levels_table[i] + sub_level*sincr)){
	    loose_sub_level(ch, sub_level);
	    sub_level--;
	    GET_SUB_LEVEL(ch) -= 1;
	    if (sub_level < 0){
	      sub_level = 9;
	      GET_SUB_LEVEL(ch) = 9;	     
	      i--;
	      GET_LEVEL(ch) -= 1;
	      sincr = (levels_table[i+1] - levels_table[i])/10;
	    }
	  }
	}
      }
   }
}


void	gain_condition(struct char_data *ch, int condition, int value)
{
   bool intoxicated;

   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 (PLR_FLAGGED(ch, PLR_WRITING))
      return;

   switch (condition) {
   case FULL:
     if (GET_COND(ch, FULL) == 0)
       send_to_char("You are starving.\r\n",ch);
     else if (GET_COND(ch, FULL) <= 4 )
       send_to_char("You are famished.\r\n",ch);
     else if (GET_COND(ch, FULL) <= 8 )
       send_to_char("You are very hungry.\r\n",ch);
     else if (GET_COND(ch, FULL) <= 12 )
       send_to_char("You are hungry.\r\n",ch);
     else if (GET_COND(ch, FULL) < 16 )
       send_to_char("Your stomach is growling.\r\n",ch);
     return;
   case THIRST :
     if (GET_COND(ch, THIRST) == 0)
       send_to_char("You are parched.\r\n",ch);
     else if (GET_COND(ch, THIRST) <= 4)
       send_to_char("Your throat is dry and your lips cracked.\r\n",ch);
     else if (GET_COND(ch, THIRST) <= 8)
       send_to_char("Your throat is very dry.\r\n",ch);
     else if (GET_COND(ch, THIRST) <= 12)
       send_to_char("You are thirsty.\r\n",ch);
     else if (GET_COND(ch, THIRST) < 16)
       send_to_char("Your feel a little thirsty.\r\n",ch);
      return;
   case DRUNK :
      if (intoxicated)
	 send_to_char("You are now sober.\r\n", ch);
      return;
   default :
      break;
   }

}


void	check_idling(struct char_data *ch)
{
    
    if (++(ch->specials.timer) > 8)
	if (GET_LEVEL(ch) < LEVEL_BUILDER)
	    if (ch->specials.was_in_room == NOWHERE
		&& ch->in_room != NOWHERE) {
		ch->specials.was_in_room = ch->in_room;
		if (ch->specials.fighting) {
		    stop_fighting(ch->specials.fighting);
		    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.\r\n", ch);
		save_char(ch, NOWHERE);
		Crash_crashsave(ch);
		char_from_room(ch);
		char_to_room(ch, 1, FALSE);
	    }
	    else if (ch->specials.timer > 48) {
		if (ch->in_room != NOWHERE) 
		    char_from_room(ch);
		char_to_room(ch, 3, FALSE);
		if (ch->desc)
		    close_socket(ch->desc);
		ch->desc = 0;
		Crash_idlesave(ch);
		sprintf(buf, "%s force-rented and extracted (idle).", GET_NAME(ch));
		mudlog(buf, CMP, LEVEL_GOD, TRUE);
		extract_char(ch, FALSE);
	    }
}
void rem_healing_bon(struct char_data *i)
{
  struct affected_type *aff, *next;

  
  for (aff = i->affected;aff;aff = next){
    next = aff->next;
    if ((aff->type == SPELL_HEALING_TOUCH) ||
	(aff->type == SPELL_BODY_MADE_WHOLE))
      affect_remove(i, aff);
  }
}

void poison_vict(struct char_data *i)
{
   struct affected_type *aff;

   for (aff = i->affected;aff;aff = aff->next)
	if (aff->type == SPELL_POISON && aff->location == APPLY_NONE)
	    break;
    if (aff)
	switch (aff->modifier){
	case 0:
	    damage(i, i, number(1,12), SPELL_POISON,-1,0);
	    break;
	case 1:
	    damage(i, i, number(6,24), SPELL_POISON,-1,0);
	    break;
	case 2:
	    damage(i, i, number(12,48), SPELL_POISON,-1,0);
	    break;
	case 3:
	    damage(i, i, number(24,96), SPELL_POISON,-1,0);
	    break;
	case 4:
	    damage(i, i, number(96,192), SPELL_POISON,-1,0);
	    break;
	case 5:
	    damage(i, i, number(200,500), SPELL_POISON,-1,0);
	    break;
	default:
	    damage(i, i, number(96,192), SPELL_POISON,-1,0);
	}
    else
	damage(i, i, number(96,192), SPELL_POISON,-1,0);

}

/* Update both PC's & NPC's and objects*/
void	point_update( void )
{
   void	update_char_objects( struct char_data *ch ); /* handler.c */
   void	extract_obj(struct obj_data *obj, int mode); /* handler.c */
   struct char_data *i, *next_dude;
   struct obj_data *j, *next_thing, *jj, *next_thing2;
   /* characters */
   for (i = character_list; i; i = next_dude) {
      next_dude = i->next;
      if (i->specials.fighting && (i->specials.fighting->specials.fighting
				   == i)
	  && IS_AFFECTED(i, AFF_HEALING))
	  rem_healing_bon(i);
      if (GET_POS(i) >= POSITION_STUNNED) {
	 GET_HIT(i)  = MIN(GET_HIT(i)  + hit_gain(i),  GET_MAX_HIT(i));
	 GET_MOVE(i) = MIN(GET_MOVE(i) + move_gain(i), GET_MAX_MOVE(i));
	 if (IS_AFFECTED(i, AFF_HEALING) && (GET_HIT(i) == GET_MAX_HIT(i)))
	     rem_healing_bon(i);
	 if (IS_AFFECTED(i, AFF_POISON))
	     poison_vict(i);
	 if (GET_POS(i) == POSITION_STUNNED)
	    update_pos(i);
      } else if (GET_POS(i) == POSITION_INCAP)
	 damage(i, i, 1, TYPE_SUFFERING,-1,0);
      else if (!IS_NPC(i) && (GET_POS(i) == POSITION_MORTALLYW))
	 damage(i, i, 2, TYPE_SUFFERING,-1,0);
      if (i->specials.mount && (i->specials.mount ->in_room != i->in_room))
	unmount(i);
      if (i->specials.rider && (i->specials.rider->in_room != i->in_room))
	unmount(i->specials.rider);
      if (i->specials.carrying &&(i->specials.carrying->in_room != i->in_room))
	do_drop_mob(i);
      if (i->specials.carried_by &&
	  (i->specials.carried_by->in_room != i->in_room))
	do_drop_mob(i->specials.carried_by);
      if (IS_PULLING(i) && (IS_PULLING(i)->in_room != i->in_room))
	  unhitch(i,IS_PULLING(i),i,1);
	   /* if carts get separated from their */
           /* owners then they should be unhitched*/
      if (!IS_NPC(i)) {
	 update_char_objects(i);
	 if (GET_LEVEL(i) < LEVEL_IMPL)
	    check_idling(i);
      }
      gain_condition(i, FULL, -1);
      gain_condition(i, DRUNK, -1);
      gain_condition(i, THIRST, -1);
   } /* for */
   for (j = object_list; j ; j = next_thing) {
     next_thing = j->next; /* Next in object list */
     if (GET_ITEM_TYPE(j) == ITEM_SRTLIGHT) {
       if (((time_info.hours >= 21) || (time_info.hours  <= 4))
	   && !IS_SET(j->obj_flags.extra_flags, ITEM_GLOW)) {
	 SET_BIT(j->obj_flags.extra_flags, ITEM_GLOW);
	 act("$p starts to glow.", FALSE,0,j,0,TO_ROOM);
       }
       else if (((time_info.hours >= 5) && (time_info.hours <= 20))
		&& IS_SET(j->obj_flags.extra_flags, ITEM_GLOW)) {
	 REMOVE_BIT(j->obj_flags.extra_flags, ITEM_GLOW);
	 act("$p goes out.", FALSE,0,j,0,TO_ROOM);
       }
     }
     if (j->obj_flags.timer > 0)
       j->obj_flags.timer--;
     if ((j->obj_flags2.light > 0) && j->in_room
	 && !IS_OBJ_STAT(j, ITEM_MAGIC) && IS_OBJ_STAT(j, ITEM_GLOW)){
       j->obj_flags2.light--;
       if ((j->obj_flags2.light == 0)){
	 REMOVE_BIT(j->obj_flags.extra_flags, ITEM_GLOW);
	 act("$p stops glowing.",FALSE,0,j,0,TO_ROOM);
	if (j->obj_flags.type_flag == ITEM_LIGHT)
	  extinguish_light(j);
       }
       else if ((j->obj_flags2.light <= 4) && (j->obj_flags2.light > 0))
	 act("$p is growing dim.",FALSE,0,j,0,TO_CHAR);
     }
     
    /* If this is a corpse */
     if ((GET_ITEM_TYPE(j) == ITEM_CONTAINER) && (j->obj_flags.value[3] < 0)){
       /* timer count down */
       if (j->obj_flags.timer == 0) {
	 
	 if (j->carried_by)
	   act("$p decays in your hands.", FALSE, j->carried_by, j, 0, TO_CHAR);
	 else if ((j->in_room != NOWHERE) && (world[j->in_room].people)){
	   if (world[j->in_room].sector_type == SECT_UNDER_WATER) {
	     if (j->obj_flags.value[3] == -1){
	       act("A shoal of fish devour $p."
		   ,TRUE, world[j->in_room].people, j,0,TO_ROOM);
	       act("A shoal of fish devour $p."
		   ,TRUE, world[j->in_room].people, j,0,TO_CHAR);
	     }
	   }
	   else {
	     if (j->obj_flags.value[3] == -1){
	       act("$p crumbles to dust.",TRUE, world[j->in_room].people, j,0,TO_ROOM);
	       act("$p crumbles to dust.",TRUE, world[j->in_room].people, j,0,TO_CHAR);
	       j->obj_flags.timer = 1 ;
	       j->obj_flags.value[3] = -2;
	       sprintf(buf2,"dust pile");
	       free(j->name);
	       j->name = str_dup(buf2);
	       sprintf(buf2, "A pile of dust is lying here.");
	       free(j->description);
	       j->description = str_dup(buf2);
	       sprintf(buf2, "a pile of dust");
	       free(j->short_description);
	       j->short_description = str_dup(buf2);
	       free(j->action_description);
	       j->action_description = 0;
	       continue;
	     }
	     send_to_room("A gust of wind blows the dust away.\r\n",
			  j->in_room, FALSE);
	   }
	 }
	 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)
	     obj_to_room(jj, j->carried_by->in_room, FALSE);
	   else if (j->in_room != NOWHERE)
	     obj_to_room(jj, j->in_room, FALSE);
	   else
	     assert(FALSE);
	 }
	 extract_obj(j,0);
       }
     }
     else {
       if (j->obj_flags.timer == 0) {
	 if ((j->in_room != NOWHERE) && (world[j->in_room].people)) {
	   act("$p fades out of existance."
	       ,TRUE, world[j->in_room].people, j, 0, TO_NOTCHAR);
	   act("$p fades out of existance."
	       ,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)
	     obj_to_room(jj, j->carried_by->in_room, FALSE);
	   else if (j->in_room != NOWHERE)
	     obj_to_room(jj, j->in_room, FALSE);
	   else
	     assert(FALSE);
	 }
	 extract_obj(j,0);
       }
     }
   }
   
}