Argila2.0/
Argila2.0/pp/
Argila2.0/pp/lib/save/objs/g/
Argila2.0/pp/lib/save/player/g/
Argila2.0/pp/regions/
Argila2.0/pp/regions/Lscripts/
Argila2.0/pp/src/lib/
/** 
*	\file crafts.c
*	Crafting Module
*
*	This module provides functionality for crafting, including creating new
*	crafts, adding and deleting crafts from a player, determining pre-requesites
*	for a craft, and ordering the list of crafts.
*
*	Copyright 2005, Mary C. Huston, All rights reserved.
*	Copyright (C) 2004, Shadows of Isildur: Traithe	
*
*	The program(s) may be used and/or copied only with written
*	permission or in accordance with the terms and conditions
*	stipulated in the license from DIKU GAMMA (0.0) and SOI.
*
*	\author Mary Huston
*	\author Email:  auroness@gmail.com
*
******************************************************************************
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "structs.h"
#include "protos.h"
#include "utils.h"
#include "decl.h"

#define s(a) send_to_char (a "\n", ch);

int missing_craft_items (CHAR_DATA *ch, AFFECTED_TYPE *af)
{
	char	*p = NULL;
	int 	missing_said = 0;
	int 	i = 0;
	int		item_required [MAX_ITEMS_PER_SUBCRAFT];
	OBJ_DATA  *obj_list [MAX_ITEMS_PER_SUBCRAFT];
	PHASE_DATA	*phase = NULL;
	DEFAULT_ITEM_DATA	*item = NULL;
	
					
	if ( !af->a.craft || !af->a.craft->subcraft )
		return 0;

	memset (item_required, 0, MAX_ITEMS_PER_SUBCRAFT * sizeof (int));
	memset (obj_list, 0, MAX_ITEMS_PER_SUBCRAFT * sizeof (OBJ_DATA *));

	for ( phase = af->a.craft->subcraft->phases; phase; phase = phase->next ) {
		for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {
			item = af->a.craft->subcraft->items [i];

			if ( !item ) {
				continue;
			}

			if ( !item->items [0] ) { /* No items in list.  Nothing required */
				continue;
			}
			
			obj_list [i] = get_item_obj (ch, item, phase);
		}

		if ( phase->first ) {
			for ( p = phase->first; *p; p++ ) {
				if ( *p == '$' ) {
					p++;
					if ( isdigit (*p) && strtol(p, NULL, 10) < MAX_ITEMS_PER_SUBCRAFT ){
						item_required [strtol(p, NULL, 10)] = 1;
					}
				}
			}
		} /* if (phase->first)   */      
	} /* for( phase = af->a.craft->subcraft->phases... */

	for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {

		if ( !item_required [i] ){
			continue;
		}

		if ( obj_list [i] ){
			continue;
		}
		
		item = af->a.craft->subcraft->items [i];

		if ( !item ) {
			continue;
		}

		if ( item && IS_SET (item->flags, SUBCRAFT_PRODUCED) ){
			continue;
		}
		
		if ( !missing_said ) {
			missing_said = 1;
			send_to_char ("\n#1You are missing one or more items:#0\n\n", ch);
			act ("$n stops doing $s craft.", FALSE, ch, 0, 0, TO_ROOM);
			af->a.craft->timer = 0;
		}

		if ( IS_SET (item->flags, SUBCRAFT_WORN) )
			missing_item_msg (ch, item, "You must wear ");
		
		else if ( IS_SET (item->flags, SUBCRAFT_HELD) )
			missing_item_msg (ch, item, "You must hold ");

		else if ( IS_SET (item->flags, SUBCRAFT_IN_ROOM) )
			missing_item_msg (ch, item, "In the room must be ");

		else if ( IS_SET (item->flags, SUBCRAFT_IN_INVENTORY) )
			missing_item_msg (ch, item, "You must have in your inventory ");

		else if ( IS_SET (item->flags, SUBCRAFT_WIELDED) )
			missing_item_msg (ch, item, "You must wield ");

		else
			missing_item_msg (ch, item, "You need ");
	} /* for ( i = 0;       */

	if ( missing_said )
		return 1;

	return 0;
}

AFFECTED_TYPE *is_craft_command (CHAR_DATA *ch, char *argument)
{
	int 	i = 0;
	SUBCRAFT_HEAD_DATA	*craft = NULL;
	AFFECTED_TYPE 		*af = NULL;
	char			command [MAX_STRING_LENGTH] = {'\0'};
	char			subcraft_name [MAX_STRING_LENGTH] = {'\0'};

	if ( IS_NPC (ch) )
		return NULL;

	if ( IS_MORTAL (ch) && ch->room && IS_SET (ch->room->room_flags, OOC) )
		return NULL;

	
	argument = one_argument (argument, command);
	
	
	snprintf (subcraft_name, MAX_STRING_LENGTH, "%s", argument);

	for ( craft = crafts; craft; craft = craft->next){
		if ( !str_cmp (command, craft->command) &&
			 !str_cmp (subcraft_name, craft->subcraft_name) )
			break;
	}
	
	if ( !craft )
		return NULL;

	if ( !IS_MORTAL(ch) ) {
		for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ ) {
			if ( !(af = get_affect (ch, i)) ){
				break;
			}
			else if ( af->a.craft->subcraft == craft ) {
				return af;
			}
		}

		magic_add_affect (ch, i, -1, 0, 0, 0, 0);
		af = get_affect (ch, i);
		af->a.craft = (struct affect_craft_type *)alloc (sizeof (struct affect_craft_type), 23);
		af->a.craft->subcraft = craft;
	}       

	else for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ ) {
		if ( !(af = get_affect (ch, i)) ){
			continue;
		}

		if ( af->a.craft->subcraft == craft ){
			break;
		}

		if ( i > CRAFT_LAST )
			return NULL;
	}
	return af;
}

void craft_command (CHAR_DATA *ch, char *command_args,
                                        AFFECTED_TYPE *craft_affect)
{
        char                    *argument;
        char                    buf [MAX_STRING_LENGTH] = {'\0'};
        CHAR_DATA               *target_ch = NULL;
        OBJ_DATA                *target_obj = NULL;
        SUBCRAFT_HEAD_DATA *subcraft;
        AFFECTED_TYPE           *af;
        bool                    sectors = FALSE, pass = FALSE;
        int                     i = 0;
                 
        subcraft = craft_affect->a.craft->subcraft;
                
        argument = one_argument (command_args, buf);            /* Toss subcraft name */
                                
        argument = one_argument (argument, buf);                        /* Target */
                         
        if ( *buf ) {
                if ( IS_SET (subcraft->subcraft_flags, SCF_TARGET_SELF) ) {
                        snprintf (buf, MAX_STRING_LENGTH,  "'%s %s' can only be done on you.\n",
                                        subcraft->command, subcraft->subcraft_name);
                        send_to_char (buf, ch);
                        return;
                }  
        
                else if ( IS_SET (subcraft->subcraft_flags, SCF_TARGET_OBJ) ) {
                        if ( !(target_obj = get_obj_in_dark (ch, buf, ch->right_hand)) &&
                                !(target_obj = get_obj_in_dark (ch, buf, ch->left_hand)) ) {
                                send_to_char ("You don't have that in your inventory.\n", ch);
                                return;
                        }
                }
        
                else if ( IS_SET (subcraft->subcraft_flags, SCF_AREA) ) {
                        send_to_char ("This is an area spell; it takes no target.\n", ch);
                        return;
                }
                                
                else if ( IS_SET (subcraft->subcraft_flags, SCF_TARGET_CHAR) ) {
                        if ( !(target_ch = get_char_room_vis (ch, buf)) ) {
                                send_to_char ("Your target isn't here.\n", ch);
                                return;
                        }
                }
        } else
                target_ch = ch;
                                                                        
        for ( af = ch->hour_affects; af; af = af->next ) {
                if ( af->type >= CRAFT_FIRST && af->type <= CRAFT_LAST && af->a.craft->timer ) {
                        send_to_char ("You are already crafting something.\n", ch);
                        return;
                }
        }
        
        craft_affect->a.craft->target_ch = target_ch;
        craft_affect->a.craft->target_obj = target_obj;
                 
        if ( get_affect (ch, MAGIC_CRAFT_DELAY) && craft_affect->a.craft->subcraft->delay && IS_MORTAL (ch) ) {
                act ("Sorry, but your OOC craft delay timer is still in place. You'll receive a notification when it expires and you're free to craft delayed items again.", FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
                return;
        }                       
        
        for ( i = 0; i <= MAX_SECTOR; i++ )
                if ( craft_affect->a.craft->subcraft->sectors[i] )
                        sectors = TRUE;
                        
        if ( sectors ) {
                for ( i = 0; i <= MAX_SECTOR; i++ )
                        if ( craft_affect->a.craft->subcraft->sectors[i]-1 == ch->room->sector_type )
                                pass = TRUE;
                if ( !pass ) {
                        send_to_char ("That craft cannot be performed in this sort of terrain.\n", ch);
                        return;
                }
        }
                                
        for ( i = 0; i <= 5; i++ )
                if ( craft_affect->a.craft->subcraft->seasons[i] )
                        sectors = TRUE;
                
        if ( sectors ) {
                for ( i = 0; i <= 5; i++ )
                        if ( craft_affect->a.craft->subcraft->seasons[i]-1 == time_info.season )
                                pass = TRUE;
                if ( !pass ) {
                        send_to_char ("That craft cannot be performed during this season.\n", ch);
                        return;
                }
        }
                 
        if ( missing_craft_items (ch, craft_affect) )
                return;
                                
        craft_affect->a.craft->phase = NULL;
 
        player_log (ch, craft_affect->a.craft->subcraft->command, craft_affect->a.craft->subcraft->subcraft_name);

       	activate_phase (ch, craft_affect);
}

void do_materials (CHAR_DATA *ch, char *argument, int cmd)
{
	int 		i = 0;
	int			clan_flags = 0;
	int			phase_num = 0;
	AFFECTED_TYPE		*af = NULL;
	SUBCRAFT_HEAD_DATA	*craft = NULL;
	PHASE_DATA 			*phase = NULL;
	char  		buf [MAX_STRING_LENGTH] = {'\0'};
	char 		buf2 [MAX_STRING_LENGTH] = {'\0'};
	char  		clan_name [MAX_STRING_LENGTH] = {'\0'};
	bool		flag_chk = FALSE;
	char   		*p = NULL;
	char		*temp_arg = NULL;
	CHAR_DATA	*temp_char = NULL;
	CLAN_DATA 	*clan_def;
	bool   		first = TRUE;

	argument = one_argument (argument, buf);

	if ( !*buf ) {
		send_to_char ("For which craft did you wish to obtain a materials list?\n", ch);
		return;
	}

	for ( craft = crafts;
		  craft && str_cmp (craft->subcraft_name, buf);
		  craft = craft->next )
		; /*cycle to the end*/

	if ( !craft ) {
		send_to_char ("No such craft.  Type 'crafts' for a listing.\n", ch);
		return;
	}

	for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ ) {
		if ( !(af = get_affect (ch, i)) )
			continue;

		if ( af->a.craft->subcraft == craft )
			break;
	}

	if ( i > CRAFT_LAST && IS_MORTAL(ch) ) {
		send_to_char ("That craft is not one your character has knowledge of.\n", ch);
		return;
	}

/** IMM information **/
	if ( !IS_MORTAL(ch) ) {
		*buf = '\0';   
		for ( i = 0; i <= 24; i++ ) {
			if ( craft->opening[i] > 0 ){
				snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  " %s", skill_data[craft->opening[i]].skill_name);
			}
		}

		if ( *buf ) {
			snprintf (buf2, MAX_STRING_LENGTH,  "#6Opening Craft For:#0%s\n", buf);
			send_to_char (buf2, ch);
		}
	}

/** Race check **/
	for ( i = 0; i <= LAST_PC_RACE; i++ ) {
		if ( craft->race[i] )
			flag_chk = TRUE;
	}

	if ( flag_chk ) {
		snprintf (buf, MAX_STRING_LENGTH,  "#6Available To:#0 ");

		for ( i = 0; i <= LAST_PC_RACE; i++ ){
			if ( craft->race[i] ){
				snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "%s ", db_race_table[craft->race[i]-1].name);
			}
		}
		snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "\n");
		send_to_char (buf, ch);
	}

/** Clan check **/
	flag_chk = FALSE;
        
	if ( craft->clans ) {
		snprintf (buf, MAX_STRING_LENGTH,  "#6Required Clans:#0 ");
		p = craft->clans;
		
		while ( get_next_clan (&p, clan_name, &clan_flags) ) {
			clan_def = get_clandef (clan_name);

			if ( !clan_def )
				continue;

			if ( !first ){
				snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "                ");
				}
			temp_arg = get_clan_rank_name(clan_flags);
			snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "%-30s [%s]\n", clan_def->literal, temp_arg);
			first = FALSE;
		}
		
		send_to_char (buf, ch);
	}

/** Sector check **/
	flag_chk = FALSE;
	
	for ( i = 0; i <= MAX_SECTOR; i++ ) {
		if ( craft->sectors[i] ){
			flag_chk = TRUE; 
		}
	}
	if ( flag_chk ) {
		snprintf (buf, MAX_STRING_LENGTH,  "#6Only Usable In:#0 ");

		for ( i = 0; i <= MAX_SECTOR; i++ ){
			if ( craft->sectors[i] ){
				snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "%s ", 
sector_types[craft->sectors[i]-1]);
			}
		}
		
		snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "\n");
		send_to_char (buf, ch);
	}

/** Season Check **/
	flag_chk = FALSE;

	for ( i = 0; i <= MAX_SEASONS; i++ ) {
		if ( craft->seasons[i] ){
			flag_chk = TRUE; 
		}
	}
	
	if ( flag_chk ) {
		snprintf (buf, MAX_STRING_LENGTH,  "#6Usable During:#0 ");

	for ( i = 0; i <= MAX_SEASONS; i++ ){
		if ( craft->seasons[i] ){
			snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "%s ", seasons[craft->seasons[i]-1]);
		}
	}

	snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "\n");
	send_to_char (buf, ch);
	}
	
/** Phases **/
	flag_chk = FALSE;
        
	for ( phase = craft->phases; phase; phase = phase->next ) {

		phase_num++;

		snprintf (buf, MAX_STRING_LENGTH,  "#5Phase %d:#0  %d seconds", phase_num, phase->phase_seconds);

		if ( phase->skill ) {      
			snprintf (ADDBUF, MAX_STRING_LENGTH, ", %s skill utilized.\n", skill_data[phase->skill].skill_name);
			  
		}
		
		else if ( phase->attribute > 0 ) {      
			snprintf (ADDBUF, MAX_STRING_LENGTH, ", %s attribute tested.\n", attrs[phase->attribute]);
			 
		}

		else {
		snprintf (ADDBUF, MAX_STRING_LENGTH, "\n");
			  
		}
		
		send_to_char (buf, ch);
		
		if ( phase->tool ){
			missing_item_msg (ch, phase->tool, "Tool required:  ");
		}

		for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {
			if ( craft->items [i] &&
				 craft->items [i]->phase == phase &&
				!IS_SET (craft->items [i]->flags, SUBCRAFT_PRODUCED) ) {

					if (IS_SET (craft->items[i]->flags, SUBCRAFT_HELD) ||   
						IS_SET (craft->items[i]->flags, SUBCRAFT_IN_INVENTORY) )
						missing_item_msg (ch, craft->items [i],
										"Held (Reusable):  ");
					else if ( IS_SET (craft->items[i]->flags, SUBCRAFT_IN_ROOM) )
						missing_item_msg (ch, craft->items [i],
										"In Room (Reusable):  ");
					else if ( IS_SET (craft->items[i]->flags, SUBCRAFT_USED) )
						missing_item_msg (ch, craft->items [i],
										"Held or in Room (Consumed):  ");
			}

			else if ( craft->items [i] &&
					  craft->items [i]->phase == phase &&
					  IS_SET (craft->items [i]->flags, SUBCRAFT_PRODUCED) )
						missing_item_msg (ch, craft->items [i],
										"#6Produced:#0  ");
		}

		if ( phase->load_mob && vtom(phase->load_mob) ) {
			temp_char = vtom(phase->load_mob);
			temp_arg = char_short(temp_char);
			snprintf (buf, MAX_STRING_LENGTH,  "#6Produced:#0 #5%s#0\n", temp_arg);
			send_to_char (buf, ch);
		}

		if ( GET_TRUST (ch) ) {
			if ( phase->attribute > 0 ) {
				snprintf (buf, MAX_STRING_LENGTH,  "  Attribute %s vs %dd%d\n",
						attrs [phase->attribute],
						phase->dice,
						phase->sides);
				send_to_char (buf, ch);
			}

			if ( phase->skill ) {
				snprintf (buf, MAX_STRING_LENGTH,  "  Skill %s vs %dd%d\n",
						skill_data[phase->skill].skill_name,
						phase->dice,
						phase->sides);
				send_to_char (buf, ch);
			}
		}
	}

	if ( craft->delay ) {
		snprintf (buf, MAX_STRING_LENGTH,  "#6OOC Delay Timer:#0 %d RL Hours\n", craft->delay);
		send_to_char (buf, ch);
	}
}

void do_crafts (CHAR_DATA *ch, char *argument, int cmd)
{
	CHAR_DATA		*tch = NULL;
	int				has_a_craft = 0;
	int				i = 0;
	int				j = 0;
	AFFECTED_TYPE 	*af = NULL;
	SUBCRAFT_HEAD_DATA	*craft = NULL;
	SUBCRAFT_HEAD_DATA	*tcraft = NULL;
	char			buf [MAX_STRING_LENGTH] = {'\0'};
	char 			name [MAX_STRING_LENGTH] = {'\0'};
	char 			output [MAX_STRING_LENGTH] = {'\0'};
	char  			craft_name [MAX_STRING_LENGTH] = {'\0'};
	char 			subcraft [MAX_STRING_LENGTH] = {'\0'};
	char 			command [MAX_STRING_LENGTH] = {'\0'};
	bool  			close_chk = FALSE;
	bool			opening_chk = FALSE;
	bool			category_chk = FALSE;
	bool			sectors_chk = FALSE;
	bool			seasons_chk = FALSE;
	bool			flag_chk = FALSE;
                                 
/** NPC? **/                                 
        if ( IS_NPC (ch) ) {
                send_to_char ("You shouldn't be using this command...\n", ch);
                return;
        }
                        
        argument = one_argument (argument, buf);

/** Mortals checking their available crafts **/
        if ( IS_MORTAL (ch) ) {
                if ( !*buf ) {
                        snprintf (output, MAX_STRING_LENGTH,  "You currently have crafts in the following areas:\n\n");
                        for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ ) {
                                if ( (af = get_affect (ch, i)) ) {
                                        if ( !strstr (output, af->a.craft->subcraft->craft_name) ) {
						j++;
						snprintf (output + strlen(output), MAX_STRING_LENGTH,  "   #6%-20s#0", af->a.craft->subcraft->craft_name);
						if ( !(j % 3) ){
							snprintf (output + strlen(output), MAX_STRING_LENGTH,  "\n");
					}
                                }
					has_a_craft = 1;
                        }
			} /* for i = CRAFT_FIRST*/

			if ( (j % 3) ){
				snprintf (output + strlen(output), MAX_STRING_LENGTH,  "\n");
			}

			if ( !has_a_craft ){
                                send_to_char ("You have no knowledge of any crafts.\n", ch);
                }
                else {
				page_string (ch->desc, output);
			}
		} /*if ( !*buf )*/
                else {
			j = 0;
			if ( !str_cmp (buf, "all") ){
	                        snprintf (output, MAX_STRING_LENGTH,  "You know the following crafts:\n\n");
			}
			else {
	                        snprintf (output, MAX_STRING_LENGTH,  "You know the following #6%s#0 crafts:\n\n", buf);
			}

                        for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ ) {
                                if ( (af = get_affect (ch, i)) ) {
					if ( str_cmp (buf, "all") &&
					     str_cmp (buf, af->a.craft->subcraft->craft_name) ){
						continue;
					}
					
					j++;
					snprintf (name, MAX_STRING_LENGTH, "%s %s", af->a.craft->subcraft->command, af->a.craft->subcraft->subcraft_name);
                                        snprintf (output + strlen(output), MAX_STRING_LENGTH,  "   #6%-30s#0", name);
                                        has_a_craft = 1;
					
					if ( !(j % 2) ){
						snprintf (output + strlen(output), MAX_STRING_LENGTH,  "\n");
                                }
                        }
			} /* for ( i = CRAFT_FIRST */

			if ( (j % 2) )
				snprintf (output + strlen(output), MAX_STRING_LENGTH,  "\n");

			if ( !has_a_craft ){
                                send_to_char ("You have no knowledge of any crafts.\n", ch);
			}
			else {
				page_string (ch->desc, output);
			}
                }
                                
                return;  
	} /* if ( IS_MORTAL (ch) */
                
/** Immortals commands for crafts **/
/** List all crafts **/
        if ( (!*buf && !ch->pc->edit_craft) || !str_cmp (buf, "list") ) {
                list_all_crafts (ch);
                return;
        }
                
/** Start a new craft **/
        else if ( !str_cmp (buf, "new") ) {
                argument = one_argument (argument, buf);
                snprintf (craft_name, MAX_STRING_LENGTH, "%s", buf);
		
                argument = one_argument (argument, buf);
                snprintf (subcraft, MAX_STRING_LENGTH, "%s", buf);

                argument = one_argument (argument, buf);
                snprintf (command, MAX_STRING_LENGTH, "%s", buf);
                
                if ( !*buf || !*craft_name || !*subcraft || !*command ) {
                        send_to_char ("The syntax is as follows: craft new <craft> <subcraft> <command>\n", ch);
                        return;
                }

                for ( craft = crafts; craft; craft = craft->next ) {
                        if ( !craft->next ) {
                                CREATE (craft->next, SUBCRAFT_HEAD_DATA, 1);
                                craft = craft->next;
                                break;
                        }
                }

                craft->craft_name = add_hash(craft_name);
                craft->subcraft_name = add_hash(subcraft);
                craft->command = add_hash(command);
                ch->pc->edit_craft = craft;
                send_to_char ("New craft initialized and opened for editing.\n", ch);
		mysql_safe_query ("INSERT INTO new_crafts VALUES ('%s', '%s', '%s', '%s')", craft->command, craft->subcraft_name, craft->craft_name, ch->tname);
                return;
        }
         
/** Clone a craft **/
        if ( !str_cmp (buf, "clone") ) {
                if ( !ch->pc->edit_craft ) {
                        send_to_char ("You'll need to open the craft you want to clone, first.\n", ch);
                        return;
                }

                argument = one_argument (argument, buf);
                if ( !*buf ) {
                        send_to_char ("You'll need to specify a craft name for the cloned craft.\n", ch);
                        return;
                }
		else {
			snprintf (craft_name, MAX_STRING_LENGTH, "%s", buf);
		}
		
                argument = one_argument (argument, buf);
                if ( !*buf ) {
                        send_to_char ("You'll need to specify a subcraft name for the cloned craft.\n", ch);
                        return;
                }
                else if ( !str_cmp (buf, ch->pc->edit_craft->subcraft_name) ) {
                        send_to_char ("You'll need to specify a different subcraft name for the cloned craft.\n", ch);
                        return;
                }
		else {
			snprintf (subcraft, MAX_STRING_LENGTH, "%s", buf);
		}

                argument = one_argument (argument, buf);
                if ( !*buf ) {
                        send_to_char ("You'll need to specify a command for the cloned craft.\n", ch);
                        return;
                }
		else {
			snprintf (command, MAX_STRING_LENGTH, "%s", buf);
		}
		
                CREATE (tcraft, SUBCRAFT_HEAD_DATA, 1);
                memset (tcraft, 0, sizeof(SUBCRAFT_HEAD_DATA));
                memcpy (tcraft, ch->pc->edit_craft, sizeof (SUBCRAFT_HEAD_DATA));
                CREATE (tcraft->phases, PHASE_DATA, 1);
                memset (tcraft->phases, 0, sizeof(PHASE_DATA));
                memcpy (tcraft->phases, ch->pc->edit_craft->phases, sizeof (PHASE_DATA));
		
                if (ch->pc->edit_craft->items > 0) {
                        for ( i = 0; ch->pc->edit_craft->items[i]; i++ ) {
                                CREATE (tcraft->items[i], DEFAULT_ITEM_DATA, 1);
                                memset (tcraft->items[i], 0, sizeof(DEFAULT_ITEM_DATA));
                        }
                        memcpy (tcraft->items, ch->pc->edit_craft->items, sizeof (DEFAULT_ITEM_DATA));
                }

                ch->pc->edit_craft = NULL;
                tcraft->craft_name = add_hash(craft_name);
                tcraft->subcraft_name = add_hash(subcraft);
                tcraft->command = add_hash(command);
                tcraft->next = NULL;

                for ( craft = crafts; craft; craft = craft->next ) {
                        if ( !craft->next ) {
                                CREATE (craft->next, SUBCRAFT_HEAD_DATA, 1);
                                craft->next = tcraft;
                                ch->pc->edit_craft = tcraft;
                                send_to_char ("Craft cloned; new craft opened for editing.\n", ch);
				mysql_safe_query ("INSERT INTO new_crafts VALUES ('%s', '%s', '%s', '%s')", tcraft->command, tcraft->subcraft_name, tcraft->craft_name, ch->tname);
                                return;
                        }
                }
        }
         
/** Look for sub-crafts within craft category **/
	for ( craft = crafts; craft; craft = craft->next ) {
		if ( !str_cmp (craft->subcraft_name, buf) ){
                        break;
		}
                if ( !str_cmp (craft->craft_name, buf) ) {
			flag_chk = TRUE;
                        break;
                }
        }
         
	if ( flag_chk ) {
                snprintf (output, MAX_STRING_LENGTH,  "\nWe have the following #6%s#0 crafts:\n\n", buf);
		
                for ( craft = crafts; craft; craft = craft->next ) {
			if ( !str_cmp (craft->craft_name, buf) ){
				snprintf (output + strlen(output), MAX_STRING_LENGTH,  "#6Craft:#0 %-12s #6Subcraft:#0 %-20s #6Command:#0 %-10s\n", craft->craft_name, craft->subcraft_name, craft->command);
			}
                }
                page_string (ch->desc, output);
                return;
        }
         

/** Check for crafts on a loaded PC **/
        if ( (tch = load_pc(buf)) ) {
                snprintf (output, MAX_STRING_LENGTH,  "\n#6%s#0 has the following crafts on %s pfile:\n\n", tch->tname, HSHR(tch));

                for ( af = tch->hour_affects; af; af = af->next ) {
                        if ( af->type >= CRAFT_FIRST && af->type <= CRAFT_LAST ) {
				snprintf (output + strlen(output), MAX_STRING_LENGTH,  "#6Craft:#0 %-12s #6Subcraft:#0 %-20s #6Command:#0 %-10s\n", af->a.craft->subcraft->craft_name, af->a.craft->subcraft->subcraft_name, af->a.craft->subcraft->command);
                        }
                }

                unload_pc (tch);
                page_string (ch->desc, output);
                return;
        }
         
/** Opening a craft for editing **/
	if ( !craft && *buf && !category_chk ){ 
		close_chk = TRUE;
	}
                
	if ( ch->pc->edit_craft ){
                craft = ch->pc->edit_craft;
	}
                
	if ( !craft && !category_chk ) {
                send_to_char ("No such subcraft.\n", ch);
                return;
        }
         
        if ( !ch->pc->edit_craft || ch->pc->edit_craft != craft ) {
                ch->pc->edit_craft = craft;
                send_to_char ("Craft has been opened for editing.\n", ch);
                return;
        }
	else if ( ch->pc->edit_craft && close_chk ) {
                send_to_char ("Craft closed and written to memory.\n", ch);
                ch->pc->edit_craft = NULL;
                return;
        }
         
/** Listing the craft **/
        *b_buf = '\0';
        snprintf (b_buf, MAX_STRING_LENGTH, "#6Craft:#0 %s #6Subcraft:#0 %s #6Command:#0 %s\n", craft->craft_name, craft->subcraft_name, craft->command);
        
/** Race listing **/
        for ( i = 0; i <= LAST_PC_RACE; i++ ) {
                if ( craft->race[i] ) {
			opening_chk = TRUE;
                }
        }
         
	if ( opening_chk ){
                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "  #6Race:#0");
		
                for ( i = 0; i <= LAST_PC_RACE; i++ ) {
                	if ( craft->race[i] ) {
                        snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "  %s", db_race_table[craft->race[i]-1].name);
                    }
				} 
		
				snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "\n");
        }
        
/** clan listing **/
	if ( craft->clans ){
                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "  #6Clans:#0 %s\n", craft->clans);
	}
                
	opening_chk = FALSE;
        *buf = '\0';
        for ( i = 0; i <= 24; i++ ) {
                if ( craft->opening[i] ) {
			opening_chk = TRUE;   
			snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  " %s", skill_data[craft->opening[i]].skill_name);
                }
        }
         
/** Sector listing **/
	if ( opening_chk ){
                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "  #6Base:#0  %s\n", buf);
	}
                
	for ( i = 0; i <= MAX_SECTOR; i++ ){
		if ( craft->sectors [i] ){
			sectors_chk = TRUE;
		}
	}
                        
	if ( sectors_chk ) {
                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "  #6Sectors:#0 ");
		for ( i = 0; i <= MAX_SECTOR; i++ ){
			if ( craft->sectors[i] ){
                                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "%s ", sector_types[craft->sectors[i]-1]);
			}
		}

                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "\n");
        }
         
/** Season listing **/
	for ( i = 0; i <= 5; i++ ){
		if ( craft->seasons [i] ){
			seasons_chk = TRUE;
		}
	}
                        
	if ( seasons_chk ) {
                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "  #6Seasons:#0 ");
		for ( i = 0; i <= 5; i++ ){
			if ( craft->seasons[i] ){
                                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "%s ", seasons[craft->seasons[i]-1]);
			}
		}
		
                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "\n");
        }
         
/** Delay listing **/
	if ( craft->delay ){
                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "  #6OOC Delay Timer:#0 %d RL Hours\n", craft->delay);
	}
                
/** Failure listings **/	
	if ( craft->failure ) {
                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "  #6Fail:#0 %s\n", craft->failure);
	}
                
	if ( craft->failobjs ){
                snprintf (b_buf + strlen(b_buf), MAX_STRING_LENGTH, "  #6Failobjs:#0 %s\n", craft->failobjs);
	}
                
        display_craft (ch, craft);
        
	return;
}      

void do_remcraft (CHAR_DATA *ch, char *argument, int cmd)
{
        CHAR_DATA                       *edit_mob;
        AFFECTED_TYPE           *af;
        AFFECTED_TYPE           *next_affect;
        SUBCRAFT_HEAD_DATA      *craft;
        char                            buf [MAX_STRING_LENGTH] = {'\0'};
        bool                    craft_category = FALSE;
                        
        argument = one_argument (argument, buf);
         
        if ( *buf == '?' ) {
                s ("Start by using the mob command on a PC.");
                s ("");
                s ("remcraft <subcraft-name>            Use crafts to get names");
                s ("");
                s ("   remcraft swordblank ");
                s ("");
                return;
        }
 
        if ( !(edit_mob = ch->pc->edit_player) ) {
                send_to_char ("Start by using the MOB command on a PC.\n", ch);
                return;
        }
                 
        for ( craft = crafts;
                  craft;
                  craft = craft->next ) {
                if ( !str_cmp (craft->subcraft_name, buf) )
                        break;
                if ( !str_cmp (craft->craft_name, buf) ) {
                        craft_category = TRUE;
                        break;
                }
        }
 
	if ( !str_cmp (buf, "all") )
		craft_category = TRUE;

        if ( !craft && !craft_category ) {
                send_to_char ("No such craft.  Type 'crafts' for a listing.\n", ch);
                return;
        }
 
        for(af=edit_mob->hour_affects; af; af = next_affect) {
        
            next_affect = af->next; 
        
            if(af->type >= CRAFT_FIRST && af->type <= CRAFT_LAST) {
                if ( !str_cmp (buf, "all") || !str_cmp (af->a.craft->subcraft->craft_name, buf) ) {
                        remove_affect_type (edit_mob, af->type);
                        continue;
                }
                if(!str_cmp(af->a.craft->subcraft->subcraft_name, buf)) {
                    remove_affect_type(edit_mob, af->type);
                    send_to_char ("Ok.\n", ch);
                    break;
                }       
            }
        }
        
        if ( craft_category )
                send_to_char ("Craft category removed.\n", ch);
}

void do_addcraft (CHAR_DATA *ch, char *argument, int cmd)
{
        int                                     i;
        CHAR_DATA                       *edit_mob;
        AFFECTED_TYPE           *af, *next_affect;
        SUBCRAFT_HEAD_DATA      *craft;
        char                            buf [MAX_STRING_LENGTH] = {'\0'};
        bool                    craft_category = FALSE;
        
        argument = one_argument (argument, buf);
                  
        if ( *buf == '?' ) {
                s ("Start by using the mob command on a PC.");
                s ("");
                s ("addcraft <subcraft-name>            Use crafts to get names");
                s ("         <item list 1>,");
                s ("         <item list 2>, ...");
                s ("");
                s ("<item list> is item/flag or (item/flag item/flag ...)");
                s (""); 
                s ("Example:");
        s ("                       v-no item list 1 specified");
                s ("   addcraft swordblank , (- 10001 10002), 10003");
        s ("             item list 2-^^^^^^^^^^^^^^^  ^^^^^-item list 3");
                s ("");
                return;
        }
         
        if ( !(edit_mob = ch->pc->edit_player) ) {
                send_to_char ("Start by using the MOB command on a PC.\n", ch);
                return;
        }
         
        for ( craft = crafts;
                  craft;
                  craft = craft->next ) {
                if ( !str_cmp (craft->subcraft_name, buf) )
                        break;
                if ( !str_cmp (craft->craft_name, buf) )
                        craft_category = TRUE;
        }

	if ( !str_cmp (buf, "all") )
		craft_category = TRUE;
         
        if ( !craft && !craft_category ) {
                send_to_char ("No such craft or subcraft.  Type 'crafts' for a listing.\n", ch);
                return;
        }
         
        for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ )
                if ( !get_affect (edit_mob, i) )
                        break;
                        
        if ( i > CRAFT_LAST ) {
                send_to_char ("Sorry, this PC already has the maximum allowed crafts"
                                          ".\n", ch);
                return;
        }
         
        if ( craft_category ) {
                for ( af = edit_mob->hour_affects; af; af = next_affect ) {
                        next_affect = af->next;
                        if ( af->type >= CRAFT_FIRST && af->type <= CRAFT_LAST ) {
                                if ( !str_cmp (af->a.craft->subcraft->craft_name, buf) )
                                        remove_affect_type (edit_mob, af->type);
                        }
                }
                for ( craft = crafts; craft; craft = craft->next ) {
                        if ( !strcmp ("all", buf) || !strcmp (craft->craft_name, buf) ) {   
                                for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ )
                                        if ( !get_affect (edit_mob, i) )
                                                break;
                                magic_add_affect (edit_mob, i, -1, 0, 0, 0, 0);
                                af = get_affect (edit_mob, i);
                                af->a.craft = (struct affect_craft_type *)alloc (sizeof (struct affect_craft_type), 23);
                                af->a.craft->subcraft = craft;
                        }
                }
        }
        else {
                magic_add_affect (edit_mob, i, -1, 0, 0, 0, 0);
                af = get_affect (edit_mob, i);
                af->a.craft = (struct affect_craft_type *)alloc (sizeof (struct affect_craft_type), 23);
                af->a.craft->subcraft = craft;
        }
         
        send_to_char ("Craft(s) added.\n", ch);
}

void update_crafts (CHAR_DATA *ch)
{
	SUBCRAFT_HEAD_DATA	*craft;
	AFFECTED_TYPE		*af;
        int                     i = 0;

	for ( craft = crafts; craft; craft = craft->next ) {
        	if ( !strcmp (craft->craft_name, "general") && !has_craft (ch, craft) && has_required_crafting_skills (ch, craft) ) {
                	for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ )
                        	if ( !get_affect (ch, i) )
                                	break;
                        magic_add_affect (ch, i, -1, 0, 0, 0, 0);
                        af = get_affect (ch, i);
                        af->a.craft = (struct affect_craft_type *)alloc (sizeof (struct affect_craft_type), 23);
                        af->a.craft->subcraft = craft;
                }
                if ( is_opening_craft (ch, craft) && has_required_crafting_skills (ch, craft) && !has_craft (ch, craft) ) {
              		for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ )
                        	if ( !get_affect (ch, i) )
                	                break;
                        magic_add_affect (ch, i, -1, 0, 0, 0, 0);
                        af = get_affect (ch, i);
                        af->a.craft = (struct affect_craft_type *)alloc (sizeof (struct affect_craft_type), 23);
                        af->a.craft->subcraft = craft;
                }
	}
}

AFFECTED_TYPE *is_crafting (CHAR_DATA *ch)
{
	AFFECTED_TYPE *af, *next_af;

        for ( af = ch->hour_affects; af; af = next_af ) {
                next_af = af->next;
                if ( af->type >= CRAFT_FIRST && af->type <= CRAFT_LAST && af->a.craft->timer ) {
			return af;
                }
        }

	return NULL;
}

int has_required_crafting_skills (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft)
{
	PHASE_DATA		*phase;
	char			clan_name [MAX_STRING_LENGTH] = {'\0'};
	int			i, flags = 0, flags2 = 0;
	char			*c1;
	bool			required_race = FALSE, required_clan = FALSE;

	for ( i = 0; i <= 24; i++ ) {
		if ( craft->race[i] )
			required_race = TRUE;
	}

	if ( required_race ) {
		for ( i = 0; i <= 24; i++ ) {
			if ( craft->race[i] && ch->race == craft->race[i] - 1 )
				required_race = FALSE;
		}
	}

	if ( required_race )
		return 0;

	if ( craft->clans && strlen(craft->clans) > 3 ) {
		required_clan = TRUE;
	        for ( c1 = craft->clans; get_next_clan (&c1, clan_name, &flags);) {
                	if ( get_clan (ch, clan_name, &flags2) && flags2 >= flags )
                        	required_clan = FALSE;
        	}
	}

	if ( required_clan )
		return 0;

	for ( i = 0; i <= 24; i++ ) {
		if ( craft->opening[i] > 0 && !real_skill (ch, craft->opening[i]) )
			return 0;
	}

	for ( phase = craft->phases; phase; phase = phase->next ) {
		if ( phase->req_skill ) {
			if ( !real_skill (ch, phase->req_skill) )
				return 0;
		}
		if ( phase->skill ) {
			if ( !real_skill (ch, phase->skill) )
				return 0;
		}
	}

	return 1;

}

int is_opening_craft (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft)
{
	int		i = 0;

	for ( i = 0; i <= 24; i++ ) {
		if ( craft->opening[i] > 0 && real_skill (ch, craft->opening[i]) )
			return 1;
	}

	return 0;

}

char *craft_argument (char *argument, char *arg_first)
{
	char cEnd;

	if ( argument == NULL )
		return "";
    
	while ( isspace( *argument ) )
		argument++;

	if ( *argument == '(' ) {
		argument++;
		strcpy (arg_first, "(");
		return argument;
	}

	if ( *argument == ')' ) {
		argument++;
		strcpy (arg_first, ")");
		return argument;
	}

	cEnd = ' ';

	while ( *argument != '\0' ) {

		if ( *argument == '(' || *argument == ')' )
			break;

		if ( *argument == cEnd ) {
			argument++;
			break;
		}

		if ( cEnd == ' ' )
			*arg_first = LOWER (*argument);
		else
			*arg_first = *argument;

		arg_first++;
		argument++;
	}

	*arg_first = '\0';

	while ( isspace( *argument ) )
		argument++;

	return argument;
}

void add_to_default_list (DEFAULT_ITEM_DATA *items, char *flag_vnum)
{
	int				ind;
	int				ovnum;
	int				i;
	char			buf [MAX_STRING_LENGTH] = {'\0'};

	if ( !items->item_counts )
		items->item_counts = 1;

	if ( *flag_vnum == '(' || *flag_vnum == ')' )
		return;

		/* '-' means to erase all vnums */

	if ( *flag_vnum == '-' ) {
		memset (items->items, 0, MAX_DEFAULT_ITEMS);
		return;
	}

	if ( (*flag_vnum == 'x' || *flag_vnum == 'X') && isdigit (flag_vnum [1]) ) {
		snprintf (buf, MAX_STRING_LENGTH,  "%c", flag_vnum[1]);
		if ( flag_vnum[2] && isdigit(flag_vnum[2]) )
			snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "%c", flag_vnum[2]);
		if ( flag_vnum[3] && isdigit(flag_vnum[3]) )
			snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "%c", flag_vnum[3]);
		if ( flag_vnum[4] && isdigit(flag_vnum[4]) )
			snprintf (buf + strlen(buf), MAX_STRING_LENGTH,  "%c", flag_vnum[4]);
		items->item_counts = strtol(buf, NULL, 10);
		return;
	}

	if ( !isdigit (*flag_vnum) ) {
		if ( (ind = index_lookup (item_default_flags, flag_vnum)) == -1 ) {
			;
		} else
			SET_BIT (items->flags, 1 << ind);

		return;
	}

	ovnum = strtol(flag_vnum, NULL, 10);

	if ( !ovnum || !vtoo (ovnum) ) {
		snprintf (buf, MAX_STRING_LENGTH,  "NOTE:  vnum %s does not exist for CRAFTS!", flag_vnum);
		system_log (buf, TRUE);
	}

	for ( i = 0; i < MAX_DEFAULT_ITEMS; i++ ) {

		if ( !items->items [i] ) {
			items->items [i] = ovnum;
			break;
		}

		if ( items->items [i] == ovnum ) {
			break;
		}
	}

	if ( i >= MAX_DEFAULT_ITEMS ) {
		system_log ("WARNING:  Too many items specified in default item list!", TRUE);
		snprintf (buf, MAX_STRING_LENGTH,  "Item %d not added.  Max allowed in list is %d items.",
				 ovnum, MAX_DEFAULT_ITEMS);
		system_log (buf, TRUE);
	}
}

char *read_item_list (DEFAULT_ITEM_DATA **items, char *list, PHASE_DATA *phase)
{
	char				buf [MAX_STRING_LENGTH] = {'\0'};
	char				*argument;
	DEFAULT_ITEM_DATA	*deflt;

	*items = (DEFAULT_ITEM_DATA *)alloc (sizeof (DEFAULT_ITEM_DATA), 27);

	deflt = *items;

	deflt->phase = phase;

	argument = craft_argument (list, buf);

	if ( !*buf )
		return argument;

	if ( *buf != '(' ) {
		add_to_default_list (deflt, buf);
		return argument;
	}

	do {
		argument = craft_argument (argument, buf);
		add_to_default_list (deflt, buf);
	} while ( *buf != ')' );

	return argument;
}

PHASE_DATA *new_phase ()
{
	PHASE_DATA		*phase;

	phase = (PHASE_DATA *)alloc (sizeof (PHASE_DATA), 26);
	phase->attribute = -1;

	return phase;
}

char *read_extended_text (FILE *fp, char *first_line)
{
        int                     continues;
        char            line [MAX_STRING_LENGTH] = {'\0'};
        char            buf [MAX_STRING_LENGTH] = {'\0'};
        char            *buf_end = {'\0'};
        char            *buf_start = {'\0'};

	*buf = '\0';
	*line = '\0';

        strcpy (buf, first_line);

        *line = '\0';

        while ( 1 ) {

                continues = 0;

                for ( buf_start = buf; *buf_start == ' '; )
                        buf_start++;

                buf_end = buf_start + strlen (buf_start) - 1;

                while ( 1 ) {

                        if ( buf_end == buf_start )
                                break;

                        if ( *buf_end == ' ' ||
                                 *buf_end == '\n' ||
                                 *buf_end == '\r' )
                                buf_end--;
        
                        else if ( *buf_end == '\\' ) {
                                continues = 1;
                                *buf_end = '\0';
                                break;
                        }
        
                        else
                                break;

                        buf_end [1] = '\0';
                }
                
                strcat (line, buf_start);

                if ( !continues )
                        break;
                
                (void)fgets (buf, MAX_STRING_LENGTH - 1, fp);
        }
                                
        return str_dup (line);
}

void subcraft_line (FILE *fp_reg, char *line)
{
	int					ind;
	int					items_num;
	int					sn, i;
	char				c [10];
	char				*argument = NULL;
	char				buf [MAX_STRING_LENGTH] = {'\0'};
	PHASE_DATA			*phase = NULL;
	SUBCRAFT_HEAD_DATA	*subcraft;


	argument = one_argument (line, buf);

	if ( !str_cmp (buf, "craft") ) {

		if ( !crafts ) {
			crafts = subcraft = (SUBCRAFT_HEAD_DATA *)alloc (sizeof (SUBCRAFT_HEAD_DATA), 25);
			memset(crafts, 0, sizeof(SUBCRAFT_HEAD_DATA));
		} else {
			for ( subcraft = crafts; subcraft->next; subcraft = subcraft->next )
			;

			subcraft->next = (SUBCRAFT_HEAD_DATA *)alloc (sizeof (SUBCRAFT_HEAD_DATA), 25);
			subcraft = subcraft->next;
			memset(subcraft, 0, sizeof(SUBCRAFT_HEAD_DATA));
		}

		subcraft->crafts_start = ftell (fp_reg) - strlen (line) - 1;

		subcraft->clans = add_hash ("");

		argument = one_argument (argument, buf);
		subcraft->craft_name = str_dup (buf);

		argument = one_argument (argument, buf);

		if ( str_cmp (buf, "subcraft") ) {
			system_log ("Missing 'subcraft' on craft line:", TRUE);
			system_log (line, TRUE);
			system_log (buf, TRUE);
			abort();
		}

		argument = one_argument (argument, buf);
		subcraft->subcraft_name = str_dup (buf);

		argument = one_argument (argument, buf);

		if ( str_cmp (buf, "command") ) {
			system_log ("Missing 'command' on craft line:", TRUE);
			system_log (line, TRUE);
			system_log (buf, TRUE);
			abort();
		}

		argument = one_argument (argument, buf);
		subcraft->command = str_dup (buf);

		return;
	}

	if ( !crafts ) {
		system_log ("Missing first 'craft' line.", TRUE);
		system_log (line, TRUE);
		abort();
	}


		/* Determine current subcraft */

	for ( subcraft = crafts; subcraft->next; subcraft = subcraft->next )
		;

	if ( !subcraft->phases &&
		 (!str_cmp (buf, "fail:") ||
		  !str_cmp (buf, "failure:")) ) {
		subcraft->failure = read_extended_text (fp_reg, argument);
		return;
	}

	if ( !subcraft->phases && 
		(!str_cmp (buf, "failobj:") ||
		 !str_cmp (buf, "failobjs:")) ) {
		subcraft->failobjs = read_extended_text (fp_reg, argument);
		return;
	}


	if ( !subcraft->phases && !str_cmp (buf, "flags:") ) {

		argument = one_argument (argument, buf);

		while ( *buf ) {

			if ( (ind = index_lookup (subcraft_flags, buf)) != -1 )
				SET_BIT (subcraft->subcraft_flags, 1 << ind);
			else {
				system_log ("Subcraft_flags error (line, subcraft):", TRUE);
				system_log (line, TRUE);
				system_log (subcraft->subcraft_name, TRUE);
			}

			argument = one_argument (argument, buf);
		}

		if ( IS_SET (subcraft->subcraft_flags, SCF_OFFENSIVE) &&
			 IS_SET (subcraft->subcraft_flags, SCF_DEFENSIVE) ) {
			REMOVE_BIT (subcraft->subcraft_flags, SCF_DEFENSIVE);
		}

		if ( IS_SET (subcraft->subcraft_flags, SCF_TARGET_OBJ) &&
			 IS_SET (subcraft->subcraft_flags, SCF_TARGET_CHAR) ) {
			REMOVE_BIT (subcraft->subcraft_flags, SCF_DEFENSIVE);
		}

		return;
	}

	else if ( !str_cmp (buf, "sectors:") ) {

		if ( !*argument )
			return;

		argument = one_argument (argument, buf);

		while ( *buf ) {

			if ( (ind = index_lookup (sector_types, buf)) != -1 ) {
				for ( i = 0; i <= MAX_SECTOR; i++ ) {
					if ( !subcraft->sectors[i] ) {
						subcraft->sectors[i] = ind+1;
						break;
					}
				}
			}
			else {
				system_log ("Illegal subcraft sector:", TRUE);
				system_log (buf, TRUE);
			}

			argument = one_argument (argument, buf);
		}
		return;
	}

	else if ( !str_cmp (buf, "seasons:") ) {

		if ( !*argument )
			return;

		argument = one_argument (argument, buf);

		while ( *buf ) {

			if ( (ind = index_lookup (seasons, buf)) != -1 ) {
				for ( i = 0; i <= 5; i++ ) {
					if ( !subcraft->seasons[i] ) {
						subcraft->seasons[i] = ind+1;
						break;
					}
				}
			}

			argument = one_argument (argument, buf);
		}
		return;
	}

	else if ( !str_cmp (buf, "opening:") ) {

		argument = one_argument (argument, buf);

		while ( *buf ) {

			if ( strtol(buf, NULL, 10) <= LAST_SKILL ) {
				for ( i = 0; i <= 24; i++ ) {
					if ( !subcraft->opening[i] ) {
						subcraft->opening[i] = strtol(buf, NULL, 10);
						break;
					}
				}
			}

			argument = one_argument (argument, buf);
		}
		return;
	}

	else if ( !str_cmp (buf, "race:") ) {

		argument = one_argument (argument, buf);

		while ( *buf ) {

			for ( i = 0; i <= LAST_PC_RACE; i++ ) {
				if ( !subcraft->race[i] ) {
					subcraft->race[i] = strtol(buf, NULL, 10);
					break;
				}
			}

			argument = one_argument (argument, buf);
		}
		return;
	}

	else if ( !str_cmp (buf, "clans:") ) {

		subcraft->clans = add_hash (argument);

		return;
	}

	else if ( !str_cmp (buf, "ic_delay:") ) {

		argument = one_argument (argument, buf);

		subcraft->delay = strtol(buf, NULL, 10);

		return;
	}

	if ( !str_cmp (buf, "phase") || !str_cmp (buf, "phase:") ) {
		if ( !subcraft->phases )
			subcraft->phases = new_phase ();
		else {
			for ( phase = subcraft->phases; phase->next; phase = phase->next )
				;

			phase->next = new_phase ();
		}

		return;
	}

		/* Determine current phase */

	if ( subcraft->phases ) {
		for ( phase = subcraft->phases; phase->next; phase = phase->next )
			;
	}

	while ( *argument == ' ' )
		argument++;

	if ( !str_cmp (buf, "end") )
		subcraft->crafts_end = ftell (fp_reg);
		
	else if ( !str_cmp (buf, "1st:") )
		phase->first = read_extended_text (fp_reg, argument);

	else if ( !str_cmp (buf, "2nd:") )
		phase->second = read_extended_text (fp_reg, argument);

	else if ( !str_cmp (buf, "3rd:") )
		phase->third = read_extended_text (fp_reg, argument);

	else if ( !str_cmp (buf, "self:") )
		phase->self = read_extended_text (fp_reg, argument);

	else if ( !str_cmp (buf, "1stfail:") ||
			  !str_cmp (buf, "failure:") )
		phase->failure = read_extended_text (fp_reg, argument);

	else if ( !str_cmp (buf, "2ndfail:") )
		phase->second_failure = read_extended_text (fp_reg, argument);

	else if ( !str_cmp (buf, "3rdfail:") )
		phase->third_failure = read_extended_text (fp_reg, argument);

	else if ( !str_cmp (buf, "f:") ) {

		argument = one_argument (argument, buf);

		while ( *buf ) {

			if ( (ind = index_lookup (phase_flags, buf)) != -1 )
				SET_BIT (phase->flags, 1 << ind);
			else {
				system_log ("Illegal subcraft flags:", TRUE);
				system_log (buf, TRUE);
			}

			argument = one_argument (argument, buf);
		}
	}

	else if ( !str_cmp (buf, "s:") || !str_cmp (buf, "skill:") ) {

		argument = one_argument (argument, buf);

		if ( (sn = index_lookup (attrs, buf)) != -1 )
			phase->attribute = sn;

		else if ( (sn = skill_index_lookup (buf)) == -1 ) {
			system_log ("Illegal skill name in craft:", TRUE);
			system_log (buf, TRUE);
		}

		else
			phase->skill = sn;

		argument = one_argument (argument, buf);

		if ( !str_cmp (buf, "vs") || !str_cmp (buf, "vs.") )
			argument = one_argument (argument, buf);

		if ( 3 != (sscanf (buf, "%d%[dD]%d", &phase->dice, c, &phase->sides))) {
			system_log ("Parm error in skill: (s:) of craft:", TRUE);
			system_log (buf, TRUE);
		}

		if ( phase->skill && (phase->dice < 1 || phase->sides < 1) ) {
			phase->dice = 1;
			phase->sides = 100;
		}
	}

else if ( !str_cmp (buf, "a:") || !str_cmp (buf, "attr:") ) {

		argument = one_argument (argument, buf);

		if ( (sn = index_lookup (attrs, buf)) != -1 )
			phase->attribute = sn;

		else if ( (sn = index_lookup (attrs, buf)) == -1 ) {
			system_log ("Illegal attribute name in craft:", TRUE);
			system_log (buf, TRUE);
		}

		else
			phase->attribute = sn;

		argument = one_argument (argument, buf);

		if ( !str_cmp (buf, "vs") || !str_cmp (buf, "vs.") )
			argument = one_argument (argument, buf);

		if ( 3 != (sscanf (buf, "%d%[dD]%d", &phase->dice, c, &phase->sides))) {
			system_log ("Parm error in attribute: (a:) of craft:", TRUE);
			system_log (buf, TRUE);
		}

		if ( phase->attribute > -1  && (phase->dice < 1 || phase->sides < 1) ) {
			phase->dice = 1;
			phase->sides = 100;
		}

		
	}
	else if ( !str_cmp (buf, "t:") ) {
		argument = one_argument (argument, buf);

		if ( isdigit (*buf) )
			phase->phase_seconds = strtol(buf, NULL, 10);
		else {
			system_log ("Illegal t: (time) value declared in subcraft:", TRUE);
			system_log (buf, TRUE);
		}
	}

	else if ( !str_cmp (buf, "mob:") ) {
		argument = one_argument (argument, buf);

		if ( isdigit (*buf) )
			phase->load_mob = strtol(buf, NULL, 10);
	}

	else if ( !str_cmp (buf, "tool:") )
		(void)read_item_list (&phase->tool, argument, phase);

	else if ( (isdigit (*buf) && buf [1] == ':') ||
		 (isdigit (*buf) && isdigit (buf [1]) && buf [2] == ':') ) {

		items_num = strtol(buf, NULL, 10);
		if ( subcraft->items [items_num] ) {
			abort();
		}

		(void)read_item_list (&subcraft->items [strtol(buf, NULL, 10)], argument, phase);
	}

	else if ( !str_cmp (buf, "cost:") ) {
		argument = one_argument (argument, buf);

		while ( *buf ) {

			if ( !str_cmp (buf, "hits") ) {
				argument = one_argument (argument, buf);
				if ( !just_a_number (buf) ) {
					break;
				}

				phase->hit_cost = strtol(buf, NULL, 10);
			}

			else if ( !str_cmp (buf, "moves") ) {
				argument = one_argument (argument, buf);
				if ( !just_a_number (buf) ) {
					break;
				}

				phase->move_cost = strtol(buf, NULL, 10);
			}

			argument = one_argument (argument, buf);
		}
	}

	else if ( !str_cmp (buf, "open:") ) {

		argument = one_argument (argument, buf);

		if ( !str_cmp (buf, "target") ) {
			REMOVE_BIT (phase->flags, PHASE_OPEN_ON_SELF);
			argument = one_argument (argument, buf);
		} else
			SET_BIT (phase->flags, PHASE_OPEN_ON_SELF);

		if ( (sn = skill_index_lookup (buf)) == -1 ) {
			;
		} else
			phase->open_skill = sn;
	}

	else if ( !str_cmp (buf, "req:") || !str_cmp (buf, "require:") ) {

		
		argument = one_argument (argument, buf);

		if ( !str_cmp (buf, "target") ) {
			REMOVE_BIT (phase->flags, PHASE_REQUIRE_ON_SELF);
			argument = one_argument (argument, buf);
		} else
			SET_BIT (phase->flags, PHASE_REQUIRE_ON_SELF);

		if ( (sn = skill_index_lookup (buf)) == -1 ) {
			;
		} else
			phase->req_skill = sn;

		argument = one_argument (argument, buf);

		if ( *buf == '>' )
			SET_BIT (phase->flags, PHASE_REQUIRE_GREATER);
		else if ( *buf == '<' )
			REMOVE_BIT (phase->flags, PHASE_REQUIRE_GREATER);
		else {
			;
		}

		argument = one_argument (argument, buf);

		if ( !just_a_number (buf) ) {
			;
		}

		phase->req_skill_value = strtol(buf, NULL, 10);
	}

	else {
		system_log ("Did not know what to do with craft line:", TRUE);
		system_log (line, TRUE);
	}
}

void reg_read_crafts (FILE *fp_reg, char *buf)
{
	char			buf2 [MAX_STRING_LENGTH] = {'\0'};
	char			*argument;

	while ( !feof (fp_reg) ) {

		(void)fgets (buf, MAX_STRING_LENGTH, fp_reg);

		if ( *buf && buf [strlen (buf) - 1] == '\n' )
			buf [strlen (buf) - 1] = '\0';

		if ( !*buf || *buf == '#' )
			continue;
	
		argument = one_argument (buf, buf2);

		if ( !str_cmp (buf2, "[end-crafts]") ) {
			return;
		}

		subcraft_line (fp_reg, buf);
	}
}

void boot_crafts ()
{
	FILE	*fp_crafts;
	char	buf [MAX_STRING_LENGTH] = {'\0'};

	if ( port == BUILDER_PORT || port == TEST_PORT )
		system ("./ordercrafts.pl ../regions/crafts");

	if ( !(fp_crafts = fopen (CRAFTS_FILE, "r")) ) {
		system_log ("The crafts file could not be read!", TRUE);
		return;
	}

	while ( !feof (fp_crafts) ) {

		(void)fgets (buf, MAX_STRING_LENGTH, fp_crafts);

		if ( *buf && buf [strlen (buf) - 1] == '\n' )
			buf [strlen (buf) - 1] = '\0';

		if ( !*buf || *buf == '#' )
			continue;

		if ( !str_cmp (buf, "[END]") )
			break;

		if ( !str_cmp (buf, "[CRAFTS]") )
			reg_read_crafts (fp_crafts, buf);
	}

	fclose (fp_crafts);
}

void craft_prepare_message (CHAR_DATA *ch, char *message, CHAR_DATA *n,
		CHAR_DATA *N, CHAR_DATA *T, char *phase_msg,
		OBJ_DATA *tool, OBJ_DATA **obj_list)
{
	int			ovnum = 0;
	char		*p = NULL;
	char		buf [MAX_STRING_LENGTH] = {'\0'};
	char		*temp_arg = NULL;
	
	for ( p = buf; *phase_msg; ) {
		if ( *phase_msg == '$' && isdigit (phase_msg [1]) ) {
			phase_msg++;
			if ( isdigit (*phase_msg) &&
				 (ovnum = strtol(phase_msg, NULL, 10)) < MAX_ITEMS_PER_SUBCRAFT ) {
				 temp_arg = see_object (ch, obj_list [ovnum]);
				snprintf (p, MAX_STRING_LENGTH,  "#2%s#0", temp_arg);
				p = p + strlen (p);
			}

			while ( isdigit (*phase_msg) )
				phase_msg++;
		}

		else if ( *phase_msg == '$' ) {

			switch ( phase_msg [1] ) {
			   case 'e':
			   		snprintf (p, MAX_STRING_LENGTH,  "#5%s#0", n ? HSSH (n) : "HSSH-e"); 
			   		break;
			   
			   case 'm':
			   		snprintf (p, MAX_STRING_LENGTH,  "#5%s#0", n ? HMHR (n) : "HMHR-m"); 
			   		break;
			   
			   case 's':
			   		snprintf (p, MAX_STRING_LENGTH,  "#5%s#0", n ? HSHR (n) : "HSHR-s"); 
			   		break;
			   
			   case 'E':
			   		snprintf (p, MAX_STRING_LENGTH,  "#5%s#0", N ? HSSH (N) : "HSSH-E"); 
			   		break;
			   
			   case 'M':
			   		snprintf (p, MAX_STRING_LENGTH,  "#5%s#0", N ? HMHR (N) : "HMHR-M"); 
			   		break;
			   
			   case 'S':
			   		snprintf (p, MAX_STRING_LENGTH,  "#5%s#0", N ? HSHR (n) : "HSHR-S"); 
			   		break;
			   
			   case 't':
			   		temp_arg = see_object (ch, tool);
					snprintf (p, MAX_STRING_LENGTH,  "#2%s#0", temp_arg);
					p = p + strlen (p);
					break;
			   
			   case 'T':
			   		temp_arg = see_person(ch, T);
					snprintf (p, MAX_STRING_LENGTH,  "#5%s#0", T ? temp_arg : "SOMEBODY-T");
					break;
			   
			   case 'n':
			   		temp_arg = see_person (ch, n);
					snprintf (p, MAX_STRING_LENGTH,  "#5%s#0", n ? temp_arg : "SOMEBODY-n");
					break;
			   
			   case 'N':
			   		temp_arg = see_person (ch, N);
					snprintf (p, MAX_STRING_LENGTH,  "#5%s#0", N ? temp_arg : "SOMEBODY-N");
					break;
			}

			phase_msg += 2;
			p = p + strlen (p);
		}

		else {
			*(p++) = *(phase_msg++);
			*p = '\0';
		}
	}

	strcpy (message, buf);
}

OBJ_DATA *obj_list_vnum (CHAR_DATA *ch, OBJ_DATA *list, int vnum)
{
        for ( ; list; list = list->next_content )
                if ( list->virtual == vnum && CAN_SEE_OBJ (ch, list) )
                        return list;
                
        return NULL;
}
 
OBJ_DATA *obj_list_vnum_dark (OBJ_DATA *list, int vnum)
{
        for ( ; list; list = list->next_content )
                if ( list->virtual == vnum )
                        return list;
 
        return NULL;
}

OBJ_DATA *get_item_obj (CHAR_DATA *ch, DEFAULT_ITEM_DATA *item,
						PHASE_DATA *phase)
{
	int				j;
	int				vnum;
	PHASE_DATA		*tmp_phase;
	OBJ_DATA		*tobj;

	for ( j = 0; j < MAX_DEFAULT_ITEMS; j++ ) {

		if ( !(vnum = item->items [j]) )
			continue;

		if ( IS_SET (item->flags, SUBCRAFT_PRODUCED) ) {

			if ( item->phase == phase )
				break;

			for ( tmp_phase = phase->next;
				  tmp_phase;
				  tmp_phase = tmp_phase->next )
				if ( tmp_phase == item->phase )
					return vtoo (vnum);
		}

		if ( IS_SET (item->flags, SUBCRAFT_USED) ) {
			if ( (tobj = obj_list_vnum (ch, ch->right_hand, vnum)) ||
				(tobj = obj_list_vnum (ch, ch->left_hand, vnum)) ) {
				if ( item->item_counts > tobj->count )
					continue;
				else
					return tobj;
			}
			if ( (tobj = obj_list_vnum (ch, ch->room->contents, vnum)) ) {
				if ( item->item_counts > tobj->count )
					continue;
				else
					return tobj;
			}
		}

		if ( IS_SET (item->flags, SUBCRAFT_IN_ROOM)) {
			if ( (tobj = obj_list_vnum (ch, ch->room->contents, vnum)) ) {
				if ( item->item_counts > tobj->count )
					continue;
				else
					return tobj;
			}
		}

		if ( IS_SET (item->flags, SUBCRAFT_IN_INVENTORY) || IS_SET (item->flags, SUBCRAFT_HELD) ) {
			if ( (tobj = obj_list_vnum_dark (ch->right_hand, vnum)) ||
				(tobj = obj_list_vnum_dark (ch->left_hand, vnum))  ) {
				if ( item->item_counts > tobj->count )
					continue;
				else
					return tobj;
			}
		}

		if ( IS_SET (item->flags, SUBCRAFT_WIELDED) ) {
			if ( ((tobj = get_equip (ch, WEAR_BOTH)) &&
				  tobj->virtual == vnum) ||
				 ((tobj = get_equip (ch, WEAR_PRIM)) &&
				  tobj->virtual == vnum) ||
				 ((tobj = get_equip (ch, WEAR_SEC)) &&
				  tobj->virtual == vnum) ) {
				if ( item->item_counts > tobj->count )
					continue;
				else
					return tobj;
			}
		}

		if ( IS_SET (item->flags, SUBCRAFT_WORN) ) {
			for ( tobj = ch->equip; tobj; tobj = tobj->next_content ) {
				if ( tobj->virtual != vnum )
					continue;

				if ( item->item_counts > tobj->count )
					continue;

				if ( tobj->location != WEAR_BOTH &&
					 tobj->location != WEAR_PRIM &&
					 tobj->location != WEAR_SEC )
					return tobj;
			}
		}

		if ( IS_SET (item->flags, SUBCRAFT_WORN) ||
			 IS_SET (item->flags, SUBCRAFT_WIELDED) ||
			 IS_SET (item->flags, SUBCRAFT_HELD) ||
			 IS_SET (item->flags, SUBCRAFT_IN_INVENTORY) ||
			 IS_SET (item->flags, SUBCRAFT_IN_ROOM) ||
			 IS_SET (item->flags, SUBCRAFT_USED) )
			continue;

			/* Grab this item wherever it is */

		if ( ((tobj = obj_list_vnum_dark (ch->right_hand, vnum)) &&
			  tobj->virtual == vnum) ||
			((tobj = obj_list_vnum (ch, ch->left_hand, vnum)) &&
			tobj->virtual == vnum) || 
			 ((tobj = obj_list_vnum (ch, ch->room->contents, vnum)) &&
			  tobj->virtual == vnum) ||
			 ((tobj = get_equip (ch, WEAR_BOTH)) &&
			  tobj->virtual == vnum) ||
			 ((tobj = get_equip (ch, WEAR_PRIM)) &&
			  tobj->virtual == vnum) ||
			 ((tobj = get_equip (ch, WEAR_SEC)) &&
			  tobj->virtual == vnum) ) {
			if ( item->item_counts > tobj->count )
				continue;
			else
				return tobj;
		}
	}

	return NULL;
}

void missing_item_msg (CHAR_DATA *ch, DEFAULT_ITEM_DATA *item, char *header)
{
	int			i;
	int			choice_count = 0;
	OBJ_DATA	*proto_obj;
	char		*p;
	char		buf [MAX_STRING_LENGTH] = {'\0'};

	if ( item->item_counts > 1 )
		snprintf (buf, MAX_STRING_LENGTH,  "%s%d of ", header, item->item_counts);
	else
		snprintf (buf, MAX_STRING_LENGTH,  "%s", header);

	for ( i = 0; i < MAX_DEFAULT_ITEMS; i++ )
		if ( item->items [i] )
			choice_count++;

	for ( i = 0; i < MAX_DEFAULT_ITEMS; i++ ) {

		if ( !item->items [i] )
			continue;

		choice_count--;

		proto_obj = vtoo (item->items [i]);

		if ( !proto_obj )
			continue;

		snprintf (ADDBUF, MAX_STRING_LENGTH, "#2%s#0", proto_obj->short_description);
		if ( choice_count )
			strcat (buf, ", ");

		if ( choice_count == 1 )
			strcat (buf, "or ");

		if ( !choice_count )
			strcat (buf, ".");
	}

	reformat_string (buf, &p);
	send_to_char (p, ch);

	mem_free (p);
}

int craft_uses (SUBCRAFT_HEAD_DATA *craft, int vnum)
{
	int			i = 0, j = 0;

	for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {
		if ( !craft->items[i] )
			continue;
		if ( !IS_SET (craft->items[i]->flags, SUBCRAFT_USED) && !IS_SET (craft->items[i]->flags, SUBCRAFT_HELD) &&
			!IS_SET (craft->items[i]->flags, SUBCRAFT_IN_ROOM) && !IS_SET (craft->items[i]->flags, SUBCRAFT_IN_INVENTORY) )
			continue;
		for ( j = 0; j < MAX_DEFAULT_ITEMS; j++ ) {
			if ( craft->items[i]->items[j] == vnum )
				return 1;
		}
	}

	return 0;
}

int craft_produces (SUBCRAFT_HEAD_DATA *craft, int vnum)
{
	int			i = 0, j = 0;

	for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {
		if ( !craft->items[i] )
			continue;
		if ( !IS_SET (craft->items[i]->flags, SUBCRAFT_PRODUCED) )
			continue;
		for ( j = 0; j < MAX_DEFAULT_ITEMS; j++ ) {
			if ( craft->items[i]->items[j] == vnum )
				return 1;
		}
	}

	return 0;
}

SUBCRAFT_HEAD_DATA *branch_craft_backward (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft, int level)
{
	SUBCRAFT_HEAD_DATA	*tcraft = NULL;
	SUBCRAFT_HEAD_DATA	*dcraft = NULL;
	SUBCRAFT_HEAD_DATA	*next_craft = NULL;
	int			i = 0;

	if ( level >= 10 )
		return NULL;

	for ( tcraft = crafts; tcraft; tcraft = next_craft ) {
		next_craft = tcraft->next;
		
		if ( str_cmp (tcraft->craft_name, craft->craft_name) )
			continue;
		
		if ( !str_cmp (tcraft->subcraft_name, craft->subcraft_name) )
			continue;
		
		for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {
			if ( !craft->items[i] )
				continue;
			
			if ( IS_SET (craft->items[i]->flags, SUBCRAFT_PRODUCED) ||
				 IS_SET (craft->items[i]->flags, SUBCRAFT_IN_ROOM) )
				continue;
			
			if ( !tcraft )
				continue;
			
			if ( craft_produces (tcraft, craft->items[i]->items[0]) ) {
				if ( !has_craft (ch, tcraft) && meets_skill_requirements (ch, tcraft) )
					return tcraft;
				
				if ( !meets_skill_requirements (ch, tcraft) )		/* Dead-end; need to improve skills first. */
					continue;
				
				if ( (dcraft = branch_craft_backward (ch, tcraft, ++level)) )	/* Branching craft beneath tcraft. */
					return dcraft;
			}
		}
	}

	return NULL;

}

SUBCRAFT_HEAD_DATA *branch_craft_forward (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft, int level)
{
	SUBCRAFT_HEAD_DATA	*tcraft = NULL;
	SUBCRAFT_HEAD_DATA	*dcraft = NULL;
	SUBCRAFT_HEAD_DATA	*next_craft = NULL;
	int			i = 0;

	if ( level >= 10 )
		return NULL;

	for ( tcraft = crafts; tcraft; tcraft = next_craft ) {
		next_craft = tcraft->next;
		if ( str_cmp (tcraft->craft_name, craft->craft_name) )
			continue;
		if ( !str_cmp (tcraft->subcraft_name, craft->subcraft_name) )
			continue;
		for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {
			if ( !craft->items[i] )
				continue;
			if ( !IS_SET (craft->items[i]->flags, SUBCRAFT_PRODUCED) )
				continue;
			if ( !craft_uses (tcraft, craft->items[i]->items[0]) )
				continue;
			if ( (dcraft = branch_craft_backward (ch, tcraft, ++level)) )
				return dcraft;			
			if ( has_craft (ch, tcraft) || !meets_skill_requirements (ch, tcraft) )
				continue;
			return tcraft;
		}
	}

	return NULL;

}

SUBCRAFT_HEAD_DATA *get_related_subcraft (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft)
{
	SUBCRAFT_HEAD_DATA	*tcraft= NULL;
	AFFECTED_TYPE		*af = NULL;
	int			i = 0;

	tcraft = branch_craft_backward (ch, craft, 0);

	if ( !tcraft )
		tcraft = branch_craft_forward (ch, craft, 0);

	if ( !tcraft ) {
		for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ ) {
			if ( (af = get_affect (ch, i)) ) {
				if ( str_cmp (af->a.craft->subcraft->craft_name, craft->craft_name) )
					continue;
				tcraft = branch_craft_backward (ch, af->a.craft->subcraft, 0);
				if ( !tcraft )
					tcraft = branch_craft_forward (ch, af->a.craft->subcraft, 0);
				if ( tcraft && tcraft != craft )
					return tcraft;
			}
		}
	}

	if ( tcraft && tcraft != craft )
		return tcraft;

	return NULL;
}

int has_craft (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft)
{
	AFFECTED_TYPE		*af;

	for ( af = ch->hour_affects; af; af = af->next ) {
		if ( af->type >= CRAFT_FIRST && af->type <= CRAFT_LAST ) {
			if ( !str_cmp (af->a.craft->subcraft->subcraft_name, craft->subcraft_name) )
				return 1;
		}
	}

	return 0;
}

int meets_skill_requirements (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft)
{
	PHASE_DATA		*phase;
	char			clan_name [MAX_STRING_LENGTH] = {'\0'};
	char			*c1;
	int			i, flags = 0, flags2 = 0;
	bool			required_race = FALSE, required_clan = FALSE;

	for ( i = 0; i <= 24; i++ ) {
		if ( craft->race[i] )
			required_race = TRUE;
	}

	if ( required_race ) {
		for ( i = 0; i <= 24; i++ ) {
			if ( craft->race[i] && ch->race == craft->race[i] - 1 )
				required_race = FALSE;
		}
	}

	if ( required_race )
		return 0;

	if ( craft->clans && strlen(craft->clans) > 3 ) {
		required_clan = TRUE;
	        for ( c1 = craft->clans; get_next_clan (&c1, clan_name, &flags);) {
                	if ( get_clan (ch, clan_name, &flags2) && flags2 >= flags )
                        	required_clan = FALSE;
        	}
	}

	if ( required_clan )
		return 0;

	for ( phase = craft->phases; phase; phase = phase->next ) {
                if ( phase->req_skill ) {
                        if ( !real_skill (ch, phase->req_skill) )
                                return 0;
                }
		if ( phase->skill ) {
			if ( !real_skill (ch, phase->skill) || ch->skills[phase->skill] < ((int)((phase->dice*phase->sides) * 0.750)) )
				return 0;
		}
	}

	return 1;
}

void branch_craft (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft)
{
	AFFECTED_TYPE		*af = NULL;
	SUBCRAFT_HEAD_DATA	*tcraft = NULL;
	int			num = 0;
	int			i = 0;
	int			stop = 0;
	char		buf [MAX_STRING_LENGTH] = {'\0'};
	bool		related = FALSE;

	if ( get_affect (ch, MAGIC_CRAFT_BRANCH_STOP) && port != TEST_PORT )
		return;

	if ( !str_cmp (craft->craft_name, "general") )
		return;

	if ( !(tcraft = get_related_subcraft (ch, craft)) ) {
		for ( tcraft = crafts; tcraft; tcraft = tcraft->next ) {
			if ( tcraft == craft )
				continue;
			if ( !str_cmp (craft->craft_name, tcraft->craft_name) && meets_skill_requirements (ch, tcraft) && !has_craft (ch, tcraft) )
				num++;
		}

		if ( num <= 0 )
			return;

		stop = number(1,num);

		for ( tcraft = crafts, i = 0; tcraft; tcraft = tcraft->next ) {
			if ( tcraft == craft )
				continue;
			if ( !str_cmp (craft->craft_name, tcraft->craft_name) && meets_skill_requirements (ch, tcraft) && !has_craft (ch, tcraft) )
				i++;
			if ( i == stop )
				break;
		}
	}
	else related = TRUE;

	if ( !tcraft || tcraft == craft || has_craft (ch, tcraft) )
		return;

	if ( related )
		snprintf (buf, MAX_STRING_LENGTH,  "You have branched a related subcraft, #6%s %s#0!\n", tcraft->command,tcraft->subcraft_name);
	else
		snprintf (buf, MAX_STRING_LENGTH,  "You have branched a new subcraft, #6%s %s#0!\n", tcraft->command,tcraft->subcraft_name);

	send_to_char (buf, ch);

	for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ ) {
		if ( !get_affect (ch, i) )
			break;
	}

	magic_add_affect (ch, i, -1, 0, 0, 0, 0);
	af = get_affect (ch, i);
	af->a.craft = (struct affect_craft_type *)alloc (sizeof (struct affect_craft_type), 23);
	af->a.craft->subcraft = tcraft;

        magic_add_affect (ch, MAGIC_CRAFT_BRANCH_STOP, number(30,90), 0, 0, 0, 0);
}

int requires_skill_check (SUBCRAFT_HEAD_DATA *craft)
{
	PHASE_DATA			*phase;

	for ( phase = craft->phases; phase; phase = phase->next ) {
		if ( phase->req_skill || phase->skill )
			return 1;
	}

	return 0;
}

int branching_check (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft)
{
	PHASE_DATA		*phase = NULL;
	SUBCRAFT_HEAD_DATA	*tcraft = NULL;
	AFFECTED_TYPE		*af = NULL;
	int			max = 0;
	int			max_amt = 0;
	int			multiplier = 0;
	int			total_crafts = 0;
	int			char_crafts = 0;
	int			i = 0;
	float		percentage = 0;

	/* does the craft check a skill ? */
	for ( phase = craft->phases; phase; phase = phase->next ) {
		if ( phase->skill ) {
			if ( phase->dice*phase->sides > max_amt ) {
				max = phase->skill;
				max_amt = phase->dice*phase->sides;
			}
		}
		if ( phase->req_skill ) {
			if ( phase->req_skill_value > max_amt ) {
				max = phase->req_skill;
				max_amt = phase->req_skill_value;
			}
		}
	}

	/* adds up total number of eligible subcrafts (based on skill) */
	for ( tcraft = crafts; tcraft; tcraft = tcraft->next ) {
		if ( !str_cmp (tcraft->craft_name, craft->craft_name) && meets_skill_requirements (ch, tcraft) )
			total_crafts++;
	}

	/* adds up total number of subcrafts character has */
    for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ ) {
    	if ( !(af = get_affect (ch, i)) )
			continue;
		if ( !str_cmp (af->a.craft->subcraft->craft_name, craft->craft_name) )
			char_crafts++;
	}

	if ( total_crafts <= char_crafts )
		total_crafts = char_crafts + 1;

	percentage = (float)char_crafts / (float)total_crafts;

	if ( percentage >= 0 && percentage <= .33 )
		multiplier = 4;
	else if ( percentage > .33 && percentage <= .60 )
		multiplier = 3;
	else if ( percentage > .60 && percentage <= .75 )
		multiplier = 2;
	else multiplier = 1;

	return MIN ((calc_lookup (ch, REG_LV, max) * multiplier), 65);
}

int figure_craft_delay (CHAR_DATA *ch, SUBCRAFT_HEAD_DATA *craft)
{
	PHASE_DATA	*phase;
	int		seconds = 0, skill = 0, numskills = 0;

	seconds = craft->delay * 60 * 60;

	for ( phase = craft->phases; phase; phase = phase->next ) {
		if ( phase->req_skill ) {
			numskills++;
			skill += ch->skills [phase->req_skill];
		}
		if ( phase->skill ) {
			numskills++;
			skill += ch->skills [phase->skill];
		}
	}

	if ( !numskills )
		numskills = 1;

	skill /= numskills;

	if ( skill >= 30 && skill < 50 )
		(int) (seconds *= (.85));
	else if ( skill >= 50 && skill < 70 )
		(int) (seconds *= (.72));
	else if ( skill >= 70 )
		(int) (seconds *= (.61));

	return seconds;
}

void activate_phase (CHAR_DATA *ch, AFFECTED_TYPE *af)
{
	    char numbuf[20];
	    int count;
	    OBJ_DATA *failobj;
	int					i, j;
	int					delay_time = 0;
	int					missing_said = 0;
	int					phase_failed = 0;
	int					skill_value = 0;
	int					dice_value = 0;
	int 				attr_value = 0;
	char				color [MAX_STRING_LENGTH] = {'\0'};
	char				*p;
	char				*first;
	PHASE_DATA			*phase = NULL;
	DEFAULT_ITEM_DATA	*item;
	CHAR_DATA			*tch, *mob;
	CHAR_DATA			*target_ch;
	OBJ_DATA			*tool = NULL;
	OBJ_DATA			*target_obj;
	OBJ_DATA			*obj_list [MAX_ITEMS_PER_SUBCRAFT];
	SUBCRAFT_HEAD_DATA	*subcraft;
	int					item_required [MAX_ITEMS_PER_SUBCRAFT];
	char				buf [MAX_STRING_LENGTH] = {'\0'};
	char				test_buf [MAX_STRING_LENGTH] = {'\0'};
	
		/* A craft is active as long as af->a.craft->timer is non-zero. */

	if ( af->a.craft->phase )
		phase = af->a.craft->phase;

		/* Shorthand variables */

	subcraft = af->a.craft->subcraft;
	target_ch = af->a.craft->target_ch;
	target_obj = af->a.craft->target_obj;

		/* Point affect at next phase, and setup timer for that phase */

	if ( !phase ) {
		phase = af->a.craft->subcraft->phases;
		af->a.craft->phase = phase->next;
		af->a.craft->timer = phase->phase_seconds;
	} else {
		af->a.craft->phase = phase->next;

		if ( phase->next )
			af->a.craft->timer = phase->phase_seconds;
		else
			af->a.craft->timer = 0;
	}

	if ( !IS_MORTAL(ch) )
		af->a.craft->timer = 0;

	memset (item_required, 0, MAX_ITEMS_PER_SUBCRAFT * sizeof (int));
	memset (obj_list, 0, MAX_ITEMS_PER_SUBCRAFT * sizeof (OBJ_DATA *));

	for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {

		item = af->a.craft->subcraft->items [i];

		if ( !item ) {
			continue;
		}

		if ( !item->items [0] )		/* No items in list.  Nothing required */
			continue;

		obj_list [i] = get_item_obj (ch, item, phase);
	}

		/* Determine what is required for this phase based on first person */

	if ( phase->first ) {
		for ( p = phase->first; *p; p++ ) {
			if ( *p == '$' ) {
				p++;
				if ( isdigit (*p) && strtol(p, NULL, 10) < MAX_ITEMS_PER_SUBCRAFT )
					item_required [strtol(p, NULL, 10)] = 1;
			}
		}
	}

	if ( phase->tool && phase->tool->items [0] ) {
		if ( !(tool = get_item_obj (ch, phase->tool, phase)) ) {
			send_to_char ("You are missing a tool.\n", ch);
			af->a.craft->timer = 0;
			return;
		}
	}

		/* Make sure all required objects are accounted for */

	for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {

		if ( !item_required [i] )
			continue;

		if ( obj_list [i] )
			continue;

		item = af->a.craft->subcraft->items [i];

		if ( !item ) {
			continue;
		}

		if ( item && IS_SET (item->flags, SUBCRAFT_PRODUCED) &&
			 item->phase == phase )
			continue;

		if ( !missing_said ) {
			missing_said = 1;
			send_to_char ("\n#1You are missing one or more items:#0\n\n", ch);
			act ("$n stops doing $s craft.", FALSE, ch, 0, 0, TO_ROOM);
			af->a.craft->timer = 0;
		}

		if ( IS_SET (item->flags, SUBCRAFT_WORN) )
			missing_item_msg (ch, item, "You must wear ");
		else if ( IS_SET (item->flags, SUBCRAFT_HELD) )
			missing_item_msg (ch, item, "You must hold ");
		else if ( IS_SET (item->flags, SUBCRAFT_IN_ROOM) )
			missing_item_msg (ch, item, "In the room must be ");
		else if ( IS_SET (item->flags, SUBCRAFT_IN_INVENTORY) )
			missing_item_msg (ch, item, "You must have in your inventory ");
		else if ( IS_SET (item->flags, SUBCRAFT_WIELDED) )
			missing_item_msg (ch, item, "You must wield ");
		else
			missing_item_msg (ch, item, "You need ");
	}

	if ( missing_said )
		return;

		/* Check for skill requirements */

	if ( phase->req_skill ) {

		if ( IS_SET (phase->flags, PHASE_REQUIRE_ON_SELF) )
			skill_value = ch->skills [phase->req_skill];
		else
			skill_value = target_ch->skills [phase->req_skill];

		if ( IS_SET (phase->flags, PHASE_REQUIRE_GREATER) &&
			 skill_value <= phase->req_skill_value )
			phase_failed = 1;
		else if ( !IS_SET (phase->flags, PHASE_REQUIRE_GREATER) &&
				  skill_value >= phase->req_skill_value )
			phase_failed = 1;

		skill_use (ch, phase->req_skill, 0);
	}

	if ( phase->skill ) {
		skill_use (ch, phase->skill, 0);
		dice_value = dice(phase->dice, phase->sides);
		if ( dice_value > ch->skills [phase->skill] )
			phase_failed = 1;
	}
	
	
		/* Removed USED items from wherever they are */

	for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {

		item = af->a.craft->subcraft->items [i];

		if ( !item ) {
			continue;
		}

		if ( /*!item_required [i] ||*/
			item->phase != phase ||
			 !IS_SET (item->flags, SUBCRAFT_USED) )
			continue;

		if ( !obj_list [i] ) {
			act ("You are not using enough of a particular item to finish this craft.", FALSE, ch, 0, 0, TO_CHAR);

			af->a.craft->timer = 0;

			return;
		}

		if ( obj_list[i] && obj_list[i]->var_color && str_cmp (obj_list[i]->var_color, "none") )
			item->color = obj_list[i]->var_color;

		if ( obj_list[i]->count <= item->item_counts )
			extract_obj (obj_list[i]);
		else obj_list[i]->count -= item->item_counts;
	}

		/* Create objects made by this phase */

	for ( i = 0; i < MAX_ITEMS_PER_SUBCRAFT; i++ ) {

		if ( phase_failed )
			continue;

		item = af->a.craft->subcraft->items [i];

		if ( !item ) {
			continue;
		}

		if ( !item->items [0] )
			continue;

		if ( !IS_SET (item->flags, SUBCRAFT_PRODUCED) ||
			 item->phase != phase )
			continue;

			/* We need to account for the quantity of an item */

		*color = '\0';

		for ( j = 0; j < MAX_ITEMS_PER_SUBCRAFT; j++ ) {
			item = af->a.craft->subcraft->items [j];
			if ( item && item->color ) {
				snprintf (color, MAX_STRING_LENGTH, "%s", item->color);
				break;
			}
		}

		item = af->a.craft->subcraft->items [i];

		if ( !item ) {
			continue;
		}

		if ( item->items[0] && vtoo(item->items[0]) ) {
			if ( color && IS_SET (vtoo(item->items[0])->obj_flags.extra_flags, ITEM_VARIABLE) ) {
				ch->delay_who = add_hash (color);
				obj_list [i] = load_colored_object (item->items [0], ch->delay_who);
				ch->delay_who = 0;
			}
			else obj_list [i] = load_object (item->items [0]);
		}

		if ( !obj_list [i] ) {
			act ("An object produced by this craft was not found. Please inform the staff.", FALSE, ch, 0, 0, TO_CHAR);

			af->a.craft->timer = 0;

			return;
		}

		obj_list [i]->count = item->item_counts;

		obj_to_room (obj_list [i], ch->in_room);
	}

	if ( !phase_failed && phase->load_mob && vtom (phase->load_mob) ) {
		char_to_room ((mob = load_mobile (phase->load_mob)), ch->in_room);
		if ( get_affect (mob, MAGIC_HIDDEN) )
			remove_affect_type (mob, MAGIC_HIDDEN);
	}

		/* Check to see if attribute check succeeded.  This really is
		   against the theme of this mud since it is skill based, not
           attribute based, but it was asked for anyway. */

	if ( phase->attribute > -1 ) {

		

		switch ( phase->attribute ) {
			case 0:  attr_value = GET_STR (ch); break;
			case 1:  attr_value = GET_DEX (ch); break;
			case 2:  attr_value = GET_CON (ch); break;
			case 3:  attr_value = GET_WIL (ch); break;
			case 4:  attr_value = GET_INT (ch); break;
			case 5:  attr_value = GET_AUR (ch); break;
			case 6:  attr_value = GET_AGI (ch); break;
		}
		dice_value = dice (phase->dice, phase->sides);
snprintf (test_buf, MAX_STRING_LENGTH,  "%d value against %d", attr_value, dice_value);
send_to_char(test_buf, ch);
		if ( attr_value < dice_value ){
			
			phase_failed = 1;
		}
	}

	if ( phase_failed ) {

				/* 1st person failure message */

		if ( phase->failure ) {
			craft_prepare_message (ch, buf, ch, target_ch, NULL, phase->failure,
								   tool, obj_list);
			if ( *buf == '#' )
				buf[2] = toupper(buf[2]);
			else *buf = toupper(*buf);
			act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
		} else if ( af->a.craft->subcraft->failure ) {
			craft_prepare_message (ch, buf, ch, target_ch, NULL,
								   af->a.craft->subcraft->failure, tool,
                                   obj_list);
			if ( *buf == '#' )
				buf[2] = toupper(buf[2]);
			else *buf = toupper(*buf);
			act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
		} else
			act ("You fail at your work.", FALSE, ch, 0, 0, TO_CHAR);

				/* 2nd person failure message */

			/* Don't give second to self. */
			if ( !(target_ch == ch) && (phase->second_failure)) {
			craft_prepare_message (ch, buf, ch, target_ch, NULL,
								   phase->second_failure, tool, obj_list);
			if ( *buf == '#' )
				buf[2] = toupper(buf[2]);
			else *buf = toupper(*buf);
			act (buf, FALSE, target_ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
		} 
		else {
			act ("$n abruptly stops $s craft.",
						FALSE, target_ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
		}

				/* 3rd person failure message */

		if ( phase->third_failure ) {
			craft_prepare_message (ch, buf, ch, target_ch, NULL,
								   phase->third_failure, tool, obj_list);
			if ( *buf == '#' )
				buf[2] = toupper(buf[2]);
			else *buf = toupper(*buf);
			act (buf, FALSE, ch, 0, target_ch, TO_NOTVICT | TO_ACT_FORMAT);
		} else
			act ("$n abruptly stops $s craft.",
						FALSE, ch, 0, target_ch, TO_NOTVICT | TO_ACT_FORMAT);

		    count = 0;

		    p = subcraft->failobjs;

		    while(p != NULL && *p != '\0' && *p != ')') {
			/* punt leading whitespace */
			while(isspace(*p) && *p != '\0') p++;

			/* Make sure there is no whitespace inside */
			while(isspace(*p) && *p != '\0') p++;

			/* Now if we have an 'x', we have a count */ 
			if(*p == 'x') {
			    p++;
			    while(!isdigit(*p) && *p != '\0') p++;
			    for(i=0;isdigit(*p); i++,p++)
                                numbuf[i] = *p;
                            numbuf[i] = '\0';
			    count = strtol(numbuf, NULL, 10);
			}
			
		        while(!isdigit(*p) && *p != '\0') p++;
		        for(i=0;isdigit(*p); i++,p++)
		            numbuf[i] = *p;
		        numbuf[i] = '\0';
			if(i > 0) { /* Then we have some kind of # */
		            failobj = load_object(strtol(numbuf, NULL, 10));
			    if(failobj != NULL) {
				if(count > 0)
	                            failobj->count = count;
				obj_to_room(failobj, ch->in_room);
			    }
			}
		}		

		af->a.craft->timer = 0;

		return;
	}

		/* First person message */

	if ( phase->first || phase->self ) {

		first = phase->first;

			/* Use self text, if it exists,  if PC targets himself */

		if ( phase->self &&
			 target_ch == ch &&
			 IS_SET (subcraft->subcraft_flags, SCF_TARGET_CHAR) )
			first = phase->self;

		craft_prepare_message (ch, buf, ch, target_ch, NULL,
							   first, tool, obj_list);

		if ( *buf == '#' )
			buf[2] = toupper(buf[2]);
		else *buf = toupper(*buf);
		act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
	}

		/* Second person message */

	if ( phase->second && target_ch && target_ch != ch ) {

		craft_prepare_message (target_ch, buf, ch,
							target_ch, NULL, phase->second, tool, obj_list);

		if ( *buf == '#' )
			buf[2] = toupper(buf[2]);
		else *buf = toupper(*buf);
		act (buf, FALSE, target_ch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
	}

		/* Third person message */

	for ( tch = ch->room->people; tch; tch = tch->next_in_room ) {

		if ( !phase->third )
			break;

		if ( tch == ch || tch == target_ch )
			continue;

		craft_prepare_message (tch, buf, ch, target_ch, tch,
							   phase->third, tool, obj_list);
		if ( *buf == '#' )
			buf[2] = toupper(buf[2]);
		else *buf = toupper(*buf);
		act (buf, FALSE, tch, 0, 0, TO_CHAR | TO_ACT_FORMAT);
	}
	
		/* Cast any spells from this phase */

	if ( phase->spell_type ) {

			/* Handle casting and first and second person messages */

		if ( IS_SET (subcraft->subcraft_flags, SCF_TARGET_SELF) ||
			 IS_SET (subcraft->subcraft_flags, SCF_TARGET_CHAR) ) {

			apply_affect (target_ch, phase->spell_type, phase->duration,
									   phase->power);
		}
	}

	if ( phase->open_skill ) {
		if ( IS_SET (phase->flags, PHASE_OPEN_ON_SELF) &&
			 !real_skill (ch, phase->open_skill) )
			open_skill (ch, phase->open_skill);

		else if ( !IS_SET (phase->flags, PHASE_OPEN_ON_SELF) &&
				  !real_skill (target_ch, phase->open_skill) )
			open_skill (target_ch, phase->open_skill);
	}

	if ( IS_SET (subcraft->subcraft_flags, SCF_TARGET_CHAR) &&
		 !is_he_here (ch, target_ch, 1) ) {
		send_to_char ("Your target is no longer here.\n", ch);
		af->a.craft->timer = 0;
		return;
	}

	if ( weaken (ch, 0, phase->move_cost, "cost of craft") )
		return;		/* He died */

		/* Immediately activate next phase after a phase with 0 timer */

	if ( !af->a.craft->timer && af->a.craft->phase )
		activate_phase (ch, af);
	else if ( !af->a.craft->phase && requires_skill_check (af->a.craft->subcraft) ) {
		if ( number(1,100) <= branching_check (ch, af->a.craft->subcraft) )
			branch_craft (ch, af->a.craft->subcraft);
	}

	if ( af->a.craft->subcraft->delay && !af->a.craft->phase ) {
		delay_time = (int)(time(0) + figure_craft_delay (ch, af->a.craft->subcraft));
		magic_add_affect (ch, MAGIC_CRAFT_DELAY, -1, delay_time, 0, 0, 0);
	}
}