SmaugWizard/Backup/
SmaugWizard/Backup/L/
SmaugWizard/Boards/
SmaugWizard/Building/
SmaugWizard/Corpses/
SmaugWizard/Councils/
SmaugWizard/Deity/
SmaugWizard/Gods/
SmaugWizard/MudProgs/
SmaugWizard/Player/L/
SmaugWizard/Src/
SmaugWizard/Src/res/
/****************************************************************************
 * [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 ());
	}
}