/*
 * $Id: fight.c,v 1.165 1999/04/24 11:08:19 kostik Exp $
 */

/***************************************************************************
 *     ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR  *
 *     ANATOLIA has been brought to you by ANATOLIA consortium		   *
 *	 Serdar BULUT {Chronos} 	bulut@rorqual.cc.metu.edu.tr	   *
 *	 Ibrahim Canpunar  {Asena}	canpunar@rorqual.cc.metu.edu.tr    *
 *	 Murat BICER  {KIO}		mbicer@rorqual.cc.metu.edu.tr	   *
 *	 D.Baris ACAR {Powerman}	dbacar@rorqual.cc.metu.edu.tr	   *
 *     By using this code, you have agreed to follow the terms of the	   *
 *     ANATOLIA license, in the file Anatolia/anatolia.licence		   *
 ***************************************************************************/

/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,	   *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *									   *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael	   *
 *  Chastain, Michael Quan, and Mitchell Tse.				   *
 *									   *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc	   *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.						   *
 *									   *
 *  Much time and thought has gone into this software and you are	   *
 *  benefitting.  We hope that you share your changes too.  What goes	   *
 *  around, comes around.						   *
 ***************************************************************************/

/***************************************************************************
*	ROM 2.4 is copyright 1993-1995 Russ Taylor			   *
*	ROM has been brought to you by the ROM consortium		   *
*	    Russ Taylor (rtaylor@pacinfo.com)				   *
*	    Gabrielle Taylor (gtaylor@pacinfo.com)			   *
*	    Brian Moore (rom@rom.efn.org)				   *
*	By using this code, you have agreed to follow the terms of the	   *
*	ROM license, in the file Rom24/doc/rom.license			   *
***************************************************************************/

#include <sys/types.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>

#if !defined (WIN32)
#	include <unistd.h>
#endif

#include "merc.h"
#include "quest.h"
#include "fight.h"
#include "rating.h"
#include "update.h"
#include "mob_prog.h"
#include "obj_prog.h"

DECLARE_DO_FUN(do_crush		);
DECLARE_DO_FUN(do_emote		);
DECLARE_DO_FUN(do_dismount	);
DECLARE_DO_FUN(do_bash		);
DECLARE_DO_FUN(do_berserk	);
DECLARE_DO_FUN(do_disarm	);
DECLARE_DO_FUN(do_kick		);
DECLARE_DO_FUN(do_dirt		);
DECLARE_DO_FUN(do_trip		);
DECLARE_DO_FUN(do_tail		);
DECLARE_DO_FUN(do_look_in	);
DECLARE_DO_FUN(do_get		);
DECLARE_DO_FUN(do_sacrifice	);
DECLARE_DO_FUN(do_visible	);
DECLARE_DO_FUN(do_recall	);
DECLARE_DO_FUN(do_flee		);
DECLARE_DO_FUN(do_clan		);

/*
 * Local functions.
 */
void	check_assist		(CHAR_DATA *ch, CHAR_DATA *victim);
bool	check_dodge		(CHAR_DATA *ch, CHAR_DATA *victim);
bool	check_parry		(CHAR_DATA *ch, CHAR_DATA *victim, int loc);
bool	check_block		(CHAR_DATA *ch, CHAR_DATA *victim, int loc);
bool	check_blink		(CHAR_DATA *ch, CHAR_DATA *victim);
bool	check_hand_block	(CHAR_DATA *ch, CHAR_DATA *victim);
void	dam_message		(CHAR_DATA *ch, CHAR_DATA *victim, int dam,
				 int dt, bool immune, int dam_type);
void	death_cry		(CHAR_DATA *ch);
void	death_cry_org		(CHAR_DATA *ch, int part);
void	group_gain		(CHAR_DATA *ch, CHAR_DATA *victim);
int	xp_compute		(CHAR_DATA *gch, CHAR_DATA *victim,
				 int total_levels, int members);
bool	is_safe 		(CHAR_DATA *ch, CHAR_DATA *victim);

void	make_corpse		(CHAR_DATA *ch);
void	one_hit 		(CHAR_DATA *ch, CHAR_DATA *victim, int dt,
				 int loc);
void	mob_hit 		(CHAR_DATA *ch, CHAR_DATA *victim, int dt);
void	set_fighting		(CHAR_DATA *ch, CHAR_DATA *victim);
void	disarm			(CHAR_DATA *ch, CHAR_DATA *victim,
				 int disarm_second);
int	critical_strike		(CHAR_DATA *ch, CHAR_DATA *victim, int dam);
void	check_eq_damage		(CHAR_DATA *ch, CHAR_DATA *victim, int loc);
void	check_shield_damage	(CHAR_DATA *ch, CHAR_DATA *victim, int loc);
void	check_weapon_damage	(CHAR_DATA *ch, CHAR_DATA *victim, int loc);
int 	check_forest		(CHAR_DATA *ch);

#define FOREST_ATTACK 1
#define FOREST_DEFENCE 2
#define FOREST_NONE 0

void	handle_death		(CHAR_DATA *ch, CHAR_DATA *victim);

/*
 * Gets all money from the corpse.
 */
void get_gold_corpse(CHAR_DATA *ch, OBJ_DATA *corpse)
{
	OBJ_DATA *tmp, *tmp_next;
	for (tmp = corpse->contains; tmp; tmp = tmp_next) {
		tmp_next = tmp->next_content;
		if (tmp->pIndexData->item_type == ITEM_MONEY)
			get_obj(ch, tmp, corpse);
	}
}

int check_forest(CHAR_DATA* ch)
{
	AFFECT_DATA* paf;

	if (ch->in_room->sector_type != SECT_FOREST
	&& ch->in_room->sector_type != SECT_HILLS
	&& ch->in_room->sector_type != SECT_MOUNTAIN) 
		return FOREST_NONE;
	for (paf = ch->affected; paf; paf = paf->next) {
		if (paf->type == gsn_forest_fighting) {
			if (paf->location == APPLY_AC) 
				return FOREST_DEFENCE;
			else 
				return FOREST_ATTACK;
		}
	}
	return FOREST_NONE;
}



/*
 * Control the fights going on.
 * Called periodically by update_handler.
 */
void violence_update(void)
{
	CHAR_DATA *ch;
	CHAR_DATA *ch_next;
	CHAR_DATA *victim;
	OBJ_DATA *obj;
	OBJ_DATA *obj_next;

	for (ch = char_list; ch; ch = ch_next) {
		ch_next = ch->next;

		/* decrement the wait */
		if (ch->desc == NULL)
			ch->wait = UMAX(0, ch->wait - PULSE_VIOLENCE);

		if ((victim = ch->fighting) == NULL || ch->in_room == NULL)
			continue;

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

		if ((victim = ch->fighting) == NULL)
			continue;

		if (!IS_NPC(victim))
			ch->last_fought = victim;

		SET_FIGHT_TIME(ch);

		if (victim->in_room != ch->in_room)
			continue;

		for (obj = ch->carrying; obj; obj = obj_next) {
			obj_next = obj->next_content;
			if (ch->fighting == NULL)
				break;
			oprog_call(OPROG_FIGHT, obj, ch, NULL);
		}

		if ((victim = ch->fighting) == NULL
		||  victim->in_room != ch->in_room)
			continue;

		/*
		 * Fun for the whole family!
		 */
		check_assist(ch, victim);
		if (IS_NPC(ch)) {
			if (HAS_TRIGGER(ch, TRIG_FIGHT))
				mp_percent_trigger(ch, victim, NULL, NULL,
						   TRIG_FIGHT);
			if (HAS_TRIGGER(ch, TRIG_HPCNT))
				mp_hprct_trigger(ch, victim);
		}
	}
}

/* for auto assisting */
void check_assist(CHAR_DATA *ch,CHAR_DATA *victim)
{
	CHAR_DATA *rch, *rch_next;

	for (rch = ch->in_room->people; rch != NULL; rch = rch_next) {
		rch_next = rch->next_in_room;

		if (IS_AWAKE(rch) && rch->fighting == NULL) {
		    /* quick check for ASSIST_PLAYER */
		    if (!IS_NPC(ch) && IS_NPC(rch)
		    &&  IS_SET(rch->pIndexData->off_flags, ASSIST_PLAYERS)
		    &&	rch->level + 6 > victim->level) {
			do_emote(rch, "screams and attacks!");
			multi_hit(rch,victim,TYPE_UNDEFINED);
			continue;
		    }

		    /* PCs next */
		    if (!IS_NPC(rch) || IS_AFFECTED(rch, AFF_CHARM)) {
			if (((!IS_NPC(rch) &&
			      IS_SET(rch->plr_flags, PLR_AUTOASSIST)) ||
			     IS_AFFECTED(rch, AFF_CHARM))
			&&  is_same_group(ch,rch)
			&&  !is_safe_nomessage(rch, victim))
			    multi_hit (rch,victim,TYPE_UNDEFINED);
				continue;
		    }

		    if (!IS_NPC(ch) && RIDDEN(rch) == ch)
		    {
			multi_hit(rch,victim,TYPE_UNDEFINED);
			continue;
		    }

		    /* now check the NPC cases */

		    if (IS_NPC(ch)) {
			if ((IS_NPC(rch) && IS_SET(rch->pIndexData->off_flags,ASSIST_ALL))
			||   (IS_NPC(rch) && rch->race == ch->race
			   && IS_SET(rch->pIndexData->off_flags,ASSIST_RACE))
			||   (IS_NPC(rch) && IS_SET(rch->pIndexData->off_flags,ASSIST_ALIGN)
			   &&	((IS_GOOD(rch)	  && IS_GOOD(ch))
			     ||  (IS_EVIL(rch)	  && IS_EVIL(ch))
			     ||  (IS_NEUTRAL(rch) && IS_NEUTRAL(ch))))
			||   (rch->pIndexData == ch->pIndexData
			   && IS_SET(rch->pIndexData->off_flags,ASSIST_VNUM))) {
			    CHAR_DATA *vch;
			    CHAR_DATA *target;
			    int number;

			    if (number_bits(1) == 0)
				continue;

			    target = NULL;
			    number = 0;

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

			    if (target != NULL)
			    {
				do_emote(rch,"screams and attacks!");
				multi_hit(rch,target,TYPE_UNDEFINED);
			    }
			}
		    }
		}
	}
}


/*
 * Do one group of attacks.
 */
void multi_hit(CHAR_DATA *ch, CHAR_DATA *victim, int dt)
{
	int     chance;

	/* no attacks for stunnies -- just a check */
	if (ch->position < POS_RESTING)
		return;

#if 0
	/* become CRIMINAL in Law rooms */
	if (!IS_NPC(ch) && !IS_NPC(victim)
	&& IS_SET(ch->in_room->room_flags, ROOM_LAW)
	&& !IS_SET(victim->plr_flags, PLR_WANTED)
	&& !IS_SET(ch->plr_flags, PLR_WANTED)) {
		char_puts("This room is under supervision of the law! "
			  "Now you're {RCRIMINAL{x!\n", ch);
		SET_BIT(ch->plr_flags, PLR_WANTED);		
	}
#endif

	/* ridden's adjustment */
	if (RIDDEN(victim) && !IS_NPC(victim->mount)) {
		if (victim->mount->fighting == NULL
		|| victim->mount->fighting == ch)
			victim = victim->mount;
		else
			do_dismount(victim->mount, str_empty);
	}

	if (IS_AFFECTED(ch,AFF_WEAK_STUN)) {
		act_puts("You are too stunned to respond $N's attack.",
			 ch, NULL, victim, TO_CHAR, POS_FIGHTING);
		act_puts("$n is too stunned to respond your attack.",
			 ch, NULL, victim, TO_VICT, POS_FIGHTING);
		REMOVE_BIT(ch->affected_by, AFF_WEAK_STUN);
		return;
	}

	if (IS_AFFECTED(ch,AFF_STUN)) {
		act_puts("You are too stunned to respond $N's attack.",
			 ch, NULL, victim, TO_CHAR, POS_FIGHTING);
		act_puts("$n is too stunned to respond your attack.",
			 ch, NULL, victim, TO_VICT, POS_FIGHTING);
		act_puts("$n seems to be stunned.",
			 ch, NULL, victim, TO_NOTVICT, POS_FIGHTING);
		REMOVE_BIT(ch->affected_by, AFF_STUN);
		affect_bit_strip(ch, TO_AFFECTS, AFF_STUN);
		SET_BIT(ch->affected_by, AFF_WEAK_STUN);
		return;
	}

	if (IS_NPC(ch)) {
		mob_hit(ch, victim, dt);
		return;
	}

	one_hit(ch, victim, dt, WEAR_WIELD);

	if (ch->fighting != victim)
		return;

	if ((chance = get_skill(ch, gsn_area_attack))
	&&  number_percent() < chance) {
		int count = 0, max_count;
		CHAR_DATA *vch, *vch_next;

		check_improve(ch, gsn_area_attack, TRUE, 6);

		if (LEVEL(ch) < 70)
			max_count = 1;
		else if (LEVEL(ch) < 80)
			max_count = 2;
		else if (LEVEL(ch) < 90)
			max_count = 3;
		else
			max_count = 4;

		for (vch = ch->in_room->people; vch; vch = vch_next) {
			vch_next = vch->next_in_room;
			if (vch != victim && vch->fighting == ch) {
				one_hit(ch, vch, dt, WEAR_WIELD);
				if (++count == max_count)
					break;
			}
		}
	}

	if (IS_AFFECTED(ch, AFF_HASTE))
		one_hit(ch, victim, dt, WEAR_WIELD);

	if (ch->fighting != victim || dt == gsn_backstab || dt == gsn_cleave
	|| dt == gsn_ambush || dt == gsn_dual_backstab || dt == gsn_circle
	|| dt == gsn_assassinate || dt == gsn_vampiric_bite || dt == gsn_knife)
		return;

	chance = get_skill(ch, gsn_second_attack) / 2;
	if (number_percent() < chance) {
		one_hit(ch, victim, dt, WEAR_WIELD);
		check_improve(ch, gsn_second_attack, TRUE, 5);
		if (ch->fighting != victim)
			return;
	}

	chance = get_skill(ch,gsn_third_attack)/3;
	if (number_percent() < chance) {
		one_hit(ch, victim, dt, WEAR_WIELD);
		check_improve(ch, gsn_third_attack, TRUE, 6);
		if (ch->fighting != victim)
			return;
	}


	chance = get_skill(ch,gsn_fourth_attack)/6;
	if (number_percent() < chance) {
		one_hit(ch, victim, dt, WEAR_WIELD);
		check_improve(ch, gsn_fourth_attack, TRUE, 7);
		if (ch->fighting != victim)
			return;
	}

	chance = get_skill(ch,gsn_fifth_attack)/8;
	if (number_percent() < chance) {
		one_hit(ch, victim, dt, WEAR_WIELD);
		check_improve(ch,gsn_fifth_attack,TRUE,8);
		if (ch->fighting != victim)
		    return;
	}

	if (check_forest(ch) == FOREST_ATTACK) {
		chance = get_skill(ch, gsn_forest_fighting);
		while (number_percent() < chance) {
			one_hit(ch, victim, dt, WEAR_WIELD);
			check_improve (ch, gsn_forest_fighting, TRUE, 8);
			if (ch->fighting != victim)
				return;
			chance /= 3;
		}
	}
		

	chance = get_skill(ch, gsn_second_weapon) / 2;
	if (number_percent() < chance)
		if (get_eq_char(ch, WEAR_SECOND_WIELD)) {
			one_hit(ch, victim, dt, WEAR_SECOND_WIELD);
			check_improve(ch, gsn_second_weapon, TRUE, 2);
			if (ch->fighting != victim)
				return;
		}

	chance = get_skill(ch,gsn_secondary_attack) / 8;
	if (number_percent() < chance)
		if (get_eq_char(ch, WEAR_SECOND_WIELD)) {
			one_hit(ch, victim, dt, WEAR_SECOND_WIELD);
			check_improve(ch, gsn_secondary_attack, TRUE, 2);
			if (ch->fighting != victim)
				return;
		}
}

/* procedure for all mobile attacks */
void mob_hit(CHAR_DATA *ch, CHAR_DATA *victim, int dt)
{
	CHAR_DATA *vch, *vch_next;
	flag64_t act = ch->pIndexData->act;
	flag64_t off = ch->pIndexData->off_flags;

	/* no attack by ridden mobiles except spec_casts */
	if (RIDDEN(ch)) {
		if (ch->fighting != victim) {
			stop_fighting(ch, FALSE);
			set_fighting(ch, victim);
		}
		return;
	}

	one_hit(ch, victim, dt, WEAR_WIELD);

	if (ch->fighting != victim)
		return;

	/* Area attack -- BALLS nasty! */

	if (IS_SET(off, OFF_AREA_ATTACK)) {
		for (vch = ch->in_room->people; vch != NULL; vch = vch_next) {
			vch_next = vch->next_in_room;
			if ((vch != victim && vch->fighting == ch))
				one_hit(ch, vch, dt, WEAR_WIELD);
		}
	}

	if (IS_AFFECTED(ch, AFF_HASTE) || IS_SET(off, OFF_FAST))
		one_hit(ch, victim, dt, WEAR_WIELD);

	if (ch->fighting != victim || dt == gsn_backstab || dt == gsn_circle ||
		dt == gsn_dual_backstab || dt == gsn_cleave || dt == gsn_ambush
			|| dt == gsn_vampiric_bite || dt == gsn_knife)
		return;

	if (number_percent() < get_skill(ch, gsn_second_attack) / 2) {
		one_hit(ch, victim, dt, WEAR_WIELD);
		if (ch->fighting != victim)
			return;
	}

	if (number_percent() < get_skill(ch, gsn_third_attack) / 4) {
		one_hit(ch, victim, dt, WEAR_WIELD);
		if (ch->fighting != victim)
			return;
	}

	if (number_percent() < get_skill(ch, gsn_fourth_attack) / 6) {
		one_hit(ch, victim, dt, WEAR_WIELD);
		if (ch->fighting != victim)
			return;
	}

	/* PC waits */

	if (ch->wait > 0)
		return;

#if 0
	switch (number_range(0, 2)) {
	case 1:
		if (IS_SET(act, ACT_MAGE)) {
			mob_cast_mage(ch, victim);
			return;
		}
		break;
	case 2:
		if (IS_SET(act, ACT_CLERIC)) {
			mob_cast_cleric(ch, victim);
			return;
		}
		break;
	}
#endif

	/* now for the skills */

	switch (number_range(0, 7)) {
	case 0:
		if (IS_SET(off, OFF_BASH))
			do_bash(ch, str_empty);
		break;

	case 1:
		if (IS_SET(off, OFF_BERSERK)
		&&  !IS_AFFECTED(ch, AFF_BERSERK))
			do_berserk(ch, str_empty);
		break;


	case 2:
		if (IS_SET(off, OFF_DISARM)
		||  IS_SET(act, ACT_WARRIOR | ACT_THIEF)) {
			if (number_range(0, 1)
			&&  get_eq_char(victim, WEAR_SECOND_WIELD))
				do_disarm(ch, "second");
			else if (get_eq_char(victim, WEAR_WIELD))
				do_disarm(ch, str_empty);
		}
		break;

	case 3:
		if (IS_SET(off, OFF_KICK))
			do_kick(ch, str_empty);
		break;

	case 4:
		if (IS_SET(off, OFF_DIRT_KICK))
			do_dirt(ch, str_empty);
		break;

	case 5:
		if (IS_SET(off, OFF_TAIL))
			do_tail(ch, str_empty);
		break;

	case 6:
		if (IS_SET(off, OFF_TRIP))
			do_trip(ch, str_empty);
		break;
	case 7:
		if (IS_SET(off, OFF_CRUSH))
			do_crush(ch, str_empty);
		break;
	}
}

int get_dam_type(CHAR_DATA *ch, OBJ_DATA *wield, int *dt)
{
	int dam_type;

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

	if (*dt < TYPE_HIT)
		if (wield)
			dam_type = attack_table[wield->value[3]].damage;
		else
			dam_type = attack_table[ch->dam_type].damage;
	else
		dam_type = attack_table[*dt - TYPE_HIT].damage;

	if (dam_type == TYPE_UNDEFINED)
		dam_type = DAM_BASH;

	return dam_type;
}

/*
 * Hit one guy once.
 */
void one_hit(CHAR_DATA *ch, CHAR_DATA *victim, int dt, int loc)
{
	OBJ_DATA *wield;
	int victim_ac;
	int thac0;
	int thac0_00;
	int thac0_32;
	int dam;
	int diceroll;
	int sn, sk, sk2;
	int dam_type;
	bool counter;
	bool result;
	int sercount;
	int dam_flags;

	sn = -1;
	counter = FALSE;

	/* just in case */
	if (victim == ch || ch == NULL || victim == NULL)
		return;

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

	/*
	 * Figure out the type of damage message.
	 */
	wield = get_eq_char(ch, loc);
	dam_flags = DAMF_SHOW;
	if (loc == WEAR_SECOND_WIELD)
		dam_flags |= DAMF_SECOND;
	dam_type = get_dam_type(ch, wield, &dt);

	/* get the weapon skill */
	sn = get_weapon_sn(wield);
	sk = 20 + get_weapon_skill(ch, sn);

	/*
	 * Calculate to-hit-armor-class-0 versus armor.
	 */
	if (IS_NPC(ch)) {
		flag64_t act = ch->pIndexData->act;

		thac0_00 = 20;
		thac0_32 = -4;	 /* as good as a thief */
		if (IS_SET(act, ACT_WARRIOR))
			thac0_32 = -10;
		else if (IS_SET(act, ACT_THIEF))
			thac0_32 = -4;
		else if (IS_SET(act, ACT_CLERIC))
			thac0_32 = 2;
		else if (IS_SET(act, ACT_MAGE))
			thac0_32 = 6;
	}
	else {
		class_t *cl;

		if ((cl = class_lookup(ch->class)) == NULL)
			return;

		thac0_00 = cl->thac0_00;
		thac0_32 = cl->thac0_32;
	}

	thac0  = interpolate(LEVEL(ch), thac0_00, thac0_32);

	if (thac0 < 0)
		thac0 = thac0/2;

	if (thac0 < -5)
		thac0 = -5 + (thac0 + 5) / 2;

	thac0 -= GET_HITROLL(ch) * sk / 100;
	thac0 += 5 * (100 - sk) / 100;

	if (dt == gsn_backstab)
		thac0 -= 10 * (100 - get_skill(ch, gsn_backstab));
	else if (dt == gsn_dual_backstab)
		thac0 -= 10 * (100 - get_skill(ch, gsn_dual_backstab));
	else if (dt == gsn_cleave)
		thac0 -= 10 * (100 - get_skill(ch, gsn_cleave));
	else if (dt == gsn_ambush)
		thac0 -= 10 * (100 - get_skill(ch, gsn_ambush));
	else if (dt == gsn_vampiric_bite)
		thac0 -= 10 * (100 - get_skill(ch, gsn_vampiric_bite));
	else if (dt == gsn_charge)
		thac0 -= 10 * (100 - get_skill(ch, gsn_charge));

	switch(dam_type) {
	case DAM_PIERCE:victim_ac = GET_AC(victim,AC_PIERCE)/10; break;
	case DAM_BASH:  victim_ac = GET_AC(victim,AC_BASH)/10; 	 break;
	case DAM_SLASH: victim_ac = GET_AC(victim,AC_SLASH)/10;	 break;
	default:	victim_ac = GET_AC(victim,AC_EXOTIC)/10; break;
	}

	if (victim_ac < -15)
		victim_ac = (victim_ac + 15) / 5 - 15;

	if (get_skill(victim, gsn_armor_use) > 70) {
		check_improve(victim, gsn_armor_use, TRUE, 8);
		victim_ac -= (victim->level) / 2;
	}

	if (!can_see(ch, victim)) {
		 if ((sk2 = get_skill(ch, gsn_blind_fighting))
		 &&  number_percent() < sk2)
			check_improve(ch,gsn_blind_fighting,TRUE,16);
		 else
			victim_ac -= 4;
	}

	if (victim->position < POS_FIGHTING)
		victim_ac += 4;

	if (victim->position < POS_RESTING)
		victim_ac += 6;

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

	if (diceroll == 0
	|| (diceroll != 19 && diceroll < thac0 - victim_ac)) {
		/* Miss. */
		damage(ch, victim, 0, dt, dam_type, dam_flags);
		tail_chain();
		return;
	}

	/*
	 * Hit.
	 * Calc damage.
	 */

	if (IS_NPC(ch) && wield == NULL)
		dam = dice(ch->damage[DICE_NUMBER], ch->damage[DICE_TYPE]);
	else {
		if (sn != -1)
			check_improve(ch, sn, TRUE, 5);
		if (wield != NULL) {
			dam = dice(wield->value[1],
				   wield->value[2]) * sk / 100;

/* no shield = more */
			if (get_eq_char(ch, WEAR_SHIELD) == NULL)
				dam = dam * 21/20;

/* sharpness! */
			if (IS_WEAPON_STAT(wield, WEAPON_SHARP)) {
				int percent;

				if ((percent = number_percent()) <= (sk / 8))
					dam = 2 * dam + (dam * 2 * percent / 100);
			}

/* holy weapon */
			if (IS_WEAPON_STAT(wield, WEAPON_HOLY)
			&&  IS_GOOD(ch) && IS_EVIL(victim)
			&&  number_percent() < 30) {
				act("$n's flesh is burned with the holy aura of $p.", victim, wield, NULL, TO_ROOM);
				act_puts("Your flesh is burned with the holy aura of $p.", victim, wield, NULL, TO_CHAR, POS_DEAD);
				dam += dam * 120 / 100;
			}
		}
		else {
			dam = number_range(1 + 4 * sk / 100,
					   2 * LEVEL(ch) / 3 * sk / 100);
			if ((sk2 = get_skill(ch, gsn_master_hand))
			&& number_percent() <= sk2) {
				check_improve(ch, gsn_master_hand, TRUE, 6);
				dam += dam * 110 /100;
				if (number_percent() < sk2/5+LEVEL(ch)-LEVEL(victim)) {
					SET_BIT(victim->affected_by,
						AFF_WEAK_STUN);
					act_puts("You hit $N with a stunning "
						 "force!", ch, NULL, victim,
						 TO_CHAR, POS_DEAD);
					act_puts("$n hit you with a stunning "
						 "force!", ch, NULL, victim,
						 TO_VICT, POS_DEAD);
					act_puts("$n hits $N with a stunning "
						 "force!", ch, NULL, victim,
						 TO_NOTVICT, POS_DEAD);
					check_improve(ch, gsn_master_hand,
						      TRUE, 6);
				}
			}
		}
	}

	/*
	 * Bonuses.
	 */
	if ((sk2 = get_skill(ch, gsn_enhanced_damage))
	&&  (diceroll = number_percent()) <= sk2) {
		check_improve(ch, gsn_enhanced_damage, TRUE, 6);
		dam += dam * diceroll * sk2 / 10000;
	}

	if (sn == gsn_sword
	&&  (sk2 = get_skill(ch, gsn_mastering_sword))
	&&  number_percent() <= sk2) {
		OBJ_DATA *katana;

		check_improve(ch, gsn_mastering_sword, TRUE, 6);
		dam += dam * 110 /100;

		if (((katana = get_eq_char(ch,WEAR_WIELD)) ||
		     (katana = get_eq_char(ch, WEAR_SECOND_WIELD)))
		&&  IS_WEAPON_STAT(katana, WEAPON_KATANA)
		&&  strstr(mlstr_mval(katana->ed->description), ch->name)) {
			AFFECT_DATA *paf;

			if ((katana->cost = ++katana->cost % 250) == 0
			&&  (paf = affect_find(katana->affected, gsn_katana))) {
				int old_mod = paf->modifier;
				paf->modifier = UMIN(paf->modifier+1,
						     ch->level / 3);
				if (paf->next != NULL) {
					paf->next->modifier = paf->modifier;
					ch->hitroll += paf->modifier - old_mod;
					if (paf->next->next) {
						paf->next->next->modifier =
							paf->modifier;
						ch->damroll +=
							paf->modifier - old_mod;
					}
				}
				act("$n's katana glows blue.\n",
				    ch, NULL, NULL, TO_ROOM);
				char_puts("Your katana glows blue.\n",ch);
			}
		}
	}

	if (!IS_AWAKE(victim))
		dam *= 2;
	else if (victim->position < POS_FIGHTING)
		dam = dam * 3 / 2;

	sercount = number_percent();
	if (dt == gsn_backstab || dt == gsn_vampiric_bite)
		sercount += 40;
	if (!IS_IMMORTAL(ch) && IS_PUMPED(ch))
		sercount += 10;
	sercount *= 2;
	if (victim->fighting == NULL && !IS_NPC(victim)
	&&  !is_safe_nomessage(victim, ch)
	&&  !is_safe_nomessage(ch,victim)
	&&  (victim->position == POS_SITTING ||
	     victim->position == POS_STANDING)
	&&  dt != gsn_assassinate
	&&  (sercount <= get_skill(victim, gsn_counter))) {
		counter = TRUE;
		check_improve(victim,gsn_counter,TRUE,1);
		act("$N turns your attack against you!",
		    ch, NULL, victim, TO_CHAR);
		act("You turn $n's attack against $m!",
		    ch, NULL, victim, TO_VICT);
		act("$N turns $n's attack against $m!",
		    ch, NULL, victim, TO_NOTVICT);
		ch->fighting = victim;
	}
	else if (!victim->fighting)
		check_improve(victim, gsn_counter, FALSE, 1);

	if (dt == gsn_backstab && (IS_NPC(ch) || wield))
		dam = LEVEL(ch) / 11 * dam + LEVEL(ch);
	else if (dt == gsn_dual_backstab && (IS_NPC(ch) || wield))
		dam = LEVEL(ch) / 14 * dam + LEVEL(ch);
	else if (dt == gsn_circle)
		dam = (LEVEL(ch)/40 + 1) * dam + LEVEL(ch);
	else if (dt == gsn_knife)
		dam = (LEVEL(ch)/28 + 1) * dam + LEVEL(ch);
	else if (dt == gsn_vampiric_bite && is_affected(ch, gsn_vampire))
		dam = (LEVEL(ch)/13 + 1) * dam + LEVEL(ch);
	else if (dt == gsn_cleave && wield != NULL) {
		if (number_percent() <
				(URANGE(4, 5+LEVEL(ch)-LEVEL(victim), 10)
				+ (wield->value[0]==WEAPON_AXE) ? 2:0 +
				(get_curr_stat(ch,STAT_STR)-21)/2)
		&&  !counter && !IS_IMMORTAL(victim)) {
			act_puts("Your cleave chops $N IN HALF!",
				 ch, NULL, victim, TO_CHAR, POS_RESTING);
			act_puts("$n's cleave chops you IN HALF!",
				 ch, NULL, victim, TO_VICT, POS_RESTING);
			act_puts("$n's cleave chops $N IN HALF!",
				 ch, NULL, victim, TO_NOTVICT, POS_RESTING);
			char_puts("You have been KILLED!\n", victim);
			act("$n is DEAD!", victim, NULL, NULL, TO_ROOM);
			WAIT_STATE(ch, 2);
			victim->position = POS_DEAD;
			handle_death(ch, victim);
			return;
		}
		else
			dam = (dam * 2 + ch->level);
	}

	if (dt == gsn_assassinate) {
		if (number_percent() <=
				URANGE(10, 20+(LEVEL(ch) - LEVEL(victim))*2, 50)
		&& !counter && !IS_IMMORTAL(victim)) {
			act_puts("You {R+++ASSASSINATE+++{x $N!",
				 ch, NULL, victim, TO_CHAR, POS_RESTING);
			act_puts("$n {R+++ASSASSINATES+++{x $N!",
				 ch, NULL, victim, TO_NOTVICT, POS_RESTING);
			act_puts("$n {R+++ASSASSINATES+++{x you!",
				 ch, NULL, victim, TO_VICT, POS_DEAD);
			char_puts("You have been KILLED!\n", victim);
			act("$n is DEAD!", victim, NULL, victim, TO_ROOM);
			check_improve(ch, gsn_assassinate, TRUE, 1);
			victim->position = POS_DEAD;
			handle_death(ch, victim);
			return;
		}
		else {
			check_improve(ch, gsn_assassinate, FALSE, 1);
			dam *= 2;
		}
	}
	if (dt == gsn_charge)
		dam *= LEVEL(ch)/12;

	dam += GET_DAMROLL(ch) * UMIN(100, sk) / 100;

	if (dt == gsn_ambush)
		dam *= UMAX(3, LEVEL(ch)/12);

	if ((sk2 = get_skill(ch, gsn_deathblow)) > 1
	   && dt != gsn_backstab
	   && dt != gsn_dual_backstab
	   && dt != gsn_cleave
	   && dt != gsn_assassinate
	   && dt != gsn_ambush
	   && dt != gsn_vampiric_bite
	   && dt != gsn_knife) {
		if (number_percent() <  (sk2/8)) {
			act("You deliver a blow of deadly force!",
			    ch, NULL, NULL, TO_CHAR);
			act("$n delivers a blow of deadly force!",
			    ch, NULL, NULL, TO_ROOM);
			dam = LEVEL(ch)*dam/20;
			check_improve(ch, gsn_deathblow, TRUE, 1);
		}
		else
			check_improve(ch, gsn_deathblow, FALSE, 3);
	}

	if (dam <= 0)
		dam = 1;

	if (counter) {
		result = damage(ch, ch, 2*dam, dt, dam_type, DAMF_SHOW);
		multi_hit(victim, ch, TYPE_UNDEFINED);
	}
	else
		result = damage(ch, victim, dam, dt, dam_type, dam_flags);

	/* vampiric bite gives hp to ch from victim */
	if (dt == gsn_vampiric_bite) {
		int hit_ga = UMIN((dam / 2), victim->max_hit);

		ch->hit += hit_ga;
		ch->hit  = UMIN(ch->hit, ch->max_hit);
		update_pos(ch);
		char_puts("Your health increases as you suck "
			  "your victim's blood.\n", ch);
	}

	/* but do we have a funky weapon? */
	if (result && wield != NULL && ch->fighting == victim) {
		int dam;

		if (IS_WEAPON_STAT(wield, WEAPON_VORPAL)) {
			int chance;

			chance = get_skill(ch, get_weapon_sn(wield)) +
				 get_curr_stat(ch, STAT_STR) * 4;

			if (chance > number_range(1, 200000)
			&&  !IS_IMMORTAL(victim)) {
				act("$p makes an huge arc in the air, "
				    "chopping $n's head OFF!",
				     victim, wield, NULL, TO_ROOM);
				act("$p whistles in the air, "
				    "chopping your head OFF!",
				    victim, wield, NULL, TO_CHAR);
				act("$n is DEAD!", victim, NULL, NULL, TO_ROOM);
				char_puts("You have been KILLED!\n", victim);
				victim->position = POS_DEAD;
				handle_death(ch, victim);
				return;
			}
		}

		if (IS_WEAPON_STAT(wield, WEAPON_POISON)) {
			int level;
			AFFECT_DATA *poison, af;

			if ((poison = affect_find(wield->affected,
							gsn_poison)) == NULL)
				level = wield->level;
			else
				level = poison->level;

			if (!saves_spell(level / 2,victim, DAM_POISON)) {
				char_puts("You feel poison coursing "
					  "through your veins.", victim);
				act("$n is poisoned by the venom on $p.",
				    victim, wield, NULL, TO_ROOM);

				af.where     = TO_AFFECTS;
				af.type      = gsn_poison;
				af.level     = level * 3/4;
				af.duration  = level / 2;
				af.location  = APPLY_STR;
				af.modifier  = -1;
				af.bitvector = AFF_POISON;
				affect_join(victim, &af);
			}

			/* weaken the poison if it's temporary */
			if (poison != NULL) {
				poison->level = UMAX(0,poison->level - 2);
				poison->duration = UMAX(0,poison->duration - 1);
				if (poison->level == 0
				||  poison->duration == 0)
					act("The poison on $p has worn off.",
					    ch, wield, NULL, TO_CHAR);
			}
		}

		if (IS_WEAPON_STAT(wield, WEAPON_VAMPIRIC)) {
			dam = number_range(1, wield->level / 5 + 1);
			act("$p draws life from $n.",
			    victim, wield, NULL, TO_ROOM);
			act("You feel $p drawing your life away.",
			    victim, wield, NULL, TO_CHAR);
			damage(ch, victim, dam, 0, DAM_NEGATIVE, DAMF_NONE);
			ch->hit += dam/2;
		}

		if (IS_WEAPON_STAT(wield, WEAPON_FLAMING)) {
			dam = number_range(1,wield->level / 4 + 1);
			act("$n is burned by $p.", victim, wield, NULL, TO_ROOM);
			act("$p sears your flesh.",
			    victim, wield, NULL, TO_CHAR);
			fire_effect((void *) victim, wield->level/2, dam,
				    TARGET_CHAR);
			damage(ch, victim, dam, 0, DAM_FIRE, DAMF_NONE);
		}

		if (IS_WEAPON_STAT(wield, WEAPON_FROST)) {
			dam = number_range(1,wield->level / 6 + 2);
			act("$p freezes $n.", victim, wield, NULL, TO_ROOM);
			act("The cold touch of $p surrounds you with ice.",
			    victim, wield, NULL, TO_CHAR);
			cold_effect(victim, wield->level/2, dam, TARGET_CHAR);
			damage(ch, victim, dam, 0, DAM_COLD, DAMF_NONE);
		}

		if (IS_WEAPON_STAT(wield, WEAPON_SHOCKING)) {
			dam = number_range(1, wield->level/5 + 2);
			act("$n is struck by lightning from $p.",
			    victim, wield, NULL, TO_ROOM);
			act("You are shocked by $p.",
			    victim, wield, NULL, TO_CHAR);
			shock_effect(victim, wield->level/2, dam, TARGET_CHAR);
			damage(ch, victim, dam, 0, DAM_LIGHTNING, DAMF_NONE);
		}
	}

	tail_chain();
}

/*
 * handle_death - called from `damage' if `ch' has killed `victim'
 */
void handle_death(CHAR_DATA *ch, CHAR_DATA *victim)
{
	bool vnpc = IS_NPC(victim);
	ROOM_INDEX_DATA *vroom = victim->in_room;
	bool is_duel = !IS_NPC(victim) 
		&& (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM)) 
		&& IS_SET(victim->in_room->room_flags, ROOM_BATTLE_ARENA);
	OBJ_DATA *corpse;
	class_t *cl;

	group_gain(ch, victim);

	/*
	 * Death trigger
	 */
	if (vnpc && HAS_TRIGGER(victim, TRIG_DEATH)) {
		victim->position = POS_STANDING;
		mp_percent_trigger(victim, ch, NULL, NULL, TRIG_DEATH);
	}

	raw_kill(ch, victim);

	/* RT new auto commands */
	if (!IS_NPC(ch) && vnpc && vroom == ch->in_room
	&&  (corpse = get_obj_list(ch, "corpse", ch->in_room->contents))) {
		if (HAS_SKILL(ch, gsn_vampire)) {
			act_puts("$n suck {Rblood{x from $N's corpse!!",
				 ch, NULL,victim,TO_ROOM,POS_SLEEPING);
			char_puts("You suck {Rblood{x "
				  "from the corpse!!\n\n", ch);
			gain_condition(ch, COND_BLOODLUST, 3);
		}

		if (IS_SET(ch->plr_flags, PLR_AUTOLOOK))
			do_look_in(ch, "corpse");
		if (corpse->contains)
			/* corpse exists and not empty */
			if (IS_SET(ch->plr_flags, PLR_AUTOLOOT))
				do_get(ch, "all corpse");
			else if (IS_SET(ch->plr_flags, PLR_AUTOGOLD))
				get_gold_corpse(ch, corpse);

		if (IS_SET(ch->plr_flags, PLR_AUTOSAC))
			do_sacrifice(ch, "corpse");
	}

	if (vnpc || victim->position == POS_STANDING)
		return;

	if (is_duel)
		return;

	/* Dying penalty: 2/3 way back. */
	if (IS_SET(victim->plr_flags, PLR_WANTED)
	&&  victim->level > 1) {
		REMOVE_BIT(victim->plr_flags, PLR_WANTED);
		victim->level--;
		victim->pcdata->plevels++;
		victim->exp = exp_for_level(victim, victim->level);
		victim->exp_tl = 0;
	}
	else 
		if (victim->exp_tl > 0)
			gain_exp(victim, -victim->exp_tl*2/3);

	if ((++victim->pcdata->death % 3) != 2)
		return;

	/* Die too much and is deleted ... :( */
	if ((cl = class_lookup(victim->class))
	&&  !CAN_FLEE(ch, cl)) {
		victim->perm_stat[STAT_CHA]--;
		if (victim->pcdata->death > cl->death_limit) {
			char msg[MAX_STRING_LENGTH];

			snprintf(msg, sizeof(msg),
				 "%d deaths limit for %s",
				 cl->death_limit, cl->name);
			delete_player(victim, msg);
			return;
		}
	}
	else if (--victim->perm_stat[STAT_CON] < 3) {
		delete_player(victim, "lack of CON");
		return;
	}
	else
		char_puts("You feel your life power has decreased "
			  "with this death.\n", victim);
}

/*
 * Inflict damage from a hit.
 */
bool damage(CHAR_DATA *ch, CHAR_DATA *victim,
	    int dam, int dt, int dam_type, int dam_flags)
{
	bool immune;
	int dam2;
	int loc;

	if (JUST_KILLED(victim))
		return FALSE;

	if (victim != ch) {
		/*
		 * Certain attacks are forbidden.
		 * Most other attacks are returned.
		 */
		if (victim->position > POS_STUNNED) {
			if (victim->fighting == NULL) {
				set_fighting(victim, ch);
				if (IS_NPC(victim)
				&&  HAS_TRIGGER(victim, TRIG_KILL))
					mp_percent_trigger(victim, ch, NULL,
							   NULL, TRIG_KILL);
			}
			if (victim->timer <= 4)
				victim->position = POS_FIGHTING;
		}

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

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

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

		if (MOUNTED(victim) == ch || RIDDEN(victim) == ch)
			victim->riding = ch->riding = 0;
	}

	/*
	 * No one in combat can hide, be invis or camoed.
	 */
	do_visible(ch, str_empty);

	/*
	 * Damage modifiers.
	 */
	if (IS_AFFECTED(victim, AFF_SANCTUARY)
	&&  !((dt == gsn_cleave) && (number_percent() < 50)))
		dam /= 2;

	if (IS_AFFECTED(victim, AFF_BLACK_SHROUD)) 
		dam = (4*dam)/7;

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

	if (IS_AFFECTED(victim, AFF_PROTECT_GOOD) && IS_GOOD(ch))
		dam -= dam / 4;

	if (is_affected(victim,gsn_resistance))
		dam = (3 * dam)/5;

	if (is_affected(victim, gsn_protection_heat) && (dam_type == DAM_FIRE))
		dam -= dam / 4;
	if (is_affected(victim, gsn_protection_cold) && (dam_type == DAM_COLD))
		dam -= dam / 4;

	immune = FALSE;
	loc = IS_SET(dam_flags, DAMF_SECOND) ? WEAR_SECOND_WIELD : WEAR_WIELD;

	/*
	 * Check for parry, and dodge.
	 */
	if (dt >= TYPE_HIT && ch != victim) {
		/*
		 * some funny stuff
		 */
		if (is_affected(victim, gsn_mirror)) {
			act("$n shatters into tiny fragments of glass.",
			    victim, NULL, NULL, TO_ROOM);
			extract_char(victim, 0);
			return FALSE;
		}

		if (check_parry(ch, victim, loc))
			return FALSE;
		if (check_block(ch, victim, loc))
			return FALSE;
		if (check_dodge(ch, victim))
			return FALSE;
		if (check_blink(ch, victim))
			return FALSE;
		if (check_hand_block(ch, victim))
			return FALSE;
	}

	switch(check_immune(victim, dam_type)) {
	case IS_IMMUNE:
		immune = TRUE;
		dam = 0;
		break;

	case IS_RESISTANT:
		dam -= dam/3;
		break;

	case IS_VULNERABLE:
		dam += dam/2;
		break;
	}

	if (dt >= TYPE_HIT && ch != victim) {
		if ((dam2 = critical_strike(ch, victim, dam)) != 0)
			dam = dam2;
	}

	if (IS_SET(dam_flags, DAMF_SHOW))
		dam_message(ch, victim, dam, dt, immune, dam_type);

	if (dam == 0)
		return FALSE;

	if (dt >= TYPE_HIT && ch != victim)
		check_eq_damage(ch, victim, loc);

	/*
	 * Hurt the victim.
	 * Inform the victim of his new state.
	 */
	victim->hit -= dam;
	if (IS_IMMORTAL(victim) && victim->hit < 1)
		victim->hit = 1;

	update_pos(victim);

	switch(victim->position) {
	case POS_MORTAL:
		if (dam_type == DAM_HUNGER || dam_type == DAM_THIRST) break;
		act("$n is mortally wounded, and will die soon, if not aided.",
		    victim, NULL, NULL, TO_ROOM);
		char_puts( "You are mortally wounded, and will die soon, if not aided.\n", victim);
		break;

	case POS_INCAP:
		if (dam_type == DAM_HUNGER || dam_type == DAM_THIRST) break;
		act("$n is incapacitated and will slowly die, if not aided.",
		    victim, NULL, NULL, TO_ROOM);
		char_puts( "You are incapacitated and will slowly die, if not aided.\n", victim);
		break;

	case POS_STUNNED:
		if (dam_type == DAM_HUNGER || dam_type == DAM_THIRST) break;
		act("$n is stunned, but will probably recover.",
		    victim, NULL, NULL, TO_ROOM);
		char_puts("You are stunned, but will probably recover.\n",
			     victim);
		break;

	case POS_DEAD:
		act("$n is DEAD!!", victim, 0, 0, TO_ROOM);
		char_puts("You have been KILLED!!\n\n", victim);
		break;

	default:
		if (dam_type == DAM_HUNGER || dam_type == DAM_THIRST) break;
		if (dam > victim->max_hit / 4)
			char_puts("That really did HURT!\n", victim);
		if (victim->hit < victim->max_hit / 4)
			char_puts("You sure are BLEEDING!\n", victim);
		break;
	}

	/*
	 * Sleep spells and extremely wounded folks.
	 */
	if (!IS_AWAKE(victim) && victim->fighting)
		victim->fighting = NULL;

	/*
	 * Payoff for killing things.
	 */
	if (victim->position == POS_DEAD) {
		handle_death(ch, victim);
		return TRUE;
	}

	if (victim == ch)
		return TRUE;

	/*
	 * Take care of link dead people.
	 */
	if (!IS_NPC(victim)
	&&  victim->desc == NULL
	&&  !IS_SET(victim->comm, COMM_NOFLEE)) {
		if (number_range(0, victim->wait) == 0) {
			do_flee(victim, str_empty);
			return TRUE;
		}
	}

	/*
	 * Wimp out?
	 */
	if (IS_NPC(victim) && dam > 0 && victim->wait < PULSE_VIOLENCE / 2) {
		flag64_t act = victim->pIndexData->act;
		if ((IS_SET(act, ACT_WIMPY) && number_bits(2) == 0 &&
		     victim->hit < victim->max_hit / 5)
		||  (IS_AFFECTED(victim, AFF_CHARM) &&
		     victim->master != NULL &&
		     victim->master->in_room != victim->in_room)
		||  (IS_AFFECTED(victim, AFF_DETECT_FEAR) &&
		     !IS_SET(act, ACT_NOTRACK))) {
			do_flee(victim, str_empty);
			victim->last_fought = NULL;
		}
	}

	if (!IS_NPC(victim)
	&&  victim->hit > 0
	&&  (victim->hit <= victim->wimpy || IS_AFFECTED(victim, AFF_DETECT_FEAR))
	&&  victim->wait < PULSE_VIOLENCE / 2)
		do_flee(victim, str_empty);

	tail_chain();
	return TRUE;
}

static bool inline
is_safe_raw(CHAR_DATA *ch, CHAR_DATA *victim)
{
	/*
	 * ghosts are safe
	 * this check must be done first to avoid
	 * suicyco muttafuckas who recite 'leather-bound book' (#5743)
	 * without any target specified
	 * extracted NPCs are safe too
	 */
	if (!IS_NPC(victim)) {
		int clan;

		/* ghost cannot attack anyone */
		if (ch != victim
		&&  !IS_NPC(ch)
		&&  IS_SET(ch->plr_flags, PLR_GHOST))
			return TRUE;

		/* clan defenders can attack anyone in their clan */
		if (victim->in_room
		&&  (clan = victim->in_room->area->clan)
		&&  victim->clan != clan
		&&  ch->clan == clan)
			return FALSE;

		/* otherwise ghosts are safe */
		if (IS_SET(victim->plr_flags, PLR_GHOST))
			return TRUE;
	}
	else if (victim->extracted)
		return TRUE;

	if (victim->fighting == ch
	||  ch == victim
	||  IS_IMMORTAL(ch))
		return FALSE;

	/* handle ROOM_PEACE flags */
	if ((victim->in_room && IS_SET(victim->in_room->room_flags, ROOM_PEACE))
	||  (ch->in_room && IS_SET(ch->in_room->room_flags, ROOM_PEACE)))
		return TRUE;

	/* link dead players whose adrenalin is not gushing are safe */
	if (!IS_NPC(victim) && !IS_PUMPED(victim) && victim->desc == NULL)
		return TRUE;

	return !in_PK(ch, victim);
}

/*
 * generic safe-checking function wrapper
 *
 * all the checks are done is_safe_raw to properly strip PLR_GHOST
 * flag if victim is not safe. add you checks there
 */
bool is_safe_nomessage(CHAR_DATA *ch, CHAR_DATA *victim)
{
	bool safe;
	CHAR_DATA *mount;

	if (IS_NPC(ch)
	&&  IS_AFFECTED(ch, AFF_CHARM)
	&&  ch->master
	&&  ch->in_room == ch->master->in_room)
		return is_safe_nomessage(ch->master, victim);
	
	if (IS_NPC(victim)
	&&  IS_AFFECTED(victim, AFF_CHARM)
	&&  victim->master)
		return is_safe_nomessage(ch, victim->master);

	if ((mount = RIDDEN(victim)))
		return is_safe_nomessage(ch, mount);

	if ((safe = is_safe_raw(ch, victim)) || IS_NPC(ch))
		return safe;

	if (victim != ch && IS_SET(ch->plr_flags, PLR_GHOST)) {
		char_puts("You return to your normal form.\n", ch);
		REMOVE_BIT(ch->plr_flags, PLR_GHOST);
	}

	return safe;
}

bool is_safe(CHAR_DATA *ch, CHAR_DATA *victim)
{
	if (is_safe_nomessage(ch, victim)) {
		act("The gods protect $N.",ch,NULL,victim,TO_CHAR);
		act("The gods protect $N from $n.",ch,NULL,victim,TO_ROOM);
		return TRUE;
	}
	return FALSE;
}

bool is_safe_spell(CHAR_DATA *ch, CHAR_DATA *victim, bool area)
{
#if 0
	if (ch == victim && !area)
		return TRUE;
#endif
	if (area) {
		if (IS_IMMORTAL(victim)
		||  is_same_group(ch, victim)
		||  ch == victim
		||  RIDDEN(ch) == victim
		||  MOUNTED(ch) == victim)
			return TRUE;
	}

	return is_safe(ch, victim);
}

/*
 * Check for parry.
 */
bool check_parry(CHAR_DATA *ch, CHAR_DATA *victim, int loc)
{
	int chance;

	if (!IS_AWAKE(victim))
		return FALSE;

	if (IS_NPC(victim))
		chance	= UMIN(35, victim->level);
	else {
		if (get_eq_char(victim, WEAR_WIELD) == NULL)
			return FALSE;

		chance = get_skill(victim, gsn_parry) / 2;
	}

	if (check_forest(victim) == FOREST_DEFENCE
	&&  (number_percent() < get_skill(victim, gsn_forest_fighting))) {
		chance = chance * 120 / 100;
		check_improve (victim, gsn_forest_fighting, TRUE, 7);
	}

	if (number_percent() >= chance + LEVEL(victim) - LEVEL(ch))
		return FALSE;

	act("You parry $n's attack.", ch, NULL, victim, TO_VICT | ACT_VERBOSE);
	act("$N parries your attack.", ch, NULL, victim, TO_CHAR | ACT_VERBOSE);

	check_weapon_damage(ch, victim, loc);

	if (number_percent() > chance) {
		/* size and weight */
		chance += ch->carry_weight / 25;
		chance -= victim->carry_weight / 20;

		if (ch->size < victim->size)
			chance += (ch->size - victim->size) * 25;
		else
			chance += (ch->size - victim->size) * 10;

		/* stats */
		chance += get_curr_stat(ch, STAT_STR);
		chance -= get_curr_stat(victim, STAT_DEX) * 4/3;

		if (IS_AFFECTED(ch, AFF_FLYING))
			chance -= 10;

		/* speed */
		if (IS_NPC(ch) && IS_SET(ch->pIndexData->off_flags, OFF_FAST))
			chance += 10;
		if (IS_NPC(victim) && IS_SET(victim->pIndexData->off_flags,
					     OFF_FAST))
			chance -= 20;

		/* level */
		chance += (LEVEL(ch) - LEVEL(victim)) * 2;

		/* now the attack */
		if (number_percent() < (chance / 20 )) {
			act("You couldn't manage to keep your position!",
			    ch, NULL, victim, TO_VICT);
			act("You fall down!", ch, NULL, victim, TO_VICT);
			act("$N couldn't manage to hold your attack "
			    "and falls down!",
			    ch, NULL, victim, TO_CHAR);
			act("$n stunning force makes $N falling down.",
			    ch, NULL, victim, TO_NOTVICT);

			WAIT_STATE(victim, SKILL(gsn_bash)->beats);
			victim->position = POS_RESTING;
		}
	}

	check_improve(victim, gsn_parry, TRUE, 6);
	return TRUE;
}

/*
 * check blink
 */
bool check_blink(CHAR_DATA *ch, CHAR_DATA *victim)
{
	int chance;

	if (!IS_SET(victim->plr_flags, PLR_BLINK))
		return FALSE;

	if (IS_NPC(victim))
		return FALSE;
	else
		chance	= get_skill(victim, gsn_blink) / 2;

	if (number_percent() >= chance + LEVEL(victim) - LEVEL(ch)
	||  number_percent() < 50
	||  victim->mana < 10)
		return FALSE;

	victim->mana -= UMAX(victim->level / 10, 1);

	act("You blink out $n's attack.",
	    ch, NULL, victim, TO_VICT | ACT_VERBOSE);
	act("$N blinks out your attack.",
	    ch, NULL, victim, TO_CHAR | ACT_VERBOSE);
	check_improve(victim, gsn_blink, TRUE, 6);
	return TRUE;
}

/*
 * Check for shield block.
 */
bool check_block(CHAR_DATA *ch, CHAR_DATA *victim, int loc)
{
	int chance;

	if (!IS_AWAKE(victim))
		return FALSE;

	if (get_eq_char(victim, WEAR_SHIELD) == NULL)
		return FALSE;

	if (IS_NPC(victim))
		chance = 10;
	else {
		chance = get_skill(victim, gsn_shield_block) / 2;
		if (chance <= 1)
			return FALSE;
	}	

	if (check_forest(victim) == FOREST_DEFENCE 
	&& (number_percent() < get_skill(victim, gsn_forest_fighting))) {
		chance *= 1.2;
		check_improve (victim, gsn_forest_fighting, TRUE, 7);
	}

	if (MOUNTED(victim))
		chance *= 1.2;


	if (number_percent() >= chance + LEVEL(victim) - LEVEL(ch))
		return FALSE;

	act("Your shield blocks $n's attack.",
	    ch, NULL, victim, TO_VICT | ACT_VERBOSE);
	act("$N deflects your attack with $S shield.",
	    ch, NULL, victim, TO_CHAR | ACT_VERBOSE);
	check_shield_damage(ch, victim, loc);
	check_improve(victim, gsn_shield_block, TRUE, 6);
	return TRUE;
}

/* 
 * Check for hand block
 */

bool check_hand_block(CHAR_DATA *ch, CHAR_DATA *victim)
{
	int chance;

	if (!IS_AWAKE(victim) 
	|| IS_NPC(victim) 
	|| get_eq_char(victim, WEAR_WIELD)
	|| get_eq_char(victim, WEAR_SECOND_WIELD)
	|| (chance=get_skill(victim, gsn_hand_block)<=0)) 
		return FALSE;

	chance = URANGE(5, chance*2/5 + LEVEL(victim) - LEVEL(ch), 55);

	if (number_percent() < chance) {
		act("Your hand blocks $n's attack.", 
			ch, NULL, victim, TO_VICT|ACT_VERBOSE);
		act("$N blocks your attack with $S hand.",
			ch, NULL, victim, TO_CHAR|ACT_VERBOSE);
		check_improve(victim, gsn_hand_block, TRUE, 5);
		return TRUE;
	}
	return FALSE;
}



/*
 * Check for dodge.
 */
bool check_dodge(CHAR_DATA *ch, CHAR_DATA *victim)
{
	int chance;

	if (!IS_AWAKE(victim))
		return FALSE;

	if (MOUNTED(victim))
		return FALSE;

	if (IS_NPC(victim))
		 chance  = UMIN(30, victim->level);
	else {
		chance  = get_skill(victim, gsn_dodge) / 2;
		/* chance for high dex. */
		chance += 2 * (get_curr_stat(victim,STAT_DEX) - 20);
	}
	
	if (check_forest(victim) == FOREST_DEFENCE 
	  && (get_skill(victim, gsn_forest_fighting) > number_percent())) {
		chance *= 1.2;
		check_improve (victim, gsn_forest_fighting, TRUE, 7);
	}

	if (number_percent() >= chance + (victim->level - ch->level) / 2)
		return FALSE;

	act("You dodge $n's attack.", ch, NULL, victim, TO_VICT | ACT_VERBOSE);
	act("$N dodges your attack.", ch, NULL, victim, TO_CHAR	| ACT_VERBOSE);

	if (number_percent() < get_skill(victim,gsn_dodge) / 20
	&&  !(IS_AFFECTED(ch, AFF_FLYING) || ch->position < POS_FIGHTING)) {
		/* size */
		if (victim->size < ch->size)
			/* bigger = harder to trip */
			chance += (victim->size - ch->size) * 10;

		/* dex */
		chance += get_curr_stat(victim, STAT_DEX);
		chance -= get_curr_stat(ch, STAT_DEX) * 3 / 2;

		if (IS_AFFECTED(victim, AFF_FLYING))
			chance -= 10;

		/* speed */
		if ((IS_NPC(victim) && IS_SET(victim->pIndexData->off_flags,
					      OFF_FAST))
		||  IS_AFFECTED(victim, AFF_HASTE))
			chance += 10;
		if ((IS_NPC(ch) && IS_SET(ch->pIndexData->off_flags, OFF_FAST))
		||  IS_AFFECTED(ch, AFF_HASTE))
			chance -= 20;

		/* level */
		chance += (victim->level - ch->level) * 2;

		/* now the attack */
		if (number_percent() < (chance / 20)) {
			act("$n lost his postion and fall down!",
			    ch, NULL, victim, TO_VICT);
			act("As $N moves you lost your position fall down!",
			    ch, NULL, victim, TO_CHAR);
			act("As $N dodges $N's attack, $N lost his position "
			    "and falls down.", ch, NULL, victim, TO_NOTVICT);

			WAIT_STATE(ch, SKILL(gsn_trip)->beats);
			ch->position = POS_RESTING;
		}
	}
	check_improve(victim, gsn_dodge, TRUE, 6);
	return TRUE;
}

/*
 * Set position of a victim.
 */
void update_pos(CHAR_DATA *victim)
{
	if (victim->hit > 0) {
		if (victim->position <= POS_STUNNED) {
			if (IS_AFFECTED(victim, AFF_SLEEP)) {
				REMOVE_BIT(victim->affected_by, AFF_SLEEP);
				affect_bit_strip(victim, TO_AFFECTS, AFF_SLEEP);
			}

			victim->position = POS_STANDING;
		}
		return;
	}

	if (IS_NPC(victim) && victim->hit < 1) {
		victim->position = POS_DEAD;
		return;
	}

	if (victim->hit <= -11) {
		victim->position = POS_DEAD;
		return;
	}

	if (victim->hit <= -6)
		victim->position = POS_MORTAL;
	else if (victim->hit <= -3)
		victim->position = POS_INCAP;
	else
		victim->position = POS_STUNNED;
}

/*
 * Start fights.
 */
void set_fighting(CHAR_DATA *ch, CHAR_DATA *victim)
{
	if (ch->fighting != NULL) {
		bug("Set_fighting: already fighting", 0);
		return;
	}

	if (IS_AFFECTED(ch, AFF_SLEEP)) {
		REMOVE_BIT(ch->affected_by, AFF_SLEEP);
		affect_bit_strip(ch, TO_AFFECTS, AFF_SLEEP);
	}

	ch->fighting = victim;
	ch->position = POS_FIGHTING;
}

static void STOP_FIGHTING(CHAR_DATA *ch)
{
	ch->fighting = NULL;
	ch->position = IS_NPC(ch) ? ch->default_pos : POS_STANDING;
	update_pos(ch);
}

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

	STOP_FIGHTING(ch);
	if (!fBoth)
		return;

	for (fch = char_list; fch; fch = fch->next) {
		if (fch->fighting == ch)
			STOP_FIGHTING(fch);
	}
}

/*
 * Make a corpse out of a character.
 */
void make_corpse(CHAR_DATA *ch)
{
	OBJ_DATA *corpse;
	OBJ_DATA *obj;
	OBJ_DATA *obj_next;
	int i;

	if (IS_NPC(ch)) {
		corpse	= create_obj_of(get_obj_index(OBJ_VNUM_CORPSE_NPC),
					ch->short_descr);
		corpse->timer	= number_range(3, 6);
		if (ch->gold > 0 || ch->silver > 0) {
			OBJ_DATA *money = create_money(ch->gold, ch->silver);
			if (IS_SET(ch->form,FORM_INSTANT_DECAY))
				obj_to_room(money, ch->in_room);
			else
				obj_to_obj(money, corpse);
		}
	}
	else {
		corpse	= create_obj_of(get_obj_index(OBJ_VNUM_CORPSE_PC),
					ch->short_descr);
		if (IS_GOOD(ch))
		  i = 0;
		if (IS_EVIL(ch))
		  i = 2;
		else
		  i = 1;

		corpse->timer= number_range(25, 40);
		corpse->altar = get_altar(ch);

		if (ch->gold > 0 || ch->silver > 0)
			obj_to_obj(create_money(ch->gold, ch->silver), corpse);
	}

	corpse->owner = mlstr_dup(ch->short_descr);
	corpse->level = ch->level;

	ch->gold = 0;
	ch->silver = 0;

	for (obj = ch->carrying; obj != NULL; obj = obj_next) {
		obj_next = obj->next_content;
		obj_from_char(obj);
		if (obj->pIndexData->item_type == ITEM_POTION)
		    obj->timer = number_range(500,1000);
		if (obj->pIndexData->item_type == ITEM_SCROLL)
		    obj->timer = number_range(1000,2500);
		if (IS_SET(obj->extra_flags,ITEM_ROT_DEATH))  {
		    obj->timer = number_range(5,10);
		    if (obj->pIndexData->item_type == ITEM_POTION)
		       obj->timer += obj->level * 20;
		}
		REMOVE_BIT(obj->extra_flags,ITEM_VIS_DEATH);
		REMOVE_BIT(obj->extra_flags,ITEM_ROT_DEATH);

		if (IS_SET(obj->extra_flags, ITEM_INVENTORY)  ||
		    (obj->pIndexData->limit != -1 &&
			(obj->pIndexData->count > obj->pIndexData->limit)))
		  {
		    extract_obj(obj, 0);
		    continue;
		  }
		else if (IS_SET(ch->form,FORM_INSTANT_DECAY))
		  obj_to_room(obj, ch->in_room);

		else
		  obj_to_obj(obj, corpse);
	}

	obj_to_room(corpse, ch->in_room);
}

void death_cry(CHAR_DATA *ch)
{
  death_cry_org(ch, -1);
}

/*
 * Improved Death_cry contributed by Diavolo.
 */
void death_cry_org(CHAR_DATA *ch, int part)
{
	ROOM_INDEX_DATA *was_in_room;
	char *msg;
	int door;
	int vnum;

	vnum = 0;
	msg = "You hear $n's death cry.";

	if (part == -1)
	  part = number_bits(4);

	switch (part) {
	case  0:
		msg  = "$n hits the ground ... DEAD.";
		break;
	case  1:
		if (ch->material == 0) {
		    msg  = "$n splatters blood on your armor.";
		    break;
		}
		/* FALLTHRU */
	case  2:
		if (IS_SET(ch->parts, PART_GUTS)) {
			msg = "$n spills $s guts all over the floor.";
			vnum = OBJ_VNUM_GUTS;
		}
		break;
	case  3:
		if (IS_SET(ch->parts, PART_HEAD)) {
			msg  = "$n's severed head plops on the ground.";
			vnum = OBJ_VNUM_SEVERED_HEAD;
		}
		break;
	case  4:
		if (IS_SET(ch->parts, PART_HEART)) {
			msg  = "$n's heart is torn from $s chest.";
			vnum = OBJ_VNUM_TORN_HEART;
		}
		break;
	case  5:
		if (IS_SET(ch->parts, PART_ARMS)) {
			msg  = "$n's arm is sliced from $s dead body.";
			vnum = OBJ_VNUM_SLICED_ARM;
		}
		break;
	case  6:
		if (IS_SET(ch->parts, PART_LEGS)) {
			msg  = "$n's leg is sliced from $s dead body.";
			vnum = OBJ_VNUM_SLICED_LEG;
		}
		break;
	case 7:
		if (IS_SET(ch->parts, PART_BRAINS)) {
			msg = "$n's head is shattered, and $s brains splash all over you.";
			vnum = OBJ_VNUM_BRAINS;
		}
		break;
	}

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

	if (vnum) {
		OBJ_DATA *obj;

		obj = create_obj_of(get_obj_index(vnum), ch->short_descr);
		obj->level = ch->level;
		obj->owner = mlstr_dup(ch->short_descr);
		obj->timer = number_range(4, 7);

		if (obj->pIndexData->item_type == ITEM_FOOD) {
			if (IS_SET(ch->form,FORM_POISON))
				obj->value[3] = 1;
			else if (!IS_SET(ch->form,FORM_EDIBLE))
				SET_BIT(obj->extra_flags, ITEM_NOT_EDIBLE);
		}

		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.";

	if ((was_in_room = ch->in_room)) {
		for (door = 0; door <= 5; door++) {
			EXIT_DATA *pexit;

			if ((pexit = was_in_room->exit[door]) != NULL
			&&   pexit->to_room.r != NULL
			&&   pexit->to_room.r != was_in_room) {
				ch->in_room = pexit->to_room.r;
				act(msg, ch, NULL, NULL, TO_ROOM);
			}
		}
		ch->in_room = was_in_room;
	}
}

void raw_kill_org(CHAR_DATA *ch, CHAR_DATA *victim, int part)
{
	CHAR_DATA *tmp_ch, *tmp_ch_next;
	OBJ_DATA *obj,*obj_next;
	int i;
	OBJ_DATA *tattoo, *clanmark;

	for (obj = victim->carrying;obj != NULL;obj = obj_next) {
		obj_next = obj->next_content;
		if (obj->wear_loc != WEAR_NONE
		&&  oprog_call(OPROG_DEATH, obj, victim, NULL)) {
			victim->position = POS_STANDING;
			return;
		}
	}

	/* don't remember killed victims anymore */
	if (IS_NPC(ch))
		remove_mind(ch, victim->name);

	stop_fighting(victim, TRUE);
	rating_update(ch, victim);
	quest_handle_death(ch, victim);
	RESET_FIGHT_TIME(victim);
	victim->last_death_time = current_time;
	death_cry_org(victim, part);

	tattoo = get_eq_char(victim, WEAR_TATTOO);
	clanmark = get_eq_char(victim, WEAR_CLANMARK);
	if (tattoo != NULL)
		obj_from_char(tattoo);
	if (clanmark != NULL)
		obj_from_char(clanmark);
	make_corpse(victim);

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

	SET_BIT(victim->plr_flags, PLR_GHOST);
	char_puts("You turn into an invincible ghost for a few minutes.\n"
		  "As long as you don't attack anything.\n",
		  victim);

	extract_char(victim, XC_F_INCOMPLETE);

	while (victim->affected)
		affect_remove(victim, victim->affected);
	victim->affected_by	= 0;
	for (i = 0; i < 4; i++)
		victim->armor[i] = 100;
	victim->position	= POS_RESTING;
	victim->hit		= victim->max_hit / 10;
	victim->mana		= victim->max_mana / 10;
	victim->move		= victim->max_move;
	update_pos(victim);

	/* RT added to prevent infinite deaths */
	REMOVE_BIT(victim->plr_flags, PLR_BOUGHT_PET);

	victim->pcdata->condition[COND_THIRST] = 40;
	victim->pcdata->condition[COND_HUNGER] = 40;
	victim->pcdata->condition[COND_FULL] = 40;
	victim->pcdata->condition[COND_BLOODLUST] = 40;
	victim->pcdata->condition[COND_DESIRE] = 40;

	if (tattoo != NULL) {
		obj_to_char(tattoo, victim);
		equip_char(victim, tattoo, WEAR_TATTOO);
	}

	if (clanmark != NULL) {
		obj_to_char(clanmark, victim);
		equip_char(victim, clanmark, WEAR_CLANMARK);
	}

	if (victim->level > 1)
		save_char_obj(victim, FALSE);

	/*
	 * Calm down the tracking mobiles
	 */
	for (tmp_ch = npc_list; tmp_ch; tmp_ch = tmp_ch_next) {
		tmp_ch_next = tmp_ch->next;
		if (tmp_ch->last_fought == victim)
			tmp_ch->last_fought = NULL;
		remove_mind(tmp_ch, victim->name);
		if (tmp_ch->target == victim 
		&&  tmp_ch->pIndexData->vnum == MOB_VNUM_STALKER) {
			doprintf(do_clan, tmp_ch,
				"%s is dead and I can leave the realm.",
				PERS(victim, tmp_ch));
			extract_char(tmp_ch, 0);
		}
	}
}

void group_gain(CHAR_DATA *ch, CHAR_DATA *victim)
{
	CHAR_DATA *lch;
	CHAR_DATA *gch;
	int xp;
	int members;
	int group_levels;

	if (!IS_NPC(victim) || victim == ch)
		return;

	if (IS_SET(victim->pIndexData->act, ACT_PET)
	||  victim->pIndexData->vnum < 100
	||  victim->master
	||  victim->leader)
		return;

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

	members = 0;
	group_levels = 0;
	for (gch = ch->in_room->people; gch; gch = gch->next_in_room) {
		if (is_same_group(gch, ch)) {
			if (IS_NPC(gch)) {
				if (IS_SET(gch->pIndexData->act, ACT_SUMMONED))
					continue;
			}
			else {
				if (abs(gch->level - lch->level) <= 8)
					members++;
			}
			group_levels += gch->level;
		}
	}

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

		if (gch->level - lch->level > 8) {
			char_puts("You are too high for this group.\n", gch);
			continue;
		}

		if (gch->level - lch->level < -8) {
			char_puts("You are too low for this group.\n", gch);
			continue;
		}

		xp = xp_compute(gch, victim, group_levels, members);
		if (gch->level < LEVEL_HERO) {
			char_printf(gch, "You receive %d experience points.\n", xp);
			gain_exp(gch, xp);
		}
	}
}

/*
 * Compute xp for a kill.
 * Also adjust alignment of killer.
 * Edit this function to change xp computations.
 */
int xp_compute(CHAR_DATA *gch, CHAR_DATA *victim, int total_levels, int members)
{
	int xp;
	int base_exp;
	int level_range = victim->level - gch->level;
	int neg_cha = 0, pos_cha = 0;

/* base exp */
	switch (level_range) {
	case -9:	base_exp =   1; 	break;
	case -8:	base_exp =   2; 	break;
	case -7:	base_exp =   5; 	break;
	case -6:	base_exp =   9; 	break;
	case -5:	base_exp =  11; 	break;
	case -4:	base_exp =  22; 	break;
	case -3:	base_exp =  33; 	break;
	case -2:	base_exp =  43; 	break;
	case -1:	base_exp =  60; 	break;
	case  0:	base_exp =  74; 	break;
	case  1:	base_exp =  84; 	break;
	case  2:	base_exp =  99; 	break;
	case  3:	base_exp = 121; 	break;
	case  4:	base_exp = 143; 	break;
	default:
		if (level_range > 4)
			base_exp = 140 + 20 * (level_range - 4);
		else
			base_exp = 0;
	}

/* calculate exp multiplier */
#if 0
	if (IS_NPC(victim) && IS_SET(victim->pIndexData->act, ACT_NOALIGN))
		xp = base_exp;
	else
#endif
	if ((IS_EVIL(gch) && IS_GOOD(victim))
	||  (IS_EVIL(victim) && IS_GOOD(gch)))
		xp = base_exp * 8/5;
	else if (IS_GOOD(gch) && IS_GOOD(victim))
		xp = 0;
	else if (!IS_NEUTRAL(gch) && IS_NEUTRAL(victim))
		xp = base_exp * 1.1;
	else if (IS_NEUTRAL(gch) && !IS_NEUTRAL(victim))
		xp = base_exp * 1.3;
	else
		xp = base_exp;

	/* more exp at the low levels */
	if (gch->level < 6)
		xp = 15 * xp / (gch->level + 4);

	/* randomize the rewards */
	xp = number_range(xp * 3/4, xp * 5/4);

/* adjust for grouping */
	xp = xp * gch->level/total_levels;
	if (members == 2 || members == 3) {
		xp *= members;
		if (members == 2)
			xp = xp * 120 / 100;
		else
			xp = xp * 125 / 100;
	}

#if 0
	xp += (xp * (gch->max_hit - gch->hit)) / (gch->max_hit * 5);
#endif

	if (IS_GOOD(gch)) {
		if (IS_GOOD(victim)) {
			gch->pcdata->anti_killed++;
			neg_cha = 1;
		}
		else if (IS_NEUTRAL(victim)) {
			gch->pcdata->has_killed++;
			pos_cha = 1;
		}
		else if (IS_EVIL(victim)) {
			gch->pcdata->has_killed++;
			pos_cha = 1;
		}
	}
	else if (IS_NEUTRAL(gch)) {
		if (IS_GOOD(victim)) {
			gch->pcdata->has_killed++;
			pos_cha = 1;
		}
		else if (IS_NEUTRAL(victim)) {
			gch->pcdata->anti_killed++;
			neg_cha = 1;
		}
		else if (IS_EVIL(victim)) {
			gch->pcdata->has_killed++;
			pos_cha =1;
		}
	}
	else if (IS_EVIL(gch)) {
		if (IS_GOOD(victim)) {
			gch->pcdata->has_killed++;
			pos_cha = 1;
		}
		else if (IS_NEUTRAL(victim)) {
			gch->pcdata->has_killed++;
			pos_cha = 1;
		}
		else if (IS_EVIL(victim)) {
			gch->pcdata->anti_killed++;
			neg_cha = 1;
		}
	}

	if (neg_cha) {
		if ((gch->pcdata->anti_killed % 100) == 99) {
			char_printf(gch, "You have killed %d %s up to now.\n",
				    gch->pcdata->anti_killed,
				    IS_GOOD(gch) ?	"goods" :
				    IS_EVIL(gch) ?	"evils" :
							"neutrals");
			if (gch->perm_stat[STAT_CHA] > 3 && IS_GOOD(gch)) {
				char_puts("So your charisma "
					  "has reduced by one.\n", gch);
				gch->perm_stat[STAT_CHA] -= 1;
			}
		}
	}
	else if (pos_cha) {
		if ((gch->pcdata->has_killed % 200) == 199) {
			char_printf(gch, "You have killed %d %s up to now.\n",
				    gch->pcdata->anti_killed,
				    IS_GOOD(gch) ?	"anti-goods" :
				    IS_EVIL(gch) ?	"anti-evils" :
							"anti-neutrals");
			if (gch->perm_stat[STAT_CHA] <
						get_max_train(gch, STAT_CHA)
			&&  IS_GOOD(gch)) {
				char_puts("So your charisma "
					  "has increased by one.\n", gch);
				gch->perm_stat[STAT_CHA] += 1;
			}
		}
	}
	return xp;
}

void dam_message(CHAR_DATA *ch, CHAR_DATA *victim,
		 int dam, int dt, bool immune, int dam_type)
{
	const char *vs;
	const char *vp;
	const char *msg_char;
	const char *msg_vict = NULL;
	const char *msg_notvict;
	const char *attack = str_empty;

	if (dam == 0) {
		vs = "miss";
		vp = "misses";
	}
	else if (dam <= 4) {
		vs = "{cscratch{x";
		vp = "{cscratches{x";
	}
	else if (dam <= 8) {
		vs = "{cgraze{x";
		vp = "{cgrazes{x";
	}
	else if (dam <= 12) {
		vs = "{chit{x";
		vp = "{chits{x";
	}
	else if (dam <= 16) {
		vs = "{cinjure{x";
		vp = "{cinjures{x";
	}
	else if (dam <= 20) {
		vs = "{cwound{x";
		vp = "{cwounds{x";
	}
	else if (dam <= 24) {
		vs = "{cmaul{x";
		vp = "{cmauls{x";
	}
	else if (dam <= 28) {
		vs = "{cdecimate{x";
		vp = "{cdecimates{x";
	}
	else if (dam <= 32) {
		vs = "{cdevastate{x";
		vp = "{cdevastates{x";
	}
	else if (dam <= 36) {
		vs = "{cmaim{x";
		vp = "{cmaims{x";
	}
	else if (dam <= 42) {
		vs = "{MMUTILATE{x";
		vp = "{MMUTILATES{x";
	}
	else if (dam <= 52) {
		vs = "{MDISEMBOWEL{x";
		vp = "{MDISEMBOWELS{x";
	}
	else if (dam <= 65) {
		vs = "{MDISMEMBER{x";
		vp = "{MDISMEMBERS{x";
	}
	else if (dam <= 80) {
		vs = "{MMASSACRE{x";
		vp = "{MMASSACRES{x";
	}
	else if (dam <= 100) {
		vs = "{MMANGLE{x";
		vp = "{MMANGLES{x";
	}
	else if (dam <= 130) {
		vs = "{y*** DEMOLISH ***{x";
		vp = "{y*** DEMOLISHES ***{x";
	}
	else if (dam <= 175) {
		vs = "{y*** DEVASTATE ***{x";
		vp = "{y*** DEVASTATES ***{x";
	}
	else if (dam <= 250) {
		vs = "{y=== OBLITERATE ==={x";
		vp = "{y=== OBLITERATES ==={x";
	}
	else if (dam <= 325) {
		vs = "{y=== ATOMIZE ==={x";
		vp = "{y=== ATOMIZES ==={x";
	}
	else if (dam <= 400) {
		vs = "{R>>> ANNIHILATE <<<{x";
		vp = "{R>>> ANNIHILATES <<<{x";
	}
	else if (dam <= 500) {
		vs = "{R>>> ERADICATE <<<{x";
		vp = "{R>>> ERADICATES <<<{x";
	}
	else if (dam <= 650) {
		vs = "{R-==> ELECTRONIZE <==-{x";
		vp = "{R-==> ELECTRONIZES <==-{x";
	}
	else if (dam <= 800) {
		vs = "{R-==> SKELETONIZE <==-{x";
		vp = "{R-==> SKELETONIZES <==-{x";
	}
	else if (dam <= 1000) {
		vs = "{R### NUKE ###{x";
		vp = "{R### NUKES ###{x";
	}
	else if (dam <= 1250) {
		vs = "{R### TERMINATE ###{x";
		vp = "{R### TERMINATES ###{x";
	}
	else if (dam <= 1500) {
		vs = "{R[*] TEAR UP [*]{x";
		vp = "{R[*] TEARS UP [*]{x";
	}
	else {
		vs = "{*{R[*] POWER HIT [*]{x";
		vp = "{*{R[*] POWER HITS [*]{x";
	}

	if (dt == TYPE_HIT || dt == TYPE_HUNGER) {
		if (ch == victim) {
			switch (dam_type) {
			case DAM_HUNGER:
				msg_notvict = "$n's hunger $u $mself!";
				msg_char = "Your hunger $u yourself!";
				break;

			case DAM_THIRST:
				msg_notvict = "$n's thirst $u $mself!";
				msg_char = "Your thirst $u yourself!";
				break;

			case DAM_LIGHT_V:
				msg_notvict = "The light of room $u $n!";
				msg_char = "The light of room $u you!";
				break;

			case DAM_TRAP_ROOM:
				msg_notvict = "The trap at room $u $n!";
				msg_char = "The trap at room $u you!";
				break;

			default:
				msg_notvict = "$n $u $mself!";
				msg_char = "You $u yourself!";
				break;
			}
		}
		else {
			msg_notvict = "$n $u $N.";
			msg_char = "You $u $N.";
			msg_vict = "$n $u you.";
		}
	}
	else {
		skill_t *sk;

/* XXX */
#define MAX_DAMAGE_MESSAGE 40
		if ((sk = skill_lookup(dt)))
			attack	= sk->noun_damage;
		else if (dt >= TYPE_HIT && dt <= TYPE_HIT + MAX_DAMAGE_MESSAGE)
			attack	= attack_table[dt - TYPE_HIT].noun;
		else {
			bug("Dam_message: bad dt %d.", dt);
			dt = TYPE_HIT;
			attack = attack_table[0].name;
		}

		if (immune) {
			if (ch == victim) {
				msg_notvict = "$n is unaffected by $s own $U.";
				msg_char = "Luckily, you are immune to that.";
			}
			else {
				msg_notvict = "$N is unaffected by $n's $U!";
				msg_char = "$N is unaffected by your $U!";
				msg_vict = "$n's $U is powerless against you.";
			}
		}
		else {
			vs = vp;

			if (ch == victim) {
				msg_notvict = "$n's $U $u $m.";
				msg_char = "Your $U $u you.";
			}
			else {
				msg_notvict = "$n's $U $u $N.";
				msg_char = "Your $U $u $N.";
				msg_vict = "$n's $U $u you.";
			}
		}
	}

	if (ch == victim) {
		act_puts3(msg_notvict, ch, vp, NULL, attack,
			  TO_ROOM | ACT_TRANS, POS_RESTING);
		act_puts3(msg_char, ch, vs, NULL, attack,
			  TO_CHAR | ACT_TRANS, POS_RESTING);
	}
	else {
		act_puts3(msg_notvict, ch, vp, victim, attack,
			  TO_NOTVICT | ACT_TRANS, POS_RESTING);
		act_puts3(msg_char, ch, vs, victim, attack,
			  TO_CHAR | ACT_TRANS, POS_RESTING);
		act_puts3(msg_vict, ch, vp, victim, attack,
			  TO_VICT | ACT_TRANS, POS_RESTING);
	}
}

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

	one_argument(argument, arg, sizeof(arg));

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

	WAIT_STATE(ch, 1 * PULSE_VIOLENCE);

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

	if (ch->position == POS_FIGHTING) {
		if (victim == ch->fighting)
			char_puts("You do the best you can!\n", ch);
		else if (victim->fighting != ch)
			char_puts("One battle at a time, please.\n",ch);
		else {
			act("You start aiming at $N.",ch,NULL,victim,TO_CHAR);
			ch->fighting = victim;
		}
		return;
	}

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

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

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

	if (is_safe(ch, victim))
		return;

	if ((chance = get_skill(ch, gsn_mortal_strike))
	&&  get_eq_char(ch, WEAR_WIELD)
	&&  ch->level > (victim->level - 5)) {
		chance /= 30;
		chance += 1 + (ch->level - victim->level) / 2;
		if (number_percent() < chance) {
			act_puts("Your flash strike instantly slays $N!",
				 ch, NULL, victim, TO_CHAR, POS_RESTING);
			act_puts("$n flash strike instantly slays $N!",
				 ch, NULL, victim, TO_NOTVICT,
				 POS_RESTING);
			act_puts("$n flash strike instantly slays you!",
				 ch, NULL, victim, TO_VICT, POS_DEAD);
			damage(ch, victim, (victim->hit + 1),
			       gsn_mortal_strike, DAM_NONE, DAMF_SHOW);
			check_improve(ch, gsn_mortal_strike, TRUE, 1);
			return;
		} else
			check_improve(ch, gsn_mortal_strike, FALSE, 3);
	}

	multi_hit(ch, victim, TYPE_UNDEFINED);
}

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

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

	one_argument(argument, arg, sizeof(arg));

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

	if (IS_AFFECTED(ch, AFF_CHARM)
	||  (IS_NPC(ch) && IS_SET(ch->pIndexData->act, ACT_PET)))
		return;

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

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

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

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

	if (is_safe(ch, victim))
		return;

	WAIT_STATE(ch, 1 * PULSE_VIOLENCE);

	if ((chance = get_skill(ch, gsn_mortal_strike))
	&&  get_eq_char(ch, WEAR_WIELD)
	&&  ch->level > (victim->level - 5)) {
		chance /= 30;
		chance += 1 + (ch->level - victim->level) / 2;
		if (number_percent() < chance) {
			act_puts("Your flash strike instantly slays $N!",
				 ch, NULL, victim, TO_CHAR, POS_RESTING);
			act_puts("$n flash strike instantly slays $N!",
				 ch, NULL, victim, TO_NOTVICT,
				 POS_RESTING);
			act_puts("$n flash strike instantly slays you!",
				 ch, NULL, victim, TO_VICT, POS_DEAD);
			damage(ch, victim, (victim->hit + 1),
			       gsn_mortal_strike, DAM_NONE, DAMF_SHOW);
			check_improve(ch, gsn_mortal_strike, TRUE, 1);
			return;
		} else
			check_improve(ch, gsn_mortal_strike, FALSE, 3);
	}

	multi_hit(ch, victim, TYPE_UNDEFINED);
}

void do_flee(CHAR_DATA *ch, const char *argument)
{
	ROOM_INDEX_DATA *was_in;
	ROOM_INDEX_DATA *now_in;
	CHAR_DATA *victim;
	int attempt;
	class_t *cl;

	if (RIDDEN(ch)) {
		char_puts("You should ask to your rider!\n", ch);
		return;
	}

	if (MOUNTED(ch))
		do_dismount(ch, str_empty);

	if ((victim = ch->fighting) == NULL) {
		if (ch->position == POS_FIGHTING)
			ch->position = POS_STANDING;
		char_puts("You aren't fighting anyone.\n", ch);
		return;
	}

	if ((cl = class_lookup(ch->class))
	&&  !CAN_FLEE(ch, cl)) {
		 char_puts("Your honour doesn't let you flee, "
			   "try dishonoring yourself.\n", ch);
		 return;
	}

	was_in = ch->in_room;
	for (attempt = 0; attempt < 6; attempt++) {
		EXIT_DATA *pexit;
		int door;

		door = number_door();
		if ((pexit = was_in->exit[door]) == 0
		     || pexit->to_room.r == NULL
		     || (IS_SET(pexit->exit_info, EX_CLOSED)
		         && (!IS_AFFECTED(ch, AFF_PASS_DOOR)
		             || IS_SET(pexit->exit_info,EX_NOPASS))
		             && !IS_TRUSTED(ch,ANGEL))
		         || (IS_SET(pexit->exit_info , EX_NOFLEE))
		         || (IS_NPC(ch)
		             && IS_SET(pexit->to_room.r->room_flags, ROOM_NOMOB)))
			continue;

		move_char(ch, door, FALSE);
		if ((now_in = ch->in_room) == was_in)
		    continue;

		ch->in_room = was_in;
		act("$n has fled!", ch, NULL, NULL, TO_ROOM);
		ch->in_room = now_in;

		if (!IS_NPC(ch)) {
			act_puts("You fled from combat!",
				 ch, NULL, NULL, TO_CHAR, POS_DEAD);
			if (ch->level < LEVEL_HERO) {
				char_printf(ch, "You lose %d exps.\n", 10);
				gain_exp(ch, -10);
			}
		} else
			ch->last_fought = NULL;

		stop_fighting(ch, TRUE);
		return;
	}

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

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

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

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

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

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

	if (IS_IMMORTAL(victim)) {
		char_puts("You failed.\n", ch);
		return;
	}

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

/*
 * Check for obj dodge.
 */
bool check_obj_dodge(CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj, int bonus)
{
	int chance;

	if (!IS_AWAKE(victim) || MOUNTED(victim))
		return FALSE;

	if (!IS_NPC(victim) && HAS_SKILL(victim, gsn_spellbane)) {
		if (victim->pcdata->clan_status) {
			act("You catch $p that had been shot to you.",
			    ch, obj, victim, TO_VICT);
			act("$N catches $p that had been shot to $M.",
			    ch, obj, victim, TO_CHAR);
			act("$n catches $p that had been shot to $m.",
			    victim, obj, ch, TO_NOTVICT);
			obj_to_char(obj, victim);
		}
		return TRUE;
	}

	if (IS_NPC(victim))
		 chance  = UMIN(30, victim->level);
	else {
		chance  = get_skill(victim, gsn_dodge) / 2;
		/* chance for high dex. */
		chance += 2 * (get_curr_stat(victim, STAT_DEX) - 20);
	}

	chance -= (bonus - 90);
	chance /= 2;
	if (number_percent() >= chance)
		return FALSE;

	act("You dodge $p that had been shot to you.",
	    ch, obj, victim, TO_VICT);
	act("$N dodges $p that had been shot to $M.",
	    ch, obj, victim, TO_CHAR);
	act("$n dodges $p that had been shot to $m.",
	    victim, obj, ch, TO_NOTVICT);
	obj_to_room(obj, victim->in_room);
	check_improve(victim, gsn_dodge, TRUE, 6);

	return TRUE;
}

void do_dishonor(CHAR_DATA *ch, const char *argument)
{
	ROOM_INDEX_DATA *was_in;
	ROOM_INDEX_DATA *now_in;
	CHAR_DATA *gch;
	int attempt, level = 0;
	int sn_dishonor;
	int chance;

	if (RIDDEN(ch)) {
		char_puts("You should ask to your rider!\n", ch);
		return;
	}

	if ((sn_dishonor = sn_lookup("dishonor")) < 0
	||  !HAS_SKILL(ch, sn_dishonor)) {
		char_puts("Which honor?\n", ch);
		return;
	}

	if (ch->fighting == NULL) {
		if (ch->position == POS_FIGHTING)
			ch->position = POS_STANDING;
		char_puts("You aren't fighting anyone.\n", ch);
		return;
	}

	for (gch = char_list; gch; gch = gch->next)
		  if (is_same_group(gch, ch->fighting) || gch->fighting == ch)
			level += gch->level;

	if ((ch->fighting->level - ch->level) < 5 && ch->level > (level / 3)) {
		 char_puts("Your fighting doesn't worth "
			   "to dishonor yourself.\n", ch);
		 return;
	}

	was_in = ch->in_room;
	chance = get_skill(ch, sn_dishonor);
	for (attempt = 0; attempt < 6; attempt++) {
		EXIT_DATA *pexit;
		int door;

		if (number_percent() >= chance)
			continue;

		door = number_door();
		if ((pexit = was_in->exit[door]) == 0
		||  pexit->to_room.r == NULL
		||  (IS_SET(pexit->exit_info, EX_CLOSED) &&
		     (!IS_AFFECTED(ch, AFF_PASS_DOOR) ||
		      IS_SET(pexit->exit_info,EX_NOPASS)) &&
		     !IS_TRUSTED(ch,ANGEL))
		|| IS_SET(pexit->exit_info, EX_NOFLEE)
		|| (IS_NPC(ch) &&
		    IS_SET(pexit->to_room.r->room_flags, ROOM_NOMOB)))
			continue;

		move_char(ch, door, FALSE);
		if ((now_in = ch->in_room) == was_in)
			continue;

		ch->in_room = was_in;
		act("$n has dishonored $mself!",
		    ch, NULL, NULL, TO_ROOM);
		ch->in_room = now_in;

		if (!IS_NPC(ch)) {
			char_puts("You dishonored yourself "
				     "and flee from combat.\n",ch);
			if (ch->level < LEVEL_HERO) {
				char_printf(ch, "You lose %d exps.\n",
					    ch->level);
				gain_exp(ch, -(ch->level));
			}
		}
		else
			ch->last_fought = NULL;

		stop_fighting(ch, TRUE);
		if (MOUNTED(ch))
			do_dismount(ch,str_empty);

		check_improve(ch, sn_dishonor, TRUE, 1);
		return;
	}

	char_puts("PANIC! You couldn't escape!\n", ch);
	check_improve(ch, sn_dishonor, FALSE, 1);
}

void do_surrender(CHAR_DATA *ch, const char *argument)
{
	CHAR_DATA *mob;

	if (!IS_NPC(ch)) {
		char_puts("Huh?\n", ch);
		return;
	}

	if ((mob = ch->fighting) == NULL) {
		char_puts("But you're not fighting!\n", ch);
		return;
	}
	act("You surrender to $N!", ch, NULL, mob, TO_CHAR);
	act("$n surrenders to you!", ch, NULL, mob, TO_VICT);
	act("$n tries to surrender to $N!", ch, NULL, mob, TO_NOTVICT);
	stop_fighting(ch, TRUE);
 
	if (!IS_NPC(ch) && IS_NPC(mob) 
	&&  (!HAS_TRIGGER(mob, TRIG_SURR) ||
	     !mp_percent_trigger(mob, ch, NULL, NULL, TRIG_SURR))) {
		act("$N seems to ignore your cowardly act!",
		    ch, NULL, mob, TO_CHAR);
		multi_hit(mob, ch, TYPE_UNDEFINED);
	}
}
