/** * @author Someone on DW, most likely. * @changed Changed to use carpentry skills for fixing wooden things, * and added variable gp costs. * - Sandoz, June 2003. */ #include <tasks.h> #define SKILLS ({"crafts.smithing.black.weapons", \ "crafts.smithing.black.armour", \ "crafts.carpentry.weapons", \ }) #define A_MAX 5 #define C_MAX 100 #define A_COND 5 #define C_COND 25 #define SCALE 50 #define MIN_GP_COST 5 #define MAX_GP_COST 60 inherit COMMAND_BASE; /** * This method is used to determine how much to give a rough * estimate as to how much it will cost to fix a given item. * @param player the person doing the fixing * @param item the item being fixed * @param costing whether or not the cost to fix is being estimated * @param max the maximum condition of the item (optional) * @param cond the current condition of the item (optional) * @param low the lowest condition of the item (optional) * @return the cost in brass coins to repair the item */ varargs int query_fix_cost( object player, object item, int costing, int max, int cond, int low ) { int cost, diff, per; max = max || item->query_max_cond(); cond = cond || item->query_cond(); low = low || item->query_lowest_cond(); diff = max - cond; per = 100 - ENV( player )->query_discount( player ); if( per < 0 ) per = 0; cost = ( diff * sqrt( item->query_full_value() ) ) / max; cost *= A_MAX + ( C_MAX * ( max - low ) ) / max; cost *= A_COND + ( C_COND * ( cond - low ) ) / ( cond + !cond ); cost /= SCALE; if( costing ) cost *= 2; else cost += roll_MdN( 4, cost / 4 ); cost = ( cost * per ) / 100; cost = ( cost < 100 ? 100 : cost ); return cost; } /* query_fix_cost() */ /** * This method returns the internal type of an item, to determine which * skill to use when fixing it. * @param item the item to test * @return 0 for crafts.smithing.black.weapons, 1 for crafts.smithing.black.armour */ int query_item_type( object ob ) { return ( ob->query_weapon() == 1 ) + // Could be a living thing, that they're carrying, that's fighting // and has been using a weapon... Unlikely, I know, but still. ( ( 2 * ob->query_armour() ) | ( 2 * ( ob->query_scabbard() && !ob->query_clothing() ) ) ); } /* query_item_type() */ /** * This returns whether or not a given item is considered to be 'fixed' * or not. This means it is in 98% of its maximum condition. * @param item the item to test for fixedness. * @return 1 if the item is fixed, 0 if it is not */ int test_fixed( object item ) { return ( 100 * item->query_cond() > 98 * item->query_max_cond() ); } /* test_fixed() */ /** @ignore yes */ int cmd( object *things, int costing ) { int type, bonus, cond, low, max, diff, cost, val, pl, gp_cost; object here, item, fixer; string place, mess, skill; if( TP->query_fighting() ) { add_failed_mess("You cannot $V anything in the heat of battle.\n"); return 0; } fixer = TP; here = ENV( fixer ); if( !here || !here->query_property("smithy") ) { add_failed_mess("You are not in a smithy, so you cannot fix " "anything.\n"); return 0; } if( sizeof(things) > 1 ) { add_failed_mess("You can only fix one thing at a time.\n"); return 0; } place = here->query_property("place") || "default"; item = things[ 0 ]; type = query_item_type( item ); pl = query_group(item); if( !type ) { add_failed_mess("$I "+({"is", "are"})[pl]+" neither armour " "nor a weapon.\n", things ); return 0; } if( item->query_worn_by() ) { add_failed_mess("You should probably remove $I before making "+ ({"it", "them"})[pl]+" hot and hitting "+ ({"it", "them"})[pl]+" with a hammer.\n", things ); return 0; } switch( item->query_material() ) { case "leather" : add_failed_mess("$I "+({"is", "are"})[pl]+" made of leather. " "How do you expect to heat "+({"it", "them"})[pl]+" in the " "forge without destroying "+({"it", "them"})[pl]+"?\n", things ); return 0; case "cloth" : add_failed_mess("$I "+({"is", "are"})[pl]+" made of cloth. " "How do you expect to heat "+({"it", "them"})[pl]+" in the " "forge without destroying "+({"it", "them"})[pl]+"?\n", things ); return 0; case "stone" : add_failed_mess("$I "+({"is", "are"})[pl]+" made of stone. How do " "you expect to improve "+({"it", "them"})[pl]+" by hitting "+ ({"it", "them"})[pl]+" with a hammer?\n", things ); return 0; case "wood" : skill = SKILLS[ 2 ]; break; case "metal" : case "steel" : case "iron" : case "copper" : case "brass" : case "bronze" : case "gold" : case "silver" : skill = SKILLS[ type - 1 ]; break; default : add_failed_mess("$I "+({"is", "are"})[pl]+" not made from metal " "nor wood.\n", things ); return 0; } if( test_fixed( item ) ) { add_failed_mess("$I "+({"is", "are"})[pl]+" already in top " "condition.\n", things ); return 0; } if( ( bonus = fixer->query_skill_bonus( skill ) ) < 10 ) { add_failed_mess("You stare at $I for a while, but give up after a " "while of cogitating because you cannot decide where to start.\n", things ); return 0; } val = fixer->query_value_in( place ); if( place != "default") val += fixer->query_value_in("default"); max = item->query_max_cond() || 1; low = item->query_lowest_cond() || 1; cond = item->query_cond(); cost = query_fix_cost( TP, item, costing, max, cond, low ); if( costing ) { add_succeeded_mess( ({"It would probably cost you about "+ MONEY_H->money_value_string( cost, place )+" to attempt to " "fix $I.\n", ""}), things ); return 1; } if( val < cost && !fixer->query_property("freelance smith") ) { add_failed_mess("You cannot afford the materials to fix $I.\n", things ); return 0; } if( ( gp_cost = MAX_GP_COST - MAX_GP_COST * cond / max ) < MIN_GP_COST ) gp_cost = MIN_GP_COST; event( TP, "inform", sprintf("Cond: %i, Max Cond: %i, GP Cost: %i", cond, max, gp_cost ), "debug"); if( !TASKER->point_tasker( TP, "crafts", gp_cost ) ) { add_failed_mess("You do not have enough energy to $V $I.\n", things ); return 0; } if( !cond ) { add_succeeded_mess( ({"You begin to work on $I when "+ ({"it", "they"})[pl]+" break"+({"s", ""})[pl]+"! "+ ({"it", "they"})[pl]+" must have been too damaged to fix.\n", "$N begin$s to work on $I when "+({"it", "they"})[pl]+" break"+ ({"s", ""})[pl]+"!\n"}), things ); item->break_me(); return 1; } diff = max - cond; if( diff > bonus ) { diff = 200 * diff / max; switch( TASKER->perform_task( fixer, skill, diff, TM_COMMAND ) ) { case AWARD : tell_object( fixer, "%^YELLOW%^"+replace( ({ "As you begin to fix $I, you realise how to make better use " "of the materials.", "As you work on $I, you find that you're more able to fix "+ ({"it", "them"})[pl]+" completely.", "You discover that you can fix $I more effectively." })[ random( 3 ) ], "$I", item->the_short() )+"%^RESET%^\n"); case SUCCEED : XP_H->handle_xp( TP, gp_cost, 1 ); diff = max - cond; break; default : XP_H->handle_xp( TP, gp_cost, 0 ); diff = bonus; } } item->adjust_cond( diff ); // This allows NPC smithies to work for free and then charge later. if( !fixer->query_property( "freelance smith" ) ) fixer->pay_money( MONEY_H->create_money_array( cost, place ), place ); if( test_fixed( item ) ) mess = "You fix $I, bringing "+({"it", "them"})[pl]+" to top " "condition."; else mess = "You manage to fix $I a little, although "+ ({"it is", "they are"})[pl]+" still not in top condition."; add_succeeded_mess( ({ mess + "\nThe repair materials cost you "+ MONEY_H->money_value_string( cost, place )+".\n", "$N fixes up $I.\n" }), things ); return 1; } /* cmd() */ /** @ignore yes */ mixed *query_patterns() { return ({ "<indirect:object:me>", (: cmd( $1, 0 ) :), "cost <indirect:object:me>", (: cmd( $1, 1 ) :), }); } /* query_patterns() */