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