crodo_mud/cnf/
crodo_mud/lib/
crodo_mud/lib/house/
crodo_mud/lib/misc/
crodo_mud/lib/plralias/F-J/
crodo_mud/lib/plralias/U-Z/
crodo_mud/lib/plrobjs/
crodo_mud/lib/plrvars/A-E/
crodo_mud/lib/plrvars/F-J/
crodo_mud/lib/plrvars/K-O/
crodo_mud/lib/plrvars/P-T/
crodo_mud/lib/plrvars/U-Z/
crodo_mud/lib/text/
crodo_mud/lib/text/help/
crodo_mud/lib/world/
crodo_mud/src/
/*************************************************************************
*   File: act.informative.c                             Part of CircleMUD *
*  Usage: Player-level commands of an informative nature                  *
*                                                                         *
*  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 "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"
#include "screen.h"
#include "constants.h"
#include "dg_scripts.h"
#include "money.h"

/* extern variables */
extern int top_of_helpt;
extern struct help_index_element *help_table;
extern char *help;
extern struct time_info_data time_info;
extern struct room_data *world;
extern struct descriptor_data *descriptor_list;
extern struct char_data *character_list;
extern struct obj_data *object_list;
extern const char *pc_class_types[];
extern struct clan_info clan[];
extern struct index_data *mob_index;
extern struct index_data *obj_index;

extern char *credits;
extern char *news;
extern char *info;
extern char *motd;
extern char *imotd;
extern char *wizlist;
extern char *immlist;
extern char *policies;
extern char *handbook;
extern char *class_abbrevs[];

/* extern functions */
ACMD(do_action);
long find_class_bitvector(char arg);
int level_exp(int chclass, int level);
char *title_male(int chclass, int level);
char *title_female(int chclass, int level);
struct time_info_data *real_time_passed(time_t t2, time_t t1);
int compute_armor_class(struct char_data *ch);
int can_swim(struct char_data *ch);
int can_fly(struct char_data *ch);

/* local functions */
void print_object_location(int num, struct obj_data * obj, struct char_data * ch, int recur);
void show_obj_to_char(struct obj_data * object, struct char_data * ch, int mode);
void list_obj_to_char(struct obj_data * list, struct char_data * ch, int mode, int show);
ACMD(do_look);
ACMD(do_examine);
ACMD(do_score);
ACMD(do_inventory);
ACMD(do_equipment);
ACMD(do_time);
ACMD(do_weather);
ACMD(do_help);
ACMD(do_who);
ACMD(do_users);
ACMD(do_gen_ps);
void perform_mortal_where(struct char_data * ch, char *arg);
void perform_immort_where(struct char_data * ch, char *arg);
ACMD(do_where);
ACMD(do_levels);
ACMD(do_listen);
ACMD(do_consider);
ACMD(do_diagnose);
ACMD(do_color);
ACMD(do_toggle);
void sort_commands(void);
ACMD(do_commands);
void diag_char_to_char(struct char_data * i, struct char_data * ch);
void look_at_char(struct char_data * i, struct char_data * ch);
void list_all_char(struct char_data * i, struct char_data * ch, int num);
void list_char_to_char(struct char_data * list, struct char_data * ch);
void do_auto_exits(struct char_data * ch);
ACMD(do_exits);
void look_in_direction(struct char_data * ch, int dir);
void look_in_obj(struct char_data * ch, char *arg);
char *find_exdesc(char *word, struct extra_descr_data * list);
void look_at_target(struct char_data * ch, char *arg);

/* Local Variables */
int boot_high = 0;

/*
 * This function screams bitvector... -gg 6/45/98
 */
void show_obj_to_char(struct obj_data * object, struct char_data * ch,
			int mode) {

 struct char_data *tempch;
 char seated[MAX_STRING_LENGTH];
 *buf = '\0';

  if ((mode == 0) && object->description) {
    if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_ROOMFLAGS)) {
      sprintf(buf, "&c[%5d]&g ", GET_OBJ_VNUM(object));
    }
    if (IS_OBJ_STAT(object, ITEM_SEAT) && OBJ_SAT_IN_BY(object))
     strcat(buf, object->action_description);
    else strcat(buf, object->description);
  }
  else if (object->short_description && ((mode == 1) ||
	  (mode == 2) || (mode == 3) || (mode == 4))) {
  strcpy(buf, object->short_description);
     if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_ROOMFLAGS)) {
       sprintf(buf + strlen(buf), " &y(vnum %d)", GET_OBJ_VNUM(object));
     }
  }
  else if (mode == 5) {
    if (GET_OBJ_TYPE(object) == ITEM_NOTE) {
      if (object->action_description) {
	strcpy(buf, "&nThere is something written upon it:\r\n\r\n");
	strcat(buf, object->action_description);
	page_string(ch->desc, buf, 1);
      } else
	send_to_char("It's blank.\r\n", ch);
      return;
    } else if (GET_OBJ_TYPE(object) != ITEM_DRINKCON) {
      strcpy(buf, "&nYou see nothing special...");
    } else			/* ITEM_TYPE == ITEM_DRINKCON||FOUNTAIN */
      strcpy(buf, "&nIt looks like a drink container.");
  }
  if (mode != 3) {
    if (IS_OBJ_STAT(object, ITEM_INVISIBLE))
      strcat(buf, " (invisible)");
    if (IS_OBJ_STAT(object, ITEM_BLESS) && AFF_FLAGGED(ch, AFF_DETECT_ALIGN))
      strcat(buf, " ..It glows blue!");
    if (IS_OBJ_STAT(object, ITEM_MAGIC) && AFF_FLAGGED(ch, AFF_DETECT_MAGIC))
      strcat(buf, " ..It glows yellow!");
    if (IS_OBJ_STAT(object, ITEM_GLOW))
      strcat(buf, " ..It has a soft glowing aura!");
    if (IS_OBJ_STAT(object, ITEM_HUM))
      strcat(buf, " ..It emits a faint humming sound!");
  }

  if (!IS_OBJ_STAT(object, ITEM_SEAT))
      strcat(buf, "\r\n");
   else if (!OBJ_SAT_IN_BY(object))
      strcat(buf, "\r\n");

  send_to_char("&g", ch);
  page_string(ch->desc, buf, TRUE);

   /* Vehicle support */
    if (IS_OBJ_STAT(object, ITEM_SEAT) && (GET_OBJ_VAL(object, 1) > 0)) {
     sprintf(seated, "Seated %s %s %s\r\n    ",
      sit_types[GET_OBJ_VAL(object, 3)],
      object->short_description, GET_OBJ_VAL(object, 1) == 1  ? "is -" : "are -");
        send_to_char(seated, ch);   
    for (tempch = OBJ_SAT_IN_BY(object); tempch; tempch =
      NEXT_IN_SEAT(tempch)) {
       if(!IS_NPC(ch) && IS_NPC(tempch) && PRF_FLAGGED(ch, PRF_ROOMFLAGS))
         sprintf(seated, "&c[%d] &y%s", GET_MOB_VNUM(tempch), tempch == ch ? "yourself" : GET_NAME(tempch));
       else
         sprintf(seated, "&y%s", tempch == ch ? "yourself" : GET_NAME(tempch));
       if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN) && IS_EVIL(tempch)) { strcat(seated, " (&rRed&y Aura)"); }
       if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN) && IS_GOOD(tempch)) { strcat(seated, " (&bBlue&y Aura)"); }
       if (FIGHTING(tempch)) { sprintf(seated, "%s&y - fighting %s",seated,GET_NAME(FIGHTING(tempch))); }
       if (GET_POS(tempch) == POS_RESTING) { strcat(seated, " (resting)");}
       if (GET_POS(tempch) == POS_SLEEPING) { strcat(seated, " (sleeping)");}
       if (GET_POS(tempch) == POS_MORTALLYW) { strcat(seated, " (&rmortally wounded&y)");}
       if (GET_POS(tempch) == POS_INCAP) { strcat(seated, " (&rincapacitated&y)");}
       if (GET_POS(tempch) == POS_STUNNED) { strcat(seated, " (&rstunned&y)");}
       if (!IS_NPC(tempch) && !tempch->desc) {  strcat(seated, " (linkless)"); }
       if (!IS_NPC(tempch) && PLR_FLAGGED(tempch, PLR_WRITING)) { strcat(seated, " (writing)");}
       if (!IS_NPC(tempch) && PLR_FLAGGED(tempch, PLR_MAILING)) { strcat(seated, " (mailing)");}
       if (AFF_FLAGGED(tempch, AFF_INVISIBLE)) { strcat(seated, " (invisible)");}
       if (AFF_FLAGGED(tempch, AFF_HIDE)) { strcat(seated, " (hidden)");}

       if(!CAN_SEE(ch, tempch)) { sprintf(seated, "&ySomeone"); }
       if (NEXT_IN_SEAT(tempch))
        strcat(seated, ", ");
       else
        strcat(seated, ".&n\r\n");

       send_to_char(CAP(seated), ch); }
} 

}

void list_obj_to_char(struct obj_data * list, struct char_data * ch, int mode, 
 int show) {
  struct obj_data *i, *j;
  char buf[10];
  bool found;
  int num;

  found = FALSE;
  for (i = list; i; i = i->next_content) {
      num = 0;
      for (j = list; j != i; j = j->next_content)

if ((j->item_number==NOTHING) || (GET_OBJ_TYPE(j) == ITEM_MONEY)) {

    if(strcmp(j->short_description,i->short_description)==0) break;

}

else if ((j->item_number==i->item_number) &&
        (!IS_OBJ_STAT(j, ITEM_SEAT)))
         break;

      if (j!=i) continue;
      for (j = i; j; j = j->next_content)

if ((j->item_number==NOTHING) || (GET_OBJ_TYPE(j) == ITEM_MONEY)) {

    if(strcmp(j->short_description,i->short_description)==0) num++;

  }

else if (j->item_number==i->item_number) num++;

      if (CAN_SEE_OBJ(ch, i)) {

if (IS_OBJ_STAT(i, ITEM_SEAT))
    num = 1;

  if (num!=1)
 {

sprintf(buf,"&c[%2i]&g ",num);
send_to_char(buf,ch);

    }

  show_obj_to_char(i, ch, mode);

  found = TRUE;
      }
  }
  if (!found && show)
    send_to_char(" Nothing.\r\n", ch);
}

void diag_char_to_char(struct char_data * i, struct char_data * ch)
{
  int percent;

  if (GET_MAX_HIT(i) > 0)
    percent = (100 * GET_HIT(i)) / GET_MAX_HIT(i);
  else
    percent = -1;		/* How could MAX_HIT be < 1?? */

  strcpy(buf, PERS(i, ch));
  CAP(buf);

  if (percent >= 100)
    strcat(buf, " is in excellent condition.\r\n");
  else if (percent >= 90)
    strcat(buf, " has a few scratches.\r\n");
  else if (percent >= 75)
    strcat(buf, " has some small wounds and bruises.\r\n");
  else if (percent >= 50)
    strcat(buf, " has quite a few wounds.\r\n");
  else if (percent >= 30)
    strcat(buf, " has some big nasty wounds and scratches.\r\n");
  else if (percent >= 15)
    strcat(buf, " looks pretty hurt.\r\n");
  else if (percent >= 0)
    strcat(buf, " is in awful condition.\r\n");
  else
    strcat(buf, " is bleeding awfully from big wounds.\r\n");

  send_to_char(buf, ch);
}


void look_at_char(struct char_data * i, struct char_data * ch)
{
  int j, found;
  struct obj_data *tmp_obj;
  char seated[MAX_STRING_LENGTH];

  if (!ch->desc)
    return;

   if (i->player.description)
    send_to_char(i->player.description, ch);
  else
    act("You see nothing special about $m.", FALSE, i, 0, ch, TO_VICT);

  diag_char_to_char(i, ch);

  if (SITTING_IN(i)) {   
      sprintf(seated, "%s is %s %s %s.\r\n",
	     HSSH(i),
             positionL_types[(int) GET_POS(i)],
             sit_types[GET_OBJ_VAL(SITTING_IN(i), 3)],
             (CAN_SEE_OBJ(ch, SITTING_IN(i)) ? SITTING_IN(i)->short_description : "something"));
	send_to_char(CAP(seated), ch);
	}

  if (RIDING(i)) {
      sprintf(seated, "%s is mounted upon %s.\r\n",
	    HSSH(i),
	  (CAN_SEE(ch, RIDING(i)) ? GET_NAME(RIDING(i)) : "something"));
	send_to_char(CAP(seated), ch);
	}

  if (RIDDEN_BY(i)) {               
       sprintf(buf2, "$e is mounted by %s.", PERS(RIDDEN_BY(i), ch));
       act(buf2, FALSE, i, 0, ch, TO_VICT);
        }

  found = FALSE;
  for (j = 0; !found && j < NUM_WEARS; j++)
    if (GET_EQ(i, j) && CAN_SEE_OBJ(ch, GET_EQ(i, j)) &&
       (!CAN_WEAR(GET_EQ(i, j), ITEM_WEAR_SOUL) || (GET_LEVEL(ch) >= LVL_IMMORT)) )
      found = TRUE;

  if (found) {
    send_to_char("\r\n", ch);	/* act() does capitalization. */
    act("$n is using:", FALSE, i, 0, ch, TO_VICT);
    for (j = 0; j < NUM_WEARS; j++)
      if (GET_EQ(i, j) && CAN_SEE_OBJ(ch, GET_EQ(i, j)) &&
         (!CAN_WEAR(GET_EQ(i, j), ITEM_WEAR_SOUL) || (GET_LEVEL(ch) >= LVL_IMMORT)) ) {
        send_to_char("&c",ch);
	send_to_char(where[j], ch);
	show_obj_to_char(GET_EQ(i, j), ch, 1);
      }
  }
  if (ch != i && (IS_THIEF(ch) || GET_LEVEL(ch) >= LVL_IMMORT)) {
    found = FALSE;
    act("\r\n&nYou attempt to peek at $s inventory:", FALSE, i, 0, ch, 
TO_VICT);
    for (tmp_obj = i->carrying; tmp_obj; tmp_obj = tmp_obj->next_content) {
      if (CAN_SEE_OBJ(ch, tmp_obj) && (number(0, 20) < GET_LEVEL(ch))) {
	show_obj_to_char(tmp_obj, ch, 1);
	found = TRUE;
      }
    }

    if (!found)
      send_to_char("You can't see anything.\r\n", ch);
  }
}


void list_all_char(struct char_data * i, struct char_data * ch, int num)
{
  const char *positions[] = {
    " is lying here, dead.",
    " is lying here, mortally wounded.",
    " is lying here, incapacitated.",
    " is lying here, stunned.",
    " is sleeping here.",
    " is resting here.",
    " is sitting here.",
    "!FIGHTING!",
    " is standing here.",
    " is flying about here.",
    " is swimming around here.",
    " is floating here.",
  };

  if (IS_NPC(i) && i->player.long_descr && GET_POS(i) == GET_DEFAULT_POS(i)) {
    if (AFF_FLAGGED(i, AFF_INVISIBLE))
      strcpy(buf, "*");
    else
      *buf = '\0';

     if (num > 1)
      sprintf(buf,"&c[%2i] ", num);

     if (!IS_NPC(ch) && IS_NPC(i) && PRF_FLAGGED(ch, PRF_ROOMFLAGS)) {
       sprintf(buf + strlen(buf), "&c[%5d]&y ", GET_MOB_VNUM(i));
     }

    if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) {
      if (IS_EVIL(i))
	strcat(buf, "(&rRed&y Aura) ");
      else if (IS_GOOD(i))
	strcat(buf, "(&bBlue&y Aura) ");
    }

    send_to_char("&y", ch);
 
   if (RIDING(i)) {
      if (!IS_NPC(ch) && IS_NPC(i) && PRF_FLAGGED(ch, PRF_ROOMFLAGS))
        sprintf(buf, "&c[%5d]&y %s", GET_MOB_VNUM(i), i->player.short_descr);
      else
        sprintf(buf, "%s", i->player.short_descr);

      CAP(buf);
      strcat(buf, " is here mounted upon ");
      if (!IS_NPC(ch) && IS_NPC(RIDING(i)) && PRF_FLAGGED(ch, PRF_ROOMFLAGS))
        sprintf(buf + strlen(buf), "&c[%5d]&y", GET_MOB_VNUM(i));
      sprintf(buf + strlen(buf), "%s.&n\r\n",
        (CAN_SEE(ch, RIDING(i)) ? GET_NAME(RIDING(i)) : "something"));
   } else
     strcat(buf, i->player.long_descr);

    send_to_char(buf, ch);

    if (AFF_FLAGGED(i, AFF_BONE_SHIELD))
      act("...$e is surrounded by a swirling clound of bones!", FALSE, i, 0, ch, TO_VICT);
    if (AFF_FLAGGED(i, AFF_BLIND))
      act("...$e is groping around blindly!", FALSE, i, 0, ch, TO_VICT);

    return;
  }

  send_to_char("&y", ch);
  if (IS_NPC(i)) {
    if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_ROOMFLAGS))
      sprintf(buf, "&c[%5d]&y %s", GET_MOB_VNUM(i), i->player.short_descr);
    else
      strcpy(buf, i->player.short_descr);
    CAP(buf);
  } else
    sprintf(buf, "%s", i->player.name);
  if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) {
    if (IS_EVIL(i))
      strcat(buf, " (&rRed&y Aura)");  
    else if (IS_GOOD(i))
      strcat(buf, " (&bBlue&y Aura)");
  }
  if (AFF_FLAGGED(i, AFF_INVISIBLE))
    strcat(buf, " (invisible)");
  if (AFF_FLAGGED(i, AFF_HIDE))
    strcat(buf, " (hidden)");
  if (!IS_NPC(i) && !i->desc)
    strcat(buf, " (linkless)");
  if (!IS_NPC(i) && PLR_FLAGGED(i, PLR_WRITING))
    strcat(buf, " (writing)");

  if (GET_POS(i) != POS_FIGHTING) {

    if (RIDING(i)) {
      strcat(buf, " is here mounted upon ");
      if (!IS_NPC(ch) && IS_NPC(RIDING(i)) && PRF_FLAGGED(ch, PRF_ROOMFLAGS))
        sprintf(buf + strlen(buf), "&c[%5d]&y ", GET_MOB_VNUM(RIDING(i)));
      strcat(buf, (CAN_SEE(ch, RIDING(i)) ? GET_NAME(RIDING(i)) : "something"));
      if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) {
        if (IS_EVIL(RIDING(i)))
          strcat(buf, " (&rRed&y Aura)");  
        else if (IS_GOOD(RIDING(i)))
          strcat(buf, " (&bBlue&y Aura)");
      }
      strcat(buf, ".");
    }
    else if (SITTING_IN(i)) {
      sprintf(buf + strlen(buf), " is here %s %s %s.",
             positionL_types[(int) GET_POS(i)],
             sit_types[GET_OBJ_VAL(SITTING_IN(i), 3)],
             (CAN_SEE_OBJ(ch, SITTING_IN(i)) ? SITTING_IN(i)->short_description : "something"));
               } else {
	strcat(buf, positions[(int) GET_POS(i)]);
    }
  } else {
    if (FIGHTING(i)) {
      strcat(buf, " is here, fighting ");
      if (FIGHTING(i) == ch)
        strcat(buf, "YOU!");
      else {
        if (i->in_room == FIGHTING(i)->in_room)
          strcat(buf, PERS(FIGHTING(i), ch));
        else
          strcat(buf, "someone who has already left");
        strcat(buf, "!");
      }
    } else                      /* NIL fighting pointer */
      strcat(buf, " is here struggling with thin air.");
  }

  if (ROOM_FLAGGED(i->in_room, ROOM_ARENA)) {
    if (PLR_FLAGGED(i, PLR_RED))
      strcat(buf, " (&rRed&n Team&n) ");
    if (PLR_FLAGGED(i, PLR_BLUE))
      strcat(buf, " (&bBlue Team&n) ");
  }

  strcat(buf, "&n\r\n");
  send_to_char(buf, ch);

  if (AFF_FLAGGED(i, AFF_BONE_SHIELD))
    act("...$e is surrounded by a swirling cloud of bones!", FALSE, i, 0, ch, TO_VICT);
}

void list_char_to_char(struct char_data *list, struct char_data *ch)
{
    struct char_data *i;

    for (i=list; i; i = i->next_in_room) {
      if(i != ch)  {
        if (CAN_SEE(ch, i) && !SITTING_IN(i) && !RIDDEN_BY(i))
                list_all_char(i,ch,0);
        }
}
}

void do_auto_exits(struct char_data * ch)
{
  int door, slen = 0;

  *buf = '\0';

  for (door = 0; door < NUM_OF_DIRS; door++)
   if (CAN_GO(ch, door))
    slen += sprintf(buf + slen, "%s ", abbr_dirs[door]);
   else 
    if (EXIT(ch, door) && EXIT(ch, door)->to_room != NOWHERE) {

     if (EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) &&
        (GET_LEVEL(ch) < LVL_IMMORT))
      continue;
    else 
     slen += sprintf(buf + slen, "!%s ", abbr_dirs[door]); 
}
  sprintf(buf2, "%s[ Exits: %s]%s\r\n", CCCYN(ch, C_NRM),
	  *buf ? buf : "None! ", CCNRM(ch, C_NRM));

  send_to_char(buf2, ch);
}


ACMD(do_exits)
{
  int door;

  *buf = '\0';

  if (AFF_FLAGGED(ch, AFF_BLIND)) {
    send_to_char("You can't see a damned thing, you're blind!\r\n", ch);
    return;
  }
  for (door = 0; door < NUM_OF_DIRS; door++)
      if (CAN_GO(ch, door)) {
      if (GET_LEVEL(ch) >= LVL_IMMORT)
	sprintf(buf2, "%-5s - [%9d] %s\r\n", dirs[door],
		GET_ROOM_VNUM(EXIT(ch, door)->to_room),
		world[EXIT(ch, door)->to_room].name);
      else {

        if (EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) &&
            (GET_LEVEL(ch) < LVL_IMMORT))
        continue;

	sprintf(buf2, "%-9s - ", dirs[door]);
	if (IS_DARK(EXIT(ch, door)->to_room) && !CAN_SEE_IN_DARK(ch))
	  strcat(buf2, "Too dark to tell\r\n");
	else {
	  strcat(buf2, world[EXIT(ch, door)->to_room].name);
	  strcat(buf2, "\r\n");
	}
      }
      strcat(buf, CAP(buf2));
    }
  send_to_char("Obvious exits:\r\n", ch);

  if (*buf)
    send_to_char(buf, ch);
  else
    send_to_char(" None.\r\n", ch);
}



void look_at_room(struct char_data * ch, int ignore_brief)
{
  if (!ch->desc)
    return;

  if (IS_DARK(ch->in_room) && !CAN_SEE_IN_DARK(ch)) {
    send_to_char("It is pitch black...\r\n", ch);
    return;
  } else if (AFF_FLAGGED(ch, AFF_BLIND)) {
    send_to_char("You see nothing but infinite darkness...\r\n", ch);
    return;
  }
  send_to_char(CCCYN(ch, C_NRM), ch);
  if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_ROOMFLAGS)) {
    sprintbit(ROOM_FLAGS(ch->in_room), room_bits, buf);
    sprintf(buf2, "[%5d] %s [ %s: %s]", GET_ROOM_VNUM(IN_ROOM(ch)),
	    world[ch->in_room].name, sector_types[world[(ch->in_room)].sector_type], buf);
    send_to_char(buf2, ch);
  } else
    send_to_char(world[ch->in_room].name, ch);

  send_to_char(CCNRM(ch, C_NRM), ch);
  send_to_char("\r\n", ch);

  if ((!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_BRIEF)) || ignore_brief ||
      ROOM_FLAGGED(ch->in_room, ROOM_DEATH))
    send_to_char(world[ch->in_room].description, ch);

  /* autoexits */
  if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOEXIT))
    do_auto_exits(ch);

  /* now list characters & objects */
  send_to_char(CCGRN(ch, C_NRM), ch);
  list_obj_to_char(world[ch->in_room].contents, ch, 0, FALSE);
  send_to_char(CCYEL(ch, C_NRM), ch);
  list_char_to_char(world[ch->in_room].people, ch);
  send_to_char(CCNRM(ch, C_NRM), ch);
}



void look_in_direction(struct char_data * ch, int dir)
{
  if (EXIT(ch, dir)) {
    if (EXIT(ch, dir)->general_description)
      send_to_char(EXIT(ch, dir)->general_description, ch);
    else
      send_to_char("You see nothing special.\r\n", ch);

    if (EXIT_FLAGGED(EXIT(ch, dir), EX_CLOSED) && EXIT(ch, dir)->keyword) {
      sprintf(buf, "The %s is closed.\r\n", fname(EXIT(ch, dir)->keyword));
      send_to_char(buf, ch);
    } else if (EXIT_FLAGGED(EXIT(ch, dir), EX_ISDOOR) && EXIT(ch, dir)->keyword) {
      sprintf(buf, "The %s is open.\r\n", fname(EXIT(ch, dir)->keyword));
      send_to_char(buf, ch);
    }
  } else
    send_to_char("Nothing special there...\r\n", ch);
}



void look_in_obj(struct char_data * ch, char *arg)
{
  struct obj_data *obj = NULL;
  struct char_data *dummy = NULL;
  int amt, bits;

  if (!*arg)
    send_to_char("Look in what?\r\n", ch);
  else if (!(bits = generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM |
				 FIND_OBJ_EQUIP, ch, &dummy, &obj))) {
    sprintf(buf, "There doesn't seem to be %s %s here.\r\n", AN(arg), arg);
    send_to_char(buf, ch);
  } else if ((GET_OBJ_TYPE(obj) != ITEM_DRINKCON) &&
	     (GET_OBJ_TYPE(obj) != ITEM_FOUNTAIN) &&
	     (GET_OBJ_TYPE(obj) != ITEM_CONTAINER))
    send_to_char("There's nothing inside that!\r\n", ch);
  else {
    if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER) {
      if (OBJVAL_FLAGGED(obj, CONT_CLOSED))
	send_to_char("It is closed.\r\n", ch);
      else {
	send_to_char(fname(obj->name), ch);
	switch (bits) {
	case FIND_OBJ_INV:
	  send_to_char(" (carried): \r\n", ch);
	  break;
	case FIND_OBJ_ROOM:
	  send_to_char(" (here): \r\n", ch);
	  break;
	case FIND_OBJ_EQUIP:
	  send_to_char(" (used): \r\n", ch);
	  break;
	}

	list_obj_to_char(obj->contains, ch, 2, TRUE);
      }
    } else {		/* item must be a fountain or drink container */
      if (GET_OBJ_VAL(obj, 1) <= 0)
	send_to_char("It is empty.\r\n", ch);
      else {
	if (GET_OBJ_VAL(obj,0) <= 0 || GET_OBJ_VAL(obj,1)>GET_OBJ_VAL(obj,0)) {
	  sprintf(buf, "Its contents seem somewhat murky.\r\n"); /* BUG */
	} else {
	  amt = (GET_OBJ_VAL(obj, 1) * 3) / GET_OBJ_VAL(obj, 0);
	  sprinttype(GET_OBJ_VAL(obj, 2), color_liquid, buf2);
	  sprintf(buf, "It's %sfull of a %s liquid.\r\n", fullness[amt], buf2);
	}
	send_to_char(buf, ch);
      }
    }
  }
}



char *find_exdesc(char *word, struct extra_descr_data * list)
{
  struct extra_descr_data *i;

  for (i = list; i; i = i->next)
    if (isname(word, i->keyword))
      return (i->description);

  return (NULL);
}


/*
 * Given the argument "look at <target>", figure out what object or char
 * matches the target.  First, see if there is another char in the room
 * with the name.  Then check local objs for exdescs.
 *
 * Thanks to Angus Mezick <angus@EDGIL.CCMAIL.COMPUSERVE.COM> for the
 * suggested fix to this problem.
 */
void look_at_target(struct char_data * ch, char *arg)
{
  int bits, found = FALSE, j, fnum, i = 0;
  struct char_data *found_char = NULL;
  struct obj_data *obj, *found_obj = NULL;
  char *desc;

  if (!ch->desc)
    return;

  if (!*arg) {
    send_to_char("Look at what?\r\n", ch);
    return;
  }

  bits = generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP |
		      FIND_CHAR_ROOM, ch, &found_char, &found_obj);

  /* Is the target a character? */
  if (found_char != NULL) {
    look_at_char(found_char, ch);
    if (ch != found_char) {
      if (CAN_SEE(found_char, ch))
	act("$n looks at you.", TRUE, ch, 0, found_char, TO_VICT);
      act("$n looks at $N.", TRUE, ch, 0, found_char, TO_NOTVICT);
    }
    return;
  }

  /* Strip off "number." from 2.foo and friends. */
  if (!(fnum = get_number(&arg))) {
    send_to_char("Look at what?\r\n", ch);
    return;
  }

  /* Does the argument match an extra desc in the room? */
  if ((desc = find_exdesc(arg, world[ch->in_room].ex_description)) != NULL && ++i == fnum) {
    page_string(ch->desc, desc, FALSE);
    return;
  }

  /* Does the argument match an extra desc in the char's equipment? */
  for (j = 0; j < NUM_WEARS && !found; j++)
    if (GET_EQ(ch, j) && CAN_SEE_OBJ(ch, GET_EQ(ch, j)))
      if ((desc = find_exdesc(arg, GET_EQ(ch, j)->ex_description)) != NULL && ++i == fnum) {
        send_to_char(desc, ch);
        found = TRUE;
      }

  /* Does the argument match an extra desc in the char's inventory? */
  for (obj = ch->carrying; obj && !found; obj = obj->next_content) {
    if (CAN_SEE_OBJ(ch, obj))
      if ((desc = find_exdesc(arg, obj->ex_description)) != NULL && ++i == fnum) {
        send_to_char(desc, ch);
        found = TRUE;
      }
  }

  /* Does the argument match an extra desc of an object in the room? */
  for (obj = world[ch->in_room].contents; obj && !found; obj = obj->next_content)
    if (CAN_SEE_OBJ(ch, obj))
      if ((desc = find_exdesc(arg, obj->ex_description)) != NULL && ++i == fnum) {
	send_to_char(desc, ch);
	found = TRUE;
      }

  /* If an object was found back in generic_find */
  if (bits) {
    if (!found)
      show_obj_to_char(found_obj, ch, 5);	/* Show no-description */
    else
      show_obj_to_char(found_obj, ch, 6);	/* Find hum, glow etc */
  } else if (!found)
    send_to_char("You do not see that here.\r\n", ch);
}


ACMD(do_look)
{
  char arg2[MAX_INPUT_LENGTH];
  int look_type;

  if (!ch->desc)
    return;

  if (GET_POS(ch) < POS_SLEEPING)
    send_to_char("You can't see anything but stars!\r\n", ch);
  else if (AFF_FLAGGED(ch, AFF_BLIND))
    send_to_char("You can't see a damned thing, you're blind!\r\n", ch);
  else if (IS_DARK(ch->in_room) && !CAN_SEE_IN_DARK(ch)) {
    send_to_char("It is pitch black...\r\n", ch);
    list_char_to_char(world[ch->in_room].people, ch);	/* glowing red eyes */
  } else {
    half_chop(argument, arg, arg2);

    if (subcmd == SCMD_READ) {
      if (!*arg)
	send_to_char("Read what?\r\n", ch);
      else
	look_at_target(ch, arg);
      return;
    }
    if (!*arg)			/* "look" alone, without an argument at all */
      look_at_room(ch, 1);
    else if (is_abbrev(arg, "in"))
      look_in_obj(ch, arg2);
    /* did the char type 'look <direction>?' */
    else if ((look_type = search_block(arg, dirs, FALSE)) >= 0)
      look_in_direction(ch, look_type);
    else if ((look_type = search_block(arg, abbr_dirs, FALSE)) >= 0)
      look_in_direction(ch, look_type);
    else if (is_abbrev(arg, "at"))
      look_at_target(ch, arg2);
    else
      look_at_target(ch, arg);
  }
}



ACMD(do_examine)
{
  struct char_data *tmp_char;
  struct obj_data *tmp_object;

  one_argument(argument, arg);

  if (!*arg) {
    send_to_char("Examine what?\r\n", ch);
    return;
  }
  look_at_target(ch, arg);

  generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_CHAR_ROOM |
		      FIND_OBJ_EQUIP, ch, &tmp_char, &tmp_object);

  if (tmp_object) {
    if ((GET_OBJ_TYPE(tmp_object) == ITEM_DRINKCON) ||
	(GET_OBJ_TYPE(tmp_object) == ITEM_FOUNTAIN) ||
	(GET_OBJ_TYPE(tmp_object) == ITEM_CONTAINER)) {
      send_to_char("When you look inside, you see:\r\n", ch);
      look_in_obj(ch, arg);
    }
  }
}

ACMD(do_score)
{

 char born[MAX_STRING_LENGTH];
 char logon[MAX_STRING_LENGTH];
 struct time_info_data playing_time;

  if (IS_NPC(ch))
    return;

    strcpy(born, (char *) asctime(localtime(&(ch->player.time.birth))));
    strcpy(logon, (char *) asctime(localtime(&(ch->player.time.logon))));
    born[10] = logon[10] = '\0';

  sprintf(buf, "\r\nBorn: &c[&n%s&c]&n, Last Logon: &c[&n%s&c]&n, Played &c[&n%dh %dm&c]&n, Age &c[&n%d&c]&n\r\n",
            born, logon, ch->player.time.played / 3600,
            ((ch->player.time.played % 3600) / 60), age(ch)->year);

  sprintf(buf + strlen(buf),
       "You have &r%d&n(&c%d&n) hit, &r%d&n(&c%d&n) mana and &r%d&n(&c%d&n) movement points.\r\n",
          GET_HIT(ch), GET_MAX_HIT(ch), GET_MANA(ch), GET_MAX_MANA(ch),
          GET_MOVE(ch), GET_MAX_MOVE(ch));

  if (GET_LEVEL(ch) >= 10)
  sprintf(buf + strlen(buf), "Str: &c[&n%d/%d&c]&n Int: &c[&n%d&c]&n Wis: &c[&n%d&c]&n Dex: &c[&n%d&c]&n Con: &c[&n%d&c]&n Cha: &c[&n%d&c]&n\r\n",
    GET_STR(ch), GET_ADD(ch), GET_INT(ch), GET_WIS(ch), GET_DEX(ch), GET_CON(ch), GET_CHA(ch));

  sprintf(buf + strlen(buf), "Armor Class &c[&n%d&c]&n Alignment: &c[&n%d&c]&n",
          compute_armor_class(ch), GET_ALIGNMENT(ch));

if (GET_LEVEL(ch) >= 15)
  sprintf(buf + strlen(buf), " Hitroll: &c[&n%d&c]&n   Damroll: &c[&n%d&c]&n", GET_HITROLL(ch), GET_DAMROLL(ch));

  sprintf(buf + strlen(buf), "\r\n");
  
  if (GET_LEVEL(ch) < 30) {
    sprintf(buf + strlen(buf), "You have scored &c[&w%d&c]&n exp.\r\n", GET_EXP(ch));
    sprintf(buf + strlen(buf), "You need &c[&w%d&c]&n exp to reach your next level.\r\n",
	level_exp(GET_CLASS(ch), GET_LEVEL(ch) + 1) - GET_EXP(ch));

  if (GET_QUEST_POINTS(ch))
    sprintf(buf + strlen(buf), "You have accumulated &c[&w%d&c]&n quest points.\r\n",
            GET_QUEST_POINTS(ch));
  else
    strcat(buf, "You have not earned any quest points.\r\n");
}

  playing_time = *real_time_passed((time(0) - ch->player.time.logon) +
				  ch->player.time.played, 0);
  sprintf(buf + strlen(buf), "You have been playing for %d day%s and %d hour%s.\r\n",
     playing_time.day, playing_time.day == 1 ? "" : "s",
     playing_time.hours, playing_time.hours == 1 ? "" : "s");

  sprintf(buf + strlen(buf), "This ranks you as %s %s (level %d).\r\n",
	  GET_NAME(ch), GET_TITLE(ch), GET_LEVEL(ch));

    sprintf(buf + strlen(buf), "You are being trained as a &c");
    sprinttype(ch->player.chclass, pc_class_types, buf + strlen(buf));
    sprintf(buf + strlen(buf), "&n in the city of &c%s&n\r\n",home_names[GET_HOME(ch)]);

   /* Player is in a clan! */
   if (GET_CLAN(ch) != -1) {
    if (GET_CLAN_RANK(ch) != -1)
     sprintf(buf + strlen(buf), "You hold the rank of &c%s&n in the Clan &c%s&n\r\n",
     clan[GET_CLAN(ch)].rank_name[GET_CLAN_RANK(ch) - 1], clan[GET_CLAN(ch)].name);
    else
     sprintf(buf + strlen(buf), "You have applied to the Clan &c%s&n\r\n", clan[GET_CLAN(ch)].name);
                            }

    sprintf(buf + strlen(buf), "You have died &c[&w%d&c]&n times and killed &c[&w%d&c]&n opponents.\r\n", GET_RIP_CNT(ch), GET_KILL_CNT(ch));

    if (GET_DT_CNT(ch))
    sprintf(buf + strlen(buf), "On &c[&w%d&c]&n occasions, you have not paid attention and walked into a Deathtrap.\r\n",GET_DT_CNT(ch));

    if (GET_CONVICTIONS(ch))
    sprintf(buf + strlen(buf), "You have been convicted of &c[&w%d&c]&n crimes.\r\n", GET_CONVICTIONS(ch));

    if (IS_OUTLAW(ch))
    sprintf(buf + strlen(buf), "You are an &rOUTLAW&n!\r\n");

  switch (GET_POS(ch)) {
  case POS_DEAD:
    strcat(buf, "You are DEAD!\r\n");
    break;
  case POS_MORTALLYW:
    strcat(buf, "You are mortally wounded!  You should seek help!\r\n");
    break;
  case POS_INCAP:
    strcat(buf, "You are incapacitated, slowly fading away...\r\n");
    break;
  case POS_STUNNED:
    strcat(buf, "You are stunned!  You can't move!\r\n");
    break;
  case POS_SLEEPING:
    strcat(buf, "You are sleeping.\r\n");
    break;
  case POS_RESTING:
   if (!SITTING_IN(ch))
    strcat(buf, "You are resting.\r\n");
    else {
      sprintf(buf + strlen(buf), "You are resting %s %s.\r\n",
	sit_types[GET_OBJ_VAL(SITTING_IN(ch), 3)],
	SITTING_IN(ch)->short_description);
    }
    break;
  case POS_SITTING:
   if (!SITTING_IN(ch))
    strcat(buf, "You are sitting.\r\n");
    else {
      sprintf(buf + strlen(buf), "You are sitting %s %s.\r\n",
	sit_types[GET_OBJ_VAL(SITTING_IN(ch), 3)],
	 SITTING_IN(ch)->short_description);
    }
    break;
  case POS_FIGHTING:
    if (FIGHTING(ch))
      sprintf(buf + strlen(buf), "You are fighting %s.\r\n",
		PERS(FIGHTING(ch), ch));
    else
      strcat(buf, "You are fighting thin air.\r\n");
    break;
  case POS_STANDING:
    strcat(buf, "You are standing.\r\n");
    break;
  case POS_FLYING:
    strcat(buf, "You are flying about.\r\n");
    break;
  case POS_SWIMMING:
    strcat(buf, "You are swimming around.\r\n");
    break;
  default:
    strcat(buf, "You are floating.\r\n");
    break;
  }

    if (AFF_FLAGGED(ch, AFF_GROUP))
    strcat(buf, "You are grouped.\r\n");

  if (GET_COND(ch, DRUNK) > 10)
    strcat(buf, "You are intoxicated.\r\n");

  if (GET_COND(ch, FULL) == 0)
    strcat(buf, "You are hungry.\r\n");

  if (GET_COND(ch, THIRST) == 0)
    strcat(buf, "You are thirsty.\r\n");

  if (AFF_FLAGGED(ch, AFF_BLIND))
    strcat(buf, "You have been blinded!\r\n");

  if (AFF_FLAGGED(ch, AFF_INVISIBLE))
    strcat(buf, "You are invisible.\r\n");

  if (AFF_FLAGGED(ch, AFF_DETECT_INVIS))
    strcat(buf, "You are sensitive to the presence of invisible things.\r\n");

  if (AFF_FLAGGED(ch, AFF_BONE_SHIELD))
    strcat(buf, "You are protected by the bones of the dead.\r\n");

  if (AFF_FLAGGED(ch, AFF_POISON))
    strcat(buf, "You are poisoned!\r\n");

  if (AFF_FLAGGED(ch, AFF_CHARM))
    strcat(buf, "You have been charmed!\r\n");

  if (affected_by_spell(ch, SPELL_STONESKIN))
    strcat(buf, "Your skin is as hard as stone.\r\n");

  if (AFF_FLAGGED(ch, AFF_INFRAVISION))
    strcat(buf, "Your eyes are glowing red.\r\n");

  if (AFF_FLAGGED(ch, AFF_WARSONG))
    strcat(buf, "Your blood boils with &rrage&n!\r\n");

  if (AFF_FLAGGED(ch, AFF_HASTE))
    strcat(buf, "The world apeears to  move slowly about you!\r\n");

  if (PRF_FLAGGED(ch, PRF_SUMMONABLE))
    strcat(buf, "You are summonable by other players.\r\n");

  if (AFF_FLAGGED(ch, AFF_SHADOWS))
    strcat(buf, "You are concealed from the dead by shadows.\r\n");

  send_to_char(buf, ch);
}


ACMD(do_inventory)
{
  send_to_char("You are carrying:\r\n", ch);
  list_obj_to_char(ch->carrying, ch, 1, TRUE);
}


ACMD(do_equipment)
{
  int i, found = 0;

  send_to_char("You are using:\r\n", ch);
  for (i = 0; i < NUM_WEARS; i++) {
    if (GET_EQ(ch, i) &&
       (!CAN_WEAR(GET_EQ(ch, i), ITEM_WEAR_SOUL) || (GET_LEVEL(ch) >= LVL_IMMORT)) ) {
      if (CAN_SEE_OBJ(ch, GET_EQ(ch, i))) {
        send_to_char("&c", ch);
	send_to_char(where[i], ch);
	show_obj_to_char(GET_EQ(ch, i), ch, 1);
	found = TRUE;
      } else {
	send_to_char("&c", ch);
	send_to_char(where[i], ch);
	send_to_char("Something.\r\n", ch);
	found = TRUE;
      }
    }
  }
  if (!found) {
    send_to_char(" Nothing.\r\n", ch);
  }
}


ACMD(do_time)
{
  const char *suf;
  int weekday, day;

  sprintf(buf, "It is %d o'clock %s, on ",
	  ((time_info.hours % 12 == 0) ? 12 : ((time_info.hours) % 12)),
	  ((time_info.hours >= 12) ? "pm" : "am"));

  /* 35 days in a month */
  weekday = ((35 * time_info.month) + time_info.day + 1) % 7;

  strcat(buf, weekdays[weekday]);
  strcat(buf, "\r\n");
  send_to_char(buf, ch);

  day = time_info.day + 1;	/* day in [1..35] */

  if (((day % 10) == 1) && (day != 11))
    suf = "st";
  else if (((day % 10) == 2) && (day != 12))
    suf = "nd";
  else if (((day % 10) == 3) && (day != 13))
    suf = "rd";
  else
    suf = "th";

  sprintf(buf, "The %d%s Day of the %s, Year %d.\r\n",
	  day, suf, month_name[(int) time_info.month], time_info.year);

  send_to_char(buf, ch);
}


ACMD(do_weather)
{
  const char *sky_look[] = {
    "cloudless",
    "cloudy",
    "rainy",
    "lit by flashes of lightning"
  };

  if (OUTSIDE(ch)) {
    sprintf(buf, "The sky is %s and %s.\r\n", sky_look[weather_info.sky],
	    (weather_info.change >= 0 ? "you feel a warm wind from south" :
	     "your foot tells you bad weather is due"));
    send_to_char(buf, ch);
  } else
    send_to_char("You have no feeling about the weather at all.\r\n", ch);
}


ACMD(do_help)
{
  int chk, bot, top, mid, minlen;

  if (!ch->desc)
    return;

  skip_spaces(&argument);

  if (!*argument) {
    page_string(ch->desc, help, 0);
    return;
  }
  if (!help_table) {
    send_to_char("No help available.\r\n", ch);
    return;
  }

  bot = 0;
  top = top_of_helpt;
  minlen = strlen(argument);

  for (;;) {
    mid = (bot + top) / 2;

    if (bot > top) {
      send_to_char("There is no help on that word.\r\n", ch);
      return;
    } else if (!(chk = strn_cmp(argument, help_table[mid].keyword, minlen))) {
      /* trace backwards to find first matching entry. Thanks Jeff Fink! */
      while ((mid > 0) &&
	 (!(chk = strn_cmp(argument, help_table[mid - 1].keyword, minlen))))
	mid--;
      page_string(ch->desc, help_table[mid].entry, 0);
      return;
    } else {
      if (chk > 0)
        bot = mid + 1;
      else
        top = mid - 1;
    }
  }
}



/*********************************************************************
* New 'do_who' by Daniel Koepke [aka., "Argyle Macleod"] of The Keep *
******************************************************************* */

char *WHO_USAGE =
  "Usage: who [minlev[-maxlev]] [-n name] [-c classes] [-rzqimo]\r\n"
  "\r\n"
  "Classes: (M)age, (C)leric, (T)hief, (W)arrior\r\n"
  "\r\n"
  " Switches: \r\n"
  "_.,-'^'-,._\r\n"
  "\r\n"
  "  -r = who is in the current room\r\n"
  "  -z = who is in the current zone\r\n"
  "\r\n"
  "  -i = only show immortals\r\n"
  "  -m = only show mortals\r\n"
  "  -o = only show outlaws\r\n"
  "\r\n";

ACMD(do_who)
{
  struct descriptor_data *d;
  struct char_data *wch;
  char Imm_buf[MAX_STRING_LENGTH];
  char Mort_buf[MAX_STRING_LENGTH];
  char name_search[MAX_NAME_LENGTH+1];
  char mode;
  long games;
  int low = 0, high = LVL_IMPL, showclass = 0;
  bool who_room = FALSE, who_zone = FALSE;
  bool outlaws = FALSE, noimm = FALSE, nomort = FALSE;

  int Wizards = 0, Mortals = 0;
  size_t i;

  const char *WizLevels[LVL_IMPL - (LVL_IMMORT-1)] = {
    "   Immortal    ",
    "      God      ",
    "  Greater God  ",
    "* Implementor *"
  };


  skip_spaces(&argument);
  strcpy(buf, argument);
  name_search[0] = '\0';

  /* the below is from stock CircleMUD -- found no reason to rewrite it */
  while (*buf) {
    half_chop(buf, arg, buf1);
    if (isdigit(*arg)) {
      sscanf(arg, "%d-%d", &low, &high);
      strcpy(buf, buf1);
    } else if (*arg == '-') {
      mode = *(arg + 1);        /* just in case; we destroy arg in the switch */
      switch (mode) {
      case 'o':
      case 'z':
        who_zone = TRUE;
        strcpy(buf, buf1);
        break;
      case 'l':
        half_chop(buf1, arg, buf);
        sscanf(arg, "%d-%d", &low, &high);
        break;
      case 'n':
        half_chop(buf1, name_search, buf);
        break;
      case 'r':
        who_room = TRUE;
        strcpy(buf, buf1);
        break;
      case 'c':
        half_chop(buf1, arg, buf);
        for (i = 0; i < strlen(arg); i++)
          showclass |= find_class_bitvector(arg[i]);
        break;
      case 'i':
        nomort = TRUE;
        strcpy(buf, buf1);
        break;
      case 'm':
        noimm = TRUE;
        strcpy(buf, buf1);
        break;
      default:
        send_to_char(WHO_USAGE, ch);
        return;
       break;
      }                         /* end of switch */

    } else {                    /* endif */
      send_to_char(WHO_USAGE, ch);
      return;
    }
  }                             /* end while (parser) */

  strcpy(Imm_buf, "Immortals currently online\r\n--------------------------\r\n");
  strcpy(Mort_buf,"Mortals currently online\r\n------------------------\r\n");

  for (d = descriptor_list; d; d = d->next) {
    if (d->connected)
      continue;

    if (d->original)
      wch = d->original;
    else if (!(wch = d->character))
      continue;

    if (!CAN_SEE(ch, wch))
      continue;
    if (GET_LEVEL(wch) < low || GET_LEVEL(wch) > high)
      continue;
    if ((noimm && GET_LEVEL(wch) >= LVL_IMMORT) || (nomort && GET_LEVEL(wch) < LVL_IMMORT))
      continue;
    if (*name_search && str_cmp(GET_NAME(wch), name_search) && !strstr(GET_TITLE(wch), name_search))
      continue;
    if (outlaws && !PLR_FLAGGED(wch, PLR_KILLER) && !PLR_FLAGGED(wch,PLR_THIEF))
      continue;
    if (who_zone && world[ch->in_room].zone != world[wch->in_room].zone)
      continue;
    if (who_room && (wch->in_room != ch->in_room))
      continue;
    if (showclass && !(showclass & (1 << GET_CLASS(wch))))
      continue;

    if (GET_LEVEL(wch) >= LVL_IMMORT) {
      sprintf(Imm_buf, "%s%s[%s] %s %s", Imm_buf, CCYEL(ch, C_SPR),
              WizLevels[GET_LEVEL(wch)-LVL_IMMORT], GET_NAME(wch),
              GET_TITLE(wch));
      Wizards++;
    } else {
      sprintf(Mort_buf, "%s[%2d %s] %s %s", Mort_buf, GET_LEVEL(wch),
              CLASS_ABBR(wch), GET_NAME(wch), GET_TITLE(wch));
      Mortals++;
    }

    *buf = '\0'; /* **BUG FIX: Revision 2** */
    if (GET_INVIS_LEV(wch))
      sprintf(buf, "%s (i%d)", buf, GET_INVIS_LEV(wch));
    else if (IS_AFFECTED(wch, AFF_INVISIBLE))
      strcat(buf, " (invis)");

    if (PLR_FLAGGED(wch, PLR_MAILING))
      strcat(buf, " (mailing)");
    else if (PLR_FLAGGED(wch, PLR_WRITING))
      strcat(buf, " (writing)");

    if (PRF_FLAGGED(wch, PRF_DEAF))
      strcat(buf, " (deaf)");
    if (PRF_FLAGGED(wch, PRF_NOTELL))
      strcat(buf, " (notell)");
    if (PLR_FLAGGED(wch, PLR_OUTLAW))
      strcat(buf, " (Outlaw)");
    if (PLR_FLAGGED(wch, PLR_THIEF))
      strcat(buf, " (Thief)");
    if (PLR_FLAGGED(wch, PLR_KILLER))
      strcat(buf, " (Killer)");
    if (PLR_FLAGGED(wch, PLR_IT))
      strcat(buf, " (&rIT!&n)");
    if (GET_LEVEL(wch) >= LVL_IMMORT)
      strcat(buf, CCNRM(ch, C_SPR));
    strcat(buf, "\r\n");

    if (GET_LEVEL(wch) >= LVL_IMMORT)
      strcat(Imm_buf, buf);
    else
      strcat(Mort_buf, buf);
  }                             /* end of for */

  if (Wizards) {
    page_string(ch->desc, Imm_buf, 0);
    send_to_char("\r\n", ch);
  }

  if (Mortals) {
    page_string(ch->desc, Mort_buf, 0);
    send_to_char("\r\n", ch);
  }
 if ((Wizards + Mortals) == 0)
    strcpy(buf, "No wizards or mortals are currently visible to you.\r\n");
  if (Wizards)
    sprintf(buf, "There %s &c[&n%d&c]&n visible immortal%s%s", (Wizards == 1 ? "is"
    : "are"), Wizards, (Wizards == 1 ? "" : "s"), (Mortals ? " and there" : "."));
  if (Mortals)
    sprintf(buf, "%s %s &c[&n%d&c]&n visible mortal%s.", (Wizards ? buf : "There"),
       (Mortals == 1 ? "is" : "are"), Mortals, (Mortals == 1 ? "" : "s"));
    strcat(buf, "\r\n");

  if ((Wizards + Mortals) > boot_high)
    boot_high = Wizards+Mortals;
    games =  user_cnt_read();
    sprintf(buf + strlen(buf), "Current Boot-Time High: &c%d&n  Total Games Served: &c%ld&n\r\n", boot_high, games);
    send_to_char(buf, ch); }


#define USERS_FORMAT \
"format: users [-l minlevel[-maxlevel]] [-n name] [-h host] [-c classlist] [-o] [-p]\r\n"

ACMD(do_users)
{
  const char *format = "%3d %-7s %-12s %-14s %-3s %-8s ";
  char line[200], line2[220], idletime[10], classname[20];
  char state[30], *timeptr, mode;
  char name_search[MAX_INPUT_LENGTH], host_search[MAX_INPUT_LENGTH];
  struct char_data *tch;
  struct descriptor_data *d;
  size_t i;
  int low = 0, high = LVL_IMPL, num_can_see = 0;
  int showclass = 0, outlaws = 0, playing = 0, deadweight = 0;

  host_search[0] = name_search[0] = '\0';

  strcpy(buf, argument);
  while (*buf) {
    half_chop(buf, arg, buf1);
    if (*arg == '-') {
      mode = *(arg + 1);  /* just in case; we destroy arg in the switch */
      switch (mode) {
      case 'o':
      case 'k':
	outlaws = 1;
	playing = 1;
	strcpy(buf, buf1);
	break;
      case 'p':
	playing = 1;
	strcpy(buf, buf1);
	break;
      case 'd':
	deadweight = 1;
	strcpy(buf, buf1);
	break;
      case 'l':
	playing = 1;
	half_chop(buf1, arg, buf);
	sscanf(arg, "%d-%d", &low, &high);
	break;
      case 'n':
	playing = 1;
	half_chop(buf1, name_search, buf);
	break;
      case 'h':
	playing = 1;
	half_chop(buf1, host_search, buf);
	break;
      case 'c':
	playing = 1;
	half_chop(buf1, arg, buf);
	for (i = 0; i < strlen(arg); i++)
	  showclass |= find_class_bitvector(arg[i]);
	break;
      default:
	send_to_char(USERS_FORMAT, ch);
	return;
      }				/* end of switch */

    } else {			/* endif */
      send_to_char(USERS_FORMAT, ch);
      return;
    }
  }				/* end while (parser) */
  strcpy(line,
	 "Num Class      Name         State          Idl Login@ Site\r\n");
  strcat(line,
	 "--- ---------- ------------ -------------- --- -------- ------------------\r\n");
  send_to_char(line, ch);

  one_argument(argument, arg);

  for (d = descriptor_list; d; d = d->next) {
    if (STATE(d) != CON_PLAYING && playing)
      continue;
    if (STATE(d) == CON_PLAYING && deadweight)
      continue;
    if (IS_PLAYING(d)) {
      if (d->original)
	tch = d->original;
      else if (!(tch = d->character))
	continue;

      if (*host_search && !strstr(d->host, host_search))
	continue;
      if (*name_search && str_cmp(GET_NAME(tch), name_search))
	continue;
      if (!CAN_SEE(ch, tch) || GET_LEVEL(tch) < low || GET_LEVEL(tch) > high)
	continue;
      if (outlaws && !PLR_FLAGGED(tch, PLR_KILLER) &&
	  !PLR_FLAGGED(tch, PLR_THIEF))
	continue;
      if (showclass && !(showclass & (1 << GET_CLASS(tch))))
	continue;
      if (GET_INVIS_LEV(ch) > GET_LEVEL(ch))
	continue;

      if (d->original)
	sprintf(classname, "[%2d %s]", GET_LEVEL(d->original),
		CLASS_ABBR(d->original));
      else
	sprintf(classname, "[%2d %s]", GET_LEVEL(d->character),
		CLASS_ABBR(d->character));
    } else
      strcpy(classname, "   -   ");

    timeptr = asctime(localtime(&d->login_time));
    timeptr += 11;
    *(timeptr + 8) = '\0';

    if (STATE(d) == CON_PLAYING && d->original)
      strcpy(state, "Switched");
    else
      strcpy(state, connected_types[STATE(d)]);

    if (d->character && STATE(d) == CON_PLAYING && GET_LEVEL(d->character) < LVL_GOD)
      sprintf(idletime, "%3d", d->character->char_specials.timer *
	      SECS_PER_MUD_HOUR / SECS_PER_REAL_MIN);
    else
      strcpy(idletime, "");

    if (d->character && d->character->player.name) {
      if (d->original)
	sprintf(line, format, d->desc_num, classname,
		d->original->player.name, state, idletime, timeptr);
      else
	sprintf(line, format, d->desc_num, classname,
		d->character->player.name, state, idletime, timeptr);
    } else
      sprintf(line, format, d->desc_num, "   -   ", "UNDEFINED",
	      state, idletime, timeptr);

    if (d->host && *d->host)
      sprintf(line + strlen(line), "[%s]\r\n", d->host);
    else
      strcat(line, "[Hostname unknown]\r\n");

    if (STATE(d) != CON_PLAYING) {
      sprintf(line2, "%s%s%s", CCGRN(ch, C_SPR), line, CCNRM(ch, C_SPR));
      strcpy(line, line2);
    }
    if (STATE(d) != CON_PLAYING ||
		(STATE(d) == CON_PLAYING && CAN_SEE(ch, d->character))) {
      send_to_char(line, ch);
      num_can_see++;
    }
  }

  sprintf(line, "\r\n%d visible sockets connected.\r\n", num_can_see);
  send_to_char(line, ch);
}


/* Generic page_string function for displaying text */
ACMD(do_gen_ps)
{
  switch (subcmd) {
  case SCMD_CREDITS:
    page_string(ch->desc, credits, 0);
    break;
  case SCMD_NEWS:
    page_string(ch->desc, news, 0);
    break;
  case SCMD_INFO:
    page_string(ch->desc, info, 0);
    break;
  case SCMD_WIZLIST:
    page_string(ch->desc, wizlist, 0);
    break;
  case SCMD_IMMLIST:
    page_string(ch->desc, immlist, 0);
    break;
  case SCMD_HANDBOOK:
    page_string(ch->desc, handbook, 0);
    break;
  case SCMD_POLICIES:
    page_string(ch->desc, policies, 0);
    break;
  case SCMD_MOTD:
    page_string(ch->desc, motd, 0);
    break;
  case SCMD_IMOTD:
    page_string(ch->desc, imotd, 0);
    break;
  case SCMD_CLEAR:
    send_to_char("\033[H\033[J", ch);
    break;
  case SCMD_VERSION:
    send_to_char(strcat(strcpy(buf, circlemud_version), "\r\n"), ch);
    send_to_char(strcat(strcpy(buf, DG_SCRIPT_VERSION), "\r\n"), ch);
    break;
  case SCMD_WHOAMI:
    send_to_char(strcat(strcpy(buf, GET_NAME(ch)), "\r\n"), ch);
    break;
  default:
    log("SYSERR: Unhandled case in do_gen_ps. (%d)", subcmd);
    return;
  }
}


void perform_mortal_where(struct char_data * ch, char *arg)
{
  register struct char_data *i;
  register struct descriptor_data *d;

  if (!*arg) {
    send_to_char("Players in your Zone\r\n--------------------\r\n", ch);
    for (d = descriptor_list; d; d = d->next) {
      if (STATE(d) != CON_PLAYING || d->character == ch)
	continue;
      if ((i = (d->original ? d->original : d->character)) == NULL)
	continue;
      if (i->in_room == NOWHERE || !CAN_SEE(ch, i))
	continue;
      if (world[ch->in_room].zone != world[i->in_room].zone)
	continue;
      sprintf(buf, "%-20s - %s\r\n", GET_NAME(i), world[i->in_room].name);
      send_to_char(buf, ch);
    }
  } else {			/* print only FIRST char, not all. */
    for (i = character_list; i; i = i->next) {
      if (i->in_room == NOWHERE || i == ch)
	continue;
      if (!CAN_SEE(ch, i) || world[i->in_room].zone != world[ch->in_room].zone)
	continue;
      if (!isname(arg, i->player.name))
	continue;
      sprintf(buf, "%-25s - %s\r\n", GET_NAME(i), world[i->in_room].name);
      send_to_char(buf, ch);
      return;
    }
    send_to_char("No-one around by that name.\r\n", ch);
  }
}


void print_object_location(int num, struct obj_data * obj, struct char_data * ch,
			        int recur)
{
  if (num > 0)
    sprintf(buf, "O%3d. %-25s - ", num, obj->short_description);
  else
    sprintf(buf, "%33s", " - ");

  if (obj->in_room > NOWHERE) {
    sprintf(buf + strlen(buf), "[%5d] %s\r\n",
	    GET_ROOM_VNUM(IN_ROOM(obj)), world[obj->in_room].name);
    send_to_char(buf, ch);
  } else if (obj->carried_by) {
    sprintf(buf + strlen(buf), "carried by %s\r\n",
	    PERS(obj->carried_by, ch));
    send_to_char(buf, ch);
  } else if (obj->worn_by) {

    if (CAN_WEAR(obj, ITEM_WEAR_SOUL))
    sprintf(buf + strlen(buf), "the conscience of %s\r\n",
            PERS(obj->worn_by, ch));
    else
    sprintf(buf + strlen(buf), "worn by %s\r\n",
	    PERS(obj->worn_by, ch));

    send_to_char(buf, ch);
  } else if (obj->in_obj) {
    sprintf(buf + strlen(buf), "inside %s%s\r\n",
	    obj->in_obj->short_description, (recur ? ", which is" : " "));
    send_to_char(buf, ch);
    if (recur)
      print_object_location(0, obj->in_obj, ch, recur);
  } else {
    sprintf(buf + strlen(buf), "in an unknown location\r\n");
    send_to_char(buf, ch);
  }
}



void perform_immort_where(struct char_data * ch, char *arg)
{
  register struct char_data *i;
  register struct obj_data *k;
  struct descriptor_data *d;
  int num = 0, found = 0;

  if (!*arg) {
    send_to_char("Players\r\n-------\r\n", ch);
    for (d = descriptor_list; d; d = d->next)
      if (STATE(d) == CON_PLAYING) {
	i = (d->original ? d->original : d->character);
	if (i && CAN_SEE(ch, i) && (i->in_room != NOWHERE)) {
	  if (d->original)
	    sprintf(buf, "%-20s - [%5d] %s (in %s)\r\n",
		    GET_NAME(i), GET_ROOM_VNUM(IN_ROOM(d->character)),
		 world[d->character->in_room].name, GET_NAME(d->character));
	  else
	    sprintf(buf, "%-20s - [%5d] %s\r\n", GET_NAME(i),
		    GET_ROOM_VNUM(IN_ROOM(i)), world[i->in_room].name);
	  send_to_char(buf, ch);
	}
      }
  } else {
    for (i = character_list; i; i = i->next)
      if (CAN_SEE(ch, i) && i->in_room != NOWHERE && isname(arg, i->player.name)) {
	found = 1;
	sprintf(buf, "M%3d. %-25s - [%5d] %s\r\n", ++num, GET_NAME(i),
		GET_ROOM_VNUM(IN_ROOM(i)), world[IN_ROOM(i)].name);
	send_to_char(buf, ch);
      }
    for (num = 0, k = object_list; k; k = k->next)
      if (CAN_SEE_OBJ(ch, k) && isname(arg, k->name)) {
	found = 1;
	print_object_location(++num, k, ch, TRUE);
      }
    if (!found)
      send_to_char("Couldn't find any such thing.\r\n", ch);
  }
}



ACMD(do_where)
{
  one_argument(argument, arg);

  if (GET_LEVEL(ch) >= LVL_IMMORT)
    perform_immort_where(ch, arg);
  else
    perform_mortal_where(ch, arg);
}



ACMD(do_levels)
{
  int i;

  if (IS_NPC(ch)) {
    send_to_char("You ain't nothin' but a hound-dog.\r\n", ch);
    return;
  }
  *buf = '\0';

  for (i = 1; i < LVL_IMMORT; i++) {
    sprintf(buf + strlen(buf), "[%2d] %8d-%-8d : ", i,
	    level_exp(GET_CLASS(ch), i), level_exp(GET_CLASS(ch), i+1) - 1);
    switch (GET_SEX(ch)) {
    case SEX_MALE:
    case SEX_NEUTRAL:
      strcat(buf, title_male(GET_CLASS(ch), i));
      break;
    case SEX_FEMALE:
      strcat(buf, title_female(GET_CLASS(ch), i));
      break;
    default:
      send_to_char("Oh dear.  You seem to be sexless.\r\n", ch);
      break;
    }
    strcat(buf, "\r\n");
  }
  /*sprintf(buf + strlen(buf), "[%2d] %8d          : Immortality\r\n",
	  LVL_IMMORT, level_exp(GET_CLASS(ch), LVL_IMMORT));*/
  page_string(ch->desc, buf, 1);
}



ACMD(do_consider)
{
  struct char_data *victim;
  int diff;

  one_argument(argument, buf);

  if (!(victim = get_char_vis(ch, buf, FIND_CHAR_ROOM))) {
    send_to_char("Consider killing who?\r\n", ch);
    return;
  }
  if (victim == ch) {
    send_to_char("Easy!  Very easy indeed!\r\n", ch);
    return;
  }
  if (!IS_NPC(victim)) {
    send_to_char("Would you like to borrow a cross and a shovel?\r\n", ch);
    return;
  }
  diff = (GET_LEVEL(victim) - GET_LEVEL(ch));

  if (diff <= -10)
    send_to_char("Now where did that chicken go?\r\n", ch);
  else if (diff <= -5)
    send_to_char("You could do it with a needle!\r\n", ch);
  else if (diff <= -2)
    send_to_char("Easy.\r\n", ch);
  else if (diff <= -1)
    send_to_char("Fairly easy.\r\n", ch);
  else if (diff == 0)
    send_to_char("The perfect match!\r\n", ch);
  else if (diff <= 1)
    send_to_char("You would need some luck!\r\n", ch);
  else if (diff <= 2)
    send_to_char("You would need a lot of luck!\r\n", ch);
  else if (diff <= 3)
    send_to_char("You would need a lot of luck and great equipment!\r\n", ch);
  else if (diff <= 5)
    send_to_char("Do you feel lucky, punk?\r\n", ch);
  else if (diff <= 10)
    send_to_char("Are you mad!?\r\n", ch);
  else if (diff <= 100)
    send_to_char("You ARE mad!\r\n", ch);

}



ACMD(do_diagnose)
{
  struct char_data *vict;

  one_argument(argument, buf);

  if (*buf) {
    if (!(vict = get_char_vis(ch, buf, FIND_CHAR_ROOM)))
      send_to_char(NOPERSON, ch);
    else
      diag_char_to_char(vict, ch);
  } else {
    if (FIGHTING(ch))
      diag_char_to_char(FIGHTING(ch), ch);
    else
      send_to_char("Diagnose who?\r\n", ch);
  }
}


const char *ctypes[] = {
  "off", "sparse", "normal", "complete", "\n"
};

ACMD(do_color)
{
  int tp;

  if (IS_NPC(ch))
    return;

  one_argument(argument, arg);

  if (!*arg) {
    sprintf(buf, "Your current color level is %s.\r\n", ctypes[COLOR_LEV(ch)]);
    send_to_char(buf, ch);
    return;
  }
  if (((tp = search_block(arg, ctypes, FALSE)) == -1)) {
    send_to_char("Usage: color { Off | Sparse | Normal | Complete }\r\n", ch);
    return;
  }
  REMOVE_BIT(PRF_FLAGS(ch), PRF_COLOR_1 | PRF_COLOR_2);
  SET_BIT(PRF_FLAGS(ch), (PRF_COLOR_1 * (tp & 1)) | (PRF_COLOR_2 * (tp & 2) >> 1));

  sprintf(buf, "Your %scolor%s is now %s.\r\n", CCRED(ch, C_SPR),
	  CCNRM(ch, C_OFF), ctypes[tp]);
  send_to_char(buf, ch);
}


ACMD(do_toggle)
{
  if (IS_NPC(ch))
    return;
  if (GET_WIMP_LEV(ch) == 0)
    strcpy(buf2, "OFF");
  else
    sprintf(buf2, "%-3d", GET_WIMP_LEV(ch));

  if (GET_LEVEL(ch) >= LVL_IMMORT) {
    sprintf(buf,
	  "      No Hassle: %-3s    "
	  "      Holylight: %-3s    "
	  "     Room Flags: %-3s\r\n",
	ONOFF(PRF_FLAGGED(ch, PRF_NOHASSLE)),
	ONOFF(PRF_FLAGGED(ch, PRF_HOLYLIGHT)),
	ONOFF(PRF_FLAGGED(ch, PRF_ROOMFLAGS))
    );
    send_to_char(buf, ch);
  }

  sprintf(buf,
	  "Hit Pnt Display: %-3s    "
	  "     Brief Mode: %-3s    "
	  " Summon Protect: %-3s\r\n"

	  "   Move Display: %-3s    "
	  "   Compact Mode: %-3s    "
	  "       On Quest: %-3s\r\n"

	  "   Mana Display: %-3s    "
	  "         NoTell: %-3s    "
	  "   Repeat Comm.: %-3s\r\n"

	  " Auto Show Exit: %-3s    "
	  "           Deaf: %-3s    "
	  "     Wimp Level: %-3s\r\n"

	  " Gossip Channel: %-3s    "
	  "Auction Channel: %-3s    "
	  "  Grats Channel: %-3s\r\n"

          "      Auto Loot: %-3s    "
          "     Auto Title: %-3s\r\n"
	  "    Color Level: %s\r\n",

	  ONOFF(PRF_FLAGGED(ch, PRF_DISPHP)),
	  ONOFF(PRF_FLAGGED(ch, PRF_BRIEF)),
	  ONOFF(!PRF_FLAGGED(ch, PRF_SUMMONABLE)),

	  ONOFF(PRF_FLAGGED(ch, PRF_DISPMOVE)),
	  ONOFF(PRF_FLAGGED(ch, PRF_COMPACT)),
	  YESNO(PRF_FLAGGED(ch, PRF_QUEST)),

	  ONOFF(PRF_FLAGGED(ch, PRF_DISPMANA)),
	  ONOFF(PRF_FLAGGED(ch, PRF_NOTELL)),
	  YESNO(!PRF_FLAGGED(ch, PRF_NOREPEAT)),

	  ONOFF(PRF_FLAGGED(ch, PRF_AUTOEXIT)),
	  YESNO(PRF_FLAGGED(ch, PRF_DEAF)),
	  buf2,

	  ONOFF(!PRF_FLAGGED(ch, PRF_NOGOSS)),
	  ONOFF(!PRF_FLAGGED(ch, PRF_NOAUCT)),
	  ONOFF(!PRF_FLAGGED(ch, PRF_NOGRATZ)),

          ONOFF(PRF_FLAGGED(ch, PRF_AUTOLOOT)),
          ONOFF(PRF_FLAGGED(ch, PRF_AUTOTITLE)),
	  ctypes[COLOR_LEV(ch)]);

  send_to_char(buf, ch);
}


struct sort_struct {
  int sort_pos;
  byte is_social;
} *cmd_sort_info = NULL;

int num_of_cmds;


void sort_commands(void)
{
  int a, b, tmp;

  num_of_cmds = 0;

  /*
   * first, count commands (num_of_commands is actually one greater than the
   * number of commands; it inclues the '\n'.
   */
  while (*cmd_info[num_of_cmds].command != '\n')
    num_of_cmds++;

  /* create data array */
  CREATE(cmd_sort_info, struct sort_struct, num_of_cmds);

  /* initialize it */
  for (a = 1; a < num_of_cmds; a++) {
    cmd_sort_info[a].sort_pos = a;
    cmd_sort_info[a].is_social = (cmd_info[a].command_pointer == do_action);
  }

  /* the infernal special case */
  cmd_sort_info[find_command("insult")].is_social = TRUE;

  /* Sort.  'a' starts at 1, not 0, to remove 'RESERVED' */
  for (a = 1; a < num_of_cmds - 1; a++)
    for (b = a + 1; b < num_of_cmds; b++)
      if (strcmp(cmd_info[cmd_sort_info[a].sort_pos].command,
		 cmd_info[cmd_sort_info[b].sort_pos].command) > 0) {
	tmp = cmd_sort_info[a].sort_pos;
	cmd_sort_info[a].sort_pos = cmd_sort_info[b].sort_pos;
	cmd_sort_info[b].sort_pos = tmp;
      }
}



ACMD(do_commands)
{
  int no, i, cmd_num;
  int wizhelp = 0, socials = 0;
  struct char_data *vict;

  one_argument(argument, arg);

  if (*arg) {
    if (!(vict = get_char_vis(ch, arg, FIND_CHAR_WORLD)) || IS_NPC(vict)) {
      send_to_char("Who is that?\r\n", ch);
      return;
    }
    if (GET_LEVEL(ch) < GET_LEVEL(vict)) {
      send_to_char("You can't see the commands of people above your level.\r\n", ch);
      return;
    }
  } else
    vict = ch;

  if (subcmd == SCMD_SOCIALS)
    socials = 1;
  else if (subcmd == SCMD_WIZHELP)
    wizhelp = 1;

  sprintf(buf, "The following %s%s are available to %s:\r\n",
	  wizhelp ? "privileged " : "",
	  socials ? "socials" : "commands",
	  vict == ch ? "you" : GET_NAME(vict));

  /* cmd_num starts at 1, not 0, to remove 'RESERVED' */
  for (no = 1, cmd_num = 1; cmd_num < num_of_cmds; cmd_num++) {
    i = cmd_sort_info[cmd_num].sort_pos;
    if (cmd_info[i].minimum_level >= 0 &&
	GET_LEVEL(vict) >= cmd_info[i].minimum_level &&
	(cmd_info[i].minimum_level >= LVL_IMMORT) == wizhelp &&
	(wizhelp || socials == cmd_sort_info[i].is_social)) {
      sprintf(buf + strlen(buf), "%-11s", cmd_info[i].command);
      if (!(no % 7))
	strcat(buf, "\r\n");
      no++;
    }
  }

  strcat(buf, "\r\n");
  send_to_char(buf, ch);
}


ACMD(do_listen)
{
   struct char_data *tch, *tch_next;
   int dir, percent, found = 0;
   char *heard_nothing = "You don't hear anything unusual.\r\n";
   char *room_spiel    = "$n seems to listen intently for something.";


  if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_LISTEN)) {
    send_to_char("Huh?.\r\n", ch);
    return;
  }

   percent = number(1,101);

   if (GET_SKILL(ch, SKILL_LISTEN) < percent) {
      send_to_char(heard_nothing, ch);
      return;
   }

   one_argument(argument, buf);

   if (!*buf) {
      /* no argument means that the character is listening for
       * hidden or invisible beings in the room he/she is in
       */
      for(tch = world[ch->in_room].people; tch; tch = tch_next) {
         tch_next = tch->next_in_room;
         if((tch != ch) && !CAN_SEE(ch, tch) && (GET_LEVEL(tch) < LVL_IMMORT))
            found++;
      }
      if (found) {
         if(GET_LEVEL(ch) >= 15) {
            /* being a higher level is better */
            sprintf(buf, "You hear what might be %d creatures invisible, or hiding.\r\n", \
                        MAX(1,(found+number(0,1)-number(0,1))));
         }
         else sprintf(buf, "You hear an odd rustling in the immediate area.\r\n");
         send_to_char(buf, ch);
      }
      else send_to_char(heard_nothing, ch);
      act(room_spiel, TRUE, ch, 0, 0, TO_ROOM);
      return;
   }
   else {
      /* the argument must be one of the cardinal directions: north,
       * south, etc.
       */
      for (dir = 0; dir < NUM_OF_DIRS; dir++) {
         if ( (!strncmp(buf, dirs[dir], strlen(buf))) ||
              (!strncmp(buf, abbr_dirs[dir], strlen(buf))) )
            break; 
      }
      if (dir == NUM_OF_DIRS) {
         send_to_char("Listen where?\r\n", ch);
         return;
      }
      if (CAN_GO(ch, dir) || CAN_LISTEN_BEHIND_DOOR(ch, dir)) {
         for(tch = world[EXIT(ch, dir)->to_room].people; tch;tch=tch_next) {
            tch_next = tch->next_in_room;
            found++;
         }
         if (found) {

            if (GET_LEVEL(ch) >= 15) {
               sprintf(buf, "You hear what might be %d creatures %s%s.\r\n", \
                        MAX(1,(found+number(0,1)-number(0,1))),
                        ((dir==5)?"below":(dir==4)?"above": "to the "),
                        ((dir==5)?"":(dir==4)?"":dirs[dir]));
            }
            else sprintf(buf, "You hear sounds from %s%s.\r\n", \
                        ((dir==5)?"below":(dir==4)?"above": "the "),
                        ((dir==5)?"":(dir==4)?"":dirs[dir]));
            send_to_char(buf, ch);
         }
         else send_to_char(heard_nothing, ch);
         act(room_spiel, TRUE, ch, 0, 0, TO_ROOM);
         return;
      }
      else send_to_char("You can't listen in that direction.\r\n", ch);
      return;
   }
   return;
}