dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// magic.cpp - spells etc
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with all the licenses *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 ***************************************************************************
 * >> Original Diku Mud copyright (c)1990, 1991 by Sebastian Hammer,       *
 *    Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, & Katja Nyboe.   *
 * >> Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael       *
 *    Chastain, Michael Quan, and Mitchell Tse.                            *
 * >> ROM 2.4 is copyright 1993-1995 Russ Taylor and has been brought to   *
 *    you by the ROM consortium: Russ Taylor(rtaylor@pacinfo.com),         *
 *    Gabrielle Taylor(gtaylor@pacinfo.com) & Brian Moore(rom@rom.efn.org) *
 * >> Oblivion 1.2 is copyright 1996 Wes Wagner                            *
 **************************************************************************/

#include "include.h" // dawn standard includes

#include "magic.h"
#include "msp.h"
#include "ictime.h"

// command procedures needed
DECLARE_DO_FUN(do_look		);
DECLARE_DO_FUN(do_far_scan);
DECLARE_DO_FUN(do_bug);
char *format_obj_to_char (OBJ_DATA *, char_data *, bool Short);/*act_info.c*/
bool check_skin( char_data *ch, char_data *victim);
bool check_strength( int level, char_data *ch, char_data *victim, bool &half );
char *get_weapontype(OBJ_DATA *obj);
bool check_social(char_data *ch,char * command, char * argument, bool global);

// Local functions
void	say_spell	args(( char_data *ch, int sn, CLASS_CAST_TYPE type ) );
void	check_components(  char_data *ch, int sn );

// imported functions
bool    remove_obj      args( ( char_data *ch, int iWear, bool fReplace ) );

/**************************************************************************/
// Lookup a skill by name - exact match
int skill_exact_lookup( const char *name )
{
    int sn;

    for ( sn = 0; sn < MAX_SKILL; sn++ )
    {
		if ( IS_NULLSTR(skill_table[sn].name))
			break;
		if ( !str_cmp( name, skill_table[sn].name ) )
			return sn;
    }

    return -1;
}

/**************************************************************************/
// Lookup a skill by name.
int skill_lookup( const char *name )
{
	int sn;
	if(!str_cmp(name, "second")){
		name="dual wield";
	}    

	sn=skill_exact_lookup(name);

	if(sn>-1){
		return sn;
	}

    for ( sn = 0; sn < MAX_SKILL; sn++ )
    {
	if ( IS_NULLSTR(skill_table[sn].name))
	    break;
	if ( LOWER(name[0]) == LOWER(skill_table[sn].name[0])
	&&   !str_prefix( name, skill_table[sn].name ) )
	    return sn;
    }

    return -1;
}

/**************************************************************************/
int find_spell( char_data *ch, const char *name, bool spellonly)
{
    // finds a spell the character can cast if possible
    int sn, found = -1;
	int first=0;
	int last=MAX_SKILL;
	
	if(IS_NPC(ch)){
		return skill_lookup(name);
	}

	if(spellonly){
		first=FIRST_SPELL;
		last=LAST_SPELL+1;
	}

	// exact match first
    for ( sn = first; sn < last; sn++ ){
        if (skill_table[sn].name == NULL){
            break;
		}
        if (!str_cmp(name,skill_table[sn].name)){
            if ( found == -1){
                found = sn;
			}
            if (get_skill(ch,sn) > 0){
                return sn;
			}
        }
    }

	// substring match
    for ( sn = first; sn < last; 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)){
            if ( found == -1){
                found = sn;
			}
            if (get_skill(ch,sn) > 0){
                return sn;
			}
        }
    }
    return found;
}

/**************************************************************************/
// Utter mystical words for an sn.
void say_spell( char_data *ch, int sn, CLASS_CAST_TYPE type )
{
    char buf  [MSL];
    char buf2 [MSL];
    char_data *rch;
    char *pName;
    int iSyl;
    int length;

    struct syl_type
    {
	char *	old;
	char *	nw;
    };

    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"		},
	{ "fresh",	"ima"		},
	{ "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 = str_len(syl_table[iSyl].old)) != 0; iSyl++ )
		{
			if ( !str_prefix( syl_table[iSyl].old, pName ))
			{
				strcat( buf, syl_table[iSyl].nw );
				break;
			}
		}
		
		if ( length == 0 )
			length = 1;
	}

	switch (type){
		case CCT_MAXCAST:
		case CCT_NONE:
		sprintf( buf2, "$n utters the words - THERE IS A BUG, CCT_NONE IN sayspell(), '%s'.", 
			buf );
		sprintf( buf,  "$n utters the words - THERE IS A BUG, CCT_NONE IN sayspell(), '%s'.", 
			skill_table[sn].name );
		break;

		case CCT_MAGE:
		sprintf( buf2, "$n utters the words, '%s'.", buf );
		sprintf( buf,  "$n utters the words, '%s'.", skill_table[sn].name );
		break;

		case CCT_CLERIC:
		sprintf( buf2, "$n prays the words, '%s'.", buf );
		sprintf( buf,  "$n prays the words, '%s'.", skill_table[sn].name );
		break;
		case CCT_DRUID:
		sprintf( buf2, "$n summons the elements of nature using the words, '%s'.", buf );
		sprintf( buf,  "$n summons the elements of nature using the words, '%s'.", skill_table[sn].name );
		break;
		// Bardic songs won't be encrypted by the syl_table
		case CCT_BARD:
		sprintf( buf2, "$n sings the song, '%s'.", skill_table[sn].name );
		sprintf( buf,  "$n sings the song, '%s'.", skill_table[sn].name );
		break;
	}

	// MSP Spell Sound

	if ( !IS_NULLSTR( skill_table[sn].msp_sound )){
		msp_to_room(MSPT_SPELL, skill_table[sn].msp_sound, 
							0, 
							ch,
							false,
							true);
	}

    for ( rch = ch->in_room->people; rch; rch = rch->next_in_room )
    {
		if ( rch != ch ){
			if ( !is_affected(rch, gsn_deafness)) {

				// imms always get the name of the spell
				if(IS_IMMORTAL(rch)){
					act( buf, ch, NULL, rch, TO_VICT );
					continue;
				}

				if(IS_NPC(ch))
				{
					if(IS_SET(ch->act,ACT_CLERIC)){
						act( class_lookup("cleric")==rch->clss ? buf : buf2, ch, NULL, rch, TO_VICT );
					}else if(IS_SET(ch->act,ACT_MAGE)){
						act( class_lookup("mage")==rch->clss ? buf : buf2, ch, NULL, rch, TO_VICT );
					}else{
						act( buf2, ch, NULL, rch, TO_VICT );
					}
				}else{
					act( ch->clss==rch->clss || IS_IMMORTAL(rch)? buf : buf2, ch, NULL, rch, TO_VICT );
				}
			} else {
				if ( !IS_AFFECTED( rch, AFF_BLIND ) || !is_affected( rch, gsn_blindness )){
					act( "You see $N's lips moving.", rch, NULL, ch, TO_CHAR );
				}
			}
		}
    }
    return;
}



/**************************************************************************/
// Compute a saving throw - Negative apply's make saving throw better.
// a higher save value, the better for the victim
bool saves_spell( int level, char_data *victim, int dam_type )
{
    int save;

    save = 50 + ( victim->level - level) * 5 - victim->saving_throw * 2;
    if (IS_AFFECTED(victim,AFF_BERSERK))
	save += victim->level/2;

	if ( IS_NPC(victim) && IS_SET(victim->act, ACT_IS_UNSEEN))
	{
		return true;
	}

    switch(check_immune(victim,dam_type))
    {
		case IS_IMMUNE:		return true;
		case IS_RESISTANT:	save *= 2;	break;
		case IS_VULNERABLE:	save /= 2;	break;
    }

    if (!IS_NPC(victim) && class_table[victim->clss].fMana)
	save = 9 * save / 10;
    save = URANGE( 5, save, 95 );
    return number_percent( ) < save;
}

/**************************************************************************/
// RT save for dispels 
bool saves_dispel( int dis_level, int spell_level, int duration)
{
    int save;
    
    if (duration == -1)
      spell_level += 15;
      // very hard to dispel permanent effects

    save = 50 + (spell_level - dis_level) * 5;
    save = URANGE( 5, save, 95 );
    return number_percent( ) < save;
}


/**************************************************************************/
// co-routine for dispel magic and cancellation 
// return true if successful
bool check_dispel( int dis_level, char_data *victim, int sn)
{
    AFFECT_DATA *af, *af_next;
	int type;
	bool result=false;
	SPELL_FUN * spell_fun=NULL;

    if (count_affected_by_base_spell(victim, sn)>0)
    {
		// get the parent spell function if appropriate
		if(sn>=FIRST_SPELL && sn<=LAST_SPELL){
			spell_fun= skill_table[sn].spell_fun;
		}
		if(spell_fun==spell_null){
			spell_fun=NULL;
		}

        for ( af = victim->affected; af; af = af_next )
        {
			af_next=af->next;

			type=af->type;
			if(	(		spell_fun
				  &&	type>=FIRST_SPELL 
				  &&	type<=LAST_SPELL 
				  &&	skill_table[type].spell_fun == spell_fun
				)
				|| (type == sn) )
            {
                if (!saves_dispel(dis_level,af->level,af->duration))
                {
					affect_remove( victim, af);

					if ( !IS_NULLSTR(skill_table[type].msg_off) )
					{
						victim->printlnf( "%s", skill_table[type].msg_off );
					}
					result=true;
			}else{ // weaken the spell slightly
					af->level--;
				}
            }
        }
    }
    return result;
}

/**************************************************************************/
bool check_component( char_data *ch, int sn )
{
    OBJ_DATA *obj;

    if ( IS_NPC( ch )) return true;	// mobs don't need components (yet)

    for ( obj = ch->carrying; obj; obj = obj->next_content )
	{
		if ( obj->item_type == ITEM_COMPONENT && obj->value[1] == sn )
		{
			if ( --obj->value[0] == 0 )
			{
				act ( "$p has been consumed by your magic.", ch, obj, NULL, TO_CHAR );
				extract_obj( obj );
			}
			else if ( obj->value[0] < 0 )
			{
				obj->value[0] = -1;
			}
			return true;
		}
	}

	if ( !obj )
	{
		ch->println( "You lack the proper ingredient for this spell." );
		return false;
    }
    return true;
}


/**************************************************************************/
// The kludgy global is for spells who want more stuff from command line.
char *target_name;
/**************************************************************************/
void do_newcast( char_data *ch, char *argument, int cast_level, CLASS_CAST_TYPE type )
{
    char arg1[MIL];
    char arg2[MIL];
    char_data *victim;
    OBJ_DATA *obj;
	EXIT_DATA *pexit;
	int *pdoor;
    void *vo;
    int mana;
    int sn;
    int target;
    int roll;
    int spell_level;
	int mana_result;
	int door;
	AFFECT_DATA *paf; // For spell grouping
	
    // Switched NPC's can cast spells, but others can't.
    if (IS_UNSWITCHED_MOB(ch))
		return;

	if(!IS_ADMIN( ch ) && IS_OOC( ch )){
		ch->println( "You can not use magic in an ooc area." );
		return;
	}
	
	if ( IS_SET( ch->in_room->room_flags, ROOM_ANTIMAGIC )) {
		ch->println( "Your cannot conjure up a spark of magic here." );
		return;
	}
	
	// Check to see if ch is charmed and being ordered to cast
    if ( IS_AFFECTED(ch,AFF_CHARM) && !IS_SET( ch->dyn, DYN_IS_BEING_ORDERED ))
	{
		ch->println( "You must wait for your master to tell you to cast a spell." );
		return;
	}
	
    target_name = one_argument( argument, arg1 );
    one_argument( target_name, arg2 );
	
    if ( IS_NULLSTR(arg1))
    {
		switch (type){
		case CCT_MAXCAST:
		case CCT_NONE:
			ch->println( "Cast which what where? - THERE IS A BUG, CCT_NONE IN do_newcast()");
			ch->println( "please report to the admin!");
			break;
			
		case CCT_MAGE:
			ch->println( "Cast which what where?");
			break;
			
		case CCT_CLERIC:
			ch->println( "Commune which what where?");
			break;
			
		case CCT_DRUID:
			ch->println( "Summon which what where?");
			break;
		case CCT_BARD:
			ch->println( "Sing which song?" );
			break;
		}
		return;
    }

	REMOVE_BIT( ch->dyn, DYN_SUCCESS_CAST );		//  Starts out false

    // check that it is a spell, and skill is above 0% 
    if ( ( sn = find_spell( ch,arg1, true ) ) < 0
		|| get_skill(ch,sn) ==0
		|| !IS_SPELL(sn))
    {
        ch->printlnf( "You don't know any spells of the name '%s'.", arg1 );
        return;
    }
	
	// do a level check if they aren't an imm and the level 
	// on the spell is an imm level
	// a skill of 101 in the skill is a budget hack to make 
	// an acception to this
	if (!IS_NPC(ch))
	{
		if (( (skill_table[sn].skill_level[ch->clss] >=LEVEL_IMMORTAL
			   || (skill_table[sn].skill_level[ch->clss]==0))
			&& !IS_IMMORTAL(ch)) && ch->pcdata->learned[sn] !=101)
		{
			ch->wrapln("This spell is not castable by your class... "
				"even though for some reason you have it... It may have been "
				"removed from your class for game balances purposes... talk to an "
				"admin to get a refund for on the pracs you have spent on it.");
			return;
		}
	}
	
    if ( ch->position < skill_table[sn].minimum_position ){
        ch->println( "You can't concentrate enough." );
        return;
    }
	
	if ( IS_SET(skill_table[sn].sect_restrict, 1<<ch->in_room->sector_type) )
	{
		ch->printlnf( "You can't seem to cast %s %s.", 
			skill_table[sn].name, 
			sector_desc[ch->in_room->sector_type].name);
		return;
	}
	
    mana = skill_table[sn].min_mana;
	
    if(get_skill(ch,gsn_mana_focusing))
    {
		if( (roll = number_range(1,100)) < get_skill(ch,gsn_mana_focusing))
		{
			mana-=mana*(roll/2)/100;
		}
    }
	
    /*
	* Locate targets.
	*/
    victim	= NULL;
    obj		= NULL;
    vo		= NULL;
    target	= TARGET_NONE;
	
    switch ( skill_table[sn].target )
    {
    default:
        bugf( "Do_cast: bad target for sn %d.", sn );
        return;
		
    case TAR_IGNORE:
		// Check to see if the spell is component based and if they've got it
		if ( skill_table[sn].component_based )
		{
			if ( !check_component( ch, sn ))
				return;
		}
        break;
		
    case TAR_MOB_OFFENSIVE:
    case TAR_CHAR_OFFENSIVE:
        if ( arg2[0] == '\0' )
        {
            if ( ( victim = ch->fighting ) == NULL )
            {
                ch->println( "Cast the spell on whom?" );
                return;
            }
        }
        else
        {
            if ( ( victim = get_char_room( ch, target_name ) ) == NULL )
            {
                ch->printlnf( "Can't see any '%s' here.", target_name );
				if (ch->desc && ch->desc->repeat>5){
					WAIT_STATE( ch, 3 * PULSE_VIOLENCE );
				}
                return;
            }
        }
		
		// target restriction checks
		if((IS_NPC(victim) && IS_SET(skill_table[sn].flags,SKFLAGS_NO_NPCTARGET))
			||(!IS_NPC(victim) && IS_SET(skill_table[sn].flags,SKFLAGS_NO_PCTARGET)))
		{
            ch->println( "Not on that target." );
            return;
		}
		
		// is safe check
        if ( !IS_NPC(ch) ) 
		{   
            if (is_safe(ch,victim) && victim != ch)
            {
                ch->println( "Not on that target." );
                return;
            }
        }

		if ( !can_initiate_combat( ch, victim, CIT_GENERAL | CIT_CASTING_SPELL )) return;

        if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
        {
            ch->println( "You can't do that on your own follower." );
            return;
        }
		
        vo = (void *) victim;
        target = TARGET_CHAR;
		
		// Check to see if the spell is component based and if they've got it
		if ( skill_table[sn].component_based )
		{
			if ( !check_component( ch, sn ))
				return;
		}
        break;
		
    case TAR_CHAR_DEFENSIVE:
        if ( arg2[0] == '\0' )
        {
            victim = ch;
        }
        else
        {
            if ( ( victim = get_char_room( ch, target_name ) ) == NULL )
            {
				ch->printlnf( "You can't see any '%s' here.", target_name );
				return;
            }
        }
		
		// Start Grouping check
		for (paf = victim->affected; paf; paf=paf->next)
			for(int i=0; spell_group_flags[i].name; i++)
				if (   IS_SET(skill_table[sn].spellgroup, spell_group_flags[i].bit)
					&& IS_SET(skill_table[paf->type].spellgroup, spell_group_flags[i].bit) )
				{
					if (victim == ch)
						ch->println( "But you're already affected by something similar!");
					else
						ch->printlnf( "But %s is already affected by something similar!", victim->short_descr);
					return;
				}
				// End Grouping check
				
				vo = (void *) victim;
				target = TARGET_CHAR;
				
				// Check to see if the spell is component based and if they've got it
				if ( skill_table[sn].component_based )
				{
					if ( !check_component( ch, sn ))
						return;
				}
				break;
				
    case TAR_CHAR_SELF:
        if ( !IS_NULLSTR(arg2)
			&& !str_cmp(target_name, "self") 
			&& !is_name( target_name, ch->name ) )
        {
            ch->println( "You cannot cast this spell on another." );
            return;
        }
		
		// Start Grouping check
		for (paf = ch->affected; paf; paf=paf->next)
			for(int i=0; spell_group_flags[i].name; i++)
				if (   IS_SET(skill_table[sn].spellgroup, spell_group_flags[i].bit)
					&& IS_SET(skill_table[paf->type].spellgroup, spell_group_flags[i].bit) )
				{
					ch->println( "But you're already affected by something similar!" );
					return;
				}
				// End Grouping check
				
				vo = (void *) ch;
				target = TARGET_CHAR;
				
				// Check to see if the spell is component based and if they've got it
				if ( skill_table[sn].component_based )
				{
					if ( !check_component( ch, sn ))
						return;
				}
				break;
				
    case TAR_OBJ_INV:
        if ( arg2[0] == '\0' )
        {
            ch->println( "What should the spell be cast upon?" );
			return;
        }
		
        if ( ( obj = get_obj_carry( ch, target_name ) ) == NULL )
        {
            ch->printlnf( "You are not carrying any '%s'.", target_name );
            return;
        }
		
        vo = (void *) obj;
        target = TARGET_OBJ;
		
		// Check to see if the spell is component based and if they've got it
		if ( skill_table[sn].component_based )
		{
			if ( !check_component( ch, sn ))
				return;
		}
        break;
		
	case TAR_DIRECTION:
        if (arg2[0] == '\0')
		{
			ch->println( "Cast the spell in what direction?" );
			return;
		}
		
		door = dir_lookup( arg2);
		
		if ( door == -1 )
		{
			ch->printlnf( "'%s' is an invalid direction.", arg2 ); 
			return;
		}
		
		if ( (pexit = ch->in_room->exit[door]) == NULL || pexit->u1.to_room == NULL )
		{
			ch->println( "There is no exit in that direction." );
			return;
		}
		
		pdoor = &door;
		
		vo = (void *) pdoor;
		target = TARGET_CHAR;
		
		// Check to see if the spell is component based and if they've got it
		if ( skill_table[sn].component_based )
		{
			if ( !check_component( ch, sn ))
				return;
		}
		break;
		
    case TAR_OBJ_MOB_OFF:
    case TAR_OBJ_CHAR_OFF:
        if (arg2[0] == '\0')
        {
            if ((victim = ch->fighting) == NULL)
            {
				ch->println( "Cast the spell on whom or what?" );
				return;
            }
			
            target = TARGET_CHAR;
        }
        else if ((victim = get_char_room(ch,target_name)) != NULL)
        {
            target = TARGET_CHAR;
        }
		
        if (target == TARGET_CHAR) // check the sanity of the attack        		
		{
			// target restriction checks
			if((IS_NPC(victim) && IS_SET(skill_table[sn].flags,SKFLAGS_NO_NPCTARGET))
				||(!IS_NPC(victim) && IS_SET(skill_table[sn].flags,SKFLAGS_NO_PCTARGET)))
			{
				ch->println( "Not on that target." );
				return;
			}
			
			// is safe check
            if(is_safe_spell(ch,victim,false) && victim != ch)
            {
				ch->println( "Not on that target." );
				return;
            }
			
            if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
            {
                ch->println( "You can't do that on your own follower." );
                return;
			}
			
            vo = (void *) victim;
        }
        else if ((obj = get_obj_here(ch,target_name)) != NULL)
        {
            vo = (void *) obj;
            target = TARGET_OBJ;
        }
        else
        {
            ch->printlnf( "You don't see any '%s' here.", target_name );
            return;
        }
		// Check to see if the spell is component based and if they've got it
		if ( skill_table[sn].component_based )
		{
			if ( !check_component( ch, sn ))
				return;
		}
        break; 
		
    case TAR_OBJ_CHAR_DEF:
        if (arg2[0] == '\0')
		{
			// Start Grouping check
			for (paf = ch->affected; paf; paf=paf->next)
				for(int i=0; spell_group_flags[i].name; i++)
					if (   IS_SET(skill_table[sn].spellgroup, spell_group_flags[i].bit)
						&& IS_SET(skill_table[paf->type].spellgroup, spell_group_flags[i].bit) )
					{
						ch->println( "But you're already affected by something similar!" );
						return;
					}
					// End Grouping check
					
					vo = (void *) ch;
					target = TARGET_CHAR;
        }
        else if ((victim = get_char_room(ch,target_name)) != NULL)
        {
			// Start Grouping check
			for (paf = victim->affected; paf; paf=paf->next)
				for(int i=0; spell_group_flags[i].name; i++)
					if (   IS_SET(skill_table[sn].spellgroup, spell_group_flags[i].bit)
						&& IS_SET(skill_table[paf->type].spellgroup, spell_group_flags[i].bit) )
					{
						ch->printlnf( "But %s is already affected by something similar!", victim->short_descr);
						return;
					}
					//End Grouping check
					
					vo = (void *) victim;
					target = TARGET_CHAR;
        }
        else if ((obj = get_obj_carry(ch,target_name)) != NULL)
        {
            vo = (void *) obj;
            target = TARGET_OBJ;
        }
        else
        {
            ch->printlnf( "You don't see any '%s' here.", target_name );
            return;
        }
		
		// Check to see if the spell is component based and if they've got it
		if ( skill_table[sn].component_based ){
			if ( !check_component( ch, sn )){
				return;
			}
		}
        break;
    }// end of spell type switch
	
    if ( !IS_NPC(ch) && ch->mana < mana )
    {
        ch->println( "You don't have enough mana." );
        return;
    }
	
    if ( str_cmp( skill_table[sn].name, "ventriloquate" ) )
        say_spell( ch, sn, type );
	
    WAIT_STATE( ch, skill_table[sn].beats );
	
	// can't spam charming yourself to improve at it
	if (sn==gsn_charm_person && victim==ch)
	{
		if (number_percent( ) > get_skill(ch,sn) )
		{
			ch->mana -= mana / 2;
			ch->println( "You lost your concentration." );
		}
		else
		{
			ch->mana -= mana;
			ch->println( "You like yourself even better!" );
		}
		return;
	}
	
    if(get_skill(ch,gsn_mana_focusing))
    {
		if( (roll = number_range(1,100)) < get_skill(ch,gsn_mana_focusing))
		{
			check_improve(ch,gsn_mana_focusing, true, 5);
		}
		else
			check_improve(ch,gsn_mana_focusing, false, 5);
    }
	
    if ( number_percent( ) > (get_skill(ch,sn) + ch->modifiers[STAT_SD] - 5))
    {
		ch->mana -= mana / 2;
		ch->println( "You lost your concentration." );
		check_improve(ch,sn,false,1);
    }
    else
    {
        spell_level=ch->level;
		
		
		// moon casting mods by Kalahn
		// mage 
		if (HAS_CLASSFLAG(ch, CLASSFLAG_CASTING_AFFECTED_BY_MOON))
		{
			spell_level += weather_info[ch->in_room->sector_type].mage_castmod;
			if (spell_level<1)
				spell_level=1;
			
		}
		// spellfilcher at half
		if (HAS_CLASSFLAG(ch, CLASSFLAG_CASTING_HALFAFFECTED_BY_MOON))
		{
			spell_level += (weather_info[ch->in_room->sector_type].mage_castmod/2);
			if (spell_level<1)
				spell_level=1;
			
		}
				
		if(get_skill(ch,gsn_sorcery))
		{
			if( (roll = number_range(1,100)) < get_skill(ch,gsn_sorcery))
			{
				spell_level+=roll/5;
				check_improve(ch,gsn_sorcery, true, 5);
			}
			else
				check_improve(ch,gsn_sorcery, false, 5);
		}
		
		if ( IS_SET(skill_table[sn].sect_dampen, 1<<ch->in_room->sector_type) )
			spell_level -= number_range(1,20);
		else if ( IS_SET(skill_table[sn].sect_enhance, 1<<ch->in_room->sector_type) )
			spell_level += number_range(1,10);
		
		// cast_level override if casted from do_castatlevel
		if (cast_level)
			spell_level=cast_level;

		if (!skill_table[sn].spell_fun){
			ch->printlnf( "'%s' is not a spell!", skill_table[sn].name);
			return;
		}

		// spell cast on barbarian turns into a spell_fear_magic instead.
		if( victim 
			&& HAS_CLASSFLAG(victim, CLASSFLAG_MAGIC_ANTIPATHY) 
			&& number_range(1,3)==1 
			&& IS_SET(skill_table[sn].flags, SKFLAGS_MAGICAL_ANTIPATHY) 
			&& !victim->fighting)
		{
			ch->printlnf( "Your spell has set %s into a maddening frenzy!", victim->short_descr);
			sn = gsn_fear_magic;
		}
		
		SET_BIT( ch->dyn, DYN_SUCCESS_CAST );

		if (IS_NPC(ch) || class_table[ch->clss].fMana)
			// clss has spells 
			mana_result = (*skill_table[sn].spell_fun) ( sn, spell_level, ch, vo,target);
        else
            mana_result = (*skill_table[sn].spell_fun) (sn, spell_level, ch, vo,target);
		
		switch( mana_result )
		{
		case NO_MANA:
			mana = 0;
			break;
		case HALF_MANA:
			if ( mana > 0 )
				mana /= 2;
			break;
		case DOUBLE_MANA:
			if ( mana > 0 )
				mana *= 2;
			break;
		case ALL_MANA:
			mana = ch->mana;
		default:
			break;
		}
        ch->mana -= mana;
		
		if (!IS_NPC(ch))
		{
			// record when the spell was last used
			//ch->pcdata->last_used[sn]= current_time;
		}
		
        check_improve(ch,sn,true,1);
    }
	
    if ((skill_table[sn].target == TAR_CHAR_OFFENSIVE
		||   (skill_table[sn].target == TAR_OBJ_CHAR_OFF && target == TARGET_CHAR)
		||   (skill_table[sn].target == TAR_OBJ_MOB_OFF && target == TARGET_CHAR && IS_NPC(victim))
		||   (skill_table[sn].target == TAR_MOB_OFFENSIVE && IS_NPC(victim)))
		&&   ch
		&&   ch->in_room
		&&   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;
            }
        }
    }
	
	if (skill_table[sn].target == TAR_MOB_OFFENSIVE && !IS_NPC(victim) && ch!=victim)
	{
		ch->pksafe=0;
		if (ch->pknorecall<5)
			ch->pknorecall=5;
	}
	
    return;
}

/**************************************************************************/
void do_summon( char_data *ch, char *argument )
{
	if(!IS_NPC(ch) && (TRUE_CH(ch)->level<LEVEL_IMMORTAL) ){
		if(class_table[ch->clss].class_cast_type==CCT_NONE){
			ch->println( "What would you know about summoning nature?" );
			return;
		}

		if(class_table[ch->clss].class_cast_type!=CCT_DRUID){
			ch->println( "Try cast or commune." );
			return;
		}
	}
	do_newcast( ch, argument, 0, CCT_DRUID);
}
/**************************************************************************/
void do_commune( char_data *ch, char *argument )
{
	if(!IS_NPC(ch) && (TRUE_CH(ch)->level<LEVEL_IMMORTAL) ){
		if(class_table[ch->clss].class_cast_type==CCT_NONE){
			ch->println( "What would you know about praying?" );
			return;
		}

		if(class_table[ch->clss].class_cast_type!=CCT_CLERIC){
			ch->println( "Try cast or summon." );
			return;
		}
	}
	do_newcast( ch, argument, 0, CCT_CLERIC);
}
/**************************************************************************/
void do_sing( char_data *ch, char *argument )
{
	if(!IS_NPC(ch) && (TRUE_CH(ch)->level<LEVEL_IMMORTAL) )
	{
		if ( class_table[ch->clss].class_cast_type != CCT_BARD )
		{	// default to the sing social
			check_social( ch, "sing", argument, false );
			return;
		}
	}
	do_newcast( ch, argument, 0, CCT_BARD);
}
/**************************************************************************/
void do_cast( char_data *ch, char *argument )
{
	if(!IS_NPC(ch) && (TRUE_CH(ch)->level<LEVEL_IMMORTAL) ){		
		if(class_table[ch->clss].class_cast_type==CCT_NONE){
			if(GAMESETTING5(GAMESET5_DEDICATED_PKILL_STYLE_MUD)){
				do_newcast( ch, argument, 0, CCT_MAGE);
			}else{
				ch->println( "What would you know about magic?" );
			}
			return;
		}

		if(class_table[ch->clss].class_cast_type!=CCT_MAGE){
			ch->println( "Try commune or summon." );
			return;
		}
	}

	// mobs with the cleric bit dont cast spells, they 'pray' them
	if(IS_NPC(ch) && IS_SET(ch->act,ACT_CLERIC)){
		do_newcast( ch, argument, 0, CCT_CLERIC);
		return;
	}

	do_newcast( ch, argument, 0, CCT_MAGE);
}
/**************************************************************************/
void do_cast_redirect( char_data *ch, char *argument )
{
	if(class_table[ch->clss].class_cast_type==CCT_CLERIC){
		do_commune(ch,argument);
		return;
	}
	if(class_table[ch->clss].class_cast_type==CCT_DRUID){
		do_summon(ch,argument);
		return;
	}
	do_cast(ch,argument);
}

/**************************************************************************/
void do_castatlevel( char_data *ch, char *argument)
{
    char arg[MIL];
	int max_level;

	if (!IS_UNSWITCHED_MOB(ch))
		max_level=ch->level*3;
	else
		max_level=TRUE_CH(ch)->level;

    if (max_level >= MAX_LEVEL*3){
        max_level = MAX_LEVEL*6;
    }

	if ( IS_SET( ch->in_room->room_flags, ROOM_ANTIMAGIC )) {
		ch->println( "You cannot conjure up a spark of magic here." );
		return;
	}
	
    argument = one_argument( argument, arg );

    if ( arg[0] == '\0' || argument[0] == '\0' )
    {
        ch->println( "Castatlevel what?" );
        return;
    }

    if (is_number(arg))
    {
        int new_level = atoi(arg);
        if ((new_level<=max_level) && (new_level>0))
        {
            ch->printlnf( "ATLEVELCAST %d BEGIN.", new_level);
			do_newcast( ch, argument, new_level, CCT_MAGE );
            ch->printlnf( "ATLEVELCAST %d FINISHED.", new_level);
            return;

        }
        else // not high enough trust
        {
            ch->printlnf( "Level must be between 1 and %d.", max_level);
            return;
        }
    }

	ch->println( "Level must be a valid number." );
    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;
    int target = TARGET_NONE;

    if ( sn <= 0 )
	return;

    if ( sn >= MAX_SKILL || skill_table[sn].spell_fun == 0 )
    {
        bugf( "Obj_cast_spell: bad sn %d.", sn );
        return;
    }

    switch ( skill_table[sn].target )
    {
    default:
	bugf( "Obj_cast_spell: bad target for sn %d.", sn );
	return;

    case TAR_IGNORE:
        vo = NULL;
        break;

    case TAR_CHAR_OFFENSIVE:
    case TAR_MOB_OFFENSIVE:
        if ( victim == NULL )
            victim = ch->fighting;
        if ( victim == NULL )
        {
            ch->println( "You can't do that." );
            return;
        }
        if (is_safe(ch,victim) && ch != victim)
        {
            ch->println( "Something isn't right..." );
            return;
        }
        vo = (void *) victim;
        target = TARGET_CHAR;
        break;

    case TAR_CHAR_DEFENSIVE:
    case TAR_CHAR_SELF:
        if ( victim == NULL ){
            victim = ch;
		}
        vo = (void *) victim;
        target = TARGET_CHAR;
        break;

    case TAR_OBJ_INV:
        if ( obj == NULL )
        {
            ch->println( "You can't do that." );
            return;
        }
        vo = (void *) obj;
        target = TARGET_OBJ;
        break;

    case TAR_OBJ_CHAR_OFF:
        if ( victim == NULL && obj == NULL)
	    if (ch->fighting != NULL)
            victim = ch->fighting;
	    else
	    {
            ch->println( "You can't do that." );
            return;
	    }

	    if (victim != NULL)
        {
            if (is_safe_spell(ch,victim,false) && ch != victim)
            {
                ch->println( "Something isn't right..." );
                return;
            }   
            vo = (void *) victim;
            target = TARGET_CHAR;
	    }
	    else
	    {
	    	vo = (void *) obj;
	    	target = TARGET_OBJ;
	    }
        break;


    case TAR_OBJ_CHAR_DEF:
        if (victim == NULL && obj == NULL)
        {
             vo = (void *) ch;
            target = TARGET_CHAR;
        }
        else if (victim != NULL)
        {
            vo = (void *) victim;
            target = TARGET_CHAR;
        }
        else
        {
            vo = (void *) obj;
            target = TARGET_OBJ;
        }    
        break;
    }

    target_name = "";
    (*skill_table[sn].spell_fun) ( sn, level, ch, vo,target);


    if ( (skill_table[sn].target == TAR_CHAR_OFFENSIVE
    ||   (skill_table[sn].target == TAR_OBJ_CHAR_OFF && target == TARGET_CHAR))
    &&   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.
/**************************************************************************/

/**************************************************************************/
SPRESULT spell_acid_blast( int sn, int level, char_data *ch, void *vo, int )
{
	char_data *victim = (char_data *) vo;
	int dam;

	dam = dice( level, 10 );
	if ( saves_spell( level, victim, DAMTYPE(sn)))
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_armor( int sn, int level, char_data *ch, void *vo, int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( is_affected( victim, sn ) )
	{
		if (victim == ch)
			ch->println( "You are already armored." );
		else
			act("$N is already armored.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	af.where	 = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = 24;
	af.modifier  = -20;
	af.location  = APPLY_AC;
	af.bitvector = 0;
	affect_to_char( victim, &af );
	victim->println( "You feel someone protecting you." );

	if ( ch != victim )
		act("$N is protected by your magic.",ch,NULL,victim,TO_CHAR);
    return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_bless( int sn, int level, char_data *ch, void *vo, int target)
{
	char_data *victim;
	OBJ_DATA *obj;
	AFFECT_DATA af;

	// deal with the object case first 
	if (target == TARGET_OBJ)
	{
		obj = (OBJ_DATA *) vo;
		if (IS_OBJ_STAT(obj,OBJEXTRA_BLESS))
		{
			act("$p is already blessed.",ch,obj,NULL,TO_CHAR);
			return HALF_MANA;
		}
		
		if (IS_OBJ_STAT(obj,OBJEXTRA_EVIL))
		{
			AFFECT_DATA *paf;
			
			paf = affect_find(obj->affected,gsn_curse);
			if (!saves_dispel(level,paf != NULL ? paf->level : obj->level,0))
			{
				if (paf != NULL)
					affect_remove_obj(obj,paf);
				act("$p glows a pale blue.",ch,obj,NULL,TO_ALL);
				REMOVE_BIT(obj->extra_flags,OBJEXTRA_EVIL);
				return FULL_MANA;
			}
			else
			{
				act("The evil of $p is too powerful for you to overcome.",
					ch,obj,NULL,TO_CHAR);
				return FULL_MANA;
			}
		}
		
		af.where	= WHERE_OBJEXTRA;
		af.type		= sn;
		af.level	= level;
		af.duration	= 6 + level;
		af.location	= APPLY_SAVES;
		af.modifier	= -1;
		af.bitvector= OBJEXTRA_BLESS;
		affect_to_obj(obj,&af);
		
		act("$p glows with a holy aura.",ch,obj,NULL,TO_ALL);
		return FULL_MANA;
    }

    // character target 
    victim = (char_data *) vo;

	if(is_affected( victim, gsn_curse )){
		if( check_dispel( level, victim, gsn_curse )){
			act( "Your magic unravels a spell on $N.", ch, NULL, victim, TO_CHAR );
			return FULL_MANA;
        }else{
			ch->println("You failed.");
			return FULL_MANA;
        }
	}

	if(is_affected( victim, sn )){
		if (victim == ch){
			ch->println( "You are already blessed." );
		}else{
			act("$N already has divine favor.",ch,NULL,victim,TO_CHAR);
		}
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = 6+level;
	af.location  = APPLY_HITROLL;
	af.modifier  = level / 8;
	af.bitvector = 0;
	affect_to_char( victim, &af );

	af.location  = APPLY_SAVES;
	af.modifier  = 0 - level / 8;
	affect_to_char( victim, &af );
	victim->println( "You feel righteous." );

	if ( ch != victim )
		act("You grant $N the favor of your god.",ch,NULL,victim,TO_CHAR);
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_blindness( int sn, int level, char_data *ch, void *vo, int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_BLIND))
	{
		ch->printlnf( "%s already appears to be blinded.", PERS(victim, ch));
		return HALF_MANA;
	}

	if (saves_spell(level,victim,DAMTYPE(sn)))
	{
		ch->printlnf( "%s seems unaffected.", PERS(victim, ch) );
		return FULL_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.location  = APPLY_HITROLL;
	af.modifier  = -4;
	af.duration  = 1+level;
	af.bitvector = AFF_BLIND;
	affect_to_char( victim, &af );
	victim->println( "You are blinded!" );
	act("$n appears to be blinded.",victim,NULL,NULL,TO_ROOM);
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_burning_hands(int sn,int level, char_data *ch, void *vo, int )
{
	char_data *victim = (char_data *) vo;
	static const sh_int dam_each[] = 
	{
		0,
		0,  0,  0,  0,	14,	17, 20, 23, 26, 29,
		29, 29, 30, 30,	31,	31, 32, 32, 33, 33,
		34, 34, 35, 35,	36,	36, 37, 37, 38, 38,
		39, 39, 40, 40,	41,	41, 42, 42, 43, 43,
		44, 44, 45, 45,	46,	46, 47, 47, 48, 48
	};
   
	int dam;

    level	= UMIN(level, (int)sizeof(dam_each)/(int)sizeof(dam_each[0]) - 1);
    level	= UMAX(0, level);
    dam		= number_range( dam_each[level] / 2, dam_each[level] * 2 );
    if ( saves_spell( level, victim, DAMTYPE(sn)) )
		dam /= 2;
    damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_call_lightning( int sn, int level,char_data *ch,void *,int )
{
	char_data *vch;
	char_data *vch_next;
	int dam;

	if ( !IS_OUTSIDE(ch) )
	{
		ch->println( "You must be out of doors." );
		return NO_MANA;
	}

	if ( ch->in_room->sector_type == SECT_CAVE )
	{
		ch->println( "You cannot cast this spell here." );
		return NO_MANA;
	}

	if ( weather_info[ch->in_room->sector_type].sky < SKY_RAINING )
	{
		ch->println( "You need bad weather." );
		return HALF_MANA;
	}

	dam = dice(level/2, 8);

	ch->println( "Lightning from the sky strikes your foes!" );
	act( "$n calls upon the lightning to strike $s foes!", ch, NULL, NULL, TO_ROOM );

    for ( vch = ch->in_room->people; vch; vch = vch_next )
	{
        vch_next=vch->next_in_room;
		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_spell( ch, vch, saves_spell( level, vch, DAMTYPE( sn )) 
					? dam / 2 : dam, sn, DAMTYPE(sn), true);
			continue;
		}

		if ( vch->in_room->area == ch->in_room->area
		&&   IS_OUTSIDE(vch)
		&&   vch->in_room->sector_type != SECT_CAVE
		&&   IS_AWAKE(vch) )
		vch->println( "Lightning flashes in the sky." );
	}

	return FULL_MANA;
}


/**************************************************************************/
// RT calm spell stops all fighting in the room

SPRESULT spell_calm( int sn, int level, char_data *ch, void *,int )
{
	char_data *vch;
	int mlevel = 0;
	int count = 0;
	int high_level = 0;    
	int chance;
	AFFECT_DATA af;

    /* get sum of all mobile levels in the room */
	for (vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room)
	{
		if (vch->position == POS_FIGHTING)
		{
			count++;
			if (IS_NPC(vch))
				mlevel += vch->level;
			else
				mlevel += vch->level/2;
			high_level = UMAX(high_level,vch->level);
		}
	}

    /* compute chance of stopping combat */
	chance = 4 * level - high_level + 2 * count;

	if ( IS_IMMORTAL( ch )) /* always works */
		mlevel = 0;

	if ( number_range( 0, chance ) >= mlevel )  /* hard to stop large fights */
	{
		for ( vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room )
		{
			if ( IS_NPC( vch )
			&& ( IS_SET( vch->imm_flags, IMM_MAGIC )
			||   IS_SET( vch->act, ACT_UNDEAD )))
			return FULL_MANA;

			if ( IS_AFFECTED( vch, AFF_CALM )
			||   IS_AFFECTED( vch, AFF_BERSERK )
			||   is_affected( vch, gsn_frenzy ))
			return FULL_MANA;
	    
			vch->println( "A wave of calm passes over you." );

			if (vch->fighting || vch->position == POS_FIGHTING )
				stop_fighting( vch, false );


			af.where = WHERE_AFFECTS;
			af.type = sn;
			af.level = level;
			af.duration = level/4;
			af.location = APPLY_HITROLL;

			if (!IS_NPC(vch))
				af.modifier = -5;
			else
				af.modifier = -2;

			af.bitvector = AFF_CALM;
			affect_to_char(vch,&af);
			af.location = APPLY_DAMROLL;
			affect_to_char(vch,&af);
		}
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_cancellation( int , int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	char_data *roomchar;
	bool found = false;

	level += 2;

	if ((!IS_NPC(ch) && IS_NPC(victim) &&
		!(IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim) ) ||
		 (IS_NPC(ch) && !IS_NPC(victim)) )
	{
		ch->println( "You failed, try dispel magic." );
		return HALF_MANA;
	}

	// unlike dispel magic, the victim gets NO save 

	// begin running through the spells 

	if ( IS_SET( ch->in_room->affected_by, ROOMAFF_UTTERDARK )) {
		ch->println( "The darkness around you disappears." );
		act( "The darkness around you disappears.", ch, NULL, NULL, TO_ROOM );
		REMOVE_BIT( ch->in_room->affected_by, ROOMAFF_UTTERDARK );
		found = true;
	}

 	if (check_dispel(level,victim, gsn_regeneration ))
		found = true;
	if (check_dispel(level,victim, gsn_resist_poison ))
		found = true;
	if (check_dispel(level,victim, gsn_poison_immunity ))
		found = true;
	if (check_dispel(level,victim, gsn_prismatic_spray ))
		found = true;
	if (check_dispel(level,victim, gsn_illusions_grandeur ))
		found = true;
	if (check_dispel(level,victim, gsn_protection_fire ))
		found = true;
	if (check_dispel(level,victim, gsn_protection_cold ))
		found = true;
	if (check_dispel(level,victim, gsn_protection_lightning ))
		found = true;
	if (check_dispel(level,victim, gsn_holy_aura ))
		found = true;
	if (check_dispel(level,victim, gsn_true_sight ))
		found = true;
	if (check_dispel(level,victim, gsn_barkskin ))
		found = true;
	if (check_dispel(level,victim, gsn_magic_resistance ))
		found = true;
	if (check_dispel(level,victim, gsn_fire_shield ))
		found = true;
	if (check_dispel(level,victim, gsn_chill_shield ))
		found = true;
	if (check_dispel(level,victim, gsn_animal_essence))
		found = true;
    if (check_dispel(level,victim, gsn_armor ))
		found = true;
	if (check_dispel(level, victim, gsn_bless ))
		found = true;
	if (check_dispel(level,victim, gsn_blindness ))
	{
		found = true;
		act("$n is no longer blinded.",victim,NULL,NULL,TO_ROOM);
    }
	if (check_dispel(level,victim, gsn_calm ))
	{
		found = true;
		act("$n no longer looks so peaceful...",victim,NULL,NULL,TO_ROOM);
	}
    if (check_dispel(level,victim, gsn_change_sex ))
    {
        found = true;
        act("$n looks more like $mself again.",victim,NULL,NULL,TO_ROOM);
    }
    if (check_dispel(level,victim, gsn_charm_person))
	{
		found = true;
		act("$n regains $s free will.",victim,NULL,NULL,TO_ROOM);
	}
	if (check_dispel(level,victim, gsn_chill_touch ))
	{
		found = true;
		act("$n looks warmer.",victim,NULL,NULL,TO_ROOM);
	}
	if (check_dispel(level,victim, gsn_curse ))
		found = true;
	if (check_dispel(level,victim, gsn_detect_evil ))
		found = true;
	if (check_dispel(level,victim, gsn_detect_good ))
		found = true;
    if (check_dispel(level,victim, gsn_detect_hidden ))
        found = true;
	if (check_dispel(level,victim, gsn_detect_invis ))
		found = true;
	if (check_dispel(level,victim, gsn_detect_magic ))
		found = true;
	if (check_dispel(level,victim, gsn_faerie_fire ))
	{
		act("$n's outline fades.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_fly ))
	{
		act("$n falls to the ground!",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_frenzy ))
	{
		act("$n no longer looks so wild.",victim,NULL,NULL,TO_ROOM);;
		found = true;
	}
	if (check_dispel(level,victim, gsn_giant_strength ))
	{
		act("$n no longer looks so mighty.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_haste ))
	{
		act("$n is no longer moving so quickly.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_infravision ))
		found = true;
	if (check_dispel(level,victim, gsn_invisibility ))
	{
		act("$n fades into existance.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
    if (check_dispel(level,victim, gsn_mass_invis ))
    {
		act("$n fades into existance.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_pass_door ))
        found = true;
	if (check_dispel(level,victim, gsn_protection_evil ))
        found = true;
	if (check_dispel(level,victim, gsn_protection_good ))
        found = true; 
	if (check_dispel(level,victim, gsn_rage ))
		found = true;
	if (check_dispel(level,victim, gsn_sanctuary ))
	{
		act("The white aura around $n's body vanishes.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_shield ))
	{
		act("The shield protecting $n vanishes.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_sleep ))
		found = true;
	if (check_dispel(level,victim, gsn_slow ))
	{
		act("$n is no longer moving so slowly.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_stone_skin ))
	{
		act("$n's skin regains its normal texture.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_weaken ))
	{
		act("$n looks stronger.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	
	// Cancelation of the vanish skill.
	for ( roomchar = ch->in_room->people; roomchar != NULL; roomchar = roomchar->next_in_room )
	{
		if ( IS_AFFECTED2(roomchar, AFF2_VANISH))
		{
			affect_strip ( roomchar, gsn_vanish);
			REMOVE_BIT( roomchar->affected_by2, AFF2_VANISH );
			act( "A swirl of dust reveals $n.", roomchar, NULL, NULL, TO_ROOM );
			roomchar->println( "You have been revealed." );
			found = true;
		}
	}

	if (!found) {
        ch->println( "Spell failed." );
		return HALF_MANA;
	}

	ch->println( "Ok." );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_cause_light( int sn, int level, char_data *ch, void *vo,int  )
{
	damage_spell( ch, (char_data *) vo, dice(1, 8) + level / 3, sn, DAMTYPE( sn ),true);
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_cause_critical(int sn,int level,char_data *ch,void *vo,int )
{
	damage_spell( ch, (char_data *) vo, dice(3, 8) + level - 6, sn, DAMTYPE( sn ), true);
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_cause_serious(int sn,int level,char_data *ch,void *vo,int )
{
	damage_spell( ch, (char_data *) vo, dice(2, 8) + level / 2, sn, DAMTYPE( sn ), true);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_chain_lightning(int sn,int level,char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	char_data *tmp_vict,*last_vict,*next_vict;
	bool found;
	int dam;

	// first strike 
	act("A lightning bolt leaps from $n's hand and arcs to $N.", ch,NULL,victim,TO_ROOM);
	act("A lightning bolt leaps from your hand and arcs to $N.", ch,NULL,victim,TO_CHAR);
	act("A lightning bolt leaps from $n's hand and hits you!",   ch,NULL,victim,TO_VICT);  

	dam = dice(level,5);
	if (saves_spell(level,victim, DAMTYPE(sn))){
		dam /= 3;
	}
	damage_spell(ch,victim,dam,sn,DAMTYPE(sn),true);
	last_vict = victim;
    level -= 4;   // decrement damage

    // new targets 
	while (level > 0)
	{
		found = false;
		for (tmp_vict = ch->in_room->people; tmp_vict != NULL; tmp_vict = next_vict) 
		{
			next_vict = tmp_vict->next_in_room;
			if (!is_safe_spell(ch,tmp_vict,true)
				&& tmp_vict != last_vict )
			{
				found = true;
				last_vict = tmp_vict;
				act("The bolt arcs to $n!",tmp_vict,NULL,NULL,TO_ROOM);
				act("The bolt hits you!",tmp_vict,NULL,NULL,TO_CHAR);
				dam = dice(level,5);
				if (saves_spell(level,tmp_vict,DAMTYPE(sn))){
					dam /= 3;
				}
				damage_spell(ch,tmp_vict,dam,sn,DAMTYPE(sn),true);
				level -= 4;  // decrement damage
			}
		}   // end target searching loop 
	
		if (!found) // no target found, hit the caster 
		{
			if (ch == NULL)
				return FULL_MANA;

			if (last_vict == ch) // no double hits 
			{
				act("The bolt seems to have fizzled out.",ch,NULL,NULL,TO_ROOM);
				act("The bolt grounds out through your body.",ch,NULL,NULL,TO_CHAR);
				return FULL_MANA;
			}

			last_vict = ch;
			act("The bolt arcs to $n...whoops!",ch,NULL,NULL,TO_ROOM);
			ch->println( "You are struck by your own lightning!" );
			dam = dice(level,6);
			if (saves_spell(level,ch,DAMTYPE(sn))){
				dam /= 3;
			}
			damage_spell(ch,ch,dam,sn,DAMTYPE(sn),true);
			level-= 4;  // decrement damage
			if (ch==NULL || ch->in_room==NULL) {
				return FULL_MANA;
			}
		}
		// now go back and find more targets 
	}
	return FULL_MANA;
}
	  
/**************************************************************************/
SPRESULT spell_change_sex( int sn, int level, char_data *ch, void *vo,int  )
{
    char_data *victim = (char_data *) vo;
    AFFECT_DATA af;

	if ( is_affected( victim, sn ))
	{
		if (victim == ch)
			ch->println( "You've already been changed." );
		else
			act("$N has already had $s(?) sex changed.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	if (saves_spell(level , victim,DAMTYPE(sn)))
		return FULL_MANA;

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = 2 * 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 );
	victim->println( "You feel different." );
	act("$n doesn't look like $mself anymore...",victim,NULL,NULL,TO_ROOM);
	return FULL_MANA;
}


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

	if (is_safe(ch,victim)) 
	{
		ch->printlnf( "Your spell doesnt appear to have any affect on %s.", PERS(victim, ch));
		return HALF_MANA;
	}

	if ( victim == ch )
	{
		ch->println( "You like yourself even better!" );
		return HALF_MANA;
	}

	if ( IS_AFFECTED(victim, AFF_CHARM)
	||   IS_AFFECTED(ch, AFF_CHARM)
	||   level < victim->level
	||   IS_SET(victim->imm_flags,IMM_CHARM)
	||	 victim->modifiers[STAT_PR]>number_range(0,40)
	||   saves_spell( level, victim, DAMTYPE(sn) ) 
	||   (!IS_NPC(victim) 
			&& !GAMESETTING2(GAMESET2_NOCHARM_HAS_NOAFFECT)
			&& HAS_CONFIG(victim,CONFIG_NOCHARM) 
		 )
		 ){
		ch->println( "You failed." );
		return FULL_MANA;
	}

	if (!IS_NPC(victim) && IS_SET(victim->in_room->room_flags,ROOM_LAW))
	{
		ch->println( "The mayor does not allow charming in the city limits." );
		return HALF_MANA;
	}
  
	if ( victim->master ) {
		stop_follower( victim );
	}
    
	add_follower( victim, ch );
	victim->leader = ch;
	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = number_fuzzy( level / 4 );
	af.location  = APPLY_NONE;
	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 ) {
		act("$N looks at you with adoring eyes.",ch,NULL,victim,TO_CHAR);
	}

	if(IS_NPC(victim)) {
		REMOVE_BIT(victim->act, ACT_AGGRESSIVE);
	}
		
	// stop those who are charmed from logging out
	if (!IS_NPC(victim) && ch!=victim)
	{
		ch->pksafe=0;
		ch->pknorecall= UMAX(ch->pknorecall,2);
		ch->pknoquit  = UMAX(ch->pknorecall,7);

		if (!IS_NPC(ch))
		{
			victim->pknorecall= UMAX(victim->pknorecall,4);
			victim->pknoquit=UMAX(victim->pknoquit,10);
		}
	}
    return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_chill_touch( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;
	int dam;

	dam		= dice(level/2, 2);
	if ( !saves_spell( level, victim,DAMTYPE(sn)))
	{
		act("$n turns blue and shivers.",victim,NULL,NULL,TO_ROOM);
		af.where     = WHERE_AFFECTS;
		af.type      = sn;
		af.level     = level;
		af.duration  = 6;
		af.location  = APPLY_ST;
		af.modifier  = -5;
		af.bitvector = 0;
		affect_join( victim, &af );
	}
	else
	{
		dam /= 2;
	}

	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_colour_spray( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	int dam			  = dice(level/3, 4)+40;

	if ( saves_spell( level, victim,DAMTYPE(sn)) )
		dam /= 2;
	else 
		spell_blindness( gsn_blindness, level/2,ch,(void *) victim,TARGET_CHAR);

	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true );
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_continual_light(int,int ,char_data *ch,void *,int )
{
	OBJ_DATA *light;

	if(!IS_NULLSTR(target_name))  // do a glow on some object 
	{
		light = get_obj_carry(ch,target_name);

		if (light == NULL)
		{
			ch->printlnf( "You don't see any '%s' here.", target_name );
			return NO_MANA;
		}

		if (IS_OBJ_STAT(light,OBJEXTRA_GLOW))
		{
			act("$p is already glowing.",ch,light,NULL,TO_CHAR);
			return NO_MANA;
		}

		SET_BIT(light->extra_flags,OBJEXTRA_GLOW);
		act("$p glows with a white light.",ch,light,NULL,TO_ALL);
		return FULL_MANA;
	}

	light = create_object( get_obj_index( OBJ_VNUM_LIGHT_BALL ));
	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 FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_control_weather(int ,int level,char_data *ch,void *,int ) 
{
	if ( !str_cmp( target_name, "worse" ) )
		weather_info[ch->in_room->sector_type].change += dice( level / 3, 4 );
	else if ( !str_cmp( target_name, "better" ) )
		weather_info[ch->in_room->sector_type].change -= dice( level / 3, 4 );
	else {
		ch->println( "Do you want it to get better or worse?" );
		return NO_MANA;
	}

    ch->println( "Ok." );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_create_food2( int , int level, char_data *ch, void *,int )
{
	OBJ_DATA *mushroom;

	mushroom = create_object( get_obj_index( OBJ_VNUM_MUSHROOM ));
	mushroom->value[0] = number_fuzzy(level);
	mushroom->value[1] = number_fuzzy(level)*2;
	mushroom->timer = (ch->level*2)+10;
	obj_to_room( mushroom, ch->in_room );
	if(	   ch->in_room->sector_type==SECT_AIR
		|| IS_WATER_SECTOR( ch->in_room->sector_type )){
		act( "$p suddenly appears.", ch, mushroom, NULL, TO_ROOM );
		act( "$p suddenly appears.", ch, mushroom, NULL, TO_CHAR );
	}else{
		act( "$p suddenly appears to grow from the ground.", ch, mushroom, NULL, TO_ROOM );
		act( "$p suddenly appears to grow from the ground.", ch, mushroom, NULL, TO_CHAR );
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_create_food( int , int level, char_data *ch, void *,int )
{
	OBJ_DATA *fooditem;
	int		  foodvnum;
	char	  buf[MSL];

	foodvnum = race_table[ch->race]->food_vnum;

	if ( foodvnum == 0 )
		foodvnum = OBJ_VNUM_MUSHROOM;

	if ( get_obj_index( foodvnum ) == NULL )
	{
		bugf("Vnum %d not found for spell_create_food!", foodvnum );

		// do an autonote
		sprintf( buf, "Vnum `Y%d`x not found for race `Y%s`x.`1"
			"Please create item at next possible convenience.`1",
			foodvnum, race_table[ch->race]->name);
		autonote(NOTE_SNOTE, "spell_create_food()",	"Create food", "realm", buf, true);

		// default it to a known item so we don't go BOOM
		foodvnum = OBJ_VNUM_MUSHROOM;
	}

	fooditem = create_object( get_obj_index( foodvnum ));
	fooditem->value[0] = number_fuzzy(level);
	fooditem->value[1] = number_fuzzy(level)*2;
	fooditem->timer = (ch->level*2)+10;
	obj_to_room( fooditem, ch->in_room );

	act( "$p suddenly appears.", ch, fooditem, NULL, TO_ROOM );
	act( "$p suddenly appears.", ch, fooditem, NULL, TO_CHAR );

	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_create_rose( int , int , char_data *ch, void *,int  )
{
	OBJ_DATA *rose;
	if (get_obj_index(OBJ_VNUM_ROSE)) {
		rose = create_object(get_obj_index(OBJ_VNUM_ROSE));
		act("$n has created a beautiful red rose.",ch,rose,NULL,TO_ROOM);
		ch->println( "You create a beautiful red rose." );
		obj_to_char(rose,ch);
	}else{
        ch->println( "BUG: No available rose object in spell_create_rose - please report!" );
		return NO_MANA;
	}

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_create_spring(int ,int level,char_data *ch,void *,int )
{
    OBJ_DATA *spring;

	if ( ch->in_room->sector_type == SECT_AIR )
	{
		ch->println( "You cannot create a spring in the middle of the air." );
		return HALF_MANA;
	}

	if ( IS_WATER_SECTOR( ch->in_room->sector_type ))
	{
		ch->println( "You cannot create a spring in water." );
		return HALF_MANA;
	}

	spring = create_object( get_obj_index( OBJ_VNUM_SPRING ));
	spring->timer = number_fuzzy(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 FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_create_water( int , int level, char_data *ch, void *vo,int )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	int water;

	if ( obj->item_type != ITEM_DRINK_CON )
	{
		ch->println( "It is unable to hold water." );
		return NO_MANA;
	}

	if ( obj->value[2] != LIQ_WATER && obj->value[1] != 0 )
	{
		ch->println( "It contains some other liquid." );
		return HALF_MANA;
	}

	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 ) )
		{
			char buf[MSL];

			sprintf( buf, "%s water", obj->name );
			free_string( obj->name );
			obj->name = str_dup( buf );
		}
		act( "$p is filled.", ch, obj, NULL, TO_CHAR );
	}
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_cure_blindness(int ,int level,char_data *ch,void *vo,int )
{
    char_data *victim = (char_data *) vo;

	if ( !is_affected( victim, gsn_blindness ) )
	{
		if (victim == ch){
			ch->println( "You aren't blind." );
		}else{
			act("$N doesn't appear to be blinded.",ch,NULL,victim,TO_CHAR);
		}
		return HALF_MANA;
	}
 
	if (check_dispel(level,victim,gsn_blindness))
	{
		victim->println( "Your vision returns!" );
		act("$n is no longer blinded.",victim,NULL,NULL,TO_ROOM);
	}else{
		ch->println("Spell failed.");
	}

	return FULL_MANA;
}



/**************************************************************************/
SPRESULT spell_cure_critical( int , int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int heal		  = dice(level/4+1, 2);

	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );
	victim->println( "You feel better!" );
	if ( ch != victim ){
		ch->println( "Ok." );
	}
	return FULL_MANA;
}

/**************************************************************************/
// RT added to cure plague
SPRESULT spell_cure_disease( int , int level, char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;

	if ( !is_affected( victim, gsn_plague ) ){
		if (victim == ch){
			ch->println( "You aren't ill." );
		}else{
			act("$N doesn't appear to be diseased.",ch,NULL,victim,TO_CHAR);
		}
		return HALF_MANA;
	}
    
	if (check_dispel(level,victim,gsn_plague))
	{
		victim->println( "Your sores vanish." );
		act("$n looks relieved as $s sores vanish.",victim,NULL,NULL,TO_ROOM);
	}
	else
		ch->println("Spell failed.");

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_cure_light( int , int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int heal		  = dice(level/12+1, 2);

	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );
	victim->println( "You feel better!" );
	if ( ch != victim ){
		ch->println( "Ok." );
	}
    return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_cure_poison( int , int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
 
	if ( !is_affected( victim, gsn_poison ) )
	{
		if (victim == ch){
			ch->println( "You aren't poisoned." );
		}else{
			act("$N doesn't appear to be poisoned.",ch,NULL,victim,TO_CHAR);
		}
		return HALF_MANA;
	}
 
	if (check_dispel(level,victim,gsn_poison))
	{
		victim->println( "A warm feeling runs through your body." );
		act("$n looks much better.",victim,NULL,NULL,TO_ROOM);
	}
	else
		ch->println("Spell failed.");
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_cure_serious( int , int level, char_data *ch, void *vo,int  )
{
    char_data *victim = (char_data *) vo;
    int heal		  = dice(level/8+1, 2);

	victim->hit = UMIN( victim->hit + heal, victim->max_hit );
	update_pos( victim );
	victim->println( "You feel better!" );

	if ( ch != victim ){
		ch->println( "Ok." );
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_curse( int sn, int level, char_data *ch, void *vo,int target )
{
	char_data *victim;
	OBJ_DATA *obj;
	AFFECT_DATA af;

    // deal with the object curses first
	if (target == TARGET_OBJ)
	{
		obj = (OBJ_DATA *) vo;
		if (IS_OBJ_STAT(obj,OBJEXTRA_EVIL))
		{
			act("$p is already filled with evil.",ch,obj,NULL,TO_CHAR);
			return HALF_MANA;
		}

		if (IS_OBJ_STAT(obj,OBJEXTRA_BLESS))
		{
			AFFECT_DATA *paf;

			paf = affect_find(obj->affected, gsn_bless );
			if (!saves_dispel(level,paf != NULL ? paf->level : obj->level,0))
			{
				if (paf != NULL)
					affect_remove_obj(obj,paf);
				act("$p glows with a red aura.",ch,obj,NULL,TO_ALL);
				REMOVE_BIT(obj->extra_flags,OBJEXTRA_BLESS);
				return FULL_MANA;
			}
			else
			{
				act("The holy aura of $p is too powerful for you to overcome.",ch,obj,NULL,TO_CHAR);
				return FULL_MANA;
			}
		}

		af.where        = WHERE_OBJEXTRA;
		af.type         = sn;
		af.level        = level;
		af.duration     = 2 * level;
		af.location     = APPLY_SAVES;
		af.modifier     = +1;
		af.bitvector    = OBJEXTRA_EVIL;
		affect_to_obj(obj,&af);

		act("$p glows with a malevolent aura.",ch,obj,NULL,TO_ALL);
		return FULL_MANA;
	}

	// character curses 
	victim = (char_data *) vo;

	if( is_affected( victim, gsn_bless ))
		if( check_dispel( level, victim, gsn_bless ))
		{
			act( "Your magic unravels a spell on $N.", ch, NULL, victim, TO_CHAR );
			return FULL_MANA;
		}
		else
		{
			ch->println( "You failed." );
			return FULL_MANA;
		}

	if(IS_AFFECTED(victim,AFF_CURSE))
	{
		act("$N already looks very uncomfortable.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}
		
	if(saves_spell(level,victim,DAMTYPE(sn))){
		ch->println( "Your spell doesnt appear to have much affect." );
		return FULL_MANA;
	}
			
	if(HAS_CLASSFLAG(victim, CLASSFLAG_CURSE_IMMUNITY)) // fails if paladin
	{
		ch->printlnf( "Your spell doesnt appear to have any affect on %s.", PERS(victim, ch) );
		return FULL_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = level/2 + (number_fuzzy(3)*2);
	af.location  = APPLY_HITROLL;
	af.modifier  = -1 * (level / 8);
	af.bitvector = AFF_CURSE;
	affect_to_char( victim, &af );

	af.location  = APPLY_SAVES;
	af.modifier  = level / 8;
	affect_to_char( victim, &af );

	victim->println( "You feel unclean." );
	if ( ch != victim )
	{
		act("$N looks very uncomfortable.",ch,NULL,victim,TO_CHAR);
		// stop those who are slept from logging out
		if (!IS_NPC(ch))
			victim->pknoquit=UMAX(victim->pknoquit,10);
	}

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_detect_evil( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_DETECT_EVIL) )
	{
		if (victim == ch){
			ch->println( "You can already sense evil." );
		}else{
			act("$N can already detect evil.",ch,NULL,victim,TO_CHAR);
		}
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = level;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bitvector = AFF_DETECT_EVIL;
	affect_to_char( victim, &af );
	victim->println( "Your eyes tingle." );
	if ( ch != victim ){
		ch->println( "Ok." );
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_detect_good( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;
 
	if ( IS_AFFECTED(victim, AFF_DETECT_GOOD) )
	{
		if (victim == ch){
			ch->println( "You can already sense good." );
		}else{
			act("$N can already detect good.",ch,NULL,victim,TO_CHAR);
		}
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = level;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bitvector = AFF_DETECT_GOOD;
	affect_to_char( victim, &af );
	victim->println( "Your eyes tingle." );

	if ( ch != victim )
		ch->println( "Ok." );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_detect_hidden(int sn,int level,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_DETECT_HIDDEN) )
	{
		if (victim == ch){
			ch->println( "You are already as alert as you can be." );
		}else{
			act("$N can already sense hidden lifeforms.",ch,NULL,victim,TO_CHAR);
		}
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = level;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_DETECT_HIDDEN;
	affect_to_char( victim, &af );
	victim->println( "Your awareness improves." );
	if ( ch != victim ){
		ch->println( "Ok." );
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_detect_invis( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_DETECT_INVIS) )
	{
		if (victim == ch){
			ch->println( "You can already see invisible." );
		}else{
			act("$N can already see invisible things.",ch,NULL,victim,TO_CHAR);
		}
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = level;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bitvector = AFF_DETECT_INVIS;
	affect_to_char( victim, &af );
	victim->println( "Your eyes tingle." );
	if ( ch != victim ){
		ch->println( "Ok." );
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_detect_magic( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_DETECT_MAGIC) )
	{
		if (victim == ch){
			ch->println( "You can already sense magical auras." );
		}else{
			act("$N can already detect magic.",ch,NULL,victim,TO_CHAR);
		}
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = level;
	af.modifier  = 0;
	af.location  = APPLY_NONE;
	af.bitvector = AFF_DETECT_MAGIC;
	affect_to_char( victim, &af );
	victim->println( "Your eyes tingle." );
	if ( ch != victim ){
		ch->println( "Ok." );
	}
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_detect_poison( int , int , char_data *ch, void *vo,int )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;

	if ( obj->item_type == ITEM_DRINK_CON || obj->item_type == ITEM_FOOD )
	{
		if ( obj->value[3] != 0 ){
			ch->println( "You smell poisonous fumes." );
		}else{
			ch->println( "It looks delicious." );
		}
	}else{
		ch->println( "It doesn't look poisoned." );
	}

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_dispel_evil( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam;
  
	if ( !IS_NPC(ch) && IS_EVIL(ch) )
		victim = ch;
  
	if ( IS_GOOD(victim) )
	{
		act( "$N appears to be protected.", ch, NULL, victim, TO_ROOM );
		return FULL_MANA;
	}

	if ( IS_NEUTRAL(victim) )
	{
		act( "$N does not seem to be affected.", ch, NULL, victim, TO_CHAR );
		return FULL_MANA;
	}

	if (victim->hit > (ch->level * 4))
		dam = dice( level, 4 );
	else
		dam = UMAX(victim->hit, dice(level,4));
    
	if ( saves_spell( level, victim,DAMTYPE(sn)) )
		dam /= 2;

	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
	return FULL_MANA;
}

/***************************************************************************/
SPRESULT spell_dispel_good( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	int dam;
 
	if ( !IS_NPC(ch) && IS_GOOD(ch) )
		victim = ch;
 
	if ( IS_EVIL(victim) )
	{
		act( "$N is protected by $S evil.", ch, NULL, victim, TO_ROOM );
		return FULL_MANA;
	}
 
	if ( IS_NEUTRAL(victim) )
	{
		act( "$N does not seem to be affected.", ch, NULL, victim, TO_CHAR );
		return FULL_MANA;
	}
 
	if (victim->hit > (ch->level * 4))
		dam = dice( level, 4 );
	else
		dam = UMAX(victim->hit, dice(level,4));
	if ( saves_spell( level, victim,DAMTYPE(sn)) )
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn) ,true);
	return FULL_MANA;
}

/***************************************************************************/
// modified for enhanced use
SPRESULT spell_dispel_magic( int sn , int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	bool found = false;

	if (saves_spell(level, victim,DAMTYPE(sn)))
	{
		victim->println( "You feel a brief tingling sensation." );
		ch->println( "You failed." );
		return FULL_MANA;
	}

	// begin running through the spells 
	found = check_dispel(level,victim,gsn_regeneration);
	found = check_dispel(level,victim,gsn_resist_poison);
	found = check_dispel(level,victim,gsn_poison_immunity);
	found = check_dispel(level,victim,gsn_prismatic_spray);
	found = check_dispel(level,victim,gsn_illusions_grandeur);
	found = check_dispel(level,victim,gsn_protection_fire);
	found = check_dispel(level,victim,gsn_protection_cold);
	found = check_dispel(level,victim,gsn_protection_acid);
	found = check_dispel(level,victim,gsn_protection_lightning);
	found = check_dispel(level,victim,gsn_holy_aura);
	found = check_dispel(level,victim,gsn_unholy_aura);
	found = check_dispel(level,victim,gsn_true_sight);
	found = check_dispel(level,victim,gsn_barkskin);
	found = check_dispel(level,victim,gsn_magic_resistance);
	found = check_dispel(level,victim,gsn_fire_shield);
	found = check_dispel(level,victim,gsn_chill_shield);
	found = check_dispel(level,victim,gsn_animal_essence);
	found = check_dispel(level,victim,gsn_armor);
	found = check_dispel(level,victim,gsn_bless);

	if (check_dispel(level,victim,gsn_blindness ))
	{
		found = true;
		act("$n is no longer blinded.",victim,NULL,NULL,TO_ROOM);
	}
	if (check_dispel(level,victim,gsn_calm))
	{
		found = true;
		act("$n no longer looks so peaceful...",victim,NULL,NULL,TO_ROOM);
	}
	if (check_dispel(level,victim, gsn_change_sex ))
	{
		found = true;
		act("$n looks more like $mself again.",victim,NULL,NULL,TO_ROOM);
	}
	if (check_dispel(level,victim,gsn_charm_person))
	{
		found = true;
		act("$n regains $s free will.",victim,NULL,NULL,TO_ROOM);
	}
	if (check_dispel(level,victim,gsn_chill_touch))
	{
		found = true;
		act("$n looks warmer.",victim,NULL,NULL,TO_ROOM);
	}
	if (check_dispel(level,victim, gsn_curse ))
		found = true;
	if (check_dispel(level,victim,gsn_detect_evil))
		found = true;
	if (check_dispel(level,victim,gsn_detect_scry ))
		found = true;
	if (check_dispel(level,victim,gsn_detect_good))
		found = true;
	if (check_dispel(level,victim,gsn_detect_hidden))
		found = true;
    if (check_dispel(level,victim,gsn_detect_invis))
        found = true;
	if (check_dispel(level,victim,gsn_detect_magic))
		found = true;
	if (check_dispel(level,victim, gsn_faerie_fire ))
	{
		act("$n's outline fades.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_fly ))
	{
		act("$n falls to the ground!",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_frenzy ))
	{
		act("$n no longer looks so wild.",victim,NULL,NULL,TO_ROOM);;
		found = true;
	}
	if (check_dispel(level,victim, gsn_giant_strength ))
	{
		act("$n no longer looks so mighty.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_haste ))
	{
		act("$n is no longer moving so quickly.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim,gsn_infravision))
		found = true;
	if (check_dispel(level,victim, gsn_invisibility ))
	{
		act("$n fades into existance.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim,gsn_mass_invis))
	{
		act("$n fades into existance.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim,gsn_pass_door))
		found = true;
	if (check_dispel(level,victim,gsn_protection_evil))
		found = true;
	if (check_dispel(level,victim,gsn_protection_good))
		found = true;
	if (check_dispel(level,victim,gsn_rage))
		found = true;
	if (check_dispel(level,victim, gsn_sanctuary ))
	{
		act("The white aura around $n's body vanishes.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
    if (IS_AFFECTED(victim,AFF_SANCTUARY) 
	&& !saves_dispel(level, victim->level,-1)
	&& !is_affected(victim, gsn_sanctuary ))
	{
		REMOVE_BIT(victim->affected_by,AFF_SANCTUARY);
		act("The white aura around $n's body vanishes.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim,gsn_shield))
	{
		act("The shield protecting $n vanishes.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim,gsn_sleep))
		found = true;
	if (check_dispel(level,victim, gsn_slow ))
	{
		act("$n is no longer moving so slowly.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim,gsn_stone_skin))
	{
		act("$n's skin regains its normal texture.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim, gsn_weaken ))
	{
		act("$n looks stronger.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}
	if (check_dispel(level,victim,gsn_wind_shield))
	{
		act("The wind around $n's body dies down.",victim,NULL,NULL,TO_ROOM);
		found = true;
	}

    if (found)
        ch->println( "Ok." );
    else {
        ch->println("Spell failed.");
		return HALF_MANA;
	}
	return FULL_MANA;
}

/***************************************************************************/
SPRESULT spell_earthquake( int sn, int level, char_data *ch, void *,int  )
{
	char_data *vch;
	char_data *vch_next;

	ch->println( "The earth trembles beneath your feet!" );
	act( "$n makes the earth tremble and shiver.", ch, NULL, NULL, TO_ROOM );

    for ( vch = ch->in_room->people; vch; vch = vch_next )
	{
        vch_next=vch->next_in_room;
		if ( vch->in_room == NULL )
			continue;
		if ( vch->in_room == ch->in_room )
		{
			if ( vch != ch && !is_safe_spell(ch,vch,true))
			if (IS_AFFECTED(vch,AFF_FLYING))
				damage_spell(ch,vch,0,sn,DAMTYPE(sn),true);
			else
				damage_spell( ch,vch,level + dice(2, 8), sn, DAMTYPE(sn),true);
			continue;
		}

		if ( vch->in_room->area == ch->in_room->area ){
			vch->println( "The earth trembles and shivers." );
		}
	}
    return FULL_MANA;
}

/***************************************************************************/
SPRESULT spell_enchant_armor( int sn, int level, char_data *ch, void *vo,int )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA *paf; 
	int result, fail;
	int added;
	bool ac_found = false;

    /* checks if enchant can be done */
	if (obj->item_type != ITEM_ARMOR)
	{
		ch->printf( "That isn't an armor.\r\n" );
		return NO_MANA;
	}
	if (obj->wear_loc != -1)
	{
		ch->printf( "The item must be carried to be enchanted.\r\n" );
		return NO_MANA;
	}

	fail = 25;   // base 25% chance of failure 

	// find the current bonuses - affect success 
	for (paf=OBJECT_AFFECTS(obj); paf; paf=paf->next )
	{
		if ( paf->location == APPLY_AC )
		{
			if (paf->duration == -1) // can't add to a perm armour enchant
			{
				ch->printf( "%s starts to pulsate then it dissolves before your eyes!!!\r\n",
					format_obj_to_char(obj, ch, true));
				extract_obj(obj);
				return FULL_MANA;
			}
			ac_found = true;
			fail += 5 * paf->modifier * paf->modifier;
		}
		else
		{
			fail += 20;
		}
	}

	// apply other modifiers 
	fail -= level;
	if (IS_OBJ_STAT(obj,OBJEXTRA_BLESS))
		fail -= 15;
	if (IS_OBJ_STAT(obj,OBJEXTRA_GLOW))
		fail -= 5;

	fail = URANGE(5,fail,85);
	result = number_percent();

	// the moment of truth 
	if (result < (fail / 5))  // item destroyed 
	{
		act("$p flares blindingly... and evaporates!",ch,obj,NULL,TO_CHAR);
		act("$p flares blindingly... and evaporates!",ch,obj,NULL,TO_ROOM);
		extract_obj(obj);
		return FULL_MANA;
	}

	if (result < (fail / 3)) // item disenchanted
	{
		AFFECT_DATA *paf_next;

		act("$p glows brightly, then fades...oops.",ch,obj,NULL,TO_CHAR);
		act("$p glows brightly, then fades.",ch,obj,NULL,TO_ROOM);

        // free all affects 
        for (paf = obj->affected; paf; paf = paf_next)
        {
            paf_next = paf->next; 
            free_affect(paf);
        }
        obj->affected = NULL;
        obj->no_affects = true; // flag the object as no_affects so 
								// the olc template's affects arent used.
        // clear all flags 
        obj->extra_flags = 0;
		return FULL_MANA;
	}

	if ( result <= fail )  // failed, no bad result 
	{
		ch->printf( "Nothing seemed to happen.\r\n" );
		return FULL_MANA;
	}

	// **** ALL SUCCESSFUL ENCHANTS BELOW HERE ****
	// now setup all the enchants:
	// - if it enchants, weren't stored on the object, copy the enchants
    //   from the object vnums enchants.   
	affects_from_template_to_obj(obj); 

	if (result <= (90 - level/5))  // success! 
	{
		act("$p shimmers with a golden aura.",ch,obj,NULL,TO_CHAR);
		act("$p shimmers with a golden aura.",ch,obj,NULL,TO_ROOM);
		SET_BIT(obj->extra_flags, OBJEXTRA_MAGIC);
		added = -1;
	}else{  // exceptional enchant
		act("$p glows a brillant gold!",ch,obj,NULL,TO_CHAR);
		act("$p glows a brillant gold!",ch,obj,NULL,TO_ROOM);
		SET_BIT(obj->extra_flags,OBJEXTRA_MAGIC);
		SET_BIT(obj->extra_flags,OBJEXTRA_GLOW);
		added = -2;
	}
		
	// now add the new armour enchantment 
	if (ac_found){ // if there is already an enchant on it 
		for ( paf = obj->affected; paf != NULL; paf = paf->next)
		{
			if ( paf->location == APPLY_AC)
			{
				paf->type = sn;
				paf->modifier += added;
				if (ch->level>paf->level)
					paf->level = ch->level;
			}
		}
	}else{ // add a new armour affect at the head of the affected list
		paf				= new_affect();
		paf->where		= WHERE_OBJEXTRA;
        paf->type		= sn;
        paf->level		= ch->level;
        paf->duration	= level*20;
        paf->location	= APPLY_AC;
        paf->modifier	= added;
        paf->bitvector	= 0;
        paf->next		= obj->affected;
        obj->affected	= paf;
	}
	return FULL_MANA;
}

/***************************************************************************/
SPRESULT spell_enchant_weapon(int sn,int level, char_data *ch, void *vo,int )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA *paf; 
	int result, fail;
	int added;
	bool hit_found = false, dam_found = false;

	// do standard checks - if spell can be cast 
	if (obj->item_type != ITEM_WEAPON)
	{
		ch->printf( "That isn't a weapon.\r\n" );
		return NO_MANA;
    }
    if (obj->wear_loc != -1)
    {
        ch->printf( "The item must be carried to be enchanted.\r\n" );
        return NO_MANA;
    }

    fail = 25;	// base 25% chance of failure 

    // find the current bonuses - affect success 
	for (paf=OBJECT_AFFECTS(obj); paf; paf=paf->next )
    {
        if ( paf->location == APPLY_HITROLL ){
            hit_found = true;
            fail += 2 * paf->modifier * paf->modifier;
            if (paf->duration == -1) // can't add to a perm weapon enchant 
            {
                ch->printf( "%s starts to pulsate then it dissolves before your eyes!!!",
                    capitalize(format_obj_to_char(obj, ch, true)));
                extract_obj(obj);
                return FULL_MANA;
            }
        }else if (paf->location == APPLY_DAMROLL ){
            dam_found = true;
            fail += 2 * paf->modifier * paf->modifier;
            if (paf->duration == -1) // can't add to a perm weapon enchant 
            {
                ch->printf( "%s starts to pulsate then it dissolves before your eyes!!!\r\n",
                    format_obj_to_char(obj, ch, true));
                extract_obj(obj);
                return FULL_MANA;
            }
        }else{
            fail += 20;
        }
    }

    // apply other modifiers 
    fail -= 3 * level/2;
    if (IS_OBJ_STAT(obj,OBJEXTRA_BLESS)){
        fail -= 15;
    }if (IS_OBJ_STAT(obj,OBJEXTRA_GLOW)){
        fail -= 5;
	}

    fail = URANGE(5,fail,95);
    result = number_percent();

    // the moment of truth 
    if (result < (fail / 5)){  // item destroyed 
        act("$p shivers violently and explodes!",ch,obj,NULL,TO_CHAR);
        act("$p shivers violently and explodes!",ch,obj,NULL,TO_ROOM);
        extract_obj(obj);
        return FULL_MANA;
    }

    if (result < (fail / 2)){ // item disenchanted 
		AFFECT_DATA *paf_next;

		act("$p glows brightly, then fades...oops.",ch,obj,NULL,TO_CHAR);
		act("$p glows brightly, then fades.",ch,obj,NULL,TO_ROOM);

        // free all affects 
        for (paf = obj->affected; paf; paf = paf_next)
        {
            paf_next = paf->next; 
            free_affect(paf);
        }
        obj->affected = NULL;
        obj->no_affects = true; // flag the object as no_affects so 
								// the olc template's affects arent used.
        // clear all flags 
        obj->extra_flags = 0;
		return FULL_MANA;
	}

    if ( result <= fail )  // failed, no bad result
    {
        ch->printf( "Nothing seemed to happen.\r\n" );
        return FULL_MANA;
    }

    // **** ALL SUCCESSFUL ENCHANTS BELOW HERE ****
	// now setup all the enchants:
	// - if it enchants, weren't stored on the object, copy the enchants
    //   from the object vnums enchants.   
	affects_from_template_to_obj(obj); 

    if (result <= (100 - level/5)){  // success! 
        act("$p glows blue.",ch,obj,NULL,TO_CHAR);
        act("$p glows blue.",ch,obj,NULL,TO_ROOM);
        SET_BIT(obj->extra_flags, OBJEXTRA_MAGIC);
        added = 1;
    }else{  // exceptional enchant     
        act("$p glows a brillant blue!",ch,obj,NULL,TO_CHAR);
        act("$p glows a brillant blue!",ch,obj,NULL,TO_ROOM);
        SET_BIT(obj->extra_flags,OBJEXTRA_MAGIC);
        SET_BIT(obj->extra_flags,OBJEXTRA_GLOW);
        added = 2;
    }
		
    // now add the enchantments 
    if (dam_found){
        for ( paf = obj->affected; paf != NULL; paf = paf->next)
        {
            if ( paf->location == APPLY_DAMROLL)
            {
                paf->type = sn;
                paf->modifier += added;
                if (ch->level>paf->level) // up the level if caster is higher
                    paf->level = ch->level;
                if (paf->modifier > 4 && (number_range(1,100)<95))
                    SET_BIT(obj->extra_flags,OBJEXTRA_HUM);
            }
        }
    }else{ // add a new damroll affect 
        paf = new_affect();
        paf->where      = WHERE_OBJEXTRA;
        paf->type       = sn;
        paf->level      = ch->level;
        paf->duration   = level * 20;
        paf->location   = APPLY_DAMROLL;
        paf->modifier   = added;
        paf->bitvector  = 0;
        paf->next       = obj->affected;
        obj->affected   = paf;
    }

    if (hit_found){
        for ( paf = obj->affected; paf != NULL; paf = paf->next)
        {
            if ( paf->location == APPLY_HITROLL)
            {
                paf->type = sn;
                paf->modifier += added;
                paf->level = UMAX(paf->level,level)/2;
                if (paf->modifier > 4){
					SET_BIT(obj->extra_flags,OBJEXTRA_HUM);
				}
            }
        }
    }else{ // add a new affect 
        paf = new_affect();
        paf->type       = sn;
        paf->level      = ch->level;
        paf->duration   = level * 20;
        paf->location   = APPLY_HITROLL;
        paf->modifier   = added;
        paf->bitvector  = 0;
        paf->next       = obj->affected;
        obj->affected   = paf;
    }
	return FULL_MANA;
}

/**************************************************************************/
// Drain XP, MANA, HP from victim -  Caster gains HP.
SPRESULT spell_energy_drain( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	int dam;
	int temp_hps;

	if ( saves_spell( level, victim,DAMTYPE(sn)))
	{
		victim->printf( "You feel a momentary chill.\r\n" );
		ch->printf( "Your spell doesnt appear to have much affect.\r\n" );
		return FULL_MANA;
	}

	if ( victim->level <= 2 )
		dam		 = ch->hit + 1;
    else
		dam		 = dice(1, level/4);

	if (damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true))
	{	
		gain_exp( victim, 0 - number_range( level/2, level) );
		victim->mana	/= 2;
		victim->move	/= 2;

		victim->printf( "You feel your life slipping away!\r\n" );
		temp_hps=victim->hit;

		if(victim->hit<-10) 
			victim->hit=-10;

		// give caster some HP back
		if ((temp_hps-victim->hit)>0)
		{
			ch->hit+= (temp_hps-victim->hit);
			ch->printf( "Wow....what a rush!\r\n" );
		}
		else
		{
			ch->printf( "They look drained.\r\n" );
		}
	}

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_fireball( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	int dam;

	dam		= dice(level, 6)+10;
	if ( saves_spell( level, victim, DAMTYPE(sn)))
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_fireproof(int sn, int level, char_data *ch, void *vo,int )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA af;

	if (IS_OBJ_STAT(obj,OBJEXTRA_BURN_PROOF))
	{
		act("$p is already protected from burning.",ch,obj,NULL,TO_CHAR);
		return HALF_MANA;
	}

	af.where     = WHERE_OBJEXTRA;
	af.type      = sn;
	af.level     = level;
	af.duration  = number_fuzzy(level / 4);
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = OBJEXTRA_BURN_PROOF;

	affect_to_obj(obj,&af);

	act("You protect $p from fire.",ch,obj,NULL,TO_CHAR);
	act("$p is surrounded by a protective aura.",ch,obj,NULL,TO_ROOM);

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_flamestrike( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam;

	dam = dice(6 + level / 2, 8);
	if ( saves_spell( level, victim,DAMTYPE(sn)))
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_frostball ( int sn, int level, char_data *ch, void *vo, int )
{
	char_data	*victim = (char_data *) vo;
	int			dam;

	dam = dice( level, 9 );
	if ( saves_spell( level, victim, DAMTYPE(sn)))
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn), true );
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_faerie_fire( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_FAERIE_FIRE) ) {
		ch->printf( "They are already aglow.\r\n" );
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = level/3 + number_fuzzy(3)*3;
	af.location  = APPLY_AC;
	af.modifier  = 2 * level;
	af.bitvector = AFF_FAERIE_FIRE;
	affect_to_char( victim, &af );
	victim->printf( "You are surrounded by a pink outline.\r\n" );
	act( "$n is surrounded by a pink outline.", victim, NULL, NULL, TO_ROOM );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_faerie_fog( int sn, int level, char_data *ch, void *,int )
{
	char_data *ich;
	long tempflag;
	bool changed= false;

	act( "$n conjures a cloud of purple smoke.", ch, NULL, NULL, TO_ROOM );
	ch->printf( "You conjure a cloud of purple smoke.\r\n" );

	for ( ich = ch->in_room->people; ich != NULL; ich = ich->next_in_room )
	{
		if (INVIS_LEVEL(ich)> 0)
			continue;

		if ( ich == ch || saves_spell( level, ich,DAMTYPE(sn)) )
			continue;

		tempflag=ich->affected_by;

		if (is_affected( ich, gsn_invisibility ))
		{
			affect_strip ( ich, gsn_invisibility );
			changed = true;	
		}
		if (is_affected( ich, gsn_mass_invis))
		{
			affect_strip ( ich, gsn_mass_invis);
			changed = true;
		}
		if (is_affected( ich, gsn_sneak))
		{
			affect_strip ( ich, gsn_sneak);
			changed = true;
		}
		
		if (IS_AFFECTED2( ich, AFF2_VANISH))
		{
			affect_strip ( ich, gsn_vanish);
			changed = true;
		}

		REMOVE_BIT( ich->affected_by,	AFF_HIDE	);
		REMOVE_BIT( ich->affected_by,	AFF_INVISIBLE	);
		REMOVE_BIT( ich->affected_by,	AFF_SNEAK	);
		REMOVE_BIT( ich->affected_by2,	AFF2_VANISH );

		if (ich->affected_by!=tempflag || changed)
		{
			act( "$n is revealed!", ich, NULL, NULL, TO_ROOM );
			ich->printf( "You are revealed!\r\n" );
		}
	}

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_floating_disc( int , int level,char_data *ch,void *,int )
{
	OBJ_DATA *disc, *floating;

	floating = get_eq_char(ch,WEAR_FLOAT);

	if (floating != NULL && IS_OBJ_STAT(floating,OBJEXTRA_NOREMOVE))
	{
		act("You can't remove $p.",ch,floating,NULL,TO_CHAR);
		return NO_MANA;
	}

	disc = create_object(get_obj_index(OBJ_VNUM_DISC));
	disc->value[0]	= ch->level * 10; // 10 lbs per level capacity 
	disc->value[3]	= ch->level * 5; // 5 lbs per level max per item 
	disc->timer		= ch->level * 2 - number_range(0,level / 2); 

	act("$n has created a floating black disc.",ch,NULL,NULL,TO_ROOM);
	ch->printf( "You create a floating disc.\r\n" );
	obj_to_char(disc,ch);
	wear_obj(ch,disc,true, false);

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_fly( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_SET( ch->in_room->room_flags, ROOM_NOFLY )) {
		ch->println( "The powerful winds prevent you from taking to air." );
		return NO_MANA;
	}
	
	if ( IS_AFFECTED(victim, AFF_FLYING) )
	{
		if (victim == ch)
			ch->printf( "You are already airborne.\r\n" );
		else
			act("$N doesn't need your help to fly.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = level + 3;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_FLYING;
	affect_to_char( victim, &af );
	victim->println( "Your feet rise off the ground." );
	act( "$n's feet rise off the ground.", victim, NULL, NULL, TO_ROOM );

	return FULL_MANA;
}

/**************************************************************************/
// RT clerical berserking spell 
SPRESULT spell_frenzy(int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if (is_affected(victim,sn) || IS_AFFECTED(victim,AFF_BERSERK))
	{
		if (victim == ch)
			ch->printf( "You are already in a frenzy.\r\n" );
		else
			act("$N is already in a frenzy.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	if (is_affected(victim,gsn_calm))
	{
		if (victim == ch)
			ch->printf( "Why don't you just relax for a while?\r\n" );
		else
			act("$N doesn't look like $e wants to fight anymore.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	if ((IS_GOOD(ch) && !IS_GOOD(victim)) ||
		(IS_NEUTRAL(ch) && !IS_NEUTRAL(victim)) ||
		(IS_EVIL(ch) && !IS_EVIL(victim)))
	{
		act("Your god doesn't seem to like $N",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type 	 = sn;
	af.level	 = level;
	af.duration	 = level / 3;
	af.modifier  = level / 6;
	af.bitvector = 0;

	af.location  = APPLY_HITROLL;
	affect_to_char(victim,&af);

	af.location  = APPLY_DAMROLL;
	affect_to_char(victim,&af);

	af.modifier  = 10 * (level / 12);
	af.location  = APPLY_AC;
	affect_to_char(victim,&af);

	victim->printf( "You are filled with holy wrath!\r\n" );
	act("$n gets a wild look in $s eyes!",victim,NULL,NULL,TO_ROOM);

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_gate( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	bool gate_pet;

	if (( victim = get_char_icworld( ch, target_name ) ) == NULL
	 ||   victim == ch
	 ||   victim->in_room == NULL
	 ||   !can_see_room(ch,victim->in_room)
	 ||   IS_SET(victim->in_room->room_flags, ROOM_SAFE)
	 ||   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)
	 ||   IS_SET(victim->in_room->room_flags, ROOM_NOSCRY)
	 ||	  IS_SET(victim->in_room->room_flags, ROOM_ANTIMAGIC)
	 ||   IS_SET(victim->in_room->area->area_flags, AREA_NOSCRY)
	 ||   IS_SET(victim->in_room->area->area_flags, AREA_NOGATEINTO)	 
	 ||   IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
	 ||   victim->level >= level + 3
	 ||   (!IS_NPC(victim) && victim->level >= LEVEL_IMMORTAL)  // NOT trust
	 ||   (IS_NPC(victim) && IS_SET(victim->imm_flags,IMM_SUMMON))
	 ||   (IS_NPC(victim) && saves_spell( level, victim,DAMTYPE(sn)))
	 ||   (!IS_NPC(victim) && saves_spell( level, victim, DAMTYPE(sn))))
	 {
		  ch->println( "You failed." );
		  return FULL_MANA;
	 }

	if ( ch->in_room->area->continent != victim->in_room->area->continent )
	{
		ch->println( "The spell cannot span such a great distance." );
		return FULL_MANA;
	}

	if(ch->pet && ch->in_room == ch->pet->in_room){
		gate_pet = true;
	}else{
		gate_pet = false;
	}

	act("$n steps through a gate and vanishes.",ch,NULL,NULL,TO_ROOM);
	ch->printf( "You step through a gate and vanish.\r\n" );
	char_from_room(ch);
	char_to_room(ch,victim->in_room);

	act("$n has arrived through a gate.",ch,NULL,NULL,TO_ROOM);
	do_look(ch,"auto");
	 /* 
     * If someone is following the char, these triggers get activated
     * for the followers before the char, but it's safer this way...
     */
	if ( IS_NPC( ch ) && HAS_TRIGGER( ch, TRIG_ENTRY ) ){
		mp_percent_trigger( ch, NULL, NULL, NULL, TRIG_ENTRY );
	}

	if ( !IS_NPC( ch ) ){
		mp_greet_trigger( ch );
	}

	if (gate_pet)
	{
		act("$n steps through a gate and vanishes.",ch->pet,NULL,NULL,TO_ROOM);
		ch->pet->printf( "You step through a gate and vanish.\r\n" );
		char_from_room(ch->pet);
		char_to_room(ch->pet,victim->in_room);
		act("$n has arrived through a gate.",ch->pet,NULL,NULL,TO_ROOM);
		do_look(ch->pet,"auto");
	 
		 /* 
		 * If someone is following the char, these triggers get activated
		 * for the followers before the char, but it's safer this way...
		 */
		if (ch->pet)
		{
			if ( IS_NPC( ch->pet) && HAS_TRIGGER( ch->pet, TRIG_ENTRY ) ){
				mp_percent_trigger( ch->pet, NULL, NULL, NULL, TRIG_ENTRY );
			}

			if ( !IS_NPC( ch->pet) ){
				mp_greet_trigger( ch->pet);
			}
		}
	}

    return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_giant_strength(int sn,int level,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;
	bool half = false;

	if(check_strength(level, ch, victim, half))
		return FULL_MANA;
	if(half)
		return HALF_MANA;

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= level;
	af.location		= APPLY_ST;
	af.modifier		= 1 + level/5;
	af.bitvector	= 0;
	affect_to_char( victim, &af );
	victim->printf( "Your muscles surge with heightened power!\r\n" );
	act("$n's muscles surge with heightened power.",victim,NULL,NULL,TO_ROOM);
	return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_harm( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam;

	dam = UMAX(  20, victim->hit - dice(1,4) );
	if ( saves_spell( level, victim,DAMTYPE(sn)) )
		dam = UMIN( 50, dam / 2 );

	dam = UMIN( 100, dam );

	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
	return FULL_MANA;
}

/**************************************************************************/
// RT haste spell
SPRESULT spell_haste( int sn, int level, char_data *ch, void *vo,int)
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;
	
	if ( is_affected( victim, sn )
		|| IS_AFFECTED(victim,AFF_HASTE)
		|| IS_SET(victim->off_flags,OFF_FAST))
	{
		if (victim == ch)
			ch->printf( "You can't move any faster!\r\n" );
		else
			act("$N is already moving as fast as $E can.",ch,NULL,victim,TO_CHAR);
        return HALF_MANA;
	}
	
	if (IS_AFFECTED(victim,AFF_SLOW))
	{
		if (!check_dispel(level,victim, gsn_slow ))
		{
			if (victim != ch)
				ch->println("Spell failed.");
			victim->printf( "You feel momentarily faster.\r\n" );
			return FULL_MANA;
		}
		act("$n is moving less slowly.",victim,NULL,NULL,TO_ROOM);
		return FULL_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;

	if (victim == ch){
		af.duration  = level/2;
	}else{
		af.duration  = level/4;
	}

	af.location  = APPLY_QU;
	af.modifier  = 1 + level/5;
	af.bitvector = AFF_HASTE;
	affect_to_char( victim, &af );
	victim->printf( "You feel yourself moving more quickly.\r\n" );
	act("$n is moving more quickly.",victim,NULL,NULL,TO_ROOM);

	if ( ch != victim )
		ch->println( "Ok." );

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_heal( int , int , char_data *ch, void *vo,int)
{
	char_data *victim = (char_data *) vo;

	victim->hit = UMIN( victim->hit + game_settings->max_hp_from_heal_spell, victim->max_hit );
	update_pos( victim );
	victim->printf( "A warm feeling fills your body.\r\n" );

	if ( ch != victim )
		ch->println( "Ok." );
	return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_heat_metal( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	OBJ_DATA *obj_lose, *obj_next;
	int dam = 0;
	bool fail = true;
 
	if (!saves_spell(level + 2,victim,DAMTYPE(sn)) 
	&&  !IS_SET(victim->imm_flags,IMM_FIRE))
	{
		for ( obj_lose = victim->carrying; obj_lose != NULL; obj_lose = obj_next)
		{
			obj_next = obj_lose->next_content;

			if ( number_range(1,2 * level) > obj_lose->level
			&&   !saves_spell(level,victim,DAMTYPE(sn))
			&&   !IS_OBJ_STAT(obj_lose,OBJEXTRA_NONMETAL)
			&&   !IS_OBJ_STAT(obj_lose,OBJEXTRA_BURN_PROOF))
			{
				switch ( obj_lose->item_type )
				{
					case ITEM_ARMOR:
						if (obj_lose->wear_loc != -1) /* remove the item */
						{
							if (can_drop_obj(victim,obj_lose)
							&& (obj_lose->weight / 10) < number_range(1,ch->modifiers[STAT_QU])
							&&  remove_obj( victim, obj_lose->wear_loc, true ))
							{
								act("$n yelps and throws $p to the ground!",victim,obj_lose,NULL,TO_ROOM);
								act("You remove and drop $p before it burns you.",victim,obj_lose,NULL,TO_CHAR);
								dam += (number_range(1,obj_lose->level) / 3);
								obj_from_char(obj_lose);
								obj_to_room(obj_lose, victim->in_room);
								fail = false;
							}
							else /* stuck on the body! ouch! */
							{
								act("Your skin is seared by $p!",victim,obj_lose,NULL,TO_CHAR);
								dam += (number_range(1,obj_lose->level));
								fail = false;
							}
						}
						else /* drop it if we can */
						{
							if (can_drop_obj(victim,obj_lose))
							{
								act("$n yelps and throws $p to the ground!",victim,obj_lose,NULL,TO_ROOM);
								act("You and drop $p before it burns you.",victim,obj_lose,NULL,TO_CHAR);
								dam += (number_range(1,obj_lose->level) / 6);
								obj_from_char(obj_lose);
								obj_to_room(obj_lose, victim->in_room);
								fail = false;
							}
							else /* cannot drop */
							{
								act("Your skin is seared by $p!",victim,obj_lose,NULL,TO_CHAR);
								dam += (number_range(1,obj_lose->level) / 2);
								fail = false;
							}
						}
						break;
					case ITEM_WEAPON:
						if (obj_lose->wear_loc != -1) /* try to drop it */
						{
							if (IS_WEAPON_STAT(obj_lose,WEAPON_FLAMING))
								continue;

							if (can_drop_obj(victim,obj_lose) 
							&&  remove_obj(victim,obj_lose->wear_loc,true))
							{
								act("$n is burned by $p, and throws it to the ground.",victim,obj_lose,NULL,TO_ROOM);
								victim->printf( "You throw your red-hot weapon to the ground!\r\n" );
								dam += 1;
								obj_from_char(obj_lose);
								obj_to_room(obj_lose,victim->in_room);
								fail = false;
							}
							else /* YOWCH! */
							{
								victim->printf( "Your weapon sears your flesh!\r\n" );
								dam += number_range(1,obj_lose->level);
								fail = false;
							}
						}
						else /* drop it if we can */
						{
							if (can_drop_obj(victim,obj_lose))
							{
								act("$n throws a burning hot $p to the ground!",victim,obj_lose,NULL,TO_ROOM);
								act("You and drop $p before it burns you.",victim,obj_lose,NULL,TO_CHAR);
								dam += (number_range(1,obj_lose->level) / 6);
								obj_from_char(obj_lose);
								obj_to_room(obj_lose, victim->in_room);
								fail = false;
							}
							else /* cannot drop */
							{
								act("Your skin is seared by $p!",victim,obj_lose,NULL,TO_CHAR);
								dam += (number_range(1,obj_lose->level) / 2);
								fail = false;
							}
						}
						break;
					}
				}
			}
		} 

		if (fail)
	    {
			ch->printf( "Your spell had no effect.\r\n" );
			victim->printf( "You feel momentarily warmer.\r\n" );
		}
		else /* damage! */
		{
		if (saves_spell(level,victim,DAMTYPE(sn)))
			dam = 2 * dam / 3;
		damage_spell(ch,victim,dam,sn,DAMTYPE(sn),true);
    }
	return FULL_MANA;
}

/**************************************************************************/
// RT really nasty high-level attack spell
SPRESULT spell_holy_word(int sn, int level, char_data *ch, void *,int )
{
	char_data *vch;
	char_data *vch_next;
	int dam;
	int bless_num, curse_num, frenzy_num;
   
	bless_num = gsn_bless;
	curse_num = gsn_curse; 
	frenzy_num = gsn_frenzy;

	act("$n utters a word of divine power!",ch,NULL,NULL,TO_ROOM);
	ch->printf( "You utter a word of divine power.\r\n" );

	for ( vch = ch->in_room->people; vch != NULL; vch = vch_next )
	{
		vch_next = vch->next_in_room;

		if ((IS_GOOD(ch) && IS_GOOD(vch))
		||  (IS_EVIL(ch) && IS_EVIL(vch))
		||  (IS_NEUTRAL(ch) && IS_NEUTRAL(vch)))
		{
			vch->printf( "You feel full more powerful.\r\n" );
			spell_frenzy(frenzy_num,level,ch,(void *) vch,TARGET_CHAR);
			spell_bless(bless_num,level,ch,(void *) vch,TARGET_CHAR);
		}

		else if ((IS_GOOD(ch) && IS_EVIL(vch))
			 || (IS_EVIL(ch) && IS_GOOD(vch)))
		{
			if (!is_safe_spell(ch,vch,true))
			{
				spell_curse(curse_num,level,ch,(void *) vch,TARGET_CHAR);
				vch->printf( "You are struck down!\r\n" );
				dam = dice(level,12);
				damage_spell(ch,vch,dam,sn,DAMTYPE(sn),true);
			}
		}
		else if (IS_NEUTRAL(vch))
		{
			if (!is_safe_spell(ch,vch,true))
			{
				spell_curse(curse_num,level/2,ch,(void *) vch,TARGET_CHAR);
				vch->printf( "You are struck down!\r\n" );
				dam = dice(level,10);
				damage_spell(ch,vch,dam,sn,DAMTYPE(sn),true);
			}
		}
	}

	ch->printf( "You feel drained.\r\n" );
	ch->move = 0;
	ch->hit /= 2;

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_identify( int, int, char_data *ch, void *vo, int  )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	AFFECT_DATA *paf=NULL;
	
	// Herb check instant crap out
	if ( obj->item_type == ITEM_HERB ) {
		ch->printf( "Your spell fizzles.\r\n" );
		return NO_MANA;
	}
	
	ch->printf( "Object '%s' is type %s,\r\n"
		"extra flags %s.\r\n"
		"extra2 flags %s.\r\n"		
		"Weight is %0.1f lbs, value is %d, level is %d.\r\n",
		obj->name,
		item_type_name( obj ),
		extra_bit_name( obj->extra_flags ),
		extra2_bit_name( obj->extra2_flags ),
		((double)obj->weight) / 10,
		obj->cost,
		obj->level );
	
	switch ( obj->item_type )
	{
	case ITEM_SCROLL:
	case ITEM_POTION:
	case ITEM_PILL:
		ch->printf( "Level %d spells of:", obj->value[0] );
		
		if ( obj->value[1] >= 0 && obj->value[1] < MAX_SKILL )
		{
			ch->printf( " '%s'", skill_table[obj->value[1]].name );
		}
		
		if ( obj->value[2] >= 0 && obj->value[2] < MAX_SKILL )
		{
			ch->printf( " '%s'", skill_table[obj->value[2]].name );
		}
		
		if ( obj->value[3] >= 0 && obj->value[3] < MAX_SKILL )
		{
			ch->printf( " '%s'", skill_table[obj->value[3]].name );
		}
		
		if (obj->value[4] >= 0 && obj->value[4] < MAX_SKILL)
		{
			ch->printf( " '%s'", skill_table[obj->value[4]].name );
		}
		ch->printf( ".\r\n" );
		break;
		
	case ITEM_WAND: 
	case ITEM_STAFF:
		ch->printf( "Has %d charges of level %d", obj->value[2], obj->value[0] );
		
		if ( obj->value[3] >= 0 && obj->value[3] < MAX_SKILL )
		{
			ch->printf( " '%s'", skill_table[obj->value[3]].name );
		}
		ch->printf( ".\r\n" );
		break;
		
	case ITEM_DRINK_CON:
		ch->printf( "It holds %s-colored %s.\r\n",
			liq_table[obj->value[2]].liq_color,
			liq_table[obj->value[2]].liq_name);
		break;
		
	case ITEM_CAULDRON:
	case ITEM_CONTAINER:
	case ITEM_FLASK:
	case ITEM_MORTAR:
		ch->printlnf( "Maximum combined weight: %d lbs, Capacity for an individual item: %d lbs.",
			obj->value[0], obj->value[3]);
		ch->printlnf( "Flags: %s.", cont_bit_name(obj->value[1]));
		if (obj->value[4] != 100){
			ch->printf( "Weight multiplier: %d%%\r\n", obj->value[4]);
		}
		break;
		
	case ITEM_WEAPON:
		{
			ch->printf( "Weapon type is %s.\r\n", get_weapontype( obj ));
			ch->printf("Damage is %dd%d (average %d).\r\n",
				obj->value[1],obj->value[2],
				(1 + obj->value[2]) * obj->value[1] / 2);
			if (obj->value[4])  // weapon flags 
			{
				ch->printf("Weapons flags: %s\r\n",weapon_bit_name(obj->value[4]));
			}
		}
		break;
		
	case ITEM_COMPONENT:
		if ( obj->value[0] < 0 )
		{
			ch->printf( "Has unlimited charges for the spell" );
		}
		else
		{
			ch->printf( "Can be used %d more times for the spell", obj->value[0] );
		}
		if ( obj->value[1] >= 0 && obj->value[1] < MAX_SKILL )
		{
			ch->printf( " '%s'", skill_table[obj->value[1]].name );
		}
		ch->printf( ".\r\n" );
		break;
		
	case ITEM_ARMOR:
		ch->printf( "Armor class is %d pierce, %d bash, %d slash, and %d vs. magic.\r\n",
			obj->value[0],	obj->value[1], obj->value[2], obj->value[3] );
		break;
	}

	for ( paf = OBJECT_AFFECTS(obj); paf; paf = paf->next )
	{

        if ( paf->location != APPLY_NONE && paf->modifier != 0 )
        {       
			if(paf->duration > -1){
				ch->printf( "Affects %s by %d for %d hour%s.%s\r\n",
					affect_loc_name( paf->location ), paf->modifier,
					paf->duration, paf->duration==1?"":"s",
					(paf->level>ch->level?"  (above your level)":""));
			}else{
				ch->printf( "Affects %s by %d.%s\r\n",
					affect_loc_name( paf->location ), paf->modifier,
					(paf->level>ch->level?"  (above your level)":""));
			}
			
			if (paf->bitvector)
			{
				ch->printlnf( "%s", to_affect_string( paf, obj->level ));
			}
		}
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_infravision( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_INFRARED) )
	{
		if (victim == ch)
			ch->printf( "You can already see in the dark.\r\n" );
		else
			act("$N already has infravision.\r\n",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	act( "$n's eyes glow red.\r\n", ch, NULL, NULL, TO_ROOM );

	af.where	 = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = 2 * level;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_INFRARED;
	affect_to_char( victim, &af );
	victim->printf( "Your eyes glow red.\r\n" );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_invisibility( int sn, int level, char_data *ch, void *vo,int target )
{
	char_data *victim;
	OBJ_DATA *obj;
	AFFECT_DATA af;

	/* object invisibility */
	if (target == TARGET_OBJ)
	{
		obj = (OBJ_DATA *) vo;

		if (IS_OBJ_STAT(obj,OBJEXTRA_INVIS))
		{
			act("$p is already invisible.",ch,obj,NULL,TO_CHAR);
			return HALF_MANA;
		}

		af.where	= WHERE_OBJEXTRA;
		af.type		= sn;
		af.level	= level;
		af.duration	= level + 12;
		af.location	= APPLY_NONE;
		af.modifier	= 0;
		af.bitvector	= OBJEXTRA_INVIS;
		affect_to_obj(obj,&af);

		act("$p fades out of sight.",ch,obj,NULL,TO_ALL);

		return FULL_MANA;
	}

	/* character invisibility */
	victim = (char_data *) vo;

	if ( IS_AFFECTED(victim, AFF_INVISIBLE )) {
		ch->printf( "They are already invisible.\r\n" );
		return HALF_MANA;
	}

	act( "$n fades out of existence.", victim, NULL, NULL, TO_ROOM );

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = level + 12;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_INVISIBLE;
	affect_to_char( victim, &af );
	victim->printf( "You fade out of existence.\r\n" );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_know_alignment(int ,int ,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;

	if(IS_ICIMMORTAL(victim)){
		ch->printf( "You really aren't sure about %s.\r\n", PERS(victim, ch));
		return DOUBLE_MANA;
	};
	
    switch (victim->tendency)
	{
		case -3: ch->printf( "%s is very chaotic ",			PERS(victim, ch));	break;
		case -2: ch->printf( "%s is fairly chaotic ",		PERS(victim, ch));	break;
		case -1: ch->printf( "%s has chaotic tendencies ",	PERS(victim, ch));	break;
		case  0: ch->printf( "%s is balanced ",				PERS(victim, ch));	break;
		case  1: ch->printf( "%s has lawful tendencies ",	PERS(victim, ch));	break;
		case  2: ch->printf( "%s is quite lawful ",			PERS(victim, ch));	break;
		case  3: ch->printf( "%s is extremely lawful ",		PERS(victim, ch));	break;
	}
	
	switch (victim->alliance)
	{
		case -3: ch->printf( "and is completely aligned with evil.\r\n");		break;
		case -2: ch->printf( "with many attachments to the dark forces.\r\n");	break;
		case -1: ch->printf( "and some alliance with evil.\r\n");				break;                
		case  0: ch->printf( "and indifferent.\r\n");							break;
		case  1: ch->printf( "with good tendencies.\r\n");						break;                
		case  2: ch->printf( "and has definite attachments to good.\r\n");		break;                
		case  3: ch->printf( "and a champion of the divine.\r\n");				break;               
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_lightning_bolt(int sn,int level,char_data *ch,void *vo,int)
{
	char_data *victim = (char_data *) vo;
	int dam;

	dam		= dice(level,6);
	if ( saves_spell( level, victim,DAMTYPE(sn)) )
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_locate_object( int , int level, char_data *ch, void *,int )
{
	char buf[MIL];
	BUFFER *buffer;
	OBJ_DATA *obj;
	OBJ_DATA *in_obj;
	bool found;
	int number = 0, max_found;

	found = false;
	number = 0;
	max_found = IS_IMMORTAL(ch) ? 200 : 2 * level;

	buffer = new_buf();
 
	for ( obj = object_list; obj != NULL; obj = obj->next )
	{
		if ( !can_see_obj( ch, obj ) || !is_name( target_name, obj->name ) 
		||   IS_OBJ_STAT(obj,OBJEXTRA_NOLOCATE) || number_percent() > 2 * level
		||   ch->level < obj->level)
		continue;

		found = true;
		number++;

		for ( in_obj = obj; in_obj->in_obj != NULL; in_obj = in_obj->in_obj );

		if ( in_obj->carried_by != NULL && can_see(ch,in_obj->carried_by))
		{
			sprintf( buf, "one is carried by %s\r\n", PERS(in_obj->carried_by, ch) );
		}
		else
		{
			if (IS_IMMORTAL(ch) && in_obj->in_room != NULL)
				sprintf( buf, "one is in %s [Room %d]\r\n",in_obj->in_room->name, in_obj->in_room->vnum);
			else
				sprintf( buf, "one is in %s\r\n", in_obj->in_room == NULL
					? "somewhere" : in_obj->in_room->name );
		}

		buf[0] = UPPER(buf[0]);
		add_buf(buffer,buf);

		if (number >= max_found)
			break;
	}

	if ( !found )
		ch->printf( "Nothing like that in heaven or earth.\r\n" );
	else
		ch->sendpage(buf_string(buffer));

	free_buf(buffer);

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_magic_missile( int sn, int level, char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam;

	dam		= level/4+2;
	if ( saves_spell( level, victim,DAMTYPE(sn)) )
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_mass_healing(int , int level, char_data *ch, void *, int )
{
	char_data *gch;
	int heal_num, refresh_num;

	heal_num = gsn_heal;
	refresh_num = gsn_refresh;

	for ( gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room )
	{
		if ((IS_NPC(ch) && IS_NPC(gch))
		|| (!IS_NPC(ch) && !IS_NPC(gch)))
		{
			spell_heal(heal_num,level,ch,(void *) gch,TARGET_CHAR);
			spell_refresh(refresh_num,level,ch,(void *) gch,TARGET_CHAR);  
		}
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_mass_invis( int sn, int level, char_data *ch, void *, int )
{
	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 );
		gch->printf( "You slowly fade out of existence.\r\n" );

		af.where     = WHERE_AFFECTS;
		af.type      = sn;
		af.level     = level/2;
		af.duration  = 24;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bitvector = AFF_INVISIBLE;
		affect_to_char( gch, &af );
	}
	ch->println( "Ok." );

    return FULL_MANA;
}



/**************************************************************************/
SPRESULT spell_null( int, int , char_data *ch, void *, int  )
{
	ch->printf( "That's not a spell!\r\n" );
	return NO_MANA;
}

/**************************************************************************/
SPRESULT spell_pass_door( int sn, int level, char_data *ch, void *vo, int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_PASS_DOOR) )
	{
		if (victim == ch)
			ch->printf( "You are already out of phase.\r\n" );
		else
			act("$N is already shifted out of phase.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	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 );
	victim->printf( "You turn translucent.\r\n" );
	return FULL_MANA;
}

/**************************************************************************/
// RT plague spell, very nasty 
SPRESULT spell_plague( int sn, int level, char_data *ch, void *vo, int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if (saves_spell(level,victim,DAMTYPE(sn))
	|| (IS_NPC(victim) && IS_SET(victim->act,ACT_UNDEAD))
	|| HAS_CLASSFLAG(victim, CLASSFLAG_PLAGUE_IMMUNITY))
	{
		if (ch == victim){
			ch->printf( "You feel momentarily ill, but it passes.\r\n" );
		}else{
			act("$N seems to be unaffected.",ch,NULL,victim,TO_CHAR);
		}
		return FULL_MANA;
	}

	if ( IS_ICIMMORTAL(victim)){
		act( "$n doesn't appear to be even slightly affected by your magic.", victim, NULL, NULL, TO_ROOM );
		return FULL_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level * 3/4;
	af.duration		= level;
	af.location		= APPLY_ST;
	af.modifier		= -10;
	af.bitvector	= AFF_PLAGUE;
	affect_join(victim,&af);
   
	victim->printf( "You scream in agony as plague sores erupt from your skin.\r\n" );
	act("$n screams in agony as plague sores erupt from $s skin.",victim,NULL,NULL,TO_ROOM);

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_poison( int sn, int level, char_data *ch, void *vo, int target )
{
	char_data *victim;
	OBJ_DATA *obj;
	AFFECT_DATA af;

	if (target == TARGET_OBJ)
	{
		obj = (OBJ_DATA *) vo;

		if (obj->item_type == ITEM_FOOD
		||  obj->item_type == ITEM_DRINK_CON)
		{
			obj->value[3] = 1;
			act("$p is infused with poisonous vapors.",ch,obj,NULL,TO_ALL);
			return FULL_MANA;
		}

		if (obj->item_type == ITEM_WEAPON)
		{
			if (IS_WEAPON_STAT(obj,WEAPON_FLAMING)
			||  IS_WEAPON_STAT(obj,WEAPON_FROST)
			||  IS_WEAPON_STAT(obj,WEAPON_VAMPIRIC)
			||  IS_WEAPON_STAT(obj,WEAPON_SHOCKING)
			||  IS_WEAPON_STAT(obj,WEAPON_HOLY))
			{
				act("You can't seem to envenom $p.",ch,obj,NULL,TO_CHAR);
				return FULL_MANA;
			}

			if (IS_WEAPON_STAT(obj,WEAPON_POISON))
			{
				act("$p is already envenomed.",ch,obj,NULL,TO_CHAR);
				return HALF_MANA;
			}

			af.where		= WHERE_WEAPON;
		    af.type			= sn;
		    af.level		= level / 2;
		    af.duration		= level/8;
			af.location		= APPLY_NONE;
		    af.modifier		= 0;
		    af.bitvector	= WEAPON_POISON;
		    affect_to_obj(obj,&af);

		    act("$p is coated with deadly venom.",ch,obj,NULL,TO_ALL);
		    return FULL_MANA;
		}

		act("You can't poison $p.",ch,obj,NULL,TO_CHAR);
		return NO_MANA;
	}

	victim = (char_data *) vo;

	if ( saves_spell( level, victim,DAMTYPE(sn))
	||   HAS_CLASSFLAG(victim, CLASSFLAG_POISON_IMMUNITY))
	{
		act("$n turns slightly green, but it passes.",victim,NULL,NULL,TO_ROOM);
		victim->printf( "You feel momentarily ill, but it passes.\r\n" );
		return FULL_MANA;
	}

	if ( IS_ICIMMORTAL(victim)){
		act( "$n doesn't appear to be even slightly affected by your magic.", victim, NULL, NULL, TO_ROOM );
		return FULL_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = (level/2);
	af.location  = APPLY_ST;
	af.modifier  = -4;
	af.bitvector = AFF_POISON;
	affect_join( victim, &af );
	victim->printf( "You feel very sick.\r\n" );
	act("$n looks very ill.",victim,NULL,NULL,TO_ROOM);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_protection_evil(int sn,int level,char_data *ch,void *vo, int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_PROTECT_EVIL)
	||   IS_AFFECTED(victim, AFF_PROTECT_GOOD))
	{
		if (victim == ch)
			ch->printf( "You are already protected.\r\n" );
		else
			act("$N is already protected.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = 24;
	af.location  = APPLY_SAVES;
	af.modifier  = -1;
	af.bitvector = AFF_PROTECT_EVIL;
	affect_to_char( victim, &af );
	victim->printf( "You feel holy and pure.\r\n" );
	if ( ch != victim )
		act("$N is protected from evil.",ch,NULL,victim,TO_CHAR);
	return FULL_MANA;
}
 
/**************************************************************************/
SPRESULT spell_protection_good(int sn,int level,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;
 
	if ( IS_AFFECTED(victim, AFF_PROTECT_GOOD)
	||   IS_AFFECTED(victim, AFF_PROTECT_EVIL))
	{
		if (victim == ch)
			ch->printf( "You are already protected.\r\n" );
		else
			act("$N is already protected.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = 24;
	af.location  = APPLY_SAVES;
	af.modifier  = -1;
	af.bitvector = AFF_PROTECT_GOOD;
	affect_to_char( victim, &af );
	victim->printf( "You feel aligned with darkness.\r\n" );
	if ( ch != victim )
		act("$N is protected from good.",ch,NULL,victim,TO_CHAR);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_ray_of_truth (int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam;

	if (IS_EVIL(ch) )
	{
		victim = ch;
		ch->printf( "The energy explodes inside you!\r\n" );
	}
 
	if (victim != ch)
	{
		act("$n raises $s hand, and a blinding ray of light shoots forth!",ch,NULL,NULL,TO_ROOM);
		ch->printf( "You raise your hand and a blinding ray of light shoots forth!\r\n" );
	}

	if (IS_GOOD(victim))
	{
		act("$n seems unharmed by the light.",victim,NULL,victim,TO_ROOM);
		victim->printf( "The light seems powerless to affect you.\r\n" );
		return FULL_MANA;
	}

	dam = dice( level, 12 ) / abs(4+victim->alliance);
	if ( saves_spell( level, victim,DAMTYPE(sn)) )
		dam /= 2;

	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
	spell_blindness(gsn_blindness, 3 * level / 4, ch, (void *) victim,TARGET_CHAR);

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_recharge( int , int level, char_data *ch, void *vo,int )
{
	OBJ_DATA *obj = (OBJ_DATA *) vo;
	int chance, percent;

	if (obj->item_type != ITEM_WAND
	&&  obj->item_type != ITEM_STAFF)
	{
		ch->printf( "That item does not carry charges.\r\n" );
		return NO_MANA;
    }

	if (obj->value[3] >= 3 * level / 2)
	{
		ch->printf( "Your skills are not great enough for that.\r\n" );
		return FULL_MANA;
	}

	if (obj->value[1] == 0)
	{
		ch->printf( "That item has already been recharged once.\r\n" );
		return HALF_MANA;
	}

	chance = 40 + 2 * level;
	chance -= obj->value[3]; /* harder to do high-level spells */
	chance -= (obj->value[1] - obj->value[2]) * (obj->value[1] - obj->value[2]);
    chance = UMAX(level/2,chance);

	percent = number_percent();

	if (percent < chance / 2)
	{
		act("$p glows softly.",ch,obj,NULL,TO_CHAR);
		act("$p glows softly.",ch,obj,NULL,TO_ROOM);
		obj->value[2] = UMAX(obj->value[1],obj->value[2]);
		obj->value[1] = 0;
		return FULL_MANA;
	}
	else if (percent <= chance)
	{
		int chargeback,chargemax;

		act("$p glows softly.",ch,obj,NULL,TO_CHAR);
		act("$p glows softly.",ch,obj,NULL,TO_CHAR);

		chargemax = obj->value[1] - obj->value[2];
	
		if (chargemax > 0)
			chargeback = UMAX(1,chargemax * percent / 100);
		else
			chargeback = 0;

		obj->value[2] += chargeback;
		obj->value[1] = 0;
		return FULL_MANA;
	}
	else if (percent <= UMIN(95, 3 * chance / 2))
	{
		ch->printf( "Nothing seemed to happen.\r\n" );
		if (obj->value[1] > 1)
			obj->value[1]--;
		return FULL_MANA;
	}
	else /* whoops! */
	{
		act("$p glows brightly and explodes!",ch,obj,NULL,TO_CHAR);
		act("$p glows brightly and explodes!",ch,obj,NULL,TO_ROOM);
		extract_obj(obj);
	}

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_refresh( int , int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;

	victim->move = UMIN( victim->move + level, victim->max_move );
	
	if(!IS_NPC(victim) && victim->pcdata->tired!=-1)
	{
		victim->pcdata->tired-=level/25+2;
		if(victim->pcdata->tired<0)
			victim->pcdata->tired=0;
	}
	if (victim->max_move == victim->move)
		victim->printf( "You feel fully refreshed!\r\n" );
	else
		victim->printf(  "You feel less tired.\r\n" );
	if ( ch != victim )
		ch->println( "Ok." );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_remove_curse( int , int level, char_data *ch, void *vo,int target)
{
	char_data *victim;
	OBJ_DATA *obj;
	bool found = false;

	// do object cases first 
	if (target == TARGET_OBJ)
	{
		obj = (OBJ_DATA *) vo;
		if(obj==NULL)
			return NO_MANA;

		if (IS_OBJ_STAT(obj,OBJEXTRA_NODROP)
		|| IS_OBJ_STAT(obj,OBJEXTRA_NOREMOVE))
		{
			if (!IS_OBJ_STAT(obj,OBJEXTRA_NOUNCURSE)
			&&  !saves_dispel(level *2,obj->level,0))
			{
				REMOVE_BIT(obj->extra_flags,OBJEXTRA_NODROP);
				REMOVE_BIT(obj->extra_flags,OBJEXTRA_NOREMOVE);
				act("$p glows blue.",ch,obj,NULL,TO_ALL);
				return FULL_MANA;
			}

			act("The curse on $p is beyond your power.",ch,obj,NULL,TO_CHAR);
			return FULL_MANA;
		}

		act("$p is not cursed.",ch,obj,NULL,TO_CHAR);
		return HALF_MANA;
	}

    /* characters */
	victim = (char_data *) vo;

	if (!is_affected(victim, gsn_curse) || check_dispel(level,victim,gsn_curse))
	{
		victim->printf( "You feel better.\r\n" );
		act("$n looks more relaxed.",victim,NULL,NULL,TO_ROOM);
		for (obj = victim->carrying; (obj != NULL && !found); obj = obj->next_content)
		{
			if ((IS_OBJ_STAT(obj,OBJEXTRA_NODROP)
			|| IS_OBJ_STAT(obj,OBJEXTRA_NOREMOVE))
			&&  !IS_OBJ_STAT(obj,OBJEXTRA_NOUNCURSE))
			{   // attempt to remove curse 
				if (!saves_dispel(IS_HEALER(ch)?level*3:level/2,obj->level*3,0))
				{
					found = true;
					REMOVE_BIT(obj->extra_flags,OBJEXTRA_NODROP);
					REMOVE_BIT(obj->extra_flags,OBJEXTRA_NOREMOVE);
					act("Your $p glows blue.",victim,obj,NULL,TO_CHAR);
					act("$n's $p glows blue.",victim,obj,NULL,TO_ROOM);
				}
			}
		}
	}
	else
	{
		ch->printf( "It doesn't appear your magic has had any affect.\r\n" );
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_sanctuary( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_AFFECTED(victim, AFF_SANCTUARY ))
	{
		if (victim == ch)
			ch->printf( "You are already in sanctuary.\r\n" );
		else
			act("$N is already in sanctuary.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;

	if ( IS_IMMORTAL( ch ))
		af.duration  = level / 6;
	else
		af.duration  = 1 + level / 12;
	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 );
	victim->printf( "You are surrounded by a white aura.\r\n" );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_shield( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( is_affected( victim, sn ) )
	{
		if (victim == ch)
			ch->printf( "You are already shielded from harm.\r\n" );
		else
			act("$N is already protected by a shield.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	if ( is_affected( victim, gsn_oak_shield ))
	{
		if (victim == ch)
			ch->printf( "You are already protected by a shielding spell.\r\n" );
		else
			act("$N is already protected by a shielding spell.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	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 );
	victim->printf( "You are surrounded by a force shield.\r\n" );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_shocking_grasp(int sn,int level,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam;

	dam		= dice(level/4,2)+20;
	if ( saves_spell( level, victim,DAMTYPE(sn)) )
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn),true);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_sleep( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( IS_SET( victim->imm_flags, IMM_SLEEP ) || IS_ICIMMORTAL(victim)){
		act( "$n doesn't appear to be even slightly affected by your magic.", victim, NULL, NULL, TO_ROOM );
		return FULL_MANA;
	}

	if ( IS_AFFECTED(victim, AFF_SLEEP)
	|| ( IS_NPC(victim) && IS_SET(victim->act,ACT_UNDEAD))
	|| ( level + 2) < victim->level )
	{
		ch->println( "You failed." );
		return FULL_MANA;
	}

	if(saves_spell( level-4, victim,DAMTYPE(sn)) )
	{
		ch->println( "You failed." );
		// stop cheaters that panic logging out straight away
		if (!IS_NPC(victim) && victim!=ch)
		{
			victim->pknoquit=UMAX(victim->pknoquit,2);
		}
		if (!IS_NPC(ch) && !IS_NPC(victim) && victim!=ch)
		{
			ch->pksafe=0;
			ch->pknorecall= UMAX(ch->pknorecall,2);
			ch->pknoquit  = UMAX(ch->pknorecall,7);
		}
		return FULL_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = number_fuzzy(level);
	if(IS_NPC(victim))
		af.duration  = 4 + (level/2);
	else
		af.duration  = 2 + (level/9);  // duration reduced
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_SLEEP;
	affect_join( victim, &af );

	if ( IS_AWAKE(victim))
	{
		victim->printf( "You feel very sleepy ..... zzzzzz.\r\n" );
		act( "$n goes to sleep.", victim, NULL, NULL, TO_ROOM );
		victim->position = POS_SLEEPING;

		// stop those who are slept from logging out
		if (!IS_NPC(victim) && victim!=ch)
		{
			ch->pksafe=0;
			ch->pknorecall= UMAX(ch->pknorecall,2);
			ch->pknoquit  = UMAX(ch->pknorecall,7);

			if (!IS_NPC(ch))
			{
				victim->pknoquit=UMAX(victim->pknoquit,10);
			}
		}
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_slow( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if ( is_affected( victim, sn )
	|| IS_AFFECTED(victim,AFF_SLOW))
	{
		if (victim == ch)
			ch->printf( "You can't move any slower!\r\n" );
		else
			act("$N can't get any slower than that.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	if (saves_spell(level,victim,DAMTYPE(sn))
	||  IS_SET(victim->imm_flags,IMM_MAGIC))
	{
		if (victim != ch)
			ch->printf( "Nothing seemed to happen.\r\n" );
		victim->printf( "You feel momentarily lethargic.\r\n" );
		return FULL_MANA;
	}

	if (IS_AFFECTED(victim,AFF_HASTE))
	{
		if (!check_dispel(level,victim, gsn_haste ))
		{
			if (victim != ch)
			{
				ch->println("Spell failed.");
				return FULL_MANA;
			}
		}
		act("$n is moving less quickly.",victim,NULL,NULL,TO_ROOM);
		return FULL_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = level/2;
	af.location  = APPLY_QU;
	af.modifier  = -1 - level/5;
	af.bitvector = AFF_SLOW;
	affect_to_char( victim, &af );
	victim->printf( "You feel yourself slowing d o w n...\r\n" );
	act("$n starts to move in slow motion.",victim,NULL,NULL,TO_ROOM);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_stone_skin( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if(check_skin( ch, victim ))
		return HALF_MANA;

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	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 );
	victim->printf( "Your skin turns to stone.\r\n" );
	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_summon( int sn, int level, char_data *ch, void *,int  )
{
	char_data *victim;

	if ( ( victim = get_char_icworld( ch, target_name ) ) == NULL
	||   victim == ch
	||   victim->in_room == NULL
	||   IS_SET(ch->in_room->room_flags, ROOM_SAFE)
	||   IS_SET(victim->in_room->room_flags, ROOM_SAFE)
	||   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)
	||   IS_SET(victim->in_room->room_flags, ROOM_NOSCRY)
	||   IS_SET(victim->in_room->area->area_flags, AREA_NOSCRY)
	||   IS_SET(ch->in_room->area->area_flags, AREA_NOSUMMONINTO)	
	||   (IS_NPC(victim) && IS_SET(victim->act,ACT_AGGRESSIVE))
	||   victim->level >= level + 3
	||   (!IS_NPC(victim) && victim->level >= LEVEL_IMMORTAL)
	||   victim->fighting != NULL
	||   (IS_NPC(victim) && IS_SET(victim->imm_flags,IMM_SUMMON))
	||	 (IS_NPC(victim) && victim->pIndexData->pShop != NULL)
	||   (!IS_NPC(victim) && IS_SET(victim->act,PLR_NOSUMMON))
	||   (IS_NPC(victim) && saves_spell( level, victim,DAMTYPE(sn)))
	||	 (IS_SET(victim->form, FORM_MOUNTABLE) // can't summon mounts to inside
	&&	  IS_SET(ch->in_room->room_flags, ROOM_INDOORS))
	||   (IS_NPC(victim) && IS_SET(victim->act,ACT_AGGRESSIVE)) )
	{
		ch->println( "You failed." );
		return FULL_MANA;
	}

	// no charming in aggy mobs
	if(IS_NPC(victim)){
		REMOVE_BIT(victim->affected_by, ACT_AGGRESSIVE);
	}

	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!", ch, NULL, victim,   TO_VICT );
	do_look( victim, "auto" );

	/* 
	 * If someone is following the char, these triggers get activated
	 * for the followers before the char, but it's safer this way...
	 */
	if ( IS_NPC( victim)
	&& HAS_TRIGGER( victim, TRIG_ENTRY ) )
		mp_percent_trigger( victim, NULL, NULL, NULL, TRIG_ENTRY );

	if ( !IS_NPC( victim ))
		mp_greet_trigger( victim );

	return FULL_MANA;
}


/**************************************************************************/
SPRESULT spell_teleport( int sn, int level, char_data *ch, void *vo,int  )
{
	char_data *victim = (char_data *) vo;
	ROOM_INDEX_DATA *pRoomIndex;

	if ( victim->in_room == NULL
	||   IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
	|| ( victim != ch && IS_SET(victim->imm_flags,IMM_SUMMON))
	|| ( !IS_NPC(ch) && victim->fighting != NULL )
	|| ( victim != ch
	&& ( saves_spell( level - 5, victim,DAMTYPE(sn)))))
	{
		ch->println( "You failed." );
		return FULL_MANA;
	}

	pRoomIndex = get_random_room(victim);

	if (victim != ch)
		victim->printf( "You have been teleported!\r\n" );

	act( "$n vanishes!", 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 someone is following the char, these triggers get activated
	 * for the followers before the char, but it's safer this way...
	 */
	if ( IS_NPC( victim)
	&& HAS_TRIGGER( victim, TRIG_ENTRY ))
		mp_percent_trigger( victim, NULL, NULL, NULL, TRIG_ENTRY );

	if ( !IS_NPC( victim ))
		mp_greet_trigger( victim );

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_ventriloquate( int sn, int level, char_data *ch,void *,int )
{
	char buf1[MSL];
	char buf2[MSL];
	char speaker[MIL];
	char_data *vch;

	target_name = one_argument( target_name, speaker );

	sprintf( buf1, "%s says '%s'.", speaker, target_name );
	sprintf( buf2, "Someone makes %s say '%s'.", speaker, target_name );
	buf1[0] = UPPER(buf1[0]);

	for ( vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room )
	{
		if (IS_AWAKE(vch) && !is_affected(vch, gsn_deafness))
		{
			if ( !is_name( speaker, vch->name ))
				vch->printf( "%s\r\n", saves_spell(level,vch,DAMTYPE(sn)) ? buf2 : buf1 );
		}
	}

    return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_weaken( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if( is_affected( victim, gsn_giant_strength ))
		if( check_dispel( level, victim, gsn_giant_strength ))
		{
			act( "Your magic unravels a spell on $N.", ch, NULL, victim, TO_CHAR );
			return FULL_MANA;
		}
		else
		{
			ch->println( "You failed." );
			return FULL_MANA;
		}

	if ( is_affected( victim, sn ) )
	{
		act("$N already looks tired and weak.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}

	if (saves_spell( level, victim,DAMTYPE(sn)) )
	{
		ch->printf( "Your spell doesnt appear to have much affect.\r\n" );
		return FULL_MANA;
	}

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level     = level;
	af.duration  = level / 2;
	af.location  = APPLY_ST;
	af.modifier  = -1 * (level / 3);
	af.bitvector = AFF_WEAKEN;
	affect_to_char( victim, &af );
	victim->printf( "You feel your strength slip away.\r\n" );
	act("$n looks tired and weak.",victim,NULL,NULL,TO_ROOM);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_word_of_recall( int, int, char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
	ROOM_INDEX_DATA *location = NULL;

	if(IS_NPC(victim)){
		return NO_MANA;
	}

	// class recall spot first, then race
    // recall_vnum = pc_race_table[ch->race].recall_room; 
	if ( class_table[victim->clss].recall)
	{
		location = get_room_index( class_table[victim->clss].recall ); // Class
	}
	else  // Class recall room non-existant, check race room
	{
		location = get_room_index( race_table[victim->race]->recall_room); // Race
	}
	

	if ( location == NULL )
	{
		victim->println( "You are completely lost." );
		return NO_MANA;
	}

	if (IS_SET(victim->in_room->room_flags,ROOM_NO_RECALL)
	||  IS_SET(victim->in_room->room_flags, ROOM_ANTIMAGIC)
	||  IS_AFFECTED(victim,AFF_CURSE))
    {
		victim->println( "Spell failed." );
		return FULL_MANA;
	}

	if (victim->fighting != NULL)
		stop_fighting(victim,true);
    
	// Stop negative moves characters from defrauding the system
	if (ch->move>0 && IS_IC(ch))
		ch->move /= 2;

	act("$n disappears.",victim,NULL,NULL,TO_ROOM);
	char_from_room(victim);
	char_to_room(victim,location);
	act("$n appears in the room.",victim,NULL,NULL,TO_ROOM);
	do_look(victim,"auto");
	return FULL_MANA;
}

/**************************************************************************/
// NPC spells.
SPRESULT spell_acid_breath( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam,hp_dam,dice_dam,hpch;

	act("$n spits acid at $N.",ch,NULL,victim,TO_NOTVICT);
	act("$n spits a stream of corrosive acid at you.",ch,NULL,victim,TO_VICT);
	act("You spit acid at $N.",ch,NULL,victim,TO_CHAR);

	hpch = UMAX(12,ch->hit);
	hp_dam = number_range(hpch/11 + 1, hpch/6);
	dice_dam = dice(level,16);

	dam = UMAX(hp_dam + dice_dam/10,dice_dam + hp_dam/10);
    
	if (saves_spell(level,victim,DAMTYPE(sn)))
	{
		acid_effect(victim,level/2,dam/4,TARGET_CHAR);
		damage_spell(ch,victim,dam/2,sn,DAMTYPE(sn),true);
	}
	else
	{
		acid_effect(victim,level,dam,TARGET_CHAR);
		damage_spell(ch,victim,dam,sn,DAMTYPE(sn),true);
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_fire_breath( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	char_data *vch, *vch_next;
	int dam,hp_dam,dice_dam;
	int hpch;

	act("$n breathes forth a cone of fire.",ch,NULL,victim,TO_NOTVICT);
	act("$n breathes a cone of hot fire over you!",ch,NULL,victim,TO_VICT);
	act("You breath forth a cone of fire.",ch,NULL,NULL,TO_CHAR);

	hpch = UMAX( 10, ch->hit );
	hp_dam  = number_range( hpch/9+1, hpch/5 );
	dice_dam = dice(level,20);

	dam = UMAX(hp_dam + dice_dam /10, dice_dam + hp_dam / 10);
	fire_effect(victim->in_room,level,dam/2,TARGET_ROOM);

	for (vch = victim->in_room->people; vch != NULL; vch = vch_next)
	{
		vch_next = vch->next_in_room;

		if (is_safe_spell(ch,vch,true) 
		||  (IS_NPC(vch) && IS_NPC(ch) 
		&&   (ch->fighting != vch || vch->fighting != ch)))
		continue;

		if (vch == victim) /* full damage */
		{
			if (saves_spell(level,vch,DAMTYPE(sn)))
			{
				fire_effect(vch,level/2,dam/4,TARGET_CHAR);
				damage_spell(ch,vch,dam/2,sn,DAMTYPE(sn),true);
			}
			else
			{
				fire_effect(vch,level,dam,TARGET_CHAR);
				damage_spell(ch,vch,dam,sn,DAMTYPE(sn),true);
			}
		}
		else /* partial damage */
		{
			if (saves_spell(level - 2,vch,DAMTYPE(sn)))
			{
				fire_effect(vch,level/4,dam/8,TARGET_CHAR);
				damage_spell(ch,vch,dam/4,sn,DAMTYPE(sn),true);
			}
			else
			{
				fire_effect(vch,level/2,dam/4,TARGET_CHAR);
				damage_spell(ch,vch,dam/2,sn,DAMTYPE(sn),true);
			}
		}
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_frost_breath( int sn, int level, char_data *ch, void *vo,int )
{
	char_data *victim = (char_data *) vo;
	char_data *vch, *vch_next;
	int dam,hp_dam,dice_dam, hpch;

	act("$n breathes out a freezing cone of frost!",ch,NULL,victim,TO_NOTVICT);
	act("$n breathes a freezing cone of frost over you!",ch,NULL,victim,TO_VICT);
	act("You breath out a cone of frost.",ch,NULL,NULL,TO_CHAR);

	hpch = UMAX(12,ch->hit);
	hp_dam = number_range(hpch/11 + 1, hpch/6);
	dice_dam = dice(level,16);
	
	dam = UMAX(hp_dam + dice_dam/10,dice_dam + hp_dam/10);
	cold_effect(victim->in_room,level,dam/2,TARGET_ROOM); 

	for (vch = victim->in_room->people; vch != NULL; vch = vch_next)
	{
		vch_next = vch->next_in_room;

		if (is_safe_spell(ch,vch,true)
		|| (IS_NPC(vch) && IS_NPC(ch) 
		&& (ch->fighting != vch || vch->fighting != ch)))
		continue;

		if (vch == victim) /* full damage */
		{
			if (saves_spell(level,vch,DAMTYPE(sn)))
			{
				cold_effect(vch,level/2,dam/4,TARGET_CHAR);
				damage_spell(ch,vch,dam/2,sn,DAMTYPE(sn),true);
			}
			else
			{
				cold_effect(vch,level,dam,TARGET_CHAR);
				damage_spell(ch,vch,dam,sn,DAMTYPE(sn),true);
			}
		}
		else
		{
			if (saves_spell(level - 2,vch,DAMTYPE(sn)))
			{
				cold_effect(vch,level/4,dam/8,TARGET_CHAR);
				damage_spell(ch,vch,dam/4,sn,DAMTYPE(sn),true);
			}
			else
			{
				cold_effect(vch,level/2,dam/4,TARGET_CHAR);
				damage_spell(ch,vch,dam/2,sn,DAMTYPE(sn),true);
			}
		}
	}
	return FULL_MANA;
}

   
/**************************************************************************/
SPRESULT spell_gas_breath( int sn, int level, char_data *ch, void *,int  )
{
	char_data *vch;
	char_data *vch_next;
	int dam,hp_dam,dice_dam,hpch;

	act("$n breathes out a cloud of hot poisonous gas!",ch,NULL,NULL,TO_ROOM);
	act("You breath out a cloud of hot poisonous gas.",ch,NULL,NULL,TO_CHAR);

	hpch = UMAX(16,ch->hit);
	hp_dam = number_range(hpch/15+1,8);
	dice_dam = dice(level,12);

	dam = UMAX(hp_dam + dice_dam/10,dice_dam + hp_dam/10);
	poison_effect(ch->in_room,level,dam,TARGET_ROOM);

	for (vch = ch->in_room->people; vch != NULL; vch = vch_next)
	{
		vch_next = vch->next_in_room;

		if (is_safe_spell(ch,vch,true)
		|| (IS_NPC(ch) && IS_NPC(vch) 
		&& (ch->fighting == vch || vch->fighting == ch)))
		continue;

		if (check_immune(vch,DAMTYPE(sn))==IS_IMMUNE 
			|| HAS_CLASSFLAG(vch, CLASSFLAG_POISON_IMMUNITY))
		{
			vch->wrapln("The heat of the gas burns at your skin."
			"  You feel momentarily ill, but it passes.");
			damage_spell(ch,vch,dam/4,sn,DAMTYPE(sn),true);
		}
		else if (saves_spell(level,vch,DAMTYPE(sn)))
		{
			poison_effect(vch,level/2,dam/4,TARGET_CHAR);
			damage_spell(ch,vch,dam/2,sn,DAMTYPE(sn),true);
		}
		else
		{
			poison_effect(vch,level,dam,TARGET_CHAR);
			damage_spell(ch,vch,dam,sn,DAMTYPE(sn),true);
		}
	}
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_lightning_breath(int sn,int level,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam,hp_dam,dice_dam,hpch;

	act("$n breathes a bolt of lightning at $N.",ch,NULL,victim,TO_NOTVICT);
	act("$n breathes a bolt of lightning at you!",ch,NULL,victim,TO_VICT);
	act("You breathe a bolt of lightning at $N.",ch,NULL,victim,TO_CHAR);

	hpch = UMAX(10,ch->hit);
	hp_dam = number_range(hpch/9+1,hpch/5);
	dice_dam = dice(level,20);

	dam = UMAX(hp_dam + dice_dam/10,dice_dam + hp_dam/10);

	if (saves_spell(level,victim,DAMTYPE(sn)))
	{
		shock_effect(victim,level/2,dam/4,TARGET_CHAR);
		damage_spell(ch,victim,dam/2,sn,DAMTYPE(sn),true);
	}
	else
	{
		shock_effect(victim,level,dam,TARGET_CHAR);
		damage_spell(ch,victim,dam,sn,DAMTYPE(sn),true);
	}
	return FULL_MANA;
}

/**************************************************************************/
// Spells for mega1.are from Glop/Erkenbrand.
SPRESULT spell_general_purpose(int sn,int level,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam;
 
	dam = number_range( 25, 100 );
	if ( saves_spell( level, victim, DAMTYPE(sn)) )
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn) ,true);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_high_explosive(int sn,int level,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
	int dam;
 
	dam = number_range( 30, 120 );
	if ( saves_spell( level, victim, DAMTYPE(sn)) )
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn) ,true);
	return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_farsight( int , int , char_data *ch, void *,int )
{
	if (IS_AFFECTED(ch,AFF_BLIND))
	{
		ch->printf( "Maybe it would help if you could see?\r\n" );
		return HALF_MANA;
	}
 
	do_far_scan(ch,target_name);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_portal( int sn, int level, char_data *ch, void *,int )
{
	char_data *victim;
	OBJ_DATA *portal, *stone;

	if ((victim = get_char_world( ch, target_name ) ) == NULL
	||	 victim == ch
    ||	 victim->in_room == NULL
    ||	 !can_see_room(ch,victim->in_room)
    ||	 IS_SET(victim->in_room->room_flags, ROOM_SAFE)
    ||	 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_ANTIMAGIC)
    ||	 IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
    ||	 IS_SET(victim->in_room->area->area_flags, AREA_NOPORTALINTO)
    ||	 IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
    
	||	 victim->level >= level + 3
    ||	 (!IS_NPC(victim) && victim->level >= LEVEL_HERO)  /* NOT trust */
	||	 (IS_NPC(victim) && saves_spell( level, victim,DAMTYPE(sn)) )
    ||	 (is_clan(victim) && !is_same_clan(ch,victim)))
    {
        ch->println( "You failed." );
        return FULL_MANA;
    }   

	stone = get_eq_char(ch,WEAR_HOLD);
	
	if (!IS_IMMORTAL(ch) 
	&&  (stone == NULL
	|| stone->item_type != ITEM_WARP_STONE))
	{
		ch->println( "You lack the proper component for this spell." );
		return NO_MANA;
	}

	if (stone != NULL && stone->item_type == ITEM_WARP_STONE)
	{
		act("You draw upon the power of $p.",ch,stone,NULL,TO_CHAR);
		act("It flares brightly and vanishes!",ch,stone,NULL,TO_CHAR);
		extract_obj(stone);
	}

	portal = create_object(get_obj_index(OBJ_VNUM_PORTAL));
	portal->timer = 2 + level / 25; 
	portal->value[3] = victim->in_room->vnum;

	// portals aren't opaque - Kal August 98
	SET_BIT(portal->value[2],GATE_OPAQUE);

	obj_to_room(portal,ch->in_room);

	act("$p rises up from the ground.",ch,portal,NULL,TO_ROOM);
	act("$p rises up before you.",ch,portal,NULL,TO_CHAR);
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_nexus( int sn, int level, char_data *ch, void *, int)
{
	char_data *victim;
	OBJ_DATA *portal, *stone;
	ROOM_INDEX_DATA *from_room;
	ROOM_INDEX_DATA *to_room=NULL;

	from_room = ch->in_room;
 
	if ((victim = get_char_world( ch, target_name ) ) == NULL
    ||   victim == ch
    ||   (to_room = victim->in_room) == NULL
    ||   !can_see_room(ch,to_room) || !can_see_room(ch,from_room)
    ||	 IS_SET(from_room->room_flags,ROOM_SAFE)
	||   IS_SET(from_room->room_flags,ROOM_NO_RECALL)
    ||   IS_SET(to_room->room_flags, ROOM_SAFE)
	||	 IS_SET(to_room->room_flags, ROOM_ANTIMAGIC)
    ||   IS_SET(to_room->room_flags, ROOM_PRIVATE)
    ||   IS_SET(to_room->room_flags, ROOM_SOLITARY)
	||   IS_SET(to_room->room_flags, ROOM_NO_RECALL)
	||   IS_SET(to_room->area->area_flags, AREA_NOPORTALINTO)
	||   victim->level >= level + 3
	||   (!IS_NPC(victim) && victim->level >= LEVEL_HERO)  /* NOT trust */
	||   (saves_spell( level, victim,DAMTYPE(sn)) ) )
    {
        ch->println( "You failed." );
        return FULL_MANA;
	}   
 
	stone = get_eq_char(ch,WEAR_HOLD);

	if (!IS_IMMORTAL(ch)
    &&  (stone == NULL
	|| stone->item_type != ITEM_WARP_STONE))
	{
		ch->println( "You lack the proper component for this spell." );
		return NO_MANA;
	}
 
	if (stone != NULL && stone->item_type == ITEM_WARP_STONE)
	{
		act("You draw upon the power of $p.",ch,stone,NULL,TO_CHAR);
		act("It flares brightly and vanishes!",ch,stone,NULL,TO_CHAR);
		extract_obj(stone);
	}

	// portal one
	portal = create_object(get_obj_index(OBJ_VNUM_PORTAL));
	portal->timer = 1 + level / 10;
	portal->value[3] = to_room->vnum;
 
	obj_to_room(portal,from_room);
 
	act("$p rises up from the ground.",ch,portal,NULL,TO_ROOM);
	act("$p rises up before you.",ch,portal,NULL,TO_CHAR);

	// no second portal if rooms are the same 
	if (to_room == from_room)
		return HALF_MANA;

    // portal two 
	portal = create_object(get_obj_index(OBJ_VNUM_PORTAL));
	portal->timer = 1 + level/10;
	portal->value[3] = from_room->vnum;

	obj_to_room(portal,to_room);

	if (to_room->people != NULL)
	{
		act("$p rises up from the ground.",to_room->people,portal,NULL,TO_ROOM);
		act("$p rises up from the ground.",to_room->people,portal,NULL,TO_CHAR);
	}
	return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_mute( int sn, int level, char_data *ch, void *vo, int)
{
    char_data* victim = (char_data*) vo;
    AFFECT_DATA af;

    if ( IS_AFFECTED2(victim, AFF2_MUTE) )
    {
		ch->printlnf("%s is already silenced.", PERS(victim, ch));
		return HALF_MANA;
    }

    if ( saves_spell(level,victim,DAMTYPE(sn)) )
    {
		ch->println("You failed.");
		return HALF_MANA;
    }


    af.where     = WHERE_AFFECTS2;
    af.type      = sn;
    af.level     = level;
    af.duration  = level;
    af.location  = APPLY_NONE;
    af.modifier  = 0;
    af.bitvector = AFF2_MUTE;
    affect_to_char( victim, &af );
    
    act( "You have silenced $N!", ch, NULL, victim, TO_CHAR    );
    act( "$n has silenced you!",  ch, NULL, victim, TO_VICT    );
    act( "$n has silenced $N!",   ch, NULL, victim, TO_NOTVICT );
    return FULL_MANA;
}
/**************************************************************************/
SPRESULT spell_possession( int sn, int level, char_data *ch, void *vo, int)
{
    char_data* victim = (char_data*) vo;
    AFFECT_DATA af;

    if ( IS_AFFECTED2(victim, AFF2_POSSESSION) )
    {
		if (victim == ch){
			ch->println("You are already inhabited by a spirit.");
			return NO_MANA;
		}else{
			act("$N is already inhabited by a spirit.",ch,NULL,victim,TO_CHAR);
			return HALF_MANA;
		}
    }

    af.where     = WHERE_AFFECTS2;
    af.type      = sn;
    af.level     = level;
    af.duration  = level / 6;
    af.location  = APPLY_NONE;
    af.modifier  = 0;
    af.bitvector = AFF2_POSSESSION;
    affect_to_char( victim, &af );
    act( "$n looks stronger and mightier as a spirit of a dead warrior inhabits his body.",
         victim, NULL, NULL, TO_ROOM );
    victim->println("You suddenly gain the insights of a warrior of old.");
    return FULL_MANA;
}
/**************************************************************************/