eldhamud/boards/
eldhamud/clans/
eldhamud/classes/
eldhamud/councils/
eldhamud/deity/
eldhamud/doc/
eldhamud/doc/DIKU/
eldhamud/doc/MERC/
eldhamud/doc/mudprogs/
eldhamud/houses/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *			     Informational module			    *
 ****************************************************************************/

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include "mud.h"

/*
* Needed in the do_ignore function. -Orion
*/
// bool    check_parse_name        args( ( char *name, bool newchar ) );

/*
 * Keep players from defeating examine progs -Druid
 * False = do not trigger
 * True = Trigger
 */
bool EXA_prog_trigger = TRUE;

/* Had to add unknowns because someone added new positions and didn't
 * update them.  Just a band-aid till I have time to fix it right.
 * This was found thanks to mud@mini.axcomp.com pointing it out :)
 * --Shaddai
 */

char *	const	where_name	[] =
  {
    "<used as light>     ",
    "<worn on finger>    ",
    "<worn on finger>    ",
    "<worn around neck>  ",
    "<worn around neck>  ",
    "<worn on body>      ",
    "<worn on head>      ",
    "<worn on legs>      ",
    "<worn on feet>      ",
    "<worn on hands>     ",
    "<worn on arms>      ",
    "<worn as shield>    ",
    "<worn about body>   ",
    "<worn about waist>  ",
    "<worn around wrist> ",
    "<worn around wrist> ",
    "<wielded>           ",
    "<held>              ",
    "<dual wielded>      ",
    "<worn on ears>      ",
    "<worn on eyes>      ",
    "<missile wielded>   ",
    "<worn on back>      ",
    "<worn over face>    ",
    "<worn around ankle> ",
    "<worn around ankle> ",
    "<BUG Inform Nivek>  ",
    "<BUG Inform Nivek>  ",
    "<BUG Inform Nivek>  "
  };


/*
 * Local functions.
 */
void	show_char_to_char_0	args( ( CHAR_DATA *victim, CHAR_DATA *ch ) );
void	show_char_to_char_1	args( ( CHAR_DATA *victim, CHAR_DATA *ch ) );
void	show_char_to_char	args( ( CHAR_DATA *list, CHAR_DATA *ch ) );
bool	check_blind		args( ( CHAR_DATA *ch ) );
void    show_condition          args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
//Similar Helpfile Snippet Declarations
sh_int str_similarity( const char *astr, const char *bstr );
sh_int str_prefix_level( const char *astr, const char *bstr );
void similar_help_files(CHAR_DATA *ch, char *argument);



char *format_obj_to_char( OBJ_DATA *obj, CHAR_DATA *ch, bool fShort )
{
  static char buf[MAX_STRING_LENGTH];
  bool glowsee = FALSE;

  if ( !IS_NPC(ch) && ch->pcdata->questobj > 0 && obj->pIndexData->vnum == ch->pcdata->questobj)
    strcat( buf, "[TARGET] "     );
  /* can see glowing invis items in the dark */
  if ( IS_OBJ_STAT(obj, ITEM_GLOW) && IS_OBJ_STAT(obj, ITEM_INVIS)
       &&  !IS_AFFECTED(ch, AFF_TRUESIGHT) && !IS_AFFECTED(ch, AFF_DETECT_INVIS) )
    glowsee = TRUE;

  buf[0] = '\0';
  if ( IS_OBJ_STAT(obj, ITEM_INVIS))
    strcat( buf, "(Invis) "     );
  if (  (IS_AFFECTED(ch, AFF_DETECT_EVIL) && IS_OBJ_STAT(obj, ITEM_EVIL)))
    strcat( buf, "(Red Aura) "  );
if ( IS_AFFECTED(ch, AFF_DETECT_MAGIC) && IS_OBJ_STAT(obj, ITEM_MAGIC)  )
    strcat( buf, "&Y(&OMagical&Y)&D "   );
  if ( !glowsee && IS_OBJ_STAT(obj, ITEM_GLOW) )
    strcat( buf, "&Y(&WGlowing&Y)&D "   );
  if ( IS_OBJ_STAT(obj, ITEM_HUM)       )
    strcat( buf, "&Y(&pHumming&Y)&D "   );
  if ( IS_OBJ_STAT(obj, ITEM_HIDDEN)	  )
    strcat( buf, "(Hidden) "	  );
  if ( IS_OBJ_STAT(obj, ITEM_BURIED)	  )
    strcat( buf, "(Buried) "	  );
  if ( IS_IMMORTAL(ch)
       && IS_OBJ_STAT(obj, ITEM_PROTOTYPE) )
    strcat( buf, "&Y(&RPROTO&Y)&D "	  );
  if ( IS_AFFECTED(ch, AFF_DETECTTRAPS)
       && is_trapped(obj)   )
    strcat( buf, "(Trap) "  );

  if ( fShort )
    {
      if ( glowsee && !IS_IMMORTAL(ch) )
        strcat( buf, "the faint glow of something" );
      else
        if ( obj->short_descr )
          strcat( buf, obj->short_descr );
    }
  else
    {
      if ( glowsee )
        strcat( buf, "You see the faint glow of something nearby." );
      if ( obj->description )
        strcat( buf, obj->description );
    }

  return buf;
}


/*
 * Some increasingly freaky hallucinated objects		-Thoric
 * (Hats off to Albert Hoffman's "problem child")
 */
char *hallucinated_object( int ms, bool fShort )
{
  int sms = URANGE( 1, (ms+10)/5, 20 );

  if ( fShort )
    switch( number_range( 6-URANGE(1,sms/2,5), sms ) )
      {
      case  1:
        return "a sword";
      case  2:
        return "a stick";
      case  3:
        return "something shiny";
      case  4:
        return "something";
      case  5:
        return "something interesting";
      case  6:
        return "something colorful";
      case  7:
        return "something that looks cool";
      case  8:
        return "a nifty thing";
      case  9:
        return "a cloak of flowing colors";
      case 10:
        return "a mystical flaming sword";
      case 11:
        return "a swarm of insects";
      case 12:
        return "a deathbane";
      case 13:
        return "a figment of your imagination";
      case 14:
        return "your gravestone";
      case 15:
        return "the long lost boots of Ranger Thoric";
      case 16:
        return "a glowing tome of arcane knowledge";
      case 17:
        return "a long sought secret";
      case 18:
        return "the meaning of it all";
      case 19:
        return "the answer";
      case 20:
        return "the key to life, the universe and everything";
      }
  switch( number_range( 6-URANGE(1,sms/2,5), sms ) )
    {
    case  1:
      return "A nice looking sword catches your eye.";
    case  2:
      return "The ground is covered in small sticks.";
    case  3:
      return "Something shiny catches your eye.";
    case  4:
      return "Something catches your attention.";
    case  5:
      return "Something interesting catches your eye.";
    case  6:
      return "Something colorful flows by.";
    case  7:
      return "Something that looks cool calls out to you.";
    case  8:
      return "A nifty thing of great importance stands here.";
    case  9:
      return "A cloak of flowing colors asks you to wear it.";
    case 10:
      return "A mystical flaming sword awaits your grasp.";
    case 11:
      return "A swarm of insects buzzes in your face!";
    case 12:
      return "The extremely rare Deathbane lies at your feet.";
    case 13:
      return "A figment of your imagination is at your command.";
    case 14:
      return "You notice a gravestone here... upon closer examination, it reads your name.";
    case 15:
      return "The long lost boots of Ranger Thoric lie off to the side.";
    case 16:
      return "A glowing tome of arcane knowledge hovers in the air before you.";
    case 17:
      return "A long sought secret of all mankind is now clear to you.";
    case 18:
      return "The meaning of it all, so simple, so clear... of course!";
    case 19:
      return "The answer.  One.  It's always been One.";
    case 20:
      return "The key to life, the universe and everything awaits your hand.";
    }
  return "Whoa!!!";
}


/* This is the punct snippet from Desden el Chaman Tibetano - Nov 1998
   Email: jlalbatros@mx2.redestb.es
*/
char *num_punct(int foo)
{
  int nindex, index_new, rest;
  char buf[16];
  static char buf_new[16];

  sprintf(buf,"%d",foo);
  rest = strlen(buf)%3;

  for (nindex=index_new=0;nindex<strlen(buf);nindex++,index_new++)
    {
      if (nindex!=0 && (nindex-rest)%3==0 )
        {
          buf_new[index_new]=',';
          index_new++;
          buf_new[index_new]=buf[nindex];
        }
      else
        buf_new[index_new] = buf[nindex];
    }
  buf_new[index_new]='\0';
  return buf_new;
}


/*
 * Show a list to a character.
 * Can coalesce duplicated items.
 */
void show_list_to_char( OBJ_DATA *list, CHAR_DATA *ch, bool fShort, bool fShowNothing )
{
  char **prgpstrShow;
  int *prgnShow;
  int *pitShow;
  char *pstrShow;
  OBJ_DATA *obj;
  int nShow;
  int iShow;
  int count, offcount, tmp, ms, cnt;
  bool fCombine;

  if ( !ch->desc )
    return;

  /*
   * if there's no list... then don't do all this crap!  -Thoric
   */
  if ( !list )
    {
      if ( fShowNothing )
        {
          if ( IS_NPC(ch) || xIS_SET(ch->act, PLR_COMBINE) )
            send_to_char( "     ", ch );
          set_char_color( AT_OBJECT, ch );
          send_to_char( "Nothing.\n\r", ch );
        }
      return;
    }
  /*
   * Alloc space for output lines.
   */
  count = 0;
  for ( obj = list; obj; obj = obj->next_content )
    count++;

  ms  = (ch->mental_state ? ch->mental_state : 1)
        * (IS_NPC(ch) ? 1 : (ch->pcdata->condition[COND_DRUNK] ? (ch->pcdata->condition[COND_DRUNK]/12) : 1));

  /*
   * If not mentally stable...
   */
  if ( abs(ms) > 40 )
    {
      offcount = URANGE( -(count), (count * ms) / 100, count*2 );
      if ( offcount < 0 )
        offcount += number_range(0, abs(offcount));
      else
        if ( offcount > 0 )
          offcount -= number_range(0, offcount);
    }
  else
    offcount = 0;

  if ( count + offcount <= 0 )
    {
      if ( fShowNothing )
        {
          if ( IS_NPC(ch) || xIS_SET(ch->act, PLR_COMBINE) )
            send_to_char( "     ", ch );
          set_char_color( AT_OBJECT, ch );
          send_to_char( "Nothing.\n\r", ch );
        }
      return;
    }

  CREATE( prgpstrShow,	char*,	count + ((offcount > 0) ? offcount : 0) );
  CREATE( prgnShow,		int,	count + ((offcount > 0) ? offcount : 0) );
  CREATE( pitShow,		int,	count + ((offcount > 0) ? offcount : 0) );
  nShow	= 0;
  tmp		= (offcount > 0) ? offcount : 0;
  cnt		= 0;

  /*
   * Format the list of objects.
   */
  for ( obj = list; obj; obj = obj->next_content )
    {
      if ( offcount < 0 && ++cnt > (count + offcount) )
        break;
      if ( tmp > 0 && number_bits(1) == 0 )
        {
          prgpstrShow [nShow] = str_dup( hallucinated_object(ms, fShort) );
          prgnShow	[nShow] = 1;
          pitShow	[nShow] = number_range( ITEM_LIGHT, ITEM_BOOK );
          nShow++;
          --tmp;
        }
      if ( obj->wear_loc == WEAR_NONE
           && can_see_obj( ch, obj )
           && (obj->item_type != ITEM_TRAP || IS_AFFECTED(ch, AFF_DETECTTRAPS) ) )
        {
          pstrShow = format_obj_to_char( obj, ch, fShort );
          fCombine = FALSE;

          if ( IS_NPC(ch) || xIS_SET(ch->act, PLR_COMBINE) )
            {
              /*
               * Look for duplicates, case sensitive.
               * Matches tend to be near end so run loop backwords.
               */
              for ( iShow = nShow - 1; iShow >= 0; iShow-- )
                {
                  if ( !strcmp( prgpstrShow[iShow], pstrShow ) )
                    {
                      prgnShow[iShow] += obj->count;
                      fCombine = TRUE;
                      break;
                    }
                }
            }

          pitShow[nShow] = obj->item_type;
          /*
           * Couldn't combine, or didn't want to.
           */
          if ( !fCombine )
            {
              prgpstrShow [nShow] = str_dup( pstrShow );
              prgnShow    [nShow] = obj->count;
              nShow++;
            }
        }
    }
  if ( tmp > 0 )
    {
      int x;
      for ( x = 0; x < tmp; x++ )
        {
          prgpstrShow [nShow] = str_dup( hallucinated_object(ms, fShort) );
          prgnShow	[nShow] = 1;
          pitShow	[nShow] = number_range( ITEM_LIGHT, ITEM_BOOK );
          nShow++;
        }
    }

  /*
   * Output the formatted list.		-Color support by Thoric
   */
  for ( iShow = 0; iShow < nShow; iShow++ )
    {
      switch(pitShow[iShow])
        {
        default:
          set_char_color( AT_OBJECT, ch );
          break;
        case ITEM_BLOOD:
          set_char_color( AT_BLOOD, ch );
          break;
        case ITEM_MONEY:
        case ITEM_TREASURE:
          set_char_color( AT_YELLOW, ch );
          break;
        case ITEM_COOK:
        case ITEM_FOOD:
          set_char_color( AT_HUNGRY, ch );
          break;
        case ITEM_DRINK_CON:
        case ITEM_FOUNTAIN:
          set_char_color( AT_THIRSTY, ch );
          break;
        case ITEM_FIRE:
          set_char_color( AT_FIRE, ch );
          break;
        case ITEM_SCROLL:
        case ITEM_WAND:
        case ITEM_STAFF:
          set_char_color( AT_MAGIC, ch );
          break;
        }
      if ( fShowNothing )
        send_to_char( "     ", ch );
      send_to_char( prgpstrShow[iShow], ch );
      /*	if ( IS_NPC(ch) || xIS_SET(ch->act, PLR_COMBINE) ) */
      {
        if ( prgnShow[iShow] != 1 )
          ch_printf( ch, " (%d)", prgnShow[iShow] );
      }

      send_to_char( "\n\r", ch );
      DISPOSE( prgpstrShow[iShow] );
    }

  if ( fShowNothing && nShow == 0 )
    {
      if ( IS_NPC(ch) || xIS_SET(ch->act, PLR_COMBINE) )
        send_to_char( "     ", ch );
      set_char_color( AT_OBJECT, ch );
      send_to_char( "Nothing.\n\r", ch );
    }

  /*
   * Clean up.
   */
  DISPOSE( prgpstrShow );
  DISPOSE( prgnShow	 );
  DISPOSE( pitShow	 );
  return;
}


/*
 * Show fancy descriptions for certain spell affects		-Thoric
 */
void show_visible_affects_to_char( CHAR_DATA *victim, CHAR_DATA *ch )
{
  char buf[MAX_STRING_LENGTH];
  char name[MAX_STRING_LENGTH];

  if ( IS_NPC( victim ) )
    strcpy( name, victim->short_descr );
  else
    strcpy( name, victim->name);
  name[0] = toupper(name[0]);

  if ( IS_AFFECTED(victim, AFF_SANCTUARY) )
    {
      set_char_color( AT_WHITE, ch );
      if ( IS_GOOD(victim) )
        ch_printf( ch, "%s glows with an aura of divine radiance.\n\r", name );
      else if ( IS_EVIL(victim) )
        ch_printf( ch, "%s shimmers beneath an aura of dark energy.\n\r", name );
      else
        ch_printf( ch, "%s is shrouded in flowing shadow and light.\n\r", name );
    }
  if ( IS_AFFECTED(victim, AFF_FIRESHIELD) )
    {
      set_char_color( AT_FIRE, ch );
      ch_printf( ch, "%s is engulfed within a blaze of mystical flame.\n\r", name );
    }
  if ( IS_AFFECTED(victim, AFF_SHOCKSHIELD) )
    {
      set_char_color( AT_BLUE, ch );
      ch_printf( ch, "%s is surrounded by cascading torrents of energy.\n\r", name );
    }
  if ( IS_AFFECTED(victim, AFF_ACIDMIST) )
    {
      set_char_color( AT_GREEN, ch );
      ch_printf( ch, "%s is visible through a cloud of churning mist.\n\r", name );
    }
  /*Scryn 8/13*/
  if ( IS_AFFECTED(victim, AFF_ICESHIELD) )
    {
      set_char_color( AT_LBLUE, ch );
      ch_printf( ch, "%s is ensphered by shards of glistening ice.\n\r", name );
    }
  if ( IS_AFFECTED(victim, AFF_CHARM)       )
    {
      set_char_color( AT_MAGIC, ch );
      ch_printf( ch, "%s wanders in a dazed, zombie-like state.\n\r", name );
    }
  if ( !IS_NPC(victim) && !victim->desc
       &&    victim->switched && IS_AFFECTED(victim->switched, AFF_POSSESS) )
    {
      set_char_color( AT_MAGIC, ch );
      strcpy( buf, PERS( victim, ch, FALSE ) );
      strcat( buf, " appears to be in a deep trance...\n\r" );
    }
}

void show_char_to_char_0( CHAR_DATA *victim, CHAR_DATA *ch )
{
  char buf[MAX_STRING_LENGTH];
  char buf1[MAX_STRING_LENGTH];
  char message[MAX_STRING_LENGTH];

  buf[0] = '\0';

  set_char_color( AT_PERSON, ch );
  if ( !IS_NPC(victim) && !victim->desc )
    {
      if ( !victim->switched )
        send_to_char_color( "&P[(Link Dead)] ", ch );
      else if ( !IS_AFFECTED(victim, AFF_POSSESS) )
        strcat( buf, "(Switched) " );
    }
  if ( IS_NPC(victim) && IS_AFFECTED(victim, AFF_POSSESS) && IS_IMMORTAL(ch)
       && victim->desc )
    {
      sprintf( buf1, "(%s)",victim->desc->original->name );
      strcat( buf, buf1 );
    }
  if ( !IS_NPC(victim)
       &&   xIS_SET(victim->act, PLR_AFK) )
    strcat( buf, "[AFK] ");

  if ( (!IS_NPC(victim) && xIS_SET(victim->act, PLR_WIZINVIS))
       || (IS_NPC(victim) && xIS_SET(victim->act, ACT_MOBINVIS)) )
    {
      if (!IS_NPC(victim))
        sprintf( buf1,"(Invis %d) ", victim->pcdata->wizinvis );
      else
        sprintf( buf1,"(Mobinvis %d) ", victim->mobinvis);
      strcat( buf, buf1 );
    }

  if (IS_NPC(victim) && !IS_NPC(ch) && ch->pcdata->questmob > 0 && victim->pIndexData->vnum == ch->pcdata->questmob)
    strcat( buf, "[TARGET] ");

  if ( !IS_NPC( victim) )
    {
      if ( IS_IMMORTAL( victim ) && victim->level > 50 )
        send_to_char_color( "&P(&WImmortal&P) ", ch );
      if ( victim->pcdata->clan
           &&   IS_SET( victim->pcdata->flags, PCFLAG_DEADLY )
           &&   victim->pcdata->clan->badge
           && ( victim->pcdata->clan->clan_type != CLAN_ORDER
                &&   victim->pcdata->clan->clan_type != CLAN_GUILD ) )
        ch_printf_color( ch, "%s ", victim->pcdata->clan->badge );
      else if ( CAN_PKILL( victim ) && victim->level < 51 )
        send_to_char_color( "&P(&wUnclanned&P) ", ch );
    }

  set_char_color( AT_PERSON, ch );

  if ( IS_AFFECTED(victim, AFF_INVISIBLE)   )
    strcat( buf, "(Invis) "      );
  if ( IS_AFFECTED(victim, AFF_HIDE)        )
    strcat( buf, "(Hide) "       );
  if ( IS_AFFECTED(victim, AFF_PASS_DOOR)   )
    strcat( buf, "(Translucent) ");
  if ( IS_AFFECTED(victim, AFF_FAERIE_FIRE) )
    strcat( buf, "(Pink Aura) "  );
  if ( IS_EVIL(victim)  &&   (  IS_AFFECTED(ch, AFF_DETECT_EVIL) ))
    strcat( buf, "(Red Aura) "   );
  if ( IS_NEUTRAL(victim) && (  IS_AFFECTED(ch, AFF_DETECT_EVIL)  ))
    strcat( buf, "(Grey Aura) "   );
  if ( IS_GOOD(victim) &&   (  IS_AFFECTED(ch, AFF_DETECT_EVIL)  ))
    strcat( buf, "(White Aura) "   );


  if ( IS_AFFECTED(victim, AFF_BERSERK)     )
    strcat( buf, "(B) "  );
  if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_ATTACKER ) )
    strcat( buf, "(A) "   );
  if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_KILLER ) )
    strcat( buf, "(K) "     );
  if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_THIEF  ) )
    strcat( buf, "(T) "      );
  if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_LITTERBUG  ) )
    strcat( buf, "(L) "  );
  if ( IS_NPC(victim) && IS_IMMORTAL(ch)
       && xIS_SET(victim->act, ACT_PROTOTYPE) )
    strcat( buf, "(P) "      );
  if ( IS_NPC(victim) && ch->mount && ch->mount == victim
       && ch->in_room == ch->mount->in_room )
    strcat( buf, "(Mount) "      );
  if ( victim->desc && victim->desc->connected == CON_EDITING )
    strcat( buf, "(W) "    );
  if ( victim->morph != NULL )
    strcat (buf, "(Morphed) ");

  set_char_color( AT_PERSON, ch );
  if ((victim->position == victim->defposition && victim->long_descr[0] != '\0')
      || ( victim->morph && victim->morph->morph &&
           victim->morph->morph->defpos == victim->position ) )
    {
      if ( victim->morph != NULL )
        {
          if ( !IS_IMMORTAL(ch) )
            {
              if ( victim->morph->morph != NULL)
                strcat ( buf, victim->morph->morph->long_desc );
              else
                strcat ( buf, victim->long_descr );
            }
          else
            {
              strcat (buf, PERS(victim, ch, FALSE) );
              if ( !IS_NPC(victim) && !xIS_SET(ch->act, PLR_BRIEF) )
                strcat( buf, victim->pcdata->title );
              strcat( buf, ".\n\r" );
            }
        }
      else
        strcat (buf, victim->long_descr);
      send_to_char( buf, ch );
      show_visible_affects_to_char( victim, ch );
      return;
    }
  else
    {
      if ( victim->morph != NULL && victim->morph->morph != NULL &&
           !IS_IMMORTAL( ch ) )
        strcat( buf, MORPHPERS( victim, ch, FALSE ) );
      else
        strcat( buf, PERS( victim, ch, FALSE ) );
    }

  if ( !IS_NPC(victim) && !xIS_SET(ch->act, PLR_BRIEF) )
    strcat( buf, victim->pcdata->title );

  switch ( victim->position )
    {
    case POS_DEAD:
      strcat( buf, " is DEAD!!" );
      break;
    case POS_MORTAL:
      strcat( buf, " is mortally wounded." );
      break;
    case POS_INCAP:
      strcat( buf, " is incapacitated." );
      break;
    case POS_STUNNED:
      strcat( buf, " is lying here stunned." );
      break;
      /* Furniture ideas taken from ROT
      Furniture 1.01 is provided by Xerves
      Info rewrite for sleeping/resting/standing/sitting on Objects -- Xerves */
    case POS_SLEEPING:
      if (victim->on != NULL)
        {
          if (IS_SET(victim->on->value[2],SLEEP_AT))
            {
              sprintf(message,"&P is sleeping at %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
          else if (IS_SET(victim->on->value[2],SLEEP_ON))
            {
              sprintf(message,"&P is sleeping on %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
          else
            {
              sprintf(message, "&P is sleeping in %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
        }
      else
        {
          if (ch->position == POS_SITTING
              ||  ch->position == POS_RESTING )
            strcat( buf, "&P is sleeping nearby.&G" );
          else
            strcat( buf, "&P is deep in slumber here.&G" );
        }
      break;
    case POS_RESTING:
      if (victim->on != NULL)
        {
          if (IS_SET(victim->on->value[2],REST_AT))
            {
              sprintf(message,"&P is resting at %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
          else if (IS_SET(victim->on->value[2],REST_ON))
            {
              sprintf(message,"&P is resting on %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
          else
            {
              sprintf(message, "&P is resting in %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
        }
      else
        {
          if (ch->position == POS_RESTING)
            strcat ( buf, "&P is sprawled out alongside you.&G" );
          else
            if (ch->position == POS_MOUNTED)
              strcat ( buf, "&P is sprawled out at the foot of your mount.&G" );
            else
              strcat (buf, "&P is sprawled out here.&G" );
        }
      break;
    case POS_SITTING:
      if (victim->on != NULL)
        {
          if (IS_SET(victim->on->value[2],SIT_AT))
            {
              sprintf(message,"&P is sitting at %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
          else if (IS_SET(victim->on->value[2],SIT_ON))
            {
              sprintf(message,"&P is sitting on %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
          else
            {
              sprintf(message, "&P is sitting in %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
        }
      else
        strcat(buf, "&P is sitting here.");
      break;
    case POS_STANDING:
      if (victim->on != NULL)
        {
          if (IS_SET(victim->on->value[2],STAND_AT))
            {
              sprintf(message,"&P is standing at %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
          else if (IS_SET(victim->on->value[2],STAND_ON))
            {
              sprintf(message,"&P is standing on %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
          else
            {
              sprintf(message, "&P is standing in %s.",
                      victim->on->short_descr);
              strcat(buf,message);
            }
        }
      else
        if ( IS_IMMORTAL(victim) )
          strcat( buf, "&P is here before you.&G" );
        else
          if ( ( victim->in_room->sector_type == SECT_UNDERWATER )
               && !IS_AFFECTED(victim, AFF_AQUA_BREATH) && !IS_NPC(victim) )
            strcat( buf, "&P is drowning here.&G" );
          else
            if ( victim->in_room->sector_type == SECT_UNDERWATER )
              strcat( buf, "&P is here in the water.&G" );
            else
              if ( ( victim->in_room->sector_type == SECT_OCEANFLOOR )
                   && !IS_AFFECTED(victim, AFF_AQUA_BREATH) && !IS_NPC(victim) )
                strcat( buf, "&P is drowning here.&G" );
              else
                if ( victim->in_room->sector_type == SECT_OCEANFLOOR )
                  strcat( buf, "&P is standing here in the water.&G" );
                else
                  if ( IS_AFFECTED(victim, AFF_FLOATING)
                       || IS_AFFECTED(victim, AFF_FLYING) )
                    strcat( buf, "&P is hovering here.&G" );
                  else
                    strcat( buf, "&P is standing here.&G" );
      break;
    case POS_SHOVE:
      strcat( buf, " is being shoved around." );
      break;
    case POS_DRAG:
      strcat( buf, " is being dragged around." );
      break;
    case POS_MOUNTED:
      strcat( buf, " is here, upon " );
      if ( !victim->mount )
        strcat( buf, "thin air???" );
      else
        if ( victim->mount == ch )
          strcat( buf, "your back." );
        else
          if ( victim->in_room == victim->mount->in_room )
            {
              strcat( buf, PERS( victim->mount, ch, FALSE ) );
              strcat( buf, "." );
            }
          else
            strcat( buf, "someone who left??" );
      break;
    case POS_FIGHTING:
    case POS_EVASIVE:
    case POS_DEFENSIVE:
    case POS_AGGRESSIVE:
    case POS_BERSERK:
      strcat( buf, " is here, fighting " );
      if ( !victim->fighting )
        {
          strcat( buf, "thin air???" );

          /* some bug somewhere.... kinda hackey fix -h */
          if(! victim->mount)
            victim->position = POS_STANDING;
          else
            victim->position = POS_MOUNTED;
        }
      else if ( who_fighting( victim ) == ch )
        strcat( buf, "YOU!" );
      else if ( victim->in_room == victim->fighting->who->in_room )
        {
          strcat( buf, PERS( victim->fighting->who, ch, FALSE ) );
          strcat( buf, "." );
        }
      else
        strcat( buf, "someone who left??" );
      break;
    }

  strcat( buf, "\n\r" );
  buf[0] = UPPER(buf[0]);
  send_to_char( buf, ch );
  show_visible_affects_to_char( victim, ch );
  return;
}



void show_char_to_char_1( CHAR_DATA *victim, CHAR_DATA *ch )
{
  OBJ_DATA *obj;
  int iWear;
  bool found;

  if ( can_see( victim, ch, FALSE ) && !IS_NPC( ch ) && !xIS_SET( ch->act, PLR_WIZINVIS ) )
    {
      act( AT_ACTION, "$n looks at you.", ch, NULL, victim, TO_VICT    );
      if ( victim != ch )
        act( AT_ACTION, "$n looks at $N.",  ch, NULL, victim, TO_NOTVICT );
      else
        act( AT_ACTION, "$n looks at $mself.", ch, NULL, victim, TO_NOTVICT );
    }

  if ( victim->description[0] != '\0' )
    {
      if ( victim->morph != NULL && victim->morph->morph != NULL)
        send_to_char ( victim->morph->morph->description , ch );
      else
        send_to_char (victim->description, ch);
    }
  else
    {
      if ( victim->morph != NULL && victim->morph->morph != NULL)
        send_to_char ( victim->morph->morph->description , ch );
      else if ( IS_NPC( victim ) )
        act( AT_PLAIN, "You see nothing special about $M.", ch, NULL, victim, TO_CHAR );
      else if ( ch != victim )
        act( AT_PLAIN, "$E isn't much to look at...", ch, NULL, victim, TO_CHAR );
      else
        act( AT_PLAIN, "You're not much to look at...", ch, NULL, NULL, TO_CHAR );
    }

  show_race_line( ch, victim );
  show_condition( ch, victim );

  found = FALSE;
  for ( iWear = 0; iWear < MAX_WEAR; iWear++ )
    {
      if ( ( obj = get_eq_char( victim, iWear ) ) != NULL
           &&   can_see_obj( ch, obj ) )
        {
          if ( !found )
            {
              send_to_char( "\n\r", ch );
              if ( victim != ch )
                act( AT_PLAIN, "$N is using:", ch, NULL, victim, TO_CHAR );
              else
                act( AT_PLAIN, "You are using:", ch, NULL, NULL, TO_CHAR );
              found = TRUE;
            }
          if( (!IS_NPC(victim)) && (victim->race>0) && (victim->race<MAX_PC_RACE))
            send_to_char(race_table[victim->race]->where_name[iWear], ch);
          else
            send_to_char( where_name[iWear], ch );
          send_to_char( format_obj_to_char( obj, ch, TRUE ), ch );
          send_to_char( "\n\r", ch );
        }
    }

  /*
   * Crash fix here by Thoric
   */
  if ( IS_NPC(ch) || victim == ch )
    return;

  if ( IS_IMMORTAL( ch ) )
    {
      if ( IS_NPC( victim ) )
        ch_printf( ch, "\n\rMobile #%d '%s' ",
                   victim->pIndexData->vnum,
                   victim->name );
      else
        ch_printf( ch, "\n\r%s ", victim->name );
      ch_printf( ch, "is a level %d %s %s.\n\r",
                 victim->level,
                 IS_NPC(victim)?victim->race<MAX_NPC_RACE&&victim->race>=0?
           npc_race[victim->race]:"unknown":victim->race<MAX_PC_RACE&&
                 race_table[victim->race]->race_name&&
                 race_table[victim->race]->race_name[0] != '\0'?
                 race_table[victim->race]->race_name:"unknown",
                 IS_NPC(victim)?victim->class<MAX_NPC_CLASS&&victim->class>=0?
           npc_class[victim->class] : "unknown":victim->class<MAX_PC_CLASS&&
                 class_table[victim->class]->who_name&&
                 class_table[victim->class]->who_name[0] != '\0'?
                 class_table[victim->class]->who_name:"unknown");
      /* Fix so it shows what is in class table
      	victim->race<MAX_NPC_RACE&&victim->race>=0?npc_race[victim->race] : "unknown",
      	victim->class<MAX_NPC_CLASS&&victim->class>=0?npc_class[victim->class] : "unknown" );
      */
    }

  if ( number_percent( ) < LEARNED(ch, gsn_peek) )
    {
      ch_printf( ch, "\n\rYou peek at %s inventory:\n\r",
                 victim->sex == 1 ? "his" : victim->sex == 2 ? "her" : "its" );
      show_list_to_char( victim->first_carrying, ch, TRUE, TRUE );
      learn_from_success( ch, gsn_peek );
    }
  else
    if ( ch->pcdata->learned[gsn_peek] > 0 )
      learn_from_failure( ch, gsn_peek );

  return;
}


void show_char_to_char( CHAR_DATA *list, CHAR_DATA *ch )
{
  CHAR_DATA *rch;

  for ( rch = list; rch; rch = rch->next_in_room )
    {
      if ( rch == ch )
        continue;

      if ( can_see( ch, rch, FALSE ) )
        {
          show_char_to_char_0( rch, ch );
        }
      else if ( room_is_dark( ch->in_room )
                &&        IS_AFFECTED(ch, AFF_INFRARED )
                && !(!IS_NPC(rch) && IS_IMMORTAL(rch)) )
        {
          set_char_color( AT_BLOOD, ch );
          send_to_char( "The red form of a living creature is here.\n\r", ch );
        }
    }

  return;
}



bool check_blind( CHAR_DATA *ch )
{
  if ( !IS_NPC(ch) && xIS_SET(ch->act, PLR_HOLYLIGHT) )
    return TRUE;

  if ( IS_AFFECTED(ch, AFF_TRUESIGHT) )
    return TRUE;

  if ( IS_AFFECTED(ch, AFF_BLIND) )
    {
      send_to_char( "You can't see a thing!\n\r", ch );
      return FALSE;
    }

  return TRUE;
}

/*
 * Returns classical DIKU door direction based on text in arg	-Thoric
 */
int get_door( char *arg )
{
  int door;

  if ( !str_cmp( arg, "n"  ) || !str_cmp( arg, "north"	  ) )
    door = 0;
  else if ( !str_cmp( arg, "e"  ) || !str_cmp( arg, "east"	  ) )
    door = 1;
  else if ( !str_cmp( arg, "s"  ) || !str_cmp( arg, "south"	  ) )
    door = 2;
  else if ( !str_cmp( arg, "w"  ) || !str_cmp( arg, "west"	  ) )
    door = 3;
  else if ( !str_cmp( arg, "u"  ) || !str_cmp( arg, "up"	  ) )
    door = 4;
  else if ( !str_cmp( arg, "d"  ) || !str_cmp( arg, "down"	  ) )
    door = 5;
  else if ( !str_cmp( arg, "ne" ) || !str_cmp( arg, "northeast" ) )
    door = 6;
  else if ( !str_cmp( arg, "nw" ) || !str_cmp( arg, "northwest" ) )
    door = 7;
  else if ( !str_cmp( arg, "se" ) || !str_cmp( arg, "southeast" ) )
    door = 8;
  else if ( !str_cmp( arg, "sw" ) || !str_cmp( arg, "southwest" ) )
    door = 9;
  else
    door = -1;
  return door;
}

void do_look( CHAR_DATA *ch, char *argument )
{
  char arg  [MAX_INPUT_LENGTH];
  char arg1 [MAX_INPUT_LENGTH];
  char arg2 [MAX_INPUT_LENGTH];
  char arg3 [MAX_INPUT_LENGTH];
  EXIT_DATA *pexit;
  CHAR_DATA *victim;
  OBJ_DATA *obj;
  ROOM_INDEX_DATA *original;
  char *pdesc;
  sh_int door;
  int number, cnt;
  char dir_n[50];
  char dir_e[50];
  char dir_s[50];
  char dir_w[50];
  char dir_u[50];
  char dir_d[50];
  char dir_ne[50];
  char dir_nw[50];
  char dir_se[50];
  char dir_sw[50];
  char dir_sm[50];
  char *exitcolor;

  strncpy( dir_n, "&z-", 50 );
  strncpy( dir_e, "&z-", 50 );
  strncpy( dir_s, "&z-", 50 );
  strncpy( dir_w, "&z-", 50 );
  strncpy( dir_u, "&z-", 50 );
  strncpy( dir_d, "&z-", 50 );
  strncpy( dir_ne, "&z -", 50 );
  strncpy( dir_nw, "&z- ", 50 );
  strncpy( dir_se, "&z -", 50 );
  strncpy( dir_sw, "&z- ", 50 );
  strncpy( dir_sm, "&z-", 50 );

  if ( !ch->desc )
    return;

  if ( ch->position < POS_SLEEPING )
    {
      send_to_char( "You can't see anything but stars!\n\r", ch );
      return;
    }

  if ( ch->position == POS_SLEEPING )
    {
      send_to_char( "You can't see anything, you're sleeping!\n\r", ch );
      return;
    }

  if ( !check_blind( ch ) )
    return;

  if ( !IS_NPC(ch)
       &&   !xIS_SET(ch->act, PLR_HOLYLIGHT)
       &&   !IS_AFFECTED(ch, AFF_TRUESIGHT)
       &&   room_is_dark( ch->in_room ) )
    {
      set_char_color( AT_DGREY, ch );
      send_to_char( "It is pitch black ... \n\r", ch );
      show_char_to_char( ch->in_room->first_person, ch );
      return;
    }

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );
  argument = one_argument( argument, arg3 );


  if ( arg1[0] == '\0' || !str_cmp( arg1, "auto" ) )
    {
      if( IS_PLR_FLAG( ch, PLR_ONMAP ) || IS_ACT_FLAG( ch, ACT_ONMAP ) )
        {
          display_map( ch );

#ifdef DRAGONFLIGHT

          if( !ch->inflight )
            {
#endif
              show_list_to_char( ch->in_room->first_content, ch, FALSE, FALSE );
              show_char_to_char( ch->in_room->first_person,  ch );
#ifdef DRAGONFLIGHT

            }
#endif
          return;
        }
      /* 'look' or 'look auto' */
      for( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next )
        {
          if( ( pexit->to_room
                && !IS_SET (pexit->exit_info, EX_HIDDEN)
                && !IS_SET (pexit->exit_info, EX_SECRET))
              || (IS_SET (pexit->exit_info, EX_SECRET)
                  && !IS_SET (pexit->exit_info, EX_CLOSED)))
            {
              exitcolor = "&Y";
              if( IS_SET( pexit->exit_info, EX_WINDOW ) )
                exitcolor = "&C";
              if( IS_SET( pexit->exit_info, EX_SECRET ) )
                exitcolor = "&b";
              if( IS_SET( pexit->exit_info, EX_CLOSED ) )
                exitcolor = "&z";
              if( IS_SET( pexit->exit_info, EX_LOCKED ) )
                exitcolor = "&R";

              if( pexit->vdir == DIR_NORTH )
                snprintf( dir_n, 50, "%sN", exitcolor );

              if( pexit->vdir == DIR_EAST )
                snprintf( dir_e, 50, "%sE", exitcolor );

              if( pexit->vdir == DIR_SOUTH )
                snprintf( dir_s, 50, "%sS", exitcolor );

              if( pexit->vdir == DIR_WEST )
                snprintf( dir_w, 50, "%sW", exitcolor );

              if( pexit->vdir == DIR_UP )
                snprintf( dir_u, 50, "%sU", exitcolor );

              if( pexit->vdir == DIR_DOWN )
                snprintf( dir_d, 50, "%sD", exitcolor );

              if( pexit->vdir == DIR_NORTHEAST )
                snprintf( dir_ne, 50, "%sNE", exitcolor );

              if( pexit->vdir == DIR_NORTHWEST )
                snprintf( dir_nw, 50, "%sNW", exitcolor );

              if( pexit->vdir == DIR_SOUTHEAST )
                snprintf( dir_se, 50, "%sSE", exitcolor );

              if( pexit->vdir == DIR_SOUTHWEST )
                snprintf( dir_sw, 50, "%sSW", exitcolor );
            }
        }

      if( xIS_SET( ch->act, PLR_COMPASS ) )
        {
          send_to_char( "\n\r", ch );

          set_char_color( AT_RMNAME, ch );
          ch_printf( ch, "%-50s", ch->in_room->name );
          send_mip_room( ch, ch->in_room->name );

          strncat( dir_nw, "  ", 50 );
          ch_printf_color( ch, "         %s", dir_nw );
          strncat( dir_n, "  ", 50 );
          ch_printf_color( ch, "  %s", dir_n );
          ch_printf_color( ch, "  %s\n\r", dir_ne );
          send_to_char( "&z-<----------------------------------------------->-     ", ch );
          strncat( dir_w, "", 50 );
          ch_printf_color( ch, "   %s", dir_w );
          send_to_char( "&z<-", ch );
          strncat( dir_u, "&z-(&Y&W*&z)", 50 );
          ch_printf_color( ch, "%s", dir_u );
          strncat( dir_d, "&z-", 50 );
          send_to_char( "&z-", ch );
          ch_printf_color( ch, "%s", dir_d );
          send_to_char( "&z>", ch );
          ch_printf_color( ch, "%s\n\r", dir_e );
          send_to_char( "                                                        ", ch );
          strncat( dir_sw, "  ", 50 );
          ch_printf_color( ch, "   %s", dir_sw );
          strncat( dir_s, "  ", 50 );
          ch_printf_color( ch, "  %s", dir_s );
          ch_printf_color( ch, "  %s", dir_se );
          send_to_char( "\n\r", ch );

          /* Room flag display installed by Samson 12-10-97 */
          if( !IS_NPC(ch) && IS_IMMORTAL(ch) && IS_SET( ch->pcdata->flags, PCFLAG_AUTOFLAGS ) )
            {
              set_char_color( AT_BLUE, ch );

              ch_printf( ch, "[Area Flags: %s]\n\r", flag_string( ch->in_room->area->flags, area_flags ) );

              set_char_color( AT_BLUE, ch );


              ch_printf( ch, "[Room Flags: %s]\n\r", ext_flag_string( &ch->in_room->room_flags, r_flags ) );
            }

          /* Room Sector display written and installed by Samson 12-10-97 */
          if( !IS_NPC(ch) && IS_IMMORTAL(ch) && IS_SET( ch->pcdata->flags, PCFLAG_SECTORD ) )
            {
              set_char_color( AT_BLUE, ch );

              ch_printf( ch, "[Sector Type: %s]\n\r", sec_flags[ch->in_room->sector_type] );
            }

          /* Area name and filename display installed by Samson 12-13-97 */
          if( !IS_NPC(ch) && IS_IMMORTAL(ch) && IS_SET( ch->pcdata->flags, PCFLAG_ANAME ) )
            {
              set_char_color( AT_BLUE, ch );
              ch_printf( ch, "[Area name: %s]  ", ch->in_room->area->name );
              if ( ch->level >= LEVEL_CREATOR )
                ch_printf( ch, "[Area filename: %s]\n\r", ch->in_room->area->filename );
              else
                send_to_char( "\n\r", ch );
            }
          set_char_color( AT_RMDESC, ch );
          /*
          }
               else
               {*/
          if ( !IS_NPC(ch) && xIS_SET(ch->act, PLR_AUTOMAP) )   /* maps */
            {
              do_mapper(ch, "7");
              return;
            }

          /*    set_char_color( AT_RMNAME, ch );
             send_to_char( ch->in_room->name, ch );
          */   send_to_char( "\n\r", ch );

          if ( !IS_NPC(ch) && !xIS_SET(ch->act, PLR_BRIEF) )
            {
              set_char_color( AT_RMDESC, ch );
              send_to_char( ch->in_room->description, ch );
            }

        }

      if ( !IS_NPC(ch) && xIS_SET(ch->act, PLR_AUTOEXIT) )
        do_exits( ch, "auto" );


      show_list_to_char( ch->in_room->first_content, ch, FALSE, FALSE );
      show_char_to_char( ch->in_room->first_person,  ch );
      return;
    }

  if ( !str_cmp( arg1, "under" ) )
    {
      int count;

      /* 'look under' */
      if ( arg2[0] == '\0' )
        {
          send_to_char( "Look beneath what?\n\r", ch );
          return;
        }

      if ( ( obj = get_obj_here( ch, arg2 ) ) == NULL )
        {
          send_to_char( "You do not see that here.\n\r", ch );
          return;
        }
      if ( !CAN_WEAR( obj, ITEM_TAKE ) && ch->level < sysdata.level_getobjnotake )
        {
          send_to_char( "You can't seem to get a grip on it.\n\r", ch );
          return;
        }
      if ( ch->carry_weight + obj->weight > can_carry_w( ch ) )
        {
          send_to_char( "It's too heavy for you to look under.\n\r", ch );
          return;
        }
      count = obj->count;
      obj->count = 1;
      act( AT_PLAIN, "You lift $p and look beneath it:", ch, obj, NULL, TO_CHAR );
      act( AT_PLAIN, "$n lifts $p and looks beneath it:", ch, obj, NULL, TO_ROOM );
      obj->count = count;
      if ( IS_OBJ_STAT( obj, ITEM_COVERING ) )
        show_list_to_char( obj->first_content, ch, TRUE, TRUE );
      else
        send_to_char( "Nothing.\n\r", ch );
      if( EXA_prog_trigger )
        oprog_examine_trigger( ch, obj );
      return;
    }

  if ( !str_cmp( arg1, "i" ) || !str_cmp( arg1, "in" ) )
    {
      int count;

      /* 'look in' */
      if ( arg2[0] == '\0' )
        {
          send_to_char( "Look in what?\n\r", ch );
          return;
        }

      if ( ( obj = get_obj_here( ch, arg2 ) ) == NULL )
        {
          send_to_char( "You do not see that here.\n\r", ch );
          return;
        }

      switch ( obj->item_type )
        {
        default:
          send_to_char( "That is not a container.\n\r", ch );
          break;

        case ITEM_DRINK_CON:
          if ( obj->value[1] <= 0 )
            {
              send_to_char( "It is empty.\n\r", ch );
              if( EXA_prog_trigger )
                oprog_examine_trigger( ch, obj );
              break;
            }

          /* exam addition for the new liquidtable	-Nopey */
          {
            if (obj->value[2] > 17)
              obj->value[2] = 17;

            LIQ_TABLE *liq = get_liq_vnum(obj->value[2]);

            ch_printf(ch, "It's %s full of a %s liquid.",
                      obj->value[1] <	obj->value[0] / 4 ? "less than" :
                      obj->value[1] < 3 * obj->value[0] / 4 ? "about"	: "more than",
                      liq->color );
          }


          if( EXA_prog_trigger )
            oprog_examine_trigger( ch, obj );
          break;

        case ITEM_PORTAL:
          for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next )
            {
              if ( pexit->vdir == DIR_PORTAL
                   &&   IS_SET(pexit->exit_info, EX_PORTAL) )
                {
                  if ( room_is_private( pexit->to_room ) && ch->level < sysdata.level_override_private )
                    {
                      set_char_color( AT_WHITE, ch );
                      send_to_char( "The room ahead is private!\n\r", ch );
                      return;
                    }

                  if( IS_EXIT_FLAG( pexit, EX_OVERLAND ) )
                    {
                      original = ch->in_room;
                      enter_map( ch, pexit->x, pexit->y, -1 );
                      leave_map( ch, NULL, original );
                    }
                  else
                    {
                      original = ch->in_room;
                      char_from_room( ch );
                      char_to_room( ch, pexit->to_room );
                      do_look( ch, "auto" );
                      char_from_room( ch );
                      char_to_room( ch, original );
                    }
                  return;
                }
            }
          send_to_char( "You see swirling chaos...\n\r", ch );
          break;
        case ITEM_CONTAINER:
        case ITEM_QUIVER:
        case ITEM_CORPSE_NPC:
        case ITEM_CORPSE_PC:
          if ( IS_SET(obj->value[1], CONT_CLOSED) )
            {
              send_to_char( "It is closed.\n\r", ch );
              break;
            }

        case ITEM_KEYRING:
          count = obj->count;
          obj->count = 1;
          if ( obj->item_type == ITEM_CONTAINER )
            act( AT_PLAIN, "$p contains:", ch, obj, NULL, TO_CHAR );
          else
            act( AT_PLAIN, "$p holds:", ch, obj, NULL, TO_CHAR );
          obj->count = count;
          show_list_to_char( obj->first_content, ch, TRUE, TRUE );
          if( EXA_prog_trigger )
            oprog_examine_trigger( ch, obj );
          break;
        }
      return;
    }

  if ( (pdesc=get_extra_descr(arg1, ch->in_room->first_extradesc)) != NULL )
    {
      send_to_char_color( pdesc, ch );
      return;
    }

  door = get_door(arg1);
  if ( (pexit=find_door(ch, arg1, TRUE)) != NULL )
    {
      if ( IS_SET(pexit->exit_info, EX_CLOSED)
           &&  !IS_SET(pexit->exit_info, EX_WINDOW) )
        {
          if ( (IS_SET(pexit->exit_info, EX_SECRET)
                ||    IS_SET(pexit->exit_info, EX_DIG)) && door != -1 )
            send_to_char( "Nothing special there.\n\r", ch );
          else
            act( AT_PLAIN, "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR );
          return;
        }
      if ( IS_SET( pexit->exit_info, EX_BASHED ) )
        act(AT_RED, "The $d has been bashed from its hinges!",ch, NULL, pexit->keyword, TO_CHAR);

      if ( pexit->description && pexit->description[0] != '\0' )
        send_to_char( pexit->description, ch );
      else
        send_to_char( "Nothing special there.\n\r", ch );

      /*
       * Ability to look into the next room			-Thoric
       */
      if ( pexit->to_room
           && ( IS_AFFECTED( ch, AFF_SCRYING )
                ||   ch->class == CLASS_THIEF
                ||   IS_SET( pexit->exit_info, EX_xLOOK )
                ||   get_trust(ch) >= LEVEL_IMMORTAL ) )
        {
          if ( !IS_SET( pexit->exit_info, EX_xLOOK )
               &&    get_trust( ch ) < LEVEL_IMMORTAL )
            {
              set_char_color( AT_MAGIC, ch );
              send_to_char( "You attempt to scry...\n\r", ch );
              /*
               * Change by Narn, Sept 96 to allow characters who don't have the
               * scry spell to benefit from objects that are affected by scry.
               */
              if (!IS_NPC(ch) )
                {
                  int percent = LEARNED(ch, skill_lookup("scry") );
                  if ( !percent )
                    {
                      if ( ch->class == CLASS_THIEF )
                        percent = 95;
                      else
                        percent = 55;	/* 95 was too good -Thoric */
                    }

                  if ( number_percent( ) > percent )
                    {
                      send_to_char( "You fail.\n\r", ch );
                      return;
                    }
                }
            }
          if ( room_is_private( pexit->to_room ) && ch->level < sysdata.level_override_private )
            {
              set_char_color( AT_WHITE, ch );
              send_to_char( "The room ahead is private!\n\r", ch );
              return;
            }

          if( IS_EXIT_FLAG( pexit, EX_OVERLAND ) )
            {
              original = ch->in_room;
              enter_map( ch, pexit->x, pexit->y, -1 );
              leave_map( ch, NULL, original );
            }
          else
            {
              original = ch->in_room;
              char_from_room( ch );
              char_to_room( ch, pexit->to_room );
              do_look( ch, "auto" );
              char_from_room( ch );
              char_to_room( ch, original );
            }
        }
      return;
    }
  else
    if ( door != -1 )
      {
        send_to_char( "Nothing special there.\n\r", ch );
        return;
      }

  if ( (victim = get_char_room(ch, arg1)) != NULL )
    {
      show_char_to_char_1( victim, ch );
      return;
    }


  /* finally fixed the annoying look 2.obj desc bug	-Thoric */
  number = number_argument( arg1, arg );
  for ( cnt = 0, obj = ch->last_carrying; obj; obj = obj->prev_content )
    {
      if ( can_see_obj( ch, obj ) )
        {
          if ( (pdesc=get_extra_descr(arg, obj->first_extradesc)) != NULL )
            {
              if ( (cnt += obj->count) < number )
                continue;
              send_to_char_color( pdesc, ch );
              if( EXA_prog_trigger )
                oprog_examine_trigger( ch, obj );
              return;
            }

          if ( (pdesc=get_extra_descr(arg, obj->pIndexData->first_extradesc)) != NULL )
            {
              if ( (cnt += obj->count) < number )
                continue;
              send_to_char_color( pdesc, ch );
              if( EXA_prog_trigger )
                oprog_examine_trigger( ch, obj );
              return;
            }
          if ( nifty_is_name_prefix( arg, obj->name ) )
            {
              if ( (cnt += obj->count) < number )
                continue;
              pdesc = get_extra_descr( obj->name, obj->pIndexData->first_extradesc );
              if ( !pdesc )
                pdesc = get_extra_descr( obj->name, obj->first_extradesc );
              if ( !pdesc )
                send_to_char_color( "You see nothing special.\r\n", ch );
              else
                send_to_char_color( pdesc, ch );
              if( EXA_prog_trigger )
                oprog_examine_trigger( ch, obj );
              return;
            }
        }
    }

  for ( obj = ch->in_room->last_content; obj; obj = obj->prev_content )
    {
      if ( can_see_obj( ch, obj ) )
        {
          if ( (pdesc=get_extra_descr(arg, obj->first_extradesc)) != NULL )
            {
              if ( (cnt += obj->count) < number )
                continue;
              send_to_char_color( pdesc, ch );
              if( EXA_prog_trigger )
                oprog_examine_trigger( ch, obj );
              return;
            }

          if ( (pdesc=get_extra_descr(arg, obj->pIndexData->first_extradesc)) != NULL )
            {
              if ( (cnt += obj->count) < number )
                continue;
              send_to_char_color( pdesc, ch );
              if( EXA_prog_trigger )
                oprog_examine_trigger( ch, obj );
              return;
            }
          if ( nifty_is_name_prefix( arg, obj->name ) )
            {
              if ( (cnt += obj->count) < number )
                continue;
              pdesc = get_extra_descr( obj->name, obj->pIndexData->first_extradesc );
              if ( !pdesc )
                pdesc = get_extra_descr( obj->name, obj->first_extradesc );
              if ( !pdesc )
                send_to_char( "You see nothing special.\r\n", ch );
              else
                send_to_char_color( pdesc, ch );
              if( EXA_prog_trigger )
                oprog_examine_trigger( ch, obj );
              return;
            }
        }
    }

  send_to_char( "You do not see that here.\n\r", ch );
  return;
}

void show_race_line( CHAR_DATA *ch, CHAR_DATA *victim )
{
  char buf[MAX_STRING_LENGTH];
  int feet, inches;


  if ( !IS_NPC(victim) && (victim != ch) )
    {
      feet =  victim->height / 12;
      inches = victim->height % 12;
      sprintf( buf, "%s is %d'%d\" and weighs %d pounds.\n\r", PERS(victim, ch, FALSE), feet, inches, victim->weight );
      send_to_char( buf, ch);
      return;
    }
  if ( !IS_NPC(victim) && (victim == ch) )
    {
      feet =  victim->height / 12;
      inches = victim->height % 12;
      sprintf( buf, "You are %d'%d\" and weigh %d pounds.\n\r",  feet, inches, victim->weight );
      send_to_char( buf, ch);
      return;
    }

}


void show_condition( CHAR_DATA *ch, CHAR_DATA *victim )
{
  char buf[MAX_STRING_LENGTH];
  int percent;

  if ( victim->max_hit > 0 )
    percent = ( 100 * victim->hit ) / victim->max_hit;
  else
    percent = -1;


  if ( victim != ch )
    {
      strcpy( buf, PERS(victim, ch, FALSE) );
      if ( percent >= 100 )
        strcat( buf, " is in perfect health.\n\r" );
      else if ( percent >=  90 )
        strcat( buf, " is slightly scratched.\n\r" );
      else if ( percent >=  80 )
        strcat( buf, " has a few bruises.\n\r"     );
      else if ( percent >=  70 )
        strcat( buf, " has some cuts.\n\r"         );
      else if ( percent >=  60 )
        strcat( buf, " has several wounds.\n\r"    );
      else if ( percent >=  50 )
        strcat( buf, " has many nasty wounds.\n\r" );
      else if ( percent >=  40 )
        strcat( buf, " is bleeding freely.\n\r"    );
      else if ( percent >=  30 )
        strcat( buf, " is covered in blood.\n\r"   );
      else if ( percent >=  20 )
        strcat( buf, " is leaking guts.\n\r"       );
      else if ( percent >=  10 )
        strcat( buf, " is almost dead.\n\r"        );
      else
        strcat( buf, " is DYING.\n\r"              );
    }
  else
    {
      strcpy( buf, "You" );
      if ( percent >= 100 )
        strcat( buf, " are in perfect health.\n\r" );
      else if ( percent >=  90 )
        strcat( buf, " are slightly scratched.\n\r");
      else if ( percent >=  80 )
        strcat( buf, " have a few bruises.\n\r"    );
      else if ( percent >=  70 )
        strcat( buf, " have some cuts.\n\r"        );
      else if ( percent >=  60 )
        strcat( buf, " have several wounds.\n\r"   );
      else if ( percent >=  50 )
        strcat( buf, " have many nasty wounds.\n\r");
      else if ( percent >=  40 )
        strcat( buf, " are bleeding freely.\n\r"   );
      else if ( percent >=  30 )
        strcat( buf, " are covered in blood.\n\r"  );
      else if ( percent >=  20 )
        strcat( buf, " are leaking guts.\n\r"      );
      else if ( percent >=  10 )
        strcat( buf, " are almost dead.\n\r"       );
      else
        strcat( buf, " are DYING.\n\r"             );
    }

  buf[0] = UPPER(buf[0]);
  send_to_char( buf, ch );
  return;
}

/* A much simpler version of look, this function will show you only
the condition of a mob or pc, or if used without an argument, the
same you would see if you enter the room and have config +brief.
-- Narn, winter '96
*/
void do_glance( CHAR_DATA *ch, char *argument )
{
  char arg1 [MAX_INPUT_LENGTH];
  CHAR_DATA *victim;
  bool brief;

  if ( !ch->desc )
    return;

  if ( ch->position < POS_SLEEPING )
    {
      send_to_char( "You can't see anything but stars!\n\r", ch );
      return;
    }

  if ( ch->position == POS_SLEEPING )
    {
      send_to_char( "You can't see anything, you're sleeping!\n\r", ch );
      return;
    }

  if ( !check_blind( ch ) )
    return;

  set_char_color( AT_ACTION, ch );
  argument = one_argument( argument, arg1 );

  if ( arg1[0] == '\0' )
    {
      if ( xIS_SET(ch->act, PLR_BRIEF) )
        brief = TRUE;
      else
        brief = FALSE;
      xSET_BIT( ch->act, PLR_BRIEF );
      do_look( ch, "auto" );
      if ( !brief )
        xREMOVE_BIT(ch->act, PLR_BRIEF);
      return;
    }

  if ( ( victim = get_char_room( ch, arg1 ) ) == NULL )
    {
      send_to_char( "They're not here.\n\r", ch );
      return;
    }
  else
    {
      if ( can_see( victim, ch, FALSE ) )
        {
          act( AT_ACTION, "$n glances at you.", ch, NULL, victim, TO_VICT );
          act( AT_ACTION, "$n glances at $N.",  ch, NULL, victim, TO_NOTVICT );
        }
      if ( IS_IMMORTAL( ch ) && victim != ch )
        {
          if ( IS_NPC( victim ) )
            ch_printf( ch, "Mobile #%d '%s' ",
                       victim->pIndexData->vnum, victim->name );
          else
            ch_printf( ch, "%s ", victim->name );
          ch_printf( ch, "is a level %d %s %s.\n\r",
                     victim->level,
                     IS_NPC(victim)?victim->race<MAX_NPC_RACE&&victim->race>=0?
           npc_race[victim->race] : "unknown":victim->race<MAX_PC_RACE&&
                     race_table[victim->race]->race_name&&
                     race_table[victim->race]->race_name[0] != '\0'?
                     race_table[victim->race]->race_name:"unknown",
                     IS_NPC(victim)?victim->class<MAX_NPC_CLASS&&victim->class>=0?
           npc_class[victim->class] : "unknown":victim->class<MAX_PC_CLASS&&
                     class_table[victim->class]->who_name&&
                     class_table[victim->class]->who_name[0] != '\0'?
                     class_table[victim->class]->who_name:"unknown");
          /* New Change
          	    victim->race<MAX_NPC_RACE&&victim->race>=0?npc_race[victim->race] : "unknown",
          	    victim->class<MAX_NPC_CLASS&&victim->class>=0?npc_class[victim->class] : "unknown" );
          */
        }
      show_condition( ch, victim );

      return;
    }

  return;
}


void do_examine( CHAR_DATA *ch, char *argument )
{
  char buf[MAX_STRING_LENGTH];
  char arg[MAX_INPUT_LENGTH];
  OBJ_DATA *obj;
  BOARD_DATA *board;
  sh_int dam;

  if ( !argument )
    {
      bug( "do_examine: null argument.", 0);
      return;
    }

  if ( !ch )
    {
      bug( "do_examine: null ch.", 0);
      return;
    }

  one_argument( argument, arg );

  if ( arg[0] == '\0' )
    {
      send_to_char( "Examine what?\n\r", ch );
      return;
    }

  EXA_prog_trigger = FALSE;
  do_look( ch, arg );
  EXA_prog_trigger = TRUE;

  /*
   * Support for looking at boards, checking equipment conditions,
   * and support for trigger positions by Thoric
   */
  if ( (obj = get_obj_here(ch, arg)) != NULL )
    {
      if ( (board = get_board(obj)) != NULL )
        {
          if ( board->num_posts )
            ch_printf( ch, "There are about %d notes posted here.  Type 'note list' to list them.\n\r", board->num_posts );
          else
            send_to_char( "There aren't any notes posted here.\n\r", ch );
        }

      switch ( obj->item_type )
        {
        default:
          break;

        case ITEM_ARMOR:
          if ( obj->value[1] == 0 )
            obj->value[1] = obj->value[0];
          if ( obj->value[1] == 0 )
            obj->value[1] = 1;
          dam = (sh_int) ((obj->value[0] * 10) / obj->value[1]);
          strcpy( buf, "As you look more closely, you notice that it is ");
          if (dam >= 10)
            strcat( buf, "in superb condition.");
          else if (dam ==  9)
            strcat( buf, "in very good condition.");
          else if (dam ==  8)
            strcat( buf, "in good shape.");
          else if (dam ==  7)
            strcat( buf, "showing a bit of wear.");
          else if (dam ==  6)
            strcat( buf, "a little run down.");
          else if (dam ==  5)
            strcat( buf, "in need of repair.");
          else if (dam ==  4)
            strcat( buf, "in great need of repair.");
          else if (dam ==  3)
            strcat( buf, "in dire need of repair.");
          else if (dam ==  2)
            strcat( buf, "very badly worn.");
          else if (dam ==  1)
            strcat( buf, "practically worthless.");
          else if (dam <=  0)
            strcat( buf, "broken.");
          strcat( buf, "\n\r" );
          send_to_char( buf, ch );
          break;

        case ITEM_WEAPON:
          dam = INIT_WEAPON_CONDITION - obj->value[0];
          strcpy( buf, "As you look more closely, you notice that it is ");
          if (dam ==  0)
            strcat( buf, "in superb condition.");
          else if (dam ==  1)
            strcat( buf, "in excellent condition.");
          else if (dam ==  2)
            strcat( buf, "in very good condition.");
          else if (dam ==  3)
            strcat( buf, "in good shape.");
          else if (dam ==  4)
            strcat( buf, "showing a bit of wear.");
          else if (dam ==  5)
            strcat( buf, "a little run down.");
          else if (dam ==  6)
            strcat( buf, "in need of repair.");
          else if (dam ==  7)
            strcat( buf, "in great need of repair.");
          else if (dam ==  8)
            strcat( buf, "in dire need of repair.");
          else if (dam ==  9)
            strcat( buf, "very badly worn.");
          else if (dam == 10)
            strcat( buf, "practically worthless.");
          else if (dam == 11)
            strcat( buf, "almost broken.");
          else if (dam == 12)
            strcat( buf, "broken.");
          strcat( buf, "\n\r" );
          send_to_char( buf, ch );
          break;

        case ITEM_COOK:
          strcpy( buf, "As you examine it carefully you notice that it " );
          dam = obj->value[2];
          if (dam >= 3)
            strcat( buf, "is burned to a crisp.");
          else if (dam == 2)
            strcat( buf, "is a little over cooked.");
          else if (dam == 1)
            strcat( buf, "is perfectly roasted.");
          else
            strcat( buf, "is raw.");
          strcat( buf, "\n\r" );
          send_to_char( buf, ch );
        case ITEM_FOOD:
          if ( obj->timer > 0 && obj->value[1] > 0 )
            dam = (obj->timer * 10) / obj->value[1];
          else
            dam = 10;
          if ( obj->item_type == ITEM_FOOD )
            strcpy( buf, "As you examine it carefully you notice that it " );
          else
            strcpy( buf, "Also it " );
          if (dam >= 10)
            strcat( buf, "is fresh.");
          else if (dam ==  9)
            strcat( buf, "is nearly fresh.");
          else if (dam ==  8)
            strcat( buf, "is perfectly fine.");
          else if (dam ==  7)
            strcat( buf, "looks good.");
          else if (dam ==  6)
            strcat( buf, "looks ok.");
          else if (dam ==  5)
            strcat( buf, "is a little stale.");
          else if (dam ==  4)
            strcat( buf, "is a bit stale.");
          else if (dam ==  3)
            strcat( buf, "smells slightly off.");
          else if (dam ==  2)
            strcat( buf, "smells quite rank.");
          else if (dam ==  1)
            strcat( buf, "smells revolting!");
          else if (dam <=  0)
            strcat( buf, "is crawling with maggots!");
          strcat( buf, "\n\r" );
          send_to_char( buf, ch );
          break;


        case ITEM_SWITCH:
        case ITEM_LEVER:
        case ITEM_PULLCHAIN:
          if ( IS_SET( obj->value[0], TRIG_UP ) )
            send_to_char( "You notice that it is in the up position.\n\r", ch );
          else
            send_to_char( "You notice that it is in the down position.\n\r", ch );
          break;
        case ITEM_BUTTON:
          if ( IS_SET( obj->value[0], TRIG_UP ) )
            send_to_char( "You notice that it is depressed.\n\r", ch );
          else
            send_to_char( "You notice that it is not depressed.\n\r", ch );
          break;

        case ITEM_CORPSE_PC:
        case ITEM_CORPSE_NPC:
          {
            sh_int timerfrac = obj->timer;
            if ( obj->item_type == ITEM_CORPSE_PC )
              timerfrac = (int)obj->timer / 8 + 1;

            switch (timerfrac)
              {
              default:
                send_to_char( "This corpse has recently been slain.\n\r", ch );
                break;
              case 4:
                send_to_char( "This corpse was slain a little while ago.\n\r", ch );
                break;
              case 3:
                send_to_char( "A foul smell rises from the corpse, and it is covered in flies.\n\r", ch );
                break;
              case 2:
                send_to_char( "A writhing mass of maggots and decay, you can barely go near this corpse.\n\r", ch );
                break;
              case 1:
              case 0:
                send_to_char( "Little more than bones, there isn't much left of this corpse.\n\r", ch );
                break;
              }
          }
        case ITEM_CONTAINER:
          if ( IS_OBJ_STAT( obj, ITEM_COVERING ) )
            break;
        case ITEM_DRINK_CON:
        case ITEM_QUIVER:
          send_to_char( "When you look inside, you see:\n\r", ch );
        case ITEM_KEYRING:
          EXA_prog_trigger = FALSE;
          sprintf( buf, "in %s",arg );
          do_look( ch, buf );
          EXA_prog_trigger = TRUE;
          break;
        }
      if ( IS_OBJ_STAT( obj, ITEM_COVERING ) )
        {
          EXA_prog_trigger = FALSE;
          sprintf( buf, "under %s", arg );
          do_look( ch, buf );
          EXA_prog_trigger = TRUE;
        }
      oprog_examine_trigger( ch, obj );
      if ( char_died(ch) || obj_extracted(obj) )
        return;

      check_for_trap( ch, obj, TRAP_EXAMINE );
    }
  return;
}

void do_exits( CHAR_DATA *ch, char *argument )
{
  char buf[MAX_STRING_LENGTH];
  EXIT_DATA *pexit;
  bool found, closed=FALSE, locked=FALSE, DT=FALSE;
  bool fAuto;
  int  spaces;

  set_char_color( AT_EXITS, ch );
  fAuto  = !str_cmp( argument, "auto" );

  if ( !check_blind(ch) )
    return;

  strcpy( buf, fAuto ? "&WExits:" : "&WObvious exits:\n\r" );

  found = FALSE;
  for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next )
    {
      if ( pexit->to_room
           &&  !IS_SET(pexit->exit_info, EX_SECRET)
           && (!IS_SET(pexit->exit_info, EX_WINDOW)
               ||   IS_SET(pexit->exit_info, EX_ISDOOR))
           &&  !IS_SET(pexit->exit_info, EX_HIDDEN) )
        {
          found = TRUE;
          closed = IS_SET(pexit->exit_info, EX_CLOSED);
          locked = (IS_SET(pexit->exit_info, EX_LOCKED) || IS_SET(pexit->exit_info, EX_BOLTED) );
          DT = ((IS_IMMORTAL(ch) || IS_AFFECTED(ch, AFF_DETECTTRAPS)) && xIS_SET(pexit->to_room->room_flags, ROOM_DEATH));

          if ( fAuto )
            {
              sprintf( buf, "%s %s" "%s" "&W" "%s", buf,
                       DT? "&R***" : !closed ? "" : locked ? "&R[&W" : "[",
                       DT ? strupper(dir_name[pexit->vdir]): dir_name[pexit->vdir],
                       DT? "&R***&W" : !closed ? "" : locked ? "&R]&W" : "]");
            }
          else
            {
              /* I don't want to underline spaces, so I'll calculate the number we need */
              spaces = 5 - strlen (dir_name[pexit->vdir]);
              if (spaces < 0)
                spaces = 0;
              sprintf( buf + strlen(buf), "%s" "%*s - %s\n\r",
                       capitalize( dir_name[pexit->vdir] ),
                       spaces,  /* number of spaces */
                       "",
                       DT ? "&RYou sense an aura of imminent doom this way&W" : locked ? "&R[&WClosed and Locked/Barred&R]&W" : closed ? "[Closed]" : room_is_dark( pexit->to_room ) ?  "Too dark to tell" : pexit->to_room->name );
            }
        }
    }

  if ( !found )
    strcat( buf, fAuto ? " none.\n\r" : "None.\n\r" );
  else
    if ( fAuto )
      strcat( buf, ".\n\r" );
  send_to_char( buf, ch );
  return;
}

char *	const	day_name	[] =
  {
    "Monday", "Tuesday", "Wedensday", "Thursday", "Friday",
    "Saturday", "Sunday"
  };

char *	const	month_name	[] =
  {
    "January", "Febuary", "March", "April",
    "May", "June", "July", "August", "September",
    "October", "November", "December"
  };

void do_time( CHAR_DATA *ch, char *argument )
{
  extern char str_boot_time[];
  char *suf;
  int day;

  day     = time_info.day + 1;

  if ( day > 4 && day <  20 )
    suf = "th";
  else if ( day % 10 ==  1       )
    suf = "st";
  else if ( day % 10 ==  2       )
    suf = "nd";
  else if ( day % 10 ==  3       )
    suf = "rd";
  else
    suf = "th";

  set_char_color( AT_YELLOW, ch );
  ch_printf( ch,
             "It is %d o'clock %s, %s the %d%s of %s in the year %d.\n\r"
             "The mud started up at:    %s\r"
             "The system time (E.S.T.): %s\r",
             (time_info.hour % 12 == 0) ? 12 : time_info.hour % 12,
             time_info.hour >= 12 ? "pm" : "am",
             day_name[day % 7],
             day, suf,
             month_name[time_info.month],
             time_info.year,
             str_boot_time,
             (char *) ctime( &current_time ));

  if( sysdata.CLEANPFILES )
    ch_printf( ch, "\n\rNext pfile cleanup is scheduled for: %s\n\r", (char *)ctime( &new_pfile_time_t ) );

  return;
}



/*
 * Produce a description of the weather based on area weather using
 * the following sentence format:
 *		<combo-phrase> and <single-phrase>.
 * Where the combo-phrase describes either the precipitation and
 * temperature or the wind and temperature. The single-phrase
 * describes either the wind or precipitation depending upon the
 * combo-phrase.
 * Last Modified: July 31, 1997
 * Fireblade - Under Construction
 */
void do_weather(CHAR_DATA *ch, char *argument)
{
  char *combo, *single;
  char buf[MAX_INPUT_LENGTH];
  int temp, precip, wind;

  if( !IS_PLR_FLAG( ch, PLR_ONMAP ) )
    {

      if ( !xIS_OUTSIDE(ch) || INDOOR_SECTOR(ch->in_room->sector_type) )
        {
          send_to_char( "You can't see the sky from here.\n\r", ch );
          return;
        }
    }

  if ( !xIS_OUTSIDE(ch) )
    {
      ch_printf(ch, "You can't see the sky from here.\n\r");
      return;
    }

  temp = (ch->in_room->area->weather->temp + 3*weath_unit - 1)/
         weath_unit;
  precip = (ch->in_room->area->weather->precip + 3*weath_unit - 1)/
           weath_unit;
  wind = (ch->in_room->area->weather->wind + 3*weath_unit - 1)/
         weath_unit;

  if ( precip >= 3 )
    {
      combo = preciptemp_msg[precip][temp];
      single = wind_msg[wind];
    }
  else
    {
      combo = windtemp_msg[wind][temp];
      single = precip_msg[precip];
    }

  sprintf(buf, "%s and %s.\n\r", combo, single);

  set_char_color(AT_BLUE, ch);

  ch_printf(ch, buf);
}

/*
 * Moved into a separate function so it can be used for other things
 * ie: online help editing				-Thoric
 */
HELP_DATA *get_help( CHAR_DATA *ch, char *argument )
{
  char argall[MAX_INPUT_LENGTH];
  char argone[MAX_INPUT_LENGTH];
  char argnew[MAX_INPUT_LENGTH];
  HELP_DATA *pHelp;
  int lev;

  if ( argument[0] == '\0' )
    argument = "summary";

  if ( isdigit(argument[0]) )
    {
      lev = number_argument( argument, argnew );
      argument = argnew;
    }
  else
    lev = -2;
  /*
   * Tricky argument handling so 'help a b' doesn't match a.
   */
  argall[0] = '\0';
  while ( argument[0] != '\0' )
    {
      argument = one_argument( argument, argone );
      if ( argall[0] != '\0' )
        strcat( argall, " " );
      strcat( argall, argone );
    }

  for ( pHelp = first_help; pHelp; pHelp = pHelp->next )
    {
      if ( pHelp->level > get_trust( ch ) )
        continue;
      if ( lev != -2 && pHelp->level != lev )
        continue;

      if ( is_name( argall, pHelp->keyword ) )
        return pHelp;
    }

  return NULL;
}

/*
 * LAWS command
 */
void do_laws( CHAR_DATA *ch, char *argument )
{
  char buf[1024];

  if ( argument == NULL)
    do_help( ch, "laws" );
  else
    {
      sprintf( buf, "law %s", argument );
      do_help( ch, buf );
    }
}

//  Ranks by number of matches between two whole words. Coded for the Similar Helpfiles
//  Snippet by Senir.
sh_int str_similarity( const char *astr, const char *bstr )
{
  sh_int matches=0;

  if (!astr || !bstr)
    return matches;

  for ( ; *astr; astr++)
    {
      if ( LOWER(*astr) == LOWER(*bstr) )
        matches++;

      if (++bstr == '\0')
        return matches;
    }

  return matches;
}

//  Ranks by number of matches until there's a nonmatching character between two words.
//  Coded for the Similar Helpfiles Snippet by Senir.
sh_int str_prefix_level( const char *astr, const char *bstr )
{
  sh_int matches=0;

  if (!astr || !bstr)
    return matches;

  for ( ; *astr; astr++)
    {
      if ( LOWER(*astr) == LOWER(*bstr) )
        matches++;
      else
        return matches;

      if (++bstr == '\0')
        return matches;
    }

  return matches;
}

// Main function of Similar Helpfiles Snippet by Senir. It loops through all of the
// helpfiles, using the string matching function defined to find the closest matching
// helpfiles to the argument. It then checks for singles. Then, if matching helpfiles
// are found at all, it loops through and prints out the closest matching helpfiles.
// If its a single(there's only one), it opens the helpfile.
void similar_help_files(CHAR_DATA *ch, char *argument)
{
  HELP_DATA *pHelp=NULL;
  char buf[MAX_STRING_LENGTH];
  char *extension;
  sh_int lvl=0;
  bool single=FALSE;


  send_to_pager_color( "&C&BSimilar Help Files:\n\r", ch);

  for ( pHelp = first_help; pHelp; pHelp=pHelp->next)
    {
      buf[0]='\0';
      extension=pHelp->keyword;

      if (pHelp->level > get_trust(ch))
        continue;

      while ( extension[0] != '\0' )
        {
          extension= one_argument(extension, buf);

          if ( str_similarity(argument, buf) > lvl)
            {
              lvl=str_similarity(argument, buf);
              single=TRUE;
            }
          else if ( str_similarity(argument, buf) == lvl && lvl > 0)
            {
              single=FALSE;
            }
        }
    }

  if (lvl==0)
    {
      send_to_pager_color( "&C&GNo similar help files.\n\r", ch);
      return;
    }

  for ( pHelp = first_help; pHelp; pHelp=pHelp->next)
    {
      buf[0]='\0';
      extension=pHelp->keyword;

      while ( extension[0] != '\0' )
        {
          extension=one_argument(extension, buf);

          if ( str_similarity(argument, buf) >= lvl
               && pHelp->level <= get_trust(ch))
            {
              if (single)
                {
                  send_to_pager_color( "&C&GOpening only similar helpfile.&C\n\r", ch);
                  do_help( ch, buf);
                  return;
                }

              pager_printf_color(ch, "&C&G   %s\n\r", pHelp->keyword);
              break;

            }

        }
    }
  return;
}


/*
 * Now this is cleaner
 */
void do_help( CHAR_DATA *ch, char *argument )
{
  HELP_DATA *pHelp;

  set_pager_color( AT_HELP, ch );

  if ( (pHelp = get_help( ch, argument )) == NULL )
    {
      //  Looks better printing out the missed argument before going to similar
      //  helpfiles. - Senir
      pager_printf_color( ch, "&C&wNo help on \'%s\' found.\n\r", argument );
      similar_help_files(ch, argument);
      return;
    }

  /* Make newbies do a help start. --Shaddai */
  if ( !IS_NPC(ch) && !str_cmp( argument, "start" ) )
    SET_BIT(ch->pcdata->flags, PCFLAG_HELPSTART);

  set_pager_color( AT_HELP, ch );

  if ( pHelp->level >= 0 && str_cmp( argument, "imotd" ) )
    {
      send_to_pager( pHelp->keyword, ch );
      send_to_pager( "\n\r", ch );
    }

  /*
   * Strip leading '.' to allow initial blanks.
   */
  if ( pHelp->text[0] == '.' )
    send_to_pager_color( pHelp->text+1, ch );
  else
    send_to_pager_color( pHelp->text  , ch );
  return;
}

void do_news( CHAR_DATA *ch, char *argument )
{
  set_pager_color( AT_NOTE, ch );
  do_help( ch, "news" );
}

extern char * help_greeting;	/* so we can edit the greeting online */

/*
 * Help editor							-Thoric
 */
void do_hedit( CHAR_DATA *ch, char *argument )
{
  HELP_DATA *pHelp;

  if ( !ch->desc )
    {
      send_to_char( "You have no descriptor.\n\r", ch );
      return;
    }

  switch( ch->substate )
    {
    default:
      break;
    case SUB_HELP_EDIT:
      if ( (pHelp = ch->dest_buf) == NULL )
        {
          bug( "hedit: sub_help_edit: NULL ch->dest_buf", 0 );
          stop_editing( ch );
          return;
        }
      if ( help_greeting == pHelp->text )
        help_greeting = NULL;
      STRFREE( pHelp->text );
      pHelp->text = copy_buffer( ch );
      if ( !help_greeting )
        help_greeting = pHelp->text;
      stop_editing( ch );
      return;
    }
  if ( (pHelp = get_help(ch, argument)) == NULL )     /* new help */
    {
      HELP_DATA *tHelp;
      char argnew[MAX_INPUT_LENGTH];
      int lev;
      bool new_help = TRUE;

      for ( tHelp=first_help; tHelp; tHelp = tHelp->next )
        if ( !str_cmp( argument, tHelp->keyword) )
          {
            pHelp = tHelp;
            new_help = FALSE;
            break;
          }
      if ( new_help )
        {
          if ( isdigit(argument[0]) )
            {
              lev = number_argument( argument, argnew );
              argument = argnew;
            }
          else
            lev = get_trust(ch);
          CREATE( pHelp, HELP_DATA, 1 );
          pHelp->keyword = STRALLOC( strupper(argument) );
          pHelp->text    = STRALLOC( "" );
          pHelp->level   = lev;
          add_help( pHelp );
        }
    }

  ch->substate = SUB_HELP_EDIT;
  ch->dest_buf = pHelp;
  start_editing( ch, pHelp->text );
}

/*
 * Stupid leading space muncher fix				-Thoric
 */
char *help_fix( char *text )
{
  char *fixed;

  if ( !text )
    return "";
  fixed = strip_cr(text)
            ;
  if ( fixed[0] == ' ' )
      fixed[0]
        = '.';
  return fixed;
}

void do_hset( CHAR_DATA *ch, char *argument )
{
  HELP_DATA *pHelp;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];

  smash_tilde( argument );
  argument = one_argument( argument, arg1 );
  if ( arg1[0] == '\0' )
    {
      send_to_char( "Syntax: hset <field> [value] [help page]\n\r",	ch );
      send_to_char( "\n\r",						ch );
      send_to_char( "Field being one of:\n\r",			ch );
      send_to_char( "  level keyword remove save\n\r",		ch );
      return;
    }

  if ( !str_cmp( arg1, "save" ) )
    {
      FILE *fpout;

      log_string_plus( "Saving help.are...", LOG_NORMAL, LEVEL_GREATER );

      rename( "help.are", "help.are.bak" );
      fclose( fpReserve );
      if ( ( fpout = fopen( "help.are", "w" ) ) == NULL )
        {
          bug( "hset save: fopen", 0 );
          perror( "help.are" );
          fpReserve = fopen( NULL_FILE, "r" );
          return;
        }

      fprintf( fpout, "#HELPS\n\n" );
      for ( pHelp = first_help; pHelp; pHelp = pHelp->next )
        fprintf( fpout, "%d %s~\n%s~\n\n",
                 pHelp->level, pHelp->keyword, help_fix(pHelp->text) );

      fprintf( fpout, "0 $~\n\n\n#$\n" );
      fclose( fpout );
      fpReserve = fopen( NULL_FILE, "r" );
      send_to_char( "Saved.\n\r", ch );
      return;
    }
  if ( str_cmp( arg1, "remove" ) )
    argument = one_argument( argument, arg2 );

  if ( (pHelp = get_help(ch, argument)) == NULL )
    {
      send_to_char( "Cannot find help on that subject.\n\r", ch );
      return;
    }
  if ( !str_cmp( arg1, "remove" ) )
    {
      UNLINK( pHelp, first_help, last_help, next, prev );
      STRFREE( pHelp->text );
      STRFREE( pHelp->keyword );
      DISPOSE( pHelp );
      send_to_char( "Removed.\n\r", ch );
      return;
    }
  if ( !str_cmp( arg1, "level" ) )
    {
      pHelp->level = atoi( arg2 );
      send_to_char( "Done.\n\r", ch );
      return;
    }
  if ( !str_cmp( arg1, "keyword" ) )
    {
      STRFREE( pHelp->keyword );
      pHelp->keyword = STRALLOC( strupper(arg2) );
      send_to_char( "Done.\n\r", ch );
      return;
    }

  do_hset( ch, "" );
}

void do_hl( CHAR_DATA *ch, char *argument )
{
  send_to_char( "If you want to use HLIST, spell it out.\n\r", ch );
  return;
}

/*
 * Show help topics in a level range				-Thoric
 * Idea suggested by Gorog
 * prefix keyword indexing added by Fireblade
 */
void do_hlist( CHAR_DATA *ch, char *argument )
{
  int min, max, minlimit, maxlimit, cnt;
  char arg[MAX_INPUT_LENGTH];
  HELP_DATA *help;
  bool minfound, maxfound;
  char *idx;

  maxlimit = get_trust(ch);
  minlimit = maxlimit >= LEVEL_GREATER ? -1 : 0;

  min = minlimit;
  max  = maxlimit;

  idx = NULL;
  minfound = FALSE;
  maxfound = FALSE;

  for ( argument = one_argument(argument, arg); arg[0] != '\0';
        argument = one_argument(argument, arg))
    {
      if( !isdigit(arg[0]) )
        {
          if ( idx )
            {
              set_char_color(AT_GREEN, ch);
              ch_printf(ch, "You may only use a single keyword to index the list.\n\r");
              return;
            }
          idx = STRALLOC(arg);
        }
      else
        {
          if ( !minfound )
            {
              min = URANGE(minlimit, atoi(arg), maxlimit);
              minfound = TRUE;
            }
          else
            if ( !maxfound )
              {
                max = URANGE(minlimit, atoi(arg), maxlimit);
                maxfound = TRUE;
              }
            else
              {
                set_char_color(AT_GREEN, ch);
                ch_printf(ch, "You may only use two level limits.\n\r");
                return;
              }
        }
    }

  if ( min > max )
    {
      int temp = min;

      min = max;
      max = temp;
    }

  set_pager_color( AT_GREEN, ch );
  pager_printf( ch, "Help Topics in level range %d to %d:\n\r\n\r", min, max );
  for ( cnt = 0, help = first_help; help; help = help->next )
    if ( help->level >= min && help->level <= max
         &&  (!idx || nifty_is_name_prefix(idx, help->keyword)) )
      {
        pager_printf( ch, "  %3d %s\n\r", help->level, help->keyword );
        ++cnt;
      }
  if ( cnt )
    pager_printf( ch, "\n\r%d pages found.\n\r", cnt );
  else
    send_to_char( "None found.\n\r", ch );

  if ( idx )
    STRFREE(idx);

  return;
}


/*
 * New do_who with WHO REQUEST, clan, race and homepage support.  -Thoric
 *
 * Latest version of do_who eliminates redundant code by using linked lists.
 * Shows imms separately, indicates guest and retired immortals.
 * Narn, Oct/96
 *
 * Who group by Altrag, Feb 28/97
 */
struct whogr_s
  {
    struct whogr_s *next;
    struct whogr_s *follower;
    struct whogr_s *l_follow;
    DESCRIPTOR_DATA *d;
    int indent;
  }
*first_whogr, *last_whogr;

struct whogr_s *find_whogr(DESCRIPTOR_DATA *d, struct whogr_s *first)
  {
    struct whogr_s *whogr, *whogr_t;

    for (whogr = first; whogr; whogr = whogr->next)
      if (whogr->d == d)
        return whogr;
      else if (whogr->follower && (whogr_t = find_whogr(d, whogr->follower)))
        return whogr_t;
    return NULL;
  }

void indent_whogr(CHAR_DATA *looker, struct whogr_s *whogr, int ilev)
{
  for ( ; whogr; whogr = whogr->next )
    {
      if (whogr->follower)
        {
          int nlev = ilev;
          CHAR_DATA *wch =
            (whogr->d->original ? whogr->d->original : whogr->d->character);

          if (can_see(looker, wch, TRUE) && !IS_IMMORTAL(wch))
            nlev += 3;
          indent_whogr(looker, whogr->follower, nlev);
        }
      whogr->indent = ilev;
    }
}

/* This a great big mess to backwards-structure the ->leader character
   fields */
void create_whogr(CHAR_DATA *looker)
{
  DESCRIPTOR_DATA *d;
  CHAR_DATA *wch;
  struct whogr_s *whogr, *whogr_t;
  int dc = 0, wc = 0;

  while ((whogr = first_whogr) != NULL)
    {
      first_whogr = whogr->next;
      DISPOSE(whogr);
    }
  first_whogr = last_whogr = NULL;
  /* Link in the ones without leaders first */
  for (d = last_descriptor; d; d = d->prev)
    {
      if (d->connected != CON_PLAYING && d->connected != CON_EDITING)
        continue;
      ++dc;
      wch = (d->original ? d->original : d->character);
      if (!wch->leader || wch->leader == wch || !wch->leader->desc ||
          IS_NPC(wch->leader) || IS_IMMORTAL(wch) || IS_IMMORTAL(wch->leader))
        {
          CREATE(whogr, struct whogr_s, 1);
          if (!last_whogr)
            first_whogr = last_whogr = whogr;
          else
            {
              last_whogr->next = whogr;
              last_whogr = whogr;
            }
          whogr->next = NULL;
          whogr->follower = whogr->l_follow = NULL;
          whogr->d = d;
          whogr->indent = 0;
          ++wc;
        }
    }
  /* Now for those who have leaders.. */
  while (wc < dc)
    for (d = last_descriptor; d; d = d->prev)
      {
        if (d->connected != CON_PLAYING && d->connected != CON_EDITING)
          continue;
        if (find_whogr(d, first_whogr))
          continue;
        wch = (d->original ? d->original : d->character);
        if (wch->leader && wch->leader != wch && wch->leader->desc &&
            !IS_NPC(wch->leader) && !IS_IMMORTAL(wch) &&
            !IS_IMMORTAL(wch->leader) &&
            (whogr_t = find_whogr(wch->leader->desc, first_whogr)))
          {
            CREATE(whogr, struct whogr_s, 1);
            if (!whogr_t->l_follow)
              whogr_t->follower = whogr_t->l_follow = whogr;
            else
              {
                whogr_t->l_follow->next = whogr;
                whogr_t->l_follow = whogr;
              }
            whogr->next = NULL;
            whogr->follower = whogr->l_follow = NULL;
            whogr->d = d;
            whogr->indent = 0;
            ++wc;
          }
      }
  /* Set up indentation levels */
  indent_whogr(looker, first_whogr, 0);

  /* And now to linear link them.. */
  for (whogr_t = NULL, whogr = first_whogr; whogr; )
    if (whogr->l_follow)
      {
        whogr->l_follow->next = whogr;
        whogr->l_follow = NULL;
        if (whogr_t)
          whogr_t->next = whogr = whogr->follower;
        else
          first_whogr = whogr = whogr->follower;
      }
    else
      {
        whogr_t = whogr;
        whogr = whogr->next;
      }
}



void do_who( CHAR_DATA *ch, char *argument )
{
  char buf[MAX_STRING_LENGTH];
  char clan_name[MAX_INPUT_LENGTH];
  char council_name[MAX_INPUT_LENGTH];
  char invis_str[MAX_INPUT_LENGTH];
  char char_name[MAX_INPUT_LENGTH];
  char *extra_title;
  char class_text[MAX_INPUT_LENGTH];
  char const *sex;
  char const *race;
  struct whogr_s *whogr, *whogr_p;
  DESCRIPTOR_DATA *d;
  int iClass, iRace;
  int iLevelLower;
  int iLevelUpper;
  int nNumber;
  int nMatch;
  bool rgfClass[MAX_CLASS];
  bool rgfRace[MAX_RACE];
  bool fClassRestrict;
  bool fRaceRestrict;
  bool fImmortalOnly;
  bool fLeader;
  bool fPkill;
  bool fShowHomepage;
  bool fClanMatch; /* SB who clan (order),who guild, and who council */
  bool fCouncilMatch;
  bool fDeityMatch;
  bool fGroup;
  CLAN_DATA *pClan = NULL;
  COUNCIL_DATA *pCouncil = NULL;
  DEITY_DATA *pDeity = NULL;
  FILE *whoout = NULL;

  /*
  #define WT_IMM    0;
  #define WT_MORTAL 1;
  #define WT_DEADLY 2;
  */

  WHO_DATA *cur_who = NULL;
  WHO_DATA *next_who = NULL;
  WHO_DATA *first_mortal = NULL;
  WHO_DATA *first_imm = NULL;
  WHO_DATA *first_deadly  = NULL;
  WHO_DATA *first_grouped = NULL;
  WHO_DATA *first_groupwho = NULL;


  /*
   * Set default arguments.
   */
  iLevelLower    = 0;
  iLevelUpper    = MAX_LEVEL;
  fClassRestrict = FALSE;
  fRaceRestrict  = FALSE;
  fImmortalOnly  = FALSE;
  fPkill         = FALSE;
  fShowHomepage  = FALSE;
  fClanMatch	   = FALSE; /* SB who clan (order), who guild, who council */
  fCouncilMatch  = FALSE;
  fDeityMatch    = FALSE;
  fGroup	   = FALSE; /* Alty who group */
  fLeader	   = FALSE;
  for ( iClass = 0; iClass < MAX_CLASS; iClass++ )
    rgfClass[iClass] = FALSE;
  for ( iRace = 0; iRace < MAX_RACE; iRace++ )
    rgfRace[iRace] = FALSE;

#ifdef REQWHOARG
  /*
   * The who command must have at least one argument because we often
   * have up to 500 players on. Too much spam if a player accidentally
   * types "who" with no arguments.           --Gorog
   */
  if ( ch && argument[0] == '\0' )
    {
      send_to_pager_color(
        "\n\r&GYou must specify at least one argument.\n\rUse 'who 1' to view the entire who list.\n\r", ch);
      return;
    }
#endif

  /*
   * Parse arguments.
   */
  nNumber = 0;
  for ( ;; )
    {
      char arg[MAX_STRING_LENGTH];

      argument = one_argument( argument, arg );
      if ( arg[0] == '\0' )
        break;

      if ( is_number( arg ) )
        {
          switch ( ++nNumber )
            {
            case 1:
              iLevelLower = atoi( arg );
              break;
            case 2:
              iLevelUpper = atoi( arg );
              break;
            default:
              send_to_char( "Only two level numbers allowed.\n\r", ch );
              return;
            }
        }
      else
        {
          if ( strlen(arg) < 3 )
            {
              send_to_char( "Arguments must be longer than that.\n\r", ch );
              return;
            }

          /*
           * Look for classes to turn on.
           */
          if ( !str_cmp( arg, "deadly" ) || !str_cmp( arg, "pkill" ) )
            fPkill = TRUE;
          else
            if ( !str_cmp( arg, "imm" ) || !str_cmp( arg, "gods" ) )
              fImmortalOnly = TRUE;
            else
              if ( !str_cmp( arg, "leader" ) )
                fLeader = TRUE;
              else
                if ( !str_cmp( arg, "www" ) )
                  fShowHomepage = TRUE;
                else
                  if ( !str_cmp( arg, "group" ) && ch )
                    fGroup = TRUE;
                  else		 /* SB who clan (order), guild, council */
                    if  ( ( pClan = get_clan (arg) ) )
                      fClanMatch = TRUE;
                    else
                      if ( ( pCouncil = get_council (arg) ) )
                        fCouncilMatch = TRUE;
                      else
                        if ( ( pDeity = get_deity (arg) ) )
                          fDeityMatch = TRUE;
                        else
                          {
                            for ( iClass = 0; iClass < MAX_CLASS; iClass++ )
                              {
                                if ( !str_cmp( arg, class_table[iClass]->who_name ) )
                                  {
                                    rgfClass[iClass] = TRUE;
                                    break;
                                  }
                              }
                            if ( iClass != MAX_CLASS )
                              fClassRestrict = TRUE;

                            for ( iRace = 0; iRace < MAX_RACE; iRace++ )
                              {
                                if ( !str_cmp( arg, race_table[iRace]->race_name ) )
                                  {
                                    rgfRace[iRace] = TRUE;
                                    break;
                                  }
                              }
                            if ( iRace != MAX_RACE )
                              fRaceRestrict = TRUE;

                            if ( iClass == MAX_CLASS && iRace == MAX_RACE
                                 && fClanMatch == FALSE
                                 && fCouncilMatch == FALSE
                                 && fDeityMatch == FALSE )
                              {
                                send_to_char( "That's not a class, race, order, guild,"
                                              " council or deity.\n\r", ch );
                                return;
                              }
                          }
        }
    }

  /*
   * Now find matching chars.
   */
  nMatch = 0;
  buf[0] = '\0';
  if ( ch )
    set_pager_color( AT_GREEN, ch );
  else
    {
      if ( fShowHomepage )
        whoout = fopen( WEBWHO_FILE, "w" );
      else
        whoout = fopen( WHO_FILE, "w" );
      if ( !whoout )
        {
          bug( "do_who: cannot open who file!" );
          return;
        }
    }

  /* start from last to first to get it in the proper order */
  if (fGroup)
    {
      create_whogr(ch);
      whogr = first_whogr;
      d = whogr->d;
    }
  else
    {
      whogr = NULL;
      d = last_descriptor;
    }
  whogr_p = NULL;
  for ( ; d; whogr_p = whogr, whogr = (fGroup ? whogr->next : NULL),
        d = (fGroup ? (whogr ? whogr->d : NULL) : d->prev))
    {
      CHAR_DATA *wch;
      char const *class;

      if ( (d->connected != CON_PLAYING && d->connected != CON_EDITING)
           ||   !can_see( ch, d->character, TRUE ) || d->original)
        continue;
      wch   = d->original ? d->original : d->character;
      if ( wch->level < iLevelLower
           ||   wch->level > iLevelUpper
           || ( fPkill && !CAN_PKILL( wch ) )
           || ( fImmortalOnly  && wch->level < LEVEL_IMMORTAL )
           || ( fClassRestrict && !rgfClass[wch->class] )
           || ( fRaceRestrict && !rgfRace[wch->race] )
           || ( fClanMatch && ( pClan != wch->pcdata->clan ))  /* SB */
           || ( fCouncilMatch && ( pCouncil != wch->pcdata->council )) /* SB */
           || ( fDeityMatch && ( pDeity != wch->pcdata->deity )) )
        continue;
      if ( fLeader && !(wch->pcdata->council &&
                        ((wch->pcdata->council->head2 &&
                          !str_cmp(wch->pcdata->council->head2, wch->name)) ||
                         (wch->pcdata->council->head &&
                          !str_cmp(wch->pcdata->council->head, wch->name)))) &&
           !(wch->pcdata->clan && ((wch->pcdata->clan->deity &&
                                    !str_cmp(wch->pcdata->clan->deity,wch->name) )
                                   || (wch->pcdata->clan->leader
                                       && !str_cmp(wch->pcdata->clan->leader, wch->name ) )
                                   || (wch->pcdata->clan->number1
                                       && !str_cmp(wch->pcdata->clan->number1, wch->name ) )
                                   || (wch->pcdata->clan->number2
                                       && !str_cmp(wch->pcdata->clan->number2, wch->name )))))
        continue;

      if (fGroup && !wch->leader &&
          !IS_SET(wch->pcdata->flags, PCFLAG_GROUPWHO) &&
          (!whogr_p || !whogr_p->indent))
        continue;

      nMatch++;

      if ( fShowHomepage
           &&   wch->pcdata->homepage
           &&   wch->pcdata->homepage[0] != '\0' )
        sprintf( char_name, "<A HREF=\"%s\">%s</A>",
                 show_tilde( wch->pcdata->homepage ), wch->name );
      else
        strcpy( char_name, wch->name );

      sprintf( class_text, "%s%2d ", NOT_AUTHED(wch) ? "N" : " ", wch->level/*, class_table[wch->class]->who_name */);
      class = class_text;



      switch ( wch->sex )
        {
        case SEX_MALE:
          sex = "M";
          break;

        case SEX_FEMALE:
          sex = "F";
          break;

        case SEX_NEUTRAL:
          sex = "N";
          break;
        }

      switch ( wch->level )
        {
        default:
          break;
        case MAX_LEVEL -  0:
          class = " IMP";
          break;
        case MAX_LEVEL -  1:
          class = " Imm";
          break;
        case MAX_LEVEL -  2:
          class = " Imm";
          break;
        case MAX_LEVEL -  3:
          class = " Imm";
          break;
        case MAX_LEVEL -  4:
          class = " Imm";
          break;
        case MAX_LEVEL -  5:
          class = " Imm";
          break;
        case MAX_LEVEL -  6:
          class = " Imm";
          break;
        case MAX_LEVEL -  7:
          class = " Imm";
          break;
        case MAX_LEVEL -  8:
          class = " Imm";
          break;
        case MAX_LEVEL -  9:
          class = " Imm";
          break;
        case MAX_LEVEL - 10:
          class = " Imm";
          break;
        case MAX_LEVEL - 11:
          class = " Imm";
          break;
        case MAX_LEVEL - 12:
          class = " Imm";
          break;
        case MAX_LEVEL - 13:
          class = " Imm";
          break;
        case MAX_LEVEL - 14:
          class = " Imm";
          break;
        case MAX_LEVEL - 15:
          class = " AV";
          break;
        }

      switch ( wch->race )
        {
        case 0:
          race = "Hum";
          break;
	case 1:
          race = "Elf";
          break;
        case 2:
          race = "Dwa";
          break;
        case 3:
          race = "Hal";
          break;
        case 4:
          race = "Pix";
          break;
        case 5:
          race = "Min";
          break;
        case 6:
          race = "Orc";
          break;
        case 7:
          race = "Ogr";
          break;
        case 8:
          race = "Tro";
          break;
        case 9:
          race = "Gia";
          break;
        case 10:
          race = "Git";
          break;
        case 11:
          race = "Dro";
          break;
        case 12:
          race = "Dra";
          break;
        case 13:
          race = "liz";
          break;
        case 14:
          race = "Gno";
          break;
        }

      if ( !str_cmp( wch->name, sysdata.guild_overseer ) )
        extra_title = " [Overseer of Guilds]";
      else if ( !str_cmp( wch->name, sysdata.guild_advisor ) )
        extra_title = " [Advisor to Guilds]";
      else
        extra_title = "";

      if ( IS_RETIRED( wch ) )
        class = "Retired";
      else if ( IS_GUEST( wch ) )
        class = "Guest";
      else if ( wch->pcdata->clan
                &&  !str_cmp( wch->name, wch->pcdata->clan->leader )
                &&   wch->pcdata->clan->leadrank[0] != '\0' )
        class = wch->pcdata->clan->leadrank;
      else if ( wch->pcdata->clan
                &&  !str_cmp( wch->name, wch->pcdata->clan->number1 )
                &&   wch->pcdata->clan->onerank[0] != '\0' )
        class = wch->pcdata->clan->onerank;
      else if ( wch->pcdata->clan
                &&  !str_cmp( wch->name, wch->pcdata->clan->number2 )
                &&   wch->pcdata->clan->tworank[0] != '\0' )
        class = wch->pcdata->clan->tworank;
      else if ( wch->pcdata->rank && wch->pcdata->rank[0] != '\0' )
        class = wch->pcdata->rank;

      if ( wch->pcdata->clan )
        {
          CLAN_DATA *pclan = wch->pcdata->clan;
          if ( pclan->clan_type == CLAN_GUILD )
            strcpy( clan_name, " <" );
          else
            strcpy( clan_name, " (" );

          if ( pclan->clan_type == CLAN_ORDER )
            {
              if ( !str_cmp( wch->name, pclan->deity ) )
                strcat( clan_name, "Deity, Order of " );
              else
                if ( !str_cmp( wch->name, pclan->leader ) )
                  strcat( clan_name, "Leader, Order of " );
                else
                  if ( !str_cmp( wch->name, pclan->number1 ) )
                    strcat( clan_name, "Number One, Order of " );
                  else
                    if ( !str_cmp( wch->name, pclan->number2 ) )
                      strcat( clan_name, "Number Two, Order of " );
                    else
                      strcat( clan_name, "Order of " );
            }
          else
            if ( pclan->clan_type == CLAN_GUILD )
              {
                if ( !str_cmp( wch->name, pclan->leader ) )
                  strcat( clan_name, "Leader, " );
                if ( !str_cmp( wch->name, pclan->number1 ) )
                  strcat( clan_name, "First, " );
                if ( !str_cmp( wch->name, pclan->number2 ) )
                  strcat( clan_name, "Second, " );
              }
            else
              {
                if ( !str_cmp( wch->name, pclan->deity ) )
                  strcat( clan_name, "Deity of " );
                else
                  if ( !str_cmp( wch->name, pclan->leader ) )
                    strcat( clan_name, "Leader of " );
                  else
                    if ( !str_cmp( wch->name, pclan->number1 ) )
                      strcat( clan_name, "Number One " );
                    else
                      if ( !str_cmp( wch->name, pclan->number2 ) )
                        strcat( clan_name, "Number Two " );
              }
          strcat( clan_name, pclan->name );
          if ( pclan->clan_type == CLAN_GUILD )
            strcat( clan_name, ">" );
          else
            strcat( clan_name, ")" );
        }
      else
        clan_name[0] = '\0';

      if ( wch->pcdata->council )
        {
          strcpy( council_name, " [" );
          if (  wch->pcdata->council->head2 == NULL )
            {
              if (!str_cmp (wch->name, wch->pcdata->council->head))
                strcat (council_name, "Head of ");
            }
          else
            {
              if (!str_cmp (wch->name, wch->pcdata->council->head)
                  || !str_cmp ( wch->name, wch->pcdata->council->head2) )
                strcat (council_name, "Co-Head of ");
            }
          strcat( council_name, wch->pcdata->council_name );
          strcat( council_name, "]" );
        }
      else
        council_name[0] = '\0';

      if ( xIS_SET(wch->act, PLR_WIZINVIS) )
        sprintf( invis_str, "(%d) ", wch->pcdata->wizinvis );
      else
        invis_str[0] = '\0';


      sprintf( buf, "%*s%-3s &W%-10s&D%-20s &B%-3s &P%-1s &Y%-10s&D %d &R%-3s%s%s%s%s%s%s&D\n\r",
               (fGroup ? whogr->indent : 0), "",
               class, //level
               char_name,
               wch->pcdata->title,
               race,
               sex,
               wch->in_room->area->name,
               wch->remorts,
               
               IS_SET(wch->pcdata->flags, PCFLAG_HELPER) ? "&R[&WHELPER&R]&D " : "",
	       (wch->desc && wch->desc->connected) ? "[W] " : "",
               xIS_SET(wch->act, PLR_AFK) ? "[AFK] " : "",
               xIS_SET(wch->act, PLR_ATTACKER) ? "(A) " : "",
               xIS_SET(wch->act, PLR_KILLER) ? "(K) " : "",
               xIS_SET(wch->act, PLR_THIEF)  ? "(T) "  : "",
	       invis_str); //robert


      /*
       * This is where the old code would display the found player to the ch.
       * What we do instead is put the found data into a linked list
       */

      /* First make the structure. */
      CREATE( cur_who, WHO_DATA, 1 );
      cur_who->text = str_dup( buf );
      if ( wch->level > 50 && IS_IMMORTAL( wch ) )
        cur_who->type = WT_IMM;
      else if ( fGroup )
        if ( wch->leader || (whogr_p && whogr_p->indent) )
          cur_who->type = WT_GROUPED;
        else
          cur_who->type = WT_GROUPWHO;
      else if ( CAN_PKILL( wch ) )
        cur_who->type = WT_DEADLY;
      else
        cur_who->type = WT_MORTAL;

      /* Then put it into the appropriate list. */
      switch ( cur_who->type )
        {
        case WT_MORTAL:
          cur_who->next = first_mortal;
          first_mortal = cur_who;
          break;
        case WT_DEADLY:
          cur_who->next = first_deadly;
          first_deadly = cur_who;
          break;
        case WT_GROUPED:
          cur_who->next = first_grouped;
          first_grouped = cur_who;
          break;
        case WT_GROUPWHO:
          cur_who->next = first_groupwho;
          first_groupwho = cur_who;
          break;
        case WT_IMM:
          cur_who->next = first_imm;
          first_imm = cur_who;
          break;
        }

    }


  /* Ok, now we have three separate linked lists and what remains is to
   * display the information and clean up.
   */
  /*
   * Two extras now for grouped and groupwho (wanting group). -- Alty
   */



  send_to_pager( "\n\r[Lvl][Name]----[Title]-----------[Race][Sex][Loc][Rem]\n\r", ch );

  for ( cur_who = first_mortal; cur_who; cur_who = next_who )
    {
      if ( !ch )
        fprintf( whoout, "%s", cur_who->text );
      else
        send_to_pager( cur_who->text, ch );
      next_who = cur_who->next;
      DISPOSE( cur_who->text );
      DISPOSE( cur_who );
    }

  if ( first_deadly )
    {
      if ( !ch )
        fprintf( whoout, "%s", "\n\r-------------------------------[ DEADLY CHARACTERS ]-------------------------\n\r\n\r" );
      else
        send_to_pager( "\n\r-------------------------------[ DEADLY CHARACTERS ]--------------------------\n\r\n\r", ch );
    }

  for ( cur_who = first_deadly; cur_who; cur_who = next_who )
    {
      if ( !ch )
        fprintf( whoout, "%s", cur_who->text );
      else
        send_to_pager( cur_who->text, ch );
      next_who = cur_who->next;
      DISPOSE( cur_who->text );
      DISPOSE( cur_who );
    }

  if (first_grouped)
    {
      /*      if ( !ch )
              fprintf( whoout, "%s", "\n\r-----------------------------[ GROUPED CHARACTERS ]---------------------------\n\r\n\r" );
            else*/
      send_to_pager( "\n\r-----------------------------[ GROUPED CHARACTERS ]---------------------------\n\r\n\r", ch );
    }
  for ( cur_who = first_grouped; cur_who; cur_who = next_who )
    {
      /*      if ( !ch )
              fprintf( whoout, cur_who->text );
            else*/
      send_to_pager( cur_who->text, ch );
      next_who = cur_who->next;
      DISPOSE( cur_who->text );
      DISPOSE( cur_who );
    }

  if (first_groupwho)
    {
      if ( !ch )
        fprintf( whoout, "%s", "\n\r-------------------------------[ WANTING GROUP ]------------------------------\n\r\n\r" );
      else
        send_to_pager( "\n\r-------------------------------[ WANTING GROUP ]------------------------------\n\r\n\r", ch );
    }
  for ( cur_who = first_groupwho; cur_who; cur_who = next_who )
    {
      if ( !ch )
        fprintf( whoout, "%s", cur_who->text );
      else
        send_to_pager( cur_who->text, ch );
      next_who = cur_who->next;
      DISPOSE( cur_who->text );
      DISPOSE( cur_who );
    }

  if ( first_imm )
    {
      if ( !ch )
        fprintf( whoout, "%s", "\n\r-----------------------------------[ IMMORTALS ]-----------------------------\n\r\n\r" );
      else
        send_to_pager( "\n\r-----------------------------------[ IMMORTALS ]------------------------------\n\r\n\r", ch );
    }

  for ( cur_who = first_imm; cur_who; cur_who = next_who )
    {
      if ( !ch )
        fprintf( whoout, "%s", cur_who->text );
      else
        send_to_pager( cur_who->text, ch );
      next_who = cur_who->next;
      DISPOSE( cur_who->text );
      DISPOSE( cur_who );
    }

  if ( !ch )
    {
      fprintf( whoout, "%d player%s.\n\r", nMatch, nMatch == 1 ? "" : "s" );
      fclose( whoout );
      return;
    }

  set_char_color( AT_YELLOW, ch );
  ch_printf( ch, "%d player%s.\n\r", nMatch, nMatch == 1 ? "" : "s" );
  return;
}

void do_compare( CHAR_DATA *ch, char *argument )
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  OBJ_DATA *obj1;
  OBJ_DATA *obj2;
  int value1;
  int value2;
  char *msg;

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );
  if ( arg1[0] == '\0' )
    {
      send_to_char( "Compare what to what?\n\r", ch );
      return;
    }

  if ( ( obj1 = get_obj_carry( ch, arg1 ) ) == NULL )
    {
      send_to_char( "You do not have that item.\n\r", ch );
      return;
    }

  if ( arg2[0] == '\0' )
    {
      for ( obj2 = ch->first_carrying; obj2; obj2 = obj2->next_content )
        {
          if ( obj2->wear_loc != WEAR_NONE
               &&   can_see_obj( ch, obj2 )
               &&   obj1->item_type == obj2->item_type
               && ( obj1->wear_flags & obj2->wear_flags & ~ITEM_TAKE) != 0 )
            break;
        }

      if ( !obj2 )
        {
          send_to_char( "You aren't wearing anything comparable.\n\r", ch );
          return;
        }
    }
  else
    {
      if ( ( obj2 = get_obj_carry( ch, arg2 ) ) == NULL )
        {
          send_to_char( "You do not have that item.\n\r", ch );
          return;
        }
    }

  msg		= NULL;
  value1	= 0;
  value2	= 0;

  if ( obj1 == obj2 )
    {
      msg = "You compare $p to itself.  It looks about the same.";
    }
  else if ( obj1->item_type != obj2->item_type )
    {
      msg = "You can't compare $p and $P.";
    }
  else
    {
      switch ( obj1->item_type )
        {
        default:
          msg = "You can't compare $p and $P.";
          break;

        case ITEM_ARMOR:
          value1 = obj1->value[0];
          value2 = obj2->value[0];
          break;

        case ITEM_WEAPON:
          value1 = obj1->value[1] + obj1->value[2];
          value2 = obj2->value[1] + obj2->value[2];
          break;
        }
    }

  if ( !msg )
    {
      if ( value1 == value2 )
        msg = "$p and $P look about the same.";
      else if ( value1  > value2 )
        msg = "$p looks better than $P.";
      else
        msg = "$p looks worse than $P.";
    }

  act( AT_PLAIN, msg, ch, obj1, obj2, TO_CHAR );
  return;
}



void do_where( CHAR_DATA *ch, char *argument )
{
  char arg[MAX_INPUT_LENGTH];
  CHAR_DATA *victim;
  DESCRIPTOR_DATA *d;
  bool found;

  one_argument( argument, arg );

  if ( arg[0]!='\0'
       &&   (victim=get_char_world(ch, arg)) && !IS_NPC(victim)
       &&   IS_SET(victim->pcdata->flags, PCFLAG_DND)
       &&   get_trust(ch) < get_trust(victim) )
    {
      act( AT_PLAIN, "You didn't find any $T.", ch, NULL, arg, TO_CHAR );
      return;
    }

  set_pager_color( AT_PERSON, ch );
  if ( arg[0] == '\0' )
    {
      pager_printf( ch, "\n\rPlayers near you in %s:\n\r", ch->in_room->area->name );
      found = FALSE;
      for ( d = first_descriptor; d; d = d->next )
        if ( (d->connected == CON_PLAYING || d->connected == CON_EDITING )
             && ( victim = d->character ) != NULL
             &&   !IS_NPC(victim)
             &&   victim->in_room
             &&   victim->in_room->area == ch->in_room->area
             &&   can_see( ch, victim, TRUE )
             && ( get_trust(ch) >= get_trust(victim)
                  ||   !IS_SET(victim->pcdata->flags, PCFLAG_DND) )
           ) /* if victim has the DND flag ch must outrank them */

          {
            found = TRUE;
            /*		if ( CAN_PKILL( victim ) )
            		  set_pager_color( AT_PURPLE, ch );
            		else
            		  set_pager_color( AT_PERSON, ch );
            */
            pager_printf_color( ch, "&P%-13s  ", victim->name );
            if ( IS_IMMORTAL( victim ) && victim->level > 50 )
              send_to_pager_color( "&P(&WImmortal&P)\t", ch );
            else if ( CAN_PKILL( victim ) && victim->pcdata->clan
                      && victim->pcdata->clan->clan_type != CLAN_ORDER
                      && victim->pcdata->clan->clan_type != CLAN_GUILD )
              pager_printf_color( ch, "%-18s\t", victim->pcdata->clan->badge );
            else if ( CAN_PKILL( victim ) )
              send_to_pager_color( "(&wUnclanned&P)\t", ch );
            else
              send_to_pager( "\t\t\t", ch );
            pager_printf_color( ch, "&P%s\n\r", victim->in_room->name );
          }
      if ( !found )
        send_to_char( "None\n\r", ch );
    }
  else
    {
      found = FALSE;
      for ( victim = first_char; victim; victim = victim->next )
        if ( victim->in_room
             &&   victim->in_room->area == ch->in_room->area
             &&   !IS_AFFECTED(victim, AFF_HIDE)
             &&   !IS_AFFECTED(victim, AFF_SNEAK)
             &&   can_see( ch, victim, TRUE )
             &&   is_name( arg, victim->name ) )
          {
            found = TRUE;
            pager_printf( ch, "%-28s %s\n\r",
                          PERS(victim, ch, TRUE), victim->in_room->name );
            break;
          }
      if ( !found )
        act( AT_PLAIN, "You didn't find any $T.", ch, NULL, arg, TO_CHAR );
    }

  return;
}




void do_consider( CHAR_DATA *ch, char *argument )
{
  char arg[MAX_INPUT_LENGTH];
  CHAR_DATA *victim;
  char *msg;
  int diff;

  one_argument( argument, arg );

  if ( arg[0] == '\0' )
    {
      send_to_char( "Consider killing whom?\n\r", ch );
      return;
    }

  if ( ( victim = get_char_room( ch, arg ) ) == NULL )
    {
      send_to_char( "They're not here.\n\r", ch );
      return;
    }
  if ( victim == ch )
    {
      send_to_char( "You decide you're pretty sure you could take yourself in a fight.\n\r", ch );
      return;
    }
  diff = victim->level - ch->level;

  if ( diff <= -10 )
    msg = "You are far more experienced than $N.";
  else if ( diff <=  -5 )
    msg = "$N is not nearly as experienced as you.";
  else if ( diff <=  -2 )
    msg = "You are more experienced than $N.";
  else if ( diff <=   1 )
    msg = "You are just about as experienced as $N.";
  else if ( diff <=   4 )
    msg = "You are not nearly as experienced as $N.";
  else if ( diff <=   9 )
    msg = "$N is far more experienced than you!";
  else
    msg = "$N would make a great teacher for you!";
  act( AT_CONSIDER, msg, ch, NULL, victim, TO_CHAR );

  diff = (int) (victim->max_hit - ch->max_hit) / 6;

  if ( diff <= -200)
    msg = "$N looks like a feather!";
  else if ( diff <= -150)
    msg = "You could kill $N with your hands tied!";
  else if ( diff <= -100)
    msg = "Hey! Where'd $N go?";
  else if ( diff <=  -50)
    msg = "$N is a wimp.";
  else if ( diff <=    0)
    msg = "$N looks weaker than you.";
  else if ( diff <=   50)
    msg = "$N looks about as strong as you.";
  else if ( diff <=  100)
    msg = "It would take a bit of luck...";
  else if ( diff <=  150)
    msg = "It would take a lot of luck, and equipment!";
  else if ( diff <=  200)
    msg = "Why don't you dig a grave for yourself first?";
  else
    msg = "$N is built like a TANK!";
  act( AT_CONSIDER, msg, ch, NULL, victim, TO_CHAR );

  return;
}



/*
 * Place any skill types you don't want them to be able to practice
 * normally in this list.  Separate each with a space.
 * (Uses an is_name check). -- Altrag
 */
#define CANT_PRAC "Tongue"

void do_practice( CHAR_DATA *ch, char *argument )
{
  char buf[MAX_STRING_LENGTH];
  int sn;

  if ( IS_NPC(ch) )
    return;

  if ( argument[0] == '\0' )
    {
      int	col;
      sh_int	lasttype, cnt;

      col = cnt = 0;
      lasttype = SKILL_SPELL;
      set_pager_color( AT_MAGIC, ch );
      for ( sn = 0; sn < top_sn; sn++ )
        {
          if ( !skill_table[sn]->name )
            break;

          if ( strcmp(skill_table[sn]->name, "reserved") == 0
               && ( IS_IMMORTAL(ch) || CAN_CAST(ch) ) )
            {
              if ( col % 3 != 0 )
                send_to_pager( "\n\r", ch );
              //   set_pager_color( AT_DGREY, ch );
              send_to_pager_color(
                " &Y----------------------------------[&CSpells&Y]----------------------------------&D\n\r", ch);
              col = 0;
            }
          if ( skill_table[sn]->type != lasttype )
            {
              if ( !cnt )
                send_to_pager( "                                   (none)\n\r", ch );
              else
                if ( col % 3 != 0 )
                  send_to_pager( "&D\n\r", ch );
              //       set_pager_color( AT_CYAN, ch );
              pager_printf_color( ch,
                                  " &Y----------------------------------&C%ss&Y----------------------------------\n\r",
                                  skill_tname[skill_table[sn]->type]);
              col = cnt = 0;
            }
          lasttype = skill_table[sn]->type;

          if (!IS_IMMORTAL(ch)
              && ( skill_table[sn]->guild != CLASS_NONE
                   && ( !IS_GUILDED(ch)
                        || (ch->pcdata->clan->class != skill_table[sn]->guild) ) ) )
            continue;



          if ( ch->level < skill_table[sn]->skill_level[ch->class]
               || (!IS_IMMORTAL(ch) && skill_table[sn]->skill_level[ch->class] == 0) )
            continue;

          if ( ch->pcdata->learned[sn] <= 0   &&   SPELL_FLAG(skill_table[sn], SF_SECRETSKILL) )
            continue;

          ++cnt;
          //    set_pager_color( AT_ORANGE, ch );
          pager_printf( ch, "&c%20.20s", skill_table[sn]->name );
          if ( ch->pcdata->learned[sn] > 0 )
            set_pager_color( AT_YELLOW, ch );
          pager_printf( ch, "&Y %3d%%&D ", ch->pcdata->learned[sn] );
          if ( ++col % 3 == 0 )
            send_to_pager( "\n\r", ch );
        }

      if ( col % 3 != 0 )
        send_to_pager( "&D\n\r", ch );
      set_pager_color( AT_GREEN, ch );
      pager_printf( ch, "You have %d practice sessions left.\n\r",
                    ch->practice );
    }
  else
    {
      CHAR_DATA *mob;
      int adept;
      bool can_prac = TRUE;

      if ( !IS_AWAKE(ch) )
        {
          send_to_char( "In your dreams, or what?\n\r", ch );
          return;
        }

      for ( mob = ch->in_room->first_person; mob; mob = mob->next_in_room )
        if ( IS_NPC(mob) && xIS_SET(mob->act, ACT_PRACTICE) )
          break;

      if ( !mob )
        {
          send_to_char( "You can't do that here.\n\r", ch );
          return;
        }

      if ( ch->practice <= 0 )
        {
          act( AT_TELL, "$n tells you 'You must earn some more practice sessions.'",
               mob, NULL, ch, TO_VICT );
          return;
        }

      sn = skill_lookup( argument );



      if ( ch->pcdata->learned[sn] <= 0   &&   SPELL_FLAG(skill_table[sn], SF_SECRETSKILL) )
        {
          send_to_char("$n tells you 'You cannot practice that untill someone teaches you...'", ch);
          return;
        }


      if ( can_prac && ( ( sn == -1 ) || ( !IS_NPC(ch) &&  ch->level < skill_table[sn]->skill_level[ch->class])))
        {
          act( AT_TELL, "$n tells you 'You're not ready to learn that yet...'", mob, NULL, ch, TO_VICT );
          return;
        }

      if ( is_name( skill_tname[skill_table[sn]->type], CANT_PRAC ) )
        {
          act( AT_TELL, "$n tells you 'I do not know how to teach that.'",
               mob, NULL, ch, TO_VICT );
          return;
        }

      /*
       * Skill requires a special teacher
       */
      if ( skill_table[sn]->teachers && skill_table[sn]->teachers[0] != '\0' )
        {
          sprintf( buf, "%d", mob->pIndexData->vnum );
          if ( !is_name( buf, skill_table[sn]->teachers ) )
            {
              act( AT_TELL, "$n tells you, 'I know not know how to teach that.'",
                   mob, NULL, ch, TO_VICT );
              return;
            }
        }

      /*
       * Guild checks - right now, cant practice guild skills - done on 
       * induct/outcast
       */
      /*
      	if ( !IS_NPC(ch) && !IS_GUILDED(ch)
      	&&    skill_table[sn]->guild != CLASS_NONE)
      	{
      	    act( AT_TELL, "$n tells you 'Only guild members can use that..'"
      		mob, NULL, ch, TO_VICT );
      	    return;
      	}
       
      	if ( !IS_NPC(ch) && skill_table[sn]->guild != CLASS_NONE 
      	     && ch->pcdata->clan->class != skill_table[sn]->guild )
      	{
      	    act( AT_TELL, "$n tells you 'That can not be used by your guild.'"
      		mob, NULL, ch, TO_VICT );
      	    return;
      	}
      */
      if ( !IS_NPC(ch) && skill_table[sn]->guild != CLASS_NONE)
        {
          act( AT_TELL, "$n tells you 'That is only for members of guilds...'",
               mob, NULL, ch, TO_VICT );
          return;
        }

      /*
       * Disabled for now
      if ( mob->level < skill_table[sn]->skill_level[ch->class]
      ||   mob->level < skill_table[sn]->skill_level[mob->class] )
      {
          act( AT_TELL, "$n tells you 'You must seek another to teach you that...'",
      	mob, NULL, ch, TO_VICT );
          return;
      }
       */

      adept = class_table[ch->class]->skill_adept * 0.55;

      if ( ch->pcdata->learned[sn] >= adept )
        {
          act( AT_TELL, "$n, You'll have to practice it on your own now...",
               ch, NULL, ch, TO_CHAR );
          sprintf( buf, "$n tells you, 'I've taught you everything I can about %s.'",
                   skill_table[sn]->name );
          act( AT_TELL, buf, mob, NULL, ch, TO_VICT );

        }
      else
        {
          ch->practice--;
          ch->pcdata->learned[sn] += int_app[get_curr_int(ch)].learn;
          act( AT_ACTION, "You practice $T.",
               ch, NULL, skill_table[sn]->name, TO_CHAR );
          act( AT_ACTION, "$n practices $T.",
               ch, NULL, skill_table[sn]->name, TO_ROOM );
          if ( ch->pcdata->learned[sn] >= adept )
            {
              ch->pcdata->learned[sn] = adept;
              act( AT_TELL,
                   "$n tells you. 'You'll have to practice it on your own now...'",
                   mob, NULL, ch, TO_VICT );
            }
        }
    }
  return;
}


void do_wimpy( CHAR_DATA *ch, char *argument )
{
  char arg[MAX_INPUT_LENGTH];
  int wimpy;

  set_char_color( AT_YELLOW, ch );
  one_argument( argument, arg );
  if ( !str_cmp( arg, "max" ) )
    {
      if ( IS_PKILL( ch ) )
        wimpy = (int) ch->max_hit / 2.25;
      else
        wimpy = (int) ch->max_hit / 1.2;
    }
  else
    if ( arg[0] == '\0' )
      wimpy = (int) ch->max_hit / 5;
    else
      wimpy = atoi( arg );

  if ( wimpy < 0 )
    {
      send_to_char( "Your courage exceeds your wisdom.\n\r", ch );
      return;
    }
  if ( IS_PKILL( ch ) && wimpy > (int) ch->max_hit / 2.25 )
    {
      send_to_char( "Such cowardice ill becomes you.\n\r", ch );
      return;
    }
  else if ( wimpy > (int) ch->max_hit / 1.2 )
    {
      send_to_char( "Such cowardice ill becomes you.\n\r", ch );
      return;
    }
  ch->wimpy	= wimpy;
  ch_printf( ch, "Wimpy set to %d hit points.\n\r", wimpy );
  return;
}



void do_password( CHAR_DATA *ch, char *argument )
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char *pArg;
  char *pwdnew;
  char *p;
  char cEnd;

  if ( IS_NPC(ch) )
    return;

  /*
   * Can't use one_argument here because it smashes case.
   * So we just steal all its code.  Bleagh.
   */
  pArg = arg1;
  while ( isspace(*argument) )
    argument++;

  cEnd = ' ';
  if ( *argument == '\'' || *argument == '"' )
    cEnd = *argument++;

  while ( *argument != '\0' )
    {
      if ( *argument == cEnd )
        {
          argument++;
          break;
        }
      *pArg++ = *argument++;
    }
  *pArg = '\0';

  pArg = arg2;
  while ( isspace(*argument) )
    argument++;

  cEnd = ' ';
  if ( *argument == '\'' || *argument == '"' )
    cEnd = *argument++;

  while ( *argument != '\0' )
    {
      if ( *argument == cEnd )
        {
          argument++;
          break;
        }
      *pArg++ = *argument++;
    }
  *pArg = '\0';

  if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
      send_to_char( "Syntax: password <new> <again>.\n\r", ch );
      send_to_char( "Syntax: password <new> <again>.\n\r", ch );
      return;
    }

  /* This should stop all the mistyped password problems --Shaddai */
  if ( strcmp( arg1, arg2 ))
    {
      send_to_char("Passwords don't match try again.\n\r", ch );
      return;
    }
  if ( strlen(arg2) < 5 )
    {
      send_to_char( "New password must be at least five characters long.\n\r", ch );
      return;
    }

  if (arg1[0] == '!' || arg2[0] == '!')
    {
      send_to_char( "New password cannot begin with the '!' character.",ch);
      return;
    }

  /*
   * No tilde allowed because of player file format.
   */
  pwdnew = smaug_crypt( arg2 );
  for ( p = pwdnew; *p != '\0'; p++ )
    {
      if ( *p == '~' )
        {
          send_to_char(	"New password not acceptable, try again.\n\r", ch );
          return;
        }
    }

  DISPOSE( ch->pcdata->pwd );
  ch->pcdata->pwd = str_dup( pwdnew );
  if ( IS_SET(sysdata.save_flags, SV_PASSCHG) )
    save_char_obj( ch );
  if ( ch->desc && ch->desc->host[0]  != '\0' )
    sprintf(log_buf, "%s changing password from site %s\n", ch->name, ch->desc->host );
  else
    sprintf(log_buf, "%s changing thier password with no descriptor!", ch->name);
  log_string( log_buf );
  send_to_char( "Ok.\n\r", ch );
  return;
}



void do_socials( CHAR_DATA *ch, char *argument )
{
  int iHash;
  int col = 0;
  SOCIALTYPE *social;

  set_pager_color( AT_PLAIN, ch );
  for ( iHash = 0; iHash < 27; iHash++ )
    for ( social = social_index[iHash]; social; social = social->next )
      {
        pager_printf( ch, "%-12s", social->name );
        if ( ++col % 6 == 0 )
          send_to_pager( "\n\r", ch );
      }

  if ( col % 6 != 0 )
    send_to_pager( "\n\r", ch );
  return;
}


void do_commands( CHAR_DATA *ch, char *argument )
{
  int col;
  bool found;
  int hash;
  CMDTYPE *command;

  col = 0;
  set_pager_color( AT_PLAIN, ch );
  if ( argument[0] == '\0' )
    {
      for ( hash = 0; hash < 126; hash++ )
        for ( command = command_hash[hash]; command; command = command->next )
          if ( command->level <  LEVEL_HERO
               &&   command->level <= get_trust( ch )
               &&  (command->name[0] != 'm'
                    ||   command->name[1] != 'p') )
            {
              pager_printf( ch, "%-12s", command->name );
              if ( ++col % 6 == 0 )
                send_to_pager( "\n\r", ch );
            }
      if ( col % 6 != 0 )
        send_to_pager( "\n\r", ch );
    }
  else
    {
      found = FALSE;
      for ( hash = 0; hash < 126; hash++ )
        for ( command = command_hash[hash]; command; command = command->next )
          if ( command->level <  LEVEL_HERO
               &&   command->level <= get_trust( ch )
               &&  !str_prefix(argument, command->name)
               &&  (command->name[0] != 'm'
                    ||   command->name[1] != 'p') )
            {
              pager_printf( ch, "%-12s", command->name );
              found = TRUE;
              if ( ++col % 6 == 0 )
                send_to_pager( "\n\r", ch );
            }

      if ( col % 6 != 0 )
        send_to_pager( "\n\r", ch );
      if ( !found )
        ch_printf( ch, "No command found under %s.\n\r", argument);
    }
  return;
}

void do_channels( CHAR_DATA *ch, char *argument )
{
  char arg[MAX_INPUT_LENGTH];
  one_argument( argument, arg );

  if ( IS_NPC( ch ) )
    return;

  if ( arg[0] == '\0' )
    {
      if ( !IS_NPC(ch) && xIS_SET(ch->act, PLR_SILENCE) )
        {
          set_char_color( AT_GREEN, ch );
          send_to_char( "You are silenced.\n\r", ch );
          return;
        }

      /* Channels everyone sees regardless of affiliation --Blodkai */
      send_to_char_color( "\n\r &gPublic channels  (severe penalties for abuse)&G:\n\r  ", ch );
      /*(    ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_RACETALK )?
                           " &G+RACETALK" :
                           " &g-racetalk" ); */
      ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_GOSSIP )    ?
                       " &G+GOSSIP" 	          :
                       " &g-gossip" );
      ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_OOC )   ?
                       " &G+OOC" 	          :
                       " &g-ooc" );


      ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_FLAME ) ?
                       " &G+FLAME" 	          :
                       " &g-flame" );

	ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_SAYTO ) ?
                       " &G+SAYTO" 	          :
                       " &g-sayto" );	       
		       
      ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_MUSIC )   ?
                       " &G+MUSIC" 	          :
                       " &g-music" );
      ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_ASK )     ?
                       " &G+ASK"                 :
                       " &g-ask" );

      ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_YELL )    ?
                       " &G+YELL"	          :
                       " &g-yell" );

      ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_NEWBIE) ?
                       " &G+NEWBIE"	     	  :
                       " &g-newbie" );

      if ( get_trust( ch ) > 2 && !NOT_AUTHED( ch ) )
        ch_printf_color( ch, "%s", !IS_SET( ch->deaf, CHANNEL_AUCTION ) ?
                         " &G+AUCTION" 	          :
                         " &g-auction" );

      if ( IS_HERO( ch ) )
        ch_printf_color( ch, "%s", !IS_SET( ch->deaf, CHANNEL_AVTALK )  ?
                         " &G+AVATAR"	          :
                         " &g-avatar" );

      /* For organization channels (orders, clans, guilds, councils) */
      send_to_char_color( "\n\r &gPrivate channels (severe penalties for abuse)&G:\n\r ", ch );
      ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_TELLS )   ?
                       " &G+TELLS"               :
                       " &g-tells" );
      ch_printf_color( ch, "%s", !IS_SET( ch->deaf, CHANNEL_WHISPER )   ?
                       " &G+WHISPER"		  :
                       " &g-whisper" );
      if ( !IS_NPC( ch ) && ch->pcdata->clan )
        {
          if ( ch->pcdata->clan->clan_type == CLAN_ORDER )
            send_to_char_color( !IS_SET( ch->deaf, CHANNEL_ORDER ) ?
                                " &G+ORDER"	:	" &g-order", ch );

          else if ( ch->pcdata->clan->clan_type == CLAN_GUILD )
            send_to_char_color( !IS_SET( ch->deaf, CHANNEL_GUILD ) ?
                                " &G+GUILD"	:	" &g-guild", ch );
          else
            send_to_char_color( !IS_SET( ch->deaf, CHANNEL_CLAN )  ?
                                " &G+CLAN"	:	" &g-clan", ch );
        }

      if ( !IS_NPC( ch ) && ch->pcdata->council )
        ch_printf_color( ch, "%s",   !IS_SET( ch->deaf, CHANNEL_COUNCIL)?
                         " &G+COUNCIL"	     	  :
                         " &g-council" );

      /* Immortal channels */
      if ( IS_IMMORTAL( ch ) )
        {
          send_to_char_color( "\n\r &gImmortal Channels&G:\n\r  ", ch );
          send_to_char_color( !IS_SET( ch->deaf, CHANNEL_IMMTALK )    ?
                              " &G+IMMTALK"	:	" &g-immtalk", ch );
          /*          send_to_char_color( !IS_SET( ch->deaf, CHANNEL_PRAY )       ?
          		" &G+PRAY"	:	" &g-pray", ch ); */
          if ( get_trust( ch ) >= sysdata.muse_level )
            send_to_char_color( !IS_SET( ch->deaf, CHANNEL_HIGHGOD )  ?
                                " &G+MUSE"	:	" &g-muse", ch );
          send_to_char_color( !IS_SET( ch->deaf, CHANNEL_MONITOR )    ?
                              " &G+MONITOR"	:	" &g-monitor", ch );
          send_to_char_color( !IS_SET( ch->deaf, CHANNEL_AUTH )	?
                              " &G+AUTH"	:	" &g-auth", ch );
        }
      if ( get_trust( ch ) >= sysdata.log_level )
        {
          send_to_char_color( !IS_SET( ch->deaf, CHANNEL_LOG ) 	?
                              " &G+LOG"	:	" &g-log", ch);
          send_to_char_color( !IS_SET( ch->deaf, CHANNEL_BUILD)       ?
                              " &G+BUILD"	:	" &g-build", ch );
          send_to_char_color( !IS_SET( ch->deaf, CHANNEL_COMM ) 	?
                              " &G+COMM"	:	" &g-comm", ch );
          send_to_char_color( !IS_SET (ch->deaf, CHANNEL_WARN)
                              ? " &G+WARN" : " &g-warn", ch);
          if ( get_trust( ch ) >= sysdata.think_level )
            send_to_char_color( !IS_SET( ch->deaf, CHANNEL_HIGH ) 	?
                                " &G+HIGH"	:	" &g-high", ch );
        }
      send_to_char( "\n\r", ch );
    }
  else
    {
      bool fClear;
      bool ClearAll;
      int bit;

      bit=0;
      ClearAll = FALSE;

      if ( arg[0] == '+' )
        fClear = TRUE;
      else if ( arg[0] == '-' )
        fClear = FALSE;
      else
        {
          send_to_char( "Channels -channel or +channel?\n\r", ch );
          return;
        }

      if ( !str_cmp( arg+1, "auction"  ) )
        bit = CHANNEL_AUCTION;
      else if ( !str_cmp( arg+1, "traffic"  ) )
        bit = CHANNEL_TRAFFIC;
      else if ( !str_cmp( arg+1, "gossip"     ) )
        bit = CHANNEL_GOSSIP;
      else if ( !str_cmp( arg+1, "clan"     ) )
        bit = CHANNEL_CLAN;
      else if ( !str_cmp( arg+1, "council"  ) )
        bit = CHANNEL_COUNCIL;
      else if ( !str_cmp( arg+1, "guild"    ) )
        bit = CHANNEL_GUILD;
      else if ( !str_cmp( arg+1, "ooc"    ) )
        bit = CHANNEL_OOC;
      else if ( !str_cmp( arg+1, "tells"    ) )
        bit = CHANNEL_TELLS;
      else if ( !str_cmp( arg+1, "immtalk"  ) )
        bit = CHANNEL_IMMTALK;
      else if ( !str_cmp( arg+1, "log"      ) )
        bit = CHANNEL_LOG;
      else if ( !str_cmp( arg+1, "build"    ) )
        bit = CHANNEL_BUILD;
      else if ( !str_cmp( arg+1, "high"     ) )
        bit = CHANNEL_HIGH;
      else if ( !str_cmp( arg+1, "pray"     ) )
        bit = CHANNEL_PRAY;
      else if ( !str_cmp( arg+1, "avatar"   ) )
        bit = CHANNEL_AVTALK;
      else if ( !str_cmp( arg+1, "monitor"  ) )
        bit = CHANNEL_MONITOR;
      else if ( !str_cmp( arg+1, "auth"     ) )
        bit = CHANNEL_AUTH;
      else if ( !str_cmp( arg+1, "newbie"   ) )
        bit = CHANNEL_NEWBIE;
      else if ( !str_cmp( arg+1, "music"    ) )
        bit = CHANNEL_MUSIC;
      else if ( !str_cmp( arg+1, "muse"     ) )
        bit = CHANNEL_HIGHGOD;
      else if ( !str_cmp( arg+1, "ask"      ) )
        bit = CHANNEL_ASK;
      else if ( !str_cmp( arg+1, "shout"    ) )
        bit = CHANNEL_SHOUT;
      else if ( !str_cmp( arg+1, "yell"     ) )
        bit = CHANNEL_YELL;
      else if ( !str_cmp( arg+1, "comm"     ) )
        bit = CHANNEL_COMM;
      else if ( !str_cmp (arg+1, "warn"     ) )
        bit = CHANNEL_WARN;
      else if ( !str_cmp( arg+1, "order"    ) )
        bit = CHANNEL_ORDER;
      else if ( !str_cmp( arg+1, "flame"  ) )
        bit = CHANNEL_FLAME;
      else if ( !str_cmp( arg+1, "sayto"  ) )
        bit = CHANNEL_SAYTO;	
      else if ( !str_cmp( arg+1, "whisper"  ) )
        bit = CHANNEL_WHISPER;
      else if ( !str_cmp( arg+1, "racetalk" ) )
        bit = CHANNEL_RACETALK;
      else if ( !str_cmp( arg+1, "all"      ) )
        ClearAll = TRUE;
      else
        {
          send_to_char( "Set or clear which channel?\n\r", ch );
          return;
        }

      if (( fClear ) && ( ClearAll ))
        {
          REMOVE_BIT (ch->deaf, CHANNEL_RACETALK);
          REMOVE_BIT (ch->deaf, CHANNEL_AUCTION);
          REMOVE_BIT (ch->deaf, CHANNEL_GOSSIP);
          REMOVE_BIT (ch->deaf, CHANNEL_OOC);
          REMOVE_BIT (ch->deaf, CHANNEL_FLAME);
          REMOVE_BIT (ch->deaf, CHANNEL_PRAY);
          REMOVE_BIT (ch->deaf, CHANNEL_TRAFFIC);
          REMOVE_BIT (ch->deaf, CHANNEL_MUSIC);
          REMOVE_BIT (ch->deaf, CHANNEL_ASK);
          REMOVE_BIT (ch->deaf, CHANNEL_SHOUT);
          REMOVE_BIT (ch->deaf, CHANNEL_YELL);

          /*     if (ch->pcdata->clan)
                 REMOVE_BIT (ch->deaf, CHANNEL_CLAN);

          if (ch->pcdata->council)
          REMOVE_BIT (ch->deaf, CHANNEL_COUNCIL);

               if (ch->pcdata->guild)
                 REMOVE_BIT (ch->deaf, CHANNEL_GUILD);
          */
          if (ch->level >= LEVEL_IMMORTAL)
            REMOVE_BIT (ch->deaf, CHANNEL_AVTALK);

          /*
          if (ch->level >= sysdata.log_level )
            REMOVE_BIT (ch->deaf, CHANNEL_COMM);
          */

        }
      else if ((!fClear) && (ClearAll))
        {
          SET_BIT (ch->deaf, CHANNEL_RACETALK);
          SET_BIT (ch->deaf, CHANNEL_AUCTION);
          SET_BIT (ch->deaf, CHANNEL_TRAFFIC);
          SET_BIT (ch->deaf, CHANNEL_GOSSIP);
          SET_BIT (ch->deaf, CHANNEL_OOC);
          SET_BIT (ch->deaf, CHANNEL_PRAY);
          SET_BIT (ch->deaf, CHANNEL_MUSIC);
          SET_BIT (ch->deaf, CHANNEL_ASK);
          SET_BIT (ch->deaf, CHANNEL_SHOUT);
          SET_BIT (ch->deaf, CHANNEL_FLAME);
          SET_BIT (ch->deaf, CHANNEL_YELL);

          /*     if (ch->pcdata->clan)
                 SET_BIT (ch->deaf, CHANNEL_CLAN);

          if (ch->pcdata->council)
          SET_BIT (ch->deaf, CHANNEL_COUNCIL);

               if ( IS_GUILDED(ch) )
                 SET_BIT (ch->deaf, CHANNEL_GUILD);
          */
          if (ch->level >= LEVEL_IMMORTAL)
            SET_BIT (ch->deaf, CHANNEL_AVTALK);

          /*
          if (ch->level >= sysdata.log_level)
            SET_BIT (ch->deaf, CHANNEL_COMM);
          */

        }
      else if (fClear)
        {
          REMOVE_BIT (ch->deaf, bit);
        }
      else
        {
          SET_BIT    (ch->deaf, bit);
        }

      send_to_char( "Ok.\n\r", ch );
    }

  return;
}


/*
 * display WIZLIST file						-Thoric
 */
void do_wizlist( CHAR_DATA *ch, char *argument )
{
  set_pager_color( AT_IMMORT, ch );
  show_file( ch, WIZLIST_FILE );
}

/*
 * Contributed by Grodyn.
 * Display completely overhauled, 2/97 -- Blodkai
 */
void do_config( CHAR_DATA *ch, char *argument )
{
  char arg[MAX_INPUT_LENGTH];

  if ( IS_NPC(ch) )
    return;

  one_argument( argument, arg );

  set_char_color( AT_GREEN, ch );

  if ( arg[0] == '\0' )
    {
      set_char_color( AT_DGREEN, ch );
      send_to_char( "\n\rConfigurations ", ch );
      set_char_color( AT_GREEN, ch );
      send_to_char( "(use 'config +/- <keyword>' to toggle, see 'help config')\n\r\n\r", ch );
      set_char_color( AT_DGREEN, ch );
      send_to_char( "Display:   ", ch );
      set_char_color( AT_GREY, ch );
      ch_printf( ch, "%-12s   %-12s   %-12s   %-12s\n\r           %-12s   %-12s   %-12s   %-12s\n\r",         //  %-12s   %-12s
                 IS_SET( ch->pcdata->flags, PCFLAG_PAGERON ) 	? "[+] PAGER"
                 : "[-] pager",
                 IS_SET( ch->pcdata->flags, PCFLAG_GAG )     	? "[+] GAG"
                 : "[-] gag",
                 xIS_SET( ch->act, PLR_BRIEF )                	? "[+] BRIEF"
                 : "[-] brief",
                 xIS_SET( ch->act, PLR_COMBINE )              	? "[+] COMBINE"
                 : "[-] combine",
                 xIS_SET( ch->act, PLR_BLANK )                	? "[+] BLANK"
                 : "[-] blank",
                 xIS_SET( ch->act, PLR_PROMPT )               	? "[+] PROMPT"
                 : "[-] prompt",
                 xIS_SET( ch->act, PLR_ANSI )                 	? "[+] ANSI"
                 : "[-] ansi",
                 xIS_SET( ch->act, PLR_RIP )                  	? "[+] RIP"
                 : "[-] rip");
      /*      xIS_SET( ch->act, PLR_COMPASS )			? "[+] COMPASS"
            : "[-] compass",
            xIS_SET( ch->act, PLR_AUTOMAP)			? "[+] MAP"
            : "[-] map" ); */

      set_char_color( AT_DGREEN, ch );
      send_to_char( "\n\r\n\rAuto:      ", ch );
      set_char_color( AT_GREY, ch );
      ch_printf( ch, "%-12s   %-12s   %-12s   %-12s",
                 xIS_SET(ch->act, PLR_AUTOSAC  )             	? "[+] AUTOSAC"
                 : "[-] autosac",
                 xIS_SET(ch->act, PLR_AUTOGOLD )             	? "[+] AUTOGOLD"
                 : "[-] autogold",
                 xIS_SET(ch->act, PLR_AUTOLOOT )             	? "[+] AUTOLOOT"
                 : "[-] autoloot",
                 xIS_SET(ch->act, PLR_AUTOEXIT )             	? "[+] AUTOEXIT"
                 : "[-] autoexit" );

      set_char_color( AT_DGREEN, ch );
      send_to_char( "\n\r\n\rSafeties:  ", ch );
      set_char_color( AT_GREY, ch );
      ch_printf( ch, "%-12s   %-12s",
                 IS_SET( ch->pcdata->flags, PCFLAG_NORECALL ) 	? "[+] NORECALL"
                 : "[-] norecall",
                 IS_SET( ch->pcdata->flags, PCFLAG_NOSUMMON ) 	? "[+] NOSUMMON"
                 : "[-] nosummon" );

      if ( !IS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) )
        ch_printf( ch, "   %-12s   %-12s",
                   xIS_SET(ch->act, PLR_SHOVEDRAG )             ? "[+] DRAG"
                   : "[-] drag",
                   xIS_SET(ch->act, PLR_NICE )               	? "[+] NICE"
                   : "[-] nice" );

      set_char_color( AT_DGREEN, ch );
      send_to_char( "\n\r\n\rMisc:      ", ch );
      set_char_color( AT_GREY, ch );
      ch_printf( ch, "%-12s   %-12s   %-12s",
                 xIS_SET(ch->act, PLR_TELNET_GA )		? "[+] TELNETGA"
                 : "[-] telnetga",
                 IS_SET( ch->pcdata->flags, PCFLAG_GROUPWHO ) ? "[+] GROUPWHO"
                 : "[-] groupwho",
                 IS_SET( ch->pcdata->flags, PCFLAG_NOINTRO )  ? "[+] NOINTRO"
                 : "[-] nointro" );

      set_char_color( AT_DGREEN, ch );
      send_to_char( "\n\r\n\rSettings:  ", ch );
      set_char_color( AT_GREY, ch );
      ch_printf_color( ch, "Pager Length (%d)    Wimpy (&W%d&w)",
                       ch->pcdata->pagerlen,
                       ch->wimpy );

      if ( IS_IMMORTAL( ch ) )
        {
          set_char_color( AT_DGREEN, ch );
          send_to_char( "\n\r\n\rImmortal toggles:  ", ch );
          set_char_color( AT_GREY, ch );
          ch_printf( ch, "Roomvnum [%s]",
                     xIS_SET(ch->act, PLR_ROOMVNUM ) 		? "+"
                     : " ");
        }

      /* Config option for Room Flag display added by Samson 12-10-97 */
      /* Config option for Sector Type display added by Samson 12-10-97 */
      /* Config option Area name and filename added by Samson 12-13-97 */
      if( IS_IMMORTAL( ch ) )
        {
          set_char_color( AT_DGREEN, ch );
          send_to_char( "\n\rMore Immortal toggles:  ", ch );
          set_char_color( AT_GREY, ch );
          ch_printf( ch, "Roomflags [%s] Sectortypes [%s] Filename [%s]\n\r",
                     IS_SET(ch->pcdata->flags, PCFLAG_AUTOFLAGS) ? "+"
                     : " ",
                     IS_SET(ch->pcdata->flags, PCFLAG_SECTORD)   ? "+"
                     : " ",
                     IS_SET(ch->pcdata->flags, PCFLAG_ANAME)     ? "+"
                     : " " );
        }

      set_char_color( AT_DGREEN, ch );
      send_to_char( "\n\r\n\rSentences imposed on you (if any):", ch );
      set_char_color( AT_YELLOW, ch );
      ch_printf( ch, "\n\r%s%s%s%s%s%s",
                 xIS_SET(ch->act, PLR_SILENCE )  ?
                 " For your abuse of channels, you are currently silenced.\n\r" : "",
                 xIS_SET(ch->act, PLR_NO_EMOTE ) ?
                 " The gods have removed your emotes.\n\r"                      : "",
                 xIS_SET(ch->act, PLR_NO_TELL )  ?
                 " You are not permitted to send 'tells' to others.\n\r"        : "",
                 xIS_SET(ch->act, PLR_LITTERBUG )?
                 " A convicted litterbug.  You cannot drop anything.\n\r"       : "",
                 xIS_SET(ch->act, PLR_THIEF )    ?
                 " A proven thief, you will be hunted by the authorities.\n\r"  : "",
                 xIS_SET(ch->act, PLR_KILLER )   ?
                 " For the crime of murder you are sentenced to death...\n\r"   : "" );
    }
  else
    {
      bool fSet;
      int bit = 0;

      if ( arg[0] == '+' )
        fSet = TRUE;
      else if ( arg[0] == '-' )
        fSet = FALSE;
      else
        {
          send_to_char( "Config -option or +option?\n\r", ch );
          return;
        }

      if ( !str_prefix( arg+1, "autoexit" ) )
        bit = PLR_AUTOEXIT;
      else if ( !str_prefix( arg+1, "autoloot" ) )
        bit = PLR_AUTOLOOT;
      else if ( !str_prefix( arg+1, "autosac"  ) )
        bit = PLR_AUTOSAC;
      else if ( !str_prefix( arg+1, "autogold" ) )
        bit = PLR_AUTOGOLD;
      else if ( !str_prefix( arg+1, "blank"    ) )
        bit = PLR_BLANK;
      else if ( !str_prefix( arg+1, "brief"    ) )
        bit = PLR_BRIEF;
      else if ( !str_prefix( arg+1, "combine"  ) )
        bit = PLR_COMBINE;
      else if ( !str_prefix( arg+1, "prompt"   ) )
        bit = PLR_PROMPT;
      else if ( !str_prefix( arg+1, "telnetga" ) )
        bit = PLR_TELNET_GA;
      else if ( !str_prefix( arg+1, "ansi"     ) )
        bit = PLR_ANSI;
      else if ( !str_prefix( arg+1, "rip"      ) )
        bit = PLR_RIP;
      else if ( !str_prefix( arg+1, "compass"  ) )
        bit = PLR_COMPASS;
      else if (!str_prefix( arg+1,  "map"      ) )
        bit = PLR_AUTOMAP;     /* maps */
      /*	else if ( !str_prefix( arg+1, "flee"     ) ) bit = PLR_FLEE; */
      else if ( !str_prefix( arg+1, "nice"     ) )
        bit = PLR_NICE;
      else if ( !str_prefix( arg+1, "drag"     ) )
        bit = PLR_SHOVEDRAG;
      else if ( IS_IMMORTAL( ch )
                &&   !str_prefix( arg+1, "vnum"     ) )
        bit = PLR_ROOMVNUM;


      if (bit)
        {
          if ( (bit == PLR_FLEE || bit == PLR_NICE || bit == PLR_SHOVEDRAG)
               &&  IS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) )
            {
              send_to_char( "Pkill characters can not config that option.\n\r", ch );
              return;
            }

          if ( fSet )
            xSET_BIT   (ch->act, bit);
          else
            xREMOVE_BIT(ch->act, bit);
          send_to_char( "Ok.\n\r", ch );
          return;
        }
      else
        {
          if ( !str_prefix( arg+1, "norecall" ) )
            bit = PCFLAG_NORECALL;
          else if ( !str_prefix( arg+1, "nointro"  ) )
            bit = PCFLAG_NOINTRO;
          else if ( !str_prefix( arg+1, "nosummon" ) )
            bit = PCFLAG_NOSUMMON;
          else if ( !str_prefix( arg+1, "gag"      ) )
            bit = PCFLAG_GAG;
          else if ( !str_prefix( arg+1, "pager"    ) )
            bit = PCFLAG_PAGERON;
          else if ( IS_IMMORTAL ( ch )
                    && ( !str_prefix( arg+1, "roomflags" ) ) )
            bit = PCFLAG_AUTOFLAGS;
          else if ( IS_IMMORTAL ( ch )
                    && ( !str_prefix( arg+1, "sectortypes" ) ) )
            bit = PCFLAG_SECTORD;
          else if ( IS_IMMORTAL ( ch )
                    && ( !str_prefix( arg+1, "filename" ) ) )
            bit = PCFLAG_ANAME;

          else if ( !str_prefix( arg+1, "groupwho" ) )
            bit = PCFLAG_GROUPWHO;
          else if ( !str_prefix( arg+1, "@hgflag_" ) )
            bit = PCFLAG_HIGHGAG;
          else
            {
              send_to_char( "Config which option?\n\r", ch );
              return;
            }

          if ( fSet )
            SET_BIT    (ch->pcdata->flags, bit);
          else
            REMOVE_BIT (ch->pcdata->flags, bit);

          send_to_char( "Ok.\n\r", ch );
          return;
        }
    }

  return;
}


void do_credits( CHAR_DATA *ch, char *argument )
{
  do_help( ch, "credits" );
}


extern int top_area;

/*
 * New do_areas, written by Fireblade, last modified - 4/27/97
 *
 *   Syntax: area            ->      lists areas in alphanumeric order
 *           area <a>        ->      lists areas with soft max less than
 *                                                    parameter a
 *           area <a> <b>    ->      lists areas with soft max bewteen
 *                                                    numbers a and b
 *           area old        ->      list areas in order loaded
 *
 */
void do_areas( CHAR_DATA *ch, char *argument )
{
  char *header_string1 = "\n\r|  Author       |             Area"
                         "                     | "
                         "Recommended |  Enforced |\n\r";
  char *header_string2 = "----------------+-----------------"
                         "-------------------+----"
                         "---------+------------\n\r";
  char *print_string = "| %-13s | %-34s | %4d - %-4d | %3d - "
                       "%-3d |\n\r";

  AREA_DATA *pArea;
  int lower_bound = 0;
  int upper_bound = MAX_LEVEL + 1;
  /* make sure is to init. > max area level */
  char arg[MAX_STRING_LENGTH];

  argument = one_argument(argument,arg);

  if(arg[0] != '\0')
    {
      if(!is_number(arg))
        {
          if(!strcmp(arg,"old"))
            {
              set_pager_color( AT_PLAIN, ch );
              send_to_pager(header_string1, ch);
              send_to_pager(header_string2, ch);
              for (pArea = first_area; pArea;pArea = pArea->next)
                {
                  pager_printf(ch, print_string,
                               pArea->author, pArea->name,
                               pArea->low_soft_range,
                               pArea->hi_soft_range,
                               pArea->low_hard_range,
                               pArea->hi_hard_range);
                }
              return;
            }
          else
            {
              send_to_char("Area may only be followed by numbers, or 'old'.\n\r", ch);
              return;
            }
        }

      upper_bound = atoi(arg);
      lower_bound = upper_bound;

      argument = one_argument(argument,arg);

      if(arg[0] != '\0')
        {
          if(!is_number(arg))
            {
              send_to_char("Area may only be followed by numbers.\n\r", ch);
              return;
            }

          upper_bound = atoi(arg);

          argument = one_argument(argument,arg);
          if(arg[0] != '\0')
            {
              send_to_char("Only two level numbers allowed.\n\r",ch);
              return;
            }
        }
    }

  if(lower_bound > upper_bound)
    {
      int swap = lower_bound;
      lower_bound = upper_bound;
      upper_bound = swap;
    }

  set_pager_color( AT_PLAIN, ch );
  send_to_char("----------------+--------------------------------------+-------------+------------", ch);
  send_to_pager(header_string1, ch);
  send_to_pager(header_string2, ch);

  for (pArea = first_area_name; pArea; pArea = pArea->next_sort_name)
    {
      if (pArea->hi_soft_range >= lower_bound
          &&  pArea->low_soft_range <= upper_bound)
        {
          pager_printf(ch, print_string,
                       pArea->author, pArea->name,
                       pArea->low_soft_range,
                       pArea->hi_soft_range,
                       pArea->low_hard_range,
                       pArea->hi_hard_range);
        }
    }
  send_to_char("----------------+--------------------------------------+-------------+------------\n\r", ch);
  return;
}

void do_afk( CHAR_DATA *ch, char *argument )
{
  if ( IS_NPC(ch) )
    return;

  if xIS_SET(ch->act, PLR_AFK)
    {
      xREMOVE_BIT(ch->act, PLR_AFK);
      send_to_char( "You are no longer afk.\n\r", ch );
      /*	act(AT_GREY,"$n is no longer afk.", ch, NULL, NULL, TO_ROOM);*/
      act(AT_GREY,"$n is no longer afk.", ch, NULL, NULL, TO_CANSEE);
    }
  else
    {
      xSET_BIT(ch->act, PLR_AFK);
      send_to_char( "You are now afk.\n\r", ch );
      /*	act(AT_GREY,"$n is now afk.", ch, NULL, NULL, TO_ROOM);*/
      act(AT_GREY,"$n is now afk.", ch, NULL, NULL, TO_CANSEE);
      return;
    }

}

void do_slist( CHAR_DATA *ch, char *argument )
{
  int sn, i, lFound;
  char skn[MAX_INPUT_LENGTH];
  char buf[MAX_INPUT_LENGTH];
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  int lowlev, hilev;
  sh_int lasttype = SKILL_SPELL;

  if ( IS_NPC(ch) )
    return;

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );

  lowlev=1;
  hilev=100;

  if (arg1[0]!='\0')
    lowlev=atoi(arg1);

  if ((lowlev<1) || (lowlev>LEVEL_IMMORTAL))
    lowlev=1;

  if (arg2[0]!='\0')
    hilev=atoi(arg2);

  if ((hilev<0) || (hilev>=LEVEL_IMMORTAL))
    hilev=LEVEL_HERO;

  if(lowlev>hilev)
    lowlev=hilev;

  set_pager_color( AT_MAGIC, ch );
  send_to_pager("SPELL & SKILL LIST\n\r",ch);
  send_to_pager("------------------\n\r",ch);

  for (i=lowlev; i <= hilev; i++)
    {
      lFound= 0;
      sprintf(skn,"Spell");
      for ( sn = 0; sn < top_sn; sn++ )
        {
          if ( !skill_table[sn]->name )
            break;

          if ( skill_table[sn]->type != lasttype )
            {
              lasttype = skill_table[sn]->type;
              strcpy( skn, skill_tname[lasttype] );
            }

          if ( ch->pcdata->learned[sn] <= 0
               &&   SPELL_FLAG(skill_table[sn], SF_SECRETSKILL) )
            continue;

          if(i==skill_table[sn]->skill_level[ch->class]  )
            {
              if( !lFound )
                {
                  lFound=1;
                  pager_printf( ch, "Level %d\n\r", i );
                }
              switch (skill_table[sn]->minimum_position)
                {
                default:
                  sprintf(buf, "Invalid");
                  bug( "do_slist: skill with invalid minpos, skill=%s",
                       skill_table[sn]->name );
                  break;
                case POS_DEAD:
                  sprintf(buf, "any");
                  break;
                case POS_MORTAL:
                  sprintf(buf, "mortally wounded");
                  break;
                case POS_INCAP:
                  sprintf(buf, "incapacitated");
                  break;
                case POS_STUNNED:
                  sprintf(buf, "stunned");
                  break;
                case POS_SLEEPING:
                  sprintf(buf, "sleeping");
                  break;
                case POS_RESTING:
                  sprintf(buf, "resting");
                  break;
                case POS_STANDING:
                  sprintf(buf, "standing");
                  break;
                case POS_FIGHTING:
                  sprintf(buf, "fighting");
                  break;
                case POS_EVASIVE:
                  sprintf(buf, "fighting (evasive)");   /* Fighting style support -haus */
                  break;
                case POS_DEFENSIVE:
                  sprintf(buf, "fighting (defensive)");
                  break;
                case POS_AGGRESSIVE:
                  sprintf(buf, "fighting (aggressive)");
                  break;
                case POS_BERSERK:
                  sprintf(buf, "fighting (berserk)");
                  break;
                case POS_MOUNTED:
                  sprintf(buf, "mounted");
                  break;
                case POS_SITTING:
                  sprintf(buf, "sitting");
                  break;
                }

              pager_printf(ch, "%7s: %20.20s \t Current: %-3d Max: %-3d  MinPos: %s \n\r",
                           skn, skill_table[sn]->name,
                           ch->pcdata->learned[sn],
                           skill_table[sn]->skill_adept[ch->class],
                           buf );
            }
        }
    }
  return;
}

void do_whois( CHAR_DATA *ch, char *argument)
{
  CHAR_DATA *victim;
  char buf[MAX_STRING_LENGTH];
  char buf2[MAX_STRING_LENGTH];

  buf[0] = '\0';

  if(IS_NPC(ch))
    return;

  if(argument[0] == '\0')
    {
      send_to_pager("You must input the name of an online character.\n\r", ch);
      return;
    }

  strcat(buf, "0.");
  strcat(buf, argument);
  if( ( ( victim = get_char_world(ch, buf) ) == NULL ))
    {
      send_to_pager("No such character online.\n\r", ch);
      return;
    }

  if(IS_NPC(victim))
    {
      send_to_pager("That's not a player!\n\r", ch);
      return;
    }

  set_pager_color( AT_GREY, ch );
  pager_printf(ch, "\n\r'%s%s.'\n\r %s is a %s level %d %s %s, %d years of age.\n\r",
               victim->name,
               victim->pcdata->title,
               victim->sex == SEX_MALE ? "He" :
               victim->sex == SEX_FEMALE ? "She" : "It",
               victim->sex == SEX_MALE ? "male" :
               victim->sex == SEX_FEMALE ? "female" : "neutral",
               victim->level,
               capitalize(race_table[victim->race]->race_name),
               class_table[victim->class]->who_name,
               get_age(victim) );

  pager_printf(ch, " %s is a %sdeadly player",
               victim->sex == SEX_MALE ? "He" :
               victim->sex == SEX_FEMALE ? "She" : "It",
               IS_SET(victim->pcdata->flags, PCFLAG_DEADLY) ? "" : "non-");

  if ( victim->pcdata->clan )
    {
      if ( victim->pcdata->clan->clan_type == CLAN_ORDER )
        send_to_pager( ", and belongs to the Order ", ch );
      else
        if ( victim->pcdata->clan->clan_type == CLAN_GUILD )
          send_to_pager( ", and belongs to the ", ch );
        else
          send_to_pager( ", and belongs to Clan ", ch );
      send_to_pager( victim->pcdata->clan->name, ch );
    }
  send_to_pager( ".\n\r", ch );

  if(victim->pcdata->council)
    pager_printf(ch, " %s holds a seat on:  %s\n\r",
                 victim->sex == SEX_MALE ? "He" :
                 victim->sex == SEX_FEMALE ? "She" : "It",
                 victim->pcdata->council->name );

  if(victim->pcdata->deity)
    pager_printf(ch, " %s has found succor in the deity %s.\n\r",
                 victim->sex == SEX_MALE ? "He" :
                 victim->sex == SEX_FEMALE ? "She" : "It",
                 victim->pcdata->deity->name);

  if(victim->pcdata->homepage && victim->pcdata->homepage[0] != '\0')
    pager_printf(ch, " %s homepage can be found at %s\n\r",
                 victim->sex == SEX_MALE ? "His" :
                 victim->sex == SEX_FEMALE ? "Her" : "Its",
                 show_tilde( victim->pcdata->homepage ) );

  if(victim->pcdata->bio && victim->pcdata->bio[0] != '\0')
    pager_printf(ch, " %s's personal bio:\n\r%s",
                 victim->name,
                 victim->pcdata->bio);
  else
    pager_printf(ch, " %s has yet to create a bio.\n\r",
                 victim->name );

  if(IS_IMMORTAL(ch))
    {
      send_to_pager("-------------------\n\r", ch);
      send_to_pager("Info for immortals:\n\r", ch);
      if ( mip_enabled( victim ) )
        pager_printf( ch, "%s's client is: %s (sec_code: %s)\n\r",
                      victim->name, victim->pcdata->mip_ver, victim->pcdata->sec_code );

      if ( victim->pcdata->authed_by && victim->pcdata->authed_by[0] != '\0' )
        pager_printf(ch, "%s was authorized by %s.\n\r",
                     victim->name, victim->pcdata->authed_by );

      pager_printf(ch, "%s has killed %d mobiles, and been killed by a mobile %d times.\n\r",
                   victim->name, victim->pcdata->mkills, victim->pcdata->mdeaths );
      if ( victim->pcdata->pkills || victim->pcdata->pdeaths )
        pager_printf(ch, "%s has killed %d players, and been killed by a player %d times.\n\r",
                     victim->name, victim->pcdata->pkills, victim->pcdata->pdeaths );
      if ( victim->pcdata->illegal_pk )
        pager_printf(ch, "%s has committed %d illegal player kills.\n\r",
                     victim->name, victim->pcdata->illegal_pk );

      pager_printf(ch, "%s is %shelled at the moment.\n\r",
                   victim->name,
                   (victim->pcdata->release_date == 0) ? "not " : "");

      if (victim->pcdata->nuisance )
        {
          pager_printf_color( ch, "&RNuisance   &cStage: (&R%d&c/%d)  Power:  &w%d  &cTime:  &w%s.\n\r", victim->pcdata->nuisance->flags,
                              MAX_NUISANCE_STAGE, victim->pcdata->nuisance->power,
                              ctime(&victim->pcdata->nuisance->time));
        }
      if(victim->pcdata->release_date != 0)
        pager_printf(ch, "%s was helled by %s, and will be released on %24.24s.\n\r",
                     victim->sex == SEX_MALE ? "He" :
                     victim->sex == SEX_FEMALE ? "She" : "It",
                     victim->pcdata->helled_by,
                     ctime(&victim->pcdata->release_date));

      if(get_trust(victim) < get_trust(ch))
        {
          sprintf(buf2, "list %s", buf);
          do_comment(ch, buf2);
        }

      if(xIS_SET(victim->act, PLR_SILENCE) || xIS_SET(victim->act, PLR_NO_EMOTE)
          || xIS_SET(victim->act, PLR_NO_TELL) || xIS_SET(victim->act, PLR_THIEF)
          || xIS_SET(victim->act, PLR_KILLER) )
        {
          sprintf(buf2, "This player has the following flags set:");
          if(xIS_SET(victim->act, PLR_SILENCE))
            strcat(buf2, " silence");
          if(xIS_SET(victim->act, PLR_NO_EMOTE))
            strcat(buf2, " noemote");
          if(xIS_SET(victim->act, PLR_NO_TELL) )
            strcat(buf2, " notell");
          if(xIS_SET(victim->act, PLR_THIEF) )
            strcat(buf2, " thief");
          if(xIS_SET(victim->act, PLR_KILLER) )
            strcat(buf2, " killer");
          strcat(buf2, ".\n\r");
          send_to_pager(buf2, ch);
        }
      if ( victim->desc && victim->desc->host[0]!='\0' )   /* added by Gorog */
        {
          sprintf (buf2, "%s's IP info: %s ", victim->name, victim->desc->host);
          strcat (buf2, "\n\r");
          send_to_pager(buf2, ch);
        }
    }
}

void do_pager( CHAR_DATA *ch, char *argument )
{
  char arg[MAX_INPUT_LENGTH];

  if ( IS_NPC(ch) )
    return;
  set_char_color( AT_NOTE, ch );
  argument = one_argument(argument, arg);
  if ( !*arg )
    {
      if ( IS_SET(ch->pcdata->flags, PCFLAG_PAGERON) )
        {
          send_to_char( "Pager disabled.\n\r", ch );
          do_config(ch, "-pager");
        }
      else
        {
          ch_printf( ch, "Pager is now enabled at %d lines.\n\r", ch->pcdata->pagerlen );
          do_config(ch, "+pager");
        }
      return;
    }
  if ( !is_number(arg) )
    {
      send_to_char( "Set page pausing to how many lines?\n\r", ch );
      return;
    }
  ch->pcdata->pagerlen = atoi(arg);
  if ( ch->pcdata->pagerlen < 5 )
    ch->pcdata->pagerlen = 5;
  ch_printf( ch, "Page pausing set to %d lines.\n\r", ch->pcdata->pagerlen );
  return;
}

/*
 * The ignore command allows players to ignore up to MAX_IGN
 * other players. Players may ignore other characters whether
 * they are online or not. This is to prevent people from
 * spamming someone and then logging off quickly to evade
 * being ignored.
 * Syntax:
 *	ignore		-	lists players currently ignored
 *	ignore none	-	sets it so no players are ignored
 *	ignore <player>	-	start ignoring player if not already
 *				ignored otherwise stop ignoring player
 *	ignore reply	-	start ignoring last player to send a
 *				tell to ch, to deal with invis spammers
 * Last Modified: June 26, 1997
 * - Fireblade
 */
void do_ignore(CHAR_DATA *ch, char *argument)
{
  char arg[MAX_INPUT_LENGTH];
  IGNORE_DATA *temp, *next;
  char fname[1024];
  struct stat fst;
  CHAR_DATA *victim;

  if(IS_NPC(ch))
    return;

  argument = one_argument(argument, arg);

  sprintf(fname, "%s%c/%s", PLAYER_DIR,
          tolower(arg[0]), capitalize(arg));

  victim = NULL;

  /* If no arguements, then list players currently ignored */
  if(arg[0] == '\0')
    {
      set_char_color(AT_DIVIDER, ch);
      ch_printf(ch, "\n\r----------------------------------------\n\r");
      set_char_color(AT_DGREEN, ch);
      ch_printf(ch, "You are currently ignoring:\n\r");
      set_char_color(AT_DIVIDER, ch);
      ch_printf(ch, "----------------------------------------\n\r");
      set_char_color(AT_IGNORE, ch);

      if(!ch->pcdata->first_ignored)
        {
          ch_printf(ch, "\t    no one\n\r");
          return;
        }

      for(temp = ch->pcdata->first_ignored; temp;
          temp = temp->next)
        {
          ch_printf(ch,"\t  - %s\n\r",temp->name);
        }

      return;
    }
  /* Clear players ignored if given arg "none" */
  else if(!strcmp(arg, "none"))
    {
      for(temp = ch->pcdata->first_ignored; temp; temp = next)
        {
          next = temp->next;
          UNLINK(temp, ch->pcdata->first_ignored,
                 ch->pcdata->last_ignored,
                 next, prev);
          STRFREE(temp->name);
          DISPOSE(temp);
        }

      set_char_color(AT_IGNORE, ch);
      ch_printf(ch, "You now ignore no one.\n\r");

      return;
    }
  /* Prevent someone from ignoring themself... */
  else if(!strcmp(arg, "self") || nifty_is_name(arg, ch->name))
    {
      set_char_color(AT_IGNORE, ch);
      ch_printf(ch, "Did you type something?\n\r");
      return;
    }
  else
    {
      int i;

      /* get the name of the char who last sent tell to ch */
      if(!strcmp(arg, "reply"))
        {
          if(!ch->reply)
            {
              set_char_color(AT_IGNORE, ch);
              ch_printf(ch, "They're not here.\n\r");
              return;
            }
          else
            {
              strcpy(arg, ch->reply->name);
            }
        }

      /* Loop through the linked list of ignored players */
      /* 	keep track of how many are being ignored     */
      for(temp = ch->pcdata->first_ignored, i = 0; temp;
          temp = temp->next, i++)
        {
          /* If the argument matches a name in list remove it */
          if(!strcmp(temp->name, capitalize(arg)))
            {
              UNLINK(temp, ch->pcdata->first_ignored,
                     ch->pcdata->last_ignored,
                     next, prev);
              set_char_color(AT_IGNORE, ch);
              ch_printf(ch,"You no longer ignore %s.\n\r",
                        temp->name);
              STRFREE(temp->name);
              DISPOSE(temp);
              return;
            }
        }

      /* if there wasn't a match check to see if the name   */
      /* is valid. This if-statement may seem like overkill */
      /* but it is intended to prevent people from doing the*/
      /* spam and log thing while still allowing ya to      */
      /* ignore new chars without pfiles yet...             */
      if( stat(fname, &fst) == -1 &&
          (!(victim = get_char_world(ch, arg)) ||
           IS_NPC(victim) ||
           strcmp(capitalize(arg),victim->name) != 0))
        {
          set_char_color(AT_IGNORE, ch);
          ch_printf(ch,"No player exists by that"
                    " name.\n\r");
          return;
        }

      if(victim)
        {
          strcpy(capitalize(arg),victim->name);
        }

      if (!check_parse_name( capitalize(arg), TRUE ))
        {
          set_char_color( AT_IGNORE, ch );
          send_to_char( "No player exists by that name.\n\r", ch );
          return;
        }

      /* If its valid and the list size limit has not been */
      /* reached create a node and at it to the list	     */
      if(i < MAX_IGN)
        {
          IGNORE_DATA *new;
          CREATE(new, IGNORE_DATA, 1);
          new->name = STRALLOC(capitalize(arg));
          new->next = NULL;
          new->prev = NULL;
          LINK(new, ch->pcdata->first_ignored,
               ch->pcdata->last_ignored, next, prev);
          set_char_color(AT_IGNORE, ch);
          ch_printf(ch,"You now ignore %s.\n\r", new->name);
          return;
        }
      else
        {
          set_char_color(AT_IGNORE, ch);
          ch_printf(ch,"You may only ignore %d players.\n\r",
                    MAX_IGN);
          return;
        }
    }
}

/*
 * This function simply checks to see if ch is ignoring ign_ch.
 * Last Modified: October 10, 1997
 * - Fireblade
 */
bool is_ignoring(CHAR_DATA *ch, CHAR_DATA *ign_ch)
{
  IGNORE_DATA *temp;

  if(IS_NPC(ch) || IS_NPC(ign_ch))
    return FALSE;

  for(temp = ch->pcdata->first_ignored; temp; temp = temp->next)
    {
      if(nifty_is_name(temp->name, ign_ch->name))
        return TRUE;
    }

  return FALSE;
}

/* Version info -- Scryn */

void do_version(CHAR_DATA* ch, char* argument)
{
  if(IS_NPC(ch))
    return;

  set_char_color(AT_YELLOW, ch);
  ch_printf(ch, "SMAUG %s.%s\n\r", SMAUG_VERSION_MAJOR, SMAUG_VERSION_MINOR);

  if(IS_IMMORTAL(ch))
    ch_printf(ch, "Compiled on %s at %s.\n\r", __DATE__, __TIME__);

  return;
}

/***************************************************************************
*     Shows mana and blood (if vampire) requirements to cast a spell.      *
*          Created by Desden, el Chaman Tibetano - Jun 1999                *
* Snippets page: http://luisso.net/smaug_snippets.htm *
*                Email: jose@luisso.net                          *
***************************************************************************/
void do_mana( CHAR_DATA *ch, char *argument)
{
  SKILLTYPE *skill=NULL;
  char arg1[MAX_INPUT_LENGTH];
  int sn;
  int col = 0;

  argument=one_argument(argument, arg1);

  if (IS_NPC(ch))
    {
      send_to_char("Mobs cannot use this command.\n\r", ch);
      return;
    }

  if (arg1[0]=='\0')
    {
      if(IS_VAMPIRE(ch))
        send_to_char("Syntax: blood all\n\r        blood <spell>\n\r",ch);
      else
        send_to_char("Syntax: mana all\n\r        mana <spell>\n\r",ch);
      return;
    }

  if(!strcmp(arg1,"all"))
    {
      set_pager_color(AT_YELLOW,ch);

      if(IS_VAMPIRE(ch))
        send_to_pager("                         BLOOD REQUIRED TO CAST\n\r", ch);
      else
        send_to_pager("                         MANA REQUIRED TO CAST\n\r", ch);

      send_to_pager("                        -----------------------\n\r", ch);

      for ( sn = 0; sn < top_sn ; sn++ )
        {
          skill=get_skilltype(sn);
          if(ch->pcdata->learned[sn] < 1 ||
              !skill->name || !skill->min_mana )
            continue;

          if(ch->level>=skill->skill_level[ch->class]  )
            {
              if(IS_VAMPIRE(ch))
                {
                  if(ch->pcdata->condition[COND_BLOODTHIRST] >= BLOOD)
                    pager_printf_color(ch, "&Y%-22.22s:%4d   ",
                                       skill->name, BLOOD);
                  else
                    pager_printf_color(ch, "&R%-22.22s:%4d   ",
                                       skill->name, BLOOD);
                }
              else
                {
                  if(ch->mana >= MANA)
                    pager_printf_color(ch, "&Y%-22.22s:%4d   ", skill->name, MANA );
                  else
                    pager_printf_color(ch, "&R%-22.22s:%4d   ",
                                       skill->name, MANA );
                }

              if(++col % 3 == 0)

                pager_printf(ch,"\n\r");

            }
        }

      pager_printf(ch,"\n\r");
    }

  else

    {
      if((sn =skill_lookup( arg1)) > 0)
        {
          skill=get_skilltype(sn);

          if(!skill->min_mana)
            {
              ch_printf(ch, "%s, '%s' doesn't use %s points.\n\r", ch->name, skill->name, IS_VAMPIRE(ch)?"blood":"mana");
              return;
            }

          if(ch->pcdata->learned[sn] < 1)
            {
              if (  ch->level < skill->skill_level[ch->class]  )
                {
                  send_to_char( "You have not enough level to cast it.\n\r", ch );
                  return;
                }
              else
                {
                  send_to_char("You must practice a spell before using it.\n\r",ch);
                  return;
                }
            }

          pager_printf(ch,"You need %d %s points to cast '%s' with success.\n\r",IS_VAMPIRE(ch)?BLOOD:MANA,IS_VAMPIRE(ch)?"blood":"mana", skill->name);
        }
      else
        ch_printf(ch, "That is not a spell or a skill.\n\r");
    }
  return;
}