/**************************************************************************** * [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. * * ------------------------------------------------------------------------ * * Smaug Menus Implementation file * ****************************************************************************/ #include "stdafx.h" #define MENUS_CPP #include "smaug.h" #include "SysData.h" #include "mobiles.h" #include "affect.h" #include "objects.h" #include "rooms.h" #include "menus.h" #include "descriptor.h" #include "character.h" void MenuStringEditReturn (CCharacter* ch, BOOL bDone); void CSmaugMenu::DisplayData (CCharacter& Ch) { CMenuFnData MfData; if (m_pPageData) { for (int i=0; i < m_nDataItems; ++i) { CMenuData &Md = m_pPageData [i]; void *addr = m_Base [Md.Base] + Md.Offset; int len = Md.Len; switch (Md.Type) { case MT_INT: Ch.SendColorf ("\x1b[%d;%dH&p%-*d", Md.y, Md.x, len, *(int*) addr); break; case MT_SINT: Ch.SendColorf ("\x1b[%d;%dH&p%-+*d ", Md.y, Md.x, len, *(int*) addr); break; case MT_BOOL: { BOOL b = *(BOOL*) addr; Md.SetCheck (Ch, b, TRUE); // TRUE for soft color } break; case MT_GROUP: MfData.pMd = &Md; MfData.Base = addr; MfData.ch = &Ch; HandleBooleanGroup (MfData, TRUE); // TRUE for display break; case MT_RIS: Ch.SendColorf ("\x1b[%d;%dH&p%-*.*s", Md.y, Md.x, len, len, addr); break; case MT_CSTRING: if (Md.MenuFn) { MfData.Op = MF_DISP; MfData.pMd = &Md; MfData.Base = m_Base [Md.Base]; MfData.ch = &Ch; Md.MenuFn (MfData); } else { CString &s = *(CString*) addr; Ch.SendColorf ("\x1b[%d;%dH&p%-*.*s", Md.y, Md.x, len, len, NCCP s); } break; case MT_STRING: Ch.SendColorf ("\x1b[%d;%dH&p%-*.*s", Md.y, Md.x, len, len, *(char**) addr); } } } Ch.SendTextf ("\x1b[%d;1H", m_CurrPageLines + 1); } BOOL CSmaugMenu::Edit (CCharacter& Ch, char* arg, const char* cmd) { CMenuFnData MfData; char arg1 [MAX_STRING_LENGTH]; if (! stricmp (cmd, "Unlock")) { Ch.LockMenus (FALSE); ClearToEnd (Ch); Ch.SendText ("OK"); return TRUE; } if (! stricmp (cmd, "Lock")) { Ch.LockMenus (TRUE); ClearToEnd (Ch); Ch.SendText ("OK"); return TRUE; } else if (! stricmp (cmd, "pagelen")) { Ch.SetMenuPagelen (max (15, atoi (arg))); ClearToEnd (Ch); Ch.SendTextf ("Page length set to %d.", Ch.GetMenuPagelen ()); return TRUE; } if (m_pPageData) { for (int i=0; i < m_nDataItems; ++i) { CMenuData &Md = m_pPageData [i]; // IF 1st char matches && 2nd CHAR MATCHES... if (Md.Section == cmd [0]) { // just check the 1st char if (Md.Choice == arg [0]) { BOOL bClearToEnd = TRUE; void *addr = m_Base [Md.Base] + Md.Offset; int len = Md.Len; arg = one_argument (arg, arg1); switch (Md.Type) { case MT_INT: { int &i = *(int*) addr; i = atoi (arg); Ch.SendColorf ("\x1b[%d;%dH&P%-*d", Md.y, Md.x, len, i); } break; case MT_SINT: { int &i = *(int*) addr; i = atoi (arg); Ch.SendColorf ("\x1b[%d;%dH&P%-+*d ", Md.y, Md.x, len, i); } break; case MT_BOOL: { BOOL &b = *(BOOL*) addr; b ^= 1; // toggling Md.SetCheck (Ch, b); } break; case MT_GROUP: MfData.pMd = &Md; MfData.Base = addr; MfData.ch = &Ch; HandleBooleanGroup (MfData, FALSE); // FALSE for set break; case MT_RIS: { int i; char *ptr = (char*) addr; char c = toupper (arg [0]); if (c == 'R') then i = 0; else if (c == 'I') then i = 1; else if (c == 'S') then i = 2; else return FALSE; if (c == ptr [i]) then c = '.'; ptr [i] = c; Ch.SendColorf ("\x1b[%d;%dH&P%c", Md.y, Md.x + i, c); } break; case MT_STRING: Ch.SendColorf ("\x1b[%d;%dH&P%-*.*s", Md.y, Md.x, len, len, arg); break; case MT_CSTRING: if (Md.MenuFn) { MfData.Op = MF_EDIT; MfData.pMd = &Md; MfData.Base = m_Base [Md.Base]; MfData.ch = &Ch; MfData.pArg = arg; bClearToEnd = Md.MenuFn (MfData); } else { CString &s = *(CString*) addr; s = arg; Ch.SendColorf ("\x1b[%d;%dH&P%-*.*s%s", Md.y, Md.x, len, len, arg, s.GetLength () > len ? "..." : " "); } break; } if (bClearToEnd) then ClearToEnd (Ch); return TRUE; } } } } if (Ch.AreMenusLocked ()) { ClearToEnd (Ch); Ch.SendTextf ("Invalid Menu Command: %s", cmd); return TRUE; } return FALSE; } void CSmaugMenu::ClearToEnd (CCharacter& Ch) { int nLines = 4; if (Ch.GetMenuPagelen () > (m_CurrPageLines + 4)) nLines = Ch.GetMenuPagelen () - m_CurrPageLines; for (int n=1; n <= nLines; ++n) Ch.SendTextf ("\x1b[%d;1H\x1b[K", m_CurrPageLines + n); Ch.SendTextf ("\x1b[%d;1H", m_CurrPageLines + 1); } int GetLineCount (const char* str) { int Count = 0; while (*str) if (*str++ == '\n') then ++Count; return Count; } int GetItemCount (CMenuData* pMd) { int Count = 0; while (pMd [Count].Type != MT_END) ++Count; return Count + 1; } int GetAffect (CAffectList& AList, int apply) { int total = 0; POSITION pos = AList.GetHeadPosition (); while (pos) { CAffectData *aff = AList.GetNext (pos); if (aff->location == apply) { total += aff->modifier; } } return total; } BOOL GetAffected (CAffectList& AList, int bit) { POSITION pos = AList.GetHeadPosition (); while (pos) { CAffectData &Af = *AList.GetNext (pos); if (Af.location == APPLY_AFFECT && IS_SET (Af.modifier, 1 << bit)) return TRUE; } return FALSE; } void SetRisString (char* str, CAffectList& AList, int bit) { strcpy (str, "..."); POSITION pos = AList.GetHeadPosition (); while (pos) { CAffectData *aff = AList.GetNext (pos); if (aff->location >= APPLY_RESISTANT && aff->location <= APPLY_SUSCEPTIBLE) { if (IS_SET (aff->modifier, bit)) switch (aff->location) { case APPLY_RESISTANT: str [0] = 'R'; break; case APPLY_IMMUNE: str [1] = 'I'; break; case APPLY_SUSCEPTIBLE: str [2] = 'S'; break; } } } } void SetAffect (CAffectList& AList, int apply, int value) { CAffectData *aff = new CAffectData; aff->location = apply; aff->modifier = value; AList.AddTail (aff); } CAffectData *CAffectList::GetAffect (int loc) { POSITION apos = GetHeadPosition (); while (apos) { CAffectData *aff = GetNext (apos); if (aff->location == loc) then return aff; } return NULL; } CString GetNextString (CString& Str, int len, BOOL bLast); BOOL MenuStringEditFn (CMenuFnData& Fd) { if (Fd.Op == MF_DISP) then return MenuStringFn (Fd); CMenuData &Md = *Fd.pMd; if (Md.Type != MT_CSTRING) then return TRUE; CString &s = *(CString*) ((char*) Fd.Base + Md.Offset); CCharacter &Ch = *Fd.ch; Ch.tempnum = SUB_NONE; Ch.SetSubstate (SUB_ROOM_DESC); // have to have something here Ch.dest_buf = NULL; Ch.GetMenu ().m_pRetFun = MenuStringEditReturn; Ch.GetMenu ().m_pRetData = &s; Ch.SendText ("\x1b[2J"); // clear page & home cursor start_editing (&Ch, s); return FALSE; // FALSE means don't clear rest of screen } void MenuStringEditReturn (CCharacter* ch, BOOL bDone) { CSmaugMenu &Menu = ch->GetMenu (); if (bDone) { CString &s = *(CString*) Menu.m_pRetData; char *ptr = ch->GetEditBuffer (); s = ptr; STRFREE (ptr); } ch->StopEditing (); Menu.Display (*ch, Menu.m_PageNr); } BOOL MenuStringFn (CMenuFnData& Fd) { CMenuData &Md = *Fd.pMd; CCharacter &Ch = *Fd.ch; if (Md.Type != MT_CSTRING) then return FALSE; CString &s = *(CString*) ((char*) Fd.Base + Md.Offset); if (Fd.Op == MF_EDIT) s = Fd.pArg; CString Str = s; Ch.StartColorStack (); set_char_color (Fd.Op == MF_EDIT ? AT_PINK : AT_PURPLE, &Ch); for (int n=0; n <= Md.Xlines; ++n) { BOOL bFirst = n == 0; int len = bFirst ? Md.Len : Md.Xlen; CString OutStr = GetNextString (Str, len, n == Md.Xlines); Ch.SendColorf ("\x1b[%d;%dH%-*.*s", Md.y + n, bFirst ? Md.x : Md.Xcol, len, len, OutStr); } Ch.EndColorStack (); return TRUE; } BOOL HandleBooleanGroup (CMenuFnData& Fd, BOOL bDisplay) { CMenuData *pMd = Fd.pMd; CCharacter &Ch = *Fd.ch; UINT nCur = pMd [0].Xlines; UINT nGroup = pMd [0].Xcol; UINT &val = *(UINT*) Fd.Base; if (bDisplay) pMd [0].SetCheck (Ch, nCur == (int) val, bDisplay); // Make sure we have valid indexes (just skip it if not). else if (val < nGroup && nCur < nGroup) { // Set the pointer to the first MenuData item in the group pMd -= nCur; pMd [val].SetCheck (Ch, FALSE); // Turn off the old check val = nCur; // Update the value pMd [val].SetCheck (Ch, TRUE); // Turn on the new check } return FALSE; } void CMenuData::SetCheck (CCharacter& Ch, BOOL bSet, BOOL bDisplay /* = FALSE */) { // bSet indicates to set or unset the check. // bDisplay indicates to use soft color. Ch.SendColorf ("\x1b[%d;%dH&%c%c", y, x, bDisplay ? 'p' : 'P', bSet ? 'X' : ' '); } CString GetNextString (CString& Str, int len, BOOL bLast) { CString Line; if (len > 0) { char *ptr = NCCP Str; int i; for (i=0; *ptr; ++i, ++ptr) if (*ptr == '\r' || *ptr == '\n') then break; int npos = *ptr ? i : 0; int nlen; // Get length of eol for (nlen=0; *ptr && (*ptr == '\r' || *ptr == '\n'); ++nlen) ++ptr; if (npos && npos <= len) { int LineLen = npos; if (bLast && *ptr) then LineLen = min (npos, len-3); Line = Str.Left (LineLen); if (bLast && *ptr) then Line += "..."; Str = Str.Mid (npos + nlen); } else if (npos && npos > len) { Line = Str.Left (bLast ? len-3 : len); if (bLast) then Line += "..."; else Str = Str.Mid (len); } else if (Str.GetLength () > len) { Line = Str.Left (bLast ? len-3 : len); if (bLast) then Line += "..."; else Str = Str.Mid (len); } else { Line = Str; Str.Empty (); } } return Line; } void do_pagelen (CCharacter* ch, char* argument) { char buf [MAX_STRING_LENGTH]; char arg [MAX_INPUT_LENGTH]; int lines; one_argument (argument, arg); if (arg [0] == '\0') lines = 24; else lines = atoi (arg); if (lines < 1) { ch->SendText ("Negative or Zero values for a page length is not legal.\n\r"); return; } ch->SetMenuPagelen (lines); sprintf (buf, "Page length set to %d lines.\n\r", lines); ch->SendText (buf); }