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