/****************************************************************************
* [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. *
****************************************************************************/
// character.cpp
#include "stdafx.h"
#include "smaug.h"
#include "language.h"
#include "skill.h"
#include "mobiles.h"
#include "objects.h"
#include "rooms.h"
#include "deity.h"
#include "area.h"
#include "menus.h"
#include "editor.h"
#include "races.h"
#include "class.h"
#include "descriptor.h"
#include "character.h"
#include "sysdata.h"
#include "SmaugFiles.h"
#include "Exits.h"
pc_data::~pc_data ()
{
STRFREE (m_pClanName);
STRFREE (m_pCouncilName);
delete m_pPassWord;
delete m_pBamfin;
delete m_pBamfout;
delete m_pRank;
STRFREE (m_pTitle);
STRFREE (bio);
delete m_pBestowments;
delete m_pHomepage;
STRFREE (authed_by);
STRFREE (m_Prompt);
STRFREE (m_Fprompt);
STRFREE (m_Subprompt);
STRFREE (helled_by);
STRFREE (m_pDeityName);
}
// Clear a new character.
void CCharacter::InitChar ()
{
Empty ();
SetLogonTime (CurrentTime);
SetArmor (100);
SetPosition (POS_STANDING);
SetHp (20);
SetMaxHp (20);
SetMana (100);
SetMaxMana (100);
SetMove (100);
SetMaxMove (100);
m_Height = 72;
m_Weight = 180;
SetClass (NPC_WARRIOR);
SetSpeaking (LanguageTable.GetCommon ());
SetSpeaks (LanguageTable.GetCommon ());
barenumdie = 1;
baresizedie = 4;
perm_str = 13;
perm_dex = 13;
perm_int = 13;
perm_wis = 13;
perm_cha = 13;
perm_con = 13;
perm_lck = 13;
}
int CCharacter::GetManaCost (int sn)
{
return IsNpc () ? 0 : UMAX (SkillTable.GetMinMana (sn),
100 / (2 + m_Level - SkillTable.GetClassLevel (sn, m_Class)));
}
// Retrieve a character's trusted level for permission checking.
int CCharacter::GetTrustLevel ()
{
CCharacter *ch = this;
if (m_pDesc && m_pDesc->m_pOriginal) then
ch = m_pDesc->m_pOriginal;
if (ch->GetTrust ()) then return ch->GetTrust ();
if (ch->IsNpc () && ch->GetLevel () >= LEVEL_AVATAR) then
return LEVEL_AVATAR;
if (ch->GetLevel () >= LEVEL_NEOPHYTE && ch->IsRetired ())
return LEVEL_NEOPHYTE;
return ch->GetLevel ();
}
// Retrieve a character's age.
int CCharacter::GetAge ()
{
return 17 + (m_Played + (CurrentTime - m_LogTime).GetTotalSeconds ()) / 7200;
// 12240 assumes 30 second hours, 24 hours a day, 20 day - Kahn
}
// Retrieve character's current strength.
int CCharacter::GetCurrentStrength ()
{
short max;
if (IsNpc () || ClassTable.GetAttrPrime (m_Class) == APPLY_STR) then
max = 25;
else
max = 20;
return URANGE (3, perm_str + mod_str, max);
}
// Retrieve character's current intelligence.
int CCharacter::GetIntelligence ()
{
short max;
if (IsNpc () || ClassTable.GetAttrPrime (m_Class) == APPLY_INT) then
max = 25;
else max = 20;
return URANGE (3, perm_int + mod_int, max);
}
// Retrieve character's current wisdom.
int CCharacter::GetWisdom ()
{
short max;
if (IsNpc () || ClassTable.GetAttrPrime (m_Class) == APPLY_WIS) then
max = 25;
else max = 22;
return URANGE (3, perm_wis + mod_wis, max);
}
// Retrieve character's current dexterity.
int CCharacter::GetDexterity ()
{
short max;
if (IsNpc () || ClassTable.GetAttrPrime (m_Class) == APPLY_DEX) then
max = 25;
else max = 22;
return URANGE (3, perm_dex + mod_dex, max);
}
// Retrieve character's current constitution.
int CCharacter::GetConstitution ()
{
short max;
if (IsNpc () || ClassTable.GetAttrPrime (m_Class) == APPLY_CON) then
max = 25;
else max = 22;
return URANGE (3, perm_con + mod_con, max);
}
// Retrieve a character's item carrying capacity.
// Vastly reduced (finally) due to containers -Thoric
int CCharacter::GetMaxItems ()
{
int penalty = 0;
if (! IsNpc () && GetLevel () >= LEVEL_IMMORTAL)
return GetTrustLevel () * 200;
if (IsNpc () && IsPet ())
return 0;
if (get_eq_char (this, WEAR_WIELD))
++penalty;
if (get_eq_char (this, WEAR_DUAL_WIELD))
++penalty;
if (get_eq_char (this, WEAR_MISSILE_WIELD))
++penalty;
if (get_eq_char (this, WEAR_HOLD))
++penalty;
if (get_eq_char (this, WEAR_SHIELD))
++penalty;
return URANGE (5, (m_Level + 15) / 5 +
GetDexterity () - 13 - penalty, 20);
}
// Move a char out of a room.
void CCharacter::RemoveFromRoom ()
{
CObjData *obj;
if (! GetInRoom ()) {
bug ("RemoveFromRoom: NULL room.");
return;
}
if (! IsNpc ()) then --m_pInRoom->GetArea ()->nplayer;
if ((obj = get_eq_char (this, WEAR_LIGHT)) != NULL
&& obj->item_type == ITEM_LIGHT
&& obj->value [2] != 0
&& m_pInRoom->light > 0)
--m_pInRoom->light;
GetInRoom ()->UnLinkPerson (this);
SetInRoom (NULL);
SetNextInRoom (NULL);
SetPrevInRoom (NULL);
if (! IsNpc () && get_timer (this, TIMER_SHOVEDRAG) > 0)
remove_timer (this, TIMER_SHOVEDRAG);
}
// Move a char into a room.
void CCharacter::SendToRoom (CRoomIndexData *pRoom)
{
CObjData *obj;
if (! pRoom) {
bug ("CCharacter::SendToRoom: %s -> NULL room! Putting char in limbo (%d)",
GetName (), SysData.m_RoomLimbo);
// This used to just return, but there was a problem with crashing
// and I saw no reason not to just put the char in limbo. -Narn
pRoom = RoomTable.GetRoom (SysData.m_RoomLimbo);
}
SetInRoom (pRoom);
pRoom->LinkPerson (this);
if (! IsNpc ()) {
CAreaData &Area = *pRoom->GetArea ();
if (++Area.nplayer > Area.max_players)
Area.max_players = Area.nplayer;
}
if ((obj = get_eq_char (this, WEAR_LIGHT)) != NULL
&& obj->item_type == ITEM_LIGHT
&& obj->value [2] != 0)
++pRoom->light;
if (! IsNpc ()
&& pRoom->IsSafe () && get_timer (this, TIMER_SHOVEDRAG) <= 0)
add_timer (this, TIMER_SHOVEDRAG, 10, NULL, 0); // -30 Seconds-
// Delayed Teleport rooms -Thoric
// Should be the last thing checked in this function
if (pRoom->IsTeleport () && pRoom->tele_delay > 0) {
CTeleportData *tele;
for (tele = first_teleport; tele; tele = tele->GetNext ())
if (tele->room == pRoom)
return;
tele = new CTeleportData;
LINK (tele, first_teleport, last_teleport);
tele->room = pRoom;
tele->timer = pRoom->tele_delay;
}
}
void CCharacter::StopIdling ()
{
ASSERT (this);
SetTimer (0);
if (GetConnectStatus () != CON_PLAYING
|| m_pWasInRoom == NULL
|| GetInRoom () != RoomTable.GetRoom (SysData.m_RoomLimbo))
return;
RemoveFromRoom ();
SendToRoom (m_pWasInRoom);
m_pWasInRoom = NULL;
act (AT_ACTION, "$n has returned from the void.", this, NULL, NULL, TO_ROOM);
}
//void ch_printf (CCharacter *ch, char *fmt, ...)
void CCharacter::SendTextf (char *fmt, ...)
{
char buf [MAX_STRING_LENGTH*2]; // better safe than sorry
va_list args;
va_start (args, fmt);
vsprintf (buf, fmt, args);
va_end (args);
SendText (buf);
}
void CCharacter::SendText (const char *txt)
{
ASSERT (this);
if (txt == NULL || GetDesc () == NULL)
return;
if (HasColor (txt))
SendColor (txt);
else
GetDesc ()->WriteToBuffer (txt);
}
void CCharacter::SendColorf (char *fmt, ...)
{
char buf [MAX_STRING_LENGTH*2]; // better safe than sorry
va_list args;
va_start (args, fmt);
vsprintf (buf, fmt, args);
va_end (args);
SendColor (buf);
}
bool IsPushColor (const char*& col);
bool IsPopColor (const char*& col);
// Same as above, but converts &color codes to ANSI sequences..
void CCharacter::SendColor (const char *txt)
{
ASSERT (this);
CDescriptor *d = GetDesc ();
const char *colstr;
const char *prevstr = txt;
char colbuf [32];
int len;
if (! txt || ! d)
return;
BOOL bWasStackingColors = IsStackColors ();
if (! bWasStackingColors)
StartColorStack ();
while ((colstr = strpbrk (prevstr, "&^"))) {
len = colstr - prevstr;
if (len > 0)
d->WriteToBuffer (prevstr, len);
if (IsPopColor (colstr)) {
if (! m_ColorStack.IsEmpty ()) {
UCHAR Prev = (UCHAR) m_ColorStack.RemoveTail ();
len = MakeColorSequence (Prev, colbuf, d);
if (len)
d->WriteToBuffer (colbuf, len);
}
prevstr = colstr;
continue;
}
else if (IsPushColor (colstr)) {
m_ColorStack.AddTail ((void*) d->m_PrevColor);
prevstr = colstr;
continue;
}
else
len = MakeColorSequence (colstr, colbuf, d);
if (len > sizeof (colbuf)) {
bug ("BIGBUG!: SendColor: Buffer overflow! (%d)", len);
return;
}
if (len < 0) {
prevstr = colstr+1;
break;
}
if (len)
d->WriteToBuffer (colbuf, len);
prevstr = colstr + 2;
}
if (*prevstr)
d->WriteToBuffer (prevstr);
// If we were already stacking colors then leave the stack intact.
if (! bWasStackingColors) {
if (! m_ColorStack.IsEmpty ()) {
UCHAR Prev = (UCHAR) m_ColorStack.RemoveTail ();
len = MakeColorSequence (Prev, colbuf, d);
if (len)
d->WriteToBuffer (colbuf, len);
}
EndColorStack ();
}
}
bool IsPushColor (const char*& col)
{
if (col [0] == '&' && col [1] == '[') {
col += 2;
return TRUE;
}
return FALSE;
}
bool IsPopColor (const char*& col)
{
if (col [0] == '&' && col [1] == ']') {
col += 2;
return TRUE;
}
return FALSE;
}
void CCharacter::PageColorf (char *fmt, ...)
{
char buf [MAX_STRING_LENGTH*2]; // better safe than sorry
va_list args;
va_start (args, fmt);
vsprintf (buf, fmt, args);
va_end (args);
PageColor (buf);
}
void CCharacter::PageColor (const char *txt)
{
const char *colstr;
const char *prevstr = txt;
char colbuf [20];
int ln;
CPtrList List;
CDescriptor &Ds = *GetDesc ();
if (!txt || !&Ds)
return;
CCharacter *ch = Ds.m_pOriginal ? Ds.m_pOriginal : Ds.m_pCharacter;
if (ch->IsNpc () || ! ch->IsPagerOn ()) {
Ds.m_pCharacter->SendColor (txt);
return;
}
// Clear out old color stuff
// make_color_sequence (NULL, NULL, NULL);
while ((colstr = strpbrk (prevstr, "&^")) != NULL) {
if (colstr > prevstr)
write_to_pager (&Ds, prevstr, (colstr - prevstr));
if (IsPopColor (colstr)) {
if (! List.IsEmpty ()) {
UCHAR Prev = (UCHAR) List.RemoveTail ();
ln = MakeColorSequence (Prev, colbuf, &Ds);
if (ln)
Ds.WriteToBuffer (colbuf, ln);
}
prevstr = colstr;
continue;
}
else if (IsPushColor (colstr)) {
List.AddTail ((void*) Ds.m_PrevColor);
prevstr = colstr;
continue;
}
else
ln = MakeColorSequence (colstr, colbuf, &Ds);
if (ln > sizeof (colbuf)) {
bug ("BIGBUG!: send_to_pager_color: Buffer overflow! (%d)", ln);
return;
}
if (ln < 0) {
prevstr = colstr+1;
break;
}
if (ln)
write_to_pager (&Ds, colbuf, ln);
prevstr = colstr+2;
}
if (*prevstr)
write_to_pager (&Ds, prevstr, 0);
if (! List.IsEmpty ()) {
UCHAR Prev = (UCHAR) List.RemoveTail ();
ln = MakeColorSequence (Prev, colbuf, &Ds);
if (ln)
Ds.WriteToBuffer (colbuf, ln);
}
List.RemoveAll ();
}
BOOL CCharacter::CheckSubrestricted ()
{
if (GetSubstate () == SUB_RESTRICTED) {
SendText (
"You cannot use this command from within another command.\n\r");
return TRUE;
}
return FALSE;
}
// Read in a char.
#if defined (KEY)
#undef KEY
#endif
#define KEY(literal,field,value) \
if (!str_cmp (word, literal)) { \
field = value; \
fMatch = TRUE; \
break; \
}
#define KEY2(literal, field, value) \
if (!str_cmp (word, literal)) { \
field (value); \
fMatch = TRUE; \
break; \
}
extern int file_ver; // in save.cpp (move to CCharacterTable class when
// that class is coded).
BOOL CCharacter::Read (FILE *fp, BOOL bPreload)
{
char buf [MAX_STRING_LENGTH];
char *word;
int x1, x2, x3, x4, x5, x6, x7;
short killcnt = 0;
BOOL fMatch;
char *pLine;
file_ver = 0;
pc_data &Pc = *GetPcData ();
for (;;) {
fMatch = FALSE;
if (! feof (fp)) {
pLine = fread_line (fp);
word = ParseWord (pLine);
}
else word = "End";
switch (UPPER (word [0])) {
case '*':
fMatch = TRUE;
break;
case 'A':
if (! str_cmp (word, "Act")) {
m_ActionBits.Parse (pLine);
fMatch = TRUE;
break;
}
if (! str_cmp (word, "AffectedBy")) {
m_AffectBits.Parse (pLine);
fMatch = TRUE;
break;
}
KEY2 ("Alignment", SetAlignment, ParseNumber (pLine));
KEY2 ("Armor", SetArmor, ParseNumber (pLine));
if (!str_cmp (word, "Affect") || !str_cmp (word, "AffectData")) {
CAffectData *paf;
if (bPreload) {
fMatch = TRUE;
break;
}
paf = new CAffectData;
if (! str_cmp (word, "Affect")) {
paf->type = ParseNumber (pLine);
} else {
int sn;
char *sname = ParseWord (pLine);
if ((sn = SkillTable.Lookup (sname)) < 0) {
if ((sn = HerbTable.Lookup (sname)) < 0)
bug ("CCharacter::Read: unknown skill: %s", sname);
else
sn += TYPE_HERB;
}
paf->type = sn;
}
paf->duration = ParseNumber (pLine);
paf->modifier = ParseNumber (pLine);
paf->location = ParseNumber (pLine);
// 1.4add
if (paf->location == APPLY_WEAPONSPELL
|| paf->location == APPLY_WEARSPELL
|| paf->location == APPLY_REMOVESPELL
|| paf->location == APPLY_STRIPSN
|| paf->location == APPLY_RECURRINGSPELL)
paf->modifier = slot_lookup (paf->modifier);
paf->SetVector (ParseWord (pLine));
m_AffectList.AddTail (paf);
fMatch = TRUE;
break;
}
if (! str_cmp (word, "AttrMod" )) {
x1 = x2 = x3 = x4 = x5 = x6 = x7 = 13;
sscanf (pLine, "%d %d %d %d %d %d %d", &x1, &x2, &x3, &x4,
&x5, &x6, &x7);
mod_str = x1;
mod_int = x2;
mod_wis = x3;
mod_dex = x4;
mod_con = x5;
mod_cha = x6;
mod_lck = x7;
fMatch = TRUE;
break;
}
if (!str_cmp (word, "AttrPerm")) {
x1 = x2 = x3 = x4 = x5 = x6 = x7 = 0;
sscanf (pLine, "%d %d %d %d %d %d %d", &x1, &x2, &x3, &x4,
&x5, &x6, &x7);
perm_str = x1;
perm_int = x2;
perm_wis = x3;
perm_dex = x4;
perm_con = x5;
perm_cha = x6;
perm_lck = x7;
if (!x7)
perm_lck = 13;
fMatch = TRUE;
break;
}
KEY ("AuthedBy", Pc.authed_by, ParseString (pLine, fp));
break;
case 'B':
KEY2("Bamfin", Pc.SetBamfin, ParseStringNohash (pLine, fp));
KEY2("Bamfout", Pc.SetBamfout, ParseStringNohash (pLine, fp));
KEY ("Bestowments", Pc.m_pBestowments, ParseStringNohash (pLine, fp));
KEY ("Bio", Pc.bio, ParseString (pLine, fp));
break;
case 'C':
if (! str_cmp (word, "Clan")) {
Pc.SetClanName (ParseString (pLine, fp));
Pc.SetClan (ClanList.Find (Pc.GetClanName (), CLAN_ALL));
if (! bPreload && Pc.HasClanName () && ! Pc.GetClan ()) {
SendTextf ("Warning: the organization %s no longer "
"exists, and therefore you no longer\n\rbelong to "
"that organization.\n\r", Pc.GetClanName ());
STRFREE (Pc.GetClanName ());
Pc.SetClanName (STRALLOC (""));
}
fMatch = TRUE;
break;
}
if (! str_cmp (word, "Class")) {
if (! bPreload) {
int c = ClassTable.GetClass (ParseCString (pLine, fp));
if (ClassTable.IsValidClass (c))
SetClass (c);
else
SetConnectError (CE_BADCLASS);
}
fMatch = TRUE;
break;
}
if (! str_cmp (word, "Condition")) {
sscanf (pLine, "%d %d %d %d", &x1, &x2, &x3, &x4);
Pc.condition [0] = x1;
Pc.condition [1] = x2;
Pc.condition [2] = x3;
Pc.condition [3] = x4;
fMatch = TRUE;
break;
}
if (! str_cmp (word, "Council")) {
Pc.SetCouncilName (ParseString (pLine, fp));
if (! bPreload && Pc.HasCouncilName () && (Pc.council =
get_council (Pc.GetCouncilName ())) == NULL) {
SendTextf ("Warning: the council %s no longer exists,"
" and herefore you no longer\n\r"
"belong to a council.\n\r", Pc.GetCouncilName ());
STRFREE (Pc.GetCouncilName ());
Pc.SetCouncilName (STRALLOC (""));
}
fMatch = TRUE;
break;
}
break;
case 'D':
KEY2 ("Damroll", SetDamroll, ParseNumber (pLine));
KEY ("Deaf", deaf, ParseNumber (pLine));
if (! str_cmp (word, "Deity")) {
Pc.SetDeityName (ParseString (pLine, fp));
if (! bPreload && Pc.HasDeityName () && (Pc.deity =
get_deity (Pc.GetDeityName ())) == NULL) {
SendTextf ("Warning: the deity %s no longer "
"exists.\n\r", Pc.GetDeityName ());
STRFREE (Pc.GetDeityName ());
Pc.SetDeityName (STRALLOC (""));
Pc.favor = 0;
}
fMatch = TRUE;
break;
}
KEY2("Description", SetDescription, ParseCString (pLine, fp));
break;
case 'E':
if (! stricmp (word, "End")) {
ValidateLoad ();
return TRUE;
}
KEY2("Exp", SetExp, ParseNumber (pLine));
break;
case 'F':
KEY ("Favor", Pc.favor, ParseNumber (pLine));
KEY ("Flags", Pc.m_flags, ParseNumber (pLine));
KEY ("FPrompt", Pc.m_Fprompt, ParseString (pLine, fp));
break;
case 'G':
KEY ("Glory", Pc.quest_curr, ParseNumber (pLine));
KEY2("Gold", SetGold, ParseNumber (pLine));
// temporary measure
if (!str_cmp (word, "Guild")) {
Pc.SetClanName (ParseString (pLine, fp));
Pc.SetClan (ClanList.Find (Pc.GetClanName (), CLAN_ALL));
if (! bPreload && Pc.HasClanName () && ! Pc.GetClan ()) {
SendTextf ("Warning: the organization %s no longer "
"exists, and therefore you no longer\n\rbelong "
"to that organization.\n\r", Pc.GetClanName ());
STRFREE (Pc.GetClanName ());
Pc.SetClanName (STRALLOC (""));
}
fMatch = TRUE;
break;
}
break;
case 'H':
KEY ("Height", m_Height, ParseNumber (pLine));
if (!str_cmp (word, "Helled")) {
Pc.release_date = CTime (ParseNumber (pLine));
Pc.helled_by = ParseString (pLine, fp);
if (Pc.release_date < CurrentTime) {
STRFREE (Pc.helled_by);
Pc.helled_by = NULL;
Pc.release_date = CTime (0);
}
fMatch = TRUE;
break;
}
KEY2("Hitroll", SetHitroll, ParseNumber (pLine));
KEY2("Homepage", Pc.SetHomepage, ParseStringNohash (pLine, fp));
if (!str_cmp (word, "HpManaMove")) {
SetHp (ParseNumber (pLine));
SetMaxHp (ParseNumber (pLine));
SetMana (ParseNumber (pLine));
SetMaxMana (ParseNumber (pLine));
SetMove (ParseNumber (pLine));
SetMaxMove (ParseNumber (pLine));
fMatch = TRUE;
break;
}
break;
case 'I':
// 1.4add - read ignored list here
if (! strcmp (word, "Ignored")) {
CString Name = ParseCString (pLine, fp);
// If there's a pfile for the name then add it to the list
if (FileTable.Exists (FileTable.PlayerName (Name)))
Pc.m_IgnoreList.AddTail (Name);
fMatch = TRUE;
break;
}
KEY ("IllegalPK", Pc.illegal_pk, ParseNumber (pLine));
KEY ("IMC", Pc.imc_def, ParseNumber (pLine));
KEY ("IMCAllow", Pc.imc_allow, ParseNumber (pLine));
KEY ("IMCDeny", Pc.imc_deny, ParseNumber (pLine));
KEY ("ICEListen", Pc.ice_listen, ParseStringNohash (pLine, fp));
KEY ("Immune", m_Immune, ParseNumber (pLine));
break;
case 'K':
if (!str_cmp (word, "Killed")) {
fMatch = TRUE;
if (killcnt >= MAX_KILLTRACK)
bug ("CCharacter::Read: killcnt (%d) >= MAX_KILLTRACK",
killcnt);
else {
Pc.killed [killcnt].vnum = ParseNumber (pLine);
Pc.killed [killcnt++].count = ParseNumber (pLine);
}
}
break;
case 'L':
KEY2("Level", SetLevel, ParseNumber (pLine));
KEY2("LongDescr", SetLongDescr, ParseCString (pLine, fp));
break;
case 'M':
KEY ("MDeaths", Pc.mdeaths, ParseNumber (pLine));
KEY2("Mentalstate", SetMentalState, ParseNumber (pLine));
KEY ("MGlory", Pc.quest_accum, ParseNumber (pLine));
KEY ("Minsnoop", Pc.min_snoop, ParseNumber (pLine));
KEY ("MKills", Pc.mkills, ParseNumber (pLine));
KEY ("Mobinvis", m_MobInvis, ParseNumber (pLine));
if (!str_cmp (word, "MobRange")) {
Pc.m_range_lo = ParseNumber (pLine);
Pc.m_range_hi = ParseNumber (pLine);
fMatch = TRUE;
}
break;
case 'N':
if (! str_cmp (word, "Name")) {
// Name already set externally.
fMatch = TRUE;
break;
}
if (! str_cmp (word, "NoAffectedBy")) {
m_NoAffectBits.Parse (pLine);
fMatch = TRUE;
break;
}
KEY ("NoImmune", m_NoImmune, ParseNumber (pLine));
KEY ("NoResistant", m_NoResist, ParseNumber (pLine));
KEY ("NoSusceptible", m_NoSuscept, ParseNumber (pLine));
break;
case 'O':
KEY ("Outcast_time", Pc.outcast_time, ParseNumber (pLine));
if (!str_cmp (word, "ObjRange")) {
Pc.o_range_lo = ParseNumber (pLine);
Pc.o_range_hi = ParseNumber (pLine);
fMatch = TRUE;
}
break;
case 'P':
KEY ("Pagerlen", Pc.pagerlen, ParseNumber (pLine));
KEY2("Password", Pc.SetPassWord, ParseStringNohash (pLine, fp));
KEY ("PDeaths", Pc.pdeaths, ParseNumber (pLine));
KEY ("PKills", Pc.pkills, ParseNumber (pLine));
KEY2("Played", SetPlayed, ParseNumber (pLine));
KEY2("Position", SetPosition, ParseNumber (pLine));
KEY2("Practice", SetPractices, ParseNumber (pLine));
KEY ("Prompt", Pc.m_Prompt, ParseString (pLine, fp));
if (!str_cmp (word, "PTimer")) {
add_timer (this, TIMER_PKILLED, ParseNumber (pLine), NULL, 0);
fMatch = TRUE;
break;
}
break;
case 'R':
if (! str_cmp (word, "Race")) {
if (! bPreload) {
int r = RaceTable.GetRace (ParseCString (pLine, fp));
if (RaceTable.IsValidRace (r))
SetRace (r);
else
SetConnectError (CE_BADRACE);
}
fMatch = TRUE;
break;
}
KEY2("Rank", Pc.SetRank, ParseStringNohash (pLine, fp));
KEY ("Resistant", m_Resist, ParseNumber (pLine));
KEY ("Restore_time",Pc.restore_time, CTime (ParseNumber (pLine)));
if (!str_cmp (word, "Room")) {
SetInRoom (RoomTable.GetRoom (ParseNumber (pLine)));
if (!GetInRoom ())
SetInRoom (RoomTable.GetRoom (SysData.m_RoomLimbo));
fMatch = TRUE;
break;
}
if (!str_cmp (word, "RoomRange")) {
Pc.r_range_lo = ParseNumber (pLine);
Pc.r_range_hi = ParseNumber (pLine);
fMatch = TRUE;
}
break;
case 'S':
KEY2("Sex", SetSex, ParseNumber (pLine));
KEY2("ShortDescr", SetShortDescr, ParseCString (pLine, fp));
KEY ("Style", m_Style, ParseNumber (pLine));
KEY ("Susceptible", m_Suscept, ParseNumber (pLine));
if (! str_cmp (word, "SavingThrow")) {
saving_wand = ParseNumber (pLine);
saving_poison_death = saving_wand;
saving_para_petri = saving_wand;
saving_breath = saving_wand;
saving_spell_staff = saving_wand;
fMatch = TRUE;
break;
}
if (! str_cmp (word, "SavingThrows")) {
saving_poison_death = ParseNumber (pLine);
saving_wand = ParseNumber (pLine);
saving_para_petri = ParseNumber (pLine);
saving_breath = ParseNumber (pLine);
saving_spell_staff = ParseNumber (pLine);
fMatch = TRUE;
break;
}
if (! str_cmp (word, "Site")) {
if (bPreload) {
ValidateLoad ();
return TRUE;
}
SendTextf ("Last connected from: %s\n\r", ParseLine (pLine));
fMatch = TRUE;
break;
}
if (! str_cmp (word, "Speaking")) {
m_Speaking = LanguageTable.GetLanguage (ParseWord (pLine));
fMatch = TRUE;
}
if (! str_cmp (word, "Skill")) {
if (bPreload) {
ValidateLoad ();
return TRUE;
}
int sn;
int value;
value = ParseNumber (pLine);
sn = SkillTable.BsearchExact (ParseWord (pLine),
gsn_first_skill, gsn_first_weapon-1);
if (sn < 0)
bug ("CCharacter::Read: unknown skill: %s", word);
else {
Pc.learned [sn] = value;
// Take care of people who have stuff they shouldn't
// Assumes class and level were loaded before. Altrag *
// Assumes practices are loaded first too now. Altrag */
if (GetLevel () < LEVEL_IMMORTAL) {
if (SkillTable.GetClassLevel (sn, m_Class)
>= LEVEL_IMMORTAL) {
Pc.learned [sn] = 0;
AddPractices (1);
}
}
}
fMatch = TRUE;
break;
}
if (! str_cmp (word, "Spell")) {
if (bPreload) {
ValidateLoad ();
return TRUE;
}
int sn;
int value;
value = ParseNumber (pLine);
sn = SkillTable.BsearchExact (ParseWord (pLine),
gsn_first_spell, gsn_first_skill-1);
if (sn < 0)
bug ("CCharacter::Read: unknown spell: %s", word);
else {
Pc.learned [sn] = value;
if (GetLevel () < LEVEL_IMMORTAL)
if (SkillTable.GetClassLevel (sn,
m_Class) >= LEVEL_IMMORTAL) {
Pc.learned [sn] = 0;
AddPractices (1);
}
}
fMatch = TRUE;
break;
}
break;
case 'T':
if (! stricmp (word, "Tongue")) {
if (IsMortal ()) {
int value = ParseNumber (pLine);
int sn = SkillTable.BsearchExact (ParseWord (pLine),
gsn_first_tongue, gsn_top_sn-1);
if (sn < 0)
bug ("CCharacter::Read: unknown tongue: %s", word);
else {
if (SkillTable.GetClassLevel (sn, GetClass ()) >=
LEVEL_IMMORTAL) {
Pc.learned [sn] = 0;
AddPractices (1);
} else {
Pc.learned [sn] = value;
SetSpeaks (LanguageTable.GetLanguage (word));
}
}
}
fMatch = TRUE;
break;
}
KEY2("Trust", SetTrust, ParseNumber (pLine));
// Let no character be trusted higher than
// one below maxlevel -- Narn
SetTrust (UMIN (GetTrust (), MAX_LEVEL - 1));
if (! str_cmp (word, "Title")) {
Pc.SetTitle (ParseString (pLine, fp));
if (isalpha (Pc.GetTitle () [0])
|| isdigit (Pc.GetTitle () [0])) {
sprintf (buf, " %s", Pc.GetTitle ());
if (Pc.GetTitle ())
STRFREE (Pc.GetTitle ());
Pc.SetTitle (STRALLOC (buf));
}
fMatch = TRUE;
break;
}
break;
case 'V':
if (! stricmp (word, "Version")) {
file_ver = ParseNumber (pLine);
if (file_ver != GetCurrentVersion ()) {
bug ("Incompatible Player File: %s, Version %d "
"(%d required)", GetName (), file_ver,
GetCurrentVersion ());
return FALSE;
}
fMatch = TRUE;
break;
}
if (!str_cmp (word, "Vnum")) {
SetMobIndex (MobTable.GetMob (ParseNumber (pLine)));
fMatch = TRUE;
break;
}
break;
case 'W':
KEY ("Weight", m_Weight, ParseNumber (pLine));
if (! str_cmp (word, "Weapon")) {
if (bPreload) {
ValidateLoad ();
return TRUE;
}
int sn;
int value;
value = ParseNumber (pLine);
sn = SkillTable.BsearchExact (ParseWord (pLine),
gsn_first_weapon, gsn_first_tongue-1);
if (sn < 0)
bug ("CCharacter::Read: unknown weapon: %s", word);
else {
Pc.learned [sn] = value;
if (GetLevel () < LEVEL_IMMORTAL)
if (SkillTable.GetClassLevel (sn,
GetClass ()) >= LEVEL_IMMORTAL) {
Pc.learned [sn] = 0;
AddPractices (1);
}
}
fMatch = TRUE;
break;
}
KEY2("Wimpy", SetWimpLevel, ParseNumber (pLine));
KEY ("WizInvis", Pc.wizinvis, ParseNumber (pLine));
break;
}
if (! fMatch)
bug ("CCharacter::Read: %s, no match: %s", GetName (), word);
if (file_ver == 0) {
bug ("CCharacter::Read: %s, Incompatible Player file, no Version.",
GetName ());
break;
}
}
return FALSE; // will never get here but VC++ likes to see a return!
}
void CCharacter::ValidateLoad ()
{
pc_data &Pc = *GetPcData ();
if (!GetShortDescr ())
SetShortDescr ("");
if (!GetLongDescr ())
SetLongDescr ("");
if (!GetDescription ())
SetDescription ("");
if (!Pc.GetPassWord ())
Pc.SetPassWord (str_dup (""));
if (!Pc.GetBamfin ())
Pc.SetBamfin (str_dup (""));
if (!Pc.GetBamfout ())
Pc.SetBamfout (str_dup (""));
if (!Pc.bio)
Pc.bio = STRALLOC ("");
if (!Pc.GetRank ())
Pc.SetRank (str_dup (""));
if (!Pc.GetBestowments ())
Pc.SetBestowments (str_dup (""));
if (!Pc.GetTitle ())
Pc.SetTitle (STRALLOC (""));
if (!Pc.GetHomepage ())
Pc.SetHomepage (str_dup (""));
if (!Pc.authed_by)
Pc.authed_by = STRALLOC ("");
if (!Pc.m_Prompt)
Pc.m_Prompt = STRALLOC ("");
if (!Pc.m_Fprompt)
Pc.m_Fprompt = STRALLOC ("");
m_pEditor = NULL;
int killcnt = URANGE (2, ((GetLevel ()+3) * MAX_KILLTRACK)/LEVEL_AVATAR,
MAX_KILLTRACK);
if (killcnt < MAX_KILLTRACK)
Pc.killed [killcnt].vnum = 0;
if (! m_Speaking)
SetSpeaking (LanguageTable.GetCommon ());
if (IsImmortal ())
SetSpeaks (LANG_ALL);
else if (m_Speaks.IsEmpty ()) {
SetSpeaksFlags (RaceTable.GetLanguages (GetRace ()));
SetSpeaks (LanguageTable.GetCommon ());
}
// 1.4add
// ch->pcdata->tell_history = new char* [26];
// for (i = 0; i < 26; i++)
// ch->pcdata->tell_history [i] = NULL;
// this disallows chars from being 6', 180lbs, but easier
// than a flag
CRaceData &Ra = *RaceTable.GetRaceData (GetRace ());
if (! m_Height || m_Height == 72)
m_Height = number_range ((int)(Ra.GetHeight () * .9),
(int)(Ra.GetHeight () * 1.1));
if (! m_Weight || m_Weight == 180)
m_Weight = number_range ((int)(Ra.GetWeight () * .9),
(int)(Ra.GetWeight () * 1.1));
}
void CCharacter::ReadMob (FILE* fp)
{
char *pLine;
char *word;
BOOL fMatch;
for (;;) {
fMatch = FALSE;
if (! feof (fp)) {
pLine = fread_line (fp);
word = ParseWord (pLine);
}
else word = "EndMobile";
switch (UPPER (word [0])) {
case '*':
fMatch = TRUE;
break;
case '#':
if (! strcmp (word, "#OBJECT"))
fread_obj (this, fp, OS_CARRY);
break;
case 'D':
KEY2("Description", SetDescription, ParseCString (pLine, fp));
break;
case 'E':
if (! strcmp (word, "EndMobile"))
return;
break;
case 'F':
if (! str_cmp (word, "Flags")) {
m_ActionBits.Parse (pLine);
fMatch = TRUE;
break;
}
case 'L':
KEY2("LongDescr", SetLongDescr, ParseCString (pLine, fp));
break;
case 'N':
KEY2("Name", SetName, ParseCString (pLine, fp));
break;
case 'P':
KEY2("Position", SetPosition, ParseNumber (pLine));
break;
case 'R':
KEY ("Room", tempnum, ParseNumber (pLine));
break;
case 'S':
KEY2("ShortDescr", SetShortDescr, ParseCString (pLine, fp));
break;
}
if (! fMatch)
bug ( "ReadMob: no match: %s", word);
}
}
// Write the char.
void CCharacter::Write (FILE *fp)
{
CAffectData *paf;
int sn, track;
CSkill *skill = NULL;
if (IsNpc ()) {
WriteMob (fp);
return;
}
fprintf (fp, "#PLAYER\n");
fprintf (fp, "Version %d SmaugWiz V2\n\n",
GetCurrentVersion ());
fprintf (fp, "Name %s~\n", GetName ());
if (HasShortDescription ())
fprintf (fp, "ShortDescr %s~\n", GetShortDescr ());
if (HasLongDescription ())
fprintf (fp, "LongDescr %s~\n", GetLongDescr ());
if (HasDescription ())
fprintf (fp, "Description %s~\n", GetDescription ());
fprintf (fp, "Sex %d\n", GetSex ());
fprintf (fp, "Class %s~\n", ClassTable.GetName (GetClass ()));
fprintf (fp, "Race %s~\n", RaceTable.GetName (GetRace ()));
fprintf (fp, "Level %d\n", GetLevel ());
fprintf (fp, "Speaking '%s'\n",
NCCP LanguageTable.GetName (m_Speaking));
fprintf (fp, "Played %d\n",
GetPlayed () + (CurrentTime - GetLogonTime ()).GetTotalSeconds ());
fprintf (fp, "Room %d\n",
(GetInRoom () == RoomTable.GetRoom (SysData.m_RoomLimbo)
&& GetWasInRoom ()) ? GetWasInRoom ()->vnum : GetInRoom ()->vnum);
fprintf (fp, "HpManaMove %d %d %d %d %d %d\n",
GetHp (), GetMaxHp (), GetMana (), GetMaxMana (), GetMove (),
GetMaxMove ());
fprintf (fp, "Gold %d\n", GetGold ());
fprintf (fp, "Exp %d\n", GetExp ());
fprintf (fp, "Height %d\n", GetHeight ());
fprintf (fp, "Weight %d\n", GetWeight ());
if (! GetActFlags ().IsEmpty ())
fprintf (fp, "Act %s\n", NCCP GetActFlags ().PrintVector ());
if (! GetAffectFlags ().IsEmpty ())
fprintf (fp, "AffectedBy %s\n", NCCP GetAffectFlags ().PrintVector ());
if (! GetNoAffectFlags ().IsEmpty ())
fprintf (fp, "NoAffectedBy %s\n", NCCP GetNoAffectFlags ().PrintVector ());
fprintf (fp, "Position %d\n",
IsFightPosition () ? POS_STANDING : GetPosition ());
fprintf (fp, "Style %d\n", GetStyle ());
fprintf (fp, "Practice %d\n", GetPractices ());
fprintf (fp, "SavingThrows %d %d %d %d %d\n", saving_poison_death,
saving_wand, saving_para_petri, saving_breath, saving_spell_staff);
fprintf (fp, "Alignment %d\n", GetAlignment ());
fprintf (fp, "Hitroll %d\n", GetHitroll ());
fprintf (fp, "Damroll %d\n", GetDamroll ());
fprintf (fp, "Armor %d\n", GetArmor ());
if (IsWimpy ())
fprintf (fp, "Wimpy %d\n", GetWimpLevel ());
if (deaf)
fprintf (fp, "Deaf %d\n", deaf);
if (m_Resist)
fprintf (fp, "Resistant %d\n", m_Resist);
if (m_NoResist)
fprintf (fp, "NoResistant %d\n", m_NoResist);
if (m_Immune)
fprintf (fp, "Immune %d\n", m_Immune);
if (m_NoImmune)
fprintf (fp, "NoImmune %d\n", m_NoImmune);
if (m_Suscept)
fprintf (fp, "Susceptible %d\n", m_Suscept);
if (m_NoSuscept)
fprintf (fp, "NoSusceptible %d\n", m_NoSuscept);
if (GetMentalState ())
fprintf (fp, "Mentalstate %d\n", GetMentalState ());
if (IsNpc ()) {
fprintf (fp, "Vnum %d\n", GetMobIndex ()->vnum);
fprintf (fp, "Mobinvis %d\n", m_MobInvis);
} else {
pc_data &Pc = *m_pPcdata;
fprintf (fp, "Password %s~\n", Pc.GetPassWord ());
if (Pc.HasRank ())
fprintf (fp, "Rank %s~\n", Pc.GetRank ());
if (Pc.HasBestowments ())
fprintf (fp, "Bestowments %s~\n", Pc.GetBestowments ());
fprintf (fp, "Title %s~\n", Pc.GetTitle ());
fprintf (fp, "Favor %d\n", Pc.favor);
if (Pc.quest_curr)
fprintf (fp, "Glory %d\n", Pc.quest_curr);
if (Pc.quest_accum)
fprintf (fp, "MGlory %d\n", Pc.quest_accum);
if (Pc.HasHomepage ())
fprintf (fp, "Homepage %s~\n", Pc.GetHomepage ());
if (Pc.imc_def)
fprintf (fp, "IMC %d\n", Pc.imc_def);
if (Pc.imc_allow)
fprintf (fp, "IMCAllow %d\n", Pc.imc_allow);
if (Pc.imc_deny)
fprintf (fp, "IMCDeny %d\n", Pc.imc_deny);
fprintf (fp, "ICEListen %s~\n", Pc.ice_listen);
if (Pc.HasBio ())
fprintf (fp, "Bio %s~\n", Pc.bio);
if (Pc.HasAuthedBy ())
fprintf (fp, "AuthedBy %s~\n", Pc.authed_by);
if (Pc.min_snoop)
fprintf (fp, "Minsnoop %d\n", Pc.min_snoop);
if (Pc.HasPrompt ())
fprintf (fp, "Prompt %s~\n", Pc.m_Prompt);
if (Pc.HasFightPrompt ())
fprintf (fp, "FPrompt %s~\n", Pc.m_Fprompt);
if (Pc.pagerlen)
fprintf (fp, "Pagerlen %d\n", Pc.pagerlen);
// 1.4add
// If ch is ignoring players then store those players
POSITION pos = Pc.m_IgnoreList.GetHeadPosition ();
while (pos)
fprintf (fp, "Ignored %s~\n",
NCCP Pc.m_IgnoreList.GetNext (pos));
if (IsImmortal ()) {
if (Pc.HasBamfin ())
fprintf (fp, "Bamfin %s~\n", Pc.GetBamfin ());
if (Pc.HasBamfout ())
fprintf (fp, "Bamfout %s~\n", Pc.GetBamfout ());
if (GetTrust ())
fprintf (fp, "Trust %d\n", GetTrust ());
if (! Pc.restore_time.IsZero ())
fprintf (fp, "Restore_time %d\n",
Pc.restore_time.GetCtime ());
fprintf (fp, "WizInvis %d\n", Pc.wizinvis);
if (Pc.r_range_lo && Pc.r_range_hi)
fprintf (fp, "RoomRange %d %d\n", Pc.r_range_lo,
Pc.r_range_hi);
if (Pc.o_range_lo && Pc.o_range_hi)
fprintf (fp, "ObjRange %d %d\n", Pc.o_range_lo,
Pc.o_range_hi);
if (Pc.m_range_lo && Pc.m_range_hi)
fprintf (fp, "MobRange %d %d\n", Pc.m_range_lo,
Pc.m_range_hi);
}
if (Pc.HasCouncilName ())
fprintf (fp, "Council %s~\n", Pc.GetCouncilName ());
if (Pc.HasDeityName ())
fprintf (fp, "Deity %s~\n", Pc.GetDeityName ());
if (Pc.HasClanName ())
fprintf (fp, "Clan %s~\n", Pc.GetClanName ());
fprintf (fp, "Flags %d\n", Pc.m_flags);
if (Pc.release_date > CurrentTime)
fprintf (fp, "Helled %d %s~\n",
Pc.release_date.GetCtime (), Pc.helled_by);
if (Pc.pkills)
fprintf (fp, "PKills %d\n", Pc.pkills);
if (Pc.pdeaths)
fprintf (fp, "PDeaths %d\n", Pc.pdeaths);
if (get_timer (this, TIMER_PKILLED)
&& (get_timer (this, TIMER_PKILLED) > 0))
fprintf (fp, "PTimer %d\n", get_timer (this, TIMER_PKILLED));
fprintf (fp, "MKills %d\n", Pc.mkills);
fprintf (fp, "MDeaths %d\n", Pc.mdeaths);
if (Pc.illegal_pk)
fprintf (fp, "IllegalPK %d\n", Pc.illegal_pk);
fprintf (fp, "AttrPerm %d %d %d %d %d %d %d\n", perm_str,
perm_int, perm_wis, perm_dex, perm_con, perm_cha, perm_lck);
fprintf (fp, "AttrMod %d %d %d %d %d %d %d\n", mod_str,
mod_int, mod_wis, mod_dex, mod_con, mod_cha, mod_lck);
if (Pc.outcast_time)
fprintf (fp, "Outcast_time %ld\n", Pc.outcast_time);
fprintf (fp, "Condition %d %d %d %d\n", Pc.condition [0],
Pc.condition [1], Pc.condition [2], Pc.condition [3]);
if (GetDesc () && GetDesc ()->IsHost ())
fprintf (fp, "Site %s\n", GetDesc ()->m_pHost);
else
fprintf (fp, "Site (Link-Dead)\n");
for (sn = 1; sn < SkillTable.GetCount (); sn++) {
if (SkillTable.GetName (sn) && Pc.learned [sn] > 0)
switch (SkillTable.GetType (sn)) {
default:
fprintf (fp, "Skill %d '%s'\n",
Pc.learned [sn], SkillTable.GetName (sn));
break;
case SKILL_SPELL:
fprintf (fp, "Spell %d '%s'\n",
Pc.learned [sn], SkillTable.GetName (sn));
break;
case SKILL_WEAPON:
fprintf (fp, "Weapon %d '%s'\n",
Pc.learned [sn], SkillTable.GetName (sn));
break;
case SKILL_TONGUE:
if (IsMortal ())
fprintf (fp, "Tongue %d '%s'\n",
Pc.learned [sn], SkillTable.GetName (sn));
break;
}
}
}
POSITION pos = m_AffectList.GetHeadPosition ();
while (pos) {
paf = m_AffectList.GetNext (pos);
if (paf->type >= 0
&& (skill = SkillTable.GetValidSkill (paf->type)) == NULL)
continue;
if (paf->type >= 0 && paf->type < TYPE_PERSONAL)
fprintf (fp, "AffectData '%s' %3d %3d %3d '%s'\n",
skill->GetName (), paf->duration, paf->modifier,
paf->location, paf->GetVectorName ());
else
fprintf (fp, "Affect %3d %3d %3d %3d '%s'\n",
paf->type, paf->duration, paf->modifier, paf->location,
paf->GetVectorName ());
}
track = URANGE (2,
((GetLevel ()+3) * MAX_KILLTRACK)/LEVEL_AVATAR, MAX_KILLTRACK);
for (sn = 0; sn < track; sn++) {
if (m_pPcdata->killed[sn].vnum == 0)
break;
fprintf (fp, "Killed %d %d\n", m_pPcdata->killed [sn].vnum,
m_pPcdata->killed [sn].count);
}
fprintf (fp, "End\n\n");
}
void CCharacter::WriteMob (FILE *fp)
{
fprintf (fp, "#MOBILE\n");
fprintf (fp, "Vnum %d\n", m_pIndexData->vnum );
if (GetInRoom ())
fprintf (fp, "Room %d\n",
(GetInRoom () == RoomTable.GetRoom (SysData.m_RoomLimbo)
&& GetWasInRoom ()) ? GetWasInRoom ()->vnum : GetInRoom ()->vnum);
if (QUICKMATCH (GetName (), m_pIndexData->GetPlayerName ()) == 0)
fprintf (fp, "Name %s~\n", GetName ());
if (QUICKMATCH (GetShortDescr (), m_pIndexData->GetShortDescr ()) == 0)
fprintf (fp, "Short %s~\n", GetShortDescr ());
if (QUICKMATCH (GetLongDescr (), m_pIndexData->GetLongDescr ()) == 0)
fprintf (fp, "Long %s~\n", GetLongDescr ());
if (QUICKMATCH (GetDescription (), m_pIndexData->GetDescription ()) == 0)
fprintf (fp, "Description %s~\n", GetDescription ());
fprintf (fp, "Position %d\n", GetPosition ());
if (! GetActFlags ().IsEmpty ())
fprintf (fp, "Flags %s\n", GetActFlags ().PrintVector ());
if (! GetCarryList ().IsEmpty ())
fwrite_obj (GetCarryList (), fp, 0, OS_CARRY);
fprintf (fp, "EndMobile\n");
}
// Note: these functions cannot be inline due to not wanting to have to
// include menus.h everywhere character.h is needed.
void CCharacter::DisplayMenu (char menu)
{
m_pEditMenu->Display (*this, menu);
}
void CCharacter::RemoveMenu ()
{
ASSERT (m_pEditMenu);
SendText ("\x1b[2J"); // clear screen
SendTextf ("&gChanges to %s:%u Abandoned.\r\n",
m_pEditMenu->GetName (), m_pEditMenu->m_Vnum);
// for now just delete it. Later we can ask for save, etc.
delete m_pEditMenu;
m_pEditMenu = NULL;
}
BOOL CCharacter::EditMenu (char* arg, const char* cmd)
{
ASSERT (m_pEditMenu);
if (! stricmp (cmd, "quitmenu") || ! stricmp (cmd, "qm")) {
RemoveMenu ();
return TRUE;
}
else if (! stricmp (cmd, "savemenu") || ! stricmp (cmd, "sm")) {
SaveMenu ();
return TRUE;
}
else return m_pEditMenu->Edit (*this, arg, cmd);
}
void CCharacter::SaveMenu ()
{
ASSERT (m_pEditMenu);
SendColorf ("\x1b[2J&YSaving %s %s:%u.\r\n",
m_pEditMenu->m_bProto ? "Prototype" : "Non-Prototype",
NCCP m_pEditMenu->GetName (), m_pEditMenu->m_Vnum);
m_pEditMenu->Save (*this);
delete m_pEditMenu;
m_pEditMenu = NULL;
}
void CCharacter::ReturnToMenu (BOOL b)
{
m_pEditMenu->ReturnToMenu (this, b);
}
void CCharacter::Edit (char* arg)
{
if (m_pEditor)
m_pEditor->Edit (*this, arg);
else
SetConnectStatus (CON_PLAYING);
}
char* CCharacter::GetEditBuffer ()
{
if (m_pEditor)
return m_pEditor->CopyToBuffer ();
else
return STRALLOC ("");
}
void CCharacter::StopEditing ()
{
if (m_pEditor)
m_pEditor->StopEditing (*this);
else
SetConnectStatus (CON_PLAYING);
}
BOOL CCharacter::IsPermanentAffect (int bit)
{
return bit < 0 ? FALSE : RaceTable.IsAffected (GetRace (), bit);
}
int CCharacter::GetConnectStatus ()
{
return m_pDesc ? m_pDesc->m_Connected : 0;
}
void CCharacter::SetConnectStatus (int st)
{
if (m_pDesc) m_pDesc->m_Connected = st;
}
const char *CCharacter::GetRaceName ()
{
return IsNpc () ?
RaceTable.GetNpcRaceName (GetRace ()) :
RaceTable.GetName (GetRace ());
}
const char *CCharacter::GetClassName ()
{
const char *pName = "Unknown";
if (IsNpc ()) {
if (GetClass () < MAX_NPC_CLASS && GetClass () >= 0)
return ClassTable.GetNpcClassName (GetClass ());
}
else pName = ClassTable.GetName (GetClass ());
return pName;
}
BOOL CCharacter::IsVampire ()
{
return ! IsNpc ()
&& (RaceTable.IsVampire (m_Race) || ClassTable.IsVampire (m_Class));
}
BOOL CCharacter::IsFightPosition ()
{
return m_Position == POS_FIGHTING || m_Position == POS_EVASIVE
|| m_Position == POS_DEFENSIVE || m_Position == POS_AGGRESSIVE
|| m_Position == POS_BERSERK;
}
BOOL CCharacter::HasValidRace ()
{
return RaceTable.IsValidRace (GetRace ());
}
ConnectErrorTypes CCharacter::GetConnectError ()
{
for (int i=0; i < CE_MAX; ++i)
if (m_ConnectError.IsSet (i))
return (ConnectErrorTypes) i;
return CE_NONE;
}
void CCharacter::SetConnectError (ConnectErrorTypes e)
{
if (e == CE_NONE)
m_ConnectError.Empty ();
else m_ConnectError.SetBit (e);
}
BOOL CCharacter::CanGo (short door)
{
CExitData &Ex = *GetExit (door);
if (! &Ex)
return FALSE;
return Ex.GetToRoom () && ! Ex.IsDisabled () && ! Ex.IsClosed ();
}
// This function checks to see if ch is ignoring ich - Fireblade.
BOOL CCharacter::IsIgnoring (CCharacter* ich)
{
if (IsNpc () || ich->IsNpc ())
return FALSE;
CStringList &List = GetPcData ()->m_IgnoreList;
POSITION pos = List.GetHeadPosition ();
while (pos)
if (nifty_is_name (List.GetNext (pos), ich->GetName ()))
return TRUE;
return FALSE;
}
CCharacter::~CCharacter ()
{
ASSERT (this);
m_AffectList.RemoveAll ();
CTimerData *pNtimer, *pTimer = first_timer;
while (pTimer) {
pNtimer = pTimer->GetNext ();
delete pTimer;
pTimer = pNtimer;
}
delete m_pEditor;
delete hunting;
delete hating;
delete fearing;
delete m_pFighting;
CNoteData *pNnote, *pNote = m_pNote;
while (pNote) {
pNnote = pNote->GetNext ();
delete pNote;
pNote = pNnote;
}
delete m_pPcdata;
CMobProgActList *pNpact, *pPact = m_pMobPact;
while (pPact) {
pNpact = pPact->GetNext ();
delete pPact;
pPact = pNpact;
}
CNoteData *pNcomm, *pComments = comments;
while (pComments) {
pNcomm = pComments->GetNext ();
delete pComments;
pComments = pNcomm;
}
}