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.    *
 ****************************************************************************/
// Descriptor2.cpp

#include	"stdafx.h"
#include	"smaug.h"
#include	"SmaugSocket.h"
#include	"SysData.h"
#include	"objects.h"
#include	"rooms.h"
#include	"character.h"
#include	"descriptor.h"
#include	"Smaugx.h"

char *GetFightDamageString (CCharacter* ch);


void CDescriptor::DisplayPrompt ()
{
	CCharacter	*ch = m_pCharacter;
	ASSERT (ch);

	char		buf [MAX_STRING_LENGTH];
	CCharacter	*och = (m_pOriginal ? m_pOriginal : m_pCharacter);
	CCharacter	*victim = NULL;
	BOOL		ansi = (! och->IsNpc () && och->IsAnsi ());
	const char	*prompt;
	char		*pbuf = buf;
	int			stat;

	pc_data	&Pc = *ch->GetPcData ();

// 1.4add
//	if (! ch->IsNpc () && !IS_SET(ch->pcdata->flags, PCFLAG_HELPSTART))
//		prompt = helpstart;
//	else
	if (!ch->IsNpc () && ch->GetSubstate () != SUB_NONE && Pc.HasSubPrompt ())
		prompt = Pc.GetSubPrompt ();
	else if (ch->IsNpc () || (! ch->GetFightWho () && ! Pc.HasPrompt ()))
		prompt = default_prompt (ch);
	else if (ch->GetFightWho ()) {
		if (! Pc.HasFightPrompt ())
			prompt = default_prompt (ch);
		else
			prompt = Pc.GetFightPrompt ();
	}
	else prompt = Pc.GetPrompt ();

	if (ansi) {
		strcpy (pbuf, "\033[m");
		m_PrevColor = 0x07;
		pbuf += 3;
	}
	// Clear out old color stuff
	//  make_color_sequence (NULL, NULL, NULL);
	for (; *prompt; prompt++) {
		// '&' = foreground color/intensity bit
		// '^' = background color/blink bit
		// '%' = prompt commands
		// Note: foreground changes will revert background to 0 (black)
		if (*prompt != '&' && *prompt != '^' && *prompt != '%') {
			* (pbuf++) = *prompt;
			continue;
		}
		++prompt;
		if (!*prompt)
			break;
		if (*prompt == * (prompt-1)) {
			* (pbuf++) = *prompt;
			continue;
		}
		switch (* (prompt-1)) {
		  default:
			bug ("DisplayPrompt: bad command char '%c'.", * (prompt-1));
			break;
		  case '&':
		  case '^':
			stat = MakeColorSequence (&prompt [-1], pbuf, this);
			if (stat < 0)
				--prompt;
			else if (stat > 0)
				pbuf += stat;
			break;
		  case '%':
			*pbuf = '\0';
			stat = 0x80000000;
			switch (*prompt) {
			  case '%':
				*pbuf++ = '%';
				*pbuf = '\0';
				break;
			  case 'a':
				if (ch->GetLevel () >= 10)
					stat = ch->GetAlignment ();
				else if (ch->IsGood ())
					strcpy (pbuf, "good");
				else if (ch->IsEvil ())
					strcpy (pbuf, "evil");
				else strcpy (pbuf, "neutral");
				break;

			  case 'A':
				sprintf (pbuf, "%s%s%s", ch->IsInvis () ? "I" : "",
					ch->IsHidden () ? "H" : "", ch->IsSneaking () ? "S" : "");
				break;

			  case 'f':
				if (ch->GetPcData ()->deity)
					stat = ch->GetPcData ()->favor;
				else strcpy (pbuf, "no favor");
				break;

			  case 'F':
				if (ch->IsImmortal ())
					strcpy (pbuf,
						flag_string (ch->GetInRoom ()->GetRoomFlags (),
							r_flags));
				break;

			  case 'C':		// Tank
				if (ch->IsImmortal ()) {
					if (! (victim = ch->GetFightWho ()))
						strcpy (pbuf, "N/A");
					else if (! victim->GetFightWho ())
						strcpy (pbuf, "N/A");
					else
						strcpy (pbuf, GetFightDamageString (victim));
				}
				break;
			  case 'c':
				if (ch->IsImmortal ()) {
					if (! (victim = ch->GetFightWho ()))
						strcpy (pbuf, "N/A");
					else
						strcpy (pbuf, GetFightDamageString (victim));
				}
				break;

			  case 'h':
				stat = ch->GetHp ();
				break;
			  case 'H':
				stat = ch->GetMaxHp ();
				break;
			  case 'm':
				if (ch->IsVampire ())
					stat = 0;
				else stat = ch->GetMana ();
				break;
			  case 'M':
				if (ch->IsVampire ())
					stat = 0;
				else stat = ch->GetMaxMana ();
				break;
			  case 'N':		// Tank
				if (ch->IsImmortal ()) {
					if (! (victim = ch->GetFightWho ()))
						strcpy (pbuf, "N/A");
					else if (! victim->GetFightWho ())
						strcpy (pbuf, "N/A");
					else {
						if (ch == victim)
							strcpy (pbuf, "You");
						else if (victim->IsNpc ())
							strcpy (pbuf, victim->GetShortDescr ());
						else
							strcpy (pbuf, victim->GetName ());
						pbuf [0] = UPPER (pbuf [0]);
					}
				}
				break;
			  case 'n':
				if (ch->IsImmortal ()) {
					if (! (victim = ch->GetFightWho ()))
						strcpy (pbuf, "N/A");
					else {
						if (ch == victim)
							strcpy (pbuf, "You");
						else if (victim->IsNpc ())
							strcpy (pbuf, victim->GetShortDescr ());
						else
							strcpy (pbuf, victim->GetName ());
						pbuf [0] = UPPER (pbuf [0]);
					}
				}
				break;
			  case 'T':
				if (time_info.hour < 5)			strcpy (pbuf, "night");
				else if (time_info.hour < 6)	strcpy (pbuf, "dawn");
				else if (time_info.hour < 19)	strcpy (pbuf, "day");
				else if (time_info.hour < 21)	strcpy (pbuf, "dusk");
				else strcpy (pbuf, "night");
				break;
			  case 'b':
				if (ch->IsVampire ())
				stat = ch->GetPcData ()->condition [COND_BLOODTHIRST];
				else stat = 0;
				break;
			  case 'B':
				if (ch->IsVampire ())
					stat = ch->GetLevel () + 10;
				else stat = 0;
				break;
			  case 'u':
				stat = DList.GetCount ();
				break;
			  case 'U':
				stat = SysData.MaxPlayers;
				break;
			  case 'v':
				stat = ch->GetMove ();
				break;
			  case 'V':
				stat = ch->GetMaxMove ();
				break;
			  case 'g':
				stat = ch->GetGold ();
				break;
			  case 'r':
				if (och->IsImmortal ())
					stat = ch->GetInRoom ()->vnum;
				break;
			  case 'R':
				if (och->IsVnums ())
					sprintf (pbuf, "<#%d> ", ch->GetInRoom ()->vnum);
				break;
			  case 'x':
				stat = ch->GetExp ();
				break;
			  case 'X':
				stat = exp_level (ch, ch->GetLevel () + 1) - ch->GetExp ();
				break;
			  case 'S':
				if (ch->IsBeserkStyle ())			strcpy (pbuf, "B");
				else if (ch->IsAggressiveStyle ())	strcpy (pbuf, "A");
				else if (ch->IsFightingStyle ())	strcpy (pbuf, "D");
				else if (ch->IsEvasiveStyle ())		strcpy (pbuf, "E");
				else strcpy (pbuf, "S");
				break;
			  case 'i':
				if ((! ch->IsNpc () && ch->IsWizInvis ())
				  || (ch->IsNpc () && ch->IsMobInvis ()))
					sprintf (pbuf, "(Invis %d) ", ch->IsNpc () ?
						ch->GetMobInvisLevel () : ch->GetPcData ()->wizinvis);
				else if (ch->IsInvis ())
					sprintf (pbuf, "(Invis) ");
				break;
			  case 'I':
				stat = ch->IsNpc () ?
					 (ch->IsMobInvis () ? ch->GetMobInvisLevel () : 0)
				: (ch->IsWizInvis () ? ch->GetPcData ()->wizinvis : 0);
				break;
			}
			if (stat != 0x80000000)
				sprintf (pbuf, "%d", stat);
			pbuf += strlen (pbuf);
			break;
		}
	}
	*pbuf = '\0';
	WriteToBuffer (buf, (pbuf-buf));
}


char *GetFightDamageString (CCharacter* ch)
{
	int percent =
		ch->GetMaxHp () ? 100 * ch->GetHp () / ch->GetMaxHp () : -1;

	if (percent >= 100)
		return "perfect health";
	else if (percent >= 90)
		return "slightly scratched";
	else if (percent >= 80)
		return "few bruises";
	else if (percent >= 70)
		return "some cuts";
	else if (percent >= 60)
		return "several wounds";
	else if (percent >= 50)
		return "nasty wounds";
	else if (percent >= 40)
		return "bleeding freely";
	else if (percent >= 30)
		return "covered in blood";
	else if (percent >= 20)
		return "leaking guts";
	else if (percent >= 10)
		return "almost dead";

	return "DYING";
}


// Low level output function.
BOOL CDescriptor::ProcessOutput (BOOL fPrompt)
{
    char			buf [MAX_INPUT_LENGTH];
	extern BOOL		bSmaugDown;

	try {
		if (pagepoint)
			return PagerOutput ();

		// Bust a prompt.
		if (fPrompt && !bSmaugDown && m_Connected == CON_PLAYING
		  && ! m_bCloseSocket) {
			CCharacter	*ch;

			ch = m_pOriginal ? m_pOriginal : m_pCharacter;
			if (ch->IsBlank ())
				WriteToBuffer ("\n\r", 2);

			if (ch->HasPrompt ())
				DisplayPrompt ();

			if (ch->IsTelenet ())
				WriteToBuffer (go_ahead_str, 0);
		}

		// Short-circuit if nothing to write.
		if (m_Outtop == 0)
			return TRUE;

		// Snoop-o-rama.
		if (m_pSnoopBy) {
			// without check, 'force mortal quit' while snooped caused crash, -h
			if (m_pCharacter && m_pCharacter->GetName ()) {
				// Show original snooped names. -- Altrag
				if (m_pOriginal && m_pOriginal->GetName ())
					sprintf (buf, "%s (%s)", m_pCharacter->GetName (),
						m_pOriginal->GetName ());
				else sprintf (buf, "%s", m_pCharacter->GetName ());
				m_pSnoopBy->WriteToBuffer (buf, 0);
			}
			m_pSnoopBy->WriteToBuffer ("% ", 2);
			m_pSnoopBy->WriteToBuffer (m_pOutbuf, m_Outtop);
		}

		// Wake up Winsock, if necessary
		if (! m_pSocket->SelectReadWrite ()) {
			if (m_pCharacter != NULL)
				save_char_obj (m_pCharacter);
			m_Outtop = 0;
			RemoveCharacter (*this);
			return FALSE;
		}
	}
	catch (...) {
		int				siz = m_Outtop < 40 ? m_Outtop : 40;
		CSwException	ex;
		ex.SetChar (m_pCharacter);
		ex.Printf ("ProcessOutput:Exception for %s, on output %-*.*",
			m_pCharacter->GetName (), siz, siz, m_pOutbuf);
		m_Outtop = 0;
		m_Incomm [0] = 0;
		throw ex;
	}

	return TRUE;
}


void CDescriptor::GetPagerInput ()
{
	char	*ptr = m_Incomm;
	while (isspace (*ptr))
		++ptr;
	pagecmd = *ptr;
}


BOOL CDescriptor::PagerOutput ()
{
	ASSERT (this);
	char		*last;
	CCharacter	*ch;
	int			pclines;
	int			lines;
	BOOL		ret;

	if (! pagepoint || pagecmd == -1)
		return TRUE;
	ch = m_pOriginal ? m_pOriginal : m_pCharacter;
	pclines = UMAX (ch->GetPcData ()->pagerlen, 5) - 1;

	switch (LOWER (pagecmd)) {
	  default:
		lines = 0;
		break;
	  case 'b':
		lines = -1-(pclines*2);
		break;
	  case 'r':
		lines = -1-pclines;
		break;
	  case 'q':
		pagetop = 0;
		pagepoint = NULL;		// pagepoint must be NULL
		ProcessOutput (TRUE);	// to call ProcessOutput from here
		free (pagebuf);
		pagebuf = NULL;
		pagesize = MAX_STRING_LENGTH;
		return TRUE;
	}
	while (lines < 0 && pagepoint >= pagebuf)
		if (* (--pagepoint) == '\n')
			++lines;

	if (*pagepoint == '\n' && *(++pagepoint) == '\r')
		++pagepoint;

	if (pagepoint < pagebuf)
		pagepoint = pagebuf;

	for (lines = 0, last = pagepoint; lines < pclines; ++last)
		if (! *last)
			break;
		else if (*last == '\n')
			++lines;

	if (*last == '\r')
		++last;

	if (last != pagepoint) {
		if (! WriteToDescriptor (pagepoint, (last - pagepoint)))
			return FALSE;
		pagepoint = last;
	}

	while (isspace (*last))
		++last;

	if (! *last) {
		pagetop = 0;
		pagepoint = NULL;
		ProcessOutput (TRUE);
		free (pagebuf);
		pagebuf = NULL;
		pagesize = MAX_STRING_LENGTH;
		return TRUE;
	}

	pagecmd = -1;
	char	buf [32];
	int		len;
	int		PrevColor = m_PrevColor;	// save current color

	if (ch->IsAnsi ()) {
		len = MakeColorSequence (AT_CYAN, buf, this);
		if (! WriteToDescriptor (buf, len))
			return FALSE;
	}

	ret = WriteToDescriptor ("(C)ontinue, (R)efresh, (B)ack, (Q)uit: [C] ");

	if (ret) {
		if (ch->IsAnsi ()) {
			len = MakeColorSequence (PrevColor, buf, this);
			ret = WriteToDescriptor (buf, len);
		}
	}
	return ret;
}