mc25b/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen  *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/
/***************************************************************************
 *                                 _/                            _/        *
 *      _/_/_/  _/_/      _/_/_/  _/    _/_/    _/    _/    _/_/_/         *
 *     _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/          *
 *    _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/           *
 *   _/    _/    _/    _/_/_/  _/    _/_/      _/_/_/    _/_/_/            *
 ***************************************************************************
 * Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius),                 *
 * Additional credits are in the help file CODECREDITS                     *
 * All Rights Reserved.                                                    *
 ***************************************************************************/
/*
 * Communication storage system. Ye Jobo.
 */

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

HISTORY_DATA * history_free;
HISTORY_DATA * stored_tells;

void init_channel_storage()
{
  int i, j;

  for (i = 1; i < STORE_MAX; i++)
  {
    for (j = 1; j <= MAX_STORAGE; j++)
    {
      old_messages[i].last[j] = str_dup("");
    }
  }
}

void update_channel_storage(char *buf, int chan)
{
  char xbuf[MAX_STRING_LENGTH];
  char tbuf[20];
  int i;

  if (chan != STORE_TELL)
  {
    xprintf(tbuf, "%-18.18s", buf);
    xprintf(xbuf, "%s %s", tbuf, line_indent(&buf[19], 15, 85));
  }
  else xprintf(xbuf, buf);

  if (chan >= STORE_MAX)
  {
    bug("update_channel_storage : Bad channel", 0);
    return;
  }

  for (i = MAX_STORAGE; i > 1; i--)
  {
    free_string(old_messages[chan].last[i]);
    old_messages[chan].last[i] = str_dup(old_messages[chan].last[i-1]);
  }
  free_string(old_messages[chan].last[1]);
  old_messages[chan].last[1] = str_dup(xbuf);
}

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

  one_argument(argument, arg);

  if (IS_NPC(ch)) return;
  if (!str_cmp(arg, "chat")) showchannel(ch, STORE_CHAT);
  else if (!str_cmp(arg, "newbie")) showchannel(ch, STORE_NEWBIE);
  else if (!str_cmp(arg, "flame")) showchannel(ch, STORE_FLAME);
  else if (!str_cmp(arg, "roleplay")) showchannel(ch, STORE_ROLEPLAY);
  else if (!str_cmp(arg, "tell") && ch->level > 6) showchannel(ch, STORE_TELL);
  else if (ch->level < 7) send_to_char("Show the last chat/newbie/flame/roleplay messages ?\n\r", ch);
  else send_to_char("Show the last chat/newbie/flame/roleplay/tell messages ?\n\r", ch);
  return;
}

void showchannel(CHAR_DATA *ch, int chan)
{
  char buf[MAX_STRING_LENGTH];
  int i;

  for (i = MAX_STORAGE; i > 0; i--)
  {
    if (strlen(old_messages[chan].last[i]) < 1) continue;
    xprintf(buf, "%s\n\r", old_messages[chan].last[i]);
    send_to_char(buf, ch);
  }
}

void init_tell_storage()
{
  HISTORY_DATA *history_new;
  HISTORY_DATA *history_prev = NULL;
  int i;

  for (i = 0; i < MAX_STORAGE; i++)
  {
    if (history_free == NULL)
    {
      history_new = alloc_perm(sizeof(*history_new));
    }
    else
    {
      history_new  = history_free;
      history_free = history_free->next;
    }
    history_new->message = str_dup("");
    history_new->next = history_prev;
    history_prev = history_new;
  }
  stored_tells = history_new;
}

/*
char *makedrunk ( char *string, CHAR_DATA * ch )
{
    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[MSL];
    char temp;
    int pos = 0;
    int drunklevel;
    int randomnum;

    if ( ch == NULL )
        drunklevel = 5;
    else
    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';       
        strcpy ( string, buf );
        return ( string );
    }
    return ( string );
}
*/

char *drunktalk(char *argument)
{
  static char buf[MAX_STRING_LENGTH];
  char *ptr;
  int i, length;

  struct spk_type
  {
    char * old;
    char * new;
  };

  static const struct spk_type spk_table[] =
  {
    { " ",  " "   },
    { "is", "ish" },
    { "a", "a" }, { "b", "b" }, { "c", "c" }, { "d", "d" },
    { "e", "e" }, { "f", "f" }, { "g", "g" }, { "h", "h" },
    { "i", "i" }, { "j", "j" }, { "k", "k" }, { "l", "l" },
    { "m", "m" }, { "n", "n" }, { "o", "o" }, { "p", "p" },
    { "q", "q" }, { "r", "r" }, { "s", "s" }, { "t", "t" },
    { "u", "u" }, { "v", "v" }, { "w", "w" }, { "x", "x" },
    { "y", "y" }, { "z", "z" }, { ",", "," }, { ".", "." },
    { ";", ";" }, { ":", ":" }, { "(", "(" }, { ")", ")" },
    { ")", ")" }, { "-", "-" }, { "!", "!" }, { "?", "?" },
    { "1", "1" }, { "2", "2" }, { "3", "3" }, { "4", "4" },
    { "5", "5" }, { "6", "6" }, { "7", "7" }, { "8", "8" },
    { "9", "9" }, { "0", "0" }, { "%", "%" }, {  "",  "" }
  };

  buf[0] = '\0';

  for (ptr = argument; *ptr != '\0'; ptr += length)
  {
    for (i = 0; spk_table[i].old[0] != '\0'; i++)
    {
      if (!str_prefix(spk_table[i].old, ptr))
	 {
        strcat(buf, spk_table[i].new);

        if (number_range(1, 5) == 1 && str_cmp(spk_table[i].new, " "))
          strcat(buf, spk_table[i].new);
        else if (!str_cmp(spk_table[i].new, " "))
        {
          if (number_range(1, 5) == 1 && strlen(buf) < MAX_INPUT_LENGTH)
            strcat(buf, "*hic* ");
        }
        break;
      }
    }

    length = UMAX(1, strlen(spk_table[i].old));
  }

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

  for (i = 1; buf[i] != '\0'; i++)
  {
    if (number_range(1, 3) == 1)
      buf[i] = UPPER(buf[i]);
  }

  return buf;
}


void talk_channel( CHAR_DATA *ch, char *argument, int channel, int sub_channel, const char *verb )
{
  char buf[MAX_STRING_LENGTH];
  DESCRIPTOR_DATA *d;

  if (RTIMER(ch->in_room, RTIMER_SILENCE) != 0)
  {
    send_to_char("Something prevents you from speaking in this room.\n\r", ch);
    return;
  }
  if ( argument[0] == '\0' )
  {
    xprintf( buf, "%s what?\n\r", verb );
    buf[0] = UPPER(buf[0]);
    send_to_char(buf,ch);
    return;
  }
  if ( IS_HEAD(ch, LOST_TONGUE) )
  {
    xprintf( buf, "You can't %s without a tongue!\n\r", verb );
    send_to_char( buf, ch );
    return;
  }
  if ( IS_EXTRA(ch, GAGGED) )
  {
    xprintf( buf, "You can't %s with a gag on!\n\r", verb );
    send_to_char( buf, ch );
    return;
  }
  
  argument = drunktalk ( argument );

  REMOVE_BIT(ch->deaf, channel);
  switch ( channel )
  {
    default:
      if (ch->flag4 == 1)
      {
        xprintf( buf, "You whine '#1%s#n'.\n\r",  argument );
        send_to_char( buf, ch );
        xprintf( buf, "%s #Pwhines#n '#1$t#n'.",ch->name );
      }
      else if (channel == CHANNEL_FLAME)
      {
        xprintf( buf, "You %s '#G%s#n'.\n\r", verb, argument );
        send_to_char( buf, ch );
        xprintf( buf, "%s %ses '#G$t#n'.",ch->name, verb );
      }
      else if (channel == CHANNEL_CHAT)
      {
      	argument = pcolor ( ch, argument, 0 );
        xprintf( buf, "You %s '#W%s#n'.\n\r", verb, argument );
        send_to_char( buf, ch );
        if (ch->trust > 6)
          xprintf( buf, "#Y(#G*#Y)#C%s#Y(#G*#Y)#n '#1$t#n'.", ch->name);
        else if (IS_NPC(ch))
          xprintf( buf, "%s chats '#W$t#n'.", ch->short_descr);
        else if (IS_CLASS(ch, CLASS_WEREWOLF))
          xprintf( buf, "%s barks '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_MAGE))
          xprintf( buf, "%s chants '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_SHAPESHIFTER))
          xprintf( buf, "%s whispers '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_VAMPIRE))
          xprintf( buf, "%s snarls '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_DRONE))
          xprintf( buf, "%s drools '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_ANGEL))
          xprintf( buf, "%s preaches '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_TANARRI))
          xprintf( buf, "%s booms '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_LICH))
          xprintf( buf, "%s squicks '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_DEMON))
          xprintf( buf, "%s growls '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_CYBORG))
          xprintf( buf, "%s chitters '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_GIANT))
          xprintf( buf, "%s rumbles '#W$t#n'.",ch->name);
        else if (IS_CLASS(ch, CLASS_SKYBLADE))
          xprintf( buf, "%s hollars '#W$t#n'.",ch->name);
        else  
          xprintf( buf, "%s %ss '#W$t#n'.", ch->name, verb );
      }
      else
      {
        xprintf( buf, "You %s '#W%s#n'.\n\r", verb, argument );
        send_to_char( buf, ch );
        xprintf( buf, "%s %ss '#W$t#n'.",ch->name,     verb );
      }
      break;
    case CHANNEL_IMMTALK:
      xprintf( buf, "#Y.:#P%s#Y:.#C $t.#n",ch->name);
      act( buf, ch, argument, NULL, TO_CHAR );
      break;
    case CHANNEL_CLASS:
      switch(sub_channel)
      {
        case CC_ANGEL:
          xprintf( buf, "#0[#7%s#0]#C '$t'.#n",ch->name );
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_DEMON:
          xprintf( buf, "#0[#R%s#0]#C '$t'.#n",ch->name );
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_MAGE:
          xprintf( buf, "#n{{#0%s#n}}#C '$t'.#n",ch->name );
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_SHIFTER:
          xprintf( buf, "#G*#C(>#R%s#C<)#G* #C'$t'.#n",ch->name );
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_CYBORG:
          xprintf( buf, "#p{#0-#p}#0%s#p{#0-#p} #C'$t'.#n",ch->name);
          act( buf,ch,argument,NULL,TO_CHAR);
          break;
        case CC_WW:
          xprintf( buf, "#Y((#L%s#Y))#C '$t'.#n",ch->name );
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_NINJA:
          xprintf(buf, "#Y-*(#0%s#Y)*-#C '$t'.#n",ch->name );
          act(buf, ch, argument, NULL, TO_CHAR);
          break;
        case CC_SAMURAI:
          xprintf( buf, "#C-=#R%s#C=-  '$t'.#n",ch->name );
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_KNIGHT:
          xprintf( buf, "#0.x.#7%s#0.x.#C '$t'.#n",ch->name);
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_FAE:
          xprintf( buf, "#G>>#R(#Y%s#R)#G<<#C '$t'.#n",ch->name);
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_GIANT:
          xprintf( buf, "#G<:>#o%s#G<:>#C '$t'.#n",ch->name);
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_TANARRI:
          xprintf( buf, "#Y{#R%s#Y}#C '$t'.#n",ch->name);
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_LICH:
          xprintf( buf, "#G>*<#7%s#G>*<#C '$t'.#n",ch->name);
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_DRONE:
          xprintf( buf, "#G<#0=#Y{#0%s#Y}#0=#G> #C'$t'.#n", ch->name);
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_SKYBLADE:
          xprintf( buf, "#B=#R*#w>#0%s#w<#R*#B= #W'$t#W'.#n", ch->name);
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_DROW:
          xprintf( buf, "#P.o0#0%s#P0o.#C '$t'.#n",ch->name);
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_MONK:
          xprintf( buf, "#0.x[#l%s#0]x. #C '$t'.#n",ch->name );
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
        case CC_VAMPIRE:
          xprintf( buf, "#R<<#0%s#R>>#C $t.#n" , ch->name);
          act( buf, ch, argument, NULL, TO_CHAR );
          break;
      }
      break;      
    case CHANNEL_ROLEPLAY:
      xprintf( buf, "#o(#R%s#o) #n'#Y$t#n'.", ch->name);
      act( buf, ch, argument, NULL, TO_CHAR ); 
      break;
    case CHANNEL_RELIGION:
      xprintf( buf, religion_table[ch->pcdata->religion].channel, ch->name );
      act( buf, ch, argument, NULL, TO_CHAR );
      break;
  }

  /* silenced, and they don't know it :) */
  if (!IS_NPC(ch) && IS_SET(ch->act, PLR_SILENCE)) return;

  /* anti spamming */
  //if (!IS_NPC(ch) && (channel == CHANNEL_CHAT || channel == CHANNEL_NEWBIE))
  //{
  //  if (!str_cmp(ch->pcdata->last_global, argument)) return;
   // free_string(ch->pcdata->last_global);
   // ch->pcdata->last_global = str_dup(argument);
  //}

  for ( d = descriptor_list; d != NULL; d = d->next )
  {
    CHAR_DATA *gch;

    if (d->connected != CON_PLAYING) continue;
    if ((gch = d->character) == NULL) continue;
    if (gch == ch) continue;
    if (IS_SET(gch->deaf, channel)) continue;

    if (channel == CHANNEL_IMMTALK && !IS_IMMORTAL(gch)) continue;
    if (channel == CHANNEL_CLASS && !IS_IMMORTAL(gch) && (gch->class != ch->class || gch->level < 3))
      continue;
    if (channel == CHANNEL_RELIGION && !IS_IMMORTAL(gch) &&
      gch->pcdata->religion != ch->pcdata->religion) continue;
    if (channel == CHANNEL_YELL && gch->in_room && gch->in_room->area != ch->in_room->area)
      continue;

    if (!IS_NPC(gch) && !IS_NPC(ch))
    {
      bool ignore = FALSE;
      int i;
 
      for (i = 0; i < MAX_IGNORE; i++)
        if (gch->pcdata->ignore[i] == ch->pcdata->playerid) ignore = TRUE;
  
      if (ignore) continue;
    }

    act(buf, ch, argument, gch, TO_VICT);
  }
  return;  
}


HISTORY_DATA *generate_history()
{
  HISTORY_DATA *history_new;
  HISTORY_DATA *history_prev = NULL;
  int i;

  for (i = 0; i < MAX_HISTORY; i++)
  {
    if (history_free == NULL)
    {
      history_new = alloc_perm(sizeof(*history_new));
    }
    else
    {
      history_new  = history_free;
      history_free = history_free->next;
    }
    history_new->message = STRALLOC("");
    history_new->next = history_prev;
    history_prev = history_new;
  }
  return history_new;
}

void strip_history(CHAR_DATA *ch)
{
  HISTORY_DATA *pHistory;
  HISTORY_DATA *pHistory_next;

  for (pHistory = ch->pcdata->history; pHistory; pHistory = pHistory_next)
  {
    pHistory_next = pHistory->next;

    free_string(pHistory->message);
    pHistory->next = history_free;
    history_free = pHistory;    
  }
}

void do_history(CHAR_DATA *ch, char *argument)
{
  HISTORY_DATA *history;
  char buf[MAX_STRING_LENGTH];

  if (IS_NPC(ch)) return;

  for (history = ch->pcdata->history; history; history = history->next)
  {
    if (strlen(history->message) > 3)
    {
      xprintf(buf, " %s\n\r", history->message);
      send_to_char(buf, ch);
    }
  }
}

void update_history(CHAR_DATA *ch, CHAR_DATA *talker, char *buf, char *argument, bool tell)
{
  char message[MAX_STRING_LENGTH];
  char tbuf[MAX_STRING_LENGTH];
  char xbuf[MAX_STRING_LENGTH];
  int i = 0;

  if (IS_NPC(ch)) return;

  xprintf(xbuf, "%s", line_indent(strip_ansi(argument), 22, 80));

  if (!tell)
  {
    xprintf(tbuf, strip_ansi(buf));
    while (tbuf[i] != '\0' && tbuf[i] != ' ') i++;
    tbuf[i] = '\0';
    xprintf(message, "#C%-18s #0: #R%-s#n", tbuf, xbuf);
  }
  else
  {
    xprintf(message, "#0[#GT#0] #C%-14s #0: #R%-s#n", talker->name, xbuf);
  }

  attach_history(ch, message);
  return;
}

void attach_history(CHAR_DATA *ch, char *message)
{
  HISTORY_DATA *history;
  HISTORY_DATA *history_prev1 = NULL;
  HISTORY_DATA *history_prev2 = NULL;

  if (history_free == NULL)
  {
    history = alloc_perm(sizeof(*history));
  }
  else
  {
    history      = history_free;
    history_free = history_free->next;
  }
  history->message = str_dup(message);
  history->next = ch->pcdata->history;
  ch->pcdata->history = history;

  for (history = ch->pcdata->history; history; history = history->next)
  {
    if (history_prev1) history_prev2 = history_prev1;
    history_prev1 = history;
  }
  history_prev2->next = NULL;
  free_string(history_prev1->message);
  history_prev1->next = history_free;
  history_free = history_prev1;
}

/*
 * Will remove the last line in the current note,
 * if there is a note, and it has a line to remove.
 */
void delete_last_line_in_note(CHAR_DATA *ch)
{
  char buf[4 * MAX_STRING_LENGTH];
  char *ptr;
  bool found = FALSE;
  int nCount = 0;

  buf[0] = '\0';

  if (IS_NPC(ch)) return;
  if (ch->pcdata->in_progress->text == NULL)
  {
    send_to_char("No note to delete lines in.\n\r", ch);
    return;
  }
  if (strlen(ch->pcdata->in_progress->text) < 1)
  {
    send_to_char("Empty note, nothing to delete.\n\r", ch);
    return;
  }
  strcpy(buf, ch->pcdata->in_progress->text);
  ptr = buf;
  while (*ptr != '\0')
  {
    if (*ptr == '\n') nCount++;
    ptr++;
  }
  if (nCount == 1)
  {
    free_string(ch->pcdata->in_progress->text);
    ch->pcdata->in_progress->text = NULL;
    send_to_char("Entire note deleted.\n\r", ch);
    return;
  }
  else
  {
    while (*ptr != '\n' || !found)
    {
      if (*ptr == '\n') found = TRUE;
      ptr--;
    }
  }
  ptr++;
  *ptr = '\0';
  free_string(ch->pcdata->in_progress->text);
  ch->pcdata->in_progress->text = str_dup(buf);
  send_to_char("Line deleted.\n\r", ch);
}