lurf/area/
lurf/build/testing/
lurf/log/
lurf/player/
lurf/player/backup/
/***************************************************************************
 *  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.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  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.                                                  *
 ***************************************************************************/
#include <glib.h>

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <merc.h>
#include <tables.h>
#include <interp.h>
#include <fight.h>
#include <recycle.h>



/*
 * Local functions.
 */
void	say_spell	args( ( CHAR_DATA *ch, int sn ) );
void	improve_spl	args( ( CHAR_DATA *ch, int dtype, int sn ) );




/*
 * Improve ability at a certain spell type.  KaVir.
 */
void improve_spl( CHAR_DATA *ch, int dtype, int sn )
{
	char buf[MAX_INPUT_LENGTH];
	char bufskill[MAX_INPUT_LENGTH];
	char buftype[MAX_INPUT_LENGTH];
	int dice1,dice2,mdice1,mdice2;
	
	dice1 = number_percent();
	dice2 = number_percent();
        mdice1 = number_range(1,200);
        mdice2 = number_range(1,200);

	if (ch->spl[dtype] >= 200 && !IS_CLASS(ch, CLASS_MAGE)) return;
	if (ch->spl[dtype] >= 400) return;
        if ( IS_CLASS(ch,CLASS_MAGE))
        {
		if ((mdice1 > ch->spl[dtype] || mdice2 > ch->spl[dtype]) 
                             || (mdice1==200 || mdice2==200)) 
			ch->spl[dtype] += 1;
                else
			return;
        }
	else
	{
		if ((dice1 > ch->spl[dtype] || dice2 > ch->spl[dtype]) 
                             || (dice1==100 || dice2==100)) 
 			ch->spl[dtype] += 1;
                else
			return;
	}	
	if      (ch->spl[dtype] == 1  ) sprintf(bufskill,"an apprentice of");
	else if (ch->spl[dtype] == 26 ) sprintf(bufskill,"a student at");
	else if (ch->spl[dtype] == 51 ) sprintf(bufskill,"a scholar at");
	else if (ch->spl[dtype] == 76 ) sprintf(bufskill,"a magus at");
	else if (ch->spl[dtype] == 101) sprintf(bufskill,"an adept at");
	else if (ch->spl[dtype] == 126) sprintf(bufskill,"a mage at");
	else if (ch->spl[dtype] == 151) sprintf(bufskill,"a warlock at");
	else if (ch->spl[dtype] == 176) sprintf(bufskill,"a master wizard at");
	else if (ch->spl[dtype] == 200) sprintf(bufskill,"a grand sorcerer at");
	else if (ch->spl[dtype] == 400) sprintf(bufskill,"complete master of");
	else return;
	
	if      (dtype == 0 ) sprintf(buftype,"purple");
	else if (dtype == 1 ) sprintf(buftype,"red");
	else if (dtype == 2 ) sprintf(buftype,"blue");
	else if (dtype == 3 ) sprintf(buftype,"green");
	else if (dtype == 4 ) sprintf(buftype,"yellow");
	else return;
	
	sprintf(buf,"{WYou are now %s %s magic.\n\r{x",bufskill,buftype);
	send_to_char(buf,ch);
	return;
}

bool is_obj( CHAR_DATA *ch )
{
	OBJ_DATA *obj;
	
	if ( ( obj = ch->pcdata->chobj ) == NULL )
	{
		send_to_char("Huh?\n\r",ch);
		return FALSE;
	}
	if ( obj->chobj == NULL || obj->chobj != ch )
	{
		send_to_char("Huh?\n\r",ch);
		return FALSE;
	}
	return TRUE;
}

/*
 * Lookup a skill by name.
 */
int skill_lookup( const char *name )
{
	int sn;
	
	for ( sn = 0; sn < (MAX_SKILL + SKILL_ADD); sn++ )
	{
		if ( skill_table[sn].name == NULL )
			break;
		if ( LOWER(name[0]) == LOWER(skill_table[sn].name[0])
			&&   !str_prefix( name, skill_table[sn].name ) )
			return sn;
	}
	
	return -1;
}



/*
 * Lookup a skill by slot number.
 * Used for object loading.
 */
int slot_lookup( int slot )
{
	extern bool fBootDb;
	int sn;
	
	if ( slot <= 0 )
		return -1;
	
	for ( sn = 0; sn < MAX_SKILL; sn++ )
	{
		if ( slot == skill_table[sn].slot )
			return sn;
	}
	
	if ( fBootDb )
	{
		bug( "Slot_lookup: bad slot %d.", slot );
		abort( );
	}
	
	return -1;
}



/*
 * Utter mystical words for an sn.
 */
void say_spell( CHAR_DATA *ch, int sn )
{
	char buf  [MAX_STRING_LENGTH];
	char buf2 [MAX_STRING_LENGTH];
	GString *colour;
/*  CHAR_DATA *rch; */
	char *pName;
	int iSyl;
	int length;
	
	struct syl_type
	{
		char *	old;
		char *	new_type;
	};
	
	static const struct syl_type syl_table[] =
	{
		{ " ",		" "		},
		{ "ar",		"abra"		},
		{ "au",		"kada"		},
		{ "bless",	"fido"		},
		{ "blind",	"nose"		},
		{ "bur",	"mosa"		},
		{ "cu",		"judi"		},
		{ "de",		"oculo"		},
		{ "en",		"unso"		},
		{ "light",	"dies"		},
		{ "lo",		"hi"		},
		{ "mor",	"zak"		},
		{ "move",	"sido"		},
		{ "ness",	"lacri"		},
		{ "ning",	"illa"		},
		{ "per",	"duda"		},
		{ "ra",		"gru"		},
		{ "re",		"candus"	},
		{ "son",	"sabru"		},
		{ "tect",	"infra"		},
		{ "tri",	"cula"		},
		{ "ven",	"nofo"		},
		{ "a", "a" }, { "b", "b" }, { "c", "q" }, { "d", "e" },
		{ "e", "z" }, { "f", "y" }, { "g", "o" }, { "h", "p" },
		{ "i", "u" }, { "j", "y" }, { "k", "t" }, { "l", "r" },
		{ "m", "w" }, { "n", "i" }, { "o", "a" }, { "p", "s" },
		{ "q", "d" }, { "r", "f" }, { "s", "g" }, { "t", "h" },
		{ "u", "j" }, { "v", "z" }, { "w", "x" }, { "x", "n" },
		{ "y", "l" }, { "z", "k" },
		{ "", "" }
	};
	
	buf[0]	= '\0';
	for ( pName = skill_table[sn].name; *pName != '\0'; pName += length )
	{
		for ( iSyl = 0; (length = strlen(syl_table[iSyl].old)) != 0; iSyl++ )
		{
			if ( !str_prefix( syl_table[iSyl].old, pName ) )
			{
				strcat( buf, syl_table[iSyl].new_type );
				break;
			}
		}
		
		if ( length == 0 )
			length = 1;
	}
	
	sprintf( buf2, "$n utters the words, '%s'.", buf );
	sprintf( buf,  "$n utters the words, '%s'.", skill_table[sn].name );

	colour = g_string_new("");
        if ( !IS_HEAD(ch, LOST_EYE_L) && !IS_HEAD(ch, LOST_EYE_R) ) /* no eyes, no eye glow -rc */
        {
	    g_string_sprintf(colour,"$n's eyes glow bright %s for a moment.", spell_colour_table[skill_table[sn].target].name);
	    ADD_COLOUR(ch,colour,spell_colour_table[skill_table[sn].target].colour)
	    act(colour->str,ch,NULL,NULL,TO_ROOM);
	    
            g_string_sprintf(colour,"Your eyes glow bright %s for a moment.", spell_colour_table[skill_table[sn].target].name);
	    ADD_COLOUR(ch,colour,spell_colour_table[skill_table[sn].target].colour);
	    act(colour->str,ch,NULL,NULL,TO_CHAR);
        }
	g_string_free(colour,TRUE);	
	return;
}



/*
 * Compute a saving throw.
 * Negative apply's make saving throw better.
 */
bool saves_spell( int level, CHAR_DATA *victim )
{
	int save;
	int tsave;
	if (!IS_NPC(victim))
	{
		tsave = (int)((double)( victim->spl[0]+victim->spl[1]+victim->spl[2]+
			victim->spl[3]+victim->spl[4] ) * 0.05);
		save = 50 + ( tsave - level - victim->saving_throw ) * 5;
	}
	else
		save = 50 + ( victim->level - level - victim->saving_throw ) * 5;
	save = URANGE( 15, save, 85 );
	return number_percent( ) < save;
}



/*
 * The kludgy global is for spells who want more stuff from command line.
 */
char *target_name;

void do_cast( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	OBJ_DATA *obj;
	void *vo;
	int mana;
	int sn;
        
        victim = NULL;	
    /*
     * Switched NPC's can cast spells, but others can't.
     */
	if ( IS_NPC(ch) && ch->desc == NULL )
		return;
	
    /* Polymorphed players cannot cast spells */
	if ( (!IS_NPC(ch) && IS_AFFECTED(ch, AFF_POLYMORPH) && 
		!IS_VAMPAFF(ch,VAM_DISGUISED)) || IS_EXTRA(ch, EXTRA_OSWITCH))
	{
		if ( !is_obj(ch) )
		{
			send_to_char( "You cannot cast spells in this form.\n\r", ch );	
			return;
		}
	}

        if ( ch->delay_timer > 1)
        {
                send_to_char("Not with a delay timer...\n\r",ch);
                return;
        }

	if ( IS_ITEMAFF(ch, ITEMA_REFLECT))
	{
		send_to_char( "You are unable to focus your spell.\n\r", ch );
		return;
	}
	
	target_name = one_argument( argument, arg1 );
	one_argument( target_name, arg2 );
	
	if ( arg1[0] == '\0' )
	{
		send_to_char( "Cast which what where?\n\r", ch );
		return;
	}
	
	if ( ( sn = skill_lookup( arg1 ) ) < 0
		|| ( !IS_NPC(ch) && ch->level < skill_table[sn].skill_level) )
	{
		send_to_char( "You can't do that.\n\r", ch );
		return;
	}
	
	if ( skill_table[sn].spell_fun == spell_null )
	{
		send_to_char( "That's not a spell!\n\r", ch );
		return;
	}
	
	if (!IS_NPC(ch) && IS_SET(ch->pcdata->powers[WOLF_POLYAFF], POLY_ZULO))
	{
		send_to_char("Not in your form",ch);
		return;
	}
	
	if ( ch->position < skill_table[sn].minimum_position )
	{
		if (!IS_NPC(ch) && !IS_CLASS(ch, CLASS_VAMPIRE) &&
			get_disc(ch, DISC_CELERITY) > 0 )
		{
			if ( ch->move < 25 )
			{
				send_to_char( "You can't concentrate enough.\n\r", ch );
				return;
			}
			ch->move = ch->move - 25;
		}
		else
		{
			if ( ch->move < 50 )
			{
				send_to_char( "You can't concentrate enough.\n\r", ch );
				return;
			}
			ch->move = ch->move - 50;
		}
	}
	
	mana = IS_NPC(ch) ? 0 : UMAX(
		skill_table[sn].min_mana,
		100 / ( 2 + (ch->level*12) - skill_table[sn].skill_level) );
	
	if ( !IS_NPC(ch) && IS_SET(ch->special, SPC_WOLFMAN) )
	{
		if (ch->pcdata->powers[WPOWER_OWL] < 4) mana *= 2;
	}
	
    /*
     * Locate targets.
     */
	obj		= NULL;
	vo		= NULL;
	
	switch ( skill_table[sn].target )
	{
		default:
			bug( "Do_cast: bad target for sn %d.", sn );
			return;

		case TAR_IGNORE:
			break;

		case TAR_CHAR_OFFENSIVE:
			if ( arg2[0] == '\0' )
			{
				if ( ( victim = ch->fighting ) == NULL )
				{
					send_to_char( "Cast the spell on whom?\n\r", ch );
					return;
				}
			}
			else
			{
				if ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
				{
					send_to_char( "They aren't here.\n\r", ch );
					return;
				}
			}

			if ( ch == victim )
				send_to_char( "Cast this on yourself? Ok...\n\r", ch );

			if (check_pk(ch,victim,CHECK_DELAY|CHECK_ATTACK) )
				return;

			if ( IS_ITEMAFF(victim, ITEMA_REFLECT))
			{
				send_to_char( "You are unable to focus your spell upon them.\n\r", ch );
				return;
			}

			if (is_safe(ch,victim))
			{
				send_to_char("No hostlye magic in a safe room!\n\r",ch);
				return;
			}

			if (!IS_NPC(victim) && (!CAN_PK(ch) || !CAN_PK(victim)) && (ch != victim))
			{
				send_to_char( "You are unable to affect them.\n\r", ch );
				return;
			}
			/* You cannot attack across planes */
			if (ch->plane != victim->plane){
				send_to_char("Nope, your not on same plane!\n\e",ch);
				return;
			}
 		    if ( !IS_NPC(ch) )
			{
				if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
				{
					send_to_char( "You can't do that on your own follower.\n\r",
							ch );
					return;
				}
			}

			set_attack_flag(ch,victim);
			vo = (void *) victim;
			break;

		case TAR_CHAR_DEFENSIVE:
			if ( arg2[0] == '\0' )
			{
				victim = ch;
			}
			else
			{
				if ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
				{
					send_to_char( "They aren't here.\n\r", ch );
					return;
				}
			}

			if ( IS_ITEMAFF(victim, ITEMA_REFLECT))
			{
				send_to_char( "You are unable to focus your spell upon them.\n\r", ch );
				return;
			}

			//      if (!IS_NPC(victim) && (!CAN_PK(ch) || !CAN_PK(victim)) && (ch != victim))
			if ( (ch->level < 3) && ((victim->level > 2) && !IS_NPC(victim)))
			{
				send_to_char( "You are unable to affect them.\n\r", ch );
				return;
			}
			/* You cannot attack across planes */
			if (ch->plane != victim->plane){
				send_to_char("Nope, your not int he same plane!\n\e",ch);
				return;
			}
			vo = (void *) victim;
			break;

		case TAR_CHAR_SELF:
			if ( arg2[0] != '\0' && !is_name( arg2, ch->name->str ) )
			{
				send_to_char( "You cannot cast this spell on another.\n\r", ch );
				return;
			}

			vo = (void *) ch;
			break;

		case TAR_OBJ_INV:
			if ( arg2[0] == '\0' )
			{
				send_to_char( "What should the spell be cast upon?\n\r", ch );
				return;
			}

			if ( ( obj = get_obj_carry( ch, arg2 ) ) == NULL )
			{
				send_to_char( "You are not carrying that.\n\r", ch );
				return;
			}

			vo = (void *) obj;
			break;
	}
	
	if ( !IS_NPC(ch) && ch->mana < mana )
	{
		send_to_char( "You don't have enough mana.\n\r", ch );
		return;
	}
	
	if ( str_cmp( skill_table[sn].name, "ventriloquate" ) )
		say_spell( ch, sn );
	
	WAIT_STATE( ch, skill_table[sn].beats );
	
	if ( !IS_NPC(ch) && number_percent( ) > ch->pcdata->learned[sn] )
	{
		send_to_char( "You lost your concentration.\n\r", ch );
		ch->mana -= mana / 2;
		improve_spl(ch,skill_table[sn].target,sn);
	}
	else
	{
		ch->mana -= mana;
	/* Check players ability at spell type for spell power...KaVir */
		if (IS_NPC(ch))
			(*skill_table[sn].spell_fun) ( sn, ch->level, ch, vo );
		else
		{
			(*skill_table[sn].spell_fun) ( sn, (int)((double)ch->spl[skill_table[sn].target]*0.25), ch, vo );
			improve_spl(ch,skill_table[sn].target,sn);
		}
	}
	
	if ( skill_table[sn].target == TAR_CHAR_OFFENSIVE
		&&   victim != ch
		&&   victim->master != ch )
	{
		CHAR_DATA *vch;
		CHAR_DATA *vch_next;
		
		for ( vch = ch->in_room->people; vch; vch = vch_next )
		{
			vch_next = vch->next_in_room;
			if ( victim == vch && victim->fighting == NULL )
			{
				multi_hit( victim, ch, TYPE_UNDEFINED );
				break;
			}
		}
	}
	
	return;
}



/*
 * Cast spells at targets using a magical object.
 */
void obj_cast_spell( int sn, int level, CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj )
{
	void *vo;
	
	if ( sn <= 0 )
		return;
	
	if ( sn >= MAX_SKILL || skill_table[sn].spell_fun == 0 )
	{
		bug( "Obj_cast_spell: bad sn %d.", sn );
		return;
	}
	
	switch ( skill_table[sn].target )
	{
		default:
			bug( "Obj_cast_spell: bad target for sn %d.", sn );
			return;
			
		case TAR_IGNORE:
			vo = NULL;
			break;
			
		case TAR_CHAR_OFFENSIVE:
			if ( victim == NULL )
				victim = ch->fighting;
			if ( victim == NULL )
			{
				send_to_char( "You can't do that.\n\r", ch );
				return;
			}
			vo = (void *) victim;
			break;
			
		case TAR_CHAR_DEFENSIVE:
			if ( victim == NULL )
				victim = ch;
			vo = (void *) victim;
			break;
			
		case TAR_CHAR_SELF:
			vo = (void *) ch;
			break;
			
		case TAR_OBJ_INV:
			if ( obj == NULL )
			{
				send_to_char( "You can't do that.\n\r", ch );
				return;
			}
			vo = (void *) obj;
			break;
	}
	
	target_name = "";
	(*skill_table[sn].spell_fun) ( sn, level, ch, vo );
	
	if ( skill_table[sn].target == TAR_CHAR_OFFENSIVE
		&&   victim != ch
		&&   victim->master != ch )
	{
		CHAR_DATA *vch;
		CHAR_DATA *vch_next;
		
		for ( vch = ch->in_room->people; vch; vch = vch_next )
		{
			vch_next = vch->next_in_room;
			if ( victim == vch && victim->fighting == NULL )
			{
				multi_hit( victim, ch, TYPE_UNDEFINED );
				break;
			}
		}
	}
	
	return;
}



/*
 * Spell functions.
 */
void spell_acid_blast( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_ACIDSHIELD)) return;
	dam = dice( level * 5, 10 );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_ACID) )
		return;
	else
	{
		if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_ACID) )
			damage( ch, victim, dam, sn );
		damage( ch, victim, dam, sn );
	}
	return;
}



void spell_armor( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	int arm_mod = -20;
	
	if (!IS_NPC(ch) && IS_CLASS(ch, CLASS_MAGE))
		arm_mod = -40;

	if ( is_affected( victim, sn ) )
		return;
	af.type      = sn;
	af.duration  = 24;
	af.modifier  = arm_mod;
	af.location  = APPLY_AC;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	act( "$n is shrouded in a suit of translucent glowing armor.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You are shrouded in a suit of translucent glowing armor.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_bless( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( is_affected( victim, sn ) ) return;
	af.type      = sn;
	af.duration  = 6+level;
	af.location  = APPLY_HITROLL;
	af.modifier  = level / 8 + 5;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	
	af.location  = APPLY_SAVING_SPELL;
	af.modifier  = 0 - level / 8;
	affect_to_char( victim, &af );
	act( "$n is blessed.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You feel righteous.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_blindness( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	char buf [MAX_INPUT_LENGTH];
	
	if ( IS_AFFECTED(victim, AFF_BLIND) || victim->level >= 100 || saves_spell( level, victim ) )
		return;
	
	af.type      = sn;
	af.location  = APPLY_HITROLL;
	af.modifier  = -14;
	af.duration  = 1+level;
	af.bitvector = AFF_BLIND;
	affect_to_char( victim, &af );
	send_to_char( "You are blinded!\n\r", victim );
	if (!IS_NPC(victim))
		sprintf(buf,"%s is blinded!\n\r",victim->name->str);
	else
		sprintf(buf,"%s is blinded!\n\r",victim->short_descr->str);
	send_to_char(buf,ch);
	return;
}



void spell_burning_hands( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_FIRESHIELD)) return;
	
	dam		= number_range( level, level * 2 );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_HEAT) )
		return;
	else
	{
		if (!IS_NPC(victim) && IS_CLASS(victim, CLASS_VAMPIRE) )
		{
			if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_HEAT) )
				damage( ch, victim, (dam*2), sn );
			damage( ch, victim, (dam*2), sn );
			hp = ((hp - victim->hit)/2) + victim->hit;
		}
		else
			if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_HEAT) )
				damage( ch, victim, dam, sn );
			damage( ch, victim, dam, sn );
	}
	return;
}



void spell_call_lightning( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *vch;
	CHAR_DATA *vch_next;
	int dam;
	int hp;
	
	if ( !IS_OUTSIDE(ch) )
	{
		send_to_char( "You must be out of doors.\n\r", ch );
		return;
	}
	
	if ( weather_info[ch->in_room->sector_type].sky < SKY_RAINING )
	{
		send_to_char( "You need bad weather.\n\r", ch );
		return;
	}
	
	dam = dice(level/2, 8);
	
	send_to_char( "God's lightning strikes your foes!\n\r", ch );
	act( "$n calls God's lightning to strike $s foes!",
		ch, NULL, NULL, TO_ROOM );
	
	for ( vch = char_list; vch != NULL; vch = vch_next )
	{
		vch_next	= vch->next;
		if ( vch->in_room == NULL )
			continue;
		if ( vch->in_room == ch->in_room )
		{
			if ( vch != ch && ( IS_NPC(ch) ? !IS_NPC(vch) : IS_NPC(vch) ) )
			{
				if (IS_ITEMAFF(vch, ITEMA_SHOCKSHIELD)) continue;
				if ( saves_spell( level, vch ) )
					dam /= 2;
				hp = vch->hit;
				if (!IS_NPC(vch) && IS_IMMMERIT(vch, IMM_MERIT_LIGHTNING) )
					continue;
				else
				{
					if (!IS_NPC(vch) && IS_IMMFLAW(vch, IMM_FLAW_LIGHTNING) )
						damage( ch, vch, dam, sn );
					damage( ch, vch, dam, sn );
				}
			}
			continue;
		}
		
		if ( vch->in_room->area == ch->in_room->area
			&&   IS_OUTSIDE(vch)
			&&   IS_AWAKE(vch) )
			send_to_char( "Lightning flashes in the sky.\n\r", vch );
	}
	return;
}




void spell_cause_light( int sn, int level, CHAR_DATA *ch, void *vo )
{
	damage( ch, (CHAR_DATA *) vo, dice(1, 8) + level / 3, sn );
	return;
}



void spell_cause_critical( int sn, int level, CHAR_DATA *ch, void *vo )
{
	damage( ch, (CHAR_DATA *) vo, dice(3, 8) + level - 6, sn );
	return;
}



void spell_cause_serious( int sn, int level, CHAR_DATA *ch, void *vo )
{
	damage( ch, (CHAR_DATA *) vo, dice(2, 8) + level / 2, sn );
	return;
}



void spell_change_sex( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	return;
	if ( is_affected( victim, sn ) )
		return;
	af.type      = sn;
	af.duration  = 10 * level;
	af.location  = APPLY_SEX;
	do
	{
		af.modifier  = number_range( 0, 2 ) - victim->sex;
	}
	while ( af.modifier == 0 );
	af.bitvector = 0;
	affect_to_char( victim, &af );
	send_to_char( "You feel different.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_charm_person( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;

	if (victim == NULL)
		return;

	if (ch->fighting != NULL || victim->fighting != NULL)
	{
		send_to_char("they resist!",ch);
		return;
	}

	if ( victim->level < 3 && !IS_NPC(victim) )
	{
		send_to_char( "You can NOT charm that target!\n\r", ch );
		return;
	}
	
	if ( victim == ch )
	{
		send_to_char( "You like yourself even better!\n\r", ch );
		return;
	}
	
	if ( !IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_CHARM) )
	{
		send_to_char( "You failed.\n\r", ch );
		return;
	}
	
    /* I don't want people charming ghosts and stuff - KaVir */
    if (ch->plane != PLANE_NORMAL){
		send_to_char("You must cast this on the normal plane.\n\r",ch);
		return;
	}	

	if (IS_IMMORTAL( victim ))
	{
		send_to_char( "You can't cast puny mortal magic on immortals!\n\r",ch);
		return;
	}
	
	if ( IS_AFFECTED(victim, AFF_CHARM)
		||   IS_AFFECTED(ch, AFF_CHARM)
		||   level < victim->level
		||   saves_spell( level, victim ) )
		return;
	
	if ( victim->master )
		stop_follower( victim );

	add_follower( victim, ch );
	af.type      = sn;
	af.duration  = number_fuzzy( level / 4 );
	af.location  = 0;
	af.modifier  = 0;
	af.bitvector = AFF_CHARM;
	affect_to_char( victim, &af );
	act( "Isn't $n just so nice?", ch, NULL, victim, TO_VICT );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_chill_touch( int sn, int level, CHAR_DATA *ch, void *vo )
{
	bool no_dam = FALSE;
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	int dam;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_ICESHIELD)) return;
	
	dam		= number_range( level / 2, level * 2 );
    if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_COLD) ) no_dam = TRUE;
	if ( !no_dam && (!saves_spell( level, victim ) ||
		IS_NPC(victim) || !IS_CLASS(victim, CLASS_VAMPIRE) ) )
	{
		af.type      = sn;
		af.duration  = 6;
		af.location  = APPLY_STR;
		af.modifier  = -1;
		af.bitvector = 0;
		affect_join( victim, &af );
	}
	else
	{
		dam /= 2;
	}
	
	hp = victim->hit;
	damage( ch, victim, dam, sn );
	if (no_dam) victim->hit = hp;
	return;
}



void spell_colour_spray( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	
    dam		= number_range( level / 3, level );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	
	damage( ch, victim, dam, sn );
	return;
}



void spell_continual_light( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *light;
	
	light = create_object( get_obj_index( OBJ_VNUM_LIGHT_BALL ), 0 );
	obj_to_room( light, ch->in_room );
	act( "$n twiddles $s thumbs and $p appears.",   ch, light, NULL, TO_ROOM );
	act( "You twiddle your thumbs and $p appears.", ch, light, NULL, TO_CHAR );
	return;
}



void spell_control_weather( int sn, int level, CHAR_DATA *ch, void *vo )
{
	if ( !str_cmp( target_name, "better" ) )
		weather_info[ch->in_room->sector_type].change += dice( level / 3, 4 );
	else if ( !str_cmp( target_name, "worse" ) )
		weather_info[ch->in_room->sector_type].change -= dice( level / 3, 4 );
	else
		send_to_char ("Do you want it to get better or worse?\n\r", ch );
	
	send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_create_food( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *mushroom;
	
	mushroom = create_object( get_obj_index( OBJ_VNUM_MUSHROOM ), 0 );
	mushroom->value[0] = 5 + level;
	obj_to_room( mushroom, ch->in_room );
	act( "$p suddenly appears.", ch, mushroom, NULL, TO_ROOM );
	act( "$p suddenly appears.", ch, mushroom, NULL, TO_CHAR );
	return;
}



void spell_create_spring( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *spring;
	
	spring = create_object( get_obj_index( OBJ_VNUM_SPRING ), 0 );
	spring->timer = level;
	obj_to_room( spring, ch->in_room );
	act( "$p flows from the ground.", ch, spring, NULL, TO_ROOM );
	act( "$p flows from the ground.", ch, spring, NULL, TO_CHAR );
	return;
}



void spell_create_water( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	int water;
	
	if ( obj->item_type != ITEM_DRINK_CON )
	{
		send_to_char( "It is unable to hold water.\n\r", ch );
		return;
	}
	
	if ( obj->value[2] != LIQ_WATER && obj->value[1] != 0 )
	{
		send_to_char( "It contains some other liquid.\n\r", ch );
		return;
	}
	
	water = UMIN(
		level * (weather_info[ch->in_room->sector_type].sky >= SKY_RAINING ? 4 : 2),
		obj->value[0] - obj->value[1]
		);
	
	if ( water > 0 )
	{
		obj->value[2] = LIQ_WATER;
		obj->value[1] += water;
		if ( !is_name( "water", obj->name->str ) )
		{
			char buf[MAX_STRING_LENGTH];
			
			sprintf( buf, "%s water", obj->name->str );
			obj->name = g_string_assign(obj->name,buf);
		}
		act( "$p is filled.", ch, obj, NULL, TO_CHAR );
	}
	
	return;
}



void spell_cure_blindness( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	if ( !is_affected( victim, gsn_blindness ) )
		return;
	affect_strip( victim, gsn_blindness );
	send_to_char( "Your vision returns!\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	return;
}



void spell_cure_critical( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int heal;
	
	heal = dice(3, 8) + level - 6;
	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );
	send_to_char( "You feel better!\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	return;
}



void spell_cure_light( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int heal;
	
	heal = dice(1, 8) + level / 3;
	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );
	send_to_char( "You feel better!\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	return;
}



void spell_cure_poison( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	if ( is_affected( victim, gsn_poison ) )
	{
		affect_strip( victim, gsn_poison );
		act( "$N looks better.", ch, NULL, victim, TO_NOTVICT );
		send_to_char( "A warm feeling runs through your body.\n\r", victim );
		send_to_char( "Ok.\n\r", ch );
		if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	}
	return;
}



void spell_cure_serious( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int heal;
	
	heal = dice(2, 8) + level /2 ;
	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );
	send_to_char( "You feel better!\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	return;
}



void spell_curse( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( IS_AFFECTED(victim, AFF_CURSE) || saves_spell( level, victim ) )
		return;
	af.type      = sn;
	af.duration  = 4*level;
	af.location  = APPLY_HITROLL;
	af.modifier  = -10;
	af.bitvector = AFF_CURSE;
	affect_to_char( victim, &af );
	
	af.location  = APPLY_SAVING_SPELL;
	af.modifier  = 1;
	affect_to_char( victim, &af );
	
	send_to_char( "You feel unclean.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_detect_evil( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	SPHERE_DATA af;
	
	if ( IS_SET(victim->sight, SIGHT_ALIGNMENT) )
		return;
	af.spell_number = mage_affect_slot("DetectEvil");
	af.type      = TYPE_SIGHT;
	af.duration  = level;
	af.bitvector = SIGHT_ALIGNMENT;
	sphere_to_char( victim, &af );
	send_to_char( "Your eyes tingle.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_detect_hidden( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	SPHERE_DATA af;
	
	if ( IS_SET(victim->sight, SIGHT_HIDDEN) )
		return;
	af.spell_number = mage_affect_slot("DetectHidden");
	af.type      = TYPE_SIGHT;
	af.duration  = level;
	af.bitvector = SIGHT_HIDDEN;
	sphere_to_char( victim, &af );
	send_to_char( "Your awareness improves.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_detect_invis( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	SPHERE_DATA af;
	
	if ( IS_SET(victim->sight, SIGHT_INVISABLE) )
		return;
	af.spell_number = mage_affect_slot("Detectinvis");
	af.type      = TYPE_SIGHT;
	af.duration  = level;
	af.bitvector = SIGHT_INVISABLE;
	sphere_to_char( victim, &af );
	send_to_char( "Your eyes tingle.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_detect_magic( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	SPHERE_DATA af;
	
	if ( IS_SET(victim->sight, SIGHT_MAGIC) )
		return;
	af.spell_number = mage_affect_slot("DetectMagic");
	af.type      = TYPE_SIGHT;
	af.duration  = level;
	af.bitvector = SIGHT_MAGIC;
	sphere_to_char( victim, &af );
	send_to_char( "Your eyes tingle.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_detect_poison( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	
	if ( obj->item_type == ITEM_DRINK_CON || obj->item_type == ITEM_FOOD )
	{
		if ( obj->value[3] != 0 )
			send_to_char( "You smell poisonous fumes.\n\r", ch );
		else
			send_to_char( "It looks very delicious.\n\r", ch );
	}
	else
	{
		send_to_char( "It doesn't look poisoned.\n\r", ch );
	}
	
	return;
}



void spell_dispel_evil( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	
	if ( !IS_NPC(ch) && IS_EVIL(ch) )
		victim = ch;
	
	if ( IS_GOOD(victim) )
	{
		act( "God protects $N.", ch, NULL, victim, TO_ROOM );
		return;
	}
	
	if ( IS_NEUTRAL(victim) )
	{
		act( "$N does not seem to be affected.", ch, NULL, victim, TO_CHAR );
		return;
	}
	
	dam = dice( level, 4 );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	damage( ch, victim, dam, sn );
	if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	return;
}



void spell_dispel_magic( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA *paf;
	AFFECT_DATA *paf_next = NULL;
	
	if ( victim != ch &&
		(saves_spell( level, victim ) || level < victim->level) )
	{
		send_to_char( "You failed.\n\r", ch );
		return;
	}
	
	if ( !(victim->affected) )
	{
		send_to_char( "Nothing happens.\n\r", ch );
		return;
	}
 
	for ( paf = victim->affected; paf != NULL; paf = paf_next )
	{
                paf_next = paf->next;
		if ( paf->type >= MAX_SKILL )
			continue;

		affect_remove(victim,paf);

	}
	
	if ( ch == victim )
	{
		act("You remove all magical affects from yourself.",ch,NULL,NULL,TO_CHAR);
		act("$n has removed all magical affects from $mself.",ch,NULL,NULL,TO_ROOM);
	}
	else
	{
		act("You remove all magical affects from $N.",ch,NULL,victim,TO_CHAR);
		act("$n has removed all magical affects from $N.",ch,NULL,victim,TO_NOTVICT);
		act("$n has removed all magical affects from you.",ch,NULL,victim,TO_VICT);
	}
	
	return;
}



void spell_earthquake( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *vch;
	CHAR_DATA *vch_next;
	
	send_to_char( "The earth trembles beneath your feet!\n\r", ch );
	act( "$n makes the earth tremble and shiver.", ch, NULL, NULL, TO_ROOM );
	
	for ( vch = char_list; vch != NULL; vch = vch_next )
	{
		vch_next	= vch->next;

		if ( vch->in_room == NULL )
			continue;

		if ( vch->in_room == ch->in_room )
		{
			if ( vch != ch && ( IS_NPC(ch) ? !IS_NPC(vch) : IS_NPC(vch) ) )
				damage( ch, vch, level + dice(2, 8), sn );
			continue;
		}
		
		if ( vch->in_room->area == ch->in_room->area )
			send_to_char( "The earth trembles and shivers.\n\r", vch );
	}
	
	return;
}



void spell_enchant_weapon( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA *paf;
	
	if ( obj->item_type != ITEM_WEAPON
		||   IS_SET(obj->quest, QUEST_ENCHANTED)
		||   IS_SET(obj->quest, QUEST_ARTIFACT)
		||   obj->chobj != NULL )
	{
		send_to_char("You are unable to enchant this weapon.\n\r",ch);
		return;
	}
	
	paf = new_affect();

	paf->type		= sn;
	paf->duration	= -1;
	paf->location	= APPLY_HITROLL;
	paf->modifier	= level / 5;
	paf->bitvector	= 0;
	paf->next		= obj->affected;
	obj->affected	= paf;
	
	paf = new_affect();
/*
    paf->type		= -1;
*/
	paf->type		= sn;
	paf->duration	= -1;
	paf->location	= APPLY_DAMROLL;
	paf->modifier	= level / 10;
	paf->bitvector	= 0;
	paf->next		= obj->affected;
	obj->affected	= paf;
	
	if ( IS_GOOD(ch) )
	{
		SET_BIT(obj->extra_flags, ITEM_ANTI_EVIL);
		SET_BIT(obj->quest, QUEST_ENCHANTED);
		act( "$p glows blue.", ch, obj, NULL, TO_CHAR );
		act( "$p glows blue.", ch, obj, NULL, TO_ROOM );
	}
	else if ( IS_EVIL(ch) )
	{
		SET_BIT(obj->extra_flags, ITEM_ANTI_GOOD);
		SET_BIT(obj->quest, QUEST_ENCHANTED);
		act( "$p glows red.", ch, obj, NULL, TO_CHAR );
		act( "$p glows red.", ch, obj, NULL, TO_ROOM );
	}
	else
	{
		SET_BIT(obj->extra_flags, ITEM_ANTI_EVIL);
		SET_BIT(obj->extra_flags, ITEM_ANTI_GOOD);
		SET_BIT(obj->quest, QUEST_ENCHANTED);
		act( "$p glows yellow.", ch, obj, NULL, TO_CHAR );
		act( "$p glows yellow.", ch, obj, NULL, TO_ROOM );
	}
	return;
}



/*
 * Drain XP, MANA, HP.
 * Caster gains HP.
 */
void spell_energy_drain( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	int hp;
	
	if ( saves_spell( level, victim ) )
		return;
	
	if ( !IS_HERO(ch))
		ch->alignment = UMAX(-1000, ch->alignment - 200);
	
	if ( victim->level <= 2 )
	{
		dam		 = dice(1, level);
	}
	else
	{
		dam		 = dice(1, level);
		if (!IS_NPC(victim) && !IS_IMMMERIT(victim, IMM_MERIT_DRAIN) )
		{
			if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_DRAIN) )
			{
			victim->mana	/= 2;
			victim->move	/= 2;
			ch->hit		+= dam;
			if (ch->hit > (2*ch->max_hit))
				ch->hit = (2 * ch->max_hit);
			}
			victim->mana	/= 2;
			victim->move	/= 2;
			ch->hit		+= dam;
			if (ch->hit > (2*ch->max_hit))
				ch->hit = (2 * ch->max_hit);
		}
		if (IS_NPC(victim))
		{
			victim->mana	/= 2;
			victim->move	/= 2;
			ch->hit		+= dam;
			if (ch->hit > (2*ch->max_hit))
				ch->hit = (2 * ch->max_hit);
		}
	}
	
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_DRAIN) )
		return;             
	else 
		damage( ch, victim, dam, sn );
	if (!IS_NPC(ch) && ch != victim) do_beastlike(ch,"");
	
	return;
}



void spell_fireball( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_FIRESHIELD)) return;
	
	dam		= number_range( level * 2, level * 3 );
    if ( saves_spell( level, victim ) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_HEAT) )
		return;
	else
	{
		if (!IS_NPC(victim) && IS_CLASS(victim, CLASS_VAMPIRE) )
		{
			if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_HEAT) )
				damage( ch, victim, (dam*2), sn );
			damage( ch, victim, (dam*2), sn );
			hp = ((hp - victim->hit)/2) + victim->hit;
		}
		else
			if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_HEAT) )
				damage( ch, victim, dam, sn );
			damage( ch, victim, dam, sn );
	}
	return;
}



void spell_flamestrike( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_FIRESHIELD)) return;
	dam = dice(6, 8);
	if ( saves_spell( level, victim ) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_HEAT) )
		return;
	else
	{
		if (!IS_NPC(victim) && IS_CLASS(victim, CLASS_VAMPIRE) )
		{
			if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_HEAT) )
				damage( ch, victim, (dam*2), sn );
			damage( ch, victim, (dam*2), sn );
			hp = ((hp - victim->hit)/2) + victim->hit;
		}
		else
			if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_HEAT) )
				damage( ch, victim, dam, sn );
			damage( ch, victim, dam, sn );
	}
	return;
}



void spell_faerie_fire( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( IS_AFFECTED(victim, AFF_FAERIE_FIRE) )
		return;
	af.type      = sn;
	af.duration  = level;
	af.location  = APPLY_AC;
	af.modifier  = 2 * level;
	af.bitvector = AFF_FAERIE_FIRE;
	affect_to_char( victim, &af );
	send_to_char( "You are surrounded by a pink outline.\n\r", victim );
	act( "$n is surrounded by a pink outline.", victim, NULL, NULL, TO_ROOM );
	return;
}



void spell_faerie_fog( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *ich;
	
	act( "$n conjures a cloud of purple smoke.", ch, NULL, NULL, TO_ROOM );
	send_to_char( "You conjure a cloud of purple smoke.\n\r", ch );
	
	for ( ich = ch->in_room->people; ich != NULL; ich = ich->next_in_room )
	{
		if ( !IS_NPC(ich) && IS_SET(ich->act, PLR_WIZINVIS) )
			continue;
		
		if ( ich == ch || saves_spell( level, ich ) )
			continue;
		
		affect_strip ( ich, gsn_invis			);
		affect_strip ( ich, gsn_mass_invis		);
		affect_strip ( ich, gsn_sneak			);
		REMOVE_BIT   ( ich->affected_by, AFF_HIDE	);
		REMOVE_BIT   ( ich->affected_by, AFF_INVISIBLE	);
		REMOVE_BIT   ( ich->affected_by, AFF_SNEAK	);
		act( "$n is revealed!", ich, NULL, NULL, TO_ROOM );
		send_to_char( "You are revealed!\n\r", ich );
	}
	
	return;
}



void spell_fly( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( IS_AFFECTED(victim, AFF_FLYING) )
		return;
	af.type      = sn;
	af.duration  = level + 3;
	af.location  = 0;
	af.modifier  = 0;
	af.bitvector = AFF_FLYING;
	affect_to_char( victim, &af );
	send_to_char( "You rise up off the ground.\n\r", victim );
	act( "$n rises up off the ground.", victim, NULL, NULL, TO_ROOM );
	return;
}



void spell_gate( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char_to_room( create_mobile( get_mob_index(MOB_VNUM_VAMPIRE) ),
		ch->in_room );
	return;
}



/*
 * Spell for mega1.are from Glop/Erkenbrand.
 */
void spell_general_purpose( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	
	dam = number_range( 25, 100 );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	damage( ch, victim, dam, sn );
	return;
}



void spell_giant_strength( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( is_affected( victim, sn ) )
		return;
	af.type      = sn;
	af.duration  = level;
	af.location  = APPLY_STR;
	af.modifier  = 2 + (level >= 18) + (level >= 25);
	af.bitvector = 0;
	affect_to_char( victim, &af );
	send_to_char( "You feel stronger.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_harm( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	
	dam = UMAX(  20, victim->hit - dice(1,4) );
	if ( saves_spell( level, victim ) )
		dam = UMIN( 50, dam / 4 );
	dam = UMIN( 100, dam ) * 10;
	damage( ch, victim, dam, sn );
	return;
}



void spell_heal( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	victim->hit = UMIN( victim->hit + 100, victim->max_hit );
	update_pos( victim );
	send_to_char( "A warm feeling fills your body.\n\r", victim );
	if (ch == victim)
		act( "$n heals $mself.", ch, NULL, NULL, TO_ROOM );
	else
		act( "$n heals $N.", ch, NULL, victim, TO_NOTVICT );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	return;
}



/*
 * Spell for mega1.are from Glop/Erkenbrand.
 */
void spell_high_explosive( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	
	dam = number_range( 30, 120 );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	damage( ch, victim, dam, sn );
	return;
}



void spell_identify( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	char buf[MAX_STRING_LENGTH];
	AFFECT_DATA *paf;
	int itemtype;
	
	act("You examine $p carefully.",ch,obj,NULL,TO_CHAR);
	act("$n examines $p carefully.",ch,obj,NULL,TO_ROOM);
	
	sprintf( buf,
		"Object '%s' is type %s, extra flags %s.\n\rWeight is %d, value is %d.\n\r",
		
		obj->name->str,
		item_type_name( obj ),
		extra_bit_name( obj->extra_flags ),
		obj->weight,
		obj->cost
		);
	send_to_char( buf, ch );
	
	if (obj->points > 0 && obj->item_type != ITEM_QUEST
		&& obj->item_type != ITEM_PAGE)
	{
		sprintf( buf, "Quest point value is %d.\n\r", obj->points );
		send_to_char( buf, ch );
	}
	if (obj->questmaker != NULL && obj->questmaker->len > 1 &&
		obj->questowner != NULL && obj->questowner->len > 1)
	{
		sprintf( buf, "This object was created by %s, and is owned by %s.\n\r", obj->questmaker->str,obj->questowner->str );
		send_to_char( buf, ch );
	}
	else if (obj->questmaker != NULL && obj->questmaker->len > 1)
	{
		sprintf( buf, "This object was created by %s.\n\r", obj->questmaker->str );
		send_to_char( buf, ch );
	}
	else if (obj->questowner != NULL && obj->questowner->len > 1)
	{
		sprintf( buf, "This object is owned by %s.\n\r", obj->questowner->str );
		send_to_char( buf, ch );
	}
	
	if (IS_SET(obj->quest, QUEST_ENCHANTED))
		send_to_char( "This item has been enchanted.\n\r", ch );
	if (IS_SET(obj->quest, QUEST_SPELLPROOF))
		send_to_char( "This item is resistant to offensive spells.\n\r", ch );
	if (IS_SET(obj->spectype, SITEM_DEMONIC))
		send_to_char( "This item is crafted from demonsteel.\n\r", ch );
	else if (IS_SET(obj->spectype, SITEM_SILVER))
		send_to_char( "This item is crafted from gleaming silver.\n\r", ch );
	
	switch ( obj->item_type )
	{
		case ITEM_PILL: 
		case ITEM_SCROLL: 
		case ITEM_POTION:
			sprintf( buf, "Level %d spells of:", obj->value[0] );
			send_to_char( buf, ch );
			
			if ( obj->value[1] >= 0 && obj->value[1] < MAX_SKILL )
			{
				send_to_char( " '", ch );
				send_to_char( skill_table[obj->value[1]].name, ch );
				send_to_char( "'", ch );
			}
			
			if ( obj->value[2] >= 0 && obj->value[2] < MAX_SKILL )
			{
				send_to_char( " '", ch );
				send_to_char( skill_table[obj->value[2]].name, ch );
				send_to_char( "'", ch );
			}
			
			if ( obj->value[3] >= 0 && obj->value[3] < MAX_SKILL )
			{
				send_to_char( " '", ch );
				send_to_char( skill_table[obj->value[3]].name, ch );
				send_to_char( "'", ch );
			}
			
			send_to_char( ".\n\r", ch );
			break;
			
		case ITEM_QUEST:
			sprintf( buf, "Quest point value is %d.\n\r", obj->value[0] );
			send_to_char( buf, ch );
			break;
			
		case ITEM_QUESTCARD:
			sprintf( buf, "Quest completion reward is %d quest points.\n\r", obj->level );
			send_to_char( buf, ch );
			break;
			
		case ITEM_WAND: 
		case ITEM_STAFF: 
			sprintf( buf, "Has %d(%d) charges of level %d",
				obj->value[1], obj->value[2], obj->value[0] );
			send_to_char( buf, ch );
			
			if ( obj->value[3] >= 0 && obj->value[3] < MAX_SKILL )
			{
				send_to_char( " '", ch );
				send_to_char( skill_table[obj->value[3]].name, ch );
				send_to_char( "'", ch );
			}
			
			send_to_char( ".\n\r", ch );
			break;
			
		case ITEM_WEAPON:
			sprintf( buf, "Damage is %d to %d (average %d).\n\r",
				obj->value[1], obj->value[2],
				( obj->value[1] + obj->value[2] ) / 2 );
			send_to_char( buf, ch );
			
			if (obj->value[0] >= 1000)
				itemtype = obj->value[0] - ((obj->value[0] / 1000) * 1000);
			else
				itemtype = obj->value[0];
			
			if (itemtype > 0)
			{
				if (obj->level < 10)
					sprintf(buf,"%s is a minor spell weapon.\n\r",capitalize(obj->short_descr->str));
				else if (obj->level < 20)
					sprintf(buf,"%s is a lesser spell weapon.\n\r",capitalize(obj->short_descr->str));
				else if (obj->level < 30)
					sprintf(buf,"%s is an average spell weapon.\n\r",capitalize(obj->short_descr->str));
				else if (obj->level < 40)
					sprintf(buf,"%s is a greater spell weapon.\n\r",capitalize(obj->short_descr->str));
				else if (obj->level < 50)
					sprintf(buf,"%s is a major spell weapon.\n\r",capitalize(obj->short_descr->str));
				else if (obj->level > 50)
					sprintf(buf,"%s is an ultimate spell weapon.\n\r",capitalize(obj->short_descr->str));
				else
					sprintf(buf,"%s is a supreme spell weapon.\n\r",capitalize(obj->short_descr->str));
				send_to_char(buf,ch);
			}
			
			if (itemtype == 1)
				sprintf (buf, "This weapon is dripping with corrosive acid.\n\r");
			else if (itemtype == 4)
				sprintf (buf, "This weapon radiates an aura of darkness.\n\r");
			else if (itemtype == 5)
				sprintf (buf, "Blood is dripping all over this weapon.\n\r");
			else if (itemtype == 30)
				sprintf (buf, "This ancient relic is the bane of all evil.\n\r");
			else if (itemtype == 34)
				sprintf (buf, "This vampiric weapon drinks the souls of its victims.\n\r");
			else if (itemtype == 37)
				sprintf (buf, "This weapon has been tempered in hellfire.\n\r");
			else if (itemtype == 48)
				sprintf (buf, "This weapon crackles with sparks of lightning.\n\r");
			else if (itemtype == 53)
				sprintf (buf, "This weapon is dripping with a dark poison.\n\r");
			else if (itemtype > 0)
				sprintf (buf, "This weapon has been imbued with the power of %s.\n\r",skill_table[itemtype].name);
			if (itemtype > 0)
				send_to_char( buf, ch );
			
			if (obj->value[0] >= 1000)
				itemtype = obj->value[0] / 1000;
			else
				break;
			
			if (itemtype == 4)
				sprintf (buf, "This weapon radiates an aura of darkness.\n\r");
			else if (itemtype == 27 || itemtype == 2)
				sprintf (buf, "This weapon allows the wielder to see invisible things.\n\r");
			else if (itemtype == 39 || itemtype == 3)
				sprintf (buf, "This weapon grants the power of flight.\n\r");
			else if (itemtype == 45 || itemtype == 1)
				sprintf (buf, "This weapon allows the wielder to see in the dark.\n\r");
			else if (itemtype == 46 || itemtype == 5)
				sprintf (buf, "This weapon renders the wielder invisible to the human eye.\n\r");
			else if (itemtype == 52 || itemtype == 6)
				sprintf (buf, "This weapon allows the wielder to walk through solid doors.\n\r");
			else if (itemtype == 54 || itemtype == 7)
				sprintf (buf, "This holy weapon protects the wielder from evil.\n\r");
			else if (itemtype == 57 || itemtype == 8)
				sprintf (buf, "This ancient weapon protects the wielder in combat.\n\r");
			else if (itemtype == 9)
				sprintf (buf, "This crafty weapon allows the wielder to walk in complete silence.\n\r");
			else if (itemtype == 10)
				sprintf (buf, "This powerful weapon surrounds its wielder with a shield of lightning.\n\r");
			else if (itemtype == 11)
				sprintf (buf, "This powerful weapon surrounds its wielder with a shield of fire.\n\r");
			else if (itemtype == 12)
				sprintf (buf, "This powerful weapon surrounds its wielder with a shield of ice.\n\r");
			else if (itemtype == 13)
				sprintf (buf, "This powerful weapon surrounds its wielder with a shield of acid.\n\r");
			else if (itemtype == 14)
				sprintf (buf, "This weapon protects its wielder from clan DarkBlade guardians.\n\r");
			else if (itemtype == 15)
				sprintf (buf, "This ancient weapon surrounds its wielder with a shield of chaos.\n\r");
			else if (itemtype == 16)
				sprintf (buf, "This ancient weapon regenerates the wounds of its wielder.\n\r");
			else if (itemtype == 17)
				sprintf (buf, "This ancient weapon allows its wielder to move at supernatural speed.\n\r");
			else if (itemtype == 18)
				sprintf (buf, "This razor sharp weapon can slice through armour without difficulty.\n\r");
			else if (itemtype == 19)
				sprintf (buf, "This ancient weapon protects its wearer from player attacks.\n\r");
			else if (itemtype == 20)
				sprintf (buf, "This ancient weapon surrounds its wielder with a shield of darkness.\n\r");
			else if (itemtype == 21)
				sprintf (buf, "This ancient weapon grants superior protection to its wielder.\n\r");
			else if (itemtype == 22)
				sprintf (buf, "This ancient weapon grants its wielder supernatural vision.\n\r");
			else if (itemtype == 23)
				sprintf (buf, "This ancient weapon makes its wielder fleet-footed.\n\r");
			else if (itemtype == 24)
				sprintf (buf, "This ancient weapon conceals its wielder from sight.\n\r");
			else if (itemtype == 25)
				sprintf (buf, "This ancient weapon invokes the power of the beast.\n\r");
			else
				sprintf (buf, "This item is bugged...please report it.\n\r");
			if (itemtype > 0)
				send_to_char( buf, ch );
			break;
			
		case ITEM_ARMOR:
			sprintf( buf, "Armor class is %d.\n\r", obj->value[0] );
			send_to_char( buf, ch );
			if (obj->value[3] < 1)
				break;
			if (obj->value[3] == 4)
				sprintf (buf, "This object radiates an aura of darkness.\n\r");
			else if (obj->value[3] == 27 || obj->value[3] == 2)
				sprintf (buf, "This item allows the wearer to see invisible things.\n\r");
			else if (obj->value[3] == 39 || obj->value[3] == 3)
				sprintf (buf, "This object grants the power of flight.\n\r");
			else if (obj->value[3] == 45 || obj->value[3] == 1)
				sprintf (buf, "This item allows the wearer to see in the dark.\n\r");
			else if (obj->value[3] == 46 || obj->value[3] == 5)
				sprintf (buf, "This object renders the wearer invisible to the human eye.\n\r");
			else if (obj->value[3] == 52 || obj->value[3] == 6)
				sprintf (buf, "This object allows the wearer to walk through solid doors.\n\r");
			else if (obj->value[3] == 54 || obj->value[3] == 7)
				sprintf (buf, "This holy relic protects the wearer from evil.\n\r");
			else if (obj->value[3] == 57 || obj->value[3] == 8)
				sprintf (buf, "This ancient relic protects the wearer in combat.\n\r");
			else if (obj->value[3] == 9)
				sprintf (buf, "This crafty item allows the wearer to walk in complete silence.\n\r");
			else if (obj->value[3] == 10)
				sprintf (buf, "This powerful item surrounds its wearer with a shield of lightning.\n\r");
			else if (obj->value[3] == 11)
				sprintf (buf, "This powerful item surrounds its wearer with a shield of fire.\n\r");
			else if (obj->value[3] == 12)
				sprintf (buf, "This powerful item surrounds its wearer with a shield of ice.\n\r");
			else if (obj->value[3] == 13)
				sprintf (buf, "This powerful item surrounds its wearer with a shield of acid.\n\r");
			else if (obj->value[3] == 14)
				sprintf (buf, "This object protects its wearer from clan DarkBlade guardians.\n\r");
			else if (obj->value[3] == 15)
				sprintf (buf, "This ancient item surrounds its wearer with a shield of chaos.\n\r");
			else if (obj->value[3] == 16)
				sprintf (buf, "This ancient item regenerates the wounds of its wearer.\n\r");
			else if (obj->value[3] == 17)
				sprintf (buf, "This ancient item allows its wearer to move at supernatural speed.\n\r");
			else if (obj->value[3] == 18)
				sprintf (buf, "This powerful item allows its wearer to shear through armour without difficulty.\n\r");
			else if (obj->value[3] == 19)
				sprintf (buf, "This powerful item protects its wearer from player attacks.\n\r");
			else if (obj->value[3] == 20)
				sprintf (buf, "This ancient item surrounds its wearer with a shield of darkness.\n\r");
			else if (obj->value[3] == 21)
				sprintf (buf, "This ancient item grants superior protection to its wearer.\n\r");
			else if (obj->value[3] == 22)
				sprintf (buf, "This ancient item grants its wearer supernatural vision.\n\r");
			else if (obj->value[3] == 23)
				sprintf (buf, "This ancient item makes its wearer fleet-footed.\n\r");
			else if (obj->value[3] == 24)
				sprintf (buf, "This ancient item conceals its wearer from sight.\n\r");
			else if (obj->value[3] == 25)
				sprintf (buf, "This ancient item invokes the power of the beast.\n\r");
			else if (obj->value[3] == 66)
				sprintf (buf, "This ancient item protects vampires from sunlight.\n\r");
			else
				sprintf (buf, "This item is bugged...please report it.\n\r");
			if (obj->value[3] > 0)
				send_to_char( buf, ch );
			break;
	}
	
	for ( paf = obj->pIndexData->affected; paf != NULL; paf = paf->next )
	{
		if ( paf->location != APPLY_NONE && paf->modifier != 0 )
		{
			sprintf( buf, "Affects %s by %d.\n\r",
				affect_loc_name( paf->location ), paf->modifier );
			send_to_char( buf, ch );
		}
	}
	
	for ( paf = obj->affected; paf != NULL; paf = paf->next )
	{
		if ( paf->location != APPLY_NONE && paf->modifier != 0 )
		{
			sprintf( buf, "Affects %s by %d.\n\r",
				affect_loc_name( paf->location ), paf->modifier );
			send_to_char( buf, ch );
		}
	}
	
	return;
}



void spell_infravision( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	SPHERE_DATA af;
	
	if ( IS_SET(victim->sight, SIGHT_INFRARED) )
		return;
	act( "$n's eyes glow red.\n\r", ch, NULL, NULL, TO_ROOM );
	af.spell_number = mage_affect_slot("DetectMagic");
	af.type      = TYPE_SIGHT;
	af.duration  = 2 * level;
	af.bitvector = SIGHT_INFRARED;
	sphere_to_char( victim, &af );
	send_to_char( "Your eyes glow red.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_invis( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( IS_AFFECTED(victim, AFF_INVISIBLE) )
		return;
	
	act( "$n fades out of existence.", victim, NULL, NULL, TO_ROOM );
	af.type      = sn;
	af.duration  = 24;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_INVISIBLE;
	affect_to_char( victim, &af );
	send_to_char( "You fade out of existence.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_know_alignment( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	char *msg;
	int ap;
	
	ap = victim->alignment;
	
	if ( ap >  700 ) msg = "$N has an aura as white as the driven snow.";
	else if ( ap >  350 ) msg = "$N is of excellent moral character.";
	else if ( ap >  100 ) msg = "$N is often kind and thoughtful.";
	else if ( ap > -100 ) msg = "$N doesn't have a firm moral commitment.";
	else if ( ap > -350 ) msg = "$N lies to $S friends.";
	else if ( ap > -700 ) msg = "$N's slash DISEMBOWELS you!";
	else msg = "I'd rather just not say anything at all about $N.";
	
	act( msg, ch, NULL, victim, TO_CHAR );
	return;
}



void spell_lightning_bolt( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_SHOCKSHIELD)) return;
	
	dam		= number_range( level, level * 2 );
    if ( saves_spell( level, victim ) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_LIGHTNING) )
		return;
	else
	{
		if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_LIGHTNING) )
			damage( ch, victim, dam, sn );
		damage( ch, victim, dam, sn );
	}
	return;
}

typedef struct locate_info locinfo;
struct locate_info{ 
	CHAR_DATA *ch;
	int count;
	bool found;
}; 

void process_locate(OBJ_DATA *obj, locinfo *user_data)
{
	OBJ_DATA *in_obj;
	GString *buffer;
	
	if (user_data->count > 50 )
		return;
	
	if ( !is_name( target_name, obj->name->str ) ){
		return;
	}
		
    for ( in_obj = obj; in_obj->in_obj != NULL; in_obj = in_obj->in_obj )
			;
		
    if (!can_see_obj( user_data->ch, in_obj )){
    	return;
    }
		
	if (obj->item_type == ITEM_WWF_CONT){
		return;
	}
		
	buffer = g_string_new("");
	if ( in_obj->carried_by != NULL )
	{
		g_string_sprintf( buffer, "%s carried by %s.\n\r",
			obj->short_descr->str, PERS(in_obj->carried_by, user_data->ch) );
	}
	else
	{
		g_string_sprintf( buffer, "%s in %s.\n\r",
			obj->short_descr->str, in_obj->in_room == NULL
			? "somewhere" : in_obj->in_room->name );
	}
	
	buffer = g_string_assign(buffer,capitalize(buffer->str));
	send_to_char( buffer->str, user_data->ch );
	g_string_free(buffer,TRUE);
	user_data->found = TRUE;
	user_data->count++;

	return;	
} 

void spell_locate_object( int sn, int level, CHAR_DATA *ch, void *vo )
{
	locinfo *locinfo1;
	locinfo1 = (locinfo *)g_malloc(sizeof(locinfo));
	
	locinfo1->found = FALSE;
	locinfo1->count = 0;
	locinfo1->ch = ch;
	
	g_slist_foreach(object_list,(GFunc)process_locate,locinfo1);
		
	if ( !locinfo1->found )
		send_to_char( "Nothing like that in hell, earth, or heaven.\n\r", ch );
	g_free(locinfo1);
	return;
}



void spell_magic_missile( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	
	dam		= number_range( level /3, level / 2 );
    if ( saves_spell( level, victim ) )
		dam /= 2;
	damage( ch, victim, dam, sn );
	return;
}



void spell_mass_invis( int sn, int level, CHAR_DATA *ch, void *vo )
{
	AFFECT_DATA af;
	CHAR_DATA *gch;
	
	for ( gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room )
	{
		if ( !is_same_group( gch, ch ) || IS_AFFECTED(gch, AFF_INVISIBLE) )
			continue;
		act( "$n slowly fades out of existence.", gch, NULL, NULL, TO_ROOM );
		send_to_char( "You slowly fade out of existence.\n\r", gch );
		af.type      = sn;
		af.duration  = 24;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bitvector = AFF_INVISIBLE;
		affect_to_char( gch, &af );
	}
	send_to_char( "Ok.\n\r", ch );
	
	return;
}

void spell_perfection( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj;
	char buf[MAX_INPUT_LENGTH];
	bool IS_MASTER;
	int  stype;
	int  wtype;
	int  dtype;
	
	IS_MASTER = TRUE;
	
	if (IS_NPC(ch))
	{ 
		send_to_char( "NPC's don't get perfection!\n\r", ch );
		return;
	}
	
	if ( ch->level < 3 )
	{ 
		send_to_char( "You must avatar to cast this spell.\n\r", ch );
		return;
	}
	
	for ( stype = 1; stype <= 10; stype++ )
	{
		if ( ch->stance[stype] < 200 )
		{    
			IS_MASTER = FALSE;
			break;
		}
	}
	
	for ( wtype = 0; wtype <= 12; wtype++ )
	{
		if ( ch->wpn[wtype] < 200 )
		{
			IS_MASTER = FALSE;
			break;
		}
	}
	
	for ( dtype = 0; dtype <= 4; dtype++ )
	{
		if (ch->spl[dtype] < 200) 
		{
			IS_MASTER = FALSE;
			break;
		}
	}
	
	if (!IS_MASTER)
	{ 
		send_to_char( "Looks like you need to practice more.\n\r", ch );
		return;
	}
	
	obj = create_object( get_obj_index( OBJ_VNUM_MASTERY ), 0 );
	
	obj->item_type = ITEM_ARMOR;
	obj->wear_flags = ITEM_TAKE + ITEM_WEAR_FACE;
	obj->weight = 1;
	
	sprintf(buf,"%s mask perfection",ch->name->str);
	obj->name = g_string_assign(obj->name,buf);
	sprintf(buf,"%s's Mask of Perfection",ch->name->str);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	sprintf(buf,"%s's Mask of Perfection lies here.",ch->name->str);
	obj->description = g_string_assign(obj->description,buf);
	
	obj->questmaker = g_string_assign(obj->questmaker,ch->name->str);
	
	obj->questowner = g_string_assign(obj->questowner,ch->name->str);
	
	obj_to_char( obj, ch );
	act( "$p suddenly appears in your hands.", ch, obj, NULL, TO_CHAR );
	act( "$p suddenly appears in $n's hands.", ch, obj, NULL, TO_ROOM );
	return;
}

void spell_null( int sn, int level, CHAR_DATA *ch, void *vo )
{
	send_to_char( "That's not a spell!\n\r", ch );
	return;
}



void spell_pass_door( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( IS_AFFECTED(victim, AFF_PASS_DOOR) )
		return;
	af.type      = sn;
	af.duration  = number_fuzzy( level / 4 );
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_PASS_DOOR;
	affect_to_char( victim, &af );
	act( "$n turns translucent.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You turn translucent.\n\r", victim );
	return;
}



void spell_poison( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	char buf [MAX_INPUT_LENGTH];
	
    /* Ghosts cannot be poisoned - KaVir */
	if ( is_tempsafe(victim))
	{
		send_to_char("Not in safe rooms!",ch);
		return;
	}

	if ( !IS_NPC(victim) && IS_CLASS(victim, CLASS_VAMPIRE) &&
		get_disc(victim, DISC_SERPENTIS) > 0 ) return;
	else if ( !IS_NPC(victim) && IS_CLASS(victim, CLASS_WEREWOLF) &&
		victim->pcdata->powers[WPOWER_SPIDER] > 2 ) return;
    
    if (IS_SWWF(victim) && get_tribe(victim,TRIBE_FIANNA) >= 1)
        {
            send_to_char("They seem to be unaffected.\n\r",ch);
            return;
        }

	
	if ( saves_spell( level, victim ) )
		return;
	af.type      = sn;
	af.duration  = level;
	af.location  = APPLY_STR;
	af.modifier  = 0 - number_range(1,3);
	af.bitvector = AFF_POISON;
	affect_join( victim, &af );
	send_to_char( "You feel very sick.\n\r", victim );
	if ( ch == victim ) return;
	if (!IS_NPC(victim))
		sprintf(buf,"%s looks very sick as your poison takes affect.\n\r",victim->name->str);
	else
		sprintf(buf,"%s looks very sick as your poison takes affect.\n\r",victim->short_descr->str);
	send_to_char(buf,ch);
	return;
}



void spell_protection( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( IS_AFFECTED(victim, AFF_PROTECT) )
		return;
	af.type      = sn;
	af.duration  = 24;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_PROTECT;
	affect_to_char( victim, &af );
	send_to_char( "You feel protected.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



void spell_refresh( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	victim->move = UMIN( victim->move + level, victim->max_move );
	act("$n looks less tired.",victim,NULL,NULL,TO_ROOM);
	send_to_char( "You feel less tired.\n\r", victim );
	if (!IS_NPC(victim) && victim->sex == SEX_MALE && 
		victim->pcdata->stage[0] < 1 && victim->pcdata->stage[2] > 0)
		victim->pcdata->stage[2] = 0;
	return;
}



void spell_remove_curse( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim;
	OBJ_DATA  *obj;
	char       arg [MAX_INPUT_LENGTH];
	
	one_argument( target_name, arg );
	
	if ( arg[0] == '\0')
	{
		send_to_char( "Remove curse on what?\n\r", ch );
		return;
	}
	
	if ( ( victim = get_char_world( ch, target_name ) ) != NULL )
	{
		if ( is_affected( victim, gsn_curse ) )
		{
			affect_strip( victim, gsn_curse );
			send_to_char( "You feel better.\n\r", victim );
			if ( ch != victim )
				send_to_char( "Ok.\n\r", ch );
			if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
		}
		return;
	}
	if ( ( obj = get_obj_carry( ch, arg ) ) != NULL )
	{
		if ( IS_SET(obj->extra_flags, ITEM_NOREMOVE) )
		{
			REMOVE_BIT(obj->extra_flags, ITEM_NOREMOVE);
			act( "$p flickers with energy.", ch, obj, NULL, TO_CHAR );
		}
		else if ( IS_SET(obj->extra_flags, ITEM_NODROP) )
		{
			REMOVE_BIT(obj->extra_flags, ITEM_NODROP);
			act( "$p flickers with energy.", ch, obj, NULL, TO_CHAR );
		}
		return;
	}
	send_to_char( "No such creature or object to remove curse on.\n\r", ch );
	return;
}



void spell_sanctuary( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( IS_AFFECTED(victim, AFF_SANCTUARY) )
		return;
	af.type      = sn;
	af.duration  = number_fuzzy( level / 8 );
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_SANCTUARY;
	affect_to_char( victim, &af );
	act( "$n is surrounded by a white aura.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You are surrounded by a white aura.\n\r", victim );
	return;
}



void spell_shield( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( is_affected( victim, sn ) )
		return;
	af.type      = sn;
	af.duration  = 8 + level;
	af.location  = APPLY_AC;
	af.modifier  = -20;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	act( "$n is surrounded by a force shield.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You are surrounded by a force shield.\n\r", victim );
	return;
}



void spell_shocking_grasp( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_SHOCKSHIELD)) return;
	
	dam		= number_range( level * 2 , level * 3 );
    if ( saves_spell( level, victim ) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_LIGHTNING) )
		return;
	else
	{
		if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_LIGHTNING) )
			damage( ch, victim, dam, sn );
		damage( ch, victim, dam, sn );
	}
	return;
}



void spell_sleep( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if (victim == NULL)
		return;

	if (ch->fighting != NULL || victim->fighting != NULL)
	{
		send_to_char("they resist!",ch);
		return;
	}

	if ( IS_AFFECTED(victim, AFF_SLEEP)
		||   level < victim->level
		|| ( !IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_SLEEP) )
		|| ( !IS_NPC(victim) && !IS_IMMFLAW(victim, IMM_FLAW_SLEEP) && saves_spell( level, victim )) )
		return;
	
	if (IS_AFFECTED(victim, AFF_SLEEP))
		return;
	
	af.type      = sn;
	af.duration  = 6;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_SLEEP;
	affect_join( victim, &af );
	
	if ( IS_AWAKE(victim) )
	{
		send_to_char( "You feel very sleepy ..... zzzzzz.\n\r", victim );
		act( "$n goes to sleep.", victim, NULL, NULL, TO_ROOM );
		victim->position = POS_SLEEPING;
	}
	
	return;
}



void spell_stone_skin( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( is_affected( ch, sn ) )
		return;
	af.type      = sn;
	af.duration  = level;
	af.location  = APPLY_AC;
	af.modifier  = -40;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	act( "$n's skin turns to stone.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "Your skin turns to stone.\n\r", victim );
	return;
}



void spell_summon( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim;
	CHAR_DATA *mount;
	
	if ( ( victim = get_char_world( ch, target_name ) ) == NULL
		||   victim == ch
		||   victim->in_room == NULL
		||   is_tempsafe(victim) 
		||   IS_SET(victim->in_room->room_flags, ROOM_PRIVATE)
		||   IS_SET(victim->in_room->room_flags, ROOM_SOLITARY)
		||   IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
		||   victim->level >= level + 3
		||   victim->fighting != NULL
		||   victim->in_room->area != ch->in_room->area
		||   (strstr(victim->in_room->area->builders, "Unlinked" ))
		||   (!IS_NPC(victim) && !IS_IMMUNE(victim, IMM_SUMMON) )
		||   (IS_NPC(victim) && saves_spell( level, victim ) ) )
	{
		send_to_char( "You failed.\n\r", ch );
		return;
	}
	
	act( "$n disappears suddenly.", victim, NULL, NULL, TO_ROOM );
	char_from_room( victim );
	char_to_room( victim, ch->in_room );
	act( "$n arrives suddenly.", victim, NULL, NULL, TO_ROOM );
	act( "$N has summoned you!", victim, NULL, ch,   TO_CHAR );
	do_look( victim, "auto" );
	if ( (mount = victim->mount) == NULL ) return;
	char_from_room( mount );
	char_to_room( mount, get_room_index(victim->in_room->vnum) );
	do_look( mount, "auto" );
	return;
}

void teleport_char(CHAR_DATA *victim){

	CHAR_DATA *mount;
	ROOM_INDEX_DATA *pRoomIndex;
	int to_room;
	
	for ( ; ; )
	{
		to_room = number_range( 0, 65535 );
		pRoomIndex = get_room_index( to_room );
		if ( pRoomIndex != NULL )
			if ( !IS_SET(pRoomIndex->room_flags, ROOM_PRIVATE)
				&&   !IS_SET(pRoomIndex->room_flags, ROOM_SOLITARY)
				&&   !IS_SET(pRoomIndex->room_flags, ROOM_NO_TELEPORT)
				&& ( !(strstr(pRoomIndex->area->builders, "Unlinked")))
				&&   to_room != 30008 && to_room != 30002 && to_room != 2
				&&   to_room != 1     && to_room != 1200)
				break;
	}
	
	act( "$n slowly fades out of existence.", victim, NULL, NULL, TO_ROOM );
	char_from_room( victim );
	char_to_room( victim, pRoomIndex );
	act( "$n slowly fades into existence.", victim, NULL, NULL, TO_ROOM );
	do_look( victim, "auto" );
	if ( (mount = victim->mount) == NULL ) return;
	char_from_room( mount );
	char_to_room( mount, victim->in_room );
	do_look( mount, "auto" );
	return;

}

void spell_teleport( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;

	if ( victim->in_room == NULL
		||   IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
		||   is_tempsafe(victim)
		||   IS_SET(victim->in_room->room_flags, ROOM_NO_TELEPORT)
		|| ( !IS_NPC(ch) && victim->fighting != NULL )
		|| ( !IS_NPC(victim) && !IS_IMMUNE(victim, IMM_SUMMON) )
		|| ( victim != ch
			&& ( saves_spell( level, victim ) || saves_spell( level, victim ) ) ) )
	{
		send_to_char( "You failed.\n\r", ch );
		return;
	}
	/**
	 * Made this in to a function for other routines in the 
	 * code.
	 */
	teleport_char(victim);
	return;
}



void spell_ventriloquate( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char buf1[MAX_STRING_LENGTH];
	char buf2[MAX_STRING_LENGTH];
	char speaker[MAX_INPUT_LENGTH];
	CHAR_DATA *vch;
	
	target_name = one_argument( target_name, speaker );
	
	sprintf( buf1, "%s says '%s'.\n\r",              speaker, target_name );
	sprintf( buf2, "Someone makes %s say '%s'.\n\r", speaker, target_name );
	buf1[0] = UPPER(buf1[0]);
	
	for ( vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room )
	{
		if ( !is_name( speaker, vch->name->str ) )
			send_to_char( saves_spell( level, vch ) ? buf2 : buf1, vch );
	}
	
	return;
}



void spell_weaken( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( is_affected( victim, sn ) || saves_spell( level, victim ) )
		return;
	af.type      = sn;
	af.duration  = level / 2;
	af.location  = APPLY_STR;
	af.modifier  = -2;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	send_to_char( "You feel weaker.\n\r", victim );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	return;
}



/*
 * This is for muds that _want_ scrolls of recall.
 * Ick.
 */
void spell_word_of_recall( int sn, int level, CHAR_DATA *ch, void *vo )
{
	do_recall( (CHAR_DATA *) vo, "" );
	return;
}



/*
 * NPC spells.
 */
void spell_acid_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj_lose;
	OBJ_DATA *obj_next;
	int dam;
	int hpch;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_ACIDSHIELD)) return;
	
	if ( number_percent( ) < 2 * level && !saves_spell( level, victim ) )
	{
		for ( obj_lose = ch->carrying; obj_lose != NULL; obj_lose = obj_next )
		{
			int iWear;
			
			obj_next = obj_lose->next_content;
			
			if ( number_bits( 2 ) != 0 )
				continue;
			
			if (IS_SET(obj_lose->quest,QUEST_SPELLPROOF)) continue;
			switch ( obj_lose->item_type )
			{
				case ITEM_ARMOR:
					if ( obj_lose->value[0] > 0 )
					{
						act( "$p is pitted and etched!",
							victim, obj_lose, NULL, TO_CHAR );
						if ( ( iWear = obj_lose->wear_loc ) != WEAR_NONE )
							victim->armor -= apply_ac( obj_lose, iWear );
						obj_lose->value[0] -= 1;
						obj_lose->cost      = 0;
						if ( iWear != WEAR_NONE )
							victim->armor += apply_ac( obj_lose, iWear );
					}
					break;
					
				case ITEM_CONTAINER:
					act( "$p fumes and dissolves!",
						victim, obj_lose, NULL, TO_CHAR );
					extract_obj( obj_lose );
					break;
			}
		}
	}
	
	hpch = UMAX( 10, ch->hit );
	dam  = number_range( hpch/16+1, hpch/8 );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_ACID) )
		return;          
	else
	{
		if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_ACID) )
			damage( ch, victim, dam, sn );
		damage( ch, victim, dam, sn );
	}
	return;
}



void spell_fire_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj_lose;
	OBJ_DATA *obj_next;
	int dam;
	int hpch;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_FIRESHIELD)) return;
	
	if ( number_percent( ) < 2 * level && !saves_spell( level, victim ) )
	{
		for ( obj_lose = victim->carrying; obj_lose != NULL;
			obj_lose = obj_next )
		{
			char *msg;
			
			obj_next = obj_lose->next_content;
			if ( number_bits( 2 ) != 0 )
				continue;
			
			if (IS_SET(obj_lose->quest,QUEST_SPELLPROOF)) continue;
			switch ( obj_lose->item_type )
			{
				default:             continue;
				case ITEM_CONTAINER: msg = "$p ignites and burns!";   break;
				case ITEM_POTION:    msg = "$p bubbles and boils!";   break;
				case ITEM_SCROLL:    msg = "$p crackles and burns!";  break;
				case ITEM_STAFF:     msg = "$p smokes and chars!";    break;
				case ITEM_WAND:      msg = "$p sparks and sputters!"; break;
				case ITEM_FOOD:      msg = "$p blackens and crisps!"; break;
				case ITEM_PILL:      msg = "$p melts and drips!";     break;
			}
			
			act( msg, victim, obj_lose, NULL, TO_CHAR );
			extract_obj( obj_lose );
		}
	}
	
	hpch = UMAX( 10, ch->hit );
	dam  = number_range( hpch/16+1, hpch/8 );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_HEAT) )
		return;
	else
	{
		if (!IS_NPC(victim) && IS_CLASS(victim, CLASS_VAMPIRE) )
		{
			if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_HEAT) )
				damage( ch, victim, (dam*2), sn );
			damage( ch, victim, (dam*2), sn );
			hp = ((hp - victim->hit)/2) + victim->hit;
		}
		else
		{
			if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_HEAT) )
				damage( ch, victim, dam, sn );
			damage( ch, victim, dam, sn );
		}
	}
	return;
}



void spell_frost_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA *obj_lose;
	OBJ_DATA *obj_next;
	int dam;
	int hpch;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_ICESHIELD)) return;
	
	if ( number_percent( ) < 2 * level && !saves_spell( level, victim ) )
	{
		for ( obj_lose = victim->carrying; obj_lose != NULL;
			obj_lose = obj_next )
		{
			char *msg;
			
			obj_next = obj_lose->next_content;
			if ( number_bits( 2 ) != 0 )
				continue;
			
			if (IS_SET(obj_lose->quest,QUEST_SPELLPROOF)) continue;
			switch ( obj_lose->item_type )
			{
				default:            continue;
				case ITEM_CONTAINER:
				case ITEM_DRINK_CON:
				case ITEM_POTION:   msg = "$p freezes and shatters!"; break;
			}
			
			act( msg, victim, obj_lose, NULL, TO_CHAR );
			extract_obj( obj_lose );
		}
	}
	
	hpch = UMAX( 10, ch->hit );
	dam  = number_range( hpch/16+1, hpch/8 );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	if (!IS_NPC(victim) && IS_CLASS(victim, CLASS_VAMPIRE) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_COLD) )
		return;
	else
	{
		if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_COLD) )
			damage( ch, victim, dam, sn );
		damage( ch, victim, dam, sn );
	}
	return;
}



void spell_gas_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *vch;
	CHAR_DATA *vch_next;
	int dam;
	int hpch;
	int chhp;
	
	for ( vch = ch->in_room->people; vch != NULL; vch = vch_next )
	{
		vch_next = vch->next_in_room;
		if ( IS_NPC(ch) ? !IS_NPC(vch) : IS_NPC(vch) )
		{
			hpch = UMAX( 10, ch->hit );
			dam  = number_range( hpch/16+1, hpch/8 );
			if ( saves_spell( level, vch ) )
				dam /= 2;
			chhp = vch->hit;
			damage( ch, vch, dam, sn );
			if (!IS_NPC(vch) && IS_CLASS(vch, CLASS_VAMPIRE) )
				vch->hit = chhp;
		}
	}
	return;
}



void spell_lightning_breath( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	int hpch;
	int hp;
	
	if (IS_ITEMAFF(victim, ITEMA_SHOCKSHIELD)) return;
	
	hpch = UMAX( 10, ch->hit );
	dam = number_range( hpch/16+1, hpch/8 );
	if ( saves_spell( level, victim ) )
		dam /= 2;
	hp = victim->hit;
	if (!IS_NPC(victim) && IS_IMMMERIT(victim, IMM_MERIT_LIGHTNING) )
		return;
	else
	{
		if (!IS_NPC(victim) && IS_IMMFLAW(victim, IMM_FLAW_LIGHTNING) )
			damage( ch, victim, dam, sn );
	}
	return;
}

/* Extra spells written by KaVir. */

void spell_guardian( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char buf [MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	AFFECT_DATA af;
	
	if ( IS_NPC(ch))
	{
		send_to_char("Mobiles can't cast this! Shoo.",ch);
		return;
	}
	
	if (ch->pcdata->followers > 4)
	{
		send_to_char("Nothing happens.\n\r",ch);
		return;
	}
	ch->pcdata->followers++;
	
	victim=create_mobile( get_mob_index( MOB_VNUM_GUARDIAN ) );
	victim->level = level;
	victim->hit = 100*level;
	victim->max_hit = 100*level;
	victim->hitroll = level;
	victim->damroll = level;
	victim->armor = 100 - (level*7);
	
	str_cpy(buf,"Come forth, creature of darkness, and do my bidding!");
	do_say( ch, buf );
	
	send_to_char( "A demon bursts from the ground and bows before you.\n\r",ch );
	act( "$N bursts from the ground and bows before $n.", ch, NULL, victim, TO_ROOM );
	
	char_to_room( victim, ch->in_room );
	
	add_follower( victim, ch );
	af.type      = sn;
	af.duration  = 666;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_CHARM;
	affect_to_char( victim, &af );
	return;
}

void spell_soulblade( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA    *obj = (OBJ_DATA *) vo;
	char buf     [MAX_STRING_LENGTH];
	char wpnname [MAX_INPUT_LENGTH];
	int weapontype = 3;
	
	obj = create_object( get_obj_index( OBJ_VNUM_SOULBLADE ), 0 );
	
	if (ch->wpn[1]  > ch->wpn[weapontype])
	{weapontype = 1;str_cpy(wpnname,"blade");}
	if (ch->wpn[2]  > ch->wpn[weapontype])
	{weapontype = 2;str_cpy(wpnname,"blade");}
	if (ch->wpn[4]  > ch->wpn[weapontype])
	{weapontype = 4;str_cpy(wpnname,"whip");}
	if (ch->wpn[5]  > ch->wpn[weapontype])
	{weapontype = 5;str_cpy(wpnname,"claw");}
	if (ch->wpn[6]  > ch->wpn[weapontype])
	{weapontype = 6;str_cpy(wpnname,"blaster");}
	if (ch->wpn[7]  > ch->wpn[weapontype])
	{weapontype = 7;str_cpy(wpnname,"mace");}
	if (ch->wpn[8]  > ch->wpn[weapontype])
	{weapontype = 8;str_cpy(wpnname,"mace");}
	if (ch->wpn[9]  > ch->wpn[weapontype])
	{weapontype = 9;str_cpy(wpnname,"grepper");}
	if (ch->wpn[10] > ch->wpn[weapontype])
	{weapontype = 10;str_cpy(wpnname,"biter");}
	if (ch->wpn[11] > ch->wpn[weapontype])
	{weapontype = 11;str_cpy(wpnname,"blade");}
	if (ch->wpn[12] > ch->wpn[weapontype])
	{weapontype = 12;str_cpy(wpnname,"sucker");}
	if (weapontype == 3) str_cpy(wpnname,"blade");
    /* First we name the weapon */
	sprintf(buf,"%s soul %s",ch->name->str,wpnname);
	obj->name = g_string_assign(obj->name,buf);
	if (IS_NPC(ch)) sprintf(buf,"%s's soul %s",ch->short_descr->str,wpnname);
	else sprintf(buf,"%s's soul %s",ch->name->str,wpnname);
	buf[0] = UPPER(buf[0]);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	if (IS_NPC(ch)) sprintf(buf,"%s's soul %s is lying here.",ch->short_descr->str,wpnname);
	else sprintf(buf,"%s's soul %s is lying here.",ch->name->str,wpnname);
	buf[0] = UPPER(buf[0]);
	obj->description = g_string_assign(obj->description,buf);
	
	if (IS_NPC(ch)) obj->level = ch->level;
	else if (ch->spl[2] > 4) obj->level = ch->spl[2]/4;
	else obj->level = 1;
	if (obj->level > 60) obj->level = 60;
	obj->value[0] = 13034;
	obj->value[1] = 10;
	obj->value[2] = 20;
	obj->value[3] = weapontype;
	obj->questmaker = g_string_assign(obj->questmaker,ch->name->str);
	if (!IS_NPC(ch))
	{
		obj->questowner = g_string_assign(obj->questowner,ch->name->str);
	}
	obj_to_char(obj,ch);
	act("$p fades into existance in your hand.", ch, obj, NULL, TO_CHAR);
	act("$p fades into existance in $n's hand.", ch, obj, NULL, TO_ROOM);
	return;
}

void spell_mana( int sn, int level, CHAR_DATA *ch, void *vo)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	if (!IS_NPC(ch) && !IS_CLASS(ch, CLASS_VAMPIRE) &&
		get_disc(ch, DISC_CELERITY) > 0 )
	{
		if ( ch->move < 25 )
		{
			send_to_char( "You are too exhausted to do that.\n\r", ch );
			return;
		}
		ch->move = ch->move - 25;
	}
	else
	{
		if ( ch->move < 50 )
		{
			send_to_char( "You are too exhausted to do that.\n\r", ch );
			return;
		}
		ch->move = ch->move - 50;
	}
	victim->mana = UMIN( victim->mana + level + 10, victim->max_mana);
	update_pos(ch);
	update_pos(victim);
	if (ch == victim)
	{
		send_to_char("You draw in energy from your surrounding area.\n\r",
			ch);
		act("$n draws in energy from $s surrounding area.", ch, NULL, NULL,
			TO_ROOM);
		return;
	}
	act("You draw in energy from around you and channel it into $N.",
		ch, NULL, victim, TO_CHAR);
	act("$n draws in energy and channels it into $N.",
		ch, NULL, victim, TO_NOTVICT);
	act("$n draws in energy and channels it into you.",
		ch, NULL, victim, TO_VICT);
	if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	return;
}

void spell_frenzy( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA  *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	
	if ( is_affected( victim, sn )) return;
	af.type      = sn;
	af.duration  = 1 + level / 10;
	af.location  = APPLY_HITROLL;
	af.modifier  = level / 5;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	
	af.location  = APPLY_DAMROLL;
	af.modifier  = level / 5;
	affect_to_char( victim, &af );
	
	af.location  = APPLY_AC;
	af.modifier  = level / 2;
	affect_to_char( victim, &af );
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	act( "$n is consumed with rage.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You are consumed with rage!\n\r", victim );
	if (!IS_NPC(victim)) do_beastlike(victim,"");
	return;
}

void spell_darkblessing( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA  *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( is_affected( victim, sn ) ) return;
	
	af.type      = sn;
	af.duration  = level / 2;
	af.location  = APPLY_HITROLL;
	af.modifier  = 10 + level / 14;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	af.location  = APPLY_DAMROLL;
	af.modifier  = 10 + level / 14;
	affect_to_char( victim, &af );
	
	if ( ch != victim )
		send_to_char( "Ok.\n\r", ch );
	act( "$n looks wicked.", victim, NULL, NULL, TO_ROOM );
	send_to_char( "You feel wicked.\n\r", victim );
	return;
}

void spell_portal( int sn, int level, CHAR_DATA *ch, void *vo)
{
	CHAR_DATA *victim;
	char buf[MAX_INPUT_LENGTH];
	OBJ_DATA  *obj;
	char       arg [MAX_INPUT_LENGTH];
	int        duration;
	
	one_argument( target_name, arg );
	
	if ( arg[0] == '\0')
	{
		send_to_char( "Who do you wish to create a portal to?\n\r", ch );
		return;
	}
	
	victim = get_char_world( ch, arg );
	
	if ( ( victim = get_char_world( ch, target_name ) ) == NULL
		||   victim == ch
		||   victim->in_room == NULL
		||   IS_NPC(ch)
		||   victim->level >= level + 6  //-dc  
		||   (!IS_NPC(victim) && !IS_IMMUNE(victim, IMM_SUMMON) )
		||   IS_SET(ch->in_room->room_flags, ROOM_PRIVATE)
		||   IS_SET(ch->in_room->room_flags, ROOM_SOLITARY)
		||   IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
		||   IS_SET(victim->in_room->room_flags, ROOM_PRIVATE)
		||   IS_SET(victim->in_room->room_flags, ROOM_SOLITARY)
		||   IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
		||   victim->in_room->vnum == 1
		||   victim->in_room->vnum == 2
		||   victim->in_room->vnum == 1200
		||   (ch->pk_timer > 0 && is_tempsafe(ch)) 
		||   ( strstr(victim->in_room->area->builders, "Unlinked" ) )
		||   victim->in_room->vnum == ch->in_room->vnum)
	{
		send_to_char( "You failed.\n\r", ch );
		return;
	}
	
	
	duration = number_range(2,3);
	
	obj = create_object( get_obj_index( OBJ_VNUM_PORTAL ), 0 );
	obj->value[0] = victim->in_room->vnum;
	obj->value[3] = ch->in_room->vnum;
	obj->timer = duration;
	obj_to_room( obj, ch->in_room );
	
	obj = create_object( get_obj_index( OBJ_VNUM_PORTAL ), 0 );
	obj->value[0] = ch->in_room->vnum;
	obj->value[3] = victim->in_room->vnum;
	obj->timer = duration;
	obj_to_room( obj, victim->in_room );
	
    /* Send MSP String if triggered */
	if ( IS_SET(ch->deaf, CHANNEL_MSP ))
	{
		sprintf(buf,"\n\r!!SOUND(%s T=sound L=1 V=100 U=http://%s%s )\n\r",msp_general_table[2].msp_string, msp_general_table[2].msp_server, msp_general_table[2].msp_dirinfo);
		send_to_char(buf,ch);
		if ( IS_SET(victim->deaf, CHANNEL_MSP ))
			send_to_char(buf,victim);
	}
	
	act( "$p appears in front of $n.", ch, obj, NULL, TO_ROOM );
	act( "$p appears in front of you.", ch, obj, NULL, TO_CHAR );
	act( "$p appears in front of $n.", victim, obj, NULL, TO_ROOM );
	act( "$p appears in front of you.", ch, obj, victim, TO_VICT );
	return;
}

/* This spell is designed for potions */
void spell_energyflux( int sn, int level, CHAR_DATA *ch, void *vo)
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	
	victim->mana = UMIN( victim->mana + 50, victim->max_mana);
	update_pos(victim);
	send_to_char("You feel mana channel into your body.\n\r",victim);
	return;
}

void spell_voodoo( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	OBJ_DATA  *obj;
	char       buf [MAX_INPUT_LENGTH];
	char       arg [MAX_INPUT_LENGTH];
	char     part1 [MAX_INPUT_LENGTH];
	char     part2 [MAX_INPUT_LENGTH];
	int       worn;
	
	one_argument( target_name, arg );
	
	victim = get_char_world( ch, arg );
	
	if (ch->practice < 5)
	{
		send_to_char( "It costs 5 points of primal energy to create a voodoo doll.\n\r", ch );
		return;
	}
	
	if ( ( victim = get_char_world( ch, target_name ) ) == NULL )
	{
		send_to_char( "Nobody by that name is playing.\n\r", ch );
		return;
	}
	
	if (!IS_AVATAR(victim))
	{
		send_to_char("Nope.\n\r",ch);
		return;
	}

	if ( ( obj = get_eq_char( ch, WEAR_WIELD ) ) == NULL )
	{
		if ( ( obj = get_eq_char( ch, WEAR_HOLD ) ) == NULL )
		{
			send_to_char( "You are not holding any body parts.\n\r", ch );
			return;
		}
		else worn = WEAR_HOLD;
	}
	else worn = WEAR_WIELD;
	
	if ( IS_NPC(victim) )
	{
		send_to_char( "Not on NPC's.\n\r", ch );
		return;
	}
	
	if      (obj->pIndexData->vnum == 12) sprintf(part1,"head %s",victim->name->str);
	else if (obj->pIndexData->vnum == 13) sprintf(part1,"heart %s",victim->name->str);
	else if (obj->pIndexData->vnum == 14) sprintf(part1,"arm %s",victim->name->str);
	else if (obj->pIndexData->vnum == 15) sprintf(part1,"leg %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30004) sprintf(part1,"entrails %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30005) sprintf(part1,"brain %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30006) sprintf(part1,"eye eyeball %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30012) sprintf(part1,"face %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30013) sprintf(part1,"windpipe %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30014) sprintf(part1,"cracked head %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30025) sprintf(part1,"ear %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30026) sprintf(part1,"nose %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30027) sprintf(part1,"tooth %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30028) sprintf(part1,"tongue %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30029) sprintf(part1,"hand %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30030) sprintf(part1,"foot %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30031) sprintf(part1,"thumb %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30032) sprintf(part1,"index finger %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30033) sprintf(part1,"middle finger %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30034) sprintf(part1,"ring finger %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30035) sprintf(part1,"little finger %s",victim->name->str);
	else if (obj->pIndexData->vnum == 30036) sprintf(part1,"toe %s",victim->name->str);
	else
	{
		sprintf(buf,"%s isn't a part of %s!\n\r",obj->name->str,victim->name->str);
		send_to_char( buf, ch );
		return;
	}
	
	sprintf(part2,obj->name->str);
	
	if ( str_infix(part1,part2) )
	{
		sprintf(buf,"But you are holding %s, not %s!\n\r",obj->short_descr->str,victim->name->str);
		send_to_char( buf, ch );
		return;
	}
	
	act("$p vanishes from your hand in a puff of smoke.", ch, obj, NULL, TO_CHAR);
	act("$p vanishes from $n's hand in a puff of smoke.", ch, obj, NULL, TO_ROOM);
	obj_from_char(obj);
	extract_obj(obj);
	
	obj = create_object( get_obj_index( OBJ_VNUM_VOODOO_DOLL ), 0 );
	
	sprintf(buf,"%s voodoo doll",victim->name->str);
	obj->name = g_string_assign(obj->name,buf);
	
	sprintf(buf,"a voodoo doll of %s",victim->name->str);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	
	sprintf(buf,"A voodoo doll of %s lies here.",victim->name->str);
	obj->description = g_string_assign(obj->description,buf);
	
	obj_to_char(obj,ch);
	equip_char(ch,obj,worn);
	
	act("$p appears in your hand.", ch, obj, NULL, TO_CHAR);
	act("$p appears in $n's hand.", ch, obj, NULL, TO_ROOM);
	
	ch->practice -= 5;
	
	return;
}

void spell_transport( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	OBJ_DATA *obj;
	CHAR_DATA *victim;
	
	/*
	 * Check this ... I think it's fishy...
	 */

	target_name = one_argument( target_name, arg1 );
	target_name = one_argument( target_name, arg2 );
	
	if ( arg1[0] == '\0' )
	{
		send_to_char( "Transport which object?\n\r", ch );
		return;
	}
	
	if ( arg2[0] == '\0' )
	{
		send_to_char( "Transport who whom?\n\r", ch );
		return;
	}
	if ( ch->pk_timer != 0 )
	{
		send_to_char("You can't transfer now! Settle down!\n\r",ch);
		return;
	}
	if ( ( victim = get_char_world( ch, arg2 ) ) == NULL )
	{
		send_to_char( "They aren't here.\n\r", ch );
		return;
	}
	
	if ( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
	{
		send_to_char( "You are not carrying that item.\n\r", ch );
		return;
	}
	
	if (!IS_NPC(victim) && !IS_IMMUNE(victim, IMM_TRANSPORT))
	{
		send_to_char( "You are unable to transport anything to them.\n\r", ch );
		return;
	}
	
	if (!is_same_plane(ch,victim))
	{
		send_to_char("There in myst form.. they can't hold it!\n\r",ch);
		return;
	}
	
	act("$p vanishes from your hands in a swirl of smoke.",ch,obj,NULL,TO_CHAR);
	act("$p vanishes from $n's hands in a swirl of smoke.",ch,obj,NULL,TO_ROOM);
	obj_from_char(obj);
	obj_to_char(obj,victim);
	act("$p appears in your hands in a swirl of smoke.",victim,obj,NULL,TO_CHAR);
	act("$p appears in $n's hands in a swirl of smoke.",victim,obj,NULL,TO_ROOM);
	do_autosave(ch,"");
	do_autosave(victim,"");
	return;
}

void spell_regenerate( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	OBJ_DATA *obj;
	CHAR_DATA *victim;
	int teeth = 0;
	
	target_name = one_argument( target_name, arg1 );
	target_name = one_argument( target_name, arg2 );
	
	if ( arg1[0] == '\0' )
	{
		send_to_char( "Which body part?\n\r", ch );
		return;
	}
	
	if ( arg2[0] == '\0' )
	{
		send_to_char( "Regenerate which person?\n\r", ch );
		return;
	}
	if ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
	{
		send_to_char( "They aren't here.\n\r", ch );
		return;
	}
	
	if (victim->loc_hp[6] > 0)
	{
		send_to_char( "You cannot regenerate someone who is still bleeding.\n\r", ch );
		return;
	}
	
	if ( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
	{
		send_to_char( "You are not carrying that item.\n\r", ch );
		return;
	}
	
	if (IS_HEAD(victim,LOST_TOOTH_1  )) teeth += 1;
	if (IS_HEAD(victim,LOST_TOOTH_2  )) teeth += 2;
	if (IS_HEAD(victim,LOST_TOOTH_4  )) teeth += 4;
	if (IS_HEAD(victim,LOST_TOOTH_8  )) teeth += 8;
	if (IS_HEAD(victim,LOST_TOOTH_16 )) teeth += 16;
	
	if (obj->pIndexData->vnum == OBJ_VNUM_SLICED_ARM)
	{
		if (!IS_ARM_L(victim,LOST_ARM) && !IS_ARM_R(victim,LOST_ARM))
		{send_to_char("They don't need an arm.\n\r",ch); return;}
		if (IS_ARM_L(victim,LOST_ARM))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_L],LOST_ARM);
		else if (IS_ARM_R(victim,LOST_ARM))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_R],LOST_ARM);
		act("You press $p onto the stump of $N's shoulder.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto the stump of $N's shoulder.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto the stump of your shoulder.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SLICED_LEG)
	{
		if (!IS_LEG_L(victim,LOST_LEG) && !IS_LEG_R(victim,LOST_LEG))
		{send_to_char("They don't need a leg.\n\r",ch); return;}
		if (IS_LEG_L(victim,LOST_LEG))
			REMOVE_BIT(victim->loc_hp[LOC_LEG_L],LOST_LEG);
		else if (IS_LEG_R(victim,LOST_LEG))
			REMOVE_BIT(victim->loc_hp[LOC_LEG_R],LOST_LEG);
		act("You press $p onto the stump of $N's hip.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto the stump of $N's hip.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto the stump of your hip.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SQUIDGY_EYEBALL)
	{
		if (!IS_HEAD(victim,LOST_EYE_L) && !IS_HEAD(victim,LOST_EYE_R))
		{send_to_char("They don't need an eye.\n\r",ch); return;}
		if (IS_HEAD(victim,LOST_EYE_L))
			REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_EYE_L);
		else if (IS_HEAD(victim,LOST_EYE_R))
			REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_EYE_R);
		act("You press $p into $N's empty eye socket.",ch,obj,victim,TO_CHAR);
		act("$n presses $p into $N's empty eye socket.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p into your empty eye socket.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SLICED_EAR)
	{
		if (!IS_HEAD(victim,LOST_EAR_L) && !IS_HEAD(victim,LOST_EAR_R))
		{send_to_char("They don't need an ear.\n\r",ch); return;}
		if (IS_HEAD(victim,LOST_EAR_L))
			REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_EAR_L);
		else if (IS_HEAD(victim,LOST_EAR_R))
			REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_EAR_R);
		act("You press $p onto the side of $N's head.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto the side of $N's head.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto the side of your head.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SLICED_NOSE)
	{
		if (!IS_HEAD(victim,LOST_NOSE))
		{send_to_char("They don't need a nose.\n\r",ch); return;}
		REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_NOSE);
		act("You press $p onto the front of $N's face.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto the front of $N's face.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto the front of your face.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SEVERED_HAND)
	{
		if (!IS_ARM_L(victim,LOST_ARM) && IS_ARM_L(victim,LOST_HAND))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_L],LOST_HAND);
		else if (!IS_ARM_R(victim,LOST_ARM) && IS_ARM_R(victim,LOST_HAND))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_R],LOST_HAND);
		else
		{
			send_to_char("They don't need a hand.\n\r",ch);
			return;
		}
		act("You press $p onto the stump of $N's wrist.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto the stump of $N's wrist.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto the stump of your wrist.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SEVERED_FOOT)
	{
		if (!IS_LEG_L(victim,LOST_LEG) && IS_LEG_L(victim,LOST_FOOT))
			REMOVE_BIT(victim->loc_hp[LOC_LEG_L],LOST_FOOT);
		else if (!IS_LEG_R(victim,LOST_LEG) && IS_LEG_R(victim,LOST_FOOT))
			REMOVE_BIT(victim->loc_hp[LOC_LEG_R],LOST_FOOT);
		else
		{
			send_to_char("They don't need a foot.\n\r",ch);
			return;
		}
		act("You press $p onto the stump of $N's ankle.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto the stump of $N's ankle.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto the stump of your ankle.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SEVERED_THUMB)
	{
		if (!IS_ARM_L(victim,LOST_ARM) && !IS_ARM_L(victim,LOST_HAND)
			&& IS_ARM_L(victim,LOST_THUMB))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_L],LOST_THUMB);
		else if (!IS_ARM_R(victim,LOST_ARM) && !IS_ARM_R(victim,LOST_HAND)
			&& IS_ARM_R(victim,LOST_THUMB))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_R],LOST_THUMB);
		else
		{
			send_to_char("They don't need a thumb.\n\r",ch);
			return;
		}
		act("You press $p onto $N's hand.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto $N's hand.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto your hand.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SEVERED_INDEX)
	{
		if (!IS_ARM_L(victim,LOST_ARM) && !IS_ARM_L(victim,LOST_HAND)
			&& IS_ARM_L(victim,LOST_FINGER_I))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_L],LOST_FINGER_I);
		else if (!IS_ARM_R(victim,LOST_ARM) && !IS_ARM_R(victim,LOST_HAND)
			&& IS_ARM_R(victim,LOST_FINGER_I))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_R],LOST_FINGER_I);
		else
		{
			send_to_char("They don't need an index finger.\n\r",ch);
			return;
		}
		act("You press $p onto $N's hand.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto $N's hand.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto your hand.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SEVERED_MIDDLE)
	{
		if (!IS_ARM_L(victim,LOST_ARM) && !IS_ARM_L(victim,LOST_HAND)
			&& IS_ARM_L(victim,LOST_FINGER_M))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_L],LOST_FINGER_M);
		else if (!IS_ARM_R(victim,LOST_ARM) && !IS_ARM_R(victim,LOST_HAND)
			&& IS_ARM_R(victim,LOST_FINGER_M))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_R],LOST_FINGER_M);
		else
		{
			send_to_char("They don't need a middle finger.\n\r",ch);
			return;
		}
		act("You press $p onto $N's hand.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto $N's hand.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto your hand.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SEVERED_RING)
	{
		if (!IS_ARM_L(victim,LOST_ARM) && !IS_ARM_L(victim,LOST_HAND)
			&& IS_ARM_L(victim,LOST_FINGER_R))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_L],LOST_FINGER_R);
		else if (!IS_ARM_R(victim,LOST_ARM) && !IS_ARM_R(victim,LOST_HAND)
			&& IS_ARM_R(victim,LOST_FINGER_R))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_R],LOST_FINGER_R);
		else
		{
			send_to_char("They don't need a ring finger.\n\r",ch);
			return;
		}
		act("You press $p onto $N's hand.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto $N's hand.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto your hand.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (obj->pIndexData->vnum == OBJ_VNUM_SEVERED_LITTLE)
	{
		if (!IS_ARM_L(victim,LOST_ARM) && !IS_ARM_L(victim,LOST_HAND)
			&& IS_ARM_L(victim,LOST_FINGER_L))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_L],LOST_FINGER_L);
		else if (!IS_ARM_R(victim,LOST_ARM) && !IS_ARM_R(victim,LOST_HAND)
			&& IS_ARM_R(victim,LOST_FINGER_L))
			REMOVE_BIT(victim->loc_hp[LOC_ARM_R],LOST_FINGER_L);
		else
		{
			send_to_char("They don't need a little finger.\n\r",ch);
			return;
		}
		act("You press $p onto $N's hand.",ch,obj,victim,TO_CHAR);
		act("$n presses $p onto $N's hand.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p onto your hand.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
		return;
	}
	else if (teeth > 0)
	{
		if (IS_HEAD(victim,LOST_TOOTH_1 ))
			REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_1);
		if (IS_HEAD(victim,LOST_TOOTH_2 ))
			REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_2);
		if (IS_HEAD(victim,LOST_TOOTH_4 ))
			REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_4);
		if (IS_HEAD(victim,LOST_TOOTH_8 ))
			REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_8);
		if (IS_HEAD(victim,LOST_TOOTH_16))
			REMOVE_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_16);
		teeth -= 1;
		if (teeth >= 16) {teeth -= 16;
		SET_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_16);}
		if (teeth >= 8 ) {teeth -= 8;
		SET_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_8);}
		if (teeth >= 4 ) {teeth -= 4;
		SET_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_4);}
		if (teeth >= 2 ) {teeth -= 2;
		SET_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_2);}
		if (teeth >= 1 ) {teeth -= 1;
		SET_BIT(victim->loc_hp[LOC_HEAD],LOST_TOOTH_1);}
		act("You press $p into $N's mouth.",ch,obj,victim,TO_CHAR);
		act("$n presses $p into $N's mouth.",ch,obj,victim,TO_NOTVICT);
		act("$n presses $p into your mouth.",ch,obj,victim,TO_VICT);
		extract_obj(obj);
	}
	else
	{
		act("There is nowhere to stick $p on $N.",ch,obj,victim,TO_CHAR);
		return;
	}
	return;
}

void spell_clot( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	if (IS_BLEEDING(victim,BLEEDING_HEAD))
	{
		act("$n's head stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("Your head stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_HEAD);
	}
	else if (IS_BLEEDING(victim,BLEEDING_THROAT))
	{
		act("$n's throat stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("Your throat stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_THROAT);
	}
	else if (IS_BLEEDING(victim,BLEEDING_ARM_L))
	{
		act("The stump of $n's left arm stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("The stump of your left arm stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_ARM_L);
	}
	else if (IS_BLEEDING(victim,BLEEDING_ARM_R))
	{
		act("The stump of $n's right arm stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("The stump of your right arm stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_ARM_R);
	}
	else if (IS_BLEEDING(victim,BLEEDING_LEG_L))
	{
		act("The stump of $n's left leg stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("The stump of your left leg stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_LEG_L);
	}
	else if (IS_BLEEDING(victim,BLEEDING_LEG_R))
	{
		act("The stump of $n's right leg stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("The stump of your right leg stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_LEG_R);
	}
	else if (IS_BLEEDING(victim,BLEEDING_HAND_L))
	{
		act("The stump of $n's left wrist stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("The stump of your left wrist stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_HAND_L);
	}
	else if (IS_BLEEDING(victim,BLEEDING_HAND_R))
	{
		act("The stump of $n's right wrist stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("The stump of your right wrist stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_HAND_R);
	}
	else if (IS_BLEEDING(victim,BLEEDING_FOOT_L))
	{
		act("The stump of $n's left ankle stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("The stump of your left ankle stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_FOOT_L);
	}
	else if (IS_BLEEDING(victim,BLEEDING_FOOT_R))
	{
		act("The stump of $n's right ankle stops bleeding.",victim,NULL,NULL,TO_ROOM);
		act("The stump of your right ankle stops bleeding.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[6],BLEEDING_FOOT_R);
	}
	else if (level != AUTO_REGEN)
                 send_to_char("They have no wounds to clot.\n\r",ch);
	if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	return;
}

void spell_mend( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int ribs = 0;
	
	if (IS_BODY(victim,BROKEN_RIBS_1 )) ribs += 1;
	if (IS_BODY(victim,BROKEN_RIBS_2 )) ribs += 2;
	if (IS_BODY(victim,BROKEN_RIBS_4 )) ribs += 4;
	if (IS_BODY(victim,BROKEN_RIBS_8 )) ribs += 8;
	if (IS_BODY(victim,BROKEN_RIBS_16)) ribs += 16;
	
	if (ribs > 0)
	{
		if (IS_BODY(victim,BROKEN_RIBS_1 ))
			REMOVE_BIT(victim->loc_hp[1],BROKEN_RIBS_1);
		if (IS_BODY(victim,BROKEN_RIBS_2 ))
			REMOVE_BIT(victim->loc_hp[1],BROKEN_RIBS_2);
		if (IS_BODY(victim,BROKEN_RIBS_4 ))
			REMOVE_BIT(victim->loc_hp[1],BROKEN_RIBS_4);
		if (IS_BODY(victim,BROKEN_RIBS_8 ))
			REMOVE_BIT(victim->loc_hp[1],BROKEN_RIBS_8);
		if (IS_BODY(victim,BROKEN_RIBS_16))
			REMOVE_BIT(victim->loc_hp[1],BROKEN_RIBS_16);
		ribs -= 1;
		if (ribs >= 16) {ribs -= 16;
		SET_BIT(victim->loc_hp[1],BROKEN_RIBS_16);}
		if (ribs >= 8 ) {ribs -= 8;
		SET_BIT(victim->loc_hp[1],BROKEN_RIBS_8);}
		if (ribs >= 4 ) {ribs -= 4;
		SET_BIT(victim->loc_hp[1],BROKEN_RIBS_4);}
		if (ribs >= 2 ) {ribs -= 2;
		SET_BIT(victim->loc_hp[1],BROKEN_RIBS_2);}
		if (ribs >= 1 ) {ribs -= 1;
		SET_BIT(victim->loc_hp[1],BROKEN_RIBS_1);}
		act("One of $n's ribs snap back into place.",victim,NULL,NULL,TO_ROOM);
		act("One of your ribs snap back into place.",victim,NULL,NULL,TO_CHAR);
	}
	else if (IS_HEAD(victim,BROKEN_NOSE) && !IS_HEAD(victim,LOST_NOSE))
	{
		act("$n's nose snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your nose snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_HEAD],BROKEN_NOSE);
	}
	else if (IS_HEAD(victim,BROKEN_JAW))
	{
		act("$n's jaw snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your jaw snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_HEAD],BROKEN_JAW);
	}
	else if (IS_HEAD(victim,BROKEN_SKULL))
	{
		act("$n's skull knits itself back together.",victim,NULL,NULL,TO_ROOM);
		act("Your skull knits itself back together.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_HEAD],BROKEN_SKULL);
	}
	else if (IS_BODY(victim,BROKEN_SPINE))
	{
		act("$n's spine knits itself back together.",victim,NULL,NULL,TO_ROOM);
		act("Your spine knits itself back together.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_BODY],BROKEN_SPINE);
	}
	else if (IS_BODY(victim,BROKEN_NECK))
	{
		act("$n's neck snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your neck snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_BODY],BROKEN_NECK);
	}
	else if (IS_ARM_L(victim,BROKEN_ARM) && !IS_ARM_L(victim,LOST_ARM))
	{
		act("$n's left arm snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your left arm snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_L],BROKEN_ARM);
	}
	else if (IS_ARM_R(victim,BROKEN_ARM) && !IS_ARM_R(victim,LOST_ARM))
	{
		act("$n's right arm snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your right arm snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_R],BROKEN_ARM);
	}
	else if (IS_LEG_L(victim,BROKEN_LEG) && !IS_LEG_L(victim,LOST_LEG))
	{
		act("$n's left leg snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your left leg snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_LEG_L],BROKEN_LEG);
	}
	else if (IS_LEG_R(victim,BROKEN_LEG) && !IS_LEG_R(victim,LOST_LEG))
	{
		act("$n's right leg snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your right leg snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_LEG_R],BROKEN_LEG);
	}
	else if (IS_ARM_L(victim,BROKEN_THUMB) && !IS_ARM_L(victim,LOST_ARM)
		&& !IS_ARM_L(victim,LOST_HAND) && !IS_ARM_L(victim,LOST_THUMB))
	{
		act("$n's left thumb snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your left thumb snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_L],BROKEN_THUMB);
	}
	else if (IS_ARM_L(victim,BROKEN_FINGER_I) && !IS_ARM_L(victim,LOST_ARM)
		&& !IS_ARM_L(victim,LOST_HAND) && !IS_ARM_L(victim,LOST_FINGER_I))
	{
		act("$n's left index finger snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your left index finger snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_L],BROKEN_FINGER_I);
	}
	else if (IS_ARM_L(victim,BROKEN_FINGER_M) && !IS_ARM_L(victim,LOST_ARM)
		&& !IS_ARM_L(victim,LOST_HAND) && !IS_ARM_L(victim,LOST_FINGER_M))
	{
		act("$n's left middle finger snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your left middle finger snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_L],BROKEN_FINGER_M);
	}
	else if (IS_ARM_L(victim,BROKEN_FINGER_R) && !IS_ARM_L(victim,LOST_ARM)
		&& !IS_ARM_L(victim,LOST_HAND) && !IS_ARM_L(victim,LOST_FINGER_R))
	{
		act("$n's left ring finger snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your left ring finger snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_L],BROKEN_FINGER_R);
	}
	else if (IS_ARM_L(victim,BROKEN_FINGER_L) && !IS_ARM_L(victim,LOST_ARM)
		&& !IS_ARM_L(victim,LOST_HAND) && !IS_ARM_L(victim,LOST_FINGER_L))
	{
		act("$n's left little finger snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your left little finger snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_L],BROKEN_FINGER_L);
	}
	else if (IS_ARM_R(victim,BROKEN_THUMB) && !IS_ARM_R(victim,LOST_ARM)
		&& !IS_ARM_R(victim,LOST_HAND) && !IS_ARM_R(victim,LOST_THUMB))
	{
		act("$n's right thumb snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your right thumb snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_R],BROKEN_THUMB);
	}
	else if (IS_ARM_R(victim,BROKEN_FINGER_I) && !IS_ARM_R(victim,LOST_ARM)
		&& !IS_ARM_R(victim,LOST_HAND) && !IS_ARM_R(victim,LOST_FINGER_I))
	{
		act("$n's right index finger snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your right index finger snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_R],BROKEN_FINGER_I);
	}
	else if (IS_ARM_R(victim,BROKEN_FINGER_M) && !IS_ARM_R(victim,LOST_ARM)
		&& !IS_ARM_R(victim,LOST_HAND) && !IS_ARM_R(victim,LOST_FINGER_M))
	{
		act("$n's right middle finger snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your right middle finger snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_R],BROKEN_FINGER_M);
	}
	else if (IS_ARM_R(victim,BROKEN_FINGER_R) && !IS_ARM_R(victim,LOST_ARM)
		&& !IS_ARM_R(victim,LOST_HAND) && !IS_ARM_R(victim,LOST_FINGER_R))
	{
		act("$n's right ring finger snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your right ring finger snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_R],BROKEN_FINGER_R);
	}
	else if (IS_ARM_R(victim,BROKEN_FINGER_L) && !IS_ARM_R(victim,LOST_ARM)
		&& !IS_ARM_R(victim,LOST_HAND) && !IS_ARM_R(victim,LOST_FINGER_L))
	{
		act("$n's right little finger snaps back into place.",victim,NULL,NULL,TO_ROOM);
		act("Your right little finger snaps back into place.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_ARM_R],BROKEN_FINGER_L);
	}
	else if (IS_BODY(victim,CUT_THROAT))
	{
		if (IS_SET(victim->loc_hp[6], BLEEDING_THROAT))
		{
			if (level == AUTO_REGEN)
                        {
		            act("$n's throat stops bleeding.",victim,NULL,NULL,TO_ROOM);
		            act("Your throat stops bleeding.",victim,NULL,NULL,TO_CHAR);
		            REMOVE_BIT(victim->loc_hp[6],BLEEDING_THROAT);
                        }
                        else
                        {
                            send_to_char( "But their throat is still bleeding!\n\r", ch );
			    return;
                        }
		}
		act("The wound in $n's throat closes up.",victim,NULL,NULL,TO_ROOM);
		act("The wound in your throat closes up.",victim,NULL,NULL,TO_CHAR);
		REMOVE_BIT(victim->loc_hp[LOC_BODY],CUT_THROAT);
	}
	else if (level != AUTO_REGEN)
                 send_to_char("They have no bones to mend.\n\r",ch);
	if (!IS_NPC(ch) && ch != victim) do_humanity(ch,"");
	return;
}

void spell_quest( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_INDEX_DATA *pObjIndex;
	OBJ_DATA *obj;
	
	if (ch->practice < 1)
	{
		send_to_char( "It costs at least 1 point of primal energy to create a quest card.\n\r", ch );
		return;
	}
	
	if ( (pObjIndex = get_obj_index( OBJ_VNUM_QUESTCARD )) == NULL)
	{
		send_to_char("Missing object, please inform Spiral\n\r",ch);
		return;
	}
	if (ch->in_room == NULL) return;
	obj = create_object(pObjIndex, 0);
	obj_to_char(obj, ch);
	quest_object(ch,obj);
	if (ch->practice >= 100) 
	{
		ch->practice -= 100; 
		ch->pcdata->spent[SPENT_P] += 100;
		obj->level = 100;
	}
	else 
	{
		obj->level = ch->practice; 
		ch->pcdata->spent[SPENT_P] += ch->practice;
		ch->practice = 0;
	}
	act("$p fades into existance in your hands.",ch,obj,NULL,TO_CHAR);
	act("$p fades into existance in $n's hands.",ch,obj,NULL,TO_ROOM);
	obj->questmaker = g_string_assign(obj->questmaker,ch->name->str);
	obj->questowner = g_string_assign(obj->questowner,ch->name->str);
	return;
}

void spell_minor_creation( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj;
	char arg[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	char itemkind[10];
	int itemtype;
	
	target_name = one_argument( target_name, arg );
	
	if      (!str_cmp(arg,"potion")) {itemtype = ITEM_POTION;sprintf(itemkind,"potion");}
	else if (!str_cmp(arg,"scroll")) {itemtype = ITEM_SCROLL;sprintf(itemkind,"scroll");}
	else if (!str_cmp(arg,"wand"  )) {itemtype = ITEM_WAND;sprintf(itemkind,"wand");}
	else if (!str_cmp(arg,"staff" )) {itemtype = ITEM_STAFF;sprintf(itemkind,"staff");}
	else if (!str_cmp(arg,"pill"  )) {itemtype = ITEM_PILL;sprintf(itemkind,"pill");}
	else
	{
		send_to_char( "Item can be one of: Potion, Scroll, Wand, Staff or Pill.\n\r", ch );
		return;
	}
	obj = create_object( get_obj_index( OBJ_VNUM_PROTOPLASM ), 0 );
	obj->item_type = itemtype;
	
	sprintf(buf,"%s %s",ch->name->str,itemkind);
	obj->name = g_string_assign(obj->name,buf);
	sprintf(buf,"%s's %s",ch->name->str, itemkind);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	sprintf(buf,"%s's %s lies here.",ch->name->str,itemkind);
	obj->description = g_string_assign(obj->description,buf);
	
	obj->weight = 10;
	
	obj->questmaker = g_string_assign(obj->questmaker,ch->name->str);
	
	obj_to_char( obj, ch );
	act( "$p suddenly appears in your hands.", ch, obj, NULL, TO_CHAR );
	act( "$p suddenly appears in $n's hands.", ch, obj, NULL, TO_ROOM );
	return;
}

void spell_brew( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	char col[10];
	int perf_sn;
	OBJ_DATA *obj;
	
	target_name = one_argument( target_name, arg1 );
	target_name = one_argument( target_name, arg2 );
	
	if (IS_NPC(ch)) return;
	if ( arg1[0] == '\0' || arg2[0] == '\0' )
	{
		send_to_char( "What spell do you wish to brew, and on what?\n\r", ch );
		return;
	}
	
	
	if ( ( sn = skill_lookup( arg2 ) ) < 0
		|| ( !IS_NPC(ch) && ch->level < skill_table[sn].skill_level) )
	{
		send_to_char( "You can't do that.\n\r", ch );
		return;
	}
	
	perf_sn = skill_lookup( "perfection" );
	if ( sn == perf_sn )
	{ 
		send_to_char("You can't brew a spell of perfection!\n\r",ch);
		return;
	}
	
	if ( ch->pcdata->learned[sn] < 100 )
	{
		send_to_char( "You are not adept at that spell.\n\r", ch );
		return;
	}
	
	if ( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
	{
		send_to_char( "You are not carrying that.\n\r", ch );
		return;
	}
	
	if ( obj->item_type != ITEM_POTION )
	{
		send_to_char( "That is not a potion.\n\r", ch );
		return;
	}
	
	if ( obj->value[0] != 0 || obj->value[1] != 0 ||
		obj->value[2] != 0 || obj->value[3] != 0 )
	{
		send_to_char( "You need an empty potion bottle.\n\r", ch );
		return;
	}
	if      ( skill_table[sn].target == 0 )
	{obj->value[0] = ch->spl[0]/4;sprintf(col,"purple");}
	else if ( skill_table[sn].target == 1 )
	{obj->value[0] = ch->spl[1]/4;sprintf(col,"red");}
	else if ( skill_table[sn].target == 2 )
	{obj->value[0] = ch->spl[2]/4;sprintf(col,"blue");}
	else if ( skill_table[sn].target == 3 )
	{obj->value[0] = ch->spl[3]/4;sprintf(col,"green");}
	else if ( skill_table[sn].target == 4 )
	{obj->value[0] = ch->spl[4]/4;sprintf(col,"yellow");}
	else
	{
		send_to_char( "Oh dear...big bug...please inform Spiral\n\r", ch );
		return;
	}
	obj->value[1] = sn;
	if (obj->value[0] >= 25) obj->value[2] = sn; else obj->value[2] = -1;
	if (obj->value[0] >= 50) obj->value[3] = sn; else obj->value[3] = -1;
	sprintf(buf,"%s potion %s %s",ch->name->str,col,skill_table[sn].name);
	obj->name = g_string_assign(obj->name,buf);
	sprintf(buf,"%s's %s potion of %s",ch->name->str,col,skill_table[sn].name);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	sprintf(buf,"A %s potion is lying here.",col);
	obj->description = g_string_assign(obj->description,buf);
	act("You brew $p.",ch,obj,NULL,TO_CHAR);
	act("$n brews $p.",ch,obj,NULL,TO_ROOM);
	return;
}

void spell_scribe( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	char col[10];
	int perf_sn;
	OBJ_DATA *obj;
	
	target_name = one_argument( target_name, arg1 );
	target_name = one_argument( target_name, arg2 );
	
	if (IS_NPC(ch)) return;
	if ( arg1[0] == '\0' || arg2[0] == '\0' )
	{
		send_to_char( "What spell do you wish to scribe, and on what?\n\r", ch );
		return;
	}
	
	if ( ( sn = skill_lookup( arg2 ) ) < 0
		|| ( !IS_NPC(ch) && ch->level < skill_table[sn].skill_level) )
	{
		send_to_char( "You can't do that.\n\r", ch );
		return;
	}
	
	perf_sn = skill_lookup( "perfection" );
	if ( sn == perf_sn )
	{ 
		send_to_char("You can't scribe a spell of perfection!\n\r",ch);
		return;
	}
	
	if ( ch->pcdata->learned[sn] < 100 )
	{
		send_to_char( "You are not adept at that spell.\n\r", ch );
		return;
	}
	
	if ( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
	{
		send_to_char( "You are not carrying that.\n\r", ch );
		return;
	}
	
	if ( obj->item_type != ITEM_SCROLL )
	{
		send_to_char( "That is not a scroll.\n\r", ch );
		return;
	}
	
	if ( obj->value[0] != 0 || obj->value[1] != 0 ||
		obj->value[2] != 0 || obj->value[3] != 0 )
	{
		send_to_char( "You need an empty scroll parchment.\n\r", ch );
		return;
	}
	if      ( skill_table[sn].target == 0 )
	{obj->value[0] = ch->spl[0]/4;sprintf(col,"purple");}
	else if ( skill_table[sn].target == 1 )
	{obj->value[0] = ch->spl[1]/4;sprintf(col,"red");}
	else if ( skill_table[sn].target == 2 )
	{obj->value[0] = ch->spl[2]/4;sprintf(col,"blue");}
	else if ( skill_table[sn].target == 3 )
	{obj->value[0] = ch->spl[3]/4;sprintf(col,"green");}
	else if ( skill_table[sn].target == 4 )
	{obj->value[0] = ch->spl[4]/4;sprintf(col,"yellow");}
	else
	{
		send_to_char( "Oh dear...big bug...please inform Spiral\n\r", ch );
		return;
	}
	obj->value[1] = sn;
	if (obj->value[0] >= 25) obj->value[2] = sn; else obj->value[2] = -1;
	if (obj->value[0] >= 50) obj->value[3] = sn; else obj->value[3] = -1;
	sprintf(buf,"%s scroll %s %s",ch->name->str,col,skill_table[sn].name);
	obj->name = g_string_assign(obj->name,buf);
	sprintf(buf,"%s's %s scroll of %s",ch->name->str,col,skill_table[sn].name);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	sprintf(buf,"A %s scroll is lying here.",col);
	obj->description = g_string_assign(obj->description,buf);
	act("You scribe $p.",ch,obj,NULL,TO_CHAR);
	act("$n scribes $p.",ch,obj,NULL,TO_ROOM);
	return;
}

void spell_carve( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	char col[10];
	int perf_sn;
	OBJ_DATA *obj;
	
	target_name = one_argument( target_name, arg1 );
	target_name = one_argument( target_name, arg2 );
	
	if (IS_NPC(ch)) return;
	if ( arg1[0] == '\0' || arg2[0] == '\0' )
	{
		send_to_char( "What spell do you wish to carve, and on what?\n\r", ch );
		return;
	}
	
	
	if ( ( sn = skill_lookup( arg2 ) ) < 0
		|| ( !IS_NPC(ch) && ch->level < skill_table[sn].skill_level) )
	{
		send_to_char( "You can't do that.\n\r", ch );
		return;
	}
	
	perf_sn = skill_lookup( "perfection" );
	if ( sn == perf_sn )
	{ 
		send_to_char("You can't carve a spell of perfection!\n\r",ch);
		return;
	}
	
	if ( ch->pcdata->learned[sn] < 100 )
	{
		send_to_char( "You are not adept at that spell.\n\r", ch );
		return;
	}
	
	if ( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
	{
		send_to_char( "You are not carrying that.\n\r", ch );
		return;
	}
	
	if ( obj->item_type != ITEM_WAND )
	{
		send_to_char( "That is not a wand.\n\r", ch );
		return;
	}
	
	if ( obj->value[0] != 0 || obj->value[1] != 0 ||
		obj->value[2] != 0 || obj->value[3] != 0 )
	{
		send_to_char( "You need an unenchanted wand.\n\r", ch );
		return;
	}
	if      ( skill_table[sn].target == 0 )
	{obj->value[0] = ch->spl[0]/4;sprintf(col,"purple");}
	else if ( skill_table[sn].target == 1 )
	{obj->value[0] = ch->spl[1]/4;sprintf(col,"red");}
	else if ( skill_table[sn].target == 2 )
	{obj->value[0] = ch->spl[2]/4;sprintf(col,"blue");}
	else if ( skill_table[sn].target == 3 )
	{obj->value[0] = ch->spl[3]/4;sprintf(col,"green");}
	else if ( skill_table[sn].target == 4 )
	{obj->value[0] = ch->spl[4]/4;sprintf(col,"yellow");}
	else
	{
		send_to_char( "Oh dear...big bug...please inform Spiral\n\r", ch );
		return;
	}
	obj->value[1] = (obj->value[0] / 5) + 1;
	obj->value[2] = (obj->value[0] / 5) + 1;
	obj->value[3] = sn;
	sprintf(buf,"%s wand %s %s",ch->name->str,col,skill_table[sn].name);
	obj->name = g_string_assign(obj->name,buf);
	sprintf(buf,"%s's %s wand of %s",ch->name->str,col,skill_table[sn].name);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	sprintf(buf,"A %s wand is lying here.",col);
	obj->description = g_string_assign(obj->description,buf);
	obj->wear_flags = ITEM_TAKE + ITEM_HOLD;
	act("You carve $p.",ch,obj,NULL,TO_CHAR);
	act("$n carves $p.",ch,obj,NULL,TO_ROOM);
	return;
}

void spell_engrave( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	char col[10];
	int perf_sn;
	OBJ_DATA *obj;
	
	target_name = one_argument( target_name, arg1 );
	target_name = one_argument( target_name, arg2 );
	
	if (IS_NPC(ch)) return;
	if ( arg1[0] == '\0' || arg2[0] == '\0' )
	{
		send_to_char( "What spell do you wish to engrave, and on what?\n\r", ch );
		return;
	}
	
	if ( ( sn = skill_lookup( arg2 ) ) < 0
		|| ( !IS_NPC(ch) && ch->level < skill_table[sn].skill_level ) )
	{
		send_to_char( "You can't do that.\n\r", ch );
		return;
	}
	
	perf_sn = skill_lookup( "perfection" );
	if ( sn == perf_sn )
	{ 
		send_to_char("You can't engrave a spell of perfection!\n\r",ch);
		return;
	}
	
	if ( ch->pcdata->learned[sn] < 100 )
	{
		send_to_char( "You are not adept at that spell.\n\r", ch );
		return;
	}
	
	if ( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
	{
		send_to_char( "You are not carrying that.\n\r", ch );
		return;
	}
	
	if ( obj->item_type != ITEM_STAFF )
	{
		send_to_char( "That is not a staff.\n\r", ch );
		return;
	}
	
	if ( obj->value[0] != 0 || obj->value[1] != 0 ||
		obj->value[2] != 0 || obj->value[3] != 0 )
	{
		send_to_char( "You need an unenchanted staff.\n\r", ch );
		return;
	}
	if      ( skill_table[sn].target == 0 )
	{obj->value[0] = (ch->spl[0]+1)/4;sprintf(col,"purple");}
	else if ( skill_table[sn].target == 1 )
	{obj->value[0] = (ch->spl[1]+1)/4;sprintf(col,"red");}
	else if ( skill_table[sn].target == 2 )
	{obj->value[0] = (ch->spl[2]+1)/4;sprintf(col,"blue");}
	else if ( skill_table[sn].target == 3 )
	{obj->value[0] = (ch->spl[3]+1)/4;sprintf(col,"green");}
	else if ( skill_table[sn].target == 4 )
	{obj->value[0] = (ch->spl[4]+1)/4;sprintf(col,"yellow");}
	else
	{
		send_to_char( "Oh dear...big bug...please inform Spiral\n\r", ch );
		return;
	}
	obj->value[1] = (obj->value[0] / 10) + 1;
	obj->value[2] = (obj->value[0] / 10) + 1;
	obj->value[3] = sn;
	sprintf(buf,"%s staff %s %s",ch->name->str,col,skill_table[sn].name);
	obj->name = g_string_assign(obj->name,buf);
	sprintf(buf,"%s's %s staff of %s",ch->name->str,col,skill_table[sn].name);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	sprintf(buf,"A %s staff is lying here.",col);
	obj->description = g_string_assign(obj->description,buf);
	obj->wear_flags = ITEM_TAKE + ITEM_HOLD;
	act("You engrave $p.",ch,obj,NULL,TO_CHAR);
	act("$n engraves $p.",ch,obj,NULL,TO_ROOM);
	return;
}

void spell_bake( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	char col[10];
	int perf_sn;
	OBJ_DATA *obj;
	
	target_name = one_argument( target_name, arg1 );
	target_name = one_argument( target_name, arg2 );
	
	if (IS_NPC(ch)) return;
	if ( arg1[0] == '\0' || arg2[0] == '\0' )
	{
		send_to_char( "What spell do you wish to bake, and on what?\n\r", ch );
		return;
	}
	
	
	if ( ( sn = skill_lookup( arg2 ) ) < 0
		|| ( !IS_NPC(ch) && ch->level < skill_table[sn].skill_level ) )
	{
		send_to_char( "You can't do that.\n\r", ch );
		return;
	}
	
	perf_sn = skill_lookup( "perfection" );
	if ( sn == perf_sn )
	{ 
		send_to_char("You can't bake a spell of perfection!\n\r",ch);
		return;
	}
	
	if ( ch->pcdata->learned[sn] < 100 )
	{
		send_to_char( "You are not adept at that spell.\n\r", ch );
		return;
	}
	
	if ( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
	{
		send_to_char( "You are not carrying that.\n\r", ch );
		return;
	}
	
	if ( obj->item_type != ITEM_PILL )
	{
		send_to_char( "That is not a pill.\n\r", ch );
		return;
	}
	
	if ( obj->value[0] != 0 || obj->value[1] != 0 ||
		obj->value[2] != 0 || obj->value[3] != 0 )
	{
		send_to_char( "You need an unused pill.\n\r", ch );
		return;
	}
	if      ( skill_table[sn].target == 0 )
	{obj->value[0] = ch->spl[0]/4;sprintf(col,"purple");}
	else if ( skill_table[sn].target == 1 )
	{obj->value[0] = ch->spl[1]/4;sprintf(col,"red");}
	else if ( skill_table[sn].target == 2 )
	{obj->value[0] = ch->spl[2]/4;sprintf(col,"blue");}
	else if ( skill_table[sn].target == 3 )
	{obj->value[0] = ch->spl[3]/4;sprintf(col,"green");}
	else if ( skill_table[sn].target == 4 )
	{obj->value[0] = ch->spl[4]/4;sprintf(col,"yellow");}
	else
	{
		send_to_char( "Oh dear...big bug...please inform Spiral\n\r", ch );
		return;
	}
	obj->value[1] = sn;
	if (obj->value[0] >= 25) obj->value[2] = sn; else obj->value[2] = -1;
	if (obj->value[0] >= 50) obj->value[3] = sn; else obj->value[3] = -1;
	sprintf(buf,"%s pill %s %s",ch->name->str,col,skill_table[sn].name);
	obj->name = g_string_assign(obj->name,buf);
	sprintf(buf,"%s's %s pill of %s",ch->name->str,col,skill_table[sn].name);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	sprintf(buf,"A %s pill is lying here.",col);
	obj->description = g_string_assign(obj->description,buf);
	act("You bake $p.",ch,obj,NULL,TO_CHAR);
	act("$n bakes $p.",ch,obj,NULL,TO_ROOM);
	return;
}

void spell_mount( int sn, int level, CHAR_DATA *ch, void *vo )
{
	char buf[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	
	if (IS_NPC(ch)) return;
	
	if (ch->pcdata->followers > 4)
	{
		send_to_char("Nothing happens.\n\r",ch);
		return;
	}
	ch->pcdata->followers++;
	
	victim=create_mobile( get_mob_index( MOB_VNUM_MOUNT ) );
	victim->level = level;
	victim->armor = 0 - (2*level);
	victim->hitroll = level;
	victim->damroll = level;
	victim->hit = 100*level;
	victim->max_hit = 100*level;
	victim->lord = g_string_assign(victim->lord,ch->name->str);
	SET_BIT(victim->affected_by,AFF_FLYING);
	SET_BIT(victim->act, ACT_MOUNT);
	if (IS_GOOD(ch))
	{
		victim->name = g_string_assign(victim->name,"mount white horse pegasus");
		sprintf(buf,"%s's white pegasus",ch->name->str);
		victim->short_descr = g_string_assign(victim->short_descr,buf);
		victim->long_descr = g_string_assign(victim->long_descr,"A beautiful white pegasus stands here.\n\r");
	}
	else if (IS_NEUTRAL(ch))
	{
		victim->name = g_string_assign(victim->name,"mount griffin");
		sprintf(buf,"%s's griffin",ch->name->str);
		victim->short_descr = g_string_assign(victim->short_descr,buf);
		victim->long_descr = g_string_assign(victim->long_descr,"A vicious looking griffin stands here.\n\r");
	}
	else
	{
		victim->name = g_string_assign(victim->name,"mount black horse nightmare");
		sprintf(buf,"%s's black nightmare",ch->name->str);
		victim->short_descr = g_string_assign(victim->short_descr,buf);
		victim->long_descr = g_string_assign(victim->long_descr,"A large black demonic horse stands here.\n\r");
	}
	char_to_room( victim, ch->in_room );
	act( "$N fades into existance.", ch, NULL, victim, TO_CHAR );
	act( "$N fades into existance.", ch, NULL, victim, TO_ROOM );
	return;
}



void spell_scan( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj;
	OBJ_DATA *obj_next;
	bool found = FALSE;
	
	for ( obj = ch->carrying; obj != NULL; obj = obj_next )
	{
		obj_next = obj->next_content;
		if ( obj->condition < 100 && can_see_obj( ch, obj ) )
		{
			found = TRUE;
			act("$p needs repairing.",ch,obj,NULL,TO_CHAR);
		}
	}
	if ( !found )
	{
		send_to_char( "None of your equipment needs repairing.\n\r", ch );
		return;
	}
	return;
}

void spell_repair( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj;
	OBJ_DATA *obj_next;
	bool found = FALSE;
	
	for ( obj = ch->carrying; obj != NULL; obj = obj_next )
	{
		obj_next = obj->next_content;
		if ( obj->condition < 100 && can_see_obj( ch, obj ) )
		{
			found = TRUE;
			obj->condition = 100;
			act("$p magically repairs itself.",ch,obj,NULL,TO_CHAR);
			act("$p magically repairs itself.",ch,obj,NULL,TO_ROOM);
		}
	}
	if ( !found )
	{
		send_to_char( "None of your equipment needs repairing.\n\r", ch );
		return;
	}
	return;
}

void spell_spellproof( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	
	if ( obj->chobj != NULL )
	{
		send_to_char("Your spell has no affect.\n\r",ch);
		return;
	}
	
	if ( IS_SET(obj->quest, QUEST_SPELLPROOF) )
	{
		send_to_char( "That item is already resistance to spells.\n\r", ch );
		return;
	}
	
	SET_BIT(obj->quest, QUEST_SPELLPROOF);
	act("$p shimmers for a moment.",ch,obj,NULL,TO_CHAR);
	act("$p shimmers for a moment.",ch,obj,NULL,TO_ROOM);
	return;
}

void spell_preserve( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	
	if ( obj->timer < 1 )
	{
		send_to_char( "That item doesn't require preserving.\n\r", ch );
		return;
	}
	if ( obj->chobj != NULL )
	{
		send_to_char( "You cannot preserve that.\n\r", ch );
		return;
	}
	
	obj->timer = -1;
	act("$p shimmers for a moment.",ch,obj,NULL,TO_CHAR);
	act("$p shimmers for a moment.",ch,obj,NULL,TO_ROOM);
	return;
}

void spell_major_creation( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj;
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	char itemkind[10];
	int itemtype;
	int itempower = 0;
	int vn = 0;
	
	target_name = one_argument( target_name, arg1 );
	target_name = one_argument( target_name, arg2 );
	
	if (IS_NPC(ch)) return;
	if (arg1[0] == '\0')
	{
		send_to_char( "Item can be one of: Rune, Glyph, Sigil, Book, Page or Pen.\n\r", ch );
		return;
	}
	
/*
The Rune is the foundation/source of the spell.
The Glyphs form the focus/purpose of the spell.
The Sigils form the affects of the spell.
*/
	
	if (!str_cmp(arg1,"rune"  ))
	{
		if (arg2[0] == '\0')
		{send_to_char("You know of no such Rune.\n\r",ch);return;}
		itemtype = ITEM_SYMBOL;
		vn = 1;
		sprintf(itemkind,"rune");
		if      (!str_cmp(arg2,"fire"   )) itempower = 1;
		else if (!str_cmp(arg2,"air"    )) itempower = 2;
		else if (!str_cmp(arg2,"earth"  )) itempower = 4;
		else if (!str_cmp(arg2,"water"  )) itempower = 8;
		else if (!str_cmp(arg2,"dark"   )) itempower = 16;
		else if (!str_cmp(arg2,"light"  )) itempower = 32;
		else if (!str_cmp(arg2,"life"   )) itempower = 64;
		else if (!str_cmp(arg2,"death"  )) itempower = 128;
		else if (!str_cmp(arg2,"mind"   )) itempower = 256;
		else if (!str_cmp(arg2,"spirit" )) itempower = 512;
		else if (!str_cmp(arg2,"mastery")) itempower = 1024;
		else
		{send_to_char("You know of no such Rune.\n\r",ch);return;}
		if (!IS_SET(ch->pcdata->powers[vn], itempower))
		{send_to_char("You know of no such Rune.\n\r",ch);return;}
	}
	else if (!str_cmp(arg1,"glyph" ))
	{
		if (arg2[0] == '\0')
		{send_to_char("You know of no such Glyph.\n\r",ch);return;}
		itemtype = ITEM_SYMBOL;
		vn = 2;
		sprintf(itemkind,"glyph");
		if      (!str_cmp(arg2,"creation"      )) itempower = 1;
		else if (!str_cmp(arg2,"destruction"   )) itempower = 2;
		else if (!str_cmp(arg2,"summoning"     )) itempower = 4;
		else if (!str_cmp(arg2,"transformation")) itempower = 8;
		else if (!str_cmp(arg2,"transportation")) itempower = 16;
		else if (!str_cmp(arg2,"enhancement"   )) itempower = 32;
		else if (!str_cmp(arg2,"reduction"     )) itempower = 64;
		else if (!str_cmp(arg2,"control"       )) itempower = 128;
		else if (!str_cmp(arg2,"protection"    )) itempower = 256;
		else if (!str_cmp(arg2,"information"   )) itempower = 512;
		else
		{send_to_char("You know of no such Glyph.\n\r",ch);return;}
		if (!IS_SET(ch->pcdata->powers[vn], itempower))
		{send_to_char("You know of no such Glyph.\n\r",ch);return;}
	}
	else if (!str_cmp(arg1,"sigil" ))
	{
		if (arg2[0] == '\0')
		{send_to_char("You know of no such Sigil.\n\r",ch);return;}
		itemtype = ITEM_SYMBOL;
		vn = 3;
		sprintf(itemkind,"sigil");
		if      (!str_cmp(arg2,"self"     )) itempower = 1;
		else if (!str_cmp(arg2,"targeting")) itempower = 2;
		else if (!str_cmp(arg2,"area"     )) itempower = 4;
		else if (!str_cmp(arg2,"object"   )) itempower = 8;
		else
		{send_to_char("You know of no such Sigil.\n\r",ch);return;}
		if (!IS_SET(ch->pcdata->powers[vn], itempower))
		{send_to_char("You know of no such Sigil.\n\r",ch);return;}
	}
	else if (!str_cmp(arg1,"book"  )) {itemtype = ITEM_BOOK;sprintf(itemkind,"book");}
	else if (!str_cmp(arg1,"page"  )) {itemtype = ITEM_PAGE;sprintf(itemkind,"page");}
	else if (!str_cmp(arg1,"pen"   )) {itemtype = ITEM_TOOL;sprintf(itemkind,"pen");}
	else
	{
		send_to_char( "Item can be one of: Rune, Glyph, Sigil, Book, Page or Pen.\n\r", ch );
		return;
	}
	obj = create_object( get_obj_index( OBJ_VNUM_PROTOPLASM ), 0 );
	obj->item_type = itemtype;
	
	if (itemtype == ITEM_SYMBOL)
	{
		sprintf(buf,"%s %s",itemkind,arg2);
		obj->value[vn] = itempower;
	}
	else sprintf(buf,"%s",itemkind);
	if (itemtype == ITEM_TOOL)
	{
		obj->value[0] = TOOL_PEN;
		obj->weight = 1;
		obj->wear_flags = ITEM_TAKE + ITEM_HOLD;
	}
	else if (itemtype == ITEM_BOOK)
	{obj->weight = 50;obj->wear_flags = ITEM_TAKE + ITEM_HOLD;}
	obj->name = g_string_assign(obj->name,buf);
	if (itemtype == ITEM_SYMBOL) sprintf(buf,"a %s of %s",itemkind,arg2);
	else sprintf(buf,"a %s",itemkind);
	obj->short_descr = g_string_assign(obj->short_descr,buf);
	sprintf(buf,"A %s lies here.",itemkind);
	obj->description = g_string_assign(obj->description,buf);
	
	obj->questmaker = g_string_assign(obj->questmaker,ch->name->str);
	
	obj_to_char( obj, ch );
	act( "$p suddenly appears in your hands.", ch, obj, NULL, TO_CHAR );
	act( "$p suddenly appears in $n's hands.", ch, obj, NULL, TO_ROOM );
	return;
}

void spell_insert_page( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *page;
	OBJ_DATA *book;
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	
	target_name = one_argument( target_name, arg1 );
	target_name = one_argument( target_name, arg2 );
	
	if ( arg1[0] == '\0' || arg2[0] == '\0' )
	{send_to_char("Syntax is: cast 'insert page' <page> <book>.\n\r",ch);return;}
	if ( ( page = get_obj_carry( ch, arg1 ) ) == NULL )
	{send_to_char("You are not carrying that page.\n\r",ch);return;}
	if ( page->item_type != ITEM_PAGE )
	{send_to_char("That item isn't a page.\n\r",ch);return;}
	if ( ( book = get_obj_carry( ch, arg2 ) ) == NULL )
	{send_to_char("You are not carrying that book.\n\r",ch);return;}
	if ( book->item_type != ITEM_BOOK )
	{send_to_char("That item isn't a book.\n\r",ch);return;}
	if ( IS_SET(book->value[1], CONT_CLOSED) )
	{send_to_char("First you need to open it!\n\r",ch);return;}
	
	obj_from_char(page);
	obj_to_obj(page,book);
	book->value[3] += 1;
	book->value[2] = book->value[3];
	page->value[0] = book->value[3];
	page->specpower = book->value[3]+1;
	
	act("You insert $p into $P.",ch,page,book,TO_CHAR);
	act("$n inserts $p into $P.",ch,page,book,TO_ROOM);
	return;
}

void spell_chaos_blast( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	int dam;
	
	if (IS_ITEMAFF(victim, ITEMA_CHAOSSHIELD)) return;
	dam = dice( level * 5, 10 );
	if ( saves_spell( level, victim ) ) 
		dam =(int)((double)dam * 0.5);
	damage( ch, victim, dam, sn );
	return;
}

void spell_resistance( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	
	if ( obj->chobj != NULL )
	{
		send_to_char("Your spell has no affect.\n\r",ch);
		return;
	}
	if ( IS_SET(obj->quest, QUEST_ARTIFACT) )
	{
		send_to_char( "Not on artifacts.\n\r", ch );
		return;
	}
	if ( obj->resistance <= 10 )
	{
		send_to_char( "You cannot make that item any more resistant.\n\r", ch );
		return;
	}
	obj->resistance = 10;
	act("$p sparkles for a moment.",ch,obj,NULL,TO_CHAR);
	act("$p sparkles for a moment.",ch,obj,NULL,TO_ROOM);
	return;
}

void spell_web( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	act("You point your finger at $N and a web flies from your hand!",ch,NULL,victim,TO_CHAR);
	act("$n points $s finger at $N and a web flies from $s hand!",ch,NULL,victim,TO_NOTVICT);
	act("$n points $s finger at you and a web flies from $s hand!",ch,NULL,victim,TO_VICT);
	
	if ( IS_AFFECTED(victim, AFF_WEBBED) )
	{
		send_to_char( "But they are already webbed!\n\r", ch );
		return;
	}
	
	if ( is_safe(ch, victim) ) return;
	
	if ( saves_spell( level, victim ) && victim->position >= POS_FIGHTING )
	{
		send_to_char( "You dodge the web!\n\r", victim );
		act("$n dodges the web!",victim,NULL,NULL,TO_ROOM);
		return;
	}
	
	af.type      = sn;
	af.location  = APPLY_AC;
	af.modifier  = 200;
	af.duration  = number_range(1,2);
	af.bitvector = AFF_WEBBED;
	affect_to_char( victim, &af );
	send_to_char( "You are coated in a sticky web!\n\r", victim );
	act("$n is coated in a sticky web!",victim,NULL,NULL,TO_ROOM);
	return;
}

void spell_arm( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	
	if ( IS_AFFECTED(victim, AFF_WEBBED) )
	{
		send_to_char( "But they are already surrounded with tenticals!\n\r", ch );
		return;
	}
	
	if ( is_safe(ch, victim) ) return;
	
	if ( saves_spell( level, victim ) && victim->position >= POS_FIGHTING )
	{
		send_to_char( "You dodge the darkness!\n\r", victim );
		act("$n dodges the darkness!",victim,NULL,NULL,TO_ROOM);
		return;
	}
	
	act("You summon tentacles of solid darkess from the shadows, which gasp $N firmly!",ch,NULL,victim,TO_CHAR);
	act("$n summons tentacles of solid darkess from the shadows, which grasp $N firmly!",ch,NULL,victim,TO_NOTVICT);
	act("$n summons tentacles of solid darkess from the shadows, which grasp you firmly!",ch,NULL,victim,TO_VICT);
	
	af.type      = sn;
	af.location  = APPLY_AC;
	af.modifier  = 200;
	af.duration  = number_range(1,2);
	af.bitvector = AFF_WEBBED;
	affect_to_char( victim, &af );
	return;
}

void spell_polymorph( int sn, int level, CHAR_DATA *ch, void *vo )
{
	AFFECT_DATA af;
	char buf [MAX_INPUT_LENGTH];
	
	if (IS_AFFECTED(ch, AFF_POLYMORPH))
	{
		send_to_char("You cannot polymorph from this form.\n\r",ch);
		return;
	}
	if ( ch->position == POS_FIGHTING || is_affected( ch, sn ) )
		return;
	
	if ( !str_cmp( target_name, "frog" ) )
	{
		if (!IS_NPC(ch) && ch->stance[0] != -1) do_stance(ch,"");
		if (ch->mounted == IS_RIDING) do_dismount(ch,"");
		act("$n polymorphs into a frog!",ch,NULL,NULL,TO_ROOM);
		send_to_char("You polymorph into a frog!\n\r",ch);
		clear_stats(ch);
		af.type      = sn;
		af.duration  = number_range(3,5);
		af.location  = APPLY_POLY;
		af.modifier  = POLY_FROG;
		af.bitvector = AFF_POLYMORPH;
		affect_to_char( ch, &af );
		sprintf(buf,"%s the frog",ch->name->str);
		ch->morph = g_string_assign(ch->morph,buf);
		return;
	}
	else if ( !str_cmp( target_name, "fish" ) )
	{
		if (!IS_NPC(ch) && ch->stance[0] != -1) do_stance(ch,"");
		if (ch->mounted == IS_RIDING) do_dismount(ch,"");
		act("$n polymorphs into a fish!",ch,NULL,NULL,TO_ROOM);
		send_to_char("You polymorph into a fish!\n\r",ch);
		clear_stats(ch);
		af.type      = sn;
		af.duration  = number_range(3,5);
		af.location  = APPLY_POLY;
		af.modifier  = POLY_FISH;
		af.bitvector = AFF_POLYMORPH;
		affect_to_char( ch, &af );
		sprintf(buf,"%s the fish",ch->name->str);
		ch->morph = g_string_assign(ch->morph,buf);
		return;
	}
	else if ( !str_cmp( target_name, "raven" ) )
	{
		if (!IS_NPC(ch) && ch->stance[0] != -1) do_stance(ch,"");
		if (ch->mounted == IS_RIDING) do_dismount(ch,"");
		act("$n polymorphs into a raven!",ch,NULL,NULL,TO_ROOM);
		send_to_char("You polymorph into a raven!\n\r",ch);
		clear_stats(ch);
		af.type      = sn;
		af.duration  = number_range(3,5);
		af.location  = APPLY_AC;
		af.modifier  = -150;
		if (IS_AFFECTED(ch, AFF_FLYING)) af.bitvector = AFF_POLYMORPH;
		else af.bitvector = AFF_POLYMORPH + AFF_FLYING;
		affect_to_char( ch, &af );
		af.location  = APPLY_POLY;
		af.modifier  = POLY_RAVEN;
		affect_to_char( ch, &af );
		sprintf(buf,"%s the raven",ch->name->str);
		ch->morph = g_string_assign(ch->morph,buf);
		return;
	}
	send_to_char( "You can polymorph into a frog, a fish, or an raven.\n\r", ch );
	return;
}

void spell_contraception( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim = (CHAR_DATA *) vo;
	AFFECT_DATA af;
	
	if ( IS_AFFECTED(victim, AFF_CONTRACEPTION) )
		return;
	if (victim->sex != SEX_FEMALE) return;
	af.type      = sn;
	af.duration  = 24;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_CONTRACEPTION;
	affect_to_char( victim, &af );
	return;
}

void spell_find_familiar( int sn, int level, CHAR_DATA *ch, void *vo )
{
	CHAR_DATA *victim;
	CHAR_DATA *familiar;
	
/* kavirpoint */
	send_to_char( "This spell has been temporarily disabled.\n\r", ch );
	return;
	
	if ( target_name[0] == '\0' )
	{
		send_to_char( "Your familiar can be a frog, a raven, a cat or a dog.\n\r", ch );
		return;
	}
	
	if ( ( familiar = ch->pcdata->familiar ) != NULL ) 
	{
		send_to_char( "But you already have a familiar!\n\r", ch );
		return;
	}
	
	if ( !str_cmp( target_name, "frog" ) )
	{
		victim = create_mobile( get_mob_index( MOB_VNUM_FROG ) );
		if (victim == NULL)
		{send_to_char("Error - please inform Spiral\n\r",ch); return;}
	}
	else if ( !str_cmp( target_name, "raven" ) )
	{
		victim = create_mobile( get_mob_index( MOB_VNUM_RAVEN ) );
		if (victim == NULL)
		{send_to_char("Error - please inform Spiral\n\r",ch); return;}
	}
	else if ( !str_cmp( target_name, "cat" ) )
	{
		victim = create_mobile( get_mob_index( MOB_VNUM_CAT ) );
		if (victim == NULL)
		{send_to_char("Error - please inform Spiral\n\r",ch); return;}
	}
	else if ( !str_cmp( target_name, "dog" ) )
	{
		victim = create_mobile( get_mob_index( MOB_VNUM_DOG ) );
		if (victim == NULL)
		{send_to_char("Error - please inform Spiral\n\r",ch); return;}
	}
	else 
	{
		send_to_char( "Your familiar can be a frog, a raven, a cat or a dog.\n\r", ch );
		return;
	}
	
	act( "You make a few gestures and $N appears in a swirl of smoke.", ch, NULL, victim, TO_CHAR );
	act( "$n makes a few gestures and $N appears in a swirl of smoke.", ch, NULL, victim, TO_ROOM );
	char_to_room( victim, ch->in_room );
	
	ch->pcdata->familiar = victim;
	victim->wizard = ch;
	return;
}

void spell_improve( int sn, int level, CHAR_DATA *ch, void *vo )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	
	if ( IS_SET(obj->quest, QUEST_ARTIFACT) )
	{
		send_to_char( "Not on artifacts.\n\r", ch );
		return;
	}
	if ( obj->pIndexData->vnum != OBJ_VNUM_PROTOPLASM )
	{
		send_to_char( "You cannot enhance this object.\n\r", ch );
		return;
	}
	if (IS_SET(obj->quest, QUEST_IMPROVED))
	{
		send_to_char( "This item has already been improved.\n\r", ch );
		return;
	}
	else if ( obj->points < 750 && obj->item_type != ITEM_WEAPON )
	{
		send_to_char( "The object must be worth at least 750 quest points.\n\r", ch );
		return;
	}
	else if ( obj->points < 1500 && obj->item_type == ITEM_WEAPON )
	{
		send_to_char( "The object must be worth at least 1500 quest points.\n\r", ch );
		return;
	}
	REMOVE_BIT(obj->quest, QUEST_STR);
	REMOVE_BIT(obj->quest, QUEST_DEX);
	REMOVE_BIT(obj->quest, QUEST_INT);
	REMOVE_BIT(obj->quest, QUEST_WIS);
	REMOVE_BIT(obj->quest, QUEST_CON);
	REMOVE_BIT(obj->quest, QUEST_HITROLL);
	REMOVE_BIT(obj->quest, QUEST_DAMROLL);
	REMOVE_BIT(obj->quest, QUEST_HIT);
	REMOVE_BIT(obj->quest, QUEST_MANA);
	REMOVE_BIT(obj->quest, QUEST_MOVE);
	REMOVE_BIT(obj->quest, QUEST_AC);
	SET_BIT(obj->quest, QUEST_IMPROVED);
	act("$p flickers for a moment.",ch,obj,NULL,TO_CHAR);
	act("$p flickers for a moment.",ch,obj,NULL,TO_ROOM);
	return;
}

void spell_plague( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;

	if ( is_tempsafe(victim))
	{
		send_to_char("Not in safe rooms!",ch);
		return;
	}

    if ( saves_spell( level, victim ) )
    {
    	if (ch == victim)
      		send_to_char("You feel momentarily ill, but it passes.\n\r",ch);
    	else
      		act("$N seems to be unaffected.",ch,NULL,victim,TO_CHAR);
    	return;
    }

    if (IS_SWWF(victim) && get_tribe(victim,TRIBE_FIANNA) >= 1)
    {
        send_to_char("They seem to be unaffected.\n\r",ch);
        return;
    }

    af.type       = sn;
    af.duration  = level;
    af.location  = APPLY_STR;
    af.modifier  = -5;
    af.bitvector = AFF_PLAGUE;
    affect_to_char( victim, &af );

    send_to_char
      ("You scream in agony as plague sores erupt from your skin.\n\r",victim);
    act("$n screams in agony as plague sores erupt from $s skin.", victim,NULL,NULL,TO_ROOM);
    return;
}

void spell_cure_disease( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *) vo;

    if ( !is_affected( victim, gsn_plague ) )
    {
        if (victim == ch)
          send_to_char("You aren't ill.\n\r",ch);
        else
          act("$N doesn't appear to be diseased.",ch,NULL,victim,TO_CHAR);
        return;
    }

    if ( is_affected( victim, gsn_plague ) )
	{
		affect_strip( victim, gsn_plague );
    		act("$n looks relieved as $s sores vanish.",victim,NULL,NULL,TO_ROOM);
    		send_to_char("Your sores vanish.\n\r",victim);
		send_to_char( "Ok.\n\r", ch );
		return;
    }
}

void spell_fear( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;

    if ( victim == ch )
    {
	send_to_char( "You're really scared of yourself!\n\r", ch );
	return;
    }

    if ( IS_AFFECTED(victim, AFF_FEAR) )
    {
	send_to_char( "They already seem pretty scared!\n\r", ch );
	return;
    }

    if (IS_ADDED(victim, ADDED_COURAGE))
    {
	send_to_char( "They are far too brave to be scared so easily.\n\r", ch );
	return;
    }

    if (!IS_NPC(victim))
    {
	if ((IS_VAMPIRE(victim) && (victim->pcdata->stats[UNI_GEN] < ch->pcdata->stats[UNI_GEN])) )
	{send_to_char("Nothing happens.\n\r",ch);return;}
    }

    if ( is_safe(ch, victim) ) return;

    if ( saves_spell( level, victim ) && victim->position >= POS_FIGHTING )
    {
	act("$E ignores you.",ch,NULL,victim,TO_CHAR);
	act("You ignore $m.",ch,NULL,victim,TO_VICT);
	act("$N ignores $n.",ch,NULL,victim,TO_NOTVICT);
	return;
    }

    af.type      = sn;
    af.location  = APPLY_NONE;
    af.modifier  = 0;
    af.duration  = number_range(1,2);
    af.bitvector = AFF_FEAR;
    affect_to_char( victim, &af );
    send_to_char( "You scream in terror!\n\r", victim );
    act("$n screams in terror!",victim,NULL,NULL,TO_ROOM);
    return;
}