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