SmaugWizard/Backup/
SmaugWizard/Backup/L/
SmaugWizard/Boards/
SmaugWizard/Building/
SmaugWizard/Corpses/
SmaugWizard/Councils/
SmaugWizard/Deity/
SmaugWizard/Gods/
SmaugWizard/MudProgs/
SmaugWizard/Player/L/
SmaugWizard/Src/
SmaugWizard/Src/res/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |				*
 * -----------------------------------------------------------|   \\._.//	*
 * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version)   |   (0...0)	*
 * -----------------------------------------------------------|    ).:.(	*
 * SMAUG (C) 1994, 1995, 1996 by Derek Snider                 |    {o o}	*
 * -----------------------------------------------------------|   / ' ' \	*
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |~'~.VxvxV.~'~*
 * Scryn, Swordbearer, Rennard, Tricops, and Gorog.           |				*
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe.    *
 ****************************************************************************/

#include	"stdafx.h"
#include	"smaug.h"
#include	"objects.h"
#include	"rooms.h"
#include	"editor.h"
#include	"SmaugWizDoc.h"
#include	"descriptor.h"
#include	"character.h"


void start_editing (CCharacter *ch, const char *data)
{
	CEditor		*edit;
	
	if (!ch->GetDesc ()) {
	   bug ("Fatal: start_editing: no desc");
	   return;
	}
	if (ch->GetSubstate () == SUB_RESTRICTED)
	   bug ("NOT GOOD: start_editing: ch->substate == SUB_RESTRICTED");

	set_char_color (AT_GREEN, ch);
	ch->SendText ("Begin entering your text now (/? = help /s = save /c = clear /l = list)\n\r");
	ch->SendText ("-----------------------------------------------------------------------\n\r> ");
	
	// if we're already editing something, stop it.
	ch->StopEditing ();

	edit = new CEditor;
	edit->Init (data);
	ch->SetEditor (edit);
	edit->Edit (*ch, "/l");				// show text at start
	ch->GetDesc ()->m_Connected = CON_EDITING;
}


void CEditor::Init (const char *data)
{
	int		size = 0;
	int		lpos = 0;
	int		lines = 0;
	char	c;

	if (! data) {
	    bug ("editor: data is NULL!\n\r");
		return;
	}

	for (;;) {  
		c = data [size++];
		if (c == '\0') {
			m_Buf [lines][lpos] = '\0';
			break;
		}
		else if (c == '\r');
		else if (c == '\n' || lpos > 78) {
			m_Buf [lines][lpos] = '\0';
			++lines;
			lpos = 0;
		}
		else m_Buf [lines][lpos++] = c;

		if (lines >= 49 || size > 4096) {
			m_Buf [lines][lpos] = '\0';
			break;
		}	   
	}
	if (lpos) then ++lines;		// if last line has no '\n', count it anyway

	m_Numlines = lines;
	m_Size = size;
	m_OnLine = lines;
}


// Simple but nice and handle line editor.			-Thoric
void CEditor::Edit (CCharacter &Ch, char *argument)
{
	char		cmd [MAX_INPUT_LENGTH];
	char		buf [MAX_INPUT_LENGTH];
	short		x, line, max_buf_lines;

	CDescriptor	&Ds = *Ch.GetDesc ();

	if (Ch.GetSubstate () <= SUB_PAUSE) {
		Ch.SendText ("You can't do that!\n\r");
		bug ("Edit_buffer: illegal Ch.substate (%d)", Ch.GetSubstate ());
		Ds.m_Connected = CON_PLAYING;
		return;
	}

	BOOL	bSave = FALSE;
	max_buf_lines = 24;

	if (Ch.GetSubstate () == SUB_MPROG_EDIT
	  || Ch.GetSubstate () == SUB_HELP_EDIT)
		max_buf_lines = 48;

	if (argument [0] == '/' || argument [0] == '\\') {
		one_argument (argument, cmd);
		if (! str_cmp (cmd+1, "?")) {
			Ch.SendText ("Editing commands\n\r----------------------------"
				"-----\n\r");
			Ch.SendText ("/l              list buffer\n\r");
			Ch.SendText ("/c              clear buffer\n\r");
			Ch.SendText ("/d [line]       delete line\n\r");
			Ch.SendText ("/g <line>       goto line\n\r");
			Ch.SendText ("/i <line>       insert line\n\r");
			Ch.SendText ("/r <old> <new>  global replace\n\r");
			Ch.SendText ("/a              abort editing\n\r");
			if (Ch.GetTrustLevel () > LEVEL_IMMORTAL)
				Ch.SendText ("/! <command>    execute command (do not "
					"use another editing command)\n\r");
			Ch.SendText ("/s              save buffer\n\r\n\r> ");
			return;
		}

		if (! str_cmp (cmd+1, "c")) {
			Clear ();
			Ch.SendText ("Buffer cleared.\n\r> ");
			return;
		}
		if (! str_cmp (cmd+1, "r")) {
			char	word1 [MAX_INPUT_LENGTH];
			char	word2 [MAX_INPUT_LENGTH];
			char	*sptr, *wptr, *lwptr;
			int		x, count, wordln, word2ln, lineln;

			sptr = one_argument (argument, word1);
			sptr = one_argument (sptr, word1);
			sptr = one_argument (sptr, word2);
			if (word1 [0] == '\0' || word2 [0] == '\0') {
				Ch.SendText ("Need word to replace, and replacement.\n\r> ");
				return;
			}
			if (strcmp (word1, word2) == 0) {
				Ch.SendText ("Done.\n\r> ");
				return;
			}
			count = 0;
			wordln = strlen (word1);
			word2ln = strlen (word2);
			Ch.SendTextf ("Replacing all occurrences of %s with %s...\n\r",
				word1, word2);

			for (x = m_OnLine; x < m_Numlines; x++) {
				lwptr = m_Buf [x];
				while ((wptr = strstr (lwptr, word1)) != NULL) {
					sptr = lwptr;
					lwptr = wptr + wordln;
					sprintf (buf, "%s%s", word2, wptr + wordln);
					lineln = wptr - m_Buf [x] - wordln;
					++count;
					if (strlen (buf) + lineln > 79) {
						lineln = UMAX (0, (79 - strlen (buf)));
						buf [lineln] = '\0';
						break;
					}
					else lineln = strlen (buf);

					buf [lineln] = '\0';
					strcpy (wptr, buf);
				}
			}
			Ch.SendTextf ("Found and replaced %d occurrence (s).\n\r> ",
				count);
			return;
		}

		if (! str_cmp (cmd+1, "i")) {
			if (m_Numlines >= max_buf_lines)
				Ch.SendText ("Buffer is full.\n\r> ");
			else {
				if (argument [2] == ' ')
					line = atoi (argument + 2) - 1;
				else
					line = m_OnLine;
				if (line < 0)
					line = m_OnLine;
				if (line < 0 || line > m_Numlines)
					Ch.SendText ("Out of range.\n\r> ");
				else {
					for (x = ++m_Numlines; x > line; x--)
						strcpy (m_Buf [x], m_Buf [x-1]);
					strcpy (m_Buf [line], "");
					Ch.SendText ("Line inserted.\n\r> ");
				}
			}
			return;
		}
		if (! str_cmp (cmd+1, "d")) {
			if (m_Numlines == 0)
				Ch.SendText ("Buffer is empty.\n\r> ");
			else {
				if (argument [2] == ' ')
					line = atoi (argument + 2) - 1;
				else
					line = m_OnLine;
				if (line < 0)
					line = m_OnLine;
				if (line < 0 || line > m_Numlines)
					Ch.SendText ("Out of range.\n\r> ");
				else {
					if (line == 0 && m_Numlines == 1) {
						Clear ();
						Ch.SendText ("Line deleted.\n\r> ");
						return;
					}
					for (x = line; x < (m_Numlines - 1); x++)
						strcpy (m_Buf [x], m_Buf [x+1]);
					strcpy (m_Buf [m_Numlines--], "");
					if (m_OnLine > m_Numlines)
						m_OnLine = m_Numlines;
					Ch.SendText ("Line deleted.\n\r> ");
				}
			}
			return;
		}

		if (! str_cmp (cmd+1, "g")) {
			if (m_Numlines == 0)
				Ch.SendText ("Buffer is empty.\n\r> ");
			else {
				if (argument [2] == ' ')
					line = atoi (argument + 2) - 1;
				else {
					Ch.SendText ("Goto what line?\n\r> ");
					return;
				}
				if (line < 0)
					line = m_OnLine;
				if (line < 0 || line > m_Numlines)
					Ch.SendText ("Out of range.\n\r> ");
				else {
					m_OnLine = line;
					Ch.SendTextf ("(On line %d)\n\r> ", line+1);
				}
			}
			return;
		}

		if (! str_cmp (cmd+1, "l")) {
			if (m_Numlines == 0)
				Ch.SendText ("Buffer is empty.\n\r> ");
			else {
				Ch.SendText ("------------------\n\r");
				for (x = 0; x < m_Numlines; x++)
					Ch.SendTextf ("%2d> %s\n\r", x+1, m_Buf [x]);
				Ch.SendText ("------------------\n\r> ");
			}
			return;
		}

		if (! str_cmp (cmd+1, "a")) {
			if (Ch.IsMenuActive ()) {
				Ch.ReturnToMenu (FALSE);
				return;
			}
			Ch.SendText ("\n\rAborting... ");
			StopEditing (Ch);
			return;
		}

		if (Ch.GetTrustLevel () > LEVEL_IMMORTAL && !str_cmp (cmd+1, "!")) {
			DO_FUN	*last_cmd;
			int		substate = Ch.GetSubstate ();

			last_cmd = Ch.last_cmd;
			Ch.SetSubstate (SUB_RESTRICTED);
			interpret (&Ch, argument+3);
			Ch.SetSubstate (substate);
			Ch.last_cmd = last_cmd;
			set_char_color (AT_GREEN, &Ch);
			Ch.SendText ("\n\r> ");
			return;
		}

		if (! str_cmp (cmd+1, "s")) {
			Ds.m_Connected = CON_PLAYING;
			if (Ch.IsMenuActive ()) {
				Ch.ReturnToMenu (TRUE);
				return;
			}
			if (Ch.last_cmd)
				(*Ch.last_cmd) (&Ch, "");
			return;
		}
	}

	if (m_Size + strlen (argument) + 1 >= MAX_STRING_LENGTH - 1)
		Ch.SendText ("Your buffer is full.\n\r");
	else {
		if (strlen (argument) > 79) {
			strncpy (buf, argument, 79);
			buf [79] = 0; 
			Ch.SendText ("(Long line trimmed)\n\r> ");
		}
		else strcpy (buf, argument);

		strcpy (m_Buf [m_OnLine++], buf);
		if (m_OnLine > m_Numlines)
			m_Numlines++;
		if (m_Numlines > max_buf_lines) {
			m_Numlines = max_buf_lines;
			Ch.SendText ("Buffer full.\n\r");
			bSave = TRUE;
		}
	}

	if (bSave) {
		Ds.m_Connected = CON_PLAYING;
			if (Ch.IsMenuActive ()) {
				Ch.ReturnToMenu (TRUE);
				return;
			}
		if (Ch.last_cmd)
			(*Ch.last_cmd) (&Ch, "");
		return;
	}
	Ch.SendText ("> ");
}


char *CEditor::CopyToBuffer ()
{
	char	buf [MAX_STRING_LENGTH];
	char	tmp [100];
	short	x, len;

	buf [0] = '\0';
	for (x = 0; x < m_Numlines; x++) {
		strcpy (tmp, m_Buf [x]);
		smush_tilde (tmp);
		len = strlen (tmp);
		if (len && tmp [len-1] == '~')
			tmp [len-1] = '\0';
		else
			strcat (tmp, "\r\n");
		strcat (buf, tmp);
	}
	return STRALLOC (buf);
}


void CEditor::StopEditing (CCharacter& Ch)
{
	set_char_color (AT_PLAIN, &Ch);
	Ch.SendText ("Done.\n\r");
	Ch.dest_buf = NULL;
	Ch.spare_ptr = NULL;
	Ch.SetSubstate (SUB_NONE);

	if (!Ch.GetDesc ())
		bug ("CEditor::StopEditing: no desc");
	else
		Ch.GetDesc ()->m_Connected = CON_PLAYING;

	Ch.SetEditor (NULL);
	delete this;
}