cm3/
cm3/clans/
cm3/mudprogs/
cm3/player/a/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *			 Shop and repair shop module			    *
 ****************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#ifndef WIN32
  #include <dirent.h>
#endif
#include "mud.h"



/*
 * Local functions
 */

#define	CD	CHAR_DATA
int	get_cost	args( ( CHAR_DATA *ch, SHOP_DATA *pShop,
				OBJ_DATA *obj, bool fBuy ) );
#undef CD

/* handler.c */
extern MAT_SHOP *find_matshop (int i);
extern MATERIAL_DATA *material_lookup( int number );
extern void learn_noncombat(CHAR_DATA *ch, int i);

/* makeobjs.c */
extern OBJ_DATA *make_ore (int i);


int get_cost( CHAR_DATA *ch, SHOP_DATA *pShop, OBJ_DATA *obj, bool fBuy )
{
	if (obj) {
	    if (fBuy) {
		/* Low cost items need the precision,
		 * but high cost items need to not overflow MAXINT -
		 * items over 21 mithril could not be sold before
		 */
		if (obj->cost < 1000000) 
		    return (obj->cost * pShop->profit_sell) / 100;
		else
		    return (obj->cost / 100) * pShop->profit_sell;
		} else {
	    	return obj->cost;
	    }
	}
	else
		return 0;
}

void do_buy( CHAR_DATA *ch, char *argument ) {
    char arg[MAX_INPUT_LENGTH];
    int maxgold;
	OBJ_DATA *obj;
	int cost;
	int noi = 1;		/* Number of items */
	sh_int mnoi = 100;	/* Max number of items to be bought at once */
	MAT_SHOP *matshop;
	MATERIAL_DATA *mat;
	int i;

    argument = one_argument( argument, arg );

    if ( arg[0] == '\0' ) {
	send_to_char( "Buy what?\n\r", ch );
	return;
    }

    if ( ( matshop = find_matshop ( ch->in_room->vnum) ) != NULL ) {
         for (i = 0;i < 5; i++) {
                mat = material_lookup(matshop->mat[i]);
                if (!mat) continue;
		if (!str_cmp(arg, mat->name)
		|| !str_prefix(arg, mat->name)) {
			if (ch->gold < mat->cost) {
				send_to_char("You don't have enough gold.\n\r", ch);
				return;
			}
	   	if ( ch->carry_number + 1 > can_carry_n( ch ) ) {
		        send_to_char( "You have your hands full.\n\r", ch );
		        return;
		}

		if ( ch->carry_weight + mat->weight > can_carry_w( ch ) ) {
        		send_to_char( "You can't carry that much weight.\n\r", ch );
        		return;
    		}
		ch->gold -= mat->cost;
		boost_economy(ch->in_room->area, mat->cost);
		obj = make_ore(matshop->mat[i]);
		obj_to_char(obj, ch);
		ch_printf(ch, "You buy %s.\n\r", mat->short_descr);
		act(AT_ACTION, "$n buys $p.", ch, obj, NULL, TO_ROOM);
		return;
		}
	    }
	return;
	}

    if (!ch->in_room->pShop) {
	send_to_char("This isn't a shop.\n\r", ch);
	return;
    }

    if (!str_cmp(ch->in_room->pShop->owner, "(for sale)")) {
	if (!str_cmp(arg, "shop")) {
	    if (ch->gold < 1000000) {
		send_to_char("You can't afford it.\n\r", ch);
		return;
	    }
		act(AT_ACTION, "$n purchases this shop.", ch, NULL, NULL, TO_ROOM);
		send_to_char("You purchase this shop for &C1 mithril.\n\r",ch);
		ch->gold -= 1000000;
		STRFREE(ch->in_room->pShop->owner);
		ch->in_room->pShop->owner = STRALLOC(ch->name);
		fold_area(ch->in_room->area, ch->in_room->area->filename, FALSE);
		return;
	}
    }

	maxgold = ch->in_room->pShop->gold;

	if ( is_number( arg ) ) {
	    noi = atoi( arg );
	    argument = one_argument( argument, arg );
	    if ( noi > mnoi ) {
		send_to_char("You can't buy that many items at once.\n\r", ch);
		return;
	    }
	}

	obj  = get_obj_list( ch, arg, ch->in_room->first_content );
	if (!obj) {
		send_to_char("There is no such item here.\n\r", ch);
		return;
	}
	cost = ( get_cost( ch, ch->in_room->pShop, obj, TRUE ) * noi );

        if (obj && IS_AFFECTED(ch, AFF_HAS_ARTI) && IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
                act(AT_ACTION, "$p evades your grasp.", ch, obj, NULL, TO_CHAR);
                act(AT_ACTION, "$p evades $n's grasp.", ch, obj, NULL, TO_ROOM);
                return;
        }

	if (IS_AFFECTED(ch, AFF_ETHEREAL)) {
		act(AT_ACTION, "Your hand passes through $p.", ch, obj, NULL, TO_CHAR);
		act(AT_ACTION, "$n's hand passes through $p.", ch, obj, NULL, TO_ROOM);
		return;
	}

	if ( cost <= 0 || !can_see_obj( ch, obj ) ) {
	    send_to_char("That item isn't sold here. Try 'list'.\n\r", ch);
	    return;
	}

	if ( noi > obj->count && !IS_OBJ_STAT(obj, ITEM_INVENTORY)) {
	    send_to_char("There aren't enough of that item here to buy that many.\n\r", ch);
	    return;
	}
	
	if ( ch->gold < cost ) {
	    send_to_char("You can't afford to buy that.\n\r", ch);
	    return;
	}

	if ( IS_OBJ_STAT(obj, ITEM_PROTOTYPE) &&
             IS_SET(ch->pcdata->permissions, PERMIT_BUILD) ) {
	    send_to_char("That is only a prototype, you can't buy that.\n\r", ch);
	    return;
	}

	separate_obj(obj);
	if ( ch->carry_number + get_obj_number( obj ) > can_carry_n( ch ) )
	{
	    send_to_char( "You can't carry that many items.\n\r", 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.\n\r", ch );
	    return;
	}

	ch->gold     -= cost;
	if (!IS_OBJ_STAT(obj, ITEM_INVENTORY))
		ch->in_room->pShop->gold += cost;

	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 );
	    if (str_cmp(ch->in_room->pShop->owner, "Keolah")) {
		/* If the shop is owned by a player, make sure their
		 * profits are saved
		 */
		fold_area(ch->in_room->area, ch->in_room->area->filename, FALSE);
		WAIT_STATE(ch, PULSE_VIOLENCE);
	    }
	} 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, "A clerk puts them into a bag and hands it to you.",
		ch, NULL, NULL, TO_CHAR );
	}


	if ( IS_OBJ_STAT( obj, ITEM_INVENTORY ) ) {
	    OBJ_DATA *buy_obj, *bag;

	    buy_obj = create_object( obj->pIndexData, 0 );

	    /*
	     * 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_room( obj );
	    obj_to_char( obj, ch );
	}

	return;
}

void do_list( CHAR_DATA *ch, char *argument ) {
        char arg[MAX_INPUT_LENGTH];
        char *rest;
        OBJ_DATA *obj;
        int cost, gp, count;
	MAT_SHOP *matshop; 
	int i;
	MATERIAL_DATA *mat;

        rest = one_argument( argument, arg );
 
	    if ( ( matshop = find_matshop(ch->in_room->vnum)) != NULL) {
		for (i = 0;i < 5; i++) {
			mat = material_lookup(matshop->mat[i]);
			if (!mat) continue;
   gp = mat->cost;
   pager_printf( ch, "[&C%dm ", (int)gp/1000000 );
   gp = gp % 1000000;
   pager_printf( ch, "&Y%dg ", (int)gp/10000 );
   gp = gp % 10000;
   pager_printf( ch, "&W%ds ", (int)gp/100 );
   gp = gp % 100;
   pager_printf( ch, "&O%dc&w", gp);
                pager_printf( ch, "] - %s\n\r",
                        mat->short_descr );
		}
		return;
	}

	if (!ch->in_room->pShop) {
		send_to_char("This isn't a shop.\n\r",ch);
		return;
	}

        count = 0;
        for ( obj = ch->in_room->first_content; obj;
                obj = obj->next_content )
        {
            if ( can_see_obj( ch, obj )
            && ( cost = get_cost( ch, ch->in_room->pShop, obj, TRUE ) ) > 0
            && ( arg[0] == '\0' || nifty_is_name( arg, obj->name ) ) )
            {
                if ( !count )
                    send_to_pager( "[Price] Item\n\r", ch );

			count++;
   gp = get_cost(ch, ch->in_room->pShop, obj, TRUE);
   pager_printf( ch, "[&C%dm ", (int)gp/1000000 );
   gp = gp % 1000000;
   pager_printf( ch, "&Y%dg ", (int)gp/10000 );
   gp = gp % 10000;
   pager_printf( ch, "&W%ds ", (int)gp/100 );
   gp = gp % 100;
   pager_printf( ch, "&O%dc&w", gp);
                pager_printf( ch, "] %s.\n\r",
                    capitalize( aoran(myobj(obj))) );
		    if (count > 50) {
                send_to_char( "There are many other items here besides these.\n\r", ch );
			break;
		    }
            }
        }
        
        if ( !count )
        {
            if ( arg[0] == '\0' )
                send_to_char( "There is nothing for sale here.\n\r", ch );
            else
                send_to_char( "That isnt for sale here.\n\r", ch );
        }
        return;
}

void do_sell( CHAR_DATA *ch, char *argument ) {
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    int cost, gp;

    one_argument( argument, arg );

    if (!ch->in_room->pShop) {
	send_to_char("This isn't a shop.\n\r", ch);
	return;
    }

    if ( arg[0] == '\0' )
    {
	send_to_char( "Sell what?\n\r", ch );
	return;
    }

    if (!str_cmp(arg, "shop")
    &&  !str_cmp(ch->name, ch->in_room->pShop->owner)) {
	do_withdraw(ch, "");
	act(AT_ACTION, "$n sells the deed to the shop.", ch, NULL, NULL, TO_ROOM);
	send_to_char("You sell the shop to the city for &C1 mithril.\n\r", ch);
	ch->gold += 1000000;
	STRFREE(ch->in_room->pShop->owner);
	ch->in_room->pShop->owner = STRALLOC("(for sale)");
		fold_area(ch->in_room->area, ch->in_room->area->filename, FALSE);
	return;
    }

    if ( str_cmp( arg, "all" ) && str_prefix( "all.", arg ) )
    {
	/* 'sell obj' */

    if ( ( obj = get_obj_carry( ch, arg ) ) == NULL )
    {
	send_to_char("You don't have that.\n\r", ch);
	return;
    }

    if ( !can_drop_obj( ch, obj ) )
    {
	send_to_char( "You can't let go of it!\n\r", ch );
	return;
    }

    if ( obj->timer > 0 )
    {
	send_to_char("You should preserve that first.\n\r", ch);
	return;
    }

    if (IS_OBJ_STAT(obj, ITEM_DREAMWORLD)) {
	send_to_char("The shop won't buy your imaginary items.\n\r", ch);
	return;
    }

    if ( ( cost = get_cost( ch, ch->in_room->pShop, obj, FALSE ) ) <= 0 )
    {
	send_to_char("The shop isn't interested.\r\n", ch);
	return;
    }

    if ( ch->in_room->pShop->type != -1
    &&   ch->in_room->pShop->type != obj->item_type ) {
	send_to_char("This shop does not deal in this type of items.\n\r", ch);
	return;
    }

    if ( ch->in_room->pShop->flag != -1
    &&  !xIS_SET(obj->extra_flags, ch->in_room->pShop->flag ) ) {
	send_to_char("This shop does not deal in items of this nature.\n\r", ch);
	return;
    }

    separate_obj( obj );

	if (!str_cmp(ch->in_room->pShop->owner, ch->name)) {
		act( AT_ACTION, "$n puts $p up for sale.", ch, obj, NULL, TO_ROOM);
		ch_printf(ch, "You put %s up for sale.\n\r", 
			aoran(myobj(obj)));
		obj_from_char(obj);
		obj_to_room(obj, ch->in_room);
		return;
	} else if ( ch->in_room->pShop->gold < obj->cost
    &&   str_cmp(ch->in_room->pShop->owner, "Keolah") ) {
	send_to_char("The shop cannot afford to buy this.\n\r", ch);
	return;
    }

    act( AT_ACTION, "$n sells $p.", ch, obj, NULL, TO_ROOM );
   gp = get_cost(ch, ch->in_room->pShop, obj, FALSE);
   ch_printf( ch, "You sell %s for &C%dmithril, ",
	aoran(obj->short_descr), (int)gp/1000000 );
   gp = gp % 1000000;
   ch_printf( ch, "&Y%dgold, ", (int)gp/10000 );
   gp = gp % 10000;
   ch_printf( ch, "&W%dsilver, ", (int)gp/100 );
   gp = gp % 100;
   ch_printf( ch, "and &O%dcopper&w coins.\n\r", gp);
    ch->gold     += cost;
    ch->in_room->pShop->gold -= cost;

	obj_from_char( obj );
	obj_to_room( obj, ch->in_room );

	} else {

	char *chk;
	bool fAll, found;
	OBJ_DATA *obj_next;

	/* 'sell all' or 'sell all.obj' */

	if ( !str_cmp(arg, "all") ) {
	    chk = arg;
	    fAll = TRUE;
	} else {
	    chk = &arg[4];
	    fAll = FALSE;
	}
	found = FALSE;
	gp = 0;
	for ( obj = ch->first_carrying; obj; obj = obj_next )
	{
	    obj_next = obj->next_content;

	    if ( (fAll || nifty_is_name_prefix( chk, obj->name ) )
	    &&   can_see_obj( ch, obj )
	    &&   obj->wear_loc == WEAR_NONE
	    &&   can_drop_obj( ch, obj ) )
	    {
		if ( obj->timer > 0 ) continue;

		if (IS_OBJ_STAT(obj, ITEM_DREAMWORLD)) continue;

		if ((cost = get_cost(ch, ch->in_room->pShop, obj, FALSE)) <= 0) continue;

		if ( ch->in_room->pShop->type != -1
		&&   ch->in_room->pShop->type != obj->item_type ) continue;

		if ( ch->in_room->pShop->flag != -1
		&&  !xIS_SET(obj->extra_flags, ch->in_room->pShop->flag ) ) continue;

		if ( ch->in_room->pShop->gold < obj->cost
		&&   str_cmp(ch->in_room->pShop->owner, "Keolah")
		&&   str_cmp(ch->in_room->pShop->owner, ch->name) ) continue;


		separate_obj( obj );

		found = TRUE;
		cost = get_cost(ch, ch->in_room->pShop, obj, FALSE);
		if (str_cmp(ch->in_room->pShop->owner, ch->name)) {
			gp += cost;
			ch->in_room->pShop->gold -= cost;
		}
		obj_from_char( obj );
		obj_to_room( obj, ch->in_room );
	    }
	}

	if (found) {
	if (!str_cmp(ch->in_room->pShop->owner, ch->name)) {
		act( AT_ACTION, "$n puts a bunch of stuff up for sale.", ch, obj, NULL, TO_ROOM);
		send_to_char("You put a bunch of stuff up for sale.\n\r", ch);
		return;
	} else {
		ch->gold     += gp;
		act( AT_ACTION, "$n sells a bunch of stuff.", ch, NULL, NULL, TO_ROOM );
		ch_printf( ch, "You sell a bunch of stuff for &C%dmithril, ", (int)gp/1000000 );
		gp = gp % 1000000;
		ch_printf( ch, "&Y%dgold, ", (int)gp/10000 );
		gp = gp % 10000;
		ch_printf( ch, "&W%dsilver, ", (int)gp/100 );
		gp = gp % 100;
		ch_printf( ch, "and &O%dcopper&w coins.\n\r", gp);
		STRFREE(ch->last_taken);
		ch->last_taken = STRALLOC("selling things");
		WAIT_STATE(ch, PULSE_VIOLENCE);
		return;
	}
	} else {
		send_to_char("You have nothing this shop can buy.\n\r", ch);
		return;
	}
	}
}



void do_value( CHAR_DATA *ch, char *argument ) {
    OBJ_DATA *obj;
    int gp;

    if ( argument[0] == '\0' )
    {
	send_to_char( "Value what?\n\r", ch );
	return;
    }

    if (!ch->in_room->pShop) {
	send_to_char("This isn't a shop.\n\r", ch);
	return;
    }

    if ( ( obj = get_obj_carry( ch, argument ) ) == NULL )
    {
	send_to_char("You don't have any such item.\n\r", ch);
	return;
    }

    if ( ( gp = get_cost( ch, ch->in_room->pShop, obj, FALSE ) ) <= 0 )
    {
	send_to_char("The shop isn't interested in that.\n\r", ch);
	return;
    }

   ch_printf( ch, "%s is worth &C%dmithril, ",
        aoran(obj->short_descr), (int)gp/1000000 );
   gp = gp % 1000000;
   ch_printf( ch, "&Y%dgold, ", (int)gp/10000 );
   gp = gp % 10000;
   ch_printf( ch, "&W%dsilver, ", (int)gp/100 );
   gp = gp % 100;
   ch_printf( ch, "and &O%dcopper&w coins.\n\r", gp);

    return;
}

void do_repair( CHAR_DATA *ch, char *argument ) {
    PART_DATA *part;
    OBJ_DATA *obj;
    CHAR_DATA *victim = NULL;
	char buf[MAX_STRING_LENGTH];

    if ( argument[0] == '\0' ) {
	victim = ch;
    }

    if ( ( obj = get_obj_carry( ch, argument ) ) == NULL ) {
	if (( victim = get_char_room( ch, argument) ) == NULL) {
		send_to_char("You don't see that here.\n\r", ch);
		return;
	}
    }

	learn_noncombat(ch, SK_SMITH);

    if ( number_percent( ) * (IS_AFFECTED(ch, AFF_NUISANCE) ? 2 : 1)
    > (IS_NPC(ch) ? 100 : LEARNED(ch, gsn_repair)) ) {
	if (obj) {
		sprintf(buf, "repairing the %s", myobj(obj));
		ch->last_taken = STRALLOC(buf);
		act( AT_SKILL, "You attempt to repair your $t, but damage it further.", ch, myobj(obj), NULL, TO_CHAR);
		act( AT_SKILL, "$n attempts to repair $s $t, but damages it.", ch, myobj(obj), NULL, TO_ROOM);
		damage_obj(obj);
	}
	if (victim) {
		sprintf(buf, "repairing %s", victim->name);
		ch->last_taken = STRALLOC(buf);
    if (!IS_AFFECTED(victim, AFF_CONSTRUCT)) {
        send_to_char("Just how do you propose to do that?\n\r", ch);
        return;
    }
	    if (victim != ch) {
		act( AT_SKILL, "You attempt to repair $N, but damage $M further.", ch, NULL, victim, TO_CHAR );
		act( AT_SKILL, "$n attempts to repair you, but damages you further.", ch, NULL, victim, TO_VICT);
		act( AT_SKILL, "$n attempts to repair $N, but damages $M further.", ch, NULL, victim, TO_NOTVICT);
	    } else {
		act( AT_SKILL, "You attempt to repair yourself, but damage yourself further.", ch, NULL, NULL, TO_CHAR);
		act( AT_SKILL, "$n attempts to repair $mself, but damages $mself further.", ch, NULL, NULL, TO_ROOM);
	    }
		lose_hp(victim, 20);
	}
	learn_from_failure( ch, gsn_repair );
    } else {
	if (obj) {
		sprintf(buf, "repairing the %s", myobj(obj));
		ch->last_taken = STRALLOC(buf);
		act( AT_SKILL, "You carefully repair your $t.", ch, myobj(obj), NULL, TO_CHAR);
		act( AT_SKILL, "$n carefully repairs $s $t.", ch, myobj(obj), NULL, TO_ROOM);
		obj->condition = number_fuzzy(obj->weight * 50);
	}
	if (victim) {
		int amt;

    if (!IS_AFFECTED(victim, AFF_CONSTRUCT)) {
        send_to_char("Just how do you propose to do that?\n\r", ch);
        return;
    }

		sprintf(buf, "repairing %s", victim->name);
		ch->last_taken = STRALLOC(buf);
	    if (victim != ch) {
		act( AT_SKILL, "You carefully repair $N.", ch, NULL, victim, TO_CHAR);
		act( AT_SKILL, "$n carefully repairs you.", ch, NULL, victim, TO_VICT);
		act( AT_SKILL, "$n carefully repairs $N.", ch, NULL, victim, TO_NOTVICT);
	    } else {
		act( AT_SKILL, "You carefully repair yourself.", ch, NULL, NULL, TO_CHAR);
		act( AT_SKILL, "$n carefully repairs $mself.", ch, NULL, NULL, TO_ROOM);
	    }
        	amt = number_range(ch->pcdata->noncombat[SK_SMITH],
                	ch->pcdata->noncombat[SK_SMITH]*5);
        	if (victim != ch) amt *= 2;
        	if (!IS_FIGHTING(ch)) amt *= 2;
	        victim->hit += amt;
        for (part = victim->first_part;part;part = part->next) {
            if (part->flags == PART_SEVERED
            && part->cond == PART_WELL
            && (part->connect_to
            ?   part->connect_to->flags != PART_SEVERED
            :   TRUE)
            &&  amt > 300) {
                act(AT_MAGIC, "You replace your $t.",
                        victim, part_locs[part->loc], NULL, TO_CHAR);
                act(AT_MAGIC, "$n replaces $s $t.",
                        victim, part_locs[part->loc], NULL, TO_ROOM);
                part->flags = PART_WELL;
                return; /* No more healing after a part is regened */
            } else {
                part->cond = UMIN(PART_WELL, part->cond+amt/10);
            }
        }
	}
	learn_from_success( ch, gsn_repair );
    }
}

/* ------------------ Shop Building and Editing Section ----------------- */


void do_makeshop( CHAR_DATA *ch, char *argument )
{
    SHOP_DATA *shop;
    int vnum;
    ROOM_INDEX_DATA *room;

    if ( !argument || argument[0] == '\0' )
    {
	vnum = ch->in_room->vnum;
	room = ch->in_room;
    } else {

    vnum = atoi( argument );
    
    if ( (room = get_room_index(vnum)) == NULL )
    {
	send_to_char( "Room not found.\n\r", ch );
	return;
    }
    }

    if ( room->pShop )
    {
	send_to_char( "This room already has a shop.\n\r", ch );
	return;
    }

    CREATE( shop, SHOP_DATA, 1 );

    LINK( shop, first_shop, last_shop, next, prev );
    shop->room		= vnum;
    shop->profit_buy	= 90;
    shop->profit_sell	= 120;
    shop->type		= -1;
    shop->flag		= -1;
    shop->owner		= STRALLOC("(for sale)");
    shop->gold		= 0;
    room->pShop		= shop;
    send_to_char( "Done.\n\r", ch );
    return;
}


void do_shopset( CHAR_DATA *ch, char *argument )
{
    SHOP_DATA *shop;
    ROOM_INDEX_DATA *room, *room2;
    char arg1[MAX_INPUT_LENGTH];
    int vnum, value;

    if (IS_NPC(ch)) {
	huh(ch);
	return;
    }
    
    argument = one_argument( argument, arg1 );

    if ( arg1[0] == '\0' )
    {
	send_to_char( "Usage: shopset <field> value\n\r", ch );
	send_to_char( "\n\rField being one of:\n\r", ch );
	if (IS_SET(ch->pcdata->permissions, PERMIT_HIBUILD))
	send_to_char( "  room salary sell type flag owner gold\n\r", ch );
	else
	send_to_char( "  sell salary\n\r", ch);
	return;
    }

    vnum = atoi( arg1 );

    room = ch->in_room;

    if ( !room->pShop )
    {
	send_to_char( "This room doesn't keep a shop.\n\r", ch );
	return;
    }
    shop = room->pShop;
    value = atoi( argument );

    if ( !str_cmp( arg1, "sell" )
    &&   (IS_SET(ch->pcdata->permissions, PERMIT_HIBUILD)
    ||   !str_cmp(ch->name, shop->owner)) )
    {
	if ( value < 0 )
	{
	    send_to_char( "Out of range.\n\r", ch );
	    return;
	}
	shop->profit_sell = value;
	send_to_char( "The selling profit for this shop has been changed.\n\r", ch );
	fold_area(ch->in_room->area, ch->in_room->area->filename, FALSE);
	return;
    }

    if ( !str_cmp( arg1, "salary" )
    &&   (IS_SET(ch->pcdata->permissions, PERMIT_HIBUILD)
    ||   !str_cmp(ch->name, shop->owner)) )
    {
	if (shop->gold && !IS_SET(ch->pcdata->permissions, PERMIT_HIBUILD)) {
		send_to_char("You can't change your shopkeeper's salary with money in the vault.\n\rWithdraw first, then change it.\n\r", ch);
		return;
	}
	if ( value < 0 || value > 100 )
	{
	    send_to_char( "Out of range.\n\r", ch );
	    return;
	}
	shop->profit_buy = value;
	send_to_char( "The salary for this shopkeeper has been changed.\n\r", ch );
	fold_area(ch->in_room->area, ch->in_room->area->filename, FALSE);
	return;
    }

    if (!IS_SET(ch->pcdata->permissions, PERMIT_HIBUILD)) {
	send_to_char("Invalid option.\n\r", ch);
	return;
    }

    if ( !str_cmp( arg1, "type" ) )
    {
	if (!str_cmp(argument, "none")) {
		shop->flag = -1;
	} else {
	if ( !is_number(argument) )
		value = get_otype(argument);
	if (value < 0 || value > MAX_ITEM_TYPE )
	{
		send_to_char( "Invalid item type.\n\r", ch);
		return;
	}
	shop->type = value;
	}
	send_to_char("Done.\n\r", ch);
	return;
    }

    if ( !str_cmp( arg1, "flag" ) )
    {
	if (!str_cmp(argument, "none")) {
		shop->flag = -1;
	} else {
	value = get_oflag(argument);
	if (value < 0 || value > MAX_BITS ) {
		send_to_char( "Invalid flag.\n\r", ch);
		return;
	}
	shop->flag = value;
	}
	send_to_char("Done.\n\r", ch);
	return;
    }

    if ( !str_cmp( arg1, "owner" ) )
    {
	STRFREE(shop->owner);
	shop->owner = STRALLOC(argument);
	send_to_char("Done.\n\r", ch);
	return;
    }

    /* This doesn't work right now for some reason */
    if ( !str_cmp( arg1, "room" ) )
    {
	if ( (room2 = get_room_index(vnum)) == NULL )
	{
	    send_to_char( "Room not found.\n\r", ch );
	    return;
	}
	if ( room2->pShop )
	{
	    send_to_char( "That room already has a shop.\n\r", ch );
	    return;
	}
	room->pShop  = NULL;
	room2->pShop = shop;
	shop->room = value;
	send_to_char( "Done.\n\r", ch );
	return;
    }

    do_shopset( ch, "" );
    return;
}


void do_shopstat( CHAR_DATA *ch, char *argument )
{
    SHOP_DATA *shop;
    ROOM_INDEX_DATA *room;
    int vnum, gp;
    struct stat fst;
	char buf[MAX_STRING_LENGTH];

    if (IS_NPC(ch)) {
	huh(ch);
	return;
    }
    
    if ( argument[0] == '\0' )
    {
	vnum = ch->in_room->vnum;
	room = ch->in_room; 
    } else {

    vnum = atoi( argument );
    
    if ( (room = get_room_index(vnum)) == NULL )
    {
	send_to_char( "Room not found.\n\r", ch );
	return;
    }
    }

    if ( !room->pShop )
    {
	send_to_char( "This room doesn't keep a shop.\n\r", ch );
	return;
    }
    shop = room->pShop;

	if (IS_SET(ch->pcdata->permissions, PERMIT_HIBUILD))
    ch_printf( ch, "Room: [%d] %s\n\r", shop->room, room->name );
	else
    ch_printf( ch, "Stats for %s...\n\r", room->name );

	if (!str_cmp(shop->owner, ch->name)
	||   IS_SET(ch->pcdata->permissions, PERMIT_HIBUILD)) {
    ch_printf( ch, "Profit:  Salary %3d%%  Sell %3d%%  Vault: ",
			shop->profit_buy,
			shop->profit_sell);
   gp = shop->gold;
   ch_printf( ch, "&C%dm ", (int)gp/1000000 );
   gp = gp % 1000000;
   ch_printf( ch, "&Y%dg ", (int)gp/10000 );
   gp = gp % 10000;
   ch_printf( ch, "&W%ds ", (int)gp/100 );
   gp = gp % 100;
   ch_printf( ch, "&O%dc&w\n\r", gp);
	}

	/* Clear out shops of players that no longer exist */
    if (str_cmp(shop->owner, "(for sale)")) {
    sprintf( buf, "%s%c/%s", PLAYER_DIR, LOWER(shop->owner[0]), shop->owner );
    if ( stat( buf, &fst ) == -1 ) {
      STRFREE(shop->owner);
	shop->owner = STRALLOC("(for sale)");
	fold_area(ch->in_room->area, ch->in_room->area->filename, FALSE);
    }
	}
    ch_printf( ch, "The owner of this shop is %s.\n\r", capitalize(shop->owner));
    ch_printf( ch, "This shop will sell %s %ss.\n\r", 
			shop->flag == -1 ? "any" :
			o_flags[shop->flag],
			shop->type == -1 ? "item" :
			o_types[shop->type]);
    return;
}


void do_shops( CHAR_DATA *ch, char *argument ) {
    int gp;
    SHOP_DATA *shop;

    if (IS_NPC(ch)) {
	huh(ch);
	return;
    }

    if ( !first_shop )
    {
	send_to_char( "There are no shops.\n\r", ch );
	return;
    }

    set_char_color( AT_NOTE, ch );
    if (IS_SET(ch->pcdata->permissions, PERMIT_HIBUILD))
    for ( shop = first_shop; shop; shop = shop->next )
	pager_printf( ch, "Room: %5d Salary: %3d Sell: %3d Type: %d Flag: %d Owner: %s\n\r",
		shop->room,	   shop->profit_buy, shop->profit_sell,
		shop->type, shop->flag, shop->owner);
    else
    for ( shop = first_shop; shop; shop = shop->next ) {
	if (!str_cmp(shop->owner, ch->name)) {
	pager_printf( ch, "Room: %20s in %10s   Salary: %3d   Sell: %3d  Vault: ",
		get_room_index(shop->room)->name,
		get_room_index(shop->room)->area->name,	   
		shop->profit_buy, shop->profit_sell);
   gp = shop->gold;
   pager_printf( ch, "&C%dm ", (int)gp/1000000 );
   gp = gp % 1000000;
   pager_printf( ch, "&Y%dg ", (int)gp/10000 );
   gp = gp % 10000;
   pager_printf( ch, "&W%ds ", (int)gp/100 );
   gp = gp % 100;
   pager_printf( ch, "&O%dc&w\n\r", gp);
    }
    }
    return;
}