/****************************************************************************
* [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;
}