AwakeMUD-0.51Beta/area/
AwakeMUD-0.51Beta/doc/
AwakeMUD-0.51Beta/lib/
AwakeMUD-0.51Beta/lib/etc/
AwakeMUD-0.51Beta/lib/fixer_data/
AwakeMUD-0.51Beta/lib/misc/
AwakeMUD-0.51Beta/lib/plrobjs/
AwakeMUD-0.51Beta/lib/plrobjs/A-E/
AwakeMUD-0.51Beta/lib/plrobjs/K-O/
AwakeMUD-0.51Beta/lib/plrobjs/U-Z/
AwakeMUD-0.51Beta/lib/plrspells/A-E/
AwakeMUD-0.51Beta/lib/plrtext/A-E/
AwakeMUD-0.51Beta/lib/world/
AwakeMUD-0.51Beta/lib/world/mob/
AwakeMUD-0.51Beta/lib/world/obj/
AwakeMUD-0.51Beta/lib/world/qst/
AwakeMUD-0.51Beta/lib/world/shp/
AwakeMUD-0.51Beta/lib/world/wld/
AwakeMUD-0.51Beta/lib/world/zon/
/* ************************************************************************
*   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, 94 by the Trustees of the Johns Hopkins University *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <assert.h>
#include <string.h>

#include "structs.h"
#include "awake.h"
#include "utils.h"
#include "spells.h"
#include "comm.h"
#include "db.h"
#include "dblist.h"
#include "handler.h"
#include "interpreter.h"

extern class objList ObjList;
extern struct char_data *character_list;
extern struct room_data *world;
extern int check_spirit_sector(int room, int spirit);
extern int is_allergic(struct char_data *ch, int type);
extern int max_exp_gain;
extern int max_exp_loss;
extern int fixers_need_save;
extern int modify_target(struct char_data *ch);
extern int spell_resist(struct char_data *ch);
extern int reverse_web(struct char_data *ch, int &skill, int &target);
extern "C" pid_t getpid(void);
extern const char *composition_names[];
extern void save_etext(struct char_data *ch);
extern void write_spells(struct char_data *ch);
extern void check_trace(struct char_data *ic);
extern void end_quest(struct char_data *ch);
extern void save_fixer_data(struct char_data *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 */
}

void mental_gain(struct char_data * ch)
{
  int gain = 0;

  if (IS_PERSONA(ch) || IS_PROJECT(ch))
    return;

  if (IS_IC(ch)) {
    GET_MENTAL(ch) = MIN(GET_MAX_MENTAL(ch), GET_MENTAL(ch) + 100);
    return;
  }
  if (IS_AFFECTED(ch, AFF_SLEEP)) {
    REMOVE_BIT(AFF_FLAGS(ch), AFF_SLEEP);
    return;
  }

  switch (GET_POS(ch)) {
    case POS_STUNNED:  gain = 20; break;
    case POS_SLEEPING: gain = 25; break;
    case POS_RESTING:  gain = 20; break;
    case POS_SITTING:  gain = 15; break;
    case POS_FIGHTING: gain = 5;  break;
    case POS_STANDING: gain = 10; break;
  }

  if (IS_NPC(ch))
    gain *= 2;
  else if (GET_LEVEL(ch) < LVL_LEGEND)
    switch (GET_RACE(ch)) {
      case RACE_HUMAN:
        if (GET_AGE(ch) >= 60)
          gain -= (int)((GET_AGE(ch) - 58) / 2);
        break;
      case RACE_DWARF:
        if (GET_AGE(ch) >= 130)
          gain -= (int)((GET_AGE(ch) - 125) / 5);
        break;
      case RACE_ELF:
        if (GET_AGE(ch) >= 325)
          gain -= (int)((GET_AGE(ch) - 315) / 10);
        break;
      case RACE_ORK:
        if (GET_AGE(ch) >= 50)
          gain -= (int)((GET_AGE(ch) - 48) / 2);
        break;
      case RACE_TROLL:
        if (GET_AGE(ch) >= 54)
          gain -= (int)((GET_AGE(ch) - 52) / 2);
        break;
    }

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

  gain = MAX(1, gain);

  GET_MENTAL(ch) = MIN(GET_MAX_MENTAL(ch), GET_MENTAL(ch) + gain);
}

void physical_gain(struct char_data * ch)
{
  int gain = 0;
  struct obj_data *bio;

  if (IS_IC(ch) || IS_PERSONA(ch) || IS_PROJECT(ch))
    return;

  switch (GET_POS(ch)) {
    case POS_STUNNED:  gain = 13; break;
    case POS_SLEEPING: gain = 15; break;
    case POS_RESTING:  gain = 13; break;
    case POS_SITTING:  gain = 10; break;
    case POS_FIGHTING: gain = 5;  break;
    case POS_STANDING: gain = 7;  break;
  }

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

  if (IS_NPC(ch))
    gain *= 2;
  else {
    if (GET_LEVEL(ch) < LVL_LEGEND)
      switch (GET_RACE(ch)) {
        case RACE_HUMAN:
          if (GET_AGE(ch) >= 60)
            gain -= (int)((GET_AGE(ch) - 57) / 3);
          break;
        case RACE_DWARF:
          if (GET_AGE(ch) >= 130)
            gain -= (int)((GET_AGE(ch) - 124) / 6);
          break;
        case RACE_ELF:
          if (GET_AGE(ch) >= 325)
            gain -= (int)((GET_AGE(ch) - 313) / 12);
          break;
        case RACE_ORK:
          if (GET_AGE(ch) >= 50)
            gain -= (int)((GET_AGE(ch) - 47) / 3);
          break;
        case RACE_TROLL:
          if (GET_AGE(ch) >= 55)
            gain -= (int)((GET_AGE(ch) - 52) / 3);
          break;
      }
    gain = MAX(1, gain);
    for (bio = ch->bioware; bio; bio = bio->next_content)
      if (GET_OBJ_VAL(bio, 2) == 1) {
        switch (GET_OBJ_VAL(bio, 0)) {
          case 1: gain = (int)(gain * 10/9); break;
          case 2: gain = (int)(gain * 7/5);  break;
          case 3: gain *= 2;                 break;
        }
        break;
      }
  }

  GET_PHYSICAL(ch) = MIN(GET_MAX_PHYSICAL(ch), GET_PHYSICAL(ch) + gain);
}

int move_gain(struct char_data * ch)
{
  int gain;

  if (IS_NPC(ch)) {
    return (GET_BOD(ch) * 5);
  } else {
    gain = graf(age(ch).year, 16, 20, 24, 20, 16, 12, 10);

    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_AFFECTED(ch, AFF_POISON))
    gain >>= 2;

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

  if (IS_IC(ch) || IS_PERSONA(ch))
    gain = 0;

  return (gain);
}

void set_title(struct char_data * ch, char *title)
{
  if (title == NULL)
    title = "";

  if (strlen(title) > MAX_TITLE_LENGTH)
    title[MAX_TITLE_LENGTH] = '\0';

  if (GET_TITLE(ch) != NULL)
    delete [] GET_TITLE(ch);

  GET_TITLE(ch) = str_dup(title);
}


void set_whotitle(struct char_data * ch, char *title)
{
  if (title == NULL)
    title = "title";

  if (strlen(title) > 5)
    title[5] = '\0';

  if (GET_WHOTITLE(ch) != NULL)
    delete [] GET_WHOTITLE(ch);

  GET_WHOTITLE(ch) = str_dup(title);
}

void set_pretitle(struct char_data * ch, char *title)
{
  if (title == NULL)
    title = "";

  if (strlen(title) > MAX_TITLE_LENGTH)
    title[MAX_TITLE_LENGTH] = '\0';

  if (GET_PRETITLE(ch) != NULL)
    delete [] GET_PRETITLE(ch);

  GET_PRETITLE(ch) = str_dup(title);
}

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) >= LVL_LEGEND) {
    sprintf(buf, "nice ../bin/autowiz %d %s %d %s %d &", min_wizlist_lev,
            WIZLIST_FILE, LVL_LEGEND, IMMLIST_FILE, (int) getpid());
    mudlog("Initiating autowiz.", NULL, LOG_SYSLOG, FALSE);
    system(buf);
  }
}

int gain_exp(struct char_data * ch, int gain)
{
  int max_gain, old = (int)(GET_KARMA(ch) / 100);

  if (!IS_NPC(ch) && ((GET_LEVEL(ch) < 1 || GET_LEVEL(ch) >= LVL_LEGEND)))
    return 0;

  if (IS_NPC(ch)) {
    GET_KARMA(ch) += (int)(gain / 10);
    return (int)(gain / 10);
  }

  max_gain = (PLR_FLAGGED(ch, PLR_NEWBIE) ? 20 : GET_REP(ch) * 2);

  if (gain > 0) {
    gain = MIN(max_gain, gain); /* put a cap on the max gain per kill */
    GET_KARMA(ch) += gain;
    GET_REP(ch) += (int)(GET_KARMA(ch) / 100) - old;
  } else if (gain < 0) {
    gain = MAX(-max_exp_loss, gain);    /* Cap max exp lost per death */
    GET_KARMA(ch) += gain;
    if (GET_KARMA(ch) < 0)
      GET_KARMA(ch) = 0;
    GET_REP(ch) += (int)(GET_KARMA(ch) / 100) - old;
  }

  return gain;
}

void gain_exp_regardless(struct char_data * ch, int gain)
{
  int is_altered = FALSE;
  int old = (int)(GET_KARMA(ch) / 100);

  if (!IS_NPC(ch)) {
    GET_KARMA(ch) += gain;
    if (GET_KARMA(ch) < 0)
      GET_KARMA(ch) = 0;
    GET_REP(ch) += (int)(GET_KARMA(ch) / 100) - old;

//    while (!access_level(ch, LVL_OWNER)) {
//      send_to_char("You rise a level!\r\n", ch);
//      GET_LEVEL(ch) += 1;
//      advance_level(ch);
//      is_altered = TRUE;
//    }

    if (is_altered) {
      check_autowiz(ch);
    }
  } else {
    GET_KARMA(ch) += gain;
    if (GET_KARMA(ch) < 0)
      GET_KARMA(ch) = 0;
  }
}

// only the pcs should need to access this
void gain_condition(struct char_data * ch, int condition, int value)
{
  bool intoxicated;
  struct obj_data *bio;

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

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

  if (value == -1)
    for (bio = ch->bioware; bio; bio = bio->next_content)
      if (GET_OBJ_VAL(bio, 2) == 1) {
        switch (GET_OBJ_VAL(bio, 0)) {
          case 1:
            if (GET_OBJ_VAL(bio, 6))
              value--;
            GET_OBJ_VAL(bio, 6) = !GET_OBJ_VAL(bio, 6);
            break;
          case 2:
            if (!(GET_OBJ_VAL(bio, 6) % 3))
              value--;
            if ((++GET_OBJ_VAL(bio, 6)) > 9)
              GET_OBJ_VAL(bio, 6) = 0;
            break;
          case 3:
            value--;
            break;
        }
      } else if (GET_OBJ_VAL(bio, 2) == 5)
        value--;

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

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

void resist_petrify(struct char_data *ch)
{
  extern const char *spell_wear_off_msg[];
  struct affected_type *af;
  int resist = 0;

  for (af = ch->affected; af; af = af->next)
    if (af->type == SPELL_PETRIFY) {
      resist = GET_BOD(ch);
      break;
    } else if (af->type == SPELL_OVERSTIMULATION) {
      resist = GET_WIL(ch);
      break;
    }

  if (!resist || !af)
    return;

  if (success_test(resist + spell_resist(ch), af->modifier + modify_target(ch)) > 0) {
    send_to_char(ch, "%s\r\n", spell_wear_off_msg[af->type]);
    if (af->type == SPELL_PETRIFY)
      act("$n's skin returns to normal.", TRUE, ch, 0, 0, TO_ROOM);
    affect_remove(ch, af, 1);
  }
}

void resist_poison(struct char_data *ch)
{
  extern const char *spell_wear_off_msg[];
  struct affected_type *af;
  struct obj_data *obj;
  int resist = GET_BOD(ch), success, dam;

  for (af = ch->affected; af; af = af->next)
    if (af->type == SPELL_POISON)
      break;

  for (obj = ch->cyberware; obj; obj = obj->next_content)
    if (GET_OBJ_VAL(obj, 2) == 25)
      resist += GET_OBJ_VAL(obj, 0);

  obj = GET_EQ(ch, WEAR_PATCH);
  resist += (obj && GET_OBJ_VAL(obj, 0) == 0 ? GET_OBJ_VAL(obj, 1) : 0);

  success = resisted_test(resist, af->duration + modify_target(ch), af->duration, resist);
  dam = convert_damage(stage(-success, af->modifier));

  if (!dam && af) {
    send_to_char(ch, "%s\r\n", spell_wear_off_msg[af->type]);
    affect_remove(ch, af, 1);
  } else damage(ch, ch, dam, SPELL_POISON, PHYSICAL);
}

void remove_patch(struct char_data *ch)
{
  struct obj_data *patch = GET_EQ(ch, WEAR_PATCH);
  int stun;

  if (!patch)
    return;

  switch (GET_OBJ_VAL(patch, 0)) {
    case 0:
      if (AFF_FLAGGED(ch, AFF_POISON) && affected_by_spell(ch, SPELL_POISON) != 1) {
        REMOVE_BIT(AFF_FLAGS(ch), AFF_POISON);
        send_to_char("You feel the effects of the toxin dissipate.\r\n", ch);
      }
      break;
    case 1:
      act("The effects of $p wear off, leaving you exhausted!", FALSE, ch, patch, 0, TO_CHAR);
      GET_MENTAL(ch) = MAX(0, GET_MENTAL(ch) - (GET_OBJ_VAL(patch, 1) - 1) * 100);
      if (GET_TRADITION(ch) == TRAD_HERMETIC || GET_TRADITION(ch) == TRAD_SHAMANIC &&
          success_test(GET_MAGIC(ch), GET_OBJ_VAL(patch, 1)) < 0) {
        send_to_char("You feel your magical ability decline.\r\n", ch);
        ch->real_abils.mag = MAX(0, ch->real_abils.mag - 100);
        affect_total(ch);
      }
      update_pos(ch);
      break;
    case 2:
      stun = resisted_test(GET_OBJ_VAL(patch, 1), GET_BOD(ch),
                           GET_BOD(ch), GET_OBJ_VAL(patch, 1));
      if (stun > 0) {
        act("You feel the drugs from $p take effect.", FALSE, ch, patch, 0, TO_CHAR);
        GET_MENTAL(ch) = MAX(0, GET_MENTAL(ch) - (stun * 100));
        update_pos(ch);
      } else act("You resist the feeble effects of $p.", FALSE, ch, patch, 0, TO_CHAR);
      break;
    case 3:
      if (success_test(ch->real_abils.bod, GET_OBJ_VAL(patch, 1)) > 0)
        SET_BIT(AFF_FLAGS(ch), AFF_STABILIZE);
      break;
  }
  GET_EQ(ch, WEAR_PATCH) = NULL;
  patch->worn_by = NULL;
  patch->worn_on = -1;
  extract_obj(patch);
}

void check_idling(void)
{
  extern int free_rent;
  extern void Crash_rentsave(struct char_data *, int);
  void perform_immort_invis(struct char_data *ch, int level);
  ACMD(do_return);
  ACMD(do_disconnect);
  struct char_data *ch, *next;

  for (ch = character_list; ch; ch = next) {
    next = ch->next;

    if (IS_NPC(ch) && ch->desc && ch->desc->original) {
      if (ch->desc->original->char_specials.timer > 10) {
        if (IS_PERSONA(ch))
          do_disconnect(ch, "", 0, SCMD_MORTED);
        else do_return(ch, "", 0, 0);
      }
    } else if (!IS_NPC(ch)) {
      ch->char_specials.timer++;
      if (GET_LEVEL(ch) < LVL_LEGEND) {
        if (GET_WAS_IN(ch) == NOWHERE && ch->in_room != NOWHERE &&
            ch->char_specials.timer > 15) {
          GET_WAS_IN(ch) = ch->in_room;
          if (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.\r\n", ch);
          char_from_room(ch);
          char_to_room(ch, 1);
        } else if (ch->char_specials.timer > 30) {
          if (ch->in_room != NOWHERE)
            char_from_room(ch);
          char_to_room(ch, 1);
          if (ch->desc)
            close_socket(ch->desc);
          ch->desc = NULL;
          if (GET_QUEST(ch))
            end_quest(ch);
          if (free_rent)
            Crash_rentsave(ch, 0);
          else Crash_idlesave(ch);
          sprintf(buf, "%s force-rented and extracted (idle).", GET_NAME(ch));
          mudlog(buf, ch, LOG_MISCLOG, TRUE);
          extract_char(ch);
        }
      } else if (!ch->desc && ch->char_specials.timer > 15) {
        sprintf(buf, "%s removed from game (no link).", GET_NAME(ch));
        mudlog(buf, ch, LOG_MISCLOG, FALSE);
        Crash_rentsave(ch, 0);
        extract_char(ch);
      } else if (GET_LEVEL(ch) >= LVL_LEGEND && ch->char_specials.timer > 15 &&
                 GET_INVIS_LEV(ch) < 2 && IS_SET(PRF_FLAGS(ch), PRF_AUTOINVIS))
        perform_immort_invis(ch, 2);
    }
  }
}

void check_bioware(struct char_data *ch)
{
  if (!ch->desc || (ch->desc && ch->desc->connected))
    return;

  struct obj_data *bio;
  int dam = 0;

  for (bio = ch->bioware; bio; bio = bio->next_content)
    if (GET_OBJ_VAL(bio, 2) == 0)
      break;

  if (bio && GET_OBJ_VAL(bio, 2) == 0) {
    if (GET_OBJ_VAL(bio, 5) < 1) {
      if (!success_test(GET_BOD(ch),
          3 + modify_target(ch) + (int)(GET_OBJ_VAL(bio, 6) / 2))) {
        dam = convert_damage(stage(-success_test(GET_BOD(ch), 4 +
                                   modify_target(ch)), DEADLY));
        send_to_char("Your blood seems to erupt.\r\n", ch);
        damage(ch, ch, dam, TYPE_BIOWARE, PHYSICAL);
      }
      GET_OBJ_VAL(bio, 5) = 12;
      GET_OBJ_VAL(bio, 6)++;
    } else GET_OBJ_VAL(bio, 5)--;
  }
}

void check_swimming(struct char_data *ch)
{
  int target, skill, i, dam, test;

  if (IS_NPC(ch) || GET_LEVEL(ch) >= LVL_LEGEND)
    return;

  target = MAX(2, world[ch->in_room].rating);
  if (GET_POS(ch) < POS_RESTING) {
    target -= success_test(MAX(1, (int)(ch->real_abils.bod / 3)), target);
    dam = convert_damage(stage(target, 0));
    if (dam > 0) {
      act("$n's unconscious body is mercilessly thrown about by the current.",
          FALSE, ch, 0, 0, TO_ROOM);
      damage(ch, ch, dam, TYPE_DROWN, FALSE);
    }
    return;
  }
  skill = SKILL_ATHLETICS;
  if (!GET_SKILL(ch, skill))
    i = reverse_web(ch, skill, target);
  else i = GET_SKILL(ch, skill);
  i = resisted_test(i, target + modify_target(ch), target, i);
  if (i < 0) {
    test = success_test(GET_WIL(ch), modify_target(ch) - i);
    dam = convert_damage(stage(-test, SERIOUS));
    if (dam > 0) {
      send_to_char(ch, "You struggle to prevent your lungs getting "
                       "flooded with water.\r\n");
      damage(ch, ch, dam, TYPE_DROWN, FALSE);
    }
  } else if (!i) {
    test = success_test(GET_WIL(ch), 3 + modify_target(ch));
    dam = convert_damage(stage(-test, MODERATE));
    if (dam > 0) {
      send_to_char(ch, "You struggle to prevent your lungs getting "
                       "flooded with water.\r\n");
      damage(ch, ch, dam, TYPE_DROWN, FALSE);
    }
  } else if (i < 3) {
    test = success_test(GET_WIL(ch), 5 - i + modify_target(ch));
    dam = convert_damage(stage(-test, LIGHT));
    if (dam > 0) {
      send_to_char(ch, "You struggle to prevent your lungs getting "
                       "flooded with water.\r\n");
      damage(ch, ch, dam, TYPE_DROWN, FALSE);
    }
  }
}

void cycle_allergy(struct char_data *ch)
{
  int i;

  if (PLR_FLAGGED(ch, PLR_NEWBIE))
    return;

  if (GET_SEVERITY(ch) < REACT_SEVERE) {
    if (GET_ALLERGY(ch) != ALLERGIC_SUNLIGHT) {
      for (i = 0; i < NUM_WEARS; i++)
        if (GET_EQ(ch, i) && is_allergic(ch, GET_OBJ_RENT(GET_EQ(ch, i))) &&
            (i == WEAR_WIELD || i == WEAR_HOLD ? !GET_EQ(ch, WEAR_HANDS) : TRUE)) {
          send_to_char(ch, "Your skin tingles from contact with %s.\r\n",
                       composition_names[GET_OBJ_RENT(GET_EQ(ch, i))]);
          return;
        }
    } else if (IS_LIGHT(ch->in_room) && weather_info.sunlight >= SUN_RISE &&
               OUTSIDE(ch) && weather_info.sky < SKY_RAINING) {
      send_to_char("The presence of sunlight makes your skin tingle.\r\n", ch);
      return;
    }
    return;
  }
  if (GET_ALLERGY(ch) != ALLERGIC_SUNLIGHT) {
    for (i = 0; i < NUM_WEARS; i++)
      if (GET_EQ(ch, i) && is_allergic(ch, GET_OBJ_RENT(GET_EQ(ch, i))) &&
          (i == WEAR_WIELD || i == WEAR_HOLD ? !GET_EQ(ch, WEAR_HANDS) : TRUE)) {
        send_to_char(ch, "Prolonged contact with %s fills your mind with pain!\r\n",
                     composition_names[GET_OBJ_RENT(GET_EQ(ch, i))]);
        damage(ch, ch, 1, TYPE_ALLERGY, PHYSICAL);
        return;
      }
  } else if (IS_LIGHT(ch->in_room) && weather_info.sunlight >= SUN_RISE &&
             OUTSIDE(ch) && weather_info.sky < SKY_RAINING) {
    send_to_char("Prolonged contact with sunlight fills your mind with pain!\r\n", ch);
    damage(ch, ch, 1, TYPE_ALLERGY, PHYSICAL);
    return;
  }
  return;
}

void process_regeneration(int half_hour)
{
  struct char_data *ch, *next_char;

  for (ch = character_list; ch; ch = next_char) {
    next_char = ch->next;

    if ((affected_by_spell(ch, SPELL_PETRIFY) == 1 ||
        affected_by_spell(ch, SPELL_OVERSTIMULATION) == 1) && half_hour)
      resist_petrify(ch);
    if (affected_by_spell(ch, SPELL_POISON) == 1 && half_hour)
      resist_poison(ch);
    else if (AFF_FLAGGED(ch, AFF_POISON) && half_hour)
      damage(ch, ch, 1, SPELL_POISON, PHYSICAL);
    else if (GET_POS(ch) >= POS_STUNNED) {
      physical_gain(ch);
      mental_gain(ch);
      if (!IS_NPC(ch) && SECT(ch->in_room) == SECT_WATER_SWIM && half_hour)
        check_swimming(ch);
      if (GET_POS(ch) == POS_STUNNED)
        update_pos(ch);
    } else if (AFF_FLAGGED(ch, AFF_STABILIZE) && half_hour)
      REMOVE_BIT(AFF_FLAGS(ch), AFF_STABILIZE);
    else if (GET_POS(ch) <= POS_INCAP && half_hour)
      damage(ch, ch, 1, TYPE_SUFFERING, PHYSICAL);
  }
}

/* Update PCs, NPCs, and objects */
void point_update(void)
{
  SPECIAL(fixer);
  struct char_data *i, *next_char;

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

    if (!IS_NPC(i)) {
      Crash_crashsave(i);
      save_char(i, GET_LOADROOM(i));
      if ( GET_TRADITION(i) != TRAD_MUNDANE )
          write_spells(i);
      save_etext(i);
      REMOVE_BIT(PLR_FLAGS(i), PLR_CRASH);

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

      if (GET_LEVEL(i) >= LVL_LEGEND) {
        GET_NUYEN(i) = 0;
        GET_BANK(i) = 0;
      }

      if (i->bioware)
        check_bioware(i);
      // check to see if char just died, as check_bioware might kill
      if (!PLR_FLAGGED(i, PLR_JUST_DIED) && GET_ALLERGY(i) &&
          GET_POS(i) > POS_SLEEPING && GET_LEVEL(i) < LVL_LEGEND)
        cycle_allergy(i);
    } else {
      if (GET_MOB_SPEC(i) && GET_MOB_SPEC(i) == fixer && fixers_need_save)
        save_fixer_data(i);
      GET_MOOD(i) = MAX(-5, MIN(4, GET_MOOD(i) + number(-1, 1)));
    }

    if (IS_NPC(i) || !PLR_FLAGGED(i, PLR_JUST_DIED)) {
      if (LAST_HEAL(i) > 0)
        LAST_HEAL(i)--;
      else if (LAST_HEAL(i) < 0)
        LAST_HEAL(i)++;
      if (GET_EQ(i, WEAR_PATCH))
        remove_patch(i);
    }
  }

  // process the objects in the object list
   ObjList.UpdateCounters();
}

void misc_update(void)
{
  struct char_data *ch, *next_ch;
  struct obj_data *obj, *o = NULL;
  struct affected_type *af;
  int i;

  // first go through the objects...extract temp items on mortals
  ObjList.RemoveObjs();

  // loop through all the characters
  for (ch = character_list; ch; ch = next_ch) {
    next_ch = ch->next;

    for (af = ch->affected; af; af = af->next)
      if ((af->type == SPELL_HEAL || af->type == SPELL_ANTIDOTE ||
          af->type == SPELL_STABILIZE || af->type == SPELL_CURE_DISEASE) &&
          !af->caster) {
        if (af->duration > 0)
          af->duration--;
        else affect_remove(ch, af, 0);
      }

    if (IS_NPC(ch) && !ch->desc && GET_MOB_VNUM(ch) >= 20 &&
        GET_MOB_VNUM(ch) <= 22) {
      act("$n dissolves into the background and is no more.",
          TRUE, ch, 0, 0, TO_ROOM);
      for (i = 0; i < NUM_WEARS; i++)
        if (ch->equipment[i])
          extract_obj(ch->equipment[i]);
      for (obj = ch->carrying; obj; obj = o) {
        o = obj->next_content;
        extract_obj(obj);
      }
      extract_char(ch);
    } else if (IS_NPC(ch) && !ch->desc && GET_MOB_VNUM(ch) >= 50 &&
               GET_MOB_VNUM(ch) < 70)
      extract_char(ch);
    else if (IS_SPIRIT(ch) && GET_MOB_VNUM(ch) >= 25 &&
             GET_MOB_VNUM(ch) <= 41) {
      if (GET_ACTIVE(ch) < 1) {
        act("$s service fulfilled, $n dissolves from existence.",
            TRUE, ch, 0, 0, TO_ROOM);
        act("Your pitiful life as a slave to a mortal is over."
            "Have a nice nonexistence!", FALSE, ch, 0, 0, TO_CHAR);
        extract_char(ch);
      } else if (!check_spirit_sector(ch->in_room, GET_MOB_VNUM(ch) - 24)) {
        act("Being away from its environment, $n suddenly ceases to "
            "physically exist.", TRUE, ch, 0, 0, TO_ROOM);
        act("You feel extremely homesick, and depart the depressing "
            "physical realm.", FALSE, ch, 0, 0, TO_CHAR);
        extract_char(ch);
      }
    } else if (IS_IC(ch)) {
      check_trace(ch);
      if (AFF_FLAGGED(ch, AFF_COUNTER_ATT))
        REMOVE_BIT(AFF_FLAGS(ch), AFF_COUNTER_ATT);
    }
  }
}