/**************************************************************************** * [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. * * ------------------------------------------------------------------------ * * SmaugWizard Classes Interface Module * ***************************************************************************/ #include "stdafx.h" #include "smaug.h" #include "Smaugx.h" #include "skill.h" #include "objects.h" #include "rooms.h" #include "SmaugFiles.h" #include "character.h" #include "class.h" #if defined (KEY) #undef KEY #endif #define KEY(literal,field,value) \ if (!str_cmp (word, literal)) { \ field = value; \ fMatch = TRUE; \ break; \ } BOOL CClassTable::LoadClassFile (const char *fname) { FILE *fp; CString Fname = FileTable.MakeName (SD_CLASS_DIR, fname); if ((fp = fopen (Fname, "r")) == NULL) { perror (Fname); return FALSE; } CClassData *pClass = new CClassData; if (pClass->Read (fp)) { fclose (fp); Add (pClass); return TRUE; } bug ("LoadClassFile: Class (%s) bad/not found.", pClass->m_pName ? pClass->m_pName : "name not found"); delete pClass; return FALSE; } BOOL CClassData::Read (FILE* fp) { char *word; BOOL fMatch; int tlev = 0; int version = 0; char *pLine; m_Class = ClassTable.GetCount (); // First set the level and adept for each skill (for this class) for (int sk = 0; sk < SkillTable.GetCount (); ++sk) { SkillTable.SetClassLevel (sk, m_Class, LEVEL_IMMORTAL); SkillTable.SetClassAdept (sk, m_Class, 95); } 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': KEY ("AttrPrime", m_AttrPrime, ParseNumber (pLine)); break; case 'E': if (! str_cmp (word, "End")) return TRUE; KEY ("ExpBase", m_ExpBase, ParseNumber (pLine)); break; case 'G': KEY ("Guild", m_Guild, ParseNumber (pLine)); break; case 'H': KEY ("HpMax", m_HpMax, ParseNumber (pLine)); KEY ("HpMin", m_HpMin, ParseNumber (pLine)); break; case 'M': KEY ("Mana", m_bManaGain, ParseNumber (pLine)); break; case 'N': KEY ("Name", m_pName, ParseString (pLine, fp)); break; case 'S': KEY ("ShoveDrag", m_SDPercent, ParseNumber (pLine)); if (! str_cmp (word, "Skill")) { word = ParseWord (pLine); int lev = ParseNumber (pLine); int adp = ParseNumber (pLine); CSkill *pSkill = SkillTable.Find (word); if (! pSkill) bug ("CClassData::Read: Class %s: Invalid Skill: %s", GetName (), word); else { pSkill->SetClassLevel (m_Class, lev); pSkill->SetClassAdept (m_Class, adp); } fMatch = TRUE; break; } KEY ("Skilladept", m_SkillAdept, ParseNumber (pLine)); break; case 'T': if (! str_cmp (word, "Title")) { if (tlev < MAX_LEVEL+1) { pLine = fread_line (fp); m_Titles [tlev][0] = ParseStringNohash (pLine, fp); pLine = fread_line (fp); m_Titles [tlev][1] = ParseStringNohash (pLine, fp); ++tlev; } else bug ("CClassData::Read: %s, Too many titles", GetName ()); fMatch = TRUE; break; } KEY ("Thac0", m_Thac0_00, ParseNumber (pLine)); KEY ("Thac32", m_Thac0_32, ParseNumber (pLine)); break; case 'V': if (! stricmp (word, "Version")) { version = ParseNumber (pLine); if (version != GetCurrentVersion ()) { bug ("Incompatible Class File: %s, Version %d (%d required)", GetName (), version, GetCurrentVersion ()); return FALSE; } fMatch = TRUE; } break; case 'W': KEY ("Weapon", m_Weapon, ParseNumber (pLine)); break; } if (fMatch && version == 0) { bug ("CClassData::Read: %s, Incompatible Class file, no Version.", GetName ()); break; } if (! fMatch) bug ("CClassData::Read: %s, no match: %s", GetName (), word); } return FALSE; } BOOL CClassData::CanMorph (const char* morph) { if (! stricmp (m_pName, "mage")) { if (str_cmp (morph, "wolf")) return TRUE; if (str_cmp (morph, "cat")) return TRUE; if (str_cmp (morph, "hawk")) return TRUE; return FALSE; } if (! stricmp (m_pName, "vampire")) { if (str_cmp (morph, "mist")) return TRUE; if (str_cmp (morph, "bat")) return TRUE; return FALSE; } if (! stricmp (m_pName, "cleric")) { if (str_cmp (morph, "dove")) return TRUE; if (str_cmp (morph, "fish")) return TRUE; return FALSE; } return FALSE; } // Load in all the class files. void CClassTable::Load () { FILE *fp; char *filename; char *pLine; CString Fname = FileTable.GetName (SM_CLASS_LIST); if ((fp = fopen (Fname, "r")) == NULL) { perror (Fname); ThrowSmaugException (SE_CLASS); } for (;;) { if (! feof (fp)) { pLine = fread_line (fp); filename = ParseWord (pLine); } else filename = "$"; if (filename [0] == '$') then break; if (filename [0] != '*') if (! LoadClassFile (filename)) bug ("Cannot load class file: %s", filename); } fclose (fp); } // Write the class data to name.class void CClassData::Write () { FILE *fp; int x, y; CString Fname = FileTable.MakeName (SD_CLASS_DIR, m_pName) + ".class"; if ((fp = fopen (Fname, "w")) == NULL) { bug ("Cannot open: %s for writing", NCCP Fname); return; } fprintf (fp, "Version %d SmaugWiz V2\n\n", GetCurrentVersion ()); fprintf (fp, "Name %s~\n", m_pName); fprintf (fp, "Attrprime %d\n", m_AttrPrime); fprintf (fp, "Weapon %d\n", m_Weapon); fprintf (fp, "Guild %d\n", m_Guild); fprintf (fp, "Skilladept %d\n", m_SkillAdept); fprintf (fp, "Thac0 %d\n", m_Thac0_00); fprintf (fp, "Thac32 %d\n", m_Thac0_32); fprintf (fp, "Hpmin %d\n", m_HpMin); fprintf (fp, "Hpmax %d\n", m_HpMax); fprintf (fp, "Mana %d\n", m_bManaGain); fprintf (fp, "Expbase %d\n", m_ExpBase); fprintf (fp, "ShoveDrag %d\n", m_SDPercent); for (x = 0; x < SkillTable.GetCount (); x++) { if (! SkillTable.GetName (x) || SkillTable.GetName (x)[0] == '\0') break; if ((y = SkillTable.GetClassLevel (x, m_Class)) < LEVEL_IMMORTAL) fprintf (fp, "Skill '%s' %d %d\n", SkillTable.GetName (x), y, SkillTable.GetClassAdept (x, m_Class)); } for (x = 0; x <= MAX_LEVEL; x++) fprintf (fp, "Title\n%s~\n%s~\n", m_Titles [x][0], m_Titles [x][1]); fprintf (fp, "End\n"); fclose (fp); } CClassData::~CClassData () { for (int lev=0; lev < MAX_LEVEL+1; ++lev) { delete m_Titles [lev][0]; delete m_Titles [lev][1]; } } // Get CClassData pointer from class name CClassData *CClassTable::Find (const char* name) { CClassData *pClass = NULL; for (int cl = 0; cl < GetCount (); ++cl) if (! stricmp (GetName (cl), name)) { pClass = GetClassData (cl); break; } return pClass; } // Get Class number from class name int CClassTable::GetClass (const char* name) { CClassData *pClass = Find (name); return pClass ? pClass->GetClass () : CLASS_NONE; } // Save all class files void CClassTable::Save () { POSITION pos = GetHeadPosition (); while (pos) GetNext (pos)->Write (); } void CClassTable::RemoveAll () { while (! IsEmpty ()) delete RemoveTail (); CPtrList::RemoveAll (); } void CClassTable::ListClasses (CCharacter *ch) { POSITION pos = GetHeadPosition (); while (pos) { CClassData &Cl = *GetNext (pos); ch->SendTextf ("%2d) %s\r\n", Cl.GetClass (), Cl.GetName ()); } }