circlemud_squared_0.5.153/cnf/
circlemud_squared_0.5.153/etc/
circlemud_squared_0.5.153/etc/etc/
circlemud_squared_0.5.153/etc/house/
circlemud_squared_0.5.153/etc/misc/
circlemud_squared_0.5.153/etc/plralias/A-E/
circlemud_squared_0.5.153/etc/plralias/F-J/
circlemud_squared_0.5.153/etc/plralias/K-O/
circlemud_squared_0.5.153/etc/plralias/P-T/
circlemud_squared_0.5.153/etc/plralias/U-Z/
circlemud_squared_0.5.153/etc/plralias/ZZZ/
circlemud_squared_0.5.153/etc/plrobjs/
circlemud_squared_0.5.153/etc/plrobjs/A-E/
circlemud_squared_0.5.153/etc/plrobjs/F-J/
circlemud_squared_0.5.153/etc/plrobjs/K-O/
circlemud_squared_0.5.153/etc/plrobjs/P-T/
circlemud_squared_0.5.153/etc/plrobjs/U-Z/
circlemud_squared_0.5.153/etc/plrobjs/ZZZ/
circlemud_squared_0.5.153/etc/text/
circlemud_squared_0.5.153/etc/text/help/
circlemud_squared_0.5.153/src/util/
circlemud_squared_0.5.153/src/util/worldconv/
/* ************************************************************************
*   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 "character.h"
#include "comm.h"
#include "db.h"
#include "handler.h"
#include "interpreter.h"
#include "spells.h"
#include "log.h"
#include "room.h"
#include "item.h"

/* local functions */
int apply_ac(charData_t *ch, int eq_pos);
void update_object(itemData_t *obj, int use);
void update_char_objects(charData_t *ch);

/* external functions */
void remove_follower(charData_t *ch);

char *fname(const char *namelist)
{
  static char holder[30];
  char *point;

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

  *point = '\0';

  return (holder);
}


bool isfullname(const char *str, const char *namelist)
{
  const char *curname, *curstr;

  curname = namelist;
  for (;;) {
    for (curstr = str;; curstr++, curname++) {
      if (!*curstr && !isalpha(*curname))
	return (TRUE);
      if (!*curname)
	return (FALSE);
      if (!*curstr || *curname == ' ')
	break;
      if (LOWER(*curstr) != LOWER(*curname))
	break;
    }

    /* skip to next name */

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

int isname(const char *str, const char *namelist) {
  if (str == NULL) {
    log("isname(): invalid 'str' string.");
  } else if (namelist == NULL) {
    log("isname(): invalid 'namelist' string.");
  } else {
    /* Declare a buffer to copy the name list. */
    char buf[MAX_STRING_LENGTH];
    /* Declare an iterator variable. */
    register char *p = NULL;

    /* Copy the name list because strtok is destructive. */
    strlcpy(buf, namelist, MAX_INPUT_LENGTH);

    /* Iterate the copied name list searching for matches. */
    for (p = strtok(buf, " \t"); p && *p != '\0'; p = strtok(NULL, " \t")) {
      if (p && is_abbrev(str, p))
	return (TRUE);
    }
  }
  return (FALSE);
}



void effectData_modify(charData_t *ch, byte loc, sbyte mod, 
                   bitvector_t bitv, bool add)
{
  if (add)
    SET_BIT(AFF_FLAGS(ch), bitv);
  else {
    REMOVE_BIT(AFF_FLAGS(ch), bitv);
    mod = -mod;
  }

  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;
  /*
   * My personal thoughts on these two would be to set the person to the
   * value of the apply.  That way you won't have to worry about people
   * making +1 level things to be imp (you restrict anything that gives
   * immortal level of course).  It also makes more sense to set someone
   * to a class rather than adding to the class number. -gg
   */
  case APPLY_LEVEL:
    /* ??? GET_LEVEL(ch) += mod; */
    break;
  case APPLY_AGE:
    ch->player.time.birth -= (mod * SECS_PER_MUD_YEAR);
    break;
  case APPLY_WEIGHT:
    GET_WEIGHT(ch) += mod;
    break;
  case APPLY_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_AC:
    GET_AC(ch) += mod;
    break;
  case APPLY_HITROLL:
    GET_HITROLL(ch) += mod;
    break;
  case APPLY_DAMROLL:
    GET_DAMROLL(ch) += mod;
    break;
  case APPLY_SAVING_PARA:
    GET_SAVE(ch, SAVING_PARA) += mod;
    break;
  case APPLY_SAVING_ROD:
    GET_SAVE(ch, SAVING_ROD) += mod;
    break;
  case APPLY_SAVING_PETRI:
    GET_SAVE(ch, SAVING_PETRI) += mod;
    break;
  case APPLY_SAVING_BREATH:
    GET_SAVE(ch, SAVING_BREATH) += mod;
    break;
  case APPLY_SAVING_SPELL:
    GET_SAVE(ch, SAVING_SPELL) += mod;
    break;
  default:
    log("SYSERR: Unknown apply adjust %d attempt (%s, effectData_modify).", loc, __FILE__);
    break;
  } /* switch */
}



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

  for (i = 0; i < NUM_WEARS; i++) {
    if (GET_EQ(ch, i))
      for (j = 0; j < MAX_ITEM_AFFECT; j++)
	effectData_modify(ch, GET_EQ(ch, i)->affected[j].location,
		      GET_EQ(ch, i)->affected[j].modifier,
		      GET_ITEM_AFFECT(GET_EQ(ch, i)), FALSE);
  }


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

  ch->aff_abils = ch->real_abils;

  for (i = 0; i < NUM_WEARS; i++) {
    if (GET_EQ(ch, i))
      for (j = 0; j < MAX_ITEM_AFFECT; j++)
	effectData_modify(ch, GET_EQ(ch, i)->affected[j].location,
		      GET_EQ(ch, i)->affected[j].modifier,
		      GET_ITEM_AFFECT(GET_EQ(ch, i)), TRUE);
  }


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

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

  i = (IS_NPC(ch) || GET_AUTH(ch) >= AUTH_OWNER) ? 25 : 18;

  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_CHA(ch) = MAX(0, MIN(GET_CHA(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) > 18) {
      i = GET_ADD(ch) + ((GET_STR(ch) - 18) * 10);
      GET_ADD(ch) = MIN(i, 100);
      GET_STR(ch) = 18;
    }
  }
}



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

  CREATE(affected_alloc, effectData_t, 1);

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

  effectData_modify(ch, af->location, af->modifier, af->bitvector, TRUE);
  effectData_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 effectData_remove(charData_t *ch, effectData_t *af)
{
  effectData_t *temp;

  if (ch->affected == NULL) {
    core_dump();
    return;
  }

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



/* Call effectData_remove with every spell of spelltype "skill" */
void effectData_fromChar(charData_t *ch, int type)
{
  effectData_t *hjp, *next;

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



/*
 * Return TRUE if a char is affected by a spell (SPELL_XXX),
 * FALSE indicates not affected.
 */
bool affected_by_spell(charData_t *ch, int type)
{
  effectData_t *hjp;

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

  return (FALSE);
}



void effectData_join(charData_t *ch, effectData_t *af,
		      bool add_dur, bool avg_dur, bool add_mod, bool avg_mod)
{
  effectData_t *hjp, *next;
  bool found = FALSE;

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

    if ((hjp->type == af->type) && (hjp->location == af->location)) {
      if (add_dur)
	af->duration += hjp->duration;
      if (avg_dur)
	af->duration /= 2;

      if (add_mod)
	af->modifier += hjp->modifier;
      if (avg_mod)
	af->modifier /= 2;

      effectData_remove(ch, hjp);
      effectData_toChar(ch, af);
      found = TRUE;
    }
  }
  if (!found)
    effectData_toChar(ch, af);
}

/* give an object to a char   */
void itemData_toChar(itemData_t *object, charData_t *ch)
{
  if (object && ch) {
    object->nextContent = ch->carrying;
    ch->carrying = object;
    object->carriedBy = ch;
    IN_ROOM(object) = NULL;
    IS_CARRYING_W(ch) += GET_ITEM_WEIGHT(object);
    IS_CARRYING_N(ch)++;

    /* set flag for crash-save system, but not on mobs! */
    if (!IS_NPC(ch))
      SET_BIT(PLR_FLAGS(ch), PLR_CRASH);
  } else
    log("SYSERR: NULL obj (%p) or char (%p) passed to itemData_toChar.", object, ch);
}


/* take an object from a char */
void itemData_fromChar(itemData_t *object)
{
  itemData_t *temp;

  if (object == NULL) {
    log("SYSERR: NULL object passed to itemData_fromChar.");
    return;
  }
  REMOVE_FROM_LIST(object, object->carriedBy->carrying, nextContent);

  /* set flag for crash-save system, but not on mobs! */
  if (!IS_NPC(object->carriedBy))
    SET_BIT(PLR_FLAGS(object->carriedBy), PLR_CRASH);

  IS_CARRYING_W(object->carriedBy) -= GET_ITEM_WEIGHT(object);
  IS_CARRYING_N(object->carriedBy)--;
  object->carriedBy = NULL;
  object->nextContent = NULL;
}



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

  if (GET_EQ(ch, eq_pos) == NULL) {
    core_dump();
    return (0);
  }

  if (!(GET_ITEM_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_ITEM_VAL(GET_EQ(ch, eq_pos), 0));
}

bool invalid_align(charData_t *ch, itemData_t *obj)
{
  if (ITEM_FLAGGED(obj, ITEM_ANTI_EVIL) && IS_EVIL(ch))
    return (TRUE);
  if (ITEM_FLAGGED(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch))
    return (TRUE);
  if (ITEM_FLAGGED(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch))
    return (TRUE);
  return (FALSE);
}

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

  *number = '\0';

  if ((ppos = strchr(*name, '.')) != NULL) {
    *ppos++ = '\0';
    strlcpy(number, *name, sizeof(number));
    strcpy(*name, ppos);	/* strcpy: OK (always smaller) */

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

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

/* search a room for a char, and return a pointer if found..  */
charData_t *get_char_room(char *name, int *number, roomData_t *room)
{
  charData_t *i;
  int num;

  if (!number) {
    number = &num;
    num = get_number(&name);
  }

  if (*number == 0)
    return (NULL);

  for (i = room->people; i && *number; i = i->next_in_room)
    if (isname(name, i->player.name))
      if (--(*number) == 0)
	return (i);

  return (NULL);
}



/* search all over the world for a char num, and return a pointer if found */
charData_t *get_char_num(mobileVnum_t nr)
{
/*
  charData_t *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 itemData_toRoom(itemData_t *object, roomData_t *room)
{
  if (!object || room == NULL)
    log("SYSERR: Illegal value(s) passed to itemData_toRoom.");
  else {
    object->nextContent = room->contents;
    room->contents = object;
    IN_ROOM(object) = room;
    object->carriedBy = NULL;
    if (ROOM_FLAGGED(room, ROOM_HOUSE))
      SET_BIT(ROOM_FLAGS(room), ROOM_HOUSE_CRASH);
  }
}


/* Take an object from a room */
void itemData_fromRoom(itemData_t *object)
{
  itemData_t *temp;

  if (!object || IN_ROOM(object) == NULL) {
    log("SYSERR: NULL object (%p) or obj not in a room passed to itemData_fromRoom",
	object);
    return;
  }

  REMOVE_FROM_LIST(object, object->room->contents, nextContent);

  if (ROOM_FLAGGED(IN_ROOM(object), ROOM_HOUSE))
    SET_BIT(ROOM_FLAGS(IN_ROOM(object)), ROOM_HOUSE_CRASH);
  IN_ROOM(object) = NULL;
  object->nextContent = NULL;
}


/* put an object in an object (quaint)  */
void itemData_toItem(itemData_t *obj, itemData_t *obj_to)
{
  itemData_t *tmp_obj;

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

  obj->nextContent = obj_to->contains;
  obj_to->contains = obj;
  obj->inObj = obj_to;

  for (tmp_obj = obj->inObj; tmp_obj->inObj; tmp_obj = tmp_obj->inObj)
    GET_ITEM_WEIGHT(tmp_obj) += GET_ITEM_WEIGHT(obj);

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


/* remove an object from an object */
void itemData_fromItem(itemData_t *obj)
{
  itemData_t *temp, *obj_from;

  if (obj->inObj == NULL) {
    log("SYSERR: (%s): trying to illegally extract obj from obj.", __FILE__);
    return;
  }
  obj_from = obj->inObj;
  REMOVE_FROM_LIST(obj, obj_from->contains, nextContent);

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

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

  obj->inObj = NULL;
  obj->nextContent = NULL;
}


/* Set all carriedBy to point to new owner */
void object_list_new_owner(itemData_t *list, charData_t *ch)
{
  if (list) {
    object_list_new_owner(list->contains, ch);
    object_list_new_owner(list->nextContent, ch);
    list->carriedBy = ch;
  }
}


/* Extract an object from the world */
void itemData_extract(itemData_t *obj)
{
  itemData_t *temp;

  if (obj->wornBy != NULL)
    if (char_unequipItem(obj->wornBy, obj->wornOn) != obj)
      log("SYSERR: Inconsistent wornBy and worn_on pointers!!");
  if (IN_ROOM(obj) != NULL)
    itemData_fromRoom(obj);
  else if (obj->carriedBy)
    itemData_fromChar(obj);
  else if (obj->inObj)
    itemData_fromItem(obj);

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

  REMOVE_FROM_LIST(obj, object_list, next);

  if (obj->prototype != NULL)
    (obj->prototype->number)--;
  free_obj(obj);
}



void update_object(itemData_t *obj, int use)
{
  if (GET_ITEM_TIMER(obj) > 0)
    GET_ITEM_TIMER(obj) -= use;
  if (obj->contains)
    update_object(obj->contains, use);
  if (obj->nextContent)
    update_object(obj->nextContent, use);
}


void update_char_objects(charData_t *ch)
{
  int i;

  if (GET_EQ(ch, WEAR_LIGHT) != NULL)
    if (GET_ITEM_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT)
      if (GET_ITEM_VAL(GET_EQ(ch, WEAR_LIGHT), 2) > 0) {
	i = --GET_ITEM_VAL(GET_EQ(ch, WEAR_LIGHT), 2);
	if (i == 1) {
	  send_to_char(ch, "Your light begins to flicker and fade.\r\n");
	  act("$n's light begins to flicker and fade.", FALSE, ch, 0, 0, TO_ROOM);
	} else if (i == 0) {
	  send_to_char(ch, "Your light sputters out and dies.\r\n");
	  act("$n's light sputters out and dies.", FALSE, ch, 0, 0, TO_ROOM);
	  ch->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);
}

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


charData_t *get_player_vis(charData_t *ch, char *name, int *number, int inroom)
{
  charData_t *i;
  int num;

  if (!number) {
    number = &num;
    num = get_number(&name);
  }

  for (i = character_list; i; i = i->next) {
    if (IS_NPC(i))
      continue;
    if (inroom == FIND_CHAR_ROOM && IN_ROOM(i) != IN_ROOM(ch))
      continue;
    if (str_cmp(i->player.name, name)) /* If not same, continue */
      continue;
    if (!CAN_SEE(ch, i))
      continue;
    if (--(*number) != 0)
      continue;
    return (i);
  }

  return (NULL);
}


charData_t *get_char_room_vis(charData_t *ch, char *name, int *number)
{
  charData_t *i;
  int num;

  if (!number) {
    number = &num;
    num = get_number(&name);
  }

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

  /* 0.<name> means PC with name */
  if (*number == 0)
    return (get_player_vis(ch, name, NULL, FIND_CHAR_ROOM));

  for (i = ch->room->people; i && *number; i = i->next_in_room)
    if (isname(name, i->player.name))
      if (CAN_SEE(ch, i))
	if (--(*number) == 0)
	  return (i);

  return (NULL);
}


charData_t *get_char_world_vis(charData_t *ch, char *name, int *number)
{
  charData_t *i;
  int num;

  if (!number) {
    number = &num;
    num = get_number(&name);
  }

  if ((i = get_char_room_vis(ch, name, number)) != NULL)
    return (i);

  if (*number == 0)
    return get_player_vis(ch, name, NULL, 0);

  for (i = character_list; i && *number; i = i->next) {
    if (IN_ROOM(ch) == IN_ROOM(i))
      continue;
    if (!isname(name, i->player.name))
      continue;
    if (!CAN_SEE(ch, i))
      continue;
    if (--(*number) != 0)
      continue;

    return (i);
  }
  return (NULL);
}


charData_t *get_char_vis(charData_t *ch, char *name, int *number, int where)
{
  if (where == FIND_CHAR_ROOM)
    return get_char_room_vis(ch, name, number);
  else if (where == FIND_CHAR_WORLD)
    return get_char_world_vis(ch, name, number);
  else
    return (NULL);
}


itemData_t *get_item_in_list_vis(charData_t *ch, char *name, int *number, itemData_t *list)
{
  itemData_t *i;
  int num;

  if (!number) {
    number = &num;
    num = get_number(&name);
  }

  if (*number == 0)
    return (NULL);

  for (i = list; i && *number; i = i->nextContent)
    if (isname(name, i->name))
      if (CAN_SEE_ITEM(ch, i))
	if (--(*number) == 0)
	  return (i);

  return (NULL);
}


/* search the entire world for an object, and return a pointer  */
itemData_t *get_item_vis(charData_t *ch, char *name, int *number)
{
  itemData_t *i;
  int num;

  if (!number) {
    number = &num;
    num = get_number(&name);
  }

  if (*number == 0)
    return (NULL);

  /* scan items carried */
  if ((i = get_item_in_list_vis(ch, name, number, ch->carrying)) != NULL)
    return (i);

  /* scan room */
  if ((i = get_item_in_list_vis(ch, name, number, ch->room->contents)) != NULL)
    return (i);

  /* ok.. no luck yet. scan the entire obj list   */
  for (i = object_list; i && *number; i = i->next)
    if (isname(name, i->name))
      if (CAN_SEE_ITEM(ch, i))
	if (--(*number) == 0)
	  return (i);

  return (NULL);
}


itemData_t *get_item_in_equip_vis(charData_t *ch, char *arg, int *number, itemData_t *equipment[])
{
  int j, num;

  if (!number) {
    number = &num;
    num = get_number(&arg);
  }

  if (*number == 0)
    return (NULL);

  for (j = 0; j < NUM_WEARS; j++)
    if (equipment[j] && CAN_SEE_ITEM(ch, equipment[j]) && isname(arg, equipment[j]->name))
      if (--(*number) == 0)
        return (equipment[j]);

  return (NULL);
}


int get_item_pos_in_equip_vis(charData_t *ch, char *arg, int *number, itemData_t *equipment[])
{
  int j, num;

  if (!number) {
    number = &num;
    num = get_number(&arg);
  }

  if (*number == 0)
    return (-1);

  for (j = 0; j < NUM_WEARS; j++)
    if (equipment[j] && CAN_SEE_ITEM(ch, equipment[j]) && isname(arg, equipment[j]->name))
      if (--(*number) == 0)
        return (j);

  return (-1);
}


const char *money_desc(int amount)
{
  int cnt;
  struct {
    int limit;
    const char *description;
  } money_table[] = {
    {          1, "a gold coin"				},
    {         10, "a tiny pile of gold coins"		},
    {         20, "a handful of gold coins"		},
    {         75, "a little pile of gold coins"		},
    {        200, "a small pile of gold coins"		},
    {       1000, "a pile of gold coins"		},
    {       5000, "a big pile of gold coins"		},
    {      10000, "a large heap of gold coins"		},
    {      20000, "a huge mound of gold coins"		},
    {      75000, "an enormous mound of gold coins"	},
    {     150000, "a small mountain of gold coins"	},
    {     250000, "a mountain of gold coins"		},
    {     500000, "a huge mountain of gold coins"	},
    {    1000000, "an enormous mountain of gold coins"	},
    {          0, NULL					},
  };

  if (amount <= 0) {
    log("SYSERR: Try to create negative or 0 money (%d).", amount);
    return (NULL);
  }

  for (cnt = 0; money_table[cnt].limit; cnt++)
    if (amount <= money_table[cnt].limit)
      return (money_table[cnt].description);

  return ("an absolutely colossal mountain of gold coins");
}


itemData_t *create_money(int amount)
{
  itemData_t *obj;
  extraDescData_t *new_descr;
  char buf[200];

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

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

    new_descr->keyword = strdup("coins gold");
    if (amount < 10)
      snprintf(buf, sizeof(buf), "There are %d coins.", amount);
    else if (amount < 100)
      snprintf(buf, sizeof(buf), "There are about %d coins.", 10 * (amount / 10));
    else if (amount < 1000)
      snprintf(buf, sizeof(buf), "It looks to be about %d coins.", 100 * (amount / 100));
    else if (amount < 100000)
      snprintf(buf, sizeof(buf), "You guess there are, maybe, %d coins.",
	      1000 * ((amount / 1000) + rand_number(0, (amount / 1000))));
    else
      strcpy(buf, "There are a LOT of coins.");	/* strcpy: OK (is < 200) */
    new_descr->description = strdup(buf);
  }

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

  GET_ITEM_TYPE(obj) = ITEM_MONEY;
  GET_ITEM_WEAR(obj) = ITEM_WEAR_TAKE;
  GET_ITEM_VAL(obj, 0) = amount;
  GET_ITEM_COST(obj) = amount;
  obj->vnum = NOTHING;
  obj->prototype = NULL;

  return (obj);
}


/* Generic Find, designed to find any object/character
 *
 * Calling:
 *  *arg     is the pointer 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 used to return a pointer to the next word in *arg (just
 * like the one_argument routine), but now it returns an integer that
 * describes what it filled in.
 */
int generic_find(char *arg, bitvector_t bitvector, charData_t *ch,
		     charData_t **tar_ch, itemData_t **tar_obj)
{
  int i, found, number;
  char name_val[MAX_INPUT_LENGTH];
  char *name = name_val;

  *tar_ch = NULL;
  *tar_obj = NULL;

  one_argument(arg, name);

  if (!*name)
    return (0);
  if (!(number = get_number(&name)))
    return (0);

  if (IS_SET(bitvector, FIND_CHAR_ROOM)) {	/* Find person in room */
    if ((*tar_ch = get_char_room_vis(ch, name, &number)) != NULL)
      return (FIND_CHAR_ROOM);
  }

  if (IS_SET(bitvector, FIND_CHAR_WORLD)) {
    if ((*tar_ch = get_char_world_vis(ch, name, &number)) != NULL)
      return (FIND_CHAR_WORLD);
  }

  if (IS_SET(bitvector, FIND_ITEM_EQUIP)) {
    for (found = FALSE, i = 0; i < NUM_WEARS && !found; i++)
      if (GET_EQ(ch, i) && isname(name, GET_EQ(ch, i)->name) && --number == 0) {
	*tar_obj = GET_EQ(ch, i);
	found = TRUE;
      }
    if (found)
      return (FIND_ITEM_EQUIP);
  }

  if (IS_SET(bitvector, FIND_ITEM_INV)) {
    if ((*tar_obj = get_item_in_list_vis(ch, name, &number, ch->carrying)) != NULL)
      return (FIND_ITEM_INV);
  }

  if (IS_SET(bitvector, FIND_ITEM_ROOM)) {
    if ((*tar_obj = get_item_in_list_vis(ch, name, &number, ch->room->contents)) != NULL)
      return (FIND_ITEM_ROOM);
  }

  if (IS_SET(bitvector, FIND_ITEM_WORLD)) {
    if ((*tar_obj = get_item_vis(ch, name, &number)))
      return (FIND_ITEM_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);	/* strcpy: OK (always less) */
    return (FIND_ALLDOT);
  } else
    return (FIND_INDIV);
}