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
------------------------------------------------------------------------------
pc_wiz.cc
*/

#include <sys/time.h>
#include <unistd.h>

#if !defined(WIN32)
#include <sys/resource.h>
#endif

#include "config.h"
#include "string.h"
#include "llist.h"
#include "room.h"
#include "repop.h"
#include "hash.h"
#include "server.h"
#include "area.h"
#include "bit.h"
#include "screen.h"
#include "pc.h"
#include "social.h"
#include "random.h"
#include "cluster.h"

#include "global.h"
#include "properties.h"
#include "persist.h"

// This is a utility function which I change often just for debugging
// things
void PC::do_debug( const String & )
{
}

void PC::do_shell( const String & arg )
{
	String arg1;
	String arg2;
	arg.startArgs();
	arg1 = arg.getArg();
	arg2 = arg.getArg();
	pcs.remove( this );
	shellpcs.addTop( this );
	startShell( arg1, arg2 );
}


void PC::do_peace( const String & )
{
	Char * ch;
	for_each( inRoom()->chars, ch )
		if( ch->isFighting() )
			ch->stopFighting();
	out( "Ok.\n\r" );
}


void PC::do_smite( const String & arg )
{
	PC * victim;
	if( !arg )
	{
		out( "Smite whom?\n\r" );
		return;
	}

	victim = getPCWorld( arg );
	if( !victim )
	{
		out( "No such person.\n\r" );
		return;
	}

	victim->out( getShort() );
	victim->out( " smites you!\n\rThat really hurt!\n\r...You feel a little groggy.\n\r" );
	victim->setOrientation( randgen.get( 1, 3 ) );
	victim->setHP( victim->getHP() / 2 );
	victim->inRoom()->interp(
			"** W H A P **\n\r$n smites $N right out of $P boots!!\n\r",
					this, victim, 0, 0 );
	interp( "You smite $N out of $P boots.", this, victim, 0, 0 );
}


void PC::do_snoop( const String & arg )
{
	PC * victim;
	if( !(bool)arg )
	{
		out( "Snoop whom?\n\r" );
		return;
	}

	if( arg == "self" || arg == "none" || arg == "off" )
	{
		out( "Snoops off.\n\r" );	
		if( ( victim = getSnoopVictim() ) )
		{
			victim->setSnooper( 0 );
			setSnoopVictim( 0 );	
		}
		return;
	}

	victim = getPCWorld( arg );
	if( !victim )
	{
		out( "No such person.\n\r" );
		return;
	}

	if( victim == this )
	{
		out( "Can't snoop yourself, think of the bugs that could cause.\n\r" );
		return;
	}

	if( victim->getLevel() >= getLevel() )
	{
		out( "That person is un-snoopable as far as you are concerned.\n\r" );
		return;
	}

	if( victim->getSnooper() )
	{
		out( "That person is already being spied on.\n\r" );
		return;
	}

	victim->setSnooper( this );
	setSnoopVictim( victim );
	out( "Ok now snooping " );
	out( victim->getShort() );
	out( ".\n\r" );
}


void PC::do_show( const String & arg )
{
	String str;
	Host * host;

	if( !(bool)arg )
	{
		out( "Usage:    show { cluster }\n\r" );
		return;
	}

	if( arg == "cluster" )
	{
		str = "MUD++ cluster information:\n\n\r"; 
		for_each( cluster, host )
		{
			str.sprintfAdd( "%12s %30s %d\n\r",
							(const char*)host->getName(),
							(const char*)host->getHost(),
							host->getPlayerPort() );
		}
	}
	
	out( str );
}

void PC::do_force( const String & arg )
{
	arg.startArgs();

	String argName	= arg.getArg();
	String argComd	= arg.getArgRest();

	// NPCs dont have command parser yet.
	if( !(bool)argName || !(bool)argComd )
	{
		out( "Usage: force <person> <command string>\n\r" );
		return;
	}

	PC *plr = getPCWorld( argName );
	if( !plr )
	{
		out( argName );
		out( " is not playing.\n\r" );
		return;
	}

	if( plr->getLevel() >= getLevel() )
	{
		out( plr->getName() );
		out( " is too powerful for you.\n\r" );
		plr->out( getName() );
		plr->out( " just tried to force you to " );
		plr->out( argComd );
		plr->out( " but got denied!\n\r" );
		return;
	}

	plr->out( getName() );
	plr->out( " forces you to " );
	plr->out( argComd );
	plr->out( ".\n\r" );

	plr->command( argComd );
	out( "Ok.\n\r" );
}

// Just a test to get ident working. Will do non-blocking when
// this is done.
void PC::do_ident( const String & arg )
{
	char ip[ 256 ];
	char buf[ 256 ];

	PC *pc;
	Socket *identServ;

	if( !( pc = getPCWorld( arg ) ) )
	{
		out( "No such player connected.\n\r" );
		return;
	}

	if( !pc->getSocket() )
	{
		out( "That player is currently link dead.\n\r" );
		return;
	}

	strcpy( ip, pc->getSocket()->getHostName() );

	identServ = new Socket( SOCK_STREAM, ip, 113 );

	if( identServ->error() )
	{
		out( "Socket error.\n\r" );
		delete socket;
		return;
	}

	if( identServ->connect() == -1 )
	{
		out( "Connect error. Ident server may not be running on foreign host.\n\r" );
		delete identServ;
		return;
	}

	out( "Connected to ident server on " );
	out( identServ->getHostName() );
	out( "\n\r" );

	int foreign_port = pc->getSocket()->getPort();
	int bytes = sprintf( buf, "%d , %d\n\r", foreign_port, 4000 );

	identServ->write( buf, bytes );
	*buf = 0;
	while( !*buf )
		identServ->read( buf, 256 );

	delete identServ;

	out( buf );
}


void PC::do_cat( const String & arg )
{
	if( !(bool)arg )
		return;

	view( arg.chars() );
}


void PC::do_users( const String & )
{
	String str;
	PC *pc;
	LList<PC> tlist = pcs;

	str =  "Name           Host                       Foreign  Idle\n\r";
	str += "                                          Port         \n\r";
	
	for_each( tlist, pc )
	{
		if( pc->getSocket() )
		{
			str.sprintfAdd( "%-15s%-35s%-12d%s\n\r", pc->getName().chars(),
					pc->getSocket()->getHostName(),
					pc->getSocket()->getPort(),
					pc->getIdle() ? itoa(pc->getIdle()) : "" );
		}
		else
		{
			str.sprintfAdd( "%-15s%-35s%-12d%s\n\r", pc->getName().chars(),
					"(*LOST LINK*)", 0,
					pc->getIdle() ? itoa(pc->getIdle()) : "" );
		}
	}

	out( str );
}


void PC::do_echo( const String & arg )
{
	String str;

	str <<  "\n\n\r" << arg << "\n\r";

	outAllCharExcept( str, 0, 0 );
}


void PC::do_immtalk( const String & arg )
{
	PC *ch;
	LList<PC> tlist = pcs;

	String str;

	if( !(bool)arg )
	{
		out( "Immtalk what?\n\r" );
		return;
	}

 	str << BYELLOW << name << " : " << arg << "\n\r" << NTEXT;

	for_each( tlist, ch )
	{
		if( ch->isPlaying() )
		{
			if( ch != this )
				ch->out( "\n\r" );
			ch->out( str );
		}
	}
}


void PC::do_advance( const String & arg )
{
	arg.startArgs();
	String argName	= arg.getArg();
	String argLevel	= arg.getArg();

	if( !(bool)argName || !(bool)argLevel )
	{
		out( "Usage: advance <person> <level>\n\r" );
		return;
	}

	PC *plr = getPCWorld( argName );
	if( !plr )
	{
		out( argName );
		out( " is not online.\n\r" );
		return;
	}

	int lev = argLevel.asInt();
	if( lev < 1 || lev > MAX_PC_LEVEL )
	{
		out( "No can do.\n\r" );
		return;
	}

	// Need to check levels here.
	plr->advance( lev - plr->getLevel() );
	out( "Ok.\n\r" );
}


void PC::do_memory( const String & )
{

	String str;

	str << "NUMBER OF" <<endl;
	str.sprintfAdd("Objects:   %6d        Rooms:     %6d\n\r",
		Object::getTotalCount() ,Room::getTotalCount() );
	str.sprintfAdd("NPCs:      %6d        Repops:    %6d\n\r",
		NPC::getTotalCount(), Repop::getTotalCount() );
	str.sprintfAdd("PCs:       %6d        Affects:   %6d\n\r",
		PC::getTotalCount(), Affect::getTotalCount() );
	str <<         "Actions:   " << Action::getTotalCount() << endl;
	str << "LList nodes (used/allocated): " << 
		Node::allocated_nodes - Node::getFreeCount() << '/' << 
		Node::allocated_nodes << endl;
	str << endl;

#if !defined(WIN32)
	struct rusage use;
	getrusage( RUSAGE_SELF, &use );
	str << "Usage of resources:" << endl;
	str << "User time:     "<< use.ru_utime.tv_sec << "s " << (use.ru_utime.tv_usec/1000) << "ms " <<endl;
	str << "System time:   "<< use.ru_stime.tv_sec << "s " << (use.ru_stime.tv_usec/1000) << "ms " <<endl;
	str << "Page reclaims/faults: "<< use.ru_minflt <<'/'<< use.ru_majflt << endl;
	getrusage( RUSAGE_CHILDREN, &use );
	str << "Same for children:" << endl;
	str << "User time:   "<< use.ru_utime.tv_sec << "s " << (use.ru_utime.tv_usec/1000) << "ms " <<endl;
	str << "System time: "<< use.ru_stime.tv_sec << "s " << (use.ru_stime.tv_usec/1000) << "ms " <<endl;
	str << "Page reclaims/faults: "<< use.ru_minflt <<'/'<< use.ru_majflt << endl;
#endif //WIN32
	out(str);	

/*
	str << "Maximum resident set size: " << use.ru_maxrss <<endl;
	str << "Shared memory size:        " << use.ru_ixrss << endl;
	str << "Data memory size:          " << use.ru_idrss << endl;
	str << "Stack memory size:         " << use.ru_isrss << endl;

	str << "Maximum resident set size: " << use.ru_maxrss <<endl;
	str << "Shared memory size:        " << use.ru_ixrss << endl;
	str << "Data memory size:          " << use.ru_idrss << endl;
	str << "Stack memory size:         " << use.ru_isrss << endl;
*/

}

void GC_dump();
int GC_run();

void PC::do_gc( const String & args )
{
	if ( args == "dump" )
{
	GC_dump();
	out ( "Garbage collector stack dumped.\n\r");   
}
	else if ( args == "run" )
{
	String str;
	str << "Garbage collected " << GC_run() << " VMObjects.\n\r";
	out(str);
}
	else if ( args == "hint" )
	{
		String str;
		str.sprintf("Current (used gc stack)/(gc stack size) is        %d/%d\n\r",
			GC_getStackSize() - GC_getFreeCount() ,GC_getStackSize() );
		str.sprintfAdd("Previous run (used gc stack)/(gc stack size) were %d/%d\n\r",
			GC_stack_hint - GC_free_hint , GC_stack_hint );
		str << "You can tune GC_start_size property if you want to (see help gc).\n\r";
		out(str);
	}
	else
	{
		out ("Usage: gc [dump/run/hint]\n\r");
	}
}

void PC::do_invis( const String & arg )
{
	String str;
	
	int invisLevel;

	if( !(bool)arg )
	{
		if( isInvis() )
		{
			str.sprintf( "You currently invisible at level %d.\n\r",
							getInvisLevel() );
			out( str );
		}
		else
			out( "You are not affected by any invisibility.\n\r" );

		return;
	}
	
	invisLevel = arg.asInt();

	if( invisLevel == 0 )
	{
		if( isInvis() )
		{
			out( "You fade into existence.\n\r" );
			str.sprintf( "\n\r%s fades into existence.\n\r", (const char*)getName() ); 
			in_room->outAllCharExcept( str, this, 0 ); 
		}
	}
	else
	{
		if( !isInvis() )
		{
			out( "You fade out of existence.\n\r" );
			str.sprintf( "\n\r%s fades out of existence.\n\r", (const char *)getName() );
			in_room->outAllCharExcept( str, this, 0 ); 
		}
	}

	setInvisLevel( invisLevel );
}

void PC::do_goto( const String & arg )
{
	String str;
	Char *ch;
	Room *to;

	// Search players first, then NPCs
	if( !( ch = getPCWorld( arg ) ) )
		ch = getNPCWorld( arg );

	if( ch && ch->inRoom() )
		to = ch->inRoom();
	else
	{
		// Now try rooms in this area unless scope: was specified
		Index x( arg );
		if( !(bool)x.getScope() )
			x.setScope( in_room->getArea()->getKey() );

		if( !( to = lookupRoom( x ) ) )
		{
			// Now try global (no scope)
			x.setScope( "" );
			to = lookupRoom( x );
		}
	}

	if( !to )
	{
		out("No such location.\n\r");
		return;
	}

	if( to == in_room )
		return;

	str << "\n\r" << name << " disappears in a puff of smoke.\n\r";
	in_room->outAllCharExcept( str, this, 0 );

	// We can use simple out() since character not in room yet.

	in_room->rmCharInv( this );
	str.clr();
	str << "\n\r" << name << " appears with an ear-splitting BANG!!\n\r";
	to->out( str );
	to->addCharInv( this );
	setOrientation(0); // just testing, so goto can clear dis-orientation
	do_look( "" ); 
}



void PC::do_transfer( const String & arg )
{
	Room *src;
	Room *dest = in_room;
	Char *ch = getPCWorld( arg );

	if( !ch )
	{
		ch = getNPCWorld( arg );
		if( !ch )
		{
			out( "No such character, Coolio.\n\r" );
			return;
		}
	}

	if( !( src = ch->inRoom() ) )
	{
		out( "PC::do_transfer() : victim not in a room." );
		return;
	}

	src->outAllCharExcept( ch->getShort(), ch, 0 );
	src->outAllCharExcept( " dissappears in a mushroom cloud.\n\r", ch, 0 );

	ch->inRoom()->rmCharInv( ch );
	ch->out( shortdesc );
	ch->out( " has transferred you!\n\r" );
	dest->outAllCharExcept( ch->getShort(), ch, 0 );
	dest->outAllCharExcept( " arrives from a puff of smoke.\n\r", ch, 0 );
	dest->addCharInv( ch );
	if( ch->isPC() )
		((PC *)ch)->do_look( "" );
}


void PC::do_slay( const String & arg )
{
	Char *tch;

	if( !(bool)arg )
	{
		out( "\n\rWho shall we be slaying?\n\r" );
		return;
	}

	Char *ch = in_room->getChar( arg );

	if( !ch )
	{
		out( "\n\rHmm, you must need your eyes checked.\n\r" );
		return;
	}

	if( ch == this )
	{
		out( "\n\rAren't we funny today?\n\r" );
		return;
	}

	for_each( in_room->chars, tch )
		if( tch->getFighting() == ch )
			tch->stopFighting();

  	if ( !ch->die( this ) )
		return;
	
	String str;
	ch->out( "\n\n\r** YOU HAVE BEEN SLAIN!!! **\n\r" );
	out( "\n\rAAAAAHG - Blood everywhere!!!\n\r" );
	str << "\n\n\r" << name << " chops " << ch->getShort()
		<< " to pieces!!!\n\r*SPLATTER*\n\r";
   
	in_room->outAllCharExcept( str, this, ch );
  
	if( ch->isNPC() )
	{
		ch->extract();
		ch->fordelete(); 
		return;
	}

	//INCOMPLETE
	ch->inRoom()->rmCharInv( ch ); 
	((PC*)ch)->setState( STATE_MAIN_MENU );  
}


void PC::do_purge( const String & )
{
	Char *ch;
	Object *obj;

	in_room->chars.reset();
	ch = in_room->chars.peek();
	for( ; ch; )
	{
		if( ch->isNPC() )
		{
			out( "Purging " );
			out( ch->getShort() );
			out( ".\n\r" );
			ch->extract();
			ch->fordelete();
			ch = in_room->chars.peek();
			continue;
		}
		// else
		in_room->chars.next();
		ch = in_room->chars.peek();
	}

	in_room->inv.reset();
	while( ( obj = in_room->inv.remove() ) )
	{
		out( "Purging " );
		out( obj->getShort() );
		out( ".\n\r" );
		obj->extract();
		obj->fordelete();
	}
}


void PC::do_ostat( const String & arg )
{
	Object * obj;
	String str;
	if( !(bool)arg )
	{
		out( "Stat what?\n\r" );
		return;
	}

	if( !( obj = inRoom()->getObj( arg ) )
		&& !( obj = getObjWorld( arg ) ) )
	{
		out( "Didn't find any " );
#ifndef _MSC_VER
		out( arg + ".\n\r" );
#else
		out( arg + ( const char *) &(".\n\r") );
#endif /* _MSC_VER */
		return;
	} 

/*	str.sprintf( "Keywords: %s\n\rShort: %s\n\rLong: %s\n\r",
			obj->getName().chars(), obj->getShort().chars(),
			obj->getLong().chars() );
*/
	obj->describeItself( str );
	if( obj->inObj() )
		str.sprintfAdd( "Inside: %s\n\r", obj->inObj()->getShort().chars() );
	else if( obj->inChar() )
		str.sprintfAdd( "Carried by: %s\n\r", obj->inChar()->getShort().chars() );
	else if( obj->inRoom() )
		str.sprintfAdd( "Location: %s\n\r", obj->inRoom()->getName().chars() );
	else str += "Object is NOWHERE!!\n\r";

/*	OutputBuffer ob(1000);
	obj->writeTo(ob);
	str << ob.getDataAsString();
	*/
	out( str );
}

void PC::do_mstat( const String & arg )
{
	Char * ch;
	String str;
	if( !(bool)arg )
	{
		out( "Stat whom?\n\r" );
		return;
	}

	if( !( ch = inRoom()->getNPC( arg ) )
		&& !( ch = getNPCWorld( arg ) ) )
	{
		out( "Didn't find any " );
#ifndef _MSC_VER
		out( arg + ".\n\r" );
#else
		out( arg + ( const char * ) &(".\n\r") );
#endif /* _MSC_VER */
		return;
	} 

/*	str.sprintf( "Keywords: %s\n\rShort: %s\n\rLong: %s\n\r",
			ch->getName().chars(), ch->getShort().chars(),
			ch->getLong().chars() );
*/
	ch->describeItself( str );

	str.sprintfAdd( "Location: %s\n\rHp: %d\n\r",
			ch->inRoom()->getName().chars(), ch->getHP() );
	out( str );
}

void PC::do_rstat( const String & arg )
{
	String str;
	if ( arg )
	{
		out("Sorry, rstat works only for current room for now");
		return;
	}
	inRoom()->describeItself( str );
	out (str);
}

void PC::do_mwhere( const String & arg )
{
	String str( 4096 );
	NPC * pNPC;
	if( !(bool)arg )
	{
		out( "Look for what?\n\r" );
		return;
	}

	for_each( npcs, pNPC )
	{
		if( pNPC->isName( arg ) )
			str.sprintfAdd( "%s at location: %s\n\r",
				pNPC->getShort().chars(),
				pNPC->inRoom()->getName().chars() );
	}
	out( str );
}

void PC::do_page( const String & )
{

}



void PC::do_reboot( const String & arg )
{
	void loadSocials();
	void loadHelps();
	void loadTitle();

	String str;

	if( !(bool)arg )
	{
		out( "Usage:    reboot <option>\n\n\r" );
		out( "Options are:  server world helps socials programs title\n\r" );
		return;
	}

	if( arg == "server" )
	{
		DOWN = 1;
		REBOOT = 1;
		str << "\n\rRebooted by " << name << "\n\n\r";
		out( str );
	}
	else if( arg == "socials" )
	{
		Social * social;
		int ihash;

		for( ihash = 0; ihash < 26; ihash++ )
		{
			social_table[ihash].reset();
			while( ( social = social_table[ihash].remove() ) )
				delete social;
		}

		loadSocials();
		out( "Socials reloaded from database.\n\r" );
	}
	else if( arg == "title" )
	{
		loadTitle();
		out( "Title screen reloaded.\n\r" );
	}
}


void PC::do_shutdown( const String & )
{
	String str;
	DOWN = 1;
	str << "\n\rShutdown by " << name << "\n\n\r";
	out( str );
}


void PC::do_rfind( const String & arg )
{
	bool global = false;
//	bool wildcard = false;
	String str( BUF * 2 );
	const Room * ptr;
	Area *area = in_room->getArea();

	// Sorry to mess your code, Fusion, but '*' seems to more in convention
	// than "all" - Artur
	if( arg == "*" )
	{
		global = true;
		for_each( areas, area )
		{
			str << "\n\r--:" << area->getName() << ":--\n\r";
			for_each( area->roomIndex, ptr )
			{
				str.sprintfAdd( "%-30s%-40s\n\r",
						ptr->getKey().chars(),
						ptr->getName().chars() );
			}
		}
	}
	else if ( arg )
	{
		area = lookupArea( arg );
		if ( !area )
		{
			str << "Unknown area " << arg << endl;
		   	out( str );
		   	return;
		}

		str << "Rooms in area " << arg << ":" << endl;
		str << "-----------------------\n\r";
		for_each( area->roomIndex, ptr )
		{
			str.sprintfAdd( "%-30s%-40s\n\r",
					ptr->getKey().chars(),
					ptr->getName().chars() );
		}

	}
	else
	{
		str << "Rooms in this area:\n\r-----------------------\n\r";

		for_each( area->roomIndex, ptr )
		{
			str.sprintfAdd( "%-30s%-40s\n\r",
					ptr->getKey().chars(),
					ptr->getName().chars() );
		}
	}

	out( str );
}



void PC::do_ofind( const String & arg )
{
	String str( BUF * 2 );
	String strName;
	String strArea;
	const Object * ptr;
	Area *area;
	bool wildcard = false;
	bool global = false;

	if( !(bool)arg )
	{
		out( "Find what?\n\r" );
		return;
	}

	// Use index object to parse arg
	Index tempIndex( arg );
	strName = tempIndex.getKey();
	strArea = tempIndex.getScope();
	
	HashTable<Object> *objHashTable;

	if( strArea == "*" )
		global = true;

	if( strName == "*" )
		wildcard = true;

	str	<< "Looking up [" << strName << "]\n\r-------------\n\r";

	if( !global )
	{
		if( !(bool)strArea )
			objHashTable = &in_room->getArea()->objIndex; 
		else
		{
			if( !( area = lookupArea( strArea ) ) )
			{
				str << "Unknown area " << strArea << "\n\r";
				out( str );
				return;
			}
	
			objHashTable = &area->objIndex;
		}

		for_each( (*objHashTable), ptr )
		{
			if( !wildcard && !ptr->isName( strName ) )
			{
				objHashTable->next();
				continue;
    		}
 
			str.sprintfAdd( "%-30s%-40s\n\r",
					objHashTable->getKey().chars(),
					ptr->getShort().chars() );
		}
	}
	else
	{
		for_each( areas, area )
		{
			objHashTable = &area->objIndex;
			for_each( (*objHashTable), ptr )
			{
				if( !wildcard && !ptr->isName( strName ) )
					continue;
	
				str.sprintfAdd( "%17s:%-30s%-31s\n\r",
						area->getKey().chars(),
						objHashTable->getKey().chars(),
						ptr->getShort().chars() );
			}
		}
	}

	out( str );
}


void PC::do_owhere( const String & arg )
{
	Object *obj;
	String str( BUF );

	if( !(bool)arg )
		return;

	for_each( objects, obj )
	{
		if( !obj->isName( arg ) )
			continue;
		else if( obj->inRoom() )
			str.sprintfAdd( "%-20s in room %20s\n",
					obj->getShort().chars(), obj->inRoom()->getName().chars() );
		else if( obj->inChar() )
			str.sprintfAdd( "%-20s carried by %20s\n",
					obj->getShort().chars(), obj->inChar()->getShort().chars() );
		else if( obj->inObj() )
			str.sprintfAdd( "%-20s inside %20s\n",
					obj->getShort().chars(), obj->inObj()->getShort().chars() );
		else
			str.sprintfAdd( "%-20s is just sort of floating around! BUG!\n",
					obj->getShort().chars() );
	}

	if( !(bool)str )
		str.sprintf( "Could not find any %s.\n\r", arg.chars() );

	out( str );
}


void PC::do_mfind( const String & arg )
{
	String str( BUF * 2 );
	String strName;
	String strArea;
	const NPC *ptr;
	Area *area;
	bool global = false;
	bool wildcard = false;

	if( !(bool)arg )
	{
		out( "Find what?\n\r" );
		return;
	}

	HashTable<NPC> *npcHashTable;

	// Use index constructor to parse the string
	Index tempIndex( arg );
	strArea = tempIndex.getScope();
	strName = tempIndex.getKey();

	if( strArea == "*" )
		global = true;

	if( strName == "*" )
		wildcard =  true;

	str	<< "Looking up [" << strName << "]\n\r-------------\n\r";

	if( !global )
	{
		if( !(bool)strArea )
			npcHashTable = &in_room->getArea()->npcIndex; 
		else
		{
			if( !( area = lookupArea( strArea ) ) )
			{
				str << "Unknown area " << strArea << "\n\r";
				out( str );
				return;
			}
	
			npcHashTable = &area->npcIndex;
		}

		for_each( (*npcHashTable), ptr )
		{
			if( !wildcard && !ptr->isName( strName ) )
			{
				npcHashTable->next();
				continue;
     		}

			str.sprintfAdd( "%-30s%-40s\n\r",
					npcHashTable->getKey().chars(),
					ptr->getShort().chars() );
		}
	}
	else
	{
		for_each( areas, area )
		{
			npcHashTable = &area->npcIndex;
			for_each( (*npcHashTable), ptr )
			{
				if( !wildcard && !ptr->isName( strName ) )
					continue;

				str.sprintfAdd( "%17s:%-25s%-31s\n\r",
						area->getKey().chars(),
						npcHashTable->getKey().chars(),
						ptr->getShort().chars() );
			}
		}
	}

	out( str );
}

void PC::do_cset( const String & )
{
}

void PC::do_grant( const String & arg )
{
	PC *ch;
	String person;
	String privilege;
	int bit;

	arg.startArgs();
	privilege	= arg.getArg();
	person		= arg.getArg();

	if( !(bool)person || !(bool)privilege )
	{
		out( "grant <privilege> <person>\n\r" );
		out( "Available privs:\n\r" );
		for( bit = 1; ; bit++ )
		{
			if(  priv_bit_list[bit].val )
			{
				out( "  " );
				out( getPrivBitName( bit ) );
				if( ! ( bit % 4 ) )
					out( "\n\r" );
			}
			else
			{
				out( "\n\r" );
				return;
			}
		}
		return;
	}

    if( !( ch = getPCWorld( person ) ) )
    {
        out( "Could not find anyone by that name.\n\r" );
        return;
    }

	if( privilege == "all" )
	{
		// Add your individual privs here, setting mass bits not
		// good in this case. -Fusion

		// SUPERUSER and DIRECTOR are better left out.
		ch->setPrivBit( N_ADMIN );
		ch->setPrivBit( N_OPERATOR );
		ch->setPrivBit( N_MASTERBUILDER );
		ch->setPrivBit( N_BUILDER );
		ch->setPrivBit( N_QUESTER );
		ch->setPrivBit( N_WIZARD );
		ch->out( "You have been granted primary privileges.\n\r" );
		out( "Primary privileges granted to " );
#ifndef _MSC_VER
		out( ch->getName() + ".\n\r" );
#else
		out( ch->getName() + ( const char * ) &(".\n\r") );
#endif /* _MSC_VER */
		ch->save();
	}
	else
	{
		bit = getPrivBit( privilege.chars() );
		if( !bit )
		{
			out( "No such privilege to grant.\n\r" );
			return;
		}

		ch->setPrivBit( bit );
		out( "Privilege granted to " );
		out( ch->getName() );
		out( ".\n\r" );
		ch->out( "You have been granted '" );
		ch->out( getPrivBitName( bit ) );
		ch->out( "' privileges.\n\r" );
		ch->save();
	}
}


void PC::do_revoke( const String & arg )
{
	PC *ch;
	int bit;
	String privilege;
	String person;

	arg.startArgs();

	privilege	= arg.getArg();
	person		= arg.getArg();

	if( !(bool)person || !(bool)privilege )
	{
		out( "revoke <privilege> <person>\n\r" );
		out( "Available privs:\n\r" );
		for( bit = 1; ; bit++ )
		{
			if( priv_bit_list[bit].val )
			{
				out( "  " );
				out( getPrivBitName( bit ) );
				if( ! ( bit % 4 ) )
					out( "\n\r" );
			}
			else
			{
				out( "\n\r" );
				return;
			}
		}
		return;
	}

    ch = getPCWorld( person );
    if( !ch )
    {
        out( "Could not find anyone by that name.\n\r" );
        return;
    }

	if( privilege == "all" )
	{
		ch->clrPrivBits();
		ch->out( "All your privileges have been revoked!\n\r" );
		out( "Revoking all privileges from " );
#ifndef _MSC_VER
		out( ch->getName() + ".\n\r" );
#else
		out( ch->getName() + (const char *) &(".\n\r") );
#endif /* _MSC_VER */
		ch->save();
		return;
	}
	else
	{
		bit = getPrivBit( privilege );
		if( !bit )
		{
			out( "No such privilege to revoke.\n\r" );
			return;
		}

		ch->rmPrivBit( bit );
		out( "Privilege revoked from " );
		out( ch->getName() );
		out( ".\n\r" );
		ch->out( "Your '" );
		ch->out( getPrivBitName( bit ) );
		ch->out( "' privilege has been revoked.\n\r" );
		ch->save();
	}
}


void PC::do_privileges( const String & arg )
{
	PC *pc = this;
	bool found = false;
	int bit;
	int count = 1;

	if( arg )
		pc = getPCWorld( arg );

	if( !pc )
	{
		out( "No such person.\n\r" );
		return;
	}

	out( "Privileges granted to " );
	out( pc->getName() );
	out( ":\n\r" );

	for( bit = 1; ; bit++ )
	{
		if( priv_bit_list[bit].val )
		{
			if( pc->authorized( BIT(bit) ) )
			{
				found = true;
				out( "  " );
				out( getPrivBitName( bit ) );
				if( ! ( count % 4 ) )
					out( "\n\r" );
				count++;
			}
		}
		else
		{
			out( "\n\r" );
			return;
		}
	}

	if( !found )
	{
		out( "None.\n\r" );
		return;
	}
}

#include "vmachine.h"
#include "asmloader.h"

void PC::do_vm( const String & args )
{
	String arg1;
	String arg2;
	String arg3;
	VMachine * vm;

	if ( !vmachine_enabled)
	{
		out("VMachine disabled.\n\r");
		return;
	}

	args.startArgs();
	arg1 = args.getArg();

	if ( arg1 == "ftest" )
	{
		// will be disabled soon, as it can crash mud if called for
		// non ( PC, string) argument function
		arg2 = args.getArg();
		arg3 = args.getArgRest();
		int fun = lookup_vmfun_number( arg2.chars() );
		if ( fun < 0 )
	{
		out("No such fun.");
		return;
	}
		vm = getFreeVM();
		vm->defaultValues();
		vm->push_string( arg3 );
		vm->push_obj( VMT_PC, this );
		vm->run(fun);
		return;
	}
	else if ( arg1 == "info" )
	{
		arg2 << "Sizeof VM is " << (int) sizeof (VMachine) << endl;
		arg2 << "Sizeof String is " << (int) sizeof (String) << endl;
		arg2 << "Sizeof vmfun is " << (int) sizeof (vmfun) << endl;
		arg2 << "There are:" << endl;
		arg2 << vmfun_table.length() << " vmfunctions" << endl;
		arg2 << vmstatvar_table.length() << " static variables" << endl;
		arg2 << vmconstant_table.length() << " constants" << endl;
		VMstatistic( arg2 );
		out( arg2 );
		return;
	}
	else
	{
		out ( "Usage:\n\r\tvm ftest name_of_fun\n\r\tvm info\n\r");
		return;
	}
}


void PC::do_proset( const String & args )
{
	Property * prop;
	String arg1;
	String arg2;
	const char * txt;

	args.startArgs();
	arg1 = args.getArg();

	if ( !(prop = properties.lookup(arg1) ) )
	{
		out("No such property.");
		return;
	}
	arg2 = args.getArgRest();
	txt = prop->parseValue(arg2);
 	if ( !txt )
	{
		out("You managed to change this value\n\rRemeber to save changes.\n\r");

		return;
	}
	out("You failed to change this value because:\n\r");
	out(txt);
	return;
}

void PC::do_prodisplay( const String & args )
{
	Property * prop;
	String str;

	int nprop = 0;
	if ( !args )
	{
		for_each( properties, prop )
		{
			str.sprintfAdd("%c %-6.6s %-25.25s %-40.40s\n\r",
				(prop->getRuntime() ? 'T' : 'R'), prop->getTypeName(),
				prop->getName().chars(), prop->asText());
			nprop++;
		}
		str << "Displayed " << nprop << " properties.\n\r";
		out(str);
		return;
	}

	prop = properties.lookup(args);
	if ( !prop )
	{
		out("No such property");
		return;
	}

	str << "Name: " << prop->getName() << endl;
	str << "R/T Type: " << (prop->getRuntime() ? "runTime" : "Reboot" )<< endl;
	str << "Type: " << prop->getTypeName() << endl;
	str << "Value: " << prop->asText() << endl;
	str << "Description: " << endl;
	out(str);

	str.clr();
	str << "../help/propert/" << prop->getName();
	view(str.chars());
}

#define DEF_PRO_BACKUP "../etc/backup.pro"

void PC::do_prosave( const String & args )
{
	if ( args )
	{
		if ( !args.legalFilename() )
		{
			out("Wrong filename specified\n\r");
			return;
		}
		String str;
		str << "../etc/" << args << ".pro";
		OutputFile of( str.chars() );
		saveProperties(of);
		out("Properties saved to file ...\n\r");
		return;
	}
	unlink(DEF_PRO_BACKUP);
	rename(DEFAULT_PROPERTIES_FILE, DEF_PRO_BACKUP);
	OutputFile of( DEFAULT_PROPERTIES_FILE );
	saveProperties(of);
	out("Created backup and saved new properties as default.\n\r");
}

void PC::do_proload( const String & args )
{
	String str;
	
	if ( args )
	{
		if ( !args.legalFilename() )
		{
			out("Illegal filename.n\r");
			return;
		}
		str << "../etc/" << args << ".pro";
		InputFile inf(str);
		if ( !inf )
		{
			out("No such file (remember to omit .pro suffix).\n\r");
			return;
		}
		str.clr();
   		loadProperties( inf, str );
	}
	else
	{
		InputFile inf(DEFAULT_PROPERTIES_FILE);
		if ( !inf )
		{
			out("No default properties file.\n\r");
			return;
		}
		loadProperties( inf, str );
	}
	out ( "Properties loaded with following info:\n\r");
	out( str );
	return;
}

void PC::do_probackup( const String & args )
{
	String str;
	if ( !args.legalFilename() )
	{
		out("Illegal filename\n\r");
		return;
	}
	InputFile inf( DEFAULT_PROPERTIES_FILE );
	if ( !inf )
	{	
		out("No default properties file (mudpp.pro) to backup\n\r");
		return;
	}
	if ( args )
		str << "../etc/" << args << ".pro";
	else
		str << DEF_PRO_BACKUP;
	OutputFile outf( str.chars() );
	outf.largewrite( inf.getBuf(), inf.size() );
	out("Backup sucessful.\n\r");
}

void PC::do_prorestore( const String & args )
{
	String str;
	if ( !args.legalFilename() )
	{
		out("Illegal filename");
		return;
	}
	if ( args )
		str << "../etc/" << args << ".pro";
	else
		str << DEF_PRO_BACKUP;

	InputFile inf(str);
	if ( !inf )
	{
		out("No such property file");
		return;
	}
	OutputFile outf( DEFAULT_PROPERTIES_FILE );
	outf.largewrite( inf.getBuf(), inf.size() );
	out("Restore sucessful.\n\r");
}