/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen  *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "merc.h"

/*
 * Local functions.
 */
void  mobile_update               args (( void ));
void  weather_update              args (( void ));
void  room_update                 args (( void ));
void  char_update                 args (( void ));
void  obj_update                  args (( void ));
void  ww_update                   args (( void ));
void  update_regen                args (( CHAR_DATA * ch, int multiplier ));
void  update_active_counters      args (( CHAR_DATA * ch ));
void  update_morted_timer         args (( CHAR_DATA * ch ));
void  update_sit_safe_counter     args (( CHAR_DATA * ch ));
void  update_drunks               args (( CHAR_DATA * ch ));
void  sex_update                  args (( CHAR_DATA * ch ));
void  update_arti_regen           args (( CHAR_DATA * ch ));
void  regen_limb                  args (( CHAR_DATA * ch ));


void gain_exp(CHAR_DATA * ch, int gain)
{
  CHAR_DATA *mount = NULL;
  CHAR_DATA *master = NULL;

  if (IS_NPC(ch) && (mount = ch->mount) != NULL && !IS_NPC(mount))
  {
    if ((master = ch->master) == NULL || master != mount)
      mount->exp += gain;
  }
  if (!IS_NPC(ch))
    ch->exp += gain;
  return;
}

void gain_condition(CHAR_DATA * ch, int iCond, int value)
{
  int condition;

  if (value == 0 || IS_NPC(ch))
    return;

  if (!IS_NPC(ch) && IS_HERO(ch) && iCond != COND_DRUNK)
    return;

  condition = ch->pcdata->condition[iCond];
  if (!IS_NPC(ch))
  {
    ch->pcdata->condition[iCond] = URANGE(0, condition + value, 48);
  }
  else
    ch->pcdata->condition[iCond] = URANGE(0, condition + value, 20000 / ch->generation);

  if (ch->pcdata->condition[iCond] == 0)
  {
    switch (iCond)
    {
      case COND_FULL:
        send_to_char("You are REALLY hungry.\n\r", ch);
        act("You hear $n's stomach rumbling.", ch, NULL, NULL, TO_ROOM);
        break;

      case COND_THIRST:
        send_to_char("You are REALLY thirsty.\n\r", ch);
        break;

      case COND_DRUNK:
        if (condition != 0)
          send_to_char("You are sober.\n\r", ch);
        break;
    }
  }
  else if (ch->pcdata->condition[iCond] < 10)
  {
    switch (iCond)
    {
      case COND_FULL:
        send_to_char("You feel hungry.\n\r", ch);
        break;

      case COND_THIRST:
        send_to_char("You feel thirsty.\n\r", ch);
        break;
    }
  }

  return;
}

/*
 * Mob autonomous action.
 * This function takes 25% to % of ALL Merc cpu time.
 * -- Furey
 */
void mobile_update(void)
{
  CHAR_DATA *ch;
  CHAR_DATA *ch_next;
  EXIT_DATA *pexit;
  int door;

  /* Examine all mobs. */
  for (ch = char_list; ch != NULL; ch = ch_next)
  {
    ch_next = ch->next;

    if (ch->in_room == NULL)
      continue;

    if (!IS_NPC(ch) && ch->hunting != NULL && ch->hunting != '\0' && strlen(ch->hunting) > 1)
    {
      check_hunt(ch);
      continue;
    }
    if (!IS_NPC(ch))
    {
      update_morted_timer(ch);
      update_sit_safe_counter(ch);
      update_drunks(ch);
      sex_update(ch);
      if (IS_HERO(ch) && ch->hit > 0 && !IS_SET(ch->extra, EXTRA_AFK))
      {
        if (ch->class == 0 && IS_ITEMAFF(ch, ITEMA_REGENERATE))
          update_arti_regen(ch);
      }
      else
      {
        ch->hit += number_range(1, 5);
        if (ch->hit > ch->max_hit)
          ch->hit = ch->max_hit;
        update_pos(ch);
        if (IS_ITEMAFF(ch, ITEMA_REGENERATE) && ch->hit > 0)
          update_arti_regen(ch);
      }
    }
    else                        // This is for the mobs
    {
      if (IS_AFFECTED(ch, AFF_CHARM))
        continue;
      if (ch->spec_fun != 0)
      {
        if ((*ch->spec_fun) (ch, "update"))
          continue;
        if (ch == NULL)
          continue;
      }
      if (ch->position != POS_STANDING)
      {
        do_stand(ch, "");
        continue;
      }
      if (IS_SET(ch->act, ACT_SCAVENGER) && ch->in_room->contents != NULL && number_bits(2) == 0)
      {
        OBJ_DATA *obj;
        OBJ_DATA *obj_best = 0;
        int max = 1;

        for (obj = ch->in_room->contents; obj; obj = obj->next_content)
        {
          if (!can_see_obj(ch, obj))
            continue;
          if (IS_SET(obj->quest, QUEST_ARTIFACT))
            continue;
          if (CAN_WEAR(obj, ITEM_TAKE) && obj->cost > max)
          {
            obj_best = obj;
            max = obj->cost;
          }
        }
        if (obj_best)
        {
          obj_from_room(obj_best);
          obj_to_char(obj_best, ch);
          act("$n picks $p up.", ch, obj_best, NULL, TO_ROOM);
          act("You pick $p up.", ch, obj_best, NULL, TO_CHAR);
        }
      }
      if (!IS_SET(ch->act, ACT_SENTINEL) && (door = number_bits(5)) <= 5 && (pexit = ch->in_room->exit[door]) != NULL
        && pexit->to_room != NULL && !IS_SET(pexit->exit_info, EX_CLOSED) && !IS_SET(pexit->to_room->room_flags, ROOM_NO_MOB)
        && (ch->hunting == NULL || strlen(ch->hunting) < 1)
        && !(IS_SET(ch->act, ACT_FISH) && pexit->to_room->sector_type != SECT_WATER_SWIM && pexit->to_room->sector_type != SECT_WATER_NOSWIM)
        && !(IS_SET(ch->act, ACT_NOSWIM) && (pexit->to_room->sector_type == SECT_WATER_SWIM || pexit->to_room->sector_type == SECT_WATER_NOSWIM))
        && ((!IS_SET(ch->act, ACT_STAY_AREA) && ch->level < 900) || pexit->to_room->area == ch->in_room->area))
      {
        move_char(ch, door);
      }
      if (ch->hit < ch->max_hit / 2 && (door = number_bits(3)) <= 5 && (pexit = ch->in_room->exit[door]) != NULL
          && pexit->to_room != NULL && ch->level < 900 && !IS_SET(pexit->exit_info, EX_CLOSED) && !IS_SET(pexit->to_room->room_flags, ROOM_NO_MOB))
      {
        CHAR_DATA *rch;
        bool found;

        found = FALSE;
        for (rch = pexit->to_room->people; rch != NULL; rch = rch->next_in_room)
        {
          if (!IS_NPC(rch))
          {
            found = TRUE;
            break;
          }
        }
        if (!found)
          move_char(ch, door);
      }
    }
  }
  return;
}

/*
 * Update the weather.
 */
void weather_update(void)
{
  char buf[MAX_STRING_LENGTH];
  DESCRIPTOR_DATA *d;
  CHAR_DATA *ch = NULL;
  int diff;
  bool char_up;
  bool thunder = FALSE;

  buf[0] = '\0';

  switch (++time_info.hour)
  {
    case 5:
      weather_info.sunlight = SUN_LIGHT;
      strcat(buf, "Another day has begun.\n\r");
      break;

    case 6:
      weather_info.sunlight = SUN_RISE;
      strcat(buf, "The black orb rises in the sky.\n\r");
      break;

    case 19:
      weather_info.sunlight = SUN_SET;
      strcat(buf, "The sun slowly disappears in the west.\n\r");
      break;

    case 20:
      weather_info.sunlight = SUN_DARK;
      strcat(buf, "The night has begun.\n\r");
      break;

    case 24:
      time_info.hour = 0;
      time_info.day++;
      for (d = descriptor_list; d != NULL; d = d->next)
      {
        char_up = FALSE;
        if ((d->connected == CON_PLAYING || d->connected == CON_EDITING) && (ch = d->character) != NULL && !IS_NPC(ch))
        {
          send_to_char("You hear a clock in the distance strike midnight.\n\r", ch);
          if (ch->pcdata->followers > 0)
            ch->pcdata->followers = 0;
          if (IS_SET(ch->in_room->room_flags, ROOM_SILENCE))
          {
            send_to_char("The silence leaves the room.\n\r", ch);
            act("The silence leaves the room.", ch, NULL, NULL, TO_ROOM);
            REMOVE_BIT(ch->in_room->room_flags, ROOM_SILENCE);

          }

          if (IS_SET(ch->in_room->room_flags, ROOM_FLAMING))
          {
            send_to_char("The flames in the room die down.\n\r", ch);
            act("The flames in the room die down.", ch, NULL, NULL, TO_ROOM);
            REMOVE_BIT(ch->in_room->room_flags, ROOM_FLAMING);
          }
        }

      }
      break;
  }

  if (time_info.day >= 35)
  {
    time_info.day = 0;
    time_info.month++;
  }

  if (time_info.month >= 17)
  {
    time_info.month = 0;
    time_info.year++;
  }

  /*
   * Weather change.
   */
  if (time_info.month >= 9 && time_info.month <= 16)
    diff = weather_info.mmhg > 985 ? -2 : 2;
  else
    diff = weather_info.mmhg > 1015 ? -2 : 2;

  weather_info.change += diff * dice(1, 4) + dice(2, 6) - dice(2, 6);
  weather_info.change = UMAX(weather_info.change, -12);
  weather_info.change = UMIN(weather_info.change, 12);

  weather_info.mmhg += weather_info.change;
  weather_info.mmhg = UMAX(weather_info.mmhg, 960);
  weather_info.mmhg = UMIN(weather_info.mmhg, 1040);

  switch (weather_info.sky)
  {
    default:
      bug("Weather_update: bad sky %d.", weather_info.sky);
      weather_info.sky = SKY_CLOUDLESS;
      break;

    case SKY_CLOUDLESS:
      if (weather_info.mmhg < 990 || (weather_info.mmhg < 1010 && number_bits(2) == 0))
      {
        strcat(buf, "The sky is getting cloudy.\n\r");
        weather_info.sky = SKY_CLOUDY;
      }
      break;

    case SKY_CLOUDY:
      if (weather_info.mmhg < 970 || (weather_info.mmhg < 990 && number_bits(2) == 0))
      {
        strcat(buf, "It starts to rain.\n\r");
        weather_info.sky = SKY_RAINING;
      }

      if (weather_info.mmhg > 1030 && number_bits(2) == 0)
      {
        strcat(buf, "The clouds disappear.\n\r");
        weather_info.sky = SKY_CLOUDLESS;
      }
      break;

    case SKY_RAINING:
      if (weather_info.mmhg < 970 && number_bits(2) == 0)
      {
        strcat(buf, "Lightning flashes in the sky.\n\r");
        thunder = TRUE;
        weather_info.sky = SKY_LIGHTNING;
      }

      if (weather_info.mmhg > 1030 || (weather_info.mmhg > 1010 && number_bits(2) == 0))
      {
        strcat(buf, "The rain stopped.\n\r");
        weather_info.sky = SKY_CLOUDY;
      }
      break;

    case SKY_LIGHTNING:
      if (weather_info.mmhg > 1010 || (weather_info.mmhg > 990 && number_bits(2) == 0))
      {
        strcat(buf, "The lightning has stopped.\n\r");
        weather_info.sky = SKY_RAINING;
        break;
      }
      break;
  }

  if (buf[0] != '\0')
  {
    for (d = descriptor_list; d != NULL; d = d->next)
    {
      if ((d->connected == CON_PLAYING || d->connected == CON_EDITING) && IS_OUTSIDE(d->character) && IS_AWAKE(d->character))
      {
        if (thunder)
          send_thunder(d->character);
        send_to_char(buf, d->character);
      }
    }
  }

  return;
}

void reg_mend(CHAR_DATA * ch)
{
  int ribs = 0;
  int teeth = 0;
 
  if (IS_BODY(ch, BROKEN_RIBS_1))
    ribs += 1;
  if (IS_BODY(ch, BROKEN_RIBS_2))
    ribs += 2;
  if (IS_BODY(ch, BROKEN_RIBS_4))
    ribs += 4;
  if (IS_BODY(ch, BROKEN_RIBS_8))
    ribs += 8;
  if (IS_BODY(ch, BROKEN_RIBS_16))
    ribs += 16;
  if (IS_HEAD(ch, LOST_TOOTH_1))
    teeth += 1;
  if (IS_HEAD(ch, LOST_TOOTH_2))
    teeth += 2;
  if (IS_HEAD(ch, LOST_TOOTH_4))
    teeth += 4;
  if (IS_HEAD(ch, LOST_TOOTH_8))
    teeth += 8;
  if (IS_HEAD(ch, LOST_TOOTH_16))
    teeth += 16;

  if (ribs > 0)
  {
    if (IS_BODY(ch, BROKEN_RIBS_1))
      REMOVE_BIT(ch->loc_hp[1], BROKEN_RIBS_1);
    if (IS_BODY(ch, BROKEN_RIBS_2))
      REMOVE_BIT(ch->loc_hp[1], BROKEN_RIBS_2);
    if (IS_BODY(ch, BROKEN_RIBS_4))
      REMOVE_BIT(ch->loc_hp[1], BROKEN_RIBS_4);
    if (IS_BODY(ch, BROKEN_RIBS_8))
      REMOVE_BIT(ch->loc_hp[1], BROKEN_RIBS_8);
    if (IS_BODY(ch, BROKEN_RIBS_16))
      REMOVE_BIT(ch->loc_hp[1], BROKEN_RIBS_16);
    ribs -= 1;
    if (ribs >= 16)
    {
      ribs -= 16;
      SET_BIT(ch->loc_hp[1], BROKEN_RIBS_16);
    }
    if (ribs >= 8)
    {
      ribs -= 8;
      SET_BIT(ch->loc_hp[1], BROKEN_RIBS_8);
    }
    if (ribs >= 4)
    {
      ribs -= 4;
      SET_BIT(ch->loc_hp[1], BROKEN_RIBS_4);
    }
    if (ribs >= 2)
    {
      ribs -= 2;
      SET_BIT(ch->loc_hp[1], BROKEN_RIBS_2);
    }
    if (ribs >= 1)
    {
      ribs -= 1;
      SET_BIT(ch->loc_hp[1], BROKEN_RIBS_1);
    }
    act("One of $n's ribs snap back into place.", ch, NULL, NULL, TO_ROOM);
    act("One of your ribs snap back into place.", ch, NULL, NULL, TO_CHAR);
  }
  else if (IS_HEAD(ch, LOST_EYE_L))
  {
    act("An eyeball appears in $n's left eye socket.", ch, NULL, NULL, TO_ROOM);
    act("An eyeball appears in your left eye socket.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_EYE_L);
  }
  else if (IS_HEAD(ch, LOST_EYE_R))
  {
    act("An eyeball appears in $n's right eye socket.", ch, NULL, NULL, TO_ROOM);
    act("An eyeball appears in your right eye socket.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_EYE_R);
  }
  else if (IS_HEAD(ch, LOST_EAR_L))
  {
    act("An ear grows on the left side of $n's head.", ch, NULL, NULL, TO_ROOM);
    act("An ear grows on the left side of your head.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_EAR_L);
  }
  else if (IS_HEAD(ch, LOST_EAR_R))
  {
    act("An ear grows on the right side of $n's head.", ch, NULL, NULL, TO_ROOM);
    act("An ear grows on the right side of your head.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_EAR_R);
  }
  else if (IS_HEAD(ch, LOST_NOSE))
  {
    act("A nose grows on the front of $n's face.", ch, NULL, NULL, TO_ROOM);
    act("A nose grows on the front of your face.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_NOSE);
    REMOVE_BIT(ch->loc_hp[LOC_HEAD], BROKEN_NOSE);
  }  
  else if (teeth > 0)
  {  
    if (IS_HEAD(ch, LOST_TOOTH_1))
      REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_1);
    if (IS_HEAD(ch, LOST_TOOTH_2))
      REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_2);
    if (IS_HEAD(ch, LOST_TOOTH_4))
      REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_4);
    if (IS_HEAD(ch, LOST_TOOTH_8))
      REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_8);
    if (IS_HEAD(ch, LOST_TOOTH_16))
      REMOVE_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_16);
    teeth -= 1; 
    if (teeth >= 16)
    {
      teeth -= 16;
      SET_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_16);
    }
    if (teeth >= 8)
    {
      teeth -= 8;
      SET_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_8);
    }
    if (teeth >= 4)
    {
      teeth -= 4;
      SET_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_4);
    }
    if (teeth >= 2)
    {
      teeth -= 2;
      SET_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_2);
    }
    if (teeth >= 1)
    {
      teeth -= 1;
      SET_BIT(ch->loc_hp[LOC_HEAD], LOST_TOOTH_1);
    }
    act("A missing tooth grows in your mouth.", ch, NULL, NULL, TO_CHAR);
    act("A missing tooth grows in $n's mouth.", ch, NULL, NULL, TO_ROOM);
  }
  else if (IS_HEAD(ch, BROKEN_NOSE))
  {
    act("$n's nose snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your nose snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_HEAD], BROKEN_NOSE);
  }
  else if (IS_HEAD(ch, BROKEN_JAW))
  {
    act("$n's jaw snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your jaw snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_HEAD], BROKEN_JAW);
  }
  else if (IS_HEAD(ch, BROKEN_SKULL))
  {
    act("$n's skull knits itself back together.", ch, NULL, NULL, TO_ROOM);
    act("Your skull knits itself back together.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_HEAD], BROKEN_SKULL);  
  }
  else if (IS_BODY(ch, BROKEN_SPINE))
  {
    act("$n's spine knits itself back together.", ch, NULL, NULL, TO_ROOM);
    act("Your spine knits itself back together.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_BODY], BROKEN_SPINE);  
  }
  else if (IS_BODY(ch, BROKEN_NECK))
  {
    act("$n's neck snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your neck snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_BODY], BROKEN_NECK);
  }
  else if (IS_ARM_L(ch, LOST_ARM))
  {
    act("An arm grows from the stump of $n's left shoulder.", ch, NULL, NULL, TO_ROOM);
    act("An arm grows from the stump of your left shoulder.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], LOST_ARM);  
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_ARM);
    SET_BIT(ch->loc_hp[LOC_ARM_L], LOST_HAND);
  }  
  else if (IS_ARM_R(ch, LOST_ARM))
  {
    act("An arm grows from the stump of $n's right shoulder.", ch, NULL, NULL, TO_ROOM);
    act("An arm grows from the stump of your right shoulder.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], LOST_ARM);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_ARM);
    SET_BIT(ch->loc_hp[LOC_ARM_R], LOST_HAND);
  }  
  else if (IS_LEG_L(ch, LOST_LEG))
  {  
    act("A leg grows from the stump of $n's left hip.", ch, NULL, NULL, TO_ROOM);
    act("A leg grows from the stump of your left hip.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_LEG_L], LOST_LEG);
    REMOVE_BIT(ch->loc_hp[LOC_LEG_L], BROKEN_LEG);
    SET_BIT(ch->loc_hp[LOC_LEG_L], LOST_FOOT);
  }
  else if (IS_LEG_R(ch, LOST_LEG))  
  {
    act("A leg grows from the stump of $n's right hip.", ch, NULL, NULL, TO_ROOM);
    act("A leg grows from the stump of your right hip.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_LEG_R], LOST_LEG);  
    REMOVE_BIT(ch->loc_hp[LOC_LEG_R], BROKEN_LEG);
    SET_BIT(ch->loc_hp[LOC_LEG_R], LOST_FOOT);
  }
  else if (IS_ARM_L(ch, BROKEN_ARM))
  {
    act("$n's left arm snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your left arm snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_ARM);
  }
  else if (IS_ARM_R(ch, BROKEN_ARM))
  {
    act("$n's right arm snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your right arm snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_ARM);
  }
  else if (IS_LEG_L(ch, BROKEN_LEG))
  {
    act("$n's left leg snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your left leg snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_LEG_L], BROKEN_LEG);
  }
  else if (IS_LEG_R(ch, BROKEN_LEG))
  {
    act("$n's right leg snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your right leg snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_LEG_R], BROKEN_LEG);
  }
  else if (IS_ARM_L(ch, LOST_HAND))
  {
    act("A hand grows from the stump of $n's left wrist.", ch, NULL, NULL, TO_ROOM);
    act("A hand grows from the stump of your left wrist.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], LOST_HAND);
    SET_BIT(ch->loc_hp[LOC_ARM_L], LOST_THUMB);
    SET_BIT(ch->loc_hp[LOC_ARM_L], LOST_FINGER_I);
    SET_BIT(ch->loc_hp[LOC_ARM_L], LOST_FINGER_M);
    SET_BIT(ch->loc_hp[LOC_ARM_L], LOST_FINGER_R);
    SET_BIT(ch->loc_hp[LOC_ARM_L], LOST_FINGER_L);
  }
  else if (IS_ARM_R(ch, LOST_HAND))
  {
    act("A hand grows from the stump of $n's right wrist.", ch, NULL, NULL, TO_ROOM);
    act("A hand grows from the stump of your right wrist.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], LOST_HAND);
    SET_BIT(ch->loc_hp[LOC_ARM_R], LOST_THUMB);
    SET_BIT(ch->loc_hp[LOC_ARM_R], LOST_FINGER_I);
    SET_BIT(ch->loc_hp[LOC_ARM_R], LOST_FINGER_M);
    SET_BIT(ch->loc_hp[LOC_ARM_R], LOST_FINGER_R);
    SET_BIT(ch->loc_hp[LOC_ARM_R], LOST_FINGER_L);
  }
  else if (IS_LEG_L(ch, LOST_FOOT)) 
  {
    act("A foot grows from the stump of $n's left ankle.", ch, NULL, NULL, TO_ROOM);
    act("A foot grows from the stump of your left ankle.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_LEG_L], LOST_FOOT); 
  }
  else if (IS_LEG_R(ch, LOST_FOOT))
  {
    act("A foot grows from the stump of $n's right ankle.", ch, NULL, NULL, TO_ROOM);
    act("A foot grows from the stump of your right ankle.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_LEG_R], LOST_FOOT);
  }
  else if (IS_ARM_L(ch, LOST_THUMB))
  {
    act("A thumb slides out of $n's left hand.", ch, NULL, NULL, TO_ROOM);
    act("A thumb slides out of your left hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], LOST_THUMB);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_THUMB);
  }
  else if (IS_ARM_L(ch, BROKEN_THUMB))
  {
    act("$n's left thumb snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your left thumb snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_THUMB);
  }
  else if (IS_ARM_L(ch, LOST_FINGER_I))
  {
    act("An index finger slides out of $n's left hand.", ch, NULL, NULL, TO_ROOM);
    act("An index finger slides out of your left hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], LOST_FINGER_I);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_FINGER_I);
  }
  else if (IS_ARM_L(ch, BROKEN_FINGER_I))
  {
    act("$n's left index finger snaps back into place.", ch, NULL, NULL, TO_ROOM);  
    act("Your left index finger snaps back into place.", ch, NULL, NULL, TO_CHAR);  
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_FINGER_I);
  }
  else if (IS_ARM_L(ch, LOST_FINGER_M))
  {
    act("A middle finger slides out of $n's left hand.", ch, NULL, NULL, TO_ROOM);
    act("A middle finger slides out of your left hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], LOST_FINGER_M);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_FINGER_M);
  }
  else if (IS_ARM_L(ch, BROKEN_FINGER_M))
  {
    act("$n's left middle finger snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your left middle finger snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_FINGER_M);
  }
  else if (IS_ARM_L(ch, LOST_FINGER_R))
  {
    act("A ring finger slides out of $n's left hand.", ch, NULL, NULL, TO_ROOM);
    act("A ring finger slides out of your left hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], LOST_FINGER_R);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_FINGER_R);
  }
  else if (IS_ARM_L(ch, BROKEN_FINGER_R))
  {
    act("$n's left ring finger snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your left ring finger snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_FINGER_R);
  }
  else if (IS_ARM_L(ch, LOST_FINGER_L))
  {
    act("A little finger slides out of $n's left hand.", ch, NULL, NULL, TO_ROOM);
    act("A little finger slides out of your left hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], LOST_FINGER_L);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_FINGER_L);
  }
  else if (IS_ARM_L(ch, BROKEN_FINGER_L))
  {
    act("$n's left little finger snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your left little finger snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_L], BROKEN_FINGER_L);
  }
  else if (IS_ARM_R(ch, LOST_THUMB))
  {
    act("A thumb slides out of $n's right hand.", ch, NULL, NULL, TO_ROOM);
    act("A thumb slides out of your right hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], LOST_THUMB);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_THUMB);
  }
  else if (IS_ARM_R(ch, BROKEN_THUMB))
  {
    act("$n's right thumb snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your right thumb snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_THUMB);
  }
  else if (IS_ARM_R(ch, LOST_FINGER_I))
  {
    act("An index finger slides out of $n's right hand.", ch, NULL, NULL, TO_ROOM);
    act("An index finger slides out of your right hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], LOST_FINGER_I);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_FINGER_I);
  }
  else if (IS_ARM_R(ch, BROKEN_FINGER_I))
  {
    act("$n's right index finger snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your right index finger snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_FINGER_I);
  }
  else if (IS_ARM_R(ch, LOST_FINGER_M))
  {
    act("A middle finger slides out of $n's right hand.", ch, NULL, NULL, TO_ROOM);
    act("A middle finger slides out of your right hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], LOST_FINGER_M);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_FINGER_M);
  }
  else if (IS_ARM_R(ch, BROKEN_FINGER_M))
  {
    act("$n's right middle finger snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your right middle finger snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_FINGER_M);
  }
  else if (IS_ARM_R(ch, LOST_FINGER_R))
  {
    act("A ring finger slides out of $n's right hand.", ch, NULL, NULL, TO_ROOM);
    act("A ring finger slides out of your right hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], LOST_FINGER_R);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_FINGER_R);
  }
  else if (IS_ARM_R(ch, BROKEN_FINGER_R))
  {
    act("$n's right ring finger snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your right ring finger snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_FINGER_R);
  }
  else if (IS_ARM_R(ch, LOST_FINGER_L))
  {
    act("A little finger slides out of $n's right hand.", ch, NULL, NULL, TO_ROOM);
    act("A little finger slides out of your right hand.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], LOST_FINGER_L);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_FINGER_L);
  }
  else if (IS_ARM_R(ch, BROKEN_FINGER_L))
  {
    act("$n's right little finger snaps back into place.", ch, NULL, NULL, TO_ROOM);
    act("Your right little finger snaps back into place.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_ARM_R], BROKEN_FINGER_L);
  }
  else if (IS_BODY(ch, CUT_THROAT))
  {
    if (IS_SET(ch->loc_hp[6], BLEEDING_THROAT))
      return;
    act("The wound in $n's throat closes up.", ch, NULL, NULL, TO_ROOM);
    act("The wound in your throat closes up.", ch, NULL, NULL, TO_CHAR);
    REMOVE_BIT(ch->loc_hp[LOC_BODY], CUT_THROAT);
  }
  return;
}


int is_wall(EXIT_DATA * ex)
{

  if (IS_SET(ex->exit_info, EX_ICE_WALL))
    return 1;
  if (IS_SET(ex->exit_info, EX_FIRE_WALL))
    return 2;
  if (IS_SET(ex->exit_info, EX_SWORD_WALL))
    return 3;
  if (IS_SET(ex->exit_info, EX_PRISMATIC_WALL))
    return 4;
  if (IS_SET(ex->exit_info, EX_IRON_WALL))
    return 5;
  if (IS_SET(ex->exit_info, EX_MUSHROOM_WALL))
    return 6;
  if (IS_SET(ex->exit_info, EX_CALTROP_WALL))
    return 7;
  if (IS_SET(ex->exit_info, EX_ASH_WALL))
    return 8;
  return 0;
}

/*
 * Update all rooooooms, like gore, poison clouds etc....
 */
void room_update(void)
{
  int i;
  ROOM_INDEX_DATA *room;

  for (room = room_list; room != NULL; room = room->next_room)
  {

    if (RTIMER(room, RTIMER_SILENCE) < 0)
      room->tick_timer[i] = UMAX(room->tick_timer[i], 0);
    if (RTIMER(room, RTIMER_SILENCE) == 1)
      room_message(room, "The silence disappates.");

    for (i = 0; i < MAX_RTIMER; i++)
      room->tick_timer[i] = UMAX(room->tick_timer[i] - 1, 0);

  }

  return;

}

/*
 * Update all chars, including mobs.
 * This function is performance sensitive.
 */
void char_update(void)
{
  AFFECT_DATA *paf;
  AFFECT_DATA *paf_next;
  QUEST_DATA *quest;
  QUEST_DATA *quest_next;
  CHAR_DATA *ch_quit = NULL;
  CHAR_DATA *ch_save = NULL;
  CHAR_DATA *ch;
  CHAR_DATA *ch_next;
  char buf[MAX_STRING_LENGTH];
  bool is_obj;
  time_t save_time;
  int count = 0, i;

  save_time = current_time;

  for (ch = char_list; ch != NULL; ch = ch_next)
  {
    ch_next = ch->next;
    count++;

    /*
     * Is the player an object ?
     */
    if (!IS_NPC(ch) && (IS_HEAD(ch, LOST_HEAD) || IS_EXTRA(ch, EXTRA_OSWITCH)))
      is_obj = TRUE;
    else if (!IS_NPC(ch) && ch->pcdata->obj_vnum != 0)
    {
      is_obj = TRUE;
      SET_BIT(ch->extra, EXTRA_OSWITCH);
    }
    else
      is_obj = FALSE;

    /* fae djinns */
    if (IS_NPC(ch))
    {
      if (ch->decay_pulse > 0)
      {
        if (--ch->decay_pulse <= 0)
        {
          act("$n vanishes in a puff of smoke.", ch, NULL, NULL, TO_ROOM);
          extract_char(ch, TRUE);
          continue;
        }
      }
    }

    /*
     * Tick Timers and other PC only stuff
     */
    if (!IS_NPC(ch))
    {
      if (ch->tick_timer[TIMER_CHALLENGE] == 1)
        send_to_char("You can use challenge again.\n\r", ch);

      for (i = 0; i < MAX_TIMER; i++)
        if (ch->tick_timer[i] > 0)
          ch->tick_timer[i]--;

      /*
       * update active quests
       */
      for (quest = ch->pcdata->quests; quest; quest = quest_next)
      {
        quest_next = quest->next;
        if (--quest->time > 0)
          continue;
        quest_from_char(ch, quest);
        send_to_char("You have failed to complete a quest.\n\r", ch);
      }

      /*
       * void, autosave, time bonus, etc
       */
      if ((ch->level < LEVEL_IMMORTAL || !ch->desc) && !is_obj && !IS_SET(ch->extra, EXTRA_AFK))
      {
        if ((ch->desc == NULL || ch->desc->connected == CON_PLAYING) && ch->level >= 2 && ch->save_time < save_time)
        {
          ch_save = ch;
          save_time = ch->save_time;
        }
        if (++ch->timer >= 12 && !in_fortress(ch))
        {
          if (ch->was_in_room == NULL && ch->in_room != NULL)
          {
            ch->was_in_room = ch->in_room;
            if (ch->fighting != NULL)
              stop_fighting(ch, TRUE);
            act("$n disappears into the void.", ch, NULL, NULL, TO_ROOM);
            send_to_char("You disappear into the void.\n\r", ch);
            save_char_obj(ch);
            char_from_room(ch);
            char_to_room(ch, get_room_index(ROOM_VNUM_LIMBO));
          }
        }
        update_active_counters(ch);
    update_regen(ch, 2);

        if (ch->timer > 20)
          ch_quit = ch;
      }
    }

    /*
     * updating spells on all mobs and players
     */
    for (paf = ch->affected; paf != NULL; paf = paf_next)
    {
      paf_next = paf->next;
      if (paf->duration > 0)
        paf->duration--;
      else
      {
        if (paf_next == NULL || paf_next->type != paf->type || paf_next->duration > 0)
        {
          if (paf->type > 0 && paf->type < MAX_SKILL && skill_table[paf->type].msg_off && !is_obj)
          {
            send_to_char(skill_table[paf->type].msg_off, ch);
            send_to_char("\n\r", ch);
          }
          else
          {
            sprintf(buf, "Update Bug : Bad affect on %s.", ch->name);
            bug(buf, 0);
          }
        }
        affect_remove(ch, paf);
      }
    }

    /*
     * Updating current position
     */
    if (ch->position == POS_MORTAL || ch->position == POS_STUNNED || ch->position == POS_INCAP)
    {
      update_pos(ch);
    }
    if (ch->position > POS_STUNNED && !is_obj)
    {
      if (ch->hit < ch->max_hit)
        ch->hit = UMIN(ch->hit + number_range(5, 10), ch->max_hit);
      if (ch->mana < ch->max_mana)
        ch->mana = UMIN(ch->mana + number_range(5, 10), ch->max_mana);
      if (ch->move < ch->max_move)
        ch->move = UMIN(ch->move + number_range(5, 10), ch->max_move);
    }
    else if (ch->position <= POS_STUNNED && !is_obj)
    {
      ch->hit = ch->hit + number_range(2, 4);
      update_pos(ch);
      if (ch->position > POS_STUNNED)
      {
        act("$n clambers back to $s feet.", ch, NULL, NULL, TO_ROOM);
        act("You clamber back to your feet.", ch, NULL, NULL, TO_CHAR);
      }
    }

    /*
     * Dealing damage due to missling limbs, etc.
     */
    if (ch->loc_hp[6] > 0 && !is_obj && ch->in_room != NULL)
    {
      int dam = 0;

      if (IS_BLEEDING(ch, BLEEDING_HEAD))
      {
        act("A spray of blood shoots from the stump of $n's neck.", ch, NULL, NULL, TO_ROOM);
        send_to_char("A spray of blood shoots from the stump of your neck.\n\r", ch);
        dam += number_range(20, 50);
      }
      if (IS_BLEEDING(ch, BLEEDING_THROAT))
      {
        act("Blood pours from the slash in $n's throat.", ch, NULL, NULL, TO_ROOM);
        send_to_char("Blood pours from the slash in your throat.\n\r", ch);
        dam += number_range(10, 20);
      }
      if (IS_BLEEDING(ch, BLEEDING_ARM_L))
      {
        act("A spray of blood shoots from the stump of $n's left arm.", ch, NULL, NULL, TO_ROOM);
        send_to_char("A spray of blood shoots from the stump of your left arm.\n\r", ch);
        dam += number_range(10, 20);
      }
      else if (IS_BLEEDING(ch, BLEEDING_HAND_L))
      {
        act("A spray of blood shoots from the stump of $n's left wrist.", ch, NULL, NULL, TO_ROOM);
        send_to_char("A spray of blood shoots from the stump of your left wrist.\n\r", ch);
        dam += number_range(5, 10);
      }
      if (IS_BLEEDING(ch, BLEEDING_ARM_R))
      {
        act("A spray of blood shoots from the stump of $n's right arm.", ch, NULL, NULL, TO_ROOM);
        send_to_char("A spray of blood shoots from the stump of your right arm.\n\r", ch);
        dam += number_range(10, 20);
      }
      else if (IS_BLEEDING(ch, BLEEDING_HAND_R))
      {
        act("A spray of blood shoots from the stump of $n's right wrist.", ch, NULL, NULL, TO_ROOM);
        send_to_char("A spray of blood shoots from the stump of your right wrist.\n\r", ch);
        dam += number_range(5, 10);
      }
      if (IS_BLEEDING(ch, BLEEDING_LEG_L))
      {
        act("A spray of blood shoots from the stump of $n's left leg.", ch, NULL, NULL, TO_ROOM);
        send_to_char("A spray of blood shoots from the stump of your left leg.\n\r", ch);
        dam += number_range(10, 20);
      }
      else if (IS_BLEEDING(ch, BLEEDING_FOOT_L))
      {
        act("A spray of blood shoots from the stump of $n's left ankle.", ch, NULL, NULL, TO_ROOM);
        send_to_char("A spray of blood shoots from the stump of your left ankle.\n\r", ch);
        dam += number_range(5, 10);
      }
      if (IS_BLEEDING(ch, BLEEDING_LEG_R))
      {
        act("A spray of blood shoots from the stump of $n's right leg.", ch, NULL, NULL, TO_ROOM);
        send_to_char("A spray of blood shoots from the stump of your right leg.\n\r", ch);
        dam += number_range(10, 20);
      }
      else if (IS_BLEEDING(ch, BLEEDING_FOOT_R))
      {
        act("A spray of blood shoots from the stump of $n's right ankle.", ch, NULL, NULL, TO_ROOM);
        send_to_char("A spray of blood shoots from the stump of your right ankle.\n\r", ch);
        dam += number_range(5, 10);
      }
      ch->hit = ch->hit - dam;
      if (ch->hit < 1)
        ch->hit = 1;
      update_pos(ch);
      ch->in_room->blood += dam;
      if (ch->in_room->blood > 1000)
        ch->in_room->blood = 1000;
    }
    if (IS_AFFECTED(ch, AFF_FLAMING) && !is_obj)
    {
      int dam;

      act("$n's flesh burns and crisps.", ch, NULL, NULL, TO_ROOM);
      send_to_char("Your flesh burns and crisps.\n\r", ch);
      dam = number_range(250, 300);
      ch->hit = ch->hit - dam;
      if (ch->hit < 1)
        ch->hit = 1;
      update_pos(ch);
    }

    /*
     * More damage stuff
     */
    if (IS_AFFECTED(ch, AFF_POISON) && !is_obj)
    {
      act("$n shivers and suffers.", ch, NULL, NULL, TO_ROOM);
      send_to_char("You shiver and suffer.\n\r", ch);
      ch->hit = ch->hit - number_range(100, 200);
      if (ch->hit < 1)
        ch->hit = 1;
      if (number_range(1, 4) == 1)
      {
        REMOVE_BIT(ch->affected_by, AFF_POISON);
        send_to_char("You feel the poison leave your system.\n\r", ch);
      }
    }

    /*
     * and then we do some healing - messy ?
     */
    if (ch->position == POS_INCAP && !is_obj)
    {
      ch->hit = ch->hit + number_range(2, 4);
      update_pos(ch);
      if (ch->position > POS_INCAP)
      {
        act("$n's wounds stop bleeding and seal up.", ch, NULL, NULL, TO_ROOM);
        send_to_char("Your wounds stop bleeding and seal up.\n\r", ch);
      }
      if (ch->position > POS_STUNNED)
      {
        act("$n clambers back to $s feet.", ch, NULL, NULL, TO_ROOM);
        send_to_char("You clamber back to your feet.\n\r", ch);
      }
    }
    else if (ch->position == POS_MORTAL && !is_obj)
    {
      ch->hit = ch->hit + number_range(2, 4);
      update_pos(ch);
      if (ch->position == POS_INCAP)
      {
        act("$n's wounds begin to close, and $s bones pop back into place.", ch, NULL, NULL, TO_ROOM);
        send_to_char("Your wounds begin to close, and your bones pop back into place.\n\r", ch);
      }
    }
  }

  /*
   * Autosave, Autoquit checks
   */
  if (ch_save != NULL || ch_quit != NULL)
  {
    for (ch = char_list; ch != NULL; ch = ch_next)
    {
      ch_next = ch->next;
      if (ch == ch_save)
        save_char_obj(ch);
      if (ch == ch_quit)
        do_quit(ch, "");
    }
  }
  return;
}

/*
 * Update all objs.
 * This function is performance sensitive.
 */
void obj_update(void)
{
  OBJ_DATA *obj;
  OBJ_DATA *obj_next;

  for (obj = object_list; obj != NULL; obj = obj_next)
  {
    CHAR_DATA *rch;
    char *message;

    obj_next = obj->next;
    if (obj->timer <= 0 || --obj->timer > 0)
      continue;

    switch (obj->item_type)
    {
      default:
        message = "$p vanishes.";
        break;
      case ITEM_FOUNTAIN:
        message = "$p dries up.";
        break;
      case ITEM_CORPSE_NPC:
        message = "$p decays into dust.";
        break;
      case ITEM_CORPSE_PC:
        message = "$p decays into dust.";
        break;
      case ITEM_FOOD:
        message = "$p decomposes.";
        break;
      case ITEM_TRASH:
        message = "$p crumbles into dust.";
        break;
//      case ITEM_WEAPON:
//        message = "$p turns to fine dust and blows away.";
//        break;
      case ITEM_WALL:
        message = "$p flows back into the ground.";
        break;
      case ITEM_GRENADE:
        message = "$p explodes in a shower of flames.";
        break;
    }

    if (obj->carried_by != NULL)
    {
      act(message, obj->carried_by, obj, NULL, TO_CHAR);
    }
    else if (obj->in_room != NULL && (rch = obj->in_room->people) != NULL)
    {
      act(message, rch, obj, NULL, TO_ROOM);
      act(message, rch, obj, NULL, TO_CHAR);
    }


    /*
     * BUGFIX : The famous extract_obj bug....
     *          basicly we just make sure that we don't skip into the obj_free list
     *          by accident. (That's what caused it).
     */

    if (obj == object_list)
    {
      extract_obj(obj);
      obj_next = object_list;
    }
    else
    {
      OBJ_DATA *bugObj;

      for (bugObj = object_list; bugObj; bugObj = bugObj->next)
      {
        if (bugObj->next == obj)
          break;
      }
      /*
       * This shouldn't happen, but if it does, I want to make sure we never see that object again,
       * so we let extract_obj() try and handle it, terminating to avoid further corruption.
       */
      if (!bugObj)
      {
        bug("obj_update: obj %d not in object_list. Terminating obj_update.", obj->pIndexData->vnum);
        return;
      }
      extract_obj(obj);
      obj_next = bugObj->next;
    }
  }

  return;
}


void ww_update(void)
{
  DESCRIPTOR_DATA *d;
  CHAR_DATA *victim;
  float dam = 0;

  for (d = descriptor_list; d != NULL; d = d->next)
  {
    if (!IS_PLAYING(d) || (victim = d->character) == NULL || IS_NPC(victim) || IS_IMMORTAL(victim) || victim->in_room == NULL || victim->pcdata->chobj != NULL)
    {
      continue;
    }
    if (!IS_SET(d->character->in_room->room_flags, ROOM_BLADE_BARRIER))
      continue;

    act("The scattered blades on the ground fly up into the air ripping into you.", d->character, NULL, NULL, TO_CHAR);
    act("The scattered blades on the ground fly up into the air ripping into $n.", d->character, NULL, NULL, TO_ROOM);

    act("The blades drop to the ground inert.", d->character, NULL, NULL, TO_CHAR);
    act("The blades drop to the ground inert.", d->character, NULL, NULL, TO_ROOM);

    dam = number_range(7, 14);
    dam = dam / 100;
    dam = d->character->hit * dam;
    if (dam < 100)
      dam = 100;
    d->character->hit = d->character->hit - dam;
    if (d->character->hit < -10)
      d->character->hit = -10;
    update_pos(victim);
  }

  return;
}

/*
 * Handle all kinds of updates.
 * Called once per pulse from game loop.
 * Random times to defeat tick-timing clients and players.
 */
void update_handler(void)
{
  static int pulse_area;
  static int pulse_mobile;
  static int pulse_violence;
  static int pulse_point;
  static int pulse_ww;
  static int pulse_mudinfo;
  static int pulse_track;

  recycle_descriptors();

  if (--pulse_track <= 0)
  {
    pulse_track = 2;
    update_trackers();
  }
  if (++ragnarok_timer > PULSE_RAGNAROK && ragnarok)
  {
    ragnarok_stop();
    ragnarok_timer = 0;
  }
  if (--pulse_ww <= 0)
  {
    pulse_ww = PULSE_WW;
    ww_update();
  }
  if (arena_open)
  {
    pulse_arena = PULSE_ARENA - (45 * PULSE_PER_SECOND + 1);
    arena_open = FALSE;
  }
  if (++pulse_arena >= PULSE_ARENA - 45 * PULSE_PER_SECOND)
  {
    if (pulse_arena < PULSE_ARENA && !arenaopen)
      open_arena();
    else if (pulse_arena >= PULSE_ARENA)
    {
      pulse_arena = 0;
      close_arena();
    }
  }
  if (--pulse_area <= 0)
  {
    pulse_area = number_range(PULSE_AREA / 2, 3 * PULSE_AREA / 2);
    area_update();
  }

  if (--pulse_mudinfo <= 0)
  {
    pulse_mudinfo = PULSE_THIRTY;
    update_mudinfo();
    update_polls();
    recycle_dummys();           // every 30 secs is enough
  }

  if (--pulse_mobile <= 0)
  {
    pulse_mobile = PULSE_MOBILE;
    mobile_update();
  }

  if (--pulse_violence <= 0)
  {
    pulse_violence = PULSE_VIOLENCE;
    violence_update ( );
    update_midi     ( );
  }
  if (--pulse_point <= 0)
  {
    pulse_point = number_range(PULSE_TICK / 2, 3 * PULSE_TICK / 2);
    weather_update();
    char_update();
    obj_update();
    room_update();

    /*
     * The following is some excessive force.
     * If the mud crashes again within a pulse from last crash,
     * let it go down to avoid crashloops.
     */
    if (iDelete == 0)
      iDelete++;
    else if (iDelete == 1)
    {
      unlink(CRASH_TEMP_FILE);
      iDelete++;
    }

  }

  tail_chain();
  return;
}

void update_morted_timer(CHAR_DATA * ch)
{
  if (ch->hit > 0 && ch->pcdata->mortal > 0)
    ch->pcdata->mortal = 0;
  else
  {
    ch->pcdata->mortal += 1;
    if (ch->pcdata->mortal > 10 && !in_fortress(ch))
    {
      ch->hit = 100;
      update_pos(ch);
      char_from_room(ch);
      char_to_room(ch, get_room_index(ROOM_VNUM_ALTAR));
      stc("You recieve a heal from the gods.\n\r", ch);
      ch->pcdata->mortal = 0;
      ch->fight_timer = 0;
    }
  }
}

void update_sit_safe_counter(CHAR_DATA * ch)
{
  if (IS_NPC(ch))
    return;

  if (ch->pcdata->safe_counter > 0)
  {
    ch->pcdata->safe_counter--;
    if (ch->pcdata->safe_counter == 0)
      send_to_char("You can now pk again.\n\r", ch);
  }
  if (IS_SET(ch->in_room->room_flags, ROOM_SAFE) && ch->level > 2 && ch->level < 7 && getMight(ch) >= 150)
  {
    if (!IS_SET(ch->extra, EXTRA_AFK))
      ch->pcdata->sit_safe += number_range(5, 10);

    if ((ch->pcdata->sit_safe > 200 || ch->fight_timer != 0) && !ragnarok && !ch->fighting)
    {
      stc("\nThe gods are tired of granting you refuge.\n\r", ch);
      char_from_room(ch);
      char_to_room(ch, get_room_index(ROOM_VNUM_TEMPLE));
    }
  }
  else
  {
    if (ch->pcdata->sit_safe > 0)
      ch->pcdata->sit_safe -= 10;
    else
      ch->pcdata->sit_safe = 0;
  }
}

void update_drunks(CHAR_DATA * ch)
{
  if (ch->pcdata->condition[COND_DRUNK] > 10 && number_range(1, 10) == 1)
  {
    send_to_char("You hiccup loudly.\n\r", ch);
    act("$n hiccups.", ch, NULL, NULL, TO_ROOM);
  }
  if (ch->pcdata->condition[COND_DRUNK] > 0 && number_range(1, 10) == 5)
  {
    ch->pcdata->condition[COND_DRUNK]--;
    if (ch->pcdata->condition[COND_DRUNK] == 0)
      send_to_char("You feel sober again.\n\r", ch);
  }
}

void sex_update(CHAR_DATA * ch)
{
  if (ch->pcdata->stage[0] > 0 || ch->pcdata->stage[2] > 0)
  {
    CHAR_DATA *vch;

    if (ch->pcdata->stage[1] > 0 && ch->pcdata->stage[2] >= 225)
    {
      ch->pcdata->stage[2] += 1;
      if ((vch = ch->pcdata->partner) != NULL &&
          !IS_NPC(vch) && vch->pcdata->partner == ch && ((vch->pcdata->stage[2] >= 200 && vch->sex == SEX_FEMALE) || (ch->pcdata->stage[2] >= 200 && ch->sex == SEX_FEMALE)))
      {
        if (ch->in_room != vch->in_room)
          return;
        if (vch->pcdata->stage[2] >= 225 && ch->pcdata->stage[2] >= 225 && vch->pcdata->stage[2] < 240 && ch->pcdata->stage[2] < 240)
        {
          ch->pcdata->stage[2] = 240;
          vch->pcdata->stage[2] = 240;
        }
        if (ch->sex == SEX_MALE && vch->pcdata->stage[2] >= 240)
        {
          act("You thrust deeply between $N's warm, damp thighs.", ch, NULL, vch, TO_CHAR);
          act("$n thrusts deeply between your warm, damp thighs.", ch, NULL, vch, TO_VICT);
          act("$n thrusts deeply between $N's warm, damp thighs.", ch, NULL, vch, TO_NOTVICT);
          if (vch->pcdata->stage[2] > ch->pcdata->stage[2])
            ch->pcdata->stage[2] = vch->pcdata->stage[2];
        }
        else if (ch->sex == SEX_FEMALE && vch->pcdata->stage[2] >= 240)
        {
          act("You squeeze your legs tightly around $N, moaning loudly.", ch, NULL, vch, TO_CHAR);
          act("$n squeezes $s legs tightly around you, moaning loudly.", ch, NULL, vch, TO_VICT);
          act("$n squeezes $s legs tightly around $N, moaning loudly.", ch, NULL, vch, TO_NOTVICT);
          if (vch->pcdata->stage[2] > ch->pcdata->stage[2])
            ch->pcdata->stage[2] = vch->pcdata->stage[2];
        }
      }
      if (ch->pcdata->stage[2] >= 250)
      {
        if ((vch = ch->pcdata->partner) != NULL && !IS_NPC(vch) && vch->pcdata->partner == ch && ch->in_room == vch->in_room)
        {
          vch->pcdata->stage[2] = 250;
          if (ch->sex == SEX_MALE)
          {
            stage_update(ch, vch, 2, "xm-thrust");
            stage_update(vch, ch, 2, "xf-squeeze");
          }
          else
          {
            stage_update(vch, ch, 2, "xm-thrust");
            stage_update(ch, vch, 2, "xf-squeeze");
          }

          ch->pcdata->stage[0] = 0;
          vch->pcdata->stage[0] = 0;

          if (!IS_EXTRA(ch, EXTRA_EXP))
          {
            send_to_char("Congratulations on achieving a simultanious orgasm!  Recieve 100000 exp!\n\r", ch);
            SET_BIT(ch->extra, EXTRA_EXP);
            ch->exp += 100000;
          }
          if (!IS_EXTRA(vch, EXTRA_EXP))
          {
            send_to_char("Congratulations on achieving a simultanious orgasm!  Recieve 100000 exp!\n\r", vch);
            SET_BIT(vch->extra, EXTRA_EXP);
            vch->exp += 100000;
          }
        }
      }
    }
    else
    {
      if (ch->pcdata->stage[0] > 0 && ch->pcdata->stage[2] < 1 && ch->position != POS_RESTING)
      {
        if (ch->pcdata->stage[0] > 1)
          ch->pcdata->stage[0] -= 1;
        else
          ch->pcdata->stage[0] = 0;
      }
      else if (ch->pcdata->stage[2] > 0 && ch->pcdata->stage[0] < 1)
      {
        if (ch->pcdata->stage[2] > 10)
          ch->pcdata->stage[2] -= 10;
        else
          ch->pcdata->stage[2] = 0;
        if (ch->sex == SEX_MALE && ch->pcdata->stage[2] == 0)
          send_to_char("You feel fully recovered.\n\r", ch);
      }
    }
  }
}

void regen_limb(CHAR_DATA * ch)
{
  if (ch->loc_hp[6] > 0)
  {
    int sn = skill_lookup("clot");

    (*skill_table[sn].spell_fun) (sn, ch->level, ch, ch);
  }
  else if ((ch->loc_hp[0] + ch->loc_hp[1] + ch->loc_hp[2] + ch->loc_hp[3] + ch->loc_hp[4] + ch->loc_hp[5]) != 0)
    reg_mend(ch);
  return;
}

void update_arti_regen(CHAR_DATA * ch)
{
  if (ch->hit < ch->max_hit || ch->mana < ch->max_mana || ch->move < ch->max_move)
    update_regen(ch, 2);
  regen_limb(ch);
  return;
}

void update_regen(CHAR_DATA * ch, int multiplier)
{
  int min = 5; // 5
  int max = 10; // 10
  int hit_gain = 0;
  int mana_gain = 0;
  int move_gain = 0;

  if (IS_NPC(ch))
    return;

  if (ch->position == POS_SLEEPING)
  {
    if (!IS_RACE(ch, RACE_TROLL))
    {
    min += 800;
    max += 1000;
    }
    else
    {
    min += 1400;
    max += 2000;
    }
    hit_gain += number_range(min, max);
    mana_gain += number_range(min, max);
    move_gain += number_range(min, max);
  }
  else
  {
    if (!IS_RACE(ch, RACE_TROLL))
    {
    min += 600;
    max += 700;
    }
    else
    {
    min += 1200;
    max += 1400;
    }
    hit_gain += number_range(min, max);
    mana_gain += number_range(min, max);
    move_gain += number_range(min, max);
  }
  ch->hit = UMIN(ch->hit + (hit_gain * multiplier), ch->max_hit);
  ch->mana = UMIN(ch->mana + (mana_gain * multiplier), ch->max_mana);
  ch->move = UMIN(ch->move + (move_gain * multiplier), ch->max_move);
  update_pos(ch);
  if (ch->hit >= ch->max_hit && ch->mana >= ch->max_mana && ch->move >= ch->max_move)
    send_to_char("Your body has completely regenerated itself.\n\r", ch);
  return;
}

void update_active_counters(CHAR_DATA *ch)
{
  /* we do not update idle players */
  if (ch->timer >= 6) return;

  if (ch->pcdata->time_tick < 250) ch->pcdata->time_tick++;
}

