/**
* @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() */