/*******************************************************************************
 *         _               | File Name:   act_newc.c
 *        / \      _-'     | Description: New Action code
 *      _/|  \-''- _ /     |
 * __-' |          \       |
 *     /              \    |
 *     /       "o.  |o |   |
 *     |            \ ;    |
 *                   ',    |
 *        \_         __\   | (c) 2000-2001 TAKA
 *          ''-_    \.//   | (c) 2000-2001 The GhostMud Project Team
 *            / '-____'    |
 *           /             | You may use this code under GNU license restriction
 *         _'  The Wolf    | 1) This header block remains in the code.
 *       _-'   strikes!    | 2) You email me at a_ghost_dancer@excite.com
 *_________________________|    letting me know you are using this code
 *                              please incluse your name, your mud name
 * All rights reserved          your mud address, your email and this file
 * GhostMud is copyrighted      name.
 * by TAKA                   3) In your help files mention me where appropriate
 *                              IE: help snippets.
 *********************************************************************************/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "merc.h"
#include "recycle.h"
#include "tables.h"
#include "magic.h"

DECLARE_DO_FUN (do_knock);
DECLARE_DO_FUN (do_ushare);
DECLARE_DO_FUN (do_rename);
DECLARE_DO_FUN (do_butcher);
DECLARE_DO_FUN (do_wpeace);
DECLARE_DO_FUN (do_area_list);
DECLARE_DO_FUN (do_fremove);
DECLARE_DO_FUN (do_frecall);
DECLARE_DO_FUN (do_transfer);
DECLARE_DO_FUN (do_whowas);
DECLARE_DO_FUN (do_look);


extern void do_quit (CHAR_DATA * ch, char *argument);
extern int find_door args ((CHAR_DATA * ch, char *arg));
extern void update_handler2 (bool forced);
extern bool check_parse_name args ((char *name));
bool write_version (char *argument);
void read_version (char *version);
void do_butcher (CHAR_DATA * ch, char *argument);
extern bool remove_obj args ((CHAR_DATA * ch, int iWear, bool fReplace));
void do_frecall (CHAR_DATA * ch, char *argument);
void whowas (CHAR_DATA * ch, FILE * fp);
void do_whowas (CHAR_DATA * ch, char *argument);
void do_rsetpword (CHAR_DATA * ch, char *argument);
void do_history (CHAR_DATA * ch, char *argument);

void
strip_mortal_color (char *bufin, bool GLOBAL)
{
  const char *pointer;

  for (pointer = bufin; *pointer; pointer++)
    {
      if (*pointer == '{')
	{
	  pointer++;
	  bufin++;
	  if (*pointer == 'z')	/*blinking text reserved */
	    {
	      *bufin = ' ';
	    }
	  *bufin = ' ';
	}

      bufin++;
    }
}

/*
	Mortal spells and skills stat for immortals commands
	by TAKA     March 2000 (c)
 */

void
do_mortskill (CHAR_DATA * ch, char *argument)
{
  BUFFER *buffer;
  char arg[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  char skill_list[LEVEL_HERO + 1][MAX_STRING_LENGTH];
  char skill_columns[LEVEL_HERO + 1];
  int sn, level, min_lev = 1, max_lev = LEVEL_HERO;
  bool found = FALSE;
  CHAR_DATA *victim;

  if (IS_NPC (ch))
    return;

  one_argument (argument, arg);

  if (arg[0] == '\0')
    {
      send_to_char ("{RList skills for whom?{x\n\r", ch);
      return;
    }

  if ((victim = get_char_world (ch, argument)) == NULL)
    {
      send_to_char ("{RThey aren't here.{x\n\r", ch);
      return;
    }

  if (IS_NPC (victim))
    {
      send_to_char ("{RUse this for skills on players.{x\n\r", ch);
      return;
    }

  /* initialize data */
  for (level = 0; level < LEVEL_HERO + 1; level++)
    {
      skill_columns[level] = 0;
      skill_list[level][0] = '\0';
    }

  for (sn = 0; sn < MAX_SKILL; sn++)
    {
      if (skill_table[sn].name == NULL)
	break;

      if ((level =
	   skill_table[sn].skill_level[victim->class]) < LEVEL_HERO + 1
	  && level >= min_lev && level <= max_lev
	  && skill_table[sn].spell_fun == spell_null
	  && victim->pcdata->learned[sn] > 0)
	{
	  found = TRUE;
	  level = skill_table[sn].skill_level[victim->class];

	  if (victim->level < level)
	    sprintf (buf, "{C%-18s {Yn{W/{Ya      {x", skill_table[sn].name);
	  else
	    sprintf (buf, "{C%-18s {Y%3d%%      {x", skill_table[sn].name,
		     victim->pcdata->learned[sn]);

	  if (skill_list[level][0] == '\0')
	    sprintf (skill_list[level], "\n\rLevel {W%3d:{x %s", level, buf);
	  else			/* append */
	    {
	      if (++skill_columns[level] % 2 == 0)
		strcat (skill_list[level], "\n\r           ");
	      strcat (skill_list[level], buf);
	    }
	}
    }

  /* return results */
  if (!found)
    {
      send_to_char ("{RNo skills found.{x\n\r", ch);
      return;
    }

  buffer = new_buf ();

  for (level = 0; level < LEVEL_HERO + 1; level++)
    if (skill_list[level][0] != '\0')
      add_buf (buffer, skill_list[level]);

  add_buf (buffer, "\n\r");
  page_to_char (buf_string (buffer), ch);
  free_buf (buffer);
}

void
do_mortspell (CHAR_DATA * ch, char *argument)
{
  BUFFER *buffer;
  char buff[100];
  char arg[MAX_INPUT_LENGTH];
  char spell_list[LEVEL_HERO + 1][MAX_STRING_LENGTH];
  char spell_columns[LEVEL_HERO + 1];
  int sn, gn, col, level, min_lev = 1, max_lev = LEVEL_HERO, mana;
  bool found = FALSE;
  char buf[MAX_STRING_LENGTH];
  CHAR_DATA *victim;

  if (IS_NPC (ch))
    return;

  one_argument (argument, arg);

  if (arg[0] == '\0')
    {
      send_to_char ("{RList spells for whom?{x\n\r", ch);
      return;
    }

  if ((victim = get_char_world (ch, argument)) == NULL)
    {
      send_to_char ("{RThey aren't here.{x\n\r", ch);
      return;
    }

  if (IS_NPC (victim))
    {
      send_to_char ("{RUse this for skills on players.{x\n\r", ch);
      return;
    }

  /* groups */
  col = 0;
  for (gn = 0; gn < MAX_GROUP; gn++)
    {
      if (group_table[gn].name == NULL)
	break;
      if (victim->pcdata->group_known[gn])
	{
	  sprintf (buff, "{G%-20s{x ", group_table[gn].name);
	  send_to_char (buff, ch);

	  if (++col % 3 == 0)
	    send_to_char ("\n\r", ch);
	}
    }

  if (col % 3 != 0)
    {
      send_to_char ("\n\r", ch);
      sprintf (buff, "{GCreation points: {W%d{x\n\r", victim->pcdata->points);
      send_to_char (buff, ch);
    }

  /* initialize data */
  for (level = 0; level < LEVEL_HERO + 1; level++)
    {
      spell_columns[level] = 0;
      spell_list[level][0] = '\0';
    }

  for (sn = 0; sn < MAX_SKILL; sn++)
    {
      if (skill_table[sn].name == NULL)
	break;

      if ((level =
	   skill_table[sn].skill_level[victim->class]) < LEVEL_HERO + 1
	  && level >= min_lev && level <= max_lev
	  && skill_table[sn].spell_fun != spell_null
	  && victim->pcdata->learned[sn] > 0)
	{
	  found = TRUE;
	  level = skill_table[sn].skill_level[victim->class];
	  if (victim->level < level)
	    sprintf (buf, "{C%-18s {Yn{W/{Ya{x      ", skill_table[sn].name);
	  else
	    {
	      mana =
		UMAX (skill_table[sn].min_mana,
		      100 / (2 + victim->level - level));
	      sprintf (buf, "{C%-18s  {Y%3d {Gmana{x  ", skill_table[sn].name,
		       mana);
	    }

	  if (spell_list[level][0] == '\0')
	    sprintf (spell_list[level], "\n\rLevel {W%3d:{x %s", level, buf);
	  else			/* append */
	    {
	      if (++spell_columns[level] % 2 == 0)
		strcat (spell_list[level], "\n\r           ");
	      strcat (spell_list[level], buf);
	    }
	}
    }

  /* return results */
  if (!found)
    {
      send_to_char ("{RNo spells found.{x\n\r", ch);
      return;
    }

  buffer = new_buf ();
  for (level = 0; level < LEVEL_HERO + 1; level++)
    if (spell_list[level][0] != '\0')
      add_buf (buffer, spell_list[level]);
  add_buf (buffer, "\n\r");
  page_to_char (buf_string (buffer), ch);
  free_buf (buffer);
}

/* End TAKA     spell adds */

/*
 * UNREMORT by TAKA of Ghost Dancer mud project.....
 * (c) 2000 TAKA
 */

bool do_unremort
args ((CHAR_DATA * ch, char *argument))
{

  char strsave[MAX_INPUT_LENGTH];
  char strbackup[MAX_INPUT_LENGTH + 4];
  char buf[MAX_INPUT_LENGTH + 4];
  FILE *fp;
  int result;

  sprintf (strsave, "%s%s", PLAYER_DIR, capitalize (ch->name));
  strcpy (strbackup, strsave);
  strcat (strbackup, ".rmt");

  if ((fp = fopen (strbackup, "r")) == NULL)
    {
      send_to_char
	("Invalid unremort state or you have already unremorted!\n\r", ch);
      bug ("close file", 0);
      return FALSE;
    }
  fclose (fp);

  /*
   * unlink player
   */
  send_to_char ("wait about 30 seconds then resign in.....\n\r", ch);
  do_quit (ch, "");


  /*
   * reset old pfile
   */
  unlink (strsave);
  result = rename (strbackup, strsave);
  if (result != 0)
    {
      sprintf (buf, "%s was not renamed to %s", strbackup, strsave);
      bug (buf, 0);
    }
  else
    {
      sprintf (buf, "%s was renamed to %s", strbackup, strsave);
      bug (buf, 0);
    }

  return TRUE;
}


/*
	I saw comm stat on dark scapes I liked it and it and swiped it
	the idea for me started there the code however is all original
	-- TAKA
 */

void
do_commstat (CHAR_DATA * ch, char *argument)
{

  DESCRIPTOR_DATA *d;
  char buf[MAX_INPUT_LENGTH + 80];

  send_to_char
    ("{W  Player   gos auc mus  ?  quo gra rac sho qui AFK dea{x\n\r", ch);

  for (d = descriptor_list; d != NULL; d = d->next)
    {
      CHAR_DATA *victim;
      victim = (d->original != NULL) ? d->original : d->character;

      if (d->connected != CON_PLAYING || !can_see (ch, d->character))
	continue;

      sprintf (buf, "{W%-10s{G %s %s %s %s %s %s %s %s %s %s %s\n\r",
	       victim->name, IS_SET (victim->comm,
				     COMM_NOGOSSIP) ? "OFF" : "ON ",
	       IS_SET (victim->comm, COMM_NOAUCTION) ? "OFF" : "ON ",
	       IS_SET (victim->comm, COMM_NOMUSIC) ? "OFF" : "ON ",
	       IS_SET (victim->comm, COMM_NOQUESTION) ? "OFF" : "ON ",
	       IS_SET (victim->comm, COMM_NOQUOTE) ? "OFF" : "ON ",
	       IS_SET (victim->comm, COMM_NOGRATS) ? "OFF" : "ON ",
	       /*IS_SET(victim->comm,COMM_NORACE)?"OFF":"ON ", */
	       "OFF",
	       IS_SET (victim->comm, COMM_NOSHOUT) ? "OFF" : "ON ",
	       IS_SET (victim->comm, COMM_QUIET) ? "{RON {x" : "{ROFF{x",
	       IS_SET (victim->comm, COMM_AFK) ? "{YYes{x" : "{YNo {x",
	       IS_SET (victim->comm, COMM_DEAF) ? "{DON {x" : "{DOFF{x");
      send_to_char (buf, ch);

      if (IS_IMMORTAL (ch))
	{
	  sprintf (buf, "{MGod channel: %s  %s\n\r",
		   IS_SET (victim->comm, COMM_NOWIZ) ? "OFF " : " ON ",
		   IS_SET (victim->comm,
			   COMM_SNOOP_PROOF) ? "{CImmune to snooping.{x\n\r" :
		   "{CNot Immune to snooping.{x\n\r");
	  send_to_char (buf, ch);
	}
    }
  return;
}

/**************************************************************************/

/*
 *  This function allows a character to knock on a door.
 *  -- TAKA (you're welcome)
 */

void
do_knock (CHAR_DATA * ch, char *argument)
{
  /* Some code taken from do_open().  */
  long door;
  char arg[MAX_INPUT_LENGTH];

  one_argument (argument, arg);

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

  if ((door = find_door (ch, arg)) >= 0)
    {
      ROOM_INDEX_DATA *to_room;
      EXIT_DATA *pexit;
      EXIT_DATA *pexit_rev;

      pexit = ch->in_room->exit[door];

      act ("{W$n {Rknocks on the $d.{x", ch, NULL, pexit->keyword, TO_ROOM);
      act ("{RYou knock on the $d.{x", ch, NULL, pexit->keyword, TO_CHAR);

      /* Notify the other side.  */
      if ((to_room = pexit->u1.to_room) != NULL
	  && (pexit_rev = to_room->exit[rev_dir[door]]) != NULL
	  && pexit_rev->u1.to_room == ch->in_room)
	{
	  CHAR_DATA *rch;
	  for (rch = to_room->people; rch != NULL; rch = rch->next_in_room)
	    act ("{RYou hear someone knocking.{x", rch, NULL,
		 pexit_rev->keyword, TO_CHAR);
	}
    }
  return;
}


void
do_ushare (CHAR_DATA * ch, char *argument)	/* by Maniac */
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];


  if (argument[0] == '\0')	/* No options ??? */
    {
      send_to_char ("Ushare\n\r", ch);
      send_to_char ("Ushare bankI   (share_value1).\n\r", ch);
      send_to_char ("Ushare bankII  (share_value2).\n\r", ch);
      send_to_char ("Ushare bankIII (share_value3).\n\r", ch);
      send_to_char ("Ushare bankIV  (share_value4).\n\r", ch);

      return;
    }

  argument = one_argument (argument, arg1);
  if (!str_prefix (arg1, "bankI"))
    {

      argument = one_argument (argument, arg2);
      /*
         * Snarf the value (which need not be numeric).
       */
      share_value1 = is_number (arg2) ? atoi (arg2) : -1;

      if (share_value1 < 0)
	share_value1 = 1;

      bank_update2 ();
      send_to_char ("Ok...bank share value I updated.\n\r", ch);

      return;
    }

  if (!str_prefix (arg1, "bankII"))
    {

      argument = one_argument (argument, arg2);
      /*
         * Snarf the value (which need not be numeric).
       */
      share_value2 = is_number (arg2) ? atoi (arg2) : -1;

      if (share_value2 < 0)
	share_value2 = 1;

      bank_update2 ();
      send_to_char ("Ok...bank share value II updated.\n\r", ch);

      return;
    }

  if (!str_prefix (arg1, "bankIII"))
    {

      argument = one_argument (argument, arg2);
      /*
         * Snarf the value (which need not be numeric).
       */
      share_value3 = is_number (arg2) ? atoi (arg2) : -1;

      if (share_value3 < 0)
	share_value3 = 1;

      bank_update2 ();
      send_to_char ("Ok...bank share value III updated.\n\r", ch);

      return;
    }

  if (!str_prefix (arg1, "bankIV"))
    {

      argument = one_argument (argument, arg2);
      /*
         * Snarf the value (which need not be numeric).
       */
      share_value4 = is_number (arg2) ? atoi (arg2) : -1;

      if (share_value4 < 0)
	share_value4 = 1;

      bank_update2 ();
      send_to_char ("Ok...bank share value IV updated.\n\r", ch);

      return;
    }

  return;
}

/* allow force tick */

void
do_force_tick (CHAR_DATA * ch, char *argument)
{
  update_handler2 (TRUE);
  send_to_char ("You Have Forced Time To Fly By....TICK\n\r", ch);
  return;
}

/* end force tick TAKA     */

/*
 * Coded by: Thale (Andrew Maslin)
 * Syntax: Rename <victim> <new_name>
 * Limitations: This header must be kept with this function.  In addition,
 * this file is subject to the ROM license.  The code in this file is
 * copywritten by Andrew Maslin, 1998.  If you have a "credits" help in your
 * mud, please add the name Thale to that as credit for this function.
 */

void
do_rename (CHAR_DATA * ch, char *argument)
{
  CHAR_DATA *victim;
  FILE *fp;
  char strsave[MAX_INPUT_LENGTH];
  char *name;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char buf[MAX_INPUT_LENGTH];
  char playerfile[MAX_INPUT_LENGTH];

  if (!IS_IMMORTAL (ch))
    {
      send_to_char ("{RYou don't have the power to do that.{x\n\r", ch);
      return;
    }

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

  if (arg1[0] == '\0')
    {
      send_to_char ("{RRename who?{x\n\r", ch);
      return;
    }

  if (arg2[0] == '\0')
    {
      send_to_char ("{RWhat should their new name be?{x\n\r", ch);
      return;
    }

  arg2[0] = UPPER (arg2[0]);

  if ((victim = get_char_world (ch, arg1)) == NULL)
    {
      send_to_char ("{RThey aren't connected.{x\n\r", ch);
      return;
    }

  if (IS_NPC (victim))
    {
      send_to_char ("{RUse string for NPC's.{x\n\r", ch);
      return;
    }

  if (!check_parse_name (arg2))
    {
      sprintf (buf, "{RThe name {c%s{x is {Rnot allowed{x.\n\r", arg2);
      send_to_char (buf, ch);
      return;
    }

  sprintf (playerfile, "%s%s", PLAYER_DIR, capitalize (arg2));

  if ((fp = fopen (playerfile, "r")) != NULL)
    {
      sprintf (buf, "{RThere is already someone named {W%s{R.{x\n\r",
	       capitalize (arg2));
      send_to_char (buf, ch);
      fclose (fp);
      return;
    }

  if ((victim->level >= ch->level) && (victim->level >= ch->trust)
      && ((ch->level != IMPLEMENTOR) || (ch->trust != IMPLEMENTOR))
      && (ch != victim))
    {
      send_to_char ("{RI don't think that's a good idea.{x\n\r", ch);
      return;
    }

  if (victim->position == POS_FIGHTING)
    {
      send_to_char ("{RThey are fighting right now.{x\n\r", ch);
      return;
    }

  name = str_dup (victim->name);
  sprintf (strsave, "%s%s", PLAYER_DIR, capitalize (victim->name));
  arg2[0] = UPPER (arg2[0]);
  free_string (victim->name);
  victim->name = str_dup (arg2);
  save_char_obj (victim);
  unlink (strsave);

#if defined(unix)
  if (IS_IMMORTAL (victim))
    {
      sprintf (strsave, "%s%s", GOD_DIR, capitalize (name));
      unlink (strsave);
    }
#endif

  if (victim != ch)
    {
      sprintf (buf, "{YNOTICE: {xYou have been renamed to {c%s{x.\n\r", arg2);
      send_to_char (buf, victim);
    }

  send_to_char ("{RDone.{x\n\r", ch);
  return;
}

/*
 * Version command read/write ect...
 * by TAKA
 */

void
do_version (CHAR_DATA * ch, char *argument)
{
  char version[MAX_STRING_LENGTH];
  char buf[MAX_STRING_LENGTH];

  version[0] = '\0';

  if (IS_NPC (ch))
    return;

  if (ch->level < MAX_LEVEL)	/* Stuff trusted characters! */
    {
      read_version (version);
      sprintf (buf, "Current version is :- %s\n\r", version);
      send_to_char (buf, ch);
      return;
    }
  else
    {
      if (argument[0] == '\0')
	{
	  read_version (version);
	  sprintf (buf, "Current version is :- %s\n\r", version);
	  send_to_char (buf, ch);
	  return;
	}
      else
	{
	  if (write_version (argument))
	    {
	      sprintf (buf, "Current version changed to %s\n\r", argument);
	      send_to_char (buf, ch);
	      sprintf (buf, "%s has changed the current version number to %s",
		       ch->name, argument);
	      log_string (buf);
	    }
	  else
	    send_to_char ("Write version failed - please report", ch);

	  /* report it on wiznet as well if you like... */
	  return;
	}
    }

}


bool
write_version (char *argument)	/*Returns true if sucsessful, else false */
{
  FILE *versionfp;
  bool situation;
  char buf[MAX_STRING_LENGTH];

  fclose (fpReserve);

  if ((versionfp = fopen (VERSION_FILE, "w")) == NULL)
    {
      bug ("write_version : can't open version file", 0);
      situation = FALSE;
    }
  else
    {
      sprintf (buf, "%s\n", argument);

      fprintf (versionfp, "#\n");
      fprintf (versionfp, buf);

      fclose (versionfp);
      situation = TRUE;
    }

  fpReserve = fopen (NULL_FILE, "r");

  return situation;
}

void
read_version (char *version)	/*dumps the version No. in version */
{
  FILE *versionfp;

  fclose (fpReserve);

  if ((versionfp = fopen (VERSION_FILE, "r")) == NULL)
    {
      bug ("read_version : can't open version file", 0);
      sprintf (version, "V0.0 -- Please report!\n\r");
    }
  else
    {
      if (fread_letter (versionfp) != '#')
	{
	  bug ("read_version : # not found", 0);
	  sprintf (version, "V0.0 -- Please report!\n\r");
	  fclose (versionfp);
	}
      else
	{
	  sprintf (version, fread_string_eol (versionfp));
	  fclose (versionfp);
	}
    }

  fpReserve = fopen (NULL_FILE, "r");

  return;
}

/* end of versions code by TAKA */

/*
 * new commands added here are all by TAKA
 * of ghost dancer.
 * butcher	- allows player to butcher corpses for food.
 */

/* Butcher Skill By TAKA     */
void
do_butcher (CHAR_DATA * ch, char *argument)
{

  /* If you have an interest in this skill, feel free */
  /* to use it in your mud if you so desire. */

  char buf[MAX_STRING_LENGTH];
  char arg[MAX_STRING_LENGTH];
  int numst = 0;
  OBJ_DATA *steak;
  OBJ_DATA *obj;

  one_argument (argument, arg);

  if (get_skill (ch, gsn_butcher) == 0)
    {
      send_to_char ("Butchering is beyond your skills.\n\r", ch);
      return;
    }

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

  obj = get_obj_list (ch, arg, ch->in_room->contents);

  if (obj == NULL)
    {
      send_to_char ("It's not here.\n\r", ch);
      return;
    }

  if ((obj->item_type != ITEM_CORPSE_NPC)
      && (obj->item_type != ITEM_CORPSE_PC))
    {
      send_to_char ("You can only butcher corpses.\n\r", ch);
      return;
    }

  /* create and rename the steak */
  buf[0] = '\0';
  strcat (buf, "A steak of ");
  strcat (buf, str_dup (obj->short_descr));
  strcat (buf, " is here.");

  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);

  steak->description = str_dup (buf);
  steak->value[0] = ch->level / 2;
  steak->value[1] = ch->level;

  buf[0] = '\0';
  strcat (buf, "A steak of ");
  strcat (buf, str_dup (obj->short_descr));

  steak->short_descr = str_dup (buf);

  /* Check the skill roll, and put a random ammount of steaks here. */
  if (number_percent () < get_skill (ch, gsn_butcher))
    {
      numst = dice (1, 4);
      switch (numst)
	{
	case 1:
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  act ("$n butchers a corpse and creates a steak.", ch, steak, NULL,
	       TO_ROOM);
	  act ("You butcher a corpse and create a steak.", ch, steak, NULL,
	       TO_CHAR);
	  break;
	case 2:
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  act ("$n butchers a corpse and creates two steaks.", ch, steak,
	       NULL, TO_ROOM);
	  act ("You butcher a corpse and create two steaks.", ch, steak, NULL,
	       TO_CHAR);
	  break;
	case 3:
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  act ("$n butchers a corpse and creates three steaks.", ch, steak,
	       NULL, TO_ROOM);
	  act ("You butcher a corpse and create three steaks.", ch, steak,
	       NULL, TO_CHAR);
	  break;
	case 4:
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  steak = create_object (get_obj_index (OBJ_VNUM_STEAK), 0);
	  obj_to_room (steak, ch->in_room);
	  act ("$n butchers a corpse and creates four steaks.", ch, steak,
	       NULL, TO_ROOM);
	  act ("You butcher a corpse and create four steaks.", ch, steak,
	       NULL, TO_CHAR);
	  break;
	}
      check_improve (ch, gsn_butcher, TRUE, 1);

    }
  else
    {
      act ("$n fails to butcher a corpse, and destroys it.", ch, steak, NULL,
	   TO_ROOM);
      act ("You fail to butcher a corpse, and destroy it.", ch, steak, NULL,
	   TO_CHAR);
      check_improve (ch, gsn_butcher, FALSE, 1);
    }
  /* dump items caried */
  /* Taken from the original ROM code and added into here. */

  if (obj->item_type == ITEM_CORPSE_PC)
    {				/* save the contents */
      {
	OBJ_DATA *t_obj, *next_obj;
	for (t_obj = obj->contains; t_obj != NULL; t_obj = next_obj)
	  {
	    next_obj = t_obj->next_content;
	    obj_from_obj (t_obj);
	    if (obj->in_obj)	/* in another object */
	      obj_to_obj (t_obj, obj->in_obj);
	    else if (obj->carried_by)	/* carried */
	      if (obj->wear_loc == WEAR_FLOAT)
		if (obj->carried_by->in_room == NULL)
		  extract_obj (t_obj);
		else
		  obj_to_room (t_obj, obj->carried_by->in_room);
	      else
		obj_to_char (t_obj, obj->carried_by);
	    else if (obj->in_room == NULL)	/* destroy it */
	      extract_obj (t_obj);
	    else		/* to a room */
	      obj_to_room (t_obj, obj->in_room);
	  }
      }
    }
  if (obj->item_type == ITEM_CORPSE_NPC)
    {
      {
	OBJ_DATA *t_obj, *next_obj;
	for (t_obj = obj->contains; t_obj != NULL; t_obj = next_obj)
	  {
	    next_obj = t_obj->next_content;
	    obj_from_obj (t_obj);
	    if (obj->in_obj)	/* in another object */
	      obj_to_obj (t_obj, obj->in_obj);
	    else if (obj->carried_by)	/* carried */
	      if (obj->wear_loc == WEAR_FLOAT)
		if (obj->carried_by->in_room == NULL)
		  extract_obj (t_obj);
		else
		  obj_to_room (t_obj, obj->carried_by->in_room);
	      else
		obj_to_char (t_obj, obj->carried_by);
	    else if (obj->in_room == NULL)	/* destroy it */
	      extract_obj (t_obj);
	    else		/* to a room */
	      obj_to_room (t_obj, obj->in_room);
	  }
      }
    }

  /* Now remove the corpse */
  extract_obj (obj);
  return;
}

/*
 * (c) TAKA 2000 Ghost Dancer MUD Project
 * forced remove and sieze
 */

void
do_fremove (CHAR_DATA * ch, char *argument)
{
  char arg1[MAX_INPUT_LENGTH];
  CHAR_DATA *victim;
  OBJ_DATA *obj_next;
  OBJ_DATA *obj;

  argument = one_argument (argument, arg1);

  if (arg1[0] == '\0')
    {
      send_to_char ("Syntax: fremove <char>\n\r", ch);
      return;
    }

  if ((victim = get_char_world (ch, arg1)) == NULL)
    {
      send_to_char ("That player is not here.\n\r", ch);
      return;
    }

  if (victim->level > get_trust (ch))
    {
      send_to_char ("Limited to your trust level.\n\r", ch);
      return;
    }

  for (obj = victim->carrying; obj; obj = obj_next)
    {
      obj_next = obj->next_content;
      if (obj->wear_loc != WEAR_NONE)
	{
	  remove_obj (victim, obj->wear_loc, TRUE);
	  obj_from_char (obj);
	  obj_to_char (obj, ch);
	}
    }

  save_char_obj (victim);
  return;
}

/*
 * (c) 2000 TAKA
 * makes the world at peace took some of the code from do_peace
 */

void
do_wpeace (CHAR_DATA * ch, char *argument)
{
  CHAR_DATA *rch;
  char buf[MAX_STRING_LENGTH];

  rch = get_char_world (ch, buf);

  for (rch = char_list; rch; rch = rch->next)
    {
      if (ch->desc == NULL || ch->desc->connected != CON_PLAYING)
	continue;
      if (rch->fighting)
	{
	  sprintf (buf, "%s has declared World Peace.\n\r", ch->name);
	  send_to_char (buf, rch);
	  stop_fighting (rch, TRUE);
	}
    }
  send_to_char ("You have declared World Peace.\n\r", ch);
  return;
}


/*
 * (c) 2000 TAKA Ghost Dancer MUD Project
 * list all areas
 */
void
do_area_list (CHAR_DATA * ch, char *argument)
{
  BUFFER *output;
  char buf[MAX_STRING_LENGTH];
  char result[MAX_STRING_LENGTH * 2];	/* May need tweaking. */
  AREA_DATA *pArea;

  output = new_buf ();

  sprintf (result,
	   "{C[{M%3s{C] [{W%-27s{C] ({G%-5s{W-{G%5s{C) [{B%-10s{C]{x\n\r",
	   "Num", "Area Name", "lvnum", "uvnum", "Filename");
  send_to_char (result, ch);

  for (pArea = area_first; pArea; pArea = pArea->next)
    {
      sprintf (buf,
	       "{C[{M%3ld{C] {W%-29.29s {C({G%-5ld{W-{G%5ld{C) {B%-12.12s{x\n\r",
	       pArea->vnum, pArea->name, pArea->min_vnum, pArea->max_vnum,
	       pArea->file_name);
      add_buf (output, buf);
    }

  page_to_char (buf_string (output), ch);
  free_buf (output);
}

/*
 * (c) 2000 TAKA Ghost Dancer MUD Project
 * Loads a player file.
 */
void
do_lpfile (CHAR_DATA * ch, char *argument)
{
  DESCRIPTOR_DATA d;
  bool isChar = FALSE;
  char name[MAX_INPUT_LENGTH];

  if (argument[0] == '\0')
    {
      send_to_char ("{RLoad who?{x\n\r", ch);
      return;
    }

  argument[0] = UPPER (argument[0]);
  argument = one_argument (argument, name);

  /*
   * if player is already on do not load it
   */
  if (get_char_world (ch, name) != NULL)
    {
      send_to_char ("{RThat person is allready playing!{x\n\r", ch);
      return;
    }

  isChar = load_char_obj (&d, name);	/* char pfile exists? */

  if (!isChar)
    {
      send_to_char ("{RThey do not exist!{x\n\r", ch);
      return;
    }

  d.character->desc = NULL;
  d.character->next = char_list;
  char_list = d.character;
  d.connected = CON_PLAYING;
  reset_char (d.character);

  /*
   * player to imm room
   */
  if (d.character->in_room != NULL)
    {
      char_to_room (d.character, ch->in_room);
    }

  act ("{W$n {Ghas loaded {W$N!{x", ch, NULL, d.character, TO_ROOM);

  if (d.character->pet != NULL)
    {
      char_to_room (d.character->pet, d.character->in_room);
      act ("{W$n {Ghas entered the game.{x", d.character->pet, NULL, NULL,
	   TO_ROOM);
    }

}

/*
 * (c) 2000 TAKA Ghost Dancer MUD Project
 * Loads a player file.
 */
void
do_ulpfile (CHAR_DATA * ch, char *argument)
{
  CHAR_DATA *victim;
  char who[MAX_INPUT_LENGTH];

  argument = one_argument (argument, who);

  /*
   * unload only if found in the world
   */
  if ((victim = get_char_world (ch, who)) == NULL)
    {
      send_to_char ("{RThey aren't here.{x\n\r", ch);
      return;
    }

  /*
   * player description == NULL then the player was a loaded pfile!
   */
  if (victim->desc != NULL)
    {
      send_to_char ("{RI dont think that would be a good idea...{x\n\r", ch);
      return;
    }

  /*
   * return player and pet to thier original room
   */
  if (victim->was_in_room != NULL)
    {
      char_to_room (victim, victim->was_in_room);
      if (victim->pet != NULL)
	char_to_room (victim->pet, victim->was_in_room);
    }

  save_char_obj (victim);
  do_quit (victim, "");

  act ("{W$n {Ghas released {W$N!", ch, NULL, victim, TO_ROOM);
}

/*
 * (c) TAKA 2000 Ghost Dancer MUD Project
 * IMM Set password command
 */

void
do_rsetpword (CHAR_DATA * ch, char *argument)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  CHAR_DATA *victim;
  char *pwdnew;

  if (IS_NPC (ch))
    return;

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

  victim = get_char_world (ch, arg1);

  if ((ch->pcdata->pwd != '\0') && (arg1[0] == '\0' || arg2[0] == '\0'))
    {
      send_to_char ("Syntax: rsetpword <char> <new>.\n\r", ch);
      return;
    }
  if (victim == '\0')
    {
      send_to_char
	("That person isn't here, they have to be here to reset pwd's.\n\r",
	 ch);
      return;
    }
  if (IS_NPC (victim))
    {
      send_to_char ("You cannot change the password of NPCs!\n\r", ch);
      return;
    }

  if ((victim->level > LEVEL_IMMORTAL)
      || (get_trust (victim) > LEVEL_IMMORTAL))
    {
      send_to_char ("You can't change the password of that player.\n\r", ch);
      return;
    }

  if (strlen (arg2) < 5)
    {
      send_to_char ("New password must be at least five characters long.\n\r",
		    ch);
      return;
    }

  pwdnew = (char *) crypt (arg2, victim->name);
  free_string (victim->pcdata->pwd);
  victim->pcdata->pwd = str_dup (pwdnew);
  save_char_obj (victim);
  send_to_char ("Ok.\n\r", ch);
  sprintf (buf, "Your password has been changed to %s.", arg2);
  send_to_char (buf, victim);
  return;
}

/*
 * (c) 2000 TAKA Ghost Dancer MUD Project
 * gets the player pword for the imp!
 */
void
do_getpw (CHAR_DATA * ch, char *argument)
{
  CHAR_DATA *victim;
  char buf[MAX_STRING_LENGTH];

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

  if ((victim = get_char_world (ch, argument)) == NULL)
    {
      send_to_char ("You can't find them.\n\r", ch);
      return;
    }


  sprintf (buf, "PW = %s", victim->pcdata->pwd);	/*(char *) crypt(ch->pcdata->pwd, ch->name)); */
  send_to_char (buf, ch);
  return;

}

/*
 * Lore written by TAKA (c) 2000 Ghost Dancer MUD Project
 */
void
do_lore (CHAR_DATA * ch, char *argument)
{
  OBJ_DATA *obj;
  char arg[MAX_STRING_LENGTH];
  char buf[MAX_STRING_LENGTH];

  one_argument (argument, arg);

  obj = get_obj_world (ch, arg);

  if (obj == NULL)
    {
      sprintf (buf, "You've never heard of a %s.\n\r", arg);
      send_to_char (buf, ch);
      return;
    }

  if (get_skill (ch, gsn_lore) == 0)
    {
      send_to_char ("You don't know anything about it.\n\r", ch);
      return;
    }

  if (arg[0] == '\0')
    {
      send_to_char ("What do you want information on?\n\r", ch);
      return;
    }

  if (number_percent () < get_skill (ch, gsn_lore))
    {
      sprintf (buf, "'%s' is type %s, extra flags %s.\n\rLevel %d.\n\r",
	       obj->name, item_name (obj->item_type),
	       extra_bit_name (obj->extra_flags), obj->level);
      send_to_char (buf, ch);

      check_improve (ch, gsn_lore, TRUE, 1);
    }
  else
    {
      send_to_char ("You can't remember a thing about it.\n\r", ch);
      check_improve (ch, gsn_lore, FALSE, 1);
    }

  return;
}

/*
 * forced recall for when a player was accidentally trapped in a
 * no recall, no teleport, type area.
 * It should only be used if the imm was at fualt for the mess
 * It give a message on wiznet.
 *
 * (c) 2000 TAKA Ghost Dancer MUD Project
 * a PYROX - ribbed for her pleasure - original idea!
 *
 * It will only transfer them to the temple vnum nowhere else
 * so i believe it safe for a low level imm.
 */

void
do_frecall (CHAR_DATA * ch, char *argument)
{
  char arg[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  CHAR_DATA *victim;

  one_argument (argument, arg);

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

  if ((victim = get_char_world (ch, arg)) == NULL)
    {
      send_to_char ("{RThey aren't here.{x\n\r", ch);
      return;
    }

  if (IS_NPC (victim))
    {
      send_to_char ("{RNot on NPC's.{x\n\r", ch);
      return;
    }

  if (get_trust (victim) >= get_trust (ch))
    {
      send_to_char ("{RYou failed.{x\n\r", ch);
      return;
    }

  sprintf (buf, "$N force recalled %s", victim->name);
  wiznet (buf, ch, NULL, WIZ_PENALTIES, WIZ_SECURE, 0);
  send_to_char ("Force Recall Done.\n\r", ch);

  stop_fighting (victim, TRUE);
  sprintf (buf, "%s %d", victim->name, ROOM_VNUM_TEMPLE);

  do_transfer (ch, buf);

  return;
}


/*
 * This is whowas for players logged off
 * parts of this stolen from load_characer
 */

void
do_whowas (CHAR_DATA * ch, char *argument)
{

  FILE *fp;
  char arg[MAX_INPUT_LENGTH];
  char strsave[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  char *name;
  DESCRIPTOR_DATA *d;
  bool found = FALSE;
  char letter;
  char *word;

  one_argument (argument, arg);

  if (arg[0] == '\0')
    {
      send_to_char ("You must provide a name.\n\r", ch);
      return;
    }

  name = arg;

  for (d = descriptor_list; d; d = d->next)
    {
      CHAR_DATA *wch;

      if (d->connected != CON_PLAYING || !can_see (ch, d->character))
	continue;

      wch = (d->original != NULL) ? d->original : d->character;

      if (!can_see (ch, wch))
	continue;

      if (!str_prefix (arg, wch->name))
	{
	  found = TRUE;
	  if ((wch->level > ch->level) && !can_see (wch, ch))
	    {
	      sprintf (buf, "{GName:{W %s %s{x\n\r", wch->name,
		       wch->pcdata->title);
	      send_to_char (buf, ch);

	      if (wch->level >= LEVEL_IMMORTAL)
		{
		  sprintf (buf, "{RIs an IMMORTAL.{x\n\r");
		  send_to_char (buf, ch);
		  sprintf (buf,
			   "{GLevel:{W %d {GRace:{W %s{G Class:{W %s{x\n\r",
			   wch->level, race_table[wch->race].name,
			   class_table[wch->class].name);

		}
	      else
		sprintf (buf,
			 "{GLevel:{W %d {GRace:{W %s{G Class:{W %s{x\n\r",
			 wch->level, race_table[wch->race].name,
			 class_table[wch->class].name);

	      send_to_char (buf, ch);

	      send_to_char ("{CHistory{x\n\r", ch);
	      sprintf (buf, ch->pcdata->history);
	      send_to_char (buf, ch);


	    }
	}
    }

  if (found)
    {
      send_to_char ("That char is playing right now use whois.\n\r", ch);
      return;
    }
  else
    {
      /* open file */
#if defined(unix)
      /* decompress if .gz file exists */
      sprintf (strsave, "%s%s%s", PLAYER_DIR, capitalize (name), ".gz");
      if ((fp = fopen (strsave, "r")) != NULL)
	{
	  fclose (fp);
	  sprintf (buf, "gzip -dfq %s", strsave);
	  system (buf);
	}
#endif

      sprintf (strsave, "%s%s", PLAYER_DIR, capitalize (name));
      if ((fp = fopen (strsave, "r")) != NULL)	/* open file */
	{
	  letter = fread_letter (fp);

	  if (letter == '*')
	    fread_to_eol (fp);

	  if (letter != '#')
	    {
	      bug ("Do_whowas: # not found.", 0);
	      return;
	    }

	  word = fread_word (fp);

	  if (str_cmp (word, "PLAYER"))
	    {
	      bug ("Bug in whowas: File opened is not Player file.", 0);
	      fclose (fp);
	      return;
	    }

	  whowas (ch, fp);
	  fclose (fp);
	}
      else
	{
	  send_to_char ("There is no player by that name.\n\r", ch);
	  return;
	}

    }

}


/*
 * get file information
 */
void
whowas (CHAR_DATA * ch, FILE * fp)
{
  char buf[MAX_STRING_LENGTH];
  char *word;
  bool fMatch;
  char *name, *race, *date, *title, *history;
  int classnum, level, sex;
  long LLogT;

/* Initialize variables to Error checking states. */

  name = NULL;
  race = NULL;
  history = NULL;
  date = NULL;
  title = NULL;
  classnum = -1;
  level = -1;
  sex = -1;

  for (;;)
    {
      word = feof (fp) ? "End" : fread_word (fp);
      fMatch = FALSE;

      switch (UPPER (word[0]))
	{
	case '*':
	  fMatch = TRUE;
	  fread_to_eol (fp);
	  break;

	case 'C':
	  if (!str_cmp (word, "Cla"))
	    {
	      classnum = fread_number (fp);
	      fMatch = TRUE;
	      break;
	    }
	  break;

	case 'E':
	  if (!str_cmp (word, "End"))
	    {
	      if ((name == NULL) || (race == NULL)
/*                   ||(date    == NULL) */
		  || (sex == -1) || (classnum == -1) || (level == -1))
		{
		  send_to_char ("Information not available.\n\r", ch);
		  return;
		}

	      sprintf (buf, "{GName:{W %s %s{x\n\r", name, title);
	      send_to_char (buf, ch);

	      if (level >= LEVEL_IMMORTAL)
		{
		  sprintf (buf, "{RIs an IMMORTAL.{x\n\r");
		  send_to_char (buf, ch);
		  sprintf (buf,
			   "{GLevel:{W %d {GRace:{W %s{G Class:{W %s{x\n\r",
			   level, race, class_table[classnum].name);

		}
	      else
		sprintf (buf,
			 "{GLevel:{W %d {GRace:{W %s{G Class:{W %s{x\n\r",
			 level, race, class_table[classnum].name);

	      send_to_char (buf, ch);

	      if (((ch->level >= LEVEL_IMMORTAL) && (ch->level >= level))
		  || (level < LEVEL_IMMORTAL))
		{
		  sprintf (buf, "{YLast seen on:{m %s{x\n\r",
			   (char *) ctime (&LLogT));
		  send_to_char (buf, ch);
		}

	      send_to_char ("{CHistory{x\n\r", ch);
	      sprintf (buf, history);
	      send_to_char (buf, ch);


	      free_string (name);
	      free_string (race);
	      free_string (date);
	      free_string (title);
	      return;
	    }
	  break;

	case 'L':
	  if (!str_cmp (word, "Levl")
	      || !str_cmp (word, "Lev") || !str_cmp (word, "Level"))

	    {
	      level = fread_number (fp);
	      fMatch = TRUE;
	      break;

	    }

	  if (!str_cmp (word, "LogO"))
	    {
	      /* date = str_dup(fread_string( fp )); */
	      LLogT = fread_number (fp);
	      fMatch = TRUE;
	      break;
	    }
	  break;

	case 'H':
	  if (!str_cmp (word, "Hist"))
	    {
	      history = str_dup (fread_string (fp));
	      fMatch = TRUE;
	      break;
	    }
	  break;

	case 'N':
	  if (!str_cmp (word, "Name"))
	    {
	      name = str_dup (fread_string (fp));
	      fMatch = TRUE;
	      break;
	    }
	  break;

	case 'R':
	  if (!str_cmp (word, "Race"))
	    {
	      race = str_dup (fread_string (fp));
	      fMatch = TRUE;
	      break;
	    }
	  break;

	case 'S':
	  if (!str_cmp (word, "Sex"))
	    {
	      sex = fread_number (fp);
	      fMatch = TRUE;
	      break;
	    }
	  break;

	case 'T':
	  if (!str_cmp (word, "Titl"))
	    {
	      title = str_dup (fread_string (fp));
	      fMatch = TRUE;
	      break;
	    }
	  break;

	}

      if (!fMatch)

	{
	  fread_to_eol (fp);
	}

    }

}

/*
 * home recall selectable by character
 * (c) 2000 TAKA Ghost Dancer MUD Project
 */
void
do_hrecall (CHAR_DATA * ch, char *argument)
{
  char buf[MAX_STRING_LENGTH];
  char arg[MAX_INPUT_LENGTH];
  CHAR_DATA *victim;
  int location;

  argument = one_argument (argument, arg);

  /*
   * Check flexable options here
   */
  if (USE_HOME_RECALL != 1)
    {
      send_to_char ("This option disabled!\n\r", ch);
      return;
    }

  if (ch->level < MIN_HOME_LEVEL)
    {
      sprintf (buf,
	       "You must be level %d or greater to use this command.\n\r",
	       MIN_HOME_LEVEL);
      send_to_char (buf, ch);
      return;
    }

  /*
   * set home location with hrecall set
   */
  if (!str_cmp (arg, "set"))
    {
      ch->pcdata->hrecall = ch->in_room->vnum;
      send_to_char ("This is now your home recall.\n\r", ch);
      return;
    }

  location = ch->pcdata->hrecall;

  /*
   * checks
   * 1) not an NPC
   * 2) already standing in the home recall point
   * 3) not in a no recall room
   * 4) not fighting
   */
  if (IS_NPC (ch) && !IS_SET (ch->act, ACT_PET))
    {
      send_to_char ("You are always home. NPC lives where they are.\n\r", ch);
      return;
    }

  /* Be sure they are not currently home */
  if ((ch->in_room->vnum == ch->pcdata->hrecall))
    {
      send_to_char ("{RYou are at your home recall.\n\r", ch);
      return;
    }

  if (IS_SET (ch->in_room->room_flags, ROOM_NO_RECALL))
    {
      send_to_char ("That is impossible in a no-recall area.\n\r", ch);
      return;
    }

  if ((victim = ch->fighting) != NULL)
    {
      sprintf (buf, "That is not possible while fighting!.\n\r");
      send_to_char (buf, ch);
      return;
    }

  /*
   * recall penalties half move
   */
  ch->move /= 2;
  act ("$n prays for transportation and disappears.", ch, NULL, NULL,
       TO_ROOM);
  char_from_room (ch);
  char_to_room (ch, get_room_index (location));
  act ("$n appears in the room.", ch, NULL, NULL, TO_ROOM);
  send_to_char ("You return to your home recall spot.\n\r", ch);
  do_look (ch, "");

}

/*
 * Allows PC to make and store a history.
 * by TAKA
 * (c) 2000 TAKA of the Ghost Dancer MUD Project
 */
void
do_history (CHAR_DATA * ch, char *argument)
{
  char buf[MAX_STRING_LENGTH];

  if (argument[0] != '\0')
    {
      buf[0] = '\0';
      smash_tilde (argument);

      if (argument[0] == '-')
	{
	  int len;
	  bool found = FALSE;

	  if (ch->pcdata->history == NULL || ch->pcdata->history[0] == '\0')
	    {
	      send_to_char ("No lines left to remove.\n\r", ch);
	      return;
	    }

	  strcpy (buf, ch->pcdata->history);

	  for (len = strlen (buf); len > 0; len--)
	    {
	      if (buf[len] == '\r')
		{
		  if (!found)	/* back it up */
		    {
		      if (len > 0)
			len--;
		      found = TRUE;
		    }
		  else		/* found the second one */
		    {
		      buf[len + 1] = '\0';
		      free_string (ch->pcdata->history);
		      ch->pcdata->history = str_dup (buf);
		      send_to_char ("Your history is:\n\r", ch);
		      page_to_char (ch->pcdata->history ? ch->pcdata->
				    history : "(None).\n\r", ch);
		      return;
		    }
		}
	    }
	  buf[0] = '\0';
	  free_string (ch->pcdata->history);
	  ch->pcdata->history = str_dup (buf);
	  send_to_char ("{RHistory cleared.{x\n\r", ch);
	  return;
	}

      if (argument[0] == '+')
	{
	  if (ch->pcdata->history != NULL)
	    strcat (buf, ch->pcdata->history);

	  argument++;

	  while (isspace (*argument))
	    argument++;
	}

      if (strlen (buf) >= 4096)
	{
	  send_to_char ("History too long.\n\r", ch);
	  return;
	}

      strcat (buf, argument);
      strcat (buf, "\n\r");
      free_string (ch->pcdata->history);
      ch->pcdata->history = str_dup (buf);
    }

  send_to_char ("Your history is:\n\r", ch);
  page_to_char (ch->pcdata->history ? ch->pcdata->history : "(None).\n\r",
		ch);
  return;
}

/*
	TAKA     add skill pill
	1) get chance of success     number_test
	2) imbue the spell			 embue_spell
	3) do skill make pill		 do_mpill
	TAKA     add skill brew
	4) do skill brew potion		 do_brew
 */

/* 1 */
bool
number_test (int num)
{
  if (number_range (1, 100) <= num)
    return TRUE;
  else
    return FALSE;
}

/* 2 embue the spell into potion of pill */
void
embue_spell (int sn, int level, CHAR_DATA * ch, void *vo)
{
  char buf[MAX_STRING_LENGTH];
  OBJ_DATA *obj = (OBJ_DATA *) vo;
  int free_slots, i, mana, class;
  int snlev = 0, srate = 0;

  for (free_slots = i = 1; i <= 4; i++)
    if (obj->value[i] != 0)
      free_slots++;

  if (free_slots > 4)
    {
      act ("{R$p cannot contain any more spells.{x", ch, obj, NULL, TO_CHAR);
      return;
    }
  mana = 40;
  mana += skill_table[sn].min_mana;

  if (!IS_NPC (ch) && ch->mana < mana)
    {
      send_to_char ("{RYou don't have enough mana.{x\n\r", ch);
      return;
    }

  if (IS_IMMORTAL (ch))
    srate = 85 + (MAX_LEVEL - (ch->level - 1));
  else
    srate = (100 - (free_slots * 20));

  if (number_percent () > ch->pcdata->learned[sn])
    {
      send_to_char ("{RYou lost your concentration.{x\n\r", ch);
      ch->mana -= mana / 2;
      return;
    }
  ch->mana -= mana;
  obj->value[free_slots] = sn;

  if (number_percent () > srate)
    {
      sprintf (buf,
	       "{RThe magic enchantment has failed: the {W%s {Rvanishes.{x\n\r",
	       item_name (obj->item_type));
      send_to_char (buf, ch);
      obj->value[0] = -1;
      return;
    }

  free_string (obj->short_descr);
  sprintf (buf, "{Ra {W%s {Rof {G", item_name (obj->item_type));
  for (i = 1; i <= free_slots; i++)
    if (obj->value[i] != -1)
      {
	strcat (buf, skill_table[obj->value[i]].name);
	(i != free_slots) ? strcat (buf, ", ") : strcat (buf, "{x");
      }

  obj->short_descr = str_dup (buf);
  sprintf (buf, "%s %s", obj->name, item_name (obj->item_type));
  free_string (obj->name);
  obj->name = str_dup (buf);

  for (class = 0; class < MAX_CLASS; class++)
    {
      if (skill_table[sn].skill_level[class] < snlev)
	{
	  snlev = skill_table[sn].skill_level[class];
	}
    }

  if (obj->level < snlev)
    {
      obj->level = snlev;
    }
  sprintf (buf, "{RYou have imbued a new spell to the %s.{x\n\r",
	   item_name (obj->item_type));
  send_to_char (buf, ch);
  return;
}

/* 3 make a pill */
void
do_mpill (CHAR_DATA * ch, char *argument)
{
  OBJ_DATA *pill;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  char arg4[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  int sn;

  if (IS_NPC (ch))
    {
      send_to_char ("{RYou don't have any need for pills.{x\n\r", ch);
      return;
    }

  if (get_skill (ch, gsn_mpill) < 1)
    {
      send_to_char ("Huh?\n\r", ch);
      return;
    }

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

  if (arg1[0] == '\0')
    {
      send_to_char ("{RMake a pill out of what spells?{x\n\r", ch);
      send_to_char ("{G  mpill {M<spell1> <spell2> <spell3> <spell4>{x\n\r",
		    ch);
      return;
    }

  if ((sn = skill_lookup (arg1)) < 0)
    {
      sprintf (buf, "{RYou don't know any spells by that name {W%s.{x\n\r",
	       arg1);
      send_to_char (buf, ch);
      return;
    }
  /* check spell selections 2,3,4 */
  if ((arg2[0] != '\0') && ((sn = skill_lookup (arg2)) < 0))
    {
      sprintf (buf, "{RYou don't know any spells by that name {W%s.{x\n\r",
	       arg2);
      send_to_char (buf, ch);
      return;
    }

  if ((arg3[0] != '\0') && ((sn = skill_lookup (arg3)) < 0))
    {
      sprintf (buf, "{RYou don't know any spells by that name {W%s.{x\n\r",
	       arg3);
      send_to_char (buf, ch);
      return;
    }


  if ((arg4[0] != '\0') && ((sn = skill_lookup (arg4)) < 0))
    {
      sprintf (buf, "{RYou don't know any spells by that name {W%s.{x\n\r",
	       arg4);
      send_to_char (buf, ch);
      return;
    }


  sn = skill_lookup (arg1);
  if (!number_test (get_skill (ch, sn)))
    {
      send_to_char
	("{RYou don't know that spell well enough to make a pill of it!{x\n\r",
	 ch);
      return;
    }

  if (skill_table[sn].target != TAR_CHAR_DEFENSIVE
      && skill_table[sn].target != TAR_CHAR_SELF
      && skill_table[sn].target != TAR_OBJ_CHAR_DEF)
    {
      send_to_char ("{RYou cannot make a pill of that spell.{x\n\r", ch);
      return;
    }

  pill = create_object (get_obj_index (OBJ_VNUM_PILL), 0);
  pill->value[1] = 0;
  pill->value[2] = 0;
  pill->value[3] = 0;
  pill->value[4] = 0;

  if (!pill)
    {
      send_to_char
	("{RCould not find the pill object, please notify an 	IMP!{x\n\r",
	 ch);
      return;
    }

  obj_to_char (pill, ch);
  send_to_char ("{RYou begin focus your energy and mutter the words.{x\n\r",
		ch);
  act ("{W$n {Rbegins focusing and chanting.{x", ch, NULL, NULL, TO_ROOM);
  WAIT_STATE (ch, skill_table[gsn_mpill].beats);
  act ("{R$p appears suddenly.{x", ch, pill, NULL, TO_CHAR);
  act ("{R$p appears suddenly.{x", ch, pill, NULL, TO_ROOM);

  if (!IS_NPC (ch) && (number_percent () > ch->pcdata->learned[gsn_mpill]
		       || number_percent () >
		       ((get_curr_stat (ch, STAT_INT) - 13) * 5 +
			(get_curr_stat (ch, STAT_SPI) - 13) * 3)))
    {
      act ("$p {Yexplodes {Rviolently{x!", ch, pill, NULL, TO_CHAR);
      act ("$p {Yexplodes {Rviolently{x!", ch, pill, NULL, TO_ROOM);
      extract_obj (pill);
      sn = skill_lookup ("energy drain");
      damage (ch, ch, ch->max_hit / 10, sn, DAM_ENERGY, FALSE);
      check_improve (ch, gsn_mpill, FALSE, 1);
      return;
    }

  pill->level = 1;
  pill->value[0] = ch->level;
  if (arg1[0] != '\0')
    {
      sn = skill_lookup (arg1);
      embue_spell (sn, ch->level, ch, pill);
      if (pill->value[0] == -1)
	{
	  extract_obj (pill);
	  return;
	}

    }
  if (arg2[0] != '\0')
    {
      sn = skill_lookup (arg2);
      embue_spell (sn, ch->level, ch, pill);
      if (pill->value[0] == -1)
	{
	  extract_obj (pill);
	  return;
	}

    }
  if (arg3[0] != '\0')
    {
      sn = skill_lookup (arg3);
      embue_spell (sn, ch->level, ch, pill);
      if (pill->value[0] == -1)
	{
	  extract_obj (pill);
	  return;
	}

    }
  if (arg4[0] != '\0')
    {
      sn = skill_lookup (arg4);
      embue_spell (sn, ch->level, ch, pill);
      if (pill->value[0] == -1)
	{
	  extract_obj (pill);
	  return;
	}

    }

  check_improve (ch, gsn_mpill, TRUE, 1);
  return;
}

/* 4 brew potion */
void
do_brew (CHAR_DATA * ch, char *argument)
{
  OBJ_DATA *potion;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  char arg4[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  int sn;

  if (IS_NPC (ch))
    {
      send_to_char ("{RYou don't have any need for potions.{x\n\r", ch);
      return;
    }

  if (get_skill (ch, gsn_brew) < 1)
    {
      send_to_char ("Huh?\n\r", ch);
      return;
    }

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

  if (arg1[0] == '\0')
    {
      send_to_char ("{RMake a potion out of what spells?{x\n\r", ch);
      send_to_char ("{G  brew {M<spell1> <spell2> <spell3> <spell4>{x\n\r",
		    ch);
      return;
    }

  if ((sn = skill_lookup (arg1)) < 0)
    {
      sprintf (buf, "{RYou don't know any spells by that name {W%s.{x\n\r",
	       arg1);
      send_to_char (buf, ch);
      return;
    }
  /* check spell selections 2,3,4 */
  if ((arg2[0] != '\0') && ((sn = skill_lookup (arg2)) < 0))
    {
      sprintf (buf, "{RYou don't know any spells by that name {W%s.{x\n\r",
	       arg2);
      send_to_char (buf, ch);
      return;
    }

  if ((arg3[0] != '\0') && ((sn = skill_lookup (arg3)) < 0))
    {
      sprintf (buf, "{RYou don't know any spells by that name {W%s.{x\n\r",
	       arg3);
      send_to_char (buf, ch);
      return;
    }


  if ((arg4[0] != '\0') && ((sn = skill_lookup (arg4)) < 0))
    {
      sprintf (buf, "{RYou don't know any spells by that name {W%s.{x\n\r",
	       arg4);
      send_to_char (buf, ch);
      return;
    }


  sn = skill_lookup (arg1);
  if (!number_test (get_skill (ch, sn)))
    {
      send_to_char
	("{RYou don't know that spell well enough to make a potion of it!{x\n\r",
	 ch);
      return;
    }

  if (skill_table[sn].target != TAR_CHAR_DEFENSIVE
      && skill_table[sn].target != TAR_CHAR_SELF
      && skill_table[sn].target != TAR_OBJ_CHAR_DEF)
    {
      send_to_char ("{RYou cannot make a potion of that spell.{x\n\r", ch);
      return;
    }

  potion = create_object (get_obj_index (OBJ_VNUM_POTION), 0);
  potion->value[1] = 0;
  potion->value[2] = 0;
  potion->value[3] = 0;
  potion->value[4] = 0;

  if (!potion)
    {
      send_to_char
	("{RCould not find the potion object, please notify an 	IMP!{x\n\r",
	 ch);
      return;
    }

  obj_to_char (potion, ch);
  send_to_char ("{RYou begin focus your energy and mutter the words.{x\n\r",
		ch);
  act ("{W$n {Rbegins focusing and chanting.{x", ch, NULL, NULL, TO_ROOM);
  WAIT_STATE (ch, skill_table[gsn_brew].beats);
  act ("{R$p appears suddenly.{x", ch, potion, NULL, TO_CHAR);
  act ("{R$p appears suddenly.{x", ch, potion, NULL, TO_ROOM);

  if (!IS_NPC (ch) && (number_percent () > ch->pcdata->learned[gsn_mpill]
		       || number_percent () >
		       ((get_curr_stat (ch, STAT_INT) - 13) * 5 +
			(get_curr_stat (ch, STAT_SPI) - 13) * 3)))
    {
      act ("$p {Yexplodes {Rviolently{x!", ch, potion, NULL, TO_CHAR);
      act ("$p {Yexplodes {Rviolently{x!", ch, potion, NULL, TO_ROOM);
      extract_obj (potion);
      sn = skill_lookup ("energy drain");
      damage (ch, ch, ch->max_hit / 10, sn, DAM_ENERGY, FALSE);
      check_improve (ch, gsn_brew, FALSE, 1);
      return;
    }

  potion->level = 1;
  potion->value[0] = ch->level;
  if (arg1[0] != '\0')
    {
      sn = skill_lookup (arg1);
      embue_spell (sn, ch->level, ch, potion);
      if (potion->value[0] == -1)
	{
	  extract_obj (potion);
	  return;
	}

    }
  if (arg2[0] != '\0')
    {
      sn = skill_lookup (arg2);
      embue_spell (sn, ch->level, ch, potion);
      if (potion->value[0] == -1)
	{
	  extract_obj (potion);
	  return;
	}

    }
  if (arg3[0] != '\0')
    {
      sn = skill_lookup (arg3);
      embue_spell (sn, ch->level, ch, potion);
      if (potion->value[0] == -1)
	{
	  extract_obj (potion);
	  return;
	}

    }
  if (arg4[0] != '\0')
    {
      sn = skill_lookup (arg4);
      embue_spell (sn, ch->level, ch, potion);
      if (potion->value[0] == -1)
	{
	  extract_obj (potion);
	  return;
	}

    }

  check_improve (ch, gsn_brew, TRUE, 1);
  return;
}

/* End make pill & brew TAKA     */

/*
 * Strip reserved immortal only colors from strings
 * These are based on my color codes yours may very some.
 *
 * Last the GLOBAL flag is used only when this affects everyone
 * mud wide like gossip. For say i make this false and allow
 * clear screen to be used by mortals.
 */
//Added by Xeric --Neener neener neener :P
void
do_newforge (CHAR_DATA * ch, char *argument)
{
  char arg[MAX_STRING_LENGTH];
  char arg2[MAX_STRING_LENGTH];
  char buf1[MAX_STRING_LENGTH];
  OBJ_DATA *obj;
  OBJ_DATA *obj2;
  AFFECT_DATA *pAf;
  int to_hit;
  int to_dam;

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

  if ((arg == '\0') || (arg2 == '\0'))
    {
      send_to_char ("Syntax:  forge (item) (weapon)\n\r", ch);
      return;
    }

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

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

  if (obj->item_type != ITEM_SOCKET)
    {
      send_to_char ("That isn't a socket.\n\r", ch);
      return;
    }

  if (obj2->item_type != ITEM_WEAPON)
    {
      if (obj2->item_type != ITEM_ARMOR)
	send_to_char ("That is not a weapon or piece of armor!\n\r", ch);
      return;
    }


  to_hit = obj->value[0];
  to_dam = obj->value[1];

  if (obj2->item_type == ITEM_ARMOR)
    {
      to_hit = obj->value[1];
      to_dam = obj->value[2];
    }

  extract_obj (obj);

  if (to_hit != 0)
    {
      pAf = new_affect ();
      pAf->location = APPLY_HITROLL;
      pAf->modifier = to_hit;
      pAf->where = TO_OBJECT;
      pAf->type = 0;
      pAf->duration = -1;
      pAf->bitvector = 0;
      pAf->level = obj2->level;
      pAf->next = obj2->affected;
      obj2->affected = pAf;
      /*      affect_to_obj (obj2, pAf); */
    }
  if (to_dam != 0)
    {
      pAf = new_affect ();
      pAf->location = APPLY_DAMROLL;
      pAf->modifier = to_dam;
      pAf->where = TO_OBJECT;
      pAf->type = 0;
      pAf->duration = -1;
      pAf->bitvector = 0;
      pAf->level = obj2->level;
      pAf->next = obj2->affected;
      obj2->affected = pAf;
      /* affect_to_obj (obj2, pAf); */
    }

  sprintf (buf1, "{B[{W*{B]{x %s", obj2->short_descr);
  obj2->short_descr = buf1;
  free_string (buf1);

  send_to_char
    ("You have inserted the socket into your weapon, it glows and humms for an instant and now seems much more powerful.\n\r",
     ch);
  return;
}

/* How to make a string look drunk... by Apex (robink@htsa.hva.nl) */
/* Modified and enhanced for envy(2) by the Maniac from Mythran */
/* Further mods/upgrades for ROM 2.4 by Kohl Desenee */

char *
makedrunk (char *string, CHAR_DATA * ch)
{
/* This structure defines all changes for a character */
  struct struckdrunk drunk[] = {
    {3, 10,
     {"a", "a", "a", "A", "aa", "ah", "Ah", "ao", "aw", "oa", "ahhhh"}},
    {8, 5,
     {"b", "b", "b", "B", "B", "vb"}},
    {3, 5,
     {"c", "c", "C", "cj", "sj", "zj"}},
    {5, 2,
     {"d", "d", "D"}},
    {3, 3,
     {"e", "e", "eh", "E"}},
    {4, 5,
     {"f", "f", "ff", "fff", "fFf", "F"}},
    {8, 2,
     {"g", "g", "G"}},
    {9, 6,
     {"h", "h", "hh", "hhh", "Hhh", "HhH", "H"}},
    {7, 6,
     {"i", "i", "Iii", "ii", "iI", "Ii", "I"}},
    {9, 5,
     {"j", "j", "jj", "Jj", "jJ", "J"}},
    {7, 2,
     {"k", "k", "K"}},
    {3, 2,
     {"l", "l", "L"}},
    {5, 8,
     {"m", "m", "mm", "mmm", "mmmm", "mmmmm", "MmM", "mM", "M"}},
    {6, 6,
     {"n", "n", "nn", "Nn", "nnn", "nNn", "N"}},
    {3, 6,
     {"o", "o", "ooo", "ao", "aOoo", "Ooo", "ooOo"}},
    {3, 2,
     {"p", "p", "P"}},
    {5, 5,
     {"q", "q", "Q", "ku", "ququ", "kukeleku"}},
    {4, 2,
     {"r", "r", "R"}},
    {2, 5,
     {"s", "ss", "zzZzssZ", "ZSssS", "sSzzsss", "sSss"}},
    {5, 2,
     {"t", "t", "T"}},
    {3, 6,
     {"u", "u", "uh", "Uh", "Uhuhhuh", "uhU", "uhhu"}},
    {4, 2,
     {"v", "v", "V"}},
    {4, 2,
     {"w", "w", "W"}},
    {5, 6,
     {"x", "x", "X", "ks", "iks", "kz", "xz"}},
    {3, 2,
     {"y", "y", "Y"}},
    {2, 9,
     {"z", "z", "ZzzZz", "Zzz", "Zsszzsz", "szz", "sZZz", "ZSz", "zZ", "Z"}}
  };

  char buf[1024];
  char temp;
  int pos = 0;
  int drunklevel;
  int randomnum;

  /* Check how drunk a person is... */
  if (IS_NPC (ch))
    drunklevel = 0;
  else
    drunklevel = ch->pcdata->condition[COND_DRUNK];

  if (drunklevel > 0)
    {
      do
	{
	  temp = toupper (*string);
	  if ((temp >= 'A') && (temp <= 'Z'))
	    {
	      if (drunklevel > drunk[temp - 'A'].min_drunk_level)
		{
		  randomnum =
		    number_range (0, drunk[temp - 'A'].number_of_rep);
		  strcpy (&buf[pos],
			  drunk[temp - 'A'].replacement[randomnum]);
		  pos += strlen (drunk[temp - 'A'].replacement[randomnum]);
		}
	      else
		buf[pos++] = *string;
	    }
	  else
	    {
	      if ((temp >= '0') && (temp <= '9'))
		{
		  temp = '0' + number_range (0, 9);
		  buf[pos++] = temp;
		}
	      else
		buf[pos++] = *string;
	    }
	}
      while (*string++);
      buf[pos] = '\0';		/* Mark end of the string... */
      strcpy (string, buf);
      return (string);
    }
  return (string);
}

/* move the cursor up a number of rows */
void
cursor_up (CHAR_DATA * ch, int rows)
{
  printf_to_char (ch, "\x01B[%uA", rows);
}

/* move the cursor down a number of rows */
void
cursor_down (CHAR_DATA * ch, int rows)
{
  printf_to_char (ch, "\x01B[%uB", rows);
}

/* move the cursor forward a number of columns */
void
cursor_forward (CHAR_DATA * ch, int cols)
{
  printf_to_char (ch, "\x01B[%uC", cols);
}

/* move the cursor backwards a number of columns */
void
cursor_back (CHAR_DATA * ch, int cols)
{
  printf_to_char (ch, "\x01B[%uD", cols);
}

/* save the current cursor position */
void
save_cursor (CHAR_DATA * ch)
{
  send_to_char ("\x01B[s", ch);
}

/* retore the cursor position to a previously saved location */
void
restore_cursor (CHAR_DATA * ch)
{
  send_to_char ("\x01B[r", ch);
}

/* erase the current line, beginning from current cursor position, to
   end of line */
void
erase_eol (CHAR_DATA * ch)
{
  /** note: error in DOS documentation 
    * lists K as lowercase 
    */
  send_to_char ("\x01B[K", ch);
}

/* go to xy, then erase the line from that cursor position to the end of
   line */
void
erase_xyeol (CHAR_DATA * ch, int col, int row)
{
  printf_to_char (ch, "\x01B[%u;%uH\x01B[K", row, col);
}

/* beep the character */
void
beep_char (CHAR_DATA * ch, char *argument)
{
  CHAR_DATA *victim;

  if ((victim = get_char_world (ch, argument)) == NULL)
    {
      send_to_char ("They aren't here.\n\r", ch);
      return;
    }

  printf_to_char (victim, "\007%s needs your attention.\n\r", ch->name);
  printf_to_char (ch, "You beep %s\n\r", victim->name);
}

/* move the cursor to column x, row y */
void
goto_xy (CHAR_DATA * ch, int col, int row)
{
  printf_to_char (ch, "\x01B[%u;%uH", row, col);
}

/* clear the screen and place the cursor in default position */
void
clear_screen (CHAR_DATA * ch)
{
  send_to_char ("\x01B[2J", ch);
}

/* at column x, row y, send string "str" to char */
void
send_to_char_xy (CHAR_DATA * ch, int col, int row, char *str)
{
  printf_to_char (ch, "\x01B[%u;%uH%s", row, col, str);
}

/* at row y, send string "str" to char, and center on the screen */
void
send_to_char_center_xy (CHAR_DATA * ch, int row, char *str)
{
  printf_to_char (ch, "\x01B[%u;%uH%s", row, ((80 - (strlen (str) - 1)) / 2),
		  str);
}

MPROG_QUEUE_DATA *mprog_queue;
MPROG_QUEUE_DATA *mprog_queue_last;

void
queue_mprog (int vnum, char *pos, CHAR_DATA * mob, CHAR_DATA * ch,
	     const void *arg1, const void *arg2, sh_int delay, int level,
	     int *state, int *cond)
{
  MPROG_QUEUE_DATA *mpq;
  int i;

  mpq = new_mprog_queue_data ();

  mpq->vnum = vnum;
  mpq->mob = mob;
  mpq->ch = ch;
  mpq->arg1 = (void *) arg1;
  mpq->arg2 = (void *) arg2;
  mpq->delay = delay;
  mpq->pos = pos;
  mpq->level = level;
  for (i = 0; i < MAX_NESTED_LEVEL; i++)
    {
      mpq->state[i] = state[i];
      mpq->cond[i] = cond[i];
    }
  mpq->next = NULL;

  if (mprog_queue == NULL)
    mprog_queue = mpq;
  else
    mprog_queue_last->next = mpq;
  mprog_queue_last = mpq;
}

void
exec_mprog_queue (MPROG_QUEUE_DATA * mpq)
{
  if ((mpq->mob != NULL && !IS_VALID (mpq->mob))
      || (mpq->ch != NULL && !IS_VALID (mpq->mob))
      || mpq->mob->in_room == NULL || mpq->ch->in_room == NULL)
    return;
  program_flow (mpq->vnum, mpq->pos, mpq->mob, NULL, NULL, mpq->ch, mpq->arg1,
		mpq->arg2);
  return;
}

void
dequeue_mprog (MPROG_QUEUE_DATA * mpq)
{
  MPROG_QUEUE_DATA *prev;




  if (mprog_queue == mpq)
    {
      if (mprog_queue_last == mpq)
	mprog_queue_last = NULL;
      mprog_queue = mprog_queue->next;
      free_mprog_queue_data (mpq);
      return;
    }

  for (prev = mprog_queue; prev->next; prev = prev->next)
    {
      if (prev->next == mpq)
	{
	  if (mpq == mprog_queue_last)
	    mprog_queue_last = prev;
	  prev->next = prev->next->next;
	  break;
	}
    }
  free_mprog_queue_data (mpq);
}

void
mprog_queue_update (void)
{
  MPROG_QUEUE_DATA *mpq;
  MPROG_QUEUE_DATA *mpq_next;

  for (mpq = mprog_queue; mpq; mpq = mpq_next)
    {
      mpq_next = mpq->next;

      if (mpq->delay <= 0)
	{
	  exec_mprog_queue (mpq);
	  dequeue_mprog (mpq);
	}
      else
	mpq->delay--;
    }
}

int
strlen_color (char *argument)
{
  char *str;
  int length;

  if (argument == NULL || argument[0] == '\0')
    return 0;

  length = 0;
  str = argument;

  while (*str != '\0')
    {
      if (*str != '{')
	{
	  str++;
	  length++;
	  continue;
	}

      if (*(++str) == '{')
	length++;

      str++;
    }

  return length;
}

void
do_mana_shield (CHAR_DATA * ch, char *argument)
{
  char arg1[MAX_INPUT_LENGTH];
  int arg2;

  argument = one_argument (argument, arg1);

  if (!is_number (arg1))
    {
      send_to_char ("You cannot do that.\n\r", ch);
      return;
    }

  if (arg1[0] == '\0')
    {
      send_to_char
	("Your hands pulse with energy as you raise your mana shield.\n\r",
	 ch);
      act
	("$n raises his hands and is surrounded by a crackling blue mana shield.\n\r",
	 ch, NULL, NULL, TO_ROOM);
      if (ch->mana <= 5)
	send_to_char ("Your energy is depleted\n\r", ch);
      else
	{
	  ch->shield = (ch->mana * 0.75);
	  ch->mana = (ch->mana * 0.25);
	  return;
	}
    }
  arg2 = atoi (arg1);

  if (arg2 > ch->mana)
    {
      send_to_char ("You don't have enough energy.\n\r", ch);
      return;
    }
  else
    {
      send_to_char
	("Your hands pulse with energy as you raise your mana shield.\n\r",
	 ch);
      act
	("$n raises his hands and is surrounded by a crackling blue mana shield.\n\r",
	 ch, NULL, NULL, TO_ROOM);
      ch->shield = (ch->shield + arg2);
      ch->mana = (ch->mana - arg2);
      return;
    }
  return;
}