dotd-2.3.7/area/
dotd-2.3.7/clans/
dotd-2.3.7/classes/
dotd-2.3.7/councils/
dotd-2.3.7/deity/
dotd-2.3.7/dict/
dotd-2.3.7/doc/mudprogs/
dotd-2.3.7/player/a/
dotd-2.3.7/player/g/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.0 (C) 1994, 1995, 1996 by Derek Snider             |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh and Tricops  |~'~.VxvxV.~'~*
 * ------------------------------------------------------------------------ *
 * 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			    *
 ****************************************************************************/

/*static char rcsid[] = "$Id: fight.c,v 1.103 2004/04/06 22:00:09 dotd Exp $";*/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"
#include "gsn.h"
#include "quest.h"

DECLARE_DO_FUN(do_shout);
DECLARE_DO_FUN(do_bash);
DECLARE_DO_FUN(do_stun);
DECLARE_DO_FUN(do_gouge);
DECLARE_DO_FUN(do_bite);
DECLARE_DO_FUN(do_claw);
DECLARE_DO_FUN(do_tail);
DECLARE_DO_FUN(do_sting);
DECLARE_DO_FUN(do_punch);
DECLARE_DO_FUN(do_kick);
DECLARE_DO_FUN(do_get);
DECLARE_DO_FUN(do_split);
DECLARE_DO_FUN(do_look);
DECLARE_DO_FUN(do_sacrifice);
DECLARE_DO_FUN(do_recall);
DECLARE_DO_FUN(do_flee);
DECLARE_DO_FUN(do_return);
DECLARE_DO_FUN(do_revert);
DECLARE_DO_FUN(do_help);
DECLARE_DO_FUN(do_variables);

DECLARE_SPELL_FUN(spell_energy_drain);
DECLARE_SPELL_FUN(spell_fire_breath);
DECLARE_SPELL_FUN(spell_frost_breath);
DECLARE_SPELL_FUN(spell_acid_breath);
DECLARE_SPELL_FUN(spell_gas_breath);
DECLARE_SPELL_FUN(spell_lightning_breath);
DECLARE_SPELL_FUN(spell_blindness);
DECLARE_SPELL_FUN(spell_cause_serious);
DECLARE_SPELL_FUN(spell_curse);
DECLARE_SPELL_FUN(spell_flamestrike);
DECLARE_SPELL_FUN(spell_harm);
DECLARE_SPELL_FUN(spell_fireball);
DECLARE_SPELL_FUN(spell_colour_spray);
DECLARE_SPELL_FUN(spell_weaken);
DECLARE_SPELL_FUN(spell_dispel_magic);
DECLARE_SPELL_FUN(spell_dispel_evil);
DECLARE_SPELL_FUN(spell_poison);
DECLARE_SPELL_FUN(spell_earthquake);

extern char		lastplayercmd[MAX_INPUT_LENGTH*2];
extern CHAR_DATA *	gch_prev;
extern const sh_int backstab_mult[MAX_LEVEL+1];
extern const int thaco[REAL_MAX_CLASS][111];

/*
 * Local functions.
 */
static void	dam_message	args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dam,
                                        int dt ) );
static void	group_gain	args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
static int	align_compute	args( ( CHAR_DATA *gch, CHAR_DATA *victim ) );
static void	align_zap	args( ( CHAR_DATA *ch ) );
static int	obj_hitroll	args( ( OBJ_DATA *obj ) );
int             berserkdambonus args( ( CHAR_DATA *ch, int dam ) );
int             BarbarianToHitMagicBonus args( ( CHAR_DATA *ch ) );
bool     life_protection_object args( ( CHAR_DATA *ch ) );
bool	dual_flip = FALSE;


/*
 * Check to see if weapon is poisoned.
 */
static 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;
    ch->hunting->start_time = current_time;
    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;
    ch->hating->start_time = current_time;
    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;
    ch->fearing->start_time = current_time;
    return;
}

int get_dam_by_race( CHAR_DATA *ch )
{
    int num;

    num = number_percent();
    switch(GET_RACE(ch)) {
    case RACE_REPTILE:
        if (num <= 50) {
            return(DAM_CLAW);
        } else {
            return(DAM_BITE);
        }
        break;
    case RACE_LYCANTH:
    case RACE_DRAGON:
    case RACE_DRAGON_RED    :
    case RACE_DRAGON_BLACK  :
    case RACE_DRAGON_GREEN  :
    case RACE_DRAGON_WHITE  :
    case RACE_DRAGON_BLUE   :
    case RACE_DRAGON_SILVER :
    case RACE_DRAGON_GOLD   :
    case RACE_DRAGON_BRONZE :
    case RACE_DRAGON_COPPER :
    case RACE_DRAGON_BRASS  :
    case RACE_PREDATOR:
    case RACE_LABRAT:
        if (num <= 33) {
            return(DAM_BITE);
        } else {
            return(DAM_CLAW);
        }
        break;
    case RACE_INSECT:
        if (num <= 50) {
            return(DAM_BITE);
        } else {
            return(DAM_STING);
        }
        break;
    case RACE_ARACHNID:
    case RACE_DINOSAUR:
    case RACE_FISH:
    case RACE_SNAKE:
        return(DAM_BITE);
        break;
    case RACE_BIRD:
    case RACE_SKEXIE:
        return(DAM_CLAW);
        break;
    case RACE_GIANT:
    case RACE_GIANT_HILL   :
    case RACE_GIANT_FROST  :
    case RACE_GIANT_FIRE   :
    case RACE_GIANT_CLOUD  :
    case RACE_GIANT_STORM  :
    case RACE_GIANT_STONE  :
    case RACE_GOLEM:
        return(DAM_POUND);
        break;
    case RACE_DEMON:
    case RACE_DEVIL:
    case RACE_TROLL:
    case RACE_TROGMAN:
    case RACE_LIZARDMAN:
        return(DAM_CLAW);
        break;
    case RACE_TREE:
        return(DAM_SMASH);
        break;
    case RACE_MFLAYER:
        if (num <= 60) {
            return(DAM_WHIP);
        } else if (num < 80) {
            return(DAM_BITE);
        } else {
            return(DAM_HIT);
        }
        break;
    case RACE_PRIMATE:
        if (num <= 70) {
            return(DAM_HIT);
        } else {
            return(DAM_BITE);
        }
        break;
    case RACE_TYTAN:
        return(DAM_BLAST);
        break;
    default:
        return(DAM_HIT);
    }


}

/*
 * Get the current armor class for a vampire based on time of day
 */
sh_int VAMP_AC( CHAR_DATA * ch )
{
    if ( IS_VAMPIRE( ch ) || IS_OUTSIDE( ch ) )
    {
        switch(time_info.sunlight)
        {
        case SUN_DARK:
            return -8;
        case SUN_RISE:
            return 5;
        case SUN_LIGHT:
            return 10;
        case SUN_SET:
            return 2;
        default:
            return 0;
        }
    }
    else
        return 0;
}

/*
 * 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_DATA *ch;
    CHAR_DATA *lst_ch;
    CHAR_DATA *victim;
    CHAR_DATA *rch, *rch_next;
    TIMER	*timer, *timer_next;
    ch_ret     retcode;
    int	       x, attacktype = 0, cnt;

    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..." );
            ch->prev = NULL;
        }

        gch_prev	= ch->prev;

        if ( gch_prev && gch_prev->next != ch )
        {
	    bug( "FATAL: violence_update: %s->prev->next doesn't point to ch.", GET_NAME(ch) );
            bug( "Short-cutting here" );
            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_plus( "violence_update: bad ch record!  (Shortcutting.)", LOG_NORMAL, LEVEL_LOG_CSET, SEV_ALERT );
            sprintf( log_buf, "ch: %d  ch->in_room: %d  ch->prev: %d  ch->next: %d",
                     (int) ch, (int) ch->in_room, (int) ch->prev, (int) ch->next );
            log_string_plus( log_buf, LOG_NORMAL, LEVEL_LOG_CSET, SEV_ALERT );
            log_string_plus( lastplayercmd, LOG_NORMAL, LEVEL_LOG_CSET, SEV_ALERT );
            if ( lst_ch )
                sprintf( log_buf, "lst_ch: %d  lst_ch->prev: %d  lst_ch->next: %d",
                         (int) lst_ch, (int) lst_ch->prev, (int) lst_ch->next );
            else
                strcpy( log_buf, "lst_ch: NULL" );
            log_string_plus( log_buf, LOG_NORMAL, LEVEL_LOG_CSET, SEV_ALERT );
            gch_prev = NULL;
            continue;
        }

        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;
                }
                if ( timer->count <= 0 )
                    extract_timer( ch, timer );
            }
        }

        if ( char_died(ch) )
            continue;

        /* Spell wearing-off used to be here -Jesse 8-22-97 */

        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( log_buf, "violence_update: %s fighting %s in a SAFE room.",
                     ch->name, victim->name );
            log_string_plus( log_buf, LOG_BUG, LEVEL_LOG_CSET, SEV_ERR );
            stop_fighting( ch, TRUE );
            continue;
        }

        if ( IS_AWAKE(ch) && ch->in_room == victim->in_room )
            retcode = multi_hit( ch, victim, TYPE_UNDEFINED );
        else
            stop_fighting( ch, FALSE );

        if ( retcode == rCHAR_DIED || char_died(ch) )
            continue;

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

        /*
         * Violence triggered specs
         */
        if ( ch->spec_fun && sysdata.specials_enabled==TRUE )
        {
            (*ch->spec_fun) ( ch, NULL, "", victim, SFT_VIO_UPDATE );

            if ( char_died(ch) )
                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;
        if ( get_eq_char(ch, WEAR_WIELD) )
        {
            oprog_fight_trigger( ch, get_eq_char(ch, WEAR_WIELD), victim );
            if ( char_died(ch) )
                continue;
        }
        if ( get_eq_char(ch, WEAR_DUAL_WIELD) )
        {
            oprog_fight_trigger( ch, get_eq_char(ch, WEAR_DUAL_WIELD), victim );
            if ( char_died(ch) )
                continue;
        }

        /*
         * NPC special attack flags				-Thoric
         */
        if ( IS_NPC(ch) )
        {
            cnt = 0;
            if ( ch->attacks )
                for ( ;; )
                {
                    if ( cnt++ > 10 )
                    {
                        attacktype = 0;
                        break;
                    }
                    x = number_range( 7, 31 );
                    attacktype = 1 << x;
                    if ( IS_SET( ch->attacks, attacktype ) )
                        break;
                }

            if ( 30 + (GetAveLevel(ch)/4) < number_percent( ) )
                attacktype = 0;
            switch( attacktype )
            {
            case ATCK_BASH:
                do_bash( ch, "" );
                retcode = global_retcode;
                break;
            case ATCK_STUN:
                do_stun( ch, "" );
                retcode = global_retcode;
                break;
            case ATCK_GOUGE:
                do_gouge( ch, "" );
                retcode = global_retcode;
                break;
            case ATCK_FEED:
                do_gouge( ch, "" );
                retcode = global_retcode;
                break;
            case ATCK_DRAIN:
                retcode = spell_energy_drain( gsn_energy_drain,
                                              BestSkLv(ch, gsn_energy_drain), ch, victim );
                break;
            case ATCK_FIREBREATH:
                retcode = spell_fire_breath( skill_lookup( "breath of fire" ),
                                             BestSkLv(ch, skill_lookup("breath of fire")), ch, victim );
                break;
            case ATCK_FROSTBREATH:
                retcode = spell_frost_breath( skill_lookup( "breath of frost" ),
                                              BestSkLv(ch, skill_lookup("breath of frost")), ch, victim );
                break;
            case ATCK_ACIDBREATH:
                retcode = spell_acid_breath( skill_lookup( "breath of acid" ),
                                             BestSkLv(ch, skill_lookup("breath of acid")), ch, victim );
                break;
            case ATCK_LIGHTNBREATH:
                retcode = spell_lightning_breath( skill_lookup( "breath of lightning" ),
                                                  BestSkLv(ch, skill_lookup("breath of lightning")), ch, victim );
                break;
            case ATCK_GASBREATH:
                retcode = spell_gas_breath( skill_lookup( "breath of gas" ),
                                            BestSkLv(ch, skill_lookup("breath of gas")), ch, victim );
                break;
            case ATCK_SPIRALBLAST:
                break;
            case ATCK_POISON:
                retcode = spell_poison( gsn_poison, BestSkLv(ch, gsn_poison), ch, victim );
                break;
            case ATCK_NASTYPOISON:
                break;
            case ATCK_GAZE:
                break;
            case ATCK_BLINDNESS:
                retcode = spell_blindness( gsn_blindness,
                                           BestSkLv(ch, gsn_blindness), ch, victim );
                break;
            case ATCK_CAUSESERIOUS:
                /*
                 retcode = spell_cause_serious( gsn_cause_serious,
                 BestSkLv(ch, gsn_cause_serious), ch, victim );
                 */
                break;
            case ATCK_EARTHQUAKE:
                retcode = spell_earthquake( gsn_earthquake,
                                            BestSkLv(ch, gsn_earthquake), ch, victim );
                break;
            case ATCK_CAUSECRITICAL:
                /*
                 retcode = spell_cause_critical( gsn_cause_critical,
                 BestSkLv(ch, gsn_cause_critical), ch, victim );
                 */
                break;
            case ATCK_CURSE:
                retcode = spell_curse( gsn_curse,
                                       BestSkLv(ch, gsn_curse), ch, victim );
                break;
            case ATCK_FLAMESTRIKE:
                retcode = spell_flamestrike( gsn_flamestrike,
                                             BestSkLv(ch, gsn_flamestrike), ch, victim );
                break;
            case ATCK_HARM:
                retcode = spell_harm( gsn_harm,
                                      BestSkLv(ch, gsn_harm), ch, victim );
                break;
            case ATCK_FIREBALL:
                retcode = spell_fireball( gsn_fireball,
                                          BestSkLv(ch, gsn_fireball), ch, victim );
                break;
            case ATCK_COLORSPRAY:
                retcode = spell_colour_spray( gsn_colour_spray,
                                              BestSkLv(ch, gsn_colour_spray), ch, victim );
                break;
            case ATCK_WEAKEN:
                retcode = spell_weaken( gsn_weaken,
                                        BestSkLv(ch, gsn_weaken), ch, victim );
                break;
            }
            if ( retcode == rCHAR_DIED || (char_died(ch)) )
                continue;

            /*
             * NPC special defense flags				-Thoric
             */
            cnt = 0;
            if ( ch->defenses )
                for ( ;; )
                {
                    if ( cnt++ > 10 )
                    {
                        attacktype = 0;
                        break;
                    }
                    x = number_range( 2, 18 );
                    attacktype = 1 << x;
                    if ( IS_SET( ch->defenses, attacktype ) )
                        break;
                }
            if ( 50 + (GetMaxLevel(ch)/4) < number_percent( ) )
                attacktype = 0;
            switch( attacktype )
            {
            case DFND_CURELIGHT:
                act( AT_MAGIC, "$n mutters a few incantations...and looks a little better.", ch, NULL, NULL, TO_ROOM );
                retcode = spell_smaug( gsn_cure_light,
                                       BestSkLv(ch, gsn_cure_light), ch, ch );
                break;
            case DFND_CURESERIOUS:
                act( AT_MAGIC, "$n mutters a few incantations...and looks a bit better.", ch, NULL, NULL, TO_ROOM );
                retcode = spell_smaug( gsn_cure_serious,
                                       BestSkLv(ch, gsn_cure_serious), ch, ch );
                break;
            case DFND_CURECRITICAL:
                act( AT_MAGIC, "$n mutters a few incantations...and looks a bit healthier.", ch, NULL, NULL, TO_ROOM );
                retcode = spell_smaug( gsn_cure_critical,
                                       BestSkLv(ch, gsn_cure_critical), ch, ch );
                break;
            case DFND_DISPELMAGIC:
                act( AT_MAGIC, "$n mutters a few incantations...and waves $s arms about.", ch, NULL, NULL, TO_ROOM );
                retcode = spell_dispel_magic( gsn_dispel_magic,
                                              BestSkLv(ch, gsn_dispel_magic), ch, victim );
                break;
            case DFND_DISPELEVIL:
                act( AT_MAGIC, "$n mutters a few incantations...and waves $s arms about.", ch, NULL, NULL, TO_ROOM );
                retcode = spell_dispel_evil( gsn_dispel_evil,
                                             BestSkLv(ch, gsn_dispel_evil), ch, victim );
                break;
            case DFND_SANCTUARY:
                if ( !IS_AFFECTED(victim, AFF_SANCTUARY) )
                {
                    act( AT_MAGIC, "$n mutters a few incantations...", ch, NULL, NULL, TO_ROOM );
                    retcode = spell_smaug( gsn_sanctuary,
                                           BestSkLv(ch, gsn_sanctuary), ch, ch );
                }
                else
                    retcode = rNONE;
                break;
            }
            if ( retcode == rCHAR_DIED || (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 ( rch->fighting || rch == victim || !IS_AWAKE(rch) )
                continue;

            /*
             * PC's auto-assist others in their group.
             */
            if ( !IS_NPC(ch) )
            {
                if ( IS_AFFECTED(rch, AFF_CHARM) &&
                     rch->master != ch )
                    continue;

                /* PC's check for group, NPC's only check for master */
                if ( !IS_NPC(rch) )
                {
                    if ( !IS_PLR2_FLAG(rch, PLR2_AUTOASSIST) )
                        continue;

                    if ( !is_same_group(rch, ch) ||
                         is_same_group(rch, victim) )
                        continue;
                }
                else
                {
                    if ( !IS_ACT_FLAG(rch, ACT_GUARDIAN) )
                        continue;
                }

                if ( !can_see(rch, victim) ||
                     !can_see(rch, ch) )
                    continue;

                multi_hit( rch, victim, TYPE_UNDEFINED );
                act(AT_PLAIN, "You assist $N!", rch, NULL, ch, TO_CHAR);

                if (char_died(victim) ||
                    char_died(ch) ||
                    char_died(rch))
                    break;

                continue;
            }

            /* PC's should never assist NPC's */
            if ( !IS_NPC(rch) )
                continue;

            /*
             * NPC's assist NPC's of same type
             */
            if ( (IS_AFFECTED(rch, AFF_CHARM) && rch->master!=ch) ||
                 IS_SET(rch->act, ACT_NOASSIST) ||
                 !can_see(rch, ch) ||
                 !can_see(rch, victim) ||
                 is_same_race_align(rch, victim) ||
                 is_same_group(rch, victim) ||
                 number_percent() > 40)
                 continue;

            if ( rch->pIndexData == ch->pIndexData ||
                 is_same_group(rch, ch) ||
                 is_same_race_align(rch, ch) ||
                 rch->master == ch )
            {
                one_hit( rch, victim, TYPE_UNDEFINED );
                if (char_died(victim) ||
                    char_died(ch) ||
                    char_died(rch))
                    break;
            }
        }
    }

    return;
}



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

    if (char_died(ch))
        return rNONE;

    /* 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)
        return rNONE;

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

    x=get_numattacks(ch);

    x-=1000;

    while (x>=1000)
    {
        retcode = one_hit( ch, victim, dt );
        if ( retcode != rNONE || who_fighting( ch ) != victim )
            return retcode;
        x-=1000;
    }

    if (x>0)
        if ((10*number_percent())<x)
        {
            retcode = one_hit( ch, victim, dt );
            if ( retcode != rNONE || who_fighting( ch ) != victim )
                return retcode;
        }

    if ( get_eq_char( ch, WEAR_DUAL_WIELD ) )
    {
        percent = IS_NPC(ch) ? GetMaxLevel(ch) : LEARNED(ch, gsn_dual_wield);
        if ( number_percent( ) < percent )
        {
            if ( !get_eq_char( ch, WEAR_WIELD ) )
            {
                bug("!WEAR_WIELD in multi_hit in fight.c");
                return rNONE;
            }
            dual_flip = TRUE;
            retcode = one_hit( ch, victim, dt );
            if ( retcode != rNONE || who_fighting( ch ) != victim )
                return retcode;
        }
        else
            learn_from_failure( ch, gsn_dual_wield );
    }

    retcode = rNONE;

    percent = IS_NPC(ch) ? (int) (GetMaxLevel(ch) / 2) : 0;
    if ( number_percent( ) < percent )
        retcode = one_hit( ch, victim, dt );

    if ( retcode == rNONE && !char_died(ch) )
    {
        int move;

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

    return retcode;
}


/*
 * Weapon types, haus
 */
static 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) && GET_LEVEL(ch, BestFightingClass(ch)) > 5 && wield)
    {
        switch(wield->value[3])
        {
        default:	*gsn_ptr = -1;			break;
        case 0:
        case 12:
        case 10:
        case 6:
        case 3:
        case 1:
        case 11:
        case 2:
        case 4:
        case 5:
        case 7:
        case 8:	break;

        }
        if ( *gsn_ptr != -1 )
            bonus = (int) ((LEARNED(ch, *gsn_ptr) -50)/10);

        /* Reduce weapon bonuses for misaligned clannies.
         if ( IS_CLANNED(ch) )
         {
         bonus = bonus /
         ( 1 + abs( GET_ALIGN(ch) - ch->pcdata->clan->alignment ) / 1000 );
         }*/

        if ( IS_DEVOTED( ch ) )
        {
            bonus = bonus - abs( ch->pcdata->favor ) / -100 ;
        }

    }
    return bonus;
}

/*
 * Calculate the tohit bonus on the object and return RIS values.
 * -- Altrag
 */
static 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 ||
             paf->location == APPLY_HITNDAM )
            tohit += paf->modifier;
    return tohit;
}

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

 if ( !IS_NPC(ch) )
 {
 lvl = UMAX( 1, (GetMaxLevel(ch) - 10) / 2 );
 if ( number_percent() + (GetMaxLevel(victim) - lvl) < 35 )
 return lvl;
 else
 return 0;
 }
 else
 {
 lvl = GetMaxLevel(ch) / 2;
 if ( number_percent() + (GetMaxLevel(victim) - lvl) < 70 )
 return lvl;
 else
 return 0;
 }
 }
 */

/*
 * Hit one guy once.
 */

int one_hit_affects(CHAR_DATA *ch, CHAR_DATA *victim, AFFECT_DATA *first_affect, int dam)
{
    AFFECT_DATA *aff;

    for ( aff = first_affect; aff; aff = aff->next )
    {
        if ( aff->location == APPLY_RACE_SLAYER )
        {
            if ( (aff->modifier == GET_RACE(victim)) ||
                 ((aff->modifier == RACE_UNDEAD) && IsUndead(victim)) ||
                 ((aff->modifier == RACE_DRAGON) && IsDragon(victim)) ||
                 ((aff->modifier == RACE_GIANT) && IsGiantish(victim)) )
            {
                sprintf(log_buf, "%s race slaying %s for %d*2 damage.",
                        GET_NAME(ch), GET_NAME(victim), dam);
                log_string_plus(log_buf,LOG_MONITOR,LEVEL_IMMORTAL,SEV_SPAM+1);
                dam *= 2;
            }
        }
        else if ( aff->location == APPLY_ALIGN_SLAYER )
        {
            switch(aff->modifier)
            {
            case 0: if (IS_EVIL(victim))    dam *= 2; break;
            case 1: if (IS_NEUTRAL(victim)) dam *= 2; break;
            case 2: if (IS_GOOD(victim))    dam *= 2; break;
            default: break;
            }
            sprintf(log_buf, "%s(%d) possibly align slaying %s(%d) for %d*2 damage, align mod %d.",
                    GET_NAME(ch), GET_ALIGN(ch),
                    GET_NAME(victim), GET_ALIGN(victim), dam, aff->modifier);
            log_string_plus(log_buf,LOG_MONITOR,LEVEL_IMMORTAL,SEV_SPAM+1);
        }
    }
    return dam;
}


int WeaponCheck(CHAR_DATA *ch, OBJ_DATA *wield, CHAR_DATA *victim, int dt, int dam)
{
    int plusris = 0, x;

    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
    {
        OBJ_DATA *gloves;
        int ris = RIS_NONMAGIC;

        if ( IS_ACTIVE(ch, CLASS_BARBARIAN) )
            plusris = UMAX(plusris, BarbarianToHitMagicBonus( ch ));

        /* inate tohit plus based on level, mostly for monks */
        if (GetMaxLevel(ch) > 48)
            plusris = 5;
        else if (GetMaxLevel(ch) > 36)
            plusris = 4;
        else if (GetMaxLevel(ch) > 26)
            plusris = 3;
        else if (GetMaxLevel(ch) > 18)
            plusris = 2;
        else if (GetMaxLevel(ch) > 12)
            plusris = 1;

        /* magic if wearing magic gloves, mostly for monks */
        if ( (gloves = get_eq_char( ch, WEAR_HANDS )) != NULL )
            if ( IS_OBJ_STAT(gloves, ITEM_MAGIC) )
                ris = RIS_MAGIC;

        dam = ris_damage( victim, dam, ris );
    }

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

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

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

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

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

    return dam;
}


ch_ret one_hit( CHAR_DATA *ch, CHAR_DATA *victim, int dt )
{
    OBJ_DATA *wield;
    int thac0;
#if SMAUG_THACO
    int victim_ac;
    int thac0_00;
    int thac0_32;
    int i, max;
    int diceroll;
#endif
    int dam, x;
    int attacktype, cnt;
    int	prof_bonus;
    int	prof_gsn;
    ch_ret retcode = 0;

    /*
     * 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 == TRUE )
        {
            dual_flip = FALSE;
        }
        else
            wield = get_eq_char( ch, WEAR_WIELD );
    } 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];
        } else dt += get_dam_by_race(ch);
    }

#if SMAUG_THACO
    /*
     * Calculate to-hit-armor-ch_class-0 versus armor.
     */
    for (i = 0, thac0 = 21; i < MAX_CLASS; ++i) {
        if ( IS_NPC(ch) )
        {
            thac0_00 = ch->mobthac0;
            thac0_32 =  0;
        }
        else
        {
            thac0_00 = class_table[i]->thac0_00;
            thac0_32 = class_table[i]->thac0_32;
        }

        max = interpolate(GET_LEVEL(ch, i), thac0_00, thac0_32 ) - GET_HITROLL(ch);
        thac0 = UMIN(thac0, max);
    }

    victim_ac = UMAX( -19, (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;
#endif

#if 0
    /*
     * "learning" between combatients.  Takes the intelligence difference,
     * and multiplies by the times killed to make up a learning bonus
     * given to whoever is more intelligent		-Thoric
     */
    if ( ch->fighting && ch->fighting->who == victim )
    {
        sh_int times = ch->fighting->timeskilled;

        if ( times )
        {
            sh_int intdiff = get_curr_int(ch) - get_curr_int(victim);

            if ( intdiff != 0 )
                victim_ac += (intdiff*times)/10;
        }
    }
#endif

#if SMAUG_THACO
    /* Weapon proficiency bonus */
    victim_ac += prof_bonus;

    /*
     * The moment of excitement!
     */
    while ( ( diceroll = number_bits( 5 ) ) >= 20 )
        ;

    if ( diceroll == 0
         || ( diceroll != 19 && diceroll < thac0 - victim_ac ) )
#else /* dale thaco */
    thac0 = CalcThaco(ch);

    if (!HitOrMiss(ch, victim, thac0))
#endif
    {
        /* Miss. */
        if ( prof_gsn != -1 || prof_gsn == gsn_fireball )
            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 = dice( ch->barenumdie, ch->baresizedie );
    else if ( wield->item_type == ITEM_WEAPON )
        dam = dice( wield->value[1], wield->value[2] );
    else
    {
        dam = dice( ch->barenumdie, ch->baresizedie );
        bug("one_hit: %s wielding %s", GET_NAME(ch), wield->name);
    }
    /*
     * Bonuses.
     */
    dam += GET_DAMROLL(ch);

    if ( prof_bonus )
        dam += prof_bonus / 4;

    /* Auto-poisoning is bonus enough... and no check here for immunity
     if ( wield && IS_SET( wield->extra_flags, ITEM_POISONED ) )
     dam += dam / 4;
     */

    if ( !IS_AWAKE(victim) )
        dam *= 2;
    if ( dt == gsn_backstab && CanUseSkill(ch, dt))
    {
        int mult;
        mult = backstab_mult[BestSkLv(ch, dt)];
        mult += lorebonus(ch, victim, dt);

        dam *= mult;

        log_printf_plus( LOG_DEBUG, LEVEL_LOG_CSET, SEV_DEBUG,
                         "backstab: %s vs %s  dam: %d  bs_mult: %d  mult: %d",
                         GET_NAME(ch), GET_NAME(victim),
                         dam,
                         backstab_mult[GET_LEVEL(ch, CLASS_THIEF)],
                         mult);
    }

    if (is_affected(ch, gsn_berserk) && wield)
        dam = berserkdambonus(ch,dam);

    dam = UMAX(dam, 0);

    dam = WeaponCheck(ch, wield, victim, dt, dam);

    /*
     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 found1 = FALSE, found2 = FALSE, found3 = FALSE;

            if ( skill->imm_char && skill->imm_char[0] != '\0' )
            {
                act( AT_HIT, skill->imm_char, ch, NULL, victim, TO_CHAR );
                found1 = TRUE;
            }
            if ( skill->imm_vict && skill->imm_vict[0] != '\0' )
            {
                act( AT_HITME, skill->imm_vict, ch, NULL, victim, TO_VICT );
                found2 = TRUE;
            }
            if ( skill->imm_room && skill->imm_room[0] != '\0' )
            {
                act( AT_ACTION, skill->imm_room, ch, NULL, victim, TO_NOTVICT );
                found3 = TRUE;
            }
            if ( !found1 || !found2 || !found3 )
                log_printf_plus(LOG_MAGIC, LEVEL_LOG_CSET, SEV_DEBUG,
                                "spell %d is missing an immune message", dt);
            if ( found1 || found2 || found3 )
                return rNONE;
        }
        dam = 0;
    }

    if (wield && wield->first_affect)
        dam = one_hit_affects(ch, victim, wield->first_affect, dam);

    if (ch->first_affect)
        dam = one_hit_affects(ch, victim, ch->first_affect, dam);

    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, GetMaxLevel(ch)/3, ch, victim );
        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, GetMaxLevel(ch)/3, ch, victim );
        if ( retcode != rNONE || char_died(ch) || char_died(victim) )
            return retcode;
    }


    /*
     * magic shields that retaliate				-Thoric
     */
    /*
     * Redone in dale fashion   -Heath, 1-18-98
     */
    if ( IS_AFFECTED( victim, AFF_FIRESHIELD )
         &&  !IS_AFFECTED( ch, AFF_FIRESHIELD ) )
        retcode = damage(victim, ch, dam, gsn_fireball);
    if ( retcode != rNONE || char_died(ch) || char_died(victim) )
        return retcode;

    if ( IS_AFFECTED( victim, AFF_ICESHIELD )
         &&  !IS_AFFECTED( ch, AFF_ICESHIELD ) )
        retcode = damage(victim, ch, dam, gsn_chill_touch);
    if ( retcode != rNONE || char_died(ch) || char_died(victim) )
        return retcode;

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

    tail_chain( );
    return retcode;
}

/*
 * Hit one guy with a projectile.
 * Handles use of missile weapons (wield = missile weapon)
 * or thrown items/weapons
 */
ch_ret projectile_hit( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *wield,
                       OBJ_DATA *projectile, sh_int dist )
{
    int thac0;
#ifdef SMAUG_THACO
    int victim_ac;
    int thac0_00;
    int thac0_32;
    int diceroll;
    int i, max;
#endif
    int plusris;
    int dam;
    int	prof_bonus;
    int	prof_gsn = -1;
    int proj_bonus;
    int dt;
    ch_ret retcode;

    if ( !projectile )
        return rNONE;

    if ( projectile->item_type == ITEM_PROJECTILE
         ||   projectile->item_type == ITEM_WEAPON )
    {
        dt = TYPE_HIT + projectile->value[2];
        proj_bonus = number_range(projectile->value[1], projectile->value[3]);
    }
    else
    {
        dt = TYPE_UNDEFINED;
        proj_bonus = number_range(1, URANGE(2, get_obj_weight(projectile), 100) );
    }

    /*
     * Can't beat a dead char!
     */
    if ( victim->position == POS_DEAD || char_died(victim) )
    {
        extract_obj(projectile);
        return rVICT_DIED;
    }

    if ( wield )
        prof_bonus = weapon_prof_bonus_check( ch, wield, &prof_gsn );
    else
        prof_bonus = 0;

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

#if SMAUG_THACO
    /*
     * Calculate to-hit-armor-ch_class-0 versus armor.
     */
    for (i = 0, thac0 = 21; i < MAX_CLASS; ++i) {
        if ( IS_NPC(ch) )
        {
            thac0_00 = ch->mobthac0;
            thac0_32 =  0;
        }
        else
        {
            thac0_00 = class_table[i]->thac0_00;
            thac0_32 = class_table[i]->thac0_32;
        }

        max = interpolate(GET_LEVEL(ch, i), thac0_00, thac0_32 ) - GET_HITROLL(ch);
        thac0 = UMIN(thac0, max);
    }

    victim_ac = UMAX( -19, (int) (GET_AC(victim) / 10) );

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

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

    /*
     * The moment of excitement!
     */
    while ( ( diceroll = number_bits( 5 ) ) >= 20 )
        ;

    if ( diceroll == 0
         || ( diceroll != 19 && diceroll < thac0 - victim_ac ) )
#else /* dale thaco */
    thac0 = CalcThaco(ch);

    if (!HitOrMiss(ch, victim, thac0))
#endif
    {
        /* Miss. */
        if ( prof_gsn != -1 )
            learn_from_failure( ch, prof_gsn );

        /* Do something with the projectile */
        if ( number_percent() < 50 )
            extract_obj(projectile);
        else
        {
            if ( projectile->in_obj )
                obj_from_obj(projectile);
            if ( projectile->carried_by )
                obj_from_char(projectile);
            obj_to_room(projectile, victim->in_room);
        }
        damage( ch, victim, 0, dt );
        tail_chain( );
        return rNONE;
    }

    /*
     * Hit.
     * Calc damage.
     */

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

    /*
     * Bonuses.
     */
    dam += GET_DAMROLL(ch);

    if ( prof_bonus )
        dam += prof_bonus / 4;

    if ( !IS_AWAKE(victim) )
        dam *= 2;

    if ( dam <= 0 )
        dam = 1;

    plusris = 0;

    /* one_hit does this, should we too? */
/*    dam = WeaponCheck(ch, wield, victim, dam, dt);*/

    if ( IS_OBJ_STAT(projectile, 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
     */
    if ( wield )
        plusris = obj_hitroll( wield );

    /* check for RIS_PLUSx 					-Thoric */
    if ( dam )
    {
        int x, 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 ( x = RIS_PLUS1; x <= RIS_PLUS6; x <<= 1 )
        {
            if ( IS_SET( victim->immune, x ) )
                imm = x;
            if ( IS_SET( victim->resistant, x ) )
                res = x;
            if ( IS_SET( victim->susceptible, x ) )
                sus = x;
        }
        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;
    }

    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 found1 = FALSE, found2 = FALSE, found3 = FALSE;

            if ( skill->imm_char && skill->imm_char[0] != '\0' )
            {
                act( AT_HIT, skill->imm_char, ch, NULL, victim, TO_CHAR );
                found1 = TRUE;
            }
            if ( skill->imm_vict && skill->imm_vict[0] != '\0' )
            {
                act( AT_HITME, skill->imm_vict, ch, NULL, victim, TO_VICT );
                found2 = TRUE;
            }
            if ( skill->imm_room && skill->imm_room[0] != '\0' )
            {
                act( AT_ACTION, skill->imm_room, ch, NULL, victim, TO_NOTVICT );
                found3 = TRUE;
            }
            if ( !found1 || !found2 || !found3 )
                log_printf_plus(LOG_MAGIC, LEVEL_LOG_CSET, SEV_DEBUG,
                                "spell %d is missing an immune message", dt);
            if ( found1 || found2 || found3 )
            {
                if ( number_percent() < 50 )
                    extract_obj(projectile);
                else
                {
                    if ( projectile->in_obj )
                        obj_from_obj(projectile);
                    if ( projectile->carried_by )
                        obj_from_char(projectile);
                    obj_to_room(projectile, victim->in_room);
                }
                return rNONE;
            }
        }
        dam = 0;
    }
    if ( (retcode = damage( ch, victim, dam, dt )) != rNONE )
    {
        extract_obj(projectile);
        return retcode;
    }
    if ( char_died(ch) )
    {
        extract_obj(projectile);
        return rCHAR_DIED;
    }
    if ( char_died(victim) )
    {
        extract_obj(projectile);
        return rVICT_DIED;
    }

    retcode = rNONE;
    if ( dam == 0 )
    {
        if ( number_percent() < 50 )
            extract_obj(projectile);
        else
        {
            if ( projectile->in_obj )
                obj_from_obj(projectile);
            if ( projectile->carried_by )
                obj_from_char(projectile);
            obj_to_room(projectile, victim->in_room);
        }
        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, GetMaxLevel(ch)/3, ch, victim );
        if ( retcode != rNONE || char_died(ch) || char_died(victim) )
        {
            extract_obj(projectile);
            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, GetMaxLevel(ch)/3, ch, victim );
        if ( retcode != rNONE || char_died(ch) || char_died(victim) )
        {
            extract_obj(projectile);
            return retcode;
        }
    }

    extract_obj(projectile);

    tail_chain( );
    return retcode;
}

/*
 * Calculate damage based on resistances, immunities and suceptibilities
 *					-Thoric
 */
sh_int ris_damage( CHAR_DATA *ch, sh_int dam, int ris )
{
    if ( IS_SET(ch->absorb, ris ) )
    {
        log_printf_plus(LOG_DEBUG, LEVEL_IMMORTAL, SEV_SPAM+2,
                        "ris_damage: %s absorbed %d",
                        GET_NAME(ch), dam);
        return(dam*-1);
    }
    if ( IS_SET(ch->immune, ris ) )
    {
        log_printf_plus(LOG_DEBUG, LEVEL_IMMORTAL, SEV_SPAM+2,
                        "ris_damage: %s immune, no damage",
                        GET_NAME(ch));
        return(-1);
    }
    if ( IS_SET(ch->resistant, ris ) )
    {
        log_printf_plus(LOG_DEBUG, LEVEL_IMMORTAL, SEV_SPAM+2,
                        "ris_damage: %s resistant, half of %d",
                        GET_NAME(ch), dam);
        return(dam/2);
    }
    if ( IS_SET(ch->susceptible, ris ) )
    {
        log_printf_plus(LOG_DEBUG, LEVEL_IMMORTAL, SEV_SPAM+2,
                        "ris_damage: %s susceptible, double of %d",
                        GET_NAME(ch), dam);
        return(dam*2);
    }

    return dam;
}


/*
 * Inflict damage from a hit.
 */
ch_ret damage( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt )
{
    char buf1[MAX_STRING_LENGTH];
    sh_int dameq;
    sh_int maxdam;
    bool npcvict;
    bool loot;
    OBJ_DATA *damobj;
    ch_ret retcode;
    sh_int dampmod;
    CHAR_DATA *gch;

    retcode = rNONE;

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

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

    if (check_illegal_pk(ch, victim))
    {
        stop_fighting( ch, TRUE );
        return rNONE;
    }

    npcvict = IS_NPC(victim);

    if ( dam > 0 && dt != TYPE_UNDEFINED && IS_VALID_SN(dt) )
    {
        int slm, sls;

        slm = skill_table[dt]->skill_level[CLASS_MAGE];
        sls = skill_table[dt]->skill_level[CLASS_SORCERER];

        if ( (slm <= 5 || sls <= 5) &&
             is_affected(victim, gsn_minor_invulnerability) )
            dam = 0;

        if ( ((slm >= 6  && slm <= 10) ||
              (sls >= 6 && sls >= 10)) &&
             is_affected(victim, gsn_major_invulnerability) )
            dam = 0;

        if ( dam == 0 )
        {
            act(AT_MAGIC, "$N's globe deflects your $t.",
                ch, skill_table[dt]->noun_damage, victim, TO_CHAR);
            act(AT_MAGIC, "Your globe deflects $n's $t.",
                ch, skill_table[dt]->noun_damage, victim, TO_VICT);
            act(AT_MAGIC, "A globe around $N deflects $n's $t.",
                ch, skill_table[dt]->noun_damage, victim, TO_NOTVICT);
        }
    }

    /*
     * Check Align types for RIS                                 -Heath ;)
     */

    if ( IS_GOOD(ch) && IS_EVIL(victim) )
        dam = ris_damage(victim, dam, RIS_GOOD);
    else if ( IS_EVIL(ch) && IS_GOOD(victim) )
        dam = ris_damage(victim, dam, RIS_EVIL);

    /*
     * Check damage types for RIS				-Thoric
     */
    if ( dam > 0 && 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) || dt == gsn_backstab)
            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 > 0 && npcvict && ch != victim )
    {
        if ( !IS_SET( victim->act, ACT_SENTINEL ) )
        {
            if (!is_hunting(victim, ch))
                start_hunting(victim, ch);
        }

        if (!is_hating(victim, ch))
            start_hating(victim, ch);
    }
    /*
     * Stop up any residual loopholes.
     */

    maxdam = BestSkLv(ch, dt) * 30;
    if ( dt == gsn_backstab )
        maxdam = BestSkLv(ch, dt) * 60;
    if ( dam > maxdam )
    {
        log_printf_plus(LOG_MONITOR, LEVEL_IMMORTAL, SEV_INFO,
                        "damage: %d more than %d points - %s (lvl %d) -> %s",
                        dam, maxdam,
                        GET_NAME(ch),
                        GetMaxLevel(ch),
                        GET_NAME(victim));

        dam = maxdam;
    }

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


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

        if ( victim->position > POS_STUNNED )
        {
            if ( !ch->fighting && victim->in_room == ch->in_room )
                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 );

        /* Pkill stuff.  If a deadly attacks another deadly or is attacked by one,
         * then ungroup any nondealies.  Disabled untill I can figure out the right
         * way to do it.
         */

        /*	{
         sh_int anopc = 0;  * # of (non-pkill) pc in a (ch) *
         sh_int bnopc = 0;  * # of (non-pkill) pc in b (victim) *
         CHAR_DATA *lch;   * leader ch *

         * count the # of non-pkill pc in a ( not including == ch ) *
         for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
         if ( is_same_group( ch, gch ) && !IS_NPC( gch )
         && !IS_PKILL( gch ) && ( ch != gch ) ) anopc++;

         * count the # of non-pkill pc in b ( not including == victim ) *
         for ( gch = victim->in_room->first_person; gch; gch = gch->next_in_room )
         if ( is_same_group( victim, gch ) && !IS_NPC( gch )
         && !IS_PKILL( gch ) && ( victim != gch ) ) bnopc++;


         * only consider disbanding if both groups have 1(+) non-pk pc *
         if ( ( bnopc > 0 ) && ( anopc > 0 ) )
         {
         * look at group a through ch's leader first *
         lch = ch->leader ? ch->leader : ch;
         if ( lch != ch )
         {
         * stop following leader if it isn't pk *
         if ( !IS_NPC(lch) && !IS_PKILL( lch ) )
         stop_follower( ch );
         else
         {
         * disband non-pk members from lch's group if it is pk *
         for ( gch = ch->in_room->first_person; gch;
         gch = gch->next_in_room )
         {
         if ( is_same_group( lch, gch )
         && ( lch != gch )
         && !IS_NPC(gch) && !IS_PKILL( gch ) )
         stop_follower( gch );
         }
         }
         }
         else
         for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
         {
         * ch is leader - disband non-pks from group *
         if ( is_same_group( ch, gch )
         && ( ch != gch )
         && ( !IS_PKILL( gch ) && !IS_NPC( gch ) ) )
         stop_follower( gch );
         }

         * time to look at the victims group through its leader *
         lch = victim->leader ? victim->leader : victim;

         if ( lch != victim )
         {
         * if leader isn't deadly, stop following lch *
         if ( !IS_PKILL( lch ) && !IS_NPC( lch ) )
         stop_follower( victim );
         else
         {
         * lch is pk, disband non-pk's from group *
         for ( gch = victim->in_room->first_person; gch;
         gch = gch->next_in_room )
         {
         if ( is_same_group( lch, gch )
         && ( lch != gch )
         && ( !IS_PKILL( gch ) && !IS_NPC( gch ) ) )
         stop_follower( gch );
         }
         }
         }
         else
         {
         * victim is leader of group - disband non-pks *
         for ( gch = victim->in_room->first_person; gch;
         gch = gch->next_in_room )
         {
         if ( is_same_group( victim, gch )
         && ( victim != gch )
         && !IS_PKILL( gch ) && !IS_NPC( gch ) )
         stop_follower( gch );
         }
         }
         }
         }*/

        {
            sh_int anopc = 0;  /* # of (non-pkill) pc in a (ch) */
            sh_int bnopc = 0;  /* # of (non-pkill) pc in b (victim) */

            /* count the # of non-pkill pc in a ( not including == ch ) */
            for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
                if ( is_same_group( ch, gch ) && !IS_NPC( gch )
                     && !IS_PKILL( gch ) && ( ch != gch ) ) anopc++;

            /* count the # of non-pkill pc in b ( not including == victim ) */
            for ( gch = victim->in_room->first_person; gch; gch = gch->next_in_room )
                if ( is_same_group( victim, gch ) && !IS_NPC( gch )
                     && !IS_PKILL( gch ) && ( victim != gch ) ) bnopc++;


            /* only consider disbanding if both groups have 1(+) non-pk pc,
             or when one participant is pc, and the other group has 1(+)
             pk pc's (in the case that participant is only pk pc in group) */
            if ( ( bnopc > 0 && anopc > 0 )
                 || ( bnopc > 0 && !IS_NPC(ch) )
                 || ( anopc > 0 && !IS_NPC(victim) ) )
            {
                /* Disband from same group first */
                if ( is_same_group(ch, victim) )
                {
                    /* Messages to char and master handled in stop_follower */
                    act( AT_ACTION, "$n disbands from $N's group.",
                         (ch->leader == victim) ? victim : ch, NULL,
                         (ch->leader == victim) ? victim->master : ch->master,
                         TO_NOTVICT );
                    if ( ch->leader == victim )
                        stop_follower(victim);
                    else
                        stop_follower(ch);
                }
                /* if leader isnt pkill, leave the group and disband ch */
                if ( ch->leader != NULL && !IS_NPC(ch->leader) &&
                     !IS_PKILL(ch->leader) )
                {
                    act( AT_ACTION, "$n disbands from $N's group.", ch, NULL,
                         ch->master, TO_NOTVICT );
                    stop_follower( ch );
                }
                else
                {
                    for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
                        if ( is_same_group(gch, ch) && !IS_NPC( gch ) &&
                             !IS_PKILL( gch ) && gch != ch )
                        {
                            act( AT_ACTION, "$n disbands from $N's group.", ch, NULL,
                                 gch->master, TO_NOTVICT );
                            stop_follower( gch );
                        }
                }
                /* if leader isnt pkill, leave the group and disband victim */
                if ( victim->leader != NULL && !IS_NPC(victim->leader) &&
                     !IS_PKILL(victim->leader) )
                {
                    act( AT_ACTION, "$n disbands from $N's group.", victim, NULL,
                         victim->master, TO_NOTVICT );
                    stop_follower( victim );
                }
                else
                {
                    for ( gch = victim->in_room->first_person; gch; gch = gch->next_in_room )
                        if ( is_same_group(gch, victim) && !IS_NPC( gch ) &&
                             !IS_PKILL( gch ) && gch != victim )
                        {
                            act( AT_ACTION, "$n disbands from $N's group.", gch, NULL,
                                 gch->master, TO_NOTVICT );
                            stop_follower( gch );
                        }
                }
            }
        }

        /*         for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
         {
         if ( is_same_group( ch, gch )
         && ( IS_PKILL( ch ) != IS_PKILL( gch ) ) )
         {
         stop_follower( ch );
         stop_follower( gch );
         }
         }

         for ( gch = victim->in_room->first_person; gch; gch = gch->next_in_room )
         {
         if ( is_same_group( victim, gch )
         && ( IS_PKILL( victim ) != IS_PKILL( gch ) ) )
         {
         stop_follower( victim );
         stop_follower( gch );
         }
         }
         */
        /*
         * Inviso attacks ... not.
         */

        if ( IS_AFFECTED(ch, AFF_INVISIBLE) )
        {
            affect_strip( ch, gsn_invis );
            affect_strip( ch, gsn_group_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 ( dam > 0 )
        {
            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 ( dam > 0 && dt >= TYPE_HIT )
        {
            if ( IS_NPC(ch)
                 &&   IS_SET( ch->attacks, DFND_DISARM )
                 &&   GetMaxLevel(ch) > 9
                 &&   number_percent( ) < GetMaxLevel(ch) / 2 )
                disarm( ch, victim );

            if ( IS_NPC(ch)
                 &&   IS_SET( ch->attacks, ATCK_TRIP )
                 &&   GetMaxLevel(ch) > 5
                 &&   number_percent( ) < GetMaxLevel(ch) / 2 )
                trip( ch, victim );

            dam = check_parry( ch, victim, dam );
            dam = check_dodge( ch, victim, dam );
        }

        /*
         * 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, MAX_WEAR-1);
        damobj = get_eq_char(victim, dameq);
        if ( damobj )
        {
            if ( dam > get_obj_resistance(damobj) )
            {
                damage_obj(damobj);
            }
            dam -= 5;  /* add a bonus for having something to block the blow */
        }
        else
            dam += 5;  /* add penalty for bare skin! */
    }

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

#ifdef MUD_DEBUG
    if (!IS_NPC(ch) || !IS_NPC(victim))
        log_printf_plus(LOG_DEBUG, LEVEL_IMMORTAL, SEV_SPAM+9,
                        "damage: %d points - %s -> %s",
                        dam,
                        GET_NAME(ch),
                        GET_NAME(victim));
#endif

    dam_message( ch, victim, dam, dt );

    if (IS_AFFECTED2(victim, AFF2_LIFE_PROT) && dam >= GET_HIT(victim))
    {
        if (life_protection_object(victim))
            dam = 0;
        REMOVE_BIT(victim->affected_by2, AFF2_LIFE_PROT);
    }

    /* destroy brittle weapons */
    damobj = get_eq_char( ch, WEAR_DUAL_WIELD );
    if (damobj && IS_OBJ_STAT2(damobj, ITEM2_BRITTLE))
        damage_obj(damobj);
    damobj = get_eq_char( ch, WEAR_WIELD );
    if (damobj && IS_OBJ_STAT2(damobj, ITEM2_BRITTLE))
        damage_obj(damobj);

    /* dam is -1 when immune */
    if (dam == -1)
        dam = 0;

    if (dam < 0)
    {
        log_printf_plus(LOG_MONITOR, LEVEL_IMMORTAL, SEV_SPAM+1,
                        "damage: %s healing %s for %d points (absorb?)",
                        GET_NAME(ch),
                        GET_NAME(victim),
                        dam*-1);
    }

    if ( !IS_IMMORTAL(victim) )
        victim->hit = UMIN(victim->hit-dam, GET_MAX_HIT(victim));

    /* Make sure newbies dont die */

    if ( dam > 0 && (dt > TYPE_HIT || dt == gsn_backstab)
         && !IS_AFFECTED( victim, AFF_POISON )
         &&  is_wielding_poisoned( ch )
         && !IS_SET( victim->immune, RIS_POISON )
         && !saves_poison_death( GetMaxLevel(ch), 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 );
    }

    /*
     * Vampire self preservation				-Thoric
     */
    if ( IS_VAMPIRE(victim) )
    {
        if ( dam >= (GET_MAX_HIT(victim) / 10) )	/* get hit hard, lose blood */
            gain_condition(victim, COND_BLOODTHIRST, -1 - (GetMaxLevel(victim) / 20));
        if ( GET_HIT(victim) <= (GET_MAX_HIT(victim) / 8)
             && GET_COND(victim, COND_BLOODTHIRST)>5 )
        {
            gain_condition(victim, COND_BLOODTHIRST,
                           -URANGE(3, GetMaxLevel(victim) / 10, 8) );
            GET_HIT(victim) += URANGE( 4, (GET_MAX_HIT(victim) / 30), 15);
            set_char_color(AT_BLOOD, victim);
            send_to_char("You howl with rage as the beast within stirs!\n\r", victim);
        }
    }

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

    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 );
        act( AT_DANGER, "You are mortally wounded, and will die soon, if not aided.",
             victim, NULL, NULL, TO_CHAR );
        break;

    case POS_INCAP:
        act( AT_DYING, "$n is incapacitated and will slowly die, if not aided.",
             victim, NULL, NULL, TO_ROOM );
        act( AT_DANGER, "You are incapacitated and will slowly die, if not aided.",
             victim, NULL, NULL, TO_CHAR );
        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 );
            act( AT_HURT, "You are stunned, but will probably recover.",
                 victim, NULL, NULL, TO_CHAR );
        }
        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_DIEMSG, skill->die_char, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_CHAR );
            if ( skill->die_vict && skill->die_vict[0] != '\0' )
                act( AT_DIEMSG, skill->die_vict, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_VICT );
            if ( skill->die_room && skill->die_room[0] != '\0' )
                act( AT_DIEMSG, skill->die_room, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_NOTVICT );
        }
        act( AT_DIEMSG, "$n is DEAD!", victim, 0, 0, TO_ROOM );
        act( AT_DIEMSG, "You have been killed!", victim, 0, 0, TO_CHAR );
        break;

    default:
        if ( dam > GET_MAX_HIT(victim) / 4 )
        {
            act( AT_HURT, "That really did HURT!", victim, 0, 0, TO_CHAR );
            if ( number_bits(3) == 0 )
                worsen_mental_state( ch, 1 );
        }
        if ( GET_HIT(victim) < GET_MAX_HIT(victim) / 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( ch, 1 );
        }
        break;
    }

    /*
     * Sleep spells and extremely wounded folks.
     */
    /* lets make NPC's not slaughter PC's */
    /*
     if ( !IS_AWAKE(victim)
     &&   !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 );

     if (!npcvict && IS_NPC(ch))
     stop_fighting( victim, TRUE );
     else
     stop_fighting( victim, FALSE );
     }
     */
    /*
     * Payoff for killing things.
     */
    if ( victim->position == POS_DEAD )
    {
        group_gain( ch, victim );

        if ( in_arena(ch) || in_arena(victim) )
        {
            sprintf( log_buf, "%s killed by %s in the arena at %d",
                     victim->name,
                     (IS_NPC(ch) ? ch->short_descr : ch->name),
                     victim->in_room->vnum );
            log_string_plus( log_buf,LOG_MONITOR,LEVEL_IMMORTAL,SEV_NOTICE);
        }
        else if ( !npcvict )
        {
            int loss;

            /*
             * Dying penalty:
             */
            if (GetMaxLevel(victim)>=51)
                loss = (int)((float)GET_EXP(victim) * 0.25);
            else if (GetMaxLevel(victim)>=40)
                loss = (int)((float)GET_EXP(victim) * 0.20);
            else if (GetMaxLevel(victim)>=25)
                loss = (int)((float)GET_EXP(victim) * 0.15);
            else if (GetMaxLevel(victim)>=15)
                loss = (int)((float)GET_EXP(victim) * 0.10);
            else if (GetMaxLevel(victim)>=5)
                loss = (int)((float)GET_EXP(victim) * 0.08);
            else
                loss = (int)((float)GET_EXP(victim) * 0.03);

            /* less loss for being killed by something stronger than you */
            if (GetMaxLevel(ch) > GetMaxLevel(victim))
                loss /= 2;

            /* less loss for being killed twice by the same mob */
            if ( IS_NPC(ch) )
            {
                if ( victim->last_killed_by == ch->vnum )
                    loss = (int)((float)loss * 0.10);
                else
                    victim->last_killed_by = ch->vnum;

            }

            sprintf( log_buf, "%s killed by %s at %d, lost %d/%d exp, dam %d, dt %d",
		    victim->name,
		    (IS_NPC(ch) ? ch->short_descr : ch->name),
		    victim->in_room->vnum,
		    loss, GET_EXP(victim),
		    dam, dt);
            log_string_plus( log_buf, LOG_MONITOR, LEVEL_IMMORTAL, SEV_NOTICE);

            GET_EXP(victim) -= UMIN(GET_EXP(victim), loss);
        }
        else
            if ( !IS_NPC(ch) )		/* keep track of mob vnum killed */
                add_kill( ch, victim );

        check_killer( ch, victim );

        loot = legal_loot( ch, victim );

        if ( ch->in_room != victim->in_room )
            loot = FALSE;

        set_cur_char(victim);
        raw_kill( ch, victim, dt );

        if ( victim == ch )
            return rNONE;

        victim = NULL;

        if ( !IS_NPC(ch) && loot )
        {
            /* Autogold by Scryn 8/12 */
            if ( IS_SET(ch->act, PLR_AUTOGOLD) )
            {
                int init, diff;
                OBJ_DATA *corpse;

                if ((corpse = get_obj_here(ch, "corpse")))
                {
                    OBJ_DATA *mobj, *mobj_next;
                    char mbuf[80];
		    int currtype;

                    for (mobj = corpse->first_content; mobj; mobj=mobj_next)
                    {
			mobj_next = mobj->next_content;
                        if (mobj->item_type != ITEM_MONEY)
                            continue;
			currtype = mobj->value[2];
                        init = GET_MONEY(ch, currtype);
                        sprintf(mbuf, "%s-coins corpse", curr_types[currtype]);
                        do_get( ch, mbuf );
                        diff = GET_MONEY(ch, currtype) - init;
                        if (diff)
                        {
                            sprintf(buf1,"%d %s", diff, curr_types[currtype]);
                            do_split( ch, buf1 );
                        }
                    }
                }
            }
            if ( IS_SET(ch->act, PLR_AUTOLOOT) )
                do_get( ch, "all corpse" );
            else if ( !IS_NPC(ch) && !IS_SET(ch->pcdata->flags, PCFLAG_GAG) )
                do_look( ch, "in corpse" );

            if ( IS_SET(ch->act, PLR_AUTOSAC) )
                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
         && !IS_SET( victim->pcdata->flags, PCFLAG_NORECALL ) )
    {
        if ( number_range( 0, victim->wait ) == 0)
        {
            do_recall( victim, "" );
            return rNONE;
        }
    }

    /*
     * Wimp out?
     */
    if ( npcvict && dam > 0 )
    {
        if ( ( IS_SET(victim->act, ACT_WIMPY) && number_bits( 3 ) == 0
               &&   GET_HIT(victim) < GET_MAX_HIT(victim) / 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
         &&   GET_HIT(victim) > 0
         &&   GET_HIT(victim) <= 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 )
{
    /* Thx Josh! */
    if ( who_fighting( ch ) == ch )
	return FALSE;

    if ( in_arena( ch ) )
        return FALSE;

    if ( IS_SET( victim->in_room->room_flags, ROOM_SAFE ) )
    {
        set_char_color( AT_MAGIC, ch );
        send_to_char( "A magical force stops you.\n\r", ch );
        return TRUE;
    }

    if ( GetMaxLevel(ch) > LEVEL_IMMORTAL )
        return FALSE;

    if( !IS_NPC( ch ) && !IS_NPC( victim )
        && ch != victim
        && IS_SET( victim->in_room->area->flags, AFLAG_NOPKILL ) )
    {
        set_char_color( AT_IMMORT, ch );
        send_to_char( "The gods have forbidden player killing in this area.\n\r", ch );
        return TRUE;
    }

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

    if ( get_age( ch ) < 18 || GetMaxLevel(ch) < 5 )
    {
        send_to_char( "You are not yet ready, needing age or experience, if not both.\n\r", ch );
        return TRUE;
    }

    if ( get_age( victim ) < 18 || GetMaxLevel(victim) < 5 )
    {
        send_to_char( "They are yet too young to die.\n\r", ch );
        return TRUE;
    }

    if ( GetMaxLevel(ch) - GetMaxLevel(victim) > 5
         ||   GetMaxLevel(victim) - GetMaxLevel(ch) > 5 )
    {
        set_char_color( AT_IMMORT, ch );
        send_to_char( "The gods do not allow murder when there is such a difference in level.\n\r", ch );
        return TRUE;
    }

    if ( get_timer(victim, TIMER_PKILLED) > 0 )
    {
        set_char_color( AT_GREEN, ch );
        send_to_char( "That character has died within the last 5 minutes.\n\r", ch);
        return TRUE;
    }

    if ( get_timer(ch, TIMER_PKILLED) > 0 )
    {
        set_char_color( AT_GREEN, ch );
        send_to_char( "You have been killed within the last 5 minutes.\n\r", ch );
        return TRUE;
    }

    return FALSE;
}

/*
 * just verify that a corpse looting is legal
 */
bool legal_loot( CHAR_DATA *ch, CHAR_DATA *victim )
{
    /* anyone can loot mobs */
    if ( IS_NPC(victim) )
        return TRUE;
    /* non-charmed mobs can loot anything */
    if ( IS_NPC(ch) && !ch->master )
        return TRUE;
    /* members of different clans can loot too! -Thoric */
    if ( !IS_NPC(ch) && !IS_NPC(victim)
         &&    IS_SET( ch->pcdata->flags, PCFLAG_DEADLY )
         &&    IS_SET( victim->pcdata->flags, PCFLAG_DEADLY ) )
        return TRUE;
    return FALSE;
}

/*
 * See if an attack justifies a KILLER flag.
 */
void check_killer( CHAR_DATA *ch, CHAR_DATA *victim )
{
    if (ch == victim)
        return;

    /*
     * NPC's are fair game.
     */
    if ( IS_NPC(victim) )
    {
        if ( !IS_NPC( ch ) )
        {
            int level_ratio;
            level_ratio = URANGE( 1, GetMaxLevel(ch) / GetMaxLevel(victim), 50);
            if ( ch->pcdata->clan )
                ch->pcdata->clan->mkills++;
            ch->pcdata->mkills++;
            ch->in_room->area->mkills++;
            if ( ch->pcdata->deity )
            {
                if ( victim->race == ch->pcdata->deity->npcrace )
                    adjust_favor( ch, 3, level_ratio );
                else
                    if ( victim->race == ch->pcdata->deity->npcfoe )
                        adjust_favor( ch, 17, level_ratio );
                    else
                        adjust_favor( ch, 2, level_ratio );
            }
        }
        return;
    }

    /*
     * Any character in the arena is ok to kill.
     */
    if ( in_arena( ch ) )
        return;

    /*
     * So are killers and thieves.
     */
    if ( IS_SET(victim->act, PLR_KILLER) ||
         IS_SET(victim->act, PLR_THIEF) )
    {
        if ( !IS_NPC( ch ) )
        {
            if ( ch->pcdata->clan )
                ch->pcdata->clan->pkills++;
            ch->pcdata->pkills++;
            ch->in_room->area->pkills++;
        }
        if ( victim->pcdata->clan )
            victim->pcdata->clan->mdeaths++;
        victim->pcdata->mdeaths++;
        victim->in_room->area->mdeaths++;
        return;
    }

    /*
     * Charm-o-rama.
     */
    if ( IS_SET(ch->affected_by, AFF_CHARM) )
    {
        if ( !ch->master )
        {
	    bug( "Check_killer: %s bad AFF_CHARM", GET_NAME(ch) );
            affect_strip( ch, gsn_charm_person );
            REMOVE_BIT( ch->affected_by, AFF_CHARM );
            return;
        }

        /* stop_follower( ch ); */

        check_killer( ch->master, victim );
        return;
    }

    if ( !IS_NPC(ch) &&
         !IS_NPC(victim) &&
         IS_PC_FLAG( ch, PCFLAG_DEADLY ) &&
         IS_PC_FLAG( victim, PCFLAG_DEADLY ) )
    {

        if ( ch->pcdata->clan )
            ch->pcdata->clan->pkills++;
        ch->pcdata->pkills++;
        ch->in_room->area->pkills++;

        GET_HIT(ch)  = GET_MAX_HIT(ch);
        GET_MANA(ch) = GET_MAX_MANA(ch);
        GET_MOVE(ch) = GET_MAX_MOVE(ch);
        if ( ch->pcdata )
            ch->pcdata->condition[COND_BLOODTHIRST] = GET_MAX_BLOOD(ch);
        update_pos(victim);

        if ( victim != ch )
        {
            act( AT_MAGIC, "Bolts of blue energy rise from the corpse, seeping into $n.", ch, victim->name, NULL, TO_ROOM );
            act( AT_MAGIC, "Bolts of blue energy rise from the corpse, seeping into you.", ch, victim->name, NULL, TO_CHAR );
        }

        if ( victim->pcdata->clan )
            victim->pcdata->clan->pdeaths++;
        victim->pcdata->pdeaths++;

        adjust_favor( victim, 11, 1 );
        adjust_favor( ch, 2, 1 );
        add_timer( victim, TIMER_PKILLED, 115, NULL, 0 );
        WAIT_STATE( victim, 3 * PULSE_VIOLENCE );

        return;
    }

    /*
     * NPC's are cool of course (as long as not charmed).
     * And current killers stay as they are.
     */
    if ( IS_NPC(ch) )
    {
        if ( !IS_NPC(victim) )
        {
            int level_ratio;
            if ( victim->pcdata->clan )
                victim->pcdata->clan->mdeaths++;
            victim->pcdata->mdeaths++;
            victim->in_room->area->mdeaths++;

            level_ratio = URANGE( 1, GetMaxLevel(ch) / GetMaxLevel(victim), 50);
            if ( victim->pcdata->deity )
            {
                if ( ch->race == victim->pcdata->deity->npcrace )
                    adjust_favor( victim, 12, level_ratio );
                else
                    if ( ch->race == victim->pcdata->deity->npcfoe )
                        adjust_favor( victim, 15, level_ratio );
                    else
                        adjust_favor( victim, 11, level_ratio );
            }
        }
        return;
    }

    if ( ch->pcdata->clan )
        ch->pcdata->clan->illegal_pk++;
    ch->pcdata->illegal_pk++;
    ch->in_room->area->illegal_pk++;

    if ( victim->pcdata->clan )
        victim->pcdata->clan->pdeaths++;
    victim->pcdata->pdeaths++;
    victim->in_room->area->pdeaths++;

    if ( IS_SET(ch->act, PLR_KILLER) )
        return;

    log_printf_plus(LOG_MONITOR, LEVEL_IMMORTAL, SEV_NOTICE, "check_killer: %s attacking %s, setting KILLER", GET_NAME(ch), GET_NAME(victim));

    set_char_color( AT_WHITE, ch );
    send_to_char( "A strange feeling grows deep inside you, and a tingle goes up your spine...\n\r", ch );
    set_char_color( AT_IMMORT, ch );
    send_to_char( "A deep voice booms inside your head, 'Thou shall now be known as a deadly murderer!!!'\n\r", ch );
    set_char_color( AT_WHITE, ch );
    send_to_char( "You feel as if your soul has been revealed for all to see.\n\r", ch );

    SET_BIT(ch->act, PLR_KILLER);
    if ( IS_SET( ch->act, PLR_ATTACKER) )
        REMOVE_BIT(ch->act, PLR_ATTACKER);
    save_char_obj( ch );
    return;
}

/*
 * See if an attack justifies a ATTACKER flag.
 */
void check_attacker( CHAR_DATA *ch, CHAR_DATA *victim )
{

    /*
     * Made some changes to this function Apr 6/96 to reduce the prolifiration
     * of attacker flags in the realms. -Narn
     */
    /*
     * NPC's are fair game.
     * So are killers and thieves and people in the arena.
     */
    if ( ch == victim ||
         IS_NPC(victim) ||
         IS_SET(victim->act, PLR_KILLER) ||
         IS_SET(victim->act, PLR_THIEF) ||
         in_arena(victim) )
        return;

    /* deadly char check */
    if ( !IS_NPC(ch) &&
         !IS_NPC(victim) &&
         IS_PC_FLAG( ch, PCFLAG_DEADLY ) &&
         IS_PC_FLAG( victim, PCFLAG_DEADLY ) )
        return;

    /*
     * Charm-o-rama.
     */
    if ( IS_SET(ch->affected_by, AFF_CHARM) )
    {
        if ( !ch->master )
        {
	    bug( "Check_attacker: %s bad AFF_CHARM", GET_NAME(ch) );
            affect_strip( ch, gsn_charm_person );
            REMOVE_BIT( ch->affected_by, AFF_CHARM );
            return;
        }

        /* Won't have charmed mobs fighting give the master an attacker
         flag.  The killer flag stays in, and I'll put something in
         do_murder. -Narn */
        /*SET_BIT(ch->master->act, PLR_ATTACKER);*/
        /* stop_follower( ch ); */
        return;
    }

    /*
     * NPC's are cool of course (as long as not charmed).
     * And current killers stay as they are.
     */
    if ( IS_NPC(ch)
         ||   IS_SET(ch->act, PLR_ATTACKER)
         ||   IS_SET(ch->act, PLR_KILLER) )
        return;

    log_printf_plus(LOG_MONITOR, LEVEL_IMMORTAL, SEV_NOTICE, "check_attacker: %s attacking %s, setting ATTACKER", GET_NAME(ch), GET_NAME(victim));

    SET_BIT(ch->act, PLR_ATTACKER);
    save_char_obj( ch );
    return;
}


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

    if ( GET_HIT(victim) > 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) || GET_HIT(victim) <= -11 )
    {
        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->position == POS_FIGHTING && !victim->fighting )
        victim->position = POS_STANDING;

    if ( GET_HIT(victim) <= -6 ) victim->position = POS_MORTAL;
    else if ( GET_HIT(victim) <= -3 ) 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 == victim )
    {
        bug( "Set_fighting: %s fighting self?", GET_NAME(ch) );
        return;
    }

    if ( ch->fighting )
    {
        bug( "Set_fighting: %s -> %s (already fighting %s)",
             GET_NAME(ch), GET_NAME(ch), GET_NAME(ch->fighting->who) );
        return;
    }

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

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

    CREATE( fight, FIGHT_DATA, 1 );
    fight->who	 = 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!\n\r", victim->switched );
        do_return( victim->switched, "" );
    }
    return;
}


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

void free_fight( CHAR_DATA *ch )
{
    if ( !ch )
    {
        bug( "Free_fight: null ch!" );
        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("\n\r", ch);
        act( AT_WEAROFF, skill_table[gsn_berserk]->msg_off_room, ch, NULL, NULL, TO_ROOM );
    }
    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;
}


/*
 * Improved Death_cry contributed by Diavolo.
 * Additional improvement by Thoric (and removal of turds... sheesh!)
 */
void death_cry( CHAR_DATA *ch )
{
    ROOM_INDEX_DATA *was_in_room;
    char *msg;
    EXIT_DATA *pexit;
    int vnum;

    if ( !ch )
    {
        bug( "DEATH_CRY: null ch!" );
        return;
    }

    vnum = 0;
    switch ( number_bits( 4 ) )
    {
    default: msg  = "You hear $n's death cry.";				break;
    case  0: msg  = "$n hits the ground ... DEAD.";			break;
    case  1: msg  = "$n splatters blood on your armor.";		break;
    case  2: if ( HAS_BODYPART(ch, PART_GUTS) )
    {
        msg  = "$n's guts spill all over the ground.";
        vnum = OBJ_VNUM_SPILLED_GUTS;
    }
    else
        msg = "$n collapses lifeless to the ground.";
    break;
    case  3: if ( HAS_BODYPART(ch, PART_HEAD) )
    {
        msg  = "$n's severed head plops on the ground.";
        vnum = OBJ_VNUM_SEVERED_HEAD;
    }
    else
        msg = "You hear $n's death cry.";
    break;
    case  4: if ( HAS_BODYPART(ch, PART_HEART) )
    {
        msg  = "$n's heart is torn from $s chest.";
        vnum = OBJ_VNUM_TORN_HEART;
    }
    else
        msg = "$n collapses lifeless to the ground.";
    break;
    case  5: if ( HAS_BODYPART(ch, PART_ARMS) )
    {
        msg  = "$n's arm is sliced from $s dead body.";
        vnum = OBJ_VNUM_SLICED_ARM;
    }
    else
        msg = "You hear $n's death cry.";
    break;
    case  6: if ( HAS_BODYPART(ch, PART_LEGS) || HAS_BODYPART(ch, PART_FORELEGS) )
    {
        msg  = "$n's leg is sliced from $s dead body.";
        vnum = OBJ_VNUM_SLICED_LEG;
    }
    else
        msg = "$n collapses lifeless to the ground.";
    break;
    }

    act( AT_CARNAGE, msg, ch, NULL, NULL, TO_ROOM );

    if ( vnum )
    {
        char buf[MAX_STRING_LENGTH];
        OBJ_DATA *obj;
        char *name;

        name		= IS_NPC(ch) ? ch->short_descr : ch->name;
        obj		= create_object( vnum );
        if (obj) {
            obj->timer	= number_range( 4, 7 );

            sprintf( buf, obj->short_descr, name );
            STRFREE( obj->short_descr );
            obj->short_descr = STRALLOC( buf );

            sprintf( buf, obj->description, name );
            STRFREE( obj->description );
            obj->description = STRALLOC( buf );

            obj = obj_to_room( obj, ch->in_room );
        }
    }

    if ( IS_NPC(ch) )
        msg = "You hear something's death cry.";
    else
        msg = "You hear someone's death cry.";

    was_in_room = ch->in_room;
    for ( pexit = was_in_room->first_exit; pexit; pexit = pexit->next )
    {
        if ( pexit->to_room
             &&   pexit->to_room != was_in_room )
        {
            ch->in_room = pexit->to_room;
            act( AT_CARNAGE, msg, ch, NULL, NULL, TO_ROOM );
        }
    }
    ch->in_room = was_in_room;

    return;
}



void raw_kill( CHAR_DATA *ch, CHAR_DATA *victim, int dt )
{
    CHAR_DATA *victmp;
    int tpos = 0;

    /*    char buf[MAX_STRING_LENGTH]; */

    if ( !victim )
    {
        bug( "raw_kill: null victim!" );
        return;
    }
    /* backup in case hp goes below 1 */
    if (NOT_AUTHED(victim))
    {
        bug( "raw_kill: killing unauthed" );
        return;
    }

    stop_fighting( victim, TRUE );

    if (IS_SYSTEMFLAG(SYS_NOKILL))
    {
        GET_POS(ch) = POS_STANDING;
        GET_POS(victim) = POS_STANDING;
        GET_HIT(victim) 	= UMAX( 1, GET_HIT(victim)  );
        GET_MANA(victim)	= UMAX( 1, GET_MANA(victim) );
        GET_MOVE(victim)	= UMAX( 1, GET_MOVE(victim) );
        return;
    }

    /* 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, "");
        raw_kill(ch, victmp, dt);
        return;
    }

#ifdef VTRACK
    if (IS_NPC(victim))
        vtrack_add_mobkill(ch, victim->vnum);
#endif

    tpos = GET_POS(ch);

    GET_POS(ch) = POS_STANDING;

    if (IS_NPC(victim))
        quest_trigger_mobkill(ch, victim);

    mprog_death_trigger( ch, victim );
    if ( char_died(victim) )
        return;
    /* death_cry( victim ); */

    rprog_death_trigger( ch, victim );
    if ( char_died(victim) )
        return;

    GET_POS(ch) = tpos;

    make_corpse( victim, ch, dt );
    make_blood( victim );

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

    set_char_color( AT_DIEMSG, victim );

    if (in_arena(victim))
    {
        recall_char(victim);
        ch->position = POS_RESTING;
        do_look( victim, "auto" );
        return;
    }

    do_help(victim, "_DIEMSG_" );

    extract_char( victim, FALSE );
    if ( !victim )
    {
        bug( "oops! raw_kill: extract_char destroyed pc char" );
        return;
    }
    while ( victim->first_affect )
        affect_remove( victim, victim->first_affect );
    victim->affected_by	= race_table[victim->race].affected;
    victim->affected_by2 = 0;
    victim->resistant   = 0;
    victim->susceptible = 0;
    victim->immune      = 0;
    victim->carry_weight= 0;
    victim->armor	= 100;
    victim->mod_str	= 0;
    victim->mod_dex	= 0;
    victim->mod_wis	= 0;
    victim->mod_int	= 0;
    victim->mod_con	= 0;
    victim->mod_cha	= 0;
    victim->mod_lck   	= 0;
    victim->damroll	= 0;
    victim->hitroll	= 0;
    victim->mental_state = -10;
    GET_ALIGN(victim)	= URANGE( -1000, GET_ALIGN(victim), 1000 );
    victim->saving_spell_staff = 0;
    victim->position	= POS_RESTING;
    GET_HIT(victim)	= UMAX( 1, GET_HIT(victim)  );
    GET_MANA(victim)	= UMAX( 1, GET_MANA(victim) );
    GET_MOVE(victim)	= UMAX( 1, GET_MOVE(victim) );
    stop_hunting(ch);
    stop_hating(ch);

    /*
     * Pardon crimes...						-Thoric
     */
    if ( IS_SET( victim->act, PLR_KILLER) )
    {
        REMOVE_BIT( victim->act, PLR_KILLER);
        send_to_char("The gods have pardoned you for your murderous acts.\n\r",victim);
    }
    if ( IS_SET( victim->act, PLR_THIEF) )
    {
        REMOVE_BIT( victim->act, PLR_THIEF);
        send_to_char("The gods have pardoned you for your thievery.\n\r",victim);
    }

    /* for resur/reinc code - Heath */
    SET_BIT(victim->act2, PLR2_DIED);

    victim->pcdata->condition[COND_FULL]   = MAX_COND_VAL;
    victim->pcdata->condition[COND_THIRST] = MAX_COND_VAL;
    if ( IS_VAMPIRE( victim ) )
        victim->pcdata->condition[COND_BLOODTHIRST] = (GetMaxLevel(victim) / 2);

    if ( IS_SET( sysdata.save_flags, SV_DEATH ) )
        save_char_obj( victim );

    do_look( victim, "auto" );
    return;
}


static void group_gain( CHAR_DATA *ch, CHAR_DATA *victim )
{
    char buf[MAX_STRING_LENGTH];
    CHAR_DATA *gch;
    CHAR_DATA *lch;
    int xp, max_level = 0, share, diff;
    int members = 0, member_level = 1, npcs = 0;

    /*
     * 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) && !ch->master) || victim == ch )
        return;

    if ( !IS_NPC(victim) )
        return;

    for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
    {
        if ( !is_same_group( gch, ch ) )
            continue;
	if ( IS_NPC( gch ) )
	    npcs++;
	else
	{
	    members++;
	    max_level = UMAX(max_level, GetMaxLevel(gch));
	    member_level += GetAveLevel(gch);
	}
    }

    if ( members == 0 )
    {
        bug( "Group_gain: %s's group has 0 members", GET_NAME(ch) );
        members = 1;
    }

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

    share = GET_EXP(victim) / member_level;

    for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
    {
        if ( !is_same_group( gch, ch ) || IS_NPC( gch ) )
            continue;

        xp = share * GetAveLevel(gch);
        xp *= (100 + members);
        xp /= 100;
        diff = max_level - GetMaxLevel(gch);
        if (diff >= 10)
            xp /= ((diff / 10) + 1);
        /* aggressive calc */
        /* level mod calc */
	if (IS_SYSTEMFLAG(SYS_FREEXP))
	    xp = UMIN(xp, 5000000);
	else if (members > 8)
            xp = UMIN(xp, 2000000);
        else
            xp = UMIN(xp, ((members * 100000) + (npcs * 10000) + 100000));
        xp = UMAX(xp, 0);

        GET_ALIGN(gch) = align_compute( gch, victim );
        sprintf( buf, "%sYou receive %d experience points.\n\r", color_str(AT_PLAIN,gch), xp );
        send_to_char( buf, gch );
        gain_exp( gch, xp ); /* group gain */
        align_zap(ch);
    }

    return;
}

static int align_compute( CHAR_DATA *ch, CHAR_DATA *victim )
{
    int change;

    if (IS_NPC(ch) && !IS_ACT_FLAG(ch,ACT_POLYMORPHED))
        return GET_ALIGN(ch);

    if (in_arena(ch))
        return GET_ALIGN(ch);

    change = GET_ALIGN(victim)/10;

    return (URANGE(-1000, GET_ALIGN(ch)-change, 1000));
}

static void align_zap(CHAR_DATA *ch)
{
    OBJ_DATA *obj, *obj_next;

    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(ch)    )
             ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_GOOD)    && IS_GOOD(ch)    )
             ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch) ) )
        {
            act( AT_MAGIC, "You are zapped by $p.", ch, obj, NULL, TO_CHAR );
            act( AT_MAGIC, "$n is zapped by $p.",   ch, obj, NULL, TO_ROOM );

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

bool cant_hit_part(int part)
{
    if (part==PART_BRAINS)
        return TRUE;

    if (part==PART_LONG_TONGUE)
        return TRUE;

    if (part==PART_SHARPSCALES)
        return TRUE;

    if (part==PART_TAILATTACK)
        return TRUE;

    if (part==PART_HEART)
        return TRUE;

    return FALSE;
}

int RandomBodyPart(CHAR_DATA *ch)
{
    int i = number_range(0, 31);

    if (!ch)
        return(0);

    if (ch->xflags == 0)
        ch->xflags = race_bodyparts(ch);

    if (ch->xflags == 0)
        return(0);

    while (!HAS_BODYPART(ch, 1<<i) || cant_hit_part(1<<i))
        i = number_range(0,31);

    return(i);
}

static void dam_message( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt )
{
    char buf1[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH], buf3[MAX_INPUT_LENGTH];
    struct skill_type *skill = NULL;
    int snum = 0, hitloc = 0;

    static struct dam_weapon_type {
        char *to_room;
        char *to_char;
        char *to_victim;
    } dam_weapons[] = {
        {
            "$n misses $N with a wild swing.",                 /*    0    */
            "You miss $N.",
            "$n misses you with a wild swing."
        },
        {
            "$n bruises $N with $s %s %s.",                       /*  1.. 2  */
            "You bruise $N as you %s $M %s.",
            "$n bruises you as $e %s your %s."
        },
        {
            "$n barely %s $N %s.",                            /*  3.. 4  */
            "You barely %s $N %s.",
            "$n barely %s your %s."
        },
        {
            "$n %s $N %s.",                                   /*  5.. 6  */
            "You %s $N %s.",
            "$n %s your %s."
        },
        {
            "$n %s $N hard %s.",                               /*  7..10  */
            "You %s $N hard %s.",
            "$n %s you hard on your %s."
        },
        {
            "$n %s $N very hard %s.",                         /* 11..14  */
            "You %s $N very hard %s.",
            "$n %s you very hard on your %s."
        },
        {
            "$n %s $N extremely well %s.",                  /* 15..20  */
            "You %s $N extremely well %s.",
            "$n %s you extremely well on your %s."
        },
        {
            "$n ravages $N with $s %s %s.",
            "You ravage $N with your %s %s.",
            "$n ravages you with $s %s on your %s."
        },
        {
            "$n butchers $N with $s %s %s.",
            "You butcher $N with your %s %s.",
            "$n butchers you with $s %s on your %s."
        },
        {
            "$n demolishes $N with $s %s %s.",
            "You demolish $N with your %s %s.",
            "$n demolishes you with $s %s on your %s."
        },
        {
            "$n slaughters $N with $s %s %s.",
            "You slaughter $N with your %s %s.",
            "$n slaughters you with $s %s on your %s."
        },
        {
            "$n pulverizes $N with $s %s %s.",
            "You pulverize $N with your %s %s.",
            "$n pulverizes you with $s %s on your %s."
        },
        {
            "$n massacres $N with $s %s %s.",
            "You massacre $N with your %s %s.",
            "$n massacres you with $s %s on your %s."
        },
        {
            "$n decimates $N with $s %s %s.",
            "You decimate $N with your %s %s.",
            "$n decimates you with $s %s on your %s."
        },
        {
            "$n devastates $N with $s %s %s.",
            "You devastate $N with your %s %s.",
            "$n tears you up with $s %s on your %s."
        },
        {
            "$n extirpates $N with $s %s %s.",
            "You extirpate $N with your %s %s.",
            "$n extirpates you with $s %s on your %s."
        },
        {
            "$n obliterates $N with $s %s %s.",
            "You obliterate $N with your %s %s.",
            "$n obliterates you with $s %s on your %s."
        },
        {
            "$n vaporizes $N with $s %s %s.",
            "You vaporize $N with your %s %s.",
            "$n vaporizes you with $s %s on your %s."
        },
        {
            "$n atomizes $N with $s %s %s.",
            "You atomize $N with your %s %s.",
            "$n atomizes you with $s %s on your %s."
        },
        {
            "$n disembowels $N with $s %s %s.",
            "You disembowel $N with your %s %s.",
            "$n disembowels you with $s %s on your %s."
        },
        {
            "$n eviscerates $N with $s %s %s.",
            "You eviscerate $N with your %s %s.",
            "$n eviscerates you with $s %s on your %s."
        },
        {
            "$n incinerates $N with $s %s %s.",
            "You incinerate $N with your %s %s.",
            "$n incinerates you with $s %s on your %s."
        }
    };

    if ( dt==TYPE_UNDEFINED )
    {
	log_printf_plus(LOG_MAGIC, LEVEL_LOG_CSET, SEV_DEBUG+1,
			"dam_message: undefined dt");
        return;
    }

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

    buf1[0]=buf2[0]=buf3[0]='\0';

    if ( dt >= TYPE_HIT )
    {
        if (dam <= 0) {
            snum = 0;
        } else if (dam <= 2) {
            snum = 1;
        } else if (dam <= 4) {
            snum = 2;
        } else if (dam <= 10) {
            snum = 3;
        } else if (dam <= 15) {
            snum = 4;
        } else if (dam <= 25) {
            snum = 5;
        } else if (dam <= 30) {
            snum = 6;
        } else if (dam <= 34) {
            snum = 7; /* ravage */
        } else if (dam <= 38) {
            snum = 8; /* butcher */
        } else if (dam <= 41) {
            snum = 9; /* demolish */
        } else if (dam <= 44) {
            snum = 10; /* slaughter */
        } else if (dam <= 47) {
            snum = 11; /* pulverize */
        } else if (dam <= 50) {
            snum = 12; /* massacre */
        } else if (dam <= 53) {
            snum = 13; /* decimate */
        } else if (dam <= 56) {
            snum = 14; /* devastate */
        } else if (dam <= 59) {
            snum = 15; /* expirate */
        } else if (dam <= 62) {
            snum = 16; /* obliterate */
        } else if (dam <= 66) {
            snum = 17; /* vaporize */
        } else if (dam <= 70) {
            snum = 18; /* atomize */
        } else if (dam <= 72) {
            snum = 19; /* disembowel */
        } else if (dam <= 75) {
            snum = 20; /* eviscerate */
        } else {
            snum = 21; /* incinerate */
        }

        if ( dt >= TYPE_HIT + sizeof(attack_table)/sizeof(attack_table[0]) ||
             dt >= TYPE_HIT + sizeof(attack_table_plural)/sizeof(attack_table_plural[0]) )
        {
            bug( "Dam_message: bad dt %d.", dt );
            dt  = TYPE_HIT;
        }

        hitloc = RandomBodyPart(victim);

        if (IS_NPC(victim) && victim->pIndexData->mudprogs)
        {
            char tbuf[MAX_INPUT_LENGTH];
            sprintf(tbuf, "self set hitloc %s", body_location[hitloc]);
            do_variables(victim, tbuf);
        }

        if (snum==0) {
            sprintf(buf1, "%s", dam_weapons[snum].to_room);
            sprintf(buf2, "%s", dam_weapons[snum].to_char);
            sprintf(buf3, "%s", dam_weapons[snum].to_victim);
        } else if (snum>=2 && snum<=6) {
            sprintf(buf1, dam_weapons[snum].to_room,
                    attack_table_plural[dt-TYPE_HIT],
                    body_location_hit[hitloc]);
            sprintf(buf2, dam_weapons[snum].to_char,
                    attack_table[dt-TYPE_HIT],
                    body_location_hit[hitloc]);
            sprintf(buf3, dam_weapons[snum].to_victim,
                    attack_table_plural[dt-TYPE_HIT],
                    body_location[hitloc]);
        } else {
            sprintf(buf1, dam_weapons[snum].to_room,
                    attack_table[dt-TYPE_HIT],
                    body_location_hit[hitloc]);
            sprintf(buf2, dam_weapons[snum].to_char,
                    attack_table[dt-TYPE_HIT],
                    body_location_hit[hitloc]);
            sprintf(buf3, dam_weapons[snum].to_victim,
                    attack_table[dt-TYPE_HIT],
                    body_location[hitloc]);
        }
    }
    else /* spell dam messages */
    {
        if ( skill )
        {
            bool found1 = FALSE, found2 = FALSE, found3 = FALSE;

            if ( dam < -1 )
            {
                if ( skill->abs_char && skill->abs_char[0] != '\0' ) {
                    act( AT_HIT, skill->abs_char, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_CHAR );
                    found1 = TRUE;
                }
                if ( skill->abs_vict && skill->abs_vict[0] != '\0' ) {
                    act( AT_HITME, skill->abs_vict, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_VICT );
                    found2 = TRUE;
                }
                if ( skill->abs_room && skill->abs_room[0] != '\0' ) {
                    act( AT_ACTION, skill->abs_room, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_NOTVICT );
                    found3 = TRUE;
                }
                if ( !found1 || !found2 || !found3 )
                    log_printf_plus(LOG_MAGIC, LEVEL_LOG_CSET, SEV_DEBUG,
                                    "spell %d is missing an absorb message", dt);
            }
            else if ( dam == -1 )
            {
                if ( skill->imm_char && skill->imm_char[0] != '\0' ) {
                    act( AT_HIT, skill->imm_char, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_CHAR );
                    found1 = TRUE;
                }
                if ( skill->imm_vict && skill->imm_vict[0] != '\0' ) {
                    act( AT_HITME, skill->imm_vict, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_VICT );
                    found2 = TRUE;
                }
                if ( skill->imm_room && skill->imm_room[0] != '\0' ) {
                    act( AT_ACTION, skill->imm_room, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_NOTVICT );
                    found3 = TRUE;
                }
                if ( !found1 || !found2 || !found3 )
                    log_printf_plus(LOG_MAGIC, LEVEL_LOG_CSET, SEV_DEBUG,
                                    "spell %d is missing an immune message", dt);
            }
            else if ( dam == 0 )
            {
                if ( skill->miss_char && skill->miss_char[0] != '\0' ) {
                    act( AT_HIT, skill->miss_char, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_CHAR );
                    found1 = TRUE;
                }
                if ( skill->miss_vict && skill->miss_vict[0] != '\0' ) {
                    act( AT_HITME, skill->miss_vict, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_VICT );
                    found2 = TRUE;
                }
                if ( skill->miss_room && skill->miss_room[0] != '\0' ) {
                    act( AT_ACTION, skill->miss_room, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_NOTVICT );
                    found3 = TRUE;
                }
                if ( !found1 || !found2 || !found3 )
                    log_printf_plus(LOG_MAGIC, LEVEL_LOG_CSET, SEV_DEBUG,
                                    "spell %d is missing a miss message", dt);
            }
            else
            {
                if (GET_POS(victim) != POS_DEAD)
                {
                    if ( skill->hit_char && skill->hit_char[0] != '\0' ) {
                        if ( !SPELL_FLAG(skill, SF_AREA) ||
                             (SPELL_FLAG(skill, SF_AREA) &&
                              strstr(skill->hit_char, "$N")) )
                            act( AT_HIT, skill->hit_char, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_CHAR );
                        found1 = TRUE;
                    }
                    if ( skill->hit_vict && skill->hit_vict[0] != '\0' ) {
                        if ( !SPELL_FLAG(skill, SF_AREA) ||
                             (SPELL_FLAG(skill, SF_AREA) &&
                              strstr(skill->hit_vict, "$N")) )
                            act( AT_HITME, skill->hit_vict, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_VICT );
                        found2 = TRUE;
                    }
                    if ( skill->hit_room && skill->hit_room[0] != '\0' ) {
                        if ( !SPELL_FLAG(skill, SF_AREA) ||
                             (SPELL_FLAG(skill, SF_AREA) &&
                              strstr(skill->hit_room, "$N")) )
                            act( AT_ACTION, skill->hit_room, ch, get_eq_char(ch, WEAR_WIELD), victim, TO_NOTVICT );
                        found3 = TRUE;
                    }
                }
                if ( !found1 || !found2 || !found3 )
                    log_printf_plus(LOG_MAGIC, LEVEL_LOG_CSET, SEV_DEBUG,
                                    "spell %d is missing a hit message", dt);

            }

            if ( found1 || found2 || found3 )
                return;

            /* generic spell hit message here */
	    log_printf_plus(LOG_MAGIC, LEVEL_LOG_CSET, SEV_DEBUG+1,
			    "dam_message: generic spell hit message here");

            return;
        }
    }

    act( AT_ACTION, buf1, ch, NULL, victim, TO_NOTVICT );

    if (IS_NPC(ch) || !IS_SET(ch->pcdata->flags, PCFLAG_GAG))
        act( AT_HIT, buf2, ch, NULL, victim, TO_CHAR );

    if (IS_NPC(victim) || !IS_SET(victim->pcdata->flags, PCFLAG_GAG))
        act( AT_HITME, buf3, ch, NULL, victim, TO_VICT );
}

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

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

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

    victim = who_fighting(bob);

    if (!victim)
    {
        send_to_char( "They aren't fighting anyone!\n\r", ch );
        return;
    }

    if ( !IS_NPC(victim) )
    {
        if ( !IS_SET(victim->act, PLR_KILLER)
             &&   !IS_SET(victim->act, PLR_THIEF) )
        {
            send_to_char( "You must MURDER a player.\n\r", ch );
            return;
        }
    }

    if ( victim == ch )
    {
        send_to_char( "You hit yourself.  Ouch!\n\r", ch );
        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!\n\r", ch );
        return;
    }

    WAIT_STATE( ch, 1 * PULSE_VIOLENCE );
    check_attacker( ch, victim );
    multi_hit( ch, victim, TYPE_UNDEFINED );
    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?\n\r", ch );
        return;
    }

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

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

    if ( is_safe( ch, victim ) )
        return;

    if (!CAN_PKILL(ch) && !CAN_PKILL(victim))
    {

    }

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

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

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

    if (check_illegal_pk( ch, victim ))
    {
        send_to_char("You cannot do that.\n\r", ch);
        return;
    }

    if (!IS_NPC (victim) && !in_arena(ch))
    {
        sprintf( log_buf, "%s: murder %s.", ch->name, victim->name );
        log_string_plus( log_buf, LOG_MONITOR, GetMaxLevel(ch), SEV_NOTICE );
    }

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

bool in_arena( CHAR_DATA *ch )
{

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

    if ( IS_SET( ch->in_room->area->flags, AFLAG_ARENA ) )
        return TRUE;

    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;
}

bool check_illegal_pk( CHAR_DATA *ch, CHAR_DATA *victim )
{
    if (!victim || IS_NPC(victim) || IS_NPC(ch) || ch == victim || in_arena(victim))
        return FALSE;

    if (ch->pcdata->clan && victim->pcdata->clan)
        return FALSE;

    if (!is_same_race_align(ch, victim) &&
        GetMaxLevel(ch) - GetMaxLevel(victim) < 10)
        return FALSE;

    log_printf_plus(LOG_MONITOR, LEVEL_IMMORTAL, SEV_NOTICE,
                    "check_illegal_pk: ch: %s, victim: %s",
                    GET_NAME(ch), GET_NAME(victim));

    if (!CAN_PKILL(victim) || !CAN_PKILL(ch) ||
        GetMaxLevel(ch) - GetMaxLevel(victim) > 10)
    {
        sprintf( log_buf, "%s performing illegal pkill on %s at %d",
                 (IS_NPC(ch) ? ch->short_descr : ch->name),
                 victim->name,
                 victim->in_room->vnum );
        log_string_plus(log_buf,LOG_MONITOR,LEVEL_IMMORTAL,SEV_CRIT);
        return TRUE;
    }

    return FALSE;
}

void do_flee( CHAR_DATA *ch, char *argument )
{
    ROOM_INDEX_DATA *was_in;
    ROOM_INDEX_DATA *now_in;
    int attempt;
    int los = 0;
    bool retreated = FALSE;
    sh_int 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.\n\r", ch );
        return;
    }

    if ( GET_MOVE(ch) <= 0 )
    {
        send_to_char( "You're too exhausted to flee from combat!\n\r", ch );
        act(AT_FLEE, "$n tries to flee but is too exhausted.", ch, NULL, NULL, TO_ROOM);
        return;
    }

    if (GET_POS(ch) == POS_SITTING || GET_POS(ch) == POS_RESTING)
    {
        GET_MOVE(ch) -= 10;
        act(AT_PLAIN, "$n scrambles madly to $s feet!",
            ch, NULL, NULL, TO_ROOM);
        act(AT_PLAIN, "Panic-stricken, you scramble to your feet.",
            ch, NULL, NULL, TO_CHAR);
        GET_POS(ch) = POS_STANDING;
        WAIT_STATE(ch, PULSE_VIOLENCE);
        return;
    }

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

    if (is_affected(ch, gsn_berserk))
    {
        send_to_char("You can think of nothing but the battle.\n\r", ch);
        return;
    }

    if (is_affected(ch, gsn_web))
    {
        if (saves_para_petri(GetMaxLevel(ch), ch))
        {
            send_to_char("You are entrapped in sticky webs!\n\r", ch);
            send_to_char("Your struggles only entrap you further!\n\r", ch);
            act(AT_PLAIN, "$n struggles against webs that bind $s.", ch, NULL, NULL, TO_ROOM);
            WAIT_STATE(ch, PULSE_VIOLENCE);
            GET_MOVE(ch) = 0;
        }
        else
        {
            send_to_char("You briefly pull free from the sticky webbing!\n\r", ch);
            act(AT_PLAIN, "$n briefly pulls free from the webs that bind $s.", ch, NULL, NULL, TO_ROOM);
            GET_MOVE(ch) -= 50;
        }
        return;
    }


    if (!IS_NPC(ch))
        retreated = (number_percent() < LEARNED(ch, gsn_retreat)) ? TRUE : FALSE;

    if (!retreated)
        act(AT_FLEE, "$n panics and attempts to flee!", ch, NULL, NULL, TO_ROOM);

    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;
        if (retreated)
        {
            act( AT_FLEE, "$n skillfully retreats from battle.", ch, NULL, NULL, TO_ROOM );
            act( AT_FLEE, "You skillfully retreat from battle.", ch, NULL, NULL, TO_CHAR );
        }
        else
        {
            act( AT_FLEE, "$n flees head over heels!", ch, NULL, NULL, TO_ROOM );
            act( AT_FLEE, "You flee, head over heels!", ch, NULL, NULL, TO_CHAR );
            learn_from_failure(ch, gsn_retreat);
        }
        ch->in_room = now_in;
        act( AT_FLEE, "$n glances around for signs of pursuit.", ch, NULL, NULL, TO_ROOM );

        if ( !IS_NPC(ch) )
        {
            CHAR_DATA *wf = who_fighting(ch);

	    if (!wf)
	    {
		bug("do_flee: something seriously wrong, !who_fighting(%s)", GET_NAME(ch));
		return;
	    }

            if (GetMaxLevel(ch) > 3) {
                if (!retreated ||
                    !HAS_CLASS(ch, CLASS_WARRIOR) ||
                    !HAS_CLASS(ch, CLASS_BARBARIAN) ||
                    !HAS_CLASS(ch, CLASS_PALADIN) ||
                    !HAS_CLASS(ch, CLASS_ANTIPALADIN) ||
                    !HAS_CLASS(ch, CLASS_RANGER))
                {
                    los = GetMaxLevel(ch) +
                        (GetSecMaxLev(ch)/2) +
                        (GetThirdMaxLev(ch)/3);
                    los -= GetMaxLevel(wf) +
                        (GetSecMaxLev(wf)/2) +
                        (GetThirdMaxLev(wf)/3);
                    los *= GetMaxLevel(ch);
                    if (los < 0)
                        los = 1;
                }
            } else
                los = 0;

            if (IS_NPC(wf) && !IS_ACT_FLAG(wf, ACT_SENTINEL))
            {
                if (IS_ACT_FLAG(wf, ACT_META_AGGR))
                {
                    start_hating(wf, ch);
                    start_hunting(wf, ch);
                }
                else if (IS_ACT_FLAG(wf, ACT_AGGRESSIVE))
                    start_hating(wf, ch);
            }

            if (los)
                gain_exp(ch, -los);


            if ( ch->pcdata->deity )
            {
                if ( wf && wf->race == ch->pcdata->deity->npcrace )
                    adjust_favor( ch, 1, 1 );
                else
                    if ( wf && wf->race == ch->pcdata->deity->npcfoe )
                        adjust_favor( ch, 16, 1 );
                    else
                        adjust_favor( ch, 0, 1 );
            }
        }
        stop_fighting( ch, TRUE );
        return;
    }

    send_to_char("PANIC! You couldn't escape!\n\r", ch);
    return;
}



void do_sla( CHAR_DATA *ch, char *argument )
{
    send_to_char( "If you want to SLAY, spell it out.\n\r", 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?\n\r", ch );
        return;
    }

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

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

    if ( !IS_NPC(victim) && get_trust( victim ) >= get_trust( ch ) )
    {
        send_to_char( "You failed.\n\r", 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 if ( !str_cmp( arg2, "cow" ) && get_trust(ch) >= LEVEL_ASCENDANT )
    {
        act( AT_WHITE, "You summon the cow spirits to do harm to $N.", ch, NULL, victim, TO_CHAR );
        act( AT_WHITE, "$n summons a giant cow which procedes to chew your head off.", ch, NULL, victim, TO_VICT );
        act( AT_WHITE, "$n summons a giant cow which procedes to chew $N's head off.", 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, TYPE_UNDEFINED );
    return;
}

int BarbarianToHitMagicBonus(CHAR_DATA *ch)
{
    if (GetMaxLevel(ch) <= 7)
        return 1;
    if (GetMaxLevel(ch) <= 13)
        return 2;
    if (GetMaxLevel(ch) <= 20)
        return 3;
    if (GetMaxLevel(ch) <= 28)
        return 4;
    if (GetMaxLevel(ch) <= 35)
        return 5;
    if (GetMaxLevel(ch) <= 50)
        return 5;

    return(6);
}

int berserkthaco(CHAR_DATA *ch)
{
    if (GetMaxLevel(ch) <= 10) /* -5 to hit when berserked */
        return(5);
    if (GetMaxLevel(ch) <= 25) /* -3 */
        return(3);
    if (GetMaxLevel(ch) <= 40) /* -2 */
        return(2);

    return(1);
}

int berserkdambonus(CHAR_DATA *ch, int dam)
{
    if (GetMaxLevel(ch) <= 10)     /* 1.33 dam when berserked */
        return((int)((float)dam*1.33));
    if (GetMaxLevel(ch) <= 25)     /* 1.5 */
        return((int)((float)dam*1.5));
    if (GetMaxLevel(ch) <= 40)     /* 1.7 */
        return((int)((float)dam*1.7));
    if (GetMaxLevel(ch) <= 50)     /* 1.8 */
        return((int)((float)dam*1.8));
    if (GetMaxLevel(ch) <= 60)     /* 1.8 */
        return((int)((float)dam*1.9));

    return((int)((float)dam*1.8));
}

int CalcThaco(CHAR_DATA *ch)
{
    int calc_thaco;

    /* Calculate the raw armor including magic armor */
    /* The lower AC, the better                      */

    if (!IS_NPC(ch))
        calc_thaco = thaco[BestFightingClass(ch)][GET_LEVEL(ch, BestFightingClass(ch))];
    else
        /* THAC0 for monsters is set in the HitRoll */
        calc_thaco = 20;

    /*  Drow are -4 to hit during daylight or lighted rooms. */
    if (!room_is_dark(ch->in_room) && GET_RACE(ch) == RACE_DROW && !IS_NPC(ch) &&
        !is_affected(ch,gsn_darkness) && !IS_UNDERGROUND(ch))
        calc_thaco +=4;

    if (!room_is_dark(ch->in_room) && GET_RACE(ch) == RACE_UNDEAD_VAMPIRE)
        calc_thaco +=4;

    if (IS_AFFECTED(ch,AFF_BERSERK))
        calc_thaco += berserkthaco(ch);

    if (IS_IMMUNE(ch, RIS_EVIL) || IS_RESIS(ch, RIS_EVIL))
        if (ch->fighting)
            if (IS_EVIL(who_fighting(ch))) calc_thaco -=1;

    /* you get -4 to hit a mob if your evil and he has */
    /* prot from evil */
    if (who_fighting(ch) && IS_EVIL(ch))
        if (IS_IMMUNE(who_fighting(ch), RIS_EVIL) ||
            IS_RESIS(who_fighting(ch), RIS_EVIL))
            calc_thaco+=4;

    calc_thaco -= str_app[get_curr_str(ch)].tohit;
    calc_thaco -= GET_HITROLL(ch);
    calc_thaco += IS_NPC(ch)?0:(GET_COND(ch, COND_DRUNK)/5);
    return calc_thaco;
}

int HitOrMiss(CHAR_DATA *ch, CHAR_DATA *victim, int calc_thaco)
{
    int diceroll, victim_ac;

    diceroll = number_range(1,20);

    victim_ac  = GET_AC(victim)/10;

    if (!IS_AWAKE(victim))
        victim_ac -= dex_app[get_curr_dex(victim)].defensive;

    victim_ac = UMAX(-10, victim_ac);  /* -10 is lowest */

    if (diceroll < 20 && IS_AWAKE(victim) &&
        (diceroll==1 || calc_thaco-diceroll > victim_ac))
        return FALSE;

    return TRUE;
}

CHAR_DATA *race_align_hatee(CHAR_DATA *ch)
{
    CHAR_DATA *vch;

    for (vch=ch->in_room->first_person;vch;vch=vch->next_in_room)
    {
        if (!IS_NPC(vch) && IS_IMMORTAL(vch))
            continue;
        if (char_died(vch))
            continue;
        if (can_see(ch,vch) &&
            ((IsBadSide(vch) && IsGoodSide(ch)) ||
             (IsGoodSide(vch) && IsBadSide(ch)) ||
             (IsUndead(vch) && !IsUndead(ch)) ||
             (!IsUndead(vch) && IsUndead(ch))))
            return vch;
    }

    return NULL;
}

int lorebonus(CHAR_DATA *ch, CHAR_DATA *victim, int sn)
{
    int mult=0, loresn=-1;

    if (IsAnimal(victim))
        loresn = gsn_animal_lore;
    else if (IsVeggie(victim))
        loresn = gsn_vegetable_lore;
    else if (IsDiabolic(victim))
        loresn = gsn_demonology;
    else if (IsReptile(victim))
        loresn = gsn_reptile_lore;
    else if (IsUndead(victim))
        loresn = gsn_necromancy;
    else if (IsGiantish(victim) || IsGiant(victim))
        loresn = gsn_giant_lore;
    else if (IsPerson(victim))
        loresn = gsn_people_lore;
    else if (IsOther(victim))
        loresn = gsn_other_lore;
    else
        return 0;

    if (loresn == -1)
    {
        bug("lorebonus: unknown lore");
        return 0;
    }

    if (LEARNED(ch, loresn) > 40)
        mult += 1;
    if (LEARNED(ch, loresn) > 74)
        mult += 1;

    if (mult > 0)
        send_to_char("Your lore aids your attack!\n\r", ch);

    return mult;
}

bool life_protection_object(CHAR_DATA *ch)
{
    OBJ_DATA *obj, *obj_next;
    AFFECT_DATA *paf;

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

        for (paf = obj->first_affect; paf; paf = paf->next)
            if (paf->location == APPLY_AFF2 &&
                IS_SET(paf->modifier, AFF2_LIFE_PROT))
            {
                act(AT_PLAIN, "$p shatters with a blinding flash of light!", ch, obj, NULL, TO_CHAR);
                make_scraps(obj,TRUE);
                return TRUE;
            }

        /*
        if (!obj->pIndexData)
            continue;
        for (paf = obj->pIndexData->first_affect; paf; paf = paf->next)
            if (paf->location == APPLY_AFF2 &&
                IS_SET(paf->modifier, AFF2_LIFE_PROT))
            {
                act(AT_PLAIN, "$p shatters with a blinding flash of light!", ch, obj, NULL, TO_CHAR);
                make_scraps(obj,TRUE);
                return TRUE;
            }
        */
    }

    return FALSE;
}