deltamud/deltamud/
deltamud/deltamud/bin/
deltamud/deltamud/cnf/
deltamud/deltamud/lib/
deltamud/deltamud/lib/etc/
deltamud/deltamud/lib/misc/
deltamud/deltamud/lib/plrobjs/
deltamud/deltamud/lib/text/
deltamud/deltamud/lib/text/help/
deltamud/deltamud/lib/world/
deltamud/deltamud/lib/world/trg/
/* ************************************************************************
   *   File: handler.c                                     Part of CircleMUD *
   *  Usage: internal funcs: moving and finding chars/objs                   *
   *                                                                         *
   *  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 "conf.h"
#include "sysdep.h"

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "db.h"
#include "handler.h"
#include "interpreter.h"
#include "spells.h"
#include "dg_scripts.h"
#include "gcmd.h"

/* external vars */
extern int top_of_world;
extern int weaponrestrictions;
extern struct room_data *world;
extern struct obj_data *object_list;
extern struct char_data *character_list;
extern struct index_data *mob_index;
extern struct index_data *obj_index;
extern struct descriptor_data *descriptor_list;
extern int lvl_maxdmg_weapon[LVL_IMMORT];
extern char *MENU;

/* external functions */
void free_char (struct char_data *ch);
void stop_fighting (struct char_data *ch);
void remove_follower (struct char_data *ch);
void clearMemory (struct char_data *ch);

char *
fname (char *namelist)
{
  static char holder[30];
  register char *point=NULL;

  if (namelist != NULL)
    for (point = holder; isalpha (*namelist); namelist++, point++)
      *point = *namelist;

  *point = '\0';

  return (holder);
}

#define WHITESPACE " \t"

int isname(char *str, char *namelist)
{
  char *newlist;
  char *curtok;
  if (!namelist || !str) return 0;
  newlist = strdup(namelist); /* make a copy since strtok 'modifies'
strings */

  for(curtok = strtok(newlist, WHITESPACE); curtok; curtok = strtok(NULL,
		WHITESPACE))
     if(curtok && is_abbrev(str, curtok))
     {
        free(newlist); 
        return 1;
     }
  free(newlist);
  return 0;
}
int is_name(char *str, char *namelist)
{
  register char *curname, *curstr;
  if (!namelist || !str) return 0;
  curname = namelist;
  for (;;) {
    for (curstr = str;; curstr++, curname++) {
      if (!*curstr && !isalpha(*curname))
        return (1);

      if (!*curname)
        return (0);

      if (!*curstr || *curname == ' ')
        break;

      if (LOWER(*curstr) != LOWER(*curname))
        break;
    }

    /* skip to next name */

    for (; isalpha(*curname); curname++);
    if (!*curname)
      return (0);
    curname++;                  /* first char of new name */
  }
}

/* affect modify: adds/removes object/spell affections or perm affections...
   first 5 args are self explanatory, 6th arg determines whether the aff
   will be echoed to the player
*/

void 
affect_modify (struct char_data *ch, byte loc, long mod, long bitv,
	       bool add, bool echo)
{
  int maxabil, i;
  extern const char *affect_aff_msg[];
  extern const char *affect_wear_off_msg[];

  if (add) {
    SET_BIT (AFF_FLAGS (ch), bitv);
    if (echo) {
      for (i=0; i<=31; i++)
        if (IS_SET(bitv, (1 << i))) {
          send_to_char((char *) affect_aff_msg[i], ch);
          send_to_char("\r\n", ch);
        }
    }
  }
  else {
    REMOVE_BIT (AFF_FLAGS (ch), bitv);
    if (echo) {
      for (i=0; i<=31; i++)
        if (IS_SET(bitv, (1 << i))) {   
          send_to_char((char *) affect_wear_off_msg[i], ch);
          send_to_char("\r\n", ch);
        }
    }
    mod = -mod;
  }

  maxabil = (IS_NPC (ch) || GET_LEVEL(ch) >= LVL_IMMORT ? MAX_STAT : MAX_PLAYER_STAT);

  switch (loc)
    {
    case APPLY_NONE:
      break;

    case APPLY_STR:
      GET_STR (ch) += mod;
      break;
    case APPLY_DEX:
      GET_DEX (ch) += mod;
      break;
    case APPLY_INT:
      GET_INT (ch) += mod;
      break;
    case APPLY_WIS:
      GET_WIS (ch) += mod;
      break;
    case APPLY_CON:
      GET_CON (ch) += mod;
      break;
    case APPLY_CHA:
      GET_CHA (ch) += mod;
      break;

    case APPLY_CLASS:
      /* ??? GET_CLASS(ch) += mod; */
      break;

    case APPLY_LEVEL:
      /* ??? GET_LEVEL(ch) += mod; */
      break;

    case APPLY_AGE:
      ch->player.time.birth -= (mod * SECS_PER_MUD_YEAR);
      break;

    case APPLY_CHAR_WEIGHT:
      GET_WEIGHT (ch) += mod;
      break;

    case APPLY_CHAR_HEIGHT:
      GET_HEIGHT (ch) += mod;
      break;

    case APPLY_MANA:
      GET_MAX_MANA (ch) += mod;
      break;

    case APPLY_HIT:
      GET_MAX_HIT (ch) += mod;
      break;

    case APPLY_MOVE:
      GET_MAX_MOVE (ch) += mod;
      break;

    case APPLY_GOLD:
      break;

    case APPLY_EXP:
      break;

    case APPLY_POWER:
      GET_POWER (ch) += mod;
      break;

    case APPLY_MPOWER:
      GET_MPOWER (ch) += mod;
      break;

    case APPLY_DEFENSE:
      GET_DEFENSE (ch) += mod;
      break;

    case APPLY_MDEFENSE:
      GET_MDEFENSE (ch) += mod;
      break;

    case APPLY_TECHNIQUE:
      GET_TECHNIQUE (ch) += mod;
      break;

    default:
      log ("SYSERR: Unknown apply adjust attempt (handler.c, affect_modify).");
      break;

    }				/* switch */
}



/* This updates a character by subtracting everything he is affected by */
/* restoring original abilities, and then affecting all again           */
void 
affect_total (struct char_data *ch)
{
  struct affected_type *af;
  int i, j;

  for (i = 0; i < NUM_WEARS; i++)
    { 
      if (GET_EQ (ch, i)) {
	for (j = 0; j < MAX_OBJ_AFFECT; j++)
	  affect_modify (ch, GET_EQ (ch, i)->affected[j].location,
			 GET_EQ (ch, i)->affected[j].modifier,
			 GET_EQ (ch, i)->obj_flags.bitvector, FALSE, FALSE);
      }
    }


  for (af = ch->affected; af; af = af->next)
    affect_modify (ch, af->location, af->modifier, af->bitvector, FALSE, FALSE);

  ch->aff_abils = ch->real_abils;

  for (i = 0; i < NUM_WEARS; i++)
    {
      if (GET_EQ (ch, i)) {
	for (j = 0; j < MAX_OBJ_AFFECT; j++)
	  affect_modify (ch, GET_EQ (ch, i)->affected[j].location,
			 GET_EQ (ch, i)->affected[j].modifier,
			 GET_EQ (ch, i)->obj_flags.bitvector, TRUE, FALSE);
      }
    }


  for (af = ch->affected; af; af = af->next)
    affect_modify (ch, af->location, af->modifier, af->bitvector, TRUE, FALSE);

  /* Make certain values are between 0..25, not < 0 and not > 25! */

  i = (IS_NPC (ch) || GET_LEVEL(ch) >= LVL_IMMORT ? MAX_STAT : MAX_PLAYER_STAT);

  GET_DEX (ch) = MAX (0, MIN (GET_DEX (ch), i));
  GET_INT (ch) = MAX (0, MIN (GET_INT (ch), i));
  GET_WIS (ch) = MAX (0, MIN (GET_WIS (ch), i));
  GET_CON (ch) = MAX (0, MIN (GET_CON (ch), i));
  GET_STR (ch) = MAX (0, GET_STR (ch));

  if (IS_NPC (ch))
    {
      GET_STR (ch) = MIN (GET_STR (ch), i);
    }
  else
    {
      if (GET_STR (ch) > MAX_PLAYER_STAT)
	{
	  i = GET_ADD (ch) + ((GET_STR (ch) - MAX_PLAYER_STAT) * 10);
	  GET_ADD (ch) = MIN (i, 100);
	  GET_STR (ch) = MAX_PLAYER_STAT;
	}
    }
}



/* Insert an affect_type in a char_data structure
   Automatically sets apropriate bits and apply's */
void 
affect_to_char (struct char_data *ch, struct affected_type *af)
{
  struct affected_type *affected_alloc;

  CREATE (affected_alloc, struct affected_type, 1);

  *affected_alloc = *af;
  affected_alloc->next = ch->affected;
  ch->affected = affected_alloc;

  affect_modify (ch, af->location, af->modifier, af->bitvector, TRUE, FALSE);
  affect_total (ch);
}



/*
 * Remove an affected_type structure from a char (called when duration
 * reaches zero). Pointer *af must never be NIL!  Frees mem and calls
 * affect_location_apply
 */
void 
affect_remove (struct char_data *ch, struct affected_type *af)
{
  struct affected_type *temp;

  assert (ch->affected);

  affect_modify (ch, af->location, af->modifier, af->bitvector, FALSE, FALSE);
  REMOVE_FROM_LIST (af, ch->affected, next);
  free (af);
  affect_total (ch);
}



/* Call affect_remove with every spell of spelltype "skill" */
void 
affect_from_char (struct char_data *ch, int type)
{
  struct affected_type *hjp, *next;

  for (hjp = ch->affected; hjp; hjp = next)
    {
      next = hjp->next;
      if (hjp->type == type)
	affect_remove (ch, hjp);
    }
}



/*
 * Return if a char is affected by a spell (SPELL_XXX), NULL indicates
 * not affected
 */
bool 
affected_by_spell (struct char_data *ch, int type)
{
  struct affected_type *hjp;

  for (hjp = ch->affected; hjp; hjp = hjp->next)
    if (hjp->type == type)
      return TRUE;

  return FALSE;
}



void 
affect_join (struct char_data *ch, struct affected_type *af,
	     bool add_dur, bool avg_dur, bool add_mod, bool avg_mod)
{
  struct affected_type *hjp;
  bool found = FALSE;
  int max_dur, max_aff;

  switch (af->type) {
    case SKILL_CARNALRAGE:
      max_dur = 200; max_aff = 200; af->type=SKILL_ADRENALINE; break;
    case SKILL_BLOODLUST:
      max_dur = 100; max_aff = 100; af->type=SKILL_ADRENALINE; break;
    case SKILL_ADRENALINE:
      max_dur = 50; max_aff = 50; break;
    default:
      max_dur = 65500; max_aff = 65500; break;
  }

  for (hjp = ch->affected; !found && hjp; hjp = hjp->next)
    {

      if ((hjp->type == af->type) && (hjp->location == af->location))
	{
          if (af->type==-1 && af->location==APPLY_NONE && af->duration==-1 && af->bitvector !=
hjp->bitvector) continue;
	  if (add_dur)
            af->duration = MIN(af->duration + hjp->duration, max_dur-1);
	  if (avg_dur)
	    af->duration >>= 1;

	  if (add_mod)
	    af->modifier = MAX(-max_aff, MIN(af->modifier+hjp->modifier, max_aff));

	  if (avg_mod)
	    af->modifier >>= 1;

	  affect_remove (ch, hjp);
	  affect_to_char (ch, af);
	  found = TRUE;
	}
    }
  if (!found)
    affect_to_char (ch, af);
}


/* move a player out of a room */
void 
char_from_room (struct char_data *ch)
{
  struct char_data *temp;

  if (ch == NULL || ch->in_room == NOWHERE)
    {
      log ("SYSERR: NULL or NOWHERE in handler.c, char_from_room");
      exit (1);
    }

  if (FIGHTING (ch) != NULL)
    stop_fighting (ch);

  if (GET_EQ (ch, WEAR_LIGHT) != NULL)
    if (GET_OBJ_TYPE (GET_EQ (ch, WEAR_LIGHT)) == ITEM_LIGHT)
      if (GET_OBJ_VAL (GET_EQ (ch, WEAR_LIGHT), 2))	/* Light is ON */
	world[ch->in_room].light--;

  REMOVE_FROM_LIST (ch, world[ch->in_room].people, next_in_room);
  ch->in_room = NOWHERE;
  ch->next_in_room = NULL;
}


/* place a character in a room */
void extract_zone_objs (struct obj_data *obj, room_vnum bzone, room_vnum tzone, struct
char_data *ch)
{
  if (obj)
    {
      extract_zone_objs (obj->contains, bzone, tzone, ch);
      extract_zone_objs (obj->next_content, bzone, tzone, ch);
      if (bzone <= GET_OBJ_VNUM(obj) && tzone >=  GET_OBJ_VNUM(obj)) {
        sprintf(buf2, "%s distintegrates.\r\n", obj->short_description);
        if (ch)
          send_to_char(buf2, ch);
        extract_obj (obj);
      }
    }
}

void extract_zone_objs_from_equipped (struct char_data *ch, room_vnum bzone, room_vnum tzone)
{
  int j;
  
  for (j = 0; j < NUM_WEARS; j++)
    {
      if (GET_EQ (ch, j))
        {
          if (bzone <= GET_OBJ_VNUM(GET_EQ (ch, j)) && tzone >=  GET_OBJ_VNUM(GET_EQ (ch, j)))
            obj_to_char (unequip_char (ch, j), ch);
          else
            extract_zone_objs (GET_EQ (ch, j), bzone, tzone, ch);
        }
    }
}

void 
char_to_room (struct char_data *ch, room_rnum room)
{
  extern struct zone_data *zone_table;
  if (ch == NULL || room < 0 || room > top_of_world)
    log ("SYSERR: Illegal value(s) passed to char_to_room");
  else
    {
      ch->next_in_room = world[room].people;
      world[room].people = ch;
      ch->in_room = room;

      if (GET_EQ (ch, WEAR_LIGHT))
	if (GET_OBJ_TYPE (GET_EQ (ch, WEAR_LIGHT)) == ITEM_LIGHT)
	  if (GET_OBJ_VAL (GET_EQ (ch, WEAR_LIGHT), 2))		/* Light ON */
	    world[room].light++;

      /* Stop fighting now, if we left. */
      if (FIGHTING(ch) && IN_ROOM(ch) != IN_ROOM(FIGHTING(ch))) {
        stop_fighting(FIGHTING(ch));
        stop_fighting(ch);
      }
      if (ch->player_specials->saved.buildmodezone>=0 && IS_SET(PRF2_FLAGS(ch), PRF2_MBUILDING)) {
        /* The player was in build mode */
        if (ch->player_specials->saved.buildmodezone!=world[room].zone) {
          sprintf(buf, "%s exiting build mode.", GET_NAME(ch));
          mudlog(buf, BRF, LVL_IMMORT, TRUE);
          extract_zone_objs_from_equipped (ch,       
zone_table[ch->player_specials->saved.buildmodezone].number*100,
zone_table[ch->player_specials->saved.buildmodezone].top);   
          extract_zone_objs (ch->carrying,
zone_table[ch->player_specials->saved.buildmodezone].number*100,
zone_table[ch->player_specials->saved.buildmodezone].top, ch);
          ch->player_specials->saved.buildmodezone=-1;
          ch->player_specials->saved.buildmoderoom=-1;
          REMOVE_BIT(PRF2_FLAGS(ch), PRF2_MBUILDING | PRF2_INTANGIBLE);
          REMOVE_BIT(PRF_FLAGS(ch), PRF_ROOMFLAGS);
          REMOVE_BIT(PRF_FLAGS(ch), PRF_NOHASSLE);
          REMOVE_BIT(PRF_FLAGS(ch), PRF_HOLYLIGHT);
          REMOVE_BIT(GCMD_FLAGS(ch), GCMD_PURGE);
          REMOVE_BIT(GCMD_FLAGS(ch), GCMD_LOAD);
          REMOVE_BIT(GCMD2_FLAGS(ch), GCMD2_OLC);
          REMOVE_BIT(GCMD2_FLAGS(ch), GCMD2_ZRESET);
          REMOVE_BIT(GCMD3_FLAGS(ch), GCMD3_PEACE);
        }
      }
    }
}


/* give an object to a char   */
void 
obj_to_char (struct obj_data *object, struct char_data *ch)
{
  if (object && ch)
    {
      object->next_content = ch->carrying;
      ch->carrying = object;
      object->carried_by = ch;
      object->in_room = NOWHERE;
      IS_CARRYING_W (ch) += GET_OBJ_WEIGHT (object);
      IS_CARRYING_N (ch)++;

      /* set flag for crash-save system */
      SET_BIT (PLR_FLAGS (ch), PLR_CRASH);
    }
  else
    log ("SYSERR: NULL obj or char passed to obj_to_char");
}


/* take an object from a char */
void 
obj_from_char (struct obj_data *object)
{
  struct obj_data *temp;

  if (object == NULL)
    {
      log ("SYSERR: NULL object passed to obj_from_char");
      return;
    }
  REMOVE_FROM_LIST (object, object->carried_by->carrying, next_content);

  /* set flag for crash-save system */
  SET_BIT (PLR_FLAGS (object->carried_by), PLR_CRASH);

  IS_CARRYING_W (object->carried_by) -= GET_OBJ_WEIGHT (object);
  IS_CARRYING_N (object->carried_by)--;
  object->carried_by = NULL;
  object->next_content = NULL;
}



/* Return the effect of a piece of armor in position eq_pos */
int 
apply_ac (struct char_data *ch, int eq_pos)
{
  int factor;

  assert (GET_EQ (ch, eq_pos));

  if (!(GET_OBJ_TYPE (GET_EQ (ch, eq_pos)) == ITEM_ARMOR))
    return 0;

  switch (eq_pos)
    {

    case WEAR_BODY:
      factor = 3;
      break;			/* 30% */
    case WEAR_HEAD:
      factor = 2;
      break;			/* 20% */
    case WEAR_LEGS:
      factor = 2;
      break;			/* 20% */
    default:
      factor = 1;
      break;			/* all others 10% */
    }

  return (factor * GET_OBJ_VAL (GET_EQ (ch, eq_pos), 0));
}

bool check_perm_duration (struct char_data *ch, long bitvector) {
  struct affected_type *af;
  for (af=ch->affected; af; af=af->next)
    if (IS_SET(af->bitvector, bitvector) && af->duration==-1 && af->type==-1) return 1;
  return 0;
}

void reaffect_obj_char(struct char_data *ch) {
  struct affected_type af;
  int j, i;
  for (i = 0; i < NUM_WEARS; i++)
    if (GET_EQ(ch, i))
    for (j=0; j<=31; j++)
      if (IS_SET(GET_EQ(ch, i)->obj_flags.bitvector, (1 << j))) {
        af.type = -1;
        af.location = APPLY_NONE;
        af.modifier = 0; 
        af.duration = -1;
        af.bitvector = (1 << j);
        affect_join (ch, &af, 0, FALSE, FALSE, FALSE);
      }
}

void 
do_equip_char (struct char_data *ch, struct obj_data *obj, int pos, bool echo)
{
  int j;
  int invalid_class (struct char_data *ch, struct obj_data *obj);
  struct obj_data *wielded;

  assert (pos >= 0 && pos < NUM_WEARS);

  if (GET_EQ (ch, pos))
    {
      sprintf (buf, "SYSERR: Char is already equipped: %s, %s", GET_NAME (ch),
	       obj->short_description);
      log (buf);
      return;
    }
  if (obj->carried_by)
    {
      log ("SYSERR: EQUIP: Obj is carried_by when equip.");
      return;
    }
  if (obj->in_room != NOWHERE)
    {
      log ("SYSERR: EQUIP: Obj is in_room when equip.");
      return;
    }
  if (((IS_OBJ_STAT (obj, ITEM_ANTI_EVIL) && IS_EVIL (ch)) ||
      (IS_OBJ_STAT (obj, ITEM_ANTI_GOOD) && IS_GOOD (ch)) ||
      (IS_OBJ_STAT (obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL (ch)) ||
      invalid_class (ch, obj) || obj->min_level > GET_LEVEL(ch)) && (GET_LEVEL (ch) < LVL_IMMORT))
    {
      act ("You are zapped by $p and instantly let go of it.", 
	   FALSE, ch, obj, 0, TO_CHAR);
      act ("$n is zapped by $p and instantly lets go of it.", 
	   FALSE, ch, obj, 0, TO_ROOM);
      obj_to_char (obj, ch);	/* changed to drop in inventory instead of
				 * ground */
      return;
    }

  wielded  = GET_EQ (ch, WEAR_WIELD);
  if (wielded){
    if (GET_OBJ_TYPE (wielded) == ITEM_WEAPON 
      && weaponrestrictions > 0 && GET_LEVEL(ch) < LVL_IMMORT){
      if ( (((GET_OBJ_VAL (obj, 2) + 1) / 2.0) * GET_OBJ_VAL (obj, 1))
	   > lvl_maxdmg_weapon[(int) GET_LEVEL(ch)]){
	act ("$p fumbles out of your inexperienced hands.",
	     FALSE, ch, wielded, 0, TO_CHAR);
	act ("$p fumbles out of $n's inexperienced hands.",
	     FALSE, ch, wielded, 0, TO_ROOM);
	obj_to_char (unequip_char(ch, WEAR_WIELD), ch);
	/* return; */
      }
    }
  }

  GET_EQ (ch, pos) = obj;
  obj->worn_by = ch;
  obj->worn_on = pos;

  if (GET_OBJ_TYPE (obj) == ITEM_ARMOR)
    affect_modify (ch, APPLY_DEFENSE, apply_ac (ch, pos), 0, TRUE, 0);

  if (ch->in_room != NOWHERE)
    {
      if (pos == WEAR_LIGHT && GET_OBJ_TYPE (obj) == ITEM_LIGHT)
	if (GET_OBJ_VAL (obj, 2))	/* if light is ON */
	  world[ch->in_room].light++;
    }
  else
    log ("SYSERR: ch->in_room = NOWHERE when equipping char.");

  for (j = 0; j < MAX_OBJ_AFFECT; j++)
    affect_modify (ch, obj->affected[j].location,
		   obj->affected[j].modifier,
		   obj->obj_flags.bitvector, TRUE, FALSE);
  affect_modify (ch, APPLY_NONE, 0, obj->obj_flags.bitvector, TRUE, echo);

  reaffect_obj_char(ch);

  affect_total (ch);
  /* Special spell procedures go here... */
  if (GET_POS(ch)!=POS_SLEEPING && IS_SET(obj->obj_flags.bitvector, AFF_SLEEP) &&
GET_LEVEL(ch)<LVL_IMMORT)
    command_interpreter(ch, "sleep");
}

struct obj_data *
do_unequip_char (struct char_data *ch, int pos, bool echo)
{
  int j;
  struct obj_data *obj;
  struct affected_type *af, *next;
  struct affected_type *temp;

  assert (pos >= 0 && pos < NUM_WEARS);
  assert (GET_EQ (ch, pos));

  obj = GET_EQ (ch, pos);
  obj->worn_by = NULL;
  obj->worn_on = -1;

  if (GET_OBJ_TYPE (obj) == ITEM_ARMOR)
    affect_modify (ch, APPLY_DEFENSE, -apply_ac (ch, pos), 0, TRUE, 0);

  if (ch->in_room != NOWHERE)
    {
      if (pos == WEAR_LIGHT && GET_OBJ_TYPE (obj) == ITEM_LIGHT)
	if (GET_OBJ_VAL (obj, 2))	/* if light is ON */
	  world[ch->in_room].light--;
    }
  else
    log ("SYSERR: ch->in_room = NOWHERE when equipping char.");

  GET_EQ (ch, pos) = NULL;

  for (j = 0; j < MAX_OBJ_AFFECT; j++)
    affect_modify (ch, obj->affected[j].location,
		   obj->affected[j].modifier,
		   obj->obj_flags.bitvector, FALSE, FALSE);
  affect_modify (ch, APPLY_NONE, 0, obj->obj_flags.bitvector, FALSE, echo);

  for (j=0; j<=31; j++)
    for (af = ch->affected; af; af = next) {
      next=af->next;
      if (af->type==-1 && af->duration==-1 && IS_SET(af->bitvector, (1 << j)) &&
IS_SET(obj->obj_flags.bitvector, (1 << j))) {
         REMOVE_FROM_LIST (af, ch->affected, next);
         free(af);
      }
    }

  reaffect_obj_char(ch);

  affect_total (ch);

  return (obj);
}

void equip_char(struct char_data *ch, struct obj_data *obj, int pos) {
  do_equip_char(ch, obj, pos, TRUE);
}
struct obj_data *unequip_char(struct char_data *ch, int pos) {
  return do_unequip_char(ch, pos, TRUE);
}
void nequip_char(struct char_data *ch, struct obj_data *obj, int pos) {
  do_equip_char(ch, obj, pos, FALSE);
}
struct obj_data *nunequip_char(struct char_data *ch, int pos) {
  return do_unequip_char(ch, pos, FALSE);
}

int 
get_number (char **name)
{
  int i;
  char *ppos;
  char number[MAX_INPUT_LENGTH];

  *number = '\0';

  if ((ppos = strchr (*name, '.')))
    {
      *ppos++ = '\0';
      strcpy (number, *name);
      strcpy (*name, ppos);

      for (i = 0; *(number + i); i++)
	if (!isdigit (*(number + i)))
	  return 0;

      return (atoi (number));
    }
  return 1;
}



/* Search a given list for an object number, and return a ptr to that obj */
struct obj_data *
get_obj_in_list_num (int num, struct obj_data *list)
{
  struct obj_data *i;

  for (i = list; i; i = i->next_content)
    if (GET_OBJ_RNUM (i) == num)
      return i;

  return NULL;
}



/* search the entire world for an object number, and return a pointer  */
struct obj_data *
get_obj_num (obj_rnum nr)
{
  struct obj_data *i;

  for (i = object_list; i; i = i->next)
    if (GET_OBJ_RNUM (i) == nr)
      return i;

  return NULL;
}



/* search a room for a char, and return a pointer if found..  */
struct char_data *
get_char_room (char *name, room_rnum room)
{
  struct char_data *i;
  int j = 0, number;
  char tmpname[MAX_INPUT_LENGTH];
  char *tmp = tmpname;

  strcpy (tmp, name);
  if (!(number = get_number (&tmp)))
    return NULL;

  for (i = world[room].people; i && (j <= number); i = i->next_in_room)
    if (isname (tmp, i->player.name))
      if (++j == number)
	return i;

  return NULL;
}



/* search all over the world for a char num, and return a pointer if found */
struct char_data *
get_char_num (mob_rnum nr)
{
  struct char_data *i;

  for (i = character_list; i; i = i->next)
    if (GET_MOB_RNUM (i) == nr)
      return i;

  return NULL;
}



/* put an object in a room */
void 
obj_to_room (struct obj_data *object, room_rnum room)
{
  if (!object || room < 0 || room > top_of_world)
    log ("SYSERR: Illegal value(s) passed to obj_to_room");
  else
    {
      object->next_content = world[room].contents;
      world[room].contents = object;
      object->in_room = room;
      object->carried_by = NULL;
      if (ROOM_FLAGGED (room, ROOM_HOUSE))
	SET_BIT (ROOM_FLAGS (room), ROOM_HOUSE_CRASH);
    }
}


/* Take an object from a room */
void 
obj_from_room (struct obj_data *object)
{
  struct obj_data *temp;

  if (!object || object->in_room == NOWHERE)
    {
      log ("SYSERR: NULL object or obj not in a room passed to obj_from_room");
      return;
    }

  REMOVE_FROM_LIST (object, world[object->in_room].contents, next_content);

  if (ROOM_FLAGGED (object->in_room, ROOM_HOUSE))
    SET_BIT (ROOM_FLAGS (object->in_room), ROOM_HOUSE_CRASH);
  object->in_room = NOWHERE;
  object->next_content = NULL;
}


/* put an object in an object (quaint)  */
void 
obj_to_obj (struct obj_data *obj, struct obj_data *obj_to)
{
  struct obj_data *tmp_obj;

  if (!obj || !obj_to || obj == obj_to)
    {
      log ("SYSERR: NULL object or same source and target obj passed to obj_to_obj");
      return;
    }

  obj->next_content = obj_to->contains;
  obj_to->contains = obj;
  obj->in_obj = obj_to;

  for (tmp_obj = obj->in_obj; tmp_obj->in_obj; tmp_obj = tmp_obj->in_obj)
    GET_OBJ_WEIGHT (tmp_obj) += GET_OBJ_WEIGHT (obj);

  /* top level object.  Subtract weight from inventory if necessary. */
  GET_OBJ_WEIGHT (tmp_obj) += GET_OBJ_WEIGHT (obj);
  if (tmp_obj->carried_by)
    IS_CARRYING_W (tmp_obj->carried_by) += GET_OBJ_WEIGHT (obj);
}


/* remove an object from an object */
void 
obj_from_obj (struct obj_data *obj)
{
  struct obj_data *temp, *obj_from;

  if (obj->in_obj == NULL)
    {
      log ("error (handler.c): trying to illegally extract obj from obj");
      return;
    }
  obj_from = obj->in_obj;
  REMOVE_FROM_LIST (obj, obj_from->contains, next_content);

  /* Subtract weight from containers container */
  for (temp = obj->in_obj; temp->in_obj; temp = temp->in_obj)
    GET_OBJ_WEIGHT (temp) -= GET_OBJ_WEIGHT (obj);

  /* Subtract weight from char that carries the object */
  GET_OBJ_WEIGHT (temp) -= GET_OBJ_WEIGHT (obj);
  if (temp->carried_by)
    IS_CARRYING_W (temp->carried_by) -= GET_OBJ_WEIGHT (obj);

  obj->in_obj = NULL;
  obj->next_content = NULL;
}


/* Set all carried_by to point to new owner */
void 
object_list_new_owner (struct obj_data *list, struct char_data *ch)
{
  if (list)
    {
      object_list_new_owner (list->contains, ch);
      object_list_new_owner (list->next_content, ch);
      list->carried_by = ch;
    }
}


/* Extract an object from the world */
void 
extract_obj (struct obj_data *obj)
{
  struct obj_data *temp;

  if (obj->worn_by != NULL)
    if (unequip_char (obj->worn_by, obj->worn_on) != obj)
      log ("SYSERR: Inconsistent worn_by and worn_on pointers!!");
  if (obj->in_room != NOWHERE)
    obj_from_room (obj);
  else if (obj->carried_by)
    obj_from_char (obj);
  else if (obj->in_obj)
    obj_from_obj (obj);

  /* Get rid of the contents of the object, as well. */
  while (obj->contains)
    extract_obj (obj->contains);

  REMOVE_FROM_LIST (obj, object_list, next);

  if (GET_OBJ_RNUM (obj) >= 0)
    (obj_index[GET_OBJ_RNUM (obj)].number)--;

   if (SCRIPT(obj))
     extract_script(SCRIPT(obj));

  free_obj (obj);
}



void 
update_object (struct obj_data *obj, int use)
{
  if (GET_OBJ_TIMER (obj) > 0)
    GET_OBJ_TIMER (obj) -= use;
  if (obj->contains)
    update_object (obj->contains, use);
  if (obj->next_content)
    update_object (obj->next_content, use);
}


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

  if (GET_EQ (ch, WEAR_LIGHT) != NULL)
    if (GET_OBJ_TYPE (GET_EQ (ch, WEAR_LIGHT)) == ITEM_LIGHT)
      if (GET_OBJ_VAL (GET_EQ (ch, WEAR_LIGHT), 2) > 0)
	{
	  i = --GET_OBJ_VAL (GET_EQ (ch, WEAR_LIGHT), 2);
	  if (i == 1)
	    {
	      act ("Your light begins to flicker and fade.", FALSE, ch, 0, 0, TO_CHAR);
	      act ("$n's light begins to flicker and fade.", FALSE, ch, 0, 0, TO_ROOM);
	    }
	  else if (i == 0)
	    {
	      act ("Your light sputters out and dies.", FALSE, ch, 0, 0, TO_CHAR);
	      act ("$n's light sputters out and dies.", FALSE, ch, 0, 0, TO_ROOM);
	      world[ch->in_room].light--;
	    }
	}

  for (i = 0; i < NUM_WEARS; i++)
    if (GET_EQ (ch, i))
      update_object (GET_EQ (ch, i), 2);

  if (ch->carrying)
    update_object (ch->carrying, 1);
}



/* Extract a ch completely from the world, and leave his stuff behind */
void 
do_extract_char (struct char_data *ch, int type)
{
  struct char_data *k, *temp;
  struct obj_data *obj;
  int i, freed = 0;
  void dismount_char(struct char_data *ch);

  extern struct char_data *combat_list;

  ACMD (do_return);

  void die_follower (struct char_data *ch);

  if (ch->desc && ch->desc->original)
    do_return (ch, "", 0, 0);

  if (ch->in_room == NOWHERE)
    {
      log ("SYSERR: NOWHERE extracting char. (handler.c, extract_char)");
      exit (1);
    }
  if (ch->followers || ch->master)
    die_follower (ch);
  if (RIDING(ch) || RIDDEN_BY(ch))
    dismount_char(ch);

  /* Forget snooping, if applicable */
  if (ch->desc && type!=1)
    {
      if (ch->desc->snooping)
	{
	  ch->desc->snooping->snoop_by = NULL;
	  ch->desc->snooping = NULL;
	}
      if (ch->desc->snoop_by)
	{
	  SEND_TO_Q ("Your victim is no longer among us.\r\n",
		     ch->desc->snoop_by);
	  ch->desc->snoop_by->snooping = NULL;
	  ch->desc->snoop_by = NULL;
	}
    }
  /* transfer objects to room, if any */
  while (ch->carrying)
    {
      obj = ch->carrying;
      obj_from_char (obj);
      obj_to_room (obj, ch->in_room);
    }

  /* transfer equipment to room, if any */
  for (i = 0; i < NUM_WEARS; i++)
    if (GET_EQ (ch, i))
      obj_to_room (unequip_char (ch, i), ch->in_room);

  if (FIGHTING (ch))
    stop_fighting (ch);

  for (k = combat_list; k; k = temp)
    {
      temp = k->next_fighting;
      if (FIGHTING (k) == ch)
	stop_fighting (k);
    }

  char_from_room (ch);

  /* pull the char from the list */
  if (type!=1) { REMOVE_FROM_LIST (ch, character_list, next); }

  if (!IS_NPC (ch))
    {
      save_char (ch, NOWHERE);
      Crash_delete_crashfile (ch);
    }
  else
    {
      if (GET_MOB_RNUM (ch) > -1)	/* if mobile */
	mob_index[GET_MOB_RNUM (ch)].number--;
      clearMemory (ch);		/* Only NPC's can have memory */
     if (SCRIPT(ch))
       extract_script(SCRIPT(ch));
      free_char (ch);
      freed = 1;
    }

  REMOVE_BIT(PRF2_FLAGS(ch), PRF2_INTANGIBLE);

  if (type!=1) {
    if (!freed && ch->desc != NULL)
      {
        if (type!=2) {
          STATE (ch->desc) = CON_MENU;
          SEND_TO_Q (MENU, ch->desc);
        }
      }
    else
      {				/* if a player gets purged from within the game */
        if (!freed)
	  free_char (ch);
      }
  }
  else {
    char_to_room(ch, real_room(99));
    SET_BIT(PRF2_FLAGS(ch), PRF2_INTANGIBLE);
    GET_POS(ch)=POS_STANDING;
    GET_HIT(ch)=GET_MANA(ch)=GET_MOVE(ch)=1;
    ch->player_specials->saved.death_timer=96; /* Make em' wait two hours before respawning. */
    send_to_char("You suddenly find yourself floating in space... you feel nothing.\r\n", ch);
    act("$n slowly materializes before you...\r\n", FALSE, ch, NULL, NULL, TO_ROOM);
  }
}

void extract_char (struct char_data *ch) {
  do_extract_char(ch, 0);
}



/* ***********************************************************************
   * Here follows high-level versions of some earlier routines, ie functions*
   * which incorporate the actual player-data                               *.
   *********************************************************************** */


struct char_data *
get_player_vis (struct char_data *ch, char *name, int inroom)
{
  struct char_data *i;

  if (!ch) return NULL;

  for (i = character_list; i; i = i->next)
    if (!IS_NPC (i) && (!inroom || (i->in_room == ch->in_room)) &&
	!str_cmp (i->player.name, name) && CAN_SEE (ch, i))
      return i;

  return NULL;
}


struct char_data *
get_char_room_vis (struct char_data *ch, char *name)
{
  struct char_data *i;
  int j = 0, number;
  char tmpname[MAX_INPUT_LENGTH];
  char *tmp = tmpname;

  /* JE 7/18/94 :-) :-) */
  if (!str_cmp (name, "self") || !str_cmp (name, "me"))
    return ch;

  /* 0.<name> means PC with name */
  strcpy (tmp, name);
  if (!(number = get_number (&tmp)))
    return get_player_vis (ch, tmp, 1);

  for (i = world[ch->in_room].people; i && j <= number; i = i->next_in_room)
    if (isname (tmp, i->player.name))
      if (CAN_SEE (ch, i))
	if (++j == number)
	  return i;

  return NULL;
}


struct char_data *
get_char_vis (struct char_data *ch, char *name)
{
  struct char_data *i;
  int j = 0, number;
  char tmpname[MAX_INPUT_LENGTH];
  char *tmp = tmpname;

  /* check the room first */
  if (ch ? ((i = get_char_room_vis (ch, name)) != NULL) : 0)
    return i;

  strcpy (tmp, name);
  if (!(number = get_number (&tmp)))
    return get_player_vis (ch, tmp, 0);

  for (i = character_list; i && (j <= number); i = i->next)
    if (isname (tmp, i->player.name) && (ch ? CAN_SEE (ch, i) : 1))
      if (++j == number)
	return i;

  return NULL;
}



struct obj_data *
get_obj_in_list_vis (struct char_data *ch, char *name,
		     struct obj_data *list)
{
  struct obj_data *i;
  int j = 0, number;
  char tmpname[MAX_INPUT_LENGTH];
  char *tmp = tmpname;

  if (!ch) return NULL;

  strcpy (tmp, name);
  if (!(number = get_number (&tmp)))
    return NULL;

  for (i = list; i && (j <= number); i = i->next_content)
    if (isname (tmp, i->name))
      if (CAN_SEE_OBJ (ch, i))
	if (++j == number)
	  return i;

  return NULL;
}




/* search the entire world for an object, and return a pointer  */
struct obj_data *
get_obj_vis (struct char_data *ch, char *name)
{
  struct obj_data *i;
  int j = 0, number;
  char tmpname[MAX_INPUT_LENGTH];
  char *tmp = tmpname;

  if (ch) {
  /* scan items carried */
  if ((i = get_obj_in_list_vis (ch, name, ch->carrying)))
    return i;

  /* scan room */
  if ((i = get_obj_in_list_vis (ch, name, world[ch->in_room].contents)))
    return i;
  }
  strcpy (tmp, name);
  if (!(number = get_number (&tmp)))
    return NULL;

  /* ok.. no luck yet. scan the entire obj list   */
  for (i = object_list; i && (j <= number); i = i->next)
    if (isname (tmp, i->name))
      if ((ch ? CAN_SEE_OBJ (ch, i) : 1) && (!i->carried_by || (ch ? CAN_SEE (ch, i->carried_by) : 1)))
	if (++j == number)
	  return i;

  return NULL;
}



struct obj_data *
get_object_in_equip_vis (struct char_data *ch,
			 char *arg, struct obj_data *equipment[], int *j)
{
  for ((*j) = 0; (*j) < NUM_WEARS; (*j)++)
    if (equipment[(*j)])
      if (CAN_SEE_OBJ (ch, equipment[(*j)]))
	if (isname (arg, equipment[(*j)]->name))
	  return (equipment[(*j)]);

  return NULL;
}


char *
money_desc (int amount)
{
  static char buf[128];

  if (amount <= 0)
    {
      log ("SYSERR: Try to create negative or 0 money.");
      return NULL;
    }
  if (amount == 1)
    strcpy (buf, "a gold coin");
  else if (amount <= 10)
    strcpy (buf, "a tiny pile of gold coins");
  else if (amount <= 20)
    strcpy (buf, "a handful of gold coins");
  else if (amount <= 75)
    strcpy (buf, "a little pile of gold coins");
  else if (amount <= 200)
    strcpy (buf, "a small pile of gold coins");
  else if (amount <= 1000)
    strcpy (buf, "a pile of gold coins");
  else if (amount <= 5000)
    strcpy (buf, "a big pile of gold coins");
  else if (amount <= 10000)
    strcpy (buf, "a large heap of gold coins");
  else if (amount <= 20000)
    strcpy (buf, "a huge mound of gold coins");
  else if (amount <= 75000)
    strcpy (buf, "an enormous mound of gold coins");
  else if (amount <= 150000)
    strcpy (buf, "a small mountain of gold coins");
  else if (amount <= 250000)
    strcpy (buf, "a mountain of gold coins");
  else if (amount <= 500000)
    strcpy (buf, "a huge mountain of gold coins");
  else if (amount <= 1000000)
    strcpy (buf, "an enormous mountain of gold coins");
  else
    strcpy (buf, "an absolutely colossal mountain of gold coins");

  return buf;
}


struct obj_data *
create_money (int amount)
{
  struct obj_data *obj;
  struct extra_descr_data *new_descr;
  char buf[200];

  if (amount <= 0)
    {
      log ("SYSERR: Try to create negative or 0 money.");
      return NULL;
    }
  obj = create_obj ();
  CREATE (new_descr, struct extra_descr_data, 1);

  if (amount == 1)
    {
      obj->name = str_dup ("coin gold");
      obj->short_description = str_dup ("a gold coin");
      obj->description = str_dup ("One miserable gold coin is lying here.");
      new_descr->keyword = str_dup ("coin gold");
      new_descr->description = str_dup ("It's just one miserable little gold coin.");
    }
  else
    {
      obj->name = str_dup ("coins gold");
      obj->short_description = str_dup (money_desc (amount));
      sprintf (buf, "%s is lying here.", money_desc (amount));
      obj->description = str_dup (CAP (buf));

      new_descr->keyword = str_dup ("coins gold");
      if (amount < 10)
	{
	  sprintf (buf, "There are %d coins.", amount);
	  new_descr->description = str_dup (buf);
	}
      else if (amount < 100)
	{
	  sprintf (buf, "There are about %d coins.", 10 * (amount / 10));
	  new_descr->description = str_dup (buf);
	}
      else if (amount < 1000)
	{
	  sprintf (buf, "It looks to be about %d coins.", 100 * (amount / 100));
	  new_descr->description = str_dup (buf);
	}
      else if (amount < 100000)
	{
	  sprintf (buf, "You guess there are, maybe, %d coins.",
		   1000 * ((amount / 1000) + number (0, (amount / 1000))));
	  new_descr->description = str_dup (buf);
	}
      else
	new_descr->description = str_dup ("There are a LOT of coins.");
    }

  new_descr->next = NULL;
  obj->ex_description = new_descr;

  GET_OBJ_TYPE (obj) = ITEM_MONEY;
  GET_OBJ_WEAR (obj) = ITEM_WEAR_TAKE;
  GET_OBJ_VAL (obj, 0) = amount;
  GET_OBJ_COST (obj) = amount;
  obj->item_number = NOTHING;

  return obj;
}


/* Generic Find, designed to find any object/character                    */
/* Calling :                                                              */
/*  *arg     is the sting containing the string to be searched for.       */
/*           This string doesn't have to be a single word, the routine    */
/*           extracts the next word itself.                               */
/*  bitv..   All those bits that you want to "search through".            */
/*           Bit found will be result of the function                     */
/*  *ch      This is the person that is trying to "find"                  */
/*  **tar_ch Will be NULL if no character was found, otherwise points     */
/* **tar_obj Will be NULL if no object was found, otherwise points        */
/*                                                                        */
/* The routine returns a pointer to the next word in *arg (just like the  */
/* one_argument routine).                                                 */

int 
generic_find (char *arg, int bitvector, struct char_data *ch,
	      struct char_data **tar_ch, struct obj_data **tar_obj)
{
  int i, found;
  char name[256];

  one_argument (arg, name);

  if (!*name)
    return (0);

  *tar_ch = NULL;
  *tar_obj = NULL;

  if (IS_SET (bitvector, FIND_CHAR_ROOM))
    {				/* Find person in room */
      if ((*tar_ch = get_char_room_vis (ch, name)))
	{
	  return (FIND_CHAR_ROOM);
	}
    }
  if (IS_SET (bitvector, FIND_CHAR_WORLD))
    {
      if ((*tar_ch = get_char_vis (ch, name)))
	{
	  return (FIND_CHAR_WORLD);
}
}
  if (IS_SET (bitvector, FIND_OBJ_EQUIP))
    {
      for (found = FALSE, i = 0; i < NUM_WEARS && !found; i++)
	if (GET_EQ (ch, i) && CAN_SEE_OBJ (ch, GET_EQ (ch, i)) &&
	    isname (name, GET_EQ (ch, i)->name))
	  {
	    *tar_obj = GET_EQ (ch, i);
	    found = TRUE;
	  }
      if (found)
	{
	  return (FIND_OBJ_EQUIP);
	}
    }
  if (IS_SET (bitvector, FIND_OBJ_INV))
    {
      if ((*tar_obj = get_obj_in_list_vis (ch, name, ch->carrying)))
	{
	  return (FIND_OBJ_INV);
	}
    }
  if (IS_SET (bitvector, FIND_OBJ_ROOM))
    {
      if ((*tar_obj = get_obj_in_list_vis (ch, name, world[ch->in_room].contents)))
	{
	  return (FIND_OBJ_ROOM);
	}
    }
  if (IS_SET (bitvector, FIND_OBJ_WORLD))
    {
      if ((*tar_obj = get_obj_vis (ch, name)))
	{
	  return (FIND_OBJ_WORLD);
	}
    }
  return (0);
}

/* a function to scan for "all" or "all.x" */
int 
find_all_dots (char *arg)
{
  if (!strcmp (arg, "all"))
    return FIND_ALL;
  else if (!strncmp (arg, "all.", 4))
    {
      strcpy (arg, arg + 4);
      return FIND_ALLDOT;
    }
  else
    return FIND_INDIV;
}


void dismount_char(struct char_data *ch) {
  if (RIDING(ch)) {
    RIDDEN_BY(RIDING(ch)) = NULL;
    RIDING(ch) = NULL;
  }

  if (RIDDEN_BY(ch)) {
    RIDING(RIDDEN_BY(ch)) = NULL;
    RIDDEN_BY(ch) = NULL;
  }
}

// mount_char() / fr: Daniel Koepke (dkoepke@california.com)
//   Sets _ch_ to mounting _mount_.  This does not make any checks
//   what-so-ever to see if the _mount_ is mountable, etc.  That is
//   left up to the calling function.  This does not present any
//   messages, either.
void mount_char(struct char_data *ch, struct char_data *mount) {
  RIDING(ch) = mount;
  RIDDEN_BY(mount) = ch;
    }

/* blood update (Mulder) */

void blood_update(void)
{
  int i;
  extern int top_of_world;

  for (i = 0; i < top_of_world; i++)
    if (RM_BLOOD(i) > 0)
      RM_BLOOD(i) -= 1;
}