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.     *
 ***************************************************************************/
 
/***************************************************************************
 * skills.c: Functions for skills, abilities and skill checks						   *
 ***************************************************************************/

#include "mud.h"

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

#define turn		10
#define hr			100
#define PARTIAL -1

/* This forces instant incubation of disease in corrupt touch spell */
void	disease_update		args(( CHAR_DATA *ch ));
bool CRIT = FALSE;

/*
 * Return the max uses per day of an ability - Kregor
 *
 * This obviously grows longer as more daily use
 * abilities are added to skill list.
 */
int get_max_uses( CHAR_DATA *ch, int sn )
{
	int uses = 0;
	
	push_call("get_max_uses(%p,%p)",ch,sn);

	if (!learned(ch, sn))
	{
		pop_call();
		return 0;
	}
	if (sn == gsn_lay_hands
	|| sn == gsn_touch_of_courage
	|| sn == gsn_touch_of_grace
	|| sn == gsn_touch_of_profanity
	|| sn == gsn_touch_of_resolve
	|| sn == gsn_touch_of_righteousness
	|| sn == gsn_touch_of_zeal
	|| sn == gsn_corrupt_touch)
	{
		uses = (multi_class_level(ch, gsn_lay_hands) + multi_class_level(ch, gsn_corrupt_touch)) / 4;
		uses += UMAX(0, stat_bonus(FALSE, ch, APPLY_CHA));
	}
	if (sn == gsn_turn_undead
	|| sn == gsn_command_undead
	|| sn == gsn_channeling_attack
	|| sn == gsn_turn_plants
	|| sn == gsn_turn_elemental
	|| sn == gsn_turn_reptiles
	|| sn == gsn_turn_lycanthrope
	|| sn == gsn_turn_outsider)
	{
		uses = 3 + UMAX(0, stat_bonus(FALSE, ch, APPLY_CHA));
		uses += multi_skill_level(ch, sn) / 5;
		if (learned(ch, gsn_extra_turning))
			uses += 4;
	}
	if (sn == gsn_bardic_song)
	{
		uses = multi_class_level(ch, sn);
		uses += UMAX(0, stat_bonus(FALSE, ch, APPLY_CHA));
		if (learned(ch, gsn_extra_song))
			uses += 4;
	}
	if (sn == gsn_stunning_fist)
	{
		uses = 1 + UMAX(ch->level/4, class_level(ch, CLASS_MONK)/2);
	}
	if (sn == gsn_barbarian_rage)
	{
		uses = multi_skill_level(ch, sn) / 4 + 1 + UMAX(0, stat_bonus(FALSE, ch, APPLY_CON));
	}
	if (sn == gsn_defensive_stance)
	{
		uses = ROUNDUP(multi_skill_level(ch, sn) / 2);
	}
	if (sn == gsn_divine_refuge)
	{
		uses = multi_class_level(ch, sn) / 4 + 1;
	}
	if (sn == gsn_divine_veil)
	{
		uses = ROUNDUP(multi_skill_level(ch, sn) / 2);
	}
	if (sn == gsn_divine_location)
	{
		uses = ROUNDUP(multi_skill_level(ch, sn) / 2);
	}
	if (sn == gsn_wildshape)
	{
		uses = multi_skill_level(ch, sn) / 2 + 1;
	}
	if (sn == gsn_smite || sn == gsn_destructive_smite || sn == gsn_smite_infidel)
	{
		uses = multi_skill_level(ch, sn) / 4 + 1;
	}
	if (sn == gsn_retributive_strike)
	{
		uses = class_level(ch, CLASS_CLERIC) / 5 + 1;
	}
	if (sn == gsn_defensive_roll)
	{
		uses = 1;
	}
	if (sn == gsn_shadow_companion)
	{
		uses = 1;
	}
	if (sn == gsn_shadow_jump)
	{
		uses = multi_skill_level(ch, gsn_shadow_jump) / 2;
	}
	if (sn == gsn_abundant_step || sn == gsn_empty_body)
	{
		uses = class_level(ch, CLASS_MONK) >= 20 ? 3 : class_level(ch, CLASS_MONK) >= 16 ? 2 : 1;
	}
	if (sn == gsn_shadow_illusion)
	{
		uses = multi_skill_level(ch, gsn_shadow_illusion) / 2;
	}
	if (sn == gsn_shadow_bolt)
	{
		uses = multi_skill_level(ch, gsn_shadow_bolt) / 3 + 1;
	}
	if (sn == gsn_energy_arrow)
	{
		uses = ((class_level(ch, CLASS_ARCANE_ARCHER) - 6) / 2 + 1);
	}
	if (sn == gsn_seeker_arrow)
	{
		uses = ((class_level(ch, CLASS_ARCANE_ARCHER) - 4) / 2 + 1);
	}
	if (sn == gsn_pilfer_dweomer)
	{
		uses = ((class_level(ch, CLASS_ARCANE_TRICKSTER) - 1) / 4 + 1);
	}
	if (sn == gsn_impromptu_sneak_attack)
	{
		if (class_level(ch, CLASS_ARCANE_TRICKSTER) >= 7)
			uses = 2;
		else
			uses = 1;
	}
	if (sn == gsn_death_arrow)
	{
		uses = 1;
	}
	pop_call();
	return uses;
}

/*
 * groups enhanced class abilities under parent ability's uses - Kregor
 */
void add_uses( CHAR_DATA *ch, int sn )
{
	push_call("add_uses(%p,%p)",ch,sn);
	
	if (sn == gsn_turn_undead
	|| sn == gsn_command_undead
	|| sn == gsn_turn_plants
	|| sn == gsn_turn_elemental
	|| sn == gsn_turn_reptiles
	|| sn == gsn_channeling_attack
	|| sn == gsn_turn_lycanthrope
	|| sn == gsn_turn_outsider)
	{
		sn = gsn_turn_undead;
	}
	ch->uses[sn]++;
	
	pop_call();
	return;
}


/*
 * Check get_max_uses against spent uses of ability - Kregor
 */
bool CHECK_USES( CHAR_DATA *ch, int sn)	
{
	int uses;

	push_call("CHECK_USES(%p,%p)",ch,sn);

	if ((uses = get_max_uses(ch, sn)) <= 0)
	{
		pop_call();
		return TRUE;
	}
	if (ch->uses[sn] >= uses)
	{
		ch_printf_color( ch, "You can't use your %s ability without resting.\n\r", skill_table[sn].name );
		pop_call();
		return FALSE;
	}
	wiz_printf("check uses (%s): uses %d, max %d.", skill_table[sn].name, ch->uses[sn], uses);
	pop_call();
	return TRUE;
}

/*
 * functions to allow for taking 10 and 20 in skill rolls - Kregor
 */
int take_ten( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	
	if (IS_AFFECTED( ch, AFF2_FASCINATED))
	{
		pop_call();
		return (roll);
	}

	if (in_combat(ch))
	{
		pop_call();
		return (roll);
	}
	
	if (ch->distracted)
	{
		pop_call();
		return (roll);
	}

	roll = UMAX(10, roll);

	pop_call();
	return (roll);
}


int take_twenty( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	
	if (IS_AFFECTED( ch, AFF2_FASCINATED))
	{
		pop_call();
		return (roll);
	}

	if (in_combat(ch))
	{
		pop_call();
		return (roll);
	}
	
	if (ch->distracted)
	{
		pop_call();
		return (roll);
	}

	pop_call();
	return 20;
}

/*
	Dupes the same const char as in magic.c for spell like abilities - Kregor
*/
char * target_name;
char * origarg;

/*
 * Trivial hack of original do_cast function for
 * using class special abilities - Kregor
 */
void do_activate( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char arg3[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	OBJ_DATA *obj, *symbol;
	void *vo;
	bool ranged = FALSE;
	int sn, level, target, dir, range;

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

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

	origarg			= argument;
	argument 		= snarf_skill_name(argument, arg1);
	target_name = argument;
	argument    = one_argument( argument, arg2 );

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

	sn = skill_lookup( arg1 );

	if (skill_table[sn].skilltype == FSKILL_SPELL)
	{
		cast_spell(ch, origarg, TRUE);
		pop_call();
		return;
	}
	if (skill_table[sn].skilltype != FSKILL_ABILITY
	&& skill_table[sn].skilltype != FSKILL_FEAT)
	{
		if (!IS_NPC(ch) && ch->desc == NULL)
		{
			log_printf("[%u] using unknown ability: %s", ch->pIndexData->vnum, arg1);
		}
		send_to_char( "That is not a special ability.\n\r", ch );
		pop_call();
		return;
	}
	
	if (!skill_table[sn].spell_fun || skill_table[sn].spell_fun == spell_null)
	{
		ch_printf_color(ch, "That ability cannot be activated.\n\r");
		pop_call();
		return;
	}

	if (!learned(ch, sn))
	{
		ch_printf_color(ch, "You are not able to use that ability.\n\r");
		pop_call();
		return;
	}

	if ((level = multi_skill_level(ch, sn)) == -1)
	{
		ch_printf_color(ch, "You are not able to use that ability.\n\r");
		pop_call();
		return;
	}

	if (IS_SET(ch->action, ACTION_STANDARD) && skill_table[sn].beats >= CASTING_STANDARD)
	{	
		ch_printf_color(ch, "You have already made a standard action this round.\n\r");
		pop_call();
		return;
	}
	if (IS_SET(ch->action, ACTION_SWIFT) && skill_table[sn].beats == CASTING_SWIFT)
	{	
		ch_printf_color(ch, "You have already made a swift action this round.\n\r");
		pop_call();
		return;
	}
	
	if (is_safe_magic(ch, NULL, sn))
	{
		pop_call();
		return;
	}

	/*
	 * Determine whether it's a ranged affect or not
	 */
	if (*arg2 != '\0'
	&& skill_table[sn].target != TAR_IGNORE
	&& skill_table[sn].target != TAR_CHAR_SELF
	&& skill_table[sn].target != TAR_OBJ_INV
	&& skill_table[sn].target != TAR_OBJ_ROOM
	&& skill_table[sn].target != TAR_OBJ_WIELD)
	{
		if ((dir = direction_door(arg2)) != -1)
		{
			ranged = TRUE;
			target_name = argument;
			argument    = one_argument( argument, arg2 );
			argument    = one_argument( argument, arg3 );
		}
	}
	else
	{
		argument    = one_argument( argument, arg3 );
	}

	if (ranged && !is_valid_exit(ch, ch->in_room, dir))
	{
		send_to_char( "You cannot target in that direction.\n\r", ch );
		pop_call();
		return;
	}

	if (ranged && (range = get_spell_range(level, sn)) <= 0)
	{	
		ch_printf_color(ch, "That ability cannot be activated at that range.\n\r");
		pop_call();
		return;
	}
	
	if (!CHECK_USES(ch, sn))
	{
		pop_call();
		return;
	}

	if (IS_SET(skill_table[sn].flags, SF_DIVINEFOCUS) && !IS_NPC(ch) && (!IS_GOD(ch) || !IS_PLR(ch, PLR_HOLYLIGHT)))
	{
		if ((symbol = get_obj_wear_type(ch, ITEM_SYMBOL)) == NULL)
		{
			send_to_char( "You don't have your holy symbol.\n\r", ch);
			pop_call();
			return;
		}
	
		if (symbol->value[2] != ch->god)
		{
			send_to_char( "You need have your OWN deity's symbol!\n\r", ch);
			pop_call();
			return;
		}
	}
	
	/*
		Locate targets.
	*/
	victim	= NULL;
	obj		= NULL;
	vo		= NULL;
	target	= skill_table[sn].target;
	
	if (ranged)
	{
		switch (target)
		{
			default:
				send_to_char( "That ability cannot be activated at range!\n\r", ch );
				pop_call();
				return;
			case TAR_CHAR_OFFENSIVE:
			case TAR_CHAR_DEFENSIVE:
			case TAR_UNDEAD_OFF:
			case TAR_UNDEAD_DEF:
			case TAR_OBJ_CHAR_OFF:
			case TAR_OBJ_CHAR_DEF:
				break;
		}
	}
				
	switch (target)
	{
		default:
			bug( "do_activate: bad target for sn %d.", sn );
			pop_call();
			return;

		case TAR_IGNORE:
			break;

		case TAR_CHAR_OFFENSIVE:
			if (arg2[0] == '\0')
			{
				if (who_fighting(ch) == NULL)
				{
					send_to_char( "Use this ability on whom?\n\r", ch );
					pop_call();
					return;
				}
				victim = who_fighting(ch);
			}
			else
			{
				if (ranged)
				{
					if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
					{
						send_to_char("Your target must have slipped out of sight!\n\r", ch);
						pop_call();
						return;
					}
				}
				else if ((victim = get_char_room(ch, arg2)) == NULL)
				{
					send_to_char( "Your target isn't here.\n\r", ch );
					pop_call();
					return;
				}
			}
			if (is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}
			vo = (void *) victim;
			break;

		case TAR_UNDEAD_OFF:
			if (arg2[0] == '\0')
			{
				if ((victim = who_fighting(ch)) == NULL || !IS_UNDEAD(who_fighting(ch)))
				{
					if (IS_UNDEAD(ch))
					{
						send_to_char( "Use this ability on whom?\n\r", ch );
						pop_call();
						return;
					}
					else
					{
						victim = ch;
					}
				}
			}
			else
			{
				if (ranged)
				{
					if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
					{
						send_to_char("Your target must have slipped out of sight!\n\r", ch);
						pop_call();
						return;
					}
				}
				else if ((victim = get_char_room(ch, arg2)) == NULL)
				{
					send_to_char( "Your target isn't here.\n\r", ch );
					pop_call();
					return;
				}
			}
			if (IS_UNDEAD(victim) && is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}
			vo = (void *) victim;
			if (IS_UNDEAD(victim))
				target = TAR_CHAR_OFFENSIVE;
			else
				target = TAR_CHAR_DEFENSIVE;
			break;

		case TAR_CHAR_DEFENSIVE:
			if (arg2[0] == '\0')
			{
				victim = ch;
			}
			else
			{
				if (ranged)
				{
					if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
					{
						send_to_char("Your target must have slipped out of sight!\n\r", ch);
						pop_call();
						return;
					}
				}
				else if ((victim = get_char_room(ch, arg2)) == NULL)
				{
					send_to_char( "Your target isn't here.\n\r", ch );
					pop_call();
					return;
				}
			}
			if (is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}
			vo = (void *) victim;
			break;

		case TAR_UNDEAD_DEF:
			if (arg2[0] == '\0')
			{
				if ((victim = who_fighting(ch)) == NULL || IS_UNDEAD(who_fighting(ch)))
				{
					if (!IS_UNDEAD(ch))
					{
						send_to_char( "Use this ability on whom?\n\r", ch );
						pop_call();
						return;
					}
					else
					{
						victim = ch;
					}
				}
			}
			else
			{
				if (ranged)
				{
					if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
					{
						send_to_char("Your target must have slipped out of sight!\n\r", ch);
						pop_call();
						return;
					}
				}
				else if ((victim = get_char_room(ch, arg2)) == NULL)
				{
					send_to_char( "Your target isn't here.\n\r", ch );
					pop_call();
					return;
				}
			}
			if (!IS_UNDEAD(victim) && is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}
			vo = (void *) victim;
			if (!IS_UNDEAD(victim))
				target = TAR_CHAR_OFFENSIVE;
			else
				target = TAR_CHAR_DEFENSIVE;
			break;

		case TAR_CHAR_SELF:
			if (ranged)
			{
				send_to_char( "You activate this ability at range.\n\r", ch );
				pop_call();
				return;
			}
			if (arg2[0] == '\0' || is_name_short(arg2, ch->name))
			{
				victim = ch;
			}
			if (ch != victim && is_safe_magic(ch, victim, sn))
			{
				pop_call();
				return;
			}			
			vo = (void *) victim;
			break;

		case TAR_OBJ_INV:
			if (arg2[0] == '\0')
			{
				send_to_char( "What should the ability be activated upon?\n\r", ch );
				pop_call();
				return;
			}
			if ((obj = get_obj_carry(ch, arg2)) == NULL)
			{
				if ((obj = get_obj_wear(ch, arg2)) == NULL)
				{
					send_to_char( "You are not carrying that.\n\r", ch );
					pop_call();
					return;
				}
			}
			vo = (void *) obj;
			break;

		case TAR_OBJ_WIELD:
			if (arg2[0] == '\0')
			{
				if ((obj = get_wield(ch, FALSE)) == NULL)
				{
					send_to_char( "What should the ability be activated upon?\n\r", ch );
					pop_call();
					return;
				}
			}
			if ((obj = get_obj_wear(ch, arg2)) == NULL)
			{
				send_to_char( "You are not holding that.\n\r", ch );
				pop_call();
				return;
			}
			vo = (void *) obj;
			break;

		case TAR_OBJ_ROOM:
			if (arg2[0] == '\0')
			{
				send_to_char( "What should the ability be activated upon?\n\r", ch );
				pop_call();
				return;
			}
			if ((obj = get_obj_here(ch, arg2)) == NULL)
			{
				send_to_char( "That item does not seem to be here.\n\r", ch );
				pop_call();
				return;
			}
			vo = (void *) obj;
			break;

		case TAR_OBJ_CHAR_DEF:
			if (arg2[0] == '\0')
			{
				victim = ch;
			}
			else if ((victim = get_char_room(ch, arg2)) == NULL)
			{
				if ((obj = get_obj_carry(ch, arg2)) == NULL)
				{
					send_to_char( "Who or what should the ability be activated upon?\n\r", ch );
					pop_call();
					return;
				}
			}
			if (victim)
			{
				if (is_safe_magic(ch, victim, sn))
				{
					pop_call();
					return;
				}
				target = TAR_CHAR_DEFENSIVE;
				vo     = (void *) victim;
			}
			else
			{
				if (ranged)
				{
					send_to_char( "That item does not seem to be here.\n\r", ch );
					pop_call();
					return;
				}
				target = TAR_OBJ_INV;
				vo     = (void *) obj;
			}
			break;

		case TAR_OBJ_CHAR_OFF:

			if (arg2[0] == '\0')
			{
				if (who_fighting(ch) == NULL)
				{
					send_to_char("Cast the spell on whom?\n\r", ch);
					pop_call();
					return;
				}
				victim = who_fighting(ch);
			}
			else if ((victim = get_char_room(ch, arg2)) == NULL)
			{
				if ((obj = get_obj_carry(ch, arg2)) == NULL)
				{
					send_to_char( "Who or what should the ability be activated upon?\n\r", ch );
					pop_call();
					return;
				}
			}

			if (victim)
			{
				if (is_safe_magic(ch, victim, sn))
				{
					pop_call();
					return;
				}
				target = TAR_CHAR_OFFENSIVE;
				vo     = (void *) victim;
			}
			else
			{
				if (ranged)
				{
					send_to_char( "That item does not seem to be here.\n\r", ch );
					pop_call();
					return;
				}
				target = TAR_OBJ_INV;
				vo     = (void *) obj;
			}
			break;
	}
	
	if (ranged && findpath_search_victim(ch, victim, range) == -1)
	{
		send_to_char("That target is out of your reach.\n\r", ch);
		pop_call();
		return;
	}
	
	if (target == TAR_CHAR_OFFENSIVE)
	{
		if (!in_combat(ch) || !in_combat(victim))
		{
			fight(ch, victim);
		}
	}
	
	CHECK_TURN(ch, victim);
	
	switch (skill_table[sn].minimum_position)
	{
		case POS_FIGHTING:
			if (ch->position < POS_FIGHTING)
			{
				act("You might want to be standing up to do that.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return;
			}
			break;
		case POS_STANDING:
			if (in_combat(ch))
			{
				act("You cannot do that in combat.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return;
			}
			if (ch->position < POS_FIGHTING)
			{
				act("You might want to be standing up to do that.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return;
			}
			break;
		default:
			if (ch->position < skill_table[sn].minimum_position)
			{
				act("You're too relaxed to do that.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return;
			}
			break;
	}
	
	// give concentration delay and AoO for spell-like abilities
	if (IS_SET(skill_table[sn].flags, SF_SPELL_LIKE) && !ch->concentrating)
	{
		act( "$n starts to concentrate...", ch, NULL, NULL, TO_ROOM );
		act( "You concentrate to activate an ability...", ch, NULL, NULL, TO_CHAR );
		ch->concentrating = TRUE;
		ch->skill_timer		= skill_table[sn].beats;
		ch->timer_fun			= do_activate;
		RESTRING(ch->cmd_argument, origarg);
		pop_call();
		return;
	}

	if (IS_SET(skill_table[sn].flags, SF_SPELL_LIKE))
	{
		if (IS_ENTANGLED(ch) || drunk_level(ch) >= DRUNK_TIPSY || is_affected(ch, gsn_insect_plague) || ch->grappling || ch->grappled_by)
		{
			int diceroll = concentration_roll(ch);
			int DC;
			
			if (ch->grappled_by)
				DC = 10 + combat_maneuver_bonus(ch->grappled_by) + skill_table[sn].native_level;
			else
				DC = 15 + skill_table[sn].native_level;
				
			if (!concentration_check(ch, victim, diceroll, DC))
			{
				send_to_char_color("{138}You lost your concentration!\n\r", ch);
				ch->uses[sn]++;
				pop_call();
				return;
			}
		}
	}

	bool fTouch = TRUE;
	
	if (victim != NULL && victim != ch && IS_SET(skill_table[sn].flags, SF_TOUCH))
	{
		switch (target)
		{
			case TAR_CHAR_OFFENSIVE:
				if(!check_hit(ch, victim, dice(1,20), 0, sn, NULL, TRUE, FALSE))
				{
					act( "You attempt to touch $N, but miss.", ch, NULL, victim, TO_CHAR);
					act( "$n attempts to touch $N, but misses.", ch, NULL, victim, TO_NOTVICT);
					act( "$n attempts to touch you, but misses.", ch, NULL, victim, TO_VICT);
					fTouch = FALSE;
				}
				break;
			case TAR_CHAR_DEFENSIVE:
				if((in_combat(victim) || in_combat(ch) || IS_AFFECTED(victim, AFF2_CONFUSION))
				&& !check_hit(ch, victim, dice(1,20), 0, sn, NULL, TRUE, FALSE))
				{
					act( "You attempt to touch $N, but miss.", ch, NULL, victim, TO_CHAR);
					act( "$n attempts to touch $N, but misses.", ch, NULL, victim, TO_NOTVICT);
					act( "$n attempts to touch you, but misses.", ch, NULL, victim, TO_VICT);
					fTouch = FALSE;
				}
				break;
		}
	}

	if (fTouch)
	{
		if ((*skill_table[sn].spell_fun) (sn, level, ch, vo, target))
		{
			add_uses(ch, sn);
			//abilities can trigger cast progs too
			mprog_cast_trigger(ch, victim, sn);
			oprog_cast_trigger(ch, obj, sn);
			rprog_cast_trigger(ch, sn);
		}
		else
		{
			pop_call(); // if ability errors out, don't expend uses
			return;
		}
	}
	
	if (skill_table[sn].beats == CASTING_SWIFT)
		TAKE_ACTION(ch, ACTION_SWIFT);
	else if (skill_table[sn].beats == CASTING_STANDARD)
		TAKE_ACTION(ch, ACTION_STANDARD);
	else if (skill_table[sn].beats == CASTING_ROUND)
		TAKE_ACTION(ch, ACTION_FULL);

	pop_call();
	return;
}

 
/*
 * Appraise skill D20 - Kregor 5/12/07
 * Kept PFRPG beta mechanic that varies DC based on value,
 * appraise + detect magic/identify can identify magic items
 */
void do_appraise( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	OBJ_DATA *obj;
	int cost, diceroll, DC;

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

	one_argument( argument, arg );

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

	if ((obj = get_obj_carry(ch, arg)) == NULL)
	{
		send_to_char_color("You don't have that item.\n\r", ch);
		pop_call();
		return;
	}
	
	if (!ch->concentrating)
	{
		act( "$n sets to appraising $p.", ch, obj, NULL, TO_ROOM );
		act( "You set to appraising $p.", ch, obj, NULL, TO_CHAR );
		ch->concentrating = TRUE;
		ch->skill_timer		= 12;
		ch->timer_fun			= do_appraise;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_STANDARD);
		pop_call();
		return;
	}
	
	if ((cost = obj->cost) <= 10000)
		DC = 5;
	else if (cost <= 50000)
		DC = 10;
	else if (cost <= 100000)
		DC = 15;
	else if (cost <= 500000)
		DC = 20;
	else if (cost <= 1000000)
		DC = 25;
	else
		DC = 30;

	if (IS_OBJ_STAT(obj,ITEM_MAGIC))
	{
		if(!learned(ch, gsn_appraise))
		{
			act( "{178}You cannot even begin to appraise $p correctly.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		if (!domain_apotheosis(ch, DOMAIN_TRADE) && !domain_apotheosis(ch, DOMAIN_MAGIC) && !CAN_SEE_MAGIC(ch) && !is_affected(ch, gsn_analyze_dweomer) && !is_affected(ch, gsn_identify))
		{
			act( "{178}You are not affected with a means to detect magic.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		DC = 15 + obj_level_estimate(obj->pIndexData);
		diceroll = appraise_roll(ch, obj);
		
		if (domain_apotheosis(ch, DOMAIN_MAGIC) || is_affected(ch, gsn_identify))
			diceroll += 10;

		diceroll += synergy_bonus(ch, gsn_spellcraft);
		diceroll += synergy_bonus(ch, gsn_know_arcana);
		diceroll += multi_class_level(ch, gsn_lore) / 2;

		if (diceroll < DC && !domain_apotheosis(ch, DOMAIN_TRADE) && !domain_apotheosis(ch, DOMAIN_MAGIC) && !is_affected(ch, gsn_analyze_dweomer))
		{
			act( "{178}You cannot even begin to appraise $p correctly.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		if (!obj->identified)
			obj->identified = TRUE;
	}
	else if ((diceroll = appraise_roll(ch,obj)) + 5 < DC)
	{
		act( "{178}You cannot even begin to appraise $p correctly.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return;
	}
	else if (diceroll < DC)
		cost = cost * (dice(1, 40) + 80) / 100;

	show_examine_string(obj, ch);
	
	sprintf(buf, "%s {300}is worth approximately %s.\n\r", obj->short_descr, format_coins(cost,TRUE));
	if (IS_OBJ_STAT(obj,ITEM_MASTERWORK))
		cat_sprintf(buf, "{178}it is a masterwork item.\n\r");
	send_to_char_color(buf, ch);
	pop_call();
	return;
}

/*
 * AID command uses the First Aid skill. hit points are only 
 * restored with a first aid kit. Only the stabilizing
 * option can be done while in combat. Each treatment
 * type takes a separate use of the AID command. - Kregor
 */
void do_aid( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	AFFECT_DATA *paf;
	char arg[MAX_INPUT_LENGTH];
	bool healed = FALSE;
	bool HasKit = TRUE;
	OBJ_DATA *kit;
	int diceroll, dc;
	int heal = 0;

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

	one_argument(argument, arg);

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

	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		send_to_char("That person doesn't seem to be here.\n\r", ch);
		pop_call();
		return;
	}
	
	if (victim->hit >= get_max_hit(victim) && !IS_POISONED(victim)
	&& victim->nonlethal < victim->hit
	&& ch->position > POS_STUNNED && !is_affected(ch, gsn_bleed_damage)
	&& !IS_DISEASED(victim))
	{
		act( "$N does not need your aid.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if ((kit = get_obj_carry_type(ch, ITEM_TOOLS)) == NULL || !TOOL_TYPE(kit, TOOL_FIRSTAID_KIT))
	{
		HasKit = FALSE;
		if (!is_handy(ch) || hands_full(ch))
		{
			send_to_char( "You have no free hand to do that.\n\r", ch );
			pop_call();
			return;
		}
	}
	
	if (in_combat(ch))
	{
		if (victim->position > POS_MORTAL && !IS_AFFECTED(victim, AFF2_BLEEDING))
		{
			act("You may only treat the critically wounded while in combat.", ch, NULL, NULL, TO_CHAR);
			pop_call();
			return;
		}
	}

	CHECK_TURN(ch, victim);
	
	// making this a concentration skill means you can get interrupted and spoiled
	if (!ch->concentrating)
	{
		if (ch == victim)
		{
			act( "You tend to your health...", ch, NULL, victim, TO_CHAR);
			act( "$n tends to $s health...", ch, NULL, victim, TO_ROOM);
		}
		else
		{
			act( "You tend to $N's health...", ch, NULL, victim, TO_CHAR);
			act( "$n tends to $N health...", ch, NULL, victim, TO_NOTVICT);
			act( "$n tends to your health...", ch, NULL, victim, TO_VICT);
		}
		ch->concentrating = TRUE;
		ch->skill_timer		= in_combat(ch) ? 36 : 8;
		ch->timer_fun			= do_aid;
		RESTRING(ch->cmd_argument, argument);
		if (in_combat(ch))
			TAKE_ACTION(ch, ACTION_STANDARD);
		else
			TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}
	
	diceroll = first_aid_roll(ch);

	if (victim->position <= POS_INCAP
	|| is_affected(victim, gsn_bleed_damage))
	{
		// DC is harder the more hurt or bleeding the victim is - Kregor
		dc = 10;
		if (victim->hit < 0)
			dc -= victim->hit;
		if ((paf = get_affect_sn(victim, gsn_bleed_damage)) != NULL)
			dc += paf->modifier;

		if ((heal = first_aid_check(ch, NULL, diceroll, dc)) >= 0)
		{
			if (ch == victim)
			{
				act( "{138}You bind your wounds.",ch, NULL, victim, TO_CHAR);
				act( "{138}$n binds $s wounds.",ch, NULL, victim, TO_ROOM);
			}
			else
			{
				act( "{138}You bind $N's wounds.",ch, NULL, victim, TO_CHAR);
				act( "{138}$n binds $N's wounds.",ch, NULL, victim, TO_NOTVICT);
				act( "{138}$n binds your wounds.",ch, NULL, victim, TO_VICT);
			}
			if (is_affected(victim, gsn_bleed_damage))
			{
				affect_strip(victim, gsn_bleed_damage);
				healed = TRUE;
			}
			if (victim->position <= POS_INCAP)
			{
				victim->hit = 0;
				act( "You are stabilized.", victim, NULL, NULL, TO_CHAR);
				act( "$n is stabilized.", victim, NULL, NULL, TO_ROOM);
				healed = TRUE;
			}
			if (HasKit)
			{
				victim->hit = UMIN(victim->hit + heal, get_max_hit(victim));
				victim->nonlethal = UMAX(0, victim->nonlethal - heal);
				healed = TRUE;
			}
		}
	}
	
	else if (ch != victim && IS_AFFECTED(victim, AFF2_STUNNED))
	{
		if (diceroll >= 15)
		{
			AFFECT_STRIP(victim, AFF2_STUNNED);
			act( "{138}You help $N come to.",ch, NULL, victim, TO_CHAR);
			act( "{138}$n helps $N come to.",ch, NULL, victim, TO_NOTVICT);
			act( "{138}$n helps you come to.",ch, NULL, victim, TO_VICT);
			healed = TRUE;
		}
	}

	else if (is_affected(victim, gsn_poison) || victim->poison != NULL)
	{
		if (!HasKit)
		{
			act("You cannot treat poison without a first aid kit.", ch, NULL, NULL, TO_CHAR);
			pop_call();
			return;
		}
		if (is_affected(victim, gsn_poison) && diceroll >= 10 + get_affect_level(victim, gsn_poison))
		{
			affect_strip(victim, gsn_poison);
			healed = TRUE;
		}
	
		if (victim->poison != NULL)
		{
			POISON_DATA *npd, *pd;
	
			if (diceroll >= (victim->poison->dc ? victim->poison->dc : poison_table[victim->poison->type].dc))
			{
				pd = victim->poison;
				victim->poison = NULL;
		
				while (pd != NULL)
				{
					npd = pd->next;
					FREEMEM( pd );
					pd = npd;
				}
				act( "{138}$N's color begins to return as poison cleanses from $M.", victim, NULL, NULL, TO_ROOM);
				act( "{138}You feel better as poison cleanses from you.", victim, NULL, NULL, TO_CHAR);
				healed = TRUE;
			}
			else if (victim == ch)
			{
				act( "{028}You try to cure your poison, with little results.", ch, NULL, victim, TO_CHAR);
			}
			else
			{
				act( "{028}You try to cure $N's poison, with little results.", ch, NULL, victim, TO_CHAR);
			}
		}
	}
	
	else if (IS_DISEASED(victim))
	{
		DISEASE_DATA *dis;
		
		if (!HasKit)
		{
			act("You cannot treat disease without a first aid kit.", ch, NULL, NULL, TO_CHAR);
			pop_call();
			return;
		}
		for (dis = victim->first_disease ; dis != NULL ; dis = dis->next)
		{
			if ((dis->dc && diceroll >= dis->dc) || (!dis->dc && diceroll >= disease_table[dis->type].dc))
			{
				disease_from_char(victim, dis);
				act( "{138}$N shows signs of recovery from $S malady.", victim, NULL, NULL, TO_ROOM);
				act( "{138}You begin to feel signs of recovery from your malady.", victim, NULL, NULL, TO_CHAR);
				healed = TRUE;
			}
			else if (victim == ch)
			{
				act( "{028}Disease still holds fast in your system.", ch, NULL, victim, TO_CHAR);
			}
			else
			{
				act( "{028}Disease still holds fast in $N's system.", ch, NULL, victim, TO_CHAR);
			}
		}
	}
	
	else if (victim->hit < get_max_hit(victim) || victim->nonlethal > 0)
	{
		if ((heal = first_aid_check(ch, NULL, diceroll, 20)) >= 0)
		{
			if (ch == victim)
			{
				act( "{138}You bind your wounds.",ch, NULL, victim, TO_CHAR);
				act( "{138}$n binds $s wounds.",ch, NULL, victim, TO_ROOM);
			}
			else
			{
				act( "{138}You bind $N's wounds.",ch, NULL, victim, TO_CHAR);
				act( "{138}$n binds $N's wounds.",ch, NULL, victim, TO_NOTVICT);
				act( "{138}$n binds your wounds.",ch, NULL, victim, TO_VICT);
			}
			if (HasKit)
			{
				victim->hit = UMIN(victim->hit + heal, get_max_hit(victim));
				victim->nonlethal = UMAX(0, victim->nonlethal - heal);
				healed = TRUE;
			}
			//only gain long-term care benefit out of combat
			if (!in_combat(ch) && !in_combat(victim) && !IS_AFFECTED(victim, AFF2_LONGTERM_CARE))
			{
				if (victim != ch)
				{
					SET_AFFECT(victim, AFF2_LONGTERM_CARE);
					send_to_char("You must rest to gain the benefits of long-term care.\n\r", victim);
				}
				else
				{
					send_to_char("You cannot give yourself long-term care.\n\r", victim);
				}
			}			
		}
	}
	
	update_pos(victim,-1);
	
	if (!healed)
	{
		act( "Your aid does not seem to have offered any benefit.", ch, NULL, victim, TO_CHAR);
		act( "$n's attempt to aid does not seem to offer any benefit.", ch, NULL, victim, TO_ROOM);
	}
	pop_call();
	return;
}

/*
 * Bluff skill w/ targeted and room options
 */
void do_bluff( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	AFFECT_DATA af;
	CHAR_DATA *victim;
	CHAR_DATA *fch;
	int diceroll;

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

	argument = one_argument(argument, arg);

	if (arg[0] == '\0')
	{
		send_to_char("Syntax: bluff <target|all>\n\r",ch);
		pop_call();
		return;
	}
	
	if (in_combat(ch))
	{
		send_to_char("You can only FEINT or TAUNT when you are fighting.\n\r",ch);
		pop_call();
		return;
	}

	diceroll = bluff_roll(ch);
	
	if (!strcasecmp(arg, "all"))
	{
		act( "You attempt to bluff everyone in the room.", ch, NULL, NULL, TO_CHAR );
		
		for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
		{
			if (ch == fch)
				continue;
			if (!in_combat(ch) && in_combat(fch))
			{
				act( "$N is too busy fighting.", ch, NULL, fch, TO_CHAR );
				continue;
			}
				
			if (fch->position <= POS_SLEEPING || !can_see(fch, ch))
			{
				act( "$N is not paying attention to you.", ch, NULL, fch, TO_CHAR );
				continue;
			}
			if (fch->distracted > 0 || is_affected(fch, gsn_bluff))
			{
				act( "$N is already distracted.", ch, NULL, fch, TO_CHAR );
				continue;
			}
			if (!bluff_check(ch, fch, diceroll, 0))
			{
				act( "$N looks at you very suspiciously.", ch, NULL, fch, TO_CHAR );
				act( "You call $n's bluff.", ch, NULL, fch, TO_VICT );
				fch->distracted = 0;
				affect_strip(fch, gsn_bluff);
				continue;
			}

			act( "$n bluffs you with a clever ruse.", ch, NULL, fch, TO_VICT);
			act( "You bluff $N with a clever ruse.", ch, NULL, fch, TO_CHAR);

			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, fch, &af );
			wait_state( fch, skill_table[gsn_bluff].beats );
		}
		TAKE_ACTION(ch, ACTION_STANDARD);
	}
	else
	{
		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( "Distract yourself?", ch );
		}

		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;
		}
		if (!bluff_check(ch, victim, diceroll, 0))
		{
			act( "$N suddenly looks very suspicious.", ch, NULL, victim, TO_CHAR );
			act( "You call $n's bluff!", ch, NULL, victim, TO_VICT);
			victim->distracted = 0;
			affect_strip(victim, gsn_bluff);
			pop_call();
			return;
		}
		act( "$n bluffs you with a clever ruse.", ch, NULL, victim, TO_VICT);
		act( "You bluff $N with a clever ruse.", ch, NULL, victim, TO_CHAR);
		act( "$n bluffs $N with a clever ruse.", 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 );

		wait_state( victim, skill_table[gsn_bluff].beats );
		TAKE_ACTION(ch, ACTION_STANDARD);
	}
	pop_call();
	return;
}

/*
 * Check to see if a name is one that can
 * be used for naming a pet/companion - Kregor
 */
bool check_legal_name( CHAR_DATA *ch, char *name )
{
	CHAR_DATA *victim;

	push_call("check_legal_name(%p,%p)",ch,name);

	if (!check_parse_name(name, TRUE))
	{
		send_to_char ("That is an illegal name, try another.\n\r",ch);
		pop_call();
		return FALSE;
	}

	if ((victim = lookup_char(name)) != NULL)
	{
		send_to_char ("That name belongs to a player character.\n\r",ch);
		pop_call();
		return FALSE;
	}
		
	if ((victim = start_partial_load(ch, name)) != NULL)
	{
		send_to_char ("That name belongs to a player character.\n\r",ch);
		clear_partial_load(victim);
		pop_call();
		return FALSE;
	}
	pop_call();
	return TRUE;
}


/*
 * Disguise skill, totally gutted and reworked - Kregor 3/12/07
 */

/*
 * Hack of check_parse_name from nanny to 
 * determine a legal adjective for disguise - Kregor
 */
bool is_legal_adj(char *name)
{
	push_call("is_legal_adj(%p)",name);

	/*	Reserved Words	*/
	if (is_name(name, "all auto immortal god enemy clan target race class someone north east south west down order chaos open close hours hit mana armor damage castle save bak del dmp hours"))
	{
		pop_call();
		return FALSE;
	}
	if (lookup_god(name) != -1)
	{
		pop_call();
		return FALSE;
	}

	/* Alphanumerics only */
	{
		char *pc;

		for (pc = name ; *pc != '\0' ; pc++)
		{
			if ((*pc < 'a' || *pc > 'z') && *pc != ',' && *pc != ' ' && (*pc < 'A' || *pc > 'Z'))
			{
				pop_call();
				return FALSE;
			}
		}

		/*
			No more names containing 'you'
		*/
		for (pc = name ; *(pc+2) != '\0' ; pc++)
		{
			if ((*(pc+0) == 'Y' || *(pc+0) == 'y')
			&&  (*(pc+1) == 'O' || *(pc+1) == 'o')
			&&  (*(pc+2) == 'U' || *(pc+2) == 'u'))
			{
				pop_call();
				return FALSE;
			}
		}
	}
	pop_call();
	return TRUE;
}

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

	CHECK_EDITMODE( ch );

	if (!ch->desc)
	{
		bug( "ed_disguise_desc: no descriptor", 0 );
		pop_call();
		return;
	}

	switch( ch->pcdata->editmode )
	{
		default:
			bug( "ed_disguise_desc: illegal editmode", 0 );
			pop_call();
			return;

		case MODE_RESTRICTED:
			send_to_char( "You cannot use this command from while editing something else.\n\r",ch);
			pop_call();
			return;

		case MODE_NONE:
			ch->pcdata->editmode = MODE_DISGUISE_DESC;
			ch->pcdata->tempmode  = MODE_NONE;
			start_editing( ch, ch->pcdata->disguise_descr );
			pop_call();
			return;

		case MODE_DISGUISE_DESC:
			STRFREE (ch->pcdata->disguise_descr);
			ch->pcdata->disguise_descr = copy_buffer( ch );
			stop_editing( ch );
			pop_call();
			return;
	}
	pop_call();
	return;
}

void do_disguise( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char adj[MAX_STRING_LENGTH];
	char buf[MAX_STRING_LENGTH];
	OBJ_DATA *kit;
	int diceroll, race, sex;
	
	push_call("do_disguise(%p,%p)",ch,argument);

	if (IS_NPC(ch))
	{
		send_to_char("NPCs cannot disguise.\n\r", ch);
		pop_call();
		return;
	}
	if (!ch->desc)
	{
		pop_call();
		return;
	}

	if (in_combat(ch))
	{
		send_to_char( "You can't do that while fighting.\n\r", ch );
		pop_call();
		return;
	}
	
	if (*argument == '\0')
	{
		if (is_string(ch->pcdata->disguise))
		{
			if (is_string(ch->pcdata->disguise_descr))
			{
				ch_printf_color(ch, "{300}You're disguised as {178}%s %s.\n\r", a_an(ch->pcdata->disguise), ch->pcdata->disguise);
				pop_call();
				return;
			}
			else
			{
				ed_disguise_desc(ch);
				pop_call();
				return;
			}
		}
		else
		{
			send_to_char("Disguise yourself as what?\n\r", ch);
			send_to_char("syntax: disguise <sex> <race> <adjective>\n\r", ch);
			pop_call();
			return;
		}
	}
	
	if (!strcasecmp(argument,"remove"))
	{
		STRFREE(ch->pcdata->disguise);
		ch->pcdata->disguise = STRALLOC("");
		STRFREE(ch->pcdata->disguise_descr);
		ch->pcdata->disguise_descr = STRALLOC("");
		ch->pcdata->disguise_roll = 0;
		affect_strip(ch, gsn_disguise);
		send_to_char( "You remove your disguise.\n\r", ch );
		act( "$n removes $s disguise.", ch, NULL, NULL, TO_ROOM);
		pop_call();
		return;
	}
	
	if (ch->pcdata->disguise != NULL && ch->pcdata->disguise[0] != '\0')
	{
		act("You must remove your current disguise before applying a new one.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (strstr(argument, "{"))
	{
		send_to_char("You cannot use color codes in a disguise.\n\r", ch);
		pop_call();
		return;
	}
	
	smash_tilde( argument );
	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );
	strcpy( adj, argument );

	if (*arg1 == '\0' || *arg2 == '\0' || *argument == '\0')
	{
		send_to_char("syntax: disguise <sex> <race> <adjective>\n\r", ch);
		pop_call();
		return;
	}
	if ((sex = get_flag(arg1, sex_types)) == -1)
	{
		send_to_char("That is not a valid gender.\n\r", ch);
		pop_call();
		return;
	}
	if ((race = lookup_race(arg2)) == -1)
	{
		send_to_char("That is not a race.\n\r", ch);
		pop_call();
		return;
	}
	if (!is_legal_adj(argument))
	{
		send_to_char("That is not a legal adjective.\n\r", ch);
		pop_call();
		return;
	}
	if (strlen(argument) > 30)
	{
		send_to_char("Your adjective must be 30 characters or less.\n\r", ch);
		pop_call();
		return;
	}

	// Just the dice here, use the check function for adjustments
	diceroll = dice(1,20);

	if (!is_polymorph(ch))
	{
		if ((kit = get_obj_carry_type(ch, ITEM_TOOLS)) != NULL)
		{
			if (TOOL_TYPE(kit, TOOL_DISGUISE_KIT))
			{
				if (kit->value[1] == 0)
				{
					act( "You've used the last of your disguise kit.", ch, NULL, NULL, TO_CHAR);
					junk_obj(kit);
					diceroll -= 2;
				}
				else
				{
					kit->value[1]--;
	
					if (IS_OBJ_STAT(kit, ITEM_MASTERWORK))
					{
						if (kit->value[2] > 0)
							diceroll += kit->value[2];
						else
							diceroll += 2;
					}
				}
			}
			else
			{
				act( "You suffer a penalty for not using a disguise kit.", ch, NULL, NULL, TO_CHAR);
				diceroll -= 2;
			}
		}
		else
		{
			act( "You suffer a penalty for not using a disguise kit.", ch, NULL, NULL, TO_CHAR);
			diceroll -= 2;
		}	
	}
	
	// suffer -2 penalty for disguise of different race
	if (race != ch->race)
	{
		if (race_table[race].size != get_size(ch))
		{
			send_to_char("You can only disguise youself as a race of the same size.\n\r", ch);
			pop_call();
			return;
		}
		if (race_table[race].type != race_type(ch))
		{
			send_to_char("You cannot disguise as another racial type.\n\r", ch);
			pop_call();
			return;
		}
		diceroll -= 2;
	}

	// suffer -2 penalty for disguise as different gender
	if (ch->sex != sex)
	{
		diceroll -= 2;
	}

	sprintf(buf, "%s %s %s",
		adj, sex_types[sex], race_table[race].race_name);

	smash_tilde( buf );

	if (ch->pcdata->disguise && *ch->pcdata->disguise != '\0')
		STRFREE(ch->pcdata->disguise);
	ch->pcdata->disguise = STRALLOC(buf);

	send_to_char( "You meticulously disguise yourself.\n\r", ch );
	act( "$n meticulously disguises $mself.", ch, NULL, NULL, TO_ROOM);
	ch->pcdata->disguise_roll = diceroll;
	
	// to foil pronouns and socials
	if (sex != ch->sex)
	{
		AFFECT_DATA af;
		
		af.type      = gsn_disguise;
		af.duration  = -1;
		af.modifier  = sex - ch->sex;
		af.location  = APPLY_SEX;
		af.bittype   = AFFECT_TO_NONE;
		af.bitvector = AFF_NONE;
		af.level		 = diceroll;	
		affect_join( ch, ch, &af );
	}

	act("Please set your description for your disguise.", ch, NULL, NULL, TO_CHAR);
	ed_disguise_desc(ch);

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


/*
 * Hide, sneak and vis, modified significantly for Mud20 - Kregor
 */
/*
 * Just about triple the original command function's length
 * Goes through everyone in the room to see if the char's
 * attempt to hide actually works against them,
 * also added ability to hide behind furnishings - Kregor
 */
void do_stealth( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *gch, *gch_next;
	AFFECT_DATA af;
	bool hips = FALSE;

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

	if ((hips = learned(ch, gsn_hide_plain_sight)) == FALSE && in_combat(ch))
	{
		send_to_char("You're too busy fighting to run and hide.\n\r", ch);
		pop_call();
		return;
	}

	int diceroll = bluff_roll(ch);
	if (learned(ch, gsn_stealthy))
		diceroll += 4;

	if (!hips)
	{
		if (IS_SET(ch->in_room->room_flags, ROOM_NO_COVER))
		{
			send_to_char_color( "You can't find suitable cover.\n\r", ch );
			pop_call();
			return;
		}	
		
		for (gch = ch->in_room->first_person ; gch ; gch = gch_next)
		{
			gch_next = gch->next_in_room;
	
			if (gch == ch)
				continue;
			if (gch->distracted || is_affected(ch, gsn_bluff))
				continue;
			if (!IS_AWAKE(gch))
				continue;
			if (is_same_group(gch, ch))
				continue;
			if (!can_see(gch, ch))
				continue;
			if (!can_see(ch, gch))
				continue;
				
			// You can't hide with aggro after you
			if (IS_ACT(gch, ACT_AGGRESSIVE) || (who_fighting(gch) && who_fighting(gch) == ch))
			{
				// -4 penalty to bluff and hide from an active enemy
				if (!bluff_check(ch, gch, diceroll - 5, sense_motive_roll(gch)))
				{
					act( "You cannot hide with enemies aware of you!", ch, NULL, gch, TO_CHAR );
					pop_call();
					return;
				}
			}
		}
	}
	else
	{
		if (IS_SET(ch->in_room->room_flags, ROOM_NO_COVER) && get_room_light(ch->in_room) == LIGHT_BRIGHT)
		{
			act("You can't find sufficient cover!", ch, NULL, NULL, TO_CHAR);
			pop_call();
			return;
		}
	}
	af.type      = gsn_stealth;
	af.duration  = -1;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF_HIDE|AFF_SNEAK;
	af.level     = 0;
	affect_join( ch, ch, &af );

	if (learned(ch, gsn_swift_stealth))
		ch->speed	= UMIN(ch->speed, 1);
	else
		ch->speed	= 0;

	if (learned(ch, gsn_trackless_step))
	{
		send_to_char("The wind would leave more trace of it's passage than you.\n\r",ch);
	}
	else
	{
		send_to_char("You attempt to move stealthily.\n\r",ch);
	}

	for (gch = ch->in_room->first_person ; gch ; gch = gch_next)
	{
		gch_next = gch->next_in_room;
		
		if (!IS_NPC(gch))
		{
			if (IS_NPC(ch))
			{
				if ((!hips && !bluff_check(ch, gch, diceroll, sense_motive_roll(gch))) || can_see(gch, ch)) 
				{
					act( "$n tries to duck into hiding, but you still see $m.", ch, NULL, gch, TO_VICT );
					gch->pcdata->found_vnum[ch->pIndexData->vnum] = 1;
				}
				else
				{
					act( "You blink and suddenly, $n has ducked away!", ch, NULL, gch, TO_VICT );
					gch->pcdata->found_vnum[ch->pIndexData->vnum] = -1;
				}
			}
			else
			{
				if ((!hips && !bluff_check(ch, gch, diceroll, sense_motive_roll(gch))) || can_see(gch, ch)) 
				{
					act( "$n tries to duck into hiding, but you still see $m.", ch, NULL, gch, TO_VICT );
					gch->pcdata->found_pvnum[ch->pcdata->pvnum] = 1;
				}
				else
				{
					act( "You blink and suddenly, $n has ducked away!", ch, NULL, gch, TO_VICT );
					gch->pcdata->found_pvnum[ch->pcdata->pvnum] = -1;
				}
			}
		}
	}
	pop_call();
	return;
}


/*
	Contributed by Alander.
	removed affects that were taken out for Mud20
	added greet_trigger so you can't sneak up
	on a mobile to get around progs - Kregor 2/12/07
*/
void do_visible( CHAR_DATA *ch, char *argument )
{
	bool hidden = FALSE;
	bool invis = FALSE;
	int pick = 0;

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

	if (IS_AFFECTED(ch, AFF_INVISIBLE))
	{
		invis = TRUE;
		pick++;

		AFFECT_STRIP( ch, AFF_INVISIBLE	);
	}

	if (IS_AFFECTED(ch, AFF_HIDE))
	{
		hidden = TRUE;
		pick++;

		AFFECT_STRIP( ch, AFF_HIDE );
	}

	if (IS_AFFECTED(ch, AFF_SNEAK))
	{
		act( "Your footfalls become audible once more.", ch, NULL, NULL, TO_CHAR );
		pick++;

		AFFECT_STRIP( ch, AFF_SNEAK	);
	}

	if (hidden)
	{
		act( "$n steps out of $s concealment.", ch, NULL, NULL, TO_ROOM );
		act( "You step out of your concealment.", ch, NULL, NULL, TO_CHAR );
		if (ch->furniture && ch->position == POS_CROUCHING)
		{
			ch->position = POS_STANDING;
			user_from_furniture(ch);
		}
	}
	else if (invis)
	{
		act( "$n fades slowly into view...", ch, NULL, NULL, TO_ROOM );
		act( "You fade slowly into view...", ch, NULL, NULL, TO_CHAR );
	}
	if (!pick)
	{
		send_to_char( "You are not concealed in any way.\n\r", ch);
	}
	if (!IS_NPC(ch) && (hidden || invis))
	{
		mprog_greet_trigger(ch);
	}	
	pop_call();
	return;
}


/* 
 * Wizard's familiar - Kregor 3/19/07
 */
void do_familiar (CHAR_DATA *ch, char * argument)
{
	char arg[MAX_INPUT_LENGTH];
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mh;
	int mob, level, was_room;
	
	push_call("do_familiar(%p,%p)",ch,argument);

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

	if ((level = multi_skill_level(ch,gsn_familiar)) <= 0)
	{
		send_to_char( "You cannot summon a familiar.\n\r", ch);
		pop_call();
		return;
	}

	if (argument[0] == '\0')
	{
		if ((mh = get_familiar(ch)) != NULL)
		{
			send_to_char( "Syntax: familiar <call|scry|locate>.\n\r", ch);
			pop_call();
			return;
		}
		else
		{
			send_to_char( "Syntax: familiar <bat|cat|hawk|lizard|owl|rat|raven|snake|toad|weasel> <name> [adjective]\n\r", ch);
			pop_call();
			return;
		}
	}
	
	argument = one_argument(argument, arg);
	
	if ((mh = get_familiar(ch)) != NULL)
	{
		if (!strcasecmp(arg, "call"))
		{
			if (!mh->in_room && !ch->in_room)
			{
				send_to_char( "You cannot seem to reach your familiar.\n\r", ch);
				pop_call();
				return;
			}
			if (mh->in_room == ch->in_room)
			{
				send_to_char( "Your familiar is already here!\n\r", ch);
				pop_call();
				return;
			}
			if (ch->in_room->area != mh->in_room->area || findpath_room(mh, ch->in_room->vnum, 400) == -2)
			{
				send_to_char( "You cannot summon your familiar from that far away!\n\r", ch);
				pop_call();
				return;
			}
	
			act( "You send a mental summons to $N.", ch, NULL, mh, TO_CHAR);
	
			if (findpath_room(mh, ch->in_room->vnum, 400) == -1)
			{
				send_to_char( "Your familiar cannot seem to reach you.\n\r", ch);
				pop_call();
				return;
			}
			act( "You sense $N homing $S way to you.", ch, NULL, mh, TO_CHAR);
			mh->walkto = ch->in_room->vnum;
			pop_call();
			return;
		}
		
		if (!strcasecmp(arg, "locate"))
		{
			if (!mh->in_room || mh->in_room->name == NULL || !is_room_good_for_teleport(mh, mh->in_room->vnum))
			{
				send_to_char( "You cannot seem to locate your familiar.\n\r", ch);
				pop_call();
				return;
			}
			act( "You sense $N at $t.", ch, mh->in_room->name, mh, TO_CHAR);
			pop_call();
			return;
		}	
	
		if (!strcasecmp(arg, "scry"))
		{
			if (level < 12)
			{
				send_to_char( "You are not high enough level to scry through your familiar.\n\r", ch);
				pop_call();
				return;
			}
			if (!mh->in_room || mh->in_room->name == NULL || !is_room_good_for_teleport(mh, mh->in_room->vnum))
			{
				send_to_char( "You cannot seem to scry upon your familiar.\n\r", ch);
				pop_call();
				return;
			}
			send_to_char("You attempt to focus in on your familiar's eyes...\n\r", ch);
	
			was_room = ch->in_room->vnum;
			char_from_room(ch);
			char_to_room(ch, mh->in_room->vnum, FALSE);
			do_look(ch, "");
			char_from_room(ch);
			char_to_room(ch, was_room, FALSE);
			
			pop_call();
			return;
		}
		send_to_char( "Syntax: familiar <call|scry|locate>.\n\r", ch);
		pop_call();
		return;
	}
	else if (!strcasecmp(arg, "scry") || !strcasecmp(arg, "locate") || !strcasecmp(arg, "call"))
	{
		send_to_char( "You do not have a familiar.\n\r", ch);
		pop_call();
		return;
	}

	if (!strcasecmp(arg, "bat"))
		mob = MOB_VNUM_COMP_BAT;
	else if (!strcasecmp(arg, "cat"))
		mob = MOB_VNUM_COMP_CAT;
	else if (!strcasecmp(arg, "hawk"))
		mob = MOB_VNUM_COMP_HAWK;
	else if (!strcasecmp(arg, "lizard"))
		mob = MOB_VNUM_COMP_LIZARD;
	else if (!strcasecmp(arg, "owl"))
		mob = MOB_VNUM_COMP_OWL;
	else if (!strcasecmp(arg, "rat"))
		mob = MOB_VNUM_COMP_RAT;
	else if (!strcasecmp(arg, "raven"))
		mob = MOB_VNUM_COMP_RAVEN;
	else if (!strcasecmp(arg, "snake"))
		mob = MOB_VNUM_COMP_SNAKE;
	else if (!strcasecmp(arg, "toad"))
		mob = MOB_VNUM_COMP_TOAD;
	else if (!strcasecmp(arg, "weasel"))
		mob = MOB_VNUM_COMP_WEASEL;
	else
	{
		send_to_char( "Syntax: familiar <bat|cat|hawk|lizard|owl|rat|raven|snake|toad|weasel> <name> [adjective]\n\r", ch);
		pop_call();
		return;
	}

	if (argument[0] == '\0')
	{
		send_to_char( "You could at least give your familiar a name...\n\r", ch);
		pop_call();
		return;
	}
		
	argument = one_argument(argument, arg);
	
	if (!check_legal_name(mh, arg))
	{
		pop_call();
		return;
	}

	pMob = get_mob_index(mob);
	mh = create_mobile( pMob );

	if (argument[0] != '\0')
	{
		RESTRING(mh->name, format("%s %s %s", race_table[mh->race].race_name, arg, argument));
		RESTRING(mh->short_descr, format("%s, %s %s %s", capitalize(arg), a_an(argument), argument, race_table[mh->race].race_name));
	}
	else
	{
		RESTRING(mh->name, format("%s %s", race_table[mh->race].race_name, arg));
		RESTRING(mh->short_descr, format("%s, %s %s", capitalize(arg), a_an(race_table[mh->race].race_name), race_table[mh->race].race_name));
	}

	char_to_room( mh, ch->in_room->vnum, TRUE );
	
	act( "$N answers your call for a familiar.", ch, NULL, mh, TO_CHAR);
	act( "$N familiar answers $n's call.", ch, NULL, mh, TO_ROOM);
	
	mh->max_hit		= ch->max_hit / 2;
	mh->hit				= get_max_hit(mh);
	mh->perm_int	=	level / 2 + 5;
	mh->nat_armor	= level / 2;
	SET_BIT(mh->act, ACT_PET|ACT_FAMILIAR|ACT_SENTINEL);
	
	add_follower( mh , ch );

	pop_call();
	return;
}


/*
 * The totally gutted, reworked, d20-ized
 * tracking skill that really works like tracking - Kregor
 */
void add_tracking (CHAR_DATA *ch, CHAR_DATA *victim)
{
	push_call("add_tracking(%p,%p)",ch,victim);

	if (ch->pcdata->tracking)
	{
		act("You're already tracking someone.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}
	ch->pcdata->tracking = victim;
	victim->tracked_by = ch;
	act ("You are now tracking $N.", ch, NULL, victim, TO_CHAR);
	pop_call();
	return;
}

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

	if (IS_NPC(ch) || ch->pcdata->tracking == NULL)
	{
		pop_call();
		return;
	}

	ch->pcdata->tracking->tracked_by = NULL;
	ch->pcdata->tracking = NULL;

	pop_call();
	return;
}


int track_dc( CHAR_DATA *ch, CHAR_DATA *victim )
{
	int dc;

	push_call("track_dc(%p,%p)",ch,victim);
	
	switch (ch->in_room->sector_type)
	{
		case SECT_DESERT:
		case SECT_BEACH:
		case SECT_TUNDRA:
			dc = 5;
			break;
		
		case SECT_SWAMP:
			dc = 10;
			break;
		
		case SECT_ROAD:
		case SECT_FIELD:
		case SECT_FOREST:
		case SECT_HILLS:
			dc = 15;
			break;
		
		case SECT_UNDER_GROUND:
		case SECT_DEEP_EARTH:
		case SECT_INSIDE:
		case SECT_CITY:
		case SECT_MOUNTAIN:
		case SECT_RIVER:
			dc = 20;
			break;
			
		default:
			dc = 99;
			break;
	}
	
	if (learned(ch, gsn_scent))
	{
		// give aquatic creatures w scent ability to track in water.
		if (rspec_req(ch, RSPEC_AQUATIC))
		{
			switch(ch->in_room->sector_type)
			{
				case SECT_LAKE:
				case SECT_RIVER:
				case SECT_UNDER_WATER:
				case SECT_OCEAN:
					dc = UMIN(dc, 10);
					break;
			}
		}
		else if (dc != 99)
		{
			dc = UMIN(dc, 10);
		}
	}
	else // tracking by scent ignores weather, visibility & size
	{
		if (mud->time_info->hour > 19 && mud->time_info->hour < 5)
		{
			dc += 3;
		}
	
		switch (ch->in_room->area->weather_info->sky)
		{
			case 0: dc += 0;	break;
			case 1: dc += 1;	break;
			case 2: dc += 3;	break;
			case 3: dc += 5;	break;
		}
	
		if (victim != NULL)
		{
			switch (get_size(victim))
			{
				case SIZE_FINE:
					dc += 8;
					break;		
				case SIZE_DIMINUTIVE:
					dc += 4;
					break;		
				case SIZE_TINY:
					dc += 2;
					break;				
				case SIZE_SMALL:
					dc += 1;
					break;		
				case SIZE_LARGE:
					dc -= 1;
					break;			
				case SIZE_HUGE:
					dc -= 2;
					break;				
				case SIZE_GARGANTUAN:
					dc -= 4;
					break;		
				case SIZE_COLOSSAL:
					dc -= 8;
					break;
			}
		}
	}
	pop_call();
	return dc;
}


void do_track( CHAR_DATA *ch, char *argument)
{
	int cnt, count;
	int roll;
	int TRACK_DIR;
	CHAR_DATA *victim, *rch;
	bool fScent = FALSE;
	
	push_call("do_track(%p,%p)",ch,argument);

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

	if ((fScent = learned(ch, gsn_scent)) == FALSE)
	{
		if (!learned(ch, gsn_survival))
		{
			send_to_char_color( "You do not have any survival skills.\n\r", ch);
			pop_call();
			return;
		}
	
		if (IS_BLIND(ch) )
		{
			send_to_char_color("You can't see a thing!\n\r",ch);
			pop_call();
			return;
		}
	}

	roll = survival_roll(ch);
	roll += synergy_bonus(ch, gsn_search);
	roll += UMAX(1, multi_class_level(ch, gsn_track) / 2);
	
	if (argument[0] == '\0')
	{
		if (ch->pcdata->tracking)
		{
			act("{178}You stop tracking $N.", ch, NULL, ch->pcdata->tracking, TO_CHAR);
			stop_tracking(ch);
			pop_call();
			return;
		}
		if (!learned(ch, gsn_master_hunter) && !ch->concentrating)
		{
			if (fScent)
			{
				act("$n sniffs at the ground...", ch, NULL, NULL, TO_ROOM);
				act("You sniff the ground for tracks...", ch, NULL, NULL, TO_CHAR);
			}
			else
			{
				act("$n studies the ground...", ch, NULL, NULL, TO_ROOM);
				act("You study the ground for tracks...", ch, NULL, NULL, TO_CHAR);
			}
			ch->concentrating = TRUE;
			ch->skill_timer		= learned(ch, gsn_swift_tracker) ? 4 : 12;
			ch->timer_fun			= do_track;
			RESTRING(ch->cmd_argument, "");
			if (!learned(ch, gsn_swift_tracker))
				TAKE_ACTION(ch, ACTION_STANDARD);
			else
				TAKE_ACTION(ch, ACTION_MOVE);
			pop_call();
			return;
		}
		send_to_char_color("{178}You locate the following sets of tracks:\n\r", ch);
		for (cnt = count = 0 ; cnt < MAX_LAST_LEFT ; cnt++)
		{
			if (ch->in_room->last_left_bits[cnt] == 0)
				continue;

			if (IS_SET(ch->in_room->last_left_bits[cnt], TRACK_FLY))
				continue;

			TRACK_DIR = UNSHIFT(ch->in_room->last_left_bits[cnt]);

			if ((rch = get_char_area(ch, ch->in_room->last_left[cnt])) == NULL)
			{
				if ((rch = get_char_pvnum(ch->in_room->last_left_pvnum[cnt])) == NULL)
				{
					if (survival_check(ch, NULL, roll, track_dc(ch, NULL)))
					{
						ch_printf_color(ch, "  {300}An unidentifiable set of tracks leading %s.\n\r", dir_name[TRACK_DIR]);
						count++;
					}
					continue;
				}
			}

			if (rch == ch)
				continue;

			if (survival_check(ch, rch, roll, track_dc(ch, rch)))
			{
				ch_printf_color(ch, "  {300}%s leading %s.\n\r", PERS(rch,ch), dir_name[TRACK_DIR]);
				count++;
			}
		}
		if (!count)
		{
			ch_printf_color(ch, "  {300}None.\n\r");
		}
	}
	else
	{
		if (!fScent && !learned(ch, gsn_swift_tracker))
		{
			send_to_char_color("Right, maybe if you were a ranger!\n\r", ch);
			pop_call();
			return;
		}

		stop_tracking(ch);

		if (ch->position <= POS_SITTING)
		{
			send_to_char_color("You're too relaxed.\n\r", ch);
			pop_call();
			return;
		}

		if ((victim = get_char_area(ch, argument)) == NULL)
		{
			if ((victim = lookup_char(argument)) == NULL)
			{
				send_to_char("You can't find a good enough trail to follow.\n\r", ch);
				pop_call();
				return;
			}
		}
		track_char(ch, victim);
	}
	pop_call();
	return;
}


void track_char( CHAR_DATA *ch, CHAR_DATA *victim )
{
	bool found = FALSE;
	CHAR_DATA *rch;
	int dc, cnt, roll, TRACK_DIR;

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

	roll = survival_roll(ch);
	roll += synergy_bonus(ch, gsn_search);

	dc = track_dc(ch, victim);

	switch (ch->speed)
	{
		case 0:
		case 1:
			dc += 0;
			break;		
		case 2:
			if (!learned(ch, gsn_master_hunter))
				dc += 10;
			break;				
		default:
			act("You are traveling too fast to track.", ch, NULL, NULL, TO_CHAR);
			ch->speed = 2;
			dc += 10;
			break;				
	}

	if (ch->pcdata->tracking)
	{
		ch->pcdata->was_in_room = ch->in_room->vnum;
		if (victim != ch->pcdata->tracking)
			stop_tracking(ch);
	}
	else
	{
		for (rch = ch->in_room->first_person ; rch ; rch = rch->next_in_room)
		{
			if (!can_see(ch, rch))
			{
				continue;
			}
			if (rch == victim)
			{
				act( "You're already in the same room as $N.", ch, NULL, rch, TO_CHAR);
				pop_call();
				return;
			}
		}
	}

	for (cnt = MAX_LAST_LEFT-1 ; cnt >= 0 ; cnt--)
	{
		if (ch->in_room->last_left_bits[cnt] == 0)
		{
			continue;
		}
		if (IS_SET(ch->in_room->last_left_bits[cnt], TRACK_FLY))
		{
			continue;
		}
		if (!strcasecmp(ch->in_room->last_left[cnt], victim->name)) 
		{
			if (survival_check(ch, victim, roll, dc))
			{
				TRACK_DIR = UNSHIFT(ch->in_room->last_left_bits[cnt]);
				act("{138}You find the tracks of $N leading $t...", ch, dir_name[TRACK_DIR], victim, TO_CHAR);
				if (!ch->pcdata->tracking)
					add_tracking(ch, victim);
				found = TRUE;
				break;
			}
		}
	}
	if (found)
	{
		TRACK_DIR = UNSHIFT(ch->in_room->last_left_bits[cnt]);

		if (ch->in_room->exit[TRACK_DIR]->to_room == ch->pcdata->was_in_room)
		{
			send_to_char ("{138}Your prey has doubled back!\n\r", ch);
			stop_tracking(ch);
			pop_call();
			return;
		}
	}
	else
	{
		if (!ch->pcdata->tracking)
		{
			act("{178}You cannot find any tracks made by $N.", ch, NULL, victim, TO_CHAR);
		}
		else
		{
			act("{178}$N's tracks end here.", ch, NULL, ch->pcdata->tracking, TO_CHAR);
			stop_tracking(ch);
		}
	}
	pop_call();
	return;
}


/* 
 * Forage for survival skill, overhauled for D20 - Kregor 12/16/06
 */
void do_forage( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *gch;
	
	push_call("do_forage(%p,%p)",ch,argument);

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

	if (!learned(ch, gsn_survival))
	{
		send_to_char( "You were never taught to find your own food.\n\r", ch );
		pop_call();
		return;
	}

	if (ch->in_room == NULL
	|| (ch->in_room->sector_type != SECT_FIELD
	&&  ch->in_room->sector_type != SECT_FOREST
	&&  ch->in_room->sector_type != SECT_HILLS
	&&  ch->in_room->sector_type != SECT_MOUNTAIN ))
	{
		send_to_char( "There is no food to be found here.\n\r", ch );
		pop_call();
		return;
	}
	
	if (!ch->concentrating)
	{
		act( "You forage about for sustenance...", ch, NULL, NULL, TO_CHAR);
		act( "$n forages about for sustenance...", ch, NULL, NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= 16;
		ch->timer_fun			= do_forage;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	int roll, count;
	roll = survival_roll(ch);
	if (survival_check(ch, NULL, roll, 10 ))
	{
		act( "You find enough food and water to satisfy yourself.", ch, NULL, NULL, TO_CHAR);
		act( "$n finds enough food and water to satisfy $mself.", ch, NULL, NULL, TO_ROOM);
		gain_condition( ch, COND_FULL, roll);
		gain_condition( ch, COND_THIRST, roll);
		
		count = (roll - 10)/2;
		
		for (gch = ch->in_room->first_person ; gch ; gch = gch->next_in_room)
		{
			if (gch == ch)
				continue;
			if (count <= 0)
			{
				act( "There is no food or water left for anyone else.", ch, NULL, gch, TO_CHAR);
				act( "There is no food or water left for anyone else.", ch, NULL, gch, TO_ROOM);
				break;
			}
			if (!IS_NPC(gch) && is_same_group(ch, gch))
			{
				if (gch->pcdata->condition[COND_THIRST] < 30 || gch->pcdata->condition[COND_FULL] < 30)
				{
					act( "You provide food and water for $N as well.", ch, NULL, gch, TO_CHAR);
					act( "$n provides enough for you as well.", ch, NULL, gch, TO_VICT);
					act( "$n provides enough for $N as well.", ch, NULL, gch, TO_NOTVICT);
					gain_condition( gch, COND_FULL, roll);
					gain_condition( gch, COND_THIRST, roll);
					count--;
				}
			}
		}
		pop_call();
		return;
	}
	else
	{
		send_to_char( "You fail to find any food and water.\n\r", ch );
		pop_call();
		return;
	}
}


/*fishing
 *
 * snippet by Hera, of Athens - The Mud athens.boue.ca port 9000 
 *	hera_of_athens@yahoo.com
 */
 
void fish_start( CHAR_DATA *ch )
{
	push_call("fish_start(%p)",ch);

	OBJ_INDEX_DATA *pObjIndex;
	OBJ_DATA *fish, *bait;
	char name[20];
	
	if (IS_NPC(ch)) 
	{ 
		pop_call();
		return;	
	}
	
	for (bait = ch->first_carrying ; bait ; bait = bait->next_content)
	{
		if (IS_OBJ_TYPE(bait, ITEM_FOOD))
		{ 
			break;
		}
	}
	
	if (!bait)
	{
		ch_printf_color(ch, "You need bait!\n\r");
		pop_call();
		return;
	} 
	
	if (!ch->concentrating)
	{
		act("You dip your line in to fish...", ch, NULL, NULL, TO_CHAR);
		act("$n dips his line into the water to fish...", ch, NULL, NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= dice(2,16);
		ch->timer_fun			= do_fish;
		RESTRING(ch->cmd_argument, "");
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	if ((pObjIndex = get_obj_index(OBJ_VNUM_FISHCATCH)) == NULL)
	{
		ch_printf_color(ch, "Try as you might, you can't seem to catch a fish.\n\r");
		bug("do_fish: OBJ_VNUM_FISHCATCH non existant.");
		pop_call();
		return;
	}
	
	fish = create_object(pObjIndex,0);
	
	switch(dice(1,12)) 
	{
		case 1:
		case 7:
			ch_printf_color(ch, "You get a nibble but the fish leaves without taking the bait.\n\r"); 
			extract_obj(fish);
			fish = NULL;
			break;
		
		case 2:
		case 8:
			ch_printf_color(ch, "A fish steals your bait without getting hooked!\n\r"); 
			extract_obj(bait);
			extract_obj(fish);
			fish = NULL;
			break;		
		
		case 3:
			if (ch->in_room->sector_type == SECT_OCEAN)
				strcpy(name, "tuna");
			else
				strcpy(name, "catfish");
			fish->value[0] = 4;
			extract_obj(bait);
			break;

		case 4:
			if (ch->in_room->sector_type == SECT_OCEAN)
				strcpy(name, "cod");
			else
				strcpy(name, "bass");				
			fish->value[0] = 3;
			extract_obj(bait);
			break;

		case 5:
			if (ch->in_room->sector_type == SECT_OCEAN)
				strcpy(name, "flounder");
			else
				strcpy(name, "pike");
			fish->value[0] = 2;
			fish->size = SIZE_DIMINUTIVE;
			extract_obj(bait);
			break;

		case 6:
			if (ch->in_room->sector_type == SECT_OCEAN)
				strcpy(name, "salmon");
			else
				strcpy(name, "trout");
			fish->value[0] = 3;
			extract_obj(bait);
			break;

		case 9:
		case 10:
		case 11:
		case 12:
			strcpy(name, "tiny fish");
			fish->value[0] = 0;
			fish->size = SIZE_FINE;
			extract_obj(bait);
			break;
	}
	
	if (fish != NULL)
	{
		RESTRING(fish->long_descr, format("A freshly caught %s lies here.", name));
		RESTRING(fish->short_descr, format("a %s", name));
		RESTRING(fish->name, format("fish %s", name));
		obj_to_char(fish, ch);
		ch_printf_color(ch, "You caught something!\n\r");
		if (fish->value[0] == 0)
			ch_printf_color(ch, "The fish wouldn't even be a mouthful, but you could use it as bait.\n\r");
		act("$n caught a fish!", ch, NULL, NULL, TO_ROOM);
	}
	
	pop_call();
	return;
}


void do_fish( CHAR_DATA *ch, char *argument )
{
	OBJ_DATA *obj;

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

	if (IS_NPC(ch))
	{
		send_to_char( "NPCs don't need to fish.\n\r", ch );
		pop_call();
		return;
	}

	switch (ch->in_room->sector_type)
	{
		case SECT_LAKE:
		case SECT_RIVER:
		case SECT_OCEAN:
			break;
		default:
			send_to_char( "You can't fish on dry land.\n\r", ch );
			pop_call();
			return;
	}
	
	if ((obj = get_obj_wear_type(ch, ITEM_TOOLS)) != NULL && TOOL_TYPE(obj, TOOL_FISHING_POLE))
	{
		fish_start( ch );
		pop_call();
		return;
	}
	
	send_to_char("You are not holding a fishing pole.\n\r", ch);

	pop_call();
	return;
}

/* 
 * Camping for survival skill
 */
void do_camp( CHAR_DATA *ch, char *argument )
{
	OBJ_DATA *kit;
	int diceroll;
	
	push_call("do_camp(%p,%p)",ch,argument);

	if(ch->position<=POS_RESTING && in_camp(ch))
	{
		send_to_char("You are already camping.\n\r", ch);
		pop_call();
		return;
	}

	if (argument && ch->pcdata->last_combat + 60 > mud->current_time)
	{
		ch_printf_color(ch, "{018}Your adrenaline is pumping too hard to set up camp!\n\r");
		pop_call();
		return;
	}

	if (ch->fear_level)
	{
		ch_printf_color(ch, "{018}Mind is racing too fast with fear to camp now!\n\r");
		pop_call();
		return;
	}

	if(ch->in_room->sector_type == SECT_CITY)
	{
		send_to_char("The city guards would likely arrest you for vagrancy.\n\r", ch);
		send_to_char("Perhaps you should find an inn instead.\n\r", ch);
		pop_call();
		return;
	}

	if(ch->in_room->sector_type == SECT_ROAD)
	{
		send_to_char("You should set up camp a little off the beaten path, hm?\n\r", ch);
		pop_call();
		return;
	}

	if(ch->position != POS_STANDING)
	{
		send_to_char("You must be standing in order to establish a camp.\n\r", ch);
		pop_call();
		return;
	}
	
	diceroll = survival_roll(ch);
	
	if ((kit = get_obj_wear_type(ch, ITEM_TOOLS)) != NULL && TOOL_TYPE(kit, TOOL_SURVIVAL_TOOLS))
	{
		if (IS_OBJ_STAT(kit, ITEM_MASTERWORK))
		{
			if (kit->value[2] > 0)
				diceroll += kit->value[2];
			else
				diceroll += 2;
		}
	}

	if (survival_check(ch, NULL, diceroll, 10))
	{
		if (!can_see_in_room(ch, ch->in_room))
		{
			if (number_percent() > 25)
			{
				send_to_char("You fumble around with your tools, but it looks nothing like a camp.\n\r",ch);
				act( "$n fumbles around with $s tools...\n\r",ch,NULL,NULL,TO_ROOM);
			}
			else
			{
				send_to_char("You fumble around with your tools, and miraculously you establish a camp!\n\r",ch);
				act( "$n fumbles around with $s tools, and establishes a camp!\n\r",ch,NULL,NULL,TO_ROOM);
				ch->position = POS_RESTING;
				SET_AFFECT(ch, AFF2_CAMPING);
			}
		}
		else
		{
			send_to_char("You establish a camp and begin recuperating.\n\r", ch);
			act( "$n establishes a camp.",ch,NULL,NULL,TO_ROOM);
			ch->position = POS_RESTING;
			SET_AFFECT(ch, AFF2_CAMPING);
		}
	}
	else
	{
		send_to_char("You fail to establish a good camp.\n\r", ch);
	}

	pop_call();
	return;
}

/*
 * Skin and slice skill from Smaug 1.4a - Kregor 12/16/06
 */
void do_skin( CHAR_DATA * ch, char *argument )
{
	OBJ_DATA *corpse;
	OBJ_DATA *obj;
	OBJ_DATA *skin;
	bool found;
	char *name = NULL;
	static char suffix[MAX_INPUT_LENGTH];
	found = FALSE;
	int size;

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

	if (!learned(ch,gsn_survival))
	{
		send_to_char( "You're not that experienced a survivalist.\r\n", ch );
		pop_call();
		return;
	}
	if (argument[0] == '\0')
	{
		send_to_char( "What corpse do you wish to skin?\r\n", ch );
		pop_call();
		return;
	}
	if ((corpse = get_obj_here(ch, argument)) == NULL )
	{
		send_to_char( "You cannot find that here.\r\n", ch );
		pop_call();
		return;
	}
	if ((obj = get_obj_wear_type( ch, ITEM_WEAPON )) == NULL || !WEAPON_TYPE(obj, WEAPON_TYPE_KNIFE))
	{
		send_to_char( "You have to wield a knife.\r\n", ch );
		pop_call();
		return;
	}
	if (corpse->item_type != ITEM_CORPSE_NPC && corpse->item_type != ITEM_CORPSE_PC)
	{
		send_to_char( "You can only skin corpses.\r\n", ch );
		pop_call();
		return;
	}
	if (corpse->material != MATERIAL_FLESH)
	{
		act( "There is no hide to take from $p.", ch, corpse, NULL, TO_CHAR );
		pop_call();
		return;
	}
	if ((size = corpse->value[6]) == 0)
	{
		send_to_char( "That corpse has already been skinned.\r\n", ch );
		pop_call();
		return;
	}
	if (get_obj_index(OBJ_VNUM_SKIN) == NULL)
	{
		bug( "Vnum %d (OBJ_VNUM_SKIN) not found for do_skin!", OBJ_VNUM_SKIN );
		pop_call();
		return;
	}

	corpse->value[6] = 0;

	if (!survival_check(ch, NULL, survival_roll(ch), 15))
	{
		act( "You fail to skin $p properly.", ch, corpse, NULL, TO_CHAR );
		act( "{018}$n tries to skin $p, and makes a mess.", ch, corpse, NULL, TO_ROOM );
		pop_call();
		return;
	}
	skin = create_object (get_obj_index(OBJ_VNUM_SKIN), 0);
	sprintf(name, "%s", corpse->short_descr);
	strcpy(suffix, &name[strlen("the corpse of ")]);
	RESTRING(skin->name, format("%s%s", skin->name, suffix));
	RESTRING(skin->short_descr, format("%s%s", skin->short_descr, suffix));
	RESTRING(skin->long_descr, format(skin->long_descr, suffix));
	skin->size = size;
	act( "{018}$n skins the hide from $p.", ch, corpse, NULL, TO_ROOM );
	act( "{018}You skins the hide from $p.", ch, corpse, NULL, TO_CHAR );
	obj_to_char( skin, ch );
	
	pop_call();
	return;
}

void do_slice( CHAR_DATA * ch, char *argument )
{
	OBJ_DATA *corpse, *obj, *slice;
	bool found;
	found = FALSE;

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

	if (!learned(ch,gsn_survival))
	{
		send_to_char( "You're not that experienced a survivalist.\r\n", ch );
		pop_call();
		return;
	}
	if (argument[0] == '\0')
	{
		send_to_char( "What corpse do you wish to slice?\r\n", ch );
		pop_call();
		return;
	}
	if ((corpse = get_obj_here( ch, argument)) == NULL)
	{
		send_to_char( "You cannot find that here.\r\n", ch );
		pop_call();
		return;
	}
	if (corpse->item_type != ITEM_CORPSE_NPC && corpse->item_type != ITEM_CORPSE_PC)
	{
		send_to_char( "You can only slice corpses.\r\n", ch );
		pop_call();
		return;
	}
	if (corpse->material != MATERIAL_FLESH)
	{
		act( "There is no flesh to slice from $p.", ch, corpse, NULL, TO_CHAR );
		pop_call();
		return;
	}
	if ((obj = get_obj_wear_type( ch, ITEM_WEAPON )) == NULL || !WEAPON_TYPE(obj, WEAPON_TYPE_KNIFE))
	{
		send_to_char( "You have to wield a knife.\r\n", ch );
		pop_call();
		return;
	}
	if (corpse->value[5] <= 0)
	{
		act( "There's not enough meat left on $p", ch, corpse, NULL, TO_CHAR );
		pop_call();
		return;
	}
	if (get_obj_index(OBJ_VNUM_SLICE) == NULL )
	{
		bug( "Vnum %d (OBJ_VNUM_SLICE) not found for do_slice!", OBJ_VNUM_SKIN );
		pop_call();
		return;
	}

	corpse->value[5]--;

	if (!survival_check(ch, NULL, survival_roll(ch), 15))
	{
		send_to_char( "{018}You fail to slice the corpse properly.\r\n", ch );
		act( "{018}$n tries to slice $p, and makes a mess.", ch, corpse, NULL, TO_ROOM );
		corpse->value[5]--;
		pop_call();
		return;
	}
	slice = create_object (get_obj_index(OBJ_VNUM_SLICE), 0);
	act( "{018}$n slices meat from $p.", ch, corpse, NULL, TO_ROOM );
	act( "{018}You slice meat from $p.", ch, corpse, NULL, TO_CHAR );
	obj_to_room( slice, ch->in_room->vnum );
	pop_call();
	return;
}

/*
 * Locate, urban tracking feat for Streetwise skill - Kregor
 */
void do_locate( CHAR_DATA *ch, char *argument)
{
	int roll, TRACK_DIR, track_dc, area_size;
	CHAR_DATA *victim;
	
	push_call("do_locate(%p,%p)",ch,argument);

	if (!learned(ch, gsn_urban_tracking))
	{
		send_to_char_color( "You are not skilled in urban tracking.\n\r", ch);
		pop_call();
		return;
	}

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

	if (IS_SET(ch->in_room->area->flags, AFLAG_METROPOLIS))
		track_dc = 20;
	else if (IS_SET(ch->in_room->area->flags, AFLAG_CITY))
		track_dc = 15;
	else if (IS_SET(ch->in_room->area->flags, AFLAG_TOWN))
		track_dc = 10;
	else if (IS_SET(ch->in_room->area->flags, AFLAG_VILLAGE))
		track_dc = 5;
	else
	{
		send_to_char("You cannot find enough people to network with here.\n\r", ch);
		pop_call();
		return;
	}

	if (mud->time_info->hour > 19 && mud->time_info->hour < 5)
	{
		track_dc += 3;
	}

	roll = streetwise_roll(ch);
	area_size = ch->in_room->area->hi_r_vnum - ch->in_room->area->low_r_vnum;
	
	if (argument[0] == '\0')
	{
		send_to_char("Locate whom?\n\r", ch);
		pop_call();
		return;
	}
	if ((victim = get_char_area(ch, argument)) == NULL)
	{
		if ((victim = lookup_char(argument)) == NULL)
		{
			send_to_char("The local populace can't seem to point you in the right direction.\n\r", ch);
			act( "$n mills about the local populace, asking many questions about someone.", ch, NULL, NULL, TO_ROOM);
			pop_call();
			return;
		}
	}
	
	track_dc += synergy_bonus(victim, gsn_bluff);
	track_dc += multi_class_level(victim, gsn_faceless);

	if (!streetwise_check(ch, victim, roll, track_dc))
	{
		send_to_char("The local populace can't seem to point you in the right direction.\n\r", ch);
		act( "$n mills about the local populace, asking many questions about someone.", ch, NULL, NULL, TO_ROOM);
		pop_call();
		return;
	}
	
	if ((TRACK_DIR = findpath_search_victim(ch, victim, area_size)) == -2)
	{
		if (can_see(ch, victim))
		{
			act( "You mill about asking about $N, then you find $M in the same room!", ch, NULL, victim, TO_CHAR);
			act( "$n mills about asking about you, then sees you standing there!", ch, NULL, victim, TO_VICT);
			act( "$n mills about asking about $N, then finds $M standing there!", ch, NULL, victim, TO_NOTVICT);
		}
		else
		{
			act( "Someone informs you they saw $M just a moment ago, right here.", ch, NULL, victim, TO_CHAR);
		}
		pop_call();
		return;
	}
	else if (TRACK_DIR == -1)
	{
		act( "The local populace says that $N aready left the area.", ch, NULL, victim, TO_CHAR);
		act( "$n mills about asking residents about $N", ch, NULL, victim, TO_ROOM);
		pop_call();
		return;
	}
	
	act( "The local populace places $N somewhere to the $t of here.", ch, dir_name[TRACK_DIR], victim, TO_CHAR);
	act( "Some residents point $n somewhere to the $t", ch, dir_name[TRACK_DIR], NULL, TO_ROOM);
	
	pop_call();
	return;
}


/*
 * The much better, totally redone SNATCH command
 * now turned into a function to wrap into STEAL command
 * now more checks and includes containers - Kregor
 */
bool snatch_object( CHAR_DATA *ch, char *arg1, char *arg2 )
{
	CHAR_DATA *fch;
	OBJ_DATA  *obj, *container;
	int diceroll, dc;

	push_call("snatch_object(%p,%p,%p)",ch,arg1,arg2);

	if (is_string(arg2) && ((container = get_obj_carry(ch, arg2)) != NULL || (container = get_obj_here(ch, arg2)) != NULL))
	{
		if (container->item_type != ITEM_SPELLPOUCH && container->item_type != ITEM_CONTAINER
		&& container->item_type != ITEM_SHEATH && container->item_type != ITEM_CART && container->item_type != ITEM_QUIVER)
		{
			act( "$p is not a container.", ch, container, NULL, TO_CHAR );
			pop_call();
			return FALSE;
		}
	
		if (IS_SET(container->value[1], CONT_CLOSED))
		{
			act( "$p is closed.", ch, container, NULL, TO_CHAR );
			pop_call();
			return FALSE;
		}

		if ((obj = get_obj_list(ch, arg1, container->first_content)) == NULL)
		{
			act( "You do not see any $T in $p.", ch, container, arg1, TO_CHAR);
			pop_call();
			return FALSE;
		}

		diceroll = sleight_of_hand_roll(ch);
		dc = get_obj_weight(obj) / 10 + 15;

		if (get_size(ch) - obj->size < 2)
		{
			send_to_char( "That item is too large for you to palm.\n\r", ch );
			pop_call();
			return FALSE;
		}

		if (!get_obj(ch, obj, container, FALSE, FALSE))
		{
			act( "You cannot seem to snatch $p from $P.", ch, obj, container, TO_CHAR);
		}
		else
		{
			act( "You attempt to snatch $p discreetly from $P.", ch, obj, container, TO_CHAR);		
			if (sleight_of_hand_check(ch, NULL, diceroll, dc))
			{
				for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
				{
					if (ch == fch || fch->position <= POS_SLEEPING)
					{
						continue;
					}
					if (perception_check(fch, ch, perception_roll(fch, SENSE_SIGHT), diceroll))
					{		
						ch_printf_color( fch, "{138}%s tries to snatch %s {138}from %s.", PERS(ch, fch), obj->short_descr, container->short_descr);
					}
				}
			}
			else
			{
				act( "$n gets $p from $P.", ch, obj, container, TO_ROOM);
			}
		}
		TAKE_ACTION(ch, ACTION_STANDARD);

		pop_call();
		return TRUE;
	}
		
	if ((obj = get_obj_list(ch, arg1, ch->in_room->first_content)) == NULL)
	{
		pop_call();
		return FALSE;
	}

	diceroll = sleight_of_hand_roll(ch);
	dc = get_obj_weight(obj) / 10 + 15;

	if (get_size(ch) - obj->size < 2)
	{
		send_to_char( "That item is too large for you to palm.\n\r", ch );
		pop_call();
		return FALSE;
	}

	if (get_obj(ch, obj, NULL, TRUE, FALSE))
	{
		act( "You attempt to snatch $p unseen.", ch, obj, NULL, TO_CHAR);
		if (sleight_of_hand_check(ch, NULL, diceroll, dc))
		{
			for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
			{
				if (ch == fch || fch->position <= POS_SLEEPING)
				{
					continue;
				}
				if (perception_check(fch, ch, perception_roll(fch, SENSE_SIGHT), diceroll))
				{		
					act( "{138}You see $N attempt to snatch $p.", fch, obj, ch, TO_CHAR);
				}
			}
		}
		else
		{
			act( "$n gets $p.", ch, obj, NULL, TO_ROOM);
		}
	}
	TAKE_ACTION(ch, ACTION_STANDARD);

	pop_call();
	return TRUE;
}

/*
 * Moved pick and steal to skills.c, because even
 * though they are acts on objects, they are also skills.
 */
void do_steal( CHAR_DATA *ch, char *argument )
{
	char buf  [MAX_STRING_LENGTH];
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim, *fch;
	OBJ_DATA *obj;
	bool fCaught = FALSE;
	bool fSuccess = FALSE;
	int diceroll, dc;
	int amount = 0;

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

	if (!learned(ch, gsn_sleight_of_hand))
	{
		send_to_char( "You are not trained in Sleight of Hand.\n\r", ch);
		pop_call();
		return;
	}
	
	if (is_safe(ch, NULL))
	{
		pop_call();
		return;
	}

	if (!is_handy(ch) || hands_full(ch))
	{
		send_to_char( "You have no free hand to do that.\n\r", ch );
		pop_call();
		return;
	}
	
	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );
	
	//allow "from" in command
	if (!strcasecmp(arg2, "from"))
		argument = one_argument( argument, arg2 );

	if (arg1[0] == '\0')
	{
		send_to_char( "Steal what?\n\r", ch );
		pop_call();
		return;
	}

	if (arg2[0] == '\0')
	{
		if (!snatch_object(ch, arg1, ""))
		{
			send_to_char( "Steal what from whom or what?\n\r", ch );
			pop_call();
			return;
		}
		else
		{
			pop_call();
			return;
		}
	}

	if ((victim = get_char_room(ch, arg2)) == NULL)
	{
		if (!snatch_object(ch, arg1, arg2))
		{
			act( "$t doesn't seem to be here.", ch, arg2, NULL, TO_CHAR );
			pop_call();
			return;
		}
		else
		{
			pop_call();
			return;
		}
	}

	if (victim == ch)
	{
		send_to_char( "Steal from yourself??\n\r", ch );
		pop_call();
		return;
	}

	if (in_combat(victim))
	{
		act( "$N is moving too fast for you to steal from.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (!can_attack( ch, victim ))
	{
		act( "You may not steal from $N at the moment.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	diceroll = sleight_of_hand_roll(ch);
	dc = 20;

	if (victim->position == POS_SLEEPING)
	{
		dc -= 10;
	}

	if ( !strcasecmp( arg1, "coin"  )
	||   !strcasecmp( arg1, "coins" ) )
	{
		if (domain_apotheosis(victim, DOMAIN_TRADE) || perception_check(victim, ch, perception_roll(victim, SENSE_TOUCH), diceroll))
		{
			act( "You catch $n reaching for your coin purse.", ch, NULL, victim, TO_VICT);
			fCaught = TRUE;
			dc += get_refl_save(victim);
		}

		if (!domain_apotheosis(victim, DOMAIN_TRADE) && diceroll >= dc)
		{
			amount = victim->gold / number_range(10, 100);

			if (amount <= 0)
			{
				send_to_char("You couldn't grab any coins.\n\r", ch);
			}
			else
			{
				gold_transaction(ch, amount);
				gold_transaction(victim, 0 - amount);
		
				ch_printf_color(ch, "Bingo! You lift %s from their coin purse.\n\r", format_coins(amount, FALSE));
				gain_favor(ch, DOMAIN_TRICKERY, 2);
				fSuccess = TRUE;
			}
		}
	}
	else
	{
		if ((obj = get_obj_carry_even_invis(victim, arg1)) == NULL)
		{
			send_to_char( "You cannot find that.\n\r", ch );
			pop_call();
			return;
		}
	
		if ( !can_drop_obj( ch, obj )
		||   IS_SET(obj->extra_flags, ITEM_INVENTORY)
		||   IS_SET(obj->extra_flags, ITEM_NODROP)
		||   obj->item_type == ITEM_QUIVER
		||   obj->item_type == ITEM_SHEATH
		||   obj->item_type == ITEM_SPELLPOUCH
		||   obj->item_type == ITEM_CONTAINER)
		{
			send_to_char( "You cannot pry it away from them.\n\r", ch );
			pop_call();
			return;
		}
	
		if (ch->carry_number >= can_carry_n(ch))
		{
			send_to_char( "You have your hands full.\n\r", ch );
			pop_call();
			return;
		}
	
		if (get_carry_w(ch) + get_obj_weight( obj ) > can_carry_w( ch ) )
		{
			send_to_char( "That would weigh you down too much to steal it.\n\r", ch );
			pop_call();
			return;
		}
		
		if (get_size(ch) - obj->size < 2)
		{
			send_to_char( "That item is too large for you to palm.\n\r", ch );
			pop_call();
			return;
		}

		diceroll -= UMAX(0, get_obj_weight(obj)/10 - 1);
		
		if (domain_apotheosis(victim, DOMAIN_TRADE) || perception_check(victim, ch, perception_roll(victim, SENSE_TOUCH), diceroll))
		{
			act( "{138}You notice $n grabbing for $p.", ch, obj, victim, TO_VICT);
			fCaught = TRUE;
			dc += get_refl_save(victim);
		}

		if (!domain_apotheosis(victim, DOMAIN_TRADE) && diceroll >= dc)
		{
			obj_from_char( obj );
			obj_to_char( obj, ch );
			act( "You deftly lift $p from $N.", ch, obj, victim, TO_CHAR );
			gain_favor(ch, DOMAIN_TRICKERY, 2);
			fSuccess = TRUE;
		}
	}

	wiz_printf_room( ch, "Sleight of Hand check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), diceroll, dc, diceroll >= dc ? "SUCCESS" : "FAILURE");
	
	if (!IS_NPC(ch))
	{
		if (obj)
			log_god_printf("STEAL [%s] %s tried to steal %s from %s.", get_time_string(mud->current_time), get_name(ch), obj->name, get_name(victim));
		else
			log_god_printf("STEAL [%s] %s tried to steal coins from %s.", get_time_string(mud->current_time), get_name(ch), get_name(victim));
	}

	if (!fSuccess)
	{
		if (fCaught)
			act ("$N moves suddenly, thwarting your attempt.", ch, NULL, victim, TO_CHAR);
		else
			act ("You fail in your attempt to steal.", ch, NULL, victim, TO_CHAR);
	}
	
	for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
	{
		if (ch == fch || victim == fch || fch->position <= POS_SLEEPING)
		{
			continue;
		}
		
		if (perception_check(fch, ch, perception_roll(fch, SENSE_SIGHT), diceroll))
		{
			ch_printf_color(fch, "%s tried to steal something from %s.\n\r", 
				capitalize(PERS(ch,fch)), PERS(victim,fch));
			if (!IS_NPC(ch) && IS_GUARD(fch) && IS_CITIZEN(victim))
			{
				sprintf(buf, "Alarm! %s is a thief!!", adjective(ch));
				do_shout(fch, buf);
				fight(fch, ch);
			}
		}
	}

	if (fCaught)
	{
		if (IS_NPC(victim))
		{
			if (!IS_NPC(ch))
				ch->pcdata->theft_grudge[victim->pIndexData->vnum]++;
			
			if (CAN_TALK(victim))
			{
				sprintf(buf, "%s is a bloody thief!", adjective(ch));
				do_shout( victim, buf );
			}
			if (IS_CITIZEN(victim))
			{
				check_guard_assist(victim, ch);
				act( "$n runs off to report the crime.", victim, NULL, NULL, TO_ROOM);
				set_bounty(victim, ch, CRIME_MUGGING);
				junk_mob(victim);
				gain_reputation(ch, -1);
			}
			else if (IS_ACT(victim, ACT_WIMPY))
			{
				act( "$n skitters away!", victim, NULL, NULL, TO_ROOM);
				junk_mob(victim);
			}
			else
			{
				fight( victim, ch );
			}
		}
	}
	TAKE_ACTION(ch, ACTION_STANDARD);
	
	pop_call();
	return;
}

/*
 * Revised PLANT command, with containers, and room, for sleight of hand - Kregor
 */
void do_plant( CHAR_DATA *ch, char *argument )
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim = NULL;
	CHAR_DATA *fch;
	OBJ_DATA  *obj, *container;
	int diceroll, dc;

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

	if (!learned(ch, gsn_sleight_of_hand))
	{
		send_to_char( "You are not trained in Sleight of Hand.\n\r", ch);
		pop_call();
		return;
	}

	if (!is_handy(ch) || hands_full(ch))
	{
		send_to_char( "You have no free hand to do that.\n\r", ch );
		pop_call();
		return;
	}
	
	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );

	if (arg1[0] == '\0' || arg2[0] == '\0')
	{
		send_to_char( "Syntax: plant <object> <victim|container|room>\n\r", ch );
		pop_call();
		return;
	}

	if ((obj = get_obj_carry(ch, arg1)) == NULL)
	{
		send_to_char( "You do not have that item.\n\r", ch );
		pop_call();
		return;
	}

	if (!IS_CARRIED(obj))
	{
		send_to_char( "You aren't carrying that.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_WORN(obj))
	{
		send_to_char( "You must remove it first.\n\r", ch );
		pop_call();
		return;
	}

	if (!can_drop_obj(ch, obj))
	{
		send_to_char( "You cannot let go of it.\n\r", ch );
		pop_call();
		return;
	}

	if (get_size(ch) - obj->size < 2)
	{
		send_to_char( "That item is too large for you to palm.\n\r", ch );
		pop_call();
		return;
	}

	diceroll = sleight_of_hand_roll(ch);
	diceroll -= UMAX(0, get_obj_weight(obj)/10 - 1);

	// plant in room
	if (!strcasecmp(arg2, "room"))
	{
		if (IS_OBJ_STAT(obj, ITEM_HIDDEN))
		{
			send_to_char( "You cannot let go of it.\n\r", ch );
			pop_call();
			return;
		}
		
		if (!ch->in_room || IS_SET(ch->in_room->room_flags, ROOM_NO_COVER))
		{
			send_to_char( "There's nowhere to hide it!\n\r", ch );
			pop_call();
			return;
		}

		if (in_combat(ch))
			dc = 20;
		else
			dc = 10;
		
		if (sleight_of_hand_check(ch, NULL, diceroll, dc))
		{
			obj_from_char(obj);
			if (IS_OBJ_STAT(obj, ITEM_CONCEALED))
				REMOVE_BIT(obj->extra_flags,ITEM_CONCEALED);
			SET_BIT(obj->extra_flags,ITEM_HIDDEN);
			obj->value[7] = diceroll;
			obj_to_room( obj, ch->in_room->vnum );
			act( "You attempt to hide $p in your surroundings.",ch,obj,NULL,TO_CHAR);
			pop_call();
			return;

			for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
			{
				if (ch == fch || fch == victim || !IS_AWAKE(fch))
				{
					continue;
				}
				if (perception_check(fch, ch, perception_roll(fch, SENSE_SIGHT), diceroll))
				{		
					act( "{138}$N tries to plant $p nearby.", fch, obj, ch, TO_CHAR );
				}
			}
		}
		else
		{
			if (IS_OBJ_STAT(obj, ITEM_CONCEALED))
				REMOVE_BIT(obj->extra_flags,ITEM_CONCEALED);
			act( "$n tries to plant $p nearby, and fails.", ch, obj, NULL, TO_ROOM);
			act( "You fail to plant $p in your surroundings.",ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		TAKE_ACTION(ch, ACTION_STANDARD);
	
		pop_call();
		return;
	}

	//plant in container
	if ((container = get_obj_carry(ch, arg2)) != NULL || (container = get_obj_here(ch, arg2)) != NULL)
	{
		if (container->item_type != ITEM_SPELLPOUCH && container->item_type != ITEM_CONTAINER
		&& container->item_type != ITEM_SHEATH && container->item_type != ITEM_CART && container->item_type != ITEM_QUIVER)
		{
			act( "$p is not a container.", ch, container, NULL, TO_CHAR );
			pop_call();
			return;
		}
	
		if (IS_SET(container->value[1], CONT_CLOSED))
		{
			act( "$p is closed.", ch, container, NULL, TO_CHAR );
			pop_call();
			return;
		}

		if (in_combat(ch))
		{
			if (container->carried_by == ch)
			{
				dc = 15;
			}
			else
			{			
				dc = 20;
			}
		}
		else
			dc = 10;

		if (sleight_of_hand_check(ch, victim, diceroll, dc))
		{
			if (put_obj(ch, obj, container, FALSE, FALSE))
			{
				act( "You attempt to slip $p discreetly into $P.", ch, obj, container, TO_CHAR);		

				for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
				{
					if (ch == fch || fch == victim || !IS_AWAKE(fch))
					{
						continue;
					}
					if (perception_check(fch, ch, perception_roll(fch, SENSE_SIGHT), diceroll))
					{		
						ch_printf_color( fch, "{138}%s tries to slip %s {138}into %s.\n\r", PERS(ch, fch), obj->short_descr, container->short_descr);
					}
				}
			}
			else
			{
				act( "You cannot seem to plant $p in $P.", ch, obj, container, TO_CHAR);
			}
		}
		else
		{
			put_obj(ch, obj, container, TRUE, TRUE);
		}
		TAKE_ACTION(ch, ACTION_STANDARD);
		pop_call();
		return;
	}
		
	//plant on person
	if ((victim = get_char_room(ch, arg2)) == NULL)
	{
		send_to_char( "They aren't here.\n\r", ch );
		pop_call();
		return;
	}

	if (find_keeper(ch) == victim)
	{
		send_to_char( "You may only sell items to a shop keeper.\n\r", ch );
		pop_call();
		return;
	}

	CHECK_TURN(ch, victim);

	if (get_carry_w(victim) + get_obj_weight(obj) > can_carry_w(victim))
	{
		act( "That is too heavy to plant on $N.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return;
	}
	
	if (in_combat(victim) || in_combat(ch))
		dc = 30;
	else
		dc = 20;

	if (domain_apotheosis(victim, DOMAIN_TRADE) || perception_check(victim, ch, perception_roll(victim, SENSE_SIGHT), diceroll))
	{
		act( "{138}$n tries to plant something on you!", ch, obj, victim, TO_VICT);
		dc += get_refl_save(victim);
	}
	
	if (domain_apotheosis(victim, DOMAIN_TRADE) || !sleight_of_hand_check(ch, victim, diceroll, dc))
	{
		act( "$N moves suddenly, thwarting your attempt to plant $p.", ch, obj, victim, TO_CHAR);

		for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
		{
			if (ch == fch || fch == victim || fch->position <= POS_SLEEPING)
			{
				continue;
			}
			if (perception_check(fch, ch, perception_roll(fch, SENSE_SIGHT), diceroll))
			{		
				ch_printf_color( fch, "{138}%s tries to plant something on %s.\n\r", PERS(ch, fch), PERS(victim, fch));
			}
		}
	}
	else
	{
		act( "You attempt to plant $p on $N.", ch, obj, victim, TO_CHAR);
		if (IS_OBJ_STAT(obj, ITEM_CONCEALED))
		{
			REMOVE_BIT(obj->extra_flags, ITEM_CONCEALED);
		}
		obj_from_char( obj );
		obj_to_char( obj, victim );

		if (perception_check(victim, ch, perception_roll(victim, SENSE_TOUCH), diceroll))
		{
			act( "{138}$n attempts to plant $p on you!", ch, obj, victim, TO_VICT);
		}
		for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
		{
			if (ch == fch || fch == victim || fch->position <= POS_SLEEPING)
			{
				continue;
			}
			if (perception_check(fch, ch, perception_roll(fch, SENSE_SIGHT), diceroll))
			{		
				ch_printf_color( fch, "{138}%s tries to plant %s {138}on %s.\n\r", PERS(ch, fch), obj->short_descr, PERS(victim, fch));
			}
		}
	}
	TAKE_ACTION(ch, ACTION_STANDARD);
	pop_call();
	return;
}

/*
 * Pick for the Open Lock skill
 */
void do_pick( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *gch;
	OBJ_DATA *obj;
	int door, dc, diceroll;

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

	if (!check_blind(ch))
	{
		pop_call();
		return;
	}

	if (!IS_NPC(ch) && !learned(ch, gsn_pick_lock) && !learned(ch, gsn_jack_of_all_trades))
	{
		act( "You wouldn't even begin to know how to do that!", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (!is_handy(ch) || hands_full(ch))
	{
		send_to_char( "You have no free hand to do that.\n\r", ch );
		pop_call();
		return;
	}
	
	one_argument(argument, arg);

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

	if ((door = find_door(ch, arg)) >= 0)
	{
		ROOM_INDEX_DATA *to_room;
		EXIT_DATA *pExit;
		EXIT_DATA *pExit_rev;

		pExit = ch->in_room->exit[door];

		if (!IS_SET(pExit->exit_info, EX_CLOSED))
		{
			act( "The $d is not closed.", ch, pExit->keyword, NULL, TO_CHAR);
			pop_call();
			return;
		}
		if (!IS_SET(pExit->exit_info, EX_LOCKED) || IS_SET(pExit->exit_info, EX_KNOCKED))
		{
			act( "The $d is already unlocked.", ch, pExit->keyword, NULL, TO_CHAR);
			pop_call();
			return;
		}
		if (pExit->key == -1)
		{
			act( "There is no lock to pick.", ch, NULL, NULL, TO_CHAR);
			pop_call();
			return;
		}	
		if (pExit->key == -2)
		{
			send_to_char("You could just try using the latch to UNLOCK it?\n\r", ch);
			pop_call();
			return;
		}

		if (!ch->concentrating)
		{
			/* look for guards */
			for (gch = ch->in_room->first_person ; gch ; gch = gch->next_in_room)
			{
				if (!can_see(ch, gch))
					continue;
		
				if (IS_GUARD(gch))
				{
					do_say(gch, "You, there! What do you think you are doing?");
					act( "$N shoves you away from the lock!", ch, NULL, gch, TO_CHAR );
					pop_call();
					return;
				}
			}
		
			act( "You set to work picking the $d...", ch, pExit->keyword, NULL, TO_CHAR);
			act( "$n sets to work picking the $d...", ch, pExit->keyword, NULL, TO_ROOM);
			ch->concentrating = TRUE;
			ch->skill_timer		= 16;
			ch->timer_fun			= do_pick;
			RESTRING(ch->cmd_argument, argument);
			TAKE_ACTION(ch, ACTION_FULL);
			pop_call();
			return;
		}

		if (IS_SET(pExit->exit_info, EX_PICKPROOF) || IS_SET(pExit->exit_info, EX_MAGICAL_LOCK))
		{
			act( "The $d is barred from passage.", ch, pExit->keyword, NULL, TO_CHAR);
			pop_call();
			return;
		}

		diceroll = pick_lock_roll(ch);
	
		dc = lock_dc(pExit, NULL);

		if (!pick_lock_check(ch, NULL, diceroll, dc))
		{
			act( "You attempt to pick the $d's lock but fail.",  ch, pExit->keyword, NULL, TO_CHAR);
			act( "$n attempts to pick the $d's lock but fails.", ch, pExit->keyword, NULL, TO_ROOM);

			pop_call();
			return;
		}

		REMOVE_BIT(pExit->exit_info, EX_LOCKED);

		act( "A satisfying 'click' tells you the $d's lock is open.", ch, pExit->keyword, NULL, TO_CHAR);
		act( "$n picks the $d's lock with a gentle 'click'.", ch, pExit->keyword, NULL, TO_ROOM);

		/*
		 * pick the other side
		 */
		if ((to_room = room_index[pExit->to_room]) != NULL
		&&  (pExit_rev = to_room->exit[rev_dir[door]]) != NULL
		&&   room_index[pExit_rev->to_room] == ch->in_room)
		{
			REMOVE_BIT( pExit_rev->exit_info, EX_LOCKED );
		}
		pop_call();
		return;
	}

	/*
	 * pick a container
	 */
	if ((obj = get_obj_here(ch, arg)) != NULL)
	{
		if (obj->item_type == ITEM_CONTAINER)
		{
			if (!IS_SET(obj->value[1], CONT_CLOSED))
			{
				act( "$p is not closed.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
	
			if (!IS_SET(obj->value[1], CONT_LOCKED) || IS_SET(obj->value[1], CONT_KNOCKED))
			{
				act( "$p is already unlocked.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
	
			if (obj->value[2] == -1)
			{
				act( "$p has no lock to pick.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
	
			if (!ch->concentrating)
			{
				act( "You set to work picking the $p...", ch, obj, NULL, TO_CHAR);
				act( "$n sets to work picking the $p...", ch, obj, NULL, TO_ROOM);
				ch->concentrating = TRUE;
				ch->skill_timer		= 16;
				ch->timer_fun			= do_pick;
				RESTRING(ch->cmd_argument, argument);
				TAKE_ACTION(ch, ACTION_FULL);
				pop_call();
				return;
			}
	
			if (IS_SET(obj->value[1], CONT_PICKPROOF) || IS_SET(obj->value[1], CONT_MAGICAL_LOCK))
			{
				act( "$p's lock cannot be picked.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
	
			diceroll = pick_lock_roll(ch);
	
			dc = lock_dc(NULL, obj);
	
			if (!pick_lock_check(ch, NULL, diceroll, dc))
			{
				act( "You attempt to pick $p's lock but fail.",  ch, obj, NULL, TO_CHAR);
				act( "$n attempts to pick $p's lock but fails.", ch, obj, NULL, TO_ROOM);
	
				pop_call();
				return;
			}
	
			REMOVE_BIT(obj->value[1], CONT_LOCKED);
	
			act( "You pick $p's lock with a satifying 'click'.", ch, obj, NULL, TO_CHAR);
			act( "$n picks $p's lock with a gentle 'click'.", ch, obj, NULL, TO_ROOM);
	
			TAKE_ACTION(ch, ACTION_STANDARD);
			pop_call();
			return;
		}
		if (obj->item_type == ITEM_PORTAL)
		{
			if (!IS_SET(obj->value[2], PORTAL_CLOSED))
			{
				act( "$p is not closed.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
	
			if (!IS_SET(obj->value[2], PORTAL_LOCKED) || IS_SET(obj->value[2], PORTAL_KNOCKED))
			{
				act( "$p is already unlocked.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
			
			if (obj->value[1] == -1)
			{
				act( "$p has no lock to pick.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
	
			if (!ch->concentrating)
			{
				act( "You set to work unlocking the $p...", ch, obj, NULL, TO_CHAR);
				act( "$n sets to work unlocking the $p...", ch, obj, NULL, TO_ROOM);
				ch->concentrating = TRUE;
				ch->skill_timer		= 16;
				ch->timer_fun			= do_pick;
				RESTRING(ch->cmd_argument, argument);
				TAKE_ACTION(ch, ACTION_FULL);
				pop_call();
				return;
			}
	
			if (IS_SET(obj->value[2], PORTAL_PICKPROOF))
			{
				act( "$p's lock cannot be picked.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
	
			diceroll = pick_lock_roll(ch);
	
			dc = lock_dc(NULL, obj);
	
			if (!pick_lock_check(ch, NULL, diceroll, dc))
			{
				act( "You attempt to pick $p's lock but fail.",  ch, obj, NULL, TO_CHAR);
				act( "$n attempts to pick $p's lock but fails.", ch, obj, NULL, TO_ROOM);
	
				pop_call();
				return;
			}
	
			REMOVE_BIT(obj->value[2], PORTAL_LOCKED);
	
			act( "You pick $p's lock with a satifying 'click'.", ch, obj, NULL, TO_CHAR);
			act( "$n picks $p's lock with a gentle 'click'.", ch, obj, NULL, TO_ROOM);
	
			TAKE_ACTION(ch, ACTION_STANDARD);
			pop_call();
			return;
		}
		else
		{
			act( "$p is not a container or portal.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
	}
	else
	{
		act( "You see no $T here.", ch, NULL, arg, TO_CHAR );
	}
	pop_call();
	return;
}


/*
 * For the Disable Device skill
 */
void do_disable( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	OBJ_DATA *obj, *trap;
	int door, diceroll, dc, ranks, check;

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

	if (!check_blind(ch))
	{
		pop_call();
		return;
	}

	if (!IS_NPC(ch) && !learned(ch, gsn_disable_device) && !learned(ch, gsn_jack_of_all_trades))
	{
		act( "You wouldn't even begin to know how to do that!", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (!is_handy(ch) || hands_full(ch))
	{
		send_to_char( "You have no free hand to do that.\n\r", ch );
		pop_call();
		return;
	}
	
	one_argument(argument, arg);

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

	/* disarm a move or door direction */
	if ((door = find_door(ch, arg)) >= 0)
	{
		EXIT_DATA *pExit;

		pExit = ch->in_room->exit[door];

		if ((trap = get_room_trap(ch->in_room, trap_dir[door]|trap_door[door])) == NULL)
		{
			send_to_char( "There is nothing to disable in that direction.\n\r", ch );
			pop_call();
			return;
		}
		
		dc = trap_dc(trap);

		if (!ch->concentrating)
		{
			act( "You set to work disarming a trap to the $t...", ch, dir_name[door], NULL, TO_CHAR);
			act( "$n sets to work disarming a trap to the $t...", ch, dir_name[door], NULL, TO_ROOM);
			ch->concentrating = TRUE;
			ch->skill_timer		= 16;
			ch->timer_fun			= do_disable;
			RESTRING(ch->cmd_argument, argument);
			TAKE_ACTION(ch, ACTION_FULL);
			pop_call();
			return;
		}

		diceroll = disable_device_roll(ch);
		if ((ranks = multi_class_level(ch, gsn_trapfinding)) > 0)
			diceroll += UMAX(1, ranks/2);
	
		if ((check = disable_device_check(ch, NULL, diceroll, dc)) <= -5)
		{
			if (spring_trap(ch, trap))
			{
				pop_call();
				return;
			}
		}
		else if (check < 0)
		{
			act( "You fail to disable the trap.",  ch, NULL, NULL, TO_CHAR);
			act( "$n fails to disable the trap.", ch, NULL, NULL, TO_ROOM);
			pop_call();
			return;
		}

		act( "You successfully disarm the trap.", ch, NULL, NULL, TO_CHAR);
		act( "$n successfully disarms trap.", ch, NULL, NULL, TO_ROOM);

		TRAP_STATE(trap) = TRAP_UNARMED;
		pop_call();
		return;
	}

	/*
	 * detrap an object
	 */
	if ((obj = get_obj_here(ch, arg)) != NULL)
	{
		if ((trap = get_obj_trap(obj)) == NULL)
		{
			act( "$p is not trapped.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		
		diceroll = disable_device_roll(ch);
		if ((ranks = multi_class_level(ch, gsn_trapfinding)) > 0)
			diceroll += UMAX(1, ranks/2);

		dc = trap_dc(trap);

		if (!ch->concentrating)
		{
			act( "You set to work detrapping $p...", ch, obj, NULL, TO_CHAR);
			act( "$n sets to work detrapping $p...", ch, obj, NULL, TO_ROOM);
			ch->concentrating = TRUE;
			ch->skill_timer		= 12;
			ch->timer_fun			= do_disable;
			RESTRING(ch->cmd_argument, argument);
			TAKE_ACTION(ch, ACTION_FULL);
			pop_call();
			return;
		}

		if ((check = disable_device_check(ch, NULL, diceroll, dc)) <= -5)
		{
			if (spring_trap(ch, trap))
			{
				pop_call();
				return;
			}
		}
		if (check < 0)
		{
			act( "You fail to disable the trap.",  ch, NULL, NULL, TO_CHAR);
			act( "$n fails to disable the trap.", ch, NULL, NULL, TO_ROOM);
			pop_call();
			return;
		}

		act( "You successfully disarm the trap.", ch, NULL, NULL, TO_CHAR);
		act( "$n successfully disarms trap.", ch, NULL, NULL, TO_ROOM);

		TRAP_STATE(trap) = TRAP_UNARMED;
		pop_call();
		return;
	}
	else
	{
		act( "You see no $T here.", ch, NULL, arg, TO_CHAR );
	}
	pop_call();
	return;
}


/*
 * snagged from GodWars code, but redone for Mud20 standard - Kregor
 */
void do_tie( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	OBJ_DATA *rope;
	AFFECT_DATA af;
	char arg[MAX_INPUT_LENGTH];
	int bonus;
	
	push_call("do_tie()");
	
	if (*argument == '\0')
	{
		send_to_char("Tie up whom?\n\r", ch);
		pop_call();
		return;
	}
		
	argument = one_argument( argument, arg );

	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		send_to_char("They aren't here.\n\r", ch);
		pop_call();
		return;
	}
	if (victim == ch)
	{
		send_to_char("You cannot tie yourself up!\n\r", ch);
		pop_call();
		return;
	}
	if (IS_AFFECTED(victim, AFF2_TIED_UP))
	{
		act("$N is already tied up.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}
	if (!IS_HELPLESS(victim))
	{
		send_to_char("You can only tie up a defenseless person.\n\r", ch);
		pop_call();
		return;
	}
	if (is_safe(ch, victim))
	{
		send_to_char("Wards of peace prevent you from doing that.\n\r", ch);
		pop_call();
		return;
	}
	
	for (rope = ch->first_carrying ; rope ; rope = rope->next)
	{
		if (TOOL_TYPE(rope, TOOL_ROPE))
			break;
		if (TOOL_TYPE(rope, TOOL_SHACKLES))
			break;
	}
	if (!rope)
	{
		act("You have nothing to tie $N up with.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (!ch->concentrating)
	{
		act( "You quickly set to tying up $N...", ch, NULL, victim, TO_CHAR);
		act( "$n quickly sets to tying up $N...", ch, NULL, victim, TO_NOTVICT);
		act( "$n quickly sets to tying you up...", ch, NULL, victim, TO_VICT);
		ch->concentrating = TRUE;
		ch->skill_timer		= 16;
		ch->timer_fun			= do_tie;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	if (TOOL_TYPE(rope, TOOL_SHACKLES))
	{
		bonus = 30;
	}
	else
	{
		bonus = dice(1,20) + combat_maneuver_bonus(ch) + synergy_bonus(ch, gsn_escape_artist);
	}

	if (IS_OBJ_STAT(rope, ITEM_MASTERWORK))
	{
		bonus += UMAX(5, rope->value[2]);
	}

	af.type      = -1;
	af.duration  = -1;
	af.location  = APPLY_NONE;
	af.modifier  = bonus;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_TIED_UP;
	af.level     = ch->level;
	affect_join( ch, victim, &af );

	act("You tightly bind $N.", ch, NULL, victim, TO_CHAR);
	act("$n binds $N.", ch, NULL, victim, TO_ROOM);
	send_to_char("You have been tied up!\n\r",victim);
	
	obj_from_char(rope);
	obj_to_char(rope, victim);

	pop_call();
	return;
}


void do_untie( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	AFFECT_DATA *paf;
	char arg[MAX_INPUT_LENGTH];
	
	push_call("do_tie()");
	
	if (*argument == '\0')
	{
		send_to_char("Untie whom?\n\r", ch);
		pop_call();
		return;
	}
		
	argument = one_argument(argument, arg);

	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		send_to_char("They aren't here.\n\r", ch);
		pop_call();
		return;
	}
	for (paf = victim->first_affect ; paf ; paf = paf->next)
	{
		if (paf->bitvector == AFF2_TIED_UP)
			break;
	}
	if (!paf)
	{
		if (victim == ch)
			act("You are not tied up.", ch, NULL, NULL, TO_CHAR);
		else
			act("$N is not tied up.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	if (!ch->concentrating)
	{
		if (ch == victim)
		{
			act( "You attempt to escape your bonds...", victim, NULL, NULL, TO_CHAR);
			act( "$n attempts to escape $s bonds...", victim, NULL, NULL, TO_ROOM);
		}
		else
		{
			act( "You begin untying $N...", ch, NULL, victim, TO_CHAR);
			act( "$n begins untying $N...", ch, NULL, victim, TO_NOTVICT);
			act( "$n begins untying you...", ch, NULL, victim, TO_VICT);
		}
		ch->concentrating = TRUE;
		ch->skill_timer		= 16;
		ch->timer_fun			= do_untie;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	// added in skill check for escape artist, to allow victim to unbind himself - Kregor.
	if (victim == ch)
	{
		if (!escape_artist_check(ch, NULL, escape_artist_roll(ch), UMAX(20, paf->modifier)))
		{
			act("You fail to break free.", victim, NULL, NULL, TO_CHAR);
			act("$n fails to break free.", victim, NULL, NULL, TO_ROOM);
			pop_call();
			return;
		}
	}
		
	act("You are untied.", victim, NULL, NULL, TO_CHAR);
	act("$n in untied.", victim, NULL, NULL, TO_ROOM);

	affect_from_char(victim, paf);
	pop_call();
	return;
}


/*
 * It's cleaner to make this a function - Kregor
 */
int synergy_bonus( CHAR_DATA *ch, int sn )
{
	int ranks, bonus;

	push_call("synergy_bonus(%p)",ch);
	
	if ((ranks = learned(ch, sn)) < 5)
	{
		pop_call();
		return 0;
	}
	bonus = ranks / 5 + 1;

	pop_call();
	return bonus;
}


/*
 * Skill check functions - Kregor
 */
int appraise_roll( CHAR_DATA *ch, OBJ_DATA *obj )
{
	int roll;
	int ranks = learned(ch, gsn_appraise);

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

	if (obj && IS_OBJ_STAT(obj, ITEM_MAGIC) && learned(ch, gsn_scholar))
		roll = 20;
	else
		roll = dice(1,20);

	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_mercantilism))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += ranks;
	
	roll += get_apply(ch, APPLY_APPRAISE);

	if (learned(ch, gsn_silver_palm))
		roll += ranks / 5 + 2;

	if (has_familiar(ch, RACE_BIRD))
		roll += 3;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int bluff_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_bluff);

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

	roll = dice(1,20);
	if (domain_apotheosis(ch, DOMAIN_TRICKERY))
		roll = UMAX(roll, dice(1,20));
	roll += stat_mods(ch, APPLY_CHA);
	roll += ranks;
	if (domain_skill(ch, gsn_divine_trickery))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += multi_class_level(ch, gsn_oratory) / 2;

	roll += get_apply(ch, APPLY_BLUFF);
	
	if (learned(ch, gsn_deceitful))
		roll += ranks / 5 + 2;
		
	if (has_familiar(ch, RACE_SNAKE))
		roll += 3;

	if (get_monk_style(ch) == STYLE_PASSIVE_WAY)
		roll += 2;

	if (learned(ch, gsn_serpents_tongue))
		roll += 4;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int feint_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks;

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

	if (learned(ch, gsn_agile_feint))
	{
		roll = dice(1,20);
	
		ranks = base_attack(ch);
		roll += stat_mods(ch, APPLY_DEX);
		roll += ranks;
		
		if (learned(ch, gsn_deceitful))
			roll += ranks / 5 + 2;

		if (domain_skill(ch, gsn_divine_trickery))
			roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));

		if (has_familiar(ch, RACE_SNAKE))
			roll += 3;
	
		if (get_monk_style(ch) == STYLE_PASSIVE_WAY)
			roll += 2;
	
		// strip one-shot enhancements
		if (is_affected(ch, gsn_guidance))
			affect_strip(ch, gsn_guidance);
		if (is_affected(ch, gsn_moment_of_prescience))
			affect_strip(ch, gsn_moment_of_prescience);
	}
	else
	{
		roll = bluff_roll(ch);
	}

	pop_call();
	return( roll );
}

int climb_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_climb);

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

	roll = take_ten(ch);
	roll += ranks;
	/* feat added for races which use dex instead of str to climb */
	if (learned(ch, gsn_agile_climber))
		roll += stat_mods(ch, APPLY_DEX);
	else
		roll += stat_mods(ch, APPLY_STR);
	
	roll += get_apply(ch, APPLY_CLIMB);
	
	if (IS_BLIND(ch))
		roll -= 4;
		
	roll -= armor_check_penalty(ch);

	if (learned(ch, gsn_athletic))
		roll += ranks / 5 + 2;

	if (has_familiar(ch, RACE_LIZARD))
		roll += 3;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int concentration_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_concentration);

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

	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_CON);
	roll += ranks;
	
	roll += get_apply(ch, APPLY_CONCENTRATE);
	
	if (get_monk_style(ch) == STYLE_UNDYING_WAY)
		roll += 2;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int decipher_script_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks;

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

	if ((ranks = learned(ch, gsn_decipher_script)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return( -99 );
	}

	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_INT);
	roll += ranks;
		
	roll += get_apply(ch, APPLY_DECIPHER);
	
	if (learned(ch, gsn_linguist))
		roll += ranks / 5 + 2;
		
	roll += multi_class_level(ch, gsn_greater_lore);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int diplomacy_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_diplomacy);

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_CHA);
	if (domain_skill(ch, gsn_divine_mercantilism))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += ranks;
	roll += multi_class_level(ch, gsn_oratory) / 2;
	
	roll += get_apply(ch, APPLY_DIPLOMACY);
	
	if (learned(ch, gsn_persuasive))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_bluff);
	roll += synergy_bonus(ch, gsn_sense_motive);
	roll += synergy_bonus(ch, gsn_know_nobility);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int disable_device_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks;

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

	if ((ranks = learned(ch, gsn_disable_device)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return( -99 );
	}
	roll = take_ten(ch);

	if (domain_apotheosis(ch, DOMAIN_TRICKERY))
		roll = UMAX(roll, dice(1,20));
	
	if (learned(ch, gsn_skill_mastery))
		roll = UMAX(10, roll);

	roll += stat_mods(ch, APPLY_INT);
	roll += ranks;
	
	roll += get_apply(ch, APPLY_DISABLE);
	
	if (learned(ch, gsn_deft_hands))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_craft_traps);

	if (IS_BLIND(ch))
		roll -= 4;
		
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int disguise_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_disguise);

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

	if (!IS_NPC(ch))
	{
		if ((roll = ch->pcdata->disguise_roll) == 0)
		{
			roll = dice(1,20);
		}
	}
	else
	{
		roll = dice(1,20);
	}

	if (domain_apotheosis(ch, DOMAIN_TRICKERY))
		roll = UMAX(roll, dice(1,20));
	
	roll += stat_mods(ch, APPLY_CHA);
	if (domain_skill(ch, gsn_divine_trickery))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += ranks;
		
	if (learned(ch, gsn_deceitful))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_bluff);
	roll += synergy_bonus(ch, gsn_perform);

	roll += multi_class_level(ch, gsn_faceless);
		
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int escape_artist_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_escape_artist);

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_DEX);
	roll += ranks;
	
	roll += get_apply(ch, APPLY_ESCAPE);
	
	roll -= armor_check_penalty(ch);

	if (learned(ch, gsn_nimble))
		roll += ranks / 5 + 2;

	if (get_monk_style(ch) == STYLE_COBRA_STRIKE)
		roll += 2;

	if (IS_BLIND(ch))
		roll -= 4;
		
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int first_aid_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_first_aid);

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

	roll = get_apply(ch, APPLY_FIRST_AID);
	
	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_WIS);
	roll += ranks;
	
	if (learned(ch, gsn_self_sufficient))
		roll += ranks / 5 + 2;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int haggle_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_haggle);

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_CHA);
	if (domain_skill(ch, gsn_divine_mercantilism))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += ranks;
		
	if (learned(ch, gsn_silver_palm))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_appraise);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int handle_animal_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks;

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

	ranks = learned(ch, gsn_handle_animal);

	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_CHA);
	roll += ranks;

	roll += get_apply(ch, APPLY_HANDLE_ANIM);
	
	if (learned(ch, gsn_wild_empathy))
		roll += UMAX(0, stat_bonus(TRUE, ch, APPLY_WIS));
	if (learned(ch, gsn_animal_affinity))
		roll += ranks / 5 + 2;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int intimidate_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_intimidate);

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

	roll = dice(1,20);
	if (learned(ch, gsn_strongarm_diplomacy))
		roll += stat_mods(ch, APPLY_STR);
	else
		roll += stat_mods(ch, APPLY_CHA);
	roll += ranks;
	roll += multi_class_level(ch, gsn_oratory) / 2;
	
	roll += get_apply(ch, APPLY_INTIMIDATE);
	
	if (learned(ch, gsn_persuasive))
		roll += ranks / 5 + 2;
		
	roll += synergy_bonus(ch, gsn_bluff);
	
	if (learned(ch, gsn_aura_of_cowardice))
		roll += 4;
		
	if (domain_apotheosis(ch, DOMAIN_WRATH))
		roll += UMAX(1, stat_bonus(TRUE, ch, APPLY_WIS));

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int jump_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_jump);

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

	roll = take_ten(ch);
	if (learned(ch, gsn_agile_climber))
		roll += stat_mods(ch, APPLY_DEX);
	else
		roll += stat_mods(ch, APPLY_STR);
	roll += ranks;
	
	roll += get_apply(ch, APPLY_JUMP);
	
	roll -= armor_check_penalty(ch);

	if (learned(ch, gsn_acrobatic))
		roll += ranks / 5 + 2;

	if (IS_BLIND(ch))
		roll -= 4;
		
	roll += synergy_bonus(ch, gsn_tumble);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int mount_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_mount);

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

	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_DEX);
	roll += ranks;
	
	roll += get_apply(ch, APPLY_MOUNT);

	if (has_armor_penalty(ch))
		roll -= armor_check_penalty(ch);

	if (learned(ch, gsn_animal_affinity))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_handle_animal);

	if (IS_BLIND(ch))
		roll -= 4;
		
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int pick_lock_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks;

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

	if ((ranks = learned(ch, gsn_pick_lock)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return( -99 );
	}
	roll = take_twenty(ch);
	
	if (learned(ch, gsn_skill_mastery))
		roll = UMAX(10, roll);

	roll += stat_mods(ch, APPLY_DEX);
	roll += ranks;
	
	if (has_armor_penalty(ch))
		roll -= armor_check_penalty(ch);
	
	roll += get_apply(ch, APPLY_OPEN_LOCK);
	
	if (learned(ch, gsn_deft_hands))
		roll += ranks / 5 + 2;

	if (IS_BLIND(ch))
		roll -= 4;
		
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int perception_roll( CHAR_DATA *ch, int sense )
{
	int roll;
	int ranks = learned(ch, gsn_perception);

	push_call("perception_roll(%p)",ch);
	
	if (sense == SENSE_SIGHT && IS_BLIND(ch))
	{
		pop_call();
		return -99;
	}
	if (sense == SENSE_SOUND && IS_DEAF(ch))
	{
		pop_call();
		return -99;
	}

	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_WIS);
	roll += ranks;
		
	if (learned(ch, gsn_alertness))
		roll += ranks / 5 + 2;

	if (get_monk_style(ch) == STYLE_INVISIBLE_EYE)
		roll += 2;

	if (sense == SENSE_SIGHT)
	{
		roll += race_skill(ch, gsn_sight_perception);
		roll += get_apply(ch, APPLY_SIGHT);
	}
	else if (sense == SENSE_SOUND)
	{
		roll += race_skill(ch, gsn_sound_perception);
		roll += get_apply(ch, APPLY_LISTEN);
	}
	else if (sense == SENSE_TOUCH)
		roll += race_skill(ch, gsn_touch_perception);
	else if (sense == SENSE_TASTE)
		roll += race_skill(ch, gsn_taste_perception);
	else if (sense == SENSE_SMELL)
	{
		roll += race_skill(ch, gsn_smell_perception);
		if (learned(ch, gsn_scent))
			roll += 8;
	}

	if (IS_DAZZLED(ch))
		roll -= 2;
		
	if (sense == SENSE_SIGHT)
	{
		if (IS_OUTSIDE(ch))
		{
			if (mud->sunlight != SUN_DARK && has_familiar(ch, RACE_HAWK))
				roll += 3;
			else if (mud->sunlight == SUN_DARK && has_familiar(ch, RACE_OWL))
				roll += 3;
			if (ch->in_room->area->weather_info->sky >= 2
			|| ch->in_room->area->weather_info->sky >= 8)
			{
				roll -= 4;
			}
		}
		else if (has_familiar(ch, RACE_OWL))
			roll += 3;
	}

	if (sense == SENSE_SOUND)
	{
		if (IS_OUTSIDE(ch))
		{
			if (ch->in_room->area->weather_info->sky >= 2
			|| ch->in_room->area->weather_info->sky >= 8)
			{
				roll -= 4;
			}
		}
		if (has_familiar(ch, RACE_BAT))
		{
			roll += 3;
		}
	}

	pop_call();
	return( UMAX(0, roll) );
}

int perform_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_perform);

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

	roll = dice(1,20);
	if (learned(ch, gsn_magna_alumnus))
		roll = UMAX(10, roll);
		
	roll += stat_mods(ch, APPLY_CHA);
	roll += ranks;
	
	roll += get_apply(ch, APPLY_PERFORM);
	
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int search_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_search);

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

	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_INT);
	roll += ranks;
	
	roll += get_apply(ch, APPLY_SEARCH);
	
	if (learned(ch, gsn_insightful))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_perception);

	if (IS_BLIND(ch))
		roll -= 4;
	else if (IS_DAZZLED(ch))
		roll -= 1;
		
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int sense_motive_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_sense_motive);

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

	roll = wis_roll(ch) + ranks;
	
	roll += get_apply(ch, APPLY_SENSE_MOT);
	
	if (learned(ch, gsn_negotiator))
		roll += ranks / 5 + 2;
	if (learned(ch, gsn_insightful))
		roll += ranks / 5 + 2;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int sleight_of_hand_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks;

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

	ranks = learned(ch, gsn_sleight_of_hand);

	if (learned(ch, gsn_stealth_mastery))
		roll = take_twenty(ch);
	else
		roll = take_ten(ch);
	
	if (domain_apotheosis(ch, DOMAIN_TRICKERY))
		roll = UMAX(roll, dice(1,20));
	
	if (learned(ch, gsn_skill_mastery))
		roll = UMAX(10, roll);
		
	roll += stat_mods(ch, APPLY_DEX);
	if (domain_skill(ch, gsn_divine_trickery))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += ranks;
	
	roll += get_apply(ch, APPLY_SLEIGHT);
	
	roll -= armor_check_penalty(ch);
	
	if (learned(ch, gsn_nimble))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_bluff);

	if (IS_BLIND(ch))
		roll -= 4;
		
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int hide_roll( CHAR_DATA *ch )
{
	int roll = 0;
	int ranks = learned(ch, gsn_stealth);

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

	if (!IS_AFFECTED(ch, AFF_HIDE))
	{
		pop_call();
		return -99;
	}
	
	if (learned(ch, gsn_stealth_mastery))
		roll = take_twenty(ch);
	else if (learned(ch, gsn_hide_plain_sight))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += stat_mods(ch, APPLY_DEX);
	roll += ranks;
	
	roll += get_apply(ch, APPLY_STEALTH);
	
	if (learned(ch, gsn_stealthy))
		roll += ranks / 5 + 2;

	if (get_monk_style(ch) == STYLE_SLEEPING_TIGER)
		roll += 2;

	if (has_armor_penalty(ch))
		roll -= armor_check_penalty(ch);

	if (IS_BLIND(ch))
		roll -= 4;
		
	if (IS_OUTSIDE(ch) && learned(ch, gsn_camouflage))
		roll += 5;
		
	if (is_affected(ch, gsn_faerie_fire))
		roll -= 20;

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

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int sneak_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_stealth);

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

	if (!IS_AFFECTED(ch, AFF_SNEAK))
	{
		pop_call();
		return -99;
	}
	
	if (learned(ch, gsn_stealth_mastery))
		roll = take_twenty(ch);
	else if (ch->speed == 0)
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += stat_mods(ch, APPLY_DEX);
	roll += ranks;
		
	if (learned(ch, gsn_stealthy))
		roll += ranks / 5 + 2;

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

	switch (ch->speed)
	{
		case 0:
			roll += 0;
			break;
		case 1:
			if (!learned(ch, gsn_swift_stealth))
				roll -= 5;
			break;
		default:
			roll -= 20;
			break;
	}
	
	if (IS_FLYING(ch))
		roll += 20;

	if (!learned(ch, gsn_woodland_stride) && !IS_FLYING(ch)) //these two bonuses do not stack
	{
		if (ch->in_room->sector_type == SECT_FIELD
		||  ch->in_room->sector_type == SECT_HILLS
		||  ch->in_room->sector_type == SECT_MOUNTAIN
		||  ch->in_room->sector_type == SECT_DESERT
		||  ch->in_room->sector_type == SECT_SWAMP
		||  ch->in_room->sector_type == SECT_BEACH)
		{
			roll -= 2;
		}
	
		if (ch->in_room->sector_type == SECT_FOREST
		||  ch->in_room->sector_type == SECT_TUNDRA)
		{
			roll -= 5;
		}
	}

	roll += get_apply(ch, APPLY_STEALTH);
	
	roll -= armor_check_penalty(ch);

	if (IS_BLIND(ch))
		roll -= 4;
		
	if (has_familiar(ch, RACE_CAT))
		roll += 3;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int spellcraft_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks;

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

	if ((ranks = learned(ch, gsn_spellcraft)) <= 0
	&& !learned(ch, gsn_jack_of_all_trades)
	&& !learned(ch, gsn_divine_arcana))
	{
		pop_call();
		return( -99 );
	}
	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_INT);
	roll += ranks;	
	if (domain_skill(ch, gsn_divine_arcana))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	
	roll += get_apply(ch, APPLY_SPELLCRAFT);
	
	if (learned(ch, gsn_magical_aptitude))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_know_arcana);

	if (learned(ch, gsn_divine_arcana))
		roll += 2;
		
	roll += multi_class_level(ch, gsn_greater_lore);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int streetwise_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_streetwise);

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

	roll = cha_roll(ch) + ranks;
	
	roll += get_apply(ch, APPLY_GATHER_INFO);
	
	if (learned(ch, gsn_insightful))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_know_local);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int survival_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_survival);

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

	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_WIS);
	roll += ranks;
	
	if (learned(ch, gsn_self_sufficient))
		roll += ranks / 5 + 2;

	roll += get_apply(ch, APPLY_SURVIVAL);
	
	if (class_level(ch, CLASS_DRUID) > 0)
		roll += 2;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int swim_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks = learned(ch, gsn_swim);

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

	if (domain_apotheosis(ch, DOMAIN_WATER))
	{
		roll = 20;
	}
	else if (CAN_SWIM(ch))
	{
		roll = UMAX(10, dice(1,20));
	}
	else if (!IS_NPC(ch) && ch->pcdata->condition[COND_AIR] <= 0)
	{
		roll = dice(1,20);
	}
	else
	{
		switch (ch->in_room->sector_type)
		{
			case SECT_LAKE:
				roll = take_ten(ch);
				break;
			
			default:
				roll = dice(1,20);
				break;			
		}
	}
	
	roll += stat_mods(ch, APPLY_CON);
	roll += ranks;
	
	roll -= armor_check_penalty(ch) * 2;

	roll -= encumberance(ch) * 3;

	if (learned(ch, gsn_athletic))
		roll += ranks / 5 + 2;

	if (IS_BLIND(ch))
		roll -= 4;
		
	roll += get_apply(ch, APPLY_SWIM);
		
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int tumble_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks;

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

	if ((ranks = learned(ch, gsn_tumble)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return( -99 );
	}
	roll = take_ten(ch);
	roll += stat_mods(ch, APPLY_DEX);
	roll += ranks;
	
	roll += get_apply(ch, APPLY_TUMBLE);

	roll -= armor_check_penalty(ch);

	if (learned(ch, gsn_acrobatic))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_jump);

	if (get_monk_style(ch) == STYLE_DENYING_STANCE)
		roll += 2;

	if (get_monk_style(ch) == STYLE_HAND_AND_FOOT)
		roll += 2;

	if (IS_BLIND(ch))
		roll -= 4;
		
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int use_magic_roll( CHAR_DATA *ch )
{
	int roll;
	int ranks;
	
	push_call("use_magic_roll(%p)",ch);

	if ((ranks = learned(ch, gsn_use_magic)) <= 0
	&& !learned(ch, gsn_jack_of_all_trades)
	&& !learned(ch, gsn_divine_arcana))
	{
		pop_call();
		return( -99 );
	}
	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_CHA);
	roll += ranks;
	if (domain_skill(ch, gsn_divine_arcana))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	
	roll += get_apply(ch, APPLY_USE_MAGIC);

	if (learned(ch, gsn_magical_aptitude))
		roll += ranks / 5 + 2;

	roll += synergy_bonus(ch, gsn_know_arcana);

	if (learned(ch, gsn_divine_arcana))
		roll += 2;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

bool appraise_check( CHAR_DATA *ch, OBJ_DATA *obj, int roll, int dc )
{
	push_call("appraise_check(%p)",ch);

	if (obj != NULL)
	{
		if (IS_RACE(ch, RACE_DWARF))
		{
			if (obj->item_type == ITEM_ARMOR || obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_TREASURE)
				roll += 2;
		}
		if (IS_RACE(ch, RACE_GNOME) && obj->item_type == ITEM_TREASURE)
			roll += 2;
	
		if (obj->item_type == ITEM_WEAPON)
			roll += synergy_bonus(ch, gsn_craft_weapons);
	
		if (obj->item_type == ITEM_ARMOR)
			roll += synergy_bonus(ch, gsn_craft_armor);
	
		if (obj->item_type == ITEM_TREASURE)
			roll += synergy_bonus(ch, gsn_craft_jewelry);
	}
	else
	{
		log_printf("%s appraise_check: No obj.\n\r", capitalize(get_name(ch)));
		pop_call();
		return FALSE;
	}

	wiz_printf_room( ch, "Appraise check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	pop_call();
	return( roll >= dc );
}


bool bluff_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("bluff_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (och == NULL)
	{
		log_printf("%s bluff_check: Must have an opposing char.\n\r", capitalize(get_name(ch)));
		pop_call();
		return FALSE;
	}
	dc = sense_motive_roll(och);
	dc += fave_enemy_bonus(och,ch);
	roll += fave_enemy_bonus(ch,och);
	
	roll += reputation_bonus(ch);
	if (ch->race == och->race && learned(ch, gsn_noble_birth))
		roll += 2;

	if (is_affected(och, gsn_suggestion))
	{
		roll += 20;
		affect_strip(och, gsn_suggestion);
	}
	else if (is_affected(och, gsn_charm_monster))
	{
		if (get_caster(och, gsn_charm_monster) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_person))
	{
		if (get_caster(och, gsn_charm_person) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_plant))
	{
		if (get_caster(och, gsn_charm_plant) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_animal))
	{
		if (get_caster(och, gsn_charm_animal) == ch)
			roll += 10;
	}
	
	if (learned(och, gsn_secret_of_truth))
	{
		dc += 2;
	}
	
	wiz_printf_room( ch, "Bluff check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Bluff check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	
	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_TRICKERY, 2);
		gain_favor(ch, DOMAIN_CHAOS, 2);
		gain_favor(ch, DOMAIN_CHARM, 2);
	}

	pop_call();
	return( roll >= dc );
}

int climb_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	OBJ_DATA *kit;
	int mod = 0;

	push_call("climb_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (IS_SET(ch->in_room->room_flags, ROOM_ICE) && !IS_AFFECTED(ch, AFF_WATER_WALK))
	{
		dc += 5;
	}
	else if (IS_OUTSIDE(ch) && ch->in_room->area->weather_info->sky == 3)
	{
		dc += 5;
	}
	else if (IS_OUTSIDE(ch) && ch->in_room->area->weather_info->sky == 2)
	{
		dc += 2;
	}

	if ((kit = get_obj_carry_type(ch, ITEM_TOOLS)) != NULL)
	{
		if (TOOL_TYPE(kit, TOOL_CLIMBERS_KIT))
		{
			if (IS_OBJ_STAT(kit, ITEM_MASTERWORK))
			{
				if (kit->value[2] > 0)
					mod += kit->value[2];
				else
					mod += 2;
			}
			else
			{
				mod += 1;
			}
		}
	}
	
	if (roll + mod < dc && domain_apotheosis(ch, DOMAIN_STRENGTH))
	{
		roll = UMAX(roll, climb_roll(ch));
	}
	
	roll += mod;

	wiz_printf_room( ch, "Climb check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Climb check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_STRENGTH, 2);
		gain_favor(ch, DOMAIN_CAVERN, 2);
		gain_favor(ch, DOMAIN_TRAVEL, 2);
	}

	if (dc - roll >= 5)
	{
		pop_call();
		return -2;
	}
	pop_call();
	return (roll >= dc);
}

bool concentration_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	int dc2 = 0;

	push_call("concentration_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (IS_OUTSIDE(ch))
	{
		if (ch->in_room->area->weather_info->wind_speed >= 8)
		{
			if (ch->in_room->area->weather_info->sky == 2)
			{
				dc2 = 5;
			} 
			else if (ch->in_room->area->weather_info->sky == 3)
			{
				dc2 = 10;
			}
		}
	}
	if (ch->in_room->sector_type == SECT_OCEAN
	|| ch->in_room->sector_type == SECT_RIVER
	|| ch->in_room->sector_type == SECT_LAKE)
	{
		if (!IS_FLYING(ch))
		{
			if (ch->in_room->area->weather_info->wind_speed >= 8)
			{
				dc2 = 15;
			}
			else if (ch->in_room->area->weather_info->wind_speed >= 6)
			{
				dc2 = 10;
			}
		}
	}
	else if (is_mounting(ch))
	{
		if (in_combat(ch))
		{
			dc2 = 15;
		}
		else
		{
			dc2 = 10;
		}
	}
	
	if (ch->casting && learned(ch, gsn_combat_casting))
		roll += 4;
		
	if (ch->concentrating && learned(ch, gsn_skill_mastery))
		if (ch->timer_fun == do_pick || ch->timer_fun == do_disable)
			roll += 4;
	
	if (dc2 > dc)
		dc = dc2;

	wiz_printf_room( ch, "Concentration check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Concentration check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	pop_call();
	return( roll >= dc );
}

bool decipher_script_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("decipher_script_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (!learned(ch, gsn_decipher_script) && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return FALSE;
	}
	
	wiz_printf_room( ch, "Decipher Script check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Decipher Script check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_MAGIC, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool diplomacy_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("diplomacy_check(%p,%p,%p,%p)",ch,och,roll,dc);
	
	if (och == NULL)
	{
		log_printf("%s diplomacy_check: Must have an opposing char.\n\r", capitalize(get_name(ch)));
		pop_call();
		return FALSE;
	}

	if (IS_ACT(och, ACT_AGGRESSIVE))
		dc += 10;

	if (IS_EVIL(och))
		roll += (0 - reputation_bonus(ch));
	else
		roll += reputation_bonus(ch);

	if (ch->race == och->race && learned(ch, gsn_noble_birth))
		roll += 2;

	if (is_affected(och, gsn_suggestion))
	{
		roll += 20;
		affect_strip(och, gsn_suggestion);
	}
	else if (is_affected(och, gsn_charm_monster))
	{
		if (get_caster(och, gsn_charm_monster) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_person))
	{
		if (get_caster(och, gsn_charm_person) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_plant))
	{
		if (get_caster(och, gsn_charm_plant) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_animal))
	{
		if (get_caster(och, gsn_charm_animal) == ch)
			roll += 10;
	}
		
	wiz_printf_room( ch, "Diplomacy check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Diplomacy check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_COMMUNITY, 2);
		gain_favor(ch, DOMAIN_LAW, 2);
	}

	pop_call();
	return( roll >= dc );
}

int disable_device_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	OBJ_DATA *lockpick;

	push_call("disable_device_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (!learned(ch, gsn_disable_device) && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return FALSE;
	}
	
	if ((lockpick = get_obj_carry_type(ch, ITEM_TOOLS)) != NULL)
	{
		if (TOOL_TYPE(lockpick, TOOL_THIEVES_TOOLS))
		{
			if (lockpick->value[1] == 0)
			{
				act( "Your tools are worn from overuse.", ch, NULL, NULL, TO_CHAR);
				junk_obj(lockpick);
				dc += 5;
			}
			else
			{
				lockpick->value[1]--;

				if (IS_OBJ_STAT(lockpick, ITEM_MASTERWORK))
				{
					if (lockpick->value[2] > 0)
						roll += lockpick->value[2];
					else
						roll += 2;
				}
			}
		}
		else
		{
			act( "You suffer a penalty for not holding thieves tools.", ch, NULL, NULL, TO_CHAR);
			dc += 5;
		}
	}
	else
	{
		act( "You suffer a penalty for not holding thieves tools.", ch, NULL, NULL, TO_CHAR);
		dc += 5;
	}	

	wiz_printf_room( ch, "Disable Device check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Disable Device check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_TRICKERY, 2);
		gain_favor(ch, DOMAIN_ARTIFICE, 2);
	}

	pop_call();
	return( roll - dc );
}

int disguise_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("disguise_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (!IS_NPC(ch))
	{
		if (!ch->pcdata->disguise_roll)
		{
			pop_call();
			return FALSE;
		}
		else if (!roll)
		{
			roll = disguise_roll(ch);
		}
	}
	else if (roll <= 0)
	{
		if (is_polymorph(ch))
		{
			roll = disguise_roll(ch);
		}
		else
		{
			pop_call();
			return FALSE;
		}
	}
	if (och != NULL)
	{
		dc = perception_roll(och, SENSE_SIGHT);

		if (!IS_AFFECTED(och, AFF_TRUESIGHT))
		{
			roll += get_apply(ch, APPLY_DISGUISE);
		}
		if (is_affected(och, gsn_suggestion))
		{
			roll += 20;
			affect_strip(och, gsn_suggestion);
		}
	}
	
	wiz_printf_room( ch, "Disguise check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Disguise check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_TRICKERY, 2);
		gain_favor(ch, DOMAIN_ILLUSION, 2);
	}

	pop_call();
	return( roll - dc );
}

bool escape_artist_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("escape_artist_check(%p,%p,%p,%p)",ch,och,roll,dc);
	
	wiz_printf_room( ch, "Escape Artist check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Escape Artist check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_TRICKERY, 2);
		gain_favor(ch, DOMAIN_LIBERATION, 2);
	}

	pop_call();
	return( roll >= dc );
}

int first_aid_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	OBJ_DATA *kit;

	push_call("first_aid_check(%p,%p,%p,%p)",ch,och,roll,dc);
	
	if ((kit = get_obj_carry_type(ch, ITEM_TOOLS)) != NULL)
	{
		if (TOOL_TYPE(kit, TOOL_FIRSTAID_KIT))
		{
			kit->value[1]--;

			if (IS_OBJ_STAT(kit, ITEM_MASTERWORK))
			{
				if (kit->value[2] > 0)
					roll += kit->value[2];
				else
					roll += 2;
			}
			if (kit->value[1] == 0)
			{
				act( "You've used the last of your first aid kit.", ch, NULL, NULL, TO_CHAR);
				junk_obj(kit);
			}
		}
	}	

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_COMMUNITY, 2);
		gain_favor(ch, DOMAIN_HEALING, 2);
	}

	wiz_printf_room( ch, "First Aid check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "First Aid check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	pop_call();
	return( roll - dc );
}

bool streetwise_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("streetwise_check(%p,%p,%p,%p)",ch,och,roll,dc);
	
	if (och && IS_EVIL(och))
		roll += 0 - reputation_bonus(ch);
	else
		roll += reputation_bonus(ch);

	if (och && ch->race == och->race && learned(ch, gsn_noble_birth))
		roll += 2;

	wiz_printf_room( ch, "Streetwise check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Streetwise check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	pop_call();
	return( roll >= dc );
}

int haggle_check( CHAR_DATA *ch, CHAR_DATA *och )
{
	int roll = 0, dc = 0;

	push_call("haggle_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (och == NULL)
	{
		log_printf("%s haggle_check: Must have an opposing char.\n\r", capitalize(get_name(ch)));
		pop_call();
		return 0;
	}
	
	roll = haggle_roll(ch);
	dc = haggle_roll(och);
		
	if (is_affected(och, gsn_suggestion))
	{
		roll += 20;
		affect_strip(och, gsn_suggestion);
	}
	else if (is_affected(och, gsn_charm_monster))
	{
		if (get_caster(och, gsn_charm_monster) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_plant))
	{
		if (get_caster(och, gsn_charm_plant) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_person))
	{
		if (get_caster(och, gsn_charm_person) == ch)
			roll += 10;
	}
	
	wiz_printf_room( ch, "Haggle check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Haggle check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_TRADE, 2);
	}

	pop_call();
	return( dc - roll );
}

bool handle_animal_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("handle_animal_check(%p,%p,%p,$p)",ch,och,roll,dc);

	if (!learned(ch, gsn_handle_animal) && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return FALSE;
	}
	
	wiz_printf_room( ch, "Handle Animal check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Handle Animal check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_ANIMAL, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool hide_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("hide_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (!IS_AFFECTED(ch, AFF_HIDE))
	{
		pop_call();
		return FALSE;
	}
	
	if (och != NULL && dc == 0)
	{
		dc = perception_roll(och, SENSE_SIGHT);
		dc += fave_enemy_bonus(och, ch);
	}
	
	wiz_printf_room( ch, "Hide check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Hide check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_DARKNESS, 2);
		gain_favor(ch, DOMAIN_ILLUSION, 2);
		gain_favor(ch, DOMAIN_TRICKERY, 2);
	}

	pop_call();
	return( roll >= dc );
}

int intimidate_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("intimidate_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (och == NULL)
	{
		log_printf("%s intimidate_check: Must have an opposing char.\n\r", capitalize(get_name(ch)));
		pop_call();
		return FALSE;
	}

	roll += (ch->size - och->size) * 4;
	
	if (IS_UNDEAD(och))
	{
		pop_call();
		return FALSE;
	}
	if (get_curr_int(och) < 3)
	{
		if (get_curr_int(och) <= 0 || !learned(ch, gsn_wild_empathy))
		{
			pop_call();
			return FALSE;
		}
	}
	
	//intimidate treats negative REP bonus as positive - Kregor
	roll += (abs)(reputation_bonus(ch));
	
	if (ch->race == och->race && learned(ch, gsn_noble_birth))
		roll += 2;

	if (is_affected(och, gsn_suggestion))
	{
		roll += 20;
		affect_strip(och, gsn_suggestion);
	}
	else if (is_affected(och, gsn_charm_monster))
	{
		if (get_caster(och, gsn_charm_monster) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_person))
	{
		if (get_caster(och, gsn_charm_person) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_plant))
	{
		if (get_caster(och, gsn_charm_plant) == ch)
			roll += 10;
	}
	else if (is_affected(och, gsn_charm_animal))
	{
		if (get_caster(och, gsn_charm_animal) == ch)
			roll += 10;
	}
	
	dc = stat_bonus(TRUE, och, APPLY_WIS) + get_will_save(och) + 10;
	
	wiz_printf_room( ch, "Intimidate check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Intimidate check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_LAW, 2);
		gain_favor(ch, DOMAIN_WAR, 2);
		gain_favor(ch, DOMAIN_WRATH, 2);
	}

	pop_call();
	return( roll - dc );
}

int jump_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("jump_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (roll < dc && domain_apotheosis(ch, DOMAIN_STRENGTH))
	{
		roll = UMAX(roll, climb_roll(ch));
	}

	wiz_printf_room( ch, "Jump check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Jump check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_STRENGTH, 2);
		gain_favor(ch, DOMAIN_TRAVEL, 2);
	}

	pop_call();
	return( roll - dc );
}

bool mount_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("mount_check(%p,%p,%p,%p)",ch,och,roll,dc);

	wiz_printf_room( ch, "Mount check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Mount check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	pop_call();
	return( roll >= dc );
}

bool pick_lock_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	OBJ_DATA *lockpick;

	push_call("pick_lock_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (!learned(ch, gsn_pick_lock) && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return FALSE;
	}
	
	if ((lockpick = get_obj_carry_type(ch, ITEM_TOOLS)) != NULL)
	{
		if (TOOL_TYPE(lockpick, TOOL_THIEVES_TOOLS))
		{
			if (lockpick->value[1] == 0)
			{
				act( "Your tools are worn from overuse.", ch, NULL, NULL, TO_CHAR);
				junk_obj(lockpick);
				dc += 5;
			}
			else
			{
				lockpick->value[1]--;

				if (IS_OBJ_STAT(lockpick, ITEM_MASTERWORK))
				{
					if (lockpick->value[2] > 0)
						roll += lockpick->value[2];
					else
						roll += 2;
				}
			}
		}
		else
		{
			act( "You suffer a penalty for not holding thieves tools.", ch, NULL, NULL, TO_CHAR);
			dc += 5;
		}
	}
	else
	{
		act( "You suffer a penalty for not holding thieves tools.", ch, NULL, NULL, TO_CHAR);
		dc += 5;
	}	

	wiz_printf_room( ch, "Open Lock check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Open Lock check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_ARTIFICE, 2);
		gain_favor(ch, DOMAIN_TRICKERY, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool perception_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("perception_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (roll < 0)
	{
		pop_call();
		return FALSE;
	}
	if (och != NULL)
	{
		roll += fave_enemy_bonus(ch,och);
	}
	
	wiz_printf_room( ch, "Perception check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Perception check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 1);
	}

	pop_call();
	return( roll >= dc );
}

bool search_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("search_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (ch->in_room->sector_type == SECT_UNDER_GROUND
	||  ch->in_room->sector_type == SECT_DEEP_EARTH)
	{
		roll += synergy_bonus(ch, gsn_know_dungeoneering);
	}

	wiz_printf_room( ch, "Search check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Search check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 1);
	}

	pop_call();
	return( roll >= dc );
}

bool sense_motive_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("sense_motive_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (och != NULL)
	{
		roll += fave_enemy_bonus(ch,och);
		dc += fave_enemy_bonus(och,ch);
	}
	
	wiz_printf_room( ch, "Sense Motive check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Sense Motive check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 1);
	}

	pop_call();
	return( roll >= dc );
}

bool sleight_of_hand_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("sleight_of_hand_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (!learned(ch, gsn_sleight_of_hand) && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return FALSE;
	}
	if (och != NULL && dc <= 0)
	{
		dc = perception_roll(och, SENSE_SIGHT);
		dc += fave_enemy_bonus(och, ch);
	}
	
	wiz_printf_room( ch, "Sleight of Hand check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Sleight of Hand check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_CHAOS, 2);
		gain_favor(ch, DOMAIN_TRICKERY, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool sneak_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("sneak_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (och != NULL && dc <= 0)
	{
		dc = perception_roll(och, SENSE_SOUND);
		dc += fave_enemy_bonus(och, ch);
	}
	
	wiz_printf_room( ch, "Sneak check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Sneak check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	pop_call();
	return( roll >= dc );
}

bool spellcraft_check( CHAR_DATA *ch, CHAR_DATA *och, int sn, int roll, int dc )
{
	push_call("spellcraft_check(%p,%p,%p,%p,%p)",ch,och,sn,roll,dc);

	if (!learned(ch, gsn_spellcraft) && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return FALSE;
	}
	
	if (sn > -1)
	{
		if (school_spell(ch, sn))
			roll += 2;
		else if (opposing_school(ch, sn))
			roll -= 5;
	}
	
	if (och && learned(och, gsn_furtive_spell) && !learned(ch, gsn_shadow_casting))
	{
		dc += 4;
	}
	
	wiz_printf_room( ch, "Spellcraft check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Spellcraft check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_MAGIC, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool survival_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("survival_check(%p,%p,%p,%p)",ch,och,roll,dc);

	if (och != NULL)
	{
		roll += fave_enemy_bonus(ch,och);
	}
	
	if (ch->in_room->sector_type == SECT_UNDER_GROUND
	||  ch->in_room->sector_type == SECT_DEEP_EARTH)
	{
		roll += synergy_bonus(ch, gsn_know_dungeoneering);
	}

	if (ch->in_room->sector_type == SECT_FIELD
	||  ch->in_room->sector_type == SECT_FOREST
	||  ch->in_room->sector_type == SECT_HILLS
	||  ch->in_room->sector_type == SECT_MOUNTAIN
	||  ch->in_room->sector_type == SECT_LAKE
	||  ch->in_room->sector_type == SECT_RIVER
	||  ch->in_room->sector_type == SECT_OCEAN
	||  ch->in_room->sector_type == SECT_DESERT
	||  ch->in_room->sector_type == SECT_SWAMP
	||  ch->in_room->sector_type == SECT_BEACH
	||  ch->in_room->sector_type == SECT_TUNDRA)
	{
		roll += synergy_bonus(ch, gsn_know_nature);
	}

	wiz_printf_room( ch, "Survival check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Survival check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_ANIMAL, 2);
		gain_favor(ch, DOMAIN_CAVERN, 2);
		gain_favor(ch, DOMAIN_PLANT, 2);
		gain_favor(ch, DOMAIN_TRAVEL, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool swim_check(CHAR_DATA *ch, int dc)
{
	int roll, swim_dc, stamina;
	
	push_call("swim_check(%p)",ch);

	//immortals cannot drown
	if (IS_IMMORTAL(ch))
	{
		pop_call();
		return TRUE;
	}
	
	switch (ch->in_room->sector_type)
	{
		case SECT_LAKE:
			swim_dc = 10;
			break;
		
		case SECT_OCEAN:
		case SECT_UNDER_WATER:
			swim_dc = 15;
			break;
			
		default:
			pop_call();
			return TRUE;
	}

	//adjust speed for non-aquatic races to half
	if (!CAN_SWIM(ch))
		ch->speed = 0;

	swim_dc += dc;
	
	//stormy water adds to dc
	switch (ch->in_room->area->weather_info->sky)
	{
		case 0:
		case 1:
			swim_dc += 0;
			break;
		case 2:
			swim_dc += 3;
			break;
		case 3:
			swim_dc += 5;
			break;
	}
	
	if (in_combat(ch))
	{
		swim_dc += 2;
	}
		
	roll = swim_roll(ch);
	
	stamina = get_max_move(ch) / (ch->perm_con * 2);
	
	wiz_printf_room( ch, "Swim check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, swim_dc, roll >= swim_dc ? "SUCCESS" : "FAILURE");

	/* if he's out, he's going down. */
	if (!IS_AWAKE(ch))
	{
		gain_condition(ch, COND_AIR, -1);
		TAKE_ACTION(ch, ACTION_STANDARD);
		pop_call();
		return FALSE;
	}
	/* fails the roll by 5 or more, or is exhausted, he goes under */
	else if ((ch->move == 0 || roll - swim_dc <= -5) && !CAN_BREATH_WATER(ch) && must_breathe(ch))
	{
		act( "{048}You fail to keep yourself above water, and choke and tire!{300}", ch, NULL, NULL, TO_CHAR);
		act( "{048}$n fails to swim, and gulps some water!{300}", ch, NULL, NULL, TO_ROOM);
		ch->move = UMAX(0, ch->move - stamina);
		gain_condition(ch, COND_AIR, -1);
		TAKE_ACTION(ch, ACTION_STANDARD);
		pop_call();
		return FALSE;
	}
	/* Makes the swim roll, let him take a breath with each success */
	if (ch->pcdata->condition[COND_AIR] < max_air(ch))
	{
		gain_condition(ch, COND_AIR, 1);
	}
	/* fails the roll by 4 or less, treads the water */
	if (roll - swim_dc < 0)
	{
		act( "{048}You try to swim, but don't make much progress.{300}", ch, NULL, NULL, TO_CHAR);
		act( "{048}$n tries to swim, but doesn't make much progress.{300}", ch, NULL, NULL, TO_ROOM);
		TAKE_ACTION(ch, ACTION_MOVE);
		pop_call();
		return FALSE;
	}
	pop_call();
	return (roll >= swim_dc);
}	
	
bool tumble_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("tumble_check(%p,%p,%p,$p)",ch,och,roll,dc);

	if (!learned(ch, gsn_tumble) && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return FALSE;
	}

	else if (encumberance(ch) >= VERY_ENCUMBERED)
	{
		send_to_char("You cannot perform tumbling acts with so much weight!", ch);
		pop_call();
		return FALSE;
	}

	if (IS_ENCUMBERED(ch))
		roll -= 6;

	if (IS_SET(ch->in_room->room_flags, ROOM_ICE) && !IS_AFFECTED(ch, AFF_WATER_WALK))
	{
		dc += 5;
	}
	else if (IS_OUTSIDE(ch) && ch->in_room->area->weather_info->sky == 3)
	{
		dc += 5;
	}
	else if (IS_OUTSIDE(ch) && ch->in_room->area->weather_info->sky == 2)
	{
		dc += 2;
	}

	if (ch->in_room)
	{
		if (ch->in_room->sector_type == SECT_HILLS
		||  ch->in_room->sector_type == SECT_SWAMP
		||  ch->in_room->sector_type == SECT_BEACH)
		{
			dc += 2;
		}
		if (ch->in_room->sector_type == SECT_FOREST
		||  ch->in_room->sector_type == SECT_MOUNTAIN
		||  ch->in_room->sector_type == SECT_UNDER_GROUND
		||  ch->in_room->sector_type == SECT_DEEP_EARTH
		||  ch->in_room->sector_type == SECT_TUNDRA)
		{
			dc += 5;
		}
	}
	
	wiz_printf_room( ch, "Tumble check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Tumble check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	pop_call();
	return( roll >= dc );
}

bool use_magic_check( CHAR_DATA *ch, CHAR_DATA *och, int roll, int dc )
{
	push_call("use_magic_check(%p,%p,%p.%p)",ch,och,roll,dc);

	if (!learned(ch, gsn_use_magic) && !learned(ch, gsn_jack_of_all_trades))
	{
		pop_call();
		return FALSE;
	}
	
	wiz_printf_room( ch, "Use Magic Device check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");
	if (och && och->in_room != ch->in_room)
		wiz_printf_room( och, "Use Magic Device check (%s): diceroll: %d, DC: %d - %s\n\r", get_name(ch), roll, dc, roll >= dc ? "SUCCESS" : "FAILURE");

	if (roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_MAGIC, 2);
	}

	pop_call();
	return( roll >= dc );
}

int craft_alchemy_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_alchemy);
	
	roll += get_apply(ch, APPLY_CRAFT_ALCHEMY);
	
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_armor_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_armor);
	
	roll += get_apply(ch, APPLY_CRAFT_ARMOR);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_bow_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_bows);
	
	roll += get_apply(ch, APPLY_CRAFT_BOWS);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_cooking_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_cooking);
	
	roll += get_apply(ch, APPLY_CRAFT_COOKING);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_fletch_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_fletching);
	
	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_jewelry_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_jewelry);
	
	roll += get_apply(ch, APPLY_CRAFT_JEWELRY);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_leather_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_leather);
	
	roll += get_apply(ch, APPLY_CRAFT_LEATHER);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_mining_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_mining);
	
	roll += get_apply(ch, APPLY_CRAFT_MINING);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_poison_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_poison);
	
	roll += synergy_bonus(ch, gsn_craft_alchemy);
	
	roll += get_apply(ch, APPLY_CRAFT_POISON);

	if (learned(ch, gsn_poison_use))
		roll += 4;

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_tailor_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_tailoring);
	
	roll += get_apply(ch, APPLY_CRAFT_TAILOR);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_trap_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_traps);
	
	roll += get_apply(ch, APPLY_CRAFT_TRAPS);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

int craft_weapon_roll( CHAR_DATA *ch )
{
	int roll;

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

	roll = dice(1,20);
	roll += stat_mods(ch, APPLY_INT);
	if (domain_skill(ch, gsn_divine_craftsmanship))
		roll += UMIN(class_level(ch, CLASS_CLERIC), stat_bonus(TRUE, ch, APPLY_WIS));
	roll += learned(ch, gsn_craft_weapons);
	
	roll += get_apply(ch, APPLY_CRAFT_WEAPONS);

	// strip one-shot enhancements
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	pop_call();
	return( roll );
}

bool know_arcana_check( CHAR_DATA *ch, int dc )
{
	int roll, ranks;

	push_call("know_arcana_roll(%p%p)",ch,dc);

	if ((ranks = learned(ch, gsn_know_arcana)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		if (dc > 10 && !learned(ch, gsn_lore))
		{
			pop_call();
			return FALSE;
		}
	}
	if (learned(ch, gsn_scholar) && ranks)
		roll = take_twenty(ch);
	else if (learned(ch, gsn_lore_mastery))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += ranks + stat_mods(ch, APPLY_INT);
	roll += multi_class_level(ch, gsn_lore) / 2;
	
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	if (dc > 10 && roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_MAGIC, 2);
	}

	pop_call();
	return( roll );
}

bool know_dungeoneering_check( CHAR_DATA *ch, int dc )
{
	int roll, ranks;

	push_call("know_arcana_roll(%p%p)",ch,dc);

	if ((ranks = learned(ch, gsn_know_dungeoneering)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		if (dc > 10 && !learned(ch, gsn_lore))
		{
			pop_call();
			return FALSE;
		}
	}
	if (learned(ch, gsn_scholar) && ranks)
		roll = take_twenty(ch);
	else if (learned(ch, gsn_lore_mastery))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += ranks + stat_mods(ch, APPLY_INT);
	roll += multi_class_level(ch, gsn_lore) / 2;
	
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	if (dc > 10 && roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_CAVERN, 2);
		gain_favor(ch, DOMAIN_TRAVEL, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool know_geography_check( CHAR_DATA *ch, int dc )
{
	int roll, ranks;

	push_call("know_geography_roll(%p%p)",ch,dc);

	if ((ranks = learned(ch, gsn_know_geography)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		if (dc > 10 && !learned(ch, gsn_lore))
		{
			pop_call();
			return FALSE;
		}
	}
	if (learned(ch, gsn_scholar) && ranks)
		roll = take_twenty(ch);
	else if (learned(ch, gsn_lore_mastery))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += ranks + stat_mods(ch, APPLY_INT);
	roll += multi_class_level(ch, gsn_lore) / 2;
	
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	if (dc > 10 && roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_TRAVEL, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool know_history_check( CHAR_DATA *ch, int dc )
{
	int roll, ranks;

	push_call("know_history_roll(%p%p)",ch,dc);

	if ((ranks = learned(ch, gsn_know_history)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		if (dc > 10 && !learned(ch, gsn_lore))
		{
			pop_call();
			return FALSE;
		}
	}
	if (learned(ch, gsn_scholar) && ranks)
		roll = take_twenty(ch);
	else if (learned(ch, gsn_lore_mastery))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += ranks + stat_mods(ch, APPLY_INT);
	roll += multi_class_level(ch, gsn_lore) / 2;
	
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	if (dc > 10 && roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_PLANNING, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool know_local_check( CHAR_DATA *ch, int dc )
{
	int roll, ranks;

	push_call("know_local_roll(%p%p)",ch,dc);

	if ((ranks = learned(ch, gsn_know_local)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		if (dc > 10 && !learned(ch, gsn_lore))
		{
			pop_call();
			return FALSE;
		}
	}
	if (learned(ch, gsn_scholar) && ranks)
		roll = take_twenty(ch);
	else if (learned(ch, gsn_lore_mastery))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += ranks + stat_mods(ch, APPLY_INT);
	roll += multi_class_level(ch, gsn_lore) / 2;
	
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	if (dc > 10 && roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool know_nature_check( CHAR_DATA *ch, int dc )
{
	int roll, ranks;

	push_call("know_nature_roll(%p%p)",ch,dc);

	if ((ranks = learned(ch, gsn_know_nature)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		if (dc > 10 && !learned(ch, gsn_lore))
		{
			pop_call();
			return FALSE;
		}
	}
	if (learned(ch, gsn_scholar) && ranks)
		roll = take_twenty(ch);
	else if (learned(ch, gsn_lore_mastery))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += ranks + stat_mods(ch, APPLY_INT);
	roll += multi_class_level(ch, gsn_lore) / 2;
	
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	if (dc > 10 && roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_ANIMAL, 2);
		gain_favor(ch, DOMAIN_PLANT, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool know_nobility_check( CHAR_DATA *ch, int dc )
{
	int roll, ranks;

	push_call("know_nobility_roll(%p%p)",ch,dc);

	if ((ranks = learned(ch, gsn_know_nobility)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		if (dc > 10 && !learned(ch, gsn_lore))
		{
			pop_call();
			return FALSE;
		}
	}
	if (learned(ch, gsn_scholar) && ranks)
		roll = take_twenty(ch);
	else if (learned(ch, gsn_lore_mastery))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += ranks + stat_mods(ch, APPLY_INT);
	roll += multi_class_level(ch, gsn_lore) / 2;
	
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	if (dc > 10 && roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_LAW, 2);
		gain_favor(ch, DOMAIN_NOBILITY, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool know_religion_check( CHAR_DATA *ch, int dc )
{
	int roll, ranks;

	push_call("know_religion_roll(%p%p)",ch,dc);

	if ((ranks = learned(ch, gsn_know_religion)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		if (dc > 10 && !learned(ch, gsn_lore))
		{
			pop_call();
			return FALSE;
		}
	}
	if (learned(ch, gsn_scholar) && ranks)
		roll = take_twenty(ch);
	else if (learned(ch, gsn_lore_mastery))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	roll += ranks + stat_mods(ch, APPLY_INT);
	roll += multi_class_level(ch, gsn_lore) / 2;
	
	if (dc > 10 && roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
	}

	pop_call();
	return( roll >= dc );
}

bool know_planes_check( CHAR_DATA *ch, int dc )
{
	int roll, ranks;

	push_call("know_planes_roll(%p%p)",ch,dc);

	if ((ranks = learned(ch, gsn_know_planes)) <= 0 && !learned(ch, gsn_jack_of_all_trades))
	{
		if (dc > 10 && !learned(ch, gsn_lore))
		{
			pop_call();
			return FALSE;
		}
	}
	if (learned(ch, gsn_scholar) && ranks)
		roll = take_twenty(ch);
	else if (learned(ch, gsn_lore_mastery))
		roll = take_ten(ch);
	else
		roll = dice(1,20);

	roll += ranks + stat_mods(ch, APPLY_INT);
	roll += multi_class_level(ch, gsn_lore) / 2;
	
	if (is_affected(ch, gsn_guidance))
		affect_strip(ch, gsn_guidance);
	if (is_affected(ch, gsn_moment_of_prescience))
		affect_strip(ch, gsn_moment_of_prescience);

	if (dc > 10 && roll >= dc)
	{
		gain_favor(ch, DOMAIN_KNOWLEDGE, 2);
		gain_favor(ch, DOMAIN_TRAVEL, 2);
	}

	pop_call();
	return( roll >= dc );
}

/*
 * Count the total levels of controlled creatures - Kregor
 */
int count_minions( CHAR_DATA *ch)
{
	PET_DATA *pet;
	int cnt = 0;

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

	for (pet = mud->f_pet ; pet ; pet = pet->next)
	{
		if (pet->ch->master == ch)
		{
			if (IS_ACT(pet->ch, ACT_PET))
				continue;
			if (IS_AFFECTED(pet->ch, AFF_DOMINATE))
				cnt++;
		}
	}
	pop_call();
	return( cnt );
}

/*
 * Turn undead for paladin/cleric - Kregor 2/16/07
 * Added domain support for elemental and plant types - Kregor 11/29/07
 * Revised to PFRPG's channel energy mechanic - Kregor 2/10/10
 * Added construct and lycan types for domains - Kregor 11/5/10
 */
DO_ABILITY(ability_turn_undead)
{
	CHAR_DATA *vch, *vch_next;
	int turn_dc, turn_dice, turn_dmg, count;
	bool fUndead 		= FALSE;
	bool fElemental = FALSE;
	bool fPlant 		= FALSE;
	bool fOutsider 	= FALSE;
	bool fReptile 	= FALSE;
	bool fLycan 		= FALSE;
	bool fTurned 		= FALSE;
	bool fCommand 	= FALSE;

	push_call("ability_turn_undead(%p,%p,%p,%p)",sn,level,ch,vo);

	if (sn == gsn_turn_undead || sn == gsn_command_undead)
	{
		fUndead = TRUE;
	}
	if (sn == gsn_command_undead)
	{
		fUndead = TRUE;
		fCommand = TRUE;
	}
	if (sn == gsn_turn_elemental)
	{
		fElemental = TRUE;
		fCommand = TRUE;
	}
	if (sn == gsn_turn_plants)
	{
		fPlant = TRUE;
		fCommand = TRUE;
	}
	if (sn == gsn_turn_outsider)
	{
		fPlant = TRUE;
	}
	if (sn == gsn_turn_reptiles)
	{
		fReptile = TRUE;
		fCommand = TRUE;
	}
	if (sn == gsn_turn_lycanthrope)
	{
		fLycan = TRUE;
	}

	turn_dice = ROUNDUP(level / 2);
	turn_dc = dice(1,20) + stat_bonus(TRUE, ch, APPLY_CHA) + turn_dice;
	turn_dc += synergy_bonus(ch, gsn_know_religion);
	if (learned(ch, gsn_imp_turning))
		turn_dc += 2;
		
	if (learned(ch, gsn_empower_turning))
	{
		if (fCommand)
			turn_dc += level/4 + 1;
		else
			turn_dice += level/4 + 1;
	}

	act( "{138}You brandish your holy symbol and chant...", ch, NULL, NULL, TO_CHAR );
	act( "{138}$n brandishes $s holy symbol and chants...", ch, NULL, NULL, TO_ROOM );
	
	for (count = 0, vch = ch->in_room->first_person ; vch ; vch = vch_next)
	{
		vch_next = vch->next_in_room;
		
		if (is_same_group(vch, ch))
			continue;
		if (fElemental && (!rspec_req(vch, RSPEC_ELEMENTAL) || race_type(vch) != RTYPE_OUTSIDER))
			continue;
		if (fOutsider && race_type(vch) != RTYPE_OUTSIDER)
			continue;

		fTurned = FALSE;

		if (fUndead && IS_UNDEAD(vch))
			fTurned = TRUE;

		if (fPlant && race_type(vch) == RTYPE_PLANT)
			fTurned = TRUE;

		if (fReptile && race_type(vch) == RTYPE_ANIMAL && rspec_req(vch, RSPEC_REPTILIAN))
			fTurned = TRUE;
			
		if (fLycan)
		{
			if (rspec_req(vch, RSPEC_SHAPECHANGER))
				fTurned = TRUE;
			if ((IS_GOOD(ch) && IS_EVIL(vch)) || (IS_EVIL(ch) && IS_GOOD(vch)))
				fCommand = FALSE;
			else
				fCommand = TRUE;
		}

		if (fElemental)
		{
			if ((has_domain(ch, DOMAIN_AIR) && rspec_req(vch, RSPEC_AIR))
			|| (has_domain(ch, DOMAIN_EARTH) && rspec_req(vch, RSPEC_EARTH))
			|| (has_domain(ch, DOMAIN_FIRE) && rspec_req(vch, RSPEC_FIRE))
			|| (has_domain(ch, DOMAIN_WATER) && rspec_req(vch, RSPEC_WATER)))
				fTurned = TRUE;
		}
		if (fOutsider)
		{
			if ((has_domain(ch, DOMAIN_GOOD) && rspec_req(vch, RSPEC_EVIL))
			|| (has_domain(ch, DOMAIN_EVIL) && rspec_req(vch, RSPEC_GOOD))
			|| (has_domain(ch, DOMAIN_CHAOS) && rspec_req(vch, RSPEC_LAWFUL))
			|| (has_domain(ch, DOMAIN_LAW) && rspec_req(vch, RSPEC_CHAOTIC)))
				fTurned = TRUE;
		}
		
		if (!fTurned)
			continue;

		if (fCommand)
		{
			if (count_minions(ch) + vch->level > level)
			{
				act("{118}$N is too strong for you to command!", ch, NULL, vch, TO_CHAR);
				continue;
			}

			if (will_save(vch, ch, turn_dc - get_apply(vch, APPLY_TURN_RESIST), -1))
			{
				act("{118}Your attempt to command $N has no effect!", ch, NULL, vch, TO_CHAR);
				act("{118}You resist $n's attempt to command you!", ch, NULL, vch, TO_VICT);
				continue;
			}
			
			AFFECT_DATA af;
	
			af.type      = sn;
			af.location  = APPLY_NONE;
			af.modifier  = 0;
			af.duration  = turn * turn_dice;
			af.bittype   = AFFECT_TO_CHAR;
			af.bitvector = AFF_DOMINATE;
			af.level     = level;
			affect_join( ch, vch, &af );
			add_follower(vch, ch);
			
			act("{108}$N turns to regard you as master.", ch, NULL, vch, TO_CHAR);
			act("{108}You turn to regard $n as your master.", ch, NULL, vch, TO_VICT);
			act("{108}$N turns to regard $n as $S master.", ch, NULL, vch, TO_VICT);
			continue;
		}

		turn_dmg = dice(turn_dice, 6);

		if (will_save(vch, ch, turn_dc - get_apply(vch, APPLY_TURN_RESIST), -1))
		{
			damage(ch, vch, turn_dmg/2, sn, NULL);
		}
		else
		{
			damage(ch, vch, turn_dmg, sn, NULL);
		}
		
		if (!valid_fight(ch, vch))
			continue;
		
		AFFECT_DATA af;

		af.type      = sn;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.duration  = turn_dice;
		af.bittype   = AFFECT_TO_CHAR;
		af.bitvector = AFF2_PARALYSIS;
		af.level     = level;
		affect_join( ch, vch, &af );

		count += vch->level;
	}
	if (count == 0)
		send_to_char_color( "Your attempt to turn has no effect.\n\r", ch );
	pop_call();
	return TRUE;
}


/*
 * Lay on hands for paladins - Kregor 12/26/07
 */
DO_ABILITY(ability_lay_hands)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA *paf, *paf_next;
	int numdice, heal, paf_type, caster_check;
	bool dam = FALSE;

	push_call("ability_lay_hands(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( stat_bonus(TRUE, ch, APPLY_CHA) < 1 )
	{
		send_to_char( "You lack the command of presence to do that.\n\r", ch );
		pop_call();
		return FALSE;
	}

	numdice = level / 2;
	heal = dice(numdice, 6);
	caster_check = dice(1,20) + level + stat_bonus(TRUE, ch, APPLY_CHA);

	if (!IS_UNDEAD(victim))
	{
		if (!strcasecmp(target_name, "fatigue"))
		{
			if (!learned(ch, gsn_layhands_fatigue))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			heal *= 2;
			victim->move = UMIN( victim->hit + heal, get_max_move(victim));
		}
		else if (!strcasecmp(target_name, "disease"))
		{
			if (!learned(ch, gsn_layhands_disease))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (victim->first_disease != NULL)
			{
				DISEASE_DATA *dis, *dis_next;
		
				for (dis = victim->first_disease ; dis ; dis = dis_next)
				{
					dis_next = dis->next;
		
					if ((dis->dc && caster_check >= dis->dc) || (!dis->dc && caster_check >= disease_table[dis->type].dc))
						disease_from_char(victim, dis);
				}
			}
			else
			{
				act("$N is not diseased.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
		}
		else if (!strcasecmp(target_name, "poison"))
		{
			if (!learned(ch, gsn_layhands_poison))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (victim->poison)
			{
				POISON_DATA *pd, *pd_next;
				
				if (IS_AFFECTED(victim, AFF_POISON) && caster_check >= 15)
					AFFECT_STRIP(victim, AFF_POISON);
		
				for (pd = victim->poison ; pd ; pd = pd_next)
				{
					pd_next = pd->next;
					
					if (caster_check >= (pd->dc ? pd->dc : poison_table[pd->type].dc))
					{
						victim->poison = victim->poison->next;
						FREEMEM( pd );
					}
				}
			}
			else
			{
				act("$N is not poisoned.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
		}
		else if (!strcasecmp(target_name, "blindness"))
		{
			if (!learned(ch, gsn_layhands_blindness))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (IS_BLIND(victim))
			{	
				AFFECT_STRIP(victim, AFF_BLIND);
			}
			else
			{
				act("$N can see perfectly well.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
		}
		else if (!strcasecmp(target_name, "curse"))
		{
			if (!learned(ch, gsn_layhands_curse))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (!spell_remove_curse(gsn_remove_curse, level, ch, vo, TAR_CHAR_DEFENSIVE))
			{
				pop_call();
				return FALSE;
			}
		}
		else if (!strcasecmp(target_name, "fear"))
		{
			if (!learned(ch, gsn_layhands_fear))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			for ( paf_type = 0, paf = victim->first_affect; paf != NULL; paf = paf_next )
			{
				paf_next = paf->next;
		
				if (!IS_SET(paf->bitvector, AFF2_FEAR))
					continue;
					
				paf_type = paf->type;
	
				if (caster_check < 11 + paf->level)
					continue;
					
				if (paf->duration >= 0)
				{
					if (skill_table[paf->type].msg_off)
					{
						act( skill_table[paf->type].msg_off, victim, NULL, NULL, TO_CHAR);
					}
				}
				affect_from_char(victim, paf);
				victim->fear_level = 0;
			}
		
			if (paf_type == 0)
			{
				act("$N does not seem to be frightened.", ch, NULL, victim, TO_CHAR);
				pop_call();
				return FALSE;
			}
		}
		else
		{
			if (victim->hit >= get_max_hit(victim))
			{
				act("$N does not need healing.", ch, NULL, victim, TO_CHAR);
				pop_call();
				return FALSE;
			}
			victim->hit = UMIN( victim->hit + heal, get_max_hit(victim));
			victim->nonlethal = UMAX(0, victim->nonlethal - heal);
		}
	}
	else
	{
		dam = TRUE;
	}
	if (ch != victim)
	{
		act( "{138}You lay your hands on $N and channel healing energy.", ch, NULL, victim, TO_CHAR );
		act( "{138}$n lays hands upon you, channeling healing energy.", ch, NULL, victim, TO_VICT );
		act( "{138}$n lays hands upon $N, channeling healing energy.", ch, NULL, victim, TO_NOTVICT );
	}
	else
	{
		act( "{138}You lay hands upon yourself, channeling healing energy.", ch, NULL, victim, TO_CHAR );
		act( "{138}$n lays hands upon $mself, channeling healing energy.", ch, NULL, victim, TO_ROOM );
	}
	
	if (dam)
	{
		spell_damage(ch, victim, heal, sn, level);
	}
	update_pos(victim,-1);

	pop_call();
	return TRUE;
}

/*
 * Another divine blessing or five - Kregor
 */
DO_ABILITY(ability_touch_of_courage)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	char col[10];
	
	push_call("ability_touch_of_courage(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if ((IS_GOOD(ch) && !IS_GOOD(victim))
	|| (IS_EVIL(ch) && !IS_EVIL(victim)))
	{
		act("You can only share your aura with someone of your alignment.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if (IS_GOOD(ch))
		strcpy(col, "{138}");
	else
		strcpy(col, "{108}");
	
	act("$t$n channels divine energy into $N.", ch, col, victim, TO_NOTVICT);
	act("$tYou channel your divine courage into $N.", ch, col, victim, TO_CHAR);
	act("$t$n channels $s divine courage into you.", ch, col, victim, TO_VICT);

	af.type      = sn;
	af.location  = APPLY_IMM_FEAR;
	af.modifier  = 1;
	af.duration  = 10 * level;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}


DO_ABILITY(ability_touch_of_grace)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	char col[10];
	
	push_call("ability_touch_of_grace(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if ((IS_GOOD(ch) && !IS_GOOD(victim))
	|| (IS_EVIL(ch) && !IS_EVIL(victim)))
	{
		act("You can only share your aura with someone of your alignment.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if (IS_GOOD(ch))
		strcpy(col, "{138}");
	else
		strcpy(col, "{108}");
	
	act("$t$n channels divine energy into $N.", ch, col, victim, TO_NOTVICT);
	act("$tYou channel your divine grace into $N.", ch, col, victim, TO_CHAR);
	act("$t$n channels $s divine grace into you.", ch, col, victim, TO_VICT);

	af.type      = sn;
	af.location  = APPLY_SAVES;
	af.modifier  = stat_bonus(TRUE, ch, APPLY_CHA);
	af.duration  = 10 * level;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}


DO_ABILITY(ability_touch_of_resolve)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	char col[10];
	
	push_call("ability_touch_of_resolve(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if ((IS_GOOD(ch) && !IS_GOOD(victim))
	|| (IS_EVIL(ch) && !IS_EVIL(victim)))
	{
		act("You can only share your aura with someone of your alignment.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if (IS_GOOD(ch))
		strcpy(col, "{138}");
	else
		strcpy(col, "{108}");
	
	act("$t$n channels divine energy into $N.", ch, col, victim, TO_NOTVICT);
	act("$tYou channel your divine resolve into $N.", ch, col, victim, TO_CHAR);
	act("$t$n channels $s divine resolve into you.", ch, col, victim, TO_VICT);

	af.type      = sn;
	af.location  = APPLY_IMM_CHARM;
	af.modifier  = 1;
	af.duration  = 10 * level;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}


DO_ABILITY(ability_touch_of_zeal)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	char col[10];
	
	push_call("ability_touch_of_zeal(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if ((IS_GOOD(ch) && !IS_GOOD(victim))
	|| (IS_EVIL(ch) && !IS_EVIL(victim)))
	{
		act("You can only share your aura with someone of your alignment.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if (IS_GOOD(ch))
		strcpy(col, "{138}");
	else
		strcpy(col, "{108}");
	
	act("$t$n channels divine energy into $N.", ch, col, victim, TO_NOTVICT);
	act("$tYou channel your divine zeal into $N.", ch, col, victim, TO_CHAR);
	act("$t$n channels $s divine zeal into you.", ch, col, victim, TO_VICT);

	af.type      = sn;
	af.location  = APPLY_IMM_COMPULSION;
	af.modifier  = 1;
	af.duration  = 10 * level;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}


DO_ABILITY(ability_touch_of_righteousness)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	push_call("ability_touch_of_righteousness(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if (!IS_GOOD(victim))
	{
		act("You can only share your aura with someone of your alignment.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	act("{138}$n channels divine energy into $N.", ch, NULL, victim, TO_NOTVICT);
	act("{138}You channel your divine righteousness into $N.", ch, NULL, victim, TO_CHAR);
	act("{138}$n channels $s divine righteousness into you.", ch, NULL, victim, TO_VICT);

	af.type      = sn;
	af.location  = APPLY_IMM_EVIL;
	af.modifier  = 1;
	af.duration  = 10 * level;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}


DO_ABILITY(ability_touch_of_profanity)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	push_call("ability_touch_of_profanity(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if (!IS_EVIL(victim))
	{
		act("You can only share your aura with someone of your alignment.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	act("{108}$n channels divine energy into $N.", ch, NULL, victim, TO_NOTVICT);
	act("{108}You channel your divine profanity into $N.", ch, NULL, victim, TO_CHAR);
	act("{108}$n channels $s divine profanity into you.", ch, NULL, victim, TO_VICT);

	af.type      = sn;
	af.location  = APPLY_IMM_GOOD;
	af.modifier  = 1;
	af.duration  = 10 * level;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}


/*
 * Paladin/Blackguard smite
 */
DO_ABILITY(ability_smite)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	push_call("ability_smite(%p,%p,%p,%p)",sn,level,ch,vo);

	act("{138}You call on the favor of your deity against $N.", ch, NULL, victim, TO_CHAR);
	act("{138}$n calls on the favor of $s deity against $N.", ch, NULL, victim, TO_NOTVICT);
	act("{138}$n calls on the favor of $s deity against you.", ch, NULL, victim, TO_VICT);

	if (sn == gsn_smite)
	{
		if ((IS_GOOD(ch) && !IS_EVIL(victim))
		|| (IS_EVIL(ch) && !IS_GOOD(victim)))
		{
			send_to_char("The gods do not answer your call.", ch);
			pop_call();
			return FALSE;
		}
	}
	if (sn == gsn_smite_infidel)
	{
		if (!faith_enemies(ch, victim))
		{
			act("$N is not of an opposing faith.", ch, NULL, victim, TO_CHAR);
			pop_call();
			return FALSE;
		}
	}

	af.type      = sn;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.duration  = -1;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}

/*
 * Corrupt Touch for Blackguards - Kregor 11/27/10
 */
DO_ABILITY(ability_corrupt_touch)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int numdice, heal, caster_check;
	bool dam = FALSE;

	push_call("ability_corrupt_touch(%p,%p,%p,%p)",sn,level,ch,vo);

	if ( stat_bonus(TRUE, ch, APPLY_CHA) < 1 )
	{
		send_to_char( "You lack the command of presence to do that.\n\r", ch );
		pop_call();
		return FALSE;
	}

	numdice = level / 2;
	heal = dice(numdice, 6);
	caster_check = dice(1,20) + level + stat_bonus(TRUE, ch, APPLY_CHA);

	if (!IS_UNDEAD(victim))
	{
		if (!strcasecmp(target_name, "fatigue"))
		{
			if (!learned(ch, gsn_layhands_fatigue))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			heal *= 2;
			victim->move = UMAX(0, victim->move - heal);
		}
		else if (!strcasecmp(target_name, "disease"))
		{
			DISEASE_DATA *dis, *dis_next;

			if (!learned(ch, gsn_layhands_disease))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (save_resist(ch, victim, gsn_contagion, level))
			{
				pop_call();
				return TRUE;
			}
			
			infect_char(ch, victim, DIS_FILTH_FEVER);
		
			for (dis = victim->first_disease ; dis ; dis = dis_next)
			{
				dis_next = dis->next;
				
				if (dis->type != DIS_FILTH_FEVER)
					continue;
					
				if (dis->incubation < disease_table[dis->type].incubation)
				{
					dis->incubation = disease_table[dis->type].incubation;
					disease_update(victim);
					break;
				}
			}
			pop_call();
			return TRUE;
		}
		else if (!strcasecmp(target_name, "poison"))
		{
			if (!learned(ch, gsn_layhands_poison))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (!spell_poison(gsn_poison, level, ch, vo, TAR_CHAR_OFFENSIVE))
			{
				pop_call();
				return FALSE;
			}
		}
		else if (!strcasecmp(target_name, "blindness"))
		{
			if (!learned(ch, gsn_layhands_blindness))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (!spell_affect(gsn_blindness, level, ch, vo, TAR_CHAR_OFFENSIVE))
			{
				pop_call();
				return FALSE;
			}
		}
		else if (!strcasecmp(target_name, "curse"))
		{
			if (!learned(ch, gsn_layhands_curse))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (!spell_affect(gsn_curse, level, ch, vo, TAR_CHAR_OFFENSIVE))
			{
				pop_call();
				return FALSE;
			}
		}
		else if (!strcasecmp(target_name, "fear"))
		{
			if (!learned(ch, gsn_layhands_fear))
			{
				act("You do not know that divine blessing.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (spell_cause_fear(gsn_cause_fear, level, ch, vo, TAR_CHAR_OFFENSIVE))
			{
				pop_call();
				return FALSE;
			}
		}
		else
		{
			dam = TRUE;
		}
	}
	else
	{
		dam = TRUE;
	}

	act( "{108}Your hand pulses with black energy as you touch $N.", ch, NULL, victim, TO_CHAR );
	act( "{108}$n lays a blackened hand upon you.", ch, NULL, victim, TO_VICT );
	act( "{108}$n lays a darkened hand upon $N.", ch, NULL, victim, TO_NOTVICT );
	
	if (dam)
	{
		if (IS_UNDEAD(victim))
		{
			victim->hit = UMIN( victim->hit + heal, get_max_hit(victim));
		}
		else
		{
			spell_damage(ch, victim, heal, sn, level);
		}
	}
	update_pos(victim,-1);

	pop_call();
	return TRUE;
}

/*
 * Battle Cry feat - aoe intimidate for rage ability - Kregor
 */
void battle_cry( CHAR_DATA *ch )
{
	CHAR_DATA *vch, *vch_next;
	AFFECT_DATA af;
	int roll;

	push_call("battle_cry(%p)",ch);
	
	if (!in_combat(ch) || !is_affected(ch, gsn_barbarian_rage))
	{
		pop_call();
		return;
	}
	roll = intimidate_roll(ch);
	
	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, gsn_intimidate))
			continue;
		
		if (IS_AFFECTED(vch, AFF2_FEAR))
			continue;
			
		if (intimidate_check(ch, vch, roll, 0) < 0)
			continue;

		af.type      = gsn_intimidate;
		af.duration  = 1;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bittype   = AFFECT_TO_CHAR;
		af.bitvector = AFF2_FEAR;
		af.level     = ch->level;
		affect_to_char( ch, vch, &af );
		vch->fear_level++;

		act( "$N is visibly intimidated by your presence.", ch, NULL, vch, TO_CHAR);
		act( "You are shaken at $n's intimidating presence.", ch, NULL, vch, TO_VICT);
		act( "$N is visibly intimidated by $n's presence.", ch, NULL, vch, TO_NOTVICT);
	}
	pop_call();
	return;
}	


/*
 * Barbarian Rage, reworked do_berserk - Kregor
 */
DO_ABILITY(ability_rage)
{
	AFFECT_DATA af;
	int mod;

	push_call("ability_rage(%p,%p,%p,%p)",sn,level,ch,vo);

	if (IS_AFFECTED(ch, AFF2_BERSERK))
	{
		send_to_char("You're already enraged!\n\r", ch);
		pop_call();
		return FALSE;
	}
	
	act( "{118}The din of battle works you into a frenzied rage!",ch, NULL, NULL, TO_CHAR);
	act( "{118}$n works up into a frenzied rage!",ch, NULL, NULL, TO_ROOM);
	
	if (sn == gsn_blood_rage)
	{
		af.type      = sn;
		af.duration  = -1;
		af.bittype   = AFFECT_TO_CHAR;
		af.bitvector = AFF2_BERSERK;
	
		af.modifier  = 2;
		af.location  = APPLY_STR;
		affect_join( ch, ch, &af );
	
		af.modifier  = 2;
		af.location  = APPLY_CON;
		affect_join( ch, ch, &af );
		
		af.modifier  = -2;
		af.location  = APPLY_DODGE;
		affect_join( ch, ch, &af );
	
		pop_call();
		return TRUE;
	}
	else if (learned(ch, gsn_mighty_rage))
	{
		mod = 8;
	}
	else if (learned(ch, gsn_greater_rage))
	{
		mod = 6;
	}
	else
	{
		mod = 4;
	}

	af.type      = sn;
	af.duration  = -1;
	af.bittype   = AFFECT_TO_CHAR;
	af.bitvector = AFF2_BERSERK;

	af.modifier  = mod;
	af.location  = APPLY_STR;
	affect_join( ch, ch, &af );

	af.modifier  = mod / 2;
	af.location  = APPLY_DODGE;
	affect_join( ch, ch, &af );

	af.modifier  = mod / 2;
	af.location  = APPLY_MOR_REFL;
	affect_join( ch, ch, &af );

	if (mod < 8)
	{
		af.modifier  = -2;
		af.location  = APPLY_COMP_TOHIT;
		affect_join( ch, ch, &af );
	}

	if (learned(ch, gsn_battle_cry))
	{
		battle_cry(ch);
	}

	pop_call();
	return TRUE;
}

/*
 * Retribution domain ability
 */
DO_ABILITY(ability_retributive_strike)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	push_call("ability_retributive_strike(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!victim->last_attacker)
	{
		act("You have not been recently injured in current combat.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	act("{138}You call upon divine retribution!", ch, NULL, victim, TO_CHAR);
	act("{138}$n calls upon divine retribution!", ch, NULL, victim, TO_ROOM);

	af.type      = sn;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.duration  = -1;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}

/*
 * Shapechange skill for druids
 */
DO_ABILITY(ability_wildshape)
{
	char buf[MAX_INPUT_LENGTH];
	int race;

	push_call("ability_wildshape(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!is_string(target_name))
	{
		ch_printf_color(ch, "Wildshape into what?\n\r");
		pop_call();
		return FALSE;
	}

// 	if (is_polymorph(ch))
// 	{
// 		ch_printf_color(ch, "You are already in an alternate form.\n\r");
// 		pop_call();
// 		return;
// 	}

	if ((race = lookup_race(target_name)) == -1)
	{
		ch_printf_color(ch, "%s is not a valid race.\n\r", target_name);
		pop_call();
		return FALSE;
	}

	sprintf(buf, "%s", race_table[race].race_name);
	
	if (race == get_race(ch))
	{
		ch_printf_color(ch, "You are already %s %s.\n\r", a_an(buf), buf);
		pop_call();
		return FALSE;
	}
	
	if (learned(ch, gsn_infinite_wildshape))
	{
		if (race_table[race].type != RTYPE_ANIMAL
		&& race_table[race].type != RTYPE_PLANT
		&& race_table[race].type != RTYPE_VERMIN)
		{
			ch_printf_color(ch, "You cannot assume the form of %s %s.\n\r", a_an(buf), buf);
			pop_call();
			return FALSE;
		}
	}
	else if (race_table[race].type != RTYPE_ANIMAL)
	{
		if (race_table[race].type == RTYPE_PLANT
		&& !learned(ch, gsn_wildshape_plant))
		{
			ch_printf_color(ch, "You cannot assume the form of %s %s.\n\r", a_an(buf), buf);
			pop_call();
			return FALSE;
		}
		else if (!IS_SET(race_table[race].flags, RSPEC_ELEMENTAL))
		{
			if (!learned(ch, gsn_wildshape_elemental))
			{
				ch_printf_color(ch, "You cannot assume the form of %s %s.\n\r", a_an(buf), buf);
				pop_call();
				return FALSE;
			}
			if (race_table[race].size < SIZE_SMALL)
			{
				ch_printf_color(ch, "%s %s is too small a creature.\n\r", a_an(buf), buf);
				pop_call();
				return FALSE;
			}
			else if (race_table[race].size > SIZE_LARGE)
			{
				ch_printf_color(ch, "%s %s is too large a creature.\n\r", a_an(buf), buf);
				pop_call();
				return FALSE;
			}
		}
		else
		{
			ch_printf_color(ch, "You cannot assume the form of %s %s.\n\r", a_an(buf), buf);
			pop_call();
			return FALSE;
		}
	}
	else
	{
		if (race_table[race].size < SIZE_TINY)
		{
			ch_printf_color(ch, "%s %s is too small a creature.\n\r", a_an(buf), buf);
			pop_call();
			return FALSE;
		}
		else if (race_table[race].size < SIZE_SMALL
		&& !learned(ch, gsn_wildshape_tiny))
		{
			ch_printf_color(ch, "%s %s is too small a creature.\n\r", a_an(buf), buf);
			pop_call();
			return FALSE;
		}
		else if (race_table[race].size > SIZE_HUGE)
		{
			ch_printf_color(ch, "%s %s is too large a creature.\n\r", a_an(buf), buf);
			pop_call();
			return FALSE;
		}
		else if (race_table[race].size > SIZE_LARGE
		&& !learned(ch, gsn_wildshape_huge))
		{
			ch_printf_color(ch, "%s %s is too large a creature.\n\r", a_an(buf), buf);
			pop_call();
			return FALSE;
		}
		else if (race_table[race].size > SIZE_MEDIUM
		&& !learned(ch, gsn_wildshape_large))
		{
			ch_printf_color(ch, "%s %s is too large a creature.\n\r", a_an(buf), buf);
			pop_call();
			return FALSE;
		}
	}

	if (level < race_table[race].hit_dice)
	{
		ch_printf_color(ch, "%s %s is too strong a creature.\n\r", a_an(buf), buf);
		pop_call();
		return FALSE;
	}
		
	if (!morph(ch, ch, race, gsn_wildshape, level))
	{
		pop_call();
		return FALSE;
	}
	pop_call();
	return TRUE;
}


/*
 * Animal companion summoning 
 * for druids and rangers - Kregor 3/19/07
 */
DO_ABILITY(ability_companion)
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mob = NULL;
	char arg[MAX_INPUT_LENGTH];
	char buf[MAX_STRING_LENGTH];
	int race, bonus;
	
	push_call("ability_companion(%p,%p,%p,%p)",sn,level,ch,vo);

	if( IS_NPC( ch ) )
	{
		pop_call();
		return FALSE;
	}

	if (ch->race != get_race(ch))
	{
		send_to_char( "You cannot summon a companion while shapechanged.\r\n", ch );
		pop_call();
		return FALSE;
	}
	
	if (get_companion(ch) == NULL)
	{
		target_name = one_argument( target_name, arg );
		
		if (arg[0] == '\0' || target_name[0] == '\0')
		{
			send_to_char( "Syntax: activate companion <animal type> <name> [adjective]\r\n", ch );
			pop_call();
			return FALSE;
		}
		
		if ((race = lookup_race(arg)) == -1
		|| race_table[race].type != RTYPE_ANIMAL
		|| race_table[race].hit_dice + 1 >= level)
		{
			sprintf(buf, "You may summon one of the following:\n\r");
			
			for (race = 0 ; race < MAX_RACE ; race++)
			{
				if (race_table[race].type != RTYPE_ANIMAL
				|| (race_table[race].hit_dice > 2 && race_table[race].hit_dice + 1 >= level))
					continue;
				if (!is_string(race_table[race].race_name))
					continue;
				if (IS_SET(race_table[race].flags, RSPEC_AQUATIC)
				&& !rspec_req(ch, RSPEC_AQUATIC))
					continue;
					
				cat_sprintf(buf, "'%s' ", race_table[race].race_name);
			}
			strcat(buf, "\n\r");
			send_to_char(justify(buf, get_page_width(ch)), ch);
			pop_call();
			return FALSE;
		}
		
		if (IS_SET(race_table[race].flags, RSPEC_AQUATIC) && !rspec_req(ch, RSPEC_AQUATIC))
		{
			send_to_char( "Only aquatic characters may have aquatic companions.\r\n", ch );
			pop_call();
			return FALSE;
		}
	
		pMob = get_mob_index(MOB_VNUM_COMPANION);   /* Hard coded in mud.are */
		mob = create_mobile( pMob );
		
		mob->race 			= race;
		mob->level			= UMAX(1, race_table[race].hit_dice);
		mob->perm_str		= 10 + race_table[race].race_mod[0];
		mob->perm_int		= 10 + race_table[race].race_mod[3];
		mob->perm_wis		= 10 + race_table[race].race_mod[4];
		mob->perm_cha		= 10 + race_table[race].race_mod[5];
		mob->size				= race_table[race].size;
		mob->height			= race_table[race].height;
		mob->weight			= race_table[race].weight;
		mob->alignment	= race_table[race].alignment;
		mob->ethos			= race_table[race].ethos;
	
		target_name = one_argument(target_name, arg);
	
		if (!check_legal_name(mob, arg))
		{
			junk_mob(mob);
			pop_call();
			return FALSE;
		}
	
		if (target_name[0] != '\0')
		{
			RESTRING(mob->name, format("%s %s %s", race_table[race].race_name, arg, target_name));
			RESTRING(mob->short_descr, format("%s, %s %s %s", capitalize(arg), a_an(target_name), target_name, race_table[race].race_name));
			RESTRING(mob->long_descr, format("%s, %s %s %s is here.", capitalize(arg), a_an(target_name), target_name, race_table[race].race_name));
		}
		else
		{
			RESTRING(mob->name, format("%s %s", race_table[race].race_name, arg));
			RESTRING(mob->short_descr, format("%s, %s %s", capitalize(arg), a_an(race_table[race].race_name), race_table[race].race_name));
			RESTRING(mob->long_descr, format("%s, %s %s is here.", capitalize(arg), a_an(race_table[race].race_name), race_table[race].race_name));
		}
	
		char_to_room( mob, ch->in_room->vnum, TRUE );
		SET_BIT(mob->act, ACT_PET|ACT_COMPANION|ACT_SENTINEL);
		
		bonus = UMAX(0, (level - race_table[race].hit_dice) / 3);
		
		mob->level			= bonus * 2 + UMAX(1, race_table[race].hit_dice);
		mob->nat_armor	= bonus * 2;
		mob->perm_str		= 10 + race_table[race].race_mod[0] + bonus;
		mob->perm_dex		= 10 + race_table[race].race_mod[1] + bonus;
		mob->max_hit		= dice(mob->level, race_type_table[race_type(mob)].hit_die);
		mob->hit				= get_max_hit(mob);
	}
	else
	{		
		if (in_same_room(mob, ch))
		{
			act("$N is already here beside you.", ch, NULL, mob, TO_CHAR);
			pop_call();
			return FALSE;
		}
	
		char_from_room(mob);
		char_to_room( mob, ch->in_room->vnum, TRUE );
	}

	act( "$N answers your call to the wild.", ch, NULL, mob, TO_CHAR);
	act( "$N companion answers $n's call to the wild.", ch, NULL, mob, TO_ROOM);
	
	add_follower( mob , ch );

	pop_call();
	return TRUE;
}


/*
 * Warhorse summoning for paladins - Kregor 12/05/09
 */
DO_ABILITY(ability_warhorse)
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mob;
	AFFECT_DATA af;
	char arg[MAX_INPUT_LENGTH];
	
	push_call("ability_warhorse(%p,%p,%p,%p)",sn,level,ch,vo);

	if (ch->race != get_race(ch))
	{
		send_to_char( "You cannot summon a warhorse while shapechanged.\r\n", ch );
		pop_call();
		return FALSE;
	}

	if ((mob = get_warhorse(ch)) == NULL)
	{
		if( target_name[0] == '\0' )
		{
			send_to_char( "You need to give your mount a name.\r\n", ch );
			pop_call();
			return FALSE;
		}
	
		pMob = get_mob_index(MOB_VNUM_WARHORSE);   /* Hard coded in mud.are */
		mob = create_mobile( pMob );

		target_name = one_argument(target_name, arg);
	
		if (!check_legal_name(mob, arg))
		{
			junk_mob(mob);
			pop_call();
			return FALSE;
		}
	
		char_to_room( mob, ch->in_room->vnum, TRUE );
		
		if (target_name[0] != '\0')
		{
			RESTRING(mob->name, format("warhorse horse %s %s", arg, target_name));
			RESTRING(mob->short_descr, format("%s, %s %s warhorse", capitalize(arg), a_an(target_name), target_name));
			RESTRING(mob->long_descr, format("%s, %s %s warhorse stands here proudly.", capitalize(arg), a_an(target_name), target_name));
		}
		else
		{
			RESTRING(mob->name, format("horse warhorse %s", arg));
			RESTRING(mob->short_descr, format("%s, a regal warhorse", capitalize(arg)));
			RESTRING(mob->short_descr, format("%s, a regal warhorse stands here proudly.", capitalize(arg)));
		}

		mob->level			= (level / 2) + race_table[mob->race].hit_dice;
		mob->nat_armor	= ROUNDUP(level * 2 / 3);
		mob->perm_str		= (level / 5) + 10 + race_table[mob->race].race_mod[0];
		mob->perm_int		= URANGE(6, level*2/3, 9) ;
		mob->max_hit		= dice(mob->level, race_type_table[race_type(mob)].hit_die);
		mob->hit				= get_max_hit(mob);
		
		while (mob->first_affect)
		{
			affect_from_char(mob, mob->first_affect);
		}
	
		if (level >= 10)
		{
			af.type      = gsn_warhorse;
			af.duration  = -1;
			af.bittype   = AFFECT_TO_NONE;
			af.bitvector = AFF_NONE;
			af.location  = APPLY_SPELL_RES;
			af.modifier  = level + 11;
			af.level     = level;
			affect_to_char( mob, mob, &af );
		}
	
		if (level >= 6)
		{
			af.type      = gsn_warhorse;
			af.duration  = -1;
			af.level     = level;
			af.bittype   = AFFECT_TO_NONE;
			af.bitvector = AFF_NONE;
			af.location  = APPLY_DR_EVIL;
			af.modifier  = 5;
			affect_to_char( mob, mob, &af );
	
			af.bitvector = AFF_NONE;
			af.location  = APPLY_DR_COLD;
			af.modifier  = 10;
			affect_to_char( mob, mob, &af );
	
			af.bitvector = AFF_NONE;
			af.location  = APPLY_DR_ACID;
			af.modifier  = 10;
			affect_to_char( mob, mob, &af );
	
			af.bitvector = AFF_NONE;
			af.location  = APPLY_DR_ELECTRIC;
			af.modifier  = 10;
			affect_to_char( mob, mob, &af );
		}
		
		/* alignment settings for both blackguard and paladin */
		if (IS_GOOD(ch))
			mob->alignment = mob->ethos = 1000;
		else
			mob->alignment = mob->ethos = -1000;
	
		SET_BIT(mob->act, ACT_PET|ACT_WARHORSE|ACT_SENTINEL);
		add_follower( mob, ch );
	}
	else
	{		
		if (in_same_room(mob, ch))
		{
			act("$N is already here beside you.", ch, NULL, mob, TO_CHAR);
			pop_call();
			return FALSE;
		}
	
		char_from_room(mob);
		char_to_room( mob, ch->in_room->vnum, TRUE );
	}
	
	act("$N answers your call from $S $t refuge.", ch, IS_GOOD(ch) ? "celestial" : "fiendish", mob, TO_CHAR);
	act("$N answers $n's call from $S $t refuge.", ch, IS_GOOD(ch) ? "celestial" : "fiendish", mob, TO_ROOM);

	pop_call();
	return TRUE;
}


/*
 * Shadow companions for shadow dancers - Kregor 6/6/11
 */
DO_ABILITY(ability_shadow_companion)
{
	MOB_INDEX_DATA *pMob;
	CHAR_DATA *mob;
	char arg[MAX_INPUT_LENGTH];
	
	push_call("ability_shadow_companion(%p,%p,%p,%p)",sn,level,ch,vo);

	if ((mob = get_companion(ch)) == NULL)
	{
		if( target_name[0] == '\0' )
		{
			send_to_char( "You need to give your companion a name.\r\n", ch );
			pop_call();
			return FALSE;
		}
	
		pMob = get_mob_index(MOB_VNUM_SHADOW_BEAST);   /* Hard coded in mud.are */
		mob = create_mobile( pMob );

		target_name = one_argument(target_name, arg);
	
		if (!check_legal_name(mob, arg))
		{
			junk_mob(mob);
			pop_call();
			return FALSE;
		}
	
		char_to_room( mob, ch->in_room->vnum, TRUE );
		
		if (target_name[0] != '\0')
		{
			RESTRING(mob->name, format("shadow mastiff %s %s", arg, target_name));
			RESTRING(mob->short_descr, format("%s, a shadow mastiff", capitalize(arg)));
			RESTRING(mob->long_descr, format("%s, %s %s shadow mastiff prowls here.", capitalize(arg), a_an(target_name), target_name));
		}
		else
		{
			RESTRING(mob->name, format("shadow mastiff %s", arg));
			RESTRING(mob->short_descr, format("%s, a shadow mastiff", capitalize(arg)));
			RESTRING(mob->short_descr, format("%s, {108}a jet black shadow mastiff prowls here.", capitalize(arg)));
		}

		int bonus = UMAX(0, (level - race_table[mob->race].hit_dice) / 3);

		mob->level			= bonus * 2 + UMAX(1, race_table[mob->race].hit_dice);
		mob->nat_armor	= bonus * 2;
		mob->perm_str		= 10 + race_table[mob->race].race_mod[0] + bonus;
		mob->perm_dex		= 10 + race_table[mob->race].race_mod[1] + bonus;
		mob->max_hit		= dice(mob->level, race_type_table[race_type(mob)].hit_die);
		mob->hit				= get_max_hit(mob);

		SET_BIT(mob->act, ACT_PET|ACT_COMPANION|ACT_SENTINEL);
		add_follower( mob, ch );
	}
	else
	{		
		if (in_same_room(mob, ch))
		{
			act("$N is already here beside you.", ch, NULL, mob, TO_CHAR);
			pop_call();
			return FALSE;
		}
	
		char_from_room(mob);
		char_to_room( mob, ch->in_room->vnum, TRUE );
	}
	
	act("{108}$N answers your call from the shadows.", ch, NULL, mob, TO_CHAR);
	act("{108}$N answers $n's call from the shadows.", ch, NULL, mob, TO_ROOM);

	pop_call();
	return TRUE;
}


/*
 * arcane archer ability functions - Kregor
 */
DO_ABILITY(ability_imbue_arrow)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj, *wield;
	AFFECT_DATA af;
	char arg[MAX_INPUT_LENGTH];
	int spell, class, mana;

	push_call("ability_imbue_arrow(%p,%p,%p,%p)",sn,level,ch,vo);

	if (!is_string(target_name))
	{
		act("Imbue with what spell?", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if ((wield = get_wield(ch, FALSE)) == NULL || !is_bow(wield))
	{
		act("You are not wielding a bow.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if ((obj = get_ammo(ch, wield)) == NULL)
	{
		act("You cannot find any ammo for that weapon.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if (IS_OBJ_STAT(obj, ITEM_MAGIC) || WEAPON_FLAG(obj, WFLAG_SPELL_STORING))
	{
		act("$p is already magical.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	target_name = one_argument(target_name, arg);
	
	if ((spell = skill_lookup(arg)) == -1)
	{
		act("That is not a spell.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if ((class = prepared(ch, spell)) == -1)
	{
		if ((class = spontaneous_cast(ch, spell)) == -1)
		{
			act("You do not have that spell prepared.", ch, NULL, NULL, TO_CHAR);
			pop_call();
			return FALSE;
		}
	}
	
	if ((mana = get_mana(ch, spell, skill_table[spell].skill_level[class], class)) > ch->mana[class])
	{
		act("You do not have enough mana to imbue that spell.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	ch->mana[class] -= mana;

	act( "{158}You imbue $p with $T.", ch, obj, skill_table[spell].name, TO_CHAR);

	af.type      = sn;
	af.duration  = 1;
	af.location  = APPLY_WEAPON_FLAG;
	af.modifier  = WFLAG_SPELL_STORING;
	af.bittype   = AFFECT_TO_OBJ;
	af.bitvector = ITEM_MAGIC;
	af.level     = level;
	affect_to_obj( ch,obj, &af);

	af.location  = APPLY_OBJVAL_2;
	af.modifier  = spell;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_obj( ch,obj, &af);

	af.location  = APPLY_OBJVAL_3;
	af.modifier  = multi_class_level(ch, spell);
	af.level     = level;

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

	pop_call();
	return TRUE;
}

DO_ABILITY(ability_seeker_arrow)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj, *wield;
	AFFECT_DATA af;

	push_call("ability_seeker_arrow(%p,%p,%p,%p)",sn,level,ch,vo);

	if ((wield = get_wield(ch, FALSE)) == NULL || !is_bow(wield))
	{
		act("You are not wielding a bow.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if ((obj = get_ammo(ch, wield)) == NULL)
	{
		act("You cannot find any ammo for that weapon.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if (IS_OBJ_STAT(obj, ITEM_MAGIC) || WEAPON_FLAG(obj, WFLAG_SEEKING))
	{
		act("$p is already magical.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	act( "{158}You create an arrow of seeking.", ch, NULL, NULL, TO_CHAR);

	af.type      = sn;
	af.duration  = 1;
	af.location  = APPLY_WEAPON_FLAG;
	af.modifier  = WFLAG_SEEKING;
	af.bittype   = AFFECT_TO_OBJ;
	af.bitvector = ITEM_MAGIC;
	af.level     = multi_class_level(ch, sn);
	affect_to_obj( ch,obj, &af);

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

	pop_call();
	return TRUE;
}

DO_ABILITY(ability_hail_of_arrows)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	CHAR_DATA *vch, *vch_next;
	OBJ_DATA *ammo, *wield;
	int cnt, count;

	push_call("ability_hail_of_arrows(%p,%p,%p,%p)",sn,level,ch,vo);

	if ((wield = get_wield(ch, FALSE)) == NULL || !is_bow(wield))
	{
		act("You are not wielding a bow.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if ((ammo = get_ammo(ch, wield)) == NULL)
	{
		act("You cannot find any ammo for that weapon.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

	one_hit(ch, victim, TYPE_UNDEFINED, 0, wield);
	
	count = class_level(ch, CLASS_ARCANE_ARCHER);

	for (cnt = 0, vch = victim->in_room->first_person ; vch ; vch = vch_next)
	{
		vch_next = vch->next_in_room;

		if (get_ammo(ch, wield) == NULL)
			break;

		if (!can_mass_attack(ch, vch))
			continue;
			
		if (!is_same_group(victim, vch))
			continue;

		if (vch == victim)
			continue;
			
		one_hit( ch, vch, TYPE_UNDEFINED, 0, wield );
		cnt++;
		
		if (cnt >= count)
			break;
	}
	TAKE_ACTION(ch, ACTION_FULL);
	pop_call();
	return TRUE;
}

DO_ABILITY(ability_energy_arrow)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj, *wield;
	AFFECT_DATA af;
	char echo[MAX_INPUT_LENGTH];
	int flag;

	push_call("ability_energy_arrow(%p,%p,%p,%p)",sn,level,ch,vo);

	if ((wield = get_wield(ch, FALSE)) == NULL || !is_bow(wield))
	{
		act("You are not wielding a bow.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if ((obj = get_ammo(ch, wield)) == NULL)
	{
		act("You cannot find any ammo for that weapon.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if (IS_OBJ_STAT(obj, ITEM_MAGIC))
	{
		act("$p is already magical.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if (!strcasecmp(target_name, "fire"))
	{
		flag = WFLAG_FLAMING_BURST;
		strcpy(echo, "flame");
	}
	else if (!strcasecmp(target_name, "frost"))
	{
		flag = WFLAG_ICY_BURST;
		strcpy(echo, "frost");
	}
	else if (!strcasecmp(target_name, "shock"))
	{
		flag = WFLAG_SHOCK_BURST;
		strcpy(echo, "electricity");
	}
	else
	{
		flag = 0;
		echo[0] = '\0';
	}

	if (!flag)
	{
		send_to_char("Which type of energy? fire, frost, or shock?\n\r", ch);
		pop_call();
		return FALSE;
	}
	
	act( "{158}You create an arrow of $t.", ch, echo, NULL, TO_CHAR);

	af.type      = sn;
	af.duration  = 1;
	af.location  = APPLY_WEAPON_FLAG;
	af.modifier  = flag;
	af.bittype   = AFFECT_TO_OBJ;
	af.bitvector = ITEM_MAGIC;
	af.level     = multi_class_level(ch, sn);
	affect_to_obj( ch,obj, &af);

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

	pop_call();
	return TRUE;
}

DO_ABILITY(ability_death_arrow)
{
	OBJ_DATA *obj, *wield;
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	push_call("ability_death_arrow(%p,%p,%p,%p)",sn,level,ch,vo);

	if ((wield = get_wield(ch, FALSE)) == NULL || !is_bow(wield))
	{
		act("You are not wielding a bow.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if ((obj = get_ammo(ch, wield)) == NULL)
	{
		act("You cannot find any ammo for that weapon.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

	if (IS_OBJ_STAT(obj, ITEM_MAGIC) || WEAPON_FLAG(obj, WFLAG_SPELL_STORING))
	{
		act("$p is already magical.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	act( "{158}You create an arrow of death against $N!", ch, NULL, victim, TO_CHAR);

	af.type      = sn;
	af.duration  = 1;
	af.location  = APPLY_WEAPON_FLAG;
	af.modifier  = WFLAG_SLAYING;
	af.bittype   = AFFECT_TO_OBJ;
	af.bitvector = ITEM_MAGIC;
	af.level     = multi_class_level(ch, sn);
	affect_to_obj( ch,obj, &af);

	af.location  = APPLY_OBJVAL_2;
	af.modifier  = race_table[victim->race].type;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_obj( ch,obj, &af);

	af.location  = APPLY_OBJVAL_3;
	af.modifier  = race_table[victim->race].flags;
	affect_to_obj( ch,obj, &af);
	
	one_hit(ch, victim, TYPE_UNDEFINED, 0, wield);

	pop_call();
	return TRUE;
}


/*
 * Ranger/Druid Wild Empathy
 */
DO_ABILITY(ability_wild_empathy)
{
	push_call("ability_wild_empathy(%p,%p,%p,%p)",sn,level,ch,vo);

	do_tame(ch, target_name);

	pop_call();
	return TRUE;
}

/*
 * the TAME command is for the Wild Empathy ability per the SRD.
 * Variant uses the hit dice of the animal as a mod to the DC - Kregor
 */
void do_tame( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	int level;
	char *cmd = STRALLOC(argument);

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

	if (IS_SET(ch->action, ACTION_FULL))
	{
		send_to_char("This action takes a full round to perform.\n\r", ch);
		pop_call();
		return;
	}
	
	if ((level = multi_skill_level(ch, gsn_wild_empathy)) <= 0)
	{
		send_to_char("You are not skilled enough to tame the wild.\n\r", ch);
		pop_call();
		return;
	}
	if (argument[0] == '\0')
	{
		send_to_char("Tame who?\n\r", ch);
		pop_call();
		return;
	}
	if ((victim = get_char_room(ch, argument)) == NULL)
	{
		send_to_char("They aren't here.\n\r", ch);
		pop_call();
		return;
	}
	if (!IS_NPC(victim))
	{
		send_to_char("You cannot tame PCs.\n\r", ch);
		pop_call();
		return;
	}
	
	if (!IS_ANIMAL(victim))
	{
		act("$N cannot be tamed.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}
	
	CHECK_TURN(ch, victim);
	
	if (!ch->concentrating)
	{
		act( "You attempt to empathize with $N.", ch, NULL, victim, TO_CHAR);
		act( "$n attempts to empathize with $N.", ch, NULL, victim, TO_NOTVICT);
		ch->concentrating = TRUE;
		ch->skill_timer		= 12;
		ch->timer_fun			= do_tame;
		RESTRING(ch->cmd_argument, cmd);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	int diceroll, dc;
	
	/* chance = handle animal roll vs. DC 15 + creature level */
	diceroll = cha_roll(ch);
	diceroll += level / 2;
	diceroll += synergy_bonus(ch, gsn_handle_animal);
	dc = 15;	
	dc += victim->level;
	if (IS_ACT(victim, ACT_AGGRESSIVE))
		dc += 4;

	if (is_affected(victim, gsn_charm_animal))
	{
		if (get_caster(victim, gsn_charm_animal) == ch)
			diceroll += 10;
	}
	
	if (!handle_animal_check(ch, victim, diceroll, dc))
	{
		act( "$N reacts to you unfavorably.",  ch, NULL, victim, TO_CHAR);
		act( "$n tries to tame $N, but fails.",  ch, NULL, victim, TO_NOTVICT);
		pop_call();
		return;
	}

	if (in_combat(victim) || IS_ACT(victim, ACT_AGGRESSIVE))
	{
		if (in_combat(victim))
			char_from_combat(victim);
		REMOVE_BIT(victim->act, ACT_AGGRESSIVE);
		act( "$n loses $s agression and is calmed.",  victim, NULL, NULL, TO_ROOM);
		act( "You lose your agression and are calmed.",  victim, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}
		
	if (victim->master || IS_AFFECTED(victim, AFF_DOMINATE))
	{
		act( "$N already has a master.", ch, NULL, victim, TO_CHAR);
		pop_call();
		return;
	}

	// make effect temporary if too many followers - Kregor
	if (get_pet_levels(ch) + victim->level >= max_pet_levels(ch))
	{
		AFFECT_DATA af;
	
		af.type      = gsn_wild_empathy;
		af.duration  = hr * level;
		af.location  = 0;
		af.modifier  = 0;
		af.bittype   = AFFECT_TO_CHAR;
		af.bitvector = AFF_DOMINATE;
		af.level     = level;
		affect_to_char( ch, victim, &af );
	}
	else
	{
		SET_BIT(victim->act, ACT_PET|ACT_SENTINEL);
	}

	act( "$N reacts to you favorably, and follows you.",  ch, NULL, victim, TO_CHAR);
	act( "$N reacts favorably to $n, and follows $m.",  ch, NULL, victim, TO_NOTVICT);

	add_follower(victim, ch);

	pop_call();
	return;
}

/*
 * Dwarven Defender class ability
 */
DO_ABILITY(ability_defensive_stance)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	push_call("ability_defensive_stance(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if (is_affected(ch, sn))
	{
		act("You are already in a defensive stance.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if (IS_AFFECTED(ch, AFF2_BERSERK))
	{
		act("You are not focused enough.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if (IS_EXHAUSTED(ch) || (!learned(ch, gsn_tireless_defense) && IS_FATIGUED(ch)))
	{
		act("You are too tired to stand your ground.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	

	act("{138}You plant your feet, and stand your ground!", ch, NULL, victim, TO_CHAR);
	act("{138}$n plants $s feet, and stands $s ground!", ch, NULL, victim, TO_ROOM);

	af.type      = sn;
	af.location  = APPLY_STR;
	af.modifier  = 2;
	af.duration  = 3 + stat_bonus(FALSE, victim, APPLY_CON);
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_join( ch, victim, &af );

	af.location  = APPLY_CON;
	af.modifier  = 4;
	affect_join( ch, victim, &af );

	af.location  = APPLY_RES_SAVES;
	af.modifier  = 2;
	affect_join( ch, victim, &af );

	pop_call();
	return TRUE;
}

/*
 * Eldritch Knight class ability
 */
DO_ABILITY(ability_arcane_weapon)
{
	OBJ_DATA *wield;
	AFFECT_DATA af;
	lg_int bitv = 0;
	int mana, lvl;

	push_call("ability_arcane_weapon(%p,%p,%p,%p)",sn,level,ch,vo);

	if ((wield = get_wield(ch, FALSE)) == NULL)
	{
		act("You are not wielding a weapon.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if (IS_OBJ_STAT(wield, ITEM_MAGIC))
	{
		act("$p is already magical.", ch, wield, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	lvl = multi_class_level(ch, sn);
	
	if (is_string(target_name))
	{
		if (strcasecmp(target_name, "fire"))
		{
			if (lvl < 7)
			{
				act("You cannot add that effect to $p.", ch, wield, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			bitv = WFLAG_FLAMING;
		}
		else if (strcasecmp(target_name, "cold"))
		{
			if (lvl < 7)
			{
				act("You cannot add that effect to $p.", ch, wield, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			bitv = WFLAG_FROST;
		}
		else if (strcasecmp(target_name, "acid"))
		{
			if (lvl < 7)
			{
				act("You cannot add that effect to $p.", ch, wield, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			bitv = WFLAG_CAUSTIC;
		}
		else if (strcasecmp(target_name, "shock"))
		{
			if (lvl < 7)
			{
				act("You cannot add that effect to $p.", ch, wield, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			bitv = WFLAG_SHOCK;
		}
		else if (strcasecmp(target_name, "vorpal"))
		{
			if (lvl < 9)
			{
				act("You cannot add that effect to $p.", ch, wield, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			bitv = WFLAG_VORPAL;
		}
		else if (strcasecmp(target_name, "wounding"))
		{
			if (lvl < 9)
			{
				act("You cannot add that effect to $p.", ch, wield, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			bitv = WFLAG_WOUNDING;
		}
		else if (strcasecmp(target_name, "aligned"))
		{
			if (lvl < 9)
			{
				act("You cannot add that effect to $p.", ch, wield, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (IS_NEUTRAL(ch) && IS_UNCONCERNED(ch))
			{
				act("You are too neutral to align $p.", ch, wield, NULL, TO_CHAR);
				pop_call();
				return FALSE;
			}
			if (IS_GOOD(ch))
				SET_BIT(bitv, WFLAG_HOLY);
			if (IS_EVIL(ch))
				SET_BIT(bitv, WFLAG_UNHOLY);
			if (IS_LAWFUL(ch))
				SET_BIT(bitv, WFLAG_AXIOMATIC);
			if (IS_CHAOTIC(ch))
				SET_BIT(bitv, WFLAG_ANARCHIC);
		}
		else
		{
			send_to_char("That is not a valid effect.\n\r", ch);
			pop_call();
			return FALSE;
		}
	}
	
	if (bitv)
	{
		if (WEAPON_FLAG(wield, bitv))
		{
			act("$p already possesses that affect.", ch, wield, NULL, TO_CHAR);
			pop_call();
			return FALSE;
		}
		switch(bitv)
		{
			case WFLAG_FLAMING:
			case WFLAG_FROST:
			case WFLAG_CAUSTIC:
			case WFLAG_SHOCK:
				mana = 9;
				break;
			default:
				mana = 15;
				break;
		}
		// mana has to come from arcane casting class
		if (ch->mana[CLASS_WIZARD] < mana)
		{
			if (ch->mana[CLASS_SORCERER] < mana)
			{
				if (ch->mana[CLASS_BARD] < mana)
				{
					act("You do not have enough mana to empower $p.", ch, wield, NULL, TO_CHAR);
					pop_call();
					return FALSE;
				}
				else
				{
					ch->mana[CLASS_BARD] -= mana;
				}
			}
			else
			{
				ch->mana[CLASS_SORCERER] -= mana;
			}
		}
		else
		{
			ch->mana[CLASS_WIZARD] -= mana;
		}
	}
	
	act( "{178}$p crackles with arcane energy!", ch, wield, NULL, TO_CHAR);
	act( "{178}$p crackles with arcane energy!", ch, wield, NULL, TO_ROOM);

	af.type      = sn;
	af.duration  = 10 * lvl;
	af.location  = APPLY_HITROLL;
	af.modifier  = lvl / 2;
	af.bittype   = AFFECT_TO_OBJ;
	af.bitvector = ITEM_MAGIC;
	af.level     = lvl;
	affect_to_obj( ch, wield, &af);

	if (bitv)
	{
		af.location  = APPLY_WEAPON_FLAG;
		af.modifier  = bitv;
		affect_to_obj( ch, wield, &af);
	}

	pop_call();
	return TRUE;
}

/*
 * Divine Trickster undead backstab
 */
DO_ABILITY(ability_channeling_attack)
{
	AFFECT_DATA af;
	
	push_call("ability_channeling_attack(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if (is_affected(ch, sn))
	{
		act("You are already using this ability.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	act("{138}You channel your turning energy into your attacks!", ch, NULL, NULL, TO_CHAR);

	af.type      = sn;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.duration  = UMAX(1, 1+stat_bonus(TRUE, ch, APPLY_CHA));
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, ch, &af );

	pop_call();
	return TRUE;
}

/*
 * Divine Trickster hide bonus
 */
DO_ABILITY(ability_divine_veil)
{
	AFFECT_DATA af;
	
	push_call("ability_divine_veil(%p,%p,%p,%p)",sn,level,ch,vo);
	
	act("{138}You pray for divine blessing against detection!", ch, NULL, NULL, TO_CHAR);

	af.type      = sn;
	af.location  = APPLY_STEALTH;
	af.modifier  = level / 2 + 5;
	af.duration  = 10 * UMAX(1, stat_bonus(TRUE, ch, APPLY_CHA));
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, ch, &af );

	pop_call();
	return TRUE;
}

/*
 * Divine Trickster locate spell like ability
 */
DO_ABILITY(ability_divine_location)
{
	OBJ_DATA *obj;
	OBJ_DATA *in_obj;
	char obj_name[MAX_INPUT_LENGTH];
	char txt[MAX_STRING_LENGTH];
	int count;
	
	push_call("ability_divine_location(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if (*target_name == '\0')
	{
		send_to_char( "What are you trying to locate?\n\r", ch );
		pop_call();
		return FALSE;
	}
	
	*txt = '\0';

	for (count = 0, obj = mud->f_obj ; obj ; obj = obj->next)
	{
		if (!is_multi_name_list_short(target_name, obj->short_descr) || !can_see_obj(ch, obj) )
		{
			continue;
		}
		
		if (IS_SET(obj->extra_flags, ITEM_NOSCRY))
		{
			continue;
		}

		if (obj->in_room && IS_SET(obj->in_room->room_flags, ROOM_NOSCRY))
		{
			continue;
		}

		for (in_obj = obj ; in_obj->in_obj ; in_obj = in_obj->in_obj);

		if (in_obj->carried_by && !can_see_world(ch, in_obj->carried_by))
		{
			continue;
		}

		if (in_obj->carried_by)
		{
			if (check_nondetection(ch, in_obj->carried_by, gsn_locate_object))
			{
				continue;
			}
		}
		else if (!obj->in_room)
		{
			continue;
		}

		if (in_obj->carried_by->in_room && IS_SET(in_obj->carried_by->in_room->room_flags, ROOM_NOSCRY))
		{
			continue;
		}

		if (in_obj->material == MATERIAL_LEAD)
		{
			continue;
		}
		
		strcpy(obj_name, capitalize(obj->short_descr));

		if (in_obj->carried_by != NULL)
		{
			cat_sprintf(txt, "%s {300}is carried by %s.\n\r", obj_name, PERS(in_obj->carried_by, ch));
		}
		else
		{
			cat_sprintf(txt, "%s {300}is at %s.\n\r", obj_name, in_obj->in_room->name);
		}
		if (++count >= UMIN(level/2, 10))
		{
			break;
		}
	}

	if (count == 0)
	{
		send_to_char( "You find nothing like that in hell, earth, or heaven.\n\r", ch );
	}
	pop_call();
	return TRUE;
}

/*
 * Arcane Trickster ability to replace
 * Ranged Legerdemain (inspired by NWN2 - Kregor
 */
DO_ABILITY(ability_pilfer_dweomer)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA *paf, *paf_next;
	int paf_type, diceroll, count, cls;

	push_call("ability_pilfer_dweomer(%p,%p,%p,%p)",sn,level,ch,vo);

	if (victim == ch)
	{
		if ((victim = who_fighting(ch)) == NULL)
		{
			act("You cannot steal your own magic.", ch, NULL, NULL, TO_CHAR);
			pop_call();
			return FALSE;
		}
	}
	
	// snarf arcane casting class for mana
	for (cls = 0 ; cls < MAX_CLASS ; cls++)
	{
		if (!class_level(ch, cls))
			continue;
		if (class_table[cls].mana_table != MANA_NONE)
			continue;
		if (class_table[cls].attr_prime != APPLY_INT
		|| class_table[cls].attr_prime != APPLY_CHA)
			continue;
		break;
	}
	
	diceroll = dice(1, 20) + level;
	count = 0;
	
	for ( paf_type = 0, paf = victim->first_affect; paf != NULL; paf = paf_next )
	{
		paf_next = paf->next;

		if (!is_spell(paf->type))
			continue;
			
		if (sn == gsn_dispel_magic && IS_SET(paf->bitvector, AFF_CURSE))
			continue;
		
		if (diceroll < 11 + paf->level)
		{
			continue;
		}
	
		if (paf->duration >= 0)
		{
			if (skill_table[paf->type].msg_off)
			{
				act( skill_table[paf->type].msg_off, victim, NULL, NULL, TO_CHAR);
			}
			if (skill_table[paf->type].msg_off_room)
			{
				act( skill_table[paf->type].msg_off_room, victim, NULL, NULL, TO_ROOM);
			}
		}
		paf_type = paf->type;
		ch->mana[cls] += UMAX(1, skill_table[paf->type].native_level * 2 - 1);
		affect_from_char(victim, paf);
		break;
	}
	if (paf_type == 0)
	{
		send_to_char( "You did not succeed in stealing any magic.\n\r", ch );
	}
	pop_call();
	return TRUE;
}


/*
 * Arcane Trickster sneak attack
 */
DO_ABILITY(ability_impromptu_sneak_attack)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	push_call("ability_impromptu_sneak_attack(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if (!in_combat(victim))
	{
		send_to_char( "You are not currently in combat.\n\r", ch );
		pop_call();
		return FALSE;
	}

	act("{108}You prepare to make an impromptu sneak attack.", ch, NULL, victim, TO_CHAR);

	af.type      = sn;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.duration  = -1;
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_to_char( ch, victim, &af );

	pop_call();
	return TRUE;
}

/*
 * Divine Champion Wrath
 */
DO_ABILITY(ability_divine_wrath)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	push_call("ability_divine_wrath(%p,%p,%p,%p)",sn,level,ch,vo);
	
	if (is_affected(ch, sn))
	{
		act("You are already channeling wrath.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	act("{138}You call upon divine wrath!", ch, NULL, victim, TO_CHAR);
	act("{138}$n calls upon divine wrath!", ch, NULL, victim, TO_ROOM);

	af.type      = sn;
	af.location  = APPLY_DR_NONE;
	af.modifier  = learned(ch, gsn_divine_paragon) ? 10 : 5;
	af.duration  = 1 + stat_bonus(FALSE, victim, APPLY_CHA);
	af.bittype   = AFFECT_TO_NONE;
	af.bitvector = AFF_NONE;
	affect_join( ch, victim, &af );

	pop_call();
	return TRUE;
}

/*
 * Community domain power - Kregor
 */
DO_ABILITY(ability_divine_refuge)
{
	CHAR_DATA *vch, *vch_next;
	AFFECT_DATA af;

	push_call("ability_divine_refuge(%p,%p,%p,%p)",sn,level,ch,vo);
	
	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 (IS_AFFECTED(vch, AFF_SANCTUARY))
			continue;

		if (in_combat(vch))
			char_from_combat(vch);
			
		af.type      = gsn_sanctuary;
		af.duration  = level;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bittype   = AFFECT_TO_CHAR;
		af.bitvector = AFF_SANCTUARY;
		af.level     = level;
		affect_to_char( ch, vch, &af );

		act( "{178}$n is surrounded by a white aura.", vch, NULL, NULL, TO_ROOM );
		act( "{178}You are surrounded by a white aura.", vch, NULL, NULL, TO_CHAR );
	}
	pop_call();
	return TRUE;
}	

/*
 * Halfling Slinger signature ability - Kregor
 */
DO_ABILITY(ability_skip_rock)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	CHAR_DATA *vch, *vch_next;
	OBJ_DATA *ammo, *wield;
	int diceroll, hit_mod, dam, cnt, dt, threat;

	push_call("ability_skip_rock(%p,%p,%p,%p)",sn,level,ch,vo);

	if ((wield = get_wield(ch, FALSE)) == NULL || !WEAPON_TYPE(wield, WEAPON_TYPE_SLING))
	{
		act("You are not wielding a sling.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}
	
	if ((ammo = get_ammo(ch, wield)) == NULL)
	{
		act("You cannot find any ammo for that weapon.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return FALSE;
	}

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

	hit_mod = 0;

	if (diceroll == 1 && !WEAPON_FLAG(ammo, WFLAG_SEEKING))
		ch_printf_color(ch, "{118}Critical miss!\n\r");
	
	threat = weapon_table[wield->value[0]].threat;

	if (IS_SET(weapon_skill(ch, wield), WSKILL_IMP_CRITICAL))
	{
		threat = (20 - threat) * 2;
		threat = 20 - threat;
	}
	if (diceroll == 20 || diceroll >= threat)
	{
		if (check_hit(ch, victim, dice(1,20), hit_mod, dt, wield, FALSE, TRUE)
		|| learned(ch, gsn_dead_shot))
		{
			CRIT = 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, wield, FALSE, TRUE))
	{
		act( "$p whistles past $N.", ch, ammo, victim, TO_NOTVICT );
		act( "$p whistles past you.", ch, ammo, victim, TO_VICT );
		act( "$p whistles past $N.", ch, ammo, victim, TO_ROOM );
		pop_call();
		return TRUE;
	}
	else
	{
		dam = GET_DAMROLL(ch, victim, dt, wield);
				
		if (CRIT && CAN_CRITICAL(victim) && (!is_affected(victim, gsn_defensive_stance) || !learned(victim, gsn_impenetrable_defense)))
			dam *= weapon_table[ammo->value[0]].critical;

		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;
		}
		else
		{
			pop_call();
			return TRUE;
		}
	}

	// Here's where the rock ricochets!
	for (cnt = 0, vch = victim->in_room->first_person ; vch ; vch = vch_next)
	{
		vch_next = vch->next_in_room;

		if (!can_mass_attack(ch, vch))
			continue;
			
		if (!is_same_group(victim, vch))
			continue;
			
		if (vch == victim)
			continue;
			
		diceroll = dice(1,20);

		hit_mod = 0 - 2 - cnt * 2;
	
		if (!WEAPON_FLAG(ammo, WFLAG_SEEKING) && diceroll != 20 && !check_hit(ch, vch, diceroll, hit_mod, dt, wield, FALSE, TRUE))
		{
			act( "$p whistles past $N.", ch, ammo, vch, TO_NOTVICT );
			act( "$p whistles past you.", ch, ammo, vch, TO_VICT );
			act( "$p whistles past $N.", ch, ammo, vch, TO_ROOM );
			break;
		}
		else
		{
			dam = GET_DAMROLL(ch, vch, dt, wield);
					
			act( "$p ricochets toward $N.", ch, ammo, vch, TO_NOTVICT );
			act( "$p ricochets toward you!", ch, ammo, vch, TO_VICT );
			act( "$p ricochets toward $N.", ch, ammo, vch, TO_CHAR );
	
			if (!deflect_missile(vch, ch, ammo, -1))
			{
				damage(ch, vch, dam, dt, ammo);
			}
			else
			{
				break;
			}
		}
		if (cnt++ >= level)
			break;
	}
	if (ammo)
	{
		junk_obj(ammo);
	}
	TAKE_ACTION(ch, ACTION_STANDARD);
	pop_call();
	return TRUE;
}