#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "emlen.h"

bool quit_flag = FALSE;


void 
clear_tracks (CHAR_DATA * ch)
{
  ROOM_DATA *rid;
  int hash;
  TRACK_DATA *tr;
  TRACK_DATA *tr_n;
  TRACK_DATA *tt;
  if (!ch)
    return;
  for (hash = 0; hash < HASH_MAX; hash++)
    {
      for (rid = room_hash[hash]; rid != NULL; rid = rid->next)
	{
	  if (rid->tracks && rid->tracks->ch == ch)
	    {
	      tt = rid->tracks;
	      rid->tracks = rid->tracks->next_track_in_room;
	      free_m (tt);
	      continue;
	    }
	  for (tr = rid->tracks; tr != NULL; tr = tr_n)
	    {
	      tr_n = tr->next_track_in_room;
	      if (tr_n && tr_n->ch == ch)
		{
		  tt = tr->next_track_in_room;
		  tr->next_track_in_room = tr_n->next_track_in_room;
		  free_m (tt);
		  goto tt;
		}
	    }
	tt:
		if (tr) {};
	}
    }

  return;
}

void 
do_busy (CHAR_DATA * ch, char *argy)
{
  DEFINE_COMMAND ("busy", do_busy, POSITION_DEAD, 110, LOG_NORMAL, "Allows you to enter busy mode.")

    if (IS_MOB (ch))
    return;
  if (LEVEL (ch) < 109)
    {
      send_to_char ("You may not go into busy mode unless you are a god.\n\r", ch);
      return;
    }
  if (ch->pcdata->quiet != 2)
    ch->pcdata->quiet = 2;
  else
    ch->pcdata->quiet = 0;
  if (ch->pcdata->quiet == 0)
    send_to_char ("You are no longer in busy mode! Prepare yourself!\n\r", ch);
  if (ch->pcdata->quiet == 2)
    send_to_char ("You have entered busy mode.\n\r", ch);
  return;
}

void 
do_action (CHAR_DATA * ch, char *argy)
{
  int k;
  char *t;
  int empty = 0;
  int n1 = 0;
  int n2 = 0;
  char arg1[SML_LENGTH];
  char arg2[SML_LENGTH];
  char general_use[STD_LENGTH];
  int an;
  DEFINE_COMMAND ("action", do_action, POSITION_DEAD, 0, LOG_NORMAL, "Allows you to set up actions, or delete/modify existing actions.")
    send_to_char ("Actions are disabled right now.\n\r", ch);
  return;
  SET_BIT (ch->special, ACTION_OFF);
  if (!ch || IS_MOB (ch))
    {
      return;
    }
  for (k = 0; k < MAXALIAS; k++)
    if (!ch->pcdata->action[k] || ch->pcdata->action[k][0] == '\0'
      || !ch->pcdata->actionname[k] || ch->pcdata->actionname[k][0] == '\0')
      empty++;
  if (!argy || argy[0] == '\0')
    {
      if (empty == MAXALIAS)
	{
	  send_to_char ("You have no actions. To set one up, use: Action \"<trigger>\" <action to perform>.\n\r", ch);
	  return;
	}
      send_to_char ("\x1B[34;1m---------\x1B[35m[ Actions ]\x1B[34m---------\x1B[37;0m\n\r\n\r", ch);
      for (k = 0; k < MAXALIAS; k++)
	{
	  if (ch->pcdata->action[k] && ch->pcdata->action[k][0] != '\0'
	      && ch->pcdata->actionname[k] && ch->pcdata->actionname[k][0] != '\0')
	    {
	      char *iio;
	      for (iio = ch->pcdata->action[k]; *iio != '\0'; iio++)
		{
		  if (*iio == '~')
		    *iio = '*';
		}
	      sprintf (general_use,
		       "\x1B[1;30m[\x1B[34m%2d\x1B[30m]\x1B[34m --> \x1B[32m%-22s\x1B[34m Then Do: \x1B[37m\"%s\"\x1B[37;0m\n\r",
		   k + 1, ch->pcdata->actionname[k], ch->pcdata->action[k]);
	      send_to_char (general_use, ch);
	      for (iio = ch->pcdata->action[k]; *iio != '\0'; iio++)
		{
		  if (*iio == '*')
		    *iio = '~';
		}
	    }
	}
      return;
    }
  argy = one_argy (argy, arg1);
  one_argy (argy, arg2);
  if (argy[0] == '{' && argy[strlen (argy) - 1] == '}')
    {
      argy[strlen (argy) - 1] = '\0';
      argy++;
    }
  for (t = arg1; *t != '\0'; t++)
    {
      if (*t == '^')
	n1++;
      if (*t == '&')
	n2++;
      if (n1 > 1 || n2 > 1)
	{
	  send_to_char ("You may not have more than ONE ^ or & in your action TRIGGER.\n\r", ch);
	  return;
	}
    }
  if (!arg2 || arg2[0] == '\0')
    {
      for (k = 0; k < MAXALIAS; k++)
	{
	  if (ch->pcdata->actionname[k] && !str_cmp (arg1, ch->pcdata->actionname[k]))
	    {
	      sprintf (general_use,
		       "Deleted action #%d.\n\r", k + 1);
	      send_to_char (general_use, ch);
	      free_string (ch->pcdata->actionname[k]);
	      free_string (ch->pcdata->action[k]);
	      ch->pcdata->actionname[k] = NULL;
	      ch->pcdata->action[k] = NULL;
	      return;
	    }
	}
      an = atoi (arg1);
      if (an > 0)
	{
	  for (k = 0; k < MAXALIAS; k++)
	    {
	      if (an == (k + 1))
		{
		  if (!ch->pcdata->actionname[k])
		    {
		      send_to_char ("That action number does not exist!\n\r", ch);
		      return;
		    }
		  sprintf (general_use,
			   "Deleted action #%d.\n\r", k + 1);
		  send_to_char (general_use, ch);
		  free_string (ch->pcdata->actionname[k]);
		  free_string (ch->pcdata->action[k]);
		  ch->pcdata->actionname[k] = NULL;
		  ch->pcdata->action[k] = NULL;
		  return;
		}
	    }
	}
      sprintf (general_use, "Action \"%s\" not found.\n\r",
	       arg1);
      send_to_char (general_use, ch);
      return;
    }
  if (empty == 0)
    {
      send_to_char ("You have no free action entries. You must delete one before adding\n\rany more.\n\r", ch);
      return;
    }
  if (strlen (arg1) < 5)
    {
      send_to_char ("Action triggers must be at least 5 letters long.\n\r", ch);
      return;
    }

  for (k = 0; k < MAXALIAS; k++)
    {
      if (ch->pcdata->actionname[k] && !str_cmp (arg1, ch->pcdata->actionname[k]))
	{
	  char *msk;
	  free_string (ch->pcdata->actionname[k]);
	  free_string (ch->pcdata->actionname[k]);
	  ch->pcdata->actionname[k] = str_dup (arg1);
	  ch->pcdata->action[k] = str_dup (argy);
	  for (msk = ch->pcdata->action[k]; *msk != '\0'; msk++)
	    if (*msk == '*')
	      *msk = '~';
	  break;
	}
    }
  if (k == MAXALIAS)
    for (k = 0; k < MAXALIAS; k++)
      {
	if (ch->pcdata->actionname[k] == '\0' || !ch->pcdata->actionname[k]
	    || !ch->pcdata->action[k] || ch->pcdata->action[k] == '\0')
	  {
	    char *msk;
	    ch->pcdata->actionname[k] = str_dup (arg1);
	    ch->pcdata->action[k] = str_dup (argy);
	    for (msk = ch->pcdata->action[k]; *msk != '\0'; msk++)
	      if (*msk == '*')
		*msk = '~';
	    break;
	  }
      }
  sprintf (general_use, "\x1B[34;1m[\x1B[37mAdded action #%d\x1B[34m]\x1B[37;0m\n\r", k + 1);
  send_to_char (general_use, ch);
  return;
}

void 
do_alias (CHAR_DATA * ch, char *argy)
{
  int k;
  int empty = 0;
  char *t;
  char arg1[SML_LENGTH];
  char arg2[SML_LENGTH];
  char general_use[STD_LENGTH];
  int an;
  DEFINE_COMMAND ("alias", do_alias, POSITION_DEAD, 0, LOG_NORMAL, "Allows you to set up an alias expansion, or delete/modify existing aliases.")

    if (!ch || IS_MOB (ch))
    return;
  for (k = 0; k < MAXALIAS; k++)
    if (!ch->pcdata->alias[k] || ch->pcdata->alias[k][0] == '\0'
	|| !ch->pcdata->aliasname[k] || ch->pcdata->aliasname[k][0] == '\0')
      empty++;
  if (!argy || argy[0] == '\0')
    {
      if (empty == MAXALIAS)
	{
	  send_to_char ("You have no aliases. To set one up, use: Alias <name> <expansion>.\n\r", ch);
	  return;
	}
      send_to_char ("\x1B[34;1m---------\x1B[35m[ Aliases ]\x1B[34m---------\x1B[37;0m\n\r\n\r", ch);
      for (k = 0; k < MAXALIAS; k++)
	{
	  if (ch->pcdata->alias[k] && ch->pcdata->alias[k][0] != '\0'
	  && ch->pcdata->aliasname[k] && ch->pcdata->aliasname[k][0] != '\0')
	    {
	      char *iio;
	      for (t = ch->pcdata->alias[k]; *t != '\0'; t++)
		{
		  if (*t == '%')
		    *t = '@';
		}
	      for (t = ch->pcdata->aliasname[k]; *t != '\0'; t++)
		{
		  if (*t == '%')
		    *t = '@';
		}
	      for (iio = ch->pcdata->alias[k]; *iio != '\0'; iio++)
		{
		  if (*iio == '~')
		    *iio = '*';
		}
	      sprintf (general_use,
		       "\x1B[1;30m[\x1B[34m%2d\x1B[30m]\x1B[34m --> \x1B[32m%-10s\x1B[34m Expansion: \x1B[37m\"%s\"\x1B[37;0m\n\r",
		     k + 1, ch->pcdata->aliasname[k], ch->pcdata->alias[k]);
	      send_to_char (general_use, ch);
	      for (iio = ch->pcdata->alias[k]; *iio != '\0'; iio++)
		{
		  if (*iio == '*')
		    *iio = '~';
		}
	    }
	}
      return;
    }
  argy = one_argy (argy, arg1);
  one_argy (argy, arg2);
  if (argy[0] == '{' && argy[strlen (argy) - 1] == '}')
    {
      argy[strlen (argy) - 1] = '\0';
      argy++;
    }
  if (!arg2 || arg2[0] == '\0')
    {
      for (k = 0; k < MAXALIAS; k++)
	{
	  if (ch->pcdata->aliasname[k] && !str_cmp (arg1, ch->pcdata->aliasname[k]))
	    {
	      sprintf (general_use,
		       "Deleted alias #%d.\n\r", k + 1);
	      send_to_char (general_use, ch);
	      free_string (ch->pcdata->aliasname[k]);
	      free_string (ch->pcdata->alias[k]);
	      ch->pcdata->aliasname[k] = NULL;
	      ch->pcdata->alias[k] = NULL;
	      return;
	    }
	}
      an = atoi (arg1);
      if (an > 0)
	{
	  for (k = 0; k < MAXALIAS; k++)
	    {
	      if (an == (k + 1))
		{
		  if (!ch->pcdata->aliasname[k])
		    {
		      send_to_char ("That alias number does not exist!\n\r", ch);
		      return;
		    }
		  sprintf (general_use,
			   "Deleted alias #%d.\n\r", k + 1);
		  send_to_char (general_use, ch);
		  free_string (ch->pcdata->aliasname[k]);
		  free_string (ch->pcdata->alias[k]);
		  ch->pcdata->aliasname[k] = NULL;
		  ch->pcdata->alias[k] = NULL;
		  return;
		}
	    }
	}
      sprintf (general_use, "Alias \"%s\" not found.\n\r",
	       arg1);
      send_to_char (general_use, ch);
      return;
    }
  if (empty == 0)
    {
      send_to_char ("You have no free alias entries. You must delete one before adding\n\rany more.\n\r", ch);
      return;
    }
  if (strlen (arg1) == 1 && (arg1[0] == 'l' || arg1[0] == 'k' || arg1[0] == 'n' ||
		       arg1[0] == 's' || arg1[0] == 'e' || arg1[0] == 'w' ||
			arg1[0] == 'i' || arg1[0] == 'u' || arg1[0] == 'd'))
    {
      send_to_char ("Aliases that begin with that letter must be more than 1 character long.\n\r", ch);
      return;
    }
  for (k = 0; k < MAXALIAS; k++)
    {
      if (ch->pcdata->aliasname[k] &&
	  !aliasok (ch->pcdata->aliasname[k], argy))
	{
	  send_to_char ("Recursive aliases are not acceptable!\n\r", ch);
	  return;
	}
    }
  if (!aliasok (arg1, argy))
    {
      send_to_char ("Partially recursive aliases are not acceptable!\n\r", ch);
      return;
    }
  for (k = 0; k < MAXALIAS; k++)
    {
      if (ch->pcdata->aliasname[k] && !str_cmp (arg1, ch->pcdata->aliasname[k]))
	{
	  char *msk;
	  free_string (ch->pcdata->alias[k]);
	  free_string (ch->pcdata->aliasname[k]);
	  ch->pcdata->aliasname[k] = str_dup (arg1);
	  ch->pcdata->alias[k] = str_dup (argy);
	  for (t = ch->pcdata->alias[k]; *t != '\0'; t++)
	    {
	      if (*t == '%')
		*t = '@';
	    }
	  for (t = ch->pcdata->aliasname[k]; *t != '\0'; t++)
	    {
	      if (*t == '%')
		*t = '@';
	    }
	  for (msk = ch->pcdata->alias[k]; *msk != '\0'; msk++)
	    if (*msk == '*')
	      *msk = '~';
	  break;
	}
    }
  if (k == MAXALIAS)
    for (k = 0; k < MAXALIAS; k++)
      {
	if (ch->pcdata->aliasname[k] == '\0' || !ch->pcdata->aliasname[k]
	    || !ch->pcdata->alias[k] || ch->pcdata->alias[k] == '\0')
	  {
	    char *msk;
	    ch->pcdata->aliasname[k] = str_dup (arg1);
	    ch->pcdata->alias[k] = str_dup (argy);
	    for (t = ch->pcdata->alias[k]; *t != '\0'; t++)
	      {
		if (*t == '%')
		  *t = '@';
	      }
	    for (t = ch->pcdata->aliasname[k]; *t != '\0'; t++)
	      {
		if (*t == '%')
		  *t = '@';
	      }
	    for (msk = ch->pcdata->alias[k]; *msk != '\0'; msk++)
	      if (*msk == '*')
		*msk = '~';
	    break;
	  }
      }
  sprintf (general_use, "\x1B[34;1m[\x1B[37mAdded alias #%d\x1B[34m]\x1B[37;0m\n\r", k + 1);
  send_to_char (general_use, ch);
  return;
}

void 
do_qui (CHAR_DATA * ch, char *argy)
{
  DEFINE_COMMAND ("qui", do_qui, POSITION_DEAD, 0, LOG_NORMAL, "This command is so you don't type q or qu and quit out by accident.")

    send_to_char ("Huh?\n\r", ch);
  return;
}

void 
do_quit (CHAR_DATA * ch, char *argy)
{
  DESCRIPTOR_DATA *d;
  CHAR_DATA *bah_nir;
  CHAR_DATA *bah;
  char general_use[STD_LENGTH];
  DEFINE_COMMAND ("quit", do_quit, POSITION_DEAD, 0, LOG_NORMAL, "This command saves your character and terminates the session.")

    if (IS_MOB (ch) && ch->desc != NULL)
    {
      do_return (ch, "");
      return;
    }
if (str_cmp(argy,"yyuu")) {
  if (ch->in_room && ch->in_room->sector_type == SECT_WATER_NOSWIM)
    {
      send_to_char ("You may not quit in an unswimmable water sector.\n\r", ch);
      return;
    }
  if (ch->in_room && ch->in_room->more && ch->in_room->more->linked_to) {
	  send_to_char ("You cannot quit while in a vehicle.\n\r",ch);
	return;
  }

  if (ch->desc && !ch->desc->character)
    {
      ch->desc->character = ch;
    }
  if (IS_AFFECTED (ch, AFF_CHARM))
    return;
  check_ced (ch);
#ifndef NEW_WORLD
  if (ch->ced->in_boat != NULL)
    {
      send_to_char ("You cannot quit inside of a boat!!\n\r", ch);
      return;
    }
#endif
  if (IN_BATTLE (ch))
    {
      send_to_char ("You cannot quit in the battleground!\n\r", ch);
      return;
    }
#ifdef NEW_WORLD
  if (LEVEL (ch) < 100)
    {
      ROOM_DATA *rrd;
      if (ch->in_room && ch->in_room->area && ch->in_room->area->can_quit == 2)
	{
	  send_to_char ("You may not quit while in this zone.\n\r", ch);
	  return;
	}
      if (!IS_EVIL (ch) && (rrd = get_room_index (1501)) != NULL &&
	  ch->in_room && ch->in_room->area != rrd->area &&
	  rrd->vnum > 1200 && ch->in_room->area->can_quit == 0 &&
	  IS_SET (ch->in_room->room_flags, ROOM_INDOORS))
	{
	  send_to_char ("You cannot quit while indoors.  You may only quit in town or outside.\n\r", ch);
	  return;
	}
      if (IS_EVIL (ch) && ch->in_room && IS_SET (ch->in_room->room_flags, ROOM_INDOORS)
	  && ch->in_room->area->can_quit == 0)
	{
	  send_to_char ("You cannot quit while indoors.\n\r", ch);
	  return;
	}
    }
#endif
  if (ch->in_room && ch->in_room->vnum > 440 && ch->in_room->vnum < 700 &&
      !ch->in_room->area->can_quit)
    {
      send_to_char ("You are not in a valid place in the world to quit.\n\r", ch);
      return;
    }
  if (CHALLENGE (ch) == 10)
    {
      send_to_char ("You must wait until after the arena battle!\n\r", ch);
      return;
    }
  if (auction_char == ch || e_auction_char == ch)
    {
      send_to_char ("Not while you are auctioning an item!\n\r", ch);
      return;
    }
  if (auction_tochar == ch || e_auction_tochar == ch)
    {
      send_to_char ("Not while you have the current bid on the auction!\n\r", ch);
      return;
    }
  if (ch->pcdata->no_quit_pk != 0)
    {
      sprintf (general_use, "Our records show you have recently been near or in combat with a player.\n\r");
      send_to_char (general_use, ch);
      sprintf (general_use, "You must wait %d more game hours to quit.\n\r",
	       ch->pcdata->no_quit_pk);
      send_to_char (general_use, ch);
      return;
    }
 
  if (ch->pcdata->no_quit != 0)
    {
      send_to_char ("Due to possibilities of avoiding hunting mobs and/or players, killing,\n\r", ch);
      send_to_char ("looting, then quitting out right away, you cannot quit from the game\n\r", ch);
      send_to_char ("this soon after combat.  Combat with mobs sets the counter to 3 ticks,\n\r", ch);
      send_to_char ("combat with players sets the counter to 6 ticks, and encountering an\n\r", ch);
      send_to_char ("player opponent, sets the counter to 2 ticks.\n\r", ch);
      sprintf (general_use, "You must wait %d more game hours to quit.\n\r",
	       ch->pcdata->no_quit);
      send_to_char (general_use, ch);
      return;
    }
  if (ch->position == POSITION_FIGHTING)
    {
      send_to_char ("You may not quit during combat.\n\r", ch);
      return;
    }
  if (ch->position < POSITION_STUNNED)
    {
      send_to_char ("You must wait until you die or recover to quit.\n\r", ch);
      return;
    }
} /* End of quit for sure with yyuu */
/* Pray that they are not auctioning stuff.. or it might crashie! */

  check_ced (ch);
  if (ch->ced->wasroom != 0)
    {
      char_from_room (ch);
      char_to_room (ch, get_room_index (ch->ced->wasroom));
    }
  if (ch->in_room && ch->in_room->vnum > 500 && ch->in_room->vnum < 550)
    {
      fprintf (stderr, "Moved %s back into portal room from arena/waiting rooms.\n", NAME (ch));
      char_from_room (ch);
      if (IS_EVIL (ch))
	char_to_room (ch, get_room_index (99));
      else
	char_to_room (ch, get_room_index (100));
    }
  do_help (ch, "FAREWELL");
  clear_tracks (ch);
  update_pbase (ch);
  if (IS_PLAYER (ch) && ch->pcdata->prompt != 0)
    {
      char tmps[500];
      sprintf (tmps, "\x1B[1;%dr\x1B[2J", ch->pcdata->pagelen);
      write_to_descriptor2 (ch->desc, tmps, 0);
    }
  if (IS_PLAYER (ch) && ch->desc != NULL && IS_SET (ch->pcdata->act2, PLR_BLANKPROMPT))
    {
      char tmps[500];
      sprintf (tmps, "\x1B[1;%dr\x1B[2J", ch->pcdata->pagelen);
      write_to_descriptor2 (ch->desc, tmps, 0);
    }
  if (str_cmp (RNAME (ch), "Orin"))
    {
      sprintf (log_buf, "%s (%s@%s) has left the world.", NAME (ch),
	       (ch->desc ? ch->desc->username : "nodesc"),
	       (ch->desc ? ch->desc->host : "nodesc"));
      log_string (log_buf);
      sprintf (general_use, "Notify> %s has left the world.", NAME (ch));
      do_global (general_use, LEVEL_IMMORTAL, WIZ_NOTIFY_LOGIN);
      if (LEVEL (ch) < LEVEL_IMMORTAL)
	act ("$n logged off.", ch, NULL, NULL, TO_NOTVICT);
    }
/*for (bah=char_list;bah!=NULL;bah=bah->next)
   {
   if (IS_PLAYER(bah)) continue;
   if ( bah->npcdata->hire != NULL )
   {
   if ( bah->npcdata->hire==ch || !get_player_world(bah, NAME(bah->npcdata->hire),FALSE) )
   {
   bah->npcdata->hire = NULL;
   bah->npcdata->paid = 0;
   bah->leader = NULL;
   bah->master = NULL;
   continue;
   }
   }
   }
 */
  NEW_POSITION(ch, POSITION_STANDING);
  ch->pcdata->number_pets = 0;
  sprintf (general_use, "%s logged off.\n\r", NAME (ch));
  do_chan_notify (ch, general_use);
  if (LEVEL (ch) > 110)
    ch->pcdata->level = 1;
  save_char_obj (ch);
  save_char_tro (ch);
  if (ch->in_room)
    {
      for (bah = ch->in_room->more->people; bah != NULL; bah = bah_nir)
	{
	  bah_nir = bah->next_in_room;
	  if (IS_MOB (bah) && MASTER (bah) == ch && IS_AFFECTED (bah, AFF_CHARM))
	    {
	      char_from_room (bah);
	      check_fgt (bah);
	      bah->fgt->master = NULL;
	      extract_char (bah, TRUE);
	    }
	}
    }
  d = ch->desc;
  quit_flag = TRUE;
  do_rawclear (ch, "");
  extract_char (ch, TRUE);
  quit_flag = FALSE;
  if (d != NULL)
    {
      close_socket (d);
    }
  return;
}

void 
do_delete (CHAR_DATA * ch, char *argy)
{
  DESCRIPTOR_DATA *d;
  PLAYERBASE_DATA *playerbase;
  char general_use[STD_LENGTH];
  DEFINE_COMMAND ("delete", do_delete, POSITION_DEAD, 0, LOG_ALWAYS, "This command is used to delete your character permanently and irreversably.")

    if (FIGHTING (ch) != NULL || ch->position == POSITION_FIGHTING)
    return;
  check_ced (ch);
#ifndef NEW_WORLD
  if (ch->ced->in_boat != NULL)
    {
      send_to_char ("You cannot delete inside of a boat!!\n\r", ch);
      return;
    }
#endif
  if (ch->in_room && ch->in_room->vnum > 400 && ch->in_room->vnum < 700)
    {
      send_to_char ("You are not in a valid place in the world to delete.\n\r", ch);
      return;
    }
  if (IS_AFFECTED (ch, AFF_CHARM))
    return;
  if (IN_BATTLE (ch))
    {
      send_to_char ("You cannot delete in the battleground!\n\r", ch);
      return;
    }
  if (!str_cmp (argy, "character forever"))
    {
      if (CHALLENGE (ch) == 10)
	{
	  send_to_char ("You must wait until after the arena battle!\n\r", ch);
	  return;
	}
      if (auction_char == ch || e_auction_char == ch)
	{
	  send_to_char ("Not while you are auctioning an item!\n\r", ch);
	  return;
	}
      if (auction_tochar == ch || e_auction_tochar == ch)
	{
	  send_to_char ("Not while you have the current bid on the auction!\n\r", ch);
	  return;
	}
      clear_tracks (ch);
      save_char_obj (ch);
      sprintf (general_use, "%s%s.p", PLAYER_DIR_2, NAME (ch));
      unlink (general_use);
      sprintf (general_use, "%s%s.cor", PLAYER_DIR_2, NAME (ch));
      unlink (general_use);
      sprintf (general_use, "%s%s.tro", PLAYER_DIR_2, NAME (ch));
      unlink (general_use);
      sprintf (general_use, "%s%s", PLAYER_DIR_2, NAME (ch));
      unlink (general_use);
      for (playerbase = playerbase_zero; playerbase != NULL; playerbase = playerbase->next)
	{
	  if (!str_cmp (playerbase->player_name, NAME (ch)))
	    {
	      playerbase->player_level = -1;
	      save_playerbase ();
	      break;
	    }
	}
      sprintf (log_buf, "--> %s deleted self.", NAME (ch));
      log_string (log_buf);
      sprintf (general_use, "Notify> %s has deleted self.", NAME (ch));
      do_global (general_use, LEVEL_IMMORTAL, WIZ_NOTIFY_LOGIN);
      /*sprintf(general_use,"rm \"%s%s\" &",PLAYER_DIR_2,jumble_name(NAME(ch),FALSE));
         system(general_use); */
      d = ch->desc;
      extract_char (ch, TRUE);
      if (d != NULL)
	close_socket (d);
      return;
    }
  if (argy[0] == '\0')
    {
      send_to_char ("To delete this character permanently, type delete character forever\n\r", ch);
      return;
    }
  return;
}

void 
do_allsave (CHAR_DATA * ch, char *argy)
{
  DESCRIPTOR_DATA *dd;
  DEFINE_COMMAND ("allsave", do_allsave, POSITION_DEAD, 110, LOG_ALWAYS, "This command forces a complete save of all characters.")

    for (dd = descriptor_list; dd != NULL; dd = dd->next)
    {
      if (!dd->character || dd->connected != CON_PLAYING)
	continue;
      write_to_descriptor2 (dd, "Forced save... saving your character.\n\r", 0);
      save_char_obj (dd->character);
    }
  return;
}

void 
do_save (CHAR_DATA * ch, char *argy)
{
  DEFINE_COMMAND ("save", do_save, POSITION_DEAD, 0, LOG_NORMAL, "This command is used to save your character.")

    if (IS_MOB (ch))
    return;
  if (argy && argy != NULL && !str_cmp (argy, "xx2xx11"))
    {
      save_char_obj (ch);
      return;
    }
  send_to_char ("Saving... Successful.\n\r", ch);
#ifdef NEW_WORLD
  if (number_range (1, 4) == 2)
    save_char_obj (ch);
#endif
  return;
}

void 
do_follow (CHAR_DATA * ch, char *argy)
{
  char arg[SML_LENGTH];
  CHAR_DATA *victim;
  DEFINE_COMMAND ("follow", do_follow, POSITION_STANDING, 0, LOG_NORMAL, "This command allows you to follow a player or mob.  See also Ditch and Group.")

    one_argy (argy, arg);
  if (arg[0] == '\0')
    {
      send_to_char ("Syntax: Follow <person>\n\r", ch);
      return;
    }
  if ((victim = get_char_room (ch, arg)) == NULL)
    {
      send_to_char ("That person is either not here, or not visible to you.\n\r", ch);
      return;
    }
  if (LEVEL (victim) > 100 && LEVEL (ch) < 100)
    {
      send_to_char ("Mortals may not follow immorts!\n\r", ch);
      return;
    }
  if (IS_AFFECTED (ch, AFF_CHARM) && MASTER (ch) != NULL)
    {
      act ("You'd rather follow your master... $N!", ch, NULL, MASTER (ch), TO_CHAR);
      return;
    }
  if (victim == ch)
    {
      if (MASTER (ch) == NULL)
	{
	  send_to_char ("Okay.  You stop following anyone you were following.\n\r", ch);
	  return;
	}
      stop_follower (ch);
      return;
    }
  conv_race (victim);
  conv_race (ch);
  if (not_is_same_align (ch, victim))
    {
      if (IS_EVIL (victim)) {
		send_to_char ("FOLLOW AN ALIEN!? No way!\n\r", ch);
	  }
      if (!IS_EVIL (victim)) {
		send_to_char ("FOLLOW THAT HUMANOID SCUM!? No way!\n\r", ch);
	  }
      return;
    }
  if (MASTER (ch) != NULL)
    stop_follower (ch);
  add_follower (ch, victim);
  return;
}

void 
add_follower (CHAR_DATA * ch, CHAR_DATA * master)
{
  if (MASTER (ch) != NULL)
    {
      bug ("Add_follower: non-null master.", 0);
      return;
    }
  check_fgt (ch);
  ch->fgt->master = master;
  ch->fgt->leader = NULL;
  if (can_see (master, ch))
    act ("$n now follows you.", ch, NULL, master, TO_VICT);
  act ("You now follow $N.", ch, NULL, master, TO_CHAR);
  return;
}

void 
stop_follower (CHAR_DATA * ch)
{
  char general_use[STD_LENGTH];
  if (MASTER (ch) == NULL)
    {
      bug ("Stop_follower: null master.", 0);
      return;
    }
  if (IS_AFFECTED (ch, AFF_CHARM))
    {
      REMOVE_BIT (ch->affected_by, AFF_CHARM);
      affect_strip (ch, gsn_charm_person);
    }
  if (can_see (MASTER (ch), ch))
    act ("$n stops following you around.", ch, NULL, MASTER (ch), TO_VICT);
  act ("You stop following $N.", ch, NULL, MASTER (ch), TO_CHAR);
  if (LEADER (ch) != NULL)
    {
      sprintf (general_use, "%s has left the group.", NAME (ch));
      group_notify (general_use, ch);
    }
  check_fgt (ch);
  ch->fgt->master = NULL;
  ch->fgt->leader = NULL;
  return;
}

void 
die_follower (CHAR_DATA * ch)
{
  CHAR_DATA *fch;
  if (MASTER (ch) != NULL)
    stop_follower (ch);
  if (!ch->fgt)
    return;
  ch->fgt->leader = NULL;
  for (fch = char_list; fch != NULL; fch = fch->next)
    {
      if (MASTER (fch) == ch)
	stop_follower (fch);
      if (LEADER (fch) == ch)
	fch->fgt->leader = fch;
    }
  return;
}

int 
chars_in_group (CHAR_DATA * ch)
{
  DESCRIPTOR_DATA *tch;
  int tally;
  tally = 0;
  if (IS_MOB (ch))
    return 1;			/*Just dummy value */
  for (tch = descriptor_list; tch != NULL; tch = tch->next)
    {
      if (tch->character == NULL || tch->connected != CON_PLAYING)
	continue;
      if (is_same_group (ch, tch->character))
	tally++;
    }
  if (tally == 0)
    tally = 1;
  return tally;
}

int 
rchars_in_group (CHAR_DATA * ch)
{
  CHAR_DATA *tch;
  int tally;
  tally = 0;
  if (IS_MOB (ch))
    return 1;			/*Just dummy value */
  for (tch = ch->in_room->more->people; tch != NULL; tch = tch->next_in_room)
    {
      if (IS_MOB (tch))
	continue;
      if (is_same_group (ch, tch))
	tally++;
    }
  if (tally == 0)
    tally = 1;
  return tally;
}

int 
tchars_in_group (CHAR_DATA * ch)
{
  CHAR_DATA *tch;
  int tally;
  tally = 0;
  if (IS_MOB (ch))
    return 1;			/*Just dummy value */
  for (tch = char_list; tch != NULL; tch = tch->next)
    {
      if (IS_MOB (tch))
	continue;
      if (is_same_group (ch, tch))
	tally++;
    }
  if (tally == 0)
    tally = 1;
  return tally;
}

void 
do_ditch (CHAR_DATA * ch, char *argy)
{
  CHAR_DATA *ditchee;
  DEFINE_COMMAND ("ditch", do_ditch, POSITION_DEAD, 0, LOG_NORMAL, "This command allows you to ditch a following character.")

    if (argy == "" || argy[0] == '\0')
    {
      send_to_char ("Ditch whom?\n\r", ch);
      return;
    }
  if ((ditchee = get_char_world (ch, argy)) == NULL)
    {
      send_to_char ("Ditch Whom?\n\r", ch);
      return;
    }
  if (ditchee == ch)
    {
      send_to_char ("Ditch yourself? Get a clue...\n\r", ch);
      return;
    }
  if ((!MASTER (ditchee) || MASTER (ditchee) != ch) &&
      (!LEADER (ditchee) || LEADER (ditchee) != ch))
    {
      send_to_char ("Ditch Whom?\n\r", ch);
      return;
    }
  send_to_char ("Player successfully ditched.\n\r", ch);
  check_fgt (ditchee);
  ditchee->fgt->master = NULL;
  ditchee->fgt->leader = NULL;
  if (IS_AFFECTED (ditchee, AFF_CHARM))
    REMOVE_BIT (ditchee->affected_by, AFF_CHARM);
  send_to_char ("The group leader has ditched you!\n\r", ditchee);
  return;
}

void 
do_group (CHAR_DATA * ch, char *argy)
{
  char buf[STD_LENGTH];
  char arg[SML_LENGTH];
  int cig;
  CHAR_DATA *victim;
  int tcig;
  DEFINE_COMMAND ("group", do_group, POSITION_DEAD, 0, LOG_NORMAL, "This command allows you to group 'all' or playername.  With no arguments, it shows info on your current group.")

    one_argy (argy, arg);
  if (arg[0] == '\0')
    {
      CHAR_DATA *gch;
      CHAR_DATA *leader;
      leader = (LEADER (ch) != NULL) ? LEADER (ch) : ch;
      sprintf (buf, "Group Leader [\x1B[37;1m%s\x1B[0m]\n\r\n\r", NAME (leader));
      send_to_char (buf, ch);
      sprintf (buf, "%14s %-14s %-18s %-14s  %s\n\r",
	       "[-Char Power-]", "--Name--", "+-Health-+", "*-Stamina-*", "=-Exp2Lvl-=");
      send_to_char (buf, ch);
      for (gch = char_list; gch != NULL; gch = gch->next)
	{
	  if (is_same_group (gch, ch))
	    {
	      char tmp[40];
#ifndef NEW_WORLD
	       if (gch == ch) sprintf(tmp, "%13d", LEVEL(ch)); else 
	      if (LEVEL (gch) < 4)
		strcpy (tmp, "Inexperienced");
	      else if (LEVEL (gch) < 12)
		strcpy (tmp, "Knowledgable");
	      else if (LEVEL (gch) < 27)
		strcpy (tmp, "Experienced");
	      else if (LEVEL (gch) < 45)
		strcpy (tmp, "Well-Known");
	      else if (LEVEL (gch) < 99)
		strcpy (tmp, "---Famous---");
	      else
		strcpy (tmp, "Immortal");
#endif
	
#ifdef NEW_WORLD
	      sprintf (buf,
		       "[%s\x1B[30;1m%-6d\x1B[37;0m] \x1B[37;1m%-14s\x1B[0m \x1B[31;1m%-18s\x1B[34m %-14s\x1B[37;0m  (%ld)\n\r",
		       (IS_PLAYER(gch)?(NO_PKILL(gch)?"\x1B[33;1mNo-PK ":"\x1B[34;1mPKill "):""),
			LEVEL(gch), (IS_MOB (gch) ? gch->pIndexData->short_descr : capitalize (PERS (gch, ch))),
		       STRING_HITS (gch), STRING_MOVES (gch), ((FIND_EXP (LEVEL (gch), gch->race)) - gch->exp));
	      send_to_char (buf, ch);
#else
	      sprintf (buf,
		       "[\x1B[30;1m%13s\x1B[37;0m] \x1B[37;1m%-14s\x1B[0m \x1B[31;1m%-18s\x1B[34m %-14s\x1B[37;0m  (%ld)\n\r",
		       tmp,
			(IS_MOB (gch) ? gch->pIndexData->short_descr : capitalize (PERS (gch, ch))),
		       STRING_HITS (gch), STRING_MOVES (gch), ((FIND_EXP (LEVEL (gch), gch->race)) - gch->exp));
	      send_to_char (buf, ch);

#endif
	    }
	}
      if (LEADER (ch) == NULL)
	cig = tchars_in_group (ch);
      else
	cig = tchars_in_group (LEADER (ch));
      if (cig > 1)
	{
	  sprintf (buf, "--Members in group: [\x1B[34;1m%d\x1B[37;0m]\n\r", cig);
	  send_to_char (buf, ch);
	}
      return;
    }
  tcig = tchars_in_group (ch);	/*added substitution, saves TONS of cpu */
  if (!str_cmp (arg, "all"))
    {
      CHAR_DATA *gch;
      if (LEADER (ch) != NULL)
	{
	  send_to_char ("You must be the leader of the group someone or ALL!\n\r", ch);
	  return;
	}
      for (gch = char_list; gch != NULL; gch = gch->next)
	{
	  if (
	       ch->in_room != NULL && !is_same_group (gch, ch) && ch->in_room == gch->in_room
	       && MASTER (gch) != NULL && MASTER (gch) == ch && LEADER (gch) == NULL
	       && tcig < 16)
	    {
	      check_fgt (gch);
	      gch->fgt->leader = ch;
	      act ("$N joins $n's group.", ch, NULL, gch, TO_NOTVICT);
	      act ("You join $n's group.", ch, NULL, gch, TO_VICT);
	      act ("$N joins your group.", ch, NULL, gch, TO_CHAR);
	      sprintf (buf, "%s has joined the group!", NAME (gch));
	      group_notify (buf, ch);
	    }
	}
      return;
    }
/*end all */
  if ((victim = get_player_world (ch, arg, FALSE)) == NULL ||
      !can_see (ch, victim))
    {
      send_to_char ("They aren't here.\n\r", ch);
      return;
    }
  if ((IS_EVIL (ch) && !IS_EVIL (victim)) || (!IS_EVIL (ch) && IS_EVIL (victim)))
    {
      send_to_char ("They aren't here.\n\r", ch);
      return;
    }
  if (MASTER (ch) != NULL || (LEADER (ch) != NULL && LEADER (ch) != ch))
    {
      send_to_char ("You can follow two people at once!\n\r", ch);
      return;
    }
  if (MASTER (victim) != ch && ch != victim)
    {
      act ("$N must be following you in order to group up.", ch, NULL, victim, TO_CHAR);
      return;
    }
  if (ch == victim)
    {
      CHAR_DATA *tch;
      send_to_char ("You disband your group.  All players stop following you.\n\r", ch);
      for (tch = char_list; tch != NULL; tch = tch->next)
	{
	  if (is_same_group (tch, ch))
	    {
	      check_fgt (tch);
	      tch->fgt->leader = NULL;
	      if (IS_PLAYER (tch))
		tch->fgt->master = NULL;
	      send_to_char ("The leader has disbanded the group, and you now follow no-one.\n\r", tch);
	    }
	}
      return;
    }
  if (is_same_group (victim, ch))
    {
      char buffy[200];
      check_fgt (victim);
      victim->fgt->leader = NULL;
      sprintf (buffy, "%s removed %s from the group.", NAME (ch), NAME (victim));
      group_notify (buffy, ch);
      return;
    }
  if (tcig > 14)
    {
      send_to_char ("Max limit of 15 players per group.\n\r", ch);
      return;
    }
  check_fgt (victim);
  victim->fgt->leader = ch;
  sprintf (buf, "%s has joined the group!", NAME (victim));
  group_notify (buf, ch);
  return;
}

void 
do_split (CHAR_DATA * ch, char *argy)
{
  char buf[STD_LENGTH];
  char arg[STD_LENGTH];
  CHAR_DATA *gch;
  char str1[1000];
  char str2[1000];
  int copper;
  int gold;
  int total_coinage;
  int members;
  int amount;
  int share;
  int counter;
  DEFINE_COMMAND ("split", do_split, POSITION_RESTING, 0, LOG_NORMAL, "This command can be used to split up coins.  It will not make change.")
if (!ch->in_room) return;
    argy = one_argy (argy, arg);
  if (arg[0] == '\0')
    {
      send_to_char ("Split how much?\n\r", ch);
      return;
    }
  amount = atoi (arg);
  if (!str_cmp (argy, "gold"))
    amount *= 100;
  if (amount < 0)
    {
      send_to_char ("Your group wouldn't like that.\n\r", ch);
      return;
    }
  if (amount == 0)
    {
      send_to_char ("Split nothing?\n\r", ch);
      return;
    }
  if (tally_coins (ch) < amount)
    {
      send_to_char ("You don't have that much money.\n\r", ch);
      return;
    }
  copper = 0;
  gold = 0;
  sprintf (str1, "%s", name_amount (amount));
  if (amount >= 100)
    {
      gold = amount / 100;
      amount %= 100;
    }
  if (amount >= 1)
    {
      copper = amount;
      amount = 0;
    }

  while (ch->gold < gold)
    {
      ch->copper -= 100;
      ch->gold++;
    }
  while (ch->copper < amount)
    {
      ch->copper += 100;
      ch->gold--;
    }

/*if (ch->gold<gold) 
   {
   send_to_char("You don't have that many gold coins!\n\r",ch); return;
   }
   if (ch->copper<copper) 
   {
   send_to_char("You don't have that many copper coins!\n\r",ch); return;
   } */
  members = 0;
  ch->pcdata->voting_on = 0;
  for (gch = ch->in_room->more->people; gch != NULL; gch = gch->next_in_room)
    {
      if (is_same_group (gch, ch) && IS_PLAYER (gch))
	{
	  gch->pcdata->voting_on = 0;
	  members++;
	}
    }
  if (members < 2)
    return;
  for (counter = 0; counter < 2; counter++)
    {
      if (counter == 0)
	amount = gold;
      if (counter == 1)
	amount = copper;
      if (amount < 1)
	continue;
      total_coinage = amount;
      share = 1;
      if (counter == 0)
	{
	  amount *= 100;
	  share *= 100;
	}
      sub_coins (amount, ch);
      while (total_coinage > 0)
	{
	  create_amount (share, ch, NULL, NULL);	/*Initial coin to the char */
	  ch->pcdata->voting_on += share;
	  total_coinage--;
	  if (total_coinage == 0)
	    goto bah;
	  for (gch = ch->in_room->more->people; gch != NULL; gch = gch->next_in_room)
	    {
	      if (IS_MOB (gch))
		continue;
	      if (gch != ch && is_same_group (gch, ch))
		{
		  total_coinage--;
		  gch->pcdata->voting_on += share;
		  create_amount (share, gch, NULL, NULL);
		  if (total_coinage == 0)
		    goto bah;
		}
	    }
	}
    bah:
	if (share) {};
    }
/*End counter */
  if (ch->pcdata->voting_on != 0)
    {
      sprintf (buf,
	       "You split %s coins.  You keep your share of %s coins.\n\r", str1, name_amount (ch->pcdata->voting_on));
      ch->pcdata->voting_on = 0;
      send_to_char (buf, ch);
    }
  for (gch = ch->in_room->more->people; gch != NULL; gch = gch->next_in_room)
    {
      if (IS_MOB (gch))
	continue;
      if (gch != ch && is_same_group (gch, ch))
	{
	  if (gch->pcdata->voting_on == 0)
	    {
	      sprintf (buf, "$n splits %s coins, but there is not enough to go around, and you receive nothing.", str1);
	      act (buf, ch, NULL, gch, TO_VICT);
	      continue;
	    }
	  sprintf (str2, "%s", name_amount (gch->pcdata->voting_on));
	  sprintf (buf, "$n splits %s coins.  Your get your portion... %s coins.", str1, str2);
	  gch->pcdata->voting_on = 0;
	  act (buf, ch, NULL, gch, TO_VICT);
	}
    }
  return;
}


bool 
is_same_group (CHAR_DATA * ach, CHAR_DATA * bch)
{
  if (LEADER (ach) != NULL)
    ach = LEADER (ach);
  if (LEADER (bch) != NULL)
    bch = LEADER (bch);
  return ach == bch;
}