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

/*$Id: crafting.c,v 1.23 2005/04/10 16:29:00 tyrion Exp $*/

#if defined( macintosh )
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <math.h>

#include "merc.h"
char* target_name;

/* local functions */
char* set_skin_quality(OBJ_DATA* skin);
char* name_tanned_armor(OBJ_DATA* armor);

/* Use this file for all ranger skills */

extern char* target_name;

void spell_imprint( int sn, int level, CHAR_DATA *ch, void *vo );

// skin corpses for hides
int skill_skin( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char buf[MAX_STRING_LENGTH];
	char buf2[MAX_STRING_LENGTH];
	OBJ_DATA* obj  = (OBJ_DATA*) vo;
	OBJ_DATA* skin = NULL;
	
	if (IS_NPC(ch))
		return SKPELL_BOTCHED;

	if (obj->item_type == ITEM_CORPSE_NPC)
	{

		if (obj->value[0] == TAN_NONE || (obj->value[0] == TAN_PC && !IS_IMMORTAL(ch)))
		{
			send_to_char(AT_RED, "You cannot skin that!\n\r", ch);
			return SKPELL_BOTCHED;
		}
	} else if ( obj->item_type == ITEM_ARMOR )
	{
		if (!IS_SET(obj->extra_flags2, ITEM_CRAFTED))
		{
			send_to_char(AT_RED, "You can't scrape leather from non-leather armor!\n\r", ch);
			return SKPELL_BOTCHED;
		}
	} else if (obj->item_type == ITEM_SKIN)
	{
		OBJ_DATA* obj2;
		char arg [MAX_INPUT_LENGTH]="";

		target_name = one_argument(target_name, arg);
		one_argument(target_name, arg);

		if (!obj->carried_by)
		{
			send_to_char(AT_RED, "You do not have that in your inventory! Pick it up!\n\r", ch);
			return SKPELL_BOTCHED;
		}

		if (arg[0]=='\0')
		{
			send_to_char(AT_RED, "You need two rolls of leather to combine!\n\r", ch);
			return SKPELL_BOTCHED;
		}
		
		obj2 = get_obj_carry(ch, arg);
		
		if (!obj2 || (obj2 && obj2->item_type != ITEM_SKIN))
		{
			send_to_char(AT_RED, "You need two rolls of leather to combine!\n\r", ch);
			return SKPELL_BOTCHED;
		}

		if (obj==obj2)
		{
			send_to_char(AT_RED, "You cannot combine a roll of leather with itself!\n\r", ch);
			return SKPELL_BOTCHED;
		}

		if (number_percent() - 20 < ( ch->pcdata->learned[sn] / 10 ) )
		{
			int waste = 0;
			skin = create_object( get_obj_index( OBJ_VNUM_LEATHER ), obj->level );

			waste = URANGE(1, UMIN( obj->value[1], obj->value[2]), 10);
			/* waste -= waste * ch->pcdata->learned[sn] / 1000; */
			if( number_percent( ) + 10 <= ch->pcdata->learned[sn] / 10 && waste > 0 ) 
			{
				waste -= 1;
			}

			skin->item_type = ITEM_SKIN;
			skin->level	= (obj->level + obj2->level) / 2;
			skin->value[1]  = UMAX(1, obj->value[1] + obj2->value[1] - waste);
			skin->value[0]  = (obj->value[0] + obj2->value[0]) / 2;
			skin->weight    = obj->weight + obj2->weight;

			strcpy(buf2, set_skin_quality( skin ));

			send_to_char(AT_WHITE, "You skilfully combine:\n\r", ch);
			send_to_char(AT_BLUE, obj->short_descr, ch);
			send_to_char(AT_BLUE, "\n\r", ch);
			send_to_char(AT_BLUE, obj2->short_descr, ch);
			send_to_char(AT_BLUE, "\n\r", ch);
			if (waste)
			{
				sprintf(buf, "You waste %d yards of leather.\n\r", waste);
				send_to_char(AT_BLUE, buf, ch);
			}

			sprintf(buf, "Creating %d yards of %s leather!\n\r", skin->value[1], buf2);
			send_to_char(AT_RED, buf, ch);

	        	act(AT_RED, "$n combines two rolls of leather." , ch, NULL, NULL, TO_ROOM);

			extract_obj(obj);
			extract_obj(obj2);

			obj_to_char(skin, ch);

			return SKPELL_NO_DAMAGE; 
		} else
		{
			send_to_char(AT_RED, "You fail to combine the two rolls of leather, destroying both of them!\n\r", ch);
			act(AT_RED, "$n attempts to combine two rolls of leather, but fails!", ch, NULL, NULL, TO_ROOM);
			extract_obj(obj);
			extract_obj(obj2);

			return SKPELL_BOTCHED;
		}

	} else
	{
		send_to_char(AT_RED, "You can only skin corpses. What are you thinking?\n\r", ch);
		return SKPELL_BOTCHED;
	}

	if (number_percent() - 20 < ( ch->pcdata->learned[sn] / 10 ) )
	{
		int learned = ch->pcdata->learned[sn];

		skin = create_object( get_obj_index( OBJ_VNUM_LEATHER ), obj->level );

		skin->item_type = ITEM_SKIN;
		if (obj->item_type == ITEM_ARMOR)
		{
			skin->level 	= obj->level;
			skin->value[1]  = 1 + obj->level * number_range(1, learned / 10) / 100;
		}
		else
		{

			skin->level	= UMIN( 105, (get_mob_index( obj->value[1] ))->level);
			skin->value[1]  = (get_mob_index( obj->value[1] ))->size      /* mob size   		*/
					   * number_range(1, learned / 40) 	      /* x (multi by) 1 to 25 */
					   / 10					      /* / (divide by) 10       */
					   + UMAX(1, ( skin->level / 25 ) ); 	      /* + (plus) 1 to 4	*/
		}

		skin->weight = number_range( skin->value[1]/2, skin->value[1] );

		if (learned == 1000)
		{
			skin->value[0]=number_range(SKIN_GOOD, SKIN_PERFECT);
		}
		else if (learned > 750)
		{
			if (number_percent() < 25)
				skin->value[0]=number_range(SKIN_GOOD, SKIN_PERFECT);
			else
				skin->value[0]=number_range(SKIN_DECENT, SKIN_EXCELLENT);
		}
		else if (learned > 500)
		{
			if(number_percent() < 10)
				skin->value[0]=number_range(SKIN_GOOD, SKIN_PERFECT);
			else if (number_percent() < 30)
				skin->value[0]=number_range(SKIN_DECENT, SKIN_EXCELLENT);
			else
				skin->value[0]=number_range(SKIN_LOUSY, SKIN_DECENT);
		} else
		{
			if(number_percent() < 5)
				skin->value[0]=number_range(SKIN_GOOD, SKIN_PERFECT);
			else if (number_percent() < 15)
				skin->value[0]=number_range(SKIN_DECENT, SKIN_EXCELLENT);
			else if (number_percent() < 30)
				skin->value[0]=number_range(SKIN_LOUSY, SKIN_DECENT);
			else
				skin->value[0]=number_range(SKIN_DESTROYED, SKIN_PASSABLE);
		}

		strcpy(buf2, set_skin_quality(skin) );

		obj_to_char(skin, ch );

		sprintf(buf, "You skillfully scrape the leather creating %d yards of %s leather!\n\r", skin->value[1], buf2);
		send_to_char(AT_RED, buf, ch);
		sprintf(buf, "$n scrapes the %s for its leather.", obj->short_descr);
	        act(AT_RED, buf, ch, NULL, NULL, TO_ROOM);
	}
	else
	{
		send_to_char(AT_RED, "You mangle the skin. You've destroyed it!\n\r", ch);
		act(AT_RED, "$n thoroughly dices a corpse, but it yields no leather!", ch, NULL, NULL, TO_ROOM);
	}

	extract_obj(obj);

	return SKPELL_ZERO_DAMAGE;
}

// tan hides for armor
int skill_tan( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA* skin 	 = (OBJ_DATA*) vo;
	OBJ_DATA* needle = get_obj_carry(ch, "needle");
	OBJ_DATA* armor  = NULL;

	char buf [MAX_STRING_LENGTH];
	char arg1[MAX_STRING_LENGTH];
	char arg2[MAX_STRING_LENGTH];
	
	int yards = 0;
	int loc   = 0;
	int lvl   = 0;
	int bonus = 0;
 
	if (IS_NPC(ch))
		return SKPELL_BOTCHED;

	if (skin->item_type != ITEM_SKIN)
	{
		send_to_char(AT_ORANGE, "You need to use leather to tan!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	if (!needle || needle->item_type != ITEM_NEEDLE)
	{
		send_to_char(AT_ORANGE, "You need a needle to tan leather!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	if (!IS_SET(ch->in_room->room_flags, ROOM_TANNERY))
	{
		send_to_char(AT_ORANGE, "You need to be in a tannery to tan leather!\n\r", ch);
		return SKPELL_BOTCHED;
	}


	target_name = one_argument(target_name, arg1);
	target_name = one_argument(target_name, arg1); /* Repeat to throw away first arg */
	target_name = one_argument(target_name, arg2); 
	
	if (arg1[0]=='\0' || !is_number(arg1))
	{
		send_to_char(AT_ORANGE, "You need to choose how many yards of leather you will use!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	yards = atoi( arg1 );

	if (!yards)
	{
		send_to_char(AT_ORANGE, "You need to choose how many yards of leather you will use!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	if ( yards > skin->value[1] )
	{
		sprintf(buf, "Your %s doesn't contain enough leather.\n\rChoose another roll or combine two rolls.\n\r", skin->short_descr);
		send_to_char(AT_ORANGE, buf, ch );
		return SKPELL_BOTCHED;
	} else if ( yards <= 0)
	{
		send_to_char(AT_ORANGE, "How many yards of leather do you plan on using?\n\r", ch);
		return SKPELL_BOTCHED;
	}

	if (arg2[0]=='\0' || !is_number(arg2))
	{
		lvl = ch->level;
	} else
	{
		lvl = atoi( arg2 );

		if (lvl <= 0)
			lvl = ch->level;

		if (lvl > ch->level)
		{
			send_to_char(AT_ORANGE, "You can't try to make an item high level than you are!\n\r", ch);
			return SKPELL_BOTCHED;
		}
		lvl = UMIN( lvl, ch->level );
	}


	if ( lvl > yards )
	{
		send_to_char(AT_ORANGE, "You need at least 1 yard per level of item you are creating!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	/* extra leather supplied */
	bonus = yards - lvl;
        /* difficulty for levelv */
	bonus += skin->value[0] - (lvl/5);
	bonus = UMAX( bonus, 25 ); /* cap the bonus. not sure on value yet */

	do 
	{
		loc   = (int) pow(2,number_range(2, 20)) + ITEM_TAKE; /* generate a valid wear loc */
	} while (loc == ITEM_WIELD + ITEM_TAKE || loc == ITEM_PROTOTYPE + ITEM_TAKE || loc == ITEM_WEAR_CONTACT + ITEM_TAKE );

	skin->value[1] -= yards;
	if (skin->value[1] <= 0)
	{
		extract_obj( skin );	
		send_to_char( AT_ORANGE, "You use all of your leather roll.\n\r", ch );
	} else
	{
		set_skin_quality(skin);
	}

	if (number_percent() < (((ch->pcdata->learned[sn]/10)+bonus)))
	{
		int max_extra 	= 0;
		int cur_extra 	= 0;
		int bv			= 2;
		int rescount	= 0;
		int statcount	= 0;
		send_to_char(AT_ORANGE, "You skillfully tan and sew the leather!\n\r", ch);

		armor = create_object( get_obj_index(OBJ_VNUM_TANNED), lvl);

		armor->weight		= number_range(5, 15);
		armor->level 	 	= lvl;
		armor->wear_flags  	= loc;
		armor->cost	 	= lvl;
		armor->durability_max	= number_fuzzy(skin->value[0]) * number_fuzzy(lvl/10);
		armor->durability_cur	= number_range(armor->durability_max/4, armor->durability_max);

		max_extra = lvl / 17 + 1; /* 2->7 affects plus 2 possible spells */

		cur_extra = 0;
		while (bv <= ITEM_ACID && cur_extra < max_extra )
		{
			if (number_percent() < 10 && bv != ITEM_INVENTORY && bv != ITEM_PATCHED && bv != ITEM_LOCK)
			{
				cur_extra++;
				armor->extra_flags += bv;
			}
			bv *= 2;
		}

		bv = 0;
		while (bv <= ITEM_DISPEL && cur_extra < max_extra )
		{
			if (number_percent() < 10 )
			{
				cur_extra++;
				armor->extra_flags2 += bv;
			}
			bv *= 2;
		}

		SET_BIT(armor->extra_flags2, ITEM_CRAFTED);

		/* ac */
		armor->value[0]	= number_fuzzy( level / 4 + 2 );

		/* applies */
		for (cur_extra = 0; cur_extra < max_extra; cur_extra++)
		{
			int apply = 0;
			int amt   = 0;
			int pct   = 0;
			AFFECT_DATA* pAf;

			pct = number_percent();
			if (pct<5)
			{
				if (rescount >= 2) 
					continue;

				rescount++;
				
				apply = number_range(APPLY_DAM_ACID, APPLY_DAM_WATER );
				if (loc == WEAR_BODY || loc == WEAR_HOLD || loc == WEAR_SHIELD)
					amt = number_range( - lvl / 10, lvl / 4 );
				else if (loc == ITEM_WEAR_FINGER || loc == ITEM_WEAR_NECK || loc == ITEM_WEAR_ORBIT || loc == ITEM_WEAR_ANKLE || loc == ITEM_WEAR_WRIST || loc == ITEM_WEAR_WAIST )
					amt = number_range( 1, lvl / 20 );
				else
					amt = number_range( -1, lvl / 10);

			} else if (pct < 20)
			{
				apply = APPLY_SAVING_SPELL;
				amt   = 0 - number_range(lvl / 20 , lvl / 5 );
				if (lvl > 100)
					amt -= number_range(0, 20);
			} else if (pct < 50)
			{
				if (statcount >= 2)
					continue;

				statcount++;

				apply = number_range(APPLY_STR,APPLY_CON);
				amt = number_range(1, (lvl / 30) + 1 );
			} else if (pct < 75 )
			{
				apply = number_range(APPLY_SEX, APPLY_ANTI_DIS);
				switch(apply)
				{
				default:
					cur_extra--;
					continue;
					break; /* you got hosed */
				case APPLY_MANA:
					amt = number_range(lvl / 5, lvl   );
										amt = number_range(lvl / 5, lvl   );
					if (lvl > LEVEL_HERO)
						amt += number_range(0, (lvl - LEVEL_HERO) / 4);
					break;
				case APPLY_BP:
					amt = number_range(lvl / 10 , lvl / 3);
					amt = number_range(lvl / 5, lvl   );
					if (lvl > LEVEL_HERO)
						amt += number_range(0, (lvl - LEVEL_HERO) * 20);
					break;
				case APPLY_HIT:
					amt = number_range(lvl / 5, lvl   );
					if (lvl > LEVEL_HERO)
						amt += number_range(0, (lvl - LEVEL_HERO) * 20);
					break;
				case APPLY_MOVE:
					amt = number_range(lvl, lvl * 2 );
					break;
				case APPLY_AC:
					amt = 0 - number_range(lvl / 5, lvl + 50 );
					if (lvl > LEVEL_HERO)
						amt -= number_range(0, (lvl - LEVEL_HERO) * 10);
					break;
				case APPLY_HITROLL:
				case APPLY_DAMROLL:
					if (loc==ITEM_WEAR_BODY)
						amt = number_range( lvl / 5, lvl / 2 );
					else
						amt = number_range( level / 10, level / 3 );
					break;
				case APPLY_ANTI_DIS:
					amt = number_range( lvl / 5, lvl );
					break;
				}
			}

			if (apply)
			{
				bool found = FALSE;
				for (pAf = armor->affected; pAf; pAf=pAf->next)
				{
					if (pAf->location == apply)
					{
						found = TRUE;
						break;
					}
				}
				if (found)
				{
					cur_extra--;
					continue;
				}

				pAf             =   new_affect();
				pAf->location   =   apply;
				if (amt < 0)
					pAf->modifier   =  -number_fuzzy( -amt );
				else
					pAf->modifier   =   number_fuzzy(amt);
				pAf->type       =   0;
				pAf->duration   =   -1;
				pAf->bitvector  =   0;
				pAf->next       =   armor->affected;
				pAf->type		=	0;
				armor->affected =   pAf;

				/* if you got hitroll, you got damroll */
				if (apply == APPLY_HITROLL || apply == APPLY_DAMROLL)
				{
					if (apply == APPLY_HITROLL)
						apply = APPLY_DAMROLL;
					else
						apply = APPLY_HITROLL;

					pAf             =   new_affect();
					pAf->location   =   apply;
					pAf->modifier   =   number_fuzzy(amt);
					pAf->type		=	0;
					pAf->duration   =   -1;
					pAf->bitvector  =   0;
					pAf->next       =   armor->affected;
					armor->affected =   pAf;

				}
			}
		}

		/* perm spells */
		if (lvl > 30 && number_percent() < 10)
		{
			AFFECT_DATA* pAf = new_affect();
			pAf = new_affect();
			do
			{
				pAf->location = number_range(PERM_SPELL_BEGIN, PERM_SPELL_END);
			} while ( !valid_aff_loc(pAf->location) );

			pAf->type	=   skill_lookup(affect_loc_name(pAf->location));
			if (pAf->type < 0)
			{
				pAf->type = 0;
				sprintf(buf, "skill_tanning: affect name for: %s does not match sn for skill_lookup", affect_loc_name(pAf->location) );
				bug(buf, 0);
			}
			pAf->modifier   =   -1;
			pAf->duration   =   -1;
			pAf->bitvector  =   0;
			pAf->next       =   armor->affected;
			armor->affected =   pAf;
		}

		if (number_percent() < 3 && lvl > LEVEL_HERO)
		{
			AFFECT_DATA* pAf = new_affect();
			pAf = new_affect();
			do
			{
				pAf->location = number_range(PERM_SPELL_BEGIN, PERM_SPELL_END );
			} while (!valid_aff_loc(pAf->location) );

			pAf->type	=   skill_lookup(affect_loc_name(pAf->location));
			if (pAf->type < 0)
			{
				pAf->type = 0;
				sprintf(buf, "skill_tanning: affect name for: %s does not match sn for skill_lookup", affect_loc_name(pAf->location) );
				bug(buf, 0);
			}

			pAf->modifier   =   -1;
			pAf->duration   =   -1;
			pAf->bitvector  =   0;
			pAf->next       =   armor->affected;
			armor->affected =   pAf;
		}


		send_to_char(AT_ORANGE, "You manage to create:\n\r", ch);
		sprintf(buf, "%s\n\r", name_tanned_armor(armor));
		send_to_char(AT_WHITE, buf, ch);
 
		obj_to_char(armor, ch);

		if (number_percent() < 10)
		{
			send_to_char(AT_CYAN, "Your needle breaks!\n\r", ch);
			extract_obj(needle);
		}

		act(AT_ORANGE, "$n skillfully tans and stitches together some new armor!", ch, NULL, NULL, TO_ROOM);
        } else
	{
		if (number_percent() < 25)
		{
			send_to_char(AT_CYAN, "You break your needle in the attempt!\n\r", ch);
			extract_obj( needle );
		} 
		send_to_char(AT_ORANGE, "Your attempt at tanning fails miserably!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	return SKPELL_ZERO_DAMAGE;
}

/* Helper function to avoid repetitive code */
char* set_skin_quality(OBJ_DATA* skin)
{
	static char buf    [MAX_STRING_LENGTH];
	static char quality[MAX_STRING_LENGTH];

	if (skin->item_type != ITEM_SKIN)
	{
		bug("set_skin_quality: object is not a skin!", 0);
		return NULL;
	}

	strcpy(quality, flag_string(quality_flags, skin->value[0]));

	sprintf(buf, (get_obj_index( OBJ_VNUM_LEATHER ))->short_descr, skin->value[1], quality);	
	free_string(skin->short_descr);
	skin->short_descr = str_dup(buf);

	sprintf(buf, (get_obj_index( OBJ_VNUM_LEATHER ))->description, quality);	
	free_string(skin->description);
	skin->description = str_dup(buf);
	
	return quality;
}

char* name_tanned_armor(OBJ_DATA* armor)
{

	char prefix1	[MAX_STRING_LENGTH] = "";
	char prefix2	[MAX_STRING_LENGTH] = "";
	char location	[MAX_STRING_LENGTH] = "";
	char suffix1	[MAX_STRING_LENGTH] = "";
	char suffix2	[MAX_STRING_LENGTH] = "";
	
	char format	[MAX_STRING_LENGTH] = "%s%s%s of %s%s";

	static char final[MAX_STRING_LENGTH] = "";

	char first = 0;
	char last  = 0;

	int e1 = armor->extra_flags;
	int e2 = armor->extra_flags2;

	AFFECT_DATA* paf = NULL;

	switch (armor->wear_flags - ITEM_TAKE)
	{
	case ITEM_WEAR_FINGER: strcpy(location, "ring"); break;
	case ITEM_WEAR_NECK: 
	{
		int pct = number_percent();
		if (pct < 20)
			strcpy(location, "Scarf");
		else if (pct < 40)
			strcpy(location, "Chain");
		else if (pct < 60)
			strcpy(location, "Choker");
		else
			strcpy(location, "Necklace");
	}
	break;
	case ITEM_WEAR_BODY:
	{
		int pct = number_percent();
		if (pct < 10)
			strcpy(location, "Breastplate");
		else if (pct < 20)
			strcpy(location, "Leather");
		else if (pct < 30)
			strcpy(location, "Studded Leather");
		else if (pct < 40)
			strcpy(location, "Padded Leather");
		else if (pct < 50)
			strcpy(location, "Banded Leather");
		else if (pct < 75)
			strcpy(location, "Cured Leather");
		else	
			strcpy(location, "Hide");
	}
	break;
	case ITEM_WEAR_HEAD:
	{
		int pct = number_percent();
		if (pct < 30)
			strcpy(location, "Headdress");
		else if (pct < 60)
			strcpy(location, "Helm");
		else 
			strcpy(location, "Helmet");
	}
	break;
	case ITEM_WEAR_LEGS: strcpy(location, "Leggings"); break;
	case ITEM_WEAR_FEET:
	{
		int pct = number_percent();
		if (pct < 25)
			strcpy(location, "Sandals");
		else if (pct < 50)
			strcpy(location, "Shoes");
		else	
			strcpy(location, "Boots");
	}
	break;
	case ITEM_WEAR_HANDS:
	if (number_percent() < 50)
		strcpy(location, "Gloves");
	else
		strcpy(location, "Gauntlets");
	break;
	case ITEM_WEAR_ARMS:	
	if (number_percent() < 50)
		strcpy(location, "Sleeves");
	else
		strcpy(location, "Vambraces");
	break;
	case ITEM_WEAR_SHIELD: strcpy(location, "Shield"); break;
	case ITEM_WEAR_ABOUT: strcpy(location, "Cloak"); break;
	case ITEM_WEAR_WAIST: strcpy(location, "Belt"); break;
	case ITEM_WEAR_WRIST: strcpy(location, "Bracelet"); break;
	case ITEM_HOLD:	strcpy(location, "Orb"); break;
	case ITEM_WEAR_ORBIT: strcpy(location, "Ball"); break;
	case ITEM_WEAR_FACE: strcpy(location, "Mask"); break;
	case ITEM_WEAR_EARS: strcpy(location, "Earrings"); break; 
	case ITEM_WEAR_ANKLE: strcpy(location, "Ankle Bracelet"); break;
	}

	/* Checked in reverse order. extra2 high->low, extra1 high->low
         * since low bits are more likely due to the algorithm, this gives
         * high order bits precedence for naming. (Otherwise you see a lot
         * of glowing and humming stuff)
         */
	if (IS_SET(e2, ITEM_DISPEL))
	{
		strcpy(prefix2, "Vortex ");
	} else if (IS_SET(e2, ITEM_SPARKING ))
	{
		strcpy(prefix2, "Lightning ");
	} else if (IS_SET(e2, ITEM_HIDDEN))
	{
		strcpy(prefix2, "Shadey ");
	} else if (IS_SET(e1, ITEM_ACID))
	{
		strcpy(prefix2, "Corrosive ");
	} else if (IS_SET(e1, ITEM_ICY))
	{
		strcpy(prefix2, "Freezing ");
	} else if (IS_SET(e1, ITEM_FLAME))
	{
		strcpy(prefix2, "Flaming ");
	} else if (IS_SET(e1, ITEM_POISONED))
	{
		strcpy(prefix2, "Virulent ");
	} else if (IS_SET(e1, ITEM_BLESS) || IS_SET(e2, ITEM_HOLY))
	{
		strcpy(prefix2, "Blessed ");
	} else if (IS_SET(e1, ITEM_NODROP) || IS_SET(e1, ITEM_NOREMOVE))
	{
		strcpy(prefix2, "Cursed ");
	} else if (IS_SET(e1, ITEM_MAGIC))
	{
		strcpy(prefix2, "Magic ");
	} else if (IS_SET(e1, ITEM_INVIS))
	{
		strcpy(prefix2, "Translucent ");
	} else if (IS_SET(e1, ITEM_EVIL))
	{
		strcpy(prefix2, "Wicked ");
	} else if (IS_SET(e1, ITEM_DARK))
	{
		strcpy(prefix2, "Dark ");
	} else if (IS_SET(e1, ITEM_HUM))
	{
		strcpy(prefix2, "Vibrating ");
	} else if (IS_SET(e1, ITEM_GLOW))
	{
		strcpy(prefix2, "Bright ");
	} else
	{
		if (number_percent() < 50 )
			strcpy(prefix2, "Strange ");
		else
			strcpy(prefix2, "Queer ");
	}

	first = prefix2[0];
	last  = location[strlen(location)-1];

	if (last == 's')
		strcpy(prefix1, "");
	else if (first == 'A' || first == 'E' || first == 'I' || first == 'O' || first =='U')
		strcpy(prefix1, "an ");
	else
		strcpy(prefix1, "a ");		


	for (paf = armor->affected ; paf; paf = paf->next)
	{
		if (strcmp(suffix1, "") && strcmp(suffix2, ""))
			break;

		switch (paf->location)
		{
		case APPLY_STR: if (!strcmp(suffix1, "")) { strcpy(suffix1, "Steel "); }; break;
		case APPLY_DEX:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Quicksilver "); }; break;
		case APPLY_INT:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Mentats"); }; break;
		case APPLY_WIS:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Owls"); }; break;
		case APPLY_CON:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Dragonkind"); }; break;
		case APPLY_MANA:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "BattleMages"); }; break;
 		case APPLY_BP:      if (!strcmp(suffix2, "")) { strcpy(suffix2, "Vampires"); }; break;
    		case APPLY_ANTI_DIS:  if (!strcmp(suffix1, "")) { strcpy(suffix1, "Iron "); }; break;
    		case APPLY_HIT:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Healthiness"); }; break;
    		case APPLY_MOVE:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Swift "); }; break;
    		case APPLY_AC:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "BlackSmiths"); }; break;
    		case APPLY_HITROLL:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Aiming"); }; break;
    		case APPLY_DAMROLL:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Bloodmetal "); }; break;

	  	case APPLY_AGE_SPELL:		if (!strcmp(suffix1, "")) { strcpy(suffix1, "Old "); }; break;
      		case APPLY_ANGELIC_AURA: if (!strcmp(suffix1, "")) { strcpy(suffix1, "Angelic "); }; break;	
	  	case APPLY_ANTI_FLEE: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Spiders"); }; break;
      		case APPLY_AURA_ANTI_MAGIC: if (!strcmp(suffix1, "")) { strcpy(suffix1, "Dispelling "); }; break;		
	  	case APPLY_BEND_LIGHT:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Prismatic "); }; break;
      		case APPLY_BIOFEEDBACK: if (!strcmp(suffix1, "")) { strcpy(suffix1, "Controlled "); }; break;
	  	case APPLY_BLADE: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Blades"); }; break;
      		case APPLY_BLESS:		if (!strcmp(suffix1, "")) { strcpy(suffix1, "Blessed "); }; break;
	  	case APPLY_BLIND:		if (!strcmp(suffix2, "")) { strcpy(suffix2, "Justice"); }; break;
      		case APPLY_BLOODSHIELD: 	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Bloodrayne"); }; break;	
	  	case APPLY_CHANGE_SEX:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Homaphradite "); }; break;
      		case APPLY_CHAOS:         if (!strcmp(suffix2, "")) { strcpy(suffix2, "Insanity"); }; break;		
	  	case APPLY_CLOAKING:		if (!strcmp(suffix2, "")) { strcpy(suffix2, "Thieves"); }; break;
	  	case APPLY_CLOUD_OF_HEALING: if (!strcmp(suffix1, "")) { strcpy(suffix1, "Druidic "); }; break;
      		case APPLY_COFIRE:        if (!strcmp(suffix1, "")) { strcpy(suffix1, "Fire "); }; break;		
      		case APPLY_COMBAT_MIND:   if (!strcmp(suffix2, "")) { strcpy(suffix2, "Monks"); }; break;
	  	case APPLY_CONFUSED:		if (!strcmp(suffix1, "")) { strcpy(suffix1, "Dimwitted "); }; break;
	  	case APPLY_CURSE:			if (!strcmp(suffix2, "")) { strcpy(suffix2, "Caring"); }; break;
	  	case APPLY_CURSE_NATURE:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Nature's "); }; break;
	  	case APPLY_DANCING:		if (!strcmp(suffix2, "")) { strcpy(suffix2, "Twinkling"); }; break;
      		case APPLY_DETECT_EVIL:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Inquisition"); }; break;	
	  	case APPLY_DETECT_GOOD:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Slayers "); }; break;
      		case APPLY_DETECT_HIDDEN:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Eagle-Eyed "); }; break;	
      		case APPLY_DETECT_INVIS:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Astral-Eyed "); }; break;	
      		case APPLY_DETECT_MAGIC:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Magic-Eyed "); }; break;	
      		case APPLY_EARTHSHIELD: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Gaia"); }; break;		
      		case APPLY_ESSENCE_OF_GAIA: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Mother Earth"); }; break;		
      		case APPLY_ETHEREAL_SNAKE: if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Serpent "); }; break;		
      		case APPLY_ETHEREAL_WOLF: if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Wolf "); }; break;		
      		case APPLY_FAERIE_FIRE:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Visibility"); }; break;	
     	 	case APPLY_FIRESHIELD:    if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Fire Elemental "); }; break;
	  	case APPLY_FLAMING:		if (!strcmp(suffix1, "")) { strcpy(suffix1, "Everflaming "); }; break;
      		case APPLY_FLYING:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Winged "); }; break;	
      		case APPLY_FORCE_OF_NATURE: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Nature Warriors"); }; break;		
      		case APPLY_FORESTWALK:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Rangers"); }; break;	
	  	case APPLY_FUMBLE:		if (!strcmp(suffix2, "")) { strcpy(suffix2, "Butterfingers"); }; break;
      		case APPLY_GHOST_SHIELD:  if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Dead "); }; break;		
      		case APPLY_GIANT_STRENGTH:if (!strcmp(suffix2, "")) { strcpy(suffix2, "Cloud Giants"); }; break;		
      		case APPLY_GOLDEN_ARMOR:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Shiny "); }; break;	
      		case APPLY_GOLDEN_SANCTUARY: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Rightousness"); }; break;		
      		case APPLY_HASTE:		if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Hare "); }; break;
      		case APPLY_HEIGHTEN_SENSES:      if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Hound "); }; break;		
      		case APPLY_HIDE:		if (!strcmp(suffix2, "")) { strcpy(suffix2, "Stealth"); }; break;
      		case APPLY_HOLY_PROTECTION: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Gods Hand"); }; break;		
      		case APPLY_ICESHIELD:     if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Arctic "); }; break;  		
      		case APPLY_IMPROVED_HIDE: if (!strcmp(suffix1, "")) { strcpy(suffix1, "Thieves "); }; break;		
      		case APPLY_IMPROVED_INVIS:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Forgotten"); }; break;	
	  	case APPLY_INERTIAL:		if (!strcmp(suffix2, "")) { strcpy(suffix2, "Wall"); }; break;
      		case APPLY_INFRARED:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Dwarf "); }; break;	
      		case APPLY_INVISIBLE:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Unseen"); }; break;	
      		case APPLY_LEAF_SHIELD: if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Forest "); }; break;		
      		case APPLY_LIQUID_SKIN: if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Fish "); }; break;		
	  	case APPLY_MALIGNIFY:		if (!strcmp(suffix1, "")) { strcpy(suffix1, "Weakness "); }; break;
      		case APPLY_MIST: 		if (!strcmp(suffix1, "")) { strcpy(suffix1, "Fog "); }; break;
      		case APPLY_MOUNTAINWALK:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Cherpa "); }; break;	
      		case APPLY_NAGAROMS_CURSE: if (!strcmp(suffix1, "")) { strcpy(suffix1, "NAGAROM'S UNHOLY WRATH!!!111oneone!1"); }; break;		
      		case APPLY_OCCULUTUS_VISUM: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Visage"); }; break;		
      		case APPLY_PASS_DOOR:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Phantom Formed "); }; break;	
	  	case APPLY_PEACE: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Mediation"); }; break;
	  	case APPLY_PESTILENCE:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Plague "); }; break;
      		case APPLY_PLAINSWALK:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Foal "); }; break;	
	  	case APPLY_POWER_LEAK:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Fatigue"); }; break;
      		case APPLY_PRAYER:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Holiness"); }; break;	
      		case APPLY_PROTECT:	if (!strcmp(suffix1, "")) { strcpy(suffix1, "Darks Bane "); }; break;	
	  	case APPLY_PROTECTION_GOOD: if (!strcmp(suffix1, "")) { strcpy(suffix1, "Gods Bane "); }; break;
      		case APPLY_QUICKNESS:      if (!strcmp(suffix1, "")) { strcpy(suffix1, "Speed "); }; break;		
      		case APPLY_RANDOMSHIELD: if (!strcmp(suffix1, "")) { strcpy(suffix1, "the Unknown "); }; break;		
      		case APPLY_SANCTUARY:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Safety"); }; break;	
      		case APPLY_SATANIC_INFERNO: if (!strcmp(suffix2, "")) { strcpy(suffix2, "HellFury"); }; break;		
     		case APPLY_SCRY:          if (!strcmp(suffix1, "")) { strcpy(suffix1, "Farseeing "); }; break;		
      		case APPLY_SHADOW_IMAGE:  if (!strcmp(suffix1, "")) { strcpy(suffix1, "Ever-Ecplipsing "); }; break;		
      		case APPLY_SHOCKSHIELD:   if (!strcmp(suffix1, "")) { strcpy(suffix1, "Shocking "); }; break;		
	  	case APPLY_SLIT:		if (!strcmp(suffix1, "")) { strcpy(suffix1, "Gagging "); }; break;
      		case APPLY_SNEAK:		if (!strcmp(suffix1, "")) { strcpy(suffix1, "Silence "); }; break;
      		case APPLY_SWAMPWALK:	if (!strcmp(suffix2, "")) { strcpy(suffix2, "Moors"); }; break;	
	  	case APPLY_TALE_OF_TERROR: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Fear"); }; break;
      		case APPLY_TITAN_STRENGTH: if (!strcmp(suffix1, "")) { strcpy(suffix1, "Titan "); }; break;		
      		case APPLY_TONGUES: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Babel"); }; break;
	  	case APPLY_TORTURE: if (!strcmp(suffix1, "")) { strcpy(suffix1, "Soul "); }; break;
	  	case APPLY_TRUESIGHT: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Visions"); }; break;
		case APPLY_UNHOLY_STRENGTH: if (!strcmp(suffix2, "")) { strcpy(suffix2, "Demon Strength"); }; break;
		}
	}

	if (!strcmp(suffix1,"") && !strcmp(suffix2, ""))
	{
		strcpy(suffix1, "Insignificance");
	}

	sprintf(final, format, prefix1, prefix2, location, suffix1, suffix2);
	free_string(armor->short_descr);
	armor->short_descr = str_dup(final);

	sprintf(format, "A %s lies here upon the groud, discarded.", location);
	free_string(armor->description);
	armor->description = str_dup(format);

	sprintf(format, "%s %s %s%s", prefix2, location, suffix1, suffix2);
	free_string(armor->name);
	armor->name = str_dup(format);

	return final;
}

int skill_forestry( int sn, int level, CHAR_DATA *ch, void *vo )
{
	int i;
	int forest_count;
	ROOM_INDEX_DATA* room = ch->in_room;
	char buf[MAX_STRING_LENGTH];

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

	if (!IS_OUTSIDE(ch) || !IS_FOREST(ch))
	{
		send_to_char(AT_DGREEN, "You have to be outside in a forest to chop wood!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	if (IS_SET(room->timed_room_flags, ROOM_TIMED_DEFORESTED))
	{
		send_to_char(AT_DGREEN, "This forest has already been harvested!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	forest_count = 1;
	
	for (i = 0; i < MAX_DIR; i++)
	{
		if (room->exit[i] && IS_OUTSIDE(ch) && IS_FOREST(ch))
			forest_count++;
	}

	sprintf(buf, "%d forest rooms found!\n\r", forest_count);
	bug(buf, 0);

	set_timed_room_flags( ch->in_room, ROOM_TIMED_DEFORESTED, 600 );

	send_to_char(AT_GREEN, "Forestry isn't completed yet!\n\r", ch);
	return SKPELL_NO_DAMAGE;
}

int skill_fletching( int sn, int level, CHAR_DATA *ch, void *vo )
{
	send_to_char(AT_YELLOW, "Fletching isn't completed yet!\n\r", ch);
	return SKPELL_NO_DAMAGE;
}

int skill_mining( int sn, int level, CHAR_DATA *ch, void *vo )
{
	send_to_char(AT_DGREY, "Mining isn't completed yet!\n\r", ch);
	return SKPELL_NO_DAMAGE;
}

int skill_forging( int sn, int level, CHAR_DATA *ch, void *vo )
{
	send_to_char(AT_DGREY, "Forging isn't completed yet!\n\r", ch);
	return SKPELL_NO_DAMAGE;
}

void destroy_craft( CHAR_DATA* ch, bool failed )
{
	char buf[MAX_STRING_LENGTH];
	char* name; 
	PC_DATA* pc;

	if (IS_NPC(ch))
		return;

	pc = ch->pcdata;

	name = item_type_name(pc->craft_target);

	if (failed)
	{
		char verb[MAX_STRING_LENGTH];
		if (pc->craft_type == CRAFT_SCROLL)
			strcpy(verb, "burst into flames");
		else
			strcpy(verb, "explodes into pieces");

		sprintf(buf, "Your %s %s and disappears!\n\r", name, verb);
		send_to_char(AT_RED, buf, ch);
		send_to_char(AT_RED, "You must have made a mistake somewhere!\n\r\n\r", ch);
	}
	else
	{
		sprintf(buf, "The momentary distraction makes you ruin the %s!\n\r\n\r", name);
		send_to_char(AT_RED, "Your attempt at crafting is interrupted!\n\r", ch);
		send_to_char(AT_RED, buf, ch);
	}

	if (number_percent() < 25)
	{
		OBJ_DATA* o;
		int type = 0;

		if (pc->craft_type == CRAFT_SCROLL)
			type = ITEM_QUILL;
		else if (pc->craft_type == CRAFT_POTION)
			type = ITEM_PESTLE;

		if (type)
		{
			for (o = ch->carrying; o; o = o->next_content)
			{
				if ( o->item_type == type)
					break;
			}
			sprintf(buf, "Your %s breaks!\n\r", item_type_name(o) );
			send_to_char(AT_WHITE, buf, ch);
			extract_obj(o);
		}
	}

	pc->craft_timer = 0;
	pc->craft_type = 0;
	pc->spell1 = 0;
	pc->spell2 = 0;
	pc->spell3 = 0;
	extract_obj(pc->craft_target);
}

void finish_craft( CHAR_DATA* ch )
{
	PC_DATA* pc;
	char	 buf[MAX_STRING_LENGTH];

	if (IS_NPC(ch))
		return;

	pc = ch->pcdata;

	/* take care of stuff like having sleep cast on you */
	if (ch->position != POS_STANDING)
		destroy_craft(ch, FALSE);

	switch (pc->craft_type)
	{
	default:
		send_to_char(AT_RED, "You finished something...\n\r", ch);
		break;
	case CRAFT_POTION:
	{
		int lvl1, lvl2, lvl3;
		int pct1, pct2, pct3;
		int pct_scribe = pc->learned[skill_lookup("alchemy")]/10;
		if (pc->spell3)
		{
			int target = 0;

			lvl1 = UMIN( skill_table[pc->spell1].skill_level[ch->class], skill_table[pc->spell1].skill_level[ch->multied] );
			lvl2 = UMIN( skill_table[pc->spell2].skill_level[ch->class], skill_table[pc->spell2].skill_level[ch->multied] );
			lvl3 = UMIN( skill_table[pc->spell3].skill_level[ch->class], skill_table[pc->spell3].skill_level[ch->multied] );
			pct1 = pc->learned[pc->spell1]/10;
			pct2 = pc->learned[pc->spell2]/10;
			pct3 = pc->learned[pc->spell3]/10;

			target = (pct_scribe + ( (120-lvl1) + pct1) + ( (120-lvl2) + pct2/2) + ( (120-lvl3) + pct3/4) ) / 7;

			if (number_percent() < target )
			{
				spell_imprint(pc->spell1, ch->level, ch, pc->craft_target);
				spell_imprint(pc->spell2, ch->level, ch, pc->craft_target);
				spell_imprint(pc->spell3, ch->level, ch, pc->craft_target);
				act(AT_WHITE, "$n finishes brewing a potion.",  ch, NULL, NULL, TO_ROOM );
			} else
			{
				destroy_craft( ch, TRUE );
				act(AT_WHITE, "$n failed to brew a potion.",  ch, NULL, NULL, TO_ROOM );
				return;
			}
		
		} else if (pc->spell2)
		{
			int target = 0;

			lvl1 = UMIN( skill_table[pc->spell1].skill_level[ch->class], skill_table[pc->spell1].skill_level[ch->multied] );
			lvl2 = UMIN( skill_table[pc->spell2].skill_level[ch->class], skill_table[pc->spell2].skill_level[ch->multied] );
			pct1 = pc->learned[pc->spell1]/10;
			pct2 = pc->learned[pc->spell2]/10;

			target = (pct_scribe + ( (120-lvl1) + pct1) + ( (120-lvl2) + pct2/2) )  / 5;

			if (number_percent() < target )
			{
				spell_imprint(pc->spell1, ch->level, ch, pc->craft_target);
				spell_imprint(pc->spell2, ch->level, ch, pc->craft_target);
				act(AT_WHITE, "$n finishes brewing a potion.",  ch, NULL, NULL, TO_ROOM );
			} else
			{
				destroy_craft( ch, TRUE );
				act(AT_WHITE, "$n failed to brew a potion.",  ch, NULL, NULL, TO_ROOM );
				return;
			}
				
  		} else
		{
			int target = 0;

			lvl1 = UMIN( skill_table[pc->spell1].skill_level[ch->class], skill_table[pc->spell1].skill_level[ch->multied] );
			pct1 = pc->learned[pc->spell1]/10;

			target = (pct_scribe + ( (120-lvl1) + pct1) ) / 3;

			if (number_percent() < target )
			{
				spell_imprint(pc->spell1, ch->level, ch, pc->craft_target);
				act(AT_WHITE, "$n finishes brewing a potion.",  ch, NULL, NULL, TO_ROOM );
			} else
			{
				destroy_craft( ch, TRUE );
				act(AT_WHITE, "$n failed to brew a potion.",  ch, NULL, NULL, TO_ROOM );
				return;
			}

		}
	}
	break;	
	case CRAFT_SCROLL:
	{
		int lvl1, lvl2, lvl3;
		int pct1, pct2, pct3;
		int pct_scribe = pc->learned[skill_lookup("inscription")]/10;
		if (pc->spell3)
		{
			int target = 0;

			lvl1 = UMIN( skill_table[pc->spell1].skill_level[ch->class], skill_table[pc->spell1].skill_level[ch->multied] );
			lvl2 = UMIN( skill_table[pc->spell2].skill_level[ch->class], skill_table[pc->spell2].skill_level[ch->multied] );
			lvl3 = UMIN( skill_table[pc->spell3].skill_level[ch->class], skill_table[pc->spell3].skill_level[ch->multied] );
			pct1 = pc->learned[pc->spell1]/10;
			pct2 = pc->learned[pc->spell2]/10;
			pct3 = pc->learned[pc->spell3]/10;

			target = (pct_scribe + ( (120-lvl1) + pct1) + ( (120-lvl2) + pct2/2) + ( (120-lvl3) + pct3/4) ) / 7;

			if (number_percent() < target )
			{
				spell_imprint(pc->spell1, ch->level, ch, pc->craft_target);
				spell_imprint(pc->spell2, ch->level, ch, pc->craft_target);
				spell_imprint(pc->spell3, ch->level, ch, pc->craft_target);
				act(AT_WHITE, "$n finishes writing a scroll.",  ch, NULL, NULL, TO_ROOM );

			} else
			{
				destroy_craft( ch, TRUE );
				act(AT_WHITE, "$n failed to write a scroll.",  ch, NULL, NULL, TO_ROOM );
				return;
			}
		
		} else if (pc->spell2)
		{
			int target = 0;

			lvl1 = UMIN( skill_table[pc->spell1].skill_level[ch->class], skill_table[pc->spell1].skill_level[ch->multied] );
			lvl2 = UMIN( skill_table[pc->spell2].skill_level[ch->class], skill_table[pc->spell2].skill_level[ch->multied] );
			pct1 = pc->learned[pc->spell1]/10;
			pct2 = pc->learned[pc->spell2]/10;

			target = (pct_scribe + ( (120-lvl1) + pct1) + ( (120-lvl2) + pct2/2) )  / 5;

			if (number_percent() < target )
			{
				spell_imprint(pc->spell1, ch->level, ch, pc->craft_target);
				spell_imprint(pc->spell2, ch->level, ch, pc->craft_target);
				act(AT_WHITE, "$n finishes writing a scroll.",  ch, NULL, NULL, TO_ROOM );
			} else
			{
				destroy_craft( ch, TRUE );
				act(AT_WHITE, "$n failed to write a scroll.",  ch, NULL, NULL, TO_ROOM );
				return;
			}
				
  		} else
		{
			int target = 0;

			lvl1 = UMIN( skill_table[pc->spell1].skill_level[ch->class], skill_table[pc->spell1].skill_level[ch->multied] );
			pct1 = pc->learned[pc->spell1]/10;

			target = (pct_scribe + ( (120-lvl1) + pct1) ) / 3;

			if (number_percent() < target )
			{
				spell_imprint(pc->spell1, ch->level, ch, pc->craft_target);
				act(AT_WHITE, "$n finishes writing a scroll.",  ch, NULL, NULL, TO_ROOM );
			} else
			{
				destroy_craft( ch, TRUE );
				act(AT_WHITE, "$n failed to write a scroll.",  ch, NULL, NULL, TO_ROOM );
				return;
			}

		}
	}
	break;
	}

	if ( number_percent() < 10 )
	{
		OBJ_DATA* o;
		int type = 0;

		if (pc->craft_type == CRAFT_SCROLL)
			type = ITEM_QUILL;
		else if (pc->craft_type == CRAFT_POTION)
			type = ITEM_PESTLE;

		if (type)
		{
			for (o = ch->carrying; o; o = o->next_content)
			{
				if ( o->item_type == type)
					break;
			}
			sprintf(buf, "Your %s breaks!\n\r", item_type_name(o) );
			send_to_char(AT_WHITE, buf, ch);
			extract_obj(o);
		}
	}

	pc->craft_target->level = ch->level;
	pc->craft_target->value[0] = ch->level;
	SET_BIT(pc->craft_target->extra_flags2, ITEM_CRAFTED);

	pc->craft_target = NULL;
	pc->craft_timer  = 0;
	pc->craft_type   = 0;
	pc->spell1		 = 0;
	pc->spell2		 = 0;
	pc->spell3		 = 0;
}

int skill_brew ( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA* pestle;
    OBJ_DATA* vial;
    char buf   [MAX_STRING_LENGTH];
    char spell1[MAX_INPUT_LENGTH];
    char spell2[MAX_INPUT_LENGTH];
    char spell3[MAX_INPUT_LENGTH];
    int sn1;
    int sn2;
    int sn3;

    target_name = one_argument( target_name, spell1 );
    target_name = one_argument( target_name, spell2 );
    target_name = one_argument( target_name, spell3 );


    if ( spell1[0] == '\0' )
    {
	send_to_char(AT_WHITE, "Use alchemy on what spell?\n\r", ch );
	return SKPELL_BOTCHED;
    }

    if ( (vial = get_obj_carry(ch, spell1)) )
    {
	if (vial->item_type != ITEM_POTION)
	{
		send_to_char(AT_WHITE, "You can't empty an item that isn't a potion!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	extract_obj(vial);

	if (number_percent() > ( ( ch->pcdata->learned[skill_lookup("alchemy")]/10 + (120-vial->level) + (120-vial->value[0]) ) /2 ) )
	{
		send_to_char(AT_WHITE, "Oh no! You crack the vial. It's ruined!\n\r", ch);
		act( AT_WHITE, "$n cracks a vial while trying to empty it.\n\r", ch, NULL, NULL, TO_ROOM);
		return SKPELL_BOTCHED;
	}

	act( AT_WHITE, "$n empties a vial..\n\r", ch, NULL, NULL, TO_ROOM);
	send_to_char(AT_WHITE, "You empty the vial.\n\r", ch); 

	vial = create_object( get_obj_index( OBJ_VNUM_FLASK ), ch->level);
	obj_to_char(vial, ch);
	return SKPELL_NO_DAMAGE;
    }

    if ( (sn1 = skill_lookup(spell1)) < 0 || !ch->pcdata->learned[sn1] || !can_use_skspell(ch, sn1) )
    {
	sprintf(buf, "You don't know '%s'! How can you brew it?\n\r", spell1);
	send_to_char(AT_WHITE, buf, ch);
	return SKPELL_BOTCHED;
    }
    else if (!skill_table[sn1].is_spell)
    {
	sprintf(buf, "'%s' is not a spell!\n\r", spell1);
	send_to_char(AT_WHITE, buf, ch);
	return SKPELL_BOTCHED;
    }
    else if (!IS_SET(skill_table[sn1].craftable, CRAFT_POTION))
    {
	sprintf( buf, "You are unable to brew the spell '%s'\n\r", spell1);
	send_to_char(AT_WHITE, buf, ch);
	return SKPELL_BOTCHED;
    }


    if (spell2[0])
    {
        if ( (sn2 = skill_lookup(spell2) ) < 0 || !ch->pcdata->learned[sn2] || !can_use_skspell(ch, sn2) )

        {
		sprintf(buf, "You don't know '%s'! How can you brew it?\n\r", spell2);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
	}
	else if (!skill_table[sn2].is_spell)
	{
		sprintf(buf, "'%s' is not a spell!\n\r", spell2);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
	}
    	else if (!IS_SET(skill_table[sn2].craftable, CRAFT_POTION))
    	{
		sprintf( buf, "You are unable to brew the spell '%s'\n\r", spell2);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
    	}

    } else
    {
	sn2 = 0;
    }

    if (spell3[0])
    {
        if ( (sn3 = skill_lookup(spell3) ) < 0 || !ch->pcdata->learned[sn3] || !can_use_skspell(ch, sn3) )

        {
		sprintf(buf, "You don't know '%s'! How can you brew it?\n\r", spell3);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
	}
	else if (!skill_table[sn3].is_spell)
	{
		sprintf(buf, "'%s' is not a spell!\n\r", spell3);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
	}
    	else if (!IS_SET(skill_table[sn3].craftable, CRAFT_POTION))
    	{
		sprintf( buf, "You are unable to brew the spell '%s'\n\r", spell3);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
 	}
    } else
    {
	sn3 = 0;
    }

    /* Do we have a parchment to scribe spells? */
    for ( vial = ch->carrying; vial; vial = vial->next_content )
    {
	if ( vial->item_type == ITEM_POTION && 
		!(vial->value[0] || vial->value[1] || vial->value[2] || vial->value[3]) )
	    break;
    }
    if ( !vial )
    {
	send_to_char(AT_WHITE, "You do not have an empty vial.\n\r", ch );
	return SKPELL_BOTCHED;
    }   

    for ( pestle = ch->carrying; pestle; pestle = pestle->next_content )
    {
	if ( pestle->item_type == ITEM_PESTLE )
	    break;
    }
    if ( !pestle )
    {
	send_to_char(AT_WHITE, "You do not have a pestle and mortar.\n\r", ch );
	return SKPELL_BOTCHED;
    }
    
    act(AT_WHITE, "$n begins brewing a potion.", ch, vial, NULL, TO_ROOM );
    send_to_char(AT_WHITE, "You begin to carefully brew the potion.\n\r", ch);

    ch->pcdata->spell1 		= sn1;
    ch->pcdata->spell2 		= sn2;
    ch->pcdata->spell3 		= sn3;
    ch->pcdata->craft_target 	= vial;
    ch->pcdata->craft_type   	= CRAFT_POTION;
    ch->pcdata->craft_timer  	= ( MANA_COST( ch, sn1)
					+ (sn2 ? MANA_COST(ch, sn2) : 0 ) 
					+ (sn3 ? MANA_COST(ch, sn3) : 0 ) );


    return SKPELL_NO_DAMAGE;
}

int skill_inscription ( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA* quill;
    OBJ_DATA* parch;
    char buf   [MAX_STRING_LENGTH];
    char spell1[MAX_INPUT_LENGTH];
    char spell2[MAX_INPUT_LENGTH];
    char spell3[MAX_INPUT_LENGTH];
    int sn1;
    int sn2;
    int sn3;

    target_name = one_argument( target_name, spell1 );
    target_name = one_argument( target_name, spell2 );
    target_name = one_argument( target_name, spell3 );


    if ( spell1[0] == '\0' )
    {
	send_to_char(AT_WHITE, "Use inscription what spell?\n\r", ch );
	return SKPELL_BOTCHED;
    }

    if ( (parch = get_obj_carry(ch, spell1)) )
    {
	if (parch->item_type != ITEM_SCROLL)
	{
		send_to_char(AT_WHITE, "You can't scrape an item that isn't a scroll!\n\r", ch);
		return SKPELL_BOTCHED;
	}

	extract_obj(parch);

	if (number_percent() > ( ( ch->pcdata->learned[skill_lookup("inscription")]/10 + (120-parch->level) + (120-parch->value[0]) ) /2 ) )
	{
		send_to_char(AT_WHITE, "Oh no! You made a mistake. The scroll is ruined!\n\r", ch);
		act( AT_WHITE, "$n tears a scroll while trying to clear it.\n\r", ch, NULL, NULL, TO_ROOM);
		return SKPELL_BOTCHED;
	}

	act( AT_WHITE, "$n scrapes the words from a scroll.\n\r", ch, NULL, NULL, TO_ROOM);
	send_to_char(AT_WHITE, "You scrape the text from the scroll.\n\r", ch); 

	parch = create_object( get_obj_index( OBJ_VNUM_PARCHMENT ), ch->level);
	obj_to_char(parch, ch);
	return SKPELL_NO_DAMAGE;
    }

    if ( (sn1 = skill_lookup(spell1)) < 0 || !ch->pcdata->learned[sn1] || !can_use_skspell(ch, sn1) )
    {
	sprintf(buf, "You don't know '%s'! How can you scribe it?\n\r", spell1);
	send_to_char(AT_WHITE, buf, ch);
	return SKPELL_BOTCHED;
    }
    else if (!skill_table[sn1].is_spell)
    {
	sprintf(buf, "'%s' is not a spell!\n\r", spell1);
	send_to_char(AT_WHITE, buf, ch);
	return SKPELL_BOTCHED;
    }
    else if (!IS_SET(skill_table[sn1].craftable, CRAFT_SCROLL))
    {
	sprintf( buf, "You are unable to scribe the spell '%s'\n\r", spell1);
	send_to_char(AT_WHITE, buf, ch);
	return SKPELL_BOTCHED;
    }


    if (spell2[0])
    {
        if ( (sn2 = skill_lookup(spell2) ) < 0 || !ch->pcdata->learned[sn2] || !can_use_skspell(ch, sn2) )

        {
		sprintf(buf, "You don't know '%s'! How can you scribe it?\n\r", spell2);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
	}
	else if (!skill_table[sn2].is_spell)
	{
		sprintf(buf, "'%s' is not a spell!\n\r", spell2);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
	}
    	else if (!IS_SET(skill_table[sn2].craftable, CRAFT_SCROLL))
    	{
		sprintf( buf, "You are unable to scribe the spell '%s'\n\r", spell2);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
    	}

    } else
    {
	sn2 = 0;
    }

    if (spell3[0])
    {
        if ( (sn3 = skill_lookup(spell3) ) < 0 || !ch->pcdata->learned[sn3] || !can_use_skspell(ch, sn3) )

        {
		sprintf(buf, "You don't know '%s'! How can you scribe it?\n\r", spell3);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
	}
	else if (!skill_table[sn3].is_spell)
	{
		sprintf(buf, "'%s' is not a spell!\n\r", spell3);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
	}
    	else if (!IS_SET(skill_table[sn3].craftable, CRAFT_SCROLL))
    	{
		sprintf( buf, "You are unable to scribe the spell '%s'\n\r", spell3);
		send_to_char(AT_WHITE, buf, ch);
		return SKPELL_BOTCHED;
 	}
    } else
    {
	sn3 = 0;
    }

    /* Do we have a parchment to scribe spells? */
    for ( parch = ch->carrying; parch; parch = parch->next_content )
    {
	if ( parch->item_type == ITEM_SCROLL && 
		!(parch->value[0] || parch->value[1] || parch->value[2] || parch->value[3] ))
	    break;
    }
    if ( !parch )
    {
	send_to_char(AT_WHITE, "You do not have a parchment.\n\r", ch );
	return SKPELL_BOTCHED;
    }

    for ( quill = ch->carrying; quill; quill = quill->next_content )
    {
	if ( quill->item_type == ITEM_QUILL )
	    break;
    }
    if ( !quill )
    {
	send_to_char(AT_WHITE, "You do not have a quill.\n\r", ch );
	return SKPELL_BOTCHED;
    }
    
    act(AT_WHITE, "$n begins writing a scroll.", ch, parch, NULL, TO_ROOM );
    send_to_char(AT_WHITE, "You begin to carefully write the scroll.\n\r", ch);

    ch->pcdata->spell1 		= sn1;
    ch->pcdata->spell2 		= sn2;
    ch->pcdata->spell3 		= sn3;
    ch->pcdata->craft_target 	= parch;
    ch->pcdata->craft_type   	= CRAFT_SCROLL;
    ch->pcdata->craft_timer  	= ( MANA_COST( ch, sn1)
					+ (sn2 ? MANA_COST(ch, sn2) : 0 ) 
					+ (sn3 ? MANA_COST(ch, sn3) : 0 ) );


    return SKPELL_NO_DAMAGE;
}

void spell_imprint( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA *obj = (OBJ_DATA *) vo;
    int       sp_slot, i, mana;
    char      buf[ MAX_STRING_LENGTH ];

     if (obj->deleted) { return; };

      if (skill_table[sn].spell_fun == spell_null )
      {
	send_to_char(AT_WHITE,"That is not a spell.\n\r",ch);
	return;
      }

    /* counting the number of spells contained within */

    for (sp_slot = i = 1; i < 4; i++) 
	if (obj->value[i] != skill_lookup("reserved"))
	    sp_slot++;

    if (sp_slot > 3)
    {
	act (AT_WHITE,"$p cannot contain any more spells.", ch, obj, NULL, TO_CHAR);
	return;
    }

   /* scribe/brew costs 4 times the normal mana required to cast the spell */

    mana = 4 * MANA_COST(ch, sn);
	    
    if ( !IS_NPC(ch) && ch->mana < mana )
    {
	send_to_char(AT_WHITE, "You don't have enough mana.\n\r", ch );
	return;
    }
      
    if ( IS_NPC( ch ) || ( number_percent() > ( ch->pcdata->learned[sn] / 10 ) && ch->level < L_SEN ) )
    {
	send_to_char(AT_WHITE, "You lost your concentration.\n\r", ch );
	ch->mana -= mana / 2;
	return;
    }

    /* executing the imprinting process */
    ch->mana -= mana;
    obj->value[sp_slot] = sn;

    /* Making it successively harder to pack more spells into potions or 
       scrolls - JH */ 

    if (ch->level < L_SEN )
    {
    switch( sp_slot )
    {
   
    default:
	bug( "sp_slot has more than %d spells.", sp_slot );
	return;

    case 1:
	break;
    case 2:
        if ( number_percent() > 80 )
        { 
          sprintf(buf, "The magic enchantment has failed --- the %s vanishes.\n\r", item_type_name(obj) );
	  send_to_char(AT_WHITE, buf, ch );
	  extract_obj( obj );
	  return;
	}     
	break;

    case 3:
        if ( number_percent() > 60 )
        { 
          sprintf(buf, "The magic enchantment has failed --- the %s vanishes.\n\r", item_type_name(obj) );
	  send_to_char(AT_WHITE, buf, ch );
	  extract_obj( obj );
	  return;
	}     
	break;
    }
    } /* If level < L_SEN */ 
  

    /* labeling the item */

    free_string (obj->short_descr);
    sprintf ( buf, "a %s of ", item_type_name(obj) ); 
    for (i = 1; i <= sp_slot ; i++)
      if (obj->value[i] != -1)
      {
	strcat (buf, skill_table[obj->value[i]].name);
        (i != sp_slot ) ? strcat (buf, ", ") : strcat (buf, "") ; 
      }
    obj->short_descr = str_dup(buf);

    free_string( obj->name );
    sprintf( buf, "%s ", item_type_name( obj ) );
    for( i = 1; i <= sp_slot; i++ )
	if( obj->value[i] != -1 )
	{
	    strcat( buf, skill_table[obj->value[i]].name);
	    (i != sp_slot ) ? strcat( buf, " ") : strcat( buf, "" );
	}
    obj->name = strdup( buf );

    free_string( obj->description );
    sprintf( buf, "A %s is here. (", item_type_name( obj ) );
    for( i = 1; i <= sp_slot; i++ )
	if( obj->value[i] != -1 )
	{
	    strcat( buf, skill_table[obj->value[i]].name);
	    (i != sp_slot ) ? strcat( buf, ", ") : strcat( buf, "" );
	}
    sprintf( buf, "%s).", buf );
    obj->description = strdup( buf );

    sprintf(buf, "You have imbued a new spell to the %s.\n\r", item_type_name(obj) );
    send_to_char(AT_WHITE, buf, ch );

    return; 
}

/* Study skill... converted from Rom by Maniac */ 
int skill_study( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA *scroll;

    return SKPELL_MISSED;

    if (( scroll = get_obj_carry(ch,target_name)) == NULL)
    {
        send_to_char(AT_WHITE,"You don't have that scroll.\n\r",ch);
        return SKPELL_BOTCHED;
    }

    if ( scroll->item_type != ITEM_SCROLL )
    {
        send_to_char(AT_WHITE,"You can only study scrolls.\n\r",ch);
        return SKPELL_BOTCHED;
    }

    if ( ch->level < scroll->level )
    {
        send_to_char(AT_WHITE,"You are not a high enough level to use this scroll.\n\r", ch );
        return SKPELL_MISSED;
    }

    if (( skill_table[scroll->value[1]].skill_level[ch->class] >= 72 )
        && ( !IS_IMMORTAL(ch) ))
    {
        send_to_char(AT_WHITE,"Your class may not learn that spell.\n\r",ch);
        return SKPELL_MISSED;
    }

    if ( skill_table[scroll->value[1]].skill_level[ch->class] > ch->level )
    {
        send_to_char(AT_WHITE,"This spell is beyond your grasp. Perhaps in a few levels...\n\r", ch );
        return SKPELL_MISSED;
    }

    if ( ch->pcdata->learned[scroll->value[1]] > 0 )
    {
        send_to_char(AT_WHITE,"You know that spell already!\n\r",ch);
        return SKPELL_MISSED;
    }

    act(AT_WHITE,"$n studies $p.",ch,scroll,NULL,TO_ROOM);
    act(AT_WHITE,"You study $p.",ch,scroll,NULL,TO_CHAR);

    if (number_percent() >= (20 + ( ch->pcdata->learned[skill_lookup("scrolls")] / 10 ) ) * 4/5)
    {
        send_to_char(AT_WHITE,"You mess up and the scroll vanishes!\n\r",ch);
        act(AT_WHITE,"$n screams in anger.",ch,NULL,NULL,TO_ROOM);
    }

    else
    {
        act(AT_WHITE,"You learn the spell!",ch,NULL,NULL,TO_CHAR);
        act(AT_WHITE,"$n learned the spell!",ch,NULL,NULL,TO_ROOM);
        ch->pcdata->learned[scroll->value[1]] = 50;
    }
    extract_obj(scroll);

    return SKPELL_NO_DAMAGE;
}

void strip_timed_room_flags( ROOM_INDEX_DATA* room)
{
	char buf[MAX_STRING_LENGTH];
	sprintf(buf, "Resetting flags for room: %d", room->vnum);
	log_string(  buf, CHANNEL_LOG, L_APP);
	room->timed_room_flags = 0;
}

void set_timed_room_flags( ROOM_INDEX_DATA* room, int flag, int timer )
{

	if (!room)
		return;

	SET_BIT(room->timed_room_flags, flag);
	room->flag_timer = UMAX( room->flag_timer, timer);

	room->next_timed_room = timed_room_list;
	timed_room_list = room;

	switch (flag)
	{
	case ROOM_TIMED_DEFORESTED:
	case ROOM_TIMED_MINED:
	case ROOM_TIMED_CAMP:
	default:
		/* do something. like... load a camp fire */
		break;
	}
}