Condition and Repair system version 1.3 Changes in version 1.3: In fight.c - Moved the check for damage to weapons from the function one_hit() to damage(). In act_obj.c - In do_repair I tweaked chance a bit to make repairing eq a bit easier but capping it off at 95%. In merc.h - I fixed a bug in the ITEM_HAMMER type. The hammers should now register correctly as item_type rather than wear_type. If you used a previous version, you'll now have to reset your hammer item_type for them to be usable. Changes in version 1.2: Squashed a few bugs like blacksmith mobs being able to repair hammers. Recoded item_update(): to be more efficient and to include both inventory items and items on the ground. Added the code lines to this snippet for saving pcdata->repair to the player file. This snippet will allow you to add item conditions, item damages, and a way for both players and mobs to repair damaged items. The condition of an object will degrade with use and need to be repaired or it will break and become unusable. The repair command is used to allow players to both attempt to repair items themselves or have a mob with ACT_REPAIR flag set to do it for them. If a player tries to repair his/her own items they will need to have a repair hammer. The repair skill is used to determine how effective they are. There are 4 levels of skill: Novice, Apprentice, Journeyman, and Master. There are also 4 types of repair hammers (That you have to make yourself and adjust the VNUMS in the code accordingly) that coincide with the 4 levels of the repair skill. The higher the skill and the better the repair hammer used, the more effective the repair command is. I've tried to make this as easy as I can for anyone to use this snippet to add the code to your mud. Just follow the directions and it should be a snap. This code should have no trouble compiling on any merc or envy based mud. This snippet contains the following: Item Conditions Item Combat Damage Item Conditions that can be seen in the equipment and inventory commands and in room descriptions. Repair Commands Repair Skill ACT_REPAIR flag for mobs Mprepair skill for mobs (Not used via mob_prog but is called through the normal repair command ) Add the below code to the end of act_obj.c ##############COPY BELOW HERE#################### /* * This code is copyright 2009, Dark Hope MUD and was * written by Theodryck. You are free to use this code * and distribute it as long as the documentation remains * as-is and unaltered. */ /* * Since equipment now has a condition factor and can * become damaged or worn it only makes sense to have * a way to repair all that crap. This function allows * players to either attempt to repair their own gear * or if they are in the same room as a mob with * ACT_REPAIR set then the mob will do it. -- Theo */ void do_repair( CHAR_DATA * ch, char * argument ) { char arg[ MAX_STRING_LENGTH ]; char buf[ MAX_STRING_LENGTH ]; OBJ_DATA *obj; OBJ_DATA *hammer; CHAR_DATA *mob; int chance; int amt; int tmp; int rep; bool found = FALSE; bool no_use = FALSE; bool change = FALSE; one_argument( argument, arg ); if( arg[0] == '\0' ) { send_to_char( "What would you like to repair?\n\r", ch ); return; } /* * First let's take a look and see if we are in the same room * as a mob with ACT_REPAIR set. */ for( mob = ch->in_room->people; mob; mob = mob->next_in_room ) { if( mob->deleted ) continue; if( IS_NPC( mob ) && IS_SET( mob->act, ACT_REPAIR ) ) { found = TRUE; do_mprepair( mob, ch, argument ); break; } } /* * No blacksmith mob around? Ok, let PC try to make repairs * themselves. They must have a repair hammer equipped. * -- Theo */ if( !found ) { if( !( hammer = get_eq_char( ch, WEAR_HOLD ) ) ) { send_to_char( "You hold nothing in your hand.\n\r", ch ); return; } if( hammer->item_type != ITEM_HAMMER ) { send_to_char( "You need to be using a repair hammer or be in the same room as a blacksmith mob.\n\r", ch ); return; } if( !( obj = get_obj_carry( ch, arg ) ) ) { send_to_char( "You don't have that.\n\r" , ch ); return; } /* * Can't repair objects that are already broken. Broken objects * shouldn't be in inventory anyway since item_update in update.c * will remove them once an object gets broken. This is mainly * an error trap. * -- Theo */ if( obj->condition < 1 ) { send_to_char( "This item is broken beyond repair.\n\r", ch ); return; } if( obj->condition >= 100 ) { send_to_char( "This item doesn't need to be repaired.\n\r", ch ); return; } /* No repairing the repair hammers */ if( obj->item_type == ITEM_HAMMER ) { send_to_char( "You can't repair your repair hammer, silly.\n\r", ch ); return; } /* Make sure them repair hammer itself is usable */ if( hammer->condition < 1 ) { send_to_char( "Your repair hammer is in worse shape than what you are trying to fix.\n\r", ch ); return; } /* Parse the repair skill of the char */ rep = ch->pcdata->repair / 10; /* Make sure we're using the right type of repair hammer based on repair skill */ if( rep < 25 ) { if( hammer->pIndexData->vnum != 71 ) no_use = TRUE; } if( rep >= 25 && rep < 50 ) { if( ( hammer->pIndexData->vnum != 71 ) && ( hammer->pIndexData->vnum != 72 ) ) no_use = TRUE; } if( rep >= 50 && rep < 75 ) { if( ( hammer->pIndexData->vnum !=71 ) && ( hammer->pIndexData->vnum != 72 ) && ( hammer->pIndexData->vnum != 73 ) ) no_use = TRUE; } if( no_use ) { send_to_char( "You need more skill to use this repair hammer.\n\r", ch ); return; } /* * Ok. The player has a repair hammer. Now to attempt to make * repairs to the equipment. * * First let's take care of level 0 objects to keep from having a * floating point or divide by 0 exception, * --Theo */ if( obj->level < 1 ) { tmp = obj->level; obj->level = 1; change = TRUE; } /* Repair hammers are damamged from using them */ hammer->condition -= number_fuzzy( 3 ); /* Parse the repair skill of the char */ rep = ch->pcdata->repair / 10; /* Check to see if repair is successful */ chance = ( ( ch->pcdata->repair * 2 ) / obj->level ) * 3; if( chance >= 95 ) chance = 95; /* Nobody's perfect... */ if( ( obj->level > rep * 3 ) || ( obj->level > ch->level ) ) { send_to_char( "You aren't skilled enough to repair such an item yet.\n\r", ch ); return; } /* Now to make the repair attempt */ if( chance >= number_percent( ) ) { if( hammer->pIndexData->vnum == 71 ) amt = number_range( 1, 3 ); else if( hammer->pIndexData->vnum == 72 ) amt = number_range( 2, 5 ); else if( hammer->pIndexData->vnum == 73 ) amt = number_range( 3, 6 ); else amt = number_range( 4, 8 ); } else { sprintf( buf, "You are unable to make repairs to %s.\n\r", obj->short_descr ); send_to_char( buf, ch ); return; } /* Success! Ok, lets add a little to the condition of the item. */ if( obj->condition < 100 ) { obj->condition += amt; if( obj->condition > 100 ) /* Can only repair to 100% */ obj->condition = 100; } sprintf( buf, "You successfully make repairs to %s.\n\r", obj->short_descr ); send_to_char( buf, ch ); /* * A chance to add a little to the repair skill for each successful attempt. * The amount is based on ch->level vs obj->level so repairing a higher * level object yields a bigger result. */ chance = 50; if( chance >= number_range( 1, 100 ) ) { int bonus = obj->level / ch->level + number_fuzzy( 1 ); ch->pcdata->repair += number_fuzzy ( 2 ) + bonus; } /*In case of 0 level object, return back to level 0 */ if( change ) obj->level = tmp; return; /* all done with PC repairs */ } /* found statement */ return; } ##########END ACT_OBJ.C############### Add the following to mob_comm.c ##########COPY BELOW HERE############ /* * The following code allows mobs to repair damaged equipment * for a fee that is based on the level and condition of the * item being repaired. This is done without the player having * to actually give the mob his/her equipment to be repaired. * --Theo */ void do_mprepair( CHAR_DATA * ch, CHAR_DATA * victim, char * argument ) { char buf[ MAX_STRING_LENGTH ]; char arg[ MAX_STRING_LENGTH ]; OBJ_DATA * obj; OBJ_DATA * obj_next; int cost = 0; int total = 0; int num = 0; if( !IS_NPC( ch ) ) { send_to_char( "Huh?\n\r", ch ); return; } if( !can_see( ch, victim ) ) { do_say( ch, "I don't trade with folks I can't see.\n\r" ); return; } one_argument( argument, arg ); if( !str_cmp( arg, "all" ) ) /* Do we need everything repaired? */ { /* * This FOR loop reads in the player's items and looks * for those that need to be repaired, then repairs them. */ for( obj = victim->carrying; obj ; obj = obj_next ) { obj_next = obj->next_content; if( obj->deleted ) continue; if( obj->wear_loc != WEAR_NONE || obj->condition >= 95 ) continue; cost = ( ( 100 - obj->condition ) + obj->level ) * 3; if( cost > victim->gold ) { sprintf( buf, "It costs %d to repair %s. You don't have enough gold.", cost, obj->short_descr ); do_say( ch, buf ); break; } obj->condition = 95; /* Only repair items to 95% */ victim->gold -= cost; sprintf( buf, "The cost of repairing %s is %d gold.\n\r", obj->short_descr, cost ); send_to_char( buf, victim ); total += cost; num += 1; } /* for */ if( num != 0 ) { sprintf( buf, "%s skillfully repairs your damaged items.\n\r", ch->short_descr ); send_to_char( buf, victim ); sprintf( buf, "You pay a total of %d gold for the repair of %d items", total, num ); do_say( ch, buf ); return; } else { do_say( ch, "You don't need to have anything repaired." ); return; } } /* if */ if( !( obj = get_obj_carry( victim, arg ) ) ) { do_say( ch, "I can't repair what you don't have." ); return; } if( obj->condition >= 95 ) /* Only repair items that are at less than 95% */ { sprintf( buf, "%s doesn't need to be repaired.", obj->short_descr ); do_say( ch, buf ); return; } cost = ( ( 100 - obj->condition ) + obj->level ) * 3; if( cost > victim->gold ) { sprintf( buf, "It costs %d to repair %s. You don't have enough gold.", cost, obj->short_descr ); do_say( ch, buf ); return; } obj->condition = 95; /* Again, only allowing mobs to repair items to 95% */ victim->gold -= cost; sprintf( buf, "%s takes %s and skillfully repairs it back to full working order.\n\r", ch->short_descr, obj->short_descr ); send_to_char( buf, victim ); sprintf( buf, "The cost of the repair is %d gold.\n\r", cost ); send_to_char( buf, victim ); return; } ###########END MOB_COMM.C############# Add the following code to format_obj_to_char in act_info.c ###########COPY BELOW HERE############ if( obj->condition > 1 && obj->condition < 16 ) strcat( buf, "{o{w[Unusable]{x " ); else if( obj->condition >= 16 && obj->condition < 26 ) strcat( buf, "{o{w[Awful]{x " ); else if( obj->condition >= 26 && obj->condition < 51 ) strcat( buf, "{x{w[Bad]{x " ); else if( obj->condition >= 51 && obj->condition < 76 ) strcat( buf, "{o{w[Fair]{x " ); else if( obj->condition >= 76 && obj->condition < 86 ) strcat( buf, "{o{w[Good]{x " ); else if( obj->condition >= 86 && obj->condition < 96 ) strcat( buf, "{o{w[Excellent]{x " ); else if( obj->condition >= 96 ) strcat( buf, "{o{w[Perfect{x " ); else strcat( buf, "{o{w[{bBroken{w]{x " ); ###########END ACT_INFO.C################ Add this to the create_object function in db.c ( Before the switch statement ) obj->condition = 95; Add the following to function one_hit in fight.c to alter the damage based on a weapon's condition ##########COPY BELOW HERE############### /* * Adjust weapon damage based on the condition * of them item. -- Theo */ if( wield ) { num2 = wield->condition * .01; val1 = wield->value[1] * num2; val2 = wield->value[2] * num2; } #############END COPY#################### Further down in the function damage we'll add the following code just after the line victim->hit -= dam; ##############COPY BELOW HERE############### /* * A chance that some random piece of armor is damaged * during the attack. I put the check for damage outside * the FOR loop to insure that all items have an equal * chance of getting damamged. * --Theo */ if( !IS_NPC( victim ) ) { /* Let's read the victim's eq */ for( wear = 0; wear < MAX_WEAR; wear++ ) { if( !( obj = get_eq_char( victim, wear ) ) ) continue; } while( !found ) { /* Now to pick a random obj */ num = number_range( 0, wear ); if( !( obj = get_eq_char( victim, num ) ) ) continue; /* Found one. Now a chance to damage it a bit */ if( obj->item_type == ITEM_ARMOR ) { if( number_percent( ) > 80 ) obj->condition -= number_fuzzy(2); found = TRUE; } } } /* * Check to see if we've damaged our weapon. * -- Theo */ if( wield && !IS_NPC( ch ) && dam > 0 ) { base = 80; chance = number_range( 1, 100 ); if( IS_SET( wield->extra_flags, ITEM_BLESS ) ) base += 10; if( IS_SET( wield->extra_flags, ITEM_ARTIFACT ) ) base += 15; if( chance > base ) wield->condition -= number_fuzzy( 2 ); } /* end weapon damage */ ##################END COPY##################### ##################END FIGHT.C################## Now let's move on to magic.c where we'll add the following lines to spell_identify In the declarations of the function add this char word[ MAX_STRING_LENGTH]; Then copy and and the following to right before you see if( obj->item_type == ITEM_ARMOR ) ###############COPY BELOW HERE############### if( obj->condition >= 0 && obj->condition < 15 ) word = str_dup( "{o{d[{rUnusable{d]{x" ); else if( obj->condition >= 15 && obj->condition < 26 ) word = str_dup( "{d[{yAwful{d]{x" ); else if( obj->condition >= 25 && obj->condition < 51 ) word = str_dup( "{d[{yBad{d]" ); else if( obj->condition >= 51 && obj->condition < 76 ) word = str_dup( "{d[{yFair{d]" ); else if( obj->condition >= 76 && obj->condition < 86 ) word = str_dup( "{d[{yGood{d]{x" ); else if( obj->condition >= 86 && obj->condition < 96 ) word = str_dup( "{d[{yExcellent{d]{x" ); else if( obj->condition >=96 && obj->condition < 101 ) word = str_dup( "{d[{yPerfect{d]{x" ); else word = str_dup( "{d[{bBroken{d]{x" ); sprintf( buf, "{o{dCondition: {y%d%% %s{x\n\r", obj->condition, word ); send_to_char( buf, ch ); #################END COPY#################### You'll want to format it up to match your Mud. #################END MAGIC.C################# Now we go to save.c and add the next few lines of code to the function fwrite_obj. You'll want to add this just before you see then line with - fprintf( fp. "Value" , fprintf( fp, "Condition %d\n", obj->condition ); In both fread_obj and new_fread_obj in the same spot in both functions; just after you see - { "Cost", FALSE, Add this: { "Condition", FALSE, DEFLT, { &obj.condition, NULL } }, You'll also need to add the pcdata->repair value. In function fwrite_char add this to the - fprintf( fp, "Repair %d\n", ch->pcdata->repair ); A little further down in fread_char you'll need to add the following to the key_tab struct - { "Repair", FALSE, DEFLT, { &ch->pcdata->repair,NULL } }, Further down in both functions you'll also want to add the following code as an error check. Look for this - new_obj->pIndexData->count++; and place this just after it: if( new_obj->condition == 0 ) new_obj->condition = 95; #################END SAVE.C##################### Now on to interp.c to add the following line of code to the command table - { "repair" , do_repair, POS_RESTING , 0, LOG_NORMAL, 1 }, The command 'mprepair' doesn't need to be added since it's only called via the do_repair function. In update.c we'll need to add the following to make sure broken weapons get removed from a player's inventory - In the function update_handler look for the call to obj_update() and right below it add a call to item_update, like so - item_update( ); ##################COPY BELOW HERE################ /* * The following is code the updates the condition * on an object to see if the object has broken and * become unusable. This function is called during * update_handler and can cause considerable * drain on CPU time especially if there are a lot * of players on the MUD and if there is a lot of combat * going on. * -- Theo */ void item_update( void ) { OBJ_DATA *obj; OBJ_DATA *obj_next; for ( obj = object_list; obj; obj = obj_next ) { obj_next = obj->next; if ( obj->deleted ) continue; /* Check to see if an item breaks during use -- Theo */ if( obj->condition < 1 ) { if( obj->carried_by ) /* Is it carried by a character? */ { act( "$p has {o{W{bBROKEN{x! It falls to pieces before your eyes!", obj->carried_by, obj, NULL, TO_CHAR ); unequip_char( obj->carried_by , obj ); extract_obj( obj ); } else /* If not, just eat it */ { act( "$p has {o{W{bBROKEN{x! It crumbles into a million tiny pieces!", obj->short_descr, obj, NULL, TO_ROOM ); extract_obj( obj ); } } } return; } ###############END UPDATE.C#################### In bit.c we'll need to add the new object type - ITEM_HAMMER to the array flag_type type_flags { "hammer", ITEM_HAMMER, TRUE }, In db.c we'll have to do add this line to the switch ( obj->item_type ) in the function create_object. case ITEM_HAMMER: ################DECLARATIONS IN MERC.H######### Now on to merc.h to make all our declarations. We'll need to add a definition for the new item type #define ITEM_HAMMER 36 Adjust the number to suit your MUD. Find the ACT bits used to #Mobiles section and add this to it - #define ACT_REPAIR BV12 /* Blacksmith mobs -- Theo */ In the DECLARE_DO_FUN section add this: DECLARE_DO_FUN( do_repair ); /* Theodryck */ At the end of the struct defintion for pcdata add this- int repair; Further down in the global declarations part of merc.h we'll add our function declarations - /* mob_comm.c */ void do_mprepair args( ( CHAR_DATA * ch, CHAR_DATA * victim, char * argument ) ); And that should get you set up and going with a new item conditions and repair system. Let me know how you like it by emailing me: white-n-creamy@hotmail.com Let me know if this snippet was easy to use. And if you make changes or additions please share them.