tmw/
tmw/data/
tmw/help/
tmw/player/
tmw/player/f/
tmw/player/i/
tmw/player/o/
tmw/player/q/
tmw/player/u/
tmw/player/y/
/* FuBaR 1.3.1X */
/* This code uses some hacked functins, mainly the original */
/* diku/merc/envy fight functions, but comes together to    */
/* create some very nice and very  unique code.             */
/* therefore, i give my thanks to the creators of merc and  */
/* envy, but my biggest thanks goes to the creators of diku */
/* without whom mudding would not be as popular as it is    */
/* today. thank you. Big thanks to project co-head Eleven  */
/************************************************************/

#define unix 1
#if defined( macintosh )
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"


void    death_xp_loss        args( ( CHAR_DATA *victim ) );
void    group_gain           args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
bool    check_dodge          args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
void    check_killer         args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
void    dam_message          args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dam,
                                    int dt ) );
void    set_shooting         args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
void    stop_shooting	args(( CHAR_DATA *ch, bool fBoth ));
void    item_damage             args( ( CHAR_DATA *ch, int dam ) );
void ranged_damage args(( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt ));
void    ranged_multi    args(( CHAR_DATA *ch, CHAR_DATA *victim, int dt ));
bool    target_available args(( CHAR_DATA *ch, CHAR_DATA *fch ));
int    per_type args((CHAR_DATA *ch, OBJ_DATA *Obj));
CHAR_DATA * crossfire_check args(( CHAR_DATA *ch, CHAR_DATA *fch )); 
void   ranged_hit args((CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *gun ));
OBJ_DATA * parmor_check args ( ( CHAR_DATA *ch ) );
int   count_inv_obj args( ( CHAR_DATA *ch, OBJ_DATA *obj ) );
/*
  *
  * control those freaks fighting long range. :)
  *
 */
void update_ranged( void )
{
    CHAR_DATA *ch;
    CHAR_DATA *victim;
    int stun;

    for ( ch = char_list; ch; ch = ch->next )
    {
        if ( ch->deleted )
            continue;

        for (stun = 0; stun < STUN_MAX; stun++)
        {
          if ( IS_STUNNED( ch, stun ) )
            ch->stunned[stun]--;
        }


        if ( ( victim = ch->engaged ) )
        {
            if ( IS_AWAKE( ch )){
/*		send_to_char( AT_WHITE, "message 1\n\r", ch); */
                ranged_multi( ch, victim, TYPE_UNDEFINED ); }
            else {
/*		send_to_char( C_DEFAULT, "Stop_shooting 1\n\r", ch ); */
                stop_shooting( ch, FALSE ); }
            continue;
        }

        if ( IS_AFFECTED( ch, AFF_BLIND )
            || ( IS_NPC( ch ) && ch->pIndexData->pShop ) )
            continue;
    }             
    return;
} 

void ranged_multi( CHAR_DATA *ch, CHAR_DATA *victim, int dt )
{

    OBJ_DATA *gun = NULL;
    int shot;
    int numshot;
    OBJ_DATA *obj;
    bool gunfound = FALSE;
    ch->engaged = victim;
/*	send_to_char( C_DEFAULT, "ranged_multi.\n\r", ch );  booger */

    if ( IS_NPC( ch ) )
    {
      mprog_hitprcnt_trigger( ch, victim );
      mprog_fight_trigger( ch, victim );
    } 


    if ( ch->position <= POS_STUNNED )
    {
     send_to_char(AT_WHITE,
	"You are stunned, but will probably recover.\n\r", ch );
     act(AT_WHITE, "$n is stunned, but will probably recover.",
	    ch, NULL, NULL, TO_ROOM );
     return;
    }

    if ( ( IS_AFFECTED2( ch, AFF_CONFUSED ) )
       && number_percent ( ) < 40 )
    {
      act(AT_YELLOW, "$n looks around confused at what's going on.", ch, NULL, NULL, TO_ROOM );
      send_to_char( AT_YELLOW, "You stand confused.\n\r", ch );
      return;
    }
    
	/* send_to_char( C_DEFAULT, "Stun/confused check.\n\r", ch );  booger */
/* couldn't put ammo here to speed up ranged_hit because it would not
identify ammo each time it would hit. thus when character is out of ammo
it would not having the repetitive click type affect. */
/*   ooooooooooh, new update, you only have to wear a gun to shoot it now,
     and oh man, each gun you have equipped shoots! mounted too */


     for ( obj = ch->carrying; obj; obj = obj->next_content )
        {
        if ( obj->deleted )
            continue;
/*	send_to_char( C_DEFAULT, "Looping through objs.\n\r", ch );  booger */
        if ( obj->item_type == ITEM_RANGED_WEAPON )
            {
            gun = obj;
            }
/*	send_to_char( C_DEFAULT, "Found a gun.\n\r", ch );  booger */
		if ( obj->wear_loc == WEAR_NONE ) 
		{ 
/*	send_to_char( C_DEFAULT, "Not equipped.\n\r", ch );  booger */
			continue;
        }
		else
		{
/*	send_to_char( C_DEFAULT, "Shooting.\n\r", ch );  booger */
			gunfound = TRUE;
            if ( gun && gun->value[4] < 2 )
            ranged_hit( ch, victim, gun );

            numshot = gun->value[4];

           if ( gun && gun->value[4] > 1 )
              for ( shot = 0; shot < numshot; shot++ )
                      ranged_hit( ch, victim, gun );
		}

        }

     for ( obj = ch->carrying; obj; obj = obj->next_content )
        {
        if ( obj->deleted )
            continue;
/*	send_to_char( C_DEFAULT, "Looking for mounted weapons.\n\r", ch );  booger */
 
                if ( IS_SET(obj->extra_flags, ITEM_LOADED ))
				{
/*	send_to_char( C_DEFAULT, "Shooting.\n\r", ch );  booger */
					gunfound = TRUE;
					gun = obj;
			if ( gun && gun->value[4] < 2 )
            ranged_hit( ch, victim, gun ); 

            numshot = gun->value[4];

           if ( gun && gun->value[4] > 1 )
              for ( shot = 0; shot < numshot; shot++ )
                      ranged_hit( ch, victim, gun );
				}
        }

	   if (!gunfound)
       {
        send_to_char(AT_BLUE, "You do not have a ranged weapon equipped.\n\r", ch);
        return;
	   }
/*	send_to_char( C_DEFAULT, "end ranged_multi.\n\r", ch );  booger */
    return;
}

void do_engage( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA 		*victim;
    OBJ_DATA 		*ammo;
    OBJ_DATA 		*gun = NULL;
    OBJ_DATA 		*clip = NULL;
    OBJ_DATA		*obj;
    ROOM_INDEX_DATA 	*to_room;
    ROOM_INDEX_DATA 	*in_room;
    EXIT_DATA 		*pexit;
    char       		arg1[ MAX_INPUT_LENGTH ];
    char       		arg2[ MAX_INPUT_LENGTH ];
    int 		MAX_DIST = 0;
    int  		dir;
    bool 		ammocheck = FALSE;
    bool		gunfound = FALSE;

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );

/*	send_to_char( C_DEFAULT, "Starting engage engine.\n\r", ch ); booger */
  if ( ch->engaged != NULL )
     {
	send_to_char( C_DEFAULT, "You are already shooting at someone.\n\r", ch );
	return;
     }

     for ( obj = ch->carrying; obj; obj = obj->next_content )
        {
	if ( obj->deleted )
	    continue;


	if ( obj->item_type == ITEM_RANGED_WEAPON )
	    {
	    gun = obj;
	    }

    if (  obj->wear_loc == WEAR_NONE )
	    continue;
     else
	    gunfound = TRUE;	 
	 }

    if (!gunfound)
     {
     for ( obj = ch->carrying; obj; obj = obj->next_content )
        {
        if ( obj->deleted )
            continue;

	if ( IS_SET(obj->extra_flags, ITEM_LOADED))
	{
	gun = obj;
	gunfound = TRUE;
	}
	}
     }

        if (!gunfound)
          {
	send_to_char(AT_BLUE, "You do not have a ranged weapon equipped.\n\r", ch );
         return;
		}
/*	send_to_char( C_DEFAULT, "Gun check.\n\r", ch ); booger*/
/*        
if ( gun->value[2] == 0 )
ammocheck = TRUE;

if (gun->value[2] > 0)
{ */
    for ( ammo = gun->contains; ammo; ammo = ammo->next_content )
    {
     if ( !ammo || ammo->deleted )
      continue;

     if ( ammo->item_type != ITEM_BULLET && ammo->item_type != ITEM_CLIP )
      continue;

     if ( ammo->item_type == ITEM_BULLET )
     {
      ammocheck = TRUE;
      break;
     }

     if ( ammo->item_type == ITEM_CLIP )
     {
      clip = ammo;

      if ( !clip->contains )
       continue;

      for ( ammo = clip->contains; ammo; ammo = ammo->next_content )
      {
       if ( !ammo )
        continue;
  
       if ( ammo->item_type == ITEM_BULLET )
       {
        ammocheck = TRUE;
        break;
       }
      }
      if ( ammocheck == TRUE )
       break;
     }
    } /*
} */

     if ( !ammocheck || ammo->item_type == ITEM_CLIP )
     {
      send_to_char( AT_WHITE, "You are out of ammo.\n\r", ch );
      return;
     }
/*	send_to_char( C_DEFAULT, "Ammo check.\n\r", ch );  booger */
    in_room = ch->in_room;
    to_room = ch->in_room;
    MAX_DIST = gun->value[1];

    if ( arg1[0] == '\0' )
    {
      send_to_char( C_DEFAULT, "Shoot at whom?\n\r", ch );
      return;
    }

    if ( arg2[0] == '\0' )
    {
      if ( ( victim = get_char_room( ch, arg1 ) ) == NULL )
      {
	send_to_char( C_DEFAULT, "They aren't here.\n\r", ch );
	return;
      }
    }
    else
    {
      for ( dir = 0; dir < 6; dir++ )
       if ( arg2[0] == dir_name[dir][0]
           && !str_prefix( arg2, dir_name[dir] ) )
	  break;

      ch->rangedir = dir;

      if ( dir == 6 )
      {
	send_to_char( C_DEFAULT, "Shoot in which direction?\n\r", ch );
	return;
      }

      if ( ( pexit = to_room->exit[dir] ) == NULL ||
	   ( to_room = pexit->to_room ) == NULL ||
	   IS_SET( pexit->exit_info, EX_ISWALL ))

      {
	send_to_char( C_DEFAULT, "You cannot shoot in that direction.\n\r", ch );
	return;
      }

      if ( IS_SET( pexit->exit_info, EX_CLOSED ) )
      {
	send_to_char( C_DEFAULT, "You cannot shoot through a door.\n\r", ch );
	return;
      }
/* sigh flux changed this code up to be slightly cracked
   this comment is causing the searches for mobs to miss
   occasionally, actually, a lot.... working on something
   more dynamic */
      if ( !( victim = get_char_world( ch, arg1 ) ) ||
		victim->in_vehicle != NULL)
      {
	send_to_char( C_DEFAULT, "They aren't anywhere.\n\r", ch );
	return;
      }

    if ( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim )
    {
        act(AT_BLUE, "$N is your beloved master!", ch, NULL, victim, TO_CHAR );
        return;
    }
/*	send_to_char( C_DEFAULT, "Syntax check.\n\r", ch );  booger */
   set_shooting( ch, victim );
   ranged_multi( ch, victim, TYPE_UNDEFINED );
  }
/*	send_to_char( C_DEFAULT, "end engage.\n\r", ch );  booger */
 return;
}

void ranged_hit( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *gun )
{
    int          dir, aim, number;
    OBJ_DATA *ammo;
    OBJ_DATA *shell;
    OBJ_DATA *clip = NULL;
    ROOM_INDEX_DATA *to_room;
    ROOM_INDEX_DATA *in_room;
    EXIT_DATA *pexit;
    int dam = 0;
    int dist = 0;
    int MAX_DIST = 0;
    char buf[MAX_STRING_LENGTH];
    extern char *dir_noun []; 
    bool ammocheck = FALSE;    
    CHAR_DATA *xfirevict;
/*
if (gun->value[2] == 0)
ammocheck = TRUE;
if (gun->value[2] > 0)
{*/
/*		send_to_char( C_DEFAULT, "ranged_hit.\n\r", ch );  booger */
    for ( ammo = gun->contains; ammo; ammo = ammo->next_content )
    {
     if ( !ammo )
      continue;

     if ( ammo->item_type != ITEM_BULLET && ammo->item_type != ITEM_CLIP )
      continue;

     if ( ammo->item_type == ITEM_BULLET )
     {
	ammocheck = TRUE;
      break;
     }

     if ( ammo->item_type == ITEM_CLIP )
     {
      clip = ammo;

      if ( !clip->contains )
       continue;

      for ( ammo = clip->contains; ammo; ammo = ammo->next_content )
      {
       if ( ammo->item_type == ITEM_BULLET )
       {
        ammocheck = TRUE;
        break;
       }
      }
      if ( ammocheck == TRUE )
       break;
     }
    }/*
} */
     if ( !ammocheck || ammo->item_type == ITEM_CLIP )
     {
      act( AT_RED,
       "You move to fire your $p, but find that it's out of ammo!",
        ch, gun, NULL, TO_CHAR );
      act( AT_YELLOW,
       "$n's $p makes a clicking noise.", ch, gun, NULL, TO_ROOM );
      stop_shooting( ch, FALSE );
      return;
     }
/*	send_to_char( C_DEFAULT, "ammo check.\n\r", ch );  booger */
/*
if (gun->value[2] > 0)
*/
     dam = number_range(ammo->value[2], ammo->weight + (ammo->value[2] * 2));
/*
else
     dam = number_range( (200 + gun->level), (1000 + gun->level));
*/
     if ( dam > 1000 && !IS_IMMORTAL(ch) )
     {
      sprintf( buf, "ranged_hit dam range > 1000 from %d to %d",
       ammo->value[2], ammo->weight + (ammo->value[2] * 2) );
      bug( buf, 0 );
      if ( ammo->name )
       bug( ammo->name, 0 );
     }
/*	send_to_char( C_DEFAULT, "Damage calculated.\n\r", ch );  booger */

     in_room = ch->in_room;
     to_room = ch->in_room;
     dir = ch->rangedir;

      if ( ( pexit = to_room->exit[dir] ) == NULL ||
	   ( to_room = pexit->to_room ) == NULL )
      {
	send_to_char( C_DEFAULT, "You cannot shoot in that direction.\n\r", ch );
       stop_shooting( ch, FALSE );
	return;
      }

      if ( IS_SET( pexit->exit_info, EX_CLOSED ) )
      {
	send_to_char( C_DEFAULT, "You cannot shoot through a door.\n\r", ch );
       stop_shooting( ch, FALSE );
	return;
      }
/*	send_to_char( C_DEFAULT, "Shooting in a valid direction.\n\r", ch );  booger */
/*
if (gun->value[2] > 0)
{
*/
      shell = create_object( get_obj_index(OBJ_VNUM_BULLET_SHELL), 0 );
      shell->timer = number_range( 5, 10 );
      obj_to_room( shell, ch->in_room );
/*
}
*/
      MAX_DIST = gun->value[1];
      for ( dist = 1; dist <= MAX_DIST; dist++ )
      {
/*	send_to_char( C_DEFAULT, "Searching rooms.\n\r", ch );  booger */
	char_from_room( ch );
	char_to_room( ch, to_room );


	if ( target_available( ch, victim ) )
	  break;

	if ( ( pexit = to_room->exit[dir] ) == NULL ||
	     ( to_room = pexit->to_room ) == NULL ||
	       IS_SET( pexit->exit_info, EX_CLOSED )||
	       IS_SET( pexit->exit_info, EX_ISWALL ))
	{
/*
if (gun->value[2] > 0)
{
*/
	  sprintf( buf, "A $p flys in from $T and hits the %s wall.", 
		   dir_name[dir] );
	  act( AT_WHITE, buf, ch, ammo, dir_noun[rev_dir[dir]], TO_ROOM );
	  sprintf( buf, "You shoot your $p %d room%s $T, where it hits a wall.",
		   dist, dist > 1 ? "s" : "" );

	  act( AT_WHITE, buf, ch, ammo, dir_name[dir], TO_CHAR );
	  char_from_room( ch );
	  char_to_room( ch, in_room );
          oprog_throw_trigger( ammo, ch );
          obj_from_obj( ammo );
          extract_obj( ammo );
/*
}
else
{
          sprintf( buf, "An enrgy blast flys in from $T and hits the %s wall.",
                   dir_name[dir] );
          act( AT_WHITE, buf, ch, NULL, dir_noun[rev_dir[dir]], TO_ROOM );
          sprintf( buf, "You shoot your $p %d room%s $T, where it hits a wall.",
                   dist, dist > 1 ? "s" : "" );
          act( AT_WHITE, buf, ch, gun, dir_name[dir], TO_CHAR );
          char_from_room( ch );
          char_to_room( ch, in_room );
}
*/
          stop_shooting( ch, FALSE );
	  return;
	}
      }

      if ( !target_available( ch, victim ) )
      {
/*
if (gun->value[2] > 0)
{
*/
	act( AT_WHITE, 
	    "A $p flies in from $T and falls harmlessly to the ground.",
	    ch, ammo, dir_noun[rev_dir[dir]], TO_ROOM );
	sprintf( buf,
	"Your $p falls harmlessly to the ground %d room%s $T of here.",
		dist, dist > 1 ? "s" : "" );
	act( AT_WHITE, buf, ch, ammo, dir_name[dir], TO_CHAR );
	char_from_room( ch );
	char_to_room( ch, in_room );
	oprog_throw_trigger( ammo, ch );
         obj_from_obj( ammo );
          extract_obj( ammo );
/*
}
else
{
        act( AT_WHITE,
            "A energy blast flies in from $T and falls harmlessly to the ground.",
            ch, ammo, dir_noun[rev_dir[dir]], TO_ROOM );
        sprintf( buf,
        "Your blast fizzles out harmlessly%d room%s $T of here.",
                dist, dist > 1 ? "s" : "" );
        act( AT_WHITE, buf, ch, NULL, dir_name[dir], TO_CHAR );
        char_from_room( ch );
        char_to_room( ch, in_room );
}
*/
        stop_shooting( ch, FALSE );
	return;
      }
     if (dist > 0 && (xfirevict = crossfire_check(ch, victim)) != NULL)
     {
/*
if (gun->value[2] > 0)
{
*/
      char_from_room( ch );
      char_to_room( ch, in_room );
      act( AT_WHITE, "A $p flys in from $T and hits $n!", xfirevict, ammo,
          dir_noun[rev_dir[dir]], TO_NOTVICT );
      act( AT_WHITE, "A $p flys in from $T and hits you!", xfirevict, ammo,
          dir_noun[rev_dir[dir]], TO_CHAR );
      sprintf( buf, "Your $p flew %d rooms %s and hit $N!", dist,
              dir_name[dir] );
      act( AT_WHITE, buf, ch, ammo, xfirevict, TO_CHAR );
      oprog_throw_trigger( ammo, ch );
      obj_from_obj( ammo );
      extract_obj( ammo );
      ranged_damage( ch, xfirevict, dam, gsn_bullet_shot );
/*
}
else
{      char_from_room( ch );
      char_to_room( ch, in_room );
      act( AT_WHITE, "An energy blast flys in from $T and hits $n!", xfirevict, NULL,
          dir_noun[rev_dir[dir]], TO_NOTVICT );
      act( AT_WHITE, "An energy blast flys in from $T and hits you!", xfirevict,
NULL,
          dir_noun[rev_dir[dir]], TO_CHAR );
      sprintf( buf, "Your energy blast flew %d rooms %s and hit $N!", dist,
              dir_name[dir] );
      act( AT_WHITE, buf, ch, NULL, xfirevict, TO_CHAR );
      ranged_damage( ch, xfirevict, dam, gsn_energy_shot );
}
*/
      if ( IS_NPC( xfirevict ) )
      {
         if ( xfirevict->level > 3 )
             xfirevict->hunting = ch;
      }
      return;
     }
/*	send_to_char( C_DEFAULT, "crossfire check.\n\r", ch );  booger */
    aim = (get_curr_dex( ch ) * 3);
    number = number_percent();


     if ( dist > 0 )
     {
/*
if (gun->value[2] > 0)
{
*/
/*	send_to_char( C_DEFAULT, "about to hit target...\n\r", ch );  booger */

      char_from_room( ch );
      char_to_room( ch, in_room );
      act( AT_WHITE, "A $p flys in from $T and hits $n!", victim, ammo,
	  dir_noun[rev_dir[dir]], TO_NOTVICT );
      act( AT_WHITE, "A $p flys in from $T and hits you!", victim, ammo,
	  dir_noun[rev_dir[dir]], TO_CHAR );
      sprintf( buf, "Your $p flew %d rooms %s and hit $N!", dist,
	      dir_name[dir] );
      act( AT_WHITE, buf, ch, ammo, victim, TO_CHAR );
      oprog_throw_trigger( ammo, ch );
      obj_from_obj( ammo );
      extract_obj( ammo );
      ranged_damage( ch, victim, dam, gsn_bullet_shot );
/*	send_to_char( C_DEFAULT, "target has been smacked.\n\r", ch );  booger */
/*
}
else
{      char_from_room( ch );
      char_to_room( ch, in_room );
      act( AT_WHITE, "An energy blast flys in from $T and hits $n!",
xfirevict, NULL,
          dir_noun[rev_dir[dir]], TO_NOTVICT );
      act( AT_WHITE, "An energy blast flys in from $T and hits you!",
xfirevict,
NULL,
          dir_noun[rev_dir[dir]], TO_CHAR );
      sprintf( buf, "Your energy blast flew %d rooms %s and hit $N!",
dist,
              dir_name[dir] );
      act( AT_WHITE, buf, ch, NULL, xfirevict, TO_CHAR );
      ranged_damage( ch, xfirevict, dam, gsn_energy_shot );
} 
*/
      if ( IS_NPC( victim ) )
      {
         if ( victim->level > 3 )
             victim->hunting = ch;
      }  
      return;
	}
   
/*
if (gun->value[2] > 0)
{
*/
  obj_from_obj( ammo );
  act( AT_WHITE, "$n shoots a $p at $N!", ch, ammo, victim, TO_ROOM );
  act( AT_WHITE, "You shoot your $p at $N.", ch, ammo, victim, TO_CHAR );
  oprog_throw_trigger( ammo, ch );
  ranged_damage( ch, victim, dam, gsn_bullet_shot );
  extract_obj( ammo );
/*
}
else
{
  act( AT_WHITE, "$n shoots a $p at $N!", ch, gun, victim, TO_ROOM );
  act( AT_WHITE, "You shoot your $p at $N.", ch, gun, victim, TO_CHAR );
  ranged_damage( ch, victim, dam, gsn_energy_shot );
}
*/
/*	send_to_char( C_DEFAULT, "end ranged_hit.\n\r", ch );  booger */
  tail_chain( );
 return;
}

void ranged_damage( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt )
{
    OBJ_DATA *parmor;
/*	send_to_char( C_DEFAULT, "ranged_damage.\n\r", ch );  booger */
    if ( victim->position == POS_DEAD )
        return;

    /*
     * Stop up any residual loopholes.
     */

    if ( victim != ch )
    {
        /*
         * Certain attacks are forbidden.
         * Most other attacks are returned.
         */
/*        if ( is_safe( ch, victim ) )
            return; 
        check_killer( ch, victim ); 
        send_to_char( AT_WHITE, "setting shooting\n\r", ch);
        set_shooting( ch, victim ); */

        /*
         * More charm stuff.
         */
        if ( victim->master == ch )
            stop_follower( victim );

        /*
         * Inviso attacks ... not.
        */
        if ( IS_AFFECTED( ch, AFF_INVISIBLE ) )
        {
            affect_strip( ch, gsn_invis      );
            affect_strip( ch, gsn_mass_invis );
            REMOVE_BIT( ch->affected_by, AFF_INVISIBLE );
            act(AT_GREY, "$n fades into existence.", ch, NULL, NULL,
TO_ROOM );
        }
        if (IS_AFFECTED2( ch, AFF_PHASED ) )
        {
            affect_strip ( ch, skill_lookup("phase shift") );
            affect_strip ( ch, skill_lookup("mist form") );
            REMOVE_BIT( ch->affected_by2, AFF_PHASED );
            act(AT_GREY, "$n returns from an alternate plane.", ch, NULL,
NULL, TO_ROOM );
        }
 
    if ((parmor = parmor_check(victim)) != NULL
    && parmor->value[1] > 1 )
	dam /= parmor->value[1];

        /*
         * Check for dodge.
         */
/*        if  (  dt >= TYPE_HIT )
        {

            if ( check_dodge( ch, victim ) && dam > 0 )
                return;       
         } */

        if ( IS_AFFECTED( victim, AFF_SANCTUARY ) )
            dam /= 2;
        if ( IS_AFFECTED2( victim, AFF_GOLDEN ) )
            dam /= 4;

       
        if ( dam < 0 )
            dam = 0;

    }

    /* We moved dam_message out of the victim != ch if above
     * so self damage would show.  Other valid type_undefined
     * damage is ok to avoid like mortally wounded damage - Kahn
     */
    if ( ( !IS_NPC(ch) ) && ( !IS_NPC(victim) ) )
       dam -= dam/4;

    /*
     * Hurt the victim.
     * Inform the victim of his new state.
     */

    if ( dt != TYPE_UNDEFINED )
        dam_message( ch, victim, dam, dt );

    if ( dam > 25 && number_range( 0, 100 ) <= 15 )
      item_damage(victim, dam);

    victim->hit -= dam;
    if ( ( ( !IS_NPC( victim )                  /* so imms only die by */
           && IS_NPC( ch )                      /* the hands of a PC   */
           && victim->level >= LEVEL_IMMORTAL )
         ||
           ( !IS_NPC( victim )                   /* so imms don,t die  */
           && victim->level >= LEVEL_IMMORTAL    /* by poison type dmg */
           && ch == victim ) )                   /* since an imm == pc */
         && victim->hit < 1 )
            victim->hit = 1;
  if ( victim->position == POS_DEAD  )
        return;

    update_pos( victim );

    switch( victim->position )
    {
    case POS_MORTAL:
        send_to_char(AT_RED,
            "You are mortally wounded, and will die soon, if not aided.\n\r",
            victim );
        act(AT_RED, "$n is mortally wounded, and will die soon, if not aided.",
            victim, NULL, NULL, TO_ROOM );
        break;
    case POS_INCAP:
        send_to_char(AT_RED,
            "You are incapacitated and will slowly die, if not aided.\n\r",
            victim );
        act(AT_RED, "$n is incapacitated and will slowly die, if not aided.",
            victim, NULL, NULL, TO_ROOM );
        break;

    case POS_STUNNED:
        send_to_char(AT_WHITE,"You are stunned, but will probably recover.\n\r",
            victim );
        act(AT_WHITE, "$n is stunned, but will probably recover.",
            victim, NULL, NULL, TO_ROOM );
        break;

    case POS_DEAD:
        send_to_char(AT_BLOOD, "You have been KILLED!!\n\r\n\r", victim );
        act(AT_BLOOD, "$n is DEAD!!", victim, NULL, NULL, TO_ROOM );
        break;

    default:
        if ( dam > MAX_HIT(victim) / 4 )
            send_to_char(AT_RED, "That really did HURT!\n\r", victim );
        if ( victim->hit < MAX_HIT(victim) / 4 )
            send_to_char(AT_RED, "You sure are BLEEDING!\n\r", victim );
        break;
    }

    /*
     * Sleep spells and extremely wounded folks.
     */
    if ( !IS_AWAKE( victim ) ) {
/*	send_to_char( C_DEFAULT, "stop shooting 3\n\r", ch ); */
        stop_shooting( victim, FALSE ); }
    /*
     * Payoff for killing things.
     */

    if ( victim->position == POS_DEAD )
    {
        if ( !IS_ARENA(ch) )
        {
          group_gain( ch, victim );

            if ( ( !IS_NPC(ch) ) && ( !IS_NPC(victim) ) )
            {
              if ( !(abs(ch->level - victim->level) > 10 ) )
              {
              ch->pkills++;
              victim->pkilled++;
                if ( ch->clan != victim->clan )
                {
                  CLAN_DATA  *pClan;
                  CLAN_DATA  *Cland;
                  if ( (pClan = get_clan_index(ch->clan)) != NULL )
                  pClan->pkills++;
                  if ( (Cland = get_clan_index(victim->clan)) != NULL )
                  Cland->pdeaths++;
                }     
              }
           }
          if ( ( !IS_NPC(ch) ) && ( IS_NPC(victim) ) )
          {
           CLAN_DATA    *pClan;
           if ( (pClan=get_clan_index(ch->clan)) != NULL )
             pClan->mkills++;
          }
          if ( ( IS_NPC(ch) ) && (!IS_NPC(victim)) )
          {
           CLAN_DATA   *pClan;
           if ( (pClan=get_clan_index(victim->clan)) != NULL )
             pClan->mdeaths++;
          }

          if ( !IS_NPC( victim ) )
          {
            /*
             * Dying penalty:
             * 1/2 way back to previous level.
             */
            if ( victim->level < LEVEL_HERO
            || ( victim->level >= LEVEL_HERO && IS_NPC( ch ) ) )
                death_xp_loss( victim );
            sprintf( log_buf, "%s killed by %s at %d.", victim->name,
                ch->name, victim->in_room->vnum );
            log_string( log_buf, CHANNEL_LOG, -1 );
            wiznet(log_buf,NULL,NULL,WIZ_DEATHS,0,0);
                info( "%s gets slaughtered by %s!", (int)victim->name,
                  (int)(IS_NPC(ch) ? ch->short_descr : ch->name) );
            save_clans();
          }
        }
        else
        {
          sprintf(log_buf, "&C%s &chas defeated &C%s &cin the arena!",
                  ch->name, victim->name);
          wiznet(log_buf, NULL, NULL, WIZ_DEATHS, 0, 0);
          log_string(log_buf, CHANNEL_LOG, -1);
          challenge(log_buf, 0, 0);
          ch->arenawon++;
          victim->arenalost++;
        }

        raw_kill( ch, victim );
        stop_shooting( ch, FALSE );
        /* Ok, now we want to remove the deleted flag from the
         * PC victim.
         */
        if ( !IS_NPC( victim ) )
            victim->deleted = FALSE;

/*        if ( !IS_NPC( ch ) && IS_NPC( victim ) )
        {
            if ( IS_SET( ch->act, PLR_AUTOLOOT ) )
                do_get( ch, "all corpse" );
            else
                do_look( ch, "in corpse" );

            if ( IS_SET( ch->act, PLR_AUTOCOINS ) )
                do_get( ch, "all.coin corpse" );
            if ( IS_SET( ch->act, PLR_AUTOSAC  ) )
                do_sacrifice( ch, "corpse" );
        } */

        return;
    }

    if ( victim == ch )
        return;

    /*
     * Take care of link dead people.
     */
/*    if ( !IS_NPC( victim ) && !victim->desc )
    {
        if ( number_range( 0, victim->wait ) == 0 )
        {
            do_recall( victim, "" );
            return;
        }
    } */

    /*
     * Wimp out?
     */
    if ( IS_NPC( victim ) && dam > 0 )
    {
        if ( ( IS_SET( victim->act, ACT_WIMPY ) && number_bits( 1 ) == 0
              && victim->hit < MAX_HIT(victim) / 2 )
            || ( IS_AFFECTED( victim, AFF_CHARM ) && victim->master
                && victim->master->in_room != victim->in_room ) )
            do_flee( victim, "" );
    }

    if ( !IS_NPC( victim )
        && victim->hit   > 0
        && victim->hit  <= victim->wimpy
        && victim->wait == 0 )
        do_flee( victim, "" );

    tail_chain( );
    return;
}


void set_shooting( CHAR_DATA *ch, CHAR_DATA *victim )
{
    char buf [ MAX_STRING_LENGTH ];

    if ( ch->engaged )
    {
        bug( "Set_shooting: already fighting", 0 );
        sprintf( buf, "...%s shooting %s at %d",
                ( IS_NPC( ch )     ? ch->short_descr     : ch->name     ),
                ( IS_NPC( victim ) ? victim->short_descr : victim->name ),
                victim->in_room->vnum );
        bug( buf , 0 );
        return;
    }

    if ( IS_AFFECTED( ch, AFF_SLEEP ) )
        affect_strip( ch, gsn_sleep );

    ch->engaged = victim;

    return;
}

void do_disengage( CHAR_DATA *ch, char *argument )
{
    if ( ch->engaged == NULL )
	{
	send_to_char( C_DEFAULT, "You are not shooting at anyone.\n\r", ch );
	return;
	}

	stop_shooting( ch, FALSE );

return;
}

void stop_shooting( CHAR_DATA *ch, bool fBoth )
{
    CHAR_DATA *fch;

    for ( fch = char_list; fch; fch = fch->next )
    {
        if ( fch == ch || ( fBoth && fch->engaged == ch ) )
        {
            fch->engaged       = NULL;
            fch->hunting        = NULL;
        }
    }

    return;
}


CHAR_DATA *crossfire_check( CHAR_DATA *ch, CHAR_DATA *fch )
{
    CHAR_DATA *rch;
    int aim, number;   





    aim = (get_curr_dex( ch ) * 3);
    number = number_percent();

    if ( number <= aim )
	return NULL;

    for ( rch = ch->in_room->people; rch; rch = rch->next_in_room )
    {
        if ( rch->level >= LEVEL_IMMORTAL )
	continue;

	if ( rch == ch )
	continue;

        if ( fch != rch )
            return rch;
    }

    return NULL;
}


bool target_available( CHAR_DATA *ch, CHAR_DATA *fch )
{
    CHAR_DATA *rch;

    for ( rch = ch->in_room->people; rch; rch = rch->next_in_room )
    {
        if ( !can_see( ch, rch ) || rch->name != fch->name )
            continue;
        if ( fch->name == rch->name )
            return TRUE;
    }

    return FALSE;
}

void do_reload( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj;
    OBJ_DATA *ammo;
    OBJ_DATA *ammox;
    OBJ_DATA *clip = NULL;
    char arg[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    bool ammocheck = FALSE;
    int  clipnum = 0;
    int  amount = 0;
    int  hasamount = 0;

  argument = one_argument( argument, arg );
  argument = one_argument( argument, arg2 );

  if ( arg[0] == '\0' )
  {
   send_to_char( AT_BLUE,
    "What do you plan to load into the gun or clip?\n\r", ch );
   return;
  }

  if ( ( obj = get_eq_char( ch, WEAR_HOLD ) ) == NULL )
  {
   send_to_char(AT_BLUE,"You aren't holding anything to reload.\n\r", ch );
   return;
  }


  if ( !( ammo = get_obj_carry( ch, arg ) ) )
  {
   send_to_char(AT_BLUE, "You are not holding the ammunition you refer to.\n\r", ch );
   return;
  }

  if ( ammo->item_type != ITEM_BULLET && ammo->item_type != ITEM_CLIP )
  {
   send_to_char( C_DEFAULT, "That is neither a clip nor a bullet.\n\r", ch );
   return;
  }

  if ( ammo->value[2] != obj->value[2] )
  {
   send_to_char( C_DEFAULT,
    "The calibur of the ammunition does not equal the calibur of the gun/clip.\n\r", ch );
   return;
  }

  if ( obj->item_type == ITEM_RANGED_WEAPON )
  {
    for ( ammox = obj->contains; ammox; ammox = ammox->next_content )
    {
     if ( !ammox )
      continue;

     if ( ammox->item_type != ITEM_BULLET && ammox->item_type != ITEM_CLIP )
      continue;

     if ( ammox->item_type == ITEM_BULLET )
     {
      ammocheck = TRUE;
      break;
     }

     if ( ammox->item_type == ITEM_CLIP )
     {
      clip = ammox;

      if ( !clip->contains ) 
       continue;

      for ( ammox = clip->contains; ammox; ammox = ammox->next_content )
      {
       if ( ammox->item_type == ITEM_BULLET )
       {
        ammocheck = TRUE;
        break;
       }
      }
      if ( ammocheck == TRUE )
       break;
     }
    }

  if ( ammox != NULL )
  {
   if ( ammox->item_type == ITEM_BULLET && 
        ammo->item_type == ITEM_BULLET && !(clip) )
   {
    send_to_char( C_DEFAULT, "There is already a single bullet in the chamber.\n\r", ch );
    return;
   }

   if ( (clip) && ammo->item_type == ITEM_CLIP )
   {
    send_to_char( C_DEFAULT, "There is a clip loaded already.\n\r", ch );
    return;
   }
  }

   if ( ammo->item_type == ITEM_CLIP && ammo->pIndexData->vnum != obj->value[3] )
   {
    send_to_char( C_DEFAULT, "That clip does not go with this gun.\n\r", ch );
    return;
   }    

   obj_from_char( ammo );
   obj_to_obj( ammo, obj );
   act(AT_GREEN, "You load $p into $P.", ch, ammo, obj, TO_CHAR );
   act(AT_GREEN, "$n loads $p into $P.", ch, ammo, obj, TO_ROOM );
  }
  else if ( obj->item_type == ITEM_CLIP )
  {
    char buf[MAX_STRING_LENGTH];
    if ( ammo->item_type != ITEM_BULLET )
    {
     send_to_char( C_DEFAULT, "That is not a bullet.\n\r", ch );
     return;
    }

    for ( ammox = obj->contains; ammox; ammox = ammox->next_content )
     clipnum += 1;

    if ( clipnum >= obj->value[1] )
    {
     send_to_char( C_DEFAULT, "That clip is full.\n\r", ch );
     return;
    }

   if ( !arg2[0] == '\0' && is_number(arg2) )
    amount = atoi(arg2);
   else
    amount = 1;

    hasamount = count_inv_obj( ch, ammo );
    if ( amount > hasamount )
    {
    send_to_char( AT_BLUE, "You don't have that much ammo.\n\r", ch );
    return;
    }

    if ( amount > ( obj->value[1] - clipnum ) )
    {
     sprintf( buf,
      "You are trying to load too many bullets into the clip,"
      " it has room enough for %d.\n\r", obj->value[1] - clipnum );
    
     send_to_char( C_DEFAULT, buf, ch );
     return;
    }

   while( amount >= 1 )
   {
    if ( (ammo = get_obj_carry( ch, arg )) )
    {
     obj_from_char( ammo );
     obj_to_obj( ammo, obj );
    }
    amount -= 1;
   }
   act(AT_GREEN, "You load $p into $P.", ch, ammo, obj, TO_CHAR );
   act(AT_GREEN, "$n loads $p into $P.", ch, ammo, obj, TO_ROOM );
 }
 return;
}

void do_unload( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *ammo;
    OBJ_DATA *gun = NULL;
    OBJ_DATA *obj;
    bool ammocheck = FALSE;
    bool gunfound = FALSE;

     for ( obj = ch->carrying; obj; obj = obj->next_content )
        {
        if ( obj->deleted )
            continue;

        if ( obj->item_type == ITEM_RANGED_WEAPON )
            {
            gun = obj;
            }
    if ( obj->wear_loc == WEAR_NONE )
            continue;
    	else
         gunfound = TRUE;

        }

        if (!gunfound)
          {
        send_to_char(AT_BLUE, "You do not have a ranged weapon equipped.\n\r", ch);
         return;
		}


    if ( !gun->contains )
    {
     send_to_char(AT_BLUE,"There isn't anything in that weapon.\n\r", ch );
     return;
    }
 

    for ( ammo = gun->contains; ammo; ammo = ammo->next_content )
    {
     if ( !ammo || ammo->deleted )
      continue;

     if ( !gun->contains ) 
      break;

     obj_from_obj( ammo );
     obj_to_char( ammo, ch );
     ammocheck = TRUE;
    }

  if ( ammocheck )
  {
   act(AT_GREEN, "You unload $p.", ch, gun, NULL, TO_CHAR );
   act(AT_GREEN, "$n unloads $p.", ch, gun, NULL, TO_ROOM );
  }
  else
   act(AT_GREEN, "Your $p is empty.", ch, gun, NULL, TO_CHAR );

 return;
}

int count_inv_obj(CHAR_DATA *ch, OBJ_DATA *obj)
{
    OBJ_DATA *inv;
    int count = 0;

    for ( inv = ch->carrying; inv; inv = inv->next_content )
        {
	if (inv->deleted)
	continue;
	if ( inv->pIndexData->vnum == obj->pIndexData->vnum )
	count++;
	}

return count;
}