tfe-1.0/area/
tfe-1.0/files/
tfe-1.0/logs/
tfe-1.0/logs/immortal/
tfe-1.0/logs/mob/
tfe-1.0/logs/object/
tfe-1.0/logs/player/
tfe-1.0/logs/room/
tfe-1.0/notes/clans/
tfe-1.0/player/
tfe-1.0/prev/
tfe-1.0/prev/area/
tfe-1.0/prev/player/
tfe-1.0/prev/rooms/
tfe-1.0/rooms/
tfe-1.0/src-gc/
tfe-1.0/src-msvc/
tfe-1.0/src-unix/
tfe-1.0/www/
tfe-1.0/www/html/
#include "ctype.h"
#include "math.h"
#include "sys/types.h"
#include "stdio.h"
#include "stdlib.h"
#include "define.h"
#include "struct.h"


shop_data*  shop_list     = NULL;
const char* shop_flags [] = { "buys.stolen" };

const int ingot_vnum[] = { 638, 639, 640, 641, 643, 642 };


/*
 *   LOCAL FUNCTIONS
 */


bool        will_trade    ( char_data*, obj_data* );
int         get_cost      ( char_data*, char_data*, obj_data*, bool );
int         melt_cost     ( char_data*, obj_data* );
int         repair_cost   ( char_data*, obj_data* );


/*
 *   SHOP OBJET PROPERTIES
 */


bool Obj_Data :: Damaged( )
{
  return( condition < 9*repair_condition( this )/10 );
};


/*
 *   UPDATE ROUTINE
 */


void shop_update( void )
{
  mob_data*    keeper;
  obj_data*       obj;

  for( int i = 0; i < mob_list; i++ ) {
    keeper = mob_list[i];

    if( keeper->pShop == NULL || keeper->reset == NULL
      || player_in_room( keeper->in_room ) )
      continue;

    reset_shop( keeper );

    for( int j = keeper->contents-1; j >= 0; j-- ) {
      obj = (obj_data*) keeper->contents[j];
      for( int k = obj->number; k > 0; k-- ) 
        if( number_range( 0, 10 ) == 0 && --obj->number == 0 )
          obj->Extract( );
      } 
    }
}


/*
 *   COST ROUTINES
 */


bool will_trade( char_data* keeper, obj_data* obj )
{
  if( obj->pIndexData->materials != 0 
    && keeper->pShop->materials && obj->pIndexData->materials == 0 )
    return FALSE;

  return is_set( keeper->pShop->buy_type, obj->pIndexData->item_type );
}


int get_cost( char_data* keeper, char_data* ch, obj_data* obj, bool fBuy )
{
  obj_data*    inv;
  int        total  = 0;
  int         cost  = 0;
  int       number  = 0;

  if( obj == NULL || is_set( obj->extra_flags, OFLAG_NO_SELL )
    || !will_trade( keeper, obj ) )
    return 0;

  for( int i = 0; i < keeper->contents; i++ ) {
    inv = object( keeper->contents[i] );
    if( inv->pIndexData == obj->pIndexData )
      number += inv->number;
    }

  cost = obj->Cost( );

  if( ch->species == NULL ) 
    cost += (1-2*fBuy)*ch->shdata->skill[SKILL_HAGGLE]*cost/100;

  if( ch->shdata->skill[SKILL_HAGGLE] > 0 )
    ch->improve_skill( SKILL_HAGGLE );

  if( !fBuy ) {
    if( obj->pIndexData->item_type == ITEM_ARMOR
      || obj->pIndexData->item_type == ITEM_WEAPON )
      cost /= 12;
    else
      cost /= 4;
    }

  cost = cost*obj->condition/obj->pIndexData->durability
    *sqr(4-obj->rust)/16;

  switch( obj->pIndexData->item_type ) {
    case ITEM_STAFF :
    case ITEM_WAND :
      if( obj->value[0] != 0 )
        cost = cost*(1+obj->value[3]/obj->value[0])/2;
      break;

    case ITEM_DRINK_CON :
      if( fBuy )
        cost += obj->value[1]*liquid_table[ obj->value[2] ].cost/100;
      break;
    }    

  for( int i = 0; i < obj->selected; i++ )
    total += cost*12/(3+number+( fBuy ? -i : i ) );

  return total;
}


int repair_cost( char_data* keeper, obj_data* obj )
{
  obj_clss_data*   obj_clss  = obj->pIndexData;
  int                  cost;

  if( !will_trade( keeper, obj )
    || obj->pIndexData->repair > keeper->pShop->repair )
    return 0;

  cost = 50*sqr( obj_clss->repair )+obj_clss->cost
    *( obj_clss->durability-obj->condition )
    /( 2*obj_clss->durability );

  cost = cost*(20+obj->age)/20;  

  return cost;
}


/*
 *   BUY FUNCTION 
 */


bool buyable_pet( char_data* pet )
{
  if( pet->species == NULL || pet->leader != NULL
    || !is_set( &pet->species->act_flags, ACT_CAN_TAME ) )
    return FALSE;

  return TRUE;
}


thing_data* cantafford( thing_data* t1, char_data* ch, thing_data* t2 )
{
  obj_data*    obj  = (obj_data*) t1;
  mob_data* keeper  = (mob_data*) t2;

  obj->temp = get_cost( keeper, ch, obj, TRUE );

  return( remove_coins( ch, obj->temp, NULL ) ? obj : NULL );
}


thing_data* buy( thing_data* t1, char_data* ch, thing_data* )
{
  obj_data* obj = (obj_data*) t1;
 
  obj = (obj_data*) obj->From( obj->selected );   
  set_owner( obj, ch, NULL );
  obj->To( ch );

  return obj;
}


void do_buy( char_data *ch, char *argument )
{
  char             buf  [ MAX_INPUT_LENGTH ];
  char_data*    keeper;
  char_data*       pet;
  obj_data*        obj;
  room_data*      room;
  thing_array*   array;

  if( ( keeper = find_keeper( ch ) ) == NULL )
    return;

  /* PET SHOP */

  if( is_set( &ch->in_room->room_flags, RFLAG_PET_SHOP ) ) {
    if( ch->species != NULL  ) {
      send( ch, "Monsters can't buy pets." );
      return;
      }

    if( ( room = get_room_index( ch->in_room->vnum+1 ) ) == NULL ) {
      send( ch, "The pet shop is still under construction.\n\r" );
      return;
      }

    thing_array list;

    for( int i = 0; i < room->contents; i++ ) 
      if( ( pet = character( room->contents[i] ) ) != NULL
        && buyable_pet( pet ) )
        list += pet;

    if( ( pet = one_character( ch, argument, "buy", &list ) ) == NULL )
      return;

    if( pet->shdata->level > ch->shdata->level ) {
      send( ch, "%s is too high a level for you.\n\r", pet );
      return;
      }

    if( pet->species->price == 0 ) {
      send( ch,
        "That pet is not for sale until a god sets a price for it.\n\r" );
      return;
      }

    if( is_set( &pet->species->act_flags, ACT_MOUNT ) ) {
      if( has_mount( ch ) )
        return;
      }
    else {
      if( number_of_pets( ch ) >= 2 ) {
        send( ch, "You already have two pets.\n\r" );
        return;
        }
      }

    sprintf( buf, "You hand %s", keeper->descr->name ); 
    if( !remove_coins( ch, pet->species->price, buf ) ) {
      if( ch->shdata->level < LEVEL_APPRENTICE ) {
        send( ch, "You can't afford it.\n\r" );
        return;
        }
      send( ch, "You don't have enough gold, but it doesn't seem to\
 matter.\n\r" );
      }

    pet->From( );
    pet->To( ch->array );

    set_bit( &pet->status, STAT_PET );
    add_follower( pet, ch );

    send( ch, "Enjoy your pet.\n\r" );
    fsend( ch, "%s bought %s as a pet.\n\r", ch, pet );

    if( pet->reset != NULL ) {
      pet->reset->count--;
      pet->reset = NULL;
      }
    return;
    }

  /* OBJECT SHOP */

  thing_array list;

  for( int i = 0; i < keeper->contents; i++ ) {
    obj = (obj_data*) keeper->contents[i];
    if( will_trade( keeper, obj ) )
      list += obj;
    }
    
  if( ( array = several_things( ch, argument, "buy", &list ) ) == NULL )
    return;

  thing_array   subset  [ 4 ];
  thing_func*     func  [ 4 ]  = { heavy, many, cantafford, buy };

  sort_objects( ch, *array, keeper, 4, subset, func );
  
  page_priv( ch, NULL, empty_string );
  page_priv( ch, &subset[0], "can't lift" );
  page_priv( ch, &subset[1], "can't handle" );
  page_priv( ch, &subset[2], "can't afford" );
  page_publ( ch, &subset[3], "buy", keeper, "from", "for" );

  delete array;
}


void do_list( char_data* ch, char* argument )
{
  char_data*   keeper;
  char_data*      pet;
  thing_array*  array;
  obj_data*       obj;
  room_data*     room;

  if( ( keeper = find_keeper( ch ) ) == NULL )
    return;

  if( *argument == '\0' )
    argument = "all";

  /* PET SHOP */

  if( is_set( &ch->in_room->room_flags, RFLAG_PET_SHOP ) ) {
    if( ( room = get_room_index( ch->in_room->vnum+1 ) ) == NULL ) {
      send( ch, "The pet shop is still under construction.\n\r" );
      return;
      }

    thing_array list;

    for( int i = 0; i < room->contents; i++ ) 
      if( ( pet = character( room->contents[i] ) ) != NULL
        && buyable_pet( pet ) )
        list += pet;

    if( is_empty( list ) ) {
      process_tell( keeper, ch, "Sorry, I'm out of pets right now.\n\r" );
      return;
      }

    if( ( array = several_things( ch, argument, "list", &list ) ) == NULL )
      return;

    send( ch, "Copper Pieces: %d\n\r\n\r", get_money( ch ) );
    send_underlined( ch,
      "Pet                          Cost    Level\n\r" );

    for( int i = 0; i < *array; i++ ) {
      pet = (char_data*) array->list[i];
      send( ch, "%-25s%8d%8d\n\r", pet->Seen_Name( ch, 1, TRUE ),
        pet->species->price, pet->shdata->level );
      }

    delete array;

    return;
    }

  /* OBJECT SHOP */

  thing_array list;

  for( int i = 0; i < keeper->contents; i++ ) {
    obj = (obj_data*) keeper->contents[i];
    obj->selected = 1;
    if( ( obj->temp = get_cost( keeper, ch, obj, TRUE ) ) > 0 )
      list += obj;
    }

  if( is_empty( list ) ) {
    process_tell( keeper, ch,
      "Sorry, I have nothing to sell right now.\n\r" );
    return;
    }

  if( ( array = several_things( ch, argument, "list",  &list ) ) == NULL )
    return;

  page( ch, "Copper Pieces: %d\n\r\n\r", get_money( ch ) );
  page_underlined( ch, "Item                                     Cost\
    Level   Number   Condition\n\r" );

  char level [ 5 ];

  include_closed = FALSE;

  for( int i = 0; i < *array; i++ ) {
    obj = (obj_data*) array->list[i];

    if( !can_use( ch, obj->pIndexData, obj ) )
      sprintf( level, "***" );
    else
      sprintf( level, "%d", obj->pIndexData->level );

    page( ch, "%-37s%8d%8s%8d%5s%-s\n\r",
      truncate( obj->Seen_Name( ch, 1, TRUE ), 37 ), obj->temp, level,
      obj->number, "", obj->condition_name( ch, TRUE ) );
    }

  include_closed = TRUE;

  delete array;
}


/*
 *   SELL
 */


thing_data* sold( thing_data* t1, char_data*, thing_data* )
{
  return t1;
}


thing_data* uninterested( thing_data* thing, char_data* ch,
  thing_data* keeper )
{
  obj_data* obj = (obj_data*) thing;

  if( ( obj->temp = get_cost( (char_data*) keeper, ch, obj, FALSE ) ) <= 0 ) 
    return NULL;

  return obj;
}


thing_data* not_empty( thing_data* obj, char_data*, thing_data* )
{
  return( obj->contents == NULL ? obj : NULL );
}


void do_sell( char_data* ch, char* argument )
{
  char_data*   keeper;
  thing_array*  array;
  obj_data*       obj;

  if( ( keeper = find_keeper( ch ) ) == NULL )
    return;

  if( is_set( &ch->in_room->room_flags, RFLAG_PET_SHOP ) ) {
    process_tell( keeper, ch, "We don't buy pets." );
    ch->reply = keeper;
    return;
    }

  if( *argument == '\0' ) {
    send( ch, "Sell what?\n\r" );
    return;
    }

  if( ( array = several_things( ch, argument, "sell", 
    &ch->contents ) ) == NULL ) 
    return;

  thing_array   subset  [ 5 ];
  thing_func*     func  [ 5 ]  = { cursed, stolen, uninterested,
                                   not_empty, sold };

  sort_objects( ch, *array, keeper, 5, subset, func );

  page_priv( ch, NULL, empty_string );
  page_priv( ch, &subset[1], "don't own" );
  page_priv( ch, &subset[2], "isn't interested in", keeper );
  page_priv( ch, &subset[0], "can't let go of" );
  page_priv( ch, &subset[3], NULL, NULL, "isn't empty", "aren't empty" );
  page_publ( ch, &subset[4], "sell", keeper, "to", "for" );

  for( int i = 0; i < subset[4]; i++ ) {
    obj = (obj_data*) subset[4][i];
    obj = (obj_data*) obj->From( obj->selected );

    set_bit( obj->extra_flags, OFLAG_IDENTIFIED );
    set_bit( obj->extra_flags, OFLAG_KNOWN_LIQUID );

    if( obj->pIndexData->item_type == ITEM_WAND
      || obj->pIndexData->item_type == ITEM_STAFF ) 
      obj->value[3] = obj->pIndexData->value[3];

    free_string( obj->label, MEM_OBJECT );
    obj->label = empty_string;

    obj->owner = NULL;
    add_coins( ch, obj->temp );
    obj->To( keeper );
    consolidate( obj );
    }

  delete array;
}


void do_value( char_data* ch, char* argument )
{
  char           buf  [ MAX_STRING_LENGTH ];
  char_data*  keeper;
  obj_data*      obj;
  int           cost;
  int          rcost;
  int         blocks;

  if( ( keeper = find_keeper( ch ) ) == NULL )
    return;

  if( is_set( &ch->in_room->room_flags, RFLAG_PET_SHOP ) ) {
    process_tell( keeper, ch, "We don't buy pets" );
    return;
    }

  if( ( obj = one_object( ch, argument, "value",
    &ch->contents ) ) == NULL ) 
    return;

  if( !obj->droppable( ) ) {
    send( ch, "You can't let go of %s.\n\r", obj );
    return;
    }
  
  if( !obj->Belongs( ch ) ) {
    sprintf( buf, "%s is stolen so I would never buy it.",
      obj->Seen_Name( ch ) );
    process_tell( keeper, ch, buf );
    return;
    } 

  cost  = get_cost( keeper, ch, obj, FALSE );
  rcost = repair_cost( keeper, obj );
 
  if( obj->Damaged( ) ) {
    if( rcost > 0 ) 
      sprintf( buf, "I see %s is damaged.  I can repair it for %d cp %s ",
        obj->Seen_Name( ch ), rcost, cost > 0 ? "or" : "but" ); 
    else 
      sprintf( buf, "I see %s is damaged.  I am unable to repair it %s ",
        obj->Seen_Name( ch ), cost > 0 ? "but" : "and" );
    if( cost > 0 ) 
      sprintf( buf+strlen( buf ), "would give you %d cp for it.", cost );
    else
      strcat( buf, "am uninterested in buying it." );
    }
  else {
    if( cost > 0 )
      sprintf( buf, "I would pay you %d cp for %s.",
        cost, obj->Seen_Name( ch ) ); 
    else
      sprintf( buf, "I am uninterested in buying %s.",
        obj->Seen_Name( ch ) );
    }

  blocks = obj->pIndexData->blocks;
  if( ( cost = melt_cost( keeper, obj ) ) != 0 ) 
    sprintf( buf+strlen( buf ),
      "  I would melt it down to produce %d block%s for %d cp.",
      blocks, blocks == 1 ? "" : "s", cost );
      
  process_tell( keeper, ch, buf );
}


/*
 *   REPAIR ROUTINES
 */


void do_repair( char_data* ch, char* argument )
{
  char           buf  [ MAX_INPUT_LENGTH ];
  char_data*  keeper;
  obj_data*      obj;
  int           cost;
  int           cond;

  if( *argument == '\0' ) {
    send( ch, "Repair what?\n\r" );
    return;
    }

  if( ( keeper = find_keeper( ch ) ) == NULL )
    return;

  if( keeper->pShop->repair == 0 ) {
    process_tell( keeper, ch, "Sorry - I do not repair items." );
    return;
    }

  if( ( obj = one_object( ch, argument, "repair", &ch->contents ) ) == NULL ) 
    return;

  if( !obj->droppable( ) ) {
    send( ch, "You can't let go of %s.\n\r", obj );
    return;
    }

  if( ( cost = repair_cost( keeper, obj ) ) <= 0 ) {
    process_tell( keeper, ch, "That isn't something I can repair" );
    return;
    }

  if( ( cond = repair_condition( obj ) ) < 0 ) {
    process_tell( keeper, ch,
      "That item is too old to be worth repairing." );
    return;
    }

  if( !obj->Damaged( ) ) {
    process_tell( keeper, ch,
      "That isn't damaged enough to be worth repairing." );
    return;
    }

  sprintf( buf, "%s repairs %s for you at a cost of",
    keeper->Name( ch ), obj->Seen_Name( ch ) );
  *buf = toupper( *buf );
  if( !remove_coins( ch, cost, buf ) ) {
    sprintf( buf, "You can't afford the cost of repairing %s.", 
      obj->Seen_Name( ch ) );
    process_tell( keeper, ch, buf );   
    return;
    }
    
  fsend( ch, "%s gets %s repaired.\n\r", ch, obj );

  obj = (obj_data*) obj->From( 1 );

  obj->age       += int( 1+obj->rust*pow(cond-obj->condition,1.5)/100. );
  obj->condition  = cond;

  obj->To( &ch->contents );
  consolidate( obj );
}


/*
 *   MELT FUNCTIONS
 */


int melt_cost( char_data *keeper, obj_data *obj )
{
  int metal;

  for( metal = MAT_BRONZE; metal <= MAT_GOLD; metal++ )
    if( is_set( &obj->materials, metal ) )
      break;

  if( metal > MAT_GOLD ) 
    return 0;

  if( obj->pIndexData->blocks == 0 
    || keeper->pShop->materials & ( 1 << metal ) == 0 )
    return 0;

  return 100;
}


void do_melt( char_data *ch, char *argument )
{
  char           buf  [ MAX_INPUT_LENGTH ];
  char_data*  keeper;
  obj_data*      obj;
  int           cost;
  int         blocks;
  int          metal;
  int         length;

  if( ( keeper = find_keeper( ch ) ) == NULL )
    return;

  if( ( obj = one_object( ch, argument, "melt", &ch->contents ) ) == NULL ) 
    return;

  for( metal = MAT_BRONZE; metal <= MAT_GOLD; metal++ )
    if( is_set( &obj->materials, metal ) )
      break;

  if( metal > MAT_GOLD ) {
    fsend( ch, "%s is not made out of metal.", obj );
    return;
    }

  if( ( blocks = obj->pIndexData->blocks ) == 0 ) {
    fsend( ch, "%s does not contain enough metal to be worth melting.",
      obj );
    return;
    }

  if( !obj->droppable( ) ) {
    send( ch, "You can't let go of %s.\n\r", obj );
    return;
    }

  if( keeper->pShop->materials & ( 1 << metal ) == 0 ) {
    process_tell( keeper, ch,
      "Sorry that is not made out of a metal I deal with." );
    return;
    }

  cost = 100;

  sprintf( buf, "You hand %s to %s along with",
    obj->Seen_Name( ch ), keeper->Seen_Name( ch ) );
  if( !remove_coins( ch, cost, buf ) ) { 
    sprintf( buf, "You can't afford my fee of %d cp to melt %s.",
      cost, obj->Seen_Name( ch ) );
    process_tell( keeper, ch, buf );
    return;
    }
    
  fsend( ch, "%s has %s melted down.", ch, obj );
  sprintf( buf, "%s takes %s and places it in the furnace.  ",
    keeper->Seen_Name( ch ), obj->Seen_Name( ch ) );
  buf[0] = toupper( buf[0] );

  obj->Extract( 1 );

  if( ( obj = create( get_obj_index(
    ingot_vnum[metal-MAT_BRONZE] ) ) ) == NULL ) {
    bug( "Repair: Ingot for %s does not exist.", 
      material_table[metal].name );
    return;
    }

  obj->number = blocks;
  obj->shown  = blocks;
  set_bit( &obj->materials, metal );

  length = strlen( buf );
  sprintf( &buf[length],
  "%s then pulls it out and after much hammering and reheating hands you %s.",
    keeper->He_She( ), obj->Seen_Name( ch, blocks ) );
  buf[length] = toupper( buf[length] );
  fsend( ch, buf );

  obj->To( &ch->contents );
}


/*
 *  ONLINE EDITING OF SHOPS
 */


void do_shedit( char_data* ch, char* argument )
{
  char                  buf  [MAX_STRING_LENGTH ];
  mob_data*          keeper;
  shop_data*           shop;
  char_data*         victim;
  species_data*     species;
  int                number;
  
  for( shop = shop_list; shop != NULL; shop = shop->next )
    if( ch->in_room == shop->room ) 
      break;  

  if( *argument != '\0' && !can_edit( ch, ch->in_room ) )
    return;

  if( exact_match( argument, "new" ) ) {
    if( shop != NULL ) {
      send( ch, "There is already a shop here.\n\r" );
      return;
      }
    shop = new shop_data;
    shop->room = ch->in_room;
    shop->custom = NULL;
    shop->keeper = -1;
    shop->repair = 0;
    shop->materials = 0;
    shop->buy_type[0] = 0;
    shop->buy_type[1] = 0;
    shop->next = shop_list;
    shop_list = shop;
    send( ch, "New shop created here.\n\r" );
    return;
    }

  if( shop == NULL ) {
    send( ch, "There is no shop associated with this room.\n\r" );
    return;
    }

  if( *argument == '\0' ) {
    species = get_species( shop->keeper ); 
    sprintf( buf, "Shop Keeper: %s  [ Vnum: %d ]\n\r\n\r", ( species == NULL
      ? "none" : species->descr->name ), shop->keeper );
    sprintf( buf+strlen( buf ), "Repair: %d\n\r\n\r", shop->repair );
    send( buf, ch );
    return;
    }
  
  if( exact_match( argument, "delete" ) ) {
    remove( shop_list, shop );
    for( int i = 0; i < mob_list; i++ )
      if( mob_list[i]->pShop == shop )
        mob_list[i]->pShop = NULL;
    send( ch, "Shop deleted.\n\r" );
    return;
    }
   
  if( matches( argument, "keeper" ) ) {
    if( ( victim = one_character( ch, argument, "set keepr",
      ch->array ) ) == NULL )
      return;

    if( ( keeper = mob( victim ) ) == NULL ) {
      send( ch, "Players can not be shop keepers.\n\r" );
      return;
      }
    shop->keeper = keeper->species->vnum;
    keeper->pShop = shop;
    send( ch, "Shop keeper set to %s.\n\r", keeper->descr->name );
    return;
    }

  if( matches( argument, "repair" ) ) {
    if( ( number = atoi( argument ) ) < 0 || number > 10 ) {
      send( ch,
        "A shop's repair level must be between 0 and 10.\n\r" ); 
      return;
      }
    shop->repair = number;
    send( ch, "The shop's repair level is set to %d.\n\r", number );
    } 
}


void do_shflag( char_data* ch, char* argument )
{
  shop_data*       shop;
  const char*  response;

  for( shop = shop_list; shop != NULL; shop = shop->next )
    if( ch->in_room == shop->room ) 
      break;  

  if( shop == NULL ) {
    send( ch, "This room has no shop entry.\n\r" );
    return;
    }

#define types 3

  const char*  title [types] = { "Basic", "Obj_Types", "Materials" };
  int            max [types] = { MAX_SHOP, MAX_ITEM, MAX_MATERIAL };

  const char** name1 [types] = { &shop_flags[0], &item_type_name[0],
    &material_name[0] };
  const char** name2 [types] = { &shop_flags[1], &item_type_name[1],
    &material_name[1] };

  int*    flag_value [types] = { &shop->flags, shop->buy_type,
    &shop->materials };
  int      uses_flag [types] = { 1, 1, 1 };

  response = flag_handler( title, name1, name2, flag_value, max,
    uses_flag, (const char*) NULL, ch, argument, types );

#undef types

  if( response == NULL ) 
    send( ch, "No such flag.\n\r" );
  else
    room_log( ch, ch->in_room->vnum, response );

  return;
}


void do_shstat( char_data*, char* )
{
  return;
}


/*
 *   MISC SHOP ROUTINES
 */


char_data* active_shop( char_data* ch )
{
  room_data*    room  = ch->in_room;
  char_data*  keeper;

  if( !is_set( &room->room_flags, RFLAG_PET_SHOP )
    && !is_set( &room->room_flags, RFLAG_SHOP ) ) 
    return NULL;

  for( int i = 0; i < room->contents; i++ )
    if( ( keeper = mob( room->contents[i] ) ) != NULL
      && keeper->pShop != NULL && keeper->pShop->room == room 
      && IS_AWAKE( keeper ) && ch->Seen( keeper ) )
      return keeper;

  return NULL;
}


char_data* find_keeper( char_data* ch )
{
  char_data* keeper = NULL;

  for( int i = 0; ; i++ ) {
    if( i >= *ch->array ) {
      if( is_set( &ch->in_room->room_flags, RFLAG_PET_SHOP )
        || is_set( &ch->in_room->room_flags, RFLAG_SHOP ) ) {
        send( ch, "The shop keeper is not around right now.\n\r" );
        return NULL;
        }
      send( ch, "You are not in a shop.\n\r" );
      return NULL;
      } 
    if( ( keeper = mob( ch->array->list[i] ) ) != NULL
      && keeper->pShop != NULL )
      break;
    }

  if( !IS_AWAKE( keeper ) ) {
    send( ch, "The shopkeeper seems to be asleep.\n\r" );
    return NULL;
    }
   
  if( !ch->Seen( keeper ) && ch->shdata->level < LEVEL_APPRENTICE ) {
    do_say( keeper, "I don't trade with folks I can't see." );
    return NULL;
    }

  if( ch->species != NULL
    && !is_set( &ch->species->act_flags, ACT_HUMANOID ) ) {
    send( ch,
      "You can't carry anything so shopping is rather pointless.\n\r" );
    return NULL;
    }

  return keeper;
}


/*
 *   DISK ROUTINES
 */


void load_shops( void )
{
  shop_data*      shop  = NULL;
  custom_data*  custom;
  FILE*             fp;
  int             i, j;

  fprintf( stderr, "Loading Shops...\n\r" );

  fp = open_file( SHOP_FILE, "r" );
  
  if( strcmp( fread_word( fp ), "#SHOPS" ) ) 
    panic( "Load_shops: header not found" );

  for( ; ; ) {
    if( ( i = fread_number( fp ) ) == -1 )
      break;

    if( i == 0 ) {
      custom        = new custom_data;
      custom->item  = get_obj_index( fread_number( fp ) );
      custom->cost  = fread_number( fp );
  
      for( i = 0; i < MAX_INGRED; i++ ) {
        if( ( j = fread_number( fp ) ) == 0 ) {
          fread_number( fp );
          continue;
	  }
        custom->ingred[i] = get_obj_index( j );
        custom->number[i] = fread_number( fp );
        }
 
      if( custom->item == NULL ) {
        roach( "Load_Shops: Removing null custom item." );
        delete custom;
        }
      else if( shop == NULL ) {
        roach( "Load_Shops: Custom in null shop?" );
        delete custom;
        }
      else {
        custom->next = shop->custom;
        shop->custom = custom;
        }
   
      fread_to_eol( fp );
      continue;
      }

    shop = new shop_data;

    shop->keeper  = fread_number( fp );
  
    shop->flags       = fread_number( fp );
    shop->buy_type[0] = fread_number( fp );
    shop->buy_type[1] = fread_number( fp );

    shop->repair      = fread_number( fp );
    shop->materials   = fread_number( fp );
    shop->open_hour   = fread_number( fp );
    shop->close_hour  = fread_number( fp );

    fread_to_eol( fp );
  
    if( ( shop->room = get_room_index( i ) ) == NULL ) {
      roach( "Load_Shops: Deleting shop in non-existent room %d.", i ); 
      delete shop;
      shop = NULL;
      }
    else {
      shop->next = shop_list;
      shop_list  = shop; 
      }
    }

  fclose( fp );
  return;
}


void save_shops( )
{
  shop_data*      shop;
  custom_data*  custom;
  FILE*             fp;
  int                i;

  if( ( fp = open_file( SHOP_FILE, "w" ) ) == NULL )
    return;

  fprintf( fp, "#SHOPS\n" );

  for( shop = shop_list; shop != NULL; shop = shop->next ) {
    fprintf( fp, "%5d %5d ", shop->room->vnum, shop->keeper );
    fprintf( fp, "%5d %5d %5d ", shop->flags, shop->buy_type[0],
      shop->buy_type[1] );
    fprintf( fp, "%2d %5d %5d %5d\n", shop->repair, shop->materials,
      shop->open_hour, shop->close_hour );
    for( custom = shop->custom; custom != NULL; custom = custom->next ) {
      fprintf( fp, "    0 %5d %5d ", custom->item->vnum, custom->cost );
      for( i = 0; i < MAX_INGRED; i++ )
        fprintf( fp, "%5d %2d ", ( custom->ingred[i] == NULL ? 0 :
          custom->ingred[i]->vnum ), custom->number[i] );
      fprintf( fp, "\n" );
      }
    }
  fprintf( fp, "-1\n\n#$\n\n" );
  fclose( fp );

  return;
}