/* -*- LPC -*- */ /* * $Locker: $ * $Id: fix.c,v 1.22 2003/06/07 01:51:38 pinkfish Exp $ */ #include <money.h> #include <tasks.h> #define TEACH_LEVEL 10 #define LEARN_LEVEL 10 #define SKILL "crafts.smithing.black" #define SKILLS ({ "crafts.smithing.black.weapons", \ "crafts.smithing.black.armour", \ "crafts.smithing.black.tools" }) #define A_MAX 5 #define C_MAX 100 #define A_COND 5 #define C_COND 25 #define SCALE 50 // These mapp to the SKILLS array up the top. #define USE_WEAPON_SKILL 1 #define USE_ARMOUR_SKILL 2 #define USE_TOOL_SKILL 3 inherit "/cmds/guild_base"; int query_item_type( object ob ); int query_fix_cost( object player, object smithy, object item, int costing, int max, int cond, int low ); int test_fixed( object item ); /** @ignore yes */ void create() { ::create(); set_nroff_file("fix"); set_command_name("fix"); add_teach_skill(SKILL, 10, 10); } /* create() */ /** * This finds the smithy either as an object in the room or as the * room itself. */ object find_smithy(object player) { if (environment(player)->query_property("smithy")) { return environment(player); } foreach (object ob in all_inventory(player)) { if (ob->query_smithy()) { return ob; } } return 0; } /** @ignore yes */ int cmd( object *things, int costing ) { int type, bonus, cond, low, max, diff, cost, val, award; int new_cost; object here, item, fixer; string place; fixer = this_player(); here = find_smithy(fixer); if ( !here || !here->query_property( "smithy" ) ) { add_failed_mess( "You are not in a smithy, so you cannot fix " "anything.\n" ); return 0; } place = here->query_property( "place" ); if ( !place || ( place == "" ) ) place = "default"; if ( sizeof( things ) > 1 ) { add_failed_mess( "You can only fix one thing at a time.\n" ); return 0; } item = things[ 0 ]; type = query_item_type( item ); if ( !type ) { add_failed_mess( "$I is 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 " "hot and hitting it with a hammer.\n", things ); return 0; } if( member_array( "leather", item->query_materials() ) != -1 ) { add_failed_mess( "$I would be destroyed if you put it in the fire.\n", things ); return 0; } if( member_array( "wool", item->query_materials() ) != -1 ) { add_failed_mess( "Putting a woolen item in the fire isn't going " "to improve its condition.\n", things ); return 0; } if( item->query_unfixable() ) { add_failed_mess( "Sticking $I in a hot forge probably isn't " "going to do much for its condition.\n", things ); return 0; } bonus = (int)fixer->query_skill_bonus( SKILLS[ type - 1 ] ); val = (int)fixer->query_value_in( place ); if ( place != "default" ) val += (int)fixer->query_value_in( "default" ); low = (int)item->query_lowest_cond(); if ( !low ) low = 1; cond = (int)item->query_cond(); max = (int)item->query_max_cond(); if ( !max ) max = 1; if ( test_fixed( item ) ) { add_failed_mess( "$I is already in top condition.\n", things ); return 0; } diff = max - cond; cost = query_fix_cost( this_player(), here, item, costing, max, cond, low ); new_cost = here->generate_cost(cost, 0); if (new_cost == -1) { return 0; } if (new_cost) { cost = new_cost; } if ( ( diff > bonus ) && !costing ) { diff = ( 150 * diff ) / max; switch ( (int)TASKER->perform_task( fixer, SKILLS[ type-1 ], diff, TM_COMMAND ) ) { case AWARD : award = 1; case SUCCEED : diff = max - cond; break; default : diff = bonus; } } if ( ( val < cost ) && !fixer->query_property( "freelance smith" ) && !costing ) { add_failed_mess( "You cannot afford the materials to fix " "$I.\n", things ); return 0; } if ( costing ) { add_succeeded_mess( ({ "To attempt to fix $I, it would probably cost " "you about " + MONEY_HAND->money_value_string( cost, place ) + ".\n", "" }), things ); return 1; } if ( !cond ) { add_succeeded_mess( ({ "You begin to work on $I when it breaks! " "It must have been too damaged to fix.\n", "$N begin$s to work on $I when it breaks!\n" }), things ); item->break_me(); return 1; } 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( (mixed *)MONEY_HAND->create_money_array( cost, place ), place ); here->generate_cost(cost, 1); } if ( award ) { write( "%^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 able to fix it completely.", "You discover " "that you can fix $I more effectively." })[ random( 3 ) ], "$I", item->the_short() ) +"%^RESET%^\n" ); } if ( test_fixed( item ) ) write( "You fix "+ item->the_short() + ", bringing it to top condition.\n" ); else write( "You manage to fix "+ item->the_short() + " a little, although it's still not in top condition.\n" ); write( "The repair materials cost you " + MONEY_HAND->money_value_string( cost, place ) +".\n" ); add_succeeded_mess( ({ "", "$N fixes up $I.\n" }), things ); return 1; } /* cmd() */ /** * 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() ); } /* item() */ /** * 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 1 for crafts.smithing.black.weapons, 2 for * crafts.smithing.black.armour, 3 for tools */ int query_item_type( object ob ) { // Arf. This is just nasty. // return ( ( ob->query_weapon() == 1 ) | // ( 1 * ( ob->query_material() == "metal" ) ) ) + // /* 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() ) ); if ( ob->query_weapon() == 1 ) { return USE_WEAPON_SKILL; } if ( ob->query_armour() || ob->query_scabbard() ) { return USE_ARMOUR_SKILL; } if ( ob->query_material() == "metal" ) { return USE_TOOL_SKILL; } // Nothing! return 0; } /* query_item_type() */ /** * 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 */ int query_fix_cost( object player, object smithy, object item, int costing, int max, int cond, int low ) { int cost, diff, per; if ( !max ) max = item->query_max_cond(); if ( !cond ) cond = item->query_cond(); if ( !low ) low = item->query_lowest_cond(); diff = max - cond; per = 100 - smithy->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; if ( cost < 100 ) { cost = 100; } return cost; } /* query_fix_cost() */ /** @ignore yes */ mixed *query_patterns() { return ({ "<indirect:object:me>", (: cmd($1, 0) :), "cost <indirect:object:me>", (: cmd($1, 1) :) }); } /* query_patterns() */