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

#include	"stdafx.h"
#include	"smaug.h"
#include	"Smaugx.h"
#include	"area.h"
#include	"objects.h"
#include	"resets.h"
#include	"rooms.h"
#include	"Exits.h"


// Create a new room (for online building)			-Thoric
CRoomIndexData *make_room (int vnum)
{
	CRoomIndexData *pRoomIndex;

	pRoomIndex = new CRoomIndexData (vnum);
	pRoomIndex->SetName (STRALLOC ("Floating in a void"));
	pRoomIndex->SetDescription (STRALLOC (""));
	pRoomIndex->SetPrototype ();
	pRoomIndex->sector_type = 1;

	RoomTable.Add (pRoomIndex, vnum);

	return pRoomIndex;
}


void CRoomIndexData::Read (FILE* fp, BOOL bBug)
{
	char	*pLine;
	char	ch;

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

	pLine = fread_line (fp);
	int		x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0;
	sscanf (pLine, "%d %d %d %d %d", &x1, &x2, &x3, &x4, &x5);

	m_flags = x1;
	sector_type = x2;
	tele_delay = x3;
	tele_vnum = x4;
	tunnel = x5;

	if (sector_type < 0 || sector_type == SECT_MAX) {
		bug ("CRoomIndexData::Read: vnum %d has bad sector_type %d.", vnum,
			sector_type);
		sector_type = 1;
	}
	light = 0;
	first_exit = NULL;
	last_exit = NULL;

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

		if (letter == 'S')
			break;

		if (letter == 'D') {
			CExitData *pexit;
			int locks;

			int	door = ParseNumber (pLine);
			if (door < 0 || door > 10) {
				bug ("CRoomIndexData::Read: Room %d has bad door number %d.", vnum,
					door);
				if (bBug)
				  ThrowSmaugException (SE_ROOM);
			} else {
				pexit = make_exit (this, NULL, door);
				pLine = fread_line (fp);
				pexit->description = ParseString (pLine, fp);
				pLine = fread_line (fp);
				pexit->keyword = ParseString (pLine, fp);
				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);

				locks = x1;
				pexit->key = x2;
				pexit->vnum = x3;
				pexit->vdir = door;
				pexit->distance = x4;
				pexit->pulltype	= x5;
				pexit->pull		= x6;

				switch (locks) {
				  case 1:
					pexit->SetDoor ();
					break;
				  case 2:
					pexit->SetDoor ();
					pexit->SetPickProof ();
					break;
				  default:
					pexit->SetFlags (locks);
				}
			}
		}
		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 == 'M');			// ignore maps
		else if (letter == '>') {
			--pLine;
			ReadPrograms (pLine, fp);
		}
		else if (letter == 'R') {			// resets
			ch = 0;
			x1=x2=x3=x4=x5=0;
			sscanf (pLine, " %c %d %d %d %d %d",
				&ch, &x1, &x2, &x3, &x4, &x5);
			CResetData	*pReset = new CResetData (ch, x1, x2, x3, x4, x5);
			ResetList.AddTail (pReset);
		} else {
			bug ("CRoomIndexData::Read: vnum %d has flag '%c' not 'DES'.",
				vnum, letter);
			shutdown_mud ("Room flag not DES");
			ThrowSmaugException (SE_ROOM);
		}
	}
}


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

	if ((letter = *pLine++) != '>') {
		bug ("Load_rooms: vnum %d ROOMPROG char", vnum);
		ThrowSmaugException (SE_ROOMPROG);
	}

	CMobProgData	*pRprg = new CMobProgData;
	RoomPrgList.AddTail (pRprg);

	while (! done) {
		pRprg->type = mprog_name_to_type (ParseWord (pLine));
		switch (pRprg->type) {
		  case ERROR_PROG:
			bug ("Load_rooms: vnum %d ROOMPROG type.", vnum);
			ThrowSmaugException (SE_ROOMPROG);
			break;
		  case IN_FILE_PROG:
			bug ("Error: Room %d SmaugWiz does not handle "
				"file Room Progs.", vnum);
			ThrowSmaugException (SE_ROOMPROG);
			break;

		  default:
			m_Progtypes.SetBit (pRprg->type);
			pRprg->arglist = ParseString (pLine, fp);
			pLine = fread_line (fp);
			pRprg->comlist = ParseString (pLine, fp);
			pLine = fread_line (fp);
			switch (letter = *pLine++) {
			  case '>':
				pRprg = new CMobProgData;
				RoomPrgList.AddTail (pRprg);
				break;
			  case '|':
				done = TRUE;
				break;
			  default:
				bug ("Load_rooms: Room %d bad ROOMPROG.", vnum);
				ThrowSmaugException (SE_ROOMPROG);
				break;
			}
			break;
		}
	}
}


void CRoomIndexData::Write (FILE *fp)
{
	fprintf (fp, "#%d\n", vnum);
	fprintf (fp, "%s~\n", GetName ());
	fprintf (fp, "%s~\n", strip_cr (GetDescription ()));
	fprintf (fp, "%d %d %d %d %d\n", GetRoomFlags (),
		sector_type, tele_delay, tele_vnum, tunnel);

	CExitData	*pExit = first_exit;
	for ( ; pExit; pExit = pExit->GetNext ()) {
		if (pExit->IsPortal ())				// don't fold portals
			continue;
		fprintf (fp, "D%d\n", pExit->vdir);
		fprintf (fp, "%s~\n", strip_cr (pExit->description));
		fprintf (fp, "%s~\n", strip_cr (pExit->keyword));
		pExit->ClrBashed ();
		fprintf (fp, "%s %d %d %d\n", pExit->PrintFlagVector (),
			pExit->key, pExit->vnum, pExit->distance);
	}	

	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));
	}

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

	if (! ResetList.IsEmpty ()) {
		POSITION	pos = ResetList.GetHeadPosition ();
		while (pos) {
			CResetData	&Reset = *ResetList.GetNext (pos);
			fprintf (fp, "R %c %d %d %d %d %d\n", Reset.command,
				Reset.extra, Reset.mob, Reset.arg1, Reset.arg2, Reset.arg3);
		}
	}
	fprintf (fp, "S\n");
}


// clean out a room (leave list pointers intact)		-Thoric
void CRoomIndexData::Clean ()
{
	STRFREE (m_pDescription);
	m_pDescription = NULL;
	STRFREE (m_pName);
	m_pName = NULL;

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

	ResetList.RemoveAll ();

	CExitData		*pexit, *pexit_next;

	for (pexit = first_exit; pexit; pexit = pexit_next) {
		pexit_next = pexit->GetNext ();
		STRFREE (pexit->keyword);
		STRFREE (pexit->description);
		delete pexit;
		top_exit--;
	}
	first_exit = NULL;
	last_exit = NULL;
	m_flags = 0;
	sector_type = 0;
	light = 0;
}


void CRoomIndexData::FixExits (BOOL bBoot)
{
	CExitData	*pExit, *pNext;
			
	BOOL	bAllBad = TRUE;
	for (pExit = first_exit; pExit; pExit = pNext) {
		pNext = pExit->GetNext ();
		pExit->rvnum = vnum;

		CRoomIndexData	*pToRoom = RoomTable.GetRoom (pExit->vnum);
		if (pExit->vnum > 0 && pToRoom) {
			pExit->SetToRoom (pToRoom);		// set exit pointer
			pExit->ClrDisabled ();
			bAllBad = FALSE;			// found at least 1 good exit
		} else {
			if (bBoot) then BootLog (
				"Fix_exits: %s, room %d, exit %s leads to bad vnum (%d)",
				NCCP GetArea ()->GetName (),
				vnum, dir_name [pExit->vdir], pExit->vnum);

			bug ("Disabling %s exit in room %d", dir_name [pExit->vdir],
				vnum);
			pExit->SetDisabled ();
			// extract_exit (this, pExit);
		}
	}
	if (bAllBad)
		SetNoMob ();
}


CRoomIndexData::~CRoomIndexData ()
{
	// Free up the ram for all strings attached to the room.
	STRFREE (m_pName);
	STRFREE (m_pDescription);

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

	CExitData		*pNexit, *pExit = first_exit;
	while (pExit) {
		pNexit = pExit->GetNext ();
		delete pExit;
		pExit = pNexit;
	}

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

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







// Translates room virtual number to its room index struct.
// Hash table lookup.
CRoomIndexData *CRoomTable::GetRoom (int vnum, BOOL bBug /* = FALSE */)
{
	CRoomIndexData *pIdx;

	if (vnum < 0)
		vnum = 0;

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

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

	return NULL;
}


void CRoomTable::Remove (CRoomIndexData *room)
{
	CRoomIndexData	*tmp, *prev = NULL;

	int		iHash = GetHash (room->vnum);

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

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

		--m_Count;
	}
}


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


void CRoomTable::RemoveAll ()
{
    CRoomIndexData *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
}


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