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