/ circle3.1 / src / act.informative.c
act.informative.c
   1  /* ************************************************************************
   2  *   File: act.informative.c                             Part of CircleMUD *
   3  *  Usage: Player-level commands of an informative nature                  *
   4  *                                                                         *
   5  *  All rights reserved.  See license.doc for complete information.        *
   6  *                                                                         *
   7  *  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
   8  *  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
   9  ************************************************************************ */
  10  
  11  #include "conf.h"
  12  #include "sysdep.h"
  13  
  14  #include "structs.h"
  15  #include "utils.h"
  16  #include "comm.h"
  17  #include "interpreter.h"
  18  #include "handler.h"
  19  #include "db.h"
  20  #include "spells.h"
  21  #include "screen.h"
  22  #include "constants.h"
  23  
  24  /* extern variables */
  25  extern int top_of_helpt;
  26  extern struct help_index_element *help_table;
  27  extern char *help;
  28  extern struct time_info_data time_info;
  29  
  30  extern char *credits;
  31  extern char *news;
  32  extern char *info;
  33  extern char *motd;
  34  extern char *imotd;
  35  extern char *wizlist;
  36  extern char *immlist;
  37  extern char *policies;
  38  extern char *handbook;
  39  extern char *class_abbrevs[];
  40  
  41  /* extern functions */
  42  ACMD(do_action);
  43  ACMD(do_insult);
  44  bitvector_t find_class_bitvector(const char *arg);
  45  int level_exp(int chclass, int level);
  46  char *title_male(int chclass, int level);
  47  char *title_female(int chclass, int level);
  48  struct time_info_data *real_time_passed(time_t t2, time_t t1);
  49  int compute_armor_class(struct char_data *ch);
  50  
  51  /* local functions */
  52  int sort_commands_helper(const void *a, const void *b);
  53  void print_object_location(int num, struct obj_data *obj, struct char_data *ch, int recur);
  54  void show_obj_to_char(struct obj_data *obj, struct char_data *ch, int mode);
  55  void list_obj_to_char(struct obj_data *list, struct char_data *ch, int mode, int show);
  56  void show_obj_modifiers(struct obj_data *obj, struct char_data *ch);
  57  ACMD(do_look);
  58  ACMD(do_examine);
  59  ACMD(do_gold);
  60  ACMD(do_score);
  61  ACMD(do_inventory);
  62  ACMD(do_equipment);
  63  ACMD(do_time);
  64  ACMD(do_weather);
  65  ACMD(do_help);
  66  ACMD(do_who);
  67  ACMD(do_users);
  68  ACMD(do_gen_ps);
  69  void perform_mortal_where(struct char_data *ch, char *arg);
  70  void perform_immort_where(struct char_data *ch, char *arg);
  71  ACMD(do_where);
  72  ACMD(do_levels);
  73  ACMD(do_consider);
  74  ACMD(do_diagnose);
  75  ACMD(do_color);
  76  ACMD(do_toggle);
  77  void sort_commands(void);
  78  ACMD(do_commands);
  79  void diag_char_to_char(struct char_data *i, struct char_data *ch);
  80  void look_at_char(struct char_data *i, struct char_data *ch);
  81  void list_one_char(struct char_data *i, struct char_data *ch);
  82  void list_char_to_char(struct char_data *list, struct char_data *ch);
  83  void do_auto_exits(struct char_data *ch);
  84  ACMD(do_exits);
  85  void look_in_direction(struct char_data *ch, int dir);
  86  void look_in_obj(struct char_data *ch, char *arg);
  87  char *find_exdesc(char *word, struct extra_descr_data *list);
  88  void look_at_target(struct char_data *ch, char *arg);
  89  
  90  /* local globals */
  91  int *cmd_sort_info;
  92  
  93  /* For show_obj_to_char 'mode'.	/-- arbitrary */
  94  #define SHOW_OBJ_LONG		0
  95  #define SHOW_OBJ_SHORT		1
  96  #define SHOW_OBJ_ACTION		2
  97  
  98  
  99  void show_obj_to_char(struct obj_data *obj, struct char_data *ch, int mode)
 100  {
 101    if (!obj || !ch) {
 102      log("SYSERR: NULL pointer in show_obj_to_char(): obj=%p ch=%p", obj, ch);
 103      return;
 104    }
 105  
 106    switch (mode) {
 107    case SHOW_OBJ_LONG:
 108      send_to_char(ch, "%s", obj->description);
 109      break;
 110  
 111    case SHOW_OBJ_SHORT:
 112      send_to_char(ch, "%s", obj->short_description);
 113      break;
 114  
 115    case SHOW_OBJ_ACTION:
 116      switch (GET_OBJ_TYPE(obj)) {
 117      case ITEM_NOTE:
 118        if (obj->action_description) {
 119          char notebuf[MAX_NOTE_LENGTH + 64];
 120  
 121          snprintf(notebuf, sizeof(notebuf), "There is something written on it:\r\n\r\n%s", obj->action_description);
 122          page_string(ch->desc, notebuf, TRUE);
 123        } else
 124  	send_to_char(ch, "It's blank.\r\n");
 125        return;
 126  
 127      case ITEM_DRINKCON:
 128        send_to_char(ch, "It looks like a drink container.");
 129        break;
 130  
 131      default:
 132        send_to_char(ch, "You see nothing special..");
 133        break;
 134      }
 135      break;
 136  
 137    default:
 138      log("SYSERR: Bad display mode (%d) in show_obj_to_char().", mode);
 139      return;
 140    }
 141  
 142    show_obj_modifiers(obj, ch);
 143    send_to_char(ch, "\r\n");
 144  }
 145  
 146  
 147  void show_obj_modifiers(struct obj_data *obj, struct char_data *ch)
 148  {
 149    if (OBJ_FLAGGED(obj, ITEM_INVISIBLE))
 150      send_to_char(ch, " (invisible)");
 151  
 152    if (OBJ_FLAGGED(obj, ITEM_BLESS) && AFF_FLAGGED(ch, AFF_DETECT_ALIGN))
 153      send_to_char(ch, " ..It glows blue!");
 154  
 155    if (OBJ_FLAGGED(obj, ITEM_MAGIC) && AFF_FLAGGED(ch, AFF_DETECT_MAGIC))
 156      send_to_char(ch, " ..It glows yellow!");
 157  
 158    if (OBJ_FLAGGED(obj, ITEM_GLOW))
 159      send_to_char(ch, " ..It has a soft glowing aura!");
 160  
 161    if (OBJ_FLAGGED(obj, ITEM_HUM))
 162      send_to_char(ch, " ..It emits a faint humming sound!");
 163  }
 164  
 165  
 166  void list_obj_to_char(struct obj_data *list, struct char_data *ch, int mode, int show)
 167  {
 168    struct obj_data *i;
 169    bool found = FALSE;
 170  
 171    for (i = list; i; i = i->next_content) {
 172      if (CAN_SEE_OBJ(ch, i)) {
 173        show_obj_to_char(i, ch, mode);
 174        found = TRUE;
 175      }
 176    }
 177    if (!found && show)
 178      send_to_char(ch, " Nothing.\r\n");
 179  }
 180  
 181  
 182  void diag_char_to_char(struct char_data *i, struct char_data *ch)
 183  {
 184    struct {
 185      byte percent;
 186      const char *text;
 187    } diagnosis[] = {
 188      { 100, "is in excellent condition."			},
 189      {  90, "has a few scratches."			},
 190      {  75, "has some small wounds and bruises."		},
 191      {  50, "has quite a few wounds."			},
 192      {  30, "has some big nasty wounds and scratches."	},
 193      {  15, "looks pretty hurt."				},
 194      {   0, "is in awful condition."			},
 195      {  -1, "is bleeding awfully from big wounds."	},
 196    };
 197    int percent, ar_index;
 198    const char *pers = PERS(i, ch);
 199  
 200    if (GET_MAX_HIT(i) > 0)
 201      percent = (100 * GET_HIT(i)) / GET_MAX_HIT(i);
 202    else
 203      percent = -1;		/* How could MAX_HIT be < 1?? */
 204  
 205    for (ar_index = 0; diagnosis[ar_index].percent >= 0; ar_index++)
 206      if (percent >= diagnosis[ar_index].percent)
 207        break;
 208  
 209    send_to_char(ch, "%c%s %s\r\n", UPPER(*pers), pers + 1, diagnosis[ar_index].text);
 210  }
 211  
 212  
 213  void look_at_char(struct char_data *i, struct char_data *ch)
 214  {
 215    int j, found;
 216    struct obj_data *tmp_obj;
 217  
 218    if (!ch->desc)
 219      return;
 220  
 221     if (i->player.description)
 222      send_to_char(ch, "%s", i->player.description);
 223    else
 224      act("You see nothing special about $m.", FALSE, i, 0, ch, TO_VICT);
 225  
 226    diag_char_to_char(i, ch);
 227  
 228    found = FALSE;
 229    for (j = 0; !found && j < NUM_WEARS; j++)
 230      if (GET_EQ(i, j) && CAN_SEE_OBJ(ch, GET_EQ(i, j)))
 231        found = TRUE;
 232  
 233    if (found) {
 234      send_to_char(ch, "\r\n");	/* act() does capitalization. */
 235      act("$n is using:", FALSE, i, 0, ch, TO_VICT);
 236      for (j = 0; j < NUM_WEARS; j++)
 237        if (GET_EQ(i, j) && CAN_SEE_OBJ(ch, GET_EQ(i, j))) {
 238  	send_to_char(ch, "%s", wear_where[j]);
 239  	show_obj_to_char(GET_EQ(i, j), ch, SHOW_OBJ_SHORT);
 240        }
 241    }
 242    if (ch != i && (IS_THIEF(ch) || GET_LEVEL(ch) >= LVL_IMMORT)) {
 243      found = FALSE;
 244      act("\r\nYou attempt to peek at $s inventory:", FALSE, i, 0, ch, TO_VICT);
 245      for (tmp_obj = i->carrying; tmp_obj; tmp_obj = tmp_obj->next_content) {
 246        if (CAN_SEE_OBJ(ch, tmp_obj) && (rand_number(0, 20) < GET_LEVEL(ch))) {
 247  	show_obj_to_char(tmp_obj, ch, SHOW_OBJ_SHORT);
 248  	found = TRUE;
 249        }
 250      }
 251  
 252      if (!found)
 253        send_to_char(ch, "You can't see anything.\r\n");
 254    }
 255  }
 256  
 257  
 258  void list_one_char(struct char_data *i, struct char_data *ch)
 259  {
 260    const char *positions[] = {
 261      " is lying here, dead.",
 262      " is lying here, mortally wounded.",
 263      " is lying here, incapacitated.",
 264      " is lying here, stunned.",
 265      " is sleeping here.",
 266      " is resting here.",
 267      " is sitting here.",
 268      "!FIGHTING!",
 269      " is standing here."
 270    };
 271  
 272    if (IS_NPC(i) && i->player.long_descr && GET_POS(i) == GET_DEFAULT_POS(i)) {
 273      if (AFF_FLAGGED(i, AFF_INVISIBLE))
 274        send_to_char(ch, "*");
 275  
 276      if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) {
 277        if (IS_EVIL(i))
 278  	send_to_char(ch, "(Red Aura) ");
 279        else if (IS_GOOD(i))
 280  	send_to_char(ch, "(Blue Aura) ");
 281      }
 282      send_to_char(ch, "%s", i->player.long_descr);
 283  
 284      if (AFF_FLAGGED(i, AFF_SANCTUARY))
 285        act("...$e glows with a bright light!", FALSE, i, 0, ch, TO_VICT);
 286      if (AFF_FLAGGED(i, AFF_BLIND))
 287        act("...$e is groping around blindly!", FALSE, i, 0, ch, TO_VICT);
 288  
 289      return;
 290    }
 291  
 292    if (IS_NPC(i))
 293      send_to_char(ch, "%c%s", UPPER(*i->player.short_descr), i->player.short_descr + 1);
 294    else
 295      send_to_char(ch, "%s %s", i->player.name, GET_TITLE(i));
 296  
 297    if (AFF_FLAGGED(i, AFF_INVISIBLE))
 298      send_to_char(ch, " (invisible)");
 299    if (AFF_FLAGGED(i, AFF_HIDE))
 300      send_to_char(ch, " (hidden)");
 301    if (!IS_NPC(i) && !i->desc)
 302      send_to_char(ch, " (linkless)");
 303    if (!IS_NPC(i) && PLR_FLAGGED(i, PLR_WRITING))
 304      send_to_char(ch, " (writing)");
 305  
 306    if (GET_POS(i) != POS_FIGHTING)
 307      send_to_char(ch, "%s", positions[(int) GET_POS(i)]);
 308    else {
 309      if (FIGHTING(i)) {
 310        send_to_char(ch, " is here, fighting ");
 311        if (FIGHTING(i) == ch)
 312  	send_to_char(ch, "YOU!");
 313        else {
 314  	if (IN_ROOM(i) == IN_ROOM(FIGHTING(i)))
 315  	  send_to_char(ch, "%s!", PERS(FIGHTING(i), ch));
 316  	else
 317  	  send_to_char(ch,  "someone who has already left!");
 318        }
 319      } else			/* NIL fighting pointer */
 320        send_to_char(ch, " is here struggling with thin air.");
 321    }
 322  
 323    if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) {
 324      if (IS_EVIL(i))
 325        send_to_char(ch, " (Red Aura)");
 326      else if (IS_GOOD(i))
 327        send_to_char(ch, " (Blue Aura)");
 328    }
 329    send_to_char(ch, "\r\n");
 330  
 331    if (AFF_FLAGGED(i, AFF_SANCTUARY))
 332      act("...$e glows with a bright light!", FALSE, i, 0, ch, TO_VICT);
 333  }
 334  
 335  
 336  
 337  void list_char_to_char(struct char_data *list, struct char_data *ch)
 338  {
 339    struct char_data *i;
 340  
 341    for (i = list; i; i = i->next_in_room)
 342      if (ch != i) {
 343        if (CAN_SEE(ch, i))
 344  	list_one_char(i, ch);
 345        else if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch) &&
 346  	       AFF_FLAGGED(i, AFF_INFRAVISION))
 347  	send_to_char(ch, "You see a pair of glowing red eyes looking your way.\r\n");
 348      }
 349  }
 350  
 351  
 352  void do_auto_exits(struct char_data *ch)
 353  {
 354    int door, slen = 0;
 355  
 356    send_to_char(ch, "%s[ Exits: ", CCCYN(ch, C_NRM));
 357  
 358    for (door = 0; door < NUM_OF_DIRS; door++) {
 359      if (!EXIT(ch, door) || EXIT(ch, door)->to_room == NOWHERE)
 360        continue;
 361      if (EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED))
 362        continue;
 363  
 364      send_to_char(ch, "%c ", LOWER(*dirs[door]));
 365      slen++;
 366    }
 367  
 368    send_to_char(ch, "%s]%s\r\n", slen ? "" : "None!", CCNRM(ch, C_NRM));
 369  }
 370  
 371  
 372  ACMD(do_exits)
 373  {
 374    int door, len = 0;
 375  
 376    if (AFF_FLAGGED(ch, AFF_BLIND)) {
 377      send_to_char(ch, "You can't see a damned thing, you're blind!\r\n");
 378      return;
 379    }
 380  
 381    send_to_char(ch, "Obvious exits:\r\n");
 382  
 383    for (door = 0; door < NUM_OF_DIRS; door++) {
 384      if (!EXIT(ch, door) || EXIT(ch, door)->to_room == NOWHERE)
 385        continue;
 386      if (EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED))
 387        continue;
 388  
 389      len++;
 390  
 391      if (GET_LEVEL(ch) >= LVL_IMMORT)
 392        send_to_char(ch, "%-5s - [%5d] %s\r\n", dirs[door], GET_ROOM_VNUM(EXIT(ch, door)->to_room),
 393  		world[EXIT(ch, door)->to_room].name);
 394      else
 395        send_to_char(ch, "%-5s - %s\r\n", dirs[door], IS_DARK(EXIT(ch, door)->to_room) &&
 396  		!CAN_SEE_IN_DARK(ch) ? "Too dark to tell." : world[EXIT(ch, door)->to_room].name);
 397    }
 398  
 399    if (!len)
 400      send_to_char(ch, " None.\r\n");
 401  }
 402  
 403  
 404  
 405  void look_at_room(struct char_data *ch, int ignore_brief)
 406  {
 407    if (!ch->desc)
 408      return;
 409  
 410    if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch)) {
 411      send_to_char(ch, "It is pitch black...\r\n");
 412      return;
 413    } else if (AFF_FLAGGED(ch, AFF_BLIND)) {
 414      send_to_char(ch, "You see nothing but infinite darkness...\r\n");
 415      return;
 416    }
 417    send_to_char(ch, "%s", CCCYN(ch, C_NRM));
 418    if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_ROOMFLAGS)) {
 419      char buf[MAX_STRING_LENGTH];
 420  
 421      sprintbit(ROOM_FLAGS(IN_ROOM(ch)), room_bits, buf, sizeof(buf));
 422      send_to_char(ch, "[%5d] %s [ %s]", GET_ROOM_VNUM(IN_ROOM(ch)), world[IN_ROOM(ch)].name, buf);
 423    } else
 424      send_to_char(ch, "%s", world[IN_ROOM(ch)].name);
 425  
 426    send_to_char(ch, "%s\r\n", CCNRM(ch, C_NRM));
 427  
 428    if ((!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_BRIEF)) || ignore_brief ||
 429        ROOM_FLAGGED(IN_ROOM(ch), ROOM_DEATH))
 430      send_to_char(ch, "%s", world[IN_ROOM(ch)].description);
 431  
 432    /* autoexits */
 433    if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOEXIT))
 434      do_auto_exits(ch);
 435  
 436    /* now list characters & objects */
 437    send_to_char(ch, "%s", CCGRN(ch, C_NRM));
 438    list_obj_to_char(world[IN_ROOM(ch)].contents, ch, SHOW_OBJ_LONG, FALSE);
 439    send_to_char(ch, "%s", CCYEL(ch, C_NRM));
 440    list_char_to_char(world[IN_ROOM(ch)].people, ch);
 441    send_to_char(ch, "%s", CCNRM(ch, C_NRM));
 442  }
 443  
 444  
 445  
 446  void look_in_direction(struct char_data *ch, int dir)
 447  {
 448    if (EXIT(ch, dir)) {
 449      if (EXIT(ch, dir)->general_description)
 450        send_to_char(ch, "%s", EXIT(ch, dir)->general_description);
 451      else
 452        send_to_char(ch, "You see nothing special.\r\n");
 453  
 454      if (EXIT_FLAGGED(EXIT(ch, dir), EX_CLOSED) && EXIT(ch, dir)->keyword)
 455        send_to_char(ch, "The %s is closed.\r\n", fname(EXIT(ch, dir)->keyword));
 456      else if (EXIT_FLAGGED(EXIT(ch, dir), EX_ISDOOR) && EXIT(ch, dir)->keyword)
 457        send_to_char(ch, "The %s is open.\r\n", fname(EXIT(ch, dir)->keyword));
 458    } else
 459      send_to_char(ch, "Nothing special there...\r\n");
 460  }
 461  
 462  
 463  
 464  void look_in_obj(struct char_data *ch, char *arg)
 465  {
 466    struct obj_data *obj = NULL;
 467    struct char_data *dummy = NULL;
 468    int amt, bits;
 469  
 470    if (!*arg)
 471      send_to_char(ch, "Look in what?\r\n");
 472    else if (!(bits = generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM |
 473  				 FIND_OBJ_EQUIP, ch, &dummy, &obj))) {
 474      send_to_char(ch, "There doesn't seem to be %s %s here.\r\n", AN(arg), arg);
 475    } else if ((GET_OBJ_TYPE(obj) != ITEM_DRINKCON) &&
 476  	     (GET_OBJ_TYPE(obj) != ITEM_FOUNTAIN) &&
 477  	     (GET_OBJ_TYPE(obj) != ITEM_CONTAINER))
 478      send_to_char(ch, "There's nothing inside that!\r\n");
 479    else {
 480      if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER) {
 481        if (OBJVAL_FLAGGED(obj, CONT_CLOSED))
 482  	send_to_char(ch, "It is closed.\r\n");
 483        else {
 484  	send_to_char(ch, "%s", fname(obj->name));
 485  	switch (bits) {
 486  	case FIND_OBJ_INV:
 487  	  send_to_char(ch, " (carried): \r\n");
 488  	  break;
 489  	case FIND_OBJ_ROOM:
 490  	  send_to_char(ch, " (here): \r\n");
 491  	  break;
 492  	case FIND_OBJ_EQUIP:
 493  	  send_to_char(ch, " (used): \r\n");
 494  	  break;
 495  	}
 496  
 497  	list_obj_to_char(obj->contains, ch, SHOW_OBJ_SHORT, TRUE);
 498        }
 499      } else {		/* item must be a fountain or drink container */
 500        if (GET_OBJ_VAL(obj, 1) <= 0)
 501  	send_to_char(ch, "It is empty.\r\n");
 502        else {
 503  	if (GET_OBJ_VAL(obj,0) <= 0 || GET_OBJ_VAL(obj,1)>GET_OBJ_VAL(obj,0)) {
 504  	  send_to_char(ch, "Its contents seem somewhat murky.\r\n"); /* BUG */
 505  	} else {
 506            char buf2[MAX_STRING_LENGTH];
 507  	  amt = (GET_OBJ_VAL(obj, 1) * 3) / GET_OBJ_VAL(obj, 0);
 508  	  sprinttype(GET_OBJ_VAL(obj, 2), color_liquid, buf2, sizeof(buf2));
 509  	  send_to_char(ch, "It's %sfull of a %s liquid.\r\n", fullness[amt], buf2);
 510  	}
 511        }
 512      }
 513    }
 514  }
 515  
 516  
 517  
 518  char *find_exdesc(char *word, struct extra_descr_data *list)
 519  {
 520    struct extra_descr_data *i;
 521  
 522    for (i = list; i; i = i->next)
 523      if (isname(word, i->keyword))
 524        return (i->description);
 525  
 526    return (NULL);
 527  }
 528  
 529  
 530  /*
 531   * Given the argument "look at <target>", figure out what object or char
 532   * matches the target.  First, see if there is another char in the room
 533   * with the name.  Then check local objs for exdescs.
 534   *
 535   * Thanks to Angus Mezick <angus@EDGIL.CCMAIL.COMPUSERVE.COM> for the
 536   * suggested fix to this problem.
 537   */
 538  void look_at_target(struct char_data *ch, char *arg)
 539  {
 540    int bits, found = FALSE, j, fnum, i = 0;
 541    struct char_data *found_char = NULL;
 542    struct obj_data *obj, *found_obj = NULL;
 543    char *desc;
 544  
 545    if (!ch->desc)
 546      return;
 547  
 548    if (!*arg) {
 549      send_to_char(ch, "Look at what?\r\n");
 550      return;
 551    }
 552  
 553    bits = generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP |
 554  		      FIND_CHAR_ROOM, ch, &found_char, &found_obj);
 555  
 556    /* Is the target a character? */
 557    if (found_char != NULL) {
 558      look_at_char(found_char, ch);
 559      if (ch != found_char) {
 560        if (CAN_SEE(found_char, ch))
 561  	act("$n looks at you.", TRUE, ch, 0, found_char, TO_VICT);
 562        act("$n looks at $N.", TRUE, ch, 0, found_char, TO_NOTVICT);
 563      }
 564      return;
 565    }
 566  
 567    /* Strip off "number." from 2.foo and friends. */
 568    if (!(fnum = get_number(&arg))) {
 569      send_to_char(ch, "Look at what?\r\n");
 570      return;
 571    }
 572  
 573    /* Does the argument match an extra desc in the room? */
 574    if ((desc = find_exdesc(arg, world[IN_ROOM(ch)].ex_description)) != NULL && ++i == fnum) {
 575      page_string(ch->desc, desc, FALSE);
 576      return;
 577    }
 578  
 579    /* Does the argument match an extra desc in the char's equipment? */
 580    for (j = 0; j < NUM_WEARS && !found; j++)
 581      if (GET_EQ(ch, j) && CAN_SEE_OBJ(ch, GET_EQ(ch, j)))
 582        if ((desc = find_exdesc(arg, GET_EQ(ch, j)->ex_description)) != NULL && ++i == fnum) {
 583  	send_to_char(ch, "%s", desc);
 584  	found = TRUE;
 585        }
 586  
 587    /* Does the argument match an extra desc in the char's inventory? */
 588    for (obj = ch->carrying; obj && !found; obj = obj->next_content) {
 589      if (CAN_SEE_OBJ(ch, obj))
 590        if ((desc = find_exdesc(arg, obj->ex_description)) != NULL && ++i == fnum) {
 591  	send_to_char(ch, "%s", desc);
 592  	found = TRUE;
 593        }
 594    }
 595  
 596    /* Does the argument match an extra desc of an object in the room? */
 597    for (obj = world[IN_ROOM(ch)].contents; obj && !found; obj = obj->next_content)
 598      if (CAN_SEE_OBJ(ch, obj))
 599        if ((desc = find_exdesc(arg, obj->ex_description)) != NULL && ++i == fnum) {
 600  	send_to_char(ch, "%s", desc);
 601  	found = TRUE;
 602        }
 603  
 604    /* If an object was found back in generic_find */
 605    if (bits) {
 606      if (!found)
 607        show_obj_to_char(found_obj, ch, SHOW_OBJ_ACTION);
 608      else {
 609        show_obj_modifiers(found_obj, ch);
 610        send_to_char(ch, "\r\n");
 611      }
 612    } else if (!found)
 613      send_to_char(ch, "You do not see that here.\r\n");
 614  }
 615  
 616  
 617  ACMD(do_look)
 618  {
 619    int look_type;
 620  
 621    if (!ch->desc)
 622      return;
 623  
 624    if (GET_POS(ch) < POS_SLEEPING)
 625      send_to_char(ch, "You can't see anything but stars!\r\n");
 626    else if (AFF_FLAGGED(ch, AFF_BLIND))
 627      send_to_char(ch, "You can't see a damned thing, you're blind!\r\n");
 628    else if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch)) {
 629      send_to_char(ch, "It is pitch black...\r\n");
 630      list_char_to_char(world[IN_ROOM(ch)].people, ch);	/* glowing red eyes */
 631    } else {
 632      char arg[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
 633  
 634      half_chop(argument, arg, arg2);
 635  
 636      if (subcmd == SCMD_READ) {
 637        if (!*arg)
 638  	send_to_char(ch, "Read what?\r\n");
 639        else
 640  	look_at_target(ch, arg);
 641        return;
 642      }
 643      if (!*arg)			/* "look" alone, without an argument at all */
 644        look_at_room(ch, 1);
 645      else if (is_abbrev(arg, "in"))
 646        look_in_obj(ch, arg2);
 647      /* did the char type 'look <direction>?' */
 648      else if ((look_type = search_block(arg, dirs, FALSE)) >= 0)
 649        look_in_direction(ch, look_type);
 650      else if (is_abbrev(arg, "at"))
 651        look_at_target(ch, arg2);
 652      else
 653        look_at_target(ch, arg);
 654    }
 655  }
 656  
 657  
 658  
 659  ACMD(do_examine)
 660  {
 661    struct char_data *tmp_char;
 662    struct obj_data *tmp_object;
 663    char tempsave[MAX_INPUT_LENGTH], arg[MAX_INPUT_LENGTH];
 664  
 665    one_argument(argument, arg);
 666  
 667    if (!*arg) {
 668      send_to_char(ch, "Examine what?\r\n");
 669      return;
 670    }
 671  
 672    /* look_at_target() eats the number. */
 673    look_at_target(ch, strcpy(tempsave, arg));	/* strcpy: OK */
 674  
 675    generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_CHAR_ROOM |
 676  		      FIND_OBJ_EQUIP, ch, &tmp_char, &tmp_object);
 677  
 678    if (tmp_object) {
 679      if ((GET_OBJ_TYPE(tmp_object) == ITEM_DRINKCON) ||
 680  	(GET_OBJ_TYPE(tmp_object) == ITEM_FOUNTAIN) ||
 681  	(GET_OBJ_TYPE(tmp_object) == ITEM_CONTAINER)) {
 682        send_to_char(ch, "When you look inside, you see:\r\n");
 683        look_in_obj(ch, arg);
 684      }
 685    }
 686  }
 687  
 688  
 689  
 690  ACMD(do_gold)
 691  {
 692    if (GET_GOLD(ch) == 0)
 693      send_to_char(ch, "You're broke!\r\n");
 694    else if (GET_GOLD(ch) == 1)
 695      send_to_char(ch, "You have one miserable little gold coin.\r\n");
 696    else
 697      send_to_char(ch, "You have %d gold coins.\r\n", GET_GOLD(ch));
 698  }
 699  
 700  
 701  ACMD(do_score)
 702  {
 703    struct time_info_data playing_time;
 704  
 705    if (IS_NPC(ch))
 706      return;
 707  
 708    send_to_char(ch, "You are %d years old.\r\n", GET_AGE(ch));
 709  
 710    if (age(ch)->month == 0 && age(ch)->day == 0)
 711      send_to_char(ch, "  It's your birthday today.\r\n");
 712    else
 713      send_to_char(ch, "\r\n");
 714  
 715    send_to_char(ch, "You have %d(%d) hit, %d(%d) mana and %d(%d) movement points.\r\n",
 716  	  GET_HIT(ch), GET_MAX_HIT(ch), GET_MANA(ch), GET_MAX_MANA(ch),
 717  	  GET_MOVE(ch), GET_MAX_MOVE(ch));
 718  
 719    send_to_char(ch, "Your armor class is %d/10, and your alignment is %d.\r\n",
 720  	  compute_armor_class(ch), GET_ALIGNMENT(ch));
 721  
 722    send_to_char(ch, "You have scored %d exp, and have %d gold coins.\r\n",
 723  	  GET_EXP(ch), GET_GOLD(ch));
 724  
 725    if (GET_LEVEL(ch) < LVL_IMMORT)
 726      send_to_char(ch, "You need %d exp to reach your next level.\r\n",
 727  	level_exp(GET_CLASS(ch), GET_LEVEL(ch) + 1) - GET_EXP(ch));
 728  
 729    playing_time = *real_time_passed((time(0) - ch->player.time.logon) +
 730  				  ch->player.time.played, 0);
 731    send_to_char(ch, "You have been playing for %d day%s and %d hour%s.\r\n",
 732       playing_time.day, playing_time.day == 1 ? "" : "s",
 733       playing_time.hours, playing_time.hours == 1 ? "" : "s");
 734  
 735    send_to_char(ch, "This ranks you as %s %s (level %d).\r\n",
 736  	  GET_NAME(ch), GET_TITLE(ch), GET_LEVEL(ch));
 737  
 738    switch (GET_POS(ch)) {
 739    case POS_DEAD:
 740      send_to_char(ch, "You are DEAD!\r\n");
 741      break;
 742    case POS_MORTALLYW:
 743      send_to_char(ch, "You are mortally wounded!  You should seek help!\r\n");
 744      break;
 745    case POS_INCAP:
 746      send_to_char(ch, "You are incapacitated, slowly fading away...\r\n");
 747      break;
 748    case POS_STUNNED:
 749      send_to_char(ch, "You are stunned!  You can't move!\r\n");
 750      break;
 751    case POS_SLEEPING:
 752      send_to_char(ch, "You are sleeping.\r\n");
 753      break;
 754    case POS_RESTING:
 755      send_to_char(ch, "You are resting.\r\n");
 756      break;
 757    case POS_SITTING:
 758      send_to_char(ch, "You are sitting.\r\n");
 759      break;
 760    case POS_FIGHTING:
 761      send_to_char(ch, "You are fighting %s.\r\n", FIGHTING(ch) ? PERS(FIGHTING(ch), ch) : "thin air");
 762      break;
 763    case POS_STANDING:
 764      send_to_char(ch, "You are standing.\r\n");
 765      break;
 766    default:
 767      send_to_char(ch, "You are floating.\r\n");
 768      break;
 769    }
 770  
 771    if (GET_COND(ch, DRUNK) > 10)
 772      send_to_char(ch, "You are intoxicated.\r\n");
 773  
 774    if (GET_COND(ch, FULL) == 0)
 775      send_to_char(ch, "You are hungry.\r\n");
 776  
 777    if (GET_COND(ch, THIRST) == 0)
 778      send_to_char(ch, "You are thirsty.\r\n");
 779  
 780    if (AFF_FLAGGED(ch, AFF_BLIND))
 781      send_to_char(ch, "You have been blinded!\r\n");
 782  
 783    if (AFF_FLAGGED(ch, AFF_INVISIBLE))
 784      send_to_char(ch, "You are invisible.\r\n");
 785  
 786    if (AFF_FLAGGED(ch, AFF_DETECT_INVIS))
 787      send_to_char(ch, "You are sensitive to the presence of invisible things.\r\n");
 788  
 789    if (AFF_FLAGGED(ch, AFF_SANCTUARY))
 790      send_to_char(ch, "You are protected by Sanctuary.\r\n");
 791  
 792    if (AFF_FLAGGED(ch, AFF_POISON))
 793      send_to_char(ch, "You are poisoned!\r\n");
 794  
 795    if (AFF_FLAGGED(ch, AFF_CHARM))
 796      send_to_char(ch, "You have been charmed!\r\n");
 797  
 798    if (affected_by_spell(ch, SPELL_ARMOR))
 799      send_to_char(ch, "You feel protected.\r\n");
 800  
 801    if (AFF_FLAGGED(ch, AFF_INFRAVISION))
 802      send_to_char(ch, "Your eyes are glowing red.\r\n");
 803  
 804    if (PRF_FLAGGED(ch, PRF_SUMMONABLE))
 805      send_to_char(ch, "You are summonable by other players.\r\n");
 806  }
 807  
 808  
 809  ACMD(do_inventory)
 810  {
 811    send_to_char(ch, "You are carrying:\r\n");
 812    list_obj_to_char(ch->carrying, ch, SHOW_OBJ_SHORT, TRUE);
 813  }
 814  
 815  
 816  ACMD(do_equipment)
 817  {
 818    int i, found = 0;
 819  
 820    send_to_char(ch, "You are using:\r\n");
 821    for (i = 0; i < NUM_WEARS; i++) {
 822      if (GET_EQ(ch, i)) {
 823        if (CAN_SEE_OBJ(ch, GET_EQ(ch, i))) {
 824  	send_to_char(ch, "%s", wear_where[i]);
 825  	show_obj_to_char(GET_EQ(ch, i), ch, SHOW_OBJ_SHORT);
 826  	found = TRUE;
 827        } else {
 828  	send_to_char(ch, "%s", wear_where[i]);
 829  	send_to_char(ch, "Something.\r\n");
 830  	found = TRUE;
 831        }
 832      }
 833    }
 834    if (!found)
 835      send_to_char(ch, " Nothing.\r\n");
 836  }
 837  
 838  
 839  ACMD(do_time)
 840  {
 841    const char *suf;
 842    int weekday, day;
 843  
 844    /* day in [1..35] */
 845    day = time_info.day + 1;
 846  
 847    /* 35 days in a month, 7 days a week */
 848    weekday = ((35 * time_info.month) + day) % 7;
 849  
 850    send_to_char(ch, "It is %d o'clock %s, on %s.\r\n",
 851  	  (time_info.hours % 12 == 0) ? 12 : (time_info.hours % 12),
 852  	  time_info.hours >= 12 ? "pm" : "am", weekdays[weekday]);
 853  
 854    /*
 855     * Peter Ajamian <peter@PAJAMIAN.DHS.ORG> supplied the following as a fix
 856     * for a bug introduced in the ordinal display that caused 11, 12, and 13
 857     * to be incorrectly displayed as 11st, 12nd, and 13rd.  Nate Winters
 858     * <wintersn@HOTMAIL.COM> had already submitted a fix, but it hard-coded a
 859     * limit on ordinal display which I want to avoid.	-dak
 860     */
 861  
 862    suf = "th";
 863  
 864    if (((day % 100) / 10) != 1) {
 865      switch (day % 10) {
 866      case 1:
 867        suf = "st";
 868        break;
 869      case 2:
 870        suf = "nd";
 871        break;
 872      case 3:
 873        suf = "rd";
 874        break;
 875      }
 876    }
 877  
 878    send_to_char(ch, "The %d%s Day of the %s, Year %d.\r\n",
 879  	  day, suf, month_name[time_info.month], time_info.year);
 880  }
 881  
 882  
 883  ACMD(do_weather)
 884  {
 885    const char *sky_look[] = {
 886      "cloudless",
 887      "cloudy",
 888      "rainy",
 889      "lit by flashes of lightning"
 890    };
 891  
 892    if (OUTSIDE(ch))
 893      {
 894      send_to_char(ch, "The sky is %s and %s.\r\n", sky_look[weather_info.sky],
 895  	    weather_info.change >= 0 ? "you feel a warm wind from south" :
 896  	     "your foot tells you bad weather is due");
 897      if (GET_LEVEL(ch) >= LVL_GOD)
 898        send_to_char(ch, "Pressure: %d (change: %d), Sky: %d (%s)\r\n",
 899                   weather_info.pressure,
 900                   weather_info.change,
 901                   weather_info.sky,
 902                   sky_look[weather_info.sky]);
 903      }
 904    else
 905      send_to_char(ch, "You have no feeling about the weather at all.\r\n");
 906  }
 907  
 908  
 909  ACMD(do_help)
 910  {
 911    int chk, bot, top, mid, minlen;
 912  
 913    if (!ch->desc)
 914      return;
 915  
 916    skip_spaces(&argument);
 917  
 918    if (!*argument) {
 919      page_string(ch->desc, help, 0);
 920      return;
 921    }
 922    if (!help_table) {
 923      send_to_char(ch, "No help available.\r\n");
 924      return;
 925    }
 926  
 927    bot = 0;
 928    top = top_of_helpt;
 929    minlen = strlen(argument);
 930  
 931    for (;;) {
 932      mid = (bot + top) / 2;
 933  
 934      if (bot > top) {
 935        send_to_char(ch, "There is no help on that word.\r\n");
 936        return;
 937      } else if (!(chk = strn_cmp(argument, help_table[mid].keyword, minlen))) {
 938        /* trace backwards to find first matching entry. Thanks Jeff Fink! */
 939        while ((mid > 0) &&
 940  	 (!(chk = strn_cmp(argument, help_table[mid - 1].keyword, minlen))))
 941  	mid--;
 942        page_string(ch->desc, help_table[mid].entry, 0);
 943        return;
 944      } else {
 945        if (chk > 0)
 946          bot = mid + 1;
 947        else
 948          top = mid - 1;
 949      }
 950    }
 951  }
 952  
 953  
 954  
 955  #define WHO_FORMAT \
 956  "format: who [minlev[-maxlev]] [-n name] [-c classlist] [-s] [-o] [-q] [-r] [-z]\r\n"
 957  
 958  /* FIXME: This whole thing just needs rewritten. */
 959  ACMD(do_who)
 960  {
 961    struct descriptor_data *d;
 962    struct char_data *tch;
 963    char name_search[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH];
 964    char mode;
 965    int low = 0, high = LVL_IMPL, localwho = 0, questwho = 0;
 966    int showclass = 0, short_list = 0, outlaws = 0, num_can_see = 0;
 967    int who_room = 0;
 968  
 969    skip_spaces(&argument);
 970    strcpy(buf, argument);	/* strcpy: OK (sizeof: argument == buf) */
 971    name_search[0] = '\0';
 972  
 973    while (*buf) {
 974      char arg[MAX_INPUT_LENGTH], buf1[MAX_INPUT_LENGTH];
 975  
 976      half_chop(buf, arg, buf1);
 977      if (isdigit(*arg)) {
 978        sscanf(arg, "%d-%d", &low, &high);
 979        strcpy(buf, buf1);	/* strcpy: OK (sizeof: buf1 == buf) */
 980      } else if (*arg == '-') {
 981        mode = *(arg + 1);       /* just in case; we destroy arg in the switch */
 982        switch (mode) {
 983        case 'o':
 984        case 'k':
 985  	outlaws = 1;
 986  	strcpy(buf, buf1);	/* strcpy: OK (sizeof: buf1 == buf) */
 987  	break;
 988        case 'z':
 989  	localwho = 1;
 990  	strcpy(buf, buf1);	/* strcpy: OK (sizeof: buf1 == buf) */
 991  	break;
 992        case 's':
 993  	short_list = 1;
 994  	strcpy(buf, buf1);	/* strcpy: OK (sizeof: buf1 == buf) */
 995  	break;
 996        case 'q':
 997  	questwho = 1;
 998  	strcpy(buf, buf1);	/* strcpy: OK (sizeof: buf1 == buf) */
 999  	break;
1000        case 'l':
1001  	half_chop(buf1, arg, buf);
1002  	sscanf(arg, "%d-%d", &low, &high);
1003  	break;
1004        case 'n':
1005  	half_chop(buf1, name_search, buf);
1006  	break;
1007        case 'r':
1008  	who_room = 1;
1009  	strcpy(buf, buf1);	/* strcpy: OK (sizeof: buf1 == buf) */
1010  	break;
1011        case 'c':
1012  	half_chop(buf1, arg, buf);
1013  	showclass = find_class_bitvector(arg);
1014  	break;
1015        default:
1016  	send_to_char(ch, "%s", WHO_FORMAT);
1017  	return;
1018        }				/* end of switch */
1019  
1020      } else {			/* endif */
1021        send_to_char(ch, "%s", WHO_FORMAT);
1022        return;
1023      }
1024    }				/* end while (parser) */
1025  
1026    send_to_char(ch, "Players\r\n-------\r\n");
1027  
1028    for (d = descriptor_list; d; d = d->next) {
1029      if (STATE(d) != CON_PLAYING)
1030        continue;
1031  
1032      if (d->original)
1033        tch = d->original;
1034      else if (!(tch = d->character))
1035        continue;
1036  
1037      if (*name_search && str_cmp(GET_NAME(tch), name_search) &&
1038  	!strstr(GET_TITLE(tch), name_search))
1039        continue;
1040      if (!CAN_SEE(ch, tch) || GET_LEVEL(tch) < low || GET_LEVEL(tch) > high)
1041        continue;
1042      if (outlaws && !PLR_FLAGGED(tch, PLR_KILLER) &&
1043  	!PLR_FLAGGED(tch, PLR_THIEF))
1044        continue;
1045      if (questwho && !PRF_FLAGGED(tch, PRF_QUEST))
1046        continue;
1047      if (localwho && world[IN_ROOM(ch)].zone != world[IN_ROOM(tch)].zone)
1048        continue;
1049      if (who_room && (IN_ROOM(tch) != IN_ROOM(ch)))
1050        continue;
1051      if (showclass && !(showclass & (1 << GET_CLASS(tch))))
1052        continue;
1053      if (short_list) {
1054        send_to_char(ch, "%s[%2d %s] %-12.12s%s%s",
1055  	      (GET_LEVEL(tch) >= LVL_IMMORT ? CCYEL(ch, C_SPR) : ""),
1056  	      GET_LEVEL(tch), CLASS_ABBR(tch), GET_NAME(tch),
1057  	      (GET_LEVEL(tch) >= LVL_IMMORT ? CCNRM(ch, C_SPR) : ""),
1058  	      ((!(++num_can_see % 4)) ? "\r\n" : ""));
1059      } else {
1060        num_can_see++;
1061        send_to_char(ch, "%s[%2d %s] %s %s",
1062  	      (GET_LEVEL(tch) >= LVL_IMMORT ? CCYEL(ch, C_SPR) : ""),
1063  	      GET_LEVEL(tch), CLASS_ABBR(tch), GET_NAME(tch),
1064  	      GET_TITLE(tch));
1065  
1066        if (GET_INVIS_LEV(tch))
1067  	send_to_char(ch, " (i%d)", GET_INVIS_LEV(tch));
1068        else if (AFF_FLAGGED(tch, AFF_INVISIBLE))
1069  	send_to_char(ch, " (invis)");
1070  
1071        if (PLR_FLAGGED(tch, PLR_MAILING))
1072  	send_to_char(ch, " (mailing)");
1073        else if (PLR_FLAGGED(tch, PLR_WRITING))
1074  	send_to_char(ch, " (writing)");
1075  
1076        if (PRF_FLAGGED(tch, PRF_DEAF))
1077  	send_to_char(ch, " (deaf)");
1078        if (PRF_FLAGGED(tch, PRF_NOTELL))
1079  	send_to_char(ch, " (notell)");
1080        if (PRF_FLAGGED(tch, PRF_QUEST))
1081  	send_to_char(ch, " (quest)");
1082        if (PLR_FLAGGED(tch, PLR_THIEF))
1083  	send_to_char(ch, " (THIEF)");
1084        if (PLR_FLAGGED(tch, PLR_KILLER))
1085  	send_to_char(ch, " (KILLER)");
1086        if (GET_LEVEL(tch) >= LVL_IMMORT)
1087  	send_to_char(ch, CCNRM(ch, C_SPR));
1088        send_to_char(ch, "\r\n");
1089      }				/* endif shortlist */
1090    }				/* end of for */
1091    if (short_list && (num_can_see % 4))
1092      send_to_char(ch, "\r\n");
1093    if (num_can_see == 0)
1094      send_to_char(ch, "\r\nNobody at all!\r\n");
1095    else if (num_can_see == 1)
1096      send_to_char(ch, "\r\nOne lonely character displayed.\r\n");
1097    else
1098      send_to_char(ch, "\r\n%d characters displayed.\r\n", num_can_see);
1099  }
1100  
1101  
1102  #define USERS_FORMAT \
1103  "format: users [-l minlevel[-maxlevel]] [-n name] [-h host] [-c classlist] [-o] [-p]\r\n"
1104  
1105  /* BIG OL' FIXME: Rewrite it all. Similar to do_who(). */
1106  ACMD(do_users)
1107  {
1108    char line[200], line2[220], idletime[10], classname[20];
1109    char state[30], *timeptr, mode;
1110    char name_search[MAX_INPUT_LENGTH], host_search[MAX_INPUT_LENGTH];
1111    struct char_data *tch;
1112    struct descriptor_data *d;
1113    int low = 0, high = LVL_IMPL, num_can_see = 0;
1114    int showclass = 0, outlaws = 0, playing = 0, deadweight = 0;
1115    char buf[MAX_INPUT_LENGTH], arg[MAX_INPUT_LENGTH];
1116  
1117    host_search[0] = name_search[0] = '\0';
1118  
1119    strcpy(buf, argument);	/* strcpy: OK (sizeof: argument == buf) */
1120    while (*buf) {
1121      char buf1[MAX_INPUT_LENGTH];
1122  
1123      half_chop(buf, arg, buf1);
1124      if (*arg == '-') {
1125        mode = *(arg + 1);  /* just in case; we destroy arg in the switch */
1126        switch (mode) {
1127        case 'o':
1128        case 'k':
1129  	outlaws = 1;
1130  	playing = 1;
1131  	strcpy(buf, buf1);	/* strcpy: OK (sizeof: buf1 == buf) */
1132  	break;
1133        case 'p':
1134  	playing = 1;
1135  	strcpy(buf, buf1);	/* strcpy: OK (sizeof: buf1 == buf) */
1136  	break;
1137        case 'd':
1138  	deadweight = 1;
1139  	strcpy(buf, buf1);	/* strcpy: OK (sizeof: buf1 == buf) */
1140  	break;
1141        case 'l':
1142  	playing = 1;
1143  	half_chop(buf1, arg, buf);
1144  	sscanf(arg, "%d-%d", &low, &high);
1145  	break;
1146        case 'n':
1147  	playing = 1;
1148  	half_chop(buf1, name_search, buf);
1149  	break;
1150        case 'h':
1151  	playing = 1;
1152  	half_chop(buf1, host_search, buf);
1153  	break;
1154        case 'c':
1155  	playing = 1;
1156  	half_chop(buf1, arg, buf);
1157  	showclass = find_class_bitvector(arg);
1158  	break;
1159        default:
1160  	send_to_char(ch, "%s", USERS_FORMAT);
1161  	return;
1162        }				/* end of switch */
1163  
1164      } else {			/* endif */
1165        send_to_char(ch, "%s", USERS_FORMAT);
1166        return;
1167      }
1168    }				/* end while (parser) */
1169    send_to_char(ch,
1170  	 "Num Class   Name         State          Idl Login@   Site\r\n"
1171  	 "--- ------- ------------ -------------- --- -------- ------------------------\r\n");
1172  
1173    one_argument(argument, arg);
1174  
1175    for (d = descriptor_list; d; d = d->next) {
1176      if (STATE(d) != CON_PLAYING && playing)
1177        continue;
1178      if (STATE(d) == CON_PLAYING && deadweight)
1179        continue;
1180      if (STATE(d) == CON_PLAYING) {
1181        if (d->original)
1182  	tch = d->original;
1183        else if (!(tch = d->character))
1184  	continue;
1185  
1186        if (*host_search && !strstr(d->host, host_search))
1187  	continue;
1188        if (*name_search && str_cmp(GET_NAME(tch), name_search))
1189  	continue;
1190        if (!CAN_SEE(ch, tch) || GET_LEVEL(tch) < low || GET_LEVEL(tch) > high)
1191  	continue;
1192        if (outlaws && !PLR_FLAGGED(tch, PLR_KILLER) &&
1193  	  !PLR_FLAGGED(tch, PLR_THIEF))
1194  	continue;
1195        if (showclass && !(showclass & (1 << GET_CLASS(tch))))
1196  	continue;
1197        if (GET_INVIS_LEV(ch) > GET_LEVEL(ch))
1198  	continue;
1199  
1200        if (d->original)
1201  	sprintf(classname, "[%2d %s]", GET_LEVEL(d->original),
1202  		CLASS_ABBR(d->original));
1203        else
1204  	sprintf(classname, "[%2d %s]", GET_LEVEL(d->character),
1205  		CLASS_ABBR(d->character));
1206      } else
1207        strcpy(classname, "   -   ");
1208  
1209      timeptr = asctime(localtime(&d->login_time));
1210      timeptr += 11;
1211      *(timeptr + 8) = '\0';
1212  
1213      if (STATE(d) == CON_PLAYING && d->original)
1214        strcpy(state, "Switched");
1215      else
1216        strcpy(state, connected_types[STATE(d)]);
1217  
1218      if (d->character && STATE(d) == CON_PLAYING && GET_LEVEL(d->character) < LVL_GOD)
1219        sprintf(idletime, "%3d", d->character->char_specials.timer *
1220  	      SECS_PER_MUD_HOUR / SECS_PER_REAL_MIN);
1221      else
1222        strcpy(idletime, "");
1223  
1224      sprintf(line, "%3d %-7s %-12s %-14s %-3s %-8s ", d->desc_num, classname,
1225  	d->original && d->original->player.name ? d->original->player.name :
1226  	d->character && d->character->player.name ? d->character->player.name :
1227  	"UNDEFINED",
1228  	state, idletime, timeptr);
1229  
1230      if (d->host && *d->host)
1231        sprintf(line + strlen(line), "[%s]\r\n", d->host);
1232      else
1233        strcat(line, "[Hostname unknown]\r\n");
1234  
1235      if (STATE(d) != CON_PLAYING) {
1236        sprintf(line2, "%s%s%s", CCGRN(ch, C_SPR), line, CCNRM(ch, C_SPR));
1237        strcpy(line, line2);
1238      }
1239      if (STATE(d) != CON_PLAYING ||
1240  		(STATE(d) == CON_PLAYING && CAN_SEE(ch, d->character))) {
1241        send_to_char(ch, "%s", line);
1242        num_can_see++;
1243      }
1244    }
1245  
1246    send_to_char(ch, "\r\n%d visible sockets connected.\r\n", num_can_see);
1247  }
1248  
1249  
1250  /* Generic page_string function for displaying text */
1251  ACMD(do_gen_ps)
1252  {
1253    switch (subcmd) {
1254    case SCMD_CREDITS:
1255      page_string(ch->desc, credits, 0);
1256      break;
1257    case SCMD_NEWS:
1258      page_string(ch->desc, news, 0);
1259      break;
1260    case SCMD_INFO:
1261      page_string(ch->desc, info, 0);
1262      break;
1263    case SCMD_WIZLIST:
1264      page_string(ch->desc, wizlist, 0);
1265      break;
1266    case SCMD_IMMLIST:
1267      page_string(ch->desc, immlist, 0);
1268      break;
1269    case SCMD_HANDBOOK:
1270      page_string(ch->desc, handbook, 0);
1271      break;
1272    case SCMD_POLICIES:
1273      page_string(ch->desc, policies, 0);
1274      break;
1275    case SCMD_MOTD:
1276      page_string(ch->desc, motd, 0);
1277      break;
1278    case SCMD_IMOTD:
1279      page_string(ch->desc, imotd, 0);
1280      break;
1281    case SCMD_CLEAR:
1282      send_to_char(ch, "\033[H\033[J");
1283      break;
1284    case SCMD_VERSION:
1285      send_to_char(ch, "%s\r\n", circlemud_version);
1286      break;
1287    case SCMD_WHOAMI:
1288      send_to_char(ch, "%s\r\n", GET_NAME(ch));
1289      break;
1290    default:
1291      log("SYSERR: Unhandled case in do_gen_ps. (%d)", subcmd);
1292      return;
1293    }
1294  }
1295  
1296  
1297  void perform_mortal_where(struct char_data *ch, char *arg)
1298  {
1299    struct char_data *i;
1300    struct descriptor_data *d;
1301  
1302    if (!*arg) {
1303      send_to_char(ch, "Players in your Zone\r\n--------------------\r\n");
1304      for (d = descriptor_list; d; d = d->next) {
1305        if (STATE(d) != CON_PLAYING || d->character == ch)
1306  	continue;
1307        if ((i = (d->original ? d->original : d->character)) == NULL)
1308  	continue;
1309        if (IN_ROOM(i) == NOWHERE || !CAN_SEE(ch, i))
1310  	continue;
1311        if (world[IN_ROOM(ch)].zone != world[IN_ROOM(i)].zone)
1312  	continue;
1313        send_to_char(ch, "%-20s - %s\r\n", GET_NAME(i), world[IN_ROOM(i)].name);
1314      }
1315    } else {			/* print only FIRST char, not all. */
1316      for (i = character_list; i; i = i->next) {
1317        if (IN_ROOM(i) == NOWHERE || i == ch)
1318  	continue;
1319        if (!CAN_SEE(ch, i) || world[IN_ROOM(i)].zone != world[IN_ROOM(ch)].zone)
1320  	continue;
1321        if (!isname(arg, i->player.name))
1322  	continue;
1323        send_to_char(ch, "%-25s - %s\r\n", GET_NAME(i), world[IN_ROOM(i)].name);
1324        return;
1325      }
1326      send_to_char(ch, "Nobody around by that name.\r\n");
1327    }
1328  }
1329  
1330  
1331  void print_object_location(int num, struct obj_data *obj, struct char_data *ch,
1332  			        int recur)
1333  {
1334    if (num > 0)
1335      send_to_char(ch, "O%3d. %-25s - ", num, obj->short_description);
1336    else
1337      send_to_char(ch, "%33s", " - ");
1338  
1339    if (IN_ROOM(obj) != NOWHERE)
1340      send_to_char(ch, "[%5d] %s\r\n", GET_ROOM_VNUM(IN_ROOM(obj)), world[IN_ROOM(obj)].name);
1341    else if (obj->carried_by)
1342      send_to_char(ch, "carried by %s\r\n", PERS(obj->carried_by, ch));
1343    else if (obj->worn_by)
1344      send_to_char(ch, "worn by %s\r\n", PERS(obj->worn_by, ch));
1345    else if (obj->in_obj) {
1346      send_to_char(ch, "inside %s%s\r\n", obj->in_obj->short_description, (recur ? ", which is" : " "));
1347      if (recur)
1348        print_object_location(0, obj->in_obj, ch, recur);
1349    } else
1350      send_to_char(ch, "in an unknown location\r\n");
1351  }
1352  
1353  
1354  
1355  void perform_immort_where(struct char_data *ch, char *arg)
1356  {
1357    struct char_data *i;
1358    struct obj_data *k;
1359    struct descriptor_data *d;
1360    int num = 0, found = 0;
1361  
1362    if (!*arg) {
1363      send_to_char(ch, "Players\r\n-------\r\n");
1364      for (d = descriptor_list; d; d = d->next)
1365        if (STATE(d) == CON_PLAYING) {
1366  	i = (d->original ? d->original : d->character);
1367  	if (i && CAN_SEE(ch, i) && (IN_ROOM(i) != NOWHERE)) {
1368  	  if (d->original)
1369  	    send_to_char(ch, "%-20s - [%5d] %s (in %s)\r\n",
1370  		GET_NAME(i), GET_ROOM_VNUM(IN_ROOM(d->character)),
1371  		world[IN_ROOM(d->character)].name, GET_NAME(d->character));
1372  	  else
1373  	    send_to_char(ch, "%-20s - [%5d] %s\r\n", GET_NAME(i), GET_ROOM_VNUM(IN_ROOM(i)), world[IN_ROOM(i)].name);
1374  	}
1375        }
1376    } else {
1377      for (i = character_list; i; i = i->next)
1378        if (CAN_SEE(ch, i) && IN_ROOM(i) != NOWHERE && isname(arg, i->player.name)) {
1379  	found = 1;
1380  	send_to_char(ch, "M%3d. %-25s - [%5d] %s\r\n", ++num, GET_NAME(i),
1381  		GET_ROOM_VNUM(IN_ROOM(i)), world[IN_ROOM(i)].name);
1382        }
1383      for (num = 0, k = object_list; k; k = k->next)
1384        if (CAN_SEE_OBJ(ch, k) && isname(arg, k->name)) {
1385  	found = 1;
1386  	print_object_location(++num, k, ch, TRUE);
1387        }
1388      if (!found)
1389        send_to_char(ch, "Couldn't find any such thing.\r\n");
1390    }
1391  }
1392  
1393  
1394  
1395  ACMD(do_where)
1396  {
1397    char arg[MAX_INPUT_LENGTH];
1398  
1399    one_argument(argument, arg);
1400  
1401    if (GET_LEVEL(ch) >= LVL_IMMORT)
1402      perform_immort_where(ch, arg);
1403    else
1404      perform_mortal_where(ch, arg);
1405  }
1406  
1407  
1408  
1409  ACMD(do_levels)
1410  {
1411    char buf[MAX_STRING_LENGTH];
1412    size_t i, len = 0;
1413    int nlen;
1414  
1415    if (IS_NPC(ch)) {
1416      send_to_char(ch, "You ain't nothin' but a hound-dog.\r\n");
1417      return;
1418    }
1419  
1420    for (i = 1; i < LVL_IMMORT; i++) {
1421      nlen = snprintf(buf + len, sizeof(buf) - len, "[%2d] %8d-%-8d : ", i,
1422  		level_exp(GET_CLASS(ch), i), level_exp(GET_CLASS(ch), i + 1) - 1);
1423      if (len + nlen >= sizeof(buf) || nlen < 0)
1424        break;
1425      len += nlen;
1426  
1427      switch (GET_SEX(ch)) {
1428      case SEX_MALE:
1429      case SEX_NEUTRAL:
1430        nlen = snprintf(buf + len, sizeof(buf) - len, "%s\r\n", title_male(GET_CLASS(ch), i));
1431        break;
1432      case SEX_FEMALE:
1433        nlen = snprintf(buf + len, sizeof(buf) - len, "%s\r\n", title_female(GET_CLASS(ch), i));
1434        break;
1435      default:
1436        nlen = snprintf(buf + len, sizeof(buf) - len, "Oh dear.  You seem to be sexless.\r\n");
1437        break;
1438      }
1439      if (len + nlen >= sizeof(buf) || nlen < 0)
1440        break;
1441      len += nlen;
1442    }
1443  
1444    if (len < sizeof(buf))
1445      snprintf(buf + len, sizeof(buf) - len, "[%2d] %8d          : Immortality\r\n",
1446  		LVL_IMMORT, level_exp(GET_CLASS(ch), LVL_IMMORT));
1447    page_string(ch->desc, buf, TRUE);
1448  }
1449  
1450  
1451  
1452  ACMD(do_consider)
1453  {
1454    char buf[MAX_INPUT_LENGTH];
1455    struct char_data *victim;
1456    int diff;
1457  
1458    one_argument(argument, buf);
1459  
1460    if (!(victim = get_char_vis(ch, buf, NULL, FIND_CHAR_ROOM))) {
1461      send_to_char(ch, "Consider killing who?\r\n");
1462      return;
1463    }
1464    if (victim == ch) {
1465      send_to_char(ch, "Easy!  Very easy indeed!\r\n");
1466      return;
1467    }
1468    if (!IS_NPC(victim)) {
1469      send_to_char(ch, "Would you like to borrow a cross and a shovel?\r\n");
1470      return;
1471    }
1472    diff = (GET_LEVEL(victim) - GET_LEVEL(ch));
1473  
1474    if (diff <= -10)
1475      send_to_char(ch, "Now where did that chicken go?\r\n");
1476    else if (diff <= -5)
1477      send_to_char(ch, "You could do it with a needle!\r\n");
1478    else if (diff <= -2)
1479      send_to_char(ch, "Easy.\r\n");
1480    else if (diff <= -1)
1481      send_to_char(ch, "Fairly easy.\r\n");
1482    else if (diff == 0)
1483      send_to_char(ch, "The perfect match!\r\n");
1484    else if (diff <= 1)
1485      send_to_char(ch, "You would need some luck!\r\n");
1486    else if (diff <= 2)
1487      send_to_char(ch, "You would need a lot of luck!\r\n");
1488    else if (diff <= 3)
1489      send_to_char(ch, "You would need a lot of luck and great equipment!\r\n");
1490    else if (diff <= 5)
1491      send_to_char(ch, "Do you feel lucky, punk?\r\n");
1492    else if (diff <= 10)
1493      send_to_char(ch, "Are you mad!?\r\n");
1494    else if (diff <= 100)
1495      send_to_char(ch, "You ARE mad!\r\n");
1496  }
1497  
1498  
1499  
1500  ACMD(do_diagnose)
1501  {
1502    char buf[MAX_INPUT_LENGTH];
1503    struct char_data *vict;
1504  
1505    one_argument(argument, buf);
1506  
1507    if (*buf) {
1508      if (!(vict = get_char_vis(ch, buf, NULL, FIND_CHAR_ROOM)))
1509        send_to_char(ch, "%s", NOPERSON);
1510      else
1511        diag_char_to_char(vict, ch);
1512    } else {
1513      if (FIGHTING(ch))
1514        diag_char_to_char(FIGHTING(ch), ch);
1515      else
1516        send_to_char(ch, "Diagnose who?\r\n");
1517    }
1518  }
1519  
1520  
1521  const char *ctypes[] = {
1522    "off", "sparse", "normal", "complete", "\n"
1523  };
1524  
1525  ACMD(do_color)
1526  {
1527    char arg[MAX_INPUT_LENGTH];
1528    int tp;
1529  
1530    if (IS_NPC(ch))
1531      return;
1532  
1533    one_argument(argument, arg);
1534  
1535    if (!*arg) {
1536      send_to_char(ch, "Your current color level is %s.\r\n", ctypes[COLOR_LEV(ch)]);
1537      return;
1538    }
1539    if (((tp = search_block(arg, ctypes, FALSE)) == -1)) {
1540      send_to_char(ch, "Usage: color { Off | Sparse | Normal | Complete }\r\n");
1541      return;
1542    }
1543    REMOVE_BIT(PRF_FLAGS(ch), PRF_COLOR_1 | PRF_COLOR_2);
1544    SET_BIT(PRF_FLAGS(ch), (PRF_COLOR_1 * (tp & 1)) | (PRF_COLOR_2 * (tp & 2) >> 1));
1545  
1546    send_to_char(ch, "Your %scolor%s is now %s.\r\n", CCRED(ch, C_SPR), CCNRM(ch, C_OFF), ctypes[tp]);
1547  }
1548  
1549  
1550  ACMD(do_toggle)
1551  {
1552    char buf2[4];
1553  
1554    if (IS_NPC(ch))
1555      return;
1556  
1557    if (GET_WIMP_LEV(ch) == 0)
1558      strcpy(buf2, "OFF");	/* strcpy: OK */
1559    else
1560      sprintf(buf2, "%-3.3d", GET_WIMP_LEV(ch));	/* sprintf: OK */
1561  
1562    if (GET_LEVEL(ch) >= LVL_IMMORT) {
1563      send_to_char(ch,
1564  	  "      No Hassle: %-3s    "
1565  	  "      Holylight: %-3s    "
1566  	  "     Room Flags: %-3s\r\n",
1567  	ONOFF(PRF_FLAGGED(ch, PRF_NOHASSLE)),
1568  	ONOFF(PRF_FLAGGED(ch, PRF_HOLYLIGHT)),
1569  	ONOFF(PRF_FLAGGED(ch, PRF_ROOMFLAGS))
1570      );
1571    }
1572  
1573    send_to_char(ch,
1574  	  "Hit Pnt Display: %-3s    "
1575  	  "     Brief Mode: %-3s    "
1576  	  " Summon Protect: %-3s\r\n"
1577  
1578  	  "   Move Display: %-3s    "
1579  	  "   Compact Mode: %-3s    "
1580  	  "       On Quest: %-3s\r\n"
1581  
1582  	  "   Mana Display: %-3s    "
1583  	  "         NoTell: %-3s    "
1584  	  "   Repeat Comm.: %-3s\r\n"
1585  
1586  	  " Auto Show Exit: %-3s    "
1587  	  "           Deaf: %-3s    "
1588  	  "     Wimp Level: %-3s\r\n"
1589  
1590  	  " Gossip Channel: %-3s    "
1591  	  "Auction Channel: %-3s    "
1592  	  "  Grats Channel: %-3s\r\n"
1593  
1594  	  "    Color Level: %s\r\n",
1595  
1596  	  ONOFF(PRF_FLAGGED(ch, PRF_DISPHP)),
1597  	  ONOFF(PRF_FLAGGED(ch, PRF_BRIEF)),
1598  	  ONOFF(!PRF_FLAGGED(ch, PRF_SUMMONABLE)),
1599  
1600  	  ONOFF(PRF_FLAGGED(ch, PRF_DISPMOVE)),
1601  	  ONOFF(PRF_FLAGGED(ch, PRF_COMPACT)),
1602  	  YESNO(PRF_FLAGGED(ch, PRF_QUEST)),
1603  
1604  	  ONOFF(PRF_FLAGGED(ch, PRF_DISPMANA)),
1605  	  ONOFF(PRF_FLAGGED(ch, PRF_NOTELL)),
1606  	  YESNO(!PRF_FLAGGED(ch, PRF_NOREPEAT)),
1607  
1608  	  ONOFF(PRF_FLAGGED(ch, PRF_AUTOEXIT)),
1609  	  YESNO(PRF_FLAGGED(ch, PRF_DEAF)),
1610  	  buf2,
1611  
1612  	  ONOFF(!PRF_FLAGGED(ch, PRF_NOGOSS)),
1613  	  ONOFF(!PRF_FLAGGED(ch, PRF_NOAUCT)),
1614  	  ONOFF(!PRF_FLAGGED(ch, PRF_NOGRATZ)),
1615  
1616  	  ctypes[COLOR_LEV(ch)]);
1617  }
1618  
1619  
1620  int sort_commands_helper(const void *a, const void *b)
1621  {
1622    return strcmp(cmd_info[*(const int *)a].command, cmd_info[*(const int *)b].command);
1623  }
1624  
1625  
1626  void sort_commands(void)
1627  {
1628    int a, num_of_cmds = 0;
1629  
1630    while (cmd_info[num_of_cmds].command[0] != '\n')
1631      num_of_cmds++;
1632    num_of_cmds++;	/* \n */
1633  
1634    CREATE(cmd_sort_info, int, num_of_cmds);
1635  
1636    for (a = 0; a < num_of_cmds; a++)
1637      cmd_sort_info[a] = a;
1638  
1639    /* Don't sort the RESERVED or \n entries. */
1640    qsort(cmd_sort_info + 1, num_of_cmds - 2, sizeof(int), sort_commands_helper);
1641  }
1642  
1643  
1644  ACMD(do_commands)
1645  {
1646    int no, i, cmd_num;
1647    int wizhelp = 0, socials = 0;
1648    struct char_data *vict;
1649    char arg[MAX_INPUT_LENGTH];
1650  
1651    one_argument(argument, arg);
1652  
1653    if (*arg) {
1654      if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)) || IS_NPC(vict)) {
1655        send_to_char(ch, "Who is that?\r\n");
1656        return;
1657      }
1658      if (GET_LEVEL(ch) < GET_LEVEL(vict)) {
1659        send_to_char(ch, "You can't see the commands of people above your level.\r\n");
1660        return;
1661      }
1662    } else
1663      vict = ch;
1664  
1665    if (subcmd == SCMD_SOCIALS)
1666      socials = 1;
1667    else if (subcmd == SCMD_WIZHELP)
1668      wizhelp = 1;
1669  
1670    send_to_char(ch, "The following %s%s are available to %s:\r\n",
1671  	  wizhelp ? "privileged " : "",
1672  	  socials ? "socials" : "commands",
1673  	  vict == ch ? "you" : GET_NAME(vict));
1674  
1675    /* cmd_num starts at 1, not 0, to remove 'RESERVED' */
1676    for (no = 1, cmd_num = 1; cmd_info[cmd_sort_info[cmd_num]].command[0] != '\n'; cmd_num++) {
1677      i = cmd_sort_info[cmd_num];
1678  
1679      if (cmd_info[i].minimum_level < 0 || GET_LEVEL(vict) < cmd_info[i].minimum_level)
1680        continue;
1681  
1682      if ((cmd_info[i].minimum_level >= LVL_IMMORT) != wizhelp)
1683        continue;
1684  
1685      if (!wizhelp && socials != (cmd_info[i].command_pointer == do_action || cmd_info[i].command_pointer == do_insult))
1686        continue;
1687  
1688      send_to_char(ch, "%-11s%s", cmd_info[i].command, no++ % 7 == 0 ? "\r\n" : "");
1689    }
1690  
1691    if (no % 7 != 1)
1692      send_to_char(ch, "\r\n");
1693  }