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.