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.    *
 ****************************************************************************/
// mobiles.cpp

#include	"stdafx.h"
#include	"smaug.h"
#include	"Smaugx.h"
#include	"area.h"
#include	"class.h"
#include	"affect.h"
#include	"objects.h"
#include	"rooms.h"
#include	"skill.h"
#include	"Exits.h"


CObjData::~CObjData ()
{
	STRFREE (m_pName);
	STRFREE (m_pDescription);
	STRFREE (m_pShortDescr);
	STRFREE (m_pActionDesc);

	while (! ExDesList.IsEmpty ())
		delete (CExtraDescrData*) ExDesList.RemoveTail ();
	ExDesList.RemoveAll ();

	AffList.RemoveAll ();

	CMobProgActList	*pNpact, *pMpact = mpact;
	while (pMpact) {
		pNpact = pMpact->GetNext ();
		delete pMpact;
		pMpact = pNpact;
	}
}


// Write a single object to a file
void CObjData::Write (FILE *fp, int iNest, short StorageType,
				  short ChLevel /* = 0 */)
{
	CAffectData		*paf;
	short			wear, wear_loc, x;

	// Castrate storage characters. (Say what?!)
	if ((ChLevel && ChLevel < GetLevel ())
		|| (item_type == ITEM_KEY && ! IsClanObject ()))
			return;

	// Catch deleted objects					-Thoric
	if (obj_extracted (this))
		return;

	// Do NOT save prototype items!				-Thoric
	if (IsPrototype ())
		return;

	// Corpse saving. -- Altrag
	fprintf (fp, (StorageType == OS_CORPSE ? "#CORPSE\n" : "#OBJECT\n"));

	CObjIndexData	&Idx = *GetIndex ();

	if (iNest)
		fprintf (fp, "Nest         %d\n", iNest);
	if (count > 1)
		fprintf (fp, "Count        %d\n", count );
	if (QUICKMATCH (GetName (), Idx.GetName ()) == 0)
		fprintf (fp, "Name         %s~\n", GetName ());
	if (QUICKMATCH (GetShortDescr (), Idx.GetShortDescr ()) == 0)
		fprintf (fp, "ShortDescr   %s~\n", GetShortDescr ());
	if (QUICKMATCH (GetDescription (), Idx.GetDescription ()) == 0)
		fprintf (fp, "Description  %s~\n", GetDescription ());
	if (QUICKMATCH (GetActionDescr (), Idx.GetActionDescr ()) == 0)
		fprintf (fp, "ActionDesc   %s~\n", GetActionDescr ());

	fprintf (fp, "Vnum         %d\n", Idx.vnum);

	if (StorageType == OS_CORPSE && GetInRoom ())
		fprintf (fp, "Room         %d\n", in_room->vnum);
	if (m_ExtraFlags != Idx.m_ExtraFlags)
		fprintf (fp, "ExtraFlags   %s\n", m_ExtraFlags.PrintVector ());
	if (wear_flags != Idx.wear_flags)
		fprintf (fp, "WearFlags    %d\n", wear_flags);
	if (GetAntiClassFlags () != Idx.GetAntiClassFlags ()) {
		for (int cl=0; cl < ClassTable.GetCount (); ++cl)
			if (IsAntiClass (cl))
				fprintf (fp, "AntiClass    %s~\n", ClassTable.GetName (cl));
	}

	wear_loc = -1;
	for (wear = 0; wear < MAX_WEAR; wear++) {
		for (x = 0; x < MAX_LAYERS; x++)
			if (save_equipment [wear][x] == this) {
				wear_loc = wear;
				break;
			}
			else if (! save_equipment [wear][x])
				break;
	}

	if (wear_loc != -1)
		fprintf (fp, "WearLoc      %d\n", wear_loc);
	if (item_type != Idx.item_type)
		fprintf (fp, "ItemType     %d\n", item_type);
	if (weight != Idx.weight)
		fprintf (fp, "Weight       %d\n", weight);
	if (GetLevel ())
		fprintf (fp, "Level        %d\n", GetLevel ());
	if (timer)
		fprintf (fp, "Timer        %d\n", timer);
	if (cost != Idx.cost)
		fprintf (fp, "Cost         %d\n", cost);
	if (value [0] || value [1] || value [2]
		|| value [3] || value [4] || value [5])
			fprintf (fp, "Values       %d %d %d %d %d %d\n",
				value [0], value [1], value [2],
				value [3], value [4], value [5]);

	switch (item_type) {
	  case ITEM_PILL:
	  case ITEM_POTION:
	  case ITEM_SCROLL:
		if (SkillTable.IsValid (value [1]))
			fprintf (fp, "Spell 1      '%s'\n",
				SkillTable.GetName (value [1]));

		if (SkillTable.IsValid (value [2]))
			fprintf (fp, "Spell 2      '%s'\n",
				SkillTable.GetName (value [2]));

		if (SkillTable.IsValid (value [3]))
			fprintf (fp, "Spell 3      '%s'\n",
				SkillTable.GetName (value [3]));

		break;

	  case ITEM_STAFF:
	  case ITEM_WAND:
		if (SkillTable.IsValid (value [3]))
			fprintf (fp, "Spell 3      '%s'\n",
				SkillTable.GetName (value [3]));

		break;
	  case ITEM_SALVE:
		if (SkillTable.IsValid (value [4]))
			fprintf (fp, "Spell 4      '%s'\n",
				SkillTable.GetName (value [4]));

		if (SkillTable.IsValid (value [5]))
			fprintf (fp, "Spell 5      '%s'\n",
				SkillTable.GetName (value [5]));
		break;
	}

	POSITION	apos = AffList.GetHeadPosition ();
	while (apos) {
			paf = AffList.GetNext (apos);

		// Save extra object affects				-Thoric
		if (paf->type < 0 || paf->type >= SkillTable.GetCount ()) {
			fprintf (fp, "Affect       %d %d %d %d '%s'\n",
				paf->type, paf->duration,
				((paf->location == APPLY_WEAPONSPELL
				|| paf->location == APPLY_WEARSPELL
				|| paf->location == APPLY_REMOVESPELL
				|| paf->location == APPLY_STRIPSN)
				&& SkillTable.IsValid (paf->modifier))
				? SkillTable.GetSlot (paf->modifier) : paf->modifier,
				paf->location, paf->GetVectorName ());
		}

		else fprintf (fp, "AffectData   '%s' %d %d %d '%s'\n",
			SkillTable.GetName (paf->type), paf->duration,
			((paf->location == APPLY_WEAPONSPELL
			|| paf->location == APPLY_WEARSPELL
			|| paf->location == APPLY_REMOVESPELL
			|| paf->location == APPLY_STRIPSN)
			&& SkillTable.IsValid (paf->modifier))
			? SkillTable.GetSlot (paf->modifier) : paf->modifier,
			paf->location, paf->GetVectorName ());
	}

	POSITION	pos = ExDesList.GetHeadPosition ();
	while (pos) {
		CExtraDescrData	&Ed = *(CExtraDescrData*) ExDesList.GetNext (pos);
		fprintf (fp, "ExtraDescr   %s~ %s~\n",
			Ed.keyword, Ed.GetDescription ());
	}

	fprintf (fp, "End\n\n");
}


// Create a new INDEX object (for online building)		-Thoric
// Option to clone an existing index object.
CObjIndexData *make_object (int vnum, int cvnum, char *name)
{
	CObjIndexData	*pObjIndex, *cObjIndex;
	char			buf [MAX_STRING_LENGTH];

	if (cvnum > 0)
		cObjIndex = OIdxTable.GetObj (cvnum);
	else
		cObjIndex = NULL;

	pObjIndex = new CObjIndexData (vnum);
	pObjIndex->SetName (name);

	if (! cObjIndex) {
		sprintf (buf, "a newly created %s", name);
		pObjIndex->SetShortDescr (buf);
		sprintf (buf, "Some god dropped a newly created %s here.", name);
		pObjIndex->SetDescription (buf);
		pObjIndex->SetActionDescr ("");
		pObjIndex->item_type = ITEM_TRASH;
		pObjIndex->SetPrototype ();
		pObjIndex->wear_flags = 0;
		pObjIndex->value [0] = 0;
		pObjIndex->value [1] = 0;
		pObjIndex->value [2] = 0;
		pObjIndex->value [3] = 0;
		pObjIndex->weight = 1;
		pObjIndex->cost = 0;
	} else {
		pObjIndex->SetShortDescr (cObjIndex->GetShortDescr ());
		pObjIndex->SetDescription (cObjIndex->GetDescription ());
		pObjIndex->SetActionDescr (cObjIndex->GetActionDescr ());
		pObjIndex->item_type = cObjIndex->item_type;
		pObjIndex->m_ExtraFlags = cObjIndex->m_ExtraFlags;
		pObjIndex->SetPrototype ();
		pObjIndex->wear_flags = cObjIndex->wear_flags;
		pObjIndex->value [0] = cObjIndex->value[0];
		pObjIndex->value [1] = cObjIndex->value[1];
		pObjIndex->value [2] = cObjIndex->value[2];
		pObjIndex->value [3] = cObjIndex->value[3];
		pObjIndex->weight = cObjIndex->weight;
		pObjIndex->cost = cObjIndex->cost;

		POSITION	pos = cObjIndex->ExDesList.GetHeadPosition ();
		while (pos) {
			CExtraDescrData &Ced =
				*(CExtraDescrData*) cObjIndex->ExDesList.GetNext (pos);
			CExtraDescrData *ed = new CExtraDescrData;
			ed->keyword = QUICKLINK (Ced.keyword);
			ed->description = QUICKLINK (Ced.description);
			pObjIndex->ExDesList.AddTail (ed);
			top_ed++;
		}

		CAffectList	&AList = pObjIndex->AffList;
		POSITION	apos = AList.GetHeadPosition ();
		while (apos) {
			CAffectData	*paf = new CAffectData (*AList.GetNext (apos));
			pObjIndex->AddAffect (paf);
			++top_affect;
		}
	}
	pObjIndex->count = 0;
	OIdxTable.Add (pObjIndex, vnum);

	return pObjIndex;
}


char* CObjIndexData::Read (FILE* fp, int AreaVersion)
{
    int		x1, x2, x3, x4, x5, x6;
	char	letter;
	char	*pLine;

	pLine = fread_line (fp);
	m_pName = ParseString (pLine, fp);
	pLine = fread_line (fp);
	m_pShortDescr = ParseString (pLine, fp);
	pLine = fread_line (fp);
	m_pDescription = ParseString (pLine, fp);
	pLine = fread_line (fp);
	m_pActionDesc = ParseString (pLine, fp);

	// Commented out by Narn, Apr/96 to allow item short descs like 
	// Bonecrusher and Oblivion
	// m_pShortDescr [0] = LOWER (m_pShortDescr [0]);
	m_pDescription [0] = UPPER (m_pDescription [0]);

	pLine = fread_line (fp);
	item_type = ParseNumber (pLine);
	m_ExtraFlags.Parse (pLine);
	wear_flags = ParseNumber (pLine);
	layers = ParseNumber (pLine);

	pLine = fread_line (fp);
	x1 = x2 = x3 = x4 = x5 = x6 = 0;
	sscanf (pLine, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6);
	value [0] = x1;
	value [1] = x2;
	value [2] = x3;
	value [3] = x4;
	value [4] = x5;
	value [5] = x6;

	switch (item_type) {
	  case ITEM_PILL:
	  case ITEM_POTION:
	  case ITEM_SCROLL:
		pLine = fread_line (fp);
		value [1] = SkillTable.Lookup (ParseWord (pLine));
		value [2] = SkillTable.Lookup (ParseWord (pLine));
		value [3] = SkillTable.Lookup (ParseWord (pLine));
		break;
	  case ITEM_STAFF:
	  case ITEM_WAND:
		pLine = fread_line (fp);
		value [3] = SkillTable.Lookup (ParseWord (pLine));
		break;
	  case ITEM_SALVE:
		pLine = fread_line (fp);
		value [4] = SkillTable.Lookup (ParseWord (pLine));
		value [5] = SkillTable.Lookup (ParseWord (pLine));
		break;
	}

	do {
		pLine = fread_line (fp);
		if (memcmp (pLine, "AntiClass", 9))
			break;
		pLine += 9;
		CString		s = ParseCString (pLine, fp);
		CClassData	*pClass = ClassTable.Find (s);
		if (pClass)
			SetAntiClass (pClass->GetClass ());
		else
			bug ("Unknown AntiClass: %s", NCCP s);
	} while (1);

	weight = ParseNumber (pLine);
	weight = UMAX (1, weight);
	cost = ParseNumber (pLine);
	level = ParseNumber (pLine);	// Using old rent field for level storage

	for (;;) {
		pLine = fread_line (fp);
		letter = *pLine++;

		if (letter == 'A') {
			CAffectData *paf = new CAffectData;
			pLine = fread_line (fp);
			paf->location = ParseNumber (pLine);
			if (paf->location == APPLY_WEAPONSPELL
			  || paf->location == APPLY_WEARSPELL
			  || paf->location == APPLY_REMOVESPELL
			  || paf->location == APPLY_STRIPSN
			  || paf->location == APPLY_RECURRINGSPELL) then
				paf->modifier = slot_lookup (ParseNumber (pLine));
			else paf->modifier = ParseNumber (pLine);
			AddAffect (paf);
			top_affect++;
		}
		else if (letter == 'E') {
			CExtraDescrData *ed = new CExtraDescrData;
			pLine = fread_line (fp);
			ed->keyword = ParseString (pLine, fp);
			pLine = fread_line (fp);
			ed->description = ParseString (pLine, fp);
			ExDesList.AddTail (ed);
			++top_ed;
		}
		else if (letter == '>') {
			--pLine;
			ReadPrograms (pLine, fp);
		} else {
			--pLine;
			break;
		}
	}
	return pLine;			// return the next line
}


// This procedure is responsible for reading any in_file OBJprograms.
void CObjIndexData::ReadPrograms (char* pLine, FILE *fp)
{
	char	letter;
	BOOL	done = FALSE;

	if ((letter = *pLine++) != '>') {
		bug ("Load_objects: vnum %d OBJPROG char", vnum);
		ThrowSmaugException (SE_OBJPROG);
	}

	CMobProgData	*pMprg = new CMobProgData;
	ObjPrgList.AddTail (pMprg);

	while (! done) {
		pMprg->type = mprog_name_to_type (ParseWord (pLine));
		switch (pMprg->type) {
		  case ERROR_PROG:
			bug ("Load_objects: vnum %d OBJPROG type.", vnum);
			ThrowSmaugException (SE_OBJPROG);
			break;
		  case IN_FILE_PROG:
			bug ("Error: Object %d. SmaugWiz does not handle "
				"file Object Progs.", vnum);
			ThrowSmaugException (SE_OBJPROG);
			break;

		  default:
			m_Progtypes.SetBit (pMprg->type);
			pMprg->arglist = ParseString (pLine, fp);
			pLine = fread_line (fp);
			pMprg->comlist = ParseString (pLine, fp);
			pLine = fread_line (fp);
			switch (letter = *pLine++) {
			  case '>':
				pMprg = new CMobProgData;
				ObjPrgList.AddTail (pMprg);
				break;
			  case '|':
				done = TRUE;
				break;
			  default:
				bug ("LoadObjects: vnum %d bad OBJPROG.", vnum);
				ThrowSmaugException (SE_OBJPROG);
				break;
			}
			break;
		}
	}
}


void CObjIndexData::Write (FILE *fp)
{
	fprintf (fp, "#%d\n", vnum);
	fprintf (fp, "%s~\n", m_pName);
	fprintf (fp, "%s~\n", m_pShortDescr);
	fprintf (fp, "%s~\n", m_pDescription);
	fprintf (fp, "%s~\n", m_pActionDesc);
	fprintf (fp, "%d %s %d %d\n", item_type,
		NCCP m_ExtraFlags.PrintVector (), wear_flags, layers);

	int	val0 = value [0];
	int	val1 = value [1];
	int	val2 = value [2];
	int	val3 = value [3];
	int	val4 = value [4];
	int	val5 = value [5];

	switch (item_type) {
	  case ITEM_PILL:
	  case ITEM_POTION:
	  case ITEM_SCROLL:
		if (SkillTable.IsValid (val1)) val1 = SkillTable.GetSlot (val1);
		if (SkillTable.IsValid (val2)) val2 = SkillTable.GetSlot (val2);
		if (SkillTable.IsValid (val3)) val3 = SkillTable.GetSlot (val3);
		break;
	  case ITEM_STAFF:
	  case ITEM_WAND:
		if (SkillTable.IsValid (val3)) val3 = SkillTable.GetSlot (val3);
		break;
	  case ITEM_SALVE:
		if (SkillTable.IsValid (val4)) val4 = SkillTable.GetSlot (val4);
		if (SkillTable.IsValid (val5)) val5 = SkillTable.GetSlot (val5);
		break;
	}
	if (val4 || val5)
		fprintf (fp, "%d %d %d %d %d %d\n", val0, val1, val2,
			val3, val4, val5);
	else
		fprintf (fp, "%d %d %d %d\n", val0, val1, val2, val3);

	switch (item_type) {
	  case ITEM_PILL: 
	  case ITEM_POTION:
	  case ITEM_SCROLL:
		fprintf (fp, "'%s' '%s' '%s'\n",
			SkillTable.IsValid (value [1]) ?
				SkillTable.GetName (value [1]) : "NONE",
			SkillTable.IsValid (value [2]) ?
				SkillTable.GetName (value [2]) : "NONE",
			SkillTable.IsValid (value [3]) ? 
				SkillTable.GetName (value [3]) : "NONE");
		break;

	  case ITEM_STAFF:
	  case ITEM_WAND:
		fprintf (fp, "'%s'\n", SkillTable.IsValid (value [3]) ?  
			SkillTable.GetName (value [3]) : "NONE");
		break;

	  case ITEM_SALVE:
		fprintf (fp, "'%s' '%s'\n",
			SkillTable.IsValid (value [4]) ?  
				SkillTable.GetName (value [4]) : "NONE",
			SkillTable.IsValid (value [5]) ?
				SkillTable.GetName (value [5]) : "NONE");
		break;
	}

	// Save Anti-class flags as class names
	for (int cl=0; cl < ClassTable.GetCount (); ++cl)
		if (IsAntiClass (cl))
			fprintf (fp, "AntiClass    %s~\n", ClassTable.GetName (cl));

	fprintf (fp, "%d %d %d\n", weight, cost, level);

	POSITION	pos = ExDesList.GetHeadPosition ();
	while (pos) {
		CExtraDescrData	&Ed = *(CExtraDescrData*) ExDesList.GetNext (pos);
		fprintf (fp, "E\n%s~\n%s~\n",
			Ed.keyword, strip_cr (Ed.description));
	}

	POSITION	apos = AffList.GetHeadPosition ();
	while (apos) {
		CAffectData	*paf = AffList.GetNext (apos);
		fprintf (fp, "A\n%d %d\n", paf->location,
			((paf->location == APPLY_WEAPONSPELL
			|| paf->location == APPLY_WEARSPELL
			|| paf->location == APPLY_REMOVESPELL
			|| paf->location == APPLY_STRIPSN)
			&& SkillTable.IsValid (paf->modifier))
			? SkillTable.GetSlot (paf->modifier) : paf->modifier);
	}

	if (! ObjPrgList.IsEmpty ()) {
		POSITION	pos = ObjPrgList.GetHeadPosition ();
		while (pos) {
			CMobProgData	&Oprg = *(CMobProgData*) ObjPrgList.GetNext (pos);
			fprintf (fp, "> %s %s~\n%s~\n",
				mprog_type_to_name (Oprg.type),
				Oprg.arglist, strip_cr (Oprg.comlist));
		}
		fprintf (fp, "|\n");	  
	}
}


// clean out an object (index) (leave list pointers intact)	-Thoric
void CObjIndexData::Clear ()
{
	STRFREE (m_pName);
	STRFREE (m_pShortDescr);
	STRFREE (m_pDescription);
	STRFREE (m_pActionDesc);
	item_type = 0;
	m_AntiClassFlags.Empty ();
	m_ExtraFlags.Empty ();
	wear_flags = 0;
	count = 0;
	weight = 0;
	cost = 0;
	value [0] = 0;
	value [1] = 0;
	value [2] = 0;
	value [3] = 0;

	top_affect -= AffList.GetCount ();
	AffList.RemoveAll ();

	while (! ExDesList.IsEmpty ())
		delete (CExtraDescrData*) ExDesList.RemoveTail ();
	ExDesList.RemoveAll ();
}


CObjIndexData::~CObjIndexData ()
{
	while (! ExDesList.IsEmpty ())
		delete (CExtraDescrData*) ExDesList.RemoveTail ();
	ExDesList.RemoveAll ();

	AffList.RemoveAll ();

	while (! ObjPrgList.IsEmpty ())
		delete (CMobProgData*) ObjPrgList.RemoveTail ();
	ObjPrgList.RemoveAll ();

	m_ObjList.RemoveAll ();
}




CObjIndexData *CObjIdxTable::Find (int vnum)
{
	if (vnum < 0)
		return NULL;

	CObjIndexData *pIdx;

	for (pIdx = GetFirst (vnum); pIdx; pIdx = pIdx->GetNext ())
		if (pIdx->vnum == vnum)
			return pIdx;

	return NULL;
}



// Translates obj virtual number to its obj index struct.
// Hash table lookup.
CObjIndexData *CObjIdxTable::GetObj (int vnum, BOOL bBug /* = FALSE */)
{
	if (vnum < 0)
		vnum = 0;

	CObjIndexData *pIdx = Find (vnum);

	if (! pIdx && bBug)
		bug ("OIdxTable.GetObj: bad vnum %d.", vnum);

	return pIdx;
}


void CObjIdxTable::Add (CObjIndexData *pIndex, int vnum)
{
	pIndex->SetNext (GetFirst (vnum));
	SetFirst (GetHash (vnum), pIndex);
	++m_Count;
}


void CObjIdxTable::Remove (CObjIndexData* pIdx)
{
	CObjIndexData	*tmp, *prev = NULL;

	int		iHash = GetHash (pIdx->vnum);

	// Take the room index out of the hash list.
	for (tmp = m_ot [iHash]; tmp && tmp != pIdx; tmp = tmp->GetNext ())
		prev = tmp;

	if (tmp) {
		if (prev)
			prev->SetNext (pIdx->GetNext ());
		else
			m_ot [iHash] = pIdx->GetNext ();

		--m_Count;
	}
}


void CObjIdxTable::RemoveAll ()
{
    CObjIndexData *pNidx, *pIdx;
	for (int hash = 0; hash < MAX_KEY_HASH; ++hash) {
		pIdx = GetFirstByHash (hash);
		while (pIdx) {
			pNidx = pIdx->GetNext ();
			delete pIdx;
			pIdx = pNidx;
		}
	}
	Empty ();				// clear pointers and count
}


void CObjectList::AddByLevel (CObjData* pObj, BOOL bLevSort)
{
	BOOL	bIns = FALSE;

	if (bLevSort) {
		POSITION	CurPos, pos = GetHeadPosition ();
		while (pos) {
			CurPos = pos;
			if (GetNext (pos)->GetLevel () < pObj->GetLevel ()) {
				InsertBefore (CurPos, pObj);
				bIns = TRUE;
				break;
			}
		}
	}
	if (! bIns)
		CPtrList::AddTail (pObj);

	m_Loaded += pObj->count;
}


void CObjectList::AddTail (CObjData* obj)
{
	CPtrList::AddTail (obj);
	m_Loaded += obj->count;
}


void CObjectList::Remove (CObjData* obj)
{
	POSITION pos = Find (obj);
	if (pos) {
		RemoveAt (pos);
		m_Loaded -= obj->count;
	}
}


int CParseinfo::GetCount (ObjCountTypes type)
{
	int		count = 0;

	AApos = AllAreasList.GetHeadPosition ();
	while (AApos) {
		pAreaList = (CAreaList*) AllAreasList.GetNext (AApos);
		Apos = pAreaList->GetHeadPosition ();
		while (Apos) {
			CAreaData	&Area = *pAreaList->GetNext (Apos);
			Ipos = Area.m_ObjIdxList.GetHeadPosition ();
			while (Ipos) {
				CObjIndexData	&Idx =
					*(CObjIndexData*) Area.m_ObjIdxList.GetNext (Ipos);
				count += (type == COUNT_OBJS) ?
					Idx.m_ObjList.GetCount () : Idx.GetCount ();
			}
		}
	}

	return count;
}



// ParseAllObjects uses the CParseInfo structure to keep track of it's
// current position.  It returns each Object in each ObjectIndex in each
// Area, and returns NULL when done.
CObjData *CParseinfo::Parse (CAreaList& AList)
{
	if (bFirst) {
		Apos = AList.GetHeadPosition ();
		bFirst = FALSE;
	}
	while (! Opos) {		// if end of object list get next object list
		while (! Ipos) {	// if end of index list get next index list
			if (! Apos)		// if end of area list, done.
				return NULL;
			pIdxList = &AList.GetNext (Apos)->m_ObjIdxList;
			Ipos = pIdxList->GetHeadPosition ();
		}
		pObjList = &((CObjIndexData*) pIdxList->GetNext (Ipos))->m_ObjList;
		Opos = pObjList->GetHeadPosition ();
	}
	return pObjList->GetNext (Opos);
}


CObjData *CParseinfo::ParseAreaLists (CPtrList& AllAreasList)
{
	if (bFirst) {
		AApos = AllAreasList.GetHeadPosition ();
		bFirst = FALSE;
	}
	while (! Opos) {		// if end of object list get next object list
		while (! Ipos) {	// if end of index list get next index list
			while (! Apos) {// if end of area list get next area list
				if (! AApos)		// if end of all areas list, done.
					return NULL;
				pAreaList = (CAreaList*) AllAreasList.GetNext (AApos);
				Apos = pAreaList->GetHeadPosition ();
			}
			pIdxList = &pAreaList->GetNext (Apos)->m_ObjIdxList;
			Ipos = pIdxList->GetHeadPosition ();
		}
		pObjList = &((CObjIndexData*) pIdxList->GetNext (Ipos))->m_ObjList;
		Opos = pObjList->GetHeadPosition ();
	}
	return pObjList->GetNext (Opos);
}	



// Clean out the object list
void CObjectList::RemoveAll ()
{
	while (! IsEmpty ())
		delete RemoveTail ();

	CPtrList::RemoveAll ();
	m_Loaded = 0;
}


CString CObjData::AntiClassNames ()
{
	CString	s;

	for (int cl=0; cl < ClassTable.GetCount (); ++cl)
		if (IsAntiClass (cl)) {
			s += " Anti-";
			s += ClassTable.GetName (cl);
		}

	return s;
}


BOOL CObjData::CanGo (short door)
{
	CExitData	&Ex = *GetExit (door);

	if (! &Ex)
		return FALSE;

	return Ex.GetToRoom () && ! Ex.IsDisabled () && ! Ex.IsClosed ();
}


// return TRUE if an object contains a trap			-Thoric
BOOL CObjData::IsTrapped () const
{
	if (m_Content.IsEmpty ())
		return FALSE;

	POSITION	pos = m_Content.GetHeadPosition ();
	while (pos)
		if (m_Content.GetNext (pos)->item_type == ITEM_TRAP)
			return TRUE;

	return FALSE;
}



CExtraDescrData::~CExtraDescrData ()
{
	STRFREE (description);
	STRFREE (keyword);
	--top_ed;
}




#ifdef _DEBUG
void CObjIndexData::Dump (CDumpContext& dc) const
{
	CObject::Dump (dc);
	dc << "CObjIndexData Name: " << m_pName << "\n";
}

void CObjData::Dump (CDumpContext& dc) const
{
//	if (! memcmp (m_pName, "glass", 5)) {
	CObject::Dump (dc);
	dc << "CObjData Name: " << m_pName << "\n";
//	}
}
#endif