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

/*char *itoa (int);*/

void remove_trigger_from_list (SINGLE_TRIGGER * tr);


/* Finds a trigger given a set trigger id name */
SINGLE_TRIGGER *
find_trigger (char *trigname)
{
  int i;
  SINGLE_TRIGGER *tr;
  MARK_DEBUG ("Find_trigger")
    for (i = 0; i < TMAX_TRIGGERS; i++)
    {
      for (tr = trigger_list[i]; tr != NULL; tr = tr->next)
	{
	  if (!str_cmp (tr->trigger_id, trigname))
	    return tr;
	}
    }
  return NULL;
}

/* Creates a new trigger, names it, and puts it in the trigger list with type 1 */
SINGLE_TRIGGER *
new_trigger (char *trigname)
{
  SINGLE_TRIGGER *tr;
  tr = mem_alloc (sizeof (*tr));
  bzero (tr, sizeof (*tr));
  if (strlen (trigname) > 19)
    trigname[19] = '\0';
  strcpy (tr->trigger_id, trigname);
  tr->keywords = &str_empty[0];
  tr->trigger_type = 1;
  tr->next = trigger_list[1];
  trigger_list[1] = tr;
  return tr;
}

/* returns the type of the trigger given a specific trigger name */
int 
trigger_name (char *trig)
{
  int i = TMAX_TRIGGERS;
  if (!str_cmp (trig, "Enters"))
    i = TENTERS;
  else if (!str_cmp (trig, "Leaves"))
    i = TLEAVES;
  else if (!str_cmp (trig, "Created"))
    i = TCREATED;
  else if (!str_cmp (trig, "Command"))
    i = TCOMMAND;
  else if (!str_cmp (trig, "Moves"))
    i = TMOVES;
  else if (!str_cmp (trig, "Destroyed"))
    i = TDESTROYED;
  else if (!str_cmp (trig, "Say"))
    i = TSAYS;
  else if (!str_cmp (trig, "Tell"))
    i = TTELLS;
  else if (!str_cmp (trig, "Hourly"))
    i = TEVERY_HOUR;
  else if (!str_cmp (trig, "Quicktick"))
    i = TEVERY_QUICKTICK;
  else if (!str_cmp (trig, "Regentick"))
    i = TEVERY_REGENTICK;
  else if (!str_cmp (trig, "At_hour"))
    i = TAT_HOUR;
  if (!str_cmp (trig, "Given"))
    i = TGIVEN;
  else if (!str_cmp (trig, "Dropped"))
    i = TDROPPED;
  else if (!str_cmp (trig, "Equipped"))
    i = TEQUIPPED;
  else if (!str_cmp (trig, "Attacked"))
    i = TATTACKED;
  else if (!str_cmp (trig, "Sacced"))
    i = TOBJ_SACCED;
  else if (!str_cmp (trig, "Money"))
    i = TGIVEN_MONEY;

  return i;
}



/* returns the name of the trigger given a specific trigger number */
char *
trigger_type (int trig)
{
  static char trigret[100];
  strcpy (trigret, "Bad_Trgger");
  if (trig == TENTERS)
    strcpy (trigret, "Enters    ");
  else if (trig == TLEAVES)
    strcpy (trigret, "Leaves    ");
  else if (trig == TCREATED)
    strcpy (trigret, "Created   ");
  else if (trig == TCOMMAND)
    strcpy (trigret, "Command   ");
  else if (trig == TMOVES)
    strcpy (trigret, "Moves     ");
  else if (trig == TDESTROYED)
    strcpy (trigret, "Destroyed ");
  else if (trig == TSAYS)
    strcpy (trigret, "Say       ");
  else if (trig == TTELLS)
    strcpy (trigret, "Tell      ");
  else if (trig == TEVERY_HOUR)
    strcpy (trigret, "Hourly    ");
  else if (trig == TEVERY_QUICKTICK)
    strcpy (trigret, "Quicktick ");
  else if (trig == TEVERY_REGENTICK)
    strcpy (trigret, "Regentick ");
  else if (trig == TAT_HOUR)
    strcpy (trigret, "At_hour   ");
  else if (trig == TGIVEN)
    strcpy (trigret, "Given     ");
  else if (trig == TDROPPED)
    strcpy (trigret, "Dropped   ");
  else if (trig == TEQUIPPED)
    strcpy (trigret, "Equipped  ");
  else if (trig == TATTACKED)
    strcpy (trigret, "Attacked  ");
  else if (trig == TOBJ_SACCED)
    strcpy (trigret, "Sacced  ");
  else if (trig == TGIVEN_MONEY)
    strcpy (trigret, "Money  ");

  return trigret;
}

void 
list_triggers (CHAR_DATA * ch, char *argy)
{
  int i;
  SINGLE_TRIGGER *tr;
  DEFINE_COMMAND ("listtriggers", list_triggers, POSITION_DEAD, 110, LOG_NORMAL, "Lists all triggers.")
    hugebuf_o[0] = '\0';
  sprintf (hugebuf_o, "%-20s %s %5s %5s %5s\n\r", "Trigger ID", "TrigType  ", "Room", "Mob", "Objct");
  strcat (hugebuf_o, "------------------------------------------------------------------------------\n\r");
  for (i = 0; i < TMAX_TRIGGERS; i++)
    {
      for (tr = trigger_list[i]; tr != NULL; tr = tr->next)
	{
	  sprintf (hugebuf_o + strlen (hugebuf_o), "%-20s %s %5d %5d %5d\n\r",
		   tr->trigger_id,
		   trigger_type (tr->trigger_type),
		   tr->attached_to_room,
		   tr->attached_to_mob,
		   tr->attached_to_obj);
	}
    }
  page_to_char (hugebuf_o, ch);
  return;
}

void 
script_editor (CHAR_DATA * ch, char *argy)
{
  char arg1[500];
  char arg2[500];
  SINGLE_TRIGGER *tr;
  DEFINE_COMMAND ("scriptedit", script_editor, POSITION_DEAD, 110, LOG_NORMAL, "For Orin's use only right now.")
    if (!ch->desc)
    return;
  argy = one_argy (argy, arg1);
  argy = one_argy (argy, arg2);
  if (!str_cmp (arg1, "create") && arg2[0] != '\0')
    {
      if (find_trigger (arg2) != NULL)
	{
	  send_to_char ("That trigger already exists!\n\r", ch);
	  return;
	}
      tr = new_trigger (arg2);
      ch->desc->pEdit = (void *) tr;
      ch->desc->connected = CON_SCRIPTEDITOR;
      return;
    }
  if (!str_cmp (arg1, "delete") && arg2[0] != '\0')
    {
      if ((tr = find_trigger (arg2)) == NULL)
	{
	  send_to_char ("That trigger doesn't exist!\n\r", ch);
	  return;
	}
      remove_trigger_from_list (tr);
      free_string (tr->keywords);
      free (tr);
      send_to_char ("Trigger deleted.\n\r", ch);
      return;
    }
  if (arg1[0] == '\0')
    return;
  tr = find_trigger (arg1);
  if (!tr)
    {
      send_to_char ("That trigger was not found.\n\r", ch);
      return;
    }
  ch->desc->pEdit = (void *) tr;
  ch->desc->connected = CON_SCRIPTEDITOR;
  return;
}

void 
show_this_trigger (CHAR_DATA * ch, char *trig)
{
  SINGLE_TRIGGER *tr;
  char buf[500];
  if ((tr = find_trigger (trig)) == NULL)
    {
      send_to_char ("Trigger not found.\n\r", ch);
      return;
    }
  sprintf (buf, "Trigger ID: \x1B[37;1m%s\x1B[37;0m  Trigger Type: \x1B[37;1m%s\x1B[37;0m\n\r",
	   tr->trigger_id,
	   trigger_type (tr->trigger_type));
  send_to_char (buf, ch);
  sprintf (buf, "Room: %d  Mob: %d  Object: %d  Interruptable: %s\n\r",
	   tr->attached_to_room,
	   tr->attached_to_mob,
	   tr->attached_to_obj,
	   (tr->interrupted == 1 ? "Yes" : (tr->interrupted == 2 ? "Yes, and multiple!" : "No")));
  send_to_char (buf, ch);
  sprintf (buf, "\x1B[37;1mPlayer\x1B[37;0m only: %s  \x1B[37;1mStop\x1B[37;0ms if player leaves: %s\n\r",
	   (tr->players_only == 1 ? "Yes" : "No"),
	   (tr->leaves_room == 1 ? "Yes" : "No"));
  send_to_char (buf, ch);
  sprintf (buf, "Calls code label: \x1B[34;1m%s\x1B[37;0m\n\r", tr->code_label);
  send_to_char (buf, ch);
  sprintf (buf, "Keywords: \x1B[37;1m%s\x1B[37;0m\n\r", tr->keywords);
  send_to_char (buf, ch);
  return;
}

void 
remove_trigger_from_list (SINGLE_TRIGGER * tr)
{
  SINGLE_TRIGGER *tt;
  if (tr == trigger_list[tr->trigger_type])
    {
      trigger_list[tr->trigger_type] = tr->next;
      tr->next = NULL;
      return;
    }
  for (tt = trigger_list[tr->trigger_type]; tt != NULL; tt = tt->next)
    {
      if (tt->next == tr)
	{
	  tt->next = tr->next;
	  tr->next = NULL;
	  return;
	}
    }
  fprintf (stderr, "Trigger not found to remove from trigger list!!\n");
  return;
}

void 
scriptedit (CHAR_DATA * ch, char *argy)
{
  SINGLE_TRIGGER *tr;
  int tmp;
  char orig_argy[500];
  char arg1[500];
  if (!ch->desc)
    return;
  if (!ch->desc->pEdit)
    {
      ch->desc->connected = CON_PLAYING;
      return;
    }
  tr = (SINGLE_TRIGGER *) ch->desc->pEdit;
  strcpy (orig_argy, argy);
  if (!str_cmp (argy, "done"))
    {
      ch->desc->pEdit = NULL;
      ch->desc->connected = CON_PLAYING;
      return;
    }
  if (argy[0] == '\0' || argy[0] == ' ')
    {
      show_this_trigger (ch, tr->trigger_id);
      return;
    }
  argy = one_argy (argy, arg1);
  if ((tmp = trigger_name (arg1)) > 0 && tmp < TMAX_TRIGGERS)
    {
      remove_trigger_from_list (tr);
      tr->trigger_type = tmp;
      /* Must place in the new hash position */
      tr->next = trigger_list[tmp];
      trigger_list[tmp] = tr;
      send_to_char ("Trigger type set.\n\r", ch);
      return;
    }
  if (!str_cmp (arg1, "code") && argy[0] != '\0')
    {
      if (strlen (argy) > 9)
	{
	  send_to_char ("Invalid code label.  Must be less than 10 letters.\n\r", ch);
	  return;
	}
      strcpy (tr->code_label, argy);
      send_to_char ("Code label set.\n\r", ch);
      return;
    }
  if (!str_prefix ("inter", arg1))
    {
      if (argy[0] != '\0' && is_number (argy))
	{
	  tr->interrupted = atoi (argy);
	  return;
	}
      if (tr->interrupted)
	{
	  tr->interrupted = FALSE;
	  send_to_char ("Script cannot be interrupted.\n\r", ch);
	}
      else
	{
	  tr->interrupted = TRUE;
	  send_to_char ("Script can now be interrupted.\n\r", ch);
	}
      return;
    }
  if (!str_prefix ("player", arg1))
    {
      if (argy[0] != '\0' && is_number (argy))
	{
	  tr->players_only = atoi (argy);
	  return;
	}
      if (tr->players_only)
	{
	  tr->players_only = FALSE;
	  send_to_char ("Script can now be triggered by mobs as well.\n\r", ch);
	}
      else
	{
	  tr->players_only = TRUE;
	  send_to_char ("Script can only be triggered by players now.\n\r", ch);
	}
      return;
    }
  if (!str_prefix ("stop", arg1))
    {
      if (argy[0] != '\0' && is_number (argy))
	{
	  tr->leaves_room = atoi (argy);
	  return;
	}
      if (tr->leaves_room)
	{
	  tr->leaves_room = FALSE;
	  send_to_char ("Script continues if char leaves the room.\n\r", ch);
	}
      else
	{
	  tr->leaves_room = TRUE;
	  send_to_char ("Script now stops if the character leaves the room.\n\r", ch);
	}
      return;
    }

  if (!str_prefix ("keyword", arg1))
    {
      free_string (tr->keywords);
      tr->keywords = str_dup (argy);
      send_to_char ("Key words set.\n\r", ch);
      return;
    }
  if (!str_cmp ("obj", arg1) && is_number (argy))
    {
      tr->attached_to_obj = atoi (argy);
      send_to_char ("Object vnum set.\n\r", ch);
      return;
    }
  if (!str_cmp ("room", arg1) && is_number (argy))
    {
      tr->attached_to_room = atoi (argy);
      send_to_char ("Room vnum set.\n\r", ch);
      return;
    }
  if (!str_cmp ("mob", arg1) && is_number (argy))
    {
      tr->attached_to_mob = atoi (argy);
      send_to_char ("Mob vnum set.\n\r", ch);
      return;
    }
  interpret (ch, orig_argy);
  return;
}

/* Finds a code label */
CODE *
find_code (char *id)
{
  CODE *c;
  int i;
  for (i = 0; i < 256; i++)
    {
      for (c = code_list[i]; c != NULL; c = c->next)
	{
	  if (!str_cmp (id, c->label))
	    return c;
	}
    }
  return NULL;
}

CODE *
new_code (char *id)
{
  CODE *c;
  c = mem_alloc (sizeof (*c));
  bzero (c, sizeof (*c));
  if (strlen (id) > 9)
    id[9] = '\0';
  strcpy (c->label, id);
  c->next = code_list[c->label[0]];
  code_list[c->label[0]] = c;
  c->code=&str_empty[0];
  return c;
}

void 
online_coding (CHAR_DATA * ch, char *argy)
{
  char arg1[500];
  CODE *cd;
  CODE *c;
  DEFINE_COMMAND ("edit", online_coding, POSITION_DEAD, 110, LOG_NORMAL, "Add/Modify online script code.")
    argy = one_argy (argy, arg1);
  if (!str_cmp (arg1, "delete") && argy[0] != '\0')
    {
      if ((cd = find_code (argy)) == NULL)
	{
	  send_to_char ("That label does not exist!!\n\r", ch);
	  return;
	}
      if (code_list[cd->label[0]] == cd)
	{
	  code_list[cd->label[0]] = cd->next;
	}
      else
	for (c = code_list[cd->label[0]]; c != NULL; c = c->next)
	  {
	    if (c->next == cd)
	      {
		c->next = cd->next;
		goto duu;
	      }
	  }
    duu:
      free_string (cd->code);
      free (cd);
      send_to_char ("Code label and code freed.\n\r", ch);
      return;
    }
  if (!str_cmp (arg1, "create") && argy[0] != '\0')
    {
      if (find_code (argy) != NULL)
	{
	  send_to_char ("That label already exists!!\n\r", ch);
	  return;
	}
      cd = new_code (argy);
      string_append (ch, &cd->code);
      return;
    }
  if ((cd = find_code (arg1)) == NULL)
    {
      send_to_char ("Code label was not found.\n\r", ch);
      return;
    }
  string_append (ch, &cd->code);
  return;
}

void 
list_code (CHAR_DATA * ch, char *argy)
{
  int i;
  int col = 0;
  CODE *tr;
  DEFINE_COMMAND ("listcode", list_code, POSITION_DEAD, 110, LOG_NORMAL, "Lists all code labels.")
    hugebuf_o[0] = '\0';
  for (i = 0; i < 256; i++)
    {
      for (tr = code_list[i]; tr != NULL; tr = tr->next)
	{
	  col++;
	  if (col == 7)
	    {
	      strcat (hugebuf_o, "\n\r");
	      col = 1;
	    }
	  sprintf (hugebuf_o + strlen (hugebuf_o), "%-10s  ", tr->label);
	}
    }
  strcat (hugebuf_o, "\n\r");
  page_to_char (hugebuf_o, ch);
  return;
}

void 
save_triggers (void)
{
  FILE *fp;
  SINGLE_TRIGGER *tr;
  int i;
  if ((fp = fopen ("trig.dat", "w+")) == NULL)
    {
      fprintf (stderr, "Error on trigger write open!!  NOT GOOD!\n");
      return;
    }
  for (i = 0; i < TMAX_TRIGGERS; i++)
    {
      for (tr = trigger_list[i]; tr != NULL; tr = tr->next)
	{
	  fprintf (fp, "ID %s~\n", tr->trigger_id);
	  fprintf (fp, "Keywords %s~\n", tr->keywords);
	  fprintf (fp, "TT   %d\n", tr->trigger_type);
	  fprintf (fp, "Room %d\n", tr->attached_to_room);
	  fprintf (fp, "Mob  %d\n", tr->attached_to_mob);
	  fprintf (fp, "Obj  %d\n", tr->attached_to_obj);
	  fprintf (fp, "Int  %d\n", tr->interrupted);
	  fprintf (fp, "Plo  %d\n", tr->players_only);
	  fprintf (fp, "Clr  %d\n", tr->leaves_room);
	  fprintf (fp, "Code %s~\n", tr->code_label);
	}
    }
  fprintf (fp, "END\n");
  fclose (fp);
  return;
}

void 
load_triggers (void)
{
  SINGLE_TRIGGER *tr = NULL;
  FILE *fp;
  int ntr;
  char txt[100];
  if ((fp = fopen ("trig.dat", "r")) == NULL)
    {
      return;
    }

  for (;;)
    {
      strcpy (txt, fread_word (fp));
      if (!str_cmp (txt, "END"))
	break;
      if (!str_cmp (txt, "ID"))
	{
	  strcpy (txt, fread_string2 (fp, NULL));
	  tr = new_trigger (txt);
	  continue;
	}

      if (!str_cmp (txt, "TT"))
	{
	  ntr = fread_number (fp);
	  remove_trigger_from_list (tr);
	  tr->trigger_type = ntr;
	  tr->next = trigger_list[tr->trigger_type];
	  trigger_list[tr->trigger_type] = tr;
	  continue;
	}

      if (!str_cmp (txt, "Keywords"))
	{
	  tr->keywords = fread_string (fp, NULL);
	  continue;
	}
      if (!str_cmp (txt, "Room"))
	{
	  tr->attached_to_room = fread_number (fp);
	  continue;
	}
      if (!str_cmp (txt, "Mob"))
	{
	  tr->attached_to_mob = fread_number (fp);
	  continue;
	}
      if (!str_cmp (txt, "Obj"))
	{
	  tr->attached_to_obj = fread_number (fp);
	  continue;
	}
      if (!str_cmp (txt, "Plo"))
	{
	  tr->players_only = fread_number (fp);
	  continue;
	}
      if (!str_cmp (txt, "Clr"))
	{
	  tr->leaves_room = fread_number (fp);
	  continue;
	}
      if (!str_cmp (txt, "Int"))
	{
	  tr->interrupted = fread_number (fp);
	  continue;
	}
      if (!str_cmp (txt, "Code"))
	{
	  strcpy (tr->code_label, fread_string2 (fp, NULL));
	  continue;
	}
    }

  fclose (fp);
  return;
}



void 
save_code (void)
{
  FILE *fp;
  CODE *c;
  int i;
  if ((fp = fopen ("code.dat", "w+")) == NULL)
    {
      fprintf (stderr, "Error on code write open!!  NOT GOOD!\n");
      return;
    }
  for (i = 0; i < 256; i++)
    {
      for (c = code_list[i]; c != NULL; c = c->next)
	{
	  fprintf (fp, "LABEL %s~\n", c->label);
	  if (c->code)
	    fprintf (fp, "CODE %s~\n", fix_string (c->code));
	  else
	    fprintf (fp, "CODE done~\n");
	}
    }
  fprintf (fp, "END\n");
  fclose (fp);
  return;
}

void 
load_code (void)
{
  CODE *c = NULL;
  char txt[1100];
  FILE *fp;
  if ((fp = fopen ("code.dat", "r")) == NULL)
    {
      return;
    }

  for (;;)
    {
      strcpy (txt, fread_word (fp));
      if (!str_cmp (txt, "END"))
	break;
      if (!str_cmp (txt, "LABEL"))
	{
	  strcpy (txt, fread_string2 (fp, NULL));
	  c = new_code (txt);
	  continue;
	}
      if (!str_cmp (txt, "CODE"))
	{
	  c->code = fread_string (fp, NULL);
	  continue;
	}
    }

  fclose (fp);
  return;
}


/* ----------------------------------------------------- */
/* Stuff below here is for actually running the scripts! */
/* ----------------------------------------------------- */

CHAR_DATA *debugger = NULL;	/* This holds who debugging should go to */
char e_buf[500];
int executed_lines = 0;		/* Keeps track of lines executed.. traps repeating loops */


void 
debug (CHAR_DATA * ch, char *argy)
{
  DEFINE_COMMAND ("debug", debug, POSITION_DEAD, 110, LOG_NORMAL, "Sets all script error messages to go to you.")
    debugger = ch;
  send_to_char ("You now will recieve all script error messages.\n\r", ch);
  return;
}



void 
end_script (SCRIPT_INFO * scr)
{
  SCRIPT_INFO *ls;
  MARK_DEBUG ("End_script")
    scr->called_by->running_info = NULL;
  if (scr == info_list)
    {
      info_list = scr->next;
      scr->next = NULL;
    }
  else
    for (ls = info_list; ls != NULL; ls = ls->next)
      {
	if (ls->next == scr)
	  {
	    ls->next = scr->next;
	    scr->next = NULL;
	    break;
	  }
      }
  free (scr);
  return;
}

void 
e_goto_invalid_line_number (SCRIPT_INFO * scr, char *ln, int linenum)
{
  sprintf (e_buf, "Invalid goto line number '%s' in code label %s, line %d.  Script ended.\n\r",
	   ln, scr->code_seg, linenum);
  if (debugger)
    send_to_char (e_buf, debugger);
  end_script (scr);
  return;
}

void 
e_couldnt_find_label (SCRIPT_INFO * scr, char *lab, int linenum)
{
  sprintf (e_buf, "Couldn't find code label %s, line %d, in trigger %s.  Script ended.\n\r",
	   lab, linenum, scr->called_by->trigger_id);
  if (debugger)
    send_to_char (e_buf, debugger);
  end_script (scr);
  return;
}

void 
e_bad_wait_value (SCRIPT_INFO * scr, char *cmd)
{
  sprintf (e_buf, "Bad wait value of '%s', line %d, code label %s.  Script ended.\n\r",
	   cmd, scr->current_line - 1, scr->code_seg);
  if (debugger)
    send_to_char (e_buf, debugger);
  end_script (scr);
  return;
}

void 
e_bad_wait_type (SCRIPT_INFO * scr, char *typ)
{
  sprintf (e_buf, "Bad wait type '%s', line %d, code label %s.  Script ended.\n\r",
	   typ, scr->current_line - 1, scr->code_seg);
  if (debugger)
    send_to_char (e_buf, debugger);
  end_script (scr);
  return;
}

void 
e_repeating_loop (SCRIPT_INFO * scr)
{
  sprintf (e_buf, "Apparent repeating loop in code label %s, trigger %s.  Script ended.\n\r",
	   scr->code_seg, scr->called_by->trigger_id);
  if (debugger)
    send_to_char (e_buf, debugger);
  end_script (scr);
  return;
}

void 
e_invalid_create_obj (SCRIPT_INFO * scr, char *ln)
{
  sprintf (e_buf, "Invalid create object vnum '%s', code label %s line %d.  Script ended.\n\r",
	   ln, scr->code_seg, scr->current_line - 1);
  if (debugger)
    send_to_char (e_buf, debugger);
  end_script (scr);
  return;
}

void 
e_invalid_create_mob (SCRIPT_INFO * scr, char *ln)
{
  sprintf (e_buf, "Invalid create mob vnum '%s', code label %s line %d.  Script ended.\n\r",
	   ln, scr->code_seg, scr->current_line - 1);
  if (debugger)
    send_to_char (e_buf, debugger);
  end_script (scr);
  return;
}

void 
e_bad_if (SCRIPT_INFO * scr, char *ln)
{
  sprintf (e_buf, "Invalid if statement '%s', code label %s line %d.  Script ended.\n\r",
	   ln, scr->code_seg, scr->current_line - 1);
  if (debugger)
    send_to_char (e_buf, debugger);
  end_script (scr);
  return;
}

void 
e_bad_destroy_num (SCRIPT_INFO * scr, char *ln)
{
  sprintf (e_buf, "Bad destroy vnum: %s, code label %s line %d.  Script ended.\n\r",
	   ln, scr->code_seg, scr->current_line - 1);
  if (debugger)
    send_to_char (e_buf, debugger);
  end_script (scr);
  return;
}



char *
substitue_vars (SCRIPT_INFO * scr, char *ln)
{
  static char curln[8000];
  char *t;
  int pos = 0;
  curln[0] = '\0';
  MARK_DEBUG ("Substitute_vars")
    for (t = ln; *t != '\0'; t++)
    {
      if (*t == '@')
	{
	  t++;
	  if (*t == '\0')
	    break;
	  if (UPPER (*t) == 'C')
	    {
	      char toad[8000];
	      toad[0] = '\0';
	      curln[pos] = '\0';
	      t++;
	      if (*t == 't') {
		sprintf(toad,"%d",time_info.hour);
		} else
	      if (*t == 'r') {
		sprintf(toad,"%d",scr->current->pcdata->remort_times);
		} else
	      if (*t == 'K') {
		sprintf(toad,"%d",scr->current->pcdata->totalkills);
		} else

	      if (*t == 'k') {
		sprintf(toad,"%d",scr->current->pcdata->killpoints);
		} else
	      if (*t == 'c') {
		sprintf(toad,"%d",clan_number(scr->current));
		} else
	      if (*t == 'C') {
		sprintf(toad,"%d",clan_number_2(scr->current));
		} else
	      if (*t == 'm') {
		sprintf(toad,"%d",scr->current->move);
		} else
	      if (*t == 'M') {
		sprintf(toad,"%d",scr->current->max_move);
		} else
	      if (*t == 'H') {
		sprintf(toad,"%d",scr->current->max_hit);
		} else
	      if (*t == 'h') {
		sprintf(toad,"%d",scr->current->hit);
		} else
	      if (*t == 'w') {
		sprintf(toad,"%d",(IS_PLAYER(scr->current)?scr->current->pcdata->warpoints:0));
		} else
	      if (*t == 'g')
		{
		  if (!IS_EVIL (scr->current))
		    {
		      strcpy (toad, "1");
		    }
		  else
		    strcpy (toad, "0");
		}
	      else if (*t == 'e')
		{
		  if (!IS_EVIL (scr->current))
		    {
		      strcpy (toad, "0");
		    }
		  else
		    strcpy (toad, "1");
		}
	      else if (*t == 'l')
		{
			  sprintf(toad,"%d",LEVEL(scr->current));
		  
		}

	      strcat (curln, toad);
	      pos += strlen (toad);

	      continue;
	    }
	  if (UPPER (*t) == 'V')
	    {
		char vv[500];
	      curln[pos] = '\0';
	if (scr->obj && scr->obj->pIndexData->item_type==ITEM_CORPSE_NPC) {
		sprintf(vv,"%d",((I_CONTAINER *) (scr->obj->more))->key_vnum);
		strcat(curln,vv);
		pos += strlen(vv);
		}
		else
	      if (scr->mob)
		{
			  char tmp[50];
			  sprintf(tmp,"%d",scr->mob->pIndexData->vnum);
		  strcat (curln,tmp);
		  pos += strlen (tmp);
		}
	      else if (scr->obj)
		{
			  char tmp[50];
			  sprintf(tmp,"%d",scr->obj->pIndexData->vnum);
		  strcat (curln, tmp);
		  pos += strlen (tmp);
		}
	      else if (scr->room)
		{
			  char tmp[50];
			  sprintf(tmp,"%d",scr->room->vnum);
		  strcat (curln, tmp);
		  pos += strlen (tmp);
		}
	      else
		continue;
	    }
	  if (UPPER (*t) == 'P')
	    {			/* Player name */
	      curln[pos] = '\0';
	      if (scr->current)
		{
		  strcat (curln, NAME (scr->current));
		  pos += strlen (NAME (scr->current));
		}
	      continue;
	    }
	  if (UPPER (*t) == 'M')
	    {			/* Mob name */
	      curln[pos] = '\0';
	      if (scr->mob)
		{
		  strcat (curln, NAME (scr->mob));
		  pos += strlen (NAME (scr->mob));
		}
	      continue;
	    }
	  if (UPPER (*t) == 'O')
	    {			/* Obj name */
	      curln[pos] = '\0';
	      if (scr->obj)
		{
		  strcat (curln, scr->obj->pIndexData->short_descr);
		  pos += strlen (scr->obj->pIndexData->short_descr);
		}
	      continue;
	    }
	  if (UPPER (*t) == 'R')
	    {			/* Random number eg... @R(1,10) */
	      char num1[50];
	      char num2[50];
	      int n1;
	      int n2;
	      int rn;
	      int tt = 0;
	      curln[pos] = '\0';
	      t++;
	      if (*t != '(')
		continue;
	      t++;
	      for (; *t != ',' && *t != ')'; t++)
		{
		  num1[tt] = *t;
		  tt++;
		}
	      num1[tt] = '\0';
	      t++;
	      tt = 0;
	      for (; *t != ')'; t++)
		{
		  if (*t != ' ')
		    num2[tt] = *t;
		  tt++;
		}
		  {
		  char tmp[50];
	      num2[tt] = '\0';
	      n1 = atoi (num1);
	      n2 = atoi (num2);
	      rn = number_range (n1, n2);
		  sprintf(tmp,"%d",rn);
	      strcat (curln, tmp);
	      pos += strlen (tmp);
	      continue;
		  }
	    }
	  continue;
	}
      curln[pos] = *t;
      pos++;
    }

  curln[pos] = '\0';
  return curln;
}




void 
execute_code (SCRIPT_INFO * scr)
{
  CODE *c;
  char cur_line[5000];
  char arg1[5000];
  char curl2[5000];
  char *ln;
  int i;
  int linenum;
  char *t;
  char argg[5000];
  executed_lines = 0;

  MARK_DEBUG ("Execute_code")

    if (!scr->current || !scr->called_by || !scr->current->in_room)
    {
      end_script (scr);
      return;
    }
/*sprintf(cl,":Current (%s) (%d)",NAME(scr->current),scr->current->in_room->vnum);
sprintf(cl+strlen(cl),":Called_by (%s)",scr->called_by->trigger_id);
*/
/* Halt script if character left the room and the script says to do so */
  if (scr->called_by && scr->called_by->leaves_room &&
      ((scr->mob && scr->mob->in_room != scr->current->in_room) ||
       (scr->room && scr->room != scr->current->in_room)))
    {
      end_script (scr);
      return;
    }
execute:			/* Main execute loop */

  cur_line[0] = '\0';
  i = 0;
  linenum = 0;
  t = NULL;
  ln = NULL;
  arg1[0] = '\0';
  scr->tick_type = 0;
  scr->delay_ticks = 0;

  c = NULL;

  if ((c = find_code (scr->code_seg)) == NULL)
    {
      e_couldnt_find_label (scr, scr->code_seg, 0);
      return;
    }



  if (scr->current_line == 0)
    scr->current_line = 1;

  for (t = c->code; *t != '\0'; t++)
    {
      if (*t == ':')
	linenum++;
      if (linenum == scr->current_line)
	{
	  t++;
	  for (; *t != ' ' && *t != ':' && *t != '\0'; t++)
	    {
	    }
	  if (*t != '\0')
	    t++;
	  for (; *t != '\n' && *t != ':' && *t != '\0'; t++)
	    {
	      cur_line[i] = *t;
	      i++;
	    }
	  cur_line[i] = '\0';
	  goto foundit;
	}
    }
  end_script (scr);		/* Past the max line numbers */
  return;

foundit:

  strcpy (curl2, substitue_vars (scr, cur_line));
  strcpy (cur_line, curl2);
  one_argy (curl2, argg);
  ln = cur_line;

/*sprintf(cl,"Scriptline: %s\n",cur_line);
*/
  scr->current_line++;		/* Increment 'program counter' */

/* Begin interpretting commands */

  if (!str_cmp (argg, "call"))
    {				/* Call <other code label> */
	char clab[500];
      ln = one_argy (ln, arg1);
      if ((c = find_code (ln)) == NULL)
	{
	  e_couldnt_find_label (scr, ln, scr->current_line - 1);
	  return;
	}
      strcpy(clab,scr->code_seg);
      strcpy (scr->code_seg, ln);
      scr->current_line = 1;
	execute_code(scr);
	strcpy(scr->code_seg,clab);
	return;
    }

  else if (!str_cmp (argg, "goto"))
    {
      int totl = 0;
      int got = 0;
      char *tt;
      ln = one_argy (ln, arg1);
      for (tt = c->code; *tt != '\0'; tt++)
	{
	  if (*tt == ':')
	    totl++;
	}
      if (!is_number (ln))
	{
	  e_goto_invalid_line_number (scr, ln, scr->current_line - 1);
	  return;
	}
      got = atoi (ln);
      if (got < 1 || got > totl)
	{
	  e_goto_invalid_line_number (scr, ln, scr->current_line - 1);
	  return;
	}
      scr->current_line = got;
    }

  else if (!str_cmp (argg, "wait"))
    {
      char *l;
      char rg1[500];
      char rg2[500];
      int wait;
      l = cur_line;
      l = one_argy (l, rg1);
      l = one_argy (l, rg2);	/* rg1 holds wait, rg2 holds number, l holds tick type */
      if ((wait = atoi (rg2)) < 1)
	{
	  e_bad_wait_value (scr, rg2);
	  return;
	}
      if (!str_cmp (l, "superquick"))
	{
	  scr->tick_type = 4;
	  scr->delay_ticks = wait;
	}
      else if (!str_cmp (l, "quick"))
	{
	  scr->tick_type = 1;
	  scr->delay_ticks = wait;
	}
      else if (!str_prefix ("heart", l))
	{
	  scr->tick_type = 2;
	  scr->delay_ticks = wait;
	}
      else if (!str_cmp (l, "hour"))
	{
	  scr->tick_type = 3;
	  scr->delay_ticks = wait;
	}
      else
	{
	  e_bad_wait_type (scr, l);
	}
      return;
    }

  else if (!str_cmp (cur_line, "done"))
    {
      end_script (scr);
      return;
    }

  else if (!str_prefix ("create_mob", argg))
    {
      int mnum;
      MOB_PROTOTYPE *m;
      CHAR_DATA *mob;
      char *l = cur_line;
      l = one_argy (l, argg);
      if (!is_number (l))
	{
	  e_invalid_create_mob (scr, l);
	  return;
	}
      mnum = atoi (l);
      if ((m = get_mob_index (mnum)) == NULL)
	{
	  e_invalid_create_mob (scr, l);
	  return;
	}
      mob = create_mobile (m);
      /* Created the mob.. now place in room.. */
      if (scr->mob)
	{
	  char_to_room (mob, scr->mob->in_room);
	}
      else if (scr->room)
	{
	  char_to_room (mob, scr->room);
	}
      if (scr->obj)
	{
	  if (scr->obj->carried_by != NULL)
	    char_to_room (mob, scr->current->in_room);
	  else if (scr->obj->in_room != NULL)
	    char_to_room (mob, scr->obj->in_room);
	}
    }

  else if (!str_prefix ("destroy_mob", argg))
    {
      char *l = cur_line;
      l = one_argy (l, argg);
      if (scr->current)
	{
	  stop_fighting (scr->current, TRUE);
	  char_from_room (scr->current);
	  extract_char (scr->current, TRUE);
	  return;
	}
    }

  else if (!str_prefix ("destroy_obj", argg))
    {
      char *l = cur_line;
      OBJ_PROTOTYPE *op;
      l = one_argy (l, argg);
      if (scr->obj)
	{
	  obj_from (scr->obj);
	  free_it (scr->obj);	/*free_it also stops ends script! */
	  return;
	}
      if (!is_number (l))
	{
	  e_bad_destroy_num (scr, l);
	  return;
	}
      if ((op = get_obj_index (atoi (l))) == NULL)
	{
	  e_bad_destroy_num (scr, l);
	  return;
	}
      if (scr->mob)
	{
	  SINGLE_OBJECT *o;
	  SINGLE_OBJECT *o_next_content;
	  bool des = FALSE;
	  for (o = scr->mob->carrying; o != NULL && !des; o = o_next_content)
	    {
	      o_next_content = o->next_content;
	      if (o->pIndexData == op)
		{
		  obj_from (o);
		  free_it (o);
		  des = TRUE;
		}
	    }
	}
      else if (scr->room)
	{
	  SINGLE_OBJECT *o;
	  SINGLE_OBJECT *o_next_content;
	  bool des = FALSE;
	  if (scr->room->more)
	    for (o = scr->room->more->contents; o != NULL && !des; o = o_next_content)
	      {
		o_next_content = o->next_content;
		if (o->pIndexData == op)
		  {
		    obj_from (o);
		    free_it (o);
		    des = TRUE;
		  }
	      }
	}
    }

  else if (!str_prefix ("create_obj_char", argg))
  {
      int onum;
      OBJ_PROTOTYPE *o;
      SINGLE_OBJECT *obj;
      char *l = cur_line;
      l = one_argy (l, argg);
      if (!is_number (l))
	{
	  e_invalid_create_obj (scr, l);
	  return;
	}
      onum = atoi (l);
      if ((o = get_obj_index (onum)) == NULL)
	{
	  e_invalid_create_obj (scr, l);
	  return;
	}
      obj = create_object (o, 1);
      if (scr->current)
	{
        obj_to (obj, scr->current);
	}
    }

  else if (!str_prefix ("create_obj", argg))
    {
      int onum;
      OBJ_PROTOTYPE *o;
      SINGLE_OBJECT *obj;
      char *l = cur_line;
      l = one_argy (l, argg);
      if (!is_number (l))
	{
	  e_invalid_create_obj (scr, l);
	  return;
	}
      onum = atoi (l);
      if ((o = get_obj_index (onum)) == NULL)
	{
	  e_invalid_create_obj (scr, l);
	  return;
	}
      obj = create_object (o, 1);
      /* Created the object.. now place in room, on char, on mob.. */
      if (scr->mob)
	{
	  obj_to (obj, scr->mob);
	}
      else if (scr->room)
	{
	  obj_to (obj, scr->room);
	}
      if (scr->obj)
	{
	  if (scr->obj->carried_by != NULL)
	    obj_to (obj, scr->obj->carried_by);
	  else if (scr->obj->in_room != NULL)
	    obj_to (obj, scr->obj->in_room);
	  else if (scr->obj->in_obj != NULL)
	    obj_to (obj, scr->obj->in_obj);
	}
    }

  else if (!str_cmp (argg, "if"))
    {
      char *l = cur_line;
      char *tc;
      char leftnum[50];
      int cci = 0;
      bool beq = FALSE;
      bool bge = FALSE;
      bool bgt = FALSE;
      bool ble = FALSE;
      bool blt = FALSE;
      bool bne = FALSE;
      char rightnum[50];
      l = one_argy (l, argg);
      if (*l == '(')
	{
	  int st;
	  bool ne = FALSE;
	  l++;
	  if (*l == '!')
	    {
	      ne = TRUE;
	      l++;
	    }
	  for (tc = l; *tc != ')'; tc++)
	    {
	      if (*tc == '\0')
		{
		  e_bad_if (scr, cur_line);
		  return;
		}
	      leftnum[cci] = *tc;
	      cci++;
	    }
	  leftnum[cci] = '\0';

	  for (st = 0; st < 3000; st++)
	    {
	      if (!scr->current->pcdata->script_flags[st] || scr->current->pcdata->script_flags[st][0] == '\0')
		continue;
	      if (!str_cmp (scr->current->pcdata->script_flags[st], leftnum))
		goto matched;
	    }
	  scr->current_line++;
	  goto dunw;
	matched:
	  if (ne)
	    scr->current_line++;
	dunw:
	  if (scr) {};
	}
      else
	{
	  for (tc = l; *tc != '=' && *tc != '>' && *tc != '<' && *tc != '!'; tc++)
	    {
	      if (*tc == '\0')
		{
		  e_bad_if (scr, cur_line);
		  return;
		}
	      if (*tc == ' ')
		continue;
	      leftnum[cci] = *tc;
	      cci++;
	    }
	  leftnum[cci] = '\0';

	  if (*tc == '=')
	    {
	      if (*(tc + 1) == '=')
		tc++;
	      beq = TRUE;
	    }
	  else if (*tc == '>')
	    {
	      if (*(tc + 1) == '=')
		{
		  tc++;
		  bge = TRUE;
		}
	      else
		bgt = TRUE;
	    }
	  else if (*tc == '<')
	    {
	      if (*(tc + 1) == '=')
		{
		  tc++;
		  ble = TRUE;
		}
	      else
		blt = TRUE;
	    }
	  else if (*tc == '!')
	    {
	      if (*(tc + 1) == '=')
		{
		  tc++;
		}
	      bne = TRUE;
	    }
	  else
	    {
	      e_bad_if (scr, cur_line);
	      return;
	    }

	  tc++;
	  cci = 0;

	  for (; *tc != ' '; tc++)
	    {
	      if (*tc == '\0')
		{
		  e_bad_if (scr, cur_line);
		  return;
		}
	      rightnum[cci] = *tc;
	      cci++;
	    }
	  rightnum[cci] = '\0';

	  if (is_number (leftnum))
	    {
	      int lnm;
	      int rnm;
	      lnm = atoi (leftnum);
	      rnm = atoi (rightnum);
	      if (beq && lnm != rnm)
		{
		  scr->current_line++;
		}
	      else if (bgt && lnm <= rnm)
		{
		  scr->current_line++;
		}
	      else if (bge && lnm < rnm)
		{
		  scr->current_line++;
		}
	      else if (blt && lnm >= rnm)
		{
		  scr->current_line++;
		}
	      else if (ble && lnm > rnm)
		{
		  scr->current_line++;
		}
	      else if (bne && lnm == rnm)
		{
		  scr->current_line++;
		}
	    }
	  else
	    {
	      if (bne && !str_cmp (leftnum, rightnum))
		{
		  scr->current_line++;
		}
	      else if (!bne && str_cmp (leftnum, rightnum))
		{
		  scr->current_line++;
		}
	    }
	}
    }

  else if (!str_cmp (argg, "recho"))
    {
      char *l = cur_line;
      l = one_argy (l, argg);
      do_recho (scr->current, l);
    }

  else if (!str_cmp (argg, "show"))
    {
      char *l = cur_line;
      l = one_argy (l, argg);
      send_to_char (l, scr->current);
      send_to_char ("\n\r", scr->current);
    }

  else if (!str_cmp (argg, "show_to_room"))
    {
      char *l = cur_line;
      l = one_argy (l, argg);
      act (l, scr->current, NULL, scr->current, TO_ROOM);
    }

  else if (scr->mob)
    {
      interpret (scr->mob, cur_line);
    }

  else if (scr->room || scr->obj)
    {				/* Warning.. should ONLY be used for pset, etc.. not recho! */
      CHAR_DATA *sch;
      sch=create_mobile(get_mob_index(1));
      if (scr->room) char_to_room(sch,scr->room);
         else char_to_room(sch,get_room_index(1));
      interpret (sch, cur_line);
	extract_char(sch,TRUE);
    }

/* End interpretting commands */

  executed_lines++;
  if (executed_lines > 300)
    {
      e_repeating_loop (scr);
      return;
    }

  goto execute;

  return;
}

char *
string_unpad (char *argy)
{
  char buf[STD_LENGTH];
  char *s;
  s = argy;
  while (*s == ' ')
    s++;
  strcpy (buf, s);
  s = buf;
  if (*s != '\0')
    {
      while (*s != '\0')
	s++;
      s--;
      while (*s == ' ')
	s--;
      s++;
      *s = '\0';
    }
  free_string (argy);
  return str_dup (buf);
}

char *
string_proper (char *argy)
{
  char *s;
  s = argy;
  while (*s != '\0')
    {
      if (*s != ' ')
	{
	  *s = UPPER (*s);
	  while (*s != ' ' && *s != '\0')
	    s++;
	}
      else
	{
	  s++;
	}
    }
  return argy;
}

char *
string_replace (char *orig, char *old, char *new)
{
  char xbuf[STD_LENGTH];
  int i;
  xbuf[0] = '\0';
  strcpy (xbuf, orig);
  if (strstr (orig, old) != NULL)
    {
      i = strlen (orig) - strlen (strstr (orig, old));
      xbuf[i] = '\0';
      strcat (xbuf, new);
      strcat (xbuf, &orig[i + strlen (old)]);
      free_string (orig);
    }
  return str_dup (xbuf);
}

void 
string_edit (CHAR_DATA * ch, char **pString)
{
  send_to_char ("-=======================================-\n\r", ch);
  send_to_char (" Entering line editing mode.\n\r", ch);
  send_to_char (" Terminate with a @ on a blank line.\n\r", ch);
  send_to_char ("-=======================================-\n\r", ch);
  if (*pString == NULL)
    {
      *pString = str_dup ("");
    }
  else
    {
      free_string (*pString);
      *pString = str_dup ("");
    }
  ch->desc->pString = pString;
  return;
}

void 
string_append (CHAR_DATA * ch, char **pString)
{
  send_to_char ("------------------------ LINE Editor -------------------------\n\r", ch);
  send_to_char (" Type .c to clear the whole text, .f to format the text,\n\r", ch);
  send_to_char (" .r 'orig' 'new' to replace, and .s to view the string so far.\n\r", ch);
  send_to_char (" Use @ on a blank line to save and quit the editor.\n\r", ch);
  send_to_char ("--------------------------------------------------------------\n\r", ch);
  if (*pString == NULL)
    {
      *pString = str_dup ("");
    }
  send_to_char ("Editing description:\n\r", ch);
  send_edit_char (*pString, ch);
  send_to_char ("-=======================================-\n\r", ch);
  ch->desc->pString = pString;
  return;
}

void 
string_add (CHAR_DATA * ch, char *argy)
{
  char buf[40000];
  if (!ch->desc)
    return;
  if (!ch->pcdata->name)
    return;
  if (!argy || argy == "")
    return;
  if (*argy == ':')
    {
      char texts[202][255];
      char *lne;
      char *t;
      int i = 0;
      int mrk = 0;
      int curline = -1;
      int linenum = 0;
      buf[0] = '\0';
      for (t = argy; *t != ' ' && *t != '\0'; t++)
	{
	  mrk++;
	}
      *t = '\0';
      lne = (argy + 1);
      if ((linenum = atoi (lne)) < 1 || linenum > 199)
	{
	  send_to_char ("Invalid line number!\n\r", ch);
	  return;
	}
      argy += mrk + 1;
      for (t = *ch->desc->pString; *t != '\0'; t++)
	{
	  if (*t == ':' || t == *ch->desc->pString)
	    {
	      for (; *(t + 1) != '\0' && *t != ' '; t++)
		{
		};
	      if (curline >= 0)
		texts[curline][i] = '\0';
	      curline++;
	      i = 0;
	      continue;
	    }
	  if (curline < 0)
	    curline = 0;
	  if (*t == '\r')
	    continue;
	  if (*t == '\n')
	    continue;
	  texts[curline][i] = *t;
	  i++;
	}
      texts[curline][i] = '\0';

      /* Insert into correct place */
      for (i = curline; i >= linenum - 1; i--)
	{
	  strcpy (texts[i + 1], texts[i]);
	}
      strcpy (texts[linenum - 1], argy);
      curline++;

      /* Now reconstruct in the char buffer */
      buf[0] = '\0';
      for (i = 0; i <= curline; i++)
	{
	  sprintf (buf + strlen (buf), ":%d ", i + 1);
	  strcat (buf, texts[i]);
	}
      strcat (buf, "\n\r");
      free_string (*ch->desc->pString);
      *ch->desc->pString = str_dup (buf);
      return;
    }
  if (*argy == '.')
    {
      char arg1[SML_LENGTH];
      char arg2[SML_LENGTH];
      char arg3[SML_LENGTH];
      argy = one_argy (argy, arg1);
      argy = first_arg (argy, arg2, FALSE);
      argy = first_arg (argy, arg3, FALSE);

      if (!str_cmp (arg1, ".c"))
	{
	  if (is_number (arg2))
	    {
	      char texts[202][150];
	      int i = 0;
	      char *t;
	      int curline = -1;
	      int linenum = atoi (arg2);
	      buf[0] = '\0';
	      if (linenum < 1 || linenum > 199)
		{
		  send_to_char ("Invalid line number!\n\r", ch);
		  return;
		}
	      for (t = *ch->desc->pString; *t != '\0'; t++)
		{
		  if (*t == ':' || t == *ch->desc->pString)
		    {
		      for (; *(t + 1) != '\0' && *t != ' '; t++)
			{
			};
		      if (curline >= 0)
			texts[curline][i] = '\0';
		      curline++;
		      i = 0;
		      continue;
		    }
		  if (curline < 0)
		    curline = 0;
		  if (*t == '\r')
		    continue;
		  if (*t == '\n')
		    continue;
		  texts[curline][i] = *t;
		  i++;
		}
	      texts[curline][i] = '\0';
	      buf[0] = '\0';
	      for (i = linenum; i <= curline; i++)
		{
		  strcpy (texts[i - 1], texts[i]);
		}
	      texts[i][0] = '\0';
	      curline--;
	      buf[0] = '\0';
	      for (i = 0; i <= curline; i++)
		{
		  sprintf (buf + strlen (buf), ":%d ", i + 1);
		  strcat (buf, texts[i]);
		}
	      strcat (buf, "\n\r");
	      free_string (*ch->desc->pString);
	      *ch->desc->pString = str_dup (buf);
	      return;
	    }
	  send_to_char ("String cleared.\n\r", ch);
	  free_string (*ch->desc->pString);
	  *ch->desc->pString = str_dup ("");
	  return;
	}
      if (!str_cmp (arg1, ".s"))
	{
	  send_to_char ("String so far:\n\r", ch);
	  send_edit_char (*ch->desc->pString, ch);
	  return;
	}
      if (!str_cmp (arg1, ".r"))
	{
	  if (arg2[0] == '\0')
	    {
	      send_to_char ("usage: .r \"old text\" \"new text\"\n\r", ch);
	      return;
	    }
	  *ch->desc->pString = string_replace (*ch->desc->pString, arg2, arg3);
	  sprintf (buf, "'%s' replaced with '%s'.\n\r", arg2, arg3);
	  send_to_char (buf, ch);
	  return;
	}
      if (!str_cmp (arg1, ".f"))
	{
	  *ch->desc->pString = format_string (*ch->desc->pString);
	  send_to_char ("String formatted.\n\r", ch);
	  return;
	}
      if (!str_cmp (arg1, ".h"))
	{
	  send_to_char ("Help (commands): \n\r", ch);
	  send_to_char (".r 'old text' 'new text' - replace a string with a new string \n\r", ch);
	  send_to_char (" (requires '' OR \"\" around the argys)\n\r", ch);
	  send_to_char (".h - this info \n\r", ch);
	  send_to_char (".s - show the string \n\r", ch);
	  send_to_char (".f - format (word wrap/capitalize and space) string \n\r", ch);
	  send_to_char (".c - clear the entire string! \n\r", ch);
	  send_to_char ("@ - end string editor \n\r", ch);
	  return;
	}
      send_to_char ("Command unrecognized.\n\r", ch);
      return;
    }
  if (*argy == '~' || *argy == '@')
    {
      ch->desc->pString = NULL;
      return;
    }
  if (LEVEL (ch) < 110 && *ch->desc->pString && strlen (*ch->desc->pString) > 5000)
    {
      send_to_char ("Edited text too long.\n\r", ch);
      free_string (*ch->desc->pString);
      *ch->desc->pString = &str_empty[0];
      ch->desc->pString = NULL;
      return;
    }
  strcpy (buf, *ch->desc->pString);
  if (strlen(buf)>4096) {
      send_to_char ("String too long, truncating.\n\r", ch);
      free_string (*ch->desc->pString);
      *ch->desc->pString = str_dup("");
      ch->desc->pString = NULL;
      return;
  }

  if (strlen (buf) + strlen (argy) >= (STD_LENGTH - 4))
    {
      send_to_char ("String too long, truncating.\n\r", ch);
      free_string (*ch->desc->pString);
      *ch->desc->pString = str_dup("");
      ch->desc->pString = NULL;
      return;
    }
  strcat (buf, argy);
  strcat (buf, "\n\r");
  free_string (*ch->desc->pString);
  *ch->desc->pString = str_dup (buf);
  return;
}

char *
format_string (char *oldstring)
{
  char xbuf[40000];
  char xbuf2[40000];
  char *rdesc;
  char *t;
  int i = 0;
  bool cap = TRUE;
  xbuf[0] = xbuf2[0] = 0;
  i = 0;
  for (t = oldstring; *t; t++)
    {
      if (*t == ':' && *(t + 1) >= '0' && *(t + 1) <= '9')
	{
	  xbuf[0] = '\0';
	  i = 0;
	  for (t = oldstring; *t; t++)
	    {
	      if (*t == '\n' || *t == '\r')
		continue;
	      xbuf[i] = *t;
	      i++;
	    }
	  xbuf[i] = '\n';
	  xbuf[i + 1] = '\r';
	  xbuf[i + 2] = '\0';
	  free_string (oldstring);
	  return (str_dup (xbuf));
	}
    }
  for (rdesc = oldstring; *rdesc; rdesc++)
    {
      if (*rdesc == '\n')
	{
	  if (xbuf[i - 1] != ' ')
	    {
	      xbuf[i] = ' ';
	      i++;
	    }
	}
      else if (*rdesc == '\r');
      else if (*rdesc == ' ')
	{
	  if (xbuf[i - 1] != ' ')
	    {
	      xbuf[i] = ' ';
	      i++;
	    }
	}
      else if (*rdesc == ')')
	{
	  if (xbuf[i - 1] == ' ' && xbuf[i - 2] == ' ' &&
	   (xbuf[i - 3] == '.' || xbuf[i - 3] == '?' || xbuf[i - 3] == '!'))
	    {
	      xbuf[i - 2] = *rdesc;
	      xbuf[i - 1] = ' ';
	      xbuf[i] = ' ';
	      i++;
	    }
	  else
	    {
	      xbuf[i] = *rdesc;
	      i++;
	    }
	}
      else if ((*rdesc == '.' && *(rdesc + 1) < '0' && *(rdesc + 1) > '9')
	       || *rdesc == '?' || *rdesc == '!')
	{
	  if (xbuf[i - 1] == ' ' && xbuf[i - 2] == ' ' &&
	   (xbuf[i - 3] == '.' || xbuf[i - 3] == '?' || xbuf[i - 3] == '!'))
	    {
	      xbuf[i - 2] = *rdesc;
	      if (*(rdesc + 1) != '\"')
		{
		  xbuf[i - 1] = ' ';
		  xbuf[i] = ' ';
		  i++;
		}
	      else
		{
		  xbuf[i - 1] = '\"';
		  xbuf[i] = ' ';
		  xbuf[i + 1] = ' ';
		  i += 2;
		  rdesc++;
		}
	    }
	  else
	    {
	      xbuf[i] = *rdesc;
	      if (*(rdesc + 1) != '\"')
		{
		  xbuf[i + 1] = ' ';
		  xbuf[i + 2] = ' ';
		  i += 3;
		}
	      else
		{
		  xbuf[i + 1] = '\"';
		  xbuf[i + 2] = ' ';
		  xbuf[i + 3] = ' ';
		  i += 4;
		  rdesc++;
		}
	    }
	  cap = TRUE;
	}
      else
	{
	  xbuf[i] = *rdesc;
	  if (cap)
	    {
	      cap = FALSE;
	      xbuf[i] = UPPER (xbuf[i]);
	    }
	  i++;
	}
    }
  xbuf[i] = 0;
  strcpy (xbuf2, xbuf);
  rdesc = xbuf2;
  xbuf[0] = 0;
  for (;;)
    {
      for (i = 0; i < 77; i++)
	{
	  if (!*(rdesc + i))
	    break;
	}
      if (i < 77)
	{
	  break;
	}
      for (i = (xbuf[0] ? 76 : 73); i; i--)
	{
	  if (*(rdesc + i) == ' ')
	    break;
	}
      if (i)
	{
	  *(rdesc + i) = 0;
	  strcat (xbuf, rdesc);
	  strcat (xbuf, "\n\r");
	  rdesc += i + 1;
	  while (*rdesc == ' ')
	    rdesc++;
	}
      else
	{
	  bug ("No spaces", 0);
	  *(rdesc + 75) = 0;
	  strcat (xbuf, rdesc);
	  strcat (xbuf, "-\n\r");
	  rdesc += 76;
	}
    }
  while (*(rdesc + i) && (*(rdesc + i) == ' ' ||
			  *(rdesc + i) == '\n' ||
			  *(rdesc + i) == '\r'))
    i--;
  *(rdesc + i + 1) = 0;
  strcat (xbuf, rdesc);
  if (xbuf[strlen (xbuf) - 2] != '\n')
    strcat (xbuf, "\n\r");
  free_string (oldstring);
  return (str_dup (xbuf));
}

/*
   * Replace a substring with a new substring, return the new version.
   * (make sure to str_dup() when needed)
 */
char *
replace_string (char *orig, char *old, char *new)
{
  char xbuf[STD_LENGTH];
  int i;
  xbuf[0] = '\0';
  strcpy (xbuf, orig);
  if (strstr (orig, old) != NULL)
    {
      i = strlen (orig) - strlen (strstr (orig, old));
      xbuf[i] = '\0';
      strcat (xbuf, new);
      strcat (xbuf, &orig[i + strlen (old)]);
      free_string (orig);
    }
  return (str_dup (xbuf));
}


bool
one_is_of_two (char *looking_for, char *line)
{
  char arg[8000];
  char *r;
  arg[0]='\0';
  while (line[0] != '\0')
    {
      line = one_argy (line, arg);
      r = arg;
      if (!str_cmp (looking_for, r) ||
	  (strlen (looking_for) > 4 && !str_prefix (looking_for, r)) ||
	  (strlen (looking_for) > 4 && !str_prefix (r, looking_for)) ||
	  !str_infix (r, looking_for))
	return TRUE;
    }
  return FALSE;
}

bool
one_is_in_list_two (char *looking_for, char *line)
{
  char arg[8000];
  char *r;
  arg[0]='\0';
  while (line[0] != '\0')
    {
      line = one_argy (line, arg);
      r = arg;
      if (!str_cmp (looking_for, r))
	return TRUE;
    }
  return FALSE;
}