This code allows autostealing (ie, stealing automatically, as a "force of
habit" or whatnot, without an actual command from the player).  It should
work fine, but depending on your mud you may want to tweak the numbers that
determine the success/failure rate in steal_check.  The level difference
multiplier (in case the character is lower level than the victim) is
probably the main one to pay attention to.  It should work fine, but feel
free to tweak it to reflect your mud better.  You can also then use the
steal_check function to determine success for steals in do_steal.  It's set
so that autosteal calls to steal_check will be somewhat more successful
than do_steal calls, since the player does not get to choose his/her target
or the time he/she steals.

Some of the restrictions found in the code: it's for a PK mud using a 7 level
range.  An NPC that's 20 levels higher or lower can be robbed, but there's
at least some limit to the attempt. :)  Autosteal was written for a
DragonLance themed mud, so Kender are the ones who autosteal.  Since they're
supposed to be extremely curious and immune to fear, a mob 20 levels higher
than them or less will probably not intimidate them enough to stop them.

Use this code at your own risk.  I make no guarantees about anything. :)
Also, it should be used according to the diku/merc/ROM copywrite licenses.
If you use it, I would appreciate appropriate credit within the code (leaving
the headers to functions, etc) as well as in any help files you have to give
credit to writers of snippets.  Also, please email me to let me know that 
you're using it at the following address: amaslin@hotmail.com.  Thanks!

Any questions, comments, suggestions, or bug reports (please sent NICELY)
should also be sent to amaslin@hotmail.com.

Thale (Andrew Maslin - amaslin@hotmail.com)


-----------------------
I use several macros in here that aren't stock ROM.  For instance, macros to
determine race in the form of IS_KENDER, IS_HUMAN, etc.  If you don't have
these defined, you can define them by putting something like this in
merc.h:

#define IS_KENDER(ch)     (ch->race == race_lookup("kender"))

IS_HARPER is a macro (defined similar to IS_KENDER) for a non-PK clan.  Thus,
since you can't steal from them (or otherwise perform an offense-based
action) you can't autosteal either.  On with the installation:




***in merc.h***
search for act_obj.c, then add this in the function declarations found there:

void    autosteal       args( (CHAR_DATA *ch ) );


***in act_obj.c***
Somewhere add these functions.  If you want, you can change do_steal so that it
uses steal_check to see if the theft is successful.  Just remember to pass
a FALSE boolean value if you do.

void autosteal(CHAR_DATA *ch)
{
    CHAR_DATA *vch, *vch_next;
    OBJ_DATA *obj, *tobj, *next_tobj;
    int chance, steal_kind, chance_obj, gold, steel;
    int stolen = 0;
    char buf[MAX_STRING_LENGTH];

    if (IS_SET(ch->in_room->room_flags,ROOM_SAFE))
	return;

    for (vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room)
    {
	vch_next = vch->next_in_room;

	if (IS_IMMORTAL(vch))
	  continue;
	if (ch == vch)
	  continue;
	if (!IS_NPC(vch) && !IS_NPC(ch))
	{
	  if (((UMAX(ch->level, vch->level) - UMIN(ch->level, vch->level)) > 7)
	  ||IS_HARPER(ch) ||IS_HARPER(vch))
	    continue;
	}
	if (is_safe(ch,vch))
	  continue;
	if ((UMAX(ch->level, vch->level) - UMIN(ch->level,vch->level)) > 20)
	  continue;

	chance = number_range(1,200);
	if (!IS_AWAKE(vch))
	  chance -= 100;

	if (chance <= 30)
	{
	if (!steal_check(ch,vch,TRUE)) /* failed the steal */
	  return;
	else
	  {
	    steal_kind = number_range(1,10);
	    if (steal_kind <= 7)
	    {
	      for (tobj = vch->carrying; tobj != NULL; tobj = next_tobj)
	      {
		next_tobj = tobj->next_content;
		obj = NULL;
		stolen += 1;
		if ((chance_obj = number_percent()) < (5 + (stolen * 2)))
		  obj=tobj;
		else
		  continue;

		/* just to be safe */
		if (obj == NULL)
		  continue;

		if (!can_drop_obj(vch, obj)
    		|| IS_SET(obj->extra_flags, ITEM_INVENTORY)
		|| obj->level > (ch->level + 20))
		  continue;

		if (ch->carry_number + get_obj_number(obj) > can_carry_n(ch))
		  continue;

		if (ch->carry_weight + get_obj_weight(obj) > can_carry_w(ch))
		  continue;

		obj_from_char(obj);
		obj_to_char(obj,ch);
	        check_improve(ch,gsn_steal,TRUE,2);
	      }
	    }
	    else
	    {
	      /* GOLD/STEEL! */
	      steel = vch->steel * number_range(1, ch->level) / 110;
	      gold = vch->gold * number_range(1,ch->level) / 110;
	      if ( gold <= 0 && steel <= 0 )
		continue;
	      if (gold < 0)
		gold = 0;
	      if (steel < 0)
		steel = 0;

	      ch->gold        += gold;
	      ch->steel       += steel;
	      vch->steel   -= steel;
	      vch->gold    -= gold;

	      check_improve(ch,gsn_steal,TRUE,2);
	    }
	  }
	}
    }
  return;
}


/* A TRUE return means they manage to steal, a FALSE means unsuccessful
 * Pass a TRUE to the function only from autosteal... all others
 * should pass a FALSE value (do_steal, for instance)
 */

bool steal_check(CHAR_DATA *ch, CHAR_DATA *victim, bool is_auto)
{
    char buf  [MAX_STRING_LENGTH];
    int percent;

    if (IS_IMMORTAL(ch) && IS_IMMORTAL(victim)
	&& (ch->level < victim->level))
    {
	send_to_char("They're a little bit bigger than you are.\n\r",ch);
	return FALSE;
    }

    if (IS_IMMORTAL(ch))
	return TRUE;

    if (IS_IMMORTAL(victim))
    {
	send_to_char("I don't think that's such a good idea.\n\r",ch);
	return FALSE;
    }

    if (is_safe(ch,victim))
	return FALSE;

    percent = number_range(1,220);

    /*
     * Assuming that 17 is the "average" dex for people trying to steal.
     * Thus, a better dex yields a better success rate, and vice versa.
     * I upped it from 15 because thieves are expected to be more dextrous,
     * and 15 was just making it too easy.
     */
    percent -= 3 * (get_curr_stat(ch,STAT_DEX) - 17);

    /*
     * If the character is lower level than the victim, the level
     * difference becomes extremely important
     */
    if (ch->level < victim->level)
	percent -= 6 * (ch->level - victim->level);
    else
	percent -= (ch->level - victim->level);

    /* The dex difference between the two also makes a difference */
    percent += (get_curr_stat(victim,STAT_DEX) - get_curr_stat(ch,STAT_DEX));

    /* 
     * Race makes a difference, too.  Some races simply aren't cut out
     * to be thieves!
     */
    if IS_KENDER(ch)
	percent -= 35;
    else if (IS_SILVANESTI(ch) || IS_QUALINESTI(ch)
	  || IS_DARGONESTI(ch) || IS_DIMERNESTI(ch))
	percent -= 10;
    else if (IS_HYLAR(ch) || IS_NEIDAR(ch))
	percent += 10;
    else if (IS_MINOTAUR(ch) || IS_AGHAR(ch)
	  || IS_KAGONESTI(ch))
	percent += 25;
    if (is_auto)
	percent -= 20;
    if (!IS_AWAKE(victim))
	percent -= 20;
    else if (!can_see(victim,ch))
	percent += 45;
    else 
	percent += 80;

    if (percent >= 2)
	percent /= 2;

    if ( !IS_NPC(ch) && (percent > get_skill(ch,gsn_steal)))
        {
	/*
	 * Failure.
	 */
	send_to_char( "Oops.\n\r", ch );

	affect_strip(ch,gsn_sneak);
	REMOVE_BIT(ch->affected_by,AFF_SNEAK);

	act( "$n tried to steal from you.\n\r", ch, NULL, victim, TO_VICT    );
	act( "$n tried to steal from $N.\n\r",  ch, NULL, victim, TO_NOTVICT );
	switch(number_range(0,3))
	{
	case 0 :
	   sprintf( buf, "%s is a lousy thief!", ch->name );
	   break;
	case 1 :
	   sprintf( buf, "%s couldn't rob %s way out of a paper bag!",
		    ch->name,(ch->sex == 2) ? "her" : "his");
	   break;
	case 2 :
	    sprintf( buf,"%s tried to rob me!",ch->name );
	    break;
	case 3 :
	    sprintf(buf,"Keep your hands out of there, %s!",ch->name);
	    break;
	}
	if (!IS_AWAKE(victim))
	    do_wake(victim,"");
	if (IS_AWAKE(victim))
	    do_yell( victim, buf );
	if ( !IS_NPC(ch) )
	{
	    if ( IS_NPC(victim) )
	    {
		check_improve(ch,gsn_steal,FALSE,2);
		multi_hit( victim, ch, TYPE_UNDEFINED );
	    }
	    else
	    {
		sprintf(buf,"$N tried to steal from %s.",victim->name);
		wiznet(buf,ch,NULL,WIZ_FLAGS,0,0);
		if ( !IS_SET(ch->act, PLR_THIEF) )
		{
                  if ((ch->level >= (victim->level + 7))
                  ||  (ch->level <= (victim->level - 7)))
                    {
 		    SET_BIT(ch->act, PLR_THIEF);
		    send_to_char( "*** You are now a THIEF!! ***\n\r", ch );
		    save_char_obj( ch );
                    }
		}
	    }
	}
	return FALSE;
    }
return TRUE;
}


***in update.c***
in char_update, look for these lines:

	if ( ch->position == POS_STUNNED )
	    update_pos( ch );

Then add this after it:
        if (IS_KENDER(ch) && IS_AWAKE(ch)
	 &&!IS_IMMORTAL(ch)
	 &&(ch->level >= 11)
	 &&(ch->position != POS_FIGHTING)
	 &&(ch->position > POS_SLEEPING))
	  autosteal(ch);

