/
swrfuss/
swrfuss/boards/
swrfuss/color/
swrfuss/doc/mudprogs/
swrfuss/email/
swrfuss/planets/
swrfuss/space/
/***************************************************************************
*                           STAR WARS REALITY 1.0                          *
*--------------------------------------------------------------------------*
* Star Wars Reality Code Additions and changes from the Smaug Code         *
* copyright (c) 1997 by Sean Cooper                                        *
* -------------------------------------------------------------------------*
* Starwars and Starwars Names copyright(c) Lucas Film Ltd.                 *
*--------------------------------------------------------------------------*
* SMAUG 1.0 (C) 1994, 1995, 1996 by Derek Snider                           *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,                    *
* Scryn, Rennard, Swordbearer, Gorog, Grishnakh and Tricops                *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
* Chastain, Michael Quan, and Mitchell Tse.                                *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
* ------------------------------------------------------------------------ *
*			    Battle & death module			   *
****************************************************************************/

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include "mud.h"

extern char lastplayercmd[MAX_INPUT_LENGTH];
extern CHAR_DATA *gch_prev;

/* From Skills.c */
int ris_save( CHAR_DATA * ch, int schance, int ris );

/*
 * Local functions.
 */
void dam_message args( ( CHAR_DATA * ch, CHAR_DATA * victim, int dam, int dt ) );
void group_gain args( ( CHAR_DATA * ch, CHAR_DATA * victim ) );
int xp_compute args( ( CHAR_DATA * gch, CHAR_DATA * victim ) );
int align_compute args( ( CHAR_DATA * gch, CHAR_DATA * victim ) );
ch_ret one_hit args( ( CHAR_DATA * ch, CHAR_DATA * victim, int dt ) );
int obj_hitroll args( ( OBJ_DATA * obj ) );
bool get_cover( CHAR_DATA * ch );
bool dual_flip = FALSE;

bool loot_coins_from_corpse( CHAR_DATA *ch, OBJ_DATA *corpse )
{
   OBJ_DATA *content, *content_next;
   int oldgold = ch->gold;

   for( content = corpse->first_content; content; content = content_next )
   {
      content_next = content->next_content;

      if( content->item_type != ITEM_MONEY )
         continue;
      if( !can_see_obj( ch, content ) )
         continue;
      if( !CAN_WEAR( content, ITEM_TAKE ) && ch->top_level < sysdata.level_getobjnotake )
         continue;
      if( IS_OBJ_STAT( content, ITEM_PROTOTYPE ) && !can_take_proto( ch ) )
         continue;

      act( AT_ACTION, "You get $p from $P", ch, content, corpse, TO_CHAR );
      act( AT_ACTION, "$n gets $p from $P", ch, content, corpse, TO_ROOM );
      obj_from_obj( content );
      check_for_trap( ch, content, TRAP_GET );
      if( char_died( ch ) )
         return FALSE;

      oprog_get_trigger( ch, content );
      if( char_died( ch ) )
         return FALSE;

      ch->gold += content->value[0] * content->count;
      extract_obj( content );
   }

   if( ch->gold - oldgold > 1 && ch->position > POS_SLEEPING )
   {
      char buf[MAX_INPUT_LENGTH];

      snprintf( buf, MAX_INPUT_LENGTH, "%d", ch->gold - oldgold );
      do_split( ch, buf );
   }
   return TRUE;
}

/*
 * Check to see if weapon is poisoned.
 */
bool is_wielding_poisoned( CHAR_DATA * ch )
{
   OBJ_DATA *obj;

   if( ( obj = get_eq_char( ch, WEAR_WIELD ) ) && ( IS_SET( obj->extra_flags, ITEM_POISONED ) ) )
      return TRUE;

   return FALSE;

}

/*
 * hunting, hating and fearing code				-Thoric
 */
bool is_hunting( CHAR_DATA * ch, CHAR_DATA * victim )
{
   if( !ch->hunting || ch->hunting->who != victim )
      return FALSE;

   return TRUE;
}

bool is_hating( CHAR_DATA * ch, CHAR_DATA * victim )
{
   if( !ch->hating || ch->hating->who != victim )
      return FALSE;

   return TRUE;
}

bool is_fearing( CHAR_DATA * ch, CHAR_DATA * victim )
{
   if( !ch->fearing || ch->fearing->who != victim )
      return FALSE;

   return TRUE;
}

void stop_hunting( CHAR_DATA * ch )
{
   if( ch->hunting )
   {
      STRFREE( ch->hunting->name );
      DISPOSE( ch->hunting );
      ch->hunting = NULL;
   }
   return;
}

void stop_hating( CHAR_DATA * ch )
{
   if( ch->hating )
   {
      STRFREE( ch->hating->name );
      DISPOSE( ch->hating );
      ch->hating = NULL;
   }
   return;
}

void stop_fearing( CHAR_DATA * ch )
{
   if( ch->fearing )
   {
      STRFREE( ch->fearing->name );
      DISPOSE( ch->fearing );
      ch->fearing = NULL;
   }
   return;
}

void start_hunting( CHAR_DATA * ch, CHAR_DATA * victim )
{
   if( ch->hunting )
      stop_hunting( ch );

   CREATE( ch->hunting, HHF_DATA, 1 );
   ch->hunting->name = QUICKLINK( victim->name );
   ch->hunting->who = victim;
   return;
}

void start_hating( CHAR_DATA * ch, CHAR_DATA * victim )
{
   if( ch->hating )
      stop_hating( ch );

   CREATE( ch->hating, HHF_DATA, 1 );
   ch->hating->name = QUICKLINK( victim->name );
   ch->hating->who = victim;
   return;
}

void start_fearing( CHAR_DATA * ch, CHAR_DATA * victim )
{
   if( ch->fearing )
      stop_fearing( ch );

   CREATE( ch->fearing, HHF_DATA, 1 );
   ch->fearing->name = QUICKLINK( victim->name );
   ch->fearing->who = victim;
   return;
}


int max_fight( CHAR_DATA * ch )
{
   return 8;
}

/*
 * Control the fights going on.
 * Called periodically by update_handler.
 * Many hours spent fixing bugs in here by Thoric, as noted by residual
 * debugging checks.  If you never get any of these error messages again
 * in your logs... then you can comment out some of the checks without
 * worry.
 */
void violence_update( void )
{
   char buf[MAX_STRING_LENGTH];
   CHAR_DATA *ch;
   CHAR_DATA *lst_ch;
   CHAR_DATA *victim;
   CHAR_DATA *rch, *rch_next;
   AFFECT_DATA *paf, *paf_next;
   TIMER *timer, *timer_next;
   ch_ret retcode;
   SKILLTYPE *skill;

   lst_ch = NULL;
   for( ch = last_char; ch; lst_ch = ch, ch = gch_prev )
   {
      set_cur_char( ch );

      if( ch == first_char && ch->prev )
      {
         bug( "ERROR: first_char->prev != NULL, fixing...", 0 );
         ch->prev = NULL;
      }

      gch_prev = ch->prev;

      if( gch_prev && gch_prev->next != ch )
      {
         sprintf( buf, "FATAL: violence_update: %s->prev->next doesn't point to ch.", ch->name );
         bug( buf, 0 );
         bug( "Short-cutting here", 0 );
         ch->prev = NULL;
         gch_prev = NULL;
         do_shout( ch, "Thoric says, 'Prepare for the worst!'" );
      }

      /*
       * See if we got a pointer to someone who recently died...
       * if so, either the pointer is bad... or it's a player who
       * "died", and is back at the healer...
       * Since he/she's in the char_list, it's likely to be the later...
       * and should not already be in another fight already
       */
      if( char_died( ch ) )
         continue;

      /*
       * See if we got a pointer to some bad looking data...
       */
      if( !ch->in_room || !ch->name )
      {
         log_string( "violence_update: bad ch record!  (Shortcutting.)" );
         sprintf( buf, "ch: %ld  ch->in_room: %ld  ch->prev: %ld  ch->next: %ld",
                  ( long )ch, ( long )ch->in_room, ( long )ch->prev, ( long )ch->next );
         log_string( buf );
         log_string( lastplayercmd );
         if( lst_ch )
            sprintf( buf, "lst_ch: %ld  lst_ch->prev: %ld  lst_ch->next: %ld",
                     ( long )lst_ch, ( long )lst_ch->prev, ( long )lst_ch->next );
         else
            strcpy( buf, "lst_ch: NULL" );
         log_string( buf );
         gch_prev = NULL;
         continue;
      }

      /*
       * Experience gained during battle deceases as battle drags on
       */
      if( ch->fighting )
         if( ( ++ch->fighting->duration % 24 ) == 0 )
            ch->fighting->xp = ( ( ch->fighting->xp * 9 ) / 10 );


      for( timer = ch->first_timer; timer; timer = timer_next )
      {
         timer_next = timer->next;
         if( --timer->count <= 0 )
         {
            if( timer->type == TIMER_DO_FUN )
            {
               int tempsub;

               tempsub = ch->substate;
               ch->substate = timer->value;
               ( timer->do_fun ) ( ch, "" );
               if( char_died( ch ) )
                  break;
               ch->substate = tempsub;
            }
            extract_timer( ch, timer );
         }
      }

      if( char_died( ch ) )
         continue;

      /*
       * We need spells that have shorter durations than an hour.
       * So a melee round sounds good to me... -Thoric
       */
      for( paf = ch->first_affect; paf; paf = paf_next )
      {
         paf_next = paf->next;
         if( paf->duration > 0 )
            paf->duration--;
         else if( paf->duration < 0 )
            ;
         else
         {
            if( !paf_next || paf_next->type != paf->type || paf_next->duration > 0 )
            {
               skill = get_skilltype( paf->type );
               if( paf->type > 0 && skill && skill->msg_off )
               {
                  set_char_color( AT_WEAROFF, ch );
                  send_to_char( skill->msg_off, ch );
                  send_to_char( "\r\n", ch );
               }
            }
            if( paf->type == gsn_possess )
            {
               ch->desc->character = ch->desc->original;
               ch->desc->original = NULL;
               ch->desc->character->desc = ch->desc;
               ch->desc->character->switched = NULL;
               ch->desc = NULL;
            }
            affect_remove( ch, paf );
         }
      }

      if( ( victim = who_fighting( ch ) ) == NULL || IS_AFFECTED( ch, AFF_PARALYSIS ) )
         continue;

      retcode = rNONE;

      if( IS_SET( ch->in_room->room_flags, ROOM_SAFE ) )
      {
         sprintf( buf, "violence_update: %s fighting %s in a SAFE room.", ch->name, victim->name );
         log_string( buf );
         stop_fighting( ch, TRUE );
      }
      else if( IS_AWAKE( ch ) && ch->in_room == victim->in_room )
         retcode = multi_hit( ch, victim, TYPE_UNDEFINED );
      else
         stop_fighting( ch, FALSE );

      if( char_died( ch ) )
         continue;

      if( retcode == rCHAR_DIED || ( victim = who_fighting( ch ) ) == NULL )
         continue;

      /*
       *  Mob triggers
       */
      rprog_rfight_trigger( ch );
      if( char_died( ch ) )
         continue;
      mprog_hitprcnt_trigger( ch, victim );
      if( char_died( ch ) )
         continue;
      mprog_fight_trigger( ch, victim );
      if( char_died( ch ) )
         continue;

      /*
       * Fun for the whole family!
       */
      for( rch = ch->in_room->first_person; rch; rch = rch_next )
      {
         rch_next = rch->next_in_room;

         if( IS_AWAKE( rch ) && !rch->fighting )
         {
            /*
             * PC's auto-assist others in their group.
             */
            if( !IS_NPC( ch ) || IS_AFFECTED( ch, AFF_CHARM ) )
            {
               if( ( !IS_NPC( rch ) || IS_AFFECTED( rch, AFF_CHARM ) ) && is_same_group( ch, rch ) )
                  multi_hit( rch, victim, TYPE_UNDEFINED );
               continue;
            }

            /*
             * NPC's assist NPC's of same type or 12.5% schance regardless.
             */
            if( IS_NPC( rch ) && !IS_AFFECTED( rch, AFF_CHARM ) && !IS_SET( rch->act, ACT_NOASSIST ) )
            {
               if( char_died( ch ) )
                  break;
               if( rch->pIndexData == ch->pIndexData || number_bits( 3 ) == 0 )
               {
                  CHAR_DATA *vch;
                  CHAR_DATA *target;
                  int number;

                  target = NULL;
                  number = 0;
                  for( vch = ch->in_room->first_person; vch; vch = vch->next )
                  {
                     if( can_see( rch, vch ) && is_same_group( vch, victim ) && number_range( 0, number ) == 0 )
                     {
                        target = vch;
                        number++;
                     }
                  }

                  if( target )
                     multi_hit( rch, target, TYPE_UNDEFINED );
               }
            }
         }
      }
   }

   return;
}



/*
 * Do one group of attacks.
 */
ch_ret multi_hit( CHAR_DATA * ch, CHAR_DATA * victim, int dt )
{
   int schance;
   int dual_bonus;
   ch_ret retcode;

   /*
    * add timer if player is attacking another player 
    */
   if( !IS_NPC( ch ) && !IS_NPC( victim ) )
      add_timer( ch, TIMER_RECENTFIGHT, 20, NULL, 0 );

   if( !IS_NPC( ch ) && IS_SET( ch->act, PLR_NICE ) && !IS_NPC( victim ) )
      return rNONE;

   if( ( retcode = one_hit( ch, victim, dt ) ) != rNONE )
      return retcode;

   if( who_fighting( ch ) != victim || dt == gsn_backstab || dt == gsn_circle )
      return rNONE;

   /*
    * Very high schance of hitting compared to schance of going berserk 
    */
   /*
    * 40% or higher is always hit.. don't learn anything here though. 
    */
   /*
    * -- Altrag 
    */
   schance = IS_NPC( ch ) ? 100 : ( ch->pcdata->learned[gsn_berserk] * 5 / 2 );
   if( IS_AFFECTED( ch, AFF_BERSERK ) && number_percent(  ) < schance )
      if( ( retcode = one_hit( ch, victim, dt ) ) != rNONE || who_fighting( ch ) != victim )
         return retcode;

   if( get_eq_char( ch, WEAR_DUAL_WIELD ) )
   {
      dual_bonus = IS_NPC( ch ) ? ( ch->skill_level[COMBAT_ABILITY] / 10 ) : ( ch->pcdata->learned[gsn_dual_wield] / 10 );
      schance = IS_NPC( ch ) ? ch->top_level : ch->pcdata->learned[gsn_dual_wield];
      if( number_percent(  ) < schance )
      {
         learn_from_success( ch, gsn_dual_wield );
         retcode = one_hit( ch, victim, dt );
         if( retcode != rNONE || who_fighting( ch ) != victim )
            return retcode;
      }
      else
         learn_from_failure( ch, gsn_dual_wield );
   }
   else
      dual_bonus = 0;

   if( ch->move < 10 )
      dual_bonus = -20;

   /*
    * NPC predetermined number of attacks         -Thoric
    */
   if( IS_NPC( ch ) && ch->numattacks > 0 )
   {
      for( schance = 0; schance <= ch->numattacks; schance++ )
      {
         retcode = one_hit( ch, victim, dt );
         if( retcode != rNONE || who_fighting( ch ) != victim )
            return retcode;
      }
      return retcode;
   }

   schance = IS_NPC( ch ) ? ch->top_level : ( int )( ( ch->pcdata->learned[gsn_second_attack] + dual_bonus ) / 1.5 );
   if( number_percent(  ) < schance )
   {
      learn_from_success( ch, gsn_second_attack );
      retcode = one_hit( ch, victim, dt );
      if( retcode != rNONE || who_fighting( ch ) != victim )
         return retcode;
   }
   else
      learn_from_failure( ch, gsn_second_attack );

   schance = IS_NPC( ch ) ? ch->top_level : ( int )( ( ch->pcdata->learned[gsn_third_attack] + ( dual_bonus * 1.5 ) ) / 2 );
   if( number_percent(  ) < schance )
   {
      learn_from_success( ch, gsn_third_attack );
      retcode = one_hit( ch, victim, dt );
      if( retcode != rNONE || who_fighting( ch ) != victim )
         return retcode;
   }
   else
      learn_from_failure( ch, gsn_third_attack );

   retcode = rNONE;

   schance = IS_NPC( ch ) ? ( int )( ch->top_level / 4 ) : 0;
   if( number_percent(  ) < schance )
      retcode = one_hit( ch, victim, dt );

   if( retcode == rNONE )
   {
      int move;

      if( !IS_AFFECTED( ch, AFF_FLYING ) && !IS_AFFECTED( ch, AFF_FLOATING ) )
         move = encumbrance( ch, movement_loss[UMIN( SECT_MAX - 1, ch->in_room->sector_type )] );
      else
         move = encumbrance( ch, 1 );
      if( ch->move )
         ch->move = UMAX( 0, ch->move - move );
   }

   return retcode;
}


/*
 * Weapon types, haus
 */
int weapon_prof_bonus_check( CHAR_DATA * ch, OBJ_DATA * wield, int *gsn_ptr )
{
   int bonus;

   bonus = 0;
   *gsn_ptr = -1;
   if( !IS_NPC( ch ) && wield )
   {
      switch ( wield->value[3] )
      {
         default:
            *gsn_ptr = -1;
            break;
         case 3:
            *gsn_ptr = gsn_lightsabers;
            break;
         case 2:
            *gsn_ptr = gsn_vibro_blades;
            break;
         case 4:
            *gsn_ptr = gsn_flexible_arms;
            break;
         case 5:
            *gsn_ptr = gsn_talonous_arms;
            break;
         case 6:
            *gsn_ptr = gsn_blasters;
            break;
         case 8:
            *gsn_ptr = gsn_bludgeons;
            break;
         case 9:
            *gsn_ptr = gsn_bowcasters;
            break;
         case 11:
            *gsn_ptr = gsn_force_pikes;
            break;

      }
      if( *gsn_ptr != -1 )
         bonus = ( int )( ch->pcdata->learned[*gsn_ptr] );

   }
   if( IS_NPC( ch ) && wield )
      bonus = get_trust( ch );
   return bonus;
}

/*
 * Calculate the tohit bonus on the object and return RIS values.
 * -- Altrag
 */
int obj_hitroll( OBJ_DATA * obj )
{
   int tohit = 0;
   AFFECT_DATA *paf;

   for( paf = obj->pIndexData->first_affect; paf; paf = paf->next )
      if( paf->location == APPLY_HITROLL )
         tohit += paf->modifier;
   for( paf = obj->first_affect; paf; paf = paf->next )
      if( paf->location == APPLY_HITROLL )
         tohit += paf->modifier;
   return tohit;
}

/*
 * Offensive shield level modifier
 */
short off_shld_lvl( CHAR_DATA * ch, CHAR_DATA * victim )
{
   short lvl;

   if( !IS_NPC( ch ) )  /* players get much less effect */
   {
      lvl = UMAX( 1, ( ch->skill_level[FORCE_ABILITY] ) );
      if( number_percent(  ) + ( victim->skill_level[COMBAT_ABILITY] - lvl ) < 35 )
         return lvl;
      else
         return 0;
   }
   else
   {
      lvl = ch->top_level;
      if( number_percent(  ) + ( victim->skill_level[COMBAT_ABILITY] - lvl ) < 70 )
         return lvl;
      else
         return 0;
   }
}

/*
 * Hit one guy once.
 */
ch_ret one_hit( CHAR_DATA * ch, CHAR_DATA * victim, int dt )
{
   OBJ_DATA *wield;
   int victim_ac;
   int thac0;
   int thac0_00;
   int thac0_32;
   int plusris;
   int dam, x;
   int diceroll;
   int attacktype, cnt;
   int prof_bonus;
   int prof_gsn;
   ch_ret retcode = rNONE;
   int schance;
   bool fail;
   AFFECT_DATA af;


   /*
    * Can't beat a dead char!
    * Guard against weird room-leavings.
    */
   if( victim->position == POS_DEAD || ch->in_room != victim->in_room )
      return rVICT_DIED;


   /*
    * Figure out the weapon doing the damage         -Thoric
    */
   if( ( wield = get_eq_char( ch, WEAR_DUAL_WIELD ) ) != NULL )
   {
      if( dual_flip == FALSE )
      {
         dual_flip = TRUE;
         wield = get_eq_char( ch, WEAR_WIELD );
      }
      else
         dual_flip = FALSE;
   }
   else
      wield = get_eq_char( ch, WEAR_WIELD );

   prof_bonus = weapon_prof_bonus_check( ch, wield, &prof_gsn );

   if( ch->fighting  /* make sure fight is already started */
       && dt == TYPE_UNDEFINED && IS_NPC( ch ) && ch->attacks != 0 )
   {
      cnt = 0;
      for( ;; )
      {
         x = number_range( 0, 6 );
         attacktype = 1 << x;
         if( IS_SET( ch->attacks, attacktype ) )
            break;
         if( cnt++ > 16 )
         {
            attacktype = 0;
            break;
         }
      }
      if( attacktype == ATCK_BACKSTAB )
         attacktype = 0;
      if( wield && number_percent(  ) > 25 )
         attacktype = 0;
      switch ( attacktype )
      {
         default:
            break;
         case ATCK_BITE:
            do_bite( ch, "" );
            retcode = global_retcode;
            break;
         case ATCK_CLAWS:
            do_claw( ch, "" );
            retcode = global_retcode;
            break;
         case ATCK_TAIL:
            do_tail( ch, "" );
            retcode = global_retcode;
            break;
         case ATCK_STING:
            do_sting( ch, "" );
            retcode = global_retcode;
            break;
         case ATCK_PUNCH:
            do_punch( ch, "" );
            retcode = global_retcode;
            break;
         case ATCK_KICK:
            do_kick( ch, "" );
            retcode = global_retcode;
            break;
         case ATCK_TRIP:
            attacktype = 0;
            break;
      }
      if( attacktype )
         return retcode;
   }

   if( dt == TYPE_UNDEFINED )
   {
      dt = TYPE_HIT;
      if( wield && wield->item_type == ITEM_WEAPON )
         dt += wield->value[3];
   }

   /*
    * Calculate to-hit-armor-class-0 versus armor.
    */
   thac0_00 = 20;
   thac0_32 = 10;
   thac0 = interpolate( ch->skill_level[COMBAT_ABILITY], thac0_00, thac0_32 ) - GET_HITROLL( ch );
   victim_ac = ( int )( GET_AC( victim ) / 10 );

   /*
    * if you can't see what's coming... 
    */
   if( wield && !can_see_obj( victim, wield ) )
      victim_ac += 1;
   if( !can_see( ch, victim ) )
      victim_ac -= 4;

   if( ch->race == RACE_DEFEL )
      victim_ac += 2;

   if( !IS_AWAKE( victim ) )
      victim_ac += 5;

   /*
    * Weapon proficiency bonus 
    */
   victim_ac += prof_bonus / 20;

   /*
    * The moment of excitement!
    */
   diceroll = number_range( 1, 20 );

   if( diceroll == 1 || ( diceroll < 20 && diceroll < thac0 - victim_ac ) )
   {
      /*
       * Miss. 
       */
      if( prof_gsn != -1 )
         learn_from_failure( ch, prof_gsn );
      damage( ch, victim, 0, dt );
      tail_chain(  );
      return rNONE;
   }

   /*
    * Hit.
    * Calc damage.
    */

   if( !wield )   /* dice formula fixed by Thoric */
      dam = number_range( ch->barenumdie, ch->baresizedie * ch->barenumdie ) + ch->damplus;
   else
      dam = number_range( wield->value[1], wield->value[2] );

   /*
    * Bonuses.
    */

   dam += GET_DAMROLL( ch );

   if( prof_bonus )
      dam *= ( 1 + prof_bonus / 100 );


   if( !IS_NPC( ch ) && ch->pcdata->learned[gsn_enhanced_damage] > 0 )
   {
      dam += ( int )( dam * ch->pcdata->learned[gsn_enhanced_damage] / 120 );
      learn_from_success( ch, gsn_enhanced_damage );
   }


   if( !IS_AWAKE( victim ) )
      dam *= 2;
   if( dt == gsn_backstab )
      dam *= ( 2 + URANGE( 2, ch->skill_level[HUNTING_ABILITY] - ( victim->skill_level[COMBAT_ABILITY] / 4 ), 30 ) / 8 );

   if( dt == gsn_circle )
      dam *= ( 2 + URANGE( 2, ch->skill_level[HUNTING_ABILITY] - ( victim->skill_level[COMBAT_ABILITY] / 4 ), 30 ) / 16 );

   plusris = 0;

   if( wield )
   {
      if( IS_SET( wield->extra_flags, ITEM_MAGIC ) )
         dam = ris_damage( victim, dam, RIS_MAGIC );
      else
         dam = ris_damage( victim, dam, RIS_NONMAGIC );

      /*
       * Handle PLUS1 - PLUS6 ris bits vs. weapon hitroll   -Thoric
       */
      plusris = obj_hitroll( wield );
   }
   else
      dam = ris_damage( victim, dam, RIS_NONMAGIC );

   /*
    * check for RIS_PLUSx                -Thoric 
    */
   if( dam )
   {
      int xx, res, imm, sus, mod;

      if( plusris )
         plusris = RIS_PLUS1 << UMIN( plusris, 7 );

      /*
       * initialize values to handle a zero plusris 
       */
      imm = res = -1;
      sus = 1;

      /*
       * find high ris 
       */
      for( xx = RIS_PLUS1; xx <= RIS_PLUS6; xx <<= 1 )
      {
         if( IS_SET( victim->immune, xx ) )
            imm = xx;
         if( IS_SET( victim->resistant, xx ) )
            res = xx;
         if( IS_SET( victim->susceptible, xx ) )
            sus = xx;
      }
      mod = 10;
      if( imm >= plusris )
         mod -= 10;
      if( res >= plusris )
         mod -= 2;
      if( sus <= plusris )
         mod += 2;

      /*
       * check if immune 
       */
      if( mod <= 0 )
         dam = -1;
      if( mod != 10 )
         dam = ( dam * mod ) / 10;
   }

   /*
    * race modifier 
    */

   if( victim->race == RACE_DUINUOGWUIN )
      dam /= 5;

   /*
    * check to see if weapon is charged 
    */

   if( dt == ( TYPE_HIT + WEAPON_BLASTER ) && wield && wield->item_type == ITEM_WEAPON )
   {
      if( wield->value[4] < 1 )
      {
         act( AT_YELLOW, "$n points their blaster at you but nothing happens.", ch, NULL, victim, TO_VICT );
         act( AT_YELLOW, "*CLICK* ... your blaster needs a new ammunition cell!", ch, NULL, victim, TO_CHAR );
         if( IS_NPC( ch ) )
         {
            do_remove( ch, wield->name );
         }
         return rNONE;
      }
      else if( wield->blaster_setting == BLASTER_FULL && wield->value[4] >= 5 )
      {
         dam *= 1.5;
         wield->value[4] -= 5;
      }
      else if( wield->blaster_setting == BLASTER_HIGH && wield->value[4] >= 4 )
      {
         dam *= 1.25;
         wield->value[4] -= 4;
      }
      else if( wield->blaster_setting == BLASTER_NORMAL && wield->value[4] >= 3 )
      {
         wield->value[4] -= 3;
      }
      else if( wield->blaster_setting == BLASTER_STUN && wield->value[4] >= 5 )
      {
         dam /= 10;
         wield->value[4] -= 3;
         fail = FALSE;
         schance = ris_save( victim, ch->skill_level[COMBAT_ABILITY], RIS_PARALYSIS );
         if( schance == 1000 )
            fail = TRUE;
         else
            fail = saves_para_petri( schance, victim );
         if( victim->was_stunned > 0 )
         {
            fail = TRUE;
            victim->was_stunned--;
         }
         schance = 100 - get_curr_con( victim ) - victim->skill_level[COMBAT_ABILITY] / 2;
         /*
          * harder for player to stun another player 
          */
         if( !IS_NPC( ch ) && !IS_NPC( victim ) )
            schance -= sysdata.stun_plr_vs_plr;
         else
            schance -= sysdata.stun_regular;
         schance = URANGE( 5, schance, 95 );
         if( !fail && number_percent(  ) < schance )
         {
            WAIT_STATE( victim, PULSE_VIOLENCE );
            act( AT_BLUE, "Blue rings of energy from $N's blaster knock you down leaving you stunned!", victim, NULL, ch,
                 TO_CHAR );
            act( AT_BLUE, "Blue rings of energy from your blaster strike $N, leaving $M stunned!", ch, NULL, victim,
                 TO_CHAR );
            act( AT_BLUE, "Blue rings of energy from $n's blaster hit $N, leaving $M stunned!", ch, NULL, victim,
                 TO_NOTVICT );
            stop_fighting( victim, TRUE );
            if( !IS_AFFECTED( victim, AFF_PARALYSIS ) )
            {
               af.type = gsn_stun;
               af.location = APPLY_AC;
               af.modifier = 20;
               af.duration = 7;
               af.bitvector = AFF_PARALYSIS;
               affect_to_char( victim, &af );
               update_pos( victim );
               if( IS_NPC( victim ) )
               {
                  start_hating( victim, ch );
                  start_hunting( victim, ch );
                  victim->was_stunned = 10;
               }
            }
         }
         else
         {
            act( AT_BLUE, "Blue rings of energy from $N's blaster hit you but have little effect", victim, NULL, ch,
                 TO_CHAR );
            act( AT_BLUE, "Blue rings of energy from your blaster hit $N, but nothing seems to happen!", ch, NULL, victim,
                 TO_CHAR );
            act( AT_BLUE, "Blue rings of energy from $n's blaster hit $N, but nothing seems to happen!", ch, NULL, victim,
                 TO_NOTVICT );

         }
      }
      else if( wield->blaster_setting == BLASTER_HALF && wield->value[4] >= 2 )
      {
         dam *= 0.75;
         wield->value[4] -= 2;
      }
      else
      {
         dam *= 0.5;
         wield->value[4] -= 1;
      }

   }
   else if( dt == ( TYPE_HIT + WEAPON_VIBRO_BLADE ) && wield && wield->item_type == ITEM_WEAPON )
   {
      if( wield->value[4] < 1 )
      {
         act( AT_YELLOW, "Your vibro-blade needs recharging ...", ch, NULL, victim, TO_CHAR );
         dam /= 3;
      }
   }
   else if( dt == ( TYPE_HIT + WEAPON_FORCE_PIKE ) && wield && wield->item_type == ITEM_WEAPON )
   {
      if( wield->value[4] < 1 )
      {
         act( AT_YELLOW, "Your force-pike needs recharging ...", ch, NULL, victim, TO_CHAR );
         dam /= 2;
      }
      else
         wield->value[4]--;
   }
   else if( dt == ( TYPE_HIT + WEAPON_LIGHTSABER ) && wield && wield->item_type == ITEM_WEAPON )
   {
      if( wield->value[4] < 1 )
      {
         act( AT_YELLOW, "$n waves a dead hand grip around in the air.", ch, NULL, victim, TO_VICT );
         act( AT_YELLOW, "You need to recharge your lightsaber ... it seems to be lacking a blade.", ch, NULL, victim,
              TO_CHAR );
         if( IS_NPC( ch ) )
         {
            do_remove( ch, wield->name );
         }
         return rNONE;
      }
   }
   else if( dt == ( TYPE_HIT + WEAPON_BOWCASTER ) && wield && wield->item_type == ITEM_WEAPON )
   {
      if( wield->value[4] < 1 )
      {
         act( AT_YELLOW, "$n points their bowcaster at you but nothing happens.", ch, NULL, victim, TO_VICT );
         act( AT_YELLOW, "*CLICK* ... your bowcaster needs a new bolt cartridge!", ch, NULL, victim, TO_CHAR );
         if( IS_NPC( ch ) )
         {
            do_remove( ch, wield->name );
         }
         return rNONE;
      }
      else
         wield->value[4]--;
   }

   if( dam <= 0 )
      dam = 1;

   if( prof_gsn != -1 )
   {
      if( dam > 0 )
         learn_from_success( ch, prof_gsn );
      else
         learn_from_failure( ch, prof_gsn );
   }

   /*
    * immune to damage 
    */
   if( dam == -1 )
   {
      if( dt >= 0 && dt < top_sn )
      {
         SKILLTYPE *skill = skill_table[dt];
         bool found = FALSE;

         if( skill->imm_char && skill->imm_char[0] != '\0' )
         {
            act( AT_HIT, skill->imm_char, ch, NULL, victim, TO_CHAR );
            found = TRUE;
         }
         if( skill->imm_vict && skill->imm_vict[0] != '\0' )
         {
            act( AT_HITME, skill->imm_vict, ch, NULL, victim, TO_VICT );
            found = TRUE;
         }
         if( skill->imm_room && skill->imm_room[0] != '\0' )
         {
            act( AT_ACTION, skill->imm_room, ch, NULL, victim, TO_NOTVICT );
            found = TRUE;
         }
         if( found )
            return rNONE;
      }
      dam = 0;
   }
   if( ( retcode = damage( ch, victim, dam, dt ) ) != rNONE )
      return retcode;
   if( char_died( ch ) )
      return rCHAR_DIED;
   if( char_died( victim ) )
      return rVICT_DIED;

   retcode = rNONE;
   if( dam == 0 )
      return retcode;

   /* weapon spells -Thoric */
   if( wield && !IS_SET( victim->immune, RIS_MAGIC ) && !IS_SET( victim->in_room->room_flags, ROOM_NO_MAGIC ) )
   {
      AFFECT_DATA *aff;

      for( aff = wield->pIndexData->first_affect; aff; aff = aff->next )
         if( aff->location == APPLY_WEAPONSPELL && IS_VALID_SN( aff->modifier ) && skill_table[aff->modifier]->spell_fun )
            retcode = ( *skill_table[aff->modifier]->spell_fun ) ( aff->modifier, ( wield->level + 3 ) / 3, ch, victim );

      if( retcode == rSPELL_FAILED ) retcode = rNONE; // Luc, 6/11/2007

      if( retcode != rNONE || char_died( ch ) || char_died( victim ) )
         return retcode;
      for( aff = wield->first_affect; aff; aff = aff->next )
         if( aff->location == APPLY_WEAPONSPELL && IS_VALID_SN( aff->modifier ) && skill_table[aff->modifier]->spell_fun )
            retcode = ( *skill_table[aff->modifier]->spell_fun ) ( aff->modifier, ( wield->level + 3 ) / 3, ch, victim );

      if( retcode == rSPELL_FAILED ) retcode = rNONE; // Luc, 6/11/2007

      if( retcode != rNONE || char_died( ch ) || char_died( victim ) )
         return retcode;
   }

   /*
    * magic shields that retaliate          -Thoric
    */
   if( IS_AFFECTED( victim, AFF_FIRESHIELD ) && !IS_AFFECTED( ch, AFF_FIRESHIELD ) )
      retcode = spell_fireball( gsn_fireball, off_shld_lvl( victim, ch ), victim, ch );
   if( retcode != rNONE || char_died( ch ) || char_died( victim ) )
      return retcode;

   if( retcode != rNONE || char_died( ch ) || char_died( victim ) )
      return retcode;

   if( IS_AFFECTED( victim, AFF_SHOCKSHIELD ) && !IS_AFFECTED( ch, AFF_SHOCKSHIELD ) )
      retcode = spell_lightning_bolt( gsn_lightning_bolt, off_shld_lvl( victim, ch ), victim, ch );
   if( retcode != rNONE || char_died( ch ) || char_died( victim ) )
      return retcode;

   /*
    *   folks with blasters move and snipe instead of getting neatin up in one spot.
    */
   if( IS_NPC( victim ) )
   {
      OBJ_DATA *owield;

      owield = get_eq_char( victim, WEAR_WIELD );
      if( owield != NULL && owield->value[3] == WEAPON_BLASTER && get_cover( victim ) == TRUE )
      {
         start_hating( victim, ch );
         start_hunting( victim, ch );
      }
   }

   tail_chain(  );
   return retcode;
}

/*
 * Calculate damage based on resistances, immunities and suceptibilities
 *					-Thoric
 */
short ris_damage( CHAR_DATA * ch, short dam, int ris )
{
   short modifier;

   modifier = 10;
   if( IS_SET( ch->immune, ris ) )
      modifier -= 10;
   if( IS_SET( ch->resistant, ris ) )
      modifier -= 2;
   if( IS_SET( ch->susceptible, ris ) )
      modifier += 2;
   if( modifier <= 0 )
      return -1;
   if( modifier == 10 )
      return dam;
   return ( dam * modifier ) / 10;
}

/*
 * Inflict damage from a hit.
 */
ch_ret damage( CHAR_DATA * ch, CHAR_DATA * victim, int dam, int dt )
{
   short dameq;
   bool npcvict;
   bool loot;
   int xp_gain;
   OBJ_DATA *damobj;
   ch_ret retcode;
   short dampmod;

   retcode = rNONE;

   if( !ch )
   {
      bug( "Damage: null ch!", 0 );
      return rERROR;
   }
   if( !victim )
   {
      bug( "Damage: null victim!", 0 );
      return rVICT_DIED;
   }

   if( victim->position == POS_DEAD )
      return rVICT_DIED;

   npcvict = IS_NPC( victim );

   /*
    * Check damage types for RIS            -Thoric
    */
   if( dam && dt != TYPE_UNDEFINED )
   {
      if( IS_FIRE( dt ) )
         dam = ris_damage( victim, dam, RIS_FIRE );
      else if( IS_COLD( dt ) )
         dam = ris_damage( victim, dam, RIS_COLD );
      else if( IS_ACID( dt ) )
         dam = ris_damage( victim, dam, RIS_ACID );
      else if( IS_ELECTRICITY( dt ) )
         dam = ris_damage( victim, dam, RIS_ELECTRICITY );
      else if( IS_ENERGY( dt ) )
         dam = ris_damage( victim, dam, RIS_ENERGY );
      else if( IS_DRAIN( dt ) )
         dam = ris_damage( victim, dam, RIS_DRAIN );
      else if( dt == gsn_poison || IS_POISON( dt ) )
         dam = ris_damage( victim, dam, RIS_POISON );
      else if( dt == ( TYPE_HIT + 7 ) || dt == ( TYPE_HIT + 8 ) )
         dam = ris_damage( victim, dam, RIS_BLUNT );
      else if( dt == ( TYPE_HIT + 2 ) || dt == ( TYPE_HIT + 11 ) || dt == ( TYPE_HIT + 10 ) )
         dam = ris_damage( victim, dam, RIS_PIERCE );
      else if( dt == ( TYPE_HIT + 1 ) || dt == ( TYPE_HIT + 3 ) || dt == ( TYPE_HIT + 4 ) || dt == ( TYPE_HIT + 5 ) )
         dam = ris_damage( victim, dam, RIS_SLASH );

      if( dam == -1 )
      {
         if( dt >= 0 && dt < top_sn )
         {
            bool found = FALSE;
            SKILLTYPE *skill = skill_table[dt];

            if( skill->imm_char && skill->imm_char[0] != '\0' )
            {
               act( AT_HIT, skill->imm_char, ch, NULL, victim, TO_CHAR );
               found = TRUE;
            }
            if( skill->imm_vict && skill->imm_vict[0] != '\0' )
            {
               act( AT_HITME, skill->imm_vict, ch, NULL, victim, TO_VICT );
               found = TRUE;
            }
            if( skill->imm_room && skill->imm_room[0] != '\0' )
            {
               act( AT_ACTION, skill->imm_room, ch, NULL, victim, TO_NOTVICT );
               found = TRUE;
            }
            if( found )
               return rNONE;
         }
         dam = 0;
      }
   }

   if( dam && npcvict && ch != victim )
   {
      if( !IS_SET( victim->act, ACT_SENTINEL ) )
      {
         if( victim->hunting )
         {
            if( victim->hunting->who != ch )
            {
               STRFREE( victim->hunting->name );
               victim->hunting->name = QUICKLINK( ch->name );
               victim->hunting->who = ch;
            }
         }
         else
            start_hunting( victim, ch );
      }

      if( victim->hating )
      {
         if( victim->hating->who != ch )
         {
            STRFREE( victim->hating->name );
            victim->hating->name = QUICKLINK( ch->name );
            victim->hating->who = ch;
         }
      }
      else
         start_hating( victim, ch );
   }

   if( victim != ch )
   {
      /*
       * Certain attacks are forbidden.
       * Most other attacks are returned.
       */
      if( is_safe( ch, victim ) )
         return rNONE;


      if( victim->position > POS_STUNNED )
      {
         if( !victim->fighting )
            set_fighting( victim, ch );
         if( victim->fighting )
            victim->position = POS_FIGHTING;
      }

      if( victim->position > POS_STUNNED )
      {
         if( !ch->fighting )
            set_fighting( ch, victim );

         /*
          * If victim is charmed, ch might attack victim's master.
          */
         if( IS_NPC( ch )
             && npcvict
             && IS_AFFECTED( victim, AFF_CHARM )
             && victim->master && victim->master->in_room == ch->in_room && number_bits( 3 ) == 0 )
         {
            stop_fighting( ch, FALSE );
            retcode = multi_hit( ch, victim->master, TYPE_UNDEFINED );
            return retcode;
         }
      }

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

      /*
       * Inviso attacks ... not.
       */
      if( IS_AFFECTED( ch, AFF_INVISIBLE ) && ch->race != RACE_DEFEL )
      {
         affect_strip( ch, gsn_invis );
         affect_strip( ch, gsn_mass_invis );
         REMOVE_BIT( ch->affected_by, AFF_INVISIBLE );
         act( AT_MAGIC, "$n fades into existence.", ch, NULL, NULL, TO_ROOM );
      }

      /*
       * Take away Hide 
       */
      if( IS_AFFECTED( ch, AFF_HIDE ) )
         REMOVE_BIT( ch->affected_by, AFF_HIDE );
      /*
       * Damage modifiers.
       */
      if( IS_AFFECTED( victim, AFF_SANCTUARY ) )
         dam /= 2;

      if( IS_AFFECTED( victim, AFF_PROTECT ) && IS_EVIL( ch ) )
         dam -= ( int )( dam / 4 );

      if( dam < 0 )
         dam = 0;

      /*
       * Check for disarm, trip, parry, and dodge.
       */
      if( dt >= TYPE_HIT )
      {
         if( IS_NPC( ch ) && IS_SET( ch->attacks, DFND_DISARM ) && number_percent(  ) < ch->skill_level[COMBAT_ABILITY] / 2 )
            disarm( ch, victim );

         if( IS_NPC( ch ) && IS_SET( ch->attacks, ATCK_TRIP ) && number_percent(  ) < ch->skill_level[COMBAT_ABILITY] )
            trip( ch, victim );

         if( check_parry( ch, victim ) )
            return rNONE;
         if( check_dodge( ch, victim ) )
            return rNONE;
      }

      /*
       * Check control panel settings and modify damage
       */
      if( IS_NPC( ch ) )
      {
         if( npcvict )
            dampmod = sysdata.dam_mob_vs_mob;
         else
            dampmod = sysdata.dam_mob_vs_plr;
      }
      else
      {
         if( npcvict )
            dampmod = sysdata.dam_plr_vs_mob;
         else
            dampmod = sysdata.dam_plr_vs_plr;
      }
      if( dampmod > 0 )
         dam = ( dam * dampmod ) / 100;
   }

   /*
    * Code to handle equipment getting damaged, and also support  -Thoric
    * bonuses/penalties for having or not having equipment where hit
    */
   if( dam > 10 && dt != TYPE_UNDEFINED )
   {
      /*
       * get a random body eq part 
       */
      dameq = number_range( WEAR_LIGHT, WEAR_EYES );
      damobj = get_eq_char( victim, dameq );
      if( damobj )
      {
         if( dam > get_obj_resistance( damobj ) )
         {
            set_cur_obj( damobj );
            damage_obj( damobj );
         }
         dam -= 5;   /* add a bonus for having something to block the blow */
      }
      else
         dam += 5;   /* add penalty for bare skin! */
   }

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

   /*
    * Hurt the victim.
    * Inform the victim of his new state.
    */
   victim->hit -= dam;

   /*
    * Get experience based on % of damage done       -Thoric
    */
   if( dam && ch != victim && !IS_NPC( ch ) && ch->fighting && ch->fighting->xp )
   {
      xp_gain = ( int )( xp_compute( ch, victim ) * 0.1 * dam ) / victim->max_hit;
      gain_exp( ch, xp_gain, COMBAT_ABILITY );
   }

   if( !IS_NPC( victim ) && victim->top_level >= LEVEL_IMMORTAL && victim->hit < 1 )
      victim->hit = 1;

   /*
    * Make sure newbies dont die 
    */
   if( !IS_NPC( victim ) && NOT_AUTHED( victim ) && victim->hit < 1 )
      victim->hit = 1;

   if( dam > 0 && dt > TYPE_HIT
       && !IS_AFFECTED( victim, AFF_POISON )
       && is_wielding_poisoned( ch )
       && !IS_SET( victim->immune, RIS_POISON ) && !saves_poison_death( ch->skill_level[COMBAT_ABILITY], victim ) )
   {
      AFFECT_DATA af;

      af.type = gsn_poison;
      af.duration = 20;
      af.location = APPLY_STR;
      af.modifier = -2;
      af.bitvector = AFF_POISON;
      affect_join( victim, &af );
      victim->mental_state = URANGE( 20, victim->mental_state + 2, 100 );
   }

   if( !npcvict && get_trust( victim ) >= LEVEL_IMMORTAL && get_trust( ch ) >= LEVEL_IMMORTAL && victim->hit < 1 )
      victim->hit = 1;
   update_pos( victim );

   switch ( victim->position )
   {
      case POS_MORTAL:
         act( AT_DYING, "$n is mortally wounded, and will die soon, if not aided.", victim, NULL, NULL, TO_ROOM );
         send_to_char( "&RYou are mortally wounded, and will die soon, if not aided.", victim );
         break;

      case POS_INCAP:
         act( AT_DYING, "$n is incapacitated and will slowly die, if not aided.", victim, NULL, NULL, TO_ROOM );
         send_to_char( "&RYou are incapacitated and will slowly die, if not aided.", victim );
         break;

      case POS_STUNNED:
         if( !IS_AFFECTED( victim, AFF_PARALYSIS ) )
         {
            act( AT_ACTION, "$n is stunned, but will probably recover.", victim, NULL, NULL, TO_ROOM );
            send_to_char( "&RYou are stunned, but will probably recover.", victim );
         }
         break;

      case POS_DEAD:
         if( dt >= 0 && dt < top_sn )
         {
            SKILLTYPE *skill = skill_table[dt];

            if( skill->die_char && skill->die_char[0] != '\0' )
               act( AT_DEAD, skill->die_char, ch, NULL, victim, TO_CHAR );
            if( skill->die_vict && skill->die_vict[0] != '\0' )
               act( AT_DEAD, skill->die_vict, ch, NULL, victim, TO_VICT );
            if( skill->die_room && skill->die_room[0] != '\0' )
               act( AT_DEAD, skill->die_room, ch, NULL, victim, TO_NOTVICT );
         }
         if( IS_NPC( victim ) && IS_SET( victim->act, ACT_NOKILL ) )
            act( AT_YELLOW, "$n flees for $s life ... barely escaping certain death!", victim, 0, 0, TO_ROOM );
         else if( IS_NPC( victim ) && IS_SET( victim->act, ACT_DROID ) )
            act( AT_DEAD, "$n EXPLODES into many small pieces!", victim, 0, 0, TO_ROOM );
         else
            act( AT_DEAD, "$n is DEAD!", victim, 0, 0, TO_ROOM );
         send_to_char( "&WYou have been KILLED!\r\n", victim );
         break;

      default:
         if( dam > victim->max_hit / 4 )
         {
            act( AT_HURT, "That really did HURT!", victim, 0, 0, TO_CHAR );
            if( number_bits( 3 ) == 0 )
               worsen_mental_state( victim, 1 );
         }
         if( victim->hit < victim->max_hit / 4 )

         {
            act( AT_DANGER, "You wish that your wounds would stop BLEEDING so much!", victim, 0, 0, TO_CHAR );
            if( number_bits( 2 ) == 0 )
               worsen_mental_state( victim, 1 );
         }
         break;
   }

   /*
    * Sleep spells and extremely wounded folks.
    */
   if( !IS_AWAKE( victim ) /* lets make NPC's not slaughter PC's */
       && !IS_AFFECTED( victim, AFF_PARALYSIS ) )
   {
      if( victim->fighting && victim->fighting->who->hunting && victim->fighting->who->hunting->who == victim )
         stop_hunting( victim->fighting->who );

      if( victim->fighting && victim->fighting->who->hating && victim->fighting->who->hating->who == victim )
         stop_hating( victim->fighting->who );

      stop_fighting( victim, TRUE );
   }

   if( victim->hit <= 0 && !IS_NPC( victim ) )
   {
      OBJ_DATA *obj;
      OBJ_DATA *obj_next;
      int cnt = 0;

      REMOVE_BIT( victim->act, PLR_ATTACKER );

      stop_fighting( victim, TRUE );

      if( ( obj = get_eq_char( victim, WEAR_DUAL_WIELD ) ) != NULL )
         unequip_char( victim, obj );
      if( ( obj = get_eq_char( victim, WEAR_WIELD ) ) != NULL )
         unequip_char( victim, obj );
      if( ( obj = get_eq_char( victim, WEAR_HOLD ) ) != NULL )
         unequip_char( victim, obj );
      if( ( obj = get_eq_char( victim, WEAR_MISSILE_WIELD ) ) != NULL )
         unequip_char( victim, obj );
      if( ( obj = get_eq_char( victim, WEAR_LIGHT ) ) != NULL )
         unequip_char( victim, obj );

      for( obj = victim->first_carrying; obj; obj = obj_next )
      {
         obj_next = obj->next_content;

         if( obj->wear_loc == WEAR_NONE )
         {
            if( obj->pIndexData->progtypes & DROP_PROG && obj->count > 1 )
            {
               ++cnt;
               separate_obj( obj );
               obj_from_char( obj );
               if( !obj_next )
                  obj_next = victim->first_carrying;
            }
            else
            {
               cnt += obj->count;
               obj_from_char( obj );
            }
            act( AT_ACTION, "$n drops $p.", victim, obj, NULL, TO_ROOM );
            act( AT_ACTION, "You drop $p.", victim, obj, NULL, TO_CHAR );
            obj = obj_to_room( obj, victim->in_room );
         }
      }

      if( IS_NPC( ch ) && !IS_NPC( victim ) )
      {
         long lose_exp;
         lose_exp = UMAX( ( victim->experience[COMBAT_ABILITY] - exp_level( victim->skill_level[COMBAT_ABILITY] ) ), 0 );
         ch_printf( victim, "You lose %ld experience.\r\n", lose_exp );
         victim->experience[COMBAT_ABILITY] -= lose_exp;
      }

      add_timer( victim, TIMER_RECENTFIGHT, 100, NULL, 0 );

   }

   /*
    * Payoff for killing things.
    */
   if( victim->position == POS_DEAD )
   {
      CHAR_DATA *gch;
      OBJ_DATA *new_corpse;

      group_gain( ch, victim );

      if( !npcvict )
      {
         sprintf( log_buf, "%s killed by %s at %d",
                  victim->name, ( IS_NPC( ch ) ? ch->short_descr : ch->name ), victim->in_room->vnum );
         log_string( log_buf );
         to_channel( log_buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL );

      }
      else if( !IS_NPC( ch ) && IS_NPC( victim ) )   /* keep track of mob vnum killed */
      {
         add_kill( ch, victim );

         /*
          * Add to kill tracker for grouped chars, as well. -Halcyon
          */
         for( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
            if( is_same_group( gch, ch ) && !IS_NPC( gch ) && gch != ch )
               add_kill( gch, victim );
      }

      check_killer( ch, victim );

      if( !IS_NPC( victim ) || !IS_SET( victim->act, ACT_NOKILL ) )
         loot = legal_loot( ch, victim );
      else
         loot = FALSE;

      set_cur_char( victim );
      new_corpse = raw_kill( ch, victim );
      victim = NULL;

      if( !IS_NPC( ch ) && loot && new_corpse && new_corpse->item_type == ITEM_CORPSE_NPC
       && new_corpse->in_room == ch->in_room && can_see_obj( ch, new_corpse ) && ch->position > POS_SLEEPING )
      {
         /*
          * Autogold by Scryn 8/12 
          */
         if( IS_SET( ch->act, PLR_AUTOGOLD ) && !loot_coins_from_corpse( ch, new_corpse ) )
            return rBOTH_DIED;

         if( new_corpse && !obj_extracted(new_corpse) && new_corpse->in_room == ch->in_room
          && ch->position > POS_SLEEPING && can_see_obj( ch, new_corpse ) )
         {
            if( IS_SET( ch->act, PLR_AUTOLOOT ) )
               do_get( ch, "all corpse" );
            else
               do_look( ch, "in corpse" );
            if( !char_died(ch) && IS_SET( ch->act, PLR_AUTOSAC ) && !obj_extracted(new_corpse)
             && new_corpse->in_room == ch->in_room && ch->position > POS_SLEEPING
             && can_see_obj( ch, new_corpse ) )
               do_sacrifice( ch, "corpse" );
         }
      }

      if( IS_SET( sysdata.save_flags, SV_KILL ) )
         save_char_obj( ch );
      return rVICT_DIED;
   }

   if( victim == ch )
      return rNONE;

   /*
    * Take care of link dead people.
    */
   if( !npcvict && !victim->desc && !victim->switched )
   {
      if( number_range( 0, victim->wait ) == 0 )
      {
         do_flee( victim, "" );
         do_flee( victim, "" );
         do_flee( victim, "" );
         do_flee( victim, "" );
         do_flee( victim, "" );
         do_hail( victim, "" );
         do_quit( victim, "" );
         return rNONE;
      }
   }

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

   if( !npcvict && victim->hit > 0 && victim->hit <= victim->wimpy && victim->wait == 0 )
      do_flee( victim, "" );
   else if( !npcvict && IS_SET( victim->act, PLR_FLEE ) )
      do_flee( victim, "" );

   tail_chain(  );
   return rNONE;
}

bool is_safe( CHAR_DATA * ch, CHAR_DATA * victim )
{
   if( !victim )
      return FALSE;

   /*
    * Thx Josh! 
    */
   if( who_fighting( ch ) == ch )
      return FALSE;

   if( IS_SET( victim->in_room->room_flags, ROOM_SAFE ) )
   {
      set_char_color( AT_MAGIC, ch );
      send_to_char( "You'll have to do that elswhere.\r\n", ch );
      return TRUE;
   }

   if( get_trust( ch ) > LEVEL_HERO )
      return FALSE;

   if( IS_NPC( ch ) || IS_NPC( victim ) )
      return FALSE;


   return FALSE;

}

/* checks is_safe but without the output 
   cuts out imms and safe rooms as well 
   for info only */

bool is_safe_nm( CHAR_DATA * ch, CHAR_DATA * victim )
{
   return FALSE;
}


/*
 * just verify that a corpse looting is legal
 */
bool legal_loot( CHAR_DATA * ch, CHAR_DATA * victim )
{
   /*
    * pc's can now loot .. why not .. death is pretty final 
    */
   if( !IS_NPC( ch ) )
      return TRUE;
   /*
    * non-charmed mobs can loot anything 
    */
   if( IS_NPC( ch ) && !ch->master )
      return TRUE;

   return FALSE;
}

/*
see if an attack justifies a KILLER flag --- edited so that none do but can't 
murder a no pk person. --- edited again for planetary wanted flags -- well will be soon :p
 */

void check_killer( CHAR_DATA * ch, CHAR_DATA * victim )
{

   int x;

   /*
    * Charm-o-rama.
    */
   if( IS_SET( ch->affected_by, AFF_CHARM ) )
   {
      if( !ch->master )
      {
         char buf[MAX_STRING_LENGTH];

         sprintf( buf, "Check_killer: %s bad AFF_CHARM", IS_NPC( ch ) ? ch->short_descr : ch->name );
         bug( buf, 0 );
         affect_strip( ch, gsn_charm_person );
         REMOVE_BIT( ch->affected_by, AFF_CHARM );
         return;
      }

      /*
       * stop_follower( ch ); 
       */
      if( ch->master )
         check_killer( ch->master, victim );
   }

   if( IS_NPC( victim ) )
   {
      if( !IS_NPC( ch ) )
      {
         for( x = 0; x < 32; x++ )
         {
            if( IS_SET( victim->vip_flags, 1 << x ) )
            {
               SET_BIT( ch->pcdata->wanted_flags, 1 << x );
               ch_printf( ch, "&YYou are now wanted on %s.&w\r\n", planet_flags[x], victim->short_descr );
            }
         }
         if( ch->pcdata->clan )
            ch->pcdata->clan->mkills++;
         ch->pcdata->mkills++;
         ch->in_room->area->mkills++;
      }
      return;
   }

   if( !IS_NPC( ch ) && !IS_NPC( victim ) )
   {
      if( ch->pcdata->clan )
         ch->pcdata->clan->pkills++;
      ch->pcdata->pkills++;
      update_pos( victim );
      if( victim->pcdata->clan )
         victim->pcdata->clan->pdeaths++;
   }


   if( IS_NPC( ch ) )
      if( !IS_NPC( victim ) )
         victim->in_room->area->mdeaths++;

   return;
}



/*
 * Set position of a victim.
 */
void update_pos( CHAR_DATA * victim )
{
   if( !victim )
   {
      bug( "update_pos: null victim", 0 );
      return;
   }

   if( victim->hit > 0 )
   {
      if( victim->position <= POS_STUNNED )
         victim->position = POS_STANDING;
      if( IS_AFFECTED( victim, AFF_PARALYSIS ) )
         victim->position = POS_STUNNED;
      return;
   }

   if( IS_NPC( victim ) || victim->hit <= -500 )
   {
      if( victim->mount )
      {
         act( AT_ACTION, "$n falls from $N.", victim, NULL, victim->mount, TO_ROOM );
         REMOVE_BIT( victim->mount->act, ACT_MOUNTED );
         victim->mount = NULL;
      }
      victim->position = POS_DEAD;
      return;
   }

   if( victim->hit <= -400 )
      victim->position = POS_MORTAL;
   else if( victim->hit <= -200 )
      victim->position = POS_INCAP;
   else
      victim->position = POS_STUNNED;

   if( victim->position > POS_STUNNED && IS_AFFECTED( victim, AFF_PARALYSIS ) )
      victim->position = POS_STUNNED;

   if( victim->mount )
   {
      act( AT_ACTION, "$n falls unconscious from $N.", victim, NULL, victim->mount, TO_ROOM );
      REMOVE_BIT( victim->mount->act, ACT_MOUNTED );
      victim->mount = NULL;
   }
   return;
}


/*
 * Start fights.
 */
void set_fighting( CHAR_DATA * ch, CHAR_DATA * victim )
{
   FIGHT_DATA *fight;

   if( ch->fighting )
   {
      char buf[MAX_STRING_LENGTH];

      sprintf( buf, "Set_fighting: %s -> %s (already fighting %s)", ch->name, victim->name, ch->fighting->who->name );
      bug( buf, 0 );
      return;
   }

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

   /*
    * Limit attackers -Thoric 
    */
   if( victim->num_fighting > max_fight( victim ) )
   {
      send_to_char( "There are too many people fighting for you to join in.\r\n", ch );
      return;
   }

   CREATE( fight, FIGHT_DATA, 1 );
   fight->who = victim;
   fight->xp = ( int )xp_compute( ch, victim );
   fight->align = align_compute( ch, victim );
   if( !IS_NPC( ch ) && IS_NPC( victim ) )
      fight->timeskilled = times_killed( ch, victim );
   ch->num_fighting = 1;
   ch->fighting = fight;
   ch->position = POS_FIGHTING;
   victim->num_fighting++;
   if( victim->switched && IS_AFFECTED( victim->switched, AFF_POSSESS ) )
   {
      send_to_char( "You are disturbed!\r\n", victim->switched );
      do_return( victim->switched, "" );
   }
   return;
}


CHAR_DATA *who_fighting( CHAR_DATA * ch )
{
   if( !ch )
   {
      bug( "who_fighting: null ch", 0 );
      return NULL;
   }
   if( !ch->fighting )
      return NULL;
   return ch->fighting->who;
}

void free_fight( CHAR_DATA * ch )
{
   if( !ch )
   {
      bug( "Free_fight: null ch!", 0 );
      return;
   }
   if( ch->fighting )
   {
      if( !char_died( ch->fighting->who ) )
         --ch->fighting->who->num_fighting;
      DISPOSE( ch->fighting );
   }
   ch->fighting = NULL;
   if( ch->mount )
      ch->position = POS_MOUNTED;
   else
      ch->position = POS_STANDING;
   /*
    * Berserk wears off after combat. -- Altrag 
    */
   if( IS_AFFECTED( ch, AFF_BERSERK ) )
   {
      affect_strip( ch, gsn_berserk );
      set_char_color( AT_WEAROFF, ch );
      send_to_char( skill_table[gsn_berserk]->msg_off, ch );
      send_to_char( "\r\n", ch );
   }
   return;
}


/*
 * Stop fights.
 */
void stop_fighting( CHAR_DATA * ch, bool fBoth )
{
   CHAR_DATA *fch;

   free_fight( ch );
   update_pos( ch );

   if( !fBoth )   /* major short cut here by Thoric */
      return;

   for( fch = first_char; fch; fch = fch->next )
   {
      if( who_fighting( fch ) == ch )
      {
         free_fight( fch );
         update_pos( fch );
      }
   }
   return;
}

void death_cry( CHAR_DATA * ch )
{
   return;
}

OBJ_DATA *raw_kill( CHAR_DATA * ch, CHAR_DATA * victim )
{
   CHAR_DATA *victmp;
   OBJ_DATA *corpse_to_return;
   OBJ_DATA *obj, *obj_next;
   SHIP_DATA *ship;
   char buf[MAX_STRING_LENGTH];
   char buf2[MAX_STRING_LENGTH];
   char arg[MAX_STRING_LENGTH];

   if( !victim )
   {
      bug( "%s: null victim!", __FUNCTION__ );
      return NULL;
   }

   strcpy( arg, victim->name );

   stop_fighting( victim, TRUE );

   if( ch && !IS_NPC( ch ) && !IS_NPC( victim ) )
      claim_disintigration( ch, victim );

   /* Take care of polymorphed chars */
   if( IS_NPC( victim ) && IS_SET( victim->act, ACT_POLYMORPHED ) )
   {
      char_from_room( victim->desc->original );
      char_to_room( victim->desc->original, victim->in_room );
      victmp = victim->desc->original;
      do_revert( victim, "" );
      return raw_kill( ch, victmp );
   }

   if( victim->in_room && IS_NPC( victim ) && victim->vip_flags != 0 && victim->in_room->area
       && victim->in_room->area->planet )
   {
      victim->in_room->area->planet->population--;
      victim->in_room->area->planet->population = UMAX( victim->in_room->area->planet->population, 0 );
      victim->in_room->area->planet->pop_support -= ( float )( 1 + 1 / ( victim->in_room->area->planet->population + 1 ) );
      if( victim->in_room->area->planet->pop_support < -100 )
         victim->in_room->area->planet->pop_support = -100;
   }

   if( !IS_NPC( victim ) || !IS_SET( victim->act, ACT_NOKILL ) )
      mprog_death_trigger( ch, victim );
   if( char_died( victim ) )
      return NULL;

   if( !IS_NPC( victim ) || !IS_SET( victim->act, ACT_NOKILL ) )
      rprog_death_trigger( ch, victim );
   if( char_died( victim ) )
      return NULL;

   if( !IS_NPC( victim ) || ( !IS_SET( victim->act, ACT_NOKILL ) && !IS_SET( victim->act, ACT_NOCORPSE ) ) )
      corpse_to_return = make_corpse( victim, ch );
   else
   {
      for( obj = victim->last_carrying; obj; obj = obj_next )
      {
         obj_next = obj->prev_content;
         obj_from_char( obj );
         extract_obj( obj );
      }
   }

   if( IS_NPC( victim ) )
   {
      victim->pIndexData->killed++;
      extract_char( victim, TRUE );
      victim = NULL;
      return corpse_to_return;
   }

   set_char_color( AT_DIEMSG, victim );
   do_help( victim, "_DIEMSG_" );

   /* swreality chnages begin here */

   for( ship = first_ship; ship; ship = ship->next )
   {
      if( !str_cmp( ship->owner, victim->name ) )
      {
         STRFREE( ship->owner );
         ship->owner = STRALLOC( "" );
         STRFREE( ship->pilot );
         ship->pilot = STRALLOC( "" );
         STRFREE( ship->copilot );
         ship->copilot = STRALLOC( "" );

         save_ship( ship );
      }
   }

   if( victim->plr_home )
   {
      ROOM_INDEX_DATA *room = victim->plr_home;

      STRFREE( room->name );
      room->name = STRALLOC( "An Empty Apartment" );

      REMOVE_BIT( room->room_flags, ROOM_PLR_HOME );
      SET_BIT( room->room_flags, ROOM_EMPTY_HOME );

      fold_area( room->area, room->area->filename, FALSE );
   }

   if( victim->pcdata && victim->pcdata->clan )
   {
      if( !str_cmp( victim->name, victim->pcdata->clan->leader ) )
      {
         STRFREE( victim->pcdata->clan->leader );
         if( victim->pcdata->clan->number1 )
         {
            victim->pcdata->clan->leader = STRALLOC( victim->pcdata->clan->number1 );
            STRFREE( victim->pcdata->clan->number1 );
            victim->pcdata->clan->number1 = STRALLOC( "" );
         }
         else if( victim->pcdata->clan->number2 )
         {
            victim->pcdata->clan->leader = STRALLOC( victim->pcdata->clan->number2 );
            STRFREE( victim->pcdata->clan->number2 );
            victim->pcdata->clan->number2 = STRALLOC( "" );
         }
         else
            victim->pcdata->clan->leader = STRALLOC( "" );
      }

      if( !str_cmp( victim->name, victim->pcdata->clan->number1 ) )
      {
         STRFREE( victim->pcdata->clan->number1 );
         if( victim->pcdata->clan->number2 )
         {
            victim->pcdata->clan->number1 = STRALLOC( victim->pcdata->clan->number2 );
            STRFREE( victim->pcdata->clan->number2 );
            victim->pcdata->clan->number2 = STRALLOC( "" );
         }
         else
            victim->pcdata->clan->number1 = STRALLOC( "" );
      }

      if( !str_cmp( victim->name, victim->pcdata->clan->number2 ) )
      {
         STRFREE( victim->pcdata->clan->number2 );
         victim->pcdata->clan->number1 = STRALLOC( "" );
      }
      victim->pcdata->clan->members--;
   }

   if( !victim )
   {
      DESCRIPTOR_DATA *d;

      /*
       * Make sure they aren't halfway logged in. 
       */
      for( d = first_descriptor; d; d = d->next )
         if( ( victim = d->character ) && !IS_NPC( victim ) )
            break;
      if( d )
         close_socket( d, TRUE );
   }
   else
   {
      int x, y;

      quitting_char = victim;
      save_char_obj( victim );
      saving_char = NULL;
      extract_char( victim, TRUE );
      for( x = 0; x < MAX_WEAR; x++ )
         for( y = 0; y < MAX_LAYERS; y++ )
            save_equipment[x][y] = NULL;
   }

   sprintf( buf, "%s%c/%s", PLAYER_DIR, tolower( arg[0] ), capitalize( arg ) );
   sprintf( buf2, "%s%c/%s", BACKUP_DIR, tolower( arg[0] ), capitalize( arg ) );

   rename( buf, buf2 );

   sprintf( buf, "%s%c/%s.clone", PLAYER_DIR, tolower( arg[0] ), capitalize( arg ) );
   sprintf( buf2, "%s%c/%s", PLAYER_DIR, tolower( arg[0] ), capitalize( arg ) );

   rename( buf, buf2 );

   return corpse_to_return;
}

void group_gain( CHAR_DATA * ch, CHAR_DATA * victim )
{
   char buf[MAX_STRING_LENGTH];
   CHAR_DATA *gch, *gch_next;
   CHAR_DATA *lch;
   int xp;
   int members;

   /*
    * Monsters don't get kill xp's or alignment changes.
    * Dying of mortal wounds or poison doesn't give xp to anyone!
    */
   if( IS_NPC( ch ) || victim == ch )
      return;

   members = 0;

   for( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
   {
      if( is_same_group( gch, ch ) )
         members++;
   }

   if( members == 0 )
   {
      bug( "Group_gain: members.", members );
      members = 1;
   }

   lch = ch->leader ? ch->leader : ch;

   for( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
   {
      OBJ_DATA *obj;
      OBJ_DATA *obj_next;

      gch_next = gch->next_in_room;
      if( !is_same_group( gch, ch ) )
         continue;

      xp = ( int )( xp_compute( gch, victim ) / members );

      gch->alignment = align_compute( gch, victim );

      if( !IS_NPC( gch ) && IS_NPC( victim ) && gch->pcdata && gch->pcdata->clan
          && !str_cmp( gch->pcdata->clan->name, victim->mob_clan ) )
      {
         xp = 0;
         sprintf( buf, "You receive no experience for killing your organizations resources.\r\n" );
         send_to_char( buf, gch );
      }
      else
      {
         sprintf( buf, "You receive %d combat experience.\r\n", xp );
         send_to_char( buf, gch );
      }

      gain_exp( gch, xp, COMBAT_ABILITY );

      if( lch == gch && members > 1 )
      {
         xp =
            URANGE( members, xp * members,
                    ( exp_level( gch->skill_level[LEADERSHIP_ABILITY] + 1 ) -
                      exp_level( gch->skill_level[LEADERSHIP_ABILITY] ) / 10 ) );
         sprintf( buf, "You get %d leadership experience for leading your group to victory.\r\n", xp );
         send_to_char( buf, gch );
         gain_exp( gch, xp, LEADERSHIP_ABILITY );
      }


      for( obj = ch->first_carrying; obj; obj = obj_next )
      {
         obj_next = obj->next_content;
         if( obj->wear_loc == WEAR_NONE )
            continue;

         if( ( IS_OBJ_STAT( obj, ITEM_ANTI_EVIL ) && IS_EVIL( gch ) ) ||
             ( IS_OBJ_STAT( obj, ITEM_ANTI_GOOD ) && IS_GOOD( gch ) ) ||
             ( IS_OBJ_STAT( obj, ITEM_ANTI_NEUTRAL ) && IS_NEUTRAL( gch ) ) )
         {
            act( AT_MAGIC, "You are zapped by $p.", gch, obj, NULL, TO_CHAR );
            act( AT_MAGIC, "$n is zapped by $p.", gch, obj, NULL, TO_ROOM );

            obj_from_char( obj );
            obj = obj_to_room( obj, gch->in_room );
            oprog_zap_trigger( gch, obj );   /* mudprogs */
            if( char_died( gch ) )
               break;
         }
      }
   }

   return;
}


int align_compute( CHAR_DATA * gch, CHAR_DATA * victim )
{

/* never cared much for this system

    int align, newalign;

    align = gch->alignment - victim->alignment;

    if ( align >  500 )
	newalign  = UMIN( gch->alignment + (align-500)/4,  1000 );
    else
    if ( align < -500 )
	newalign  = UMAX( gch->alignment + (align+500)/4, -1000 );
    else
	newalign  = gch->alignment - (int) (gch->alignment / 4);
    
    return newalign;

make it simple instead */

   return URANGE( -1000, ( int )( gch->alignment - victim->alignment / 5 ), 1000 );

}


/*
 * Calculate how much XP gch should gain for killing victim
 * Lots of redesigning for new exp system by Thoric
 */
int xp_compute( CHAR_DATA * gch, CHAR_DATA * victim )
{
   int align;
   int xp;

   xp = ( get_exp_worth( victim )
          * URANGE( 1, ( victim->skill_level[COMBAT_ABILITY] - gch->skill_level[COMBAT_ABILITY] ) + 10, 20 ) ) / 10;
   align = gch->alignment - victim->alignment;

   /*
    * bonus for attacking opposite alignment 
    */
   if( align > 990 || align < -990 )
      xp = ( xp * 5 ) >> 2;
   else
      /*
       * penalty for good attacking same alignment 
       */
   if( gch->alignment > 300 && align < 250 )
      xp = ( xp * 3 ) >> 2;

   xp = number_range( ( xp * 3 ) >> 2, ( xp * 5 ) >> 2 );

   /*
    * reduce exp for killing the same mob repeatedly    -Thoric 
    */
   if( !IS_NPC( gch ) && IS_NPC( victim ) )
   {
      int times = times_killed( gch, victim );

      if( times >= 5 )
         xp = 0;
      else if( times )
         xp = ( xp * ( 5 - times ) ) / 5;
   }

   /*
    * new xp cap for swreality 
    */

   return URANGE( 1, xp,
                  ( exp_level( gch->skill_level[COMBAT_ABILITY] + 1 ) - exp_level( gch->skill_level[COMBAT_ABILITY] ) ) );
}

/*
 * Revamped by Thoric to be more realistic
 */
void dam_message( CHAR_DATA * ch, CHAR_DATA * victim, int dam, int dt )
{
   char buf1[256], buf2[256], buf3[256];
   const char *vs;
   const char *vp;
   const char *attack;
   char punct;
   int dampc;
   struct skill_type *skill = NULL;
   bool gcflag = FALSE;
   bool gvflag = FALSE;

   if( !dam )
      dampc = 0;
   else
      dampc = ( ( dam * 1000 ) / victim->max_hit ) + ( 50 - ( ( victim->hit * 50 ) / victim->max_hit ) );

   /*
    * 10 * percent               
    */
   if( dam == 0 )
   {
      vs = "miss";
      vp = "misses";
   }
   else if( dampc <= 5 )
   {
      vs = "barely scratch";
      vp = "barely scratches";
   }
   else if( dampc <= 10 )
   {
      vs = "scratch";
      vp = "scratches";
   }
   else if( dampc <= 20 )
   {
      vs = "nick";
      vp = "nicks";
   }
   else if( dampc <= 30 )
   {
      vs = "graze";
      vp = "grazes";
   }
   else if( dampc <= 40 )
   {
      vs = "bruise";
      vp = "bruises";
   }
   else if( dampc <= 50 )
   {
      vs = "hit";
      vp = "hits";
   }
   else if( dampc <= 60 )
   {
      vs = "injure";
      vp = "injures";
   }
   else if( dampc <= 75 )
   {
      vs = "thrash";
      vp = "thrashes";
   }
   else if( dampc <= 80 )
   {
      vs = "wound";
      vp = "wounds";
   }
   else if( dampc <= 90 )
   {
      vs = "maul";
      vp = "mauls";
   }
   else if( dampc <= 125 )
   {
      vs = "decimate";
      vp = "decimates";
   }
   else if( dampc <= 150 )
   {
      vs = "devastate";
      vp = "devastates";
   }
   else if( dampc <= 200 )
   {
      vs = "maim";
      vp = "maims";
   }
   else if( dampc <= 300 )
   {
      vs = "MUTILATE";
      vp = "MUTILATES";
   }
   else if( dampc <= 400 )
   {
      vs = "DISEMBOWEL";
      vp = "DISEMBOWELS";
   }
   else if( dampc <= 500 )
   {
      vs = "MASSACRE";
      vp = "MASSACRES";
   }
   else if( dampc <= 600 )
   {
      vs = "PULVERIZE";
      vp = "PULVERIZES";
   }
   else if( dampc <= 750 )
   {
      vs = "EVISCERATE";
      vp = "EVISCERATES";
   }
   else if( dampc <= 990 )
   {
      vs = "* OBLITERATE *";
      vp = "* OBLITERATES *";
   }
   else
   {
      vs = "*** ANNIHILATE ***";
      vp = "*** ANNIHILATES ***";
   }

   punct = ( dampc <= 30 ) ? '.' : '!';

   if( dam == 0 && ( !IS_NPC( ch ) && ( IS_SET( ch->pcdata->flags, PCFLAG_GAG ) ) ) )
      gcflag = TRUE;

   if( dam == 0 && ( !IS_NPC( victim ) && ( IS_SET( victim->pcdata->flags, PCFLAG_GAG ) ) ) )
      gvflag = TRUE;

   if( dt >= 0 && dt < top_sn )
      skill = skill_table[dt];

   if( dt == ( TYPE_HIT + WEAPON_BLASTER ) )
   {
      char sound[MAX_STRING_LENGTH];
      int vol = number_range( 20, 80 );

      sprintf( sound, "!!SOUND(blaster V=%d)", vol );
      sound_to_room( ch->in_room, sound );
   }

   if( dt == TYPE_HIT || dam == 0 )
   {
      sprintf( buf1, "$n %s $N%c", vp, punct );
      sprintf( buf2, "You %s $N%c", vs, punct );
      sprintf( buf3, "$n %s you%c", vp, punct );
   }
   else if( dt > TYPE_HIT && is_wielding_poisoned( ch ) )
   {
      if( dt < TYPE_HIT + sizeof( attack_table ) / sizeof( attack_table[0] ) )
         attack = attack_table[dt - TYPE_HIT];
      else
      {
         bug( "Dam_message: bad dt %d.", dt );
         dt = TYPE_HIT;
         attack = attack_table[0];
      }

      sprintf( buf1, "$n's poisoned %s %s $N%c", attack, vp, punct );
      sprintf( buf2, "Your poisoned %s %s $N%c", attack, vp, punct );
      sprintf( buf3, "$n's poisoned %s %s you%c", attack, vp, punct );
   }
   else
   {
      if( skill )
      {
         attack = skill->noun_damage;
         if( dam == 0 )
         {
            bool found = FALSE;

            if( skill->miss_char && skill->miss_char[0] != '\0' )
            {
               act( AT_HIT, skill->miss_char, ch, NULL, victim, TO_CHAR );
               found = TRUE;
            }
            if( skill->miss_vict && skill->miss_vict[0] != '\0' )
            {
               act( AT_HITME, skill->miss_vict, ch, NULL, victim, TO_VICT );
               found = TRUE;
            }
            if( skill->miss_room && skill->miss_room[0] != '\0' )
            {
               act( AT_ACTION, skill->miss_room, ch, NULL, victim, TO_NOTVICT );
               found = TRUE;
            }
            if( found ) /* miss message already sent */
               return;
         }
         else
         {
            if( skill->hit_char && skill->hit_char[0] != '\0' )
               act( AT_HIT, skill->hit_char, ch, NULL, victim, TO_CHAR );
            if( skill->hit_vict && skill->hit_vict[0] != '\0' )
               act( AT_HITME, skill->hit_vict, ch, NULL, victim, TO_VICT );
            if( skill->hit_room && skill->hit_room[0] != '\0' )
               act( AT_ACTION, skill->hit_room, ch, NULL, victim, TO_NOTVICT );
         }
      }
      else if( dt >= TYPE_HIT && dt < TYPE_HIT + sizeof( attack_table ) / sizeof( attack_table[0] ) )
         attack = attack_table[dt - TYPE_HIT];
      else
      {
         bug( "Dam_message: bad dt %d.", dt );
         dt = TYPE_HIT;
         attack = attack_table[0];
      }

      sprintf( buf1, "$n's %s %s $N%c", attack, vp, punct );
      sprintf( buf2, "Your %s %s $N%c", attack, vp, punct );
      sprintf( buf3, "$n's %s %s you%c", attack, vp, punct );
   }

   if( ch->skill_level[COMBAT_ABILITY] >= 100 )
      sprintf( buf2, "%s You do %d points of damage.", buf2, dam );

   act( AT_ACTION, buf1, ch, NULL, victim, TO_NOTVICT );
   if( !gcflag )
      act( AT_HIT, buf2, ch, NULL, victim, TO_CHAR );
   if( !gvflag )
      act( AT_HITME, buf3, ch, NULL, victim, TO_VICT );

   return;
}


void do_kill( CHAR_DATA * ch, char *argument )
{
   char arg[MAX_INPUT_LENGTH];
   CHAR_DATA *victim;

   one_argument( argument, arg );

   if( arg[0] == '\0' )
   {
      send_to_char( "Kill whom?\r\n", ch );
      return;
   }

   if( ( victim = get_char_room( ch, arg ) ) == NULL )
   {
      send_to_char( "They aren't here.\r\n", ch );
      return;
   }

   if( !IS_NPC( victim ) )
   {
      send_to_char( "You must MURDER a player.\r\n", ch );
      return;
   }

   /*
    *
    else
    {
    if ( IS_AFFECTED(victim, AFF_CHARM) && victim->master != NULL )
    {
    send_to_char( "You must MURDER a charmed creature.\r\n", ch );
    return;
    }
    }
    *
    */

   if( victim == ch )
   {
      send_to_char( "You hit yourself.  Ouch!\r\n", ch );
      multi_hit( ch, ch, TYPE_UNDEFINED );
      return;
   }

   if( is_safe( ch, victim ) )
      return;

   if( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim )
   {
      act( AT_PLAIN, "$N is your beloved master.", ch, NULL, victim, TO_CHAR );
      return;
   }

   if( ch->position == POS_FIGHTING )
   {
      send_to_char( "You do the best you can!\r\n", ch );
      return;
   }

   if( victim->vip_flags != 0 )
      ch->alignment -= 10;

   WAIT_STATE( ch, 1 * PULSE_VIOLENCE );
   multi_hit( ch, victim, TYPE_UNDEFINED );
   return;
}

void do_murde( CHAR_DATA * ch, char *argument )
{
   send_to_char( "If you want to MURDER, spell it out.\r\n", ch );
   return;
}

void do_murder( CHAR_DATA * ch, char *argument )
{
   char arg[MAX_INPUT_LENGTH];
   CHAR_DATA *victim;

   one_argument( argument, arg );

   if( arg[0] == '\0' )
   {
      send_to_char( "Murder whom?\r\n", ch );
      return;
   }

   if( ( victim = get_char_room( ch, arg ) ) == NULL )
   {
      send_to_char( "They aren't here.\r\n", ch );
      return;
   }

   if( victim == ch )
   {
      send_to_char( "Suicide is a mortal sin.\r\n", ch );
      return;
   }

   if( is_safe( ch, victim ) )
      return;

   if( IS_AFFECTED( ch, AFF_CHARM ) )
   {
      if( ch->master == victim )
      {
         act( AT_PLAIN, "$N is your beloved master.", ch, NULL, victim, TO_CHAR );
         return;
      }
   }

   if( ch->position == POS_FIGHTING )
   {
      send_to_char( "You do the best you can!\r\n", ch );
      return;
   }

   if( !IS_NPC( victim ) && IS_SET( ch->act, PLR_NICE ) )
   {
      send_to_char( "You feel too nice to do that!\r\n", ch );
      return;
   }

   ch->alignment = URANGE( -1000, ch->alignment - 10, 1000 );

   WAIT_STATE( ch, 1 * PULSE_VIOLENCE );
   multi_hit( ch, victim, TYPE_UNDEFINED );
   return;
}

bool in_arena( CHAR_DATA * ch )
{

   if( !str_cmp( ch->in_room->area->filename, "arena.are" ) )
      return TRUE;

   if( ch->in_room->vnum < 29 || ch->in_room->vnum > 43 )
      return FALSE;

   return TRUE;
}


void do_flee( CHAR_DATA * ch, char *argument )
{
   ROOM_INDEX_DATA *was_in;
   ROOM_INDEX_DATA *now_in;
   char buf[MAX_STRING_LENGTH];
   int attempt;
   short door;
   EXIT_DATA *pexit;

   if( !who_fighting( ch ) )
   {
      if( ch->position == POS_FIGHTING )
      {
         if( ch->mount )
            ch->position = POS_MOUNTED;
         else
            ch->position = POS_STANDING;
      }
      send_to_char( "You aren't fighting anyone.\r\n", ch );
      return;
   }

   if( ch->move <= 0 )
   {
      send_to_char( "You're too exhausted to flee from combat!\r\n", ch );
      return;
   }

   /*
    * No fleeing while stunned. - Narn 
    */
   if( ch->position < POS_FIGHTING )
      return;

   was_in = ch->in_room;
   for( attempt = 0; attempt < 8; attempt++ )
   {

      door = number_door(  );
      if( ( pexit = get_exit( was_in, door ) ) == NULL
          || !pexit->to_room
          || ( IS_SET( pexit->exit_info, EX_CLOSED )
               && !IS_AFFECTED( ch, AFF_PASS_DOOR ) )
          || ( IS_NPC( ch ) && IS_SET( pexit->to_room->room_flags, ROOM_NO_MOB ) ) )
         continue;

      affect_strip( ch, gsn_sneak );
      REMOVE_BIT( ch->affected_by, AFF_SNEAK );
      if( ch->mount && ch->mount->fighting )
         stop_fighting( ch->mount, TRUE );
      move_char( ch, pexit, 0 );
      if( ( now_in = ch->in_room ) == was_in )
         continue;

      ch->in_room = was_in;
      act( AT_FLEE, "$n runs for cover!", ch, NULL, NULL, TO_ROOM );
      ch->in_room = now_in;
      act( AT_FLEE, "$n glances around for signs of pursuit.", ch, NULL, NULL, TO_ROOM );
      sprintf( buf, "You run for cover!" );
      send_to_char( buf, ch );

      stop_fighting( ch, TRUE );
      return;
   }

   sprintf( buf, "You attempt to run for cover!" );
   send_to_char( buf, ch );
   return;
}

bool get_cover( CHAR_DATA * ch )
{
   ROOM_INDEX_DATA *was_in;
   ROOM_INDEX_DATA *now_in;
   int attempt;
   short door;
   EXIT_DATA *pexit;

   if( !who_fighting( ch ) )
      return FALSE;

   if( ch->position < POS_FIGHTING )
      return FALSE;

   was_in = ch->in_room;
   for( attempt = 0; attempt < 10; attempt++ )
   {

      door = number_door(  );
      if( ( pexit = get_exit( was_in, door ) ) == NULL
          || !pexit->to_room
          || ( IS_SET( pexit->exit_info, EX_CLOSED )
               && !IS_AFFECTED( ch, AFF_PASS_DOOR ) )
          || ( IS_NPC( ch ) && IS_SET( pexit->to_room->room_flags, ROOM_NO_MOB ) ) )
         continue;

      affect_strip( ch, gsn_sneak );
      REMOVE_BIT( ch->affected_by, AFF_SNEAK );
      if( ch->mount && ch->mount->fighting )
         stop_fighting( ch->mount, TRUE );
      move_char( ch, pexit, 0 );
      if( ( now_in = ch->in_room ) == was_in )
         continue;

      ch->in_room = was_in;
      act( AT_FLEE, "$n sprints for cover!", ch, NULL, NULL, TO_ROOM );
      ch->in_room = now_in;
      act( AT_FLEE, "$n spins around and takes aim.", ch, NULL, NULL, TO_ROOM );

      stop_fighting( ch, TRUE );

      return TRUE;
   }

   return FALSE;
}



void do_sla( CHAR_DATA * ch, char *argument )
{
   send_to_char( "If you want to SLAY, spell it out.\r\n", ch );
   return;
}



void do_slay( CHAR_DATA * ch, char *argument )
{
   CHAR_DATA *victim;
   char arg[MAX_INPUT_LENGTH];
   char arg2[MAX_INPUT_LENGTH];

   argument = one_argument( argument, arg );
   one_argument( argument, arg2 );
   if( arg[0] == '\0' )
   {
      send_to_char( "Slay whom?\r\n", ch );
      return;
   }

   if( ( victim = get_char_room( ch, arg ) ) == NULL )
   {
      send_to_char( "They aren't here.\r\n", ch );
      return;
   }

   if( ch == victim )
   {
      send_to_char( "Suicide is a mortal sin.\r\n", ch );
      return;
   }

   if( !IS_NPC( victim ) && ( get_trust( victim ) == 103 || get_trust( ch ) < 103 ) )
   {
      send_to_char( "You failed.\r\n", ch );
      return;
   }

   if( !str_cmp( arg2, "immolate" ) )
   {
      act( AT_FIRE, "Your fireball turns $N into a blazing inferno.", ch, NULL, victim, TO_CHAR );
      act( AT_FIRE, "$n releases a searing fireball in your direction.", ch, NULL, victim, TO_VICT );
      act( AT_FIRE, "$n points at $N, who bursts into a flaming inferno.", ch, NULL, victim, TO_NOTVICT );
   }

   else if( !str_cmp( arg2, "shatter" ) )
   {
      act( AT_LBLUE, "You freeze $N with a glance and shatter the frozen corpse into tiny shards.", ch, NULL, victim,
           TO_CHAR );
      act( AT_LBLUE, "$n freezes you with a glance and shatters your frozen body into tiny shards.", ch, NULL, victim,
           TO_VICT );
      act( AT_LBLUE, "$n freezes $N with a glance and shatters the frozen body into tiny shards.", ch, NULL, victim,
           TO_NOTVICT );
   }

   else if( !str_cmp( arg2, "demon" ) )
   {
      act( AT_IMMORT, "You gesture, and a slavering demon appears.  With a horrible grin, the", ch, NULL, victim, TO_CHAR );
      act( AT_IMMORT, "foul creature turns on $N, who screams in panic before being eaten alive.", ch, NULL, victim,
           TO_CHAR );
      act( AT_IMMORT, "$n gestures, and a slavering demon appears.  The foul creature turns on", ch, NULL, victim, TO_VICT );
      act( AT_IMMORT, "you with a horrible grin.   You scream in panic before being eaten alive.", ch, NULL, victim,
           TO_VICT );
      act( AT_IMMORT, "$n gestures, and a slavering demon appears.  With a horrible grin, the", ch, NULL, victim,
           TO_NOTVICT );
      act( AT_IMMORT, "foul creature turns on $N, who screams in panic before being eaten alive.", ch, NULL, victim,
           TO_NOTVICT );
   }

   else if( !str_cmp( arg2, "pounce" ) && get_trust( ch ) >= LEVEL_ASCENDANT )
   {
      act( AT_BLOOD, "Leaping upon $N with bared fangs, you tear open $S throat and toss the corpse to the ground...", ch,
           NULL, victim, TO_CHAR );
      act( AT_BLOOD,
           "In a heartbeat, $n rips $s fangs through your throat!  Your blood sprays and pours to the ground as your life ends...",
           ch, NULL, victim, TO_VICT );
      act( AT_BLOOD,
           "Leaping suddenly, $n sinks $s fangs into $N's throat.  As blood sprays and gushes to the ground, $n tosses $N's dying body away.",
           ch, NULL, victim, TO_NOTVICT );
   }

   else if( !str_cmp( arg2, "slit" ) && get_trust( ch ) >= LEVEL_ASCENDANT )
   {
      act( AT_BLOOD, "You calmly slit $N's throat.", ch, NULL, victim, TO_CHAR );
      act( AT_BLOOD, "$n reaches out with a clawed finger and calmly slits your throat.", ch, NULL, victim, TO_VICT );
      act( AT_BLOOD, "$n calmly slits $N's throat.", ch, NULL, victim, TO_NOTVICT );
   }

   else
   {
      act( AT_IMMORT, "You slay $N in cold blood!", ch, NULL, victim, TO_CHAR );
      act( AT_IMMORT, "$n slays you in cold blood!", ch, NULL, victim, TO_VICT );
      act( AT_IMMORT, "$n slays $N in cold blood!", ch, NULL, victim, TO_NOTVICT );
   }

   set_cur_char( victim );
   raw_kill( ch, victim );
   return;
}