mud++0.35/etc/
mud++0.35/etc/guilds/
mud++0.35/help/propert/
mud++0.35/mudC/
mud++0.35/player/
mud++0.35/src/interface/
mud++0.35/src/os/cygwin32/
mud++0.35/src/os/win32/
mud++0.35/src/os/win32/bcppbuilder/
mud++0.35/src/osaddon/
mud++0.35/src/util/
/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project.  All 
................................................ contributions are welcome. 
....Copyright(C).1995.Melvin.Smith.............. Enjoy. 
------------------------------------------------------------------------------
Melvin Smith (aka Fusion)         msmith@hom.net 
MUD++ development mailing list    mudpp@van.ml.org
------------------------------------------------------------------------------
area.cc
*/

#include "config.h"
#include "io.h"
#include "string.h"
#include "llist.h"
#include "hash.h"
#include "room.h"
#include "area.h"
#include "pc.h"
#include "object.h"

extern LList<PC> pcs;
extern LList<NPC> npcs;
extern LList<Area> areas;

extern HashTable<Object> objIndex;
extern HashTable<NPC> npcIndex;
extern HashTable<Room> roomIndex;


int Area::reload()
{
	// This leaves invalid pointers in other areas so it is imperative
	// that a global relink be done immediately following an area reload
	Room * room;
	NPC * npc;
	Object * obj;

	roomIndex.reset();
	while ( (room = roomIndex.remove() ) )
	{
		room->fordelete();
	}

	npcIndex.reset();
	while ( (npc = npcIndex.remove() ) )
	{
		npc->fordelete();
	}

	objIndex.reset();
	while ( (obj = objIndex.remove() ) )
	{
		obj->fordelete();
	}

	rmDirtyBit();
	return load();
}


int Area::readFrom( StaticInput &in )
{  
	String	str;
	char	buf[BUF];
	Index	tempIndex;
	int		version;

	// Read area header
	for( ; ; ) 
	{
		in.getword( buf );
		switch( *buf )
		{
			default :
				str << "Area:readFrom:" << "unexpected char " << *buf;
				in.error( str );
			case '{': // nest++; unused for now
				continue;
			case '}': // nest--;
				break;
			case 'A':
				if( !strcmp( buf, "Author" ) )
					author = in.getstring( buf );
				else if( !strcmp( buf, "AreaFlags" ) )
					a_flags = in.getnum();
				else
					in.error( buf );
				continue;
			case 'B':
				if( !strcmp( buf, "Builder" ) )
					builder = in.getstring( buf );
				else
					in.error( buf );
				continue;
			case 'N':
				if( !strcmp( buf, "Name" ) )
					setName( in.getstring( buf ) );
				else
					in.error( buf );
				continue;
			case 'M':
				if( !strcmp( buf, "MinLev" ) )
					min_level = in.getnum();
				else if( !strcmp( buf, "MaxLev" ) )
					max_level = in.getnum();
				else
					in.error( buf );
				continue;
			case 'R':
				if( !strcmp( buf, "Recall" ) )
					setRecall( in.getstring( buf ) );
				else if( !strcmp( buf, "RepopMes" ) )
					setRepopMessg( in.getstring( buf ) );
				else if( !strcmp( buf, "RepopTime" ) )
					repop_time = in.getnum();
				else
					in.error( buf );
				continue;
			case 'S':
				if( !strcmp( buf, "Security" ) )
					security = in.getnum();
				else
					in.error( buf );
				continue;
			case 'T':
				if( !strcmp( buf, "Title" ) )
					title = in.getstring( buf );
				else
					in.error( buf );
				continue;
			case 'V':
				if( !strcmp( buf, "Version" ) ) 
					version = in.getnum(); // future expansion
				else
					in.error( buf );
				continue;
		} 
		break;
	}

	while(in)
	{
		in.getword( buf );

		if( !in )
			break;

		if( *buf == 'R' ) // Room
		{
			tempIndex = in.getword( buf );
			Room *newRoom = new Room( this, tempIndex.getKey() );  // This = Area *

			newRoom->readFrom( in );
			roomIndex.add( tempIndex.getKey(), newRoom );
#ifdef DEBUG
			Cout << "Loading room " << tempIndex << endl;
#endif
		}
		else if( *buf == 'N' ) // NPC
		{
			NPC *newNPC = new NPC;
			tempIndex = in.getword( buf );
			newNPC->readFrom( in );
			npcIndex.add( tempIndex.getKey(), newNPC );
#ifdef DEBUG
			Cout << "Loading NPC " << tempIndex << endl;
#endif
		}
		else if( *buf == 'O' ) // Object
		{
			tempIndex = in.getword( buf );
			in.getword(buf);
			Object * newObj = Object::createObject( lookupObjType(buf) );
			if (newObj == NULL )
			{
				in.error(buf);
			}

			newObj->readFrom( in );
			objIndex.add( tempIndex.getKey(), newObj );
#ifdef DEBUG
			Cout << "Loading Object " << tempIndex << endl;
#endif
		}
		else if( *buf == '#' )
			return 0;
		else
			return -1;
	}
	return 0;
}



int Area::writeTo( Output & out ) const
{
	out << "A " << key << " {\n"
		<< "Name " << name << "~\n"
		<< "Title " << title << "~\n"
		<< "Author " << author << "~\n"
		<< "MinLev " << min_level << "\nMaxLev " << max_level << "\n"
		<< "Security " << security << "\n"
		<< "RepopMes " << repop_messg << "~\n"
		<< "RepopTime " << repop_time << "\n"
		<< "Builder " << builder << "~\n"
		<< "Version " << version << "\n"
		<< "}\n\n";

	NPC *npc;

	for_each( npcIndex, npc )
	{
//		if( npc->isShopKeeper() )
//			continue;

		out << "N " << getKey() << ':' << npcIndex.getKey() << "\n";
		npc->writeTo( out );
	}
/*
	for_each( npcIndex, npc )
	{
		if( !npc->isShopKeeper() )
			continue;

		out << "S " << getKey() << ':' << npcIndex.getKey() << "\n";
		npc->writeTo( out );
	}
*/
	Object *obj;
	for_each( objIndex, obj )
	{
		out << "O " << getKey() << ':' << objIndex.getKey() << ' ' <<
			obj->typeName() << "\n";
		obj->writeTo( out );
	}

	Room *room;
	for_each( roomIndex, room )
	{
		out << "R " << getKey() << ':' << roomIndex.getKey() << "\n";
		room->writeTo( out );
	}

	out << "#\n";
	return 1;
}


void Area::addRoom( Room * room )
{
	// Add checks later
	roomIndex.add( room->getKey(), room );
}


void Area::removeRoom( Room * room )
{
	roomIndex.remove( room->getKey() );
}


void Area::repop()
{
	Room * room;
	roomIndex.reset();
	while( ( room = roomIndex.peek() ) )
	{
		roomIndex.next();
		room->repop();
	}

	outAllChar( repop_messg );
	timer = 0;
}


Object *Area::createObj( const String & x )
{
	Object *obj;
	obj = objIndex.lookup( x );

	if( !obj )
		return 0;
	// call the Object copy constructor to correctly clone the Object
	return obj->clone();
}


NPC *Area::createNPC( const String & x )
{
	NPC *npc = npcIndex.lookup( x );

	if( npc )
		// call the NPC copy constructor to correctly clone the Object
		return new NPC( *npc ); 
	
	return 0;
}


void Area::hardLink()
{
	Room *room;
	roomIndex.reset();

	while( ( room = roomIndex.peek() ) )
	{
		roomIndex.next();
		room->hardLink();
	}
}


void Area::outAllChar( const char * str )
{
	PC *pc;
	LList<PC> tList = pcs;
	tList.reset();
	while( ( pc = tList.peek() ) )
	{
		tList.next();
		// Add check for awake after position implemented

		if( !pc->isPlaying() )
			continue;
		else if( pc->inRoom()->getArea() != this )
			continue;
		else
			pc->out( str );
	}
}


void Area::outAllCharExcept( const char * str, PC * skip )
{
	PC *pc;
	LList<PC> tList = pcs;

	tList.reset();
	while( ( pc = tList.peek() ) )
	{
		tList.next();
		// Add check for awake after position implemented
		if( !pc->isPlaying() )
			continue;
		else if( pc->inRoom()->getArea() != this )
			continue;
		else if( pc == skip )
			continue;
		else
			pc->out( str );
	}
}


Area * lookupArea( const String & x )
{
	Area *area;
	LList<Area> tlist = areas;
	
	tlist.reset();
	while( ( area = tlist.peek() ) )
	{
		tlist.next();
		if( area->getKey() == x )
			return area;
	}

	return 0;	
}


Area * lookupArea( const char * x )
{
	return lookupArea( String( x ) );
}