Mud20/accounts/
Mud20/accounts/c/
Mud20/accounts/f/
Mud20/accounts/k/
Mud20/accounts/s/
Mud20/accounts/t/
Mud20/area_current/
Mud20/area_current/newareas/
Mud20/bin/
Mud20/clans/
Mud20/gods/
Mud20/old-sources/
Mud20/player/
Mud20/player/a/del/
Mud20/player/b/
Mud20/player/b/bak/
Mud20/player/b/del/
Mud20/player/f/
Mud20/player/f/bak/
Mud20/player/f/del/
Mud20/player/k/
Mud20/player/k/bak/
Mud20/player/k/del/
Mud20/player/k/dmp/
Mud20/player/m/
Mud20/player/m/bak/
Mud20/player/o/
Mud20/player/o/bak/
Mud20/player/p/
Mud20/player/s/
Mud20/player/s/bak/
Mud20/player/s/del/
Mud20/player/t/
Mud20/player/t/del/
Mud20/player/v/
Mud20/public_html/
Mud20/races/
Mud20/skilltables/
__MACOSX/Mud20/accounts/
__MACOSX/Mud20/accounts/c/
__MACOSX/Mud20/accounts/f/
__MACOSX/Mud20/accounts/k/
__MACOSX/Mud20/accounts/s/
__MACOSX/Mud20/area_current/
__MACOSX/Mud20/area_current/core_areas/
__MACOSX/Mud20/area_current/helps/
__MACOSX/Mud20/area_current/newareas/
__MACOSX/Mud20/backups/
__MACOSX/Mud20/bin/
__MACOSX/Mud20/clans/
__MACOSX/Mud20/gods/
__MACOSX/Mud20/log/
__MACOSX/Mud20/old-sources/
__MACOSX/Mud20/player/
__MACOSX/Mud20/player/a/del/
__MACOSX/Mud20/player/b/
__MACOSX/Mud20/player/b/bak/
__MACOSX/Mud20/player/f/
__MACOSX/Mud20/player/f/bak/
__MACOSX/Mud20/player/f/del/
__MACOSX/Mud20/player/k/
__MACOSX/Mud20/player/k/bak/
__MACOSX/Mud20/player/k/del/
__MACOSX/Mud20/player/k/dmp/
__MACOSX/Mud20/player/m/
__MACOSX/Mud20/player/m/bak/
__MACOSX/Mud20/player/o/
__MACOSX/Mud20/player/o/bak/
__MACOSX/Mud20/player/p/
__MACOSX/Mud20/player/s/
__MACOSX/Mud20/player/s/bak/
__MACOSX/Mud20/player/t/del/
__MACOSX/Mud20/player/v/
__MACOSX/Mud20/public_html/
__MACOSX/Mud20/races/
__MACOSX/Mud20/skilltables/
/***************************************************************************
 * Mud20 1.0 by Todd H. Johnson (Kregor) a derivative of the Open Gaming   *
 * License by Wizards of the Coast. All comments referring to D20, OGL,    *
 * and SRD refer to the System Reference Document for the Open Gaming      *
 * system. Any inclusion of these derivatives must include credit to the   *
 * Mud20 system, the full and complete Open Gaming LIcense, and credit to  *
 * the respective authors. See ../doc/srd.txt for more information.        *
 *                                                                         *
 * Emud  2.2 by Igor van den Hoven, Michiel Lange, and Martin Bethlehem.   *
 *                                                                         *
 * MrMud 1.4 by David Bills, Dug Michael and Martin Gallwey                *
 *                                                                         *
 * 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{rfeld, Tom Madsen, and Katje Nyboe.     *
 ***************************************************************************/
/***************************************************************************
 * Originally fight.c in merc                                              *
 ***************************************************************************/

#include "mud.h"

#define DO_ABILITY(ability) 			bool ability( int sn, int level, CHAR_DATA *ch, void *vo, int target )
/*
	Global functions.
*/

sh_int	martial_arts_attack;
sh_int	body_part_attack;
sh_int	brawling_attack;

bool remove_obj args( ( CHAR_DATA *ch, int iWear, bool fReplace, bool fDisplay ) );

/*
 * Kludgy globals for passing the dam_type and critical hit along
 */
int DAM_TYPE;
bool CRIT_HIT = FALSE;
bool confused = FALSE;

/*
	Local functions.
*/
void		spam_attack_list		args( ( CHAR_DATA * ) );
void		add_to_victory_list	args( ( CHAR_DATA *, CHAR_DATA *) );
void		arena_death					args( ( CHAR_DATA *victim ) );
void		newbie_death				args( ( CHAR_DATA *victim ) );
void		player_death				args( ( CHAR_DATA *victim, int dt ) );
void		dam_message					args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, OBJ_DATA *wield));
char		*get_dam_nounce			args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dt, OBJ_DATA *wield));
bool		has_mirror					args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dt));
int			xp_compute					args( ( CHAR_DATA *gch,CHAR_DATA *victim ) );
void		group_gain					args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
bool		whirl								args( ( CHAR_DATA *ch ) );


/*
 * Unarmed attack tables - random
 * damage nouns for each attack.
 */
const struct attack_type martial_arts_table[] =
{
	{
		"combination punch",			DAM_BASH
	},
	{
		"palm punch",							DAM_BASH
	},
	{
		"thrust kick",						DAM_BASH
	},
	{
		"spinning back-hand",			DAM_BASH
	},
	{
		"jump kick",							DAM_BASH
	},
	{
		"round house",						DAM_BASH
	},
	{
		"flip kick",							DAM_BASH
	},
	{
		"thrusting spear hand",		DAM_PIERCE
	},
	{
		"spinning reverse kick",	DAM_BASH
	},
	{
		"spinning hook kick",			DAM_BASH
	},
	{
		"flying scissors kick",		DAM_BASH
	},
	{
		"triple round house kick",DAM_BASH
	}
};


const struct attack_type brawling_table[] =
{
	{
		"combination punch",	DAM_BASH
	},
	{
		"uppercut",						DAM_BASH
	},
	{
		"kidney punch",				DAM_BASH
	},
	{
		"right hook",					DAM_BASH
	},
	{
		"left hook",					DAM_BASH
	},
	{
		"sucker punch",				DAM_BASH
	},
	{
		"knee",								DAM_BASH
	},
	{
		"head butt",					DAM_BASH
	},
	{
		"elbow slam",					DAM_BASH
	}
};

/*
 * Fixed damage dice based on size and body part,
 * taken from Pathfinder RPG's Universal Monster
 * Rules for all creature attacks - Kregor
 */
const	struct	attack_part_type	dam_no_dice [ATTK_MAX] =
{							
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 4}	}, /* BITE */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* CLAW */	
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* GORE */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* HOOF */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 1, 2}	}, /* KICK */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 4}	}, /* PINCER */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 1, 2}	}, /* PUNCH */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* RAKE */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* SLAM */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* STING */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 4}	}, /* TAIL */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* TALON */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* TENTACLE */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* WING */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 2, 2}	}, /* OTHER */
	{	{0, 1, 1, 1, 1, 1, 1, 1, 1, 1}	}  /* TOUCH */
};							

const	struct	attack_part_type	dam_size_dice [ATTK_MAX] =
{							
	{	{0, 1, 2, 3, 4, 6, 8, 12, 8, 6}	}, /* BITE */
	{	{0, 1, 1, 2, 3, 4, 6, 8,  6, 8}	}, /* CLAW */
	{	{0, 1, 2, 3, 3, 4, 6, 8,  6, 8}	}, /* GORE */
	{	{0, 1, 1, 2, 3, 4, 6, 8,  6, 8}	}, /* HOOF */
	{	{0, 1, 1, 1, 2, 3, 4, 6,  8, 6}	}, /* KICK */
	{	{0, 1, 2, 3, 4, 6, 8, 12, 8, 6}	}, /* PINCER */
	{	{0, 1, 1, 1, 2, 3, 4, 6,  8, 6}	}, /* PUNCH */
	{	{0, 1, 1, 2, 3, 4, 6, 8,  6, 8}	}, /* RAKE */
	{	{0, 1, 1, 2, 3, 4, 6, 8,  6, 8}	}, /* SLAM */
	{	{0, 1, 1, 2, 3, 4, 6, 8,  6, 8}	}, /* STING */
	{	{0, 1, 2, 3, 4, 6, 8, 12, 8, 6}	}, /* TAIL */
	{	{0, 1, 1, 2, 3, 4, 6, 8,  6, 8}	}, /* TALON */
	{	{0, 1, 1, 2, 3, 4, 6, 8,  6, 8}	}, /* TENTACLE */
	{	{0, 1, 1, 2, 3, 4, 6, 8,  6, 8}	}, /* WING */
	{	{0, 1, 1, 2, 3, 4, 6, 8,  6, 8}	}, /* OTHER */
	{	{0, 1, 1, 1, 1, 1, 1, 1,  1, 1}	}  /* TOUCH */
};							

const	struct	body_type	attack_part_table	[ATTK_MAX]	=
{
	{		"bite",					DAM_PIERCE|DAM_BASH|DAM_SLASH, TRUE, TRUE	},
	{		"claw",					DAM_BASH|DAM_SLASH, TRUE, TRUE	},
	{		"gore",					DAM_PIERCE, TRUE, TRUE	},
	{		"kick",					DAM_BASH, FALSE, TRUE	},
	{		"kick",					DAM_BASH, FALSE, FALSE	},
	{		"pincer",				DAM_PIERCE, FALSE, TRUE	},
	{		"punch",				DAM_BASH,	TRUE, FALSE	},
	{		"rake",					DAM_SLASH, FALSE, TRUE	},
	{		"slam attack",	DAM_BASH, TRUE, TRUE	},
	{		"sting",				DAM_PIERCE, TRUE, TRUE	},
	{		"tail slap",		DAM_BASH, FALSE, TRUE	},
	{		"talon",				DAM_SLASH, TRUE, TRUE	},
	{		"tentacle",			DAM_BASH|DAM_SLASH, FALSE, TRUE	},
	{		"wing buffet",	DAM_BASH, FALSE, TRUE	},
	{		"attack",				DAM_BASH, FALSE, TRUE	},
	{		"touch",				DAM_NONE, TRUE, TRUE	}
};



/*
 * Returns TRUE if the skill number
 * deals a physical attack - Kregor 
 */
bool is_attack( int sn )
{
	push_call("is_attack(%p)",sn);

	if (sn >= TYPE_HIT)
	{
		pop_call();
  	return TRUE;
  }
  if (sn == TYPE_NOFIGHT)
	{
		pop_call();
  	return FALSE;
  }
  if (sn == gsn_whirl
  || sn == gsn_opportunist
  || sn == gsn_sunder
  || sn == gsn_coup_de_grace
  || sn == gsn_stunning_fist
  || sn == gsn_backstab
  || sn == gsn_assassinate
  || sn == gsn_quivering_palm
  || sn == gsn_martial_arts
  || sn == gsn_shield_bash)
	{
		pop_call();
  	return TRUE;
  }
	pop_call();
	return FALSE;
}


/*
 * Rolled all the checks for making a sneak attack
 * into this one function here - Kregor
 */
bool can_backstab( CHAR_DATA *ch, CHAR_DATA *victim, int dt )
{
	push_call("can_backstab(%p,%p)",ch,victim);
	
	if (!in_same_room(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (is_spell(dt))
	{
		if (!IS_SET(skill_table[dt].flags, SF_RANGED_TOUCH) && !IS_SET(skill_table[dt].flags, SF_TOUCH))
		{
			pop_call();
			return FALSE;
		}
		if (!learned(ch, gsn_sneaky_spell))
		{
			pop_call();
			return FALSE;
		}
	}

	if (!learned(ch, gsn_backstab))
	{
		// sleeping tiger ability gained at lvl 12
		if (get_monk_style(ch) != STYLE_SLEEPING_TIGER || class_level(ch, CLASS_MONK) < 12)
		{
			pop_call();
			return FALSE;
		}
	}
	if (IS_AFFECTED(ch, AFF2_BERSERK)) // no precision dmg while raging
	{
		pop_call();
		return FALSE;
	}
	if (!CAN_CRITICAL(victim))
	{
		if (!IS_UNDEAD(victim) || !is_affected(ch, gsn_channeling_attack))
		{
			pop_call();
			return FALSE;
		}
	}
	if (is_affected(victim, gsn_defensive_stance) && learned(victim, gsn_impenetrable_defense))
	{
		pop_call();
		return FALSE;
	}
	if (!can_see(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	if (arcane_mastery(victim, SCHOOL_DIVINATION))
	{
		pop_call();
		return FALSE;
	}
	if (!is_affected(victim, gsn_foresight))
	{
		pop_call();
		return FALSE;
	}
	// if victim is too small, or too large, you can't hit critical spots
	if (get_size(victim) < get_size(ch) - 1 || get_size(victim) > get_size(ch) + 1)
	{
		pop_call();
		return FALSE;
	}
	if (is_mounting(ch) || is_mounted(ch))
	{
		pop_call();
		return FALSE;
	}
	if (dt == gsn_backstab)
	{
		pop_call();
		return TRUE;
	}
	if (!is_affected(ch, gsn_impromptu_sneak_attack))
	{
		if (dt != gsn_opportunist && can_dodge(victim, ch) && !is_flanking(ch, victim))
		{
			pop_call();
			return FALSE;
		}	
	}
	pop_call();
	return TRUE;
}

/* 
 * checks for conditions that would prevent
 * ch from physically attacking victim - Kregor 2/20/11
 * should be called in any function that can be
 * considered a melee attack!
 */
bool can_melee_attack( CHAR_DATA *ch, CHAR_DATA *victim )
{
	OBJ_DATA *wield;

	push_call("can_melee_attack($p,$p,)",ch,victim);
	
	// incorporeals cannot hit someone unless wielding a ghost touch weapon - Kregor
	if (IS_INCORPOREAL(ch) && !IS_INCORPOREAL(victim))
	{
		// special incorp touch attack is allowed
		if (ch->attack_part != ATTK_TOUCH)
		{
			if ((wield = get_wield(ch, FALSE)) == NULL || !WEAPON_FLAG(wield, WFLAG_GHOST_TOUCH))
			{
				act("You cannot touch $N to attack $M.", ch, NULL, victim, TO_CHAR);
				pop_call();
				return FALSE;
			}
		}
	}
	//prot from alignment hedges summoned creatures IF not attacked - Kregor
	if (IS_ACT(ch, ACT_SUMMONED) || race_type(ch) == RTYPE_OUTSIDER)
	{
		if ((IS_EVIL(ch) && get_apply(victim, APPLY_RES_EVIL))
		|| (IS_GOOD(ch) && get_apply(victim, APPLY_RES_GOOD))
		|| (IS_LAWFUL(ch) && get_apply(victim, APPLY_RES_LAW))
		|| (IS_CHAOTIC(ch) && get_apply(victim, APPLY_RES_CHAOS)))
		{
			if (!victim->last_attacked || victim->last_attacked != ch)
			{
				act("$N's wards hedge you away!", ch, NULL, victim, TO_CHAR);
				act("Your wards hedge $n away!", ch, NULL, victim, TO_VICT);
				act( "$n recoils away from $N.", ch, NULL, victim, TO_NOTVICT );
				pop_call();
				return FALSE;
			}
		}
	}
	if (is_affected(victim, gsn_repulsion))
	{
		if (!ch->last_attacker || ch->last_attacker != victim)
		{
			if (!save_resist(ch, victim, gsn_repulsion, get_affect_level(victim, gsn_repulsion)))
			{
				pop_call();
				return FALSE;
			}
		}
	}
	if (is_affected(victim, gsn_antilife_shell))
	{
		switch (race_type(ch))
		{
			case RTYPE_CONSTRUCT:
			case RTYPE_OUTSIDER:
			case RTYPE_UNDEAD:
				break;
			default:
				if (!ch->last_attacker || ch->last_attacker != victim)
				{
					if (!save_resist(ch, victim, gsn_antilife_shell, get_affect_level(victim, gsn_antilife_shell)))
					{
						pop_call();
						return FALSE;
					}
				}
				break;
		}
	}
	if (is_affected(victim, gsn_repel_metal))
	{
		if (wears_metal(ch, TRUE))
		{
			pop_call();
			return FALSE;
		}
	}
	pop_call();
	return TRUE;
}


/*
 * Actively reload a missile weapon to prepare
 * it to fire without reloading delay.
 */
void do_reload(CHAR_DATA *ch, char *argument)
{
	OBJ_DATA *wield;
	
	push_call("do_reload(%p,%p)",ch,argument);
	
	if ((wield = get_wield(ch, FALSE)) == NULL)
	{
		send_to_char_color("You are holding no weapon to reload.\n\r", ch);
		pop_call();
		return;
	}
	if (!is_missile_weapon(wield))
	{
		send_to_char_color("You aren't wielding a missile weapon.\n\r", ch);
		pop_call();
		return;
	}
	if (get_ammo(ch, wield) == NULL)
	{
		send_to_char_color("{138}Oops...forgot to stock up on ammunition, eh?{300}\n\r", ch);
		ch->reloaded = FALSE;
		pop_call();
		return;
	}
	if (ch->reloaded)
	{
		send_to_char_color("Your weapon is already loaded.\n\r", ch);
		pop_call();
		return;
	}
	reload(ch, wield);
	pop_call();
	return;
}


/*
 * Checks to see if a missile weapon is loaded
 * if not, search for ammunition, if ammo found,
 * set action time to reload. Returns FALSE if
 * cannot fire immediately for whatever reason - Kregor
 */
bool reload( CHAR_DATA *ch, OBJ_DATA *wield )
{
	OBJ_DATA *ammo = NULL;

	push_call("reload(%p,%p)",ch,wield);
	
	if (wield == NULL || !is_missile_weapon(wield))
	{
		ch->reloaded = FALSE;
		pop_call();
		return FALSE;
	}

	if ((ammo = get_ammo(ch, wield)) == NULL)
	{
		send_to_char_color("{138}Oops...forgot to stock up on ammunition, eh?{300}\n\r", ch);
		ch->reloaded = FALSE;
		pop_call();
		return FALSE;
	}
	
	if (hands_full(ch))
	{
		if (!WEAPON_TYPE(wield, WEAPON_TYPE_SLING))
		{
			act("You cannot reload $p without a free hand.", ch, wield, NULL, TO_CHAR);
			pop_call();
			return FALSE;
		}
		if (ch->reloaded)
		{
			if (!WEAPON_TYPE(wield, WEAPON_TYPE_CROSSBOW_HAND)
			&& !WEAPON_TYPE(wield, WEAPON_TYPE_SLING))
			{
				act("You cannot shoot $p without a free hand.", ch, wield, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}			
			pop_call();
			return TRUE;
		}
	}	
	
	if (ch->reloaded)
	{
		pop_call();
		return TRUE;
	}

	switch(wield->value[0])
	{
		default:
			if (!learned(ch, gsn_rapid_reload))
			{
				act( "You pause to reload $p.", ch, wield, NULL, TO_CHAR);
				act( "$n pauses to reload $p.", ch, wield, NULL, TO_ROOM);
				if (IS_SET(ch->action, ACTION_MOVE))
				{
					TAKE_ACTION(ch, ACTION_STANDARD);
					pop_call();
					return FALSE;
				}
				else
				{
					TAKE_ACTION(ch, ACTION_MOVE);
				}
			}
			break;
		case WEAPON_TYPE_CROSSBOW_HEAVY:
			if (!learned(ch, gsn_rapid_reload))
			{
				act( "You pause to reload $p.", ch, wield, NULL, TO_CHAR);
				act( "$n pauses to reload $p.", ch, wield, NULL, TO_ROOM);
				TAKE_ACTION(ch, ACTION_FULL);
				pop_call();
				return FALSE;
			}
			else
			{
				act( "You pause to reload $p.", ch, wield, NULL, TO_CHAR);
				act( "$n pauses to reload $p.", ch, wield, NULL, TO_ROOM);
				if (IS_SET(ch->action, ACTION_MOVE))
				{
					TAKE_ACTION(ch, ACTION_STANDARD);
					pop_call();
					return FALSE;
				}
				else
				{
					TAKE_ACTION(ch, ACTION_MOVE);
				}
			}
			break;
		case WEAPON_TYPE_SHORTBOW:
		case WEAPON_TYPE_SHORTBOW_COMPOSITE:
		case WEAPON_TYPE_LONGBOW:
		case WEAPON_TYPE_LONGBOW_COMPOSITE:
			break;
	}
	ch->reloaded = TRUE;
	pop_call();
	return TRUE;
}


/*
 * new function for manyshot, makes it work right
 * in do_attack or do_shoot. Hacked one_hit and took
 * out everything except finding ammo and dealing
 * base damage, cuz crits and backstab don't count - Kregor
 */
bool manyshot_hit(CHAR_DATA *ch, CHAR_DATA *victim, int dt, int hit_adj, OBJ_DATA *wield)
{
	OBJ_DATA *ammo;
	int dam;

	push_call("manyshot_hit(%p,%p,%p)",ch,victim,dt);

	if (ch == NULL || victim == NULL)
	{
		pop_call();
		return FALSE;
	}
	
	if (wield == NULL || !is_missile_weapon(wield))
	{
		pop_call();
		return FALSE;
	}
	
	if (!COMBATMODE(ch, COMBAT_MANYSHOT))
	{
		pop_call();
		return FALSE;
	}
	
	switch(wield->value[0])
	{
		case WEAPON_TYPE_SHORTBOW:
		case WEAPON_TYPE_SHORTBOW_COMPOSITE:
		case WEAPON_TYPE_LONGBOW:
		case WEAPON_TYPE_LONGBOW_COMPOSITE:
		case WEAPON_TYPE_SLING:
			break;
		default:
			send_to_char("You can only manyshot with a bow or sling.\n\r", ch);
			REMOVE_BIT(ch->combatmode, COMBAT_MANYSHOT);
			pop_call();
			return FALSE;
	}

	if (hit_adj == -5 && base_attack(ch) <= 10)
	{
		pop_call();
		return FALSE;
	}
	
	if (hit_adj == -10 && base_attack(ch) <= 15)
	{
		pop_call();
		return FALSE;
	}

	if (hit_adj < -10)
	{
		pop_call();
		return FALSE;
	}

	if ((ammo = get_ammo(ch, wield)) == NULL)
	{
		pop_call();
		return FALSE;
	}
	
	/*
		Calc damage and check for specials
	*/
	dam = GET_DAMROLL(ch, victim, dt, wield);

	if (!deflect_missile(victim, ch, ammo, -1))
	{
		damage(ch, victim, dam, dt, wield);
		/* weapon spells on missile ammo here */
		if (weapon_cast_spell(ammo->value[2], ammo->value[3], ch, victim, ammo))
			ammo->value[2] = ammo->value[3] = 0;
	}
	junk_obj(ammo);

	pop_call();
	return TRUE;
}


/*
 * Return throw of snatched thrown weapon using Snatch Missiles feat. 
 */
void throwback( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *weapon, int dir )
{
	int range, diceroll, dam, mult;
	
	push_call("throwback(%p,%p)",ch,victim);

	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}
	
	if (weapon->carried_by != ch)
	{
		pop_call();
		return;
	}

	if (!weapon || !IS_WEAPON(weapon))
	{
		pop_call();
		return;
	}
	
	if (dir != -1)
	{
		dir = rev_dir[dir];

		if (!can_see_dir(ch, victim, dir))
		{
			send_to_char("Your attacker must have slipped out of sight.\n\r", ch);
			pop_call();
			return;
		}
	
		if ((range = get_missile_range(weapon)) <= 0 || findpath_search_victim(ch, victim, range) == -1)
		{
			send_to_char("Your target is out of range.\n\r", ch);
			pop_call();
			return;
		}
	}
		
	CHECK_TURN(ch, victim);

	int dt = TYPE_HIT;
	int hit_mod = 0;
	diceroll = dice(1,20);
	CRIT_HIT = FALSE;

	if (diceroll == 1 && !WEAPON_FLAG(weapon, WFLAG_SEEKING))
		ch_printf_color(ch, "{118}You score a critical miss!\n\r");
	
	if (number_percent() > get_apply(victim, APPLY_FORTIFICATION))
	{
		int threat = weapon_table[weapon->value[0]].threat;
	
		if (WEAPON_FLAG(weapon, WFLAG_KEEN))
		{
			threat = (20 - threat) * 2;
			threat = 20 - threat;
		}
		if (IS_SET(weapon_skill(ch, weapon), WSKILL_IMP_CRITICAL))
		{
			threat += 1;
		}
		if (diceroll == 20 || diceroll >= threat)
		{
			if (check_hit(ch, victim, dice(1,20), hit_mod, dt, weapon, FALSE, TRUE)
			|| (fave_enemy_bonus(ch, victim) && learned(ch, gsn_master_hunter))
			|| (can_backstab(ch, victim, dt) && learned(ch, gsn_stealth_mastery))
			|| (is_affected(victim, gsn_smite) && get_caster(victim, gsn_smite) == ch && (learned(ch, gsn_holy_champion) || learned(ch, gsn_unholy_champion))))
			{
				CRIT_HIT = TRUE;
				ch_printf_color(ch, "{118}You score a critical hit!\n\r");
			}
		}
	}

	if (!WEAPON_FLAG(weapon, WFLAG_SEEKING) && !CRIT_HIT && !check_hit(ch, victim, diceroll, hit_mod, dt, weapon, FALSE, TRUE))
	{
		dam_message(ch, victim, 0, dt, weapon);

		if (!WEAPON_FLAG(weapon, WFLAG_RETURNING) && (!WSPEC(weapon, WSPEC_RETURNING) || !weapon_skill(ch, weapon)))
		{
			weapon->sac_timer = OBJ_SAC_TIME;
			obj_to_room(weapon, victim->in_room->vnum);
		}
		else
		{
			act( "$p returns to $n's hand.", ch, weapon, NULL, TO_ROOM );
			act( "$p returns to your hand.", ch, weapon, NULL, TO_CHAR );
		}
	}
	else
	{
		dam = GET_DAMROLL(ch, victim, dt, weapon);
		mult = weapon_table[weapon->value[0]].critical;

		if (IS_SET(weapon_skill(ch, weapon), WSKILL_IMP_CRITICAL) && learned(ch, gsn_weapon_grandmastery))
			mult++;

		if (CRIT_HIT && CAN_CRITICAL(victim) && (!is_affected(victim, gsn_defensive_stance) || !learned(victim, gsn_impenetrable_defense)))
			dam *= mult;

		if (!deflect_missile(victim, ch, weapon, dir))
		{
			damage(ch, victim, dam, dt, weapon);

			if (weapon_cast_spell(weapon->value[2], weapon->value[3], ch, victim, weapon))
				weapon->value[2] = weapon->value[3] = 0;
		
			if (!WEAPON_FLAG(weapon, WFLAG_RETURNING) && (!WSPEC(weapon, WSPEC_RETURNING) || !weapon_skill(ch, weapon)))
				obj_to_char(weapon, victim);
			else
			{
				act( "$p returns to $n's hand.", ch, weapon, NULL, TO_ROOM );
				act( "$p returns to your hand.", ch, weapon, NULL, TO_CHAR );
			}
		}
		if (dir != -1 && !IS_NPC(ch) && MP_VALID_MOB(victim))
		{
			mprog_range_trigger(victim, ch, rev_dir[dir]);
		}
	}
	if (is_affected(ch, gsn_impromptu_sneak_attack))
		affect_strip(ch, gsn_impromptu_sneak_attack);

	pop_call();
	return;
}

/*
 * Displays a list of all your current fight participants - Kregor
 */
void fight_list(CHAR_DATA * ch)
{
	char buf[MAX_STRING_LENGTH];
	CHAR_DATA *unit, *vch;
	int count = 0;
	char colg[20], colw[20], colW[20], colG[20], colR[20];

	push_call("fight_list(%p)",ch);

	if (!in_combat (ch))
	{
		send_to_char ("You aren't part of a battle.\n\r", ch);
		pop_call();
		return;
	}
	
	strcpy(colg, get_color_string(ch, COLOR_ACCENT, VT102_DIM));
	strcpy(colw, get_color_string(ch, COLOR_TEXT, VT102_DIM));
	strcpy(colW, get_color_string(ch, COLOR_TEXT, VT102_BOLD));
	strcpy(colG, get_color_string(ch, COLOR_TACT_PARTY, VT102_BOLD));
	strcpy(colR, get_color_string(ch, COLOR_TACT_ENEMY, VT102_BOLD));

	for (buf[0] = '\0', unit = ch->in_battle->unit_list; unit != NULL; unit = unit->next_in_battle)
	{
		count++;

		cat_sprintf(buf, "%s[%s%2d%s] ", colg, colW, count, colg);

		vch = who_fighting(unit);
		
		if (unit != ch)
		{
			if (is_same_group(unit, ch))
				cat_sprintf(buf, "%s%s is attacking %s.\n\r", colG, PERS(unit, ch), vch == NULL ? "Noone" : vch == ch ? "YOU" : PERS(vch, ch));
			else
				cat_sprintf(buf, "%s%s is attacking %s.\n\r", colR, PERS(unit, ch), vch == NULL ? "Noone" : vch == ch ? "YOU" : PERS(vch, ch));
		}
		else
		{
			cat_sprintf(buf, "%sYou are attacking %s.\n\r", colw, vch == NULL ? "Noone" : PERS(vch, ch));
		}
	}
	send_to_char_color(buf, ch);
	pop_call();
	return;
}


/*
 * Begins a fight against a victim, or dsplays a list of
 * those in an active fight - Kregor
 */
void do_fight (CHAR_DATA * ch, char * argument)
{
	CHAR_DATA *victim;

	push_call("do_fight(%p,%p)",ch,argument);

	if (argument[0] != '\0')
	{
		if (!strcasecmp(argument, "list"))
		{
			if (!in_combat(ch))
			{
				send_to_char ("You're not in combat.\n\r", ch);
				pop_call();
				return;
			}
			fight_list(ch);
			pop_call();
			return;
		}
		else
		{
			if (in_combat(ch))
			{
				send_to_char ("You're already fighting.\n\r", ch);
				pop_call();
				return;
			}
		}
	}
	else
	{
		if (in_combat(ch))
		{
			fight_list(ch);
			pop_call();
			return;
		}
		send_to_char ("Fight whom?\n\r", ch);
		pop_call();
		return;
	}

	if ((victim = get_char_room (ch, argument)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}
	if (victim == ch)
	{
		send_to_char ("You won!\n\r", ch);
		pop_call();
		return;
	}
	fight(ch, victim);
	pop_call();
	return;
}

/*
 * mobiles use this function, PCs use the do_fun above
 * to trigger this function - Kregor
 */
void fight(CHAR_DATA * ch, CHAR_DATA * victim)
{	
	push_call("fight(%p,%p)",ch,victim);
	
	if (ch == NULL || victim == NULL || victim->position == POS_DEAD)
	{
		pop_call();
		return;
	}

	if (ch == victim)
	{
		pop_call();
		return;
	}

	if (in_combat(ch))
	{
		pop_call();
		return;
	}

	if (is_safe(ch,victim))
	{
		pop_call();
		return;
	}

	if (!check_murder(ch, victim))
	{
		pop_call();
		return;
	}
	
	/*
		set recently fought
	*/
	if (!IS_NPC(ch) && IS_NPC(victim))
	{
		if (ch->leader && !IS_NPC(ch->leader))
		{
			victim->npcdata->pvnum_last_hit = ch->leader->pcdata->pvnum;
		}
		else
		{
			victim->npcdata->pvnum_last_hit = ch->pcdata->pvnum;
		}
	}

	if (in_combat (victim))
	{
		char_to_combat (ch, victim->in_battle);
		set_fighting(ch, victim);
		act ("You rush headlong into the fray!", ch, NULL, victim, TO_CHAR);
		act ("$n rushes headlong into the fray!", ch, NULL, victim, TO_ROOM);
		pop_call();
		return;
	}
	initiate_combat (ch, victim);
	if (IS_AWAKE(ch) && IS_AWAKE(victim) && can_see(victim, ch) && in_same_room(ch, victim))
	{
		act ("You initiate combat against $N.", ch, NULL, victim, TO_CHAR);
		act ("$n initiates combat against you.", ch, NULL, victim, TO_VICT);
		act ("$n initiates combat against $N.", ch, NULL, victim, TO_NOTVICT);
	}
	pop_call();
	return;
}


/*
 * Delays your turn, letting the next character go first,
 * permanently swaps places with the next character.
 */
void do_delay (CHAR_DATA * ch, char * argument)
{
	int initA, initB;
	CHAR_DATA *rch;

	push_call("do_delay(%p,%p)",ch,argument);

	if (!in_combat(ch))
	{
		act ("You are not in combat.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}
	
	if (!is_active(ch))
	{
		act ("Just wait your turn.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}
	
	if (ch->action != 0)
	{
		act ("You cannot delay after you have already acted.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if ((rch = ch->in_battle->turn_list->next->unit) == NULL)
	{
		bug("do_delay: null rch", 0);
		pop_call();
		return;
	}

	initA = ch->initiative;
	initB = rch->initiative;

	act ("You bide your time to see what $N will do.", ch, NULL, rch, TO_CHAR);
	act ("$n bides $s time to see what you will do.", ch, NULL, rch, TO_VICT);
	act ("$n bides $s time to see what $N will do.", ch, NULL, rch, TO_NOTVICT);
			
	ch->initiative = initB;
	rch->initiative = initA;
	
	SET_BIT(ch->attack, ATTACK_DELAY);
	
// 	skip_turn (ch->turn, TRUE);
	swap_turn (ch->turn, rch->turn);

	pop_call();
	return;
}

/*
 * Attempts to withdraw from combat. Subject to
 * attacks of opportunity unless you have the
 * spring attack feat, or can tumble away.
 */
void do_withdraw (CHAR_DATA * ch, char * argument)
{
	CHAR_DATA *rch, *rch_next;
	EXIT_DATA *pExitData;
	int dir, attempts, to_room;
	
	push_call("do_withdraw(%p,%p)",ch,argument);

	if (!in_combat(ch))
	{
		send_to_char("You aren't fighting anyone.\n\r", ch);
		pop_call();
		return;
	}

	if (!is_active(ch))
	{
		send_to_char ("Just wait your turn to run away screaming!\n\r", ch);
		pop_call();
		return;
	}

	if (IS_AFFECTED(ch, AFF2_BERSERK))
	{
		send_to_char( "You aren't of clear mind to do that!\n\r", ch );
		pop_call();
		return;
	}

	if (ch->position < POS_FIGHTING)
	{
		send_to_char("Get up first!.\n\r", ch);
		pop_call();
		return;
	}

	if ((ch->action != 0 || IS_SET(ch->attack, ATTACK_MELEE)) && !learned(ch, gsn_spring_attack))
	{
		send_to_char ("You cannot withdraw after acting on your turn.\n\r", ch);
		pop_call();
		return;
	}

	if (argument == NULL)
	{
		for (dir = -1, attempts = 0 ; attempts < 100 ; attempts++)
		{
			dir = number_range(0,5);
			if (can_move_char(ch, dir))
				break;
			dir = -1;
		}
		if (dir == -1)
		{
			send_to_char("Argh! You can't find an escape!!\n\r",ch);
			pop_call();
			return;
		}
	}
	else if (argument[0] == '\0')
	{
		send_to_char ("Withdraw in what direction?\n\r", ch);
		pop_call();
		return;
	}
	else if ((dir = direction_door(argument)) == -1 || !can_move_char(ch, dir))
	{
		send_to_char("There is no escape in that direction!\n\r",ch);
		pop_call();
		return;
	}
	
	if ((pExitData = get_exit(ch->in_room->vnum, dir)) == NULL)
	{
		bug("do_withwraw: NULL room",0);
		pop_call();
		return;
	}

	if (IS_SET(ch->in_room->room_flags, ROOM_FOG)
	&& !can_see_smoke(ch) && number_bits(2))
	{
		send_to_char( "You blunder around and get lost in the cloud!\n\r", ch);
		TAKE_ACTION(ch, ACTION_MOVE);
		pop_call();
		return;
	}

	if (IS_SET(ch->in_room->room_flags, ROOM_ICE) && !IS_FLYING(ch) && !IS_AFFECTED(ch, AFF_WATER_WALK))
	{
		if (!tumble_check(ch, NULL, tumble_roll(ch), 15))
		{
			switch (number_bits(1))
			{
				case 0:
					act( "You try to flee but your feet slip on the icy surface.",		ch, NULL, NULL, TO_CHAR);
					act( "$n tries to flee but $s feet slip on the icy surface.",		ch, NULL, NULL, TO_ROOM);
					break;
				case 1:
					act( "Your feet slip as you try to flee and you crash to the ice.",	ch, NULL, NULL, TO_CHAR);
					act( "$n's feet slip as $e tries to flee and $e crashes to the ice.",	ch, NULL, NULL, TO_ROOM);
					break;
			}
			TAKE_ACTION(ch, ACTION_MOVE);
			update_pos(ch,POS_RESTING);
			pop_call();
			return;
		}
	}

	to_room = pExitData->to_room;
	
	act( "$n withdraws hastily from combat!", ch, NULL, NULL, TO_ROOM );
	act( "You withdraw hastily from combat!", ch, NULL, NULL, TO_CHAR );
	
	/* provoke attacks of opportunity without Spring Attack */
	if (!learned(ch, gsn_spring_attack))
	{
		for (rch = ch->in_room->first_person ; rch != NULL ; rch = rch_next)
		{
			rch_next = rch->next_in_room;
	
			// stop the loop if he dies
			if (!valid_fight(rch, ch))
				break;

			if (rch == ch)
				continue;

			if (rch->last_attacker && rch->last_attacker == ch)
			{
				if (combat_maneuver_check(rch, ch, gsn_tumble) >= 0)
					attack_of_opportunity(rch, ch);
				continue;
			}

			if (rch->last_attacked && rch->last_attacked == ch)
			{
				if (combat_maneuver_check(rch, ch, gsn_tumble) >= 0)
					attack_of_opportunity(rch, ch);
				continue;
			}
		}
	}
	
	// if he gets toasted, he can't flee - Kregor
	if (!IS_HELPLESS(ch))
	{
		pop_call();
		return;
	}

	withdraw_combat(ch);
	char_from_room(ch);
	char_to_room(ch, to_room, TRUE);
	
	act( "$n glances around for signs of pursuit.", ch, NULL, NULL, TO_ROOM);
	act( "You glance around for signs of pursuit.", ch, NULL, NULL, TO_CHAR);

	TAKE_ACTION(ch, ACTION_MOVE);
	pop_call();
	return;
}


/*
 * Grappling support added here. Hacked
 * shadowing code for starters - Kregor
 */
void start_grapple (CHAR_DATA *ch, CHAR_DATA *victim)
{
	push_call("start_grapple(%p,%p)",ch,victim);

	if (ch->grappling || ch->grappled_by)
	{
		bug("start_grapple : already grappling.", 0);
		pop_call();
		return;
	}
	if (is_affected(victim, gsn_crushing_hand)
	|| is_affected(victim, gsn_grasping_hand)
	|| is_affected(ch, gsn_crushing_hand)
	|| is_affected(ch, gsn_grasping_hand))
	{
		pop_call();
		return;
	}
	act("$tYou grapple $N.", ch, get_color_string(ch, COLOR_YOU_HIT, VT102_BOLD), victim, TO_CHAR);
	act("$t$n grapples you!", ch, get_color_string(ch, COLOR_YOU_ARE_HIT, VT102_BOLD), victim, TO_VICT);
	act("{178}$n grapples $N!", ch, NULL, victim, TO_NOTVICT);
	ch->grappling = victim;
	victim->grappled_by = ch;

	pop_call();
	return;
}


void stop_grapple (CHAR_DATA *ch)
{
	push_call("stop_grapple(%p)",ch);

	if (ch->grappling == NULL)
	{
		pop_call();
		return;
	}
	act("{178}You stop grappling $N.", ch, NULL, ch->grappling, TO_CHAR);
	act("$tYou break $n's grapple!", ch, get_color_string(ch, COLOR_YOU_HIT, VT102_BOLD), ch->grappling, TO_VICT);
	act("{178}$N breaks $n's grapple!", ch, NULL, ch->grappling, TO_NOTVICT);

	ch->grappling->grappled_by = NULL;
	ch->grappling = NULL;

	pop_call();
	return;
}


/*
 * Grapple maneuver from Pathfinder RPG SRD - Kregor
 */
void do_grapple( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	int check;

	push_call("do_grapple(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		if ((victim = ch->last_attacked) == NULL)
		{
			send_to_char( "Grapple whom?\n\r", ch );
			pop_call();
			return;
		}
	}
	else if ((victim = get_char_room(ch, argument)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}
	
	if (ch->grappling)
	{
		send_to_char( "You are already grappling someone.\n\r", ch );
		pop_call();
		return;
	}
	
	if (!race_skill(ch, gsn_grab) && hands_full(ch))
	{
		send_to_char( "You have no free hand to grapple with.\n\r", ch );
		pop_call();
		return;
	}
	
	if (ch == victim)
	{
		send_to_char( "You give yourself a big bear hug!\n\r", ch );
		act("$n gives $mself a big bear hug!", ch, NULL, NULL, TO_ROOM);
		pop_call();
		return;
	}

	if (!IS_AWAKE(victim))
	{
		act( "You can't grapple $N while $E's down.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (get_size(ch) + 1 < get_size(victim))
	{
		act( "$N is too big for you to grapple.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (get_size(victim) + 1 < get_size(ch))
	{
		act( "$N is too small for you to grapple.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (is_mounting(victim))
	{
		send_to_char( "You can't grapple a mounted target... MAYBE you could grapple the mount.\n\r", ch );
		pop_call();
		return;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}
	
	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return;
	}
	
	CHECK_TURN(ch, victim);	

	if (!can_surprise(ch, victim))
	{
		pop_call();
		return;
	}

	if (!has_mirror(ch, victim, gsn_grapple))
	{
		if (!in_combat(ch) || is_active(ch))
		{
			if (!learned(ch, gsn_imp_grapple) || (learned(victim, gsn_combat_reflexes) && victim->level > ch->level - 4))
			{
				if (attack_of_opportunity(victim, ch))
				{
					if (!valid_fight(ch, victim))
					{
						pop_call();
						return;
					}
				}
			}
		}
	
		if ((check = combat_maneuver_check(ch, victim, gsn_grapple)) >= 0)
		{
			start_grapple(ch, victim);
		}
		else
		{
			act( "$N avoids your grappling attempt.", ch, NULL, victim, TO_CHAR);
			act( "You avoid $n's grappling attempt.", ch, NULL, victim, TO_VICT);
			act( "$n avoids $n's grappling attempt.", ch, NULL, victim, TO_NOTVICT);
		}
	}
	TAKE_ACTION(ch, ACTION_STANDARD);
	
	if (!IS_NPC(ch) && IS_NPC(victim) && !in_combat(victim))
		fight(victim, ch);

	pop_call();
	return;
}


void do_release( CHAR_DATA *ch, char *argument )
{
	push_call("do_release(%p,%p)",ch,argument);

	if (!ch->grappling)
	{
		send_to_char( "You are not grappling anyone.\n\r", ch );
		pop_call();
		return;
	}
	
	stop_grapple(ch);

	pop_call();
	return;
}


/*
 * Monster grab ability - Kregor
 */
void grab( CHAR_DATA *ch, CHAR_DATA *victim )
{
	push_call("grab(%p,%p)",ch,victim);

	if (ch->grappling)
	{
		pop_call();
		return;
	}
	
	if (!race_skill(ch, gsn_grab))
	{
		pop_call();
		return;
	}

	if (get_size(ch) < get_size(victim))
	{
		act( "$N is too big for you to grab.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (is_mounting(victim))
	{
		send_to_char( "You can't grapple a mounted target... MAYBE you could grapple the mount.\n\r", ch );
		pop_call();
		return;
	}

	if (combat_maneuver_check(ch, victim, gsn_grapple) >= 0)
	{
		start_grapple(ch, victim);
	}
	else
	{
		act( "$N avoids your grappling attempt.", ch, NULL, victim, TO_CHAR);
		act( "You avoid $n's grappling attempt.", ch, NULL, victim, TO_VICT);
		act( "$n avoids $n's grappling attempt.", ch, NULL, victim, TO_NOTVICT);
	}

	pop_call();
	return;
}



/*
 * do_fun for attacking in melee
 * also handles making a surprize attack or
 * AoO out of combat - Kregor
 */
void do_attack (CHAR_DATA *ch, char *argument)
{
	CHAR_DATA *victim;
	
	push_call("do_attack(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		if ((victim = ch->last_attacked) == NULL)
		{
			send_to_char ("Attack whom?\n\r", ch);
			pop_call();
			return;
		}
	}
	else
	{
		if ((victim = get_char_room (ch, argument)) == NULL)
		{
		ch_printf(ch, "There's no %s here.\n\r", argument );
			pop_call();
			return;
		}
	}
	if (in_combat(ch) && !is_active (ch))
	{
		if (!attack_of_opportunity(ch, victim))
		{
			send_to_char ("Nope. Just wait your turn.\n\r", ch);
			pop_call();
			return;
		}
		else
		{
			pop_call();
			return;
		}
	}
	// safeguard is my preference, take it out if you want to allow it - Kregor
	if (is_same_group(ch, victim))
	{
		send_to_char ("You cannot attack a member of your own group.\n\r", ch);
		pop_call();
		return;
	}		

	if (!in_combat(ch) && !in_combat(victim))
	{
		if (is_safe(ch, NULL))
		{
			pop_call();
			return;
		}	
		if (attack_of_opportunity(ch, victim))
		{
			pop_call();
			return;
		}
		else if (!can_see(victim, ch) || !IS_AWAKE(victim) || multi(ch, gsn_backstab) != -1)
		{
			if (check_murder(ch, victim))
			{
				act( "$n attacks you by surprise!", ch, NULL, victim, TO_VICT);
				act( "You attack $N by surprise!", ch, NULL, victim, TO_CHAR);
				act( "$n attacks $N by surprise!", ch, NULL, victim, TO_NOTVICT);
				attack(ch, victim);
				pop_call();
				return;
			}
		}
		else
		{
			act("$N is too wary to be taken by surprise!", ch, NULL, victim, TO_CHAR);
			pop_call();
			return;
		}
	}
	
	CHECK_TURN(ch, victim);

	attack(ch, victim);
	
	pop_call();
	return;
}


/*
 * Execute additional primary melee attacks after first attack or combat maneuver.
 * If none of these iterations trigger, return FALSE - Kregor
 *
 * Wrote this for house rule to allow all attack-multiplying conditions
 * to happen during a standard action. Only iterative attacks due to BAB
 * happen during a secondary attack now. In return, monsters get to make
 * all primary part attacks on a standard action also.
 */
bool primary_melee_attacks( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *wield, OBJ_DATA *wield2 )
{
	bool iterate = FALSE;
	
	push_call("primary_melee_attacks(%p,%p,%p,%p)",ch,victim,wield,wield2);
	
	//give on-hand attack to shield basher - Kregor
	if (valid_fight(ch, victim))
	{
		if (IS_SET(ch->attack, ATTACK_SHIELD_BASH))
		{
			one_hit(ch, victim, TYPE_UNDEFINED, 0, wield);
			iterate = TRUE;
		}
	}

	//flurry of blows or dual wield attack
	if (valid_fight(ch, victim))
	{
		if (COMBATMODE(ch, COMBAT_FLURRY))
		{
			if (!wield || WSPEC(wield, WSPEC_MONK))
			{
				one_hit(ch, victim, TYPE_UNDEFINED, 0, wield);
				iterate = TRUE;
			}
		}
		else if (wield2)
		{
			one_hit(ch, victim, TYPE_UNDEFINED, 0, wield2);
			iterate = TRUE;
		}
	}

	// rapid shot attack
	if (is_missile_weapon(wield) && COMBATMODE(ch, COMBAT_RAPIDSHOT) && valid_fight(ch, victim))
	{
		one_hit(ch, victim, TYPE_UNDEFINED, 0, wield);
		iterate = TRUE;
	}
	pop_call();
	return iterate;
}


/*
 * Wrote macro to handle custom NPCs with no race
 * which have attacks set in mob_index - Kregor
 */
int num_attacks( CHAR_DATA *ch, int part )
{
	int race;
	
	push_call("num_attacks(%p,%p)",ch,part);
	
	if ((race = get_race(ch)) == RACE_NONE)
	{
		if (!IS_NPC(ch))
		{
			pop_call();
			return -1;
		}
		pop_call();
		return ch->pIndexData->attacks[part];
	}
	pop_call();
	return race_table[race].attacks[part];
}

/*
 * Large function for melee attacks. Controls both standard
 * and full-round attacks, natural weapon attacks for unarmed
 * creatures with them. Also controls missile weapons used
 * in melee rather than at-range - Kregor
 */
bool attack(CHAR_DATA *ch, CHAR_DATA *victim)
{
	OBJ_DATA *obj;
	OBJ_DATA *wield = NULL;
	OBJ_DATA *wield2 = NULL;
	OBJ_DATA *shield = NULL;

	push_call("attack(%p,%p)",ch,victim);

	for (obj = ch->first_carrying ; obj ; obj = obj->next_content)
	{
		if (WEAR_LOC(obj, WEAR_BOTH_HANDS) && obj->item_type == ITEM_WEAPON)
		{
			wield = obj;
			if (WSPEC(obj, WSPEC_DOUBLE))
				wield2 = obj;
		}
		if (WEAR_LOC(obj, WEAR_WIELD) && obj->item_type == ITEM_WEAPON)
		{
			wield = obj;
		}
		if (WEAR_LOC(obj, WEAR_DUAL_WIELD) && obj->item_type == ITEM_WEAPON)
		{
			wield2 = obj;
		}
		if (WEAR_LOC(obj, WEAR_SHIELD) && obj->item_type == ITEM_ARMOR)
		{
			shield = obj;
		}
	}

	/*
		Disallow fighting in different rooms and safe rooms
	*/
	if (victim->in_room != ch->in_room)
	{
		pop_call();
		return FALSE;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	/*
	 * can't attack if casting spell or doing something else
	 */
	if (ch->casting || ch->concentrating)
	{
		pop_call();
		return FALSE;
	}
	
	if (IS_SET(ch->action, ACTION_STANDARD) && !IS_SET(ch->attack, ATTACK_MELEE))
	{
		send_to_char("You cannot make a melee attack after other standard actions.\n\r", ch);
		pop_call();
		return FALSE;
	}

	// Swarms automatically hit the person engaged, deal dmg based on HD
	if (rspec_req(ch, RSPEC_SWARM))
	{
		int numdice = ch->level / 5 + 1;
		int dam = dice(numdice, 6);

		ch->attack_part = get_body_part(ch, TYPE_HIT, 1);
				
		damage(ch, victim, dam, TYPE_HIT, NULL);

		SET_BIT(ch->attack, ATTACK_MELEE);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return TRUE;
	}

	// nonhumanoid unarmed attack goes here.
	if (!wield && has_natural_weapon(ch))
	{
		int part, count, numattacks;
		bool HasPrimary = FALSE;
		
		// check if has primary attack, if not use secondaries as standard with no hit_adj
		for (part = 0 ; part < ATTK_MAX ; part++)
		{
			if (!attack_part_table[part].primary)
				continue;
			if ((numattacks = num_attacks(ch, part)) == -1)
			{
				pop_call();
				return FALSE;
			}
			if (numattacks)
			{
				if (part == ATTK_TOUCH)
					ch->attack_part = part; // for the can_melee check below
				HasPrimary = TRUE;
				break;
			}
		}
		
		if (!can_melee_attack(ch, victim))
		{
			pop_call();
			return FALSE;
		}

		if (!IS_SET(ch->attack, ATTACK_MELEE))
		{
			for (ch->attack_part = -1, part = 0 ; part < ATTK_MAX ; part++)
			{
				if (part == ATTK_RAKE)
					continue;
				if (IS_RACE(ch, RACE_DRAGON))
				{
					if (part == ATTK_WING && ch->size < SIZE_MEDIUM)
						continue;
					if (part == ATTK_TAIL && ch->size < SIZE_LARGE)
						continue;
				}
				if (!valid_fight(ch, victim))
					break;
				if (HasPrimary && !attack_part_table[part].primary)
					continue;
				if ((numattacks = num_attacks(ch, part)) > 0)
				{
					for (count = 0 ; count < numattacks ; count++)
					{
						ch->attack_part = part;
						one_hit(ch, victim, TYPE_HIT, 0, NULL);
					}
				}
			}
			if (ch->attack_part != -1) // if still -1, no parts were used
			{
				SET_BIT(ch->attack, ATTACK_MELEE);
				TAKE_ACTION(ch, ACTION_STANDARD);
				pop_call();
				return TRUE;
			}
		}
		else if (HasPrimary) // secondaries already went off w/standard attack if not.
		{
			for (ch->attack_part = -1, part = 0 ; part < ATTK_MAX ; part++)
			{
				if (!valid_fight(ch, victim))
					break;
				if (part == ATTK_RAKE)
					continue;
				if (IS_RACE(ch, RACE_DRAGON))
				{
					if (part == ATTK_WING && ch->size < SIZE_MEDIUM)
						continue;
					if (part == ATTK_TAIL && ch->size < SIZE_LARGE)
						continue;
				}
				if (attack_part_table[part].primary)
					continue;
				if ((numattacks = num_attacks(ch, part)) > 0)
				{
					for (count = 0 ; count < numattacks ; count++)
					{
						ch->attack_part = part;
						one_hit(ch, victim, TYPE_HIT, -5, NULL); // secondary parts at -5 to hit
					}
				}
			}
		}
		if (ch->attack_part == -1)
		{
			send_to_char("You have no more attacks.\n\r", ch);
			if (IS_NPC(ch) && !IS_SET(ch->attack, ATTACK_MELEE)) // if we didn't get any attacks off, we need to set parts
				log_build_printf(ch->pIndexData->vnum, "attack: natural attack attempt with no race parts set.");
			pop_call();
			return FALSE;
		}
		TAKE_ACTION(ch, ACTION_MOVE);
		pop_call();
		return TRUE;
	}
	
	// check contact resistances unless a ranged attack
	if (!wield || (!is_missile_weapon(wield) && !WSPEC(wield, WSPEC_NOMELEE)))
	{
		if (!can_melee_attack(ch, victim))
		{
			pop_call();
			return FALSE;
		}
	}

	// if this is the first attack this round, do this, and no more.
	if (!IS_SET(ch->attack, ATTACK_MELEE))
	{
		if (one_hit(ch, victim, TYPE_UNDEFINED, 0, wield))
		{
			manyshot_hit(ch, victim, TYPE_UNDEFINED, 0, wield);
		}
		// take this function out if changed mind about more attacks in standard action - Kregor
		primary_melee_attacks(ch, victim, wield, wield2);
		
		TAKE_ACTION(ch, ACTION_STANDARD);
		SET_BIT(ch->attack, ATTACK_MELEE);
		pop_call();
		return TRUE;
	}
	
	bool iterate = FALSE;
	int bab = base_attack(ch);

	if (IS_SET(ch->attack, ATTACK_DISARM|ATTACK_TRIP|ATTACK_SHIELD_BASH|ATTACK_STUNNING_FIST|ATTACK_SUNDER))
	{
		//this is where the primary attack functions go again if we reverse the change.
	}

	// Barbarian rage bonus attack
	if (valid_fight(ch, victim))
	{
		if (is_affected(ch, gsn_barbarian_rage))
		{
			one_hit(ch, victim, TYPE_UNDEFINED, 0, wield);
			iterate = TRUE;
		}
	}

	if ((bab > 5 || is_speedy(ch, wield, wield2)) && valid_fight(ch, victim))
	{
		if (one_hit(ch, victim, TYPE_UNDEFINED, -5, wield))
		{
			manyshot_hit(ch, victim, TYPE_UNDEFINED, -5, wield);
		}
		iterate = TRUE;
	}

	if (valid_fight(ch, victim))
	{
		if (COMBATMODE(ch, COMBAT_FLURRY) && learned(ch, gsn_imp_flurry))
		{
			if (!wield || WSPEC(wield, WSPEC_MONK))
			{
				one_hit(ch, victim, TYPE_UNDEFINED, -5, wield);
				iterate = TRUE;
			}
		}
		else if (wield2 && learned(ch, gsn_imp_two_weapon))
		{
			one_hit(ch, victim, TYPE_UNDEFINED, -5, wield2);
			iterate = TRUE;
		}
	}
	
	if ((bab > 10 || (bab > 5 && is_speedy(ch, wield, wield2))) && valid_fight(ch, victim))
	{
		if (one_hit(ch, victim, TYPE_UNDEFINED, -10, wield))		
		{
			manyshot_hit(ch, victim, TYPE_UNDEFINED, -10, wield);
		}
		iterate = TRUE;
	}

	if (valid_fight(ch, victim))
	{
		if (COMBATMODE(ch, COMBAT_FLURRY) && learned(ch, gsn_greater_flurry))
		{
			if (!wield || WSPEC(wield, WSPEC_MONK))
			{
				one_hit(ch, victim, TYPE_UNDEFINED, -10, wield);
				iterate = TRUE;
			}
		}
		else if (wield2 && learned(ch, gsn_greater_two_weapon))
		{
			one_hit(ch, victim, TYPE_UNDEFINED, -10, wield2);
			iterate = TRUE;
		}
	}
	
	if ((bab > 15 || (bab > 10 && is_speedy(ch, wield, wield2))) && valid_fight(ch, victim))
	{
		one_hit(ch, victim, TYPE_UNDEFINED, -15, wield);
		iterate = TRUE;
	}
	
	if (valid_fight(ch, victim))
	{
		if (wield2 && learned(ch, gsn_perfect_two_weapon))
		{
			one_hit(ch, victim, TYPE_UNDEFINED, -15, wield2);
			iterate = TRUE;
		}
	}
	
	if (iterate)
	{
		TAKE_ACTION(ch, ACTION_MOVE);
	}

	pop_call();
	return iterate;
}


/*
 * Rock throwing ability.
 * Keeping it simple - no real obj for rock, just a virtual one
 * with proper damage types and messages. Just assumes the giant
 * can find SOMETHING big to throw. - Kregor
 */
bool throw_rock( CHAR_DATA *ch, CHAR_DATA *victim )
{
	int dam, diceroll, range;

	push_call("throw_rock(%p,%p)",ch,victim);

	if (!race_skill(ch, gsn_rock_throwing))
	{
		pop_call();
		return FALSE;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (victim == ch)
	{
		pop_call();
		return FALSE;
	}
	
	if (who_fighting(victim) && who_fighting(victim) == ch && IS_SET(victim->attack, ATTACK_MELEE))
	{
		act("$N is engaged to closely to throw anything at.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if ((range = get_size(ch)) <= 0 || findpath_search_victim(ch, victim, range) == -1)
	{
		act("$N is out of range.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}

	TAKE_ACTION(ch, ACTION_STANDARD);
	
	act("You grab and hurl a large projectile at $N!", ch, NULL, victim, TO_CHAR);
	act("$n grabs a large projectile and hurls it at $N!", ch, NULL, victim, TO_NOTVICT);
	act("$n grabs a large projectile and hurls it at you!", ch, NULL, victim, TO_VICT);
		
	int hit_mod = 0;
	diceroll = dice(1,20);
	CRIT_HIT = FALSE;

	if (diceroll == 1)
		ch_printf_color(ch, "{118}You score a critical miss!\n\r");
	
	if (diceroll == 20 || (diceroll >= 19 && learned(ch, gsn_imp_critical)))
	{
		if (check_hit(ch, victim, dice(1,20), hit_mod, gsn_rock_throwing, NULL, FALSE, TRUE)
		|| (fave_enemy_bonus(ch, victim) && learned(ch, gsn_master_hunter))
		|| (is_affected(victim, gsn_smite) && get_caster(victim, gsn_smite) == ch && (learned(ch, gsn_holy_champion) || learned(ch, gsn_unholy_champion))))
		{
			CRIT_HIT = TRUE;
			ch_printf_color(ch, "{118}You score a critical hit!\n\r");
		}
	}

	if (!CRIT_HIT && !check_hit(ch, victim, diceroll, hit_mod, gsn_rock_throwing, NULL, FALSE, TRUE))
	{
		act("The missile falls short of you with a THUD!!", ch, NULL, victim, TO_VICT);
		act("The missile falls short of $N with a THUD!!", ch, NULL, victim, TO_VICT);
		act("Your missile falls short of $N!", ch, NULL, victim, TO_CHAR);
	}
	else
	{
		dam = GET_DAMROLL(ch, victim, gsn_rock_throwing, NULL);

		if (CRIT_HIT && CAN_CRITICAL(victim) && (!is_affected(victim, gsn_defensive_stance) || !learned(victim, gsn_impenetrable_defense)))
			dam *= 2;

		damage(ch, victim, dam, gsn_rock_throwing, NULL);
	}

	if (is_affected(ch, gsn_impromptu_sneak_attack))
		affect_strip(ch, gsn_impromptu_sneak_attack);

	pop_call();
	return TRUE;
}


void do_throw_rock( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	int dir;
	char buf1[MAX_INPUT_LENGTH];
	char buf2[MAX_INPUT_LENGTH];

	push_call("do_throw_rock(%p,%p)",ch,argument);

	if (!race_skill(ch, gsn_rock_throwing))
	{
		send_to_char("You don't possess that racial ability.\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument(argument, buf1);
	argument = one_argument(argument, buf2);

	if ((dir = direction_door(buf1)) != -1)
	{
		if ((victim = find_char_dir(ch, dir, buf2)) == NULL)
		{
			send_to_char("Your victim must have slipped out of sight.\n\r", ch);
			pop_call();
			return;
		}
	}
	else if ((victim = get_char_room(ch, buf1)) == NULL)
	{
		send_to_char("Your victim must have slipped away.\n\r", ch);
		pop_call();
		return;
	}
	throw_rock(ch, victim);
	
	pop_call();
	return;
}
	
/*
 * New improved do_shoot with iterative attack support - Kregor
 */
void do_shoot(CHAR_DATA *ch, char *argument)
{
	CHAR_DATA *victim;
	OBJ_DATA  *ammo, *weapon;
	int dir, dam, mult, diceroll, hit_mod, cnt, count, range, bab;
	char *name;
	char buf1[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];

	push_call("do_shoot(%p,%p)",ch,argument);

	if ((weapon = get_eq_char(ch,WEAR_WIELD)) == NULL)
	{
		send_to_char("You must wield a weapon to shoot!\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_OBJ_TYPE(weapon, ITEM_WEAPON) || !WSPEC(weapon, WSPEC_MISSILE))
	{
		send_to_char("You are not wielding a missile weapon.\n\r", ch);
		pop_call();
		return;
	}
	
	if (IS_SET(ch->action, ACTION_STANDARD) && !IS_SET(ch->attack, ATTACK_SHOOT))
	{
		send_to_char("You have already made another standard action this round.\n\r", ch);
		pop_call();
		return;
	}
	
	if ((ammo = get_ammo(ch, weapon)) == NULL || !reload(ch, weapon))
	{
		pop_call();
		return;
	}
	
	if ((range = get_missile_range(weapon)) <= 0)
	{
		send_to_char("You cannot use that weapon at range.\n\r", ch);
		pop_call();
		return;
	}

	argument = one_argument(argument, buf1);
	argument = one_argument(argument, buf2);

	if ((dir = direction_door(buf1)) == -1)
	{
		if ((dir = direction_door(buf2)) == -1)
		{
			send_to_char( "Shoot which direction?\n\r", ch );
			pop_call();
			return;
		}
		name = buf1;
	}
	else
	{
		name = buf2;
	}

	if (*name == '\0')
	{
		send_to_char( "Shoot at whom?\n\r", ch );
		pop_call();
		return;
	}

	if ((victim = find_char_dir(ch, dir, name)) == NULL)
	{
		send_to_char("Your victim must have slipped out of sight!\n\r", ch);
		pop_call();
		return;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}

	if (find_keeper(victim) != NULL || IS_SET(victim->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char("You can't shoot into that room.\n\r", ch);
		pop_call();
		return;
	}

	if (findpath_search_victim(ch, victim, range) == -1)
	{
		send_to_char("That target is out of range.\n\r", ch);
		pop_call();
		return;
	}

	if (COMBATMODE(ch, COMBAT_MANYSHOT))
	{
		switch(weapon->value[0])
		{
			case WEAPON_TYPE_SHORTBOW:
			case WEAPON_TYPE_SHORTBOW_COMPOSITE:
			case WEAPON_TYPE_LONGBOW:
			case WEAPON_TYPE_LONGBOW_COMPOSITE:
			case WEAPON_TYPE_SLING:
				break;
			default:
				send_to_char("You can only manyshot with a bow or sling.\n\r", ch);
				REMOVE_BIT(ch->combatmode, COMBAT_MANYSHOT);
				break;
		}
	}

	bab = base_attack(ch);
	bool speedy = is_speedy(ch,weapon,weapon);

	if (!IS_SET(ch->action, ACTION_STANDARD))
		count = 1 + (COMBATMODE(ch, COMBAT_RAPIDSHOT));
	else
		count = 1 + (bab > 5 || speedy) + (bab > 10 || (bab > 10 && speedy)) + (bab > 15 || (bab > 15 && speedy)) + (speedy);
	
	for (cnt = 0 ; cnt < count ; cnt++)
	{
		if (!cnt && IS_SET(ch->action, ACTION_STANDARD) && count > 1)
			continue;

		if ((ammo = get_ammo(ch, weapon)) == NULL || !reload(ch, weapon))
		{
			break;
		}			

		if ((victim = find_char_dir(ch, dir, name)) == NULL)
		{
			break;
		}

		diceroll = dice(1,20);
		CRIT_HIT = FALSE;
		int dt = TYPE_HIT;

		if (IS_SET(ch->action, ACTION_STANDARD))
		{
			switch (cnt)
			{
				case 1:
					hit_mod = -5;
					break;
				case 2:
					hit_mod = -10;
					break;
				case 3:
					hit_mod = -15;
					break;
			}
		}
	
		if (diceroll == 1 && !WEAPON_FLAG(ammo, WFLAG_SEEKING))
			ch_printf_color(ch, "{118}Critical miss!\n\r");
		
		if (number_percent() > get_apply(victim, APPLY_FORTIFICATION))
		{
			int threat = weapon_table[weapon->value[0]].threat;
		
			if (WEAPON_FLAG(ammo, WFLAG_KEEN)
			|| (is_bow(weapon) && learned(ch, gsn_keen_arrow)))
			{
				threat = (20 - threat) * 2;
				threat = 20 - threat;
			}
			if (IS_SET(weapon_skill(ch, weapon), WSKILL_IMP_CRITICAL))
			{
				threat += 1;
			}
			if (diceroll == 20 || diceroll >= threat)
			{
				if (check_hit(ch, victim, dice(1,20), hit_mod, dt, weapon, FALSE, TRUE)
				|| (weapon != NULL && WEAPON_TYPE(weapon, WEAPON_TYPE_SLING) && learned(ch, gsn_dead_shot))
				|| (fave_enemy_bonus(ch, victim) && learned(ch, gsn_master_hunter))
				|| (can_backstab(ch, victim, dt) && learned(ch, gsn_stealth_mastery))
				|| (is_affected(victim, gsn_smite) && get_caster(victim, gsn_smite) == ch && (learned(ch, gsn_holy_champion) || learned(ch, gsn_unholy_champion))))
				{
					CRIT_HIT = TRUE;
					ch_printf_color(ch, "{118}You score a critical threat!\n\r");
				}
			}
		}
	
		if (!WEAPON_FLAG(ammo, WFLAG_SEEKING) && diceroll != 20 && !check_hit(ch, victim, diceroll, hit_mod, dt, weapon, FALSE, TRUE))
		{
			act( "$n looses $p $Twards.", ch, ammo, dir_name[dir], TO_ROOM );
			act( "You loose $p $Twards.", ch, ammo, dir_name[dir], TO_CHAR );
			act( "$p whistles past you from $T.", victim, ammo, rev_dir_name[dir], TO_CHAR);
			act( "$p whistles past $n from $T.", victim, ammo, rev_dir_name[dir], TO_ROOM);
			act( "$p whistles past $N.", ch, ammo, victim, TO_CHAR );
			act( "$p whistles past $N.", ch, ammo, victim, TO_ROOM );
		}
		else
		{
			dam = GET_DAMROLL(ch, victim, dt, weapon);
			mult = weapon_table[ammo->value[0]].critical;
					
			if (IS_SET(weapon_skill(ch, weapon), WSKILL_IMP_CRITICAL) && learned(ch, gsn_weapon_grandmastery))
				mult++;
			if (WEAPON_TYPE(weapon, WEAPON_TYPE_SLING) && learned(ch, gsn_between_the_eyes))
				mult++;

			if (cnt == 0 && CRIT_HIT && CAN_CRITICAL(victim) && (!is_affected(victim, gsn_defensive_stance) || !learned(victim, gsn_impenetrable_defense)))
				dam *= mult;
	
			act( "$n looses $p $Twards.", ch, ammo, dir_name[dir], TO_ROOM );
			act( "You loose $p $Twards.", ch, ammo, dir_name[dir], TO_CHAR );
			act( "$p flies in from $T.", victim, ammo, rev_dir_name[dir], TO_CHAR );
			act( "$p flies in from $T.", victim, ammo, rev_dir_name[dir], TO_ROOM );
	
			if (!deflect_missile(victim, ch, ammo, -1))
			{
				damage(ch, victim, dam, dt, ammo);
	
				if (weapon_cast_spell(ammo->value[2], ammo->value[3], ch, victim, ammo))
					ammo->value[2] = ammo->value[3] = 0;
			
				if (COMBATMODE(ch, COMBAT_MANYSHOT) && (!IS_SET(ch->action, ACTION_STANDARD) || !cnt))
				{
					manyshot_hit(ch, victim, dt, hit_mod, weapon);
				}
			}
		}
		if (ammo)
		{
			junk_obj(ammo);
		}
	}
	if (!IS_SET(ch->action, ACTION_STANDARD))
	{
		TAKE_ACTION(ch, ACTION_STANDARD);
	}
	else
	{
		TAKE_ACTION(ch, ACTION_MOVE);
	}
	
	SET_BIT(ch->attack, ATTACK_SHOOT); // this gives others AoO until your next turn.
	
	if (MP_VALID_MOB(victim) && dam > 0)
	{
		mprog_range_trigger(victim, ch, rev_dir[dir]);
	}
	if (is_affected(ch, gsn_impromptu_sneak_attack))
		affect_strip(ch, gsn_impromptu_sneak_attack);

	pop_call();
	return;
}


/*
 * Thrown missile support, with D20 goodness, support for
 * drawing and throwing missiles in sheaths. 
 */
void do_throw( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	OBJ_DATA  *weapon, *cont;
	int dir, dam, mult, wielded, diceroll, range;
	char buf1[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH], buf3[MAX_INPUT_LENGTH];

	push_call("do_throw(%p,%p)",ch,argument);

	if (IS_SET(ch->action, ACTION_STANDARD))
	{
		send_to_char("You have already made a standard action this round.\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument(argument, buf1);
	argument = one_argument(argument, buf2);
	argument = one_argument(argument, buf3);

	if (buf2[0] == '\0' || buf1[0] == '\0')
	{
		send_to_char( "Throw what at whom?\n\r", ch );
		pop_call();
		return;
	}

	if ((dir = direction_door(buf2)) == -1)
	{
		if ((victim = find_char_dir(ch, dir, buf2)) == NULL)
		{
			send_to_char("Your victim must have slipped out of sight.\n\r", ch);
			pop_call();
			return;
		}
	}
	else
	{
		if (buf3[0] == '\0')
		{
			send_to_char( "Throw at whom?\n\r", ch );
			pop_call();
			return;
		}
		if ((victim = find_char_dir(ch, dir, buf3)) == NULL)
		{
			send_to_char("Your victim must have slipped out of sight.\n\r", ch);
			pop_call();
			return;
		}
	}

	// for Rock Throwing racial ability - Kregor
	if (!strcasecmp(buf1, "rock"))
	{
		throw_rock(ch, victim);
		pop_call();
		return;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}

	wielded = FALSE;

	if ((weapon = get_wield(ch, FALSE)) != NULL)
	{
		if (is_name(buf1, weapon->name) || is_name_short(buf1, weapon->name))
		{
			wielded = TRUE;
		}
	}

	if (wielded == FALSE)
	{
		if (!remove_obj(ch, WEAR_WIELD, TRUE, FALSE))
		{
			send_to_char("You can't throw with another weapon wielded!\n\r", ch);
			pop_call();
			return;
		}
		for (weapon = ch->first_carrying ; weapon ; weapon = weapon->next_content)
		{
			if (weapon->item_type == ITEM_WEAPON && (is_name(buf1, weapon->name) || is_name_short(buf1, weapon->name)))
			{
				break;
			}
			if (weapon->item_type == ITEM_SHEATH && !IS_SET(weapon->value[1], CONT_CLOSED))
			{
				cont = weapon;

				for (weapon = weapon->first_content ; weapon ; weapon = weapon->next_content)
				{
					if (weapon->item_type == ITEM_WEAPON && (is_name(buf1, weapon->name) || is_name_short(buf1, weapon->name)))
					{
						break;
					}
				}
				if (weapon)
				{
					break;
				}
				else
				{
					weapon = cont;
				}
			}
		}
	}

	if (weapon == NULL)
	{
		send_to_char("Hmmm... you don't seem to have that weapon.\n\r", ch);
		pop_call();
		return;
	}

	if (IS_SET(weapon->extra_flags, ITEM_NODROP))
	{
		send_to_char("You can't let go of it.\n\r", ch);
		pop_call();
		return;
	}

	if (!WEAPON_FLAG(weapon, WFLAG_THROWING))
	{
		if (!WSPEC(weapon, WSPEC_THROW))
		{
			send_to_char("You can't throw that type of weapon.\n\r", ch);
			pop_call();
			return;
		}
	}

	if (dir != -1)
	{
		if ((range = get_missile_range(weapon)) <= 0 || findpath_search_victim(ch, victim, range) == -1)
		{
			send_to_char("That target is out of range.\n\r", ch);
			pop_call();
			return;
		}
	}
	
	CHECK_TURN(ch, victim);

	if (weapon->in_obj)
	{
		if (!learned(ch, gsn_quick_draw))
		{
			if (IS_SET(ch->action, ACTION_MOVE))
			{
				act("You do not have enough actions to draw and throw $p.", ch, weapon, NULL, TO_CHAR);
				pop_call();
				return;
			}
			TAKE_ACTION(ch, ACTION_MOVE);
		}
		act( "$n pulls $p from $P.", ch, weapon, weapon->in_obj, TO_ROOM );
		act( "You pull $p from $P.", ch, weapon, weapon->in_obj, TO_CHAR );
		obj_from_obj(weapon);
		obj_to_char(weapon, ch);
	}

	TAKE_ACTION(ch, ACTION_STANDARD);
		
	/*
	 * The dice roll, calculate mods
	 */
	int dt = TYPE_HIT;
	int hit_mod = 0;
	diceroll = dice(1,20);
	CRIT_HIT = FALSE;

	if (diceroll == 1 && !WEAPON_FLAG(weapon, WFLAG_SEEKING))
		ch_printf_color(ch, "{118}Critical miss!\n\r");
	
	if (number_percent() > get_apply(victim, APPLY_FORTIFICATION))
	{
		int threat = weapon_table[weapon->value[0]].threat;
	
		if (WEAPON_FLAG(weapon, WFLAG_KEEN))
		{
			threat = (20 - threat) * 2;
			threat = 20 - threat;
		}
		if (IS_SET(weapon_skill(ch, weapon), WSKILL_IMP_CRITICAL))
		{
			threat += 1;
		}
		if (diceroll == 20 || diceroll >= threat)
		{
			if (check_hit(ch, victim, dice(1,20), hit_mod, dt, weapon, FALSE, TRUE)
			|| (fave_enemy_bonus(ch, victim) && learned(ch, gsn_master_hunter))
			|| (can_backstab(ch, victim, dt) && learned(ch, gsn_stealth_mastery))
			|| (is_affected(victim, gsn_smite) && get_caster(victim, gsn_smite) == ch && (learned(ch, gsn_holy_champion) || learned(ch, gsn_unholy_champion))))
			{
				CRIT_HIT = TRUE;
				ch_printf_color(ch, "{118}You score a critical threat!\n\r");
			}
		}
	}

	if (!WEAPON_FLAG(weapon, WFLAG_SEEKING) && diceroll != 20 && !check_hit(ch, victim, diceroll, hit_mod, dt, weapon, FALSE, TRUE))
	{
		dam_message(ch, victim, 0, dt, weapon);

		if (!WEAPON_FLAG(weapon, WFLAG_RETURNING) && (!WSPEC(weapon, WSPEC_RETURNING) || !weapon_skill(ch, weapon)))
		{
			weapon->sac_timer = OBJ_SAC_TIME;
			obj_to_room(weapon, victim->in_room->vnum);
		}
		else
		{
			act( "$p returns to $n's hand.", ch, weapon, NULL, TO_ROOM );
			act( "$p returns to your hand.", ch, weapon, NULL, TO_CHAR );
		}
	}
	else
	{
		dam = GET_DAMROLL(ch, victim, dt, weapon);
		mult = weapon_table[weapon->value[0]].critical;

		if (IS_SET(weapon_skill(ch, weapon), WSKILL_IMP_CRITICAL) && learned(ch, gsn_weapon_grandmastery))
			mult++;

		if (CRIT_HIT && CAN_CRITICAL(victim) && (!is_affected(victim, gsn_defensive_stance) || !learned(victim, gsn_impenetrable_defense)))
			dam *= mult;

		if (!deflect_missile(victim, ch, weapon, dir))
		{
			damage(ch, victim, dam, dt, weapon);

			if (weapon_cast_spell(weapon->value[2], weapon->value[3], ch, victim, weapon))
				weapon->value[2] = weapon->value[3] = 0;
		
			if (!WEAPON_FLAG(weapon, WFLAG_RETURNING) && (!WSPEC(weapon, WSPEC_RETURNING) || !weapon_skill(ch, weapon)))
				obj_to_char(weapon, victim);
			else
			{
				act( "$p returns to $n's hand.", ch, weapon, NULL, TO_ROOM );
				act( "$p returns to your hand.", ch, weapon, NULL, TO_CHAR );
			}
		}
		if (dir != -1 && !IS_NPC(ch) && MP_VALID_MOB(victim))
		{
			mprog_range_trigger(victim, ch, rev_dir[dir]);
		}
	}
	if (is_affected(ch, gsn_impromptu_sneak_attack))
		affect_strip(ch, gsn_impromptu_sneak_attack);

	pop_call();
	return;
}


/*
 * Trip, the command and the function. Mobiles use the function alone.
 */
void do_trip( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;

	push_call("do_trip(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		if ((victim = ch->last_attacked) == NULL)
		{
			send_to_char( "Trip whom?\n\r", ch );
			pop_call();
			return;
		}
	}
	else if ((victim = get_char_room(ch, argument)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}

	trip(ch, victim, 0);

	pop_call();
	return;
}

/*
 * Returns TRUE if the attempt is made, whether or not it succeeds.
 */
bool trip( CHAR_DATA *ch, CHAR_DATA *victim, int hit_adj )
{
	int check = 0;
	OBJ_DATA *wield;

	push_call("trip(%p,%p)",ch,victim);

	if (victim == NULL)
	{
		pop_call();
		return FALSE;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (IS_NPC(ch) && !learned(ch, gsn_trip))
	{
		pop_call();
		return FALSE;
	}
	
	if (IS_NPC(ch) && IS_SET(ch->attack, ATTACK_TRIP))
	{
		pop_call();
		return FALSE;
	}
	
	if (IS_FLYING(victim))
	{
		send_to_char( "How would YOU trip a flying person?\n\r", ch );
		pop_call();
		return FALSE;
	}
	
	if (get_size(ch) + 1 < get_size(victim))
	{
		act( "$N is too large for you to trip", ch, NULL, victim, TO_CHAR );
		pop_call();
		return FALSE;
	}
	
	if (is_mounting(victim))
	{
		send_to_char( "You can't trip a mounted target. MAYBE you could trip the mount.\n\r", ch );
		pop_call();
		return FALSE;
	}

	if (victim->position < POS_FIGHTING)
	{
		act( "$N is already down!", ch, NULL, victim, TO_CHAR );
		pop_call();
		return FALSE;
	}

	if (!can_surprise(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	wield = get_wield(ch, FALSE);

	if (!has_mirror(ch, victim, gsn_trip))
	{
		if (!in_combat(ch) || is_active(ch)) // else it's his own attack of opportunity
		{
			if (!learned(ch, gsn_improved_trip) || (learned(victim, gsn_combat_reflexes) && victim->level > ch->level - 4))
			{
				if (attack_of_opportunity(victim, ch))
				{
					if (!valid_fight(ch, victim))
					{
						pop_call();
						return TRUE;
					}
				}
			}
		}
		
		if ((check = combat_maneuver_check(ch, victim, gsn_trip)) == -2)
		{
			if (!wield || !WSPEC(wield, WSPEC_TRIP))
			{
				act( "$n tries to trip you and you counter $m!", ch, NULL, victim, TO_VICT);
				act( "$N counters your attempt to trip $M!", ch, NULL, victim, TO_CHAR);
				act( "$n tries to trip $N, who counters $s move.!", ch, NULL, victim, TO_NOTVICT);
				update_pos(ch, POS_RESTING);
				ch->distracted = 2;
			}
			else
			{
				act( "$n tries to trip you, but fails.", ch, NULL, victim, TO_VICT);
				act( "You fail your attempt to trip $N.", ch, NULL, victim, TO_CHAR);
				act( "$n tries to trip $N and fails.", ch, NULL, victim, TO_NOTVICT);
			}		
		}
		else if (check == -1)
		{
			act( "$n tries to trip you, but fails.", ch, NULL, victim, TO_VICT);
			act( "You fail your attempt to trip $N.", ch, NULL, victim, TO_CHAR);
			act( "$n tries to trip $N and fails.", ch, NULL, victim, TO_NOTVICT);
		}
		else
		{		
			act( "$n trips you and you go down!", ch, NULL, victim, TO_VICT);
			act( "You trip $N and $E goes down!", ch, NULL, victim, TO_CHAR);
			act( "$n trips $N and $E goes down!", ch, NULL, victim, TO_NOTVICT);
			update_pos(victim, POS_RESTING);
			victim->distracted = 2;
		}	
		// so these don't go off on attacks of opportunity
		if (!ch->distracted && in_same_combat(ch, victim) && is_active(ch))
		{
			primary_melee_attacks(ch, victim, wield, get_wield(ch, TRUE));
		}
	}

	if (!IS_NPC(ch) && IS_NPC(victim) && !in_combat(victim))
		fight(victim, ch);

	TAKE_ACTION(ch, ACTION_STANDARD);
	SET_BIT(ch->attack, ATTACK_TRIP|ATTACK_MELEE);

	pop_call();
	return TRUE;
}

/*
 * Disarm, the command and the function. Mobiles use the function alone.
 */
void do_disarm( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	OBJ_DATA *wield;

	push_call("do_disarm(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		if ((victim = ch->last_attacked) == NULL)
		{
			send_to_char( "Disarm whom?\n\r", ch );
			pop_call();
			return;
		}
	}
	else if ((victim = get_char_room(ch, argument)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}
	
	if ((wield = get_wield(ch, FALSE)) == NULL || !WSPEC(wield, WSPEC_DISARM))
	{
		if ((wield = get_wield(ch, TRUE)) == NULL || !WSPEC(wield, WSPEC_DISARM))
		{
			if (!learned(ch, gsn_disarm))
			{
				send_to_char( "You are unable to perform this feat.\n\r", ch );
				pop_call();
				return;
			}
		}
	}
				
	disarm(ch, victim, 0);

	pop_call();
	return;
}

/*
 * Returns TRUE if the attempt is made, whether or not it succeeds.
 */
bool disarm( CHAR_DATA *ch, CHAR_DATA *victim, int hit_adj )
{
	OBJ_DATA *chwield, *victwield;
	int check;

	push_call("disarm(%p,%p)",ch,victim);

	if (victim == NULL)
	{
		pop_call();
		return FALSE;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (IS_NPC(ch) && !learned(ch, gsn_disarm))
	{
		pop_call();
		return FALSE;
	}
	
	if (IS_NPC(ch) && IS_SET(ch->attack, ATTACK_DISARM))
	{
		pop_call();
		return FALSE;
	}
	
	if ((chwield = get_wield(ch, FALSE)) != NULL && is_missile_weapon(chwield))
	{
		send_to_char( "You cannot disarm with a missile weapon.\n\r", ch );
		pop_call();
		return FALSE;
	}
	
	if ((victwield = get_wield(victim, FALSE)) == NULL)
	{
		if ((victwield = get_wield(victim, TRUE)) == NULL)
		{
			send_to_char( "Your opponent is not wielding a weapon.\n\r", ch );
			pop_call();
			return FALSE;
		}
	}

	if (IS_SET(victwield->extra_flags,ITEM_INVENTORY) 
	|| IS_SET(victwield->extra_flags,ITEM_NODROP) 
	|| IS_SET(victwield->extra_flags,ITEM_NOREMOVE))
	{
		send_to_char( "You cannot pry it from their hands.\n\r", ch );
		SET_BIT(ch->attack, ATTACK_DISARM);
		pop_call();
		return FALSE;
	}

	if (!can_surprise(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	if (!can_see_obj(ch, victwield))
	{
		if (number_percent() > 50)
		{
			act( "You fail to get a good look at $p.", ch, victwield, victim, TO_CHAR);
			act( "$n attempts to disarm $N and fails.", ch, NULL, victim, TO_NOTVICT);
			act( "$n attempts to disarm you and fails.", ch, NULL, victim, TO_VICT);
			SET_BIT(ch->attack, ATTACK_DISARM);
		}
	}
	else if (!has_mirror(ch, victim, gsn_disarm))
	{
		if (!in_combat(ch) || is_active(ch))
		{
			if (!learned(ch, gsn_imp_disarm) || (learned(victim, gsn_combat_reflexes) && victim->level > ch->level - 4))
			{
				if (attack_of_opportunity(victim, ch))
				{
					if (!valid_fight(ch, victim))
					{
						pop_call();
						return TRUE;
					}
				}
			}
		}
		if ((check = combat_maneuver_check(ch, victim, gsn_disarm)) >= 0)
		{
			unequip_char(victim, victwield, TRUE);
			obj_from_char(victwield);
			if (!chwield)
			{
				act( "$n snatches $p from your hands!", ch, victwield, victim, TO_VICT);
				act( "You snatches $p from $N's hands!",  ch, victwield, victim, TO_CHAR);
				act( "$n snatches $p from $N's hands!",  ch, victwield, victim, TO_NOTVICT);
				obj_to_char(victwield, ch);
			}
			else
			{
				act( "$n knocks $p from your hands!", ch, victwield, victim, TO_VICT);
				act( "You knock $p from $N's hands!",  ch, victwield, victim, TO_CHAR);
				act( "$n knocks $p from $N's hands!",  ch, victwield, victim, TO_NOTVICT);
				obj_to_room(victwield, victim->in_room->vnum);
			}
		}
		else if (check == -2)
		{
			act( "$n attempts to disarm you, but you counter the attempt!", ch, NULL, victim, TO_VICT);
			act( "$N counters the attempt to disarm!",  ch, NULL, victim, TO_CHAR);
			act( "$n attempts to disarm $N, who counters the attempt!",  ch, NULL, victim, TO_NOTVICT);
			unequip_char(ch, chwield, TRUE);
			obj_from_char(chwield);
			obj_to_room(chwield, ch->in_room->vnum);
			chwield = NULL;
		}
		else
		{
			act( "You fail your attempt to disarm $N.", ch, NULL, victim, TO_CHAR);
			act( "$n attempts to disarm $N and fails.", ch, NULL, victim, TO_NOTVICT);
			act( "$n attempts to disarm you and fails.", ch, NULL, victim, TO_VICT);
		}

		// so these don't go off on attacks of opportunity
		if (in_same_combat(ch, victim) && is_active(ch))
		{
			primary_melee_attacks(ch, victim, chwield, get_wield(ch, TRUE));
		}
	}

	if (!IS_NPC(ch) && IS_NPC(victim) && !in_combat(victim))
		fight(victim, ch);
		
	TAKE_ACTION(ch, ACTION_STANDARD);
	SET_BIT(ch->attack, ATTACK_DISARM|ATTACK_MELEE);

	pop_call();
	return TRUE;
}


/*
 * Returns TRUE if attempt is made, whether or not it succeeds.
 * Called from the BASH command in act_obj using a char target.
 */
bool bash( CHAR_DATA *ch, CHAR_DATA *victim, int hit_adj )
{
	OBJ_DATA *shield;
	
	push_call("bash(%p,%p)",ch,victim);

	if (victim == NULL)
	{
		pop_call();
		return FALSE;
	}

	if (IS_NPC(ch) && !learned(ch, gsn_imp_shield_bash))
	{
		pop_call();
		return FALSE;
	}
	
	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (IS_SET(ch->attack, ATTACK_SHIELD_BASH))
	{
		act("You can only make one shield bash per round.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if ((shield = get_eq_char(ch, WEAR_SHIELD)) == NULL || shield->item_type != ITEM_ARMOR)
	{
		act("You do not have a shield to bash with.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if (!ARMOR_TYPE(shield, ARMOR_TYPE_LIGHT_SHIELD) && !ARMOR_TYPE(shield, ARMOR_TYPE_HEAVY_SHIELD))
	{
		act("You can only bash with a light or heavy shield.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	BOOL_CHECK_TURN(ch, victim);
	
	one_hit( ch, victim, gsn_shield_bash, hit_adj, NULL );
	// so these don't go off on attacks of opportunity
	if (in_same_combat(ch, victim) && is_active(ch))
	{
		primary_melee_attacks(ch, victim, get_wield(ch, FALSE), get_wield(ch, TRUE));
	}

	TAKE_ACTION(ch, ACTION_STANDARD);
	SET_BIT(ch->attack, ATTACK_SHIELD_BASH|ATTACK_MELEE);

	pop_call();
	return TRUE;
}

/*
 * Whirlwind Attack - command and action
 */
void do_whirl( CHAR_DATA *ch, char *argument )
{	
	push_call("do_whirl(%p,%p)",ch,argument);

	if (!learned(ch, gsn_whirl)
	&& (!learned(ch, gsn_mighty_rage) || !is_affected(ch, gsn_barbarian_rage) || armor_type_worn(ch) > ARMOR_MEDIUM))
	{
		send_to_char( "You do not know that maneuver.\n\r", ch);
		pop_call();
		return;
	}
	
	if (is_safe(ch, NULL))
	{
		pop_call();
		return;
	}

	if (!in_combat(ch) || !who_fighting(ch))
	{
		send_to_char( "You aren't fighting anyone.\n\r", ch );
		pop_call();
		return;
	}

	if (!is_active(ch))
	{
		send_to_char( "Just wait your turn.\n\r", ch );
		pop_call();
		return;
	}

	whirl(ch);

	pop_call();
	return;
}
	
/*
 * Returns TRUE if attempt is made, whether successful or not.
 */
bool whirl( CHAR_DATA *ch )
{
	CHAR_DATA *vch, *vch_next;
	OBJ_DATA *wield;

	push_call("whirl(%p)",ch);

	if (!who_fighting(ch))
	{
		pop_call();
		return FALSE;
	}
	
	if (!learned(ch, gsn_whirl)
	&& (!learned(ch, gsn_mighty_rage) || !is_affected(ch, gsn_barbarian_rage) || armor_type_worn(ch) > ARMOR_MEDIUM))
	{
		pop_call();
		return FALSE;
	}
	
	if ((wield = get_wield(ch, FALSE)) != NULL && (is_missile_weapon(wield) || WSPEC(wield, WSPEC_NOMELEE)))
	{
		send_to_char( "You cannot whirl with a missile weapon.\n\r", ch);
		pop_call();
		return FALSE;
	}

	if (IS_SET(ch->attack, ATTACK_WHIRL))
	{
		send_to_char( "You can only do this maneuver once in a round.\n\r", ch);
		pop_call();
		return FALSE;
	}

	act( "You spin about in a whirlwind of movement!", ch, NULL, NULL, TO_CHAR);
	act( "$n spins about in a whirlwind of movement!", ch, NULL, NULL, TO_NOTVICT);
	
	for (vch = ch->in_room->first_person ; vch ; vch = vch_next)
	{
		vch_next = vch->next_in_room;

		if (!who_fighting(vch) || who_fighting(vch) != ch)
			continue;
			
		one_hit( ch, vch, gsn_whirl, 0, wield );
	}

	SET_BIT(ch->attack, ATTACK_WHIRL);
	TAKE_ACTION(ch, ACTION_FULL);

	pop_call();
	return TRUE;
}

/*
 * Trample, the command and the function. Mobiles use the function alone.
 */
void do_trample( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;

	push_call("do_trample(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		if ((victim = ch->last_attacked) == NULL)
		{
			send_to_char( "Trample whom?\n\r", ch );
			pop_call();
			return;
		}
	}
	else if ((victim = get_char_room(ch, argument)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}

	trample(ch, victim, 0);

	pop_call();
	return;
}

/*
 * Returns TRUE if the attempt is made, whether or not it succeeds.
 */
bool trample( CHAR_DATA *ch, CHAR_DATA *victim, int hit_adj )
{
	int check = 0;
	CHAR_DATA *mount, *vch, *vch_next;

	push_call("trample(%p,%p)",ch,victim);

	if (victim == NULL)
	{
		pop_call();
		return FALSE;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	if (ch == victim)
	{
		act("You cannot trample yourself.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if (!learned(ch, gsn_trample))
	{
		act("You don't know the trample feat.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if (!quadruped(ch) && !many_legged(ch) && !is_mounting(ch))
	{
		act("You are not mounted.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
		
	if ((mount = ch->mounting) == NULL)
	{
		mount = ch;
	}
	else
	{
		if (!combat_mount(mount))
		{
			act("$N is not a combat-ready mount!", ch, NULL, mount, TO_CHAR);
			pop_call();
			return FALSE;
		}
	}
	
	if (!can_melee_attack(mount, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (IS_NPC(ch) && (IS_SET(ch->attack, ATTACK_TRAMPLE) || IS_SET(mount->attack, ATTACK_TRAMPLE)))
	{
		pop_call();
		return FALSE;
	}

	if (IS_FLYING(victim) || get_size(mount) + 1 < get_size(victim))
	{
		act( "$N cannot be trampled.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return FALSE;
	}
	
	if (is_mounting(victim))
	{
		send_to_char( "You can't trample a mounted target.\n\r", ch );
		pop_call();
		return FALSE;
	}

	if (victim->position < POS_FIGHTING)
	{
		act( "$N is already down!", ch, NULL, victim, TO_CHAR );
		pop_call();
		return FALSE;
	}

	BOOL_CHECK_TURN(ch, victim);
	
	if (!has_mirror(ch, victim, gsn_trample))
	{
		if ((check = combat_maneuver_check(mount, victim, gsn_trip)) < 0)
		{
			act( "$n tries to trample you, but fails.", ch, NULL, victim, TO_VICT);
			act( "You fail your attempt to trample $N.", ch, NULL, victim, TO_CHAR);
			act( "$n tries to trample $N and fails.", ch, NULL, victim, TO_NOTVICT);
		}
		else
		{		
			act( "$n tramples you and you go down!", mount, NULL, victim, TO_VICT);
			act( "You trample $N and $E goes down!", mount, NULL, victim, TO_CHAR);
			act( "$n tramples $N and $E goes down!", mount, NULL, victim, TO_NOTVICT);
			update_pos(victim, POS_RESTING);
			victim->distracted = 2;
		}
		if (!IS_SET(mount->attack, ATTACK_OPPORTUNITY))
		{
			one_hit(mount, victim, TYPE_UNDEFINED, hit_adj, NULL);
			take_opportunity(mount, victim);
		}
	}

	SET_BIT(ch->attack, ATTACK_TRAMPLE);
	SET_BIT(mount->attack, ATTACK_TRAMPLE);

	// mounted onslaught = multi opponent trample!	
	if (learned(ch, gsn_mounted_onslaught))
	{
		for (vch = ch->in_room->first_person ; vch ; vch = vch_next)
		{
			vch_next = vch->next_in_room;
	
			if (!can_mass_attack(ch, vch))
				continue;
				
			if (vch == victim)
				continue;
				
			if (vch->last_attacked && vch->last_attacked != ch)
				continue;
	
			// first failed attempt ends the movement
			if (!has_mirror(ch, vch, gsn_trample))
			{
				if ((check = combat_maneuver_check(mount, vch, gsn_trip)) < 0)
				{
					act( "$n tries to trample you, but fails.", ch, NULL, vch, TO_VICT);
					act( "You fail your attempt to trample $N.", ch, NULL, vch, TO_CHAR);
					act( "$n tries to trample $N and fails.", ch, NULL, vch, TO_NOTVICT);
					break;
				}
				else
				{		
					act( "$n tramples you and you go down!", mount, NULL, vch, TO_VICT);
					act( "You trample $N and $E goes down!", mount, NULL, vch, TO_CHAR);
					act( "$n tramples $N and $E goes down!", mount, NULL, vch, TO_NOTVICT);
					update_pos(vch, POS_RESTING);
					vch->distracted = 2;
				}
			}
			else
			{
				break;
			}
		}
	}
	TAKE_ACTION(ch, ACTION_STANDARD);

	pop_call();
	return TRUE;
}


/*
 * Charge: enter next room and attack victim in one command - Kregor
 */
void do_charge(CHAR_DATA *ch, char *argument)
{
	CHAR_DATA *victim, *mount;
	OBJ_DATA *weapon;
	int dir, range;
	char *name;
	char buf1[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];

	push_call("do_charge(%p,%p)",ch,argument);

	if (!is_mounting(ch) && !quadruped(ch) && !many_legged(ch))
	{
		send_to_char("You are not mounted.\n\r", ch);
		pop_call();
		return;
	}
	if ((mount = ch->mounting) == NULL)
		mount = ch;

	if ((weapon = get_eq_char(ch,WEAR_WIELD)) == NULL || WSPEC(weapon, WSPEC_MISSILE))
	{
		send_to_char("You must wield a melee weapon to charge!\n\r", ch);
		pop_call();
		return;
	}

	if (IS_OBJ_TYPE(weapon, ITEM_WEAPON) || WSPEC(weapon, WSPEC_MISSILE))
	{
		send_to_char("You must be holding a melee weapon to charge.\n\r", ch);
		pop_call();
		return;
	}
	
	if ((range = race_table[get_race(mount)].land_speed / 15) <= 0)
	{
		send_to_char("You cannot charge fast enough to strike anyone.\n\r", ch);
		pop_call();
		return;
	}

	argument = one_argument(argument, buf1);
	argument = one_argument(argument, buf2);

	if ((dir = direction_door(buf1)) == -1)
	{
		if ((dir = direction_door(buf2)) == -1)
		{
			send_to_char( "Charge in which direction?\n\r", ch );
			pop_call();
			return;
		}
		name = buf1;
	}
	else
	{
		name = buf2;
	}
	
	if (!can_move_char(ch, dir))
	{
		send_to_char("You cannot charge in that direction!\n\r", ch);
		pop_call();
		return;
	}

	if (*name == '\0')
	{
		send_to_char( "Charge at whom?\n\r", ch );
		pop_call();
		return;
	}

	if ((victim = find_char_dir(ch, dir, name)) == NULL)
	{
		send_to_char("Your victim must have slipped out of sight!\n\r", ch);
		pop_call();
		return;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}

	if (find_keeper(victim) != NULL || IS_SET(victim->in_room->room_flags, ROOM_SAFE))
	{
		send_to_char("You can't charge into that room.\n\r", ch);
		pop_call();
		return;
	}

	if (findpath_search_victim(ch, victim, range) == -1)
	{
		act("You cannot reach $N quickly enough to charge $M.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}
	if (mount->move < 10)
	{
		if (mount != ch)
		{
			act("Your mount is too tired to charge.", ch, NULL, NULL, TO_CHAR);
		}
		else
		{
			act("You are too tired to charge.", ch, NULL, NULL, TO_CHAR);
		}
		pop_call();
		return;
	}
	
	if (mount != ch)
	{
		act("You charge $twards upon $N!", ch, dir_name[dir], mount, TO_CHAR);
		act("$n charges $twards upon $N!", ch, dir_name[dir], mount, TO_ROOM);
	}
	else
	{
		act("You charge $twards!", ch, dir_name[dir], NULL, TO_CHAR);
		act("$n charges $twards!", ch, dir_name[dir], NULL, TO_ROOM);
	}
	
	char_from_room(ch);
	char_to_room(ch, victim->in_room->vnum, TRUE);
	
	if (mount != ch)
	{
		ch->mounting = mount;
		char_from_room(mount);
		char_to_room(mount, ch->in_room->vnum, TRUE);
		do_look(mount, "");
	}

	do_look(ch, "auto");

	if (mount != ch)
	{
		act("$n charges in from $t upon $N!", ch, dir_name[dir], mount, TO_ROOM);
	}
	else
	{
		act("$n charges in from $t!", ch, dir_name[dir], NULL, TO_ROOM);
	}

	if (!IS_NPC(ch))
	{
		mprog_greet_trigger(ch);
		oprog_greet_trigger(ch);
		rprog_greet_trigger(ch);
	}
	
	move_loss(ch, mount, 10);
	
	// just in case a mprog kills someone...
	if (!valid_fight(ch, victim) || !valid_fight(mount, victim))
	{
		pop_call();
		return;
	}
	
	SET_BIT(ch->attack, ATTACK_CHARGE);
	
	if (!can_melee_attack(mount, victim))
	{
		pop_call();
		return;
	}
	
	one_hit(ch, victim, TYPE_UNDEFINED, 0, weapon);
	
	// ride-by attack feat. Find second victim to iterate attack
	if (learned(ch, gsn_ride_by_attack) && IS_AWAKE(ch) && IS_AWAKE(mount))
	{
		CHAR_DATA *fch;
	
		if ((fch = get_next_fighting(ch, victim)) != NULL)
		{
			act("$n charges charges through to another target!", ch, NULL, NULL, TO_ROOM);
			act("You charge charges through to another target!", ch, NULL, NULL, TO_CHAR);
			
			one_hit(ch, victim, TYPE_UNDEFINED, -5, weapon);
		}
	}
	TAKE_ACTION(ch, ACTION_FULL);
	
	pop_call();
	return;
}

/*
 * Rescue - take over an opponent from another
 * revised to use PFRPG combat maneuver - Kregor
 */
void do_rescue( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	CHAR_DATA *fch, *fch_next;

	push_call("do_rescue(%p,%p)",ch,argument);

	one_argument( argument, arg );

	if ( arg[0] == '\0' )
	{
		send_to_char( "Rescue whom?\n\r", ch );
		pop_call();
		return;
	}
	
	if (!in_combat(ch))
	{
		send_to_char( "This isn't your fight, unless you join in.\n\r", ch );
		pop_call();
		return;
	}

	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", arg );
		pop_call();
		return;
	}

	if (victim == ch)
	{
		send_to_char( "What about fleeing instead?\n\r", ch );
		pop_call();
		return;
	}

	for (fch = ch->in_room->first_person ; fch != NULL ; fch = fch_next)
	{
		fch_next = fch->next_in_room;

		if (fch->last_attacked && fch->last_attacked == victim)
		{
			break;
		}
	}

	if (fch == NULL)
	{
		send_to_char( "That person isn't under attack.\n\r", ch );
		pop_call();
		return;
	}
	
	act( "{128}You attempt to rescue $N!",  ch, NULL, victim, TO_CHAR    );
	act( "{128}$n attempts to rescue you!", ch, NULL, victim, TO_VICT    );
	act( "{128}$n attempts to rescue $N!",  ch, NULL, victim, TO_NOTVICT );

	for (fch = ch->in_room->first_person ; fch != NULL ; fch = fch_next)
	{
		fch_next = fch->next_in_room;

		if (fch->last_attacked && fch->last_attacked == victim)
		{
			if (!learned(ch, gsn_spring_attack) && combat_maneuver_check(fch, ch, gsn_tumble) < 0)
			{
				attack_of_opportunity(fch, ch);
			}
			if (combat_maneuver_check(ch, fch, gsn_rescue) >= 0)
			{
				fch->last_attacked = ch;
				act( "{128}$n switches places with your opponent!", ch, NULL, fch, TO_VICT );
			}
			else
			{
				break;
			}
		}
	}
	
	gain_favor(ch, DOMAIN_PROTECTION, 4);
	gain_favor(ch, DOMAIN_RETRIBUTION, 4);
	
	TAKE_ACTION(ch, ACTION_MOVE);
	pop_call();
	return;
}

/*
 * Divert - the reverse rescue, one way to flank - Kregor
 */
void do_divert( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	CHAR_DATA *fch, *fch_next;

	push_call("do_divert(%p,%p)",ch,argument);

	if (!IS_NPC(ch) && !learned(ch, gsn_tumble))
	{
		send_to_char( "What about fleeing instead?\n\r", ch );
		pop_call();
		return;
	}

	if (!in_combat(ch))
	{
		send_to_char( "You aren't fighting!\n\r", ch );
		pop_call();
		return;
	}

	for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
	{
		if (fch->last_attacked && fch->last_attacked == ch)
		{
			break;
		}
	}
	if (fch == NULL)
	{
		send_to_char( "You aren't under attack.\n\r", ch );
		pop_call();
		return;
	}

	if (argument[0] == '\0')
	{
		send_to_char( "Divert to whom?\n\r", ch );
		pop_call();
		return;
	}

	argument = one_argument( argument, arg );

	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", arg );
		pop_call();
		return;
	}

	if (victim == ch)
	{
		send_to_char( "What about fleeing instead?\n\r", ch );
		pop_call();
		return;
	}

	if (ch->last_attacked == victim)
	{
		act( "Trying to make $m fight $mself?",  ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (!in_same_combat(ch, victim))
	{
		send_to_char( "That person is not fighting with you.\n\r", ch );
		pop_call();
		return;
	}

	if (!is_same_group(ch,victim))
	{
		act( "$N isn't a member of your group.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	for (fch = ch->in_room->first_person ; fch != NULL ; fch = fch_next)
	{
		fch_next = fch->next_in_room;

		if (fch->last_attacked && fch->last_attacked == ch)
		{
			if (combat_maneuver_check(fch, ch, gsn_tumble) < 0)
			{
				act( "{138}You fail to divert $N.", ch, NULL, fch, TO_CHAR );

				if (!learned(ch, gsn_spring_attack))
				{
					attack_of_opportunity(fch, ch);
				}
				break;
			}
			act( "You divert your attacker to $N!",  ch, NULL, victim, TO_CHAR);
			act( "$n diverts $s attacker to you!", ch, NULL, victim, TO_VICT);
			act( "$n diverts $s attacker to $N!",  ch, NULL, victim, TO_NOTVICT);

			fch->last_attacked = victim;
		}
	}
	
	gain_favor(ch, DOMAIN_PROTECTION, -4);
	gain_favor(ch, DOMAIN_TRICKERY, 2);
	
	TAKE_ACTION(ch, ACTION_MOVE);
	pop_call();
	return;
}


/*
 * Sunder, the command and the function. Mobiles use the function alone.
 */
void do_sunder( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	OBJ_DATA *wield, *vicwield;
	char arg[MAX_INPUT_LENGTH];

	push_call("do_sunder(%p,%p)",ch,argument);
	
	argument = one_argument(argument, arg);

	if (argument[0] == '\0' || arg[0] == '\0' )
	{
		send_to_char( "Sunder what on whom?\n\r", ch );
		pop_call();
		return;
	}
	else if ((victim = get_char_room(ch, argument)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}
	else if ((vicwield = get_obj_wear(victim, arg)) == NULL)
	{
		act("You don't see $t on $N.", ch, arg, victim, TO_CHAR );
		pop_call();
		return;
	}

	if ((wield = get_wield(ch, FALSE)) == NULL || !IS_WEAPON(wield) || WSPEC(wield, WSPEC_MISSILE|WSPEC_NOMELEE))
	{
		send_to_char( "You need a melee weapon to sunder with.\n\r", ch );
		pop_call();
		return;
	}
	
	sunder(ch, victim, vicwield, 0);

	pop_call();
	return;
}

/*
 * Returns TRUE if the attempt is made, whether or not it succeeds.
 */
bool sunder( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj, int hit_adj )
{
	OBJ_DATA *wield;
	int dt, dam;

	push_call("sunder(%p,%p)",ch,victim);

	if (victim == NULL || obj == NULL)
	{
		pop_call();
		return FALSE;
	}
	
	if (victim == ch)
	{
		act("You could just sell it.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if ((wield = get_wield(ch, FALSE)) == NULL || !IS_WEAPON(wield) || WSPEC(wield, WSPEC_MISSILE|WSPEC_NOMELEE))
	{
		pop_call();
		return FALSE;
	}
	
	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	dt = TYPE_HIT;

	if (!can_see_obj(ch, obj))
	{
		if (number_percent() > 50)
		{
			act( "You fail to get a good look at $p.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return FALSE;
		}
	}

	if (!can_surprise(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (!has_mirror(ch, victim, gsn_sunder))
	{
		if (!in_combat(ch) || is_active(ch))
		{
			if (!learned(ch, gsn_imp_sunder) || (learned(victim, gsn_combat_reflexes) && victim->level > ch->level - 4))
			{
				if (attack_of_opportunity(victim, ch))
				{
					if (!valid_fight(ch, victim))
					{
						pop_call();
						return TRUE;
					}
				}
			}
		}
		if (combat_maneuver_check(ch, victim, gsn_sunder) < 0)
		{
			act( "You fail your attempt to sunder $p.", ch, obj, victim, TO_CHAR);
			act( "$n attempts to sunder $p and misses.", ch, obj, victim, TO_NOTVICT);
			act( "$n attempts to sunder $p and misses.", ch, obj, victim, TO_VICT);
		}
		else
		{
			act( "You attempt to sunder $p on $N.", ch, obj, victim, TO_CHAR);
			act( "$n attempts to sunder $p.", ch, obj, victim, TO_NOTVICT);
			act( "$n attempts to sunder $p on $N.", ch, obj, victim, TO_VICT);
		
			dam = dice(weapon_table[wield->value[0]].damnodice, weapon_table[wield->value[0]].damsizedice);
			damage_equipment(ch, victim, obj, dam, dt, wield);
		}
	}
	// so these don't go off on attacks of opportunity
	if (in_same_combat(ch, victim) && is_active(ch))
	{
		primary_melee_attacks(ch, victim, wield, get_wield(ch, TRUE));
	}
	
	if (!IS_NPC(ch) && IS_NPC(victim) && !in_combat(victim))
		fight(victim, ch);
	
	TAKE_ACTION(ch, ACTION_STANDARD);
	SET_BIT(ch->attack, ATTACK_SUNDER|ATTACK_MELEE);

	pop_call();
	return TRUE;
}

/*
 * Coup de grace, final blow for
 * helpless victims - Kregor
 */
void do_coupdegrace( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	OBJ_DATA *wield;

	push_call("coup_de_grace(%p,%p)",ch,argument);

	wield = get_wield(ch, FALSE);
	one_argument( argument, arg );

	if (arg[0] == '\0')
	{
		send_to_char( "To whom is it you wish to deliver a coup de grace?\n\r", ch );
		pop_call();
		return;
	}

	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", arg );
		pop_call();
		return;
	}

	if (victim == ch)
	{
		send_to_char( "Putting yourself out of your misery?\n\r", ch);
		pop_call();
		return;
	}

 	if (!IS_HELPLESS(victim))
	{
		act( "$N is not as helpless as you may think.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}
	
	if (!CAN_CRITICAL(victim))
	{
		act( "$N is not subject to critical hits.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}
	
	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}
	
	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return;
	}
	
	if (!in_combat(ch) && !in_combat(victim))
	{
		fight(ch, victim);
	}
	CHECK_TURN(ch, victim);

	if (!ch->concentrating && !learned(ch, gsn_swift_death))
	{
		if (!check_murder(ch, victim))
		{
			pop_call();
			return;
		}
		act( "$n readies a coup de grace against $N.", ch, NULL, victim, TO_ROOM );
		act( "You ready a coup de grace against $N.", ch, NULL, victim, TO_CHAR );
		ch->concentrating = TRUE;
		ch->skill_timer		= 8;
		ch->timer_fun			= do_coupdegrace;
		RESTRING(ch->cmd_argument, argument);
		pop_call();
		return;
	}
	
	act( "$n attempts a coup de grace on $N!", ch, wield, victim, TO_NOTVICT);
	act( "$n attempts a coup de grace on you!", ch, wield, victim, TO_VICT);
	act( "You attempt a coup de grace on $N!", ch, wield, victim, TO_CHAR);
	one_hit( ch, victim, gsn_coup_de_grace, 0, wield );

	TAKE_ACTION(ch, ACTION_FULL);
	pop_call();
	return;
}

/*
 * Assassin death attack. Issue command once to start 3 round
 * observation countdown. After countdown, three more rounds 
 * to issue command again to assassinate the person - Kregor
 */
void do_assassinate( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	OBJ_DATA *wield;

	push_call("do_assassinate(%p,%p)",ch,argument);

	if (multi(ch, gsn_assassinate) == -1)
	{
		send_to_char("You are not that practiced a cut-throat.\n\r", ch );
		pop_call();
		return;
	}

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

	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", arg );
		pop_call();
		return;
	}

	if (victim == ch)
	{
		send_to_char( "Suicide would be easier.\n\r", ch);
		pop_call();
		return;
	}

	if (!CAN_CRITICAL(victim))
	{
		send_to_char( "You question your ability to land a telling blow.\n\r", ch );
		pop_call();
		return;
	}

	if (in_combat(ch) && !is_active(ch))
	{
		send_to_char( "You need to wait your turn.\n\r", ch );
		pop_call();
		return;
	}
	
	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}
	
	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return;
	}
	
	if (IS_AWAKE(victim) && !IS_FLATFOOTED(victim) && !IS_HELPLESS(victim))
	{
		act( "You cannot take $N by surprize.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return;
	}
	
	wield = get_wield(ch, FALSE);

	if (ch->assassinate == NULL)
	{
		if (!learned(ch, gsn_swift_death))
		{
			act( "You begin to study $N's anatomy and movements...", ch, NULL, victim, TO_CHAR);
	
			if (IS_AWAKE(victim) && can_see(victim, ch) && sense_motive_check(victim, ch, sense_motive_roll(victim), bluff_roll(ch)))
			{
				act( "$N eyes you suspiciously.", ch, NULL, victim, TO_CHAR);
				act( "{138}$n eyes you like a stalker sizing up $s kill.", ch, NULL, victim, TO_VICT);
				pop_call();
				return;
			}
			
			ch->assassinate = victim;
			ch->asn_count = 71;
			pop_call();
			return;
		}
	}
		
	if (!learned(ch, gsn_swift_death))
	{
		if (victim != ch->assassinate)
		{
			act( "$N is not your mark.", ch, NULL, victim, TO_CHAR);
			pop_call();
			return;
		}
		
		if (ch->asn_count > 36 || ch->asn_count <= 0)
		{
			act( "You have not studied $N enough to make your move.", ch, NULL, victim, TO_CHAR);
			pop_call();
			return;
		}
	}
	
	if (victim->in_room != ch->in_room)
	{
		act( "Your target must have slipped out of sight.", ch, NULL, NULL, TO_CHAR);
		ch->assassinate = NULL;
		ch->asn_count = 0;
		pop_call();
		return;
	}
	
	if (!check_murder(ch, victim))
	{
		pop_call();
		return;
	}

	one_hit( ch, victim, gsn_assassinate, 0, wield );

	ch->assassinate = NULL;
	ch->asn_count = 0;
	TAKE_ACTION(ch, ACTION_FULL);

	pop_call();
	return;
}


/*
 * Stunning fist feat - Kregor
 */
void do_stun(CHAR_DATA *ch, char *argument)
{
	CHAR_DATA *victim;

	push_call("do_stun(%p,%p)",ch,argument);

	if (IS_SET(ch->attack, ATTACK_STUNNING_FIST))
	{
		send_to_char("You've already used that maneuver\n\r", ch);
		pop_call();
		return;
	}

	if (!learned(ch, gsn_stunning_fist))
	{
		send_to_char("You don't know this feat.\n\r",ch);
		pop_call();
		return;
	}

	if (!CHECK_USES(ch, gsn_stunning_fist))
	{
		pop_call();
		return;
	}

	if (hands_full(ch))
	{
		send_to_char("You cannot make a stunning fist without an open hand.\n\r", ch);
		pop_call();
		return;
	}

	if (argument[0] == '\0')
	{
		if ((victim = ch->last_attacked) == NULL)
		{
			send_to_char( "Stun whom?\n\r", ch );
			pop_call();
			return;
		}
	}
	else if ((victim = get_char_room(ch, argument)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}
	stun(ch, victim, 0);
}

bool stun(CHAR_DATA *ch, CHAR_DATA *victim, int hit_adj)
{
	push_call("stun(%p,%p)",ch,victim);

	if (IS_SET(ch->attack, ATTACK_STUNNING_FIST))
	{
		pop_call();
		return FALSE;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (!learned(ch, gsn_stunning_fist))
	{
		pop_call();
		return FALSE;
	}
	
	if (!CHECK_USES(ch, gsn_stunning_fist))
	{
		pop_call();
		return FALSE;
	}

	if (get_wield(ch, FALSE) != NULL)
	{
		pop_call();
		return FALSE;
	}

	BOOL_CHECK_TURN(ch, victim);

	one_hit(ch, victim, gsn_stunning_fist, 0, NULL);

	// so these don't go off on attacks of opportunity
	if (in_same_combat(ch, victim) && is_active(ch))
	{
		primary_melee_attacks(ch, victim, NULL, NULL);
	}

	ch->uses[gsn_stunning_fist]++;
	TAKE_ACTION(ch, ACTION_STANDARD);
	SET_BIT(ch->attack, ATTACK_STUNNING_FIST|ATTACK_MELEE);

	pop_call();
	return TRUE;
}

/*
 * Bullrush maneuver from Open Gaming SRD - Kregor
 */
void do_bullrush( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_STRING_LENGTH];
	char arg2[MAX_STRING_LENGTH];
	CHAR_DATA *victim;
	EXIT_DATA *pExit;
	ROOM_INDEX_DATA *to_room;
	int door, check;

	push_call("do_bullrush(%p,%p)",ch,argument);

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

	if (arg1[0] == '\0' || arg2[0] == '\0')
	{
		send_to_char("Syntax: bullrush <target> <direction>\n\r", ch);
		pop_call();
		return;
	}

	if ((victim = get_char_room(ch, arg1)) == NULL)
	{
		send_to_char( "Bullrush whom?\n\r", ch );
		pop_call();
		return;
	}
	
	if (victim == ch)
	{
		send_to_char( "You shouldn't shove yourself around like that.\n\r", ch );
		pop_call();
		return;
	}
	
	if ((door = direction_door(arg2)) == -1)
	{
		act("Bullrush $N in what direction?", ch, NULL, victim, TO_CHAR);
		pop_call();
	  return;
	}

	if ((pExit = get_exit(ch->in_room->vnum, door)) == NULL
	|| (to_room = room_index[pExit->to_room]) == NULL)
	{
	  ch_printf_color(ch, "Alas, you cannot press anyone in that direction.\n\r");
		pop_call();
		return;
	}

	if (!IS_AWAKE(victim))
	{
		act( "You can't bullrush $N while $E's down.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (get_size(ch) + 1 < get_size(victim))
	{
		act( "$N is too big for you to push around.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (is_mounting(victim))
	{
		send_to_char( "You can't bullrush a mounted target... MAYBE you could rush the mount.\n\r", ch );
		pop_call();
		return;
	}

	if (!can_move_char(ch, door))
	{
		pop_call();
		return;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}
	
	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return;
	}
	
	CHECK_TURN(ch, victim);	

	if (!can_surprise(ch, victim))
	{
		pop_call();
		return;
	}

	if (!has_mirror(ch, victim, gsn_bullrush))
	{
		if (!in_combat(ch) || is_active(ch))
		{
			if (!learned(ch, gsn_imp_bullrush) || (learned(victim, gsn_combat_reflexes) && victim->level > ch->level - 4))
			{
				if (attack_of_opportunity(victim, ch))
				{
					if (!valid_fight(ch, victim))
					{
						pop_call();
						return;
					}
				}
			}
		}
	
		if ((check = combat_maneuver_check(ch, victim, gsn_bullrush)) >= 10)
		{
			act( "You press $N $tward, travelling with $M!", ch, dir_name[door], victim, TO_CHAR);
			act( "$n presses you $tward, travelling with you!", ch, dir_name[door], victim, TO_VICT);
			act( "$n presses $N $tward, travelling with $M!", ch, dir_name[door], victim, TO_NOTVICT);
			char_from_room(ch);
			char_to_room(ch, to_room->vnum, TRUE);
			char_from_room(victim);
			char_to_room(victim, to_room->vnum, TRUE);
			act( "$n and $N arrive in a press from $T.", ch, rev_dir_name[door], victim, TO_NOTVICT);
		}			
		else if (check >= 0)
		{
			act( "You press $N back away from you.", ch, NULL, victim, TO_CHAR);
			act( "$n presses you back away from $m.", ch, NULL, victim, TO_VICT);
			act( "$n presses $N back away from $m.", ch, NULL, victim, TO_NOTVICT);
			victim->distracted = 2;
		}
		else
		{
			act( "You try to bullrush $N but $E resists your attempt.", ch, NULL, victim, TO_CHAR);
			act( "$n tries to bullrush you, and you resist $s attempt", ch, NULL, victim, TO_VICT);
			act( "$n tries to bulrush $N and fails!", ch, NULL, victim, TO_NOTVICT);
		}
	}
	TAKE_ACTION(ch, ACTION_STANDARD);
	SET_BIT(ch->attack, ATTACK_MELEE);
	
	if (!IS_NPC(ch) && IS_NPC(victim) && !in_combat(victim))
		fight(victim, ch);

	pop_call();
	return;
}

/*
 * Turned gouge into a feat, trainable by
 * rogues as a rogue talent - Kregor
 */
void do_gouge( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	AFFECT_DATA af;
	int check;

	push_call("do_gouge(%p,%p)",ch,argument);

	if (!learned(ch, gsn_gouge))
	{
		ch_printf_color(ch, "You haven't learned this dirty trick!\n\r");
		pop_call();
		return;
	}

	if (argument[0] == '\0')
	{
		if ((victim = ch->last_attacked) == NULL)
		{
			send_to_char( "Gouge whose eyes out?\n\r", ch );
			pop_call();
			return;
		}
	}
	else if ((victim = get_char_room(ch, argument)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}
	
	if (ch == victim)
	{
		ch_printf(ch, "Claw your own eyes out?\n\r", argument );
		pop_call();
		return;
	}
	
	if (CAN_CRITICAL(victim))
	{
		send_to_char("You wouldn't even begin to know where to gouge.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_RACE_AFFECT(victim, AFF_BLIND))
	{
		act("$N cannot be blinded.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}
	
	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return;
	}
	
	CHECK_TURN(ch, victim);	

	if (!can_surprise(ch, victim))
	{
		pop_call();
		return;
	}

	if (!has_mirror(ch, victim, gsn_gouge))
	{
		if ((check = combat_maneuver_check(ch, victim, gsn_gouge)) < 0)
		{
			damage(ch, victim, 0, gsn_gouge, NULL);
		}
		else
		{	
			damage(ch, victim, dice(1,4), gsn_gouge, NULL);
	
			if (valid_fight(ch, victim))
			{
				if (!IS_AFFECTED(victim, AFF_BLIND))
				{
					if (check > 0)
					{
						act( "{138}$N screams as you gouge at $S eyes!", ch, NULL, victim, TO_CHAR );
						act( "{138}You scream and can't see a thing as $n gouges your eyes!", ch, NULL, victim, TO_VICT );
						act( "{138}$N screams as $n gouges at $S eyes!", ch, NULL, victim, TO_NOTVICT );
		
						af.type      = gsn_gouge;
						af.location  = APPLY_NONE;
						af.modifier  = 0;
						af.duration  = check;
						af.bittype   = AFFECT_TO_CHAR;
						af.bitvector = AFF_BLIND;
						affect_to_char( ch, victim, &af );
					}
					else
					{
						act( "$N seems to be able to see despite your attack!", ch, NULL, victim, TO_CHAR );
						act( "You are unhindered by $n's attack.", ch, NULL, victim, TO_VICT );
					}
				}
			}
			else
			{
				act( "Your fingers plunge into your victim's brain, causing immediate death!", ch, NULL, NULL, TO_CHAR );
			}
		}
	}
	pop_call();
	return;
}


/*
 * Intimidate skill active command - Kregor 06/09/07
 */
void do_intimidate (CHAR_DATA * ch, char *argument)
{
	CHAR_DATA *victim;
	AFFECT_DATA af;
	int check;

	push_call("do_intimidate(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		send_to_char ("Intimidate whom?\n\r", ch);
		pop_call();
		return;
	}
	
	if (!in_combat(ch))
	{
		send_to_char ("You are not fighting anyone.\n\r", ch);
		pop_call();
		return;
	}

	if ((victim = get_char_room(ch, argument)) == NULL )
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}
	
  if (ch == victim)
  {
		send_to_char ("Oooh, you've scared yourself!\n\r", ch);
		pop_call();
		return;
	}

	CHECK_TURN(ch, victim);

	if (!IS_AFFECTED(victim, AFF2_FEAR))
	{
		if ((check = intimidate_check(ch, victim, intimidate_roll(ch), 0)) >= 0)
		{
			af.type      = gsn_intimidate;
			af.duration  = 1 + check / 5;
			af.location  = APPLY_NONE;
			af.modifier  = 0;
			af.bittype   = AFFECT_TO_CHAR;
			af.bitvector = AFF2_FEAR;
			af.level     = ch->level;
			affect_to_char( ch, victim, &af );
			victim->fear_level++;
			act( "$N is visibly intimidated by your presence.", ch, NULL, victim, TO_CHAR);
			act( "You are shaken at $n's intimidating presence.", ch, NULL, victim, TO_VICT);
			act( "$N is visibly intimidated by $n's presence.", ch, NULL, victim, TO_NOTVICT);
		}
		else
		{
			act( "$N shrugs off your effort at being intimidating.", ch, NULL, victim, TO_CHAR);
			act( "You shrug off $n's attempt at intimidating you.", ch, NULL, victim, TO_VICT);
			act( "$N shrugs off $n's effort at being intimidating.", ch, NULL, victim, TO_NOTVICT);
		}
	}
	else
  {
		act ("$N is already fearful.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}
	TAKE_ACTION(ch, ACTION_STANDARD);
	pop_call();
	return;
}

/*
 * Feint, Bluff skill in combat. Mobiles use the function alone.
 */
void do_feint( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;

	push_call("do_feint(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		if ((victim = ch->last_attacked) == NULL)
		{
			send_to_char( "Feint against whom?\n\r", ch );
			pop_call();
			return;
		}
	}
	else if ((victim = get_char_room(ch, argument)) == NULL)
	{
		ch_printf(ch, "There's no %s here.\n\r", argument );
		pop_call();
		return;
	}

	if (IS_SET(ch->action, ACTION_STANDARD) && !learned(ch, gsn_improved_feint))
	{
		send_to_char("You have already made a standard action this round.\n\r",ch);
		pop_call();
		return;
	}
	
	if (victim == ch)
	{
		send_to_char_color( "Distract yourself?", ch );
		pop_call();
		return;
	}

	CHECK_TURN(ch, victim);
	
	feint(ch, victim, 0);

	pop_call();
	return;
}

/*
 * Feint command, for bluff skill in combat.
 */
bool feint( CHAR_DATA *ch, CHAR_DATA *victim, int hit_adj )
{
	AFFECT_DATA af;
	int diceroll, dc;

	push_call("feint(%p,%p)",ch,victim);

	if (IS_NPC(ch) && !learned(ch, gsn_backstab))
	{
		pop_call();
		return FALSE;
	}
	
	if (!in_combat(ch) || !is_active(ch))
	{
		pop_call();
		return FALSE;
	}
	
	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	diceroll = feint_roll(ch);
	
	if (victim->distracted > 0 || is_affected(victim, gsn_bluff))
	{
		act( "$N won't be fooled again.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return FALSE;
	}
	if (victim->position <= POS_SLEEPING || !can_see(victim, ch))
	{
		act( "$N is not paying attention to you.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return FALSE;
	}
	if (get_curr_int(victim) <= 0)
	{			
		act( "$N just ignores your attempt.",ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}
	else if (victim->perm_int <= 2)
		diceroll -= 8;
	else if (!IS_HUMANOID(victim))
		diceroll -= 4;

	if (learned(ch, gsn_greater_feint))	
	{
		if (!IS_SET(ch->action, ACTION_SWIFT))
			TAKE_ACTION(ch, ACTION_SWIFT);
		else
			TAKE_ACTION(ch, ACTION_MOVE);
	}
	else if (learned(ch, gsn_improved_feint))
		TAKE_ACTION(ch, ACTION_MOVE);
	else
		TAKE_ACTION(ch, ACTION_STANDARD);
		
	dc = UMAX(base_attack(victim), learned(victim, gsn_sense_motive)) + stat_bonus(TRUE, victim, APPLY_WIS) + dice(1,20);

	if (sense_motive_check(victim, ch, dc, diceroll))
	{
		act( "$t$N ignores your feint attempt.", ch, get_color_string(ch, COLOR_YOU_ARE_HIT, VT102_BOLD), victim, TO_CHAR );
		act( "$tYou outsmart $n's feint attempt against you!", ch, get_color_string(victim, COLOR_YOU_HIT, VT102_BOLD), victim, TO_VICT);
		victim->distracted = 0;
		affect_strip(victim, gsn_bluff);
		pop_call();
		return TRUE;
	}
	act( "$t$n feints you and you drop your guard!", ch, get_color_string(victim, COLOR_YOU_ARE_HIT, VT102_BOLD), victim, TO_VICT);
	act( "$tYou feint against $N!", ch, get_color_string(ch, COLOR_YOU_HIT, VT102_BOLD), victim, TO_CHAR);
	act( "$n feints against $N!", ch, NULL, victim, TO_NOTVICT);

	af.type      = gsn_bluff;
	af.duration  = 2;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = 0;
	af.level     = diceroll;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}

/*
 * Taunt command, for bluff skill against casters.
 */
void do_taunt( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	int diceroll, victroll;

	push_call("do_taunt(%p,%p)",ch,argument);

	argument = one_argument(argument, arg);

	if (arg[0] == '\0')
	{
		send_to_char("Syntax: taunt <target>\n\r",ch);
		pop_call();
		return;
	}
	
	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		send_to_char("They are not here.\n\r",ch);
		pop_call();
		return;
	}
	if (victim == ch)
	{
		send_to_char_color( "You taunt yourself?", ch );
		pop_call();
		return;
	}

	if (!victim->casting && !victim->concentrating)
	{
		act( "$N is doing nothing to be distracted from.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return;
	}
	
	CHECK_TURN(ch, victim);

	if (victim->distracted > 0 || is_affected(victim, gsn_bluff))
	{
		act( "$N won't be fooled again.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return;
	}
	if (victim->position <= POS_SLEEPING || !can_see(victim, ch))
	{
		act( "$N is not paying attention to you.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return;
	}

	diceroll = bluff_roll(ch);
	victroll = concentration_roll(victim);
	
	if (in_combat(ch) && !is_active(ch))
	{
		take_opportunity(ch, victim);
	}	
	TAKE_ACTION(ch, ACTION_STANDARD);

	if (get_curr_int(victim) <= 0)
	{			
		act( "$N just ignores your attempt.",ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}
	else if (victim->perm_int <= 2)
	{
		diceroll -= 8;
	}

	if (concentration_check(victim, ch, victroll, diceroll))
	{
		act( "$N ignores your taunting.", ch, NULL, victim, TO_CHAR );
		act( "$n attempts to taunt you, but you ignore it.", ch, NULL, victim, TO_VICT);
		act( "$n unsuccessfully tries to taunt $N.", ch, NULL, victim, TO_NOTVICT);
		victim->distracted = 0;
		affect_strip(victim, gsn_bluff);
		pop_call();
		return;
	}

	act( "$n's taunting distracts you from your concentration!", ch, NULL, victim, TO_VICT);
	act( "Your taunting distracts $N from $S concentration!", ch, NULL, victim, TO_CHAR);
	act( "$n's taunting distracts $N from $S concentration!", ch, NULL, victim, TO_NOTVICT);

	if (victim->casting)
	{
		if (victim->cast_sn == gsn_recite_scroll && victim->reciting)
		{
			junk_obj(victim->reciting);
		}
		free_cast(victim);
	}
	if (victim->concentrating)
	{
		free_skill(victim);
	}
	
	pop_call();
	return;
}

/*
 * For creatures with rend attacks - Kregor 9/19/08
 */
void do_rend( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg[MAX_INPUT_LENGTH];

	push_call("do_rend(%p,%p)",ch,argument);

	if (!learned(ch, gsn_rend))
	{
		send_to_char("You cannot do that.\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument(argument, arg);

	if (arg[0] == '\0' || (victim = get_char_room(ch, arg)) == NULL)
	{
		if ((victim = who_fighting(ch)) == NULL)
		{
			send_to_char("You are not fighting anyone.\n\r",ch);
			pop_call();
			return;
		}
	}

	if (in_combat(ch) && !is_active(ch))
	{
		send_to_char("Just wait your turn.\n\r", ch);
		pop_call();
		return;
	}

	rend(ch, victim);

	pop_call();
	return;
}


/*
 * For creatures with rend attacks - Kregor 9/19/08
 * Does additional damage over and above the two attacks
 * if both attacks hit. This is over and above DR,
 * equal to the damage of both attacks, plus magic
 * or STR bonuses. No other bonuses apply.
 */
bool rend( CHAR_DATA *ch, CHAR_DATA *victim )
{
	bool hitone, hittwo;
	int dam, dam2;

	push_call("rend(%p,%p)",ch,victim);

	if (!learned(ch, gsn_rend))
	{
		pop_call();
		return FALSE;
	}
	
	if (get_wield(ch, FALSE) || get_wield(ch, TRUE) || get_hold(ch))
	{
		send_to_char("You must rend with two claws.\n\r", ch);
		pop_call();
		return FALSE;
	}
		
	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (!check_murder(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	if (victim != NULL && in_combat(victim))
	{	
		if (!in_combat(ch) || (ch->last_attacked && ch->last_attacked != victim))
		{							
			send_to_char("You can only rend someone you are actively fighting.\n\r", ch);
			pop_call();
			return FALSE;
		}
		if (!is_active(ch))	
		{
			send_to_char("Just wait your turn!\n\r", ch);
			pop_call();
			return FALSE;
		}	
	}

	if (!has_mirror(ch, victim, gsn_rend))
	{
		hitone = (one_hit(ch, victim, TYPE_UNDEFINED, 0, NULL));
		hittwo = (one_hit(ch, victim, TYPE_UNDEFINED, 0, NULL));
	
		//if either one doesn't connect, there's no rend
		if (!hitone || !hittwo)
		{
			TAKE_ACTION(ch, ACTION_FULL);
			pop_call();
			return TRUE;
		}
		
		//calc each attack's additional damg
		dam = dice(get_damnodice(ch), get_damsizedice(ch));
	
		dam2 = dice(get_damnodice(ch), get_damsizedice(ch));
		dam2 += get_apply(ch, APPLY_COMP_DAMG);
		dam2 += get_apply(ch, APPLY_LUCK_DAMG);
		dam2 += get_apply(ch, APPLY_MOR_DAMG);
	
		if (IS_AFFECTED(ch, AFF2_SICKENED))
		{
			dam -= 2;
			dam2 -= 2;
		}
	
		dam += dam2;
		
		//it's a single effect, so mods only once
		dam += stat_bonus(TRUE, ch, APPLY_STR) * 3 / 2;
		dam += get_apply(ch, APPLY_COMP_DAMG);
		dam += get_apply(ch, APPLY_LUCK_DAMG);
		dam += get_apply(ch, APPLY_MOR_DAMG);
		
		if (dam <= 0)
			dam = 1;
		
		dam_message(ch, victim, dam, gsn_rend, NULL);
		
		//type nofight bypasses DR, damage is supplemental to hits - Kregor
		damage(ch, victim, dam, TYPE_NOFIGHT, NULL);
	}
	TAKE_ACTION(ch, ACTION_FULL);
	pop_call();
	return TRUE;
}


/*
 * For creatures with pounce attacks - Kregor 9/19/08
 */
void do_pounce( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg[MAX_INPUT_LENGTH];

	push_call("do_pounce(%p,%p)",ch,argument);

	if (!learned(ch, gsn_pounce))
	{
		send_to_char("You cannot do that.\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument(argument, arg);

	if (arg[0] == '\0' || (victim = get_char_room(ch, arg)) == NULL)
	{
		if ((victim = who_fighting(ch)) == NULL)
		{
			send_to_char("You are not fighting anyone.\n\r",ch);
			pop_call();
			return;
		}
	}

	if (in_combat(ch) && !is_active(ch))
	{
		send_to_char("Just wait your turn.\n\r", ch);
		pop_call();
		return;
	}

	pounce(ch, victim);

	pop_call();
	return;
}


/*
 * For creatures with pounce attacks - Kregor 9/19/08
 * Allows a full-round action to launch all possible
 * attacks including a rake against a single foe.
 */
bool pounce( CHAR_DATA *ch, CHAR_DATA *victim )
{
	int part, count;

	push_call("pounce(%p,%p)",ch,victim);

	if (!learned(ch, gsn_pounce))
	{
		pop_call();
		return FALSE;
	}
	
	if (is_safe(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (!can_melee_attack(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (IS_SET(ch->action, ACTION_FULL))
	{
		pop_call();
		return FALSE;
	}

	if (!check_murder(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	BOOL_CHECK_TURN(ch, victim);

	act("You pounce onto $N!", ch, NULL, victim, TO_CHAR);
	act("$n pounces onto $N!", ch, NULL, victim, TO_NOTVICT);
	act("$n pounce onto you!", ch, NULL, victim, TO_VICT);

	if (!has_mirror(ch, victim, gsn_pounce))
	{
		for (ch->attack_part = -1, part = 0 ; part < ATTK_MAX ; part++)
		{
			if (!valid_fight(ch, victim))
				break;
			if (num_attacks(ch, part) == -1)
			{
				pop_call();
				return FALSE;
			}
			if (num_attacks(ch, part))
			{
				for (count = 0 ; count < num_attacks(ch, part) ; count++)
				{
					ch->attack_part = part;
					one_hit(ch, victim, TYPE_HIT, 0, NULL);
				}
			}
		}
	}
	TAKE_ACTION(ch, ACTION_FULL);
	pop_call();
	return TRUE;
}


/*
 * Drain result from creatures with draining attacks - Kregor
 * Note the variant of draining puts the saving throw at the
 * beginning, and all successful drains are permanent unless restored.
 */
void level_drain( CHAR_DATA *ch, CHAR_DATA *victim )
{
	AFFECT_DATA af;

	push_call("level_drain(%p,%p,%p)",ch,victim);

	if (!save_resist(ch, victim, gsn_drain, ch->level))
	{
		af.type      = gsn_drain;
		af.duration  = -1;
		af.modifier  = 0 - learned(ch, gsn_drain);
		af.location  = APPLY_LEVEL;
		af.bittype   = AFFECT_TO_NONE;
		af.bitvector = AFF_NONE;
		af.level		 = ch->level;	
		affect_join( ch, victim, &af );

		act( "$n wails as the life force is drawn from $m!", victim, NULL, NULL, TO_ROOM);
		act( "You wail as your life force is drawn from you!", victim, NULL, NULL, TO_CHAR);

		update_pos(victim, -1);

		af.type      = gsn_drain;
		af.duration  = 100;
		af.bittype   = AFFECT_TO_NONE;
		af.bitvector = 0;
		af.level     = ch->level;
		af.location  = APPLY_HIT;
		af.modifier  = learned(ch, gsn_drain) * 5;
		affect_join( ch, ch, &af );
	}
	pop_call();
	return;
}

/*
 * Stat damaging abilities pass through this function
 * at damage function - Kregor
 */
void stat_damage( CHAR_DATA *ch, CHAR_DATA *victim, int apply, int sn )
{
	AFFECT_DATA af;
	int mod;

	push_call("stat_damage(%p,%p,%p,%p)",ch,victim,apply,sn);

	if (ch == NULL)
	{
		ch = victim;
	}
	
	if (sn == gsn_poison)
	{
		mod = dice(1,3);
	}
	else
	{
		mod = dice(1, race_skill(ch,sn));
		// drains get critical hits too!
		if (CRIT_HIT)
		{
			mod += dice(1, race_skill(ch,sn));
		}
	}
	
	if (domain_apotheosis(victim, DOMAIN_REPOSE))
	{
		if (sn == gsn_str_drain || sn == gsn_dex_drain || sn == gsn_con_drain
		|| sn == gsn_int_drain || sn == gsn_wis_drain || sn == gsn_cha_drain)
		{
			pop_call();
			return;
		}
	}

	if (!is_immune(victim, skill_table[sn].spell_desc))
	{
		af.type      = sn;
		af.duration  = -1;
		af.modifier  = 0 - mod;
		af.location  = apply;
		af.bittype   = AFFECT_TO_NONE;
		af.bitvector = AFF_NONE;
		af.level		 = ch->level;	
		affect_join( ch, victim, &af );

		if (victim != ch && (IS_SET(skill_table[sn].flags, SF_TOUCH) || ch->attack_part == ATTK_TOUCH))
		{
			act( "{108}$N staggers as your touch debilitates $M!", ch, NULL, victim, TO_CHAR);
			act( "{108}You stagger as $n's touch debilitates you!", ch, NULL, victim, TO_VICT);
			act( "{108}$N staggers as $n's touch debilitates $M!", ch, NULL, victim, TO_NOTVICT);

			// so that drain affects boost the attacker
			if (IS_SET(skill_table[sn].spell_desc, SDESC_NEGATIVE))
			{
				af.type      = sn;
				af.duration  = 100;
				af.bittype   = AFFECT_TO_NONE;
				af.bitvector = 0;
				af.level     = ch->level;
				af.location  = APPLY_HIT;
				af.modifier  = 5;
				affect_join( ch, ch, &af );
			}
		}
		// stat damage for cockatrice is gradual petrification
		if (ch->race == RACE_COCKATRICE && get_curr_dex(victim) == 0)
		{
			af.type      = sn;
			af.duration  = -1;
			af.modifier  = 0;
			af.location  = APPLY_NONE;
			af.bittype   = AFFECT_TO_CHAR;
			af.bitvector = AFF2_PETRIFICATION;
			af.level		 = ch->level;	
			affect_join( ch, victim, &af );
	
			act( "{108}$n freezes and turns to stone!", victim, NULL, NULL, TO_ROOM);
			act( "{108}Your limbs stiffen, then everything goes black!", victim, NULL, NULL, TO_CHAR);
		}		
		update_pos(victim,-1);
	}
	pop_call();
	return;
}


/*
 * Natural poison attack - Kregor
 * This triggers upon successful hit of poisoned body part
 */
void poison_attack(CHAR_DATA *ch, CHAR_DATA *victim, int type)
{
	POISON_DATA pd;
	int bonus;

	push_call("poison_attack(%p,%p,%p)",ch,victim,type);
	
	pd.type								= type;
	pd.constant_duration	= -1;
	if (!IS_NPC(ch))
		pd.poisoner					= ch->pcdata->pvnum;
	else
		pd.poisoner					= -1;

	// calc actual DC of natural poison based on level and stat
	if (get_curr_con(ch) < 0)
		bonus = stat_bonus(TRUE, ch, APPLY_CHA);
	else
		bonus = stat_bonus(TRUE, ch, APPLY_CON);
	
	pd.dc									= ch->level / 2 + 10 + bonus;

	poison_to_char(ch, victim, &pd);
	
	pop_call();
	return;
}

/*
 * Save or contract disease from attack - Kregor
 */
void disease_attack(CHAR_DATA *ch, CHAR_DATA *victim, int type)
{
	push_call("poison_attack(%p,%p,%p)",ch,victim,type);
	
	if (save_resist(ch, victim, gsn_disease_attack, ch->level))
	{
		pop_call();
		return;
	}

	infect_char(ch, victim, type);
	
	pop_call();
	return;
}



/* 
 * Frightful Presence attack for dragons etc.
 * done at entry into combat - Kregor
 */
void frightful_presence(CHAR_DATA *ch)
{
	CHAR_DATA *vch, *vch_next;
	AFFECT_DATA af;
	int sn, duration;

	push_call("frightful_presence(%p)",ch);
	
	if (!race_skill(ch, gsn_frightful_presence))
	{
		if (!race_skill(ch, gsn_fearful_howl))
		{
			if (!race_skill(ch, gsn_fear_aura))
			{
				pop_call();
				return;
			}
			else
			{
				sn = gsn_fear_aura;
			}
		}
		else
		{
			sn = gsn_fearful_howl;
			act("{118}You let out a chilling howl!", ch, NULL, NULL, TO_CHAR);
			act("{118}$n lets out a chilling howl!", ch, NULL, NULL, TO_ROOM);
			do_shout(ch, "ArrraoooOOOooOOoo..oo..ooo!");
		}
	}
	else
	{
		sn = gsn_frightful_presence;
	}
	
	for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
	{
		vch_next	= vch->prev_in_room;
		
		if (is_same_group(ch, vch))
			continue;

		if (!can_mass_cast(ch, vch, -1))
			continue;

		if (ch->race == vch->race)
			continue;
		if (race_type(ch) == RTYPE_DRAGON && race_type(vch) == RTYPE_DRAGON)
			continue;
		if (rspec_req(ch, RSPEC_DEMON) && rspec_req(vch, RSPEC_DEMON))
			continue;
		if (rspec_req(ch, RSPEC_DEVIL) && rspec_req(vch, RSPEC_DEVIL))
			continue;
		
		if (save_resist(ch, vch, sn, ch->level))
			continue;
			
		if (sn == gsn_frightful_presence)
			duration = dice(5,6);
		else if (sn == gsn_fearful_howl)
			duration = dice(2,4);
		else
			duration = ch->level;

		af.type     	= sn;
		af.level    	= ch->level;
		af.duration		= duration;
		af.bittype  	= AFFECT_TO_CHAR;
		af.bitvector	= AFF2_FEAR;
		af.location 	= APPLY_NONE;
		af.modifier 	= 0;
		affect_join( ch, vch, &af);
		vch->fear_level = UMIN(vch->fear_level + 2, 3);
		
		act( "{118}You are overcome with terror in $N's presence!", vch, NULL, ch, TO_CHAR);
		act( "{118}$n is overcome with terror!", vch, NULL, NULL, TO_ROOM);

		if (in_combat(vch))
		{
			do_withdraw(vch, NULL);
		}
	}
	pop_call();
	return;
}

/* 
 * for the stench racial ability - Kregor
 */
void check_stench(CHAR_DATA *ch)
{
	CHAR_DATA *vch, *vch_next;
	AFFECT_DATA af;

	push_call("check_stench(%p)",ch);
	
	if (!race_skill(ch, gsn_stench))
	{
		pop_call();
		return;
	}

	if (number_range(1,6) == 1)
		act("{128}A vile stench wafts from $n.", ch, NULL, NULL, TO_ROOM);

	for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
	{
		vch_next	= vch->prev_in_room;
		
		if (race_skill(vch, gsn_stench))
			continue;

		if (!can_mass_cast(ch, vch, -1))
			continue;
		
		if (save_resist(ch, vch, gsn_stench, ch->level))
		{
			act("You manage to ignore the smell of $N.", vch, NULL, ch, TO_CHAR);
			affect_strip(ch, gsn_stench);
			continue;
		}

		af.type     	= gsn_stench;
		af.level    	= ch->level;
		af.duration		= 2;
		af.bittype  	= AFFECT_TO_CHAR;
		af.bitvector	= AFF2_SICKENED;
		af.location 	= APPLY_NONE;
		af.modifier 	= 0;
		affect_join( ch, vch, &af);
		
		act( "{128}$N's stench makes you want to wretch!", vch, NULL, ch, TO_CHAR);
		act( "{128}$n fights the urge to wretch!", vch, NULL, NULL, TO_ROOM);
	}
	pop_call();
	return;
}


/* 
 * for aura affects - Kregor
 */
void check_aura(CHAR_DATA *ch, int sn)
{
	CHAR_DATA *vch, *vch_next;
	AFFECT_DATA af;

	push_call("check_aura(%p,%p)",ch,sn);
	
	if (!race_skill(ch, sn))
	{
		pop_call();
		return;
	}
	
	for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
	{
		vch_next	= vch->prev_in_room;
		
		if (who_fighting(vch) != ch)
			continue;

		if (!can_mass_cast(ch, vch, -1))
			continue;
			
		if (is_immune(vch, skill_table[sn].spell_desc))
			continue;
		
		if (will_save(vch, ch, ch->level, sn))
		{
			act("You manage to overcome $N's aura.", vch, NULL, ch, TO_CHAR);
			affect_strip(ch, sn);
			continue;
		}
		
		if (sn == gsn_aura_of_menace)
		{
			af.type     	= sn;
			af.level    	= ch->level;
			af.duration		= 2;
			af.bittype  	= AFFECT_TO_NONE;
			af.bitvector	= AFF_NONE;
			af.location 	= APPLY_INS_AC;
			af.modifier 	= -2;
			affect_join( ch, vch, &af);

			af.location 	= APPLY_MOR_TOHIT;
			af.modifier 	= -2;
			affect_join( ch, vch, &af);
			
			af.location 	= APPLY_MOR_SAVES;
			af.modifier 	= -2;
			affect_join( ch, vch, &af);

			act( "{138}You are repulsed by $N's righteous aura!", vch, NULL, ch, TO_CHAR);
		}
		if (sn == gsn_babble)
		{
			af.type     	= sn;
			af.level    	= ch->level;
			af.duration		= 2;
			af.bittype  	= AFFECT_TO_CHAR;
			af.bitvector	= AFF2_FASCINATED;
			af.location 	= APPLY_NONE;
			af.modifier 	= 0;
			affect_join( ch, vch, &af);

			act( "{138}You are fascinated by $N's endless babble!", vch, NULL, ch, TO_CHAR);
		}
	}
	pop_call();
	return;
}



/*
 * check for the defensive roll ability - Kregor
 */
bool defensive_roll( CHAR_DATA *ch, CHAR_DATA *attacker, int dt, int dam )
{
	push_call("defensive_roll(%p,%p,%p)",ch,attacker,dt,dam);

	if (!IS_AWAKE(ch))
	{
		pop_call();
		return FALSE;
	}
	if (IS_SET(ch->attack, ATTACK_DEF_ROLL)) // only one in a round
	{
		pop_call();
		return FALSE;
	}
	if (ch->hit - dam > 0) // only if attack reduces ch below 0 hp
	{
		pop_call();
		return FALSE;
	}
	if (!learned(ch, gsn_defensive_roll)) //duh!
	{
		pop_call();
		return FALSE;
	}
	if (ch->uses[gsn_defensive_roll]) // one per day
	{
		pop_call();
		return FALSE;
	}
	if (!is_attack(dt)) // has to be a physical attack
	{
		pop_call();
		return FALSE;
	}
	if (!can_dodge(ch, attacker)) // cannot roll if denied DEX bonus
	{
		pop_call();
		return FALSE;
	}
	if (!refl_save(ch, attacker, dam, gsn_defensive_roll)) // REFL save vs damage dealt
	{
		pop_call();
		return FALSE;
	}
	act("{138}$n rolls with the brunt of your blow!", ch, NULL, attacker, TO_VICT);
	act("{138}$n rolls with the brunt of $N's blow!", ch, NULL, attacker, TO_NOTVICT);
	act("{138}you roll with the brunt of $N's blow!", ch, NULL, attacker, TO_CHAR);
	
	SET_BIT(ch->attack, ATTACK_DEF_ROLL);
	ch->uses[gsn_defensive_roll]++;

	pop_call();
	return TRUE;
}

/*
 * Rust monsters, Black Puddings and other corrosive things - Kregor
 */
void corrosive_touch( CHAR_DATA *ch, CHAR_DATA *victim, int level )
{
	OBJ_DATA *obj;
	int cnt, pick;

	push_call("spell_rusting_grasp(%p,%p,%p)",ch,victim,level);

	switch (race_table[get_race(victim)].material)
	{
		case MATERIAL_STEEL:
		case MATERIAL_COLD_IRON:
			damage( ch, victim, dice(3, 6) + UMIN(level, 15), gsn_corrosion, NULL );
			pop_call();
			return;
		default:
			break;
	}
	
	for (cnt = 0, obj = victim->first_carrying ; obj ; obj = obj->next_content)
	{
		if (!IS_WORN(obj))
		{
			continue;
		}
		if (material_table[obj->material].parent != MATERIAL_TYPE_METAL)
		{
			continue;
		}
		if (!IS_OBJ_TYPE(obj, ITEM_ARMOR) && !IS_OBJ_TYPE(obj, ITEM_WEAPON))
		{
			continue;
		}
		if (IS_OBJ_STAT(obj, ITEM_MAGIC|ITEM_BROKEN))
		{
			continue;
		}
		cnt++;
	}
	if (cnt)
	{
		pick = number_range(1,cnt);
		
		for (cnt = 0, obj = victim->first_carrying ; obj ; obj = obj->next_content)
		{
			if (!IS_WORN(obj))
			{
				continue;
			}
			if (material_table[obj->material].parent != MATERIAL_TYPE_METAL)
			{
				continue;
			}
			if (!IS_OBJ_TYPE(obj, ITEM_ARMOR) && !IS_OBJ_TYPE(obj, ITEM_WEAPON))
			{
				continue;
			}
			if (IS_OBJ_STAT(obj, ITEM_MAGIC|ITEM_BROKEN))
			{
				continue;
			}
			if (cnt == pick)
			{
				damage_equipment(ch, victim, obj, dice(1,6) + UMIN(level/2,10), gsn_corrosion, NULL);
				break;
			}
		}
	}
	pop_call();
	return;
}


/*
 * For the SPLIT defense of oozes - Kregor
 */
bool split( CHAR_DATA *ch, int dam_type )
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mh;
	int lev, vnum, hp, hp_max;
	
	push_call("split(%p)",ch);

	if (!IS_NPC(ch))
	{
		pop_call();
		return FALSE;
	}
	
	// because splitting mset npc's will cause unexpected results - Kregor
	if (ch->race != ch->pIndexData->race)
	{
		pop_call();
		return FALSE;
	}

	if (!race_skill(ch, gsn_split))
	{
		pop_call();
		return FALSE;
	}
	
	if (ch->level <= 1)
	{
		pop_call();
		return FALSE;
	}
	
	if (!IS_SET(dam_type, DAM_SLASH|DAM_PIERCE))
	{
		pop_call();
		return FALSE;
	}

	vnum 		= ch->pIndexData->vnum;
	lev  		= ch->level/2;
	hp			= ch->hit/2;
	hp_max 	= ch->max_hit/2;
	
	pMob = get_mob_index( vnum );
	mh = create_mobile( pMob );
	char_to_room( mh, ch->in_room->vnum, TRUE );

	ch->level				= lev;
	ch->hit					= hp;
	ch->max_hit			= hp_max;
	mh->level				= lev;
	mh->hit					= hp;
	mh->max_hit			= hp_max;

	act( "$n splits in two!", ch, NULL, NULL, TO_CHAR);
	act( "$n splits in two!", ch, NULL, NULL, TO_ROOM);
	
	if (who_fighting(ch))
		fight(mh, who_fighting(ch));

	pop_call();
	return TRUE;
}


/*
 * Sever a limb - Kregor
 */
bool sever_limb( CHAR_DATA *ch, CHAR_DATA *victim, lg_int part )
{
	OBJ_DATA *obj;

	push_call("sever_limb(%p,%p)",ch,victim);
	
	switch(part)
	{
		case CAN_WEAR_WRIST:
			if (IS_SEVERED(victim, CAN_WEAR_WRIST))
				part = CAN_WEAR_HANDS;
			break;
		case CAN_WEAR_ANKLE:
			if (IS_SEVERED(victim, CAN_WEAR_ANKLE))
				part = CAN_WEAR_FEET;
			break;
		case CAN_WEAR_FINGER:
			if (IS_SEVERED(victim, CAN_WEAR_FINGER))
				part = CAN_WEAR_HANDS;
			break;
		default:
			act("That part cannot be severed.", ch, NULL, NULL, TO_CHAR);
			pop_call();
			return FALSE;
	}
	SET_BIT(victim->severed, part);
	victim->hit -= victim->hit / 4;

	act("$n viciously severs your $T!", ch, flag_string(part, w_flags), victim, TO_VICT);
	act("$n viciously severs $N's $T!", ch, flag_string(part, w_flags), victim, TO_NOTVICT);
	act("You viciously sever $N's $T!", ch, flag_string(part, w_flags), victim, TO_CHAR);

	// unequip items on severed part(s)
	for (obj = victim->first_carrying ; obj ; obj = obj->next_content)
	{
		if (part == CAN_WEAR_HANDS)
		{
			if (!WEAR_LOC(obj, WEAR_HANDS)
			&& !WEAR_LOC(obj, WEAR_WIELD)
			&& !WEAR_LOC(obj, WEAR_HOLD)
			&& !WEAR_LOC(obj, WEAR_SHIELD)
			&& !WEAR_LOC(obj, WEAR_DUAL_WIELD)
			&& !WEAR_LOC(obj, WEAR_FINGER_L)
			&& !WEAR_LOC(obj, WEAR_FINGER_R)
			&& !WEAR_LOC(obj, WEAR_WRIST_L)
			&& !WEAR_LOC(obj, WEAR_WRIST_R))
				continue;
		}
		if (part == CAN_WEAR_FINGER)
		{
			if (!WEAR_LOC(obj, WEAR_FINGER_R))
				continue;
		}
		if (part == CAN_WEAR_FEET)
		{
			if (!WEAR_LOC(obj, WEAR_FEET)
			&& !WEAR_LOC(obj, WEAR_ANKLE_L)
			&& !WEAR_LOC(obj, WEAR_ANKLE_R))
				continue;
		}
		if (part == CAN_WEAR_ANKLE)
		{
			if (!WEAR_LOC(obj, WEAR_ANKLE_R))
				continue;
		}
		if (part == CAN_WEAR_FEET)
		{
			if (!WEAR_LOC(obj, WEAR_FEET)
			&& !WEAR_LOC(obj, WEAR_ANKLE_L)
			&& !WEAR_LOC(obj, WEAR_ANKLE_R))
				continue;
		}
		if (part == CAN_WEAR_WRIST)
		{
			if (!WEAR_LOC(obj, WEAR_WRIST_R)
			&& !WEAR_LOC(obj, WEAR_FINGER_R)
			&& !WEAR_LOC(obj, WEAR_WIELD)
			&& !WEAR_LOC(obj, WEAR_BOTH_HANDS))
				continue;
		}
			
		unequip_char(victim, obj, TRUE);
		obj_from_char(obj);
		obj_to_room(obj, victim->in_room->vnum);
		act("$p falls onto the ground!", ch, NULL, NULL, TO_ALL);
	}

	pop_call();
	return TRUE;
}

/*
 * Attack roll calculation and check, optional touch and ranged options
 */
bool check_hit( CHAR_DATA *ch, CHAR_DATA *victim, int diceroll, int hit_adj, int dt, OBJ_DATA *wield, bool fTouch, bool fRanged )
{
	int ac = 0;
	int adj = 0;
	bool hit = FALSE;

	push_call("check_hit(%p,%p,%p,%p,%p,%p)",ch,victim,hit_adj,dt,wield,fTouch,fRanged);

	if (dt == gsn_coup_de_grace) // coup de grace is automatic hit
		hit = TRUE;
	else if (diceroll == 1 && !IS_PLR(ch, PLR_HOLYLIGHT)) // 1 always misses
		hit = FALSE;
	else if (number_percent() <= can_miss(ch, victim, dt, fRanged, wield)) // % roll against concealment
		hit = FALSE;
	else if (diceroll == 20) // 20 is automatic hit
	{
		wiz_printf_room(ch, "Perfect 20 roll! diceroll: %d, adj: %d, ac: %d\n\r", diceroll, adj, ac);
		if (!IS_NPC(ch) && !IS_SET(ch->pcdata->spam, SPAM_DICE_ROLLS))
		{
			ch_printf_color(ch, "%sRolled perfect 20! + adjs: %d vs. AC %d\n\r", get_color_string(ch, COLOR_ACCENT, VT102_DIM), adj, ac);
		}
		hit = TRUE;
	}
	else
	{
		ac = calc_ac(victim, ch, fTouch);
	
		adj = GET_HITROLL(ch, victim, dt, wield);
	
		if (fRanged)
		{
			if (wield && ch->in_room)
			{
				if (ch->in_room->area->weather_info->wind_speed >= 9)
				{
					act("The raging winds blow make your ranged attack useless.", ch, NULL, NULL, TO_CHAR);
					pop_call();
					return FALSE;
				}
				else if (ch->in_room->area->weather_info->wind_speed >= 8)
				{
					adj -= 4;
				}
				else if (ch->in_room->area->weather_info->wind_speed >= 7)
				{
					adj -= 2;
				}
			}
			adj -= range_mod(ch, victim, wield);
		}
		
		wiz_printf_room(ch, "Attack Roll(%s): diceroll: %d, adj: %d, mod: %d  vs. ac: %d\n\r", get_name(ch), diceroll, adj, hit_adj, ac);
		if (victim && victim->in_room != ch->in_room)
			wiz_printf_room(victim, "Attack Roll(%s): diceroll: %d, adj: %d, mod: %d  vs. ac: %d\n\r", get_name(ch), diceroll, adj, hit_adj, ac);
		if (!IS_NPC(ch) && !IS_SET(ch->pcdata->spam, SPAM_DICE_ROLLS))
		{
			ch_printf_color(ch, "%sAttack roll: %d + adjs: %d vs. AC %d\n\r", get_color_string(ch, COLOR_ACCENT, VT102_DIM), diceroll, adj, ac);
		}
		diceroll += adj;
		diceroll += hit_adj;
		
		hit = diceroll >= ac;
	}

	// True Strike only good for one hit, so, once it's checked, strip the effect
	if (is_affected(ch, gsn_true_strike))
		affect_strip(ch, gsn_true_strike);	

	pop_call();
	return(hit);
}

/*
 * check for combat maneuvers. Roll of 1 by attacker or failure
 * by 10 or more are both critical failures, and return -2.
 * otherwise, return -1 on failure. Roll of 20, is a critical 
 * success, same as beating the defender roll by 10 or more. - Kregor
 */
int combat_maneuver_check( CHAR_DATA *ch, CHAR_DATA *victim, int sn )
{
	int chroll, victroll, bonus;

	push_call("combat_maneuver_check(%p,%p)",ch,victim);
	
	// 1 = crit fail, 20 = crit success
	if ((chroll = dice(1,20)) == 1)
	{
		pop_call();
		return -2;
	}
	else if (chroll == 20 || IS_HELPLESS(victim))
	{
		pop_call();
		return 10;
	}
	if (sn != gsn_crushing_hand && sn != gsn_grasping_hand && sn != gsn_forceful_hand)
		chroll += combat_maneuver_bonus(ch);
	
	victroll = dice(1,20);
	victroll += combat_maneuver_defense(victim, ch);
	
	/* skill-dependant adjustments */
	if (sn != gsn_grapple)
	{
		if (ch->grappling || ch->grappled_by)
		{
			chroll -= 2;
		}
		if (victim->grappling || victim->grappled_by)
		{
			victroll -= 2;
		}
	}
	if (sn == gsn_trip)
	{
		if (can_trip(victim))
		{
			pop_call();
			return -1;
		}
		if (learned(ch, gsn_improved_trip))
			chroll += 2;
		if (get_monk_style(ch) == STYLE_PASSIVE_WAY && class_level(ch, CLASS_MONK) >= 12)
			chroll += 4;
		if (IS_SET(ch->attack, ATTACK_TRAMPLE)) // mod for Mounted Onslaught feat - Kregor
			chroll -= 5;

		if (!IS_FLYING(victim) && !is_mounting(victim))
		{
			if (learned(victim, gsn_stability))
				victroll += 4;
			if (is_affected(victim, gsn_defensive_stance) && (bonus = multi_class_level(victim, gsn_greater_stability)) > 0)
				victroll += UMIN(stat_bonus(TRUE, ch, APPLY_CON), bonus);
		}
		if (quadruped(victim))
			victroll += 4;
		if (many_legged(victim))
			victroll += 8;
		if (learned(victim, gsn_improved_trip))
			victroll += 2;
		if (get_monk_style(victim) == STYLE_HAND_AND_FOOT && class_level(victim, CLASS_MONK) >= 12)
			victroll += 2;
		victroll += learned(victim, gsn_tumble);
	}
	if (sn == gsn_bullrush)
	{
		if (learned(ch, gsn_imp_bullrush))
			chroll += 2;

		if (!IS_FLYING(victim) && !is_mounting(victim))
		{
			if (learned(victim, gsn_stability))
				victroll += 4;
			if (is_affected(victim, gsn_defensive_stance) && (bonus = multi_class_level(victim, gsn_greater_stability)) > 0)
				victroll += UMIN(stat_bonus(TRUE, ch, APPLY_CON), bonus);
		}
		if (quadruped(victim))
			victroll += 4;
		if (many_legged(victim))
			victroll += 8;
		if (learned(victim, gsn_imp_bullrush))
			victroll += 2;
		if (get_monk_style(victim) == STYLE_HAND_AND_FOOT && class_level(victim, CLASS_MONK) >= 12)
			victroll += 2;
		victroll += synergy_bonus(victim, gsn_tumble);
	}
	if (sn == gsn_grapple)
	{
		if (learned(ch, gsn_imp_grapple))
			chroll += 2;
		if (get_monk_style(ch) == STYLE_DENYING_STANCE && class_level(ch, CLASS_MONK) >= 12)
			chroll += 2;
		chroll += synergy_bonus(ch, gsn_escape_artist);
		if (race_skill(ch, gsn_grab))
			chroll += 4;
	
		victroll = UMAX(victroll, escape_artist_roll(victim));

		if (learned(ch, gsn_imp_grapple))
			victroll += 2;
		if (get_monk_style(victim) == STYLE_DENYING_STANCE && class_level(victim, CLASS_MONK) >= 12)
			victroll += 2;
	}
	if (sn == gsn_grasping_hand || sn == gsn_crushing_hand)
	{
		if (is_affected(victim, sn))
			chroll += get_affect_level(victim, sn) + 11;
		else
			chroll += get_caster_level(ch, sn) + 11;
		if (sn == gsn_crushing_hand)
			chroll += 2;
	
		victroll = UMAX(victroll, escape_artist_roll(victim));

		if (learned(ch, gsn_imp_grapple))
			victroll += 2;
		if (get_monk_style(victim) == STYLE_DENYING_STANCE && class_level(victim, CLASS_MONK) >= 12)
			victroll += 2;
	}
	if (sn == gsn_forceful_hand)
	{
		if (can_trip(victim))
		{
			pop_call();
			return -1;
		}
		if (is_affected(victim, sn))
			chroll += get_affect_level(victim, sn) + 9;
		else
			chroll += get_caster_level(ch, sn) + 9;

		if (!IS_FLYING(victim) && !is_mounting(victim))
		{
			if (learned(victim, gsn_stability))
				victroll += 4;
			if (is_affected(victim, gsn_defensive_stance) && (bonus = multi_class_level(victim, gsn_greater_stability)) > 0)
				victroll += UMIN(stat_bonus(TRUE, ch, APPLY_CON), bonus);
		}
		if (quadruped(victim))
			victroll += 4;
		if (many_legged(victim))
			victroll += 8;
		if (learned(victim, gsn_imp_bullrush))
			victroll += 2;
		if (get_monk_style(victim) == STYLE_HAND_AND_FOOT && class_level(victim, CLASS_MONK) >= 12)
			victroll += 2;
		victroll += synergy_bonus(victim, gsn_tumble);
	}
	if (sn == gsn_disarm)
	{
		OBJ_DATA *chwield, *victwield;

		if ((chwield = get_wield(ch, FALSE)) != NULL)
			chwield = get_wield(ch, TRUE);
	
		if (chwield)
		{
			if (WEAR_LOC(chwield, WEAR_BOTH_HANDS))
				chroll += 4;
			if (WSPEC(chwield, WSPEC_DISARM))
				chroll += 2;
		}
		else
			chroll -= 4;

		if (learned(ch, gsn_imp_disarm))
			chroll += 2;
		if (get_monk_style(ch) == STYLE_DENYING_STANCE && class_level(ch, CLASS_MONK) >= 12)
			chroll += 2;
	
		if ((victwield = get_wield(victim, FALSE)) == NULL)
		{
			if ((victwield = get_wield(victim, TRUE)) == NULL)
			{
				if ((victwield = get_hold(victim)) == NULL)
				{
					bug( "combat_maneuver_check: funtion passed NULL object", 0 );
					pop_call();
					return -1;
				}
			}
		}
		//weapon grandmastery defeats disarm.
		if (IS_SET(weapon_skill(victim, victwield), WSKILL_IMP_CRITICAL) && learned(victim, gsn_weapon_grandmastery))
		{
			pop_call();
			return -1;
		}
		if (victwield && WEAR_LOC(victwield, WEAR_BOTH_HANDS))
			victroll += 4;
		if (IS_SET(weapon_skill(victim, victwield), WSKILL_FOCUS) && learned(victim, gsn_weapon_mastery))
			victroll += (multi_skill_level(ch, gsn_weapon_mastery) / 4) + 1;
		if (learned(victim, gsn_imp_disarm))
			victroll += 2;
	}
	if (sn == gsn_sunder)
	{
		OBJ_DATA *chwield;

		if ((chwield = get_wield(ch, FALSE)) != NULL && WEAR_LOC(chwield, WEAR_BOTH_HANDS))
			chroll += 4;
		else if (!chwield)
			chroll -= 4;
		if (learned(ch, gsn_imp_sunder))
			chroll += 2;
	}
	if (sn == gsn_rescue)
	{
		chroll += synergy_bonus(ch, gsn_tumble);
		if (learned(ch, gsn_mobility))
			chroll += 4;
	}
	if (sn == gsn_tumble)
	{
		victroll = tumble_roll(victim);
		if (learned(victim, gsn_mobility))
			victroll += 4;
	}

	/* the moment of truth */
	if (chroll + 10 < victroll)
	{
		pop_call();
		return -2;
	}
	else if (chroll < victroll)
	{
		pop_call();
		return -1;
	}
	pop_call();
	return (chroll - victroll);
}


/*
 * Taken from the Pathfider RPG System (www.paizo.com)
 * Alternative resolution for all special combat maneuvers
 */
int combat_maneuver_bonus( CHAR_DATA *ch )
{
	int bonus;
	
	push_call("combat_maneuver_bonus(%p)",ch);
	
	bonus = base_attack(ch);
	if (get_size(ch) <= SIZE_TINY || learned(ch, gsn_agile_combatant))
		bonus += stat_bonus(TRUE, ch, APPLY_DEX);
	else
		bonus += stat_bonus(TRUE, ch, APPLY_STR);
	
	if (learned(ch, gsn_mounted_combat))
	{
		if (ch->mounting || quadruped(ch))
		{
			bonus += 3;
		}
	}
	switch (get_size(ch))
	{
		case SIZE_FINE:
			bonus -= 8;
			break;		
		case SIZE_DIMINUTIVE:
			bonus -= 4;
			break;		
		case SIZE_TINY:
			bonus -= 2;
			break;				
		case SIZE_SMALL:
			bonus -= 1;
			break;		
		case SIZE_LARGE:
			bonus += 1;
			break;			
		case SIZE_HUGE:
			bonus += 2;
			break;				
		case SIZE_GARGANTUAN:
			bonus += 4;
			break;		
		case SIZE_COLOSSAL:
			bonus += 8;
			break;		
	}

	switch(drunk_level(ch))
	{
		case DRUNK_SOBER:
			break;
		case DRUNK_TIPSY:
			bonus -= 1;
			break;
		case DRUNK_MERRY:
			bonus -= 2;
			break;
		case DRUNK_DRUNK:
			bonus -= 4;
			break;
		case DRUNK_HAMMERED:
			bonus -= 8;
			break;
		default:
			bonus -= 16;
			break;
	}

	bonus += get_apply(ch, APPLY_COMP_TOHIT);
	bonus += get_apply(ch, APPLY_INS_TOHIT);
	bonus += get_apply(ch, APPLY_LUCK_TOHIT);
	bonus += get_apply(ch, APPLY_MOR_TOHIT);

	if (IS_AFFECTED(ch, AFF2_SICKENED))
		bonus -= 2;
	if (IS_DAZZLED(ch))
		bonus -= 1;
	if (IS_ENTANGLED(ch))
		bonus -= 2;
		
	if (ch->fear_level)
		bonus -= UMIN(ch->fear_level, 3) * 2;

	bonus += get_apply(ch, APPLY_LEVEL);
	
	pop_call();
	return bonus;
}


/*
 * Taken from the Pathfider RPG System (www.paizo.com)
 * Alternative resolution for all special combat maneuvers
 */
int combat_maneuver_defense( CHAR_DATA *ch, CHAR_DATA *attacker )
{
	OBJ_DATA *shield;
	int bonus, deflect;
	
	push_call("combat_maneuver_bonus(%p)",ch);
	
	bonus = base_attack(ch);
	bonus += stat_bonus(TRUE, ch, APPLY_STR);
	deflect = 0;
	
	if (ch->mounting && learned(ch, gsn_mounted_combat))
		bonus += 3;
	
	switch (get_size(ch))
	{
		case SIZE_FINE:
			bonus -= 8;
			break;		
		case SIZE_DIMINUTIVE:
			bonus -= 4;
			break;		
		case SIZE_TINY:
			bonus -= 2;
			break;				
		case SIZE_SMALL:
			bonus -= 1;
			break;		
		case SIZE_LARGE:
			bonus += 1;
			break;			
		case SIZE_HUGE:
			bonus += 2;
			break;				
		case SIZE_GARGANTUAN:
			bonus += 4;
			break;		
		case SIZE_COLOSSAL:
			bonus += 8;
			break;		
	}

	switch(drunk_level(ch))
	{
		case DRUNK_SOBER:
			break;
		case DRUNK_TIPSY:
			bonus -= 1;
			break;
		case DRUNK_MERRY:
			bonus -= 2;
			break;
		case DRUNK_DRUNK:
			bonus -= 4;
			break;
		case DRUNK_HAMMERED:
			bonus -= 8;
			break;
		default:
			bonus -= 16;
			break;
	}
	if (attacker != NULL)
	{
		if (IS_EVIL(attacker))
			deflect = UMAX(deflect, get_apply(ch, APPLY_RES_EVIL));
	
		if (IS_GOOD(attacker))
			deflect = UMAX(deflect, get_apply(ch, APPLY_RES_GOOD));
	
		if (IS_LAWFUL(attacker))
			deflect = UMAX(deflect, get_apply(ch, APPLY_RES_LAW));
	
		if (IS_CHAOTIC(attacker))
			deflect = UMAX(deflect, get_apply(ch, APPLY_RES_CHAOS));
			
		if (!can_see(ch, attacker) && !learned(ch,gsn_blind_fight))
			bonus -= 2;
		
		if (can_dodge(ch, attacker))
		{
			bonus += dodge_bonus(ch);
			if (rspec_req(attacker, RSPEC_GIANT) && learned(ch, gsn_defensive_training))
				bonus += 4;
		}
		else
		{
			bonus += dodge_penalty(ch);
		}
	}
	if ((shield = get_eq_char(ch, WEAR_SHIELD)) != NULL && learned(ch, gsn_shield_ward))
		bonus += shield_bonus(ch);

	if (class_level(ch, CLASS_MONK)
	&& armor_type_worn(ch) == ARMOR_NONE
	&& !shield && !IS_ENCUMBERED(ch))
	{
		bonus += class_level(ch, CLASS_MONK) / 5;
		bonus += stat_bonus(TRUE, ch, APPLY_WIS);
	}

	deflect = UMAX(deflect, race_table[get_race(ch)].deflection);
	deflect = UMAX(deflect, get_apply(ch, APPLY_DEFLECT));
	if (domain_apotheosis(ch, DOMAIN_PROTECTION))
		deflect = stat_bonus(TRUE, ch, APPLY_WIS);
	bonus += deflect;

	bonus += get_apply(ch, APPLY_LEVEL);
	
	pop_call();
	return bonus;
}


/*
 * Hit one guy once.
 * Changed to bool, returns TRUE if a hit is successful - Kregor
 */
bool one_hit(CHAR_DATA *ch, CHAR_DATA *victim, int dt, int hit_adj, OBJ_DATA *wield)
{
	OBJ_DATA *ammo;
	int dam, diceroll, threat;
	bool fRanged = FALSE;
	bool QuiverHit = FALSE;
	bool VorpalHit = FALSE;
	bool fTouch = FALSE;
	bool BackStab = FALSE;

	push_call("one_hit(%p,%p,%p)",ch,victim,dt);

	if (ch == NULL || victim == NULL)
	{
		pop_call();
		return FALSE;
	}

	if (is_safe(ch, NULL))
	{
		pop_call();
		return FALSE;
	}

	ammo = NULL;
	
	if (wield != NULL && is_missile_weapon(wield))
	{
		if ((ammo = get_ammo(ch, wield)) == NULL || !reload(ch, wield))
		{
			pop_call();
			return FALSE;
		}
		ch->reloaded = FALSE;
		fRanged = TRUE;
	}

	// shuriken and chakram, that you can't beat someone with
	if (wield && WSPEC(wield, WSPEC_NOMELEE))
	{
		fRanged = TRUE;
	}
	
	if (!fRanged && !can_melee_attack(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	/*
		Make them a bit tired
	*/
	if (!move_loss(ch, NULL, 1))
	{
		pop_call();
		return FALSE;
	}

	/*
		Figure out the type of damage message.
	*/
	if (dt == TYPE_UNDEFINED || dt == gsn_whirl || dt == gsn_opportunist)
	{
		if (IS_SET(ch->attack, ATTACK_MIRROR))
		{
			pop_call();
			return FALSE;
		}

		if (wield == NULL || (wield->item_type != ITEM_WEAPON && wield->item_type != ITEM_AMMO))
		{
			if ((ch->attack_part = get_body_part(ch, TYPE_HIT, 0)) == -1)
			{
				send_to_char("You have no body parts to attack with!\n\r", ch);
				pop_call();
				return FALSE;
			}
			if (learned(ch, gsn_martial_arts))
			{
				if (dt == gsn_whirl)
					martial_arts_attack = 5;
				else
					martial_arts_attack = number_range(0,11);
			}
			else if (learned(ch, gsn_imp_unarmed_strike))
			{
				if (dt == gsn_whirl)
					brawling_attack = 4;
				else
					brawling_attack = number_range(0, 8);
			}
		}
		if (dt != gsn_opportunist && dt != gsn_coup_de_grace)
		{
			dt = TYPE_HIT;
// 			if (wield != NULL && (wield->item_type == ITEM_WEAPON || wield->item_type == ITEM_AMMO))
// 			{
// 				dt += weapon_table[wield->value[0]].dam_type;
// 			}
		}
	}

	if (is_attack(dt) && !wield && !is_armed(ch, FALSE))
		attack_of_opportunity(victim, ch);

	if (!valid_fight(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	// check for slip and fall in slippery rooms to ruin attack
	if (IS_SET(ch->in_room->room_flags, ROOM_ICE) && !IS_FLYING(ch) && !IS_AFFECTED(ch, AFF_WATER_WALK))
	{
		if (!tumble_check(ch, NULL, tumble_roll(ch), 10))
		{
			if (!refl_save(ch, NULL, 10, -1))
			{
				switch (number_bits(1))
				{
					case 0:
						act( "You slip and fall flat on your back.", ch, NULL, NULL, TO_CHAR);
						act( "$n slips and falls flat on $s back.", ch, NULL, NULL, TO_ROOM);
						break;
					case 1:
						act( "You lose your footing and fall.", ch, NULL, NULL, TO_CHAR);
						act( "$n loses $s footing and falls.", ch, NULL, NULL, TO_ROOM);
						break;
				}
				TAKE_ACTION(ch, ACTION_MOVE);
				update_pos(ch, POS_RESTING);
			}
			else
			{
				act( "You lose your balance, and manage to right yourself.", ch, NULL, NULL, TO_CHAR);
				TAKE_ACTION(ch, ACTION_MOVE);
			}				
			pop_call();
			return FALSE;
		}
	}

	/*
	 * The dice roll, possible critical miss or threat
	 */
	diceroll = dice(1,20);
	CRIT_HIT = FALSE;

	if (wield != NULL)
	{
		threat = weapon_table[wield->value[0]].threat;
	}
	else
	{
		threat = 20;
	}

	if ((wield != NULL && WEAPON_FLAG(wield, WFLAG_KEEN))
	|| (wield != NULL && is_bow(wield) && learned(ch, gsn_keen_arrow)))
	{
		threat = (20 - threat) * 2;
		threat = 20 - threat;
	}
	if (IS_SET(weapon_skill(ch, wield), WSKILL_IMP_CRITICAL))
	{
		threat += 1;
	}
	
	// if touch attack, then use touch AC on check_hit
	if (!wield && ch->attack_part == ATTK_TOUCH)
	{
		fTouch = TRUE;
	}
	
	// crit miss - nothing else happens, just end it here.
	if (diceroll == 1 && !IS_PLR(ch, PLR_HOLYLIGHT))
	{
		ch_printf_color(ch, "{118}Critical miss!\n\r");

		damage(ch, victim, 0, dt, wield);
		if (ammo)
		{
			junk_obj(ammo);
		}
		pop_call();
		return FALSE;
	}
	
	if (number_percent() > get_apply(victim, APPLY_FORTIFICATION))
	{
		if (can_backstab(ch, victim, dt))
			BackStab = TRUE;
		
		if (dt == gsn_coup_de_grace)
		{
			CRIT_HIT = TRUE;
			ch_printf_color(ch, "{118}You score a critical hit!\n\r");
		}
		else if (diceroll == 20 || diceroll >= threat)
		{
			if (check_hit(ch, victim, dice(1,20), hit_adj, dt, wield, fTouch, fRanged)
			|| (wield != NULL && WEAPON_TYPE(wield, WEAPON_TYPE_SLING) && learned(ch, gsn_dead_shot))
			|| (fave_enemy_bonus(ch, victim) && learned(ch, gsn_master_hunter))
			|| (BackStab && learned(ch, gsn_stealth_mastery))
			|| (is_affected(victim, gsn_smite) && get_caster(victim, gsn_smite) == ch && (learned(ch, gsn_holy_champion) || learned(ch, gsn_unholy_champion))))
			{
				CRIT_HIT = TRUE;
				ch_printf_color(ch, "{118}You score a critical threat!\n\r");
			}
		}
	}
	else if (dt == gsn_assassinate || dt == gsn_backstab || dt == gsn_coup_de_grace)
	{
		dt = TYPE_HIT;
	}

	/*
		Calc damage and check for specials
	*/
	dam = GET_DAMROLL(ch, victim, dt, wield);

	if (CRIT_HIT && CAN_CRITICAL(victim) && (!is_affected(victim, gsn_defensive_stance) || !learned(victim, gsn_impenetrable_defense)))
	{
		if (wield != NULL)
		{
			int mult = weapon_table[wield->value[0]].critical;
			
			if (IS_SET(weapon_skill(ch, wield), WSKILL_IMP_CRITICAL) && learned(ch, gsn_weapon_grandmastery))
				mult++;
			if (WEAPON_TYPE(wield, WEAPON_TYPE_SLING) && learned(ch, gsn_between_the_eyes))
				mult++;
			else if (learned(ch, gsn_thrust_home) && (is_light_weapon(ch, wield) || WSPEC(wield, WSPEC_FINESSE)) && get_eq_char(ch, WEAR_SHIELD) == NULL)
				mult++;
				
			dam *= mult;

			if (WEAPON_FLAG(wield, WFLAG_VORPAL) && diceroll == 20) /* vorpal weapon flag - DECAPITATED!! */
			{
				VorpalHit = TRUE;
			}
		}
		else
		{
			// now added Imp Crit to unarmed strikes!!
			if (IS_SET(weapon_skill(ch, wield), WSKILL_IMP_CRITICAL) && learned(ch, gsn_weapon_grandmastery))
				dam *= 3;
			else
				dam *= 2;
			// monk's quivering palm, per mud20 specs - Kregor
			if (learned(ch, gsn_quivering_palm) && !COMBATMODE(ch, COMBAT_NONLETHAL)
			&& multi_class_level(ch, gsn_quivering_palm) >= victim->level)
			{
				QuiverHit = TRUE;
			}
		}
	}

	int bs_dice = 0;
	int bs_dam = 0;
	
	if (BackStab)
	{
		bs_dice = ROUNDUP(multi_skill_level(ch, gsn_backstab) / 2);

		if (COMBATMODE(ch, COMBAT_ARTERIAL))
			bs_dice -= 1;
		if (COMBATMODE(ch, COMBAT_CRIPPLE))
			bs_dice -= 1;
		if (get_monk_style(ch) == STYLE_SLEEPING_TIGER && class_level(ch, CLASS_MONK) >= 12)
			bs_dice++;
		if (bs_dice > 0)
		{
			if (learned(ch, gsn_greater_sneak_attack))
			{
				bs_dam = dice(bs_dice, 8);
			}
			else
			{
				bs_dam = dice(bs_dice, 6);
			}
		}		
		if (dt == gsn_assassinate)
		{
			dam += bs_dam;
		}
		else if (is_flanking(ch, victim))
		{
			if (dt != gsn_coup_de_grace)
			{
				act( "{118}You attack $N from $S flank!", ch, NULL, victim, TO_CHAR);
				act( "$n {118}attacks you from your flank!", ch, NULL, victim, TO_VICT);
				dam += bs_dam;
				dt = gsn_backstab;
			}
		}
		else
		{
			dam += bs_dam;
			if (dt != gsn_coup_de_grace)
			{
				dt = gsn_backstab;
				act( "{118}You attempt a sneak attack on $N!", ch, NULL, victim, TO_CHAR);
				act( "$n {118}attempts a sneak attack on you!", ch, NULL, victim, TO_VICT);
			}
		}
	}

	if (diceroll != 20 && !check_hit(ch, victim, diceroll, hit_adj, dt, wield, fTouch, fRanged))
	{
		damage(ch, victim, 0, dt, wield);
		if (ammo)
		{
			junk_obj(ammo);
		}
		if (is_affected(ch, gsn_impromptu_sneak_attack))
			affect_strip(ch, gsn_impromptu_sneak_attack);

		pop_call();
		return FALSE;
	}
	
	if (is_affected(ch, gsn_impromptu_sneak_attack))
		affect_strip(ch, gsn_impromptu_sneak_attack);

	bool fHit = TRUE;

	if (dam <= 0)
	{
		dam = 1;
	}

	// because ranged doesn't need to consider cleave, 
	// damage shields and other crap - Kregor
	if (fRanged)
	{
		if (is_missile_weapon(wield) && !ammo)
		{
			bug("(one_hit): Missile wield hit with no ammo.", 0);
			act( "{138}Where did your ammo go???", ch, NULL, NULL, TO_CHAR);
			pop_call();
			return FALSE;
		}
		if (WSPEC(wield, WSPEC_NOMELEE))
		{
			if (!deflect_missile(victim, ch, wield, -1))
			{
				damage(ch, victim, dam, dt, wield);
				/* weapon spells on ranged weapon here */
				weapon_cast_spell(wield->value[2], wield->value[3], ch, victim, wield);

				if (WSPEC(wield, WSPEC_RETURNING) || WEAPON_FLAG(wield, WFLAG_RETURNING))
				{
					act("$p returns to your hand.", ch, wield, NULL, TO_CHAR);
					act("$p returns to $n's hand.", ch, wield, NULL, TO_ROOM);
				}
				else
				{
					obj_from_char(wield);
					obj_to_char(wield, victim);
				}
			}
			else
			{
				pop_call();
				return FALSE;
			}
		}
		else if (!deflect_missile(victim, ch, ammo, -1))
		{
			damage(ch, victim, dam, dt, wield);
			/* weapon spells on missile ammo here */
			if (weapon_cast_spell(ammo->value[2], ammo->value[3], ch, victim, ammo))
				ammo->value[2] = ammo->value[3] = 0;
			junk_obj(ammo);
		}
		else
		{
			pop_call();
			return FALSE;
		}
	}
	else
	{
		// check for parry feat
		if (!check_parry(victim, ch, wield, diceroll + hit_adj + GET_HITROLL(ch, victim, dt, wield)))
		{
			damage(ch, victim, dam, QuiverHit ? gsn_quivering_palm : VorpalHit ? gsn_vorpal_hit : dt, wield);

			/* weapon spells on melee weapons here */
			if (wield && valid_fight(ch, victim) && weapon_cast_spell(wield->value[2], wield->value[3], ch, victim, wield))
				wield->value[2] = wield->value[3] = 0;
		}
		else
		{
			fHit = FALSE; // make sure no cleave on this parried attack - Kregor
		}

		// make acidic creatures damage weapons - Kregor
		if (wield)
		{
			if (race_skill(victim, gsn_acid_touch) && race_skill(victim, gsn_corrosion))
			{
				if (IS_OBJ_TYPE(wield, ITEM_WEAPON))
				{
					if (!IS_OBJ_STAT(wield, ITEM_MAGIC) && !refl_save(ch, NULL, victim->level, gsn_acid_touch))
					{
						damage_equipment(victim, ch, wield, dice(1,race_skill(victim, gsn_acid_touch)), gsn_acid_touch, NULL);
					}
				}
			}
		}
		
		/* damage shields kick in here. Only the first to affect ch counts. */
		if (valid_fight(ch, victim) && !has_reach(ch, wield)) // only damage if not using reach weapon.
		{
			int lvl;

			if ((lvl = get_affect_level(victim, gsn_fire_shield)) > 0 && !save_resist(victim, ch, gsn_fire_shield, lvl))
			{
				damage(victim, ch, dice(1,6) + UMIN(lvl,15), gsn_fire_shield, NULL);
			}
			else if ((lvl = get_affect_level(victim, gsn_blade_barrier)) > 0 && !save_resist(victim, ch, gsn_blade_barrier, lvl))
			{
				damage(victim, ch, dice(1,6) + UMIN(lvl,15), gsn_blade_barrier, NULL);
			}
			else if ((lvl = get_affect_level(victim, gsn_death_armor)) > 0 && !save_resist(victim, ch, gsn_death_armor, lvl))
			{
				damage(victim, ch, dice(1,6) + UMIN(lvl,15), gsn_death_armor, NULL);
			}
			else if ((lvl = get_affect_level(victim, gsn_aura_of_retribution)) > 0 && !save_resist(victim, ch, gsn_aura_of_retribution, lvl))
			{
				damage(victim, ch, dice(1,6) + UMIN(lvl,15), gsn_aura_of_retribution, NULL);
			}
			else if ((lvl = get_affect_level(victim, gsn_thorn_body)) > 0 && !save_resist(victim, ch, gsn_thorn_body, lvl))
			{
				damage(victim, ch, dice(1,6) + UMIN(lvl,15), gsn_thorn_body, NULL);
			}
			else if (!wield) // damage touches only affect barehanded attacks
			{
				if ((lvl = race_skill(victim, gsn_barbed_touch)) > 0)
				{
					damage(victim, ch, dice(1,lvl), gsn_barbed_touch, NULL);
				}
				else if ((lvl = race_skill(victim, gsn_fire_touch)) > 0)
				{
					damage(victim, ch, dice(1,lvl), gsn_fire_touch, NULL);
				}
				else if ((lvl = race_skill(victim, gsn_frost_touch)) > 0)
				{
					damage(victim, ch, dice(1,lvl), gsn_frost_touch, NULL);
				}
				else if ((lvl = race_skill(victim, gsn_shock_touch)) > 0)
				{
					damage(victim, ch, dice(1,lvl), gsn_shock_touch, NULL);
				}
				else if ((lvl = race_skill(victim, gsn_acid_touch)) > 0)
				{
					damage(victim, ch, dice(1,lvl), gsn_acid_touch, NULL);
				}
			}
		}

		// grab ability = automatic grapple on a hit
		if (race_skill(ch, gsn_grab) && !wield && valid_fight(ch, victim))
		{
			grab(ch, victim);
			pop_call();
			return TRUE;
		}
		
		/* cleave kicks in here - Kregor */
		
		// but not if damage shields above took him out - Kregor
		if (!valid_fight(ch, victim))
		{
			pop_call();
			return TRUE;
		}
		
		//don't be giving cleaves to whirlwinds, coups, stunning fists, etc - Kregor
		if (dt < TYPE_HIT) 
		{
			pop_call();
			return TRUE;
		}		
		if (!learned(ch, gsn_cleave))
		{
			if (!IS_AFFECTED(ch, AFF2_BERSERK) || !learned(ch, gsn_cloud_of_cleaves))
			{
				pop_call();
				return TRUE;
			}
		}
		if (IS_SET(ch->attack, ATTACK_CLEAVE))
		{
			if (learned(ch, gsn_great_cleave) || (IS_AFFECTED(ch, AFF2_BERSERK) && learned(ch, gsn_cloud_of_cleaves)))
				REMOVE_BIT(ch->attack, ATTACK_CLEAVE);
			pop_call();
			return TRUE;
		}
		if (fHit && COMBATMODE(ch, COMBAT_POWER))
		{
			CHAR_DATA *fch;
			
			if ((fch = get_next_fighting(ch, victim)) == NULL)
			{
				pop_call();
				return TRUE;
			}
			act("{138}You cleave through to another opponent!", ch, NULL, NULL, TO_CHAR);
			act("$n {138}cleaves through to another opponent!", ch, NULL, NULL, TO_ROOM);
			one_hit( ch, fch, dt, hit_adj, wield );
			SET_BIT(ch->attack, ATTACK_CLEAVE);
		}
	}
	pop_call();
	return TRUE;
}


/*
 * Calculate the range of a missile weapon in no. of rooms - Kregor
 */
int get_missile_range( OBJ_DATA *weapon )
{
	int range;
	
	push_call("get_weapon_range(%p)",weapon);
	
	if (weapon == NULL)
	{
		bug ("get_missile_range: no weapon.", 0);
		pop_call();
		return -1;
	}
		
	if ((range = weapon_table[weapon->value[0]].range) <= 0)
	{
		if (WEAPON_FLAG(weapon, WFLAG_THROWING))
		{
			range = 10;
		}
		else
		{
			pop_call();
			return 0;
		}
	}
	
	range = UMAX(1, range / 10);

	if (WEAPON_FLAG(weapon, WFLAG_DISTANCE))
	{
		range *= 2;
	}

	pop_call();
	return range;
}


/*
 * calculate range penalty to hit - Kregor
 */
int range_mod(CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *wield)
{
	int range;

	push_call("range_mod(%p,%p)",ch,victim);
	
	if (ch->in_room == victim->in_room)
	{
		pop_call();
		return 0;
	}
	
	if ((range = get_range(ch, victim)) == -1)
	{
		pop_call();
		return 0;
	}
	
	if (learned(ch, gsn_far_shot))
	{
		if (is_missile_weapon(wield))
			range /= 2;
		else
			range = range * 2 / 3;
	}
	if (wield && (WEAPON_FLAG(wield, WFLAG_DISTANCE) || (is_bow(wield) && learned(ch, gsn_distance_arrow))))
		range /= 2;
	
	pop_call();
	return range;
}


/*
 * Damage a victim
 */
void damage( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, OBJ_DATA *wield )
{
	AFFECT_DATA af;
	bool hit = FALSE;
	int diceroll;

	push_call("damage(%p,%p,%p,%p,%p)",ch,victim,dam,dt,wield);

	// really, there's just no need...
	if (victim->position == POS_DEAD)
	{
		pop_call();
		return;
	}
	
	if (is_affected(victim, gsn_time_stop))
	{
		pop_call();
		return;
	}

	if (dt != TYPE_NOFIGHT)
	{
		if (is_safe(ch, NULL))
		{
			// Disallow damage in shops and safe places.
			if (in_combat(ch))
				clean_combat(ch->in_battle);
			pop_call();
			return;
		}

		user_from_furniture(ch);

		if (victim != ch)
		{
			if (IS_AFFECTED(ch, AFF_HIDE))
			{
				if (wield && is_missile_weapon(wield) && !IS_SET(ch->action, ACTION_STANDARD) && learned(ch, gsn_sniper))
				{
					act( "You take a single shot from your concealment.", ch, NULL, NULL, TO_CHAR );
				}
				else
				{
					AFFECT_STRIP(ch, AFF_HIDE);
					act( "$n steps out from $s hiding spot.",   ch, NULL, NULL, TO_ROOM );
					act( "You step out from your hiding spot.", ch, NULL, NULL, TO_CHAR );
				}
			}

			if (IS_AFFECTED(ch, AFF_INVISIBLE))
			{
				affect_strip(ch, gsn_invis);
				REMOVE_BIT(ch->affected_by, AFF_INVISIBLE);
			}

			if (IS_AFFECTED(ch, AFF_SANCTUARY) && is_attack(dt))
			{
				AFFECT_STRIP(ch, AFF_SANCTUARY);
			}
			
			if (IS_AFFECTED(victim, AFF2_CHARMED) && is_attack(dt))
			{
				if (is_affected(victim, gsn_charm_monster) && get_caster(victim, gsn_charm_monster) == ch)
						affect_strip(victim, gsn_charm_monster);
				if (is_affected(victim, gsn_charm_person) && get_caster(victim, gsn_charm_person) == ch)
						affect_strip(victim, gsn_charm_person);
				if (is_affected(victim, gsn_charm_plant) && get_caster(victim, gsn_charm_plant) == ch)
						affect_strip(victim, gsn_charm_plant);
				if (is_affected(victim, gsn_charm_animal) && get_caster(victim, gsn_charm_animal) == ch)
						affect_strip(victim, gsn_charm_animal);
			}

			if (IS_AFFECTED(victim, AFF_DOMINATE) && is_attack(dt))
			{
				if (is_affected(victim, gsn_dominate_monster) && get_caster(victim, gsn_dominate_monster) == ch)
						affect_strip(victim, gsn_dominate_monster);
				if (is_affected(victim, gsn_dominate_person) && get_caster(victim, gsn_dominate_person) == ch)
						affect_strip(victim, gsn_dominate_person);
				if (is_affected(victim, gsn_dominate_animal) && get_caster(victim, gsn_dominate_animal) == ch)
						affect_strip(victim, gsn_dominate_animal);
			}

			if (!in_combat(ch))
			{
				fight(ch,victim);
			}
			
			// strip out bluffs and feints
			affect_strip(victim, gsn_bluff);
			victim->distracted = 0;

			// Nope, you just got a mirror image!
			if (has_mirror(ch, victim, dt))
			{
				pop_call();
				return;
			}
			victim->last_attacker = ch;
		}
	}

	/*
	 * Set recently fought info.
	 */
	if (IS_NPC(victim) && !IS_NPC(ch) && !confused && dam > 0 && dt != TYPE_NOFIGHT)
	{
		if (ch->leader && !IS_NPC(ch->leader))
		{
			victim->npcdata->pvnum_last_hit = ch->leader->pcdata->pvnum;
		}
		else
		{
			victim->npcdata->pvnum_last_hit = ch->pcdata->pvnum;
		}
	}

	if (dam && !IS_NPC(ch) && IS_NPC(victim) && !confused && ch != victim && dt != TYPE_NOFIGHT)
	{
		if (ch->level > 1 && victim->npcdata->hate_fear != ch->pcdata->pvnum)
		{
			victim->npcdata->hate_fear = ch->pcdata->pvnum;
		}
	}

	/*
	 * Weapon flags support - Kregor 7/13/07
	 * damage that is subject to reduction and only 
	 * triggers on successful hit.
	 */
	if (dam > 0)
	{
		/*
		 * remember real hit result, because it matters after damage reductions - Kregor
		 */
		hit = TRUE;

		if (wield)
		{
			// concat weapon flags from missile weapons onto ammo
			if (IS_WEAPON(wield) && is_missile_weapon(wield))
			{
				OBJ_DATA *ammo;
				
				if ((ammo = get_ammo(ch, wield)) == NULL)
				{
					bug("damage: missile weapon returned NULL ammo!", 0);
					pop_call();
					return;
				}
				if (wield->value[1])
				{
					SET_BIT(ammo->value[1], wield->value[1]);
				}
				wield = ammo;
			}
			
			if (WEAPON_FLAG(wield, WFLAG_ANARCHIC))
			{
				if (IS_LAWFUL(victim))
				{
					dam += dice(2, 6);
				}
			}
			if (WEAPON_FLAG(wield, WFLAG_AXIOMATIC))
			{
				if (IS_CHAOTIC(victim))
				{
					dam += dice(2, 6);
				}
			}
			if (WEAPON_FLAG(wield, WFLAG_BANE))
			{
				if (race_table[victim->race].type == wield->value[2])
				{
					if (wield->value[3] > 0 && IS_SET(race_table[victim->race].flags, wield->value[3]))
					{
						dam += dice(2, 6);
					}
				}
			}
			if (WEAPON_FLAG(wield, WFLAG_HOLY))
			{
				if (IS_EVIL(victim))
				{
					dam += dice(2, 6);
				}
			}
			if (WEAPON_FLAG(wield, WFLAG_MERCIFUL))
			{
				dam += dice(1, 6);
			}
			if (WEAPON_FLAG(wield, WFLAG_UNHOLY))
			{
				if (IS_GOOD(victim))
				{
					dam += dice(2, 6);
				}
			}
		}
		if (IS_SET(weapon_skill(ch, wield), WSKILL_PWR_CRITICAL) && IS_SET(ch->attack, ATTACK_MELEE) && COMBATMODE(ch, COMBAT_POWER))
		{
			if (CRIT_HIT && CAN_CRITICAL(victim) && (!is_affected(victim, gsn_defensive_stance) || !learned(victim, gsn_impenetrable_defense)))
			{
				if (wield)
					dam += dice(weapon_table[wield->value[0]].critical - 1, 6);
				else
					dam += dice(1,6);
			}
		}
	}
		
	// modify the physical damage before adding further effects.
	dam = damage_modify(ch, victim, dt, dam, wield);
	
	/* 
	 * elemental damage, drains and touch attacks do
	 * damage whether the physical hit is resisted or not - Kregor
	 * each element and affect gets modified individually
	 * before concating back onto physical damage.
	 */
	if (hit)
	{
		if (wield)
		{
			if (WEAPON_FLAG(wield, WFLAG_DISRUPTION))
			{
				if (IS_UNDEAD(victim) && !will_save(victim, NULL, actual_tohit_bonus(wield) * 2 + 10, -1))
				{
					dam += victim->hit + 10;
				}
			}
			if (WEAPON_FLAG(wield, WFLAG_FLAMING))
			{
				dam += damage_modify(ch, victim, gsn_fire_hit, dice(1, 6), wield);
			}
			if (WEAPON_FLAG(wield, WFLAG_FLAMING_BURST))
			{
				dam += damage_modify(ch, victim, gsn_fire_hit, dice(CRIT_HIT ? weapon_table[wield->value[0]].critical : 1, 6), wield);
			}
			if (WEAPON_FLAG(wield, WFLAG_FROST))
			{
				dam += damage_modify(ch, victim, gsn_frost_hit, dice(1, 6), wield);
			}
			if (WEAPON_FLAG(wield, WFLAG_ICY_BURST))
			{
				dam += damage_modify(ch, victim, gsn_frost_hit, dice(CRIT_HIT ? weapon_table[wield->value[0]].critical : 1, 6), wield);
			}
			if (WEAPON_FLAG(wield, WFLAG_SHOCK))
			{
				dam += damage_modify(ch, victim, gsn_shock_hit, dice(1, 6), wield);
			}
			if (WEAPON_FLAG(wield, WFLAG_SHOCK_BURST))
			{
				dam += damage_modify(ch, victim, gsn_shock_hit, dice(CRIT_HIT ? weapon_table[wield->value[0]].critical : 1, 6), wield);
			}
			if (WEAPON_FLAG(wield, WFLAG_VICIOUS))
			{
				dam += damage_modify(ch, victim, gsn_sonic_blast, dice(1, 6), wield);
			}
			if (WEAPON_FLAG(wield, WFLAG_CAUSTIC))
			{
				dam += damage_modify(ch, victim, gsn_acid_hit, dice(1, 6), wield);
			}
		}
		else if (is_attack(dt))
		{	
			int sizedie = 0;
			
			if (ch->attack_part == ATTK_TOUCH)
			{
				wiz_printf_room(ch, "damage: incorporeal touch hit!!\n\r");
			}
	
			if (race_skill(ch, gsn_corrosion))
			{
				corrosive_touch(ch, victim, ch->level);
			}

			if ((sizedie = race_skill(ch, gsn_barbed_touch)) > 0)
			{
				dam += damage_modify(ch, victim, gsn_barbed_touch, dice(1, sizedie), NULL);
			}
			if ((sizedie = race_skill(ch, gsn_fire_touch)) > 0)
			{
				dam += damage_modify(ch, victim, gsn_fire_touch, dice(1, sizedie), NULL);
			}
			if ((sizedie = race_skill(ch, gsn_frost_touch)) > 0)
			{
				dam += damage_modify(ch, victim, gsn_frost_touch, dice(1, sizedie), NULL);
			}
			if ((sizedie = race_skill(ch, gsn_shock_touch)) > 0)
			{
				dam += damage_modify(ch, victim, gsn_shock_touch, dice(1, sizedie), NULL);
			}
			if ((sizedie = race_skill(ch, gsn_acid_touch)) > 0)
			{
				dam += damage_modify(ch, victim, gsn_acid_touch, dice(1, sizedie), NULL);
			}
			if ((sizedie = race_skill(ch, gsn_divine_touch)) > 0)
			{
				dam += damage_modify(ch, victim, gsn_divine_touch, dice(1, sizedie), NULL);
			}
			if ((sizedie = race_skill(ch, gsn_negative_energy_touch)) > 0)
			{
				dam += damage_modify(ch, victim, gsn_negative_energy_touch, ch->level / 2 + dice(sizedie, 8), NULL);
			}
			if (race_skill(ch, gsn_drain))
				level_drain(ch, victim);
			if (race_skill(ch, gsn_cha_drain))
				stat_damage(ch, victim, APPLY_CHA_DRAIN, gsn_cha_drain);
			if (race_skill(ch, gsn_con_drain))
				stat_damage(ch, victim, APPLY_CON_DRAIN, gsn_con_drain);
			if (race_skill(ch, gsn_dex_drain))
				stat_damage(ch, victim, APPLY_DEX_DRAIN, gsn_dex_drain);
			if (race_skill(ch, gsn_int_drain))
				stat_damage(ch, victim, APPLY_INT_DRAIN, gsn_int_drain);
			if (race_skill(ch, gsn_str_drain))
				stat_damage(ch, victim, APPLY_STR_DRAIN, gsn_str_drain);
			if (race_skill(ch, gsn_wis_drain))
				stat_damage(ch, victim, APPLY_WIS_DRAIN, gsn_wis_drain);
			if (race_skill(ch, gsn_paralysis_touch))
			{
				if (!save_resist(ch, victim, gsn_paralysis_touch, ch->level))
				{
					af.type      = gsn_paralysis_touch;
					af.duration  = dice(1, race_skill(ch, gsn_paralysis_touch));
					af.bitvector = AFF2_PARALYSIS;
					af.modifier  = 0;
					af.location  = APPLY_NONE;	
					af.bittype   = AFFECT_TO_CHAR;
					affect_join( ch, victim, &af );
					
					act( "$t$N's touch leaves you paralyzed!", victim, get_color_string(victim, COLOR_YOU_ARE_HIT, VT102_BOLD), ch, TO_VICT);
					act( "{118}$n is paralyzed!", victim, NULL, NULL, TO_ROOM);
				}
			}
		}
	}
	
	dam_message(ch, victim, (hit && IS_INCORPOREAL(ch) && !dam) ? -1 : dam, dt, wield);
	damage_hurt(ch, victim, dam, dt);
	
	if (hit && victim != ch && is_attack(dt) && victim->position > POS_DEAD) // if victim is dead, none of this matters.
	{
		if (dam > 0) // these only work if actual physical damage happens
		{
			if (wield != NULL && wield->poison != NULL && dam > 0)
			{
				if (IS_NPC(ch) || in_area(ch, ROOM_VNUM_ARENA))
				{
					wield->poison->poisoner = -1;
				}
				else
				{
					wield->poison->poisoner = ch->pcdata->pvnum;
				}
				obj_affect_poison(wield, victim);
			}
	
			if (CAN_CRITICAL(victim))
			{
				if (get_apply(victim, APPLY_REGENERATION) <= 0) // regenerating creatures do not take bleed damage
				{
					int bleed;
	
					if ((bleed = learned(ch, gsn_bleed_damage)) > 0)
					{
						af.type      = gsn_bleed_damage;
						af.duration  = -1;
						af.modifier  = dice(1,bleed);
						af.location  = APPLY_NONE;
						af.bittype   = AFFECT_TO_CHAR;
						af.bitvector = AFF2_BLEEDING;
						if (!IS_NPC(ch))
						{
							victim->critical_hit_by = ch->pcdata->pvnum;
						}
						else
						{
							victim->critical_hit_by = 0;
						}
						affect_join( ch, victim, &af );
					}
					if ((dt == gsn_backstab && wield != NULL && learned(ch, gsn_arterial_strike) && COMBATMODE(ch, COMBAT_ARTERIAL))
					|| (wield != NULL && WEAPON_FLAG(wield, WFLAG_WOUNDING)))
					{
						af.type      = gsn_bleed_damage;
						af.duration  = -1;
						af.modifier  = 1;
						af.location  = APPLY_NONE;
						af.bittype   = AFFECT_TO_CHAR;
						af.bitvector = AFF2_BLEEDING;
						if (!IS_NPC(ch))
						{
							victim->critical_hit_by = ch->pcdata->pvnum;
						}
						else
						{
							victim->critical_hit_by = 0;
						}
						affect_join( ch, victim, &af );
					}
					if (race_skill(ch, gsn_wounding_attack))
					{
						// horned devil only gets the tail
						if (ch->race != RACE_CORNUGON || ch->attack_part == ATTK_TAIL)
						{
							af.type			 = gsn_festering_wounds;
							af.duration  = -1;
							af.bittype   = AFFECT_TO_CHAR;
							af.bitvector = AFF_CURSE;
							af.location  = APPLY_NONE;
							af.modifier  = 0;
							affect_join( ch, victim, &af );
					
							act( "{118}The wound begins to fester!", victim, NULL, NULL, TO_CHAR );
							act( "{118}$n's wound festers and bleeds!", victim, NULL, NULL, TO_ROOM );
						}
					}
				}
				if (dt == gsn_backstab && learned(ch, gsn_cripple) && COMBATMODE(ch, COMBAT_CRIPPLE))
				{
					if (!fort_save(victim, ch, dam, -1))
					{
						af.type      = gsn_cripple;
						af.duration  = -1;
						af.modifier  = -2;
						af.location  = APPLY_STR_DAMAGE;	
						af.bittype   = AFFECT_TO_NONE;
						af.bitvector = AFF_NONE;
						affect_join( ch, victim, &af );
						
						act( "$tYour crippling blow weakens $N", ch, get_color_string(ch, COLOR_YOU_HIT, VT102_BOLD), victim, TO_CHAR);
						act( "$t$n's crippling blow weakens you.", ch, get_color_string(victim, COLOR_YOU_ARE_HIT, VT102_BOLD), victim, TO_CHAR);
					}
				}
			}
			if (!wield && is_attack(dt))
			{
				/* natural poison attack */
				if (race_table[ch->race].poison) // shapechange does not grant poison
				{
					if (ch->attack_part == race_table[ch->race].poison_part) // must be hit w/ the right part
					{
						poison_attack(ch, victim, race_table[ch->race].poison);
					}
				}
				if (race_table[ch->race].disease) // shapechange does not grant disease
				{
					if (ch->attack_part == race_table[ch->race].disease_part) // must be hit w/ the right part
					{
						disease_attack(ch, victim, race_table[ch->race].disease);
					}
				}
				/* stat damage only happens along w physical dmg */
				if (race_skill(ch, gsn_cha_damage))
					stat_damage(ch, victim, APPLY_CHA_DAMAGE, gsn_cha_damage);
				if (race_skill(ch, gsn_con_damage))
					stat_damage(ch, victim, APPLY_CON_DAMAGE, gsn_con_damage);
				if (race_skill(ch, gsn_dex_damage))
					stat_damage(ch, victim, APPLY_DEX_DAMAGE, gsn_dex_damage);
				if (race_skill(ch, gsn_int_damage))
					stat_damage(ch, victim, APPLY_INT_DAMAGE, gsn_int_damage);
				if (race_skill(ch, gsn_str_damage))
					stat_damage(ch, victim, APPLY_STR_DAMAGE, gsn_str_damage);
				if (race_skill(ch, gsn_wis_damage))
					stat_damage(ch, victim, APPLY_WIS_DAMAGE, gsn_wis_damage);
			}
			if (is_mounting(victim))
			{
				int roll = mount_roll(victim);
				if (learned(victim, gsn_mounted_combat))
					roll += 3;
				if (!mount_check(victim, victim->mounting, roll, 5 + dam))
				{
					act( "You fall off of $N.",  victim, NULL, victim->mounting, TO_CHAR);
					act( "$n falls off of you.", victim, NULL, victim->mounting, TO_VICT);
					act( "$n falls off of $N.",  victim, NULL, victim->mounting, TO_NOTVICT);
					if (!mount_check(victim, victim->mounting, roll, 15))
						damage(victim, victim, dice(1,6), TYPE_NOFIGHT, NULL);
					victim->mounting = NULL;
				}
			}
		}
	}

	if (dam > 0 && dt != TYPE_NOFIGHT)
	{
		if (wield && WEAPON_FLAG(wield, WFLAG_VAMPIRIC))
		{
			int heal = UMIN(dam, wield->value[2]);
			ch->hit = UMIN( ch->hit + heal, get_max_hit(ch));
			ch->nonlethal = UMAX(0, ch->nonlethal - heal);
			update_pos(ch,-1);
			act( "You feel a chill as $N's life force heals you.", ch, NULL, victim, TO_CHAR);
			act( "$n's wounds seem to heal themselves.", ch, NULL, victim, TO_ROOM);
		}	
		if (victim->position == POS_SLEEPING)
		{
			if (!IS_AFFECTED(victim, AFF_SLEEP))
			{
				update_pos(victim, POS_RESTING);
			}
		}
	}
	
	if (valid_fight(ch, victim))
	{
		if (dam > 0 && victim->casting)
		{
			if (dt == TYPE_NOFIGHT)
				dam /= 2;
				
			diceroll = concentration_roll(victim);
			if (class_ability(ch, gsn_warmage))
				diceroll += 4;
	
			if (!concentration_check(victim, ch, diceroll, 10 + dam + get_spell_circle(NULL, victim->cast_sn)))
			{
				act( "{138}You lost your concentration!", victim, NULL, NULL, TO_CHAR);
				act( "$n stops casting.", victim, NULL, NULL, TO_ROOM);
				if (victim->cast_sn == gsn_recite_scroll && victim->reciting)
					junk_obj(victim->reciting);
				free_cast(victim);
			}
		}
		if (dam > 0 && victim->concentrating)
		{
			if (dt == TYPE_NOFIGHT)
				dam /= 2;
				
			diceroll = concentration_roll(victim);
	
			if (!concentration_check(victim, ch, diceroll, 10 + dam))
			{
				act( "{138}You lost your concentration!", victim, NULL, NULL, TO_CHAR);
				act( "$n loses $s concentration.", victim, NULL, NULL, TO_ROOM);
				free_skill(victim);
			}
		}
	}

	pop_call();
	return;
}


/*
 * Scandum 4-6-2003
 * Heavily modified by Kregor 2006
 */
int damage_modify( CHAR_DATA *ch, CHAR_DATA *victim, int dt, int dam, OBJ_DATA *wield )
{
	int dam_type = DAM_BASH;

	push_call("damage_modify(%p,%p,%p,%p)",ch,victim,dt,dam,wield);

	// incorporeals pass 1 point dmg to here just to treat it as a hit - Kregor
	if (dam <= 0 || (!wield && is_attack(dt) && IS_INCORPOREAL(ch)))
	{
		pop_call();
		return 0;
	}

	if (dt == TYPE_NOFIGHT)
	{
		pop_call();
		return dam;
	}

	if (wield != NULL && (wield->item_type == ITEM_WEAPON || wield->item_type == ITEM_AMMO))
	{
		dam_type = weapon_table[wield->value[0]].dam_type;
	}
	else if (is_attack(dt))
	{
		if (learned(ch, gsn_martial_arts))
		{
			dam_type = martial_arts_table[martial_arts_attack].dam_type;
		}
		else if (learned(ch, gsn_imp_unarmed_strike))
		{
			dam_type = brawling_table[brawling_attack].dam_type;
		}
		else if (ch->attack_part != -1)
		{
			dam_type = attack_part_table[ch->attack_part].dam_type;
		}
		else if ((dam_type = skill_table[dt].dam_type) == DAM_NONE)
		{
			dam_type = DAM_BASH;
		}
	}
	else
	{
		if (valid_skill(dt))
		{
			dam_type = skill_table[dt].dam_type;
			if (is_spell(dt) && IS_SET(ch->cast_feats, METAMAGIC_MERCIFUL)
			&& !IS_SET(skill_table[dt].spell_desc, SDESC_DEATH))
			{
				SET_BIT(dam_type, DAM_NONLETHAL);
			}
		}
		else if (dt >= TYPE_HIT)
		{
			bug("dam_modify: Do we even use this anymore?", 0);
		}
		else
		{
			if (dt != TYPE_UNDEFINED)
			{
				bug("damage_modify: bad dt %d.", dt);
			}
		}
	}
	if (!is_spell(dt) && (dam_type == DAM_NONE || dam_type == DAM_NONLETHAL))
	{
		bug("damage_modify: no dam_type %d.", dt);
		send_to_char("Something went wrong with the damage... contact an immortal!\n\r", ch);
	}

	if (dam <= 0)
	{
		dam = 1;
	}

	/*
	 * Here's where ALL the physical damage types
	 * get concatenated for damage reduction purposes
	 * Kregor 7/25/07
	 */
	if (is_attack(dt))
	{
		if (dt == gsn_shield_bash)
		{
			wield = get_eq_char(ch, WEAR_SHIELD);
		}
		if (COMBATMODE(ch, COMBAT_NONLETHAL)
		&& dt != gsn_assassinate && dt != gsn_backstab)
		{
			SET_BIT(dam_type, DAM_NONLETHAL);
		}
		if (wield != NULL)
		{
			if (WSPEC(wield, WSPEC_NONLETHAL))
			{
				SET_BIT(dam_type, DAM_NONLETHAL);
			}
			if (material_table[wield->material].parent == MATERIAL_TYPE_METAL && domain_apotheosis(ch, DOMAIN_METAL))
			{
				SET_BIT(dam_type, DAM_ADAMANTINE|DAM_IRON|DAM_SILVER);
			}
			if (WEAPON_FLAG(wield, WFLAG_KI_FOCUS))
			{
				if (learned(ch, gsn_ki_strike_magic))
				{
					SET_BIT(dam_type, DAM_MAGICAL);
				}
				if (learned(ch, gsn_ki_strike_lawful))
				{
					SET_BIT(dam_type, DAM_LAWFUL);
				}
				if (learned(ch, gsn_ki_strike_adamant))
				{
					SET_BIT(dam_type, DAM_ADAMANTINE);
				}
			}
			if (WEAPON_FLAG(wield, WFLAG_MERCIFUL))
			{
				SET_BIT(dam_type, DAM_NONLETHAL);
			}
			if (IS_OBJ_STAT(wield, ITEM_MAGIC) || (is_bow(wield) && learned(ch, gsn_enhance_arrow)))
			{
				SET_BIT(dam_type, DAM_MAGICAL);
			}
			if (IS_OBJ_EVIL(wield) || rspec_req(ch, RSPEC_EVIL) || learned(ch, gsn_aura_of_blasphemy) || actual_tohit_bonus(wield) >= 5)
			{
				SET_BIT(dam_type, DAM_EVIL);
			}
			if (IS_OBJ_GOOD(wield) || rspec_req(ch, RSPEC_GOOD) || learned(ch, gsn_aura_of_faith) || actual_tohit_bonus(wield) >= 5)
			{
				SET_BIT(dam_type, DAM_GOOD);
			}
			if (IS_OBJ_CHAOTIC(wield) || rspec_req(ch, RSPEC_CHAOTIC) || actual_tohit_bonus(wield) >= 5)
			{
				SET_BIT(dam_type, DAM_CHAOTIC);
			}
			if (IS_OBJ_LAWFUL(wield) || rspec_req(ch, RSPEC_LAWFUL) || actual_tohit_bonus(wield) >= 5)
			{
				SET_BIT(dam_type, DAM_LAWFUL);
			}
			if (wield->material == MATERIAL_COLD_IRON || actual_tohit_bonus(wield) >= 3)
			{
				SET_BIT(dam_type, DAM_IRON);
			}
			if (wield->material == MATERIAL_MITHRAL || wield->material == MATERIAL_SILVER || actual_tohit_bonus(wield) >= 3)
			{
				SET_BIT(dam_type, DAM_SILVER);
			}
			if (wield->material == MATERIAL_ADAMANTINE || actual_tohit_bonus(wield) >= 4)
			{
				SET_BIT(dam_type, DAM_ADAMANTINE);
			}
		}
		else
		{
			if (!COMBATMODE(ch, COMBAT_NONLETHAL) && IS_SET(dam_type, DAM_NONLETHAL))
			{
				if (has_natural_weapon(ch) || is_armed(ch, FALSE))
				{
					REMOVE_BIT(dam_type, DAM_NONLETHAL);
				}
			}
			if (race_table[get_race(ch)].apply[APPLY_DR_MAGIC]
			|| learned(ch, gsn_ki_strike_magic))
			{
				SET_BIT(dam_type, DAM_MAGICAL);
			}
			if (rspec_req(ch, RSPEC_EVIL) || learned(ch, gsn_aura_of_blasphemy) || (IS_EVIL(ch) && learned(ch, gsn_align_ki)))
			{
				SET_BIT(dam_type, DAM_EVIL);
			}
			if (rspec_req(ch, RSPEC_GOOD) || learned(ch, gsn_aura_of_faith) || (IS_GOOD(ch) && learned(ch, gsn_align_ki)))
			{
				SET_BIT(dam_type, DAM_GOOD);
			}
			if (rspec_req(ch, RSPEC_CHAOTIC))
			{
				SET_BIT(dam_type, DAM_CHAOTIC);
			}
			if (rspec_req(ch, RSPEC_LAWFUL) || learned(ch, gsn_ki_strike_lawful))
			{
				SET_BIT(dam_type, DAM_LAWFUL);
			}
			if (learned(ch, gsn_ki_strike_adamant))
			{
				SET_BIT(dam_type, DAM_ADAMANTINE);
			}
		}
	}
		
	/* incorporeal creatures can only be hit by
	 * magical effects and weapons, and only 50% damage,
	 * or 100% with the ghost touch weapon flag - Kregor 7/23/07
	 */
	if (IS_INCORPOREAL(victim) && !IS_INCORPOREAL(ch) && dt != TYPE_NOFIGHT)
	{
		if (!wield)
		{
			if (is_attack(dt) && !IS_SET(dam_type, DAM_MAGICAL))
			{
				dam = 0;
			}
			if (!is_spell(dt))
			{
				dam = 0;
			}
			else
			{
				dam /= 2;
			}
		}
		else
		{
			if (!WEAPON_FLAG(wield, WFLAG_GHOST_TOUCH))
			{
				if (!IS_SET(dam_type, DAM_MAGICAL))
				{
					dam = 0;
				}
				else
				{
					dam /= 2;
				}
			}
		}
	}
	
	if (dam > 0 && IS_AREA_SPELL(dt))
	{
		dam = dam * 3 / 2;
	}

	if (dam_type == DAM_NONE)
	{
		pop_call();
		return dam;
	}
	
	if (is_spell(dt))
	{
		wiz_printf("dam_type %s", flag_string(dam_type, dtype_flags));
		wiz_printf("spell_desc %s", flag_string(skill_table[dt].spell_desc, sdesc_flags));
	}
	else
		wiz_printf("dam_type %s", flag_string(dam_type, dtype_flags));

	if (is_immune(victim, skill_table[dt].spell_desc))
	{
		dam = 0;
	}
	else
	{
		if (IS_SET(dam_type, DAM_PHYSICAL) && (!is_affected(victim, gsn_smite) || get_caster(victim, gsn_smite) != ch))
			dam -= dam_reduction(ch, victim, dam, dam_type);
	
		/* ablative immunity first, followed by resistance, followed by innate immunity */
		if (IS_SET(dam_type, DAM_ENERGY))
		{
			if ((dam = energy_immunity(victim, dam, dam_type)) > 0)
			{
				dam -= energy_resistance(victim, dam, dam_type);
			}
		}
		if (dam < 0)
		{
			dam = 0;
		}
		if (dam > 0 && is_vulnerable(ch, victim, dam_type))
		{
			dam = dam * 3 / 2;
		}
	}

	DAM_TYPE = dam_type;
	
	pop_call();
	return dam;
}


/*
 * hurt the victim and inform him of new state, award exp
 */
void damage_hurt( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt )
{
	char buf[MAX_INPUT_LENGTH];

	push_call("damage_hurt(%p,%p,%p,%p)",ch,victim,dam,dt);
	
	dam = UMIN(dam, victim->hit + 10);

	/* insta-kill attacks cannot be nonlethal */
	if (dt == gsn_coup_de_grace || dt == gsn_assassinate || dt == gsn_vorpal_hit || dt == gsn_quivering_palm)
		REMOVE_BIT(DAM_TYPE, DAM_NONLETHAL);
		
	if (IS_SET(DAM_TYPE, DAM_NONLETHAL))
	{
		if (race_type(victim) != RTYPE_CONSTRUCT && race_type(victim) != RTYPE_UNDEAD && !IS_GOD(victim))
			victim->nonlethal = UMIN(victim->nonlethal + dam, get_max_hit(victim) + 10);
	}
	else if (!split(victim, DAM_TYPE)) // should check for split, else do actual dmg - Kregor
	{
		if (dt == gsn_vorpal_hit /* vorpal weapon flag - DECAPITATED!! - Kregor */
		|| (CRIT_HIT && IS_SET(DAM_TYPE, DAM_SLASH) && ch->race == RACE_BALOR)) // any slashing weapon balor wields is vorpal
		{
			act( "$n's slash severs your head!!", ch, NULL, victim, TO_VICT);
			act( "$n's slash severs $N's head!!", ch, NULL, victim, TO_NOTVICT);
			act( "Your slash severs $N's head!!", ch, NULL, victim, TO_CHAR);
			dam = victim->hit + 10;
		}
		else if (dt == gsn_quivering_palm && !is_immune(victim, SDESC_DEATH)) /* quivering palm - save or die! - Kregor */
		{
			if (!will_save(victim, ch, multi_class_level(ch, gsn_quivering_palm) / 2 + stat_bonus(TRUE, ch, APPLY_WIS) + 10, -1))
			{
				act( "{118}Your body starts to quiver and spasm, then... blackness!", victim, NULL, NULL, TO_CHAR);
				act( "{118}$n starts to quiver and spasm, then collapses!", victim, NULL, NULL, TO_ROOM);
				dam = victim->hit + 10;
			}
		}
		// vorpal and quivering palm trump regen - Kregor
		else if (get_apply(victim, APPLY_REGENERATION) <= 0 || IS_SET(DAM_TYPE, DAM_ACID|DAM_FIRE) || is_vulnerable(ch, victim, DAM_TYPE))
		{
			if (dt == gsn_coup_de_grace)
			{
				if (!fort_save(victim, ch, 10 + dam, -1))
				{
					act( "{118}$n ends your life with a single strike!", ch, NULL, victim, TO_VICT);
					act( "{118}$n ends $N's life with a single strike!", ch, NULL, victim, TO_NOTVICT);
					act( "{128}You end $N's life with a single strike!", ch, NULL, victim, TO_CHAR);
					dam = victim->hit + 10;
				}
			}
			else if (dt == gsn_assassinate) /* assasination - instant stun - Kregor */
			{
				if (!fort_save(victim, ch, 10 + multi_skill_level(ch, gsn_assassinate) + stat_bonus(TRUE, ch, APPLY_INT), -1))
				{
					dam = victim->hit;
					if (learned(ch, gsn_true_death))
					{
						dam += 11;
					}
				}
			}
			else if (dam > UMAX(50, get_max_hit(victim) / 2) && CAN_CRITICAL(victim)) /* Pathfinder RPG massive damage rule */
			{
				if (!fort_save(victim, ch, 15, -1))
				{
					act( "{118}You succumb to massive damage!", ch, NULL, victim, TO_VICT);
					act( "{128}$N succumbs to massive damage!", ch, NULL, victim, TO_CHAR);
					act( "{118}$N succumbs to massive damage!", ch, NULL, victim, TO_NOTVICT);
					dam = victim->hit + 1;
				}
				else
				{
					send_to_char( "{018}***That really did HURT!***{300}\n\r", victim);
				}
			}
		}
		//defensive roll here!
		if (defensive_roll(victim, ch, dt, dam))
			dam /= 2;

		victim->hit -= dam;
	}
	
	if (!IS_NPC(victim) && (victim->level >= LEVEL_IMMORTAL || NEW_AUTH(victim) || victim->in_room->vnum == ROOM_VNUM_LIMBO) && victim->hit < 1)
	{
		victim->hit = 1;
	}
	
	if (victim->hit < 0 && get_apply(victim, APPLY_REGENERATION) > 0 && !IS_SET(DAM_TYPE, DAM_ACID|DAM_FIRE) && !is_vulnerable(ch, victim, DAM_TYPE))
	{
		victim->hit = 0;
	}
	
	// domain/race abilities to restore hit points at mortal wounding - Kregor
	if (victim->hit < 0 && victim->hit > -10)
	{
		if (domain_skill(victim, gsn_divine_renewal) && !victim->uses[gsn_divine_renewal])
		{
			if ((victim->hit += 8 + UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, victim, APPLY_WIS))) >= 0)
			{
				act("{138}You feel a surge of divine renewal!", victim, NULL, NULL, TO_CHAR);
				act("{138}$n beams with divine renewal!", victim, NULL, NULL, TO_CHAR);
				victim->uses[gsn_divine_renewal]++;
			}
		}
		else if (race_skill(victim, gsn_ferocity) && !victim->uses[gsn_ferocity])
		{
			act("{118}You keep going, in spite of grievous wounds!", victim, NULL, NULL, TO_CHAR);
			act("{118}$n presses on in spite of grievous wounds!", victim, NULL, NULL, TO_CHAR);
		}
	}
	
	update_pos(victim,-1);
	
	if (victim->position == POS_MORTAL)
	{
		if (!IS_NPC(ch))
		{
			victim->critical_hit_by = ch->pcdata->pvnum;
		}
		else
		{
			victim->critical_hit_by = 0;
		}
	}

	if (dt == gsn_vorpal_hit) /* Here goes the head! */
	{
		if (!collect_bounty(ch, victim))
		{
			OBJ_DATA *obj;
			char *name;
	
			name            = IS_NPC(ch) ? victim->short_descr : victim->name;
			obj             = create_object( get_obj_index( OBJ_VNUM_SEVERED_HEAD ), 0 );
		
			sprintf(buf, obj->short_descr, name);
			RESTRING(obj->short_descr, buf);
	
			sprintf(buf, obj->long_descr, name);
			RESTRING(obj->long_descr, buf);
	
			obj_to_room(obj, ch->in_room->vnum);
			act ("$p plops to the ground.", ch, obj, victim, TO_CHAR);
			act ("$p plops to the ground.", ch, obj, victim, TO_ROOM);
		}
		else
		{
			ch->pcdata->bounties++;
		}
	}

	if (victim->position > POS_STUNNED && dam > 0)
	{
		if (dt == gsn_stunning_fist)
		{
			int dc = (ch->level / 2) + 10 + stat_bonus(TRUE, ch, APPLY_WIS);
			
			if (CAN_CRITICAL(victim) && !fort_save(victim, ch, dc, -1))
			{
				AFFECT_DATA af;
	
				af.type      = gsn_stunning_fist;
				af.location  = APPLY_NONE;
				af.modifier  = 0;
				af.level     = ch->level;
				af.duration  = 1;
				af.bittype   = AFFECT_TO_CHAR;
				af.bitvector = AFF2_STUNNED;
				affect_join( ch, victim, &af );
				
				act( "$tYour punch sends $N reeling!", ch, get_color_string(ch, COLOR_YOU_HIT, VT102_BOLD), victim, TO_CHAR);
				act( "$t$n's punch sends $N reeling!", ch, get_color_string(ch, COLOR_TEXT, VT102_BOLD), victim, TO_NOTVICT);
				act( "$t$n's punch sends you reeling!", ch, get_color_string(ch, COLOR_YOU_ARE_HIT, VT102_BOLD), victim, TO_VICT);
			}
			update_pos(victim,-1);
		}
		if (dt == gsn_shield_bash && learned(ch, gsn_shield_slam))
		{
			if (CAN_CRITICAL(victim) && !fort_save(victim, ch, 10 + dam, -1))
			{
				AFFECT_DATA af;
	
				af.type      = gsn_shield_slam;
				af.location  = APPLY_NONE;
				af.modifier  = 0;
				af.level     = ch->level;
				af.duration  = 1;
				af.bittype   = AFFECT_TO_CHAR;
				af.bitvector = AFF2_DAZED;
				affect_join( ch, victim, &af );
				
				act( "$tYour shield bash sends $N reeling!", ch, get_color_string(ch, COLOR_YOU_HIT, VT102_BOLD), victim, TO_CHAR);
				act( "$t$n's shield bash sends $N reeling!", ch, get_color_string(ch, COLOR_TEXT, VT102_BOLD), victim, TO_NOTVICT);
				act( "$t$n's shield bash sends you reeling!", ch, get_color_string(ch, COLOR_YOU_ARE_HIT, VT102_BOLD), victim, TO_VICT);
			}
			update_pos(victim,-1);
		}
		if (victim->position > POS_STUNNED)
			show_char_to_char( victim, NULL, FALSE );
	}

	switch (victim->position)
	{
		case POS_MORTAL:
			act( "$n is mortally wounded, and will die soon, if not aided.", victim, NULL, NULL, TO_ROOM);
			send_to_char( "You are mortally wounded, and will die soon, if not aided.\n\r", victim);
			break;
		case POS_INCAP:
			act( "$n is incapacitated, but stable.", victim, NULL, NULL, TO_ROOM );
			send_to_char("You are incapacitated, but stable.\n\r",victim );
			break;
		case POS_STUNNED:
			act( "$n is stunned, but will probably recover.",victim, NULL, NULL, TO_ROOM );
			send_to_char("You are stunned, but will probably recover.\n\r", victim );
			break;
		case POS_DEAD:
			if (in_combat(victim))
			{
				if (IS_NPC(ch) && ch->master)
				{
					victim->last_attacker = ch->master;
				}
				else
				{
					victim->last_attacker = ch;
				}
			}
			mprog_death_trigger(ch, victim);
			rprog_death_trigger(ch, victim);
			mprog_kill_trigger(ch, victim);
			rprog_kill_trigger(ch, victim);
			if (IS_NPC(victim) && dt != gsn_death_throes && race_skill(victim, gsn_death_throes)) // added going out with a blast!
			{
				act("{118}$n is consumed in a blast of flames!!", victim, NULL, NULL, TO_ROOM);
				spell_damage(victim, ch, victim->level*5, gsn_death_throes, victim->level);
			}
			else
			{
				act( "$n is DEAD!!", victim, NULL, NULL, TO_ROOM );
				send_to_char_color( "{138}You have been KILLED!!\n\r\n\r", victim );
			}
			break;
		default:
			break;
	}

	/*
	 * Sleep spells and extremely wounded folks.
	 */
	if (!IS_AWAKE(victim) || ch == victim)
	{
		if (dt != TYPE_NOFIGHT)
		{
			stop_hate_fear(victim);
		}
	}
	else if (!IS_NPC(victim) && is_attack(dt))
	{
		oprog_hit_trigger(victim);
	}
	else if (IS_NPC(victim))
	{
		mprog_hit_trigger(victim, ch);
	}

	if (!IS_NPC(ch) && IS_AWAKE(ch) && ch != victim)
	{
		if (is_attack(dt))
		{
			oprog_damage_trigger(ch);
		}
	}
	
	/*
	 * Payoff for killing things.
	 */
	if (victim->position == POS_DEAD)
	{
		if (!IS_NPC(victim))
		{
			if (!IS_NPC(ch))
			{
				if (ch != victim)
				{
					spam_attack_list(victim);
					if (in_area(victim, ROOM_VNUM_ARENA))
					{
						add_to_victory_list( ch, victim );
					}
					else if (dt != gsn_vorpal_hit && collect_bounty(ch, victim))
					{
						ch->pcdata->bounties++;
					}
				}
			}
			else
			{
				victim->pcdata->mdeaths++;

				if (victim->pcdata->clan != NULL)
				{
					victim->pcdata->clan->mdeaths++;
					save_clan( victim->pcdata->clan );
				}
			}
		}

		if (IS_NPC(victim) && !IS_NPC(ch))
		{
			ch->pcdata->mkills++;

			if (ch->pcdata->clan != NULL)
			{
				ch->pcdata->clan->mkills++;
			}
			ch->pcdata->murder_grudge[victim->pIndexData->vnum]++;
			
			if ((IS_CITIZEN(victim) || IS_GUARD(victim)) && OPPOSITE_ALIGN(ch, victim) < 75)
			{
				gain_reputation(ch, -3);
			}
			if (IS_CITIZEN(victim) || IS_GUARD(victim))
			{
				set_bounty(victim, ch, CRIME_LOW_MURDER);
			}
		}

		if (!IS_NPC(victim))
		{
			log_printf("%s killed by %s at %u", victim->name, get_name( ch ),  victim->in_room->vnum );

			save_char_obj(victim, BACKUP_SAVE);

			if (!PERM_DEATH) // disabled perm death means xp & level loss at the time of death.
			{
				if (IS_NPC(ch))
				{
					int exp_loss = victim->pcdata->exp - exp_level(victim, victim->level - 1);
	
					if (exp_loss > 0)
					{
						gain_exp(victim, 0 - exp_loss / 2);
					}
					if (victim->level > 1)
						lose_level(victim, TRUE);
				}
			}

			if (!in_area(victim, ROOM_VNUM_ARENA))
			{
				// killer and thief flags only go away if killed by PC who isn't one himself.
				if (!IS_PLR(ch, PLR_KILLER|PLR_THIEF)) 
				{
					if (IS_SET(victim->act, PLR_KILLER))
					{
						REMOVE_BIT(victim->act, PLR_KILLER);
					}
					if (IS_SET(victim->act, PLR_THIEF))
					{
						REMOVE_BIT(victim->act, PLR_THIEF);
					}
				}
			}
		}
		else
		{
			group_gain( ch, victim );
		}

		if (ch == victim)
		{
			if (ch->position == POS_DEAD)
			{
				if (IS_NPC(ch))
				{
					log_printf("[%u] %s just killed itself using damage type %d.", ch->pIndexData->vnum, ch->short_descr, dt);
				}
				else
				{
					log_printf("%s just killed itself using damage type %d.", get_name(ch), dt);
				}
				raw_kill(ch, dt);
			}
			pop_call();
			return;
		}

		if (!confused)
			set_fighting(victim, ch);

		if (!IS_NPC(ch) && !IS_NPC(victim) && in_area(ch, ROOM_VNUM_ARENA))
		{
			PLAYER_GAME *gpl;

			for (gpl = mud->f_player ; gpl ; gpl = gpl->next )
			{
				if (gpl->ch != ch && gpl->ch != victim)
				{
					ch_printf( gpl->ch, "Announcers exclaim throughout the city, %s'%s has defeated %s in the arena!'\n\r", get_color_string(gpl->ch, COLOR_SPEECH, VT102_BOLD), ch->name, victim->name );
				}
			}
			ch->pcdata->akills++;
		}

		raw_kill( victim, dt );
		
		if (!IS_NPC(victim) && !IS_NPC(ch))
		{
			OBJ_DATA *corpse;
			
			if ((corpse = victim->pcdata->corpse) != NULL)
			{
				corpse->value[5] = ch->pcdata->pvnum; //marks the killer of PC for single-item loot.
			}
		}

		if (ch->desc && CH(ch->desc)->pcdata->vt100 == 1)
		{
			vt100prompt( ch );
		}
		pop_call();
		return;
	}
	else if (!IS_AWAKE(victim)) // jail or sever if disabled - Kregor
	{
		if (collect_bounty(ch, victim))
		{
			ch->pcdata->bounties++;
		}
	}

	if (ch->desc)
	{
		if (CH(ch->desc)->pcdata->vt100 == 1)
		{
			vt100prompt( ch );
		}
	}
	if (victim->desc)
	{
		if (CH(victim->desc)->pcdata->vt100 == 1)
		{
			vt100prompt( victim );
		}
	}
	pop_call();
	return;
}

bool has_mirror(CHAR_DATA *ch, CHAR_DATA *victim, int dt)
{
	AFFECT_DATA *paf;
	char message[MAX_INPUT_LENGTH];
	const char *attack;
	bool all;

	push_call("has_mirror(%p,%p)",ch,victim);

	attack = NULL;
	all    = FALSE;

	if (IS_AFFECTED(ch, AFF_TRUESIGHT))
	{
		pop_call();
		return FALSE;
	}

	if (!is_affected(victim, gsn_mirror_image))
	{
		pop_call();
		return FALSE;
	}

	if (dt == TYPE_NOFIGHT)
	{
		pop_call();
		return FALSE;
	}

	SET_BIT(ch->attack, ATTACK_MIRROR);

	for (paf = victim->first_affect ; paf ; paf = paf->next)
	{
		if (paf->type == gsn_mirror_image)
		{
			if (number_range(0, paf->modifier))
			{
				paf->modifier -= 1;

				if (paf->modifier <= 0)
				{
					all = TRUE;
					affect_strip(victim, paf->type);
				}
			}
			else
			{
				act( "You discover the real $N.", ch, NULL, short_to_name(PERS(victim,ch), 1), TO_CHAR);
				pop_call();
				return FALSE;
			}
			break;
		}
	}
	attack = get_dam_nounce(ch, victim, dt, NULL);

	if (attack[0] != '\0')
	{
		sprintf(message, "Your %s destroys $N in one blow!", attack);
		act( message, ch, NULL, victim, TO_CHAR);
		sprintf(message, "$n's %s destroys $N in one blow!", attack);
		act( message, ch, NULL, victim, TO_NOTVICT);
		act( "One of your images is dispelled!", ch, NULL, victim, TO_VICT);
	}
	else
	{
		act( "You destroy $N in one blow!", ch, NULL, victim, TO_CHAR);
		act( "$n destroys $N in one blow!", ch, NULL, victim, TO_NOTVICT);
		act( "One of your images is dispelled!", ch, NULL, victim, TO_VICT);
	}

	if (all)
	{
		act( "You discover the real $T.", ch, NULL, short_to_name(PERS(victim,ch), 1), TO_CHAR    );
		act( "All your images are gone!",    ch, NULL, victim, TO_VICT    );
		act( "All $N's images have vanished.",    ch, NULL, victim, TO_NOTVICT );
	}
	pop_call();
	return TRUE;
}


/*
 * Make a corpse out of a character.
 * Added dt for effects that leave corpse or prevent raising on corpse - Kregor
 */
void make_corpse( CHAR_DATA *ch, int dt )
{
	char buf[MAX_INPUT_LENGTH];
	OBJ_DATA *corpse;
	OBJ_DATA *obj;
	OBJ_DATA *obj_next;
	int size;

	push_call("make_corpse(%p)",ch);

	if (IS_UNDEAD(ch) || IS_ACT(ch, ACT_NOCORPSE) || (valid_skill(dt) && IS_SET(skill_table[dt].flags, SF_NOCORPSE)))
	{
		for (obj = ch->first_carrying ; obj ; obj = obj_next)
		{
			obj_next = obj->next_content;

			if (IS_SET(obj->extra_flags, ITEM_INVENTORY))
			{
				if (IS_NPC(ch))
					junk_obj(obj);
			}
			else
			{
				obj_to_room( obj, ch->in_room->vnum );
			}
		}
		pop_call();
		return;
	}
	
	size = UMAX(0, ch->size - 2);

	if (IS_NPC(ch))
	{
		corpse            = create_object(get_obj_index(OBJ_VNUM_CORPSE_NPC), 0);
		corpse->timer     = 4;
		corpse->level     = ch->level;
		corpse->owned_by  = 0;
		corpse->value[4]	= ch->pIndexData->vnum;
		corpse->value[5]	= size * size;
		corpse->value[6]	= size;
		corpse->weight		= ch->weight;
		corpse->size			= ch->size;

		if (IS_ACT(ch, ACT_PET) && ch->master != NULL && ch->master->pcdata != NULL )
		{
			corpse->owned_by = ch->master->pcdata->pvnum;
		}
		if (ch->gold > 0)
		{
			obj_to_obj(create_money(ch->gold), corpse);
			ch->gold = 0;
		}
		RESTRING(corpse->description, ch->description);
	}
	else
	{
		corpse = create_object(get_obj_index(OBJ_VNUM_CORPSE_PC), 0);
		corpse->timer = 60;

		if (ch->pcdata->corpse == NULL)
		{
			ch->pcdata->corpse = corpse;
			ch->pcdata->corpse_room	= ch->in_room->vnum;
		}
		corpse->owned_by = ch->pcdata->pvnum;
		RESTRING(corpse->description, ch->description);
	
		corpse->value[4] = ch->pcdata->pvnum;
		corpse->weight = ch->weight;
		corpse->size = ch->size;
		
		if (is_spell(dt) && IS_SET(skill_table[dt].spell_desc, SDESC_DEATH))
			SET_BIT(corpse->extra_flags, ITEM_NO_RAISE);
	}

	sprintf(buf, "corpse %s %s", IS_NPC(ch) ? "npc_corpse" : "pc_corpse", short_to_name(get_name(ch), 1));
	RESTRING(corpse->name, buf);

	sprintf(buf, "the corpse of %s", adjective(ch));
	RESTRING(corpse->short_descr, buf);

	sprintf(buf, "The corpse of %s is lying here.", adjective(ch));
	RESTRING(corpse->long_descr, buf);

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

		// sorry, but shopkeepers' inventory gets purged - Kregor
		if (is_keeper(ch) && obj->reset && obj->reset->command == 'G')
		{
			junk_obj(obj);
			continue;
		}
		if (IS_NPC(ch))
		{
			obj_to_obj( obj, corpse );
			continue;
		}
		// nodrop items will stay with dead character - Kregor
		if (!IS_SET(obj->extra_flags, ITEM_INVENTORY) && !IS_SET(obj->extra_flags, ITEM_NODROP))
		{
			obj_to_obj( obj, corpse );
		}
	}

	if (ch->gold > 0)
	{
		obj_to_obj(create_money(ch->gold), corpse);
		ch->gold = 0;
	}
	
	obj_to_room(corpse, ch->in_room->vnum);
	
	if (valid_skill(dt) && IS_SET(skill_table[dt].spell_desc, SDESC_DEATH))
		SET_BIT(corpse->extra_flags, ITEM_NO_RAISE);

	if (!IS_NPC(ch))
	{
		ch->pcdata->time_of_death						= mud->current_time;
		ch->pcdata->just_died_ctr						= 10;
		ch->pcdata->condition[COND_FULL]		= max_hunger(ch);
		ch->pcdata->condition[COND_THIRST]	= max_thirst(ch);
		ch->pcdata->condition[COND_DRUNK]		= 0;
		ch->pcdata->condition[COND_AIR]			= max_air(ch);
		if (PERM_DEATH)
			ch_printf_color(ch, "You feel yourself leaving your body as everything goes black...\n\r");
		else
			ch_printf_color(ch, "The gods have retreived your soul from oblivion.\n\r");
	}
	pop_call();
	return;
}

/*
 * Kills a character, for whatever reason.
 */
void raw_kill( CHAR_DATA *victim, int dt )
{
	push_call("raw_kill(%p)",victim);

	if (victim == supermob)
	{
		log_printf("The SuperMob is immortal, he cannot die!!");
		pop_call();
		return;
	}
	if (IS_NPC(victim))
	{
		if (IS_SET(victim->act, ACT_WILL_DIE))
		{
			pop_call();
			return;
		}
		SET_BIT(victim->act, ACT_WILL_DIE);
	}

	if (victim->furniture)
	{
		user_from_furniture(victim);
	}

	if (victim->hitched)
	{
		user_from_cart(victim);
	}

	if (victim->poison)
	{
		POISON_DATA *pd;

		while ((pd = victim->poison) != NULL)
		{
			victim->poison = victim->poison->next;
			FREEMEM( pd );
		}
	}

	while (victim->first_disease)
	{
		disease_from_char(victim, victim->first_disease);
	}

	while (victim->first_affect)
	{
		affect_from_char(victim, victim->first_affect);
	}
	victim->affected_by		= 0;
	victim->affected2_by	= 0;

	if (victim->tracked_by)
		stop_tracking(victim->tracked_by);

	if (victim->grappling)
	{
		stop_grapple(victim->grappled_by);
	}
	
	if (victim->grappled_by)
	{
		stop_grapple(victim->grappled_by);
	}
		
	if (!IS_NPC(victim))
	{
		if (victim->pcdata->shadowing)
		{
			stop_shadow(victim);
		}

		if (victim->pcdata->tracking)
		{
			stop_tracking(victim);
		}

		if (victim->pcdata->shadowed_by)
		{
			stop_shadow(victim->pcdata->shadowed_by);
		}
		
		if (in_area(victim, ROOM_VNUM_ARENA))
		{
			arena_death(victim);
		}
		else if (in_area(victim, ROOM_VNUM_SCHOOL))
		{
			newbie_death(victim);
		}
		else
		{
			player_death(victim, dt);
		}
		pop_call();
		return;
	}

	make_corpse(victim, dt);
	stop_fighting(victim, TRUE);

	if (IS_SET(victim->act, ACT_PET) && victim->master)
	{
		send_to_char("Your pet dies a horrible death.\n\r", victim->master);
	}

	/* Familiar death, costs 200 exp per level, save for half */
	if (IS_ACT(victim, ACT_FAMILIAR|ACT_WARHORSE) && victim->master)
	{
		int exp_loss = victim->level * 200;

		if (fort_save(victim->master, NULL, 10 + victim->level, -1))
			exp_loss /= 2;

		if (exp_loss > 0)
		{
			gain_exp(victim, 0 - exp_loss);
			if (IS_ACT(victim, ACT_FAMILIAR))
				act( "You suffer from the death of your familiar!", victim->master, NULL, NULL, TO_CHAR);
			if (IS_ACT(victim, ACT_WARHORSE))
				act( "You suffer from the death of your mount!", victim->master, NULL, NULL, TO_CHAR);
			act( "$n writhes in pain and looks drained!", victim->master, NULL, NULL, TO_ROOM);
		}
	}

	junk_mob(victim);

	pop_call();
	return;
}


/*
 * Gutted the death cry, no more chunks and gibs - Kregor
 */
void death_cry( CHAR_DATA *ch )
{
	EXIT_DATA *pExit;
	char *msg;
	int door, temp_vnum;
	bool cry = FALSE;

	push_call("death_cry(%p)",ch);

	if (IS_UNDEAD(ch))
	{
		msg = "$n turns to dust.";
	}
	else if (IS_ACT(ch, ACT_NOCORPSE))
	{
		msg = "$n vanishes into thin air.";
	}
	else
	{
		msg  = "$n lets out a death cry.";
		cry = TRUE;
	}

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

	if (IS_NPC(ch) && !CAN_TALK(ch))
	{
		msg = "You hear something's death cry.";
	}
	else
	{
		msg = "You hear someone's death cry.";
	}

	if (cry && !in_area(ch, ROOM_VNUM_ARENA))
	{
		temp_vnum = ch->in_room->vnum;
	
		for (door = 0 ; door <= 5 ; door++)
		{
			if ((pExit = get_exit(temp_vnum, door)) != NULL)
			{
				ch->in_room = room_index[pExit->to_room];
				act( msg, ch, NULL, NULL, TO_ROOM );
			}
		}
		ch->in_room = room_index[temp_vnum];
	}
	pop_call();
	return;
}


/*
 * Newbies do not perm death, because we're nice - Kregor.
 */
void newbie_death( CHAR_DATA *victim )
{
	push_call("arena_death(%p)",victim);

	victim->position 		= POS_RESTING;
	victim->hit      		= UMAX( 1, victim->hit  );
	destroy_mana( victim );
	victim->move     		= UMAX( 1, victim->move );

	char_from_room(victim);
	char_to_room(victim, ROOM_VNUM_SCHOOL, TRUE);

	char_reset(victim);

	pop_call();
	return;
}

/*
 * Defeat in arena is not lethal. Sends back
 * to PCs death room.
 */
void arena_death( CHAR_DATA *victim )
{
	push_call("arena_death(%p)",victim);

	victim->position 		= POS_RESTING;
	victim->hit      		= UMAX( 1, victim->hit  );
	destroy_mana( victim );
	victim->move     		= UMAX( 1, victim->move );

	char_from_room(victim);
	char_to_room(victim, ROOM_VNUM_TEMPLE, TRUE);

	char_reset(victim);

	pop_call();
	return;
}

/*
 * Very lethal death. Depending on perm death option,
 * character is either stuck on fugue plane, or respawned
 * with level loss back to a safe room - Kregor
 */
void player_death( CHAR_DATA *victim, int dt )
{
	OBJ_DATA *obj, *obj_next;

	push_call("player_death(%p)",victim);

	if (victim->pcdata->death_room == ROOM_VNUM_SCHOOL)
	{
		if (!in_area(victim, ROOM_VNUM_SCHOOL))
		{
			victim->pcdata->death_room = ROOM_VNUM_TEMPLE;
		}
	}

	make_corpse(victim, dt);

	for (obj = victim->first_carrying ; obj ; obj = obj_next)
	{
		obj_next = obj->next_content;
		if (!IS_SET(obj->extra_flags, ITEM_INVENTORY))
		{
			junk_obj( obj );
		}
	}

	char_from_room(victim);

	if (PERM_DEATH)
	{
		SET_BIT(victim->act, PLR_DEAD);
		char_to_room(victim, ROOM_VNUM_DEATH, TRUE);
		victim->pcdata->recall = ROOM_VNUM_TEMPLE;
	}
	else
	{
		if (victim->level < 2)
		{
			char_to_room(victim, ROOM_VNUM_SCHOOL, TRUE);
		}
		else
		{
			char_to_room(victim, victim->pcdata->death_room, TRUE);
		}
		victim->pcdata->recall = victim->in_room->vnum;
	}

	victim->position 		= POS_RESTING;
	victim->hit      		= UMAX( 1, victim->hit  );
	destroy_mana( victim );
	victim->move     		= UMAX( 1, victim->move );

	char_reset(victim);

	save_char_obj(victim, NORMAL_SAVE);
	do_look(victim, "");

	pop_call();
	return;
}


/*
 * Make the spam string for an attack, base verb
 * on percent HP damaged - Kregor
 */
void dam_message( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, OBJ_DATA *wield )
{
	CHAR_DATA *fch;
	PLAYER_GAME *fpl;
	char buf1[MAX_INPUT_LENGTH];
	char buf2[MAX_INPUT_LENGTH];
	char buf3[MAX_INPUT_LENGTH];
	char youHit[41], hitYou[41];
	const char *vp;
	const char *attack;
	char punct;
	int percent;
	int diceroll = 0;

	push_call("dam_message(%p,%p,%d,%d,%d)",ch,victim,dam,dt,wield);

	if (dt == TYPE_NOFIGHT || dam == -1)
	{
		pop_call();
		return;
	}

	if (ch == NULL) /* crash prevention */
		ch = victim;
		
	percent = 100 * dam / UMAX(1, get_max_hit(victim));

	attack = NULL;

	if ( dam == 0 )
	{
		if ( dt == gsn_acid_hit || dt == gsn_fire_hit || dt == gsn_frost_hit || dt == gsn_shock_hit )
		{
			vp = "is resisted by";
		}
		else
		{
			vp = "misses";
		}
	}
	else if ( dt == gsn_acid_hit )
	{
		vp = "eats away at";
	}
	else if ( dt == gsn_fire_hit )
	{
		vp = "burns";
	}
	else if ( dt == gsn_frost_hit )
	{
		vp = "chills";
	}
	else if ( dt == gsn_shock_hit )
	{
		vp = "shocks";
	}
	else if ( percent <= 5 )
	{
		vp = "barely touches";
	}
	else if ( percent <= 10 )
	{
		vp = "scratches";
	}
	else if ( percent <= 15 )
	{
		vp = "grazes";
	}
	else if ( percent <= 20 )
	{
		vp = "hits";
	}
	else if ( percent <= 30 )
	{
		vp = "solidly hits";
	}
	else if ( percent <= 40 )
	{
		vp = "hurts";
	}
	else if ( percent <= 50 )
	{
		vp = "MUTILATES";
	}
	else if ( percent <= 60 )
	{
		vp = "*EVISCERATES*";
	}
	else if ( percent <= 70 )
	{
		vp = "**MASSACRES**";
	}
	else if ( percent <= 80 )
	{
		vp = "***DEMOLISHES***";
	}
	else if ( percent <= 90 )
	{
		vp = "****ANNIHILATES****";
	}
	else
	{
		vp = "*****OBLITERATES*****";
	}

	punct = (percent <= 20) ? '.' : '!';

	strcpy(hitYou, (dam <= 0) ? "" : get_color_code(victim, COLOR_YOU_ARE_HIT, VT102_BOLD));
	if (ch != victim)
		strcpy(youHit, (dam <= 0) ? "" : get_color_code(ch, COLOR_YOU_HIT, VT102_BOLD));
	else
		strcpy(hitYou, (dam <= 0) ? "" : get_color_code(victim, COLOR_YOU_ARE_HIT, VT102_BOLD));
	
	if (dt == TYPE_HIT)
	{
		attack = get_dam_nounce(ch, victim, dt, wield);

		if (attack[0] != '\0')
		{
			sprintf(buf1, "%s %s", attack, vp);

			if (dam > 0)
			{
				sprintf(buf2, "%sYour %s %s $N for %dhp%c",  youHit, attack, vp, dam, punct);
			}
			else
			{
				sprintf(buf2, "%sYour %s %s $N%c",  youHit, attack, vp, punct);
			}
			if (dam > 0)
			{
				sprintf(buf3, "%s$n's %s %s you for %dhp%c", hitYou, attack, vp, dam, punct);
			}
			else
			{
				sprintf(buf3, "%s$n's %s %s you%c", hitYou, attack, vp, punct);
			}
		}
		else
		{
			sprintf(buf1, "attack %s", vp);

			if (dam > 0)
			{
				sprintf(buf2, "%sYour attack %s $N for %dhp%c", youHit, vp, dam, punct );
			}
			else
			{
				sprintf(buf2, "%sYour attack %s $N%c", youHit, vp, punct);
			}
			if (dam > 0)
			{
				sprintf(buf3, "%s$n's attack %s you for %dhp%c", hitYou, vp, dam, punct);
			}
			else
			{
				sprintf(buf3, "%s$n's attack %s you%c", hitYou, vp, punct);
			}
		}
	}
	else
	{
		attack = get_dam_nounce(ch, victim, dt, wield);

		sprintf(buf1, "%s %s", attack, vp);

		if (dam > 0)
		{
			sprintf( buf2, "%sYour %s %s $N for %dhp%c", youHit, attack, vp, dam, punct );
		}
		else
		{
			sprintf( buf2, "%sYour %s %s $N%c",	youHit, attack, vp, punct );
		}
		if (dam > 0)
		{
			sprintf(buf3, "%s%s's %s %s you for %dhp%c", hitYou, ch == victim ? "Someone" : "$n", attack, vp, dam, punct);
		}
		else
		{
			sprintf(buf3,"%s%s's %s %s you%c", hitYou, ch == victim ? "Someone" : "$n", attack, vp, punct);
		}
	}

	if (dt == gsn_assassinate && learned(ch, gsn_silent_death))
		diceroll = hide_roll(ch);
	else
		diceroll = 0;
	/*
		Spam code for combat			-	Chaos 12/20/94
	*/
	for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
	{
		if (fch->desc && fch != ch && fch != victim)
		{
			if (diceroll && hide_check(ch, fch, diceroll, perception_roll(fch, SENSE_SIGHT)))
				continue;
			if (fch->position > POS_SLEEPING)
			{
				bool gch, gvic;
				gch = is_same_group( ch, fch );
				gvic = is_same_group( victim, fch );
				if (gch && !gvic)
				{
					if (dam <= 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_PARTY_MISS))
					{
						ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
					}
					if (dam > 0  && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_PARTY_HIT))
					{
						ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_YOU_HIT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
					}
				}
				else	if (!gch && gvic)
				{
					if (dam <= 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_THEY_MISS_PARTY))
					{
						ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
					}
					else if (dam > 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_THEY_HIT_PARTY))
					{
						ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_YOU_ARE_HIT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
					}
				}
				else	if (!gch && !gvic)
				{
					if (dam <= 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_OTHER_MISS))
					{
						ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
					}
					if (dam > 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_OTHER_HIT))
					{
						ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_BOLD), ch == victim ? "Someone" : capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
					}
				}
				else
				{
					ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
				}
			}
		}
	}
	if (in_area(ch, ROOM_VNUM_ARENA))
	{
		for (fpl = mud->f_player ; fpl ; fpl = fpl->next)
		{
			if (!IS_IMMORTAL(fpl->ch) && blocking(fpl->ch, ch))
				continue;
			if (!fpl->ch->desc || fpl->ch == ch || fpl->ch == victim)
				continue;
			if (fpl->ch == ch)
				continue;
			if (fpl->ch->in_room == NULL || in_same_room(ch, fpl->ch)
			|| !in_area(fpl->ch, ROOM_VNUM_ARENA)
			|| !IS_SET(fpl->ch->in_room->room_flags, ROOM_AUDIENCE))
				continue;
	
			if (diceroll && hide_check(ch, fpl->ch, diceroll, perception_roll(fpl->ch, SENSE_SIGHT)))
				continue;

			if (fpl->ch->position > POS_SLEEPING)
			{
				bool	gch, gvic;
				gch = is_same_group( ch, fpl->ch );
				gvic = is_same_group( victim, fpl->ch );
				if (gch && !gvic)
				{
					if (dam <= 0 && !IS_SET(CH(fpl->ch->desc)->pcdata->spam, SPAM_PARTY_MISS))
					{
						ch_printf_color(fpl->ch, "%s%s's %s %s%c\n\r", get_color_string(fpl->ch, COLOR_TEXT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fpl->ch)), buf1, PERS(victim, fpl->ch), (percent <= 18) ? '.' : '!');
					}
					if (dam > 0  && !IS_SET(CH(fpl->ch->desc)->pcdata->spam, SPAM_PARTY_HIT))
					{
						ch_printf_color(fpl->ch, "%s%s's %s %s%c\n\r", get_color_string(fpl->ch, COLOR_YOU_HIT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fpl->ch)), buf1, PERS(victim, fpl->ch), (percent <= 18) ? '.' : '!');
					}
				}
				else	if (!gch && gvic)
				{
					if (dam <= 0 && !IS_SET(CH(fpl->ch->desc)->pcdata->spam, SPAM_THEY_MISS_PARTY))
					{
						ch_printf_color(fpl->ch, "%s%s's %s %s%c\n\r", get_color_string(fpl->ch, COLOR_TEXT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fpl->ch)), buf1, PERS(victim, fpl->ch), (percent <= 18) ? '.' : '!');
					}
					else if (dam > 0 && !IS_SET(CH(fpl->ch->desc)->pcdata->spam, SPAM_THEY_HIT_PARTY))
					{
						ch_printf_color(fpl->ch, "%s%s's %s %s%c\n\r", get_color_string(fpl->ch, COLOR_YOU_ARE_HIT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fpl->ch)), buf1, PERS(victim, fpl->ch), (percent <= 18) ? '.' : '!');
					}
				}
				else	if (!gch && !gvic)
				{
					if (dam <= 0 && !IS_SET(CH(fpl->ch->desc)->pcdata->spam, SPAM_OTHER_MISS))
					{
						ch_printf_color(fpl->ch, "%s%s's %s %s%c\n\r", get_color_string(fpl->ch, COLOR_TEXT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fpl->ch)), buf1, PERS(victim, fpl->ch), (percent <= 18) ? '.' : '!');
					}
					if (dam > 0 && !IS_SET(CH(fpl->ch->desc)->pcdata->spam, SPAM_OTHER_HIT))
					{
						ch_printf_color(fpl->ch, "%s%s's %s %s%c\n\r", get_color_string(fpl->ch, COLOR_TEXT, VT102_BOLD), ch == victim ? "Someone" : capitalize(PERS(ch, fpl->ch)), buf1, PERS(victim, fpl->ch), (percent <= 18) ? '.' : '!');
					}
				}
				else
				{
					ch_printf_color(fpl->ch, "%s%s's %s %s%c\n\r", get_color_string(fpl->ch, COLOR_TEXT, VT102_DIM), ch == victim ? "Someone" : capitalize(PERS(ch, fpl->ch)), buf1, PERS(victim, fpl->ch), (percent <= 18) ? '.' : '!');
				}
			}
		}
	}
	if (ch->in_room->vnum != victim->in_room->vnum)
	{
		for (fch = victim->in_room->first_person ; fch ; fch = fch->next_in_room)
		{
			if (fch->desc && fch != ch && fch != victim)
			{
				if (diceroll && hide_check(ch, fch, diceroll, perception_roll(fch, SENSE_SIGHT)))
					continue;

				if (fch->position > POS_SLEEPING)
				{
					bool	gch, gvic;
					gch = is_same_group( ch, fch );
					gvic = is_same_group( victim, fch );
					if (gch && !gvic)
					{
						if (dam <= 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_PARTY_MISS))
						{
							ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_DIM), capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
						}
						if (dam > 0  && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_PARTY_HIT))
						{
							ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_YOU_HIT, VT102_DIM), capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
						}
					}
					else	if (!gch && gvic)
					{
						if (dam <= 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_THEY_MISS_PARTY))
						{
							ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_DIM), capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
						}
						else if (dam > 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_THEY_HIT_PARTY))
						{
							ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_YOU_ARE_HIT, VT102_DIM), capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
						}
					}
					else	if (!gch && !gvic)
					{
						if (dam <= 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_OTHER_MISS))
						{
							ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_DIM), capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
						}
						if (dam > 0 && !IS_SET(CH(fch->desc)->pcdata->spam, SPAM_OTHER_HIT))
						{
							ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_BOLD), capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
						}
					}
					else
					{
						ch_printf_color(fch, "%s%s's %s %s%c\n\r", get_color_string(fch, COLOR_TEXT, VT102_DIM), capitalize(PERS(ch, fch)), buf1, PERS(victim, fch), (percent <= 18) ? '.' : '!');
					}
				}
			}
		}
	}
	if (dam == 0)
	{
		if (ch->desc && !IS_SET(CH(ch->desc)->pcdata->spam, SPAM_YOU_MISS))
		{
			if (ch->position > POS_SLEEPING)
			{
				act( ch == victim ? buf3 : buf2, ch, NULL, victim, TO_CHAR);
			}
		}
		if (victim->desc && !IS_SET(CH(victim->desc)->pcdata->spam, SPAM_THEY_MISS))
		{
			if (victim->position > POS_SLEEPING)
			{
				act( buf3, ch, NULL, victim, TO_VICT);
			}
		}
	}
	else
	{
		if (ch->desc && !IS_SET(CH(ch->desc)->pcdata->spam, SPAM_YOU_HIT))
		{
			if (ch->position > POS_SLEEPING)
			{
				act( ch == victim ? buf3 : buf2, ch, NULL, victim, TO_CHAR);
			}
		}
		if (victim->desc && !IS_SET(CH(victim->desc)->pcdata->spam, SPAM_THEY_HIT))
		{
			if (victim->position > POS_SLEEPING)
			{
				act( buf3, ch, NULL, victim, TO_VICT);
			}
		}
	}
	pop_call();
	return;
}

/*
 * revamped function significantly - Kregor
 *
 * pass type 1 to select a primary attack part,
 * or the first body part if no primary attack.
 * pass type 0 to select a random attack part.
 */
int get_body_part( CHAR_DATA *ch, int dt, int type )
{
	int race, part, pick, cnt, rdm;

	push_call("get_body_part(%p,%p,%p)",ch,dt,type);

	if (dt != TYPE_HIT)
	{
		pop_call();
		return -1;
	}
	
	if ((race = get_race(ch)) == RACE_NONE && !IS_NPC(ch))
	{
		pop_call();
		return -1;
	}
	
	part = -1;

	if (type == 1)
	{
		for (cnt = 0 ; cnt < ATTK_MAX ; cnt++)
		{
			if (num_attacks(ch, cnt) == -1)
			{
				pop_call();
				return -1;
			}
			if (cnt == ATTK_RAKE)
				continue;
			if (num_attacks(ch, cnt) && attack_part_table[cnt].primary)
			{
				part = cnt;
				break;
			}
		}
		if (part == -1) // if no primary part, grab the first actual attack part
		{
			for (cnt = 0 ; cnt < ATTK_MAX ; cnt++)
			{
				if (cnt == ATTK_RAKE)
					continue;
				if (num_attacks(ch, cnt))
				{
					part = cnt;
					break;
				}
			}
		}
	}
	else
	{
		for (rdm = cnt = 0 ; rdm < ATTK_MAX ; rdm++)
		{
			if (rdm == ATTK_RAKE)
				continue;
			if (num_attacks(ch, rdm))
			{
				cnt++;
			}
		}
		pick = number_range(1, cnt);

		for (rdm = cnt = 0 ; rdm < ATTK_MAX ; rdm++)
		{
			if (rdm == ATTK_RAKE)
				continue;
			if (num_attacks(ch, rdm) && ++cnt == pick)
			{
				part = rdm;
				break;
			}
		}
	}
	pop_call();
	return part;
}


/*
 * loop through set attack parts, if one is flagged
 * as a natural weapon, return TRUE - Kregor
 */
bool has_natural_weapon(CHAR_DATA *ch)
{
	int part, race;
	
	push_call("has_natural_weapon(%p)",ch);

	if (IS_NPC(ch) && ch->pIndexData->unique && !ch->pIndexData->race)
	{
		pop_call();
		return FALSE;
	}
	else if ((race = get_race(ch)) == RACE_NONE)
	{
		pop_call();
		return FALSE;
	}

	for (part = 0; part < ATTK_MAX ; part++)
	{
		if (num_attacks(ch, part) && attack_part_table[part].natural)
		{
			pop_call();
			return TRUE;
		}
	}
	pop_call();
	return FALSE;
}

/*
 * Snarf the noun message for the damage done.
 * if wield is passed, it copies the name of the weapon,
 * if no weapon, it copies the name of the unarmed attack,
 * or the name of the damage in skill_table for spells and
 * non-physical damage - Kregor
 */
char *get_dam_nounce( CHAR_DATA *ch, CHAR_DATA *victim, int dt, OBJ_DATA *wield )
{
	static char *attack;

	push_call("get_dam_nounce(%p,%p,%p,%p)",ch,victim,dt,wield);

	attack = "";

	if (wield)
	{
		if (wield->pIndexData->attack_string[0] != '\0')
		{
			attack = wield->pIndexData->attack_string;
		}
		else
		{
			attack = weapon_table[wield->value[0]].name;
		}
	}
	else if (is_attack(dt))
	{
		if (learned(ch, gsn_martial_arts))
		{
			attack = martial_arts_table[martial_arts_attack].message;
		}
		else if (learned(ch, gsn_imp_unarmed_strike))
		{
			attack = brawling_table[brawling_attack].message;
		}
		else if (ch->attack_part != -1)
		{
			attack = attack_part_table[ch->attack_part].attack;
		}
		else if (valid_skill(dt))
		{
			attack = skill_table[dt].noun_damage;
		}
	}
	else
	{
		if (mpdamstring[0] != '\0')
		{
			attack = &mpdamstring[0];
		}
		else if (valid_skill(dt))
		{
			attack = skill_table[dt].noun_damage;
		}
		else
		{
			if (dt != TYPE_UNDEFINED)
			{
				bug("get_dam_nounce: bad dt %d.", dt);
			}
			attack = STRALLOC("<BAD ATTACK NAME>");
		}
	}
	pop_call();
	return attack;
}

/*
 * get the number of damage dice for an
 * unarmed attack - Kregor
 */
int get_damnodice( CHAR_DATA *ch )
{
	int dam, bodypart, level, size;

	push_call("get_damnodice(%p)",ch);

	size = get_size(ch);

	if ((bodypart = ch->attack_part) != -1)
	{
		if (race_skill(ch, gsn_imp_natural_attack)
		|| is_affected(ch, gsn_stone_fist)
		|| is_affected(ch, gsn_iron_body))
		{
			size = UMIN(size + 1, SIZE_COLOSSAL);
		}
		dam = dam_no_dice[bodypart].size[size];
	}
	else if ((bodypart = get_body_part(ch, TYPE_HIT, 1)) == -1)
	{
		bug("get_damnodice(%s): char has no body parts or race setting", ch->name);
		pop_call();
		return 0;
	}

	if (race_skill(ch, gsn_golem_slam))
	{
		dam = UMIN(2, ch->level / 6);
	}
	else if ((level = multi_skill_level(ch, gsn_martial_arts)) > 0)
	{		
		switch (size)
		{
			case SIZE_TINY:
				if (level >= 20)
					dam = 2;
				else
					dam = 1;
				break;
			case SIZE_SMALL:
				if (level >= 16)
					dam = 2;
				else
					dam = 1;
				break;
			case SIZE_MEDIUM:
				if (level >= 12)
					dam = 2;
				else
					dam = 1;
				break;
			case SIZE_LARGE:
				if (level >= 20)
					dam = 3;
				else if (level >= 8)
					dam = 2;
				else
					dam = 1;
				break;
			case SIZE_HUGE:
				if (level >= 16)
					dam = 3;
				else if (level >= 4)
					dam = 2;
				else
					dam = 1;
				break;
			case SIZE_GARGANTUAN:
				if (level >= 20)
					dam = 4;
				else if (level >= 12)
					dam = 3;
				else
					dam = 2;
				break;
			case SIZE_COLOSSAL:
				if (level >= 20)
					dam = 5;
				else if (level >= 12)
					dam = 4;
				else if (level >= 4)
					dam = 3;
				else
					dam = 2;
				break;
			default:
				dam = 1;
				break;
		}
	}
	pop_call();
	return dam;
}

/*
 * get the size of damage dice for an
 * unarmed attack - Kregor
 */
int get_damsizedice( CHAR_DATA *ch )
{
	int dam, bodypart, level, size;

	push_call("get_damsizedice(%p)",ch);
	
	size = get_size(ch);

	if ((bodypart = ch->attack_part) != -1)
	{
		if ((bodypart = get_body_part(ch, TYPE_HIT, 1)) == -1)
		{
			bug("get_damsizedice(%s): char has no body parts or race setting", ch->name);
			pop_call();
			return 0;
		}
		if (race_skill(ch, gsn_imp_natural_attack)
		|| is_affected(ch, gsn_stone_fist)
		|| is_affected(ch, gsn_iron_body))
		{
			size = UMIN(size + 1, SIZE_COLOSSAL);
		}
		dam = dam_size_dice[bodypart].size[size];
	}

	if (race_skill(ch, gsn_golem_slam))
	{
		switch (get_size(ch))
		{
			default:
				dam = 1;
				break;
			case SIZE_TINY:
				dam = 3;
				break;
			case SIZE_SMALL:
				dam = 4;
				break;
			case SIZE_MEDIUM:
				dam = 6;
				break;
			case SIZE_LARGE:
				dam = 8;
				break;
			case SIZE_HUGE:
				dam = 10;
				break;
			case SIZE_GARGANTUAN:
			case SIZE_COLOSSAL:
				dam = 12;
				break;
		}
	}
	else if ((level = multi_skill_level(ch, gsn_martial_arts)) > 0)
	{		
		switch (size)
		{
			case SIZE_TINY:
				if (level >= 20)
					dam = 6;
				else if (level >= 16)
					dam = 10;
				else if (level >= 12)
					dam = 8;
				else if (level >= 8)
					dam = 6;
				else if (level >= 4)
					dam = 4;
				else
					dam = 3;
				break;
			case SIZE_SMALL:
				if (level >= 20)
					dam = 8;
				else if (level >= 16)
					dam = 6;
				else if (level >= 12)
					dam = 10;
				else if (level >= 8)
					dam = 8;
				else if (level >= 4)
					dam = 6;
				else
					dam = 4;
				break;
			case SIZE_MEDIUM:
				if (level >= 20)
					dam = 10;
				else if (level >= 16)
					dam = 8;
				else if (level >= 12)
					dam = 6;
				else if (level >= 8)
					dam = 10;
				else if (level >= 4)
					dam = 8;
				else
					dam = 6;
				break;
			case SIZE_LARGE:
				if (level >= 20)
					dam = 8;
				else if (level >= 16)
					dam = 10;
				else if (level >= 12)
					dam = 8;
				else if (level >= 8)
					dam = 6;
				else if (level >= 4)
					dam = 10;
				else
					dam = 8;
				break;
			case SIZE_HUGE:
				if (level >= 20)
					dam = 10;
				else if (level >= 16)
					dam = 8;
				else if (level >= 12)
					dam = 10;
				else if (level >= 8)
					dam = 8;
				else if (level >= 4)
					dam = 6;
				else
					dam = 10;
				break;
			case SIZE_GARGANTUAN:
				if (level >= 20)
					dam = 10;
				else if (level >= 16)
					dam = 8;
				else if (level >= 12)
					dam = 10;
				else if (level >= 8)
					dam = 8;
				else if (level >= 4)
					dam = 10;
				else
					dam = 8;
				break;
			case SIZE_COLOSSAL:
				if (level >= 16)
					dam = 10;
				else if (level >= 12)
					dam = 8;
				else if (level >= 8)
					dam = 10;
				else if (level >= 4)
					dam = 8;
				else
					dam = 10;
				break;
			default:
				if (level >= 20)
					dam = 8;
				else if (level >= 16)
					dam = 6;
				else if (level >= 20)
					dam = 4;
				else if (level >= 20)
					dam = 3;
				else
					dam = 2;
				break;
		}
	}
	pop_call();
	return dam;
}

/*
 * Return TRUE if ch is wielding
 * or considered a lethal weapon - Kregor
 */
bool is_armed( CHAR_DATA *ch, bool wield )
{
	OBJ_DATA *obj = NULL;
	
	push_call("is_armed(%p)", ch);
	
	if (is_affected(ch, gsn_stone_fist)
	|| is_affected(ch, gsn_thorn_body)
	|| is_affected(ch, gsn_iron_body))
	{
		pop_call();
		return TRUE;
	}

	if (learned(ch, gsn_martial_arts)
	|| learned(ch, gsn_imp_unarmed_strike))
	{
		pop_call();
		return TRUE;
	}

	if (!has_natural_weapon(ch))
	{
		if (!wield)
		{
			pop_call();
			return FALSE;
		}
		if ((obj = get_wield(ch, FALSE)) == NULL)
		{
			if ((obj = get_wield(ch, TRUE)) == NULL)
			{
				pop_call();
				return FALSE;
			}
		}
	}

	if (obj && !IS_WEAPON(obj))
	{
		pop_call();
		return FALSE;
	}
	
	if (obj && (is_missile_weapon(obj) || WSPEC(obj, WSPEC_NOMELEE)) && !learned(ch, gsn_combat_archery))
	{
		pop_call();
		return FALSE;
	}
	
	pop_call();
	return TRUE;
}
	
/************************
 * Attacks of Opportunity - D20 style - Kregor
 */
 
/*
 * First, is CH able?
 */
bool can_take_opportunity( CHAR_DATA *ch, CHAR_DATA *victim )
{
	push_call("can_take_opportunity(%p,%p)",ch,victim);

	// crash insurance:
	if (ch == NULL || victim == NULL)
	{
		pop_call();
		return FALSE;
	}	
	
	/* DUH! */
	if (!IS_AWAKE(ch))
	{
		pop_call();
		return FALSE;
	}
	
	if (ch == victim)
	{
		pop_call();
		return FALSE;
	}

	if (is_affected(ch, gsn_time_stop))
	{
		pop_call();
		return FALSE;
	}
	/* confused will not take AoO */
	if (IS_AFFECTED(ch, AFF2_CONFUSION))
	{
		act("You are too confused to take an opportunity.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}	
	/* no threat unless actively fighting victim */
	if (who_fighting(ch) != victim)
	{
		act("You are not actively engaging $N.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}
	/* grappled can't take opportunity */
	if (ch->grappling || ch->grappled_by)
	{
		act("You too restrained to take the opportunity.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	if (!IS_AFFECTED(ch, AFF_FREEDOM) && (is_affected(ch, gsn_crushing_hand) || is_affected(ch, gsn_grasping_hand)))
	{
		act("You too restrained to take the opportunity.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	/* can't take opportunity with missile weapon */
	if (MISSILE_WIELD(ch))
	{
		act("You cannot threaten with a missile weapon.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}	
	/* can't take opportunity if considered unarmed */
	if (!is_armed(ch, TRUE))
	{
		act("You are unarmed and cannot take the opportunity.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}	
	/* can't interrupt your concentration to take opportunity */
	if (ch->casting || ch->concentrating)
	{
		act("You are concentrating on something else.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}	
	/* can't attack flatfooted without combat reflexes */
	if (IS_FLATFOOTED(ch) && !learned(ch, gsn_combat_reflexes))
	{
		act("You missed your attack of opportunity.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	/* can't attack if you've cast this round */
	if (IS_SET(ch->attack, ATTACK_CAST))
	{
		act("You can't take opportunity after casting this round.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	/* can't attack what you can't see */
	if (!can_see(ch, victim))
	{
		act("You can't see $N to take an opportunity.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}
	/* ONE AoO per round */
	if (IS_SET(ch->attack, ATTACK_OPPORTUNITY))
	{
		act("You've already made your attack of opportunity this round.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	pop_call();
	return TRUE;
}

/*
 * Next, is VICT vulnerable?
 * (Only used for manual actions, auto AoO are controlled in functions)
 */
bool has_opportunity( CHAR_DATA *ch, CHAR_DATA *victim )
{
	bool fOpportunity = FALSE;
	
	push_call("has_opportunity(%p,%p)",ch,victim);

	// crash insurance:
	if (ch == NULL || victim == NULL)
	{
		pop_call();
		return FALSE;
	}
	
	if (!can_take_opportunity(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	// qualifiers for opportunity

	if (victim->casting && !learned(victim, gsn_warmage))
	{
		fOpportunity = TRUE;	
	}
	else if (victim->concentrating)
	{
		fOpportunity = TRUE;	
	}
	else if (IS_SET(victim->attack, ATTACK_SHOOT) && !learned(victim, gsn_combat_archery))
	{
		fOpportunity = TRUE;	
	}
	else if (is_affected(victim, gsn_irresistible_dance))
	{
		fOpportunity = TRUE;	
	}
	else if (in_combat(victim))
	{
		if (!is_armed(victim, TRUE))
		{
			fOpportunity = TRUE;
		}
	}
	
	if (!fOpportunity)
	{
		pop_call();
		return FALSE;
	}
	
	// After all this, check for murder allowance:
	
	if (!check_murder(ch, victim))
	{
		pop_call();
		return FALSE;
	}

	pop_call();
	return TRUE;
}

/*
 * Auto attacks of opportunity
 */
bool attack_of_opportunity( CHAR_DATA *ch, CHAR_DATA *victim )
{
	push_call("attack_of_opportunity(%p,%p)",ch,victim);

	if (!has_opportunity(ch, victim))	
	{
		pop_call();
		return FALSE;
	}

	act( "{138}You make an attack of opportunity against $N.", ch, NULL, victim, TO_CHAR);
	act( "{138}$n makes an attack of opportunity against you.", ch, NULL, victim, TO_VICT);
	act( "{138}$n makes an attack of opportunity against $N.", ch, NULL, victim, TO_NOTVICT);

	one_hit(ch, victim, learned(ch, gsn_opportunist) ? gsn_opportunist : TYPE_UNDEFINED, 0, get_wield(ch, FALSE));
	SET_BIT(ch->attack, ATTACK_OPPORTUNITY);

	pop_call();
	return TRUE;
}


/*
 * Used to take elective attacks of opportunity.
 */
void take_opportunity( CHAR_DATA *ch, CHAR_DATA *victim )
{
	push_call("take_opportunity(%p,%p)",ch,victim);

	act( "{138}You make an attack of opportunity against $N.", ch, NULL, victim, TO_CHAR);
	act( "{138}$n makes an attack of opportunity against you.", ch, NULL, victim, TO_VICT);
	act( "{138}$n makes an attack of opportunity against $N.", ch, NULL, victim, TO_NOTVICT);

	SET_BIT(ch->attack, ATTACK_OPPORTUNITY);

	pop_call();
	return;
}


/*
 * Conditions for ch to receive dodge bonus to AC
 */
bool can_dodge(	CHAR_DATA *ch, CHAR_DATA *attacker	)
{
	push_call("can_dodge(%p,%p)",ch,attacker);

	if (IS_HELPLESS(ch))
	{
		pop_call();
		return FALSE;
	}
	if (IS_AFFECTED(ch, AFF2_STUNNED))
	{
		pop_call();
		return FALSE;
	}
	if (IS_FLATFOOTED(ch) && !learned(ch,gsn_uncanny_dodge))
	{
		pop_call();
		return FALSE;
	}
	if (!IS_AWAKE(ch))
	{
		pop_call();
		return FALSE;
	}
	if (encumberance(ch) == OVERLOADED)
	{
		pop_call();
		return FALSE;
	}
	if (attacker == NULL)
	{
		pop_call();
		return TRUE;
	}
	if (is_affected(attacker, gsn_impromptu_sneak_attack))
	{
		pop_call();
		return FALSE;
	}
	if (!can_see(ch, attacker) && !learned(ch, gsn_uncanny_dodge) && !learned(ch,gsn_blind_fight))
	{
		pop_call();
		return FALSE;
	}
	pop_call();
	return TRUE;
}


/*
 * This is where the improved uncanny dodge shines - Kregor
 */
bool is_flanking (CHAR_DATA *ch, CHAR_DATA *victim)
{
	int dodge_level, flank_level;
	
	push_call("is_flanking(%p,%p)",ch,victim);
	
	if (IS_PLR(victim, PLR_HOLYLIGHT))
	{
		pop_call();
		return FALSE;
	}
	if (who_fighting(victim) != NULL && who_fighting(victim) != ch)
	{
		if (multi_skill_level(victim, gsn_uncanny_dodge) >= 4)
		{
			dodge_level = multi_class_level(victim, gsn_uncanny_dodge);
			flank_level = multi_skill_level(ch, gsn_backstab);
			
			if (dodge_level + 4 >= flank_level)
			{
				pop_call();
				return FALSE;
			}
		}
	}
	if (who_fighting(victim) && who_fighting(victim) == ch)
	{
		pop_call();
		return FALSE;
	}
	pop_call();
	return race_type_table[race_type(victim)].can_flank;
}


/*
 * Conditions for parry and riposte feat - Kregor
 */
bool check_parry ( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *weapon, int attack )
{
	OBJ_DATA *wield;

	push_call("check_parry(%p,%p)",ch,victim);
	
	if (IS_SET(ch->attack, ATTACK_PARRY) || !COMBATMODE(ch, COMBAT_DEFENSIVE) || !learned(ch, gsn_parry))
	{
		pop_call();
		return FALSE;
	}
	
	if (!can_dodge(ch, victim))
	{
		pop_call();
		return FALSE;
	}
	
	if (get_size(victim) > get_size(ch) + 1)
	{
		pop_call();
		return FALSE;
	}
	if (get_size(ch) > get_size(victim) + 2)
	{
		pop_call();
		return FALSE;
	}

	if ((wield = get_wield(ch, FALSE)) == NULL)
		wield = get_wield(ch, TRUE);

	if (weapon)
	{
		if (!wield)
			attack += 4;
		else
			attack += (weapon->size - wield->size);
	}
	else
	{
		attack += (get_size(victim) - get_size(ch));
	}

	if (!refl_save(ch, NULL, attack, -1))
	{
		pop_call();
		return FALSE;
	}

	if (learned(ch, gsn_riposte) && attack_of_opportunity(ch, victim))
	{
		act( "{138}$n makes an agile riposte against your attack!", ch, NULL, victim, TO_VICT);
		act( "{138}$n makes an agile riposte against $N!", ch, NULL, victim, TO_NOTVICT);
		act( "{138}You make an agile riposte against $N!", ch, NULL, victim, TO_CHAR);
		SET_BIT(ch->attack, ATTACK_RIPOSTE);
	}
	else
	{
		act( "{138}$n parries your attack!!", ch, NULL, victim, TO_VICT);
		act( "{138}$n parries $N's attack!", ch, NULL, victim, TO_NOTVICT);
		act( "{138}You parry $N's attack!", ch, NULL, victim, TO_CHAR);
	}
	
	SET_BIT(ch->attack, ATTACK_PARRY);

	pop_call();
	return TRUE;
}

/*
 * Code for the Deflect Missiles/Snatch Missiles feats - Kregor
 * added support for missile deflection from spells
 */
bool deflect_missile ( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *missile, int dir )
{
	AFFECT_DATA *paf;

	push_call("deflect_missile(%p,%p,%p)",ch,victim,missile);
	
	if (missile == NULL)
	{
		log_printf("deflect_missile(): NULL ammo or weapon.");
		pop_call();
		return FALSE;
	}
	else if (ch == NULL || victim == NULL)
	{
		log_printf("deflect_missile(): NULL actor, ch or victim.");
		pop_call();
		return FALSE;
	}
	
	if (!IS_OBJ_STAT(missile, ITEM_MAGIC))
	{
		if ((paf = get_affect_sn(victim, gsn_missile_deflection)) != NULL)
		{
			--paf->modifier;
			if (paf->modifier <= 0)
			{
				act( skill_table[paf->type].msg_off, victim, NULL, NULL, TO_CHAR);
				affect_strip(victim, gsn_missile_deflection);
			}
			act( "$p deflects harmlessly off of $n.", victim, missile, NULL, TO_ROOM);
			act( "$p is deflected harmlessly away.", victim, missile, NULL, TO_CHAR);
			if (ch->in_room != victim->in_room)
				act( "$p deflects harmlessly off of $N.", ch, missile, NULL, TO_ROOM);

			obj_from_char(missile);
			
			if (!IS_AMMO(missile))
			{
				if (WEAPON_FLAG(missile, WFLAG_RETURNING) || (WSPEC(missile, WSPEC_RETURNING) && weapon_skill(ch, missile)))
				{
					act( "$p returns to $n's hand.", ch, missile, NULL, TO_ROOM );
					act( "$p returns to your hand.", ch, missile, NULL, TO_CHAR );
					obj_to_char(missile, ch);
				}
				else
				{
					missile->sac_timer = OBJ_SAC_TIME;
					obj_to_room(missile, victim->in_room->vnum);
				}
			}
			else
			{
				junk_obj(missile);
			}
			pop_call();
			return TRUE;
		}
	}
	
	//repel metal bounces metal missiles away, guaranteed! - Kregor
	if (is_affected(victim, gsn_repel_metal))
	{
		if (missile->material && material_table[missile->material].parent == MATERIAL_TYPE_METAL)
		{
			act( "$p is repelled by $n.", victim, missile, NULL, TO_ROOM);
			act( "$p is repelled harmlessly away.", victim, missile, NULL, TO_CHAR);
			if (ch->in_room != victim->in_room)
				act( "$p is repelled by $N.", ch, missile, NULL, TO_ROOM);

			obj_from_char(missile);

			if (!IS_AMMO(missile))
			{
				if (WEAPON_FLAG(missile, WFLAG_RETURNING) || (WSPEC(missile, WSPEC_RETURNING) && weapon_skill(ch, missile)))
				{
					act( "$p returns to $n's hand.", ch, missile, NULL, TO_ROOM );
					act( "$p returns to your hand.", ch, missile, NULL, TO_CHAR );
					obj_to_char(missile, ch);
				}
				else
				{
					missile->sac_timer = OBJ_SAC_TIME;
					obj_to_room(missile, victim->in_room->vnum);
				}
			}
			else
			{
				junk_obj(missile);
			}
			pop_call();
			return TRUE;
		}
	}
	
	if (IS_SET(ch->attack, ATTACK_DEFLECT))
	{
		pop_call();
		return FALSE;
	}
	if (IS_FLATFOOTED(ch) || IS_HELPLESS(ch))
	{
		pop_call();
		return FALSE;
	}
	
	if (learned(ch, gsn_ranged_parry))
	{
		OBJ_DATA *weapon;
		if (armor_type_worn(ch) == ARMOR_NONE
		&& get_eq_char(ch, WEAR_SHIELD) == NULL
		&& (weapon = get_wield(ch, FALSE)) != NULL
		&& WSPEC(weapon, WSPEC_FINESSE))
		{
			if (!refl_save(ch, victim, 20, -1))
			{
				pop_call();
				return FALSE;
			
				act( "$n deflects $p with $P.", ch, missile, weapon, TO_ROOM);
				act( "You deflect $p with $P.", ch, missile, weapon, TO_CHAR);
				if (ch->in_room != victim->in_room)
					act( "$N deflects $p with $P.", victim, missile, weapon, TO_ROOM);
					
				if (!IS_AMMO(missile))
				{
					if (WEAPON_FLAG(missile, WFLAG_RETURNING) || (WSPEC(missile, WSPEC_RETURNING) && weapon_skill(ch, missile)))
					{
						act( "$p returns to $n's hand.", ch, missile, NULL, TO_ROOM );
						act( "$p returns to your hand.", ch, missile, NULL, TO_CHAR );
						obj_to_char(missile, ch);
					}
					else
					{
						missile->sac_timer = OBJ_SAC_TIME;
						obj_to_room(missile, victim->in_room->vnum);
					}
				}
				else
				{
					junk_obj(missile);
				}
				pop_call();
				return TRUE;
			}
			else
			{
				pop_call();
				return FALSE;
			}
		}
	}
	
	if (!learned(ch, gsn_deflect_arrows) && !learned(ch, gsn_snatch_arrows))
	{
		pop_call();
		return FALSE;
	}
	if (!is_handy(ch) || hands_full(ch))
	{
		pop_call();
		return FALSE;
	}
	
	if (!refl_save(ch, victim, 20, -1))
	{
		pop_call();
		return FALSE;
	}
	
	obj_from_char(missile);
	
	if (learned(ch, gsn_snatch_arrows) && !IS_AMMO(missile))
	{
		act( "$n snatches $p from midair.", ch, missile, victim, TO_ROOM);
		act( "You snatch $p from midair.", ch, missile, victim, TO_CHAR);
		if (ch->in_room != victim->in_room)
			act( "$N snatches $p from midair.", victim, missile, ch, TO_ROOM);
			
		obj_to_char(missile, victim);
		throwback(victim, ch, missile, dir);
	}
	else
	{
		act( "$n deflects $p.", ch, missile, victim, TO_ROOM);
		act( "You deflect $p.", ch, missile, victim, TO_CHAR);
		if (ch->in_room != victim->in_room)
			act( "$N deflects $p.", victim, missile, ch, TO_ROOM);
			
		if (!IS_AMMO(missile))
		{
			if (WEAPON_FLAG(missile, WFLAG_RETURNING) || (WSPEC(missile, WSPEC_RETURNING) && weapon_skill(ch, missile)))
			{
				act( "$p returns to $n's hand.", ch, missile, NULL, TO_ROOM );
				act( "$p returns to your hand.", ch, missile, NULL, TO_CHAR );
				obj_to_char(missile, ch);
			}
			else
			{
				missile->sac_timer = OBJ_SAC_TIME;
				obj_to_room(missile, victim->in_room->vnum);
			}
		}
		else
		{
			junk_obj(missile);
		}
	}
	pop_call();
	return TRUE;
}


/*
 * AC conditional calculations for attack rolls
 */
int calc_ac( CHAR_DATA *victim, CHAR_DATA *ch, bool touch )
{
	int ac, bonus;
	
	push_call("calc_ac(%p,%p)",victim,ch);

	ac = GET_AC(victim, touch);
	bonus = 0;

	if (IS_EVIL(ch))
		bonus = UMAX(bonus, get_apply(victim, APPLY_RES_EVIL));

	if (IS_GOOD(ch))
		bonus = UMAX(bonus, get_apply(victim, APPLY_RES_GOOD));

	if (IS_LAWFUL(ch))
		bonus = UMAX(bonus, get_apply(victim, APPLY_RES_LAW));

	if (IS_CHAOTIC(ch))
		bonus = UMAX(bonus, get_apply(victim, APPLY_RES_CHAOS));
		
	if (race_type(ch) == RTYPE_OUTSIDER)
	{
		if (learned(victim, gsn_divine_defense))
			bonus += ROUNDUP(multi_skill_level(victim, gsn_divine_defense) / 2);
	}

	ac += bonus;

	if (can_dodge(victim, ch))
	{
		ac += dodge_bonus(victim);
		if (rspec_req(ch, RSPEC_GIANT) && learned(victim, gsn_defensive_training))
			ac += 4;
	}
	else
	{
		ac += dodge_penalty(victim);
	}
	
	if ((who_fighting(victim) == NULL && can_see(victim, ch)) || who_fighting(victim) == ch)
	{
		if (!touch || learned(victim, gsn_shield_ward))
			ac += shield_bonus(victim);
	}
	pop_call();
	return ac;
}


/*
 * Find weapon wielded, return NULL if item is not a weapon - Kregor
 */
OBJ_DATA *get_wield( CHAR_DATA *ch, bool fDual )
{
	OBJ_DATA *wield;

	push_call("get_wield(%p,%p)",ch,fDual);

	for (wield = ch->first_carrying ; wield ; wield = wield->next_content)
	{
		if (!IS_WEAPON(wield))
			continue;
			
		if (!IS_WORN(wield))
			continue;

		if (fDual && WEAR_LOC(wield, WEAR_DUAL_WIELD))
		{
			pop_call();
			return wield;
		}
		if (WEAR_LOC(wield, WEAR_BOTH_HANDS))
		{
			if (!fDual || WSPEC(wield, WSPEC_DOUBLE))
			{
				pop_call();
				return wield;
			}
		}
		if (!fDual && WEAR_LOC(wield, WEAR_WIELD))
		{
			pop_call();
			return wield;
		}
	}
	pop_call();
	return NULL;
}

/*
 * Check if missile weapon wielded - Kregor
 */
bool MISSILE_WIELD( CHAR_DATA *ch )
{
	OBJ_DATA *wield;
	
	push_call("MISSILE_WIELD(%p)",ch);
	
	if ((wield = get_wield(ch, FALSE)) != NULL)
	{
		pop_call();
		return WSPEC(wield, WSPEC_MISSILE|WSPEC_NOMELEE);
	}
	pop_call();
	return FALSE;
}

/*
 * Check if object is a missile weapon - Kregor
 */
bool is_missile_weapon( OBJ_DATA *wield )
{	
	push_call("is_missile_weapon(%p)",wield);
	
	if (wield == NULL)
	{
		pop_call();
		return FALSE;
	}
	pop_call();
	return WSPEC(wield, WSPEC_MISSILE);
}

/*
 * Check if object is a bow - Kregor
 */
bool is_bow( OBJ_DATA *wield )
{	
	push_call("is_missile_weapon(%p)",wield);
	
	if (wield == NULL)
	{
		pop_call();
		return FALSE;
	}
	if (WEAPON_TYPE(wield, WEAPON_TYPE_LONGBOW)
	|| WEAPON_TYPE(wield, WEAPON_TYPE_LONGBOW_COMPOSITE)
	|| WEAPON_TYPE(wield, WEAPON_TYPE_SHORTBOW)
	|| WEAPON_TYPE(wield, WEAPON_TYPE_SHORTBOW_COMPOSITE))
	{
		pop_call();
		return TRUE;
	}
	pop_call();
	return FALSE;
}

/*
 * Checks for ammo for missile weapon
 * returns NULL if none found in inventory or quiver
 */
OBJ_DATA *get_ammo( CHAR_DATA *ch, OBJ_DATA *wield )
{
	OBJ_DATA  *ammo, *cont;
	
	push_call("get_ammo(%p,%p)",ch,wield);

	ammo = NULL;

	if (is_missile_weapon(wield))
	{
		for (ammo = ch->first_carrying ; ammo ; ammo = ammo->next_content)
		{
			if (ammo->item_type == ITEM_AMMO && ammo->value[0] == wield->value[0] && ammo->level <= wield->level)
			{
				break;
			}
			if (ammo->item_type == ITEM_QUIVER && !IS_SET(ammo->value[1], CONT_CLOSED))
			{
				cont = ammo;

				for (ammo = ammo->first_content ; ammo ; ammo = ammo->next_content)
				{
					if (ammo->item_type == ITEM_AMMO && ammo->value[0] == wield->value[0])
					{
						break;
					}
				}
				if (ammo)
				{
					break;
				}
				else
				{
					ammo = cont;
				}
			}
		}
	}
	pop_call();
	return (ammo);
}


/*
 * Calculate all the possible modifiers to attack roll - Kregor
 */
int GET_HITROLL(CHAR_DATA *ch, CHAR_DATA *victim, int dt, OBJ_DATA *wield)
{
	int val, wskill;
	OBJ_DATA *obj;
	OBJ_DATA *ammo = NULL;
	OBJ_DATA *wield1 = NULL;
	OBJ_DATA *wield2 = NULL;
	OBJ_DATA *shield = NULL;

	push_call("GET_HITROLL(%p)",ch);

	val = 0;
	val = base_attack(ch);

	val += get_apply(ch, APPLY_COMP_TOHIT);
	val += get_apply(ch, APPLY_INS_TOHIT);
	val += get_apply(ch, APPLY_LUCK_TOHIT);
	val += get_apply(ch, APPLY_MOR_TOHIT);
	
	for (obj = ch->first_carrying ; obj ; obj = obj->next_content)
	{
		if (WEAR_LOC(obj, WEAR_BOTH_HANDS) && obj->item_type == ITEM_WEAPON && WSPEC(obj, WSPEC_DOUBLE))
		{
			wield2 = obj;
		}
		if (WEAR_LOC(obj, WEAR_WIELD) && obj->item_type == ITEM_WEAPON)
		{
			wield1 = obj;
		}
		if (WEAR_LOC(obj, WEAR_DUAL_WIELD) && obj->item_type == ITEM_WEAPON)
		{
			wield2 = obj;
		}
		if (WEAR_LOC(obj, WEAR_SHIELD) && obj->item_type == ITEM_ARMOR)
		{
			shield = obj;
		}
	}

	if (IS_SET(ch->attack, ATTACK_SHIELD_BASH) && !learned(ch, gsn_imp_shield_bash))
		val -= 2;
		
	// apply mount's STR bonus to hit during charge, or double ch if quadruped
	if (IS_SET(ch->attack, ATTACK_CHARGE))
	{
		if (is_mounting(ch))
		{
			val += UMAX(0, stat_bonus(TRUE, ch->mounting, APPLY_STR));
		}
		else
		{
			val += UMAX(0, stat_bonus(TRUE, ch, APPLY_STR));
		}
	}

	switch (get_size(ch))
	{
		case SIZE_FINE:
			val += 8;
			break;		
		case SIZE_DIMINUTIVE:
			val += 4;
			break;		
		case SIZE_TINY:
			val += 2;
			break;				
		case SIZE_SMALL:
			val += 1;
			break;		
		case SIZE_LARGE:
			val -= 1;
			break;			
		case SIZE_HUGE:
			val -= 2;
			break;				
		case SIZE_GARGANTUAN:
			val -= 4;
			break;		
		case SIZE_COLOSSAL:
			val -= 8;
			break;		
	}

	if (IS_AFFECTED(ch, AFF2_SICKENED))
		val -= 2;
	if (IS_DAZZLED(ch))
		val -= 1;
	if (IS_ENTANGLED(ch))
		val -= 2;
	if (is_affected(ch, gsn_barbarian_rage) && !learned(ch, gsn_mighty_rage))
		val -= 2;
		
	switch(drunk_level(ch))
	{
		case DRUNK_SOBER:
			break;
		case DRUNK_TIPSY:
			val -= 1;
			break;
		case DRUNK_MERRY:
			val -= 2;
			break;
		case DRUNK_DRUNK:
			val -= 4;
			break;
		case DRUNK_HAMMERED:
			val -= 8;
			break;
		default:
			val -= 16;
			break;
	}

	// penalty to hit -2 for each level of fear
	if (ch->fear_level)
		val -= UMIN(ch->fear_level, 3) * 2;
	
	// armor penalty applies if wearing non-proficient armor
	if (has_armor_penalty(ch))
		val -= armor_check_penalty(ch);
	
	// weapon proficiency feats
	wskill = weapon_skill(ch, wield);
	
	if (IS_SET(wskill, WSKILL_EPIC_FOCUS))
		val += 2;
	if (IS_SET(wskill, WSKILL_GREATER_FOCUS))
		val += 1;
	if (IS_SET(wskill, WSKILL_FOCUS))
		val += 1;
	if (learned(ch, gsn_weapon_mastery) && IS_SET(wskill, WSKILL_FOCUS))
		val += (multi_skill_level(ch, gsn_weapon_mastery) / 4) + 1;

	// These modifiers only apply to missile weapons
	if (is_missile_weapon(wield))
	{
		if (COMBATMODE(ch, COMBAT_CALLED))
			val -= UMIN(stat_bonus(TRUE, ch, APPLY_DEX), base_attack(ch));

		if (COMBATMODE(ch, COMBAT_RAPIDSHOT))
			val -= 2;

		if (COMBATMODE(ch, COMBAT_MANYSHOT))
			val -= 2;	

		if (is_mounting(ch) && !learned(ch, gsn_mounted_archery))
			val -= 2;
	}
	else // these modifiers only apply in melee
	{
		if (COMBATMODE(ch, COMBAT_POWER))
			val -= UMIN(stat_bonus(TRUE, ch, APPLY_STR), base_attack(ch));

		if (COMBATMODE(ch, COMBAT_DEFENSIVE))
		{
			if (learned(ch, gsn_combat_expertise))
				val -= UMIN(stat_bonus(TRUE, ch, APPLY_DEX), base_attack(ch));
			else
				val -= 4;
		}
		if (COMBATMODE(ch, COMBAT_FLURRY))
		{
			if (!wield || WSPEC(wield, WSPEC_MONK))
			{
				if (class_level(ch, CLASS_MONK) < 5)
					val -= 2;
				else if  (class_level(ch, CLASS_MONK) < 10)
					val -= 1;
			}
		}
	}	
	
	if (wield != NULL)
	{
		// nonproficient penalty
		if (!wskill)
			val -= 4;
		
		if (WEAPON_TYPE(wield, WEAPON_TYPE_SLING))
			val += ROUNDUP(multi_class_level(ch, gsn_crack_shot)/2);

		if (is_missile_weapon(wield))
		{
			val += stat_bonus(TRUE, ch, APPLY_DEX);

			if (victim != NULL)
			{
				if (learned(ch, gsn_point_blank) && in_same_room(ch, victim))
					val += 1;
				// firing into melee without precise shot -4 to hit
				if (victim->position == POS_FIGHTING && !learned(ch, gsn_precise_shot))
					val -= 4;
			}

			// apply only the greater of weapon or ammo enchantment
			int bonus = 0;

			bonus = weapon_tohit_bonus(wield);
			if ((ammo = get_ammo(ch, wield)) != NULL)
				bonus = UMAX(weapon_tohit_bonus(ammo), bonus);
			if (is_bow(wield) && learned(ch, gsn_enhance_arrow))
				bonus = UMAX(ROUNDUP(multi_class_level(ch, gsn_enhance_arrow) / 2), bonus);
			val += bonus;
		}
		else
		{
			val += weapon_tohit_bonus(wield);

			// weapon finesse - DEX bonus instead of STR for light weapons
			if ((is_light_weapon(ch, wield) || WSPEC(wield, WSPEC_FINESSE))
			&& learned(ch,gsn_weapon_finesse) && shield == NULL
			&& get_curr_dex(ch) >= 13 && !COMBATMODE(ch, COMBAT_POWER))
			{
				val += stat_bonus(TRUE, ch, APPLY_DEX);
			}
			else
			{
				val += stat_bonus(TRUE, ch, APPLY_STR);
			}
		}

		/* -4 if fighting nonlethal with lethal weapon */
		if (COMBATMODE(ch, COMBAT_NONLETHAL)
		&& !WSPEC(wield, WSPEC_NONLETHAL) && !WEAPON_FLAG(wield, WFLAG_MERCIFUL))
			val -= 4;

		/*
		 * two-weapon fighting penalties:
		 * light weapon w/feat - -2 -2
		 * light weapon w/o feat - -4 -8
		 * normal weapons w/feat - -4 -4
		 * normal weapons w/o feat - -6 -10
		 * double weapon w feat - -3 -3
		 * double weapon w/o feat - -6 -6
		 * Besides making coding easier for double weapons, I rationale the
		 * fact that a PC has to spend an exotic weapon feat to use a double
		 * weapon enough for a lesser penalty even without TWF (since w/o
		 * Exotic Weapon feat the penalties would be -10/-10 - Kregor
		 */
		else if (!learned(ch, gsn_perfect_two_weapon))
		{
			if (WEAR_LOC(wield, WEAR_DUAL_WIELD))
			{
				if (learned(ch, gsn_twin_sword) && wield1 && wield1->value[0] == wield->value[0])
				{
					val -= 2;
				}
				else if (is_light_weapon(ch, wield))
				{
					if (learned(ch, gsn_two_weapon))
						val -= 2;
					else
						val -= 8;
				}
				else if (learned(ch, gsn_two_weapon))
					val -= 4;
				else
					val -= 10;
			}
			else if (WEAR_LOC(wield, WEAR_BOTH_HANDS) && WSPEC(wield, WSPEC_DOUBLE))
			{
				if (learned(ch, gsn_two_weapon))
					val -= 3;
				else
					val -= 6;
			}
			else if (wield2 != NULL)
			{
				if (learned(ch, gsn_twin_sword) && wield2 && wield2->value[0] == wield->value[0])
				{
					val -= 2;
				}
				else if (is_light_weapon(ch, wield2))
				{
					if (learned(ch, gsn_two_weapon))
						val -= 2;
					else
						val -= 4;
				}
				else if (learned(ch, gsn_two_weapon))
					val -= 4;
				else
					val -= 6;
			}
		}
		if (wield->material == MATERIAL_COLD_IRON)
		{
			val -= 1;
		}			
	}
	else
	{
		/* -4 to hit if fighting lethal unarmed */
		if (!has_natural_weapon(ch) && !is_armed(ch, FALSE)
		&& !COMBATMODE(ch, COMBAT_NONLETHAL))
		{
			val -= 4;
		}
		/* unarmed strike = light weapon */
		if (learned(ch,gsn_weapon_finesse) && shield == NULL
		&& get_curr_dex(ch) >= 13 && !COMBATMODE(ch, COMBAT_POWER))
			val += stat_bonus(TRUE, ch, APPLY_DEX);
		else
			val += stat_bonus(TRUE, ch, APPLY_STR);

		// added here, to keep from adding to weapon bonus
		val += get_apply(ch, APPLY_HITROLL);
	}

	if (victim != NULL)
	{
		if (!can_see(victim, ch))
			val += 2;
		if (is_flanking(ch, victim))
			val += 2;

		/* paladin/blackguard smite ability */
		if (is_affected(victim, gsn_smite) && get_caster(victim, gsn_smite) == ch && stat_bonus(TRUE, ch, APPLY_CHA) > 0)
		{
			val += stat_bonus(TRUE, ch, APPLY_CHA);
		}
		
		/* retribution domain strike */
		if (is_affected(ch, gsn_retributive_strike) && ch->last_attacker && ch->last_attacker == victim)
		{
			val += stat_bonus(TRUE, ch, APPLY_WIS);
		}
		
		if (is_affected(ch, gsn_divine_wrath))
		{
			val += UMAX(1, stat_bonus(TRUE, ch, APPLY_CHA));
		}
	}
	val += get_apply(ch, APPLY_LEVEL);

	if (ch->grappling)
		val -= 2;
	else if (!IS_AFFECTED(ch, AFF_FREEDOM))
	{
		if (ch->grappled_by || IS_UNDERWATER(ch) || is_affected(ch, gsn_crushing_hand) || is_affected(ch, gsn_grasping_hand))
			val -= 2;
	}
	pop_call();
	return(UMIN(val, 99));
}

/*
 * Get the damage dice for a weapon or attack, plus bonuses
 */
int GET_DAMROLL(CHAR_DATA *ch, CHAR_DATA *victim, int dt, OBJ_DATA *wield)
{
	OBJ_DATA *obj;
	OBJ_DATA *ammo = NULL;
	OBJ_DATA *wield2 = NULL;
	OBJ_DATA *shield = NULL;
	int dam = 0;

	push_call("GET_DAMROLL(%p)",ch);

	for (obj = ch->first_carrying ; obj ; obj = obj->next_content)
	{
		if (WEAR_LOC(obj, WEAR_BOTH_HANDS) && obj->item_type == ITEM_WEAPON && WSPEC(obj, WSPEC_DOUBLE))
		{
			wield2 = obj;
		}
		if (WEAR_LOC(obj, WEAR_DUAL_WIELD) && obj->item_type == ITEM_WEAPON)
		{
			wield2 = obj;
		}
		if (WEAR_LOC(obj, WEAR_SHIELD) && obj->item_type == ITEM_ARMOR)
		{
			shield = obj;
		}
	}

	// first, get base weapon damage - Kregor
	if (wield != NULL && (IS_WEAPON(wield) || IS_AMMO(wield)))
	{
		dam = dice(weapon_table[wield->value[0]].damnodice, weapon_table[wield->value[0]].damsizedice);
		
		// charge damage multiplied for lance and/or spirited charge
		if (IS_SET(ch->attack, ATTACK_CHARGE))
		{
			if (learned(ch, gsn_spirited_charge) && WEAPON_TYPE(wield, WEAPON_TYPE_LANCE))
			{
				dam *= 3;
			}
			else if (learned(ch, gsn_spirited_charge) || WEAPON_TYPE(wield, WEAPON_TYPE_LANCE))
			{
				dam *= 2;
			}
			// apply mount's STR bonus to dam during charge, or double ch STR bonus if quadruped
			if (is_mounting(ch))
			{
				dam += UMAX(0, stat_bonus(TRUE, ch->mounting, APPLY_STR));
			}
			else
			{
				dam += UMAX(0, stat_bonus(TRUE, ch, APPLY_STR));
			}
		}

		if (WEAPON_TYPE(wield, WEAPON_TYPE_SLING))
			dam += ROUNDUP(multi_class_level(ch, gsn_crack_shot)/2) * 2;

		// bows & slings have STR penalties, slings & composite bows grant STR bonus 
		if (is_missile_weapon(wield))
		{
			switch(wield->value[0])
			{
				case WEAPON_TYPE_SHORTBOW:
				case WEAPON_TYPE_LONGBOW:
					if (get_curr_str(ch) < 10)
						dam += stat_bonus(TRUE, ch, APPLY_STR);
					break;
				case WEAPON_TYPE_SHORTBOW_COMPOSITE:
				case WEAPON_TYPE_LONGBOW_COMPOSITE:
				case WEAPON_TYPE_SLING:
					dam += stat_bonus(TRUE, ch, APPLY_STR);
					break;
			}
			// point-blank shot feat
			if (victim != NULL && learned(ch, gsn_point_blank) && in_same_room(ch, victim))
				dam += 1;
				
			// take greater of weapon or ammo enchantment
			int bonus = weapon_dam_bonus(wield);
			if ((ammo = get_ammo(ch, wield)) != NULL)
				bonus = UMAX(weapon_dam_bonus(ammo), bonus);
			if (is_bow(wield) && learned(ch, gsn_enhance_arrow))
				bonus = UMAX(ROUNDUP(multi_class_level(ch, gsn_enhance_arrow) / 2), bonus);
			dam += bonus;
		}
		// imp weapon finesse - DEX bonus instead of STR for light weapons
		else if ((is_light_weapon(ch, wield) || WSPEC(wield, WSPEC_FINESSE))
		&& learned(ch, gsn_imp_weapon_finesse) && shield == NULL
		&& get_curr_dex(ch) >= 13 && !COMBATMODE(ch, COMBAT_POWER))
		{
			if (wield->wear_loc == WEAR_DUAL_WIELD)
				dam += stat_bonus(TRUE, ch, APPLY_DEX) / 2;
			else
				dam += stat_bonus(TRUE, ch, APPLY_DEX);
		}
		else
		{
			switch(wield->wear_loc)
			{
				case WEAR_BOTH_HANDS:
					dam += stat_bonus(TRUE, ch, APPLY_STR) * 1.5;
					break;
				case WEAR_DUAL_WIELD:
					dam += stat_bonus(TRUE, ch, APPLY_STR) / 2;
					break;
				default:
					dam += stat_bonus(TRUE, ch, APPLY_STR);
					break;
			}
		}
		switch (wield->material)
		{
			case MATERIAL_SILVER:
			case MATERIAL_SOFTWOOD:
			case MATERIAL_STONE:
				dam -= 1;
				break;
			case MATERIAL_BONE:
				dam -= 2;
				break;
			default:
				break;
		}
	}
	else if (dt == gsn_shield_bash)
	{
		if (shield == NULL || shield->item_type != ITEM_ARMOR)
		{
			bug("GET_DAMROLL(%s): dt shield_bash with no shield!", get_name(ch));
			pop_call();
			return 0;
		}
		if (ARMOR_TYPE(shield, ARMOR_TYPE_LIGHT_SHIELD))
			dam = dice(1,4);
		if (ARMOR_TYPE(shield, ARMOR_TYPE_HEAVY_SHIELD))
			dam = dice(1,6);
		dam += stat_bonus(TRUE, ch, APPLY_STR) / 2;
	}
	else if (dt == gsn_rock_throwing)
	{
		dam = dice(dam_no_dice[ATTK_SLAM].size[get_size(ch)] * 2, dam_size_dice[ATTK_SLAM].size[get_size(ch)]);
		dam += stat_bonus(TRUE, ch, APPLY_STR) * 3 / 2;
	}
	else
	{
		dam = dice(get_damnodice(ch), get_damsizedice(ch));
		
		int stat;
		
		if (learned(ch, gsn_imp_weapon_finesse) && shield == NULL
		&& get_curr_dex(ch) >= 13 && !COMBATMODE(ch, COMBAT_POWER))
			stat = APPLY_DEX;
		else
			stat = APPLY_STR;

		if (ch->attack_part > -1)
		{
			if (attack_part_table[ch->attack_part].primary)
			{
				if (race_skill(ch, gsn_imp_natural_attack))
					dam += stat_bonus(TRUE, ch, stat) * 3 / 2;
				else
					dam += stat_bonus(TRUE, ch, stat);
			}
			else
				dam += (stat_bonus(TRUE, ch, stat) / 2);
		}
		else
			dam += (stat_bonus(TRUE, ch, stat));

		wiz_printf("get_damdice(%s): body part %d - %dd%d+%d", get_name(ch), ch->attack_part, get_damnodice(ch), get_damsizedice(ch), stat_bonus(TRUE, ch, stat));
	}

	// then, add modifiers
	int wskill = weapon_skill(ch, wield);

	if (IS_SET(wskill, WSKILL_SPECIALIZED))
		dam += 2;
	if (IS_SET(wskill, WSKILL_GREATER_SPEC))
		dam += 2;
	if (IS_SET(wskill, WSKILL_EPIC_SPEC))
		dam += 4;			
	if (learned(ch, gsn_weapon_mastery) && IS_SET(wskill, WSKILL_FOCUS))
		dam += (multi_skill_level(ch, gsn_weapon_mastery) / 4) + 1;

	dam += get_apply(ch, APPLY_COMP_DAMG);
	dam += get_apply(ch, APPLY_LUCK_DAMG);
	dam += get_apply(ch, APPLY_MOR_DAMG);

	if (IS_AFFECTED(ch, AFF2_SICKENED))
		dam -= 2;

	if (is_missile_weapon(wield))
	{
		if (COMBATMODE(ch, COMBAT_CALLED))
			dam += UMIN(stat_bonus(TRUE, ch, APPLY_DEX), base_attack(ch));
	}
	else
	{
		if (COMBATMODE(ch, COMBAT_POWER))
		{
			if (wield && (is_light_weapon(ch, wield) || WEAR_LOC(wield, WEAR_DUAL_WIELD)))
				dam += UMIN(stat_bonus(TRUE, ch, APPLY_STR), base_attack(ch)) / 2;
			else if (wield && WEAR_LOC(wield, WEAR_BOTH_HANDS))
				dam += UMIN(stat_bonus(TRUE, ch, APPLY_STR), base_attack(ch)) * 2;
			else
				dam += UMIN(stat_bonus(TRUE, ch, APPLY_STR), base_attack(ch));
		}
		else if (learned(ch, gsn_precise_strike) && !IS_AFFECTED(ch, AFF2_BERSERK) && CAN_CRITICAL(victim) && (!is_affected(victim, gsn_defensive_stance) || !learned(victim, gsn_impenetrable_defense)))
		{
			if (wield && (is_light_weapon(ch, wield) || WSPEC(wield, WSPEC_FINESSE))
			&& wield2 == NULL && shield == NULL)
			{
				dam += dice (multi_class_level(ch, gsn_precise_strike)/5, 6);
			}
		}
	}
	
	if (victim != NULL)
	{
		/* paladin/blackguard smite ability */
		if (is_affected(victim, gsn_smite) && get_caster(victim, gsn_smite) == ch)
		{
			if (race_type(victim) == RTYPE_OUTSIDER
			|| race_type(victim) == RTYPE_DRAGON
			|| race_type(victim) == RTYPE_UNDEAD)
				dam += multi_class_level(ch, gsn_smite) * 2;
			else
				dam += multi_class_level(ch, gsn_smite);
		}
		if (is_affected(ch, gsn_retributive_strike) && ch->last_attacker && ch->last_attacker == victim)
		{
			dam += class_level(ch, CLASS_CLERIC);
		}
		if (is_affected(ch, gsn_divine_wrath))
		{
			dam += UMAX(1, stat_bonus(TRUE, ch, APPLY_CHA));
		}
		/* ranger favored enemy bonus */
		dam += fave_enemy_bonus(ch, victim);
	}
	
	if (IS_UNDERWATER(ch) && !IS_AFFECTED(ch, AFF_FREEDOM))
		dam /= 2;

	pop_call();
	return(UMAX(1,dam));
}

int weapon_tohit_bonus( OBJ_DATA *wield )
{
	push_call("weapon_tohit_bonus(%p)",wield);
	
	if (!IS_WEAPON(wield) && !IS_AMMO(wield))
	{
		pop_call();
		return 0;
	}
	if (!wield->apply[APPLY_HITROLL] && IS_OBJ_STAT(wield, ITEM_MASTERWORK))
	{
		pop_call();
		return 1;
	}
	pop_call();
	return wield->apply[APPLY_HITROLL];
}

int weapon_dam_bonus( OBJ_DATA *wield )
{
	push_call("weapon_enhance_bonus(%p)",wield);
	
	if (!IS_WEAPON(wield) && !IS_AMMO(wield))
	{
		pop_call();
		return 0;
	}
	pop_call();
	return wield->apply[APPLY_DAMROLL];
}


/* 
 * Count only permanent weapon bonus
 * because only permanent enchantment breaks other DR - Kregor
 */
int actual_tohit_bonus( OBJ_DATA *wield )
{
	AFFECT_DATA *paf;
	int mod = 0;

	push_call("actual_tohit_bonus(%p)",wield);
	
	for (paf = wield->first_affect ; paf ; paf = paf->next)
	{
		if (paf->location == APPLY_HITROLL)
		{
			if (paf->modifier <= 0 || paf->duration >= 0)
			{
				continue;
			}
			mod = UMAX(mod, paf->modifier);
		}
	}
	pop_call();
	return mod;
}


/*
 * returns the miss chance for an attack
 * against a concealed/hidden target
 * -1 means can't miss - Kregor
 */
int can_miss( CHAR_DATA *ch, CHAR_DATA *victim, int dt, bool fRanged, OBJ_DATA *wield )
{
	int miss = -1;
	push_call("can_miss(%p,%p,%p,%p,%p)",ch,victim,dt,fRanged,wield);
	
	//ethereal creatures cannot affect or be affected by non-ethereal
	if ((CAN_ETHEREAL_WALK(ch) && !CAN_ETHEREAL_WALK(victim))
	|| (CAN_ETHEREAL_WALK(victim) && !CAN_ETHEREAL_WALK(ch)))
	{
		pop_call();
		return 100;
	}
	
	if (IS_AFFECTED(ch, AFF_GASEOUS))
	{
		pop_call();
		return 100;
	}
	
	// mundane partial concealment that trumps True Sight
	if (IS_AFFECTED(victim, AFF_HIDE)
	|| IS_BLIND(ch)
	|| IS_SET(ch->in_room->room_flags, ROOM_FOG)
	|| IS_SET(victim->in_room->room_flags, ROOM_FOG)
	|| (learned(victim, gsn_self_concealment) && !IS_FLATFOOTED(victim) && !IS_HELPLESS(victim))
	|| (arcane_mastery(victim, SCHOOL_ILLUSION) && !IS_HELPLESS(victim)))
	{
		miss = 50;
	}
	else if (IS_AFFECTED(ch, AFF_TRUESIGHT))
	{
		pop_call();
		return -1;
	}
	
	if (race_skill(victim, gsn_light_invisibility))
	{
		switch (get_room_light(victim->in_room))
		{
			default:
				break;
			case LIGHT_BRIGHT:
				miss = UMAX(50, miss);
				break;
			case LIGHT_NORMAL:
				miss = UMAX(20, miss);
				break;
			case LIGHT_DARKNESS:
				miss = UMIN(miss, 20);
				break;
		}
	}

	// Light blindness = 50% miss in bright, 20% miss in normal - Kregor
	if (ch->in_room && race_skill(ch, gsn_light_blindness))
	{
		switch (get_room_light(ch->in_room))
		{
			default:
				break;
			case LIGHT_BRIGHT:
				miss = UMIN(miss, 50);
				break;
			case LIGHT_NORMAL:
				miss = UMIN(miss, 20);
				break;
		}
	}

	if (wield && WEAPON_FLAG(wield, WFLAG_SEEKING))
	{
		pop_call();
		return -1;
	}
		
	if (!can_see(ch, victim))
		miss = UMAX(50, miss);
		
	miss = UMAX(get_apply(victim, APPLY_CONCEALMENT), miss);
	
	if (fRanged)
	{
		if (is_affected(victim, gsn_entropic_shield))
			miss = UMAX(20, miss);

		if (learned(ch, gsn_imp_precise_shot))
			miss = -1;
	}
	else
	{
		// blind fight only works against miss chance in melee
		if (miss > 0 && learned(ch,gsn_blind_fight))
			miss /= 2;
	}
	if (is_affected(ch, gsn_true_strike))
		miss = -1;
		
	// blindsight does not require sight at all
	if (race_skill(ch, gsn_blindsight) || domain_apotheosis(ch, DOMAIN_CAVERN))
		miss = -1;
	
	// faerie fire foils concealment
	if (is_affected(victim, gsn_faerie_fire))
		miss = -1;

	pop_call();
	return miss;
}
	
/* 
 * virtually from scratch object damage codes,
 * consistent with d20 guildelines for sundering and
 * failed saves - Kregor
 */
 
/*
 * dmg gets passed thru here for resistancs and vulnerabilities,
 * just like damage_modify for chars
 */
int obj_damage_modify( OBJ_DATA *obj, OBJ_DATA *wield, int dam, int dam_type )
{
	int material, hardness;
	AFFECT_DATA *paf, *paf_next;
	
	push_call("obj_damage_modify(%p,%p,%p,%p)",obj,wield,dam,dam_type);
	
	if (!obj || !wield)
	{
		pop_call();
		return dam;
	}
	
	material = obj->material;
	
	if (IS_SET(material_table[material].vulnerable, dam_type))
		dam *= 2;
	else if (IS_SET(material_table[material].resist_lo, dam_type))
		dam /= 2;
	else if (IS_SET(material_table[material].resist_hi, dam_type))
		dam /= 4;
	else if (IS_SET(material_table[material].immune, dam_type))
		dam = 0;
	
	hardness = material_table[material].hardness;
	hardness += obj->hardness;
	hardness += actual_tohit_bonus(obj) * 2;
	
	/* adamantine bypasses all hardness less than 20 */
	if (wield && wield->material == MATERIAL_ADAMANTINE && hardness < 20)
		hardness = 0;

	if (!IS_SET(material_table[material].vulnerable, dam_type))
		dam -= hardness;
		
	if (dam <= 0)
	{
		pop_call();
		return 0;
	}

	/* 
	 * it stands to reason that one elemental damage weapon is going 
	 * to have at least as much resistance to that element as it deals - Kregor
	 */
	if (WEAPON_FLAG(obj, WFLAG_FLAMING|WFLAG_FLAMING_BURST) && IS_SET(dam_type, DAM_FIRE))
		dam -= 6;
	else if (WEAPON_FLAG(obj, WFLAG_SHOCK|WFLAG_SHOCK_BURST) && IS_SET(dam_type, DAM_ELECTRIC))
		dam -= 6;
	else if (WEAPON_FLAG(obj, WFLAG_FROST|WFLAG_ICY_BURST) && IS_SET(dam_type, DAM_COLD))
		dam -= 6;
	else if (WEAPON_FLAG(obj, WFLAG_VICIOUS) && IS_SET(dam_type, DAM_SONIC))
		dam -= 6;
	else if (WEAPON_FLAG(obj, WFLAG_CAUSTIC) && IS_SET(dam_type, DAM_ACID))
		dam -= 6;

	/* no need to loop thru the effects if there's already no damage left */
	if (dam <= 0)
	{
		pop_call();
		return 0;
	}

	if (obj->first_affect != NULL)
	{
		for ( paf = obj->first_affect; paf != NULL; paf = paf_next )
		{
			paf_next = paf->next;
			
			switch (paf->location)
			{
				case APPLY_DR_FIRE:
					if (IS_SET(dam_type, DAM_FIRE))
						dam -= paf->modifier;
					break;

				case APPLY_DR_ACID:
					if (IS_SET(dam_type, DAM_ACID))
						dam -= paf->modifier;
					break;

				case APPLY_DR_COLD:
					if (IS_SET(dam_type, DAM_COLD))
						dam -= paf->modifier;
					break;

				case APPLY_DR_ELECTRIC:
					if (IS_SET(dam_type, DAM_ELECTRIC))
						dam -= paf->modifier;
					break;

				case APPLY_DR_SONIC:
					if (IS_SET(dam_type, DAM_SONIC))
						dam -= paf->modifier;
					break;

				case APPLY_IMM_FIRE:
					if (IS_SET(dam_type, DAM_FIRE))
						dam = 0;
					break;

				case APPLY_IMM_ACID:
					if (IS_SET(dam_type, DAM_ACID))
						dam = 0;
					break;

				case APPLY_IMM_COLD:
					if (IS_SET(dam_type, DAM_COLD))
						dam = 0;
					break;

				case APPLY_IMM_ELECTRIC:
					if (IS_SET(dam_type, DAM_ELECTRIC))
						dam = 0;
					break;

				case APPLY_IMM_SONIC:
					if (IS_SET(dam_type, DAM_SONIC))
						dam = 0;
					break;
			}
		}
	}
	if (dam <= 0)
	{
		pop_call();
		return 0;
	}
	pop_call();
	return dam;
}

/*
 * currently, only weapons, armor and treasure can be damaged
 * and/or repaired. Mostly what would matter for getting damaged
 * or sundered anyway.
 */
void damage_equipment( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj, int dam, int dt, OBJ_DATA *wield )
{
  int condition;
  int dam_type = DAM_BASH;

	push_call("damage_equipment(%p,%p,%p,%p,%p,%p)",ch,victim,obj,dt,dam,wield);

  if ( obj == NULL )
	{
		pop_call();
		return;
	}

	if ( (obj->item_type != ITEM_WEAPON
	&& obj->item_type != ITEM_ARMOR
	&& obj->item_type != ITEM_TREASURE)
	|| IS_OBJ_STAT(obj, ITEM_INVENTORY) || IS_OBJ_STAT(obj, ITEM_NODROP)) //plot items can't be damaged
	{
		pop_call();
		return;
	}

	if (is_attack(dt))
	{
		if (wield != NULL)
		{
			dam_type = weapon_table[wield->value[0]].dam_type;
		}
	}
	else if (valid_skill(dt))
	{
		dam_type = skill_table[dt].dam_type;
	}
	else
	{
		if (dt != TYPE_UNDEFINED)
		{
			bug("damage_equipment: bad dt %d.", dt);
		}
	}
	
	int wskill = weapon_skill(ch, wield);
	
	if (IS_SET(wskill, WSKILL_SPECIALIZED))
		dam += 2;
	if (IS_SET(wskill, WSKILL_GREATER_SPEC))
		dam += 2;
	if (IS_SET(wskill, WSKILL_EPIC_SPEC))
		dam += 4;
	if (learned(ch, gsn_weapon_mastery) && IS_SET(wskill, WSKILL_FOCUS))
		dam += (multi_skill_level(ch, gsn_weapon_mastery) / 4) + 1;
				
	if (dam > 0)
	{
		if (wield != NULL && IS_WEAPON(wield))
		{
			if (WEAR_LOC(wield, WEAR_BOTH_HANDS))
				dam += stat_bonus(TRUE, ch, APPLY_STR) * 1.5;
			else if (WEAR_LOC(wield, WEAR_DUAL_WIELD))
				dam += stat_bonus(TRUE, ch, APPLY_STR) / 2;
			else
				dam += stat_bonus(TRUE, ch, APPLY_STR);
	
			dam += weapon_dam_bonus(wield);
			dam += get_apply(ch, APPLY_COMP_DAMG);
			dam += get_apply(ch, APPLY_LUCK_DAMG);
			dam += get_apply(ch, APPLY_MOR_DAMG);
		
			if (IS_AFFECTED(ch, AFF2_SICKENED))
				dam -= 2;
			if (COMBATMODE(ch, COMBAT_POWER))
				dam += UMIN(stat_bonus(TRUE, ch, APPLY_STR), base_attack(ch));
			
			//makes sense that anti-alignment weapons would damage weapons of that alignment, doesn't it?
			
			if (WEAPON_FLAG(wield, WFLAG_HOLY))
			{
				if (IS_OBJ_STAT(obj, ITEM_EVIL))
				{
					dam += dice(2, 6);
				}
			}
			if (WEAPON_FLAG(wield, WFLAG_UNHOLY))
			{
				if (IS_OBJ_STAT(obj, ITEM_GOOD))
				{
					dam += dice(2, 6);
				}
			}
			if (WEAPON_FLAG(wield, WFLAG_FLAMING) || WEAPON_FLAG(wield, WFLAG_FLAMING_BURST))
			{
				dam += obj_damage_modify(obj, wield, dice(1, 6), DAM_FIRE);
			}
			if (WEAPON_FLAG(wield, WFLAG_FROST) || WEAPON_FLAG(wield, WFLAG_ICY_BURST))
			{
				dam += obj_damage_modify(obj, wield, dice(1, 6), DAM_COLD);
			}
			if (WEAPON_FLAG(wield, WFLAG_SHOCK) || WEAPON_FLAG(wield, WFLAG_SHOCK_BURST))
			{
				dam += obj_damage_modify(obj, wield, dice(1, 6), DAM_ELECTRIC);
			}
			if (WEAPON_FLAG(wield, WFLAG_VICIOUS))
			{
				dam += obj_damage_modify(obj, wield, dice(1, 6), DAM_SONIC);
			}
			if (WEAPON_FLAG(wield, WFLAG_CAUSTIC))
			{
				dam += obj_damage_modify(obj, wield, dice(1, 6), DAM_ACID);
			}
		}
	}
	
	if ((dam = obj_damage_modify(obj, wield, dam, dam_type)) <= 0)
	{
		pop_call();
		return;
	}

  obj->hit_points -= dam;
  
  if ( obj->hit_points < 0 )
		obj->hit_points = 0;

	if (obj->hit_points > 0)
	{
		if ((condition = what_percent(obj->hit_points, UMAX(1, get_obj_max_hit(obj)))) >= 90)
		{
			act("$p is damaged, but still in great condition.", ch, obj, NULL, TO_CHAR);
			if (victim)
				act("$p is damaged, but still in great condition.", victim, obj, NULL, TO_CHAR);
		}
		else if ( condition >= 70 )
		{
			act("$p is damaged, but is in good condition.", ch, obj, NULL, TO_CHAR);
			if (victim)
				act("$p is damaged, but is in good condition.", victim, obj, NULL, TO_CHAR);
		}
		else if ( condition >= 50 )
		{
			act("$p is damaged and is in fair condition.", ch, obj, NULL, TO_CHAR);
			if (victim)
				act("$p is damaged and is in fair condition.", victim, obj, NULL, TO_CHAR);
		}
		else if ( condition >= 30 )
		{
			act("$p is damaged and in poor condition.", ch, obj, NULL, TO_CHAR);
			if (victim)
				act("$p is damaged and in poor condition.", victim, obj, NULL, TO_CHAR);
		}
		else if ( condition >= 10 )
		{
			act("$p is damaged and in bad condition.", ch, obj, NULL, TO_CHAR);
			if (victim)
				act("$p is damaged and in bad condition.", victim, obj, NULL, TO_CHAR);
		}
		else
		{
			act("$p is damaged and about to fall apart.", ch, obj, NULL, TO_CHAR);
			if (victim)
				act("$p is damaged and about to fall apart.", victim, obj, NULL, TO_CHAR);
		}
	}
	else
	{
		act( "$p is damaged beyond any use.", ch, obj, NULL, TO_ALL);
		SET_BIT( obj->extra_flags, ITEM_BROKEN );
		if (victim && IS_WORN(obj))
			remove_obj(victim, obj->wear_loc, TRUE, FALSE);
	}
	pop_call();
  return;
}


/*
 * For breath weapon attacks by DM chars - Kregor
 */
void do_breath( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg[MAX_INPUT_LENGTH];

	push_call("do_breath(%p,%p)",ch,argument);

	argument = one_argument(argument, arg);

	if (arg[0] == '\0' || (victim = get_char_room(ch, arg)) == NULL)
	{
		if ((victim = who_fighting(ch)) == NULL)
		{
			send_to_char("You are not fighting anyone.\n\r",ch);
			pop_call();
			return;
		}
	}

	if (!check_murder(ch, victim))
	{
		pop_call();
		return;
	}

	CHECK_TURN(ch, victim);

	if (!breath_weapon(ch, victim))
		send_to_char("Try as you might, you cannot muster a breath weapon.\n\r", ch);

	pop_call();
	return;
}


/*
 * Replaces dragon spec_fun - Kregor
 */
bool breath_weapon( CHAR_DATA *ch, CHAR_DATA *victim )
{
	int sn, Breathe;

	push_call("breath_weapon(%p,%p)",ch,victim);

	if (!in_combat(ch))
	{
		pop_call();
		return FALSE;
	}
	if (IS_SET(ch->action, ACTION_STANDARD))
	{
		pop_call();
		return FALSE;
	}
 
	for (Breathe = FALSE, sn = gsn_acid_breath ; sn <= gsn_slow_gas ; sn++)
	{
		if (learned(ch, sn) && (dice(1,4) == 1)) // simulate 1d4 rounds cooldown
		{
			Breathe = TRUE;
			break;
		}
	}
	
	if (!Breathe)
	{
		pop_call();
		return FALSE;
	}

	if (victim == NULL)
	{
		pop_call();
		return FALSE;
	}

	if ((*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim, 0 ))
	{
		TAKE_ACTION(ch, ACTION_STANDARD);
		pop_call();
		return TRUE;
	}
	
	pop_call();
	return FALSE;
}


/*
 * For gaze weapon attacks by DM chars - Kregor
 */
void do_gaze( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg[MAX_INPUT_LENGTH];

	push_call("do_gaze(%p,%p)",ch,argument);

	argument = one_argument(argument, arg);

	if (arg[0] == '\0' || (victim = get_char_room(ch, arg)) == NULL)
	{
		if ((victim = who_fighting(ch)) == NULL)
		{
			send_to_char("You are not fighting anyone.\n\r",ch);
			pop_call();
			return;
		}
	}

	if (is_safe(ch, victim))
	{
		pop_call();
		return;
	}

	if (!check_murder(ch, victim))
	{
		pop_call();
		return;
	}

	CHECK_TURN(ch, victim);

	if (!gaze_attack(ch, victim))
		send_to_char("Even with your best stink eye, you cannot muster a gaze attack.\n\r", ch);

	pop_call();
	return;
}


/*
 * For creatures with gaze attacks.
 */
bool gaze_attack( CHAR_DATA *ch, CHAR_DATA *victim )
{
	AFFECT_DATA af;
	int dc, sn, level;

	push_call("do_gaze(%p,%p)",ch,victim);

	if (IS_SET(ch->action, ACTION_STANDARD))
	{
		pop_call();
		return FALSE;
	}

	if ((sn = gsn_petri_gaze) && !learned(ch, sn))
	{
		if ((sn = gsn_death_gaze) && !learned(ch, sn))
		{
			if ((sn = gsn_fear_gaze) && !learned(ch, sn))
			{
				pop_call();
				return FALSE;
			}
		}
	}
		
	if (!in_combat(ch) || (dice(1,4) != 1)) // simulate 1d4 rounds cooldown
	{
		pop_call();
		return FALSE;
	}

	if (victim == NULL)
	{
		pop_call();
		return FALSE;
	}

	if (!who_fighting(victim) || who_fighting(victim) != ch)
	{
		if (number_percent() > 50)
		{
			pop_call();
			return FALSE;
		}
	}

	level = ch->level;
	dc = (level / 2) + 10;
	dc += stat_bonus(TRUE, ch, APPLY_CHA);

	if (sn == gsn_petri_gaze)
	{
		if (!save_resist(ch, victim, sn, level))
		{
			af.type      = sn;
			af.duration  = -1;
			af.modifier  = 0;
			af.location  = APPLY_NONE;
			af.bittype   = AFFECT_TO_CHAR;
			af.bitvector = AFF2_PETRIFICATION;
			af.level		 = dc;	
			affect_join( ch, victim, &af );
	
			act( "$n freezes and turns to stone!", victim, NULL, NULL, TO_ROOM);
			act( "Your limbs begin to stiffen, then everything goes black!", victim, NULL, NULL, TO_CHAR);
	
			update_pos(victim,-1);
		}
	}
	if (sn == gsn_fear_gaze)
	{
		if (!save_resist(ch, victim, sn, level))
		{
			af.type      = sn;
			af.duration  = dice(1,8);
			af.modifier  = 0;
			af.location  = APPLY_NONE;
			af.bittype   = AFFECT_TO_CHAR;
			af.bitvector = AFF2_FEAR;
			af.level		 = dc;	
			affect_join( ch, victim, &af );
			victim->fear_level += UMIN(3, victim->fear_level + 2);
	
			act( "$n is paralyzed with fear!", victim, NULL, NULL, TO_ROOM);
			act( "You freeze in your tracks with fear!", victim, NULL, NULL, TO_CHAR);
		}
	}
	if (sn == gsn_death_gaze)
	{
		if (!save_resist(ch, victim, sn, level))
		{
			act( "$N falls dead from $n's deadly gaze!", ch, NULL, victim, TO_NOTVICT);
			act( "$N falls dead from your deadly gaze!", ch, NULL, victim, TO_CHAR);
			act( "You die from $n's deadly gaze!", ch, NULL, victim, TO_VICT);
		
			damage(ch, victim, victim->hit + 11, sn, NULL);
		}
	}
	TAKE_ACTION(ch, ACTION_STANDARD);
	pop_call();
	return TRUE;
}