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.     *
 ***************************************************************************/
 /**************************************************************************
  * Crafting.c is a system coded from the ground up by Kregor for the      *
  * Mud20 system. It is based on PnP crafting rules from the Open Gaming   *
  * System, and also draws some inspiration from the Neverwinter Nights    *
  * crafting system by Vulcano for how to rest and pause between sessions. *
  **************************************************************************/
 
#include "mud.h"

bool check_components		args((CHAR_DATA *ch, int sn, bool fCast));

char * const  craft_armor_types [] =
{
	"cloth",
	"padded",
	"leather",
	"studded",
	"elven",
	"hide",
	"scalemail",	
	"chainmail",
	"splint",
	"banded",
	"plate",
	"@",
	"@",
	"@",
	"@",
	"*"
};

char * const  craft_shield_types [] =
{
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",	
	"@",
	"@",
	"@",
	"@",
	"@",
	"buckler",
	"light",
	"heavy",
	"tower",
	"*"
};

char *  const   armor_locs [] =
{
	"@",
	"@",
	"head",
	"face",
	"@",
	"neck",
	"arms",
	"@",
	"hands",
	"@",
	"body",
	"@",
	"@",
	"waist",
	"@",	
	"legs",
	"@",
	"feet",
	"shield",
	"@",
	"@",
	"@",
	"@",
	"*"
};

/*
 * Required spell for adding effect to item using do_enchant - Kregor
 */
char *  const   craft_apply_spells [] =
{
	"",
	"bulls strength",
	"cats grace",
	"foxs cunning",
	"owls wisdom",
	"bears endurance",
	"eagles splendor",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"shield of faith",
	"haste",
	"shield",
	"armor",
	"guidance",
	"true strike",
	"",
	"bears endurance",
	"haste",
	"aid",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"prayer",
	"",
	"",
	"",
	"",
	"",
	"prayer",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"barkskin",
	"protection from good",
	"protection from evil",
	"protection from law",
	"protection from chaos",
	"resistance",
	"protection from spells",
	"",
	"",
	"spider climb",
	"",
	"",
	"",
	"detect traps",
	"disguise self",
	"",
	"",
	"",
	"",
	"",
	"leap",
	"clairvoyance",
	"",
	"knock",
	"",
	"",
	"invisibility",
	"",
	"",
	"",
	"clairvoyance",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"resist elements",
	"resist elements",
	"resist elements",
	"resist elements",
	"resist elements",
	"spell resistance",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"death ward",
	"remove disease",
	"",
	"",
	"",
	"remove fear",
	"",
	"",
	"",
	"",
	"",
	"",
	"",
	"mind blank",
	"death ward",
	"",
	"",
	"slow poison",
	"",
	"",
	"vigilance",
	"",
	"",
	"protection from energy",
	"",
	"",
	"",
	"protection from energy",
	"",
	"",
	"undeaths eternal foe",
	"remove disease",
	"",
	"protection from energy",
	"",
	"remove fear",
	"protection from energy",
	"",
	"",
	"",
	"",
	"",
	"",
	"mind immunity",
	"death ward",
	"",
	"",
	"remove poison",
	"",
	"",
	"",
	"protection from energy",
	"",
	"",
	"",
	"",
	"",
	"",
	"regeneration",
	"",
	"darkvision",
	"",
	"displacement",
	"stone body",
	"",
	"",
	"",
	""
};


/*
 * available apply locations for do_enchant - Kregor
 */
char *  const   craft_applies [] =
{
	"none",
	"str",
	"dex",
	"int",
	"wis",
	"con",
	"cha",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"deflection",
	"dodge",
	"shield",
	"armor",
	"skills",
	"hitroll",
	"@",
	"fortitude",
	"reflex",
	"will",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"luck skills",
	"@",
	"@",
	"@",
	"@",
	"@",
	"luck saves",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"natural ac",
	"protection good",
	"protection evil",
	"protection law",
	"protection chaos",
	"saves",
	"save vs spell",
	"@",
	"@",
	"climb",
	"@",
	"@",
	"@",
	"disable device",
	"disguise",
	"@",
	"@",
	"@",
	"@",
	"@",
	"jump",
	"listen",
	"@",
	"open lock",
	"@",
	"@",
	"stealth",
	"@",
	"@",
	"@",
	"sight",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"acid resist",
	"cold resist",
	"electric resist",
	"fire resist",
	"sonic resist",
	"spell resistance",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"save vs death",
	"save vs disease",
	"@",
	"@",
	"@",
	"save vs fear",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"save vs mind",
	"save vs negative",
	"@",
	"@",
	"save vs poison",
	"@",
	"@",
	"save vs sleep",
	"@",
	"@",
	"acid immunity",
	"@",
	"@",
	"@",
	"cold immunity",
	"@",
	"@",
	"death immunity",
	"disease immunity",
	"@",
	"electric immunity",
	"@",
	"fear immunity",
	"fire immunity",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"mind immunity",
	"negative immunity",
	"@",
	"@",
	"poison immunity",
	"@",
	"@",
	"@",
	"sonic immunity",
	"@",
	"@",
	"@",
	"@",
	"@",
	"@",
	"regeneration",
	"@",
	"darkvision",
	"@",
	"concealment",
	"fortification",
	"@",
	"@",
	"@",
	"*"
};


/*
 * Get the flag for a weapon type to craft.
 * pass optional trade skill type - Kregor
 */
int craft_weapon_flag(char *argument, sh_int type)
{
	int cnt;
	
	push_call("craft_weapon_flag()");
	
	for (cnt = 0 ; cnt < WEAPON_TYPE_MAX ; cnt++)
	{
		if (!strcasecmp(argument, weapon_table[cnt].name))
		{
			if (!type || weapon_table[cnt].craft_skill == type)
			{
				pop_call();
				return cnt;
			}
		}
	}
	pop_call();
	return -1;
}


/*
 * requisite spells for affects on do_enchant - Kregor
 */
int craft_effect_spell( int flag )
{
	int sn = -1;

	push_call("craft_effect_spell()");
	
	switch(flag)
	{
		case AFF_INVISIBLE:
			sn = gsn_invis;
			break;
		case AFF_DETECT_INVIS:
			sn = gsn_detect_invis;
			break;
		case AFF_FREEDOM:
			sn = gsn_freedom_of_movement;
			break;
		case AFF_IMMUNE_SPELL:
			sn = gsn_spell_immunity;
			break;
		case AFF_DETECT_HIDDEN:
			sn = gsn_detect_secret;
			break;
		case AFF_UNDERSTAND:
			sn = gsn_comprehend_languages;
			break;
		case AFF_DETECT_TRAPS:
			sn = gsn_detect_traps;
			break;
		case AFF_TRUESIGHT:
			sn = gsn_true_seeing;
			break;
		case AFF_TONGUES:
			sn = gsn_tongues;
			break;
		case AFF_HASTE:
			sn = gsn_haste;
			break;
		case AFF_NONDETECTION:
			sn = gsn_nondetection;
			break;
		case AFF_WATER_BREATH:
			sn = gsn_water_breathing;
			break;
		case AFF_WATER_WALK:
			sn = gsn_water_walk;
			break;
	}
	pop_call();
	return sn;
}

	
/*
 * get available effect flags for do_enchant - Kregor
 */
int craft_effect_flag( char *argument )
{
	int flag = -1;
	
	push_call("craft_effect_flag()");
	
	if (!strcasecmp(argument, "invisibility"))
		flag = AFF_INVISIBLE;
	else if (!strcasecmp(argument, "detect invis"))
		flag = AFF_DETECT_INVIS;
	else if (!strcasecmp(argument, "freedom"))
		flag = AFF_FREEDOM;
	else if (!strcasecmp(argument, "spell immunity"))
		flag = AFF_IMMUNE_SPELL;
	else if (!strcasecmp(argument, "detect hidden"))
		flag = AFF_DETECT_HIDDEN;
	else if (!strcasecmp(argument, "comprehend languages"))
		flag = AFF_UNDERSTAND;
	else if (!strcasecmp(argument, "detect traps"))
		flag = AFF_DETECT_TRAPS;
	else if (!strcasecmp(argument, "true seeing"))
		flag = AFF_TRUESIGHT;
	else if (!strcasecmp(argument, "tongues"))
		flag = AFF_TONGUES;
	else if (!strcasecmp(argument, "haste"))
		flag = AFF_HASTE;
	else if (!strcasecmp(argument, "nondetection"))
		flag = AFF_NONDETECTION;
	else if (!strcasecmp(argument, "water breathing"))
		flag = AFF_WATER_BREATH;
	else if (!strcasecmp(argument, "water walking"))
		flag = AFF_WATER_WALK;
	else
		flag = -1;

	pop_call();
	return flag;
}


/*
 * requisite spells for armor flags - Kregor
 */
int armor_flag_spell( int flag )
{
	int sn = -1;

	push_call("treasure_flag_spell()");
	
	switch(flag)
	{
		case ARMORFLAG_ARROW_DEFLECTION:
			sn = gsn_deflect_arrows;
			break;
		case ARMORFLAG_BASHING:
			sn = gsn_bulls_strength;
			break;
		case ARMORFLAG_GHOST_TOUCH:
			sn = gsn_ethereal;
			break;
		case ARMORFLAG_REFLECTING:
			sn = gsn_spell_turning;
			break;
		case ARMORFLAG_WILD:
			sn = gsn_beast_shape;
			break;
	}
	pop_call();
	return sn;
}	

/*
 * get available armor flags in do_enchant - Kregor
 */
int get_armor_flag( char *argument )
{
	int flag = -1;
	
	push_call("get_armor_flag()");
	
	if (!strcasecmp(argument, "arrow deflection"))
		flag = ARMORFLAG_ARROW_DEFLECTION;
	if (!strcasecmp(argument, "bashing"))
		flag = ARMORFLAG_BASHING;
	if (!strcasecmp(argument, "ghost touch"))
		flag = ARMORFLAG_GHOST_TOUCH;
	if (!strcasecmp(argument, "reflecting"))
		flag = ARMORFLAG_REFLECTING;
	if (!strcasecmp(argument, "wild"))
		flag = ARMORFLAG_WILD;

	pop_call();
	return flag;
}

/*
 * requisite spells for weapon flags in do_enchant - Kregor
 */
char * weapon_flag_spells [] =
{
	"chaos hammer",
	"orders wrath",
	"",	
	"heal",
	"clairvoyance",
	"flame blade",
	"fireball",
	"chill metal",
	"etherealness",
	"holy smite",
	"ice storm",
	"keen edge",
	"",
	"cure light",
	"",
	"true strike",
	"shocking grasp",
	"call lightning",
	"haste",
	"",
	"shout",
	"",
	"unholy blight",
	"poison",
	"enervation",
	"vampiric touch",
	"circle of death",
	"keen edge",
	"",
	"acid arrow"
};

/*
 * get weapon flags for do_enchant - Kregor
 */
int get_weapon_flag( char *argument )
{
	push_call("get_weapon_flag()");
	
	pop_call();
	return get_flag(argument, weapon_flags);
}


/*
 * Certain applies are only useable on certain
 * wear locations. This returns whether the apply
 * is suitable for the item or not - Kregor
 */
int body_affinities( int location )
{
	int wear_loc;

	push_call("body_affinities()");
	
	switch (location)
	{
		case APPLY_INT:
		case APPLY_DISGUISE:
			wear_loc = CAN_WEAR_HEAD;
			break;

		case APPLY_WIS:
			wear_loc = CAN_WEAR_HEAD|CAN_WEAR_NECK;
			break;

		case APPLY_COMP_TOHIT:
			wear_loc = CAN_WEAR_FACE|CAN_WEAR_HANDS;
			break;
			
		case APPLY_SIGHT:	
		case APPLY_DARKVISION:
			wear_loc = CAN_WEAR_FACE;
			break;
			
		case APPLY_CHA:
		case APPLY_SAVE_DEATH:
		case APPLY_SAVE_DISEASE:
		case APPLY_SAVE_FEAR:
		case APPLY_SAVE_MIND:
		case APPLY_SAVE_NEGATIVE:
		case APPLY_SAVE_POISON:
		case APPLY_SAVE_SLEEP:
		case APPLY_IMM_ACID:
		case APPLY_IMM_COLD:
		case APPLY_IMM_DEATH:
		case APPLY_IMM_DISEASE:
		case APPLY_IMM_ELECTRIC:
		case APPLY_IMM_FEAR:
		case APPLY_IMM_FIRE:
		case APPLY_IMM_MIND:
		case APPLY_IMM_NEGATIVE:
		case APPLY_IMM_POISON:	
		case APPLY_IMM_SONIC:
			wear_loc = CAN_WEAR_WRIST|CAN_WEAR_NECK;
			break;
			
		case APPLY_STR:
		case APPLY_CON:
			wear_loc = CAN_WEAR_WAIST|CAN_WEAR_HANDS;
			break;
			
		case APPLY_DEFLECT:
			wear_loc = CAN_WEAR_ABOUT;
			break;
			
		case APPLY_COMP_REFL:
		case APPLY_DODGE:
		case APPLY_JUMP:
		case APPLY_CLIMB:
			wear_loc = CAN_WEAR_FEET;
			break;

		case APPLY_RES_GOOD:
		case APPLY_RES_EVIL:
		case APPLY_RES_LAW:
		case APPLY_RES_CHAOS:
		case APPLY_RES_SAVES:
		case APPLY_RES_SPELL:
		case APPLY_DR_ACID:
		case APPLY_DR_COLD:
		case APPLY_DR_ELECTRIC:
		case APPLY_DR_FIRE:
		case APPLY_DR_SONIC:
		case APPLY_SPELL_RES:
		case APPLY_LUCK_SKILL:
		case APPLY_LUCK_SAVES:
		case APPLY_STEALTH:
		case APPLY_CONCEALMENT:
			wear_loc = CAN_WEAR_NECK|CAN_WEAR_ABOUT;
			break;
			
		case APPLY_FORTIFICATION:
			wear_loc = CAN_WEAR_BODY|CAN_WEAR_ABOUT;
			break;
			
		case APPLY_COMP_FORT:
		case APPLY_COMP_WILL:
		case APPLY_SHIELD:
		case APPLY_NATURAL_AC:
			wear_loc = CAN_WEAR_NECK;
			break;
			
		case APPLY_OPEN_LOCK:
		case APPLY_DISABLE:
		case APPLY_ARMOR:
		case APPLY_DEX:
		case APPLY_COMP_SKILL:
			wear_loc = CAN_WEAR_HANDS;
			break;
	}
	// any apply is available on a ring
	SET_BIT(wear_loc, CAN_WEAR_FINGER|CAN_WEAR_BODY|CAN_WEAR_FLOAT);
	
	pop_call();
	return wear_loc;
}


/*
 * Limit the maximum bonus for an apply - Kregor
 */
int mod_max( int apply, int level )
{
	int bonus;

	push_call("body_affinities()");
	
	switch (level)
	{
		case APPLY_CHA:
		case APPLY_CON:
		case APPLY_DEX:
		case APPLY_INT:
		case APPLY_STR:
		case APPLY_WIS:
			bonus = UMIN(level/2, 6);
			break;

		case APPLY_DARKVISION:
			bonus = UMIN(level / 5 * 30, 120);
			break;


		case APPLY_IMM_ACID:
		case APPLY_IMM_COLD:
		case APPLY_IMM_DEATH:
		case APPLY_IMM_DISEASE:
		case APPLY_IMM_ELECTRIC:
		case APPLY_IMM_FEAR:
		case APPLY_IMM_FIRE:
		case APPLY_IMM_MIND:
		case APPLY_IMM_NEGATIVE:
		case APPLY_IMM_POISON:	
		case APPLY_IMM_SONIC:
			bonus = 1;
			break;

		case APPLY_COMP_TOHIT:
		case APPLY_RES_GOOD:
		case APPLY_RES_EVIL:
		case APPLY_RES_LAW:
		case APPLY_RES_CHAOS:
		case APPLY_RES_SAVES:
		case APPLY_RES_SPELL:
		case APPLY_LUCK_SKILL:
		case APPLY_LUCK_SAVES:
		case APPLY_COMP_FORT:
		case APPLY_COMP_REFL:
		case APPLY_COMP_WILL:
		case APPLY_COMP_SKILL:
			bonus = UMIN(level/2, 5);
			break;

		case APPLY_CLIMB:
		case APPLY_DISABLE:
		case APPLY_DISGUISE:
		case APPLY_JUMP:
		case APPLY_OPEN_LOCK:
		case APPLY_SIGHT:	
		case APPLY_STEALTH:
		case APPLY_SAVE_DEATH:
		case APPLY_SAVE_DISEASE:
		case APPLY_SAVE_FEAR:
		case APPLY_SAVE_MIND:
		case APPLY_SAVE_NEGATIVE:
		case APPLY_SAVE_POISON:
		case APPLY_SAVE_SLEEP:
			bonus = UMIN(level/2, 10);
			break;

		case APPLY_DR_ACID:
		case APPLY_DR_COLD:
		case APPLY_DR_ELECTRIC:
		case APPLY_DR_FIRE:
		case APPLY_DR_SONIC:
			bonus = UMIN(level/2, 20);
			break;

		case APPLY_SPELL_RES:
			bonus = level / 2 + 12;
			break;

		case APPLY_CONCEALMENT:
			bonus = level * 5 / 2;
			break;

		case APPLY_FORTIFICATION:
			bonus = level * 5;
			break;

		case APPLY_DEFLECT:
		case APPLY_DODGE:
		case APPLY_SHIELD:
		case APPLY_NATURAL_AC:
		case APPLY_ARMOR:
			bonus = UMIN(level/2, 8);
			break;

		default:
			bonus = UMIN(level/2, 5);
			break;
	}	
	pop_call();
	return bonus;
}


/* Up to five components can be set for crafting of
 * a specific weapon or type of armor. Crafter must
 * have these in inventory to create the initial craft - Kregor
 */
const	struct	ingredient_type	weapon_ingredients [WEAPON_TYPE_MAX] =
{
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	}			
};							

const	struct	ingredient_type	armor_ingredients [MAX_ARMOR_TYPE] =
{
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	},			
	{	{COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE, 		COMP_NONE}	}			
};							

/*
 * Hack of check_components for use in crafting with ingredients - Kregor 8/23/10
 */
bool check_ingredients( CHAR_DATA *ch, int sn, int type, bool ForReal )
{
	OBJ_DATA *ingredient;
	int cnt, comp;
	bool found;
	
	push_call("check_ingredients(%p,%p,%p)",ch,sn,ForReal);

	if (sn <= 0)
	{
		pop_call();
		return TRUE;
	}
	
	// imms and npcs don't need ingredients
	if (IS_NPC(ch) || IS_IMMORTAL(ch))
	{
		pop_call();
		return TRUE;
	}
	
	for (found = TRUE, cnt = 0 ; cnt < 5 ; cnt++)
	{
		ingredient = NULL;
		
		if (sn == gsn_craft_weapons)
		{
			if ((comp = weapon_ingredients[type].ingredient[cnt]) <= 0) // if ingredient is null, go no further
				continue;
		}
		else if (sn == gsn_craft_armor)
		{
			if ((comp = armor_ingredients[type].ingredient[cnt]) <= 0) // if ingredient is null, go no further
				continue;
		}
		else
			break;
			
		if (!is_string(component_table[comp].name))
		{
			bug("check_ingredients: %s bad ingredient type %d", skill_table[sn].name, comp);
			pop_call();
			return FALSE;
		}

		for (ingredient = ch->first_carrying ; ingredient ; ingredient = ingredient->next_content)
		{
			if (ingredient->item_type == ITEM_COMPONENT && comp == ingredient->value[0])
			{
				break;
			}
		} 
		if (ingredient == NULL)
		{
			ch_printf_color(ch, "You are missing your %s.\n\r", component_table[comp].name);
			found = FALSE;
			continue;
		}
		if (ForReal && --ingredient->value[1] <= 0)
		{
			act("You use up $p.", ch, NULL, NULL, TO_CHAR);
			act("$n uses up $p.", ch, NULL, NULL, TO_ROOM);
			junk_obj(ingredient);
		}
	}
	pop_call();
	return found;
}

/*
 * check to see if in proper workshop for crafting - Kregor
 */
bool check_workshop(CHAR_DATA *ch, int sn, int type)
{
	OBJ_DATA *obj;
	bool found = TRUE;

	push_call("check_workshop(%p,%p,%p)",ch,sn,type);
	
	if (IS_NPC(ch) || IS_IMMORTAL(ch))
	{
		pop_call();
		return TRUE;
	}
	
	if ((sn == gsn_craft_armor && armor_table[type].material == MATERIAL_TYPE_METAL)
	|| (sn == gsn_craft_weapons && weapon_table[type].material == MATERIAL_TYPE_METAL))
	{
		for (obj = ch->in_room->first_content ; obj != NULL ; obj = obj->next_content)
		{
			if (TOOL_TYPE(obj, TOOL_ANVIL))
				break;
		}
		if (obj == NULL)
		{
			send_to_char("There is no anvil here.\n\r", ch);
			found = FALSE;
		}
		for (obj = ch->in_room->first_content ; obj != NULL ; obj = obj->next_content)
		{
			if (TOOL_TYPE(obj, TOOL_FURNACE))
				break;
		}
		if (obj == NULL)
		{
			send_to_char("There is no furnace here.\n\r", ch);
			found = FALSE;
		}
	}
	if (sn == gsn_craft_weapons && IS_SET(weapon_table[type].weap_spec, WSPEC_WOODEN_HAFTED))
	{
		for (obj = ch->in_room->first_content ; obj != NULL ; obj = obj->next_content)
		{
			if (TOOL_TYPE(obj, TOOL_LATHE))
				break;
		}
		if (obj == NULL)
		{
			send_to_char("You need a lathe to hone your weapon.\n\r", ch);
			found = FALSE;
		}
	}
	pop_call();
	return found;
}
	

/*
 * check for crafting tool held - Kregor
 */
bool check_tools(CHAR_DATA *ch, int tool, bool ForReal)
{
	OBJ_DATA *tools;

	push_call("check_tools(%p,%p,%p)",ch,tool,ForReal);
	
	if (IS_NPC(ch) || IS_IMMORTAL(ch))
	{
		pop_call();
		return TRUE;
	}
	
	if ((tools = get_obj_wear_type(ch, ITEM_TOOLS)) == NULL || TOOL_TYPE(tools, tool))
	{
		ch_printf_color(ch, "You lack the proper tools.\n\r");
		pop_call();
		return FALSE;
	}
	
	if (ForReal)
	{
		if (--tools->value[1] <= 0)
		{
			act("$p are worn out from use.", ch, tools, NULL, TO_CHAR);
			junk_obj(tools);
		}
	}

	pop_call();
	return TRUE;
}
	

void do_craft_poison( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	OBJ_DATA  *obj;
	POISON_DATA pd;
	int roll, poison, dc;

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

	if (IS_NPC(ch) || !learned(ch, gsn_craft_poison))
	{
		send_to_char( "You do not know the art of poison crafting.\n\r", ch );
		pop_call();
		return;
	}

	for (obj = ch->first_carrying ; obj ; obj = obj->next_content)
	{
		if (!IS_OBJ_TYPE(obj, ITEM_POTION))
			continue;
		if (obj->value[0] == 0)
			break;
	}

	if (!obj)
	{
		send_to_char("You need an empty potion vial to hold your poison.\n\r",ch);
		pop_call();
		return;
	}

	if (obj->poison != NULL)
	{
		send_to_char( "That vial already contains poison.\n\r", ch );
		pop_call();
		return;
	}

	/*
	 * For testing purposes, this is just an argument to
	 * get a poison flag, ultimately, will want poison
	 * components to distill from - Kregor
	 */
	one_argument( argument, arg1 );

	if (arg1[0] == '\0')
	{
		send_to_char( "Craft what type of poison?\n\r", ch );
		pop_call();
		return;
	}
	
	if ((poison = get_flag(arg1, poison_names)) == -1)
	{
		send_to_char( "That is not a type of poison.\n\r", ch );
		pop_call();
		return;
	}
		
	if (!ch->concentrating)
	{
		if (!check_ingredients(ch, gsn_craft_poison, poison, FALSE))
		{
			pop_call();
			return;
		}
		act( "You set to crafting poison from $t...", ch, poison_table[poison].name, NULL, TO_CHAR);
		act( "$n sets to crafting poison from $t...", ch, poison_table[poison].name, NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= 16;
		ch->timer_fun			= do_craft_poison;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}
	
	if (!check_ingredients(ch, gsn_craft_poison, poison, TRUE))
	{
		pop_call();
		return;
	}
	
	roll = craft_poison_roll(ch);
	dc = poison_table[poison].dc;

	if (!learned(ch, gsn_poison_use) && roll <= dc - 10)
	{
		act( "$n tries to craft a poison and makes a mess.", ch, NULL, NULL, TO_ROOM );
		act( "You try to craft a poison and make a mess.",   ch, NULL, NULL, TO_CHAR );
		send_to_char_color( "{128}You poison yourself!\n\r", ch );

		pd.type				= poison;
		pd.constant_duration	= dc - roll;
		pd.owner			= IS_NPC(ch) ? 0 : ch->pcdata->pvnum;
		pd.poisoner		= IS_NPC(ch) ? 0 : ch->pcdata->pvnum;
		pd.dc					= poison_table[poison].dc;
		poison_to_char(ch, ch, &pd);

		pop_call();
		return;
	}
	if (roll < dc)
	{
		act( "$n tries to craft a poison and makes a mess.", ch, NULL, NULL, TO_ROOM );
		act( "You try to craft a poison and make a mess.",   ch, NULL, NULL, TO_CHAR );
		pop_call();
		return;
	}

	ch_printf_color(ch, "{128}You make a vial of poison from %s.\n\r", poison_table[poison].name);
	act( "{128}$n makes a vial of $t poison.", ch, poison_table[poison].name, NULL, TO_ROOM);
	cat_sprintf(obj->name, " poison %s", poison_table[poison].name);
	
	gain_favor(ch, DOMAIN_ARTIFICE, 2);

	pd.type				= poison;
	pd.constant_duration	= -1;
	pd.owner			= IS_NPC(ch) ? 0 : ch->pcdata->pvnum;
	pd.poisoner		= IS_NPC(ch) ? 0 : ch->pcdata->pvnum;
	pd.dc					= poison_table[poison].dc;
	poison_to_obj(ch, obj, &pd);

	pop_call();
	return;
}

void craft_alchemy( CHAR_DATA *ch, char *argument )
{

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

	send_to_char( "Alchemy is currently under development once in place, you'll be able\n\r", ch );
	send_to_char( "to make cool things, like acid, antitoxin, and tanglefoot bags!\n\r", ch );

	if (!IS_NPC(ch) && !learned(ch, gsn_craft_alchemy))
	{
		send_to_char( "You never learned this craft.\n\r", ch );
		pop_call();
		return;
	}

	if (argument[0] == '\0')
	{
		send_to_char( "Craft what alchemical substance?\n\r", ch );
		send_to_char( "    acid, alchemist fire, smokestick, antitoxin,\n\r", ch );
		send_to_char( "    sunrod, tanglefoot bag, thunderstone?\n\r", ch );
		pop_call();
		return;
	}
	else if (!strcasecmp(argument, "acid"))
	{
		send_to_char( "This will invoke a vial of acid\n\r", ch );
		pop_call();
		return;
	}
	else if (!strcasecmp(argument, "alchemist fire"))
	{
		send_to_char( "This will invoke a vial of alchemist fire\n\r", ch );
		pop_call();
		return;
	}
	else if (!strcasecmp(argument, "smokestick"))
	{
		send_to_char( "This will invoke a smokestick\n\r", ch );
		pop_call();
		return;
	}
	else if (!strcasecmp(argument, "antitoxin"))
	{
		send_to_char( "This will invoke a vial of antitoxin\n\r", ch );
		pop_call();
		return;
	}
	else if (!strcasecmp(argument, "sunrod"))
	{
		send_to_char( "This will invoke a sunrod\n\r", ch );
		pop_call();
		return;
	}
	else if (!strcasecmp(argument, "tanglefoot bag"))
	{
		send_to_char( "This will invoke a tanglefoot bag\n\r", ch );
		pop_call();
		return;
	}
	else if (!strcasecmp(argument, "thunderstone"))
	{
		send_to_char( "This will invoke a thunderstone\n\r", ch );
		pop_call();
		return;
	}
	else
	{
		send_to_char( "Craft what alchemical substance?\n\r", ch );
		send_to_char( "    acid, alchemist fire, smokestick, antitoxin,\n\r", ch );
		send_to_char( "    sunrod, tanglefoot bag, thunderstone?\n\r", ch );
		pop_call();
		return;
	}

	gain_favor(ch, DOMAIN_ARTIFICE, 2);

	pop_call();
	return;
}


void do_craft_wand(CHAR_DATA *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	OBJ_DATA *wand;
	int sn, level, circle, value, class, mana;
	
	push_call("do_craft_wand(%p,%p)",ch,argument);
	
	if (IS_NPC(ch))
	{
		send_to_char( "You can't do that!\n\r", ch);
		pop_call();
		return;
	}

	if (!learned(ch, gsn_craft_wand))
	{
		ch_printf(ch, "You do not know how to create magic wands.\n\r");
		pop_call();
		return;
	}
	
	if (ch->uses[gsn_craft_wand])
	{
		ch_printf(ch, "You cannot create a wand today. Maybe after you've rested.\n\r");
		pop_call();
		return;
	}
	
	if (argument[0] =='\0')
	{
		send_to_char("Syntax: craft wand <'spell name'>\n\r", ch);
		pop_call();
		return;
	}
	
	// look for blank wand in inventory
	for (wand = ch->first_carrying ; wand ; wand = wand->next_content)
	{
		if (!IS_OBJ_TYPE(wand, ITEM_WAND))
			continue;
		if (wand->value[2] == 0)
			break;
	}

	if (!wand)
	{
		send_to_char("You do not have a wand in your inventory.\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument(argument, arg);

	if ((sn = skill_lookup(arg)) < 0 || !is_spell(sn))
	{
		send_to_char( "That is not a spell.\n\r", ch );
		pop_call();
		return;
	}
	if (!learned(ch, sn))
	{
		send_to_char( "You don't know that spell.\n\r", ch );
		pop_call();
		return;
	}
	
	if ((class = prepared(ch, sn)) == -1)
	{
		if ((class = spontaneous_cast(ch, sn)) == -1)
		{
			send_to_char( "You have to prepare that spell.\n\r", ch );
			pop_call();
			return;
		}
	}
	
	level = class_level(ch, class);

	if ((circle = circle_by_class(ch, sn, class)) > 4)
	{
		send_to_char( "You can only make wands of 4th circle spells or lower.\n\r", ch );
		pop_call();
		return;
	}

	value = level * circle * 37500;
	
	if (ch->gold + ch->pcdata->bank < value)
	{
		send_to_char( "You don't have enough gold to craft that wand.\n\r", ch );
		pop_call();
		return;
	}

	if (!check_workshop(ch, gsn_craft_wand, -1))
	{
		pop_call();
		return;
	}
	
	if ((mana = get_mana(ch, sn, circle, class) * 5) > ch->mana[class])
	{
		act("You do not have enough mana to imbue that spell.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (!ch->concentrating)
	{
		if (!check_components(ch, sn, FALSE))
		{
			pop_call();
			return;
		}
		act( "You set to enchanting $p", ch, wand, NULL, TO_CHAR);
		act( "$n sets to enchanting $p", ch, wand, NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= dice(4,8);
		ch->timer_fun			= do_craft_wand;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}
	
	if (!check_components(ch, sn, TRUE))
	{
		pop_call();
		return;
	}

	ch->mana[class] -= mana;
	ch->uses[gsn_craft_wand]++;

	// dc per SRD
	if (!spellcraft_check(ch, NULL, sn, spellcraft_roll(ch), 5+level))
	{
		act("You fail to craft $p properly.", ch, wand, NULL, TO_CHAR);
		gold_transaction(ch, 0 - value / 5);
	}
	else
	{
		wand->value[0] = level;
		wand->value[3] = sn;
		wand->value[1] = wand->value[2] = 50;
		act("You craft a wand of $t.", ch, skill_table[sn].name, NULL, TO_CHAR);
		gold_transaction(ch, 0 - value);
		gain_favor(ch, DOMAIN_ARTIFICE, 2);
		gain_favor(ch, DOMAIN_MAGIC, 1);
	}

	act("$n finishes crafting.", ch, NULL, NULL, TO_ROOM);

	pop_call();
	return;
}


void do_craft_staff(CHAR_DATA *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	OBJ_DATA *staff;
	int sn, level, circle, value, count, class, cnt, mana;
	bool recharge = FALSE;
	
	push_call("do_craft_staff(%p,%p)",ch,argument);
	
	if (IS_NPC(ch))
	{
		send_to_char( "You can't do that!\n\r", ch);
		pop_call();
		return;
	}

	if (!learned(ch, gsn_craft_staff))
	{
		ch_printf(ch, "You do not know how to create magic staves.\n\r");
		pop_call();
		return;
	}
	
	if (ch->uses[gsn_craft_staff])
	{
		ch_printf(ch, "You cannot create a staff today. Maybe after you've rested.\n\r");
		pop_call();
		return;
	}
	
	if (argument[0] =='\0')
	{
		send_to_char("Syntax: craft staff <'spell name'>\n\r", ch);
		pop_call();
		return;
	}
	
	// look for blank staff in inventory
	for (staff = ch->first_carrying ; staff ; staff = staff->next_content)
	{
		if (!IS_OBJ_TYPE(staff, ITEM_WAND))
			continue;
		if (staff->value[2] == 0)
			break;
	}

	if (!staff)
	{
		send_to_char("You do not have a staff in your inventory.\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument(argument, arg);

	if ((sn = skill_lookup(arg)) < 0 || !is_spell(sn))
	{
		send_to_char( "That is not a spell.\n\r", ch );
		pop_call();
		return;
	}
	if (!learned(ch, sn))
	{
		send_to_char( "You don't know that spell.\n\r", ch );
		pop_call();
		return;
	}

	if ((class = prepared(ch, sn)) == -1)
	{
		if ((class = spontaneous_cast(ch, sn)) == -1)
		{
			send_to_char( "You have to prepare that spell.\n\r", ch );
			pop_call();
			return;
		}
	}

	level = class_level(ch, class);
	circle = circle_by_class(ch, sn, class);

	// count empty spell slots on staff
	// if spell already on staff, it's a recharge - Kregor
	for (count = 0, cnt = 3 ; cnt < 7 ; cnt++)
	{
		if (staff->value[cnt] == sn)
			recharge = TRUE;
		if (!is_spell(staff->value[cnt]))
			continue;
		count++;
	}
	
	if (count >= 4 && !recharge)
	{
		act("All the slots for spells on $p are taken.", ch, staff, NULL, TO_CHAR);
		pop_call();
		return;
	}
	
	if (recharge)
	{
		value = level * circle * 37500;
	}
	else
	{
		switch (count)
		{
			case 0:
				value = level * circle * 37500;
				break;
			case 1:
				value = level * circle * 28125;
				break;
			default:
				value = level * circle * 18750;
				break;
		}
	}
	
	if (ch->gold + ch->pcdata->bank < value)
	{
		send_to_char( "You don't have enough gold to craft that staff.\n\r", ch );
		pop_call();
		return;
	}

	if (!check_workshop(ch, gsn_craft_staff, -1))
	{
		pop_call();
		return;
	}
	
	if ((mana = get_mana(ch, sn, circle, class) * 5) > ch->mana[class])
	{
		act("You do not have enough mana to imbue that spell.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (!ch->concentrating)
	{
		if (!check_components(ch, sn, FALSE))
		{
			pop_call();
			return;
		}
		act( "You set to enchanting $p", ch, staff, NULL, TO_CHAR);
		act( "$n sets to enchanting $p", ch, staff, NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= dice(4,8);
		ch->timer_fun			= do_craft_staff;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}
	
	// find first empty slot on staff - Kregor
	for (cnt = 3 ; cnt < 7 ; cnt++)
	{
		if (staff->value[cnt] == sn)
			break;
		if (!is_spell(staff->value[cnt]))
			break;
	}
	
	if (!check_components(ch, sn, TRUE))
	{
		pop_call();
		return;
	}

	ch->mana[class] -= mana;
	ch->uses[gsn_craft_staff]++;

	// dc per SRD
	if (!spellcraft_check(ch, NULL, sn, spellcraft_roll(ch), 5+level))
	{
		act("You fail to craft $p properly.", ch, staff, NULL, TO_CHAR);
		gold_transaction(ch, 0 - value / 5);
	}
	else
	{
		staff->value[0] = level;
		staff->value[cnt] = sn;
		staff->value[1] = staff->value[2] = 50;
		act("You imbue $p with $t.", ch, staff, skill_table[sn].name, TO_CHAR);
		gold_transaction(ch, 0 - value);
		gain_favor(ch, DOMAIN_ARTIFICE, 2);
		gain_favor(ch, DOMAIN_MAGIC, 1);
	}

	act("$n finishes crafting.", ch, NULL, NULL, TO_ROOM);

	pop_call();
	return;
}


void do_craft_weapon(CHAR_DATA *ch, char *argument)
{
	int skill, type, roll, dc;
	OBJ_DATA *craft, *weapon;
	
	push_call("do_craft_weapon(%p,%p)",ch,argument);
	
	if (argument[0] =='\0')
	{
		send_to_char("Syntax: craft weapon <type>\n\r", ch);
		send_to_char("Syntax: craft weapon <object in inventory>\n\r", ch);
		pop_call();
		return;
	}
	
	if ((craft = get_obj_carry(ch, argument)) != NULL)
	{
		// crafting on existing craft piece goes here
		if (!IS_OBJ_TYPE(craft, ITEM_CRAFT))
		{
			send_to_char("That is not a work in progress.\n\r", ch);
			pop_call();
			return;
		}
		if (craft->value[0] != ITEM_WEAPON)
		{
			send_to_char("That is not a weapon.\n\r", ch);
			pop_call();
			return;
		}
		type = craft->value[1];
	}
	else
	{
		if ((type = craft_weapon_flag(argument, TRADE_CRAFT_NONE)) == -1)
		{
			send_to_char("That is not a valid weapon type.", ch);
			pop_call();
			return;
		}
	}
	
	// figure out which trade skill to check
	switch (weapon_table[type].craft_skill)
	{
		case TRADE_CRAFT_WEAPON:
			skill = gsn_craft_weapons;
			break;
		case TRADE_CRAFT_BOW:
			skill = gsn_craft_bows;
			break;
		case TRADE_CRAFT_LEATHER:
			skill = gsn_craft_leather;
			break;
		default:
			send_to_char("You cannot craft that.", ch);
			pop_call();
			return;
	}
	
	if (!learned(ch, skill))
	{
		ch_printf(ch, "You lack the proper trade to do that.\n\r");
		pop_call();
		return;
	}
	
	if (ch->uses[skill])
	{
		ch_printf(ch, "You cannot craft again today; try after you've rested.\n\r");
		pop_call();
		return;
	}
	
	// check for proper tools
	switch (weapon_table[type].craft_skill)
	{
		case TRADE_CRAFT_WEAPON:
			if (weapon_table[type].material == MATERIAL_TYPE_METAL
			&& !check_tools(ch, TOOL_SMITH_TOOLS, TRUE))
			{
				pop_call();
				return;
			}	
			if (weapon_table[type].material == MATERIAL_TYPE_WOOD
			&& !check_tools(ch, TOOL_WOODWORKERS_TOOLS, TRUE))
			{
				pop_call();
				return;
			}	
			break;
		case TRADE_CRAFT_BOW:
			if (!check_tools(ch, TOOL_WOODWORKERS_TOOLS, TRUE))
			{
				pop_call();
				return;
			}	
			break;
		case TRADE_CRAFT_LEATHER:
			if (!check_tools(ch, TOOL_TANNING_TOOLS, TRUE))
			{
				pop_call();
				return;
			}	
			break;
	}

	if (!check_workshop(ch, skill, type))
	{
		pop_call();
		return;
	}
	if (!check_ingredients(ch, skill, type, FALSE))
	{
		pop_call();
		return;
	}

	if (!ch->concentrating)
	{
		act( "You set to crafting on $t $T", ch, a_an(weapon_table[type].name), weapon_table[type].name, TO_CHAR);
		act( "$n sets to crafting on $t $T", ch, a_an(weapon_table[type].name), weapon_table[type].name, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= dice(4,8);
		ch->timer_fun			= do_craft_weapon;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}
	
	if (!check_ingredients(ch, skill, type, TRUE))
	{
		pop_call();
		return;
	}

	switch(weapon_table[type].class) // dc per SRD
	{
		case WEAPON_CLASS_SIMPLE:
			dc = 12;
			break;
		case WEAPON_CLASS_MARTIAL:
			dc = 15;
			break;
		case WEAPON_CLASS_EXOTIC:
			dc = 18;
			break;
	}

	// invokes the starter item for continued crafting sessions.
	if (!craft)
	{
		if ((craft = create_object(get_obj_index(OBJ_VNUM_CRAFT), 0)) == NULL)
		{
			ch_printf(ch, "There is a bug. Please contact an admin.\n\r");
			bug("do_craft_weapon: OBJ_VNUM_CRAFT non existant.");
			pop_call();
			return;
		}
		
		craft->value[0] = ITEM_WEAPON;
		craft->value[1] = type;
		craft->value[5] = weapon_table[type].cost; // progress points = value in copper
		if (IS_SET(weapon_table[type].weap_spec, WSPEC_WOODEN_HAFTED))
			craft->material = MATERIAL_HARDWOOD;
		else
			craft->material = MATERIAL_STEEL;
		
		RESTRING(craft->name, format("weapon craft %s %s", material_types[craft->material], weap_types[type]));
		RESTRING(craft->short_descr, format("a partially crafted %s", weap_types[type]));
		RESTRING(craft->long_descr, format("A partially crafted %s lies here", weap_types[type]));

		obj_to_char(craft, ch);
	}

	if ((roll = craft_weapon_roll(ch)) >= dc) // allow minute progress for failure, instead of none, lose the material in any case
		roll *= dc;
	else
	{
		// failure decreases masterwork chance
		if (craft->value[6])
			craft->value[6]--;
	}
	if (roll - dc >= 5) // puts item on track for masterwork
		craft->value[6]++;

	// crafting bit gets set here also, locking out crafting until full rest.
	ch->uses[skill]++;
	
	craft->value[4] += roll; // tally craft points here until reaches value 5.
	craft->value[7]++;			 // number of sessions to craft for % chance of masterwork.

	if (craft->value[4] >= craft->value[5])
	{
		//Here is where the weapon item in invoked, and set with all the right values
		if ((weapon = create_object(get_obj_index(OBJ_VNUM_WEAPON), 0)) == NULL)
		{
			ch_printf(ch, "There is a bug. Please contact an admin.\n\r");
			bug("do_craft_weapon: OBJ_VNUM_WEAPON non existant.");
			pop_call();
			return;
		}
		
		obj_to_char(weapon, ch);

		weapon->value[0]  = craft->value[1];
		
		// roll for masterwork - Kregor
		if (number_percent() <= craft->value[6] * 100 / craft->value[7])
			SET_BIT(weapon->extra_flags, ITEM_MASTERWORK);
		weapon->material = craft->material;

		act("You have finished $p.", ch, weapon, NULL, TO_CHAR);
		act("$n finishes crafting $p.", ch, weapon, NULL, TO_ROOM);
		gain_favor(ch, DOMAIN_ARTIFICE, 2);
		
		junk_obj(craft);
		pop_call();
		return;
	}
	
	act("You finish your crafting session.", ch, NULL, NULL, TO_CHAR);
	act("$n finishes his crafting.", ch, NULL, NULL, TO_ROOM);
	gain_favor(ch, DOMAIN_ARTIFICE, 2);

	pop_call();
	return;
}


void do_craft_armor(CHAR_DATA *ch, char *argument)
{
	int type, loc, size, roll, skill, tool, dc, material;
	OBJ_DATA *craft, *armor;
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char cmnd[MAX_INPUT_LENGTH];
	
	push_call("do_craft_armor(%p,%p)",ch,argument);
	
	if (argument[0] =='\0')
	{
		send_to_char("Syntax: craft armor <type> <wear location> [size]\n\r", ch);
		send_to_char("        craft armor <name of work in progress>\n\r", ch);
		pop_call();
		return;
	}
	
	if (ch->uses[gsn_craft_armor]
	|| ch->uses[gsn_craft_leather])
	{
		ch_printf_color(ch, "You cannot craft armor again today; try after you've rested.\n\r");
		pop_call();
		return;
	}		
	if (ch->uses[gsn_craft_tailoring])
	{
		ch_printf_color(ch, "You cannot tailor again today; try after you've rested.\n\r");
		pop_call();
		return;
	}
	
	strcpy(cmnd, argument); 
	
	if ((craft = get_obj_carry(ch, argument)) != NULL)
	{
		// crafting on existing craft piece goes here
		if (!IS_OBJ_TYPE(craft, ITEM_CRAFT))
		{
			send_to_char("That is not a work in progress.\n\r", ch);
			pop_call();
			return;
		}
		if (craft->value[0] != ITEM_ARMOR)
		{
			send_to_char("That is not a piece of armor.\n\r", ch);
			pop_call();
			return;
		}

		type = craft->value[1];
	}
	else
	{
		// craft armor <type> <wear loc>
		argument = one_argument(argument, arg1);
		argument = one_argument(argument, arg2);

		if (arg1[0] =='\0' || arg2[0] =='\0')
		{
			send_to_char("Syntax: craft armor <type> <wear location> [size]\n\r", ch);
			pop_call();
			return;
		}
	
		if ((loc = get_flag(arg2, armor_locs)) == -1)
		{
			ch_printf_color(ch, "Armor locations: <%s>\n\r", justify(give_flags(armor_locs), get_page_width(ch)));
			pop_call();
			return;
		}
		
		if (1 << loc == CAN_WEAR_SHIELD)
		{
			if ((type = get_flag(arg1, craft_shield_types)) == -1)
			{
				ch_printf_color(ch, "Shield types: <%s>\n\r", justify(give_flags(craft_shield_types), get_page_width(ch)));
				pop_call();
				return;
			}
		}
		else if ((type = get_flag(arg1, craft_armor_types)) == -1)
		{
			ch_printf_color(ch, "Armor types: <%s>\n\r", justify(give_flags(craft_armor_types), get_page_width(ch)));
			pop_call();
			return;
		}
	
		if (argument[0] == '\0')
		{
			size = ch->size;
		}
		else if ((size = get_flag(argument, size_types)) == -1)
		{
			ch_printf_color(ch, "Armor sizes: <%s>\n\r", justify(give_flags(size_types), get_page_width(ch)));
			pop_call();
			return;
		}
	}
	
	switch (type)
	{
		default:
			skill = gsn_craft_armor;
			tool = TOOL_SMITH_TOOLS;
			material = MATERIAL_STEEL;
			break;
		case ARMOR_TYPE_LEATHER:
		case ARMOR_TYPE_STUDDED_LEATHER:
		case ARMOR_TYPE_HIDE:
			skill = gsn_craft_leather;
			tool = TOOL_TANNING_TOOLS;
			material = MATERIAL_LEATHER;
			break;
		case ARMOR_TYPE_BUCKLER:
		case ARMOR_TYPE_LIGHT_SHIELD:
			skill = gsn_craft_armor;
			tool = TOOL_WOODWORKERS_TOOLS;
			material = MATERIAL_HARDWOOD;
			break;
		case ARMOR_TYPE_PADDED:
		case ARMOR_TYPE_CLOTH:
			skill = gsn_craft_tailoring;
			tool = TOOL_TAILORS_TOOLS;
			material = MATERIAL_CLOTH;
			break;
	}
	
	if (!learned(ch, skill))
	{
		ch_printf_color(ch, "You lack the %s trade to do that.\n\r", skill_table[skill].name);
		pop_call();
		return;
	}

	if (!check_tools(ch, tool, FALSE))
	{
		pop_call();
		return;
	}

	if (!check_workshop(ch, gsn_craft_armor, type))
	{
		pop_call();
		return;
	}
	if (!check_ingredients(ch, gsn_craft_armor, type, FALSE))
	{
		pop_call();
		return;
	}

	if (!ch->concentrating)
	{
		act( "You set to crafting on a piece of $t armor...", ch, craft_armor_types[type], NULL, TO_CHAR);
		act( "$n sets to crafting on a piece of $t armor...", ch, craft_armor_types[type], NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= dice(4,8);
		ch->timer_fun			= do_craft_armor;
		RESTRING(ch->cmd_argument, cmnd);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}
	
	if (!check_tools(ch, tool, TRUE))
	{
		pop_call();
		return;
	}
	
	if (!check_ingredients(ch, gsn_craft_armor, type, TRUE))
	{
		pop_call();
		return;
	}

	if (!craft)
	{
		if ((craft = create_object(get_obj_index(OBJ_VNUM_CRAFT), 0)) == NULL)
		{
			ch_printf_color(ch, "There is a bug. Please contact an admin.\n\r");
			bug("do_craft_armor: OBJ_VNUM_CRAFT non existant.");
			pop_call();
			return;
		}
		
		craft->value[0] = ITEM_ARMOR;
		craft->value[1] = type;
		craft->value[2] = loc;
		craft->value[3] = size;
		craft->value[5] = armor_table[type].cost; // progress points = value in copper
		craft->material = material;

		switch (1 << loc)
		{
			case CAN_WEAR_HEAD:
			case CAN_WEAR_ARMS:
			case CAN_WEAR_LEGS:
				craft->value[5] *= 2;
				break;
			case CAN_WEAR_BODY:
				craft->value[5] *= 3;
				break;
		}
				
		RESTRING(craft->name, format("armor crafted %s %s", material_types[material], craft_armor_types[type]));
		RESTRING(craft->short_descr, format("a partially crafted piece of %s armor", craft_armor_types[type]));
		RESTRING(craft->long_descr, "A partially crafted piece of armor lies here");

		obj_to_char(craft, ch);
	}

	dc = 10 + armor_table[type].ac_bonus; // dc per SRD

	if (skill == gsn_craft_armor)
		roll = craft_armor_roll(ch);
	else if (skill == gsn_craft_leather)
		roll = craft_leather_roll(ch);
	else
		roll = craft_tailor_roll(ch);

	if (roll >= dc) // allow minute progress for failue, instead of none, lose the material in any case
		roll *= dc;
	else
	{
		if (craft->value[6]) // penalize masterwork chance on failure.
		craft->value[6]--;
	}

	if (roll - dc >= 5) // puts item on track for masterwork
		craft->value[6]++;

	// crafting bit gets set here also, locking out crafting until full rest.
	ch->uses[skill]++;
	
	craft->value[4] += roll;
	craft->value[7]++;

	if (craft->value[4] >= craft->value[5])
	{
		//Here is where the armor item in invoked, and set with all the right values
		if ((armor = create_object(get_obj_index(OBJ_VNUM_ARMOR), 0)) == NULL)
		{
			ch_printf_color(ch, "There is a bug. Please contact an admin.\n\r");
			bug("do_craft_armor: OBJ_VNUM_ARMOR non existant.");
			pop_call();
			return;
		}
		obj_to_char(armor, ch);

		armor->value[0]  		= craft->value[1];
		armor->wear_flags		= 1 << craft->value[2];
		armor->value[3] 		= craft->value[3];
		armor->value[4] 		= LAYER_ARMOR;
		if (number_percent() <= craft->value[6] * 100 / craft->value[7])
			SET_BIT(armor->extra_flags, ITEM_MASTERWORK);
		armor->material 		= craft->material;

		act("You have finished a piece of armor.", ch, NULL, NULL, TO_CHAR);
		act("$n finishes a piece of armor.", ch, NULL, NULL, TO_ROOM);
		gain_favor(ch, DOMAIN_ARTIFICE, 2);
		
		junk_obj(craft);
		pop_call();
		return;
	}
	
	act("You finish your crafting session.", ch, NULL, NULL, TO_CHAR);
	act("$n finishes his crafting.", ch, NULL, NULL, TO_ROOM);
	gain_favor(ch, DOMAIN_ARTIFICE, 2);

	pop_call();
	return;
}


void do_craft_ammo(CHAR_DATA *ch, char *argument)
{
	int type, roll, dc;
	OBJ_DATA *arrowhead, *branch, *feather, *ammo;
	char noun[10];
	
	
	push_call("do_craft_ammo(%p,%p)",ch,argument);
	
	if (!learned(ch, gsn_craft_fletching))
	{
		ch_printf(ch, "You lack the fletching trade to do that.\n\r");
		pop_call();
		return;
	}
	
	if (argument[0] =='\0')
	{
		send_to_char("Syntax: craft ammo <weapon>\n\r", ch);
		pop_call();
		return;
	}
	
	if ((type = craft_weapon_flag(argument, TRADE_CRAFT_BOW)) == -1)
	{
		ch_printf(ch, "You cannot fletch ammo for %s %s.", a_an(argument), argument);
		pop_call();
		return;
	}
	
	if (!check_tools(ch, TOOL_WOODWORKERS_TOOLS, FALSE))
	{
		pop_call();
		return;
	}	

	for (arrowhead = ch->first_carrying ; arrowhead ; arrowhead = arrowhead->next_content)
	{
		if (arrowhead->item_type == ITEM_COMPONENT && arrowhead->value[0] == COMP_ARROWHEAD)
		{
			break;
		}
	} 
	if (arrowhead == NULL)
	{
		ch_printf_color(ch, "You are missing an arrowhead.\n\r");
		pop_call();
		return;
	}

	for (branch = ch->first_carrying ; branch ; branch = branch->next_content)
	{
		if (branch->item_type == ITEM_COMPONENT && branch->value[0] == COMP_BRANCH)
		{
			break;
		}
	} 
	if (branch == NULL)
	{
		ch_printf_color(ch, "You are missing a branch.\n\r");
		pop_call();
		return;
	}

	for (feather = ch->first_carrying ; feather ; feather = feather->next_content)
	{
		if (feather->item_type == ITEM_COMPONENT && feather->value[0] == COMP_FEATHERS)
		{
			break;
		}
	} 
	if (feather == NULL)
	{
		ch_printf_color(ch, "You are missing a feather.\n\r");
		pop_call();
		return;
	}

	if (!ch->concentrating)
	{
		act( "You set to crafting $t $T...", ch, a_an(weapon_table[type].name), weapon_table[type].name, TO_CHAR);
		act( "$n sets to crafting $t $T...", ch, a_an(weapon_table[type].name), weapon_table[type].name, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= dice(2,8);
		ch->timer_fun			= do_craft_ammo;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	if (!check_tools(ch, TOOL_WOODWORKERS_TOOLS, TRUE))
	{
		pop_call();
		return;
	}
	
	//need to add variables to vary dc.
	dc = 10;

	if ((roll = craft_weapon_roll(ch)) > dc)
	{
		if ((ammo = create_object(get_obj_index(OBJ_VNUM_AMMO), 0)) == NULL)
		{
			ch_printf(ch, "There is a bug. Please contact an admin.\n\r");
			bug("do_craft_weapon: OBJ_VNUM_CRAFT non existant.");
			pop_call();
			return;
		}
		
		if (roll >= dc + 10)
			SET_BIT(ammo->extra_flags, ITEM_MASTERWORK);
	
		obj_to_char(ammo, ch);
	
		ammo->value[0] = type;
		ammo->material = arrowhead->material;
		
		switch(type)
		{
			case WEAPON_TYPE_CROSSBOW_HAND:
			case WEAPON_TYPE_CROSSBOW_HEAVY:
			case WEAPON_TYPE_CROSSBOW_LIGHT:
				strcpy(noun, "bolt");
				break;
			default:
				strcpy(noun, "arrow");
				break;
		}
		
		RESTRING(ammo->name, format("ammo %s %s %s", material_types[arrowhead->material], noun));
		RESTRING(ammo->short_descr, format("{038}%s %s tipped %s with %s", a_an(material_types[arrowhead->material]), material_types[arrowhead->material], noun, feather->short_descr));
		RESTRING(ammo->long_descr, format("%s lies here", ammo->short_descr));
	
		act("You have finished crafting $p.", ch, ammo, NULL, TO_CHAR);
		act("$n finishes crafting $p.", ch, ammo, NULL, TO_ROOM);
	}
	else
	{
		act("You fail to craft $t $T.", ch, a_an(weapon_table[type].name), weapon_table[type].name, TO_CHAR);
		act("$n fails to craft $t $T.", ch, a_an(weapon_table[type].name), weapon_table[type].name, TO_ROOM);
	}
	
	if (--arrowhead->value[1] <= 0)
	{
		act("You have used up $p.", ch, arrowhead, NULL, TO_CHAR);
		junk_obj(arrowhead);
	}
	if (--feather->value[1] <= 0)
	{
		act("You have used up $p.", ch, feather, NULL, TO_CHAR);
		junk_obj(feather);
	}
	if (--branch->value[1] <= 0)
	{
		act("You have used up $p.", ch, branch, NULL, TO_CHAR);
		junk_obj(branch);
	}

	pop_call();
	return;
}


/* The Crafting skills command - Kregor 2/25/07 */
void do_craft( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];

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

	argument = one_argument(argument, arg);

	if (IS_NPC(ch))
	{
		log_printf("do_craft: used by mob");
		dump_stack();
		pop_call();
		return;
	}

	if (!strcasecmp(arg, "poison"))
	{
		do_craft_poison(ch, argument);
	}
	else if (!strcasecmp(arg, "wand"))
	{
		do_craft_wand(ch, argument);
	}
	else if (!strcasecmp(arg, "staff"))
	{
		do_craft_staff(ch, argument);
	}
	else if (!strcasecmp(arg, "potion"))
	{
		do_brew(ch, argument);
	}
	else if (!strcasecmp(arg, "scroll"))
	{
		do_scribe(ch, argument);
	}
	else if (!strcasecmp(arg, "alchemy"))
	{
		craft_alchemy(ch, argument);
	}
	else if (!strcasecmp(arg, "armor"))
	{
		do_craft_armor(ch, argument);
	}
	else if (!strcasecmp(arg, "weapon"))
	{
		do_craft_weapon(ch, argument);
	}
	else if (!strcasecmp(arg, "ammo"))
	{
		do_craft_ammo(ch, argument);
	}
	else if (!strcasecmp(arg, "bow")||!strcasecmp(arg, "jewelry")
	||!strcasecmp(arg, "trap"))
	{
		send_to_char("Crafting is still under construction. Bear with us...\n\r", ch);
		send_to_char("Pretty soon you'll be able to use your crafting skills to\n\r", ch);
		send_to_char("make all sorts of cool stuff for yourself or to sell/trade!\n\r", ch);
	}
	else
		send_to_char("Syntax: craft <alchemy|armor|bow|jewelry|poison|trap|weapon|ammo>\n\r", ch);

  pop_call();
	return;
}

/*
 * called in do_enchant to add applies and effect flags - Kregor
 */
void enchant_obj( CHAR_DATA *ch, OBJ_DATA *obj, char *argument, bool fEstimate )
{
	AFFECT_DATA paf;
	bool Affect, Apply, wFlag, aFlag;
	int cost, stat, sn, class, mana, circle, level, skill, mod;
	lg_int flag;

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

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}
	
  Affect = Apply = wFlag = aFlag = FALSE;
  sn = flag = -1;
	
	if (!is_string(argument))
	{
		act("Enchant $p with that effect?", ch, obj, NULL, TO_CHAR);
		pop_call();
		return;
	}
	
	ch_printf(ch, "String is %s,\n\r", argument);
	
	if (IS_WORN(obj))
	{
		act("You must unequip $p to enchant it.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (!IS_OBJ_STAT(obj,ITEM_MASTERWORK))
	{
		send_to_char( "You can only enchant a masterwork item.\n\r", ch);
		pop_call();
		return;
	}

	switch(obj->item_type)
	{
		case ITEM_ARMOR:
			if (IS_SET(obj->wear_flags, CAN_WEAR_HANDS|CAN_WEAR_FEET|CAN_WEAR_HEAD|CAN_WEAR_ABOUT|CAN_WEAR_WAIST|CAN_WEAR_SADDLE))
			{
				skill = gsn_craft_wondrous;
			}
			else if (IS_SET(obj->wear_flags, CAN_WEAR_BODY))
			{
				if (!obj->apply[APPLY_ENHANCE_AC])
				{
					act("$p must have an enhancement bonus before other enchantments are added.", ch, obj, NULL, TO_CHAR);
					pop_call();
					return;
				}
				skill = gsn_craft_magic_arms;
			}
			else
			{
				act("$p cannot hold enchantment.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return;
			}
			break;

		case ITEM_WEAPON:
			if (!obj->apply[APPLY_HITROLL])
			{
				act("$p must have an enhancement bonus before other enchantments are added.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
			skill = gsn_craft_magic_arms;
			break;

		case ITEM_SYMBOL:
		case ITEM_TREASURE:
			if (IS_SET(obj->wear_flags, CAN_WEAR_FINGER))
			{
				skill = gsn_forge_ring;
			}
			else
			{
				skill = gsn_craft_wondrous;
			}
			break;

		default:
			send_to_char( "You cannot enchant that kind of an object.\n\r", ch);
			pop_call();
			return;
	}

	if (!learned(ch,skill))
	{
		send_to_char( "You are not trained to enchant that item.\n\r", ch);
		pop_call();
		return;
	}

	if (ch->uses[skill])
	{
		send_to_char( "You must rest before you can enchant again.\n\r", ch);
		pop_call();
		return;
	}

	if ((flag = get_flag(argument, craft_applies)) != -1)
	{
		ch_printf_color(ch, "{058}DEBUG: Adding Apply flag %d (%s).\n\r", flag, type_string(flag, a_types));

		if ((sn = skill_lookup(craft_apply_spells[flag])) == -1)
		{
			act("Cannot find the spell for that effect.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		Apply = TRUE;
	}
	else if ((flag = craft_effect_flag(argument)) != -1)
	{
		ch_printf_color(ch, "{058}DEBUG: Adding Affect flag %d (%s).\n\r", flag, argument);

		if ((sn = craft_effect_spell(flag)) == -1)
		{
			act("Cannot find the spell for that effect.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		Affect = TRUE;
	}
	else if ((flag = get_armor_flag(argument)) != -1 && obj->item_type == ITEM_ARMOR)
	{
		ch_printf_color(ch, "{058}DEBUG: Adding Armor flag %d (%s).\n\r", flag, argument);

		if ((sn = armor_flag_spell(flag)) == -1)
		{
			act("Cannot find the spell for that effect.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		aFlag = TRUE;
	}
	else if ((flag = get_weapon_flag(argument)) != -1 && obj->item_type == ITEM_WEAPON)
	{
		ch_printf_color(ch, "{058}DEBUG: Adding Weapon flag %d (%s).\n\r", flag, argument);

		if ((sn = skill_lookup(weapon_flag_spells[flag])) == -1)
		{
			act("Cannot find the spell for that effect.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		wFlag = TRUE;
	}
	else
	{
		send_to_char("There is no such effect.\n\r", ch);
		pop_call();
		return;
	}

	if (!learned(ch, sn))
	{
		act( "You do not know the spell $t.", ch, skill_table[sn].name, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if ((class = prepared(ch, sn)) == -1)
	{
		if ((class = spontaneous_cast(ch, sn)) == -1)
		{
			ch_printf( ch, "You have to prepare %s to imbue it.\n\r", skill_table[sn].name );
			pop_call();
			return;
		}
	}
	
	level = class_level(ch, class);
	circle = circle_by_class(ch, sn, class);
	if (Apply)
		stat = mod_max(flag, class_level(ch, class));

	if ((mana = get_mana(ch, sn, circle, class) * 5) > ch->mana[class])
	{
		act("You do not have enough mana to imbue that into $p.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (Apply)
	{
		if (obj->apply[flag])
		{
			act("$p already has that effect.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		if (skill == gsn_craft_wondrous && !IS_SET(obj->wear_flags, body_affinities(flag)))
		{
			act("That effect is not available on that wear location.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		paf.type				= gsn_object_rape;
		paf.location		= flag;
		paf.modifier		= stat;
		paf.bittype			= AFFECT_TO_NONE;
		paf.duration		= -1;
		paf.bitvector	= 0;
		paf.level			= class_level(ch, class) / 2;
		
		cost = obj_affect_cost(&paf);
	}
	if (Affect)
	{
		if (IS_OBJ_STAT(obj, flag))
		{
			act("$p already has that effect.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		paf.type				= gsn_object_rape;
		paf.location		= 0;
		paf.modifier		= 0;
		paf.bittype			= AFFECT_TO_CHAR;
		paf.duration		= -1;
		paf.bitvector		= flag;
		paf.level				= class_level(ch, class) / 2;
		
		cost = obj_affect_cost(&paf);
	}
	if (wFlag)
	{
		if (obj->value[1])
		{
			act("$p can only have one special ability.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		if (WEAPON_FLAG(obj, flag))
		{
			act("$p already has that ability.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		mod = obj->apply[APPLY_HITROLL] + wflag_cost_mod[UNSHIFT(flag)];
		cost = mod * mod * 100000;
		cost -= obj->apply[APPLY_HITROLL] * obj->apply[APPLY_HITROLL] * 100000;
	}
	if (aFlag)
	{
		if (obj->value[1])
		{
			act("$p can only have one special ability.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		if (ARMOR_FLAG(obj, flag))
		{
			act("$p already has that ability.", ch, obj, NULL, TO_CHAR);
			pop_call();
			return;
		}
		mod = obj->apply[APPLY_ENHANCE_AC] + armflag_cost_mod[UNSHIFT(flag)];
		cost = mod * mod * 100000;
		cost -= obj->apply[APPLY_ENHANCE_AC] * obj->apply[APPLY_ENHANCE_AC] * 100000;
	}
	
	cost /= 2;
	
	// slotless item costs more - Kregor
	if (IS_SET(obj->wear_flags, CAN_WEAR_FLOAT))
	{
		cost = cost * 3 / 2;
	}
	
	if (fEstimate)
	{
		act("It will cost $T to enchant $p.", ch, obj, format_coins(cost, FALSE), TO_CHAR);
		pop_call();
		return;
	}
	else if (ch->gold + ch->pcdata->bank < cost)
	{
		send_to_char( "You do not have enough gold.\n\r", ch);
		pop_call();
		return;
	}
	
	if (!ch->concentrating)
	{
		act( "You start to enchant $p...", ch, obj, NULL, TO_CHAR);
		act( "$n starts to enchant $p...", ch, obj, NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= dice(3,6);
		ch->timer_fun			= do_enchant;
		RESTRING(ch->cmd_argument, format("i%d %s", obj->pIndexData->vnum, argument));
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	int roll = spellcraft_roll(ch);
	if (domain_apotheosis(ch, DOMAIN_ARTIFICE))
		roll += 10;
	if (!spellcraft_check(ch, NULL, sn, roll, class_level(ch, class) / 2 + 10))
	{
		act( "You failed to enchant $p.", ch, obj, NULL, TO_CHAR);
		gold_transaction(ch, 0 - cost / 5);
		pop_call();
		return;
	}

	if (Apply || Affect)
	{
		affect_to_obj(ch,obj,&paf);
	}
	else if (wFlag)
	{
		SET_SHIFT(obj->value[1], flag);
	}
	else if (aFlag)
	{
		SET_BIT(obj->value[1], flag);
	}

	ch->uses[skill]++;
	gold_transaction(ch, 0 - cost);
	
	SET_BIT(obj->extra_flags, ITEM_MAGIC);
	obj->level	= class_level(ch, class) / 2;
	obj->hit_points = get_obj_max_hit(obj);
	obj->cost = obj_cost(obj);

	act("$p glimers with a newly imbued dweomer.", ch, obj, NULL, TO_ALL);
	gain_favor(ch, DOMAIN_ARTIFICE, 2);
	gain_favor(ch, DOMAIN_MAGIC, 2);
	pop_call();
	return;
}


/*
 * Borrowed from old ENGRAVE command on eMud, adapted for
 * d20 magic armor/weapon crafting - Kregor
 */
void do_enchant( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	OBJ_DATA *obj;
	AFFECT_DATA paf;
	bool fEstimate = FALSE;
	int cost, stat, sn, class, mana, circle, level, skill;

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

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}
	
	if (!is_string(argument))
	{
		send_to_char("Enchant what?\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument(argument, arg);
	
	if (!strcasecmp(arg, "estimate"))
	{
		fEstimate = TRUE;
		argument = one_argument(argument, arg);
	}

	if (*arg == '\0')
	{
		send_to_char( "You must choose an object to enchant.\n\r", ch);
		pop_call();
		return;
	}

	if ((obj = get_obj_here(ch, arg)) == NULL)
	{
		send_to_char( "You do not have that object.\n\r", ch);
		pop_call();
		return;
	}
	
	if (!is_string(argument))
	{
		act("Enchant $p with that effect?", ch, obj, NULL, TO_CHAR);
		pop_call();
		return;
	}
	
	switch(obj->item_type)
	{
		case ITEM_ARMOR:
			if (IS_SET(obj->wear_flags, CAN_WEAR_HANDS|CAN_WEAR_FEET|CAN_WEAR_HEAD|CAN_WEAR_ABOUT|CAN_WEAR_WAIST|CAN_WEAR_SADDLE))
			{
				if (is_number(argument))
				{
					act("$p cannot hold an enhancement bonus.", ch, obj, NULL, TO_CHAR);
					pop_call();
					return;
				}
				skill = gsn_craft_wondrous;
			}
			else if (IS_SET(obj->wear_flags, CAN_WEAR_BODY))
			{
				skill = gsn_craft_magic_arms;
			}
			else
			{
				act("$p cannot hold enchantment.", ch, NULL, NULL, TO_CHAR);
				pop_call();
				return;
			}
			break;

		case ITEM_WEAPON:
			skill = gsn_craft_magic_arms;
			break;

		case ITEM_SYMBOL:
		case ITEM_TREASURE:
			if (IS_SET(obj->wear_flags, CAN_WEAR_FINGER))
			{
				skill = gsn_forge_ring;
			}
			else
			{
				skill = gsn_craft_wondrous;
			}
			break;

		default:
			send_to_char( "You cannot enchant that kind of an object.\n\r", ch);
			pop_call();
			return;
	}

	if (!learned(ch,skill))
	{
		send_to_char( "You are not trained to enchant that item.\n\r", ch);
		pop_call();
		return;
	}

	if (ch->uses[skill])
	{
		send_to_char( "You must rest before you can enchant again.\n\r", ch);
		pop_call();
		return;
	}

	if (IS_WORN(obj))
	{
		act("You must unequip $p to enchant it.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (!IS_OBJ_STAT(obj,ITEM_MASTERWORK))
	{
		send_to_char( "You can only enchant a masterwork item.\n\r", ch);
		pop_call();
		return;
	}

	if (!is_number(argument))
	{
		enchant_obj(ch, obj, argument, fEstimate);
		pop_call();
		return;
	}
	
	switch(obj->item_type)
	{
		case ITEM_WEAPON:
			if (obj->apply[APPLY_HITROLL])
			{
				act("$p already has an enhancement bonus.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
			sn = gsn_magic_vestment;
			break;

		case ITEM_ARMOR:
			if (obj->apply[APPLY_ENHANCE_AC])
			{
				act("$p already has an enhancement bonus.", ch, obj, NULL, TO_CHAR);
				pop_call();
				return;
			}
			sn = gsn_magic_weapon;
			break;

		default:
			send_to_char( "You cannot add an enhancement bonus that kind of an object.\n\r", ch);
			pop_call();
			return;
	}

	if (!learned(ch, sn))
	{
		act( "You do not know the spell $t.", ch, skill_table[sn].name, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if ((class = prepared(ch, sn)) == -1)
	{
		if ((class = spontaneous_cast(ch, sn)) == -1)
		{
			send_to_char( "You have to prepare a spell to imbue it.\n\r", ch );
			pop_call();
			return;
		}
	}

	level = class_level(ch, class);
	circle = circle_by_class(ch, sn, class);

	if ((stat = atoi(argument)) > class_level(ch, class) / 2 || stat > 5)
	{
		act( "You cannot enchant $p that high.", ch, obj, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if ((mana = get_mana(ch, sn, circle, class) * 5) > ch->mana[class])
	{
		act("You do not have enough mana to imbue that spell.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	switch(obj->item_type)
	{
		case ITEM_ARMOR:
			cost = stat * stat * 50000;
			break;

		case ITEM_WEAPON:
			cost = stat * stat * 100000;
			break;

		default:
			send_to_char( "You cannot enhance that kind of an object.\n\r", ch);
			pop_call();
			return;
	}

	if (fEstimate)
	{
		act("It will cost $T to enchant $p.", ch, obj, format_coins(cost, FALSE), TO_CHAR);
		pop_call();
		return;
	}
	if (ch->gold + ch->pcdata->bank < cost)
	{
		send_to_char( "You do not have enough gold.\n\r", ch);
		pop_call();
		return;
	}
	
	if (!ch->concentrating)
	{
		act( "You start to enchant $p...", ch, obj, NULL, TO_CHAR);
		act( "$n starts to enchant $p...", ch, obj, NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= dice(3,6);
		ch->timer_fun			= do_enchant;
		RESTRING(ch->cmd_argument, format("%s %s", arg, argument));
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	int roll = spellcraft_roll(ch);
	if (domain_apotheosis(ch, DOMAIN_ARTIFICE))
		roll += 10;
	if (!spellcraft_check(ch, NULL, sn, roll, stat * 3 + 5))
	{
		act( "You failed to enchant $p.", ch, obj, NULL, TO_CHAR);
		gold_transaction(ch, 0 - cost / 5);
		pop_call();
		return;
	}

	switch(obj->item_type)
	{
		case ITEM_ARMOR:
			paf.type				= gsn_object_rape;
			paf.location		= APPLY_ENHANCE_AC;
			paf.bittype  		= AFFECT_TO_NONE;
			paf.modifier		= stat;
			paf.duration		= -1;
			paf.bitvector	= 0;
			paf.level			= ch->level;
			affect_to_obj(ch,obj,&paf);
			break;

		case ITEM_WEAPON:
			paf.type				= gsn_object_rape;
			paf.location		= APPLY_HITROLL;
			paf.bittype  		= AFFECT_TO_NONE;
			paf.modifier		= stat;
			paf.duration		= -1;
			paf.bitvector	= 0;
			paf.level			= ch->level;
			affect_to_obj(ch,obj,&paf);
			break;
	}

	ch->uses[gsn_craft_magic_arms]++;
	gold_transaction(ch, 0 - cost);
	
	SET_BIT(obj->extra_flags, ITEM_MAGIC);
	obj->level	= ch->level/2;

	act("$p glimers with a newly imbued dweomer.", ch, obj, NULL, TO_ALL);
	gain_favor(ch, DOMAIN_ARTIFICE, 2);
	gain_favor(ch, DOMAIN_MAGIC, 2);
	pop_call();
	return;
}


/*
 * Brew potion feat - Kregor 1/15/07
 */
void do_brew(CHAR_DATA *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	char buf2[MAX_INPUT_LENGTH];
	OBJ_DATA *potion;
	int sn, class, level, circle, value, mana;

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

	if (IS_NPC(ch))
	{
		send_to_char( "You can't do that!\n\r", ch);
		pop_call();
		return;
	}

	if (!learned(ch,gsn_brew_potion))
	{
		send_to_char( "You don't know how to brew potions!\n\r", ch);
		pop_call();
		return;
	}
	
	if (ch->uses[gsn_brew_potion] >= 3)
	{
		send_to_char( "You cannot brew any more potions until you've rested.\n\r", ch);
		pop_call();
		return;
	}

	for (potion = ch->first_carrying ; potion ; potion = potion->next_content)
	{
		if (!IS_OBJ_TYPE(potion, ITEM_POTION))
			continue;
		if (potion->value[0] == 0)
			break;
	}

	if (!potion)
	{
		send_to_char("You need an empty potion to hold your potion.\n\r",ch);
		pop_call();
		return;
	}

	argument = one_argument(argument, arg);

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

	if ((sn = skill_lookup(arg)) < 0 || !is_spell(sn))
	{
		send_to_char( "That is not a spell.\n\r", ch );
		pop_call();
		return;
	}
	if ((level = multi_caster_level(ch, sn)) == -1)
	{
		send_to_char( "You can only brew spells in your classes.\n\r", ch );
		pop_call();
		return;
	}
	if (!learned(ch, sn))
	{
		send_to_char( "You don't know that spell to brew it.\n\r", ch );
		pop_call();
		return;
	}
	
	/* Can only brew potions that affect other or self
	 * and cannot brew spells over level 3
	 */
	if (skill_table[sn].target != TAR_CHAR_DEFENSIVE
	&& skill_table[sn].target != TAR_CHAR_SELF
	&& skill_table[sn].target != TAR_OBJ_CHAR_DEF)
	{
		send_to_char( "You cannot brew that spell.\n\r", ch );
		pop_call();
		return;
	}
	if ((class = prepared(ch, sn)) == -1)
	{
		if ((class = spontaneous_cast(ch, sn)) == -1)
		{
			send_to_char( "You have to prepare a spell to scribe it.\n\r", ch );
			pop_call();
			return;
		}
	}
	
	level = class_level(ch, class);

	if ((circle = circle_by_class(ch, sn, class)) > 3)
	{
		send_to_char( "You can only brew spells up to 3rd circle.\n\r", ch );
		pop_call();
		return;
	}

	value = level * circle * 2500;
	
	if (ch->gold + ch->pcdata->bank < value)
	{
		send_to_char( "You don't have enough gold for materials.\n\r", ch );
		pop_call();
		return;
	}
	
	if ((mana = get_mana(ch, sn, circle, class)) > ch->mana[class])
	{
		act("You do not have enough mana to brew that spell.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (!ch->concentrating)
	{
		if (!check_components(ch, sn, FALSE))
		{
			pop_call();
			return;
		}
		act( "You start to brew a potion...", ch, NULL, NULL, TO_CHAR);
		act( "$n starts to brew a potion...", ch, NULL, NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= 16;
		ch->timer_fun			= do_brew;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	if (!check_components(ch, sn, TRUE))
	{
		pop_call();
		return;
	}
	ch->mana[class] -= mana;
	ch->uses[gsn_brew_potion]++;
	
	if (craft_alchemy_roll(ch) < 5 + level)
	{
		act("You fail to brew the potion.", ch, NULL, NULL, TO_CHAR);
		act("$n fails to brew the potion.", ch, NULL, NULL, TO_ROOM);
		gold_transaction(ch, 0 - value / 5);
		pop_call();
		return;
	}

	sprintf(buf, "a potion of %s", skill_table[sn].name);
	sprintf(buf2, "%s %s", potion->name, skill_table[sn].name);

	RESTRING(potion->name, buf2);

	potion->cost			= value;
	potion->level			= level;
	potion->value[0]	= level;
	potion->value[1]	= sn;
	potion->owned_by	= ch->pcdata->pvnum;

	act( "$n brews up a potion.", ch, potion, NULL, TO_ROOM);
	act( "You brew up $t!", ch, buf, NULL, TO_CHAR);
	gold_transaction(ch, 0 - value);
	gain_favor(ch, DOMAIN_ARTIFICE, 2);
	gain_favor(ch, DOMAIN_MAGIC, 2);

	pop_call();
	return;
}


/*
 * Scribe scroll feat - Kregor 1/15/07
 */
void do_scribe(CHAR_DATA *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	char buf2[MAX_INPUT_LENGTH];
	OBJ_DATA *scroll, *pen;
	int sn, level, circle, value, class, mana;

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

	if (IS_NPC(ch))
	{
		send_to_char( "You can't do that!\n\r", ch);
		pop_call();
		return;
	}

	if (!learned(ch,gsn_scribe_scroll))
	{
		send_to_char( "You don't know how to scribe scrolls!\n\r", ch);
		pop_call();
		return;
	}

	if (ch->uses[gsn_scribe_scroll] >= 3)
	{
		send_to_char( "You cannot scribe any more scrolls until you've rested.\n\r", ch);
		pop_call();
		return;
	}

	for (scroll = ch->first_carrying ; scroll ; scroll = scroll->next_content)
	{
		if (!IS_OBJ_TYPE(scroll, ITEM_SCROLL))
			continue;
		if (scroll->value[0] == 0)
			break;
	}

	if (!scroll)
	{
		send_to_char("You need a blank scroll to write upon.\n\r",ch);
		pop_call();
		return;
	}

	if ((pen = get_obj_wear_type(ch, ITEM_TOOLS)) == NULL
	|| !TOOL_TYPE(pen, TOOL_PEN))
	{
		send_to_char("You need to hold a pen to scribe with.\n\r",ch);
		pop_call();
		return;
	}
	
	if (pen->value[1] == 0)
	{
		send_to_char("Your pen is empty.\n\r",ch);
		pop_call();
		return;
	}		

	argument = one_argument(argument, arg);

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

	if ((sn = skill_lookup(arg) < 0) || !is_spell(sn))
	{
		send_to_char( "That is not a spell.\n\r", ch );
		pop_call();
		return;
	}
	if (multi(ch, sn) == -1)
	{
		send_to_char( "You can only scribe spells in your classes.\n\r", ch );
		pop_call();
		return;
	}
	if (!learned(ch, sn))
	{
		send_to_char( "You don't know that spell to scribe it.\n\r", ch );
		pop_call();
		return;
	}
	if ((class = prepared(ch, sn)) == -1)
	{
		if ((class = spontaneous_cast(ch, sn)) == -1)
		{
			send_to_char( "You have to prepare a spell to scribe it.\n\r", ch );
			pop_call();
			return;
		}
	}
	
	level = class_level(ch, class);

	circle = circle_by_class(ch, sn, class);
	value = level * circle * 1250;
	
	if (ch->gold + ch->pcdata->bank < value)
	{
		send_to_char( "You don't have enough gold for materials.\n\r", ch );
		pop_call();
		return;
	}

	if ((mana = get_mana(ch, sn, circle, class)) > ch->mana[class])
	{
		act("You do not have enough mana to brew that spell.", ch, NULL, NULL, TO_CHAR);
		pop_call();
		return;
	}

	if (!ch->concentrating)
	{
		if (!check_components(ch, sn, FALSE))
		{
			pop_call();
			return;
		}
		act( "You start to scribe a scroll...", ch, NULL, NULL, TO_CHAR);
		act( "$n starts to scribe a scroll...", ch, NULL, NULL, TO_ROOM);
		ch->concentrating = TRUE;
		ch->skill_timer		= 16;
		ch->timer_fun			= do_scribe;
		RESTRING(ch->cmd_argument, argument);
		TAKE_ACTION(ch, ACTION_FULL);
		pop_call();
		return;
	}

	if (!check_components(ch, sn, TRUE))
	{
		pop_call();
		return;
	}

	ch->mana[class] -= mana;
	if (pen->value[1] > 0)
		--pen->value[1];
	ch->uses[gsn_scribe_scroll]++;

	if (spellcraft_check(ch, NULL, sn, spellcraft_roll(ch), level + 5))
	{
		act( "You failed to scibe the scroll.", ch, NULL, NULL, TO_CHAR);
		gold_transaction(ch, 0 - value / 5);
	}
	else
	{
		sprintf(buf, "a spell scroll");
		sprintf(buf2, "scroll %s", skill_table[sn].name);
	
		RESTRING(scroll->name, buf2);
		RESTRING(scroll->short_descr, buf);
	
		scroll->cost			= value;
		scroll->level			= level;
		scroll->value[0]	= multi(ch,sn);
		scroll->value[1]	= sn;
		if (class_table[class].attr_prime == APPLY_WIS)
			scroll->value[2] = SCROLL_DIVINE;
		else
			scroll->value[2] = SCROLL_ARCANE;
		scroll->owned_by	= ch->pcdata->pvnum;

		act( "You painstakingly scribe $p.", ch, scroll, NULL, TO_CHAR);
		gold_transaction(ch, 0 - value);
		gain_favor(ch, DOMAIN_ARTIFICE, 2);
		gain_favor(ch, DOMAIN_MAGIC, 2);
	}

	act( "$n finishes scribing.", ch, scroll, NULL, TO_ROOM);

	pop_call();
	return;
}