pdirt/data/
pdirt/data/HELP/
pdirt/data/HELP/0/
pdirt/data/HELP/F/
pdirt/data/HELP/G/
pdirt/data/HELP/H/
pdirt/data/HELP/J/
pdirt/data/HELP/K/
pdirt/data/HELP/O/
pdirt/data/HELP/Q/
pdirt/data/HELP/R/
pdirt/data/HELP/U/
pdirt/data/HELP/V/
pdirt/data/HELP/Y/
pdirt/data/HELP/Z/
pdirt/data/MESSAGES/
pdirt/data/POWERINFO/
pdirt/data/WIZ_ZONES/
pdirt/drv/
pdirt/drv/bin/
pdirt/drv/compiler/converter/
pdirt/drv/compiler/libs/
pdirt/drv/compiler/scripts/
pdirt/drv/include/AberChat/
pdirt/drv/include/InterMud/
pdirt/drv/include/machine/
pdirt/drv/src/InterMud/
pdirt/drv/src/Players/
pdirt/drv/utils/UAFPort/
pdirt/drv/utils/dnsresolv/
pdirt/drv/utils/gdbm/
#define MOBILE_C
/* Commenting of functions started 8 January 1998 - Marty*/
#include "kernel.h"
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/socket.h>
#include "log.h"
#include "objsys.h"
#include "hate.h"
#include "oflags.h"
#include "mflags.h"
#include "cflags.h"
#include "sflags.h"
#include "lflags.h"
#include "pflags.h"
#include "quests.h"
#include "sendsys.h"
#include "timing.h"
#include "mobile.h"
#include "communicate.h"
#include "jmp.h"
#include "rooms.h"
#include "parse.h"
#include "wizlist.h"
#include "bprintf.h"
#include "flags.h"
#include "wizard.h"
#include "misc.h"
#include "fight.h"
#include "mud.h"
#include "commands.h"
#include "uaf.h"
#include "zones.h"
#include "special.h"
#include "questpoints.h"
#include "quest.h"
#include "tables.h"
#ifdef GROUP
#include "party.h"
void setpscore (int pl, int newsc);
#endif

/*****************************************************************************
 ** GLOBAL VARIABLES
 *****************************************************************************/
extern char *WizLevels[];
static void _userlist (char mode);
char *make_here (int num);

/** XPLEV  : returns the real player level of a player, holding into account that
 **          the player can be assuming a mortal form.
 ** RETURNS: Player level
 **/
int xplev(int plr)
{   if (plr >= max_players)
       return plev(plr);
       
    if (players[plr].defrob != NULL)
        return players[plr].defrob->real_level;
        
    return plev(plr);
}

#ifdef GROUP
/** SETPSCORE: this function replaces the macro in mudmacros.h when the mud
 **            uses the grouping/party system. It will share all possitive
 **            points with other members of a group. Negative points are only
 **            for the player who received them.
 ** RETURNS  : nothing.
 **/
void setpscore (int pl, int newsc)
{
   if (pl >= max_players)
   {   pscore(pl) = newsc;
   } 
   else
   { /* check if the player is in a group to see if points need to be shared or
      * not 
      */
     if (!IN_GROUP(pl))
     {   pscore(pl) = newsc;
     } 
     else
     {  /* We need to share points, then lets first see how many points should
         * be shared by substracting the old score from the new 
         */
        int wonsc = newsc-pscore(pl);
       
        /* The gained score should be greater than 0, because we only share 
         * won points and not lost points. If we did, it would mean that if
         * one member dies, he shares the loss with all players, making it
         * (the dying) easier on him.
         */ 
        if (wonsc > 0)
        {   int plx;
            int totalsh = P_GROUP_SHARES(pl) == 0 ? 1 : P_GROUP_SHARES(pl);

            /* We have the amount of shares in the group, now go through
             * the whole group and assign the points.
             */
            for (plx = 0; plx < max_players; plx++)
            {   if (is_in_game(plx) && P_GROUP(plx) == P_GROUP(pl))
                   pscore(plx) += ((P_SHARE(plx) * wonsc)/totalsh);
            }
            /* For statistics, add it here as well 
             */
            P_GROUP_XP(pl) += wonsc;
        }
        else
           pscore(pl) = newsc;
     }
   }
}
#endif



/** CMP_PLAYER: Compare players (for the qsort() function). This is a helper 
 **             function. 
 ** RETURNS   : the difference between the two player's levels.
 **/
int cmp_player (const void *a, const void *b)
{ return plev (*(int *)b) - plev (*(int *)a);
}


/*****************************************************************************
 ** The USERS command. Show names and locations of users. Possibly also
 ** their local host if PFL_SHUSERS is set.
 **/
A_COMMAND(usercom)
{ _userlist (0);
}


/****************************************************************************
 ** The WHO command
 **/
A_COMMAND(whocom)
{ _userlist (1);
}


/*****************************************************************************
 ** The MLEFT command. Shows the name of all mobiles that are still alive
 **/
 
#define COLUMNS (72/MNAME_LEN)  /* Calculate the maximum colomns on one row */

A_COMMAND(mleftcom)
{ char buff[64];
  int i;
  int ct;
  int zone;
  int nr;
  FILE *fp;
  char fn[512];
 
  Boolean list_all = True;
  int first = max_players;
  int last = numchars;
  
  zone = 0;
 
  /* Check if the player wants to see all mobiles left, or only the mobile's
   * who are still alive in a particulair zone.
   */ 
  if (brkword () != -1)
  {   list_all = False;
    
      /* Try to find the zone so we can determine where to start and where to
       * stop.
       */  
      if ((zone = get_zone_by_name (wordbuf)) == -1)
      {  bprintf ("No such zone: &+w%s&*\n", wordbuf);
	 return;
      }
      
      first = 0;
      last = znumchars (zone);
  }

  /* Because this output usually covers more than one page we first dump
   * the results to a file before showing it to the player, so lets open
   * a temporary file and get to it.
   */
  sprintf(fn,"%smleft.%s",TEMP_DIR,pname(mynum));

  if ((fp=fopen(fn,"w"))==NULL)
  {   fwerror(fn);
      return;
  }
   
  fprintf (fp,"&+wLive Mobiles&*\n&+w%s&*\n",DASHLINE);
  
  /* Get all mobiles, starting at the first and ending at the last. If no
   * zone name was specified, last means the last mobile, otherwise last is
   * the last mobile of that zone (see above).
   */
  for (ct = first, nr = 0; ct < last; ++ct)
  {  i = list_all ? ct : zmob_nr (ct, zone);
     
     /* check if we can see the mobile and if it's alive before adding it
      * to the list.
      */ 
     if (!EMPTY (pname (i)) && pstr (i) >= 0 &&
        (pvis (i) <= 0 || pvis (i) <= plev (mynum)))
     {  ++nr;

        /* Make it show that a mobile in that zone is invisible to
         * a certain level
         */	  
        if (pvis (i) > 0)
	    sprintf (buff, "(%s)", pname (i));
        else
	    strcpy (buff, pname (i));
	  
	fprintf (fp,"%-*s%c",
		   PNAME_LEN + 3, buff, (nr % COLUMNS) ? ' ' : '\n');
     }
  }
 
  /* End the file with a statistic and close the file
   */ 
  fprintf (fp,"\n&+w%s&*\nThere are &+w%d&* mobiles left (from &+w%d&*)\n",
	   DASHLINE, nr, last - first);
  fclose(fp);

  /* Open the file pager and show the file paged to the user. After that we
   * can safely delete the file.
   */
  read_file(fn,NULL,True,NULL);
  unlink(fn);   
}

/** PLAYER_DAMAGE: returns to total amount of damage a player can inflict,
 **                taking into account his base damage, plus the damage
 **                of a possibly wielded weapon.
 ** RETURNS: the total damage a player can inflict with one hit.
 **/
int player_damage (int player)
{ int w;
  int damage = pdam (player);
 
  /* Check if the player is wielding a weapon and if he really has it and has
   * it wielded. Sometimes this is not the case, so we have to check here.
   */ 
  if ((w = pwpn (player)) != -1 && iscarrby (w, player) && iswielded (w))
     damage += odamage (w);
  
  return damage;
}

/** PLAYER_ARMOR: returns the total amount of armour worn by a player, taking
 **               into account any armour his body may give him/her.
 ** RETURNS: Total armour of a player/mobile
 **/
int player_armor (int player)
{ int i, j;
  int armor = parmor (player);	/* The armor of the body of the player */
 
  /* run by all objects in his inventory and see which ones his has worn and
   * if he can really be wearing them.
   */ 
  for (j = 0; j < pnumobs (player) && (i = pobj_nr (j, player), 1); j++)
  { if (iswornby (i, player) && otstbit (i, OFL_ARMOR))
       armor += oarmor (i);
  }
  
  return armor;
}

/** USTATS: Shows the statistics for all players. This is the USTATS command.
 **         It shows a list with details about the players online. It shows
 **         their name, their level, if they're visible, their damage and
 **         armour and where they are in the mud.
 */
void ustats (int minlvl, int maxlvl)
{ int i, j;
  int a[256], a_len = 0;
  char buff[64];
  int usercount = 0;

  /* This is a wizard only command
   */  
  if (plev (mynum) < LVL_APPREN)
  {  erreval ();
     return;
  }
  
  /* run through all players to see which one should appear in the listing.
   * This means we have to check for players who are logging in, players who
   * are invisible to the current player and people who are linkdead.
   * If the outcome is that a player can see a certain player, then it is added
   * to the list of players to show in this listing.
   */
  for (i = 0; i < max_players; i++) 
  {  
     if ((pvis (i) > plev (mynum) && i != mynum) ||
#ifdef TCP_ANNOUNCE
        (!players[i].inp_handler && !players[i].linkdead) ||
        (plev(mynum) < LVL_SENIOR && (!players[i].iamon || players[i].linkdead)) ||
#else
        (!players[i].iamon && !players[i].linkdead) ||
#endif
        strncasecmp(pname(i), item1, strlen(item1)) ||
        (plev(i) < minlvl) || (plev(i) > maxlvl)
        )
      continue;
      
    a[a_len++] = i;
  }
 
  /* Hmm, although there is someone (the current player), the above criteria
   * caused no players to be found that should show up. So we abort here before
   * it shows nasty input.
   */ 
  if (a_len == 0) 
  { bprintf ("No one is online!\n");
    return;
  }
 
  /* We prefer our listings sorted by player level. So we sort them using the
   * default sorting routine: qsort.
   */ 
  qsort (a, a_len, sizeof (int), cmp_player);

  /* The header 
   */ 
  bprintf ("&+wLevel     Name     Status Str/Max Dam Arm Vis"
           " Idle      On For    Location\n&+w%s\n&*",MIXLINE);
 
  /* Now walk through all players that should be shown and print them to the
   * player.
   */ 
  for (j = 0; i = a[j], j < a_len; ++j)
  {   /* linkdead players dont have names. neither have players who are just
       * logging in, so we have to fake the level here. Als there is a small
       * trick in there which makes me Creator level no matter what level i am.
       * For immortals we show the level name, for mortals we show the level.
       */
      if (players[i].linkdead)
         bprintf("&+w[&+wNoLink &+w]");
      else if (!players[i].iamon) 
      { if (!EMPTY(pname(i)))
          bprintf("&+w[ &+w*tcp* &+w]");
      } 
      else if (EQ(pname(i),"Marty"))
          bprintf ("&+w[&+w%7.7s&+w]","Creator");
      else if (plev (i) < LVL_APPREN)
          bprintf ("&+w[&+w%7d&+w]", plev (i));
      else 
      {  /* Get the level name for this player 
          */
         lev2s(buff,plev(i),psex(i));
         bprintf ("&+w[&+w%7.7s&+w]&*", buff);
      }
      
      bprintf (" &+w%-*s", PNAME_LEN, EMPTY(pname(i)) ? "Undecided" : pname(i));
     
      /* It matters only for mortals which level they are.
       */ 
      if (plev(i) < LVL_APPREN) 
      { if (pfighting(i) >= 0) 
          bprintf ("&+wfgt");
	else if (psitting(i)==1) 
          bprintf ("&+wsit");
        else if (psitting(i)==2) 
          bprintf ("&+wslp");
	else if (psitting(i)==3) 
          bprintf (" &+wtr");
        else
          bprintf (" &+wup");
      } 
      else
        bprintf ("&+w---");
      
      if (plev (i) < LVL_APPREN && players[i].iamon)
        bprintf (" &+w%3d/&+w%-3d &+w%3d &+w%3d",
                 pstr (i), pmaxstrength (plev (i)),
                 player_damage (i),
                 player_armor (i));
      else
        bprintf (" &+w---/--- &+w--- ---");
      
      bprintf (pvis (i) < LVL_APPREN ? " &+w%3d" : "&+w inv", pvis (i));
      
      if (cur_player->last_cmd >= 0)
        strcpy (buff, sec_to_hhmmss (time(0) - plast_cmd(i)));
      else
        strcpy (buff, sec_to_hhmmss (time(0) + plast_cmd(i)));
      
      bprintf ("&+w%9.9s&+w%10.10s  &+w%s\n",
               buff,
               sec_to_hhmmss (time(0) - plogged_on(i)),
               (!ploc(i) ? "Unconnected" : showname (ploc (i))));
      usercount++;
  }
  bprintf ("&+w%s\n&+wA total of &+w%d&+w visible users.&*\n",MIXLINE, (long)usercount);
}

A_COMMAND(lastoncom)
{ PERSONA d;
  Boolean is_mobile;
  int b;
  char *name;
  int laston;
  int lev;
  Boolean nofinger=False;
  char host[MAXHOSTNAMELEN+1];
 
  if (brkword() == -1)
  {  bprintf("Check the last time who was on?\n");
     return;
  }
  if ((b = fpbns (wordbuf)) != -1 && seeplayer (b))
  {   is_mobile = b >= max_players;
      player2pers (&d, NULL, b);
      laston = 0;
      name = pname (b);
      lev = plev(b);
      nofinger = ststflg(b,SFL_NOFINGER);
      if (!is_mobile)
         strcpy(host,players[b].realhostname);
  }
  else if (getuaf (wordbuf, &d))
  {   is_mobile = False;
      laston = 1;
      name = d.p_name;
      lev = d.p_level;
      nofinger = tst_doublebit(&d.p_sflags,SFL_NOFINGER);
      strcpy(host,d.p_lasthost);
  }
  else
  {  bprintf ("Who's that?\n");
     return;
  }
  
  if (is_mobile)
     bprintf("You can't check when a mobile was last on!\n");
  else if (!nofinger || (nofinger && plev(mynum) >= LVL_WIZARD && lev <= plev(mynum)))
  {  if ((lev >= LVL_GOD && plev(mynum) >= LVL_GOD) || lev < LVL_GOD)
     {  bprintf("&+wName\t:&+w %s&*", name);
        bprintf("\n&+wLast on\t:&+w %s&*", (laston) ? time2ascii(d.p_last_on) : "&+wCurrently Logged on.&*");
        bprintf("\n");
     }
     else 
        bprintf("&+wName\t: &+w%s&*\n&+wLast on\t:&+w Unknown.\n",name);

     if (plev(mynum) >= LVL_ARCHWIZARD)
        bprintf("&+wlast on from host: &+w%s\n",host);
  }
  else
     bprintf("%s's last on time can't be checked by you.\n",name);
} 

/* The STATS command */
A_COMMAND(showplayer)
{ extern char *Mflags[];     /* For Behaviour of Mobiles Dump */
  char buff[80];
  char host[MAXHOSTNAMELEN+1];
  PERSONA d;                 /* If player is not on we need to search the uaf*/
  int b;
  int max_str;
  int i, j, w=-1, armor;
  char *title, *name;
  Boolean in_file, is_mobile;

  if (!ptstflg (mynum, PFL_STATS))
  {  erreval ();
     return;
  }

  if (brkword () == -1)
  {  ustats (LVL_MIN, LVL_MAX);
     return;
  }
 
  /* Get player data */
  if ((b = fpbns (wordbuf)) != -1 && seeplayer (b))
  {  in_file = False;
     is_mobile = (b >= max_players);
     player2pers (&d, NULL, b);
     name = pname (b);
     title = is_mobile ? NULL : ptitle (b);
     /*d.p_home = find_loc_by_id (is_mobile ? ploc_reset (b) : phome (b));*/
     strcpy(d.p_home, showname (is_mobile ? ploc_reset (b) : phome (b)));
     max_str = is_mobile ? pstr_reset (b) : maxstrength (b);
     if (!is_mobile)
     {   if (plev(mynum) < LVL_ARCHWIZARD)
             strncpy(host,players[b].hostname,MAXHOSTNAMELEN);
         else
             strncpy(host,players[b].realhostname,MAXHOSTNAMELEN);
     }
  }
  else if (getuaf (wordbuf, &d))
  {  in_file = True;
     is_mobile = False;
     title = d.p_title;
     name = d.p_name;
     max_str = pmaxstrength (d.p_level);
     if (plev(mynum) >= LVL_ARCHWIZARD)
         strncpy(host,d.p_lasthost,MAXHOSTNAMELEN);
     else
         find_fake_host_name(d.p_name,d.p_lasthost,host);
  }
  else
  {  bprintf ("Who's that?\n");
     return;
  }
  
  if(d.p_level >= LVL_MAX)
  {  bprintf("Who's that?\n");
     return;
  }
 
  if (is_mobile)
  {   if (!can_manipulate(mynum,b) )
      {   bprintf("You can't see %s %s status, %s is out of your reach.\n",
                  d.p_name, his_or_her(b), psex(b) ? "she" : "he");
          return;
      }
  }
  bprintf ("&+w[&+w%-13s&+w]&+w=============================================================",name );
  if (!is_mobile)
  {  bprintf ("\n&+wTitle      &+w:&* %s", make_title (title, "<name>"));
     bprintf ("\n&+wEmail      &+w:&+w %s", (tst_doublebit(&d.p_sflags,SFL_NOFINGER)) ?
                                     "Private" : d.p_email);
     bprintf ("\n&+wScore      &+w:&* %-7d             &+wLevel &+w:&* %d", d.p_score,d.p_level);
     bprintf ("\n&+wQuestpoints&+w:&* %-2d",d.p_questpoints);
  }
  
  bprintf ("\n&+wStrength   &+w: &+w%d&+w/%d"
           "\n&+wDamage     &+w:&* %d", d.p_strength, max_str, d.p_damage);
  
  if (!in_file && (w = pwpn (b)) != -1 && iscarrby (w, b) && iswielded (w))
  {   int w_damage = is_mobile ? odamage (w) / 2 : odamage (w);
      
      bprintf (" + %s(%d) = %d",
	       oname (w), w_damage, w_damage + d.p_damage);
  }
  
  bprintf ("\n&+wArmor      &+w:&* %d", armor = d.p_armor);
  if (!in_file)
  {  for (j = 0; j < pnumobs (b) && (i = pobj_nr (j, b), 1); j++)
     {  if (iswornby (i, b) && otstbit (i, OFL_ARMOR))
        {  armor += oarmor (i);
	   bprintf (" + %s(%d)", oname (i), oarmor (i));
	}
     }
     if (armor != d.p_armor)
	bprintf (" = %d", armor);
  }
  
  bprintf ("\n&+wVisibility &+w:&* %d ", d.p_vlevel);
  if (is_mobile)
  {  bprintf ("\n&+wAggression &+w:&* %-3d %%      &+wSpeed &+w:&* %d", pagg (b),pspeed(b));
     bprintf ("\n&+wHates      &+w:&* %s",((i = hates_who(b)) == -1) ? "No one" : pname(i));
     bprintf ("\n&+w%s      &+w:&* %s",
	       zpermanent (pzone (b)) ? "Zone " : "Owner", zname (pzone (b)));
  }
    
  bprintf("\n&+wWimpy      &+w:&* %2d        &+wDied&+w: &*%3d    &+wTourny kills&+w  :&* %3d",d.p_wimpy, d.p_died, d.p_killed);
  
  if (exists (findroomnum(d.p_home)))
    bprintf ("\n&+wStart      &+w:&* %s \t(%s)", sdesc (findroomnum(d.p_home)), d.p_home /*xshowname (buff, d.p_home)*/);
  
  if (!in_file)
  {  bprintf ("\n&+wLocation   &+w:&* %s \t(%s)",
              sdesc (ploc (b)), xshowname (buff, ploc (b)));
      
     bprintf ("\n&+wCondition  &+w:&*");
      
     if (pfighting (b) >= 0)
	bprintf (" Fighting %s", pname (pfighting (b)));
      
     if (phelping (b) >= 0)
	bprintf (" Helping %s", pname (phelping (b)));
      
     if (psitting (b) == 1)
	bprintf (" Sitting");
     if (psitting (b) == 2)
        bprintf (" Sleeping");
     if (psitting (b) == 3)
        bprintf (" In trance");
      
     if (is_mobile)
     {  bprintf ("\n&+wBehavior   &+w:&*\n");
        show_bits ((int *) &mflags (b), sizeof (MFLAGS) / sizeof (int), Mflags);
      }
  }
  else if ((d.p_level >= LVL_GOD && plev(mynum) >= LVL_GOD) || d.p_level < LVL_GOD)
  {  bprintf ("\n&+wLast on    &+w:&* %s", time2ascii (d.p_last_on));
  }

  if (ptstflg (mynum, PFL_SHUSER) && !is_mobile)
  {  bprintf ("\n&+w%s  &+w:&* %s", in_file ? "Last Host" : "From Host",host);
  }
  
#ifdef ARENA
  if (!is_mobile)
  {   bprintf("\n&+wArena wins &+w: %d          &+wlosses&+w: %d",
              combatwins(b),combatlosses(b));
  } 
#endif

  if (d.p_sflags.b3 != 0 || d.p_sflags.b2 != 0 || d.p_sflags.b1 != 0)
  {  if (!is_mobile)
	bprintf ("\n");
     
     bprintf ("&+wVarious    &+w:&*\n");
     show_bits ((int *) &(d.p_sflags), sizeof (SFLAGS) / sizeof (int), Sflags);
  } 
  else 
     bprintf("\n");
  
  bprintf ("&+w%s\n",DASHLINE);
}


/* The MOBILE command
 */
A_COMMAND(mobilecom)
{ FILE *fp;
  char fn[512];

  int i;
  int ct;
  int zone;
  int live = 0;
  int dead = 0;
  
  Boolean list_all = True;
  int first = max_players;
  int last = numchars;
  
  zone = 0;
  if (plev (mynum) < LVL_APPREN)
  {  erreval ();
     return;
  }
  
  if (brkword () != -1)
  {  list_all = False;
      
     if ((zone = get_zone_by_name (wordbuf)) == -1)
     {  bprintf ("No such zone: %s\n", wordbuf);
        return;
     }
      
     first = 0;
     last = znumchars (zone);
  }

  sprintf(fn,"%smobile.%s",TEMP_DIR,pname(mynum));

  if ((fp = fopen(fn,"w"))==NULL)
  {  fwerror(fn);
     return;
  }  

  fprintf (fp,"&+wMobiles&*\n&+w%s&*\n",MIXLINE);
  
  if (the_world->w_mob_stop)
    fprintf (fp,"   [Currently STOPped]");
  
  for (ct = first; ct < last; ++ct)
  {  i = list_all ? ct : zmob_nr (ct, zone);
      
     fprintf (fp,"%4d %-*s %c", i + GLOBAL_MAX_OBJS, MNAME_LEN,
	       EMPTY (pname (i)) ? pname_reset (i) : pname (i),
	       ststflg (i, SFL_OCCUPIED) ? '*' : ' ');
      
     if (EMPTY (pname (i)))
     {  fprintf (fp,"<QUIT or KICKED OFF>\n");
        ++dead;
     }
     else
     {  fprintf (fp,"%s\n",xdesrm (globalbuf,ploc (i), IN_ROOM));
	  
	 if (pstr (i) < 0)
	    ++dead;
	 else
	    ++live;
     }
  }
  
  fprintf (fp,"&+w%s&*\nA total of %d live mobile(s) + %d dead = %d.\n",
	   MIXLINE,live, dead, live + dead);
	   
  fclose(fp);
  read_file(fn,NULL,True,NULL);        /* Paged dump */
  unlink(fn);
}


/* List the people in a room as seen from myself
 */
void list_people (void)
{ int i, j;
  int room = ploc (mynum);
  
  for (j = 0; j < lnumchars (room) && (i = lmob_nr (j, room), 1); j++)
  {  if (i != mynum && is_in_game (i) && seeplayer (i))
     {  /* mobile ? */
        if (i >= max_players)
        {  bprintf ("%s%s%s\n", 
                       pvis (i) > 0 ? "(" : "",
		       pftxt (i),
		       pvis (i) > 0 ? ")" : "");
	}
        else if (players[i].linkdead == True)
        {   bprintf("A stone statue of %s stands here. &+w(&+wlinkdead&+w)&*\n",
                    pname(i));
        }
	else      /* Player ? */
        {  bprintf ("%s%s%s\n",
		       pvis (i) > 0 ? "(" : "",
		       make_here (i),
		       pvis (i) > 0 ? ")" : "");
	}
	  
	if (gotanything (i) && !ststflg(mynum, SFL_NOINVEN))
	    print_inventory(i);
	
     }
  }
}

Boolean eat_out_of_fleeing(int plx, int_set *inventory)
{   int     ob;
    Boolean yesno = False;
    int_set *inv;

    if (ststflg(plx,SFL_AUTOEAT))
    {   
        if (inventory == NULL)
            inv = pinv(plx);
        else 
            inv = inventory;

        for (ob = first_obj(inv); ob != SET_END; ob = next_obj(inv))
        {   
            if (iscarrby(ob,plx) && (otstbit(ob,OFL_FOOD) || otstbit(ob,OFL_BOOZE)))
            {   eat(ob);
                if (!yesno)
                {   sendf(plx,"You frantically search your inventory for any food and munch away.\n");
                    send_msg(ploc(plx),0,pvis(plx),LVL_MAX,plx,NOBODY,
                             "%s quickly eats some food to restore %s strength.\n",
                             pname(plx),his_or_her(plx));
                     yesno = True;
                }
                send_msg(ploc(plx),MODE_NOBLIND,pvis(plx),LVL_MAX, plx, NOBODY,
                     "%s greedily devours the %s.\n", pname(mynum), oname(ob)); 
                sendf(plx,"You quickly eat the %s.\n",oname(ob));
                eat(ob);
                setpstr(plx,pstr(plx) + 12);
            }
            else if (otstbit(ob,OFL_CONTAINER))
            {  
               yesno = (yesno || eat_out_of_fleeing(plx,oinv(ob)));
            }

            if (pstr(plx) >= maxstrength(plx))
               return yesno;
        }
    }
    if (!yesno && inventory == NULL)
       sendf(plx,"You frantically search your inventory for something to eat but find nothing.\n");
    return yesno;   
}

void fleemob(int plx)
{  static char *fleemsg[] = 
   {	"%s says &+w'Yikes, I'm outta here.'&*\n",
        "%s makes a frantic attempt to flee.\n",
	"%s says &+w'It was nice talking to you, but I got to go.'&*\n",
        "%s ducks the attack and heads for one of the exits.\n",
	"%s says &+w'See ya!'\n"
   };
  
   if (!mtstflg(plx,MFL_NOTALK)) 
      sendf(ploc(plx),fleemsg[MY_RANDOM() % ARRAYSIZE(fleemsg)],pname(plx)); 
   movemob(plx);
}

/*****************************************************************************
 ** All in one function that can replace move_mobiles() and onlook(), uses
 ** one for loop instead of four.
 ****************************************************************************/
void do_move_fight(void)
{   register int plx, vict;

    for (plx = 0; plx < numchars; plx++)
    {   if (!is_in_game(plx))
           continue;

        /* Do mobile stuff */
        if (plx >= max_players)
        {   if (!ststflg(plx,SFL_OCCUPIED) && alive(plx) != -1)
            {   consid_move(plx);
                chkfight(plx);
            }
        }
        else   /* Do player stuff */
        {   if (phelping (plx) != -1)
                helpchkr (plx);
        }
        
        /* Combat control */
        if ((vict = pfighting(plx)) >= 0)
        {   /* One of the players fled from the scene */
            if (ploc(vict) != ploc(plx) || testpeace(plx))
               pfighting(plx) = pfighting(vict) = -1;
            else
            {  hit_player(plx,vict,pwpn(plx));
         
               /** "Wimpy" code, make victim flee if his
	        ** strength is less then his "wimpy" val.
                ** Mobile wimpy by Marty 1996
	        **/
	       if (pstr (vict) >= 0 && pstr (vict) < pwimpy (vict))
               {  if (eat_out_of_fleeing(vict,NULL))
                       continue;

                  if (vict < max_players)      /* Player flee */
                  {   int x = mynum;
		
		      setup_globals (vict);
                      stp = 0;
                      strbuf[0] = '\0';
	              fleecom();
	              setup_globals (x);
	           }
                   else                     
                   {   fleemob(vict);
                   }
               }
            }
        }
    }
    
    if (ocarrf (RuneSword_Obj) >= CARRIED_BY)
    {  dorune (oloc (RuneSword_Obj));
    } 
}

void consid_move (int mon)
{
  static char *underwater[] = {
    "&+wBlub blub blub&*",
    "&+wGorglll blub blub&*",
    "&+wprrrrrrrrr blub blub&*"
  };

  static char *weak[] = {
    "&+wOuch!  That hurts!&*",
    "&+wI'm telling my mommy!&*",
    "&+wOw!&*",
    "&+wLeave me alone!&*"
  };
  
  static char *medium[] = {
    "&+wHmm... I'm not so sure about this...",
    "&+wWow, you're good.",
    "&+wWhew, I need a break!",
    "&+wThis sucks."
  };
  
  static char *strong[] = {
    "&+wPuny mortal!&*",
      "&+wYou cannot defeat me!&*",
      "&+wYou shall die!&*",
      "&+wFlee, while you still can, weakling!&*",
      "&+wGee, you're funny!&*"
  };
  int plx, s, t;
  
  if (EMPTY (pname (mon)))
    return;
  
  for (plx = 0; plx < lnumchars (ploc (mon)); plx++)
  {
      if (pfighting(lmob_nr(plx, ploc(mon)) ) == mon && !mtstflg(mon,MFL_NOTALK) )
      {
	if(randperc() > 8) return;
        /* Don't talk underwater */
        if (!ltstflg(ploc(mon),LFL_IN_WATER) )
        {
	   s = pstr_reset(mon) - pstr(mon);
	   t = (int) (pstr_reset(mon) / 3);
	   if(s < (2 * t)) 
           {
	     sendf(ploc(mon), "&+w\001p%s\003&* says '&+w%s&*'\n", pname(mon),
                  strong[MY_RANDOM() % ARRAYSIZE(strong)]);
	     return;
	   } 
           else if(s < t) 
           {
	     sendf(ploc(mon), "&+w\001p%s\003&* says '&+w%s&*'\n", pname(mon),
                medium[MY_RANDOM() % ARRAYSIZE(medium)]);
	     return;
	   } 
           else 
             sendf(ploc(mon), "&+w\001p%s\003&* says '&+w%s&*'\n", pname(mon),
		     weak[MY_RANDOM() % ARRAYSIZE(weak)]);
        } 
        else
        /* Unless it is mixed with air bubbles */
             sendf(ploc(mon),"&+w\001p%s\003&* says '&+w%s&*'\n", pname(mon)  ,
                   underwater[MY_RANDOM() % ARRAYSIZE(underwater)]);
      }
    }
  
  if (pspeed(mon) > 0 && pfighting(mon) < 0) 
    if (randperc () * 6 / (10 * TIMER_INTERRUPT) < pspeed (mon))
       movemob (mon);

  if (((mtstflg (mon, MFL_THIEF) && randperc () < 20 && stealstuff (mon)))
      || ((mtstflg (mon, MFL_PICK) && randperc () < 40 && shiftstuff (mon))))
    return;
  
}

/* Handle Runesword */
void dorune (int plx)
{ int ply;
  
  if (pfighting (plx) >= 0 || testpeace (plx))
    return;
  
  for (ply = lfirst_mob (ploc (plx)); ply != SET_END; ply = lnext_mob (ploc (plx)))
    {
      
      if (ply != plx && !EMPTY (pname (ply)) &&
	  plev (ply) < LVL_APPREN && fpbns (pname (ply)) >= 0 &&
	  randperc () >= 9 * plev (plx))
	{
	  sendf (plx, "The Runesword twists in your hands, lashing out savagely!\n");
	  hit_player (plx, ply, RuneSword_Obj);
	  return;
	}
    }
}

Boolean dragget (void)
{ int l,i;
  
  if (plev (mynum) >= LVL_APPREN)
    return False;

  for (i=0; dragget_mobs[i] != -1; i++)
  {  l = dragget_mobs[i]+max_players;

     if (alive(l) != -1 && ploc(l) == ploc(mynum))
     {   bprintf("%s",dragget_msgs[i]);
         return True;
     }
  }
  return False;
}

void helpchkr (int plx)
{ int x = phelping (plx);
  
  if (!is_in_game (x))
  {
      sendf (plx, "You can no longer help.\n");
      setphelping (plx, -1);
  }
  else if (ploc (x) != ploc (plx))
  {
      sendf (plx, "You can no longer help %s.\n", pname (x));
      sendf (x, "%s can no longer help you.\n", pname (plx));
      setphelping (plx, -1);
  }
}



void movemob (int x)
{ int n, r;
  
  if (the_world->w_mob_stop)
    return;
  r = randperc () % NEXITS;		/* change this.... here chance is less if few exits */
  if ((n = getexit (ploc (x), r)) >= EX_SPECIAL)
    return;
  if (n >= DOOR)
  {
      if (state (n - DOOR) > 0)
	return;
      n = obj_loc (olinked (n - DOOR));
  }
  if (n >= 0 || ltstflg (n, LFL_NO_MOBILES) || ltstflg (n, LFL_DEATH))
    return;
  
  send_msg (ploc (x), 0, pvis (x), LVL_MAX, x, NOBODY,
	    "%s has gone %s.\n", pname (x), exits[r]);
  setploc (x, n);
  send_msg (ploc (x), 0, pvis (x), LVL_MAX, x, NOBODY,
	    "%s has arrived.\n", pname(x)); 
}

/*
 * Steal random object from random player in the same room
 * -Nicknack  Sep. 1990
 * improved by Alf Oct, 1991
 * improved by Nicknack May, 1993
 */
Boolean stealstuff (int m)
{ int p[50];			/* Room for mortals and objects */
  int i, j, k;
  int nr = 0;
  
  /* Count the number of mortals in the same room:
   */
  for (j = 0; j < lnumchars (ploc (m)) && nr < 50; j++)
    {
      i = lmob_nr (j, ploc (m));
      
      if (is_in_game (i) && i < max_players && plev (i) < LVL_APPREN)
	{
	  p[nr++] = i;
	}
    }
  if (nr == 0)
    return False;
  
  /* select a random one of those in the same room:
   */
  i = p[randperc () % nr];
  
  /* Count the number of objects he carries that we can take:
   */
  for (nr = k = 0; k < pnumobs (i) && nr < 50; k++)
    {
      j = pobj_nr (k, i);
      
      if (iscarrby (j, i))
	{
	  if (((ocarrf (j) == WORN_BY || ocarrf (j) == BOTH_BY)
	       && !mtstflg (m, MFL_SWORN))
	      ||
	      ((ocarrf (j) == WIELDED_BY || ocarrf (j) == BOTH_BY)
	       && !mtstflg (m, MFL_SWPN)))
	    continue;
	  else
	    p[nr++] = j;
	}
    }
  
  if (nr == 0)
    return False;
  
  /* Select random object from those he carries
   */
  j = p[randperc () % nr];
  
  sendf (i, "\001p%s\003 steals the %s from you!\n", pname (m), oname (j));
  
  send_msg (ploc (i), 0, LVL_MIN, LVL_MAX, i, NOBODY,
	    "\001p%s\003 steals the %s from \001p%s\003!\n",
	    pname (m), oname (j), pname (i));
  
  if (otstbit (j, OFL_WEARABLE))
    {
      setoloc (j, m, WORN_BY);
    }
  else
    {
      setoloc (j, m, CARRIED_BY);
    }
  
  if (otstbit (j, OFL_WEAPON) &&
      (pwpn (m) == -1 || odamage (pwpn (m)) < odamage (j)))
    {
      set_weapon (m, j);
    }
  return True;
}


Boolean shiftstuff (int m)
{ Boolean took = False;
  int a, b;
  int maxdam = 0, w = -1;
  int maxarm = 0, ww = -1;
  
  if (pwpn(m) != -1)
  {  w = pwpn(m);
     maxdam = odamage(w);
  }
 
  for (b = 0; b < lnumobs (ploc (m)); b++)
    {
      
      a = lobj_nr (b, ploc (m));
      
      if (!oflannel (a) && !otstbit(a,OFL_NOMGET))
	{
	  took = True;
	  
	  sendf (ploc (m), "\001p%s\003 takes the %s.\n",
		 pname (m), oname (a));
	  
	  /* Wield the best weapon, wear the best armor:
	   */
	  if (otstbit (a, OFL_WEAPON) && odamage (a) > maxdam)
	    {
	      w = a;
	      maxdam = odamage (a);
	    }
	  if (otstbit (a, OFL_ARMOR) && oarmor (a) > maxarm)
	    {
	      ww = a;
	      maxarm = oarmor (a);
	    }
	  setoloc (a, m, CARRIED_BY);
	}
      
      if (w >= 0)
	set_weapon (m, w);
      if (ww >= 0)
	{
	  setoloc (ww, m, (w == ww) ? BOTH_BY : WORN_BY);
	}
    }
  return took;
}


char * xname (char *n)
{ char *t;
  
  if (n != NULL && (t = strrchr (n, ' ')) != NULL)
    {
      return t + 1;
    }
  return n;
}



void setname (int plx)
{ register PLAYER_REC *p = cur_player;
  
  if (psex (plx))
    p->wd_them = strcpy (p->wd_her, pname (plx));
  else
    p->wd_them = strcpy (p->wd_him, pname (plx));
}

Boolean see_player (int pla, int plb)
{ if (pla < 0 || pla >= numchars)
    return False;
  if (plb == pla || plb < 0 || plb >= numchars)
    return True;
  if (pvis (plb) > 0 && plev (pla) < pvis (plb))
    return False;
  if (ststflg (pla, SFL_BLIND))
    return False;
  if (ploc (pla) == ploc (plb) && r_isdark (ploc (pla), pla))
    return False;
  return True;
}


char * see_name (int pla, int plb)
{ return see_player (pla, plb) ? pname (plb) : "Someone";
}

Boolean seeplayer (int plx)
{
  if (plx == mynum || plx < 0 || plx >= numchars)
    return True;
  if (!see_player (mynum, plx))
    return False;
  setname (plx);
  return True;
}




/* Return a player index given a target name on one of the forms:
 * 1) <player-number>
 * 2) <player-name>
 * 3) <player-name><number-in-sequence-with-that-name>
 *
 * Return -1 if not found.
 */
int find_player_by_name (char *name)
{
  char b[MNAME_LEN + 1], *p = b;
  int n, i;
  int nn;
  
  if (name == NULL || strlen (name) > MNAME_LEN)
    return -1;
  
  name = xname (name);		/* Skip the "The " if there. */
  
  while (*name != '\0' && isalpha (*name))
    *p++ = *name++;
  *p = '\0';
  
  if (isdigit (*name))
    {
      n = atoi (name);
      
      while (isdigit (*++name));
      if (*name != '\0')
	return -1;
    }
  else if (*name != '\0')
    {
      return -1;
    }
  else
    n = 1;
  
  if (*b == '\0')
    {
      
      if (n >= GLOBAL_MAX_OBJS && n < GLOBAL_MAX_OBJS + numchars
	  && is_in_game (n - GLOBAL_MAX_OBJS))
	return n - GLOBAL_MAX_OBJS;
      else
	return -1;
    }
  else
    {
      /* Try the mobiles in the players location first:
       */
      if (is_in_game (mynum))
	{
	  int m = n;
	  int loc = ploc (mynum);
	  
	  for (i = 0; i < lnumchars (loc); i++)
	    {
	      
	      if (EQ (b, xname (pname (lmob_nr (i, loc))))
		  && is_in_game (lmob_nr (i, loc))
		  && --m == 0)
		
		return lmob_nr (i, loc);
	    }
	  
	  if (m < n)
	    return -1;
	}
      
      /* Now try anyone.
       */
      
      nn = n;
      /* got an exact match? */
      for (i = 0; i < numchars; i++)
	{
	  if (EQ (b, xname (pname (i))) && is_in_game (i) && --n == 0)
	    return i;
	}
      
      n = nn;
      if (cur_player) if (cur_player->iamon)
	for (i = 0; i < numchars; i++)
	  {
	    if (!strncasecmp (b, xname (pname (i)), strlen (b)) &&
		is_in_game (i) && --n == 0)
	      return i;
	  }
    }
  
  return -1;
}



/* Find player by name, if visible to mynum:
 */
int fpbn (char *name)
{
  int n = find_player_by_name (name);
  
  return n < 0 || seeplayer (n) ? n : -1;
}


/* Find mobile's in-game index from its ID. Return -1 if not found.
 */
int find_mobile_by_id (long int id)
{
  long int x;
  
  if (id >= max_players && id < num_const_chars)
    return id;
  
  return (x = lookup_entry (id, &id_table)) == NOT_IN_TABLE
    || x < 0 || x >= numchars ? -1 : x;
}



/* Find player or mobile, return number if in game.
 * Set f to true if in file, False if in game. If exists, put
 * the data in the object pointed to by p.
 */
int find_player (char *name, PERSONA * p, Boolean * f)
{
  int plr;
  
  *f = False;
  if ((plr = fpbns (name)) >= 0)
    {
      if (!seeplayer (plr))
	return -1;
      player2pers (p, NULL, plr);
      return plr;
    }
  else if (ptstflg (mynum, PFL_UAF) != 0 && getuaf (name, p))
    {
      *f = True;
      return -2;
    }
  return -1;
}

int alive (int i)
{
  if ((pstr(i) < 0) || (EMPTY (pname (i))) || (EQ(pname(i),"Corpse")))
    return -1;
  else
    return i;
}

int wlevel (int lev)
{
  if (lev < LVL_GUEST)
    return LEV_NEG;		/* Negative level */
  if (lev < LVL_APPREN)
    return LEV_MORTAL;		/* Mortal */
  if (lev == LVL_APPREN)
    return LEV_APPRENTICE;	/* Apprentice */
  if (lev < LVL_WIZARD)
    return LEV_EMERITUS;	/* Emeriti */
  if (lev < LVL_SENIOR)
    return LEV_WIZARD;		/* Wizard */
  if (lev < LVL_COUNSEL)
    return LEV_SENIOR;
  if (lev < LVL_ARCHWIZARD)
    return LEV_COUNSEL;		/* Senior */
  if (lev < LVL_HIGHARCH)
    return LEV_ARCHWIZARD;	/* Arch wizard */
  if (lev < LVL_ADVISOR)
    return LEV_HIGHARCH;
  if (lev < LVL_DEMI)
    return LEV_ADVISOR;	/* High Arch */
  if (lev < LVL_HIGHDEMI)
    return LEV_DEMI;		/* Demi */
  if (lev < LVL_GOD)
    return LEV_HIGHDEMI;	/* High Demi */
  if (lev < LVL_MASTER)
    return LEV_GOD;		/* God */
  return LEV_MASTER;		/* Master */
}

Boolean do_okay_l (int p, int v, Boolean c)
{
  int lev_p = wlevel (p);
  int lev_v = wlevel (v);
  
  if (lev_v > lev_p && lev_p > LEV_NEG)
    {
      return False;
    }
  
  return (c || (lev_v < lev_p && lev_p > LEV_WIZARD) || lev_p >= LEV_MASTER);
}


/* Can p(layer) do XX to v(ictim) ?
 * ** prot_flag protects against it.
 */

Boolean do_okay (int p, int v, int prot_flag)
{
  return do_okay_l (xplev (p), xplev (v),
		    (prot_flag < PFL_MAX && !ptstflg (v, prot_flag)));
}


void setpsex (int chr, Boolean v)
{
  if (v)
    ssetflg (chr, SFL_FEMALE);
  else
    sclrflg (chr, SFL_FEMALE);
}


/* SET Player LOCation.
 */
void setploc (int plr, int room)
{
  
  /* First remove plr from his current location:
   */
  if (exists (ploc (plr)))
    remove_int (plr, lmobs (ploc (plr)));
  
  /* Then add him to the new room:
   */
  if (exists (room))
    add_int (plr, lmobs (room));
  
  ploc (plr) = room;
}

int ptothlp (int pl)
{
  int ct;
  
  for (ct = 0; ct < numchars; ct++)
    {
      if (ploc (ct) == ploc (pl) && phelping (ct) == pl)
	return ct;
    }
  return -1;
}

int maxstrength (int p)
{
  return pmaxstrength (plev (p));
}

char * make_here (int num)
{ static char buff[256];
  static char tbuff[512];
  register int t;
/*  int save_mynum;*/
  
  if (num >= max_players)
  {				/* mobile */
      sprintf (buff, "%s", pftxt (num));
  }
  else
  { /*
      save_mynum = real_mynum;
      setup_globals (num);
     *//* all nums were mynums */ 
      if (!psitting(num))
	{
	  build_setin(num,buff,players[num].setstand, pname(num), NULL);
	  /*build_setin(num,buff,cur_player->setstand, pname(num), NULL);*/
	  sprintf(tbuff,"%s",buff);
	}
      else if (psitting(num)==1)
        {
	  build_setin(num,buff,players[num].setsit, pname(num), NULL);
	  /* build_setin(num,buff,cur_player->setsit, pname(num), NULL);*/
 	  sprintf(tbuff,"%s",buff);
	}
      else if (psitting(num)==2)
        {
           build_setin(num,buff,players[num].setsleep, pname(num), NULL);
           /*build_setin(num,buff,cur_player->setsleep, pname(num), NULL);*/
           sprintf(tbuff,"%s",buff);
        }
      else if (psitting(num)==3)
        {
            build_setin(num,buff,players[num].settrance , pname(num), NULL);
            /*build_setin(num,buff,cur_player->settrance , pname(num), NULL);*/
            sprintf(tbuff,"%s",buff);
        }
      if (ststflg(num, SFL_GLOWING))
        strcat(tbuff," (providing light)");

      for (t = 0; t != PNAME_LEN + TITLE_LEN + 20; t++)
	if (tbuff[t] == '%' && tbuff[t + 1] == 'n')
	  {
	    tbuff[t] = '%';
	    tbuff[t + 1] = 's';
	  }
      
      sprintf (buff, tbuff, pname (num));
  /*
      setup_globals (save_mynum);
   */
  }
  
  return buff;
}


char * make_title (char *title, char *name)
{
  static char buff[PNAME_LEN + TITLE_LEN + 20];
  
  sprintf (buff, (EMPTY (title) ? "%s the Unknown" : title), name);
  return buff;
}

char * std_title (int level, Boolean sex)
{
  extern char *MLevels[];
  extern char *FLevels[];
  extern char *FWizLevels[];
  extern char *WizLevels[];
 
  static char buff[TITLE_LEN + 10];
  int wl = wlevel (level);
  
  strcpy (buff, "%s the ");
 
  switch (wl)
    {
    case LEV_NEG:
      strcat (buff, "Mobile");
      break;
    case LEV_MORTAL:
    case LEV_APPRENTICE:
      strcat (buff, (sex ? FLevels : MLevels)[level]);
      break;
    default:
      strcat (buff, sex ? FWizLevels[wl] : WizLevels[wl]);
    }
  return buff;
}


/* Try to reset a mobile.
 */
Boolean reset_mobile (int m)
{
  int loc;
  
  setpstr (m, pstr_reset (m));
  setpvis (m, pvis_reset (m));
  setpflags (m, pflags_reset (m));
  setmflags (m, mflags_reset (m));
  setsflags (m, sflags_reset (m));
  setpmsk1 (m, 0);
  setpmsk2 (m, 0);
  setpmsk3 (m, 0);
  setpsitting (m, 0);
  setpfighting (m, -1);
  setphelping (m, -1);
  setpwpn (m, -1);
  setplev (m, plev_reset (m));
  setpagg (m, pagg_reset (m));
  setpspeed (m, pspeed_reset (m));
  setpdam (m, pdam_reset (m));
  setparmor (m, parmor_reset (m));
  setpwimpy (m, pwimpy_reset (m));

  clear_hate(m);
 
  if (EMPTY (pname (m)))
    setpname (m, pname_reset (m));
  
  if ((loc = find_loc_by_id (ploc_reset (m))) == 0)
    {
      setpstr (m, -1);
      setploc (m, dead_loc);
      return False;
    }
  else
    {
      setploc (m, loc);
      return True;
    }
}



void p_crapup (int player, char *str, int flags)
{
  int m = real_mynum;
  
  if (pfighting(player) > 0)
  {   m = pfighting(player);
      setpfighting(player,-1);
      setpfighting(m,-1);
      m = real_mynum;
  }

  setup_globals (player);
 
  if (player > max_players && player < numchars)
       crapup(str, flags | CRAP_UNALIAS | CRAP_RETURN); 
  else 
       crapup (str, flags | CRAP_RETURN );
  setup_globals (m);
}

void crapup (char *str, int flags)
{
  if ((flags & CRAP_UNALIAS) != 0)
    { if (pfighting(mynum) >= 0)
         setpfighting(mynum,-1);

      unalias (real_mynum);
      unpolymorph (real_mynum);
      return;
    }
  xcrapup (str, (flags & CRAP_SAVE) != 0);
  if ((flags & CRAP_RETURN) == 0)
    {
      longjmp (to_main_loop, JMP_QUITTING);
    }
}

void xcrapup (char *str, Boolean save_flag)
{ int i,temp;
  
  if (cur_player->aliased)
    {
      bprintf ("%s\n", str);
      unalias (real_mynum);
      return;
    }
  else if (cur_player->polymorphed >= 0)
    {
      bprintf ("%s\n", str);
      unpolymorph (real_mynum);
      return;
    }

  if (mob_fun(real_mynum) != NULL && !players[real_mynum].linkdead)
  {   param_s.plx = real_mynum;
      mob_fun(real_mynum)(E_STORE);
  }

#ifdef GROUP
  if (IN_GROUP(real_mynum))
  {   int plx=mynum;
      setup_globals(real_mynum);
      pleave();
      setup_globals(plx);
   }
#endif

  temp = real_mynum;
  clear_mobs_hate(mynum);
  for(i=0;i<max_players;i++)
  {
     if (players[i].converse.active == True)
        if (players[i].converse.talking_to == temp)
        {   sendf(i,"%s has left, you can no longer converse with them.\n",
                  pname(temp));
            players[i].converse.talking_to = -1;
            players[i].converse.active = False;
            strcpy(players[i].prompt, players[i].converse.old_prompt);
        }

     if (players[i].i_follow == temp)
     {  sendf(i,"%s died, you can't follow %s anymore.\n",
                 pname(temp), him_or_her(temp));
        players[i].i_follow = -1;
     }
  }

  setup_globals(temp);

  if (cur_player->defrob != NULL)
  {   setplev(mynum,cur_player->defrob->real_level);
      pflags(mynum).b1 = cur_player->defrob->real_pflags.b1;
      pflags(mynum).b2 = cur_player->defrob->real_pflags.b2;
      pflags(mynum).b3 = cur_player->defrob->real_pflags.b3;
      pmask(mynum).b1 = cur_player->defrob->real_mask.b1;
      pmask(mynum).b2 = cur_player->defrob->real_mask.b2;
      pmask(mynum).b3 = cur_player->defrob->real_mask.b3;
      setpdam(mynum,cur_player->defrob->real_dam);
      setparmor(mynum,cur_player->defrob->real_armor);
      setpstr(mynum,pmaxstrength(plev(mynum)));
      setpvis(mynum,cur_player->defrob->real_vis);
      free(cur_player->defrob);
      cur_player->defrob = NULL;
  }
 
  if (cur_player->editor.active == True)
  {  Line *s, *p;
     p = cur_player->editor.start;

     while (p != NULL)
     {  s = p->next;
        free(p->line);
        free(p);
        p = s;
     }
     cur_player->editor.active = False;
     cur_player->editor.current = NULL;
     strcpy(cur_player->prompt,cur_player->editor.old_prompt);
  } 

  loseme (save_flag);
  if (str != NULL)
    {
      bprintf ("\n%s\n\n%s\n\n%s\n", DASHLINE, str, DASHLINE);
      bflush ();
    }
  
  remove_entry (mob_id (mynum), &id_table);
 
  shutdown(cur_player->fil_des,0); 
  cur_player->iamon = False;
  setpname (mynum, "");
  setploc (mynum, 0);
  quit_player ();		/* So we don't get a prompt after exit */
}

/* Remove me from the game. Dump objects, send messages, save etc..
 * May only be used after has been called.
 */
void loseme (Boolean save_flag)
{
  char b[80];
  int x, y ;
  Boolean emp = EMPTY (pname (mynum));
  
  if (cur_player->aliased || cur_player->polymorphed >= 0)
    return;
  
  if (cur_player->iamon)
  {
      if (!emp)
      {
	  
	  if (save_flag)
	    save_player(mynum,True);
	  
	  if ((x = the_world->w_lock) > 0
	      && (y = plev (mynum)) >= x && y >= LVL_APPREN)
	    bprintf ("\nDon't forget the game is locked....\n");
	  
	  send_msg (DEST_ALL, MODE_BRACKET|MODE_QUIET, Max(pvis (mynum), LVL_APPREN),
		    LVL_MAX, mynum, NOBODY,
		    "%s has departed from MUD in %s &+w(%s)",
		    pname (mynum), sdesc (ploc (mynum)), xshowname (b, ploc (mynum)));
	  
	  
      }
      
      dumpitems ();
      if (!emp)
      {  
          if (plev(mynum) < LVL_APPREN)
	     mudlog ("CONN: Exit %s [lev %d, scr %d, str %d/%d][fd: %d]", pname(mynum),
		   plev (mynum), pscore (mynum),pstr(mynum), maxstrength(mynum),cur_player->fil_des);
          else if (pvis(mynum) < (LVL_GOD+1))
             mudlog ("CONN: Exit %s [lev %d][fd: %d]",pname(mynum),plev(mynum),cur_player->fil_des);
	  
	  setpname (mynum, "");
	  setploc (mynum, 0);
      }
      
      cur_player->iamon = False;
      
      snoop_off (mynum);
    }
}

char * lev2s (char *b, int lvl, Boolean x)
{ extern char *FLevels[];
  extern char *MLevels[];
  extern char *FWizLevels[];
  extern char *WizLevels[];

  if (lvl <= LVL_APPRENTICE)
  {  if (x)
        strcpy(b,FLevels[lvl]);
     else
        strcpy(b,MLevels[lvl]);
  }
  else if (lvl > LVL_APPREN && lvl < LVL_MAX)
  {   int wlev = wlevel(lvl);

      if (x)
          strcpy(b,FWizLevels[wlev]);
      else
          strcpy(b,WizLevels[wlev]);
  }
  else
     sprintf(b,"Level %d",lvl);
  strcat(b," ");
  return b;
}

int tscale (void)
{
  int a = 0;
  int b;
  
  for (b = 0; b < max_players; b++)
    if (is_in_game (b) && plev (b) < LVL_APPREN)
      a++;
  if (a < 2)
    return 1;
  else
    return (a > 9 ? 9 : a);
}

Boolean chkdumb (void)
{
  if (!ststflg (mynum, SFL_DUMB))
    return False;
  bprintf ("You are mute.\n");
  return True;
}

Boolean chkcrip (void)
{
  if (!ststflg (mynum, SFL_CRIPPLED))
    return False;
  bprintf ("You are crippled.\n");
  return True;
}

Boolean chksitting (void)
{
  if (!psitting (mynum))
    return False;
  bprintf ("You'll have to stand up, first.\n");
  return True;
}


void calib_player (int pl)
{
  extern char *MLevels[];
  extern char *FLevels[];
  int b = 1,qp;
  int oldlevel;

  if (pl >= max_players || !players[pl].iamon || players[pl].aliased || 
      players[pl].polymorphed >= 0) 
     return;

  if (pl < max_players && wlevel(xplev(pl)) == LEV_WIZARD && q_all(&qflags(pl)))
  {   char *levstr = "";
      extern char *FWizLevels[];
      extern char *WizLevels[];

      if (players[pl].defrob != NULL)
      {   players[pl].defrob->real_level = LVL_SENIOR;
          set_xpflags(players[pl].defrob->real_level, &(players[pl].defrob->real_pflags), 
                      &(players[pl].defrob->real_mask) );
      }
      else
      {   setplev(pl,LVL_SENIOR);
          setptitle(pl, std_title(b, psex(pl)));
          set_xpflags(plev(pl), &pflags(pl), &pmask(pl) );
      }
      update_wizlist(pname(pl), wlevel(plev(pl)));

      levstr = psex(pl) ? FWizLevels[wlevel(xplev(pl))] : WizLevels[wlevel(xplev(pl))];
      
      mudlog("GAME: %s has qualified for %s",pname(pl),levstr);
      sendf(pl,"&+wCongratulations, you qualified for %s!&*\n", levstr);
      send_msg(DEST_ALL,MODE_QUIET|MODE_BRACKET,LVL_APPREN,LVL_MAX,pl,NOBODY,
          "%s is now %s!",pname(pl),levstr); 
  }
  else if (plev(pl) >= LVL_APPREN)
     return;
      
  oldlevel = plev(pl);   
  b = levelof(pscore(pl), plev(pl) );
  qp = qp_for_level(b);

  if (b == LVL_APPREN && oldlevel < LVL_SIXTEEN)
      b = LVL_SIXTEEN;

  if (qpoints(pl) < qp)
  {  Boolean go_on = False;

     for (b -= 1;b > plev(pl); b--)
     {  qp = qp_for_level(b);
        if (qpoints(pl) >= qp)
           go_on = True;
     }
     if (!go_on)
        return;
  } 

  if (b == LVL_APPREN && !q_required(&qflags(pl)))
     return;
  
  if (b == LVL_APPREN && players[pl].defrob != NULL)
     return;

  if (b != oldlevel && oldlevel > 0) 
  {  
      setplev(pl, b);                      
      setptitle(pl, std_title(b, psex(pl)));
      mudlog("%s went from level %d to level %d.",pname(pl),oldlevel,b);
      if (b > oldlevel)
      {
         sendf(pl,"&+wCongratulations, %s!&*\n", make_title(ptitle(pl), pname(pl)) );
      } 
      else 
         sendf(pl,"You are now %s\n", make_title( ptitle(pl), pname(pl)));
      
      send_msg(DEST_ALL,MODE_QUIET|MODE_BRACKET,LVL_APPREN,LVL_MAX,pl,NOBODY,
               "%s went from level %d to %d",pname(pl),oldlevel,b );
      
      /*saveallcom();i*/ /* I dont think a saveall is needed */
      save_player(pl,True);
      
      setpstr(pl, maxstrength(pl));
      
      if (b > oldlevel)
      switch (b) {
      case LVL_FOUR: 
		set_doublebit(&pflags(pl), PFL_EMOTE);
		set_doublebit(&pflags(pl), PFL_TITLES);
		sendf(pl,"You may now emote and change your own title.\n");
		break;
      case LVL_SEVEN: 
		sendf(pl,"Welcome %s, you may now use the POSE command.\n",
                      (psex(pl) ? FLevels : MLevels)[LVL_SEVEN]);
		break;
      case LVL_EIGHT:
		sendf(pl,"You can now use the SCAN command to probe adjacent rooms.\n");
		break;
      case LVL_TEN: 
		sendf(pl,"Nice work, %s. You may now use the BANG command.\n",
                      (psex(pl) ? "Dudette" : "Dude") );
		break;
      case LVL_TWELVE: 
		set_doublebit(&pflags(pl), PFL_CANTRANCE);
		sendf(pl,"You are now trained enough to use the trance as a form of heal.\n");
		break;
      case LVL_FIFTEEN: 
		set_xpflags(LVL_FIFTEEN, &pflags(pl) , &pmask(pl) );
		sendf(pl,"My complements %s! You may now EMOTE anywhere.\n",
                      (psex(pl) ? FLevels : MLevels)[LVL_FIFTEEN]);
		break;
      case LVL_APPREN: if (cur_player->defrob != NULL)
                            break;
                            
                       set_xpflags(LVL_APPREN, &pflags(pl), &pmask(pl) );
                       /* Player can't be in a group anymore. */ 
                       if (IN_GROUP(pl))
                       {   if (P_GROUP_LEADER(pl) == pl)
                           {  int plx;
                             
			      setup_globals(pl);
                              /* Drop the whole group.   */
                              sprintf(globalbuf,"Party is disbanded");
                              partyannounce(globalbuf);
                              for (plx =0 ; plx < max_players; plx++)
                              {  
                                 if (is_in_game(plx) && (P_GROUP(plx) == P_GROUP(pl)) && plx != pl)
                                 {  
                                     leaveplayer(plx);
                                 }
                              }  /* Now only the leader is in the group */
                              P_GROUP_SHARES(pl) -= P_SHARE(pl);
                              P_SHARE(pl) = 0;
                              free(P_GROUP(pl));       /* Loose allocated mem */
                              P_GROUP(pl) = NULL;
                           }
                           else
                           {   setup_globals(pl); 
                               sprintf(globalbuf,"%s has left the party",pname(pl));
                               partyannounce(globalbuf);
                               leaveplayer(pl);
                           }
                       }
                       sendf(DEST_ALL,"&+wTrumpets sounds praise %s the new Wizard!&+w\n",
                             pname(pl) );
                       sendf(pl, "\001f%s\003",GWIZ);
                       update_wizlist(pname(pl), LEV_APPRENTICE);
                       break;
      default: sendf(pl,"Keep up the good work.\n");
               break;
      }
  }
/*
  if (pstr(pl) > (b = maxstrength(pl)))
     setpstr(pl,b);
*/
}


void calibme ()
{
  calib_player (mynum);
}



void destroy_mobile (int mob)
{
  setploc (mob, dead_loc);
}



int levelof (int score, int lev)
{
  int i;
  
  if (lev > LVL_APPREN || lev < LVL_ONE)
    return lev;
  for (i = LVL_APPREN; i > LVL_GUEST; i--)
    if (score >= levels[i])
      return i;
  return 0;
}

Boolean check_busy (int plx)
{
  if (ststflg (plx, SFL_BUSY))
    {
      bprintf ("%s is busy, try later!\n", pname (plx));
      return True;
    }
  return False;
}

/***************************************************************************
 ** Flexible prompting routine. Builds a prompt everytime it's needed,
 ** giving up to date information.
 ** Author: Marty 1997
 **************************************************************************/
char *build_prompt(int plx)
{   int     i,len;
    char    *format;
    static  char buffer2[3*PROMPT_LEN];   /* Second step build buffer */
    static  char buffer[3*PROMPT_LEN];    /* First step build buffer */
    char    *p = buffer;
    Boolean fightmsg = False;

    if (plx < 0 || plx >= max_players)
       return ">";

    format = players[plx].prompt;

    if (format == NULL || buffer == NULL)
        return NULL;

    len = strlen(format);

    *p = '\0';

    if (pvis(plx) > 0)                   /* The () around an invis prompt */
    {   strcat(p,"&+w(");
        p += strlen(p);
    }

    if (players[plx].aliased)
    {   strcat(p,"&+w@&*");
        p += strlen(p);
    } 

    for (i = 0; i < len && strlen(buffer2) < (PROMPT_LEN *2) ; i++)
    {   if (format[i] == '%')
        {  switch (format[i+1]) {
           case '%' : *p = format[i++];
		      break;
	   case 'h' : if (pstr(plx) == 0)
                         sprintf(p,"&+w0");
		      else
		         sprintf(p,"&+%c%d",(maxstrength(plx) / pstr(plx) >= 3 || pstr(plx) < 0) ?
			         'R' : (maxstrength(plx) / pstr(plx) >= 2) ? 'Y' : 'G',
			         pstr(plx));
		      p += strlen(p);
		      i++;
		      fightmsg = True;
		      break;
           case 'H' : sprintf(p,"%d",maxstrength(plx));
		      p += strlen(p);
		      i++;
		      break;
           case 'S' :
	   case 's' : sprintf(p,"%d",pscore(plx));
		      p += strlen(p);
		      i++;
		      break;
           case 'Q' : sprintf(p,"%d",qp_for_level(plev(plx)));
                      p += strlen(p);
                      i++;
                      break;
	   case 'q' : sprintf(p,"%d",qpoints(plx));
		      p += strlen(p);
		      i++;
		      break;
           case 'D' :
           case 'd' :
           {   int dam;
               int obdam = (pwpn(plx) == -1 || pwpn(plx) > numobs) ? 0 : odamage(pwpn(plx));

               dam = pdam(plx) + obdam;
               if (dam < 10)
                   sprintf(p,"D:&+w.&*");
               else if (dam < 20)
                   sprintf(p,"D:&+w+&*");
               else if (dam < 32)
                   sprintf(p,"D:&+w*&*");
               else
                   sprintf(p,"D:&+wo&*");
               p += strlen(p);
               i++;
               break;
           }
           case 'A':
           case 'a':
           {   int plxarm = player_armor(plx);

               if (plxarm < 10)
                  sprintf(p,"A:&+w.&*");
               else if (plxarm < 25)
                  sprintf(p,"A:&+w+&*");
               else if (plxarm < 48)
                  sprintf(p,"A:&+w*&*");
               else 
                  sprintf(p,"A:&+wo&*");
               p += strlen(p);
               i++;
               break;
           }
	   default:
	   }
        }
        else
        {  *p = format[i];
           p++;
        }
    }

    if (pvis(plx) > 0)
       sprintf(p,"&+w)&*");
    else
       sprintf(p,"&*"); 

    p += strlen(p);
    *p = '\0';

    buffer2[0] = '\0';

    if (pfighting(plx) >= 0 && !fightmsg)
    {  if (pstr(plx) > 0)
          sprintf(buffer2,"&+w[&+%c%d&+L/&+w%d&+w]",(maxstrength(plx) / pstr(plx) >= 3) ?
	         'R' : (maxstrength(plx) / pstr(plx) >= 2) ? 'Y' : 'G',
	         pstr(plx),maxstrength(plx));
       else
          sprintf(buffer2,"&+w[&+w0&+L/&+w%d&+w]",maxstrength(plx));
    }
    else
      return buffer;    /* Not going to strcat to nothing, only takes time*/

    strcat(buffer2,buffer);
    return buffer2;
}

int vicf2 (int fl, int i)
{
  int plr;
  
  if (ltstflg (ploc (mynum), LFL_NO_MAGIC) != 0 && plev (mynum) < LVL_APPREN)
    {
      bprintf ("Something about this location has drained your mana.\n");
      return -1;
    }
  if (fl >= SPELL_VIOLENT && plev (mynum) < LVL_APPREN && testpeace (mynum))
    {
      bprintf ("No, that's violent!\n");
      return -1;
    }
  if ((plr = vicbase ()) < 0)
    return -1;
  
  if (pstr (mynum) < 10)
    {
      bprintf ("You are too weak to cast magic.\n");
      return -1;
    }

  if (plev (mynum) < LVL_APPREN)
    setpstr (mynum, pstr (mynum) - 5);
 
  i += has_magic_object(mynum);
  i /= 2;

  if (plev (mynum) < LVL_APPREN && randperc () > i * plev (mynum))
  {
      bprintf ("You fumble the magic.\n");
      if (fl == SPELL_REFLECTS)
	{
	  bprintf ("The spell reflects back.\n");
	  return mynum;
	}
      return -1;
  }

  if (plr < max_players && plr >= 0)
  {
    if (players[plr].linkdead && plev(mynum) < LVL_ARCHWIZARD)
    { bprintf("%s is linkdead and can't be affected by your actions.\n",
              pname(plr));
      return -1;
    }
  }
  
  if (plev (mynum) < LVL_APPREN)
  {   Boolean has_shield = wearsobjfrom(plr,sp_shields);

      if ((fl >= SPELL_VIOLENT) && has_shield)
	{
	  bprintf ("The spell is absorbed by %s shield!\n", his_or_her (plr));
	  return -1;
	}
  }
  bprintf ("The spell succeeds!\n");
  return plr;
}

int vichfb (int cth)
{
  int a;
  
  if ((a = vicf2 (SPELL_VIOLENT, cth)) < 0)
    return a;
  if (ploc (a) != ploc (mynum))
    {
      bprintf ("%s isnt here.\n", psex (a) ? "She" : "He");
      return -1;
    }
  return a;
}

int vichere (void)
{
  int a;
  if ((a = vicbase ()) == -1)
    return -1;
  if (ploc (a) != ploc (mynum))
    {
      bprintf ("They aren't here.\n");
      return -1;
    }
  return a;
}

int vicbase (void)
{
  int a;
  
  do
    {
      if (brkword () == -1)
	{
	  bprintf ("Who?\n");
	  return -1;
	}
    }
  while (EQ (wordbuf, "at"));
  if ((a = fpbn (wordbuf)) < 0)
    {
      bprintf ("That person isn't playing now.\n");
      return -1;
    }
  return a;
}







/* The JUMP command
 */
A_COMMAND(jumpcom)
{
  int a, b, i, j, x;
  char ms[128];
  
  if (psitting (mynum))
    {
      bprintf ("You have to stand up first.\n");
      return;
    }
  
  /* Search the jump-table for special locations..
   */
  for (a = 0, b = 0; jumtb[a]; a += 2)
    {
      if (jumtb[a] == ploc (mynum))
	{
	  b = jumtb[a + 1];
	  break;
	}
    }
  
    if (rom_fun(ploc(mynum)) != NULL)
    {   param_s.plx = mynum;
        param_s.loc = ploc(mynum);
        param_s.to  = b;
        rom_fun(ploc(mynum))(E_ONJUMP);
        if (param_s.ret != 1)
            return;
    }

  /* Are we by a pit ? If so we'll jump into it.
   */
  for (i = 0; (j = pit_jumptb[i]) != -1 && oloc (j) != ploc (mynum);i += 2)
    ;
  
  if (pit_jumptb[i] != -1)
     b = pit_jumptb[i+1];

  if (b == 0)
    {
      bprintf ("&+wWheeeeee....&*\n");
      return;
    }
  
  if ((x = carries_obj_type (mynum, Umbrella_Obj)) > -1
      && state (x) != 0)
    {
      sprintf (ms, "%s jumps off the ledge.\n", pname (mynum));
      bprintf ("You grab hold of the %s and fly down like "
	       "Mary Poppins.\n", oname (x));
    }
  else if (plev (mynum) < LVL_APPREN)
    {
      sprintf (ms, "%s makes a perfect swan dive off the ledge.\n",
	       pname (mynum));
      if (b != pit_loc)
	{
	  send_msg (ploc (mynum), 0, pvis (mynum), LVL_MAX, mynum, NOBODY, ms);
	  setploc (mynum, b);
	  bprintf ("&+wWheeeeeeeeeeeeeeeee&*       <<<<SPLAT>>>>\n"
	           "You seem to be splattered all over the place.\n");
	  crapup ("\t\tI suppose you could be scraped up with a spatula.",
		  SAVE_ME);
	  
	}
    }
  else
    sprintf (ms, "%s dives off the ledge and floats down.\n", pname (mynum));
  
  
  send_msg (ploc (mynum), 0, pvis (mynum), LVL_MAX, mynum, NOBODY, ms);
  
  setploc (mynum, b);
  
  if (iscarrby (Umbrella_Obj, mynum))
    sprintf (ms, "%s flys down, clutching an umbrella.\n", pname (mynum));
  else
    sprintf (ms, "%s has just dropped in.\n", pname (mynum));
  
  send_msg (ploc (mynum), 0, pvis (mynum), LVL_MAX, mynum, NOBODY, ms);
  
  trapch (b);
}

/****************************************************************************
 ** BOOZE and DRUNK code. Show some messages at random intervals, and count
 ** down the time untill a player is sober. Marty 1996
 ****************************************************************************/
void do_drunk(int plx)
{  if (randperc() < 15)
   {   if (pdrunk(plx) < 3)
       {  send_msg(ploc(plx),0,LVL_MIN,LVL_MAX,plx,NOBODY,
                   "\001p%s\003 feels a bit dazed.\n",pname(plx));
          sendf(plx,"You feel a bit dazed.\n");
       }
       else if (pdrunk(plx) < 8)
       {  send_msg(ploc(plx),0,LVL_MIN,LVL_MAX,plx,NOBODY,
                   "\001p%s\003 feels a bit light headed.\n",pname(plx));
          sendf(plx,"You feel a bit light headed.\n");
       }
       else if (pdrunk(plx) < 15)
       {  send_msg(ploc(plx),0,LVL_MIN,LVL_MAX,plx,NOBODY,
                   "\001p%s\003 burps loudly.\n",pname(plx));
          sendf(plx,"You burp loudly.\n");
       }
       else if (pdrunk(plx) < 24)
       {  sendf(plx,"The &+ww&+wo&+wr&+wl&+wd&* starts to spin.\n");
          send_msg(ploc(plx),0,LVL_MIN,LVL_MAX,plx,NOBODY,
                   "\001p%s\003 looks a bit drunk.\n",pname(plx));
       } 
       else 
       {  send_msg(ploc(plx),0,LVL_MIN,LVL_MAX,plx,NOBODY,
                   "\001p%s\003 suddenly starts to &+wpuke&*!\n",pname(plx));
          sendf(plx,"You &+wpuke&* all over the floor!\n");
       }
   }

   /* Decrease the time a player is drunk, clear flag is player is sober */
   setpdrunk(plx,pdrunk(plx)--);
   if (pdrunk(plx) == 0)
      sclrflg(plx,SFL_DRUNK);
}

void do_trace(int plr)
{  TRACE *tr;
   static char b[512], b1[80];
   int x,r,l;

   tr = &players[plr].tr;
   x = tr->trace_item;

   switch (tr->trace_class) {
   case 2:
       if (is_in_game(x))
       {  if (ploc(x) != tr->trace_loc)
          {  sendf(plr,"&+w[&+wTRACE&+w: %s is now at %s&+w]&*\n", pname(x),
                   showname(ploc(x)));
             tr->trace_loc = ploc(x);
          }
       }
       else
       {   sendf(plr,"&+w[&+wTRACE&+w: Person/Mobile has departed from the game&+w]&*\n");
           tr->trace_item = -1;
       }
       break;
   case 1:
       if (oloc(x) != tr->trace_loc || ocarrf(x) != tr->trace_carrf ||
           tr->trace_oroom != roomobjin(x))
       {  r = roomobjin(x);
          l = oloc(x);
          if (r == pit_loc)
          {   sprintf("&+w[&+wTRACE&+w: %s has been dropped in the pit&+w]&*\n",oname(x));
              tr->trace_item = -1;
              return;
          }
          sprintf(b,"&+w[&+wTRACE&+w: %s is",oname(x));
          tr->trace_loc   = oloc(x);
          tr->trace_carrf = ocarrf(x);
          tr->trace_oroom = r;
          
          while (ocarrf(x) == IN_CONTAINER)
          {  sprintf(b1," in the %s", oname(l));
             strcat(b,b1);
             x = l;
             l = oloc(x);
          }
          switch (ocarrf(x)) {
          case CARRIED_BY: sprintf(b1," carried by %s", pname(oloc(x))); break;
          case WORN_BY:    sprintf(b1," worn by %s", pname(oloc(x))); break;
          case WIELDED_BY: sprintf(b1," wielded by %s", pname(oloc(x))); break;
          case BOTH_BY:    sprintf(b1," worn and wielded by %s",pname(oloc(x))); break;
          default:
          }
          strcat(b,b1);
          sprintf(b1," in %s&+w]&*\n",showname(r));
          strcat(b,b1);
          sendf(plr,b); 
       }
       break;
   default:
	mudlog("TRACE: Error in trace, wrong type.\n");
        sendf(plr,"&+w[&+wTRACE&+w: Aborted, data screwup&+w]&*\n");
        tr->trace_item = -1;
   }
}

/* Stuff that should be done both after every command and at every
 * i/o-interrupt at the latest.
 */
void special_events (int player)
{ int start = (player == SP_ALL) ? 0 : player;
  int stop = (player == SP_ALL) ? max_players - 1 : player;	/*max_chars ? */
  int i;
  int r_fig; /* cut down on randoms */
  Boolean has_amulet;

  if (player >= max_players)
    return;
  
  for (i = start; i <= stop; ++i)
    if (is_in_game (i))
    {   calib_player(i);

        r_fig= randperc();

        if (players[i].tr.trace_item != -1)
        {   do_trace(i);
        }

        if (plev (i) < LVL_APPREN && ltstflg (ploc (i), LFL_ON_WATER))
        {  if (!carries_boat (i))
           {
	       p_crapup (i, "\t\tYou plunge beneath the waves....", CRAP_SAVE);
	       continue;
           }
        }

        has_amulet = (wearsobjfrom(i,amulets) ||
                      !players[i].iamon ||
                      plev(i) >= LVL_WIZARD);

        if (ltstflg(ploc(i),LFL_IN_WATER))
        {
           if (!has_amulet)
           {
              p_crapup(i, "\t\t&+wWater rushes in to fill your lungs....&+w", CRAP_SAVE);
              broad("In this distance you hear some splashing and a gurgle.\n");
              continue;
           }
           if ( randperc() <= 5)
              sendf(i,"You notice &+wair bubbles&+w floating up as you exhale.\n");
        }
        if (ltstflg(ploc(i),LFL_AIRLESS))
        {
            if (!has_amulet)
            {  sendf(i,"You gasp for air, but there is no atmosphere here you can breathe.\n");
               p_crapup(i,"\t\tYou died by suffocation.",CRAP_SAVE);
               continue;
            } 
        }
        /*
         * If you are underwater and have an extinguishable light, KILL IT!
         */
        if (ltstflg(ploc(i),LFL_IN_WATER)) 
        {  int x;

           for(x=0;x<numobs;x++)
             if(iscarrby(x,i) && otstbit(x,OFL_LIT) && otstbit(x, OFL_EXTINGUISH))
	   {
              sendf (i, "The &+wwater&* promptly extingishues your %s!\n", oname(x));
              oclrbit(x,OFL_LIT);
           }
        }

        if (ltstflg(ploc(i),LFL_AIRLESS))
        {  int x;

           for(x=0;x<numobs;x++)
             if(iscarrby(x,i) && otstbit(x,OFL_LIT) && otstbit(x, OFL_EXTINGUISH))
	     {
                sendf (i, "The %s promptly extingishues because of lack of oxygen!\n", oname(x));
                oclrbit(x,OFL_LIT);
             }
        }


         /* SPECIAL EVENTS */	
         param_s.plx = i;
         check_obj_in_room(i,E_ONTIMER);
         check_pl_in_room(i,E_ONTIMER);
         check_obj_on_plx(i,E_ONTIMER);
         if (rom_fun(ploc(i)) != NULL)
         {  rom_fun(ploc(i))(E_ONTIMER);
            if (param_s.ret == -1)
               continue;
         }

         if (ublock[Puff_The_Dragon+max_players].spec_case != NULL)
         {   if (alive(Puff_The_Dragon+max_players) != -1)
             {
                param_s.pl  = Puff_The_Dragon+max_players;
                param_s.loc = ploc(param_s.pl);
                ublock[Puff_The_Dragon+max_players].spec_case(E_ONTIMER);
             }
         }          

         /* END SPECIAL EVENTS */

	 /* If the snoop-victim has disappeard or the snooper is (only) a wizard 
	  * * and the target has gone into a private room, then stop the snoop.
	  */
	 if (players[i].snooptarget != -1)
	 {
	    if (!is_in_game (players[i].snooptarget))
            {
		sendf (i, "You can no longer snoop.\n");
		snoop_off (i);
	    }
	    else if (ltstflg (ploc (players[i].snooptarget), LFL_PRIVATE)
		     && plev (i) < LVL_ARCHWIZARD)
	    {
		sendf (i, "%s went into a PRIVATE room, you can no longer snoop.\n",
		       pname (players[i].snooptarget));
		
		snoop_off (i);
	     }
	  } 
	
	  /* count down if polymorphed
	   */
	  if (players[i].polymorphed == 0)
	     unpolymorph (i);

	  if (players[i].polymorphed > -1)
	     players[i].polymorphed--;
	
	  /* if invis, count down
	   */
    if (players[i].me_ivct > 0 && --players[i].me_ivct == 0)
        setpvis(i,0);
        
    /* Make people loose drunk, only on timer, so it doesnt matter
     * how many commands you type in a second ;)      */
          if (pdrunk(i) > 0 && player == SP_ALL)
              do_drunk(i);
	
	  if (pstr (i) < 0 && (players[i].aliased || players[i].polymorphed != -1))
	  {   sendf (i, "You've just died.\n");
	 
              if (players[i].polymorphed != -1)
	         unpolymorph (i);
	      else
	         unalias (i);
	  }
    }				/* end for each player */
}



void regenerate (void)
{
  /* chance of heal is now 15 and 30 instead of 20 and 40 since
   * the interrupt now occurs every 2 secs. instead of 3
   */
  int i;
  int r_fig = randperc();
  Boolean has_ring;
  Boolean has_heal_obj = False;
 
  for (i = 0; i < max_players; ++i)
    if (is_in_game (i) && pfighting (i) < 0 && pstr (i) < maxstrength (i) &&
        players[i].linkdead == False)
    { 
	has_ring = (wears_obj_type (i, Tower_Ring_Obj) > -1);
        has_heal_obj = (p_ohanyflag(i,OFL_FASTHEAL) >= 0);

        r_fig=randperc(); /* Only one random call per player */

        if (ststflg(i,SFL_POISONED) && r_fig < 50)
        {   sendf(i,"You feel the poison slowly crawling through your veins draining your strength\n");
            setpstr(i,pstr(i) - 1);
            continue;
        }

        if ((r_fig  < 15) && ltstflg(ploc(i), LFL_NEG_REGEN) && 
            (!has_ring && pstr(i) > 1) && plev(i) < LVL_APPREN) 
        {
           sendf(i, "You feel your energy draining away!\n");
           setpstr( i, pstr(i) - 1);
           continue; 
        }
 
	if (((!has_ring && (randperc()  < 25)) 
            || ((psitting (i) && randperc()  < 40)))
            || ((psitting(i)==2 && randperc() <60))
	    || ((has_ring && randperc()  < 67)) 
	    || (psitting(i)==3 && ptstflg(i,PFL_CANTRANCE) && randperc()  < 70)
            || (has_heal_obj && randperc() < 74)
	    || (pdrunk(i) > 0 && randperc() < pdrunk(i) * 10)
            )
	  {
	    if (maxstrength (i) == pstr (i) + 1)
	    {
		sendf (i, "You feel fully healed.\n");
	    }
	    
	    setpstr (i, pstr (i) + 1);
	    
	    if (players[i].iamon)
	      calib_player (i);
	  }
      }
}

static void _userlist (char mode)
{ char line[256];
  char locname[80];
  register int t;
/*  int old_mynum = 0;*/
  int a[256], a_len = 0;
  int idle = 0;
  struct tm *tm;
  int j;
  char buff[10];
  char uname[20];
  int usercount = 0;
  Boolean show_hostname = False;
  Boolean show_location = False;
  Boolean notHere = False;

  if (cur_player->aliased || cur_player->polymorphed != -1)
  {
      bprintf("Not while aliased.\n");
      return;
  }

  if (the_world->w_tournament || plev (mynum) >= LVL_APPREN)
    show_location = True;

  if (ptstflg (mynum, PFL_SHUSER) || the_world->w_tournament)
    show_hostname = True;
  
  if (mode)
  {
      bprintf("&+wLevel        Player&*\n");
      bprintf ("&+w%s&+w\n",DASHLINE);
  }
  else
  {
      bprintf ("&+w%-7s %-12.12s %-16.16s %-8.8s %-10.10s %-21.21s&+w\n",
	       "Level", "Player", show_hostname ? "Hostname" : " ", 
	       "Idle",
	       show_location ? "Zone" : " ",
	       show_location ? "Room" : " ");
      bprintf ("&+w%s&*\n",MIXLINE);
  }
  
  for (t=0; t<max_players; t++)
    if (is_in_game(t) && ((pvis(t) <= plev(mynum)) || (t == mynum)))
    {
        a[a_len++]=t;
    }

  qsort( a, a_len, sizeof(int), cmp_player);

  for (j = 0; t = a[j], j < a_len; ++j)
  {  idle = time(0) - players[t].last_command;
     tm = (struct tm *)gmtime((const time_t *)&idle);
     
     if ((plev(t) < LVL_APPREN && idle > 180) || (plev(t)  >= LVL_APPREN && (idle > 300)))
         notHere = True;
    
     if (EQ(pname(t),"Marty"))
     {  strcpy(uname,"HellSpawn");
     }
     else     
     {  lev2s(uname, plev(t), psex(t));
        uname[strlen(uname) -1] = '\0';
     }
     
     if (mode)
     {  Boolean nocomm = ststflg(t,SFL_NOCOMM);
        if (ststflg(t,SFL_AWAY))
           sprintf (line, "&+w[&+w%-9.9s&+w]&+w%c&* %s is away, %s\n",uname,(pvis(t) > 0) ? '*' : ' ',
		pname(t),players[t].awaymsg);
        else
           sprintf (line, "&+w[&+w%-9.9s&+w]&+w%c&* %s&+w%s%s%s%s%s%s%s%s%s%s%s%s&+w\n",
		 uname,
                 (pvis(t) > 0) ? '*' : ' ',
		 t < max_players ? make_title (ptitle(t), pname(t)) : "&+w[Possessed&*]",
                 players[t].linkdead ? " &+w(&+wlinkdead&+w)&+w" : "",
                 players[t].defrob != NULL ? " [Asmortal]" : "",
                 /* Show party name */
                 whopartytst(t),
		 (ststflg(t, SFL_NOSHOUT) && !nocomm) ? " [NoShout]" : "",
		 (ststflg(t, SFL_NO_GOSSIP) && !nocomm) ? " [NoGossip]" : "",
                 (ststflg(t, SFL_NO_CHAT) && !nocomm) ? " [NoChat]" : "",
		 ststflg(t, SFL_BUSY) ? " [Busy]" : "",
		 ststflg(t, SFL_CODING) ? " [Coding]" : "",
		 (ststflg(t, SFL_NO_WIZ) && !nocomm && 
                  plev(mynum) >= LVL_APPREN) ? " [NoWiz]" : "",
		 (notHere && !players[t].linkdead) ? " [Idle]" : "",
		 (ststflg(t, SFL_DISTRACTED) && !players[t].inmailer) ? " [Distracted]" : "",
		 players[t].inmailer ? " &+w[&+wMailing&+w]&+w" : ""
		);

	  notHere = False;
     }
     else
     {  idle = time (0) - players[t].last_cmd;
        tm = (struct tm *) gmtime ((const time_t *)&idle);
	  
	strftime (buff, 10, "%H:%M:%S", tm);
	sprintf(line, 
		  "&+w[&+w%5d&+w]&+w%s%-12.12s&* &+w%-16.16s&* &+w%-8.8s&* &+w%-10.10s&+w %-s\n",
	  	  plev(t),
		  (pvis(t) > 0) ? "*" : " ",
		  pname (t),
		  show_hostname ? players[t].hostname : " ",
		  buff,
		  show_location ? showname (ploc (t)) : " ",
		  show_location ? bstrncpy(locname,sdesc(ploc(t)),19) : " ");
     }
      
     if (((pvis (t) <= plev (mynum)) || t == mynum) && strlen (pname (t)))
     {
	  usercount++;
	  bprintf ("%s",line);
     }
  }
  
  bprintf ("&+w%s\n&+wA total of &+w%d&+w visible users.\n", (mode) ? DASHLINE : MIXLINE, usercount);
  return;
  
}


void show_mob_strength(int plx)
{ int x,p;
  static char *t[] = 
    {
      "%s near death.&*\n",
      "%s near death.&*\n",
      "%s mortally wounded.&*\n",
      "%s seriously wounded.&*\n",
      " some wounds, but %s still fairly strong.&*\n",
      " minor cuts and abrasions.&*\n",
      " minor cuts and abrasions.&*\n",
      " feels a bit dazed.&*\n",
      "%s in better than average condition.&*\n",
      "%s in exceptional health.&*\n",
      "%s in exceptional health.&*\n"
    };
    
    if (plx >= max_players) 
    {  x = pstr_reset (plx);
    } 
    else 
    {  x = maxstrength (plx);
    }
    if (pstr(plx) < 0)
	p = -1;
	  else if (pstr(plx) == 0 || x == 0)
	     p =0;
    else if (pstr(plx) > x)
	p = 11;
    else
	p = (int) (pstr(plx) * 10 / x);
    bprintf("&+w%s&* ", pname(plx));
    if (p >= 4 && p <= 6)
       bprintf ("&+w%s&*", "&+whas");
    if (p >= 0 && p <= 10)
	bprintf (t[p], "&+wis");
    else
       bprintf ("&+wmust %s&*", p < 0 ? "&+wbe undead!&*\n" :
		 "&+whave had Wheaties for breakfast!&*\n");
}

char *short_mob_strength(int plx)
{ int x,p;
  static char *t[] = 
    {
      "near death",
      "near death",
      "mortally wounded",
      "seriously wounded",
      "fairly strong",
      "minor cuts and abrasions",
      "minor cuts and abrasions",
      "dazed",
      "average condition",
      "exceptional health",
      "excellent health"
    };
    
    if (plx >= max_players) 
    {  x = pstr_reset (plx);
    } 
    else 
    {  x = maxstrength (plx);
    }
    if (pstr(plx) < 0)
	p = -1;
    else if (pstr(plx) > x)
	p = 11;
    else if (pstr(plx) == 0 || x == 0)
        p = 0;
    else
	p = (int) (pstr(plx) * 10 / x);

    if (p < ARRAYSIZE(t) && p >= 0)
       return t[p];
    else
       return (p < 0 ? "&+Lundead!&*" : "&+wSuperman!&*");
}