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

#include "config.h"
#include "string.h"
#include "llist.h"
#include "hash.h"
#include "server.h"
#include "room.h"
#include "bit.h"
#include "spell.h"
#include "pc.h"
#include "mudobj.h"
#include "area.h"
#include "shop.h"

#include "global.h"

void PC::do_cast( const String & arg )
{
	String str;
	String extra_args;
	char targetbuf[ 256 ];
	MudObject * target = 0;

	targetbuf[0] = 0;
	const SpellType * stp = lookupSpell( arg.chars(), targetbuf );

	if( !stp )
	{
		out( "You know of no such incantation.\n\r" );
		return;
	}

	// Didnt specify a target: cast control weather worse, cast sanc
	if ( !*targetbuf )
	{
		// Its a no target spell
		if ( IS_SET( &stp->target_bits, TAR_NONE ) )
			;
		else if ( IS_SET( &stp->target_bits, TAR_SELF ) )
			target = this;
		else if ( IS_SET( &stp->target_bits, TAR_ROOM ) )
			target = in_room;
		else if ( IS_SET( &stp->target_bits, TAR_AREA ) )
			target = in_room->getArea();
		else
		{
			out( "What do you want to cast this spell on?\n\r" );
			return;
		}
	}
	else
	{
		str = targetbuf;

		// If spell takes no target, just set the extra args
		// to whatever the command line is (the target_buf is
		// stuff after the spell name)
		if ( IS_SET( &stp->target_bits, TAR_NONE ) )
		{
			extra_args = targetbuf;
		}
		else if ( str == "self" )
		{
			if ( !IS_SET( &stp->target_bits, TAR_SELF ) 
			&&   !IS_SET( &stp->target_bits, TAR_ANY ) )
			{
				out( "You can't cast this spell on yourself!\n\r" );
				return;
			}
			else
				target = this;
		}
		else if ( str == "room" )
		{
			if ( !IS_SET( &stp->target_bits, TAR_ROOM )
			&&   !IS_SET( &stp->target_bits, TAR_ANY ) )
			{
				out( "You can't cast this spell on the room!\n\r" );
				return;
			}
			else
				target = in_room;
		}
		else if ( str == "area" )
		{
			if ( !IS_SET( &stp->target_bits, TAR_AREA )
			&&   !IS_SET( &stp->target_bits, TAR_ANY ) )
			{
				out( "You can't cast this spell on the area!\n\r" );
				return;
			}
			else
				target = in_room->getArea();
		}
		else
		{
			// ok str is either an object or a char
			target = inRoom()->getChar( str );
			if ( target )
			{
				// its a char
				if ( !IS_SET( &stp->target_bits, TAR_CHAR )
				&&   !IS_SET( &stp->target_bits, TAR_ANY ) )
				{
					out( "You can't cast this spell on that!\n\r" );
					return;
				}

				if ( target == this
				&&   !IS_SET( &stp->target_bits, TAR_SELF ) )
				{
					out( "You can't cast that on yourself!\n\r" );
					return;	
				}
			}
			else
			{
				// not a char so its probably an obj
				target = inRoom()->getObj( str );
				if ( target )
				{
					if ( !IS_SET( &stp->target_bits, TAR_OBJECT )
					&&   !IS_SET( &stp->target_bits, TAR_ANY ) )
					{
						out( "You can't cast this spell on that!\n\r" );
						return;
					}
				}
				else
				{
					// ack its nothing
					out( "Your target is not here.\n\r" );
					return;
				}
			}
		}
	}

	out( "You concentrate deeply while uttering each word of the incantation.\n\r" );

	// This doesn't cast right away; it launches an action.
	cast( stp, target, extra_args );
}


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

	if( !( obj = getObjInv( arg ) ) )
	{
		out( "You don't have that.\n\r" );
		return;
	}

	if( obj->isCompass() )
	{
		interp( "You pull out $o and look at it.\n\r", 0, 0, obj, 0 );
		inRoom()->interp( "$n pulls out $o and looks at it for a moment.\n\r", this, 0, obj, 0 );
		if( getOrientation() )
		{
			out( "You have a better sense of direction now.\n\r" );
			inRoom()->interp( "$n turns and looks north.\n\r", this, 0, 0, 0 );
			setOrientation(0);
			return;
		}
		out( "The compass points north.\n\r" );
		return;
	}

	// Add other use object types

	out( "What do you want to use it for?\n\r" );
}


void PC::do_open( const String & arg )
{
	Exit * door;
	int dir;

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

	dir = getDir( arg[0] );
	if( dir == DIR_UNDEFINED )
	{
		out( "Nothing to open in that direction.\n\r" );
		return;
	}

	door = in_room->getExit( dir );
	if( !door )
		return;
	else if( door->isOpen() )
	{
		out( "It's already open.\n\r" );
		return;
	}

	open( door );
	out( "You open the door.\n\r" );
}


void PC::do_close( const String & arg )
{
	Exit * door;
	int dir;

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

	dir = getDir( arg[0] );
	if( dir == DIR_UNDEFINED )
	{
		out( "Nothing to close in that direction.\n\r" );
		return;
	}

	door = in_room->getExit( dir );
	if( !door )
		return;
	else if( door->isClosed() )
	{
		out( "It's already closed.\n\r" );
		return;
	}

	close( door );
	out( "You close the door.\n\r" );
}


void PC::do_quaff( const String & arg )
{
	if( !(bool)arg )
	{
		out( "Quaff what?\n\r" );
		return;
	}

	Object *obj = getObjInv( arg.chars() );
	if( !obj )
	{
		out( "You don't have that.\n\r" );
		return;
	}

	if( !obj->isPotion() && !obj->isLiquidContainer() )
	{
		out( "You can't drink that.\n\r" );
		return;
	}

	quaff( obj );
}


void PC::do_eat( const String & arg )
{
	String str;
	if( !(bool)arg )
	{
		out( "Eat what?\n\r" );
		return;
	}

	Object *obj = getObjInv( arg.chars() );
	if( !obj )
	{
		out( "You don't have that.\n\r" );
		return;
	}

	if( !obj->isFood() )
	{
		// Wizards can eat anything
		if( authorized( WIZARD ) )
		{
			rmObjInv( obj );
			obj->extract();
			str << getShort() << " eats " << obj->getShort() << ".\n\r";
			inRoom()->outAllCharExcept( str, this, 0 );
			str.clr();
			str << "You eat " << obj->getShort() << ".\n\r";
			out( str );
			obj->fordelete();
			return;
		}

		out( "You can't eat that.\n\r" );
		return;
	}

	eat( obj );
}




void PC::do_drop( const String & arg )
{
	String str;
	Object *obj;
	String arg1;
	String arg2;
	long num = -1;

	arg.startArgs();

	arg1	= arg.getArg();
	arg2	= arg.getArg();

	if( arg1.isNumber() )
	{
		if( !(bool)arg2 )
		{
			out( "Drop what?\n\r" );
			return;
		}

		num = arg1.asInt();
	}

	if( num > 1 )
	{
		if( !(bool)arg2 )
		{
			out( "Drop what?\n\r" );
			return;
		}

		if( arg2 == "coins" || arg2 == "gold" )
		{
			if( gold <= 0 )
			{
				out( "Forget it, you are broke!\n\r" );
				return;
			}

			if( gold < (unsigned long)num )
			{
				out( "Very generous of you, but you aren't that wealthy.\n\r" );
				return;
			}

			gold -= num;

			obj = new ObjGold();
			obj->setName( "gold pieces coins" );
			obj->setShort( "a pile of gold" );
			obj->setLong( "a pile of gold is here."	);
			obj->setCost( num );
			out( "You drop some gold.\n\r" );
			str << shortdesc << " drops some gold pieces.\n\r";
			in_room->outAllCharExcept( str, this, 0 );
			obj->toWorld();
			in_room->addObjInv( obj );
			return;
		}
	}

	if( num == 1 )
	{
		if( arg2 == "coin" || arg2 == "gold" )
		{
			if( gold <= 0 )
			{
				out( "Forget it, you are broke!\n\r" );
				return;
			}

			obj = new ObjGold();
			obj->setName( "gold piece coin" );
			obj->setShort( "a gold piece" );
			obj->setLong( "a gold piece lies here in the dust."	);
			obj->setCost( 1 );
			obj->toWorld();
			in_room->addObjInv( obj );
			out( "You drop a piece of gold.\n\r" );
			str << shortdesc << " drops a piece of gold.\n\r";
			in_room->outAllCharExcept( str, this, 0 );
			gold--;
			return;
		}
		else
			arg1 = arg2;
	}

	obj = getObjInv( arg1 );

	if( obj )
	{
		if (!drop( obj ))
			return;
		str << "\n\rYou drop " << obj->getShort() << ".\n\r";
		out( str );
		str.clr();
		str << "\n\r" << name << " drops " << obj->getShort() << ".\n\r";
		in_room->outAllCharExcept( str, this, 0 );
		return;
	}

	out( "You don't have that.\n\r" ); 
}


void PC::do_get( const String & arg )
{

	String str;
	Object *obj;
	Object *container = 0;
	String arg1;
	String arg2;
	int num = -1;

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

	arg.startArgs();

	arg1 = arg.getArg();
	arg2 = arg.getArg();

	if( arg1 == "all" )
	{
		if( !(bool)arg2 )
		{
			out( "Don't be so greedy.\n\r" );
			return;
		}

		if( arg2 == "in" || arg2 == "from" )
			arg2 = arg.getArg();

		if( !(bool)arg2 )
		{
			out( "Get all from what?\n\r" );
			return;
		}

		countedThing cI(arg2);
		container = getObjInv( cI );
		if ( container == NULL )
		{
			container = in_room->getObj( cI );
			if ( container == NULL )
			{
				out( "You don't see the " );
				out( arg2 + ".\n\r" );
				return;
			}
		}

		if( !container->isContainer() && !container->isCorpse() )
		{
			out( "Nothing there.\n\r" );
			return;
		}

		container->inv.reset();
		if( !container->inv.peek() )
		{
			out( "There is nothing in " );
			out( container->getShort() );
			out( ".\n\r" );
			return;
		}

		while( ( obj = container->inv.remove() ) )
		{
			out( "You get " );
			out( obj->getShort() );
			out( " from " );
			out( container->getShort() );
			out( ".\n\r" );
			addObjInv( obj );
		}

		return;
	}

	if( arg1.isNumber() )
		num = arg1.asInt();

	// Add plural case
	//

	if( !(bool)arg2 )
	{
		if( ( obj = in_room->getObj( arg1 ) ) )
		{
			if( obj->isGold() )
			{
				str << "You get " << obj->getCost() << " pieces of gold.\n\r";
				out( str );
				str.clr();
				str << "\n\r" << shortdesc << " gets " << obj->getShort() << ".\n\r";
				in_room->outAllCharExcept( str, this, 0 );
				gold += obj->getCost();
				obj->extract();
				obj->fordelete();
				return;
			}
			else
			{
				if (!get( obj ))
					return;
			}
	
			str << "\n\rYou get " << obj->getShort() << ".\n\r";
			out( str );
	
			str.clr();
			str << "\n\r" << name << " gets " << obj->getShort() << ".\n\r";
 	
			in_room->outAllCharExcept( str, this, 0 );
			return;
		}
		out( "You don't see the " );
		out( arg1 );
		out( ".\n\r" );
		return;
	}

	// arg2 passed so get a container in room or inv

	countedThing cI(arg2);
	container = getObjInv( cI );
	if ( container == NULL )
	{
		container = in_room->getObj( cI );
		if ( container == NULL )
		{
			out( "You don't see the " );
			out( arg2 + ".\n\r" );
			return;
		}
	}

	if( !container->isContainer() && !container->isCorpse() )
	{
		out( "Nothing there.\n\r" );
		return;
	}

	if( !( obj = container->getObjInv( arg1 ) ) )
	{
		out( "It's not in the " );
		out( container->getShort() );
		out( ".\n\r" );
		return;
	}

	if ( !get(obj, container) )
		return;

	str << "You get " << obj->getShort() << " from " << container->getShort()
		<< ".\n\r";
	out( str );
	str.clr();
	str << getShort() << " gets " << obj->getShort() << " from "
		<< container->getShort() << ".\n\r";
	inRoom()->outAllCharExcept( str, this, 0 );
}


void PC::do_put( const String & arg )
{
	String arg1;
	String arg2;
	Object * obj;
	Object * container;

	arg.startArgs();

	arg1 = arg.getArg();
	arg2 = arg.getArg();

	if( !(bool)arg1 )
	{
		out( "Eh?\n\r" );
		return;
	}

	obj = getObjInv( arg1 );
	if( !obj )
	{
		out( "You don't have that.\n\r" );
		return;
	}

	if( !(bool)arg2 )
	{
		out( "Put it in what?\n\r" );
		return;
	}

	countedThing cI(arg2);

	if ( !(container = getObjInv(cI) ) )
	{
		if ( !(container = in_room->getObj(cI) ) )
		{
			out( "Don't see that container.\n\r" );
			return;
		}
	}

	if ( container == obj )
	{
		out( "You cannot put it into itself.\n\r");
		return;
	}

	if ( !put( obj, container ) )
		return;

	out( "You put " );
	out( obj->getShort() );
	out( " in " );
	out( container->getShort() );
	out( ".\n\r" );
	
}


void PC::do_up( const String & )
{
	if( fighting )
	{
		out( "You are in the middle of battle!\n\r" );
		return;
	}
 
	if( in_room->getExit( DIR_UP ) )
	{
		if( moveDir( DIR_UP ) )
			do_look( "" ); 
	}
	else out("You can't go that way.\n\r"); 
}


void PC::do_down( const String & )
{
	if( fighting )
	{
		out( "You are in the middle of battle!\n\r" );
		return;
	}
 
	if( in_room->getExit( DIR_DOWN ) )
	{
		if( moveDir( DIR_DOWN ) )
			do_look( "" ); 
	}
	else out("You can't go that way.\n\r"); 
}


void PC::do_north( const String & )
{
	if( fighting )
	{
		out( "You are in the middle of battle!\n\r" );
		return;
	}
 
	int dir = ( DIR_NORTH + orientation ) % DIR_UP;
	if( in_room->getExit( dir ) )
	{
		if( moveDir( dir ) )
			do_look( "" ); 
	}
	else out("You can't go that way.\n\r"); 
}


void PC::do_south( const String & )
{
	if( fighting )
	{
		out( "You are in the middle of battle!\n\r" );
		return;
	}
 
	int dir = ( DIR_SOUTH + orientation ) % DIR_UP;
	if( in_room->getExit( dir ) )
	{
		if( moveDir( dir ) )
			do_look( "" ); 
	}
	else out("You can't go that way.\n\r"); 
}


void PC::do_east( const String & )
{
	if( fighting )
	{
		out( "You are in the middle of battle!\n\r" );
		return;
	}
 
	int dir = ( DIR_EAST + orientation ) % DIR_UP;
	if( in_room->getExit( dir ) )
	{
		if( moveDir( dir ) )
			do_look( "" );
	}
	else out("You can't go that way.\n\r"); 
}


void PC::do_west( const String & )
{
	if( fighting )
	{
		out( "You are in the middle of battle!\n\r" );
		return;
	}
 
	int dir = ( DIR_WEST + orientation ) % DIR_UP;
	if( in_room->getExit( dir ) )
	{
		if( moveDir( dir ) )
			do_look( "" ); 
	}
	else out("You can't go that way.\n\r"); 
}


void PC::do_wear( const String & arg )
{
	if( !(bool)arg )
	{
		out( "\n\rWhat do you want to wear?\n\r" );
		return;
	}

	Object *obj = getObjInv( arg );
	if( !obj )
	{
		out( "\n\rYou dont have that.\n\r" );
		return;
	} 

	if( !obj->isWearable() )
	{
		out( "\n\rYou can't wear that.\n\r" );
		return;
	}

	int wear_pos = 1;
	while( wear_pos <= EQ_MAX ) 
	{
		if( canWear( obj, wear_pos ) )
		{ 
			if( IS_SET( eq_bits, wear_pos ) )
			{
				out( "\n\rYou already wear something there.\n\r" );
			}
			else
			{
			   	if ( !wear( obj, wear_pos ) )
					return;

				out( "Ok.\n\r" );
				return;
			}
		}

		wear_pos++; 
	}
}


void PC::do_remove( const String & arg )
{
	if( !(bool)arg )
	{
		out( "\n\rWhat do you want to remove?\n\r" );
		return;
	}

	Object *obj = getObjWear( arg );

	if( !obj )
	{
		out( "\n\rYou aren't wearing that.\n\r" );
		return;
	}

	if ( !remove( obj ) )
		return;

	out( "\n\rOk.\n\r" );
}


void PC::do_hide( const String & )
{
	out( "Feature not implemented yet. --Fusion\n\r" );
}

void PC::do_sneak( const String & )
{
	out( "Feature not implemented yet. --Fusion\n\r" );
}

void PC::do_study( const String & )
{
	out( "Feature not implemented yet. --Fusion\n\r" );
}

void PC::do_practice( const String & )
{
	out( "Feature not implemented yet. --Fusion\n\r" );
}


// Buy/sell code lacks item type discrepancy, alignment, charisma
// etc. but it is functional enough for you to code your own for now.

void PC::do_buy( const String & arg )
{
	Object *obj;
	String str;
	Char *keeper;
	int cost;
	String arg1;
	String arg2;
	arg.startArgs();
	arg1 = arg.getArg();
	arg2 = arg.getArg();

	if( !arg1 )
	{
		out( "Buy what?\n\r" );
		return;
	}

	for_each( inRoom()->chars, keeper )
	{
		if( keeper->isShopKeeper() && (!arg2 || keeper->isName(arg2) ) )
			break;
	}

	if( !keeper )
	{
		if ( !arg2 )
			out( "There is no shopkeeper here.\n\r" );
		else
			out( "There is no shopkeeper here with that name.\n\r");
		return;
	}

	if( !( obj = keeper->getObjInv( arg1 ) ) )
	{
		out( keeper->getShort() );
		out( " tells you, \"I don't have that.\"\n\r" );
		return;
	}

	cost = ((ShopKeeper *)keeper)->sellValue(obj);
	
	if ( cost == SHOPKEEPER_NOT_TRADING )
	{
		out( keeper->getShort() );
		out( " tells you, \"I have no such an item.\"\n\r" );
		return;
	}

	if( getGold() < cost )
	{
		out( keeper->getShort() );
		out( " tells you, \"You can't afford it. Go get a job.\"\n\r" );
		return;
	}

	str << getShort() << " buys " << obj->getShort() << ".\n\r";
	inRoom()->outAllCharExcept( str, this, keeper );
	str.clr();
	str << "You give " << keeper->getShort() << " " << cost
		<< " gold pieces.\n\r";
	
	str << keeper->getShort() << " gives you "
		<< obj->getShort() << ".\n\r";

	keeper->rmObjInv( obj );
	addObjInv( obj );
	keeper->setGold( keeper->getGold() + cost );
	setGold( getGold() - cost );
	out( str );
}

void PC::do_sell( const String & arg )
{
	Object *obj;
	String str;
	Char *keeper;
	int cost;
	String arg1;
	String arg2;
	arg.startArgs();
	arg1 = arg.getArg();
	arg2 = arg.getArg();

	if( !arg1 )
	{
		out( "Sell what?\n\r" );
		return;
	}

	for_each( inRoom()->chars, keeper )
	{
		if( keeper->isShopKeeper() && (!arg2 || keeper->isName(arg2) ) )
			break;
	}

	if( !keeper )
	{
		if ( !arg2 )
			out( "There is no shopkeeper here.\n\r" );
		else
			out( "There is no shopkeeper here with that name.\n\r");
		return;
	}


	if( !( obj = getObjInv( arg1 ) ) )
	{
		out( keeper->getShort() );
		out( " tells you, \"You don't have that.\"\n\r" );
		return;
	}


	cost = ((ShopKeeper *)keeper)->buyValue(obj);

	if ( cost == SHOPKEEPER_NOT_TRADING )
	{
		str << keeper->getShort() << " tells you, \"I'm not interested at all.\"\n\r";
		out(str);
		return;
	}
	else if ( cost == SHOPKEEPER_HAS_IDENTICAL )
	{
		str << keeper->getShort() << " tells you \"I already have a few of those.\"\n\r";
		out(str);
		return;
	}
	else if ( cost == SHOPKEEPER_HAS_TYPE )
	{
		str << keeper->getShort() << " tells you \"I already have a few of this type.\"\n\r";
		out(str);
		return;
	}


	if( keeper->getGold() < cost )
	{
		out( keeper->getShort() );
		out( " tells you \"For now I have run out of cold.\"\n\r" );
		return;
	}

	str << getShort() << " sells " << obj->getShort() << ".\n\r";
	inRoom()->outAllCharExcept( str, this, keeper );
	str.clr();
	str << keeper->getShort() << " gives you " << cost
		<< " gold pieces.\n\r";
	
	str << "You give " << keeper->getShort() << " "
		<< obj->getShort() << ".\n\r";

	rmObjInv( obj );
	keeper->addObjInv( obj );
	setGold( getGold() + cost );
	keeper->setGold( keeper->getGold() - cost );
	out( str );
}


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

void PC::do_price( const String & arg )
{
	Object *obj;
	String str;
	Char *keeper;
	int cost;
	String arg1;
	String arg2;
	arg.startArgs();
	arg1 = arg.getArg();
	arg2 = arg.getArg();

	if( !arg1 )
	{
		out( "Price what?\n\r" );
		return;
	}

	for_each( inRoom()->chars, keeper )
	{
		if( keeper->isShopKeeper() && (!arg2 || keeper->isName(arg2) ) )
			break;
	}

	if( !keeper )
	{
		if ( !arg2 )
			out( "There is no shopkeeper here.\n\r" );
		else
			out( "There is no shopkeeper here with that name.\n\r");
		return;
	}

	if( !( obj = getObjInv( arg1 ) ) )
	{
		out( "You don't have that.\n\r" );
		return;
	}


	cost = ((ShopKeeper *)keeper)->buyValue(obj);


	if ( cost == SHOPKEEPER_NOT_TRADING )
	{
		str << keeper->getShort() << " tells you, \"I'm not interested at all.\"\n\r";
	}
	else if ( cost == SHOPKEEPER_HAS_IDENTICAL )
	{
		str << keeper->getShort() << " tells you \"I already have a few of those.\"\n\r";
	}
	else if ( cost == SHOPKEEPER_HAS_TYPE )
	{
		str << keeper->getShort() << " tells you \"I already have a few of this type.\"\n\r";
	}
	else
	{
		str << keeper->getShort() << " tells you, \"I'll give you "
			<< cost << " gold pieces for that.\"\n\r";
	}

	out( str );

	if( keeper->getGold() < cost )
	{
		out( keeper->getShort() );
		out( " tells you \"But for now I have run out of cash.\"\n\r" );
	}

}


void PC::do_give ( const String & arg )
{
	String str;
	Object *obj;
	Char * ch;
	String arg1;
	String arg2;
	int num = -1;

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

	arg.startArgs();

	arg1 = arg.getArg();
	
	if( arg1.isNumber() )
	{
		num = arg1.asInt();
		arg1 = arg.getArg();
	}

	// Add plural case
	//

	arg2 = arg.getArg();

	if ( !(bool)arg2 )
	{
		out("Give to whom ?\n\r");
		return;
	}

	if( !( ch = in_room->getChar(arg2 ) ) )
	{
		out("You do not see " );
		out(arg2);
		out(" here.\n\r");
		return;
	}

	if( !( obj = getObjInv( arg1 ) ) )
	{
		if ( (arg1 == "gold") || (arg1 == "coins") )
		{
			if ( num < 0 )
			{
				out("How many gold pieces do you want to give ?\n\r");
				return;
			}

			if ( (unsigned)num > gold )
			{
				out("You do not have that much gold.\n\r");
				return;
			}
			
			if ( ch->TgGivenGold(this, num) )
				return;

			gold -= num;
			ch->setGold( ch->getGold() + num );

			// comunicate
			str << "You give " << num <<" pieces of gold to " 
				<< ch->getName() << ".\n\r";
			out(str);
			str.clr();
			str << getName() << " gives some gold to " << ch->getName() << ".\n\r";
			inRoom()->outAllCharExcept( str, this, ch );
			str.clr();
			str << getName() << " gives you " << num << " gold coins.\n\r";
			ch->out(str);
			return;
		}

		out("You do not have " );
		out( arg1 );
		out(" with you.\n\r" );
		return;
	}

	// add checks for some lame non-drop bits

	if ( !give( obj, ch ) )
		return;
	//comunicate
	str << "You give " << obj->getName() <<" to " 
		<< ch->getName() << ".\n\r";
	out(str);
	str.clr();
	str << getName() << " gives " << obj->getName() << " to " 
		<< ch->getName() << ".\n\r";
	inRoom()->outAllCharExcept( str, this, ch );
	str.clr();
	str << getName() << " gives you " << obj->getName() << ".\n\r";
	ch->out(str);
	
}


void PC::do_collect ( const String & arg )
{
	Object *obj;
	String str;
	Char *keeper;
	String arg1;
	String arg2;

	arg.startArgs();
	arg1 = arg.getArg();
	arg2 = arg.getArg();


	for_each( inRoom()->chars, keeper )
		if( keeper->isShopKeeper() && (!arg2 || keeper->isName(arg2) ) )
			break;

	if( !keeper )
	{
		if ( !arg2 )
			out( "There is no shopkeeper here.\n\r" );
		else
			out( "There is no shopkeeper here with that name.\n\r");
		return;
	}

	if ( !((ShopKeeper *)keeper)->isOwnedBy(this) )
	{
		out( keeper->getShort() );
		out( "tells you, \"Sorry, I only obey my master\".\n\r");
		return;
	}

	if( !( obj = keeper->getObjInv( arg1 ) ) )
	{
		out( keeper->getShort() );
		out( " tells you, \"I don't have that.\"\n\r" );
		return;
	}

	keeper->give(obj, this);

	str << keeper->getShort() << " gives you " << obj->getShort() << ".\n\r";
	out(str);
	str.clr();
	str << keeper->getShort() << " gives " << obj->getShort() << " to "
		<<  this->getShort() << ".\n\r";
	inRoom()->outAllCharExcept(str, this, keeper );

	return;
}