Loot command snippet Provided by Valcados for SMAUG MUDs Step 1: We're going to make it so the type of looting permitted can be adjusted using the cset command. First, in mud.h, find the system_data structure and add the element: char loot_status; Step 2: Somewhere in mud.h, add the following: #define LOOT_STATUS_RANDOM 'R' #define LOOT_STATUS_SINGLE 'S' #define LOOT_STATUS_BOTH 'B' #define LOOT_STATUS_NONE 'N' These are the possible statuses for the loot command, and the high level admins will be able to switch which one is active using cset. LOOT_STATUS_RANDOM shall mean the players can only loot 3 random items. LOOT_STATUS_SINGLE shall mean the player can only loot 1 specified item. LOOT_STATUS_BOTH shall mean the player can choose to loot 3 random or 1 specified item. LOOT_STATUS_NONE disables the loot command altogether. Step 3: We're going to be adding the loot command, so, while still in mud.h, add the line DECLARE_DO_FUN( do_loot ); To find an appropriate place to add this, just search for (eg.) "do_languages". Step 4: If no argument is supplied, cset prints system statistics. We want to make it print the current loot status. So in act_wiz.c, look up do_cset. Find the block of code which is run on no argument- it'll have lines which look like pager_printf_color(ch, "\n\r&WSacMsg: %s", sysdata.sacmsg ); Anywhere you feel appropriate, simply add the line pager_printf_color( ch, " &wLootStatus:&W %s\n\r", sysdata.loot_status == LOOT_STATUS_RANDOM ? "Random" : sysdata.loot_status == LOOT_STATUS_SINGLE ? "Single" : sysdata.loot_status == LOOT_STATUS_BOTH ? "Both" : "None" ); Step 5: Now cset at least knows this parameter exists, but we want to be able to edjust it, not just look at it. Scroll down until you find the line if (!str_cmp(arg, "mudname")) Above that block, add the following block: if ( !str_cmp( arg, "lootstatus" ) || !str_cmp( arg, "loot_status" ) ) { if ( !str_cmp( argument, "random" ) ) sysdata.loot_status = LOOT_STATUS_RANDOM; else if ( !str_cmp( argument, "single" ) ) sysdata.loot_status = LOOT_STATUS_SINGLE; else if ( !str_cmp( argument, "both" ) ) sysdata.loot_status = LOOT_STATUS_BOTH; else if ( !str_cmp( argument, "none" ) ) sysdata.loot_status = LOOT_STATUS_NONE; else { send_to_char( "Huh? Argument can be \"Random\", \"Single\", \"Both\" or \"None\".\n\r", ch ); return; } send_to_char( "Done.\n\r", ch ); return; } You might want to edit your cset helpfile to indicate the new "lootstatus" parameter. Step 6: The MUD needs some default setting, for the first time you run it with this snippet and haven't had time to adjust it with cset. Open db.c and search for "Loading sysdata configuration...". Directly below this you should see a long set of lines where various elements of sysdata are set to default values. Simply add the line sysdata.loot_status = LOOT_STATUS_NONE; Thus by default, the loot command will be disabled. So to enable it you'll have to use cset. (Or if you like, change this line to whatever default value you like, defined above) Step 7: We want the game to actually remember our preference. So, still in db.c, search for fprintf(fp, "PetSave %d\n", sys.save_pets); This is in the function save_sysdata. Beneath this line, add the line fprintf( fp, "LootStatus %c\n", sys.loot_status ); Of course it's no good saving it if we can't load it, so next, search for KEY("Log", sys->log_level, fread_number(fp)); This is in the function fread_sysdata. Below it, add the line KEY("LootStatus", sys->loot_status, fread_letter( fp ) ); It's important that this added line fall within the "case 'L':" block. Now the MUD will save and reload your cset preference for the loot status. Of course, you'll have to do "cset save" to make it save! Step 8: Since we're adding the new loot command, we'll need to put it in tables.c. Open tables.c and search for if ( !str_cmp( name, "do_languages" )) return do_languages; This will be in the function skill_function. Below it, add the line if ( !str_cmp( name, "do_loot" )) return do_loot; Then search for if ( skill == do_languages ) return "do_languages"; This will be in the function skill_name. Below it, add if ( skill == do_loot ) return "do_loot"; Step 9: Finally, to actually put in the command itself. Pick whatever file you feel is appropriate- I'd recommend clans.c At the top of whichever file, just below the initial #include section, add the line void write_corpses args( ( CHAR_DATA *ch, char *name, OBJ_DATA *objrem ) ); This simply lets the compiler know that we'll be using the write_corpses function which is located in a different file. (exception: don't do this if you're putting the loot command in the same file which HAS the write_corpses function) Then go to the bottom of the file and add the loot code: void do_loot( CHAR_DATA *ch, char *argument ) { char arg1[MAX_INPUT_LENGTH]; OBJ_DATA *corpse = NULL, *x, *loot; sh_int count = 0, loopcount, fcount; bool fObj = FALSE, fHeavy = FALSE; char *corpse_name = NULL; if ( IS_NPC( ch ) || !CAN_PKILL( ch ) ) { set_char_color( AT_BLOOD, ch ); send_to_char( "You are no pkiller...\n\r", ch ); return; } if ( sysdata.loot_status == LOOT_STATUS_NONE ) { set_char_color( AT_BLOOD, ch ); send_to_char( "Looting is not smiled upon during these dark times...\n\r", ch ); return; } if ( ms_find_obj(ch) ) return; if ( ch->carry_number + 1 > can_carry_n( ch ) ) { set_char_color( AT_RED, ch ); send_to_char( "Your inventory is too full already...\n\r", ch ); return; } argument = one_argument( argument, arg1 ); if ( argument[0] != '\0' ) /* "Loot X Y" */ { if ( sysdata.loot_status == LOOT_STATUS_RANDOM ) { set_char_color( AT_RED, ch ); send_to_char( "You can not specify which item to loot...\n\r", ch ); return; } fObj = TRUE; corpse_name = argument; } else if ( arg1[0] == '\0' ) /* "Loot" */ { if ( sysdata.loot_status == LOOT_STATUS_SINGLE ) { set_char_color( AT_RED, ch ); send_to_char( "You must specify which item to loot.\n\r", ch ); return; } } else /* "Loot X" */ { if ( sysdata.loot_status != LOOT_STATUS_SINGLE ) for ( x = ch->in_room->last_content; x; x = x->prev_content ) { if ( !can_see_obj( ch, x ) || x->item_type != ITEM_CORPSE_PC || !xIS_SET( x->extra_flags, ITEM_CLANCORPSE ) || str_cmp( x->action_desc, ch->name ) ) continue; if ( nifty_is_name( arg1, x->name ) ) break; } else x = NULL; if ( !x ) { if ( sysdata.loot_status == LOOT_STATUS_RANDOM ) fObj = TRUE; else { set_char_color( AT_RED, ch ); send_to_char( "You can not specify which item to loot...\n\r", ch ); return; } } corpse = x; } if ( !corpse ) { OBJ_DATA *empty = NULL, *cu; sh_int f_empty = 0; count = 0; for ( cu = ch->in_room->first_content; cu; cu = cu->next_content ) { if ( !can_see_obj( ch, cu ) || cu->item_type != ITEM_CORPSE_PC || !xIS_SET( cu->extra_flags, ITEM_CLANCORPSE ) || str_cmp( cu->action_desc, ch->name ) ) continue; if ( corpse_name && !nifty_is_name( corpse_name, cu->name ) ) continue; if ( cu->first_content ) { if ( !number_range( 0, count++ ) ) corpse = cu; } else { if ( !number_range( 0, f_empty++ ) ) empty = cu; } } if ( !corpse ) { if ( !empty ) { set_char_color( AT_RED, ch ); send_to_char( "You find no suitable corpse here...\n\r", ch ); return; } corpse = empty; } } if ( !fObj ) { bool fFirst = FALSE; OBJ_DATA *list_head = NULL, *list_tail = NULL; if ( !corpse->first_content ) { xREMOVE_BIT( corpse->extra_flags, ITEM_CLANCORPSE ); set_char_color( AT_RED, ch ); ch_printf( ch, "Alas, %s is empty!\n\r", corpse->short_descr ); return; } loopcount = fcount = 0; for ( ; ; ) { if ( fcount == 3 ) break; if ( loopcount++ > 30 ) break; if ( ch->carry_weight + 1 > can_carry_w( ch ) ) break; if ( ch->carry_number + 1 > can_carry_n( ch ) ) break; count = 0; loot = NULL; for ( x = corpse->first_content; x; x = x->next_content ) { if ( !can_see_obj( ch, x ) ) continue; if ( ch->carry_weight + get_obj_weight( x ) > can_carry_w( ch ) ) { fHeavy = TRUE; continue; } if ( !count++ || !number_range( 0, count ) ) loot = x; } if ( !loot ) continue; if ( !fFirst ) { fFirst = TRUE; act( AT_RED, "$n is hastily looting $p!", ch, corpse, NULL, TO_ROOM ); set_char_color( AT_RED, ch ); ch_printf( ch, "You hastily manage to loot %s:\n\r", corpse->short_descr ); } act( AT_ACTION, "$n gets $p from $P.", ch, loot, corpse, TO_ROOM ); separate_obj( loot ); obj_from_obj( loot ); LINK( loot, list_head, list_tail, next_content, prev_content ); fcount++; } if ( fFirst ) { xREMOVE_BIT( corpse->extra_flags, ITEM_CLANCORPSE ); show_list_to_char( list_head, ch, TRUE, TRUE ); while ( ( x = list_head ) != NULL ) { UNLINK( x, list_head, list_tail, next_content, prev_content ); obj_to_char( x, ch ); } write_corpses( NULL, corpse->short_descr + 14, NULL ); return; } else if ( fHeavy ) { set_char_color( AT_RED, ch ); send_to_char( "You seem to be having some problems with weight.\n\r", ch ); return; } set_char_color( AT_RED, ch ); send_to_char( "You didn't manage to loot anything...\n\r", ch ); return; } loot = get_obj_list( ch, arg1, corpse->first_content ); if ( !loot ) { set_char_color( AT_RED, ch ); ch_printf( ch, "You can't find '%s' in %s!\n\r", arg1, corpse->short_descr ); return; } if ( ch->carry_weight + (get_obj_weight( loot )/loot->count) > can_carry_w( ch ) ) { set_char_color( AT_RED, ch ); send_to_char( "It's too heavy!\n\r", ch ); return; } separate_obj( loot ); obj_from_obj( loot ); obj_to_char( loot, ch ); xREMOVE_BIT( corpse->extra_flags, ITEM_CLANCORPSE ); set_char_color( AT_ACTION, ch ); ch_printf_color( ch, "You get %s from %s.\n\r", loot->short_descr, corpse->short_descr ); act( AT_ACTION, "$n gets $p from $P.", ch, loot, corpse, TO_ROOM ); write_corpses( NULL, corpse->short_descr + 14, NULL ); return; } That's it! Don't forget, you'll need to actually activate the command using cedit.