Eldhamud_2.5.83/clans/
Eldhamud_2.5.83/classes/
Eldhamud_2.5.83/doc/
Eldhamud_2.5.83/doc/DIKU/
Eldhamud_2.5.83/doc/MERC/
Eldhamud_2.5.83/doc/mudprogs/
Eldhamud_2.5.83/houses/
/****************************************************************************
 *			Eldhamud Codebase V2.2				    *
 * ------------------------------------------------------------------------ *
 *          EldhaMUD code (C) 2003-2008 by Robert Powell (Tommi)            *
 * ------------------------------------------------------------------------ *
 * Original SMAUG 1.4a written by Thoric (Derek Snider) with Altrag,        *
 * Blodkai, Haus, Narn, Scryn, Swordbearer, Tricops, Gorog, Rennard,        *
 * Grishnakh, Fireblade, and Nivek.                                         *
 *                                                                          *
 * Original MERC 2.1 code by Hatchet, Furey, and Kahn.                      *
 *                                                                          *
 * Original DikuMUD code by: Hans Staerfeldt, Katja Nyboe, Tom Madsen,      *
 * Michael Seifert, and Sebastian Hammer.                                   *
 * ------------------------------------------------------------------------ *
 *			 Shop and repair shop module			    *
 ****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "./Headers/mud.h"
/*
 * Local functions
 */
#define	CD	CHAR_DATA
CD *find_keeper args( ( CHAR_DATA * ch ) );
CD *find_fixer args( ( CHAR_DATA * ch ) );
int get_cost args( ( CHAR_DATA * ch, CHAR_DATA * keeper, OBJ_DATA * obj, bool fBuy ) );
int get_repaircost args( ( CHAR_DATA * keeper, OBJ_DATA * obj ) );
#undef CD
/*
 * Shopping commands.
 */
CHAR_DATA *find_keeper( CHAR_DATA * ch )
{
   char buf[MAX_STRING_LENGTH];
   CHAR_DATA *keeper, *whof;
   SHOP_DATA *pShop;
   int speakswell;
   pShop = NULL;
   for( keeper = ch->in_room->first_person; keeper; keeper = keeper->next_in_room )
      if( IS_NPC( keeper ) && ( pShop = keeper->pIndexData->pShop ) != NULL )
         break;
   if( !pShop )
   {
      send_to_char( "You can't do that here.\r\n", ch );
      return NULL;
   }
   /*
    * Undesirables.
    */
   if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_KILLER ) )
   {
      do_say( keeper, "Murderers are not welcome here!" );
      sprintf( buf, "%s the KILLER is over here!\r\n", ch->name );
      do_yell( keeper, buf );
      return NULL;
   }
   if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_THIEF ) )
   {
      do_say( keeper, "Thieves are not welcome here!" );
      sprintf( buf, "%s the THIEF is over here!\r\n", ch->name );
      do_yell( keeper, buf );
      return NULL;
   }
   /*
    * Disallow sales during battle
    */
   if( ( whof = who_fighting( keeper ) ) != NULL )
   {
      if( whof == ch )
         send_to_char( "I don't think that's a good idea...\r\n", ch );
      else
         do_say( keeper, "I'm too busy for that!" );
      return NULL;
   }
   if( who_fighting( ch ) )
   {
      ch_printf( ch, "%s doesn't seem to want to get involved.\r\n", PERS( keeper, ch, FALSE ) );
      return NULL;
   }
   /*
    * Check to see if show is open.
    * Supports closing times after midnight
    */
   if( pShop->open_hour > pShop->close_hour )
   {
      if( time_info.hour < pShop->open_hour && time_info.hour > pShop->close_hour )
      {
         do_say( keeper, "Sorry, come back later." );
         return NULL;
      }
   }
   else
   {
      if( time_info.hour < pShop->open_hour )
      {
         do_say( keeper, "Sorry, come back later." );
         return NULL;
      }
      if( time_info.hour > pShop->close_hour )
      {
         do_say( keeper, "Sorry, come back tomorrow." );
         return NULL;
      }
   }
   if( keeper->position == POS_SLEEPING )
   {
      send_to_char( "While they're asleep?\r\n", ch );
      return NULL;
   }
   if( keeper->position < POS_SLEEPING )
   {
      send_to_char( "I don't think they can hear you...\r\n", ch );
      return NULL;
   }
   /*
    * Invisible or hidden people.
    */
   if( !can_see( keeper, ch, FALSE ) )
   {
      do_say( keeper, "I don't trade with folks I can't see." );
      return NULL;
   }
   speakswell = UMIN( knows_language( keeper, ch->speaking, ch ), knows_language( ch, ch->speaking, keeper ) );
   if( ( number_percent(  ) % 65 ) > speakswell )
   {
      if( speakswell > 60 )
         sprintf( buf, "%s Could you repeat that?  I didn't quite catch it.", ch->name );
      else if( speakswell > 50 )
         sprintf( buf, "%s Could you say that a little more clearly please?", ch->name );
      else if( speakswell > 40 )
         sprintf( buf, "%s Sorry... What was that you wanted?", ch->name );
      else
         sprintf( buf, "%s I can't understand you.", ch->name );
      do_tell( keeper, buf );
      return NULL;
   }
   return keeper;
}

/*
 * repair commands.
 */
CHAR_DATA *find_fixer( CHAR_DATA * ch )
{
   char buf[MAX_STRING_LENGTH];
   CHAR_DATA *keeper, *whof;
   REPAIR_DATA *rShop;
   int speakswell;
   rShop = NULL;
   for( keeper = ch->in_room->first_person; keeper; keeper = keeper->next_in_room )
      if( IS_NPC( keeper ) && ( rShop = keeper->pIndexData->rShop ) != NULL )
         break;
   if( !rShop )
   {
      send_to_char( "You can't do that here.\r\n", ch );
      return NULL;
   }
   /*
    * Undesirables.
    */
   if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_KILLER ) )
   {
      do_say( keeper, "Murderers are not welcome here!" );
      sprintf( buf, "%s the KILLER is over here!\r\n", ch->name );
      do_yell( keeper, buf );
      return NULL;
   }
   if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_THIEF ) )
   {
      do_say( keeper, "Thieves are not welcome here!" );
      sprintf( buf, "%s the THIEF is over here!\r\n", ch->name );
      do_yell( keeper, buf );
      return NULL;
   }
   /*
    * Disallow sales during battle
    */
   if( ( whof = who_fighting( keeper ) ) != NULL )
   {
      if( whof == ch )
         send_to_char( "I don't think that's a good idea...\r\n", ch );
      else
         do_say( keeper, "I'm too busy for that!" );
      return NULL;
   }
   /*
    * According to rlog, this is the second time I've done this
    * * so mobiles can repair in combat.  -- Blod, 1/98
    */
   if( !IS_NPC( ch ) && who_fighting( ch ) )
   {
      ch_printf( ch, "%s doesn't seem to want to get involved.\r\n", PERS( keeper, ch, FALSE ) );
      return NULL;
   }
   /*
    * Check to see if show is open.
    * Supports closing times after midnight
    */
   if( rShop->open_hour > rShop->close_hour )
   {
      if( time_info.hour < rShop->open_hour && time_info.hour > rShop->close_hour )
      {
         do_say( keeper, "Sorry, come back later." );
         return NULL;
      }
   }
   else
   {
      if( time_info.hour < rShop->open_hour )
      {
         do_say( keeper, "Sorry, come back later." );
         return NULL;
      }
      if( time_info.hour > rShop->close_hour )
      {
         do_say( keeper, "Sorry, come back tomorrow." );
         return NULL;
      }
   }
   if( keeper->position == POS_SLEEPING )
   {
      send_to_char( "While they're asleep?\r\n", ch );
      return NULL;
   }
   if( keeper->position < POS_SLEEPING )
   {
      send_to_char( "I don't think they can hear you...\r\n", ch );
      return NULL;
   }
   /*
    * Invisible or hidden people.
    */
   if( !can_see( keeper, ch, FALSE ) )
   {
      do_say( keeper, "I don't trade with folks I can't see." );
      return NULL;
   }
   speakswell = UMIN( knows_language( keeper, ch->speaking, ch ), knows_language( ch, ch->speaking, keeper ) );
   if( ( number_percent(  ) % 65 ) > speakswell )
   {
      if( speakswell > 60 )
         sprintf( buf, "%s Could you repeat that?  I didn't quite catch it.", ch->name );
      else if( speakswell > 50 )
         sprintf( buf, "%s Could you say that a little more clearly please?", ch->name );
      else if( speakswell > 40 )
         sprintf( buf, "%s Sorry... What was that you wanted?", ch->name );
      else
         sprintf( buf, "%s I can't understand you.", ch->name );
      do_tell( keeper, buf );
      return NULL;
   }
   return keeper;
}

int get_cost( CHAR_DATA * ch, CHAR_DATA * keeper, OBJ_DATA * obj, bool fBuy )
{
   SHOP_DATA *pShop;
   int cost;
   bool richcustomer;
   int profitmod;
   if( !obj || ( pShop = keeper->pIndexData->pShop ) == NULL )
      return 0;
   if( ch->gold > ( ch->level * ch->level * 100000 ) )
      richcustomer = TRUE;
   else
      richcustomer = FALSE;
   if( fBuy )
   {
      profitmod = 13 - get_curr_cha( ch ) + ( richcustomer ? 15 : 0 ) + ( ( URANGE( 5, ch->level, LEVEL_AVATAR ) - 20 ) / 2 );
      cost = ( int )( obj->cost * UMAX( ( pShop->profit_sell + 1 ), pShop->profit_buy + profitmod ) ) / 100;
      /*
       * Thanks to Nick Gammon for pointing out this line
       * (it was the first line in this block, making it useless) 
       */
      cost = ( int )( cost * ( 80 + UMIN( ch->level, LEVEL_AVATAR ) ) ) / 100;
   }
   else
   {
      OBJ_DATA *obj2;
      int itype;
      profitmod = get_curr_cha( ch ) - 13 - ( richcustomer ? 15 : 0 );
      cost = 0;
      for( itype = 0; itype < MAX_TRADE; itype++ )
      {
         if( obj->item_type == pShop->buy_type[itype] )
         {
            cost = ( int )( obj->cost * UMIN( ( pShop->profit_buy - 1 ), pShop->profit_sell + profitmod ) ) / 100;
            break;
         }
      }
      for( obj2 = keeper->first_carrying; obj2; obj2 = obj2->next_content )
      {
         if( obj->pIndexData == obj2->pIndexData )
         {
            cost /= 2.5;
            break;
         }
      }
   }
   if( obj->item_type == ITEM_STAFF || obj->item_type == ITEM_WAND )
      cost = ( int )( cost * obj->value[2] / obj->value[1] );
   return cost;
}

int get_repaircost( CHAR_DATA * keeper, OBJ_DATA * obj )
{
   REPAIR_DATA *rShop;
   int cost;
   int itype;
   bool found;
   if( !obj || ( rShop = keeper->pIndexData->rShop ) == NULL )
      return 0;
   cost = 0;
   found = FALSE;
   for( itype = 0; itype < MAX_FIX; itype++ )
   {
      if( obj->item_type == rShop->fix_type[itype] )
      {
         cost = ( int )( obj->cost * rShop->profit_fix / 1000 );
         found = TRUE;
         break;
      }
   }
   if( !found )
      cost = -1;
   if( cost == 0 )
      cost = 1;
   if( found && cost > 0 )
   {
      switch ( obj->item_type )
      {
         case ITEM_ARMOR:
            if( obj->value[3] >= 13 )
               cost = -2;
            else
               cost *= ( 13 - obj->value[3] );
            break;
         case ITEM_LIGHT:
            if( obj->value[0] >= 13 )
               cost = -2;
            else
               cost *= ( 13 - obj->value[0] );
         case ITEM_WEAPON:
            if( INIT_WEAPON_CONDITION == obj->value[0] )
               cost = -2;
            else
               cost *= ( INIT_WEAPON_CONDITION - obj->value[0] );
            break;
         case ITEM_WAND:
         case ITEM_STAFF:
            if( obj->value[2] >= obj->value[1] )
               cost = -2;
            else
               cost *= ( obj->value[1] - obj->value[2] );
      }
   }
   return cost;
}
void do_buy( CHAR_DATA * ch, char *argument )
{
   char arg[MAX_INPUT_LENGTH];
   int maxgold;
   argument = one_argument( argument, arg );
   if( arg[0] == STRING_NULL )
   {
      send_to_char( "Buy what?\r\n", ch );
      return;
   }
   if( xIS_SET( ch->in_room->room_flags, ROOM_PET_SHOP ) )
   {
      char buf[MAX_STRING_LENGTH];
      CHAR_DATA *pet;
      ROOM_INDEX_DATA *pRoomIndexNext;
      ROOM_INDEX_DATA *in_room;
      if( IS_NPC( ch ) )
         return;
      pRoomIndexNext = get_room_index( ch->in_room->vnum + 1 );
      if( !pRoomIndexNext )
      {
         bug( "Do_buy: bad pet shop at vnum %d.", ch->in_room->vnum );
         send_to_char( "Sorry, you can't buy that here.\r\n", ch );
         return;
      }
      in_room = ch->in_room;
      ch->in_room = pRoomIndexNext;
      pet = get_char_room( ch, arg );
      ch->in_room = in_room;
      if( pet == NULL || !IS_NPC( pet ) || !xIS_SET( pet->act, ACT_PET ) )
      {
         send_to_char( "Sorry, you can't buy that here.\r\n", ch );
         return;
      }
      if( xIS_SET( ch->act, PLR_BOUGHT_PET ) )
      {
         send_to_char( "You already bought one pet this level.\r\n", ch );
         return;
      }
      if( ch->gold < 10 * pet->level * pet->level )
      {
         send_to_char( "You can't afford it.\r\n", ch );
         return;
      }
      if( ch->level < pet->level )
      {
         send_to_char( "You're not ready for this pet.\r\n", ch );
         return;
      }
      maxgold = 10 * pet->level * pet->level;
      ch->gold -= maxgold;
      boost_economy( ch->in_room->area, maxgold );
      pet = create_mobile( pet->pIndexData );
      xSET_BIT( ch->act, PLR_BOUGHT_PET );
      xSET_BIT( pet->act, ACT_PET );
      xSET_BIT( pet->affected_by, AFF_CHARM );
/*	This isn't needed anymore since you can order your pets --Shaddai
	xSET_BIT(pet->affected_by, AFF_CHARM);
*/
      argument = one_argument( argument, arg );
      if( arg[0] != STRING_NULL )
      {
         sprintf( buf, "%s %s", pet->name, arg );
         STRFREE( pet->name );
         pet->name = STRALLOC( buf );
      }
      sprintf( buf, "%sA neck tag says 'I belong to %s'.\r\n", pet->description, ch->name );
      STRFREE( pet->description );
      pet->description = STRALLOC( buf );
      char_to_room( pet, ch->in_room );
      add_follower( pet, ch );
      send_to_char( "Enjoy your pet.\r\n", ch );
      act( AT_ACTION, "$n bought $N as a pet.", ch, NULL, pet, TO_ROOM );
      return;
   }
   else
   {
      CHAR_DATA *keeper;
      OBJ_DATA *obj;
      int cost;
      int noi = 1;   /* Number of items */
      short mnoi = 40;  /* Max number of items to be bought at once */
      if( ( keeper = find_keeper( ch ) ) == NULL )
         return;
      maxgold = keeper->level * keeper->level * 50000;
      if( is_number( arg ) )
      {
         noi = atoi( arg );
         argument = one_argument( argument, arg );
         if( noi > mnoi )
         {
            act( AT_TELL, "$n tells you 'I don't sell that many items at once.'", keeper, NULL, ch, TO_VICT );
            ch->reply = keeper;
            return;
         }
      }
      obj = get_obj_carry( keeper, arg );
      cost = ( get_cost( ch, keeper, obj, TRUE ) * noi );
      if( cost <= 0 || !can_see_obj( ch, obj ) )
      {
         act( AT_TELL, "$n tells you 'I don't sell that -- try 'list'.'", keeper, NULL, ch, TO_VICT );
         ch->reply = keeper;
         return;
      }
      if( !IS_OBJ_STAT( obj, ITEM_INVENTORY ) && ( noi > 1 ) )
      {
         interpret( keeper, "laugh" );
         act( AT_TELL, "$n tells you 'I don't have enough of those in stock" " to sell more than one at a time.'", keeper, NULL, ch, TO_VICT );
         ch->reply = keeper;
         return;
      }
      if( ch->gold < cost )
      {
         act( AT_TELL, "$n tells you 'You can't afford to buy $p.'", keeper, obj, ch, TO_VICT );
         ch->reply = keeper;
         return;
      }
      if( obj->level > ch->level )
      {
         act( AT_TELL, "$n tells you 'You can't use $p yet.'", keeper, obj, ch, TO_VICT );
         ch->reply = keeper;
         return;
      }
      if( IS_OBJ_STAT( obj, ITEM_PROTOTYPE ) && get_trust( ch ) < LEVEL_IMMORTAL )
      {
         act( AT_TELL, "$n tells you 'This is a only a prototype!  I can't sell you that...'", keeper, NULL, ch, TO_VICT );
         ch->reply = keeper;
         return;
      }
      if( ch->carry_number + get_obj_number( obj ) > can_carry_n( ch ) )
      {
         send_to_char( "You can't carry that many items.\r\n", ch );
         return;
      }
      if( ch->carry_weight + ( get_obj_weight( obj ) * noi ) + ( noi > 1 ? 2 : 0 ) > can_carry_w( ch ) )
      {
         send_to_char( "You can't carry that much weight.\r\n", ch );
         return;
      }
      if( noi == 1 )
      {
         act( AT_ACTION, "$n buys $p.", ch, obj, NULL, TO_ROOM );
         act( AT_ACTION, "You buy $p.", ch, obj, NULL, TO_CHAR );
      }
      else
      {
         sprintf( arg, "$n buys %d $p%s.", noi, ( obj->short_descr[strlen( obj->short_descr ) - 1] == 's' ? "" : "s" ) );
         act( AT_ACTION, arg, ch, obj, NULL, TO_ROOM );
         sprintf( arg, "You buy %d $p%s.", noi, ( obj->short_descr[strlen( obj->short_descr ) - 1] == 's' ? "" : "s" ) );
         act( AT_ACTION, arg, ch, obj, NULL, TO_CHAR );
         act( AT_ACTION, "$N puts them into a bag and hands it to you.", ch, NULL, keeper, TO_CHAR );
      }
      ch->gold -= cost;
      keeper->gold += cost;
      if( keeper->gold > maxgold )
      {
         boost_economy( keeper->in_room->area, keeper->gold - maxgold / 2 );
         keeper->gold = maxgold / 2;
         act( AT_ACTION, "$n puts some gold into a large safe.", keeper, NULL, NULL, TO_ROOM );
      }
      if( IS_OBJ_STAT( obj, ITEM_INVENTORY ) )
      {
         OBJ_DATA *buy_obj, *bag;
         buy_obj = create_object( obj->pIndexData, obj->level );
         /*
          * Due to grouped objects and carry limitations in SMAUG
          * The shopkeeper gives you a bag with multiple-buy,
          * and also, only one object needs be created with a count
          * set to the number bought.    -Thoric
          */
         if( noi > 1 )
         {
            bag = create_object( get_obj_index( OBJ_VNUM_SHOPPING_BAG ), 1 );
            xSET_BIT( bag->extra_flags, ITEM_GROUNDROT );
            bag->timer = 10;  /* Blodkai, 4/97 */
            /*
             * perfect size bag ;) 
             */
            bag->value[0] = bag->weight + ( buy_obj->weight * noi );
            buy_obj->count = noi;
            obj->pIndexData->count += ( noi - 1 );
            numobjsloaded += ( noi - 1 );
            obj_to_obj( buy_obj, bag );
            obj_to_char( bag, ch );
         }
         else
            obj_to_char( buy_obj, ch );
      }
      else
      {
         obj_from_char( obj );
         obj_to_char( obj, ch );
      }
      return;
   }
}

/*
 * This is a new list function which allows level limits to follow as
 * arguments.  This code relies heavily on the items held by the shopkeeper
 * being sorted in descending order by level.  obj_to_char in handler.c was
 * modified to achieve this.  Anyways, this list command will now throw flags
 * at the levels passed as arguments.  This helps pick out equipment which is
 * usable by the char, etc.  This was done rather than just producing a list
 * of equip at desired level because there would be an inconsistency between
 * #.item on one list and #.item on the other.
 * Syntax:
 *      list            -       list the items for sale, should be sorted by
 *                              level
 *      list #          -       list items and throw a flag at #
 *      list #1 #2      -       list items and throw flags at #1 and #2
 * Note that this won't work in pets stores. Since you can't control
 * the order in which the pets repop you can't guarantee a sorted list.
 * Last Modified: May 25, 1997 -- Fireblade
 */
void do_list( CHAR_DATA * ch, char *argument )
{
   /*
    * Constants for producing the flags 
    */
   char *divleft = "&D-------------------------------------[ ";
   char *divright = " &D]-------------------------------------";
   if( xIS_SET( ch->in_room->room_flags, ROOM_PET_SHOP ) )
   {
      ROOM_INDEX_DATA *pRoomIndexNext;
      CHAR_DATA *pet;
      bool found;
      pRoomIndexNext = get_room_index( ch->in_room->vnum + 1 );
      if( !pRoomIndexNext )
      {
         bug( "Do_list: bad pet shop at vnum %d.", ch->in_room->vnum );
         send_to_char( "You can't do that here.\r\n", ch );
         return;
      }
      found = FALSE;
      for( pet = pRoomIndexNext->first_person; pet; pet = pet->next_in_room )
      {
         if( xIS_SET( pet->act, ACT_PET ) && IS_NPC( pet ) )
         {
            if( !found )
            {
               found = TRUE;
               send_to_pager( "Pets for sale:\r\n", ch );
            }
            pager_printf( ch, "[%2d] %8d - %s\r\n", pet->level, 10 * pet->level * pet->level, pet->short_descr );
         }
      }
      if( !found )
         send_to_char( "Sorry, we're out of pets right now.\r\n", ch );
      return;
   }
   else
   {
      char arg[MAX_INPUT_LENGTH];
      char *rest;
      CHAR_DATA *keeper;
      OBJ_DATA *obj;
      int cost;
      bool found;
/*      bool listall; */
      int lower, upper;
      rest = one_argument( argument, arg );
      if( ( keeper = find_keeper( ch ) ) == NULL )
         return;
      found = FALSE;
      lower = -2;
      upper = -1;
      /*
       * Get the level limits for the flags 
       */

      set_pager_color( AT_SHOPS, ch);
      if( is_number( arg ) )
      {
         lower = atoi( arg );
         rest = one_argument( rest, arg );
         if( is_number( arg ) )
         {
            upper = atoi( arg );
            rest = one_argument( rest, arg );
         }
      }
      /*
       * Fix the limits if reversed 
       */
      if( lower >= upper )
      {
         int temp;
         temp = lower;
         lower = upper;
         upper = temp;
      }
      /*
       * Loop until you see an object higher level than char 
       */
      /*
       * Note that this depends on the keeper having a sorted list 
       */
      for( obj = keeper->first_carrying; obj; obj = obj->next_content )
      {
         if( obj->wear_loc == WEAR_NONE
             && can_see_obj( ch, obj ) && ( cost = get_cost( ch, keeper, obj, TRUE ) ) > 0 && ( arg[0] == STRING_NULL || nifty_is_name( arg, obj->name ) ) )
         {
            if( !found )
            {
               found = TRUE;
               send_to_pager ("&D--------------------------------------------------------------------------------\r\n", ch);
               send_to_pager( "&cLevel    Item                                                    Price  \r\n", ch );
               send_to_pager ("&D--------------------------------------------------------------------------------\r\n", ch);
            }
            if( obj->level <= upper )
            {
               pager_printf( ch, "%s&c%2d%s\r\n", divleft, upper, divright );
               upper = -1;
            }
            if( obj->level < lower )
            {
               pager_printf( ch, "%s&c%2d%s\r\n", divleft, lower, divright );
               lower = -1;
            }
            pager_printf( ch, " &w%-2d     %-50s       &R%-5d\r\n", obj->level, capitalize( obj->short_descr ), cost );
         }
      }
      if( lower >= 0 )
      {
         pager_printf( ch, "%s&c%2d%s\r\n", divleft, lower, divright );
      }
      send_to_pager ("&D--------------------------------------------------------------------------------\r\n", ch);
      if( !found )
      {
         if( arg[0] == STRING_NULL )
            send_to_char( "You can't buy anything here.\r\n", ch );
         else
            send_to_char( "You can't buy that here.\r\n", ch );
      }
      return;
   }
}
void do_sell( CHAR_DATA * ch, char *argument )
{
   char buf[MAX_STRING_LENGTH];
   char arg[MAX_INPUT_LENGTH];
   CHAR_DATA *keeper;
   OBJ_DATA *obj;
   int cost;
   one_argument( argument, arg );
   if( arg[0] == STRING_NULL )
   {
      send_to_char( "Sell what?\r\n", ch );
      return;
   }
   if( ( keeper = find_keeper( ch ) ) == NULL )
      return;
   if( ( obj = get_obj_carry( ch, arg ) ) == NULL )
   {
      act( AT_TELL, "$n tells you 'You don't have that item.'", keeper, NULL, ch, TO_ROOM );
      ch->reply = keeper;
      return;
   }
   /*
    * Bug report and solution thanks to animal@netwin.co.nz 
    */
   if( !can_see_obj( keeper, obj ) )
   {
      send_to_char( "What are you trying to sell me? I don't buy thin air!\r\n", ch );
      return;
   }
   if( !can_drop_obj( ch, obj ) )
   {
      send_to_char( "You can't let go of it!\r\n", ch );
      return;
   }
   if( obj->timer > 0 )
   {
      act( AT_TELL, "$n tells you, '$p is depreciating in value too quickly...'", keeper, obj, ch, TO_ROOM );
      return;
   }
   if( ( cost = get_cost( ch, keeper, obj, FALSE ) ) <= 0 )
   {
      act( AT_GREEN, "$n looks uninterested in $p.", keeper, obj, ch, TO_ROOM );
      return;
   }
   if( cost >= keeper->gold )
   {
      /*
       * Try to pull from economy
       */
      if( keeper->in_room->area->low_economy >= cost )
      {
         keeper->gold += cost;
         keeper->in_room->area->low_economy -= cost;
      }
      else
      {
         act( AT_GREEN, "$n tells you, '$p is worth more than I can afford...'", keeper, obj, ch, TO_CHAR );
         return;
      }
   }
   separate_obj( obj );
   act( AT_ACTION, "$n sells $p.", ch, obj, NULL, TO_ROOM );
   sprintf( buf, "You sell $p for %d gold piece%s.", cost, cost == 1 ? "" : "s" );
   act( AT_ACTION, buf, ch, obj, NULL, TO_CHAR );
   ch->gold += cost;
   keeper->gold -= cost;
   if( keeper->gold < 0 )
      keeper->gold = 0;
   if( obj->item_type == ITEM_TRASH )
      extract_obj( obj );
   else
   {
      obj_from_char( obj );
      obj_to_char( obj, keeper );
   }
   return;
}
void do_value( CHAR_DATA * ch, char *argument )
{
   char buf[MAX_STRING_LENGTH];
   CHAR_DATA *keeper;
   OBJ_DATA *obj;
   int cost;
   if( argument[0] == STRING_NULL )
   {
      send_to_char( "Value what?\r\n", ch );
      return;
   }
   if( ( keeper = find_keeper( ch ) ) == NULL )
      return;
   if( ( obj = get_obj_carry( ch, argument ) ) == NULL )
   {
      act( AT_TELL, "$n tells you 'You don't have that item.'", keeper, NULL, ch, TO_VICT );
      ch->reply = keeper;
      return;
   }
   if( !can_drop_obj( ch, obj ) )
   {
      send_to_char( "You can't let go of it!\r\n", ch );
      return;
   }
   if( ( cost = get_cost( ch, keeper, obj, FALSE ) ) <= 0 )
   {
      act( AT_ACTION, "$n looks uninterested in $p.", keeper, obj, ch, TO_VICT );
      return;
   }
   sprintf( buf, "$n tells you 'I'll give you %d gold coins for $p.'", cost );
   act( AT_TELL, buf, keeper, obj, ch, TO_VICT );
   ch->reply = keeper;
   return;
}

/*
 * Repair a single object. Used when handling "repair all" - Gorog
 */
void repair_one_obj( CHAR_DATA * ch, CHAR_DATA * keeper, OBJ_DATA * obj, char *arg, int maxgold, char *fixstr, char *fixstr2 )
{
   char buf[MAX_STRING_LENGTH];
   int cost;
   if( !can_drop_obj( ch, obj ) )
      ch_printf( ch, "You can't let go of %s.\r\n", obj->name );
   else if( ( cost = get_repaircost( keeper, obj ) ) < 0 )
   {
      if( cost != -2 )
         act( AT_TELL, "$n tells you, 'Sorry, I can't do anything with $p.'", keeper, obj, ch, TO_VICT );
      else
         act( AT_TELL, "$n tells you, '$p looks fine to me!'", keeper, obj, ch, TO_VICT );
   }
   /*
    * "repair all" gets a 10% surcharge - Gorog 
    */
   else if( ( cost = strcmp( "all", arg ) ? cost : 11 * cost / 10 ) > ch->gold )
   {
      sprintf( buf, "$N tells you, 'It will cost %d piece%s of gold to %s %s...'", cost, cost == 1 ? "" : "s", fixstr, obj->name );
      act( AT_TELL, buf, ch, NULL, keeper, TO_CHAR );
      act( AT_TELL, "$N tells you, 'Which I see you can't afford.'", ch, NULL, keeper, TO_CHAR );
   }
   else
   {
      sprintf( buf, "$n gives $p to $N, who quickly %s it.", fixstr2 );
      act( AT_ACTION, buf, ch, obj, keeper, TO_ROOM );
      sprintf( buf, "$N charges you %d gold piece%s to %s $p.", cost, cost == 1 ? "" : "s", fixstr );
      act( AT_ACTION, buf, ch, obj, keeper, TO_CHAR );
      ch->gold -= cost;
      keeper->gold += cost;
      if( keeper->gold < 0 )
         keeper->gold = 0;
      else if( keeper->gold > maxgold )
      {
         boost_economy( keeper->in_room->area, keeper->gold - maxgold / 2 );
         keeper->gold = maxgold / 2;
         act( AT_ACTION, "$n puts some gold into a large safe.", keeper, NULL, NULL, TO_ROOM );
      }
      switch ( obj->item_type )
      {
         default:
            send_to_char( "For some reason, you think you got ripped off...\r\n", ch );
            break;
         case ITEM_ARMOR:
            obj->value[3] = 13;
            break;
         case ITEM_LIGHT:
            obj->value[0] = 13;
            break;
         case ITEM_WEAPON:
            obj->value[0] = 13;
            break;
         case ITEM_WAND:
         case ITEM_STAFF:
            obj->value[2] = obj->value[1];
            break;
      }
      oprog_repair_trigger( ch, obj );
   }
}
void do_repair( CHAR_DATA * ch, char *argument )
{
   CHAR_DATA *keeper;
   OBJ_DATA *obj;
   char *fixstr;
   char *fixstr2;
   int maxgold;
   if( argument[0] == STRING_NULL )
   {
      send_to_char( "Repair what?\r\n", ch );
      return;
   }
   if( ( keeper = find_fixer( ch ) ) == NULL )
      return;
   maxgold = keeper->level * keeper->level * 100000;
   switch ( keeper->pIndexData->rShop->shop_type )
   {
      default:
      case SHOP_FIX:
         fixstr = "repair";
         fixstr2 = "repairs";
         break;
      case SHOP_RECHARGE:
         fixstr = "recharge";
         fixstr2 = "recharges";
         break;
   }
   if( !strcmp( argument, "all" ) )
   {
      for( obj = ch->first_carrying; obj; obj = obj->next_content )
      {
         if( obj->wear_loc == WEAR_NONE
             && can_see_obj( ch, obj )
             && can_see_obj( keeper, obj )
             && ( obj->item_type == ITEM_ARMOR || obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_WAND || obj->item_type == ITEM_STAFF ) )
            repair_one_obj( ch, keeper, obj, argument, maxgold, fixstr, fixstr2 );
      }
      return;
   }
   if( ( obj = get_obj_carry( ch, argument ) ) == NULL )
   {
      act( AT_TELL, "$n tells you 'You don't have that item.'", keeper, NULL, ch, TO_VICT );
      ch->reply = keeper;
      return;
   }
   repair_one_obj( ch, keeper, obj, argument, maxgold, fixstr, fixstr2 );
}
void appraise_all( CHAR_DATA * ch, CHAR_DATA * keeper, char *fixstr )
{
   OBJ_DATA *obj;
   char buf[MAX_STRING_LENGTH];
   int cost = 0, total = 0;
   for( obj = ch->first_carrying; obj != NULL; obj = obj->next_content )
   {
      if( obj->wear_loc == WEAR_NONE
          && can_see_obj( ch, obj ) && ( obj->item_type == ITEM_ARMOR || obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_WAND || obj->item_type == ITEM_STAFF ) )
      {
         if( !can_drop_obj( ch, obj ) )
            ch_printf( ch, "You can't let go of %s.\r\n", obj->name );
         else if( ( cost = get_repaircost( keeper, obj ) ) < 0 )
         {
            if( cost != -2 )
               act( AT_TELL, "$n tells you, 'Sorry, I can't do anything with $p.'", keeper, obj, ch, TO_VICT );
            else
               act( AT_TELL, "$n tells you, '$p looks fine to me!'", keeper, obj, ch, TO_VICT );
         }
         else
         {
            sprintf( buf, "$N tells you, 'It will cost %d piece%s of gold to %s %s'", cost, cost == 1 ? "" : "s", fixstr, obj->name );
            act( AT_TELL, buf, ch, NULL, keeper, TO_CHAR );
            total += cost;
         }
      }
   }
   if( total > 0 )
   {
      send_to_char( "\r\n", ch );
      sprintf( buf, "$N tells you, 'It will cost %d piece%s of gold in total.'", total, cost == 1 ? "" : "s" );
      act( AT_TELL, buf, ch, NULL, keeper, TO_CHAR );
      strcpy( buf, "$N tells you, 'Remember there is a 10% surcharge for repair all.'" );
      act( AT_TELL, buf, ch, NULL, keeper, TO_CHAR );
   }
}
void do_appraise( CHAR_DATA * ch, char *argument )
{
   char buf[MAX_STRING_LENGTH];
   char arg[MAX_INPUT_LENGTH];
   CHAR_DATA *keeper;
   OBJ_DATA *obj;
   int cost;
   char *fixstr;
   one_argument( argument, arg );
   if( arg[0] == STRING_NULL )
   {
      send_to_char( "Appraise what?\r\n", ch );
      return;
   }
   if( ( keeper = find_fixer( ch ) ) == NULL )
      return;
   switch ( keeper->pIndexData->rShop->shop_type )
   {
      default:
      case SHOP_FIX:
         fixstr = "repair";
         break;
      case SHOP_RECHARGE:
         fixstr = "recharge";
         break;
   }
   if( !strcmp( arg, "all" ) )
   {
      appraise_all( ch, keeper, fixstr );
      return;
   }
   if( ( obj = get_obj_carry( ch, arg ) ) == NULL )
   {
      act( AT_TELL, "$n tells you 'You don't have that item.'", keeper, NULL, ch, TO_VICT );
      ch->reply = keeper;
      return;
   }
   if( !can_drop_obj( ch, obj ) )
   {
      send_to_char( "You can't let go of it.\r\n", ch );
      return;
   }
   if( ( cost = get_repaircost( keeper, obj ) ) < 0 )
   {
      if( cost != -2 )
         act( AT_TELL, "$n tells you, 'Sorry, I can't do anything with $p.'", keeper, obj, ch, TO_VICT );
      else
         act( AT_TELL, "$n tells you, '$p looks fine to me!'", keeper, obj, ch, TO_VICT );
      return;
   }
   sprintf( buf, "$N tells you, 'It will cost %d piece%s of gold to %s that...'", cost, cost == 1 ? "" : "s", fixstr );
   act( AT_TELL, buf, ch, NULL, keeper, TO_CHAR );
   if( cost > ch->gold )
      act( AT_TELL, "$N tells you, 'Which I see you can't afford.'", ch, NULL, keeper, TO_CHAR );
   return;
}

/* ------------------ Shop Building and Editing Section ----------------- */
void do_makeshop( CHAR_DATA * ch, char *argument )
{
   SHOP_DATA *shop;
   int vnum;
   MOB_INDEX_DATA *mob;
   if( !argument || argument[0] == STRING_NULL )
   {
      send_to_char( "Usage: makeshop <mobvnum>\r\n", ch );
      return;
   }
   vnum = atoi( argument );
   if( ( mob = get_mob_index( vnum ) ) == NULL )
   {
      send_to_char( "Mobile not found.\r\n", ch );
      return;
   }
   if( !can_medit( ch, mob ) )
      return;
   if( mob->pShop )
   {
      send_to_char( "This mobile already has a shop.\r\n", ch );
      return;
   }
   CREATE( shop, SHOP_DATA, 1 );
   LINK( shop, first_shop, last_shop, next, prev );
   shop->keeper = vnum;
   shop->profit_buy = 120;
   shop->profit_sell = 90;
   shop->open_hour = 0;
   shop->close_hour = 23;
   mob->pShop = shop;
   send_to_char( "Done.\r\n", ch );
   return;
}
void do_shopset( CHAR_DATA * ch, char *argument )
{
   SHOP_DATA *shop;
   MOB_INDEX_DATA *mob, *mob2;
   char arg1[MAX_INPUT_LENGTH];
   char arg2[MAX_INPUT_LENGTH];
   int vnum;
   int value;
   argument = one_argument( argument, arg1 );
   argument = one_argument( argument, arg2 );
   if( arg1[0] == STRING_NULL || arg2[0] == STRING_NULL )
   {
      send_to_char( "Usage: shopset <mob vnum> <field> value\r\n", ch );
      send_to_char( "\r\nField being one of:\r\n", ch );
      send_to_char( "  buy0 buy1 buy2 buy3 buy4 buy sell open close keeper\r\n", ch );
      return;
   }
   vnum = atoi( arg1 );
   if( ( mob = get_mob_index( vnum ) ) == NULL )
   {
      send_to_char( "Mobile not found.\r\n", ch );
      return;
   }
   if( !can_medit( ch, mob ) )
      return;
   if( !mob->pShop )
   {
      send_to_char( "This mobile doesn't keep a shop.\r\n", ch );
      return;
   }
   shop = mob->pShop;
   value = atoi( argument );
   if( !str_cmp( arg2, "buy0" ) )
   {
      if( !is_number( argument ) )
         value = get_otype( argument );
      if( value < 0 || value > MAX_ITEM_TYPE )
      {
         send_to_char( "Invalid item type!\r\n", ch );
         return;
      }
      shop->buy_type[0] = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "buy1" ) )
   {
      if( !is_number( argument ) )
         value = get_otype( argument );
      if( value < 0 || value > MAX_ITEM_TYPE )
      {
         send_to_char( "Invalid item type!\r\n", ch );
         return;
      }
      shop->buy_type[1] = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "buy2" ) )
   {
      if( !is_number( argument ) )
         value = get_otype( argument );
      if( value < 0 || value > MAX_ITEM_TYPE )
      {
         send_to_char( "Invalid item type!\r\n", ch );
         return;
      }
      shop->buy_type[2] = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "buy3" ) )
   {
      if( !is_number( argument ) )
         value = get_otype( argument );
      if( value < 0 || value > MAX_ITEM_TYPE )
      {
         send_to_char( "Invalid item type!\r\n", ch );
         return;
      }
      shop->buy_type[3] = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "buy4" ) )
   {
      if( !is_number( argument ) )
         value = get_otype( argument );
      if( value < 0 || value > MAX_ITEM_TYPE )
      {
         send_to_char( "Invalid item type!\r\n", ch );
         return;
      }
      shop->buy_type[4] = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "buy" ) )
   {
      if( value <= ( shop->profit_sell + 5 ) || value > 1000 )
      {
         send_to_char( "Out of range.\r\n", ch );
         return;
      }
      shop->profit_buy = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "sell" ) )
   {
      if( value < 0 || value >= ( shop->profit_buy - 5 ) )
      {
         send_to_char( "Out of range.\r\n", ch );
         return;
      }
      shop->profit_sell = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "open" ) )
   {
      if( value < 0 || value > 23 )
      {
         send_to_char( "Out of range.\r\n", ch );
         return;
      }
      shop->open_hour = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "close" ) )
   {
      if( value < 0 || value > 23 )
      {
         send_to_char( "Out of range.\r\n", ch );
         return;
      }
      shop->close_hour = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "keeper" ) )
   {
      if( ( mob2 = get_mob_index( vnum ) ) == NULL )
      {
         send_to_char( "Mobile not found.\r\n", ch );
         return;
      }
      if( !can_medit( ch, mob ) )
         return;
      if( mob2->pShop )
      {
         send_to_char( "That mobile already has a shop.\r\n", ch );
         return;
      }
      mob->pShop = NULL;
      mob2->pShop = shop;
      shop->keeper = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   do_shopset( ch, "" );
   return;
}
void do_shopstat( CHAR_DATA * ch, char *argument )
{
   SHOP_DATA *shop;
   MOB_INDEX_DATA *mob;
   int vnum;
   if( argument[0] == STRING_NULL )
   {
      send_to_char( "Usage: shopstat <keeper vnum>\r\n", ch );
      return;
   }
   vnum = atoi( argument );
   if( ( mob = get_mob_index( vnum ) ) == NULL )
   {
      send_to_char( "Mobile not found.\r\n", ch );
      return;
   }
   if( !mob->pShop )
   {
      send_to_char( "This mobile doesn't keep a shop.\r\n", ch );
      return;
   }
   shop = mob->pShop;
   ch_printf( ch, "Keeper: %d  %s\r\n", shop->keeper, mob->short_descr );
   ch_printf( ch, "buy0 [%s]  buy1 [%s]  buy2 [%s]  buy3 [%s]  buy4 [%s]\r\n",
              o_types[shop->buy_type[0]], o_types[shop->buy_type[1]], o_types[shop->buy_type[2]], o_types[shop->buy_type[3]], o_types[shop->buy_type[4]] );
   ch_printf( ch, "Profit:  buy %3d%%  sell %3d%%\r\n", shop->profit_buy, shop->profit_sell );
   ch_printf( ch, "Hours:   open %2d  close %2d\r\n", shop->open_hour, shop->close_hour );
   return;
}
void do_shops( CHAR_DATA * ch, char *argument )
{
   SHOP_DATA *shop;
   if( !first_shop )
   {
      send_to_char( "There are no shops.\r\n", ch );
      return;
   }
   set_char_color( AT_NOTE, ch );
   for( shop = first_shop; shop; shop = shop->next )
      ch_printf( ch, "Keeper: %5d Buy: %3d Sell: %3d Open: %2d Close: %2d Buy: %2d %2d %2d %2d %2d\r\n",
                 shop->keeper, shop->profit_buy, shop->profit_sell,
                 shop->open_hour, shop->close_hour, shop->buy_type[0], shop->buy_type[1], shop->buy_type[2], shop->buy_type[3], shop->buy_type[4] );
   return;
}

/* -------------- Repair Shop Building and Editing Section -------------- */
void do_makerepair( CHAR_DATA * ch, char *argument )
{
   REPAIR_DATA *repair;
   int vnum;
   MOB_INDEX_DATA *mob;
   if( !argument || argument[0] == STRING_NULL )
   {
      send_to_char( "Usage: makerepair <mobvnum>\r\n", ch );
      return;
   }
   vnum = atoi( argument );
   if( ( mob = get_mob_index( vnum ) ) == NULL )
   {
      send_to_char( "Mobile not found.\r\n", ch );
      return;
   }
   if( !can_medit( ch, mob ) )
      return;
   if( mob->rShop )
   {
      send_to_char( "This mobile already has a repair shop.\r\n", ch );
      return;
   }
   CREATE( repair, REPAIR_DATA, 1 );
   LINK( repair, first_repair, last_repair, next, prev );
   repair->keeper = vnum;
   repair->profit_fix = 100;
   repair->shop_type = SHOP_FIX;
   repair->open_hour = 0;
   repair->close_hour = 23;
   mob->rShop = repair;
   send_to_char( "Done.\r\n", ch );
   return;
}
void do_repairset( CHAR_DATA * ch, char *argument )
{
   REPAIR_DATA *repair;
   MOB_INDEX_DATA *mob, *mob2;
   char arg1[MAX_INPUT_LENGTH];
   char arg2[MAX_INPUT_LENGTH];
   int vnum;
   int value;
   argument = one_argument( argument, arg1 );
   argument = one_argument( argument, arg2 );
   if( arg1[0] == STRING_NULL || arg2[0] == STRING_NULL )
   {
      send_to_char( "Usage: repairset <mob vnum> <field> value\r\n", ch );
      send_to_char( "\r\nField being one of:\r\n", ch );
      send_to_char( "  fix0 fix1 fix2 profit type open close keeper\r\n", ch );
      return;
   }
   vnum = atoi( arg1 );
   if( ( mob = get_mob_index( vnum ) ) == NULL )
   {
      send_to_char( "Mobile not found.\r\n", ch );
      return;
   }
   if( !can_medit( ch, mob ) )
      return;
   if( !mob->rShop )
   {
      send_to_char( "This mobile doesn't keep a repair shop.\r\n", ch );
      return;
   }
   repair = mob->rShop;
   value = atoi( argument );
   if( !str_cmp( arg2, "fix0" ) )
   {
      if( !is_number( argument ) )
         value = get_otype( argument );
      if( value < 0 || value > MAX_ITEM_TYPE )
      {
         send_to_char( "Invalid item type!\r\n", ch );
         return;
      }
      repair->fix_type[0] = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "fix1" ) )
   {
      if( !is_number( argument ) )
         value = get_otype( argument );
      if( value < 0 || value > MAX_ITEM_TYPE )
      {
         send_to_char( "Invalid item type!\r\n", ch );
         return;
      }
      repair->fix_type[1] = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "fix2" ) )
   {
      if( !is_number( argument ) )
         value = get_otype( argument );
      if( value < 0 || value > MAX_ITEM_TYPE )
      {
         send_to_char( "Invalid item type!\r\n", ch );
         return;
      }
      repair->fix_type[2] = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "profit" ) )
   {
      if( value < 1 || value > 1000 )
      {
         send_to_char( "Out of range.\r\n", ch );
         return;
      }
      repair->profit_fix = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "type" ) )
   {
      if( value < 1 || value > 2 )
      {
         send_to_char( "Out of range.\r\n", ch );
         return;
      }
      repair->shop_type = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "open" ) )
   {
      if( value < 0 || value > 23 )
      {
         send_to_char( "Out of range.\r\n", ch );
         return;
      }
      repair->open_hour = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "close" ) )
   {
      if( value < 0 || value > 23 )
      {
         send_to_char( "Out of range.\r\n", ch );
         return;
      }
      repair->close_hour = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "keeper" ) )
   {
      if( ( mob2 = get_mob_index( vnum ) ) == NULL )
      {
         send_to_char( "Mobile not found.\r\n", ch );
         return;
      }
      if( !can_medit( ch, mob ) )
         return;
      if( mob2->rShop )
      {
         send_to_char( "That mobile already has a repair shop.\r\n", ch );
         return;
      }
      mob->rShop = NULL;
      mob2->rShop = repair;
      repair->keeper = value;
      send_to_char( "Done.\r\n", ch );
      return;
   }
   do_repairset( ch, "" );
   return;
}
void do_repairstat( CHAR_DATA * ch, char *argument )
{
   REPAIR_DATA *repair;
   MOB_INDEX_DATA *mob;
   int vnum;
   if( argument[0] == STRING_NULL )
   {
      send_to_char( "Usage: repairstat <keeper vnum>\r\n", ch );
      return;
   }
   vnum = atoi( argument );
   if( ( mob = get_mob_index( vnum ) ) == NULL )
   {
      send_to_char( "Mobile not found.\r\n", ch );
      return;
   }
   if( !mob->rShop )
   {
      send_to_char( "This mobile doesn't keep a repair shop.\r\n", ch );
      return;
   }
   repair = mob->rShop;
   ch_printf( ch, "Keeper: %d  %s\r\n", repair->keeper, mob->short_descr );
   ch_printf( ch, "fix0 [%s]  fix1 [%s]  fix2 [%s]\r\n", o_types[repair->fix_type[0]], o_types[repair->fix_type[1]], o_types[repair->fix_type[2]] );
   ch_printf( ch, "Profit: %3d%%  Type: %d\r\n", repair->profit_fix, repair->shop_type );
   ch_printf( ch, "Hours:   open %2d  close %2d\r\n", repair->open_hour, repair->close_hour );
   return;
}
void do_repairshops( CHAR_DATA * ch, char *argument )
{
   REPAIR_DATA *repair;
   if( !first_repair )
   {
      send_to_char( "There are no repair shops.\r\n", ch );
      return;
   }
   set_char_color( AT_NOTE, ch );
   for( repair = first_repair; repair; repair = repair->next )
      ch_printf( ch, "Keeper: %5d Profit: %3d Type: %d Open: %2d Close: %2d Fix: %2d %2d %2d\r\n",
                 repair->keeper, repair->profit_fix, repair->shop_type, repair->open_hour, repair->close_hour, repair->fix_type[0], repair->fix_type[1], repair->fix_type[2] );
   return;
}