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